From d01cd7af319195ad632bd1d3c601344c11984a3b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 17:13:19 +0000
Subject: [PATCH 1/1001] Add latest bootstrap.


---

diff --git a/hubs/static/bootstrap b/hubs/static/bootstrap
index e9aafbd..41ec0f8 120000
--- a/hubs/static/bootstrap
+++ b/hubs/static/bootstrap
@@ -1 +1 @@
-bootstrap-3.1.1-fedora
\ No newline at end of file
+bootstrap-3.3.4-fedora
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css
new file mode 100644
index 0000000..5365111
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css
@@ -0,0 +1,587 @@
+/*!
+ * Bootstrap v3.3.4 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+}
+.btn-default:active,
+.btn-primary:active,
+.btn-success:active,
+.btn-info:active,
+.btn-warning:active,
+.btn-danger:active,
+.btn-default.active,
+.btn-primary.active,
+.btn-success.active,
+.btn-info.active,
+.btn-warning.active,
+.btn-danger.active {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-default.disabled,
+.btn-primary.disabled,
+.btn-success.disabled,
+.btn-info.disabled,
+.btn-warning.disabled,
+.btn-danger.disabled,
+.btn-default[disabled],
+.btn-primary[disabled],
+.btn-success[disabled],
+.btn-info[disabled],
+.btn-warning[disabled],
+.btn-danger[disabled],
+fieldset[disabled] .btn-default,
+fieldset[disabled] .btn-primary,
+fieldset[disabled] .btn-success,
+fieldset[disabled] .btn-info,
+fieldset[disabled] .btn-warning,
+fieldset[disabled] .btn-danger {
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+.btn-default .badge,
+.btn-primary .badge,
+.btn-success .badge,
+.btn-info .badge,
+.btn-warning .badge,
+.btn-danger .badge {
+  text-shadow: none;
+}
+.btn:active,
+.btn.active {
+  background-image: none;
+}
+.btn-default {
+  text-shadow: 0 1px 0 #fff;
+  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+  background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
+  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #dbdbdb;
+  border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus {
+  background-color: #e0e0e0;
+  background-position: 0 -15px;
+}
+.btn-default:active,
+.btn-default.active {
+  background-color: #e0e0e0;
+  border-color: #dbdbdb;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+  background-color: #e0e0e0;
+  background-image: none;
+}
+.btn-primary {
+  background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
+  background-image:      -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2));
+  background-image:         linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #2b669a;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+  background-color: #2d6ca2;
+  background-position: 0 -15px;
+}
+.btn-primary:active,
+.btn-primary.active {
+  background-color: #2d6ca2;
+  border-color: #2b669a;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+  background-color: #2d6ca2;
+  background-image: none;
+}
+.btn-success {
+  background-image: -webkit-linear-gradient(top, #79db32 0%, #5cb11f 100%);
+  background-image:      -o-linear-gradient(top, #79db32 0%, #5cb11f 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#79db32), to(#5cb11f));
+  background-image:         linear-gradient(to bottom, #79db32 0%, #5cb11f 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff5cb11f', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #58a81e;
+}
+.btn-success:hover,
+.btn-success:focus {
+  background-color: #5cb11f;
+  background-position: 0 -15px;
+}
+.btn-success:active,
+.btn-success.active {
+  background-color: #5cb11f;
+  border-color: #58a81e;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+  background-color: #5cb11f;
+  background-image: none;
+}
+.btn-info {
+  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #8255a6 100%);
+  background-image:      -o-linear-gradient(top, #a07cbc 0%, #8255a6 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#a07cbc), to(#8255a6));
+  background-image:         linear-gradient(to bottom, #a07cbc 0%, #8255a6 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff8255a6', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #7d519f;
+}
+.btn-info:hover,
+.btn-info:focus {
+  background-color: #8255a6;
+  background-position: 0 -15px;
+}
+.btn-info:active,
+.btn-info.active {
+  background-color: #8255a6;
+  border-color: #7d519f;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+  background-color: #8255a6;
+  background-image: none;
+}
+.btn-warning {
+  background-image: -webkit-linear-gradient(top, #e59728 0%, #b97616 100%);
+  background-image:      -o-linear-gradient(top, #e59728 0%, #b97616 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#e59728), to(#b97616));
+  background-image:         linear-gradient(to bottom, #e59728 0%, #b97616 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffb97616', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #b07015;
+}
+.btn-warning:hover,
+.btn-warning:focus {
+  background-color: #b97616;
+  background-position: 0 -15px;
+}
+.btn-warning:active,
+.btn-warning.active {
+  background-color: #b97616;
+  border-color: #b07015;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+  background-color: #b97616;
+  background-image: none;
+}
+.btn-danger {
+  background-image: -webkit-linear-gradient(top, #db3279 0%, #b11f5c 100%);
+  background-image:      -o-linear-gradient(top, #db3279 0%, #b11f5c 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#db3279), to(#b11f5c));
+  background-image:         linear-gradient(to bottom, #db3279 0%, #b11f5c 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb11f5c', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #a81e58;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+  background-color: #b11f5c;
+  background-position: 0 -15px;
+}
+.btn-danger:active,
+.btn-danger.active {
+  background-color: #b11f5c;
+  border-color: #a81e58;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+  background-color: #b11f5c;
+  background-image: none;
+}
+.thumbnail,
+.img-thumbnail {
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  background-color: #e8e8e8;
+  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+  background-repeat: repeat-x;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  background-color: #357ebd;
+  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
+  background-image:      -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
+  background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
+  background-repeat: repeat-x;
+}
+.navbar-default {
+  background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+  background-image:      -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
+  background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .active > a {
+  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+  background-image:      -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
+  background-image:         linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
+  background-repeat: repeat-x;
+  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+}
+.navbar-brand,
+.navbar-nav > li > a {
+  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
+}
+.navbar-inverse {
+  background-image: -webkit-linear-gradient(top, #365698 0%, #294172 100%);
+  background-image:      -o-linear-gradient(top, #365698 0%, #294172 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#365698), to(#294172));
+  background-image:         linear-gradient(to bottom, #365698 0%, #294172 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff365698', endColorstr='#ff294172', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .active > a {
+  background-image: -webkit-linear-gradient(top, #1c2c4c 0%, #1f3156 100%);
+  background-image:      -o-linear-gradient(top, #1c2c4c 0%, #1f3156 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#1c2c4c), to(#1f3156));
+  background-image:         linear-gradient(to bottom, #1c2c4c 0%, #1f3156 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1c2c4c', endColorstr='#ff1f3156', GradientType=0);
+  background-repeat: repeat-x;
+  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+}
+.navbar-inverse .navbar-brand,
+.navbar-inverse .navbar-nav > li > a {
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
+}
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  border-radius: 0;
+}
+@media (max-width: 767px) {
+  .navbar .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #fff;
+    background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
+    background-image:      -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
+    background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
+    background-repeat: repeat-x;
+  }
+}
+.alert {
+  text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+}
+.alert-success {
+  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #c7f0a9 100%);
+  background-image:      -o-linear-gradient(top, #dcf6ca 0%, #c7f0a9 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#dcf6ca), to(#c7f0a9));
+  background-image:         linear-gradient(to bottom, #dcf6ca 0%, #c7f0a9 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffc7f0a9', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #b2ea89;
+}
+.alert-info {
+  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e3d9eb 100%);
+  background-image:      -o-linear-gradient(top, #f6f2f8 0%, #e3d9eb 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f6f2f8), to(#e3d9eb));
+  background-image:         linear-gradient(to bottom, #f6f2f8 0%, #e3d9eb 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe3d9eb', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #d1bfdf;
+}
+.alert-warning {
+  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f4d4a5 100%);
+  background-image:      -o-linear-gradient(top, #f8e4c7 0%, #f4d4a5 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f8e4c7), to(#f4d4a5));
+  background-image:         linear-gradient(to bottom, #f8e4c7 0%, #f4d4a5 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff4d4a5', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #f0c383;
+}
+.alert-danger {
+  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f0a9c7 100%);
+  background-image:      -o-linear-gradient(top, #f6cadc 0%, #f0a9c7 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f6cadc), to(#f0a9c7));
+  background-image:         linear-gradient(to bottom, #f6cadc 0%, #f0a9c7 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff0a9c7', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #ea89b2;
+}
+.progress {
+  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+  background-image:      -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
+  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar {
+  background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
+  background-image:      -o-linear-gradient(top, #428bca 0%, #3071a9 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9));
+  background-image:         linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-success {
+  background-image: -webkit-linear-gradient(top, #79db32 0%, #61b921 100%);
+  background-image:      -o-linear-gradient(top, #79db32 0%, #61b921 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#79db32), to(#61b921));
+  background-image:         linear-gradient(to bottom, #79db32 0%, #61b921 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff61b921', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-info {
+  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #885aab 100%);
+  background-image:      -o-linear-gradient(top, #a07cbc 0%, #885aab 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#a07cbc), to(#885aab));
+  background-image:         linear-gradient(to bottom, #a07cbc 0%, #885aab 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff885aab', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-warning {
+  background-image: -webkit-linear-gradient(top, #e59728 0%, #c27c18 100%);
+  background-image:      -o-linear-gradient(top, #e59728 0%, #c27c18 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#e59728), to(#c27c18));
+  background-image:         linear-gradient(to bottom, #e59728 0%, #c27c18 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffc27c18', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-danger {
+  background-image: -webkit-linear-gradient(top, #db3279 0%, #b92161 100%);
+  background-image:      -o-linear-gradient(top, #db3279 0%, #b92161 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#db3279), to(#b92161));
+  background-image:         linear-gradient(to bottom, #db3279 0%, #b92161 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb92161', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.list-group {
+  border-radius: 4px;
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  text-shadow: 0 -1px 0 #3071a9;
+  background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
+  background-image:      -o-linear-gradient(top, #428bca 0%, #3278b3 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3));
+  background-image:         linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #3278b3;
+}
+.list-group-item.active .badge,
+.list-group-item.active:hover .badge,
+.list-group-item.active:focus .badge {
+  text-shadow: none;
+}
+.panel {
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+}
+.panel-default > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-primary > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
+  background-image:      -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
+  background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-success > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #cef2b4 100%);
+  background-image:      -o-linear-gradient(top, #dcf6ca 0%, #cef2b4 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#dcf6ca), to(#cef2b4));
+  background-image:         linear-gradient(to bottom, #dcf6ca 0%, #cef2b4 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffcef2b4', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-info > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e9e1f0 100%);
+  background-image:      -o-linear-gradient(top, #f6f2f8 0%, #e9e1f0 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f6f2f8), to(#e9e1f0));
+  background-image:         linear-gradient(to bottom, #f6f2f8 0%, #e9e1f0 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe9e1f0', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-warning > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f6d9b0 100%);
+  background-image:      -o-linear-gradient(top, #f8e4c7 0%, #f6d9b0 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f8e4c7), to(#f6d9b0));
+  background-image:         linear-gradient(to bottom, #f8e4c7 0%, #f6d9b0 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff6d9b0', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-danger > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f2b4ce 100%);
+  background-image:      -o-linear-gradient(top, #f6cadc 0%, #f2b4ce 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f6cadc), to(#f2b4ce));
+  background-image:         linear-gradient(to bottom, #f6cadc 0%, #f2b4ce 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff2b4ce', GradientType=0);
+  background-repeat: repeat-x;
+}
+.well {
+  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+  background-image:      -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
+  background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #dcdcdc;
+  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+          box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+}
+/*# sourceMappingURL=bootstrap-theme.css.map */
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css.map b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css.map
new file mode 100644
index 0000000..1fade89
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","bootstrap-theme.css","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"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","file":"bootstrap-theme.css","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n  text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n  @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n  .box-shadow(@shadow);\n\n  // Reset the shadow\n  &:active,\n  &.active {\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    .box-shadow(none);\n  }\n\n  .badge {\n    text-shadow: none;\n  }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n  #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n  .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n  background-repeat: repeat-x;\n  border-color: darken(@btn-color, 14%);\n\n  &:hover,\n  &:focus  {\n    background-color: darken(@btn-color, 12%);\n    background-position: 0 -15px;\n  }\n\n  &:active,\n  &.active {\n    background-color: darken(@btn-color, 12%);\n    border-color: darken(@btn-color, 14%);\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    &,\n    &:hover,\n    &:focus,\n    &.focus,\n    &:active,\n    &.active {\n      background-color: darken(@btn-color, 12%);\n      background-image: none;\n    }\n  }\n}\n\n// Common styles\n.btn {\n  // Remove the gradient for the pressed/active state\n  &:active,\n  &.active {\n    background-image: none;\n  }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info    { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger  { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n  .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n  background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n  background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n  .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n  border-radius: @navbar-border-radius;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n  .box-shadow(@shadow);\n\n  .navbar-nav > .open > a,\n  .navbar-nav > .active > a {\n    #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n    .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n  }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n  #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n  .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n\n  .navbar-nav > .open > a,\n  .navbar-nav > .active > a {\n    #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n    .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n  }\n\n  .navbar-brand,\n  .navbar-nav > li > a {\n    text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n  }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n  .navbar .navbar-nav .open .dropdown-menu > .active > a {\n    &,\n    &:hover,\n    &:focus {\n      color: #fff;\n      #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n    }\n  }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n  text-shadow: 0 1px 0 rgba(255,255,255,.2);\n  @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n  .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n  border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success    { .alert-styles(@alert-success-bg); }\n.alert-info       { .alert-styles(@alert-info-bg); }\n.alert-warning    { .alert-styles(@alert-warning-bg); }\n.alert-danger     { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n  #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar            { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success    { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info       { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning    { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger     { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n  #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n  border-radius: @border-radius-base;\n  .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n  #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n  border-color: darken(@list-group-active-border, 7.5%);\n\n  .badge {\n    text-shadow: none;\n  }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n  .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading   { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading   { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading   { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading      { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading   { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading    { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n  #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n  border-color: darken(@well-bg, 10%);\n  @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n  -webkit-animation: @animation;\n       -o-animation: @animation;\n          animation: @animation;\n}\n.animation-name(@name) {\n  -webkit-animation-name: @name;\n          animation-name: @name;\n}\n.animation-duration(@duration) {\n  -webkit-animation-duration: @duration;\n          animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n  -webkit-animation-timing-function: @timing-function;\n          animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n  -webkit-animation-delay: @delay;\n          animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n  -webkit-animation-iteration-count: @iteration-count;\n          animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n  -webkit-animation-direction: @direction;\n          animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n  -webkit-animation-fill-mode: @fill-mode;\n          animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n  -webkit-backface-visibility: @visibility;\n     -moz-backface-visibility: @visibility;\n          backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n  -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n          box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n  -webkit-box-sizing: @boxmodel;\n     -moz-box-sizing: @boxmodel;\n          box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n  -webkit-column-count: @column-count;\n     -moz-column-count: @column-count;\n          column-count: @column-count;\n  -webkit-column-gap: @column-gap;\n     -moz-column-gap: @column-gap;\n          column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n  word-wrap: break-word;\n  -webkit-hyphens: @mode;\n     -moz-hyphens: @mode;\n      -ms-hyphens: @mode; // IE10+\n       -o-hyphens: @mode;\n          hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n  // Firefox\n  &::-moz-placeholder {\n    color: @color;\n    opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n  }\n  &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n  &::-webkit-input-placeholder  { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n  -webkit-transform: scale(@ratio);\n      -ms-transform: scale(@ratio); // IE9 only\n       -o-transform: scale(@ratio);\n          transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n  -webkit-transform: scale(@ratioX, @ratioY);\n      -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n       -o-transform: scale(@ratioX, @ratioY);\n          transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n  -webkit-transform: scaleX(@ratio);\n      -ms-transform: scaleX(@ratio); // IE9 only\n       -o-transform: scaleX(@ratio);\n          transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n  -webkit-transform: scaleY(@ratio);\n      -ms-transform: scaleY(@ratio); // IE9 only\n       -o-transform: scaleY(@ratio);\n          transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n  -webkit-transform: skewX(@x) skewY(@y);\n      -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n       -o-transform: skewX(@x) skewY(@y);\n          transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n  -webkit-transform: translate(@x, @y);\n      -ms-transform: translate(@x, @y); // IE9 only\n       -o-transform: translate(@x, @y);\n          transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n  -webkit-transform: translate3d(@x, @y, @z);\n          transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n  -webkit-transform: rotate(@degrees);\n      -ms-transform: rotate(@degrees); // IE9 only\n       -o-transform: rotate(@degrees);\n          transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n  -webkit-transform: rotateX(@degrees);\n      -ms-transform: rotateX(@degrees); // IE9 only\n       -o-transform: rotateX(@degrees);\n          transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n  -webkit-transform: rotateY(@degrees);\n      -ms-transform: rotateY(@degrees); // IE9 only\n       -o-transform: rotateY(@degrees);\n          transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n  -webkit-perspective: @perspective;\n     -moz-perspective: @perspective;\n          perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n  -webkit-perspective-origin: @perspective;\n     -moz-perspective-origin: @perspective;\n          perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n  -webkit-transform-origin: @origin;\n     -moz-transform-origin: @origin;\n      -ms-transform-origin: @origin; // IE9 only\n          transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n  -webkit-transition: @transition;\n       -o-transition: @transition;\n          transition: @transition;\n}\n.transition-property(@transition-property) {\n  -webkit-transition-property: @transition-property;\n          transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n  -webkit-transition-delay: @transition-delay;\n          transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n  -webkit-transition-duration: @transition-duration;\n          transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n  -webkit-transition-timing-function: @timing-function;\n          transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n  -webkit-transition: -webkit-transform @transition;\n     -moz-transition: -moz-transform @transition;\n       -o-transition: -o-transform @transition;\n          transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n  -webkit-user-select: @select;\n     -moz-user-select: @select;\n      -ms-user-select: @select; // IE10+\n          user-select: @select;\n}\n",".btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n  text-shadow: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n}\n.btn-default {\n  background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n  background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n  background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #dbdbdb;\n  text-shadow: 0 1px 0 #fff;\n  border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n  background-color: #e0e0e0;\n  background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n  background-color: #e0e0e0;\n  border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #e0e0e0;\n  background-image: none;\n}\n.btn-primary {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #2b669a;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n  background-color: #2d6ca2;\n  background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n  background-color: #2d6ca2;\n  border-color: #2b669a;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #2d6ca2;\n  background-image: none;\n}\n.btn-success {\n  background-image: -webkit-linear-gradient(top, #79db32 0%, #5cb11f 100%);\n  background-image: -o-linear-gradient(top, #79db32 0%, #5cb11f 100%);\n  background-image: linear-gradient(to bottom, #79db32 0%, #5cb11f 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff5cb11f', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #58a81e;\n}\n.btn-success:hover,\n.btn-success:focus {\n  background-color: #5cb11f;\n  background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n  background-color: #5cb11f;\n  border-color: #58a81e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #5cb11f;\n  background-image: none;\n}\n.btn-info {\n  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #8255a6 100%);\n  background-image: -o-linear-gradient(top, #a07cbc 0%, #8255a6 100%);\n  background-image: linear-gradient(to bottom, #a07cbc 0%, #8255a6 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff8255a6', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #7d519f;\n}\n.btn-info:hover,\n.btn-info:focus {\n  background-color: #8255a6;\n  background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n  background-color: #8255a6;\n  border-color: #7d519f;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #8255a6;\n  background-image: none;\n}\n.btn-warning {\n  background-image: -webkit-linear-gradient(top, #e59728 0%, #b97616 100%);\n  background-image: -o-linear-gradient(top, #e59728 0%, #b97616 100%);\n  background-image: linear-gradient(to bottom, #e59728 0%, #b97616 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffb97616', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #b07015;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n  background-color: #b97616;\n  background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n  background-color: #b97616;\n  border-color: #b07015;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #b97616;\n  background-image: none;\n}\n.btn-danger {\n  background-image: -webkit-linear-gradient(top, #db3279 0%, #b11f5c 100%);\n  background-image: -o-linear-gradient(top, #db3279 0%, #b11f5c 100%);\n  background-image: linear-gradient(to bottom, #db3279 0%, #b11f5c 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb11f5c', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #a81e58;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n  background-color: #b11f5c;\n  background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n  background-color: #b11f5c;\n  border-color: #a81e58;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #b11f5c;\n  background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n  background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);\n  background-color: #357ebd;\n}\n.navbar-default {\n  background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n  background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n  background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n  background-image: -webkit-linear-gradient(top, #365698 0%, #294172 100%);\n  background-image: -o-linear-gradient(top, #365698 0%, #294172 100%);\n  background-image: linear-gradient(to bottom, #365698 0%, #294172 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff365698', endColorstr='#ff294172', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #1c2c4c 0%, #1f3156 100%);\n  background-image: -o-linear-gradient(top, #1c2c4c 0%, #1f3156 100%);\n  background-image: linear-gradient(to bottom, #1c2c4c 0%, #1f3156 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1c2c4c', endColorstr='#ff1f3156', GradientType=0);\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n  box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n@media (max-width: 767px) {\n  .navbar .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n    background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n    background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n    background-repeat: repeat-x;\n    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);\n  }\n}\n.alert {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #c7f0a9 100%);\n  background-image: -o-linear-gradient(top, #dcf6ca 0%, #c7f0a9 100%);\n  background-image: linear-gradient(to bottom, #dcf6ca 0%, #c7f0a9 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffc7f0a9', GradientType=0);\n  border-color: #b2ea89;\n}\n.alert-info {\n  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e3d9eb 100%);\n  background-image: -o-linear-gradient(top, #f6f2f8 0%, #e3d9eb 100%);\n  background-image: linear-gradient(to bottom, #f6f2f8 0%, #e3d9eb 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe3d9eb', GradientType=0);\n  border-color: #d1bfdf;\n}\n.alert-warning {\n  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f4d4a5 100%);\n  background-image: -o-linear-gradient(top, #f8e4c7 0%, #f4d4a5 100%);\n  background-image: linear-gradient(to bottom, #f8e4c7 0%, #f4d4a5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff4d4a5', GradientType=0);\n  border-color: #f0c383;\n}\n.alert-danger {\n  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f0a9c7 100%);\n  background-image: -o-linear-gradient(top, #f6cadc 0%, #f0a9c7 100%);\n  background-image: linear-gradient(to bottom, #f6cadc 0%, #f0a9c7 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff0a9c7', GradientType=0);\n  border-color: #ea89b2;\n}\n.progress {\n  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);\n}\n.progress-bar-success {\n  background-image: -webkit-linear-gradient(top, #79db32 0%, #61b921 100%);\n  background-image: -o-linear-gradient(top, #79db32 0%, #61b921 100%);\n  background-image: linear-gradient(to bottom, #79db32 0%, #61b921 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff61b921', GradientType=0);\n}\n.progress-bar-info {\n  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #885aab 100%);\n  background-image: -o-linear-gradient(top, #a07cbc 0%, #885aab 100%);\n  background-image: linear-gradient(to bottom, #a07cbc 0%, #885aab 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff885aab', GradientType=0);\n}\n.progress-bar-warning {\n  background-image: -webkit-linear-gradient(top, #e59728 0%, #c27c18 100%);\n  background-image: -o-linear-gradient(top, #e59728 0%, #c27c18 100%);\n  background-image: linear-gradient(to bottom, #e59728 0%, #c27c18 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffc27c18', GradientType=0);\n}\n.progress-bar-danger {\n  background-image: -webkit-linear-gradient(top, #db3279 0%, #b92161 100%);\n  background-image: -o-linear-gradient(top, #db3279 0%, #b92161 100%);\n  background-image: linear-gradient(to bottom, #db3279 0%, #b92161 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb92161', GradientType=0);\n}\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  text-shadow: 0 -1px 0 #3071a9;\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);\n  border-color: #3278b3;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n  text-shadow: none;\n}\n.panel {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);\n}\n.panel-success > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #cef2b4 100%);\n  background-image: -o-linear-gradient(top, #dcf6ca 0%, #cef2b4 100%);\n  background-image: linear-gradient(to bottom, #dcf6ca 0%, #cef2b4 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffcef2b4', GradientType=0);\n}\n.panel-info > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e9e1f0 100%);\n  background-image: -o-linear-gradient(top, #f6f2f8 0%, #e9e1f0 100%);\n  background-image: linear-gradient(to bottom, #f6f2f8 0%, #e9e1f0 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe9e1f0', GradientType=0);\n}\n.panel-warning > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f6d9b0 100%);\n  background-image: -o-linear-gradient(top, #f8e4c7 0%, #f6d9b0 100%);\n  background-image: linear-gradient(to bottom, #f8e4c7 0%, #f6d9b0 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff6d9b0', GradientType=0);\n}\n.panel-danger > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f2b4ce 100%);\n  background-image: -o-linear-gradient(top, #f6cadc 0%, #f2b4ce 100%);\n  background-image: linear-gradient(to bottom, #f6cadc 0%, #f2b4ce 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff2b4ce', GradientType=0);\n}\n.well {\n  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n  border-color: #dcdcdc;\n  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","// Gradients\n\n#gradient {\n\n  // Horizontal gradient, from left to right\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n    background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  // Vertical gradient, from top to bottom\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Opera 12\n    background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n    background-repeat: repeat-x;\n    background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n    background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n  }\n  .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .radial(@inner-color: #555; @outer-color: #333) {\n    background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n    background-image: radial-gradient(circle, @inner-color, @outer-color);\n    background-repeat: no-repeat;\n  }\n  .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n    background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n  }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n  filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.min.css b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.min.css
new file mode 100644
index 0000000..2222295
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.4 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:focus,.btn-primary:hover{background-color:#2d6ca2;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#2d6ca2;border-color:#2b669a}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#79db32 0,#5cb11f 100%);background-image:-o-linear-gradient(top,#79db32 0,#5cb11f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#79db32),to(#5cb11f));background-image:linear-gradient(to bottom,#79db32 0,#5cb11f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff5cb11f', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#58a81e}.btn-success:focus,.btn-success:hover{background-color:#5cb11f;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#5cb11f;border-color:#58a81e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb11f;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#a07cbc 0,#8255a6 100%);background-image:-o-linear-gradient(top,#a07cbc 0,#8255a6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#a07cbc),to(#8255a6));background-image:linear-gradient(to bottom,#a07cbc 0,#8255a6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff8255a6', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#7d519f}.btn-info:focus,.btn-info:hover{background-color:#8255a6;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#8255a6;border-color:#7d519f}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#8255a6;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#e59728 0,#b97616 100%);background-image:-o-linear-gradient(top,#e59728 0,#b97616 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e59728),to(#b97616));background-image:linear-gradient(to bottom,#e59728 0,#b97616 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffb97616', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b07015}.btn-warning:focus,.btn-warning:hover{background-color:#b97616;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#b97616;border-color:#b07015}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#b97616;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#db3279 0,#b11f5c 100%);background-image:-o-linear-gradient(top,#db3279 0,#b11f5c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#db3279),to(#b11f5c));background-image:linear-gradient(to bottom,#db3279 0,#b11f5c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb11f5c', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#a81e58}.btn-danger:focus,.btn-danger:hover{background-color:#b11f5c;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#b11f5c;border-color:#a81e58}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#b11f5c;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#365698 0,#294172 100%);background-image:-o-linear-gradient(top,#365698 0,#294172 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#365698),to(#294172));background-image:linear-gradient(to bottom,#365698 0,#294172 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff365698', endColorstr='#ff294172', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#1c2c4c 0,#1f3156 100%);background-image:-o-linear-gradient(top,#1c2c4c 0,#1f3156 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#1c2c4c),to(#1f3156));background-image:linear-gradient(to bottom,#1c2c4c 0,#1f3156 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1c2c4c', endColorstr='#ff1f3156', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dcf6ca 0,#c7f0a9 100%);background-image:-o-linear-gradient(top,#dcf6ca 0,#c7f0a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dcf6ca),to(#c7f0a9));background-image:linear-gradient(to bottom,#dcf6ca 0,#c7f0a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffc7f0a9', GradientType=0);background-repeat:repeat-x;border-color:#b2ea89}.alert-info{background-image:-webkit-linear-gradient(top,#f6f2f8 0,#e3d9eb 100%);background-image:-o-linear-gradient(top,#f6f2f8 0,#e3d9eb 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f6f2f8),to(#e3d9eb));background-image:linear-gradient(to bottom,#f6f2f8 0,#e3d9eb 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe3d9eb', GradientType=0);background-repeat:repeat-x;border-color:#d1bfdf}.alert-warning{background-image:-webkit-linear-gradient(top,#f8e4c7 0,#f4d4a5 100%);background-image:-o-linear-gradient(top,#f8e4c7 0,#f4d4a5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f8e4c7),to(#f4d4a5));background-image:linear-gradient(to bottom,#f8e4c7 0,#f4d4a5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff4d4a5', GradientType=0);background-repeat:repeat-x;border-color:#f0c383}.alert-danger{background-image:-webkit-linear-gradient(top,#f6cadc 0,#f0a9c7 100%);background-image:-o-linear-gradient(top,#f6cadc 0,#f0a9c7 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f6cadc),to(#f0a9c7));background-image:linear-gradient(to bottom,#f6cadc 0,#f0a9c7 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff0a9c7', GradientType=0);background-repeat:repeat-x;border-color:#ea89b2}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#79db32 0,#61b921 100%);background-image:-o-linear-gradient(top,#79db32 0,#61b921 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#79db32),to(#61b921));background-image:linear-gradient(to bottom,#79db32 0,#61b921 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff61b921', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#a07cbc 0,#885aab 100%);background-image:-o-linear-gradient(top,#a07cbc 0,#885aab 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#a07cbc),to(#885aab));background-image:linear-gradient(to bottom,#a07cbc 0,#885aab 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff885aab', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#e59728 0,#c27c18 100%);background-image:-o-linear-gradient(top,#e59728 0,#c27c18 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e59728),to(#c27c18));background-image:linear-gradient(to bottom,#e59728 0,#c27c18 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffc27c18', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#db3279 0,#b92161 100%);background-image:-o-linear-gradient(top,#db3279 0,#b92161 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#db3279),to(#b92161));background-image:linear-gradient(to bottom,#db3279 0,#b92161 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb92161', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dcf6ca 0,#cef2b4 100%);background-image:-o-linear-gradient(top,#dcf6ca 0,#cef2b4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dcf6ca),to(#cef2b4));background-image:linear-gradient(to bottom,#dcf6ca 0,#cef2b4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffcef2b4', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#f6f2f8 0,#e9e1f0 100%);background-image:-o-linear-gradient(top,#f6f2f8 0,#e9e1f0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f6f2f8),to(#e9e1f0));background-image:linear-gradient(to bottom,#f6f2f8 0,#e9e1f0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe9e1f0', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#f8e4c7 0,#f6d9b0 100%);background-image:-o-linear-gradient(top,#f8e4c7 0,#f6d9b0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f8e4c7),to(#f6d9b0));background-image:linear-gradient(to bottom,#f8e4c7 0,#f6d9b0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff6d9b0', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f6cadc 0,#f2b4ce 100%);background-image:-o-linear-gradient(top,#f6cadc 0,#f2b4ce 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f6cadc),to(#f2b4ce));background-image:linear-gradient(to bottom,#f6cadc 0,#f2b4ce 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff2b4ce', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css
new file mode 100644
index 0000000..f463649
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css
@@ -0,0 +1,6764 @@
+/*!
+ * Bootstrap v3.3.4 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+html {
+  font-family: sans-serif;
+  -webkit-text-size-adjust: 100%;
+      -ms-text-size-adjust: 100%;
+}
+body {
+  margin: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block;
+}
+audio,
+canvas,
+progress,
+video {
+  display: inline-block;
+  vertical-align: baseline;
+}
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+[hidden],
+template {
+  display: none;
+}
+a {
+  background-color: transparent;
+}
+a:active,
+a:hover {
+  outline: 0;
+}
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+b,
+strong {
+  font-weight: bold;
+}
+dfn {
+  font-style: italic;
+}
+h1 {
+  margin: .67em 0;
+  font-size: 2em;
+}
+mark {
+  color: #000;
+  background: #ff0;
+}
+small {
+  font-size: 80%;
+}
+sub,
+sup {
+  position: relative;
+  font-size: 75%;
+  line-height: 0;
+  vertical-align: baseline;
+}
+sup {
+  top: -.5em;
+}
+sub {
+  bottom: -.25em;
+}
+img {
+  border: 0;
+}
+svg:not(:root) {
+  overflow: hidden;
+}
+figure {
+  margin: 1em 40px;
+}
+hr {
+  height: 0;
+  -webkit-box-sizing: content-box;
+     -moz-box-sizing: content-box;
+          box-sizing: content-box;
+}
+pre {
+  overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+  margin: 0;
+  font: inherit;
+  color: inherit;
+}
+button {
+  overflow: visible;
+}
+button,
+select {
+  text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button;
+  cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  padding: 0;
+  border: 0;
+}
+input {
+  line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-box-sizing: content-box;
+     -moz-box-sizing: content-box;
+          box-sizing: content-box;
+  -webkit-appearance: textfield;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+fieldset {
+  padding: .35em .625em .75em;
+  margin: 0 2px;
+  border: 1px solid #c0c0c0;
+}
+legend {
+  padding: 0;
+  border: 0;
+}
+textarea {
+  overflow: auto;
+}
+optgroup {
+  font-weight: bold;
+}
+table {
+  border-spacing: 0;
+  border-collapse: collapse;
+}
+td,
+th {
+  padding: 0;
+}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+@media print {
+  *,
+  *:before,
+  *:after {
+    color: #000 !important;
+    text-shadow: none !important;
+    background: transparent !important;
+    -webkit-box-shadow: none !important;
+            box-shadow: none !important;
+  }
+  a,
+  a:visited {
+    text-decoration: underline;
+  }
+  a[href]:after {
+    content: " (" attr(href) ")";
+  }
+  abbr[title]:after {
+    content: " (" attr(title) ")";
+  }
+  a[href^="#"]:after,
+  a[href^="javascript:"]:after {
+    content: "";
+  }
+  pre,
+  blockquote {
+    border: 1px solid #999;
+
+    page-break-inside: avoid;
+  }
+  thead {
+    display: table-header-group;
+  }
+  tr,
+  img {
+    page-break-inside: avoid;
+  }
+  img {
+    max-width: 100% !important;
+  }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3;
+  }
+  h2,
+  h3 {
+    page-break-after: avoid;
+  }
+  .navbar {
+    display: none;
+  }
+  .btn > .caret,
+  .dropup > .btn > .caret {
+    border-top-color: #000 !important;
+  }
+  .label {
+    border: 1px solid #000;
+  }
+  .table {
+    border-collapse: collapse !important;
+  }
+  .table td,
+  .table th {
+    background-color: #fff !important;
+  }
+  .table-bordered th,
+  .table-bordered td {
+    border: 1px solid #ddd !important;
+  }
+}
+@font-face {
+  font-family: 'Glyphicons Halflings';
+
+  src: url('../fonts/glyphicons-halflings-regular.eot');
+  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
+.glyphicon {
+  position: relative;
+  top: 1px;
+  display: inline-block;
+  font-family: 'Glyphicons Halflings';
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1;
+
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+  content: "\2a";
+}
+.glyphicon-plus:before {
+  content: "\2b";
+}
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+  content: "\20ac";
+}
+.glyphicon-minus:before {
+  content: "\2212";
+}
+.glyphicon-cloud:before {
+  content: "\2601";
+}
+.glyphicon-envelope:before {
+  content: "\2709";
+}
+.glyphicon-pencil:before {
+  content: "\270f";
+}
+.glyphicon-glass:before {
+  content: "\e001";
+}
+.glyphicon-music:before {
+  content: "\e002";
+}
+.glyphicon-search:before {
+  content: "\e003";
+}
+.glyphicon-heart:before {
+  content: "\e005";
+}
+.glyphicon-star:before {
+  content: "\e006";
+}
+.glyphicon-star-empty:before {
+  content: "\e007";
+}
+.glyphicon-user:before {
+  content: "\e008";
+}
+.glyphicon-film:before {
+  content: "\e009";
+}
+.glyphicon-th-large:before {
+  content: "\e010";
+}
+.glyphicon-th:before {
+  content: "\e011";
+}
+.glyphicon-th-list:before {
+  content: "\e012";
+}
+.glyphicon-ok:before {
+  content: "\e013";
+}
+.glyphicon-remove:before {
+  content: "\e014";
+}
+.glyphicon-zoom-in:before {
+  content: "\e015";
+}
+.glyphicon-zoom-out:before {
+  content: "\e016";
+}
+.glyphicon-off:before {
+  content: "\e017";
+}
+.glyphicon-signal:before {
+  content: "\e018";
+}
+.glyphicon-cog:before {
+  content: "\e019";
+}
+.glyphicon-trash:before {
+  content: "\e020";
+}
+.glyphicon-home:before {
+  content: "\e021";
+}
+.glyphicon-file:before {
+  content: "\e022";
+}
+.glyphicon-time:before {
+  content: "\e023";
+}
+.glyphicon-road:before {
+  content: "\e024";
+}
+.glyphicon-download-alt:before {
+  content: "\e025";
+}
+.glyphicon-download:before {
+  content: "\e026";
+}
+.glyphicon-upload:before {
+  content: "\e027";
+}
+.glyphicon-inbox:before {
+  content: "\e028";
+}
+.glyphicon-play-circle:before {
+  content: "\e029";
+}
+.glyphicon-repeat:before {
+  content: "\e030";
+}
+.glyphicon-refresh:before {
+  content: "\e031";
+}
+.glyphicon-list-alt:before {
+  content: "\e032";
+}
+.glyphicon-lock:before {
+  content: "\e033";
+}
+.glyphicon-flag:before {
+  content: "\e034";
+}
+.glyphicon-headphones:before {
+  content: "\e035";
+}
+.glyphicon-volume-off:before {
+  content: "\e036";
+}
+.glyphicon-volume-down:before {
+  content: "\e037";
+}
+.glyphicon-volume-up:before {
+  content: "\e038";
+}
+.glyphicon-qrcode:before {
+  content: "\e039";
+}
+.glyphicon-barcode:before {
+  content: "\e040";
+}
+.glyphicon-tag:before {
+  content: "\e041";
+}
+.glyphicon-tags:before {
+  content: "\e042";
+}
+.glyphicon-book:before {
+  content: "\e043";
+}
+.glyphicon-bookmark:before {
+  content: "\e044";
+}
+.glyphicon-print:before {
+  content: "\e045";
+}
+.glyphicon-camera:before {
+  content: "\e046";
+}
+.glyphicon-font:before {
+  content: "\e047";
+}
+.glyphicon-bold:before {
+  content: "\e048";
+}
+.glyphicon-italic:before {
+  content: "\e049";
+}
+.glyphicon-text-height:before {
+  content: "\e050";
+}
+.glyphicon-text-width:before {
+  content: "\e051";
+}
+.glyphicon-align-left:before {
+  content: "\e052";
+}
+.glyphicon-align-center:before {
+  content: "\e053";
+}
+.glyphicon-align-right:before {
+  content: "\e054";
+}
+.glyphicon-align-justify:before {
+  content: "\e055";
+}
+.glyphicon-list:before {
+  content: "\e056";
+}
+.glyphicon-indent-left:before {
+  content: "\e057";
+}
+.glyphicon-indent-right:before {
+  content: "\e058";
+}
+.glyphicon-facetime-video:before {
+  content: "\e059";
+}
+.glyphicon-picture:before {
+  content: "\e060";
+}
+.glyphicon-map-marker:before {
+  content: "\e062";
+}
+.glyphicon-adjust:before {
+  content: "\e063";
+}
+.glyphicon-tint:before {
+  content: "\e064";
+}
+.glyphicon-edit:before {
+  content: "\e065";
+}
+.glyphicon-share:before {
+  content: "\e066";
+}
+.glyphicon-check:before {
+  content: "\e067";
+}
+.glyphicon-move:before {
+  content: "\e068";
+}
+.glyphicon-step-backward:before {
+  content: "\e069";
+}
+.glyphicon-fast-backward:before {
+  content: "\e070";
+}
+.glyphicon-backward:before {
+  content: "\e071";
+}
+.glyphicon-play:before {
+  content: "\e072";
+}
+.glyphicon-pause:before {
+  content: "\e073";
+}
+.glyphicon-stop:before {
+  content: "\e074";
+}
+.glyphicon-forward:before {
+  content: "\e075";
+}
+.glyphicon-fast-forward:before {
+  content: "\e076";
+}
+.glyphicon-step-forward:before {
+  content: "\e077";
+}
+.glyphicon-eject:before {
+  content: "\e078";
+}
+.glyphicon-chevron-left:before {
+  content: "\e079";
+}
+.glyphicon-chevron-right:before {
+  content: "\e080";
+}
+.glyphicon-plus-sign:before {
+  content: "\e081";
+}
+.glyphicon-minus-sign:before {
+  content: "\e082";
+}
+.glyphicon-remove-sign:before {
+  content: "\e083";
+}
+.glyphicon-ok-sign:before {
+  content: "\e084";
+}
+.glyphicon-question-sign:before {
+  content: "\e085";
+}
+.glyphicon-info-sign:before {
+  content: "\e086";
+}
+.glyphicon-screenshot:before {
+  content: "\e087";
+}
+.glyphicon-remove-circle:before {
+  content: "\e088";
+}
+.glyphicon-ok-circle:before {
+  content: "\e089";
+}
+.glyphicon-ban-circle:before {
+  content: "\e090";
+}
+.glyphicon-arrow-left:before {
+  content: "\e091";
+}
+.glyphicon-arrow-right:before {
+  content: "\e092";
+}
+.glyphicon-arrow-up:before {
+  content: "\e093";
+}
+.glyphicon-arrow-down:before {
+  content: "\e094";
+}
+.glyphicon-share-alt:before {
+  content: "\e095";
+}
+.glyphicon-resize-full:before {
+  content: "\e096";
+}
+.glyphicon-resize-small:before {
+  content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+  content: "\e101";
+}
+.glyphicon-gift:before {
+  content: "\e102";
+}
+.glyphicon-leaf:before {
+  content: "\e103";
+}
+.glyphicon-fire:before {
+  content: "\e104";
+}
+.glyphicon-eye-open:before {
+  content: "\e105";
+}
+.glyphicon-eye-close:before {
+  content: "\e106";
+}
+.glyphicon-warning-sign:before {
+  content: "\e107";
+}
+.glyphicon-plane:before {
+  content: "\e108";
+}
+.glyphicon-calendar:before {
+  content: "\e109";
+}
+.glyphicon-random:before {
+  content: "\e110";
+}
+.glyphicon-comment:before {
+  content: "\e111";
+}
+.glyphicon-magnet:before {
+  content: "\e112";
+}
+.glyphicon-chevron-up:before {
+  content: "\e113";
+}
+.glyphicon-chevron-down:before {
+  content: "\e114";
+}
+.glyphicon-retweet:before {
+  content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+  content: "\e116";
+}
+.glyphicon-folder-close:before {
+  content: "\e117";
+}
+.glyphicon-folder-open:before {
+  content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+  content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+  content: "\e120";
+}
+.glyphicon-hdd:before {
+  content: "\e121";
+}
+.glyphicon-bullhorn:before {
+  content: "\e122";
+}
+.glyphicon-bell:before {
+  content: "\e123";
+}
+.glyphicon-certificate:before {
+  content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+  content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+  content: "\e126";
+}
+.glyphicon-hand-right:before {
+  content: "\e127";
+}
+.glyphicon-hand-left:before {
+  content: "\e128";
+}
+.glyphicon-hand-up:before {
+  content: "\e129";
+}
+.glyphicon-hand-down:before {
+  content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+  content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+  content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+  content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+  content: "\e134";
+}
+.glyphicon-globe:before {
+  content: "\e135";
+}
+.glyphicon-wrench:before {
+  content: "\e136";
+}
+.glyphicon-tasks:before {
+  content: "\e137";
+}
+.glyphicon-filter:before {
+  content: "\e138";
+}
+.glyphicon-briefcase:before {
+  content: "\e139";
+}
+.glyphicon-fullscreen:before {
+  content: "\e140";
+}
+.glyphicon-dashboard:before {
+  content: "\e141";
+}
+.glyphicon-paperclip:before {
+  content: "\e142";
+}
+.glyphicon-heart-empty:before {
+  content: "\e143";
+}
+.glyphicon-link:before {
+  content: "\e144";
+}
+.glyphicon-phone:before {
+  content: "\e145";
+}
+.glyphicon-pushpin:before {
+  content: "\e146";
+}
+.glyphicon-usd:before {
+  content: "\e148";
+}
+.glyphicon-gbp:before {
+  content: "\e149";
+}
+.glyphicon-sort:before {
+  content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+  content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+  content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+  content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+  content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+  content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+  content: "\e156";
+}
+.glyphicon-unchecked:before {
+  content: "\e157";
+}
+.glyphicon-expand:before {
+  content: "\e158";
+}
+.glyphicon-collapse-down:before {
+  content: "\e159";
+}
+.glyphicon-collapse-up:before {
+  content: "\e160";
+}
+.glyphicon-log-in:before {
+  content: "\e161";
+}
+.glyphicon-flash:before {
+  content: "\e162";
+}
+.glyphicon-log-out:before {
+  content: "\e163";
+}
+.glyphicon-new-window:before {
+  content: "\e164";
+}
+.glyphicon-record:before {
+  content: "\e165";
+}
+.glyphicon-save:before {
+  content: "\e166";
+}
+.glyphicon-open:before {
+  content: "\e167";
+}
+.glyphicon-saved:before {
+  content: "\e168";
+}
+.glyphicon-import:before {
+  content: "\e169";
+}
+.glyphicon-export:before {
+  content: "\e170";
+}
+.glyphicon-send:before {
+  content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+  content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+  content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+  content: "\e174";
+}
+.glyphicon-floppy-save:before {
+  content: "\e175";
+}
+.glyphicon-floppy-open:before {
+  content: "\e176";
+}
+.glyphicon-credit-card:before {
+  content: "\e177";
+}
+.glyphicon-transfer:before {
+  content: "\e178";
+}
+.glyphicon-cutlery:before {
+  content: "\e179";
+}
+.glyphicon-header:before {
+  content: "\e180";
+}
+.glyphicon-compressed:before {
+  content: "\e181";
+}
+.glyphicon-earphone:before {
+  content: "\e182";
+}
+.glyphicon-phone-alt:before {
+  content: "\e183";
+}
+.glyphicon-tower:before {
+  content: "\e184";
+}
+.glyphicon-stats:before {
+  content: "\e185";
+}
+.glyphicon-sd-video:before {
+  content: "\e186";
+}
+.glyphicon-hd-video:before {
+  content: "\e187";
+}
+.glyphicon-subtitles:before {
+  content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+  content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+  content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+  content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+  content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+  content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+  content: "\e194";
+}
+.glyphicon-registration-mark:before {
+  content: "\e195";
+}
+.glyphicon-cloud-download:before {
+  content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+  content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+  content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+  content: "\e200";
+}
+.glyphicon-cd:before {
+  content: "\e201";
+}
+.glyphicon-save-file:before {
+  content: "\e202";
+}
+.glyphicon-open-file:before {
+  content: "\e203";
+}
+.glyphicon-level-up:before {
+  content: "\e204";
+}
+.glyphicon-copy:before {
+  content: "\e205";
+}
+.glyphicon-paste:before {
+  content: "\e206";
+}
+.glyphicon-alert:before {
+  content: "\e209";
+}
+.glyphicon-equalizer:before {
+  content: "\e210";
+}
+.glyphicon-king:before {
+  content: "\e211";
+}
+.glyphicon-queen:before {
+  content: "\e212";
+}
+.glyphicon-pawn:before {
+  content: "\e213";
+}
+.glyphicon-bishop:before {
+  content: "\e214";
+}
+.glyphicon-knight:before {
+  content: "\e215";
+}
+.glyphicon-baby-formula:before {
+  content: "\e216";
+}
+.glyphicon-tent:before {
+  content: "\26fa";
+}
+.glyphicon-blackboard:before {
+  content: "\e218";
+}
+.glyphicon-bed:before {
+  content: "\e219";
+}
+.glyphicon-apple:before {
+  content: "\f8ff";
+}
+.glyphicon-erase:before {
+  content: "\e221";
+}
+.glyphicon-hourglass:before {
+  content: "\231b";
+}
+.glyphicon-lamp:before {
+  content: "\e223";
+}
+.glyphicon-duplicate:before {
+  content: "\e224";
+}
+.glyphicon-piggy-bank:before {
+  content: "\e225";
+}
+.glyphicon-scissors:before {
+  content: "\e226";
+}
+.glyphicon-bitcoin:before {
+  content: "\e227";
+}
+.glyphicon-btc:before {
+  content: "\e227";
+}
+.glyphicon-xbt:before {
+  content: "\e227";
+}
+.glyphicon-yen:before {
+  content: "\00a5";
+}
+.glyphicon-jpy:before {
+  content: "\00a5";
+}
+.glyphicon-ruble:before {
+  content: "\20bd";
+}
+.glyphicon-rub:before {
+  content: "\20bd";
+}
+.glyphicon-scale:before {
+  content: "\e230";
+}
+.glyphicon-ice-lolly:before {
+  content: "\e231";
+}
+.glyphicon-ice-lolly-tasted:before {
+  content: "\e232";
+}
+.glyphicon-education:before {
+  content: "\e233";
+}
+.glyphicon-option-horizontal:before {
+  content: "\e234";
+}
+.glyphicon-option-vertical:before {
+  content: "\e235";
+}
+.glyphicon-menu-hamburger:before {
+  content: "\e236";
+}
+.glyphicon-modal-window:before {
+  content: "\e237";
+}
+.glyphicon-oil:before {
+  content: "\e238";
+}
+.glyphicon-grain:before {
+  content: "\e239";
+}
+.glyphicon-sunglasses:before {
+  content: "\e240";
+}
+.glyphicon-text-size:before {
+  content: "\e241";
+}
+.glyphicon-text-color:before {
+  content: "\e242";
+}
+.glyphicon-text-background:before {
+  content: "\e243";
+}
+.glyphicon-object-align-top:before {
+  content: "\e244";
+}
+.glyphicon-object-align-bottom:before {
+  content: "\e245";
+}
+.glyphicon-object-align-horizontal:before {
+  content: "\e246";
+}
+.glyphicon-object-align-left:before {
+  content: "\e247";
+}
+.glyphicon-object-align-vertical:before {
+  content: "\e248";
+}
+.glyphicon-object-align-right:before {
+  content: "\e249";
+}
+.glyphicon-triangle-right:before {
+  content: "\e250";
+}
+.glyphicon-triangle-left:before {
+  content: "\e251";
+}
+.glyphicon-triangle-bottom:before {
+  content: "\e252";
+}
+.glyphicon-triangle-top:before {
+  content: "\e253";
+}
+.glyphicon-console:before {
+  content: "\e254";
+}
+.glyphicon-superscript:before {
+  content: "\e255";
+}
+.glyphicon-subscript:before {
+  content: "\e256";
+}
+.glyphicon-menu-left:before {
+  content: "\e257";
+}
+.glyphicon-menu-right:before {
+  content: "\e258";
+}
+.glyphicon-menu-down:before {
+  content: "\e259";
+}
+.glyphicon-menu-up:before {
+  content: "\e260";
+}
+* {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+*:before,
+*:after {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+html {
+  font-size: 10px;
+
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+  font-family: Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #333;
+  background-color: #fff;
+}
+input,
+button,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+}
+a {
+  color: #428bca;
+  text-decoration: none;
+}
+a:hover,
+a:focus {
+  color: #2a6496;
+  text-decoration: underline;
+}
+a:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+figure {
+  margin: 0;
+}
+img {
+  vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  display: block;
+  max-width: 100%;
+  height: auto;
+}
+.img-rounded {
+  border-radius: 6px;
+}
+.img-thumbnail {
+  display: inline-block;
+  max-width: 100%;
+  height: auto;
+  padding: 4px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  -webkit-transition: all .2s ease-in-out;
+       -o-transition: all .2s ease-in-out;
+          transition: all .2s ease-in-out;
+}
+.img-circle {
+  border-radius: 50%;
+}
+hr {
+  margin-top: 20px;
+  margin-bottom: 20px;
+  border: 0;
+  border-top: 1px solid #eee;
+}
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  padding: 0;
+  margin: -1px;
+  overflow: hidden;
+  clip: rect(0, 0, 0, 0);
+  border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+  position: static;
+  width: auto;
+  height: auto;
+  margin: 0;
+  overflow: visible;
+  clip: auto;
+}
+[role="button"] {
+  cursor: pointer;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+  font-family: inherit;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+  font-weight: normal;
+  line-height: 1;
+  color: #777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+  margin-top: 20px;
+  margin-bottom: 10px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+  font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+  font-size: 75%;
+}
+h1,
+.h1 {
+  font-size: 36px;
+}
+h2,
+.h2 {
+  font-size: 30px;
+}
+h3,
+.h3 {
+  font-size: 24px;
+}
+h4,
+.h4 {
+  font-size: 18px;
+}
+h5,
+.h5 {
+  font-size: 14px;
+}
+h6,
+.h6 {
+  font-size: 12px;
+}
+p {
+  margin: 0 0 10px;
+}
+.lead {
+  margin-bottom: 20px;
+  font-size: 16px;
+  font-weight: 300;
+  line-height: 1.4;
+}
+@media (min-width: 768px) {
+  .lead {
+    font-size: 21px;
+  }
+}
+small,
+.small {
+  font-size: 85%;
+}
+mark,
+.mark {
+  padding: .2em;
+  background-color: #f8e4c7;
+}
+.text-left {
+  text-align: left;
+}
+.text-right {
+  text-align: right;
+}
+.text-center {
+  text-align: center;
+}
+.text-justify {
+  text-align: justify;
+}
+.text-nowrap {
+  white-space: nowrap;
+}
+.text-lowercase {
+  text-transform: lowercase;
+}
+.text-uppercase {
+  text-transform: uppercase;
+}
+.text-capitalize {
+  text-transform: capitalize;
+}
+.text-muted {
+  color: #777;
+}
+.text-primary {
+  color: #428bca;
+}
+a.text-primary:hover,
+a.text-primary:focus {
+  color: #3071a9;
+}
+.text-success {
+  color: #3f7815;
+}
+a.text-success:hover,
+a.text-success:focus {
+  color: #284d0e;
+}
+.text-info {
+  color: #603e7a;
+}
+a.text-info:hover,
+a.text-info:focus {
+  color: #452d58;
+}
+.text-warning {
+  color: #7e500f;
+}
+a.text-warning:hover,
+a.text-warning:focus {
+  color: #51330a;
+}
+.text-danger {
+  color: #78153f;
+}
+a.text-danger:hover,
+a.text-danger:focus {
+  color: #4d0e28;
+}
+.bg-primary {
+  color: #fff;
+  background-color: #428bca;
+}
+a.bg-primary:hover,
+a.bg-primary:focus {
+  background-color: #3071a9;
+}
+.bg-success {
+  background-color: #dcf6ca;
+}
+a.bg-success:hover,
+a.bg-success:focus {
+  background-color: #c0ee9e;
+}
+.bg-info {
+  background-color: #f6f2f8;
+}
+a.bg-info:hover,
+a.bg-info:focus {
+  background-color: #ddd0e7;
+}
+.bg-warning {
+  background-color: #f8e4c7;
+}
+a.bg-warning:hover,
+a.bg-warning:focus {
+  background-color: #f3ce9a;
+}
+.bg-danger {
+  background-color: #f6cadc;
+}
+a.bg-danger:hover,
+a.bg-danger:focus {
+  background-color: #ee9ec0;
+}
+.page-header {
+  padding-bottom: 9px;
+  margin: 40px 0 20px;
+  border-bottom: 1px solid #eee;
+}
+ul,
+ol {
+  margin-top: 0;
+  margin-bottom: 10px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+  margin-bottom: 0;
+}
+.list-unstyled {
+  padding-left: 0;
+  list-style: none;
+}
+.list-inline {
+  padding-left: 0;
+  margin-left: -5px;
+  list-style: none;
+}
+.list-inline > li {
+  display: inline-block;
+  padding-right: 5px;
+  padding-left: 5px;
+}
+dl {
+  margin-top: 0;
+  margin-bottom: 20px;
+}
+dt,
+dd {
+  line-height: 1.42857143;
+}
+dt {
+  font-weight: bold;
+}
+dd {
+  margin-left: 0;
+}
+@media (min-width: 768px) {
+  .dl-horizontal dt {
+    float: left;
+    width: 160px;
+    overflow: hidden;
+    clear: left;
+    text-align: right;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .dl-horizontal dd {
+    margin-left: 180px;
+  }
+}
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #777;
+}
+.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+blockquote {
+  padding: 10px 20px;
+  margin: 0 0 20px;
+  font-size: 17.5px;
+  border-left: 5px solid #eee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+  margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+  display: block;
+  font-size: 80%;
+  line-height: 1.42857143;
+  color: #777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+  content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+  padding-right: 15px;
+  padding-left: 0;
+  text-align: right;
+  border-right: 5px solid #eee;
+  border-left: 0;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+  content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+  content: '\00A0 \2014';
+}
+address {
+  margin-bottom: 20px;
+  font-style: normal;
+  line-height: 1.42857143;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+}
+code {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #c7254e;
+  background-color: #f9f2f4;
+  border-radius: 4px;
+}
+kbd {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #fff;
+  background-color: #333;
+  border-radius: 3px;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+}
+kbd kbd {
+  padding: 0;
+  font-size: 100%;
+  font-weight: bold;
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+pre {
+  display: block;
+  padding: 9.5px;
+  margin: 0 0 10px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #333;
+  word-break: break-all;
+  word-wrap: break-word;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+pre code {
+  padding: 0;
+  font-size: inherit;
+  color: inherit;
+  white-space: pre-wrap;
+  background-color: transparent;
+  border-radius: 0;
+}
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
+.container {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-right: auto;
+  margin-left: auto;
+}
+@media (min-width: 768px) {
+  .container {
+    width: 750px;
+  }
+}
+@media (min-width: 992px) {
+  .container {
+    width: 970px;
+  }
+}
+@media (min-width: 1200px) {
+  .container {
+    width: 1170px;
+  }
+}
+.container-fluid {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-right: auto;
+  margin-left: auto;
+}
+.row {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
+  position: relative;
+  min-height: 1px;
+  padding-right: 15px;
+  padding-left: 15px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+  float: left;
+}
+.col-xs-12 {
+  width: 100%;
+}
+.col-xs-11 {
+  width: 91.66666667%;
+}
+.col-xs-10 {
+  width: 83.33333333%;
+}
+.col-xs-9 {
+  width: 75%;
+}
+.col-xs-8 {
+  width: 66.66666667%;
+}
+.col-xs-7 {
+  width: 58.33333333%;
+}
+.col-xs-6 {
+  width: 50%;
+}
+.col-xs-5 {
+  width: 41.66666667%;
+}
+.col-xs-4 {
+  width: 33.33333333%;
+}
+.col-xs-3 {
+  width: 25%;
+}
+.col-xs-2 {
+  width: 16.66666667%;
+}
+.col-xs-1 {
+  width: 8.33333333%;
+}
+.col-xs-pull-12 {
+  right: 100%;
+}
+.col-xs-pull-11 {
+  right: 91.66666667%;
+}
+.col-xs-pull-10 {
+  right: 83.33333333%;
+}
+.col-xs-pull-9 {
+  right: 75%;
+}
+.col-xs-pull-8 {
+  right: 66.66666667%;
+}
+.col-xs-pull-7 {
+  right: 58.33333333%;
+}
+.col-xs-pull-6 {
+  right: 50%;
+}
+.col-xs-pull-5 {
+  right: 41.66666667%;
+}
+.col-xs-pull-4 {
+  right: 33.33333333%;
+}
+.col-xs-pull-3 {
+  right: 25%;
+}
+.col-xs-pull-2 {
+  right: 16.66666667%;
+}
+.col-xs-pull-1 {
+  right: 8.33333333%;
+}
+.col-xs-pull-0 {
+  right: auto;
+}
+.col-xs-push-12 {
+  left: 100%;
+}
+.col-xs-push-11 {
+  left: 91.66666667%;
+}
+.col-xs-push-10 {
+  left: 83.33333333%;
+}
+.col-xs-push-9 {
+  left: 75%;
+}
+.col-xs-push-8 {
+  left: 66.66666667%;
+}
+.col-xs-push-7 {
+  left: 58.33333333%;
+}
+.col-xs-push-6 {
+  left: 50%;
+}
+.col-xs-push-5 {
+  left: 41.66666667%;
+}
+.col-xs-push-4 {
+  left: 33.33333333%;
+}
+.col-xs-push-3 {
+  left: 25%;
+}
+.col-xs-push-2 {
+  left: 16.66666667%;
+}
+.col-xs-push-1 {
+  left: 8.33333333%;
+}
+.col-xs-push-0 {
+  left: auto;
+}
+.col-xs-offset-12 {
+  margin-left: 100%;
+}
+.col-xs-offset-11 {
+  margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+  margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+  margin-left: 75%;
+}
+.col-xs-offset-8 {
+  margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+  margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+  margin-left: 50%;
+}
+.col-xs-offset-5 {
+  margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+  margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+  margin-left: 25%;
+}
+.col-xs-offset-2 {
+  margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+  margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+  margin-left: 0;
+}
+@media (min-width: 768px) {
+  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+    float: left;
+  }
+  .col-sm-12 {
+    width: 100%;
+  }
+  .col-sm-11 {
+    width: 91.66666667%;
+  }
+  .col-sm-10 {
+    width: 83.33333333%;
+  }
+  .col-sm-9 {
+    width: 75%;
+  }
+  .col-sm-8 {
+    width: 66.66666667%;
+  }
+  .col-sm-7 {
+    width: 58.33333333%;
+  }
+  .col-sm-6 {
+    width: 50%;
+  }
+  .col-sm-5 {
+    width: 41.66666667%;
+  }
+  .col-sm-4 {
+    width: 33.33333333%;
+  }
+  .col-sm-3 {
+    width: 25%;
+  }
+  .col-sm-2 {
+    width: 16.66666667%;
+  }
+  .col-sm-1 {
+    width: 8.33333333%;
+  }
+  .col-sm-pull-12 {
+    right: 100%;
+  }
+  .col-sm-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-sm-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-sm-pull-9 {
+    right: 75%;
+  }
+  .col-sm-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-sm-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-sm-pull-6 {
+    right: 50%;
+  }
+  .col-sm-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-sm-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-sm-pull-3 {
+    right: 25%;
+  }
+  .col-sm-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-sm-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-sm-pull-0 {
+    right: auto;
+  }
+  .col-sm-push-12 {
+    left: 100%;
+  }
+  .col-sm-push-11 {
+    left: 91.66666667%;
+  }
+  .col-sm-push-10 {
+    left: 83.33333333%;
+  }
+  .col-sm-push-9 {
+    left: 75%;
+  }
+  .col-sm-push-8 {
+    left: 66.66666667%;
+  }
+  .col-sm-push-7 {
+    left: 58.33333333%;
+  }
+  .col-sm-push-6 {
+    left: 50%;
+  }
+  .col-sm-push-5 {
+    left: 41.66666667%;
+  }
+  .col-sm-push-4 {
+    left: 33.33333333%;
+  }
+  .col-sm-push-3 {
+    left: 25%;
+  }
+  .col-sm-push-2 {
+    left: 16.66666667%;
+  }
+  .col-sm-push-1 {
+    left: 8.33333333%;
+  }
+  .col-sm-push-0 {
+    left: auto;
+  }
+  .col-sm-offset-12 {
+    margin-left: 100%;
+  }
+  .col-sm-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-sm-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-sm-offset-9 {
+    margin-left: 75%;
+  }
+  .col-sm-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-sm-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-sm-offset-6 {
+    margin-left: 50%;
+  }
+  .col-sm-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-sm-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-sm-offset-3 {
+    margin-left: 25%;
+  }
+  .col-sm-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-sm-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-sm-offset-0 {
+    margin-left: 0;
+  }
+}
+@media (min-width: 992px) {
+  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+    float: left;
+  }
+  .col-md-12 {
+    width: 100%;
+  }
+  .col-md-11 {
+    width: 91.66666667%;
+  }
+  .col-md-10 {
+    width: 83.33333333%;
+  }
+  .col-md-9 {
+    width: 75%;
+  }
+  .col-md-8 {
+    width: 66.66666667%;
+  }
+  .col-md-7 {
+    width: 58.33333333%;
+  }
+  .col-md-6 {
+    width: 50%;
+  }
+  .col-md-5 {
+    width: 41.66666667%;
+  }
+  .col-md-4 {
+    width: 33.33333333%;
+  }
+  .col-md-3 {
+    width: 25%;
+  }
+  .col-md-2 {
+    width: 16.66666667%;
+  }
+  .col-md-1 {
+    width: 8.33333333%;
+  }
+  .col-md-pull-12 {
+    right: 100%;
+  }
+  .col-md-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-md-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-md-pull-9 {
+    right: 75%;
+  }
+  .col-md-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-md-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-md-pull-6 {
+    right: 50%;
+  }
+  .col-md-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-md-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-md-pull-3 {
+    right: 25%;
+  }
+  .col-md-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-md-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-md-pull-0 {
+    right: auto;
+  }
+  .col-md-push-12 {
+    left: 100%;
+  }
+  .col-md-push-11 {
+    left: 91.66666667%;
+  }
+  .col-md-push-10 {
+    left: 83.33333333%;
+  }
+  .col-md-push-9 {
+    left: 75%;
+  }
+  .col-md-push-8 {
+    left: 66.66666667%;
+  }
+  .col-md-push-7 {
+    left: 58.33333333%;
+  }
+  .col-md-push-6 {
+    left: 50%;
+  }
+  .col-md-push-5 {
+    left: 41.66666667%;
+  }
+  .col-md-push-4 {
+    left: 33.33333333%;
+  }
+  .col-md-push-3 {
+    left: 25%;
+  }
+  .col-md-push-2 {
+    left: 16.66666667%;
+  }
+  .col-md-push-1 {
+    left: 8.33333333%;
+  }
+  .col-md-push-0 {
+    left: auto;
+  }
+  .col-md-offset-12 {
+    margin-left: 100%;
+  }
+  .col-md-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-md-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-md-offset-9 {
+    margin-left: 75%;
+  }
+  .col-md-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-md-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-md-offset-6 {
+    margin-left: 50%;
+  }
+  .col-md-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-md-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-md-offset-3 {
+    margin-left: 25%;
+  }
+  .col-md-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-md-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-md-offset-0 {
+    margin-left: 0;
+  }
+}
+@media (min-width: 1200px) {
+  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+    float: left;
+  }
+  .col-lg-12 {
+    width: 100%;
+  }
+  .col-lg-11 {
+    width: 91.66666667%;
+  }
+  .col-lg-10 {
+    width: 83.33333333%;
+  }
+  .col-lg-9 {
+    width: 75%;
+  }
+  .col-lg-8 {
+    width: 66.66666667%;
+  }
+  .col-lg-7 {
+    width: 58.33333333%;
+  }
+  .col-lg-6 {
+    width: 50%;
+  }
+  .col-lg-5 {
+    width: 41.66666667%;
+  }
+  .col-lg-4 {
+    width: 33.33333333%;
+  }
+  .col-lg-3 {
+    width: 25%;
+  }
+  .col-lg-2 {
+    width: 16.66666667%;
+  }
+  .col-lg-1 {
+    width: 8.33333333%;
+  }
+  .col-lg-pull-12 {
+    right: 100%;
+  }
+  .col-lg-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-lg-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-lg-pull-9 {
+    right: 75%;
+  }
+  .col-lg-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-lg-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-lg-pull-6 {
+    right: 50%;
+  }
+  .col-lg-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-lg-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-lg-pull-3 {
+    right: 25%;
+  }
+  .col-lg-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-lg-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-lg-pull-0 {
+    right: auto;
+  }
+  .col-lg-push-12 {
+    left: 100%;
+  }
+  .col-lg-push-11 {
+    left: 91.66666667%;
+  }
+  .col-lg-push-10 {
+    left: 83.33333333%;
+  }
+  .col-lg-push-9 {
+    left: 75%;
+  }
+  .col-lg-push-8 {
+    left: 66.66666667%;
+  }
+  .col-lg-push-7 {
+    left: 58.33333333%;
+  }
+  .col-lg-push-6 {
+    left: 50%;
+  }
+  .col-lg-push-5 {
+    left: 41.66666667%;
+  }
+  .col-lg-push-4 {
+    left: 33.33333333%;
+  }
+  .col-lg-push-3 {
+    left: 25%;
+  }
+  .col-lg-push-2 {
+    left: 16.66666667%;
+  }
+  .col-lg-push-1 {
+    left: 8.33333333%;
+  }
+  .col-lg-push-0 {
+    left: auto;
+  }
+  .col-lg-offset-12 {
+    margin-left: 100%;
+  }
+  .col-lg-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-lg-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-lg-offset-9 {
+    margin-left: 75%;
+  }
+  .col-lg-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-lg-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-lg-offset-6 {
+    margin-left: 50%;
+  }
+  .col-lg-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-lg-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-lg-offset-3 {
+    margin-left: 25%;
+  }
+  .col-lg-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-lg-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-lg-offset-0 {
+    margin-left: 0;
+  }
+}
+table {
+  background-color: transparent;
+}
+caption {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  color: #777;
+  text-align: left;
+}
+th {
+  text-align: left;
+}
+.table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: 20px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+  padding: 8px;
+  line-height: 1.42857143;
+  vertical-align: top;
+  border-top: 1px solid #ddd;
+}
+.table > thead > tr > th {
+  vertical-align: bottom;
+  border-bottom: 2px solid #ddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+  border-top: 0;
+}
+.table > tbody + tbody {
+  border-top: 2px solid #ddd;
+}
+.table .table {
+  background-color: #fff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+  padding: 5px;
+}
+.table-bordered {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+  border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-of-type(odd) {
+  background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+  background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+  position: static;
+  display: table-column;
+  float: none;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+  position: static;
+  display: table-cell;
+  float: none;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+  background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+  background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+  background-color: #dcf6ca;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+  background-color: #cef2b4;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+  background-color: #f6f2f8;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+  background-color: #e9e1f0;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+  background-color: #f8e4c7;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+  background-color: #f6d9b0;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+  background-color: #f6cadc;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+  background-color: #f2b4ce;
+}
+.table-responsive {
+  min-height: .01%;
+  overflow-x: auto;
+}
+@media screen and (max-width: 767px) {
+  .table-responsive {
+    width: 100%;
+    margin-bottom: 15px;
+    overflow-y: hidden;
+    -ms-overflow-style: -ms-autohiding-scrollbar;
+    border: 1px solid #ddd;
+  }
+  .table-responsive > .table {
+    margin-bottom: 0;
+  }
+  .table-responsive > .table > thead > tr > th,
+  .table-responsive > .table > tbody > tr > th,
+  .table-responsive > .table > tfoot > tr > th,
+  .table-responsive > .table > thead > tr > td,
+  .table-responsive > .table > tbody > tr > td,
+  .table-responsive > .table > tfoot > tr > td {
+    white-space: nowrap;
+  }
+  .table-responsive > .table-bordered {
+    border: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:first-child,
+  .table-responsive > .table-bordered > tbody > tr > th:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+  .table-responsive > .table-bordered > thead > tr > td:first-child,
+  .table-responsive > .table-bordered > tbody > tr > td:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+    border-left: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:last-child,
+  .table-responsive > .table-bordered > tbody > tr > th:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+  .table-responsive > .table-bordered > thead > tr > td:last-child,
+  .table-responsive > .table-bordered > tbody > tr > td:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+    border-right: 0;
+  }
+  .table-responsive > .table-bordered > tbody > tr:last-child > th,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+  .table-responsive > .table-bordered > tbody > tr:last-child > td,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+    border-bottom: 0;
+  }
+}
+fieldset {
+  min-width: 0;
+  padding: 0;
+  margin: 0;
+  border: 0;
+}
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 20px;
+  font-size: 21px;
+  line-height: inherit;
+  color: #333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+label {
+  display: inline-block;
+  max-width: 100%;
+  margin-bottom: 5px;
+  font-weight: bold;
+}
+input[type="search"] {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  margin-top: 1px \9;
+  line-height: normal;
+}
+input[type="file"] {
+  display: block;
+}
+input[type="range"] {
+  display: block;
+  width: 100%;
+}
+select[multiple],
+select[size] {
+  height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+output {
+  display: block;
+  padding-top: 7px;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #555;
+}
+.form-control {
+  display: block;
+  width: 100%;
+  height: 34px;
+  padding: 6px 12px;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
+       -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+  border-color: #66afe9;
+  outline: 0;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+}
+.form-control::-moz-placeholder {
+  color: #999;
+  opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+  color: #999;
+}
+.form-control::-webkit-input-placeholder {
+  color: #999;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+  background-color: #eee;
+  opacity: 1;
+}
+.form-control[disabled],
+fieldset[disabled] .form-control {
+  cursor: not-allowed;
+}
+textarea.form-control {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-appearance: none;
+}
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+  input[type="date"],
+  input[type="time"],
+  input[type="datetime-local"],
+  input[type="month"] {
+    line-height: 34px;
+  }
+  input[type="date"].input-sm,
+  input[type="time"].input-sm,
+  input[type="datetime-local"].input-sm,
+  input[type="month"].input-sm,
+  .input-group-sm input[type="date"],
+  .input-group-sm input[type="time"],
+  .input-group-sm input[type="datetime-local"],
+  .input-group-sm input[type="month"] {
+    line-height: 30px;
+  }
+  input[type="date"].input-lg,
+  input[type="time"].input-lg,
+  input[type="datetime-local"].input-lg,
+  input[type="month"].input-lg,
+  .input-group-lg input[type="date"],
+  .input-group-lg input[type="time"],
+  .input-group-lg input[type="datetime-local"],
+  .input-group-lg input[type="month"] {
+    line-height: 46px;
+  }
+}
+.form-group {
+  margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+  position: relative;
+  display: block;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+  min-height: 20px;
+  padding-left: 20px;
+  margin-bottom: 0;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+  position: absolute;
+  margin-top: 4px \9;
+  margin-left: -20px;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+  margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+  position: relative;
+  display: inline-block;
+  padding-left: 20px;
+  margin-bottom: 0;
+  font-weight: normal;
+  vertical-align: middle;
+  cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+  margin-top: 0;
+  margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+  cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+  cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+  cursor: not-allowed;
+}
+.form-control-static {
+  min-height: 34px;
+  padding-top: 7px;
+  padding-bottom: 7px;
+  margin-bottom: 0;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+  padding-right: 0;
+  padding-left: 0;
+}
+.input-sm {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+select.input-sm {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-sm,
+select[multiple].input-sm {
+  height: auto;
+}
+.form-group-sm .form-control {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.form-group-sm select.form-control {
+  height: 30px;
+  line-height: 30px;
+}
+.form-group-sm textarea.form-control,
+.form-group-sm select[multiple].form-control {
+  height: auto;
+}
+.form-group-sm .form-control-static {
+  height: 30px;
+  min-height: 32px;
+  padding: 6px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+}
+.input-lg {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.3333333;
+  border-radius: 6px;
+}
+select.input-lg {
+  height: 46px;
+  line-height: 46px;
+}
+textarea.input-lg,
+select[multiple].input-lg {
+  height: auto;
+}
+.form-group-lg .form-control {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.3333333;
+  border-radius: 6px;
+}
+.form-group-lg select.form-control {
+  height: 46px;
+  line-height: 46px;
+}
+.form-group-lg textarea.form-control,
+.form-group-lg select[multiple].form-control {
+  height: auto;
+}
+.form-group-lg .form-control-static {
+  height: 46px;
+  min-height: 38px;
+  padding: 11px 16px;
+  font-size: 18px;
+  line-height: 1.3333333;
+}
+.has-feedback {
+  position: relative;
+}
+.has-feedback .form-control {
+  padding-right: 42.5px;
+}
+.form-control-feedback {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+  display: block;
+  width: 34px;
+  height: 34px;
+  line-height: 34px;
+  text-align: center;
+  pointer-events: none;
+}
+.input-lg + .form-control-feedback,
+.input-group-lg + .form-control-feedback {
+  width: 46px;
+  height: 46px;
+  line-height: 46px;
+}
+.input-sm + .form-control-feedback,
+.input-group-sm + .form-control-feedback {
+  width: 30px;
+  height: 30px;
+  line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+  color: #3f7815;
+}
+.has-success .form-control {
+  border-color: #3f7815;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-success .form-control:focus {
+  border-color: #284d0e;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #6ccf24;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #6ccf24;
+}
+.has-success .input-group-addon {
+  color: #3f7815;
+  background-color: #dcf6ca;
+  border-color: #3f7815;
+}
+.has-success .form-control-feedback {
+  color: #3f7815;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+  color: #7e500f;
+}
+.has-warning .form-control {
+  border-color: #7e500f;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-warning .form-control:focus {
+  border-color: #51330a;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #d98a1a;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #d98a1a;
+}
+.has-warning .input-group-addon {
+  color: #7e500f;
+  background-color: #f8e4c7;
+  border-color: #7e500f;
+}
+.has-warning .form-control-feedback {
+  color: #7e500f;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+  color: #78153f;
+}
+.has-error .form-control {
+  border-color: #78153f;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-error .form-control:focus {
+  border-color: #4d0e28;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #cf246c;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #cf246c;
+}
+.has-error .input-group-addon {
+  color: #78153f;
+  background-color: #f6cadc;
+  border-color: #78153f;
+}
+.has-error .form-control-feedback {
+  color: #78153f;
+}
+.has-feedback label ~ .form-control-feedback {
+  top: 25px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+  top: 0;
+}
+.help-block {
+  display: block;
+  margin-top: 5px;
+  margin-bottom: 10px;
+  color: #737373;
+}
+@media (min-width: 768px) {
+  .form-inline .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .form-inline .form-control-static {
+    display: inline-block;
+  }
+  .form-inline .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .form-inline .input-group .input-group-addon,
+  .form-inline .input-group .input-group-btn,
+  .form-inline .input-group .form-control {
+    width: auto;
+  }
+  .form-inline .input-group > .form-control {
+    width: 100%;
+  }
+  .form-inline .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio,
+  .form-inline .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio label,
+  .form-inline .checkbox label {
+    padding-left: 0;
+  }
+  .form-inline .radio input[type="radio"],
+  .form-inline .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .form-inline .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+  padding-top: 7px;
+  margin-top: 0;
+  margin-bottom: 0;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+  min-height: 27px;
+}
+.form-horizontal .form-group {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+@media (min-width: 768px) {
+  .form-horizontal .control-label {
+    padding-top: 7px;
+    margin-bottom: 0;
+    text-align: right;
+  }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+  right: 15px;
+}
+@media (min-width: 768px) {
+  .form-horizontal .form-group-lg .control-label {
+    padding-top: 14.333333px;
+    font-size: 18px;
+  }
+}
+@media (min-width: 768px) {
+  .form-horizontal .form-group-sm .control-label {
+    padding-top: 6px;
+    font-size: 12px;
+  }
+}
+.btn {
+  display: inline-block;
+  padding: 6px 12px;
+  margin-bottom: 0;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1.42857143;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: middle;
+  -ms-touch-action: manipulation;
+      touch-action: manipulation;
+  cursor: pointer;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus,
+.btn.focus {
+  color: #333;
+  text-decoration: none;
+}
+.btn:active,
+.btn.active {
+  background-image: none;
+  outline: 0;
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+  cursor: not-allowed;
+  filter: alpha(opacity=65);
+  -webkit-box-shadow: none;
+          box-shadow: none;
+  opacity: .65;
+}
+a.btn.disabled,
+fieldset[disabled] a.btn {
+  pointer-events: none;
+}
+.btn-default {
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default:focus,
+.btn-default.focus {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #8c8c8c;
+}
+.btn-default:hover {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.btn-default:active:hover,
+.btn-default.active:hover,
+.open > .dropdown-toggle.btn-default:hover,
+.btn-default:active:focus,
+.btn-default.active:focus,
+.open > .dropdown-toggle.btn-default:focus,
+.btn-default:active.focus,
+.btn-default.active.focus,
+.open > .dropdown-toggle.btn-default.focus {
+  color: #333;
+  background-color: #d4d4d4;
+  border-color: #8c8c8c;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  background-image: none;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default .badge {
+  color: #fff;
+  background-color: #333;
+}
+.btn-primary {
+  color: #fff;
+  background-color: #428bca;
+  border-color: #357ebd;
+}
+.btn-primary:focus,
+.btn-primary.focus {
+  color: #fff;
+  background-color: #3071a9;
+  border-color: #193c5a;
+}
+.btn-primary:hover {
+  color: #fff;
+  background-color: #3071a9;
+  border-color: #285e8e;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  color: #fff;
+  background-color: #3071a9;
+  border-color: #285e8e;
+}
+.btn-primary:active:hover,
+.btn-primary.active:hover,
+.open > .dropdown-toggle.btn-primary:hover,
+.btn-primary:active:focus,
+.btn-primary.active:focus,
+.open > .dropdown-toggle.btn-primary:focus,
+.btn-primary:active.focus,
+.btn-primary.active.focus,
+.open > .dropdown-toggle.btn-primary.focus {
+  color: #fff;
+  background-color: #285e8e;
+  border-color: #193c5a;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  background-image: none;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+  background-color: #428bca;
+  border-color: #357ebd;
+}
+.btn-primary .badge {
+  color: #428bca;
+  background-color: #fff;
+}
+.btn-success {
+  color: #fff;
+  background-color: #79db32;
+  border-color: #6ccf24;
+}
+.btn-success:focus,
+.btn-success.focus {
+  color: #fff;
+  background-color: #61b921;
+  border-color: #346311;
+}
+.btn-success:hover {
+  color: #fff;
+  background-color: #61b921;
+  border-color: #519b1b;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  color: #fff;
+  background-color: #61b921;
+  border-color: #519b1b;
+}
+.btn-success:active:hover,
+.btn-success.active:hover,
+.open > .dropdown-toggle.btn-success:hover,
+.btn-success:active:focus,
+.btn-success.active:focus,
+.open > .dropdown-toggle.btn-success:focus,
+.btn-success:active.focus,
+.btn-success.active.focus,
+.open > .dropdown-toggle.btn-success.focus {
+  color: #fff;
+  background-color: #519b1b;
+  border-color: #346311;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  background-image: none;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+  background-color: #79db32;
+  border-color: #6ccf24;
+}
+.btn-success .badge {
+  color: #79db32;
+  background-color: #fff;
+}
+.btn-info {
+  color: #fff;
+  background-color: #a07cbc;
+  border-color: #946bb3;
+}
+.btn-info:focus,
+.btn-info.focus {
+  color: #fff;
+  background-color: #885aab;
+  border-color: #533669;
+}
+.btn-info:hover {
+  color: #fff;
+  background-color: #885aab;
+  border-color: #754c95;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  color: #fff;
+  background-color: #885aab;
+  border-color: #754c95;
+}
+.btn-info:active:hover,
+.btn-info.active:hover,
+.open > .dropdown-toggle.btn-info:hover,
+.btn-info:active:focus,
+.btn-info.active:focus,
+.open > .dropdown-toggle.btn-info:focus,
+.btn-info:active.focus,
+.btn-info.active.focus,
+.open > .dropdown-toggle.btn-info.focus {
+  color: #fff;
+  background-color: #754c95;
+  border-color: #533669;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  background-image: none;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+  background-color: #a07cbc;
+  border-color: #946bb3;
+}
+.btn-info .badge {
+  color: #a07cbc;
+  background-color: #fff;
+}
+.btn-warning {
+  color: #fff;
+  background-color: #e59728;
+  border-color: #d98a1a;
+}
+.btn-warning:focus,
+.btn-warning.focus {
+  color: #fff;
+  background-color: #c27c18;
+  border-color: #67420d;
+}
+.btn-warning:hover {
+  color: #fff;
+  background-color: #c27c18;
+  border-color: #a36814;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  color: #fff;
+  background-color: #c27c18;
+  border-color: #a36814;
+}
+.btn-warning:active:hover,
+.btn-warning.active:hover,
+.open > .dropdown-toggle.btn-warning:hover,
+.btn-warning:active:focus,
+.btn-warning.active:focus,
+.open > .dropdown-toggle.btn-warning:focus,
+.btn-warning:active.focus,
+.btn-warning.active.focus,
+.open > .dropdown-toggle.btn-warning.focus {
+  color: #fff;
+  background-color: #a36814;
+  border-color: #67420d;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  background-image: none;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+  background-color: #e59728;
+  border-color: #d98a1a;
+}
+.btn-warning .badge {
+  color: #e59728;
+  background-color: #fff;
+}
+.btn-danger {
+  color: #fff;
+  background-color: #db3279;
+  border-color: #cf246c;
+}
+.btn-danger:focus,
+.btn-danger.focus {
+  color: #fff;
+  background-color: #b92161;
+  border-color: #631134;
+}
+.btn-danger:hover {
+  color: #fff;
+  background-color: #b92161;
+  border-color: #9b1b51;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  color: #fff;
+  background-color: #b92161;
+  border-color: #9b1b51;
+}
+.btn-danger:active:hover,
+.btn-danger.active:hover,
+.open > .dropdown-toggle.btn-danger:hover,
+.btn-danger:active:focus,
+.btn-danger.active:focus,
+.open > .dropdown-toggle.btn-danger:focus,
+.btn-danger:active.focus,
+.btn-danger.active.focus,
+.open > .dropdown-toggle.btn-danger.focus {
+  color: #fff;
+  background-color: #9b1b51;
+  border-color: #631134;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  background-image: none;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+  background-color: #db3279;
+  border-color: #cf246c;
+}
+.btn-danger .badge {
+  color: #db3279;
+  background-color: #fff;
+}
+.btn-link {
+  font-weight: normal;
+  color: #428bca;
+  border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link.active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+  background-color: transparent;
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+  border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+  color: #2a6496;
+  text-decoration: underline;
+  background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+  color: #777;
+  text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.3333333;
+  border-radius: 6px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+  padding: 1px 5px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.btn-block {
+  display: block;
+  width: 100%;
+}
+.btn-block + .btn-block {
+  margin-top: 5px;
+}
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+  width: 100%;
+}
+.fade {
+  opacity: 0;
+  -webkit-transition: opacity .15s linear;
+       -o-transition: opacity .15s linear;
+          transition: opacity .15s linear;
+}
+.fade.in {
+  opacity: 1;
+}
+.collapse {
+  display: none;
+}
+.collapse.in {
+  display: block;
+}
+tr.collapse.in {
+  display: table-row;
+}
+tbody.collapse.in {
+  display: table-row-group;
+}
+.collapsing {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  -webkit-transition-timing-function: ease;
+       -o-transition-timing-function: ease;
+          transition-timing-function: ease;
+  -webkit-transition-duration: .35s;
+       -o-transition-duration: .35s;
+          transition-duration: .35s;
+  -webkit-transition-property: height, visibility;
+       -o-transition-property: height, visibility;
+          transition-property: height, visibility;
+}
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  margin-left: 2px;
+  vertical-align: middle;
+  border-top: 4px dashed;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent;
+}
+.dropup,
+.dropdown {
+  position: relative;
+}
+.dropdown-toggle:focus {
+  outline: 0;
+}
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0;
+  font-size: 14px;
+  text-align: left;
+  list-style: none;
+  background-color: #fff;
+  -webkit-background-clip: padding-box;
+          background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, .15);
+  border-radius: 4px;
+  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+}
+.dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+.dropdown-menu .divider {
+  height: 1px;
+  margin: 9px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+  display: block;
+  padding: 3px 20px;
+  clear: both;
+  font-weight: normal;
+  line-height: 1.42857143;
+  color: #333;
+  white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  color: #262626;
+  text-decoration: none;
+  background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  color: #fff;
+  text-decoration: none;
+  background-color: #428bca;
+  outline: 0;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  color: #777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  text-decoration: none;
+  cursor: not-allowed;
+  background-color: transparent;
+  background-image: none;
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.open > .dropdown-menu {
+  display: block;
+}
+.open > a {
+  outline: 0;
+}
+.dropdown-menu-right {
+  right: 0;
+  left: auto;
+}
+.dropdown-menu-left {
+  right: auto;
+  left: 0;
+}
+.dropdown-header {
+  display: block;
+  padding: 3px 20px;
+  font-size: 12px;
+  line-height: 1.42857143;
+  color: #777;
+  white-space: nowrap;
+}
+.dropdown-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 990;
+}
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+  content: "";
+  border-top: 0;
+  border-bottom: 4px solid;
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+  top: auto;
+  bottom: 100%;
+  margin-bottom: 2px;
+}
+@media (min-width: 768px) {
+  .navbar-right .dropdown-menu {
+    right: 0;
+    left: auto;
+  }
+  .navbar-right .dropdown-menu-left {
+    right: auto;
+    left: 0;
+  }
+}
+.btn-group,
+.btn-group-vertical {
+  position: relative;
+  display: inline-block;
+  vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+  position: relative;
+  float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+  z-index: 2;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+  margin-left: -1px;
+}
+.btn-toolbar {
+  margin-left: -5px;
+}
+.btn-toolbar .btn,
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+  float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+  margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+  border-radius: 0;
+}
+.btn-group > .btn:first-child {
+  margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group > .btn-group {
+  float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+  padding-right: 8px;
+  padding-left: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+  padding-right: 12px;
+  padding-left: 12px;
+}
+.btn-group.open .dropdown-toggle {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+.btn .caret {
+  margin-left: 0;
+}
+.btn-lg .caret {
+  border-width: 5px 5px 0;
+  border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+  border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+  display: block;
+  float: none;
+  width: 100%;
+  max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+  float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+  margin-top: -1px;
+  margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+  border-bottom-left-radius: 4px;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.btn-group-justified {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+  border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+  display: table-cell;
+  float: none;
+  width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+  width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+  left: auto;
+}
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+  position: absolute;
+  clip: rect(0, 0, 0, 0);
+  pointer-events: none;
+}
+.input-group {
+  position: relative;
+  display: table;
+  border-collapse: separate;
+}
+.input-group[class*="col-"] {
+  float: none;
+  padding-right: 0;
+  padding-left: 0;
+}
+.input-group .form-control {
+  position: relative;
+  z-index: 2;
+  float: left;
+  width: 100%;
+  margin-bottom: 0;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.3333333;
+  border-radius: 6px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+  height: 46px;
+  line-height: 46px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+  display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+  width: 1%;
+  white-space: nowrap;
+  vertical-align: middle;
+}
+.input-group-addon {
+  padding: 6px 12px;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1;
+  color: #555;
+  text-align: center;
+  background-color: #eee;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+.input-group-addon.input-sm {
+  padding: 5px 10px;
+  font-size: 12px;
+  border-radius: 3px;
+}
+.input-group-addon.input-lg {
+  padding: 10px 16px;
+  font-size: 18px;
+  border-radius: 6px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+  margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.input-group-addon:first-child {
+  border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.input-group-addon:last-child {
+  border-left: 0;
+}
+.input-group-btn {
+  position: relative;
+  font-size: 0;
+  white-space: nowrap;
+}
+.input-group-btn > .btn {
+  position: relative;
+}
+.input-group-btn > .btn + .btn {
+  margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+  z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+  margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+  z-index: 2;
+  margin-left: -1px;
+}
+.nav {
+  padding-left: 0;
+  margin-bottom: 0;
+  list-style: none;
+}
+.nav > li {
+  position: relative;
+  display: block;
+}
+.nav > li > a {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+  text-decoration: none;
+  background-color: #eee;
+}
+.nav > li.disabled > a {
+  color: #777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+  color: #777;
+  text-decoration: none;
+  cursor: not-allowed;
+  background-color: transparent;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+  background-color: #eee;
+  border-color: #428bca;
+}
+.nav .nav-divider {
+  height: 1px;
+  margin: 9px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.nav > li > a > img {
+  max-width: none;
+}
+.nav-tabs {
+  border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+  float: left;
+  margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+  margin-right: 2px;
+  line-height: 1.42857143;
+  border: 1px solid transparent;
+  border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+  border-color: #eee #eee #ddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+  color: #555;
+  cursor: default;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+}
+.nav-tabs.nav-justified {
+  width: 100%;
+  border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+  float: none;
+}
+.nav-tabs.nav-justified > li > a {
+  margin-bottom: 5px;
+  text-align: center;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+@media (min-width: 768px) {
+  .nav-tabs.nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-tabs.nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs.nav-justified > li > a {
+  margin-right: 0;
+  border-radius: 4px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+  .nav-tabs.nav-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 4px 4px 0 0;
+  }
+  .nav-tabs.nav-justified > .active > a,
+  .nav-tabs.nav-justified > .active > a:hover,
+  .nav-tabs.nav-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.nav-pills > li {
+  float: left;
+}
+.nav-pills > li > a {
+  border-radius: 4px;
+}
+.nav-pills > li + li {
+  margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+  color: #fff;
+  background-color: #428bca;
+}
+.nav-stacked > li {
+  float: none;
+}
+.nav-stacked > li + li {
+  margin-top: 2px;
+  margin-left: 0;
+}
+.nav-justified {
+  width: 100%;
+}
+.nav-justified > li {
+  float: none;
+}
+.nav-justified > li > a {
+  margin-bottom: 5px;
+  text-align: center;
+}
+.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+@media (min-width: 768px) {
+  .nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs-justified {
+  border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+  margin-right: 0;
+  border-radius: 4px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+  .nav-tabs-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 4px 4px 0 0;
+  }
+  .nav-tabs-justified > .active > a,
+  .nav-tabs-justified > .active > a:hover,
+  .nav-tabs-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.tab-content > .tab-pane {
+  display: none;
+}
+.tab-content > .active {
+  display: block;
+}
+.nav .caret {
+  border-top-color: #db3279;
+  border-bottom-color: #db3279;
+}
+.nav a:hover .caret {
+  border-top-color: #b92161;
+  border-bottom-color: #b92161;
+}
+.nav-tabs .dropdown-menu {
+  margin-top: -1px;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.navbar {
+  position: relative;
+  min-height: 35px;
+  margin-bottom: 20px;
+  border: 1px solid transparent;
+}
+@media (min-width: 768px) {
+  .navbar {
+    border-radius: 4px;
+  }
+}
+@media (min-width: 768px) {
+  .navbar-header {
+    float: left;
+  }
+}
+.navbar-collapse {
+  padding-right: 15px;
+  padding-left: 15px;
+  overflow-x: visible;
+  -webkit-overflow-scrolling: touch;
+  border-top: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+}
+.navbar-collapse.in {
+  overflow-y: auto;
+}
+@media (min-width: 768px) {
+  .navbar-collapse {
+    width: auto;
+    border-top: 0;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+  }
+  .navbar-collapse.collapse {
+    display: block !important;
+    height: auto !important;
+    padding-bottom: 0;
+    overflow: visible !important;
+  }
+  .navbar-collapse.in {
+    overflow-y: visible;
+  }
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-static-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    padding-right: 0;
+    padding-left: 0;
+  }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+  max-height: 340px;
+}
+@media (max-device-width: 480px) and (orientation: landscape) {
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    max-height: 200px;
+  }
+}
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+@media (min-width: 768px) {
+  .container > .navbar-header,
+  .container-fluid > .navbar-header,
+  .container > .navbar-collapse,
+  .container-fluid > .navbar-collapse {
+    margin-right: 0;
+    margin-left: 0;
+  }
+}
+.navbar-static-top {
+  z-index: 1000;
+  border-width: 0 0 1px;
+}
+@media (min-width: 768px) {
+  .navbar-static-top {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  position: fixed;
+  right: 0;
+  left: 0;
+  z-index: 1030;
+}
+@media (min-width: 768px) {
+  .navbar-fixed-top,
+  .navbar-fixed-bottom {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top {
+  top: 0;
+  border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+  bottom: 0;
+  margin-bottom: 0;
+  border-width: 1px 0 0;
+}
+.navbar-brand {
+  float: left;
+  height: 35px;
+  padding: 7.5px 15px;
+  font-family: Comfortaa, "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 18px;
+  font-weight: bold;
+  line-height: 20px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+  text-decoration: none;
+}
+.navbar-brand > img {
+  display: block;
+}
+@media (min-width: 768px) {
+  .navbar > .container .navbar-brand,
+  .navbar > .container-fluid .navbar-brand {
+    margin-left: -15px;
+  }
+}
+.navbar-toggle {
+  position: relative;
+  float: right;
+  padding: 9px 10px;
+  margin-top: .5px;
+  margin-right: 15px;
+  margin-bottom: .5px;
+  background-color: transparent;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.navbar-toggle:focus {
+  outline: 0;
+}
+.navbar-toggle .icon-bar {
+  display: block;
+  width: 22px;
+  height: 2px;
+  border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+  margin-top: 4px;
+}
+@media (min-width: 768px) {
+  .navbar-toggle {
+    display: none;
+  }
+}
+.navbar-nav {
+  margin: 3.75px -15px;
+}
+.navbar-nav > li > a {
+  padding-top: 10px;
+  padding-bottom: 10px;
+  line-height: 20px;
+}
+@media (max-width: 767px) {
+  .navbar-nav .open .dropdown-menu {
+    position: static;
+    float: none;
+    width: auto;
+    margin-top: 0;
+    background-color: transparent;
+    border: 0;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+  }
+  .navbar-nav .open .dropdown-menu > li > a,
+  .navbar-nav .open .dropdown-menu .dropdown-header {
+    padding: 5px 15px 5px 25px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a {
+    line-height: 20px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-nav .open .dropdown-menu > li > a:focus {
+    background-image: none;
+  }
+}
+@media (min-width: 768px) {
+  .navbar-nav {
+    float: left;
+    margin: 0;
+  }
+  .navbar-nav > li {
+    float: left;
+  }
+  .navbar-nav > li > a {
+    padding-top: 7.5px;
+    padding-bottom: 7.5px;
+  }
+}
+.navbar-form {
+  padding: 10px 15px;
+  margin-top: .5px;
+  margin-right: -15px;
+  margin-bottom: .5px;
+  margin-left: -15px;
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+}
+@media (min-width: 768px) {
+  .navbar-form .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control-static {
+    display: inline-block;
+  }
+  .navbar-form .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .navbar-form .input-group .input-group-addon,
+  .navbar-form .input-group .input-group-btn,
+  .navbar-form .input-group .form-control {
+    width: auto;
+  }
+  .navbar-form .input-group > .form-control {
+    width: 100%;
+  }
+  .navbar-form .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio,
+  .navbar-form .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio label,
+  .navbar-form .checkbox label {
+    padding-left: 0;
+  }
+  .navbar-form .radio input[type="radio"],
+  .navbar-form .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .navbar-form .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+@media (max-width: 767px) {
+  .navbar-form .form-group {
+    margin-bottom: 5px;
+  }
+  .navbar-form .form-group:last-child {
+    margin-bottom: 0;
+  }
+}
+@media (min-width: 768px) {
+  .navbar-form {
+    width: auto;
+    padding-top: 0;
+    padding-bottom: 0;
+    margin-right: 0;
+    margin-left: 0;
+    border: 0;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+  }
+}
+.navbar-nav > li > .dropdown-menu {
+  margin-top: 0;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+  margin-bottom: 0;
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.navbar-btn {
+  margin-top: .5px;
+  margin-bottom: .5px;
+}
+.navbar-btn.btn-sm {
+  margin-top: 2.5px;
+  margin-bottom: 2.5px;
+}
+.navbar-btn.btn-xs {
+  margin-top: 6.5px;
+  margin-bottom: 6.5px;
+}
+.navbar-text {
+  margin-top: 7.5px;
+  margin-bottom: 7.5px;
+}
+@media (min-width: 768px) {
+  .navbar-text {
+    float: left;
+    margin-right: 15px;
+    margin-left: 15px;
+  }
+}
+@media (min-width: 768px) {
+  .navbar-left {
+    float: left !important;
+  }
+  .navbar-right {
+    float: right !important;
+    margin-right: -15px;
+  }
+  .navbar-right ~ .navbar-right {
+    margin-right: 0;
+  }
+}
+.navbar-default {
+  background-color: #f8f8f8;
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+  color: #777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+  color: #5e5e5e;
+  background-color: transparent;
+}
+.navbar-default .navbar-text {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+  color: #333;
+  background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+  color: #db3279;
+  background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+  color: #ccc;
+  background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+  border-color: #ddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+  background-color: #ddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+  background-color: #888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+  color: #db3279;
+  background-color: #e7e7e7;
+}
+@media (max-width: 767px) {
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+    color: #777;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #333;
+    background-color: transparent;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #db3279;
+    background-color: #e7e7e7;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #ccc;
+    background-color: transparent;
+  }
+}
+.navbar-default .navbar-link {
+  color: #777;
+}
+.navbar-default .navbar-link:hover {
+  color: #333;
+}
+.navbar-default .btn-link {
+  color: #777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+  color: #333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+  color: #ccc;
+}
+.navbar-inverse {
+  background-color: #294172;
+  border-color: #1c2c4c;
+}
+.navbar-inverse .navbar-brand {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+  color: #777;
+}
+.navbar-inverse .navbar-nav > li > a {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+  color: #fff;
+  background-color: #1c2c4c;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+  color: #444;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+  border-color: #333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+  background-color: #333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+  background-color: #fff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+  border-color: #203258;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+  color: #fff;
+  background-color: #1c2c4c;
+}
+@media (max-width: 767px) {
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+    border-color: #1c2c4c;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+    background-color: #1c2c4c;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+    color: #9d9d9d;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #fff;
+    background-color: transparent;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #fff;
+    background-color: #1c2c4c;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #444;
+    background-color: transparent;
+  }
+}
+.navbar-inverse .navbar-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-link:hover {
+  color: #fff;
+}
+.navbar-inverse .btn-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+  color: #fff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+  color: #444;
+}
+.breadcrumb {
+  padding: 8px 15px;
+  margin-bottom: 20px;
+  list-style: none;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+}
+.breadcrumb > li {
+  display: inline-block;
+}
+.breadcrumb > li + li:before {
+  padding: 0 5px;
+  color: #ccc;
+  content: "/\00a0";
+}
+.breadcrumb > .active {
+  color: #777;
+}
+.pagination {
+  display: inline-block;
+  padding-left: 0;
+  margin: 20px 0;
+  border-radius: 4px;
+}
+.pagination > li {
+  display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+  position: relative;
+  float: left;
+  padding: 6px 12px;
+  margin-left: -1px;
+  line-height: 1.42857143;
+  color: #428bca;
+  text-decoration: none;
+  background-color: #fff;
+  border: 1px solid #ddd;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+  margin-left: 0;
+  border-top-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+  z-index: 3;
+  color: #2a6496;
+  background-color: #eee;
+  border-color: #ddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+  z-index: 2;
+  color: #fff;
+  cursor: default;
+  background-color: #428bca;
+  border-color: #428bca;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+  color: #777;
+  cursor: not-allowed;
+  background-color: #fff;
+  border-color: #ddd;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+  padding: 10px 16px;
+  font-size: 18px;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+  border-top-left-radius: 6px;
+  border-bottom-left-radius: 6px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+  border-top-right-radius: 6px;
+  border-bottom-right-radius: 6px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+  padding: 5px 10px;
+  font-size: 12px;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+  border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+  border-top-right-radius: 3px;
+  border-bottom-right-radius: 3px;
+}
+.pager {
+  padding-left: 0;
+  margin: 20px 0;
+  text-align: center;
+  list-style: none;
+}
+.pager li {
+  display: inline;
+}
+.pager li > a,
+.pager li > span {
+  display: inline-block;
+  padding: 5px 14px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+  text-decoration: none;
+  background-color: #eee;
+}
+.pager .next > a,
+.pager .next > span {
+  float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+  float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+  color: #777;
+  cursor: not-allowed;
+  background-color: #fff;
+}
+.label {
+  display: inline;
+  padding: .2em .6em .3em;
+  font-size: 75%;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.label:empty {
+  display: none;
+}
+.btn .label {
+  position: relative;
+  top: -1px;
+}
+.label-default {
+  background-color: #777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+  background-color: #5e5e5e;
+}
+.label-primary {
+  background-color: #428bca;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+  background-color: #3071a9;
+}
+.label-success {
+  background-color: #79db32;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+  background-color: #61b921;
+}
+.label-info {
+  background-color: #a07cbc;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+  background-color: #885aab;
+}
+.label-warning {
+  background-color: #e59728;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+  background-color: #c27c18;
+}
+.label-danger {
+  background-color: #db3279;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+  background-color: #b92161;
+}
+.badge {
+  display: inline-block;
+  min-width: 10px;
+  padding: 3px 7px;
+  font-size: 12px;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  background-color: #777;
+  border-radius: 10px;
+}
+.badge:empty {
+  display: none;
+}
+.btn .badge {
+  position: relative;
+  top: -1px;
+}
+.btn-xs .badge,
+.btn-group-xs > .btn .badge {
+  top: 0;
+  padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+  color: #428bca;
+  background-color: #fff;
+}
+.list-group-item > .badge {
+  float: right;
+}
+.list-group-item > .badge + .badge {
+  margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+  margin-left: 3px;
+}
+.jumbotron {
+  padding: 30px 15px;
+  margin-bottom: 30px;
+  color: inherit;
+  background-color: #eee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+  color: inherit;
+}
+.jumbotron p {
+  margin-bottom: 15px;
+  font-size: 21px;
+  font-weight: 200;
+}
+.jumbotron > hr {
+  border-top-color: #d5d5d5;
+}
+.container .jumbotron,
+.container-fluid .jumbotron {
+  border-radius: 6px;
+}
+.jumbotron .container {
+  max-width: 100%;
+}
+@media screen and (min-width: 768px) {
+  .jumbotron {
+    padding: 48px 0;
+  }
+  .container .jumbotron,
+  .container-fluid .jumbotron {
+    padding-right: 60px;
+    padding-left: 60px;
+  }
+  .jumbotron h1,
+  .jumbotron .h1 {
+    font-size: 63px;
+  }
+}
+.thumbnail {
+  display: block;
+  padding: 4px;
+  margin-bottom: 20px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  -webkit-transition: border .2s ease-in-out;
+       -o-transition: border .2s ease-in-out;
+          transition: border .2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+  margin-right: auto;
+  margin-left: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+  border-color: #428bca;
+}
+.thumbnail .caption {
+  padding: 9px;
+  color: #333;
+}
+.alert {
+  padding: 15px;
+  margin-bottom: 20px;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.alert h4 {
+  margin-top: 0;
+  color: inherit;
+}
+.alert .alert-link {
+  font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+  margin-bottom: 0;
+}
+.alert > p + p {
+  margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+  padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+  position: relative;
+  top: -2px;
+  right: -21px;
+  color: inherit;
+}
+.alert-success {
+  color: #3f7815;
+  background-color: #dcf6ca;
+  border-color: #d8f2b4;
+}
+.alert-success hr {
+  border-top-color: #cdee9e;
+}
+.alert-success .alert-link {
+  color: #284d0e;
+}
+.alert-info {
+  color: #603e7a;
+  background-color: #f6f2f8;
+  border-color: #e7e1f0;
+}
+.alert-info hr {
+  border-top-color: #d9d0e7;
+}
+.alert-info .alert-link {
+  color: #452d58;
+}
+.alert-warning {
+  color: #7e500f;
+  background-color: #f8e4c7;
+  border-color: #f6ceb0;
+}
+.alert-warning hr {
+  border-top-color: #f3bf9a;
+}
+.alert-warning .alert-link {
+  color: #51330a;
+}
+.alert-danger {
+  color: #78153f;
+  background-color: #f6cadc;
+  border-color: #f2b4d8;
+}
+.alert-danger hr {
+  border-top-color: #ee9ecd;
+}
+.alert-danger .alert-link {
+  color: #4d0e28;
+}
+@-webkit-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+@-o-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+@keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+.progress {
+  height: 20px;
+  margin-bottom: 20px;
+  overflow: hidden;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+}
+.progress-bar {
+  float: left;
+  width: 0;
+  height: 100%;
+  font-size: 12px;
+  line-height: 20px;
+  color: #fff;
+  text-align: center;
+  background-color: #428bca;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+  -webkit-transition: width .6s ease;
+       -o-transition: width .6s ease;
+          transition: width .6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  -webkit-background-size: 40px 40px;
+          background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+  -webkit-animation: progress-bar-stripes 2s linear infinite;
+       -o-animation: progress-bar-stripes 2s linear infinite;
+          animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar-success {
+  background-color: #79db32;
+}
+.progress-striped .progress-bar-success {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+  background-color: #a07cbc;
+}
+.progress-striped .progress-bar-info {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+  background-color: #e59728;
+}
+.progress-striped .progress-bar-warning {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+  background-color: #db3279;
+}
+.progress-striped .progress-bar-danger {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.media {
+  margin-top: 15px;
+}
+.media:first-child {
+  margin-top: 0;
+}
+.media,
+.media-body {
+  overflow: hidden;
+  zoom: 1;
+}
+.media-body {
+  width: 10000px;
+}
+.media-object {
+  display: block;
+}
+.media-right,
+.media > .pull-right {
+  padding-left: 10px;
+}
+.media-left,
+.media > .pull-left {
+  padding-right: 10px;
+}
+.media-left,
+.media-right,
+.media-body {
+  display: table-cell;
+  vertical-align: top;
+}
+.media-middle {
+  vertical-align: middle;
+}
+.media-bottom {
+  vertical-align: bottom;
+}
+.media-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.media-list {
+  padding-left: 0;
+  list-style: none;
+}
+.list-group {
+  padding-left: 0;
+  margin-bottom: 20px;
+}
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+  margin-bottom: -1px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+}
+.list-group-item:first-child {
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+}
+.list-group-item:last-child {
+  margin-bottom: 0;
+  border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+a.list-group-item {
+  color: #555;
+}
+a.list-group-item .list-group-item-heading {
+  color: #333;
+}
+a.list-group-item:hover,
+a.list-group-item:focus {
+  color: #555;
+  text-decoration: none;
+  background-color: #f5f5f5;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+  color: #777;
+  cursor: not-allowed;
+  background-color: #eee;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+  color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+  color: #777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  z-index: 2;
+  color: #fff;
+  background-color: #428bca;
+  border-color: #428bca;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+  color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+  color: #e1edf7;
+}
+.list-group-item-success {
+  color: #3f7815;
+  background-color: #dcf6ca;
+}
+a.list-group-item-success {
+  color: #3f7815;
+}
+a.list-group-item-success .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-success:hover,
+a.list-group-item-success:focus {
+  color: #3f7815;
+  background-color: #cef2b4;
+}
+a.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus {
+  color: #fff;
+  background-color: #3f7815;
+  border-color: #3f7815;
+}
+.list-group-item-info {
+  color: #603e7a;
+  background-color: #f6f2f8;
+}
+a.list-group-item-info {
+  color: #603e7a;
+}
+a.list-group-item-info .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-info:hover,
+a.list-group-item-info:focus {
+  color: #603e7a;
+  background-color: #e9e1f0;
+}
+a.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus {
+  color: #fff;
+  background-color: #603e7a;
+  border-color: #603e7a;
+}
+.list-group-item-warning {
+  color: #7e500f;
+  background-color: #f8e4c7;
+}
+a.list-group-item-warning {
+  color: #7e500f;
+}
+a.list-group-item-warning .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-warning:hover,
+a.list-group-item-warning:focus {
+  color: #7e500f;
+  background-color: #f6d9b0;
+}
+a.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus {
+  color: #fff;
+  background-color: #7e500f;
+  border-color: #7e500f;
+}
+.list-group-item-danger {
+  color: #78153f;
+  background-color: #f6cadc;
+}
+a.list-group-item-danger {
+  color: #78153f;
+}
+a.list-group-item-danger .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-danger:hover,
+a.list-group-item-danger:focus {
+  color: #78153f;
+  background-color: #f2b4ce;
+}
+a.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus {
+  color: #fff;
+  background-color: #78153f;
+  border-color: #78153f;
+}
+.list-group-item-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.list-group-item-text {
+  margin-bottom: 0;
+  line-height: 1.3;
+}
+.panel {
+  margin-bottom: 20px;
+  background-color: #fff;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+}
+.panel-body {
+  padding: 15px;
+}
+.panel-heading {
+  padding: 10px 15px;
+  border-bottom: 1px solid transparent;
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+  color: inherit;
+}
+.panel-title {
+  margin-top: 0;
+  margin-bottom: 0;
+  font-size: 16px;
+  color: inherit;
+}
+.panel-title > a,
+.panel-title > small,
+.panel-title > .small,
+.panel-title > small > a,
+.panel-title > .small > a {
+  color: inherit;
+}
+.panel-footer {
+  padding: 10px 15px;
+  background-color: #f5f5f5;
+  border-top: 1px solid #ddd;
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+  margin-bottom: 0;
+}
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
+  border-width: 1px 0;
+  border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+  border-top: 0;
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+  border-bottom: 0;
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+  border-top-width: 0;
+}
+.list-group + .panel-footer {
+  border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+  margin-bottom: 0;
+}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+  padding-right: 15px;
+  padding-left: 15px;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+  border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+  border-top-right-radius: 3px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+  border-bottom-right-radius: 3px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+  border-top: 1px solid #ddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+  border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+  border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+  border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+  border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+  border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+  border-bottom: 0;
+}
+.panel > .table-responsive {
+  margin-bottom: 0;
+  border: 0;
+}
+.panel-group {
+  margin-bottom: 20px;
+}
+.panel-group .panel {
+  margin-bottom: 0;
+  border-radius: 4px;
+}
+.panel-group .panel + .panel {
+  margin-top: 5px;
+}
+.panel-group .panel-heading {
+  border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
+  border-top: 1px solid #ddd;
+}
+.panel-group .panel-footer {
+  border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+  border-bottom: 1px solid #ddd;
+}
+.panel-default {
+  border-color: #ddd;
+}
+.panel-default > .panel-heading {
+  color: #333;
+  background-color: #f5f5f5;
+  border-color: #ddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ddd;
+}
+.panel-default > .panel-heading .badge {
+  color: #f5f5f5;
+  background-color: #333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ddd;
+}
+.panel-primary {
+  border-color: #428bca;
+}
+.panel-primary > .panel-heading {
+  color: #fff;
+  background-color: #428bca;
+  border-color: #428bca;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #428bca;
+}
+.panel-primary > .panel-heading .badge {
+  color: #428bca;
+  background-color: #fff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #428bca;
+}
+.panel-success {
+  border-color: #d8f2b4;
+}
+.panel-success > .panel-heading {
+  color: #3f7815;
+  background-color: #dcf6ca;
+  border-color: #d8f2b4;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #d8f2b4;
+}
+.panel-success > .panel-heading .badge {
+  color: #dcf6ca;
+  background-color: #3f7815;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #d8f2b4;
+}
+.panel-info {
+  border-color: #e7e1f0;
+}
+.panel-info > .panel-heading {
+  color: #603e7a;
+  background-color: #f6f2f8;
+  border-color: #e7e1f0;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #e7e1f0;
+}
+.panel-info > .panel-heading .badge {
+  color: #f6f2f8;
+  background-color: #603e7a;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #e7e1f0;
+}
+.panel-warning {
+  border-color: #f6ceb0;
+}
+.panel-warning > .panel-heading {
+  color: #7e500f;
+  background-color: #f8e4c7;
+  border-color: #f6ceb0;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #f6ceb0;
+}
+.panel-warning > .panel-heading .badge {
+  color: #f8e4c7;
+  background-color: #7e500f;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #f6ceb0;
+}
+.panel-danger {
+  border-color: #f2b4d8;
+}
+.panel-danger > .panel-heading {
+  color: #78153f;
+  background-color: #f6cadc;
+  border-color: #f2b4d8;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #f2b4d8;
+}
+.panel-danger > .panel-heading .badge {
+  color: #f6cadc;
+  background-color: #78153f;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #f2b4d8;
+}
+.embed-responsive {
+  position: relative;
+  display: block;
+  height: 0;
+  padding: 0;
+  overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  border: 0;
+}
+.embed-responsive-16by9 {
+  padding-bottom: 56.25%;
+}
+.embed-responsive-4by3 {
+  padding-bottom: 75%;
+}
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border: 1px solid #e3e3e3;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+}
+.well blockquote {
+  border-color: #ddd;
+  border-color: rgba(0, 0, 0, .15);
+}
+.well-lg {
+  padding: 24px;
+  border-radius: 6px;
+}
+.well-sm {
+  padding: 9px;
+  border-radius: 3px;
+}
+.close {
+  float: right;
+  font-size: 21px;
+  font-weight: bold;
+  line-height: 1;
+  color: #000;
+  text-shadow: 0 1px 0 #fff;
+  filter: alpha(opacity=20);
+  opacity: .2;
+}
+.close:hover,
+.close:focus {
+  color: #000;
+  text-decoration: none;
+  cursor: pointer;
+  filter: alpha(opacity=50);
+  opacity: .5;
+}
+button.close {
+  -webkit-appearance: none;
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+}
+.modal-open {
+  overflow: hidden;
+}
+.modal {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1050;
+  display: none;
+  overflow: hidden;
+  -webkit-overflow-scrolling: touch;
+  outline: 0;
+}
+.modal.fade .modal-dialog {
+  -webkit-transition: -webkit-transform .3s ease-out;
+       -o-transition:      -o-transform .3s ease-out;
+          transition:         transform .3s ease-out;
+  -webkit-transform: translate(0, -25%);
+      -ms-transform: translate(0, -25%);
+       -o-transform: translate(0, -25%);
+          transform: translate(0, -25%);
+}
+.modal.in .modal-dialog {
+  -webkit-transform: translate(0, 0);
+      -ms-transform: translate(0, 0);
+       -o-transform: translate(0, 0);
+          transform: translate(0, 0);
+}
+.modal-open .modal {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 10px;
+}
+.modal-content {
+  position: relative;
+  background-color: #fff;
+  -webkit-background-clip: padding-box;
+          background-clip: padding-box;
+  border: 1px solid #999;
+  border: 1px solid rgba(0, 0, 0, .2);
+  border-radius: 6px;
+  outline: 0;
+  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+}
+.modal-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1040;
+  background-color: #000;
+}
+.modal-backdrop.fade {
+  filter: alpha(opacity=0);
+  opacity: 0;
+}
+.modal-backdrop.in {
+  filter: alpha(opacity=50);
+  opacity: .5;
+}
+.modal-header {
+  min-height: 16.42857143px;
+  padding: 15px;
+  border-bottom: 1px solid #e5e5e5;
+}
+.modal-header .close {
+  margin-top: -2px;
+}
+.modal-title {
+  margin: 0;
+  line-height: 1.42857143;
+}
+.modal-body {
+  position: relative;
+  padding: 15px;
+}
+.modal-footer {
+  padding: 15px;
+  text-align: right;
+  border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+  margin-bottom: 0;
+  margin-left: 5px;
+}
+.modal-footer .btn-group .btn + .btn {
+  margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+  margin-left: 0;
+}
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll;
+}
+@media (min-width: 768px) {
+  .modal-dialog {
+    width: 600px;
+    margin: 30px auto;
+  }
+  .modal-content {
+    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+  }
+  .modal-sm {
+    width: 300px;
+  }
+}
+@media (min-width: 992px) {
+  .modal-lg {
+    width: 900px;
+  }
+}
+.tooltip {
+  position: absolute;
+  z-index: 1070;
+  display: block;
+  font-family: Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 12px;
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1.42857143;
+  text-align: left;
+  text-align: start;
+  text-decoration: none;
+  text-shadow: none;
+  text-transform: none;
+  letter-spacing: normal;
+  word-break: normal;
+  word-spacing: normal;
+  word-wrap: normal;
+  white-space: normal;
+  filter: alpha(opacity=0);
+  opacity: 0;
+
+  line-break: auto;
+}
+.tooltip.in {
+  filter: alpha(opacity=90);
+  opacity: .9;
+}
+.tooltip.top {
+  padding: 5px 0;
+  margin-top: -3px;
+}
+.tooltip.right {
+  padding: 0 5px;
+  margin-left: 3px;
+}
+.tooltip.bottom {
+  padding: 5px 0;
+  margin-top: 3px;
+}
+.tooltip.left {
+  padding: 0 5px;
+  margin-left: -3px;
+}
+.tooltip-inner {
+  max-width: 200px;
+  padding: 3px 8px;
+  color: #fff;
+  text-align: center;
+  background-color: #000;
+  border-radius: 4px;
+}
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+  right: 5px;
+  bottom: 0;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+  bottom: 0;
+  left: 5px;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-width: 5px 5px 5px 0;
+  border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-width: 5px 0 5px 5px;
+  border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+  top: 0;
+  right: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+  top: 0;
+  left: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1060;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  font-family: Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1.42857143;
+  text-align: left;
+  text-align: start;
+  text-decoration: none;
+  text-shadow: none;
+  text-transform: none;
+  letter-spacing: normal;
+  word-break: normal;
+  word-spacing: normal;
+  word-wrap: normal;
+  white-space: normal;
+  background-color: #fff;
+  -webkit-background-clip: padding-box;
+          background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, .2);
+  border-radius: 6px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+
+  line-break: auto;
+}
+.popover.top {
+  margin-top: -10px;
+}
+.popover.right {
+  margin-left: 10px;
+}
+.popover.bottom {
+  margin-top: 10px;
+}
+.popover.left {
+  margin-left: -10px;
+}
+.popover-title {
+  padding: 8px 14px;
+  margin: 0;
+  font-size: 14px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  border-radius: 5px 5px 0 0;
+}
+.popover-content {
+  padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.popover > .arrow {
+  border-width: 11px;
+}
+.popover > .arrow:after {
+  content: "";
+  border-width: 10px;
+}
+.popover.top > .arrow {
+  bottom: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-top-color: #999;
+  border-top-color: rgba(0, 0, 0, .25);
+  border-bottom-width: 0;
+}
+.popover.top > .arrow:after {
+  bottom: 1px;
+  margin-left: -10px;
+  content: " ";
+  border-top-color: #fff;
+  border-bottom-width: 0;
+}
+.popover.right > .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-right-color: #999;
+  border-right-color: rgba(0, 0, 0, .25);
+  border-left-width: 0;
+}
+.popover.right > .arrow:after {
+  bottom: -10px;
+  left: 1px;
+  content: " ";
+  border-right-color: #fff;
+  border-left-width: 0;
+}
+.popover.bottom > .arrow {
+  top: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-top-width: 0;
+  border-bottom-color: #999;
+  border-bottom-color: rgba(0, 0, 0, .25);
+}
+.popover.bottom > .arrow:after {
+  top: 1px;
+  margin-left: -10px;
+  content: " ";
+  border-top-width: 0;
+  border-bottom-color: #fff;
+}
+.popover.left > .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-right-width: 0;
+  border-left-color: #999;
+  border-left-color: rgba(0, 0, 0, .25);
+}
+.popover.left > .arrow:after {
+  right: 1px;
+  bottom: -10px;
+  content: " ";
+  border-right-width: 0;
+  border-left-color: #fff;
+}
+.carousel {
+  position: relative;
+}
+.carousel-inner {
+  position: relative;
+  width: 100%;
+  overflow: hidden;
+}
+.carousel-inner > .item {
+  position: relative;
+  display: none;
+  -webkit-transition: .6s ease-in-out left;
+       -o-transition: .6s ease-in-out left;
+          transition: .6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  line-height: 1;
+}
+@media all and (transform-3d), (-webkit-transform-3d) {
+  .carousel-inner > .item {
+    -webkit-transition: -webkit-transform .6s ease-in-out;
+         -o-transition:      -o-transform .6s ease-in-out;
+            transition:         transform .6s ease-in-out;
+
+    -webkit-backface-visibility: hidden;
+            backface-visibility: hidden;
+    -webkit-perspective: 1000px;
+            perspective: 1000px;
+  }
+  .carousel-inner > .item.next,
+  .carousel-inner > .item.active.right {
+    left: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+            transform: translate3d(100%, 0, 0);
+  }
+  .carousel-inner > .item.prev,
+  .carousel-inner > .item.active.left {
+    left: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+            transform: translate3d(-100%, 0, 0);
+  }
+  .carousel-inner > .item.next.left,
+  .carousel-inner > .item.prev.right,
+  .carousel-inner > .item.active {
+    left: 0;
+    -webkit-transform: translate3d(0, 0, 0);
+            transform: translate3d(0, 0, 0);
+  }
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  display: block;
+}
+.carousel-inner > .active {
+  left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+.carousel-inner > .next {
+  left: 100%;
+}
+.carousel-inner > .prev {
+  left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+  left: 0;
+}
+.carousel-inner > .active.left {
+  left: -100%;
+}
+.carousel-inner > .active.right {
+  left: 100%;
+}
+.carousel-control {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  width: 15%;
+  font-size: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+  filter: alpha(opacity=50);
+  opacity: .5;
+}
+.carousel-control.left {
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));
+  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+  background-repeat: repeat-x;
+}
+.carousel-control.right {
+  right: 0;
+  left: auto;
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));
+  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+  background-repeat: repeat-x;
+}
+.carousel-control:hover,
+.carousel-control:focus {
+  color: #fff;
+  text-decoration: none;
+  filter: alpha(opacity=90);
+  outline: 0;
+  opacity: .9;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+  position: absolute;
+  top: 50%;
+  z-index: 5;
+  display: inline-block;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+  left: 50%;
+  margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+  right: 50%;
+  margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+  width: 20px;
+  height: 20px;
+  margin-top: -10px;
+  font-family: serif;
+  line-height: 1;
+}
+.carousel-control .icon-prev:before {
+  content: '\2039';
+}
+.carousel-control .icon-next:before {
+  content: '\203a';
+}
+.carousel-indicators {
+  position: absolute;
+  bottom: 10px;
+  left: 50%;
+  z-index: 15;
+  width: 60%;
+  padding-left: 0;
+  margin-left: -30%;
+  text-align: center;
+  list-style: none;
+}
+.carousel-indicators li {
+  display: inline-block;
+  width: 10px;
+  height: 10px;
+  margin: 1px;
+  text-indent: -999px;
+  cursor: pointer;
+  background-color: #000 \9;
+  background-color: rgba(0, 0, 0, 0);
+  border: 1px solid #fff;
+  border-radius: 10px;
+}
+.carousel-indicators .active {
+  width: 12px;
+  height: 12px;
+  margin: 0;
+  background-color: #fff;
+}
+.carousel-caption {
+  position: absolute;
+  right: 15%;
+  bottom: 20px;
+  left: 15%;
+  z-index: 10;
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+}
+.carousel-caption .btn {
+  text-shadow: none;
+}
+@media screen and (min-width: 768px) {
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-prev,
+  .carousel-control .icon-next {
+    width: 30px;
+    height: 30px;
+    margin-top: -15px;
+    font-size: 30px;
+  }
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .icon-prev {
+    margin-left: -15px;
+  }
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-next {
+    margin-right: -15px;
+  }
+  .carousel-caption {
+    right: 20%;
+    left: 20%;
+    padding-bottom: 30px;
+  }
+  .carousel-indicators {
+    bottom: 20px;
+  }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-footer:before,
+.modal-footer:after {
+  display: table;
+  content: " ";
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-footer:after {
+  clear: both;
+}
+.center-block {
+  display: block;
+  margin-right: auto;
+  margin-left: auto;
+}
+.pull-right {
+  float: right !important;
+}
+.pull-left {
+  float: left !important;
+}
+.hide {
+  display: none !important;
+}
+.show {
+  display: block !important;
+}
+.invisible {
+  visibility: hidden;
+}
+.text-hide {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+.hidden {
+  display: none !important;
+}
+.affix {
+  position: fixed;
+}
+@-ms-viewport {
+  width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+  display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+  display: none !important;
+}
+@media (max-width: 767px) {
+  .visible-xs {
+    display: block !important;
+  }
+  table.visible-xs {
+    display: table !important;
+  }
+  tr.visible-xs {
+    display: table-row !important;
+  }
+  th.visible-xs,
+  td.visible-xs {
+    display: table-cell !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-block {
+    display: block !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-inline {
+    display: inline !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm {
+    display: block !important;
+  }
+  table.visible-sm {
+    display: table !important;
+  }
+  tr.visible-sm {
+    display: table-row !important;
+  }
+  th.visible-sm,
+  td.visible-sm {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-block {
+    display: block !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md {
+    display: block !important;
+  }
+  table.visible-md {
+    display: table !important;
+  }
+  tr.visible-md {
+    display: table-row !important;
+  }
+  th.visible-md,
+  td.visible-md {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-block {
+    display: block !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg {
+    display: block !important;
+  }
+  table.visible-lg {
+    display: table !important;
+  }
+  tr.visible-lg {
+    display: table-row !important;
+  }
+  th.visible-lg,
+  td.visible-lg {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-block {
+    display: block !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (max-width: 767px) {
+  .hidden-xs {
+    display: none !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .hidden-sm {
+    display: none !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .hidden-md {
+    display: none !important;
+  }
+}
+@media (min-width: 1200px) {
+  .hidden-lg {
+    display: none !important;
+  }
+}
+.visible-print {
+  display: none !important;
+}
+@media print {
+  .visible-print {
+    display: block !important;
+  }
+  table.visible-print {
+    display: table !important;
+  }
+  tr.visible-print {
+    display: table-row !important;
+  }
+  th.visible-print,
+  td.visible-print {
+    display: table-cell !important;
+  }
+}
+.visible-print-block {
+  display: none !important;
+}
+@media print {
+  .visible-print-block {
+    display: block !important;
+  }
+}
+.visible-print-inline {
+  display: none !important;
+}
+@media print {
+  .visible-print-inline {
+    display: inline !important;
+  }
+}
+.visible-print-inline-block {
+  display: none !important;
+}
+@media print {
+  .visible-print-inline-block {
+    display: inline-block !important;
+  }
+}
+@media print {
+  .hidden-print {
+    display: none !important;
+  }
+}
+/*# sourceMappingURL=bootstrap.css.map */
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css.map b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css.map
new file mode 100644
index 0000000..5683d20
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["bootstrap.css","less/normalize.less","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/mixins/reset-text.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"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kBAAA;EHiR9C;AGhRmC;EAAW,kBAAA;EHmR9C;AGlRmC;EAAW,kBAAA;EHqR9C;AGpRmC;EAAW,kBAAA;EHuR9C;AGtRmC;EAAW,kBAAA;EHyR9C;AGxRmC;EAAW,kBAAA;EH2R9C;AG1RmC;EAAW,kBAAA;EH6R9C;AG5RmC;EAAW,kBAAA;EH+R9C;AG9RmC;EAAW,kBAAA;EHiS9C;AGhSmC;EAAW,kBAAA;EHmS9C;AGlSmC;EAAW,kBAAA;EHqS9C;AGpSmC;EAAW,kBAAA;EHuS9C;AGtSmC;EAAW,kBAAA;EHyS9C;AGxSmC;EAAW,kBAAA;EH2S9C;AG1SmC;EAAW,kBAAA;EH6S9C;AG5SmC;EAAW,kBAAA;EH+S9C;AG9SmC;EAAW,kBAAA;EHiT9C;AGhTmC;EAAW,kBAAA;EHmT9C;AGlTmC;EAAW,kBAAA;EHqT9C;AGpTmC;EAAW,kBAAA;EHuT9C;AGtTmC;EAAW,kBAAA;EHyT9C;AGxTmC;EAAW,kBAAA;EH2T9C;AG1TmC;EAAW,kBAAA;EH6T9C;AG5TmC;EAAW,kBAAA;EH+T9C;AG9TmC;EAAW,kBAAA;EHiU9C;AGhUmC;EAAW,kBAAA;EHmU9C;AGlUmC;EAAW,kBAAA;EHqU9C;AGpUmC;EAAW,kBAAA;EHuU9C;AGtUmC;EAAW,kBAAA;EHyU9C;AGxUmC;EAAW,kBAAA;EH2U9C;AG1UmC;EAAW,kBAAA;EH6U9C;AG5UmC;EAAW,kBAAA;EH+U9C;AG9UmC;EAAW,kBAAA;EHiV9C;AGhVmC;EAAW,kBAAA;EHmV9C;AGlVmC;EAAW,kBAAA;EHqV9C;AGpVmC;EAAW,kBAAA;EHuV9C;AGtVmC;EAAW,kBAAA;EHyV9C;AGxVmC;EAAW,kBAAA;EH2V9C;AG1VmC;EAAW,kBAAA;EH6V9C;AG5VmC;EAAW,kBAAA;EH+V9C;AG9VmC;EAAW,kBAAA;EHiW9C;AGhWmC;EAAW,kBAAA;EHmW9C;AGlWmC;EAAW,kBAAA;EHqW9C;AGpWmC;EAAW,kBAAA;EHuW9C;AGtWmC;EAAW,kBAAA;EHyW9C;AGxWmC;EAAW,kBAAA;EH2W9C;AG1WmC;EAAW,kBAAA;EH6W9C;AG5WmC;EAAW,kBAAA;EH+W9C;AG9WmC;EAAW,kBAAA;EHiX9C;AGhXmC;EAAW,kBAAA;EHmX9C;AGlXmC;EAAW,kBAAA;EHqX9C;AGpXmC;EAAW,kBAAA;EHuX9C;AGtXmC;EAAW,kBAAA;EHyX9C;AGxXmC;EAAW,kBAAA;EH2X9C;AG1XmC;EAAW,kBAAA;EH6X9C;AG5XmC;EAAW,kBAAA;EH+X9C;AG9XmC;EAAW,kBAAA;EHiY9C;AGhYmC;EAAW,kBAAA;EHmY9C;AGlYmC;EAAW,kBAAA;EHqY9C;AGpYmC;EAAW,kBAAA;EHuY9C;AGtYmC;EAAW,kBAAA;EHyY9C;AGxYmC;EAAW,kBAAA;EH2Y9C;AG1YmC;EAAW,kBAAA;EH6Y9C;AG5YmC;EAAW,kBAAA;EH+Y9C;AG9YmC;EAAW,kBAAA;EHiZ9C;AGhZmC;EAAW,kBAAA;EHmZ9C;AGlZmC;EAAW,kBAAA;EHqZ9C;AGpZmC;EAAW,kBAAA;EHuZ9C;AGtZmC;EAAW,kBAAA;EHyZ9C;AGxZmC;EAAW,kBAAA;EH2Z9C;AG1ZmC;EAAW,kBAAA;EH6Z9C;AG5ZmC;EAAW,kBAAA;EH+Z9C;AG9ZmC;EAAW,kBAAA;EHia9C;AGhamC;EAAW,kBAAA;EHma9C;AGlamC;EAAW,kBAAA;EHqa9C;AGpamC;EAAW,kBAAA;EHua9C;AGtamC;EAAW,kBAAA;EHya9C;AGxamC;EAAW,kBAAA;EH2a9C;AG1amC;EAAW,kBAAA;EH6a9C;AG5amC;EAAW,kBAAA;EH+a9C;AG9amC;EAAW,kBAAA;EHib9C;AGhbmC;EAAW,kBAAA;EHmb9C;AGlbmC;EAAW,kBAAA;EHqb9C;AGpbmC;EAAW,kBAAA;EHub9C;AGtbmC;EAAW,kBAAA;EHyb9C;AGxbmC;EAAW,kBAAA;EH2b9C;AG1bmC;EAAW,kBAAA;EH6b9C;AG5bmC;EAAW,kBAAA;EH+b9C;AG9bmC;EAAW,kBAAA;EHic9C;AGhcmC;EAAW,kBAAA;EHmc9C;AGlcmC;EAAW,kBAAA;EHqc9C;AGpcmC;EAAW,kBAAA;EHuc9C;AGtcmC;EAAW,kBAAA;EHyc9C;AGxcmC;EAAW,kBAAA;EH2c9C;AG1cmC;EAAW,kBAAA;EH6c9C;AG5cmC;EAAW,kBAAA;EH+c9C;AG9cmC;EAAW,kBAAA;EHid9C;AGhdmC;EAAW,kBAAA;EHmd9C;AGldmC;EAAW,kBAAA;EHqd9C;AGpdmC;EAAW,kBAAA;EHud9C;AGtdmC;EAAW,kBAAA;EHyd9C;AGxdmC;EAAW,kBAAA;EH2d9C;AG1dmC;EAAW,kBAAA;EH6d9C;AG5dmC;EAAW,kBAAA;EH+d9C;AG9dmC;EAAW,kBAAA;EHie9C;AGhemC;EAAW,kBAAA;EHme9C;AGlemC;EAAW,kBAAA;EHqe9C;AGpemC;EAAW,kBAAA;EHue9C;AGtemC;EAAW,kBAAA;EHye9C;AGxemC;EAAW,kBAAA;EH2e9C;AG1emC;EAAW,kBAAA;EH6e9C;AG5emC;EAAW,kBAAA;EH+e9C;AG9emC;EAAW,kBAAA;EHif9C;AGhfmC;EAAW,kBAAA;EHmf9C;AGlfmC;EAAW,kBAAA;EHqf9C;AGpfmC;EAAW,kBAAA;EHuf9C;AGtfmC;EAAW,kBAAA;EHyf9C;AGxfmC;EAAW,kBAAA;EH2f9C;AG1fmC;EAAW,kBAAA;EH6f9C;AG5fmC;EAAW,kBAAA;EH+f9C;AG9fmC;EAAW,kBAAA;EHigB9C;AGhgBmC;EAAW,kBAAA;EHmgB9C;AGlgBmC;EAAW,kBAAA;EHqgB9C;AGpgBmC;EAAW,kBAAA;EHugB9C;AGtgBmC;EAAW,kBAAA;EHygB9C;AGxgBmC;EAAW,kBAAA;EH2gB9C;AG1gBmC;EAAW,kBAAA;EH6gB9C;AG5gBmC;EAAW,kBAAA;EH+gB9C;AG9gBmC;EAAW,kBAAA;EHihB9C;AGhhBmC;EAAW,kBAAA;EHmhB9C;AGlhBmC;EAAW,kBAAA;EHqhB9C;AGphBmC;EAAW,kBAAA;EHuhB9C;AGthBmC;EAAW,kBAAA;EHyhB9C;AGxhBmC;EAAW,kBAAA;EH2hB9C;AG1hBmC;EAAW,kBAAA;EH6hB9C;AG5hBmC;EAAW,kBAAA;EH+hB9C;AG9hBmC;EAAW,kBAAA;EHiiB9C;AGhiBmC;EAAW,kBAAA;EHmiB9C;AGliBmC;EAAW,kBAAA;EHqiB9C;AGpiBmC;EAAW,kBAAA;EHuiB9C;AGtiBmC;EAAW,kBAAA;EHyiB9C;AGxiBmC;EAAW,kBAAA;EH2iB9C;AG1iBmC;EAAW,kBAAA;EH6iB9C;AG5iBmC;EAAW,kBAAA;EH+iB9C;AG9iBmC;EAAW,kBAAA;EHijB9C;AGhjBmC;EAAW,kBAAA;EHmjB9C;AGljBmC;EAAW,kBAAA;EHqjB9C;AGpjBmC;EAAW,kBAAA;EHujB9C;AGtjBmC;EAAW,kBAAA;EHyjB9C;AGxjBmC;EAAW,kBAAA;EH2jB9C;AG1jBmC;EAAW,kBAAA;EH6jB9C;AG5jBmC;EAAW,kBAAA;EH+jB9C;AG9jBmC;EAAW,kBAAA;EHikB9C;AGhkBmC;EAAW,kBAAA;EHmkB9C;AGlkBmC;EAAW,kBAAA;EHqkB9C;AGpkBmC;EAAW,kBAAA;EHukB9C;AGtkBmC;EAAW,kBAAA;EHykB9C;AGxkBmC;EAAW,kBAAA;EH2kB9C;AG1kBmC;EAAW,kBAAA;EH6kB9C;AG5kBmC;EAAW,kBAAA;EH+kB9C;AG9kBmC;EAAW,kBAAA;EHilB9C;AGhlBmC;EAAW,kBAAA;EHmlB9C;AGllBmC;EAAW,kBAAA;EHqlB9C;AGplBmC;EAAW,kBAAA;EHulB9C;AGtlBmC;EAAW,kBAAA;EHylB9C;AGxlBmC;EAAW,kBAAA;EH2lB9C;AG1lBmC;EAAW,kBAAA;EH6lB9C;AG5lBmC;EAAW,kBAAA;EH+lB9C;AG9lBmC;EAAW,kBAAA;EHimB9C;AGhmBmC;EAAW,kBAAA;EHmmB9C;AGlmBmC;EAAW,kBAAA;EHqmB9C;AGpmBmC;EAAW,kBAAA;EHumB9C;AGtmBmC;EAAW,kBAAA;EHymB9C;AGxmBmC;EAAW,kBAAA;EH2mB9C;AG1mBmC;EAAW,kBAAA;EH6mB9C;AG5mBmC;EAAW,kBAAA;EH+mB9C;AG9mBmC;EAAW,kBAAA;EHinB9C;AGhnBmC;EAAW,kBAAA;EHmnB9C;AGlnBmC;EAAW,kBAAA;EHqnB9C;AGpnBmC;EAAW,kBAAA;EHunB9C;AGtnBmC;EAAW,kBAAA;EHynB9C;AGxnBmC;EAAW,kBAAA;EH2nB9C;AG1nBmC;EAAW,kBAAA;EH6nB9C;AG5nBmC;EAAW,kBAAA;EH+nB9C;AG9nBmC;EAAW,kBAAA;EHioB9C;AGhoBmC;EAAW,kBAAA;EHmoB9C;AG1nBmC;EAAW,kBAAA;EH6nB9C;AG5nBmC;EAAW,kBAAA;EH+nB9C;AG9nBmC;EAAW,kBAAA;EHioB9C;AGhoBmC;EAAW,kBAAA;EHmoB9C;AGloBmC;EAAW,kBAAA;EHqoB9C;AGpoBmC;EAAW,kBAAA;EHuoB9C;AGtoBmC;EAAW,kBAAA;EHyoB9C;AGxoBmC;EAAW,kBAAA;EH2oB9C;AG1oBmC;EAAW,kBAAA;EH6oB9C;AG5oBmC;EAAW,kBAAA;EH+oB9C;AG9oBmC;EAAW,kBAAA;EHipB9C;AGhpBmC;EAAW,kBAAA;EHmpB9C;AGlpBmC;EAAW,kBAAA;EHqpB9C;AGppBmC;EAAW,kBAAA;EHupB9C;AGtpBmC;EAAW,kBAAA;EHypB9C;AGxpBmC;EAAW,kBAAA;EH2pB9C;AG1pBmC;EAAW,kBAAA;EH6pB9C;AG5pBmC;EAAW,kBAAA;EH+pB9C;AG9pBmC;EAAW,kBAAA;EHiqB9C;AGhqBmC;EAAW,kBAAA;EHmqB9C;AGlqBmC;EAAW,kBAAA;EHqqB9C;AGpqBmC;EAAW,kBAAA;EHuqB9C;AGtqBmC;EAAW,kBAAA;EHyqB9C;AGxqBmC;EAAW,kBAAA;EH2qB9C;AG1qBmC;EAAW,kBAAA;EH6qB9C;AG5qBmC;EAAW,kBAAA;EH+qB9C;AG9qBmC;EAAW,kBAAA;EHirB9C;AGhrBmC;EAAW,kBAAA;EHmrB9C;AGlrBmC;EAAW,kBAAA;EHqrB9C;AGprBmC;EAAW,kBAAA;EHurB9C;AGtrBmC;EAAW,kBAAA;EHyrB9C;AGxrBmC;EAAW,kBAAA;EH2rB9C;AG1rBmC;EAAW,kBAAA;EH6rB9C;AG5rBmC;EAAW,kBAAA;EH+rB9C;AG9rBmC;EAAW,kBAAA;EHisB9C;AGhsBmC;EAAW,kBAAA;EHmsB9C;AGlsBmC;EAAW,kBAAA;EHqsB9C;AGpsBmC;EAAW,kBAAA;EHusB9C;AGtsBmC;EAAW,kBAAA;EHysB9C;AGxsBmC;EAAW,kBAAA;EH2sB9C;AG1sBmC;EAAW,kBAAA;EH6sB9C;AG5sBmC;EAAW,kBAAA;EH+sB9C;AG9sBmC;EAAW,kBAAA;EHitB9C;AGhtBmC;EAAW,kBAAA;EHmtB9C;AGltBmC;EAAW,kBAAA;EHqtB9C;AGptBmC;EAAW,kBA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EfgkDH;AejkDC;EACE,qBAAA;EfmkDH;AepkDC;EACE,qBAAA;EfskDH;AevkDC;EACE,YAAA;EfykDH;Ae1kDC;EACE,qBAAA;Ef4kDH;Ae7kDC;EACE,oBAAA;Ef+kDH;Ae3kDC;EACE,aAAA;Ef6kDH;Ae7lDC;EACE,YAAA;Ef+lDH;AehmDC;EACE,oBAAA;EfkmDH;AenmDC;EACE,oBAAA;EfqmDH;AetmDC;EACE,WAAA;EfwmDH;AezmDC;EACE,oBAAA;Ef2mDH;Ae5mDC;EACE,oBAAA;Ef8mDH;Ae/mDC;EACE,WAAA;EfinDH;AelnDC;EACE,oBAAA;EfonDH;AernDC;EACE,oBAAA;EfunDH;AexnDC;EACE,WAAA;Ef0nDH;Ae3nDC;EACE,oBAAA;Ef6nDH;Ae9nDC;EACE,mBAAA;EfgoDH;Ae5nDC;EACE,YAAA;Ef8nDH;AehnDC;EACE,mBAAA;EfknDH;AennDC;EACE,2BAAA;EfqnDH;AetnDC;EACE,2BAAA;EfwnDH;AeznDC;EACE,kBAAA;Ef2nDH;Ae5nDC;EACE,2BAAA;Ef8nDH;Ae/nDC;EACE,2BAAA;EfioDH;AeloDC;EACE,kBAAA;EfooDH;AeroDC;EACE,2BAAA;EfuoDH;AexoDC;EACE,2BAAA;Ef0oDH;Ae3oDC;EACE,kBAAA;Ef6oDH;Ae9oDC;EACE,2BAAA;EfgpDH;AejpDC;EACE,0BAAA;EfmpDH;AeppDC;EACE,iBAAA;EfspDH;AatpDD;EElCI;IACE,aAAA;If2rDH;EeprDD;IACE,aAAA;IfsrDD;EevrDD;IACE,qBAAA;IfyrDD;Ee1rDD;IACE,qBAAA;If4rDD;Ee7rDD;IACE,YAAA;If+rDD;EehsDD;IACE,qBAAA;IfksDD;EensDD;IACE,qBAAA;IfqsDD;EetsDD;IACE,YAAA;IfwsDD;EezsDD;IACE,qBAAA;If2sDD;Ee5sDD;IACE,qBAAA;If8sDD;Ee/sDD;IACE,YAAA;IfitDD;EeltDD;IACE,qBAAA;IfotDD;EertDD;IACE,oBAAA;IfutDD;EezsDD;IACE,aAAA;If2sDD;Ee5sDD;IACE,qBAAA;If8sDD;Ee/sDD;IACE,qBAAA;IfitDD;EeltDD;IACE,YAAA;IfotDD;EertDD;IACE,qBAAA;IfutDD;EextDD;IACE,qBAAA;If0tDD;Ee3tDD;IACE,YAAA;If6tDD;Ee9tDD;IACE,qBAAA;IfguDD;EejuDD;IACE,qBAAA;IfmuDD;EepuDD;IACE,YAAA;IfsuDD;EevuDD;IACE,qBAAA;IfyuDD;Ee1uDD;IACE,oBAAA;If4uDD;EexuDD;IACE,aAAA;If0uDD;Ee1vDD;IACE,YAAA;If4vDD;Ee7vDD;IACE,oBAAA;If+vDD;EehwDD;IACE,oBAAA;IfkwDD;EenwDD;IACE,WAAA;IfqwDD;EetwDD;IACE,oBAAA;IfwwDD;EezwDD;IACE,oBAAA;If2wDD;Ee5wDD;IACE,WAAA;If8wDD;Ee/wDD;IACE,oBAAA;IfixDD;EelxDD;IACE,oBAAA;IfoxDD;EerxDD;IACE,WAAA;IfuxDD;EexxDD;IACE,oBAAA;If0xDD;Ee3xDD;IACE,mBAAA;If6xDD;EezxDD;IACE,YAAA;If2xDD;Ee7wDD;IACE,mBAAA;If+wDD;EehxDD;IACE,2BAAA;IfkxDD;EenxDD;IACE,2BAAA;IfqxDD;EetxDD;IACE,kBAAA;IfwxDD;EezxDD;IACE,2BAAA;If2xDD;Ee5xDD;IACE,2BAAA;If8xDD;Ee/xDD;IACE,kBAAA;IfiyDD;EelyDD;IACE,2BAAA;IfoyDD;EeryDD;IACE,2BAAA;IfuyDD;EexyDD;IACE,kBAAA;If0yDD;Ee3yDD;IACE,2BAAA;If6yDD;Ee9yDD;IACE,0BAAA;IfgzDD;EejzDD;IACE,iBAAA;IfmzDD;EACF;Aa3yDD;EE3CI;IACE,aAAA;Ify1DH;Eel1DD;IACE,aAAA;Ifo1DD;Eer1DD;IACE,qBAAA;Ifu1DD;Eex1DD;IACE,qBAAA;If01DD;Ee31DD;IACE,YAAA;If61DD;Ee91DD;IACE,qBAAA;Ifg2DD;Eej2DD;IACE,qBAAA;Ifm2DD;Eep2DD;IACE,YAAA;Ifs2DD;Eev2DD;IACE,qBAAA;Ify2DD;Ee12DD;IACE,qBAAA;If42DD;Ee72DD;IACE,YAAA;If+2DD;Eeh3DD;IACE,qBAAA;Ifk3DD;Een3DD;IACE,oBAAA;Ifq3DD;Eev2DD;IACE,aAAA;Ify2DD;Ee12DD;IACE,qBAAA;If42DD;Ee72DD;IACE,qBAAA;If+2DD;Eeh3DD;IACE,YAAA;Ifk3DD;Een3DD;IACE,qBAAA;Ifq3DD;Eet3DD;IACE,qBAAA;Ifw3DD;Eez3DD;IACE,YAAA;If23DD;Ee53DD;IACE,qBAAA;If83DD;Ee/3DD;IACE,qBAAA;Ifi4DD;Eel4DD;IACE,YAAA;Ifo4DD;Eer4DD;IACE,qBAAA;Ifu4DD;Eex4DD;IACE,oBAAA;If04DD;Eet4DD;IACE,aAAA;Ifw4DD;Eex5DD;IACE,YAAA;If05DD;Ee35DD;IACE,oBAAA;If65DD;Ee95DD;IACE,oBAAA;Ifg6DD;Eej6DD;IACE,WAAA;Ifm6DD;Eep6DD;IACE,oBAAA;Ifs6DD;Eev6DD;IACE,oBAAA;Ify6DD;Ee16DD;IACE,WAAA;If46DD;Ee76DD;IACE,oBAAA;If+6DD;Eeh7DD;IACE,oBAAA;Ifk7DD;Een7DD;IACE,WAAA;Ifq7DD;Eet7DD;IACE,oBAAA;Ifw7DD;Eez7DD;IACE,mBAAA;If27DD;Eev7DD;IACE,YAAA;Ify7DD;Ee36DD;IACE,mBAAA;If66DD;Ee96DD;IACE,2BAAA;Ifg7DD;Eej7DD;IACE,2BAAA;Ifm7DD;Eep7DD;IACE,kBAAA;Ifs7DD;Eev7DD;IACE,2BAAA;Ify7DD;Ee17DD;IACE,2BAAA;If47DD;Ee77DD;IACE,kBAAA;If+7DD;Eeh8DD;IACE,2BAAA;Ifk8DD;Een8DD;IACE,2BAAA;Ifq8DD;Eet8DD;IACE,kBAAA;Ifw8DD;Eez8DD;IACE,2BAAA;If28DD;Ee58DD;IACE,0BAAA;If88DD;Ee/8DD;IACE,iBAAA;Ifi9DD;EACF;Aat8DD;EE9CI;IACE,aAAA;Ifu/DH;Eeh/DD;IACE,aAAA;Ifk/DD;Een/DD;IACE,qBAAA;Ifq/DD;Eet/DD;IACE,qBAAA;Ifw/DD;Eez/DD;IACE,YAAA;If2/DD;Ee5/DD;IACE,qBAAA;If8/DD;Ee//DD;IACE,qBAAA;IfigED;EelgED;IACE,YAAA;IfogED;EergED;IACE,qBAAA;IfugED;EexgED;IACE,qBAAA;If0gED;Ee3gED;IACE,YAAA;If6gED;Ee9gED;IACE,qBAAA;IfghED;EejhED;IACE,oBAAA;IfmhED;EergED;IACE,aAAA;IfugED;EexgED;IACE,qBAAA;If0gED;Ee3gED;IACE,qBAAA;If6gED;Ee9gED;IACE,YAAA;IfghED;EejhED;IACE,qBAAA;IfmhED;EephED;IACE,qBAAA;IfshED;EevhED;IACE,YAAA;IfyhED;Ee1hED;IACE,qBAAA;If4hED;Ee7hED;IACE,qBAAA;If+hED;EehiED;IACE,YAAA;IfkiED;EeniED;IACE,qBAAA;IfqiED;EetiED;IACE,oBAAA;IfwiED;EepiED;IACE,aAAA;IfsiED;EetjED;IACE,YAAA;IfwjED;EezjED;IACE,oBAAA;If2jED;Ee5jED;IACE,oBAAA;If8jED;Ee/jED;IACE,WAAA;IfikED;EelkED;IACE,oBAAA;IfokED;EerkED;IACE,oBAAA;IfukED;EexkED;IACE,WAAA;If0kED;Ee3kED;IACE,oBAAA;If6kED;Ee9kED;IACE,oBAAA;IfglED;EejlED;IACE,WAAA;IfmlED;EeplED;IACE,oBAAA;IfslED;EevlED;IACE,mBAAA;IfylED;EerlED;IACE,YAAA;IfulED;EezkED;IACE,mBAAA;If2kED;Ee5kED;IACE,2BAAA;If8kED;Ee/kED;IACE,2BAAA;IfilED;EellED;IACE,kBAAA;IfolED;EerlED;IACE,2BAAA;IfulED;EexlED;IACE,2BAAA;If0lED;Ee3lED;IACE,kBAAA;If6lED;Ee9lED;IACE,2BAAA;IfgmED;EejmED;IACE,2BAAA;IfmmED;EepmED;IACE,kBAAA;IfsmED;EevmED;IACE,2BAAA;IfymED;Ee1mED;IACE,0BAAA;If4mED;Ee7mED;IACE,iBAAA;If+mED;EACF;AgBnrED;EACE,+BAAA;EhBqrED;AgBnrED;EACE,kBAAA;EACA,qBAAA;EACA,gBAAA;EACA,kBAAA;EhBqrED;AgBnrED;EACE,kBAAA;EhBqrE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","file":"bootstrap.css","sourcesContent":["/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n  font-family: sans-serif;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\nbody {\n  margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n[hidden],\ntemplate {\n  display: none;\n}\na {\n  background-color: transparent;\n}\na:active,\na:hover {\n  outline: 0;\n}\nabbr[title] {\n  border-bottom: 1px dotted;\n}\nb,\nstrong {\n  font-weight: bold;\n}\ndfn {\n  font-style: italic;\n}\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\nmark {\n  background: #ff0;\n  color: #000;\n}\nsmall {\n  font-size: 80%;\n}\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\nsup {\n  top: -0.5em;\n}\nsub {\n  bottom: -0.25em;\n}\nimg {\n  border: 0;\n}\nsvg:not(:root) {\n  overflow: hidden;\n}\nfigure {\n  margin: 1em 40px;\n}\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\npre {\n  overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit;\n  font: inherit;\n  margin: 0;\n}\nbutton {\n  overflow: visible;\n}\nbutton,\nselect {\n  text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\ninput {\n  line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: textfield;\n  box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n  border: 0;\n  padding: 0;\n}\ntextarea {\n  overflow: auto;\n}\noptgroup {\n  font-weight: bold;\n}\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\ntd,\nth {\n  padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n  *,\n  *:before,\n  *:after {\n    background: transparent !important;\n    color: #000 !important;\n    box-shadow: none !important;\n    text-shadow: none !important;\n  }\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  a[href^=\"#\"]:after,\n  a[href^=\"javascript:\"]:after {\n    content: \"\";\n  }\n  pre,\n  blockquote {\n    border: 1px solid #999;\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  img {\n    max-width: 100% !important;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n  .navbar {\n    display: none;\n  }\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .label {\n    border: 1px solid #000;\n  }\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: url('../fonts/glyphicons-halflings-regular.eot');\n  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n  content: \"\\2a\";\n}\n.glyphicon-plus:before {\n  content: \"\\2b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n  content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n.glyphicon-cd:before {\n  content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n  content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n  content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n  content: \"\\e204\";\n}\n.glyphicon-copy:before {\n  content: \"\\e205\";\n}\n.glyphicon-paste:before {\n  content: \"\\e206\";\n}\n.glyphicon-alert:before {\n  content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n  content: \"\\e210\";\n}\n.glyphicon-king:before {\n  content: \"\\e211\";\n}\n.glyphicon-queen:before {\n  content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n  content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n  content: \"\\e214\";\n}\n.glyphicon-knight:before {\n  content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n  content: \"\\e216\";\n}\n.glyphicon-tent:before {\n  content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n  content: \"\\e218\";\n}\n.glyphicon-bed:before {\n  content: \"\\e219\";\n}\n.glyphicon-apple:before {\n  content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n  content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n  content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n  content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n  content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n  content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n  content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n  content: \"\\e227\";\n}\n.glyphicon-btc:before {\n  content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n  content: \"\\e227\";\n}\n.glyphicon-yen:before {\n  content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n  content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n  content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n  content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n  content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n  content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n  content: \"\\e232\";\n}\n.glyphicon-education:before {\n  content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n  content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n  content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n  content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n  content: \"\\e237\";\n}\n.glyphicon-oil:before {\n  content: \"\\e238\";\n}\n.glyphicon-grain:before {\n  content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n  content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n  content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n  content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n  content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n  content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n  content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n  content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n  content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n  content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n  content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n  content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n  content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n  content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n  content: \"\\e253\";\n}\n.glyphicon-console:before {\n  content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n  content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n  content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n  content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n  content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n  content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n  content: \"\\e260\";\n}\n* {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\nhtml {\n  font-size: 10px;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n  font-family: Cantarell, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #333333;\n  background-color: #ffffff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\na {\n  color: #428bca;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #2a6496;\n  text-decoration: underline;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\nfigure {\n  margin: 0;\n}\nimg {\n  vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.img-rounded {\n  border-radius: 6px;\n}\n.img-thumbnail {\n  padding: 4px;\n  line-height: 1.42857143;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 4px;\n  -webkit-transition: all 0.2s ease-in-out;\n  -o-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n}\n.img-circle {\n  border-radius: 50%;\n}\nhr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n  position: static;\n  width: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  clip: auto;\n}\n[role=\"button\"] {\n  cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n  font-family: inherit;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n  font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n  font-size: 75%;\n}\nh1,\n.h1 {\n  font-size: 36px;\n}\nh2,\n.h2 {\n  font-size: 30px;\n}\nh3,\n.h3 {\n  font-size: 24px;\n}\nh4,\n.h4 {\n  font-size: 18px;\n}\nh5,\n.h5 {\n  font-size: 14px;\n}\nh6,\n.h6 {\n  font-size: 12px;\n}\np {\n  margin: 0 0 10px;\n}\n.lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 21px;\n  }\n}\nsmall,\n.small {\n  font-size: 85%;\n}\nmark,\n.mark {\n  background-color: #f8e4c7;\n  padding: .2em;\n}\n.text-left {\n  text-align: left;\n}\n.text-right {\n  text-align: right;\n}\n.text-center {\n  text-align: center;\n}\n.text-justify {\n  text-align: justify;\n}\n.text-nowrap {\n  white-space: nowrap;\n}\n.text-lowercase {\n  text-transform: lowercase;\n}\n.text-uppercase {\n  text-transform: uppercase;\n}\n.text-capitalize {\n  text-transform: capitalize;\n}\n.text-muted {\n  color: #777777;\n}\n.text-primary {\n  color: #428bca;\n}\na.text-primary:hover,\na.text-primary:focus {\n  color: #3071a9;\n}\n.text-success {\n  color: #3f7815;\n}\na.text-success:hover,\na.text-success:focus {\n  color: #284d0e;\n}\n.text-info {\n  color: #603e7a;\n}\na.text-info:hover,\na.text-info:focus {\n  color: #452d58;\n}\n.text-warning {\n  color: #7e500f;\n}\na.text-warning:hover,\na.text-warning:focus {\n  color: #51330a;\n}\n.text-danger {\n  color: #78153f;\n}\na.text-danger:hover,\na.text-danger:focus {\n  color: #4d0e28;\n}\n.bg-primary {\n  color: #fff;\n  background-color: #428bca;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n  background-color: #3071a9;\n}\n.bg-success {\n  background-color: #dcf6ca;\n}\na.bg-success:hover,\na.bg-success:focus {\n  background-color: #c0ee9e;\n}\n.bg-info {\n  background-color: #f6f2f8;\n}\na.bg-info:hover,\na.bg-info:focus {\n  background-color: #ddd0e7;\n}\n.bg-warning {\n  background-color: #f8e4c7;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n  background-color: #f3ce9a;\n}\n.bg-danger {\n  background-color: #f6cadc;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n  background-color: #ee9ec0;\n}\n.page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n  margin-bottom: 0;\n}\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.list-inline {\n  padding-left: 0;\n  list-style: none;\n  margin-left: -5px;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\ndl {\n  margin-top: 0;\n  margin-bottom: 20px;\n}\ndt,\ndd {\n  line-height: 1.42857143;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    clear: left;\n    text-align: right;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #777777;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\nblockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  font-size: 17.5px;\n  border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.42857143;\n  color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n  text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n  content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\naddress {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #ffffff;\n  background-color: #333333;\n  border-radius: 3px;\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: bold;\n  box-shadow: none;\n}\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: #333333;\n  background-color: #f5f5f5;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n}\npre code {\n  padding: 0;\n  font-size: inherit;\n  color: inherit;\n  white-space: pre-wrap;\n  background-color: transparent;\n  border-radius: 0;\n}\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.container {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 750px;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 970px;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n.container-fluid {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.row {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n  float: left;\n}\n.col-xs-12 {\n  width: 100%;\n}\n.col-xs-11 {\n  width: 91.66666667%;\n}\n.col-xs-10 {\n  width: 83.33333333%;\n}\n.col-xs-9 {\n  width: 75%;\n}\n.col-xs-8 {\n  width: 66.66666667%;\n}\n.col-xs-7 {\n  width: 58.33333333%;\n}\n.col-xs-6 {\n  width: 50%;\n}\n.col-xs-5 {\n  width: 41.66666667%;\n}\n.col-xs-4 {\n  width: 33.33333333%;\n}\n.col-xs-3 {\n  width: 25%;\n}\n.col-xs-2 {\n  width: 16.66666667%;\n}\n.col-xs-1 {\n  width: 8.33333333%;\n}\n.col-xs-pull-12 {\n  right: 100%;\n}\n.col-xs-pull-11 {\n  right: 91.66666667%;\n}\n.col-xs-pull-10 {\n  right: 83.33333333%;\n}\n.col-xs-pull-9 {\n  right: 75%;\n}\n.col-xs-pull-8 {\n  right: 66.66666667%;\n}\n.col-xs-pull-7 {\n  right: 58.33333333%;\n}\n.col-xs-pull-6 {\n  right: 50%;\n}\n.col-xs-pull-5 {\n  right: 41.66666667%;\n}\n.col-xs-pull-4 {\n  right: 33.33333333%;\n}\n.col-xs-pull-3 {\n  right: 25%;\n}\n.col-xs-pull-2 {\n  right: 16.66666667%;\n}\n.col-xs-pull-1 {\n  right: 8.33333333%;\n}\n.col-xs-pull-0 {\n  right: auto;\n}\n.col-xs-push-12 {\n  left: 100%;\n}\n.col-xs-push-11 {\n  left: 91.66666667%;\n}\n.col-xs-push-10 {\n  left: 83.33333333%;\n}\n.col-xs-push-9 {\n  left: 75%;\n}\n.col-xs-push-8 {\n  left: 66.66666667%;\n}\n.col-xs-push-7 {\n  left: 58.33333333%;\n}\n.col-xs-push-6 {\n  left: 50%;\n}\n.col-xs-push-5 {\n  left: 41.66666667%;\n}\n.col-xs-push-4 {\n  left: 33.33333333%;\n}\n.col-xs-push-3 {\n  left: 25%;\n}\n.col-xs-push-2 {\n  left: 16.66666667%;\n}\n.col-xs-push-1 {\n  left: 8.33333333%;\n}\n.col-xs-push-0 {\n  left: auto;\n}\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n.col-xs-offset-11 {\n  margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n  margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n.col-xs-offset-8 {\n  margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n  margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n.col-xs-offset-5 {\n  margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n  margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n.col-xs-offset-2 {\n  margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n  margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n  margin-left: 0%;\n}\n@media (min-width: 768px) {\n  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n    float: left;\n  }\n  .col-sm-12 {\n    width: 100%;\n  }\n  .col-sm-11 {\n    width: 91.66666667%;\n  }\n  .col-sm-10 {\n    width: 83.33333333%;\n  }\n  .col-sm-9 {\n    width: 75%;\n  }\n  .col-sm-8 {\n    width: 66.66666667%;\n  }\n  .col-sm-7 {\n    width: 58.33333333%;\n  }\n  .col-sm-6 {\n    width: 50%;\n  }\n  .col-sm-5 {\n    width: 41.66666667%;\n  }\n  .col-sm-4 {\n    width: 33.33333333%;\n  }\n  .col-sm-3 {\n    width: 25%;\n  }\n  .col-sm-2 {\n    width: 16.66666667%;\n  }\n  .col-sm-1 {\n    width: 8.33333333%;\n  }\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n  .col-sm-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-sm-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n  .col-sm-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-sm-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n  .col-sm-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-sm-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n  .col-sm-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-sm-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-sm-pull-0 {\n    right: auto;\n  }\n  .col-sm-push-12 {\n    left: 100%;\n  }\n  .col-sm-push-11 {\n    left: 91.66666667%;\n  }\n  .col-sm-push-10 {\n    left: 83.33333333%;\n  }\n  .col-sm-push-9 {\n    left: 75%;\n  }\n  .col-sm-push-8 {\n    left: 66.66666667%;\n  }\n  .col-sm-push-7 {\n    left: 58.33333333%;\n  }\n  .col-sm-push-6 {\n    left: 50%;\n  }\n  .col-sm-push-5 {\n    left: 41.66666667%;\n  }\n  .col-sm-push-4 {\n    left: 33.33333333%;\n  }\n  .col-sm-push-3 {\n    left: 25%;\n  }\n  .col-sm-push-2 {\n    left: 16.66666667%;\n  }\n  .col-sm-push-1 {\n    left: 8.33333333%;\n  }\n  .col-sm-push-0 {\n    left: auto;\n  }\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .col-sm-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-sm-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .col-sm-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-sm-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .col-sm-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-sm-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .col-sm-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-sm-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-sm-offset-0 {\n    margin-left: 0%;\n  }\n}\n@media (min-width: 992px) {\n  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n    float: left;\n  }\n  .col-md-12 {\n    width: 100%;\n  }\n  .col-md-11 {\n    width: 91.66666667%;\n  }\n  .col-md-10 {\n    width: 83.33333333%;\n  }\n  .col-md-9 {\n    width: 75%;\n  }\n  .col-md-8 {\n    width: 66.66666667%;\n  }\n  .col-md-7 {\n    width: 58.33333333%;\n  }\n  .col-md-6 {\n    width: 50%;\n  }\n  .col-md-5 {\n    width: 41.66666667%;\n  }\n  .col-md-4 {\n    width: 33.33333333%;\n  }\n  .col-md-3 {\n    width: 25%;\n  }\n  .col-md-2 {\n    width: 16.66666667%;\n  }\n  .col-md-1 {\n    width: 8.33333333%;\n  }\n  .col-md-pull-12 {\n    right: 100%;\n  }\n  .col-md-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-md-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-md-pull-9 {\n    right: 75%;\n  }\n  .col-md-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-md-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-md-pull-6 {\n    right: 50%;\n  }\n  .col-md-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-md-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-md-pull-3 {\n    right: 25%;\n  }\n  .col-md-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-md-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-md-pull-0 {\n    right: auto;\n  }\n  .col-md-push-12 {\n    left: 100%;\n  }\n  .col-md-push-11 {\n    left: 91.66666667%;\n  }\n  .col-md-push-10 {\n    left: 83.33333333%;\n  }\n  .col-md-push-9 {\n    left: 75%;\n  }\n  .col-md-push-8 {\n    left: 66.66666667%;\n  }\n  .col-md-push-7 {\n    left: 58.33333333%;\n  }\n  .col-md-push-6 {\n    left: 50%;\n  }\n  .col-md-push-5 {\n    left: 41.66666667%;\n  }\n  .col-md-push-4 {\n    left: 33.33333333%;\n  }\n  .col-md-push-3 {\n    left: 25%;\n  }\n  .col-md-push-2 {\n    left: 16.66666667%;\n  }\n  .col-md-push-1 {\n    left: 8.33333333%;\n  }\n  .col-md-push-0 {\n    left: auto;\n  }\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .col-md-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-md-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .col-md-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-md-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .col-md-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-md-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .col-md-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-md-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-md-offset-0 {\n    margin-left: 0%;\n  }\n}\n@media (min-width: 1200px) {\n  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n    float: left;\n  }\n  .col-lg-12 {\n    width: 100%;\n  }\n  .col-lg-11 {\n    width: 91.66666667%;\n  }\n  .col-lg-10 {\n    width: 83.33333333%;\n  }\n  .col-lg-9 {\n    width: 75%;\n  }\n  .col-lg-8 {\n    width: 66.66666667%;\n  }\n  .col-lg-7 {\n    width: 58.33333333%;\n  }\n  .col-lg-6 {\n    width: 50%;\n  }\n  .col-lg-5 {\n    width: 41.66666667%;\n  }\n  .col-lg-4 {\n    width: 33.33333333%;\n  }\n  .col-lg-3 {\n    width: 25%;\n  }\n  .col-lg-2 {\n    width: 16.66666667%;\n  }\n  .col-lg-1 {\n    width: 8.33333333%;\n  }\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n  .col-lg-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-lg-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n  .col-lg-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-lg-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n  .col-lg-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-lg-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n  .col-lg-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-lg-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-lg-pull-0 {\n    right: auto;\n  }\n  .col-lg-push-12 {\n    left: 100%;\n  }\n  .col-lg-push-11 {\n    left: 91.66666667%;\n  }\n  .col-lg-push-10 {\n    left: 83.33333333%;\n  }\n  .col-lg-push-9 {\n    left: 75%;\n  }\n  .col-lg-push-8 {\n    left: 66.66666667%;\n  }\n  .col-lg-push-7 {\n    left: 58.33333333%;\n  }\n  .col-lg-push-6 {\n    left: 50%;\n  }\n  .col-lg-push-5 {\n    left: 41.66666667%;\n  }\n  .col-lg-push-4 {\n    left: 33.33333333%;\n  }\n  .col-lg-push-3 {\n    left: 25%;\n  }\n  .col-lg-push-2 {\n    left: 16.66666667%;\n  }\n  .col-lg-push-1 {\n    left: 8.33333333%;\n  }\n  .col-lg-push-0 {\n    left: auto;\n  }\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .col-lg-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-lg-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .col-lg-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-lg-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .col-lg-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-lg-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .col-lg-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-lg-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-lg-offset-0 {\n    margin-left: 0%;\n  }\n}\ntable {\n  background-color: transparent;\n}\ncaption {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  color: #777777;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #dddddd;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #dddddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.table > tbody + tbody {\n  border-top: 2px solid #dddddd;\n}\n.table .table {\n  background-color: #ffffff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.table-bordered {\n  border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n  background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n  background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n  background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n  background-color: #dcf6ca;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n  background-color: #cef2b4;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n  background-color: #f6f2f8;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n  background-color: #e9e1f0;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n  background-color: #f8e4c7;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n  background-color: #f6d9b0;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n  background-color: #f6cadc;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n  background-color: #f2b4ce;\n}\n.table-responsive {\n  overflow-x: auto;\n  min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #dddddd;\n  }\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .table-responsive > .table > thead > tr > th,\n  .table-responsive > .table > tbody > tr > th,\n  .table-responsive > .table > tfoot > tr > th,\n  .table-responsive > .table > thead > tr > td,\n  .table-responsive > .table > tbody > tr > td,\n  .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  min-width: 0;\n}\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  line-height: normal;\n}\ninput[type=\"file\"] {\n  display: block;\n}\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\nselect[multiple],\nselect[size] {\n  height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555555;\n}\n.form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555555;\n  background-color: #ffffff;\n  background-image: none;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n  color: #999999;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #999999;\n}\n.form-control::-webkit-input-placeholder {\n  color: #999999;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #eeeeee;\n  opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n  cursor: not-allowed;\n}\ntextarea.form-control {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"],\n  input[type=\"time\"],\n  input[type=\"datetime-local\"],\n  input[type=\"month\"] {\n    line-height: 34px;\n  }\n  input[type=\"date\"].input-sm,\n  input[type=\"time\"].input-sm,\n  input[type=\"datetime-local\"].input-sm,\n  input[type=\"month\"].input-sm,\n  .input-group-sm input[type=\"date\"],\n  .input-group-sm input[type=\"time\"],\n  .input-group-sm input[type=\"datetime-local\"],\n  .input-group-sm input[type=\"month\"] {\n    line-height: 30px;\n  }\n  input[type=\"date\"].input-lg,\n  input[type=\"time\"].input-lg,\n  input[type=\"datetime-local\"].input-lg,\n  input[type=\"month\"].input-lg,\n  .input-group-lg input[type=\"date\"],\n  .input-group-lg input[type=\"time\"],\n  .input-group-lg input[type=\"datetime-local\"],\n  .input-group-lg input[type=\"month\"] {\n    line-height: 46px;\n  }\n}\n.form-group {\n  margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n  min-height: 20px;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  position: absolute;\n  margin-left: -20px;\n  margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n  cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n  cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n  cursor: not-allowed;\n}\n.form-control-static {\n  padding-top: 7px;\n  padding-bottom: 7px;\n  margin-bottom: 0;\n  min-height: 34px;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n  padding-left: 0;\n  padding-right: 0;\n}\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\n.form-group-sm .form-control {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.form-group-sm select.form-control {\n  height: 30px;\n  line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n  height: auto;\n}\n.form-group-sm .form-control-static {\n  height: 30px;\n  min-height: 32px;\n  padding: 6px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.input-lg {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-lg {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.form-group-lg .form-control {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.form-group-lg select.form-control {\n  height: 46px;\n  line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n  height: auto;\n}\n.form-group-lg .form-control-static {\n  height: 46px;\n  min-height: 38px;\n  padding: 11px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 42.5px;\n}\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 34px;\n  height: 34px;\n  line-height: 34px;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback {\n  width: 46px;\n  height: 46px;\n  line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback {\n  width: 30px;\n  height: 30px;\n  line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n  color: #3f7815;\n}\n.has-success .form-control {\n  border-color: #3f7815;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n  border-color: #284d0e;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #6ccf24;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #6ccf24;\n}\n.has-success .input-group-addon {\n  color: #3f7815;\n  border-color: #3f7815;\n  background-color: #dcf6ca;\n}\n.has-success .form-control-feedback {\n  color: #3f7815;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n  color: #7e500f;\n}\n.has-warning .form-control {\n  border-color: #7e500f;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n  border-color: #51330a;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d98a1a;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d98a1a;\n}\n.has-warning .input-group-addon {\n  color: #7e500f;\n  border-color: #7e500f;\n  background-color: #f8e4c7;\n}\n.has-warning .form-control-feedback {\n  color: #7e500f;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n  color: #78153f;\n}\n.has-error .form-control {\n  border-color: #78153f;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n  border-color: #4d0e28;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #cf246c;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #cf246c;\n}\n.has-error .input-group-addon {\n  color: #78153f;\n  border-color: #78153f;\n  background-color: #f6cadc;\n}\n.has-error .form-control-feedback {\n  color: #78153f;\n}\n.has-feedback label ~ .form-control-feedback {\n  top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n  top: 0;\n}\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n@media (min-width: 768px) {\n  .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .form-control-static {\n    display: inline-block;\n  }\n  .form-inline .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .form-inline .input-group .input-group-addon,\n  .form-inline .input-group .input-group-btn,\n  .form-inline .input-group .form-control {\n    width: auto;\n  }\n  .form-inline .input-group > .form-control {\n    width: 100%;\n  }\n  .form-inline .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio,\n  .form-inline .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio label,\n  .form-inline .checkbox label {\n    padding-left: 0;\n  }\n  .form-inline .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .form-inline .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 27px;\n}\n.form-horizontal .form-group {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    text-align: right;\n    margin-bottom: 0;\n    padding-top: 7px;\n  }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  right: 15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 14.333333px;\n    font-size: 18px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-sm .control-label {\n    padding-top: 6px;\n    font-size: 12px;\n  }\n}\n.btn {\n  display: inline-block;\n  margin-bottom: 0;\n  font-weight: normal;\n  text-align: center;\n  vertical-align: middle;\n  touch-action: manipulation;\n  cursor: pointer;\n  background-image: none;\n  border: 1px solid transparent;\n  white-space: nowrap;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  border-radius: 4px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n  color: #333333;\n  text-decoration: none;\n}\n.btn:active,\n.btn.active {\n  outline: 0;\n  background-image: none;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  cursor: not-allowed;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n  pointer-events: none;\n}\n.btn-default {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #8c8c8c;\n}\n.btn-default:hover {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n  color: #333333;\n  background-color: #d4d4d4;\n  border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.btn-default .badge {\n  color: #ffffff;\n  background-color: #333333;\n}\n.btn-primary {\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n  color: #ffffff;\n  background-color: #3071a9;\n  border-color: #193c5a;\n}\n.btn-primary:hover {\n  color: #ffffff;\n  background-color: #3071a9;\n  border-color: #285e8e;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  color: #ffffff;\n  background-color: #3071a9;\n  border-color: #285e8e;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n  color: #ffffff;\n  background-color: #285e8e;\n  border-color: #193c5a;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.btn-primary .badge {\n  color: #428bca;\n  background-color: #ffffff;\n}\n.btn-success {\n  color: #ffffff;\n  background-color: #79db32;\n  border-color: #6ccf24;\n}\n.btn-success:focus,\n.btn-success.focus {\n  color: #ffffff;\n  background-color: #61b921;\n  border-color: #346311;\n}\n.btn-success:hover {\n  color: #ffffff;\n  background-color: #61b921;\n  border-color: #519b1b;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  color: #ffffff;\n  background-color: #61b921;\n  border-color: #519b1b;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n  color: #ffffff;\n  background-color: #519b1b;\n  border-color: #346311;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #79db32;\n  border-color: #6ccf24;\n}\n.btn-success .badge {\n  color: #79db32;\n  background-color: #ffffff;\n}\n.btn-info {\n  color: #ffffff;\n  background-color: #a07cbc;\n  border-color: #946bb3;\n}\n.btn-info:focus,\n.btn-info.focus {\n  color: #ffffff;\n  background-color: #885aab;\n  border-color: #533669;\n}\n.btn-info:hover {\n  color: #ffffff;\n  background-color: #885aab;\n  border-color: #754c95;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  color: #ffffff;\n  background-color: #885aab;\n  border-color: #754c95;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n  color: #ffffff;\n  background-color: #754c95;\n  border-color: #533669;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #a07cbc;\n  border-color: #946bb3;\n}\n.btn-info .badge {\n  color: #a07cbc;\n  background-color: #ffffff;\n}\n.btn-warning {\n  color: #ffffff;\n  background-color: #e59728;\n  border-color: #d98a1a;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n  color: #ffffff;\n  background-color: #c27c18;\n  border-color: #67420d;\n}\n.btn-warning:hover {\n  color: #ffffff;\n  background-color: #c27c18;\n  border-color: #a36814;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  color: #ffffff;\n  background-color: #c27c18;\n  border-color: #a36814;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n  color: #ffffff;\n  background-color: #a36814;\n  border-color: #67420d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #e59728;\n  border-color: #d98a1a;\n}\n.btn-warning .badge {\n  color: #e59728;\n  background-color: #ffffff;\n}\n.btn-danger {\n  color: #ffffff;\n  background-color: #db3279;\n  border-color: #cf246c;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n  color: #ffffff;\n  background-color: #b92161;\n  border-color: #631134;\n}\n.btn-danger:hover {\n  color: #ffffff;\n  background-color: #b92161;\n  border-color: #9b1b51;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  color: #ffffff;\n  background-color: #b92161;\n  border-color: #9b1b51;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n  color: #ffffff;\n  background-color: #9b1b51;\n  border-color: #631134;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #db3279;\n  border-color: #cf246c;\n}\n.btn-danger .badge {\n  color: #db3279;\n  background-color: #ffffff;\n}\n.btn-link {\n  color: #428bca;\n  font-weight: normal;\n  border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n  border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n  color: #2a6496;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #777777;\n  text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-block {\n  display: block;\n  width: 100%;\n}\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n  -o-transition: opacity 0.15s linear;\n  transition: opacity 0.15s linear;\n}\n.fade.in {\n  opacity: 1;\n}\n.collapse {\n  display: none;\n}\n.collapse.in {\n  display: block;\n}\ntr.collapse.in {\n  display: table-row;\n}\ntbody.collapse.in {\n  display: table-row-group;\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition-property: height, visibility;\n  transition-property: height, visibility;\n  -webkit-transition-duration: 0.35s;\n  transition-duration: 0.35s;\n  -webkit-transition-timing-function: ease;\n  transition-timing-function: ease;\n}\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px dashed;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n  position: relative;\n}\n.dropdown-toggle:focus {\n  outline: 0;\n}\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  list-style: none;\n  font-size: 14px;\n  text-align: left;\n  background-color: #ffffff;\n  border: 1px solid #cccccc;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.42857143;\n  color: #333333;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  text-decoration: none;\n  color: #262626;\n  background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #ffffff;\n  text-decoration: none;\n  outline: 0;\n  background-color: #428bca;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  cursor: not-allowed;\n}\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n.dropdown-menu-right {\n  left: auto;\n  right: 0;\n}\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #777777;\n  white-space: nowrap;\n}\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: 990;\n}\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px solid;\n  content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    left: auto;\n    right: 0;\n  }\n  .navbar-right .dropdown-menu-left {\n    left: 0;\n    right: auto;\n  }\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.btn-toolbar {\n  margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn .caret {\n  margin-left: 0;\n}\n.btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-bottom-left-radius: 4px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  float: none;\n  display: table-cell;\n  width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n  left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n  position: absolute;\n  clip: rect(0, 0, 0, 0);\n  pointer-events: none;\n}\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-left: 0;\n  padding-right: 0;\n}\n.input-group .form-control {\n  position: relative;\n  z-index: 2;\n  float: left;\n  width: 100%;\n  margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555555;\n  text-align: center;\n  background-color: #eeeeee;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n}\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.input-group-btn > .btn {\n  position: relative;\n}\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n  z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n  z-index: 2;\n  margin-left: -1px;\n}\n.nav {\n  margin-bottom: 0;\n  padding-left: 0;\n  list-style: none;\n}\n.nav > li {\n  position: relative;\n  display: block;\n}\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n  color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #777777;\n  text-decoration: none;\n  background-color: transparent;\n  cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #eeeeee;\n  border-color: #428bca;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.nav > li > a > img {\n  max-width: none;\n}\n.nav-tabs {\n  border-bottom: 1px solid #dddddd;\n}\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.42857143;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #dddddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #555555;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-bottom-color: transparent;\n  cursor: default;\n}\n.nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n  float: none;\n}\n.nav-tabs.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs.nav-justified > .active > a,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #ffffff;\n  }\n}\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 4px;\n}\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n  color: #ffffff;\n  background-color: #428bca;\n}\n.nav-stacked > li {\n  float: none;\n}\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.nav-justified {\n  width: 100%;\n}\n.nav-justified > li {\n  float: none;\n}\n.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs-justified {\n  border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #ffffff;\n  }\n}\n.tab-content > .tab-pane {\n  display: none;\n}\n.tab-content > .active {\n  display: block;\n}\n.nav .caret {\n  border-top-color: #db3279;\n  border-bottom-color: #db3279;\n}\n.nav a:hover .caret {\n  border-top-color: #b92161;\n  border-bottom-color: #b92161;\n}\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.navbar {\n  position: relative;\n  min-height: 35px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 4px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n.navbar-collapse {\n  overflow-x: visible;\n  padding-right: 15px;\n  padding-left: 15px;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n  -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n  }\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-static-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    padding-left: 0;\n    padding-right: 0;\n  }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n  max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    max-height: 200px;\n  }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .container > .navbar-header,\n  .container-fluid > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n}\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n.navbar-brand {\n  float: left;\n  padding: 7.5px 15px;\n  font-size: 18px;\n  line-height: 20px;\n  height: 35px;\n  font-family: Comfortaa, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-weight: bold;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n  text-decoration: none;\n}\n.navbar-brand > img {\n  display: block;\n}\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand,\n  .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: 15px;\n  padding: 9px 10px;\n  margin-top: 0.5px;\n  margin-bottom: 0.5px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.navbar-toggle:focus {\n  outline: 0;\n}\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n.navbar-nav {\n  margin: 3.75px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .navbar-nav .open .dropdown-menu {\n    position: static;\n    float: none;\n    width: auto;\n    margin-top: 0;\n    background-color: transparent;\n    border: 0;\n    box-shadow: none;\n  }\n  .navbar-nav .open .dropdown-menu > li > a,\n  .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .navbar-nav > li {\n    float: left;\n  }\n  .navbar-nav > li > a {\n    padding-top: 7.5px;\n    padding-bottom: 7.5px;\n  }\n}\n.navbar-form {\n  margin-left: -15px;\n  margin-right: -15px;\n  padding: 10px 15px;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  margin-top: 0.5px;\n  margin-bottom: 0.5px;\n}\n@media (min-width: 768px) {\n  .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control-static {\n    display: inline-block;\n  }\n  .navbar-form .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .navbar-form .input-group .input-group-addon,\n  .navbar-form .input-group .input-group-btn,\n  .navbar-form .input-group .form-control {\n    width: auto;\n  }\n  .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n  .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio,\n  .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio label,\n  .navbar-form .checkbox label {\n    padding-left: 0;\n  }\n  .navbar-form .radio input[type=\"radio\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n  .navbar-form .form-group:last-child {\n    margin-bottom: 0;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n  }\n}\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  border-top-right-radius: 4px;\n  border-top-left-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.navbar-btn {\n  margin-top: 0.5px;\n  margin-bottom: 0.5px;\n}\n.navbar-btn.btn-sm {\n  margin-top: 2.5px;\n  margin-bottom: 2.5px;\n}\n.navbar-btn.btn-xs {\n  margin-top: 6.5px;\n  margin-bottom: 6.5px;\n}\n.navbar-text {\n  margin-top: 7.5px;\n  margin-bottom: 7.5px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-left: 15px;\n    margin-right: 15px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n  .navbar-right {\n    float: right !important;\n    margin-right: -15px;\n  }\n  .navbar-right ~ .navbar-right {\n    margin-right: 0;\n  }\n}\n.navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n  color: #777777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.navbar-default .navbar-text {\n  color: #777777;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #777777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #333333;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n  color: #db3279;\n  background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n  color: #cccccc;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #dddddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #dddddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n  background-color: #e7e7e7;\n  color: #db3279;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777777;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333333;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #db3279;\n    background-color: #e7e7e7;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #cccccc;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #777777;\n}\n.navbar-default .navbar-link:hover {\n  color: #333333;\n}\n.navbar-default .btn-link {\n  color: #777777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n  color: #333333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n  color: #cccccc;\n}\n.navbar-inverse {\n  background-color: #294172;\n  border-color: #1c2c4c;\n}\n.navbar-inverse .navbar-brand {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n  color: #777777;\n}\n.navbar-inverse .navbar-nav > li > a {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n  color: #ffffff;\n  background-color: #1c2c4c;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444444;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #ffffff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #203258;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n  background-color: #1c2c4c;\n  color: #ffffff;\n}\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #1c2c4c;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #1c2c4c;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #ffffff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #ffffff;\n    background-color: #1c2c4c;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #444444;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #ffffff;\n}\n.navbar-inverse .btn-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n  color: #ffffff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n  color: #444444;\n}\n.breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  content: \"/\\00a0\";\n  padding: 0 5px;\n  color: #cccccc;\n}\n.breadcrumb > .active {\n  color: #777777;\n}\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.pagination > li {\n  display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  line-height: 1.42857143;\n  text-decoration: none;\n  color: #428bca;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-bottom-left-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-bottom-right-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n  z-index: 3;\n  color: #2a6496;\n  background-color: #eeeeee;\n  border-color: #dddddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n  cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n  color: #777777;\n  background-color: #ffffff;\n  border-color: #dddddd;\n  cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-bottom-left-radius: 6px;\n  border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-bottom-right-radius: 6px;\n  border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-bottom-left-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-bottom-right-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.pager {\n  padding-left: 0;\n  margin: 20px 0;\n  list-style: none;\n  text-align: center;\n}\n.pager li {\n  display: inline;\n}\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #777777;\n  background-color: #ffffff;\n  cursor: not-allowed;\n}\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #ffffff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.label:empty {\n  display: none;\n}\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n.label-default {\n  background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #5e5e5e;\n}\n.label-primary {\n  background-color: #428bca;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #3071a9;\n}\n.label-success {\n  background-color: #79db32;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #61b921;\n}\n.label-info {\n  background-color: #a07cbc;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #885aab;\n}\n.label-warning {\n  background-color: #e59728;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #c27c18;\n}\n.label-danger {\n  background-color: #db3279;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #b92161;\n}\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  color: #ffffff;\n  line-height: 1;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: #777777;\n  border-radius: 10px;\n}\n.badge:empty {\n  display: none;\n}\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n  top: 0;\n  padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #428bca;\n  background-color: #ffffff;\n}\n.list-group-item > .badge {\n  float: right;\n}\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.jumbotron {\n  padding: 30px 15px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 21px;\n  font-weight: 200;\n}\n.jumbotron > hr {\n  border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n  border-radius: 6px;\n}\n.jumbotron .container {\n  max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding: 48px 0;\n  }\n  .container .jumbotron,\n  .container-fluid .jumbotron {\n    padding-left: 60px;\n    padding-right: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 63px;\n  }\n}\n.thumbnail {\n  display: block;\n  padding: 4px;\n  margin-bottom: 20px;\n  line-height: 1.42857143;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 4px;\n  -webkit-transition: border 0.2s ease-in-out;\n  -o-transition: border 0.2s ease-in-out;\n  transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  margin-left: auto;\n  margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #428bca;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #333333;\n}\n.alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.alert .alert-link {\n  font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n.alert > p + p {\n  margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n  padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.alert-success {\n  background-color: #dcf6ca;\n  border-color: #d8f2b4;\n  color: #3f7815;\n}\n.alert-success hr {\n  border-top-color: #cdee9e;\n}\n.alert-success .alert-link {\n  color: #284d0e;\n}\n.alert-info {\n  background-color: #f6f2f8;\n  border-color: #e7e1f0;\n  color: #603e7a;\n}\n.alert-info hr {\n  border-top-color: #d9d0e7;\n}\n.alert-info .alert-link {\n  color: #452d58;\n}\n.alert-warning {\n  background-color: #f8e4c7;\n  border-color: #f6ceb0;\n  color: #7e500f;\n}\n.alert-warning hr {\n  border-top-color: #f3bf9a;\n}\n.alert-warning .alert-link {\n  color: #51330a;\n}\n.alert-danger {\n  background-color: #f6cadc;\n  border-color: #f2b4d8;\n  color: #78153f;\n}\n.alert-danger hr {\n  border-top-color: #ee9ecd;\n}\n.alert-danger .alert-link {\n  color: #4d0e28;\n}\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  overflow: hidden;\n  height: 20px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #428bca;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-transition: width 0.6s ease;\n  -o-transition: width 0.6s ease;\n  transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n  -o-animation: progress-bar-stripes 2s linear infinite;\n  animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n  background-color: #79db32;\n}\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n  background-color: #a07cbc;\n}\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n  background-color: #e59728;\n}\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n  background-color: #db3279;\n}\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n.media,\n.media-body {\n  zoom: 1;\n  overflow: hidden;\n}\n.media-body {\n  width: 10000px;\n}\n.media-object {\n  display: block;\n}\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n.media-middle {\n  vertical-align: middle;\n}\n.media-bottom {\n  vertical-align: bottom;\n}\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.list-group {\n  margin-bottom: 20px;\n  padding-left: 0;\n}\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n}\n.list-group-item:first-child {\n  border-top-right-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\na.list-group-item {\n  color: #555555;\n}\na.list-group-item .list-group-item-heading {\n  color: #333333;\n}\na.list-group-item:hover,\na.list-group-item:focus {\n  text-decoration: none;\n  color: #555555;\n  background-color: #f5f5f5;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n  background-color: #eeeeee;\n  color: #777777;\n  cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n  color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n  color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n  color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n  color: #e1edf7;\n}\n.list-group-item-success {\n  color: #3f7815;\n  background-color: #dcf6ca;\n}\na.list-group-item-success {\n  color: #3f7815;\n}\na.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-success:hover,\na.list-group-item-success:focus {\n  color: #3f7815;\n  background-color: #cef2b4;\n}\na.list-group-item-success.active,\na.list-group-item-success.active:hover,\na.list-group-item-success.active:focus {\n  color: #fff;\n  background-color: #3f7815;\n  border-color: #3f7815;\n}\n.list-group-item-info {\n  color: #603e7a;\n  background-color: #f6f2f8;\n}\na.list-group-item-info {\n  color: #603e7a;\n}\na.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-info:hover,\na.list-group-item-info:focus {\n  color: #603e7a;\n  background-color: #e9e1f0;\n}\na.list-group-item-info.active,\na.list-group-item-info.active:hover,\na.list-group-item-info.active:focus {\n  color: #fff;\n  background-color: #603e7a;\n  border-color: #603e7a;\n}\n.list-group-item-warning {\n  color: #7e500f;\n  background-color: #f8e4c7;\n}\na.list-group-item-warning {\n  color: #7e500f;\n}\na.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-warning:hover,\na.list-group-item-warning:focus {\n  color: #7e500f;\n  background-color: #f6d9b0;\n}\na.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus {\n  color: #fff;\n  background-color: #7e500f;\n  border-color: #7e500f;\n}\n.list-group-item-danger {\n  color: #78153f;\n  background-color: #f6cadc;\n}\na.list-group-item-danger {\n  color: #78153f;\n}\na.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-danger:hover,\na.list-group-item-danger:focus {\n  color: #78153f;\n  background-color: #f2b4ce;\n}\na.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus {\n  color: #fff;\n  background-color: #78153f;\n  border-color: #78153f;\n}\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.panel {\n  margin-bottom: 20px;\n  background-color: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n  padding: 15px;\n}\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n  color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n  color: inherit;\n}\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #dddddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n  margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n  border-width: 1px 0;\n  border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n  border-top: 0;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n  border-bottom: 0;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n  margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n  border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n  border-bottom-left-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n  border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n  border-top: 1px solid #dddddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n  border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n  border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n  border-bottom: 0;\n}\n.panel > .table-responsive {\n  border: 0;\n  margin-bottom: 0;\n}\n.panel-group {\n  margin-bottom: 20px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n}\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n  border-top: 1px solid #dddddd;\n}\n.panel-group .panel-footer {\n  border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #dddddd;\n}\n.panel-default {\n  border-color: #dddddd;\n}\n.panel-default > .panel-heading {\n  color: #333333;\n  background-color: #f5f5f5;\n  border-color: #dddddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #dddddd;\n}\n.panel-default > .panel-heading .badge {\n  color: #f5f5f5;\n  background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #dddddd;\n}\n.panel-primary {\n  border-color: #428bca;\n}\n.panel-primary > .panel-heading {\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #428bca;\n}\n.panel-primary > .panel-heading .badge {\n  color: #428bca;\n  background-color: #ffffff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #428bca;\n}\n.panel-success {\n  border-color: #d8f2b4;\n}\n.panel-success > .panel-heading {\n  color: #3f7815;\n  background-color: #dcf6ca;\n  border-color: #d8f2b4;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #d8f2b4;\n}\n.panel-success > .panel-heading .badge {\n  color: #dcf6ca;\n  background-color: #3f7815;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #d8f2b4;\n}\n.panel-info {\n  border-color: #e7e1f0;\n}\n.panel-info > .panel-heading {\n  color: #603e7a;\n  background-color: #f6f2f8;\n  border-color: #e7e1f0;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #e7e1f0;\n}\n.panel-info > .panel-heading .badge {\n  color: #f6f2f8;\n  background-color: #603e7a;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #e7e1f0;\n}\n.panel-warning {\n  border-color: #f6ceb0;\n}\n.panel-warning > .panel-heading {\n  color: #7e500f;\n  background-color: #f8e4c7;\n  border-color: #f6ceb0;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #f6ceb0;\n}\n.panel-warning > .panel-heading .badge {\n  color: #f8e4c7;\n  background-color: #7e500f;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #f6ceb0;\n}\n.panel-danger {\n  border-color: #f2b4d8;\n}\n.panel-danger > .panel-heading {\n  color: #78153f;\n  background-color: #f6cadc;\n  border-color: #f2b4d8;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #f2b4d8;\n}\n.panel-danger > .panel-heading .badge {\n  color: #f6cadc;\n  background-color: #78153f;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #f2b4d8;\n}\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  height: 100%;\n  width: 100%;\n  border: 0;\n}\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  display: none;\n  overflow: hidden;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transform: translate(0, -25%);\n  -ms-transform: translate(0, -25%);\n  -o-transform: translate(0, -25%);\n  transform: translate(0, -25%);\n  -webkit-transition: -webkit-transform 0.3s ease-out;\n  -moz-transition: -moz-transform 0.3s ease-out;\n  -o-transition: -o-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n  -ms-transform: translate(0, 0);\n  -o-transform: translate(0, 0);\n  transform: translate(0, 0);\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n.modal-content {\n  position: relative;\n  background-color: #ffffff;\n  border: 1px solid #999999;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  background-clip: padding-box;\n  outline: 0;\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000000;\n}\n.modal-backdrop.fade {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n  min-height: 16.42857143px;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.42857143;\n}\n.modal-body {\n  position: relative;\n  padding: 15px;\n}\n.modal-footer {\n  padding: 15px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n  margin-left: 5px;\n  margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n  }\n  .modal-sm {\n    width: 300px;\n  }\n}\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  font-family: Cantarell, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 12px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.tooltip.in {\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.tooltip.top {\n  margin-top: -3px;\n  padding: 5px 0;\n}\n.tooltip.right {\n  margin-left: 3px;\n  padding: 0 5px;\n}\n.tooltip.bottom {\n  margin-top: 3px;\n  padding: 5px 0;\n}\n.tooltip.left {\n  margin-left: -3px;\n  padding: 0 5px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #000000;\n  border-radius: 4px;\n}\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n  bottom: 0;\n  right: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #000000;\n}\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-width: 5px 0 5px 5px;\n  border-left-color: #000000;\n}\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1060;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  font-family: Cantarell, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 14px;\n  background-color: #ffffff;\n  background-clip: padding-box;\n  border: 1px solid #cccccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n  margin-top: -10px;\n}\n.popover.right {\n  margin-left: 10px;\n}\n.popover.bottom {\n  margin-top: 10px;\n}\n.popover.left {\n  margin-left: -10px;\n}\n.popover-title {\n  margin: 0;\n  padding: 8px 14px;\n  font-size: 14px;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  border-radius: 5px 5px 0 0;\n}\n.popover-content {\n  padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n  position: absolute;\n  display: block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.popover > .arrow {\n  border-width: 11px;\n}\n.popover > .arrow:after {\n  border-width: 10px;\n  content: \"\";\n}\n.popover.top > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-bottom-width: 0;\n  border-top-color: #999999;\n  border-top-color: rgba(0, 0, 0, 0.25);\n  bottom: -11px;\n}\n.popover.top > .arrow:after {\n  content: \" \";\n  bottom: 1px;\n  margin-left: -10px;\n  border-bottom-width: 0;\n  border-top-color: #ffffff;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-left-width: 0;\n  border-right-color: #999999;\n  border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n  content: \" \";\n  left: 1px;\n  bottom: -10px;\n  border-left-width: 0;\n  border-right-color: #ffffff;\n}\n.popover.bottom > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999999;\n  border-bottom-color: rgba(0, 0, 0, 0.25);\n  top: -11px;\n}\n.popover.bottom > .arrow:after {\n  content: \" \";\n  top: 1px;\n  margin-left: -10px;\n  border-top-width: 0;\n  border-bottom-color: #ffffff;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999999;\n  border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n  content: \" \";\n  right: 1px;\n  border-right-width: 0;\n  border-left-color: #ffffff;\n  bottom: -10px;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n}\n.carousel-inner > .item {\n  display: none;\n  position: relative;\n  -webkit-transition: 0.6s ease-in-out left;\n  -o-transition: 0.6s ease-in-out left;\n  transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n  .carousel-inner > .item {\n    -webkit-transition: -webkit-transform 0.6s ease-in-out;\n    -moz-transition: -moz-transform 0.6s ease-in-out;\n    -o-transition: -o-transform 0.6s ease-in-out;\n    transition: transform 0.6s ease-in-out;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    -webkit-perspective: 1000px;\n    -moz-perspective: 1000px;\n    perspective: 1000px;\n  }\n  .carousel-inner > .item.next,\n  .carousel-inner > .item.active.right {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n    left: 0;\n  }\n  .carousel-inner > .item.prev,\n  .carousel-inner > .item.active.left {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n    left: 0;\n  }\n  .carousel-inner > .item.next.left,\n  .carousel-inner > .item.prev.right,\n  .carousel-inner > .item.active {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    left: 0;\n  }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n.carousel-inner > .active {\n  left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel-inner > .next {\n  left: 100%;\n}\n.carousel-inner > .prev {\n  left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n.carousel-inner > .active.left {\n  left: -100%;\n}\n.carousel-inner > .active.right {\n  left: 100%;\n}\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: 15%;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-size: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n  left: auto;\n  right: 0;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  outline: 0;\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n  position: absolute;\n  top: 50%;\n  z-index: 5;\n  display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n  margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n  margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  margin-top: -10px;\n  line-height: 1;\n  font-family: serif;\n}\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  border: 1px solid #ffffff;\n  border-radius: 10px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n  margin: 0;\n  width: 12px;\n  height: 12px;\n  background-color: #ffffff;\n}\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -15px;\n    font-size: 30px;\n  }\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .icon-prev {\n    margin-left: -15px;\n  }\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-next {\n    margin-right: -15px;\n  }\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n  content: \" \";\n  display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n.hidden {\n  display: none !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n  table.visible-xs {\n    display: table !important;\n  }\n  tr.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-block {\n    display: block !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline {\n    display: inline !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n  table.visible-sm {\n    display: table !important;\n  }\n  tr.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-block {\n    display: block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n  table.visible-md {\n    display: table !important;\n  }\n  tr.visible-md {\n    display: table-row !important;\n  }\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-block {\n    display: block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n  table.visible-lg {\n    display: table !important;\n  }\n  tr.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-block {\n    display: block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n  table.visible-print {\n    display: table !important;\n  }\n  tr.visible-print {\n    display: table-row !important;\n  }\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n.visible-print-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-block {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline-block {\n    display: inline-block !important;\n  }\n}\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\n/*# sourceMappingURL=bootstrap.css.map */","/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS and IE text size adjust after device orientation change,\n//    without disabling user zoom.\n//\n\nhtml {\n  font-family: sans-serif; // 1\n  -ms-text-size-adjust: 100%; // 2\n  -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n  margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; // 1\n  vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n  background-color: transparent;\n}\n\n//\n// Improve readability of focused elements when they are also in an\n// active/hover state.\n//\n\na:active,\na:hover {\n  outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n  font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n  font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n  border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n  margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n  overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n//    Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; // 1\n  font: inherit; // 2\n  margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n  overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n//    and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n//    `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; // 2\n  cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n  line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; // 1\n  padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n//\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; // 1\n  box-sizing: content-box; //2\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n  border: 0; // 1\n  padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n  overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n  font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n","/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n    *,\n    *:before,\n    *:after {\n        background: transparent !important;\n        color: #000 !important; // Black prints faster: h5bp.com/s\n        box-shadow: none !important;\n        text-shadow: none !important;\n    }\n\n    a,\n    a:visited {\n        text-decoration: underline;\n    }\n\n    a[href]:after {\n        content: \" (\" attr(href) \")\";\n    }\n\n    abbr[title]:after {\n        content: \" (\" attr(title) \")\";\n    }\n\n    // Don't show links that are fragment identifiers,\n    // or use the `javascript:` pseudo protocol\n    a[href^=\"#\"]:after,\n    a[href^=\"javascript:\"]:after {\n        content: \"\";\n    }\n\n    pre,\n    blockquote {\n        border: 1px solid #999;\n        page-break-inside: avoid;\n    }\n\n    thead {\n        display: table-header-group; // h5bp.com/t\n    }\n\n    tr,\n    img {\n        page-break-inside: avoid;\n    }\n\n    img {\n        max-width: 100% !important;\n    }\n\n    p,\n    h2,\n    h3 {\n        orphans: 3;\n        widows: 3;\n    }\n\n    h2,\n    h3 {\n        page-break-after: avoid;\n    }\n\n    // Bootstrap specific changes start\n\n    // Bootstrap components\n    .navbar {\n        display: none;\n    }\n    .btn,\n    .dropup > .btn {\n        > .caret {\n            border-top-color: #000 !important;\n        }\n    }\n    .label {\n        border: 1px solid #000;\n    }\n\n    .table {\n        border-collapse: collapse !important;\n\n        td,\n        th {\n            background-color: #fff !important;\n        }\n    }\n    .table-bordered {\n        th,\n        td {\n            border: 1px solid #ddd !important;\n        }\n    }\n\n    // Bootstrap specific changes end\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// <a href=\"#\"><span class=\"glyphicon glyphicon-star\"></span> Star</a>\n\n// Import the fonts\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: url('@{icon-font-path}@{icon-font-name}.eot');\n  src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n       url('@{icon-font-path}@{icon-font-name}.woff2') format('woff2'),\n       url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n       url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n       url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk               { &:before { content: \"\\2a\"; } }\n.glyphicon-plus                   { &:before { content: \"\\2b\"; } }\n.glyphicon-euro,\n.glyphicon-eur                    { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus                  { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud                  { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope               { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil                 { &:before { content: \"\\270f\"; } }\n.glyphicon-glass                  { &:before { content: \"\\e001\"; } }\n.glyphicon-music                  { &:before { content: \"\\e002\"; } }\n.glyphicon-search                 { &:before { content: \"\\e003\"; } }\n.glyphicon-heart                  { &:before { content: \"\\e005\"; } }\n.glyphicon-star                   { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty             { &:before { content: \"\\e007\"; } }\n.glyphicon-user                   { &:before { content: \"\\e008\"; } }\n.glyphicon-film                   { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large               { &:before { content: \"\\e010\"; } }\n.glyphicon-th                     { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list                { &:before { content: \"\\e012\"; } }\n.glyphicon-ok                     { &:before { content: \"\\e013\"; } }\n.glyphicon-remove                 { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in                { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out               { &:before { content: \"\\e016\"; } }\n.glyphicon-off                    { &:before { content: \"\\e017\"; } }\n.glyphicon-signal                 { &:before { content: \"\\e018\"; } }\n.glyphicon-cog                    { &:before { content: \"\\e019\"; } }\n.glyphicon-trash                  { &:before { content: \"\\e020\"; } }\n.glyphicon-home                   { &:before { content: \"\\e021\"; } }\n.glyphicon-file                   { &:before { content: \"\\e022\"; } }\n.glyphicon-time                   { &:before { content: \"\\e023\"; } }\n.glyphicon-road                   { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt           { &:before { content: \"\\e025\"; } }\n.glyphicon-download               { &:before { content: \"\\e026\"; } }\n.glyphicon-upload                 { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox                  { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle            { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat                 { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh                { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt               { &:before { content: \"\\e032\"; } }\n.glyphicon-lock                   { &:before { content: \"\\e033\"; } }\n.glyphicon-flag                   { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones             { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off             { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down            { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up              { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode                 { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode                { &:before { content: \"\\e040\"; } }\n.glyphicon-tag                    { &:before { content: \"\\e041\"; } }\n.glyphicon-tags                   { &:before { content: \"\\e042\"; } }\n.glyphicon-book                   { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark               { &:before { content: \"\\e044\"; } }\n.glyphicon-print                  { &:before { content: \"\\e045\"; } }\n.glyphicon-camera                 { &:before { content: \"\\e046\"; } }\n.glyphicon-font                   { &:before { content: \"\\e047\"; } }\n.glyphicon-bold                   { &:before { content: \"\\e048\"; } }\n.glyphicon-italic                 { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height            { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width             { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left             { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center           { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right            { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify          { &:before { content: \"\\e055\"; } }\n.glyphicon-list                   { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left            { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right           { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video         { &:before { content: \"\\e059\"; } }\n.glyphicon-picture                { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker             { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust                 { &:before { content: \"\\e063\"; } }\n.glyphicon-tint                   { &:before { content: \"\\e064\"; } }\n.glyphicon-edit                   { &:before { content: \"\\e065\"; } }\n.glyphicon-share                  { &:before { content: \"\\e066\"; } }\n.glyphicon-check                  { &:before { content: \"\\e067\"; } }\n.glyphicon-move                   { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward          { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward          { &:before { content: \"\\e070\"; } }\n.glyphicon-backward               { &:before { content: \"\\e071\"; } }\n.glyphicon-play                   { &:before { content: \"\\e072\"; } }\n.glyphicon-pause                  { &:before { content: \"\\e073\"; } }\n.glyphicon-stop                   { &:before { content: \"\\e074\"; } }\n.glyphicon-forward                { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward           { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward           { &:before { content: \"\\e077\"; } }\n.glyphicon-eject                  { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left           { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right          { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign              { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign             { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign            { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign                { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign          { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign              { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot             { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle          { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle              { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle             { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left             { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right            { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up               { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down             { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt              { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full            { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small           { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign       { &:before { content: \"\\e101\"; } }\n.glyphicon-gift                   { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf                   { &:before { content: \"\\e103\"; } }\n.glyphicon-fire                   { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open               { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close              { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign           { &:before { content: \"\\e107\"; } }\n.glyphicon-plane                  { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar               { &:before { content: \"\\e109\"; } }\n.glyphicon-random                 { &:before { content: \"\\e110\"; } }\n.glyphicon-comment                { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet                 { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up             { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down           { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet                { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart          { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close           { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open            { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical        { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal      { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd                    { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn               { &:before { content: \"\\e122\"; } }\n.glyphicon-bell                   { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate            { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up              { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down            { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right             { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left              { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up                { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down              { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right     { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left      { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up        { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down      { &:before { content: \"\\e134\"; } }\n.glyphicon-globe                  { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench                 { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks                  { &:before { content: \"\\e137\"; } }\n.glyphicon-filter                 { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase              { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen             { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard              { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip              { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty            { &:before { content: \"\\e143\"; } }\n.glyphicon-link                   { &:before { content: \"\\e144\"; } }\n.glyphicon-phone                  { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin                { &:before { content: \"\\e146\"; } }\n.glyphicon-usd                    { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp                    { &:before { content: \"\\e149\"; } }\n.glyphicon-sort                   { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet       { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt   { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order          { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt      { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes     { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked              { &:before { content: \"\\e157\"; } }\n.glyphicon-expand                 { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down          { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up            { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in                 { &:before { content: \"\\e161\"; } }\n.glyphicon-flash                  { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out                { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window             { &:before { content: \"\\e164\"; } }\n.glyphicon-record                 { &:before { content: \"\\e165\"; } }\n.glyphicon-save                   { &:before { content: \"\\e166\"; } }\n.glyphicon-open                   { &:before { content: \"\\e167\"; } }\n.glyphicon-saved                  { &:before { content: \"\\e168\"; } }\n.glyphicon-import                 { &:before { content: \"\\e169\"; } }\n.glyphicon-export                 { &:before { content: \"\\e170\"; } }\n.glyphicon-send                   { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk            { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved           { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove          { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save            { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open            { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card            { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer               { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery                { &:before { content: \"\\e179\"; } }\n.glyphicon-header                 { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed             { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone               { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt              { &:before { content: \"\\e183\"; } }\n.glyphicon-tower                  { &:before { content: \"\\e184\"; } }\n.glyphicon-stats                  { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video               { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video               { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles              { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo           { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby            { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1              { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1              { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1              { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark         { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark      { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download         { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload           { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer           { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous         { &:before { content: \"\\e200\"; } }\n.glyphicon-cd                     { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file              { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file              { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up               { &:before { content: \"\\e204\"; } }\n.glyphicon-copy                   { &:before { content: \"\\e205\"; } }\n.glyphicon-paste                  { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door                   { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key                    { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert                  { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer              { &:before { content: \"\\e210\"; } }\n.glyphicon-king                   { &:before { content: \"\\e211\"; } }\n.glyphicon-queen                  { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn                   { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop                 { &:before { content: \"\\e214\"; } }\n.glyphicon-knight                 { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula           { &:before { content: \"\\e216\"; } }\n.glyphicon-tent                   { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard             { &:before { content: \"\\e218\"; } }\n.glyphicon-bed                    { &:before { content: \"\\e219\"; } }\n.glyphicon-apple                  { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase                  { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass              { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp                   { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate              { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank             { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors               { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin                { &:before { content: \"\\e227\"; } }\n.glyphicon-btc                    { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt                    { &:before { content: \"\\e227\"; } }\n.glyphicon-yen                    { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy                    { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble                  { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub                    { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale                  { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly              { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted       { &:before { content: \"\\e232\"; } }\n.glyphicon-education              { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal      { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical        { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger         { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window           { &:before { content: \"\\e237\"; } }\n.glyphicon-oil                    { &:before { content: \"\\e238\"; } }\n.glyphicon-grain                  { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses             { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size              { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color             { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background        { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top       { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom    { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left      { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical  { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right     { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right         { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left          { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom        { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top           { &:before { content: \"\\e253\"; } }\n.glyphicon-console                { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript            { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript              { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left              { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right             { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down              { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up                { &:before { content: \"\\e260\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n  .box-sizing(border-box);\n}\n*:before,\n*:after {\n  .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n  font-size: 10px;\n  -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n  font-family: @font-family-base;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @text-color;\n  background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\n\n// Links\n\na {\n  color: @link-color;\n  text-decoration: none;\n\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: @link-hover-decoration;\n  }\n\n  &:focus {\n    .tab-focus();\n  }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n  margin: 0;\n}\n\n\n// Images\n\nimg {\n  vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n  .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n  border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n  padding: @thumbnail-padding;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(all .2s ease-in-out);\n\n  // Keep them at most 100% wide\n  .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n  border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n  margin-top:    @line-height-computed;\n  margin-bottom: @line-height-computed;\n  border: 0;\n  border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0,0,0,0);\n  border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n  &:active,\n  &:focus {\n    position: static;\n    width: auto;\n    height: auto;\n    margin: 0;\n    overflow: visible;\n    clip: auto;\n  }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n// Upstream patch for normalize.css submitted: https://github.com/necolas/normalize.css/pull/379 - remove this fix once that is merged\n\n[role=\"button\"] {\n  cursor: pointer;\n}","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n  -webkit-animation: @animation;\n       -o-animation: @animation;\n          animation: @animation;\n}\n.animation-name(@name) {\n  -webkit-animation-name: @name;\n          animation-name: @name;\n}\n.animation-duration(@duration) {\n  -webkit-animation-duration: @duration;\n          animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n  -webkit-animation-timing-function: @timing-function;\n          animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n  -webkit-animation-delay: @delay;\n          animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n  -webkit-animation-iteration-count: @iteration-count;\n          animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n  -webkit-animation-direction: @direction;\n          animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n  -webkit-animation-fill-mode: @fill-mode;\n          animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n  -webkit-backface-visibility: @visibility;\n     -moz-backface-visibility: @visibility;\n          backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n  -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n          box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n  -webkit-box-sizing: @boxmodel;\n     -moz-box-sizing: @boxmodel;\n          box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n  -webkit-column-count: @column-count;\n     -moz-column-count: @column-count;\n          column-count: @column-count;\n  -webkit-column-gap: @column-gap;\n     -moz-column-gap: @column-gap;\n          column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n  word-wrap: break-word;\n  -webkit-hyphens: @mode;\n     -moz-hyphens: @mode;\n      -ms-hyphens: @mode; // IE10+\n       -o-hyphens: @mode;\n          hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n  // Firefox\n  &::-moz-placeholder {\n    color: @color;\n    opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n  }\n  &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n  &::-webkit-input-placeholder  { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n  -webkit-transform: scale(@ratio);\n      -ms-transform: scale(@ratio); // IE9 only\n       -o-transform: scale(@ratio);\n          transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n  -webkit-transform: scale(@ratioX, @ratioY);\n      -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n       -o-transform: scale(@ratioX, @ratioY);\n          transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n  -webkit-transform: scaleX(@ratio);\n      -ms-transform: scaleX(@ratio); // IE9 only\n       -o-transform: scaleX(@ratio);\n          transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n  -webkit-transform: scaleY(@ratio);\n      -ms-transform: scaleY(@ratio); // IE9 only\n       -o-transform: scaleY(@ratio);\n          transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n  -webkit-transform: skewX(@x) skewY(@y);\n      -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n       -o-transform: skewX(@x) skewY(@y);\n          transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n  -webkit-transform: translate(@x, @y);\n      -ms-transform: translate(@x, @y); // IE9 only\n       -o-transform: translate(@x, @y);\n          transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n  -webkit-transform: translate3d(@x, @y, @z);\n          transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n  -webkit-transform: rotate(@degrees);\n      -ms-transform: rotate(@degrees); // IE9 only\n       -o-transform: rotate(@degrees);\n          transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n  -webkit-transform: rotateX(@degrees);\n      -ms-transform: rotateX(@degrees); // IE9 only\n       -o-transform: rotateX(@degrees);\n          transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n  -webkit-transform: rotateY(@degrees);\n      -ms-transform: rotateY(@degrees); // IE9 only\n       -o-transform: rotateY(@degrees);\n          transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n  -webkit-perspective: @perspective;\n     -moz-perspective: @perspective;\n          perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n  -webkit-perspective-origin: @perspective;\n     -moz-perspective-origin: @perspective;\n          perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n  -webkit-transform-origin: @origin;\n     -moz-transform-origin: @origin;\n      -ms-transform-origin: @origin; // IE9 only\n          transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n  -webkit-transition: @transition;\n       -o-transition: @transition;\n          transition: @transition;\n}\n.transition-property(@transition-property) {\n  -webkit-transition-property: @transition-property;\n          transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n  -webkit-transition-delay: @transition-delay;\n          transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n  -webkit-transition-duration: @transition-duration;\n          transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n  -webkit-transition-timing-function: @timing-function;\n          transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n  -webkit-transition: -webkit-transform @transition;\n     -moz-transition: -moz-transform @transition;\n       -o-transition: -o-transform @transition;\n          transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n  -webkit-user-select: @select;\n     -moz-user-select: @select;\n      -ms-user-select: @select; // IE10+\n          user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n  // Default\n  outline: thin dotted;\n  // WebKit\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n  display: @display;\n  max-width: 100%; // Part 1: Set a maximum relative to the parent\n  height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n  background-image: url(\"@{file-1x}\");\n\n  @media\n  only screen and (-webkit-min-device-pixel-ratio: 2),\n  only screen and (   min--moz-device-pixel-ratio: 2),\n  only screen and (     -o-min-device-pixel-ratio: 2/1),\n  only screen and (        min-device-pixel-ratio: 2),\n  only screen and (                min-resolution: 192dpi),\n  only screen and (                min-resolution: 2dppx) {\n    background-image: url(\"@{file-2x}\");\n    background-size: @width-1x @height-1x;\n  }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n  font-family: @headings-font-family;\n  font-weight: @headings-font-weight;\n  line-height: @headings-line-height;\n  color: @headings-color;\n\n  small,\n  .small {\n    font-weight: normal;\n    line-height: 1;\n    color: @headings-small-color;\n  }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n  margin-top: @line-height-computed;\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 65%;\n  }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n  margin-top: (@line-height-computed / 2);\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 75%;\n  }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n  margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n  margin-bottom: @line-height-computed;\n  font-size: floor((@font-size-base * 1.15));\n  font-weight: 300;\n  line-height: 1.4;\n\n  @media (min-width: @screen-sm-min) {\n    font-size: (@font-size-base * 1.5);\n  }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n  font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n  background-color: @state-warning-bg;\n  padding: .2em;\n}\n\n// Alignment\n.text-left           { text-align: left; }\n.text-right          { text-align: right; }\n.text-center         { text-align: center; }\n.text-justify        { text-align: justify; }\n.text-nowrap         { white-space: nowrap; }\n\n// Transformation\n.text-lowercase      { text-transform: lowercase; }\n.text-uppercase      { text-transform: uppercase; }\n.text-capitalize     { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n  color: @text-muted;\n}\n.text-primary {\n  .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n  .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n  .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n  .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n  .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n  // Given the contrast here, this is the only class to have its color inverted\n  // automatically.\n  color: #fff;\n  .bg-variant(@brand-primary);\n}\n.bg-success {\n  .bg-variant(@state-success-bg);\n}\n.bg-info {\n  .bg-variant(@state-info-bg);\n}\n.bg-warning {\n  .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n  .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n  padding-bottom: ((@line-height-computed / 2) - 1);\n  margin: (@line-height-computed * 2) 0 @line-height-computed;\n  border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n  margin-top: 0;\n  margin-bottom: (@line-height-computed / 2);\n  ul,\n  ol {\n    margin-bottom: 0;\n  }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n  .list-unstyled();\n  margin-left: -5px;\n\n  > li {\n    display: inline-block;\n    padding-left: 5px;\n    padding-right: 5px;\n  }\n}\n\n// Description Lists\ndl {\n  margin-top: 0; // Remove browser default\n  margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n  line-height: @line-height-base;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n  dd {\n    &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    dt {\n      float: left;\n      width: (@dl-horizontal-offset - 20);\n      clear: left;\n      text-align: right;\n      .text-overflow();\n    }\n    dd {\n      margin-left: @dl-horizontal-offset;\n    }\n  }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n  font-size: 90%;\n  .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n  padding: (@line-height-computed / 2) @line-height-computed;\n  margin: 0 0 @line-height-computed;\n  font-size: @blockquote-font-size;\n  border-left: 5px solid @blockquote-border-color;\n\n  p,\n  ul,\n  ol {\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  // Note: Deprecated small and .small as of v3.1.0\n  // Context: https://github.com/twbs/bootstrap/issues/11660\n  footer,\n  small,\n  .small {\n    display: block;\n    font-size: 80%; // back to default font-size\n    line-height: @line-height-base;\n    color: @blockquote-small-color;\n\n    &:before {\n      content: '\\2014 \\00A0'; // em dash, nbsp\n    }\n  }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid @blockquote-border-color;\n  border-left: 0;\n  text-align: right;\n\n  // Account for citation\n  footer,\n  small,\n  .small {\n    &:before { content: ''; }\n    &:after {\n      content: '\\00A0 \\2014'; // nbsp, em dash\n    }\n  }\n}\n\n// Addresses\naddress {\n  margin-bottom: @line-height-computed;\n  font-style: normal;\n  line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n  color: @color;\n  a&:hover,\n  a&:focus {\n    color: darken(@color, 10%);\n  }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n  background-color: @color;\n  a&:hover,\n  a&:focus {\n    background-color: darken(@color, 10%);\n  }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n  font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @code-color;\n  background-color: @code-bg;\n  border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @kbd-color;\n  background-color: @kbd-bg;\n  border-radius: @border-radius-small;\n  box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n  kbd {\n    padding: 0;\n    font-size: 100%;\n    font-weight: bold;\n    box-shadow: none;\n  }\n}\n\n// Blocks of code\npre {\n  display: block;\n  padding: ((@line-height-computed - 1) / 2);\n  margin: 0 0 (@line-height-computed / 2);\n  font-size: (@font-size-base - 1); // 14px to 13px\n  line-height: @line-height-base;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: @pre-color;\n  background-color: @pre-bg;\n  border: 1px solid @pre-border-color;\n  border-radius: @border-radius-base;\n\n  // Account for some code outputs that place code tags in pre tags\n  code {\n    padding: 0;\n    font-size: inherit;\n    color: inherit;\n    white-space: pre-wrap;\n    background-color: transparent;\n    border-radius: 0;\n  }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n  max-height: @pre-scrollable-max-height;\n  overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n  .container-fixed();\n\n  @media (min-width: @screen-sm-min) {\n    width: @container-sm;\n  }\n  @media (min-width: @screen-md-min) {\n    width: @container-md;\n  }\n  @media (min-width: @screen-lg-min) {\n    width: @container-lg;\n  }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n  .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n  .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n  .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n  .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n  .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n  &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n  margin-left:  (@gutter / -2);\n  margin-right: (@gutter / -2);\n  &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  float: left;\n  width: percentage((@columns / @grid-columns));\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n  margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n  left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n  right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-sm-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-offset(@columns) {\n  @media (min-width: @screen-sm-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-push(@columns) {\n  @media (min-width: @screen-sm-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-pull(@columns) {\n  @media (min-width: @screen-sm-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-md-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-offset(@columns) {\n  @media (min-width: @screen-md-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-push(@columns) {\n  @media (min-width: @screen-md-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-pull(@columns) {\n  @media (min-width: @screen-md-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-lg-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-offset(@columns) {\n  @media (min-width: @screen-lg-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-push(@columns) {\n  @media (min-width: @screen-lg-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-pull(@columns) {\n  @media (min-width: @screen-lg-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n  // Common styles for all sizes of grid columns, widths 1-12\n  .col(@index) { // initial\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      position: relative;\n      // Prevent columns from collapsing when empty\n      min-height: 1px;\n      // Inner gutter via padding\n      padding-left:  (@grid-gutter-width / 2);\n      padding-right: (@grid-gutter-width / 2);\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n  .col(@index) { // initial\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      float: left;\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n  .col-@{class}-@{index} {\n    width: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n  .col-@{class}-push-@{index} {\n    left: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n  .col-@{class}-push-0 {\n    left: auto;\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n  .col-@{class}-pull-@{index} {\n    right: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n  .col-@{class}-pull-0 {\n    right: auto;\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n  .col-@{class}-offset-@{index} {\n    margin-left: percentage((@index / @grid-columns));\n  }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n  .calc-grid-column(@index, @class, @type);\n  // next iteration\n  .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n  .float-grid-columns(@class);\n  .loop-grid-columns(@grid-columns, @class, width);\n  .loop-grid-columns(@grid-columns, @class, pull);\n  .loop-grid-columns(@grid-columns, @class, push);\n  .loop-grid-columns(@grid-columns, @class, offset);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n  background-color: @table-bg;\n}\ncaption {\n  padding-top: @table-cell-padding;\n  padding-bottom: @table-cell-padding;\n  color: @text-muted;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: @line-height-computed;\n  // Cells\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-cell-padding;\n        line-height: @line-height-base;\n        vertical-align: top;\n        border-top: 1px solid @table-border-color;\n      }\n    }\n  }\n  // Bottom align for column headings\n  > thead > tr > th {\n    vertical-align: bottom;\n    border-bottom: 2px solid @table-border-color;\n  }\n  // Remove top border from thead by default\n  > caption + thead,\n  > colgroup + thead,\n  > thead:first-child {\n    > tr:first-child {\n      > th,\n      > td {\n        border-top: 0;\n      }\n    }\n  }\n  // Account for multiple tbody instances\n  > tbody + tbody {\n    border-top: 2px solid @table-border-color;\n  }\n\n  // Nesting\n  .table {\n    background-color: @body-bg;\n  }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-condensed-cell-padding;\n      }\n    }\n  }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n  border: 1px solid @table-border-color;\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        border: 1px solid @table-border-color;\n      }\n    }\n  }\n  > thead > tr {\n    > th,\n    > td {\n      border-bottom-width: 2px;\n    }\n  }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n  > tbody > tr:nth-of-type(odd) {\n    background-color: @table-bg-accent;\n  }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n  > tbody > tr:hover {\n    background-color: @table-bg-hover;\n  }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n  position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n  float: none;\n  display: table-column;\n}\ntable {\n  td,\n  th {\n    &[class*=\"col-\"] {\n      position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n      float: none;\n      display: table-cell;\n    }\n  }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n  overflow-x: auto;\n  min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n  @media screen and (max-width: @screen-xs-max) {\n    width: 100%;\n    margin-bottom: (@line-height-computed * 0.75);\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid @table-border-color;\n\n    // Tighten up spacing\n    > .table {\n      margin-bottom: 0;\n\n      // Ensure the content doesn't wrap\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th,\n          > td {\n            white-space: nowrap;\n          }\n        }\n      }\n    }\n\n    // Special overrides for the bordered tables\n    > .table-bordered {\n      border: 0;\n\n      // Nuke the appropriate borders so that the parent can handle them\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th:first-child,\n          > td:first-child {\n            border-left: 0;\n          }\n          > th:last-child,\n          > td:last-child {\n            border-right: 0;\n          }\n        }\n      }\n\n      // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n      // chances are there will be only one `tr` in a `thead` and that would\n      // remove the border altogether.\n      > tbody,\n      > tfoot {\n        > tr:last-child {\n          > th,\n          > td {\n            border-bottom: 0;\n          }\n        }\n      }\n\n    }\n  }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n  // Exact selectors below required to override `.table-striped` and prevent\n  // inheritance to nested tables.\n  .table > thead > tr,\n  .table > tbody > tr,\n  .table > tfoot > tr {\n    > td.@{state},\n    > th.@{state},\n    &.@{state} > td,\n    &.@{state} > th {\n      background-color: @background;\n    }\n  }\n\n  // Hover states for `.table-hover`\n  // Note: this is not available for cells or rows within `thead` or `tfoot`.\n  .table-hover > tbody > tr {\n    > td.@{state}:hover,\n    > th.@{state}:hover,\n    &.@{state}:hover > td,\n    &:hover > .@{state},\n    &.@{state}:hover > th {\n      background-color: darken(@background, 5%);\n    }\n  }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n  // so we reset that to ensure it behaves more like a standard block element.\n  // See https://github.com/twbs/bootstrap/issues/12359.\n  min-width: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: @line-height-computed;\n  font-size: (@font-size-base * 1.5);\n  line-height: inherit;\n  color: @legend-color;\n  border: 0;\n  border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n  display: inline-block;\n  max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n  .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9; // IE8-9\n  line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n  display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  .tab-focus();\n}\n\n// Adjust output element\noutput {\n  display: block;\n  padding-top: (@padding-base-vertical + 1);\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n  display: block;\n  width: 100%;\n  height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n  background-color: @input-bg;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid @input-border;\n  border-radius: @input-border-radius; // Note: This has no effect on <select>s in some browsers, due to the limited stylability of <select>s in CSS.\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n  .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n  // Customize the `:focus` state to imitate native WebKit styles.\n  .form-control-focus();\n\n  // Placeholder\n  .placeholder();\n\n  // Disabled and read-only inputs\n  //\n  // HTML5 says that controls under a fieldset > legend:first-child won't be\n  // disabled if the fieldset is disabled. Due to implementation difficulty, we\n  // don't honor that edge case; we style them as disabled anyway.\n  &[disabled],\n  &[readonly],\n  fieldset[disabled] & {\n    background-color: @input-bg-disabled;\n    opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655\n  }\n\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n  }\n\n  // Reset height for `textarea`s\n  textarea& {\n    height: auto;\n  }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n\n\n// Special styles for iOS temporal inputs\n//\n// In Mobile Safari, setting `display: block` on temporal inputs causes the\n// text within the input to become vertically misaligned. As a workaround, we\n// set a pixel line-height that matches the given height of the input, but only\n// for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848\n\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"],\n  input[type=\"time\"],\n  input[type=\"datetime-local\"],\n  input[type=\"month\"] {\n    line-height: @input-height-base;\n\n    &.input-sm,\n    .input-group-sm & {\n      line-height: @input-height-small;\n    }\n\n    &.input-lg,\n    .input-group-lg & {\n      line-height: @input-height-large;\n    }\n  }\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n  margin-bottom: @form-group-margin-bottom;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n\n  label {\n    min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text\n    padding-left: 20px;\n    margin-bottom: 0;\n    font-weight: normal;\n    cursor: pointer;\n  }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  position: absolute;\n  margin-left: -20px;\n  margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n// Some special care is needed because <label>s don't inherit their parent's `cursor`.\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  &[disabled],\n  &.disabled,\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n  }\n}\n// These classes are used directly on <label>s\n.radio-inline,\n.checkbox-inline {\n  &.disabled,\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n  }\n}\n// These classes are used on elements with <label> descendants\n.radio,\n.checkbox {\n  &.disabled,\n  fieldset[disabled] & {\n    label {\n      cursor: @cursor-disabled;\n    }\n  }\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n  // Size it appropriately next to real form controls\n  padding-top: (@padding-base-vertical + 1);\n  padding-bottom: (@padding-base-vertical + 1);\n  // Remove default margin from `p`\n  margin-bottom: 0;\n  min-height: (@line-height-computed + @font-size-base);\n\n  &.input-lg,\n  &.input-sm {\n    padding-left: 0;\n    padding-right: 0;\n  }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n//\n// The `.form-group-* form-control` variations are sadly duplicated to avoid the\n// issue documented in https://github.com/twbs/bootstrap/issues/15074.\n\n.input-sm {\n  .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @input-border-radius-small);\n}\n.form-group-sm {\n  .form-control {\n    height: @input-height-small;\n    padding: @padding-small-vertical @padding-small-horizontal;\n    font-size: @font-size-small;\n    line-height: @line-height-small;\n    border-radius: @input-border-radius-small;\n  }\n  select.form-control {\n    height: @input-height-small;\n    line-height: @input-height-small;\n  }\n  textarea.form-control,\n  select[multiple].form-control {\n    height: auto;\n  }\n  .form-control-static {\n    height: @input-height-small;\n    min-height: (@line-height-computed + @font-size-small);\n    padding: (@padding-small-vertical + 1) @padding-small-horizontal;\n    font-size: @font-size-small;\n    line-height: @line-height-small;\n  }\n}\n\n.input-lg {\n  .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @input-border-radius-large);\n}\n.form-group-lg {\n  .form-control {\n    height: @input-height-large;\n    padding: @padding-large-vertical @padding-large-horizontal;\n    font-size: @font-size-large;\n    line-height: @line-height-large;\n    border-radius: @input-border-radius-large;\n  }\n  select.form-control {\n    height: @input-height-large;\n    line-height: @input-height-large;\n  }\n  textarea.form-control,\n  select[multiple].form-control {\n    height: auto;\n  }\n  .form-control-static {\n    height: @input-height-large;\n    min-height: (@line-height-computed + @font-size-large);\n    padding: (@padding-large-vertical + 1) @padding-large-horizontal;\n    font-size: @font-size-large;\n    line-height: @line-height-large;\n  }\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n  // Enable absolute positioning\n  position: relative;\n\n  // Ensure icons don't overlap text\n  .form-control {\n    padding-right: (@input-height-base * 1.25);\n  }\n}\n// Feedback icon (requires .glyphicon classes)\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2; // Ensure icon is above input groups\n  display: block;\n  width: @input-height-base;\n  height: @input-height-base;\n  line-height: @input-height-base;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback {\n  width: @input-height-large;\n  height: @input-height-large;\n  line-height: @input-height-large;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback {\n  width: @input-height-small;\n  height: @input-height-small;\n  line-height: @input-height-small;\n}\n\n// Feedback states\n.has-success {\n  .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n  .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n  .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n// Reposition feedback icon if input has visible label above\n.has-feedback label {\n\n  & ~ .form-control-feedback {\n     top: (@line-height-computed + 5); // Height of the `label` and its margin\n  }\n  &.sr-only ~ .form-control-feedback {\n     top: 0;\n  }\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n  display: block; // account for any element using help-block\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n  // Kick in the inline\n  @media (min-width: @screen-sm-min) {\n    // Inline-block all the things for \"inline\"\n    .form-group {\n      display: inline-block;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // In navbar-form, allow folks to *not* use `.form-group`\n    .form-control {\n      display: inline-block;\n      width: auto; // Prevent labels from stacking above inputs in `.form-group`\n      vertical-align: middle;\n    }\n\n    // Make static controls behave like regular ones\n    .form-control-static {\n      display: inline-block;\n    }\n\n    .input-group {\n      display: inline-table;\n      vertical-align: middle;\n\n      .input-group-addon,\n      .input-group-btn,\n      .form-control {\n        width: auto;\n      }\n    }\n\n    // Input groups need that 100% width though\n    .input-group > .form-control {\n      width: 100%;\n    }\n\n    .control-label {\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // Remove default margin on radios/checkboxes that were used for stacking, and\n    // then undo the floating of radios and checkboxes to match.\n    .radio,\n    .checkbox {\n      display: inline-block;\n      margin-top: 0;\n      margin-bottom: 0;\n      vertical-align: middle;\n\n      label {\n        padding-left: 0;\n      }\n    }\n    .radio input[type=\"radio\"],\n    .checkbox input[type=\"checkbox\"] {\n      position: relative;\n      margin-left: 0;\n    }\n\n    // Re-override the feedback icon.\n    .has-feedback .form-control-feedback {\n      top: 0;\n    }\n  }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n  // Consistent vertical alignment of radios and checkboxes\n  //\n  // Labels also get some reset styles, but that is scoped to a media query below.\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline {\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n  }\n  // Account for padding we're adding to ensure the alignment and of help text\n  // and other content below items\n  .radio,\n  .checkbox {\n    min-height: (@line-height-computed + (@padding-base-vertical + 1));\n  }\n\n  // Make form groups behave like rows\n  .form-group {\n    .make-row();\n  }\n\n  // Reset spacing and right align labels, but scope to media queries so that\n  // labels on narrow viewports stack the same as a default form example.\n  @media (min-width: @screen-sm-min) {\n    .control-label {\n      text-align: right;\n      margin-bottom: 0;\n      padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n    }\n  }\n\n  // Validation states\n  //\n  // Reposition the icon because it's now within a grid column and columns have\n  // `position: relative;` on them. Also accounts for the grid gutter padding.\n  .has-feedback .form-control-feedback {\n    right: (@grid-gutter-width / 2);\n  }\n\n  // Form group sizes\n  //\n  // Quick utility class for applying `.input-lg` and `.input-sm` styles to the\n  // inputs and labels within a `.form-group`.\n  .form-group-lg {\n    @media (min-width: @screen-sm-min) {\n      .control-label {\n        padding-top: ((@padding-large-vertical * @line-height-large) + 1);\n        font-size: @font-size-large;\n      }\n    }\n  }\n  .form-group-sm {\n    @media (min-width: @screen-sm-min) {\n      .control-label {\n        padding-top: (@padding-small-vertical + 1);\n        font-size: @font-size-small;\n      }\n    }\n  }\n}\n","// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n  // Color the label and help text\n  .help-block,\n  .control-label,\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline,\n  &.radio label,\n  &.checkbox label,\n  &.radio-inline label,\n  &.checkbox-inline label  {\n    color: @text-color;\n  }\n  // Set the border and box shadow on specific inputs to match\n  .form-control {\n    border-color: @border-color;\n    .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n    &:focus {\n      border-color: darken(@border-color, 10%);\n      @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n      .box-shadow(@shadow);\n    }\n  }\n  // Set validation states also for addons\n  .input-group-addon {\n    color: @text-color;\n    border-color: @border-color;\n    background-color: @background-color;\n  }\n  // Optional feedback icon\n  .form-control-feedback {\n    color: @text-color;\n  }\n}\n\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-border-focus` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n.form-control-focus(@color: @input-border-focus) {\n  @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n  &:focus {\n    border-color: @color;\n    outline: 0;\n    .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n  }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  height: @input-height;\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n\n  select& {\n    height: @input-height;\n    line-height: @input-height;\n  }\n\n  textarea&,\n  select[multiple]& {\n    height: auto;\n  }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n  display: inline-block;\n  margin-bottom: 0; // For input.btn\n  font-weight: @btn-font-weight;\n  text-align: center;\n  vertical-align: middle;\n  touch-action: manipulation;\n  cursor: pointer;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  white-space: nowrap;\n  .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);\n  .user-select(none);\n\n  &,\n  &:active,\n  &.active {\n    &:focus,\n    &.focus {\n      .tab-focus();\n    }\n  }\n\n  &:hover,\n  &:focus,\n  &.focus {\n    color: @btn-default-color;\n    text-decoration: none;\n  }\n\n  &:active,\n  &.active {\n    outline: 0;\n    background-image: none;\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n    .opacity(.65);\n    .box-shadow(none);\n  }\n\n  a& {\n    &.disabled,\n    fieldset[disabled] & {\n      pointer-events: none; // Future-proof disabling of clicks on `<a>` elements\n    }\n  }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n  .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n  .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n  .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n  .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n  .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n  .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n  color: @link-color;\n  font-weight: normal;\n  border-radius: 0;\n\n  &,\n  &:active,\n  &.active,\n  &[disabled],\n  fieldset[disabled] & {\n    background-color: transparent;\n    .box-shadow(none);\n  }\n  &,\n  &:hover,\n  &:focus,\n  &:active {\n    border-color: transparent;\n  }\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: @link-hover-decoration;\n    background-color: transparent;\n  }\n  &[disabled],\n  fieldset[disabled] & {\n    &:hover,\n    &:focus {\n      color: @btn-link-disabled-color;\n      text-decoration: none;\n    }\n  }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n  // line-height: ensure even-numbered height of button next to large input\n  .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n.btn-sm {\n  // line-height: ensure proper height of button next to small input\n  .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n.btn-xs {\n  .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n  display: block;\n  width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n  &.btn-block {\n    width: 100%;\n  }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n  color: @color;\n  background-color: @background;\n  border-color: @border;\n\n  &:focus,\n  &.focus {\n    color: @color;\n    background-color: darken(@background, 10%);\n        border-color: darken(@border, 25%);\n  }\n  &:hover {\n    color: @color;\n    background-color: darken(@background, 10%);\n        border-color: darken(@border, 12%);\n  }\n  &:active,\n  &.active,\n  .open > .dropdown-toggle& {\n    color: @color;\n    background-color: darken(@background, 10%);\n        border-color: darken(@border, 12%);\n\n    &:hover,\n    &:focus,\n    &.focus {\n      color: @color;\n      background-color: darken(@background, 17%);\n          border-color: darken(@border, 25%);\n    }\n  }\n  &:active,\n  &.active,\n  .open > .dropdown-toggle& {\n    background-image: none;\n  }\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    &,\n    &:hover,\n    &:focus,\n    &.focus,\n    &:active,\n    &.active {\n      background-color: @background;\n          border-color: @border;\n    }\n  }\n\n  .badge {\n    color: @background;\n    background-color: @color;\n  }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n}\n","// Opacity\n\n.opacity(@opacity) {\n  opacity: @opacity;\n  // IE8 filter\n  @opacity-ie: (@opacity * 100);\n  filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n  opacity: 0;\n  .transition(opacity .15s linear);\n  &.in {\n    opacity: 1;\n  }\n}\n\n.collapse {\n  display: none;\n\n  &.in      { display: block; }\n  tr&.in    { display: table-row; }\n  tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  .transition-property(~\"height, visibility\");\n  .transition-duration(.35s);\n  .transition-timing-function(ease);\n}\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top:   @caret-width-base dashed;\n  border-right: @caret-width-base solid transparent;\n  border-left:  @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropup,\n.dropdown {\n  position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n  outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: @zindex-dropdown;\n  display: none; // none by default, but block on \"open\" of the menu\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0; // override default ul\n  list-style: none;\n  font-size: @font-size-base;\n  text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n  background-color: @dropdown-bg;\n  border: 1px solid @dropdown-fallback-border; // IE8 fallback\n  border: 1px solid @dropdown-border;\n  border-radius: @border-radius-base;\n  .box-shadow(0 6px 12px rgba(0,0,0,.175));\n  background-clip: padding-box;\n\n  // Aligns the dropdown menu to right\n  //\n  // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n  &.pull-right {\n    right: 0;\n    left: auto;\n  }\n\n  // Dividers (basically an hr) within the dropdown\n  .divider {\n    .nav-divider(@dropdown-divider-bg);\n  }\n\n  // Links within the dropdown menu\n  > li > a {\n    display: block;\n    padding: 3px 20px;\n    clear: both;\n    font-weight: normal;\n    line-height: @line-height-base;\n    color: @dropdown-link-color;\n    white-space: nowrap; // prevent links from randomly breaking onto new lines\n  }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    color: @dropdown-link-hover-color;\n    background-color: @dropdown-link-hover-bg;\n  }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-active-color;\n    text-decoration: none;\n    outline: 0;\n    background-color: @dropdown-link-active-bg;\n  }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-disabled-color;\n  }\n\n  // Nuke hover/focus effects\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    background-color: transparent;\n    background-image: none; // Remove CSS gradient\n    .reset-filter();\n    cursor: @cursor-disabled;\n  }\n}\n\n// Open state for the dropdown\n.open {\n  // Show the menu\n  > .dropdown-menu {\n    display: block;\n  }\n\n  // Remove the outline when :focus is triggered\n  > a {\n    outline: 0;\n  }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n  left: auto; // Reset the default from `.dropdown-menu`\n  right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: @font-size-small;\n  line-height: @line-height-base;\n  color: @dropdown-header-color;\n  white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n  // Reverse the caret\n  .caret {\n    border-top: 0;\n    border-bottom: @caret-width-base solid;\n    content: \"\";\n  }\n  // Different positioning for bottom up menu\n  .dropdown-menu {\n    top: auto;\n    bottom: 100%;\n    margin-bottom: 2px;\n  }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-right {\n    .dropdown-menu {\n      .dropdown-menu-right();\n    }\n    // Necessary for overrides of the default right aligned menu.\n    // Will remove come v4 in all likelihood.\n    .dropdown-menu-left {\n      .dropdown-menu-left();\n    }\n  }\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n  height: 1px;\n  margin: ((@line-height-computed / 2) - 1) 0;\n  overflow: hidden;\n  background-color: @color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n  filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle; // match .btn alignment given font-size hack above\n  > .btn {\n    position: relative;\n    float: left;\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active,\n    &.active {\n      z-index: 2;\n    }\n  }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n  .btn + .btn,\n  .btn + .btn-group,\n  .btn-group + .btn,\n  .btn-group + .btn-group {\n    margin-left: -1px;\n  }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n  margin-left: -5px; // Offset the first child's margin\n  &:extend(.clearfix all);\n\n  .btn,\n  .btn-group,\n  .input-group {\n    float: left;\n  }\n  > .btn,\n  > .btn-group,\n  > .input-group {\n    margin-left: 5px;\n  }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  &:not(:last-child):not(.dropdown-toggle) {\n    .border-right-radius(0);\n  }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-right-radius(0);\n  }\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n  .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n  // Show no shadow for `.btn-link` since it has no other button styles.\n  &.btn-link {\n    .box-shadow(none);\n  }\n}\n\n\n// Reposition the caret\n.btn .caret {\n  margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n  border-width: @caret-width-large @caret-width-large 0;\n  border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n  border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n  > .btn,\n  > .btn-group,\n  > .btn-group > .btn {\n    display: block;\n    float: none;\n    width: 100%;\n    max-width: 100%;\n  }\n\n  // Clear floats so dropdown menus can be properly placed\n  > .btn-group {\n    &:extend(.clearfix all);\n    > .btn {\n      float: none;\n    }\n  }\n\n  > .btn + .btn,\n  > .btn + .btn-group,\n  > .btn-group + .btn,\n  > .btn-group + .btn-group {\n    margin-top: -1px;\n    margin-left: 0;\n  }\n}\n\n.btn-group-vertical > .btn {\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n  &:first-child:not(:last-child) {\n    border-top-right-radius: @border-radius-base;\n    .border-bottom-radius(0);\n  }\n  &:last-child:not(:first-child) {\n    border-bottom-left-radius: @border-radius-base;\n    .border-top-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-bottom-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n  > .btn,\n  > .btn-group {\n    float: none;\n    display: table-cell;\n    width: 1%;\n  }\n  > .btn-group .btn {\n    width: 100%;\n  }\n\n  > .btn-group .dropdown-menu {\n    left: auto;\n  }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n  > .btn,\n  > .btn-group > .btn {\n    input[type=\"radio\"],\n    input[type=\"checkbox\"] {\n      position: absolute;\n      clip: rect(0,0,0,0);\n      pointer-events: none;\n    }\n  }\n}\n","// Single side border-radius\n\n.border-top-radius(@radius) {\n  border-top-right-radius: @radius;\n   border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n  border-bottom-right-radius: @radius;\n     border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n  border-bottom-right-radius: @radius;\n   border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n  border-bottom-left-radius: @radius;\n     border-top-left-radius: @radius;\n}\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n  position: relative; // For dropdowns\n  display: table;\n  border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n  // Undo padding and float of grid classes\n  &[class*=\"col-\"] {\n    float: none;\n    padding-left: 0;\n    padding-right: 0;\n  }\n\n  .form-control {\n    // Ensure that the input is always above the *appended* addon button for\n    // proper border colors.\n    position: relative;\n    z-index: 2;\n\n    // IE9 fubars the placeholder attribute in text inputs and the arrows on\n    // select elements in input groups. To fix it, we float the input. Details:\n    // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n    float: left;\n\n    width: 100%;\n    margin-bottom: 0;\n  }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  font-weight: normal;\n  line-height: 1;\n  color: @input-color;\n  text-align: center;\n  background-color: @input-group-addon-bg;\n  border: 1px solid @input-group-addon-border-color;\n  border-radius: @border-radius-base;\n\n  // Sizing\n  &.input-sm {\n    padding: @padding-small-vertical @padding-small-horizontal;\n    font-size: @font-size-small;\n    border-radius: @border-radius-small;\n  }\n  &.input-lg {\n    padding: @padding-large-vertical @padding-large-horizontal;\n    font-size: @font-size-large;\n    border-radius: @border-radius-large;\n  }\n\n  // Nuke default margins from checkboxes and radios to vertically center within.\n  input[type=\"radio\"],\n  input[type=\"checkbox\"] {\n    margin-top: 0;\n  }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  .border-right-radius(0);\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  .border-left-radius(0);\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n  position: relative;\n  // Jankily prevent input button groups from wrapping with `white-space` and\n  // `font-size` in combination with `inline-block` on buttons.\n  font-size: 0;\n  white-space: nowrap;\n\n  // Negative margin for spacing, position for bringing hovered/focused/actived\n  // element above the siblings.\n  > .btn {\n    position: relative;\n    + .btn {\n      margin-left: -1px;\n    }\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active {\n      z-index: 2;\n    }\n  }\n\n  // Negative margin to only have a 1px border between the two\n  &:first-child {\n    > .btn,\n    > .btn-group {\n      margin-right: -1px;\n    }\n  }\n  &:last-child {\n    > .btn,\n    > .btn-group {\n      z-index: 2;\n      margin-left: -1px;\n    }\n  }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n  margin-bottom: 0;\n  padding-left: 0; // Override default ul/ol\n  list-style: none;\n  &:extend(.clearfix all);\n\n  > li {\n    position: relative;\n    display: block;\n\n    > a {\n      position: relative;\n      display: block;\n      padding: @nav-link-padding;\n      &:hover,\n      &:focus {\n        text-decoration: none;\n        background-color: @nav-link-hover-bg;\n      }\n    }\n\n    // Disabled state sets text to gray and nukes hover/tab effects\n    &.disabled > a {\n      color: @nav-disabled-link-color;\n\n      &:hover,\n      &:focus {\n        color: @nav-disabled-link-hover-color;\n        text-decoration: none;\n        background-color: transparent;\n        cursor: @cursor-disabled;\n      }\n    }\n  }\n\n  // Open dropdowns\n  .open > a {\n    &,\n    &:hover,\n    &:focus {\n      background-color: @nav-link-hover-bg;\n      border-color: @link-color;\n    }\n  }\n\n  // Nav dividers (deprecated with v3.0.1)\n  //\n  // This should have been removed in v3 with the dropping of `.nav-list`, but\n  // we missed it. We don't currently support this anywhere, but in the interest\n  // of maintaining backward compatibility in case you use it, it's deprecated.\n  .nav-divider {\n    .nav-divider();\n  }\n\n  // Prevent IE8 from misplacing imgs\n  //\n  // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n  > li > a > img {\n    max-width: none;\n  }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n  border-bottom: 1px solid @nav-tabs-border-color;\n  > li {\n    float: left;\n    // Make the list-items overlay the bottom border\n    margin-bottom: -1px;\n\n    // Actual tabs (as links)\n    > a {\n      margin-right: 2px;\n      line-height: @line-height-base;\n      border: 1px solid transparent;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n      &:hover {\n        border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n      }\n    }\n\n    // Active state, and its :hover to override normal :hover\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-tabs-active-link-hover-color;\n        background-color: @nav-tabs-active-link-hover-bg;\n        border: 1px solid @nav-tabs-active-link-hover-border-color;\n        border-bottom-color: transparent;\n        cursor: default;\n      }\n    }\n  }\n  // pulling this in mainly for less shorthand\n  &.nav-justified {\n    .nav-justified();\n    .nav-tabs-justified();\n  }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n  > li {\n    float: left;\n\n    // Links rendered as pills\n    > a {\n      border-radius: @nav-pills-border-radius;\n    }\n    + li {\n      margin-left: 2px;\n    }\n\n    // Active state\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-pills-active-link-hover-color;\n        background-color: @nav-pills-active-link-hover-bg;\n      }\n    }\n  }\n}\n\n\n// Stacked pills\n.nav-stacked {\n  > li {\n    float: none;\n    + li {\n      margin-top: 2px;\n      margin-left: 0; // no need for this gap between nav items\n    }\n  }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n  width: 100%;\n\n  > li {\n    float: none;\n    > a {\n      text-align: center;\n      margin-bottom: 5px;\n    }\n  }\n\n  > .dropdown .dropdown-menu {\n    top: auto;\n    left: auto;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li {\n      display: table-cell;\n      width: 1%;\n      > a {\n        margin-bottom: 0;\n      }\n    }\n  }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n  border-bottom: 0;\n\n  > li > a {\n    // Override margin from .nav-tabs\n    margin-right: 0;\n    border-radius: @border-radius-base;\n  }\n\n  > .active > a,\n  > .active > a:hover,\n  > .active > a:focus {\n    border: 1px solid @nav-tabs-justified-link-border-color;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li > a {\n      border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n    }\n    > .active > a,\n    > .active > a:hover,\n    > .active > a:focus {\n      border-bottom-color: @nav-tabs-justified-active-link-border-color;\n    }\n  }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n  > .tab-pane {\n    display: none;\n  }\n  > .active {\n    display: block;\n  }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Make dropdown carets use link color in navs\n.nav .caret {\n  border-top-color: @brand-danger;\n  border-bottom-color: @brand-danger;\n}\n.nav a:hover .caret {\n  border-top-color: darken(@brand-danger, 10%);\n  border-bottom-color: darken(@brand-danger, 10%);\n}\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n  // make dropdown border overlap tab border\n  margin-top: -1px;\n  // Remove the top rounded corners here since there is a hard edge above the menu\n  .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n  position: relative;\n  min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n  margin-bottom: @navbar-margin-bottom;\n  border: 1px solid transparent;\n\n  // Prevent floats from breaking the navbar\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: @navbar-border-radius;\n  }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n  }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n  overflow-x: visible;\n  padding-right: @navbar-padding-horizontal;\n  padding-left:  @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n  &:extend(.clearfix all);\n  -webkit-overflow-scrolling: touch;\n\n  &.in {\n    overflow-y: auto;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n\n    &.collapse {\n      display: block !important;\n      height: auto !important;\n      padding-bottom: 0; // Override default setting\n      overflow: visible !important;\n    }\n\n    &.in {\n      overflow-y: visible;\n    }\n\n    // Undo the collapse side padding for navbars with containers to ensure\n    // alignment of right-aligned contents.\n    .navbar-fixed-top &,\n    .navbar-static-top &,\n    .navbar-fixed-bottom & {\n      padding-left: 0;\n      padding-right: 0;\n    }\n  }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  .navbar-collapse {\n    max-height: @navbar-collapse-max-height;\n\n    @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n      max-height: 200px;\n    }\n  }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n  > .navbar-header,\n  > .navbar-collapse {\n    margin-right: -@navbar-padding-horizontal;\n    margin-left:  -@navbar-padding-horizontal;\n\n    @media (min-width: @grid-float-breakpoint) {\n      margin-right: 0;\n      margin-left:  0;\n    }\n  }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n  z-index: @zindex-navbar;\n  border-width: 0 0 1px;\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: @zindex-navbar-fixed;\n\n  // Undo the rounded corners\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0; // override .navbar defaults\n  border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n  float: left;\n  padding: @navbar-padding-vertical @navbar-padding-horizontal;\n  font-size: @font-size-large;\n  line-height: @line-height-computed;\n  height: @navbar-height;\n  font-family: @font-family-brand;\n  font-weight: bold;\n\n  &:hover,\n  &:focus {\n    text-decoration: none;\n  }\n\n  > img {\n    display: block;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    .navbar > .container &,\n    .navbar > .container-fluid & {\n      margin-left: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: @navbar-padding-horizontal;\n  padding: 9px 10px;\n  .navbar-vertical-align(34px);\n  background-color: transparent;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  border-radius: @border-radius-base;\n\n  // We remove the `outline` here, but later compensate by attaching `:hover`\n  // styles to `:focus`.\n  &:focus {\n    outline: 0;\n  }\n\n  // Bars\n  .icon-bar {\n    display: block;\n    width: 22px;\n    height: 2px;\n    border-radius: 1px;\n  }\n  .icon-bar + .icon-bar {\n    margin-top: 4px;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    display: none;\n  }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n  margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n  > li > a {\n    padding-top:    10px;\n    padding-bottom: 10px;\n    line-height: @line-height-computed;\n  }\n\n  @media (max-width: @grid-float-breakpoint-max) {\n    // Dropdowns get custom display when collapsed\n    .open .dropdown-menu {\n      position: static;\n      float: none;\n      width: auto;\n      margin-top: 0;\n      background-color: transparent;\n      border: 0;\n      box-shadow: none;\n      > li > a,\n      .dropdown-header {\n        padding: 5px 15px 5px 25px;\n      }\n      > li > a {\n        line-height: @line-height-computed;\n        &:hover,\n        &:focus {\n          background-image: none;\n        }\n      }\n    }\n  }\n\n  // Uncollapse the nav\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin: 0;\n\n    > li {\n      float: left;\n      > a {\n        padding-top:    @navbar-padding-vertical;\n        padding-bottom: @navbar-padding-vertical;\n      }\n    }\n  }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n  margin-left: -@navbar-padding-horizontal;\n  margin-right: -@navbar-padding-horizontal;\n  padding: 10px @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n\n  // Mixin behavior for optimum display\n  .form-inline();\n\n  .form-group {\n    @media (max-width: @grid-float-breakpoint-max) {\n      margin-bottom: 5px;\n\n      &:last-child {\n        margin-bottom: 0;\n      }\n    }\n  }\n\n  // Vertically center in expanded, horizontal navbar\n  .navbar-vertical-align(@input-height-base);\n\n  // Undo 100% width for pull classes\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    .box-shadow(none);\n  }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  .border-top-radius(@navbar-border-radius);\n  .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n  .navbar-vertical-align(@input-height-base);\n\n  &.btn-sm {\n    .navbar-vertical-align(@input-height-small);\n  }\n  &.btn-xs {\n    .navbar-vertical-align(22);\n  }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n  .navbar-vertical-align(@line-height-computed);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin-left: @navbar-padding-horizontal;\n    margin-right: @navbar-padding-horizontal;\n  }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-left  { .pull-left(); }\n  .navbar-right {\n    .pull-right();\n    margin-right: -@navbar-padding-horizontal;\n\n    ~ .navbar-right {\n      margin-right: 0;\n    }\n  }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  background-color: @navbar-default-bg;\n  border-color: @navbar-default-border;\n\n  .navbar-brand {\n    color: @navbar-default-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-default-brand-hover-color;\n      background-color: @navbar-default-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-default-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-default-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-hover-color;\n        background-color: @navbar-default-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-active-color;\n        background-color: @navbar-default-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-disabled-color;\n        background-color: @navbar-default-link-disabled-bg;\n      }\n    }\n  }\n\n  .navbar-toggle {\n    border-color: @navbar-default-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-default-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-default-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: @navbar-default-border;\n  }\n\n  // Dropdown menu items\n  .navbar-nav {\n    // Remove background color from open dropdown\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-default-link-active-bg;\n        color: @navbar-default-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display when collapsed\n      .open .dropdown-menu {\n        > li > a {\n          color: @navbar-default-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-hover-color;\n            background-color: @navbar-default-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-active-color;\n            background-color: @navbar-default-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-disabled-color;\n            background-color: @navbar-default-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n\n  // Links in navbars\n  //\n  // Add a class to ensure links outside the navbar nav are colored correctly.\n\n  .navbar-link {\n    color: @navbar-default-link-color;\n    &:hover {\n      color: @navbar-default-link-hover-color;\n    }\n  }\n\n  .btn-link {\n    color: @navbar-default-link-color;\n    &:hover,\n    &:focus {\n      color: @navbar-default-link-hover-color;\n    }\n    &[disabled],\n    fieldset[disabled] & {\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-disabled-color;\n      }\n    }\n  }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n  background-color: @navbar-inverse-bg;\n  border-color: @navbar-inverse-border;\n\n  .navbar-brand {\n    color: @navbar-inverse-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-inverse-brand-hover-color;\n      background-color: @navbar-inverse-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-inverse-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-inverse-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-hover-color;\n        background-color: @navbar-inverse-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-active-color;\n        background-color: @navbar-inverse-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-disabled-color;\n        background-color: @navbar-inverse-link-disabled-bg;\n      }\n    }\n  }\n\n  // Darken the responsive nav toggle\n  .navbar-toggle {\n    border-color: @navbar-inverse-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-inverse-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-inverse-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: darken(@navbar-inverse-bg, 7%);\n  }\n\n  // Dropdowns\n  .navbar-nav {\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-inverse-link-active-bg;\n        color: @navbar-inverse-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display\n      .open .dropdown-menu {\n        > .dropdown-header {\n          border-color: @navbar-inverse-border;\n        }\n        .divider {\n          background-color: @navbar-inverse-border;\n        }\n        > li > a {\n          color: @navbar-inverse-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-hover-color;\n            background-color: @navbar-inverse-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-active-color;\n            background-color: @navbar-inverse-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-disabled-color;\n            background-color: @navbar-inverse-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n  .navbar-link {\n    color: @navbar-inverse-link-color;\n    &:hover {\n      color: @navbar-inverse-link-hover-color;\n    }\n  }\n\n  .btn-link {\n    color: @navbar-inverse-link-color;\n    &:hover,\n    &:focus {\n      color: @navbar-inverse-link-hover-color;\n    }\n    &[disabled],\n    fieldset[disabled] & {\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-disabled-color;\n      }\n    }\n  }\n}\n","// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n  margin-top: ((@navbar-height - @element-height) / 2);\n  margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n  .clearfix();\n}\n.center-block {\n  .center-block();\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n  display: none !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n  position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n  padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n  margin-bottom: @line-height-computed;\n  list-style: none;\n  background-color: @breadcrumb-bg;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline-block;\n\n    + li:before {\n      content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n      padding: 0 5px;\n      color: @breadcrumb-color;\n    }\n  }\n\n  > .active {\n    color: @breadcrumb-active-color;\n  }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline; // Remove list-style and block-level defaults\n    > a,\n    > span {\n      position: relative;\n      float: left; // Collapse white-space\n      padding: @padding-base-vertical @padding-base-horizontal;\n      line-height: @line-height-base;\n      text-decoration: none;\n      color: @pagination-color;\n      background-color: @pagination-bg;\n      border: 1px solid @pagination-border;\n      margin-left: -1px;\n    }\n    &:first-child {\n      > a,\n      > span {\n        margin-left: 0;\n        .border-left-radius(@border-radius-base);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius-base);\n      }\n    }\n  }\n\n  > li > a,\n  > li > span {\n    &:hover,\n    &:focus {\n      z-index: 3;\n      color: @pagination-hover-color;\n      background-color: @pagination-hover-bg;\n      border-color: @pagination-hover-border;\n    }\n  }\n\n  > .active > a,\n  > .active > span {\n    &,\n    &:hover,\n    &:focus {\n      z-index: 2;\n      color: @pagination-active-color;\n      background-color: @pagination-active-bg;\n      border-color: @pagination-active-border;\n      cursor: default;\n    }\n  }\n\n  > .disabled {\n    > span,\n    > span:hover,\n    > span:focus,\n    > a,\n    > a:hover,\n    > a:focus {\n      color: @pagination-disabled-color;\n      background-color: @pagination-disabled-bg;\n      border-color: @pagination-disabled-border;\n      cursor: @cursor-disabled;\n    }\n  }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n  .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n  .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);\n}\n","// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n  > li {\n    > a,\n    > span {\n      padding: @padding-vertical @padding-horizontal;\n      font-size: @font-size;\n    }\n    &:first-child {\n      > a,\n      > span {\n        .border-left-radius(@border-radius);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius);\n      }\n    }\n  }\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  list-style: none;\n  text-align: center;\n  &:extend(.clearfix all);\n  li {\n    display: inline;\n    > a,\n    > span {\n      display: inline-block;\n      padding: 5px 14px;\n      background-color: @pager-bg;\n      border: 1px solid @pager-border;\n      border-radius: @pager-border-radius;\n    }\n\n    > a:hover,\n    > a:focus {\n      text-decoration: none;\n      background-color: @pager-hover-bg;\n    }\n  }\n\n  .next {\n    > a,\n    > span {\n      float: right;\n    }\n  }\n\n  .previous {\n    > a,\n    > span {\n      float: left;\n    }\n  }\n\n  .disabled {\n    > a,\n    > a:hover,\n    > a:focus,\n    > span {\n      color: @pager-disabled-color;\n      background-color: @pager-bg;\n      cursor: @cursor-disabled;\n    }\n  }\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: @label-color;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n\n  // Add hover effects, but only for links\n  a& {\n    &:hover,\n    &:focus {\n      color: @label-link-hover-color;\n      text-decoration: none;\n      cursor: pointer;\n    }\n  }\n\n  // Empty labels collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for labels in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n  .label-variant(@label-default-bg);\n}\n\n.label-primary {\n  .label-variant(@label-primary-bg);\n}\n\n.label-success {\n  .label-variant(@label-success-bg);\n}\n\n.label-info {\n  .label-variant(@label-info-bg);\n}\n\n.label-warning {\n  .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n  .label-variant(@label-danger-bg);\n}\n","// Labels\n\n.label-variant(@color) {\n  background-color: @color;\n\n  &[href] {\n    &:hover,\n    &:focus {\n      background-color: darken(@color, 10%);\n    }\n  }\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: @font-size-small;\n  font-weight: @badge-font-weight;\n  color: @badge-color;\n  line-height: @badge-line-height;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: @badge-bg;\n  border-radius: @badge-border-radius;\n\n  // Empty badges collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for badges in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n\n  .btn-xs &,\n  .btn-group-xs > .btn & {\n    top: 0;\n    padding: 1px 5px;\n  }\n\n  // Hover state, but only for links\n  a& {\n    &:hover,\n    &:focus {\n      color: @badge-link-hover-color;\n      text-decoration: none;\n      cursor: pointer;\n    }\n  }\n\n  // Account for badges in navs\n  .list-group-item.active > &,\n  .nav-pills > .active > a > & {\n    color: @badge-active-color;\n    background-color: @badge-active-bg;\n  }\n\n  .list-group-item > & {\n    float: right;\n  }\n\n  .list-group-item > & + & {\n    margin-right: 5px;\n  }\n\n  .nav-pills > li > a > & {\n    margin-left: 3px;\n  }\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n  padding: @jumbotron-padding (@jumbotron-padding / 2);\n  margin-bottom: @jumbotron-padding;\n  color: @jumbotron-color;\n  background-color: @jumbotron-bg;\n\n  h1,\n  .h1 {\n    color: @jumbotron-heading-color;\n  }\n\n  p {\n    margin-bottom: (@jumbotron-padding / 2);\n    font-size: @jumbotron-font-size;\n    font-weight: 200;\n  }\n\n  > hr {\n    border-top-color: darken(@jumbotron-bg, 10%);\n  }\n\n  .container &,\n  .container-fluid & {\n    border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n  }\n\n  .container {\n    max-width: 100%;\n  }\n\n  @media screen and (min-width: @screen-sm-min) {\n    padding: (@jumbotron-padding * 1.6) 0;\n\n    .container &,\n    .container-fluid & {\n      padding-left:  (@jumbotron-padding * 2);\n      padding-right: (@jumbotron-padding * 2);\n    }\n\n    h1,\n    .h1 {\n      font-size: @jumbotron-heading-font-size;\n    }\n  }\n}\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n  display: block;\n  padding: @thumbnail-padding;\n  margin-bottom: @line-height-computed;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(border .2s ease-in-out);\n\n  > img,\n  a > img {\n    &:extend(.img-responsive);\n    margin-left: auto;\n    margin-right: auto;\n  }\n\n  // Add a hover state for linked versions only\n  a&:hover,\n  a&:focus,\n  a&.active {\n    border-color: @link-color;\n  }\n\n  // Image captions\n  .caption {\n    padding: @thumbnail-caption-padding;\n    color: @thumbnail-caption-color;\n  }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n  padding: @alert-padding;\n  margin-bottom: @line-height-computed;\n  border: 1px solid transparent;\n  border-radius: @alert-border-radius;\n\n  // Headings for larger alerts\n  h4 {\n    margin-top: 0;\n    // Specified for the h4 to prevent conflicts of changing @headings-color\n    color: inherit;\n  }\n\n  // Provide class for links that match alerts\n  .alert-link {\n    font-weight: @alert-link-font-weight;\n  }\n\n  // Improve alignment and spacing of inner content\n  > p,\n  > ul {\n    margin-bottom: 0;\n  }\n\n  > p + p {\n    margin-top: 5px;\n  }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissible {\n  padding-right: (@alert-padding + 20);\n\n  // Adjust close link position\n  .close {\n    position: relative;\n    top: -2px;\n    right: -21px;\n    color: inherit;\n  }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n  .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n\n.alert-info {\n  .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n\n.alert-warning {\n  .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n\n.alert-danger {\n  .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n  background-color: @background;\n  border-color: @border;\n  color: @text-color;\n\n  hr {\n    border-top-color: darken(@border, 5%);\n  }\n  .alert-link {\n    color: darken(@text-color, 10%);\n  }\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n  overflow: hidden;\n  height: @line-height-computed;\n  margin-bottom: @line-height-computed;\n  background-color: @progress-bg;\n  border-radius: @progress-border-radius;\n  .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: @font-size-small;\n  line-height: @line-height-computed;\n  color: @progress-bar-color;\n  text-align: center;\n  background-color: @progress-bar-bg;\n  .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n  .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  #gradient > .striped();\n  background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n  .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n  .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n  .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n  .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n  .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Gradients\n\n#gradient {\n\n  // Horizontal gradient, from left to right\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n    background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  // Vertical gradient, from top to bottom\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Opera 12\n    background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n    background-repeat: repeat-x;\n    background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n    background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n  }\n  .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .radial(@inner-color: #555; @outer-color: #333) {\n    background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n    background-image: radial-gradient(circle, @inner-color, @outer-color);\n    background-repeat: no-repeat;\n  }\n  .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n    background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n  }\n}\n","// Progress bars\n\n.progress-bar-variant(@color) {\n  background-color: @color;\n\n  // Deprecated parent class requirement as of v3.2.0\n  .progress-striped & {\n    #gradient > .striped();\n  }\n}\n",".media {\n  // Proper spacing between instances of .media\n  margin-top: 15px;\n\n  &:first-child {\n    margin-top: 0;\n  }\n}\n\n.media,\n.media-body {\n  zoom: 1;\n  overflow: hidden;\n}\n\n.media-body {\n  width: 10000px;\n}\n\n.media-object {\n  display: block;\n}\n\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n\n.media-middle {\n  vertical-align: middle;\n}\n\n.media-bottom {\n  vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n  // No need to set list-style: none; since .list-group-item is block level\n  margin-bottom: 20px;\n  padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  // Place the border on the list items and negative margin up for better styling\n  margin-bottom: -1px;\n  background-color: @list-group-bg;\n  border: 1px solid @list-group-border;\n\n  // Round the first and last items\n  &:first-child {\n    .border-top-radius(@list-group-border-radius);\n  }\n  &:last-child {\n    margin-bottom: 0;\n    .border-bottom-radius(@list-group-border-radius);\n  }\n}\n\n\n// Linked list items\n//\n// Use anchor elements instead of `li`s or `div`s to create linked list items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item {\n  color: @list-group-link-color;\n\n  .list-group-item-heading {\n    color: @list-group-link-heading-color;\n  }\n\n  // Hover state\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    color: @list-group-link-hover-color;\n    background-color: @list-group-hover-bg;\n  }\n}\n\n.list-group-item {\n  // Disabled state\n  &.disabled,\n  &.disabled:hover,\n  &.disabled:focus {\n    background-color: @list-group-disabled-bg;\n    color: @list-group-disabled-color;\n    cursor: @cursor-disabled;\n\n    // Force color to inherit for custom content\n    .list-group-item-heading {\n      color: inherit;\n    }\n    .list-group-item-text {\n      color: @list-group-disabled-text-color;\n    }\n  }\n\n  // Active class on item itself, not parent\n  &.active,\n  &.active:hover,\n  &.active:focus {\n    z-index: 2; // Place active items above their siblings for proper border styling\n    color: @list-group-active-color;\n    background-color: @list-group-active-bg;\n    border-color: @list-group-active-border;\n\n    // Force color to inherit for custom content\n    .list-group-item-heading,\n    .list-group-item-heading > small,\n    .list-group-item-heading > .small {\n      color: inherit;\n    }\n    .list-group-item-text {\n      color: @list-group-active-text-color;\n    }\n  }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n","// List Groups\n\n.list-group-item-variant(@state; @background; @color) {\n  .list-group-item-@{state} {\n    color: @color;\n    background-color: @background;\n\n    a& {\n      color: @color;\n\n      .list-group-item-heading {\n        color: inherit;\n      }\n\n      &:hover,\n      &:focus {\n        color: @color;\n        background-color: darken(@background, 5%);\n      }\n      &.active,\n      &.active:hover,\n      &.active:focus {\n        color: #fff;\n        background-color: @color;\n        border-color: @color;\n      }\n    }\n  }\n}\n","//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n  margin-bottom: @line-height-computed;\n  background-color: @panel-bg;\n  border: 1px solid transparent;\n  border-radius: @panel-border-radius;\n  .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n  padding: @panel-body-padding;\n  &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n  padding: @panel-heading-padding;\n  border-bottom: 1px solid transparent;\n  .border-top-radius((@panel-border-radius - 1));\n\n  > .dropdown .dropdown-toggle {\n    color: inherit;\n  }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: ceil((@font-size-base * 1.125));\n  color: inherit;\n\n  > a,\n  > small,\n  > .small,\n  > small > a,\n  > .small > a {\n    color: inherit;\n  }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n  padding: @panel-footer-padding;\n  background-color: @panel-footer-bg;\n  border-top: 1px solid @panel-inner-border;\n  .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n  > .list-group,\n  > .panel-collapse > .list-group {\n    margin-bottom: 0;\n\n    .list-group-item {\n      border-width: 1px 0;\n      border-radius: 0;\n    }\n\n    // Add border top radius for first one\n    &:first-child {\n      .list-group-item:first-child {\n        border-top: 0;\n        .border-top-radius((@panel-border-radius - 1));\n      }\n    }\n\n    // Add border bottom radius for last one\n    &:last-child {\n      .list-group-item:last-child {\n        border-bottom: 0;\n        .border-bottom-radius((@panel-border-radius - 1));\n      }\n    }\n  }\n  > .panel-heading + .panel-collapse > .list-group {\n    .list-group-item:first-child {\n      .border-top-radius(0);\n    }\n  }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n  .list-group-item:first-child {\n    border-top-width: 0;\n  }\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n  > .table,\n  > .table-responsive > .table,\n  > .panel-collapse > .table {\n    margin-bottom: 0;\n\n    caption {\n      padding-left: @panel-body-padding;\n      padding-right: @panel-body-padding;\n    }\n  }\n  // Add border top radius for first one\n  > .table:first-child,\n  > .table-responsive:first-child > .table:first-child {\n    .border-top-radius((@panel-border-radius - 1));\n\n    > thead:first-child,\n    > tbody:first-child {\n      > tr:first-child {\n        border-top-left-radius: (@panel-border-radius - 1);\n        border-top-right-radius: (@panel-border-radius - 1);\n\n        td:first-child,\n        th:first-child {\n          border-top-left-radius: (@panel-border-radius - 1);\n        }\n        td:last-child,\n        th:last-child {\n          border-top-right-radius: (@panel-border-radius - 1);\n        }\n      }\n    }\n  }\n  // Add border bottom radius for last one\n  > .table:last-child,\n  > .table-responsive:last-child > .table:last-child {\n    .border-bottom-radius((@panel-border-radius - 1));\n\n    > tbody:last-child,\n    > tfoot:last-child {\n      > tr:last-child {\n        border-bottom-left-radius: (@panel-border-radius - 1);\n        border-bottom-right-radius: (@panel-border-radius - 1);\n\n        td:first-child,\n        th:first-child {\n          border-bottom-left-radius: (@panel-border-radius - 1);\n        }\n        td:last-child,\n        th:last-child {\n          border-bottom-right-radius: (@panel-border-radius - 1);\n        }\n      }\n    }\n  }\n  > .panel-body + .table,\n  > .panel-body + .table-responsive,\n  > .table + .panel-body,\n  > .table-responsive + .panel-body {\n    border-top: 1px solid @table-border-color;\n  }\n  > .table > tbody:first-child > tr:first-child th,\n  > .table > tbody:first-child > tr:first-child td {\n    border-top: 0;\n  }\n  > .table-bordered,\n  > .table-responsive > .table-bordered {\n    border: 0;\n    > thead,\n    > tbody,\n    > tfoot {\n      > tr {\n        > th:first-child,\n        > td:first-child {\n          border-left: 0;\n        }\n        > th:last-child,\n        > td:last-child {\n          border-right: 0;\n        }\n      }\n    }\n    > thead,\n    > tbody {\n      > tr:first-child {\n        > td,\n        > th {\n          border-bottom: 0;\n        }\n      }\n    }\n    > tbody,\n    > tfoot {\n      > tr:last-child {\n        > td,\n        > th {\n          border-bottom: 0;\n        }\n      }\n    }\n  }\n  > .table-responsive {\n    border: 0;\n    margin-bottom: 0;\n  }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n  margin-bottom: @line-height-computed;\n\n  // Tighten up margin so it's only between panels\n  .panel {\n    margin-bottom: 0;\n    border-radius: @panel-border-radius;\n\n    + .panel {\n      margin-top: 5px;\n    }\n  }\n\n  .panel-heading {\n    border-bottom: 0;\n\n    + .panel-collapse > .panel-body,\n    + .panel-collapse > .list-group {\n      border-top: 1px solid @panel-inner-border;\n    }\n  }\n\n  .panel-footer {\n    border-top: 0;\n    + .panel-collapse .panel-body {\n      border-bottom: 1px solid @panel-inner-border;\n    }\n  }\n}\n\n\n// Contextual variations\n.panel-default {\n  .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n  .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n  .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n  .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n  .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n  .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","// Panels\n\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n  border-color: @border;\n\n  & > .panel-heading {\n    color: @heading-text-color;\n    background-color: @heading-bg-color;\n    border-color: @heading-border;\n\n    + .panel-collapse > .panel-body {\n      border-top-color: @border;\n    }\n    .badge {\n      color: @heading-bg-color;\n      background-color: @heading-text-color;\n    }\n  }\n  & > .panel-footer {\n    + .panel-collapse > .panel-body {\n      border-bottom-color: @border;\n    }\n  }\n}\n","// Embeds responsive\n//\n// Credit: Nicolas Gallagher and SUIT CSS.\n\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n\n  .embed-responsive-item,\n  iframe,\n  embed,\n  object,\n  video {\n    position: absolute;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    height: 100%;\n    width: 100%;\n    border: 0;\n  }\n}\n\n// Modifier class for 16:9 aspect ratio\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n\n// Modifier class for 4:3 aspect ratio\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: @well-bg;\n  border: 1px solid @well-border;\n  border-radius: @border-radius-base;\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n  blockquote {\n    border-color: #ddd;\n    border-color: rgba(0,0,0,.15);\n  }\n}\n\n// Sizes\n.well-lg {\n  padding: 24px;\n  border-radius: @border-radius-large;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: @border-radius-small;\n}\n","//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n  float: right;\n  font-size: (@font-size-base * 1.5);\n  font-weight: @close-font-weight;\n  line-height: 1;\n  color: @close-color;\n  text-shadow: @close-text-shadow;\n  .opacity(.2);\n\n  &:hover,\n  &:focus {\n    color: @close-color;\n    text-decoration: none;\n    cursor: pointer;\n    .opacity(.5);\n  }\n\n  // Additional properties for button version\n  // iOS requires the button element instead of an anchor tag.\n  // If you want the anchor version, it requires `href=\"#\"`.\n  // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n  button& {\n    padding: 0;\n    cursor: pointer;\n    background: transparent;\n    border: 0;\n    -webkit-appearance: none;\n  }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open      - body class for killing the scroll\n// .modal           - container to scroll within\n// .modal-dialog    - positioning shell for the actual modal\n// .modal-content   - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n  overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n  display: none;\n  overflow: hidden;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-modal;\n  -webkit-overflow-scrolling: touch;\n\n  // Prevent Chrome on Windows from adding a focus outline. For details, see\n  // https://github.com/twbs/bootstrap/pull/10951.\n  outline: 0;\n\n  // When fading in the modal, animate it to slide down\n  &.fade .modal-dialog {\n    .translate(0, -25%);\n    .transition-transform(~\"0.3s ease-out\");\n  }\n  &.in .modal-dialog { .translate(0, 0) }\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n  position: relative;\n  background-color: @modal-content-bg;\n  border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n  border: 1px solid @modal-content-border-color;\n  border-radius: @border-radius-large;\n  .box-shadow(0 3px 9px rgba(0,0,0,.5));\n  background-clip: padding-box;\n  // Remove focus outline from opened modal\n  outline: 0;\n}\n\n// Modal background\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-modal-background;\n  background-color: @modal-backdrop-bg;\n  // Fade for backdrop\n  &.fade { .opacity(0); }\n  &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n  padding: @modal-title-padding;\n  border-bottom: 1px solid @modal-header-border-color;\n  min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n  margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n  margin: 0;\n  line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n  position: relative;\n  padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n  padding: @modal-inner-padding;\n  text-align: right; // right align buttons\n  border-top: 1px solid @modal-footer-border-color;\n  &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n  // Properly space out buttons\n  .btn + .btn {\n    margin-left: 5px;\n    margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n  }\n  // but override that for button groups\n  .btn-group .btn + .btn {\n    margin-left: -1px;\n  }\n  // and override it for block buttons as well\n  .btn-block + .btn-block {\n    margin-left: 0;\n  }\n}\n\n// Measure scrollbar width for padding body during modal show/hide\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n  // Automatically set modal's width for larger viewports\n  .modal-dialog {\n    width: @modal-md;\n    margin: 30px auto;\n  }\n  .modal-content {\n    .box-shadow(0 5px 15px rgba(0,0,0,.5));\n  }\n\n  // Modal sizes\n  .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n  .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n  position: absolute;\n  z-index: @zindex-tooltip;\n  display: block;\n  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\n  // So reset our font and text properties to avoid inheriting weird values.\n  .reset-text();\n  font-size: @font-size-small;\n\n  .opacity(0);\n\n  &.in     { .opacity(@tooltip-opacity); }\n  &.top    { margin-top:  -3px; padding: @tooltip-arrow-width 0; }\n  &.right  { margin-left:  3px; padding: 0 @tooltip-arrow-width; }\n  &.bottom { margin-top:   3px; padding: @tooltip-arrow-width 0; }\n  &.left   { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n  max-width: @tooltip-max-width;\n  padding: 3px 8px;\n  color: @tooltip-color;\n  text-align: center;\n  background-color: @tooltip-bg;\n  border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1\n.tooltip {\n  &.top .tooltip-arrow {\n    bottom: 0;\n    left: 50%;\n    margin-left: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.top-left .tooltip-arrow {\n    bottom: 0;\n    right: @tooltip-arrow-width;\n    margin-bottom: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.top-right .tooltip-arrow {\n    bottom: 0;\n    left: @tooltip-arrow-width;\n    margin-bottom: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.right .tooltip-arrow {\n    top: 50%;\n    left: 0;\n    margin-top: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-right-color: @tooltip-arrow-color;\n  }\n  &.left .tooltip-arrow {\n    top: 50%;\n    right: 0;\n    margin-top: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-left-color: @tooltip-arrow-color;\n  }\n  &.bottom .tooltip-arrow {\n    top: 0;\n    left: 50%;\n    margin-left: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n  &.bottom-left .tooltip-arrow {\n    top: 0;\n    right: @tooltip-arrow-width;\n    margin-top: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n  &.bottom-right .tooltip-arrow {\n    top: 0;\n    left: @tooltip-arrow-width;\n    margin-top: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n}\n",".reset-text() {\n  font-family: @font-family-base;\n  // We deliberately do NOT reset font-size.\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\n  line-height: @line-height-base;\n  text-align: left; // Fallback for where `start` is not supported\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: @zindex-popover;\n  display: none;\n  max-width: @popover-max-width;\n  padding: 1px;\n  // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element.\n  // So reset our font and text properties to avoid inheriting weird values.\n  .reset-text();\n  font-size: @font-size-base;\n\n  background-color: @popover-bg;\n  background-clip: padding-box;\n  border: 1px solid @popover-fallback-border-color;\n  border: 1px solid @popover-border-color;\n  border-radius: @border-radius-large;\n  .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n  // Offset the popover to account for the popover arrow\n  &.top     { margin-top: -@popover-arrow-width; }\n  &.right   { margin-left: @popover-arrow-width; }\n  &.bottom  { margin-top: @popover-arrow-width; }\n  &.left    { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n  margin: 0; // reset heading margin\n  padding: 8px 14px;\n  font-size: @font-size-base;\n  background-color: @popover-title-bg;\n  border-bottom: 1px solid darken(@popover-title-bg, 5%);\n  border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0;\n}\n\n.popover-content {\n  padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n  &,\n  &:after {\n    position: absolute;\n    display: block;\n    width: 0;\n    height: 0;\n    border-color: transparent;\n    border-style: solid;\n  }\n}\n.popover > .arrow {\n  border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n  border-width: @popover-arrow-width;\n  content: \"\";\n}\n\n.popover {\n  &.top > .arrow {\n    left: 50%;\n    margin-left: -@popover-arrow-outer-width;\n    border-bottom-width: 0;\n    border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-top-color: @popover-arrow-outer-color;\n    bottom: -@popover-arrow-outer-width;\n    &:after {\n      content: \" \";\n      bottom: 1px;\n      margin-left: -@popover-arrow-width;\n      border-bottom-width: 0;\n      border-top-color: @popover-arrow-color;\n    }\n  }\n  &.right > .arrow {\n    top: 50%;\n    left: -@popover-arrow-outer-width;\n    margin-top: -@popover-arrow-outer-width;\n    border-left-width: 0;\n    border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-right-color: @popover-arrow-outer-color;\n    &:after {\n      content: \" \";\n      left: 1px;\n      bottom: -@popover-arrow-width;\n      border-left-width: 0;\n      border-right-color: @popover-arrow-color;\n    }\n  }\n  &.bottom > .arrow {\n    left: 50%;\n    margin-left: -@popover-arrow-outer-width;\n    border-top-width: 0;\n    border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-bottom-color: @popover-arrow-outer-color;\n    top: -@popover-arrow-outer-width;\n    &:after {\n      content: \" \";\n      top: 1px;\n      margin-left: -@popover-arrow-width;\n      border-top-width: 0;\n      border-bottom-color: @popover-arrow-color;\n    }\n  }\n\n  &.left > .arrow {\n    top: 50%;\n    right: -@popover-arrow-outer-width;\n    margin-top: -@popover-arrow-outer-width;\n    border-right-width: 0;\n    border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-left-color: @popover-arrow-outer-color;\n    &:after {\n      content: \" \";\n      right: 1px;\n      border-right-width: 0;\n      border-left-color: @popover-arrow-color;\n      bottom: -@popover-arrow-width;\n    }\n  }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n  position: relative;\n}\n\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n\n  > .item {\n    display: none;\n    position: relative;\n    .transition(.6s ease-in-out left);\n\n    // Account for jankitude on images\n    > img,\n    > a > img {\n      &:extend(.img-responsive);\n      line-height: 1;\n    }\n\n    // WebKit CSS3 transforms for supported devices\n    @media all and (transform-3d), (-webkit-transform-3d) {\n      .transition-transform(~'0.6s ease-in-out');\n      .backface-visibility(~'hidden');\n      .perspective(1000px);\n\n      &.next,\n      &.active.right {\n        .translate3d(100%, 0, 0);\n        left: 0;\n      }\n      &.prev,\n      &.active.left {\n        .translate3d(-100%, 0, 0);\n        left: 0;\n      }\n      &.next.left,\n      &.prev.right,\n      &.active {\n        .translate3d(0, 0, 0);\n        left: 0;\n      }\n    }\n  }\n\n  > .active,\n  > .next,\n  > .prev {\n    display: block;\n  }\n\n  > .active {\n    left: 0;\n  }\n\n  > .next,\n  > .prev {\n    position: absolute;\n    top: 0;\n    width: 100%;\n  }\n\n  > .next {\n    left: 100%;\n  }\n  > .prev {\n    left: -100%;\n  }\n  > .next.left,\n  > .prev.right {\n    left: 0;\n  }\n\n  > .active.left {\n    left: -100%;\n  }\n  > .active.right {\n    left: 100%;\n  }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: @carousel-control-width;\n  .opacity(@carousel-control-opacity);\n  font-size: @carousel-control-font-size;\n  color: @carousel-control-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  // We can't have this transition here because WebKit cancels the carousel\n  // animation if you trip this while in the middle of another animation.\n\n  // Set gradients for backgrounds\n  &.left {\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n  }\n  &.right {\n    left: auto;\n    right: 0;\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n  }\n\n  // Hover/focus state\n  &:hover,\n  &:focus {\n    outline: 0;\n    color: @carousel-control-color;\n    text-decoration: none;\n    .opacity(.9);\n  }\n\n  // Toggles\n  .icon-prev,\n  .icon-next,\n  .glyphicon-chevron-left,\n  .glyphicon-chevron-right {\n    position: absolute;\n    top: 50%;\n    z-index: 5;\n    display: inline-block;\n  }\n  .icon-prev,\n  .glyphicon-chevron-left {\n    left: 50%;\n    margin-left: -10px;\n  }\n  .icon-next,\n  .glyphicon-chevron-right {\n    right: 50%;\n    margin-right: -10px;\n  }\n  .icon-prev,\n  .icon-next {\n    width:  20px;\n    height: 20px;\n    margin-top: -10px;\n    line-height: 1;\n    font-family: serif;\n  }\n\n\n  .icon-prev {\n    &:before {\n      content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n    }\n  }\n  .icon-next {\n    &:before {\n      content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n    }\n  }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n\n  li {\n    display: inline-block;\n    width:  10px;\n    height: 10px;\n    margin: 1px;\n    text-indent: -999px;\n    border: 1px solid @carousel-indicator-border-color;\n    border-radius: 10px;\n    cursor: pointer;\n\n    // IE8-9 hack for event handling\n    //\n    // Internet Explorer 8-9 does not support clicks on elements without a set\n    // `background-color`. We cannot use `filter` since that's not viewed as a\n    // background color by the browser. Thus, a hack is needed.\n    // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer\n    //\n    // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n    // set alpha transparency for the best results possible.\n    background-color: #000 \\9; // IE8\n    background-color: rgba(0,0,0,0); // IE9\n  }\n  .active {\n    margin: 0;\n    width:  12px;\n    height: 12px;\n    background-color: @carousel-indicator-active-bg;\n  }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: @carousel-caption-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  & .btn {\n    text-shadow: none; // No shadow for button elements in carousel-caption\n  }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n  // Scale up the controls a smidge\n  .carousel-control {\n    .glyphicon-chevron-left,\n    .glyphicon-chevron-right,\n    .icon-prev,\n    .icon-next {\n      width: 30px;\n      height: 30px;\n      margin-top: -15px;\n      font-size: 30px;\n    }\n    .glyphicon-chevron-left,\n    .icon-prev {\n      margin-left: -15px;\n    }\n    .glyphicon-chevron-right,\n    .icon-next {\n      margin-right: -15px;\n    }\n  }\n\n  // Show and left align the captions\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n\n  // Move up the indicators\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n","// Clearfix\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n//    contenteditable attribute is included anywhere else in the document.\n//    Otherwise it causes space to appear at the top and bottom of elements\n//    that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n//    `:before` to contain the top-margins of child elements.\n//\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n\n.clearfix() {\n  &:before,\n  &:after {\n    content: \" \"; // 1\n    display: table; // 2\n  }\n  &:after {\n    clear: both;\n  }\n}\n","// Center-align a block level element\n\n.center-block() {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n","// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n  font: ~\"0/0\" a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n// New mixin to use as of v3.0.1\n.text-hide() {\n  .hide-text();\n}\n","//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#support-ie10-width\n// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n  width: device-width;\n}\n\n\n// Visibility utilities\n// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  .responsive-invisibility();\n}\n\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n\n.visible-xs {\n  @media (max-width: @screen-xs-max) {\n    .responsive-visibility();\n  }\n}\n.visible-xs-block {\n  @media (max-width: @screen-xs-max) {\n    display: block !important;\n  }\n}\n.visible-xs-inline {\n  @media (max-width: @screen-xs-max) {\n    display: inline !important;\n  }\n}\n.visible-xs-inline-block {\n  @media (max-width: @screen-xs-max) {\n    display: inline-block !important;\n  }\n}\n\n.visible-sm {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    .responsive-visibility();\n  }\n}\n.visible-sm-block {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    display: block !important;\n  }\n}\n.visible-sm-inline {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    display: inline !important;\n  }\n}\n.visible-sm-inline-block {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    display: inline-block !important;\n  }\n}\n\n.visible-md {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    .responsive-visibility();\n  }\n}\n.visible-md-block {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    display: block !important;\n  }\n}\n.visible-md-inline {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    display: inline !important;\n  }\n}\n.visible-md-inline-block {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    display: inline-block !important;\n  }\n}\n\n.visible-lg {\n  @media (min-width: @screen-lg-min) {\n    .responsive-visibility();\n  }\n}\n.visible-lg-block {\n  @media (min-width: @screen-lg-min) {\n    display: block !important;\n  }\n}\n.visible-lg-inline {\n  @media (min-width: @screen-lg-min) {\n    display: inline !important;\n  }\n}\n.visible-lg-inline-block {\n  @media (min-width: @screen-lg-min) {\n    display: inline-block !important;\n  }\n}\n\n.hidden-xs {\n  @media (max-width: @screen-xs-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-sm {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-md {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-lg {\n  @media (min-width: @screen-lg-min) {\n    .responsive-invisibility();\n  }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n// Note: Deprecated .visible-print as of v3.2.0\n.visible-print {\n  .responsive-invisibility();\n\n  @media print {\n    .responsive-visibility();\n  }\n}\n.visible-print-block {\n  display: none !important;\n\n  @media print {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n\n  @media print {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n\n  @media print {\n    display: inline-block !important;\n  }\n}\n\n.hidden-print {\n  @media print {\n    .responsive-invisibility();\n  }\n}\n","// Responsive utilities\n\n//\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n  display: block !important;\n  table&  { display: table !important; }\n  tr&     { display: table-row !important; }\n  th&,\n  td&     { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n  display: none !important;\n}\n"]}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.min.css b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.min.css
new file mode 100644
index 0000000..be7e906
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.4 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:Cantarell,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:focus,a:hover{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#f8e4c7}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:focus,a.text-primary:hover{color:#3071a9}.text-success{color:#3f7815}a.text-success:focus,a.text-success:hover{color:#284d0e}.text-info{color:#603e7a}a.text-info:focus,a.text-info:hover{color:#452d58}.text-warning{color:#7e500f}a.text-warning:focus,a.text-warning:hover{color:#51330a}.text-danger{color:#78153f}a.text-danger:focus,a.text-danger:hover{color:#4d0e28}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:focus,a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dcf6ca}a.bg-success:focus,a.bg-success:hover{background-color:#c0ee9e}.bg-info{background-color:#f6f2f8}a.bg-info:focus,a.bg-info:hover{background-color:#ddd0e7}.bg-warning{background-color:#f8e4c7}a.bg-warning:focus,a.bg-warning:hover{background-color:#f3ce9a}.bg-danger{background-color:#f6cadc}a.bg-danger:focus,a.bg-danger:hover{background-color:#ee9ec0}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dcf6ca}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#cef2b4}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#f6f2f8}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#e9e1f0}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#f8e4c7}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#f6d9b0}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f6cadc}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#f2b4ce}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px \9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3f7815}.has-success .form-control{border-color:#3f7815;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#284d0e;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #6ccf24;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #6ccf24}.has-success .input-group-addon{color:#3f7815;background-color:#dcf6ca;border-color:#3f7815}.has-success .form-control-feedback{color:#3f7815}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#7e500f}.has-warning .form-control{border-color:#7e500f;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#51330a;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d98a1a;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d98a1a}.has-warning .input-group-addon{color:#7e500f;background-color:#f8e4c7;border-color:#7e500f}.has-warning .form-control-feedback{color:#7e500f}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#78153f}.has-error .form-control{border-color:#78153f;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#4d0e28;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #cf246c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #cf246c}.has-error .input-group-addon{color:#78153f;background-color:#f6cadc;border-color:#78153f}.has-error .form-control-feedback{color:#78153f}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#3071a9;border-color:#193c5a}.btn-primary:hover{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#285e8e;border-color:#193c5a}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#79db32;border-color:#6ccf24}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#61b921;border-color:#346311}.btn-success:hover{color:#fff;background-color:#61b921;border-color:#519b1b}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#61b921;border-color:#519b1b}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#519b1b;border-color:#346311}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#79db32;border-color:#6ccf24}.btn-success .badge{color:#79db32;background-color:#fff}.btn-info{color:#fff;background-color:#a07cbc;border-color:#946bb3}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#885aab;border-color:#533669}.btn-info:hover{color:#fff;background-color:#885aab;border-color:#754c95}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#885aab;border-color:#754c95}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#754c95;border-color:#533669}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#a07cbc;border-color:#946bb3}.btn-info .badge{color:#a07cbc;background-color:#fff}.btn-warning{color:#fff;background-color:#e59728;border-color:#d98a1a}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#c27c18;border-color:#67420d}.btn-warning:hover{color:#fff;background-color:#c27c18;border-color:#a36814}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#c27c18;border-color:#a36814}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#a36814;border-color:#67420d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#e59728;border-color:#d98a1a}.btn-warning .badge{color:#e59728;background-color:#fff}.btn-danger{color:#fff;background-color:#db3279;border-color:#cf246c}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#b92161;border-color:#631134}.btn-danger:hover{color:#fff;background-color:#b92161;border-color:#9b1b51}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#b92161;border-color:#9b1b51}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#9b1b51;border-color:#631134}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#db3279;border-color:#cf246c}.btn-danger .badge{color:#db3279;background-color:#fff}.btn-link{font-weight:400;color:#428bca;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#db3279;border-bottom-color:#db3279}.nav a:hover .caret{border-top-color:#b92161;border-bottom-color:#b92161}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:35px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px)and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:35px;padding:7.5px 15px;font-family:Comfortaa,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:18px;font-weight:700;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:.5px;margin-right:15px;margin-bottom:.5px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:3.75px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:7.5px;padding-bottom:7.5px}}.navbar-form{padding:10px 15px;margin-top:.5px;margin-right:-15px;margin-bottom:.5px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:.5px;margin-bottom:.5px}.navbar-btn.btn-sm{margin-top:2.5px;margin-bottom:2.5px}.navbar-btn.btn-xs{margin-top:6.5px;margin-bottom:6.5px}.navbar-text{margin-top:7.5px;margin-bottom:7.5px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#db3279;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#db3279;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#db3279;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#294172;border-color:#1c2c4c}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#777}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#1c2c4c}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#203258}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#1c2c4c}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#1c2c4c}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#1c2c4c}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#1c2c4c}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#428bca;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#3071a9}.label-success{background-color:#79db32}.label-success[href]:focus,.label-success[href]:hover{background-color:#61b921}.label-info{background-color:#a07cbc}.label-info[href]:focus,.label-info[href]:hover{background-color:#885aab}.label-warning{background-color:#e59728}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#c27c18}.label-danger{background-color:#db3279}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#b92161}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3f7815;background-color:#dcf6ca;border-color:#d8f2b4}.alert-success hr{border-top-color:#cdee9e}.alert-success .alert-link{color:#284d0e}.alert-info{color:#603e7a;background-color:#f6f2f8;border-color:#e7e1f0}.alert-info hr{border-top-color:#d9d0e7}.alert-info .alert-link{color:#452d58}.alert-warning{color:#7e500f;background-color:#f8e4c7;border-color:#f6ceb0}.alert-warning hr{border-top-color:#f3bf9a}.alert-warning .alert-link{color:#51330a}.alert-danger{color:#78153f;background-color:#f6cadc;border-color:#f2b4d8}.alert-danger hr{border-top-color:#ee9ecd}.alert-danger .alert-link{color:#4d0e28}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#79db32}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#a07cbc}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#e59728}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#db3279}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3f7815;background-color:#dcf6ca}a.list-group-item-success{color:#3f7815}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3f7815;background-color:#cef2b4}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3f7815;border-color:#3f7815}.list-group-item-info{color:#603e7a;background-color:#f6f2f8}a.list-group-item-info{color:#603e7a}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#603e7a;background-color:#e9e1f0}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#603e7a;border-color:#603e7a}.list-group-item-warning{color:#7e500f;background-color:#f8e4c7}a.list-group-item-warning{color:#7e500f}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#7e500f;background-color:#f6d9b0}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#7e500f;border-color:#7e500f}.list-group-item-danger{color:#78153f;background-color:#f6cadc}a.list-group-item-danger{color:#78153f}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#78153f;background-color:#f2b4ce}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#78153f;border-color:#78153f}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d8f2b4}.panel-success>.panel-heading{color:#3f7815;background-color:#dcf6ca;border-color:#d8f2b4}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d8f2b4}.panel-success>.panel-heading .badge{color:#dcf6ca;background-color:#3f7815}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d8f2b4}.panel-info{border-color:#e7e1f0}.panel-info>.panel-heading{color:#603e7a;background-color:#f6f2f8;border-color:#e7e1f0}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#e7e1f0}.panel-info>.panel-heading .badge{color:#f6f2f8;background-color:#603e7a}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#e7e1f0}.panel-warning{border-color:#f6ceb0}.panel-warning>.panel-heading{color:#7e500f;background-color:#f8e4c7;border-color:#f6ceb0}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f6ceb0}.panel-warning>.panel-heading .badge{color:#f8e4c7;background-color:#7e500f}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f6ceb0}.panel-danger{border-color:#f2b4d8}.panel-danger>.panel-heading{color:#78153f;background-color:#f6cadc;border-color:#f2b4d8}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f2b4d8}.panel-danger>.panel-heading .badge{color:#f6cadc;background-color:#78153f}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f2b4d8}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Cantarell,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:Cantarell,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px)and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px)and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.eot b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000..b93a495
Binary files /dev/null and b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.eot differ
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.svg b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000..94fb549
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,288 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph horiz-adv-x="0" />
+<glyph horiz-adv-x="400" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
+<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#xa5;" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
+<glyph unicode="&#x2000;" horiz-adv-x="650" />
+<glyph unicode="&#x2001;" horiz-adv-x="1300" />
+<glyph unicode="&#x2002;" horiz-adv-x="650" />
+<glyph unicode="&#x2003;" horiz-adv-x="1300" />
+<glyph unicode="&#x2004;" horiz-adv-x="433" />
+<glyph unicode="&#x2005;" horiz-adv-x="325" />
+<glyph unicode="&#x2006;" horiz-adv-x="216" />
+<glyph unicode="&#x2007;" horiz-adv-x="216" />
+<glyph unicode="&#x2008;" horiz-adv-x="162" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="325" />
+<glyph unicode="&#x20ac;" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
+<glyph unicode="&#x20bd;" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
+<glyph unicode="&#x2212;" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#x231b;" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
+<glyph unicode="&#x26fa;" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
+<glyph unicode="&#x2709;" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
+<glyph unicode="&#x270f;" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
+<glyph unicode="&#xe001;" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
+<glyph unicode="&#xe002;" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
+<glyph unicode="&#xe003;" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
+<glyph unicode="&#xe005;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
+<glyph unicode="&#xe006;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
+<glyph unicode="&#xe007;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
+<glyph unicode="&#xe008;" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
+<glyph unicode="&#xe009;" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
+<glyph unicode="&#xe010;" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe011;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
+<glyph unicode="&#xe012;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe013;" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
+<glyph unicode="&#xe014;" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
+<glyph unicode="&#xe015;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe016;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe017;" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
+<glyph unicode="&#xe018;" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe019;" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
+<glyph unicode="&#xe020;" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
+<glyph unicode="&#xe021;" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe022;" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
+<glyph unicode="&#xe023;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe026;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
+<glyph unicode="&#xe027;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
+<glyph unicode="&#xe028;" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
+<glyph unicode="&#xe029;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe030;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
+<glyph unicode="&#xe031;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
+<glyph unicode="&#xe032;" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe033;" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
+<glyph unicode="&#xe034;" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
+<glyph unicode="&#xe035;" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
+<glyph unicode="&#xe036;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
+<glyph unicode="&#xe037;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
+<glyph unicode="&#xe038;" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
+<glyph unicode="&#xe039;" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
+<glyph unicode="&#xe040;" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
+<glyph unicode="&#xe041;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe042;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe043;" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
+<glyph unicode="&#xe044;" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe045;" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
+<glyph unicode="&#xe046;" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
+<glyph unicode="&#xe047;" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
+<glyph unicode="&#xe048;" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
+<glyph unicode="&#xe049;" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
+<glyph unicode="&#xe050;" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
+<glyph unicode="&#xe051;" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
+<glyph unicode="&#xe052;" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe053;" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe054;" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe055;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe056;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe057;" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe058;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe059;" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
+<glyph unicode="&#xe062;" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
+<glyph unicode="&#xe063;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
+<glyph unicode="&#xe064;" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
+<glyph unicode="&#xe065;" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
+<glyph unicode="&#xe066;" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
+<glyph unicode="&#xe067;" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
+<glyph unicode="&#xe068;" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe069;" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe070;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe071;" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
+<glyph unicode="&#xe072;" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
+<glyph unicode="&#xe073;" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe074;" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe075;" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
+<glyph unicode="&#xe076;" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe077;" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe078;" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
+<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
+<glyph unicode="&#xe081;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="&#xe082;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="&#xe083;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
+<glyph unicode="&#xe084;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
+<glyph unicode="&#xe085;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe086;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe087;" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
+<glyph unicode="&#xe088;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe089;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe090;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
+<glyph unicode="&#xe091;" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
+<glyph unicode="&#xe092;" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe093;" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
+<glyph unicode="&#xe094;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe095;" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe096;" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
+<glyph unicode="&#xe097;" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
+<glyph unicode="&#xe101;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe102;" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
+<glyph unicode="&#xe103;" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
+<glyph unicode="&#xe104;" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
+<glyph unicode="&#xe105;" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="&#xe106;" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="&#xe107;" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
+<glyph unicode="&#xe108;" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
+<glyph unicode="&#xe109;" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
+<glyph unicode="&#xe110;" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
+<glyph unicode="&#xe111;" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
+<glyph unicode="&#xe112;" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
+<glyph unicode="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
+<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
+<glyph unicode="&#xe115;" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe116;" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
+<glyph unicode="&#xe117;" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
+<glyph unicode="&#xe118;" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
+<glyph unicode="&#xe119;" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe120;" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
+<glyph unicode="&#xe121;" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
+<glyph unicode="&#xe122;" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
+<glyph unicode="&#xe123;" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
+<glyph unicode="&#xe124;" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
+<glyph unicode="&#xe125;" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe126;" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
+<glyph unicode="&#xe127;" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe128;" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe129;" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe130;" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
+<glyph unicode="&#xe131;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
+<glyph unicode="&#xe132;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
+<glyph unicode="&#xe133;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
+<glyph unicode="&#xe134;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe135;" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
+<glyph unicode="&#xe136;" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
+<glyph unicode="&#xe138;" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
+<glyph unicode="&#xe139;" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
+<glyph unicode="&#xe140;" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
+<glyph unicode="&#xe141;" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
+<glyph unicode="&#xe142;" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
+<glyph unicode="&#xe143;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
+<glyph unicode="&#xe144;" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
+<glyph unicode="&#xe145;" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
+<glyph unicode="&#xe146;" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
+<glyph unicode="&#xe148;" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
+<glyph unicode="&#xe149;" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
+<glyph unicode="&#xe150;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe151;" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
+<glyph unicode="&#xe152;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
+<glyph unicode="&#xe153;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
+<glyph unicode="&#xe154;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
+<glyph unicode="&#xe155;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
+<glyph unicode="&#xe156;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
+<glyph unicode="&#xe157;" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
+<glyph unicode="&#xe158;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe159;" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
+<glyph unicode="&#xe160;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
+<glyph unicode="&#xe161;" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe162;" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
+<glyph unicode="&#xe163;" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe164;" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
+<glyph unicode="&#xe165;" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
+<glyph unicode="&#xe166;" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe167;" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe168;" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
+<glyph unicode="&#xe169;" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe170;" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
+<glyph unicode="&#xe172;" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
+<glyph unicode="&#xe173;" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe174;" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
+<glyph unicode="&#xe175;" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe176;" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe177;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
+<glyph unicode="&#xe178;" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
+<glyph unicode="&#xe179;" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
+<glyph unicode="&#xe180;" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
+<glyph unicode="&#xe181;" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
+<glyph unicode="&#xe182;" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
+<glyph unicode="&#xe183;" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
+<glyph unicode="&#xe184;" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe185;" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
+<glyph unicode="&#xe186;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe187;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe188;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
+<glyph unicode="&#xe189;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
+<glyph unicode="&#xe190;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
+<glyph unicode="&#xe191;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe192;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe193;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
+<glyph unicode="&#xe194;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
+<glyph unicode="&#xe195;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
+<glyph unicode="&#xe197;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe198;" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
+<glyph unicode="&#xe199;" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
+<glyph unicode="&#xe200;" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
+<glyph unicode="&#xe201;" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
+<glyph unicode="&#xe202;" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
+<glyph unicode="&#xe203;" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
+<glyph unicode="&#xe204;" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
+<glyph unicode="&#xe205;" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe206;" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe209;" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
+<glyph unicode="&#xe210;" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe211;" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe212;" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe213;" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe214;" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe215;" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe216;" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
+<glyph unicode="&#xe218;" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
+<glyph unicode="&#xe219;" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
+<glyph unicode="&#xe221;" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe223;" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
+<glyph unicode="&#xe224;" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
+<glyph unicode="&#xe225;" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe226;" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
+<glyph unicode="&#xe227;" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
+<glyph unicode="&#xe230;" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
+<glyph unicode="&#xe231;" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe232;" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe233;" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
+<glyph unicode="&#xe234;" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe235;" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe236;" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe237;" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
+<glyph unicode="&#xe238;" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe239;" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
+<glyph unicode="&#xe240;" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
+<glyph unicode="&#xe241;" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
+<glyph unicode="&#xe242;" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe243;" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
+<glyph unicode="&#xe244;" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
+<glyph unicode="&#xe245;" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
+<glyph unicode="&#xe246;" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
+<glyph unicode="&#xe247;" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe248;" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
+<glyph unicode="&#xe249;" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe250;" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
+<glyph unicode="&#xe251;" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
+<glyph unicode="&#xe252;" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
+<glyph unicode="&#xe253;" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
+<glyph unicode="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
+<glyph unicode="&#xe255;" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
+<glyph unicode="&#xe256;" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
+<glyph unicode="&#xe257;" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
+<glyph unicode="&#xe258;" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
+<glyph unicode="&#xe259;" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
+<glyph unicode="&#xe260;" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
+<glyph unicode="&#xf8ff;" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
+<glyph unicode="&#x1f511;" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
+<glyph unicode="&#x1f6aa;" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
+</font>
+</defs></svg> 
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.ttf b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000..1413fc6
Binary files /dev/null and b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.ttf differ
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000..9e61285
Binary files /dev/null and b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff differ
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff2 b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff2
new file mode 100644
index 0000000..64539b5
Binary files /dev/null and b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff2 differ
diff --git a/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.js b/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.js
new file mode 100644
index 0000000..335cc61
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.js
@@ -0,0 +1,2319 @@
+/*!
+ * Bootstrap v3.3.4 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+if (typeof jQuery === 'undefined') {
+  throw new Error('Bootstrap\'s JavaScript requires jQuery')
+}
+
++function ($) {
+  'use strict';
+  var version = $.fn.jquery.split(' ')[0].split('.')
+  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
+    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
+  }
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: transition.js v3.3.4
+ * http://getbootstrap.com/javascript/#transitions
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+  // ============================================================
+
+  function transitionEnd() {
+    var el = document.createElement('bootstrap')
+
+    var transEndEventNames = {
+      WebkitTransition : 'webkitTransitionEnd',
+      MozTransition    : 'transitionend',
+      OTransition      : 'oTransitionEnd otransitionend',
+      transition       : 'transitionend'
+    }
+
+    for (var name in transEndEventNames) {
+      if (el.style[name] !== undefined) {
+        return { end: transEndEventNames[name] }
+      }
+    }
+
+    return false // explicit for ie8 (  ._.)
+  }
+
+  // http://blog.alexmaccaw.com/css-transitions
+  $.fn.emulateTransitionEnd = function (duration) {
+    var called = false
+    var $el = this
+    $(this).one('bsTransitionEnd', function () { called = true })
+    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+    setTimeout(callback, duration)
+    return this
+  }
+
+  $(function () {
+    $.support.transition = transitionEnd()
+
+    if (!$.support.transition) return
+
+    $.event.special.bsTransitionEnd = {
+      bindType: $.support.transition.end,
+      delegateType: $.support.transition.end,
+      handle: function (e) {
+        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
+      }
+    }
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: alert.js v3.3.4
+ * http://getbootstrap.com/javascript/#alerts
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // ALERT CLASS DEFINITION
+  // ======================
+
+  var dismiss = '[data-dismiss="alert"]'
+  var Alert   = function (el) {
+    $(el).on('click', dismiss, this.close)
+  }
+
+  Alert.VERSION = '3.3.4'
+
+  Alert.TRANSITION_DURATION = 150
+
+  Alert.prototype.close = function (e) {
+    var $this    = $(this)
+    var selector = $this.attr('data-target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    var $parent = $(selector)
+
+    if (e) e.preventDefault()
+
+    if (!$parent.length) {
+      $parent = $this.closest('.alert')
+    }
+
+    $parent.trigger(e = $.Event('close.bs.alert'))
+
+    if (e.isDefaultPrevented()) return
+
+    $parent.removeClass('in')
+
+    function removeElement() {
+      // detach from parent, fire event then clean up data
+      $parent.detach().trigger('closed.bs.alert').remove()
+    }
+
+    $.support.transition && $parent.hasClass('fade') ?
+      $parent
+        .one('bsTransitionEnd', removeElement)
+        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
+      removeElement()
+  }
+
+
+  // ALERT PLUGIN DEFINITION
+  // =======================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.alert')
+
+      if (!data) $this.data('bs.alert', (data = new Alert(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  var old = $.fn.alert
+
+  $.fn.alert             = Plugin
+  $.fn.alert.Constructor = Alert
+
+
+  // ALERT NO CONFLICT
+  // =================
+
+  $.fn.alert.noConflict = function () {
+    $.fn.alert = old
+    return this
+  }
+
+
+  // ALERT DATA-API
+  // ==============
+
+  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: button.js v3.3.4
+ * http://getbootstrap.com/javascript/#buttons
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // BUTTON PUBLIC CLASS DEFINITION
+  // ==============================
+
+  var Button = function (element, options) {
+    this.$element  = $(element)
+    this.options   = $.extend({}, Button.DEFAULTS, options)
+    this.isLoading = false
+  }
+
+  Button.VERSION  = '3.3.4'
+
+  Button.DEFAULTS = {
+    loadingText: 'loading...'
+  }
+
+  Button.prototype.setState = function (state) {
+    var d    = 'disabled'
+    var $el  = this.$element
+    var val  = $el.is('input') ? 'val' : 'html'
+    var data = $el.data()
+
+    state = state + 'Text'
+
+    if (data.resetText == null) $el.data('resetText', $el[val]())
+
+    // push to event loop to allow forms to submit
+    setTimeout($.proxy(function () {
+      $el[val](data[state] == null ? this.options[state] : data[state])
+
+      if (state == 'loadingText') {
+        this.isLoading = true
+        $el.addClass(d).attr(d, d)
+      } else if (this.isLoading) {
+        this.isLoading = false
+        $el.removeClass(d).removeAttr(d)
+      }
+    }, this), 0)
+  }
+
+  Button.prototype.toggle = function () {
+    var changed = true
+    var $parent = this.$element.closest('[data-toggle="buttons"]')
+
+    if ($parent.length) {
+      var $input = this.$element.find('input')
+      if ($input.prop('type') == 'radio') {
+        if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
+        else $parent.find('.active').removeClass('active')
+      }
+      if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
+    } else {
+      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
+    }
+
+    if (changed) this.$element.toggleClass('active')
+  }
+
+
+  // BUTTON PLUGIN DEFINITION
+  // ========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.button')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.button', (data = new Button(this, options)))
+
+      if (option == 'toggle') data.toggle()
+      else if (option) data.setState(option)
+    })
+  }
+
+  var old = $.fn.button
+
+  $.fn.button             = Plugin
+  $.fn.button.Constructor = Button
+
+
+  // BUTTON NO CONFLICT
+  // ==================
+
+  $.fn.button.noConflict = function () {
+    $.fn.button = old
+    return this
+  }
+
+
+  // BUTTON DATA-API
+  // ===============
+
+  $(document)
+    .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+      var $btn = $(e.target)
+      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+      Plugin.call($btn, 'toggle')
+      e.preventDefault()
+    })
+    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
+    })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: carousel.js v3.3.4
+ * http://getbootstrap.com/javascript/#carousel
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // CAROUSEL CLASS DEFINITION
+  // =========================
+
+  var Carousel = function (element, options) {
+    this.$element    = $(element)
+    this.$indicators = this.$element.find('.carousel-indicators')
+    this.options     = options
+    this.paused      = null
+    this.sliding     = null
+    this.interval    = null
+    this.$active     = null
+    this.$items      = null
+
+    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
+
+    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
+      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
+      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
+  }
+
+  Carousel.VERSION  = '3.3.4'
+
+  Carousel.TRANSITION_DURATION = 600
+
+  Carousel.DEFAULTS = {
+    interval: 5000,
+    pause: 'hover',
+    wrap: true,
+    keyboard: true
+  }
+
+  Carousel.prototype.keydown = function (e) {
+    if (/input|textarea/i.test(e.target.tagName)) return
+    switch (e.which) {
+      case 37: this.prev(); break
+      case 39: this.next(); break
+      default: return
+    }
+
+    e.preventDefault()
+  }
+
+  Carousel.prototype.cycle = function (e) {
+    e || (this.paused = false)
+
+    this.interval && clearInterval(this.interval)
+
+    this.options.interval
+      && !this.paused
+      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+
+    return this
+  }
+
+  Carousel.prototype.getItemIndex = function (item) {
+    this.$items = item.parent().children('.item')
+    return this.$items.index(item || this.$active)
+  }
+
+  Carousel.prototype.getItemForDirection = function (direction, active) {
+    var activeIndex = this.getItemIndex(active)
+    var willWrap = (direction == 'prev' && activeIndex === 0)
+                || (direction == 'next' && activeIndex == (this.$items.length - 1))
+    if (willWrap && !this.options.wrap) return active
+    var delta = direction == 'prev' ? -1 : 1
+    var itemIndex = (activeIndex + delta) % this.$items.length
+    return this.$items.eq(itemIndex)
+  }
+
+  Carousel.prototype.to = function (pos) {
+    var that        = this
+    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
+
+    if (pos > (this.$items.length - 1) || pos < 0) return
+
+    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
+    if (activeIndex == pos) return this.pause().cycle()
+
+    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
+  }
+
+  Carousel.prototype.pause = function (e) {
+    e || (this.paused = true)
+
+    if (this.$element.find('.next, .prev').length && $.support.transition) {
+      this.$element.trigger($.support.transition.end)
+      this.cycle(true)
+    }
+
+    this.interval = clearInterval(this.interval)
+
+    return this
+  }
+
+  Carousel.prototype.next = function () {
+    if (this.sliding) return
+    return this.slide('next')
+  }
+
+  Carousel.prototype.prev = function () {
+    if (this.sliding) return
+    return this.slide('prev')
+  }
+
+  Carousel.prototype.slide = function (type, next) {
+    var $active   = this.$element.find('.item.active')
+    var $next     = next || this.getItemForDirection(type, $active)
+    var isCycling = this.interval
+    var direction = type == 'next' ? 'left' : 'right'
+    var that      = this
+
+    if ($next.hasClass('active')) return (this.sliding = false)
+
+    var relatedTarget = $next[0]
+    var slideEvent = $.Event('slide.bs.carousel', {
+      relatedTarget: relatedTarget,
+      direction: direction
+    })
+    this.$element.trigger(slideEvent)
+    if (slideEvent.isDefaultPrevented()) return
+
+    this.sliding = true
+
+    isCycling && this.pause()
+
+    if (this.$indicators.length) {
+      this.$indicators.find('.active').removeClass('active')
+      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
+      $nextIndicator && $nextIndicator.addClass('active')
+    }
+
+    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
+    if ($.support.transition && this.$element.hasClass('slide')) {
+      $next.addClass(type)
+      $next[0].offsetWidth // force reflow
+      $active.addClass(direction)
+      $next.addClass(direction)
+      $active
+        .one('bsTransitionEnd', function () {
+          $next.removeClass([type, direction].join(' ')).addClass('active')
+          $active.removeClass(['active', direction].join(' '))
+          that.sliding = false
+          setTimeout(function () {
+            that.$element.trigger(slidEvent)
+          }, 0)
+        })
+        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
+    } else {
+      $active.removeClass('active')
+      $next.addClass('active')
+      this.sliding = false
+      this.$element.trigger(slidEvent)
+    }
+
+    isCycling && this.cycle()
+
+    return this
+  }
+
+
+  // CAROUSEL PLUGIN DEFINITION
+  // ==========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.carousel')
+      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
+      var action  = typeof option == 'string' ? option : options.slide
+
+      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
+      if (typeof option == 'number') data.to(option)
+      else if (action) data[action]()
+      else if (options.interval) data.pause().cycle()
+    })
+  }
+
+  var old = $.fn.carousel
+
+  $.fn.carousel             = Plugin
+  $.fn.carousel.Constructor = Carousel
+
+
+  // CAROUSEL NO CONFLICT
+  // ====================
+
+  $.fn.carousel.noConflict = function () {
+    $.fn.carousel = old
+    return this
+  }
+
+
+  // CAROUSEL DATA-API
+  // =================
+
+  var clickHandler = function (e) {
+    var href
+    var $this   = $(this)
+    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
+    if (!$target.hasClass('carousel')) return
+    var options = $.extend({}, $target.data(), $this.data())
+    var slideIndex = $this.attr('data-slide-to')
+    if (slideIndex) options.interval = false
+
+    Plugin.call($target, options)
+
+    if (slideIndex) {
+      $target.data('bs.carousel').to(slideIndex)
+    }
+
+    e.preventDefault()
+  }
+
+  $(document)
+    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
+    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
+
+  $(window).on('load', function () {
+    $('[data-ride="carousel"]').each(function () {
+      var $carousel = $(this)
+      Plugin.call($carousel, $carousel.data())
+    })
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: collapse.js v3.3.4
+ * http://getbootstrap.com/javascript/#collapse
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // COLLAPSE PUBLIC CLASS DEFINITION
+  // ================================
+
+  var Collapse = function (element, options) {
+    this.$element      = $(element)
+    this.options       = $.extend({}, Collapse.DEFAULTS, options)
+    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
+                           '[data-toggle="collapse"][data-target="#' + element.id + '"]')
+    this.transitioning = null
+
+    if (this.options.parent) {
+      this.$parent = this.getParent()
+    } else {
+      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
+    }
+
+    if (this.options.toggle) this.toggle()
+  }
+
+  Collapse.VERSION  = '3.3.4'
+
+  Collapse.TRANSITION_DURATION = 350
+
+  Collapse.DEFAULTS = {
+    toggle: true
+  }
+
+  Collapse.prototype.dimension = function () {
+    var hasWidth = this.$element.hasClass('width')
+    return hasWidth ? 'width' : 'height'
+  }
+
+  Collapse.prototype.show = function () {
+    if (this.transitioning || this.$element.hasClass('in')) return
+
+    var activesData
+    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
+
+    if (actives && actives.length) {
+      activesData = actives.data('bs.collapse')
+      if (activesData && activesData.transitioning) return
+    }
+
+    var startEvent = $.Event('show.bs.collapse')
+    this.$element.trigger(startEvent)
+    if (startEvent.isDefaultPrevented()) return
+
+    if (actives && actives.length) {
+      Plugin.call(actives, 'hide')
+      activesData || actives.data('bs.collapse', null)
+    }
+
+    var dimension = this.dimension()
+
+    this.$element
+      .removeClass('collapse')
+      .addClass('collapsing')[dimension](0)
+      .attr('aria-expanded', true)
+
+    this.$trigger
+      .removeClass('collapsed')
+      .attr('aria-expanded', true)
+
+    this.transitioning = 1
+
+    var complete = function () {
+      this.$element
+        .removeClass('collapsing')
+        .addClass('collapse in')[dimension]('')
+      this.transitioning = 0
+      this.$element
+        .trigger('shown.bs.collapse')
+    }
+
+    if (!$.support.transition) return complete.call(this)
+
+    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+
+    this.$element
+      .one('bsTransitionEnd', $.proxy(complete, this))
+      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
+  }
+
+  Collapse.prototype.hide = function () {
+    if (this.transitioning || !this.$element.hasClass('in')) return
+
+    var startEvent = $.Event('hide.bs.collapse')
+    this.$element.trigger(startEvent)
+    if (startEvent.isDefaultPrevented()) return
+
+    var dimension = this.dimension()
+
+    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
+
+    this.$element
+      .addClass('collapsing')
+      .removeClass('collapse in')
+      .attr('aria-expanded', false)
+
+    this.$trigger
+      .addClass('collapsed')
+      .attr('aria-expanded', false)
+
+    this.transitioning = 1
+
+    var complete = function () {
+      this.transitioning = 0
+      this.$element
+        .removeClass('collapsing')
+        .addClass('collapse')
+        .trigger('hidden.bs.collapse')
+    }
+
+    if (!$.support.transition) return complete.call(this)
+
+    this.$element
+      [dimension](0)
+      .one('bsTransitionEnd', $.proxy(complete, this))
+      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
+  }
+
+  Collapse.prototype.toggle = function () {
+    this[this.$element.hasClass('in') ? 'hide' : 'show']()
+  }
+
+  Collapse.prototype.getParent = function () {
+    return $(this.options.parent)
+      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
+      .each($.proxy(function (i, element) {
+        var $element = $(element)
+        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
+      }, this))
+      .end()
+  }
+
+  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
+    var isOpen = $element.hasClass('in')
+
+    $element.attr('aria-expanded', isOpen)
+    $trigger
+      .toggleClass('collapsed', !isOpen)
+      .attr('aria-expanded', isOpen)
+  }
+
+  function getTargetFromTrigger($trigger) {
+    var href
+    var target = $trigger.attr('data-target')
+      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
+
+    return $(target)
+  }
+
+
+  // COLLAPSE PLUGIN DEFINITION
+  // ==========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.collapse')
+      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
+      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.collapse
+
+  $.fn.collapse             = Plugin
+  $.fn.collapse.Constructor = Collapse
+
+
+  // COLLAPSE NO CONFLICT
+  // ====================
+
+  $.fn.collapse.noConflict = function () {
+    $.fn.collapse = old
+    return this
+  }
+
+
+  // COLLAPSE DATA-API
+  // =================
+
+  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
+    var $this   = $(this)
+
+    if (!$this.attr('data-target')) e.preventDefault()
+
+    var $target = getTargetFromTrigger($this)
+    var data    = $target.data('bs.collapse')
+    var option  = data ? 'toggle' : $this.data()
+
+    Plugin.call($target, option)
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.3.4
+ * http://getbootstrap.com/javascript/#dropdowns
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // DROPDOWN CLASS DEFINITION
+  // =========================
+
+  var backdrop = '.dropdown-backdrop'
+  var toggle   = '[data-toggle="dropdown"]'
+  var Dropdown = function (element) {
+    $(element).on('click.bs.dropdown', this.toggle)
+  }
+
+  Dropdown.VERSION = '3.3.4'
+
+  Dropdown.prototype.toggle = function (e) {
+    var $this = $(this)
+
+    if ($this.is('.disabled, :disabled')) return
+
+    var $parent  = getParent($this)
+    var isActive = $parent.hasClass('open')
+
+    clearMenus()
+
+    if (!isActive) {
+      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
+        // if mobile we use a backdrop because click events don't delegate
+        $(document.createElement('div'))
+          .addClass('dropdown-backdrop')
+          .insertAfter($(this))
+          .on('click', clearMenus)
+      }
+
+      var relatedTarget = { relatedTarget: this }
+      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+
+      if (e.isDefaultPrevented()) return
+
+      $this
+        .trigger('focus')
+        .attr('aria-expanded', 'true')
+
+      $parent
+        .toggleClass('open')
+        .trigger('shown.bs.dropdown', relatedTarget)
+    }
+
+    return false
+  }
+
+  Dropdown.prototype.keydown = function (e) {
+    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
+
+    var $this = $(this)
+
+    e.preventDefault()
+    e.stopPropagation()
+
+    if ($this.is('.disabled, :disabled')) return
+
+    var $parent  = getParent($this)
+    var isActive = $parent.hasClass('open')
+
+    if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
+      if (e.which == 27) $parent.find(toggle).trigger('focus')
+      return $this.trigger('click')
+    }
+
+    var desc = ' li:not(.disabled):visible a'
+    var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
+
+    if (!$items.length) return
+
+    var index = $items.index(e.target)
+
+    if (e.which == 38 && index > 0)                 index--                        // up
+    if (e.which == 40 && index < $items.length - 1) index++                        // down
+    if (!~index)                                      index = 0
+
+    $items.eq(index).trigger('focus')
+  }
+
+  function clearMenus(e) {
+    if (e && e.which === 3) return
+    $(backdrop).remove()
+    $(toggle).each(function () {
+      var $this         = $(this)
+      var $parent       = getParent($this)
+      var relatedTarget = { relatedTarget: this }
+
+      if (!$parent.hasClass('open')) return
+
+      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
+
+      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+
+      if (e.isDefaultPrevented()) return
+
+      $this.attr('aria-expanded', 'false')
+      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
+    })
+  }
+
+  function getParent($this) {
+    var selector = $this.attr('data-target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    var $parent = selector && $(selector)
+
+    return $parent && $parent.length ? $parent : $this.parent()
+  }
+
+
+  // DROPDOWN PLUGIN DEFINITION
+  // ==========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.dropdown')
+
+      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  var old = $.fn.dropdown
+
+  $.fn.dropdown             = Plugin
+  $.fn.dropdown.Constructor = Dropdown
+
+
+  // DROPDOWN NO CONFLICT
+  // ====================
+
+  $.fn.dropdown.noConflict = function () {
+    $.fn.dropdown = old
+    return this
+  }
+
+
+  // APPLY TO STANDARD DROPDOWN ELEMENTS
+  // ===================================
+
+  $(document)
+    .on('click.bs.dropdown.data-api', clearMenus)
+    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
+    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: modal.js v3.3.4
+ * http://getbootstrap.com/javascript/#modals
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // MODAL CLASS DEFINITION
+  // ======================
+
+  var Modal = function (element, options) {
+    this.options             = options
+    this.$body               = $(document.body)
+    this.$element            = $(element)
+    this.$dialog             = this.$element.find('.modal-dialog')
+    this.$backdrop           = null
+    this.isShown             = null
+    this.originalBodyPad     = null
+    this.scrollbarWidth      = 0
+    this.ignoreBackdropClick = false
+
+    if (this.options.remote) {
+      this.$element
+        .find('.modal-content')
+        .load(this.options.remote, $.proxy(function () {
+          this.$element.trigger('loaded.bs.modal')
+        }, this))
+    }
+  }
+
+  Modal.VERSION  = '3.3.4'
+
+  Modal.TRANSITION_DURATION = 300
+  Modal.BACKDROP_TRANSITION_DURATION = 150
+
+  Modal.DEFAULTS = {
+    backdrop: true,
+    keyboard: true,
+    show: true
+  }
+
+  Modal.prototype.toggle = function (_relatedTarget) {
+    return this.isShown ? this.hide() : this.show(_relatedTarget)
+  }
+
+  Modal.prototype.show = function (_relatedTarget) {
+    var that = this
+    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+    this.$element.trigger(e)
+
+    if (this.isShown || e.isDefaultPrevented()) return
+
+    this.isShown = true
+
+    this.checkScrollbar()
+    this.setScrollbar()
+    this.$body.addClass('modal-open')
+
+    this.escape()
+    this.resize()
+
+    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
+      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
+        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
+      })
+    })
+
+    this.backdrop(function () {
+      var transition = $.support.transition && that.$element.hasClass('fade')
+
+      if (!that.$element.parent().length) {
+        that.$element.appendTo(that.$body) // don't move modals dom position
+      }
+
+      that.$element
+        .show()
+        .scrollTop(0)
+
+      that.adjustDialog()
+
+      if (transition) {
+        that.$element[0].offsetWidth // force reflow
+      }
+
+      that.$element.addClass('in')
+
+      that.enforceFocus()
+
+      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+      transition ?
+        that.$dialog // wait for modal to slide in
+          .one('bsTransitionEnd', function () {
+            that.$element.trigger('focus').trigger(e)
+          })
+          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+        that.$element.trigger('focus').trigger(e)
+    })
+  }
+
+  Modal.prototype.hide = function (e) {
+    if (e) e.preventDefault()
+
+    e = $.Event('hide.bs.modal')
+
+    this.$element.trigger(e)
+
+    if (!this.isShown || e.isDefaultPrevented()) return
+
+    this.isShown = false
+
+    this.escape()
+    this.resize()
+
+    $(document).off('focusin.bs.modal')
+
+    this.$element
+      .removeClass('in')
+      .off('click.dismiss.bs.modal')
+      .off('mouseup.dismiss.bs.modal')
+
+    this.$dialog.off('mousedown.dismiss.bs.modal')
+
+    $.support.transition && this.$element.hasClass('fade') ?
+      this.$element
+        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
+        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+      this.hideModal()
+  }
+
+  Modal.prototype.enforceFocus = function () {
+    $(document)
+      .off('focusin.bs.modal') // guard against infinite focus loop
+      .on('focusin.bs.modal', $.proxy(function (e) {
+        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+          this.$element.trigger('focus')
+        }
+      }, this))
+  }
+
+  Modal.prototype.escape = function () {
+    if (this.isShown && this.options.keyboard) {
+      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
+        e.which == 27 && this.hide()
+      }, this))
+    } else if (!this.isShown) {
+      this.$element.off('keydown.dismiss.bs.modal')
+    }
+  }
+
+  Modal.prototype.resize = function () {
+    if (this.isShown) {
+      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
+    } else {
+      $(window).off('resize.bs.modal')
+    }
+  }
+
+  Modal.prototype.hideModal = function () {
+    var that = this
+    this.$element.hide()
+    this.backdrop(function () {
+      that.$body.removeClass('modal-open')
+      that.resetAdjustments()
+      that.resetScrollbar()
+      that.$element.trigger('hidden.bs.modal')
+    })
+  }
+
+  Modal.prototype.removeBackdrop = function () {
+    this.$backdrop && this.$backdrop.remove()
+    this.$backdrop = null
+  }
+
+  Modal.prototype.backdrop = function (callback) {
+    var that = this
+    var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+    if (this.isShown && this.options.backdrop) {
+      var doAnimate = $.support.transition && animate
+
+      this.$backdrop = $(document.createElement('div'))
+        .addClass('modal-backdrop ' + animate)
+        .appendTo(this.$body)
+
+      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
+        if (this.ignoreBackdropClick) {
+          this.ignoreBackdropClick = false
+          return
+        }
+        if (e.target !== e.currentTarget) return
+        this.options.backdrop == 'static'
+          ? this.$element[0].focus()
+          : this.hide()
+      }, this))
+
+      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+      this.$backdrop.addClass('in')
+
+      if (!callback) return
+
+      doAnimate ?
+        this.$backdrop
+          .one('bsTransitionEnd', callback)
+          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+        callback()
+
+    } else if (!this.isShown && this.$backdrop) {
+      this.$backdrop.removeClass('in')
+
+      var callbackRemove = function () {
+        that.removeBackdrop()
+        callback && callback()
+      }
+      $.support.transition && this.$element.hasClass('fade') ?
+        this.$backdrop
+          .one('bsTransitionEnd', callbackRemove)
+          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+        callbackRemove()
+
+    } else if (callback) {
+      callback()
+    }
+  }
+
+  // these following methods are used to handle overflowing modals
+
+  Modal.prototype.handleUpdate = function () {
+    this.adjustDialog()
+  }
+
+  Modal.prototype.adjustDialog = function () {
+    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
+
+    this.$element.css({
+      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
+      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
+    })
+  }
+
+  Modal.prototype.resetAdjustments = function () {
+    this.$element.css({
+      paddingLeft: '',
+      paddingRight: ''
+    })
+  }
+
+  Modal.prototype.checkScrollbar = function () {
+    var fullWindowWidth = window.innerWidth
+    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
+      var documentElementRect = document.documentElement.getBoundingClientRect()
+      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
+    }
+    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
+    this.scrollbarWidth = this.measureScrollbar()
+  }
+
+  Modal.prototype.setScrollbar = function () {
+    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
+    this.originalBodyPad = document.body.style.paddingRight || ''
+    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
+  }
+
+  Modal.prototype.resetScrollbar = function () {
+    this.$body.css('padding-right', this.originalBodyPad)
+  }
+
+  Modal.prototype.measureScrollbar = function () { // thx walsh
+    var scrollDiv = document.createElement('div')
+    scrollDiv.className = 'modal-scrollbar-measure'
+    this.$body.append(scrollDiv)
+    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
+    this.$body[0].removeChild(scrollDiv)
+    return scrollbarWidth
+  }
+
+
+  // MODAL PLUGIN DEFINITION
+  // =======================
+
+  function Plugin(option, _relatedTarget) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.modal')
+      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+      if (typeof option == 'string') data[option](_relatedTarget)
+      else if (options.show) data.show(_relatedTarget)
+    })
+  }
+
+  var old = $.fn.modal
+
+  $.fn.modal             = Plugin
+  $.fn.modal.Constructor = Modal
+
+
+  // MODAL NO CONFLICT
+  // =================
+
+  $.fn.modal.noConflict = function () {
+    $.fn.modal = old
+    return this
+  }
+
+
+  // MODAL DATA-API
+  // ==============
+
+  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+    var $this   = $(this)
+    var href    = $this.attr('href')
+    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
+    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+    if ($this.is('a')) e.preventDefault()
+
+    $target.one('show.bs.modal', function (showEvent) {
+      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
+      $target.one('hidden.bs.modal', function () {
+        $this.is(':visible') && $this.trigger('focus')
+      })
+    })
+    Plugin.call($target, option, this)
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.3.4
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // TOOLTIP PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Tooltip = function (element, options) {
+    this.type       = null
+    this.options    = null
+    this.enabled    = null
+    this.timeout    = null
+    this.hoverState = null
+    this.$element   = null
+
+    this.init('tooltip', element, options)
+  }
+
+  Tooltip.VERSION  = '3.3.4'
+
+  Tooltip.TRANSITION_DURATION = 150
+
+  Tooltip.DEFAULTS = {
+    animation: true,
+    placement: 'top',
+    selector: false,
+    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+    trigger: 'hover focus',
+    title: '',
+    delay: 0,
+    html: false,
+    container: false,
+    viewport: {
+      selector: 'body',
+      padding: 0
+    }
+  }
+
+  Tooltip.prototype.init = function (type, element, options) {
+    this.enabled   = true
+    this.type      = type
+    this.$element  = $(element)
+    this.options   = this.getOptions(options)
+    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
+
+    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
+      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
+    }
+
+    var triggers = this.options.trigger.split(' ')
+
+    for (var i = triggers.length; i--;) {
+      var trigger = triggers[i]
+
+      if (trigger == 'click') {
+        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+      } else if (trigger != 'manual') {
+        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
+        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+      }
+    }
+
+    this.options.selector ?
+      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+      this.fixTitle()
+  }
+
+  Tooltip.prototype.getDefaults = function () {
+    return Tooltip.DEFAULTS
+  }
+
+  Tooltip.prototype.getOptions = function (options) {
+    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+    if (options.delay && typeof options.delay == 'number') {
+      options.delay = {
+        show: options.delay,
+        hide: options.delay
+      }
+    }
+
+    return options
+  }
+
+  Tooltip.prototype.getDelegateOptions = function () {
+    var options  = {}
+    var defaults = this.getDefaults()
+
+    this._options && $.each(this._options, function (key, value) {
+      if (defaults[key] != value) options[key] = value
+    })
+
+    return options
+  }
+
+  Tooltip.prototype.enter = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget).data('bs.' + this.type)
+
+    if (self && self.$tip && self.$tip.is(':visible')) {
+      self.hoverState = 'in'
+      return
+    }
+
+    if (!self) {
+      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+      $(obj.currentTarget).data('bs.' + this.type, self)
+    }
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'in'
+
+    if (!self.options.delay || !self.options.delay.show) return self.show()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'in') self.show()
+    }, self.options.delay.show)
+  }
+
+  Tooltip.prototype.leave = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget).data('bs.' + this.type)
+
+    if (!self) {
+      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+      $(obj.currentTarget).data('bs.' + this.type, self)
+    }
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'out'
+
+    if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'out') self.hide()
+    }, self.options.delay.hide)
+  }
+
+  Tooltip.prototype.show = function () {
+    var e = $.Event('show.bs.' + this.type)
+
+    if (this.hasContent() && this.enabled) {
+      this.$element.trigger(e)
+
+      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
+      if (e.isDefaultPrevented() || !inDom) return
+      var that = this
+
+      var $tip = this.tip()
+
+      var tipId = this.getUID(this.type)
+
+      this.setContent()
+      $tip.attr('id', tipId)
+      this.$element.attr('aria-describedby', tipId)
+
+      if (this.options.animation) $tip.addClass('fade')
+
+      var placement = typeof this.options.placement == 'function' ?
+        this.options.placement.call(this, $tip[0], this.$element[0]) :
+        this.options.placement
+
+      var autoToken = /\s?auto?\s?/i
+      var autoPlace = autoToken.test(placement)
+      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+      $tip
+        .detach()
+        .css({ top: 0, left: 0, display: 'block' })
+        .addClass(placement)
+        .data('bs.' + this.type, this)
+
+      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+      var pos          = this.getPosition()
+      var actualWidth  = $tip[0].offsetWidth
+      var actualHeight = $tip[0].offsetHeight
+
+      if (autoPlace) {
+        var orgPlacement = placement
+        var $container   = this.options.container ? $(this.options.container) : this.$element.parent()
+        var containerDim = this.getPosition($container)
+
+        placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top'    :
+                    placement == 'top'    && pos.top    - actualHeight < containerDim.top    ? 'bottom' :
+                    placement == 'right'  && pos.right  + actualWidth  > containerDim.width  ? 'left'   :
+                    placement == 'left'   && pos.left   - actualWidth  < containerDim.left   ? 'right'  :
+                    placement
+
+        $tip
+          .removeClass(orgPlacement)
+          .addClass(placement)
+      }
+
+      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+      this.applyPlacement(calculatedOffset, placement)
+
+      var complete = function () {
+        var prevHoverState = that.hoverState
+        that.$element.trigger('shown.bs.' + that.type)
+        that.hoverState = null
+
+        if (prevHoverState == 'out') that.leave(that)
+      }
+
+      $.support.transition && this.$tip.hasClass('fade') ?
+        $tip
+          .one('bsTransitionEnd', complete)
+          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+        complete()
+    }
+  }
+
+  Tooltip.prototype.applyPlacement = function (offset, placement) {
+    var $tip   = this.tip()
+    var width  = $tip[0].offsetWidth
+    var height = $tip[0].offsetHeight
+
+    // manually read margins because getBoundingClientRect includes difference
+    var marginTop = parseInt($tip.css('margin-top'), 10)
+    var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+    // we must check for NaN for ie 8/9
+    if (isNaN(marginTop))  marginTop  = 0
+    if (isNaN(marginLeft)) marginLeft = 0
+
+    offset.top  = offset.top  + marginTop
+    offset.left = offset.left + marginLeft
+
+    // $.fn.offset doesn't round pixel values
+    // so we use setOffset directly with our own function B-0
+    $.offset.setOffset($tip[0], $.extend({
+      using: function (props) {
+        $tip.css({
+          top: Math.round(props.top),
+          left: Math.round(props.left)
+        })
+      }
+    }, offset), 0)
+
+    $tip.addClass('in')
+
+    // check to see if placing tip in new offset caused the tip to resize itself
+    var actualWidth  = $tip[0].offsetWidth
+    var actualHeight = $tip[0].offsetHeight
+
+    if (placement == 'top' && actualHeight != height) {
+      offset.top = offset.top + height - actualHeight
+    }
+
+    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
+
+    if (delta.left) offset.left += delta.left
+    else offset.top += delta.top
+
+    var isVertical          = /top|bottom/.test(placement)
+    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
+
+    $tip.offset(offset)
+    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
+  }
+
+  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
+    this.arrow()
+      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
+      .css(isVertical ? 'top' : 'left', '')
+  }
+
+  Tooltip.prototype.setContent = function () {
+    var $tip  = this.tip()
+    var title = this.getTitle()
+
+    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+    $tip.removeClass('fade in top bottom left right')
+  }
+
+  Tooltip.prototype.hide = function (callback) {
+    var that = this
+    var $tip = $(this.$tip)
+    var e    = $.Event('hide.bs.' + this.type)
+
+    function complete() {
+      if (that.hoverState != 'in') $tip.detach()
+      that.$element
+        .removeAttr('aria-describedby')
+        .trigger('hidden.bs.' + that.type)
+      callback && callback()
+    }
+
+    this.$element.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    $tip.removeClass('in')
+
+    $.support.transition && $tip.hasClass('fade') ?
+      $tip
+        .one('bsTransitionEnd', complete)
+        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+      complete()
+
+    this.hoverState = null
+
+    return this
+  }
+
+  Tooltip.prototype.fixTitle = function () {
+    var $e = this.$element
+    if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
+      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+    }
+  }
+
+  Tooltip.prototype.hasContent = function () {
+    return this.getTitle()
+  }
+
+  Tooltip.prototype.getPosition = function ($element) {
+    $element   = $element || this.$element
+
+    var el     = $element[0]
+    var isBody = el.tagName == 'BODY'
+
+    var elRect    = el.getBoundingClientRect()
+    if (elRect.width == null) {
+      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
+      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
+    }
+    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()
+    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
+    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
+
+    return $.extend({}, elRect, scroll, outerDims, elOffset)
+  }
+
+  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
+           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+
+  }
+
+  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
+    var delta = { top: 0, left: 0 }
+    if (!this.$viewport) return delta
+
+    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
+    var viewportDimensions = this.getPosition(this.$viewport)
+
+    if (/right|left/.test(placement)) {
+      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
+      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
+      if (topEdgeOffset < viewportDimensions.top) { // top overflow
+        delta.top = viewportDimensions.top - topEdgeOffset
+      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
+        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
+      }
+    } else {
+      var leftEdgeOffset  = pos.left - viewportPadding
+      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
+      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
+        delta.left = viewportDimensions.left - leftEdgeOffset
+      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
+        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
+      }
+    }
+
+    return delta
+  }
+
+  Tooltip.prototype.getTitle = function () {
+    var title
+    var $e = this.$element
+    var o  = this.options
+
+    title = $e.attr('data-original-title')
+      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
+
+    return title
+  }
+
+  Tooltip.prototype.getUID = function (prefix) {
+    do prefix += ~~(Math.random() * 1000000)
+    while (document.getElementById(prefix))
+    return prefix
+  }
+
+  Tooltip.prototype.tip = function () {
+    return (this.$tip = this.$tip || $(this.options.template))
+  }
+
+  Tooltip.prototype.arrow = function () {
+    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
+  }
+
+  Tooltip.prototype.enable = function () {
+    this.enabled = true
+  }
+
+  Tooltip.prototype.disable = function () {
+    this.enabled = false
+  }
+
+  Tooltip.prototype.toggleEnabled = function () {
+    this.enabled = !this.enabled
+  }
+
+  Tooltip.prototype.toggle = function (e) {
+    var self = this
+    if (e) {
+      self = $(e.currentTarget).data('bs.' + this.type)
+      if (!self) {
+        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
+        $(e.currentTarget).data('bs.' + this.type, self)
+      }
+    }
+
+    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+  }
+
+  Tooltip.prototype.destroy = function () {
+    var that = this
+    clearTimeout(this.timeout)
+    this.hide(function () {
+      that.$element.off('.' + that.type).removeData('bs.' + that.type)
+    })
+  }
+
+
+  // TOOLTIP PLUGIN DEFINITION
+  // =========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.tooltip')
+      var options = typeof option == 'object' && option
+
+      if (!data && /destroy|hide/.test(option)) return
+      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.tooltip
+
+  $.fn.tooltip             = Plugin
+  $.fn.tooltip.Constructor = Tooltip
+
+
+  // TOOLTIP NO CONFLICT
+  // ===================
+
+  $.fn.tooltip.noConflict = function () {
+    $.fn.tooltip = old
+    return this
+  }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.3.4
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // POPOVER PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Popover = function (element, options) {
+    this.init('popover', element, options)
+  }
+
+  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+  Popover.VERSION  = '3.3.4'
+
+  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+    placement: 'right',
+    trigger: 'click',
+    content: '',
+    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+  })
+
+
+  // NOTE: POPOVER EXTENDS tooltip.js
+  // ================================
+
+  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+  Popover.prototype.constructor = Popover
+
+  Popover.prototype.getDefaults = function () {
+    return Popover.DEFAULTS
+  }
+
+  Popover.prototype.setContent = function () {
+    var $tip    = this.tip()
+    var title   = this.getTitle()
+    var content = this.getContent()
+
+    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
+      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+    ](content)
+
+    $tip.removeClass('fade top bottom left right in')
+
+    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+    // this manually by checking the contents.
+    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+  }
+
+  Popover.prototype.hasContent = function () {
+    return this.getTitle() || this.getContent()
+  }
+
+  Popover.prototype.getContent = function () {
+    var $e = this.$element
+    var o  = this.options
+
+    return $e.attr('data-content')
+      || (typeof o.content == 'function' ?
+            o.content.call($e[0]) :
+            o.content)
+  }
+
+  Popover.prototype.arrow = function () {
+    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
+  }
+
+
+  // POPOVER PLUGIN DEFINITION
+  // =========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.popover')
+      var options = typeof option == 'object' && option
+
+      if (!data && /destroy|hide/.test(option)) return
+      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.popover
+
+  $.fn.popover             = Plugin
+  $.fn.popover.Constructor = Popover
+
+
+  // POPOVER NO CONFLICT
+  // ===================
+
+  $.fn.popover.noConflict = function () {
+    $.fn.popover = old
+    return this
+  }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: scrollspy.js v3.3.4
+ * http://getbootstrap.com/javascript/#scrollspy
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // SCROLLSPY CLASS DEFINITION
+  // ==========================
+
+  function ScrollSpy(element, options) {
+    this.$body          = $(document.body)
+    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
+    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
+    this.selector       = (this.options.target || '') + ' .nav li > a'
+    this.offsets        = []
+    this.targets        = []
+    this.activeTarget   = null
+    this.scrollHeight   = 0
+
+    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
+    this.refresh()
+    this.process()
+  }
+
+  ScrollSpy.VERSION  = '3.3.4'
+
+  ScrollSpy.DEFAULTS = {
+    offset: 10
+  }
+
+  ScrollSpy.prototype.getScrollHeight = function () {
+    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
+  }
+
+  ScrollSpy.prototype.refresh = function () {
+    var that          = this
+    var offsetMethod  = 'offset'
+    var offsetBase    = 0
+
+    this.offsets      = []
+    this.targets      = []
+    this.scrollHeight = this.getScrollHeight()
+
+    if (!$.isWindow(this.$scrollElement[0])) {
+      offsetMethod = 'position'
+      offsetBase   = this.$scrollElement.scrollTop()
+    }
+
+    this.$body
+      .find(this.selector)
+      .map(function () {
+        var $el   = $(this)
+        var href  = $el.data('target') || $el.attr('href')
+        var $href = /^#./.test(href) && $(href)
+
+        return ($href
+          && $href.length
+          && $href.is(':visible')
+          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
+      })
+      .sort(function (a, b) { return a[0] - b[0] })
+      .each(function () {
+        that.offsets.push(this[0])
+        that.targets.push(this[1])
+      })
+  }
+
+  ScrollSpy.prototype.process = function () {
+    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
+    var scrollHeight = this.getScrollHeight()
+    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
+    var offsets      = this.offsets
+    var targets      = this.targets
+    var activeTarget = this.activeTarget
+    var i
+
+    if (this.scrollHeight != scrollHeight) {
+      this.refresh()
+    }
+
+    if (scrollTop >= maxScroll) {
+      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
+    }
+
+    if (activeTarget && scrollTop < offsets[0]) {
+      this.activeTarget = null
+      return this.clear()
+    }
+
+    for (i = offsets.length; i--;) {
+      activeTarget != targets[i]
+        && scrollTop >= offsets[i]
+        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
+        && this.activate(targets[i])
+    }
+  }
+
+  ScrollSpy.prototype.activate = function (target) {
+    this.activeTarget = target
+
+    this.clear()
+
+    var selector = this.selector +
+      '[data-target="' + target + '"],' +
+      this.selector + '[href="' + target + '"]'
+
+    var active = $(selector)
+      .parents('li')
+      .addClass('active')
+
+    if (active.parent('.dropdown-menu').length) {
+      active = active
+        .closest('li.dropdown')
+        .addClass('active')
+    }
+
+    active.trigger('activate.bs.scrollspy')
+  }
+
+  ScrollSpy.prototype.clear = function () {
+    $(this.selector)
+      .parentsUntil(this.options.target, '.active')
+      .removeClass('active')
+  }
+
+
+  // SCROLLSPY PLUGIN DEFINITION
+  // ===========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.scrollspy')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.scrollspy
+
+  $.fn.scrollspy             = Plugin
+  $.fn.scrollspy.Constructor = ScrollSpy
+
+
+  // SCROLLSPY NO CONFLICT
+  // =====================
+
+  $.fn.scrollspy.noConflict = function () {
+    $.fn.scrollspy = old
+    return this
+  }
+
+
+  // SCROLLSPY DATA-API
+  // ==================
+
+  $(window).on('load.bs.scrollspy.data-api', function () {
+    $('[data-spy="scroll"]').each(function () {
+      var $spy = $(this)
+      Plugin.call($spy, $spy.data())
+    })
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tab.js v3.3.4
+ * http://getbootstrap.com/javascript/#tabs
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // TAB CLASS DEFINITION
+  // ====================
+
+  var Tab = function (element) {
+    this.element = $(element)
+  }
+
+  Tab.VERSION = '3.3.4'
+
+  Tab.TRANSITION_DURATION = 150
+
+  Tab.prototype.show = function () {
+    var $this    = this.element
+    var $ul      = $this.closest('ul:not(.dropdown-menu)')
+    var selector = $this.data('target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    if ($this.parent('li').hasClass('active')) return
+
+    var $previous = $ul.find('.active:last a')
+    var hideEvent = $.Event('hide.bs.tab', {
+      relatedTarget: $this[0]
+    })
+    var showEvent = $.Event('show.bs.tab', {
+      relatedTarget: $previous[0]
+    })
+
+    $previous.trigger(hideEvent)
+    $this.trigger(showEvent)
+
+    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
+
+    var $target = $(selector)
+
+    this.activate($this.closest('li'), $ul)
+    this.activate($target, $target.parent(), function () {
+      $previous.trigger({
+        type: 'hidden.bs.tab',
+        relatedTarget: $this[0]
+      })
+      $this.trigger({
+        type: 'shown.bs.tab',
+        relatedTarget: $previous[0]
+      })
+    })
+  }
+
+  Tab.prototype.activate = function (element, container, callback) {
+    var $active    = container.find('> .active')
+    var transition = callback
+      && $.support.transition
+      && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
+
+    function next() {
+      $active
+        .removeClass('active')
+        .find('> .dropdown-menu > .active')
+          .removeClass('active')
+        .end()
+        .find('[data-toggle="tab"]')
+          .attr('aria-expanded', false)
+
+      element
+        .addClass('active')
+        .find('[data-toggle="tab"]')
+          .attr('aria-expanded', true)
+
+      if (transition) {
+        element[0].offsetWidth // reflow for transition
+        element.addClass('in')
+      } else {
+        element.removeClass('fade')
+      }
+
+      if (element.parent('.dropdown-menu').length) {
+        element
+          .closest('li.dropdown')
+            .addClass('active')
+          .end()
+          .find('[data-toggle="tab"]')
+            .attr('aria-expanded', true)
+      }
+
+      callback && callback()
+    }
+
+    $active.length && transition ?
+      $active
+        .one('bsTransitionEnd', next)
+        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
+      next()
+
+    $active.removeClass('in')
+  }
+
+
+  // TAB PLUGIN DEFINITION
+  // =====================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.tab')
+
+      if (!data) $this.data('bs.tab', (data = new Tab(this)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.tab
+
+  $.fn.tab             = Plugin
+  $.fn.tab.Constructor = Tab
+
+
+  // TAB NO CONFLICT
+  // ===============
+
+  $.fn.tab.noConflict = function () {
+    $.fn.tab = old
+    return this
+  }
+
+
+  // TAB DATA-API
+  // ============
+
+  var clickHandler = function (e) {
+    e.preventDefault()
+    Plugin.call($(this), 'show')
+  }
+
+  $(document)
+    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
+    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: affix.js v3.3.4
+ * http://getbootstrap.com/javascript/#affix
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // AFFIX CLASS DEFINITION
+  // ======================
+
+  var Affix = function (element, options) {
+    this.options = $.extend({}, Affix.DEFAULTS, options)
+
+    this.$target = $(this.options.target)
+      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
+      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
+
+    this.$element     = $(element)
+    this.affixed      = null
+    this.unpin        = null
+    this.pinnedOffset = null
+
+    this.checkPosition()
+  }
+
+  Affix.VERSION  = '3.3.4'
+
+  Affix.RESET    = 'affix affix-top affix-bottom'
+
+  Affix.DEFAULTS = {
+    offset: 0,
+    target: window
+  }
+
+  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
+    var scrollTop    = this.$target.scrollTop()
+    var position     = this.$element.offset()
+    var targetHeight = this.$target.height()
+
+    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
+
+    if (this.affixed == 'bottom') {
+      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
+      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
+    }
+
+    var initializing   = this.affixed == null
+    var colliderTop    = initializing ? scrollTop : position.top
+    var colliderHeight = initializing ? targetHeight : height
+
+    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
+    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
+
+    return false
+  }
+
+  Affix.prototype.getPinnedOffset = function () {
+    if (this.pinnedOffset) return this.pinnedOffset
+    this.$element.removeClass(Affix.RESET).addClass('affix')
+    var scrollTop = this.$target.scrollTop()
+    var position  = this.$element.offset()
+    return (this.pinnedOffset = position.top - scrollTop)
+  }
+
+  Affix.prototype.checkPositionWithEventLoop = function () {
+    setTimeout($.proxy(this.checkPosition, this), 1)
+  }
+
+  Affix.prototype.checkPosition = function () {
+    if (!this.$element.is(':visible')) return
+
+    var height       = this.$element.height()
+    var offset       = this.options.offset
+    var offsetTop    = offset.top
+    var offsetBottom = offset.bottom
+    var scrollHeight = $(document.body).height()
+
+    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
+    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
+    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
+
+    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
+
+    if (this.affixed != affix) {
+      if (this.unpin != null) this.$element.css('top', '')
+
+      var affixType = 'affix' + (affix ? '-' + affix : '')
+      var e         = $.Event(affixType + '.bs.affix')
+
+      this.$element.trigger(e)
+
+      if (e.isDefaultPrevented()) return
+
+      this.affixed = affix
+      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+
+      this.$element
+        .removeClass(Affix.RESET)
+        .addClass(affixType)
+        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
+    }
+
+    if (affix == 'bottom') {
+      this.$element.offset({
+        top: scrollHeight - height - offsetBottom
+      })
+    }
+  }
+
+
+  // AFFIX PLUGIN DEFINITION
+  // =======================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.affix')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.affix
+
+  $.fn.affix             = Plugin
+  $.fn.affix.Constructor = Affix
+
+
+  // AFFIX NO CONFLICT
+  // =================
+
+  $.fn.affix.noConflict = function () {
+    $.fn.affix = old
+    return this
+  }
+
+
+  // AFFIX DATA-API
+  // ==============
+
+  $(window).on('load', function () {
+    $('[data-spy="affix"]').each(function () {
+      var $spy = $(this)
+      var data = $spy.data()
+
+      data.offset = data.offset || {}
+
+      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
+      if (data.offsetTop    != null) data.offset.top    = data.offsetTop
+
+      Plugin.call($spy, data)
+    })
+  })
+
+}(jQuery);
diff --git a/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.min.js b/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.min.js
new file mode 100644
index 0000000..156b6b5
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.4 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.4",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.4",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.4",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(b&&"click"==b.type&&/input|textarea/i.test(b.target.tagName)&&a.contains(e[0],b.target)||(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.4",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27|32)/.test(b.which)&&!/input|textarea/i.test(b.target.tagName)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g&&27!=b.which||g&&27==b.which)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(b.target);38==b.which&&j>0&&j--,40==b.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport),this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-m<p.top?"bottom":"right"==h&&k.right+l>p.width?"left":"left"==h&&k.left-l<p.left?"right":h,f.removeClass(n).addClass(h)}var q=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(q,h);var r=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",r).emulateTransitionEnd(c.TRANSITION_DURATION):r()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.4",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.4",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),
+!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.4",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a(document.body).height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/js/npm.js b/hubs/static/bootstrap-3.3.4-fedora/js/npm.js
new file mode 100644
index 0000000..bf6aa80
--- /dev/null
+++ b/hubs/static/bootstrap-3.3.4-fedora/js/npm.js
@@ -0,0 +1,13 @@
+// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
+require('../../js/transition.js')
+require('../../js/alert.js')
+require('../../js/button.js')
+require('../../js/carousel.js')
+require('../../js/collapse.js')
+require('../../js/dropdown.js')
+require('../../js/modal.js')
+require('../../js/tooltip.js')
+require('../../js/popover.js')
+require('../../js/scrollspy.js')
+require('../../js/tab.js')
+require('../../js/affix.js')
\ No newline at end of file

From 71e941156d6e3319f756dcfed8cbd5c0960fd13e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 17:13:46 +0000
Subject: [PATCH 2/1001] Style up widgets just a bit.


---

diff --git a/hubs/models.py b/hubs/models.py
index 74b935f..4c5bcdf 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -82,6 +82,11 @@ class Hub(BASE):
     name = sa.Column(sa.String(50), primary_key=True)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     widgets = relation('Widget', backref=backref('hub'))
+    left_width = sa.Column(sa.Integer, nullable=False, default=8)
+
+    @property
+    def right_width(self):
+        return 12 - self.left_width
 
     @property
     def left_widgets(self):
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 14f6990..e95feb4 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -4,21 +4,23 @@
 <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
 </head>
 <body>
-<div class="row">
-  <div class="col-md-8">
-    {% for widget in hub.left_widgets %}
-    <div class="row">
-      {{ widget.render(request, session) }}
+<div class="container">
+  <div class="row">
+    <div class="col-md-{{ hub.left_width }}">
+      {% for widget in hub.left_widgets %}
+      <div class="row">
+        {{ widget.render(request, session) | safe }}
+      </div>
+      {% endfor %}
     </div>
-    {% endfor %}
-  </div>
 
-  <div class="col-md-4">
-    {% for widget in hub.right_widgets %}
-    <div class="row">
-      {{ widget.render(request, session) }}
+    <div class="col-md-{{ hub.right_width }}">
+      {% for widget in hub.right_widgets %}
+      <div class="row">
+        {{ widget.render(request, session) | safe }}
+      </div>
+      {% endfor %}
     </div>
-    {% endfor %}
   </div>
 </div>
 </body>
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
new file mode 100644
index 0000000..16d27e6
--- /dev/null
+++ b/hubs/widgets/chrome.py
@@ -0,0 +1,28 @@
+
+_panel_template = """
+<div class="panel panel-default">
+  {heading}
+  <div class="panel-body">
+    {content}
+  </div> <!-- end panel-body -->
+</div> <!-- end panel -->
+"""
+
+_panel_heading_template = """
+  <div class="panel-heading">
+    <h3 class="panel-title">
+      {title}
+    </h3>
+  </div> <!-- end panel-heading -->
+"""
+
+def panel(title=None):
+    def decorator(func):
+        def inner(*args, **kwargs):
+            heading = ''
+            if title:
+                heading = _panel_heading_template.format(title=title)
+            content = func(*args, **kwargs)
+            return _panel_template.format(content=content, heading=heading)
+        return inner
+    return decorator
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index 79d551d..b2e0983 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,3 +1,5 @@
+from chrome import panel
 
+@panel("This is a dummy widget")
 def render(request, session, config):
-    return "hello"
+    return "hello world"

From 8d55dff5857460d128c23a30a7228b6a89441b4a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 17:15:16 +0000
Subject: [PATCH 3/1001] Add populate script for dev db.


---

diff --git a/populate.py b/populate.py
new file mode 100644
index 0000000..135c1ad
--- /dev/null
+++ b/populate.py
@@ -0,0 +1,19 @@
+import hubs.models
+
+session = hubs.models.init('sqlite:////var/tmp/hubs.db', True, True)
+
+hub = hubs.models.Hub(name='lol')
+session.add(hub)
+
+widget = hubs.models.Widget(plugin='dummy', index=0)
+session.add(hub)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=1)
+session.add(hub)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=0, left=True)
+session.add(hub)
+hub.widgets.append(widget)
+
+session.commit()
+

From b561169aa710f956b489899f48d127c6f71e83fe Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 17:45:56 +0000
Subject: [PATCH 4/1001] Make widgets configurable.


---

diff --git a/hubs/models.py b/hubs/models.py
index 4c5bcdf..db4c743 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -22,6 +22,7 @@
 
 
 import datetime
+import json
 import logging
 
 import sqlalchemy as sa
@@ -105,26 +106,43 @@ class Hub(BASE):
             'name': self.name,
         }
 
+def _config_default(context):
+    plugin_name = context.current_parameters['plugin']
+    plugin = widgets.registry[plugin_name]
+
+    print plugin.widget_arguments
+    return json.dumps(dict([
+        (arg.name, arg.default) for arg in plugin.widget_arguments
+    ]))
+
 
 class Widget(BASE):
     __tablename__ = 'widgets'
     idx = sa.Column(sa.Integer, primary_key=True)
-    plugin = sa.Column(sa.String(50))
+    plugin = sa.Column(sa.String(50), nullable=False)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     hub_id = sa.Column(sa.String(50), sa.ForeignKey('hubs.name'))
-    #config = ...
-    config = 'lol'
+    _config = sa.Column(sa.String(256), default=_config_default)
 
     index = sa.Column(sa.Integer, nullable=False)
     left = sa.Column(sa.Boolean, nullable=False, default=False)
 
+    @property
+    def config(self):
+        return json.loads(self._config)
+
+    @config.setter
+    def config_setter(self, config):
+        self._config = json.dumps(config)
+
     def __json__(self, reify=False):
         return {
             'plugin': self.plugin,
         }
 
     def render(self, request, session):
-        return widgets.registry[self.plugin](request, session, self.config)
+        plugin = widgets.registry[self.plugin]
+        return plugin(request, session, **self.config)
 
 
 class User(BASE):
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
new file mode 100644
index 0000000..69715c8
--- /dev/null
+++ b/hubs/widgets/base.py
@@ -0,0 +1,14 @@
+import collections
+
+Argument = collections.namedtuple('Argument', ('name', 'default', 'help'))
+
+
+def argument(name, default, help):
+    def decorator(func):
+        def inner(*args, **kwargs):
+            return func(*args, **kwargs)
+
+        inner.widget_arguments = getattr(func, 'widget_arguments', [])
+        inner.widget_arguments.append(Argument(name, default, help))
+        return inner
+    return decorator
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 16d27e6..afc3e0d 100644
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -24,5 +24,7 @@ def panel(title=None):
                 heading = _panel_heading_template.format(title=title)
             content = func(*args, **kwargs)
             return _panel_template.format(content=content, heading=heading)
+
+        inner.widget_arguments = getattr(func, 'widget_arguments', [])
         return inner
     return decorator
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index b2e0983..ab4e963 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,5 +1,8 @@
 from chrome import panel
+from base import argument
 
 @panel("This is a dummy widget")
-def render(request, session, config):
-    return "hello world"
+@argument(name="text", default="Lorem ipsum dolor...",
+          help="Some dummy text to display.")
+def render(request, session, text):
+    return text

From 01feafd7251868f3405122e38940d9d90b73a256 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 17:51:51 +0000
Subject: [PATCH 5/1001] Wrap up argument propagation in a @wraps decorator.


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 69715c8..88f750f 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -1,14 +1,24 @@
 import collections
+import functools
+
 
 Argument = collections.namedtuple('Argument', ('name', 'default', 'help'))
 
 
 def argument(name, default, help):
     def decorator(func):
+        @wraps(func)
         def inner(*args, **kwargs):
             return func(*args, **kwargs)
 
-        inner.widget_arguments = getattr(func, 'widget_arguments', [])
         inner.widget_arguments.append(Argument(name, default, help))
         return inner
     return decorator
+
+def wraps(original):
+    @functools.wraps(original)
+    def decorator(subsequent):
+        subsequent = functools.wraps(original)(subsequent)
+        subsequent.widget_arguments = getattr(original, 'widget_arguments', [])
+        return subsequent
+    return decorator
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index afc3e0d..7862e49 100644
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -1,3 +1,4 @@
+from base import wraps
 
 _panel_template = """
 <div class="panel panel-default">
@@ -16,15 +17,15 @@ _panel_heading_template = """
   </div> <!-- end panel-heading -->
 """
 
+
 def panel(title=None):
     def decorator(func):
+        @wraps(func)
         def inner(*args, **kwargs):
             heading = ''
             if title:
                 heading = _panel_heading_template.format(title=title)
             content = func(*args, **kwargs)
             return _panel_template.format(content=content, heading=heading)
-
-        inner.widget_arguments = getattr(func, 'widget_arguments', [])
         return inner
     return decorator

From e57f0bac4d054582df4cbce7438bfc9ec4ca62b6 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 18:07:33 +0000
Subject: [PATCH 6/1001] Make DB_URL configurable.


---

diff --git a/hubs/app.py b/hubs/app.py
index 598497e..e059240 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,9 +1,17 @@
+import os
+
 import flask
 
 import models
 
 app = flask.Flask(__name__)
 
+
+app.config.from_object('default_config')
+if 'HUBS_CONFIG' in os.environ:
+    app.config.from_envvar('HUBS_CONFIG')
+
+
 @app.route('/')
 def index():
     return "hi there"
@@ -11,7 +19,7 @@ def index():
 
 @app.route('/<hub_name>')
 def hubs_view(hub_name):
-    session = models.init('sqlite:////var/tmp/hubs.db')
+    session = models.init(app.config['DB_URL'])
     hub = session.query(models.Hub)\
         .filter(models.Hub.name==hub_name)\
         .first()
diff --git a/hubs/default_config.py b/hubs/default_config.py
new file mode 100644
index 0000000..3a6a0ff
--- /dev/null
+++ b/hubs/default_config.py
@@ -0,0 +1,2 @@
+# Production ready.
+DB_URL = 'sqlite:////var/tmp/hubs.db'
diff --git a/populate.py b/populate.py
index 135c1ad..7263aa7 100644
--- a/populate.py
+++ b/populate.py
@@ -1,6 +1,15 @@
+import os
+
+import flask
+
 import hubs.models
 
-session = hubs.models.init('sqlite:////var/tmp/hubs.db', True, True)
+app = flask.Flask(__name__)
+app.config.from_object('hubs.default_config')
+if 'HUBS_CONFIG' in os.environ:
+    app.config.from_envvar('HUBS_CONFIG')
+
+session = hubs.models.init(app.config['DB_URL'], True, True)
 
 hub = hubs.models.Hub(name='lol')
 session.add(hub)

From 5c6e221893fb9cafc18057d5363f0371e88016d7 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 18:12:10 +0000
Subject: [PATCH 7/1001] Start to add some validators.


---

diff --git a/hubs/validators.py b/hubs/validators.py
new file mode 100644
index 0000000..470aad7
--- /dev/null
+++ b/hubs/validators.py
@@ -0,0 +1,5 @@
+import kitchen.text.converters
+
+
+def text(value):
+    return kitchen.text.converters.to_unicode(value)
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 88f750f..01f7c7e 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -2,16 +2,16 @@ import collections
 import functools
 
 
-Argument = collections.namedtuple('Argument', ('name', 'default', 'help'))
+Argument = collections.namedtuple('Argument', ('name', 'default', 'validator', 'help'))
 
 
-def argument(name, default, help):
+def argument(name, default, validator, help):
     def decorator(func):
         @wraps(func)
         def inner(*args, **kwargs):
             return func(*args, **kwargs)
 
-        inner.widget_arguments.append(Argument(name, default, help))
+        inner.widget_arguments.append(Argument(name, default, validator, help))
         return inner
     return decorator
 
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index ab4e963..5ddaa9a 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,8 +1,11 @@
 from chrome import panel
 from base import argument
 
+import hubs.validators as validators
+
 @panel("This is a dummy widget")
 @argument(name="text", default="Lorem ipsum dolor...",
+          validator=validators.text,
           help="Some dummy text to display.")
 def render(request, session, text):
     return text

From fe39c3efbf1696efd8dd643a862edd338eb1804f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 19:46:10 +0000
Subject: [PATCH 8/1001] Messing with styling.


---

diff --git a/hubs/app.py b/hubs/app.py
index e059240..031b971 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -18,6 +18,7 @@ def index():
 
 
 @app.route('/<hub_name>')
+@app.route('/<hub_name>/')
 def hubs_view(hub_name):
     session = models.init(app.config['DB_URL'])
     hub = session.query(models.Hub)\
diff --git a/hubs/models.py b/hubs/models.py
index db4c743..5782b60 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -81,10 +81,18 @@ def init(db_url, debug=False, create=False):
 class Hub(BASE):
     __tablename__ = 'hubs'
     name = sa.Column(sa.String(50), primary_key=True)
+    summary = sa.Column(sa.String(128))
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     widgets = relation('Widget', backref=backref('hub'))
     left_width = sa.Column(sa.Integer, nullable=False, default=8)
 
+    #fas_group = sa.Column(sa.String(32), nullable=False)
+
+    #members = ...
+    #subscribers = ...
+    #owners = ...
+
+
     @property
     def right_width(self):
         return 12 - self.left_width
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index e95feb4..b2b8579 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -1,9 +1,38 @@
 <html>
 <head>
-<title>{{ hub.name }}</title>
-<link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
+  <title>{{ hub.name }}</title>
+  <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
+  <style>
+    body {
+      background-color: #d1d3d4;
+    }
+    .panel {
+      border-radius: 0px;
+    }
+    .header {
+      color: #ffffff;
+      background-color: #3c6eb4;
+      width: 100%;
+    }
+    .padded {
+      padding: 5px;
+    }
+    .medium-wide {
+      width: 250px;
+    }
+    h1, h2, h3, h4, h5, h6 {
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+  </style>
 </head>
 <body>
+<div class="header">
+  <div class="padded center-block medium-wide">
+    <h3>{{hub.name}}</h3>
+    <h5>{{hub.summary}}</h5>
+  </div>
+</div>
 <div class="container">
   <div class="row">
     <div class="col-md-{{ hub.left_width }}">
diff --git a/populate.py b/populate.py
index 7263aa7..904d512 100644
--- a/populate.py
+++ b/populate.py
@@ -11,7 +11,7 @@ if 'HUBS_CONFIG' in os.environ:
 
 session = hubs.models.init(app.config['DB_URL'], True, True)
 
-hub = hubs.models.Hub(name='lol')
+hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
 session.add(hub)
 
 widget = hubs.models.Widget(plugin='dummy', index=0)

From 6544ed3cd62d27e57f6cec75fbdcc34039a51d2a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 21:35:41 +0000
Subject: [PATCH 9/1001] Add a stats and a rules widget.


---

diff --git a/hubs/models.py b/hubs/models.py
index 5782b60..c8c006a 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -88,10 +88,11 @@ class Hub(BASE):
 
     #fas_group = sa.Column(sa.String(32), nullable=False)
 
-    #members = ...
-    #subscribers = ...
-    #owners = ...
-
+    # This is just some silly dev data.  eventually, connect this
+    # to real database data.
+    owners = ['tatica', 'gnokii', 'duffy', 'ryanlerch']
+    members = ['ralph', 'sadin', 'sayan'] + owners
+    subscribers = []
 
     @property
     def right_width(self):
@@ -150,7 +151,7 @@ class Widget(BASE):
 
     def render(self, request, session):
         plugin = widgets.registry[self.plugin]
-        return plugin(request, session, **self.config)
+        return plugin(request, session, self, **self.config)
 
 
 class User(BASE):
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index b2b8579..c2a8247 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -14,6 +14,9 @@
       background-color: #3c6eb4;
       width: 100%;
     }
+    .row {
+      padding: 5px;
+    }
     .padded {
       padding: 5px;
     }
diff --git a/hubs/validators.py b/hubs/validators.py
index 470aad7..9525da1 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -3,3 +3,7 @@ import kitchen.text.converters
 
 def text(value):
     return kitchen.text.converters.to_unicode(value)
+
+def link(value):
+    # TODO -- verify that this is actually a link
+    return value
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 1ef49ec..f30c8d6 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -1,5 +1,9 @@
 import dummy
+import stats
+import rules
 
 registry = {
     'dummy': dummy.render,
+    'stats': stats.render,
+    'rules': rules.render,
 }
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 01f7c7e..d981ba1 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -1,6 +1,7 @@
 import collections
 import functools
-
+import hashlib
+import urllib
 
 Argument = collections.namedtuple('Argument', ('name', 'default', 'validator', 'help'))
 
@@ -22,3 +23,11 @@ def wraps(original):
         subsequent.widget_arguments = getattr(original, 'widget_arguments', [])
         return subsequent
     return decorator
+
+
+def avatar(username, size=32):
+    openid = 'http://%s.id.fedoraproject.org/' % username
+    query = urllib.urlencode({'s': size, 'd': 'retro'})
+    hash = hashlib.sha256(openid).hexdigest()
+    template = "https://seccdn.libravatar.org/avatar/%s?%s"
+    return template % (hash, query)
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index 5ddaa9a..a35e9d2 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -7,5 +7,5 @@ import hubs.validators as validators
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
           help="Some dummy text to display.")
-def render(request, session, text):
+def render(request, session, widget, text):
     return text
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
new file mode 100644
index 0000000..7f43eea
--- /dev/null
+++ b/hubs/widgets/rules.py
@@ -0,0 +1,45 @@
+from collections import OrderedDict as ordereddict
+
+import jinja2
+
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import argument, avatar
+from hubs import validators
+
+rules_template = jinja2.Template("""
+<div class="rules-container">
+  {% if link %}
+  <p class="small-heading">community rules</p>
+  <p><a href="{{link}}">Community Rules and Guidelines</a></p>
+  {% endif %}
+  <p class="small-heading">group owners</p>
+  {% for owner in owners %}
+    <span><img class="circle" src="{{owners[owner]}}"/> {{owner}}</span>
+  {% endfor %}
+</div>
+<style>
+  .rules-table {
+    width: 180px
+    padding: 0px;
+    margin: 0px;
+    display: inline-block;
+  }
+  .small-heading {
+    text-transform: uppercase;
+    font-size: 80%;
+    color: #797a7c;
+  }
+  .rules-table td {
+    font-size: 32pt;
+  }
+</style>
+""")
+
+@panel()
+@argument(name='link', default=None,
+          validator=validators.link,
+          help="Link to the community rules and guidelines")
+def render(request, session, widget, link):
+    owners = widget.hub.owners
+    owners = ordereddict([(o, avatar(o)) for o in owners])
+    return rules_template.render(owners=owners, link=link)
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
new file mode 100644
index 0000000..d7a1609
--- /dev/null
+++ b/hubs/widgets/stats.py
@@ -0,0 +1,36 @@
+from chrome import panel
+
+stats_template = """
+<div class="stats-container">
+  <table class="stats-table">
+    <tr><th>Members</th><th>Subscribers</th></tr>
+    <tr class="text-info"><td>{members}</td><td>{subscribers}</td></tr>
+  </table>
+  <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+</div>
+<style>
+  .stats-table {{
+    width: 180px
+    padding: 0px;
+    margin: 0px;
+    display: inline-block;
+  }}
+  .stats-table th {{
+    text-transform: uppercase;
+    font-size: 80%;
+    padding-right: 10px;
+    color: #797a7c;
+  }}
+  .stats-table td {{
+    font-size: 32pt;
+  }}
+
+</style>
+"""
+
+@panel()
+def render(request, session, widget):
+    return stats_template.format(
+        members=len(widget.hub.members),
+        subscribers=len(widget.hub.subscribers),
+    )
diff --git a/populate.py b/populate.py
index 904d512..0398028 100644
--- a/populate.py
+++ b/populate.py
@@ -1,3 +1,4 @@
+import json
 import os
 
 import flask
@@ -14,14 +15,16 @@ session = hubs.models.init(app.config['DB_URL'], True, True)
 hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
 session.add(hub)
 
-widget = hubs.models.Widget(plugin='dummy', index=0)
-session.add(hub)
+widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='dummy', index=1)
-session.add(hub)
+widget = hubs.models.Widget(plugin='rules', index=1,
+                            _config=json.dumps({
+                                'link': 'http://threebean.org'
+                            }))
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=2)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=0, left=True)
-session.add(hub)
 hub.widgets.append(widget)
 
 session.commit()

From 2010c04a80b1c100f5cae6872ff7a5897d8e5cb3 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 21:57:12 +0000
Subject: [PATCH 10/1001] Add a sticky note.


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index f30c8d6..2e495f7 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -1,9 +1,11 @@
 import dummy
 import stats
 import rules
+import sticky
 
 registry = {
     'dummy': dummy.render,
     'stats': stats.render,
     'rules': rules.render,
+    'sticky': sticky.render,
 }
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 7862e49..1f8d399 100644
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -1,7 +1,7 @@
 from base import wraps
 
 _panel_template = """
-<div class="panel panel-default">
+<div class="panel {klass}">
   {heading}
   <div class="panel-body">
     {content}
@@ -18,7 +18,7 @@ _panel_heading_template = """
 """
 
 
-def panel(title=None):
+def panel(title=None, klass="panel-default"):
     def decorator(func):
         @wraps(func)
         def inner(*args, **kwargs):
@@ -26,6 +26,6 @@ def panel(title=None):
             if title:
                 heading = _panel_heading_template.format(title=title)
             content = func(*args, **kwargs)
-            return _panel_template.format(content=content, heading=heading)
+            return _panel_template.format(content=content, heading=heading, klass=klass)
         return inner
     return decorator
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
new file mode 100644
index 0000000..2246ae1
--- /dev/null
+++ b/hubs/widgets/sticky.py
@@ -0,0 +1,12 @@
+from chrome import panel
+from base import argument
+
+import hubs.validators as validators
+
+@panel(title='Sticky Note', klass="panel-info")
+@argument(name="text", default="Lorem ipsum dolor...",
+          validator=validators.text,
+          help="Some dummy text to display.")
+def render(request, session, widget, text):
+    # TODO -- render with markdown
+    return text
diff --git a/populate.py b/populate.py
index 0398028..439a941 100644
--- a/populate.py
+++ b/populate.py
@@ -24,7 +24,12 @@ widget = hubs.models.Widget(plugin='rules', index=1,
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=2)
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='dummy', index=0, left=True)
+widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+                            _config=json.dumps({
+                                'text': 'This is a sticky note.',
+                            }))
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
 hub.widgets.append(widget)
 
 session.commit()

From 2f1b1e0f958d5501eec4644834465a2752d7366f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 16 2015 23:49:51 +0000
Subject: [PATCH 11/1001] :books:


---

diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..7a939cc
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,6 @@
+Try running it with::
+
+    $ PYTHONPATH=. python populate.py  # To create the db
+    $ PYTHONPATH=. python hubs/app.py  # To run the dev server
+
+And then navigate to http://localhost:5000/designteam

From 001068efab03bea4db00af22a841e3bc5fea754d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 17 2015 17:41:50 +0000
Subject: [PATCH 12/1001] Redirect to prototype page.


---

diff --git a/hubs/app.py b/hubs/app.py
index 031b971..52b2911 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -14,7 +14,7 @@ if 'HUBS_CONFIG' in os.environ:
 
 @app.route('/')
 def index():
-    return "hi there"
+    return flask.redirect('/designteam')  # TODO - remove this later
 
 
 @app.route('/<hub_name>')

From 232a749e0eca16bf97979695ba0e0bd7d9047c26 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 17 2015 17:42:56 +0000
Subject: [PATCH 13/1001] Whoops.  Wrong css class here.


---

diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 7f43eea..f6d2ee0 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -14,7 +14,7 @@ rules_template = jinja2.Template("""
   {% endif %}
   <p class="small-heading">group owners</p>
   {% for owner in owners %}
-    <span><img class="circle" src="{{owners[owner]}}"/> {{owner}}</span>
+    <span><img class="img-circle" src="{{owners[owner]}}"/> {{owner}}</span>
   {% endfor %}
 </div>
 <style>

From 350e7d4748910672e44aed287ad90f2989b8c932 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 19 2015 20:08:28 +0000
Subject: [PATCH 14/1001] Executable.


---

diff --git a/populate.py b/populate.py
old mode 100644
new mode 100755
index 439a941..2c44efc
--- a/populate.py
+++ b/populate.py
@@ -1,3 +1,6 @@
+#!/usr/bin/env python
+""" Populate the hubs db with some dev data. """
+
 import json
 import os
 

From d29a3456defcb9e5543028be708e26955a0a16a3 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 21 2015 15:52:39 +0000
Subject: [PATCH 15/1001] Add requirements.txt.


---

diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..34ba9b0
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+flask
+sqlalchemy
+fedmsg

From 9712b3d398512ae0f94fe53bec5a29f1299c9a70 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 21 2015 15:59:07 +0000
Subject: [PATCH 16/1001] PEP8.


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index d981ba1..04e1fc5 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -3,7 +3,8 @@ import functools
 import hashlib
 import urllib
 
-Argument = collections.namedtuple('Argument', ('name', 'default', 'validator', 'help'))
+Argument = collections.namedtuple(
+    'Argument', ('name', 'default', 'validator', 'help'))
 
 
 def argument(name, default, validator, help):

From e2b803d463900cc41560261ab12382af67ea72eb Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 21 2015 16:21:59 +0000
Subject: [PATCH 17/1001] Rework the widget API to separate data and presentation.


---

diff --git a/hubs/models.py b/hubs/models.py
index c8c006a..660bb9f 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -150,8 +150,8 @@ class Widget(BASE):
         }
 
     def render(self, request, session):
-        plugin = widgets.registry[self.plugin]
-        return plugin(request, session, self, **self.config)
+        module = widgets.registry[self.plugin]
+        return widgets.render(module, request, session, self, **self.config)
 
 
 class User(BASE):
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 2e495f7..1c83230 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -4,8 +4,50 @@ import rules
 import sticky
 
 registry = {
-    'dummy': dummy.render,
-    'stats': stats.render,
-    'rules': rules.render,
-    'sticky': sticky.render,
+    'dummy': dummy,
+    'stats': stats,
+    'rules': rules,
+    'sticky': sticky,
 }
+
+
+def validate_registry(registry):
+    """ Ensure that the widgets in the registry have the bits they need.
+    - Check that a template is available and has a render callable.
+    - Look for a data function, etc..
+    - Ensure it has the right number of arguments, do things to help debugging.
+    """
+    raise NotImplementedError()
+    for name, module in registry.items():
+        pass
+
+def prepare_registry(registry):
+    """ Do things ahead of time that we can to the registry.
+    - Wrap a cache layer around the data functions.
+    - Wrap any chrome around the render functions.
+    """
+    for name, module in registry.items():
+        # Wrap chrome around the render function
+        module.render = module.template.render
+        if hasattr(module, 'chrome'):
+            module.render = module.chrome(module.render)
+
+        # TODO -- wrap a cache layer around the data functions
+        #         do this only if the module provides a cache invalidator
+        #         and warn in the logs if there's not one present?
+
+# TODO -- actually call this
+#validate_registry(registry)
+prepare_registry(registry)
+
+def render(module, *args, **kwargs):
+    """ Main API entry point.
+
+    Call this to render a widget into HTML
+    """
+
+    # The API returns exactly this data.  Shared cache
+    data = module.data(*args, **kwargs)
+
+    # Use the API data to fill out a template, and potentially decorate it.
+    return module.render(**data)
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index a35e9d2..68119b5 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,11 +1,16 @@
 from chrome import panel
 from base import argument
 
+import jinja2
+
 import hubs.validators as validators
 
-@panel("This is a dummy widget")
+
+template = jinja2.Template("{{text}}")
+chrome = panel("This is a dummy widget")
+
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
           help="Some dummy text to display.")
-def render(request, session, widget, text):
-    return text
+def data(request, session, widget, text):
+    return dict(text=text)
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index f6d2ee0..2a6a632 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -6,7 +6,8 @@ from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument, avatar
 from hubs import validators
 
-rules_template = jinja2.Template("""
+chrome = panel()
+template = jinja2.Template("""
 <div class="rules-container">
   {% if link %}
   <p class="small-heading">community rules</p>
@@ -35,11 +36,10 @@ rules_template = jinja2.Template("""
 </style>
 """)
 
-@panel()
 @argument(name='link', default=None,
           validator=validators.link,
           help="Link to the community rules and guidelines")
-def render(request, session, widget, link):
+def data(request, session, widget, link):
     owners = widget.hub.owners
     owners = ordereddict([(o, avatar(o)) for o in owners])
-    return rules_template.render(owners=owners, link=link)
+    return dict(owners=owners, link=link)
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index d7a1609..c5dbea0 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,36 +1,38 @@
 from chrome import panel
 
-stats_template = """
+import jinja2
+
+chrome = panel()
+template = jinja2.Template("""
 <div class="stats-container">
   <table class="stats-table">
     <tr><th>Members</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{members}</td><td>{subscribers}</td></tr>
+    <tr class="text-info"><td>{{members}}</td><td>{{subscribers}}</td></tr>
   </table>
   <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
 </div>
 <style>
-  .stats-table {{
+  .stats-table {
     width: 180px
     padding: 0px;
     margin: 0px;
     display: inline-block;
-  }}
-  .stats-table th {{
+  }
+  .stats-table th {
     text-transform: uppercase;
     font-size: 80%;
     padding-right: 10px;
     color: #797a7c;
-  }}
-  .stats-table td {{
+  }
+  .stats-table td {
     font-size: 32pt;
-  }}
-
+  }
 </style>
-"""
+""")
+
 
-@panel()
-def render(request, session, widget):
-    return stats_template.format(
+def data(request, session, widget):
+    return dict(
         members=len(widget.hub.members),
         subscribers=len(widget.hub.subscribers),
     )
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 2246ae1..416fd0e 100644
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -1,12 +1,17 @@
 from chrome import panel
 from base import argument
 
+import jinja2
+
 import hubs.validators as validators
 
-@panel(title='Sticky Note', klass="panel-info")
+template = jinja2.Template("{{text}}")
+
+chrome = panel(title='Sticky Note', klass="panel-info")
+
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
           help="Some dummy text to display.")
-def render(request, session, widget, text):
+def data(request, session, widget, text):
     # TODO -- render with markdown
-    return text
+    return dict(text=text)

From bbdc99a2902da8235434c126dda74743aea8bc91 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 21 2015 16:43:26 +0000
Subject: [PATCH 18/1001] Provide a 302 to link to the source code for widgets.


---

diff --git a/hubs/app.py b/hubs/app.py
index 52b2911..d6f5510 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -7,6 +7,12 @@ import models
 app = flask.Flask(__name__)
 
 
+# TODO - put this in config so we can migrate to pagure
+# TODO - instead of 'develop', use the version from pkg_resources to figure out
+#        the right tag to link people to.  AGPL ftw.
+SOURCE_URL = 'https://github.com/ralphbean/fedora-hubs-prototype/blob/develop'
+
+
 app.config.from_object('default_config')
 if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
@@ -17,16 +23,58 @@ def index():
     return flask.redirect('/designteam')  # TODO - remove this later
 
 
-@app.route('/<hub_name>')
-@app.route('/<hub_name>/')
-def hubs_view(hub_name):
+@app.route('/<name>')
+@app.route('/<name>/')
+def hub(name):
     session = models.init(app.config['DB_URL'])
     hub = session.query(models.Hub)\
-        .filter(models.Hub.name==hub_name)\
+        .filter(models.Hub.name==name)\
         .first()
 
+    if not hub:
+        flask.abort(404)
+
     return flask.render_template('hubs.html', hub=hub, session=session)
 
 
+def get_widget(session, hub, idx):
+    try:
+        idx = int(idx)
+    except TypeError:
+        flask.abort(404)
+
+    hub = session.query(models.Hub)\
+        .filter(models.Hub.name==hub)\
+        .first()
+
+    if not hub:
+        flask.abort(404)
+
+    for widget in hub.widgets:
+        if widget.idx == idx:
+            return widget
+
+    flask.abort(404)
+
+
+@app.route('/<hub>/<idx>')
+@app.route('/<hub>/<idx>/')
+def widget(hub, idx):
+    session = models.init(app.config['DB_URL'])
+    widget = get_widget(session, hub, idx)
+    return widget.render(session, hub, idx)
+
+
+@app.route('/<hub>/<idx>/source')
+@app.route('/<hub>/<idx>/source/')
+def widget_source(hub, idx):
+    from hubs.widgets import registry
+    base = '/hubs/'
+    session = models.init(app.config['DB_URL'])
+    widget = get_widget(session, hub, idx)
+    fname = base + registry[widget.plugin].__file__.split(base, 1)[1][:-1]
+    return flask.redirect(SOURCE_URL + fname)
+
+
 if __name__ == '__main__':
     app.run(debug=True)

From 1a3db3cf129d76fb911964dc22f4d924f182dfa9 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 21 2015 17:31:59 +0000
Subject: [PATCH 19/1001] Give every widget a link to its own source code.


---

diff --git a/hubs/app.py b/hubs/app.py
index d6f5510..4e1e666 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -65,14 +65,12 @@ def widget(hub, idx):
     return widget.render(session, hub, idx)
 
 
-@app.route('/<hub>/<idx>/source')
-@app.route('/<hub>/<idx>/source/')
-def widget_source(hub, idx):
+@app.route('/source/<name>')
+@app.route('/source/<name>/')
+def widget_source(name):
     from hubs.widgets import registry
     base = '/hubs/'
-    session = models.init(app.config['DB_URL'])
-    widget = get_widget(session, hub, idx)
-    fname = base + registry[widget.plugin].__file__.split(base, 1)[1][:-1]
+    fname = base + registry[name].__file__.split(base, 1)[1][:-1]
     return flask.redirect(SOURCE_URL + fname)
 
 
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index c2a8247..a8e2810 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -27,6 +27,10 @@
       margin-top: 0px;
       margin-bottom: 0px;
     }
+    .widget-buttons {
+      padding: 5px;
+      /* TODO -- lots more nice styling here... */
+    }
   </style>
 </head>
 <body>
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 1c83230..30fc102 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -3,6 +3,10 @@ import stats
 import rules
 import sticky
 
+from base import AGPLv3
+
+import flask
+
 registry = {
     'dummy': dummy,
     'stats': stats,
@@ -32,6 +36,9 @@ def prepare_registry(registry):
         if hasattr(module, 'chrome'):
             module.render = module.chrome(module.render)
 
+        # Put source links in all API results
+        module.data = AGPLv3(name)(module.data)
+
         # TODO -- wrap a cache layer around the data functions
         #         do this only if the module provides a cache invalidator
         #         and warn in the logs if there's not one present?
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 04e1fc5..de78e5e 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -3,6 +3,8 @@ import functools
 import hashlib
 import urllib
 
+import flask
+
 Argument = collections.namedtuple(
     'Argument', ('name', 'default', 'validator', 'help'))
 
@@ -17,6 +19,19 @@ def argument(name, default, validator, help):
         return inner
     return decorator
 
+
+def AGPLv3(name):
+    def decorator(func):
+        @wraps(func)
+        def inner(*args, **kwargs):
+            result = func(*args, **kwargs)
+            result['source_url'] = flask.url_for('widget_source', name=name)
+            return result
+
+        return inner
+    return decorator
+
+
 def wraps(original):
     @functools.wraps(original)
     def decorator(subsequent):
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 1f8d399..07c4745 100644
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -1,21 +1,28 @@
 from base import wraps
 
-_panel_template = """
-<div class="panel {klass}">
-  {heading}
+import jinja2
+
+_panel_template = jinja2.Template("""
+<div class="panel {{klass}}">
+  {{heading}}
+  <div class="pull-right widget-buttons">
+    <!-- the AGPLv3 wrapper puts the source url in all responses -->
+    <a href="{{source_url}}"><span class="glyphicon glyphicon-eye-open"></span></a>
+    <a href="#"><span class="glyphicon glyphicon-edit"></span></a>
+  </div>
   <div class="panel-body">
-    {content}
+    {{content}}
   </div> <!-- end panel-body -->
 </div> <!-- end panel -->
-"""
+""")
 
-_panel_heading_template = """
+_panel_heading_template = jinja2.Template("""
   <div class="panel-heading">
     <h3 class="panel-title">
-      {title}
+      {{title}}
     </h3>
   </div> <!-- end panel-heading -->
-"""
+""")
 
 
 def panel(title=None, klass="panel-default"):
@@ -24,8 +31,12 @@ def panel(title=None, klass="panel-default"):
         def inner(*args, **kwargs):
             heading = ''
             if title:
-                heading = _panel_heading_template.format(title=title)
+                heading = _panel_heading_template.render(title=title)
             content = func(*args, **kwargs)
-            return _panel_template.format(content=content, heading=heading, klass=klass)
+            return _panel_template.render(
+                content=content,
+                heading=heading,
+                klass=klass,
+                **kwargs)
         return inner
     return decorator

From 741d748a83a75310d1fcee671550c35030eb417d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 21 2015 18:03:56 +0000
Subject: [PATCH 20/1001] Expose JSON data for widgets.


---

diff --git a/hubs/app.py b/hubs/app.py
index 4e1e666..e9510f9 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -59,10 +59,21 @@ def get_widget(session, hub, idx):
 
 @app.route('/<hub>/<idx>')
 @app.route('/<hub>/<idx>/')
-def widget(hub, idx):
+def widget_render(hub, idx):
     session = models.init(app.config['DB_URL'])
     widget = get_widget(session, hub, idx)
-    return widget.render(session, hub, idx)
+    return widget.render(flask.request, session)
+
+
+@app.route('/<hub>/<idx>/json')
+@app.route('/<hub>/<idx>/json/')
+def widget_json(hub, idx):
+    session = models.init(app.config['DB_URL'])
+    widget = get_widget(session, hub, idx)
+    from hubs.widgets import registry
+    module = registry[widget.plugin]
+    data = module.data(flask.request, session, widget, **widget.config)
+    return flask.jsonify(data)
 
 
 @app.route('/source/<name>')

From d92aa191425f812ad1b13b27b27e8c3caa04cbc5 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 21 2015 21:00:51 +0000
Subject: [PATCH 21/1001] Instructions for deps.  Fixes #1.


---

diff --git a/README.rst b/README.rst
index 7a939cc..6c00282 100644
--- a/README.rst
+++ b/README.rst
@@ -1,3 +1,15 @@
+Hacking
+-------
+
+Setup a python virtualenv::
+
+    $ sudo yum install python-virtualenvwrapper
+    $ mkvirtualenv hubs
+
+Install the dependencies from PyPI::
+
+    $ pip install -r requirements.txt
+
 Try running it with::
 
     $ PYTHONPATH=. python populate.py  # To create the db
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 30fc102..b030fd9 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -47,14 +47,15 @@ def prepare_registry(registry):
 #validate_registry(registry)
 prepare_registry(registry)
 
-def render(module, *args, **kwargs):
+def render(module, request, session, widget, *args, **kwargs):
     """ Main API entry point.
 
     Call this to render a widget into HTML
     """
 
+
     # The API returns exactly this data.  Shared cache
-    data = module.data(*args, **kwargs)
+    data = module.data(request, session, widget, *args, **kwargs)
 
     # Use the API data to fill out a template, and potentially decorate it.
     return module.render(**data)

From 076abc243d6c28956bca8a6fbbb10142587eed06 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 21 2015 21:05:54 +0000
Subject: [PATCH 22/1001] Remove unused import.


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index b030fd9..8a74f2a 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -5,8 +5,6 @@ import sticky
 
 from base import AGPLv3
 
-import flask
-
 registry = {
     'dummy': dummy,
     'stats': stats,

From 10511e563d51de7834ea5049c2286b5834cbab8e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 21 2015 21:19:23 +0000
Subject: [PATCH 23/1001] Add some internal design notes.


---

diff --git a/README.rst b/README.rst
index 6c00282..b2c4bb4 100644
--- a/README.rst
+++ b/README.rst
@@ -16,3 +16,40 @@ Try running it with::
     $ PYTHONPATH=. python hubs/app.py  # To run the dev server
 
 And then navigate to http://localhost:5000/designteam
+
+Internal design
+---------------
+
+There's no authn or user information at all currently.  There are only:
+
+- widgets
+- hubs (which are just collections of widgets)
+
+How things are currently (they don't have to stay this way):
+
+You write a new widget in the ``hubs/widgets/`` directory and must declare it
+in the registry dict in ``hubs/widgets/__init__.py``.
+
+In order to be valid, a widget must have:
+
+- A ``data(request, session, widgets, **kwargs)`` function that returns a
+  jsonifiable dict of data.  This will get cached -- more on that later.
+- A ``template`` object that is a jinja2 template for that widget.
+- Optionally, a ``chrome`` decorator.
+
+This isn't implemented yet, but they're going to need:
+
+- A ``invalidate(session, message)`` function that will be used to
+  *potentially* invalidate the widget's cache. That function will get called by
+  a backend daemon listening for fedmsg messages so when you update your group
+  memberships in FAS, a fedmsg message hits the fedora-hubs backend and it
+  nukes/refreshes a lookup value in memcached (or some other store).
+
+Furthermore:
+
+- The template per-widget is currently held and rendered *server-side* with
+  jinja2.  This is how all our apps do it, more or less.
+
+  We might want to consider using handlebars.js for our templates instead and
+  rendering all of the widgets asynchronously on the client.  It could be cool,
+  but is new-ground for our team.

From bc0ef8bc46e0faadafe26ca81b940ec8e601a412 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 13:22:27 +0000
Subject: [PATCH 24/1001] Be careful for widgets that have no arguments.


---

diff --git a/hubs/models.py b/hubs/models.py
index 660bb9f..352854e 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -118,11 +118,8 @@ class Hub(BASE):
 def _config_default(context):
     plugin_name = context.current_parameters['plugin']
     plugin = widgets.registry[plugin_name]
-
-    print plugin.widget_arguments
-    return json.dumps(dict([
-        (arg.name, arg.default) for arg in plugin.widget_arguments
-    ]))
+    arguments = getattr(plugin, 'widget_arguments', [])
+    return json.dumps(dict([(arg.name, arg.default) for arg in arguments]))
 
 
 class Widget(BASE):

From 1da4a22d9d3fed8eabfbb1ccedc64a47c19b8fef Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 14:07:10 +0000
Subject: [PATCH 25/1001] Get hubs working on python3 as well as python2.


---

diff --git a/hubs/models.py b/hubs/models.py
index 352854e..6d328de 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -36,7 +36,7 @@ from sqlalchemy.orm import backref
 import fedmsg
 import fedmsg.utils
 
-import widgets
+import hubs.widgets
 
 
 class HubsBase(object):
@@ -117,8 +117,8 @@ class Hub(BASE):
 
 def _config_default(context):
     plugin_name = context.current_parameters['plugin']
-    plugin = widgets.registry[plugin_name]
-    arguments = getattr(plugin, 'widget_arguments', [])
+    plugin = hubs.widgets.registry[plugin_name]
+    arguments = getattr(plugin.data, 'widget_arguments', [])
     return json.dumps(dict([(arg.name, arg.default) for arg in arguments]))
 
 
@@ -147,8 +147,9 @@ class Widget(BASE):
         }
 
     def render(self, request, session):
-        module = widgets.registry[self.plugin]
-        return widgets.render(module, request, session, self, **self.config)
+        module = hubs.widgets.registry[self.plugin]
+        render = hubs.widgets.render
+        return render(module, request, session, self, **self.config)
 
 
 class User(BASE):
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 8a74f2a..420c0a3 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -1,9 +1,9 @@
-import dummy
-import stats
-import rules
-import sticky
+from hubs.widgets import dummy
+from hubs.widgets import stats
+from hubs.widgets import rules
+from hubs.widgets import sticky
 
-from base import AGPLv3
+from hubs.widgets.base import AGPLv3
 
 registry = {
     'dummy': dummy,
@@ -15,16 +15,31 @@ registry = {
 
 def validate_registry(registry):
     """ Ensure that the widgets in the registry have the bits they need.
+
     - Check that a template is available and has a render callable.
     - Look for a data function, etc..
-    - Ensure it has the right number of arguments, do things to help debugging.
     """
-    raise NotImplementedError()
     for name, module in registry.items():
-        pass
+        if not hasattr(module, 'template'):
+            raise AttributeError('%r has no "template"' % module)
+        if not hasattr(module.template, 'render'):
+            raise AttributeError('%r\'s template has no "render"' % module)
+        if not callable(module.template.render):
+            raise TypeError('%r\'s template.render not callable' % module)
+
+        if not hasattr(module, 'data'):
+            raise AttributeError('%r has not "data" function' % module)
+        if not callable(module.data):
+            raise TypeError('%r\'s "data" is not callable' % module)
+
+        if hasattr(module, 'chrome'):
+            if not callable(module.chrome):
+                raise TypeError('%r\'s "chrome" is not callable' % module)
+
 
 def prepare_registry(registry):
     """ Do things ahead of time that we can to the registry.
+
     - Wrap a cache layer around the data functions.
     - Wrap any chrome around the render functions.
     """
@@ -41,8 +56,7 @@ def prepare_registry(registry):
         #         do this only if the module provides a cache invalidator
         #         and warn in the logs if there's not one present?
 
-# TODO -- actually call this
-#validate_registry(registry)
+validate_registry(registry)
 prepare_registry(registry)
 
 def render(module, request, session, widget, *args, **kwargs):
@@ -50,8 +64,6 @@ def render(module, request, session, widget, *args, **kwargs):
 
     Call this to render a widget into HTML
     """
-
-
     # The API returns exactly this data.  Shared cache
     data = module.data(request, session, widget, *args, **kwargs)
 
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index de78e5e..410bab5 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -1,9 +1,9 @@
 import collections
 import functools
 import hashlib
-import urllib
 
 import flask
+from six.moves import urllib_parse
 
 Argument = collections.namedtuple(
     'Argument', ('name', 'default', 'validator', 'help'))
@@ -43,7 +43,7 @@ def wraps(original):
 
 def avatar(username, size=32):
     openid = 'http://%s.id.fedoraproject.org/' % username
-    query = urllib.urlencode({'s': size, 'd': 'retro'})
-    hash = hashlib.sha256(openid).hexdigest()
+    query = urllib_parse.urlencode({'s': size, 'd': 'retro'})
+    hash = hashlib.sha256(openid.encode('utf-8')).hexdigest()
     template = "https://seccdn.libravatar.org/avatar/%s?%s"
     return template % (hash, query)
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 07c4745..4ea42c6 100644
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -1,4 +1,4 @@
-from base import wraps
+from hubs.widgets.base import wraps
 
 import jinja2
 
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index 68119b5..fb44797 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,5 +1,5 @@
-from chrome import panel
-from base import argument
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import argument
 
 import jinja2
 
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index c5dbea0..a181453 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,4 +1,4 @@
-from chrome import panel
+from hubs.widgets.chrome import panel
 
 import jinja2
 
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 416fd0e..60da776 100644
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -1,5 +1,5 @@
-from chrome import panel
-from base import argument
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import argument
 
 import jinja2
 

From e96104f01241d055e14584c9a83ee3bf5a645e7d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 14:08:01 +0000
Subject: [PATCH 26/1001] Mention python3 in the readme.


---

diff --git a/README.rst b/README.rst
index b2c4bb4..8ae88f3 100644
--- a/README.rst
+++ b/README.rst
@@ -1,10 +1,13 @@
 Hacking
 -------
 
+Hubs should work on python2 **and** python3, so let's default to python3 and
+see how that goes.
+
 Setup a python virtualenv::
 
     $ sudo yum install python-virtualenvwrapper
-    $ mkvirtualenv hubs
+    $ mkvirtualenv --python=$(which python3) hubs
 
 Install the dependencies from PyPI::
 
@@ -12,8 +15,8 @@ Install the dependencies from PyPI::
 
 Try running it with::
 
-    $ PYTHONPATH=. python populate.py  # To create the db
-    $ PYTHONPATH=. python hubs/app.py  # To run the dev server
+    $ PYTHONPATH=. python3 populate.py  # To create the db
+    $ PYTHONPATH=. python3 hubs/app.py  # To run the dev server
 
 And then navigate to http://localhost:5000/designteam
 

From a4fdd2222a7703799b3ff93b46c5dbc9b096770f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 14:29:39 +0000
Subject: [PATCH 27/1001] Add caching around the API.


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 420c0a3..832c936 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -3,7 +3,7 @@ from hubs.widgets import stats
 from hubs.widgets import rules
 from hubs.widgets import sticky
 
-from hubs.widgets.base import AGPLv3
+from hubs.widgets.base import AGPLv3, smartcache
 
 registry = {
     'dummy': dummy,
@@ -52,9 +52,9 @@ def prepare_registry(registry):
         # Put source links in all API results
         module.data = AGPLv3(name)(module.data)
 
-        # TODO -- wrap a cache layer around the data functions
-        #         do this only if the module provides a cache invalidator
-        #         and warn in the logs if there's not one present?
+        # Wrap the data functions in a cache layer to be invalidated by fedmsg
+        module.data = smartcache(module)(module.data)
+
 
 validate_registry(registry)
 prepare_registry(registry)
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 410bab5..9519079 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -1,9 +1,23 @@
 import collections
 import functools
 import hashlib
+import json
 
+import dogpile.cache
 import flask
-from six.moves import urllib_parse
+import six.moves.urllib_parse
+
+import fedmsg.config
+
+config = fedmsg.config.load_config()
+cache_defaults = {
+    "backend": "dogpile.cache.dbm",
+    "expiration_time": 1,  # Expire every 1 second, for development
+    "arguments": {"filename": "/var/tmp/fedora-hubs-cache.dbm"},
+}
+cache = dogpile.cache.make_region()
+cache.configure(**config.get('fedora-hubs.cache', cache_defaults))
+
 
 Argument = collections.namedtuple(
     'Argument', ('name', 'default', 'validator', 'help'))
@@ -32,6 +46,26 @@ def AGPLv3(name):
     return decorator
 
 
+def smartcache(module):
+    def decorator(func):
+        @wraps(func)
+        def inner(request, session, widget, *args, **kwargs):
+            key = cache_key_generator(module, args, kwargs)
+            creator = lambda: func(request, session, widget, *args, **kwargs)
+            return cache.get_or_create(key, creator)
+
+        return inner
+    return decorator
+
+
+def cache_key_generator(module, args, kwargs):
+    return "|".join([
+        module.__name__,
+        json.dumps(args),
+        json.dumps(kwargs),
+    ]).encode('utf-8')
+
+
 def wraps(original):
     @functools.wraps(original)
     def decorator(subsequent):
@@ -43,7 +77,7 @@ def wraps(original):
 
 def avatar(username, size=32):
     openid = 'http://%s.id.fedoraproject.org/' % username
-    query = urllib_parse.urlencode({'s': size, 'd': 'retro'})
+    query = six.moves.urllib_parse.urlencode({'s': size, 'd': 'retro'})
     hash = hashlib.sha256(openid.encode('utf-8')).hexdigest()
     template = "https://seccdn.libravatar.org/avatar/%s?%s"
     return template % (hash, query)
diff --git a/requirements.txt b/requirements.txt
index 34ba9b0..0f26348 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
 flask
 sqlalchemy
 fedmsg
+dogpile.cache

From 77fce24dafc7bb856c071e3193e6f4f47900849a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 14:47:35 +0000
Subject: [PATCH 28/1001] Load page fragments asynchronously.


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index a8e2810..d96958c 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -1,7 +1,6 @@
 <html>
 <head>
   <title>{{ hub.name }}</title>
-  <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <style>
     body {
       background-color: #d1d3d4;
@@ -44,20 +43,34 @@
   <div class="row">
     <div class="col-md-{{ hub.left_width }}">
       {% for widget in hub.left_widgets %}
-      <div class="row">
-        {{ widget.render(request, session) | safe }}
-      </div>
+      <div id="widget-{{ widget.idx }}" class="row"></div>
       {% endfor %}
     </div>
 
     <div class="col-md-{{ hub.right_width }}">
       {% for widget in hub.right_widgets %}
-      <div class="row">
-        {{ widget.render(request, session) | safe }}
-      </div>
+      <div id="widget-{{ widget.idx }}" class="row"></div>
       {% endfor %}
     </div>
   </div>
 </div>
-</body>
-</html>
+
+<link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
+<script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+<script>
+var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
+$.each(widgets, function(i, widget) {
+    $.ajax({
+      url: widget,
+      dataType: 'html',
+      success: function(html) {
+        $('#widget-' + widget).html(html);
+      },
+      error: function() {
+        console.log('error');
+        console.trace();
+      },
+    });
+});
+</script>
+</body></html>

From cfc45f323f7eb15d8eb6367740cb4facd21369d8 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 14:57:26 +0000
Subject: [PATCH 29/1001] Merge pull request #2 from ralphbean/feature/fragments


Load page fragments asynchronously.
---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index a8e2810..d96958c 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -1,7 +1,6 @@
 <html>
 <head>
   <title>{{ hub.name }}</title>
-  <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <style>
     body {
       background-color: #d1d3d4;
@@ -44,20 +43,34 @@
   <div class="row">
     <div class="col-md-{{ hub.left_width }}">
       {% for widget in hub.left_widgets %}
-      <div class="row">
-        {{ widget.render(request, session) | safe }}
-      </div>
+      <div id="widget-{{ widget.idx }}" class="row"></div>
       {% endfor %}
     </div>
 
     <div class="col-md-{{ hub.right_width }}">
       {% for widget in hub.right_widgets %}
-      <div class="row">
-        {{ widget.render(request, session) | safe }}
-      </div>
+      <div id="widget-{{ widget.idx }}" class="row"></div>
       {% endfor %}
     </div>
   </div>
 </div>
-</body>
-</html>
+
+<link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
+<script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+<script>
+var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
+$.each(widgets, function(i, widget) {
+    $.ajax({
+      url: widget,
+      dataType: 'html',
+      success: function(html) {
+        $('#widget-' + widget).html(html);
+      },
+      error: function() {
+        console.log('error');
+        console.trace();
+      },
+    });
+});
+</script>
+</body></html>

From 4de1edca6b9ee61a73bb6eaf93d238b63d880878 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 15:09:18 +0000
Subject: [PATCH 30/1001] Gunicorn!


---

diff --git a/README.rst b/README.rst
index 8ae88f3..02deea9 100644
--- a/README.rst
+++ b/README.rst
@@ -20,6 +20,11 @@ Try running it with::
 
 And then navigate to http://localhost:5000/designteam
 
+If you want to test it with 8 worker threads, try ``gunicorn``::
+
+    $ pip install gunicorn
+    $ gunicorn -w 8 hubs.app:app
+
 Internal design
 ---------------
 
diff --git a/hubs/app.py b/hubs/app.py
index e9510f9..0c4d996 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -13,7 +13,7 @@ app = flask.Flask(__name__)
 SOURCE_URL = 'https://github.com/ralphbean/fedora-hubs-prototype/blob/develop'
 
 
-app.config.from_object('default_config')
+app.config.from_object('hubs.default_config')
 if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
 

From 5e22adf3178238576da1e240059b3b8d89c65e6c Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 15:10:45 +0000
Subject: [PATCH 31/1001] Add a fedmsg config to get things working again.


---

diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
new file mode 100644
index 0000000..a405684
--- /dev/null
+++ b/fedmsg.d/testconfig.py
@@ -0,0 +1,4 @@
+config = {
+    'endpoints': {
+    },
+}

From 2c6fe8948e3b9ebac6949f1ba228759c4ad30966 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 16:25:45 +0000
Subject: [PATCH 32/1001] Make widgets artificially slow for development.


---

diff --git a/hubs/app.py b/hubs/app.py
index 0c4d996..629b0ea 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -62,6 +62,13 @@ def get_widget(session, hub, idx):
 def widget_render(hub, idx):
     session = models.init(app.config['DB_URL'])
     widget = get_widget(session, hub, idx)
+
+    # Make this artificially slow for development...
+    import random, time
+    s = (random.random() * 3) + 1
+    print(widget.plugin, "sleeping artificially for", s)
+    time.sleep(s)
+
     return widget.render(flask.request, session)
 
 

From 8a0ff0072827d2b51adc6f9e8d3cd3d40ce96ce1 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 22 2015 16:26:18 +0000
Subject: [PATCH 33/1001] Make widgets slide in as they're ready.


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index d96958c..f5935e5 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -30,6 +30,18 @@
       padding: 5px;
       /* TODO -- lots more nice styling here... */
     }
+    .panel {
+      visibility: hidden;
+      max-height: 0px;
+      overflow: hidden;
+      transition: max-height 0.4s;
+    }
+
+    .panel-visible {
+      visibility: visible;
+      max-height: 400px;
+    }
+
   </style>
 </head>
 <body>
@@ -65,6 +77,9 @@ $.each(widgets, function(i, widget) {
       dataType: 'html',
       success: function(html) {
         $('#widget-' + widget).html(html);
+        setTimeout(function() {
+          $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
+        }, 100);
       },
       error: function() {
         console.log('error');

From a1ce87f1b232095e313135f221563fbe0397b0f1 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 23 2015 12:16:20 +0000
Subject: [PATCH 34/1001] Thinking about EventSource.


---

diff --git a/README.rst b/README.rst
index 02deea9..e57cc71 100644
--- a/README.rst
+++ b/README.rst
@@ -53,7 +53,7 @@ This isn't implemented yet, but they're going to need:
   memberships in FAS, a fedmsg message hits the fedora-hubs backend and it
   nukes/refreshes a lookup value in memcached (or some other store).
 
-Furthermore:
+Furthermore, a proposal:
 
 - The template per-widget is currently held and rendered *server-side* with
   jinja2.  This is how all our apps do it, more or less.
@@ -61,3 +61,24 @@ Furthermore:
   We might want to consider using handlebars.js for our templates instead and
   rendering all of the widgets asynchronously on the client.  It could be cool,
   but is new-ground for our team.
+
+Still more proposals:
+
+- We could re-use the existing websocket service we have at
+  wss://hub.fedoraproject.org:9939 but it has some problems:
+- It is very inflexible.  You can subscribe to fedmsg *topics* and then you
+  receive the firehose of those topics. For a widget, we already have to write
+  a 'cache invalidation' function that listens for messages and then somehow
+  knows to invalidate the cache *for a widget* based on some of those messages.
+  If we re-used the firehose on the client, we would have to write that
+  function *twice* for *each widget*, once in python to invalidate the server's
+  memcached cache when a fedmsg message comes in and once in javascript to tell
+  the client to reload and redraw a oprtion of itself when a fedmsg comes in
+  over the websocket firehose.
+- Instead, let's give fedora-hubs its own *widget-specific* `EventSource
+  <https://developer.mozilla.org/en-US/docs/Web/API/EventSource>`_ server that
+  we tie in to the server-side cache-invalidation backend code.  I.e., when a
+  message comes into the backend, it runs all the cache invalidation checkers
+  to see which widgets' caches should be refreshed, and once they are refreshed
+  we can emit events over EventSource to tell only *those* widgets on any
+  connected clients to redraw themselves.

From be5f689b4a5cb1585e82880ffafb4ab0a8e4014a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 26 2015 19:14:32 +0000
Subject: [PATCH 35/1001] A diagram.


---

diff --git a/docs/diagram.png b/docs/diagram.png
new file mode 100644
index 0000000..be53810
Binary files /dev/null and b/docs/diagram.png differ
diff --git a/docs/diagram.txt b/docs/diagram.txt
new file mode 100644
index 0000000..ddae311
--- /dev/null
+++ b/docs/diagram.txt
@@ -0,0 +1,27 @@
+                                                     push events to clients             +-------------------------+
+                                                     as they occur                      | web client              |
+                                            +------------------------------------------>| (built from HTML and JS |
+                                            |                                           | served by the wsgi app) |
+                                            |                                           +-------------------------+
+                                            |                                                       ^
+                                            |                                                       |
+                        +--+--------------------+---+                                               | initial page load
+                        |  | EventSource server |   |     /-----------------------+                 | and ajax requests
+                        |  |                    |   |     |{s} memcached          |                 |
+                        |  |                    |   |     |  (we store the data   |                 |
+                        |  +--------------------+   |     |  for widgets here     |     +--------------------------+
+                        |                           |     |  and rebuild it       |---->|                          |
+                        |                           |---->|  as necessary)        |<----|                          |
+                        | hubs backend              |     +-----------------------/     |  hubs wsgi app           |
+                        | (a fedmsg-hub daemon      |                                   |  (the frontend that      |
+----------------------->| with a FedoraHubsConsumer |                                   |  serves what the users   |
+     ^  fedmsg          | plugin)                   |     +-----------------------+     |  see)                    |
+     |  (fas changes,   |                           |<----|{s} postgres           |<----|                          |
+     |  trac tickets,   |                           |     |  (we store the config |     +--------------------------+
+     |  etc...)         +---------------------------+     |  for widgets/hubs     |             |
+     |                                                    |  here)                |             |
+     |                                                    +-----------------------+             |
+     |                                                                                          |
+     |                                                                                          |
+     +------------------------------------------------------------------------------------------+
+                            config changes to hubs/widgets, via fedmsg

From 7917b1bbb1982aace58c66eb34a95c361c662826 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 26 2015 19:16:40 +0000
Subject: [PATCH 36/1001] Try displaying the diagram in the readme.


---

diff --git a/README.rst b/README.rst
index e57cc71..9c09417 100644
--- a/README.rst
+++ b/README.rst
@@ -82,3 +82,12 @@ Still more proposals:
   to see which widgets' caches should be refreshed, and once they are refreshed
   we can emit events over EventSource to tell only *those* widgets on any
   connected clients to redraw themselves.
+
+A picture is worth...
+---------------------
+
+.. figure:: fedora-hubs-prototype/raw/develop/docs/diagram.png
+   :scale: 50 %
+   :alt: A diagram of component interactions
+
+   A diagram of component interactions

From 548363182a5c25b53ad7ca87ceb62dfa55953602 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 26 2015 19:17:45 +0000
Subject: [PATCH 37/1001] Fully specify the url.


---

diff --git a/README.rst b/README.rst
index 9c09417..eeaf8b0 100644
--- a/README.rst
+++ b/README.rst
@@ -86,7 +86,7 @@ Still more proposals:
 A picture is worth...
 ---------------------
 
-.. figure:: fedora-hubs-prototype/raw/develop/docs/diagram.png
+.. figure:: https://raw.githubusercontent.com/ralphbean/fedora-hubs-prototype/develop/docs/diagram.png
    :scale: 50 %
    :alt: A diagram of component interactions
 

From 5b94f8c40784507f36d57ba2d03f39e1aa53a9bf Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 26 2015 19:42:35 +0000
Subject: [PATCH 38/1001] Add another interaction to the diagram.


---

diff --git a/docs/diagram.png b/docs/diagram.png
index be53810..c20d165 100644
Binary files a/docs/diagram.png and b/docs/diagram.png differ
diff --git a/docs/diagram.txt b/docs/diagram.txt
index ddae311..0e665d7 100644
--- a/docs/diagram.txt
+++ b/docs/diagram.txt
@@ -3,12 +3,12 @@
                                             +------------------------------------------>| (built from HTML and JS |
                                             |                                           | served by the wsgi app) |
                                             |                                           +-------------------------+
-                                            |                                                       ^
-                                            |                                                       |
-                        +--+--------------------+---+                                               | initial page load
-                        |  | EventSource server |   |     /-----------------------+                 | and ajax requests
-                        |  |                    |   |     |{s} memcached          |                 |
-                        |  |                    |   |     |  (we store the data   |                 |
+                                            |                                             ^                     |
+                                            |                                             |                     |
+                        +--+--------------------+---+                                     | initial page load   | configuration changes
+                        |  | EventSource server |   |     /-----------------------+       | and ajax requests   | to widgets and hubs
+                        |  |                    |   |     |{s} memcached          |       |                     |
+                        |  |                    |   |     |  (we store the data   |       |                     V
                         |  +--------------------+   |     |  for widgets here     |     +--------------------------+
                         |                           |     |  and rebuild it       |---->|                          |
                         |                           |---->|  as necessary)        |<----|                          |

From cf1b662f1a3b70ca56de1a2cf5061ab1e92918f3 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 26 2015 19:42:53 +0000
Subject: [PATCH 39/1001] Talk through a couple ways that data moves between the components.


---

diff --git a/README.rst b/README.rst
index eeaf8b0..d3a5ac6 100644
--- a/README.rst
+++ b/README.rst
@@ -86,8 +86,60 @@ Still more proposals:
 A picture is worth...
 ---------------------
 
+Aside, it became clear to me when making the diagram below that, if we use
+handlebars.js and get rid of the server-side template rendering, then 1) the
+data returned by AJAX requests at page load and 2) the data pushed by the
+EventSource server can be *the exact same data*.  It will simplify and
+streamline the responsibilities of the pieces if the backend is worried *only*
+about these per-widget JSON responses.
+
 .. figure:: https://raw.githubusercontent.com/ralphbean/fedora-hubs-prototype/develop/docs/diagram.png
    :scale: 50 %
    :alt: A diagram of component interactions
 
    A diagram of component interactions
+
+Let's talk through how data will flow through the system by asking *what
+happens when a user requsts their main hubs page*:
+
+- The user requests the page and the wsgi app responds with some barebones HTML
+  and enough javascript to get off the ground.
+- The user's browser runs javascript that *subscribes* it to the EventSource server.
+- The user's browser runs that javascript, which requests data for each of the
+  widgets defined on the page.
+- The wsgi app receives those requests and checks to see if the data for any of
+  them is *cached in memcached*.  If it is, then it is returned.  If not, then
+  the wsgi app executes the ``data(...)`` function of that widget to get the
+  response ready.  It is stuffed in memcached for later access and returned.
+- The client renders widgets as the data for each of its requests comes back.
+
+Later, what happens when a *trac ticket* is filed that should show up in some widget on their page?
+
+- The ticket is updated on fedorahosted.org and a fedmsg message is fired.
+- That is received by the hubs backend, which looks up *all* the cached
+  responses that should be invalidated by that event (there is a widget on
+  mizmo's page, threebean's page, and on the design hub that should all get
+  fresh data because of this change).
+- All of those widgets get their cached data nuked.
+- All of those widgets get their cached data rebuilt by calling ``data(...)`` on them.
+- An EventSource event is fired off for any listening clients that *new data is
+  available for widgets X, Y, and Z*.  The data is included in the EventSource
+  payload so the clients can immediately redraw without bothering to re-query
+  the wsgi app.
+
+What happens when the user navigates to the *design team* hub and
+simultaneously, an admin *changes the configuration of a widget on that page*?
+
+- Changing the configuration results in a HTTP POST to the wsgi app.
+- The configuration is changed accordingly in the postgres database.
+- A fedmsg message is fired off indicating that *the configuration for widget X
+  has changed*.
+- The wsgi app responds 200 OK to the admin.
+- Meanwhile, that fedmsg message is received by the backend which:
+- ...looks up the cache key for *widget X with the old configuration* and nukes
+  it the cached data.
+- ...looks up the cache key for *widget X with the new configuration* and
+  builds the cached data by calling ``data(...)`` on the widget.
+- An EventSource event is fired off which gets recieved by everyone looking at
+  the *design team hub*.  The widget on their pages gets redrawn with data from
+  the EventSource event.

From 33d24eff8279873a293108860e337ccb2901b95b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 26 2015 19:43:45 +0000
Subject: [PATCH 40/1001] Better language.


---

diff --git a/README.rst b/README.rst
index d3a5ac6..2365e82 100644
--- a/README.rst
+++ b/README.rst
@@ -127,7 +127,7 @@ Later, what happens when a *trac ticket* is filed that should show up in some wi
   payload so the clients can immediately redraw without bothering to re-query
   the wsgi app.
 
-What happens when the user navigates to the *design team* hub and
+What happens when the user is viewing the *design team* hub and
 simultaneously, an admin *changes the configuration of a widget on that page*?
 
 - Changing the configuration results in a HTTP POST to the wsgi app.

From d63a515b01a326748f395960bbf57411a73d6a5e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: May 26 2015 19:58:28 +0000
Subject: [PATCH 41/1001] Note that this is still a proposal and and shift the aside up a section.


---

diff --git a/README.rst b/README.rst
index 2365e82..3b380b2 100644
--- a/README.rst
+++ b/README.rst
@@ -83,15 +83,18 @@ Still more proposals:
   we can emit events over EventSource to tell only *those* widgets on any
   connected clients to redraw themselves.
 
+As an aside, it became clear to me when making the diagram in the next section
+that, if we use handlebars.js and get rid of the server-side template
+rendering, then 1) the data returned by AJAX requests at page load and 2) the
+data pushed by the EventSource server can be *the exact same data*.  It will
+simplify and streamline the responsibilities of the pieces if the backend is
+worried *only* about these per-widget JSON responses.
+
 A picture is worth...
 ---------------------
 
-Aside, it became clear to me when making the diagram below that, if we use
-handlebars.js and get rid of the server-side template rendering, then 1) the
-data returned by AJAX requests at page load and 2) the data pushed by the
-EventSource server can be *the exact same data*.  It will simplify and
-streamline the responsibilities of the pieces if the backend is worried *only*
-about these per-widget JSON responses.
+This is more "proposal" territory.  None of this is implemented, but here are
+some more details on how the whole thing should work together.
 
 .. figure:: https://raw.githubusercontent.com/ralphbean/fedora-hubs-prototype/develop/docs/diagram.png
    :scale: 50 %

From 3b93366de7cd9e020bc6544b85fca1c160fb494e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 01 2015 20:41:36 +0000
Subject: [PATCH 42/1001] Change filename to make python3 stdlib dbm module happy.


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 9519079..9bfe26e 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -13,7 +13,9 @@ config = fedmsg.config.load_config()
 cache_defaults = {
     "backend": "dogpile.cache.dbm",
     "expiration_time": 1,  # Expire every 1 second, for development
-    "arguments": {"filename": "/var/tmp/fedora-hubs-cache.dbm"},
+    "arguments": {
+        "filename": "/var/tmp/fedora-hubs-cache.db",
+    },
 }
 cache = dogpile.cache.make_region()
 cache.configure(**config.get('fedora-hubs.cache', cache_defaults))

From fff4aae5c0f12346114894edea298663c6e6aaf3 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 02 2015 19:16:05 +0000
Subject: [PATCH 43/1001] Mess around with JSON headers.


---

diff --git a/hubs/app.py b/hubs/app.py
index 629b0ea..c7432c4 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -80,7 +80,14 @@ def widget_json(hub, idx):
     from hubs.widgets import registry
     module = registry[widget.plugin]
     data = module.data(flask.request, session, widget, **widget.config)
-    return flask.jsonify(data)
+    response = flask.jsonify(data)
+
+    # We don't actually need these two headers.  Just messing around.
+    response.headers['X-fedora-hubs-hub-name'] = hub
+    response.headers['X-fedora-hubs-widget-id'] = idx
+    # TODO -- add other headers here as we decide we need them.
+
+    return response
 
 
 @app.route('/source/<name>')

From e1de5825d5bed3b18159d5997617dd2781c1f123 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 02 2015 20:09:31 +0000
Subject: [PATCH 44/1001] Take a stab at cache invalidation.


---

diff --git a/.gitignore b/.gitignore
index 0d20b64..e6e04af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 *.pyc
+*.egg*
diff --git a/README.rst b/README.rst
index 3b380b2..d5dd996 100644
--- a/README.rst
+++ b/README.rst
@@ -47,11 +47,12 @@ In order to be valid, a widget must have:
 
 This isn't implemented yet, but they're going to need:
 
-- A ``invalidate(session, message)`` function that will be used to
+- A ``should_invalidate(message, session, widget)`` function that will be used to
   *potentially* invalidate the widget's cache. That function will get called by
   a backend daemon listening for fedmsg messages so when you update your group
-  memberships in FAS, a fedmsg message hits the fedora-hubs backend and it
-  nukes/refreshes a lookup value in memcached (or some other store).
+  memberships in FAS, a fedmsg message hits the fedora-hubs backend and returns
+  True if the lookup value should be nuked/refreshed in memcached (or some
+  other store).
 
 Furthermore, a proposal:
 
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index a405684..6bfeb35 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -1,4 +1,21 @@
 config = {
+
+    'hubs.consumer.enabled': True,
+    # Production ready.
+    'hubs.sqlalchemy.uri': 'sqlite:////var/tmp/hubs.db',
+
     'endpoints': {
+        # TODO -- fill these out later...
     },
+
+    'logging': dict(
+        version=1,
+        loggers=dict(
+            hubs={
+                "level": "DEBUG",
+                "propagate": False,
+                "handlers": ["console"],
+            },
+        ),
+    ),
 }
diff --git a/hubs/app.py b/hubs/app.py
index c7432c4..7485d42 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -17,6 +17,9 @@ app.config.from_object('hubs.default_config')
 if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
 
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
+
 
 @app.route('/')
 def index():
@@ -26,7 +29,7 @@ def index():
 @app.route('/<name>')
 @app.route('/<name>/')
 def hub(name):
-    session = models.init(app.config['DB_URL'])
+    session = models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     hub = session.query(models.Hub)\
         .filter(models.Hub.name==name)\
         .first()
@@ -60,7 +63,7 @@ def get_widget(session, hub, idx):
 @app.route('/<hub>/<idx>')
 @app.route('/<hub>/<idx>/')
 def widget_render(hub, idx):
-    session = models.init(app.config['DB_URL'])
+    session = models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     widget = get_widget(session, hub, idx)
 
     # Make this artificially slow for development...
@@ -75,7 +78,7 @@ def widget_render(hub, idx):
 @app.route('/<hub>/<idx>/json')
 @app.route('/<hub>/<idx>/json/')
 def widget_json(hub, idx):
-    session = models.init(app.config['DB_URL'])
+    session = models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     widget = get_widget(session, hub, idx)
     from hubs.widgets import registry
     module = registry[widget.plugin]
diff --git a/hubs/consumer.py b/hubs/consumer.py
new file mode 100644
index 0000000..0f36f63
--- /dev/null
+++ b/hubs/consumer.py
@@ -0,0 +1,76 @@
+# The fedora hubs backend daemon
+
+import time
+import random
+
+import fedmsg.consumers
+
+import hubs.models
+
+import logging
+log = logging.getLogger("hubs")
+
+
+class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
+    topic = '*'
+    config_key = 'hubs.consumer.enabled'
+
+    def __init__(self, *args, **kwargs):
+        log.info("CacheInvalidatorExtraordinaire initializing")
+        super(CacheInvalidatorExtraordinaire, self).__init__(*args, **kwargs)
+
+        self.uri = self.hub.config.get('hubs.sqlalchemy.uri', None)
+        self.junk_suffixes = self.hub.config.get('hubs.junk_suffixes', [])
+
+        if not self.uri:
+            raise ValueError('hubs.sqlalchemy.uri must be present')
+
+        log.info("CacheInvalidatorExtraordinaire initialized")
+
+    def make_session(self):
+        return hubs.models.init(self.uri)
+
+    def consume(self, raw_msg):
+        session = self.make_session()
+        try:
+            self.work(session, raw_msg)
+            session.commit()  # transaction is committed here
+        except:
+            session.rollback()  # rolls back the transaction
+            raise
+
+    def work(self, session, raw_msg):
+        topic, msg = raw_msg['topic'], raw_msg['body']
+
+        for suffix in self.junk_suffixes:
+            if topic.endswith(suffix):
+                log.info("Dropping %r", topic)
+                return
+
+        start = time.time()
+        log.info("CacheInvalidatorExtraordinaire received %s %s",
+                  msg['msg_id'], msg['topic'])
+
+        # Begin our real work.
+        # Find which widgets should have their caches nuked and make it so.
+
+        # First, make a thread-local copy of the widgets.
+        widgets = list(session.query(hubs.models.Widget).all())
+        log.info("Comparing message against %i widgets" % len(widgets))
+
+        # Shuffle it so that not all threads step through the list in the same
+        # order.  This should cut down on competition for the dogpile lock.
+        random.shuffle(widgets)
+
+        # And do the real work of comparing every widget against the message.
+        for widget in widgets:
+            if widget.module.should_invalidate(msg, session, widget):
+                raise NotImplementedError("Invalidate the cache...")
+                raise NotImplementedError("Rebuild it.")
+
+        log.info("Done.  %0.2fs %s %s",
+                  time.time() - start, msg['msg_id'], msg['topic'])
+
+    def stop(self):
+        log.info("Cleaning up CacheInvalidatorExtraordinaire.")
+        super(CacheInvalidatorExtraordinaire, self).stop()
diff --git a/hubs/default_config.py b/hubs/default_config.py
index 3a6a0ff..e69de29 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -1,2 +0,0 @@
-# Production ready.
-DB_URL = 'sqlite:////var/tmp/hubs.db'
diff --git a/hubs/models.py b/hubs/models.py
index 6d328de..3d16fb1 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -146,10 +146,13 @@ class Widget(BASE):
             'plugin': self.plugin,
         }
 
+    @property
+    def module(self):
+        return hubs.widgets.registry[self.plugin]
+
     def render(self, request, session):
-        module = hubs.widgets.registry[self.plugin]
         render = hubs.widgets.render
-        return render(module, request, session, self, **self.config)
+        return render(self.module, request, session, self, **self.config)
 
 
 class User(BASE):
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index fb44797..9731a20 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -14,3 +14,11 @@ chrome = panel("This is a dummy widget")
           help="Some dummy text to display.")
 def data(request, session, widget, text):
     return dict(text=text)
+
+
+def should_invalidate(message, session, widget):
+    if not message['topic'].endswith('hubs.widget.update'):
+        return False
+    if message['msg']['widget']['id'] != widget.id:
+        return False
+    return True
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 2a6a632..4d682be 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -43,3 +43,15 @@ def data(request, session, widget, link):
     owners = widget.hub.owners
     owners = ordereddict([(o, avatar(o)) for o in owners])
     return dict(owners=owners, link=link)
+
+
+def should_invalidate(message, session, widget):
+    if message['topic'].endswith('hubs.widget.update'):
+        if message['msg']['widget']['id'] == widget.id:
+            return True
+
+    if message['topic'].endswith('hubs.hub.update'):
+        if message['msg']['hub']['name'] == widget.hub.name:
+            return True
+
+    return False
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index a181453..868deaa 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -36,3 +36,13 @@ def data(request, session, widget):
         members=len(widget.hub.members),
         subscribers=len(widget.hub.subscribers),
     )
+
+
+def should_invalidate(message, session, widget):
+    if message['topic'].endswith('hubs.hub.update'):
+        if message['msg']['hub']['name'] == widget.hub.name:
+            return True
+
+    # TODO -- also check for FAS group changes??  are we doing that?
+
+    return False
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 60da776..85b2aaa 100644
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -15,3 +15,11 @@ chrome = panel(title='Sticky Note', klass="panel-info")
 def data(request, session, widget, text):
     # TODO -- render with markdown
     return dict(text=text)
+
+
+def should_invalidate(message, session, widget):
+    if message['topic'].endswith('hubs.widget.update'):
+        if message['msg']['widget']['id'] == widget.id:
+            return True
+
+    return False
diff --git a/populate.py b/populate.py
index 2c44efc..8751dc6 100755
--- a/populate.py
+++ b/populate.py
@@ -2,18 +2,13 @@
 """ Populate the hubs db with some dev data. """
 
 import json
-import os
-
-import flask
 
 import hubs.models
 
-app = flask.Flask(__name__)
-app.config.from_object('hubs.default_config')
-if 'HUBS_CONFIG' in os.environ:
-    app.config.from_envvar('HUBS_CONFIG')
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
 
-session = hubs.models.init(app.config['DB_URL'], True, True)
+session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
 session.add(hub)
diff --git a/requirements.txt b/requirements.txt
index 0f26348..3a9498a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,4 @@ flask
 sqlalchemy
 fedmsg
 dogpile.cache
+fedmsg_meta_fedora_infrastructure
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..5a66e3e
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,43 @@
+""" Setup file for fedora hubs """
+
+from setuptools import setup, find_packages
+
+
+def get_description():
+    with open('README.rst', 'r') as f:
+        return ''.join(f.readlines()[2:])
+
+
+def get_requirements():
+    with open('requirements.txt', 'r') as f:
+        return [l.strip() for l in f.readlines() if l.strip()]
+
+
+setup(
+    name='fedora-hubs',
+    version='0.0.1',
+    description='A community portal for fedora contributors and you!',
+    long_description=get_description(),
+    author='Ralph Bean',
+    author_email='rbean@redhat.com',
+    url="https://github.com/ralphbean/fedora-hubs-prototype",
+    download_url="https://pypi.python.org/pypi/fedora-hubs/",
+    license='AGPLv3+',
+    install_requires=get_requirements(),
+    #tests_require=tests_require,
+    #test_suite='nose.collector',
+    packages=find_packages(),
+    include_package_data=True,
+    zip_safe=False,
+    classifiers=[
+        'Environment :: Web Environment',
+        'Topic :: Software Development :: Libraries :: Python Modules',
+        'Intended Audience :: Developers',
+        'Programming Language :: Python',
+    ],
+    entry_points={
+        'moksha.consumer': [
+            "cache_invalidator = hubs.consumer:CacheInvalidatorExtraordinaire",
+        ],
+    },
+)

From 501b3dbef637a13545f3f31ca0f383593007c205 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 03 2015 01:19:22 +0000
Subject: [PATCH 45/1001] Remove the 'request' from all these functions.  We don't need it and it unnecessarily favours the Flask app.


---

diff --git a/hubs/app.py b/hubs/app.py
index 7485d42..f1fa7b7 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -72,7 +72,7 @@ def widget_render(hub, idx):
     print(widget.plugin, "sleeping artificially for", s)
     time.sleep(s)
 
-    return widget.render(flask.request, session)
+    return widget.render(session)
 
 
 @app.route('/<hub>/<idx>/json')
@@ -82,7 +82,7 @@ def widget_json(hub, idx):
     widget = get_widget(session, hub, idx)
     from hubs.widgets import registry
     module = registry[widget.plugin]
-    data = module.data(flask.request, session, widget, **widget.config)
+    data = module.data(session, widget, **widget.config)
     response = flask.jsonify(data)
 
     # We don't actually need these two headers.  Just messing around.
diff --git a/hubs/models.py b/hubs/models.py
index 3d16fb1..49eb665 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -150,9 +150,9 @@ class Widget(BASE):
     def module(self):
         return hubs.widgets.registry[self.plugin]
 
-    def render(self, request, session):
+    def render(self, session):
         render = hubs.widgets.render
-        return render(self.module, request, session, self, **self.config)
+        return render(self.module, session, self, **self.config)
 
 
 class User(BASE):
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 832c936..4078e33 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -59,13 +59,13 @@ def prepare_registry(registry):
 validate_registry(registry)
 prepare_registry(registry)
 
-def render(module, request, session, widget, *args, **kwargs):
+def render(module, session, widget, *args, **kwargs):
     """ Main API entry point.
 
     Call this to render a widget into HTML
     """
     # The API returns exactly this data.  Shared cache
-    data = module.data(request, session, widget, *args, **kwargs)
+    data = module.data(session, widget, *args, **kwargs)
 
     # Use the API data to fill out a template, and potentially decorate it.
     return module.render(**data)
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 9bfe26e..f26edd6 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -51,9 +51,9 @@ def AGPLv3(name):
 def smartcache(module):
     def decorator(func):
         @wraps(func)
-        def inner(request, session, widget, *args, **kwargs):
+        def inner(session, widget, *args, **kwargs):
             key = cache_key_generator(module, args, kwargs)
-            creator = lambda: func(request, session, widget, *args, **kwargs)
+            creator = lambda: func(session, widget, *args, **kwargs)
             return cache.get_or_create(key, creator)
 
         return inner
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index 9731a20..d0c9e57 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -12,7 +12,7 @@ chrome = panel("This is a dummy widget")
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
           help="Some dummy text to display.")
-def data(request, session, widget, text):
+def data(session, widget, text):
     return dict(text=text)
 
 
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 4d682be..3e0fb4d 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -39,7 +39,7 @@ template = jinja2.Template("""
 @argument(name='link', default=None,
           validator=validators.link,
           help="Link to the community rules and guidelines")
-def data(request, session, widget, link):
+def data(session, widget, link):
     owners = widget.hub.owners
     owners = ordereddict([(o, avatar(o)) for o in owners])
     return dict(owners=owners, link=link)
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 868deaa..1e14658 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -31,7 +31,7 @@ template = jinja2.Template("""
 """)
 
 
-def data(request, session, widget):
+def data(session, widget):
     return dict(
         members=len(widget.hub.members),
         subscribers=len(widget.hub.subscribers),
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 85b2aaa..36d4a1a 100644
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -12,7 +12,7 @@ chrome = panel(title='Sticky Note', klass="panel-info")
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
           help="Some dummy text to display.")
-def data(request, session, widget, text):
+def data(session, widget, text):
     # TODO -- render with markdown
     return dict(text=text)
 

From eb24faa27cb748ebb10226d81dd300c65e3fa610 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 03 2015 01:24:30 +0000
Subject: [PATCH 46/1001] Implement invalidation and rebuilding.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index 0f36f63..08d1eca 100644
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -7,6 +7,8 @@ import fedmsg.consumers
 
 import hubs.models
 
+from hubs.widgets.base import invalidate_cache
+
 import logging
 log = logging.getLogger("hubs")
 
@@ -65,8 +67,12 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         # And do the real work of comparing every widget against the message.
         for widget in widgets:
             if widget.module.should_invalidate(msg, session, widget):
-                raise NotImplementedError("Invalidate the cache...")
-                raise NotImplementedError("Rebuild it.")
+                log.info("Invalidating cache for %r" % widget)
+                # Invalidate the cache...
+                invalidate_cache(widget.module, **widget.config)
+                # Rebuild it.
+                widget.module.data(session, widget, **widget.config)
+                # TODO -- fire off an EventSource notice that we updated stuff
 
         log.info("Done.  %0.2fs %s %s",
                   time.time() - start, msg['msg_id'], msg['topic'])
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index f26edd6..e0d1581 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -60,6 +60,11 @@ def smartcache(module):
     return decorator
 
 
+def invalidate_cache(module, *args, **kwargs):
+    key = cache_key_generator(module, *args, **kwargs)
+    cache.delete(key)
+
+
 def cache_key_generator(module, args, kwargs):
     return "|".join([
         module.__name__,

From 887616c1c4f27e617fa306a7ae48251756cd7abf Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 16:49:15 +0000
Subject: [PATCH 47/1001] Merge pull request #3 from ralphbean/feature/invalidation


Take a stab at cache invalidation.
---

diff --git a/.gitignore b/.gitignore
index 0d20b64..e6e04af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 *.pyc
+*.egg*
diff --git a/README.rst b/README.rst
index 3b380b2..d5dd996 100644
--- a/README.rst
+++ b/README.rst
@@ -47,11 +47,12 @@ In order to be valid, a widget must have:
 
 This isn't implemented yet, but they're going to need:
 
-- A ``invalidate(session, message)`` function that will be used to
+- A ``should_invalidate(message, session, widget)`` function that will be used to
   *potentially* invalidate the widget's cache. That function will get called by
   a backend daemon listening for fedmsg messages so when you update your group
-  memberships in FAS, a fedmsg message hits the fedora-hubs backend and it
-  nukes/refreshes a lookup value in memcached (or some other store).
+  memberships in FAS, a fedmsg message hits the fedora-hubs backend and returns
+  True if the lookup value should be nuked/refreshed in memcached (or some
+  other store).
 
 Furthermore, a proposal:
 
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index a405684..6bfeb35 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -1,4 +1,21 @@
 config = {
+
+    'hubs.consumer.enabled': True,
+    # Production ready.
+    'hubs.sqlalchemy.uri': 'sqlite:////var/tmp/hubs.db',
+
     'endpoints': {
+        # TODO -- fill these out later...
     },
+
+    'logging': dict(
+        version=1,
+        loggers=dict(
+            hubs={
+                "level": "DEBUG",
+                "propagate": False,
+                "handlers": ["console"],
+            },
+        ),
+    ),
 }
diff --git a/hubs/app.py b/hubs/app.py
index c7432c4..f1fa7b7 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -17,6 +17,9 @@ app.config.from_object('hubs.default_config')
 if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
 
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
+
 
 @app.route('/')
 def index():
@@ -26,7 +29,7 @@ def index():
 @app.route('/<name>')
 @app.route('/<name>/')
 def hub(name):
-    session = models.init(app.config['DB_URL'])
+    session = models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     hub = session.query(models.Hub)\
         .filter(models.Hub.name==name)\
         .first()
@@ -60,7 +63,7 @@ def get_widget(session, hub, idx):
 @app.route('/<hub>/<idx>')
 @app.route('/<hub>/<idx>/')
 def widget_render(hub, idx):
-    session = models.init(app.config['DB_URL'])
+    session = models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     widget = get_widget(session, hub, idx)
 
     # Make this artificially slow for development...
@@ -69,17 +72,17 @@ def widget_render(hub, idx):
     print(widget.plugin, "sleeping artificially for", s)
     time.sleep(s)
 
-    return widget.render(flask.request, session)
+    return widget.render(session)
 
 
 @app.route('/<hub>/<idx>/json')
 @app.route('/<hub>/<idx>/json/')
 def widget_json(hub, idx):
-    session = models.init(app.config['DB_URL'])
+    session = models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     widget = get_widget(session, hub, idx)
     from hubs.widgets import registry
     module = registry[widget.plugin]
-    data = module.data(flask.request, session, widget, **widget.config)
+    data = module.data(session, widget, **widget.config)
     response = flask.jsonify(data)
 
     # We don't actually need these two headers.  Just messing around.
diff --git a/hubs/consumer.py b/hubs/consumer.py
new file mode 100644
index 0000000..08d1eca
--- /dev/null
+++ b/hubs/consumer.py
@@ -0,0 +1,82 @@
+# The fedora hubs backend daemon
+
+import time
+import random
+
+import fedmsg.consumers
+
+import hubs.models
+
+from hubs.widgets.base import invalidate_cache
+
+import logging
+log = logging.getLogger("hubs")
+
+
+class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
+    topic = '*'
+    config_key = 'hubs.consumer.enabled'
+
+    def __init__(self, *args, **kwargs):
+        log.info("CacheInvalidatorExtraordinaire initializing")
+        super(CacheInvalidatorExtraordinaire, self).__init__(*args, **kwargs)
+
+        self.uri = self.hub.config.get('hubs.sqlalchemy.uri', None)
+        self.junk_suffixes = self.hub.config.get('hubs.junk_suffixes', [])
+
+        if not self.uri:
+            raise ValueError('hubs.sqlalchemy.uri must be present')
+
+        log.info("CacheInvalidatorExtraordinaire initialized")
+
+    def make_session(self):
+        return hubs.models.init(self.uri)
+
+    def consume(self, raw_msg):
+        session = self.make_session()
+        try:
+            self.work(session, raw_msg)
+            session.commit()  # transaction is committed here
+        except:
+            session.rollback()  # rolls back the transaction
+            raise
+
+    def work(self, session, raw_msg):
+        topic, msg = raw_msg['topic'], raw_msg['body']
+
+        for suffix in self.junk_suffixes:
+            if topic.endswith(suffix):
+                log.info("Dropping %r", topic)
+                return
+
+        start = time.time()
+        log.info("CacheInvalidatorExtraordinaire received %s %s",
+                  msg['msg_id'], msg['topic'])
+
+        # Begin our real work.
+        # Find which widgets should have their caches nuked and make it so.
+
+        # First, make a thread-local copy of the widgets.
+        widgets = list(session.query(hubs.models.Widget).all())
+        log.info("Comparing message against %i widgets" % len(widgets))
+
+        # Shuffle it so that not all threads step through the list in the same
+        # order.  This should cut down on competition for the dogpile lock.
+        random.shuffle(widgets)
+
+        # And do the real work of comparing every widget against the message.
+        for widget in widgets:
+            if widget.module.should_invalidate(msg, session, widget):
+                log.info("Invalidating cache for %r" % widget)
+                # Invalidate the cache...
+                invalidate_cache(widget.module, **widget.config)
+                # Rebuild it.
+                widget.module.data(session, widget, **widget.config)
+                # TODO -- fire off an EventSource notice that we updated stuff
+
+        log.info("Done.  %0.2fs %s %s",
+                  time.time() - start, msg['msg_id'], msg['topic'])
+
+    def stop(self):
+        log.info("Cleaning up CacheInvalidatorExtraordinaire.")
+        super(CacheInvalidatorExtraordinaire, self).stop()
diff --git a/hubs/default_config.py b/hubs/default_config.py
index 3a6a0ff..e69de29 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -1,2 +0,0 @@
-# Production ready.
-DB_URL = 'sqlite:////var/tmp/hubs.db'
diff --git a/hubs/models.py b/hubs/models.py
index 6d328de..49eb665 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -146,10 +146,13 @@ class Widget(BASE):
             'plugin': self.plugin,
         }
 
-    def render(self, request, session):
-        module = hubs.widgets.registry[self.plugin]
+    @property
+    def module(self):
+        return hubs.widgets.registry[self.plugin]
+
+    def render(self, session):
         render = hubs.widgets.render
-        return render(module, request, session, self, **self.config)
+        return render(self.module, session, self, **self.config)
 
 
 class User(BASE):
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 832c936..4078e33 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -59,13 +59,13 @@ def prepare_registry(registry):
 validate_registry(registry)
 prepare_registry(registry)
 
-def render(module, request, session, widget, *args, **kwargs):
+def render(module, session, widget, *args, **kwargs):
     """ Main API entry point.
 
     Call this to render a widget into HTML
     """
     # The API returns exactly this data.  Shared cache
-    data = module.data(request, session, widget, *args, **kwargs)
+    data = module.data(session, widget, *args, **kwargs)
 
     # Use the API data to fill out a template, and potentially decorate it.
     return module.render(**data)
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 9bfe26e..e0d1581 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -51,15 +51,20 @@ def AGPLv3(name):
 def smartcache(module):
     def decorator(func):
         @wraps(func)
-        def inner(request, session, widget, *args, **kwargs):
+        def inner(session, widget, *args, **kwargs):
             key = cache_key_generator(module, args, kwargs)
-            creator = lambda: func(request, session, widget, *args, **kwargs)
+            creator = lambda: func(session, widget, *args, **kwargs)
             return cache.get_or_create(key, creator)
 
         return inner
     return decorator
 
 
+def invalidate_cache(module, *args, **kwargs):
+    key = cache_key_generator(module, *args, **kwargs)
+    cache.delete(key)
+
+
 def cache_key_generator(module, args, kwargs):
     return "|".join([
         module.__name__,
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index fb44797..d0c9e57 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -12,5 +12,13 @@ chrome = panel("This is a dummy widget")
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
           help="Some dummy text to display.")
-def data(request, session, widget, text):
+def data(session, widget, text):
     return dict(text=text)
+
+
+def should_invalidate(message, session, widget):
+    if not message['topic'].endswith('hubs.widget.update'):
+        return False
+    if message['msg']['widget']['id'] != widget.id:
+        return False
+    return True
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 2a6a632..3e0fb4d 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -39,7 +39,19 @@ template = jinja2.Template("""
 @argument(name='link', default=None,
           validator=validators.link,
           help="Link to the community rules and guidelines")
-def data(request, session, widget, link):
+def data(session, widget, link):
     owners = widget.hub.owners
     owners = ordereddict([(o, avatar(o)) for o in owners])
     return dict(owners=owners, link=link)
+
+
+def should_invalidate(message, session, widget):
+    if message['topic'].endswith('hubs.widget.update'):
+        if message['msg']['widget']['id'] == widget.id:
+            return True
+
+    if message['topic'].endswith('hubs.hub.update'):
+        if message['msg']['hub']['name'] == widget.hub.name:
+            return True
+
+    return False
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index a181453..1e14658 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -31,8 +31,18 @@ template = jinja2.Template("""
 """)
 
 
-def data(request, session, widget):
+def data(session, widget):
     return dict(
         members=len(widget.hub.members),
         subscribers=len(widget.hub.subscribers),
     )
+
+
+def should_invalidate(message, session, widget):
+    if message['topic'].endswith('hubs.hub.update'):
+        if message['msg']['hub']['name'] == widget.hub.name:
+            return True
+
+    # TODO -- also check for FAS group changes??  are we doing that?
+
+    return False
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 60da776..36d4a1a 100644
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -12,6 +12,14 @@ chrome = panel(title='Sticky Note', klass="panel-info")
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
           help="Some dummy text to display.")
-def data(request, session, widget, text):
+def data(session, widget, text):
     # TODO -- render with markdown
     return dict(text=text)
+
+
+def should_invalidate(message, session, widget):
+    if message['topic'].endswith('hubs.widget.update'):
+        if message['msg']['widget']['id'] == widget.id:
+            return True
+
+    return False
diff --git a/populate.py b/populate.py
index 2c44efc..8751dc6 100755
--- a/populate.py
+++ b/populate.py
@@ -2,18 +2,13 @@
 """ Populate the hubs db with some dev data. """
 
 import json
-import os
-
-import flask
 
 import hubs.models
 
-app = flask.Flask(__name__)
-app.config.from_object('hubs.default_config')
-if 'HUBS_CONFIG' in os.environ:
-    app.config.from_envvar('HUBS_CONFIG')
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
 
-session = hubs.models.init(app.config['DB_URL'], True, True)
+session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
 session.add(hub)
diff --git a/requirements.txt b/requirements.txt
index 0f26348..3a9498a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,4 @@ flask
 sqlalchemy
 fedmsg
 dogpile.cache
+fedmsg_meta_fedora_infrastructure
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..5a66e3e
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,43 @@
+""" Setup file for fedora hubs """
+
+from setuptools import setup, find_packages
+
+
+def get_description():
+    with open('README.rst', 'r') as f:
+        return ''.join(f.readlines()[2:])
+
+
+def get_requirements():
+    with open('requirements.txt', 'r') as f:
+        return [l.strip() for l in f.readlines() if l.strip()]
+
+
+setup(
+    name='fedora-hubs',
+    version='0.0.1',
+    description='A community portal for fedora contributors and you!',
+    long_description=get_description(),
+    author='Ralph Bean',
+    author_email='rbean@redhat.com',
+    url="https://github.com/ralphbean/fedora-hubs-prototype",
+    download_url="https://pypi.python.org/pypi/fedora-hubs/",
+    license='AGPLv3+',
+    install_requires=get_requirements(),
+    #tests_require=tests_require,
+    #test_suite='nose.collector',
+    packages=find_packages(),
+    include_package_data=True,
+    zip_safe=False,
+    classifiers=[
+        'Environment :: Web Environment',
+        'Topic :: Software Development :: Libraries :: Python Modules',
+        'Intended Audience :: Developers',
+        'Programming Language :: Python',
+    ],
+    entry_points={
+        'moksha.consumer': [
+            "cache_invalidator = hubs.consumer:CacheInvalidatorExtraordinaire",
+        ],
+    },
+)

From 33d19f7b7f3ca8df7406531bf14773f6e136e42a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 16:51:34 +0000
Subject: [PATCH 48/1001] Note TODO from the session today.


---

diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 1e14658..d0d3039 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -38,6 +38,7 @@ def data(session, widget):
     )
 
 
+# TODO -- add topic-based hinting here.  Solved.
 def should_invalidate(message, session, widget):
     if message['topic'].endswith('hubs.hub.update'):
         if message['msg']['hub']['name'] == widget.hub.name:

From 53b35af10e6c813690e2c746db7abf81b85009ab Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 16:59:15 +0000
Subject: [PATCH 49/1001] Make gunicorn happy on python3.


---

diff --git a/hubs/app.py b/hubs/app.py
index f1fa7b7..7c3a4f2 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -2,7 +2,7 @@ import os
 
 import flask
 
-import models
+import hubs.models
 
 app = flask.Flask(__name__)
 
@@ -29,9 +29,9 @@ def index():
 @app.route('/<name>')
 @app.route('/<name>/')
 def hub(name):
-    session = models.init(fedmsg_config['hubs.sqlalchemy.uri'])
-    hub = session.query(models.Hub)\
-        .filter(models.Hub.name==name)\
+    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+    hub = session.query(hubs.models.Hub)\
+        .filter(hubs.models.Hub.name==name)\
         .first()
 
     if not hub:
@@ -46,8 +46,8 @@ def get_widget(session, hub, idx):
     except TypeError:
         flask.abort(404)
 
-    hub = session.query(models.Hub)\
-        .filter(models.Hub.name==hub)\
+    hub = session.query(hubs.models.Hub)\
+        .filter(hubs.models.Hub.name==hub)\
         .first()
 
     if not hub:
@@ -63,7 +63,7 @@ def get_widget(session, hub, idx):
 @app.route('/<hub>/<idx>')
 @app.route('/<hub>/<idx>/')
 def widget_render(hub, idx):
-    session = models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     widget = get_widget(session, hub, idx)
 
     # Make this artificially slow for development...
@@ -78,7 +78,7 @@ def widget_render(hub, idx):
 @app.route('/<hub>/<idx>/json')
 @app.route('/<hub>/<idx>/json/')
 def widget_json(hub, idx):
-    session = models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     widget = get_widget(session, hub, idx)
     from hubs.widgets import registry
     module = registry[widget.plugin]

From 0354935eadfa342d85b240d441061b12b806734d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 17:36:01 +0000
Subject: [PATCH 50/1001] Link to source on pagure.


---

diff --git a/README.rst b/README.rst
index d5dd996..34ad916 100644
--- a/README.rst
+++ b/README.rst
@@ -1,3 +1,8 @@
+Source on Pagure.io
+-------------------
+
+The latest source is not on GitHub, it is on pagure.io.  You can find it at https://pagure.io/fedora-hubs
+
 Hacking
 -------
 

From 36456caf26c444e3ff0711f39c7fb32fcffd7e5d Mon Sep 17 00:00:00 2001
From: Solly Ross <sross@redhat.com>
Date: Jun 04 2015 17:45:03 +0000
Subject: [PATCH 51/1001] Add pysqlite to the requirements


It's used by default for the db.

---

diff --git a/requirements.txt b/requirements.txt
index 3a9498a..d42bc7e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,3 +3,4 @@ sqlalchemy
 fedmsg
 dogpile.cache
 fedmsg_meta_fedora_infrastructure
+pysqlite

From c8f4f21035d6bae7422484150746a1d16cbfa920 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 18:20:08 +0000
Subject: [PATCH 52/1001] Merge pull request #5 from DirectXMan12/develop


Add pysqlite to the requirements
---

diff --git a/requirements.txt b/requirements.txt
index 3a9498a..d42bc7e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,3 +3,4 @@ sqlalchemy
 fedmsg
 dogpile.cache
 fedmsg_meta_fedora_infrastructure
+pysqlite

From 626f7b7830d06a021f5e8b4e3cd8698d7ad4b0d4 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 18:27:32 +0000
Subject: [PATCH 53/1001] Messing with authn.


---

diff --git a/hubs/app.py b/hubs/app.py
index 7c3a4f2..9bc3f88 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,7 +1,10 @@
+import functools
 import os
 
 import flask
 
+from flask.ext.openid import OpenID
+
 import hubs.models
 
 app = flask.Flask(__name__)
@@ -20,6 +23,8 @@ if 'HUBS_CONFIG' in os.environ:
 import fedmsg.config
 fedmsg_config = fedmsg.config.load_config()
 
+session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+
 
 @app.route('/')
 def index():
@@ -29,7 +34,6 @@ def index():
 @app.route('/<name>')
 @app.route('/<name>/')
 def hub(name):
-    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     hub = session.query(hubs.models.Hub)\
         .filter(hubs.models.Hub.name==name)\
         .first()
@@ -63,7 +67,6 @@ def get_widget(session, hub, idx):
 @app.route('/<hub>/<idx>')
 @app.route('/<hub>/<idx>/')
 def widget_render(hub, idx):
-    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     widget = get_widget(session, hub, idx)
 
     # Make this artificially slow for development...
@@ -78,7 +81,6 @@ def widget_render(hub, idx):
 @app.route('/<hub>/<idx>/json')
 @app.route('/<hub>/<idx>/json/')
 def widget_json(hub, idx):
-    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
     widget = get_widget(session, hub, idx)
     from hubs.widgets import registry
     module = registry[widget.plugin]
@@ -102,5 +104,87 @@ def widget_source(name):
     return flask.redirect(SOURCE_URL + fname)
 
 
+# Set up OpenID in stateless mode
+oid = OpenID(app,
+             safe_roots=[],
+             store_factory=lambda: None,
+             url_root_as_trust_root=True)
+
+
+@app.route('/login/', methods=('GET', 'POST'))
+@app.route('/login', methods=('GET', 'POST'))
+@oid.loginhandler
+def login():
+    default = flask.url_for('index')
+    next_url = flask.request.args.get('next', default)
+    if flask.g.auth.logged_in:
+        return flask.redirect(next_url)
+
+    openid_server = flask.request.form.get('openid', None)
+    if openid_server:
+        return oid.try_login(
+            openid_server, ask_for=['email', 'fullname', 'nickname'],
+            ask_for_optional=[])
+
+    return flask.render_template(
+        'login.html', next=oid.get_next_url(), error=oid.fetch_error())
+
+
+@app.route('/login/fedora/')
+@app.route('/login/fedora')
+@oid.loginhandler
+def fedora_login():
+    #default = flask.url_for('profile_redirect')
+    #next_url = flask.request.args.get('next', default)
+    return oid.try_login(
+        'https://id.fedoraproject.org',
+        ask_for=['email', 'fullname', 'nickname'],
+        ask_for_optional=[])
+
+
+@app.route('/logout/')
+@app.route('/logout')
+def logout():
+    if 'openid' in flask.app.session:
+        flask.app.session.pop('openid')
+    return flask.redirect(flask.url_for('index'))
+
+
+@oid.after_login
+def after_openid_login(resp):
+    default = flask.url_for('index')
+    if not resp.identity_url:
+        return flask.redirect(default)
+
+    openid_url = resp.identity_url
+    flask.app.session['openid'] = openid_url
+    flask.app.session['fullname'] = resp.fullname
+    flask.app.session['nickname'] = resp.nickname or resp.fullname
+    flask.app.session['email'] = resp.email
+    next_url = flask.request.args.get('next', default)
+    return flask.redirect(next_url)
+
+
+def login_required(function):
+    """ Flask decorator to restrict access to logged-in users. """
+    @functools.wraps(function)
+    def decorated_function(*args, **kwargs):
+        """ Decorated function, actually does the work. """
+        if not flask.g.auth.logged_in:
+            flask.flash('Login required', 'errors')
+            return flask.redirect(flask.url_for(
+                'fedora_login', next=flask.request.url))
+
+        # TODO - Ensure that the logged in user exists before we proceed.
+        hubs.models.User.get_or_create(
+            session,
+            openid=flask.g.auth.openid,
+            openid_url=flask.g.auth.openid_url,
+        )
+
+        return function(*args, **kwargs)
+    return decorated_function
+
+
 if __name__ == '__main__':
     app.run(debug=True)
diff --git a/hubs/default_config.py b/hubs/default_config.py
index e69de29..39d7fce 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -0,0 +1 @@
+SECRET_KEY = 'changemeforreal'
diff --git a/requirements.txt b/requirements.txt
index d42bc7e..306c469 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,3 +4,4 @@ fedmsg
 dogpile.cache
 fedmsg_meta_fedora_infrastructure
 pysqlite
+flask-openid

From 5f1c3f1c074a35a41ba330ef70e6245a6cf79e04 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 18:43:23 +0000
Subject: [PATCH 54/1001] Get the super duper basics of openid login/logout work.


---

diff --git a/hubs/app.py b/hubs/app.py
index 9bc3f88..0b98b60 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -2,6 +2,7 @@ import functools
 import os
 
 import flask
+import munch
 
 from flask.ext.openid import OpenID
 
@@ -133,7 +134,7 @@ def login():
 @app.route('/login/fedora/')
 @app.route('/login/fedora')
 @oid.loginhandler
-def fedora_login():
+def login_fedora():
     #default = flask.url_for('profile_redirect')
     #next_url = flask.request.args.get('next', default)
     return oid.try_login(
@@ -173,7 +174,7 @@ def login_required(function):
         if not flask.g.auth.logged_in:
             flask.flash('Login required', 'errors')
             return flask.redirect(flask.url_for(
-                'fedora_login', next=flask.request.url))
+                'login_fedora', next=flask.request.url))
 
         # TODO - Ensure that the logged in user exists before we proceed.
         hubs.models.User.get_or_create(
@@ -186,5 +187,25 @@ def login_required(function):
     return decorated_function
 
 
+@app.before_request
+def check_auth():
+    flask.g.fedmsg_config = fedmsg_config
+    flask.g.auth = munch.Munch(
+        logged_in=False,
+        method=None,
+        id=None,
+    )
+    if 'openid' in flask.session:
+        openid = flask.session.get('openid').split('/')[-1]
+        flask.g.auth.logged_in = True
+        flask.g.auth.method = u'openid'
+        flask.g.auth.openid = openid
+        flask.g.auth.openid_url = flask.session.get('openid')
+        flask.g.auth.fullname = flask.session.get('fullname', None)
+        flask.g.auth.nickname = flask.session.get('nickname', None)
+        flask.g.auth.email = flask.session.get('email', None)
+
+
+
 if __name__ == '__main__':
     app.run(debug=True)
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f5935e5..a201ef1 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -53,6 +53,13 @@
 </div>
 <div class="container">
   <div class="row">
+    {% if g.auth.logged_in %}
+    Logged in as {{ g.auth.nickname }}
+    {% else %}
+    Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
+    {% endif %}
+  </div>
+  <div class="row">
     <div class="col-md-{{ hub.left_width }}">
       {% for widget in hub.left_widgets %}
       <div id="widget-{{ widget.idx }}" class="row"></div>
diff --git a/requirements.txt b/requirements.txt
index 306c469..820a56c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,5 +3,5 @@ sqlalchemy
 fedmsg
 dogpile.cache
 fedmsg_meta_fedora_infrastructure
-pysqlite
 flask-openid
+munch

From ea88d0374e27f6b42fd35f744404a8026f653419 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jun 04 2015 18:52:56 +0000
Subject: [PATCH 55/1001] readme update


---

diff --git a/README.rst b/README.rst
index 34ad916..c64767c 100644
--- a/README.rst
+++ b/README.rst
@@ -5,6 +5,9 @@ The latest source is not on GitHub, it is on pagure.io.  You can find it at http
 
 Hacking
 -------
+Install fedora dependencies:
+
+    $ sudo dnf install gcc gcc-c++ sqlite-devel 
 
 Hubs should work on python2 **and** python3, so let's default to python3 and
 see how that goes.

From 182eaec1786bb406cd379fe5525115afc1de9200 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 19:01:49 +0000
Subject: [PATCH 56/1001] Merge pull request #6 from meghanrichardson/develop


readme update
---

diff --git a/README.rst b/README.rst
index 34ad916..c64767c 100644
--- a/README.rst
+++ b/README.rst
@@ -5,6 +5,9 @@ The latest source is not on GitHub, it is on pagure.io.  You can find it at http
 
 Hacking
 -------
+Install fedora dependencies:
+
+    $ sudo dnf install gcc gcc-c++ sqlite-devel 
 
 Hubs should work on python2 **and** python3, so let's default to python3 and
 see how that goes.

From 61aeecd09cafd50c84c475a35b5b08d22517368e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 19:02:00 +0000
Subject: [PATCH 57/1001] Merge branch 'develop' of github.com:ralphbean/fedora-hubs-prototype into develop


---

diff --git a/README.rst b/README.rst
index 34ad916..c64767c 100644
--- a/README.rst
+++ b/README.rst
@@ -5,6 +5,9 @@ The latest source is not on GitHub, it is on pagure.io.  You can find it at http
 
 Hacking
 -------
+Install fedora dependencies:
+
+    $ sudo dnf install gcc gcc-c++ sqlite-devel 
 
 Hubs should work on python2 **and** python3, so let's default to python3 and
 see how that goes.

From f9493752618897707ec09cd83bf3ba659ee6e675 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 04 2015 19:18:32 +0000
Subject: [PATCH 58/1001] Copy the dummy widget, make it an About widget


---

diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
new file mode 100644
index 0000000..d5f8c7c
--- /dev/null
+++ b/hubs/widgets/about.py
@@ -0,0 +1,21 @@
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import argument
+
+import jinja2
+
+import hubs.validators as validators
+
+
+template = jinja2.Template("{{text}} decause was here")
+chrome = panel("This is a dummy widget")
+
+
+@argument(name="text", default="Lorem ipsum dolor...",
+          validator=validators.text,
+          help="Some dummy text to display.")
+def data(session, widget, text):
+    return dict(text=text)
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 9dba27c3b0380a519cb2c982eaf5f4eaf9a9c776 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 04 2015 19:18:32 +0000
Subject: [PATCH 59/1001] Add About widget to populate script


---

diff --git a/populate.py b/populate.py
index 8751dc6..0210431 100755
--- a/populate.py
+++ b/populate.py
@@ -20,8 +20,14 @@ widget = hubs.models.Widget(plugin='rules', index=1,
                                 'link': 'http://threebean.org'
                             }))
 hub.widgets.append(widget)
+
 widget = hubs.models.Widget(plugin='dummy', index=2)
 hub.widgets.append(widget)
+
+# Added a hubs about widget
+widget = hubs.models.Widget(plugin='about', index=2)
+hub.widgets.append(widget)
+
 widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
                             _config=json.dumps({
                                 'text': 'This is a sticky note.',

From a6038f443c943e19a6235cef99c8f925e52e356b Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 04 2015 19:18:32 +0000
Subject: [PATCH 60/1001] Added About widget to __init__.py


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 4078e33..f2268e7 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -2,6 +2,7 @@ from hubs.widgets import dummy
 from hubs.widgets import stats
 from hubs.widgets import rules
 from hubs.widgets import sticky
+from hubs.widgets import about
 
 from hubs.widgets.base import AGPLv3, smartcache
 
@@ -10,6 +11,7 @@ registry = {
     'stats': stats,
     'rules': rules,
     'sticky': sticky,
+    'about': about,
 }
 
 

From 9dd472cd3f12c60c808de8ff1edd441980e727d6 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 04 2015 19:32:30 +0000
Subject: [PATCH 61/1001] Added some about-specific default text


---

diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index d5f8c7c..a6f8eae 100644
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -6,13 +6,15 @@ import jinja2
 import hubs.validators as validators
 
 
-template = jinja2.Template("{{text}} decause was here")
-chrome = panel("This is a dummy widget")
+template = jinja2.Template("""
+    <p>{{text}}</p>
+    """)
+chrome = panel("About")
 
 
-@argument(name="text", default="Lorem ipsum dolor...",
+@argument(name="text", default="I am a Fedora user, and this is my about",
           validator=validators.text,
-          help="Some dummy text to display.")
+          help="Text about a user.")
 def data(session, widget, text):
     return dict(text=text)
 

From b05d48a4f72e0f651a97c04adea0c7adfb692cbb Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 04 2015 19:45:48 +0000
Subject: [PATCH 62/1001] Added slick one-liner for restarting rm db, recreate db, re-run gunicorn


---

diff --git a/README.rst b/README.rst
index c64767c..fc8cdd3 100644
--- a/README.rst
+++ b/README.rst
@@ -33,6 +33,10 @@ If you want to test it with 8 worker threads, try ``gunicorn``::
     $ pip install gunicorn
     $ gunicorn -w 8 hubs.app:app
 
+Hacking on Widgets one-liner::
+
+    $ rm /var/tmp/hubs.db; PYTHONPATH=. python3 populate.py; gunicorn -w 8 hubs.app:app
+
 Internal design
 ---------------
 

From 1056f7e887a8536c4897a484abfe5b71a3e66090 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 04 2015 19:46:19 +0000
Subject: [PATCH 63/1001] Add fancy text json config to populate.py in preparation of data feeding


---

diff --git a/populate.py b/populate.py
index 0210431..0742abc 100755
--- a/populate.py
+++ b/populate.py
@@ -25,7 +25,10 @@ widget = hubs.models.Widget(plugin='dummy', index=2)
 hub.widgets.append(widget)
 
 # Added a hubs about widget
-widget = hubs.models.Widget(plugin='about', index=2)
+widget = hubs.models.Widget(plugin='about', index=3,
+                            _config=json.dumps({
+                                "text": "I'm a Fedora user, and this is my about widget text!",
+                            }))
 hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='sticky', index=0, left=True,

From 0b329751aae57eaf04286949bcba093504b90651 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 19:46:20 +0000
Subject: [PATCH 64/1001] Personal hub creation done.


---

diff --git a/hubs/app.py b/hubs/app.py
index 0b98b60..2fee16a 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -29,7 +29,10 @@ session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 
 @app.route('/')
 def index():
-    return flask.redirect('/designteam')  # TODO - remove this later
+    if not flask.g.auth.logged_in:
+        return flask.redirect(flask.url_for('login_fedora'))
+
+    return flask.redirect(flask.url_for('hub', name=flask.g.auth.nickname))
 
 
 @app.route('/<name>')
@@ -162,6 +165,11 @@ def after_openid_login(resp):
     flask.app.session['fullname'] = resp.fullname
     flask.app.session['nickname'] = resp.nickname or resp.fullname
     flask.app.session['email'] = resp.email
+
+    openid = openid_url.strip('/').split('/')[-1]
+    hubs.models.User.get_or_create(
+        session, openid=openid, fullname=resp.fullname)
+
     next_url = flask.request.args.get('next', default)
     return flask.redirect(next_url)
 
@@ -176,13 +184,6 @@ def login_required(function):
             return flask.redirect(flask.url_for(
                 'login_fedora', next=flask.request.url))
 
-        # TODO - Ensure that the logged in user exists before we proceed.
-        hubs.models.User.get_or_create(
-            session,
-            openid=flask.g.auth.openid,
-            openid_url=flask.g.auth.openid_url,
-        )
-
         return function(*args, **kwargs)
     return decorated_function
 
@@ -196,7 +197,7 @@ def check_auth():
         id=None,
     )
     if 'openid' in flask.session:
-        openid = flask.session.get('openid').split('/')[-1]
+        openid = flask.session.get('openid').strip('/').split('/')[-1]
         flask.g.auth.logged_in = True
         flask.g.auth.method = u'openid'
         flask.g.auth.openid = openid
diff --git a/hubs/models.py b/hubs/models.py
index 49eb665..7653c2e 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -94,6 +94,26 @@ class Hub(BASE):
     members = ['ralph', 'sadin', 'sayan'] + owners
     subscribers = []
 
+    @classmethod
+    def by_name(cls, session, name):
+        return session.query(cls).filter_by(name=name).first()
+
+    @classmethod
+    def create_user_hub(cls, session, username, fullname):
+        hub = cls(name=username, summary=fullname)
+        session.add(hub)
+
+        widget = Widget(plugin='sticky', index=0, left=True,
+                        _config=json.dumps({
+                            'text': 'TODO -- put a fancy graph here..',
+                        }))
+        hub.widgets.append(widget)
+        widget = Widget(plugin='sticky', index=0,
+                        _config=json.dumps({
+                            'text': 'TODO -- your feed goes here.',
+                        }))
+        hub.widgets.append(widget)
+
     @property
     def right_width(self):
         return 12 - self.left_width
@@ -158,16 +178,19 @@ class Widget(BASE):
 class User(BASE):
     __tablename__ = 'users'
     openid = sa.Column(sa.Text, primary_key=True)
-    openid_url = sa.Column(sa.Text, unique=True)
+    fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
     def __json__(self, reify=False):
         return {
             'openid': self.openid,
-            'openid_url': self.openid_url,
             'created_on': self.created_on,
         }
 
+    @property
+    def username(self):
+        return self.openid.split('.')[0]
+
     @classmethod
     def by_openid(cls, session, openid):
         return session.query(cls).filter_by(openid=openid).first()
@@ -177,3 +200,17 @@ class User(BASE):
     @classmethod
     def all(cls, session):
         return session.query(cls).all()
+
+    @classmethod
+    def get_or_create(cls, session, openid, fullname):
+        if not openid:
+            raise ValueError("Must provide openid, not %r" % openid)
+
+        self = cls.by_openid(session, openid)
+        if not self:
+            self = cls(openid=openid, fullname=fullname)
+            session.add(self)
+            if not Hub.by_name(session, self.username):
+                Hub.create_user_hub(session, self.username, self.fullname)
+            session.commit()
+        return self

From b6b2741be917055ceaf336c6f63de0b0b5818b12 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 19:57:48 +0000
Subject: [PATCH 65/1001] Merge pull request #7 from decause/develop


Added a initial about widget as an example
---

diff --git a/README.rst b/README.rst
index c64767c..fc8cdd3 100644
--- a/README.rst
+++ b/README.rst
@@ -33,6 +33,10 @@ If you want to test it with 8 worker threads, try ``gunicorn``::
     $ pip install gunicorn
     $ gunicorn -w 8 hubs.app:app
 
+Hacking on Widgets one-liner::
+
+    $ rm /var/tmp/hubs.db; PYTHONPATH=. python3 populate.py; gunicorn -w 8 hubs.app:app
+
 Internal design
 ---------------
 
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 4078e33..f2268e7 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -2,6 +2,7 @@ from hubs.widgets import dummy
 from hubs.widgets import stats
 from hubs.widgets import rules
 from hubs.widgets import sticky
+from hubs.widgets import about
 
 from hubs.widgets.base import AGPLv3, smartcache
 
@@ -10,6 +11,7 @@ registry = {
     'stats': stats,
     'rules': rules,
     'sticky': sticky,
+    'about': about,
 }
 
 
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
new file mode 100644
index 0000000..a6f8eae
--- /dev/null
+++ b/hubs/widgets/about.py
@@ -0,0 +1,23 @@
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import argument
+
+import jinja2
+
+import hubs.validators as validators
+
+
+template = jinja2.Template("""
+    <p>{{text}}</p>
+    """)
+chrome = panel("About")
+
+
+@argument(name="text", default="I am a Fedora user, and this is my about",
+          validator=validators.text,
+          help="Text about a user.")
+def data(session, widget, text):
+    return dict(text=text)
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError
diff --git a/populate.py b/populate.py
index 8751dc6..0742abc 100755
--- a/populate.py
+++ b/populate.py
@@ -20,8 +20,17 @@ widget = hubs.models.Widget(plugin='rules', index=1,
                                 'link': 'http://threebean.org'
                             }))
 hub.widgets.append(widget)
+
 widget = hubs.models.Widget(plugin='dummy', index=2)
 hub.widgets.append(widget)
+
+# Added a hubs about widget
+widget = hubs.models.Widget(plugin='about', index=3,
+                            _config=json.dumps({
+                                "text": "I'm a Fedora user, and this is my about widget text!",
+                            }))
+hub.widgets.append(widget)
+
 widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
                             _config=json.dumps({
                                 'text': 'This is a sticky note.',

From dab6f7b98b142a9ca1dcd230d73a53b4b3f568c4 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jun 04 2015 19:59:36 +0000
Subject: [PATCH 66/1001] move css to separate file


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
new file mode 100644
index 0000000..1bdbc82
--- /dev/null
+++ b/hubs/static/css/style.css
@@ -0,0 +1,40 @@
+   body {
+      background-color: #c;
+    }
+    .panel {
+      border-radius: 0px;
+    }
+    .header {
+      color: #ffffff;
+      background-color: #3c6eb4;
+      width: 100%;
+    }
+    .row {
+      padding: 5px;
+    }
+    .padded {
+      padding: 5px;
+    }
+    .medium-wide {
+      width: 250px;
+    }
+    h1, h2, h3, h4, h5, h6 {
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    .widget-buttons {
+      padding: 5px;
+      /* TODO -- lots more nice styling here... */
+    }
+    .panel {
+      visibility: hidden;
+      max-height: 0px;
+      overflow: hidden;
+      transition: max-height 0.4s;
+    }
+
+    .panel-visible {
+      visibility: visible;
+      max-height: 400px;
+    }
+
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f5935e5..72b0154 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -1,48 +1,8 @@
 <html>
 <head>
   <title>{{ hub.name }}</title>
-  <style>
-    body {
-      background-color: #d1d3d4;
-    }
-    .panel {
-      border-radius: 0px;
-    }
-    .header {
-      color: #ffffff;
-      background-color: #3c6eb4;
-      width: 100%;
-    }
-    .row {
-      padding: 5px;
-    }
-    .padded {
-      padding: 5px;
-    }
-    .medium-wide {
-      width: 250px;
-    }
-    h1, h2, h3, h4, h5, h6 {
-      margin-top: 0px;
-      margin-bottom: 0px;
-    }
-    .widget-buttons {
-      padding: 5px;
-      /* TODO -- lots more nice styling here... */
-    }
-    .panel {
-      visibility: hidden;
-      max-height: 0px;
-      overflow: hidden;
-      transition: max-height 0.4s;
-    }
-
-    .panel-visible {
-      visibility: visible;
-      max-height: 400px;
-    }
-
-  </style>
+  <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
 </head>
 <body>
 <div class="header">
@@ -67,7 +27,6 @@
   </div>
 </div>
 
-<link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script>
 var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];

From e73f4e03a0fe809088ec308de40ea5209508eabe Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 20:02:20 +0000
Subject: [PATCH 67/1001] Merge pull request #8 from meghanrichardson/develop


move css to separate file
---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
new file mode 100644
index 0000000..1bdbc82
--- /dev/null
+++ b/hubs/static/css/style.css
@@ -0,0 +1,40 @@
+   body {
+      background-color: #c;
+    }
+    .panel {
+      border-radius: 0px;
+    }
+    .header {
+      color: #ffffff;
+      background-color: #3c6eb4;
+      width: 100%;
+    }
+    .row {
+      padding: 5px;
+    }
+    .padded {
+      padding: 5px;
+    }
+    .medium-wide {
+      width: 250px;
+    }
+    h1, h2, h3, h4, h5, h6 {
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    .widget-buttons {
+      padding: 5px;
+      /* TODO -- lots more nice styling here... */
+    }
+    .panel {
+      visibility: hidden;
+      max-height: 0px;
+      overflow: hidden;
+      transition: max-height 0.4s;
+    }
+
+    .panel-visible {
+      visibility: visible;
+      max-height: 400px;
+    }
+
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index a201ef1..0bbfc90 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -1,48 +1,8 @@
 <html>
 <head>
   <title>{{ hub.name }}</title>
-  <style>
-    body {
-      background-color: #d1d3d4;
-    }
-    .panel {
-      border-radius: 0px;
-    }
-    .header {
-      color: #ffffff;
-      background-color: #3c6eb4;
-      width: 100%;
-    }
-    .row {
-      padding: 5px;
-    }
-    .padded {
-      padding: 5px;
-    }
-    .medium-wide {
-      width: 250px;
-    }
-    h1, h2, h3, h4, h5, h6 {
-      margin-top: 0px;
-      margin-bottom: 0px;
-    }
-    .widget-buttons {
-      padding: 5px;
-      /* TODO -- lots more nice styling here... */
-    }
-    .panel {
-      visibility: hidden;
-      max-height: 0px;
-      overflow: hidden;
-      transition: max-height 0.4s;
-    }
-
-    .panel-visible {
-      visibility: visible;
-      max-height: 400px;
-    }
-
-  </style>
+  <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
 </head>
 <body>
 <div class="header">
@@ -74,7 +34,6 @@
   </div>
 </div>
 
-<link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script>
 var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];

From 4d879275c640efb9886aa923aac137eb8546ac0c Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 20:24:28 +0000
Subject: [PATCH 68/1001] Add an avatar widget.


---

diff --git a/hubs/models.py b/hubs/models.py
index 7653c2e..6c4bacf 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -108,7 +108,12 @@ class Hub(BASE):
                             'text': 'TODO -- put a fancy graph here..',
                         }))
         hub.widgets.append(widget)
-        widget = Widget(plugin='sticky', index=0,
+        widget = Widget(plugin='avatar', index=0,
+                        _config=json.dumps({
+                            'username': username,
+                        }))
+        hub.widgets.append(widget)
+        widget = Widget(plugin='sticky', index=1,
                         _config=json.dumps({
                             'text': 'TODO -- your feed goes here.',
                         }))
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 0bbfc90..829b51c 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -48,6 +48,7 @@ $.each(widgets, function(i, widget) {
         }, 100);
       },
       error: function() {
+        $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
         console.log('error');
         console.trace();
       },
diff --git a/hubs/validators.py b/hubs/validators.py
index 9525da1..1079234 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -1,9 +1,15 @@
 import kitchen.text.converters
 
+import hubs.models
 
-def text(value):
+
+def text(session, value):
     return kitchen.text.converters.to_unicode(value)
 
-def link(value):
+def link(session, value):
     # TODO -- verify that this is actually a link
     return value
+
+def username(session, value):
+    openid = 'http://%s.id.fedoraproject.org/' % value
+    return not hubs.models.User.by_openid(session, openid) is None
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index f2268e7..044849e 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -3,6 +3,7 @@ from hubs.widgets import stats
 from hubs.widgets import rules
 from hubs.widgets import sticky
 from hubs.widgets import about
+from hubs.widgets import avatar
 
 from hubs.widgets.base import AGPLv3, smartcache
 
@@ -12,6 +13,7 @@ registry = {
     'rules': rules,
     'sticky': sticky,
     'about': about,
+    'avatar': avatar,
 }
 
 
diff --git a/hubs/widgets/avatar.py b/hubs/widgets/avatar.py
new file mode 100644
index 0000000..7360773
--- /dev/null
+++ b/hubs/widgets/avatar.py
@@ -0,0 +1,38 @@
+from hashlib import sha256
+
+from hubs.widgets.base import argument
+
+import jinja2
+
+from six.moves.urllib_parse import urlencode
+
+import hubs.validators as validators
+
+
+template = jinja2.Template("""
+<img class="img-responsive img-circle center-block" src="{{avatar}}">
+""")
+
+#from hubs.widgets.chrome import panel
+#chrome = panel("About")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+
+    query = urlencode({
+        'd': 'retro',
+        's': 312,
+    })
+    openid = 'http://%s.id.fedoraproject.org/' % username
+    hash = sha256(openid.encode('utf-8')).hexdigest()
+    avatar = "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)
+
+    return dict(username=username, avatar=avatar)
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 44a90d77003e5dcdb9bcee5a3c0e919b38d2182d Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jun 04 2015 20:25:46 +0000
Subject: [PATCH 69/1001] move login to upper right


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 0bbfc90..eae7194 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -5,6 +5,16 @@
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
 </head>
 <body>
+<div class="row">
+  <div class="col-md-4 col-md-offset-8">
+    {% if g.auth.logged_in %}
+      Logged in as {{ g.auth.nickname }}
+    {% else %}
+      Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
+    {% endif %}
+  </div>
+</div>
+blah blah bookmarks menu
 <div class="header">
   <div class="padded center-block medium-wide">
     <h3>{{hub.name}}</h3>
@@ -13,11 +23,6 @@
 </div>
 <div class="container">
   <div class="row">
-    {% if g.auth.logged_in %}
-    Logged in as {{ g.auth.nickname }}
-    {% else %}
-    Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
-    {% endif %}
   </div>
   <div class="row">
     <div class="col-md-{{ hub.left_width }}">

From 0506adf6ed60ea5a83afcfb8ca76828941fd9657 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jun 04 2015 20:26:08 +0000
Subject: [PATCH 70/1001] Merge branch 'develop' of github.com:ralphbean/fedora-hubs-prototype into develop


---

diff --git a/hubs/models.py b/hubs/models.py
index 7653c2e..6c4bacf 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -108,7 +108,12 @@ class Hub(BASE):
                             'text': 'TODO -- put a fancy graph here..',
                         }))
         hub.widgets.append(widget)
-        widget = Widget(plugin='sticky', index=0,
+        widget = Widget(plugin='avatar', index=0,
+                        _config=json.dumps({
+                            'username': username,
+                        }))
+        hub.widgets.append(widget)
+        widget = Widget(plugin='sticky', index=1,
                         _config=json.dumps({
                             'text': 'TODO -- your feed goes here.',
                         }))
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index eae7194..c3e68be 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -53,6 +53,7 @@ $.each(widgets, function(i, widget) {
         }, 100);
       },
       error: function() {
+        $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
         console.log('error');
         console.trace();
       },
diff --git a/hubs/validators.py b/hubs/validators.py
index 9525da1..1079234 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -1,9 +1,15 @@
 import kitchen.text.converters
 
+import hubs.models
 
-def text(value):
+
+def text(session, value):
     return kitchen.text.converters.to_unicode(value)
 
-def link(value):
+def link(session, value):
     # TODO -- verify that this is actually a link
     return value
+
+def username(session, value):
+    openid = 'http://%s.id.fedoraproject.org/' % value
+    return not hubs.models.User.by_openid(session, openid) is None
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index f2268e7..044849e 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -3,6 +3,7 @@ from hubs.widgets import stats
 from hubs.widgets import rules
 from hubs.widgets import sticky
 from hubs.widgets import about
+from hubs.widgets import avatar
 
 from hubs.widgets.base import AGPLv3, smartcache
 
@@ -12,6 +13,7 @@ registry = {
     'rules': rules,
     'sticky': sticky,
     'about': about,
+    'avatar': avatar,
 }
 
 
diff --git a/hubs/widgets/avatar.py b/hubs/widgets/avatar.py
new file mode 100644
index 0000000..7360773
--- /dev/null
+++ b/hubs/widgets/avatar.py
@@ -0,0 +1,38 @@
+from hashlib import sha256
+
+from hubs.widgets.base import argument
+
+import jinja2
+
+from six.moves.urllib_parse import urlencode
+
+import hubs.validators as validators
+
+
+template = jinja2.Template("""
+<img class="img-responsive img-circle center-block" src="{{avatar}}">
+""")
+
+#from hubs.widgets.chrome import panel
+#chrome = panel("About")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+
+    query = urlencode({
+        'd': 'retro',
+        's': 312,
+    })
+    openid = 'http://%s.id.fedoraproject.org/' % username
+    hash = sha256(openid.encode('utf-8')).hexdigest()
+    avatar = "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)
+
+    return dict(username=username, avatar=avatar)
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 45dba6d562a181a4f37980ffed2db769de49e67a Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 04 2015 20:50:07 +0000
Subject: [PATCH 71/1001] Added Badges widget, into __init__.py, and on personal hubs


---

diff --git a/hubs/models.py b/hubs/models.py
index 6c4bacf..d5c257f 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -118,6 +118,11 @@ class Hub(BASE):
                             'text': 'TODO -- your feed goes here.',
                         }))
         hub.widgets.append(widget)
+        widget = Widget(plugin='badges', index=2,
+                        _config=json.dumps({
+                            'username': username,
+                        }))
+        hub.widgets.append(widget)
 
     @property
     def right_width(self):
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 044849e..4d3dff9 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -4,6 +4,7 @@ from hubs.widgets import rules
 from hubs.widgets import sticky
 from hubs.widgets import about
 from hubs.widgets import avatar
+from hubs.widgets import badges
 
 from hubs.widgets.base import AGPLv3, smartcache
 
@@ -14,6 +15,7 @@ registry = {
     'sticky': sticky,
     'about': about,
     'avatar': avatar,
+    'badges': badges,
 }
 
 
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
new file mode 100644
index 0000000..0f44294
--- /dev/null
+++ b/hubs/widgets/badges.py
@@ -0,0 +1,35 @@
+import requests
+
+from hubs.widgets.base import argument
+
+import jinja2
+
+
+import hubs.validators as validators
+
+
+template = jinja2.Template("""
+{% for badge in assertions %}
+    <img src="{{badge['image']}}"/>
+{%endfor%}
+""")
+
+from hubs.widgets.chrome import panel
+chrome = panel("Badges")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    url = "https://badges.fedoraproject.org/user/{username}/json"
+    url = url.format(username=username)
+    response = requests.get(url)
+    import pprint; pprint.pprint(response.json())
+
+    return response.json()
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 4e379d71c1115ebbe30b2b2bfaf591cb04a33327 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 20:54:24 +0000
Subject: [PATCH 72/1001] Merge pull request #9 from decause/develop


Added Badges widget, into __init__.py, and on personal hubs
---

diff --git a/hubs/models.py b/hubs/models.py
index 6c4bacf..d5c257f 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -118,6 +118,11 @@ class Hub(BASE):
                             'text': 'TODO -- your feed goes here.',
                         }))
         hub.widgets.append(widget)
+        widget = Widget(plugin='badges', index=2,
+                        _config=json.dumps({
+                            'username': username,
+                        }))
+        hub.widgets.append(widget)
 
     @property
     def right_width(self):
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 044849e..4d3dff9 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -4,6 +4,7 @@ from hubs.widgets import rules
 from hubs.widgets import sticky
 from hubs.widgets import about
 from hubs.widgets import avatar
+from hubs.widgets import badges
 
 from hubs.widgets.base import AGPLv3, smartcache
 
@@ -14,6 +15,7 @@ registry = {
     'sticky': sticky,
     'about': about,
     'avatar': avatar,
+    'badges': badges,
 }
 
 
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
new file mode 100644
index 0000000..0f44294
--- /dev/null
+++ b/hubs/widgets/badges.py
@@ -0,0 +1,35 @@
+import requests
+
+from hubs.widgets.base import argument
+
+import jinja2
+
+
+import hubs.validators as validators
+
+
+template = jinja2.Template("""
+{% for badge in assertions %}
+    <img src="{{badge['image']}}"/>
+{%endfor%}
+""")
+
+from hubs.widgets.chrome import panel
+chrome = panel("Badges")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    url = "https://badges.fedoraproject.org/user/{username}/json"
+    url = url.format(username=username)
+    response = requests.get(url)
+    import pprint; pprint.pprint(response.json())
+
+    return response.json()
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 6694532aa808a4f6be14c2d3f0d354b250181fe1 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jun 04 2015 20:57:26 +0000
Subject: [PATCH 73/1001] header styles


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 1bdbc82..33fb3b6 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -1,9 +1,16 @@
    body {
-      background-color: #c;
+      background-color: #d1d3d4;
     }
     .panel {
       border-radius: 0px;
     }
+    .super-header {
+      text-align: right;
+      background: -moz-linear-gradient(rgba(255,255,255,0),rgba(255,255,255,1)); /*Fx 3.6-15*/
+    }
+    .bookmarks {
+      background-color: #fff;
+    }
     .header {
       color: #ffffff;
       background-color: #3c6eb4;
@@ -38,3 +45,10 @@
       max-height: 400px;
     }
 
+//flexbox support
+.flex-container {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+} 
+
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index c3e68be..da48e9e 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -5,16 +5,20 @@
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
 </head>
 <body>
-<div class="row">
-  <div class="col-md-4 col-md-offset-8">
-    {% if g.auth.logged_in %}
-      Logged in as {{ g.auth.nickname }}
-    {% else %}
-      Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
-    {% endif %}
+<div class="super-header">
+  <div class="row">
+    <div class="col-md-4 col-md-offset-8">
+      {% if g.auth.logged_in %}
+        Logged in as {{ g.auth.nickname }}
+      {% else %}
+        Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
+      {% endif %}
+    </div>
   </div>
 </div>
-blah blah bookmarks menu
+<div class="bookmarks">
+  naaav here eventuallyyyyyyy
+</div>
 <div class="header">
   <div class="padded center-block medium-wide">
     <h3>{{hub.name}}</h3>

From 6a7b183b97899cbf10d69b0f0502084aa5ba1e00 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jun 04 2015 20:57:42 +0000
Subject: [PATCH 74/1001] Merge branch 'develop' of github.com:ralphbean/fedora-hubs-prototype into develop


---

diff --git a/hubs/models.py b/hubs/models.py
index 6c4bacf..d5c257f 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -118,6 +118,11 @@ class Hub(BASE):
                             'text': 'TODO -- your feed goes here.',
                         }))
         hub.widgets.append(widget)
+        widget = Widget(plugin='badges', index=2,
+                        _config=json.dumps({
+                            'username': username,
+                        }))
+        hub.widgets.append(widget)
 
     @property
     def right_width(self):
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 044849e..4d3dff9 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -4,6 +4,7 @@ from hubs.widgets import rules
 from hubs.widgets import sticky
 from hubs.widgets import about
 from hubs.widgets import avatar
+from hubs.widgets import badges
 
 from hubs.widgets.base import AGPLv3, smartcache
 
@@ -14,6 +15,7 @@ registry = {
     'sticky': sticky,
     'about': about,
     'avatar': avatar,
+    'badges': badges,
 }
 
 
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
new file mode 100644
index 0000000..0f44294
--- /dev/null
+++ b/hubs/widgets/badges.py
@@ -0,0 +1,35 @@
+import requests
+
+from hubs.widgets.base import argument
+
+import jinja2
+
+
+import hubs.validators as validators
+
+
+template = jinja2.Template("""
+{% for badge in assertions %}
+    <img src="{{badge['image']}}"/>
+{%endfor%}
+""")
+
+from hubs.widgets.chrome import panel
+chrome = panel("Badges")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    url = "https://badges.fedoraproject.org/user/{username}/json"
+    url = url.format(username=username)
+    response = requests.get(url)
+    import pprint; pprint.pprint(response.json())
+
+    return response.json()
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 2559f02fa8698c90e4f99e72454bc2a9b30cd422 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 21:00:48 +0000
Subject: [PATCH 75/1001] Merge pull request #10 from meghanrichardson/develop


login styles / flexbox support
---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 1bdbc82..33fb3b6 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -1,9 +1,16 @@
    body {
-      background-color: #c;
+      background-color: #d1d3d4;
     }
     .panel {
       border-radius: 0px;
     }
+    .super-header {
+      text-align: right;
+      background: -moz-linear-gradient(rgba(255,255,255,0),rgba(255,255,255,1)); /*Fx 3.6-15*/
+    }
+    .bookmarks {
+      background-color: #fff;
+    }
     .header {
       color: #ffffff;
       background-color: #3c6eb4;
@@ -38,3 +45,10 @@
       max-height: 400px;
     }
 
+//flexbox support
+.flex-container {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+} 
+
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 829b51c..da48e9e 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -5,6 +5,20 @@
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
 </head>
 <body>
+<div class="super-header">
+  <div class="row">
+    <div class="col-md-4 col-md-offset-8">
+      {% if g.auth.logged_in %}
+        Logged in as {{ g.auth.nickname }}
+      {% else %}
+        Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
+      {% endif %}
+    </div>
+  </div>
+</div>
+<div class="bookmarks">
+  naaav here eventuallyyyyyyy
+</div>
 <div class="header">
   <div class="padded center-block medium-wide">
     <h3>{{hub.name}}</h3>
@@ -13,11 +27,6 @@
 </div>
 <div class="container">
   <div class="row">
-    {% if g.auth.logged_in %}
-    Logged in as {{ g.auth.nickname }}
-    {% else %}
-    Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
-    {% endif %}
   </div>
   <div class="row">
     <div class="col-md-{{ hub.left_width }}">

From 9549f6e8c6692cf6a3a898e29dbf0d7bcdb0b1e8 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 04 2015 21:06:06 +0000
Subject: [PATCH 76/1001] We have a working badges widget!


---

diff --git a/hubs/app.py b/hubs/app.py
index 2fee16a..e914bfa 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -73,12 +73,6 @@ def get_widget(session, hub, idx):
 def widget_render(hub, idx):
     widget = get_widget(session, hub, idx)
 
-    # Make this artificially slow for development...
-    import random, time
-    s = (random.random() * 3) + 1
-    print(widget.plugin, "sleeping artificially for", s)
-    time.sleep(s)
-
     return widget.render(session)
 
 
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index 0f44294..976a137 100644
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -9,9 +9,11 @@ import hubs.validators as validators
 
 
 template = jinja2.Template("""
+<div class="flex-container">
 {% for badge in assertions %}
-    <img src="{{badge['image']}}"/>
+    <img width="19%" src="{{badge['image']}}"/>
 {%endfor%}
+</div>
 """)
 
 from hubs.widgets.chrome import panel

From d516ff78bffbae3872ea65ad68cdb9b030ae6e58 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 21:12:58 +0000
Subject: [PATCH 77/1001] Remove pprint.


---

diff --git a/hubs/app.py b/hubs/app.py
index e914bfa..621d3e0 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -72,7 +72,6 @@ def get_widget(session, hub, idx):
 @app.route('/<hub>/<idx>/')
 def widget_render(hub, idx):
     widget = get_widget(session, hub, idx)
-
     return widget.render(session)
 
 
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index 976a137..14ed116 100644
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -28,8 +28,6 @@ def data(session, widget, username):
     url = "https://badges.fedoraproject.org/user/{username}/json"
     url = url.format(username=username)
     response = requests.get(url)
-    import pprint; pprint.pprint(response.json())
-
     return response.json()
 
 

From 706c607f29146867705292efe9527e4236fb7f49 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jun 04 2015 21:33:03 +0000
Subject: [PATCH 78/1001] more styles git add static/css/style.css templates/hubs.html


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 33fb3b6..f418cc9 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -6,10 +6,18 @@
     }
     .super-header {
       text-align: right;
-      background: -moz-linear-gradient(rgba(255,255,255,0),rgba(255,255,255,1)); /*Fx 3.6-15*/
-    }
-    .bookmarks {
+      background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
+      background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
+      background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
+      background: linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
+      padding: 20px 20px 20px 0;
+      font-family: 'Open Sans', 'sans-serif';
+      font-size: 12pt;
+    }
+    .bookmarks .navbar.navbar-default {
       background-color: #fff;
+      margin-bottom: 0;
+      text-align: center;
     }
     .header {
       color: #ffffff;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index da48e9e..38313c1 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -3,13 +3,15 @@
   <title>{{ hub.name }}</title>
   <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
+  <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic|Comfortaa' rel='stylesheet' type='text/css'>
+<!--I added google fonts!!!! Sorry if I wasn't supposed to do that!!! -->
 </head>
 <body>
 <div class="super-header">
   <div class="row">
     <div class="col-md-4 col-md-offset-8">
       {% if g.auth.logged_in %}
-        Logged in as {{ g.auth.nickname }}
+        {# Logged in as #} {{ g.auth.nickname }}
       {% else %}
         Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
       {% endif %}
@@ -17,7 +19,33 @@
   </div>
 </div>
 <div class="bookmarks">
-  naaav here eventuallyyyyyyy
+  <nav class="navbar navbar-default">
+    <div class="container-fluid">
+      <!-- Brand and toggle get grouped for better mobile display -->
+      <div class="navbar-header">
+        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+          <span class="sr-only">Toggle navigation</span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+        </button>
+        <a class="navbar-brand" href="#">Fedora Hubs</a>
+      </div>
+
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav">
+          <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
+          <li><a href="#">Link</a></li>
+          <li><a href="#">Action</a></li>
+          <li><a href="#">Another action</a></li>
+          <li><a href="#">Something else here</a></li>
+          <li class="divider"></li>
+          <li><a href="#">Separated link</a></li>          
+        </ul>
+      </div><!-- /.navbar-collapse -->
+    </div><!-- /.container-fluid -->
+  </nav>
 </div>
 <div class="header">
   <div class="padded center-block medium-wide">

From f40a8445cc172a56992c51ba7f4c81c3fee1258f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 21:41:46 +0000
Subject: [PATCH 79/1001] Merge pull request #11 from meghanrichardson/develop


more styles
---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 33fb3b6..f418cc9 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -6,10 +6,18 @@
     }
     .super-header {
       text-align: right;
-      background: -moz-linear-gradient(rgba(255,255,255,0),rgba(255,255,255,1)); /*Fx 3.6-15*/
-    }
-    .bookmarks {
+      background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
+      background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
+      background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
+      background: linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
+      padding: 20px 20px 20px 0;
+      font-family: 'Open Sans', 'sans-serif';
+      font-size: 12pt;
+    }
+    .bookmarks .navbar.navbar-default {
       background-color: #fff;
+      margin-bottom: 0;
+      text-align: center;
     }
     .header {
       color: #ffffff;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index da48e9e..38313c1 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -3,13 +3,15 @@
   <title>{{ hub.name }}</title>
   <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
+  <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic|Comfortaa' rel='stylesheet' type='text/css'>
+<!--I added google fonts!!!! Sorry if I wasn't supposed to do that!!! -->
 </head>
 <body>
 <div class="super-header">
   <div class="row">
     <div class="col-md-4 col-md-offset-8">
       {% if g.auth.logged_in %}
-        Logged in as {{ g.auth.nickname }}
+        {# Logged in as #} {{ g.auth.nickname }}
       {% else %}
         Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
       {% endif %}
@@ -17,7 +19,33 @@
   </div>
 </div>
 <div class="bookmarks">
-  naaav here eventuallyyyyyyy
+  <nav class="navbar navbar-default">
+    <div class="container-fluid">
+      <!-- Brand and toggle get grouped for better mobile display -->
+      <div class="navbar-header">
+        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+          <span class="sr-only">Toggle navigation</span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+        </button>
+        <a class="navbar-brand" href="#">Fedora Hubs</a>
+      </div>
+
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav">
+          <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
+          <li><a href="#">Link</a></li>
+          <li><a href="#">Action</a></li>
+          <li><a href="#">Another action</a></li>
+          <li><a href="#">Something else here</a></li>
+          <li class="divider"></li>
+          <li><a href="#">Separated link</a></li>          
+        </ul>
+      </div><!-- /.navbar-collapse -->
+    </div><!-- /.container-fluid -->
+  </nav>
 </div>
 <div class="header">
   <div class="padded center-block medium-wide">

From 1409672fe1bfae09262e6cb396fbc57e7ac0c660 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 04 2015 21:51:19 +0000
Subject: [PATCH 80/1001] Point source url at pagure.


---

diff --git a/hubs/app.py b/hubs/app.py
index 621d3e0..9ef867d 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -14,7 +14,7 @@ app = flask.Flask(__name__)
 # TODO - put this in config so we can migrate to pagure
 # TODO - instead of 'develop', use the version from pkg_resources to figure out
 #        the right tag to link people to.  AGPL ftw.
-SOURCE_URL = 'https://github.com/ralphbean/fedora-hubs-prototype/blob/develop'
+SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'#/hubs/widgets/badges.py'
 
 
 app.config.from_object('hubs.default_config')
@@ -97,7 +97,8 @@ def widget_json(hub, idx):
 def widget_source(name):
     from hubs.widgets import registry
     base = '/hubs/'
-    fname = base + registry[name].__file__.split(base, 1)[1][:-1]
+    fname = base + registry[name].__file__.split(base, 1)[1]
+    fname = fname.replace('.pyc', '.py')
     return flask.redirect(SOURCE_URL + fname)
 
 

From 4a82cbebc8790ad11dedf0f426d49e57f3f0ce82 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 05 2015 16:33:28 +0000
Subject: [PATCH 81/1001] Pendingacls workflow widget.


---

diff --git a/hubs/models.py b/hubs/models.py
index d5c257f..87ddada 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -113,9 +113,11 @@ class Hub(BASE):
                             'username': username,
                         }))
         hub.widgets.append(widget)
-        widget = Widget(plugin='sticky', index=1,
+        widget = Widget(plugin='workflow.pendingacls', index=1,
                         _config=json.dumps({
-                            'text': 'TODO -- your feed goes here.',
+                            # Only because he has pendingacls to test against
+                            'username': 'vicodan',
+                            #'username': username,
                         }))
         hub.widgets.append(widget)
         widget = Widget(plugin='badges', index=2,
diff --git a/hubs/utils.py b/hubs/utils.py
new file mode 100644
index 0000000..35bf44a
--- /dev/null
+++ b/hubs/utils.py
@@ -0,0 +1,14 @@
+from hashlib import sha256
+
+from six.moves.urllib_parse import urlencode
+
+
+def username2avatar(username, s=312):
+    query = urlencode({
+        'd': 'retro',
+        's': s,
+    })
+    openid = 'http://%s.id.fedoraproject.org/' % username
+    hash = sha256(openid.encode('utf-8')).hexdigest()
+    avatar = "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)
+    return avatar
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 4d3dff9..51ed1b1 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -6,6 +6,8 @@ from hubs.widgets import about
 from hubs.widgets import avatar
 from hubs.widgets import badges
 
+from hubs.widgets.workflow import pendingacls
+
 from hubs.widgets.base import AGPLv3, smartcache
 
 registry = {
@@ -16,6 +18,8 @@ registry = {
     'about': about,
     'avatar': avatar,
     'badges': badges,
+
+    'workflow.pendingacls': pendingacls,
 }
 
 
diff --git a/hubs/widgets/avatar.py b/hubs/widgets/avatar.py
index 7360773..20c12ab 100644
--- a/hubs/widgets/avatar.py
+++ b/hubs/widgets/avatar.py
@@ -1,11 +1,8 @@
-from hashlib import sha256
-
 from hubs.widgets.base import argument
+from hubs.utils import username2avatar
 
 import jinja2
 
-from six.moves.urllib_parse import urlencode
-
 import hubs.validators as validators
 
 
@@ -22,15 +19,7 @@ template = jinja2.Template("""
           validator=validators.username,
           help="A FAS username.")
 def data(session, widget, username):
-
-    query = urlencode({
-        'd': 'retro',
-        's': 312,
-    })
-    openid = 'http://%s.id.fedoraproject.org/' % username
-    hash = sha256(openid.encode('utf-8')).hexdigest()
-    avatar = "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)
-
+    avatar = username2avatar(username)
     return dict(username=username, avatar=avatar)
 
 
diff --git a/hubs/widgets/workflow/__init__.py b/hubs/widgets/workflow/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/widgets/workflow/__init__.py
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
new file mode 100644
index 0000000..40149e4
--- /dev/null
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -0,0 +1,53 @@
+import requests
+
+from hubs.widgets.base import argument
+from hubs.utils import username2avatar
+
+import jinja2
+
+
+import hubs.validators as validators
+
+# TODO -- add approve/deny buttons or just link through to pkgdb
+template = jinja2.Template("""
+{% if pending_acls %}
+<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/pkgdb/acl/pending/">Manage requests</a>
+<hr/>
+<ul class="media-list">
+{% for acl in pending_acls %}
+    <li class="media">
+        <div class="media-left">
+            <img class="media-object img-responsive img-circle" src="{{acl['avatar']}}"/>
+        </div>
+        <div class="media-body">
+            <h4 class="media-heading">{{acl['user']}} is {{acl['status']}}</h4>
+            for {{acl['acl']}} on
+            {{acl['package']}}({{acl['collection']}})
+        </div>
+    </li>
+{% endfor %}
+</ul>
+{% endif %}
+""")
+
+from hubs.widgets.chrome import panel
+chrome = panel("Pending ACLs")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    baseurl = "https://admin.fedoraproject.org/pkgdb/api/pendingacls"
+    query = "?username={username}&format=json".format(username=username)
+    url = baseurl + query
+    response = requests.get(url)
+    data = response.json()
+    for acl in data['pending_acls']:
+        acl['avatar'] = username2avatar(acl['user'], s=32)
+    return data
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 307f112d518b11be27e27eca1bbb6eff12302e6f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 05 2015 17:41:33 +0000
Subject: [PATCH 82/1001] Hide chrome if there is no content.


---

diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 4ea42c6..de38df1 100644
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -25,7 +25,7 @@ _panel_heading_template = jinja2.Template("""
 """)
 
 
-def panel(title=None, klass="panel-default"):
+def panel(title=None, klass="panel-default", key=None):
     def decorator(func):
         @wraps(func)
         def inner(*args, **kwargs):
@@ -33,6 +33,8 @@ def panel(title=None, klass="panel-default"):
             if title:
                 heading = _panel_heading_template.render(title=title)
             content = func(*args, **kwargs)
+            if key and not kwargs.get(key):
+                return content
             return _panel_template.render(
                 content=content,
                 heading=heading,
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 40149e4..ad79a7e 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -31,7 +31,8 @@ template = jinja2.Template("""
 """)
 
 from hubs.widgets.chrome import panel
-chrome = panel("Pending ACLs")
+# If 'pending_acls' is empty, then don't render any chrome.
+chrome = panel('Pending ACL Requests', key='pending_acls')
 
 
 @argument(name="username",

From 0a11b8164b628ba003529558200726f64037d313 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 05 2015 17:41:51 +0000
Subject: [PATCH 83/1001] Go back to using the real username.


---

diff --git a/hubs/models.py b/hubs/models.py
index 87ddada..424f6a0 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -115,9 +115,7 @@ class Hub(BASE):
         hub.widgets.append(widget)
         widget = Widget(plugin='workflow.pendingacls', index=1,
                         _config=json.dumps({
-                            # Only because he has pendingacls to test against
-                            'username': 'vicodan',
-                            #'username': username,
+                            'username': username,
                         }))
         hub.widgets.append(widget)
         widget = Widget(plugin='badges', index=2,

From ba919f1ba6a9f482aa1a0173fc2f09be0b41da2b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 05 2015 17:42:17 +0000
Subject: [PATCH 84/1001] A note for the future.


---

diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index ad79a7e..8f40a86 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -40,6 +40,13 @@ chrome = panel('Pending ACL Requests', key='pending_acls')
           validator=validators.username,
           help="A FAS username.")
 def data(session, widget, username):
+
+    # TODO -- rewrite this to
+    # 1) use the datagrepper API instead of the direct pkgdb API
+    # 2) so that we can use the fedmsg.meta.conglomerate API to
+    # 3) group messages nicely in the UI instead of having repeats
+    # It will be slower, but that's fine because of our smart cache.
+
     baseurl = "https://admin.fedoraproject.org/pkgdb/api/pendingacls"
     query = "?username={username}&format=json".format(username=username)
     url = baseurl + query

From 1755d2b7935c27c52101a2566fca4f6dcf4ea82e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 07 2015 15:07:28 +0000
Subject: [PATCH 85/1001] Move defaults to a common file.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
new file mode 100644
index 0000000..cae90a0
--- /dev/null
+++ b/hubs/defaults.py
@@ -0,0 +1,32 @@
+import json
+
+import hubs.models
+
+
+def add_user_widgets(session, hub, username, fullname):
+    """ Some defaults for an individual user's hub. """
+    widget = hubs.models.Widget(
+        plugin='sticky', index=0, left=True,
+        _config=json.dumps({
+            'text': 'TODO -- put a fancy graph here..',
+        }))
+    hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='avatar', index=0,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='workflow.pendingacls', index=1,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='badges', index=2,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+    return hub
diff --git a/hubs/models.py b/hubs/models.py
index 424f6a0..b129f5d 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -36,6 +36,7 @@ from sqlalchemy.orm import backref
 import fedmsg
 import fedmsg.utils
 
+import hubs.defaults
 import hubs.widgets
 
 
@@ -102,27 +103,7 @@ class Hub(BASE):
     def create_user_hub(cls, session, username, fullname):
         hub = cls(name=username, summary=fullname)
         session.add(hub)
-
-        widget = Widget(plugin='sticky', index=0, left=True,
-                        _config=json.dumps({
-                            'text': 'TODO -- put a fancy graph here..',
-                        }))
-        hub.widgets.append(widget)
-        widget = Widget(plugin='avatar', index=0,
-                        _config=json.dumps({
-                            'username': username,
-                        }))
-        hub.widgets.append(widget)
-        widget = Widget(plugin='workflow.pendingacls', index=1,
-                        _config=json.dumps({
-                            'username': username,
-                        }))
-        hub.widgets.append(widget)
-        widget = Widget(plugin='badges', index=2,
-                        _config=json.dumps({
-                            'username': username,
-                        }))
-        hub.widgets.append(widget)
+        hubs.defaults.add_user_widgets(session, hub, username, fullname)
 
     @property
     def right_width(self):

From b6a1b33113287e61093b465dd51999ba80c30455 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 07 2015 19:17:48 +0000
Subject: [PATCH 86/1001] Fedmsgs widget created Unhard-code the max-height. Removal breaks the things.


Rudimentary fedmsgs graph widget

Added fedmsgs widget

Added fedmsgs widget to __init__.py

---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index cae90a0..da41b82 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -8,10 +8,18 @@ def add_user_widgets(session, hub, username, fullname):
     widget = hubs.models.Widget(
         plugin='sticky', index=0, left=True,
         _config=json.dumps({
-            'text': 'TODO -- put a fancy graph here..',
+            'text': 'TODO -- Put a fancy graph here...',
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
+        plugin='fedmsgs', index=1, left=True,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+
+    # Right Side Widgets
+    widget = hubs.models.Widget(
         plugin='avatar', index=0,
         _config=json.dumps({
             'username': username,
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index f418cc9..9ef6dae 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -50,7 +50,7 @@
 
     .panel-visible {
       visibility: visible;
-      max-height: 400px;
+      max-height: 100%;
     }
 
 //flexbox support
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 51ed1b1..2bb8570 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -5,6 +5,7 @@ from hubs.widgets import sticky
 from hubs.widgets import about
 from hubs.widgets import avatar
 from hubs.widgets import badges
+from hubs.widgets import fedmsgs
 
 from hubs.widgets.workflow import pendingacls
 
@@ -18,7 +19,7 @@ registry = {
     'about': about,
     'avatar': avatar,
     'badges': badges,
-
+    'fedmsgs': fedmsgs,
     'workflow.pendingacls': pendingacls,
 }
 
diff --git a/hubs/widgets/fedmsgs.py b/hubs/widgets/fedmsgs.py
new file mode 100644
index 0000000..ae07a7d
--- /dev/null
+++ b/hubs/widgets/fedmsgs.py
@@ -0,0 +1,32 @@
+from hubs.widgets.base import argument
+
+import jinja2
+
+
+import hubs.validators as validators
+
+
+template = jinja2.Template("""
+<div class="flex-container">
+
+    <img src="{{url}}" />
+
+</div>
+""")
+
+from hubs.widgets.chrome import panel
+chrome = panel("Daily Activity")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    url = "https://apps.fedoraproject.org/datagrepper/charts/line?delta=86400&N=12&style=clean&height=200&fill=true&user={username}"
+    url = url.format(username=username)
+    return dict(url=url)
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From f999eeac716da09b3f0ed62615fe7fbc54c89b6c Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 07 2015 19:18:05 +0000
Subject: [PATCH 87/1001] pace-ery


---

diff --git a/hubs/static/css/pace-theme-minimal.css b/hubs/static/css/pace-theme-minimal.css
new file mode 100644
index 0000000..b12e450
--- /dev/null
+++ b/hubs/static/css/pace-theme-minimal.css
@@ -0,0 +1,30 @@
+/*Copyright (c) 2013 HubSpot, Inc.
+
+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.
+*/
+.pace {
+  -webkit-pointer-events: none;
+  pointer-events: none;
+
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
+
+.pace-inactive {
+  display: none;
+}
+
+.pace .pace-progress {
+  background: #29d;
+  position: fixed;
+  z-index: 2000;
+  top: 0;
+  right: 100%;
+  width: 100%;
+  height: 2px;
+}
diff --git a/hubs/static/js/pace.min.js b/hubs/static/js/pace.min.js
new file mode 100644
index 0000000..270c5ec
--- /dev/null
+++ b/hubs/static/js/pace.min.js
@@ -0,0 +1,10 @@
+/*Copyright (c) 2013 HubSpot, Inc.
+
+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.
+*/
+/*! pace 1.0.0 */
+(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X=[].slice,Y={}.hasOwnProperty,Z=function(a,b){function c(){this.constructor=a}for(var d in b)Y.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},$=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};for(u={catchupTime:100,initialRate:.03,minTime:250,ghostTime:100,maxProgressPerFrame:20,easeFactor:1.25,startOnPageLoad:!0,restartOnPushState:!0,restartOnRequestAfter:500,target:"body",elements:{checkInterval:100,selectors:["body"]},eventLag:{minSamples:10,sampleCount:3,lagThreshold:3},ajax:{trackMethods:["GET"],trackWebSockets:!0,ignoreURLs:[]}},C=function(){var a;return null!=(a="undefined"!=typeof performance&&null!==performance&&"function"==typeof performance.now?performance.now():void 0)?a:+new Date},E=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame,null==E&&(E=function(a){return setTimeout(a,50)},t=function(a){return clearTimeout(a)}),G=function(a){var b,c;return b=C(),(c=function(){var d;return d=C()-b,d>=33?(b=C(),a(d,function(){return E(c)})):setTimeout(c,33-d)})()},F=function(){var a,b,c;return c=arguments[0],b=arguments[1],a=3<=arguments.length?X.call(arguments,2):[],"function"==typeof c[b]?c[b].apply(c,a):c[b]},v=function(){var a,b,c,d,e,f,g;for(b=arguments[0],d=2<=arguments.length?X.call(arguments,1):[],f=0,g=d.length;g>f;f++)if(c=d[f])for(a in c)Y.call(c,a)&&(e=c[a],null!=b[a]&&"object"==typeof b[a]&&null!=e&&"object"==typeof e?v(b[a],e):b[a]=e);return b},q=function(a){var b,c,d,e,f;for(c=b=0,e=0,f=a.length;f>e;e++)d=a[e],c+=Math.abs(d),b++;return c/b},x=function(a,b){var c,d,e;if(null==a&&(a="options"),null==b&&(b=!0),e=document.querySelector("[data-pace-"+a+"]")){if(c=e.getAttribute("data-pace-"+a),!b)return c;try{return JSON.parse(c)}catch(f){return d=f,"undefined"!=typeof console&&null!==console?console.error("Error parsing inline pace options",d):void 0}}},g=function(){function a(){}return a.prototype.on=function(a,b,c,d){var e;return null==d&&(d=!1),null==this.bindings&&(this.bindings={}),null==(e=this.bindings)[a]&&(e[a]=[]),this.bindings[a].push({handler:b,ctx:c,once:d})},a.prototype.once=function(a,b,c){return this.on(a,b,c,!0)},a.prototype.off=function(a,b){var c,d,e;if(null!=(null!=(d=this.bindings)?d[a]:void 0)){if(null==b)return delete this.bindings[a];for(c=0,e=[];c<this.bindings[a].length;)e.push(this.bindings[a][c].handler===b?this.bindings[a].splice(c,1):c++);return e}},a.prototype.trigger=function(){var a,b,c,d,e,f,g,h,i;if(c=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],null!=(g=this.bindings)?g[c]:void 0){for(e=0,i=[];e<this.bindings[c].length;)h=this.bindings[c][e],d=h.handler,b=h.ctx,f=h.once,d.apply(null!=b?b:this,a),i.push(f?this.bindings[c].splice(e,1):e++);return i}},a}(),j=window.Pace||{},window.Pace=j,v(j,g.prototype),D=j.options=v({},u,window.paceOptions,x()),U=["ajax","document","eventLag","elements"],Q=0,S=U.length;S>Q;Q++)K=U[Q],D[K]===!0&&(D[K]=u[K]);i=function(a){function b(){return V=b.__super__.constructor.apply(this,arguments)}return Z(b,a),b}(Error),b=function(){function a(){this.progress=0}return a.prototype.getElement=function(){var a;if(null==this.el){if(a=document.querySelector(D.target),!a)throw new i;this.el=document.createElement("div"),this.el.className="pace pace-active",document.body.className=document.body.className.replace(/pace-done/g,""),document.body.className+=" pace-running",this.el.innerHTML='<div class="pace-progress">\n  <div class="pace-progress-inner"></div>\n</div>\n<div class="pace-activity"></div>',null!=a.firstChild?a.insertBefore(this.el,a.firstChild):a.appendChild(this.el)}return this.el},a.prototype.finish=function(){var a;return a=this.getElement(),a.className=a.className.replace("pace-active",""),a.className+=" pace-inactive",document.body.className=document.body.className.replace("pace-running",""),document.body.className+=" pace-done"},a.prototype.update=function(a){return this.progress=a,this.render()},a.prototype.destroy=function(){try{this.getElement().parentNode.removeChild(this.getElement())}catch(a){i=a}return this.el=void 0},a.prototype.render=function(){var a,b,c,d,e,f,g;if(null==document.querySelector(D.target))return!1;for(a=this.getElement(),d="translate3d("+this.progress+"%, 0, 0)",g=["webkitTransform","msTransform","transform"],e=0,f=g.length;f>e;e++)b=g[e],a.children[0].style[b]=d;return(!this.lastRenderedProgress||this.lastRenderedProgress|0!==this.progress|0)&&(a.children[0].setAttribute("data-progress-text",""+(0|this.progress)+"%"),this.progress>=100?c="99":(c=this.progress<10?"0":"",c+=0|this.progress),a.children[0].setAttribute("data-progress",""+c)),this.lastRenderedProgress=this.progress},a.prototype.done=function(){return this.progress>=100},a}(),h=function(){function a(){this.bindings={}}return a.prototype.trigger=function(a,b){var c,d,e,f,g;if(null!=this.bindings[a]){for(f=this.bindings[a],g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(c.call(this,b));return g}},a.prototype.on=function(a,b){var c;return null==(c=this.bindings)[a]&&(c[a]=[]),this.bindings[a].push(b)},a}(),P=window.XMLHttpRequest,O=window.XDomainRequest,N=window.WebSocket,w=function(a,b){var c,d,e,f;f=[];for(d in b.prototype)try{e=b.prototype[d],f.push(null==a[d]&&"function"!=typeof e?a[d]=e:void 0)}catch(g){c=g}return f},A=[],j.ignore=function(){var a,b,c;return b=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],A.unshift("ignore"),c=b.apply(null,a),A.shift(),c},j.track=function(){var a,b,c;return b=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],A.unshift("track"),c=b.apply(null,a),A.shift(),c},J=function(a){var b;if(null==a&&(a="GET"),"track"===A[0])return"force";if(!A.length&&D.ajax){if("socket"===a&&D.ajax.trackWebSockets)return!0;if(b=a.toUpperCase(),$.call(D.ajax.trackMethods,b)>=0)return!0}return!1},k=function(a){function b(){var a,c=this;b.__super__.constructor.apply(this,arguments),a=function(a){var b;return b=a.open,a.open=function(d,e){return J(d)&&c.trigger("request",{type:d,url:e,request:a}),b.apply(a,arguments)}},window.XMLHttpRequest=function(b){var c;return c=new P(b),a(c),c};try{w(window.XMLHttpRequest,P)}catch(d){}if(null!=O){window.XDomainRequest=function(){var b;return b=new O,a(b),b};try{w(window.XDomainRequest,O)}catch(d){}}if(null!=N&&D.ajax.trackWebSockets){window.WebSocket=function(a,b){var d;return d=null!=b?new N(a,b):new N(a),J("socket")&&c.trigger("request",{type:"socket",url:a,protocols:b,request:d}),d};try{w(window.WebSocket,N)}catch(d){}}}return Z(b,a),b}(h),R=null,y=function(){return null==R&&(R=new k),R},I=function(a){var b,c,d,e;for(e=D.ajax.ignoreURLs,c=0,d=e.length;d>c;c++)if(b=e[c],"string"==typeof b){if(-1!==a.indexOf(b))return!0}else if(b.test(a))return!0;return!1},y().on("request",function(b){var c,d,e,f,g;return f=b.type,e=b.request,g=b.url,I(g)?void 0:j.running||D.restartOnRequestAfter===!1&&"force"!==J(f)?void 0:(d=arguments,c=D.restartOnRequestAfter||0,"boolean"==typeof c&&(c=0),setTimeout(function(){var b,c,g,h,i,k;if(b="socket"===f?e.readyState<2:0<(h=e.readyState)&&4>h){for(j.restart(),i=j.sources,k=[],c=0,g=i.length;g>c;c++){if(K=i[c],K instanceof a){K.watch.apply(K,d);break}k.push(void 0)}return k}},c))}),a=function(){function a(){var a=this;this.elements=[],y().on("request",function(){return a.watch.apply(a,arguments)})}return a.prototype.watch=function(a){var b,c,d,e;return d=a.type,b=a.request,e=a.url,I(e)?void 0:(c="socket"===d?new n(b):new o(b),this.elements.push(c))},a}(),o=function(){function a(a){var b,c,d,e,f,g,h=this;if(this.progress=0,null!=window.ProgressEvent)for(c=null,a.addEventListener("progress",function(a){return h.progress=a.lengthComputable?100*a.loaded/a.total:h.progress+(100-h.progress)/2},!1),g=["load","abort","timeout","error"],d=0,e=g.length;e>d;d++)b=g[d],a.addEventListener(b,function(){return h.progress=100},!1);else f=a.onreadystatechange,a.onreadystatechange=function(){var b;return 0===(b=a.readyState)||4===b?h.progress=100:3===a.readyState&&(h.progress=50),"function"==typeof f?f.apply(null,arguments):void 0}}return a}(),n=function(){function a(a){var b,c,d,e,f=this;for(this.progress=0,e=["error","open"],c=0,d=e.length;d>c;c++)b=e[c],a.addEventListener(b,function(){return f.progress=100},!1)}return a}(),d=function(){function a(a){var b,c,d,f;for(null==a&&(a={}),this.elements=[],null==a.selectors&&(a.selectors=[]),f=a.selectors,c=0,d=f.length;d>c;c++)b=f[c],this.elements.push(new e(b))}return a}(),e=function(){function a(a){this.selector=a,this.progress=0,this.check()}return a.prototype.check=function(){var a=this;return document.querySelector(this.selector)?this.done():setTimeout(function(){return a.check()},D.elements.checkInterval)},a.prototype.done=function(){return this.progress=100},a}(),c=function(){function a(){var a,b,c=this;this.progress=null!=(b=this.states[document.readyState])?b:100,a=document.onreadystatechange,document.onreadystatechange=function(){return null!=c.states[document.readyState]&&(c.progress=c.states[document.readyState]),"function"==typeof a?a.apply(null,arguments):void 0}}return a.prototype.states={loading:0,interactive:50,complete:100},a}(),f=function(){function a(){var a,b,c,d,e,f=this;this.progress=0,a=0,e=[],d=0,c=C(),b=setInterval(function(){var g;return g=C()-c-50,c=C(),e.push(g),e.length>D.eventLag.sampleCount&&e.shift(),a=q(e),++d>=D.eventLag.minSamples&&a<D.eventLag.lagThreshold?(f.progress=100,clearInterval(b)):f.progress=100*(3/(a+3))},50)}return a}(),m=function(){function a(a){this.source=a,this.last=this.sinceLastUpdate=0,this.rate=D.initialRate,this.catchup=0,this.progress=this.lastProgress=0,null!=this.source&&(this.progress=F(this.source,"progress"))}return a.prototype.tick=function(a,b){var c;return null==b&&(b=F(this.source,"progress")),b>=100&&(this.done=!0),b===this.last?this.sinceLastUpdate+=a:(this.sinceLastUpdate&&(this.rate=(b-this.last)/this.sinceLastUpdate),this.catchup=(b-this.progress)/D.catchupTime,this.sinceLastUpdate=0,this.last=b),b>this.progress&&(this.progress+=this.catchup*a),c=1-Math.pow(this.progress/100,D.easeFactor),this.progress+=c*this.rate*a,this.progress=Math.min(this.lastProgress+D.maxProgressPerFrame,this.progress),this.progress=Math.max(0,this.progress),this.progress=Math.min(100,this.progress),this.lastProgress=this.progress,this.progress},a}(),L=null,H=null,r=null,M=null,p=null,s=null,j.running=!1,z=function(){return D.restartOnPushState?j.restart():void 0},null!=window.history.pushState&&(T=window.history.pushState,window.history.pushState=function(){return z(),T.apply(window.history,arguments)}),null!=window.history.replaceState&&(W=window.history.replaceState,window.history.replaceState=function(){return z(),W.apply(window.history,arguments)}),l={ajax:a,elements:d,document:c,eventLag:f},(B=function(){var a,c,d,e,f,g,h,i;for(j.sources=L=[],g=["ajax","elements","document","eventLag"],c=0,e=g.length;e>c;c++)a=g[c],D[a]!==!1&&L.push(new l[a](D[a]));for(i=null!=(h=D.extraSources)?h:[],d=0,f=i.length;f>d;d++)K=i[d],L.push(new K(D));return j.bar=r=new b,H=[],M=new m})(),j.stop=function(){return j.trigger("stop"),j.running=!1,r.destroy(),s=!0,null!=p&&("function"==typeof t&&t(p),p=null),B()},j.restart=function(){return j.trigger("restart"),j.stop(),j.start()},j.go=function(){var a;return j.running=!0,r.render(),a=C(),s=!1,p=G(function(b,c){var d,e,f,g,h,i,k,l,n,o,p,q,t,u,v,w;for(l=100-r.progress,e=p=0,f=!0,i=q=0,u=L.length;u>q;i=++q)for(K=L[i],o=null!=H[i]?H[i]:H[i]=[],h=null!=(w=K.elements)?w:[K],k=t=0,v=h.length;v>t;k=++t)g=h[k],n=null!=o[k]?o[k]:o[k]=new m(g),f&=n.done,n.done||(e++,p+=n.tick(b));return d=p/e,r.update(M.tick(b,d)),r.done()||f||s?(r.update(100),j.trigger("done"),setTimeout(function(){return r.finish(),j.running=!1,j.trigger("hide")},Math.max(D.ghostTime,Math.max(D.minTime-(C()-a),0)))):c()})},j.start=function(a){v(D,a),j.running=!0;try{r.render()}catch(b){i=b}return document.querySelector(".pace")?(j.trigger("start"),j.go()):setTimeout(j.start,50)},"function"==typeof define&&define.amd?define(function(){return j}):"object"==typeof exports?module.exports=j:D.startOnPageLoad&&j.start()}).call(this);
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 38313c1..d178a0e 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -3,9 +3,11 @@
   <title>{{ hub.name }}</title>
   <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
   <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic|Comfortaa' rel='stylesheet' type='text/css'>
 <!--I added google fonts!!!! Sorry if I wasn't supposed to do that!!! -->
 </head>
+<script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
 <body>
 <div class="super-header">
   <div class="row">

From 5b1567448f0dee79999e9c20624cb75ba2b759a8 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 07 2015 19:50:24 +0000
Subject: [PATCH 88/1001] Merge pull request #13 from decause/newstuff


Newstuff
---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index cae90a0..da41b82 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -8,10 +8,18 @@ def add_user_widgets(session, hub, username, fullname):
     widget = hubs.models.Widget(
         plugin='sticky', index=0, left=True,
         _config=json.dumps({
-            'text': 'TODO -- put a fancy graph here..',
+            'text': 'TODO -- Put a fancy graph here...',
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
+        plugin='fedmsgs', index=1, left=True,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+
+    # Right Side Widgets
+    widget = hubs.models.Widget(
         plugin='avatar', index=0,
         _config=json.dumps({
             'username': username,
diff --git a/hubs/static/css/pace-theme-minimal.css b/hubs/static/css/pace-theme-minimal.css
new file mode 100644
index 0000000..b12e450
--- /dev/null
+++ b/hubs/static/css/pace-theme-minimal.css
@@ -0,0 +1,30 @@
+/*Copyright (c) 2013 HubSpot, Inc.
+
+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.
+*/
+.pace {
+  -webkit-pointer-events: none;
+  pointer-events: none;
+
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
+
+.pace-inactive {
+  display: none;
+}
+
+.pace .pace-progress {
+  background: #29d;
+  position: fixed;
+  z-index: 2000;
+  top: 0;
+  right: 100%;
+  width: 100%;
+  height: 2px;
+}
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index f418cc9..9ef6dae 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -50,7 +50,7 @@
 
     .panel-visible {
       visibility: visible;
-      max-height: 400px;
+      max-height: 100%;
     }
 
 //flexbox support
diff --git a/hubs/static/js/pace.min.js b/hubs/static/js/pace.min.js
new file mode 100644
index 0000000..270c5ec
--- /dev/null
+++ b/hubs/static/js/pace.min.js
@@ -0,0 +1,10 @@
+/*Copyright (c) 2013 HubSpot, Inc.
+
+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.
+*/
+/*! pace 1.0.0 */
+(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X=[].slice,Y={}.hasOwnProperty,Z=function(a,b){function c(){this.constructor=a}for(var d in b)Y.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},$=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};for(u={catchupTime:100,initialRate:.03,minTime:250,ghostTime:100,maxProgressPerFrame:20,easeFactor:1.25,startOnPageLoad:!0,restartOnPushState:!0,restartOnRequestAfter:500,target:"body",elements:{checkInterval:100,selectors:["body"]},eventLag:{minSamples:10,sampleCount:3,lagThreshold:3},ajax:{trackMethods:["GET"],trackWebSockets:!0,ignoreURLs:[]}},C=function(){var a;return null!=(a="undefined"!=typeof performance&&null!==performance&&"function"==typeof performance.now?performance.now():void 0)?a:+new Date},E=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame,null==E&&(E=function(a){return setTimeout(a,50)},t=function(a){return clearTimeout(a)}),G=function(a){var b,c;return b=C(),(c=function(){var d;return d=C()-b,d>=33?(b=C(),a(d,function(){return E(c)})):setTimeout(c,33-d)})()},F=function(){var a,b,c;return c=arguments[0],b=arguments[1],a=3<=arguments.length?X.call(arguments,2):[],"function"==typeof c[b]?c[b].apply(c,a):c[b]},v=function(){var a,b,c,d,e,f,g;for(b=arguments[0],d=2<=arguments.length?X.call(arguments,1):[],f=0,g=d.length;g>f;f++)if(c=d[f])for(a in c)Y.call(c,a)&&(e=c[a],null!=b[a]&&"object"==typeof b[a]&&null!=e&&"object"==typeof e?v(b[a],e):b[a]=e);return b},q=function(a){var b,c,d,e,f;for(c=b=0,e=0,f=a.length;f>e;e++)d=a[e],c+=Math.abs(d),b++;return c/b},x=function(a,b){var c,d,e;if(null==a&&(a="options"),null==b&&(b=!0),e=document.querySelector("[data-pace-"+a+"]")){if(c=e.getAttribute("data-pace-"+a),!b)return c;try{return JSON.parse(c)}catch(f){return d=f,"undefined"!=typeof console&&null!==console?console.error("Error parsing inline pace options",d):void 0}}},g=function(){function a(){}return a.prototype.on=function(a,b,c,d){var e;return null==d&&(d=!1),null==this.bindings&&(this.bindings={}),null==(e=this.bindings)[a]&&(e[a]=[]),this.bindings[a].push({handler:b,ctx:c,once:d})},a.prototype.once=function(a,b,c){return this.on(a,b,c,!0)},a.prototype.off=function(a,b){var c,d,e;if(null!=(null!=(d=this.bindings)?d[a]:void 0)){if(null==b)return delete this.bindings[a];for(c=0,e=[];c<this.bindings[a].length;)e.push(this.bindings[a][c].handler===b?this.bindings[a].splice(c,1):c++);return e}},a.prototype.trigger=function(){var a,b,c,d,e,f,g,h,i;if(c=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],null!=(g=this.bindings)?g[c]:void 0){for(e=0,i=[];e<this.bindings[c].length;)h=this.bindings[c][e],d=h.handler,b=h.ctx,f=h.once,d.apply(null!=b?b:this,a),i.push(f?this.bindings[c].splice(e,1):e++);return i}},a}(),j=window.Pace||{},window.Pace=j,v(j,g.prototype),D=j.options=v({},u,window.paceOptions,x()),U=["ajax","document","eventLag","elements"],Q=0,S=U.length;S>Q;Q++)K=U[Q],D[K]===!0&&(D[K]=u[K]);i=function(a){function b(){return V=b.__super__.constructor.apply(this,arguments)}return Z(b,a),b}(Error),b=function(){function a(){this.progress=0}return a.prototype.getElement=function(){var a;if(null==this.el){if(a=document.querySelector(D.target),!a)throw new i;this.el=document.createElement("div"),this.el.className="pace pace-active",document.body.className=document.body.className.replace(/pace-done/g,""),document.body.className+=" pace-running",this.el.innerHTML='<div class="pace-progress">\n  <div class="pace-progress-inner"></div>\n</div>\n<div class="pace-activity"></div>',null!=a.firstChild?a.insertBefore(this.el,a.firstChild):a.appendChild(this.el)}return this.el},a.prototype.finish=function(){var a;return a=this.getElement(),a.className=a.className.replace("pace-active",""),a.className+=" pace-inactive",document.body.className=document.body.className.replace("pace-running",""),document.body.className+=" pace-done"},a.prototype.update=function(a){return this.progress=a,this.render()},a.prototype.destroy=function(){try{this.getElement().parentNode.removeChild(this.getElement())}catch(a){i=a}return this.el=void 0},a.prototype.render=function(){var a,b,c,d,e,f,g;if(null==document.querySelector(D.target))return!1;for(a=this.getElement(),d="translate3d("+this.progress+"%, 0, 0)",g=["webkitTransform","msTransform","transform"],e=0,f=g.length;f>e;e++)b=g[e],a.children[0].style[b]=d;return(!this.lastRenderedProgress||this.lastRenderedProgress|0!==this.progress|0)&&(a.children[0].setAttribute("data-progress-text",""+(0|this.progress)+"%"),this.progress>=100?c="99":(c=this.progress<10?"0":"",c+=0|this.progress),a.children[0].setAttribute("data-progress",""+c)),this.lastRenderedProgress=this.progress},a.prototype.done=function(){return this.progress>=100},a}(),h=function(){function a(){this.bindings={}}return a.prototype.trigger=function(a,b){var c,d,e,f,g;if(null!=this.bindings[a]){for(f=this.bindings[a],g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(c.call(this,b));return g}},a.prototype.on=function(a,b){var c;return null==(c=this.bindings)[a]&&(c[a]=[]),this.bindings[a].push(b)},a}(),P=window.XMLHttpRequest,O=window.XDomainRequest,N=window.WebSocket,w=function(a,b){var c,d,e,f;f=[];for(d in b.prototype)try{e=b.prototype[d],f.push(null==a[d]&&"function"!=typeof e?a[d]=e:void 0)}catch(g){c=g}return f},A=[],j.ignore=function(){var a,b,c;return b=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],A.unshift("ignore"),c=b.apply(null,a),A.shift(),c},j.track=function(){var a,b,c;return b=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],A.unshift("track"),c=b.apply(null,a),A.shift(),c},J=function(a){var b;if(null==a&&(a="GET"),"track"===A[0])return"force";if(!A.length&&D.ajax){if("socket"===a&&D.ajax.trackWebSockets)return!0;if(b=a.toUpperCase(),$.call(D.ajax.trackMethods,b)>=0)return!0}return!1},k=function(a){function b(){var a,c=this;b.__super__.constructor.apply(this,arguments),a=function(a){var b;return b=a.open,a.open=function(d,e){return J(d)&&c.trigger("request",{type:d,url:e,request:a}),b.apply(a,arguments)}},window.XMLHttpRequest=function(b){var c;return c=new P(b),a(c),c};try{w(window.XMLHttpRequest,P)}catch(d){}if(null!=O){window.XDomainRequest=function(){var b;return b=new O,a(b),b};try{w(window.XDomainRequest,O)}catch(d){}}if(null!=N&&D.ajax.trackWebSockets){window.WebSocket=function(a,b){var d;return d=null!=b?new N(a,b):new N(a),J("socket")&&c.trigger("request",{type:"socket",url:a,protocols:b,request:d}),d};try{w(window.WebSocket,N)}catch(d){}}}return Z(b,a),b}(h),R=null,y=function(){return null==R&&(R=new k),R},I=function(a){var b,c,d,e;for(e=D.ajax.ignoreURLs,c=0,d=e.length;d>c;c++)if(b=e[c],"string"==typeof b){if(-1!==a.indexOf(b))return!0}else if(b.test(a))return!0;return!1},y().on("request",function(b){var c,d,e,f,g;return f=b.type,e=b.request,g=b.url,I(g)?void 0:j.running||D.restartOnRequestAfter===!1&&"force"!==J(f)?void 0:(d=arguments,c=D.restartOnRequestAfter||0,"boolean"==typeof c&&(c=0),setTimeout(function(){var b,c,g,h,i,k;if(b="socket"===f?e.readyState<2:0<(h=e.readyState)&&4>h){for(j.restart(),i=j.sources,k=[],c=0,g=i.length;g>c;c++){if(K=i[c],K instanceof a){K.watch.apply(K,d);break}k.push(void 0)}return k}},c))}),a=function(){function a(){var a=this;this.elements=[],y().on("request",function(){return a.watch.apply(a,arguments)})}return a.prototype.watch=function(a){var b,c,d,e;return d=a.type,b=a.request,e=a.url,I(e)?void 0:(c="socket"===d?new n(b):new o(b),this.elements.push(c))},a}(),o=function(){function a(a){var b,c,d,e,f,g,h=this;if(this.progress=0,null!=window.ProgressEvent)for(c=null,a.addEventListener("progress",function(a){return h.progress=a.lengthComputable?100*a.loaded/a.total:h.progress+(100-h.progress)/2},!1),g=["load","abort","timeout","error"],d=0,e=g.length;e>d;d++)b=g[d],a.addEventListener(b,function(){return h.progress=100},!1);else f=a.onreadystatechange,a.onreadystatechange=function(){var b;return 0===(b=a.readyState)||4===b?h.progress=100:3===a.readyState&&(h.progress=50),"function"==typeof f?f.apply(null,arguments):void 0}}return a}(),n=function(){function a(a){var b,c,d,e,f=this;for(this.progress=0,e=["error","open"],c=0,d=e.length;d>c;c++)b=e[c],a.addEventListener(b,function(){return f.progress=100},!1)}return a}(),d=function(){function a(a){var b,c,d,f;for(null==a&&(a={}),this.elements=[],null==a.selectors&&(a.selectors=[]),f=a.selectors,c=0,d=f.length;d>c;c++)b=f[c],this.elements.push(new e(b))}return a}(),e=function(){function a(a){this.selector=a,this.progress=0,this.check()}return a.prototype.check=function(){var a=this;return document.querySelector(this.selector)?this.done():setTimeout(function(){return a.check()},D.elements.checkInterval)},a.prototype.done=function(){return this.progress=100},a}(),c=function(){function a(){var a,b,c=this;this.progress=null!=(b=this.states[document.readyState])?b:100,a=document.onreadystatechange,document.onreadystatechange=function(){return null!=c.states[document.readyState]&&(c.progress=c.states[document.readyState]),"function"==typeof a?a.apply(null,arguments):void 0}}return a.prototype.states={loading:0,interactive:50,complete:100},a}(),f=function(){function a(){var a,b,c,d,e,f=this;this.progress=0,a=0,e=[],d=0,c=C(),b=setInterval(function(){var g;return g=C()-c-50,c=C(),e.push(g),e.length>D.eventLag.sampleCount&&e.shift(),a=q(e),++d>=D.eventLag.minSamples&&a<D.eventLag.lagThreshold?(f.progress=100,clearInterval(b)):f.progress=100*(3/(a+3))},50)}return a}(),m=function(){function a(a){this.source=a,this.last=this.sinceLastUpdate=0,this.rate=D.initialRate,this.catchup=0,this.progress=this.lastProgress=0,null!=this.source&&(this.progress=F(this.source,"progress"))}return a.prototype.tick=function(a,b){var c;return null==b&&(b=F(this.source,"progress")),b>=100&&(this.done=!0),b===this.last?this.sinceLastUpdate+=a:(this.sinceLastUpdate&&(this.rate=(b-this.last)/this.sinceLastUpdate),this.catchup=(b-this.progress)/D.catchupTime,this.sinceLastUpdate=0,this.last=b),b>this.progress&&(this.progress+=this.catchup*a),c=1-Math.pow(this.progress/100,D.easeFactor),this.progress+=c*this.rate*a,this.progress=Math.min(this.lastProgress+D.maxProgressPerFrame,this.progress),this.progress=Math.max(0,this.progress),this.progress=Math.min(100,this.progress),this.lastProgress=this.progress,this.progress},a}(),L=null,H=null,r=null,M=null,p=null,s=null,j.running=!1,z=function(){return D.restartOnPushState?j.restart():void 0},null!=window.history.pushState&&(T=window.history.pushState,window.history.pushState=function(){return z(),T.apply(window.history,arguments)}),null!=window.history.replaceState&&(W=window.history.replaceState,window.history.replaceState=function(){return z(),W.apply(window.history,arguments)}),l={ajax:a,elements:d,document:c,eventLag:f},(B=function(){var a,c,d,e,f,g,h,i;for(j.sources=L=[],g=["ajax","elements","document","eventLag"],c=0,e=g.length;e>c;c++)a=g[c],D[a]!==!1&&L.push(new l[a](D[a]));for(i=null!=(h=D.extraSources)?h:[],d=0,f=i.length;f>d;d++)K=i[d],L.push(new K(D));return j.bar=r=new b,H=[],M=new m})(),j.stop=function(){return j.trigger("stop"),j.running=!1,r.destroy(),s=!0,null!=p&&("function"==typeof t&&t(p),p=null),B()},j.restart=function(){return j.trigger("restart"),j.stop(),j.start()},j.go=function(){var a;return j.running=!0,r.render(),a=C(),s=!1,p=G(function(b,c){var d,e,f,g,h,i,k,l,n,o,p,q,t,u,v,w;for(l=100-r.progress,e=p=0,f=!0,i=q=0,u=L.length;u>q;i=++q)for(K=L[i],o=null!=H[i]?H[i]:H[i]=[],h=null!=(w=K.elements)?w:[K],k=t=0,v=h.length;v>t;k=++t)g=h[k],n=null!=o[k]?o[k]:o[k]=new m(g),f&=n.done,n.done||(e++,p+=n.tick(b));return d=p/e,r.update(M.tick(b,d)),r.done()||f||s?(r.update(100),j.trigger("done"),setTimeout(function(){return r.finish(),j.running=!1,j.trigger("hide")},Math.max(D.ghostTime,Math.max(D.minTime-(C()-a),0)))):c()})},j.start=function(a){v(D,a),j.running=!0;try{r.render()}catch(b){i=b}return document.querySelector(".pace")?(j.trigger("start"),j.go()):setTimeout(j.start,50)},"function"==typeof define&&define.amd?define(function(){return j}):"object"==typeof exports?module.exports=j:D.startOnPageLoad&&j.start()}).call(this);
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 38313c1..d178a0e 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -3,9 +3,11 @@
   <title>{{ hub.name }}</title>
   <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
   <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic|Comfortaa' rel='stylesheet' type='text/css'>
 <!--I added google fonts!!!! Sorry if I wasn't supposed to do that!!! -->
 </head>
+<script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
 <body>
 <div class="super-header">
   <div class="row">
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 51ed1b1..2bb8570 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -5,6 +5,7 @@ from hubs.widgets import sticky
 from hubs.widgets import about
 from hubs.widgets import avatar
 from hubs.widgets import badges
+from hubs.widgets import fedmsgs
 
 from hubs.widgets.workflow import pendingacls
 
@@ -18,7 +19,7 @@ registry = {
     'about': about,
     'avatar': avatar,
     'badges': badges,
-
+    'fedmsgs': fedmsgs,
     'workflow.pendingacls': pendingacls,
 }
 
diff --git a/hubs/widgets/fedmsgs.py b/hubs/widgets/fedmsgs.py
new file mode 100644
index 0000000..ae07a7d
--- /dev/null
+++ b/hubs/widgets/fedmsgs.py
@@ -0,0 +1,32 @@
+from hubs.widgets.base import argument
+
+import jinja2
+
+
+import hubs.validators as validators
+
+
+template = jinja2.Template("""
+<div class="flex-container">
+
+    <img src="{{url}}" />
+
+</div>
+""")
+
+from hubs.widgets.chrome import panel
+chrome = panel("Daily Activity")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    url = "https://apps.fedoraproject.org/datagrepper/charts/line?delta=86400&N=12&style=clean&height=200&fill=true&user={username}"
+    url = url.format(username=username)
+    return dict(url=url)
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From d882bde246cad81c7d950c0cdbc9330dc01c0ecd Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 07 2015 20:45:03 +0000
Subject: [PATCH 89/1001] Increase widget height to 300px


---

diff --git a/hubs/widgets/fedmsgs.py b/hubs/widgets/fedmsgs.py
index ae07a7d..6f7dcf1 100644
--- a/hubs/widgets/fedmsgs.py
+++ b/hubs/widgets/fedmsgs.py
@@ -23,7 +23,7 @@ chrome = panel("Daily Activity")
           validator=validators.username,
           help="A FAS username.")
 def data(session, widget, username):
-    url = "https://apps.fedoraproject.org/datagrepper/charts/line?delta=86400&N=12&style=clean&height=200&fill=true&user={username}"
+    url = "https://apps.fedoraproject.org/datagrepper/charts/line?delta=86400&N=12&style=clean&height=300&fill=true&user={username}"
     url = url.format(username=username)
     return dict(url=url)
 

From 6fa00b6f9be351bc231743b43a8e925d2245bc63 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 07 2015 21:29:34 +0000
Subject: [PATCH 90/1001] Added fedmsgstats widget, WIP


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index da41b82..7a2a619 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -26,13 +26,19 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='workflow.pendingacls', index=1,
+        plugin='fedmsgstats', index=1,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='badges', index=2,
+        plugin='workflow.pendingacls', index=2,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='badges', index=3,
         _config=json.dumps({
             'username': username,
         }))
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 2bb8570..b00af22 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -6,6 +6,7 @@ from hubs.widgets import about
 from hubs.widgets import avatar
 from hubs.widgets import badges
 from hubs.widgets import fedmsgs
+from hubs.widgets import fedmsgstats
 
 from hubs.widgets.workflow import pendingacls
 
@@ -20,6 +21,7 @@ registry = {
     'avatar': avatar,
     'badges': badges,
     'fedmsgs': fedmsgs,
+    'fedmsgstats': fedmsgstats,
     'workflow.pendingacls': pendingacls,
 }
 
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
new file mode 100644
index 0000000..e248a8c
--- /dev/null
+++ b/hubs/widgets/fedmsgstats.py
@@ -0,0 +1,38 @@
+from hubs.widgets.chrome import panel
+
+import jinja2
+
+import requests
+
+chrome = panel()
+template = jinja2.Template("""
+<div class="stats-container">
+  <table class="stats-table">
+    <tr><th>FedMsgs</th><th>Subscribers</th></tr>
+    <tr class="text-info"><td>{{fedmsgs}}</td><td>{{subscribers}}</td></tr>
+  </table>
+  <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+</div>
+""")
+
+
+def data(session, widget, username):
+    url = "https://apps.fedoraproject.org/datagrepper/raw?user={username}"
+    url = url.format(username=username)
+    response = requests.get(url)
+    fedmsgs = response.json()['total']
+    return dict(
+        fedmsgs=fedmsgs,
+        subscribers=len(widget.hub.subscribers),
+    )
+
+
+# TODO -- add topic-based hinting here.  Solved.
+def should_invalidate(message, session, widget):
+    if message['topic'].endswith('hubs.hub.update'):
+        if message['msg']['hub']['name'] == widget.hub.name:
+            return True
+
+    # TODO -- also check for FAS group changes??  are we doing that?
+
+    return False

From dd64e9c774e04d0e640a273da524e1fad1b6ded2 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 07 2015 21:33:17 +0000
Subject: [PATCH 91/1001] Added stats-table styles to global site.css instead of template


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 9ef6dae..43dc791 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -60,3 +60,18 @@
     flex-wrap: wrap;
 } 
 
+.stats-table {
+width: 180px
+padding: 0px;
+margin: 0px;
+display: inline-block;
+}
+.stats-table th {
+text-transform: uppercase;
+font-size: 80%;
+padding-right: 10px;
+color: #797a7c;
+}
+.stats-table td {
+font-size: 32pt;
+}

From 747a94a3042bfd95f427989795bd88f1197088b9 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 07 2015 21:34:36 +0000
Subject: [PATCH 92/1001] Remove stats-table style from widget and put into site.css


---

diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index d0d3039..03090a4 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -11,23 +11,6 @@ template = jinja2.Template("""
   </table>
   <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
 </div>
-<style>
-  .stats-table {
-    width: 180px
-    padding: 0px;
-    margin: 0px;
-    display: inline-block;
-  }
-  .stats-table th {
-    text-transform: uppercase;
-    font-size: 80%;
-    padding-right: 10px;
-    color: #797a7c;
-  }
-  .stats-table td {
-    font-size: 32pt;
-  }
-</style>
 """)
 
 

From 0c96f4baf47f20236ad7e15a75cab705be2c9afa Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 07 2015 21:35:37 +0000
Subject: [PATCH 93/1001] Added NotImplementedError for Cache Invalidation


---

diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index e248a8c..bd2323b 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -27,12 +27,5 @@ def data(session, widget, username):
     )
 
 
-# TODO -- add topic-based hinting here.  Solved.
 def should_invalidate(message, session, widget):
-    if message['topic'].endswith('hubs.hub.update'):
-        if message['msg']['hub']['name'] == widget.hub.name:
-            return True
-
-    # TODO -- also check for FAS group changes??  are we doing that?
-
-    return False
+    raise NotImplementedError

From 69ff57294f85da9ab8915553da4ff8f756ecf32b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 07 2015 21:38:16 +0000
Subject: [PATCH 94/1001] Merge pull request #14 from decause/feature/fedmsgstats


Feature/fedmsgstats
---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index da41b82..7a2a619 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -26,13 +26,19 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='workflow.pendingacls', index=1,
+        plugin='fedmsgstats', index=1,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='badges', index=2,
+        plugin='workflow.pendingacls', index=2,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='badges', index=3,
         _config=json.dumps({
             'username': username,
         }))
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 9ef6dae..43dc791 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -60,3 +60,18 @@
     flex-wrap: wrap;
 } 
 
+.stats-table {
+width: 180px
+padding: 0px;
+margin: 0px;
+display: inline-block;
+}
+.stats-table th {
+text-transform: uppercase;
+font-size: 80%;
+padding-right: 10px;
+color: #797a7c;
+}
+.stats-table td {
+font-size: 32pt;
+}
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 2bb8570..b00af22 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -6,6 +6,7 @@ from hubs.widgets import about
 from hubs.widgets import avatar
 from hubs.widgets import badges
 from hubs.widgets import fedmsgs
+from hubs.widgets import fedmsgstats
 
 from hubs.widgets.workflow import pendingacls
 
@@ -20,6 +21,7 @@ registry = {
     'avatar': avatar,
     'badges': badges,
     'fedmsgs': fedmsgs,
+    'fedmsgstats': fedmsgstats,
     'workflow.pendingacls': pendingacls,
 }
 
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
new file mode 100644
index 0000000..bd2323b
--- /dev/null
+++ b/hubs/widgets/fedmsgstats.py
@@ -0,0 +1,31 @@
+from hubs.widgets.chrome import panel
+
+import jinja2
+
+import requests
+
+chrome = panel()
+template = jinja2.Template("""
+<div class="stats-container">
+  <table class="stats-table">
+    <tr><th>FedMsgs</th><th>Subscribers</th></tr>
+    <tr class="text-info"><td>{{fedmsgs}}</td><td>{{subscribers}}</td></tr>
+  </table>
+  <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+</div>
+""")
+
+
+def data(session, widget, username):
+    url = "https://apps.fedoraproject.org/datagrepper/raw?user={username}"
+    url = url.format(username=username)
+    response = requests.get(url)
+    fedmsgs = response.json()['total']
+    return dict(
+        fedmsgs=fedmsgs,
+        subscribers=len(widget.hub.subscribers),
+    )
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index d0d3039..03090a4 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -11,23 +11,6 @@ template = jinja2.Template("""
   </table>
   <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
 </div>
-<style>
-  .stats-table {
-    width: 180px
-    padding: 0px;
-    margin: 0px;
-    display: inline-block;
-  }
-  .stats-table th {
-    text-transform: uppercase;
-    font-size: 80%;
-    padding-right: 10px;
-    color: #797a7c;
-  }
-  .stats-table td {
-    font-size: 32pt;
-  }
-</style>
 """)
 
 

From f1330c6b6aadd68d0b8d8be5c732da7bc5b0948f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 07 2015 22:33:58 +0000
Subject: [PATCH 95/1001] Add an updates2stable widget for the user profile.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 7a2a619..baa60c6 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -32,13 +32,19 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='workflow.pendingacls', index=2,
+        plugin='workflow.updates2stable', index=2,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='badges', index=3,
+        plugin='workflow.pendingacls', index=3,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='badges', index=4,
         _config=json.dumps({
             'username': username,
         }))
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 43dc791..2082a2a 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -75,3 +75,8 @@ color: #797a7c;
 .stats-table td {
 font-size: 32pt;
 }
+
+.square-32 {
+    width: 32px;
+    height: 32px;
+}
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index b00af22..e864e5b 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -9,6 +9,7 @@ from hubs.widgets import fedmsgs
 from hubs.widgets import fedmsgstats
 
 from hubs.widgets.workflow import pendingacls
+from hubs.widgets.workflow import updates2stable
 
 from hubs.widgets.base import AGPLv3, smartcache
 
@@ -23,6 +24,7 @@ registry = {
     'fedmsgs': fedmsgs,
     'fedmsgstats': fedmsgstats,
     'workflow.pendingacls': pendingacls,
+    'workflow.updates2stable': updates2stable,
 }
 
 
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
new file mode 100644
index 0000000..1b72c9d
--- /dev/null
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -0,0 +1,71 @@
+import requests
+
+from hubs.widgets.base import argument
+
+import jinja2
+
+
+import hubs.validators as validators
+
+# TODO -- add approve/deny buttons or just link through to pkgdb
+template = jinja2.Template("""
+<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
+<hr/>
+<ul class="media-list">
+{% for update in updates %}
+    <li class="media">
+        <div class="media-left">
+            <a href="{{update['link']}}" target="_blank">
+                <img class="media-object img-responsive square-32" src="{{update['icon']}}"/>
+            </a>
+        </div>
+        <div class="media-body">
+            <h4 class="media-heading">{{update['title']}} (karma {{update['karma']}})</h4>
+            ready for love
+        </div>
+    </li>
+{% endfor %}
+</ul>
+""")
+
+from hubs.widgets.chrome import panel
+# If 'updates' is empty, then don't render any chrome.
+chrome = panel('Updates Ready for Stable', key='updates')
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+
+    # First, get all of my updates currently in testing.
+    bodhiurl = 'https://admin.fedoraproject.org/updates/'
+    baseurl = bodhiurl + 'list'
+    query = '?username={username}&status=testing'.format(username=username)
+    url = baseurl + query
+    headers = {'Accept': 'application/json'}
+    response = requests.get(url, headers=headers)
+    data = response.json()
+
+    # Limit it this to only the updates that haven't already requested stable
+    # but which can actually be pushed to stable now.
+    giveaway = 'can be pushed to stable now'
+    data['updates'] = [
+        update for update in data['updates']
+        if update['request'] is None and
+        any([giveaway in comment['text'] for comment in update['comments']])
+    ]
+
+    # Stuff some useful information in there.
+    baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
+    for update in data['updates']:
+        package = update['builds'][0]['package']['name']
+        update['icon'] = baseurl + package + '.png'
+        update['link'] = bodhiurl + update['title']
+
+    return data
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 47b0e421c529e92893fe66b4688061e74699f8d2 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <remyd@civx.us>
Date: Jun 07 2015 22:37:33 +0000
Subject: [PATCH 96/1001] Merge pull request #15 from ralphbean/feature/updates2stable


Add an updates2stable widget for the user profile.
---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 7a2a619..baa60c6 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -32,13 +32,19 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='workflow.pendingacls', index=2,
+        plugin='workflow.updates2stable', index=2,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='badges', index=3,
+        plugin='workflow.pendingacls', index=3,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='badges', index=4,
         _config=json.dumps({
             'username': username,
         }))
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 43dc791..2082a2a 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -75,3 +75,8 @@ color: #797a7c;
 .stats-table td {
 font-size: 32pt;
 }
+
+.square-32 {
+    width: 32px;
+    height: 32px;
+}
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index b00af22..e864e5b 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -9,6 +9,7 @@ from hubs.widgets import fedmsgs
 from hubs.widgets import fedmsgstats
 
 from hubs.widgets.workflow import pendingacls
+from hubs.widgets.workflow import updates2stable
 
 from hubs.widgets.base import AGPLv3, smartcache
 
@@ -23,6 +24,7 @@ registry = {
     'fedmsgs': fedmsgs,
     'fedmsgstats': fedmsgstats,
     'workflow.pendingacls': pendingacls,
+    'workflow.updates2stable': updates2stable,
 }
 
 
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
new file mode 100644
index 0000000..1b72c9d
--- /dev/null
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -0,0 +1,71 @@
+import requests
+
+from hubs.widgets.base import argument
+
+import jinja2
+
+
+import hubs.validators as validators
+
+# TODO -- add approve/deny buttons or just link through to pkgdb
+template = jinja2.Template("""
+<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
+<hr/>
+<ul class="media-list">
+{% for update in updates %}
+    <li class="media">
+        <div class="media-left">
+            <a href="{{update['link']}}" target="_blank">
+                <img class="media-object img-responsive square-32" src="{{update['icon']}}"/>
+            </a>
+        </div>
+        <div class="media-body">
+            <h4 class="media-heading">{{update['title']}} (karma {{update['karma']}})</h4>
+            ready for love
+        </div>
+    </li>
+{% endfor %}
+</ul>
+""")
+
+from hubs.widgets.chrome import panel
+# If 'updates' is empty, then don't render any chrome.
+chrome = panel('Updates Ready for Stable', key='updates')
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+
+    # First, get all of my updates currently in testing.
+    bodhiurl = 'https://admin.fedoraproject.org/updates/'
+    baseurl = bodhiurl + 'list'
+    query = '?username={username}&status=testing'.format(username=username)
+    url = baseurl + query
+    headers = {'Accept': 'application/json'}
+    response = requests.get(url, headers=headers)
+    data = response.json()
+
+    # Limit it this to only the updates that haven't already requested stable
+    # but which can actually be pushed to stable now.
+    giveaway = 'can be pushed to stable now'
+    data['updates'] = [
+        update for update in data['updates']
+        if update['request'] is None and
+        any([giveaway in comment['text'] for comment in update['comments']])
+    ]
+
+    # Stuff some useful information in there.
+    baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
+    for update in data['updates']:
+        package = update['builds'][0]['package']['name']
+        update['icon'] = baseurl + package + '.png'
+        update['link'] = bodhiurl + update['title']
+
+    return data
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 1348ab9d296be1064f7426160a48e7d3ca61acbc Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 07 2015 22:43:19 +0000
Subject: [PATCH 97/1001] Hide everything if there are no updates here.


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 1b72c9d..905b5fd 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -9,6 +9,7 @@ import hubs.validators as validators
 
 # TODO -- add approve/deny buttons or just link through to pkgdb
 template = jinja2.Template("""
+{% if updates %}
 <a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
 <hr/>
 <ul class="media-list">
@@ -26,6 +27,7 @@ template = jinja2.Template("""
     </li>
 {% endfor %}
 </ul>
+{% endif %}
 """)
 
 from hubs.widgets.chrome import panel

From 181ec089e72b9a207c06dce24507dc34b000b7a7 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 08 2015 02:16:02 +0000
Subject: [PATCH 98/1001] First pass at check hinting.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index 08d1eca..da79a59 100644
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -1,7 +1,8 @@
 # The fedora hubs backend daemon
 
+import collections
+import threading
 import time
-import random
 
 import fedmsg.consumers
 
@@ -27,11 +28,38 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         if not self.uri:
             raise ValueError('hubs.sqlalchemy.uri must be present')
 
+        self.hint_cache_lock = threading.Lock()
+        session = self.make_session()
+        with self.hint_cache_lock:
+            self.rebuild_hubs_hint_caches(session)
+        session.commit()  # transaction is committed here
+        session.close()
+
         log.info("CacheInvalidatorExtraordinaire initialized")
 
     def make_session(self):
         return hubs.models.init(self.uri)
 
+    def rebuild_hubs_hint_caches(self, session):
+        self.checks_by_topic = collections.defaultdict(list)
+        self.checks_by_category = collections.defaultdict(list)
+
+        widgets = session.query(hubs.models.Widget).all()
+        log.info("Comparing message against %i widgets" % len(widgets))
+        for widget in widgets:
+            check = widget.module.should_invalidate
+            if not hasattr(check, 'hints'):
+                raise AttributeError("%r must declare hints" % widget.module)
+            for topic in check.hints['topics']:
+                self.checks_by_topic[topic].append((check, widget,))
+            for category in check.hints['categories']:
+                self.checks_by_category[category].append((check, widget,))
+
+
+    @property
+    def cache_initialized(self):
+        return self.checks_by_topic and self.checks_by_category
+
     def consume(self, raw_msg):
         session = self.make_session()
         try:
@@ -43,6 +71,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
 
     def work(self, session, raw_msg):
         topic, msg = raw_msg['topic'], raw_msg['body']
+        category = topic.split('.')[3]
 
         for suffix in self.junk_suffixes:
             if topic.endswith(suffix):
@@ -53,20 +82,26 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         log.info("CacheInvalidatorExtraordinaire received %s %s",
                   msg['msg_id'], msg['topic'])
 
+        if category == 'hubs' or not self.cache_initialized:
+            # Someone has modified an object in the hubs database, so let's
+            # rebuild our cache of our own database.
+            with self.hint_cache_lock:
+                self.rebuild_hubs_hint_caches(session)
+
         # Begin our real work.
         # Find which widgets should have their caches nuked and make it so.
 
-        # First, make a thread-local copy of the widgets.
-        widgets = list(session.query(hubs.models.Widget).all())
-        log.info("Comparing message against %i widgets" % len(widgets))
-
-        # Shuffle it so that not all threads step through the list in the same
-        # order.  This should cut down on competition for the dogpile lock.
-        random.shuffle(widgets)
-
-        # And do the real work of comparing every widget against the message.
-        for widget in widgets:
-            if widget.module.should_invalidate(msg, session, widget):
+        # Start this by finding a subset of widget checks that might match this
+        # message. Look them up based on the hints they declare.
+        checks = \
+            set(self.checks_by_topic[topic]) + \
+            set(self.checks_by_category[category])
+        log.info("Found %i checks to try for this message" % len(checks))
+
+        # Then, with that hopefully smaller list of checks, try them all and
+        # see if any tell us that we should nuke various data caches.
+        for check, widget in checks:
+            if check(msg, session, widget):
                 log.info("Invalidating cache for %r" % widget)
                 # Invalidate the cache...
                 invalidate_cache(widget.module, **widget.config)
diff --git a/hubs/hinting.py b/hubs/hinting.py
new file mode 100644
index 0000000..64a58ed
--- /dev/null
+++ b/hubs/hinting.py
@@ -0,0 +1,28 @@
+import collections
+import decorator
+
+import fedmsg.config
+
+import logging
+log = logging.getLogger('hubs.hinting')
+
+
+def hint(topics=None, categories=None):
+    topics = topics or []
+    categories = categories or []
+
+    @decorator.decorator
+    def wrapper(fn, *args, **kwargs):
+        return fn(*args, **kwargs)
+
+    def wrapper_wrapper(fn):
+        wrapped = wrapper(fn)
+        wrapped.hints = dict(topics=topics, categories=categories)
+        return wrapped
+
+    return wrapper_wrapper
+
+
+def prefixed(topic, prefix='org.fedoraproject'):
+    config = fedmsg.config.load_config()  # This is memoized for us.
+    return '.'.join([prefix, config['environment'], topic])
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index d0c9e57..28f48fb 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
 
@@ -16,6 +17,7 @@ def data(session, widget, text):
     return dict(text=text)
 
 
+@hint(topics=[_('hubs.widget.update')])
 def should_invalidate(message, session, widget):
     if not message['topic'].endswith('hubs.widget.update'):
         return False
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 3e0fb4d..ae36938 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -2,6 +2,7 @@ from collections import OrderedDict as ordereddict
 
 import jinja2
 
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument, avatar
 from hubs import validators
@@ -45,6 +46,7 @@ def data(session, widget, link):
     return dict(owners=owners, link=link)
 
 
+@hint(topics=[_('hubs.widget.update'), _('hubs.hub.update')])
 def should_invalidate(message, session, widget):
     if message['topic'].endswith('hubs.widget.update'):
         if message['msg']['widget']['id'] == widget.id:
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 03090a4..1826c62 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 
 import jinja2
@@ -21,7 +22,7 @@ def data(session, widget):
     )
 
 
-# TODO -- add topic-based hinting here.  Solved.
+@hint(topics=_('hubs.hub.update'))
 def should_invalidate(message, session, widget):
     if message['topic'].endswith('hubs.hub.update'):
         if message['msg']['hub']['name'] == widget.hub.name:

From 87485e1d44199f6dad7d8daaa6dca2ab822ac283 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 08 2015 02:49:49 +0000
Subject: [PATCH 99/1001] Merge pull request #16 from ralphbean/feature/check-hinting


First pass at check hinting.
---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index 08d1eca..da79a59 100644
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -1,7 +1,8 @@
 # The fedora hubs backend daemon
 
+import collections
+import threading
 import time
-import random
 
 import fedmsg.consumers
 
@@ -27,11 +28,38 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         if not self.uri:
             raise ValueError('hubs.sqlalchemy.uri must be present')
 
+        self.hint_cache_lock = threading.Lock()
+        session = self.make_session()
+        with self.hint_cache_lock:
+            self.rebuild_hubs_hint_caches(session)
+        session.commit()  # transaction is committed here
+        session.close()
+
         log.info("CacheInvalidatorExtraordinaire initialized")
 
     def make_session(self):
         return hubs.models.init(self.uri)
 
+    def rebuild_hubs_hint_caches(self, session):
+        self.checks_by_topic = collections.defaultdict(list)
+        self.checks_by_category = collections.defaultdict(list)
+
+        widgets = session.query(hubs.models.Widget).all()
+        log.info("Comparing message against %i widgets" % len(widgets))
+        for widget in widgets:
+            check = widget.module.should_invalidate
+            if not hasattr(check, 'hints'):
+                raise AttributeError("%r must declare hints" % widget.module)
+            for topic in check.hints['topics']:
+                self.checks_by_topic[topic].append((check, widget,))
+            for category in check.hints['categories']:
+                self.checks_by_category[category].append((check, widget,))
+
+
+    @property
+    def cache_initialized(self):
+        return self.checks_by_topic and self.checks_by_category
+
     def consume(self, raw_msg):
         session = self.make_session()
         try:
@@ -43,6 +71,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
 
     def work(self, session, raw_msg):
         topic, msg = raw_msg['topic'], raw_msg['body']
+        category = topic.split('.')[3]
 
         for suffix in self.junk_suffixes:
             if topic.endswith(suffix):
@@ -53,20 +82,26 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         log.info("CacheInvalidatorExtraordinaire received %s %s",
                   msg['msg_id'], msg['topic'])
 
+        if category == 'hubs' or not self.cache_initialized:
+            # Someone has modified an object in the hubs database, so let's
+            # rebuild our cache of our own database.
+            with self.hint_cache_lock:
+                self.rebuild_hubs_hint_caches(session)
+
         # Begin our real work.
         # Find which widgets should have their caches nuked and make it so.
 
-        # First, make a thread-local copy of the widgets.
-        widgets = list(session.query(hubs.models.Widget).all())
-        log.info("Comparing message against %i widgets" % len(widgets))
-
-        # Shuffle it so that not all threads step through the list in the same
-        # order.  This should cut down on competition for the dogpile lock.
-        random.shuffle(widgets)
-
-        # And do the real work of comparing every widget against the message.
-        for widget in widgets:
-            if widget.module.should_invalidate(msg, session, widget):
+        # Start this by finding a subset of widget checks that might match this
+        # message. Look them up based on the hints they declare.
+        checks = \
+            set(self.checks_by_topic[topic]) + \
+            set(self.checks_by_category[category])
+        log.info("Found %i checks to try for this message" % len(checks))
+
+        # Then, with that hopefully smaller list of checks, try them all and
+        # see if any tell us that we should nuke various data caches.
+        for check, widget in checks:
+            if check(msg, session, widget):
                 log.info("Invalidating cache for %r" % widget)
                 # Invalidate the cache...
                 invalidate_cache(widget.module, **widget.config)
diff --git a/hubs/hinting.py b/hubs/hinting.py
new file mode 100644
index 0000000..64a58ed
--- /dev/null
+++ b/hubs/hinting.py
@@ -0,0 +1,28 @@
+import collections
+import decorator
+
+import fedmsg.config
+
+import logging
+log = logging.getLogger('hubs.hinting')
+
+
+def hint(topics=None, categories=None):
+    topics = topics or []
+    categories = categories or []
+
+    @decorator.decorator
+    def wrapper(fn, *args, **kwargs):
+        return fn(*args, **kwargs)
+
+    def wrapper_wrapper(fn):
+        wrapped = wrapper(fn)
+        wrapped.hints = dict(topics=topics, categories=categories)
+        return wrapped
+
+    return wrapper_wrapper
+
+
+def prefixed(topic, prefix='org.fedoraproject'):
+    config = fedmsg.config.load_config()  # This is memoized for us.
+    return '.'.join([prefix, config['environment'], topic])
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index d0c9e57..28f48fb 100644
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
 
@@ -16,6 +17,7 @@ def data(session, widget, text):
     return dict(text=text)
 
 
+@hint(topics=[_('hubs.widget.update')])
 def should_invalidate(message, session, widget):
     if not message['topic'].endswith('hubs.widget.update'):
         return False
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 3e0fb4d..ae36938 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -2,6 +2,7 @@ from collections import OrderedDict as ordereddict
 
 import jinja2
 
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument, avatar
 from hubs import validators
@@ -45,6 +46,7 @@ def data(session, widget, link):
     return dict(owners=owners, link=link)
 
 
+@hint(topics=[_('hubs.widget.update'), _('hubs.hub.update')])
 def should_invalidate(message, session, widget):
     if message['topic'].endswith('hubs.widget.update'):
         if message['msg']['widget']['id'] == widget.id:
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 03090a4..1826c62 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 
 import jinja2
@@ -21,7 +22,7 @@ def data(session, widget):
     )
 
 
-# TODO -- add topic-based hinting here.  Solved.
+@hint(topics=_('hubs.hub.update'))
 def should_invalidate(message, session, widget):
     if message['topic'].endswith('hubs.hub.update'):
         if message['msg']['hub']['name'] == widget.hub.name:

From c4b180de354f27febeb1342d6c5ecc1782ea5a49 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 08 2015 03:27:57 +0000
Subject: [PATCH 100/1001] Fill out all the invalidate functions we currently have.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index da79a59..1515966 100644
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -43,18 +43,24 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
     def rebuild_hubs_hint_caches(self, session):
         self.checks_by_topic = collections.defaultdict(list)
         self.checks_by_category = collections.defaultdict(list)
+        self.checks_by_username = collections.defaultdict(list)
 
         widgets = session.query(hubs.models.Widget).all()
         log.info("Comparing message against %i widgets" % len(widgets))
         for widget in widgets:
             check = widget.module.should_invalidate
+
             if not hasattr(check, 'hints'):
                 raise AttributeError("%r must declare hints" % widget.module)
+
             for topic in check.hints['topics']:
                 self.checks_by_topic[topic].append((check, widget,))
+
             for category in check.hints['categories']:
                 self.checks_by_category[category].append((check, widget,))
 
+            for username in check.hints['usernames_function']:
+                self.checks_by_username[username].append((check, widget,))
 
     @property
     def cache_initialized(self):
diff --git a/hubs/hinting.py b/hubs/hinting.py
index 64a58ed..47e7d14 100644
--- a/hubs/hinting.py
+++ b/hubs/hinting.py
@@ -7,9 +7,10 @@ import logging
 log = logging.getLogger('hubs.hinting')
 
 
-def hint(topics=None, categories=None):
+def hint(topics=None, categories=None, usernames=None):
     topics = topics or []
     categories = categories or []
+    usernames = usernames or lambda x: []
 
     @decorator.decorator
     def wrapper(fn, *args, **kwargs):
@@ -17,7 +18,11 @@ def hint(topics=None, categories=None):
 
     def wrapper_wrapper(fn):
         wrapped = wrapper(fn)
-        wrapped.hints = dict(topics=topics, categories=categories)
+        wrapped.hints = dict(
+            topics=topics,
+            categories=categories,
+            username_function=usernames,
+        )
         return wrapped
 
     return wrapper_wrapper
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index a6f8eae..55693c9 100644
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -19,5 +19,10 @@ def data(session, widget, text):
     return dict(text=text)
 
 
+@hint(topics=[_('hubs.widget.update')])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    if not message['topic'].endswith('hubs.widget.update'):
+        return False
+    if message['msg']['widget']['id'] != widget.id:
+        return False
+    return True
diff --git a/hubs/widgets/avatar.py b/hubs/widgets/avatar.py
index 20c12ab..bcda21d 100644
--- a/hubs/widgets/avatar.py
+++ b/hubs/widgets/avatar.py
@@ -23,5 +23,10 @@ def data(session, widget, username):
     return dict(username=username, avatar=avatar)
 
 
+@hint(topics=[_('hubs.widget.update')])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    if not message['topic'].endswith('hubs.widget.update'):
+        return False
+    if message['msg']['widget']['id'] != widget.id:
+        return False
+    return True
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index 14ed116..4e6234d 100644
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -1,5 +1,6 @@
 import requests
 
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 
 import jinja2
@@ -31,5 +32,15 @@ def data(session, widget, username):
     return response.json()
 
 
+@hint(topics=[_('hubs.widget.update'), _('fedbadges.badge.award')])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    if message['topic'].endswith('hubs.widget.update'):
+        if message['msg']['widget']['id'] != widget.id:
+            return True
+
+    if message['topic'].endswith('fedbadges.badge.award'):
+        username = widget.config['username']
+        if message['msg']['user']['username'] == username:
+            return True
+
+    return False
diff --git a/hubs/widgets/fedmsgs.py b/hubs/widgets/fedmsgs.py
index 6f7dcf1..62e4d2c 100644
--- a/hubs/widgets/fedmsgs.py
+++ b/hubs/widgets/fedmsgs.py
@@ -1,10 +1,13 @@
+from hubs.hinting import hint
 from hubs.widgets.base import argument
 
 import jinja2
 
-
 import hubs.validators as validators
 
+import fedmsg.config
+config = fedmsg.config.load_config()
+
 
 template = jinja2.Template("""
 <div class="flex-container">
@@ -28,5 +31,8 @@ def data(session, widget, username):
     return dict(url=url)
 
 
+@hint(usernames=lambda widget: [widget.config['username']])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    usernames = fedmsg.meta.msg2usernames(message, **config)
+    username = widget.config['username']
+    return username in usernames
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index bd2323b..0c22872 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -27,5 +27,8 @@ def data(session, widget, username):
     )
 
 
+@hint(usernames=lambda widget: [widget.config['username']])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    usernames = fedmsg.meta.msg2usernames(message, **config)
+    username = widget.config['username']
+    return username in usernames
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 8f40a86..9e40b73 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -1,5 +1,6 @@
 import requests
 
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.utils import username2avatar
 
@@ -57,5 +58,13 @@ def data(session, widget, username):
     return data
 
 
+@hint(topics=[_('pkgdb.acl.update')])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    # Search the message to see if I am in the ACLs list of the request.
+    username = widget.config['username']
+
+    for acl in message['msg']['package_listing']['acls']:
+        if acl['fas_name'] == username and acl['status'] == 'Approved':
+            return True
+
+    return False
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 905b5fd..da410db 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -1,5 +1,6 @@
 import requests
 
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 
 import jinja2
@@ -35,6 +36,9 @@ from hubs.widgets.chrome import panel
 chrome = panel('Updates Ready for Stable', key='updates')
 
 
+giveaway = 'can be pushed to stable now'
+
+
 @argument(name="username",
           default=None,
           validator=validators.username,
@@ -52,7 +56,6 @@ def data(session, widget, username):
 
     # Limit it this to only the updates that haven't already requested stable
     # but which can actually be pushed to stable now.
-    giveaway = 'can be pushed to stable now'
     data['updates'] = [
         update for update in data['updates']
         if update['request'] is None and
@@ -69,5 +72,11 @@ def data(session, widget, username):
     return data
 
 
+@hint(topics=[_('bodhi.update.comment')])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    if giveaway in message['msg']['comment']['text']:
+        username = widget.config['username']
+        if username == message['msg']['comment']['update_submitter']:
+            return True
+
+    return False

From b77181a05aaf3436d14248713bc45f049f8df20a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 08 2015 04:14:59 +0000
Subject: [PATCH 101/1001] Fix some random errors.


---

diff --git a/hubs/hinting.py b/hubs/hinting.py
index 47e7d14..9f049f3 100644
--- a/hubs/hinting.py
+++ b/hubs/hinting.py
@@ -10,7 +10,8 @@ log = logging.getLogger('hubs.hinting')
 def hint(topics=None, categories=None, usernames=None):
     topics = topics or []
     categories = categories or []
-    usernames = usernames or lambda x: []
+    default_usernames = lambda x: []
+    usernames = usernames or default_usernames
 
     @decorator.decorator
     def wrapper(fn, *args, **kwargs):
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index 55693c9..b0df6cc 100644
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
 
diff --git a/hubs/widgets/avatar.py b/hubs/widgets/avatar.py
index bcda21d..bf49bf6 100644
--- a/hubs/widgets/avatar.py
+++ b/hubs/widgets/avatar.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.utils import username2avatar
 
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 0c22872..5f985af 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 
 import jinja2

From df63243ed3cdbe80872b8d377f98b1f9a5127ec9 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 08 2015 04:59:05 +0000
Subject: [PATCH 102/1001] Add a script to populate our db with all users from FAS.


---

diff --git a/populate-all-users.py b/populate-all-users.py
new file mode 100755
index 0000000..401a20e
--- /dev/null
+++ b/populate-all-users.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+""" Populate the hubs db with lots of data from FAS. """
+
+import getpass
+import socket
+import string
+
+import hubs.models
+
+import fedora.client.fas2
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
+
+fasclient = fedora.client.fas2.AccountSystem(
+    username=raw_input('Your FAS username: '),
+    password=getpass.getpass(),
+)
+timeout = socket.getdefaulttimeout()
+socket.setdefaulttimeout(None)
+
+for letter in reversed(sorted(list(set(string.letters.lower())))):
+    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
+    print "Querying FAS for the %r users.. hang on." % letter
+    request = fasclient.send_request('/user/list',
+                                    req_params={'search': '%s*' % letter},
+                                    auth=True,
+                                    timeout=500)
+    users = request['people']
+
+    for user in users:
+        username = user['username']
+        fullname = user['human_name']
+        openid = '%s.id.fedoraproject.org' % username
+        print "Creating account for %r" % openid
+        hubs.models.User.get_or_create(
+            session, openid=openid, fullname=fullname)
+
+    session.commit()

From 3e78b7f1b0c5cf4459a72996a0c53780fa39b121 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 08 2015 05:01:21 +0000
Subject: [PATCH 103/1001] Merge branch 'feature/mass-populate' into develop


---

diff --git a/hubs/hinting.py b/hubs/hinting.py
index 47e7d14..9f049f3 100644
--- a/hubs/hinting.py
+++ b/hubs/hinting.py
@@ -10,7 +10,8 @@ log = logging.getLogger('hubs.hinting')
 def hint(topics=None, categories=None, usernames=None):
     topics = topics or []
     categories = categories or []
-    usernames = usernames or lambda x: []
+    default_usernames = lambda x: []
+    usernames = usernames or default_usernames
 
     @decorator.decorator
     def wrapper(fn, *args, **kwargs):
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index 55693c9..b0df6cc 100644
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
 
diff --git a/hubs/widgets/avatar.py b/hubs/widgets/avatar.py
index bcda21d..bf49bf6 100644
--- a/hubs/widgets/avatar.py
+++ b/hubs/widgets/avatar.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.utils import username2avatar
 
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 0c22872..5f985af 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 
 import jinja2
diff --git a/populate-all-users.py b/populate-all-users.py
new file mode 100755
index 0000000..401a20e
--- /dev/null
+++ b/populate-all-users.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+""" Populate the hubs db with lots of data from FAS. """
+
+import getpass
+import socket
+import string
+
+import hubs.models
+
+import fedora.client.fas2
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
+
+fasclient = fedora.client.fas2.AccountSystem(
+    username=raw_input('Your FAS username: '),
+    password=getpass.getpass(),
+)
+timeout = socket.getdefaulttimeout()
+socket.setdefaulttimeout(None)
+
+for letter in reversed(sorted(list(set(string.letters.lower())))):
+    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
+    print "Querying FAS for the %r users.. hang on." % letter
+    request = fasclient.send_request('/user/list',
+                                    req_params={'search': '%s*' % letter},
+                                    auth=True,
+                                    timeout=500)
+    users = request['people']
+
+    for user in users:
+        username = user['username']
+        fullname = user['human_name']
+        openid = '%s.id.fedoraproject.org' % username
+        print "Creating account for %r" % openid
+        hubs.models.User.get_or_create(
+            session, openid=openid, fullname=fullname)
+
+    session.commit()

From 11d0f5544dbc18540fac82c8208347920b0977f0 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 08 2015 05:18:24 +0000
Subject: [PATCH 104/1001] Make the graph have lots of categories for now.


---

diff --git a/hubs/widgets/fedmsgs.py b/hubs/widgets/fedmsgs.py
index 62e4d2c..0a3fb91 100644
--- a/hubs/widgets/fedmsgs.py
+++ b/hubs/widgets/fedmsgs.py
@@ -18,7 +18,7 @@ template = jinja2.Template("""
 """)
 
 from hubs.widgets.chrome import panel
-chrome = panel("Daily Activity")
+chrome = panel("Weekly Activity")
 
 
 @argument(name="username",
@@ -26,7 +26,16 @@ chrome = panel("Daily Activity")
           validator=validators.username,
           help="A FAS username.")
 def data(session, widget, username):
-    url = "https://apps.fedoraproject.org/datagrepper/charts/line?delta=86400&N=12&style=clean&height=300&fill=true&user={username}"
+    categories = ['git', 'Wiki', 'Copr', 'anitya', 'mirrormanager', 'ansible',
+                  'fedoratagger', 'Pkgdb', 'summershum', 'nuancier', 'Mailman',
+                  'fedbadges', 'FMN', 'koschei', 'compose', 'fedimg',
+                  'Jenkins', 'irc', 'FAS', 'buildsys', 'Askbot', 'pagure',
+                  'Bodhi', 'faf', 'kerneltest', 'github', 'Trac', 'meetbot',
+                  'planet', 'fedocal', 'hotness']
+    categories = [c.lower() for c in categories]
+    categories = "&".join(['category=%s' % c for c in categories ])
+    url = "https://apps.fedoraproject.org/datagrepper/charts/stackedline?delta=604800&N=12&style=clean&height=300&fill=true&user={username}&split_on=categories"
+    url = url + "&" + categories
     url = url.format(username=username)
     return dict(url=url)
 

From 0d67c58d52d6d1302bdd6c49bfdaf85c58abaf2d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 09 2015 00:41:04 +0000
Subject: [PATCH 105/1001] Bugfixes.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index 1515966..3cb4fc8 100644
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -46,7 +46,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         self.checks_by_username = collections.defaultdict(list)
 
         widgets = session.query(hubs.models.Widget).all()
-        log.info("Comparing message against %i widgets" % len(widgets))
+        log.info("Building lookup from  %i total widgets" % len(widgets))
         for widget in widgets:
             check = widget.module.should_invalidate
 
@@ -59,7 +59,8 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
             for category in check.hints['categories']:
                 self.checks_by_category[category].append((check, widget,))
 
-            for username in check.hints['usernames_function']:
+            usernames = check.hints['usernames_function'](widget)
+            for username in usernames:
                 self.checks_by_username[username].append((check, widget,))
 
     @property
@@ -99,16 +100,16 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
 
         # Start this by finding a subset of widget checks that might match this
         # message. Look them up based on the hints they declare.
-        checks = \
-            set(self.checks_by_topic[topic]) + \
-            set(self.checks_by_category[category])
+        checks = set(
+            self.checks_by_topic[topic] + self.checks_by_category[category]
+        )
         log.info("Found %i checks to try for this message" % len(checks))
 
         # Then, with that hopefully smaller list of checks, try them all and
         # see if any tell us that we should nuke various data caches.
         for check, widget in checks:
             if check(msg, session, widget):
-                log.info("Invalidating cache for %r" % widget)
+                log.info("! Invalidating cache for %r" % widget)
                 # Invalidate the cache...
                 invalidate_cache(widget.module, **widget.config)
                 # Rebuild it.
diff --git a/hubs/hinting.py b/hubs/hinting.py
index 9f049f3..b04d688 100644
--- a/hubs/hinting.py
+++ b/hubs/hinting.py
@@ -1,4 +1,3 @@
-import collections
 import decorator
 
 import fedmsg.config
@@ -22,7 +21,7 @@ def hint(topics=None, categories=None, usernames=None):
         wrapped.hints = dict(
             topics=topics,
             categories=categories,
-            username_function=usernames,
+            usernames_function=usernames,
         )
         return wrapped
 
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 36d4a1a..885108d 100644
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -1,3 +1,4 @@
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
 
@@ -17,6 +18,7 @@ def data(session, widget, text):
     return dict(text=text)
 
 
+@hint(topics=[_('hubs.widget.update')])
 def should_invalidate(message, session, widget):
     if message['topic'].endswith('hubs.widget.update'):
         if message['msg']['widget']['id'] == widget.id:

From c250e651ffde60b66fee4033a07717273f6a2ed0 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 09 2015 00:55:04 +0000
Subject: [PATCH 106/1001] Tweak language to distinguish between the widget data cache and the widget check lookups.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index 3cb4fc8..a0c3f24 100644
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -28,10 +28,10 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         if not self.uri:
             raise ValueError('hubs.sqlalchemy.uri must be present')
 
-        self.hint_cache_lock = threading.Lock()
+        self.hint_lookup_lock = threading.Lock()
         session = self.make_session()
-        with self.hint_cache_lock:
-            self.rebuild_hubs_hint_caches(session)
+        with self.hint_lookup_lock:
+            self.rebuild_hubs_hint_lookups(session)
         session.commit()  # transaction is committed here
         session.close()
 
@@ -40,7 +40,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
     def make_session(self):
         return hubs.models.init(self.uri)
 
-    def rebuild_hubs_hint_caches(self, session):
+    def rebuild_hubs_hint_lookups(self, session):
         self.checks_by_topic = collections.defaultdict(list)
         self.checks_by_category = collections.defaultdict(list)
         self.checks_by_username = collections.defaultdict(list)
@@ -63,8 +63,13 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
             for username in usernames:
                 self.checks_by_username[username].append((check, widget,))
 
+        log.info("Lookup sizes are:")
+        log.info("- %i topics" % len(self.checks_by_topic))
+        log.info("- %i categories" % len(self.checks_by_category))
+        log.info("- %i usernames" % len(self.checks_by_username))
+
     @property
-    def cache_initialized(self):
+    def lookup_initialized(self):
         return self.checks_by_topic and self.checks_by_category
 
     def consume(self, raw_msg):
@@ -89,11 +94,11 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         log.info("CacheInvalidatorExtraordinaire received %s %s",
                   msg['msg_id'], msg['topic'])
 
-        if category == 'hubs' or not self.cache_initialized:
+        if category == 'hubs' or not self.lookup_initialized:
             # Someone has modified an object in the hubs database, so let's
-            # rebuild our cache of our own database.
-            with self.hint_cache_lock:
-                self.rebuild_hubs_hint_caches(session)
+            # rebuild our lookup table of our own database.
+            with self.hint_lookup_lock:
+                self.rebuild_hubs_hint_lookups(session)
 
         # Begin our real work.
         # Find which widgets should have their caches nuked and make it so.

From 4de114460f71f736fd625a19ae051462136487ff Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 09 2015 00:58:01 +0000
Subject: [PATCH 107/1001] Update gunicorn instructions.


---

diff --git a/README.rst b/README.rst
index fc8cdd3..942a73c 100644
--- a/README.rst
+++ b/README.rst
@@ -31,7 +31,7 @@ And then navigate to http://localhost:5000/designteam
 If you want to test it with 8 worker threads, try ``gunicorn``::
 
     $ pip install gunicorn
-    $ gunicorn -w 8 hubs.app:app
+    $ gunicorn -w 8 hubs.app:app -t 60 --reload
 
 Hacking on Widgets one-liner::
 

From a64995f4cb4dc4590c5a114a9cd1ca36976e274c Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 09 2015 01:40:48 +0000
Subject: [PATCH 108/1001] Allow widgets to know who is logged in, so they can display themselves differently.


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index e864e5b..76c5748 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -74,6 +74,15 @@ def prepare_registry(registry):
 validate_registry(registry)
 prepare_registry(registry)
 
+
+def get_site_vars():
+    import flask
+    return dict(
+        session=flask.app.session,
+        g=flask.g,
+    )
+
+
 def render(module, session, widget, *args, **kwargs):
     """ Main API entry point.
 
@@ -82,5 +91,8 @@ def render(module, session, widget, *args, **kwargs):
     # The API returns exactly this data.  Shared cache
     data = module.data(session, widget, *args, **kwargs)
 
+    # Also expose some site-level info to the widget here at render-time
+    data.update(get_site_vars())
+
     # Use the API data to fill out a template, and potentially decorate it.
     return module.render(**data)
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 5f985af..2f075ab 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -2,9 +2,13 @@ from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 
 import jinja2
-
 import requests
 
+import fedmsg.config
+import fedmsg.meta
+
+config = fedmsg.config.load_config()
+
 chrome = panel()
 template = jinja2.Template("""
 <div class="stats-container">
@@ -12,7 +16,9 @@ template = jinja2.Template("""
     <tr><th>FedMsgs</th><th>Subscribers</th></tr>
     <tr class="text-info"><td>{{fedmsgs}}</td><td>{{subscribers}}</td></tr>
   </table>
+  {% if session['nickname'] != username %}
   <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+  {% endif %}
 </div>
 """)
 
@@ -23,6 +29,7 @@ def data(session, widget, username):
     response = requests.get(url)
     fedmsgs = response.json()['total']
     return dict(
+        username=username,
         fedmsgs=fedmsgs,
         subscribers=len(widget.hub.subscribers),
     )
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 9e40b73..6bcee7b 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -12,8 +12,10 @@ import hubs.validators as validators
 # TODO -- add approve/deny buttons or just link through to pkgdb
 template = jinja2.Template("""
 {% if pending_acls %}
+{% if session['nickname'] == username %}
 <a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/pkgdb/acl/pending/">Manage requests</a>
 <hr/>
+{% endif %}
 <ul class="media-list">
 {% for acl in pending_acls %}
     <li class="media">
@@ -55,6 +57,7 @@ def data(session, widget, username):
     data = response.json()
     for acl in data['pending_acls']:
         acl['avatar'] = username2avatar(acl['user'], s=32)
+    data['username'] = username
     return data
 
 
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index da410db..59860a7 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -11,8 +11,10 @@ import hubs.validators as validators
 # TODO -- add approve/deny buttons or just link through to pkgdb
 template = jinja2.Template("""
 {% if updates %}
+{% if session['nickname'] == username %}
 <a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
 <hr/>
+{% endif %}
 <ul class="media-list">
 {% for update in updates %}
     <li class="media">

From 803829729f9d1932da971edd80e3a2af303537a3 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 09 2015 02:20:46 +0000
Subject: [PATCH 109/1001] Shuffle debug statements.


---

diff --git a/fedmsg.d/base.py b/fedmsg.d/base.py
new file mode 100644
index 0000000..95612f9
--- /dev/null
+++ b/fedmsg.d/base.py
@@ -0,0 +1,70 @@
+# This file is part of fedmsg.
+# Copyright (C) 2012 Red Hat, Inc.
+#
+# fedmsg is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# fedmsg 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with fedmsg; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Authors:  Ralph Bean <rbean@redhat.com>
+
+import os
+
+config = dict(
+    # Set this to dev if you're hacking on fedmsg or an app.
+    # Set to stg or prod if running in the Fedora Infrastructure
+    environment="dev",
+
+    # Default is 0
+    high_water_mark=0,
+    io_threads=1,
+
+    ## For the fedmsg-hub and fedmsg-relay. ##
+
+    # This is a status dir to keep a record of the last processed message
+    #status_directory=os.getcwd() + "/status",
+    #status_directory='/var/run/fedmsg/status',
+
+    # This is the URL of a datagrepper instance that we can query for backlog.
+    #datagrepper_url="https://apps.fedoraproject.org/datagrepper/raw",
+
+    # We almost always want the fedmsg-hub to be sending messages with zmq as
+    # opposed to amqp or stomp.
+    zmq_enabled=True,
+
+    # When subscribing to messages, we want to allow splats ('*') so we tell
+    # the hub to not be strict when comparing messages topics to subscription
+    # topics.
+    zmq_strict=False,
+
+    # Number of seconds to sleep after initializing waiting for sockets to sync
+    post_init_sleep=0.5,
+
+    # Wait a whole second to kill all the last io threads for messages to
+    # exit our outgoing queue (if we have any).  This is in milliseconds.
+    zmq_linger=1000,
+
+    # See the following
+    #   - http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
+    #   - http://api.zeromq.org/3-2:zmq-setsockopt
+    zmq_tcp_keepalive=1,
+    zmq_tcp_keepalive_cnt=3,
+    zmq_tcp_keepalive_idle=60,
+    zmq_tcp_keepalive_intvl=5,
+
+    # Number of miliseconds that zeromq will wait to reconnect until it gets 
+    # a connection if an endpoint is unavailable.
+    zmq_reconnect_ivl=100,
+    # Max delay that you can reconfigure to reduce reconnect storm spam. This
+    # is in miliseconds.
+    zmq_reconnect_ivl_max=1000,
+)
diff --git a/fedmsg.d/logging.py b/fedmsg.d/logging.py
new file mode 100644
index 0000000..c31901c
--- /dev/null
+++ b/fedmsg.d/logging.py
@@ -0,0 +1,40 @@
+# Setup fedmsg logging.
+# See the following for constraints on this format https://bit.ly/Xn1WDn
+bare_format = "[%(asctime)s][%(name)10s %(levelname)7s] %(message)s"
+
+config = dict(
+    logging=dict(
+        version=1,
+        formatters=dict(
+            bare={
+                "datefmt": "%Y-%m-%d %H:%M:%S",
+                "format": bare_format
+            },
+        ),
+        handlers=dict(
+            console={
+                "class": "logging.StreamHandler",
+                "formatter": "bare",
+                "level": "DEBUG",
+                "stream": "ext://sys.stdout",
+            },
+        ),
+        loggers=dict(
+            fedmsg={
+                "level": "INFO",
+                "propagate": False,
+                "handlers": ["console"],
+            },
+            moksha={
+                "level": "INFO",
+                "propagate": False,
+                "handlers": ["console"],
+            },
+            hubs={
+                "level": "DEBUG",
+                "propagate": False,
+                "handlers": ["console"],
+            },
+        ),
+    ),
+)
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index 6bfeb35..464b326 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -5,17 +5,8 @@ config = {
     'hubs.sqlalchemy.uri': 'sqlite:////var/tmp/hubs.db',
 
     'endpoints': {
-        # TODO -- fill these out later...
+        "fedora-infrastructure": [
+            "tcp://hub.fedoraproject.org:9940",
+        ]
     },
-
-    'logging': dict(
-        version=1,
-        loggers=dict(
-            hubs={
-                "level": "DEBUG",
-                "propagate": False,
-                "handlers": ["console"],
-            },
-        ),
-    ),
 }
diff --git a/hubs/consumer.py b/hubs/consumer.py
index a0c3f24..37faff3 100644
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -19,7 +19,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
     config_key = 'hubs.consumer.enabled'
 
     def __init__(self, *args, **kwargs):
-        log.info("CacheInvalidatorExtraordinaire initializing")
+        log.debug("CacheInvalidatorExtraordinaire initializing")
         super(CacheInvalidatorExtraordinaire, self).__init__(*args, **kwargs)
 
         self.uri = self.hub.config.get('hubs.sqlalchemy.uri', None)
@@ -34,8 +34,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
             self.rebuild_hubs_hint_lookups(session)
         session.commit()  # transaction is committed here
         session.close()
-
-        log.info("CacheInvalidatorExtraordinaire initialized")
+        log.debug("CacheInvalidatorExtraordinaire initialized")
 
     def make_session(self):
         return hubs.models.init(self.uri)
@@ -91,7 +90,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
                 return
 
         start = time.time()
-        log.info("CacheInvalidatorExtraordinaire received %s %s",
+        log.debug("CacheInvalidatorExtraordinaire received %s %s",
                   msg['msg_id'], msg['topic'])
 
         if category == 'hubs' or not self.lookup_initialized:
@@ -108,7 +107,12 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         checks = set(
             self.checks_by_topic[topic] + self.checks_by_category[category]
         )
-        log.info("Found %i checks to try for this message" % len(checks))
+
+        statement = "Found %i checks to try for this message" % len(checks)
+        if checks:
+            log.info(statement)
+        else:
+            log.debug(statement)
 
         # Then, with that hopefully smaller list of checks, try them all and
         # see if any tell us that we should nuke various data caches.
@@ -121,7 +125,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
                 widget.module.data(session, widget, **widget.config)
                 # TODO -- fire off an EventSource notice that we updated stuff
 
-        log.info("Done.  %0.2fs %s %s",
+        log.debug("Done.  %0.2fs %s %s",
                   time.time() - start, msg['msg_id'], msg['topic'])
 
     def stop(self):

From 3148d22cb72d14ea136160c4f044d6a05744f862 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 09 2015 02:27:50 +0000
Subject: [PATCH 110/1001] Add a script to delete a user for development.


---

diff --git a/delete-user.py b/delete-user.py
new file mode 100755
index 0000000..a533a00
--- /dev/null
+++ b/delete-user.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+""" Delete a user from the db.
+
+Useful for testing what happens when you recreate them.
+"""
+
+import sys
+
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
+
+import hubs.models
+
+session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+
+username = raw_input('What user do you want to delete: ')
+openid = '%s.id.fedoraproject.org' % username
+print "Looking for account %r" % openid
+user = hubs.models.User.get(session, openid)
+if not user:
+    print "No such user %r" % openid
+    sys.exit(1)
+
+print "Found %r.  Deleting." % user
+session.delete(user)
+session.commit()

From eabf034e0aea5f8c2d4df7c7773085404d5849db Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 09 2015 04:18:33 +0000
Subject: [PATCH 111/1001] Add the start of the feed widget.


---

diff --git a/delete-user.py b/delete-user.py
index a533a00..acc2563 100755
--- a/delete-user.py
+++ b/delete-user.py
@@ -19,8 +19,15 @@ print "Looking for account %r" % openid
 user = hubs.models.User.get(session, openid)
 if not user:
     print "No such user %r" % openid
-    sys.exit(1)
+else:
+    print "Found %r.  Deleting." % user
+    session.delete(user)
+
+hub = hubs.models.Hub.get(session, username)
+if not hub:
+    print "No such hub %r" % username
+else:
+    print "Found %r.  Deleting." % hub
+    session.delete(hub)
 
-print "Found %r.  Deleting." % user
-session.delete(user)
 session.commit()
diff --git a/fedmsg.d/fas_credentials.py b/fedmsg.d/fas_credentials.py
new file mode 100644
index 0000000..7f63432
--- /dev/null
+++ b/fedmsg.d/fas_credentials.py
@@ -0,0 +1,19 @@
+import commands
+import getpass
+import os
+
+username = os.environ.get('BODHI_USER')
+if not username:
+    username = raw_input('FAS username: ')
+
+if os.path.exists('/usr/bin/pass'):
+    password = commands.getoutput('pass sys/fas')
+else:
+    password = getpass.getpass('FAS password: ')
+
+config = {
+    'fas_credentials': {
+        'username': username,
+        'password': password,
+    }
+}
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index 464b326..b803bad 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -9,4 +9,19 @@ config = {
             "tcp://hub.fedoraproject.org:9940",
         ]
     },
+
+    'datanommer.sqlalchemy.uri': 'postgres://postgres:laksjdf@127.0.0.1/datanommer',
+
+    'fmn.url': 'https://apps.fedoraproject.org/notifications',
+
+    # Some configuration for the rule processors
+    "fmn.rules.utils.use_pkgdb2": False,
+    "fmn.rules.utils.pkgdb2_api_url": "http://209.132.184.188/api/",
+    "fmn.rules.cache": {
+        "backend": "dogpile.cache.dbm",
+        "expiration_time": 300,
+        "arguments": {
+            "filename": "/var/tmp/fmn-cache.dbm",
+        },
+    },
 }
diff --git a/hubs/app.py b/hubs/app.py
index 9ef867d..cbc22e7 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,30 +1,52 @@
 import functools
+import logging
 import os
 
 import flask
+import flask.json
 import munch
 
 from flask.ext.openid import OpenID
 
 import hubs.models
 
+import datanommer.models
+
+
 app = flask.Flask(__name__)
 
+logging.basicConfig()
+
 
 # TODO - put this in config so we can migrate to pagure
 # TODO - instead of 'develop', use the version from pkg_resources to figure out
 #        the right tag to link people to.  AGPL ftw.
 SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'#/hubs/widgets/badges.py'
 
-
 app.config.from_object('hubs.default_config')
 if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
 
 import fedmsg.config
+import fedmsg.meta
 fedmsg_config = fedmsg.config.load_config()
+fedmsg.meta.make_processors(**fedmsg_config)
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+datanommer.models.init(fedmsg_config['datanommer.sqlalchemy.uri'])
+
+
+class CustomJSONEncoder(flask.json.JSONEncoder):
+    def default(self, o):
+        try:
+            iterable = iter(o)
+        except TypeError:
+            pass
+        else:
+            return list(iterable)
+        return flask.json.JSONEncoder.default(self, o)
+
+app.json_encoder = CustomJSONEncoder
 
 
 @app.route('/')
diff --git a/hubs/consumer.py b/hubs/consumer.py
index 37faff3..81c4717 100644
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -4,7 +4,9 @@ import collections
 import threading
 import time
 
+import datanommer.models
 import fedmsg.consumers
+import fedmsg.meta
 
 import hubs.models
 
@@ -28,12 +30,17 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         if not self.uri:
             raise ValueError('hubs.sqlalchemy.uri must be present')
 
+        fedmsg.meta.make_processors(**self.hub.config)
+
         self.hint_lookup_lock = threading.Lock()
         session = self.make_session()
         with self.hint_lookup_lock:
             self.rebuild_hubs_hint_lookups(session)
         session.commit()  # transaction is committed here
         session.close()
+
+        datanommer.models.init(self.hub.config['datanommer.sqlalchemy.uri'])
+
         log.debug("CacheInvalidatorExtraordinaire initialized")
 
     def make_session(self):
diff --git a/hubs/defaults.py b/hubs/defaults.py
index baa60c6..a26b9de 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -6,15 +6,16 @@ import hubs.models
 def add_user_widgets(session, hub, username, fullname):
     """ Some defaults for an individual user's hub. """
     widget = hubs.models.Widget(
-        plugin='sticky', index=0, left=True,
+        plugin='fedmsgs', index=0, left=True,
         _config=json.dumps({
-            'text': 'TODO -- Put a fancy graph here...',
+            'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='fedmsgs', index=1, left=True,
+        plugin='feed', index=1, left=True,
         _config=json.dumps({
             'username': username,
+            'fmn_context': 'irc',  # TODO -- make this 'hubs'
         }))
     hub.widgets.append(widget)
 
diff --git a/hubs/models.py b/hubs/models.py
index b129f5d..e4c7fa4 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -99,6 +99,8 @@ class Hub(BASE):
     def by_name(cls, session, name):
         return session.query(cls).filter_by(name=name).first()
 
+    get = by_name
+
     @classmethod
     def create_user_hub(cls, session, username, fullname):
         hub = cls(name=username, summary=fullname)
diff --git a/hubs/validators.py b/hubs/validators.py
index 1079234..cd3d7f6 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -13,3 +13,9 @@ def link(session, value):
 def username(session, value):
     openid = 'http://%s.id.fedoraproject.org/' % value
     return not hubs.models.User.by_openid(session, openid) is None
+
+def fmn_context(session, value):
+    # TODO get this from the fedmsg config.
+    return value in [
+        'irc', 'email', 'android', 'desktop', 'hubs',
+    ]
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 76c5748..94ffaa2 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -7,6 +7,7 @@ from hubs.widgets import avatar
 from hubs.widgets import badges
 from hubs.widgets import fedmsgs
 from hubs.widgets import fedmsgstats
+from hubs.widgets import feed
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -23,6 +24,8 @@ registry = {
     'badges': badges,
     'fedmsgs': fedmsgs,
     'fedmsgstats': fedmsgstats,
+    'feed': feed,
+
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
 }
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
new file mode 100644
index 0000000..3409ea6
--- /dev/null
+++ b/hubs/widgets/feed.py
@@ -0,0 +1,137 @@
+from __future__ import print_function
+
+from hubs.hinting import hint
+from hubs.widgets.base import argument
+
+import fmn.lib
+import fmn.lib.hinting
+
+import datanommer.models
+
+import arrow
+import jinja2
+import munch
+import requests
+
+import hubs.validators as validators
+
+import datetime
+import logging
+log = logging.getLogger('hubs')
+
+import fedmsg.config
+config = fedmsg.config.load_config()
+fmn_url = config['fmn.url']
+
+
+bazillion = 1000
+paths = fmn.lib.load_rules(root='fmn.rules')
+
+
+template = jinja2.Template("""
+{% for match in matches %}
+<div class="panel panel-default">
+  <div class="panel-body">
+    <div class="media">
+      <div class="media-left">
+        <a href="{{match['link']}} target="_blank">
+          <img class="media-object img-responsive square-32 img-circle" src="{{match['secondary_icon']}}">
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">{{match['subtitle']}}</h4>
+        {{match['human_time']}}
+      </div>
+    </div>
+  </div>
+</div>
+{% endfor %}
+""")
+
+# No chrome around the feed.
+#from hubs.widgets.chrome import panel
+#chrome = panel()
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+@argument(name="fmn_context",
+          default="irc", # TODO - Make this 'hubs', or...
+          validator=validators.fmn_context,
+          help="A FMN context.")
+def data(session, widget, username, fmn_context):
+    openid = '%s.id.fedoraproject.org' % username
+    url = '/'.join([fmn_url, 'api', openid, fmn_context])
+    log.info("Getting FMN preferences from %s" % url)
+    print(url)
+    response = requests.get(url)
+    preference = response.json()
+    preference = rehydrate_preferences(preference)
+
+    # The smaller we make this, the faster it is.
+    delta = datetime.timedelta(days=365)
+    end = datetime.datetime.utcnow()
+
+    # We currently only support getting the first page.
+    # The widget framework as currently written doesn't support
+    # multiple pages yet.
+    page = 1
+
+    messages = []
+    for filter in preference['filters']:
+        rules = filter['rules']
+        fmn_hinting = fmn.lib.hinting.gather_hinting(config, rules, paths)
+        total, pages, rows = datanommer.models.Message.grep(
+            start=end-delta,
+            end=end,
+            rows_per_page=bazillion,
+            page=page,
+            order='desc',
+            **fmn_hinting
+        )
+        messages.extend(rows)
+
+    matches = []
+    for message in messages:
+        original = message.__json__()
+        recipients = fmn.lib.recipients(
+            [preference], message.__json__(), paths, config)
+        if recipients:
+            matches.append(original)
+
+    # TODO - sort messages and remove duplicates
+
+    # Smash multiple messages into single ones
+    matches = fedmsg.meta.conglomerate(matches, **config)
+
+    return dict(
+        matches=matches,
+    )
+
+
+@hint()
+def should_invalidate(message, session, widget):
+    # only if a new message would match the FMN filters would this be
+    # invalidated... but that is as expensive as being FMN ourselves.
+    raise NotImplementedError
+
+
+def rehydrate_preferences(preference):
+    for fltr in preference['filters']:
+        fltr['rules'] = [munch.Munch(r) for r in fltr['rules']]
+        for rule in fltr['rules']:
+            code_path = str(rule.code_path)
+            rule.fn = fedmsg.utils.load_class(code_path)
+
+    return preference
+
+def make_result(msg, d):
+    return {
+        'icon': fedmsg.meta.msg2icon(d, **config),
+        'icon2': fedmsg.meta.msg2secondary_icon(d, **config),
+        'subtitle': fedmsg.meta.msg2subtitle(d, **config),
+        'link': fedmsg.meta.msg2link(d, **config),
+        'time': arrow.get(msg.timestamp).humanize(),
+    }
diff --git a/requirements.txt b/requirements.txt
index 820a56c..383db66 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,3 +5,9 @@ dogpile.cache
 fedmsg_meta_fedora_infrastructure
 flask-openid
 munch
+arrow
+fmn.lib
+fmn.rules
+datanommer.models
+fb-re2
+psycopg2

From e6515440baff1235bf33f278caf7671f8d4465c0 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 10 2015 02:50:21 +0000
Subject: [PATCH 112/1001] fb-re2 is really optional.. but more importantly, it breaks py3 compat.


---

diff --git a/requirements.txt b/requirements.txt
index 383db66..62cb8fb 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,5 +9,4 @@ arrow
 fmn.lib
 fmn.rules
 datanommer.models
-fb-re2
 psycopg2

From c8790427bea607b04371fe76481b9f5f4320055e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 10 2015 03:41:17 +0000
Subject: [PATCH 113/1001] Fix some python3-isms.


---

diff --git a/fedmsg.d/fas_credentials.py b/fedmsg.d/fas_credentials.py
index 7f63432..f0d1f02 100644
--- a/fedmsg.d/fas_credentials.py
+++ b/fedmsg.d/fas_credentials.py
@@ -1,13 +1,15 @@
-import commands
 import getpass
 import os
 
+
 username = os.environ.get('BODHI_USER')
 if not username:
     username = raw_input('FAS username: ')
 
 if os.path.exists('/usr/bin/pass'):
-    password = commands.getoutput('pass sys/fas')
+    import sh  # You'll need to pip install this
+    cmd = sh.Command('pass')
+    password = cmd('sys/fas').strip()
 else:
     password = getpass.getpass('FAS password: ')
 
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index b803bad..ec13c43 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -21,7 +21,11 @@ config = {
         "backend": "dogpile.cache.dbm",
         "expiration_time": 300,
         "arguments": {
-            "filename": "/var/tmp/fmn-cache.dbm",
+            "filename": "/var/tmp/fmn-cache.db",
         },
     },
+
+    # Run datanommer locally, just for development.
+    'datanommer.enabled': True,
+    'datanommer.sqlalchemy.url': 'postgres://postgres:laksjdf@127.0.0.1/datanommer',
 }

From 771255bfc25432fd048a40e0e0ff945d9300fc77 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 11 2015 14:29:36 +0000
Subject: [PATCH 114/1001] Comment out the widget.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index a26b9de..9646f8e 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -11,13 +11,16 @@ def add_user_widgets(session, hub, username, fullname):
             'username': username,
         }))
     hub.widgets.append(widget)
-    widget = hubs.models.Widget(
-        plugin='feed', index=1, left=True,
-        _config=json.dumps({
-            'username': username,
-            'fmn_context': 'irc',  # TODO -- make this 'hubs'
-        }))
-    hub.widgets.append(widget)
+
+    ## The feed widget works, but it needs to be cleaned up lots before we
+    ## throw it in by default.
+    #widget = hubs.models.Widget(
+    #    plugin='feed', index=1, left=True,
+    #    _config=json.dumps({
+    #        'username': username,
+    #        'fmn_context': 'irc',  # TODO -- make this 'hubs'
+    #    }))
+    #hub.widgets.append(widget)
 
     # Right Side Widgets
     widget = hubs.models.Widget(

From c7b6871aaf6fdb5bb2116c88b5f03d0fb46c11f8 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 11 2015 19:52:16 +0000
Subject: [PATCH 115/1001] Switch instructions from py3 to py2.


---

diff --git a/README.rst b/README.rst
index 942a73c..113d297 100644
--- a/README.rst
+++ b/README.rst
@@ -9,13 +9,13 @@ Install fedora dependencies:
 
     $ sudo dnf install gcc gcc-c++ sqlite-devel 
 
-Hubs should work on python2 **and** python3, so let's default to python3 and
-see how that goes.
+Hubs should work on either python2 **or** python3.  These instructions will
+show the way for python2 only, though.
 
 Setup a python virtualenv::
 
-    $ sudo yum install python-virtualenvwrapper
-    $ mkvirtualenv --python=$(which python3) hubs
+    $ sudo dnf install python-virtualenvwrapper
+    $ mkvirtualenv hubs
 
 Install the dependencies from PyPI::
 
@@ -23,8 +23,8 @@ Install the dependencies from PyPI::
 
 Try running it with::
 
-    $ PYTHONPATH=. python3 populate.py  # To create the db
-    $ PYTHONPATH=. python3 hubs/app.py  # To run the dev server
+    $ PYTHONPATH=. python populate.py  # To create the db
+    $ PYTHONPATH=. python hubs/app.py  # To run the dev server
 
 And then navigate to http://localhost:5000/designteam
 
@@ -35,7 +35,7 @@ If you want to test it with 8 worker threads, try ``gunicorn``::
 
 Hacking on Widgets one-liner::
 
-    $ rm /var/tmp/hubs.db; PYTHONPATH=. python3 populate.py; gunicorn -w 8 hubs.app:app
+    $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 hubs.app:app
 
 Internal design
 ---------------

From cd98033a1355a20d9221f60dff2b06e6d04a4941 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 11 2015 20:45:47 +0000
Subject: [PATCH 116/1001] Delete old fas_credentials file that had too much threebean-specific stuff in it.


---

diff --git a/.gitignore b/.gitignore
index e6e04af..961695c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 *.pyc
 *.egg*
+fedmsg.d/fas_credentials.py
diff --git a/fedmsg.d/fas_credentials.py b/fedmsg.d/fas_credentials.py
deleted file mode 100644
index f0d1f02..0000000
--- a/fedmsg.d/fas_credentials.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import getpass
-import os
-
-
-username = os.environ.get('BODHI_USER')
-if not username:
-    username = raw_input('FAS username: ')
-
-if os.path.exists('/usr/bin/pass'):
-    import sh  # You'll need to pip install this
-    cmd = sh.Command('pass')
-    password = cmd('sys/fas').strip()
-else:
-    password = getpass.getpass('FAS password: ')
-
-config = {
-    'fas_credentials': {
-        'username': username,
-        'password': password,
-    }
-}

From ba5b9a568e32668e1775b6032cad85aee6d67238 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 11 2015 20:51:26 +0000
Subject: [PATCH 117/1001] Add some notes about FAS credentials /cc @oddshocks.


---

diff --git a/README.rst b/README.rst
index 113d297..72df979 100644
--- a/README.rst
+++ b/README.rst
@@ -21,7 +21,20 @@ Install the dependencies from PyPI::
 
     $ pip install -r requirements.txt
 
-Try running it with::
+Give fedora-hubs some FAS credentials.  It's going to need these to query FAS
+for information about other users.  When we deploy this thing to production,
+we'll use a system account for this but for now, just use your personal
+account.  Copy the following into ``fedmsg.d/fas_credentials.py``::
+
+    config = {
+        'fas_credentials': {
+            'username': 'YOUR_FAS_USERNAME_GOES_HERE',
+            'password': 'YOUR_FAS_PASSWORD_GOES_HERE',
+        }
+    }
+
+
+With that, try running the app with::
 
     $ PYTHONPATH=. python populate.py  # To create the db
     $ PYTHONPATH=. python hubs/app.py  # To run the dev server

From 7553b8ac874fde299ccc133b8153fd3dc6838e22 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jun 14 2015 00:50:11 +0000
Subject: [PATCH 118/1001] Expose some more information via the json api.


---

diff --git a/hubs/app.py b/hubs/app.py
index cbc22e7..74ea4af 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -60,34 +60,17 @@ def index():
 @app.route('/<name>')
 @app.route('/<name>/')
 def hub(name):
-    hub = session.query(hubs.models.Hub)\
-        .filter(hubs.models.Hub.name==name)\
-        .first()
-
-    if not hub:
-        flask.abort(404)
-
+    hub = get_hub(session, name)
     return flask.render_template('hubs.html', hub=hub, session=session)
 
 
-def get_widget(session, hub, idx):
-    try:
-        idx = int(idx)
-    except TypeError:
-        flask.abort(404)
-
-    hub = session.query(hubs.models.Hub)\
-        .filter(hubs.models.Hub.name==hub)\
-        .first()
-
-    if not hub:
-        flask.abort(404)
-
-    for widget in hub.widgets:
-        if widget.idx == idx:
-            return widget
-
-    flask.abort(404)
+@app.route('/<name>/json')
+@app.route('/<name>/json/')
+def hub_json(name):
+    hub = get_hub(session, name)
+    response = flask.jsonify(hub.__json__(session))
+    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
+    return response
 
 
 @app.route('/<hub>/<idx>')
@@ -101,16 +84,8 @@ def widget_render(hub, idx):
 @app.route('/<hub>/<idx>/json/')
 def widget_json(hub, idx):
     widget = get_widget(session, hub, idx)
-    from hubs.widgets import registry
-    module = registry[widget.plugin]
-    data = module.data(session, widget, **widget.config)
-    response = flask.jsonify(data)
-
-    # We don't actually need these two headers.  Just messing around.
-    response.headers['X-fedora-hubs-hub-name'] = hub
-    response.headers['X-fedora-hubs-widget-id'] = idx
-    # TODO -- add other headers here as we decide we need them.
-
+    response = flask.jsonify(widget.__json__(session))
+    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
     return response
 
 
@@ -223,6 +198,36 @@ def check_auth():
         flask.g.auth.email = flask.session.get('email', None)
 
 
+def get_hub(session, name):
+    """ Utility shorthand to get a hub and 404 if not found. """
+    hub = session.query(hubs.models.Hub)\
+        .filter(hubs.models.Hub.name==name)\
+        .first()
+
+    if not hub:
+        flask.abort(404)
+
+    return hub
+
+
+def get_widget(session, hub, idx):
+    """ Utility shorthand to get a widget and 404 if not found. """
+    try:
+        idx = int(idx)
+    except TypeError:
+        flask.abort(404)
+
+    hub = get_hub(session, hub)
+
+    for widget in hub.widgets:
+        if widget.idx == idx:
+            return widget
+
+    flask.abort(404)
+
+
+
+
 
 if __name__ == '__main__':
     app.run(debug=True)
diff --git a/hubs/models.py b/hubs/models.py
index e4c7fa4..ae2639e 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -123,9 +123,20 @@ class Hub(BASE):
             [w for w in self.widgets if not w.left],
             key=lambda w: w.index)
 
-    def __json__(self, reify=False):
+    def __json__(self, session):
         return {
             'name': self.name,
+            'summary': self.summary,
+
+            # TODO -- splash image
+
+            'widgets': [widget.idx for widget in self.widgets],
+            'left_width': self.left_width,
+
+            # TODO -- these three need to be fleshed out with real fas data.
+            'owners': self.owners,
+            'members': self.members,
+            'subscribers': self.subscribers,
         }
 
 def _config_default(context):
@@ -154,9 +165,19 @@ class Widget(BASE):
     def config_setter(self, config):
         self._config = json.dumps(config)
 
-    def __json__(self, reify=False):
+    def __json__(self, session):
+        module = hubs.widgets.registry[self.plugin]
+        data = module.data(session, self, **self.config)
         return {
+            'id': self.idx,
+            # TODO -- use flask.url_for to get the url for this widget
             'plugin': self.plugin,
+            'description': module.__doc__,
+            'hub': self.hub_id,
+            'left': self.left,
+            'index': self.index,
+            'data': data,
+            'config': self.config,
         }
 
     @property
@@ -174,10 +195,14 @@ class User(BASE):
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
-    def __json__(self, reify=False):
+    def __json__(self, session):
         return {
+            'username': self.username,
             'openid': self.openid,
+            'fullname': self.fullname,
             'created_on': self.created_on,
+            # We'll need hubs subscribed to, owned, etc..
+            #'hubs': [hub.idx for hub in self.hubx],
         }
 
     @property

From e02569cf134de90387e177d23c4ec54b32cf919a Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 19 2015 17:02:24 +0000
Subject: [PATCH 119/1001] updated .gitignore


---

diff --git a/.gitignore b/.gitignore
index 961695c..7b3bc0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 *.pyc
 *.egg*
 fedmsg.d/fas_credentials.py
+node*

From 2c4246769f4bff53b0ded3c7f447a89a766e5d6b Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jun 19 2015 18:16:11 +0000
Subject: [PATCH 120/1001] Added postgresql and postgresql-devel to README.md


---

diff --git a/README.rst b/README.rst
index 72df979..23fc872 100644
--- a/README.rst
+++ b/README.rst
@@ -14,7 +14,7 @@ show the way for python2 only, though.
 
 Setup a python virtualenv::
 
-    $ sudo dnf install python-virtualenvwrapper
+    $ sudo dnf install python-virtualenvwrapper postgresql postgresql-devel
     $ mkvirtualenv hubs
 
 Install the dependencies from PyPI::

From 25b0397ffe857e52d2081676ea320eeb6f580013 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jun 30 2015 19:00:17 +0000
Subject: [PATCH 121/1001] adding bash profile refresh info for when mkvirtualenv does not work


---

diff --git a/README.rst b/README.rst
index 23fc872..19b3ead 100644
--- a/README.rst
+++ b/README.rst
@@ -17,6 +17,11 @@ Setup a python virtualenv::
     $ sudo dnf install python-virtualenvwrapper postgresql postgresql-devel
     $ mkvirtualenv hubs
 
+If the mkvirtualenv command returns "command not found..." you may need to 
+refresh your bash profile:
+
+    $ source ~/.bashrc
+
 Install the dependencies from PyPI::
 
     $ pip install -r requirements.txt

From 3636e42e7d517254b513f7e3b6c8c3d0e9ed7263 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jun 30 2015 19:03:38 +0000
Subject: [PATCH 122/1001] clarifying that fas_credentials.py is a new file you're creating


---

diff --git a/README.rst b/README.rst
index 19b3ead..ad3d926 100644
--- a/README.rst
+++ b/README.rst
@@ -29,7 +29,8 @@ Install the dependencies from PyPI::
 Give fedora-hubs some FAS credentials.  It's going to need these to query FAS
 for information about other users.  When we deploy this thing to production,
 we'll use a system account for this but for now, just use your personal
-account.  Copy the following into ``fedmsg.d/fas_credentials.py``::
+account.  Copy the following into a new file under the fedmsg.d directory
+called fas_credentials.py (``fedmsg.d/fas_credentials.py``) ::
 
     config = {
         'fas_credentials': {

From b08c15b7d7d315c8c1f6f048d688811496a12370 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jun 30 2015 19:04:29 +0000
Subject: [PATCH 123/1001] clarifying how to fill in example fas credentials file


---

diff --git a/README.rst b/README.rst
index ad3d926..0cc29bb 100644
--- a/README.rst
+++ b/README.rst
@@ -39,6 +39,7 @@ called fas_credentials.py (``fedmsg.d/fas_credentials.py``) ::
         }
     }
 
+Make sure to leave the '' around you username and password - don't delete them!
 
 With that, try running the app with::
 

From cabbd0976c6e5f5ce651319fa4235b74960c51ce Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 01 2015 13:47:24 +0000
Subject: [PATCH 124/1001] Cosmetic rst stuff.


---

diff --git a/README.rst b/README.rst
index 19b3ead..d9e78ed 100644
--- a/README.rst
+++ b/README.rst
@@ -17,8 +17,8 @@ Setup a python virtualenv::
     $ sudo dnf install python-virtualenvwrapper postgresql postgresql-devel
     $ mkvirtualenv hubs
 
-If the mkvirtualenv command returns "command not found..." you may need to 
-refresh your bash profile:
+If the mkvirtualenv command returns "command not found..." you may need to
+refresh your bash profile::
 
     $ source ~/.bashrc
 

From 4a8c189ecc80373de39f52a98e6492f4622598ac Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 01 2015 13:57:17 +0000
Subject: [PATCH 125/1001] Some more README cleaning.


---

diff --git a/README.rst b/README.rst
index d9e78ed..6f9afee 100644
--- a/README.rst
+++ b/README.rst
@@ -5,7 +5,7 @@ The latest source is not on GitHub, it is on pagure.io.  You can find it at http
 
 Hacking
 -------
-Install fedora dependencies:
+Install fedora dependencies::
 
     $ sudo dnf install gcc gcc-c++ sqlite-devel 
 
@@ -44,14 +44,15 @@ With that, try running the app with::
     $ PYTHONPATH=. python populate.py  # To create the db
     $ PYTHONPATH=. python hubs/app.py  # To run the dev server
 
-And then navigate to http://localhost:5000/designteam
+And then navigate to http://localhost:5000/
 
 If you want to test it with 8 worker threads, try ``gunicorn``::
 
     $ pip install gunicorn
     $ gunicorn -w 8 hubs.app:app -t 60 --reload
 
-Hacking on Widgets one-liner::
+When hacking on widgets, it is useful to have this one-liner handy.  It removes
+the db alltogether, re-populates it, and restarts the app::
 
     $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 hubs.app:app
 
@@ -70,7 +71,7 @@ in the registry dict in ``hubs/widgets/__init__.py``.
 
 In order to be valid, a widget must have:
 
-- A ``data(request, session, widgets, **kwargs)`` function that returns a
+- A ``data(session, widgets, **kwargs)`` function that returns a
   jsonifiable dict of data.  This will get cached -- more on that later.
 - A ``template`` object that is a jinja2 template for that widget.
 - Optionally, a ``chrome`` decorator.

From 48c186cbd9a67ef4590a5081057e42ea60744fd5 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 01 2015 13:57:33 +0000
Subject: [PATCH 126/1001] Remove some of the uncertain language now that more has been implemented.


---

diff --git a/README.rst b/README.rst
index 6f9afee..f905ded 100644
--- a/README.rst
+++ b/README.rst
@@ -59,13 +59,6 @@ the db alltogether, re-populates it, and restarts the app::
 Internal design
 ---------------
 
-There's no authn or user information at all currently.  There are only:
-
-- widgets
-- hubs (which are just collections of widgets)
-
-How things are currently (they don't have to stay this way):
-
 You write a new widget in the ``hubs/widgets/`` directory and must declare it
 in the registry dict in ``hubs/widgets/__init__.py``.
 
@@ -75,9 +68,6 @@ In order to be valid, a widget must have:
   jsonifiable dict of data.  This will get cached -- more on that later.
 - A ``template`` object that is a jinja2 template for that widget.
 - Optionally, a ``chrome`` decorator.
-
-This isn't implemented yet, but they're going to need:
-
 - A ``should_invalidate(message, session, widget)`` function that will be used to
   *potentially* invalidate the widget's cache. That function will get called by
   a backend daemon listening for fedmsg messages so when you update your group
@@ -94,10 +84,13 @@ Furthermore, a proposal:
   rendering all of the widgets asynchronously on the client.  It could be cool,
   but is new-ground for our team.
 
-Still more proposals:
+  Furthermore, we should likely use something like angular **or** backbone.js
+  to manage the data synchronization with those client-side templates.
+
+Some discussion on how to do pushed updates to web clients:
 
 - We could re-use the existing websocket service we have at
-  wss://hub.fedoraproject.org:9939 but it has some problems:
+  ``wss://hub.fedoraproject.org:9939`` but it has some problems:
 - It is very inflexible.  You can subscribe to fedmsg *topics* and then you
   receive the firehose of those topics. For a widget, we already have to write
   a 'cache invalidation' function that listens for messages and then somehow
@@ -125,8 +118,7 @@ worried *only* about these per-widget JSON responses.
 A picture is worth...
 ---------------------
 
-This is more "proposal" territory.  None of this is implemented, but here are
-some more details on how the whole thing should work together.
+Here are some more details on how the whole thing should work together.
 
 .. figure:: https://raw.githubusercontent.com/ralphbean/fedora-hubs-prototype/develop/docs/diagram.png
    :scale: 50 %

From cdedf8fc4680a6bd0e4ff1e7fb328bf05da1e10f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 01 2015 14:35:58 +0000
Subject: [PATCH 127/1001] Add instructions for how to set up datanommer/postgres.


---

diff --git a/README.rst b/README.rst
index f905ded..f476e39 100644
--- a/README.rst
+++ b/README.rst
@@ -1,10 +1,10 @@
 Source on Pagure.io
--------------------
+===================
 
 The latest source is not on GitHub, it is on pagure.io.  You can find it at https://pagure.io/fedora-hubs
 
 Hacking
--------
+=======
 Install fedora dependencies::
 
     $ sudo dnf install gcc gcc-c++ sqlite-devel 
@@ -56,8 +56,89 @@ the db alltogether, re-populates it, and restarts the app::
 
     $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 hubs.app:app
 
+Feed Widget - the Extra Mile
+----------------------------
+
+One widget (the big tamale -- the feed widget) requires more legwork to stand
+up.  If you just want to see how hubs works and you want to hack on other
+peripheral stuff around it, you don't need to bother with these steps.
+
+The feed widget requires a direct DB connection to the datanommer
+database; it can't proxy through datagrepper because it needs more
+flexibility.  To get this working, you're going to set up:
+
+- a postgres db
+- the datanommer daemon
+
+Start with some required packages::
+
+    $ sudo dnf install postgresql-server python-datanommer-consumer datanommer-commands fedmsg-hub
+
+And there are some support libraries you'll also need::
+
+    $ sudo dnf install python-psycopg2 python-fedmsg-meta-fedora-infrastructure
+
+Now, with packages installed, you need to tell postgres to create its initial filesystem layout::
+
+    $ sudo postgresql-setup initdb
+
+And then, we need to tweak its config to let us connect easily for development::
+
+    $ sudo vim /var/lib/pgsql/data/pg_hba.conf
+
+Change **two lines** from ``ident`` to ``trust``.  These two::
+
+    # IPv4 local connections:
+    host    all             all             127.0.0.1/32            trust
+    # IPv6 local connections:
+    host    all             all             ::1/128                 trust
+
+Start that beast up::
+
+    $ sudo systemctl start postgresql
+
+Now, with the db daemon configured and running, let's configure datanommer.  Edit this file::
+
+    $ sudo vim /etc/fedmsg.d/datanommer.py
+
+And do two things:  1) set enabled to ``True`` and 2) give it a real sqlalchemy url, like this::
+
+    config = {
+        'datanommer.enabled': True,
+        'datanommer.sqlalchemy.url': 'postgres://postgres:whatever@localhost/datanommer',
+    }
+
+Tell postgres that it should create space for a 'datanommer' database with this command::
+
+    $ sudo -u postgres psql -c "CREATE DATABASE datanommer;"
+
+And finally, tell datanommer to create all of its tables in that new db we just created::
+
+    $ datanommer-create-db
+
+Tell the fedmsg-hub daemon to restart itself.  It should pick up datanommer as a plugin and start handing messages to it::
+
+    $ sudo systemctl restart fedmsg-hub
+
+And then, wait a few seconds for a message to get nommed, and then you can
+check that it's working by running ``sudo datanommer-stats``.  It should print
+out some kind of summary about what kinds of messages are in the db now -- it
+will just grow and grow over time::
+
+    $ datanommer-stats
+    [2015-07-01 14:33:21][    fedmsg    INFO] buildsys has 70 entries
+    [2015-07-01 14:33:21][    fedmsg    INFO] faf has 7 entries
+    [2015-07-01 14:33:21][    fedmsg    INFO] copr has 6 entries
+    [2015-07-01 14:33:21][    fedmsg    INFO] askbot has 2 entries
+
+**Lastly**, (fingers crossed) start up the fedora-hubs webapp and load your
+profile page.  Once there are some messages that get into your local database
+that *should* show up on your feed.. they should appear there.  (At very least,
+you shouldn't get an error message about that widget being unable to be
+displayed).
+
 Internal design
----------------
+===============
 
 You write a new widget in the ``hubs/widgets/`` directory and must declare it
 in the registry dict in ``hubs/widgets/__init__.py``.

From f0f5c94fb614236e0605c352b5283108e2447a8b Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 01 2015 17:41:03 +0000
Subject: [PATCH 128/1001] minor tweaks to styling on top bar to better resemble mockup visual design


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 2082a2a..dd536ac 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -10,10 +10,14 @@
       background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
       background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
       background: linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
-      padding: 20px 20px 20px 0;
+      padding: 5px 12px 3px 12px;
       font-family: 'Open Sans', 'sans-serif';
       font-size: 12pt;
     }
+    
+    #logo { text-align: left; }
+  /*  #logo img { padding-left: 1em; }
+    */
     .bookmarks .navbar.navbar-default {
       background-color: #fff;
       margin-bottom: 0;
diff --git a/hubs/static/img/logo-hubs.png b/hubs/static/img/logo-hubs.png
new file mode 100644
index 0000000..88f5ffc
Binary files /dev/null and b/hubs/static/img/logo-hubs.png differ
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index d178a0e..891ce74 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -11,7 +11,8 @@
 <body>
 <div class="super-header">
   <div class="row">
-    <div class="col-md-4 col-md-offset-8">
+	<div class="col-md-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
+    <div class="col-md-8">
       {% if g.auth.logged_in %}
         {# Logged in as #} {{ g.auth.nickname }}
       {% else %}

From 6fec8208a057e5e97b1aa98aef4a20db26f7b0a9 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 01 2015 17:41:50 +0000
Subject: [PATCH 129/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/README.rst b/README.rst
index 0cc29bb..c4696c9 100644
--- a/README.rst
+++ b/README.rst
@@ -1,11 +1,11 @@
 Source on Pagure.io
--------------------
+===================
 
 The latest source is not on GitHub, it is on pagure.io.  You can find it at https://pagure.io/fedora-hubs
 
 Hacking
--------
-Install fedora dependencies:
+=======
+Install fedora dependencies::
 
     $ sudo dnf install gcc gcc-c++ sqlite-devel 
 
@@ -17,8 +17,8 @@ Setup a python virtualenv::
     $ sudo dnf install python-virtualenvwrapper postgresql postgresql-devel
     $ mkvirtualenv hubs
 
-If the mkvirtualenv command returns "command not found..." you may need to 
-refresh your bash profile:
+If the mkvirtualenv command returns "command not found..." you may need to
+refresh your bash profile::
 
     $ source ~/.bashrc
 
@@ -46,39 +46,111 @@ With that, try running the app with::
     $ PYTHONPATH=. python populate.py  # To create the db
     $ PYTHONPATH=. python hubs/app.py  # To run the dev server
 
-And then navigate to http://localhost:5000/designteam
+And then navigate to http://localhost:5000/
 
 If you want to test it with 8 worker threads, try ``gunicorn``::
 
     $ pip install gunicorn
     $ gunicorn -w 8 hubs.app:app -t 60 --reload
 
-Hacking on Widgets one-liner::
+When hacking on widgets, it is useful to have this one-liner handy.  It removes
+the db alltogether, re-populates it, and restarts the app::
 
     $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 hubs.app:app
 
-Internal design
----------------
+Feed Widget - the Extra Mile
+----------------------------
+
+One widget (the big tamale -- the feed widget) requires more legwork to stand
+up.  If you just want to see how hubs works and you want to hack on other
+peripheral stuff around it, you don't need to bother with these steps.
+
+The feed widget requires a direct DB connection to the datanommer
+database; it can't proxy through datagrepper because it needs more
+flexibility.  To get this working, you're going to set up:
+
+- a postgres db
+- the datanommer daemon
+
+Start with some required packages::
+
+    $ sudo dnf install postgresql-server python-datanommer-consumer datanommer-commands fedmsg-hub
+
+And there are some support libraries you'll also need::
+
+    $ sudo dnf install python-psycopg2 python-fedmsg-meta-fedora-infrastructure
+
+Now, with packages installed, you need to tell postgres to create its initial filesystem layout::
 
-There's no authn or user information at all currently.  There are only:
+    $ sudo postgresql-setup initdb
 
-- widgets
-- hubs (which are just collections of widgets)
+And then, we need to tweak its config to let us connect easily for development::
 
-How things are currently (they don't have to stay this way):
+    $ sudo vim /var/lib/pgsql/data/pg_hba.conf
+
+Change **two lines** from ``ident`` to ``trust``.  These two::
+
+    # IPv4 local connections:
+    host    all             all             127.0.0.1/32            trust
+    # IPv6 local connections:
+    host    all             all             ::1/128                 trust
+
+Start that beast up::
+
+    $ sudo systemctl start postgresql
+
+Now, with the db daemon configured and running, let's configure datanommer.  Edit this file::
+
+    $ sudo vim /etc/fedmsg.d/datanommer.py
+
+And do two things:  1) set enabled to ``True`` and 2) give it a real sqlalchemy url, like this::
+
+    config = {
+        'datanommer.enabled': True,
+        'datanommer.sqlalchemy.url': 'postgres://postgres:whatever@localhost/datanommer',
+    }
+
+Tell postgres that it should create space for a 'datanommer' database with this command::
+
+    $ sudo -u postgres psql -c "CREATE DATABASE datanommer;"
+
+And finally, tell datanommer to create all of its tables in that new db we just created::
+
+    $ datanommer-create-db
+
+Tell the fedmsg-hub daemon to restart itself.  It should pick up datanommer as a plugin and start handing messages to it::
+
+    $ sudo systemctl restart fedmsg-hub
+
+And then, wait a few seconds for a message to get nommed, and then you can
+check that it's working by running ``sudo datanommer-stats``.  It should print
+out some kind of summary about what kinds of messages are in the db now -- it
+will just grow and grow over time::
+
+    $ datanommer-stats
+    [2015-07-01 14:33:21][    fedmsg    INFO] buildsys has 70 entries
+    [2015-07-01 14:33:21][    fedmsg    INFO] faf has 7 entries
+    [2015-07-01 14:33:21][    fedmsg    INFO] copr has 6 entries
+    [2015-07-01 14:33:21][    fedmsg    INFO] askbot has 2 entries
+
+**Lastly**, (fingers crossed) start up the fedora-hubs webapp and load your
+profile page.  Once there are some messages that get into your local database
+that *should* show up on your feed.. they should appear there.  (At very least,
+you shouldn't get an error message about that widget being unable to be
+displayed).
+
+Internal design
+===============
 
 You write a new widget in the ``hubs/widgets/`` directory and must declare it
 in the registry dict in ``hubs/widgets/__init__.py``.
 
 In order to be valid, a widget must have:
 
-- A ``data(request, session, widgets, **kwargs)`` function that returns a
+- A ``data(session, widgets, **kwargs)`` function that returns a
   jsonifiable dict of data.  This will get cached -- more on that later.
 - A ``template`` object that is a jinja2 template for that widget.
 - Optionally, a ``chrome`` decorator.
-
-This isn't implemented yet, but they're going to need:
-
 - A ``should_invalidate(message, session, widget)`` function that will be used to
   *potentially* invalidate the widget's cache. That function will get called by
   a backend daemon listening for fedmsg messages so when you update your group
@@ -95,10 +167,13 @@ Furthermore, a proposal:
   rendering all of the widgets asynchronously on the client.  It could be cool,
   but is new-ground for our team.
 
-Still more proposals:
+  Furthermore, we should likely use something like angular **or** backbone.js
+  to manage the data synchronization with those client-side templates.
+
+Some discussion on how to do pushed updates to web clients:
 
 - We could re-use the existing websocket service we have at
-  wss://hub.fedoraproject.org:9939 but it has some problems:
+  ``wss://hub.fedoraproject.org:9939`` but it has some problems:
 - It is very inflexible.  You can subscribe to fedmsg *topics* and then you
   receive the firehose of those topics. For a widget, we already have to write
   a 'cache invalidation' function that listens for messages and then somehow
@@ -126,8 +201,7 @@ worried *only* about these per-widget JSON responses.
 A picture is worth...
 ---------------------
 
-This is more "proposal" territory.  None of this is implemented, but here are
-some more details on how the whole thing should work together.
+Here are some more details on how the whole thing should work together.
 
 .. figure:: https://raw.githubusercontent.com/ralphbean/fedora-hubs-prototype/develop/docs/diagram.png
    :scale: 50 %

From 7b58c22d817af3eb3df8e484a53c98874a1a188b Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 01 2015 17:45:12 +0000
Subject: [PATCH 130/1001] cleanup of sloppiness in css file (whoops)


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index dd536ac..4a41492 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -10,14 +10,13 @@
       background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
       background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
       background: linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
-      padding: 5px 12px 3px 12px;
+      padding: 5px 12px 5px 12px;
       font-family: 'Open Sans', 'sans-serif';
       font-size: 12pt;
     }
     
     #logo { text-align: left; }
-  /*  #logo img { padding-left: 1em; }
-    */
+
     .bookmarks .navbar.navbar-default {
       background-color: #fff;
       margin-bottom: 0;

From 78ee1277eeb5a842bc035906bc05d5af11c57ff0 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 01 2015 17:50:43 +0000
Subject: [PATCH 131/1001] removing branding from bookmark bar; making topbar branding more mobile-friendly

- branding was placed in bookmark bar to make the site more mobile-friendly
- i think maximizing bookmark real estate for desktop users is important tho
  which means removing the branding from the bar (plus the branding shouldn't
  go below the search and personal menu + private messaging)
- i used the bootstrap xs class to make the branding collapse nicely with
  the personal menu and private messaging areas on the topbar in
  mobile situations

---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 891ce74..2c39755 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -11,8 +11,8 @@
 <body>
 <div class="super-header">
   <div class="row">
-	<div class="col-md-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
-    <div class="col-md-8">
+	<div class="col-md-4 col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
+    <div class="col-md-8 col-xs-8">
       {% if g.auth.logged_in %}
         {# Logged in as #} {{ g.auth.nickname }}
       {% else %}
@@ -24,7 +24,6 @@
 <div class="bookmarks">
   <nav class="navbar navbar-default">
     <div class="container-fluid">
-      <!-- Brand and toggle get grouped for better mobile display -->
       <div class="navbar-header">
         <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
           <span class="sr-only">Toggle navigation</span>
@@ -32,7 +31,6 @@
           <span class="icon-bar"></span>
           <span class="icon-bar"></span>
         </button>
-        <a class="navbar-brand" href="#">Fedora Hubs</a>
       </div>
 
       <!-- Collect the nav links, forms, and other content for toggling -->

From 901d8483b03e77c0c606cd67f3dec2f43d0a4238 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 01 2015 17:58:12 +0000
Subject: [PATCH 132/1001] minor tweaks to topbar gradient to better match mockups' visual design


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 4a41492..598aecb 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -6,10 +6,10 @@
     }
     .super-header {
       text-align: right;
-      background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
-      background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
-      background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
-      background: linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,1));
+      background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
+      background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
+      background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
+      background: linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
       padding: 5px 12px 5px 12px;
       font-family: 'Open Sans', 'sans-serif';
       font-size: 12pt;

From 818702e34e770b4a22c5da49bbc8a7494db30f16 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 01 2015 19:43:55 +0000
Subject: [PATCH 133/1001] styling the bookmarks bar to better match the mockup vis design


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 598aecb..058bce7 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -18,10 +18,28 @@
     #logo { text-align: left; }
 
     .bookmarks .navbar.navbar-default {
-      background-color: #fff;
+      background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
+      background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
+      background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
+      background: linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
       margin-bottom: 0;
       text-align: center;
     }
+    
+    .bookmarks .navbar-nav > li > a {
+      padding-bottom: 4.5px;
+      padding-top: 4.5px;
+    }
+
+    /* Bookmarks Bar: active nav item styling */
+    .bookmarks .nav > .active > a,
+    .bookmarks .nav > .active > a:hover,
+    .bookmarks .nav > .active > a:focus {
+      color: #3c6eb4;
+      background-color: transparent;
+      border-bottom: 3px solid #3c6eb4;
+    }
+    
     .header {
       color: #ffffff;
       background-color: #3c6eb4;

From fabe1242212b33f59653a8295258f43c62576a26 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 02 2015 22:05:18 +0000
Subject: [PATCH 134/1001] minor styling to widget panels


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 058bce7..3618ce2 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -66,6 +66,7 @@
       visibility: hidden;
       max-height: 0px;
       overflow: hidden;
+      border: 0;
       transition: max-height 0.4s;
     }
 
@@ -74,7 +75,19 @@
       max-height: 100%;
     }
 
-//flexbox support
+/* generic widget styling */
+.widget .panel-default > .panel-heading {
+    font-family: 'Open Sans', 'sans-serif';
+    color: #fff;
+    background-color: #a7a9ac;
+    border-radius: 0;
+}
+
+.widget .panel-default > .panel-heading h3 {
+    font-weight: 700;
+}
+
+/* flexbox support */
 .flex-container {
     display: flex;
     flex-direction: row;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 2c39755..e8587e6 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -66,7 +66,7 @@
 
     <div class="col-md-{{ hub.right_width }}">
       {% for widget in hub.right_widgets %}
-      <div id="widget-{{ widget.idx }}" class="row"></div>
+      <div id="widget-{{ widget.idx }}" class="widget row"></div>
       {% endfor %}
     </div>
   </div>

From d198ee58283424d6625788d1c9ee0cc5759db088 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 06 2015 19:55:41 +0000
Subject: [PATCH 135/1001] Avatars for hubs.


---

diff --git a/hubs/models.py b/hubs/models.py
index ae2639e..0768e92 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -24,6 +24,7 @@
 import datetime
 import json
 import logging
+import random
 
 import sqlalchemy as sa
 from sqlalchemy import create_engine
@@ -38,6 +39,7 @@ import fedmsg.utils
 
 import hubs.defaults
 import hubs.widgets
+from hubs.utils import username2avatar
 
 
 class HubsBase(object):
@@ -58,6 +60,10 @@ BASE = declarative_base(cls=HubsBase)
 log = logging.getLogger(__name__)
 
 
+placekitten = lambda: "https://placekitten.com/g/%i/%i" % (
+    random.randint(150,350), random.randint(150, 350))
+
+
 def init(db_url, debug=False, create=False):
     """ Create the tables in the database using the information from the
     url obtained.
@@ -87,6 +93,9 @@ class Hub(BASE):
     widgets = relation('Widget', backref=backref('hub'))
     left_width = sa.Column(sa.Integer, nullable=False, default=8)
 
+    # A URL to the "avatar" for this hub.
+    avatar = sa.Column(sa.String(256), default=placekitten)
+
     #fas_group = sa.Column(sa.String(32), nullable=False)
 
     # This is just some silly dev data.  eventually, connect this
@@ -103,7 +112,8 @@ class Hub(BASE):
 
     @classmethod
     def create_user_hub(cls, session, username, fullname):
-        hub = cls(name=username, summary=fullname)
+        hub = cls(name=username, summary=fullname,
+                  avatar=username2avatar(username))
         session.add(hub)
         hubs.defaults.add_user_widgets(session, hub, username, fullname)
 
@@ -195,10 +205,15 @@ class User(BASE):
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
+    @property
+    def avatar(self):
+        return username2avatar(self.username)
+
     def __json__(self, session):
         return {
             'username': self.username,
             'openid': self.openid,
+            'avatar': self.avatar,
             'fullname': self.fullname,
             'created_on': self.created_on,
             # We'll need hubs subscribed to, owned, etc..
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index e8587e6..9ba55ee 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -50,6 +50,7 @@
 </div>
 <div class="header">
   <div class="padded center-block medium-wide">
+    <img src="{{hub.avatar}}" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
   </div>

From d52d7e79d3e989c39c86c9cdc5c4570a2c680ea5 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 06 2015 21:23:05 +0000
Subject: [PATCH 136/1001] Start an association table for hubs/users.


---

diff --git a/hubs/models.py b/hubs/models.py
index 0768e92..40fbb0b 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -85,6 +85,24 @@ def init(db_url, debug=False, create=False):
     return scoped_session(sessionmaker(bind=engine))
 
 
+roles = ['subscriber', 'member', 'owner']
+
+
+class Association(BASE):
+    __tablename__ = 'association'
+
+    hub_id = sa.Column(sa.String(50),
+                       sa.ForeignKey('hubs.name'),
+                       primary_key=True)
+    user_id = sa.Column(sa.Text,
+                        sa.ForeignKey('users.openid'),
+                        primary_key=True)
+    role = sa.Column(sa.Enum(*roles), nullable=False)
+
+    user = relation("User", backref="associations")
+    hub = relation("Hub", backref="associations")
+
+
 class Hub(BASE):
     __tablename__ = 'hubs'
     name = sa.Column(sa.String(50), primary_key=True)
@@ -104,6 +122,14 @@ class Hub(BASE):
     members = ['ralph', 'sadin', 'sayan'] + owners
     subscribers = []
 
+
+    def subscribe(self, session, user):
+        # TODO -- add logic here to manage not adding the user multiple
+        # times, doing different roles, etc.. publish a fedmsg message,
+        # etc...
+        session.add(Association(user=user, hub=self, role='subscriber'))
+        session.commit()
+
     @classmethod
     def by_name(cls, session, name):
         return session.query(cls).filter_by(name=name).first()
@@ -245,5 +271,10 @@ class User(BASE):
             session.add(self)
             if not Hub.by_name(session, self.username):
                 Hub.create_user_hub(session, self.username, self.fullname)
+
+            # Subscribe self to some default hubs for now..
+            hub = Hub.by_name(session, 'designteam')
+            hub.subscribe(session, self)
+
             session.commit()
         return self
diff --git a/populate.py b/populate.py
index 0742abc..d8efe61 100755
--- a/populate.py
+++ b/populate.py
@@ -10,6 +10,7 @@ fedmsg_config = fedmsg.config.load_config()
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
+############## Infra team
 hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
 session.add(hub)
 
@@ -39,5 +40,35 @@ hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
 hub.widgets.append(widget)
 
-session.commit()
 
+############## Infra team
+hub = hubs.models.Hub(name='infrastructure', summary='The Fedora Infrastructure Team')
+session.add(hub)
+
+widget = hubs.models.Widget(plugin='stats', index=0)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='rules', index=1,
+                            _config=json.dumps({
+                                'link': 'http://threebean.org'
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='dummy', index=2)
+hub.widgets.append(widget)
+
+# Added a hubs about widget
+widget = hubs.models.Widget(plugin='about', index=3,
+                            _config=json.dumps({
+                                "text": "I'm a Fedora user, and this is my about widget text!",
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+                            _config=json.dumps({
+                                'text': 'This is a sticky note.',
+                            }))
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
+hub.widgets.append(widget)
+
+session.commit()

From c2e485d0b6744d79a919f475f1cfb16af78af4d8 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 06 2015 22:05:29 +0000
Subject: [PATCH 137/1001] styles for splash avatar


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 3618ce2..d380c5e 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -1,9 +1,7 @@
    body {
       background-color: #d1d3d4;
     }
-    .panel {
-      border-radius: 0px;
-    }
+
     .super-header {
       text-align: right;
       background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
@@ -44,6 +42,13 @@
       color: #ffffff;
       background-color: #3c6eb4;
       width: 100%;
+      height:85px;
+    }
+    .header img.avatar {
+        width: 75px;
+        float: left;
+        margin: 0 15px;
+        display: inline;
     }
     .row {
       padding: 5px;
@@ -67,6 +72,7 @@
       max-height: 0px;
       overflow: hidden;
       border: 0;
+      border-radius:0px;
       transition: max-height 0.4s;
     }
 
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 9ba55ee..25d1ca4 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -50,7 +50,7 @@
 </div>
 <div class="header">
   <div class="padded center-block medium-wide">
-    <img src="{{hub.avatar}}" />
+    <img src="{{hub.avatar}}" class="avatar" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
   </div>

From ec0b7a4cc5a5760ace26f84f09c8200f19b9f92d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 00:57:44 +0000
Subject: [PATCH 138/1001] Link to "my hubs" loosely in the nav bar.


---

diff --git a/hubs/app.py b/hubs/app.py
index 74ea4af..f5262d4 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -182,16 +182,12 @@ def login_required(function):
 @app.before_request
 def check_auth():
     flask.g.fedmsg_config = fedmsg_config
-    flask.g.auth = munch.Munch(
-        logged_in=False,
-        method=None,
-        id=None,
-    )
+    flask.g.auth = munch.Munch(logged_in=False)
     if 'openid' in flask.session:
         openid = flask.session.get('openid').strip('/').split('/')[-1]
         flask.g.auth.logged_in = True
-        flask.g.auth.method = u'openid'
         flask.g.auth.openid = openid
+        flask.g.auth.user = hubs.models.User.by_openid(session, openid)
         flask.g.auth.openid_url = flask.session.get('openid')
         flask.g.auth.fullname = flask.session.get('fullname', None)
         flask.g.auth.nickname = flask.session.get('nickname', None)
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 9ba55ee..8122eb0 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -36,13 +36,16 @@
       <!-- Collect the nav links, forms, and other content for toggling -->
       <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
         <ul class="nav navbar-nav">
-          <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
-          <li><a href="#">Link</a></li>
-          <li><a href="#">Action</a></li>
-          <li><a href="#">Another action</a></li>
-          <li><a href="#">Something else here</a></li>
+          {% if g.auth.logged_in %}
+          <li {% if request.path.endswith('/' + g.auth.user.username + '/') %}class='active'{% endif %}>
+            <a href="/{{g.auth.user.username}}">me</a></li>
+          {% for assoc in g.auth.user.associations %}
+          <li {% if request.path.endswith('/' + assoc.hub.name + '/') %}class='active'{% endif %}>
+          <a href="/{{assoc.hub.name}}">{{assoc.hub.name}}</a></li>
+          {% endfor %}
           <li class="divider"></li>
-          <li><a href="#">Separated link</a></li>          
+          <li><a href="#">Separated link</a></li>
+          {% endif %}
         </ul>
       </div><!-- /.navbar-collapse -->
     </div><!-- /.container-fluid -->

From a6bd04b00b3a6fdfdcd7715f315b3899053fbe66 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 00:58:25 +0000
Subject: [PATCH 139/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 3618ce2..d380c5e 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -1,9 +1,7 @@
    body {
       background-color: #d1d3d4;
     }
-    .panel {
-      border-radius: 0px;
-    }
+
     .super-header {
       text-align: right;
       background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
@@ -44,6 +42,13 @@
       color: #ffffff;
       background-color: #3c6eb4;
       width: 100%;
+      height:85px;
+    }
+    .header img.avatar {
+        width: 75px;
+        float: left;
+        margin: 0 15px;
+        display: inline;
     }
     .row {
       padding: 5px;
@@ -67,6 +72,7 @@
       max-height: 0px;
       overflow: hidden;
       border: 0;
+      border-radius:0px;
       transition: max-height 0.4s;
     }
 
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 8122eb0..ec46105 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -53,7 +53,7 @@
 </div>
 <div class="header">
   <div class="padded center-block medium-wide">
-    <img src="{{hub.avatar}}" />
+    <img src="{{hub.avatar}}" class="avatar" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
   </div>

From e97b5440667fe0bcc5e3bad432e6f40be6d3bd3f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 14:46:34 +0000
Subject: [PATCH 140/1001] Introduce some logging config.


---

diff --git a/README.rst b/README.rst
index c4696c9..0056e6e 100644
--- a/README.rst
+++ b/README.rst
@@ -51,12 +51,12 @@ And then navigate to http://localhost:5000/
 If you want to test it with 8 worker threads, try ``gunicorn``::
 
     $ pip install gunicorn
-    $ gunicorn -w 8 hubs.app:app -t 60 --reload
+    $ gunicorn -w 8 -t 60 --log-config logging.ini --reload hubs.app:app
 
 When hacking on widgets, it is useful to have this one-liner handy.  It removes
 the db alltogether, re-populates it, and restarts the app::
 
-    $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 hubs.app:app
+    $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 60 --log-config logging.ini hubs.app:app
 
 Feed Widget - the Extra Mile
 ----------------------------
diff --git a/logging.ini b/logging.ini
new file mode 100644
index 0000000..3512fa6
--- /dev/null
+++ b/logging.ini
@@ -0,0 +1,23 @@
+# From https://docs.python.org/2/howto/logging.html
+[loggers]
+keys=root
+
+[handlers]
+keys=console
+
+[formatters]
+keys=simple
+
+[logger_root]
+level=DEBUG
+handlers=console
+
+[handler_console]
+class=StreamHandler
+level=DEBUG
+formatter=simple
+args=(sys.stdout,)
+
+[formatter_simple]
+format=[%(asctime)s][%(process)d][%(levelname)s] (%(name)s) %(message)s
+datefmt=%H:%M:%S

From 0d0c309de1ad22a31043e61dc84444131a610adb Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 14:47:08 +0000
Subject: [PATCH 141/1001] Start using the new associations model stuff in some widgets to test it out.


---

diff --git a/hubs/models.py b/hubs/models.py
index 40fbb0b..8c7a51a 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -116,18 +116,26 @@ class Hub(BASE):
 
     #fas_group = sa.Column(sa.String(32), nullable=False)
 
-    # This is just some silly dev data.  eventually, connect this
-    # to real database data.
-    owners = ['tatica', 'gnokii', 'duffy', 'ryanlerch']
-    members = ['ralph', 'sadin', 'sayan'] + owners
-    subscribers = []
+    @property
+    def owners(self):
+        return [assoc.user for assoc in self.associations
+                if assoc.role == 'owner']
+    @property
+    def members(self):
+        return [assoc.user for assoc in self.associations
+                if assoc.role == 'member' or assoc.role =='owner']
 
+    @property
+    def subscribers(self):
+        return [assoc.user for assoc in self.associations
+                if assoc.role == 'subscriber']
 
-    def subscribe(self, session, user):
+    def subscribe(self, session, user, role='subscriber'):
+        """ Subscribe a user to this hub. """
         # TODO -- add logic here to manage not adding the user multiple
         # times, doing different roles, etc.. publish a fedmsg message,
         # etc...
-        session.add(Association(user=user, hub=self, role='subscriber'))
+        session.add(Association(user=user, hub=self, role=role))
         session.commit()
 
     @classmethod
@@ -231,15 +239,12 @@ class User(BASE):
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
-    @property
-    def avatar(self):
-        return username2avatar(self.username)
 
     def __json__(self, session):
         return {
             'username': self.username,
             'openid': self.openid,
-            'avatar': self.avatar,
+            'avatar': username2avatar(self.username),
             'fullname': self.fullname,
             'created_on': self.created_on,
             # We'll need hubs subscribed to, owned, etc..
@@ -272,9 +277,5 @@ class User(BASE):
             if not Hub.by_name(session, self.username):
                 Hub.create_user_hub(session, self.username, self.fullname)
 
-            # Subscribe self to some default hubs for now..
-            hub = Hub.by_name(session, 'designteam')
-            hub.subscribe(session, self)
-
             session.commit()
         return self
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index ae36938..3a1dd16 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -42,7 +42,7 @@ template = jinja2.Template("""
           help="Link to the community rules and guidelines")
 def data(session, widget, link):
     owners = widget.hub.owners
-    owners = ordereddict([(o, avatar(o)) for o in owners])
+    owners = ordereddict([(o.username, avatar(o.username)) for o in owners])
     return dict(owners=owners, link=link)
 
 
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 1826c62..67a0e26 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -8,17 +8,28 @@ template = jinja2.Template("""
 <div class="stats-container">
   <table class="stats-table">
     <tr><th>Members</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{{members}}</td><td>{{subscribers}}</td></tr>
+    <tr class="text-info"><td>{{members | length}}</td><td>{{subscribers | length}}</td></tr>
   </table>
-  <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+  {% if g.auth.logged_in %}
+    {% if g.auth.nickname in members %}
+    <div class="pull-right"><button class="btn btn-danger">Resign</button></div>
+    {% elif g.auth.nickname in subscribers %}
+    <div class="pull-right"><button class="btn btn-warning">Unsubscribe</button></div>
+    {% else %}
+    <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+    {% endif %}
+  {% else %}
+    <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+  {% endif %}
 </div>
 """)
 
 
 def data(session, widget):
     return dict(
-        members=len(widget.hub.members),
-        subscribers=len(widget.hub.subscribers),
+        owners=[u.username for u in widget.hub.owners],
+        members=[u.username for u in widget.hub.members],
+        subscribers=[u.username for u in widget.hub.subscribers],
     )
 
 
diff --git a/populate.py b/populate.py
index d8efe61..3c517f4 100755
--- a/populate.py
+++ b/populate.py
@@ -10,6 +10,18 @@ fedmsg_config = fedmsg.config.load_config()
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
+users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
+         'abompard', 'decause', 'ralph']
+for username in users:
+    fullname = 'Full Name Goes Here'
+    openid = '%s.id.fedoraproject.org' % username
+    print "Creating account for %r" % openid
+    hubs.models.User.get_or_create(
+        session, openid=openid, fullname=fullname)
+
+session.commit()
+
+
 ############## Infra team
 hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
 session.add(hub)
@@ -41,6 +53,16 @@ widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
 hub.widgets.append(widget)
 
 
+# Set up some memberships
+hub.subscribe(session, hubs.models.User.by_openid(session, 'duffy.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'gnokii.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
+
+
 ############## Infra team
 hub = hubs.models.Hub(name='infrastructure', summary='The Fedora Infrastructure Team')
 session.add(hub)
@@ -71,4 +93,10 @@ hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
 hub.widgets.append(widget)
 
+
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'abompard.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'subscriber')
+
 session.commit()

From 36ddde24f722da4a3cde7e0db73b0b85cd9b2fa7 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 14:47:21 +0000
Subject: [PATCH 142/1001] Fix a cache key collision bug.


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 94ffaa2..5f4d01b 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -71,7 +71,8 @@ def prepare_registry(registry):
         module.data = AGPLv3(name)(module.data)
 
         # Wrap the data functions in a cache layer to be invalidated by fedmsg
-        module.data = smartcache(module)(module.data)
+        # TODO -- we could just do this with a decorator to be explicit..
+        module.data = smartcache(module.data)
 
 
 validate_registry(registry)
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index e0d1581..4550448 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -9,6 +9,9 @@ import six.moves.urllib_parse
 
 import fedmsg.config
 
+import logging
+log = logging.getLogger(__name__)
+
 config = fedmsg.config.load_config()
 cache_defaults = {
     "backend": "dogpile.cache.dbm",
@@ -48,26 +51,26 @@ def AGPLv3(name):
     return decorator
 
 
-def smartcache(module):
-    def decorator(func):
-        @wraps(func)
-        def inner(session, widget, *args, **kwargs):
-            key = cache_key_generator(module, args, kwargs)
-            creator = lambda: func(session, widget, *args, **kwargs)
-            return cache.get_or_create(key, creator)
+def smartcache(func):
+    @wraps(func)
+    def inner(session, widget, *args, **kwargs):
+        key = cache_key_generator(widget, args, kwargs)
+        creator = lambda: func(session, widget, *args, **kwargs)
+        log.debug("Accessing cache key %s", key)
+        return cache.get_or_create(key, creator)
 
-        return inner
-    return decorator
+    return inner
 
 
-def invalidate_cache(module, *args, **kwargs):
-    key = cache_key_generator(module, *args, **kwargs)
+def invalidate_cache(widget, *args, **kwargs):
+    key = cache_key_generator(widget, *args, **kwargs)
+    log.debug("Deleting cache key %s", key)
     cache.delete(key)
 
 
-def cache_key_generator(module, args, kwargs):
+def cache_key_generator(widget, args, kwargs):
     return "|".join([
-        module.__name__,
+        str(widget.idx),
         json.dumps(args),
         json.dumps(kwargs),
     ]).encode('utf-8')

From 748f55bc2a57e7a3183024e7c5a0854c53077ea8 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 15:02:37 +0000
Subject: [PATCH 143/1001] Update signature on this function call.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index 81c4717..bd7345e 100644
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -127,7 +127,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
             if check(msg, session, widget):
                 log.info("! Invalidating cache for %r" % widget)
                 # Invalidate the cache...
-                invalidate_cache(widget.module, **widget.config)
+                invalidate_cache(widget, **widget.config)
                 # Rebuild it.
                 widget.module.data(session, widget, **widget.config)
                 # TODO -- fire off an EventSource notice that we updated stuff

From 4788d7a0a2a6b4b5291aff888726a25d0800710e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 15:57:10 +0000
Subject: [PATCH 144/1001] Add a subscriptions widget.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 9646f8e..80f4520 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -48,7 +48,13 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='badges', index=4,
+        plugin='subscriptions', index=4,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='badges', index=5,
         _config=json.dumps({
             'username': username,
         }))
diff --git a/hubs/models.py b/hubs/models.py
index 8c7a51a..eed4163 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -252,10 +252,28 @@ class User(BASE):
         }
 
     @property
+    def ownerships(self):
+        return [assoc.hub for assoc in self.associations
+                if assoc.role == 'owner']
+    @property
+    def memberships(self):
+        return [assoc.hub for assoc in self.associations
+                if assoc.role == 'member' or assoc.role =='owner']
+
+    @property
+    def subscriptions(self):
+        return [assoc.hub for assoc in self.associations
+                if assoc.role == 'subscriber']
+
+    @property
     def username(self):
         return self.openid.split('.')[0]
 
     @classmethod
+    def by_username(cls, session, username):
+        return cls.by_openid(session, "%s.id.fedoraproject.org" % username)
+
+    @classmethod
     def by_openid(cls, session, openid):
         return session.query(cls).filter_by(openid=openid).first()
 
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 5f4d01b..b644707 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -8,6 +8,7 @@ from hubs.widgets import badges
 from hubs.widgets import fedmsgs
 from hubs.widgets import fedmsgstats
 from hubs.widgets import feed
+from hubs.widgets import subscriptions
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -25,6 +26,7 @@ registry = {
     'fedmsgs': fedmsgs,
     'fedmsgstats': fedmsgstats,
     'feed': feed,
+    'subscriptions': subscriptions,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
new file mode 100644
index 0000000..f37819f
--- /dev/null
+++ b/hubs/widgets/subscriptions.py
@@ -0,0 +1,48 @@
+#from hubs.hinting import hint, prefixed as _
+from hubs.widgets.base import argument
+from hubs.widgets.chrome import panel
+
+from hubs import validators
+
+import hubs.models
+
+from fedmsg.meta.base import BaseConglomerator as BC
+
+import jinja2
+
+chrome = panel('Hubs', key='associations')
+template = jinja2.Template("""
+{% if associations %}
+    {% if memberships %}
+        <p>Belongs to: {{memberships_text}}</p>
+    {% endif %}
+    <hr/>
+    {% if subscriptions %}
+        <p>Subscribes to: {{subscriptions_text}}</p>
+    {% endif %}
+{% endif %}
+""")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    user = hubs.models.User.by_username(session, username)
+    ownerships = [u.name for u in user.ownerships]
+    memberships = [u.name for u in user.memberships]
+    subscriptions = [u.name for u in user.subscriptions]
+    return dict(
+        associations=memberships + ownerships,
+        ownerships=ownerships,
+        memberships=memberships,
+        subscriptions=subscriptions,
+        ownerships_text=BC.list_to_series(ownerships),
+        memberships_text=BC.list_to_series(memberships),
+        subscriptions_text=BC.list_to_series(subscriptions),
+    )
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError()

From c4b8128223c0d27ec8af32bd00cc860cf233d9c0 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 15:57:28 +0000
Subject: [PATCH 145/1001] Add a link to each widget to pop it out and view it individually.


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 4550448..995125c 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -42,9 +42,11 @@ def argument(name, default, validator, help):
 def AGPLv3(name):
     def decorator(func):
         @wraps(func)
-        def inner(*args, **kwargs):
-            result = func(*args, **kwargs)
+        def inner(session, widget, *args, **kwargs):
+            result = func(session, widget, *args, **kwargs)
             result['source_url'] = flask.url_for('widget_source', name=name)
+            result['widget_url'] = flask.url_for(
+                'widget_render', hub=widget.hub.name, idx=widget.idx)
             return result
 
         return inner
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index de38df1..6a313aa 100644
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -8,6 +8,7 @@ _panel_template = jinja2.Template("""
   <div class="pull-right widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
     <a href="{{source_url}}"><span class="glyphicon glyphicon-eye-open"></span></a>
+    <a href="{{widget_url}}"><span class="glyphicon glyphicon-new-window"></span></a>
     <a href="#"><span class="glyphicon glyphicon-edit"></span></a>
   </div>
   <div class="panel-body">

From bca51247f2da09fe84bdecbe5c5641fa6ef31f7e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 15:57:51 +0000
Subject: [PATCH 146/1001] Show only a user's 10 latest badges.


---

diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index 4e6234d..fe99525 100644
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -1,3 +1,5 @@
+import operator
+
 import requests
 
 from hubs.hinting import hint, prefixed as _
@@ -11,7 +13,7 @@ import hubs.validators as validators
 
 template = jinja2.Template("""
 <div class="flex-container">
-{% for badge in assertions %}
+{% for badge in assertions[:10] %}
     <img width="19%" src="{{badge['image']}}"/>
 {%endfor%}
 </div>
@@ -29,7 +31,9 @@ def data(session, widget, username):
     url = "https://badges.fedoraproject.org/user/{username}/json"
     url = url.format(username=username)
     response = requests.get(url)
-    return response.json()
+    assertions = response.json()['assertions']
+    key = operator.itemgetter('issued')
+    return dict(assertions=sorted(assertions, key=key, reverse=True))
 
 
 @hint(topics=[_('hubs.widget.update'), _('fedbadges.badge.award')])

From 9422e5a7b459bb0e800225f90e15c5c3378a7605 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 16:11:36 +0000
Subject: [PATCH 147/1001] Turn badges icons into links.


---

diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index fe99525..1018c3d 100644
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -14,7 +14,8 @@ import hubs.validators as validators
 template = jinja2.Template("""
 <div class="flex-container">
 {% for badge in assertions[:10] %}
-    <img width="19%" src="{{badge['image']}}"/>
+  <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
+    <img width="60px" src="{{badge['image']}}"/></a>
 {%endfor%}
 </div>
 """)

From b3323f68202432134c64dfa8c2af516dd8e2c502 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 16:19:35 +0000
Subject: [PATCH 148/1001] Enough with the randomness.


---

diff --git a/hubs/models.py b/hubs/models.py
index eed4163..9933dd6 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -60,8 +60,7 @@ BASE = declarative_base(cls=HubsBase)
 log = logging.getLogger(__name__)
 
 
-placekitten = lambda: "https://placekitten.com/g/%i/%i" % (
-    random.randint(150,350), random.randint(150, 350))
+placekitten = lambda: "https://placekitten.com/g/320/320"
 
 
 def init(db_url, debug=False, create=False):

From 380ae697c19d4c29262a6b9bdbb041204e8375f8 Mon Sep 17 00:00:00 2001
From: Luke Macken <lmacken@redhat.com>
Date: Jul 07 2015 16:35:17 +0000
Subject: [PATCH 149/1001] Get populate.py working on Python 3


---

diff --git a/populate.py b/populate.py
index 3c517f4..9e02e82 100755
--- a/populate.py
+++ b/populate.py
@@ -15,7 +15,7 @@ users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
 for username in users:
     fullname = 'Full Name Goes Here'
     openid = '%s.id.fedoraproject.org' % username
-    print "Creating account for %r" % openid
+    print("Creating account for %r" % openid)
     hubs.models.User.get_or_create(
         session, openid=openid, fullname=fullname)
 

From 16c1482c2ce81a87bf5a89d0597d4f32b3aba963 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 07 2015 16:56:18 +0000
Subject: [PATCH 150/1001] splash styles


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index d380c5e..008bcb2 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -42,13 +42,17 @@
       color: #ffffff;
       background-color: #3c6eb4;
       width: 100%;
-      height:85px;
+      font-family: 'Open Sans', sans-serif;
     }
     .header img.avatar {
-        width: 75px;
+        width: 70px;
         float: left;
         margin: 0 15px;
         display: inline;
+        border: 5px solid #fff;
+    }
+    .header h3 {
+        font-weight: 700;
     }
     .row {
       padding: 5px;
@@ -57,8 +61,16 @@
       padding: 5px;
     }
     .medium-wide {
-      width: 250px;
+      width: 300px;
     }
+
+@media (max-width: 320px) {
+  .medium-wide {
+    width: 100%;
+    text-align: center;
+  }
+}
+
     h1, h2, h3, h4, h5, h6 {
       margin-top: 0px;
       margin-bottom: 0px;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index ec46105..06d45a5 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -56,6 +56,7 @@
     <img src="{{hub.avatar}}" class="avatar" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
+    <div class="clearfix"></div>
   </div>
 </div>
 <div class="container">

From 63b19b0da5fa866c780c414e7718975749296eee Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 07 2015 16:56:38 +0000
Subject: [PATCH 151/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 9646f8e..80f4520 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -48,7 +48,13 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='badges', index=4,
+        plugin='subscriptions', index=4,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='badges', index=5,
         _config=json.dumps({
             'username': username,
         }))
diff --git a/hubs/models.py b/hubs/models.py
index 8c7a51a..9933dd6 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -60,8 +60,7 @@ BASE = declarative_base(cls=HubsBase)
 log = logging.getLogger(__name__)
 
 
-placekitten = lambda: "https://placekitten.com/g/%i/%i" % (
-    random.randint(150,350), random.randint(150, 350))
+placekitten = lambda: "https://placekitten.com/g/320/320"
 
 
 def init(db_url, debug=False, create=False):
@@ -252,10 +251,28 @@ class User(BASE):
         }
 
     @property
+    def ownerships(self):
+        return [assoc.hub for assoc in self.associations
+                if assoc.role == 'owner']
+    @property
+    def memberships(self):
+        return [assoc.hub for assoc in self.associations
+                if assoc.role == 'member' or assoc.role =='owner']
+
+    @property
+    def subscriptions(self):
+        return [assoc.hub for assoc in self.associations
+                if assoc.role == 'subscriber']
+
+    @property
     def username(self):
         return self.openid.split('.')[0]
 
     @classmethod
+    def by_username(cls, session, username):
+        return cls.by_openid(session, "%s.id.fedoraproject.org" % username)
+
+    @classmethod
     def by_openid(cls, session, openid):
         return session.query(cls).filter_by(openid=openid).first()
 
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 5f4d01b..b644707 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -8,6 +8,7 @@ from hubs.widgets import badges
 from hubs.widgets import fedmsgs
 from hubs.widgets import fedmsgstats
 from hubs.widgets import feed
+from hubs.widgets import subscriptions
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -25,6 +26,7 @@ registry = {
     'fedmsgs': fedmsgs,
     'fedmsgstats': fedmsgstats,
     'feed': feed,
+    'subscriptions': subscriptions,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index 4e6234d..1018c3d 100644
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -1,3 +1,5 @@
+import operator
+
 import requests
 
 from hubs.hinting import hint, prefixed as _
@@ -11,8 +13,9 @@ import hubs.validators as validators
 
 template = jinja2.Template("""
 <div class="flex-container">
-{% for badge in assertions %}
-    <img width="19%" src="{{badge['image']}}"/>
+{% for badge in assertions[:10] %}
+  <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
+    <img width="60px" src="{{badge['image']}}"/></a>
 {%endfor%}
 </div>
 """)
@@ -29,7 +32,9 @@ def data(session, widget, username):
     url = "https://badges.fedoraproject.org/user/{username}/json"
     url = url.format(username=username)
     response = requests.get(url)
-    return response.json()
+    assertions = response.json()['assertions']
+    key = operator.itemgetter('issued')
+    return dict(assertions=sorted(assertions, key=key, reverse=True))
 
 
 @hint(topics=[_('hubs.widget.update'), _('fedbadges.badge.award')])
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 4550448..995125c 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -42,9 +42,11 @@ def argument(name, default, validator, help):
 def AGPLv3(name):
     def decorator(func):
         @wraps(func)
-        def inner(*args, **kwargs):
-            result = func(*args, **kwargs)
+        def inner(session, widget, *args, **kwargs):
+            result = func(session, widget, *args, **kwargs)
             result['source_url'] = flask.url_for('widget_source', name=name)
+            result['widget_url'] = flask.url_for(
+                'widget_render', hub=widget.hub.name, idx=widget.idx)
             return result
 
         return inner
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index de38df1..6a313aa 100644
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -8,6 +8,7 @@ _panel_template = jinja2.Template("""
   <div class="pull-right widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
     <a href="{{source_url}}"><span class="glyphicon glyphicon-eye-open"></span></a>
+    <a href="{{widget_url}}"><span class="glyphicon glyphicon-new-window"></span></a>
     <a href="#"><span class="glyphicon glyphicon-edit"></span></a>
   </div>
   <div class="panel-body">
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
new file mode 100644
index 0000000..f37819f
--- /dev/null
+++ b/hubs/widgets/subscriptions.py
@@ -0,0 +1,48 @@
+#from hubs.hinting import hint, prefixed as _
+from hubs.widgets.base import argument
+from hubs.widgets.chrome import panel
+
+from hubs import validators
+
+import hubs.models
+
+from fedmsg.meta.base import BaseConglomerator as BC
+
+import jinja2
+
+chrome = panel('Hubs', key='associations')
+template = jinja2.Template("""
+{% if associations %}
+    {% if memberships %}
+        <p>Belongs to: {{memberships_text}}</p>
+    {% endif %}
+    <hr/>
+    {% if subscriptions %}
+        <p>Subscribes to: {{subscriptions_text}}</p>
+    {% endif %}
+{% endif %}
+""")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    user = hubs.models.User.by_username(session, username)
+    ownerships = [u.name for u in user.ownerships]
+    memberships = [u.name for u in user.memberships]
+    subscriptions = [u.name for u in user.subscriptions]
+    return dict(
+        associations=memberships + ownerships,
+        ownerships=ownerships,
+        memberships=memberships,
+        subscriptions=subscriptions,
+        ownerships_text=BC.list_to_series(ownerships),
+        memberships_text=BC.list_to_series(memberships),
+        subscriptions_text=BC.list_to_series(subscriptions),
+    )
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError()
diff --git a/populate.py b/populate.py
index 3c517f4..9e02e82 100755
--- a/populate.py
+++ b/populate.py
@@ -15,7 +15,7 @@ users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
 for username in users:
     fullname = 'Full Name Goes Here'
     openid = '%s.id.fedoraproject.org' % username
-    print "Creating account for %r" % openid
+    print("Creating account for %r" % openid)
     hubs.models.User.get_or_create(
         session, openid=openid, fullname=fullname)
 

From b0206be2e99027d588fbf9aaa0ba87d39ca81729 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 17:04:34 +0000
Subject: [PATCH 152/1001] Check the type of this string.


---

diff --git a/hubs/app.py b/hubs/app.py
index f5262d4..718b32f 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -5,6 +5,7 @@ import os
 import flask
 import flask.json
 import munch
+import six
 
 from flask.ext.openid import OpenID
 
@@ -184,7 +185,12 @@ def check_auth():
     flask.g.fedmsg_config = fedmsg_config
     flask.g.auth = munch.Munch(logged_in=False)
     if 'openid' in flask.session:
-        openid = flask.session.get('openid').strip('/').split('/')[-1]
+
+        openid = flask.session.get('openid')
+        if isinstance(openid, six.binary_type):
+            openid = openid.decode('utf-8')
+        openid = openid.strip('/').split('/')[-1]
+
         flask.g.auth.logged_in = True
         flask.g.auth.openid = openid
         flask.g.auth.user = hubs.models.User.by_openid(session, openid)

From 3e20642119361cdefd002b55c48795878dcc41ba Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 17:04:51 +0000
Subject: [PATCH 153/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index d380c5e..008bcb2 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -42,13 +42,17 @@
       color: #ffffff;
       background-color: #3c6eb4;
       width: 100%;
-      height:85px;
+      font-family: 'Open Sans', sans-serif;
     }
     .header img.avatar {
-        width: 75px;
+        width: 70px;
         float: left;
         margin: 0 15px;
         display: inline;
+        border: 5px solid #fff;
+    }
+    .header h3 {
+        font-weight: 700;
     }
     .row {
       padding: 5px;
@@ -57,8 +61,16 @@
       padding: 5px;
     }
     .medium-wide {
-      width: 250px;
+      width: 300px;
     }
+
+@media (max-width: 320px) {
+  .medium-wide {
+    width: 100%;
+    text-align: center;
+  }
+}
+
     h1, h2, h3, h4, h5, h6 {
       margin-top: 0px;
       margin-bottom: 0px;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index ec46105..06d45a5 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -56,6 +56,7 @@
     <img src="{{hub.avatar}}" class="avatar" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
+    <div class="clearfix"></div>
   </div>
 </div>
 <div class="container">
diff --git a/populate.py b/populate.py
index 3c517f4..9e02e82 100755
--- a/populate.py
+++ b/populate.py
@@ -15,7 +15,7 @@ users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
 for username in users:
     fullname = 'Full Name Goes Here'
     openid = '%s.id.fedoraproject.org' % username
-    print "Creating account for %r" % openid
+    print("Creating account for %r" % openid)
     hubs.models.User.get_or_create(
         session, openid=openid, fullname=fullname)
 

From 7dfd6b847b5b907c5b70e94cedbcf937ebbc3f1b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 17:30:29 +0000
Subject: [PATCH 154/1001] Up the timeout for caching FAS.


---

diff --git a/README.rst b/README.rst
index 0056e6e..3399529 100644
--- a/README.rst
+++ b/README.rst
@@ -56,7 +56,7 @@ If you want to test it with 8 worker threads, try ``gunicorn``::
 When hacking on widgets, it is useful to have this one-liner handy.  It removes
 the db alltogether, re-populates it, and restarts the app::
 
-    $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 60 --log-config logging.ini hubs.app:app
+    $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 240 --log-config logging.ini hubs.app:app
 
 Feed Widget - the Extra Mile
 ----------------------------

From af79a8ed425edd721d58b989b9979632c53d6943 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 17:34:56 +0000
Subject: [PATCH 155/1001] Get the subscribe/unsubscribe buttons working.


---

diff --git a/hubs/app.py b/hubs/app.py
index 718b32f..f3157c5 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -228,7 +228,49 @@ def get_widget(session, hub, idx):
     flask.abort(404)
 
 
-
+## Here are a bunch of API methods that should probably be broken out into
+## their own file
+@app.route('/api/hub/<hub>/subscribe', methods=['POST'])
+@login_required
+def hub_subscribe(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    hub.subscribe(session, user)
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+@app.route('/api/hub/<hub>/unsubscribe', methods=['POST'])
+@login_required
+def hub_unsubscribe(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    try:
+        hub.unsubscribe(session, user)
+    except KeyError:
+        return flask.abort(400)
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+@app.route('/api/hub/<hub>/join', methods=['POST'])
+@login_required
+def hub_join(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    hub.subscribe(session, user, role='member')
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+@app.route('/api/hub/<hub>/leave', methods=['POST'])
+@login_required
+def hub_leave(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    try:
+        hub.unsubscribe(session, user, role='member')
+    except KeyError:
+        return flask.abort(400)
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
 
 
 if __name__ == '__main__':
diff --git a/hubs/models.py b/hubs/models.py
index 9933dd6..ff117ab 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -24,7 +24,6 @@
 import datetime
 import json
 import logging
-import random
 
 import sqlalchemy as sa
 from sqlalchemy import create_engine
@@ -101,6 +100,14 @@ class Association(BASE):
     user = relation("User", backref="associations")
     hub = relation("Hub", backref="associations")
 
+    @classmethod
+    def get(cls, session, hub, user, role):
+        return session.query(cls)\
+            .filter_by(hub=hub)\
+            .filter_by(user=user)\
+            .filter_by(role=role)\
+            .first()
+
 
 class Hub(BASE):
     __tablename__ = 'hubs'
@@ -137,6 +144,18 @@ class Hub(BASE):
         session.add(Association(user=user, hub=self, role=role))
         session.commit()
 
+    def unsubscribe(self, session, user, role='subscriber'):
+        """ Subscribe a user to this hub. """
+        # TODO -- add logic here to manage not adding the user multiple
+        # times, doing different roles, etc.. publish a fedmsg message,
+        # etc...
+        association = Association.get(session, hub=self, user=user, role=role)
+        if not association:
+            raise KeyError("%r is not a %r of %r" % (user, role, self))
+        session.delete(association)
+        session.commit()
+
+
     @classmethod
     def by_name(cls, session, name):
         return session.query(cls).filter_by(name=name).first()
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 67a0e26..3f77a47 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,6 +1,7 @@
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 
+import flask
 import jinja2
 
 chrome = panel()
@@ -10,16 +11,29 @@ template = jinja2.Template("""
     <tr><th>Members</th><th>Subscribers</th></tr>
     <tr class="text-info"><td>{{members | length}}</td><td>{{subscribers | length}}</td></tr>
   </table>
+
   {% if g.auth.logged_in %}
+    <div class="pull-right">
     {% if g.auth.nickname in members %}
-    <div class="pull-right"><button class="btn btn-danger">Resign</button></div>
+    <form action="{{hub_leave_url}}" method="POST">
+        <button class="btn btn-danger">Leave Hub</button>
+    </form>
     {% elif g.auth.nickname in subscribers %}
-    <div class="pull-right"><button class="btn btn-warning">Unsubscribe</button></div>
+    <form action="{{hub_unsubscribe_url}}" method="POST">
+        <button class="btn btn-warning">Unsubscribe</button>
+    </form>
     {% else %}
-    <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+    <form action="{{hub_subscribe_url}}" method="POST">
+        <button class="btn btn-info">Subscribe</button>
+    </form>
     {% endif %}
+    </div>
   {% else %}
-    <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+    <div class="pull-right">
+        <form action="{{hub_subscribe_url}}" method="POST">
+            <button class="btn btn-info">Subscribe</button>
+        </form>
+    </div>
   {% endif %}
 </div>
 """)
@@ -30,6 +44,10 @@ def data(session, widget):
         owners=[u.username for u in widget.hub.owners],
         members=[u.username for u in widget.hub.members],
         subscribers=[u.username for u in widget.hub.subscribers],
+        hub_leave_url=flask.url_for('hub_leave', hub=widget.hub.name),
+        hub_join_url=flask.url_for('hub_join', hub=widget.hub.name),
+        hub_subscribe_url=flask.url_for('hub_subscribe', hub=widget.hub.name),
+        hub_unsubscribe_url=flask.url_for('hub_unsubscribe', hub=widget.hub.name),
     )
 
 

From a5381c312e8fef68382008fa4957156ec36192f7 Mon Sep 17 00:00:00 2001
From: Luke Macken <lmacken@redhat.com>
Date: Jul 07 2015 17:56:45 +0000
Subject: [PATCH 156/1001] Enable the feed widget by default


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 80f4520..82f9016 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -14,13 +14,13 @@ def add_user_widgets(session, hub, username, fullname):
 
     ## The feed widget works, but it needs to be cleaned up lots before we
     ## throw it in by default.
-    #widget = hubs.models.Widget(
-    #    plugin='feed', index=1, left=True,
-    #    _config=json.dumps({
-    #        'username': username,
-    #        'fmn_context': 'irc',  # TODO -- make this 'hubs'
-    #    }))
-    #hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='feed', index=1, left=True,
+        _config=json.dumps({
+            'username': username,
+            'fmn_context': 'irc',  # TODO -- make this 'hubs'
+        }))
+    hub.widgets.append(widget)
 
     # Right Side Widgets
     widget = hubs.models.Widget(

From d84cb4ea1ab9b19fc4d43f57f61224aaae293856 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 17:57:31 +0000
Subject: [PATCH 157/1001] Remove the avatar widget by default.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 82f9016..0916c23 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -24,37 +24,31 @@ def add_user_widgets(session, hub, username, fullname):
 
     # Right Side Widgets
     widget = hubs.models.Widget(
-        plugin='avatar', index=0,
+        plugin='fedmsgstats', index=0,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='fedmsgstats', index=1,
+        plugin='workflow.updates2stable', index=1,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='workflow.updates2stable', index=2,
+        plugin='workflow.pendingacls', index=2,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='workflow.pendingacls', index=3,
+        plugin='subscriptions', index=3,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='subscriptions', index=4,
-        _config=json.dumps({
-            'username': username,
-        }))
-    hub.widgets.append(widget)
-    widget = hubs.models.Widget(
-        plugin='badges', index=5,
+        plugin='badges', index=4,
         _config=json.dumps({
             'username': username,
         }))

From 8871ee9e1f969c0dd024765f28ed32f93fb6b11d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 17:58:21 +0000
Subject: [PATCH 158/1001] Add lmacken to the defaults.


---

diff --git a/populate.py b/populate.py
index 9e02e82..663da37 100755
--- a/populate.py
+++ b/populate.py
@@ -11,7 +11,7 @@ fedmsg_config = fedmsg.config.load_config()
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
-         'abompard', 'decause', 'ralph']
+         'abompard', 'decause', 'ralph', 'lmacken']
 for username in users:
     fullname = 'Full Name Goes Here'
     openid = '%s.id.fedoraproject.org' % username
@@ -96,6 +96,7 @@ hub.widgets.append(widget)
 
 hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'owner')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'abompard.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'lmacken.id.fedoraproject.org'), 'owner')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0.id.fedoraproject.org'), 'member')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'subscriber')
 

From 1d860d3954bfe572caf8155e0f3de53ab17c8c0b Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 18:02:42 +0000
Subject: [PATCH 159/1001] merge


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 0916c23..ce29c74 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -12,8 +12,8 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
 
-    ## The feed widget works, but it needs to be cleaned up lots before we
-    ## throw it in by default.
+    # The feed widget works, but it needs to be cleaned up lots before we
+    # throw it in by default.
     widget = hubs.models.Widget(
         plugin='feed', index=1, left=True,
         _config=json.dumps({
diff --git a/requirements.txt b/requirements.txt
index 62cb8fb..5585e6c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,3 +10,4 @@ fmn.lib
 fmn.rules
 datanommer.models
 psycopg2
+gunicorn

From 0d2fb7f3cedfb8040aff8fb56e0f5fd8326cf41f Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 18:02:42 +0000
Subject: [PATCH 160/1001] merge


---

diff --git a/hubs/app.py b/hubs/app.py
index f3157c5..bca015e 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -185,12 +185,10 @@ def check_auth():
     flask.g.fedmsg_config = fedmsg_config
     flask.g.auth = munch.Munch(logged_in=False)
     if 'openid' in flask.session:
-
         openid = flask.session.get('openid')
         if isinstance(openid, six.binary_type):
             openid = openid.decode('utf-8')
         openid = openid.strip('/').split('/')[-1]
-
         flask.g.auth.logged_in = True
         flask.g.auth.openid = openid
         flask.g.auth.user = hubs.models.User.by_openid(session, openid)

From f3ff66a180d90bb4a1309b142bc6cfd1b06d6cbe Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 18:02:42 +0000
Subject: [PATCH 161/1001] Added stubbed out sticky widget text for infra and design


---

diff --git a/populate.py b/populate.py
index 663da37..4e5fa75 100755
--- a/populate.py
+++ b/populate.py
@@ -46,7 +46,7 @@ hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
                             _config=json.dumps({
-                                'text': 'This is a sticky note.',
+                                'text': "The Design Team is the design group of the Fedora project. Our interests are not only in creating graphics for use by the Fedora community, but also in advocating the use of the creative tools that are a part of Fedora.",
                             }))
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
@@ -87,7 +87,7 @@ hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
                             _config=json.dumps({
-                                'text': 'This is a sticky note.',
+                                'text': "The Infrastructure Team consists of dedicated volunteers and professionals managing the servers, building the tools and utilities, and creating new applications to make Fedora development a smoother process. We're located all over the globe and communicate primarily by IRC and e-mail. ",
                             }))
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=1, left=True)

From 8fda819db66efcd526b85f81abb70a793184aeb8 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 18:03:14 +0000
Subject: [PATCH 162/1001] .gitignore build/


---

diff --git a/.gitignore b/.gitignore
index 7b3bc0e..d042055 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
 *.egg*
 fedmsg.d/fas_credentials.py
 node*
+build/

From 4df71ea13253eb9d1c4d62fac2263e6e1f2fec40 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 07 2015 18:06:32 +0000
Subject: [PATCH 163/1001] user icon top menu


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 008bcb2..eb34509 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -12,7 +12,18 @@
       font-family: 'Open Sans', 'sans-serif';
       font-size: 12pt;
     }
-    
+
+    .super-header img.avatar {
+      margin-right: 10px;
+      width: 22.5px;
+    }
+
+    .super-header .glyphicon-chevron-down {
+      color: #58595b;
+      margin: 5px 0 0 10px;
+      font-size: 18px;
+    }
+
     #logo { text-align: left; }
 
     .bookmarks .navbar.navbar-default {
@@ -23,7 +34,7 @@
       margin-bottom: 0;
       text-align: center;
     }
-    
+
     .bookmarks .navbar-nav > li > a {
       padding-bottom: 4.5px;
       padding-top: 4.5px;
@@ -37,7 +48,7 @@
       background-color: transparent;
       border-bottom: 3px solid #3c6eb4;
     }
-    
+
     .header {
       color: #ffffff;
       background-color: #3c6eb4;
@@ -110,7 +121,7 @@
     display: flex;
     flex-direction: row;
     flex-wrap: wrap;
-} 
+}
 
 .stats-table {
 width: 180px
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 06d45a5..aa38649 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -14,7 +14,9 @@
 	<div class="col-md-4 col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
     <div class="col-md-8 col-xs-8">
       {% if g.auth.logged_in %}
+	      <img src="{{hub.avatar}}" class="avatar" alt="User Icon"/>
         {# Logged in as #} {{ g.auth.nickname }}
+        <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
       {% else %}
         Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
       {% endif %}

From 6541ffbb0ec7b081aee87fb64f6ff681b3ea7361 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 07 2015 18:06:40 +0000
Subject: [PATCH 164/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/.gitignore b/.gitignore
index 7b3bc0e..d042055 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
 *.egg*
 fedmsg.d/fas_credentials.py
 node*
+build/
diff --git a/README.rst b/README.rst
index 0056e6e..3399529 100644
--- a/README.rst
+++ b/README.rst
@@ -56,7 +56,7 @@ If you want to test it with 8 worker threads, try ``gunicorn``::
 When hacking on widgets, it is useful to have this one-liner handy.  It removes
 the db alltogether, re-populates it, and restarts the app::
 
-    $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 60 --log-config logging.ini hubs.app:app
+    $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 240 --log-config logging.ini hubs.app:app
 
 Feed Widget - the Extra Mile
 ----------------------------
diff --git a/hubs/app.py b/hubs/app.py
index f5262d4..bca015e 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -5,6 +5,7 @@ import os
 import flask
 import flask.json
 import munch
+import six
 
 from flask.ext.openid import OpenID
 
@@ -184,7 +185,10 @@ def check_auth():
     flask.g.fedmsg_config = fedmsg_config
     flask.g.auth = munch.Munch(logged_in=False)
     if 'openid' in flask.session:
-        openid = flask.session.get('openid').strip('/').split('/')[-1]
+        openid = flask.session.get('openid')
+        if isinstance(openid, six.binary_type):
+            openid = openid.decode('utf-8')
+        openid = openid.strip('/').split('/')[-1]
         flask.g.auth.logged_in = True
         flask.g.auth.openid = openid
         flask.g.auth.user = hubs.models.User.by_openid(session, openid)
@@ -222,7 +226,49 @@ def get_widget(session, hub, idx):
     flask.abort(404)
 
 
-
+## Here are a bunch of API methods that should probably be broken out into
+## their own file
+@app.route('/api/hub/<hub>/subscribe', methods=['POST'])
+@login_required
+def hub_subscribe(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    hub.subscribe(session, user)
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+@app.route('/api/hub/<hub>/unsubscribe', methods=['POST'])
+@login_required
+def hub_unsubscribe(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    try:
+        hub.unsubscribe(session, user)
+    except KeyError:
+        return flask.abort(400)
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+@app.route('/api/hub/<hub>/join', methods=['POST'])
+@login_required
+def hub_join(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    hub.subscribe(session, user, role='member')
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+@app.route('/api/hub/<hub>/leave', methods=['POST'])
+@login_required
+def hub_leave(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    try:
+        hub.unsubscribe(session, user, role='member')
+    except KeyError:
+        return flask.abort(400)
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
 
 
 if __name__ == '__main__':
diff --git a/hubs/defaults.py b/hubs/defaults.py
index 80f4520..ce29c74 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -12,49 +12,43 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
 
-    ## The feed widget works, but it needs to be cleaned up lots before we
-    ## throw it in by default.
-    #widget = hubs.models.Widget(
-    #    plugin='feed', index=1, left=True,
-    #    _config=json.dumps({
-    #        'username': username,
-    #        'fmn_context': 'irc',  # TODO -- make this 'hubs'
-    #    }))
-    #hub.widgets.append(widget)
-
-    # Right Side Widgets
+    # The feed widget works, but it needs to be cleaned up lots before we
+    # throw it in by default.
     widget = hubs.models.Widget(
-        plugin='avatar', index=0,
+        plugin='feed', index=1, left=True,
         _config=json.dumps({
             'username': username,
+            'fmn_context': 'irc',  # TODO -- make this 'hubs'
         }))
     hub.widgets.append(widget)
+
+    # Right Side Widgets
     widget = hubs.models.Widget(
-        plugin='fedmsgstats', index=1,
+        plugin='fedmsgstats', index=0,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='workflow.updates2stable', index=2,
+        plugin='workflow.updates2stable', index=1,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='workflow.pendingacls', index=3,
+        plugin='workflow.pendingacls', index=2,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='subscriptions', index=4,
+        plugin='subscriptions', index=3,
         _config=json.dumps({
             'username': username,
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='badges', index=5,
+        plugin='badges', index=4,
         _config=json.dumps({
             'username': username,
         }))
diff --git a/hubs/models.py b/hubs/models.py
index 9933dd6..ff117ab 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -24,7 +24,6 @@
 import datetime
 import json
 import logging
-import random
 
 import sqlalchemy as sa
 from sqlalchemy import create_engine
@@ -101,6 +100,14 @@ class Association(BASE):
     user = relation("User", backref="associations")
     hub = relation("Hub", backref="associations")
 
+    @classmethod
+    def get(cls, session, hub, user, role):
+        return session.query(cls)\
+            .filter_by(hub=hub)\
+            .filter_by(user=user)\
+            .filter_by(role=role)\
+            .first()
+
 
 class Hub(BASE):
     __tablename__ = 'hubs'
@@ -137,6 +144,18 @@ class Hub(BASE):
         session.add(Association(user=user, hub=self, role=role))
         session.commit()
 
+    def unsubscribe(self, session, user, role='subscriber'):
+        """ Subscribe a user to this hub. """
+        # TODO -- add logic here to manage not adding the user multiple
+        # times, doing different roles, etc.. publish a fedmsg message,
+        # etc...
+        association = Association.get(session, hub=self, user=user, role=role)
+        if not association:
+            raise KeyError("%r is not a %r of %r" % (user, role, self))
+        session.delete(association)
+        session.commit()
+
+
     @classmethod
     def by_name(cls, session, name):
         return session.query(cls).filter_by(name=name).first()
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 67a0e26..3f77a47 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,6 +1,7 @@
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 
+import flask
 import jinja2
 
 chrome = panel()
@@ -10,16 +11,29 @@ template = jinja2.Template("""
     <tr><th>Members</th><th>Subscribers</th></tr>
     <tr class="text-info"><td>{{members | length}}</td><td>{{subscribers | length}}</td></tr>
   </table>
+
   {% if g.auth.logged_in %}
+    <div class="pull-right">
     {% if g.auth.nickname in members %}
-    <div class="pull-right"><button class="btn btn-danger">Resign</button></div>
+    <form action="{{hub_leave_url}}" method="POST">
+        <button class="btn btn-danger">Leave Hub</button>
+    </form>
     {% elif g.auth.nickname in subscribers %}
-    <div class="pull-right"><button class="btn btn-warning">Unsubscribe</button></div>
+    <form action="{{hub_unsubscribe_url}}" method="POST">
+        <button class="btn btn-warning">Unsubscribe</button>
+    </form>
     {% else %}
-    <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+    <form action="{{hub_subscribe_url}}" method="POST">
+        <button class="btn btn-info">Subscribe</button>
+    </form>
     {% endif %}
+    </div>
   {% else %}
-    <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+    <div class="pull-right">
+        <form action="{{hub_subscribe_url}}" method="POST">
+            <button class="btn btn-info">Subscribe</button>
+        </form>
+    </div>
   {% endif %}
 </div>
 """)
@@ -30,6 +44,10 @@ def data(session, widget):
         owners=[u.username for u in widget.hub.owners],
         members=[u.username for u in widget.hub.members],
         subscribers=[u.username for u in widget.hub.subscribers],
+        hub_leave_url=flask.url_for('hub_leave', hub=widget.hub.name),
+        hub_join_url=flask.url_for('hub_join', hub=widget.hub.name),
+        hub_subscribe_url=flask.url_for('hub_subscribe', hub=widget.hub.name),
+        hub_unsubscribe_url=flask.url_for('hub_unsubscribe', hub=widget.hub.name),
     )
 
 
diff --git a/populate.py b/populate.py
index 9e02e82..4e5fa75 100755
--- a/populate.py
+++ b/populate.py
@@ -11,7 +11,7 @@ fedmsg_config = fedmsg.config.load_config()
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
-         'abompard', 'decause', 'ralph']
+         'abompard', 'decause', 'ralph', 'lmacken']
 for username in users:
     fullname = 'Full Name Goes Here'
     openid = '%s.id.fedoraproject.org' % username
@@ -46,7 +46,7 @@ hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
                             _config=json.dumps({
-                                'text': 'This is a sticky note.',
+                                'text': "The Design Team is the design group of the Fedora project. Our interests are not only in creating graphics for use by the Fedora community, but also in advocating the use of the creative tools that are a part of Fedora.",
                             }))
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
@@ -87,7 +87,7 @@ hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
                             _config=json.dumps({
-                                'text': 'This is a sticky note.',
+                                'text': "The Infrastructure Team consists of dedicated volunteers and professionals managing the servers, building the tools and utilities, and creating new applications to make Fedora development a smoother process. We're located all over the globe and communicate primarily by IRC and e-mail. ",
                             }))
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
@@ -96,6 +96,7 @@ hub.widgets.append(widget)
 
 hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'owner')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'abompard.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'lmacken.id.fedoraproject.org'), 'owner')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0.id.fedoraproject.org'), 'member')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'subscriber')
 
diff --git a/requirements.txt b/requirements.txt
index 62cb8fb..5585e6c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,3 +10,4 @@ fmn.lib
 fmn.rules
 datanommer.models
 psycopg2
+gunicorn

From e5a8e3dc5b5126e0d5ac7c9385f3a0459023d546 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 18:25:13 +0000
Subject: [PATCH 165/1001] Added text-right class to both stats counter widgets


---

diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 2f075ab..b353ea3 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -14,7 +14,7 @@ template = jinja2.Template("""
 <div class="stats-container">
   <table class="stats-table">
     <tr><th>FedMsgs</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{{fedmsgs}}</td><td>{{subscribers}}</td></tr>
+    <tr class="text-info"><td>{{fedmsgs}}</td><td class="text-right">{{subscribers}}</td></tr>
   </table>
   {% if session['nickname'] != username %}
   <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 3f77a47..12c620a 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -9,7 +9,7 @@ template = jinja2.Template("""
 <div class="stats-container">
   <table class="stats-table">
     <tr><th>Members</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{{members | length}}</td><td>{{subscribers | length}}</td></tr>
+    <tr class="text-info"><td>{{members | length}}</td><td class="text-right">{{subscribers | length}}</td></tr>
   </table>
 
   {% if g.auth.logged_in %}

From 5740eab8f4f5aca55f902dee41aa79e5e26b1b94 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 18:39:02 +0000
Subject: [PATCH 166/1001] Added icons within Subscribe/Unsubscribe button, as per mockups


---

diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 12c620a..31205c4 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -20,11 +20,11 @@ template = jinja2.Template("""
     </form>
     {% elif g.auth.nickname in subscribers %}
     <form action="{{hub_unsubscribe_url}}" method="POST">
-        <button class="btn btn-warning">Unsubscribe</button>
+        <button class="btn btn-warning"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
     </form>
     {% else %}
     <form action="{{hub_subscribe_url}}" method="POST">
-        <button class="btn btn-info">Subscribe</button>
+        <button class="btn btn-info"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Subscribe</button>
     </form>
     {% endif %}
     </div>

From c33a179d3f07c69f3c49dcfea87aabdb5d609326 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 07 2015 18:41:48 +0000
Subject: [PATCH 167/1001] bootstrap js included


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index aa38649..6d67787 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -80,6 +80,7 @@
 </div>
 
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
 <script>
 var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
 $.each(widgets, function(i, widget) {

From 523a3795a4d641731b7457c8646652db03b59258 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 07 2015 18:42:03 +0000
Subject: [PATCH 168/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 12c620a..31205c4 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -20,11 +20,11 @@ template = jinja2.Template("""
     </form>
     {% elif g.auth.nickname in subscribers %}
     <form action="{{hub_unsubscribe_url}}" method="POST">
-        <button class="btn btn-warning">Unsubscribe</button>
+        <button class="btn btn-warning"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
     </form>
     {% else %}
     <form action="{{hub_subscribe_url}}" method="POST">
-        <button class="btn btn-info">Subscribe</button>
+        <button class="btn btn-info"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Subscribe</button>
     </form>
     {% endif %}
     </div>

From 45f392a4e48575d0c29378585669dcbdeb0066d1 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 18:46:10 +0000
Subject: [PATCH 169/1001] Added icons for all cases of button


---

diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 31205c4..ee00da2 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -16,7 +16,7 @@ template = jinja2.Template("""
     <div class="pull-right">
     {% if g.auth.nickname in members %}
     <form action="{{hub_leave_url}}" method="POST">
-        <button class="btn btn-danger">Leave Hub</button>
+        <button class="btn btn-danger"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Leave Hub</button>
     </form>
     {% elif g.auth.nickname in subscribers %}
     <form action="{{hub_unsubscribe_url}}" method="POST">
@@ -31,7 +31,7 @@ template = jinja2.Template("""
   {% else %}
     <div class="pull-right">
         <form action="{{hub_subscribe_url}}" method="POST">
-            <button class="btn btn-info">Subscribe</button>
+            <button class="btn btn-info"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Subscribe</button>
         </form>
     </div>
   {% endif %}

From 9d43f4477a8df0cf3c0ca3f2735f721c68de7fb0 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 18:46:10 +0000
Subject: [PATCH 170/1001] Added info sign icon to about widget


---

diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index b0df6cc..84b8de7 100644
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -10,7 +10,7 @@ import hubs.validators as validators
 template = jinja2.Template("""
     <p>{{text}}</p>
     """)
-chrome = panel("About")
+chrome = panel("<span class='glyphicon glyphicon-info-sign' aria-hidden='true'></span> About")
 
 
 @argument(name="text", default="I am a Fedora user, and this is my about",

From 53b861b40f346c391ab3f77b3b74281b25542949 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 19:02:48 +0000
Subject: [PATCH 171/1001] Added a marketing team. Changed 'rules' links to point to Fedora Wiki


---

diff --git a/populate.py b/populate.py
index 4e5fa75..b4a5a4d 100755
--- a/populate.py
+++ b/populate.py
@@ -11,7 +11,7 @@ fedmsg_config = fedmsg.config.load_config()
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
-         'abompard', 'decause', 'ralph', 'lmacken']
+         'abompard', 'decause', 'ralph', 'lmacken', 'croberts', 'mattdm']
 for username in users:
     fullname = 'Full Name Goes Here'
     openid = '%s.id.fedoraproject.org' % username
@@ -21,8 +21,49 @@ for username in users:
 
 session.commit()
 
+############## Marketing team
+hub = hubs.models.Hub(name='marketingteam', summary='The Fedora Marketing Team')
+session.add(hub)
 
-############## Infra team
+widget = hubs.models.Widget(plugin='stats', index=0)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='rules', index=1,
+                            _config=json.dumps({
+                                'link': 'https://fedoraproject.org/wiki/Marketing'
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='dummy', index=2)
+hub.widgets.append(widget)
+
+# Added a hubs about widget
+widget = hubs.models.Widget(plugin='about', index=3,
+                            _config=json.dumps({
+                                "text": "I'm a Fedora user, and this is my about widget text!",
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+                            _config=json.dumps({
+                                'text': "The Fedora Marketing Team develops and executes marketing strategies to promote the usage and support of Fedora worldwide. Through the development of processes and content, this project aims to support the efforts of other Fedora projects to spread Fedora and to provide a central repository of ideas and information that can be used to deliver Fedora to new audiences. We work closely with the Fedora Ambassadors who spread the word about Fedora at events and allow the Fedora Project to interact directly with its existing and prospective users. ",
+                            }))
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
+hub.widgets.append(widget)
+
+
+# Set up some memberships
+hub.subscribe(session, hubs.models.User.by_openid(session, 'croberts.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'mattdm.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
+
+
+session.commit()
+
+############## Design team
 hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
 session.add(hub)
 
@@ -30,7 +71,7 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'http://threebean.org'
+                                'link': 'https://fedoraproject.org/wiki/Design'
                             }))
 hub.widgets.append(widget)
 
@@ -62,6 +103,8 @@ hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0.id.fedoraproje
 hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
 
+session.commit()
+
 
 ############## Infra team
 hub = hubs.models.Hub(name='infrastructure', summary='The Fedora Infrastructure Team')
@@ -71,7 +114,7 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'http://threebean.org'
+                                'link': 'https://fedoraproject.org/wiki/Infrastructure'
                             }))
 hub.widgets.append(widget)
 

From 50b9c718614aa0f19ee2fe18cfdb2a732583ae44 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Jul 07 2015 19:11:28 +0000
Subject: [PATCH 172/1001] Added internationalization team stub


---

diff --git a/populate.py b/populate.py
index b4a5a4d..44699ac 100755
--- a/populate.py
+++ b/populate.py
@@ -11,7 +11,8 @@ fedmsg_config = fedmsg.config.load_config()
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
-         'abompard', 'decause', 'ralph', 'lmacken', 'croberts', 'mattdm']
+         'abompard', 'decause', 'ralph', 'lmacken', 'croberts', 'mattdm',
+         'pravins']
 for username in users:
     fullname = 'Full Name Goes Here'
     openid = '%s.id.fedoraproject.org' % username
@@ -21,6 +22,45 @@ for username in users:
 
 session.commit()
 
+############## Internationalizationteam
+hub = hubs.models.Hub(name='Internationalizationteam', summary='The Fedora Internationalization Team')
+session.add(hub)
+
+widget = hubs.models.Widget(plugin='stats', index=0)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='rules', index=1,
+                            _config=json.dumps({
+                                'link': 'https://fedoraproject.org/wiki/I18N'
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='dummy', index=2)
+hub.widgets.append(widget)
+
+# Added a hubs about widget
+widget = hubs.models.Widget(plugin='about', index=3,
+                            _config=json.dumps({
+                                "text": "I'm a Fedora user, and this is my about widget text!",
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+                            _config=json.dumps({
+                                'text': "<p>The Fedora I18N project works on internationalization (i18n) to support the localization (l10n) of Fedora in many languages. Translation of Fedora software and documentation are handled by the Fedora L10N project.</p> <p>The goals of the Project are to:</p> <ul><li>Develop, package, and maintain applications like input methods for different languages</li> <li>Improve applications and utilities to support and process different languages</li> <li>Quality-assure that existing applications meet i18n standards</li> <li>Support the infrastructure of the Fedora Localization Project</li></ul>",
+                            }))
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
+hub.widgets.append(widget)
+
+
+# Set up some memberships
+hub.subscribe(session, hubs.models.User.by_openid(session, 'pravins.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
+
+
+session.commit()
+
 ############## Marketing team
 hub = hubs.models.Hub(name='marketingteam', summary='The Fedora Marketing Team')
 session.add(hub)

From ef7e683a2b416d6ef5ee79c7534578cb9f47c802 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 19:52:37 +0000
Subject: [PATCH 173/1001] Try to match the stats widget to the mockup.


---

diff --git a/hubs/app.py b/hubs/app.py
index bca015e..cac231f 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -50,6 +50,12 @@ class CustomJSONEncoder(flask.json.JSONEncoder):
 app.json_encoder = CustomJSONEncoder
 
 
+@app.teardown_request
+def shutdown_session(exception=None):
+    """ Remove the DB session at the end of each request. """
+    session.remove()
+
+
 @app.route('/')
 def index():
     if not flask.g.auth.logged_in:
@@ -249,6 +255,27 @@ def hub_unsubscribe(hub):
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
+@app.route('/api/hub/<hub>/star', methods=['POST'])
+@login_required
+def hub_star(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    hub.subscribe(session, user, role='stargazer')
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+@app.route('/api/hub/<hub>/unstar', methods=['POST'])
+@login_required
+def hub_unstar(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    try:
+        hub.unsubscribe(session, user, role='stargazer')
+    except KeyError:
+        return flask.abort(400)
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
 @app.route('/api/hub/<hub>/join', methods=['POST'])
 @login_required
 def hub_join(hub):
diff --git a/hubs/models.py b/hubs/models.py
index ff117ab..ef97536 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -83,7 +83,7 @@ def init(db_url, debug=False, create=False):
     return scoped_session(sessionmaker(bind=engine))
 
 
-roles = ['subscriber', 'member', 'owner']
+roles = ['subscriber', 'member', 'owner', 'stargazer']
 
 
 class Association(BASE):
@@ -95,7 +95,7 @@ class Association(BASE):
     user_id = sa.Column(sa.Text,
                         sa.ForeignKey('users.openid'),
                         primary_key=True)
-    role = sa.Column(sa.Enum(*roles), nullable=False)
+    role = sa.Column(sa.Enum(*roles), primary_key=True)
 
     user = relation("User", backref="associations")
     hub = relation("Hub", backref="associations")
@@ -126,6 +126,7 @@ class Hub(BASE):
     def owners(self):
         return [assoc.user for assoc in self.associations
                 if assoc.role == 'owner']
+
     @property
     def members(self):
         return [assoc.user for assoc in self.associations
@@ -136,6 +137,11 @@ class Hub(BASE):
         return [assoc.user for assoc in self.associations
                 if assoc.role == 'subscriber']
 
+    @property
+    def stargazers(self):
+        return [assoc.user for assoc in self.associations
+                if assoc.role == 'stargazer']
+
     def subscribe(self, session, user, role='subscriber'):
         """ Subscribe a user to this hub. """
         # TODO -- add logic here to manage not adding the user multiple
@@ -284,6 +290,19 @@ class User(BASE):
                 if assoc.role == 'subscriber']
 
     @property
+    def starred_hubs(self):
+        return [assoc.hub for assoc in self.associations
+                if assoc.role == 'stargazer']
+
+    @property
+    def bookmarks(self):
+        # TODO -- someday make this editable/configurable.
+        return sorted(list(set([assoc.hub for assoc in self.associations
+                if assoc.role == 'member'
+                or assoc.role == 'subscriber'
+                or assoc.role == 'owner'])))
+
+    @property
     def username(self):
         return self.openid.split('.')[0]
 
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 6d67787..d108da0 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -41,12 +41,10 @@
           {% if g.auth.logged_in %}
           <li {% if request.path.endswith('/' + g.auth.user.username + '/') %}class='active'{% endif %}>
             <a href="/{{g.auth.user.username}}">me</a></li>
-          {% for assoc in g.auth.user.associations %}
-          <li {% if request.path.endswith('/' + assoc.hub.name + '/') %}class='active'{% endif %}>
-          <a href="/{{assoc.hub.name}}">{{assoc.hub.name}}</a></li>
+          {% for hub in g.auth.user.bookmarks %}
+          <li {% if request.path.endswith('/' + hub.name + '/') %}class='active'{% endif %}>
+          <a href="/{{hub.name}}">{{hub.name}}</a></li>
           {% endfor %}
-          <li class="divider"></li>
-          <li><a href="#">Separated link</a></li>
           {% endif %}
         </ul>
       </div><!-- /.navbar-collapse -->
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index ee00da2..228d60f 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -6,35 +6,46 @@ import jinja2
 
 chrome = panel()
 template = jinja2.Template("""
-<div class="stats-container">
+<div class="stats-container row">
+<div class="col-md-7">
   <table class="stats-table">
     <tr><th>Members</th><th>Subscribers</th></tr>
     <tr class="text-info"><td>{{members | length}}</td><td class="text-right">{{subscribers | length}}</td></tr>
   </table>
+</div>
+<div class="col-md-5">
+  <ul class="list-unstyled">
+  {% if g.auth.nickname in subscribers %}
+  <li><form action="{{hub_unsubscribe_url}}" method="POST">
+      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
+  </form></li>
+  {% else %}
+  <li><form action="{{hub_subscribe_url}}" method="POST">
+      <button class="btn btn-default"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Subscribe</button>
+  </form></li>
+  {% endif %}
+
+  {% if g.auth.nickname in stargazers %}
+  <li><form action="{{hub_unstar_url}}" method="POST">
+      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unstar Hub</button>
+  </form></li>
+  {% else %}
+  <li><form action="{{hub_star_url}}" method="POST">
+      <button class="btn btn-default"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Star Hub</button>
+  </form></li>
+  {% endif %}
 
-  {% if g.auth.logged_in %}
-    <div class="pull-right">
-    {% if g.auth.nickname in members %}
-    <form action="{{hub_leave_url}}" method="POST">
-        <button class="btn btn-danger"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Leave Hub</button>
-    </form>
-    {% elif g.auth.nickname in subscribers %}
-    <form action="{{hub_unsubscribe_url}}" method="POST">
-        <button class="btn btn-warning"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
-    </form>
-    {% else %}
-    <form action="{{hub_subscribe_url}}" method="POST">
-        <button class="btn btn-info"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Subscribe</button>
-    </form>
-    {% endif %}
-    </div>
+  {% if g.auth.nickname in members %}
+  <li><form action="{{hub_leave_url}}" method="POST">
+      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Leave Hub</button>
+  </form></li>
   {% else %}
-    <div class="pull-right">
-        <form action="{{hub_subscribe_url}}" method="POST">
-            <button class="btn btn-info"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Subscribe</button>
-        </form>
-    </div>
+  <li><form action="{{hub_join_url}}" method="POST">
+      <button class="btn btn-default"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Join Hub</button>
+  </form></li>
   {% endif %}
+  </ul>
+</div>
 </div>
 """)
 
@@ -44,8 +55,12 @@ def data(session, widget):
         owners=[u.username for u in widget.hub.owners],
         members=[u.username for u in widget.hub.members],
         subscribers=[u.username for u in widget.hub.subscribers],
+        stargazers=[u.username for u in widget.hub.stargazers],
+
         hub_leave_url=flask.url_for('hub_leave', hub=widget.hub.name),
         hub_join_url=flask.url_for('hub_join', hub=widget.hub.name),
+        hub_unstar_url=flask.url_for('hub_unstar', hub=widget.hub.name),
+        hub_star_url=flask.url_for('hub_star', hub=widget.hub.name),
         hub_subscribe_url=flask.url_for('hub_subscribe', hub=widget.hub.name),
         hub_unsubscribe_url=flask.url_for('hub_unsubscribe', hub=widget.hub.name),
     )

From 35f359a99669577e80116e672b2c65292801a4ce Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 07 2015 21:35:54 +0000
Subject: [PATCH 174/1001] nav profile dropdown


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index eb34509..7ce693b 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -3,7 +3,6 @@
     }
 
     .super-header {
-      text-align: right;
       background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
       background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
       background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 6d67787..5dcf3ee 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -12,11 +12,22 @@
 <div class="super-header">
   <div class="row">
 	<div class="col-md-4 col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
-    <div class="col-md-8 col-xs-8">
+    <div class="col-md-2 col-md-offset-6 col-xs-8">
       {% if g.auth.logged_in %}
-	      <img src="{{hub.avatar}}" class="avatar" alt="User Icon"/>
-        {# Logged in as #} {{ g.auth.nickname }}
-        <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
+        <div class="dropdown">
+        <span class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+          <img src="{{hub.avatar}}" class="avatar" alt="User Icon"/>
+          {# Logged in as #} {{ g.auth.nickname }}
+          <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
+        </span>
+        <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
+          <li class="dropdown-header">Account Information</li>
+          <li><a href="#">Full Name: {{hub.summary}}</a></li>
+          <li><a href="#">Email: blah</a></li>
+          <li role="separator" class="divider"></li>
+          <li><a href="#">Separated link</a></li>
+        </ul>
+      </div>
       {% else %}
         Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
       {% endif %}

From db44fa520de4c61ccedd328dd7239610c4f8ec30 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 07 2015 21:36:02 +0000
Subject: [PATCH 175/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/hubs/app.py b/hubs/app.py
index bca015e..cac231f 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -50,6 +50,12 @@ class CustomJSONEncoder(flask.json.JSONEncoder):
 app.json_encoder = CustomJSONEncoder
 
 
+@app.teardown_request
+def shutdown_session(exception=None):
+    """ Remove the DB session at the end of each request. """
+    session.remove()
+
+
 @app.route('/')
 def index():
     if not flask.g.auth.logged_in:
@@ -249,6 +255,27 @@ def hub_unsubscribe(hub):
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
+@app.route('/api/hub/<hub>/star', methods=['POST'])
+@login_required
+def hub_star(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    hub.subscribe(session, user, role='stargazer')
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+@app.route('/api/hub/<hub>/unstar', methods=['POST'])
+@login_required
+def hub_unstar(hub):
+    hub = get_hub(session, hub)
+    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    try:
+        hub.unsubscribe(session, user, role='stargazer')
+    except KeyError:
+        return flask.abort(400)
+    session.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
 @app.route('/api/hub/<hub>/join', methods=['POST'])
 @login_required
 def hub_join(hub):
diff --git a/hubs/models.py b/hubs/models.py
index ff117ab..ef97536 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -83,7 +83,7 @@ def init(db_url, debug=False, create=False):
     return scoped_session(sessionmaker(bind=engine))
 
 
-roles = ['subscriber', 'member', 'owner']
+roles = ['subscriber', 'member', 'owner', 'stargazer']
 
 
 class Association(BASE):
@@ -95,7 +95,7 @@ class Association(BASE):
     user_id = sa.Column(sa.Text,
                         sa.ForeignKey('users.openid'),
                         primary_key=True)
-    role = sa.Column(sa.Enum(*roles), nullable=False)
+    role = sa.Column(sa.Enum(*roles), primary_key=True)
 
     user = relation("User", backref="associations")
     hub = relation("Hub", backref="associations")
@@ -126,6 +126,7 @@ class Hub(BASE):
     def owners(self):
         return [assoc.user for assoc in self.associations
                 if assoc.role == 'owner']
+
     @property
     def members(self):
         return [assoc.user for assoc in self.associations
@@ -136,6 +137,11 @@ class Hub(BASE):
         return [assoc.user for assoc in self.associations
                 if assoc.role == 'subscriber']
 
+    @property
+    def stargazers(self):
+        return [assoc.user for assoc in self.associations
+                if assoc.role == 'stargazer']
+
     def subscribe(self, session, user, role='subscriber'):
         """ Subscribe a user to this hub. """
         # TODO -- add logic here to manage not adding the user multiple
@@ -284,6 +290,19 @@ class User(BASE):
                 if assoc.role == 'subscriber']
 
     @property
+    def starred_hubs(self):
+        return [assoc.hub for assoc in self.associations
+                if assoc.role == 'stargazer']
+
+    @property
+    def bookmarks(self):
+        # TODO -- someday make this editable/configurable.
+        return sorted(list(set([assoc.hub for assoc in self.associations
+                if assoc.role == 'member'
+                or assoc.role == 'subscriber'
+                or assoc.role == 'owner'])))
+
+    @property
     def username(self):
         return self.openid.split('.')[0]
 
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 5dcf3ee..d830fc8 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -52,12 +52,10 @@
           {% if g.auth.logged_in %}
           <li {% if request.path.endswith('/' + g.auth.user.username + '/') %}class='active'{% endif %}>
             <a href="/{{g.auth.user.username}}">me</a></li>
-          {% for assoc in g.auth.user.associations %}
-          <li {% if request.path.endswith('/' + assoc.hub.name + '/') %}class='active'{% endif %}>
-          <a href="/{{assoc.hub.name}}">{{assoc.hub.name}}</a></li>
+          {% for hub in g.auth.user.bookmarks %}
+          <li {% if request.path.endswith('/' + hub.name + '/') %}class='active'{% endif %}>
+          <a href="/{{hub.name}}">{{hub.name}}</a></li>
           {% endfor %}
-          <li class="divider"></li>
-          <li><a href="#">Separated link</a></li>
           {% endif %}
         </ul>
       </div><!-- /.navbar-collapse -->
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index b0df6cc..84b8de7 100644
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -10,7 +10,7 @@ import hubs.validators as validators
 template = jinja2.Template("""
     <p>{{text}}</p>
     """)
-chrome = panel("About")
+chrome = panel("<span class='glyphicon glyphicon-info-sign' aria-hidden='true'></span> About")
 
 
 @argument(name="text", default="I am a Fedora user, and this is my about",
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 31205c4..228d60f 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -6,35 +6,46 @@ import jinja2
 
 chrome = panel()
 template = jinja2.Template("""
-<div class="stats-container">
+<div class="stats-container row">
+<div class="col-md-7">
   <table class="stats-table">
     <tr><th>Members</th><th>Subscribers</th></tr>
     <tr class="text-info"><td>{{members | length}}</td><td class="text-right">{{subscribers | length}}</td></tr>
   </table>
+</div>
+<div class="col-md-5">
+  <ul class="list-unstyled">
+  {% if g.auth.nickname in subscribers %}
+  <li><form action="{{hub_unsubscribe_url}}" method="POST">
+      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
+  </form></li>
+  {% else %}
+  <li><form action="{{hub_subscribe_url}}" method="POST">
+      <button class="btn btn-default"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Subscribe</button>
+  </form></li>
+  {% endif %}
+
+  {% if g.auth.nickname in stargazers %}
+  <li><form action="{{hub_unstar_url}}" method="POST">
+      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unstar Hub</button>
+  </form></li>
+  {% else %}
+  <li><form action="{{hub_star_url}}" method="POST">
+      <button class="btn btn-default"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Star Hub</button>
+  </form></li>
+  {% endif %}
 
-  {% if g.auth.logged_in %}
-    <div class="pull-right">
-    {% if g.auth.nickname in members %}
-    <form action="{{hub_leave_url}}" method="POST">
-        <button class="btn btn-danger">Leave Hub</button>
-    </form>
-    {% elif g.auth.nickname in subscribers %}
-    <form action="{{hub_unsubscribe_url}}" method="POST">
-        <button class="btn btn-warning"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
-    </form>
-    {% else %}
-    <form action="{{hub_subscribe_url}}" method="POST">
-        <button class="btn btn-info"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Subscribe</button>
-    </form>
-    {% endif %}
-    </div>
+  {% if g.auth.nickname in members %}
+  <li><form action="{{hub_leave_url}}" method="POST">
+      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Leave Hub</button>
+  </form></li>
   {% else %}
-    <div class="pull-right">
-        <form action="{{hub_subscribe_url}}" method="POST">
-            <button class="btn btn-info">Subscribe</button>
-        </form>
-    </div>
+  <li><form action="{{hub_join_url}}" method="POST">
+      <button class="btn btn-default"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Join Hub</button>
+  </form></li>
   {% endif %}
+  </ul>
+</div>
 </div>
 """)
 
@@ -44,8 +55,12 @@ def data(session, widget):
         owners=[u.username for u in widget.hub.owners],
         members=[u.username for u in widget.hub.members],
         subscribers=[u.username for u in widget.hub.subscribers],
+        stargazers=[u.username for u in widget.hub.stargazers],
+
         hub_leave_url=flask.url_for('hub_leave', hub=widget.hub.name),
         hub_join_url=flask.url_for('hub_join', hub=widget.hub.name),
+        hub_unstar_url=flask.url_for('hub_unstar', hub=widget.hub.name),
+        hub_star_url=flask.url_for('hub_star', hub=widget.hub.name),
         hub_subscribe_url=flask.url_for('hub_subscribe', hub=widget.hub.name),
         hub_unsubscribe_url=flask.url_for('hub_unsubscribe', hub=widget.hub.name),
     )
diff --git a/populate.py b/populate.py
index 4e5fa75..44699ac 100755
--- a/populate.py
+++ b/populate.py
@@ -11,7 +11,8 @@ fedmsg_config = fedmsg.config.load_config()
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
-         'abompard', 'decause', 'ralph', 'lmacken']
+         'abompard', 'decause', 'ralph', 'lmacken', 'croberts', 'mattdm',
+         'pravins']
 for username in users:
     fullname = 'Full Name Goes Here'
     openid = '%s.id.fedoraproject.org' % username
@@ -21,8 +22,88 @@ for username in users:
 
 session.commit()
 
+############## Internationalizationteam
+hub = hubs.models.Hub(name='Internationalizationteam', summary='The Fedora Internationalization Team')
+session.add(hub)
 
-############## Infra team
+widget = hubs.models.Widget(plugin='stats', index=0)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='rules', index=1,
+                            _config=json.dumps({
+                                'link': 'https://fedoraproject.org/wiki/I18N'
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='dummy', index=2)
+hub.widgets.append(widget)
+
+# Added a hubs about widget
+widget = hubs.models.Widget(plugin='about', index=3,
+                            _config=json.dumps({
+                                "text": "I'm a Fedora user, and this is my about widget text!",
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+                            _config=json.dumps({
+                                'text': "<p>The Fedora I18N project works on internationalization (i18n) to support the localization (l10n) of Fedora in many languages. Translation of Fedora software and documentation are handled by the Fedora L10N project.</p> <p>The goals of the Project are to:</p> <ul><li>Develop, package, and maintain applications like input methods for different languages</li> <li>Improve applications and utilities to support and process different languages</li> <li>Quality-assure that existing applications meet i18n standards</li> <li>Support the infrastructure of the Fedora Localization Project</li></ul>",
+                            }))
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
+hub.widgets.append(widget)
+
+
+# Set up some memberships
+hub.subscribe(session, hubs.models.User.by_openid(session, 'pravins.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
+
+
+session.commit()
+
+############## Marketing team
+hub = hubs.models.Hub(name='marketingteam', summary='The Fedora Marketing Team')
+session.add(hub)
+
+widget = hubs.models.Widget(plugin='stats', index=0)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='rules', index=1,
+                            _config=json.dumps({
+                                'link': 'https://fedoraproject.org/wiki/Marketing'
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='dummy', index=2)
+hub.widgets.append(widget)
+
+# Added a hubs about widget
+widget = hubs.models.Widget(plugin='about', index=3,
+                            _config=json.dumps({
+                                "text": "I'm a Fedora user, and this is my about widget text!",
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+                            _config=json.dumps({
+                                'text': "The Fedora Marketing Team develops and executes marketing strategies to promote the usage and support of Fedora worldwide. Through the development of processes and content, this project aims to support the efforts of other Fedora projects to spread Fedora and to provide a central repository of ideas and information that can be used to deliver Fedora to new audiences. We work closely with the Fedora Ambassadors who spread the word about Fedora at events and allow the Fedora Project to interact directly with its existing and prospective users. ",
+                            }))
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
+hub.widgets.append(widget)
+
+
+# Set up some memberships
+hub.subscribe(session, hubs.models.User.by_openid(session, 'croberts.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'mattdm.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
+
+
+session.commit()
+
+############## Design team
 hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
 session.add(hub)
 
@@ -30,7 +111,7 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'http://threebean.org'
+                                'link': 'https://fedoraproject.org/wiki/Design'
                             }))
 hub.widgets.append(widget)
 
@@ -62,6 +143,8 @@ hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0.id.fedoraproje
 hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
 
+session.commit()
+
 
 ############## Infra team
 hub = hubs.models.Hub(name='infrastructure', summary='The Fedora Infrastructure Team')
@@ -71,7 +154,7 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'http://threebean.org'
+                                'link': 'https://fedoraproject.org/wiki/Infrastructure'
                             }))
 hub.widgets.append(widget)
 

From e5970a6c47a90545aff7afe2cd055f68968eac25 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 07 2015 23:47:43 +0000
Subject: [PATCH 176/1001] Put commas in those numbers.


---

diff --git a/hubs/app.py b/hubs/app.py
index cac231f..877991c 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -50,6 +50,11 @@ class CustomJSONEncoder(flask.json.JSONEncoder):
 app.json_encoder = CustomJSONEncoder
 
 
+@app.template_filter('commas')
+def commas(numeric):
+    return "{:,.2f}".format(numeric)
+
+
 @app.teardown_request
 def shutdown_session(exception=None):
     """ Remove the DB session at the end of each request. """
diff --git a/hubs/utils.py b/hubs/utils.py
index 35bf44a..0cbff18 100644
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -12,3 +12,7 @@ def username2avatar(username, s=312):
     hash = sha256(openid.encode('utf-8')).hexdigest()
     avatar = "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)
     return avatar
+
+
+def commas(numeric):
+    return "{:,}".format(numeric)
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index b353ea3..505d88b 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -1,6 +1,8 @@
 from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 
+from hubs.utils import commas
+
 import jinja2
 import requests
 
@@ -14,7 +16,7 @@ template = jinja2.Template("""
 <div class="stats-container">
   <table class="stats-table">
     <tr><th>FedMsgs</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{{fedmsgs}}</td><td class="text-right">{{subscribers}}</td></tr>
+    <tr class="text-info"><td>{{fedmsgs_text}}</td><td class="text-right">{{subscribers_text}}</td></tr>
   </table>
   {% if session['nickname'] != username %}
   <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
@@ -32,6 +34,8 @@ def data(session, widget, username):
         username=username,
         fedmsgs=fedmsgs,
         subscribers=len(widget.hub.subscribers),
+        fedmsgs_text=commas(fedmsgs),
+        subscribers_text=commas(len(widget.hub.subscribers)),
     )
 
 
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 228d60f..0e4a274 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,6 +1,8 @@
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 
+from hubs.utils import commas
+
 import flask
 import jinja2
 
@@ -10,7 +12,7 @@ template = jinja2.Template("""
 <div class="col-md-7">
   <table class="stats-table">
     <tr><th>Members</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{{members | length}}</td><td class="text-right">{{subscribers | length}}</td></tr>
+    <tr class="text-info"><td>{{members_text}}</td><td class="text-right">{{subscribers_text}}</td></tr>
   </table>
 </div>
 <div class="col-md-5">
@@ -51,11 +53,21 @@ template = jinja2.Template("""
 
 
 def data(session, widget):
+    owners = [u.username for u in widget.hub.owners]
+    members = [u.username for u in widget.hub.members]
+    subscribers = [u.username for u in widget.hub.subscribers]
+    stargazers = [u.username for u in widget.hub.stargazers]
+
     return dict(
-        owners=[u.username for u in widget.hub.owners],
-        members=[u.username for u in widget.hub.members],
-        subscribers=[u.username for u in widget.hub.subscribers],
-        stargazers=[u.username for u in widget.hub.stargazers],
+        owners=owners,
+        members=members,
+        subscribers=subscribers,
+        stargazers=stargazers,
+
+        owners_text=commas(len(owners)),
+        members_text=commas(len(members)),
+        subscribers_text=commas(len(subscribers)),
+        stargazers_text=commas(len(stargazers)),
 
         hub_leave_url=flask.url_for('hub_leave', hub=widget.hub.name),
         hub_join_url=flask.url_for('hub_join', hub=widget.hub.name),

From c0b3bac1c2d494820a17d7b2f5687342ffff7ea4 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 08 2015 01:39:58 +0000
Subject: [PATCH 177/1001] Consistent sort.


---

diff --git a/hubs/models.py b/hubs/models.py
index ef97536..205a40f 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -24,6 +24,7 @@
 import datetime
 import json
 import logging
+import operator
 
 import sqlalchemy as sa
 from sqlalchemy import create_engine
@@ -300,7 +301,7 @@ class User(BASE):
         return sorted(list(set([assoc.hub for assoc in self.associations
                 if assoc.role == 'member'
                 or assoc.role == 'subscriber'
-                or assoc.role == 'owner'])))
+                or assoc.role == 'owner'])), key=operator.attrgetter('name'))
 
     @property
     def username(self):

From 4f6dace9df4ac8bd85697a85428795400483b464 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 08 2015 18:44:20 +0000
Subject: [PATCH 178/1001] login avatar dropdown


---

diff --git a/hubs/app.py b/hubs/app.py
index 877991c..02d481b 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -13,6 +13,7 @@ import hubs.models
 
 import datanommer.models
 
+from hubs.utils import username2avatar
 
 app = flask.Flask(__name__)
 
@@ -207,6 +208,7 @@ def check_auth():
         flask.g.auth.fullname = flask.session.get('fullname', None)
         flask.g.auth.nickname = flask.session.get('nickname', None)
         flask.g.auth.email = flask.session.get('email', None)
+        flask.g.auth.avatar = username2avatar(flask.g.auth.nickname)
 
 
 def get_hub(session, name):
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 7ce693b..88a95b8 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -23,6 +23,11 @@
       font-size: 18px;
     }
 
+    .super-header .dropdown .dropdown-header {
+      font-weight: 700;
+      font-size: 16px;
+    }
+
     #logo { text-align: left; }
 
     .bookmarks .navbar.navbar-default {
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index d830fc8..ccb2cde 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -14,16 +14,16 @@
 	<div class="col-md-4 col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
     <div class="col-md-2 col-md-offset-6 col-xs-8">
       {% if g.auth.logged_in %}
-        <div class="dropdown">
+        <div class="dropdown pull-right">
         <span class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
-          <img src="{{hub.avatar}}" class="avatar" alt="User Icon"/>
+          <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
           {# Logged in as #} {{ g.auth.nickname }}
           <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
         </span>
         <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
           <li class="dropdown-header">Account Information</li>
-          <li><a href="#">Full Name: {{hub.summary}}</a></li>
-          <li><a href="#">Email: blah</a></li>
+          <li><a href="#">Full Name: {{ g.auth.fullname }}</a></li>
+          <li><a href="#">Email: {{ g.auth.email }}</a></li>
           <li role="separator" class="divider"></li>
           <li><a href="#">Separated link</a></li>
         </ul>

From 0c5a6a2c6cd25cbc910cb02d80523d1ce1e113ed Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 09 2015 14:30:23 +0000
Subject: [PATCH 179/1001] mobile nav styles


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 88a95b8..74920ec 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -31,6 +31,7 @@
     #logo { text-align: left; }
 
     .bookmarks .navbar.navbar-default {
+      font-family: 'Open Sans', sans-serif;
       background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
       background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
       background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
@@ -53,6 +54,14 @@
       border-bottom: 3px solid #3c6eb4;
     }
 
+    @media (max-width:768px) {
+      .bookmarks .nav > .active > a, .bookmarks .nav > .active > a:hover {
+        border-bottom: none;
+        color: #3C6EB4;
+        font-weight: 700;
+      }
+    }
+
     .header {
       color: #ffffff;
       background-color: #3c6eb4;
@@ -120,6 +129,10 @@
     font-weight: 700;
 }
 
+.widget {
+  font-family: 'Open Sans', sans-serif;
+}
+
 /* flexbox support */
 .flex-container {
     display: flex;

From 2198a9f70f53b8275da0b9e3a0d40f9cda39f3a9 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 09 2015 17:16:01 +0000
Subject: [PATCH 180/1001] rules widget styles


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 74920ec..7f7526c 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -22,7 +22,9 @@
       margin: 5px 0 0 10px;
       font-size: 18px;
     }
-
+    .super-header .dropdown {
+      border-radius: 0;
+    }
     .super-header .dropdown .dropdown-header {
       font-weight: 700;
       font-size: 16px;
@@ -133,6 +135,26 @@
   font-family: 'Open Sans', sans-serif;
 }
 
+/* hub widgets */
+.rules-table {
+  width: 180px
+  padding: 0px;
+  margin: 0px;
+  display: inline-block;
+}
+.rules-table td {
+  font-size: 32pt;
+}
+.rules-container h6 {
+  font-family: 'Open Sans', sans-serif;
+  text-transform: uppercase;
+  font-size: 12px;
+  color: #797a7c;
+}
+
+.rules-container img {
+  margin-bottom: 15px;
+}
 /* flexbox support */
 .flex-container {
     display: flex;
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 3a1dd16..7afc67b 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -11,13 +11,17 @@ chrome = panel()
 template = jinja2.Template("""
 <div class="rules-container">
   {% if link %}
-  <p class="small-heading">community rules</p>
-  <p><a href="{{link}}">Community Rules and Guidelines</a></p>
+  <h6>community rules</h6>
+  <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
   {% endif %}
-  <p class="small-heading">group owners</p>
-  {% for owner in owners %}
-    <span><img class="img-circle" src="{{owners[owner]}}"/> {{owner}}</span>
-  {% endfor %}
+  <h6>group owners</h6>
+  <div class="row">
+    {% for owner in owners %}
+        <div class="col-sm-6">
+            <img class="img-circle" src="{{owners[owner]}}"/> {{owner}}
+        </div>
+    {% endfor %}
+  </div>
 </div>
 <style>
   .rules-table {
@@ -26,11 +30,6 @@ template = jinja2.Template("""
     margin: 0px;
     display: inline-block;
   }
-  .small-heading {
-    text-transform: uppercase;
-    font-size: 80%;
-    color: #797a7c;
-  }
   .rules-table td {
     font-size: 32pt;
   }

From c3cbdc63d5f2c589d3ee9f9a6253d87d41ce29b6 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 09 2015 17:43:30 +0000
Subject: [PATCH 181/1001] Update diagram.


---

diff --git a/docs/diagram.png b/docs/diagram.png
index c20d165..983c04d 100644
Binary files a/docs/diagram.png and b/docs/diagram.png differ
diff --git a/docs/diagram.txt b/docs/diagram.txt
index 0e665d7..a0d18b4 100644
--- a/docs/diagram.txt
+++ b/docs/diagram.txt
@@ -1,27 +1,38 @@
-                                                     push events to clients             +-------------------------+
-                                                     as they occur                      | web client              |
-                                            +------------------------------------------>| (built from HTML and JS |
-                                            |                                           | served by the wsgi app) |
-                                            |                                           +-------------------------+
-                                            |                                             ^                     |
-                                            |                                             |                     |
-                        +--+--------------------+---+                                     | initial page load   | configuration changes
-                        |  | EventSource server |   |     /-----------------------+       | and ajax requests   | to widgets and hubs
-                        |  |                    |   |     |{s} memcached          |       |                     |
-                        |  |                    |   |     |  (we store the data   |       |                     V
-                        |  +--------------------+   |     |  for widgets here     |     +--------------------------+
-                        |                           |     |  and rebuild it       |---->|                          |
-                        |                           |---->|  as necessary)        |<----|                          |
-                        | hubs backend              |     +-----------------------/     |  hubs wsgi app           |
-                        | (a fedmsg-hub daemon      |                                   |  (the frontend that      |
------------------------>| with a FedoraHubsConsumer |                                   |  serves what the users   |
-     ^  fedmsg          | plugin)                   |     +-----------------------+     |  see)                    |
-     |  (fas changes,   |                           |<----|{s} postgres           |<----|                          |
-     |  trac tickets,   |                           |     |  (we store the config |     +--------------------------+
-     |  etc...)         +---------------------------+     |  for widgets/hubs     |             |
-     |                                                    |  here)                |             |
-     |                                                    +-----------------------+             |
-     |                                                                                          |
-     |                                                                                          |
-     +------------------------------------------------------------------------------------------+
-                            config changes to hubs/widgets, via fedmsg
+
+                        +---------------+
+                        |               |   +--------------+
+                        | statscache    |   | {s} postgres |    +---------------+
+                        | (a fedmsg-hub |   | for holding  |    | statscache    |
+                     +->| daemon with   |-->| cached time  |--->| HTTP API      |-----------------------------------+
+                     |  | the statscache|   | series and   |    | serving stats |                                   |
+                     |  | consumer.     |   | other data   |    +---------------+                                   | serving ajax data for fancy
+                     |  |               |   +--------------+                                                        | js activity graphs
+                     |  +---------------+                                                                           |
+                     |                                                                                              V
+                     |                                                   push updated JSON                +-------------------------+
+                     |                                                   to clients asap                  | web client              |
+                     |                                          +---------------------------------------->| (built from HTML and JS |
+                     |                                          |                                         | served by the wsgi app) |
+                     |                                          |                                         +-------------------------+
+                     |                                          |                                           ^                     |
+                     |                                          |                                           |                     |
+                     |                               +--------------+                                       | initial page load   | configuration changes
+                     |                               | EventSource  |       /-----------------------+       | and ajax requests   | to widgets and hubs
+                     |                               | server       |<------|{s} redis              |       |                     |
+                     |                               +--------------+       |  (we store the data   |       |                     V
+                     |                                                      |  for widgets here     |     +--------------------------+
+                     |  +---------------+   /-----------+   +-----------+   |  and rebuild it       |---->|                          |
+                     |  |               |-->|{s} redis  |-->| N cache   |-->|  as necessary)        |<----|                          |
+                     |  | hubs backend  |   |task queue |-->| worker(s) |   +-----------------------/     |  hubs wsgi app           |
+                     |  | (a fedmsg-hub |   +-----------/   +-----------+                                 |  (the frontend that      |
+---------------------+->| daemon with a |                         ^                                       |  serves what the users   |
+     ^  fedmsg          | fedora-hubs   |                         |         +-----------------------+     |  see)                    |
+     |  (fas changes,   | consumer.     |                         +---------|{s} postgres           |<----|                          |
+     |  trac tickets,   |               |                                   |  (we store the config |     +--------------------------+
+     |  etc...)         +---------------+                                   |  for widgets/hubs     |             |
+     |                                                                      |  here)                |             |
+     |                                                                      +-----------------------+             |
+     |                                                                                                            |
+     |                                                                                                            |
+     +------------------------------------------------------------------------------------------------------------+
+                                   config changes to hubs/widgets, via fedmsg

From 34b46bee9714a6ae5d120258cfca155eb11e5382 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 09 2015 17:43:36 +0000
Subject: [PATCH 182/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 74920ec..7f7526c 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -22,7 +22,9 @@
       margin: 5px 0 0 10px;
       font-size: 18px;
     }
-
+    .super-header .dropdown {
+      border-radius: 0;
+    }
     .super-header .dropdown .dropdown-header {
       font-weight: 700;
       font-size: 16px;
@@ -133,6 +135,26 @@
   font-family: 'Open Sans', sans-serif;
 }
 
+/* hub widgets */
+.rules-table {
+  width: 180px
+  padding: 0px;
+  margin: 0px;
+  display: inline-block;
+}
+.rules-table td {
+  font-size: 32pt;
+}
+.rules-container h6 {
+  font-family: 'Open Sans', sans-serif;
+  text-transform: uppercase;
+  font-size: 12px;
+  color: #797a7c;
+}
+
+.rules-container img {
+  margin-bottom: 15px;
+}
 /* flexbox support */
 .flex-container {
     display: flex;
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 3a1dd16..7afc67b 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -11,13 +11,17 @@ chrome = panel()
 template = jinja2.Template("""
 <div class="rules-container">
   {% if link %}
-  <p class="small-heading">community rules</p>
-  <p><a href="{{link}}">Community Rules and Guidelines</a></p>
+  <h6>community rules</h6>
+  <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
   {% endif %}
-  <p class="small-heading">group owners</p>
-  {% for owner in owners %}
-    <span><img class="img-circle" src="{{owners[owner]}}"/> {{owner}}</span>
-  {% endfor %}
+  <h6>group owners</h6>
+  <div class="row">
+    {% for owner in owners %}
+        <div class="col-sm-6">
+            <img class="img-circle" src="{{owners[owner]}}"/> {{owner}}
+        </div>
+    {% endfor %}
+  </div>
 </div>
 <style>
   .rules-table {
@@ -26,11 +30,6 @@ template = jinja2.Template("""
     margin: 0px;
     display: inline-block;
   }
-  .small-heading {
-    text-transform: uppercase;
-    font-size: 80%;
-    color: #797a7c;
-  }
   .rules-table td {
     font-size: 32pt;
   }

From 2fffcaecf85da30367f9d87e8d8d19f558edcfac Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 09 2015 19:27:20 +0000
Subject: [PATCH 183/1001] Fix JSON repr for Hub objects.


---

diff --git a/hubs/models.py b/hubs/models.py
index 205a40f..99b2cb9 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -196,16 +196,14 @@ class Hub(BASE):
         return {
             'name': self.name,
             'summary': self.summary,
-
-            # TODO -- splash image
+            'avatar': self.avatar,
 
             'widgets': [widget.idx for widget in self.widgets],
             'left_width': self.left_width,
 
-            # TODO -- these three need to be fleshed out with real fas data.
-            'owners': self.owners,
-            'members': self.members,
-            'subscribers': self.subscribers,
+            'owners': [u.username for u in self.owners],
+            'members': [u.username for u in self.members],
+            'subscribers': [u.username for u in self.subscribers],
         }
 
 def _config_default(context):

From 7924219cb525293460efba3977538a0ab14c7366 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 09 2015 19:27:42 +0000
Subject: [PATCH 184/1001] Make users the owner of their own hub.


---

diff --git a/hubs/models.py b/hubs/models.py
index 99b2cb9..4c6eee2 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -162,6 +162,8 @@ class Hub(BASE):
         session.delete(association)
         session.commit()
 
+    def is_admin(self, user):
+        return user in self.owners
 
     @classmethod
     def by_name(cls, session, name):
@@ -174,8 +176,12 @@ class Hub(BASE):
         hub = cls(name=username, summary=fullname,
                   avatar=username2avatar(username))
         session.add(hub)
+
         hubs.defaults.add_user_widgets(session, hub, username, fullname)
 
+        user = User.by_username(session, username)
+        hub.subscribe(session, user, role='owner')
+
     @property
     def right_width(self):
         return 12 - self.left_width
@@ -296,10 +302,13 @@ class User(BASE):
     @property
     def bookmarks(self):
         # TODO -- someday make this editable/configurable.
-        return sorted(list(set([assoc.hub for assoc in self.associations
-                if assoc.role == 'member'
-                or assoc.role == 'subscriber'
-                or assoc.role == 'owner'])), key=operator.attrgetter('name'))
+        return sorted(list(set([
+            assoc.hub for assoc in self.associations
+            if assoc.role == 'member'
+            or assoc.role == 'subscriber'
+            or assoc.role == 'owner'
+            and assoc.hub.name != self.username
+        ])), key=operator.attrgetter('name'))
 
     @property
     def username(self):

From 080bc843f598ddeb2ac36a6a1842502d104128fe Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 09 2015 19:28:17 +0000
Subject: [PATCH 185/1001] Add an edit link to the top of each hub.


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 7f7526c..bd30bb4 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -80,6 +80,11 @@
     .header h3 {
         font-weight: 700;
     }
+
+    .header a, .header a:hover, .header a:focus {
+      color: #ffffff;
+    }
+
     .row {
       padding: 5px;
     }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index ccb2cde..79ef909 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -67,6 +67,9 @@
     <img src="{{hub.avatar}}" class="avatar" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
+    {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
+    <p><a href="edit"><span class="glyphicon glyphicon-edit"></span>edit this hub</a></p>
+    {% endif %}
     <div class="clearfix"></div>
   </div>
 </div>

From 53328edfaf3680c36b63ab40dbba1d32bf2193b9 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 09 2015 19:30:56 +0000
Subject: [PATCH 186/1001] Adjust some strings in populate.py.


---

diff --git a/populate.py b/populate.py
index 44699ac..d682889 100755
--- a/populate.py
+++ b/populate.py
@@ -23,7 +23,7 @@ for username in users:
 session.commit()
 
 ############## Internationalizationteam
-hub = hubs.models.Hub(name='Internationalizationteam', summary='The Fedora Internationalization Team')
+hub = hubs.models.Hub(name='i18n', summary='The Internationalization Team')
 session.add(hub)
 
 widget = hubs.models.Widget(plugin='stats', index=0)
@@ -62,7 +62,7 @@ hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproje
 session.commit()
 
 ############## Marketing team
-hub = hubs.models.Hub(name='marketingteam', summary='The Fedora Marketing Team')
+hub = hubs.models.Hub(name='marketing', summary='The Fedora Marketing Team')
 session.add(hub)
 
 widget = hubs.models.Widget(plugin='stats', index=0)
@@ -138,7 +138,7 @@ hub.widgets.append(widget)
 hub.subscribe(session, hubs.models.User.by_openid(session, 'duffy.id.fedoraproject.org'), 'owner')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch.id.fedoraproject.org'), 'owner')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'gnokii.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard.id.fedoraproject.org'), 'owner')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0.id.fedoraproject.org'), 'member')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
 hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
@@ -147,7 +147,7 @@ session.commit()
 
 
 ############## Infra team
-hub = hubs.models.Hub(name='infrastructure', summary='The Fedora Infrastructure Team')
+hub = hubs.models.Hub(name='infrastructure', summary='The Fedora Infra Team')
 session.add(hub)
 
 widget = hubs.models.Widget(plugin='stats', index=0)

From 51cfae882bc9a710d6a297c95a70383bc2bdf96e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 09 2015 20:27:39 +0000
Subject: [PATCH 187/1001] Stubbing out some stuff about editing hubs.


---

diff --git a/hubs/app.py b/hubs/app.py
index 02d481b..e7ed3c0 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -74,8 +74,8 @@ def index():
 @app.route('/<name>/')
 def hub(name):
     hub = get_hub(session, name)
-    return flask.render_template('hubs.html', hub=hub, session=session)
-
+    return flask.render_template(
+        'hubs.html', hub=hub, session=session, edit=False)
 
 @app.route('/<name>/json')
 @app.route('/<name>/json/')
@@ -86,11 +86,28 @@ def hub_json(name):
     return response
 
 
+@app.route('/<name>/edit', methods=['GET'])
+@app.route('/<name>/edit/', methods=['GET'])
+def hub_edit_get(name):
+    hub = get_hub(session, name)
+    return flask.render_template(
+        'hubs.html', hub=hub, session=session, edit=True)
+
+
+@app.route('/<name>/edit', methods=['POST'])
+@app.route('/<name>/edit/', methods=['POST'])
+def hub_edit_post(name):
+    #hub = get_hub(session, name)
+    # TODO -- save things to the db ... and then redirect
+    raise NotImplementedError('TODO - save changes to hub config')
+    flask.redirect(flask.url_for('hub', name=name))
+
+
 @app.route('/<hub>/<idx>')
 @app.route('/<hub>/<idx>/')
 def widget_render(hub, idx):
     widget = get_widget(session, hub, idx)
-    return widget.render(session)
+    return widget.render(session, edit=False)
 
 
 @app.route('/<hub>/<idx>/json')
@@ -102,6 +119,25 @@ def widget_json(hub, idx):
     return response
 
 
+@app.route('/<hub>/<idx>/edit', methods=['GET'])
+@app.route('/<hub>/<idx>/edit/', methods=['GET'])
+def widget_edit_get(hub, idx):
+    widget = get_widget(session, hub, idx)
+    raise NotImplementedError('next step is to get the widgets to render '
+                              'editable versions of themselves with their '
+                              'declared @arguments, etc...')
+    return widget.render(session, edit=True)
+
+
+@app.route('/<hub>/<idx>/edit', methods=['POST'])
+@app.route('/<hub>/<idx>/edit/', methods=['POST'])
+def widget_edit_post(hub, idx):
+    #widget = get_widget(session, hub, idx)
+    # TODO -- save things to the db ... and then redirect
+    raise NotImplementedError('TODO - save changes to widget config')
+    flask.redirect(flask.url_for('hub', name=hub))
+
+
 @app.route('/source/<name>')
 @app.route('/source/<name>/')
 def widget_source(name):
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 79ef909..680ed62 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -67,7 +67,7 @@
     <img src="{{hub.avatar}}" class="avatar" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
-    {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
+    {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
     <p><a href="edit"><span class="glyphicon glyphicon-edit"></span>edit this hub</a></p>
     {% endif %}
     <div class="clearfix"></div>
@@ -81,12 +81,32 @@
       {% for widget in hub.left_widgets %}
       <div id="widget-{{ widget.idx }}" class="row"></div>
       {% endfor %}
+
+      {% if edit %}
+      <div id='add-widget-left' class='widget row'>
+        <div class="panel panel-default panel-visible">
+          <div class="panel-body">
+            <h1><a href="#"><span class="glyphicon glyphicon-plus"></span> Add a widget</a></h1>
+          </div>
+        </div>
+      </div>
+      {% endif %}
     </div>
 
     <div class="col-md-{{ hub.right_width }}">
       {% for widget in hub.right_widgets %}
       <div id="widget-{{ widget.idx }}" class="widget row"></div>
       {% endfor %}
+
+      {% if edit %}
+      <div id='add-widget-right' class='widget row'>
+        <div class="panel panel-default panel-visible">
+          <div class="panel-body">
+            <h1><a href="#"><span class="glyphicon glyphicon-plus"></span> Add a widget</a></h1>
+          </div>
+        </div>
+      </div>
+      {% endif %}
     </div>
   </div>
 </div>
@@ -97,7 +117,11 @@
 var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
 $.each(widgets, function(i, widget) {
     $.ajax({
+      {% if edit %}
+      url: widget + '/edit/',
+      {% else %}
       url: widget,
+      {% endif %}
       dataType: 'html',
       success: function(html) {
         $('#widget-' + widget).html(html);

From 48f4f5d39d72b4b75d6638bbd94cc3531b6142cd Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 10 2015 20:26:26 +0000
Subject: [PATCH 188/1001] assorted small things


---

diff --git a/hubs/app.py b/hubs/app.py
index e7ed3c0..05794ba 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -107,7 +107,8 @@ def hub_edit_post(name):
 @app.route('/<hub>/<idx>/')
 def widget_render(hub, idx):
     widget = get_widget(session, hub, idx)
-    return widget.render(session, edit=False)
+    return widget.render(session)#, edit=False)
+    #was blocking all widgets from working, sorry!
 
 
 @app.route('/<hub>/<idx>/json')
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index bd30bb4..6973e2a 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -56,6 +56,13 @@
       border-bottom: 3px solid #3c6eb4;
     }
 
+    .navbar-default .navbar-toggle {
+      border: none;
+    }
+
+    .navbar-default .navbar-toggle:focus {
+      background-color: none;
+    }
     @media (max-width:768px) {
       .bookmarks .nav > .active > a, .bookmarks .nav > .active > a:hover {
         border-bottom: none;
@@ -167,6 +174,10 @@
     flex-wrap: wrap;
 }
 
+.stats-container button {
+  margin: 20px 0 0 0;
+}
+
 .stats-table {
 width: 180px
 padding: 0px;
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index f37819f..4b0df3a 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -14,11 +14,11 @@ chrome = panel('Hubs', key='associations')
 template = jinja2.Template("""
 {% if associations %}
     {% if memberships %}
-        <p>Belongs to: {{memberships_text}}</p>
+        <p><strong>Belongs to: </strong>{{memberships_text}}</p>
     {% endif %}
     <hr/>
     {% if subscriptions %}
-        <p>Subscribes to: {{subscriptions_text}}</p>
+        <p><strong>Subscribes to:</strong> {{subscriptions_text}}</p>
     {% endif %}
 {% endif %}
 """)

From 2c529fec62342dd68580c415ec2b3f5837cd7bb2 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 13 2015 21:06:48 +0000
Subject: [PATCH 189/1001] edit styles


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 6973e2a..2381c4f 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -167,6 +167,11 @@
 .rules-container img {
   margin-bottom: 15px;
 }
+
+#add-widget-left h4 a, #add-widget-right h4 a {
+  color: #60605b;
+}
+
 /* flexbox support */
 .flex-container {
     display: flex;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 680ed62..d62f2d7 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -86,7 +86,7 @@
       <div id='add-widget-left' class='widget row'>
         <div class="panel panel-default panel-visible">
           <div class="panel-body">
-            <h1><a href="#"><span class="glyphicon glyphicon-plus"></span> Add a widget</a></h1>
+            <h4><a href="#"><span class="glyphicon glyphicon-plus"></span> Add a widget</a></h4>
           </div>
         </div>
       </div>
@@ -102,7 +102,7 @@
       <div id='add-widget-right' class='widget row'>
         <div class="panel panel-default panel-visible">
           <div class="panel-body">
-            <h1><a href="#"><span class="glyphicon glyphicon-plus"></span> Add a widget</a></h1>
+            <h4><a href="#"><span class="glyphicon glyphicon-plus"></span> Add a widget</a></h4>
           </div>
         </div>
       </div>

From e1b6752c0668e363491e7e1891f80817c1fad2c9 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 14 2015 15:05:56 +0000
Subject: [PATCH 190/1001] stats icons and responsive


---

diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 505d88b..b81a2cd 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -13,14 +13,18 @@ config = fedmsg.config.load_config()
 
 chrome = panel()
 template = jinja2.Template("""
-<div class="stats-container">
+<div class="stats-container row">
+  <div class="col-sm-7 col-md-12 col-lg-7">
   <table class="stats-table">
     <tr><th>FedMsgs</th><th>Subscribers</th></tr>
     <tr class="text-info"><td>{{fedmsgs_text}}</td><td class="text-right">{{subscribers_text}}</td></tr>
   </table>
+  </div>
+  <div class="col-sm-5 col-md-12 col-lg-5">
   {% if session['nickname'] != username %}
   <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
   {% endif %}
+  </div>
 </div>
 """)
 
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 0e4a274..3523e84 100644
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -23,7 +23,7 @@ template = jinja2.Template("""
   </form></li>
   {% else %}
   <li><form action="{{hub_subscribe_url}}" method="POST">
-      <button class="btn btn-default"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Subscribe</button>
+      <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
   </form></li>
   {% endif %}
 
@@ -33,7 +33,7 @@ template = jinja2.Template("""
   </form></li>
   {% else %}
   <li><form action="{{hub_star_url}}" method="POST">
-      <button class="btn btn-default"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Star Hub</button>
+      <button class="btn btn-default"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Star Hub</button>
   </form></li>
   {% endif %}
 
@@ -43,7 +43,7 @@ template = jinja2.Template("""
   </form></li>
   {% else %}
   <li><form action="{{hub_join_url}}" method="POST">
-      <button class="btn btn-default"><span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> Join Hub</button>
+      <button class="btn btn-default"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Join Hub</button>
   </form></li>
   {% endif %}
   </ul>

From 00d4bd585cd592965c81e101531f766ed8ae9b3b Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 14 2015 20:36:00 +0000
Subject: [PATCH 191/1001] search bar styles


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 2381c4f..ca82675 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -30,6 +30,27 @@
       font-size: 16px;
     }
 
+    .super-header input {
+      width: 100%;
+      border-radius: 0;
+      font-family: 'Open Sans', sans-serif;
+      padding: 5px;
+      border: 1px solid #d1d3d4;
+    }
+
+    .super-header .input-group-addon {
+      background-color: #3C6EB4;
+      color: #fff;
+      border: 0;
+      border-radius: 0;
+    }
+
+    @media (max-width: 768px) {
+      .super-header .input-group {
+        margin-top: 20px;
+      }
+    }
+
     #logo { text-align: left; }
 
     .bookmarks .navbar.navbar-default {
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index d62f2d7..fb0f390 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -11,8 +11,8 @@
 <body>
 <div class="super-header">
   <div class="row">
-	<div class="col-md-4 col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
-    <div class="col-md-2 col-md-offset-6 col-xs-8">
+	  <div class="col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
+    <div class="col-sm-4 col-sm-push-4 col-xs-8">
       {% if g.auth.logged_in %}
         <div class="dropdown pull-right">
         <span class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
@@ -32,6 +32,15 @@
         Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
       {% endif %}
     </div>
+    <div class="col-sm-4 col-sm-pull-4 col-xs-12">
+      <!-- NOT HOOKED UP TO ANYTHING XOXO -->
+      <div class="input-group">
+        <input type="search" placeholder="Search across all hubs ..."></input>
+        <span class="input-group-addon">
+          <span class="glyphicon glyphicon-search"></span>
+        </span>
+    </div>
+    </div>
   </div>
 </div>
 <div class="bookmarks">

From c44a741c0d435db2f59e6ab664abf79275f90ebf Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 16 2015 17:06:07 +0000
Subject: [PATCH 192/1001] move edit link


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index ca82675..5185d09 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -113,6 +113,9 @@
       color: #ffffff;
     }
 
+    .header span.edit {
+      margin: 5px 5px 0 0;
+    }
     .row {
       padding: 5px;
     }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index fb0f390..cc45378 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -72,13 +72,13 @@
   </nav>
 </div>
 <div class="header">
+  {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
+    <span class="edit pull-right"><a href="edit"><span class="glyphicon glyphicon-edit"></span> edit this hub</a></span>
+  {% endif %}
   <div class="padded center-block medium-wide">
     <img src="{{hub.avatar}}" class="avatar" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
-    {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
-    <p><a href="edit"><span class="glyphicon glyphicon-edit"></span>edit this hub</a></p>
-    {% endif %}
     <div class="clearfix"></div>
   </div>
 </div>

From cfe0fa54e1d36238ca910cd96628f0c33025a555 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 14:55:03 +0000
Subject: [PATCH 193/1001] Add a section on how to create a new widget.


---

diff --git a/README.rst b/README.rst
index 3399529..f07a965 100644
--- a/README.rst
+++ b/README.rst
@@ -139,8 +139,8 @@ that *should* show up on your feed.. they should appear there.  (At very least,
 you shouldn't get an error message about that widget being unable to be
 displayed).
 
-Internal design
-===============
+Stubbing out a new Widget
+=========================
 
 You write a new widget in the ``hubs/widgets/`` directory and must declare it
 in the registry dict in ``hubs/widgets/__init__.py``.
@@ -158,7 +158,18 @@ In order to be valid, a widget must have:
   True if the lookup value should be nuked/refreshed in memcached (or some
   other store).
 
-Furthermore, a proposal:
+If you want to try making a new widget:
+
+- Copy an existing one in ``hubs/widgets/``
+- Add it to the registry in ``hubs/widgets/__init__.py``
+- If you want it to show up on a **user** page, add it to ``hubs/defaults.py``
+  in the ``add_user_widgets`` function.
+- If you want it to show up on **group** pages, add it to ``populate.py``.
+
+Destroy your database, rebuild it, and re-run the app.  Your widget should show up.
+
+A proposal, client-side templates
+=================================
 
 - The template per-widget is currently held and rendered *server-side* with
   jinja2.  This is how all our apps do it, more or less.

From b62b197a14693edd39527b9431e15036beabe2d2 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 15:10:13 +0000
Subject: [PATCH 194/1001] Fix updates workflow widget on chromium.


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 59860a7..49b54e2 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -20,12 +20,12 @@ template = jinja2.Template("""
     <li class="media">
         <div class="media-left">
             <a href="{{update['link']}}" target="_blank">
-                <img class="media-object img-responsive square-32" src="{{update['icon']}}"/>
+                <img class="media-object square-32" src="{{update['icon']}}"/>
             </a>
         </div>
         <div class="media-body">
             <h4 class="media-heading">{{update['title']}} (karma {{update['karma']}})</h4>
-            ready for love
+            can be pushed to stable
         </div>
     </li>
 {% endfor %}

From 07f37381fd0bed852a38ff0090a0254f6c5c4db6 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 15:22:37 +0000
Subject: [PATCH 195/1001] Gray out hub links based on mocked inactivity.


---

diff --git a/hubs/models.py b/hubs/models.py
index 4c6eee2..2808b73 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -124,6 +124,29 @@ class Hub(BASE):
     #fas_group = sa.Column(sa.String(32), nullable=False)
 
     @property
+    def days_idle(self):
+        # TODO -- implement calculating time since this hub was active
+        import random
+        return random.randint(0, 356)
+
+    @property
+    def activity_class(self):
+        idle = self.days_idle
+        limits = [
+            (356 * 5,   '5years'),
+            (356 * 2,   '2years'),
+            (356,       'year'),
+            (31 * 3,    'quarter'),
+            (31,        'month'),
+            (7,         'week'),
+            (1,         'day'),
+            (0,         'none'),
+        ]
+        for limit, name in limits:
+            if idle > limit:
+                return name
+
+    @property
     def owners(self):
         return [assoc.user for assoc in self.associations
                 if assoc.role == 'owner']
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 5185d09..ad7f8c9 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -227,3 +227,12 @@ font-size: 32pt;
     width: 32px;
     height: 32px;
 }
+
+.navbar-nav > li.idle-none    > a { }
+.navbar-nav > li.idle-day     > a { }
+.navbar-nav > li.idle-week    > a { }
+.navbar-nav > li.idle-month   > a { color: #888; }
+.navbar-nav > li.idle-quarter > a { color: #999; }
+.navbar-nav > li.idle-year    > a { color: #AAA; }
+.navbar-nav > li.idle-2years  > a { color: #BBB; }
+.navbar-nav > li.idle-5years  > a { color: #CCC; }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index cc45378..f713641 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -62,7 +62,7 @@
           <li {% if request.path.endswith('/' + g.auth.user.username + '/') %}class='active'{% endif %}>
             <a href="/{{g.auth.user.username}}">me</a></li>
           {% for hub in g.auth.user.bookmarks %}
-          <li {% if request.path.endswith('/' + hub.name + '/') %}class='active'{% endif %}>
+          <li class='idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
           <a href="/{{hub.name}}">{{hub.name}}</a></li>
           {% endfor %}
           {% endif %}

From c92b857adb5d94a531e4a9ac6942f3a91ab4bea0 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 16:17:39 +0000
Subject: [PATCH 196/1001] Start a cobwebs widget.


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index b644707..06a3b79 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -9,6 +9,7 @@ from hubs.widgets import fedmsgs
 from hubs.widgets import fedmsgstats
 from hubs.widgets import feed
 from hubs.widgets import subscriptions
+from hubs.widgets import cobwebs
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -27,6 +28,7 @@ registry = {
     'fedmsgstats': fedmsgstats,
     'feed': feed,
     'subscriptions': subscriptions,
+    'cobwebs': cobwebs,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
new file mode 100644
index 0000000..d6684b2
--- /dev/null
+++ b/hubs/widgets/cobwebs.py
@@ -0,0 +1,36 @@
+from hubs.hinting import hint, prefixed as _
+
+import arrow
+import datetime
+import jinja2
+
+from hubs.widgets.chrome import panel
+chrome = panel(None, key='old', klass='panel-info')
+
+template = jinja2.Template("""
+{% if old %}
+<ul class="media-list">
+    <li class="media">
+        <div class="media-left">
+            <img class="media-object square-32" src="http://placekitten.com/g/32/32"/>
+        </div>
+        <div class="media-body">
+            Cobweb alert!  This hub was last active {{then}}.
+        </div>
+    </li>
+</ul>
+{% endif %}
+""")
+
+
+def data(session, widget):
+    days = widget.hub.days_idle
+    old = days > 31
+    then = datetime.datetime.utcnow() - datetime.timedelta(days=days)
+    then = arrow.get(then).humanize()
+    return dict(old=old, days=days, then=then)
+
+
+#@hint(topics=[_('hubs.widget.update')])
+def should_invalidate(message, session, widget):
+    raise NotImplementedError()
diff --git a/populate.py b/populate.py
index d682889..5b4f7a2 100755
--- a/populate.py
+++ b/populate.py
@@ -44,12 +44,14 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "<p>The Fedora I18N project works on internationalization (i18n) to support the localization (l10n) of Fedora in many languages. Translation of Fedora software and documentation are handled by the Fedora L10N project.</p> <p>The goals of the Project are to:</p> <ul><li>Develop, package, and maintain applications like input methods for different languages</li> <li>Improve applications and utilities to support and process different languages</li> <li>Quality-assure that existing applications meet i18n standards</li> <li>Support the infrastructure of the Fedora Localization Project</li></ul>",
                             }))
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
+widget = hubs.models.Widget(plugin='dummy', index=2, left=True)
 hub.widgets.append(widget)
 
 
@@ -83,12 +85,14 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "The Fedora Marketing Team develops and executes marketing strategies to promote the usage and support of Fedora worldwide. Through the development of processes and content, this project aims to support the efforts of other Fedora projects to spread Fedora and to provide a central repository of ideas and information that can be used to deliver Fedora to new audiences. We work closely with the Fedora Ambassadors who spread the word about Fedora at events and allow the Fedora Project to interact directly with its existing and prospective users. ",
                             }))
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
+widget = hubs.models.Widget(plugin='dummy', index=2, left=True)
 hub.widgets.append(widget)
 
 
@@ -125,12 +129,14 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "The Design Team is the design group of the Fedora project. Our interests are not only in creating graphics for use by the Fedora community, but also in advocating the use of the creative tools that are a part of Fedora.",
                             }))
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
+widget = hubs.models.Widget(plugin='dummy', index=2, left=True)
 hub.widgets.append(widget)
 
 
@@ -168,12 +174,14 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='sticky', index=0, left=True,
+widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='sticky', index=2, left=True,
                             _config=json.dumps({
                                 'text': "The Infrastructure Team consists of dedicated volunteers and professionals managing the servers, building the tools and utilities, and creating new applications to make Fedora development a smoother process. We're located all over the globe and communicate primarily by IRC and e-mail. ",
                             }))
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='dummy', index=1, left=True)
+widget = hubs.models.Widget(plugin='dummy', index=3, left=True)
 hub.widgets.append(widget)
 
 

From c5840bef4f66cf6c64a75c2bfd5c065e84bdba50 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 16:37:43 +0000
Subject: [PATCH 197/1001] cobwebs!


---

diff --git a/hubs/static/img/cobweb.png b/hubs/static/img/cobweb.png
new file mode 100644
index 0000000..4d94b12
Binary files /dev/null and b/hubs/static/img/cobweb.png differ
diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index d6684b2..ff1ebd5 100644
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -12,7 +12,7 @@ template = jinja2.Template("""
 <ul class="media-list">
     <li class="media">
         <div class="media-left">
-            <img class="media-object square-32" src="http://placekitten.com/g/32/32"/>
+            <img class="media-object square-32" src="{{cobweb_icon}}"/>
         </div>
         <div class="media-body">
             Cobweb alert!  This hub was last active {{then}}.
@@ -28,7 +28,9 @@ def data(session, widget):
     old = days > 31
     then = datetime.datetime.utcnow() - datetime.timedelta(days=days)
     then = arrow.get(then).humanize()
-    return dict(old=old, days=days, then=then)
+    import flask
+    cobweb_icon = flask.url_for('static', filename='img/cobweb.png')
+    return dict(old=old, days=days, then=then, cobweb_icon=cobweb_icon)
 
 
 #@hint(topics=[_('hubs.widget.update')])

From 4b1d9b5ea622130f9646b92ceef55f7173b12ff9 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 17:31:30 +0000
Subject: [PATCH 198/1001] Stub out some of locking/archiving hubs.


---

diff --git a/hubs/models.py b/hubs/models.py
index 2808b73..4045200 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -117,6 +117,8 @@ class Hub(BASE):
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     widgets = relation('Widget', backref=backref('hub'))
     left_width = sa.Column(sa.Integer, nullable=False, default=8)
+    archived = sa.Column(sa.Boolean, default=False)
+    user_hub = sa.Column(sa.Boolean, default=False)
 
     # A URL to the "avatar" for this hub.
     avatar = sa.Column(sa.String(256), default=placekitten)
@@ -197,7 +199,8 @@ class Hub(BASE):
     @classmethod
     def create_user_hub(cls, session, username, fullname):
         hub = cls(name=username, summary=fullname,
-                  avatar=username2avatar(username))
+                  avatar=username2avatar(username),
+                  user_hub=True)
         session.add(hub)
 
         hubs.defaults.add_user_widgets(session, hub, username, fullname)
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f713641..83cdcde 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -73,7 +73,22 @@
 </div>
 <div class="header">
   {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
-    <span class="edit pull-right"><a href="edit"><span class="glyphicon glyphicon-edit"></span> edit this hub</a></span>
+    <div class="dropdown pull-right">
+      <span class="dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+        <span class="glyphicon glyphicon-edit"></span> edit this page
+      </span>
+      <ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
+        <li><a href="#">Customize Header</a></li>
+        <li role="separator" class="divider"></li>
+        <li><a href="#">Configure Widgets</a></li>
+        {% if not hub.user_hub %}
+        <li role="separator" class="divider"></li>
+        <li><a href="#">Manage Members</a></li>
+        <li role="separator" class="divider"></li>
+        <li><a href="#">Archive Hub</a></li>
+        {% endif %}
+      </ul>
+    </div>
   {% endif %}
   <div class="padded center-block medium-wide">
     <img src="{{hub.avatar}}" class="avatar" />

From b44ee1c77517dd750ff26c846a430e4b30ba7075 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 17:44:30 +0000
Subject: [PATCH 199/1001] Show archived status in the cobweb widget.


---

diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index ff1ebd5..6f16810 100644
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -12,10 +12,14 @@ template = jinja2.Template("""
 <ul class="media-list">
     <li class="media">
         <div class="media-left">
-            <img class="media-object square-32" src="{{cobweb_icon}}"/>
+            <img class="media-object square-32" src="{{icon}}"/>
         </div>
         <div class="media-body">
+        {% if archived %}
+            This hub has been archived and locked.
+        {% else %}
             Cobweb alert!  This hub was last active {{then}}.
+        {% endif %}
         </div>
     </li>
 </ul>
@@ -25,12 +29,16 @@ template = jinja2.Template("""
 
 def data(session, widget):
     days = widget.hub.days_idle
-    old = days > 31
+    archived = widget.hub.archived
+    old = days > 31 or archived
     then = datetime.datetime.utcnow() - datetime.timedelta(days=days)
     then = arrow.get(then).humanize()
     import flask
-    cobweb_icon = flask.url_for('static', filename='img/cobweb.png')
-    return dict(old=old, days=days, then=then, cobweb_icon=cobweb_icon)
+    if archived:
+        icon = flask.url_for('static', filename='img/archived.png')
+    else:
+        icon = flask.url_for('static', filename='img/cobweb.png')
+    return dict(old=old, days=days, then=then, icon=icon, archived=archived)
 
 
 #@hint(topics=[_('hubs.widget.update')])

From 5db5bd0046ebcd5573668a02458304d3896a3679 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 31 2015 17:48:29 +0000
Subject: [PATCH 200/1001] purple red ified panels


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index ad7f8c9..63fefd9 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -155,6 +155,38 @@
       max-height: 100%;
     }
 
+    .panel-info, .panel-info .panel-heading {
+      background-color: #a07cbc;
+      font-family: 'Open Sans', sans-serif;
+      color: #fff;
+      border: 0;
+    }
+
+    .panel-info .panel-heading h3 {
+      font-weight: 700;
+      font-size: 16px;
+    }
+
+    .panel-info .widget-buttons a {
+      color: #fff;
+    }
+
+    .panel-danger, .panel-danger .panel-heading {
+      background-color: #bd0b0b;
+      font-family: 'Open Sans', sans-serif;
+      color: #fff;
+      border: 0;
+    }
+
+    .panel-danger .panel-heading h3 {
+      font-weight: 700;
+      font-size: 16px;
+    }
+
+    .panel-info .widget-buttons a {
+      color: #fff;
+    }
+
 /* generic widget styling */
 .widget .panel-default > .panel-heading {
     font-family: 'Open Sans', 'sans-serif';

From 6565360faece08876e01b151eae94632e98523fe Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 31 2015 17:48:46 +0000
Subject: [PATCH 201/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/hubs/models.py b/hubs/models.py
index 2808b73..4045200 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -117,6 +117,8 @@ class Hub(BASE):
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     widgets = relation('Widget', backref=backref('hub'))
     left_width = sa.Column(sa.Integer, nullable=False, default=8)
+    archived = sa.Column(sa.Boolean, default=False)
+    user_hub = sa.Column(sa.Boolean, default=False)
 
     # A URL to the "avatar" for this hub.
     avatar = sa.Column(sa.String(256), default=placekitten)
@@ -197,7 +199,8 @@ class Hub(BASE):
     @classmethod
     def create_user_hub(cls, session, username, fullname):
         hub = cls(name=username, summary=fullname,
-                  avatar=username2avatar(username))
+                  avatar=username2avatar(username),
+                  user_hub=True)
         session.add(hub)
 
         hubs.defaults.add_user_widgets(session, hub, username, fullname)
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f713641..83cdcde 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -73,7 +73,22 @@
 </div>
 <div class="header">
   {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
-    <span class="edit pull-right"><a href="edit"><span class="glyphicon glyphicon-edit"></span> edit this hub</a></span>
+    <div class="dropdown pull-right">
+      <span class="dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+        <span class="glyphicon glyphicon-edit"></span> edit this page
+      </span>
+      <ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
+        <li><a href="#">Customize Header</a></li>
+        <li role="separator" class="divider"></li>
+        <li><a href="#">Configure Widgets</a></li>
+        {% if not hub.user_hub %}
+        <li role="separator" class="divider"></li>
+        <li><a href="#">Manage Members</a></li>
+        <li role="separator" class="divider"></li>
+        <li><a href="#">Archive Hub</a></li>
+        {% endif %}
+      </ul>
+    </div>
   {% endif %}
   <div class="padded center-block medium-wide">
     <img src="{{hub.avatar}}" class="avatar" />
diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index ff1ebd5..6f16810 100644
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -12,10 +12,14 @@ template = jinja2.Template("""
 <ul class="media-list">
     <li class="media">
         <div class="media-left">
-            <img class="media-object square-32" src="{{cobweb_icon}}"/>
+            <img class="media-object square-32" src="{{icon}}"/>
         </div>
         <div class="media-body">
+        {% if archived %}
+            This hub has been archived and locked.
+        {% else %}
             Cobweb alert!  This hub was last active {{then}}.
+        {% endif %}
         </div>
     </li>
 </ul>
@@ -25,12 +29,16 @@ template = jinja2.Template("""
 
 def data(session, widget):
     days = widget.hub.days_idle
-    old = days > 31
+    archived = widget.hub.archived
+    old = days > 31 or archived
     then = datetime.datetime.utcnow() - datetime.timedelta(days=days)
     then = arrow.get(then).humanize()
     import flask
-    cobweb_icon = flask.url_for('static', filename='img/cobweb.png')
-    return dict(old=old, days=days, then=then, cobweb_icon=cobweb_icon)
+    if archived:
+        icon = flask.url_for('static', filename='img/archived.png')
+    else:
+        icon = flask.url_for('static', filename='img/cobweb.png')
+    return dict(old=old, days=days, then=then, icon=icon, archived=archived)
 
 
 #@hint(topics=[_('hubs.widget.update')])

From 740157724799686d9286d2f6b2b0f647e730cb4f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 17:57:27 +0000
Subject: [PATCH 202/1001] Set .panel-danger if archived.


---

diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 6a313aa..7dd7a96 100644
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -39,7 +39,7 @@ def panel(title=None, klass="panel-default", key=None):
             return _panel_template.render(
                 content=content,
                 heading=heading,
-                klass=klass,
+                klass=klass(kwargs) if callable(klass) else klass,
                 **kwargs)
         return inner
     return decorator
diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index 6f16810..2d5258a 100644
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -5,7 +5,8 @@ import datetime
 import jinja2
 
 from hubs.widgets.chrome import panel
-chrome = panel(None, key='old', klass='panel-info')
+klass_switcher = lambda data: 'panel-danger' if data['archived'] else 'panel-info'
+chrome = panel(None, key='old', klass=klass_switcher)
 
 template = jinja2.Template("""
 {% if old %}
diff --git a/populate.py b/populate.py
index 5b4f7a2..a23dfe7 100755
--- a/populate.py
+++ b/populate.py
@@ -23,7 +23,7 @@ for username in users:
 session.commit()
 
 ############## Internationalizationteam
-hub = hubs.models.Hub(name='i18n', summary='The Internationalization Team')
+hub = hubs.models.Hub(name='i18n', summary='The Internationalization Team', archived=True)
 session.add(hub)
 
 widget = hubs.models.Widget(plugin='stats', index=0)

From 34d9be4462212f0d27b369cf153bfbd3a4c95308 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 18:03:06 +0000
Subject: [PATCH 203/1001] Import the lock/archived icon.


---

diff --git a/hubs/static/img/archived.png b/hubs/static/img/archived.png
new file mode 100644
index 0000000..0084328
Binary files /dev/null and b/hubs/static/img/archived.png differ

From bee4c97f1d44f266aa592e2d1fed0583ec022e03 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 18:10:37 +0000
Subject: [PATCH 204/1001] Conditionalize user avatar.


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 83cdcde..87081fd 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -91,10 +91,14 @@
     </div>
   {% endif %}
   <div class="padded center-block medium-wide">
+    {% if hub.user_hub %}
     <img src="{{hub.avatar}}" class="avatar" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
     <div class="clearfix"></div>
+    {% else %}
+    TODO - put max-height overflow:hidden placekitten here...
+    {% endif %}
   </div>
 </div>
 <div class="container">

From 012e35ce295ee691ce9b260c171d2a21e63c4975 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 18:33:09 +0000
Subject: [PATCH 205/1001] Link to meeting minutes.


---

diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 7afc67b..2ec97f4 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -22,6 +22,23 @@ template = jinja2.Template("""
         </div>
     {% endfor %}
   </div>
+  {% if schedule_text or schedule_link or minutes_link %}
+  <div class="row">
+  <h6>meetings</h6>
+  {% if schedule_text %}
+  <p>{{schedule_text}}</p>
+  {% endif %}
+  {% if schedule_link %}
+  <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
+  {% endif %}
+  {% if schedule_link and minutes_link %}
+  &#8214;
+  {% endif %}
+  {% if minutes_link %}
+  <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
+  {% endif %}
+  </div>
+  {% endif %}
 </div>
 <style>
   .rules-table {
@@ -39,10 +56,22 @@ template = jinja2.Template("""
 @argument(name='link', default=None,
           validator=validators.link,
           help="Link to the community rules and guidelines")
-def data(session, widget, link):
+@argument(name='schedule_text', default=None,
+          validator=validators.text,
+          help="Some text about when meetings are")
+@argument(name='schedule_link', default=None,
+          validator=validators.link,
+          help="Link to a schedule for IRC meetings, etc..")
+@argument(name='minutes_link', default=None,
+          validator=validators.link,
+          help="Link to meeting minutes from past meetings..")
+def data(session, widget, link, schedule_text, schedule_link, minutes_link):
     owners = widget.hub.owners
     owners = ordereddict([(o.username, avatar(o.username)) for o in owners])
-    return dict(owners=owners, link=link)
+    return dict(owners=owners, link=link,
+                schedule_text=schedule_text,
+                schedule_link=schedule_link,
+                minutes_link=minutes_link)
 
 
 @hint(topics=[_('hubs.widget.update'), _('hubs.hub.update')])
diff --git a/populate.py b/populate.py
index a23dfe7..6cf905b 100755
--- a/populate.py
+++ b/populate.py
@@ -30,7 +30,10 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/I18N'
+                                'link': 'https://fedoraproject.org/wiki/I18N',
+                                'schedule_text': None,
+                                'schedule_link': None,
+                                'minutes_link': 'https://meetbot.fedoraproject.org/sresults/?group_id=i18n&type=team',
                             }))
 hub.widgets.append(widget)
 
@@ -71,7 +74,10 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/Marketing'
+                                'link': 'https://fedoraproject.org/wiki/Marketing',
+                                'schedule_text': None,
+                                'schedule_link': None,
+                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=fedora-mktg&type=channel',
                             }))
 hub.widgets.append(widget)
 
@@ -115,7 +121,10 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/Design'
+                                'link': 'https://fedoraproject.org/wiki/Design',
+                                'schedule_text': 'Meetings are every other Tuesday at 16:00 UTC',
+                                'schedule_link': 'https://apps.fedoraproject.org/calendar/design/',
+                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=fedora-design&type=channel',
                             }))
 hub.widgets.append(widget)
 
@@ -160,7 +169,10 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/Infrastructure'
+                                'link': 'https://fedoraproject.org/wiki/Infrastructure',
+                                'schedule_text': 'We meet weekly in #fedora-meeting at 18:00 UTC',
+                                'schedule_link': 'https://apps.fedoraproject.org/calendar/infrastructure/',
+                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=infrastructure&type=team',
                             }))
 hub.widgets.append(widget)
 

From e64a06714356743132ca3160775ebf03e9dc2412 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 18:53:50 +0000
Subject: [PATCH 206/1001] Whitespace management.


---

diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 2ec97f4..ce50aff 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -23,11 +23,11 @@ template = jinja2.Template("""
     {% endfor %}
   </div>
   {% if schedule_text or schedule_link or minutes_link %}
-  <div class="row">
   <h6>meetings</h6>
   {% if schedule_text %}
   <p>{{schedule_text}}</p>
   {% endif %}
+  <p>
   {% if schedule_link %}
   <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
   {% endif %}
@@ -37,7 +37,7 @@ template = jinja2.Template("""
   {% if minutes_link %}
   <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
   {% endif %}
-  </div>
+  </p>
   {% endif %}
 </div>
 <style>

From 741df347bcae1b5dc977d777628d3d7ed70dc29c Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jul 31 2015 19:35:32 +0000
Subject: [PATCH 207/1001] Meeting reminders!!


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 63fefd9..feceddf 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -260,6 +260,10 @@ font-size: 32pt;
     height: 32px;
 }
 
+.inline {
+    display: inline-block;
+}
+
 .navbar-nav > li.idle-none    > a { }
 .navbar-nav > li.idle-day     > a { }
 .navbar-nav > li.idle-week    > a { }
diff --git a/hubs/validators.py b/hubs/validators.py
index cd3d7f6..5bdf053 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -3,6 +3,9 @@ import kitchen.text.converters
 import hubs.models
 
 
+def required(session, value):
+    return bool(value)
+
 def text(session, value):
     return kitchen.text.converters.to_unicode(value)
 
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 06a3b79..d3ae5b5 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -10,6 +10,7 @@ from hubs.widgets import fedmsgstats
 from hubs.widgets import feed
 from hubs.widgets import subscriptions
 from hubs.widgets import cobwebs
+from hubs.widgets import meetings
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -29,6 +30,7 @@ registry = {
     'feed': feed,
     'subscriptions': subscriptions,
     'cobwebs': cobwebs,
+    'meetings': meetings,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
new file mode 100644
index 0000000..517ee92
--- /dev/null
+++ b/hubs/widgets/meetings.py
@@ -0,0 +1,74 @@
+#from hubs.hinting import hint, prefixed as _
+from hubs.widgets.base import argument
+from hubs.widgets.chrome import panel
+
+from hubs import validators
+
+import arrow
+import collections
+import datetime
+import jinja2
+import requests
+
+chrome = panel('Reminders', key='meetings')
+
+def next_meeting(meetings):
+    now = datetime.datetime.utcnow()
+    for meeting in meetings:
+        string = "%s %s" % (meeting['meeting_date'],
+                            meeting['meeting_time_start'])
+        dt = datetime.datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
+
+        if now < dt:
+            meeting['human_time'] = arrow.get(dt).humanize()
+            meeting['start_date'] = dt.strftime('%b %d')
+            # Just UTC for now until we do this on the client and can access
+            # their local with moment.js.
+            meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
+            meeting['location'] = meeting['meeting_location']
+            if '@' in meeting['location']:
+                meeting['location'] = '#' + meeting['location'].split('@')[0]
+            return meeting
+
+    return None
+
+jinja2_environment = jinja2.Environment()
+jinja2_environment.filters['next_meeting'] = next_meeting
+template = jinja2_environment.from_string("""
+{% if meetings %}
+    {% for title, items in meetings.items() %}
+        {% set next = items | next_meeting %}
+        {% if next %}
+        The {{ next.meeting_name }} is {{ next.human_time }}
+        <h1 class='inline'>{{next.start_date}}</h1>
+        <div class='inline'>
+            @{{next.start_time}}<br/>
+            {{next.location}}
+        </div>
+        {% endif %}
+        {% if meetings | length > 1 %}
+        <hr/>
+        {% endif %}
+    {% endfor %}
+{% endif %}
+""")
+
+
+@argument(name="calendar",
+          default=None,
+          validator=validators.required,
+          help="A fedocal calendar.")
+def data(session, widget, calendar):
+    base = 'https://apps.fedoraproject.org/calendar/api/meetings/?calendar=%s'
+    url = base % calendar
+    response = requests.get(url).json()
+
+    meetings = collections.defaultdict(list)
+    for meeting in response['meetings']:
+        meetings[meeting['meeting_name']].append(meeting)
+
+    return dict(meetings=dict(meetings))
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError()
diff --git a/populate.py b/populate.py
index 6cf905b..4bb1b21 100755
--- a/populate.py
+++ b/populate.py
@@ -37,7 +37,8 @@ widget = hubs.models.Widget(plugin='rules', index=1,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='dummy', index=2)
+widget = hubs.models.Widget(plugin='meetings', index=2,
+                            _config=json.dumps({'calendar': 'i18n'}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -81,7 +82,8 @@ widget = hubs.models.Widget(plugin='rules', index=1,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='dummy', index=2)
+widget = hubs.models.Widget(plugin='meetings', index=2,
+                            _config=json.dumps({'calendar': 'marketing'}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -128,7 +130,8 @@ widget = hubs.models.Widget(plugin='rules', index=1,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='dummy', index=2)
+widget = hubs.models.Widget(plugin='meetings', index=2,
+                            _config=json.dumps({'calendar': 'design'}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -176,7 +179,8 @@ widget = hubs.models.Widget(plugin='rules', index=1,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='dummy', index=2)
+widget = hubs.models.Widget(plugin='meetings', index=2,
+                            _config=json.dumps({'calendar': 'infrastructure'}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget

From 7669d9dbfedd8e1799987285c8574a69dc1a89ec Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 31 2015 20:19:48 +0000
Subject: [PATCH 208/1001] hub banner?


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 63fefd9..08a6e3b 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -90,6 +90,9 @@
         color: #3C6EB4;
         font-weight: 700;
       }
+      .header .medium-wide {
+        top: 150px !important;
+      }
     }
 
     .header {
@@ -98,6 +101,24 @@
       width: 100%;
       font-family: 'Open Sans', sans-serif;
     }
+
+    .header .img-wrap {
+      max-height: 100px;
+      overflow: hidden;
+      position: relative;
+    }
+
+    .header .img-wrap img {
+      width: 100%;
+      text-align: center;
+    }
+
+    .header .medium-wide {
+      position: absolute;
+      top: 100px;
+      left: 45%;
+    }
+
     .header img.avatar {
         width: 70px;
         float: left;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 83cdcde..9f0eeab 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -72,6 +72,9 @@
   </nav>
 </div>
 <div class="header">
+  <div class="img-wrap">
+    <img src="https://placekitten.com/2000/500" />
+  </div>
   {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
     <div class="dropdown pull-right">
       <span class="dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">

From 31bedb4eba12422b38545c6fe47e23230718d8ad Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 31 2015 20:19:55 +0000
Subject: [PATCH 209/1001] Merge branch 'develop' of pagure.io:fedora-hubs into develop


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 08a6e3b..93e6e01 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -281,6 +281,10 @@ font-size: 32pt;
     height: 32px;
 }
 
+.inline {
+    display: inline-block;
+}
+
 .navbar-nav > li.idle-none    > a { }
 .navbar-nav > li.idle-day     > a { }
 .navbar-nav > li.idle-week    > a { }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 9f0eeab..1a5b102 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -94,10 +94,14 @@
     </div>
   {% endif %}
   <div class="padded center-block medium-wide">
+    {% if hub.user_hub %}
     <img src="{{hub.avatar}}" class="avatar" />
     <h3>{{hub.name}}</h3>
     <h5>{{hub.summary}}</h5>
     <div class="clearfix"></div>
+    {% else %}
+    TODO - put max-height overflow:hidden placekitten here...
+    {% endif %}
   </div>
 </div>
 <div class="container">
diff --git a/hubs/validators.py b/hubs/validators.py
index cd3d7f6..5bdf053 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -3,6 +3,9 @@ import kitchen.text.converters
 import hubs.models
 
 
+def required(session, value):
+    return bool(value)
+
 def text(session, value):
     return kitchen.text.converters.to_unicode(value)
 
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 06a3b79..d3ae5b5 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -10,6 +10,7 @@ from hubs.widgets import fedmsgstats
 from hubs.widgets import feed
 from hubs.widgets import subscriptions
 from hubs.widgets import cobwebs
+from hubs.widgets import meetings
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -29,6 +30,7 @@ registry = {
     'feed': feed,
     'subscriptions': subscriptions,
     'cobwebs': cobwebs,
+    'meetings': meetings,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
new file mode 100644
index 0000000..517ee92
--- /dev/null
+++ b/hubs/widgets/meetings.py
@@ -0,0 +1,74 @@
+#from hubs.hinting import hint, prefixed as _
+from hubs.widgets.base import argument
+from hubs.widgets.chrome import panel
+
+from hubs import validators
+
+import arrow
+import collections
+import datetime
+import jinja2
+import requests
+
+chrome = panel('Reminders', key='meetings')
+
+def next_meeting(meetings):
+    now = datetime.datetime.utcnow()
+    for meeting in meetings:
+        string = "%s %s" % (meeting['meeting_date'],
+                            meeting['meeting_time_start'])
+        dt = datetime.datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
+
+        if now < dt:
+            meeting['human_time'] = arrow.get(dt).humanize()
+            meeting['start_date'] = dt.strftime('%b %d')
+            # Just UTC for now until we do this on the client and can access
+            # their local with moment.js.
+            meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
+            meeting['location'] = meeting['meeting_location']
+            if '@' in meeting['location']:
+                meeting['location'] = '#' + meeting['location'].split('@')[0]
+            return meeting
+
+    return None
+
+jinja2_environment = jinja2.Environment()
+jinja2_environment.filters['next_meeting'] = next_meeting
+template = jinja2_environment.from_string("""
+{% if meetings %}
+    {% for title, items in meetings.items() %}
+        {% set next = items | next_meeting %}
+        {% if next %}
+        The {{ next.meeting_name }} is {{ next.human_time }}
+        <h1 class='inline'>{{next.start_date}}</h1>
+        <div class='inline'>
+            @{{next.start_time}}<br/>
+            {{next.location}}
+        </div>
+        {% endif %}
+        {% if meetings | length > 1 %}
+        <hr/>
+        {% endif %}
+    {% endfor %}
+{% endif %}
+""")
+
+
+@argument(name="calendar",
+          default=None,
+          validator=validators.required,
+          help="A fedocal calendar.")
+def data(session, widget, calendar):
+    base = 'https://apps.fedoraproject.org/calendar/api/meetings/?calendar=%s'
+    url = base % calendar
+    response = requests.get(url).json()
+
+    meetings = collections.defaultdict(list)
+    for meeting in response['meetings']:
+        meetings[meeting['meeting_name']].append(meeting)
+
+    return dict(meetings=dict(meetings))
+
+
+def should_invalidate(message, session, widget):
+    raise NotImplementedError()
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 7afc67b..ce50aff 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -22,6 +22,23 @@ template = jinja2.Template("""
         </div>
     {% endfor %}
   </div>
+  {% if schedule_text or schedule_link or minutes_link %}
+  <h6>meetings</h6>
+  {% if schedule_text %}
+  <p>{{schedule_text}}</p>
+  {% endif %}
+  <p>
+  {% if schedule_link %}
+  <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
+  {% endif %}
+  {% if schedule_link and minutes_link %}
+  &#8214;
+  {% endif %}
+  {% if minutes_link %}
+  <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
+  {% endif %}
+  </p>
+  {% endif %}
 </div>
 <style>
   .rules-table {
@@ -39,10 +56,22 @@ template = jinja2.Template("""
 @argument(name='link', default=None,
           validator=validators.link,
           help="Link to the community rules and guidelines")
-def data(session, widget, link):
+@argument(name='schedule_text', default=None,
+          validator=validators.text,
+          help="Some text about when meetings are")
+@argument(name='schedule_link', default=None,
+          validator=validators.link,
+          help="Link to a schedule for IRC meetings, etc..")
+@argument(name='minutes_link', default=None,
+          validator=validators.link,
+          help="Link to meeting minutes from past meetings..")
+def data(session, widget, link, schedule_text, schedule_link, minutes_link):
     owners = widget.hub.owners
     owners = ordereddict([(o.username, avatar(o.username)) for o in owners])
-    return dict(owners=owners, link=link)
+    return dict(owners=owners, link=link,
+                schedule_text=schedule_text,
+                schedule_link=schedule_link,
+                minutes_link=minutes_link)
 
 
 @hint(topics=[_('hubs.widget.update'), _('hubs.hub.update')])
diff --git a/populate.py b/populate.py
index a23dfe7..4bb1b21 100755
--- a/populate.py
+++ b/populate.py
@@ -30,11 +30,15 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/I18N'
+                                'link': 'https://fedoraproject.org/wiki/I18N',
+                                'schedule_text': None,
+                                'schedule_link': None,
+                                'minutes_link': 'https://meetbot.fedoraproject.org/sresults/?group_id=i18n&type=team',
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='dummy', index=2)
+widget = hubs.models.Widget(plugin='meetings', index=2,
+                            _config=json.dumps({'calendar': 'i18n'}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -71,11 +75,15 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/Marketing'
+                                'link': 'https://fedoraproject.org/wiki/Marketing',
+                                'schedule_text': None,
+                                'schedule_link': None,
+                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=fedora-mktg&type=channel',
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='dummy', index=2)
+widget = hubs.models.Widget(plugin='meetings', index=2,
+                            _config=json.dumps({'calendar': 'marketing'}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -115,11 +123,15 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/Design'
+                                'link': 'https://fedoraproject.org/wiki/Design',
+                                'schedule_text': 'Meetings are every other Tuesday at 16:00 UTC',
+                                'schedule_link': 'https://apps.fedoraproject.org/calendar/design/',
+                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=fedora-design&type=channel',
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='dummy', index=2)
+widget = hubs.models.Widget(plugin='meetings', index=2,
+                            _config=json.dumps({'calendar': 'design'}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -160,11 +172,15 @@ widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
                             _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/Infrastructure'
+                                'link': 'https://fedoraproject.org/wiki/Infrastructure',
+                                'schedule_text': 'We meet weekly in #fedora-meeting at 18:00 UTC',
+                                'schedule_link': 'https://apps.fedoraproject.org/calendar/infrastructure/',
+                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=infrastructure&type=team',
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='dummy', index=2)
+widget = hubs.models.Widget(plugin='meetings', index=2,
+                            _config=json.dumps({'calendar': 'infrastructure'}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget

From f9562f672505671a8bc48cdf2f745c4300dd772a Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Jul 31 2015 20:55:41 +0000
Subject: [PATCH 210/1001] kitten banner better


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 93e6e01..4c91003 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -90,8 +90,11 @@
         color: #3C6EB4;
         font-weight: 700;
       }
-      .header .medium-wide {
-        top: 150px !important;
+      .header .dropdown.edit {
+        top: 140px !important;
+      }
+      .header h3.team {
+        top: 170px !important;
       }
     }
 
@@ -102,6 +105,13 @@
       font-family: 'Open Sans', sans-serif;
     }
 
+    .header .dropdown.edit {
+      position: absolute;
+      top: 90px;
+      right: 0;
+      z-index: 2;
+    }
+
     .header .img-wrap {
       max-height: 100px;
       overflow: hidden;
@@ -113,9 +123,9 @@
       text-align: center;
     }
 
-    .header .medium-wide {
+    .header h3.team {
       position: absolute;
-      top: 100px;
+      top: 120px;
       left: 45%;
     }
 
@@ -126,6 +136,7 @@
         display: inline;
         border: 5px solid #fff;
     }
+
     .header h3 {
         font-weight: 700;
     }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 1a5b102..0039a14 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -72,11 +72,8 @@
   </nav>
 </div>
 <div class="header">
-  <div class="img-wrap">
-    <img src="https://placekitten.com/2000/500" />
-  </div>
   {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
-    <div class="dropdown pull-right">
+    <div class="dropdown pull-right edit">
       <span class="dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
         <span class="glyphicon glyphicon-edit"></span> edit this page
       </span>
@@ -93,16 +90,19 @@
       </ul>
     </div>
   {% endif %}
-  <div class="padded center-block medium-wide">
-    {% if hub.user_hub %}
-    <img src="{{hub.avatar}}" class="avatar" />
-    <h3>{{hub.name}}</h3>
-    <h5>{{hub.summary}}</h5>
-    <div class="clearfix"></div>
+  {% if hub.user_hub %}
+    <div class="padded center-block medium-wide">
+      <img src="{{hub.avatar}}" class="avatar" />
+      <h3>{{hub.name}}</h3>
+      <h5>{{hub.summary}}</h5>
+      <div class="clearfix"></div>
+    </div>
     {% else %}
-    TODO - put max-height overflow:hidden placekitten here...
-    {% endif %}
-  </div>
+    <div class="img-wrap">
+      <img src="https://placekitten.com/2000/500" />
+    </div>
+    <h3 class="team">{{hub.name}}</h3>
+  {% endif %}
 </div>
 <div class="container">
   <div class="row">

From 29e32919e4cad7346aefaca82ab44728a2099498 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Aug 01 2015 01:30:05 +0000
Subject: [PATCH 211/1001] Chromium doesn't like img-responsive.


---

diff --git a/hubs/widgets/avatar.py b/hubs/widgets/avatar.py
index bf49bf6..10754df 100644
--- a/hubs/widgets/avatar.py
+++ b/hubs/widgets/avatar.py
@@ -8,7 +8,7 @@ import hubs.validators as validators
 
 
 template = jinja2.Template("""
-<img class="img-responsive img-circle center-block" src="{{avatar}}">
+<img class="img-circle center-block" src="{{avatar}}">
 """)
 
 #from hubs.widgets.chrome import panel
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 3409ea6..d3d0b4b 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -35,7 +35,7 @@ template = jinja2.Template("""
     <div class="media">
       <div class="media-left">
         <a href="{{match['link']}} target="_blank">
-          <img class="media-object img-responsive square-32 img-circle" src="{{match['secondary_icon']}}">
+          <img class="media-object square-32 img-circle" src="{{match['secondary_icon']}}">
         </a>
       </div>
       <div class="media-body">
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 6bcee7b..958d034 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -20,7 +20,7 @@ template = jinja2.Template("""
 {% for acl in pending_acls %}
     <li class="media">
         <div class="media-left">
-            <img class="media-object img-responsive img-circle" src="{{acl['avatar']}}"/>
+            <img class="media-object img-circle" src="{{acl['avatar']}}"/>
         </div>
         <div class="media-body">
             <h4 class="media-heading">{{acl['user']}} is {{acl['status']}}</h4>

From a4e055550dbad0f8b34c0bc84990e23561bb5a34 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Aug 01 2015 01:33:54 +0000
Subject: [PATCH 212/1001] Square up those menus.


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 4c91003..dd83526 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -296,6 +296,10 @@ font-size: 32pt;
     display: inline-block;
 }
 
+.dropdown-menu {
+    border-radius: 0px !important;
+}
+
 .navbar-nav > li.idle-none    > a { }
 .navbar-nav > li.idle-day     > a { }
 .navbar-nav > li.idle-week    > a { }

From cb79e274fc63bb2a7f9693540f61803916e4ac8d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Aug 03 2015 14:56:29 +0000
Subject: [PATCH 213/1001] This looks goofy in chrome.


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index dd83526..aa5ec8b 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -267,10 +267,6 @@
     flex-wrap: wrap;
 }
 
-.stats-container button {
-  margin: 20px 0 0 0;
-}
-
 .stats-table {
 width: 180px
 padding: 0px;

From 1f1eea9821fc116282432a24540f9af9404f791b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Aug 03 2015 15:53:45 +0000
Subject: [PATCH 214/1001] Start with random headers for hubs.  Allow changing them later.


---

diff --git a/hubs/models.py b/hubs/models.py
index 4045200..79a481f 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -25,6 +25,8 @@ import datetime
 import json
 import logging
 import operator
+import os
+import random
 
 import sqlalchemy as sa
 from sqlalchemy import create_engine
@@ -63,6 +65,13 @@ log = logging.getLogger(__name__)
 placekitten = lambda: "https://placekitten.com/g/320/320"
 
 
+def randomheader():
+    location = '/static/img/headers/'
+    header_dir = os.path.dirname(__file__) + location
+    choice = random.choice(os.listdir(header_dir))
+    return location + choice
+
+
 def init(db_url, debug=False, create=False):
     """ Create the tables in the database using the information from the
     url obtained.
@@ -122,6 +131,7 @@ class Hub(BASE):
 
     # A URL to the "avatar" for this hub.
     avatar = sa.Column(sa.String(256), default=placekitten)
+    header_img = sa.Column(sa.String(256), default=randomheader)
 
     #fas_group = sa.Column(sa.String(32), nullable=False)
 
diff --git a/hubs/static/img/headers/header-8ball.png b/hubs/static/img/headers/header-8ball.png
new file mode 100644
index 0000000..8707bdb
Binary files /dev/null and b/hubs/static/img/headers/header-8ball.png differ
diff --git a/hubs/static/img/headers/header-brain.png b/hubs/static/img/headers/header-brain.png
new file mode 100644
index 0000000..dbb135c
Binary files /dev/null and b/hubs/static/img/headers/header-brain.png differ
diff --git a/hubs/static/img/headers/header-bricks.png b/hubs/static/img/headers/header-bricks.png
new file mode 100644
index 0000000..c6ca5d5
Binary files /dev/null and b/hubs/static/img/headers/header-bricks.png differ
diff --git a/hubs/static/img/headers/header-cereal.png b/hubs/static/img/headers/header-cereal.png
new file mode 100644
index 0000000..a756b20
Binary files /dev/null and b/hubs/static/img/headers/header-cereal.png differ
diff --git a/hubs/static/img/headers/header-clouds.png b/hubs/static/img/headers/header-clouds.png
new file mode 100644
index 0000000..0606779
Binary files /dev/null and b/hubs/static/img/headers/header-clouds.png differ
diff --git a/hubs/static/img/headers/header-fireworks.png b/hubs/static/img/headers/header-fireworks.png
new file mode 100644
index 0000000..1934ca4
Binary files /dev/null and b/hubs/static/img/headers/header-fireworks.png differ
diff --git a/hubs/static/img/headers/header-glass.png b/hubs/static/img/headers/header-glass.png
new file mode 100644
index 0000000..3ad2791
Binary files /dev/null and b/hubs/static/img/headers/header-glass.png differ
diff --git a/hubs/static/img/headers/header-house-of-fedora.png b/hubs/static/img/headers/header-house-of-fedora.png
new file mode 100644
index 0000000..b5d8c60
Binary files /dev/null and b/hubs/static/img/headers/header-house-of-fedora.png differ
diff --git a/hubs/static/img/headers/header-ice.png b/hubs/static/img/headers/header-ice.png
new file mode 100644
index 0000000..b820ab3
Binary files /dev/null and b/hubs/static/img/headers/header-ice.png differ
diff --git a/hubs/static/img/headers/header-koi.png b/hubs/static/img/headers/header-koi.png
new file mode 100644
index 0000000..3b021c3
Binary files /dev/null and b/hubs/static/img/headers/header-koi.png differ
diff --git a/hubs/static/img/headers/header-nametag.png b/hubs/static/img/headers/header-nametag.png
new file mode 100644
index 0000000..c3e7b0d
Binary files /dev/null and b/hubs/static/img/headers/header-nametag.png differ
diff --git a/hubs/static/img/headers/header-signage.png b/hubs/static/img/headers/header-signage.png
new file mode 100644
index 0000000..1900b2a
Binary files /dev/null and b/hubs/static/img/headers/header-signage.png differ
diff --git a/hubs/static/img/headers/header-tea-1.png b/hubs/static/img/headers/header-tea-1.png
new file mode 100644
index 0000000..e8c5480
Binary files /dev/null and b/hubs/static/img/headers/header-tea-1.png differ
diff --git a/hubs/static/img/headers/header-tea-2.png b/hubs/static/img/headers/header-tea-2.png
new file mode 100644
index 0000000..06fe666
Binary files /dev/null and b/hubs/static/img/headers/header-tea-2.png differ
diff --git a/hubs/static/img/headers/header-tea-3.png b/hubs/static/img/headers/header-tea-3.png
new file mode 100644
index 0000000..f6346d2
Binary files /dev/null and b/hubs/static/img/headers/header-tea-3.png differ
diff --git a/hubs/static/img/headers/header-tennis.png b/hubs/static/img/headers/header-tennis.png
new file mode 100644
index 0000000..63bef6c
Binary files /dev/null and b/hubs/static/img/headers/header-tennis.png differ
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 0039a14..786f270 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -99,7 +99,7 @@
     </div>
     {% else %}
     <div class="img-wrap">
-      <img src="https://placekitten.com/2000/500" />
+      <img src="{{hub.header_img}}" />
     </div>
     <h3 class="team">{{hub.name}}</h3>
   {% endif %}

From 61d184869cc9eebc523f40aafddeaa79ba1de497 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Aug 05 2015 15:33:17 +0000
Subject: [PATCH 215/1001] fixing line break


---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 517ee92..26d5501 100644
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -39,7 +39,7 @@ template = jinja2_environment.from_string("""
     {% for title, items in meetings.items() %}
         {% set next = items | next_meeting %}
         {% if next %}
-        The {{ next.meeting_name }} is {{ next.human_time }}
+        <p>The {{ next.meeting_name }} is {{ next.human_time }}</p>
         <h1 class='inline'>{{next.start_date}}</h1>
         <div class='inline'>
             @{{next.start_time}}<br/>

From f48b0600ec60763f42111edd162a50c5b7542f46 Mon Sep 17 00:00:00 2001
From: Meghan Richardson <mrichard@fedoraproject.org>
Date: Aug 05 2015 19:22:35 +0000
Subject: [PATCH 216/1001] placeholder irc icon


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index aa5ec8b..655d2cb 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -25,6 +25,11 @@
     .super-header .dropdown {
       border-radius: 0;
     }
+    .super-header .dropdown img.icon {
+      margin-right: 20px;
+      height: 30px;
+      width: auto;
+    }
     .super-header .dropdown .dropdown-header {
       font-weight: 700;
       font-size: 16px;
@@ -199,7 +204,7 @@
       font-size: 16px;
     }
 
-    .panel-info .widget-buttons a {
+    .panel-info .widget-buttons a, .panel-danger .widget-buttons a {
       color: #fff;
     }
 
diff --git a/hubs/static/img/irc_icon.png b/hubs/static/img/irc_icon.png
new file mode 100644
index 0000000..6aa4026
Binary files /dev/null and b/hubs/static/img/irc_icon.png differ
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 786f270..bf6f021 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -15,6 +15,7 @@
     <div class="col-sm-4 col-sm-push-4 col-xs-8">
       {% if g.auth.logged_in %}
         <div class="dropdown pull-right">
+          <img class = "icon" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
         <span class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
           <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
           {# Logged in as #} {{ g.auth.nickname }}

From bed28448a65c2d2324ef578720da46398d4e9aca Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Sep 06 2015 00:41:40 +0000
Subject: [PATCH 217/1001] Update .gitignore


---

diff --git a/.gitignore b/.gitignore
index d042055..0e32795 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 fedmsg.d/fas_credentials.py
 node*
 build/
+scratch/

From a9ea4085970053a5fcef73b55635207ba118c370 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Sep 06 2015 00:42:08 +0000
Subject: [PATCH 218/1001] Added Comfortaa Fonts Locally


---

diff --git a/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.eot b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.eot
new file mode 100644
index 0000000..8755c78
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.eot differ
diff --git a/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.svg b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.svg
new file mode 100644
index 0000000..ffc745c
--- /dev/null
+++ b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.svg
@@ -0,0 +1,2644 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs >
+<font id="Comfortaa" horiz-adv-x="1003" ><font-face
+    font-family="Comfortaa"
+    units-per-em="2048"
+    panose-1="2 15 3 3 7 2 0 6 0 3"
+    ascent="2081"
+    descent="-482"
+    alphabetic="0" />
+<glyph unicode=" " glyph-name="space" horiz-adv-x="560" />
+<glyph unicode="!" glyph-name="exclam" horiz-adv-x="400" d="M307 104Q307 60 277 30Q248 0 204 0Q160 0 130 30Q100 60 100 104Q100 148 130 177Q160 207 204 207Q248 207 277 177Q307 148 307 104ZM141 1539Q141 1565 159 1583T204 1601Q230 1601 248 1583T266
+1539V393Q266 367 248 351Q230 332 204 332Q178 332 160 351Q141 368 141 393V1539Z" />
+<glyph unicode="&quot;" glyph-name="quotedbl" horiz-adv-x="560" d="M202 1227Q202 1210 190 1198T161 1186Q144 1186 132 1198T119 1227L99 1539Q99 1565 117 1583T161 1601Q187 1601 205 1583T223 1539L202 1227ZM451 1227Q451 1210 439 1198T410 1186Q393
+1186 381 1198T368 1227L347 1539Q347 1565 365 1583T410 1601Q436 1601 454 1583T472 1539L451 1227Z" />
+<glyph unicode="#" glyph-name="numbersign" horiz-adv-x="1280" d="M371 65Q366 39 344 20T294 0Q271 0 257 17T246 58L324 498H133Q109 498 97 512T85 544Q86 583 110 602T162 622H346L411 996H221Q196 996 183 1013T173 1055V1054Q178 1081 200 1100T251 1120H434L510
+1552Q515 1579 537 1598T587 1618Q610 1618 624 1601T634 1559L558 1120H849L925 1552Q930 1579 952 1598T1001 1618Q1025 1618 1039 1601T1049 1559L972 1120H1163Q1187 1120 1199 1105T1211 1073Q1209 1035 1185 1016T1133 996H950L884 622H1075Q1098 622 1112
+605T1123 564Q1117 537 1095 518T1046 498H862L786 65Q780 39 758 20T709 0Q686 0 672 17T661 58L739 498H448L371 65ZM535 996L469 622H761L826 996H535Z" />
+<glyph unicode="$" glyph-name="dollar" horiz-adv-x="1060" d="M509 1Q298 0 145 169Q125 191 108 216Q94 234 94 256Q94 282 112 300T156 318Q190 318 209 290Q222 270 240 250Q286 196 354 163T509 123V832Q360 861 269 967Q224 1021 200 1085T177 1254Q184
+1334 219 1402T315 1522Q333 1536 355 1549T403 1575T456 1596T509 1612V1721Q509 1747 527 1765T571 1784Q597 1784 615 1766T633 1721V1611Q708 1597 766 1563T871 1477Q894 1453 909 1424Q918 1407 918 1390Q918 1364 900 1346T856 1327Q831 1327 817 1343Q807
+1354 796 1369T775 1396Q727 1453 633 1485V939Q705 919 766 880T874 786Q927 720 956 643T986 484Q979 340 936 259T818 114Q739 49 633 16V-104Q633 -130 615 -148T571 -166Q545 -166 527 -148T509 -104V1ZM509 1486Q474 1475 445 1460T396 1427Q356 1391 331
+1344T301 1244Q297 1190 314 1140T366 1047Q389 1019 425 997T509 958V1486ZM633 145Q690 167 737 209Q788 255 822 317T861 481Q861 610 778 706Q752 736 716 761T633 810V145Z" />
+<glyph unicode="%" glyph-name="percent" horiz-adv-x="1760" d="M876 1208Q876 1043 760 929Q646 814 481 814Q317 814 203 929Q87 1043 87 1208Q87 1371 203 1487Q318 1602 481 1602Q645 1602 760 1487Q876 1371 876 1208ZM917 394Q917 558 1032 673Q1147 788
+1311 788Q1475 788 1590 673Q1705 558 1705 394Q1705 230 1590 115Q1475 0 1311 0Q1147 0 1032 115Q917 230 917 394ZM481 1477Q371 1477 291 1397Q212 1319 212 1208Q212 1096 291 1017Q370 938 481 938Q592 938 671 1017Q751 1097 751 1208Q751 1319 671 1397Q591
+1477 481 1477ZM1311 664Q1200 664 1120 584Q1041 505 1041 394Q1041 282 1120 203Q1199 124 1311 124Q1422 124 1501 203Q1581 283 1581 394Q1581 504 1501 584Q1421 664 1311 664ZM316 0Q290 0 272 18T253 62Q253 86 269 105L1425 1574Q1437 1587 1449 1594T1477
+1601Q1503 1601 1521 1583T1539 1539Q1539 1517 1527 1501L364 23Q342 0 316 0Z" />
+<glyph unicode="&amp;" glyph-name="ampersand" horiz-adv-x="1440" d="M506 953L643 1061Q700 1106 727 1154T754 1255Q754 1346 687 1415Q620 1481 526 1481Q431 1481 364 1415Q298 1347 298 1255Q298 1162 364 1095L506 953ZM904 382L492 793L360 693Q215 581
+215 452Q215 305 306 214Q398 123 526 123Q654 123 746 214L904 382ZM591 869L991 472L1189 682Q1205 699 1231 699Q1257 699 1275 682T1293 638Q1293 615 1279 596L1078 386L1360 103Q1376 86 1376 62Q1376 36 1358 18T1314 0Q1289 0 1271 17L992 295L833 127H834Q706
+0 526 0Q346 0 218 127Q90 254 90 452Q90 540 139 622T278 777L407 877L276 1007Q173 1112 173 1255Q173 1400 276 1502Q379 1605 526 1605Q672 1605 775 1502Q879 1401 879 1255Q879 1101 734 977L735 978L591 869Z" />
+<glyph unicode="&apos;" glyph-name="quotesingle" horiz-adv-x="320" d="M204 1228Q204 1211 192 1199T163 1187Q146 1187 134 1199T121 1228L101 1540Q101 1566 119 1584T163 1602Q189 1602 207 1584T225 1540L204 1228Z" />
+<glyph unicode="(" glyph-name="parenleft" horiz-adv-x="560" d="M345 1565Q351 1579 360 1588Q378 1606 405 1606Q430 1606 447 1590T465 1549Q464 1530 454 1509Q219 1035 219 564Q219 324 278 88T456 -386Q466 -405 466 -422Q466 -446 448 -463T405 -480Q379
+-480 361 -462Q352 -451 344 -437Q220 -184 160 65T99 565Q99 816 159 1064T345 1565Z" />
+<glyph unicode=")" glyph-name="parenright" horiz-adv-x="560" d="M344 1312T405 1064T466 565Q466 314 405 65T220 -437Q212 -451 203 -462Q186 -480 160 -480Q134 -480 117 -463T99 -422Q99 -405 109 -386Q227 -148 286 88T345 564Q345 1035 111 1509Q101 1530
+100 1549Q101 1573 117 1589T160 1606Q187 1606 204 1588Q213 1579 219 1565Q344 1312 405 1064Z" />
+<glyph unicode="*" glyph-name="asterisk" horiz-adv-x="780" d="M424 1289L586 1149Q595 1142 601 1133Q607 1125 611 1114T615 1095Q615 1081 609 1068T591 1046Q571 1032 543 1033Q518 1036 503 1056Q497 1064 492 1074L399 1269L304 1075Q299 1063 292 1054Q276
+1032 244 1032Q222 1033 206 1046Q183 1064 183 1095Q183 1117 196 1133L212 1149L374 1288L166 1310Q152 1311 143 1315Q118 1326 108 1346Q102 1360 102 1374Q103 1385 106 1394Q114 1419 137 1429T183 1432Q196 1427 204 1421L381 1318L339 1518Q336 1528 336
+1540Q336 1566 354 1584T398 1602Q424 1602 442 1584T460 1540Q460 1528 457 1518L413 1317L593 1422Q603 1428 612 1432Q637 1440 660 1430T692 1394Q696 1383 696 1373Q696 1358 690 1346Q679 1322 655 1315Q645 1311 632 1310L424 1289Z" />
+<glyph unicode="+" glyph-name="plus" horiz-adv-x="1120" d="M494 1224Q494 1250 512 1268T556 1286Q582 1286 600 1268T619 1224V871H971Q997 871 1015 853T1033 809Q1033 783 1015 765T971 747H619V394Q619 368 601 350T556 332Q530 332 512 350T494 394V747H142Q116
+747 98 765T79 809Q79 835 97 853T142 871H494V1224Z" />
+<glyph unicode="," glyph-name="comma" horiz-adv-x="400" d="M130 30Q100 60 100 104Q100 148 130 177Q160 207 204 207Q248 207 277 177Q307 148 307 104Q307 -94 220 -226Q206 -249 183 -249Q166 -249 154 -237T141 -207Q142 -191 153 -178Q190 -137 190 -91Q190
+-63 176 -33T130 30Z" />
+<glyph unicode="-" glyph-name="hyphen" horiz-adv-x="800" d="M142 498Q116 498 98 516T79 560Q79 586 97 604T142 622H639Q665 622 683 604T702 560Q702 534 684 516T639 498H142Z" />
+<glyph unicode="." glyph-name="period" horiz-adv-x="400" d="M307 104Q307 60 277 30Q248 0 204 0Q160 0 130 30Q100 60 100 104Q100 148 130 177Q160 207 204 207Q248 207 277 177Q307 148 307 104Z" />
+<glyph unicode="/" glyph-name="slash" horiz-adv-x="960" d="M763 1601Q782 1618 808 1618Q834 1618 852 1600T870 1556Q870 1541 864 1528L200 -132Q196 -142 190 -148Q170 -166 144 -166Q118 -166 100 -148T82 -104Q82 -88 87 -77L752 1584Q756 1594 763 1601Z" />
+<glyph unicode="0" glyph-name="zero" horiz-adv-x="1120" d="M80 803Q80 1041 132 1215T278 1491Q335 1544 406 1574T557 1605Q638 1605 708 1575T836 1491Q931 1389 982 1215T1034 803Q1034 564 983 390T836 114Q779 61 709 31T557 0Q477 0 406 30T278 114Q184
+216 132 390T80 803ZM557 1481Q445 1481 366 1401Q205 1221 205 803Q205 383 366 202Q444 123 557 123Q668 123 748 202Q910 384 910 803Q910 1220 748 1401Q667 1481 557 1481Z" />
+<glyph unicode="1" glyph-name="one" horiz-adv-x="560" d="M453 62Q453 36 435 18T391 0Q365 0 347 18T328 62V1452L167 1400Q152 1394 142 1394Q116 1394 98 1412T80 1457Q80 1483 98 1501Q106 1509 118 1515L367 1598Q381 1602 391 1602Q417 1602 435 1584T453
+1540V62Z" />
+<glyph unicode="2" glyph-name="two" horiz-adv-x="1120" d="M972 124Q998 124 1016 106T1034 62Q1034 36 1016 18T972 0H143Q117 0 99 18T80 62Q80 86 99 107L807 876Q856 927 883 990T910 1125Q910 1271 806 1374Q704 1477 557 1477Q411 1477 307 1374Q205 1270
+205 1125Q205 1099 187 1081T143 1063Q117 1063 99 1081T80 1125Q80 1321 219 1462Q361 1602 557 1602Q756 1602 894 1462Q1034 1323 1034 1125Q1034 926 893 786L284 124H972Z" />
+<glyph unicode="3" glyph-name="three" horiz-adv-x="1120" d="M557 822Q531 822 513 839T495 883Q495 909 513 927T557 945Q668 945 747 1023Q827 1102 827 1212Q827 1322 747 1399Q667 1478 557 1478Q445 1478 367 1399Q288 1322 288 1212Q288 1186 270 1168T226
+1150Q200 1150 182 1168T163 1212Q163 1294 192 1362T278 1488Q336 1545 405 1573T557 1602Q721 1602 836 1488Q951 1374 951 1212Q951 1041 786 889Q821 868 848 848T895 807Q1034 669 1034 472Q1034 275 894 138Q755 0 557 0Q361 0 219 138Q80 277 80 472Q80
+498 98 516T143 534Q169 534 187 516T205 472Q205 330 307 225Q361 174 422 149T557 123Q703 123 806 225Q910 328 910 472Q910 617 806 719Q704 822 557 822Z" />
+<glyph unicode="4" glyph-name="four" horiz-adv-x="1280" d="M827 522V1338L262 522H827ZM142 398Q116 398 98 416T80 460Q80 480 91 496L838 1576Q855 1601 889 1601Q915 1601 933 1583T951 1539V522H1138Q1164 522 1182 504T1200 460Q1200 434 1182 416T1138
+398H951V62Q951 36 933 18T889 0Q863 0 845 18T827 62V398H142Z" />
+<glyph unicode="5" glyph-name="five" horiz-adv-x="1200" d="M971 1602Q997 1602 1015 1584T1034 1540Q1034 1514 1016 1496T971 1477H287V1037H598Q814 1037 964 885Q1117 733 1117 519Q1117 304 964 151Q813 0 598 0Q385 0 231 151Q80 303 80 519Q80 545 98
+563T142 581Q168 581 186 563T204 519Q204 355 319 240Q438 124 598 124Q760 124 876 240Q992 355 992 519Q992 683 876 796Q760 913 598 913H225Q199 913 181 931T163 975V1540Q163 1566 181 1584T225 1602H971Z" />
+<glyph unicode="6" glyph-name="six" horiz-adv-x="1120" d="M424 939Q496 954 557 954Q756 954 894 814Q1034 677 1034 477Q1034 278 894 139Q755 0 557 0Q361 0 219 139Q80 280 80 477Q80 622 157 737L666 1566Q672 1576 678 1583Q696 1601 723 1601Q749 1601
+767 1583T786 1539Q786 1522 777 1506L424 939ZM910 477Q910 623 806 726Q704 830 557 830Q413 830 307 726Q205 622 205 477Q205 333 307 227Q361 176 422 150T557 124Q703 124 806 227Q910 331 910 477Z" />
+<glyph unicode="7" glyph-name="seven" horiz-adv-x="1120" d="M188 19Q169 0 143 0Q117 0 99 18T80 62Q80 80 95 104L867 1477H143Q117 1477 99 1495T80 1540Q80 1566 98 1584T143 1602H972Q998 1602 1016 1584T1034 1540Q1034 1521 1025 1505L200 36Q194 25 188 19Z" />
+<glyph unicode="8" glyph-name="eight" horiz-adv-x="1120" d="M557 1478Q445 1478 367 1399Q288 1322 288 1212Q288 1101 367 1023Q445 945 557 945Q668 945 747 1023Q827 1102 827 1212Q827 1322 747 1399Q667 1478 557 1478ZM557 822Q413 822 307 719Q205 616
+205 472Q205 330 307 225Q416 123 557 123Q703 123 806 225Q910 328 910 472Q910 617 806 719Q704 822 557 822ZM300 915T278 936Q163 1050 163 1212Q163 1294 192 1362T278 1488Q336 1545 405 1573T557 1602Q721 1602 836 1488Q951 1374 951 1212Q951 1049 836
+936Q818 919 787 892Q821 868 848 848T895 807Q1034 669 1034 472Q1034 275 894 138Q755 0 557 0Q361 0 219 138Q80 277 80 472Q80 668 220 807Q261 848 331 892Q300 915 278 936Z" />
+<glyph unicode="9" glyph-name="nine" horiz-adv-x="1120" d="M691 662Q627 647 557 647Q359 647 219 786Q80 927 80 1124Q80 1320 219 1461Q361 1601 557 1601Q756 1601 894 1461Q1034 1322 1034 1124Q1034 979 958 862L448 35Q443 26 436 19Q418 0 391 0Q365
+0 347 18T329 62Q329 78 338 94L691 662ZM205 1124Q205 979 307 874Q413 771 557 771Q704 771 806 874Q910 977 910 1124Q910 1270 806 1373Q704 1476 557 1476Q411 1476 307 1373Q205 1269 205 1124Z" />
+<glyph unicode=":" glyph-name="colon" horiz-adv-x="400" d="M307 104Q307 60 277 30Q248 0 204 0Q160 0 130 30Q100 60 100 104Q100 148 130 177Q160 207 204 207Q248 207 277 177Q307 148 307 104ZM307 1017Q307 972 277 944Q248 914 204 914Q160 914 130 944Q100
+972 100 1017Q100 1061 130 1091Q160 1121 204 1121Q248 1121 277 1091Q307 1061 307 1017Z" />
+<glyph unicode=";" glyph-name="semicolon" horiz-adv-x="400" d="M307 1017Q307 972 277 944Q248 914 204 914Q160 914 130 944Q100 972 100 1017Q100 1061 130 1091Q160 1121 204 1121Q248 1121 277 1091Q307 1061 307 1017ZM130 30Q100 60 100 104Q100 148
+130 177Q160 207 204 207Q248 207 277 177Q307 148 307 104Q307 -93 220 -225Q205 -249 183 -249Q166 -249 154 -237T141 -207Q141 -191 153 -178Q190 -137 190 -91Q190 -63 176 -33T130 30Z" />
+<glyph unicode="&lt;" glyph-name="less" horiz-adv-x="1120" d="M940 1279Q954 1286 971 1286Q997 1286 1015 1268T1033 1224Q1033 1190 1000 1169H1001L262 726L1001 283Q1033 262 1033 228Q1033 202 1015 184T971 166Q951 166 940 173L115 669Q79 692 79 726Q79
+758 115 783L940 1279Z" />
+<glyph unicode="=" glyph-name="equal" horiz-adv-x="1040" d="M143 913Q117 913 99 931T81 975Q81 1001 99 1019T143 1037H890Q916 1037 934 1019T952 975Q952 949 934 931T890 913H143ZM890 539Q916 539 934 521T952 477Q952 451 934 433T890 415L143 414Q117
+415 99 433T81 477Q81 503 99 521T143 539H890Z" />
+<glyph unicode="&gt;" glyph-name="greater" horiz-adv-x="1120" d="M998 783Q1034 758 1034 726Q1034 692 998 669L173 173Q162 166 142 166Q116 166 98 184T80 228Q80 262 112 283L851 726L112 1169H113Q80 1190 80 1224Q80 1250 98 1268T142 1286Q159 1286
+173 1279L998 783Z" />
+<glyph unicode="?" glyph-name="question" horiz-adv-x="1120" d="M205 1127Q205 1101 187 1084T143 1066Q117 1066 99 1083T80 1127Q80 1322 219 1463Q361 1602 557 1602Q756 1602 894 1463Q1034 1324 1034 1127Q1034 929 894 791V792L723 633Q620 530 620 384Q620
+358 602 340T557 322Q531 322 513 340T495 384Q495 581 635 720V719L806 877Q910 980 910 1127Q910 1273 806 1375Q704 1478 557 1478Q411 1478 307 1375Q205 1272 205 1127ZM661 104Q661 60 631 30Q601 0 557 0Q512 0 484 30Q454 60 454 104Q454 148 484 177Q512
+207 557 207Q601 207 631 177Q661 148 661 104Z" />
+<glyph unicode="@" glyph-name="at" horiz-adv-x="2240" d="M1123 991Q946 991 820 865Q694 739 694 562Q694 385 820 259Q946 133 1123 133Q1300 133 1426 259Q1551 384 1551 562Q1551 740 1426 865Q1300 991 1123 991ZM1551 219Q1536 196 1512 173Q1351 12 1123
+12Q893 12 734 173Q573 334 573 562Q573 790 734 951Q893 1112 1123 1112Q1351 1112 1512 951Q1673 790 1673 562V154Q1673 52 1775 52Q2040 52 2040 562Q2040 944 1771 1211Q1505 1479 1123 1479Q743 1479 473 1211Q205 940 205 562Q205 184 473 -87Q743 -355
+1123 -355Q1225 -355 1318 -336T1500 -276Q1516 -269 1533 -269Q1558 -269 1576 -286T1594 -330Q1594 -357 1576 -373Q1566 -383 1554 -389Q1360 -478 1123 -478Q691 -478 387 -173Q83 131 83 562Q83 992 387 1297Q691 1602 1123 1602Q1553 1602 1857 1297Q2163
+992 2163 562Q2163 -70 1775 -70Q1551 -70 1551 154V219Z" />
+<glyph unicode="A" glyph-name="A" horiz-adv-x="1440" d="M408 574L199 38Q193 24 185 16Q168 0 142 0Q116 0 98 18T80 62Q80 75 86 89L657 1556Q663 1572 673 1583Q690 1600 716 1600Q742 1600 760 1582Q770 1572 776 1556L1346 89Q1352 75 1352 62Q1352 36
+1334 18T1291 0Q1265 0 1248 15Q1239 24 1233 38L1025 574H408ZM977 697L716 1369L456 697H977Z" />
+<glyph unicode="B" glyph-name="B" horiz-adv-x="1120" d="M203 1477V944H470Q581 944 658 1022Q737 1101 737 1210Q737 1319 658 1398Q579 1477 470 1477H203ZM203 821V123H552Q697 123 798 225Q901 327 901 472Q901 616 798 718Q698 821 552 821H203ZM470 1600Q632
+1600 746 1486Q860 1372 860 1210Q860 1048 726 914Q826 866 887 806Q1024 667 1024 472Q1024 276 886 137Q747 0 552 0H142Q116 0 98 18T80 62V1538Q80 1564 98 1582T142 1600H470Z" />
+<glyph unicode="C" glyph-name="C" horiz-adv-x="1480" d="M1337 281Q1363 281 1381 263T1399 219Q1399 194 1384 178Q1272 91 1146 46T880 0Q717 0 574 61T314 234Q202 351 141 494T80 800Q80 1131 314 1365Q549 1600 880 1600Q1165 1600 1387 1418Q1405 1400
+1405 1374Q1405 1349 1387 1331T1344 1313Q1318 1313 1293 1337Q1120 1477 880 1477Q600 1477 401 1278Q203 1080 203 800Q203 519 401 321Q599 123 880 123Q1122 123 1304 272Q1317 281 1337 281Z" />
+<glyph unicode="D" glyph-name="D" horiz-adv-x="1360" d="M470 123Q748 123 948 321Q1147 520 1147 800Q1147 1079 948 1278Q747 1477 470 1477H203V123H470ZM470 1600Q801 1600 1035 1365Q1270 1131 1270 800Q1270 469 1035 234Q801 0 470 0H141Q116 0 98 18T80
+62V1538Q80 1564 98 1582T141 1600H470Z" />
+<glyph unicode="E" glyph-name="E" horiz-adv-x="1280" d="M1127 1600Q1152 1600 1170 1582T1188 1538Q1188 1513 1170 1495T1127 1477H203V862H880Q906 862 924 844T942 800Q942 774 924 756T880 738H203V123H1127Q1152 123 1170 105T1188 62Q1188 36 1170 18T1127
+0H142Q116 0 98 18T80 62V1538Q80 1564 98 1582T142 1600H1127Z" />
+<glyph unicode="F" glyph-name="F" horiz-adv-x="1280" d="M1127 1600Q1152 1600 1170 1582T1188 1538Q1188 1513 1170 1495T1127 1477H203V862H880Q906 862 924 844T942 800Q942 774 924 756T880 738H203V62Q203 36 186 18T142 0Q116 0 98 18T80 62V1538Q80 1564
+98 1582T142 1600H1127Z" />
+<glyph unicode="G" glyph-name="G" horiz-adv-x="1500" d="M1399 219Q1399 192 1384 178Q1272 91 1146 46T880 0Q717 0 574 61T314 234Q202 351 141 494T80 800Q80 1131 314 1365Q549 1600 880 1600Q1165 1600 1387 1418Q1405 1400 1405 1374Q1405 1349 1387 1331T1344
+1313Q1318 1313 1293 1337Q1120 1477 880 1477Q600 1477 401 1278Q203 1080 203 800Q203 519 401 321Q599 123 880 123Q1100 123 1276 250V656H931Q905 656 888 674T870 718Q870 744 887 761T931 779H1338Q1362 779 1382 761Q1399 742 1399 718V219Z" />
+<glyph unicode="H" glyph-name="H" horiz-adv-x="1280" d="M80 1538Q80 1564 98 1582T142 1600Q168 1600 185 1582T203 1538V862H1065V1538Q1065 1564 1083 1582T1127 1600Q1152 1600 1170 1582T1188 1538V62Q1188 36 1170 18T1127 0Q1101 0 1083 18T1065 62V738H203V62Q203
+36 186 18T142 0Q116 0 98 18T80 62V1538Z" />
+<glyph unicode="I" glyph-name="I" horiz-adv-x="480" d="M178 1538Q178 1564 195 1582T239 1600Q265 1600 283 1582T301 1538V62Q301 36 283 18T239 0Q213 0 196 18T178 62V1538Z" />
+<glyph unicode="J" glyph-name="J" horiz-adv-x="1120" d="M80 472Q80 498 98 515T142 533Q168 533 185 516T203 472Q203 328 305 225Q410 123 552 123Q697 123 798 225Q901 327 901 472V1538Q901 1564 919 1582T962 1600Q988 1600 1006 1582T1024 1538V472Q1024
+276 886 137Q747 0 552 0Q357 0 218 137Q80 278 80 472Z" />
+<glyph unicode="K" glyph-name="K" horiz-adv-x="1200" d="M80 1538Q80 1564 98 1582T141 1600Q167 1600 185 1582T203 1538V786L998 1581Q1017 1600 1044 1600Q1070 1600 1088 1582T1106 1538Q1106 1515 1088 1494L499 906L1094 98Q1105 82 1106 65Q1106 32 1081
+12Q1064 0 1046 0Q1012 0 993 26L410 816L203 609V62Q203 36 185 18T141 0Q116 0 98 18T80 62V1538Z" />
+<glyph unicode="L" glyph-name="L" horiz-adv-x="1200" d="M80 1538Q80 1564 98 1582T141 1600Q167 1600 185 1582T203 1538V123H1044Q1070 123 1088 105T1106 62Q1106 36 1088 18T1044 0H141Q116 0 98 18T80 62V1538Z" />
+<glyph unicode="M" glyph-name="M" horiz-adv-x="1760" d="M203 1278V62Q203 36 186 18T142 0Q116 0 98 18T80 62V1538Q80 1564 98 1582T142 1600Q179 1600 196 1568L880 199L1564 1568Q1582 1600 1619 1600Q1645 1600 1662 1582T1680 1538V62Q1680 36 1663 18T1619
+0Q1593 0 1575 18T1557 62V1278L933 29Q915 0 880 0Q840 0 823 39L203 1278Z" />
+<glyph unicode="N" glyph-name="N" horiz-adv-x="1440" d="M203 62Q203 36 186 18T142 0Q116 0 98 18T80 62V1538Q80 1564 98 1582T142 1600Q171 1600 189 1578L1229 241V1538Q1229 1564 1247 1582T1291 1600Q1316 1600 1334 1582T1352 1538V62Q1352 36 1334 18T1291
+0Q1261 0 1245 18L203 1358V62Z" />
+<glyph unicode="O" glyph-name="O" horiz-adv-x="1760" d="M880 1477Q602 1477 401 1278Q203 1080 203 800Q203 519 401 321Q600 123 880 123Q1160 123 1358 321Q1557 519 1557 800Q1557 1080 1358 1278Q1159 1477 880 1477ZM1680 800Q1680 469 1445 234Q1212
+0 880 0Q717 0 574 61T314 234Q202 351 141 494T80 800Q80 1131 314 1365Q549 1600 880 1600Q1213 1600 1445 1365Q1680 1131 1680 800Z" />
+<glyph unicode="P" glyph-name="P" horiz-adv-x="1080" d="M203 1477V697H469Q630 697 744 811Q859 926 859 1087Q859 1248 744 1362Q630 1477 469 1477H203ZM469 1600Q683 1600 831 1449Q982 1301 982 1087Q982 875 831 724Q681 574 469 574H203V62Q203 36 185
+18T141 0Q115 0 98 18T80 62V1538Q80 1564 97 1582T141 1600H469Z" />
+<glyph unicode="Q" glyph-name="Q" horiz-adv-x="1760" d="M1400 192Q1170 0 880 0Q717 0 574 61T314 234Q202 351 141 494T80 800Q80 1131 314 1365Q549 1600 880 1600Q1213 1600 1445 1365Q1680 1131 1680 800Q1680 508 1488 280L1663 105Q1680 87 1680 62Q1680
+36 1663 18T1619 0Q1593 0 1574 19L1400 192ZM1123 469Q1106 487 1106 513Q1106 539 1124 556T1167 574Q1192 574 1212 557L1401 367Q1557 562 1557 800Q1557 1080 1358 1278Q1159 1477 880 1477Q602 1477 401 1278Q203 1080 203 800Q203 519 401 321Q600 123 880
+123Q1118 123 1313 279L1123 469Z" />
+<glyph unicode="R" glyph-name="R" horiz-adv-x="1200" d="M203 1477V779H552Q696 779 798 881Q900 983 900 1128Q900 1275 798 1374Q696 1477 552 1477H203ZM552 1600Q748 1600 885 1462Q1023 1324 1023 1128Q1023 932 886 795Q821 730 726 687L1095 95Q1106
+79 1106 62Q1106 36 1088 18T1044 0Q1012 0 990 33L599 658Q578 656 552 656H203V62Q203 36 185 18T141 0Q116 0 98 18T80 62V1538Q80 1564 98 1582T141 1600H552Z" />
+<glyph unicode="S" glyph-name="S" horiz-adv-x="1060" d="M80 232T80 253Q80 279 97 297T141 315Q174 315 194 287Q207 268 224 247Q269 195 333 161T493 123Q618 123 716 206Q769 252 804 316T839 475Q839 601 756 697Q710 751 650 782T519 819Q441 827 373
+862T253 956Q209 1010 185 1073T161 1205Q163 1392 298 1506Q407 1600 552 1600Q720 1600 848 1461Q870 1435 886 1408Q895 1393 895 1374Q895 1349 877 1331T834 1313Q805 1313 793 1329Q777 1351 754 1379Q679 1467 573 1474Q464 1481 378 1410Q292 1338 285
+1231Q281 1176 296 1127T347 1036Q383 993 428 971T528 943Q623 933 705 891T851 777Q904 712 933 636T962 479Q960 341 916 259T796 113Q662 0 494 0Q283 0 130 167Q113 186 93 215Q80 232 80 253Z" />
+<glyph unicode="T" glyph-name="T" horiz-adv-x="1360" d="M142 1477Q117 1477 99 1495T81 1538Q81 1564 99 1582T142 1600H1209Q1235 1600 1253 1582T1271 1538Q1271 1513 1253 1495T1209 1477H737V62Q737 36 720 18T676 0Q650 0 632 18T614 62V1477H142Z" />
+<glyph unicode="U" glyph-name="U" horiz-adv-x="1280" d="M81 1538Q81 1564 99 1582T143 1600Q169 1600 186 1582T204 1538V554Q204 375 331 249Q457 123 635 123Q814 123 940 249Q1066 375 1066 554V1538Q1066 1564 1084 1582T1128 1600Q1153 1600 1171 1582T1189
+1538V554Q1189 324 1027 162Q865 0 635 0Q405 0 243 162Q162 243 122 340T81 554V1538Z" />
+<glyph unicode="V" glyph-name="V" horiz-adv-x="1440" d="M760 18Q742 0 716 0Q689 0 673 18Q667 25 661 38L89 1499Q80 1522 80 1538Q80 1564 98 1582T142 1600Q185 1600 198 1565L716 231L1235 1566Q1247 1600 1291 1600Q1316 1600 1334 1582T1352 1538Q1352
+1521 1343 1499L772 38Q767 25 760 18Z" />
+<glyph unicode="W" glyph-name="W" horiz-adv-x="1920" d="M916 1583Q935 1600 959 1600Q985 1600 1003 1583Q1013 1572 1018 1559L1370 293L1721 1559Q1726 1573 1737 1584Q1754 1600 1780 1600Q1806 1600 1823 1582T1841 1538Q1841 1525 1836 1508L1434 54Q1428
+32 1414 18Q1394 0 1370 0Q1344 0 1326 18Q1312 33 1306 53L959 1305L614 54Q607 33 593 18Q574 0 549 0Q524 0 506 18Q491 33 485 53L82 1508Q77 1525 77 1538Q77 1564 95 1582T139 1600Q165 1600 183 1583Q193 1572 197 1559L549 293L901 1560Q904 1571 916 1583Z"
+/>
+<glyph unicode="X" glyph-name="X" horiz-adv-x="1440" d="M716 901L1239 1573Q1262 1600 1291 1600Q1316 1600 1334 1582T1352 1538Q1352 1518 1342 1503L795 800L1339 101Q1352 85 1352 62Q1352 36 1334 18T1291 0Q1262 0 1244 21L716 698L188 21Q171 0 142
+0Q116 0 98 18T80 62Q80 84 94 101L637 800L91 1504Q80 1517 80 1538Q80 1564 98 1582T142 1600Q172 1600 193 1573L716 901Z" />
+<glyph unicode="Y" glyph-name="Y" horiz-adv-x="1280" d="M697 62Q697 36 679 18T635 0Q609 0 592 18T574 62V782L91 1504Q81 1520 81 1538Q81 1564 99 1582T143 1600Q173 1600 192 1575L635 911L1078 1575Q1096 1600 1128 1600Q1153 1600 1171 1582T1189 1538Q1189
+1518 1179 1504L697 782V62Z" />
+<glyph unicode="Z" glyph-name="Z" horiz-adv-x="1440" d="M142 1477Q116 1477 98 1495T80 1538Q80 1564 98 1582T142 1600H1291Q1316 1600 1334 1582T1352 1538Q1352 1518 1342 1504L268 123H1291Q1316 123 1334 105T1352 62Q1352 36 1334 18T1291 0H142Q116
+0 98 18T80 62Q80 82 94 101L1164 1477H142Z" />
+<glyph unicode="[" glyph-name="bracketleft" horiz-adv-x="640" d="M492 1602Q518 1602 536 1584T554 1540Q554 1514 536 1496T492 1477H222V-355H492Q518 -355 536 -373T554 -418Q554 -444 536 -462T492 -480H160Q134 -480 116 -462T98 -418V1540Q98 1566 116
+1584T160 1602H492Z" />
+<glyph unicode="\" glyph-name="backslash" horiz-adv-x="960" d="M877 -77Q883 -91 883 -104Q883 -130 865 -148T821 -166Q795 -166 777 -150Q769 -141 765 -132L100 1511Q95 1524 95 1539Q95 1565 113 1583T157 1601Q183 1601 202 1583Q210 1575 213 1567L877 -77Z" />
+<glyph unicode="]" glyph-name="bracketright" horiz-adv-x="640" d="M554 -418Q554 -444 536 -462T492 -480H160Q134 -480 116 -462T98 -418Q98 -392 116 -374T160 -355H430V1477H160Q134 1477 116 1495T98 1540Q98 1566 116 1584T160 1602H492Q518 1602 536
+1584T554 1540V-418Z" />
+<glyph unicode="^" glyph-name="asciicircum" horiz-adv-x="960" d="M489 1428L206 1002Q187 980 157 980Q131 980 113 998T95 1042Q95 1060 103 1074L439 1577Q448 1588 460 1595T489 1602Q506 1602 518 1595T539 1577L875 1074Q883 1060 883 1042Q883 1016 865
+998T821 980Q789 980 772 1002L489 1428Z" />
+<glyph unicode="_" glyph-name="underscore" horiz-adv-x="960" d="M-9 -126Q-35 -126 -53 -108T-71 -64Q-71 -38 -53 -20T-9 -1H987Q1013 -1 1031 -19T1049 -64Q1049 -90 1031 -108T987 -126H-9Z" />
+<glyph unicode="`" glyph-name="grave" horiz-adv-x="560" d="M99 1539Q99 1565 117 1583T161 1601Q187 1601 205 1583L457 1331Q472 1314 472 1290Q472 1264 454 1246T410 1227Q386 1227 367 1243L115 1495Q107 1504 103 1515T99 1539Z" />
+<glyph unicode="a" glyph-name="a" horiz-adv-x="1280" d="M640 996Q460 996 332 868Q204 740 204 560Q204 380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996ZM1075 203Q873 0 640 0Q408 0 244 164Q80 328 80
+560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560V62Q1200 36 1182 18T1138 0Q1112 0 1094 18T1075 62V203Z" />
+<glyph unicode="b" glyph-name="b" horiz-adv-x="1280" d="M640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996Q460 996 332 868Q204 740 204 560Q204 380 332 252Q460 124 640 124ZM204 917L244 956Q408 1120 640 1120Q872 1120 1036
+956Q1200 792 1200 560Q1200 328 1036 164Q872 0 640 0Q408 0 244 164Q80 328 80 560V1538Q80 1564 98 1582T142 1600Q168 1600 186 1582T204 1538V917Z" />
+<glyph unicode="c" glyph-name="c" horiz-adv-x="1120" d="M962 243Q988 243 1006 225T1024 180Q1024 154 1005 135Q929 70 836 35T640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q743 1120 836 1085T1005 985Q1014 976 1020 963T1027 936Q1027
+910 1009 892T965 874Q941 874 925 889Q803 996 640 996Q460 996 332 868Q205 741 205 560Q205 379 332 252Q460 124 640 124Q719 124 792 153T925 231Q940 243 962 243Z" />
+<glyph unicode="d" glyph-name="d" horiz-adv-x="1280" d="M1075 560Q1075 741 948 868Q820 996 640 996Q460 996 332 868Q204 740 204 560Q204 380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560ZM1075 1538Q1075 1564 1093 1582T1138 1600Q1164
+1600 1182 1582T1200 1538V560Q1200 328 1036 164Q872 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956L1075 917V1538Z" />
+<glyph unicode="e" glyph-name="e" horiz-adv-x="1280" d="M1073 622Q1045 771 948 868Q820 996 640 996Q460 996 332 868Q236 772 206 622H1073ZM959 241Q985 241 1003 223T1021 178Q1021 152 1005 135Q849 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408
+1120 640 1120Q872 1120 1036 956Q1200 792 1200 560Q1200 534 1182 516T1138 498H206Q236 348 332 252Q460 124 640 124Q722 124 792 150T920 227Q937 241 959 241Z" />
+<glyph unicode="f" glyph-name="f" horiz-adv-x="800" d="M727 1600Q753 1600 771 1582T789 1538Q789 1512 771 1494T727 1475Q374 1475 374 1123V1058H645Q671 1058 689 1040T707 996Q707 970 689 952T645 933H374V62Q374 36 356 18T312 0Q286 0 268 18T249 62V933H146Q120
+933 102 951T84 996Q84 1022 102 1040T146 1058H249V1123Q249 1600 727 1600Z" />
+<glyph unicode="g" glyph-name="g" horiz-adv-x="1280" d="M640 996Q460 996 332 869Q204 741 204 561Q204 382 332 254Q460 126 640 126Q820 126 948 254Q1075 381 1075 561Q1075 742 948 869Q820 996 640 996ZM1075 205Q892 3 640 3Q408 3 244 166Q80 330 80
+561Q80 793 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 793 1200 561V-5Q1200 -177 1075 -304Q899 -480 649 -480Q399 -480 224 -304Q159 -242 119 -169Q108 -150 108 -132Q108 -106 126 -88T170 -70Q196 -70 215 -89Q223 -96 229 -108Q263 -168 312 -217Q382
+-287 466 -321T649 -356Q847 -356 987 -216Q1075 -110 1075 -5V205Z" />
+<glyph unicode="h" glyph-name="h" horiz-adv-x="1200" d="M81 1540Q81 1566 99 1584T143 1602Q169 1602 187 1584T205 1540V942Q389 1120 599 1120Q815 1120 965 968Q1118 816 1118 601V62Q1118 36 1100 18T1055 0Q1029 0 1011 18T993 62V601Q993 766 877 879Q761
+996 599 996Q437 996 320 879Q205 765 205 601V62Q205 36 187 18T143 0Q117 0 99 18T81 62V1540Z" />
+<glyph unicode="i" glyph-name="i" horiz-adv-x="480" d="M315 1390Q315 1355 291 1331T232 1307Q198 1307 174 1331T149 1390Q149 1424 173 1448T232 1473Q267 1473 291 1449T315 1390ZM170 1058Q170 1084 188 1102T232 1120Q258 1120 276 1102T295 1058V62Q295
+36 277 18T232 0Q206 0 188 18T170 62V1058Z" />
+<glyph unicode="j" glyph-name="j" horiz-adv-x="656" d="M563 1390Q563 1355 539 1331T480 1307Q446 1307 422 1331T397 1390Q397 1424 421 1448T480 1473Q515 1473 539 1449T563 1390ZM418 1058Q418 1084 436 1102T480 1120Q506 1120 524 1102T543 1058V-3Q543
+-200 403 -340Q263 -480 66 -480Q40 -480 22 -462T3 -418Q3 -392 21 -374T66 -355Q212 -355 314 -252Q418 -149 418 -3V1058Z" />
+<glyph unicode="k" glyph-name="k" horiz-adv-x="1120" d="M206 634L940 1111Q954 1120 973 1120Q999 1120 1017 1102T1035 1058Q1035 1026 1015 1011L509 680L1018 106Q1035 88 1035 62Q1035 36 1017 18T973 0Q947 0 928 20L401 612L206 485V62Q206 36 188 18T144
+0Q118 0 100 18T81 62V1540Q81 1566 99 1584T144 1602Q170 1602 188 1584T206 1540V634Z" />
+<glyph unicode="l" glyph-name="l" horiz-adv-x="480" d="M87 1540Q87 1566 105 1584T149 1602Q175 1602 193 1584T212 1540V124H315Q341 124 359 106T378 62Q378 36 360 18T315 0H149Q123 0 105 18T87 62V1540Z" />
+<glyph unicode="m" glyph-name="m" horiz-adv-x="1760" d="M200 62Q200 36 182 18T138 0Q112 0 94 18T75 62V1058Q75 1084 93 1102T138 1120Q164 1120 182 1102T200 1058V991Q352 1120 511 1120Q691 1120 819 992Q850 960 884 914Q918 960 950 992Q1078 1120 1258
+1120Q1438 1120 1566 992Q1693 865 1693 684V62Q1693 36 1675 18T1631 0Q1605 0 1587 18T1569 62V684Q1569 813 1477 904Q1385 996 1258 996Q1130 996 1038 904Q947 813 947 684V62Q947 36 929 18T884 0Q858 0 840 18T822 62V684Q822 813 731 904Q639 996 511 996Q383
+996 291 904Q200 813 200 684V62Z" />
+<glyph unicode="n" glyph-name="n" horiz-adv-x="1200" d="M81 1058Q81 1084 99 1102T143 1120Q169 1120 187 1102T205 1058V942Q389 1120 599 1120Q815 1120 965 968Q1118 816 1118 601V62Q1118 36 1100 18T1055 0Q1029 0 1011 18T993 62V601Q993 766 877 879Q761
+996 599 996Q437 996 320 879Q205 765 205 601V62Q205 36 187 18T143 0Q117 0 99 18T81 62V1058Z" />
+<glyph unicode="o" glyph-name="o" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164Q872 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560ZM640 996Q460 996 332 868Q204 740 204 560Q204 380
+332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996Z" />
+<glyph unicode="p" glyph-name="p" horiz-adv-x="1280" d="M204 560Q204 380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996Q460 996 332 868Q204 740 204 560ZM204 -418Q204 -444 186 -462T142 -480Q116 -480
+98 -462T80 -418V560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560Q1200 328 1036 164Q872 0 640 0Q408 0 244 164L204 203V-418Z" />
+<glyph unicode="q" glyph-name="q" horiz-adv-x="1280" d="M640 996Q460 996 332 868Q204 740 204 560Q204 380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996ZM1075 203L1036 164Q872 0 640 0Q408 0 244 164Q80
+328 80 560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560V-418Q1200 -444 1182 -462T1138 -480Q1112 -480 1094 -462T1075 -418V203Z" />
+<glyph unicode="r" glyph-name="r" horiz-adv-x="960" d="M83 1058Q83 1084 101 1102T145 1120Q171 1120 189 1102T207 1058V917Q410 1120 643 1120Q768 1120 857 1081Q873 1075 886 1062Q903 1045 903 1018Q903 992 885 974T841 956Q825 956 813 962Q743 996
+643 996Q463 996 335 868Q207 741 207 560V62Q207 36 189 18T145 0Q119 0 101 18T83 62V1058Z" />
+<glyph unicode="s" glyph-name="s" horiz-adv-x="1060" d="M273 580H274Q228 597 197 613T149 648Q82 717 82 809Q82 902 152 974Q296 1120 528 1120Q652 1120 761 1068T958 919Q969 905 969 884Q969 858 951 840T906 821Q881 821 867 837L836 868Q708 996 528
+996Q347 996 237 880Q207 845 207 794Q209 764 225 742T272 709L783 540H782Q828 523 859 507T906 472Q974 404 974 311Q974 217 903 146Q760 0 528 0Q277 0 98 200Q87 215 87 236Q87 262 105 280T149 299Q173 299 189 283L220 252Q348 124 528 124Q708 124 817
+239Q848 274 848 325Q843 389 783 411L273 580Z" />
+<glyph unicode="t" glyph-name="t" horiz-adv-x="800" d="M644 124Q670 124 688 106T707 62Q707 36 689 18T644 0Q250 0 250 394V996H147Q121 996 103 1014T84 1058Q84 1084 102 1102T147 1120H250V1539Q250 1565 268 1583T312 1601Q338 1601 356 1583T375 1539V1120H562Q588
+1120 606 1102T625 1058Q625 1032 607 1014T562 996H375V394Q375 124 644 124Z" />
+<glyph unicode="u" glyph-name="u" horiz-adv-x="1200" d="M1118 62Q1118 36 1100 18T1055 0Q1029 0 1011 18T993 62V178Q809 0 599 0Q386 0 232 151Q81 303 81 519V1058Q81 1084 99 1102T143 1120Q169 1120 187 1102T205 1058V519Q205 355 320 240Q439 124 599
+124Q761 124 877 240Q993 355 993 519V1058Q993 1084 1011 1102T1055 1120Q1081 1120 1099 1102T1118 1058V62Z" />
+<glyph unicode="v" glyph-name="v" horiz-adv-x="1200" d="M642 15Q627 0 599 0Q572 0 555 17Q548 24 545 31L85 1034Q81 1044 81 1058Q81 1084 99 1102T143 1120Q169 1120 188 1103Q194 1097 199 1087L599 212L999 1087Q1003 1095 1010 1102Q1029 1120 1055 1120Q1081
+1120 1099 1103T1118 1058Q1118 1045 1113 1034L653 31Q649 22 642 15Z" />
+<glyph unicode="w" glyph-name="w" horiz-adv-x="1600" d="M760 1103Q778 1120 803 1120Q829 1120 846 1103Q858 1091 864 1072L1135 259L1409 1084Q1413 1094 1421 1102Q1439 1120 1467 1120Q1493 1120 1511 1102T1529 1058Q1529 1046 1524 1032L1193 39Q1189
+27 1178 16Q1162 0 1135 0Q1108 0 1091 17Q1082 26 1077 39L803 861L529 39Q525 27 516 18Q498 0 471 0Q444 0 427 17Q418 26 413 39L82 1032Q77 1047 77 1058Q77 1084 95 1102T139 1120Q165 1120 184 1102Q191 1095 196 1083L471 259L742 1072Q749 1092 760 1103Z"
+/>
+<glyph unicode="x" glyph-name="x" horiz-adv-x="1120" d="M477 561L96 1017Q81 1033 81 1058Q81 1084 99 1102T144 1120Q170 1120 189 1101L558 659L928 1101Q947 1120 973 1120Q999 1120 1017 1102T1035 1058Q1035 1034 1021 1017L639 561L1024 100Q1035 83
+1035 62Q1035 36 1017 18T973 0Q947 0 931 19L558 464L186 19Q170 0 144 0Q118 0 100 18T81 62Q81 83 93 100L477 561Z" />
+<glyph unicode="y" glyph-name="y" horiz-adv-x="1120" d="M490 63L85 1033Q81 1046 81 1058Q81 1084 99 1102T144 1120Q170 1120 188 1102Q197 1093 203 1077L558 227L913 1077Q919 1093 930 1104Q946 1120 973 1120Q999 1120 1017 1102T1036 1058Q1036 1048
+1032 1036L416 -438Q411 -452 402 -461Q383 -480 357 -480Q331 -480 313 -462T295 -418Q295 -405 299 -396L490 63Z" />
+<glyph unicode="z" glyph-name="z" horiz-adv-x="1120" d="M973 124Q999 124 1017 106T1035 62Q1035 36 1017 18T973 0H144Q118 0 100 18T81 62Q81 83 93 100L839 996H144Q118 996 100 1014T81 1058Q81 1084 99 1102T144 1120H973Q999 1120 1017 1102T1035 1058Q1035
+1034 1021 1017L275 124H973Z" />
+<glyph unicode="{" glyph-name="braceleft" horiz-adv-x="800" d="M644 1601Q670 1601 688 1583T707 1539Q707 1513 689 1495T644 1476Q458 1476 458 1290V809Q458 650 366 560Q458 470 458 311V-169Q458 -355 644 -355Q670 -355 688 -373T707 -418Q707 -444 689
+-462T644 -480Q333 -480 333 -169V311Q333 498 147 498Q121 498 103 516T84 560Q84 586 102 604T147 622Q333 622 333 809V1290Q333 1601 644 1601Z" />
+<glyph unicode="|" glyph-name="bar" horiz-adv-x="800" d="M333 1540Q333 1566 351 1584T395 1602Q421 1602 439 1584T458 1540V-418Q458 -444 440 -462T395 -480Q369 -480 351 -462T333 -418V1540Z" />
+<glyph unicode="}" glyph-name="braceright" horiz-adv-x="800" d="M458 809Q458 622 644 622Q670 622 688 604T707 560Q707 534 689 516T644 498Q458 498 458 311V-169Q458 -480 147 -480Q121 -480 103 -462T84 -418Q84 -392 102 -374T147 -355Q333 -355 333
+-169V311Q333 469 424 560Q333 651 333 809V1290Q333 1476 147 1476Q121 1476 103 1494T84 1539Q84 1565 102 1583T147 1601Q458 1601 458 1290V809Z" />
+<glyph unicode="~" glyph-name="asciitilde" horiz-adv-x="960" d="M517 707Q430 629 311 629Q182 629 90 721Q82 730 78 741T74 764Q74 790 92 808T136 827Q161 827 179 810Q235 754 311 754Q378 754 427 794Q515 873 635 873Q764 873 855 782Q872 764 872 738Q872
+712 854 694T810 676Q784 676 766 693Q712 749 635 749Q570 749 517 707Z" />
+<glyph unicode="&#xa0;" glyph-name="space" horiz-adv-x="560" />
+<glyph unicode="&#xa1;" glyph-name="exclamdown" horiz-adv-x="400" d="M192 912Q148 912 118 942Q88 970 88 1015Q88 1059 118 1089Q148 1119 192 1119Q236 1119 265 1089Q295 1059 295 1015Q295 970 265 942Q236 912 192 912ZM129 726Q129 750 148 768T192
+787Q218 787 236 769T254 726V-418Q254 -444 236 -462T192 -480Q166 -480 148 -462T129 -418V726Z" />
+<glyph unicode="&#xa2;" glyph-name="cent" horiz-adv-x="1120" d="M665 997Q461 989 341 868Q213 741 213 560Q213 382 360 232L665 997ZM169 -246L311 112Q280 135 252 164Q89 327 89 560Q89 793 252 956Q416 1120 649 1120Q686 1120 713 1117L832 1413Q843
+1438 866 1448Q875 1452 890 1452Q916 1452 934 1434T952 1390Q952 1380 947 1367L837 1090Q888 1070 933 1043T1014 985Q1024 976 1029 963T1035 936Q1035 910 1017 892T973 874Q951 874 933 889Q876 939 791 973L466 163Q560 124 649 124Q727 124 800 153T933
+231Q948 243 970 243Q996 243 1014 225T1032 180Q1032 155 1014 135Q937 70 845 35T649 0Q537 0 420 48L285 -292Q281 -305 270 -316Q252 -334 226 -334Q200 -334 182 -316T164 -272Q164 -258 169 -246Z" />
+<glyph unicode="&#xa3;" glyph-name="sterling" horiz-adv-x="1040" d="M227 0Q201 0 183 18T165 61Q165 72 170 87Q294 374 288 658H144Q118 658 100 676T82 719Q82 745 100 763T144 781H278Q249 935 194 1066L195 1065Q165 1140 165 1213Q165 1375 280 1489Q338
+1546 407 1574T559 1603Q642 1603 711 1575T838 1489Q867 1459 889 1428Q901 1411 901 1389Q901 1363 883 1346T839 1328Q810 1328 795 1347Q777 1373 750 1402Q670 1479 559 1479Q448 1479 368 1400Q289 1323 289 1213Q289 1187 294 1162T311 1112Q343 1037 366
+954T403 781H725Q751 781 769 763T787 719Q787 694 769 676T725 658H413Q414 529 391 396T319 123H769L837 258Q851 287 891 287Q917 287 935 270T953 226Q953 209 946 196L866 37Q861 27 853 19Q834 0 808 0H227Z" />
+<glyph unicode="&#xa4;" glyph-name="currency" horiz-adv-x="960" d="M477 944Q400 944 345 889Q290 832 290 757Q290 682 345 625Q400 570 477 570Q552 570 609 625Q664 682 664 757Q664 832 609 889Q552 944 477 944ZM734 1101Q753 1120 778 1120Q804 1120
+822 1102T840 1058Q840 1032 821 1012L736 932Q788 846 788 757Q788 673 739 587L822 501Q840 482 840 456Q840 430 822 412T778 394Q752 394 736 411L652 498Q566 446 477 446Q391 446 308 495L217 409Q201 394 176 394Q150 394 132 412T114 456Q114 482 133 500L220
+581Q192 624 179 667T166 757Q166 844 215 927L133 1014Q114 1032 114 1058Q114 1084 132 1102T176 1120Q202 1120 219 1104L302 1016Q385 1068 477 1068Q564 1068 647 1019L734 1101Z" />
+<glyph unicode="&#xa5;" glyph-name="yen" horiz-adv-x="1280" d="M142 905Q116 905 98 922T80 966Q80 992 98 1009T142 1027H414L89 1506Q80 1521 80 1542Q80 1567 98 1585T142 1603Q173 1603 192 1578L640 912L1088 1578Q1105 1603 1138 1603Q1164 1603 1182
+1585T1200 1542Q1200 1521 1189 1506L866 1027H1139Q1164 1027 1182 1009Q1200 991 1200 966Q1200 940 1182 922Q1164 905 1139 905H783L702 784V616H1138Q1164 616 1182 599T1200 555Q1200 529 1182 511T1138 493H702V61Q702 36 684 18T640 0Q614 0 596 18T578
+61V493H142Q116 493 98 511T80 555Q80 581 98 598T142 616H578V784L497 905H142Z" />
+<glyph unicode="&#xa6;" glyph-name="brokenbar" horiz-adv-x="480" d="M170 1721Q170 1747 188 1765T232 1784Q258 1784 276 1766T295 1721V975Q295 949 277 931T232 913Q206 913 188 931T170 975V1721ZM295 -418Q295 -444 277 -462T232 -480Q206 -480 188 -462T170
+-418V311Q170 337 188 355T232 373Q258 373 276 355T295 311V-418Z" />
+<glyph unicode="&#xa7;" glyph-name="section" horiz-adv-x="960" d="M477 172Q313 172 198 285Q83 398 83 560Q83 721 198 834Q232 867 262 886Q232 905 198 938Q83 1050 83 1213Q83 1374 198 1487Q256 1543 325 1571T477 1600Q560 1600 629 1572T756 1487Q871
+1374 871 1213Q871 1187 853 1169T809 1151Q783 1151 765 1169T747 1213Q747 1322 667 1398Q587 1477 477 1477Q366 1477 286 1398Q207 1322 207 1213Q207 1102 286 1025Q365 947 477 947Q641 947 756 834Q871 721 871 560Q871 398 756 285Q723 252 692 233Q723
+214 756 181Q871 69 871 -93Q871 -254 756 -367Q698 -423 629 -451T477 -480Q394 -480 325 -452T198 -367Q83 -254 83 -93Q83 -67 101 -49T145 -31Q171 -31 189 -49T207 -93Q207 -202 286 -278Q366 -357 477 -357Q587 -357 667 -278Q747 -202 747 -93Q747 15 667
+93Q587 172 477 172ZM477 825Q366 825 286 746Q207 669 207 560Q207 449 286 372Q365 294 477 294Q588 294 667 372Q747 450 747 560Q747 668 667 746Q587 825 477 825Z" />
+<glyph unicode="&#xa8;" glyph-name="dieresis" horiz-adv-x="960" d="M310 1390Q310 1355 286 1331T227 1307Q192 1307 168 1331T144 1390Q144 1424 168 1448T227 1473Q262 1473 286 1449T310 1390ZM808 1390Q808 1355 784 1331T725 1307Q690 1307 666 1331T642
+1390Q642 1424 666 1448T725 1473Q759 1473 783 1449T808 1390Z" />
+<glyph unicode="&#xa9;" glyph-name="copyright" horiz-adv-x="1760" d="M1199 489Q1225 489 1243 471T1261 426Q1261 401 1242 382Q1166 317 1074 282T879 247Q648 247 485 410Q322 573 322 804Q322 1035 485 1198Q648 1361 879 1361Q981 1361 1074 1326T1242
+1226Q1264 1207 1264 1178Q1264 1152 1246 1134T1202 1116Q1179 1116 1163 1130Q1042 1236 879 1236Q699 1236 573 1110Q447 984 447 804Q447 624 573 498Q700 371 879 371Q957 371 1030 399T1161 477Q1177 489 1199 489ZM1678 802Q1678 470 1443 234Q1208 0 877
+0Q545 0 310 234Q75 470 75 802Q75 1135 310 1367Q543 1603 877 1603Q1209 1603 1443 1367Q1678 1135 1678 802ZM877 1518Q581 1518 370 1307Q161 1098 161 802Q161 505 370 295Q582 85 877 85Q1172 85 1382 295Q1593 506 1593 802Q1593 1099 1382 1307Q1174 1518
+877 1518Z" />
+<glyph unicode="&#xaa;" glyph-name="ordfeminine" horiz-adv-x="960" d="M477 1493Q366 1493 286 1413Q207 1335 207 1224Q207 1112 286 1033Q365 954 477 954Q588 954 667 1033Q747 1113 747 1224Q747 1335 667 1413Q587 1493 477 1493ZM747 939Q635 830 477
+830Q313 830 198 945Q83 1059 83 1224Q83 1388 198 1503Q256 1560 325 1589T477 1618Q560 1618 629 1589T756 1503Q871 1388 871 1224V892Q871 866 853 848T809 830Q783 830 765 848Q747 866 747 891V939Z" />
+<glyph unicode="&#xab;" glyph-name="guillemotleft" horiz-adv-x="960" d="M336 1080Q343 1094 350 1101Q368 1119 394 1119Q420 1119 438 1101T456 1057Q456 1042 451 1031L215 560L451 88Q456 77 456 62Q456 36 438 18T394 0Q369 0 354 14Q345 23 336 38L93
+524Q83 543 83 559Q83 575 91 590L336 1080ZM760 1080Q767 1094 774 1101Q792 1119 818 1119Q844 1119 862 1101T880 1057Q880 1042 875 1031L639 560L875 88Q880 77 880 62Q880 36 862 18T818 0Q793 0 778 14Q769 23 760 38L517 524Q507 543 507 559Q507 575 515
+590L760 1080Z" />
+<glyph unicode="&#xac;" glyph-name="logicalnot" horiz-adv-x="1120" d="M144 996Q118 996 100 1014T81 1058Q81 1084 99 1102T144 1120H973Q999 1120 1017 1102T1035 1058V726Q1035 700 1017 682T973 664Q947 664 929 682T911 726V996H144Z" />
+<glyph unicode="&#xad;" glyph-name="hyphen" horiz-adv-x="800" d="M142 498Q116 498 98 516T79 560Q79 586 97 604T142 622H639Q665 622 683 604T702 560Q702 534 684 516T639 498H142Z" />
+<glyph unicode="&#xae;" glyph-name="registered" horiz-adv-x="1760" d="M1681 800Q1681 469 1447 233Q1212 0 882 0Q551 0 316 233Q82 469 82 800Q82 1132 316 1364Q549 1599 882 1599Q1213 1599 1447 1364Q1681 1132 1681 800ZM882 1514Q587 1514 376 1304Q168
+1095 168 800Q168 504 376 294Q588 85 882 85Q1176 85 1386 294Q1596 505 1596 800Q1596 1096 1386 1304Q1178 1514 882 1514ZM643 1251V779H879Q976 779 1046 849Q1116 917 1116 1016Q1116 1112 1046 1183Q975 1251 879 1251H643ZM879 1317Q1005 1317 1093 1229Q1182
+1141 1182 1016Q1182 954 1160 900T1093 801Q1072 780 1044 762T983 728L1229 334Q1236 324 1236 314Q1236 300 1226 291T1203 281Q1183 281 1173 298L913 716Q895 713 879 713H643V314Q643 300 633 291T608 281Q596 281 586 290T576 314V1285Q576 1299 586 1308T608
+1317H879Z" />
+<glyph unicode="&#xaf;" glyph-name="overscore" horiz-adv-x="1120" d="M144 1825Q118 1825 100 1843T81 1887Q81 1913 99 1931T144 1950H973Q999 1950 1017 1932T1035 1887Q1035 1861 1017 1843T973 1825H144Z" />
+<glyph unicode="&#xb0;" glyph-name="degree" horiz-adv-x="960" d="M871 1224Q871 1059 756 945Q641 830 477 830Q313 830 198 945Q83 1059 83 1224Q83 1388 198 1503Q256 1560 325 1589T477 1618Q560 1618 629 1589T756 1503Q871 1388 871 1224ZM477 1493Q366
+1493 286 1413Q207 1335 207 1224Q207 1112 286 1033Q365 954 477 954Q588 954 667 1033Q747 1113 747 1224Q747 1335 667 1413Q587 1493 477 1493Z" />
+<glyph unicode="&#xb1;" glyph-name="plusminus" horiz-adv-x="1120" d="M496 1224Q496 1250 514 1268T558 1286Q584 1286 602 1268T621 1224V871H973Q999 871 1017 853T1035 809Q1035 783 1017 765T973 747H621V394Q621 368 603 350T558 332Q532 332 514 350T496
+394V747H144Q118 747 100 765T81 809Q81 835 99 853T144 871H496V1224ZM144 0Q118 0 100 18T81 62Q81 88 99 106T144 124H973Q999 124 1017 106T1035 62Q1035 36 1017 18T973 0H144Z" />
+<glyph unicode="&#xb2;" glyph-name="uni00B2" horiz-adv-x="640" d="M517 878Q525 878 531 873T537 859Q537 849 531 844T517 838H107Q86 838 86 859Q86 866 92 874Q179 970 267 1068T443 1262Q468 1288 482 1322T496 1392Q496 1468 442 1522Q387 1577 312 1577Q234
+1577 180 1522Q126 1468 126 1392Q126 1384 121 1378T107 1372Q97 1372 92 1378T86 1392Q86 1486 151 1551Q218 1618 312 1618Q405 1618 471 1551Q537 1486 537 1392Q537 1299 470 1231L152 878H517Z" />
+<glyph unicode="&#xb3;" glyph-name="uni00B3" horiz-adv-x="640" d="M314 1245Q304 1245 299 1251T293 1266Q293 1274 298 1280T314 1287Q374 1287 416 1329Q458 1371 458 1431Q458 1492 416 1534Q374 1576 314 1576Q253 1576 211 1534Q169 1492 169 1431Q169
+1423 163 1417T148 1411Q139 1411 133 1417T127 1431Q127 1509 181 1563Q236 1618 314 1618Q353 1618 385 1604T445 1563Q500 1508 500 1431Q500 1346 409 1267Q432 1253 449 1241T475 1221Q541 1153 541 1059Q541 965 475 898Q409 832 314 832Q218 832 152 898Q86
+965 86 1059Q86 1067 91 1073T107 1080Q115 1080 121 1074T127 1059Q127 981 181 927Q235 873 314 873Q389 873 445 927Q500 982 500 1059Q500 1098 486 1130T445 1191Q389 1245 314 1245Z" />
+<glyph unicode="&#xb4;" glyph-name="acute" horiz-adv-x="560" d="M191 1241Q174 1225 149 1225Q123 1225 105 1243T87 1288Q87 1313 101 1329L353 1581Q371 1599 398 1599Q424 1599 442 1581T460 1537Q460 1525 456 1514T443 1493L191 1241Z" />
+<glyph unicode="&#xb5;" glyph-name="mu" horiz-adv-x="1200" d="M205 519Q205 355 320 240Q439 124 599 124Q761 124 877 240Q993 355 993 519V1058Q993 1084 1011 1102T1055 1120Q1081 1120 1099 1102T1118 1058V62Q1118 36 1100 18T1055 0Q1029 0 1011 18T993
+62V178Q809 0 599 0Q389 0 205 178V-418Q205 -444 187 -462T143 -480Q117 -480 99 -462T81 -418V1058Q81 1084 99 1102T143 1120Q169 1120 187 1102T205 1058V519Z" />
+<glyph unicode="&#xb6;" glyph-name="paragraph" horiz-adv-x="1120" d="M952 62Q952 36 934 18T890 0Q864 0 846 18T828 62V1476H621V62Q621 36 603 18T558 0Q532 0 514 18T496 62V813Q311 813 196 928Q81 1043 81 1207Q81 1290 110 1359T196 1486Q254 1543 323
+1572T475 1601H973Q999 1601 1017 1583T1035 1539Q1035 1513 1011 1495T952 1476V62Z" />
+<glyph unicode="&#xb7;" glyph-name="middot" horiz-adv-x="400" d="M295 767Q295 722 265 694Q236 664 192 664Q148 664 118 694Q88 722 88 767Q88 811 118 841Q148 871 192 871Q236 871 265 841Q295 811 295 767Z" />
+<glyph unicode="&#xb8;" glyph-name="cedilla" horiz-adv-x="640" d="M312 60Q329 77 355 77Q381 77 399 59T418 15Q418 7 416 -1L395 -79Q446 -101 477 -125Q542 -182 542 -265Q542 -346 476 -404Q409 -462 314 -462Q261 -462 205 -434L114 -380Q86 -360 86 -327Q86
+-301 104 -283T148 -265Q167 -265 182 -274L263 -325Q287 -337 314 -337Q357 -337 387 -318T418 -265Q418 -231 388 -212T314 -192Q288 -192 270 -174T252 -130Q252 -119 255 -110L295 33Q300 48 312 60Z" />
+<glyph unicode="&#xb9;" glyph-name="uni00B9" horiz-adv-x="480" d="M153 1535T148 1535Q140 1535 134 1541T128 1555Q128 1563 134 1569Q137 1572 141 1574L265 1617Q269 1618 273 1618Q281 1618 287 1612T294 1597V856Q294 846 288 841T273 835Q265 835 259
+840T253 856V1569L157 1537Q153 1535 148 1535Z" />
+<glyph unicode="&#xba;" glyph-name="ordmasculine" horiz-adv-x="640" d="M86 1227Q86 1466 181 1564Q236 1618 313 1618Q352 1618 384 1605T444 1564Q539 1466 539 1227Q539 987 444 889Q390 835 313 835Q235 835 181 889Q86 987 86 1227ZM313 1577Q252 1577
+209 1533Q127 1440 127 1227Q127 1012 209 919Q252 876 313 876Q372 876 415 919Q499 1013 499 1227Q499 1437 415 1533Q372 1577 313 1577Z" />
+<glyph unicode="&#xbb;" glyph-name="guillemotright" horiz-adv-x="960" d="M872 590Q880 575 880 559Q880 543 870 524L627 38Q618 23 609 14Q594 0 569 0Q543 0 525 18T507 62Q507 77 512 88L748 560L512 1031Q507 1042 507 1057Q507 1083 525 1101T569 1119Q595
+1119 613 1101Q620 1094 627 1080L872 590ZM448 590Q456 575 456 559Q456 543 446 524L203 38Q194 23 185 14Q170 0 145 0Q119 0 101 18T83 62Q83 77 88 88L324 560L88 1031Q83 1042 83 1057Q83 1083 101 1101T145 1119Q171 1119 189 1101Q196 1094 203 1080L448
+590Z" />
+<glyph unicode="&#xbc;" glyph-name="onequarter" horiz-adv-x="1440" d="M1219 1618Q1245 1618 1263 1600T1281 1556Q1281 1537 1272 1521L279 33Q256 0 224 0Q198 0 180 18T161 62Q161 82 171 96L1170 1595Q1178 1606 1190 1612T1219 1618ZM286 693Q286 680
+278 672T257 664Q244 664 236 672T228 693V1548L121 1513Q115 1511 107 1511Q95 1511 87 1519T78 1540Q78 1553 87 1561Q91 1565 98 1568L245 1617Q251 1619 257 1619Q269 1619 277 1611T286 1590V693ZM1157 307V831L795 307H1157ZM738 249Q725 249 717 257T709
+278Q709 287 714 295L1165 946Q1172 954 1186 954Q1199 954 1207 946T1215 925V307H1335Q1348 307 1356 299T1364 278Q1364 265 1356 257T1335 249H1215V29Q1215 16 1207 8T1186 0Q1173 0 1165 8T1157 29V249H738Z" />
+<glyph unicode="&#xbd;" glyph-name="onehalf" horiz-adv-x="1600" d="M1500 58Q1511 58 1520 50T1529 29Q1529 16 1520 8T1500 0H1001Q988 0 980 8T972 29Q972 42 980 50L1406 522Q1471 587 1471 677Q1471 770 1405 833Q1341 897 1250 897Q1160 897 1094 833Q1030
+767 1030 677Q1030 665 1022 657T1001 648Q988 648 980 656T972 677Q972 792 1053 873Q1135 955 1250 955Q1366 955 1447 873Q1529 792 1529 677Q1529 561 1446 478L1067 58H1500ZM286 693Q286 680 278 672T257 664Q244 664 236 672T228 693V1548L121 1513Q115
+1511 107 1511Q95 1511 87 1519T78 1540Q78 1553 87 1561Q91 1565 98 1568L245 1617Q251 1619 257 1619Q269 1619 277 1611T286 1590V693ZM1219 1618Q1245 1618 1263 1600T1281 1556Q1281 1537 1272 1521L279 33Q256 0 224 0Q198 0 180 18T161 62Q161 82 171 96L1170
+1595Q1178 1606 1190 1612T1219 1618Z" />
+<glyph unicode="&#xbe;" glyph-name="threequarters" horiz-adv-x="1600" d="M354 1160Q341 1160 333 1168T325 1189Q325 1200 333 1208T354 1217Q423 1217 473 1267Q524 1318 524 1388Q524 1457 473 1507Q423 1557 354 1557Q285 1557 235 1507Q185 1458 185 1388Q185
+1375 176 1367T156 1359Q143 1359 135 1367T127 1388Q127 1483 193 1548Q260 1615 354 1615Q448 1615 515 1548Q581 1482 581 1388Q581 1293 515 1227Q498 1209 475 1192Q515 1174 550 1138Q631 1055 631 941Q631 826 550 745Q469 664 354 664Q239 664 158 745Q77
+826 77 941Q77 953 85 961T106 970Q119 970 127 962T135 941Q135 850 198 786Q264 722 354 722Q444 722 508 786Q573 851 573 941Q573 1033 508 1096Q445 1160 354 1160ZM1377 1618Q1403 1618 1421 1600T1439 1556Q1439 1537 1430 1521L437 33Q414 0 382 0Q356
+0 338 18T319 62Q319 82 329 96L1328 1595Q1336 1606 1348 1612T1377 1618ZM1328 307V831L966 307H1328ZM909 249Q896 249 888 257T880 278Q880 287 885 295L1336 946Q1343 954 1357 954Q1370 954 1378 946T1386 925V307H1506Q1519 307 1527 299T1535 278Q1535
+265 1527 257T1506 249H1386V29Q1386 16 1378 8T1357 0Q1344 0 1336 8T1328 29V249H909Z" />
+<glyph unicode="&#xbf;" glyph-name="questiondown" horiz-adv-x="1120" d="M557 -355Q704 -355 806 -252Q910 -149 910 -3Q910 144 806 247Q763 287 721 327T635 407V406Q495 546 495 744Q495 770 513 788T557 806Q583 806 601 788T620 744Q620 596 723 493L894
+334V335Q1034 196 1034 -3Q1034 -102 1000 -186T894 -340Q756 -480 557 -480Q361 -480 219 -340Q80 -201 80 -3Q80 23 98 41T143 59Q169 59 187 41T205 -3Q205 -149 307 -252Q411 -355 557 -355ZM558 912Q513 912 485 942Q455 970 455 1015Q455 1059 485 1089Q513
+1119 558 1119Q602 1119 632 1089Q662 1059 662 1015Q662 970 632 942Q602 912 558 912Z" />
+<glyph unicode="&#xc0;" glyph-name="Agrave" horiz-adv-x="1440" d="M421 574L212 38Q206 24 198 16Q181 0 155 0Q129 0 111 18T93 62Q93 75 99 89L670 1556Q676 1572 686 1583Q703 1600 729 1600Q755 1600 773 1582Q783 1572 789 1556L1359 89Q1365 75 1365
+62Q1365 36 1347 18T1304 0Q1278 0 1261 15Q1252 24 1246 38L1038 574H421ZM990 697L729 1369L469 697H990ZM485 2019Q485 2045 503 2063T547 2081Q573 2081 591 2063L843 1811Q858 1794 858 1770Q858 1744 840 1726T796 1707Q772 1707 753 1723L501 1975Q493 1984
+489 1995T485 2019Z" />
+<glyph unicode="&#xc1;" glyph-name="Aacute" horiz-adv-x="1440" d="M421 574L212 38Q206 24 198 16Q181 0 155 0Q129 0 111 18T93 62Q93 75 99 89L670 1556Q676 1572 686 1583Q703 1600 729 1600Q755 1600 773 1582Q783 1572 789 1556L1359 89Q1365 75 1365
+62Q1365 36 1347 18T1304 0Q1278 0 1261 15Q1252 24 1246 38L1038 574H421ZM990 697L729 1369L469 697H990ZM711 1721Q694 1705 669 1705Q643 1705 625 1723T607 1768Q607 1793 621 1809L873 2061Q891 2079 918 2079Q944 2079 962 2061T980 2017Q980 2005 976 1994T963
+1973L711 1721Z" />
+<glyph unicode="&#xc2;" glyph-name="Acircumflex" horiz-adv-x="1440" d="M421 574L212 38Q206 24 198 16Q181 0 155 0Q129 0 111 18T93 62Q93 75 99 89L670 1556Q676 1572 686 1583Q703 1600 729 1600Q755 1600 773 1582Q783 1572 789 1556L1359 89Q1365 75
+1365 62Q1365 36 1347 18T1304 0Q1278 0 1261 15Q1252 24 1246 38L1038 574H421ZM990 697L729 1369L469 697H990ZM1007 1883Q1040 1860 1040 1828Q1040 1802 1022 1784T977 1766Q955 1766 937 1779L728 1918L519 1779Q501 1766 480 1766Q454 1766 436 1784T417
+1828Q417 1860 449 1883L697 2048Q711 2056 728 2056Q746 2056 760 2048L1007 1883Z" />
+<glyph unicode="&#xc3;" glyph-name="Atilde" horiz-adv-x="1440" d="M421 574L212 38Q206 24 198 16Q181 0 155 0Q129 0 111 18T93 62Q93 75 99 89L670 1556Q676 1572 686 1583Q703 1600 729 1600Q755 1600 773 1582Q783 1572 789 1556L1359 89Q1365 75 1365
+62Q1365 36 1347 18T1304 0Q1278 0 1261 15Q1252 24 1246 38L1038 574H421ZM990 697L729 1369L469 697H990ZM767 1838Q680 1760 561 1760Q432 1760 340 1852Q332 1861 328 1872T324 1895Q324 1921 342 1939T386 1958Q411 1958 429 1941Q485 1885 561 1885Q628 1885
+677 1925Q765 2004 885 2004Q1014 2004 1105 1913Q1122 1895 1122 1869Q1122 1843 1104 1825T1060 1807Q1034 1807 1016 1824Q962 1880 885 1880Q820 1880 767 1838Z" />
+<glyph unicode="&#xc4;" glyph-name="Adieresis" horiz-adv-x="1440" d="M421 574L212 38Q206 24 198 16Q181 0 155 0Q129 0 111 18T93 62Q93 75 99 89L670 1556Q676 1572 686 1583Q703 1600 729 1600Q755 1600 773 1582Q783 1572 789 1556L1359 89Q1365 75 1365
+62Q1365 36 1347 18T1304 0Q1278 0 1261 15Q1252 24 1246 38L1038 574H421ZM990 697L729 1369L469 697H990ZM564 1870Q564 1835 540 1811T481 1787Q446 1787 422 1811T398 1870Q398 1904 422 1928T481 1953Q516 1953 540 1929T564 1870ZM1062 1870Q1062 1835 1038
+1811T979 1787Q944 1787 920 1811T896 1870Q896 1904 920 1928T979 1953Q1013 1953 1037 1929T1062 1870Z" />
+<glyph unicode="&#xc5;" glyph-name="Aring" horiz-adv-x="1440" d="M421 574L212 38Q206 24 198 16Q181 0 155 0Q129 0 111 18T93 62Q93 75 99 89L670 1556Q676 1572 686 1583Q703 1600 729 1600Q755 1600 773 1582Q783 1572 789 1556L1359 89Q1365 75 1365 62Q1365
+36 1347 18T1304 0Q1278 0 1261 15Q1252 24 1246 38L1038 574H421ZM990 697L729 1369L469 697H990ZM914 1892Q914 1815 859 1758Q804 1703 726 1703Q649 1703 592 1758Q537 1815 537 1892Q537 1970 592 2025Q649 2080 726 2080Q804 2080 859 2025Q914 1970 914
+1892ZM771 1783T803 1815T835 1892Q835 1937 803 1969T726 2001Q681 2001 649 1969T617 1892Q617 1847 649 1815T726 1783Q771 1783 803 1815Z" />
+<glyph unicode="&#xc6;" glyph-name="AE" horiz-adv-x="1760" d="M900 1300L611 779H900V1300ZM1618 1600Q1644 1600 1661 1582T1679 1538Q1679 1513 1662 1495T1618 1477H1023V779H1454Q1479 779 1497 762T1515 718Q1515 692 1497 674T1454 656H1023V123H1618Q1644
+123 1661 105T1679 62Q1679 36 1662 18T1618 0H961Q935 0 918 18T900 62V656H542L193 29Q174 0 141 0Q115 0 97 18T79 62Q79 79 86 90L909 1572Q926 1600 961 1600H1618Z" />
+<glyph unicode="&#xc7;" glyph-name="Ccedilla" horiz-adv-x="1480" d="M1350 281Q1376 281 1394 263T1412 219Q1412 194 1397 178Q1285 91 1159 46T893 0Q730 0 587 61T327 234Q215 351 154 494T93 800Q93 1131 327 1365Q562 1600 893 1600Q1178 1600 1400 1418Q1418
+1400 1418 1374Q1418 1349 1400 1331T1357 1313Q1331 1313 1306 1337Q1133 1477 893 1477Q613 1477 414 1278Q216 1080 216 800Q216 519 414 321Q612 123 893 123Q1135 123 1317 272Q1330 281 1350 281ZM751 60Q768 77 794 77Q820 77 838 59T857 15Q857 7 855 -1L834
+-79Q885 -101 916 -125Q981 -182 981 -265Q981 -346 915 -404Q848 -462 753 -462Q700 -462 644 -434L553 -380Q525 -360 525 -327Q525 -301 543 -283T587 -265Q606 -265 621 -274L702 -325Q726 -337 753 -337Q796 -337 826 -318T857 -265Q857 -231 827 -212T753
+-192Q727 -192 709 -174T691 -130Q691 -119 694 -110L734 33Q739 48 751 60Z" />
+<glyph unicode="&#xc8;" glyph-name="Egrave" horiz-adv-x="1280" d="M1142 1600Q1167 1600 1185 1582T1203 1538Q1203 1513 1185 1495T1142 1477H218V862H895Q921 862 939 844T957 800Q957 774 939 756T895 738H218V123H1142Q1167 123 1185 105T1203 62Q1203
+36 1185 18T1142 0H157Q131 0 113 18T95 62V1538Q95 1564 113 1582T157 1600H1142ZM408 2019Q408 2045 426 2063T470 2081Q496 2081 514 2063L766 1811Q781 1794 781 1770Q781 1744 763 1726T719 1707Q695 1707 676 1723L424 1975Q416 1984 412 1995T408 2019Z"
+/>
+<glyph unicode="&#xc9;" glyph-name="Eacute" horiz-adv-x="1280" d="M1142 1600Q1167 1600 1185 1582T1203 1538Q1203 1513 1185 1495T1142 1477H218V862H895Q921 862 939 844T957 800Q957 774 939 756T895 738H218V123H1142Q1167 123 1185 105T1203 62Q1203
+36 1185 18T1142 0H157Q131 0 113 18T95 62V1538Q95 1564 113 1582T157 1600H1142ZM634 1721Q617 1705 592 1705Q566 1705 548 1723T530 1768Q530 1793 544 1809L796 2061Q814 2079 841 2079Q867 2079 885 2061T903 2017Q903 2005 899 1994T886 1973L634 1721Z"
+/>
+<glyph unicode="&#xca;" glyph-name="Ecircumflex" horiz-adv-x="1280" d="M1142 1600Q1167 1600 1185 1582T1203 1538Q1203 1513 1185 1495T1142 1477H218V862H895Q921 862 939 844T957 800Q957 774 939 756T895 738H218V123H1142Q1167 123 1185 105T1203 62Q1203
+36 1185 18T1142 0H157Q131 0 113 18T95 62V1538Q95 1564 113 1582T157 1600H1142ZM928 1883Q961 1860 961 1828Q961 1802 943 1784T898 1766Q876 1766 858 1779L649 1918L440 1779Q422 1766 401 1766Q375 1766 357 1784T338 1828Q338 1860 370 1883L618 2048Q632
+2056 649 2056Q667 2056 681 2048L928 1883Z" />
+<glyph unicode="&#xcb;" glyph-name="Edieresis" horiz-adv-x="1280" d="M1142 1600Q1167 1600 1185 1582T1203 1538Q1203 1513 1185 1495T1142 1477H218V862H895Q921 862 939 844T957 800Q957 774 939 756T895 738H218V123H1142Q1167 123 1185 105T1203 62Q1203
+36 1185 18T1142 0H157Q131 0 113 18T95 62V1538Q95 1564 113 1582T157 1600H1142ZM487 1870Q487 1835 463 1811T404 1787Q369 1787 345 1811T321 1870Q321 1904 345 1928T404 1953Q439 1953 463 1929T487 1870ZM985 1870Q985 1835 961 1811T902 1787Q867 1787
+843 1811T819 1870Q819 1904 843 1928T902 1953Q936 1953 960 1929T985 1870Z" />
+<glyph unicode="&#xcc;" glyph-name="Igrave" horiz-adv-x="480" d="M178 1538Q178 1564 195 1582T239 1600Q265 1600 283 1582T301 1538V62Q301 36 283 18T239 0Q213 0 196 18T178 62V1538ZM-6 2019Q-6 2045 12 2063T56 2081Q82 2081 100 2063L352 1811Q367 1794
+367 1770Q367 1744 349 1726T305 1707Q281 1707 262 1723L10 1975Q2 1984 -2 1995T-6 2019Z" />
+<glyph unicode="&#xcd;" glyph-name="Iacute" horiz-adv-x="480" d="M178 1538Q178 1564 195 1582T239 1600Q265 1600 283 1582T301 1538V62Q301 36 283 18T239 0Q213 0 196 18T178 62V1538ZM218 1721Q201 1705 176 1705Q150 1705 132 1723T114 1768Q114 1793
+128 1809L380 2061Q398 2079 425 2079Q451 2079 469 2061T487 2017Q487 2005 483 1994T470 1973L218 1721Z" />
+<glyph unicode="&#xce;" glyph-name="Icircumflex" horiz-adv-x="480" d="M178 1538Q178 1564 195 1582T239 1600Q265 1600 283 1582T301 1538V62Q301 36 283 18T239 0Q213 0 196 18T178 62V1538ZM516 1883Q549 1860 549 1828Q549 1802 531 1784T486 1766Q464
+1766 446 1779L237 1918L28 1779Q10 1766 -11 1766Q-37 1766 -55 1784T-74 1828Q-74 1860 -42 1883L206 2048Q220 2056 237 2056Q255 2056 269 2048L516 1883Z" />
+<glyph unicode="&#xcf;" glyph-name="Idieresis" horiz-adv-x="480" d="M178 1538Q178 1564 195 1582T239 1600Q265 1600 283 1582T301 1538V62Q301 36 283 18T239 0Q213 0 196 18T178 62V1538ZM73 1870Q73 1835 49 1811T-10 1787Q-45 1787 -69 1811T-93 1870Q-93
+1904 -69 1928T-10 1953Q25 1953 49 1929T73 1870ZM571 1870Q571 1835 547 1811T488 1787Q453 1787 429 1811T405 1870Q405 1904 429 1928T488 1953Q522 1953 546 1929T571 1870Z" />
+<glyph unicode="&#xd0;" glyph-name="Eth" horiz-adv-x="1520" d="M244 862V1538Q244 1564 262 1582T306 1600H634Q965 1600 1199 1365Q1434 1131 1434 800Q1434 469 1199 234Q965 0 634 0H306Q280 0 262 18T244 62V738H61Q35 738 17 756T-1 800Q-1 826 17 844T61
+862H244ZM367 862H716Q742 862 760 844T778 800Q778 774 760 756T716 738H367V123H634Q914 123 1112 321Q1311 520 1311 800Q1311 1079 1112 1278Q913 1477 634 1477H367V862Z" />
+<glyph unicode="&#xd1;" glyph-name="Ntilde" horiz-adv-x="1440" d="M216 62Q216 36 199 18T155 0Q129 0 111 18T93 62V1538Q93 1564 111 1582T155 1600Q184 1600 202 1578L1242 241V1538Q1242 1564 1260 1582T1304 1600Q1329 1600 1347 1582T1365 1538V62Q1365
+36 1347 18T1304 0Q1274 0 1258 18L216 1358V62ZM767 1838Q680 1760 561 1760Q432 1760 340 1852Q332 1861 328 1872T324 1895Q324 1921 342 1939T386 1958Q411 1958 429 1941Q485 1885 561 1885Q628 1885 677 1925Q765 2004 885 2004Q1014 2004 1105 1913Q1122
+1895 1122 1869Q1122 1843 1104 1825T1060 1807Q1034 1807 1016 1824Q962 1880 885 1880Q820 1880 767 1838Z" />
+<glyph unicode="&#xd2;" glyph-name="Ograve" horiz-adv-x="1760" d="M891 1477Q613 1477 412 1278Q214 1080 214 800Q214 519 412 321Q611 123 891 123Q1171 123 1369 321Q1568 519 1568 800Q1568 1080 1369 1278Q1170 1477 891 1477ZM1691 800Q1691 469 1456
+234Q1223 0 891 0Q728 0 585 61T325 234Q213 351 152 494T91 800Q91 1131 325 1365Q560 1600 891 1600Q1224 1600 1456 1365Q1691 1131 1691 800ZM723 2019Q723 2045 741 2063T785 2081Q811 2081 829 2063L1081 1811Q1096 1794 1096 1770Q1096 1744 1078 1726T1034
+1707Q1010 1707 991 1723L739 1975Q731 1984 727 1995T723 2019Z" />
+<glyph unicode="&#xd3;" glyph-name="Oacute" horiz-adv-x="1760" d="M891 1477Q613 1477 412 1278Q214 1080 214 800Q214 519 412 321Q611 123 891 123Q1171 123 1369 321Q1568 519 1568 800Q1568 1080 1369 1278Q1170 1477 891 1477ZM1691 800Q1691 469 1456
+234Q1223 0 891 0Q728 0 585 61T325 234Q213 351 152 494T91 800Q91 1131 325 1365Q560 1600 891 1600Q1224 1600 1456 1365Q1691 1131 1691 800ZM799 1721Q782 1705 757 1705Q731 1705 713 1723T695 1768Q695 1793 709 1809L961 2061Q979 2079 1006 2079Q1032
+2079 1050 2061T1068 2017Q1068 2005 1064 1994T1051 1973L799 1721Z" />
+<glyph unicode="&#xd4;" glyph-name="Ocircumflex" horiz-adv-x="1760" d="M891 1477Q613 1477 412 1278Q214 1080 214 800Q214 519 412 321Q611 123 891 123Q1171 123 1369 321Q1568 519 1568 800Q1568 1080 1369 1278Q1170 1477 891 1477ZM1691 800Q1691 469
+1456 234Q1223 0 891 0Q728 0 585 61T325 234Q213 351 152 494T91 800Q91 1131 325 1365Q560 1600 891 1600Q1224 1600 1456 1365Q1691 1131 1691 800ZM1165 1883Q1198 1860 1198 1828Q1198 1802 1180 1784T1135 1766Q1113 1766 1095 1779L886 1918L677 1779Q659
+1766 638 1766Q612 1766 594 1784T575 1828Q575 1860 607 1883L855 2048Q869 2056 886 2056Q904 2056 918 2048L1165 1883Z" />
+<glyph unicode="&#xd5;" glyph-name="Otilde" horiz-adv-x="1760" d="M891 1477Q613 1477 412 1278Q214 1080 214 800Q214 519 412 321Q611 123 891 123Q1171 123 1369 321Q1568 519 1568 800Q1568 1080 1369 1278Q1170 1477 891 1477ZM1691 800Q1691 469 1456
+234Q1223 0 891 0Q728 0 585 61T325 234Q213 351 152 494T91 800Q91 1131 325 1365Q560 1600 891 1600Q1224 1600 1456 1365Q1691 1131 1691 800ZM925 1838Q838 1760 719 1760Q590 1760 498 1852Q490 1861 486 1872T482 1895Q482 1921 500 1939T544 1958Q569 1958
+587 1941Q643 1885 719 1885Q786 1885 835 1925Q923 2004 1043 2004Q1172 2004 1263 1913Q1280 1895 1280 1869Q1280 1843 1262 1825T1218 1807Q1192 1807 1174 1824Q1120 1880 1043 1880Q978 1880 925 1838Z" />
+<glyph unicode="&#xd6;" glyph-name="Odieresis" horiz-adv-x="1760" d="M891 1477Q613 1477 412 1278Q214 1080 214 800Q214 519 412 321Q611 123 891 123Q1171 123 1369 321Q1568 519 1568 800Q1568 1080 1369 1278Q1170 1477 891 1477ZM1691 800Q1691 469 1456
+234Q1223 0 891 0Q728 0 585 61T325 234Q213 351 152 494T91 800Q91 1131 325 1365Q560 1600 891 1600Q1224 1600 1456 1365Q1691 1131 1691 800ZM722 1870Q722 1835 698 1811T639 1787Q604 1787 580 1811T556 1870Q556 1904 580 1928T639 1953Q674 1953 698 1929T722
+1870ZM1220 1870Q1220 1835 1196 1811T1137 1787Q1102 1787 1078 1811T1054 1870Q1054 1904 1078 1928T1137 1953Q1171 1953 1195 1929T1220 1870Z" />
+<glyph unicode="&#xd7;" glyph-name="multiply" horiz-adv-x="960" d="M388 726L99 1014Q83 1032 83 1058Q83 1084 101 1102T145 1120Q171 1120 191 1101L477 815L763 1101Q783 1120 809 1120Q835 1120 853 1102T871 1058Q871 1032 854 1014L566 726L854 438Q871
+420 871 394Q871 368 853 350T809 332Q783 332 766 347L477 637L188 347Q171 332 145 332Q119 332 101 350T83 394Q83 420 99 438L388 726Z" />
+<glyph unicode="&#xd8;" glyph-name="Oslash" horiz-adv-x="1760" d="M1487 1320Q1679 1092 1679 800Q1679 469 1444 234Q1211 0 879 0Q588 0 359 192L185 17Q167 0 141 0Q115 0 97 18T79 62Q79 87 95 104L271 280Q79 509 79 800Q79 1131 313 1365Q548 1600 879
+1600Q1169 1600 1399 1408L1574 1583Q1592 1600 1618 1600Q1644 1600 1661 1582T1679 1538Q1679 1514 1665 1498L1487 1320ZM1312 1321Q1117 1477 879 1477Q601 1477 400 1278Q202 1080 202 800Q202 564 358 367L1312 1321ZM446 279Q642 123 879 123Q1159 123 1357
+321Q1556 519 1556 800Q1556 1037 1400 1234L446 279Z" />
+<glyph unicode="&#xd9;" glyph-name="Ugrave" horiz-adv-x="1280" d="M94 1538Q94 1564 112 1582T156 1600Q182 1600 199 1582T217 1538V554Q217 375 344 249Q470 123 648 123Q827 123 953 249Q1079 375 1079 554V1538Q1079 1564 1097 1582T1141 1600Q1166 1600
+1184 1582T1202 1538V554Q1202 324 1040 162Q878 0 648 0Q418 0 256 162Q175 243 135 340T94 554V1538ZM405 2019Q405 2045 423 2063T467 2081Q493 2081 511 2063L763 1811Q778 1794 778 1770Q778 1744 760 1726T716 1707Q692 1707 673 1723L421 1975Q413 1984
+409 1995T405 2019Z" />
+<glyph unicode="&#xda;" glyph-name="Uacute" horiz-adv-x="1280" d="M94 1538Q94 1564 112 1582T156 1600Q182 1600 199 1582T217 1538V554Q217 375 344 249Q470 123 648 123Q827 123 953 249Q1079 375 1079 554V1538Q1079 1564 1097 1582T1141 1600Q1166 1600
+1184 1582T1202 1538V554Q1202 324 1040 162Q878 0 648 0Q418 0 256 162Q175 243 135 340T94 554V1538ZM631 1721Q614 1705 589 1705Q563 1705 545 1723T527 1768Q527 1793 541 1809L793 2061Q811 2079 838 2079Q864 2079 882 2061T900 2017Q900 2005 896 1994T883
+1973L631 1721Z" />
+<glyph unicode="&#xdb;" glyph-name="Ucircumflex" horiz-adv-x="1280" d="M94 1538Q94 1564 112 1582T156 1600Q182 1600 199 1582T217 1538V554Q217 375 344 249Q470 123 648 123Q827 123 953 249Q1079 375 1079 554V1538Q1079 1564 1097 1582T1141 1600Q1166
+1600 1184 1582T1202 1538V554Q1202 324 1040 162Q878 0 648 0Q418 0 256 162Q175 243 135 340T94 554V1538ZM927 1883Q960 1860 960 1828Q960 1802 942 1784T897 1766Q875 1766 857 1779L648 1918L439 1779Q421 1766 400 1766Q374 1766 356 1784T337 1828Q337
+1860 369 1883L617 2048Q631 2056 648 2056Q666 2056 680 2048L927 1883Z" />
+<glyph unicode="&#xdc;" glyph-name="Udieresis" horiz-adv-x="1280" d="M94 1538Q94 1564 112 1582T156 1600Q182 1600 199 1582T217 1538V554Q217 375 344 249Q470 123 648 123Q827 123 953 249Q1079 375 1079 554V1538Q1079 1564 1097 1582T1141 1600Q1166
+1600 1184 1582T1202 1538V554Q1202 324 1040 162Q878 0 648 0Q418 0 256 162Q175 243 135 340T94 554V1538ZM484 1870Q484 1835 460 1811T401 1787Q366 1787 342 1811T318 1870Q318 1904 342 1928T401 1953Q436 1953 460 1929T484 1870ZM982 1870Q982 1835 958
+1811T899 1787Q864 1787 840 1811T816 1870Q816 1904 840 1928T899 1953Q933 1953 957 1929T982 1870Z" />
+<glyph unicode="&#xdd;" glyph-name="Yacute" horiz-adv-x="1280" d="M710 62Q710 36 692 18T648 0Q622 0 605 18T587 62V782L104 1504Q94 1520 94 1538Q94 1564 112 1582T156 1600Q186 1600 205 1575L648 911L1091 1575Q1109 1600 1141 1600Q1166 1600 1184 1582T1202
+1538Q1202 1518 1192 1504L710 782V62ZM631 1721Q614 1705 589 1705Q563 1705 545 1723T527 1768Q527 1793 541 1809L793 2061Q811 2079 838 2079Q864 2079 882 2061T900 2017Q900 2005 896 1994T883 1973L631 1721Z" />
+<glyph unicode="&#xde;" glyph-name="Thorn" horiz-adv-x="1280" d="M82 1538Q82 1564 100 1582T144 1600Q170 1600 187 1582T205 1538V1272H718Q914 1272 1052 1133Q1190 996 1190 800Q1190 604 1052 466Q914 328 718 328H205V62Q205 36 188 18T144 0Q118 0 100
+18T82 62V1538ZM718 451Q863 451 964 553Q1067 656 1067 800Q1067 944 964 1046Q864 1149 718 1149H205V451H718Z" />
+<glyph unicode="&#xdf;" glyph-name="germandbls" horiz-adv-x="1120" d="M206 62Q206 36 188 18T144 0Q118 0 100 18T81 62V1224Q81 1307 110 1376T196 1503Q254 1560 323 1589T475 1618Q639 1618 754 1503Q869 1388 869 1224Q869 1080 778 972Q748 933 748 878Q748
+785 817 748Q876 717 920 673Q1035 558 1035 394Q1035 230 920 115Q806 0 641 0Q477 0 362 115Q342 137 342 162Q342 188 360 206T404 224Q431 224 452 204Q530 124 641 124Q752 124 831 203Q911 283 911 394Q911 506 832 585Q804 613 769 634Q733 656 701 685Q621
+765 621 879Q621 985 690 1061Q745 1132 745 1224Q745 1335 665 1413Q585 1493 475 1493Q365 1493 286 1415Q206 1335 206 1224V62Z" />
+<glyph unicode="&#xe0;" glyph-name="agrave" horiz-adv-x="1280" d="M652 996Q472 996 344 868Q216 740 216 560Q216 380 344 252Q472 124 652 124Q832 124 960 252Q1087 379 1087 560Q1087 741 960 868Q832 996 652 996ZM1087 203Q885 0 652 0Q420 0 256 164Q92
+328 92 560Q92 792 256 956Q420 1120 652 1120Q884 1120 1048 956Q1212 792 1212 560V62Q1212 36 1194 18T1150 0Q1124 0 1106 18T1087 62V203ZM428 1539Q428 1565 446 1583T490 1601Q516 1601 534 1583L786 1331Q801 1314 801 1290Q801 1264 783 1246T739 1227Q715
+1227 696 1243L444 1495Q436 1504 432 1515T428 1539Z" />
+<glyph unicode="&#xe1;" glyph-name="aacute" horiz-adv-x="1280" d="M652 996Q472 996 344 868Q216 740 216 560Q216 380 344 252Q472 124 652 124Q832 124 960 252Q1087 379 1087 560Q1087 741 960 868Q832 996 652 996ZM1087 203Q885 0 652 0Q420 0 256 164Q92
+328 92 560Q92 792 256 956Q420 1120 652 1120Q884 1120 1048 956Q1212 792 1212 560V62Q1212 36 1194 18T1150 0Q1124 0 1106 18T1087 62V203ZM583 1241Q566 1225 541 1225Q515 1225 497 1243T479 1288Q479 1313 493 1329L745 1581Q763 1599 790 1599Q816 1599
+834 1581T852 1537Q852 1525 848 1514T835 1493L583 1241Z" />
+<glyph unicode="&#xe2;" glyph-name="acircumflex" horiz-adv-x="1280" d="M652 996Q472 996 344 868Q216 740 216 560Q216 380 344 252Q472 124 652 124Q832 124 960 252Q1087 379 1087 560Q1087 741 960 868Q832 996 652 996ZM1087 203Q885 0 652 0Q420 0 256
+164Q92 328 92 560Q92 792 256 956Q420 1120 652 1120Q884 1120 1048 956Q1212 792 1212 560V62Q1212 36 1194 18T1150 0Q1124 0 1106 18T1087 62V203ZM926 1403Q959 1380 959 1348Q959 1322 941 1304T896 1286Q874 1286 856 1299L647 1438L438 1299Q420 1286 399
+1286Q373 1286 355 1304T336 1348Q336 1380 368 1403L616 1568Q630 1576 647 1576Q665 1576 679 1568L926 1403Z" />
+<glyph unicode="&#xe3;" glyph-name="atilde" horiz-adv-x="1280" d="M652 996Q472 996 344 868Q216 740 216 560Q216 380 344 252Q472 124 652 124Q832 124 960 252Q1087 379 1087 560Q1087 741 960 868Q832 996 652 996ZM1087 203Q885 0 652 0Q420 0 256 164Q92
+328 92 560Q92 792 256 956Q420 1120 652 1120Q884 1120 1048 956Q1212 792 1212 560V62Q1212 36 1194 18T1150 0Q1124 0 1106 18T1087 62V203ZM693 1358Q606 1280 487 1280Q358 1280 266 1372Q258 1381 254 1392T250 1415Q250 1441 268 1459T312 1478Q337 1478
+355 1461Q411 1405 487 1405Q554 1405 603 1445Q691 1524 811 1524Q940 1524 1031 1433Q1048 1415 1048 1389Q1048 1363 1030 1345T986 1327Q960 1327 942 1344Q888 1400 811 1400Q746 1400 693 1358Z" />
+<glyph unicode="&#xe4;" glyph-name="adieresis" horiz-adv-x="1280" d="M652 996Q472 996 344 868Q216 740 216 560Q216 380 344 252Q472 124 652 124Q832 124 960 252Q1087 379 1087 560Q1087 741 960 868Q832 996 652 996ZM1087 203Q885 0 652 0Q420 0 256
+164Q92 328 92 560Q92 792 256 956Q420 1120 652 1120Q884 1120 1048 956Q1212 792 1212 560V62Q1212 36 1194 18T1150 0Q1124 0 1106 18T1087 62V203ZM483 1390Q483 1355 459 1331T400 1307Q365 1307 341 1331T317 1390Q317 1424 341 1448T400 1473Q435 1473 459
+1449T483 1390ZM981 1390Q981 1355 957 1331T898 1307Q863 1307 839 1331T815 1390Q815 1424 839 1448T898 1473Q932 1473 956 1449T981 1390Z" />
+<glyph unicode="&#xe5;" glyph-name="aring" horiz-adv-x="1280" d="M652 996Q472 996 344 868Q216 740 216 560Q216 380 344 252Q472 124 652 124Q832 124 960 252Q1087 379 1087 560Q1087 741 960 868Q832 996 652 996ZM1087 203Q885 0 652 0Q420 0 256 164Q92
+328 92 560Q92 792 256 956Q420 1120 652 1120Q884 1120 1048 956Q1212 792 1212 560V62Q1212 36 1194 18T1150 0Q1124 0 1106 18T1087 62V203ZM834 1412Q834 1335 779 1278Q724 1223 646 1223Q569 1223 512 1278Q457 1335 457 1412Q457 1490 512 1545Q569 1600
+646 1600Q724 1600 779 1545Q834 1490 834 1412ZM691 1303T723 1335T755 1412Q755 1457 723 1489T646 1521Q601 1521 569 1489T537 1412Q537 1367 569 1335T646 1303Q691 1303 723 1335Z" />
+<glyph unicode="&#xe6;" glyph-name="ae" horiz-adv-x="2240" d="M631 996Q451 996 323 868Q195 740 195 560Q195 380 323 252Q451 124 631 124Q811 124 939 252Q1067 380 1067 560Q1067 740 939 868Q811 996 631 996ZM2060 622Q2030 773 1935 868Q1805 996 1627
+996Q1447 996 1319 868Q1269 819 1239 758T1193 622H2060ZM1191 62Q1191 36 1173 18T1129 0Q1103 0 1085 18T1067 62V203Q864 0 631 0Q399 0 235 164Q71 328 71 560Q71 792 235 956Q399 1120 631 1120Q863 1120 1027 956Q1074 909 1129 822Q1155 864 1180 897T1230
+956Q1394 1120 1627 1120Q1859 1120 2023 956Q2187 792 2187 560Q2187 534 2169 516T2124 498H1193Q1223 346 1319 252Q1447 124 1627 124Q1708 124 1778 150T1907 227Q1924 241 1946 241Q1972 241 1990 223T2008 178Q2008 150 1992 135Q1836 0 1627 0Q1394 0 1191
+203V62Z" />
+<glyph unicode="&#xe7;" glyph-name="ccedilla" horiz-adv-x="1120" d="M975 243Q1001 243 1019 225T1037 180Q1037 154 1018 135Q942 70 849 35T653 0Q421 0 257 164Q93 328 93 560Q93 792 257 956Q421 1120 653 1120Q756 1120 849 1085T1018 985Q1027 976 1033
+963T1040 936Q1040 910 1022 892T978 874Q954 874 938 889Q816 996 653 996Q473 996 345 868Q218 741 218 560Q218 379 345 252Q473 124 653 124Q732 124 805 153T938 231Q953 243 975 243ZM562 60Q579 77 605 77Q631 77 649 59T668 15Q668 7 666 -1L645 -79Q696
+-101 727 -125Q792 -182 792 -265Q792 -346 726 -404Q659 -462 564 -462Q511 -462 455 -434L364 -380Q336 -360 336 -327Q336 -301 354 -283T398 -265Q417 -265 432 -274L513 -325Q537 -337 564 -337Q607 -337 637 -318T668 -265Q668 -231 638 -212T564 -192Q538
+-192 520 -174T502 -130Q502 -119 505 -110L545 33Q550 48 562 60Z" />
+<glyph unicode="&#xe8;" glyph-name="egrave" horiz-adv-x="1280" d="M1073 622Q1045 771 948 868Q820 996 640 996Q460 996 332 868Q236 772 206 622H1073ZM959 241Q985 241 1003 223T1021 178Q1021 152 1005 135Q849 0 640 0Q408 0 244 164Q80 328 80 560Q80
+792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560Q1200 534 1182 516T1138 498H206Q236 348 332 252Q460 124 640 124Q722 124 792 150T920 227Q937 241 959 241ZM426 1539Q426 1565 444 1583T488 1601Q514 1601 532 1583L784 1331Q799 1314
+799 1290Q799 1264 781 1246T737 1227Q713 1227 694 1243L442 1495Q434 1504 430 1515T426 1539Z" />
+<glyph unicode="&#xe9;" glyph-name="eacute" horiz-adv-x="1280" d="M1073 622Q1045 771 948 868Q820 996 640 996Q460 996 332 868Q236 772 206 622H1073ZM959 241Q985 241 1003 223T1021 178Q1021 152 1005 135Q849 0 640 0Q408 0 244 164Q80 328 80 560Q80
+792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560Q1200 534 1182 516T1138 498H206Q236 348 332 252Q460 124 640 124Q722 124 792 150T920 227Q937 241 959 241ZM584 1241Q567 1225 542 1225Q516 1225 498 1243T480 1288Q480 1313 494 1329L746
+1581Q764 1599 791 1599Q817 1599 835 1581T853 1537Q853 1525 849 1514T836 1493L584 1241Z" />
+<glyph unicode="&#xea;" glyph-name="ecircumflex" horiz-adv-x="1280" d="M1073 622Q1045 771 948 868Q820 996 640 996Q460 996 332 868Q236 772 206 622H1073ZM959 241Q985 241 1003 223T1021 178Q1021 152 1005 135Q849 0 640 0Q408 0 244 164Q80 328 80 560Q80
+792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560Q1200 534 1182 516T1138 498H206Q236 348 332 252Q460 124 640 124Q722 124 792 150T920 227Q937 241 959 241ZM914 1403Q947 1380 947 1348Q947 1322 929 1304T884 1286Q862 1286 844 1299L635
+1438L426 1299Q408 1286 387 1286Q361 1286 343 1304T324 1348Q324 1380 356 1403L604 1568Q618 1576 635 1576Q653 1576 667 1568L914 1403Z" />
+<glyph unicode="&#xeb;" glyph-name="edieresis" horiz-adv-x="1280" d="M1073 622Q1045 771 948 868Q820 996 640 996Q460 996 332 868Q236 772 206 622H1073ZM959 241Q985 241 1003 223T1021 178Q1021 152 1005 135Q849 0 640 0Q408 0 244 164Q80 328 80 560Q80
+792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560Q1200 534 1182 516T1138 498H206Q236 348 332 252Q460 124 640 124Q722 124 792 150T920 227Q937 241 959 241ZM471 1390Q471 1355 447 1331T388 1307Q353 1307 329 1331T305 1390Q305 1424
+329 1448T388 1473Q423 1473 447 1449T471 1390ZM969 1390Q969 1355 945 1331T886 1307Q851 1307 827 1331T803 1390Q803 1424 827 1448T886 1473Q920 1473 944 1449T969 1390Z" />
+<glyph unicode="&#xec;" glyph-name="igrave" horiz-adv-x="480" d="M170 1058Q170 1084 188 1102T232 1120Q258 1120 276 1102T295 1058V62Q295 36 277 18T232 0Q206 0 188 18T170 62V1058ZM277 1539Q277 1565 295 1583T339 1601Q365 1601 383 1583L635 1331Q650
+1314 650 1290Q650 1264 632 1246T588 1227Q564 1227 545 1243L293 1495Q285 1504 281 1515T277 1539Z" />
+<glyph unicode="&#xed;" glyph-name="iacute" horiz-adv-x="480" d="M170 1058Q170 1084 188 1102T232 1120Q258 1120 276 1102T295 1058V62Q295 36 277 18T232 0Q206 0 188 18T170 62V1058ZM193 1241Q176 1225 151 1225Q125 1225 107 1243T89 1288Q89 1313 103
+1329L355 1581Q373 1599 400 1599Q426 1599 444 1581T462 1537Q462 1525 458 1514T445 1493L193 1241Z" />
+<glyph unicode="&#xee;" glyph-name="icircumflex" horiz-adv-x="560" d="M211 1058Q211 1084 229 1102T273 1120Q299 1120 317 1102T336 1058V62Q336 36 318 18T273 0Q247 0 229 18T211 62V1058ZM812 1403Q845 1380 845 1348Q845 1322 827 1304T782 1286Q760
+1286 742 1299L533 1438L324 1299Q306 1286 285 1286Q259 1286 241 1304T222 1348Q222 1380 254 1403L502 1568Q516 1576 533 1576Q551 1576 565 1568L812 1403Z" />
+<glyph unicode="&#xef;" glyph-name="idieresis" horiz-adv-x="600" d="M230 1058Q230 1084 248 1102T292 1120Q318 1120 336 1102T355 1058V62Q355 36 337 18T292 0Q266 0 248 18T230 62V1058ZM134 1390Q134 1355 110 1331T51 1307Q16 1307 -8 1331T-32 1390Q-32
+1424 -8 1448T51 1473Q86 1473 110 1449T134 1390ZM632 1390Q632 1355 608 1331T549 1307Q514 1307 490 1331T466 1390Q466 1424 490 1448T549 1473Q583 1473 607 1449T632 1390Z" />
+<glyph unicode="&#xf0;" glyph-name="eth" horiz-adv-x="1280" d="M640 996Q460 996 332 868Q204 740 204 560Q204 380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996ZM633 1443L588 1519Q578 1539 578 1556Q578
+1582 596 1600T640 1618Q675 1618 693 1590L741 1507L900 1599Q914 1607 931 1607Q948 1607 962 1600T985 1577Q993 1565 993 1545Q993 1529 985 1515T963 1491L804 1398Q1011 1040 1052 968T1133 829Q1165 770 1182 701T1200 560Q1200 328 1036 164Q872 0 640
+0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q681 1120 729 1113T838 1088L695 1335L532 1240Q518 1232 502 1232Q468 1232 450 1260Q440 1277 440 1294Q440 1310 448 1325T470 1348L633 1443Z" />
+<glyph unicode="&#xf1;" glyph-name="ntilde" horiz-adv-x="1200" d="M81 1058Q81 1084 99 1102T143 1120Q169 1120 187 1102T205 1058V942Q389 1120 599 1120Q815 1120 965 968Q1118 816 1118 601V62Q1118 36 1100 18T1055 0Q1029 0 1011 18T993 62V601Q993 766
+877 879Q761 996 599 996Q437 996 320 879Q205 765 205 601V62Q205 36 187 18T143 0Q117 0 99 18T81 62V1058ZM646 1358Q559 1280 440 1280Q311 1280 219 1372Q211 1381 207 1392T203 1415Q203 1441 221 1459T265 1478Q290 1478 308 1461Q364 1405 440 1405Q507
+1405 556 1445Q644 1524 764 1524Q893 1524 984 1433Q1001 1415 1001 1389Q1001 1363 983 1345T939 1327Q913 1327 895 1344Q841 1400 764 1400Q699 1400 646 1358Z" />
+<glyph unicode="&#xf2;" glyph-name="ograve" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164Q872 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560ZM640 996Q460 996 332 868Q204 740 204 560Q204
+380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996ZM426 1539Q426 1565 444 1583T488 1601Q514 1601 532 1583L784 1331Q799 1314 799 1290Q799 1264 781 1246T737 1227Q713 1227 694 1243L442 1495Q434 1504 430
+1515T426 1539Z" />
+<glyph unicode="&#xf3;" glyph-name="oacute" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164Q872 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560ZM640 996Q460 996 332 868Q204 740 204 560Q204
+380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996ZM583 1241Q566 1225 541 1225Q515 1225 497 1243T479 1288Q479 1313 493 1329L745 1581Q763 1599 790 1599Q816 1599 834 1581T852 1537Q852 1525 848 1514T835
+1493L583 1241Z" />
+<glyph unicode="&#xf4;" glyph-name="ocircumflex" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164Q872 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560ZM640 996Q460 996 332 868Q204 740
+204 560Q204 380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996ZM914 1403Q947 1380 947 1348Q947 1322 929 1304T884 1286Q862 1286 844 1299L635 1438L426 1299Q408 1286 387 1286Q361 1286 343 1304T324 1348Q324
+1380 356 1403L604 1568Q618 1576 635 1576Q653 1576 667 1568L914 1403Z" />
+<glyph unicode="&#xf5;" glyph-name="otilde" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164Q872 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560ZM640 996Q460 996 332 868Q204 740 204 560Q204
+380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996ZM681 1358Q594 1280 475 1280Q346 1280 254 1372Q246 1381 242 1392T238 1415Q238 1441 256 1459T300 1478Q325 1478 343 1461Q399 1405 475 1405Q542 1405 591
+1445Q679 1524 799 1524Q928 1524 1019 1433Q1036 1415 1036 1389Q1036 1363 1018 1345T974 1327Q948 1327 930 1344Q876 1400 799 1400Q734 1400 681 1358Z" />
+<glyph unicode="&#xf6;" glyph-name="odieresis" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164Q872 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q872 1120 1036 956Q1200 792 1200 560ZM640 996Q460 996 332 868Q204 740 204
+560Q204 380 332 252Q460 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 741 948 868Q820 996 640 996ZM471 1390Q471 1355 447 1331T388 1307Q353 1307 329 1331T305 1390Q305 1424 329 1448T388 1473Q423 1473 447 1449T471 1390ZM969 1390Q969 1355 945
+1331T886 1307Q851 1307 827 1331T803 1390Q803 1424 827 1448T886 1473Q920 1473 944 1449T969 1390Z" />
+<glyph unicode="&#xf7;" glyph-name="divide" horiz-adv-x="960" d="M560 1037Q560 1002 536 978T477 954Q442 954 418 978T394 1037Q394 1072 418 1096T477 1120Q512 1120 536 1096T560 1037ZM145 664Q119 664 101 682T83 726Q83 752 101 770T145 788H809Q835
+788 853 770T871 726Q871 700 853 682T809 664H145ZM560 415Q560 380 536 356T477 332Q442 332 418 356T394 415Q394 449 418 473T477 498Q512 498 536 474T560 415Z" />
+<glyph unicode="&#xf8;" glyph-name="oslash" horiz-adv-x="1280" d="M901 909Q773 996 640 996Q460 996 332 868Q204 740 204 560Q204 428 289 299L901 909ZM379 209Q508 124 640 124Q820 124 948 252Q1075 379 1075 560Q1075 692 990 821L379 209ZM1091 1099Q1110
+1120 1138 1120Q1164 1120 1182 1102T1200 1058Q1200 1032 1183 1014L1079 909Q1200 752 1200 560Q1200 328 1036 164Q872 0 640 0Q447 0 290 121L187 18Q168 0 142 0Q116 0 98 18T80 62Q80 88 96 106L201 211Q80 366 80 560Q80 792 244 956Q408 1120 640 1120Q833
+1120 990 999L1091 1099Z" />
+<glyph unicode="&#xf9;" glyph-name="ugrave" horiz-adv-x="1200" d="M1118 62Q1118 36 1100 18T1055 0Q1029 0 1011 18T993 62V178Q809 0 599 0Q386 0 232 151Q81 303 81 519V1058Q81 1084 99 1102T143 1120Q169 1120 187 1102T205 1058V519Q205 355 320 240Q439
+124 599 124Q761 124 877 240Q993 355 993 519V1058Q993 1084 1011 1102T1055 1120Q1081 1120 1099 1102T1118 1058V62ZM419 1539Q419 1565 437 1583T481 1601Q507 1601 525 1583L777 1331Q792 1314 792 1290Q792 1264 774 1246T730 1227Q706 1227 687 1243L435
+1495Q427 1504 423 1515T419 1539Z" />
+<glyph unicode="&#xfa;" glyph-name="uacute" horiz-adv-x="1200" d="M1118 62Q1118 36 1100 18T1055 0Q1029 0 1011 18T993 62V178Q809 0 599 0Q386 0 232 151Q81 303 81 519V1058Q81 1084 99 1102T143 1120Q169 1120 187 1102T205 1058V519Q205 355 320 240Q439
+124 599 124Q761 124 877 240Q993 355 993 519V1058Q993 1084 1011 1102T1055 1120Q1081 1120 1099 1102T1118 1058V62ZM511 1241Q494 1225 469 1225Q443 1225 425 1243T407 1288Q407 1313 421 1329L673 1581Q691 1599 718 1599Q744 1599 762 1581T780 1537Q780
+1525 776 1514T763 1493L511 1241Z" />
+<glyph unicode="&#xfb;" glyph-name="ucircumflex" horiz-adv-x="1200" d="M1118 62Q1118 36 1100 18T1055 0Q1029 0 1011 18T993 62V178Q809 0 599 0Q386 0 232 151Q81 303 81 519V1058Q81 1084 99 1102T143 1120Q169 1120 187 1102T205 1058V519Q205 355 320
+240Q439 124 599 124Q761 124 877 240Q993 355 993 519V1058Q993 1084 1011 1102T1055 1120Q1081 1120 1099 1102T1118 1058V62ZM874 1403Q907 1380 907 1348Q907 1322 889 1304T844 1286Q822 1286 804 1299L595 1438L386 1299Q368 1286 347 1286Q321 1286 303
+1304T284 1348Q284 1380 316 1403L564 1568Q578 1576 595 1576Q613 1576 627 1568L874 1403Z" />
+<glyph unicode="&#xfc;" glyph-name="udieresis" horiz-adv-x="1200" d="M1118 62Q1118 36 1100 18T1055 0Q1029 0 1011 18T993 62V178Q809 0 599 0Q386 0 232 151Q81 303 81 519V1058Q81 1084 99 1102T143 1120Q169 1120 187 1102T205 1058V519Q205 355 320 240Q439
+124 599 124Q761 124 877 240Q993 355 993 519V1058Q993 1084 1011 1102T1055 1120Q1081 1120 1099 1102T1118 1058V62ZM431 1390Q431 1355 407 1331T348 1307Q313 1307 289 1331T265 1390Q265 1424 289 1448T348 1473Q383 1473 407 1449T431 1390ZM929 1390Q929
+1355 905 1331T846 1307Q811 1307 787 1331T763 1390Q763 1424 787 1448T846 1473Q880 1473 904 1449T929 1390Z" />
+<glyph unicode="&#xfd;" glyph-name="yacute" horiz-adv-x="1120" d="M490 63L85 1033Q81 1046 81 1058Q81 1084 99 1102T144 1120Q170 1120 188 1102Q197 1093 203 1077L558 227L913 1077Q919 1093 930 1104Q946 1120 973 1120Q999 1120 1017 1102T1036 1058Q1036
+1048 1032 1036L416 -438Q411 -452 402 -461Q383 -480 357 -480Q331 -480 313 -462T295 -418Q295 -405 299 -396L490 63ZM538 1241Q521 1225 496 1225Q470 1225 452 1243T434 1288Q434 1313 448 1329L700 1581Q718 1599 745 1599Q771 1599 789 1581T807 1537Q807
+1525 803 1514T790 1493L538 1241Z" />
+<glyph unicode="&#xfe;" glyph-name="thorn" horiz-adv-x="1280" d="M204 562Q204 382 332 254Q459 127 640 127Q821 127 948 254Q1075 381 1075 562Q1075 743 948 870Q820 998 640 998Q460 998 332 870Q204 742 204 562ZM204 919Q407 1122 640 1122Q872 1122
+1036 958Q1200 794 1200 562Q1200 330 1036 166Q872 2 640 2Q407 2 204 205V-418Q204 -444 186 -462T142 -480Q116 -480 98 -462T80 -418V1538Q80 1564 98 1582T142 1600Q168 1600 186 1582T204 1538V919Z" />
+<glyph unicode="&#xff;" glyph-name="ydieresis" horiz-adv-x="1120" d="M490 63L85 1033Q81 1046 81 1058Q81 1084 99 1102T144 1120Q170 1120 188 1102Q197 1093 203 1077L558 227L913 1077Q919 1093 930 1104Q946 1120 973 1120Q999 1120 1017 1102T1036 1058Q1036
+1048 1032 1036L416 -438Q411 -452 402 -461Q383 -480 357 -480Q331 -480 313 -462T295 -418Q295 -405 299 -396L490 63ZM391 1390Q391 1355 367 1331T308 1307Q273 1307 249 1331T225 1390Q225 1424 249 1448T308 1473Q343 1473 367 1449T391 1390ZM889 1390Q889
+1355 865 1331T806 1307Q771 1307 747 1331T723 1390Q723 1424 747 1448T806 1473Q840 1473 864 1449T889 1390Z" />
+<glyph unicode="&#x2013;" glyph-name="endash" horiz-adv-x="800" d="M-19 498Q-45 498 -63 516T-82 560Q-82 586 -64 604T-19 622H810Q836 622 854 604T872 560Q872 534 854 516T810 498H-19Z" />
+<glyph unicode="&#x2014;" glyph-name="emdash" horiz-adv-x="1920" d="M-30 498Q-56 498 -74 516T-92 560Q-92 586 -74 604T-30 622H1961Q1987 622 2005 604T2024 560Q2024 534 2006 516T1961 498H-30Z" />
+<glyph unicode="&#x2018;" glyph-name="quoteleft" horiz-adv-x="480" d="M350 1041Q350 1006 326 982T267 958Q216 958 191 1007Q129 1116 129 1233Q129 1318 169 1410T281 1590Q292 1601 309 1601Q326 1601 338 1589T350 1560Q350 1552 346 1542Q320 1477 306
+1416T292 1294Q292 1236 305 1181T343 1074Q350 1058 350 1041Z" />
+<glyph unicode="&#x2019;" glyph-name="quoteright" horiz-adv-x="480" d="M129 1519Q129 1554 153 1578T212 1602Q263 1602 288 1553Q350 1444 350 1327Q350 1242 310 1150T198 970Q187 959 170 959Q153 959 141 971T129 1000Q129 1008 133 1018Q159 1083 173
+1144T187 1266Q187 1324 174 1379T136 1486Q129 1502 129 1519Z" />
+<glyph unicode="&#x201a;" glyph-name="quotesinglbase" horiz-adv-x="480" d="M129 237Q129 272 153 296T212 320Q263 320 288 271Q350 162 350 45Q350 -40 310 -132T198 -312Q187 -323 170 -323Q153 -323 141 -311T129 -282Q129 -274 133 -264Q159 -199 173
+-138T187 -16Q187 42 174 97T136 204Q129 220 129 237Z" />
+<glyph unicode="&#x201c;" glyph-name="quotedblleft" horiz-adv-x="760" d="M301 1041Q301 1006 277 982T218 958Q167 958 142 1007Q80 1116 80 1233Q80 1318 120 1410T232 1590Q243 1601 260 1601Q277 1601 289 1589T301 1560Q301 1552 297 1542Q271 1477 257
+1416T243 1294Q243 1236 256 1181T294 1074Q301 1058 301 1041ZM659 1041Q659 1006 635 982T576 958Q525 958 500 1007Q438 1116 438 1233Q438 1318 478 1410T590 1590Q601 1601 618 1601Q635 1601 647 1589T659 1560Q659 1552 655 1542Q629 1477 615 1416T601
+1294Q601 1236 614 1181T652 1074Q659 1058 659 1041Z" />
+<glyph unicode="&#x201d;" glyph-name="quotedblright" horiz-adv-x="760" d="M438 1518Q438 1553 462 1577T521 1601Q572 1601 597 1552Q659 1443 659 1326Q659 1241 619 1149T507 969Q496 958 479 958Q462 958 450 970T438 999Q438 1007 442 1017Q468 1082 482
+1143T496 1265Q496 1323 483 1378T445 1485Q438 1501 438 1518ZM80 1518Q80 1553 104 1577T163 1601Q214 1601 239 1552Q301 1443 301 1326Q301 1241 261 1149T149 969Q138 958 121 958Q104 958 92 970T80 999Q80 1007 84 1017Q110 1082 124 1143T138 1265Q138
+1323 125 1378T87 1485Q80 1501 80 1518Z" />
+<glyph unicode="&#x201e;" glyph-name="quotedblbase" horiz-adv-x="760" d="M438 237Q438 272 462 296T521 320Q572 320 597 271Q659 162 659 45Q659 -40 619 -132T507 -312Q496 -323 479 -323Q462 -323 450 -311T438 -282Q438 -274 442 -264Q468 -199 482 -138T496
+-16Q496 42 483 97T445 204Q438 220 438 237ZM80 237Q80 272 104 296T163 320Q214 320 239 271Q301 162 301 45Q301 -40 261 -132T149 -312Q138 -323 121 -323Q104 -323 92 -311T80 -282Q80 -274 84 -264Q110 -199 124 -138T138 -16Q138 42 125 97T87 204Q80 220
+80 237Z" />
+<glyph unicode="&#x2022;" glyph-name="bullet" horiz-adv-x="800" d="M624 809Q624 715 556 647Q490 581 395 581Q300 581 234 647Q167 714 167 809Q167 903 234 970Q301 1037 395 1037Q489 1037 556 970Q624 902 624 809Z" />
+<glyph unicode="&#x2039;" glyph-name="guilsinglleft" horiz-adv-x="560" d="M336 1080Q343 1094 350 1101Q368 1119 394 1119Q420 1119 438 1101T456 1057Q456 1042 451 1031L215 560L451 88Q456 77 456 62Q456 36 438 18T394 0Q369 0 354 14Q345 23 336 38L93
+524Q83 543 83 559Q83 575 91 590L336 1080Z" />
+<glyph unicode="&#x203a;" glyph-name="guilsinglright" horiz-adv-x="560" d="M448 590Q456 575 456 559Q456 543 446 524L203 38Q194 23 185 14Q170 0 145 0Q119 0 101 18T83 62Q83 77 88 88L324 560L88 1031Q83 1042 83 1057Q83 1083 101 1101T145 1119Q171
+1119 189 1101Q196 1094 203 1080L448 590Z" />
+<hkern g1="A" g2="C" k="98" />
+<hkern g1="A" g2="G" k="98" />
+<hkern g1="A" g2="O" k="69" />
+<hkern g1="A" g2="Q" k="69" />
+<hkern g1="A" g2="T" k="179" />
+<hkern g1="A" g2="V" k="189" />
+<hkern g1="A" g2="W" k="116" />
+<hkern g1="A" g2="Y" k="179" />
+<hkern g1="A" g2="f" k="64" />
+<hkern g1="A" g2="j" k="186" />
+<hkern g1="A" g2="t" k="148" />
+<hkern g1="A" g2="v" k="206" />
+<hkern g1="A" g2="w" k="143" />
+<hkern g1="A" g2="y" k="206" />
+<hkern g1="A" g2="Ccedilla" k="98" />
+<hkern g1="A" g2="Eth" k="52" />
+<hkern g1="A" g2="Ograve" k="69" />
+<hkern g1="A" g2="Oacute" k="69" />
+<hkern g1="A" g2="Ocircumflex" k="69" />
+<hkern g1="A" g2="Otilde" k="69" />
+<hkern g1="A" g2="Odieresis" k="69" />
+<hkern g1="A" g2="Yacute" k="179" />
+<hkern g1="A" g2="yacute" k="206" />
+<hkern g1="A" g2="ydieresis" k="206" />
+<hkern g1="B" g2="T" k="107" />
+<hkern g1="B" g2="V" k="127" />
+<hkern g1="B" g2="W" k="100" />
+<hkern g1="B" g2="Y" k="107" />
+<hkern g1="B" g2="j" k="230" />
+<hkern g1="B" g2="x" k="65" />
+<hkern g1="B" g2="y" k="65" />
+<hkern g1="B" g2="Yacute" k="107" />
+<hkern g1="B" g2="yacute" k="65" />
+<hkern g1="B" g2="ydieresis" k="65" />
+<hkern g1="C" g2="C" k="74" />
+<hkern g1="C" g2="G" k="74" />
+<hkern g1="C" g2="O" k="45" />
+<hkern g1="C" g2="Q" k="45" />
+<hkern g1="C" g2="f" k="91" />
+<hkern g1="C" g2="j" k="256" />
+<hkern g1="C" g2="t" k="40" />
+<hkern g1="C" g2="v" k="84" />
+<hkern g1="C" g2="w" k="89" />
+<hkern g1="C" g2="y" k="116" />
+<hkern g1="C" g2="Ccedilla" k="74" />
+<hkern g1="C" g2="Ograve" k="45" />
+<hkern g1="C" g2="Oacute" k="45" />
+<hkern g1="C" g2="Ocircumflex" k="45" />
+<hkern g1="C" g2="Otilde" k="45" />
+<hkern g1="C" g2="Odieresis" k="45" />
+<hkern g1="C" g2="yacute" k="79" />
+<hkern g1="C" g2="ydieresis" k="62" />
+<hkern g1="D" g2="A" k="113" />
+<hkern g1="D" g2="T" k="143" />
+<hkern g1="D" g2="V" k="113" />
+<hkern g1="D" g2="X" k="158" />
+<hkern g1="D" g2="Y" k="126" />
+<hkern g1="D" g2="Z" k="158" />
+<hkern g1="D" g2="j" k="276" />
+<hkern g1="D" g2="Agrave" k="113" />
+<hkern g1="D" g2="Aacute" k="113" />
+<hkern g1="D" g2="Acircumflex" k="113" />
+<hkern g1="D" g2="Atilde" k="113" />
+<hkern g1="D" g2="Adieresis" k="113" />
+<hkern g1="D" g2="Aring" k="113" />
+<hkern g1="D" g2="AE" k="95" />
+<hkern g1="D" g2="Yacute" k="126" />
+<hkern g1="E" g2="C" k="109" />
+<hkern g1="E" g2="G" k="109" />
+<hkern g1="E" g2="O" k="109" />
+<hkern g1="E" g2="Q" k="109" />
+<hkern g1="E" g2="c" k="65" />
+<hkern g1="E" g2="f" k="62" />
+<hkern g1="E" g2="j" k="184" />
+<hkern g1="E" g2="t" k="62" />
+<hkern g1="E" g2="v" k="90" />
+<hkern g1="E" g2="w" k="141" />
+<hkern g1="E" g2="y" k="122" />
+<hkern g1="E" g2="Ccedilla" k="109" />
+<hkern g1="E" g2="Eth" k="50" />
+<hkern g1="E" g2="Ograve" k="109" />
+<hkern g1="E" g2="Oacute" k="109" />
+<hkern g1="E" g2="Ocircumflex" k="109" />
+<hkern g1="E" g2="Otilde" k="109" />
+<hkern g1="E" g2="Odieresis" k="109" />
+<hkern g1="E" g2="ae" k="48" />
+<hkern g1="E" g2="ccedilla" k="65" />
+<hkern g1="E" g2="eth" k="57" />
+<hkern g1="E" g2="yacute" k="109" />
+<hkern g1="E" g2="ydieresis" k="65" />
+<hkern g1="F" g2="A" k="183" />
+<hkern g1="F" g2="C" k="109" />
+<hkern g1="F" g2="G" k="109" />
+<hkern g1="F" g2="J" k="148" />
+<hkern g1="F" g2="O" k="109" />
+<hkern g1="F" g2="Q" k="109" />
+<hkern g1="F" g2="S" k="99" />
+<hkern g1="F" g2="a" k="141" />
+<hkern g1="F" g2="c" k="141" />
+<hkern g1="F" g2="d" k="141" />
+<hkern g1="F" g2="e" k="141" />
+<hkern g1="F" g2="f" k="109" />
+<hkern g1="F" g2="g" k="141" />
+<hkern g1="F" g2="j" k="222" />
+<hkern g1="F" g2="m" k="109" />
+<hkern g1="F" g2="n" k="109" />
+<hkern g1="F" g2="o" k="141" />
+<hkern g1="F" g2="p" k="141" />
+<hkern g1="F" g2="q" k="141" />
+<hkern g1="F" g2="r" k="109" />
+<hkern g1="F" g2="s" k="109" />
+<hkern g1="F" g2="t" k="62" />
+<hkern g1="F" g2="u" k="109" />
+<hkern g1="F" g2="v" k="172" />
+<hkern g1="F" g2="w" k="172" />
+<hkern g1="F" g2="x" k="204" />
+<hkern g1="F" g2="y" k="172" />
+<hkern g1="F" g2="z" k="60" />
+<hkern g1="F" g2="Agrave" k="183" />
+<hkern g1="F" g2="Aacute" k="175" />
+<hkern g1="F" g2="Acircumflex" k="183" />
+<hkern g1="F" g2="Atilde" k="167" />
+<hkern g1="F" g2="Adieresis" k="183" />
+<hkern g1="F" g2="Aring" k="198" />
+<hkern g1="F" g2="AE" k="285" />
+<hkern g1="F" g2="Ccedilla" k="109" />
+<hkern g1="F" g2="Eth" k="50" />
+<hkern g1="F" g2="Ograve" k="109" />
+<hkern g1="F" g2="Oacute" k="109" />
+<hkern g1="F" g2="Ocircumflex" k="109" />
+<hkern g1="F" g2="Otilde" k="109" />
+<hkern g1="F" g2="Odieresis" k="109" />
+<hkern g1="F" g2="Oslash" k="109" />
+<hkern g1="F" g2="agrave" k="141" />
+<hkern g1="F" g2="aacute" k="141" />
+<hkern g1="F" g2="acircumflex" k="141" />
+<hkern g1="F" g2="adieresis" k="141" />
+<hkern g1="F" g2="aring" k="141" />
+<hkern g1="F" g2="ae" k="141" />
+<hkern g1="F" g2="ccedilla" k="141" />
+<hkern g1="F" g2="egrave" k="141" />
+<hkern g1="F" g2="eacute" k="141" />
+<hkern g1="F" g2="ecircumflex" k="141" />
+<hkern g1="F" g2="edieresis" k="141" />
+<hkern g1="F" g2="eth" k="141" />
+<hkern g1="F" g2="ograve" k="141" />
+<hkern g1="F" g2="oacute" k="141" />
+<hkern g1="F" g2="ocircumflex" k="141" />
+<hkern g1="F" g2="odieresis" k="141" />
+<hkern g1="F" g2="oslash" k="141" />
+<hkern g1="F" g2="ugrave" k="109" />
+<hkern g1="F" g2="uacute" k="109" />
+<hkern g1="F" g2="ucircumflex" k="109" />
+<hkern g1="F" g2="udieresis" k="109" />
+<hkern g1="F" g2="yacute" k="172" />
+<hkern g1="F" g2="ydieresis" k="65" />
+<hkern g1="F" g2="dotlessi" k="189" />
+<hkern g1="G" g2="f" k="60" />
+<hkern g1="G" g2="j" k="198" />
+<hkern g1="G" g2="t" k="60" />
+<hkern g1="H" g2="j" k="159" />
+<hkern g1="I" g2="I" k="26" />
+<hkern g1="I" g2="j" k="192" />
+<hkern g1="I" g2="Igrave" k="60" />
+<hkern g1="I" g2="Iacute" k="66" />
+<hkern g1="I" g2="Icircumflex" k="73" />
+<hkern g1="I" g2="Idieresis" k="52" />
+<hkern g1="I" g2="dotlessi" k="51" />
+<hkern g1="J" g2="j" k="145" />
+<hkern g1="K" g2="C" k="124" />
+<hkern g1="K" g2="G" k="124" />
+<hkern g1="K" g2="O" k="124" />
+<hkern g1="K" g2="Q" k="124" />
+<hkern g1="K" g2="a" k="89" />
+<hkern g1="K" g2="c" k="81" />
+<hkern g1="K" g2="d" k="89" />
+<hkern g1="K" g2="e" k="83" />
+<hkern g1="K" g2="f" k="65" />
+<hkern g1="K" g2="j" k="180" />
+<hkern g1="K" g2="o" k="83" />
+<hkern g1="K" g2="q" k="83" />
+<hkern g1="K" g2="t" k="71" />
+<hkern g1="K" g2="v" k="117" />
+<hkern g1="K" g2="w" k="155" />
+<hkern g1="K" g2="y" k="71" />
+<hkern g1="K" g2="Ccedilla" k="105" />
+<hkern g1="K" g2="Ograve" k="124" />
+<hkern g1="K" g2="Oacute" k="124" />
+<hkern g1="K" g2="Ocircumflex" k="124" />
+<hkern g1="K" g2="Otilde" k="124" />
+<hkern g1="K" g2="Odieresis" k="124" />
+<hkern g1="K" g2="agrave" k="101" />
+<hkern g1="K" g2="aacute" k="83" />
+<hkern g1="K" g2="acircumflex" k="76" />
+<hkern g1="K" g2="atilde" k="70" />
+<hkern g1="K" g2="adieresis" k="83" />
+<hkern g1="K" g2="aring" k="76" />
+<hkern g1="K" g2="ae" k="95" />
+<hkern g1="K" g2="ccedilla" k="87" />
+<hkern g1="K" g2="egrave" k="76" />
+<hkern g1="K" g2="eacute" k="76" />
+<hkern g1="K" g2="ecircumflex" k="95" />
+<hkern g1="K" g2="edieresis" k="95" />
+<hkern g1="K" g2="eth" k="85" />
+<hkern g1="K" g2="ograve" k="76" />
+<hkern g1="K" g2="oacute" k="89" />
+<hkern g1="K" g2="ocircumflex" k="83" />
+<hkern g1="K" g2="otilde" k="76" />
+<hkern g1="K" g2="odieresis" k="95" />
+<hkern g1="K" g2="yacute" k="143" />
+<hkern g1="K" g2="ydieresis" k="158" />
+<hkern g1="L" g2="C" k="166" />
+<hkern g1="L" g2="G" k="151" />
+<hkern g1="L" g2="O" k="166" />
+<hkern g1="L" g2="Q" k="143" />
+<hkern g1="L" g2="T" k="316" />
+<hkern g1="L" g2="U" k="79" />
+<hkern g1="L" g2="V" k="277" />
+<hkern g1="L" g2="W" k="229" />
+<hkern g1="L" g2="Y" k="309" />
+<hkern g1="L" g2="a" k="51" />
+<hkern g1="L" g2="b" k="51" />
+<hkern g1="L" g2="c" k="81" />
+<hkern g1="L" g2="d" k="51" />
+<hkern g1="L" g2="e" k="51" />
+<hkern g1="L" g2="f" k="46" />
+<hkern g1="L" g2="j" k="221" />
+<hkern g1="L" g2="o" k="51" />
+<hkern g1="L" g2="q" k="51" />
+<hkern g1="L" g2="t" k="92" />
+<hkern g1="L" g2="v" k="238" />
+<hkern g1="L" g2="w" k="155" />
+<hkern g1="L" g2="y" k="145" />
+<hkern g1="L" g2="Ccedilla" k="141" />
+<hkern g1="L" g2="Ograve" k="166" />
+<hkern g1="L" g2="Oacute" k="158" />
+<hkern g1="L" g2="Ocircumflex" k="182" />
+<hkern g1="L" g2="Otilde" k="151" />
+<hkern g1="L" g2="Odieresis" k="189" />
+<hkern g1="L" g2="Ugrave" k="79" />
+<hkern g1="L" g2="Uacute" k="79" />
+<hkern g1="L" g2="Ucircumflex" k="79" />
+<hkern g1="L" g2="Udieresis" k="79" />
+<hkern g1="L" g2="Yacute" k="277" />
+<hkern g1="L" g2="agrave" k="51" />
+<hkern g1="L" g2="aacute" k="51" />
+<hkern g1="L" g2="acircumflex" k="51" />
+<hkern g1="L" g2="atilde" k="51" />
+<hkern g1="L" g2="adieresis" k="51" />
+<hkern g1="L" g2="aring" k="51" />
+<hkern g1="L" g2="ae" k="63" />
+<hkern g1="L" g2="ccedilla" k="81" />
+<hkern g1="L" g2="egrave" k="51" />
+<hkern g1="L" g2="eacute" k="51" />
+<hkern g1="L" g2="ecircumflex" k="51" />
+<hkern g1="L" g2="edieresis" k="51" />
+<hkern g1="L" g2="eth" k="41" />
+<hkern g1="L" g2="ograve" k="51" />
+<hkern g1="L" g2="oacute" k="51" />
+<hkern g1="L" g2="ocircumflex" k="51" />
+<hkern g1="L" g2="otilde" k="51" />
+<hkern g1="L" g2="odieresis" k="51" />
+<hkern g1="L" g2="yacute" k="131" />
+<hkern g1="L" g2="ydieresis" k="154" />
+<hkern g1="M" g2="j" k="189" />
+<hkern g1="N" g2="j" k="177" />
+<hkern g1="O" g2="A" k="131" />
+<hkern g1="O" g2="S" k="65" />
+<hkern g1="O" g2="T" k="106" />
+<hkern g1="O" g2="V" k="131" />
+<hkern g1="O" g2="W" k="73" />
+<hkern g1="O" g2="X" k="148" />
+<hkern g1="O" g2="Y" k="148" />
+<hkern g1="O" g2="Z" k="148" />
+<hkern g1="O" g2="j" k="255" />
+<hkern g1="O" g2="Agrave" k="131" />
+<hkern g1="O" g2="Aacute" k="131" />
+<hkern g1="O" g2="Acircumflex" k="131" />
+<hkern g1="O" g2="Atilde" k="131" />
+<hkern g1="O" g2="Adieresis" k="131" />
+<hkern g1="O" g2="Aring" k="131" />
+<hkern g1="O" g2="AE" k="85" />
+<hkern g1="O" g2="Yacute" k="148" />
+<hkern g1="P" g2="A" k="226" />
+<hkern g1="P" g2="J" k="176" />
+<hkern g1="P" g2="T" k="55" />
+<hkern g1="P" g2="X" k="54" />
+<hkern g1="P" g2="Y" k="54" />
+<hkern g1="P" g2="Z" k="55" />
+<hkern g1="P" g2="j" k="243" />
+<hkern g1="P" g2="Agrave" k="195" />
+<hkern g1="P" g2="Aacute" k="242" />
+<hkern g1="P" g2="Acircumflex" k="250" />
+<hkern g1="P" g2="Atilde" k="211" />
+<hkern g1="P" g2="Adieresis" k="203" />
+<hkern g1="P" g2="Aring" k="234" />
+<hkern g1="P" g2="AE" k="321" />
+<hkern g1="P" g2="Yacute" k="54" />
+<hkern g1="Q" g2="T" k="139" />
+<hkern g1="Q" g2="V" k="131" />
+<hkern g1="Q" g2="W" k="73" />
+<hkern g1="Q" g2="Y" k="148" />
+<hkern g1="Q" g2="j" k="163" />
+<hkern g1="Q" g2="Yacute" k="148" />
+<hkern g1="R" g2="J" k="95" />
+<hkern g1="R" g2="T" k="111" />
+<hkern g1="R" g2="V" k="80" />
+<hkern g1="R" g2="Y" k="110" />
+<hkern g1="R" g2="a" k="101" />
+<hkern g1="R" g2="c" k="106" />
+<hkern g1="R" g2="d" k="89" />
+<hkern g1="R" g2="e" k="95" />
+<hkern g1="R" g2="j" k="150" />
+<hkern g1="R" g2="o" k="89" />
+<hkern g1="R" g2="q" k="76" />
+<hkern g1="R" g2="Yacute" k="110" />
+<hkern g1="R" g2="agrave" k="83" />
+<hkern g1="R" g2="aacute" k="89" />
+<hkern g1="R" g2="acircumflex" k="76" />
+<hkern g1="R" g2="atilde" k="76" />
+<hkern g1="R" g2="adieresis" k="76" />
+<hkern g1="R" g2="aring" k="76" />
+<hkern g1="R" g2="ae" k="82" />
+<hkern g1="R" g2="ccedilla" k="81" />
+<hkern g1="R" g2="egrave" k="83" />
+<hkern g1="R" g2="eacute" k="95" />
+<hkern g1="R" g2="ecircumflex" k="89" />
+<hkern g1="R" g2="edieresis" k="83" />
+<hkern g1="R" g2="eth" k="73" />
+<hkern g1="R" g2="ograve" k="95" />
+<hkern g1="R" g2="oacute" k="95" />
+<hkern g1="R" g2="ocircumflex" k="83" />
+<hkern g1="R" g2="otilde" k="70" />
+<hkern g1="R" g2="odieresis" k="76" />
+<hkern g1="S" g2="j" k="179" />
+<hkern g1="S" g2="y" k="68" />
+<hkern g1="S" g2="yacute" k="68" />
+<hkern g1="S" g2="ydieresis" k="68" />
+<hkern g1="T" g2="A" k="324" />
+<hkern g1="T" g2="C" k="190" />
+<hkern g1="T" g2="G" k="159" />
+<hkern g1="T" g2="J" k="269" />
+<hkern g1="T" g2="O" k="128" />
+<hkern g1="T" g2="Q" k="167" />
+<hkern g1="T" g2="S" k="46" />
+<hkern g1="T" g2="a" k="277" />
+<hkern g1="T" g2="c" k="308" />
+<hkern g1="T" g2="d" k="238" />
+<hkern g1="T" g2="e" k="285" />
+<hkern g1="T" g2="f" k="190" />
+<hkern g1="T" g2="g" k="243" />
+<hkern g1="T" g2="j" k="270" />
+<hkern g1="T" g2="m" k="204" />
+<hkern g1="T" g2="n" k="182" />
+<hkern g1="T" g2="o" k="238" />
+<hkern g1="T" g2="p" k="244" />
+<hkern g1="T" g2="q" k="258" />
+<hkern g1="T" g2="r" k="95" />
+<hkern g1="T" g2="s" k="137" />
+<hkern g1="T" g2="t" k="47" />
+<hkern g1="T" g2="u" k="114" />
+<hkern g1="T" g2="v" k="152" />
+<hkern g1="T" g2="w" k="114" />
+<hkern g1="T" g2="x" k="137" />
+<hkern g1="T" g2="y" k="146" />
+<hkern g1="T" g2="z" k="90" />
+<hkern g1="T" g2="Agrave" k="168" />
+<hkern g1="T" g2="Aacute" k="152" />
+<hkern g1="T" g2="Acircumflex" k="160" />
+<hkern g1="T" g2="Atilde" k="191" />
+<hkern g1="T" g2="Adieresis" k="176" />
+<hkern g1="T" g2="Aring" k="191" />
+<hkern g1="T" g2="AE" k="277" />
+<hkern g1="T" g2="Ccedilla" k="94" />
+<hkern g1="T" g2="Ograve" k="151" />
+<hkern g1="T" g2="Oacute" k="174" />
+<hkern g1="T" g2="Ocircumflex" k="151" />
+<hkern g1="T" g2="Otilde" k="159" />
+<hkern g1="T" g2="Odieresis" k="174" />
+<hkern g1="T" g2="Oslash" k="174" />
+<hkern g1="T" g2="agrave" k="214" />
+<hkern g1="T" g2="aacute" k="238" />
+<hkern g1="T" g2="acircumflex" k="175" />
+<hkern g1="T" g2="atilde" k="147" />
+<hkern g1="T" g2="adieresis" k="238" />
+<hkern g1="T" g2="aring" k="112" />
+<hkern g1="T" g2="ae" k="277" />
+<hkern g1="T" g2="ccedilla" k="278" />
+<hkern g1="T" g2="egrave" k="214" />
+<hkern g1="T" g2="eacute" k="238" />
+<hkern g1="T" g2="ecircumflex" k="175" />
+<hkern g1="T" g2="edieresis" k="238" />
+<hkern g1="T" g2="idieresis" k="17" />
+<hkern g1="T" g2="eth" k="175" />
+<hkern g1="T" g2="ograve" k="175" />
+<hkern g1="T" g2="oacute" k="160" />
+<hkern g1="T" g2="ocircumflex" k="175" />
+<hkern g1="T" g2="otilde" k="52" />
+<hkern g1="T" g2="odieresis" k="152" />
+<hkern g1="T" g2="oslash" k="152" />
+<hkern g1="T" g2="ugrave" k="82" />
+<hkern g1="T" g2="uacute" k="145" />
+<hkern g1="T" g2="ucircumflex" k="175" />
+<hkern g1="T" g2="udieresis" k="121" />
+<hkern g1="T" g2="yacute" k="171" />
+<hkern g1="T" g2="ydieresis" k="162" />
+<hkern g1="T" g2="dotlessi" k="319" />
+<hkern g1="U" g2="j" k="187" />
+<hkern g1="V" g2="A" k="232" />
+<hkern g1="V" g2="C" k="98" />
+<hkern g1="V" g2="G" k="98" />
+<hkern g1="V" g2="J" k="214" />
+<hkern g1="V" g2="O" k="69" />
+<hkern g1="V" g2="Q" k="69" />
+<hkern g1="V" g2="S" k="63" />
+<hkern g1="V" g2="a" k="175" />
+<hkern g1="V" g2="c" k="175" />
+<hkern g1="V" g2="d" k="175" />
+<hkern g1="V" g2="e" k="175" />
+<hkern g1="V" g2="f" k="95" />
+<hkern g1="V" g2="g" k="175" />
+<hkern g1="V" g2="j" k="270" />
+<hkern g1="V" g2="m" k="75" />
+<hkern g1="V" g2="o" k="175" />
+<hkern g1="V" g2="p" k="175" />
+<hkern g1="V" g2="q" k="175" />
+<hkern g1="V" g2="r" k="65" />
+<hkern g1="V" g2="s" k="80" />
+<hkern g1="V" g2="t" k="64" />
+<hkern g1="V" g2="w" k="73" />
+<hkern g1="V" g2="x" k="67" />
+<hkern g1="V" g2="y" k="67" />
+<hkern g1="V" g2="z" k="67" />
+<hkern g1="V" g2="Agrave" k="232" />
+<hkern g1="V" g2="Aacute" k="232" />
+<hkern g1="V" g2="Acircumflex" k="232" />
+<hkern g1="V" g2="Atilde" k="232" />
+<hkern g1="V" g2="Adieresis" k="232" />
+<hkern g1="V" g2="Aring" k="232" />
+<hkern g1="V" g2="AE" k="239" />
+<hkern g1="V" g2="Ccedilla" k="98" />
+<hkern g1="V" g2="Eth" k="52" />
+<hkern g1="V" g2="Ograve" k="69" />
+<hkern g1="V" g2="Oacute" k="69" />
+<hkern g1="V" g2="Ocircumflex" k="69" />
+<hkern g1="V" g2="Otilde" k="69" />
+<hkern g1="V" g2="Odieresis" k="69" />
+<hkern g1="V" g2="Oslash" k="69" />
+<hkern g1="V" g2="agrave" k="175" />
+<hkern g1="V" g2="aacute" k="175" />
+<hkern g1="V" g2="acircumflex" k="143" />
+<hkern g1="V" g2="adieresis" k="112" />
+<hkern g1="V" g2="aring" k="175" />
+<hkern g1="V" g2="ae" k="175" />
+<hkern g1="V" g2="ccedilla" k="130" />
+<hkern g1="V" g2="egrave" k="175" />
+<hkern g1="V" g2="eacute" k="175" />
+<hkern g1="V" g2="ecircumflex" k="143" />
+<hkern g1="V" g2="edieresis" k="112" />
+<hkern g1="V" g2="eth" k="175" />
+<hkern g1="V" g2="ograve" k="175" />
+<hkern g1="V" g2="oacute" k="175" />
+<hkern g1="V" g2="ocircumflex" k="143" />
+<hkern g1="V" g2="odieresis" k="112" />
+<hkern g1="V" g2="oslash" k="175" />
+<hkern g1="V" g2="yacute" k="67" />
+<hkern g1="V" g2="ydieresis" k="67" />
+<hkern g1="V" g2="dotlessi" k="97" />
+<hkern g1="W" g2="A" k="151" />
+<hkern g1="W" g2="C" k="101" />
+<hkern g1="W" g2="G" k="101" />
+<hkern g1="W" g2="J" k="119" />
+<hkern g1="W" g2="O" k="71" />
+<hkern g1="W" g2="Q" k="71" />
+<hkern g1="W" g2="S" k="65" />
+<hkern g1="W" g2="a" k="134" />
+<hkern g1="W" g2="c" k="164" />
+<hkern g1="W" g2="d" k="134" />
+<hkern g1="W" g2="e" k="134" />
+<hkern g1="W" g2="f" k="66" />
+<hkern g1="W" g2="g" k="134" />
+<hkern g1="W" g2="j" k="222" />
+<hkern g1="W" g2="m" k="46" />
+<hkern g1="W" g2="o" k="134" />
+<hkern g1="W" g2="p" k="134" />
+<hkern g1="W" g2="q" k="134" />
+<hkern g1="W" g2="r" k="67" />
+<hkern g1="W" g2="s" k="131" />
+<hkern g1="W" g2="t" k="66" />
+<hkern g1="W" g2="w" k="44" />
+<hkern g1="W" g2="x" k="69" />
+<hkern g1="W" g2="y" k="69" />
+<hkern g1="W" g2="z" k="69" />
+<hkern g1="W" g2="Agrave" k="159" />
+<hkern g1="W" g2="Aacute" k="159" />
+<hkern g1="W" g2="Acircumflex" k="183" />
+<hkern g1="W" g2="Atilde" k="159" />
+<hkern g1="W" g2="Adieresis" k="136" />
+<hkern g1="W" g2="Aring" k="190" />
+<hkern g1="W" g2="AE" k="167" />
+<hkern g1="W" g2="Ccedilla" k="101" />
+<hkern g1="W" g2="Ograve" k="71" />
+<hkern g1="W" g2="Oacute" k="71" />
+<hkern g1="W" g2="Ocircumflex" k="71" />
+<hkern g1="W" g2="Otilde" k="71" />
+<hkern g1="W" g2="Odieresis" k="71" />
+<hkern g1="W" g2="Oslash" k="71" />
+<hkern g1="W" g2="agrave" k="134" />
+<hkern g1="W" g2="aacute" k="134" />
+<hkern g1="W" g2="acircumflex" k="134" />
+<hkern g1="W" g2="atilde" k="71" />
+<hkern g1="W" g2="adieresis" k="134" />
+<hkern g1="W" g2="aring" k="134" />
+<hkern g1="W" g2="ae" k="178" />
+<hkern g1="W" g2="ccedilla" k="164" />
+<hkern g1="W" g2="egrave" k="134" />
+<hkern g1="W" g2="eacute" k="134" />
+<hkern g1="W" g2="ecircumflex" k="134" />
+<hkern g1="W" g2="edieresis" k="134" />
+<hkern g1="W" g2="eth" k="156" />
+<hkern g1="W" g2="ograve" k="134" />
+<hkern g1="W" g2="oacute" k="134" />
+<hkern g1="W" g2="ocircumflex" k="134" />
+<hkern g1="W" g2="otilde" k="71" />
+<hkern g1="W" g2="odieresis" k="134" />
+<hkern g1="W" g2="oslash" k="134" />
+<hkern g1="W" g2="yacute" k="69" />
+<hkern g1="W" g2="ydieresis" k="69" />
+<hkern g1="W" g2="dotlessi" k="106" />
+<hkern g1="X" g2="C" k="143" />
+<hkern g1="X" g2="G" k="140" />
+<hkern g1="X" g2="O" k="143" />
+<hkern g1="X" g2="Q" k="143" />
+<hkern g1="X" g2="c" k="68" />
+<hkern g1="X" g2="f" k="65" />
+<hkern g1="X" g2="j" k="133" />
+<hkern g1="X" g2="t" k="65" />
+<hkern g1="X" g2="v" k="143" />
+<hkern g1="X" g2="w" k="143" />
+<hkern g1="X" g2="y" k="103" />
+<hkern g1="X" g2="Ccedilla" k="114" />
+<hkern g1="X" g2="Eth" k="53" />
+<hkern g1="X" g2="Ograve" k="109" />
+<hkern g1="X" g2="Oacute" k="143" />
+<hkern g1="X" g2="Ocircumflex" k="109" />
+<hkern g1="X" g2="Otilde" k="109" />
+<hkern g1="X" g2="Odieresis" k="143" />
+<hkern g1="X" g2="ae" k="82" />
+<hkern g1="X" g2="ccedilla" k="68" />
+<hkern g1="X" g2="eth" k="60" />
+<hkern g1="X" g2="yacute" k="128" />
+<hkern g1="X" g2="ydieresis" k="111" />
+<hkern g1="Y" g2="A" k="240" />
+<hkern g1="Y" g2="C" k="109" />
+<hkern g1="Y" g2="G" k="109" />
+<hkern g1="Y" g2="J" k="193" />
+<hkern g1="Y" g2="O" k="109" />
+<hkern g1="Y" g2="Q" k="109" />
+<hkern g1="Y" g2="S" k="61" />
+<hkern g1="Y" g2="a" k="170" />
+<hkern g1="Y" g2="c" k="162" />
+<hkern g1="Y" g2="d" k="162" />
+<hkern g1="Y" g2="e" k="162" />
+<hkern g1="Y" g2="f" k="109" />
+<hkern g1="Y" g2="g" k="167" />
+<hkern g1="Y" g2="j" k="201" />
+<hkern g1="Y" g2="m" k="109" />
+<hkern g1="Y" g2="n" k="109" />
+<hkern g1="Y" g2="o" k="193" />
+<hkern g1="Y" g2="p" k="168" />
+<hkern g1="Y" g2="q" k="182" />
+<hkern g1="Y" g2="r" k="109" />
+<hkern g1="Y" g2="s" k="131" />
+<hkern g1="Y" g2="t" k="62" />
+<hkern g1="Y" g2="u" k="109" />
+<hkern g1="Y" g2="v" k="109" />
+<hkern g1="Y" g2="w" k="109" />
+<hkern g1="Y" g2="x" k="109" />
+<hkern g1="Y" g2="y" k="109" />
+<hkern g1="Y" g2="z" k="109" />
+<hkern g1="Y" g2="Agrave" k="193" />
+<hkern g1="Y" g2="Aacute" k="162" />
+<hkern g1="Y" g2="Acircumflex" k="162" />
+<hkern g1="Y" g2="Atilde" k="162" />
+<hkern g1="Y" g2="Adieresis" k="162" />
+<hkern g1="Y" g2="Aring" k="162" />
+<hkern g1="Y" g2="AE" k="162" />
+<hkern g1="Y" g2="Ccedilla" k="109" />
+<hkern g1="Y" g2="Eth" k="50" />
+<hkern g1="Y" g2="Ograve" k="109" />
+<hkern g1="Y" g2="Oacute" k="109" />
+<hkern g1="Y" g2="Ocircumflex" k="109" />
+<hkern g1="Y" g2="Otilde" k="109" />
+<hkern g1="Y" g2="Odieresis" k="109" />
+<hkern g1="Y" g2="Oslash" k="109" />
+<hkern g1="Y" g2="agrave" k="162" />
+<hkern g1="Y" g2="aacute" k="162" />
+<hkern g1="Y" g2="acircumflex" k="131" />
+<hkern g1="Y" g2="atilde" k="67" />
+<hkern g1="Y" g2="adieresis" k="131" />
+<hkern g1="Y" g2="aring" k="99" />
+<hkern g1="Y" g2="ae" k="162" />
+<hkern g1="Y" g2="ccedilla" k="171" />
+<hkern g1="Y" g2="egrave" k="162" />
+<hkern g1="Y" g2="eacute" k="162" />
+<hkern g1="Y" g2="ecircumflex" k="131" />
+<hkern g1="Y" g2="edieresis" k="131" />
+<hkern g1="Y" g2="eth" k="162" />
+<hkern g1="Y" g2="ograve" k="162" />
+<hkern g1="Y" g2="oacute" k="162" />
+<hkern g1="Y" g2="ocircumflex" k="131" />
+<hkern g1="Y" g2="otilde" k="67" />
+<hkern g1="Y" g2="odieresis" k="131" />
+<hkern g1="Y" g2="oslash" k="162" />
+<hkern g1="Y" g2="ugrave" k="109" />
+<hkern g1="Y" g2="uacute" k="109" />
+<hkern g1="Y" g2="ucircumflex" k="109" />
+<hkern g1="Y" g2="udieresis" k="98" />
+<hkern g1="Y" g2="yacute" k="109" />
+<hkern g1="Y" g2="ydieresis" k="97" />
+<hkern g1="Y" g2="dotlessi" k="221" />
+<hkern g1="Z" g2="C" k="143" />
+<hkern g1="Z" g2="G" k="143" />
+<hkern g1="Z" g2="O" k="143" />
+<hkern g1="Z" g2="Q" k="143" />
+<hkern g1="Z" g2="a" k="69" />
+<hkern g1="Z" g2="c" k="98" />
+<hkern g1="Z" g2="d" k="69" />
+<hkern g1="Z" g2="e" k="69" />
+<hkern g1="Z" g2="f" k="64" />
+<hkern g1="Z" g2="j" k="115" />
+<hkern g1="Z" g2="o" k="69" />
+<hkern g1="Z" g2="q" k="69" />
+<hkern g1="Z" g2="t" k="64" />
+<hkern g1="Z" g2="v" k="143" />
+<hkern g1="Z" g2="w" k="143" />
+<hkern g1="Z" g2="y" k="143" />
+<hkern g1="Z" g2="Ccedilla" k="143" />
+<hkern g1="Z" g2="Eth" k="52" />
+<hkern g1="Z" g2="Ograve" k="143" />
+<hkern g1="Z" g2="Oacute" k="143" />
+<hkern g1="Z" g2="Ocircumflex" k="143" />
+<hkern g1="Z" g2="Otilde" k="143" />
+<hkern g1="Z" g2="Odieresis" k="143" />
+<hkern g1="Z" g2="agrave" k="69" />
+<hkern g1="Z" g2="aacute" k="69" />
+<hkern g1="Z" g2="acircumflex" k="69" />
+<hkern g1="Z" g2="adieresis" k="69" />
+<hkern g1="Z" g2="aring" k="69" />
+<hkern g1="Z" g2="ae" k="81" />
+<hkern g1="Z" g2="ccedilla" k="98" />
+<hkern g1="Z" g2="egrave" k="69" />
+<hkern g1="Z" g2="eacute" k="69" />
+<hkern g1="Z" g2="ecircumflex" k="69" />
+<hkern g1="Z" g2="edieresis" k="69" />
+<hkern g1="Z" g2="eth" k="59" />
+<hkern g1="Z" g2="ograve" k="69" />
+<hkern g1="Z" g2="oacute" k="69" />
+<hkern g1="Z" g2="ocircumflex" k="69" />
+<hkern g1="Z" g2="odieresis" k="69" />
+<hkern g1="Z" g2="yacute" k="143" />
+<hkern g1="Z" g2="ydieresis" k="67" />
+<hkern g1="underscore" g2="underscore" k="39" />
+<hkern g1="a" g2="T" k="353" />
+<hkern g1="a" g2="V" k="172" />
+<hkern g1="a" g2="W" k="160" />
+<hkern g1="a" g2="Y" k="306" />
+<hkern g1="a" g2="f" k="58" />
+<hkern g1="a" g2="j" k="259" />
+<hkern g1="a" g2="t" k="90" />
+<hkern g1="a" g2="v" k="62" />
+<hkern g1="a" g2="y" k="61" />
+<hkern g1="a" g2="Yacute" k="298" />
+<hkern g1="a" g2="icircumflex" k="58" />
+<hkern g1="a" g2="idieresis" k="65" />
+<hkern g1="a" g2="yacute" k="61" />
+<hkern g1="a" g2="ydieresis" k="61" />
+<hkern g1="b" g2="A" k="60" />
+<hkern g1="b" g2="T" k="279" />
+<hkern g1="b" g2="V" k="129" />
+<hkern g1="b" g2="W" k="160" />
+<hkern g1="b" g2="X" k="122" />
+<hkern g1="b" g2="Y" k="294" />
+<hkern g1="b" g2="Z" k="123" />
+<hkern g1="b" g2="f" k="58" />
+<hkern g1="b" g2="j" k="199" />
+<hkern g1="b" g2="t" k="90" />
+<hkern g1="b" g2="v" k="62" />
+<hkern g1="b" g2="x" k="93" />
+<hkern g1="b" g2="y" k="61" />
+<hkern g1="b" g2="z" k="93" />
+<hkern g1="b" g2="Agrave" k="60" />
+<hkern g1="b" g2="Aacute" k="60" />
+<hkern g1="b" g2="Acircumflex" k="60" />
+<hkern g1="b" g2="Atilde" k="60" />
+<hkern g1="b" g2="Adieresis" k="60" />
+<hkern g1="b" g2="Aring" k="60" />
+<hkern g1="b" g2="AE" k="63" />
+<hkern g1="b" g2="Yacute" k="256" />
+<hkern g1="b" g2="icircumflex" k="58" />
+<hkern g1="b" g2="idieresis" k="65" />
+<hkern g1="b" g2="yacute" k="61" />
+<hkern g1="b" g2="ydieresis" k="61" />
+<hkern g1="c" g2="T" k="281" />
+<hkern g1="c" g2="V" k="123" />
+<hkern g1="c" g2="Y" k="148" />
+<hkern g1="c" g2="j" k="172" />
+<hkern g1="c" g2="Yacute" k="148" />
+<hkern g1="d" g2="A" k="60" />
+<hkern g1="d" g2="j" k="154" />
+<hkern g1="d" g2="Agrave" k="60" />
+<hkern g1="d" g2="Aacute" k="60" />
+<hkern g1="d" g2="Acircumflex" k="60" />
+<hkern g1="d" g2="Atilde" k="60" />
+<hkern g1="d" g2="Adieresis" k="60" />
+<hkern g1="d" g2="Aring" k="60" />
+<hkern g1="d" g2="AE" k="63" />
+<hkern g1="e" g2="A" k="92" />
+<hkern g1="e" g2="T" k="316" />
+<hkern g1="e" g2="V" k="172" />
+<hkern g1="e" g2="W" k="160" />
+<hkern g1="e" g2="X" k="122" />
+<hkern g1="e" g2="Y" k="246" />
+<hkern g1="e" g2="Z" k="123" />
+<hkern g1="e" g2="f" k="58" />
+<hkern g1="e" g2="j" k="229" />
+<hkern g1="e" g2="t" k="90" />
+<hkern g1="e" g2="v" k="62" />
+<hkern g1="e" g2="x" k="93" />
+<hkern g1="e" g2="y" k="61" />
+<hkern g1="e" g2="z" k="93" />
+<hkern g1="e" g2="Agrave" k="92" />
+<hkern g1="e" g2="Aacute" k="92" />
+<hkern g1="e" g2="Acircumflex" k="92" />
+<hkern g1="e" g2="Atilde" k="92" />
+<hkern g1="e" g2="Adieresis" k="92" />
+<hkern g1="e" g2="Aring" k="92" />
+<hkern g1="e" g2="AE" k="95" />
+<hkern g1="e" g2="Yacute" k="215" />
+<hkern g1="e" g2="icircumflex" k="58" />
+<hkern g1="e" g2="idieresis" k="65" />
+<hkern g1="e" g2="yacute" k="61" />
+<hkern g1="e" g2="ydieresis" k="61" />
+<hkern g1="f" g2="A" k="124" />
+<hkern g1="f" g2="J" k="178" />
+<hkern g1="f" g2="j" k="242" />
+<hkern g1="f" g2="Agrave" k="124" />
+<hkern g1="f" g2="Aacute" k="77" />
+<hkern g1="f" g2="Acircumflex" k="77" />
+<hkern g1="f" g2="Atilde" k="77" />
+<hkern g1="f" g2="Adieresis" k="77" />
+<hkern g1="f" g2="Aring" k="77" />
+<hkern g1="f" g2="AE" k="139" />
+<hkern g1="g" g2="T" k="285" />
+<hkern g1="g" g2="V" k="172" />
+<hkern g1="g" g2="W" k="160" />
+<hkern g1="g" g2="Y" k="254" />
+<hkern g1="g" g2="f" k="58" />
+<hkern g1="g" g2="t" k="90" />
+<hkern g1="g" g2="v" k="62" />
+<hkern g1="g" g2="y" k="61" />
+<hkern g1="g" g2="Yacute" k="254" />
+<hkern g1="g" g2="icircumflex" k="58" />
+<hkern g1="g" g2="idieresis" k="65" />
+<hkern g1="g" g2="yacute" k="61" />
+<hkern g1="g" g2="ydieresis" k="61" />
+<hkern g1="h" g2="T" k="308" />
+<hkern g1="h" g2="V" k="155" />
+<hkern g1="h" g2="W" k="144" />
+<hkern g1="h" g2="Y" k="261" />
+<hkern g1="h" g2="f" k="42" />
+<hkern g1="h" g2="j" k="198" />
+<hkern g1="h" g2="t" k="74" />
+<hkern g1="h" g2="v" k="46" />
+<hkern g1="h" g2="y" k="45" />
+<hkern g1="h" g2="Yacute" k="261" />
+<hkern g1="h" g2="icircumflex" k="42" />
+<hkern g1="h" g2="idieresis" k="49" />
+<hkern g1="h" g2="yacute" k="45" />
+<hkern g1="h" g2="ydieresis" k="45" />
+<hkern g1="i" g2="j" k="171" />
+<hkern g1="k" g2="T" k="251" />
+<hkern g1="k" g2="V" k="91" />
+<hkern g1="k" g2="Y" k="138" />
+<hkern g1="k" g2="a" k="63" />
+<hkern g1="k" g2="c" k="92" />
+<hkern g1="k" g2="d" k="63" />
+<hkern g1="k" g2="e" k="63" />
+<hkern g1="k" g2="j" k="156" />
+<hkern g1="k" g2="o" k="63" />
+<hkern g1="k" g2="q" k="63" />
+<hkern g1="k" g2="Yacute" k="138" />
+<hkern g1="k" g2="agrave" k="63" />
+<hkern g1="k" g2="aacute" k="63" />
+<hkern g1="k" g2="acircumflex" k="63" />
+<hkern g1="k" g2="atilde" k="63" />
+<hkern g1="k" g2="adieresis" k="63" />
+<hkern g1="k" g2="aring" k="63" />
+<hkern g1="k" g2="ae" k="75" />
+<hkern g1="k" g2="ccedilla" k="92" />
+<hkern g1="k" g2="egrave" k="63" />
+<hkern g1="k" g2="eacute" k="63" />
+<hkern g1="k" g2="ecircumflex" k="63" />
+<hkern g1="k" g2="edieresis" k="63" />
+<hkern g1="k" g2="eth" k="53" />
+<hkern g1="k" g2="ograve" k="63" />
+<hkern g1="k" g2="oacute" k="63" />
+<hkern g1="k" g2="ocircumflex" k="63" />
+<hkern g1="k" g2="otilde" k="63" />
+<hkern g1="k" g2="odieresis" k="63" />
+<hkern g1="l" g2="j" k="153" />
+<hkern g1="l" g2="ae" k="41" />
+<hkern g1="m" g2="T" k="260" />
+<hkern g1="m" g2="V" k="117" />
+<hkern g1="m" g2="W" k="130" />
+<hkern g1="m" g2="Y" k="221" />
+<hkern g1="m" g2="j" k="166" />
+<hkern g1="m" g2="t" k="60" />
+<hkern g1="m" g2="y" k="63" />
+<hkern g1="m" g2="Yacute" k="229" />
+<hkern g1="m" g2="icircumflex" k="60" />
+<hkern g1="m" g2="idieresis" k="67" />
+<hkern g1="m" g2="yacute" k="63" />
+<hkern g1="m" g2="ydieresis" k="63" />
+<hkern g1="n" g2="T" k="221" />
+<hkern g1="n" g2="V" k="155" />
+<hkern g1="n" g2="W" k="144" />
+<hkern g1="n" g2="Y" k="190" />
+<hkern g1="n" g2="f" k="42" />
+<hkern g1="n" g2="j" k="126" />
+<hkern g1="n" g2="t" k="74" />
+<hkern g1="n" g2="v" k="46" />
+<hkern g1="n" g2="y" k="45" />
+<hkern g1="n" g2="Yacute" k="221" />
+<hkern g1="n" g2="icircumflex" k="42" />
+<hkern g1="n" g2="idieresis" k="49" />
+<hkern g1="n" g2="yacute" k="45" />
+<hkern g1="n" g2="ydieresis" k="45" />
+<hkern g1="o" g2="A" k="60" />
+<hkern g1="o" g2="T" k="256" />
+<hkern g1="o" g2="V" k="172" />
+<hkern g1="o" g2="W" k="160" />
+<hkern g1="o" g2="X" k="122" />
+<hkern g1="o" g2="Y" k="225" />
+<hkern g1="o" g2="Z" k="123" />
+<hkern g1="o" g2="f" k="58" />
+<hkern g1="o" g2="j" k="201" />
+<hkern g1="o" g2="t" k="90" />
+<hkern g1="o" g2="v" k="62" />
+<hkern g1="o" g2="x" k="93" />
+<hkern g1="o" g2="y" k="61" />
+<hkern g1="o" g2="z" k="93" />
+<hkern g1="o" g2="Agrave" k="60" />
+<hkern g1="o" g2="Aacute" k="60" />
+<hkern g1="o" g2="Acircumflex" k="60" />
+<hkern g1="o" g2="Atilde" k="60" />
+<hkern g1="o" g2="Adieresis" k="60" />
+<hkern g1="o" g2="Aring" k="60" />
+<hkern g1="o" g2="AE" k="63" />
+<hkern g1="o" g2="Yacute" k="225" />
+<hkern g1="o" g2="icircumflex" k="58" />
+<hkern g1="o" g2="idieresis" k="65" />
+<hkern g1="o" g2="yacute" k="61" />
+<hkern g1="o" g2="ydieresis" k="61" />
+<hkern g1="p" g2="A" k="60" />
+<hkern g1="p" g2="T" k="297" />
+<hkern g1="p" g2="V" k="172" />
+<hkern g1="p" g2="W" k="160" />
+<hkern g1="p" g2="X" k="122" />
+<hkern g1="p" g2="Y" k="227" />
+<hkern g1="p" g2="Z" k="123" />
+<hkern g1="p" g2="f" k="58" />
+<hkern g1="p" g2="j" k="180" />
+<hkern g1="p" g2="t" k="90" />
+<hkern g1="p" g2="v" k="62" />
+<hkern g1="p" g2="x" k="93" />
+<hkern g1="p" g2="y" k="61" />
+<hkern g1="p" g2="z" k="93" />
+<hkern g1="p" g2="Agrave" k="60" />
+<hkern g1="p" g2="Aacute" k="60" />
+<hkern g1="p" g2="Acircumflex" k="60" />
+<hkern g1="p" g2="Atilde" k="60" />
+<hkern g1="p" g2="Adieresis" k="60" />
+<hkern g1="p" g2="Aring" k="60" />
+<hkern g1="p" g2="AE" k="63" />
+<hkern g1="p" g2="Yacute" k="227" />
+<hkern g1="p" g2="icircumflex" k="58" />
+<hkern g1="p" g2="idieresis" k="65" />
+<hkern g1="p" g2="yacute" k="61" />
+<hkern g1="p" g2="ydieresis" k="61" />
+<hkern g1="q" g2="T" k="263" />
+<hkern g1="q" g2="V" k="120" />
+<hkern g1="q" g2="W" k="160" />
+<hkern g1="q" g2="Y" k="247" />
+<hkern g1="q" g2="f" k="58" />
+<hkern g1="q" g2="t" k="90" />
+<hkern g1="q" g2="v" k="62" />
+<hkern g1="q" g2="y" k="61" />
+<hkern g1="q" g2="Yacute" k="247" />
+<hkern g1="q" g2="icircumflex" k="58" />
+<hkern g1="q" g2="idieresis" k="65" />
+<hkern g1="q" g2="yacute" k="61" />
+<hkern g1="q" g2="ydieresis" k="61" />
+<hkern g1="r" g2="A" k="136" />
+<hkern g1="r" g2="J" k="233" />
+<hkern g1="r" g2="T" k="224" />
+<hkern g1="r" g2="V" k="59" />
+<hkern g1="r" g2="X" k="167" />
+<hkern g1="r" g2="Y" k="136" />
+<hkern g1="r" g2="Z" k="201" />
+<hkern g1="r" g2="j" k="168" />
+<hkern g1="r" g2="Agrave" k="136" />
+<hkern g1="r" g2="Aacute" k="136" />
+<hkern g1="r" g2="Acircumflex" k="136" />
+<hkern g1="r" g2="Atilde" k="136" />
+<hkern g1="r" g2="Adieresis" k="136" />
+<hkern g1="r" g2="Aring" k="136" />
+<hkern g1="r" g2="AE" k="239" />
+<hkern g1="r" g2="Yacute" k="136" />
+<hkern g1="s" g2="T" k="233" />
+<hkern g1="s" g2="V" k="110" />
+<hkern g1="s" g2="W" k="69" />
+<hkern g1="s" g2="Y" k="256" />
+<hkern g1="s" g2="j" k="186" />
+<hkern g1="s" g2="Yacute" k="202" />
+<hkern g1="t" g2="T" k="165" />
+<hkern g1="t" g2="V" k="102" />
+<hkern g1="t" g2="W" k="63" />
+<hkern g1="t" g2="Y" k="165" />
+<hkern g1="t" g2="a" k="61" />
+<hkern g1="t" g2="c" k="90" />
+<hkern g1="t" g2="d" k="61" />
+<hkern g1="t" g2="e" k="61" />
+<hkern g1="t" g2="j" k="143" />
+<hkern g1="t" g2="o" k="61" />
+<hkern g1="t" g2="q" k="61" />
+<hkern g1="t" g2="Yacute" k="165" />
+<hkern g1="t" g2="agrave" k="61" />
+<hkern g1="t" g2="aacute" k="61" />
+<hkern g1="t" g2="acircumflex" k="61" />
+<hkern g1="t" g2="atilde" k="61" />
+<hkern g1="t" g2="adieresis" k="61" />
+<hkern g1="t" g2="aring" k="61" />
+<hkern g1="t" g2="ae" k="73" />
+<hkern g1="t" g2="ccedilla" k="90" />
+<hkern g1="t" g2="egrave" k="61" />
+<hkern g1="t" g2="eacute" k="61" />
+<hkern g1="t" g2="ecircumflex" k="61" />
+<hkern g1="t" g2="edieresis" k="61" />
+<hkern g1="t" g2="eth" k="51" />
+<hkern g1="t" g2="ograve" k="61" />
+<hkern g1="t" g2="oacute" k="61" />
+<hkern g1="t" g2="ocircumflex" k="61" />
+<hkern g1="t" g2="otilde" k="61" />
+<hkern g1="t" g2="odieresis" k="61" />
+<hkern g1="u" g2="T" k="248" />
+<hkern g1="u" g2="V" k="107" />
+<hkern g1="u" g2="W" k="49" />
+<hkern g1="u" g2="Y" k="124" />
+<hkern g1="u" g2="j" k="154" />
+<hkern g1="u" g2="Yacute" k="124" />
+<hkern g1="u" g2="icircumflex" k="42" />
+<hkern g1="u" g2="idieresis" k="49" />
+<hkern g1="v" g2="A" k="161" />
+<hkern g1="v" g2="J" k="92" />
+<hkern g1="v" g2="T" k="248" />
+<hkern g1="v" g2="V" k="107" />
+<hkern g1="v" g2="W" k="49" />
+<hkern g1="v" g2="X" k="155" />
+<hkern g1="v" g2="Y" k="124" />
+<hkern g1="v" g2="Z" k="240" />
+<hkern g1="v" g2="a" k="47" />
+<hkern g1="v" g2="c" k="77" />
+<hkern g1="v" g2="d" k="47" />
+<hkern g1="v" g2="e" k="47" />
+<hkern g1="v" g2="g" k="47" />
+<hkern g1="v" g2="j" k="216" />
+<hkern g1="v" g2="o" k="47" />
+<hkern g1="v" g2="p" k="47" />
+<hkern g1="v" g2="q" k="47" />
+<hkern g1="v" g2="Agrave" k="153" />
+<hkern g1="v" g2="Aacute" k="146" />
+<hkern g1="v" g2="Acircumflex" k="153" />
+<hkern g1="v" g2="Atilde" k="146" />
+<hkern g1="v" g2="Adieresis" k="161" />
+<hkern g1="v" g2="Aring" k="177" />
+<hkern g1="v" g2="AE" k="201" />
+<hkern g1="v" g2="Yacute" k="124" />
+<hkern g1="v" g2="agrave" k="47" />
+<hkern g1="v" g2="aacute" k="47" />
+<hkern g1="v" g2="acircumflex" k="47" />
+<hkern g1="v" g2="atilde" k="47" />
+<hkern g1="v" g2="adieresis" k="47" />
+<hkern g1="v" g2="aring" k="47" />
+<hkern g1="v" g2="ae" k="91" />
+<hkern g1="v" g2="ccedilla" k="77" />
+<hkern g1="v" g2="egrave" k="47" />
+<hkern g1="v" g2="eacute" k="47" />
+<hkern g1="v" g2="ecircumflex" k="47" />
+<hkern g1="v" g2="edieresis" k="47" />
+<hkern g1="v" g2="icircumflex" k="42" />
+<hkern g1="v" g2="idieresis" k="49" />
+<hkern g1="v" g2="eth" k="69" />
+<hkern g1="v" g2="ograve" k="47" />
+<hkern g1="v" g2="oacute" k="47" />
+<hkern g1="v" g2="ocircumflex" k="47" />
+<hkern g1="v" g2="otilde" k="47" />
+<hkern g1="v" g2="odieresis" k="47" />
+<hkern g1="v" g2="oslash" k="47" />
+<hkern g1="w" g2="A" k="146" />
+<hkern g1="w" g2="J" k="90" />
+<hkern g1="w" g2="T" k="330" />
+<hkern g1="w" g2="V" k="124" />
+<hkern g1="w" g2="X" k="146" />
+<hkern g1="w" g2="Y" k="133" />
+<hkern g1="w" g2="Z" k="146" />
+<hkern g1="w" g2="j" k="220" />
+<hkern g1="w" g2="Agrave" k="146" />
+<hkern g1="w" g2="Aacute" k="146" />
+<hkern g1="w" g2="Acircumflex" k="146" />
+<hkern g1="w" g2="Atilde" k="146" />
+<hkern g1="w" g2="Adieresis" k="146" />
+<hkern g1="w" g2="Aring" k="146" />
+<hkern g1="w" g2="AE" k="146" />
+<hkern g1="w" g2="Yacute" k="148" />
+<hkern g1="w" g2="ae" k="45" />
+<hkern g1="w" g2="icircumflex" k="59" />
+<hkern g1="w" g2="idieresis" k="66" />
+<hkern g1="x" g2="T" k="210" />
+<hkern g1="x" g2="V" k="91" />
+<hkern g1="x" g2="Y" k="138" />
+<hkern g1="x" g2="a" k="63" />
+<hkern g1="x" g2="c" k="92" />
+<hkern g1="x" g2="d" k="63" />
+<hkern g1="x" g2="e" k="63" />
+<hkern g1="x" g2="j" k="154" />
+<hkern g1="x" g2="o" k="63" />
+<hkern g1="x" g2="q" k="63" />
+<hkern g1="x" g2="Yacute" k="138" />
+<hkern g1="x" g2="agrave" k="63" />
+<hkern g1="x" g2="aacute" k="63" />
+<hkern g1="x" g2="acircumflex" k="63" />
+<hkern g1="x" g2="atilde" k="63" />
+<hkern g1="x" g2="adieresis" k="63" />
+<hkern g1="x" g2="aring" k="63" />
+<hkern g1="x" g2="ae" k="75" />
+<hkern g1="x" g2="ccedilla" k="92" />
+<hkern g1="x" g2="egrave" k="63" />
+<hkern g1="x" g2="eacute" k="63" />
+<hkern g1="x" g2="ecircumflex" k="63" />
+<hkern g1="x" g2="edieresis" k="63" />
+<hkern g1="x" g2="eth" k="53" />
+<hkern g1="x" g2="ograve" k="63" />
+<hkern g1="x" g2="oacute" k="63" />
+<hkern g1="x" g2="ocircumflex" k="63" />
+<hkern g1="x" g2="otilde" k="63" />
+<hkern g1="x" g2="odieresis" k="63" />
+<hkern g1="y" g2="A" k="125" />
+<hkern g1="y" g2="J" k="88" />
+<hkern g1="y" g2="T" k="306" />
+<hkern g1="y" g2="V" k="91" />
+<hkern g1="y" g2="X" k="78" />
+<hkern g1="y" g2="Y" k="94" />
+<hkern g1="y" g2="Z" k="118" />
+<hkern g1="y" g2="j" k="180" />
+<hkern g1="y" g2="Agrave" k="86" />
+<hkern g1="y" g2="Aacute" k="86" />
+<hkern g1="y" g2="Acircumflex" k="86" />
+<hkern g1="y" g2="Atilde" k="86" />
+<hkern g1="y" g2="Adieresis" k="86" />
+<hkern g1="y" g2="Aring" k="86" />
+<hkern g1="y" g2="AE" k="118" />
+<hkern g1="y" g2="Yacute" k="55" />
+<hkern g1="z" g2="T" k="299" />
+<hkern g1="z" g2="V" k="91" />
+<hkern g1="z" g2="Y" k="63" />
+<hkern g1="z" g2="a" k="63" />
+<hkern g1="z" g2="c" k="92" />
+<hkern g1="z" g2="d" k="63" />
+<hkern g1="z" g2="e" k="63" />
+<hkern g1="z" g2="j" k="180" />
+<hkern g1="z" g2="o" k="63" />
+<hkern g1="z" g2="q" k="63" />
+<hkern g1="z" g2="Yacute" k="149" />
+<hkern g1="z" g2="agrave" k="63" />
+<hkern g1="z" g2="aacute" k="63" />
+<hkern g1="z" g2="acircumflex" k="63" />
+<hkern g1="z" g2="atilde" k="63" />
+<hkern g1="z" g2="adieresis" k="63" />
+<hkern g1="z" g2="aring" k="63" />
+<hkern g1="z" g2="ae" k="75" />
+<hkern g1="z" g2="ccedilla" k="92" />
+<hkern g1="z" g2="egrave" k="63" />
+<hkern g1="z" g2="eacute" k="63" />
+<hkern g1="z" g2="ecircumflex" k="63" />
+<hkern g1="z" g2="edieresis" k="63" />
+<hkern g1="z" g2="eth" k="53" />
+<hkern g1="z" g2="ograve" k="63" />
+<hkern g1="z" g2="oacute" k="63" />
+<hkern g1="z" g2="ocircumflex" k="63" />
+<hkern g1="z" g2="otilde" k="63" />
+<hkern g1="z" g2="odieresis" k="63" />
+<hkern g1="Agrave" g2="C" k="98" />
+<hkern g1="Agrave" g2="G" k="98" />
+<hkern g1="Agrave" g2="O" k="69" />
+<hkern g1="Agrave" g2="Q" k="69" />
+<hkern g1="Agrave" g2="T" k="208" />
+<hkern g1="Agrave" g2="V" k="247" />
+<hkern g1="Agrave" g2="W" k="121" />
+<hkern g1="Agrave" g2="Y" k="247" />
+<hkern g1="Agrave" g2="f" k="64" />
+<hkern g1="Agrave" g2="j" k="200" />
+<hkern g1="Agrave" g2="t" k="95" />
+<hkern g1="Agrave" g2="v" k="137" />
+<hkern g1="Agrave" g2="w" k="143" />
+<hkern g1="Agrave" g2="y" k="206" />
+<hkern g1="Agrave" g2="Ccedilla" k="98" />
+<hkern g1="Agrave" g2="Eth" k="52" />
+<hkern g1="Agrave" g2="Ograve" k="69" />
+<hkern g1="Agrave" g2="Oacute" k="69" />
+<hkern g1="Agrave" g2="Ocircumflex" k="69" />
+<hkern g1="Agrave" g2="Otilde" k="69" />
+<hkern g1="Agrave" g2="Odieresis" k="69" />
+<hkern g1="Agrave" g2="Yacute" k="224" />
+<hkern g1="Agrave" g2="yacute" k="124" />
+<hkern g1="Agrave" g2="ydieresis" k="61" />
+<hkern g1="Aacute" g2="C" k="98" />
+<hkern g1="Aacute" g2="G" k="98" />
+<hkern g1="Aacute" g2="O" k="69" />
+<hkern g1="Aacute" g2="Q" k="69" />
+<hkern g1="Aacute" g2="T" k="247" />
+<hkern g1="Aacute" g2="V" k="200" />
+<hkern g1="Aacute" g2="W" k="159" />
+<hkern g1="Aacute" g2="Y" k="239" />
+<hkern g1="Aacute" g2="f" k="64" />
+<hkern g1="Aacute" g2="j" k="207" />
+<hkern g1="Aacute" g2="t" k="95" />
+<hkern g1="Aacute" g2="v" k="206" />
+<hkern g1="Aacute" g2="w" k="143" />
+<hkern g1="Aacute" g2="y" k="206" />
+<hkern g1="Aacute" g2="Ccedilla" k="98" />
+<hkern g1="Aacute" g2="Eth" k="52" />
+<hkern g1="Aacute" g2="Ograve" k="69" />
+<hkern g1="Aacute" g2="Oacute" k="69" />
+<hkern g1="Aacute" g2="Ocircumflex" k="69" />
+<hkern g1="Aacute" g2="Otilde" k="69" />
+<hkern g1="Aacute" g2="Odieresis" k="69" />
+<hkern g1="Aacute" g2="Yacute" k="200" />
+<hkern g1="Aacute" g2="yacute" k="62" />
+<hkern g1="Aacute" g2="ydieresis" k="53" />
+<hkern g1="Acircumflex" g2="C" k="98" />
+<hkern g1="Acircumflex" g2="G" k="98" />
+<hkern g1="Acircumflex" g2="O" k="69" />
+<hkern g1="Acircumflex" g2="Q" k="69" />
+<hkern g1="Acircumflex" g2="T" k="216" />
+<hkern g1="Acircumflex" g2="V" k="200" />
+<hkern g1="Acircumflex" g2="W" k="121" />
+<hkern g1="Acircumflex" g2="Y" k="200" />
+<hkern g1="Acircumflex" g2="f" k="64" />
+<hkern g1="Acircumflex" g2="j" k="106" />
+<hkern g1="Acircumflex" g2="t" k="95" />
+<hkern g1="Acircumflex" g2="v" k="206" />
+<hkern g1="Acircumflex" g2="w" k="143" />
+<hkern g1="Acircumflex" g2="y" k="206" />
+<hkern g1="Acircumflex" g2="Ccedilla" k="98" />
+<hkern g1="Acircumflex" g2="Eth" k="52" />
+<hkern g1="Acircumflex" g2="Ograve" k="69" />
+<hkern g1="Acircumflex" g2="Oacute" k="69" />
+<hkern g1="Acircumflex" g2="Ocircumflex" k="69" />
+<hkern g1="Acircumflex" g2="Otilde" k="69" />
+<hkern g1="Acircumflex" g2="Odieresis" k="69" />
+<hkern g1="Acircumflex" g2="Yacute" k="200" />
+<hkern g1="Acircumflex" g2="yacute" k="62" />
+<hkern g1="Acircumflex" g2="ydieresis" k="53" />
+<hkern g1="Atilde" g2="C" k="98" />
+<hkern g1="Atilde" g2="G" k="98" />
+<hkern g1="Atilde" g2="O" k="69" />
+<hkern g1="Atilde" g2="Q" k="69" />
+<hkern g1="Atilde" g2="T" k="204" />
+<hkern g1="Atilde" g2="V" k="204" />
+<hkern g1="Atilde" g2="W" k="78" />
+<hkern g1="Atilde" g2="Y" k="204" />
+<hkern g1="Atilde" g2="f" k="64" />
+<hkern g1="Atilde" g2="j" k="110" />
+<hkern g1="Atilde" g2="t" k="95" />
+<hkern g1="Atilde" g2="v" k="206" />
+<hkern g1="Atilde" g2="w" k="143" />
+<hkern g1="Atilde" g2="y" k="206" />
+<hkern g1="Atilde" g2="Ccedilla" k="98" />
+<hkern g1="Atilde" g2="Eth" k="52" />
+<hkern g1="Atilde" g2="Ograve" k="69" />
+<hkern g1="Atilde" g2="Oacute" k="69" />
+<hkern g1="Atilde" g2="Ocircumflex" k="69" />
+<hkern g1="Atilde" g2="Otilde" k="69" />
+<hkern g1="Atilde" g2="Odieresis" k="69" />
+<hkern g1="Atilde" g2="Yacute" k="204" />
+<hkern g1="Atilde" g2="yacute" k="66" />
+<hkern g1="Atilde" g2="ydieresis" k="57" />
+<hkern g1="Adieresis" g2="C" k="98" />
+<hkern g1="Adieresis" g2="G" k="98" />
+<hkern g1="Adieresis" g2="O" k="69" />
+<hkern g1="Adieresis" g2="Q" k="69" />
+<hkern g1="Adieresis" g2="T" k="236" />
+<hkern g1="Adieresis" g2="V" k="213" />
+<hkern g1="Adieresis" g2="W" k="188" />
+<hkern g1="Adieresis" g2="Y" k="213" />
+<hkern g1="Adieresis" g2="f" k="64" />
+<hkern g1="Adieresis" g2="j" k="158" />
+<hkern g1="Adieresis" g2="t" k="95" />
+<hkern g1="Adieresis" g2="v" k="157" />
+<hkern g1="Adieresis" g2="w" k="143" />
+<hkern g1="Adieresis" g2="y" k="206" />
+<hkern g1="Adieresis" g2="Ccedilla" k="98" />
+<hkern g1="Adieresis" g2="Eth" k="52" />
+<hkern g1="Adieresis" g2="Ograve" k="69" />
+<hkern g1="Adieresis" g2="Oacute" k="69" />
+<hkern g1="Adieresis" g2="Ocircumflex" k="69" />
+<hkern g1="Adieresis" g2="Otilde" k="69" />
+<hkern g1="Adieresis" g2="Odieresis" k="69" />
+<hkern g1="Adieresis" g2="Yacute" k="213" />
+<hkern g1="Adieresis" g2="yacute" k="75" />
+<hkern g1="Adieresis" g2="ydieresis" k="66" />
+<hkern g1="Aring" g2="C" k="98" />
+<hkern g1="Aring" g2="G" k="98" />
+<hkern g1="Aring" g2="O" k="69" />
+<hkern g1="Aring" g2="Q" k="69" />
+<hkern g1="Aring" g2="T" k="223" />
+<hkern g1="Aring" g2="V" k="230" />
+<hkern g1="Aring" g2="W" k="182" />
+<hkern g1="Aring" g2="Y" k="246" />
+<hkern g1="Aring" g2="f" k="64" />
+<hkern g1="Aring" g2="j" k="191" />
+<hkern g1="Aring" g2="t" k="95" />
+<hkern g1="Aring" g2="v" k="167" />
+<hkern g1="Aring" g2="w" k="143" />
+<hkern g1="Aring" g2="y" k="206" />
+<hkern g1="Aring" g2="Ccedilla" k="98" />
+<hkern g1="Aring" g2="Eth" k="52" />
+<hkern g1="Aring" g2="Ograve" k="69" />
+<hkern g1="Aring" g2="Oacute" k="69" />
+<hkern g1="Aring" g2="Ocircumflex" k="69" />
+<hkern g1="Aring" g2="Otilde" k="69" />
+<hkern g1="Aring" g2="Odieresis" k="69" />
+<hkern g1="Aring" g2="Yacute" k="207" />
+<hkern g1="Aring" g2="yacute" k="92" />
+<hkern g1="Aring" g2="ydieresis" k="83" />
+<hkern g1="AE" g2="C" k="100" />
+<hkern g1="AE" g2="G" k="100" />
+<hkern g1="AE" g2="J" k="65" />
+<hkern g1="AE" g2="O" k="102" />
+<hkern g1="AE" g2="Q" k="102" />
+<hkern g1="AE" g2="a" k="102" />
+<hkern g1="AE" g2="c" k="132" />
+<hkern g1="AE" g2="d" k="102" />
+<hkern g1="AE" g2="e" k="102" />
+<hkern g1="AE" g2="f" k="97" />
+<hkern g1="AE" g2="g" k="71" />
+<hkern g1="AE" g2="j" k="206" />
+<hkern g1="AE" g2="o" k="102" />
+<hkern g1="AE" g2="q" k="102" />
+<hkern g1="AE" g2="t" k="97" />
+<hkern g1="AE" g2="u" k="70" />
+<hkern g1="AE" g2="v" k="117" />
+<hkern g1="AE" g2="w" k="85" />
+<hkern g1="AE" g2="y" k="117" />
+<hkern g1="AE" g2="Ccedilla" k="100" />
+<hkern g1="AE" g2="Ograve" k="102" />
+<hkern g1="AE" g2="Oacute" k="102" />
+<hkern g1="AE" g2="Ocircumflex" k="102" />
+<hkern g1="AE" g2="Otilde" k="102" />
+<hkern g1="AE" g2="Odieresis" k="102" />
+<hkern g1="AE" g2="agrave" k="102" />
+<hkern g1="AE" g2="aacute" k="102" />
+<hkern g1="AE" g2="acircumflex" k="102" />
+<hkern g1="AE" g2="atilde" k="102" />
+<hkern g1="AE" g2="adieresis" k="102" />
+<hkern g1="AE" g2="aring" k="102" />
+<hkern g1="AE" g2="ae" k="114" />
+<hkern g1="AE" g2="ccedilla" k="132" />
+<hkern g1="AE" g2="egrave" k="102" />
+<hkern g1="AE" g2="eacute" k="102" />
+<hkern g1="AE" g2="ecircumflex" k="102" />
+<hkern g1="AE" g2="edieresis" k="102" />
+<hkern g1="AE" g2="eth" k="92" />
+<hkern g1="AE" g2="ograve" k="102" />
+<hkern g1="AE" g2="oacute" k="102" />
+<hkern g1="AE" g2="ocircumflex" k="102" />
+<hkern g1="AE" g2="otilde" k="102" />
+<hkern g1="AE" g2="odieresis" k="102" />
+<hkern g1="AE" g2="ugrave" k="70" />
+<hkern g1="AE" g2="uacute" k="70" />
+<hkern g1="AE" g2="ucircumflex" k="70" />
+<hkern g1="AE" g2="udieresis" k="70" />
+<hkern g1="AE" g2="yacute" k="117" />
+<hkern g1="AE" g2="ydieresis" k="132" />
+<hkern g1="Ccedilla" g2="C" k="91" />
+<hkern g1="Ccedilla" g2="G" k="138" />
+<hkern g1="Ccedilla" g2="O" k="91" />
+<hkern g1="Ccedilla" g2="Q" k="91" />
+<hkern g1="Ccedilla" g2="f" k="154" />
+<hkern g1="Ccedilla" g2="j" k="208" />
+<hkern g1="Ccedilla" g2="t" k="130" />
+<hkern g1="Ccedilla" g2="v" k="248" />
+<hkern g1="Ccedilla" g2="w" k="122" />
+<hkern g1="Ccedilla" g2="y" k="202" />
+<hkern g1="Ccedilla" g2="Ccedilla" k="104" />
+<hkern g1="Ccedilla" g2="Igrave" k="75" />
+<hkern g1="Ccedilla" g2="Iacute" k="105" />
+<hkern g1="Ccedilla" g2="Icircumflex" k="96" />
+<hkern g1="Ccedilla" g2="Idieresis" k="76" />
+<hkern g1="Ccedilla" g2="Eth" k="59" />
+<hkern g1="Ccedilla" g2="Ograve" k="91" />
+<hkern g1="Ccedilla" g2="Oacute" k="137" />
+<hkern g1="Ccedilla" g2="Ocircumflex" k="91" />
+<hkern g1="Ccedilla" g2="Otilde" k="91" />
+<hkern g1="Ccedilla" g2="Odieresis" k="91" />
+<hkern g1="Ccedilla" g2="iacute" k="53" />
+<hkern g1="Ccedilla" g2="yacute" k="204" />
+<hkern g1="Ccedilla" g2="ydieresis" k="164" />
+<hkern g1="Egrave" g2="C" k="127" />
+<hkern g1="Egrave" g2="G" k="127" />
+<hkern g1="Egrave" g2="O" k="129" />
+<hkern g1="Egrave" g2="Q" k="129" />
+<hkern g1="Egrave" g2="c" k="64" />
+<hkern g1="Egrave" g2="j" k="184" />
+<hkern g1="Egrave" g2="v" k="59" />
+<hkern g1="Egrave" g2="w" k="140" />
+<hkern g1="Egrave" g2="y" k="76" />
+<hkern g1="Egrave" g2="Ccedilla" k="127" />
+<hkern g1="Egrave" g2="Ograve" k="129" />
+<hkern g1="Egrave" g2="Oacute" k="129" />
+<hkern g1="Egrave" g2="Ocircumflex" k="129" />
+<hkern g1="Egrave" g2="Otilde" k="129" />
+<hkern g1="Egrave" g2="Odieresis" k="129" />
+<hkern g1="Egrave" g2="ae" k="47" />
+<hkern g1="Egrave" g2="ccedilla" k="64" />
+<hkern g1="Egrave" g2="eth" k="56" />
+<hkern g1="Egrave" g2="yacute" k="78" />
+<hkern g1="Egrave" g2="ydieresis" k="64" />
+<hkern g1="Eacute" g2="C" k="127" />
+<hkern g1="Eacute" g2="G" k="127" />
+<hkern g1="Eacute" g2="O" k="129" />
+<hkern g1="Eacute" g2="Q" k="129" />
+<hkern g1="Eacute" g2="c" k="64" />
+<hkern g1="Eacute" g2="j" k="182" />
+<hkern g1="Eacute" g2="v" k="171" />
+<hkern g1="Eacute" g2="w" k="140" />
+<hkern g1="Eacute" g2="y" k="51" />
+<hkern g1="Eacute" g2="Ccedilla" k="127" />
+<hkern g1="Eacute" g2="Ograve" k="129" />
+<hkern g1="Eacute" g2="Oacute" k="129" />
+<hkern g1="Eacute" g2="Ocircumflex" k="129" />
+<hkern g1="Eacute" g2="Otilde" k="129" />
+<hkern g1="Eacute" g2="Odieresis" k="129" />
+<hkern g1="Eacute" g2="ae" k="47" />
+<hkern g1="Eacute" g2="ccedilla" k="64" />
+<hkern g1="Eacute" g2="eth" k="56" />
+<hkern g1="Eacute" g2="yacute" k="53" />
+<hkern g1="Eacute" g2="ydieresis" k="64" />
+<hkern g1="Ecircumflex" g2="C" k="127" />
+<hkern g1="Ecircumflex" g2="G" k="127" />
+<hkern g1="Ecircumflex" g2="O" k="129" />
+<hkern g1="Ecircumflex" g2="Q" k="129" />
+<hkern g1="Ecircumflex" g2="c" k="64" />
+<hkern g1="Ecircumflex" g2="j" k="175" />
+<hkern g1="Ecircumflex" g2="v" k="171" />
+<hkern g1="Ecircumflex" g2="w" k="140" />
+<hkern g1="Ecircumflex" g2="y" k="51" />
+<hkern g1="Ecircumflex" g2="Ccedilla" k="127" />
+<hkern g1="Ecircumflex" g2="Ograve" k="129" />
+<hkern g1="Ecircumflex" g2="Oacute" k="129" />
+<hkern g1="Ecircumflex" g2="Ocircumflex" k="129" />
+<hkern g1="Ecircumflex" g2="Otilde" k="129" />
+<hkern g1="Ecircumflex" g2="Odieresis" k="129" />
+<hkern g1="Ecircumflex" g2="ae" k="47" />
+<hkern g1="Ecircumflex" g2="ccedilla" k="64" />
+<hkern g1="Ecircumflex" g2="eth" k="56" />
+<hkern g1="Ecircumflex" g2="yacute" k="53" />
+<hkern g1="Ecircumflex" g2="ydieresis" k="64" />
+<hkern g1="Edieresis" g2="C" k="127" />
+<hkern g1="Edieresis" g2="G" k="127" />
+<hkern g1="Edieresis" g2="O" k="129" />
+<hkern g1="Edieresis" g2="Q" k="129" />
+<hkern g1="Edieresis" g2="c" k="64" />
+<hkern g1="Edieresis" g2="j" k="180" />
+<hkern g1="Edieresis" g2="v" k="171" />
+<hkern g1="Edieresis" g2="w" k="140" />
+<hkern g1="Edieresis" g2="y" k="87" />
+<hkern g1="Edieresis" g2="Ccedilla" k="127" />
+<hkern g1="Edieresis" g2="Ograve" k="129" />
+<hkern g1="Edieresis" g2="Oacute" k="129" />
+<hkern g1="Edieresis" g2="Ocircumflex" k="129" />
+<hkern g1="Edieresis" g2="Otilde" k="129" />
+<hkern g1="Edieresis" g2="Odieresis" k="129" />
+<hkern g1="Edieresis" g2="ae" k="47" />
+<hkern g1="Edieresis" g2="ccedilla" k="64" />
+<hkern g1="Edieresis" g2="eth" k="56" />
+<hkern g1="Edieresis" g2="yacute" k="66" />
+<hkern g1="Edieresis" g2="ydieresis" k="64" />
+<hkern g1="Igrave" g2="I" k="42" />
+<hkern g1="Igrave" g2="j" k="283" />
+<hkern g1="Igrave" g2="dotlessi" k="42" />
+<hkern g1="Iacute" g2="j" k="199" />
+<hkern g1="Icircumflex" g2="j" k="207" />
+<hkern g1="Idieresis" g2="I" k="50" />
+<hkern g1="Idieresis" g2="j" k="227" />
+<hkern g1="Idieresis" g2="dotlessi" k="50" />
+<hkern g1="Eth" g2="A" k="128" />
+<hkern g1="Eth" g2="T" k="177" />
+<hkern g1="Eth" g2="V" k="128" />
+<hkern g1="Eth" g2="X" k="146" />
+<hkern g1="Eth" g2="Y" k="114" />
+<hkern g1="Eth" g2="Z" k="146" />
+<hkern g1="Eth" g2="j" k="176" />
+<hkern g1="Eth" g2="Agrave" k="128" />
+<hkern g1="Eth" g2="Aacute" k="128" />
+<hkern g1="Eth" g2="Acircumflex" k="128" />
+<hkern g1="Eth" g2="Atilde" k="128" />
+<hkern g1="Eth" g2="Adieresis" k="128" />
+<hkern g1="Eth" g2="Aring" k="128" />
+<hkern g1="Eth" g2="AE" k="83" />
+<hkern g1="Eth" g2="Yacute" k="114" />
+<hkern g1="Ntilde" g2="j" k="182" />
+<hkern g1="Ograve" g2="A" k="131" />
+<hkern g1="Ograve" g2="S" k="65" />
+<hkern g1="Ograve" g2="T" k="136" />
+<hkern g1="Ograve" g2="V" k="131" />
+<hkern g1="Ograve" g2="W" k="73" />
+<hkern g1="Ograve" g2="X" k="148" />
+<hkern g1="Ograve" g2="Y" k="148" />
+<hkern g1="Ograve" g2="Z" k="148" />
+<hkern g1="Ograve" g2="j" k="160" />
+<hkern g1="Ograve" g2="Agrave" k="131" />
+<hkern g1="Ograve" g2="Aacute" k="131" />
+<hkern g1="Ograve" g2="Acircumflex" k="131" />
+<hkern g1="Ograve" g2="Atilde" k="131" />
+<hkern g1="Ograve" g2="Adieresis" k="131" />
+<hkern g1="Ograve" g2="Aring" k="131" />
+<hkern g1="Ograve" g2="AE" k="85" />
+<hkern g1="Ograve" g2="Yacute" k="148" />
+<hkern g1="Oacute" g2="A" k="131" />
+<hkern g1="Oacute" g2="S" k="65" />
+<hkern g1="Oacute" g2="T" k="133" />
+<hkern g1="Oacute" g2="V" k="131" />
+<hkern g1="Oacute" g2="W" k="73" />
+<hkern g1="Oacute" g2="X" k="148" />
+<hkern g1="Oacute" g2="Y" k="148" />
+<hkern g1="Oacute" g2="Z" k="148" />
+<hkern g1="Oacute" g2="j" k="173" />
+<hkern g1="Oacute" g2="Agrave" k="131" />
+<hkern g1="Oacute" g2="Aacute" k="131" />
+<hkern g1="Oacute" g2="Acircumflex" k="131" />
+<hkern g1="Oacute" g2="Atilde" k="131" />
+<hkern g1="Oacute" g2="Adieresis" k="131" />
+<hkern g1="Oacute" g2="Aring" k="131" />
+<hkern g1="Oacute" g2="AE" k="85" />
+<hkern g1="Oacute" g2="Yacute" k="148" />
+<hkern g1="Ocircumflex" g2="A" k="131" />
+<hkern g1="Ocircumflex" g2="S" k="65" />
+<hkern g1="Ocircumflex" g2="T" k="109" />
+<hkern g1="Ocircumflex" g2="V" k="131" />
+<hkern g1="Ocircumflex" g2="W" k="73" />
+<hkern g1="Ocircumflex" g2="X" k="148" />
+<hkern g1="Ocircumflex" g2="Y" k="148" />
+<hkern g1="Ocircumflex" g2="Z" k="148" />
+<hkern g1="Ocircumflex" g2="j" k="187" />
+<hkern g1="Ocircumflex" g2="Agrave" k="131" />
+<hkern g1="Ocircumflex" g2="Aacute" k="131" />
+<hkern g1="Ocircumflex" g2="Acircumflex" k="131" />
+<hkern g1="Ocircumflex" g2="Atilde" k="131" />
+<hkern g1="Ocircumflex" g2="Adieresis" k="131" />
+<hkern g1="Ocircumflex" g2="Aring" k="131" />
+<hkern g1="Ocircumflex" g2="AE" k="85" />
+<hkern g1="Ocircumflex" g2="Yacute" k="148" />
+<hkern g1="Otilde" g2="A" k="131" />
+<hkern g1="Otilde" g2="S" k="65" />
+<hkern g1="Otilde" g2="T" k="137" />
+<hkern g1="Otilde" g2="V" k="131" />
+<hkern g1="Otilde" g2="W" k="73" />
+<hkern g1="Otilde" g2="X" k="148" />
+<hkern g1="Otilde" g2="Y" k="148" />
+<hkern g1="Otilde" g2="Z" k="148" />
+<hkern g1="Otilde" g2="j" k="169" />
+<hkern g1="Otilde" g2="Agrave" k="131" />
+<hkern g1="Otilde" g2="Aacute" k="131" />
+<hkern g1="Otilde" g2="Acircumflex" k="131" />
+<hkern g1="Otilde" g2="Atilde" k="131" />
+<hkern g1="Otilde" g2="Adieresis" k="131" />
+<hkern g1="Otilde" g2="Aring" k="131" />
+<hkern g1="Otilde" g2="AE" k="85" />
+<hkern g1="Otilde" g2="Yacute" k="148" />
+<hkern g1="Odieresis" g2="A" k="131" />
+<hkern g1="Odieresis" g2="S" k="65" />
+<hkern g1="Odieresis" g2="T" k="149" />
+<hkern g1="Odieresis" g2="V" k="131" />
+<hkern g1="Odieresis" g2="W" k="73" />
+<hkern g1="Odieresis" g2="X" k="148" />
+<hkern g1="Odieresis" g2="Y" k="110" />
+<hkern g1="Odieresis" g2="Z" k="148" />
+<hkern g1="Odieresis" g2="j" k="196" />
+<hkern g1="Odieresis" g2="Agrave" k="131" />
+<hkern g1="Odieresis" g2="Aacute" k="131" />
+<hkern g1="Odieresis" g2="Acircumflex" k="131" />
+<hkern g1="Odieresis" g2="Atilde" k="131" />
+<hkern g1="Odieresis" g2="Adieresis" k="131" />
+<hkern g1="Odieresis" g2="Aring" k="131" />
+<hkern g1="Odieresis" g2="AE" k="85" />
+<hkern g1="Odieresis" g2="Yacute" k="95" />
+<hkern g1="Oslash" g2="A" k="131" />
+<hkern g1="Oslash" g2="S" k="65" />
+<hkern g1="Oslash" g2="j" k="179" />
+<hkern g1="Oslash" g2="Agrave" k="131" />
+<hkern g1="Oslash" g2="Aacute" k="131" />
+<hkern g1="Oslash" g2="Acircumflex" k="131" />
+<hkern g1="Oslash" g2="Atilde" k="131" />
+<hkern g1="Oslash" g2="Adieresis" k="131" />
+<hkern g1="Oslash" g2="Aring" k="131" />
+<hkern g1="Oslash" g2="AE" k="85" />
+<hkern g1="Ugrave" g2="j" k="170" />
+<hkern g1="Uacute" g2="j" k="158" />
+<hkern g1="Ucircumflex" g2="j" k="175" />
+<hkern g1="Udieresis" g2="j" k="187" />
+<hkern g1="Yacute" g2="A" k="205" />
+<hkern g1="Yacute" g2="C" k="109" />
+<hkern g1="Yacute" g2="G" k="109" />
+<hkern g1="Yacute" g2="J" k="212" />
+<hkern g1="Yacute" g2="O" k="109" />
+<hkern g1="Yacute" g2="Q" k="109" />
+<hkern g1="Yacute" g2="S" k="61" />
+<hkern g1="Yacute" g2="a" k="181" />
+<hkern g1="Yacute" g2="c" k="181" />
+<hkern g1="Yacute" g2="d" k="205" />
+<hkern g1="Yacute" g2="e" k="197" />
+<hkern g1="Yacute" g2="f" k="109" />
+<hkern g1="Yacute" g2="g" k="186" />
+<hkern g1="Yacute" g2="j" k="197" />
+<hkern g1="Yacute" g2="m" k="109" />
+<hkern g1="Yacute" g2="n" k="109" />
+<hkern g1="Yacute" g2="o" k="181" />
+<hkern g1="Yacute" g2="p" k="187" />
+<hkern g1="Yacute" g2="q" k="178" />
+<hkern g1="Yacute" g2="r" k="109" />
+<hkern g1="Yacute" g2="s" k="127" />
+<hkern g1="Yacute" g2="t" k="62" />
+<hkern g1="Yacute" g2="u" k="109" />
+<hkern g1="Yacute" g2="v" k="109" />
+<hkern g1="Yacute" g2="w" k="109" />
+<hkern g1="Yacute" g2="x" k="109" />
+<hkern g1="Yacute" g2="y" k="109" />
+<hkern g1="Yacute" g2="z" k="109" />
+<hkern g1="Yacute" g2="Agrave" k="197" />
+<hkern g1="Yacute" g2="Aacute" k="205" />
+<hkern g1="Yacute" g2="Acircumflex" k="228" />
+<hkern g1="Yacute" g2="Atilde" k="197" />
+<hkern g1="Yacute" g2="Adieresis" k="197" />
+<hkern g1="Yacute" g2="Aring" k="189" />
+<hkern g1="Yacute" g2="AE" k="189" />
+<hkern g1="Yacute" g2="Ccedilla" k="109" />
+<hkern g1="Yacute" g2="Eth" k="50" />
+<hkern g1="Yacute" g2="Ograve" k="109" />
+<hkern g1="Yacute" g2="Oacute" k="109" />
+<hkern g1="Yacute" g2="Ocircumflex" k="109" />
+<hkern g1="Yacute" g2="Otilde" k="109" />
+<hkern g1="Yacute" g2="Odieresis" k="109" />
+<hkern g1="Yacute" g2="Oslash" k="109" />
+<hkern g1="Yacute" g2="agrave" k="174" />
+<hkern g1="Yacute" g2="aacute" k="189" />
+<hkern g1="Yacute" g2="acircumflex" k="166" />
+<hkern g1="Yacute" g2="atilde" k="67" />
+<hkern g1="Yacute" g2="adieresis" k="158" />
+<hkern g1="Yacute" g2="aring" k="126" />
+<hkern g1="Yacute" g2="ae" k="197" />
+<hkern g1="Yacute" g2="ccedilla" k="190" />
+<hkern g1="Yacute" g2="egrave" k="174" />
+<hkern g1="Yacute" g2="eacute" k="205" />
+<hkern g1="Yacute" g2="ecircumflex" k="150" />
+<hkern g1="Yacute" g2="edieresis" k="150" />
+<hkern g1="Yacute" g2="eth" k="166" />
+<hkern g1="Yacute" g2="ograve" k="181" />
+<hkern g1="Yacute" g2="oacute" k="174" />
+<hkern g1="Yacute" g2="ocircumflex" k="143" />
+<hkern g1="Yacute" g2="otilde" k="67" />
+<hkern g1="Yacute" g2="odieresis" k="158" />
+<hkern g1="Yacute" g2="oslash" k="181" />
+<hkern g1="Yacute" g2="ugrave" k="109" />
+<hkern g1="Yacute" g2="uacute" k="109" />
+<hkern g1="Yacute" g2="ucircumflex" k="109" />
+<hkern g1="Yacute" g2="udieresis" k="98" />
+<hkern g1="Yacute" g2="yacute" k="109" />
+<hkern g1="Yacute" g2="ydieresis" k="97" />
+<hkern g1="Yacute" g2="dotlessi" k="221" />
+<hkern g1="Thorn" g2="A" k="127" />
+<hkern g1="Thorn" g2="T" k="280" />
+<hkern g1="Thorn" g2="V" k="127" />
+<hkern g1="Thorn" g2="X" k="170" />
+<hkern g1="Thorn" g2="Y" k="186" />
+<hkern g1="Thorn" g2="Z" k="186" />
+<hkern g1="Thorn" g2="j" k="288" />
+<hkern g1="Thorn" g2="Agrave" k="127" />
+<hkern g1="Thorn" g2="Aacute" k="127" />
+<hkern g1="Thorn" g2="Acircumflex" k="127" />
+<hkern g1="Thorn" g2="Atilde" k="127" />
+<hkern g1="Thorn" g2="Adieresis" k="127" />
+<hkern g1="Thorn" g2="Aring" k="127" />
+<hkern g1="Thorn" g2="AE" k="161" />
+<hkern g1="Thorn" g2="Yacute" k="186" />
+<hkern g1="germandbls" g2="T" k="84" />
+<hkern g1="germandbls" g2="V" k="123" />
+<hkern g1="germandbls" g2="W" k="96" />
+<hkern g1="germandbls" g2="Y" k="108" />
+<hkern g1="germandbls" g2="j" k="194" />
+<hkern g1="germandbls" g2="y" k="61" />
+<hkern g1="germandbls" g2="Yacute" k="92" />
+<hkern g1="germandbls" g2="yacute" k="61" />
+<hkern g1="germandbls" g2="ydieresis" k="61" />
+<hkern g1="agrave" g2="T" k="154" />
+<hkern g1="agrave" g2="V" k="172" />
+<hkern g1="agrave" g2="W" k="160" />
+<hkern g1="agrave" g2="Y" k="223" />
+<hkern g1="agrave" g2="f" k="58" />
+<hkern g1="agrave" g2="j" k="146" />
+<hkern g1="agrave" g2="t" k="90" />
+<hkern g1="agrave" g2="v" k="62" />
+<hkern g1="agrave" g2="y" k="61" />
+<hkern g1="agrave" g2="Yacute" k="208" />
+<hkern g1="agrave" g2="icircumflex" k="58" />
+<hkern g1="agrave" g2="idieresis" k="65" />
+<hkern g1="agrave" g2="yacute" k="61" />
+<hkern g1="agrave" g2="ydieresis" k="61" />
+<hkern g1="aacute" g2="T" k="102" />
+<hkern g1="aacute" g2="V" k="172" />
+<hkern g1="aacute" g2="W" k="160" />
+<hkern g1="aacute" g2="Y" k="125" />
+<hkern g1="aacute" g2="f" k="58" />
+<hkern g1="aacute" g2="j" k="181" />
+<hkern g1="aacute" g2="t" k="90" />
+<hkern g1="aacute" g2="v" k="62" />
+<hkern g1="aacute" g2="y" k="61" />
+<hkern g1="aacute" g2="Yacute" k="118" />
+<hkern g1="aacute" g2="icircumflex" k="58" />
+<hkern g1="aacute" g2="idieresis" k="65" />
+<hkern g1="aacute" g2="yacute" k="61" />
+<hkern g1="aacute" g2="ydieresis" k="61" />
+<hkern g1="acircumflex" g2="T" k="214" />
+<hkern g1="acircumflex" g2="V" k="88" />
+<hkern g1="acircumflex" g2="W" k="160" />
+<hkern g1="acircumflex" g2="Y" k="199" />
+<hkern g1="acircumflex" g2="f" k="58" />
+<hkern g1="acircumflex" g2="j" k="207" />
+<hkern g1="acircumflex" g2="t" k="90" />
+<hkern g1="acircumflex" g2="v" k="62" />
+<hkern g1="acircumflex" g2="y" k="61" />
+<hkern g1="acircumflex" g2="Yacute" k="168" />
+<hkern g1="acircumflex" g2="yacute" k="61" />
+<hkern g1="acircumflex" g2="ydieresis" k="61" />
+<hkern g1="atilde" g2="T" k="123" />
+<hkern g1="atilde" g2="V" k="123" />
+<hkern g1="atilde" g2="W" k="97" />
+<hkern g1="atilde" g2="Y" k="122" />
+<hkern g1="atilde" g2="f" k="58" />
+<hkern g1="atilde" g2="j" k="181" />
+<hkern g1="atilde" g2="t" k="90" />
+<hkern g1="atilde" g2="v" k="62" />
+<hkern g1="atilde" g2="y" k="61" />
+<hkern g1="atilde" g2="Yacute" k="122" />
+<hkern g1="atilde" g2="yacute" k="61" />
+<hkern g1="atilde" g2="ydieresis" k="61" />
+<hkern g1="adieresis" g2="T" k="289" />
+<hkern g1="adieresis" g2="V" k="108" />
+<hkern g1="adieresis" g2="W" k="160" />
+<hkern g1="adieresis" g2="Y" k="179" />
+<hkern g1="adieresis" g2="f" k="58" />
+<hkern g1="adieresis" g2="j" k="195" />
+<hkern g1="adieresis" g2="t" k="90" />
+<hkern g1="adieresis" g2="v" k="62" />
+<hkern g1="adieresis" g2="y" k="61" />
+<hkern g1="adieresis" g2="Yacute" k="156" />
+<hkern g1="adieresis" g2="yacute" k="61" />
+<hkern g1="adieresis" g2="ydieresis" k="61" />
+<hkern g1="aring" g2="T" k="111" />
+<hkern g1="aring" g2="V" k="95" />
+<hkern g1="aring" g2="W" k="160" />
+<hkern g1="aring" g2="Y" k="111" />
+<hkern g1="aring" g2="f" k="58" />
+<hkern g1="aring" g2="j" k="190" />
+<hkern g1="aring" g2="t" k="90" />
+<hkern g1="aring" g2="v" k="62" />
+<hkern g1="aring" g2="y" k="61" />
+<hkern g1="aring" g2="Yacute" k="119" />
+<hkern g1="aring" g2="icircumflex" k="58" />
+<hkern g1="aring" g2="idieresis" k="65" />
+<hkern g1="aring" g2="yacute" k="61" />
+<hkern g1="aring" g2="ydieresis" k="61" />
+<hkern g1="ae" g2="A" k="126" />
+<hkern g1="ae" g2="S" k="123" />
+<hkern g1="ae" g2="T" k="225" />
+<hkern g1="ae" g2="V" k="156" />
+<hkern g1="ae" g2="W" k="163" />
+<hkern g1="ae" g2="X" k="157" />
+<hkern g1="ae" g2="Y" k="225" />
+<hkern g1="ae" g2="Z" k="158" />
+<hkern g1="ae" g2="f" k="93" />
+<hkern g1="ae" g2="i" k="50" />
+<hkern g1="ae" g2="j" k="192" />
+<hkern g1="ae" g2="t" k="124" />
+<hkern g1="ae" g2="v" k="97" />
+<hkern g1="ae" g2="w" k="70" />
+<hkern g1="ae" g2="x" k="127" />
+<hkern g1="ae" g2="y" k="96" />
+<hkern g1="ae" g2="z" k="127" />
+<hkern g1="ae" g2="Agrave" k="126" />
+<hkern g1="ae" g2="Aacute" k="126" />
+<hkern g1="ae" g2="Acircumflex" k="126" />
+<hkern g1="ae" g2="Atilde" k="126" />
+<hkern g1="ae" g2="Adieresis" k="126" />
+<hkern g1="ae" g2="Aring" k="126" />
+<hkern g1="ae" g2="AE" k="129" />
+<hkern g1="ae" g2="Igrave" k="47" />
+<hkern g1="ae" g2="Iacute" k="53" />
+<hkern g1="ae" g2="Icircumflex" k="60" />
+<hkern g1="ae" g2="Yacute" k="256" />
+<hkern g1="ae" g2="igrave" k="42" />
+<hkern g1="ae" g2="icircumflex" k="93" />
+<hkern g1="ae" g2="idieresis" k="100" />
+<hkern g1="ae" g2="yacute" k="96" />
+<hkern g1="ae" g2="ydieresis" k="96" />
+<hkern g1="ccedilla" g2="T" k="248" />
+<hkern g1="ccedilla" g2="V" k="123" />
+<hkern g1="ccedilla" g2="Y" k="185" />
+<hkern g1="ccedilla" g2="j" k="41" />
+<hkern g1="ccedilla" g2="Yacute" k="170" />
+<hkern g1="egrave" g2="A" k="92" />
+<hkern g1="egrave" g2="S" k="120" />
+<hkern g1="egrave" g2="T" k="210" />
+<hkern g1="egrave" g2="V" k="75" />
+<hkern g1="egrave" g2="W" k="160" />
+<hkern g1="egrave" g2="X" k="122" />
+<hkern g1="egrave" g2="Y" k="178" />
+<hkern g1="egrave" g2="Z" k="123" />
+<hkern g1="egrave" g2="f" k="58" />
+<hkern g1="egrave" g2="j" k="186" />
+<hkern g1="egrave" g2="t" k="90" />
+<hkern g1="egrave" g2="v" k="62" />
+<hkern g1="egrave" g2="x" k="93" />
+<hkern g1="egrave" g2="y" k="61" />
+<hkern g1="egrave" g2="z" k="93" />
+<hkern g1="egrave" g2="Agrave" k="92" />
+<hkern g1="egrave" g2="Aacute" k="92" />
+<hkern g1="egrave" g2="Acircumflex" k="92" />
+<hkern g1="egrave" g2="Atilde" k="92" />
+<hkern g1="egrave" g2="Adieresis" k="92" />
+<hkern g1="egrave" g2="Aring" k="92" />
+<hkern g1="egrave" g2="AE" k="95" />
+<hkern g1="egrave" g2="Yacute" k="209" />
+<hkern g1="egrave" g2="icircumflex" k="58" />
+<hkern g1="egrave" g2="idieresis" k="65" />
+<hkern g1="egrave" g2="yacute" k="61" />
+<hkern g1="egrave" g2="ydieresis" k="61" />
+<hkern g1="eacute" g2="A" k="92" />
+<hkern g1="eacute" g2="S" k="120" />
+<hkern g1="eacute" g2="T" k="129" />
+<hkern g1="eacute" g2="V" k="172" />
+<hkern g1="eacute" g2="W" k="160" />
+<hkern g1="eacute" g2="X" k="122" />
+<hkern g1="eacute" g2="Y" k="122" />
+<hkern g1="eacute" g2="Z" k="123" />
+<hkern g1="eacute" g2="f" k="58" />
+<hkern g1="eacute" g2="j" k="185" />
+<hkern g1="eacute" g2="t" k="90" />
+<hkern g1="eacute" g2="v" k="62" />
+<hkern g1="eacute" g2="x" k="93" />
+<hkern g1="eacute" g2="y" k="61" />
+<hkern g1="eacute" g2="z" k="93" />
+<hkern g1="eacute" g2="Agrave" k="92" />
+<hkern g1="eacute" g2="Aacute" k="92" />
+<hkern g1="eacute" g2="Acircumflex" k="92" />
+<hkern g1="eacute" g2="Atilde" k="92" />
+<hkern g1="eacute" g2="Adieresis" k="92" />
+<hkern g1="eacute" g2="Aring" k="92" />
+<hkern g1="eacute" g2="AE" k="95" />
+<hkern g1="eacute" g2="Yacute" k="106" />
+<hkern g1="eacute" g2="icircumflex" k="58" />
+<hkern g1="eacute" g2="idieresis" k="65" />
+<hkern g1="eacute" g2="yacute" k="61" />
+<hkern g1="eacute" g2="ydieresis" k="61" />
+<hkern g1="ecircumflex" g2="A" k="92" />
+<hkern g1="ecircumflex" g2="S" k="120" />
+<hkern g1="ecircumflex" g2="T" k="203" />
+<hkern g1="ecircumflex" g2="V" k="100" />
+<hkern g1="ecircumflex" g2="W" k="160" />
+<hkern g1="ecircumflex" g2="X" k="122" />
+<hkern g1="ecircumflex" g2="Y" k="164" />
+<hkern g1="ecircumflex" g2="Z" k="123" />
+<hkern g1="ecircumflex" g2="f" k="58" />
+<hkern g1="ecircumflex" g2="j" k="195" />
+<hkern g1="ecircumflex" g2="t" k="90" />
+<hkern g1="ecircumflex" g2="v" k="62" />
+<hkern g1="ecircumflex" g2="x" k="93" />
+<hkern g1="ecircumflex" g2="y" k="61" />
+<hkern g1="ecircumflex" g2="z" k="93" />
+<hkern g1="ecircumflex" g2="Agrave" k="92" />
+<hkern g1="ecircumflex" g2="Aacute" k="92" />
+<hkern g1="ecircumflex" g2="Acircumflex" k="92" />
+<hkern g1="ecircumflex" g2="Atilde" k="92" />
+<hkern g1="ecircumflex" g2="Adieresis" k="92" />
+<hkern g1="ecircumflex" g2="Aring" k="92" />
+<hkern g1="ecircumflex" g2="AE" k="95" />
+<hkern g1="ecircumflex" g2="Yacute" k="164" />
+<hkern g1="ecircumflex" g2="yacute" k="61" />
+<hkern g1="ecircumflex" g2="ydieresis" k="61" />
+<hkern g1="edieresis" g2="A" k="92" />
+<hkern g1="edieresis" g2="S" k="120" />
+<hkern g1="edieresis" g2="T" k="190" />
+<hkern g1="edieresis" g2="V" k="109" />
+<hkern g1="edieresis" g2="W" k="160" />
+<hkern g1="edieresis" g2="X" k="122" />
+<hkern g1="edieresis" g2="Y" k="142" />
+<hkern g1="edieresis" g2="Z" k="123" />
+<hkern g1="edieresis" g2="f" k="58" />
+<hkern g1="edieresis" g2="j" k="189" />
+<hkern g1="edieresis" g2="t" k="90" />
+<hkern g1="edieresis" g2="v" k="62" />
+<hkern g1="edieresis" g2="x" k="93" />
+<hkern g1="edieresis" g2="y" k="61" />
+<hkern g1="edieresis" g2="z" k="93" />
+<hkern g1="edieresis" g2="Agrave" k="92" />
+<hkern g1="edieresis" g2="Aacute" k="92" />
+<hkern g1="edieresis" g2="Acircumflex" k="92" />
+<hkern g1="edieresis" g2="Atilde" k="92" />
+<hkern g1="edieresis" g2="Adieresis" k="92" />
+<hkern g1="edieresis" g2="Aring" k="92" />
+<hkern g1="edieresis" g2="AE" k="95" />
+<hkern g1="edieresis" g2="Yacute" k="88" />
+<hkern g1="edieresis" g2="yacute" k="61" />
+<hkern g1="edieresis" g2="ydieresis" k="61" />
+<hkern g1="igrave" g2="T" k="40" />
+<hkern g1="igrave" g2="j" k="264" />
+<hkern g1="igrave" g2="dotlessi" k="46" />
+<hkern g1="iacute" g2="j" k="224" />
+<hkern g1="iacute" g2="dotlessi" k="49" />
+<hkern g1="icircumflex" g2="j" k="173" />
+<hkern g1="icircumflex" g2="dotlessi" k="44" />
+<hkern g1="idieresis" g2="A" k="40" />
+<hkern g1="idieresis" g2="T" k="-19" />
+<hkern g1="idieresis" g2="a" k="43" />
+<hkern g1="idieresis" g2="c" k="41" />
+<hkern g1="idieresis" g2="d" k="43" />
+<hkern g1="idieresis" g2="e" k="43" />
+<hkern g1="idieresis" g2="g" k="43" />
+<hkern g1="idieresis" g2="j" k="182" />
+<hkern g1="idieresis" g2="m" k="49" />
+<hkern g1="idieresis" g2="n" k="42" />
+<hkern g1="idieresis" g2="o" k="43" />
+<hkern g1="idieresis" g2="p" k="43" />
+<hkern g1="idieresis" g2="q" k="43" />
+<hkern g1="idieresis" g2="s" k="40" />
+<hkern g1="idieresis" g2="u" k="42" />
+<hkern g1="idieresis" g2="v" k="42" />
+<hkern g1="idieresis" g2="w" k="47" />
+<hkern g1="idieresis" g2="x" k="41" />
+<hkern g1="idieresis" g2="y" k="41" />
+<hkern g1="idieresis" g2="z" k="41" />
+<hkern g1="idieresis" g2="Agrave" k="40" />
+<hkern g1="idieresis" g2="Aacute" k="40" />
+<hkern g1="idieresis" g2="Acircumflex" k="40" />
+<hkern g1="idieresis" g2="Atilde" k="40" />
+<hkern g1="idieresis" g2="Adieresis" k="40" />
+<hkern g1="idieresis" g2="Aring" k="40" />
+<hkern g1="idieresis" g2="AE" k="43" />
+<hkern g1="idieresis" g2="agrave" k="43" />
+<hkern g1="idieresis" g2="aacute" k="43" />
+<hkern g1="idieresis" g2="aring" k="43" />
+<hkern g1="idieresis" g2="ae" k="55" />
+<hkern g1="idieresis" g2="ccedilla" k="41" />
+<hkern g1="idieresis" g2="egrave" k="43" />
+<hkern g1="idieresis" g2="eacute" k="43" />
+<hkern g1="idieresis" g2="ograve" k="43" />
+<hkern g1="idieresis" g2="oacute" k="43" />
+<hkern g1="idieresis" g2="oslash" k="43" />
+<hkern g1="idieresis" g2="ugrave" k="42" />
+<hkern g1="idieresis" g2="uacute" k="42" />
+<hkern g1="idieresis" g2="yacute" k="41" />
+<hkern g1="idieresis" g2="dotlessi" k="109" />
+<hkern g1="eth" g2="T" k="133" />
+<hkern g1="eth" g2="V" k="133" />
+<hkern g1="eth" g2="W" k="107" />
+<hkern g1="eth" g2="X" k="101" />
+<hkern g1="eth" g2="Y" k="132" />
+<hkern g1="eth" g2="Z" k="102" />
+<hkern g1="eth" g2="j" k="200" />
+<hkern g1="eth" g2="t" k="68" />
+<hkern g1="eth" g2="x" k="71" />
+<hkern g1="eth" g2="y" k="40" />
+<hkern g1="eth" g2="z" k="71" />
+<hkern g1="eth" g2="AE" k="42" />
+<hkern g1="eth" g2="Yacute" k="132" />
+<hkern g1="eth" g2="idieresis" k="44" />
+<hkern g1="eth" g2="yacute" k="40" />
+<hkern g1="eth" g2="ydieresis" k="40" />
+<hkern g1="ntilde" g2="T" k="76" />
+<hkern g1="ntilde" g2="V" k="76" />
+<hkern g1="ntilde" g2="W" k="49" />
+<hkern g1="ntilde" g2="Y" k="75" />
+<hkern g1="ntilde" g2="f" k="42" />
+<hkern g1="ntilde" g2="j" k="190" />
+<hkern g1="ntilde" g2="t" k="74" />
+<hkern g1="ntilde" g2="v" k="46" />
+<hkern g1="ntilde" g2="y" k="45" />
+<hkern g1="ntilde" g2="Yacute" k="75" />
+<hkern g1="ntilde" g2="yacute" k="45" />
+<hkern g1="ntilde" g2="ydieresis" k="45" />
+<hkern g1="ograve" g2="A" k="60" />
+<hkern g1="ograve" g2="T" k="115" />
+<hkern g1="ograve" g2="V" k="172" />
+<hkern g1="ograve" g2="W" k="160" />
+<hkern g1="ograve" g2="X" k="122" />
+<hkern g1="ograve" g2="Y" k="169" />
+<hkern g1="ograve" g2="Z" k="123" />
+<hkern g1="ograve" g2="f" k="58" />
+<hkern g1="ograve" g2="j" k="239" />
+<hkern g1="ograve" g2="t" k="90" />
+<hkern g1="ograve" g2="v" k="62" />
+<hkern g1="ograve" g2="x" k="93" />
+<hkern g1="ograve" g2="y" k="61" />
+<hkern g1="ograve" g2="z" k="93" />
+<hkern g1="ograve" g2="Agrave" k="60" />
+<hkern g1="ograve" g2="Aacute" k="60" />
+<hkern g1="ograve" g2="Acircumflex" k="60" />
+<hkern g1="ograve" g2="Atilde" k="60" />
+<hkern g1="ograve" g2="Adieresis" k="60" />
+<hkern g1="ograve" g2="Aring" k="60" />
+<hkern g1="ograve" g2="AE" k="63" />
+<hkern g1="ograve" g2="Yacute" k="169" />
+<hkern g1="ograve" g2="icircumflex" k="58" />
+<hkern g1="ograve" g2="idieresis" k="65" />
+<hkern g1="ograve" g2="yacute" k="61" />
+<hkern g1="ograve" g2="ydieresis" k="61" />
+<hkern g1="oacute" g2="A" k="60" />
+<hkern g1="oacute" g2="T" k="114" />
+<hkern g1="oacute" g2="V" k="172" />
+<hkern g1="oacute" g2="W" k="160" />
+<hkern g1="oacute" g2="X" k="122" />
+<hkern g1="oacute" g2="Y" k="160" />
+<hkern g1="oacute" g2="Z" k="123" />
+<hkern g1="oacute" g2="f" k="58" />
+<hkern g1="oacute" g2="j" k="216" />
+<hkern g1="oacute" g2="t" k="90" />
+<hkern g1="oacute" g2="v" k="62" />
+<hkern g1="oacute" g2="x" k="93" />
+<hkern g1="oacute" g2="y" k="61" />
+<hkern g1="oacute" g2="z" k="93" />
+<hkern g1="oacute" g2="Agrave" k="60" />
+<hkern g1="oacute" g2="Aacute" k="60" />
+<hkern g1="oacute" g2="Acircumflex" k="60" />
+<hkern g1="oacute" g2="Atilde" k="60" />
+<hkern g1="oacute" g2="Adieresis" k="60" />
+<hkern g1="oacute" g2="Aring" k="60" />
+<hkern g1="oacute" g2="AE" k="63" />
+<hkern g1="oacute" g2="Yacute" k="106" />
+<hkern g1="oacute" g2="icircumflex" k="58" />
+<hkern g1="oacute" g2="idieresis" k="65" />
+<hkern g1="oacute" g2="yacute" k="61" />
+<hkern g1="oacute" g2="ydieresis" k="61" />
+<hkern g1="ocircumflex" g2="A" k="60" />
+<hkern g1="ocircumflex" g2="T" k="169" />
+<hkern g1="ocircumflex" g2="V" k="141" />
+<hkern g1="ocircumflex" g2="W" k="160" />
+<hkern g1="ocircumflex" g2="X" k="122" />
+<hkern g1="ocircumflex" g2="Y" k="138" />
+<hkern g1="ocircumflex" g2="Z" k="123" />
+<hkern g1="ocircumflex" g2="f" k="58" />
+<hkern g1="ocircumflex" g2="j" k="224" />
+<hkern g1="ocircumflex" g2="t" k="90" />
+<hkern g1="ocircumflex" g2="v" k="62" />
+<hkern g1="ocircumflex" g2="x" k="93" />
+<hkern g1="ocircumflex" g2="y" k="61" />
+<hkern g1="ocircumflex" g2="z" k="93" />
+<hkern g1="ocircumflex" g2="Agrave" k="60" />
+<hkern g1="ocircumflex" g2="Aacute" k="60" />
+<hkern g1="ocircumflex" g2="Acircumflex" k="60" />
+<hkern g1="ocircumflex" g2="Atilde" k="60" />
+<hkern g1="ocircumflex" g2="Adieresis" k="60" />
+<hkern g1="ocircumflex" g2="Aring" k="60" />
+<hkern g1="ocircumflex" g2="AE" k="63" />
+<hkern g1="ocircumflex" g2="Yacute" k="138" />
+<hkern g1="ocircumflex" g2="yacute" k="61" />
+<hkern g1="ocircumflex" g2="ydieresis" k="61" />
+<hkern g1="otilde" g2="A" k="60" />
+<hkern g1="otilde" g2="T" k="83" />
+<hkern g1="otilde" g2="V" k="123" />
+<hkern g1="otilde" g2="W" k="97" />
+<hkern g1="otilde" g2="X" k="122" />
+<hkern g1="otilde" g2="Y" k="122" />
+<hkern g1="otilde" g2="Z" k="123" />
+<hkern g1="otilde" g2="f" k="58" />
+<hkern g1="otilde" g2="j" k="192" />
+<hkern g1="otilde" g2="t" k="90" />
+<hkern g1="otilde" g2="v" k="62" />
+<hkern g1="otilde" g2="x" k="93" />
+<hkern g1="otilde" g2="y" k="61" />
+<hkern g1="otilde" g2="z" k="93" />
+<hkern g1="otilde" g2="Agrave" k="60" />
+<hkern g1="otilde" g2="Aacute" k="60" />
+<hkern g1="otilde" g2="Acircumflex" k="60" />
+<hkern g1="otilde" g2="Atilde" k="60" />
+<hkern g1="otilde" g2="Adieresis" k="60" />
+<hkern g1="otilde" g2="Aring" k="60" />
+<hkern g1="otilde" g2="AE" k="63" />
+<hkern g1="otilde" g2="Yacute" k="122" />
+<hkern g1="otilde" g2="yacute" k="61" />
+<hkern g1="otilde" g2="ydieresis" k="61" />
+<hkern g1="odieresis" g2="A" k="60" />
+<hkern g1="odieresis" g2="T" k="228" />
+<hkern g1="odieresis" g2="V" k="109" />
+<hkern g1="odieresis" g2="W" k="160" />
+<hkern g1="odieresis" g2="X" k="122" />
+<hkern g1="odieresis" g2="Y" k="133" />
+<hkern g1="odieresis" g2="Z" k="123" />
+<hkern g1="odieresis" g2="f" k="58" />
+<hkern g1="odieresis" g2="j" k="227" />
+<hkern g1="odieresis" g2="t" k="90" />
+<hkern g1="odieresis" g2="v" k="62" />
+<hkern g1="odieresis" g2="x" k="93" />
+<hkern g1="odieresis" g2="y" k="61" />
+<hkern g1="odieresis" g2="z" k="93" />
+<hkern g1="odieresis" g2="Agrave" k="60" />
+<hkern g1="odieresis" g2="Aacute" k="60" />
+<hkern g1="odieresis" g2="Acircumflex" k="60" />
+<hkern g1="odieresis" g2="Atilde" k="60" />
+<hkern g1="odieresis" g2="Adieresis" k="60" />
+<hkern g1="odieresis" g2="Aring" k="60" />
+<hkern g1="odieresis" g2="AE" k="63" />
+<hkern g1="odieresis" g2="Yacute" k="118" />
+<hkern g1="odieresis" g2="yacute" k="61" />
+<hkern g1="odieresis" g2="ydieresis" k="61" />
+<hkern g1="oslash" g2="A" k="60" />
+<hkern g1="oslash" g2="T" k="163" />
+<hkern g1="oslash" g2="V" k="123" />
+<hkern g1="oslash" g2="X" k="122" />
+<hkern g1="oslash" g2="Y" k="141" />
+<hkern g1="oslash" g2="Z" k="123" />
+<hkern g1="oslash" g2="j" k="186" />
+<hkern g1="oslash" g2="Agrave" k="60" />
+<hkern g1="oslash" g2="Aacute" k="60" />
+<hkern g1="oslash" g2="Acircumflex" k="60" />
+<hkern g1="oslash" g2="Atilde" k="60" />
+<hkern g1="oslash" g2="Adieresis" k="60" />
+<hkern g1="oslash" g2="Aring" k="60" />
+<hkern g1="oslash" g2="AE" k="63" />
+<hkern g1="oslash" g2="Yacute" k="141" />
+<hkern g1="oslash" g2="icircumflex" k="58" />
+<hkern g1="oslash" g2="idieresis" k="65" />
+<hkern g1="ugrave" g2="T" k="192" />
+<hkern g1="ugrave" g2="V" k="107" />
+<hkern g1="ugrave" g2="W" k="49" />
+<hkern g1="ugrave" g2="Y" k="97" />
+<hkern g1="ugrave" g2="j" k="199" />
+<hkern g1="ugrave" g2="Yacute" k="97" />
+<hkern g1="ugrave" g2="icircumflex" k="42" />
+<hkern g1="ugrave" g2="idieresis" k="49" />
+<hkern g1="uacute" g2="T" k="93" />
+<hkern g1="uacute" g2="V" k="107" />
+<hkern g1="uacute" g2="W" k="49" />
+<hkern g1="uacute" g2="Y" k="62" />
+<hkern g1="uacute" g2="j" k="195" />
+<hkern g1="uacute" g2="Yacute" k="62" />
+<hkern g1="uacute" g2="icircumflex" k="42" />
+<hkern g1="uacute" g2="idieresis" k="49" />
+<hkern g1="ucircumflex" g2="T" k="134" />
+<hkern g1="ucircumflex" g2="V" k="107" />
+<hkern g1="ucircumflex" g2="W" k="49" />
+<hkern g1="ucircumflex" g2="Y" k="71" />
+<hkern g1="ucircumflex" g2="j" k="204" />
+<hkern g1="ucircumflex" g2="Yacute" k="71" />
+<hkern g1="udieresis" g2="T" k="216" />
+<hkern g1="udieresis" g2="V" k="107" />
+<hkern g1="udieresis" g2="W" k="49" />
+<hkern g1="udieresis" g2="Y" k="97" />
+<hkern g1="udieresis" g2="j" k="222" />
+<hkern g1="udieresis" g2="Yacute" k="97" />
+<hkern g1="yacute" g2="A" k="132" />
+<hkern g1="yacute" g2="J" k="88" />
+<hkern g1="yacute" g2="T" k="91" />
+<hkern g1="yacute" g2="V" k="91" />
+<hkern g1="yacute" g2="X" k="90" />
+<hkern g1="yacute" g2="Y" k="90" />
+<hkern g1="yacute" g2="Z" k="91" />
+<hkern g1="yacute" g2="j" k="226" />
+<hkern g1="yacute" g2="Agrave" k="139" />
+<hkern g1="yacute" g2="Aacute" k="116" />
+<hkern g1="yacute" g2="Acircumflex" k="124" />
+<hkern g1="yacute" g2="Atilde" k="116" />
+<hkern g1="yacute" g2="Adieresis" k="116" />
+<hkern g1="yacute" g2="Aring" k="124" />
+<hkern g1="yacute" g2="AE" k="125" />
+<hkern g1="yacute" g2="Yacute" k="90" />
+<hkern g1="thorn" g2="A" k="60" />
+<hkern g1="thorn" g2="T" k="251" />
+<hkern g1="thorn" g2="V" k="172" />
+<hkern g1="thorn" g2="W" k="160" />
+<hkern g1="thorn" g2="X" k="122" />
+<hkern g1="thorn" g2="Y" k="258" />
+<hkern g1="thorn" g2="Z" k="123" />
+<hkern g1="thorn" g2="f" k="58" />
+<hkern g1="thorn" g2="j" k="250" />
+<hkern g1="thorn" g2="t" k="90" />
+<hkern g1="thorn" g2="v" k="62" />
+<hkern g1="thorn" g2="x" k="93" />
+<hkern g1="thorn" g2="y" k="61" />
+<hkern g1="thorn" g2="z" k="93" />
+<hkern g1="thorn" g2="Agrave" k="60" />
+<hkern g1="thorn" g2="Aacute" k="60" />
+<hkern g1="thorn" g2="Acircumflex" k="60" />
+<hkern g1="thorn" g2="Atilde" k="60" />
+<hkern g1="thorn" g2="Adieresis" k="60" />
+<hkern g1="thorn" g2="Aring" k="60" />
+<hkern g1="thorn" g2="AE" k="63" />
+<hkern g1="thorn" g2="Yacute" k="243" />
+<hkern g1="thorn" g2="icircumflex" k="58" />
+<hkern g1="thorn" g2="idieresis" k="65" />
+<hkern g1="thorn" g2="yacute" k="61" />
+<hkern g1="thorn" g2="ydieresis" k="61" />
+<hkern g1="ydieresis" g2="A" k="125" />
+<hkern g1="ydieresis" g2="J" k="88" />
+<hkern g1="ydieresis" g2="T" k="166" />
+<hkern g1="ydieresis" g2="V" k="60" />
+<hkern g1="ydieresis" g2="X" k="55" />
+<hkern g1="ydieresis" g2="Y" k="63" />
+<hkern g1="ydieresis" g2="Z" k="133" />
+<hkern g1="ydieresis" g2="j" k="227" />
+<hkern g1="ydieresis" g2="Agrave" k="117" />
+<hkern g1="ydieresis" g2="Aacute" k="102" />
+<hkern g1="ydieresis" g2="Acircumflex" k="125" />
+<hkern g1="ydieresis" g2="Atilde" k="117" />
+<hkern g1="ydieresis" g2="Adieresis" k="125" />
+<hkern g1="ydieresis" g2="Aring" k="94" />
+<hkern g1="ydieresis" g2="AE" k="141" />
+<hkern g1="ydieresis" g2="Yacute" k="86" />
+<hkern g1="dotlessi" g2="I" k="51" />
+<hkern g1="dotlessi" g2="T" k="427" />
+<hkern g1="dotlessi" g2="V" k="80" />
+<hkern g1="dotlessi" g2="W" k="81" />
+<hkern g1="dotlessi" g2="Y" k="206" />
+<hkern g1="dotlessi" g2="i" k="63" />
+<hkern g1="dotlessi" g2="j" k="252" />
+<hkern g1="dotlessi" g2="Igrave" k="60" />
+<hkern g1="dotlessi" g2="Iacute" k="66" />
+<hkern g1="dotlessi" g2="Icircumflex" k="73" />
+<hkern g1="dotlessi" g2="Idieresis" k="52" />
+<hkern g1="dotlessi" g2="Yacute" k="206" />
+<hkern g1="dotlessi" g2="igrave" k="55" />
+<hkern g1="dotlessi" g2="iacute" k="52" />
+<hkern g1="dotlessi" g2="icircumflex" k="106" />
+<hkern g1="dotlessi" g2="idieresis" k="113" />
+<hkern g1="dotlessi" g2="dotlessi" k="51" />
+</font>
+</defs>
+</svg>
diff --git a/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.ttf b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.ttf
new file mode 100644
index 0000000..adcddfe
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.ttf differ
diff --git a/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.woff b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.woff
new file mode 100644
index 0000000..6887a69
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.woff differ
diff --git a/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.woff2 b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.woff2
new file mode 100644
index 0000000..5825d54
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-300/Comfortaa-300.woff2 differ
diff --git a/hubs/static/css/fonts/Comfortaa-300/LICENSE.txt b/hubs/static/css/fonts/Comfortaa-300/LICENSE.txt
new file mode 100644
index 0000000..e0bfe25
--- /dev/null
+++ b/hubs/static/css/fonts/Comfortaa-300/LICENSE.txt
@@ -0,0 +1,94 @@
+Copyright (c) 2010, 2011 Johan Aakerlund (aajohan@gmail.com),
+with Reserved Font Name "Comfortaa".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded, 
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.eot b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.eot
new file mode 100644
index 0000000..2c48526
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.eot differ
diff --git a/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.svg b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.svg
new file mode 100644
index 0000000..9ca007a
--- /dev/null
+++ b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.svg
@@ -0,0 +1,2651 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs >
+<font id="Comfortaa" horiz-adv-x="1003" ><font-face
+    font-family="Comfortaa"
+    units-per-em="2048"
+    panose-1="2 15 8 3 7 2 0 6 0 3"
+    ascent="2080"
+    descent="-481"
+    alphabetic="0" />
+<glyph unicode=" " glyph-name="space" horiz-adv-x="560" />
+<glyph unicode="!" glyph-name="exclam" horiz-adv-x="400" d="M353 142Q353 112 342 86T311 41T265 11T211 0Q182 0 157 11T112 41T81 86T69 142Q69 171 80 197T110 242T156 273T211 285Q240 285 266 274T311 243T342 197T353 142ZM107 1494Q107 1538 136 1568T211
+1599Q256 1599 285 1569T315 1494V450Q315 429 307 410T284 377T251 355T211 347Q189 347 170 355T137 378T115 410T107 450V1494Z" />
+<glyph unicode="&quot;" glyph-name="quotedbl" horiz-adv-x="560" d="M269 1494L250 1208Q249 1173 225 1149T165 1124Q130 1124 106 1148T80 1208L61 1494Q61 1515 69 1534T91 1567T125 1590T165 1598Q186 1598 205 1590T238 1568T261 1534T269 1494ZM516 1495L497
+1209Q496 1174 472 1150T412 1125Q377 1125 353 1149T327 1209L308 1495Q308 1516 316 1535T338 1568T372 1591T412 1599Q433 1599 452 1591T485 1569T508 1535T516 1495Z" />
+<glyph unicode="#" glyph-name="numbersign" horiz-adv-x="1280" d="M426 102Q422 80 411 62T383 30T347 8T306 0Q263 0 238 27T212 95Q212 103 213 111L276 464H157Q138 464 121 470T91 489T70 518T63 555L64 574Q67 596 78 614T106 646T143 667T184 675H313L357
+926H238Q197 926 170 952T143 1018Q143 1042 153 1064T180 1102T219 1128T265 1138H394L458 1500Q462 1522 473 1540T501 1572T537 1594T578 1602Q621 1602 646 1574T672 1505Q672 1495 671 1490L609 1138H781L845 1500Q848 1522 859 1540T886 1572T922 1594T964
+1602Q1006 1602 1032 1574T1058 1505Q1058 1495 1057 1490L995 1138H1115Q1133 1138 1150 1132T1180 1113T1200 1084T1208 1047L1207 1028Q1204 1006 1193 988T1165 956T1128 934T1087 926H958L913 675H1033Q1074 675 1100 649T1127 583Q1127 559 1117 537T1090
+499T1051 474T1005 464H876L812 102Q808 80 797 62T770 30T734 8T692 0Q652 0 625 26T598 91Q598 101 600 111L662 464H490L426 102ZM571 926L528 675H698L743 926H571Z" />
+<glyph unicode="$" glyph-name="dollar" horiz-adv-x="1060" d="M457 1337Q361 1275 361 1167Q361 1117 386 1069T457 995V1337ZM665 261Q695 285 717 308T752 358T772 416T779 488Q779 551 751 611T665 709V261ZM457 -47V3Q348 14 254 70T98 218Q77 245 77 282Q77
+327 106 356T181 386Q205 386 223 375T260 347T296 310T337 270T389 236T457 214V770Q392 787 336 824T239 914T175 1030T152 1163Q152 1233 174 1297T236 1413T332 1504T457 1561V1623Q457 1668 486 1697T561 1727Q606 1727 635 1698T665 1623V1560Q701 1551 737
+1534T805 1494T864 1440T911 1375Q918 1362 922 1349T926 1319Q926 1274 897 1245T822 1215Q793 1215 775 1227T741 1257T708 1296T665 1336V942Q735 917 794 872T897 767T964 637T988 491Q988 413 966 341T901 209T800 101T665 27V-47Q665 -68 657 -87T635 -120T601
+-143T561 -151Q539 -151 520 -143T487 -121T465 -87T457 -47Z" />
+<glyph unicode="%" glyph-name="percent" horiz-adv-x="1760" d="M872 1190Q872 1107 840 1033T753 903T623 815T464 782Q380 782 306 814T176 903T88 1033T56 1190Q56 1273 88 1347T175 1478T305 1566T464 1599Q548 1599 622 1567T752 1478T840 1348T872 1190ZM889
+408Q889 491 921 565T1008 695T1138 783T1297 816Q1380 816 1454 784T1584 697T1672 568T1705 408Q1705 323 1673 249T1585 120T1455 32T1297 0Q1213 0 1139 32T1010 120T922 250T889 408ZM464 1390Q422 1390 386 1374T323 1331T281 1267T265 1190Q265 1149 280
+1113T322 1050T385 1007T464 991Q505 991 541 1007T605 1050T647 1113T663 1190Q663 1230 647 1266T604 1330T541 1374T464 1390ZM1297 607Q1256 607 1220 592T1156 549T1114 486T1098 408Q1098 367 1113 331T1156 267T1219 225T1297 209Q1338 209 1374 225T1438
+268T1481 331T1497 408Q1497 449 1481 485T1438 548T1375 591T1297 607ZM342 0Q320 0 301 8T268 30T246 64T238 104Q238 147 263 175L1340 1558Q1376 1600 1424 1600Q1446 1600 1465 1592T1498 1569T1520 1536T1529 1495Q1529 1459 1508 1432L420 33Q390 0 342
+0Z" />
+<glyph unicode="&amp;" glyph-name="ampersand" horiz-adv-x="1440" d="M510 1007L605 1082Q645 1115 667 1151T689 1225Q689 1259 676 1289T640 1341T588 1377T525 1390Q491 1390 461 1377T409 1341T375 1288T362 1225Q362 1157 408 1110L510 1007ZM810 407L489
+729L399 660Q344 614 314 568T284 473Q284 413 303 365T355 283T432 231T525 212Q624 212 695 282L810 407ZM659 859L955 560L1106 722Q1120 737 1140 744T1181 752Q1226 752 1257 722T1288 646Q1288 625 1281 608T1260 574L1106 409L1334 179Q1365 148 1365 106Q1365
+84 1357 65T1334 31T1300 8T1258 0Q1216 0 1184 28L960 254L846 133Q712 0 525 0Q433 0 351 35T206 133T108 283T72 473Q72 568 119 653T265 815L342 875L258 959H259Q149 1071 149 1225Q149 1302 179 1371T261 1491T381 1572T525 1602Q603 1602 671 1572T790 1490T871
+1370T901 1225Q901 1058 750 927L659 859Z" />
+<glyph unicode="&apos;" glyph-name="quotesingle" horiz-adv-x="320" d="M269 1494L250 1208Q249 1173 225 1149T165 1124Q130 1124 106 1148T80 1208L61 1494Q61 1515 69 1534T91 1567T125 1590T165 1598Q186 1598 205 1590T238 1568T261 1534T269 1494Z" />
+<glyph unicode="(" glyph-name="parenleft" horiz-adv-x="560" d="M303 1525Q319 1560 345 1578T402 1597Q424 1597 443 1589T476 1565T498 1531T506 1489Q503 1455 491 1436Q277 998 277 560Q277 343 333 120T493 -321Q499 -334 502 -346T506 -373Q506 -418 477
+-449T402 -480Q370 -480 346 -464T304 -409Q71 74 71 561Q71 1049 303 1525Z" />
+<glyph unicode=")" glyph-name="parenright" horiz-adv-x="560" d="M506 561Q506 315 448 75T273 -409Q255 -447 231 -463T175 -480Q130 -480 101 -449T71 -373Q71 -358 74 -346T84 -321Q188 -104 244 119T300 560Q300 998 86 1436Q74 1455 71 1489Q71 1511 79
+1530T101 1565T134 1588T175 1597Q207 1597 232 1579T274 1525Q390 1284 447 1045T506 561Z" />
+<glyph unicode="*" glyph-name="asterisk" horiz-adv-x="780" d="M283 1233L180 1237Q138 1242 108 1270T78 1342Q78 1366 87 1385T112 1417T145 1438T182 1446Q199 1447 216 1441T247 1424L327 1366L298 1460Q293 1478 293 1494Q293 1538 322 1568T397 1599Q442
+1599 471 1569T501 1494Q501 1478 496 1460L467 1364L547 1424Q577 1446 612 1446Q631 1446 649 1439T683 1417T707 1384T717 1341Q717 1322 710 1304T690 1272T658 1248T616 1237L512 1232L595 1174Q643 1139 643 1087Q643 1045 613 1015T524 984Q493 987 473
+1005T440 1055L398 1158L356 1053Q345 1018 319 1001T256 983Q232 983 213 992T180 1015T159 1048T152 1087Q151 1113 164 1135T200 1174L283 1233Z" />
+<glyph unicode="+" glyph-name="plus" horiz-adv-x="1120" d="M941 683H666V408Q666 363 637 334T562 304Q517 304 487 333T457 408V683H182Q137 683 108 713T78 788Q78 833 107 862T182 892H457V1167Q457 1210 487 1241T562 1272Q607 1272 636 1242T666 1167V892H941Q984
+892 1015 862T1046 787Q1046 744 1015 714T941 683Z" />
+<glyph unicode="," glyph-name="comma" horiz-adv-x="400" d="M353 142Q353 86 343 21T312 -99T261 -191T192 -228Q156 -228 132 -203T107 -142Q107 -111 129 -87T151 -36Q151 0 110 42Q69 83 69 142Q69 201 110 242T211 284Q270 284 311 243T353 142Z" />
+<glyph unicode="-" glyph-name="hyphen" horiz-adv-x="800" d="M178 456Q133 456 104 485T74 560Q74 605 103 634T178 664H634Q679 664 708 635T738 560Q738 515 709 486T634 456H178Z" />
+<glyph unicode="." glyph-name="period" horiz-adv-x="400" d="M343 142Q343 83 302 42T201 0Q142 0 101 41T59 142Q59 201 100 242T201 284Q260 284 301 243T343 142Z" />
+<glyph unicode="/" glyph-name="slash" horiz-adv-x="960" d="M893 1452L276 -90Q239 -152 180 -152Q135 -152 106 -122T76 -47Q76 -27 85 -4L702 1538Q710 1555 725 1570Q755 1600 798 1600Q841 1600 871 1570T902 1496Q902 1472 893 1452Z" />
+<glyph unicode="0" glyph-name="zero" horiz-adv-x="1120" d="M78 801Q78 990 111 1138T206 1390T359 1547T567 1602Q684 1602 775 1547T928 1388T1023 1136T1056 801Q1056 615 1024 467T929 215T775 56T567 0Q450 0 359 54T206 211T111 463T78 801ZM567 1390Q497
+1390 445 1345T358 1222T306 1036T289 801Q289 673 306 565T358 378T445 256T567 212Q638 212 690 257T777 380T828 567T845 801Q845 926 828 1034T776 1221T690 1345T567 1390Z" />
+<glyph unicode="1" glyph-name="one" horiz-adv-x="560" d="M288 104V1349Q258 1339 225 1327T165 1314Q120 1314 91 1343T61 1418Q61 1450 77 1475T128 1516L357 1592Q375 1599 393 1599Q438 1599 467 1569T497 1494V104Q497 61 467 31T392 0Q349 0 319 30T288 104Z" />
+<glyph unicode="2" glyph-name="two" horiz-adv-x="1120" d="M78 1115Q78 1215 116 1303T221 1457T375 1561T562 1599Q661 1599 749 1560T903 1455T1007 1301T1046 1115Q1046 1015 1010 929T904 773L418 209H941Q985 209 1015 178T1046 104Q1046 61 1016 31T941
+0H182Q160 0 141 8T108 30T86 64T78 104Q78 149 107 178L755 918Q837 1000 837 1115Q837 1171 815 1221T756 1308T668 1368T562 1390Q505 1390 455 1369T368 1310T309 1223T287 1115Q287 1072 257 1042T182 1011Q139 1011 109 1041T78 1115Z" />
+<glyph unicode="3" glyph-name="three" horiz-adv-x="1120" d="M154 1186Q154 1273 186 1348T274 1480T404 1569T562 1602Q646 1602 720 1569T849 1479T937 1347T970 1186Q970 1020 847 891Q1046 732 1046 492Q1046 391 1008 302T904 145T750 39T562 0Q462 0 374
+38T220 144T116 300T78 492Q78 538 107 568T182 598Q226 598 256 568T287 492Q287 433 308 382T367 294T454 234T562 212Q619 212 669 234T757 295T815 384T837 492Q837 549 816 600T757 689T670 749T562 772Q517 772 487 802T457 878Q457 924 487 954T562 984Q602
+984 638 1000T702 1043T745 1108T761 1186Q761 1228 745 1265T702 1329T638 1373T562 1390Q521 1390 485 1374T421 1330T378 1265T363 1186Q363 1143 333 1112T258 1081Q215 1081 185 1112T154 1186Z" />
+<glyph unicode="4" glyph-name="four" horiz-adv-x="1280" d="M763 611V1160L384 611H763ZM763 104V403H184Q139 403 110 432T80 507Q80 542 100 568L782 1555Q796 1575 818 1587T868 1599Q889 1599 908 1591T941 1568T964 1535T972 1494V611H1095Q1139 611 1169
+582T1200 507Q1200 462 1170 433T1095 403H972V104Q972 61 942 31T867 0Q824 0 794 30T763 104Z" />
+<glyph unicode="5" glyph-name="five" horiz-adv-x="1200" d="M942 1390H363V1044H601Q706 1044 800 1003T967 892T1081 726T1123 522Q1123 415 1082 320T969 154T803 42T601 0Q494 0 399 41T233 154T121 320T79 522Q79 567 108 596T183 626Q227 626 257 597T288
+522Q288 457 312 400T379 301T479 234T601 209Q665 209 722 233T822 301T889 400T914 522Q914 586 889 643T822 742T722 810T601 835H259Q214 835 185 865T155 940V1494Q155 1538 184 1568T259 1599H942Q986 1599 1016 1568T1047 1494Q1047 1451 1017 1421T942
+1390Z" />
+<glyph unicode="6" glyph-name="six" horiz-adv-x="1120" d="M533 968H562Q662 968 750 930T904 825T1008 671T1046 484Q1046 385 1008 297T904 143T750 39T562 0Q462 0 374 38T220 142T116 296T78 484Q78 632 156 749L155 747L635 1544Q650 1569 674 1584T728
+1600Q773 1600 802 1570T832 1495Q832 1470 818 1442L533 968ZM837 484Q837 540 816 590T757 677T670 737T562 759Q504 759 454 738T367 679T309 592T287 484Q287 426 308 376T367 289T454 231T562 209Q619 209 669 231T757 290T815 378T837 484Z" />
+<glyph unicode="7" glyph-name="seven" horiz-adv-x="1120" d="M96 169L778 1391H195Q150 1391 121 1420T91 1495Q91 1539 120 1569T195 1600H954Q976 1600 995 1592T1028 1569T1050 1536T1059 1495Q1059 1468 1044 1439L276 58Q268 43 256 31Q225 0 181 0Q138
+0 108 30T77 104Q77 136 96 169Z" />
+<glyph unicode="8" glyph-name="eight" horiz-adv-x="1120" d="M569 1386Q527 1386 490 1370T426 1327T382 1262T366 1183Q366 1142 381 1105T424 1041T489 998T569 982Q609 982 646 998T710 1041T754 1105T771 1183Q771 1225 755 1262T710 1326T646 1370T569
+1386ZM569 770Q510 770 460 748T372 689T312 600T290 491Q290 432 312 382T371 294T459 234T569 212Q627 212 678 234T766 295T826 383T848 491Q848 548 826 598T767 687T678 747T569 770ZM279 888Q155 1012 155 1183Q155 1269 188 1345T277 1477T409 1565T569
+1598Q654 1598 729 1565T860 1476T949 1344T982 1183Q982 1013 858 888Q1060 729 1060 491Q1060 390 1021 301T916 145T760 39T569 0Q467 0 378 38T222 144T117 300T78 491Q78 730 279 888Z" />
+<glyph unicode="9" glyph-name="nine" horiz-adv-x="1120" d="M597 615H569Q468 615 379 654T223 759T117 915T78 1107Q78 1209 117 1298T223 1454T379 1559T569 1598Q669 1598 758 1559T914 1452T1020 1296T1060 1107Q1060 958 980 839L509 57Q473 0 415 0Q392
+0 373 8T339 31T316 65T308 105Q308 134 323 160L597 615ZM290 1107Q290 1047 312 996T373 908T461 849T569 827Q627 827 677 849T766 910T826 998T848 1107Q848 1164 826 1214T765 1303T677 1363T569 1386Q511 1386 461 1364T372 1305T312 1217T290 1107Z" />
+<glyph unicode=":" glyph-name="colon" horiz-adv-x="400" d="M343 142Q343 83 302 42T201 0Q142 0 101 41T59 142Q59 201 100 242T201 284Q260 284 301 243T343 142ZM343 976Q343 917 302 876T201 834Q142 834 101 875T59 976Q59 1035 100 1076T201 1118Q260
+1118 301 1077T343 976Z" />
+<glyph unicode=";" glyph-name="semicolon" horiz-adv-x="400" d="M343 976Q343 917 302 876T201 834Q142 834 101 875T59 976Q59 1035 100 1076T201 1118Q260 1118 301 1077T343 976ZM343 142Q343 86 333 21T302 -99T251 -191T182 -228Q146 -228 122 -203T97
+-142Q97 -111 119 -87T141 -36Q141 0 100 42Q59 83 59 142Q59 201 100 242T201 284Q260 284 301 243T343 142Z" />
+<glyph unicode="&lt;" glyph-name="less" horiz-adv-x="1120" d="M889 1259Q911 1272 941 1272Q963 1272 982 1264T1015 1241T1037 1208T1046 1167Q1046 1110 994 1076L385 712L994 346Q1046 312 1046 256Q1046 211 1016 182T941 152Q911 152 889 165L133 619Q78
+653 78 712Q78 767 133 804L889 1259Z" />
+<glyph unicode="=" glyph-name="equal" horiz-adv-x="1040" d="M864 835H181Q136 835 107 865T77 940Q77 985 106 1014T181 1044H864Q907 1044 937 1014T968 940Q968 896 938 866T864 835ZM864 379H181Q136 379 107 409T77 484Q77 529 106 558T181 588H864Q907
+588 937 558T968 484Q968 440 938 410T864 379Z" />
+<glyph unicode="&gt;" glyph-name="greater" horiz-adv-x="1120" d="M991 804Q1046 767 1046 712Q1046 653 991 619L235 165Q213 152 183 152Q139 152 109 181T78 256Q78 312 130 346L739 712L130 1076Q78 1110 78 1167Q78 1189 86 1208T109 1241T142 1263T183
+1272Q213 1272 235 1259L991 804Z" />
+<glyph unicode="?" glyph-name="question" horiz-adv-x="1120" d="M287 1115Q287 1093 279 1074T256 1041T223 1018T182 1010Q137 1010 108 1040T78 1115Q78 1215 116 1303T221 1457T375 1561T562 1599Q661 1599 749 1560T903 1455T1007 1301T1046 1115Q1046 917
+903 771L746 626Q666 546 666 451Q666 406 637 377T562 347Q517 347 487 376T457 451Q457 631 600 774L757 920Q837 1003 837 1115Q837 1171 815 1221T756 1308T668 1368T562 1390Q505 1390 455 1369T368 1310T309 1223T287 1115ZM704 142Q704 83 663 42T562 0Q503
+0 462 41T420 142Q420 201 461 242T562 284Q621 284 662 243T704 142Z" />
+<glyph unicode="@" glyph-name="at" horiz-adv-x="2240" d="M1121 917Q1047 917 981 889T867 813T790 699T761 559Q761 485 789 419T866 305T981 229T1121 201Q1195 201 1261 229T1375 307T1451 421T1479 559Q1479 632 1451 697T1375 811T1261 888T1121 917ZM1742
+-92Q1512 -92 1484 115Q1324 -14 1121 -14Q884 -14 716 154Q548 322 548 559Q548 796 716 964Q884 1132 1121 1132Q1358 1132 1525 964Q1694 796 1694 559V170Q1694 122 1742 122Q1946 122 1946 559Q1946 734 1886 878T1704 1142Q1582 1263 1438 1324T1121 1385Q778
+1385 536 1142Q295 902 295 559Q295 216 536 -24Q778 -267 1121 -267Q1303 -267 1461 -197Q1485 -183 1511 -183Q1556 -183 1586 -214T1617 -291Q1617 -324 1598 -352T1549 -390Q1351 -480 1121 -480Q691 -480 386 -175Q82 130 82 559Q82 987 386 1293Q691 1598
+1121 1598Q1549 1598 1854 1293Q2159 987 2159 559Q2159 -92 1742 -92Z" />
+<glyph unicode="A" glyph-name="A" horiz-adv-x="1440" d="M897 752L723 1201L549 752H897ZM88 154L622 1528Q654 1600 723 1600Q794 1600 824 1528L1360 149Q1368 129 1368 106Q1368 62 1337 31T1262 0Q1218 0 1188 31Q1172 47 1164 65L979 540H467L281 65Q273
+47 257 31Q226 0 182 0Q138 0 108 31T77 106Q77 130 88 154Z" />
+<glyph unicode="B" glyph-name="B" horiz-adv-x="1120" d="M286 1388V983H489Q531 983 567 999T631 1043T675 1107T691 1186Q691 1227 675 1263T631 1328T567 1372T489 1388H286ZM286 771V212H566Q624 212 675 234T763 294T823 383T845 492Q845 549 823 600T763
+689T674 749T566 771H286ZM489 1600Q574 1600 649 1568T781 1479T870 1347T903 1186Q903 1034 809 921Q870 885 916 838T993 736T1041 619T1057 492Q1057 391 1018 302T913 145T757 39T566 0H180Q158 0 139 8T106 31T83 64T74 106V1494Q74 1516 82 1535T105 1569T139
+1591T180 1600H489Z" />
+<glyph unicode="C" glyph-name="C" horiz-adv-x="1480" d="M1308 360Q1330 360 1349 352T1382 329T1405 296T1414 254Q1414 212 1381 178Q1158 0 878 0Q546 0 312 234Q78 468 78 800Q78 1131 312 1365Q547 1600 878 1600Q1162 1600 1391 1413Q1419 1386 1419 1340Q1419
+1317 1411 1298T1389 1265T1355 1242T1313 1234Q1274 1234 1240 1264Q1164 1324 1073 1356T878 1388Q634 1388 461 1215Q290 1044 290 800Q290 555 461 384Q633 212 878 212Q1087 212 1246 341Q1272 359 1308 360Z" />
+<glyph unicode="D" glyph-name="D" horiz-adv-x="1360" d="M491 212Q734 212 906 384Q993 471 1036 573T1079 800Q1079 1042 906 1215Q733 1388 491 1388H289V212H491ZM491 1600Q821 1600 1056 1365Q1174 1247 1232 1108T1291 800Q1291 469 1056 234Q822 0 491
+0H183Q161 0 142 8T108 31T85 64T76 106V1494Q76 1516 84 1535T107 1569T141 1591T183 1600H491Z" />
+<glyph unicode="E" glyph-name="E" horiz-adv-x="1280" d="M1107 212Q1151 212 1182 181T1213 106Q1213 62 1182 31T1107 0H182Q159 0 140 8T107 30T84 64T76 106V1494Q76 1516 84 1535T106 1569T140 1592T182 1600H1107Q1151 1600 1182 1569T1213 1494Q1213 1450
+1182 1419T1107 1388H288V906H876Q920 906 951 875T982 800Q982 756 951 725T876 694H288V212H1107Z" />
+<glyph unicode="F" glyph-name="F" horiz-adv-x="1280" d="M76 106V1494Q76 1516 84 1535T106 1569T140 1592T182 1600H1107Q1151 1600 1182 1569T1213 1494Q1213 1450 1182 1419T1107 1388H288V906H876Q920 906 951 875T982 800Q982 756 951 725T876 694H288V106Q288
+62 257 31T182 0Q138 0 107 31T76 106Z" />
+<glyph unicode="G" glyph-name="G" horiz-adv-x="1500" d="M1414 254Q1414 212 1381 178Q1158 0 878 0Q546 0 312 234Q78 468 78 800Q78 1131 312 1365Q547 1600 878 1600Q1162 1600 1391 1413Q1419 1387 1419 1340Q1419 1317 1411 1298T1389 1265T1355 1242T1313
+1234Q1272 1234 1240 1264Q1164 1324 1073 1356T878 1388Q634 1388 461 1215Q290 1044 290 800Q290 555 461 384Q633 212 878 212Q1059 212 1202 307V617H926Q881 617 851 647T820 723Q820 745 828 764T850 798T884 821T926 829H1309Q1330 829 1349 821T1382 798T1405
+764T1414 723V254Z" />
+<glyph unicode="H" glyph-name="H" horiz-adv-x="1280" d="M1213 106Q1213 62 1182 31T1107 0Q1063 0 1032 31T1001 106V694H288V106Q288 62 257 31T182 0Q138 0 107 31T76 106V1494Q76 1538 107 1569T182 1600Q226 1600 257 1569T288 1494V906H1001V1494Q1001
+1538 1032 1569T1107 1600Q1151 1600 1182 1569T1213 1494V106Z" />
+<glyph unicode="I" glyph-name="I" horiz-adv-x="480" d="M358 106Q358 62 327 31T252 0Q208 0 177 31T146 106V1494Q146 1538 177 1569T252 1600Q296 1600 327 1569T358 1494V106Z" />
+<glyph unicode="J" glyph-name="J" horiz-adv-x="1120" d="M286 492Q286 433 308 382T367 294T456 234T566 212Q624 212 675 234T763 294T823 383T845 492V1494Q845 1538 876 1569T951 1600Q995 1600 1026 1569T1057 1494V492Q1057 391 1018 302T913 145T757 39T566
+0Q464 0 375 39T219 145T113 302T74 492Q74 536 105 567T180 598Q224 598 255 567T286 492Z" />
+<glyph unicode="K" glyph-name="K" horiz-adv-x="1200" d="M75 1494Q75 1538 106 1569T181 1600Q225 1600 256 1569T287 1494V902L952 1567Q985 1600 1029 1600Q1051 1600 1070 1592T1104 1570T1127 1536T1135 1494Q1135 1450 1104 1419L580 894L1115 169Q1135
+141 1135 109Q1135 88 1127 68T1105 33T1072 9T1031 0Q972 0 942 45L428 742L287 601V106Q287 62 256 31T181 0Q137 0 106 31T75 106V1494Z" />
+<glyph unicode="L" glyph-name="L" horiz-adv-x="1200" d="M75 1494Q75 1538 106 1569T181 1600Q225 1600 256 1569T287 1494V212H1029Q1073 212 1104 181T1135 106Q1135 62 1104 31T1029 0H181Q158 0 139 8T106 30T83 64T75 106V1494Z" />
+<glyph unicode="M" glyph-name="M" horiz-adv-x="1760" d="M80 106V1494Q80 1516 88 1535T110 1569T144 1592T186 1600Q248 1600 280 1543L880 344L1480 1543Q1516 1600 1574 1600Q1596 1600 1615 1592T1649 1570T1672 1536T1680 1494V106Q1680 62 1649 31T1574
+0Q1530 0 1499 31T1468 106V1044L972 53Q941 0 880 0Q814 0 783 64L292 1044V106Q292 62 261 31T186 0Q142 0 111 31T80 106Z" />
+<glyph unicode="N" glyph-name="N" horiz-adv-x="1440" d="M77 106V1494Q77 1516 85 1535T107 1569T141 1592T183 1600Q230 1600 265 1561L1157 414V1494Q1157 1538 1188 1569T1263 1600Q1307 1600 1338 1569T1369 1494V106Q1369 83 1361 64T1339 31T1305 8T1263
+0Q1216 0 1182 37L289 1184V106Q289 62 258 31T183 0Q139 0 108 31T77 106Z" />
+<glyph unicode="O" glyph-name="O" horiz-adv-x="1760" d="M880 1388Q756 1388 654 1345T464 1215Q377 1128 335 1026T292 800Q292 556 464 384Q636 212 880 212Q1124 212 1296 384Q1468 556 1468 800Q1468 1043 1296 1215Q1123 1388 880 1388ZM1680 800Q1680
+469 1445 234Q1211 0 880 0Q548 0 314 234Q80 468 80 800Q80 1131 314 1365Q549 1600 880 1600Q1210 1600 1445 1365Q1563 1247 1621 1107T1680 800Z" />
+<glyph unicode="P" glyph-name="P" horiz-adv-x="1080" d="M286 1388V752H488Q553 752 610 777T711 845T780 946T806 1070Q806 1137 781 1195T712 1296T610 1363T488 1388H286ZM74 106V1494Q74 1516 82 1535T104 1569T138 1592T180 1600H488Q560 1600 627 1581T754
+1527T862 1444T945 1336T999 1210T1019 1070Q1019 852 862 695Q707 540 488 540H286V106Q286 62 255 31T180 0Q136 0 105 31T74 106Z" />
+<glyph unicode="Q" glyph-name="Q" horiz-adv-x="1760" d="M1366 164Q1260 80 1140 40T880 0Q548 0 314 234Q80 468 80 800Q80 1131 314 1365Q549 1600 880 1600Q1210 1600 1445 1365Q1563 1247 1621 1108T1680 800Q1680 660 1640 540T1516 314L1650 180Q1680
+147 1680 106Q1680 83 1672 64T1650 31T1616 8T1574 0Q1528 0 1498 31L1366 164ZM1074 455Q1044 490 1044 530Q1044 552 1052 571T1074 605T1108 628T1150 636Q1194 636 1225 605L1365 466Q1468 611 1468 800Q1468 1043 1296 1215Q1123 1388 880 1388Q756 1388
+654 1345T464 1215Q377 1128 335 1026T292 800Q292 556 464 384Q636 212 880 212Q1069 212 1215 315L1074 455Z" />
+<glyph unicode="R" glyph-name="R" horiz-adv-x="1200" d="M287 1388V829H567Q625 829 676 851T764 911T824 1000T846 1108Q846 1166 824 1217T764 1306T675 1366T567 1388H287ZM75 106V1494Q75 1516 83 1535T105 1569T139 1592T181 1600H567Q668 1600 757 1561T913
+1455T1019 1299T1058 1108Q1058 1042 1042 980T993 862T912 759T799 675L1118 164Q1135 136 1135 106Q1135 83 1127 64T1105 31T1071 8T1029 0Q973 0 938 52L585 617H287V106Q287 62 256 31T181 0Q137 0 106 31T75 106Z" />
+<glyph unicode="S" glyph-name="S" horiz-adv-x="1060" d="M95 222Q74 249 74 286Q74 308 82 327T104 361T138 384T180 392Q239 392 269 343Q311 278 374 245T510 212Q567 212 617 234T705 295T765 384T787 494Q787 549 767 597T711 682T630 742T531 770Q451 777
+382 812T261 902T180 1029T150 1181Q150 1279 187 1358T296 1500H295Q410 1600 565 1600Q615 1600 665 1588T761 1550T848 1486T921 1397Q936 1371 936 1340Q936 1317 928 1298T906 1265T872 1242T830 1234Q810 1234 795 1240T767 1257T743 1282T718 1316Q694 1351
+653 1368T563 1386Q525 1386 489 1371T425 1328T380 1264T362 1184Q362 1145 376 1110T416 1048T474 1003T547 982Q640 975 722 934T865 828T963 677T999 498Q999 264 826 118H827Q688 0 511 0Q452 0 393 14T280 57T178 127T95 222Z" />
+<glyph unicode="T" glyph-name="T" horiz-adv-x="1360" d="M1185 1388H790V106Q790 62 759 31T684 0Q640 0 609 31T578 106V1388H183Q139 1388 108 1419T77 1494Q77 1538 108 1569T183 1600H1185Q1229 1600 1260 1569T1291 1494Q1291 1450 1260 1419T1185 1388Z" />
+<glyph unicode="U" glyph-name="U" horiz-adv-x="1280" d="M288 1494V569Q288 496 316 431T392 318T505 241T644 212Q718 212 783 240T896 317T973 430T1001 569V1494Q1001 1538 1032 1569T1107 1600Q1151 1600 1182 1569T1213 1494V569Q1213 491 1193 419T1135
+284T1046 168T931 79T795 21T644 0Q408 0 243 167Q76 334 76 569V1494Q76 1538 107 1569T182 1600Q226 1600 257 1569T288 1494Z" />
+<glyph unicode="V" glyph-name="V" horiz-adv-x="1440" d="M723 0Q653 0 626 67L89 1440Q77 1471 77 1494Q77 1516 85 1535T107 1569T141 1592T183 1600Q253 1600 281 1537L723 400L1165 1537Q1189 1600 1263 1600Q1285 1600 1304 1592T1338 1570T1361 1536T1369
+1494Q1369 1468 1357 1440L820 67Q793 0 723 0Z" />
+<glyph unicode="W" glyph-name="W" horiz-adv-x="1920" d="M288 1529L573 502L857 1528Q865 1559 893 1579T959 1600Q991 1600 1019 1582T1059 1529L1344 502L1630 1529Q1637 1551 1655 1569Q1686 1600 1730 1600Q1774 1600 1804 1569T1835 1494Q1834 1474 1828
+1452L1451 86Q1437 47 1409 24T1344 0Q1299 0 1270 32Q1249 54 1238 84L959 1095L680 86Q666 47 638 24T573 0Q528 0 498 32Q478 52 467 84L88 1453Q82 1476 82 1494Q82 1538 113 1569T188 1600Q232 1600 263 1569Q280 1551 288 1529Z" />
+<glyph unicode="X" glyph-name="X" horiz-adv-x="1440" d="M257 31Q226 0 182 0Q138 0 107 30T76 105Q76 143 99 172L588 800L96 1432Q77 1459 77 1494Q77 1538 108 1569T183 1600Q231 1600 258 1569L723 973L1188 1569Q1216 1600 1263 1600Q1307 1600 1337 1569T1368
+1494Q1368 1459 1349 1432L858 800L1347 172Q1369 143 1369 105Q1369 61 1339 31T1264 0Q1211 0 1181 38L723 627L257 31Z" />
+<glyph unicode="Y" glyph-name="Y" horiz-adv-x="1280" d="M268 1556L644 993L1020 1556Q1051 1600 1107 1600Q1151 1600 1181 1569T1212 1494Q1212 1458 1196 1434L750 768V106Q750 62 719 31T644 0Q601 0 570 31T538 106V768L93 1434Q76 1460 76 1494Q76 1538
+107 1569T182 1600Q238 1600 268 1556Z" />
+<glyph unicode="Z" glyph-name="Z" horiz-adv-x="1440" d="M183 1600H1263Q1285 1600 1304 1592T1338 1570T1361 1536T1369 1494Q1369 1461 1349 1432L400 212H1263Q1308 211 1338 180T1369 105Q1369 61 1339 31T1264 0H183Q160 0 141 8T108 30T85 64T77 106Q78
+144 99 172L1046 1388H183Q140 1388 109 1419T77 1494Q77 1538 108 1569T183 1600Z" />
+<glyph unicode="[" glyph-name="bracketleft" horiz-adv-x="640" d="M494 1602Q540 1602 570 1571T601 1494Q601 1448 571 1418T494 1388H289V-266H494Q540 -266 570 -296T601 -372Q601 -419 571 -449T494 -480H183Q136 -480 106 -450T76 -372V1494Q76 1539 106
+1570T183 1602H494Z" />
+<glyph unicode="\" glyph-name="backslash" horiz-adv-x="960" d="M883 -12Q892 -31 892 -55Q892 -77 884 -96T862 -131T828 -154T786 -162Q758 -162 730 -146T688 -99L68 1450Q60 1472 60 1494Q60 1539 90 1570T166 1601Q238 1601 264 1538L883 -12Z" />
+<glyph unicode="]" glyph-name="bracketright" horiz-adv-x="640" d="M494 1602Q540 1602 570 1571T601 1494V-372Q601 -419 571 -449T494 -480H183Q136 -480 106 -450T76 -372Q76 -326 106 -296T183 -266H387V1388H183Q136 1388 106 1418T76 1494Q76 1539 106
+1570T183 1602H494Z" />
+<glyph unicode="^" glyph-name="asciicircum" horiz-adv-x="960" d="M484 1304L264 975Q232 934 180 934Q135 934 106 964T76 1039Q76 1072 90 1093L398 1555Q427 1599 484 1599Q537 1599 569 1555L877 1093Q892 1071 892 1039Q892 1017 884 998T862 965T828 942T788
+934Q735 934 703 975L484 1304Z" />
+<glyph unicode="_" glyph-name="underscore" horiz-adv-x="960" d="M976 -209H16Q-28 -209 -58 -179T-89 -105Q-89 -61 -59 -31T16 0H976Q1019 0 1049 -30T1080 -105Q1080 -148 1050 -178T976 -209Z" />
+<glyph unicode="`" glyph-name="grave" horiz-adv-x="560" d="M71 1494Q71 1538 100 1568T175 1599Q217 1599 249 1568L449 1369Q475 1341 475 1298Q475 1253 446 1224T371 1194Q327 1194 299 1222L99 1421Q71 1449 71 1494Z" />
+<glyph unicode="a" glyph-name="a" horiz-adv-x="1280" d="M640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM991 104V124Q916
+64 828 32T640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1200 792 1200 560V104Q1200 61 1170 31T1096 0Q1052 0 1022 30T991 104Z" />
+<glyph unicode="b" glyph-name="b" horiz-adv-x="1280" d="M640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209ZM289 996Q438 1120
+640 1120Q870 1120 1036 956Q1118 875 1159 776T1200 560Q1200 326 1036 164Q870 0 640 0Q408 0 244 164Q80 328 80 560V1496Q80 1541 109 1570T184 1600Q228 1600 258 1571T289 1496V996Z" />
+<glyph unicode="c" glyph-name="c" horiz-adv-x="1120" d="M932 317Q977 317 1006 288T1036 213Q1036 169 1003 136Q848 0 638 0Q406 0 242 164Q78 328 78 560Q78 792 242 956Q406 1120 638 1120Q849 1120 1003 984Q1039 952 1039 905Q1039 860 1010 830T935 800Q897
+800 867 824Q816 867 760 889T638 911Q565 911 501 884T389 809T314 697T286 560Q286 487 313 423T389 312T501 237T638 209Q704 209 760 230T866 295Q894 316 932 317Z" />
+<glyph unicode="d" glyph-name="d" horiz-adv-x="1280" d="M991 560Q991 632 964 695T889 807T777 883T640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560ZM640 1120Q839 1120
+991 997V1496Q991 1541 1020 1570T1095 1600Q1139 1600 1169 1571T1200 1496V560Q1200 326 1036 164Q870 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Z" />
+<glyph unicode="e" glyph-name="e" horiz-adv-x="1280" d="M977 664Q960 719 927 764T849 842T751 893T640 911Q583 911 529 893T430 843T352 765T303 664H977ZM932 315Q977 315 1006 286T1036 211Q1036 167 1006 136Q851 0 640 0Q408 0 244 164Q80 328 80 560Q80
+792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 875 1159 776T1200 560Q1200 515 1170 486T1095 456H303Q320 401 353 356T430 278T528 227T640 209Q706 209 761 229T863 289Q893 314 932 315Z" />
+<glyph unicode="f" glyph-name="f" horiz-adv-x="800" d="M701 1390Q425 1390 425 1115V1063H626Q669 1063 699 1033T730 959Q730 915 700 885T626 854H425V104Q425 83 417 64T395 31T362 8T321 0Q299 0 280 8T247 30T225 64T217 104V854H169Q124 854 95 884T65
+959Q65 1004 94 1033T169 1063H217V1115Q217 1599 701 1599Q744 1599 774 1569T805 1495Q805 1451 775 1421T701 1390Z" />
+<glyph unicode="g" glyph-name="g" horiz-adv-x="1280" d="M640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM991 123Q841 0 640
+0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1200 792 1200 560V4Q1200 -68 1178 -132T1117 -249T1025 -346T911 -418T782 -464T648 -480Q568 -480 491 -460T345 -399T219 -300T121 -168Q105 -145 105 -112Q105 -67 135
+-38T210 -8Q240 -8 259 -22T313 -84T373 -157Q487 -271 648 -271Q810 -271 922 -159Q991 -75 991 4V123Z" />
+<glyph unicode="h" glyph-name="h" horiz-adv-x="1200" d="M288 105Q288 61 258 31T183 0Q140 0 110 30T79 105V1495Q79 1539 109 1569T183 1600Q226 1600 256 1570T288 1495V1015Q421 1118 601 1118Q706 1118 800 1077T967 966T1081 800T1123 596V105Q1122 61
+1092 31T1018 0Q975 0 945 30T914 105V596Q914 660 889 717T822 816T722 884T601 909Q536 909 480 885T380 817T313 717T288 596V105Z" />
+<glyph unicode="i" glyph-name="i" horiz-adv-x="480" d="M363 1319Q363 1268 327 1232T240 1196Q189 1196 153 1232T117 1319Q117 1370 153 1406T240 1442Q291 1442 327 1406T363 1319ZM136 105V1015Q136 1059 166 1089T240 1120Q283 1120 313 1090T345 1015V105Q344
+61 314 31T240 0Q197 0 167 30T136 105Z" />
+<glyph unicode="j" glyph-name="j" horiz-adv-x="656" d="M602 1319Q602 1268 566 1232T479 1196Q428 1196 392 1232T356 1319Q356 1370 392 1406T479 1442Q530 1442 566 1406T602 1319ZM583 1015V5Q583 -94 545 -182T440 -336T286 -440T99 -479Q54 -479 25 -449T-5
+-374Q-5 -329 24 -300T99 -270Q156 -270 206 -249T293 -190T353 -102T375 5V1015Q375 1059 405 1089T479 1120Q522 1120 552 1090T583 1015Z" />
+<glyph unicode="k" glyph-name="k" horiz-adv-x="1120" d="M78 105V1495Q78 1539 108 1569T183 1600Q226 1600 256 1570T287 1495V715L885 1104Q910 1120 941 1120Q963 1120 982 1112T1015 1090T1037 1056T1046 1016Q1046 960 1006 933L587 661L1017 177Q1046
+145 1046 104Q1046 83 1038 64T1015 31T982 8T941 0Q899 0 871 27L409 546L287 466V105Q287 62 257 31T183 0Q139 0 109 31T78 105Z" />
+<glyph unicode="l" glyph-name="l" horiz-adv-x="480" d="M70 104V1495Q70 1539 99 1569T174 1600Q219 1600 248 1570T278 1495V209H326Q369 209 399 179T430 104Q430 61 400 31T326 0H173Q130 0 100 30T70 104Z" />
+<glyph unicode="m" glyph-name="m" horiz-adv-x="1760" d="M1661 105Q1661 61 1631 31T1557 0Q1513 0 1483 30T1453 105V674Q1453 722 1435 765T1384 840T1309 892T1215 911Q1166 911 1123 892T1048 841T997 766T978 674V105Q978 61 948 31T874 0Q830 0 800 30T769
+105V674Q769 723 750 766T699 841T624 892T532 911Q483 911 440 893T365 842T314 766T295 674V105Q295 61 265 31T191 0Q147 0 117 30T86 105V1016Q86 1059 116 1089T190 1120Q225 1120 252 1101T289 1049Q396 1120 532 1120Q632 1120 720 1081T874 961Q1013 1120
+1215 1120Q1306 1120 1387 1085T1529 989T1625 847T1661 674V105Z" />
+<glyph unicode="n" glyph-name="n" horiz-adv-x="1200" d="M288 1017Q421 1120 601 1120Q706 1120 800 1079T967 968T1081 802T1123 598V105Q1123 61 1093 31T1019 0Q975 0 945 30T914 105V598Q914 662 889 719T822 818T722 886T601 911Q536 911 480 887T380 819T313
+719T288 598V105Q288 61 258 31T184 0Q140 0 110 30T79 105V1015Q79 1058 109 1089T184 1120Q227 1120 257 1089T288 1017Z" />
+<glyph unicode="o" glyph-name="o" horiz-adv-x="1280" d="M1200 560Q1200 326 1036 164Q870 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 874 1158 775T1200 560ZM640 911Q566 911 502 883T391 808T317 696T289
+560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911Z" />
+<glyph unicode="p" glyph-name="p" horiz-adv-x="1280" d="M289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911Q566 911 502 883T391 808T317 696T289 560ZM640 0Q439 0 289
+123V-376Q289 -421 259 -450T184 -480Q139 -480 110 -451T80 -376V560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 875 1159 776T1200 560Q1200 326 1036 164Q952 81 854 41T640 0Z" />
+<glyph unicode="q" glyph-name="q" horiz-adv-x="1280" d="M640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM991 123Q841 0 640
+0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1200 792 1200 560V-376Q1200 -421 1170 -450T1095 -480Q1050 -480 1021 -451T991 -376V123Z" />
+<glyph unicode="r" glyph-name="r" horiz-adv-x="960" d="M285 1016V996Q360 1056 448 1088T636 1120Q680 1120 730 1114T823 1093T894 1050T922 980Q922 958 914 939T891 906T858 883T817 875Q798 875 773 886Q710 911 636 911Q563 911 499 884T388 809T313 697T285
+560V104Q285 61 255 31T181 0Q137 0 107 30T76 104V1016Q76 1059 106 1089T181 1120Q224 1120 254 1090T285 1016Z" />
+<glyph unicode="s" glyph-name="s" horiz-adv-x="1060" d="M284 533Q190 569 152 607H153Q77 684 77 788Q77 864 117 925T223 1030T369 1096T533 1120Q783 1120 962 919Q983 893 983 856Q983 811 954 782T879 752Q847 752 825 770T781 809Q679 911 533 911Q389
+911 303 823Q287 807 287 779Q287 751 313 741L781 587Q879 549 913 513H912Q988 436 988 332Q988 255 948 194T842 90T696 23T533 0Q281 0 104 199Q82 228 82 264Q82 309 111 338T186 368Q219 368 242 349T284 311Q386 209 533 209Q676 209 763 299Q778 316 778
+340Q778 368 751 379L284 533Z" />
+<glyph unicode="t" glyph-name="t" horiz-adv-x="800" d="M178 1120H225V1496Q225 1539 255 1569T330 1600Q373 1600 403 1570T434 1496V1120H559Q602 1120 632 1090T662 1016Q662 972 632 942T559 911H434V408Q434 209 634 209Q677 209 707 179T737 105Q737 61
+707 31T634 0Q225 0 225 408V911H178Q136 911 106 941T75 1016Q75 1059 105 1089T178 1120Z" />
+<glyph unicode="u" glyph-name="u" horiz-adv-x="1200" d="M1018 0Q973 0 944 30T914 103Q845 49 768 25T601 0Q494 0 399 41T233 154T121 320T79 522V1016Q79 1059 109 1089T184 1120Q227 1120 257 1090T288 1016V522Q288 457 312 400T379 301T479 234T601 209Q665
+209 722 233T822 301T889 400T914 522V1016Q914 1059 944 1089T1019 1120Q1062 1120 1092 1090T1123 1016V104Q1123 61 1093 31T1018 0Z" />
+<glyph unicode="v" glyph-name="v" horiz-adv-x="1200" d="M601 0Q535 0 509 56L87 974Q79 995 79 1016Q79 1037 87 1056T109 1089T142 1112T183 1120Q210 1120 235 1107T274 1068L601 355L927 1067Q956 1120 1018 1120Q1040 1120 1059 1112T1092 1090T1114 1056T1123
+1016Q1123 993 1114 974L693 56Q665 0 601 0Z" />
+<glyph unicode="w" glyph-name="w" horiz-adv-x="1600" d="M796 1120Q870 1120 896 1043L1099 434L1309 1062Q1317 1088 1341 1104T1403 1120Q1425 1120 1444 1112T1477 1090T1499 1056T1508 1016Q1508 997 1500 976L1197 67Q1188 38 1164 19T1099 0Q1064 0 1037
+20T1002 67L796 685L590 67Q581 38 554 19T492 0Q457 0 431 19T394 67L91 976Q84 998 84 1016Q84 1037 92 1056T114 1089T147 1112T188 1120Q224 1120 248 1103T282 1062L492 435L695 1043Q721 1120 796 1120Z" />
+<glyph unicode="x" glyph-name="x" horiz-adv-x="1120" d="M426 561L102 947Q78 974 78 1016Q78 1037 86 1056T108 1089T141 1112T182 1120Q229 1120 260 1086L562 725L864 1086Q894 1120 941 1120Q963 1120 982 1112T1015 1090T1037 1056T1046 1016Q1046 978
+1021 947L697 561L1024 169Q1046 144 1046 104Q1046 83 1038 64T1015 31T982 8T941 0Q898 0 866 32L562 398L256 32Q226 0 182 0Q160 0 141 8T108 30T86 64T78 104Q78 143 99 169L426 561Z" />
+<glyph unicode="y" glyph-name="y" horiz-adv-x="1120" d="M448 104L88 969Q78 992 78 1016Q78 1037 86 1056T108 1089T141 1112T182 1120Q213 1120 240 1103T281 1051L562 380L843 1053Q855 1083 877 1101T941 1120Q963 1120 982 1112T1015 1090T1037 1056T1046
+1016Q1046 994 1035 969L460 -410Q447 -441 420 -460T361 -480Q316 -480 287 -450T257 -375Q257 -351 267 -329L448 104Z" />
+<glyph unicode="z" glyph-name="z" horiz-adv-x="1120" d="M941 0H182Q160 0 141 8T108 30T86 64T78 104Q78 141 99 169L718 911H182Q140 911 110 941T79 1016Q79 1059 109 1089T182 1120H941Q963 1120 982 1112T1015 1090T1037 1056T1046 1016Q1046 975 1021
+947L403 209H941Q984 209 1014 179T1044 105Q1044 61 1014 31T941 0Z" />
+<glyph unicode="{" glyph-name="braceleft" horiz-adv-x="800" d="M634 1599Q679 1599 708 1569T738 1494Q738 1449 709 1420T634 1390Q510 1390 510 1266V788Q510 644 444 560Q510 476 510 332V-146Q510 -270 634 -270Q679 -270 708 -299T738 -374Q738 -419 709
+-449T634 -479Q301 -479 301 -146V332Q301 456 178 456Q133 456 104 485T74 560Q74 605 103 634T178 664Q301 664 301 788V1266Q301 1599 634 1599Z" />
+<glyph unicode="|" glyph-name="bar" horiz-adv-x="800" d="M510 1495V-375Q510 -420 481 -450T406 -480Q361 -480 331 -450T301 -375V1495Q301 1540 331 1570T406 1600Q451 1600 480 1570T510 1495Z" />
+<glyph unicode="}" glyph-name="braceright" horiz-adv-x="800" d="M511 1266V788Q511 664 634 664Q679 664 708 635T738 560Q738 515 709 486T634 456Q511 456 511 332V-146Q511 -479 178 -479Q133 -479 104 -449T74 -374Q74 -329 103 -300T178 -270Q302 -270
+302 -146V332Q302 476 368 560Q302 644 302 788V1266Q302 1390 178 1390Q133 1390 104 1419T74 1494Q74 1538 103 1568T178 1599Q511 1599 511 1266Z" />
+<glyph unicode="~" glyph-name="asciitilde" horiz-adv-x="960" d="M332 576Q294 576 248 587T162 620T94 673T67 747Q68 794 98 822T171 851Q207 851 252 818T336 785Q379 785 409 812Q496 894 628 894Q665 894 711 883T798 849T865 795T893 723Q893 678 863
+649T788 619Q756 619 709 652T625 685Q584 685 551 658Q461 576 332 576Z" />
+<glyph unicode="&#xa0;" glyph-name="space" horiz-adv-x="560" />
+<glyph unicode="&#xa1;" glyph-name="exclamdown" horiz-adv-x="400" d="M211 835Q182 835 156 846T111 877T80 923T69 978Q69 1008 80 1034T111 1079T156 1109T211 1120Q239 1120 265 1109T310 1079T341 1034T353 978Q353 949 342 923T312 878T266 847T211 835ZM107
+670Q107 691 115 709T137 742T170 764T211 773Q232 773 251 765T284 743T306 710T315 670V-374Q315 -418 286 -448T211 -479Q166 -479 137 -449T107 -374V670Z" />
+<glyph unicode="&#xa2;" glyph-name="cent" horiz-adv-x="1120" d="M587 906Q522 895 468 863T375 785T315 681T293 560Q293 497 310 446T363 347L587 906ZM539 223Q593 209 644 209Q710 209 766 230T873 295Q887 306 904 311T939 317Q984 317 1013 288T1043 213Q1043
+169 1010 136Q853 0 644 0Q545 0 462 28L356 -237Q344 -264 318 -284T259 -304Q237 -304 218 -296T185 -272T162 -238T154 -198Q154 -179 161 -160L279 135Q264 149 249 164Q84 327 84 560Q84 675 128 776T249 954T427 1075T644 1120H672L768 1358Q784 1399 825
+1416Q844 1424 866 1424Q888 1424 907 1416T940 1393T962 1359T970 1319Q970 1304 962 1281L879 1071Q937 1040 991 1000T1046 905Q1046 883 1038 864T1015 831T982 808T941 800Q903 800 872 825T801 875L539 223Z" />
+<glyph unicode="&#xa3;" glyph-name="sterling" horiz-adv-x="1040" d="M260 0Q208 0 181 30T154 105Q154 131 161 147Q265 390 269 615H182Q137 615 107 645T77 722Q77 768 107 797T182 827H248Q226 929 185 1028Q154 1101 154 1183Q154 1269 187 1345T276 1477T408
+1565T568 1598Q675 1598 759 1552T913 1414Q933 1385 933 1350Q933 1304 903 1274T827 1243Q788 1243 764 1270T711 1327Q652 1386 568 1386Q526 1386 489 1370T425 1327T381 1262T365 1183Q365 1148 382 1108Q412 1038 432 969T464 827H722Q768 827 797 798T827
+722Q827 676 798 646T722 615H480Q478 517 462 417T412 212H733Q764 273 791 319T875 366Q897 366 916 358T950 335T972 301T981 260Q981 232 969 210L895 64Q861 0 799 0H260Z" />
+<glyph unicode="&#xa4;" glyph-name="currency" horiz-adv-x="960" d="M484 864Q458 864 436 854T397 827T370 788T360 740Q360 716 369 694T395 654T434 627T484 617Q509 617 531 626T570 653T597 692T607 740Q607 766 597 789T570 828T531 854T484 864ZM686
+1090Q716 1120 759 1120Q781 1120 800 1112T833 1090T855 1056T863 1016Q862 968 832 940L782 893Q816 826 816 740Q816 660 783 593L834 539Q863 508 863 465Q863 420 834 391T759 361Q718 361 687 388L637 443Q565 408 484 408Q407 408 337 440L284 391Q250 361
+209 361Q164 361 134 390T104 465Q104 507 135 539L188 588Q152 657 152 740Q152 822 186 889L135 943Q104 970 104 1016Q104 1037 112 1056T134 1089T168 1112T209 1120Q250 1120 281 1092L331 1037Q410 1078 484 1073Q562 1073 631 1039L686 1090Z" />
+<glyph unicode="&#xa5;" glyph-name="yen" horiz-adv-x="1280" d="M1183 1436L936 1068H1096Q1140 1068 1171 1039T1202 964Q1202 918 1171 889T1096 859H796L744 780V688H1095Q1139 688 1169 659T1200 584Q1200 539 1170 510T1095 480H744V106Q744 61 714 31T639
+0Q594 0 565 30T535 106V480H184Q139 480 110 509T80 584Q80 629 109 658T184 688H535V780L483 859H184Q139 859 110 889T80 964Q80 1009 109 1038T184 1068H344L97 1436Q80 1462 80 1495Q80 1539 109 1569T184 1600Q237 1600 269 1556L640 1002L1010 1556Q1042
+1600 1095 1600Q1140 1600 1169 1570T1199 1495Q1199 1462 1183 1436Z" />
+<glyph unicode="&#xa6;" glyph-name="brokenbar" horiz-adv-x="480" d="M145 1623Q145 1668 175 1697T250 1727Q295 1727 324 1698T354 1623V940Q354 895 325 865T250 835Q205 835 175 865T145 940V1623ZM145 309Q145 354 175 383T250 413Q295 413 324 384T354
+309V-374Q354 -419 325 -449T250 -479Q205 -479 175 -449T145 -374V309Z" />
+<glyph unicode="&#xa7;" glyph-name="section" horiz-adv-x="960" d="M494 765Q452 765 415 750T350 706T306 641T289 562Q289 518 305 481T349 417T414 374T494 358Q535 358 572 373T637 417T681 481T698 562Q698 603 682 640T637 706T572 749T494 765ZM912 1183Q912
+1137 882 1107T805 1076Q759 1076 729 1106T698 1183Q698 1225 682 1262T637 1327T572 1371T494 1388Q452 1388 415 1372T350 1328T306 1263T289 1183Q289 1141 305 1104T348 1039T413 995T494 979Q580 979 656 946T789 856T879 723T912 562Q912 385 773 250Q912
+115 912 -60Q912 -146 879 -222T788 -355T656 -445T494 -479Q408 -479 332 -446T199 -355T109 -222T76 -60Q76 -14 106 16T184 47Q229 47 259 17T289 -60Q289 -102 305 -139T349 -204T414 -248T494 -265Q535 -265 572 -249T637 -205T681 -140T698 -60Q698 -19 682
+18T637 83T572 127T494 144Q408 144 332 176T199 266T109 399T76 562Q76 735 213 873Q136 947 106 1022T76 1183Q76 1268 109 1344T198 1478T331 1568T494 1602Q580 1602 655 1569T788 1478T878 1345T912 1183Z" />
+<glyph unicode="&#xa8;" glyph-name="dieresis" horiz-adv-x="960" d="M378 1359Q378 1308 342 1272T255 1236Q204 1236 168 1272T132 1359Q132 1410 168 1446T255 1482Q306 1482 342 1446T378 1359ZM833 1359Q833 1308 797 1272T710 1236Q659 1236 623 1272T587
+1359Q587 1410 623 1446T710 1482Q761 1482 797 1446T833 1359Z" />
+<glyph unicode="&#xa9;" glyph-name="copyright" horiz-adv-x="1760" d="M1175 561Q1220 561 1249 531T1278 457Q1278 436 1270 416T1245 381Q1169 313 1079 280T883 246Q653 246 491 409Q328 572 328 802Q328 1030 491 1194Q571 1275 669 1316T883 1357Q1093
+1357 1245 1222Q1281 1190 1281 1143Q1281 1098 1252 1069T1178 1039Q1160 1039 1142 1044T1111 1063Q1060 1106 1005 1128T883 1150Q811 1150 748 1122T637 1047T562 936T534 802Q534 730 561 667T636 557T746 482T883 454Q949 454 1004 475T1110 539Q1123 551
+1139 555T1175 561ZM1685 800Q1685 467 1450 234Q1214 0 886 0Q720 0 579 58T319 234Q201 351 144 492T86 800Q86 1130 319 1364Q552 1599 886 1599Q1218 1599 1450 1364Q1685 1132 1685 800ZM883 1437Q619 1437 433 1251Q247 1065 247 803Q247 668 292 557T433
+352Q618 167 883 167Q1015 167 1127 212T1332 352Q1518 540 1518 803Q1518 1065 1332 1251Q1146 1437 883 1437Z" />
+<glyph unicode="&#xaa;" glyph-name="ordfeminine" horiz-adv-x="960" d="M484 1367Q443 1367 407 1351T343 1308T300 1245T284 1167Q284 1126 299 1090T342 1026T405 984T484 968Q524 968 560 984T624 1027T667 1090T683 1167Q683 1208 667 1244T624 1308T560
+1351T484 1367ZM713 791Q702 802 695 816Q601 759 484 759Q400 759 326 791T196 880T108 1010T76 1167Q76 1250 108 1324T195 1455T325 1543T484 1576Q568 1576 642 1544T771 1455T859 1325T892 1167V864Q892 842 884 823T862 790T828 767T788 759Q743 759 713
+791Z" />
+<glyph unicode="&#xab;" glyph-name="guillemotleft" horiz-adv-x="960" d="M312 1055Q326 1087 351 1103T408 1119Q453 1119 482 1090T513 1015Q512 990 503 970L298 560L503 148Q512 129 512 104Q512 83 504 64T482 31T449 8T408 0Q379 0 353 16T312 64L91 505Q76
+534 76 559Q76 583 89 609L312 1055ZM694 1055Q708 1087 733 1103T790 1119Q835 1119 864 1090T895 1015Q894 990 885 970L680 560L885 148Q894 129 894 104Q894 83 886 64T864 31T831 8T790 0Q761 0 735 16T694 64L473 505Q458 534 458 559Q458 583 471 609L694
+1055Z" />
+<glyph unicode="&#xac;" glyph-name="logicalnot" horiz-adv-x="1120" d="M182 911Q137 911 108 941T78 1016Q78 1037 86 1056T108 1089T141 1112T182 1120H941Q963 1120 982 1112T1015 1090T1037 1056T1046 1016V712Q1046 690 1038 671T1015 638T982 615T941
+607Q920 607 901 615T868 637T845 671T837 712V911H182Z" />
+<glyph unicode="&#xad;" glyph-name="hyphen" horiz-adv-x="800" d="M178 456Q133 456 104 485T74 560Q74 605 103 634T178 664H634Q679 664 708 635T738 560Q738 515 709 486T634 456H178Z" />
+<glyph unicode="&#xae;" glyph-name="registered" horiz-adv-x="1760" d="M1688 802Q1688 468 1452 235Q1216 0 888 0Q721 0 580 58T320 235Q201 352 144 493T86 802Q86 1132 320 1366Q553 1602 888 1602Q1220 1602 1452 1366Q1688 1134 1688 802ZM885 1435Q622
+1435 437 1250Q252 1065 252 804Q252 670 297 560T437 356Q621 172 885 172Q1016 172 1127 217T1331 356Q1516 543 1516 804Q1516 1065 1331 1250Q1146 1435 885 1435ZM717 1181V840H888Q923 840 954 853T1008 890T1045 945T1059 1011Q1059 1046 1046 1077T1009
+1131T954 1167T888 1181H717ZM888 1338Q954 1338 1013 1312T1117 1242T1188 1138T1215 1011Q1215 923 1174 851T1051 727L1250 408Q1265 386 1265 364Q1265 348 1259 334T1242 309T1217 292T1187 285Q1143 285 1119 324L895 684H717V364Q717 332 694 309T638 285Q622
+285 608 291T584 308T567 333T560 364V1260Q560 1293 583 1315T638 1338H888Z" />
+<glyph unicode="&#xaf;" glyph-name="overscore" horiz-adv-x="1120" d="M182 1671Q137 1671 108 1700T78 1775Q78 1820 107 1849T182 1879H941Q985 1879 1015 1850T1046 1775Q1046 1730 1016 1701T941 1671H182Z" />
+<glyph unicode="&#xb0;" glyph-name="degree" horiz-adv-x="960" d="M892 1167Q892 1084 860 1010T772 880T642 792T484 759Q400 759 326 791T196 880T108 1010T76 1167Q76 1250 108 1324T195 1455T325 1543T484 1576Q568 1576 642 1544T771 1455T859 1325T892
+1167ZM484 1367Q443 1367 407 1351T343 1308T300 1245T284 1167Q284 1126 299 1090T342 1026T405 984T484 968Q524 968 560 984T624 1027T667 1090T683 1167Q683 1208 667 1244T624 1308T560 1351T484 1367Z" />
+<glyph unicode="&#xb1;" glyph-name="plusminus" horiz-adv-x="1120" d="M941 683H666V408Q666 363 637 334T562 304Q517 304 487 333T457 408V683H182Q137 683 108 713T78 788Q78 833 107 862T182 892H457V1167Q457 1210 487 1241T562 1272Q607 1272 636 1242T666
+1167V892H941Q984 892 1015 862T1046 787Q1046 744 1015 714T941 683ZM182 0Q137 0 108 29T78 104Q78 149 107 178T182 208H942Q987 208 1016 179T1046 104Q1046 59 1017 30T942 0H182Z" />
+<glyph unicode="&#xb2;" glyph-name="uni00B2" horiz-adv-x="640" d="M514 923Q540 923 559 903T579 857Q579 828 560 810T514 791H138Q109 791 91 809T72 857Q72 885 89 903L410 1258Q447 1295 447 1345Q447 1370 437 1392T411 1431T372 1458T326 1468Q300 1468
+278 1458T239 1432T213 1393T203 1345Q203 1319 184 1300T138 1280Q109 1280 91 1299T72 1345Q72 1398 92 1444T147 1525T228 1580T326 1600Q377 1600 423 1580T503 1525T558 1444T579 1345Q579 1294 560 1249T505 1167L287 923H514Z" />
+<glyph unicode="&#xb3;" glyph-name="uni00B3" horiz-adv-x="640" d="M328 1165Q299 1165 280 1183T261 1231Q261 1257 280 1277T328 1298Q363 1298 387 1322T412 1382Q412 1420 387 1444T328 1468Q310 1468 295 1461T267 1443T249 1416T242 1382Q242 1356 222
+1337T176 1317Q147 1317 129 1336T110 1382Q110 1428 127 1468T175 1537T244 1584T328 1601Q372 1601 411 1583T480 1535T527 1465T545 1382Q545 1342 531 1305T492 1238Q538 1205 560 1151T583 1042Q583 990 563 944T508 862T427 807T328 786Q275 786 229 806T147
+861T92 942T72 1042Q72 1071 90 1089T138 1108Q164 1108 184 1090T204 1042Q204 1017 213 995T238 956T278 929T328 919Q354 919 376 928T414 955T440 994T450 1042Q450 1067 440 1089T414 1128T375 1155T328 1165Z" />
+<glyph unicode="&#xb4;" glyph-name="acute" horiz-adv-x="560" d="M480 1421L280 1222Q252 1194 208 1194Q163 1194 134 1223T104 1298Q104 1341 130 1369L330 1568Q362 1599 404 1599Q449 1599 478 1569T508 1494Q508 1449 480 1421Z" />
+<glyph unicode="&#xb5;" glyph-name="mu" horiz-adv-x="1200" d="M288 522Q288 457 312 400T379 301T479 234T601 209Q665 209 722 233T822 301T889 400T914 522V1016Q914 1037 922 1056T944 1089T977 1112T1018 1120Q1040 1120 1059 1112T1092 1090T1114 1056T1123
+1016V104Q1123 83 1115 64T1092 31T1059 8T1018 0Q973 0 944 30T914 103Q845 49 768 25T601 0Q421 0 288 103V-374Q288 -396 280 -415T257 -448T224 -471T183 -479Q138 -479 109 -449T79 -374V1016Q79 1037 87 1056T109 1089T142 1112T183 1120Q205 1120 224 1112T257
+1090T279 1056T288 1016V522Z" />
+<glyph unicode="&#xb6;" glyph-name="paragraph" horiz-adv-x="1120" d="M970 104Q970 83 962 64T939 31T906 8T865 0Q844 0 825 8T792 30T769 64T761 104V1390H666V104Q666 83 658 64T636 31T603 8T562 0Q540 0 521 8T488 30T465 64T457 104V783Q378 788 309
+822T189 912T108 1040T78 1190Q78 1273 110 1347T197 1478T327 1566T486 1599H941Q963 1599 982 1591T1015 1568T1037 1535T1046 1494Q1046 1458 1025 1431T970 1394V104Z" />
+<glyph unicode="&#xb7;" glyph-name="middot" horiz-adv-x="400" d="M343 750Q343 691 302 650T201 608Q142 608 101 649T59 750Q59 809 100 850T201 892Q260 892 301 851T343 750Z" />
+<glyph unicode="&#xb8;" glyph-name="cedilla" horiz-adv-x="640" d="M293 82Q324 110 366 110Q411 110 440 80T470 5Q470 -6 467 -18L458 -53Q584 -127 584 -251Q584 -348 507 -414Q434 -479 328 -479Q264 -479 205 -448L118 -395Q72 -358 72 -308Q72 -264 101
+-234T176 -203Q205 -202 232 -219L304 -264Q316 -270 328 -270Q375 -270 375 -248Q375 -226 330 -223Q285 -223 249 -190T225 -104L265 35Q271 58 293 82Z" />
+<glyph unicode="&#xb9;" glyph-name="uni00B9" horiz-adv-x="480" d="M353 855Q353 826 333 807T286 788Q260 788 240 807T220 855V1443L198 1434Q189 1430 173 1430Q144 1430 126 1448T107 1496Q107 1514 118 1531T150 1558L265 1597Q275 1600 286 1600Q312 1600
+332 1581T353 1533V855Z" />
+<glyph unicode="&#xba;" glyph-name="ordmasculine" horiz-adv-x="640" d="M72 1194Q72 1290 89 1365T138 1492T218 1572T327 1600Q386 1600 433 1573T513 1493T563 1365T581 1194Q581 1098 564 1023T513 896T433 816T327 788Q266 788 219 815T139 895T89 1023T72
+1194ZM327 1468Q297 1468 274 1447T236 1388T212 1301T204 1194Q204 1018 268 945L266 946Q290 921 327 921Q358 921 381 942T419 1000T441 1087T449 1194Q449 1372 386 1443V1442Q362 1468 327 1468Z" />
+<glyph unicode="&#xbb;" glyph-name="guillemotright" horiz-adv-x="960" d="M882 609Q895 583 895 559Q895 534 880 505L659 64Q644 32 618 16T563 0Q541 0 522 8T489 30T467 64T459 104Q459 129 468 148L673 560L468 970Q459 990 458 1015Q459 1060 488 1089T563
+1119Q595 1119 620 1103T659 1055L882 609ZM500 609Q513 583 513 559Q513 534 498 505L277 64Q262 32 236 16T181 0Q159 0 140 8T107 30T85 64T77 104Q77 129 86 148L291 560L86 970Q77 990 76 1015Q77 1060 106 1089T181 1119Q213 1119 238 1103T277 1055L500
+609Z" />
+<glyph unicode="&#xbc;" glyph-name="onequarter" horiz-adv-x="1440" d="M1189 1600Q1211 1600 1230 1592T1263 1569T1285 1536T1294 1495Q1294 1465 1278 1438L352 51Q316 0 262 0Q240 0 221 8T188 30T166 64T158 104Q158 138 173 160L1105 1558Q1133 1600 1189
+1600ZM367 704Q367 673 346 652T292 630Q261 630 240 651T218 704V1421L182 1411Q168 1406 156 1406Q124 1406 103 1427T82 1480Q82 1502 94 1520T125 1547L266 1595Q279 1600 292 1600Q324 1600 345 1579T367 1526V704ZM1069 376V657L875 376H1069ZM733 228Q701
+228 680 249T659 302Q659 325 673 345L1082 937Q1104 968 1143 968Q1175 968 1196 947T1217 894V376H1280Q1311 376 1332 355T1354 302Q1354 270 1333 249T1280 228H1217V74Q1217 42 1196 21T1143 0Q1111 0 1090 21T1069 74V228H733Z" />
+<glyph unicode="&#xbd;" glyph-name="onehalf" horiz-adv-x="1600" d="M1433 148Q1463 148 1485 127T1508 74Q1508 42 1486 21T1433 0H977Q945 0 924 21T903 74Q903 102 924 125L1313 556Q1359 602 1359 667Q1359 699 1347 727T1313 776T1264 809T1205 821Q1173
+821 1145 809T1096 776T1063 727T1051 667Q1051 635 1030 614T977 593Q945 593 924 614T903 667Q903 729 927 784T992 880T1088 945T1205 969Q1266 969 1321 945T1418 879T1483 783T1508 667Q1508 606 1485 553T1419 454L1144 148H1433ZM1189 1600Q1211 1600 1230
+1592T1263 1569T1285 1536T1294 1495Q1294 1465 1278 1438L352 51Q316 0 262 0Q240 0 221 8T188 30T166 64T158 104Q158 138 173 160L1105 1558Q1133 1600 1189 1600ZM367 704Q367 673 346 652T292 630Q261 630 240 651T218 704V1421L182 1411Q168 1406 156 1406Q124
+1406 103 1427T82 1480Q82 1502 94 1520T125 1547L266 1595Q279 1600 292 1600Q324 1600 345 1579T367 1526V704Z" />
+<glyph unicode="&#xbe;" glyph-name="threequarters" horiz-adv-x="1600" d="M385 1089Q353 1089 332 1110T311 1163Q311 1192 332 1214T385 1236Q407 1236 426 1244T461 1268T484 1302T493 1344Q493 1367 484 1386T459 1420T425 1443T385 1452Q363 1452 344 1444T309
+1420T286 1386T277 1344Q277 1329 271 1316T255 1292T231 1276T203 1270Q172 1270 151 1291T129 1344Q129 1396 149 1442T204 1524T285 1579T385 1600Q438 1600 484 1580T565 1524T620 1442T640 1344Q640 1245 573 1172Q600 1144 621 1118T657 1063T678 1003T686
+935Q686 874 662 820T597 724T501 658T385 634Q323 634 269 658T173 723T108 818T84 935Q84 967 105 988T158 1009Q190 1009 211 988T232 935Q232 903 244 875T276 827T325 795T385 783Q416 783 443 795T492 828T525 876T537 935Q537 968 525 996T492 1044T444
+1077T385 1089ZM1343 1600Q1365 1600 1384 1592T1417 1569T1439 1536T1448 1495Q1448 1465 1432 1438L506 51Q470 0 416 0Q394 0 375 8T342 30T320 64T312 104Q312 138 327 160L1259 1558Q1287 1600 1343 1600ZM1222 376V657L1028 376H1222ZM886 228Q854 228 833
+249T812 302Q812 325 826 345L1235 937Q1257 968 1296 968Q1328 968 1349 947T1370 894V376H1433Q1464 376 1485 355T1507 302Q1507 270 1486 249T1433 228H1370V74Q1370 42 1349 21T1296 0Q1264 0 1243 21T1222 74V228H886Z" />
+<glyph unicode="&#xbf;" glyph-name="questiondown" horiz-adv-x="1120" d="M562 -271Q618 -271 668 -249T755 -190T815 -102T837 4Q837 116 757 199L600 345Q457 488 457 688Q457 733 487 762T562 792Q607 792 636 763T666 688Q666 573 746 493L903 348Q1046
+202 1046 4Q1046 -94 1008 -182T903 -336T749 -441T562 -480Q463 -480 375 -442T221 -338T117 -184T78 4Q78 49 107 79T182 109Q204 109 223 101T256 79T278 45T287 4Q287 -54 308 -104T367 -191T455 -249T562 -271ZM562 835Q503 835 462 876T420 977Q420 1036
+461 1077T562 1119Q621 1119 662 1078T704 977Q704 918 663 877T562 835Z" />
+<glyph unicode="&#xc0;" glyph-name="Agrave" horiz-adv-x="1440" d="M897 752L723 1201L549 752H897ZM88 154L622 1528Q654 1600 723 1600Q794 1600 824 1528L1360 149Q1368 129 1368 106Q1368 62 1337 31T1262 0Q1218 0 1188 31Q1172 47 1164 65L979 540H467L281
+65Q273 47 257 31Q226 0 182 0Q138 0 108 31T77 106Q77 130 88 154ZM444 1974Q444 2018 473 2048T548 2079Q590 2079 622 2048L822 1849Q848 1821 848 1778Q848 1733 819 1704T744 1674Q700 1674 672 1702L472 1901Q444 1929 444 1974Z" />
+<glyph unicode="&#xc1;" glyph-name="Aacute" horiz-adv-x="1440" d="M897 752L723 1201L549 752H897ZM88 154L622 1528Q654 1600 723 1600Q794 1600 824 1528L1360 149Q1368 129 1368 106Q1368 62 1337 31T1262 0Q1218 0 1188 31Q1172 47 1164 65L979 540H467L281
+65Q273 47 257 31Q226 0 182 0Q138 0 108 31T77 106Q77 130 88 154ZM987 1901L787 1702Q759 1674 715 1674Q670 1674 641 1703T611 1778Q611 1821 637 1849L837 2048Q869 2079 911 2079Q956 2079 985 2049T1015 1974Q1015 1929 987 1901Z" />
+<glyph unicode="&#xc2;" glyph-name="Acircumflex" horiz-adv-x="1440" d="M897 752L723 1201L549 752H897ZM88 154L622 1528Q654 1600 723 1600Q794 1600 824 1528L1360 149Q1368 129 1368 106Q1368 62 1337 31T1262 0Q1218 0 1188 31Q1172 47 1164 65L979 540H467L281
+65Q273 47 257 31Q226 0 182 0Q138 0 108 31T77 106Q77 130 88 154ZM998 1913Q1048 1875 1048 1823Q1048 1778 1019 1749T944 1719Q909 1719 878 1741L716 1848L554 1741Q524 1719 488 1719Q443 1719 414 1748T384 1823Q384 1876 433 1913L662 2064Q687 2080 716
+2080Q745 2080 770 2064L998 1913Z" />
+<glyph unicode="&#xc3;" glyph-name="Atilde" horiz-adv-x="1440" d="M897 752L723 1201L549 752H897ZM88 154L622 1528Q654 1600 723 1600Q794 1600 824 1528L1360 149Q1368 129 1368 106Q1368 62 1337 31T1262 0Q1218 0 1188 31Q1172 47 1164 65L979 540H467L281
+65Q273 47 257 31Q226 0 182 0Q138 0 108 31T77 106Q77 130 88 154ZM569 1711Q531 1711 485 1722T399 1755T331 1808T304 1882Q305 1929 335 1957T408 1986Q444 1986 489 1953T573 1920Q616 1920 646 1947Q733 2029 865 2029Q902 2029 948 2018T1035 1984T1102
+1930T1130 1858Q1130 1813 1100 1784T1025 1754Q993 1754 946 1787T862 1820Q821 1820 788 1793Q698 1711 569 1711Z" />
+<glyph unicode="&#xc4;" glyph-name="Adieresis" horiz-adv-x="1440" d="M897 752L723 1201L549 752H897ZM88 154L622 1528Q654 1600 723 1600Q794 1600 824 1528L1360 149Q1368 129 1368 106Q1368 62 1337 31T1262 0Q1218 0 1188 31Q1172 47 1164 65L979 540H467L281
+65Q273 47 257 31Q226 0 182 0Q138 0 108 31T77 106Q77 130 88 154ZM619 1839Q619 1788 583 1752T496 1716Q445 1716 409 1752T373 1839Q373 1890 409 1926T496 1962Q547 1962 583 1926T619 1839ZM1074 1839Q1074 1788 1038 1752T951 1716Q900 1716 864 1752T828
+1839Q828 1890 864 1926T951 1962Q1002 1962 1038 1926T1074 1839Z" />
+<glyph unicode="&#xc5;" glyph-name="Aring" horiz-adv-x="1440" d="M897 752L723 1201L549 752H897ZM88 154L622 1528Q654 1600 723 1600Q794 1600 824 1528L1360 149Q1368 129 1368 106Q1368 62 1337 31T1262 0Q1218 0 1188 31Q1172 47 1164 65L979 540H467L281
+65Q273 47 257 31Q226 0 182 0Q138 0 108 31T77 106Q77 130 88 154ZM938 1859Q938 1814 921 1774T873 1704T804 1657T719 1639Q674 1639 634 1656T564 1703T517 1773T499 1859Q499 1904 516 1944T564 2014T634 2061T719 2079Q764 2079 804 2061T874 2013T921 1943T938
+1859ZM719 1926Q691 1926 671 1906T651 1859Q651 1831 671 1812T719 1792Q746 1792 765 1811T785 1859Q785 1886 766 1906T719 1926Z" />
+<glyph unicode="&#xc6;" glyph-name="AE" horiz-adv-x="1760" d="M851 1084L710 829H851V1084ZM1574 1600Q1596 1600 1615 1592T1649 1570T1672 1536T1680 1494Q1680 1471 1672 1452T1650 1419T1616 1396T1574 1388H1063V829H1420Q1442 829 1461 821T1495 799T1518
+765T1526 723Q1526 700 1518 681T1496 648T1462 625T1420 617H1063V212H1574Q1596 212 1615 204T1649 182T1672 148T1680 106Q1680 83 1672 64T1650 31T1616 8T1574 0H957Q934 0 915 8T882 30T859 64T851 106V617H592L275 47Q243 0 186 0Q163 0 144 8T111 30T88
+64T80 106Q80 135 95 159L867 1550Q894 1600 957 1600H1574Z" />
+<glyph unicode="&#xc7;" glyph-name="Ccedilla" horiz-adv-x="1480" d="M1308 360Q1330 360 1349 352T1382 329T1405 296T1414 254Q1414 212 1381 178Q1158 0 878 0Q546 0 312 234Q78 468 78 800Q78 1131 312 1365Q547 1600 878 1600Q1162 1600 1391 1413Q1419
+1386 1419 1340Q1419 1317 1411 1298T1389 1265T1355 1242T1313 1234Q1274 1234 1240 1264Q1164 1324 1073 1356T878 1388Q634 1388 461 1215Q290 1044 290 800Q290 555 461 384Q633 212 878 212Q1087 212 1246 341Q1272 359 1308 360ZM719 82Q750 110 792 110Q837
+110 866 80T896 5Q896 -6 893 -18L884 -53Q1010 -127 1010 -251Q1010 -348 933 -414Q860 -479 754 -479Q690 -479 631 -448L544 -395Q498 -358 498 -308Q498 -264 527 -234T602 -203Q631 -202 658 -219L730 -264Q742 -270 754 -270Q801 -270 801 -248Q801 -226
+756 -223Q711 -223 675 -190T651 -104L691 35Q697 58 719 82Z" />
+<glyph unicode="&#xc8;" glyph-name="Egrave" horiz-adv-x="1280" d="M1108 212Q1152 212 1183 181T1214 106Q1214 62 1183 31T1108 0H183Q160 0 141 8T108 30T85 64T77 106V1494Q77 1516 85 1535T107 1569T141 1592T183 1600H1108Q1152 1600 1183 1569T1214 1494Q1214
+1450 1183 1419T1108 1388H289V906H877Q921 906 952 875T983 800Q983 756 952 725T877 694H289V212H1108ZM366 1974Q366 2018 395 2048T470 2079Q512 2079 544 2048L744 1849Q770 1821 770 1778Q770 1733 741 1704T666 1674Q622 1674 594 1702L394 1901Q366 1929
+366 1974Z" />
+<glyph unicode="&#xc9;" glyph-name="Eacute" horiz-adv-x="1280" d="M1108 212Q1152 212 1183 181T1214 106Q1214 62 1183 31T1108 0H183Q160 0 141 8T108 30T85 64T77 106V1494Q77 1516 85 1535T107 1569T141 1592T183 1600H1108Q1152 1600 1183 1569T1214 1494Q1214
+1450 1183 1419T1108 1388H289V906H877Q921 906 952 875T983 800Q983 756 952 725T877 694H289V212H1108ZM909 1901L709 1702Q681 1674 637 1674Q592 1674 563 1703T533 1778Q533 1821 559 1849L759 2048Q791 2079 833 2079Q878 2079 907 2049T937 1974Q937 1929
+909 1901Z" />
+<glyph unicode="&#xca;" glyph-name="Ecircumflex" horiz-adv-x="1280" d="M1108 212Q1152 212 1183 181T1214 106Q1214 62 1183 31T1108 0H183Q160 0 141 8T108 30T85 64T77 106V1494Q77 1516 85 1535T107 1569T141 1592T183 1600H1108Q1152 1600 1183 1569T1214
+1494Q1214 1450 1183 1419T1108 1388H289V906H877Q921 906 952 875T983 800Q983 756 952 725T877 694H289V212H1108ZM918 1913Q968 1875 968 1823Q968 1778 939 1749T864 1719Q829 1719 798 1741L636 1848L474 1741Q444 1719 408 1719Q363 1719 334 1748T304 1823Q304
+1876 353 1913L582 2064Q607 2080 636 2080Q665 2080 690 2064L918 1913Z" />
+<glyph unicode="&#xcb;" glyph-name="Edieresis" horiz-adv-x="1280" d="M1108 212Q1152 212 1183 181T1214 106Q1214 62 1183 31T1108 0H183Q160 0 141 8T108 30T85 64T77 106V1494Q77 1516 85 1535T107 1569T141 1592T183 1600H1108Q1152 1600 1183 1569T1214
+1494Q1214 1450 1183 1419T1108 1388H289V906H877Q921 906 952 875T983 800Q983 756 952 725T877 694H289V212H1108ZM541 1839Q541 1788 505 1752T418 1716Q367 1716 331 1752T295 1839Q295 1890 331 1926T418 1962Q469 1962 505 1926T541 1839ZM996 1839Q996 1788
+960 1752T873 1716Q822 1716 786 1752T750 1839Q750 1890 786 1926T873 1962Q924 1962 960 1926T996 1839Z" />
+<glyph unicode="&#xcc;" glyph-name="Igrave" horiz-adv-x="480" d="M605 106Q605 62 574 31T499 0Q455 0 424 31T393 106V1494Q393 1538 424 1569T499 1600Q543 1600 574 1569T605 1494V106ZM-3 1974Q-3 2018 26 2048T101 2079Q143 2079 175 2048L375 1849Q401
+1821 401 1778Q401 1733 372 1704T297 1674Q253 1674 225 1702L25 1901Q-3 1929 -3 1974Z" />
+<glyph unicode="&#xcd;" glyph-name="Iacute" horiz-adv-x="480" d="M605 106Q605 62 574 31T499 0Q455 0 424 31T393 106V1494Q393 1538 424 1569T499 1600Q543 1600 574 1569T605 1494V106ZM448 1901L248 1702Q220 1674 176 1674Q131 1674 102 1703T72 1778Q72
+1821 98 1849L298 2048Q330 2079 372 2079Q417 2079 446 2049T476 1974Q476 1929 448 1901Z" />
+<glyph unicode="&#xce;" glyph-name="Icircumflex" horiz-adv-x="480" d="M605 106Q605 62 574 31T499 0Q455 0 424 31T393 106V1494Q393 1538 424 1569T499 1600Q543 1600 574 1569T605 1494V106ZM531 1913Q581 1875 581 1823Q581 1778 552 1749T477 1719Q442
+1719 411 1741L249 1848L87 1741Q57 1719 21 1719Q-24 1719 -53 1748T-83 1823Q-83 1876 -34 1913L195 2064Q220 2080 249 2080Q278 2080 303 2064L531 1913Z" />
+<glyph unicode="&#xcf;" glyph-name="Idieresis" horiz-adv-x="480" d="M605 106Q605 62 574 31T499 0Q455 0 424 31T393 106V1494Q393 1538 424 1569T499 1600Q543 1600 574 1569T605 1494V106ZM142 1839Q142 1788 106 1752T19 1716Q-32 1716 -68 1752T-104 1839Q-104
+1890 -68 1926T19 1962Q70 1962 106 1926T142 1839ZM597 1839Q597 1788 561 1752T474 1716Q423 1716 387 1752T351 1839Q351 1890 387 1926T474 1962Q525 1962 561 1926T597 1839Z" />
+<glyph unicode="&#xd0;" glyph-name="Eth" horiz-adv-x="1520" d="M230 906V1494Q230 1516 238 1535T261 1569T295 1591T336 1600H645Q975 1600 1210 1365Q1328 1247 1386 1108T1445 800Q1445 469 1210 234Q976 0 645 0H336Q314 0 295 8T262 31T239 64T230 106V694H106Q83
+694 64 702T31 724T8 758T0 800Q0 822 8 841T30 875T64 898T106 906H230ZM442 906H722Q767 906 797 876T828 800Q828 777 820 758T798 725T764 702T722 694H442V212H645Q888 212 1060 384Q1147 471 1190 573T1233 800Q1233 1042 1060 1215Q887 1388 645 1388H442V906Z"
+/>
+<glyph unicode="&#xd1;" glyph-name="Ntilde" horiz-adv-x="1440" d="M77 106V1494Q77 1516 85 1535T107 1569T141 1592T183 1600Q230 1600 265 1561L1157 414V1494Q1157 1538 1188 1569T1263 1600Q1307 1600 1338 1569T1369 1494V106Q1369 83 1361 64T1339 31T1305
+8T1263 0Q1216 0 1182 37L289 1184V106Q289 62 258 31T183 0Q139 0 108 31T77 106ZM569 1711Q531 1711 485 1722T399 1755T331 1808T304 1882Q305 1929 335 1957T408 1986Q444 1986 489 1953T573 1920Q616 1920 646 1947Q733 2029 865 2029Q902 2029 948 2018T1035
+1984T1102 1930T1130 1858Q1130 1813 1100 1784T1025 1754Q993 1754 946 1787T862 1820Q821 1820 788 1793Q698 1711 569 1711Z" />
+<glyph unicode="&#xd2;" glyph-name="Ograve" horiz-adv-x="1760" d="M880 1388Q756 1388 654 1345T464 1215Q377 1128 335 1026T292 800Q292 556 464 384Q636 212 880 212Q1124 212 1296 384Q1468 556 1468 800Q1468 1043 1296 1215Q1123 1388 880 1388ZM1680
+800Q1680 469 1445 234Q1211 0 880 0Q548 0 314 234Q80 468 80 800Q80 1131 314 1365Q549 1600 880 1600Q1210 1600 1445 1365Q1563 1247 1621 1107T1680 800ZM684 1974Q684 2018 713 2048T788 2079Q830 2079 862 2048L1062 1849Q1088 1821 1088 1778Q1088 1733
+1059 1704T984 1674Q940 1674 912 1702L712 1901Q684 1929 684 1974Z" />
+<glyph unicode="&#xd3;" glyph-name="Oacute" horiz-adv-x="1760" d="M880 1388Q756 1388 654 1345T464 1215Q377 1128 335 1026T292 800Q292 556 464 384Q636 212 880 212Q1124 212 1296 384Q1468 556 1468 800Q1468 1043 1296 1215Q1123 1388 880 1388ZM1680
+800Q1680 469 1445 234Q1211 0 880 0Q548 0 314 234Q80 468 80 800Q80 1131 314 1365Q549 1600 880 1600Q1210 1600 1445 1365Q1563 1247 1621 1107T1680 800ZM1077 1901L877 1702Q849 1674 805 1674Q760 1674 731 1703T701 1778Q701 1821 727 1849L927 2048Q959
+2079 1001 2079Q1046 2079 1075 2049T1105 1974Q1105 1929 1077 1901Z" />
+<glyph unicode="&#xd4;" glyph-name="Ocircumflex" horiz-adv-x="1760" d="M880 1388Q756 1388 654 1345T464 1215Q377 1128 335 1026T292 800Q292 556 464 384Q636 212 880 212Q1124 212 1296 384Q1468 556 1468 800Q1468 1043 1296 1215Q1123 1388 880 1388ZM1680
+800Q1680 469 1445 234Q1211 0 880 0Q548 0 314 234Q80 468 80 800Q80 1131 314 1365Q549 1600 880 1600Q1210 1600 1445 1365Q1563 1247 1621 1107T1680 800ZM1158 1913Q1208 1875 1208 1823Q1208 1778 1179 1749T1104 1719Q1069 1719 1038 1741L876 1848L714
+1741Q684 1719 648 1719Q603 1719 574 1748T544 1823Q544 1876 593 1913L822 2064Q847 2080 876 2080Q905 2080 930 2064L1158 1913Z" />
+<glyph unicode="&#xd5;" glyph-name="Otilde" horiz-adv-x="1760" d="M880 1388Q756 1388 654 1345T464 1215Q377 1128 335 1026T292 800Q292 556 464 384Q636 212 880 212Q1124 212 1296 384Q1468 556 1468 800Q1468 1043 1296 1215Q1123 1388 880 1388ZM1680
+800Q1680 469 1445 234Q1211 0 880 0Q548 0 314 234Q80 468 80 800Q80 1131 314 1365Q549 1600 880 1600Q1210 1600 1445 1365Q1563 1247 1621 1107T1680 800ZM729 1711Q691 1711 645 1722T559 1755T491 1808T464 1882Q465 1929 495 1957T568 1986Q604 1986 649
+1953T733 1920Q776 1920 806 1947Q893 2029 1025 2029Q1062 2029 1108 2018T1195 1984T1262 1930T1290 1858Q1290 1813 1260 1784T1185 1754Q1153 1754 1106 1787T1022 1820Q981 1820 948 1793Q858 1711 729 1711Z" />
+<glyph unicode="&#xd6;" glyph-name="Odieresis" horiz-adv-x="1760" d="M880 1388Q756 1388 654 1345T464 1215Q377 1128 335 1026T292 800Q292 556 464 384Q636 212 880 212Q1124 212 1296 384Q1468 556 1468 800Q1468 1043 1296 1215Q1123 1388 880 1388ZM1680
+800Q1680 469 1445 234Q1211 0 880 0Q548 0 314 234Q80 468 80 800Q80 1131 314 1365Q549 1600 880 1600Q1210 1600 1445 1365Q1563 1247 1621 1107T1680 800ZM779 1839Q779 1788 743 1752T656 1716Q605 1716 569 1752T533 1839Q533 1890 569 1926T656 1962Q707
+1962 743 1926T779 1839ZM1234 1839Q1234 1788 1198 1752T1111 1716Q1060 1716 1024 1752T988 1839Q988 1890 1024 1926T1111 1962Q1162 1962 1198 1926T1234 1839Z" />
+<glyph unicode="&#xd7;" glyph-name="multiply" horiz-adv-x="960" d="M336 712L104 943Q76 974 76 1016Q76 1037 84 1056T106 1089T139 1112T180 1120Q224 1120 255 1089L484 860L713 1089Q744 1120 788 1120Q809 1120 828 1112T861 1090T884 1056T892 1016Q892
+975 863 943L632 712L863 481Q892 450 892 408Q892 386 884 367T862 334T828 312T788 304Q743 304 715 331L484 564L251 331Q223 304 180 304Q135 304 106 333T76 408Q76 454 104 481L336 712Z" />
+<glyph unicode="&#xd8;" glyph-name="Oslash" horiz-adv-x="1760" d="M1516 1286Q1600 1180 1640 1060T1680 800Q1680 469 1445 234Q1211 0 880 0Q740 0 620 40T394 164L261 30Q229 0 186 0Q163 0 144 8T111 30T88 64T80 106Q80 150 108 178L244 314Q160 420 120
+540T80 800Q80 1131 314 1365Q549 1600 880 1600Q1020 1600 1140 1560T1366 1436L1499 1569Q1530 1600 1574 1600Q1596 1600 1615 1592T1649 1570T1672 1536T1680 1494Q1680 1455 1656 1427L1516 1286ZM1215 1285Q1069 1388 880 1388Q756 1388 654 1345T464 1215Q377
+1128 335 1026T292 800Q292 611 395 466L1215 1285ZM546 315Q691 212 880 212Q1124 212 1296 384Q1468 556 1468 800Q1468 985 1364 1134L546 315Z" />
+<glyph unicode="&#xd9;" glyph-name="Ugrave" horiz-adv-x="1280" d="M288 1494V569Q288 496 316 431T392 318T505 241T644 212Q718 212 783 240T896 317T973 430T1001 569V1494Q1001 1538 1032 1569T1107 1600Q1151 1600 1182 1569T1213 1494V569Q1213 491 1193
+419T1135 284T1046 168T931 79T795 21T644 0Q408 0 243 167Q76 334 76 569V1494Q76 1538 107 1569T182 1600Q226 1600 257 1569T288 1494ZM364 1974Q364 2018 393 2048T468 2079Q510 2079 542 2048L742 1849Q768 1821 768 1778Q768 1733 739 1704T664 1674Q620
+1674 592 1702L392 1901Q364 1929 364 1974Z" />
+<glyph unicode="&#xda;" glyph-name="Uacute" horiz-adv-x="1280" d="M288 1494V569Q288 496 316 431T392 318T505 241T644 212Q718 212 783 240T896 317T973 430T1001 569V1494Q1001 1538 1032 1569T1107 1600Q1151 1600 1182 1569T1213 1494V569Q1213 491 1193
+419T1135 284T1046 168T931 79T795 21T644 0Q408 0 243 167Q76 334 76 569V1494Q76 1538 107 1569T182 1600Q226 1600 257 1569T288 1494ZM907 1901L707 1702Q679 1674 635 1674Q590 1674 561 1703T531 1778Q531 1821 557 1849L757 2048Q789 2079 831 2079Q876
+2079 905 2049T935 1974Q935 1929 907 1901Z" />
+<glyph unicode="&#xdb;" glyph-name="Ucircumflex" horiz-adv-x="1280" d="M288 1494V569Q288 496 316 431T392 318T505 241T644 212Q718 212 783 240T896 317T973 430T1001 569V1494Q1001 1538 1032 1569T1107 1600Q1151 1600 1182 1569T1213 1494V569Q1213 491
+1193 419T1135 284T1046 168T931 79T795 21T644 0Q408 0 243 167Q76 334 76 569V1494Q76 1538 107 1569T182 1600Q226 1600 257 1569T288 1494ZM918 1913Q968 1875 968 1823Q968 1778 939 1749T864 1719Q829 1719 798 1741L636 1848L474 1741Q444 1719 408 1719Q363
+1719 334 1748T304 1823Q304 1876 353 1913L582 2064Q607 2080 636 2080Q665 2080 690 2064L918 1913Z" />
+<glyph unicode="&#xdc;" glyph-name="Udieresis" horiz-adv-x="1280" d="M288 1494V569Q288 496 316 431T392 318T505 241T644 212Q718 212 783 240T896 317T973 430T1001 569V1494Q1001 1538 1032 1569T1107 1600Q1151 1600 1182 1569T1213 1494V569Q1213 491
+1193 419T1135 284T1046 168T931 79T795 21T644 0Q408 0 243 167Q76 334 76 569V1494Q76 1538 107 1569T182 1600Q226 1600 257 1569T288 1494ZM539 1839Q539 1788 503 1752T416 1716Q365 1716 329 1752T293 1839Q293 1890 329 1926T416 1962Q467 1962 503 1926T539
+1839ZM994 1839Q994 1788 958 1752T871 1716Q820 1716 784 1752T748 1839Q748 1890 784 1926T871 1962Q922 1962 958 1926T994 1839Z" />
+<glyph unicode="&#xdd;" glyph-name="Yacute" horiz-adv-x="1280" d="M268 1556L644 993L1020 1556Q1051 1600 1107 1600Q1151 1600 1181 1569T1212 1494Q1212 1458 1196 1434L750 768V106Q750 62 719 31T644 0Q601 0 570 31T538 106V768L93 1434Q76 1460 76 1494Q76
+1538 107 1569T182 1600Q238 1600 268 1556ZM907 1901L707 1702Q679 1674 635 1674Q590 1674 561 1703T531 1778Q531 1821 557 1849L757 2048Q789 2079 831 2079Q876 2079 905 2049T935 1974Q935 1929 907 1901Z" />
+<glyph unicode="&#xde;" glyph-name="Thorn" horiz-adv-x="1280" d="M76 1494Q76 1516 84 1535T106 1569T140 1592T182 1600Q204 1600 223 1592T257 1570T280 1536T288 1494V1292H722Q822 1292 911 1253T1068 1147T1174 991T1213 800Q1213 698 1174 609T1067 452T911
+347T722 308H288V106Q288 83 280 64T258 31T224 8T182 0Q159 0 140 8T107 30T84 64T76 106V1494ZM722 520Q780 520 831 542T919 602T979 691T1001 800Q1001 858 979 909T919 998T830 1058T722 1080H288V520H722Z" />
+<glyph unicode="&#xdf;" glyph-name="germandbls" horiz-adv-x="1120" d="M290 105Q290 84 282 65T259 31T225 8T183 0Q161 0 142 8T109 31T86 65T78 105V1183Q78 1267 110 1343T199 1475T331 1565T492 1598Q577 1598 652 1565T783 1476T872 1344T905 1183Q905
+1031 810 920Q793 894 793 863Q793 806 832 785Q886 756 928 716T1000 628T1044 526T1060 414Q1060 329 1027 254T938 122T806 33T646 0Q474 0 353 122Q319 155 319 199Q319 220 327 239T350 273T383 296T425 304Q467 304 503 272Q563 212 646 212Q686 212 723
+228T787 271T831 335T848 414Q848 499 789 558V557Q760 582 723 607T668 651Q578 739 578 864Q578 977 655 1065Q693 1112 693 1183Q693 1225 677 1262T633 1326T569 1370T492 1386Q450 1386 413 1371T349 1328T306 1263T290 1183V105Z" />
+<glyph unicode="&#xe0;" glyph-name="agrave" horiz-adv-x="1280" d="M640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM991 104V124Q916
+64 828 32T640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1200 792 1200 560V104Q1200 61 1170 31T1096 0Q1052 0 1022 30T991 104ZM402 1494Q402 1538 431 1568T506 1599Q548 1599 580 1568L780 1369Q806 1341 806 1298Q806
+1253 777 1224T702 1194Q658 1194 630 1222L430 1421Q402 1449 402 1494Z" />
+<glyph unicode="&#xe1;" glyph-name="aacute" horiz-adv-x="1280" d="M640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM991 104V124Q916
+64 828 32T640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1200 792 1200 560V104Q1200 61 1170 31T1096 0Q1052 0 1022 30T991 104ZM856 1421L656 1222Q628 1194 584 1194Q539 1194 510 1223T480 1298Q480 1341 506 1369L706
+1568Q738 1599 780 1599Q825 1599 854 1569T884 1494Q884 1449 856 1421Z" />
+<glyph unicode="&#xe2;" glyph-name="acircumflex" horiz-adv-x="1280" d="M640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM991
+104V124Q916 64 828 32T640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1200 792 1200 560V104Q1200 61 1170 31T1096 0Q1052 0 1022 30T991 104ZM918 1433Q968 1395 968 1343Q968 1298 939 1269T864 1239Q829 1239 798
+1261L636 1368L474 1261Q444 1239 408 1239Q363 1239 334 1268T304 1343Q304 1396 353 1433L582 1584Q607 1600 636 1600Q665 1600 690 1584L918 1433Z" />
+<glyph unicode="&#xe3;" glyph-name="atilde" horiz-adv-x="1280" d="M640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM991 104V124Q916
+64 828 32T640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1200 792 1200 560V104Q1200 61 1170 31T1096 0Q1052 0 1022 30T991 104ZM496 1231Q458 1231 412 1242T326 1275T258 1328T231 1402Q232 1449 262 1477T335 1506Q371
+1506 416 1473T500 1440Q543 1440 573 1467Q660 1549 792 1549Q829 1549 875 1538T962 1504T1029 1450T1057 1378Q1057 1333 1027 1304T952 1274Q920 1274 873 1307T789 1340Q748 1340 715 1313Q625 1231 496 1231Z" />
+<glyph unicode="&#xe4;" glyph-name="adieresis" horiz-adv-x="1280" d="M640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM991
+104V124Q916 64 828 32T640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1200 792 1200 560V104Q1200 61 1170 31T1096 0Q1052 0 1022 30T991 104ZM539 1359Q539 1308 503 1272T416 1236Q365 1236 329 1272T293 1359Q293
+1410 329 1446T416 1482Q467 1482 503 1446T539 1359ZM994 1359Q994 1308 958 1272T871 1236Q820 1236 784 1272T748 1359Q748 1410 784 1446T871 1482Q922 1482 958 1446T994 1359Z" />
+<glyph unicode="&#xe5;" glyph-name="aring" horiz-adv-x="1280" d="M640 911Q566 911 502 883T391 808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM991 104V124Q916
+64 828 32T640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1200 792 1200 560V104Q1200 61 1170 31T1096 0Q1052 0 1022 30T991 104ZM859 1379Q859 1334 842 1294T794 1224T725 1177T640 1159Q595 1159 555 1176T485 1223T438
+1293T420 1379Q420 1424 437 1464T485 1534T555 1581T640 1599Q685 1599 725 1581T795 1533T842 1463T859 1379ZM640 1446Q612 1446 592 1426T572 1379Q572 1351 592 1332T640 1312Q667 1312 686 1331T706 1379Q706 1406 687 1426T640 1446Z" />
+<glyph unicode="&#xe6;" glyph-name="ae" horiz-adv-x="2240" d="M652 911Q579 911 515 884T404 809T329 697T301 560Q301 487 328 423T403 312T515 237T652 209Q725 209 789 236T900 311T975 423T1003 560Q1003 633 976 697T901 808T789 883T652 911ZM1900 664Q1883
+719 1850 765T1771 843T1673 893T1563 911Q1507 911 1453 893T1354 843T1276 765T1226 664H1900ZM1212 104Q1212 83 1204 64T1182 31T1148 8T1108 0Q1086 0 1067 8T1034 30T1011 64T1003 104V124Q928 64 840 32T652 0Q420 0 256 164Q92 328 92 560Q92 792 256 956Q420
+1120 652 1120Q793 1120 903 1062T1108 887Q1156 945 1206 988T1312 1061T1430 1105T1563 1120Q1795 1120 1959 956Q2123 792 2123 560Q2123 515 2094 486T2019 456H1226Q1244 399 1277 354T1355 276T1453 227T1563 209Q1629 209 1684 229T1786 289Q1818 315 1855
+315Q1899 315 1929 286T1960 211Q1960 166 1929 136Q1774 0 1563 0Q1463 0 1375 32T1212 124V104Z" />
+<glyph unicode="&#xe7;" glyph-name="ccedilla" horiz-adv-x="1120" d="M932 317Q977 317 1006 288T1036 213Q1036 169 1003 136Q848 0 638 0Q406 0 242 164Q78 328 78 560Q78 792 242 956Q406 1120 638 1120Q849 1120 1003 984Q1039 952 1039 905Q1039 860 1010
+830T935 800Q897 800 867 824Q816 867 760 889T638 911Q565 911 501 884T389 809T314 697T286 560Q286 487 313 423T389 312T501 237T638 209Q704 209 760 230T866 295Q894 316 932 317ZM530 82Q561 110 603 110Q648 110 677 80T707 5Q707 -6 704 -18L695 -53Q821
+-127 821 -251Q821 -348 744 -414Q671 -479 565 -479Q501 -479 442 -448L355 -395Q309 -358 309 -308Q309 -264 338 -234T413 -203Q442 -202 469 -219L541 -264Q553 -270 565 -270Q612 -270 612 -248Q612 -226 567 -223Q522 -223 486 -190T462 -104L502 35Q508
+58 530 82Z" />
+<glyph unicode="&#xe8;" glyph-name="egrave" horiz-adv-x="1280" d="M977 664Q960 719 927 764T849 842T751 893T640 911Q583 911 529 893T430 843T352 765T303 664H977ZM932 315Q977 315 1006 286T1036 211Q1036 167 1006 136Q851 0 640 0Q408 0 244 164Q80
+328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 875 1159 776T1200 560Q1200 515 1170 486T1095 456H303Q320 401 353 356T430 278T528 227T640 209Q706 209 761 229T863 289Q893 314 932 315ZM401 1494Q401 1538 430 1568T505 1599Q547
+1599 579 1568L779 1369Q805 1341 805 1298Q805 1253 776 1224T701 1194Q657 1194 629 1222L429 1421Q401 1449 401 1494Z" />
+<glyph unicode="&#xe9;" glyph-name="eacute" horiz-adv-x="1280" d="M977 664Q960 719 927 764T849 842T751 893T640 911Q583 911 529 893T430 843T352 765T303 664H977ZM932 315Q977 315 1006 286T1036 211Q1036 167 1006 136Q851 0 640 0Q408 0 244 164Q80
+328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 875 1159 776T1200 560Q1200 515 1170 486T1095 456H303Q320 401 353 356T430 278T528 227T640 209Q706 209 761 229T863 289Q893 314 932 315ZM856 1421L656 1222Q628 1194 584 1194Q539
+1194 510 1223T480 1298Q480 1341 506 1369L706 1568Q738 1599 780 1599Q825 1599 854 1569T884 1494Q884 1449 856 1421Z" />
+<glyph unicode="&#xea;" glyph-name="ecircumflex" horiz-adv-x="1280" d="M977 664Q960 719 927 764T849 842T751 893T640 911Q583 911 529 893T430 843T352 765T303 664H977ZM932 315Q977 315 1006 286T1036 211Q1036 167 1006 136Q851 0 640 0Q408 0 244 164Q80
+328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 875 1159 776T1200 560Q1200 515 1170 486T1095 456H303Q320 401 353 356T430 278T528 227T640 209Q706 209 761 229T863 289Q893 314 932 315ZM918 1433Q968 1395 968 1343Q968 1298 939
+1269T864 1239Q829 1239 798 1261L636 1368L474 1261Q444 1239 408 1239Q363 1239 334 1268T304 1343Q304 1396 353 1433L582 1584Q607 1600 636 1600Q665 1600 690 1584L918 1433Z" />
+<glyph unicode="&#xeb;" glyph-name="edieresis" horiz-adv-x="1280" d="M977 664Q960 719 927 764T849 842T751 893T640 911Q583 911 529 893T430 843T352 765T303 664H977ZM932 315Q977 315 1006 286T1036 211Q1036 167 1006 136Q851 0 640 0Q408 0 244 164Q80
+328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 875 1159 776T1200 560Q1200 515 1170 486T1095 456H303Q320 401 353 356T430 278T528 227T640 209Q706 209 761 229T863 289Q893 314 932 315ZM539 1359Q539 1308 503 1272T416 1236Q365
+1236 329 1272T293 1359Q293 1410 329 1446T416 1482Q467 1482 503 1446T539 1359ZM994 1359Q994 1308 958 1272T871 1236Q820 1236 784 1272T748 1359Q748 1410 784 1446T871 1482Q922 1482 958 1446T994 1359Z" />
+<glyph unicode="&#xec;" glyph-name="igrave" horiz-adv-x="480" d="M393 105V1015Q393 1059 423 1089T497 1120Q540 1120 570 1090T602 1015V105Q601 61 571 31T497 0Q454 0 424 30T393 105ZM260 1494Q260 1538 289 1568T364 1599Q406 1599 438 1568L638 1369Q664
+1341 664 1298Q664 1253 635 1224T560 1194Q516 1194 488 1222L288 1421Q260 1449 260 1494Z" />
+<glyph unicode="&#xed;" glyph-name="iacute" horiz-adv-x="480" d="M393 105V1015Q393 1059 423 1089T497 1120Q540 1120 570 1090T602 1015V105Q601 61 571 31T497 0Q454 0 424 30T393 105ZM709 1421L509 1222Q481 1194 437 1194Q392 1194 363 1223T333 1298Q333
+1341 359 1369L559 1568Q591 1599 633 1599Q678 1599 707 1569T737 1494Q737 1449 709 1421Z" />
+<glyph unicode="&#xee;" glyph-name="icircumflex" horiz-adv-x="560" d="M180 105V1015Q180 1059 210 1089T284 1120Q327 1120 357 1090T389 1015V105Q388 61 358 31T284 0Q241 0 211 30T180 105ZM820 1433Q870 1395 870 1343Q870 1298 841 1269T766 1239Q731
+1239 700 1261L538 1368L376 1261Q346 1239 310 1239Q265 1239 236 1268T206 1343Q206 1396 255 1433L484 1584Q509 1600 538 1600Q567 1600 592 1584L820 1433Z" />
+<glyph unicode="&#xef;" glyph-name="idieresis" horiz-adv-x="600" d="M196 105V1015Q196 1059 226 1089T300 1120Q343 1120 373 1090T405 1015V105Q404 61 374 31T300 0Q257 0 227 30T196 105ZM203 1359Q203 1308 167 1272T80 1236Q29 1236 -7 1272T-43 1359Q-43
+1410 -7 1446T80 1482Q131 1482 167 1446T203 1359ZM658 1359Q658 1308 622 1272T535 1236Q484 1236 448 1272T412 1359Q412 1410 448 1446T535 1482Q586 1482 622 1446T658 1359Z" />
+<glyph unicode="&#xf0;" glyph-name="eth" horiz-adv-x="1280" d="M638 924Q563 924 498 896T386 819T310 706T282 568Q282 495 310 430T385 317T498 241T638 212Q712 212 777 240T890 317T966 430T994 568Q994 641 966 705T890 818T777 895T638 924ZM554 1429L538
+1457Q531 1473 531 1495Q531 1517 539 1536T562 1569T596 1592T638 1601Q688 1601 713 1568L735 1535L831 1592Q850 1601 876 1601Q904 1601 929 1588T968 1550Q982 1525 982 1495Q982 1468 969 1443T930 1404L843 1353L1137 842Q1172 781 1189 712T1206 568Q1206
+331 1039 166Q871 0 638 0Q403 0 236 166Q70 333 70 568Q70 803 236 969Q403 1136 638 1136Q682 1136 724 1130L659 1246L549 1183Q529 1173 503 1173Q475 1173 451 1186T412 1223Q398 1248 398 1278Q398 1305 410 1330T449 1369L554 1429Z" />
+<glyph unicode="&#xf1;" glyph-name="ntilde" horiz-adv-x="1200" d="M288 1017Q421 1120 601 1120Q706 1120 800 1079T967 968T1081 802T1123 598V105Q1123 61 1093 31T1019 0Q975 0 945 30T914 105V598Q914 662 889 719T822 818T722 886T601 911Q536 911 480
+887T380 819T313 719T288 598V105Q288 61 258 31T184 0Q140 0 110 30T79 105V1015Q79 1058 109 1089T184 1120Q227 1120 257 1089T288 1017ZM461 1231Q423 1231 377 1242T291 1275T223 1328T196 1402Q197 1449 227 1477T300 1506Q336 1506 381 1473T465 1440Q508
+1440 538 1467Q625 1549 757 1549Q794 1549 840 1538T927 1504T994 1450T1022 1378Q1022 1333 992 1304T917 1274Q885 1274 838 1307T754 1340Q713 1340 680 1313Q590 1231 461 1231Z" />
+<glyph unicode="&#xf2;" glyph-name="ograve" horiz-adv-x="1280" d="M1200 560Q1200 326 1036 164Q870 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 874 1158 775T1200 560ZM640 911Q566 911 502 883T391
+808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM401 1494Q401 1538 430 1568T505 1599Q547 1599 579 1568L779 1369Q805 1341 805 1298Q805 1253 776 1224T701
+1194Q657 1194 629 1222L429 1421Q401 1449 401 1494Z" />
+<glyph unicode="&#xf3;" glyph-name="oacute" horiz-adv-x="1280" d="M1200 560Q1200 326 1036 164Q870 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 874 1158 775T1200 560ZM640 911Q566 911 502 883T391
+808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM856 1421L656 1222Q628 1194 584 1194Q539 1194 510 1223T480 1298Q480 1341 506 1369L706 1568Q738 1599 780
+1599Q825 1599 854 1569T884 1494Q884 1449 856 1421Z" />
+<glyph unicode="&#xf4;" glyph-name="ocircumflex" horiz-adv-x="1280" d="M1200 560Q1200 326 1036 164Q870 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 874 1158 775T1200 560ZM640 911Q566 911 502 883T391
+808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM918 1433Q968 1395 968 1343Q968 1298 939 1269T864 1239Q829 1239 798 1261L636 1368L474 1261Q444 1239 408
+1239Q363 1239 334 1268T304 1343Q304 1396 353 1433L582 1584Q607 1600 636 1600Q665 1600 690 1584L918 1433Z" />
+<glyph unicode="&#xf5;" glyph-name="otilde" horiz-adv-x="1280" d="M1200 560Q1200 326 1036 164Q870 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 874 1158 775T1200 560ZM640 911Q566 911 502 883T391
+808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM496 1231Q458 1231 412 1242T326 1275T258 1328T231 1402Q232 1449 262 1477T335 1506Q371 1506 416 1473T500
+1440Q543 1440 573 1467Q660 1549 792 1549Q829 1549 875 1538T962 1504T1029 1450T1057 1378Q1057 1333 1027 1304T952 1274Q920 1274 873 1307T789 1340Q748 1340 715 1313Q625 1231 496 1231Z" />
+<glyph unicode="&#xf6;" glyph-name="odieresis" horiz-adv-x="1280" d="M1200 560Q1200 326 1036 164Q870 0 640 0Q408 0 244 164Q80 328 80 560Q80 792 244 956Q408 1120 640 1120Q870 1120 1036 956Q1118 874 1158 775T1200 560ZM640 911Q566 911 502 883T391
+808T317 696T289 560Q289 488 316 424T391 313T502 237T640 209Q713 209 777 237T888 313T963 424T991 560Q991 632 964 695T889 807T777 883T640 911ZM539 1359Q539 1308 503 1272T416 1236Q365 1236 329 1272T293 1359Q293 1410 329 1446T416 1482Q467 1482 503
+1446T539 1359ZM994 1359Q994 1308 958 1272T871 1236Q820 1236 784 1272T748 1359Q748 1410 784 1446T871 1482Q922 1482 958 1446T994 1359Z" />
+<glyph unicode="&#xf7;" glyph-name="divide" horiz-adv-x="960" d="M180 607Q135 607 106 637T76 712Q76 757 105 786T180 816H788Q833 816 862 787T892 712Q892 667 863 637T788 607H180ZM607 997Q607 945 571 909T484 873Q432 873 396 909T360 997Q360 1048
+396 1084T484 1120Q535 1120 571 1084T607 997ZM607 428Q607 376 571 340T484 304Q432 304 396 340T360 428Q360 479 396 515T484 551Q535 551 571 515T607 428Z" />
+<glyph unicode="&#xf8;" glyph-name="oslash" horiz-adv-x="1280" d="M804 871Q767 892 726 901T640 911Q566 911 502 883T391 808T317 696T289 560Q289 469 327 396L804 871ZM476 248Q513 228 553 219T640 209Q713 209 777 237T888 313T963 424T991 560Q991 606
+982 646T952 724L476 248ZM1019 1087Q1050 1120 1095 1120Q1117 1120 1136 1112T1169 1090T1191 1056T1200 1016Q1200 974 1170 943L1103 875Q1200 738 1200 560Q1200 326 1036 164Q870 0 640 0Q461 0 325 97L255 24Q228 0 184 0Q162 0 143 8T110 30T88 64T80 104Q80
+125 86 143T108 177L177 245Q80 381 80 560Q80 792 244 956Q408 1120 640 1120Q820 1120 956 1023L1019 1087Z" />
+<glyph unicode="&#xf9;" glyph-name="ugrave" horiz-adv-x="1200" d="M1018 0Q973 0 944 30T914 103Q845 49 768 25T601 0Q494 0 399 41T233 154T121 320T79 522V1016Q79 1059 109 1089T184 1120Q227 1120 257 1090T288 1016V522Q288 457 312 400T379 301T479
+234T601 209Q665 209 722 233T822 301T889 400T914 522V1016Q914 1059 944 1089T1019 1120Q1062 1120 1092 1090T1123 1016V104Q1123 61 1093 31T1018 0ZM391 1494Q391 1538 420 1568T495 1599Q537 1599 569 1568L769 1369Q795 1341 795 1298Q795 1253 766 1224T691
+1194Q647 1194 619 1222L419 1421Q391 1449 391 1494Z" />
+<glyph unicode="&#xfa;" glyph-name="uacute" horiz-adv-x="1200" d="M1018 0Q973 0 944 30T914 103Q845 49 768 25T601 0Q494 0 399 41T233 154T121 320T79 522V1016Q79 1059 109 1089T184 1120Q227 1120 257 1090T288 1016V522Q288 457 312 400T379 301T479
+234T601 209Q665 209 722 233T822 301T889 400T914 522V1016Q914 1059 944 1089T1019 1120Q1062 1120 1092 1090T1123 1016V104Q1123 61 1093 31T1018 0ZM800 1421L600 1222Q572 1194 528 1194Q483 1194 454 1223T424 1298Q424 1341 450 1369L650 1568Q682 1599
+724 1599Q769 1599 798 1569T828 1494Q828 1449 800 1421Z" />
+<glyph unicode="&#xfb;" glyph-name="ucircumflex" horiz-adv-x="1200" d="M1018 0Q973 0 944 30T914 103Q845 49 768 25T601 0Q494 0 399 41T233 154T121 320T79 522V1016Q79 1059 109 1089T184 1120Q227 1120 257 1090T288 1016V522Q288 457 312 400T379 301T479
+234T601 209Q665 209 722 233T822 301T889 400T914 522V1016Q914 1059 944 1089T1019 1120Q1062 1120 1092 1090T1123 1016V104Q1123 61 1093 31T1018 0ZM878 1433Q928 1395 928 1343Q928 1298 899 1269T824 1239Q789 1239 758 1261L596 1368L434 1261Q404 1239
+368 1239Q323 1239 294 1268T264 1343Q264 1396 313 1433L542 1584Q567 1600 596 1600Q625 1600 650 1584L878 1433Z" />
+<glyph unicode="&#xfc;" glyph-name="udieresis" horiz-adv-x="1200" d="M1018 0Q973 0 944 30T914 103Q845 49 768 25T601 0Q494 0 399 41T233 154T121 320T79 522V1016Q79 1059 109 1089T184 1120Q227 1120 257 1090T288 1016V522Q288 457 312 400T379 301T479
+234T601 209Q665 209 722 233T822 301T889 400T914 522V1016Q914 1059 944 1089T1019 1120Q1062 1120 1092 1090T1123 1016V104Q1123 61 1093 31T1018 0ZM499 1359Q499 1308 463 1272T376 1236Q325 1236 289 1272T253 1359Q253 1410 289 1446T376 1482Q427 1482
+463 1446T499 1359ZM954 1359Q954 1308 918 1272T831 1236Q780 1236 744 1272T708 1359Q708 1410 744 1446T831 1482Q882 1482 918 1446T954 1359Z" />
+<glyph unicode="&#xfd;" glyph-name="yacute" horiz-adv-x="1120" d="M448 104L88 969Q78 992 78 1016Q78 1037 86 1056T108 1089T141 1112T182 1120Q213 1120 240 1103T281 1051L562 380L843 1053Q855 1083 877 1101T941 1120Q963 1120 982 1112T1015 1090T1037
+1056T1046 1016Q1046 994 1035 969L460 -410Q447 -441 420 -460T361 -480Q316 -480 287 -450T257 -375Q257 -351 267 -329L448 104ZM827 1421L627 1222Q599 1194 555 1194Q510 1194 481 1223T451 1298Q451 1341 477 1369L677 1568Q709 1599 751 1599Q796 1599 825
+1569T855 1494Q855 1449 827 1421Z" />
+<glyph unicode="&#xfe;" glyph-name="thorn" horiz-adv-x="1280" d="M289 562Q289 490 316 426T391 315T502 239T640 211Q713 211 777 239T888 315T963 426T991 562Q991 634 964 697T889 809T777 885T640 913Q566 913 502 885T391 810T317 698T289 562ZM289 998Q364
+1058 452 1090T640 1122Q870 1122 1036 958Q1118 877 1159 778T1200 562Q1200 328 1036 166Q870 2 640 2Q540 2 452 34T289 126V-374Q289 -396 281 -415T258 -448T225 -471T184 -479Q139 -479 110 -449T80 -374V1496Q80 1541 109 1570T184 1600Q228 1600 258 1571T289
+1496V998Z" />
+<glyph unicode="&#xff;" glyph-name="ydieresis" horiz-adv-x="1120" d="M448 104L88 969Q78 992 78 1016Q78 1037 86 1056T108 1089T141 1112T182 1120Q213 1120 240 1103T281 1051L562 380L843 1053Q855 1083 877 1101T941 1120Q963 1120 982 1112T1015 1090T1037
+1056T1046 1016Q1046 994 1035 969L460 -410Q447 -441 420 -460T361 -480Q316 -480 287 -450T257 -375Q257 -351 267 -329L448 104ZM459 1359Q459 1308 423 1272T336 1236Q285 1236 249 1272T213 1359Q213 1410 249 1446T336 1482Q387 1482 423 1446T459 1359ZM914
+1359Q914 1308 878 1272T791 1236Q740 1236 704 1272T668 1359Q668 1410 704 1446T791 1482Q842 1482 878 1446T914 1359Z" />
+<glyph unicode="&#x2013;" glyph-name="endash" horiz-adv-x="800" d="M0 456Q-45 456 -74 485T-104 560Q-104 605 -75 634T0 664H802Q846 664 876 635T907 560Q907 515 877 486T802 456H0Z" />
+<glyph unicode="&#x2014;" glyph-name="emdash" horiz-adv-x="1920" d="M0 664H1919Q1964 664 1993 635T2023 560Q2023 515 1994 486T1919 456H0Q-45 456 -74 485T-104 560Q-104 605 -75 634T0 664Z" />
+<glyph unicode="&#x2018;" glyph-name="quoteleft" horiz-adv-x="480" d="M405 1039Q405 1013 395 991T369 951T329 925T281 915Q235 915 202 947T148 1025T118 1121T108 1214Q108 1391 259 1572Q286 1599 320 1599Q355 1599 380 1574T405 1514Q405 1497 398 1479Q353
+1369 353 1270Q353 1176 394 1088Q405 1063 405 1039Z" />
+<glyph unicode="&#x2019;" glyph-name="quoteright" horiz-adv-x="480" d="M108 1475Q108 1501 118 1523T144 1563T184 1589T232 1599Q278 1599 311 1567T365 1489T395 1393T405 1300Q405 1123 254 942Q227 915 193 915Q158 915 133 940T108 1000Q108 1017 115
+1035Q160 1145 160 1244Q160 1338 119 1426Q108 1451 108 1475Z" />
+<glyph unicode="&#x201a;" glyph-name="quotesinglbase" horiz-adv-x="480" d="M108 197Q108 223 118 245T144 285T184 311T232 321Q278 321 311 289T365 211T395 115T405 22Q405 -155 254 -336Q227 -363 193 -363Q158 -363 133 -338T108 -278Q108 -261 115 -243Q160
+-133 160 -34Q160 60 119 148Q108 173 108 197Z" />
+<glyph unicode="&#x201c;" glyph-name="quotedblleft" horiz-adv-x="760" d="M370 1039Q370 1013 360 991T334 951T294 925T246 915Q200 915 167 947T113 1025T83 1121T73 1214Q73 1391 224 1572Q251 1599 285 1599Q320 1599 345 1574T370 1514Q370 1497 363 1479Q318
+1369 318 1270Q318 1176 359 1088Q370 1063 370 1039ZM699 1039Q699 1013 689 991T663 951T623 925T575 915Q529 915 496 947T442 1025T412 1121T402 1214Q402 1391 553 1572Q580 1599 614 1599Q649 1599 674 1574T699 1514Q699 1497 692 1479Q647 1369 647 1270Q647
+1176 688 1088Q699 1063 699 1039Z" />
+<glyph unicode="&#x201d;" glyph-name="quotedblright" horiz-adv-x="760" d="M402 1475Q402 1501 412 1523T438 1563T478 1589T526 1599Q572 1599 605 1567T659 1489T689 1393T699 1300Q699 1123 548 942Q521 915 487 915Q452 915 427 940T402 1000Q402 1017
+409 1035Q454 1145 454 1244Q454 1338 413 1426Q402 1451 402 1475ZM73 1475Q73 1501 83 1523T109 1563T149 1589T197 1599Q243 1599 276 1567T330 1489T360 1393T370 1300Q370 1123 219 942Q192 915 158 915Q123 915 98 940T73 1000Q73 1017 80 1035Q125 1145
+125 1244Q125 1338 84 1426Q73 1451 73 1475Z" />
+<glyph unicode="&#x201e;" glyph-name="quotedblbase" horiz-adv-x="760" d="M402 197Q402 223 412 245T438 285T478 311T526 321Q572 321 605 289T659 211T689 115T699 22Q699 -155 548 -336Q521 -363 487 -363Q452 -363 427 -338T402 -278Q402 -261 409 -243Q454
+-133 454 -34Q454 60 413 148Q402 173 402 197ZM73 197Q73 223 83 245T109 285T149 311T197 321Q243 321 276 289T330 211T360 115T370 22Q370 -155 219 -336Q192 -363 158 -363Q123 -363 98 -338T73 -278Q73 -261 80 -243Q125 -133 125 -34Q125 60 84 148Q73 173
+73 197Z" />
+<glyph unicode="&#x2022;" glyph-name="bullet" horiz-adv-x="800" d="M662 788Q662 737 642 691T588 609T507 553T406 532Q353 532 307 552T225 607T170 688T150 788Q150 842 171 888T227 969T308 1024T406 1044Q457 1044 503 1024T585 968T641 886T662 788Z" />
+<glyph unicode="&#x2039;" glyph-name="guilsinglleft" horiz-adv-x="560" d="M312 1055Q326 1087 351 1103T408 1119Q453 1119 482 1090T513 1015Q512 990 503 970L298 560L503 148Q512 129 512 104Q512 83 504 64T482 31T449 8T408 0Q379 0 353 16T312 64L91
+505Q76 534 76 559Q76 583 89 609L312 1055Z" />
+<glyph unicode="&#x203a;" glyph-name="guilsinglright" horiz-adv-x="560" d="M500 609Q513 583 513 559Q513 534 498 505L277 64Q262 32 236 16T181 0Q159 0 140 8T107 30T85 64T77 104Q77 129 86 148L291 560L86 970Q77 990 76 1015Q77 1060 106 1089T181 1119Q213
+1119 238 1103T277 1055L500 609Z" />
+<hkern g1="A" g2="C" k="98" />
+<hkern g1="A" g2="G" k="98" />
+<hkern g1="A" g2="O" k="69" />
+<hkern g1="A" g2="Q" k="69" />
+<hkern g1="A" g2="T" k="179" />
+<hkern g1="A" g2="V" k="189" />
+<hkern g1="A" g2="W" k="116" />
+<hkern g1="A" g2="Y" k="179" />
+<hkern g1="A" g2="f" k="64" />
+<hkern g1="A" g2="j" k="186" />
+<hkern g1="A" g2="t" k="148" />
+<hkern g1="A" g2="v" k="225" />
+<hkern g1="A" g2="w" k="199" />
+<hkern g1="A" g2="y" k="256" />
+<hkern g1="A" g2="Ccedilla" k="98" />
+<hkern g1="A" g2="Eth" k="52" />
+<hkern g1="A" g2="Ograve" k="69" />
+<hkern g1="A" g2="Oacute" k="69" />
+<hkern g1="A" g2="Ocircumflex" k="69" />
+<hkern g1="A" g2="Otilde" k="69" />
+<hkern g1="A" g2="Odieresis" k="69" />
+<hkern g1="A" g2="Yacute" k="179" />
+<hkern g1="A" g2="yacute" k="256" />
+<hkern g1="A" g2="ydieresis" k="256" />
+<hkern g1="B" g2="T" k="158" />
+<hkern g1="B" g2="V" k="127" />
+<hkern g1="B" g2="W" k="100" />
+<hkern g1="B" g2="Y" k="157" />
+<hkern g1="B" g2="j" k="230" />
+<hkern g1="B" g2="x" k="65" />
+<hkern g1="B" g2="y" k="65" />
+<hkern g1="B" g2="Yacute" k="157" />
+<hkern g1="B" g2="yacute" k="65" />
+<hkern g1="B" g2="ydieresis" k="65" />
+<hkern g1="C" g2="C" k="74" />
+<hkern g1="C" g2="G" k="74" />
+<hkern g1="C" g2="O" k="45" />
+<hkern g1="C" g2="Q" k="45" />
+<hkern g1="C" g2="f" k="91" />
+<hkern g1="C" g2="j" k="256" />
+<hkern g1="C" g2="t" k="40" />
+<hkern g1="C" g2="v" k="84" />
+<hkern g1="C" g2="w" k="143" />
+<hkern g1="C" g2="y" k="116" />
+<hkern g1="C" g2="Ccedilla" k="74" />
+<hkern g1="C" g2="Ograve" k="45" />
+<hkern g1="C" g2="Oacute" k="45" />
+<hkern g1="C" g2="Ocircumflex" k="45" />
+<hkern g1="C" g2="Otilde" k="45" />
+<hkern g1="C" g2="Odieresis" k="45" />
+<hkern g1="C" g2="yacute" k="79" />
+<hkern g1="C" g2="ydieresis" k="62" />
+<hkern g1="D" g2="A" k="113" />
+<hkern g1="D" g2="T" k="143" />
+<hkern g1="D" g2="V" k="113" />
+<hkern g1="D" g2="X" k="175" />
+<hkern g1="D" g2="Y" k="175" />
+<hkern g1="D" g2="Z" k="207" />
+<hkern g1="D" g2="j" k="276" />
+<hkern g1="D" g2="Agrave" k="113" />
+<hkern g1="D" g2="Aacute" k="113" />
+<hkern g1="D" g2="Acircumflex" k="113" />
+<hkern g1="D" g2="Atilde" k="113" />
+<hkern g1="D" g2="Adieresis" k="113" />
+<hkern g1="D" g2="Aring" k="113" />
+<hkern g1="D" g2="AE" k="116" />
+<hkern g1="D" g2="Yacute" k="175" />
+<hkern g1="E" g2="C" k="128" />
+<hkern g1="E" g2="G" k="128" />
+<hkern g1="E" g2="O" k="130" />
+<hkern g1="E" g2="Q" k="130" />
+<hkern g1="E" g2="c" k="65" />
+<hkern g1="E" g2="f" k="62" />
+<hkern g1="E" g2="j" k="184" />
+<hkern g1="E" g2="t" k="62" />
+<hkern g1="E" g2="v" k="90" />
+<hkern g1="E" g2="w" k="166" />
+<hkern g1="E" g2="y" k="122" />
+<hkern g1="E" g2="Ccedilla" k="128" />
+<hkern g1="E" g2="Eth" k="50" />
+<hkern g1="E" g2="Ograve" k="130" />
+<hkern g1="E" g2="Oacute" k="130" />
+<hkern g1="E" g2="Ocircumflex" k="130" />
+<hkern g1="E" g2="Otilde" k="130" />
+<hkern g1="E" g2="Odieresis" k="130" />
+<hkern g1="E" g2="ae" k="48" />
+<hkern g1="E" g2="ccedilla" k="65" />
+<hkern g1="E" g2="eth" k="57" />
+<hkern g1="E" g2="yacute" k="109" />
+<hkern g1="E" g2="ydieresis" k="65" />
+<hkern g1="F" g2="A" k="183" />
+<hkern g1="F" g2="C" k="128" />
+<hkern g1="F" g2="G" k="128" />
+<hkern g1="F" g2="J" k="148" />
+<hkern g1="F" g2="O" k="130" />
+<hkern g1="F" g2="Q" k="130" />
+<hkern g1="F" g2="S" k="99" />
+<hkern g1="F" g2="a" k="206" />
+<hkern g1="F" g2="c" k="217" />
+<hkern g1="F" g2="d" k="225" />
+<hkern g1="F" g2="e" k="206" />
+<hkern g1="F" g2="f" k="157" />
+<hkern g1="F" g2="g" k="162" />
+<hkern g1="F" g2="j" k="222" />
+<hkern g1="F" g2="m" k="136" />
+<hkern g1="F" g2="n" k="129" />
+<hkern g1="F" g2="o" k="162" />
+<hkern g1="F" g2="p" k="162" />
+<hkern g1="F" g2="q" k="162" />
+<hkern g1="F" g2="r" k="126" />
+<hkern g1="F" g2="s" k="127" />
+<hkern g1="F" g2="t" k="62" />
+<hkern g1="F" g2="u" k="179" />
+<hkern g1="F" g2="v" k="192" />
+<hkern g1="F" g2="w" k="166" />
+<hkern g1="F" g2="x" k="254" />
+<hkern g1="F" g2="y" k="223" />
+<hkern g1="F" g2="z" k="60" />
+<hkern g1="F" g2="Agrave" k="183" />
+<hkern g1="F" g2="Aacute" k="175" />
+<hkern g1="F" g2="Acircumflex" k="183" />
+<hkern g1="F" g2="Atilde" k="167" />
+<hkern g1="F" g2="Adieresis" k="183" />
+<hkern g1="F" g2="Aring" k="198" />
+<hkern g1="F" g2="AE" k="285" />
+<hkern g1="F" g2="Ccedilla" k="128" />
+<hkern g1="F" g2="Eth" k="50" />
+<hkern g1="F" g2="Ograve" k="130" />
+<hkern g1="F" g2="Oacute" k="130" />
+<hkern g1="F" g2="Ocircumflex" k="130" />
+<hkern g1="F" g2="Otilde" k="130" />
+<hkern g1="F" g2="Odieresis" k="130" />
+<hkern g1="F" g2="Oslash" k="130" />
+<hkern g1="F" g2="agrave" k="162" />
+<hkern g1="F" g2="aacute" k="162" />
+<hkern g1="F" g2="acircumflex" k="162" />
+<hkern g1="F" g2="adieresis" k="130" />
+<hkern g1="F" g2="aring" k="162" />
+<hkern g1="F" g2="ae" k="174" />
+<hkern g1="F" g2="ccedilla" k="160" />
+<hkern g1="F" g2="egrave" k="162" />
+<hkern g1="F" g2="eacute" k="162" />
+<hkern g1="F" g2="ecircumflex" k="162" />
+<hkern g1="F" g2="edieresis" k="130" />
+<hkern g1="F" g2="eth" k="152" />
+<hkern g1="F" g2="ograve" k="162" />
+<hkern g1="F" g2="oacute" k="162" />
+<hkern g1="F" g2="ocircumflex" k="162" />
+<hkern g1="F" g2="odieresis" k="130" />
+<hkern g1="F" g2="oslash" k="162" />
+<hkern g1="F" g2="ugrave" k="129" />
+<hkern g1="F" g2="uacute" k="129" />
+<hkern g1="F" g2="ucircumflex" k="98" />
+<hkern g1="F" g2="udieresis" k="66" />
+<hkern g1="F" g2="yacute" k="223" />
+<hkern g1="F" g2="ydieresis" k="65" />
+<hkern g1="F" g2="dotlessi" k="196" />
+<hkern g1="G" g2="f" k="60" />
+<hkern g1="G" g2="j" k="198" />
+<hkern g1="G" g2="t" k="60" />
+<hkern g1="H" g2="j" k="159" />
+<hkern g1="I" g2="I" k="26" />
+<hkern g1="I" g2="j" k="192" />
+<hkern g1="I" g2="Igrave" k="60" />
+<hkern g1="I" g2="Iacute" k="66" />
+<hkern g1="I" g2="Icircumflex" k="73" />
+<hkern g1="I" g2="Idieresis" k="52" />
+<hkern g1="I" g2="dotlessi" k="51" />
+<hkern g1="J" g2="j" k="145" />
+<hkern g1="K" g2="C" k="194" />
+<hkern g1="K" g2="G" k="207" />
+<hkern g1="K" g2="O" k="177" />
+<hkern g1="K" g2="Q" k="177" />
+<hkern g1="K" g2="a" k="89" />
+<hkern g1="K" g2="c" k="81" />
+<hkern g1="K" g2="d" k="89" />
+<hkern g1="K" g2="e" k="83" />
+<hkern g1="K" g2="f" k="65" />
+<hkern g1="K" g2="j" k="180" />
+<hkern g1="K" g2="o" k="83" />
+<hkern g1="K" g2="q" k="83" />
+<hkern g1="K" g2="t" k="71" />
+<hkern g1="K" g2="v" k="117" />
+<hkern g1="K" g2="w" k="181" />
+<hkern g1="K" g2="y" k="71" />
+<hkern g1="K" g2="Ccedilla" k="105" />
+<hkern g1="K" g2="Ograve" k="177" />
+<hkern g1="K" g2="Oacute" k="177" />
+<hkern g1="K" g2="Ocircumflex" k="177" />
+<hkern g1="K" g2="Otilde" k="177" />
+<hkern g1="K" g2="Odieresis" k="177" />
+<hkern g1="K" g2="agrave" k="101" />
+<hkern g1="K" g2="aacute" k="83" />
+<hkern g1="K" g2="acircumflex" k="76" />
+<hkern g1="K" g2="atilde" k="70" />
+<hkern g1="K" g2="adieresis" k="83" />
+<hkern g1="K" g2="aring" k="76" />
+<hkern g1="K" g2="ae" k="95" />
+<hkern g1="K" g2="ccedilla" k="87" />
+<hkern g1="K" g2="egrave" k="76" />
+<hkern g1="K" g2="eacute" k="76" />
+<hkern g1="K" g2="ecircumflex" k="95" />
+<hkern g1="K" g2="edieresis" k="95" />
+<hkern g1="K" g2="eth" k="85" />
+<hkern g1="K" g2="ograve" k="76" />
+<hkern g1="K" g2="oacute" k="89" />
+<hkern g1="K" g2="ocircumflex" k="83" />
+<hkern g1="K" g2="otilde" k="76" />
+<hkern g1="K" g2="odieresis" k="95" />
+<hkern g1="K" g2="yacute" k="143" />
+<hkern g1="K" g2="ydieresis" k="158" />
+<hkern g1="L" g2="C" k="166" />
+<hkern g1="L" g2="G" k="151" />
+<hkern g1="L" g2="O" k="166" />
+<hkern g1="L" g2="Q" k="143" />
+<hkern g1="L" g2="T" k="316" />
+<hkern g1="L" g2="U" k="79" />
+<hkern g1="L" g2="V" k="277" />
+<hkern g1="L" g2="W" k="229" />
+<hkern g1="L" g2="Y" k="309" />
+<hkern g1="L" g2="a" k="51" />
+<hkern g1="L" g2="b" k="51" />
+<hkern g1="L" g2="c" k="81" />
+<hkern g1="L" g2="d" k="51" />
+<hkern g1="L" g2="e" k="51" />
+<hkern g1="L" g2="f" k="46" />
+<hkern g1="L" g2="j" k="221" />
+<hkern g1="L" g2="o" k="51" />
+<hkern g1="L" g2="q" k="51" />
+<hkern g1="L" g2="t" k="109" />
+<hkern g1="L" g2="v" k="238" />
+<hkern g1="L" g2="w" k="181" />
+<hkern g1="L" g2="y" k="145" />
+<hkern g1="L" g2="Ccedilla" k="141" />
+<hkern g1="L" g2="Ograve" k="166" />
+<hkern g1="L" g2="Oacute" k="158" />
+<hkern g1="L" g2="Ocircumflex" k="182" />
+<hkern g1="L" g2="Otilde" k="151" />
+<hkern g1="L" g2="Odieresis" k="189" />
+<hkern g1="L" g2="Ugrave" k="79" />
+<hkern g1="L" g2="Uacute" k="79" />
+<hkern g1="L" g2="Ucircumflex" k="79" />
+<hkern g1="L" g2="Udieresis" k="79" />
+<hkern g1="L" g2="Yacute" k="277" />
+<hkern g1="L" g2="agrave" k="51" />
+<hkern g1="L" g2="aacute" k="51" />
+<hkern g1="L" g2="acircumflex" k="51" />
+<hkern g1="L" g2="atilde" k="51" />
+<hkern g1="L" g2="adieresis" k="51" />
+<hkern g1="L" g2="aring" k="51" />
+<hkern g1="L" g2="ae" k="63" />
+<hkern g1="L" g2="ccedilla" k="81" />
+<hkern g1="L" g2="egrave" k="51" />
+<hkern g1="L" g2="eacute" k="51" />
+<hkern g1="L" g2="ecircumflex" k="51" />
+<hkern g1="L" g2="edieresis" k="51" />
+<hkern g1="L" g2="eth" k="41" />
+<hkern g1="L" g2="ograve" k="51" />
+<hkern g1="L" g2="oacute" k="51" />
+<hkern g1="L" g2="ocircumflex" k="51" />
+<hkern g1="L" g2="otilde" k="51" />
+<hkern g1="L" g2="odieresis" k="51" />
+<hkern g1="L" g2="yacute" k="131" />
+<hkern g1="L" g2="ydieresis" k="154" />
+<hkern g1="M" g2="j" k="189" />
+<hkern g1="N" g2="j" k="177" />
+<hkern g1="O" g2="A" k="131" />
+<hkern g1="O" g2="S" k="65" />
+<hkern g1="O" g2="T" k="106" />
+<hkern g1="O" g2="V" k="131" />
+<hkern g1="O" g2="W" k="73" />
+<hkern g1="O" g2="X" k="224" />
+<hkern g1="O" g2="Y" k="224" />
+<hkern g1="O" g2="Z" k="225" />
+<hkern g1="O" g2="j" k="255" />
+<hkern g1="O" g2="Agrave" k="131" />
+<hkern g1="O" g2="Aacute" k="131" />
+<hkern g1="O" g2="Acircumflex" k="131" />
+<hkern g1="O" g2="Atilde" k="131" />
+<hkern g1="O" g2="Adieresis" k="131" />
+<hkern g1="O" g2="Aring" k="131" />
+<hkern g1="O" g2="AE" k="165" />
+<hkern g1="O" g2="Yacute" k="224" />
+<hkern g1="P" g2="A" k="226" />
+<hkern g1="P" g2="J" k="176" />
+<hkern g1="P" g2="T" k="55" />
+<hkern g1="P" g2="X" k="54" />
+<hkern g1="P" g2="Y" k="54" />
+<hkern g1="P" g2="Z" k="55" />
+<hkern g1="P" g2="j" k="243" />
+<hkern g1="P" g2="Agrave" k="195" />
+<hkern g1="P" g2="Aacute" k="242" />
+<hkern g1="P" g2="Acircumflex" k="250" />
+<hkern g1="P" g2="Atilde" k="211" />
+<hkern g1="P" g2="Adieresis" k="203" />
+<hkern g1="P" g2="Aring" k="234" />
+<hkern g1="P" g2="AE" k="321" />
+<hkern g1="P" g2="Yacute" k="54" />
+<hkern g1="Q" g2="T" k="139" />
+<hkern g1="Q" g2="V" k="131" />
+<hkern g1="Q" g2="W" k="73" />
+<hkern g1="Q" g2="Y" k="224" />
+<hkern g1="Q" g2="j" k="163" />
+<hkern g1="Q" g2="Yacute" k="224" />
+<hkern g1="R" g2="J" k="95" />
+<hkern g1="R" g2="T" k="111" />
+<hkern g1="R" g2="V" k="80" />
+<hkern g1="R" g2="Y" k="110" />
+<hkern g1="R" g2="a" k="101" />
+<hkern g1="R" g2="c" k="106" />
+<hkern g1="R" g2="d" k="89" />
+<hkern g1="R" g2="e" k="95" />
+<hkern g1="R" g2="j" k="150" />
+<hkern g1="R" g2="o" k="89" />
+<hkern g1="R" g2="q" k="76" />
+<hkern g1="R" g2="Yacute" k="110" />
+<hkern g1="R" g2="agrave" k="83" />
+<hkern g1="R" g2="aacute" k="89" />
+<hkern g1="R" g2="acircumflex" k="76" />
+<hkern g1="R" g2="atilde" k="76" />
+<hkern g1="R" g2="adieresis" k="76" />
+<hkern g1="R" g2="aring" k="76" />
+<hkern g1="R" g2="ae" k="82" />
+<hkern g1="R" g2="ccedilla" k="81" />
+<hkern g1="R" g2="egrave" k="83" />
+<hkern g1="R" g2="eacute" k="95" />
+<hkern g1="R" g2="ecircumflex" k="89" />
+<hkern g1="R" g2="edieresis" k="83" />
+<hkern g1="R" g2="eth" k="73" />
+<hkern g1="R" g2="ograve" k="95" />
+<hkern g1="R" g2="oacute" k="95" />
+<hkern g1="R" g2="ocircumflex" k="83" />
+<hkern g1="R" g2="otilde" k="70" />
+<hkern g1="R" g2="odieresis" k="76" />
+<hkern g1="S" g2="j" k="179" />
+<hkern g1="S" g2="y" k="68" />
+<hkern g1="S" g2="yacute" k="68" />
+<hkern g1="S" g2="ydieresis" k="68" />
+<hkern g1="T" g2="A" k="324" />
+<hkern g1="T" g2="C" k="190" />
+<hkern g1="T" g2="G" k="159" />
+<hkern g1="T" g2="J" k="269" />
+<hkern g1="T" g2="O" k="128" />
+<hkern g1="T" g2="Q" k="167" />
+<hkern g1="T" g2="S" k="46" />
+<hkern g1="T" g2="a" k="277" />
+<hkern g1="T" g2="c" k="308" />
+<hkern g1="T" g2="d" k="238" />
+<hkern g1="T" g2="e" k="285" />
+<hkern g1="T" g2="f" k="190" />
+<hkern g1="T" g2="g" k="243" />
+<hkern g1="T" g2="j" k="270" />
+<hkern g1="T" g2="m" k="204" />
+<hkern g1="T" g2="n" k="182" />
+<hkern g1="T" g2="o" k="238" />
+<hkern g1="T" g2="p" k="244" />
+<hkern g1="T" g2="q" k="258" />
+<hkern g1="T" g2="r" k="95" />
+<hkern g1="T" g2="s" k="137" />
+<hkern g1="T" g2="t" k="47" />
+<hkern g1="T" g2="u" k="114" />
+<hkern g1="T" g2="v" k="152" />
+<hkern g1="T" g2="w" k="114" />
+<hkern g1="T" g2="x" k="137" />
+<hkern g1="T" g2="y" k="146" />
+<hkern g1="T" g2="z" k="90" />
+<hkern g1="T" g2="Agrave" k="168" />
+<hkern g1="T" g2="Aacute" k="152" />
+<hkern g1="T" g2="Acircumflex" k="160" />
+<hkern g1="T" g2="Atilde" k="191" />
+<hkern g1="T" g2="Adieresis" k="176" />
+<hkern g1="T" g2="Aring" k="191" />
+<hkern g1="T" g2="AE" k="277" />
+<hkern g1="T" g2="Ccedilla" k="94" />
+<hkern g1="T" g2="Ograve" k="151" />
+<hkern g1="T" g2="Oacute" k="174" />
+<hkern g1="T" g2="Ocircumflex" k="151" />
+<hkern g1="T" g2="Otilde" k="159" />
+<hkern g1="T" g2="Odieresis" k="174" />
+<hkern g1="T" g2="Oslash" k="174" />
+<hkern g1="T" g2="agrave" k="214" />
+<hkern g1="T" g2="aacute" k="238" />
+<hkern g1="T" g2="acircumflex" k="175" />
+<hkern g1="T" g2="atilde" k="147" />
+<hkern g1="T" g2="adieresis" k="238" />
+<hkern g1="T" g2="aring" k="112" />
+<hkern g1="T" g2="ae" k="277" />
+<hkern g1="T" g2="ccedilla" k="278" />
+<hkern g1="T" g2="egrave" k="214" />
+<hkern g1="T" g2="eacute" k="238" />
+<hkern g1="T" g2="ecircumflex" k="175" />
+<hkern g1="T" g2="edieresis" k="238" />
+<hkern g1="T" g2="idieresis" k="17" />
+<hkern g1="T" g2="eth" k="175" />
+<hkern g1="T" g2="ograve" k="175" />
+<hkern g1="T" g2="oacute" k="160" />
+<hkern g1="T" g2="ocircumflex" k="175" />
+<hkern g1="T" g2="otilde" k="52" />
+<hkern g1="T" g2="odieresis" k="152" />
+<hkern g1="T" g2="oslash" k="152" />
+<hkern g1="T" g2="ugrave" k="82" />
+<hkern g1="T" g2="uacute" k="145" />
+<hkern g1="T" g2="ucircumflex" k="175" />
+<hkern g1="T" g2="udieresis" k="121" />
+<hkern g1="T" g2="yacute" k="171" />
+<hkern g1="T" g2="ydieresis" k="162" />
+<hkern g1="T" g2="dotlessi" k="288" />
+<hkern g1="U" g2="j" k="187" />
+<hkern g1="V" g2="A" k="232" />
+<hkern g1="V" g2="C" k="98" />
+<hkern g1="V" g2="G" k="98" />
+<hkern g1="V" g2="J" k="214" />
+<hkern g1="V" g2="O" k="69" />
+<hkern g1="V" g2="Q" k="69" />
+<hkern g1="V" g2="S" k="63" />
+<hkern g1="V" g2="a" k="195" />
+<hkern g1="V" g2="c" k="224" />
+<hkern g1="V" g2="d" k="195" />
+<hkern g1="V" g2="e" k="195" />
+<hkern g1="V" g2="f" k="95" />
+<hkern g1="V" g2="g" k="195" />
+<hkern g1="V" g2="j" k="270" />
+<hkern g1="V" g2="m" k="75" />
+<hkern g1="V" g2="o" k="195" />
+<hkern g1="V" g2="p" k="195" />
+<hkern g1="V" g2="q" k="195" />
+<hkern g1="V" g2="r" k="65" />
+<hkern g1="V" g2="s" k="160" />
+<hkern g1="V" g2="t" k="64" />
+<hkern g1="V" g2="w" k="73" />
+<hkern g1="V" g2="x" k="67" />
+<hkern g1="V" g2="y" k="67" />
+<hkern g1="V" g2="z" k="67" />
+<hkern g1="V" g2="Agrave" k="232" />
+<hkern g1="V" g2="Aacute" k="232" />
+<hkern g1="V" g2="Acircumflex" k="232" />
+<hkern g1="V" g2="Atilde" k="232" />
+<hkern g1="V" g2="Adieresis" k="232" />
+<hkern g1="V" g2="Aring" k="232" />
+<hkern g1="V" g2="AE" k="239" />
+<hkern g1="V" g2="Ccedilla" k="98" />
+<hkern g1="V" g2="Eth" k="52" />
+<hkern g1="V" g2="Ograve" k="69" />
+<hkern g1="V" g2="Oacute" k="69" />
+<hkern g1="V" g2="Ocircumflex" k="69" />
+<hkern g1="V" g2="Otilde" k="69" />
+<hkern g1="V" g2="Odieresis" k="69" />
+<hkern g1="V" g2="Oslash" k="69" />
+<hkern g1="V" g2="agrave" k="195" />
+<hkern g1="V" g2="aacute" k="195" />
+<hkern g1="V" g2="acircumflex" k="163" />
+<hkern g1="V" g2="adieresis" k="132" />
+<hkern g1="V" g2="aring" k="195" />
+<hkern g1="V" g2="ae" k="207" />
+<hkern g1="V" g2="ccedilla" k="130" />
+<hkern g1="V" g2="egrave" k="195" />
+<hkern g1="V" g2="eacute" k="195" />
+<hkern g1="V" g2="ecircumflex" k="163" />
+<hkern g1="V" g2="edieresis" k="132" />
+<hkern g1="V" g2="eth" k="216" />
+<hkern g1="V" g2="ograve" k="195" />
+<hkern g1="V" g2="oacute" k="195" />
+<hkern g1="V" g2="ocircumflex" k="163" />
+<hkern g1="V" g2="odieresis" k="132" />
+<hkern g1="V" g2="oslash" k="195" />
+<hkern g1="V" g2="yacute" k="67" />
+<hkern g1="V" g2="ydieresis" k="67" />
+<hkern g1="V" g2="dotlessi" k="135" />
+<hkern g1="W" g2="A" k="151" />
+<hkern g1="W" g2="C" k="101" />
+<hkern g1="W" g2="G" k="101" />
+<hkern g1="W" g2="J" k="191" />
+<hkern g1="W" g2="O" k="71" />
+<hkern g1="W" g2="Q" k="71" />
+<hkern g1="W" g2="S" k="65" />
+<hkern g1="W" g2="a" k="134" />
+<hkern g1="W" g2="c" k="164" />
+<hkern g1="W" g2="d" k="134" />
+<hkern g1="W" g2="e" k="134" />
+<hkern g1="W" g2="f" k="66" />
+<hkern g1="W" g2="g" k="134" />
+<hkern g1="W" g2="j" k="222" />
+<hkern g1="W" g2="m" k="46" />
+<hkern g1="W" g2="o" k="134" />
+<hkern g1="W" g2="p" k="134" />
+<hkern g1="W" g2="q" k="134" />
+<hkern g1="W" g2="r" k="67" />
+<hkern g1="W" g2="s" k="131" />
+<hkern g1="W" g2="t" k="66" />
+<hkern g1="W" g2="w" k="44" />
+<hkern g1="W" g2="x" k="69" />
+<hkern g1="W" g2="y" k="69" />
+<hkern g1="W" g2="z" k="69" />
+<hkern g1="W" g2="Agrave" k="159" />
+<hkern g1="W" g2="Aacute" k="159" />
+<hkern g1="W" g2="Acircumflex" k="183" />
+<hkern g1="W" g2="Atilde" k="159" />
+<hkern g1="W" g2="Adieresis" k="136" />
+<hkern g1="W" g2="Aring" k="190" />
+<hkern g1="W" g2="AE" k="167" />
+<hkern g1="W" g2="Ccedilla" k="101" />
+<hkern g1="W" g2="Ograve" k="71" />
+<hkern g1="W" g2="Oacute" k="71" />
+<hkern g1="W" g2="Ocircumflex" k="71" />
+<hkern g1="W" g2="Otilde" k="71" />
+<hkern g1="W" g2="Odieresis" k="71" />
+<hkern g1="W" g2="Oslash" k="71" />
+<hkern g1="W" g2="agrave" k="134" />
+<hkern g1="W" g2="aacute" k="134" />
+<hkern g1="W" g2="acircumflex" k="134" />
+<hkern g1="W" g2="atilde" k="71" />
+<hkern g1="W" g2="adieresis" k="134" />
+<hkern g1="W" g2="aring" k="134" />
+<hkern g1="W" g2="ae" k="178" />
+<hkern g1="W" g2="ccedilla" k="164" />
+<hkern g1="W" g2="egrave" k="134" />
+<hkern g1="W" g2="eacute" k="134" />
+<hkern g1="W" g2="ecircumflex" k="134" />
+<hkern g1="W" g2="edieresis" k="134" />
+<hkern g1="W" g2="eth" k="156" />
+<hkern g1="W" g2="ograve" k="134" />
+<hkern g1="W" g2="oacute" k="134" />
+<hkern g1="W" g2="ocircumflex" k="134" />
+<hkern g1="W" g2="otilde" k="71" />
+<hkern g1="W" g2="odieresis" k="134" />
+<hkern g1="W" g2="oslash" k="134" />
+<hkern g1="W" g2="yacute" k="69" />
+<hkern g1="W" g2="ydieresis" k="69" />
+<hkern g1="W" g2="dotlessi" k="106" />
+<hkern g1="X" g2="C" k="194" />
+<hkern g1="X" g2="G" k="140" />
+<hkern g1="X" g2="O" k="164" />
+<hkern g1="X" g2="Q" k="164" />
+<hkern g1="X" g2="c" k="68" />
+<hkern g1="X" g2="f" k="65" />
+<hkern g1="X" g2="j" k="133" />
+<hkern g1="X" g2="t" k="65" />
+<hkern g1="X" g2="v" k="163" />
+<hkern g1="X" g2="w" k="200" />
+<hkern g1="X" g2="y" k="103" />
+<hkern g1="X" g2="Ccedilla" k="114" />
+<hkern g1="X" g2="Eth" k="53" />
+<hkern g1="X" g2="Ograve" k="109" />
+<hkern g1="X" g2="Oacute" k="164" />
+<hkern g1="X" g2="Ocircumflex" k="109" />
+<hkern g1="X" g2="Otilde" k="109" />
+<hkern g1="X" g2="Odieresis" k="164" />
+<hkern g1="X" g2="ae" k="82" />
+<hkern g1="X" g2="ccedilla" k="68" />
+<hkern g1="X" g2="eth" k="60" />
+<hkern g1="X" g2="yacute" k="128" />
+<hkern g1="X" g2="ydieresis" k="111" />
+<hkern g1="Y" g2="A" k="240" />
+<hkern g1="Y" g2="C" k="160" />
+<hkern g1="Y" g2="G" k="160" />
+<hkern g1="Y" g2="J" k="193" />
+<hkern g1="Y" g2="O" k="130" />
+<hkern g1="Y" g2="Q" k="130" />
+<hkern g1="Y" g2="S" k="61" />
+<hkern g1="Y" g2="a" k="170" />
+<hkern g1="Y" g2="c" k="162" />
+<hkern g1="Y" g2="d" k="162" />
+<hkern g1="Y" g2="e" k="162" />
+<hkern g1="Y" g2="f" k="157" />
+<hkern g1="Y" g2="g" k="167" />
+<hkern g1="Y" g2="j" k="201" />
+<hkern g1="Y" g2="m" k="168" />
+<hkern g1="Y" g2="n" k="129" />
+<hkern g1="Y" g2="o" k="193" />
+<hkern g1="Y" g2="p" k="168" />
+<hkern g1="Y" g2="q" k="182" />
+<hkern g1="Y" g2="r" k="158" />
+<hkern g1="Y" g2="s" k="131" />
+<hkern g1="Y" g2="t" k="62" />
+<hkern g1="Y" g2="u" k="129" />
+<hkern g1="Y" g2="v" k="129" />
+<hkern g1="Y" g2="w" k="166" />
+<hkern g1="Y" g2="x" k="160" />
+<hkern g1="Y" g2="y" k="160" />
+<hkern g1="Y" g2="z" k="160" />
+<hkern g1="Y" g2="Agrave" k="193" />
+<hkern g1="Y" g2="Aacute" k="162" />
+<hkern g1="Y" g2="Acircumflex" k="162" />
+<hkern g1="Y" g2="Atilde" k="162" />
+<hkern g1="Y" g2="Adieresis" k="162" />
+<hkern g1="Y" g2="Aring" k="162" />
+<hkern g1="Y" g2="AE" k="162" />
+<hkern g1="Y" g2="Ccedilla" k="160" />
+<hkern g1="Y" g2="Eth" k="50" />
+<hkern g1="Y" g2="Ograve" k="130" />
+<hkern g1="Y" g2="Oacute" k="130" />
+<hkern g1="Y" g2="Ocircumflex" k="130" />
+<hkern g1="Y" g2="Otilde" k="130" />
+<hkern g1="Y" g2="Odieresis" k="130" />
+<hkern g1="Y" g2="Oslash" k="130" />
+<hkern g1="Y" g2="agrave" k="162" />
+<hkern g1="Y" g2="aacute" k="162" />
+<hkern g1="Y" g2="acircumflex" k="131" />
+<hkern g1="Y" g2="atilde" k="67" />
+<hkern g1="Y" g2="adieresis" k="131" />
+<hkern g1="Y" g2="aring" k="99" />
+<hkern g1="Y" g2="ae" k="162" />
+<hkern g1="Y" g2="ccedilla" k="171" />
+<hkern g1="Y" g2="egrave" k="162" />
+<hkern g1="Y" g2="eacute" k="162" />
+<hkern g1="Y" g2="ecircumflex" k="131" />
+<hkern g1="Y" g2="edieresis" k="131" />
+<hkern g1="Y" g2="eth" k="162" />
+<hkern g1="Y" g2="ograve" k="162" />
+<hkern g1="Y" g2="oacute" k="162" />
+<hkern g1="Y" g2="ocircumflex" k="131" />
+<hkern g1="Y" g2="otilde" k="67" />
+<hkern g1="Y" g2="odieresis" k="131" />
+<hkern g1="Y" g2="oslash" k="162" />
+<hkern g1="Y" g2="ugrave" k="129" />
+<hkern g1="Y" g2="uacute" k="129" />
+<hkern g1="Y" g2="ucircumflex" k="129" />
+<hkern g1="Y" g2="udieresis" k="98" />
+<hkern g1="Y" g2="yacute" k="160" />
+<hkern g1="Y" g2="ydieresis" k="97" />
+<hkern g1="Y" g2="dotlessi" k="228" />
+<hkern g1="Z" g2="C" k="193" />
+<hkern g1="Z" g2="G" k="193" />
+<hkern g1="Z" g2="O" k="163" />
+<hkern g1="Z" g2="Q" k="163" />
+<hkern g1="Z" g2="a" k="69" />
+<hkern g1="Z" g2="c" k="98" />
+<hkern g1="Z" g2="d" k="69" />
+<hkern g1="Z" g2="e" k="69" />
+<hkern g1="Z" g2="f" k="64" />
+<hkern g1="Z" g2="j" k="115" />
+<hkern g1="Z" g2="o" k="69" />
+<hkern g1="Z" g2="q" k="69" />
+<hkern g1="Z" g2="t" k="64" />
+<hkern g1="Z" g2="v" k="162" />
+<hkern g1="Z" g2="w" k="199" />
+<hkern g1="Z" g2="y" k="193" />
+<hkern g1="Z" g2="Ccedilla" k="193" />
+<hkern g1="Z" g2="Eth" k="52" />
+<hkern g1="Z" g2="Ograve" k="163" />
+<hkern g1="Z" g2="Oacute" k="163" />
+<hkern g1="Z" g2="Ocircumflex" k="163" />
+<hkern g1="Z" g2="Otilde" k="163" />
+<hkern g1="Z" g2="Odieresis" k="163" />
+<hkern g1="Z" g2="agrave" k="69" />
+<hkern g1="Z" g2="aacute" k="69" />
+<hkern g1="Z" g2="acircumflex" k="69" />
+<hkern g1="Z" g2="adieresis" k="69" />
+<hkern g1="Z" g2="aring" k="69" />
+<hkern g1="Z" g2="ae" k="81" />
+<hkern g1="Z" g2="ccedilla" k="98" />
+<hkern g1="Z" g2="egrave" k="69" />
+<hkern g1="Z" g2="eacute" k="69" />
+<hkern g1="Z" g2="ecircumflex" k="69" />
+<hkern g1="Z" g2="edieresis" k="69" />
+<hkern g1="Z" g2="eth" k="59" />
+<hkern g1="Z" g2="ograve" k="69" />
+<hkern g1="Z" g2="oacute" k="69" />
+<hkern g1="Z" g2="ocircumflex" k="69" />
+<hkern g1="Z" g2="odieresis" k="69" />
+<hkern g1="Z" g2="yacute" k="193" />
+<hkern g1="Z" g2="ydieresis" k="67" />
+<hkern g1="underscore" g2="underscore" k="39" />
+<hkern g1="a" g2="T" k="353" />
+<hkern g1="a" g2="V" k="249" />
+<hkern g1="a" g2="W" k="160" />
+<hkern g1="a" g2="Y" k="306" />
+<hkern g1="a" g2="f" k="58" />
+<hkern g1="a" g2="j" k="259" />
+<hkern g1="a" g2="t" k="90" />
+<hkern g1="a" g2="v" k="62" />
+<hkern g1="a" g2="y" k="61" />
+<hkern g1="a" g2="Yacute" k="298" />
+<hkern g1="a" g2="icircumflex" k="58" />
+<hkern g1="a" g2="idieresis" k="65" />
+<hkern g1="a" g2="yacute" k="61" />
+<hkern g1="a" g2="ydieresis" k="61" />
+<hkern g1="b" g2="A" k="60" />
+<hkern g1="b" g2="T" k="279" />
+<hkern g1="b" g2="V" k="129" />
+<hkern g1="b" g2="W" k="160" />
+<hkern g1="b" g2="X" k="122" />
+<hkern g1="b" g2="Y" k="294" />
+<hkern g1="b" g2="Z" k="123" />
+<hkern g1="b" g2="f" k="58" />
+<hkern g1="b" g2="j" k="199" />
+<hkern g1="b" g2="t" k="90" />
+<hkern g1="b" g2="v" k="62" />
+<hkern g1="b" g2="x" k="93" />
+<hkern g1="b" g2="y" k="61" />
+<hkern g1="b" g2="z" k="93" />
+<hkern g1="b" g2="Agrave" k="60" />
+<hkern g1="b" g2="Aacute" k="60" />
+<hkern g1="b" g2="Acircumflex" k="60" />
+<hkern g1="b" g2="Atilde" k="60" />
+<hkern g1="b" g2="Adieresis" k="60" />
+<hkern g1="b" g2="Aring" k="60" />
+<hkern g1="b" g2="AE" k="63" />
+<hkern g1="b" g2="Yacute" k="256" />
+<hkern g1="b" g2="icircumflex" k="58" />
+<hkern g1="b" g2="idieresis" k="65" />
+<hkern g1="b" g2="yacute" k="61" />
+<hkern g1="b" g2="ydieresis" k="61" />
+<hkern g1="c" g2="T" k="281" />
+<hkern g1="c" g2="V" k="123" />
+<hkern g1="c" g2="Y" k="148" />
+<hkern g1="c" g2="j" k="172" />
+<hkern g1="c" g2="Yacute" k="148" />
+<hkern g1="d" g2="A" k="60" />
+<hkern g1="d" g2="j" k="154" />
+<hkern g1="d" g2="Agrave" k="60" />
+<hkern g1="d" g2="Aacute" k="60" />
+<hkern g1="d" g2="Acircumflex" k="60" />
+<hkern g1="d" g2="Atilde" k="60" />
+<hkern g1="d" g2="Adieresis" k="60" />
+<hkern g1="d" g2="Aring" k="60" />
+<hkern g1="d" g2="AE" k="63" />
+<hkern g1="e" g2="A" k="92" />
+<hkern g1="e" g2="T" k="316" />
+<hkern g1="e" g2="V" k="249" />
+<hkern g1="e" g2="W" k="160" />
+<hkern g1="e" g2="X" k="122" />
+<hkern g1="e" g2="Y" k="246" />
+<hkern g1="e" g2="Z" k="123" />
+<hkern g1="e" g2="f" k="58" />
+<hkern g1="e" g2="j" k="229" />
+<hkern g1="e" g2="t" k="90" />
+<hkern g1="e" g2="v" k="62" />
+<hkern g1="e" g2="x" k="93" />
+<hkern g1="e" g2="y" k="61" />
+<hkern g1="e" g2="z" k="93" />
+<hkern g1="e" g2="Agrave" k="92" />
+<hkern g1="e" g2="Aacute" k="92" />
+<hkern g1="e" g2="Acircumflex" k="92" />
+<hkern g1="e" g2="Atilde" k="92" />
+<hkern g1="e" g2="Adieresis" k="92" />
+<hkern g1="e" g2="Aring" k="92" />
+<hkern g1="e" g2="AE" k="95" />
+<hkern g1="e" g2="Yacute" k="215" />
+<hkern g1="e" g2="icircumflex" k="58" />
+<hkern g1="e" g2="idieresis" k="65" />
+<hkern g1="e" g2="yacute" k="61" />
+<hkern g1="e" g2="ydieresis" k="61" />
+<hkern g1="f" g2="A" k="124" />
+<hkern g1="f" g2="J" k="178" />
+<hkern g1="f" g2="j" k="242" />
+<hkern g1="f" g2="Agrave" k="124" />
+<hkern g1="f" g2="Aacute" k="77" />
+<hkern g1="f" g2="Acircumflex" k="77" />
+<hkern g1="f" g2="Atilde" k="77" />
+<hkern g1="f" g2="Adieresis" k="77" />
+<hkern g1="f" g2="Aring" k="77" />
+<hkern g1="f" g2="AE" k="139" />
+<hkern g1="g" g2="T" k="285" />
+<hkern g1="g" g2="V" k="249" />
+<hkern g1="g" g2="W" k="160" />
+<hkern g1="g" g2="Y" k="254" />
+<hkern g1="g" g2="f" k="58" />
+<hkern g1="g" g2="t" k="90" />
+<hkern g1="g" g2="v" k="62" />
+<hkern g1="g" g2="y" k="61" />
+<hkern g1="g" g2="Yacute" k="254" />
+<hkern g1="g" g2="icircumflex" k="58" />
+<hkern g1="g" g2="idieresis" k="65" />
+<hkern g1="g" g2="yacute" k="61" />
+<hkern g1="g" g2="ydieresis" k="61" />
+<hkern g1="h" g2="T" k="308" />
+<hkern g1="h" g2="V" k="233" />
+<hkern g1="h" g2="W" k="144" />
+<hkern g1="h" g2="Y" k="261" />
+<hkern g1="h" g2="f" k="42" />
+<hkern g1="h" g2="j" k="198" />
+<hkern g1="h" g2="t" k="74" />
+<hkern g1="h" g2="v" k="46" />
+<hkern g1="h" g2="y" k="45" />
+<hkern g1="h" g2="Yacute" k="261" />
+<hkern g1="h" g2="icircumflex" k="42" />
+<hkern g1="h" g2="idieresis" k="49" />
+<hkern g1="h" g2="yacute" k="45" />
+<hkern g1="h" g2="ydieresis" k="45" />
+<hkern g1="i" g2="j" k="171" />
+<hkern g1="k" g2="T" k="251" />
+<hkern g1="k" g2="V" k="91" />
+<hkern g1="k" g2="Y" k="185" />
+<hkern g1="k" g2="a" k="63" />
+<hkern g1="k" g2="c" k="92" />
+<hkern g1="k" g2="d" k="63" />
+<hkern g1="k" g2="e" k="63" />
+<hkern g1="k" g2="j" k="156" />
+<hkern g1="k" g2="o" k="63" />
+<hkern g1="k" g2="q" k="63" />
+<hkern g1="k" g2="Yacute" k="185" />
+<hkern g1="k" g2="agrave" k="63" />
+<hkern g1="k" g2="aacute" k="63" />
+<hkern g1="k" g2="acircumflex" k="63" />
+<hkern g1="k" g2="atilde" k="63" />
+<hkern g1="k" g2="adieresis" k="63" />
+<hkern g1="k" g2="aring" k="63" />
+<hkern g1="k" g2="ae" k="75" />
+<hkern g1="k" g2="ccedilla" k="92" />
+<hkern g1="k" g2="egrave" k="63" />
+<hkern g1="k" g2="eacute" k="63" />
+<hkern g1="k" g2="ecircumflex" k="63" />
+<hkern g1="k" g2="edieresis" k="63" />
+<hkern g1="k" g2="eth" k="53" />
+<hkern g1="k" g2="ograve" k="63" />
+<hkern g1="k" g2="oacute" k="63" />
+<hkern g1="k" g2="ocircumflex" k="63" />
+<hkern g1="k" g2="otilde" k="63" />
+<hkern g1="k" g2="odieresis" k="63" />
+<hkern g1="l" g2="j" k="153" />
+<hkern g1="l" g2="ae" k="41" />
+<hkern g1="m" g2="T" k="260" />
+<hkern g1="m" g2="V" k="219" />
+<hkern g1="m" g2="W" k="130" />
+<hkern g1="m" g2="Y" k="221" />
+<hkern g1="m" g2="j" k="166" />
+<hkern g1="m" g2="t" k="60" />
+<hkern g1="m" g2="y" k="63" />
+<hkern g1="m" g2="Yacute" k="229" />
+<hkern g1="m" g2="icircumflex" k="60" />
+<hkern g1="m" g2="idieresis" k="67" />
+<hkern g1="m" g2="yacute" k="63" />
+<hkern g1="m" g2="ydieresis" k="63" />
+<hkern g1="n" g2="T" k="221" />
+<hkern g1="n" g2="V" k="233" />
+<hkern g1="n" g2="W" k="144" />
+<hkern g1="n" g2="Y" k="190" />
+<hkern g1="n" g2="f" k="42" />
+<hkern g1="n" g2="j" k="126" />
+<hkern g1="n" g2="t" k="74" />
+<hkern g1="n" g2="v" k="46" />
+<hkern g1="n" g2="y" k="45" />
+<hkern g1="n" g2="Yacute" k="221" />
+<hkern g1="n" g2="icircumflex" k="42" />
+<hkern g1="n" g2="idieresis" k="49" />
+<hkern g1="n" g2="yacute" k="45" />
+<hkern g1="n" g2="ydieresis" k="45" />
+<hkern g1="o" g2="A" k="60" />
+<hkern g1="o" g2="T" k="256" />
+<hkern g1="o" g2="V" k="249" />
+<hkern g1="o" g2="W" k="160" />
+<hkern g1="o" g2="X" k="122" />
+<hkern g1="o" g2="Y" k="225" />
+<hkern g1="o" g2="Z" k="123" />
+<hkern g1="o" g2="f" k="58" />
+<hkern g1="o" g2="j" k="201" />
+<hkern g1="o" g2="t" k="90" />
+<hkern g1="o" g2="v" k="62" />
+<hkern g1="o" g2="x" k="93" />
+<hkern g1="o" g2="y" k="61" />
+<hkern g1="o" g2="z" k="93" />
+<hkern g1="o" g2="Agrave" k="60" />
+<hkern g1="o" g2="Aacute" k="60" />
+<hkern g1="o" g2="Acircumflex" k="60" />
+<hkern g1="o" g2="Atilde" k="60" />
+<hkern g1="o" g2="Adieresis" k="60" />
+<hkern g1="o" g2="Aring" k="60" />
+<hkern g1="o" g2="AE" k="63" />
+<hkern g1="o" g2="Yacute" k="225" />
+<hkern g1="o" g2="icircumflex" k="58" />
+<hkern g1="o" g2="idieresis" k="65" />
+<hkern g1="o" g2="yacute" k="61" />
+<hkern g1="o" g2="ydieresis" k="61" />
+<hkern g1="p" g2="A" k="60" />
+<hkern g1="p" g2="T" k="297" />
+<hkern g1="p" g2="V" k="249" />
+<hkern g1="p" g2="W" k="160" />
+<hkern g1="p" g2="X" k="122" />
+<hkern g1="p" g2="Y" k="227" />
+<hkern g1="p" g2="Z" k="123" />
+<hkern g1="p" g2="f" k="58" />
+<hkern g1="p" g2="j" k="180" />
+<hkern g1="p" g2="t" k="90" />
+<hkern g1="p" g2="v" k="62" />
+<hkern g1="p" g2="x" k="93" />
+<hkern g1="p" g2="y" k="61" />
+<hkern g1="p" g2="z" k="93" />
+<hkern g1="p" g2="Agrave" k="60" />
+<hkern g1="p" g2="Aacute" k="60" />
+<hkern g1="p" g2="Acircumflex" k="60" />
+<hkern g1="p" g2="Atilde" k="60" />
+<hkern g1="p" g2="Adieresis" k="60" />
+<hkern g1="p" g2="Aring" k="60" />
+<hkern g1="p" g2="AE" k="63" />
+<hkern g1="p" g2="Yacute" k="227" />
+<hkern g1="p" g2="icircumflex" k="58" />
+<hkern g1="p" g2="idieresis" k="65" />
+<hkern g1="p" g2="yacute" k="61" />
+<hkern g1="p" g2="ydieresis" k="61" />
+<hkern g1="q" g2="T" k="263" />
+<hkern g1="q" g2="V" k="120" />
+<hkern g1="q" g2="W" k="160" />
+<hkern g1="q" g2="Y" k="247" />
+<hkern g1="q" g2="f" k="58" />
+<hkern g1="q" g2="t" k="90" />
+<hkern g1="q" g2="v" k="62" />
+<hkern g1="q" g2="y" k="61" />
+<hkern g1="q" g2="Yacute" k="247" />
+<hkern g1="q" g2="icircumflex" k="58" />
+<hkern g1="q" g2="idieresis" k="65" />
+<hkern g1="q" g2="yacute" k="61" />
+<hkern g1="q" g2="ydieresis" k="61" />
+<hkern g1="r" g2="A" k="185" />
+<hkern g1="r" g2="J" k="233" />
+<hkern g1="r" g2="T" k="224" />
+<hkern g1="r" g2="V" k="59" />
+<hkern g1="r" g2="X" k="216" />
+<hkern g1="r" g2="Y" k="153" />
+<hkern g1="r" g2="Z" k="201" />
+<hkern g1="r" g2="j" k="168" />
+<hkern g1="r" g2="Agrave" k="185" />
+<hkern g1="r" g2="Aacute" k="185" />
+<hkern g1="r" g2="Acircumflex" k="185" />
+<hkern g1="r" g2="Atilde" k="185" />
+<hkern g1="r" g2="Adieresis" k="185" />
+<hkern g1="r" g2="Aring" k="185" />
+<hkern g1="r" g2="AE" k="239" />
+<hkern g1="r" g2="Yacute" k="153" />
+<hkern g1="s" g2="T" k="233" />
+<hkern g1="s" g2="V" k="158" />
+<hkern g1="s" g2="W" k="69" />
+<hkern g1="s" g2="Y" k="256" />
+<hkern g1="s" g2="j" k="186" />
+<hkern g1="s" g2="Yacute" k="202" />
+<hkern g1="t" g2="T" k="184" />
+<hkern g1="t" g2="V" k="152" />
+<hkern g1="t" g2="W" k="63" />
+<hkern g1="t" g2="Y" k="183" />
+<hkern g1="t" g2="a" k="61" />
+<hkern g1="t" g2="c" k="90" />
+<hkern g1="t" g2="d" k="61" />
+<hkern g1="t" g2="e" k="61" />
+<hkern g1="t" g2="j" k="143" />
+<hkern g1="t" g2="o" k="61" />
+<hkern g1="t" g2="q" k="61" />
+<hkern g1="t" g2="Yacute" k="183" />
+<hkern g1="t" g2="agrave" k="61" />
+<hkern g1="t" g2="aacute" k="61" />
+<hkern g1="t" g2="acircumflex" k="61" />
+<hkern g1="t" g2="atilde" k="61" />
+<hkern g1="t" g2="adieresis" k="61" />
+<hkern g1="t" g2="aring" k="61" />
+<hkern g1="t" g2="ae" k="73" />
+<hkern g1="t" g2="ccedilla" k="90" />
+<hkern g1="t" g2="egrave" k="61" />
+<hkern g1="t" g2="eacute" k="61" />
+<hkern g1="t" g2="ecircumflex" k="61" />
+<hkern g1="t" g2="edieresis" k="61" />
+<hkern g1="t" g2="eth" k="51" />
+<hkern g1="t" g2="ograve" k="61" />
+<hkern g1="t" g2="oacute" k="61" />
+<hkern g1="t" g2="ocircumflex" k="61" />
+<hkern g1="t" g2="otilde" k="61" />
+<hkern g1="t" g2="odieresis" k="61" />
+<hkern g1="u" g2="T" k="248" />
+<hkern g1="u" g2="V" k="107" />
+<hkern g1="u" g2="W" k="49" />
+<hkern g1="u" g2="Y" k="201" />
+<hkern g1="u" g2="j" k="154" />
+<hkern g1="u" g2="Yacute" k="201" />
+<hkern g1="u" g2="icircumflex" k="42" />
+<hkern g1="u" g2="idieresis" k="49" />
+<hkern g1="v" g2="A" k="161" />
+<hkern g1="v" g2="J" k="167" />
+<hkern g1="v" g2="T" k="248" />
+<hkern g1="v" g2="V" k="107" />
+<hkern g1="v" g2="W" k="49" />
+<hkern g1="v" g2="X" k="232" />
+<hkern g1="v" g2="Y" k="201" />
+<hkern g1="v" g2="Z" k="240" />
+<hkern g1="v" g2="a" k="47" />
+<hkern g1="v" g2="c" k="77" />
+<hkern g1="v" g2="d" k="47" />
+<hkern g1="v" g2="e" k="47" />
+<hkern g1="v" g2="g" k="47" />
+<hkern g1="v" g2="j" k="216" />
+<hkern g1="v" g2="o" k="47" />
+<hkern g1="v" g2="p" k="47" />
+<hkern g1="v" g2="q" k="47" />
+<hkern g1="v" g2="Agrave" k="153" />
+<hkern g1="v" g2="Aacute" k="146" />
+<hkern g1="v" g2="Acircumflex" k="153" />
+<hkern g1="v" g2="Atilde" k="146" />
+<hkern g1="v" g2="Adieresis" k="161" />
+<hkern g1="v" g2="Aring" k="177" />
+<hkern g1="v" g2="AE" k="201" />
+<hkern g1="v" g2="Yacute" k="201" />
+<hkern g1="v" g2="agrave" k="47" />
+<hkern g1="v" g2="aacute" k="47" />
+<hkern g1="v" g2="acircumflex" k="47" />
+<hkern g1="v" g2="atilde" k="47" />
+<hkern g1="v" g2="adieresis" k="47" />
+<hkern g1="v" g2="aring" k="47" />
+<hkern g1="v" g2="ae" k="91" />
+<hkern g1="v" g2="ccedilla" k="77" />
+<hkern g1="v" g2="egrave" k="47" />
+<hkern g1="v" g2="eacute" k="47" />
+<hkern g1="v" g2="ecircumflex" k="47" />
+<hkern g1="v" g2="edieresis" k="47" />
+<hkern g1="v" g2="icircumflex" k="42" />
+<hkern g1="v" g2="idieresis" k="49" />
+<hkern g1="v" g2="eth" k="69" />
+<hkern g1="v" g2="ograve" k="47" />
+<hkern g1="v" g2="oacute" k="47" />
+<hkern g1="v" g2="ocircumflex" k="47" />
+<hkern g1="v" g2="otilde" k="47" />
+<hkern g1="v" g2="odieresis" k="47" />
+<hkern g1="v" g2="oslash" k="47" />
+<hkern g1="w" g2="A" k="250" />
+<hkern g1="w" g2="J" k="90" />
+<hkern g1="w" g2="T" k="330" />
+<hkern g1="w" g2="V" k="124" />
+<hkern g1="w" g2="X" k="218" />
+<hkern g1="w" g2="Y" k="133" />
+<hkern g1="w" g2="Z" k="219" />
+<hkern g1="w" g2="j" k="220" />
+<hkern g1="w" g2="Agrave" k="250" />
+<hkern g1="w" g2="Aacute" k="250" />
+<hkern g1="w" g2="Acircumflex" k="250" />
+<hkern g1="w" g2="Atilde" k="250" />
+<hkern g1="w" g2="Adieresis" k="250" />
+<hkern g1="w" g2="Aring" k="250" />
+<hkern g1="w" g2="AE" k="222" />
+<hkern g1="w" g2="Yacute" k="148" />
+<hkern g1="w" g2="ae" k="45" />
+<hkern g1="w" g2="icircumflex" k="59" />
+<hkern g1="w" g2="idieresis" k="66" />
+<hkern g1="x" g2="T" k="210" />
+<hkern g1="x" g2="V" k="91" />
+<hkern g1="x" g2="Y" k="185" />
+<hkern g1="x" g2="a" k="63" />
+<hkern g1="x" g2="c" k="92" />
+<hkern g1="x" g2="d" k="63" />
+<hkern g1="x" g2="e" k="63" />
+<hkern g1="x" g2="j" k="154" />
+<hkern g1="x" g2="o" k="63" />
+<hkern g1="x" g2="q" k="63" />
+<hkern g1="x" g2="Yacute" k="185" />
+<hkern g1="x" g2="agrave" k="63" />
+<hkern g1="x" g2="aacute" k="63" />
+<hkern g1="x" g2="acircumflex" k="63" />
+<hkern g1="x" g2="atilde" k="63" />
+<hkern g1="x" g2="adieresis" k="63" />
+<hkern g1="x" g2="aring" k="63" />
+<hkern g1="x" g2="ae" k="75" />
+<hkern g1="x" g2="ccedilla" k="92" />
+<hkern g1="x" g2="egrave" k="63" />
+<hkern g1="x" g2="eacute" k="63" />
+<hkern g1="x" g2="ecircumflex" k="63" />
+<hkern g1="x" g2="edieresis" k="63" />
+<hkern g1="x" g2="eth" k="53" />
+<hkern g1="x" g2="ograve" k="63" />
+<hkern g1="x" g2="oacute" k="63" />
+<hkern g1="x" g2="ocircumflex" k="63" />
+<hkern g1="x" g2="otilde" k="63" />
+<hkern g1="x" g2="odieresis" k="63" />
+<hkern g1="y" g2="A" k="125" />
+<hkern g1="y" g2="J" k="88" />
+<hkern g1="y" g2="T" k="306" />
+<hkern g1="y" g2="V" k="91" />
+<hkern g1="y" g2="X" k="78" />
+<hkern g1="y" g2="Y" k="94" />
+<hkern g1="y" g2="Z" k="118" />
+<hkern g1="y" g2="j" k="180" />
+<hkern g1="y" g2="Agrave" k="86" />
+<hkern g1="y" g2="Aacute" k="86" />
+<hkern g1="y" g2="Acircumflex" k="86" />
+<hkern g1="y" g2="Atilde" k="86" />
+<hkern g1="y" g2="Adieresis" k="86" />
+<hkern g1="y" g2="Aring" k="86" />
+<hkern g1="y" g2="AE" k="118" />
+<hkern g1="y" g2="Yacute" k="55" />
+<hkern g1="z" g2="T" k="299" />
+<hkern g1="z" g2="V" k="91" />
+<hkern g1="z" g2="Y" k="63" />
+<hkern g1="z" g2="a" k="63" />
+<hkern g1="z" g2="c" k="92" />
+<hkern g1="z" g2="d" k="63" />
+<hkern g1="z" g2="e" k="63" />
+<hkern g1="z" g2="j" k="180" />
+<hkern g1="z" g2="o" k="63" />
+<hkern g1="z" g2="q" k="63" />
+<hkern g1="z" g2="Yacute" k="149" />
+<hkern g1="z" g2="agrave" k="63" />
+<hkern g1="z" g2="aacute" k="63" />
+<hkern g1="z" g2="acircumflex" k="63" />
+<hkern g1="z" g2="atilde" k="63" />
+<hkern g1="z" g2="adieresis" k="63" />
+<hkern g1="z" g2="aring" k="63" />
+<hkern g1="z" g2="ae" k="75" />
+<hkern g1="z" g2="ccedilla" k="92" />
+<hkern g1="z" g2="egrave" k="63" />
+<hkern g1="z" g2="eacute" k="63" />
+<hkern g1="z" g2="ecircumflex" k="63" />
+<hkern g1="z" g2="edieresis" k="63" />
+<hkern g1="z" g2="eth" k="53" />
+<hkern g1="z" g2="ograve" k="63" />
+<hkern g1="z" g2="oacute" k="63" />
+<hkern g1="z" g2="ocircumflex" k="63" />
+<hkern g1="z" g2="otilde" k="63" />
+<hkern g1="z" g2="odieresis" k="63" />
+<hkern g1="Agrave" g2="C" k="98" />
+<hkern g1="Agrave" g2="G" k="98" />
+<hkern g1="Agrave" g2="O" k="69" />
+<hkern g1="Agrave" g2="Q" k="69" />
+<hkern g1="Agrave" g2="T" k="208" />
+<hkern g1="Agrave" g2="V" k="247" />
+<hkern g1="Agrave" g2="W" k="121" />
+<hkern g1="Agrave" g2="Y" k="247" />
+<hkern g1="Agrave" g2="f" k="64" />
+<hkern g1="Agrave" g2="j" k="200" />
+<hkern g1="Agrave" g2="t" k="95" />
+<hkern g1="Agrave" g2="v" k="137" />
+<hkern g1="Agrave" g2="w" k="199" />
+<hkern g1="Agrave" g2="y" k="256" />
+<hkern g1="Agrave" g2="Ccedilla" k="98" />
+<hkern g1="Agrave" g2="Eth" k="52" />
+<hkern g1="Agrave" g2="Ograve" k="69" />
+<hkern g1="Agrave" g2="Oacute" k="69" />
+<hkern g1="Agrave" g2="Ocircumflex" k="69" />
+<hkern g1="Agrave" g2="Otilde" k="69" />
+<hkern g1="Agrave" g2="Odieresis" k="69" />
+<hkern g1="Agrave" g2="Yacute" k="224" />
+<hkern g1="Agrave" g2="yacute" k="124" />
+<hkern g1="Agrave" g2="ydieresis" k="61" />
+<hkern g1="Aacute" g2="C" k="98" />
+<hkern g1="Aacute" g2="G" k="98" />
+<hkern g1="Aacute" g2="O" k="69" />
+<hkern g1="Aacute" g2="Q" k="69" />
+<hkern g1="Aacute" g2="T" k="247" />
+<hkern g1="Aacute" g2="V" k="200" />
+<hkern g1="Aacute" g2="W" k="159" />
+<hkern g1="Aacute" g2="Y" k="239" />
+<hkern g1="Aacute" g2="f" k="64" />
+<hkern g1="Aacute" g2="j" k="207" />
+<hkern g1="Aacute" g2="t" k="95" />
+<hkern g1="Aacute" g2="v" k="225" />
+<hkern g1="Aacute" g2="w" k="199" />
+<hkern g1="Aacute" g2="y" k="256" />
+<hkern g1="Aacute" g2="Ccedilla" k="98" />
+<hkern g1="Aacute" g2="Eth" k="52" />
+<hkern g1="Aacute" g2="Ograve" k="69" />
+<hkern g1="Aacute" g2="Oacute" k="69" />
+<hkern g1="Aacute" g2="Ocircumflex" k="69" />
+<hkern g1="Aacute" g2="Otilde" k="69" />
+<hkern g1="Aacute" g2="Odieresis" k="69" />
+<hkern g1="Aacute" g2="Yacute" k="200" />
+<hkern g1="Aacute" g2="yacute" k="62" />
+<hkern g1="Aacute" g2="ydieresis" k="53" />
+<hkern g1="Acircumflex" g2="C" k="98" />
+<hkern g1="Acircumflex" g2="G" k="98" />
+<hkern g1="Acircumflex" g2="O" k="69" />
+<hkern g1="Acircumflex" g2="Q" k="69" />
+<hkern g1="Acircumflex" g2="T" k="216" />
+<hkern g1="Acircumflex" g2="V" k="200" />
+<hkern g1="Acircumflex" g2="W" k="121" />
+<hkern g1="Acircumflex" g2="Y" k="200" />
+<hkern g1="Acircumflex" g2="f" k="64" />
+<hkern g1="Acircumflex" g2="j" k="106" />
+<hkern g1="Acircumflex" g2="t" k="95" />
+<hkern g1="Acircumflex" g2="v" k="225" />
+<hkern g1="Acircumflex" g2="w" k="199" />
+<hkern g1="Acircumflex" g2="y" k="256" />
+<hkern g1="Acircumflex" g2="Ccedilla" k="98" />
+<hkern g1="Acircumflex" g2="Eth" k="52" />
+<hkern g1="Acircumflex" g2="Ograve" k="69" />
+<hkern g1="Acircumflex" g2="Oacute" k="69" />
+<hkern g1="Acircumflex" g2="Ocircumflex" k="69" />
+<hkern g1="Acircumflex" g2="Otilde" k="69" />
+<hkern g1="Acircumflex" g2="Odieresis" k="69" />
+<hkern g1="Acircumflex" g2="Yacute" k="200" />
+<hkern g1="Acircumflex" g2="yacute" k="62" />
+<hkern g1="Acircumflex" g2="ydieresis" k="53" />
+<hkern g1="Atilde" g2="C" k="98" />
+<hkern g1="Atilde" g2="G" k="98" />
+<hkern g1="Atilde" g2="O" k="69" />
+<hkern g1="Atilde" g2="Q" k="69" />
+<hkern g1="Atilde" g2="T" k="204" />
+<hkern g1="Atilde" g2="V" k="204" />
+<hkern g1="Atilde" g2="W" k="78" />
+<hkern g1="Atilde" g2="Y" k="204" />
+<hkern g1="Atilde" g2="f" k="64" />
+<hkern g1="Atilde" g2="j" k="110" />
+<hkern g1="Atilde" g2="t" k="95" />
+<hkern g1="Atilde" g2="v" k="225" />
+<hkern g1="Atilde" g2="w" k="199" />
+<hkern g1="Atilde" g2="y" k="256" />
+<hkern g1="Atilde" g2="Ccedilla" k="98" />
+<hkern g1="Atilde" g2="Eth" k="52" />
+<hkern g1="Atilde" g2="Ograve" k="69" />
+<hkern g1="Atilde" g2="Oacute" k="69" />
+<hkern g1="Atilde" g2="Ocircumflex" k="69" />
+<hkern g1="Atilde" g2="Otilde" k="69" />
+<hkern g1="Atilde" g2="Odieresis" k="69" />
+<hkern g1="Atilde" g2="Yacute" k="204" />
+<hkern g1="Atilde" g2="yacute" k="66" />
+<hkern g1="Atilde" g2="ydieresis" k="57" />
+<hkern g1="Adieresis" g2="C" k="98" />
+<hkern g1="Adieresis" g2="G" k="98" />
+<hkern g1="Adieresis" g2="O" k="69" />
+<hkern g1="Adieresis" g2="Q" k="69" />
+<hkern g1="Adieresis" g2="T" k="236" />
+<hkern g1="Adieresis" g2="V" k="213" />
+<hkern g1="Adieresis" g2="W" k="188" />
+<hkern g1="Adieresis" g2="Y" k="213" />
+<hkern g1="Adieresis" g2="f" k="64" />
+<hkern g1="Adieresis" g2="j" k="158" />
+<hkern g1="Adieresis" g2="t" k="95" />
+<hkern g1="Adieresis" g2="v" k="157" />
+<hkern g1="Adieresis" g2="w" k="199" />
+<hkern g1="Adieresis" g2="y" k="256" />
+<hkern g1="Adieresis" g2="Ccedilla" k="98" />
+<hkern g1="Adieresis" g2="Eth" k="52" />
+<hkern g1="Adieresis" g2="Ograve" k="69" />
+<hkern g1="Adieresis" g2="Oacute" k="69" />
+<hkern g1="Adieresis" g2="Ocircumflex" k="69" />
+<hkern g1="Adieresis" g2="Otilde" k="69" />
+<hkern g1="Adieresis" g2="Odieresis" k="69" />
+<hkern g1="Adieresis" g2="Yacute" k="213" />
+<hkern g1="Adieresis" g2="yacute" k="75" />
+<hkern g1="Adieresis" g2="ydieresis" k="66" />
+<hkern g1="Aring" g2="C" k="98" />
+<hkern g1="Aring" g2="G" k="98" />
+<hkern g1="Aring" g2="O" k="69" />
+<hkern g1="Aring" g2="Q" k="69" />
+<hkern g1="Aring" g2="T" k="223" />
+<hkern g1="Aring" g2="V" k="230" />
+<hkern g1="Aring" g2="W" k="182" />
+<hkern g1="Aring" g2="Y" k="246" />
+<hkern g1="Aring" g2="f" k="64" />
+<hkern g1="Aring" g2="j" k="191" />
+<hkern g1="Aring" g2="t" k="95" />
+<hkern g1="Aring" g2="v" k="167" />
+<hkern g1="Aring" g2="w" k="199" />
+<hkern g1="Aring" g2="y" k="256" />
+<hkern g1="Aring" g2="Ccedilla" k="98" />
+<hkern g1="Aring" g2="Eth" k="52" />
+<hkern g1="Aring" g2="Ograve" k="69" />
+<hkern g1="Aring" g2="Oacute" k="69" />
+<hkern g1="Aring" g2="Ocircumflex" k="69" />
+<hkern g1="Aring" g2="Otilde" k="69" />
+<hkern g1="Aring" g2="Odieresis" k="69" />
+<hkern g1="Aring" g2="Yacute" k="207" />
+<hkern g1="Aring" g2="yacute" k="92" />
+<hkern g1="Aring" g2="ydieresis" k="83" />
+<hkern g1="AE" g2="C" k="100" />
+<hkern g1="AE" g2="G" k="100" />
+<hkern g1="AE" g2="J" k="65" />
+<hkern g1="AE" g2="O" k="102" />
+<hkern g1="AE" g2="Q" k="102" />
+<hkern g1="AE" g2="a" k="102" />
+<hkern g1="AE" g2="c" k="132" />
+<hkern g1="AE" g2="d" k="102" />
+<hkern g1="AE" g2="e" k="102" />
+<hkern g1="AE" g2="f" k="97" />
+<hkern g1="AE" g2="g" k="71" />
+<hkern g1="AE" g2="j" k="206" />
+<hkern g1="AE" g2="o" k="102" />
+<hkern g1="AE" g2="q" k="102" />
+<hkern g1="AE" g2="t" k="97" />
+<hkern g1="AE" g2="u" k="70" />
+<hkern g1="AE" g2="v" k="196" />
+<hkern g1="AE" g2="w" k="169" />
+<hkern g1="AE" g2="y" k="195" />
+<hkern g1="AE" g2="Ccedilla" k="100" />
+<hkern g1="AE" g2="Ograve" k="102" />
+<hkern g1="AE" g2="Oacute" k="102" />
+<hkern g1="AE" g2="Ocircumflex" k="102" />
+<hkern g1="AE" g2="Otilde" k="102" />
+<hkern g1="AE" g2="Odieresis" k="102" />
+<hkern g1="AE" g2="agrave" k="102" />
+<hkern g1="AE" g2="aacute" k="102" />
+<hkern g1="AE" g2="acircumflex" k="102" />
+<hkern g1="AE" g2="atilde" k="102" />
+<hkern g1="AE" g2="adieresis" k="102" />
+<hkern g1="AE" g2="aring" k="102" />
+<hkern g1="AE" g2="ae" k="114" />
+<hkern g1="AE" g2="ccedilla" k="132" />
+<hkern g1="AE" g2="egrave" k="102" />
+<hkern g1="AE" g2="eacute" k="102" />
+<hkern g1="AE" g2="ecircumflex" k="102" />
+<hkern g1="AE" g2="edieresis" k="102" />
+<hkern g1="AE" g2="eth" k="92" />
+<hkern g1="AE" g2="ograve" k="102" />
+<hkern g1="AE" g2="oacute" k="102" />
+<hkern g1="AE" g2="ocircumflex" k="102" />
+<hkern g1="AE" g2="otilde" k="102" />
+<hkern g1="AE" g2="odieresis" k="102" />
+<hkern g1="AE" g2="ugrave" k="70" />
+<hkern g1="AE" g2="uacute" k="70" />
+<hkern g1="AE" g2="ucircumflex" k="70" />
+<hkern g1="AE" g2="udieresis" k="70" />
+<hkern g1="AE" g2="yacute" k="195" />
+<hkern g1="AE" g2="ydieresis" k="132" />
+<hkern g1="Ccedilla" g2="C" k="91" />
+<hkern g1="Ccedilla" g2="G" k="138" />
+<hkern g1="Ccedilla" g2="O" k="91" />
+<hkern g1="Ccedilla" g2="Q" k="91" />
+<hkern g1="Ccedilla" g2="f" k="154" />
+<hkern g1="Ccedilla" g2="j" k="208" />
+<hkern g1="Ccedilla" g2="t" k="130" />
+<hkern g1="Ccedilla" g2="v" k="248" />
+<hkern g1="Ccedilla" g2="w" k="122" />
+<hkern g1="Ccedilla" g2="y" k="202" />
+<hkern g1="Ccedilla" g2="Ccedilla" k="104" />
+<hkern g1="Ccedilla" g2="Igrave" k="75" />
+<hkern g1="Ccedilla" g2="Iacute" k="105" />
+<hkern g1="Ccedilla" g2="Icircumflex" k="96" />
+<hkern g1="Ccedilla" g2="Idieresis" k="76" />
+<hkern g1="Ccedilla" g2="Eth" k="59" />
+<hkern g1="Ccedilla" g2="Ograve" k="91" />
+<hkern g1="Ccedilla" g2="Oacute" k="137" />
+<hkern g1="Ccedilla" g2="Ocircumflex" k="91" />
+<hkern g1="Ccedilla" g2="Otilde" k="91" />
+<hkern g1="Ccedilla" g2="Odieresis" k="91" />
+<hkern g1="Ccedilla" g2="iacute" k="53" />
+<hkern g1="Ccedilla" g2="yacute" k="204" />
+<hkern g1="Ccedilla" g2="ydieresis" k="164" />
+<hkern g1="Egrave" g2="C" k="127" />
+<hkern g1="Egrave" g2="G" k="127" />
+<hkern g1="Egrave" g2="O" k="129" />
+<hkern g1="Egrave" g2="Q" k="129" />
+<hkern g1="Egrave" g2="c" k="64" />
+<hkern g1="Egrave" g2="j" k="184" />
+<hkern g1="Egrave" g2="v" k="59" />
+<hkern g1="Egrave" g2="w" k="165" />
+<hkern g1="Egrave" g2="y" k="76" />
+<hkern g1="Egrave" g2="Ccedilla" k="127" />
+<hkern g1="Egrave" g2="Ograve" k="129" />
+<hkern g1="Egrave" g2="Oacute" k="129" />
+<hkern g1="Egrave" g2="Ocircumflex" k="129" />
+<hkern g1="Egrave" g2="Otilde" k="129" />
+<hkern g1="Egrave" g2="Odieresis" k="129" />
+<hkern g1="Egrave" g2="ae" k="47" />
+<hkern g1="Egrave" g2="ccedilla" k="64" />
+<hkern g1="Egrave" g2="eth" k="56" />
+<hkern g1="Egrave" g2="yacute" k="78" />
+<hkern g1="Egrave" g2="ydieresis" k="64" />
+<hkern g1="Eacute" g2="C" k="127" />
+<hkern g1="Eacute" g2="G" k="127" />
+<hkern g1="Eacute" g2="O" k="129" />
+<hkern g1="Eacute" g2="Q" k="129" />
+<hkern g1="Eacute" g2="c" k="64" />
+<hkern g1="Eacute" g2="j" k="182" />
+<hkern g1="Eacute" g2="v" k="191" />
+<hkern g1="Eacute" g2="w" k="165" />
+<hkern g1="Eacute" g2="y" k="51" />
+<hkern g1="Eacute" g2="Ccedilla" k="127" />
+<hkern g1="Eacute" g2="Ograve" k="129" />
+<hkern g1="Eacute" g2="Oacute" k="129" />
+<hkern g1="Eacute" g2="Ocircumflex" k="129" />
+<hkern g1="Eacute" g2="Otilde" k="129" />
+<hkern g1="Eacute" g2="Odieresis" k="129" />
+<hkern g1="Eacute" g2="ae" k="47" />
+<hkern g1="Eacute" g2="ccedilla" k="64" />
+<hkern g1="Eacute" g2="eth" k="56" />
+<hkern g1="Eacute" g2="yacute" k="53" />
+<hkern g1="Eacute" g2="ydieresis" k="64" />
+<hkern g1="Ecircumflex" g2="C" k="127" />
+<hkern g1="Ecircumflex" g2="G" k="127" />
+<hkern g1="Ecircumflex" g2="O" k="129" />
+<hkern g1="Ecircumflex" g2="Q" k="129" />
+<hkern g1="Ecircumflex" g2="c" k="64" />
+<hkern g1="Ecircumflex" g2="j" k="175" />
+<hkern g1="Ecircumflex" g2="v" k="191" />
+<hkern g1="Ecircumflex" g2="w" k="165" />
+<hkern g1="Ecircumflex" g2="y" k="51" />
+<hkern g1="Ecircumflex" g2="Ccedilla" k="127" />
+<hkern g1="Ecircumflex" g2="Ograve" k="129" />
+<hkern g1="Ecircumflex" g2="Oacute" k="129" />
+<hkern g1="Ecircumflex" g2="Ocircumflex" k="129" />
+<hkern g1="Ecircumflex" g2="Otilde" k="129" />
+<hkern g1="Ecircumflex" g2="Odieresis" k="129" />
+<hkern g1="Ecircumflex" g2="ae" k="47" />
+<hkern g1="Ecircumflex" g2="ccedilla" k="64" />
+<hkern g1="Ecircumflex" g2="eth" k="56" />
+<hkern g1="Ecircumflex" g2="yacute" k="53" />
+<hkern g1="Ecircumflex" g2="ydieresis" k="64" />
+<hkern g1="Edieresis" g2="C" k="127" />
+<hkern g1="Edieresis" g2="G" k="127" />
+<hkern g1="Edieresis" g2="O" k="129" />
+<hkern g1="Edieresis" g2="Q" k="129" />
+<hkern g1="Edieresis" g2="c" k="64" />
+<hkern g1="Edieresis" g2="j" k="180" />
+<hkern g1="Edieresis" g2="v" k="191" />
+<hkern g1="Edieresis" g2="w" k="165" />
+<hkern g1="Edieresis" g2="y" k="87" />
+<hkern g1="Edieresis" g2="Ccedilla" k="127" />
+<hkern g1="Edieresis" g2="Ograve" k="129" />
+<hkern g1="Edieresis" g2="Oacute" k="129" />
+<hkern g1="Edieresis" g2="Ocircumflex" k="129" />
+<hkern g1="Edieresis" g2="Otilde" k="129" />
+<hkern g1="Edieresis" g2="Odieresis" k="129" />
+<hkern g1="Edieresis" g2="ae" k="47" />
+<hkern g1="Edieresis" g2="ccedilla" k="64" />
+<hkern g1="Edieresis" g2="eth" k="56" />
+<hkern g1="Edieresis" g2="yacute" k="66" />
+<hkern g1="Edieresis" g2="ydieresis" k="64" />
+<hkern g1="Igrave" g2="I" k="42" />
+<hkern g1="Igrave" g2="j" k="283" />
+<hkern g1="Igrave" g2="dotlessi" k="42" />
+<hkern g1="Iacute" g2="j" k="199" />
+<hkern g1="Icircumflex" g2="j" k="207" />
+<hkern g1="Idieresis" g2="I" k="50" />
+<hkern g1="Idieresis" g2="j" k="227" />
+<hkern g1="Idieresis" g2="dotlessi" k="50" />
+<hkern g1="Eth" g2="A" k="128" />
+<hkern g1="Eth" g2="T" k="223" />
+<hkern g1="Eth" g2="V" k="128" />
+<hkern g1="Eth" g2="X" k="190" />
+<hkern g1="Eth" g2="Y" k="190" />
+<hkern g1="Eth" g2="Z" k="223" />
+<hkern g1="Eth" g2="j" k="176" />
+<hkern g1="Eth" g2="Agrave" k="128" />
+<hkern g1="Eth" g2="Aacute" k="128" />
+<hkern g1="Eth" g2="Acircumflex" k="128" />
+<hkern g1="Eth" g2="Atilde" k="128" />
+<hkern g1="Eth" g2="Adieresis" k="128" />
+<hkern g1="Eth" g2="Aring" k="128" />
+<hkern g1="Eth" g2="AE" k="131" />
+<hkern g1="Eth" g2="Yacute" k="190" />
+<hkern g1="Ntilde" g2="j" k="182" />
+<hkern g1="Ograve" g2="A" k="131" />
+<hkern g1="Ograve" g2="S" k="65" />
+<hkern g1="Ograve" g2="T" k="136" />
+<hkern g1="Ograve" g2="V" k="131" />
+<hkern g1="Ograve" g2="W" k="73" />
+<hkern g1="Ograve" g2="X" k="224" />
+<hkern g1="Ograve" g2="Y" k="224" />
+<hkern g1="Ograve" g2="Z" k="225" />
+<hkern g1="Ograve" g2="j" k="160" />
+<hkern g1="Ograve" g2="Agrave" k="131" />
+<hkern g1="Ograve" g2="Aacute" k="131" />
+<hkern g1="Ograve" g2="Acircumflex" k="131" />
+<hkern g1="Ograve" g2="Atilde" k="131" />
+<hkern g1="Ograve" g2="Adieresis" k="131" />
+<hkern g1="Ograve" g2="Aring" k="131" />
+<hkern g1="Ograve" g2="AE" k="165" />
+<hkern g1="Ograve" g2="Yacute" k="224" />
+<hkern g1="Oacute" g2="A" k="131" />
+<hkern g1="Oacute" g2="S" k="65" />
+<hkern g1="Oacute" g2="T" k="133" />
+<hkern g1="Oacute" g2="V" k="131" />
+<hkern g1="Oacute" g2="W" k="73" />
+<hkern g1="Oacute" g2="X" k="224" />
+<hkern g1="Oacute" g2="Y" k="224" />
+<hkern g1="Oacute" g2="Z" k="225" />
+<hkern g1="Oacute" g2="j" k="173" />
+<hkern g1="Oacute" g2="Agrave" k="131" />
+<hkern g1="Oacute" g2="Aacute" k="131" />
+<hkern g1="Oacute" g2="Acircumflex" k="131" />
+<hkern g1="Oacute" g2="Atilde" k="131" />
+<hkern g1="Oacute" g2="Adieresis" k="131" />
+<hkern g1="Oacute" g2="Aring" k="131" />
+<hkern g1="Oacute" g2="AE" k="165" />
+<hkern g1="Oacute" g2="Yacute" k="224" />
+<hkern g1="Ocircumflex" g2="A" k="131" />
+<hkern g1="Ocircumflex" g2="S" k="65" />
+<hkern g1="Ocircumflex" g2="T" k="109" />
+<hkern g1="Ocircumflex" g2="V" k="131" />
+<hkern g1="Ocircumflex" g2="W" k="73" />
+<hkern g1="Ocircumflex" g2="X" k="224" />
+<hkern g1="Ocircumflex" g2="Y" k="224" />
+<hkern g1="Ocircumflex" g2="Z" k="225" />
+<hkern g1="Ocircumflex" g2="j" k="187" />
+<hkern g1="Ocircumflex" g2="Agrave" k="131" />
+<hkern g1="Ocircumflex" g2="Aacute" k="131" />
+<hkern g1="Ocircumflex" g2="Acircumflex" k="131" />
+<hkern g1="Ocircumflex" g2="Atilde" k="131" />
+<hkern g1="Ocircumflex" g2="Adieresis" k="131" />
+<hkern g1="Ocircumflex" g2="Aring" k="131" />
+<hkern g1="Ocircumflex" g2="AE" k="165" />
+<hkern g1="Ocircumflex" g2="Yacute" k="224" />
+<hkern g1="Otilde" g2="A" k="131" />
+<hkern g1="Otilde" g2="S" k="65" />
+<hkern g1="Otilde" g2="T" k="137" />
+<hkern g1="Otilde" g2="V" k="131" />
+<hkern g1="Otilde" g2="W" k="73" />
+<hkern g1="Otilde" g2="X" k="224" />
+<hkern g1="Otilde" g2="Y" k="224" />
+<hkern g1="Otilde" g2="Z" k="225" />
+<hkern g1="Otilde" g2="j" k="169" />
+<hkern g1="Otilde" g2="Agrave" k="131" />
+<hkern g1="Otilde" g2="Aacute" k="131" />
+<hkern g1="Otilde" g2="Acircumflex" k="131" />
+<hkern g1="Otilde" g2="Atilde" k="131" />
+<hkern g1="Otilde" g2="Adieresis" k="131" />
+<hkern g1="Otilde" g2="Aring" k="131" />
+<hkern g1="Otilde" g2="AE" k="165" />
+<hkern g1="Otilde" g2="Yacute" k="224" />
+<hkern g1="Odieresis" g2="A" k="131" />
+<hkern g1="Odieresis" g2="S" k="65" />
+<hkern g1="Odieresis" g2="T" k="149" />
+<hkern g1="Odieresis" g2="V" k="131" />
+<hkern g1="Odieresis" g2="W" k="73" />
+<hkern g1="Odieresis" g2="X" k="224" />
+<hkern g1="Odieresis" g2="Y" k="110" />
+<hkern g1="Odieresis" g2="Z" k="225" />
+<hkern g1="Odieresis" g2="j" k="196" />
+<hkern g1="Odieresis" g2="Agrave" k="131" />
+<hkern g1="Odieresis" g2="Aacute" k="131" />
+<hkern g1="Odieresis" g2="Acircumflex" k="131" />
+<hkern g1="Odieresis" g2="Atilde" k="131" />
+<hkern g1="Odieresis" g2="Adieresis" k="131" />
+<hkern g1="Odieresis" g2="Aring" k="131" />
+<hkern g1="Odieresis" g2="AE" k="165" />
+<hkern g1="Odieresis" g2="Yacute" k="95" />
+<hkern g1="Oslash" g2="A" k="131" />
+<hkern g1="Oslash" g2="S" k="65" />
+<hkern g1="Oslash" g2="j" k="179" />
+<hkern g1="Oslash" g2="Agrave" k="131" />
+<hkern g1="Oslash" g2="Aacute" k="131" />
+<hkern g1="Oslash" g2="Acircumflex" k="131" />
+<hkern g1="Oslash" g2="Atilde" k="131" />
+<hkern g1="Oslash" g2="Adieresis" k="131" />
+<hkern g1="Oslash" g2="Aring" k="131" />
+<hkern g1="Oslash" g2="AE" k="165" />
+<hkern g1="Ugrave" g2="j" k="170" />
+<hkern g1="Uacute" g2="j" k="158" />
+<hkern g1="Ucircumflex" g2="j" k="175" />
+<hkern g1="Udieresis" g2="j" k="187" />
+<hkern g1="Yacute" g2="A" k="205" />
+<hkern g1="Yacute" g2="C" k="160" />
+<hkern g1="Yacute" g2="G" k="160" />
+<hkern g1="Yacute" g2="J" k="212" />
+<hkern g1="Yacute" g2="O" k="130" />
+<hkern g1="Yacute" g2="Q" k="130" />
+<hkern g1="Yacute" g2="S" k="61" />
+<hkern g1="Yacute" g2="a" k="181" />
+<hkern g1="Yacute" g2="c" k="181" />
+<hkern g1="Yacute" g2="d" k="205" />
+<hkern g1="Yacute" g2="e" k="197" />
+<hkern g1="Yacute" g2="f" k="157" />
+<hkern g1="Yacute" g2="g" k="186" />
+<hkern g1="Yacute" g2="j" k="197" />
+<hkern g1="Yacute" g2="m" k="168" />
+<hkern g1="Yacute" g2="n" k="129" />
+<hkern g1="Yacute" g2="o" k="181" />
+<hkern g1="Yacute" g2="p" k="187" />
+<hkern g1="Yacute" g2="q" k="178" />
+<hkern g1="Yacute" g2="r" k="158" />
+<hkern g1="Yacute" g2="s" k="127" />
+<hkern g1="Yacute" g2="t" k="62" />
+<hkern g1="Yacute" g2="u" k="129" />
+<hkern g1="Yacute" g2="v" k="129" />
+<hkern g1="Yacute" g2="w" k="166" />
+<hkern g1="Yacute" g2="x" k="160" />
+<hkern g1="Yacute" g2="y" k="160" />
+<hkern g1="Yacute" g2="z" k="160" />
+<hkern g1="Yacute" g2="Agrave" k="197" />
+<hkern g1="Yacute" g2="Aacute" k="205" />
+<hkern g1="Yacute" g2="Acircumflex" k="228" />
+<hkern g1="Yacute" g2="Atilde" k="197" />
+<hkern g1="Yacute" g2="Adieresis" k="197" />
+<hkern g1="Yacute" g2="Aring" k="189" />
+<hkern g1="Yacute" g2="AE" k="189" />
+<hkern g1="Yacute" g2="Ccedilla" k="160" />
+<hkern g1="Yacute" g2="Eth" k="50" />
+<hkern g1="Yacute" g2="Ograve" k="130" />
+<hkern g1="Yacute" g2="Oacute" k="130" />
+<hkern g1="Yacute" g2="Ocircumflex" k="130" />
+<hkern g1="Yacute" g2="Otilde" k="130" />
+<hkern g1="Yacute" g2="Odieresis" k="130" />
+<hkern g1="Yacute" g2="Oslash" k="130" />
+<hkern g1="Yacute" g2="agrave" k="174" />
+<hkern g1="Yacute" g2="aacute" k="189" />
+<hkern g1="Yacute" g2="acircumflex" k="166" />
+<hkern g1="Yacute" g2="atilde" k="67" />
+<hkern g1="Yacute" g2="adieresis" k="158" />
+<hkern g1="Yacute" g2="aring" k="126" />
+<hkern g1="Yacute" g2="ae" k="197" />
+<hkern g1="Yacute" g2="ccedilla" k="190" />
+<hkern g1="Yacute" g2="egrave" k="174" />
+<hkern g1="Yacute" g2="eacute" k="205" />
+<hkern g1="Yacute" g2="ecircumflex" k="150" />
+<hkern g1="Yacute" g2="edieresis" k="150" />
+<hkern g1="Yacute" g2="eth" k="166" />
+<hkern g1="Yacute" g2="ograve" k="181" />
+<hkern g1="Yacute" g2="oacute" k="174" />
+<hkern g1="Yacute" g2="ocircumflex" k="143" />
+<hkern g1="Yacute" g2="otilde" k="67" />
+<hkern g1="Yacute" g2="odieresis" k="158" />
+<hkern g1="Yacute" g2="oslash" k="181" />
+<hkern g1="Yacute" g2="ugrave" k="129" />
+<hkern g1="Yacute" g2="uacute" k="129" />
+<hkern g1="Yacute" g2="ucircumflex" k="129" />
+<hkern g1="Yacute" g2="udieresis" k="98" />
+<hkern g1="Yacute" g2="yacute" k="160" />
+<hkern g1="Yacute" g2="ydieresis" k="97" />
+<hkern g1="Yacute" g2="dotlessi" k="228" />
+<hkern g1="Thorn" g2="A" k="127" />
+<hkern g1="Thorn" g2="T" k="280" />
+<hkern g1="Thorn" g2="V" k="127" />
+<hkern g1="Thorn" g2="X" k="170" />
+<hkern g1="Thorn" g2="Y" k="186" />
+<hkern g1="Thorn" g2="Z" k="186" />
+<hkern g1="Thorn" g2="j" k="288" />
+<hkern g1="Thorn" g2="Agrave" k="127" />
+<hkern g1="Thorn" g2="Aacute" k="127" />
+<hkern g1="Thorn" g2="Acircumflex" k="127" />
+<hkern g1="Thorn" g2="Atilde" k="127" />
+<hkern g1="Thorn" g2="Adieresis" k="127" />
+<hkern g1="Thorn" g2="Aring" k="127" />
+<hkern g1="Thorn" g2="AE" k="161" />
+<hkern g1="Thorn" g2="Yacute" k="186" />
+<hkern g1="germandbls" g2="T" k="84" />
+<hkern g1="germandbls" g2="V" k="123" />
+<hkern g1="germandbls" g2="W" k="96" />
+<hkern g1="germandbls" g2="Y" k="108" />
+<hkern g1="germandbls" g2="j" k="194" />
+<hkern g1="germandbls" g2="y" k="61" />
+<hkern g1="germandbls" g2="Yacute" k="92" />
+<hkern g1="germandbls" g2="yacute" k="61" />
+<hkern g1="germandbls" g2="ydieresis" k="61" />
+<hkern g1="agrave" g2="T" k="154" />
+<hkern g1="agrave" g2="V" k="249" />
+<hkern g1="agrave" g2="W" k="160" />
+<hkern g1="agrave" g2="Y" k="223" />
+<hkern g1="agrave" g2="f" k="58" />
+<hkern g1="agrave" g2="j" k="146" />
+<hkern g1="agrave" g2="t" k="90" />
+<hkern g1="agrave" g2="v" k="62" />
+<hkern g1="agrave" g2="y" k="61" />
+<hkern g1="agrave" g2="Yacute" k="208" />
+<hkern g1="agrave" g2="icircumflex" k="58" />
+<hkern g1="agrave" g2="idieresis" k="65" />
+<hkern g1="agrave" g2="yacute" k="61" />
+<hkern g1="agrave" g2="ydieresis" k="61" />
+<hkern g1="aacute" g2="T" k="102" />
+<hkern g1="aacute" g2="V" k="249" />
+<hkern g1="aacute" g2="W" k="160" />
+<hkern g1="aacute" g2="Y" k="125" />
+<hkern g1="aacute" g2="f" k="58" />
+<hkern g1="aacute" g2="j" k="181" />
+<hkern g1="aacute" g2="t" k="90" />
+<hkern g1="aacute" g2="v" k="62" />
+<hkern g1="aacute" g2="y" k="61" />
+<hkern g1="aacute" g2="Yacute" k="118" />
+<hkern g1="aacute" g2="icircumflex" k="58" />
+<hkern g1="aacute" g2="idieresis" k="65" />
+<hkern g1="aacute" g2="yacute" k="61" />
+<hkern g1="aacute" g2="ydieresis" k="61" />
+<hkern g1="acircumflex" g2="T" k="214" />
+<hkern g1="acircumflex" g2="V" k="88" />
+<hkern g1="acircumflex" g2="W" k="160" />
+<hkern g1="acircumflex" g2="Y" k="199" />
+<hkern g1="acircumflex" g2="f" k="58" />
+<hkern g1="acircumflex" g2="j" k="207" />
+<hkern g1="acircumflex" g2="t" k="90" />
+<hkern g1="acircumflex" g2="v" k="62" />
+<hkern g1="acircumflex" g2="y" k="61" />
+<hkern g1="acircumflex" g2="Yacute" k="168" />
+<hkern g1="acircumflex" g2="yacute" k="61" />
+<hkern g1="acircumflex" g2="ydieresis" k="61" />
+<hkern g1="atilde" g2="T" k="123" />
+<hkern g1="atilde" g2="V" k="123" />
+<hkern g1="atilde" g2="W" k="97" />
+<hkern g1="atilde" g2="Y" k="122" />
+<hkern g1="atilde" g2="f" k="58" />
+<hkern g1="atilde" g2="j" k="181" />
+<hkern g1="atilde" g2="t" k="90" />
+<hkern g1="atilde" g2="v" k="62" />
+<hkern g1="atilde" g2="y" k="61" />
+<hkern g1="atilde" g2="Yacute" k="122" />
+<hkern g1="atilde" g2="yacute" k="61" />
+<hkern g1="atilde" g2="ydieresis" k="61" />
+<hkern g1="adieresis" g2="T" k="289" />
+<hkern g1="adieresis" g2="V" k="108" />
+<hkern g1="adieresis" g2="W" k="160" />
+<hkern g1="adieresis" g2="Y" k="179" />
+<hkern g1="adieresis" g2="f" k="58" />
+<hkern g1="adieresis" g2="j" k="195" />
+<hkern g1="adieresis" g2="t" k="90" />
+<hkern g1="adieresis" g2="v" k="62" />
+<hkern g1="adieresis" g2="y" k="61" />
+<hkern g1="adieresis" g2="Yacute" k="156" />
+<hkern g1="adieresis" g2="yacute" k="61" />
+<hkern g1="adieresis" g2="ydieresis" k="61" />
+<hkern g1="aring" g2="T" k="111" />
+<hkern g1="aring" g2="V" k="95" />
+<hkern g1="aring" g2="W" k="160" />
+<hkern g1="aring" g2="Y" k="111" />
+<hkern g1="aring" g2="f" k="58" />
+<hkern g1="aring" g2="j" k="190" />
+<hkern g1="aring" g2="t" k="90" />
+<hkern g1="aring" g2="v" k="62" />
+<hkern g1="aring" g2="y" k="61" />
+<hkern g1="aring" g2="Yacute" k="119" />
+<hkern g1="aring" g2="icircumflex" k="58" />
+<hkern g1="aring" g2="idieresis" k="65" />
+<hkern g1="aring" g2="yacute" k="61" />
+<hkern g1="aring" g2="ydieresis" k="61" />
+<hkern g1="ae" g2="A" k="126" />
+<hkern g1="ae" g2="S" k="123" />
+<hkern g1="ae" g2="T" k="225" />
+<hkern g1="ae" g2="V" k="284" />
+<hkern g1="ae" g2="W" k="163" />
+<hkern g1="ae" g2="X" k="157" />
+<hkern g1="ae" g2="Y" k="225" />
+<hkern g1="ae" g2="Z" k="158" />
+<hkern g1="ae" g2="f" k="93" />
+<hkern g1="ae" g2="i" k="50" />
+<hkern g1="ae" g2="j" k="192" />
+<hkern g1="ae" g2="t" k="124" />
+<hkern g1="ae" g2="v" k="97" />
+<hkern g1="ae" g2="w" k="70" />
+<hkern g1="ae" g2="x" k="127" />
+<hkern g1="ae" g2="y" k="96" />
+<hkern g1="ae" g2="z" k="127" />
+<hkern g1="ae" g2="Agrave" k="126" />
+<hkern g1="ae" g2="Aacute" k="126" />
+<hkern g1="ae" g2="Acircumflex" k="126" />
+<hkern g1="ae" g2="Atilde" k="126" />
+<hkern g1="ae" g2="Adieresis" k="126" />
+<hkern g1="ae" g2="Aring" k="126" />
+<hkern g1="ae" g2="AE" k="129" />
+<hkern g1="ae" g2="Igrave" k="47" />
+<hkern g1="ae" g2="Iacute" k="53" />
+<hkern g1="ae" g2="Icircumflex" k="60" />
+<hkern g1="ae" g2="Yacute" k="256" />
+<hkern g1="ae" g2="igrave" k="42" />
+<hkern g1="ae" g2="icircumflex" k="93" />
+<hkern g1="ae" g2="idieresis" k="100" />
+<hkern g1="ae" g2="yacute" k="96" />
+<hkern g1="ae" g2="ydieresis" k="96" />
+<hkern g1="ccedilla" g2="T" k="248" />
+<hkern g1="ccedilla" g2="V" k="123" />
+<hkern g1="ccedilla" g2="Y" k="185" />
+<hkern g1="ccedilla" g2="j" k="41" />
+<hkern g1="ccedilla" g2="Yacute" k="170" />
+<hkern g1="egrave" g2="A" k="92" />
+<hkern g1="egrave" g2="S" k="120" />
+<hkern g1="egrave" g2="T" k="210" />
+<hkern g1="egrave" g2="V" k="75" />
+<hkern g1="egrave" g2="W" k="160" />
+<hkern g1="egrave" g2="X" k="122" />
+<hkern g1="egrave" g2="Y" k="178" />
+<hkern g1="egrave" g2="Z" k="123" />
+<hkern g1="egrave" g2="f" k="58" />
+<hkern g1="egrave" g2="j" k="186" />
+<hkern g1="egrave" g2="t" k="90" />
+<hkern g1="egrave" g2="v" k="62" />
+<hkern g1="egrave" g2="x" k="93" />
+<hkern g1="egrave" g2="y" k="61" />
+<hkern g1="egrave" g2="z" k="93" />
+<hkern g1="egrave" g2="Agrave" k="92" />
+<hkern g1="egrave" g2="Aacute" k="92" />
+<hkern g1="egrave" g2="Acircumflex" k="92" />
+<hkern g1="egrave" g2="Atilde" k="92" />
+<hkern g1="egrave" g2="Adieresis" k="92" />
+<hkern g1="egrave" g2="Aring" k="92" />
+<hkern g1="egrave" g2="AE" k="95" />
+<hkern g1="egrave" g2="Yacute" k="209" />
+<hkern g1="egrave" g2="icircumflex" k="58" />
+<hkern g1="egrave" g2="idieresis" k="65" />
+<hkern g1="egrave" g2="yacute" k="61" />
+<hkern g1="egrave" g2="ydieresis" k="61" />
+<hkern g1="eacute" g2="A" k="92" />
+<hkern g1="eacute" g2="S" k="120" />
+<hkern g1="eacute" g2="T" k="129" />
+<hkern g1="eacute" g2="V" k="249" />
+<hkern g1="eacute" g2="W" k="160" />
+<hkern g1="eacute" g2="X" k="122" />
+<hkern g1="eacute" g2="Y" k="122" />
+<hkern g1="eacute" g2="Z" k="123" />
+<hkern g1="eacute" g2="f" k="58" />
+<hkern g1="eacute" g2="j" k="185" />
+<hkern g1="eacute" g2="t" k="90" />
+<hkern g1="eacute" g2="v" k="62" />
+<hkern g1="eacute" g2="x" k="93" />
+<hkern g1="eacute" g2="y" k="61" />
+<hkern g1="eacute" g2="z" k="93" />
+<hkern g1="eacute" g2="Agrave" k="92" />
+<hkern g1="eacute" g2="Aacute" k="92" />
+<hkern g1="eacute" g2="Acircumflex" k="92" />
+<hkern g1="eacute" g2="Atilde" k="92" />
+<hkern g1="eacute" g2="Adieresis" k="92" />
+<hkern g1="eacute" g2="Aring" k="92" />
+<hkern g1="eacute" g2="AE" k="95" />
+<hkern g1="eacute" g2="Yacute" k="106" />
+<hkern g1="eacute" g2="icircumflex" k="58" />
+<hkern g1="eacute" g2="idieresis" k="65" />
+<hkern g1="eacute" g2="yacute" k="61" />
+<hkern g1="eacute" g2="ydieresis" k="61" />
+<hkern g1="ecircumflex" g2="A" k="92" />
+<hkern g1="ecircumflex" g2="S" k="120" />
+<hkern g1="ecircumflex" g2="T" k="203" />
+<hkern g1="ecircumflex" g2="V" k="100" />
+<hkern g1="ecircumflex" g2="W" k="160" />
+<hkern g1="ecircumflex" g2="X" k="122" />
+<hkern g1="ecircumflex" g2="Y" k="164" />
+<hkern g1="ecircumflex" g2="Z" k="123" />
+<hkern g1="ecircumflex" g2="f" k="58" />
+<hkern g1="ecircumflex" g2="j" k="195" />
+<hkern g1="ecircumflex" g2="t" k="90" />
+<hkern g1="ecircumflex" g2="v" k="62" />
+<hkern g1="ecircumflex" g2="x" k="93" />
+<hkern g1="ecircumflex" g2="y" k="61" />
+<hkern g1="ecircumflex" g2="z" k="93" />
+<hkern g1="ecircumflex" g2="Agrave" k="92" />
+<hkern g1="ecircumflex" g2="Aacute" k="92" />
+<hkern g1="ecircumflex" g2="Acircumflex" k="92" />
+<hkern g1="ecircumflex" g2="Atilde" k="92" />
+<hkern g1="ecircumflex" g2="Adieresis" k="92" />
+<hkern g1="ecircumflex" g2="Aring" k="92" />
+<hkern g1="ecircumflex" g2="AE" k="95" />
+<hkern g1="ecircumflex" g2="Yacute" k="164" />
+<hkern g1="ecircumflex" g2="yacute" k="61" />
+<hkern g1="ecircumflex" g2="ydieresis" k="61" />
+<hkern g1="edieresis" g2="A" k="92" />
+<hkern g1="edieresis" g2="S" k="120" />
+<hkern g1="edieresis" g2="T" k="190" />
+<hkern g1="edieresis" g2="V" k="186" />
+<hkern g1="edieresis" g2="W" k="160" />
+<hkern g1="edieresis" g2="X" k="122" />
+<hkern g1="edieresis" g2="Y" k="142" />
+<hkern g1="edieresis" g2="Z" k="123" />
+<hkern g1="edieresis" g2="f" k="58" />
+<hkern g1="edieresis" g2="j" k="189" />
+<hkern g1="edieresis" g2="t" k="90" />
+<hkern g1="edieresis" g2="v" k="62" />
+<hkern g1="edieresis" g2="x" k="93" />
+<hkern g1="edieresis" g2="y" k="61" />
+<hkern g1="edieresis" g2="z" k="93" />
+<hkern g1="edieresis" g2="Agrave" k="92" />
+<hkern g1="edieresis" g2="Aacute" k="92" />
+<hkern g1="edieresis" g2="Acircumflex" k="92" />
+<hkern g1="edieresis" g2="Atilde" k="92" />
+<hkern g1="edieresis" g2="Adieresis" k="92" />
+<hkern g1="edieresis" g2="Aring" k="92" />
+<hkern g1="edieresis" g2="AE" k="95" />
+<hkern g1="edieresis" g2="Yacute" k="88" />
+<hkern g1="edieresis" g2="yacute" k="61" />
+<hkern g1="edieresis" g2="ydieresis" k="61" />
+<hkern g1="igrave" g2="T" k="40" />
+<hkern g1="igrave" g2="j" k="264" />
+<hkern g1="igrave" g2="dotlessi" k="46" />
+<hkern g1="iacute" g2="j" k="224" />
+<hkern g1="iacute" g2="dotlessi" k="49" />
+<hkern g1="icircumflex" g2="j" k="173" />
+<hkern g1="icircumflex" g2="dotlessi" k="44" />
+<hkern g1="idieresis" g2="A" k="40" />
+<hkern g1="idieresis" g2="T" k="-19" />
+<hkern g1="idieresis" g2="a" k="43" />
+<hkern g1="idieresis" g2="c" k="41" />
+<hkern g1="idieresis" g2="d" k="43" />
+<hkern g1="idieresis" g2="e" k="43" />
+<hkern g1="idieresis" g2="g" k="43" />
+<hkern g1="idieresis" g2="j" k="182" />
+<hkern g1="idieresis" g2="m" k="49" />
+<hkern g1="idieresis" g2="n" k="42" />
+<hkern g1="idieresis" g2="o" k="43" />
+<hkern g1="idieresis" g2="p" k="43" />
+<hkern g1="idieresis" g2="q" k="43" />
+<hkern g1="idieresis" g2="s" k="40" />
+<hkern g1="idieresis" g2="u" k="42" />
+<hkern g1="idieresis" g2="v" k="42" />
+<hkern g1="idieresis" g2="w" k="47" />
+<hkern g1="idieresis" g2="x" k="41" />
+<hkern g1="idieresis" g2="y" k="41" />
+<hkern g1="idieresis" g2="z" k="41" />
+<hkern g1="idieresis" g2="Agrave" k="40" />
+<hkern g1="idieresis" g2="Aacute" k="40" />
+<hkern g1="idieresis" g2="Acircumflex" k="40" />
+<hkern g1="idieresis" g2="Atilde" k="40" />
+<hkern g1="idieresis" g2="Adieresis" k="40" />
+<hkern g1="idieresis" g2="Aring" k="40" />
+<hkern g1="idieresis" g2="AE" k="43" />
+<hkern g1="idieresis" g2="agrave" k="43" />
+<hkern g1="idieresis" g2="aacute" k="43" />
+<hkern g1="idieresis" g2="aring" k="43" />
+<hkern g1="idieresis" g2="ae" k="55" />
+<hkern g1="idieresis" g2="ccedilla" k="41" />
+<hkern g1="idieresis" g2="egrave" k="43" />
+<hkern g1="idieresis" g2="eacute" k="43" />
+<hkern g1="idieresis" g2="ograve" k="43" />
+<hkern g1="idieresis" g2="oacute" k="43" />
+<hkern g1="idieresis" g2="oslash" k="43" />
+<hkern g1="idieresis" g2="ugrave" k="42" />
+<hkern g1="idieresis" g2="uacute" k="42" />
+<hkern g1="idieresis" g2="yacute" k="41" />
+<hkern g1="idieresis" g2="dotlessi" k="109" />
+<hkern g1="eth" g2="T" k="133" />
+<hkern g1="eth" g2="V" k="133" />
+<hkern g1="eth" g2="W" k="107" />
+<hkern g1="eth" g2="X" k="101" />
+<hkern g1="eth" g2="Y" k="132" />
+<hkern g1="eth" g2="Z" k="102" />
+<hkern g1="eth" g2="j" k="200" />
+<hkern g1="eth" g2="t" k="68" />
+<hkern g1="eth" g2="x" k="71" />
+<hkern g1="eth" g2="y" k="40" />
+<hkern g1="eth" g2="z" k="71" />
+<hkern g1="eth" g2="AE" k="42" />
+<hkern g1="eth" g2="Yacute" k="132" />
+<hkern g1="eth" g2="idieresis" k="44" />
+<hkern g1="eth" g2="yacute" k="40" />
+<hkern g1="eth" g2="ydieresis" k="40" />
+<hkern g1="ntilde" g2="T" k="76" />
+<hkern g1="ntilde" g2="V" k="76" />
+<hkern g1="ntilde" g2="W" k="49" />
+<hkern g1="ntilde" g2="Y" k="75" />
+<hkern g1="ntilde" g2="f" k="42" />
+<hkern g1="ntilde" g2="j" k="190" />
+<hkern g1="ntilde" g2="t" k="74" />
+<hkern g1="ntilde" g2="v" k="46" />
+<hkern g1="ntilde" g2="y" k="45" />
+<hkern g1="ntilde" g2="Yacute" k="75" />
+<hkern g1="ntilde" g2="yacute" k="45" />
+<hkern g1="ntilde" g2="ydieresis" k="45" />
+<hkern g1="ograve" g2="A" k="60" />
+<hkern g1="ograve" g2="T" k="115" />
+<hkern g1="ograve" g2="V" k="249" />
+<hkern g1="ograve" g2="W" k="160" />
+<hkern g1="ograve" g2="X" k="122" />
+<hkern g1="ograve" g2="Y" k="169" />
+<hkern g1="ograve" g2="Z" k="123" />
+<hkern g1="ograve" g2="f" k="58" />
+<hkern g1="ograve" g2="j" k="239" />
+<hkern g1="ograve" g2="t" k="90" />
+<hkern g1="ograve" g2="v" k="62" />
+<hkern g1="ograve" g2="x" k="93" />
+<hkern g1="ograve" g2="y" k="61" />
+<hkern g1="ograve" g2="z" k="93" />
+<hkern g1="ograve" g2="Agrave" k="60" />
+<hkern g1="ograve" g2="Aacute" k="60" />
+<hkern g1="ograve" g2="Acircumflex" k="60" />
+<hkern g1="ograve" g2="Atilde" k="60" />
+<hkern g1="ograve" g2="Adieresis" k="60" />
+<hkern g1="ograve" g2="Aring" k="60" />
+<hkern g1="ograve" g2="AE" k="63" />
+<hkern g1="ograve" g2="Yacute" k="169" />
+<hkern g1="ograve" g2="icircumflex" k="58" />
+<hkern g1="ograve" g2="idieresis" k="65" />
+<hkern g1="ograve" g2="yacute" k="61" />
+<hkern g1="ograve" g2="ydieresis" k="61" />
+<hkern g1="oacute" g2="A" k="60" />
+<hkern g1="oacute" g2="T" k="114" />
+<hkern g1="oacute" g2="V" k="249" />
+<hkern g1="oacute" g2="W" k="160" />
+<hkern g1="oacute" g2="X" k="122" />
+<hkern g1="oacute" g2="Y" k="160" />
+<hkern g1="oacute" g2="Z" k="123" />
+<hkern g1="oacute" g2="f" k="58" />
+<hkern g1="oacute" g2="j" k="216" />
+<hkern g1="oacute" g2="t" k="90" />
+<hkern g1="oacute" g2="v" k="62" />
+<hkern g1="oacute" g2="x" k="93" />
+<hkern g1="oacute" g2="y" k="61" />
+<hkern g1="oacute" g2="z" k="93" />
+<hkern g1="oacute" g2="Agrave" k="60" />
+<hkern g1="oacute" g2="Aacute" k="60" />
+<hkern g1="oacute" g2="Acircumflex" k="60" />
+<hkern g1="oacute" g2="Atilde" k="60" />
+<hkern g1="oacute" g2="Adieresis" k="60" />
+<hkern g1="oacute" g2="Aring" k="60" />
+<hkern g1="oacute" g2="AE" k="63" />
+<hkern g1="oacute" g2="Yacute" k="106" />
+<hkern g1="oacute" g2="icircumflex" k="58" />
+<hkern g1="oacute" g2="idieresis" k="65" />
+<hkern g1="oacute" g2="yacute" k="61" />
+<hkern g1="oacute" g2="ydieresis" k="61" />
+<hkern g1="ocircumflex" g2="A" k="60" />
+<hkern g1="ocircumflex" g2="T" k="169" />
+<hkern g1="ocircumflex" g2="V" k="218" />
+<hkern g1="ocircumflex" g2="W" k="160" />
+<hkern g1="ocircumflex" g2="X" k="122" />
+<hkern g1="ocircumflex" g2="Y" k="138" />
+<hkern g1="ocircumflex" g2="Z" k="123" />
+<hkern g1="ocircumflex" g2="f" k="58" />
+<hkern g1="ocircumflex" g2="j" k="224" />
+<hkern g1="ocircumflex" g2="t" k="90" />
+<hkern g1="ocircumflex" g2="v" k="62" />
+<hkern g1="ocircumflex" g2="x" k="93" />
+<hkern g1="ocircumflex" g2="y" k="61" />
+<hkern g1="ocircumflex" g2="z" k="93" />
+<hkern g1="ocircumflex" g2="Agrave" k="60" />
+<hkern g1="ocircumflex" g2="Aacute" k="60" />
+<hkern g1="ocircumflex" g2="Acircumflex" k="60" />
+<hkern g1="ocircumflex" g2="Atilde" k="60" />
+<hkern g1="ocircumflex" g2="Adieresis" k="60" />
+<hkern g1="ocircumflex" g2="Aring" k="60" />
+<hkern g1="ocircumflex" g2="AE" k="63" />
+<hkern g1="ocircumflex" g2="Yacute" k="138" />
+<hkern g1="ocircumflex" g2="yacute" k="61" />
+<hkern g1="ocircumflex" g2="ydieresis" k="61" />
+<hkern g1="otilde" g2="A" k="60" />
+<hkern g1="otilde" g2="T" k="83" />
+<hkern g1="otilde" g2="V" k="123" />
+<hkern g1="otilde" g2="W" k="97" />
+<hkern g1="otilde" g2="X" k="122" />
+<hkern g1="otilde" g2="Y" k="122" />
+<hkern g1="otilde" g2="Z" k="123" />
+<hkern g1="otilde" g2="f" k="58" />
+<hkern g1="otilde" g2="j" k="192" />
+<hkern g1="otilde" g2="t" k="90" />
+<hkern g1="otilde" g2="v" k="62" />
+<hkern g1="otilde" g2="x" k="93" />
+<hkern g1="otilde" g2="y" k="61" />
+<hkern g1="otilde" g2="z" k="93" />
+<hkern g1="otilde" g2="Agrave" k="60" />
+<hkern g1="otilde" g2="Aacute" k="60" />
+<hkern g1="otilde" g2="Acircumflex" k="60" />
+<hkern g1="otilde" g2="Atilde" k="60" />
+<hkern g1="otilde" g2="Adieresis" k="60" />
+<hkern g1="otilde" g2="Aring" k="60" />
+<hkern g1="otilde" g2="AE" k="63" />
+<hkern g1="otilde" g2="Yacute" k="122" />
+<hkern g1="otilde" g2="yacute" k="61" />
+<hkern g1="otilde" g2="ydieresis" k="61" />
+<hkern g1="odieresis" g2="A" k="60" />
+<hkern g1="odieresis" g2="T" k="228" />
+<hkern g1="odieresis" g2="V" k="186" />
+<hkern g1="odieresis" g2="W" k="160" />
+<hkern g1="odieresis" g2="X" k="122" />
+<hkern g1="odieresis" g2="Y" k="133" />
+<hkern g1="odieresis" g2="Z" k="123" />
+<hkern g1="odieresis" g2="f" k="58" />
+<hkern g1="odieresis" g2="j" k="227" />
+<hkern g1="odieresis" g2="t" k="90" />
+<hkern g1="odieresis" g2="v" k="62" />
+<hkern g1="odieresis" g2="x" k="93" />
+<hkern g1="odieresis" g2="y" k="61" />
+<hkern g1="odieresis" g2="z" k="93" />
+<hkern g1="odieresis" g2="Agrave" k="60" />
+<hkern g1="odieresis" g2="Aacute" k="60" />
+<hkern g1="odieresis" g2="Acircumflex" k="60" />
+<hkern g1="odieresis" g2="Atilde" k="60" />
+<hkern g1="odieresis" g2="Adieresis" k="60" />
+<hkern g1="odieresis" g2="Aring" k="60" />
+<hkern g1="odieresis" g2="AE" k="63" />
+<hkern g1="odieresis" g2="Yacute" k="118" />
+<hkern g1="odieresis" g2="yacute" k="61" />
+<hkern g1="odieresis" g2="ydieresis" k="61" />
+<hkern g1="oslash" g2="A" k="60" />
+<hkern g1="oslash" g2="T" k="163" />
+<hkern g1="oslash" g2="V" k="123" />
+<hkern g1="oslash" g2="X" k="122" />
+<hkern g1="oslash" g2="Y" k="217" />
+<hkern g1="oslash" g2="Z" k="123" />
+<hkern g1="oslash" g2="j" k="186" />
+<hkern g1="oslash" g2="Agrave" k="60" />
+<hkern g1="oslash" g2="Aacute" k="60" />
+<hkern g1="oslash" g2="Acircumflex" k="60" />
+<hkern g1="oslash" g2="Atilde" k="60" />
+<hkern g1="oslash" g2="Adieresis" k="60" />
+<hkern g1="oslash" g2="Aring" k="60" />
+<hkern g1="oslash" g2="AE" k="63" />
+<hkern g1="oslash" g2="Yacute" k="217" />
+<hkern g1="oslash" g2="icircumflex" k="58" />
+<hkern g1="oslash" g2="idieresis" k="65" />
+<hkern g1="ugrave" g2="T" k="192" />
+<hkern g1="ugrave" g2="V" k="107" />
+<hkern g1="ugrave" g2="W" k="49" />
+<hkern g1="ugrave" g2="Y" k="97" />
+<hkern g1="ugrave" g2="j" k="199" />
+<hkern g1="ugrave" g2="Yacute" k="97" />
+<hkern g1="ugrave" g2="icircumflex" k="42" />
+<hkern g1="ugrave" g2="idieresis" k="49" />
+<hkern g1="uacute" g2="T" k="93" />
+<hkern g1="uacute" g2="V" k="107" />
+<hkern g1="uacute" g2="W" k="49" />
+<hkern g1="uacute" g2="Y" k="62" />
+<hkern g1="uacute" g2="j" k="195" />
+<hkern g1="uacute" g2="Yacute" k="62" />
+<hkern g1="uacute" g2="icircumflex" k="42" />
+<hkern g1="uacute" g2="idieresis" k="49" />
+<hkern g1="ucircumflex" g2="T" k="134" />
+<hkern g1="ucircumflex" g2="V" k="107" />
+<hkern g1="ucircumflex" g2="W" k="49" />
+<hkern g1="ucircumflex" g2="Y" k="71" />
+<hkern g1="ucircumflex" g2="j" k="204" />
+<hkern g1="ucircumflex" g2="Yacute" k="71" />
+<hkern g1="udieresis" g2="T" k="216" />
+<hkern g1="udieresis" g2="V" k="107" />
+<hkern g1="udieresis" g2="W" k="49" />
+<hkern g1="udieresis" g2="Y" k="97" />
+<hkern g1="udieresis" g2="j" k="222" />
+<hkern g1="udieresis" g2="Yacute" k="97" />
+<hkern g1="yacute" g2="A" k="132" />
+<hkern g1="yacute" g2="J" k="88" />
+<hkern g1="yacute" g2="T" k="91" />
+<hkern g1="yacute" g2="V" k="91" />
+<hkern g1="yacute" g2="X" k="90" />
+<hkern g1="yacute" g2="Y" k="90" />
+<hkern g1="yacute" g2="Z" k="91" />
+<hkern g1="yacute" g2="j" k="226" />
+<hkern g1="yacute" g2="Agrave" k="139" />
+<hkern g1="yacute" g2="Aacute" k="116" />
+<hkern g1="yacute" g2="Acircumflex" k="124" />
+<hkern g1="yacute" g2="Atilde" k="116" />
+<hkern g1="yacute" g2="Adieresis" k="116" />
+<hkern g1="yacute" g2="Aring" k="124" />
+<hkern g1="yacute" g2="AE" k="125" />
+<hkern g1="yacute" g2="Yacute" k="90" />
+<hkern g1="thorn" g2="A" k="60" />
+<hkern g1="thorn" g2="T" k="251" />
+<hkern g1="thorn" g2="V" k="249" />
+<hkern g1="thorn" g2="W" k="160" />
+<hkern g1="thorn" g2="X" k="122" />
+<hkern g1="thorn" g2="Y" k="258" />
+<hkern g1="thorn" g2="Z" k="123" />
+<hkern g1="thorn" g2="f" k="58" />
+<hkern g1="thorn" g2="j" k="250" />
+<hkern g1="thorn" g2="t" k="90" />
+<hkern g1="thorn" g2="v" k="62" />
+<hkern g1="thorn" g2="x" k="93" />
+<hkern g1="thorn" g2="y" k="61" />
+<hkern g1="thorn" g2="z" k="93" />
+<hkern g1="thorn" g2="Agrave" k="60" />
+<hkern g1="thorn" g2="Aacute" k="60" />
+<hkern g1="thorn" g2="Acircumflex" k="60" />
+<hkern g1="thorn" g2="Atilde" k="60" />
+<hkern g1="thorn" g2="Adieresis" k="60" />
+<hkern g1="thorn" g2="Aring" k="60" />
+<hkern g1="thorn" g2="AE" k="63" />
+<hkern g1="thorn" g2="Yacute" k="243" />
+<hkern g1="thorn" g2="icircumflex" k="58" />
+<hkern g1="thorn" g2="idieresis" k="65" />
+<hkern g1="thorn" g2="yacute" k="61" />
+<hkern g1="thorn" g2="ydieresis" k="61" />
+<hkern g1="ydieresis" g2="A" k="125" />
+<hkern g1="ydieresis" g2="J" k="88" />
+<hkern g1="ydieresis" g2="T" k="166" />
+<hkern g1="ydieresis" g2="V" k="60" />
+<hkern g1="ydieresis" g2="X" k="55" />
+<hkern g1="ydieresis" g2="Y" k="63" />
+<hkern g1="ydieresis" g2="Z" k="133" />
+<hkern g1="ydieresis" g2="j" k="227" />
+<hkern g1="ydieresis" g2="Agrave" k="117" />
+<hkern g1="ydieresis" g2="Aacute" k="102" />
+<hkern g1="ydieresis" g2="Acircumflex" k="125" />
+<hkern g1="ydieresis" g2="Atilde" k="117" />
+<hkern g1="ydieresis" g2="Adieresis" k="125" />
+<hkern g1="ydieresis" g2="Aring" k="94" />
+<hkern g1="ydieresis" g2="AE" k="141" />
+<hkern g1="ydieresis" g2="Yacute" k="86" />
+<hkern g1="dotlessi" g2="I" k="51" />
+<hkern g1="dotlessi" g2="T" k="486" />
+<hkern g1="dotlessi" g2="V" k="171" />
+<hkern g1="dotlessi" g2="W" k="81" />
+<hkern g1="dotlessi" g2="Y" k="265" />
+<hkern g1="dotlessi" g2="i" k="63" />
+<hkern g1="dotlessi" g2="j" k="278" />
+<hkern g1="dotlessi" g2="Igrave" k="60" />
+<hkern g1="dotlessi" g2="Iacute" k="66" />
+<hkern g1="dotlessi" g2="Icircumflex" k="73" />
+<hkern g1="dotlessi" g2="Idieresis" k="52" />
+<hkern g1="dotlessi" g2="Yacute" k="265" />
+<hkern g1="dotlessi" g2="igrave" k="55" />
+<hkern g1="dotlessi" g2="iacute" k="52" />
+<hkern g1="dotlessi" g2="icircumflex" k="106" />
+<hkern g1="dotlessi" g2="idieresis" k="113" />
+<hkern g1="dotlessi" g2="dotlessi" k="51" />
+</font>
+</defs>
+</svg>
diff --git a/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.ttf b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.ttf
new file mode 100644
index 0000000..579c924
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.ttf differ
diff --git a/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.woff b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.woff
new file mode 100644
index 0000000..61d4515
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.woff differ
diff --git a/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.woff2 b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.woff2
new file mode 100644
index 0000000..ebf13e8
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-700/Comfortaa-700.woff2 differ
diff --git a/hubs/static/css/fonts/Comfortaa-700/LICENSE.txt b/hubs/static/css/fonts/Comfortaa-700/LICENSE.txt
new file mode 100644
index 0000000..e0bfe25
--- /dev/null
+++ b/hubs/static/css/fonts/Comfortaa-700/LICENSE.txt
@@ -0,0 +1,94 @@
+Copyright (c) 2010, 2011 Johan Aakerlund (aajohan@gmail.com),
+with Reserved Font Name "Comfortaa".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded, 
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.eot b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.eot
new file mode 100644
index 0000000..a350907
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.eot differ
diff --git a/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.svg b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.svg
new file mode 100644
index 0000000..f5d2848
--- /dev/null
+++ b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.svg
@@ -0,0 +1,2620 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs >
+<font id="Comfortaa" horiz-adv-x="1003" ><font-face
+    font-family="Comfortaa"
+    units-per-em="2048"
+    panose-1="2 15 6 3 7 2 0 6 0 3"
+    ascent="2080"
+    descent="-480"
+    alphabetic="0" />
+<glyph unicode=" " glyph-name="space" horiz-adv-x="560" />
+<glyph unicode="!" glyph-name="exclam" horiz-adv-x="400" d="M320 120Q320 70 285 35T200 0Q150 0 115 35T80 120Q80 170 115 205T200 240Q250 240 285 205T320 120ZM120 1520Q120 1553 143 1576T200 1600Q233 1600 256 1577T280 1520V399Q280 367 257 344Q233
+320 200 320Q167 320 144 344Q120 367 120 399V1520Z" />
+<glyph unicode="&quot;" glyph-name="quotedbl" horiz-adv-x="560" d="M220 1220Q220 1195 203 1178T160 1160Q135 1160 118 1177T100 1220L80 1512V1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V1512L220 1220ZM460 1220Q460 1195 443 1178T400
+1160Q375 1160 358 1177T340 1220L320 1512V1520Q320 1553 343 1576T400 1600Q433 1600 456 1577T480 1520V1512L460 1220Z" />
+<glyph unicode="#" glyph-name="numbersign" horiz-adv-x="1280" d="M389 80Q383 47 356 24T295 0Q262 0 243 23T229 80L300 480H140Q107 480 88 504Q73 521 73 545Q73 552 74 560Q80 593 107 616T168 640H328L384 960H224Q191 960 172 983T158 1040Q164 1073
+192 1096T253 1120H413L483 1520Q489 1553 516 1576T577 1600Q610 1600 629 1577T643 1520L573 1120H813L883 1520Q889 1553 916 1576T977 1600Q1010 1600 1029 1577T1043 1520L973 1120H1133Q1166 1120 1185 1097Q1199 1079 1199 1055Q1199 1048 1198 1040Q1193
+1007 1165 984T1104 960H944L888 640H1048Q1081 640 1100 617T1114 560Q1108 527 1081 504T1020 480H860L789 80Q783 47 756 24T695 0Q662 0 643 23T629 80L700 480H460L389 80ZM544 960L488 640H728L784 960H544Z" />
+<glyph unicode="$" glyph-name="dollar" horiz-adv-x="1060" d="M480 1Q470 1 460 2Q262 18 134 170Q113 193 96 219Q80 240 80 267Q80 300 103 323T160 347Q203 347 228 310Q240 291 256 274Q341 172 480 161V805Q346 831 254 939Q147 1065 160 1231Q174 1396
+300 1503Q382 1572 480 1591V1680Q480 1713 503 1736T560 1760Q593 1760 616 1737T640 1680V1590Q773 1564 864 1457Q886 1431 903 1403Q915 1384 915 1360Q915 1327 892 1304T835 1280Q802 1280 779 1304Q770 1312 765 1321Q755 1337 742 1353Q698 1404 640 1424V940Q772
+902 867 791Q980 657 980 487Q980 464 978 441Q962 243 811 115Q732 48 640 20V-80Q640 -113 617 -136T560 -160Q527 -160 504 -137T480 -80V1ZM480 1425Q439 1411 404 1381Q328 1316 320 1218Q312 1119 377 1043Q420 991 480 971V1425ZM640 192Q675 209 707 237Q808
+322 819 454Q830 587 745 688Q699 741 640 769V192Z" />
+<glyph unicode="%" glyph-name="percent" horiz-adv-x="1760" d="M880 1200Q880 1034 763 917T480 800Q314 800 197 917T80 1200Q80 1366 197 1483T480 1600Q646 1600 763 1483T880 1200ZM880 400Q880 566 997 683T1280 800Q1446 800 1563 683T1680 400Q1680 234
+1563 117T1280 0Q1114 0 997 117T880 400ZM480 1440Q381 1440 311 1370T240 1200Q240 1101 310 1031T480 960Q579 960 649 1030T720 1200Q720 1299 650 1369T480 1440ZM1280 640Q1181 640 1111 570T1040 400Q1040 301 1110 231T1280 160Q1379 160 1449 230T1520
+400Q1520 499 1450 569T1280 640ZM320 0Q287 0 264 23T240 80Q240 111 260 134L1375 1567Q1403 1600 1440 1600Q1473 1600 1496 1577T1520 1520Q1520 1493 1504 1472L381 27Q353 0 320 0Z" />
+<glyph unicode="&amp;" glyph-name="ampersand" horiz-adv-x="1440" d="M378 1099L502 974L621 1068Q720 1147 720 1240Q720 1323 662 1381T520 1440Q437 1440 379 1382T320 1240Q320 1157 378 1099ZM857 391L485 764L372 678Q240 576 240 460Q240 324 322 242T520
+160Q636 160 718 242L857 391ZM613 863L967 508L1144 697Q1167 720 1200 720Q1233 720 1256 697T1280 640Q1280 609 1260 586L1080 395L1338 134Q1360 112 1360 80Q1360 47 1337 24T1280 0Q1248 0 1224 22L970 277L831 129Q702 0 520 0Q338 0 209 129T80 460Q80
+642 269 791L375 874L265 985Q160 1091 160 1240Q160 1389 265 1494T520 1600Q669 1600 774 1495T880 1240Q880 1081 734 955L613 863Z" />
+<glyph unicode="&apos;" glyph-name="quotesingle" horiz-adv-x="320" d="M220 1220Q220 1195 203 1178T160 1160Q135 1160 118 1177T100 1220L80 1512V1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V1512L220 1220Z" />
+<glyph unicode="(" glyph-name="parenleft" horiz-adv-x="560" d="M323 1547Q329 1563 342 1577Q366 1600 399 1600Q432 1600 455 1577T479 1520Q477 1496 466 1477Q238 1019 238 561Q238 101 468 -359Q479 -377 479 -400Q479 -433 456 -456T399 -480Q366 -480
+342 -456Q330 -442 323 -426Q80 69 80 562Q80 1055 323 1547Z" />
+<glyph unicode=")" glyph-name="parenright" horiz-adv-x="560" d="M236 1547Q480 1055 480 562Q480 69 236 -426Q228 -442 217 -456Q193 -480 160 -480Q127 -480 104 -457T80 -400Q80 -377 91 -359Q321 101 321 561Q321 1019 93 1477Q82 1496 80 1520Q80 1553
+103 1576T160 1600Q193 1600 217 1577Q230 1563 236 1547Z" />
+<glyph unicode="*" glyph-name="asterisk" horiz-adv-x="780" d="M361 1271L166 1279Q152 1280 139 1284Q108 1295 94 1325Q85 1342 85 1360Q85 1373 90 1386Q101 1418 131 1432T192 1435Q206 1430 216 1422L373 1305L315 1493Q311 1506 311 1520Q311 1553 334
+1576T391 1600Q424 1600 447 1577T471 1520Q471 1506 467 1493L409 1304L567 1422Q578 1430 591 1435Q622 1446 652 1432T693 1386Q698 1372 698 1359Q698 1342 690 1325Q676 1295 645 1284Q631 1280 618 1279L422 1271L583 1159Q594 1152 603 1140Q623 1114 619
+1081T589 1028Q567 1011 530 1012Q497 1016 477 1042Q468 1053 464 1066L392 1247L319 1066Q315 1053 306 1042Q286 1011 242 1011Q216 1011 194 1028Q168 1048 164 1081T180 1140Q189 1152 200 1159L361 1271Z" />
+<glyph unicode="+" glyph-name="plus" horiz-adv-x="1120" d="M480 1200Q480 1233 503 1256T560 1280Q593 1280 616 1257T640 1200V880H960Q993 880 1016 857T1040 800Q1040 767 1017 744T960 720H640V400Q640 367 617 344T560 320Q527 320 504 343T480 400V720H160Q127
+720 104 743T80 800Q80 833 103 856T160 880H480V1200Z" />
+<glyph unicode="," glyph-name="comma" horiz-adv-x="400" d="M115 35Q80 70 80 120Q80 170 115 205T200 240Q250 240 285 205T320 120Q320 -76 233 -208Q215 -240 180 -240Q155 -240 138 -223T120 -180Q120 -155 137 -138Q207 -60 115 35Z" />
+<glyph unicode="-" glyph-name="hyphen" horiz-adv-x="800" d="M160 480Q127 480 104 503T80 560Q80 593 103 616T160 640H640Q673 640 696 617T720 560Q720 527 697 504T640 480H160Z" />
+<glyph unicode="." glyph-name="period" horiz-adv-x="400" d="M320 120Q320 70 285 35T200 0Q150 0 115 35T80 120Q80 170 115 205T200 240Q250 240 285 205T320 120Z" />
+<glyph unicode="/" glyph-name="slash" horiz-adv-x="960" d="M744 1577Q767 1600 800 1600Q833 1600 856 1577T880 1520Q880 1502 873 1486L233 -114Q227 -126 217 -136Q193 -160 160 -160Q127 -160 104 -137T80 -80Q80 -62 87 -46L727 1554Q733 1566 744 1577Z" />
+<glyph unicode="0" glyph-name="zero" horiz-adv-x="1120" d="M80 800Q80 1280 277 1483Q394 1600 560 1600Q726 1600 843 1483Q1040 1280 1040 800Q1040 320 843 117Q726 0 560 0Q394 0 277 117Q80 320 80 800ZM560 1440Q461 1440 390 1369Q240 1200 240 800Q240
+400 390 231Q461 160 560 160Q659 160 730 231Q880 400 880 800Q880 1200 730 1369Q659 1440 560 1440Z" />
+<glyph unicode="1" glyph-name="one" horiz-adv-x="560" d="M480 80Q480 47 457 24T400 0Q367 0 344 23T320 80V1409L191 1366Q176 1360 160 1360Q127 1360 104 1383T80 1440Q80 1473 104 1497Q116 1509 131 1515L371 1595Q384 1600 400 1600Q433 1600 456 1577T480
+1520V80Z" />
+<glyph unicode="2" glyph-name="two" horiz-adv-x="1120" d="M960 160Q993 160 1016 137T1040 80Q1040 47 1017 24T960 0H160Q127 0 104 23T80 80Q80 113 103 137L786 893Q880 987 880 1120Q880 1253 787 1346T560 1440Q427 1440 334 1347T240 1120Q240 1087 217
+1064T160 1040Q127 1040 104 1063T80 1120Q80 1319 220 1459T560 1600Q759 1600 899 1460T1040 1120Q1040 921 899 780L341 160H960Z" />
+<glyph unicode="3" glyph-name="three" horiz-adv-x="1120" d="M560 800Q527 800 504 823T480 880Q480 913 503 936T560 960Q659 960 729 1030T800 1200Q800 1299 730 1369T560 1440Q461 1440 391 1370T320 1200Q320 1167 297 1144T240 1120Q207 1120 184 1143T160
+1200Q160 1366 277 1483T560 1600Q726 1600 843 1483T960 1200Q960 1024 813 889Q859 860 900 820Q1040 679 1040 480Q1040 281 900 141T560 0Q361 0 221 140T80 480Q80 513 103 536T160 560Q193 560 216 537T240 480Q240 347 333 254T560 160Q693 160 786 253T880
+480Q880 613 787 706T560 800Z" />
+<glyph unicode="4" glyph-name="four" horiz-adv-x="1280" d="M800 560V1264L313 560H800ZM160 400Q127 400 104 423T80 480Q80 506 95 527L815 1567Q837 1600 880 1600Q913 1600 936 1577T960 1520V560H1120Q1153 560 1176 537T1200 480Q1200 447 1177 424T1120
+400H960V80Q960 47 937 24T880 0Q847 0 824 23T800 80V400H160Z" />
+<glyph unicode="5" glyph-name="five" horiz-adv-x="1200" d="M960 1600Q993 1600 1016 1577T1040 1520Q1040 1487 1017 1464T960 1440H320V1040H600Q815 1040 967 888T1120 520Q1120 305 968 153T600 0Q385 0 233 152T80 520Q80 553 103 576T160 600Q193 600
+216 577T240 520Q240 371 345 266T600 160Q749 160 854 265T960 520Q960 669 855 774T600 880H240Q207 880 184 903T160 960V1520Q160 1553 183 1576T240 1600H960Z" />
+<glyph unicode="6" glyph-name="six" horiz-adv-x="1120" d="M471 952Q514 960 560 960Q759 960 899 820T1040 480Q1040 281 900 141T560 0Q361 0 221 140T80 480Q80 627 157 742L648 1556Q654 1567 664 1577Q687 1600 720 1600Q753 1600 776 1577T800 1520Q800
+1497 789 1479L471 952ZM880 480Q880 613 787 706T560 800Q427 800 334 707T240 480Q240 347 333 254T560 160Q693 160 786 253T880 480Z" />
+<glyph unicode="7" glyph-name="seven" horiz-adv-x="1120" d="M217 24Q193 0 160 0Q127 0 104 23T80 80Q80 104 96 128L825 1440H160Q127 1440 104 1463T80 1520Q80 1553 103 1576T160 1600H960Q993 1600 1016 1577T1040 1520Q1040 1496 1028 1477L232 45Q225
+32 217 24Z" />
+<glyph unicode="8" glyph-name="eight" horiz-adv-x="1120" d="M560 1440Q461 1440 391 1370T320 1200Q320 1101 390 1031T560 960Q659 960 729 1030T800 1200Q800 1299 730 1369T560 1440ZM560 800Q427 800 334 707T240 480Q240 347 333 254T560 160Q693 160
+786 253T880 480Q880 613 787 706T560 800ZM307 889Q292 902 277 917Q160 1034 160 1200Q160 1366 277 1483T560 1600Q726 1600 843 1483T960 1200Q960 1034 843 917Q828 902 813 889Q859 860 900 820Q1040 679 1040 480Q1040 281 900 141T560 0Q361 0 221 140T80
+480Q80 679 221 820Q261 860 307 889Z" />
+<glyph unicode="9" glyph-name="nine" horiz-adv-x="1120" d="M649 648Q606 640 560 640Q361 640 221 780T80 1120Q80 1319 220 1459T560 1600Q759 1600 899 1460T1040 1120Q1040 973 963 858L472 44Q466 33 457 24Q433 0 400 0Q367 0 344 23T320 80Q320 103 331
+121L649 648ZM240 1120Q240 987 333 894T560 800Q693 800 786 893T880 1120Q880 1253 787 1346T560 1440Q427 1440 334 1347T240 1120Z" />
+<glyph unicode=":" glyph-name="colon" horiz-adv-x="400" d="M320 120Q320 70 285 35T200 0Q150 0 115 35T80 120Q80 170 115 205T200 240Q250 240 285 205T320 120ZM320 1001Q320 951 285 916T200 881Q150 881 115 916T80 1001Q80 1051 115 1086T200 1121Q250
+1121 285 1086T320 1001Z" />
+<glyph unicode=";" glyph-name="semicolon" horiz-adv-x="400" d="M320 1001Q320 951 285 916T200 881Q150 881 115 916T80 1001Q80 1051 115 1086T200 1121Q250 1121 285 1086T320 1001ZM115 35Q80 70 80 120Q80 170 115 205T200 240Q250 240 285 205T320 120Q320
+-76 233 -208Q211 -240 180 -240Q155 -240 138 -223T120 -180Q120 -155 137 -138Q207 -60 115 35Z" />
+<glyph unicode="&lt;" glyph-name="less" horiz-adv-x="1120" d="M124 792L920 1270Q938 1280 960 1280Q993 1280 1016 1257T1040 1200Q1040 1157 999 1130L315 720L999 310Q1040 283 1040 240Q1040 207 1017 184T960 160Q938 160 920 170L124 648Q80 676 80 720Q80
+764 124 792Z" />
+<glyph unicode="=" glyph-name="equal" horiz-adv-x="1040" d="M160 880Q127 880 104 903T80 960Q80 993 103 1016T160 1040H880Q913 1040 936 1017T960 960Q960 927 937 904T880 880H160ZM880 560Q913 560 936 537T960 480Q960 447 937 424T880 399H160Q127 400
+104 423T80 480Q80 513 103 536T160 560H880Z" />
+<glyph unicode="&gt;" glyph-name="greater" horiz-adv-x="1120" d="M1040 720Q1040 676 996 648L200 170Q182 160 160 160Q127 160 104 183T80 240Q80 283 121 310L805 720L121 1130Q80 1157 80 1200Q80 1233 103 1256T160 1280Q182 1280 200 1270L996 792Q1040
+764 1040 720Z" />
+<glyph unicode="?" glyph-name="question" horiz-adv-x="1120" d="M240 1120Q240 1087 217 1064T160 1040Q127 1040 104 1063T80 1120Q80 1319 220 1459T560 1600Q759 1600 899 1460T1040 1120Q1040 921 899 780L734 627Q640 533 640 400Q640 367 617 344T560
+320Q527 320 504 343T480 400Q480 599 621 740L786 893Q880 987 880 1120Q880 1253 787 1346T560 1440Q427 1440 334 1347T240 1120ZM680 120Q680 70 645 35T560 0Q510 0 475 35T440 120Q440 170 475 205T560 240Q610 240 645 205T680 120Z" />
+<glyph unicode="@" glyph-name="at" horiz-adv-x="2240" d="M1120 960Q954 960 837 843T720 560Q720 394 837 277T1120 160Q1286 160 1403 277T1520 560Q1520 726 1403 843T1120 960ZM1520 167Q1352 0 1120 0Q888 0 724 164T560 560Q560 792 724 956T1120 1120Q1352
+1120 1516 956T1680 560V160Q1680 80 1760 80Q2000 80 2000 560Q2000 925 1743 1182T1120 1440Q755 1440 498 1183T240 560Q240 195 497 -62T1120 -320Q1316 -320 1482 -246Q1500 -235 1522 -235Q1555 -235 1578 -258T1602 -315Q1602 -348 1579 -371Q1566 -384
+1551 -390Q1354 -480 1120 -480Q689 -480 385 -176T80 560Q80 991 384 1295T1120 1600Q1551 1600 1855 1296T2160 560Q2160 -80 1760 -80Q1520 -80 1520 167Z" />
+<glyph unicode="A" glyph-name="A" horiz-adv-x="1440" d="M433 560L234 49Q228 35 217 23Q193 0 160 0Q127 0 104 23T80 80Q80 99 87 114L643 1544Q649 1562 664 1577Q687 1600 720 1600Q753 1600 777 1577Q791 1562 797 1544L1353 114Q1360 99 1360 80Q1360
+47 1337 24T1280 0Q1247 0 1224 23Q1212 35 1206 49L1007 560H433ZM945 720L720 1299L495 720H945Z" />
+<glyph unicode="B" glyph-name="B" horiz-adv-x="1120" d="M240 1440V960H480Q579 960 649 1030T720 1200Q720 1299 650 1369T480 1440H240ZM240 800V160H560Q693 160 786 253T880 480Q880 613 787 706T560 800H240ZM160 1600H480Q646 1600 763 1483T880 1200Q880
+1034 763 917Q837 882 900 820Q1040 679 1040 480Q1040 281 900 141T560 0H160Q127 0 104 23T80 80V1520Q80 1553 103 1576T160 1600Z" />
+<glyph unicode="C" glyph-name="C" horiz-adv-x="1480" d="M1326 314Q1359 314 1382 291T1406 234Q1406 201 1383 178Q1160 0 880 0Q549 0 315 234T80 800Q80 1131 314 1365T880 1600Q1166 1600 1389 1417Q1412 1393 1412 1360Q1412 1327 1389 1304T1332 1280Q1299
+1280 1275 1304Q1106 1440 880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1109 160 1280 300Q1300 314 1326 314Z" />
+<glyph unicode="D" glyph-name="D" horiz-adv-x="1360" d="M480 160Q745 160 932 347T1120 800Q1120 1065 933 1252T480 1440H240V160H480ZM480 1600Q811 1600 1045 1366T1280 800Q1280 469 1046 235T480 0H160Q127 0 104 23T80 80V1520Q80 1553 103 1576T160 1600H480Z" />
+<glyph unicode="E" glyph-name="E" horiz-adv-x="1280" d="M160 1600H1120Q1153 1600 1176 1577T1200 1520Q1200 1487 1177 1464T1120 1440H240V880H880Q913 880 936 857T960 800Q960 767 937 744T880 720H240V160H1120Q1153 160 1176 137T1200 80Q1200 47 1177
+24T1120 0H160Q127 0 104 23T80 80V1520Q80 1553 103 1576T160 1600Z" />
+<glyph unicode="F" glyph-name="F" horiz-adv-x="1280" d="M160 1600H1120Q1153 1600 1176 1577T1200 1520Q1200 1487 1177 1464T1120 1440H240V880H880Q913 880 936 857T960 800Q960 767 937 744T880 720H240V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1520Q80
+1553 103 1576T160 1600Z" />
+<glyph unicode="G" glyph-name="G" horiz-adv-x="1500" d="M1406 234Q1406 201 1383 178Q1160 0 880 0Q549 0 315 234T80 800Q80 1131 314 1365T880 1600Q1166 1600 1389 1417Q1412 1393 1412 1360Q1412 1327 1389 1304T1332 1280Q1299 1280 1275 1304Q1106 1440
+880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1087 160 1246 274V640H930Q897 640 874 663T850 720Q850 753 873 776T930 800H1327Q1359 800 1383 777Q1406 753 1406 720V234Z" />
+<glyph unicode="H" glyph-name="H" horiz-adv-x="1280" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V880H1040V1520Q1040 1553 1063 1576T1120 1600Q1153 1600 1176 1577T1200 1520V80Q1200 47 1177 24T1120 0Q1087 0 1064 23T1040 80V720H240V80Q240
+47 217 24T160 0Q127 0 104 23T80 80V1520Z" />
+<glyph unicode="I" glyph-name="I" horiz-adv-x="480" d="M160 1520Q160 1553 183 1576T240 1600Q273 1600 296 1577T320 1520V80Q320 47 297 24T240 0Q207 0 184 23T160 80V1520Z" />
+<glyph unicode="J" glyph-name="J" horiz-adv-x="1120" d="M80 480Q80 513 103 536T160 560Q193 560 216 537T240 480Q240 347 333 254T560 160Q693 160 786 253T880 480V1520Q880 1553 903 1576T960 1600Q993 1600 1016 1577T1040 1520V480Q1040 281 900 141T560
+0Q361 0 221 140T80 480Z" />
+<glyph unicode="K" glyph-name="K" horiz-adv-x="1200" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V834L981 1575Q1007 1600 1040 1600Q1073 1600 1096 1577T1120 1520Q1120 1487 1097 1463L535 901L1105 128Q1120 107 1120 83Q1120 41
+1088 16Q1066 0 1042 0Q998 0 974 34L420 786L240 606V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1520Z" />
+<glyph unicode="L" glyph-name="L" horiz-adv-x="1200" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V160H1040Q1073 160 1096 137T1120 80Q1120 47 1097 24T1040 0H160Q127 0 104 23T80 80V1520Z" />
+<glyph unicode="M" glyph-name="M" horiz-adv-x="1760" d="M806 49L240 1181V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1520Q80 1553 103 1576T160 1600Q208 1600 231 1558L880 259L1529 1558Q1552 1600 1600 1600Q1633 1600 1656 1577T1680 1520V80Q1680 47
+1657 24T1600 0Q1567 0 1544 23T1520 80V1181L949 39Q928 0 880 0Q830 0 806 49Z" />
+<glyph unicode="N" glyph-name="N" horiz-adv-x="1440" d="M240 80Q240 47 217 24T160 0Q127 0 104 23T80 80V1520Q80 1553 103 1576T160 1600Q196 1600 222 1571L1200 313V1520Q1200 1553 1223 1576T1280 1600Q1313 1600 1336 1577T1360 1520V80Q1360 47 1337
+24T1280 0Q1245 0 1220 26L240 1286V80Z" />
+<glyph unicode="O" glyph-name="O" horiz-adv-x="1760" d="M880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1145 160 1332 347T1520 800Q1520 1065 1333 1252T880 1440ZM1680 800Q1680 469 1446 235T880 0Q549 0 315 234T80 800Q80 1131 314 1365T880
+1600Q1211 1600 1445 1366T1680 800Z" />
+<glyph unicode="P" glyph-name="P" horiz-adv-x="1080" d="M240 1440V720H480Q629 720 734 825T840 1080Q840 1229 735 1334T480 1440H240ZM160 1600H480Q695 1600 847 1448T1000 1080Q1000 865 848 713T480 560H240V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1520Q80
+1553 103 1576T160 1600Z" />
+<glyph unicode="Q" glyph-name="Q" horiz-adv-x="1760" d="M1386 180Q1170 0 880 0Q549 0 315 234T80 800Q80 1131 314 1365T880 1600Q1211 1600 1445 1366T1680 800Q1680 510 1500 294L1658 136Q1680 112 1680 80Q1680 47 1657 24T1600 0Q1567 0 1542 24L1386
+180ZM1272 294L1103 463Q1080 487 1080 520Q1080 553 1103 576T1160 600Q1193 600 1217 577L1386 408Q1520 576 1520 800Q1520 1065 1333 1252T880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1104 160 1272 294Z" />
+<glyph unicode="R" glyph-name="R" horiz-adv-x="1200" d="M240 1440V800H560Q693 800 786 893T880 1120Q880 1253 787 1346T560 1440H240ZM160 1600H560Q759 1600 899 1460T1040 1120Q1040 921 900 781Q835 716 759 682L1107 124Q1120 105 1120 80Q1120 47 1097
+24T1040 0Q997 0 970 41L595 641Q578 640 560 640H240V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1520Q80 1553 103 1576T160 1600Z" />
+<glyph unicode="S" glyph-name="S" horiz-adv-x="1060" d="M96 219Q80 240 80 267Q80 300 103 323T160 347Q203 347 228 310Q240 291 256 274Q341 172 474 161Q606 151 707 236T819 454Q830 587 745 687T526 799Q361 813 254 939T160 1231Q174 1396 300 1503Q413
+1600 560 1600Q734 1600 864 1457Q886 1431 903 1403Q915 1384 915 1360Q915 1327 892 1304T835 1280Q797 1280 779 1304Q761 1328 742 1353Q677 1429 579 1437Q480 1445 404 1381T320 1218Q312 1119 376 1043T539 959Q738 942 867 791Q980 657 980 487Q980 464
+978 441Q962 243 811 115Q676 0 504 0Q289 0 134 170Q113 193 96 219Z" />
+<glyph unicode="T" glyph-name="T" horiz-adv-x="1360" d="M160 1440Q127 1440 104 1463T80 1520Q80 1553 103 1576T160 1600H1200Q1233 1600 1256 1577T1280 1520Q1280 1487 1257 1464T1200 1440H760V80Q760 47 737 24T680 0Q647 0 624 23T600 80V1440H160Z" />
+<glyph unicode="U" glyph-name="U" horiz-adv-x="1280" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V560Q240 394 357 277T640 160Q806 160 923 277T1040 560V1520Q1040 1553 1063 1576T1120 1600Q1153 1600 1176 1577T1200 1520V560Q1200
+328 1036 164T640 0Q408 0 244 164T80 560V1520Z" />
+<glyph unicode="V" glyph-name="V" horiz-adv-x="1440" d="M777 24Q753 0 720 0Q687 0 664 24Q653 34 647 50L90 1475Q80 1498 80 1520Q80 1553 103 1576T160 1600Q213 1600 233 1554L720 301L1207 1554Q1227 1600 1280 1600Q1313 1600 1336 1577T1360 1520Q1360
+1498 1350 1475L793 50Q787 34 777 24Z" />
+<glyph unicode="W" glyph-name="W" horiz-adv-x="1920" d="M904 1577Q927 1600 960 1600Q993 1600 1017 1577Q1030 1563 1036 1547L1360 379L1684 1547Q1690 1563 1704 1577Q1727 1600 1760 1600Q1793 1600 1816 1577T1840 1520Q1840 1503 1834 1485L1442 67Q1434
+42 1417 24Q1393 0 1360 0Q1327 0 1304 24Q1286 42 1279 66L960 1218L642 67Q634 42 617 24Q593 0 560 0Q527 0 504 24Q486 42 479 66L86 1485Q80 1503 80 1520Q80 1553 103 1576T160 1600Q193 1600 217 1577Q230 1563 236 1547L560 379L884 1547Q888 1562 904
+1577Z" />
+<glyph unicode="X" glyph-name="X" horiz-adv-x="1440" d="M720 931L1214 1566Q1242 1600 1280 1600Q1313 1600 1336 1577T1360 1520Q1360 1494 1346 1474L822 800L1343 130Q1360 108 1360 80Q1360 47 1337 24T1280 0Q1242 0 1219 28L720 669L221 28Q198 0 160
+0Q127 0 104 23T80 80Q80 108 97 130L618 800L94 1474Q80 1494 80 1520Q80 1553 103 1576T160 1600Q198 1600 226 1566L720 931Z" />
+<glyph unicode="Y" glyph-name="Y" horiz-adv-x="1280" d="M720 80Q720 47 697 24T640 0Q607 0 584 23T560 80V776L93 1475Q80 1495 80 1520Q80 1553 103 1576T160 1600Q201 1600 225 1567L640 945L1055 1567Q1079 1600 1120 1600Q1153 1600 1176 1577T1200 1520Q1200
+1495 1187 1475L720 776V80Z" />
+<glyph unicode="Z" glyph-name="Z" horiz-adv-x="1440" d="M160 1440Q127 1440 104 1463T80 1520Q80 1553 103 1576T160 1600H1280Q1313 1600 1336 1577T1360 1520Q1360 1494 1346 1474L324 160H1280Q1313 160 1336 137T1360 80Q1360 47 1337 24T1280 0H160Q127
+0 104 23T80 80Q80 108 97 130L1116 1440H160Z" />
+<glyph unicode="[" glyph-name="bracketleft" horiz-adv-x="640" d="M160 1600H480Q513 1600 536 1577T560 1520Q560 1487 537 1464T480 1440H240V-320H480Q513 -320 536 -343T560 -400Q560 -433 537 -456T480 -480H160Q127 -480 104 -457T80 -400V1520Q80 1553
+103 1576T160 1600Z" />
+<glyph unicode="\" glyph-name="backslash" horiz-adv-x="960" d="M233 1554L873 -46Q880 -62 880 -80Q880 -113 857 -136T800 -160Q767 -160 743 -136Q733 -126 727 -114L87 1486Q80 1502 80 1520Q80 1553 103 1576T160 1600Q193 1600 217 1577Q227 1566 233 1554Z" />
+<glyph unicode="]" glyph-name="bracketright" horiz-adv-x="640" d="M560 1520V-400Q560 -433 537 -456T480 -480H160Q127 -480 104 -457T80 -400Q80 -367 103 -344T160 -320H400V1440H160Q127 1440 104 1463T80 1520Q80 1553 103 1576T160 1600H480Q513 1600
+536 1577T560 1520Z" />
+<glyph unicode="^" glyph-name="asciicircum" horiz-adv-x="960" d="M480 1375L224 991Q200 960 160 960Q127 960 104 983T80 1040Q80 1063 91 1081L415 1567Q437 1600 480 1600Q523 1600 545 1567L869 1081Q880 1063 880 1040Q880 1007 857 984T800 960Q760 960
+736 991L480 1375Z" />
+<glyph unicode="_" glyph-name="underscore" horiz-adv-x="960" d="M0 -160Q-33 -160 -56 -137T-80 -80Q-80 -47 -57 -24T0 0H960Q993 0 1016 -23T1040 -80Q1040 -113 1017 -136T960 -160H0Z" />
+<glyph unicode="`" glyph-name="grave" horiz-adv-x="560" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 217 1577L460 1334Q480 1311 480 1280Q480 1247 457 1224T400 1200Q368 1200 345 1221L102 1464Q80 1488 80 1520Z" />
+<glyph unicode="a" glyph-name="a" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1040 168Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872 1120 1036
+956T1200 560V80Q1200 47 1177 24T1120 0Q1087 0 1064 23T1040 80V168Z" />
+<glyph unicode="b" glyph-name="b" horiz-adv-x="1280" d="M640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960Q474 960 357 843T240 560Q240 394 357 277T640 160ZM240 952Q242 954 244 956Q408 1120 640 1120Q872 1120 1036 956T1200 560Q1200 328
+1036 164T640 0Q408 0 244 164T80 560V1522Q80 1555 103 1578T160 1602Q193 1602 216 1579T240 1522V952Z" />
+<glyph unicode="c" glyph-name="c" horiz-adv-x="1120" d="M950 274Q983 274 1006 251T1030 194Q1030 161 1005 135Q850 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q850 1120 1005 985Q1033 960 1033 923Q1033 890 1010 867T953 843Q924 843 902 861Q790
+960 640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q790 160 901 258Q922 274 950 274Z" />
+<glyph unicode="d" glyph-name="d" horiz-adv-x="1280" d="M1040 560Q1040 726 923 843T640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560ZM1040 1522Q1040 1555 1063 1578T1120 1602Q1153 1602 1176 1579T1200 1522V560Q1200
+328 1036 164T640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872 1120 1036 956Q1038 954 1040 952V1522Z" />
+<glyph unicode="e" glyph-name="e" horiz-adv-x="1280" d="M1033 640Q1011 755 923 843Q806 960 640 960Q474 960 357 843Q269 755 247 640H1033ZM948 272Q981 272 1004 249T1028 192Q1028 159 1005 135Q850 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640
+1120Q872 1120 1036 956T1200 560Q1200 527 1177 504T1120 480H247Q269 365 357 277Q474 160 640 160Q790 160 898 255Q920 272 948 272Z" />
+<glyph unicode="f" glyph-name="f" horiz-adv-x="800" d="M720 1600Q753 1600 776 1577T800 1520Q800 1487 777 1464T720 1440Q400 1440 400 1120V1060H641Q674 1060 697 1037T721 980Q721 947 698 924T641 900H400V80Q400 47 377 24T320 0Q287 0 264 23T240 80V900H160Q127
+900 104 923T80 980Q80 1013 103 1036T160 1060H240V1120Q240 1600 720 1600Z" />
+<glyph unicode="g" glyph-name="g" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1040 168Q1038 166 1036 164Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640
+1120Q872 1120 1036 956T1200 560V0Q1200 -175 1074 -304Q898 -480 649 -480Q400 -480 225 -304Q160 -240 119 -165Q107 -147 107 -123Q107 -90 130 -67T187 -43Q220 -43 244 -66Q254 -77 261 -90Q291 -144 338 -191Q467 -320 649 -320Q831 -320 960 -191Q1040
+-95 1040 0V168Z" />
+<glyph unicode="h" glyph-name="h" horiz-adv-x="1200" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V975Q390 1120 600 1120Q815 1120 967 968T1120 600V80Q1120 47 1097 24T1040 0Q1007 0 984 23T960 80V600Q960 749 855 854T600 960Q451
+960 346 855T240 600V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1520Z" />
+<glyph unicode="i" glyph-name="i" horiz-adv-x="480" d="M340 1360Q340 1319 311 1290T240 1260Q199 1260 170 1289T140 1360Q140 1401 169 1430T240 1460Q281 1460 310 1431T340 1360ZM160 1040Q160 1073 183 1096T240 1120Q273 1120 296 1097T320 1040V80Q320
+47 297 24T240 0Q207 0 184 23T160 80V1040Z" />
+<glyph unicode="j" glyph-name="j" horiz-adv-x="656" d="M580 1360Q580 1319 551 1290T480 1260Q439 1260 410 1289T380 1360Q380 1401 409 1430T480 1460Q521 1460 550 1431T580 1360ZM400 0V1040Q400 1073 423 1096T480 1120Q513 1120 536 1097T560 1040V0Q560
+-199 420 -339T80 -480Q47 -480 24 -457T0 -400Q0 -367 23 -344T80 -320Q213 -320 306 -227T400 0Z" />
+<glyph unicode="k" glyph-name="k" horiz-adv-x="1120" d="M240 668L917 1108Q936 1120 960 1120Q993 1120 1016 1097T1040 1040Q1040 1007 1017 984Q1011 978 1006 974L542 672L1018 136Q1040 112 1040 80Q1040 47 1017 24T960 0Q927 0 902 24L405 584L240 477V80Q240
+47 217 24T160 0Q127 0 104 23T80 80V1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V668Z" />
+<glyph unicode="l" glyph-name="l" horiz-adv-x="480" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V160H320Q353 160 376 137T400 80Q400 47 377 24T320 0H160Q127 0 104 23T80 80V1520Z" />
+<glyph unicode="m" glyph-name="m" horiz-adv-x="1760" d="M240 80Q240 47 217 24T160 0Q127 0 104 23T80 80V1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V1019Q359 1120 520 1120Q702 1120 831 991Q858 964 880 934Q902 964 929 991Q1058 1120
+1240 1120Q1422 1120 1551 991T1680 680V80Q1680 47 1657 24T1600 0Q1567 0 1544 23T1520 80V680Q1520 796 1438 878T1240 960Q1124 960 1042 878T960 680V80Q960 47 937 24T880 0Q847 0 824 23T800 80V680Q800 796 718 878T520 960Q404 960 322 878T240 680V80Z"
+/>
+<glyph unicode="n" glyph-name="n" horiz-adv-x="1200" d="M80 1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V975Q390 1120 600 1120Q815 1120 967 968T1120 600V80Q1120 47 1097 24T1040 0Q1007 0 984 23T960 80V600Q960 749 855 854T600 960Q451
+960 346 855T240 600V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1040Z" />
+<glyph unicode="o" glyph-name="o" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164T640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872 1120 1036 956T1200 560ZM640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040
+726 923 843T640 960Z" />
+<glyph unicode="p" glyph-name="p" horiz-adv-x="1280" d="M240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960Q474 960 357 843T240 560ZM240 -400Q240 -433 217 -456T160 -480Q127 -480 104 -457T80 -400V560Q80 792 244
+956T640 1120Q872 1120 1036 956T1200 560Q1200 328 1036 164T640 0Q408 0 244 164Q242 166 240 168V-400Z" />
+<glyph unicode="q" glyph-name="q" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1040 168Q1038 166 1036 164Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640
+1120Q872 1120 1036 956T1200 560V-400Q1200 -433 1177 -456T1120 -480Q1087 -480 1064 -457T1040 -400V168Z" />
+<glyph unicode="r" glyph-name="r" horiz-adv-x="960" d="M80 1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V952Q408 1120 640 1120Q757 1120 855 1080Q873 1073 888 1059Q911 1035 911 1002Q911 969 888 946T831 922Q812 922 796 930Q725 960
+640 960Q474 960 357 843T240 560V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1040Z" />
+<glyph unicode="s" glyph-name="s" horiz-adv-x="1060" d="M278 560Q187 594 151 631Q80 701 80 800Q80 899 154 973Q298 1120 530 1120Q781 1120 960 919Q976 900 975 872Q975 839 952 816T895 792Q862 792 842 813T813 843Q696 960 530 960Q364 960 265 856Q241
+827 241 787Q244 740 290 723L782 560Q873 526 909 489Q980 419 980 320Q980 221 906 147Q762 0 530 0Q278 0 100 201Q85 222 85 248Q85 281 108 304T165 328Q198 328 218 307T247 277Q364 160 530 160Q696 160 795 264Q819 293 819 333Q816 380 770 397L278 560Z"
+/>
+<glyph unicode="t" glyph-name="t" horiz-adv-x="800" d="M640 160Q673 160 696 137T720 80Q720 47 697 24T640 0Q240 0 240 400V960H160Q127 960 104 983T80 1040Q80 1073 103 1096T160 1120H240V1520Q240 1553 263 1576T320 1600Q353 1600 376 1577T400 1520V1120H561Q594
+1120 617 1097T641 1040Q641 1007 618 984T561 960H400V400Q400 160 640 160Z" />
+<glyph unicode="u" glyph-name="u" horiz-adv-x="1200" d="M1120 80Q1120 47 1097 24T1040 0Q1007 0 984 23T960 80V145Q810 0 600 0Q385 0 233 152T80 520V1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V520Q240 371 345 266T600 160Q749 160 854
+265T960 520V1040Q960 1073 983 1096T1040 1120Q1073 1120 1096 1097T1120 1040V80Z" />
+<glyph unicode="v" glyph-name="v" horiz-adv-x="1200" d="M657 22Q635 0 600 0Q565 0 543 23Q536 29 530 42L86 1009Q80 1023 80 1040Q80 1073 103 1096T160 1120Q193 1120 217 1097Q225 1089 232 1076L600 272L968 1076Q975 1089 984 1097Q1007 1120 1040 1120Q1073
+1120 1096 1097T1120 1040Q1120 1023 1114 1009L670 42Q664 29 657 22Z" />
+<glyph unicode="w" glyph-name="w" horiz-adv-x="1600" d="M744 1097Q767 1120 800 1120Q833 1120 857 1097Q872 1081 878 1060L1120 333L1367 1074Q1373 1086 1384 1097Q1407 1120 1440 1120Q1473 1120 1496 1097T1520 1040Q1520 1024 1514 1009L1195 51Q1189
+36 1177 22Q1153 0 1120 0Q1087 0 1064 22Q1051 36 1045 51L800 787L555 51Q549 36 537 22Q513 0 480 0Q447 0 424 22Q411 36 405 51L86 1009Q80 1024 80 1040Q80 1073 103 1096T160 1120Q193 1120 217 1097Q227 1086 233 1074L480 333L722 1060Q729 1081 744 1097Z"
+/>
+<glyph unicode="x" glyph-name="x" horiz-adv-x="1120" d="M456 561L99 988Q80 1010 80 1040Q80 1073 103 1096T160 1120Q193 1120 219 1095L560 686L901 1095Q927 1120 960 1120Q993 1120 1016 1097T1040 1040Q1040 1010 1021 988L664 561L1024 129Q1040 108
+1040 80Q1040 47 1017 24T960 0Q927 0 904 24L560 436L216 24Q193 0 160 0Q127 0 104 23T80 80Q80 108 96 129L456 561Z" />
+<glyph unicode="y" glyph-name="y" horiz-adv-x="1120" d="M473 81L89 1003Q80 1020 80 1040Q80 1073 103 1096T160 1120Q193 1120 217 1097Q230 1083 236 1067L560 290L884 1067Q890 1083 904 1097Q927 1120 960 1120Q993 1120 1016 1097T1040 1040Q1040 1020
+1031 1003L435 -427Q429 -443 416 -456Q392 -480 359 -480Q326 -480 303 -457T279 -400Q279 -380 288 -363L473 81Z" />
+<glyph unicode="z" glyph-name="z" horiz-adv-x="1120" d="M960 160Q993 160 1016 137T1040 80Q1040 47 1017 24T960 0H160Q127 0 104 23T80 80Q80 108 96 129L789 960H160Q127 960 104 983T80 1040Q80 1073 103 1096T160 1120H960Q993 1120 1016 1097T1040 1040Q1040
+1010 1021 988L330 160H960Z" />
+<glyph unicode="{" glyph-name="braceleft" horiz-adv-x="800" d="M640 1600Q673 1600 696 1577T720 1520Q720 1487 697 1464T640 1440Q480 1440 480 1280V800Q480 640 400 560Q480 480 480 320V-160Q480 -320 640 -320Q673 -320 696 -343T720 -400Q720 -433 697
+-456T640 -480Q320 -480 320 -160V320Q320 480 160 480Q127 480 104 503T80 560Q80 593 103 616T160 640Q320 640 320 800V1280Q320 1600 640 1600Z" />
+<glyph unicode="|" glyph-name="bar" horiz-adv-x="800" d="M320 1520Q320 1553 343 1576T400 1600Q433 1600 456 1577T480 1520V-400Q480 -433 457 -456T400 -480Q367 -480 344 -457T320 -400V1520Z" />
+<glyph unicode="}" glyph-name="braceright" horiz-adv-x="800" d="M480 1280V800Q480 640 640 640Q673 640 696 617T720 560Q720 527 697 504T640 480Q480 480 480 320V-160Q480 -480 160 -480Q127 -480 104 -457T80 -400Q80 -367 103 -344T160 -320Q320 -320
+320 -160V320Q320 480 400 560Q320 640 320 800V1280Q320 1440 160 1440Q127 1440 104 1463T80 1520Q80 1553 103 1576T160 1600Q480 1600 480 1280Z" />
+<glyph unicode="~" glyph-name="asciitilde" horiz-adv-x="960" d="M532 687Q442 607 320 607Q187 607 93 701Q71 725 71 757Q71 790 94 813T151 837Q183 837 207 815Q254 767 320 767Q376 767 420 802Q509 882 632 882Q765 882 859 788Q881 764 881 732Q881 699
+858 676T801 652Q769 652 745 674Q698 722 632 722Q575 722 532 687Z" />
+<glyph unicode="&#xa0;" glyph-name="space" horiz-adv-x="560" />
+<glyph unicode="&#xa1;" glyph-name="exclamdown" horiz-adv-x="400" d="M200 879Q150 879 115 914T80 999Q80 1049 115 1084T200 1119Q250 1119 285 1084T320 999Q320 949 285 914T200 879ZM120 720Q120 752 144 775Q167 799 200 799Q233 799 257 775Q280 752
+280 720V-400Q280 -433 257 -456T200 -480Q167 -480 144 -457T120 -400V720Z" />
+<glyph unicode="&#xa2;" glyph-name="cent" horiz-adv-x="1120" d="M361 280L633 960Q476 955 364 843Q247 726 247 560Q247 396 361 280ZM497 188Q566 160 647 160Q797 160 908 258Q929 274 957 274Q990 274 1013 251T1037 194Q1037 161 1012 135Q857 0 647 0Q534
+0 438 39L315 -269Q303 -300 273 -313Q257 -320 241 -320Q226 -320 211 -314Q180 -302 167 -272T166 -210L298 121Q274 141 251 164Q87 328 87 560Q87 792 251 956T647 1120Q672 1120 696 1118L805 1390Q818 1421 849 1434Q862 1440 880 1440Q895 1440 909 1435Q940
+1423 953 1393T954 1331L855 1082Q939 1048 1012 985Q1040 960 1040 923Q1040 890 1017 867T960 843Q931 843 909 861Q856 908 795 932L497 188Z" />
+<glyph unicode="&#xa3;" glyph-name="sterling" horiz-adv-x="1040" d="M240 0Q207 0 184 23T160 80Q160 97 166 112Q283 385 279 640H160Q127 640 104 663T80 720Q80 753 103 776T160 800H265Q243 927 190 1050H191Q160 1125 160 1200Q160 1366 277 1483T560
+1600Q726 1600 843 1483Q872 1454 894 1422Q910 1400 910 1372Q910 1339 887 1316T830 1292Q793 1292 774 1316Q757 1341 730 1370Q659 1440 560 1440Q461 1440 391 1370T320 1200Q320 1155 339 1110Q404 959 427 800H720Q753 800 776 777T800 720Q800 687 777
+664T720 640H439Q441 408 356 160H750L810 280Q831 320 880 320Q913 320 936 297T960 240Q960 219 951 202L874 48Q868 35 857 24Q833 0 800 0H240Z" />
+<glyph unicode="&#xa4;" glyph-name="currency" horiz-adv-x="960" d="M480 910Q414 910 367 863T320 750Q320 684 367 637T480 590Q546 590 593 637T640 750Q640 816 593 863T480 910ZM714 1097Q737 1120 770 1120Q803 1120 826 1097T850 1040Q850 1007 826 982L755
+916Q800 842 800 750Q800 661 758 589L827 517Q850 493 850 460Q850 427 827 404T770 380Q738 380 716 402L715 401L646 475Q572 430 480 430Q391 430 320 472L243 400Q221 380 190 380Q157 380 134 403T110 460Q110 493 134 517L206 584Q160 657 160 750Q160 839
+202 911L134 984Q110 1007 110 1040Q110 1073 133 1096T190 1120Q222 1120 245 1099L314 1025Q388 1070 480 1070Q569 1070 641 1028L714 1097Z" />
+<glyph unicode="&#xa5;" glyph-name="yen" horiz-adv-x="1280" d="M160 880Q127 880 104 903T80 960Q80 993 103 1016T160 1040H384L93 1475Q80 1495 80 1520Q80 1553 103 1576T160 1600Q201 1600 225 1567L640 945L1055 1567Q1079 1600 1120 1600Q1153 1600 1176
+1577T1200 1520Q1200 1495 1187 1475L896 1040H1121Q1153 1040 1177 1017Q1200 993 1200 960Q1200 927 1177 904Q1153 880 1121 880H789L720 776V640H1120Q1153 640 1176 617T1200 560Q1200 527 1177 504T1120 480H720V80Q720 47 697 24T640 0Q607 0 584 23T560
+80V480H160Q127 480 104 503T80 560Q80 593 103 616T160 640H560V776L491 880H160Z" />
+<glyph unicode="&#xa6;" glyph-name="brokenbar" horiz-adv-x="480" d="M160 1680Q160 1713 183 1736T240 1760Q273 1760 296 1737T320 1680V960Q320 927 297 904T240 880Q207 880 184 903T160 960V1680ZM320 -400Q320 -433 297 -456T240 -480Q207 -480 184 -457T160
+-400V320Q160 353 183 376T240 400Q273 400 296 377T320 320V-400Z" />
+<glyph unicode="&#xa7;" glyph-name="section" horiz-adv-x="960" d="M480 160Q314 160 197 277T80 560Q80 726 197 843Q217 863 239 880Q217 897 197 917Q80 1034 80 1200Q80 1366 197 1483T480 1600Q646 1600 763 1483T880 1200Q880 1167 857 1144T800 1120Q767
+1120 744 1143T720 1200Q720 1299 650 1369T480 1440Q381 1440 311 1370T240 1200Q240 1101 310 1031T480 960Q646 960 763 843T880 560Q880 394 763 277Q743 257 721 240Q743 223 763 203Q880 86 880 -80Q880 -246 763 -363T480 -480Q314 -480 197 -363T80 -80Q80
+-47 103 -24T160 0Q193 0 216 -23T240 -80Q240 -179 310 -249T480 -320Q579 -320 649 -250T720 -80Q720 19 650 89T480 160ZM480 800Q381 800 311 730T240 560Q240 461 310 391T480 320Q579 320 649 390T720 560Q720 659 650 729T480 800Z" />
+<glyph unicode="&#xa8;" glyph-name="dieresis" horiz-adv-x="960" d="M339 1360Q339 1319 310 1290T239 1260Q198 1260 169 1289T139 1360Q139 1401 168 1430T239 1460Q280 1460 309 1431T339 1360ZM819 1360Q819 1319 790 1290T719 1260Q678 1260 649 1289T619
+1360Q619 1401 648 1430T719 1460Q760 1460 789 1431T819 1360Z" />
+<glyph unicode="&#xa9;" glyph-name="copyright" horiz-adv-x="1760" d="M1190 514Q1223 514 1246 491T1270 434Q1270 401 1245 375Q1090 240 880 240Q648 240 484 404T320 800Q320 1032 484 1196T880 1360Q1090 1360 1245 1225Q1273 1200 1273 1163Q1273 1130
+1250 1107T1193 1083Q1164 1083 1142 1101Q1030 1200 880 1200Q714 1200 597 1083T480 800Q480 634 597 517T880 400Q1030 400 1141 498Q1162 514 1190 514ZM1675 798Q1675 467 1442 234T878 0Q547 0 314 233T80 798Q80 1128 313 1361T878 1595Q1208 1595 1441
+1362T1675 798ZM878 1472Q598 1472 401 1275T203 798Q203 518 400 321T878 123Q1157 123 1354 320T1552 798Q1552 1077 1355 1274T878 1472Z" />
+<glyph unicode="&#xaa;" glyph-name="ordfeminine" horiz-adv-x="960" d="M480 1440Q381 1440 311 1370T240 1200Q240 1101 310 1031T480 960Q579 960 649 1030T720 1200Q720 1299 650 1369T480 1440ZM720 879Q617 800 480 800Q314 800 197 917T80 1200Q80 1366
+197 1483T480 1600Q646 1600 763 1483T880 1200V880Q880 847 857 824T800 800Q767 800 744 824Q720 847 720 879Z" />
+<glyph unicode="&#xab;" glyph-name="guillemotleft" horiz-adv-x="960" d="M90 598L326 1070Q332 1084 344 1096Q367 1119 400 1119Q433 1119 456 1096T480 1039Q480 1021 473 1005L250 560L473 114Q480 98 480 80Q480 47 457 24T400 0Q367 0 344 24Q332 35 326
+49L92 516Q80 538 80 559Q80 579 90 598ZM490 598L726 1070Q732 1084 744 1096Q767 1119 800 1119Q833 1119 856 1096T880 1039Q880 1021 873 1005L650 560L873 114Q880 98 880 80Q880 47 857 24T800 0Q767 0 744 24Q732 35 726 49L492 516Q480 538 480 559Q480
+579 490 598Z" />
+<glyph unicode="&#xac;" glyph-name="logicalnot" horiz-adv-x="1120" d="M160 960Q127 960 104 983T80 1040Q80 1073 103 1096T160 1120H960Q993 1120 1016 1097T1040 1040V720Q1040 687 1017 664T960 640Q927 640 904 663T880 720V960H160Z" />
+<glyph unicode="&#xad;" glyph-name="hyphen" horiz-adv-x="800" d="M160 480Q127 480 104 503T80 560Q80 593 103 616T160 640H640Q673 640 696 617T720 560Q720 527 697 504T640 480H160Z" />
+<glyph unicode="&#xae;" glyph-name="registered" horiz-adv-x="1760" d="M1675 798Q1675 467 1442 234T878 0Q547 0 314 233T80 798Q80 1128 313 1361T878 1595Q1208 1595 1441 1362T1675 798ZM878 1472Q598 1472 401 1275T203 798Q203 518 400 321T878 123Q1157
+123 1354 320T1552 798Q1552 1077 1355 1274T878 1472ZM665 1217V798H875Q962 798 1023 859T1085 1008Q1085 1095 1024 1156T875 1217H665ZM612 1322H875Q1005 1322 1097 1230T1190 1008Q1190 877 1097 785Q1055 743 1005 720L1233 354Q1242 342 1242 326Q1242
+304 1227 289T1190 273Q1161 273 1144 300L898 694Q886 693 875 693H665V326Q665 304 650 289T612 273Q591 273 576 288T560 326V1270Q560 1292 575 1307T612 1322Z" />
+<glyph unicode="&#xaf;" glyph-name="overscore" horiz-adv-x="1120" d="M160 1760Q127 1760 104 1783T80 1840Q80 1873 103 1896T160 1920H960Q993 1920 1016 1897T1040 1840Q1040 1807 1017 1784T960 1760H160Z" />
+<glyph unicode="&#xb0;" glyph-name="degree" horiz-adv-x="960" d="M880 1200Q880 1034 763 917T480 800Q314 800 197 917T80 1200Q80 1366 197 1483T480 1600Q646 1600 763 1483T880 1200ZM480 1440Q381 1440 311 1370T240 1200Q240 1101 310 1031T480 960Q579
+960 649 1030T720 1200Q720 1299 650 1369T480 1440Z" />
+<glyph unicode="&#xb1;" glyph-name="plusminus" horiz-adv-x="1120" d="M480 1200Q480 1233 503 1256T560 1280Q593 1280 616 1257T640 1200V880H960Q993 880 1016 857T1040 800Q1040 767 1017 744T960 720H640V400Q640 367 617 344T560 320Q527 320 504 343T480
+400V720H160Q127 720 104 743T80 800Q80 833 103 856T160 880H480V1200ZM160 0Q127 0 104 23T80 80Q80 113 103 136T160 160H960Q993 160 1016 137T1040 80Q1040 47 1017 24T960 0H160Z" />
+<glyph unicode="&#xb2;" glyph-name="uni00B2" horiz-adv-x="640" d="M516 887Q532 887 543 876T555 848Q555 831 544 820T516 808H120Q103 808 92 819T80 848Q80 864 91 876L429 1250Q476 1297 476 1362Q476 1428 430 1474T318 1521Q252 1521 206 1475T159 1362Q159
+1346 148 1335T120 1323Q103 1323 92 1334T80 1362Q80 1461 149 1530T318 1600Q416 1600 485 1531T555 1362Q555 1264 485 1194L209 887H516Z" />
+<glyph unicode="&#xb3;" glyph-name="uni00B3" horiz-adv-x="640" d="M320 1201Q303 1201 292 1212T280 1241Q280 1257 291 1269T320 1281Q369 1281 404 1316T439 1400Q439 1450 404 1485T320 1520Q270 1520 235 1485T200 1400Q200 1384 188 1373T160 1361Q143
+1361 132 1372T120 1400Q120 1483 178 1541T320 1600Q402 1600 460 1542T519 1400Q519 1308 446 1245Q469 1231 489 1211Q559 1140 559 1041Q559 942 489 872T320 802Q220 802 150 872T80 1041Q80 1058 91 1069T120 1081Q136 1081 148 1070T160 1041Q160 975 206
+929T320 882Q386 882 432 928T479 1041Q479 1108 433 1154T320 1201Z" />
+<glyph unicode="&#xb4;" glyph-name="acute" horiz-adv-x="560" d="M458 1464L215 1221Q192 1200 160 1200Q127 1200 104 1223T80 1280Q80 1311 100 1334L343 1577Q367 1600 400 1600Q433 1600 456 1577T480 1520Q480 1488 458 1464Z" />
+<glyph unicode="&#xb5;" glyph-name="mu" horiz-adv-x="1200" d="M240 520Q240 371 345 266T600 160Q749 160 854 265T960 520V1040Q960 1073 983 1096T1040 1120Q1073 1120 1096 1097T1120 1040V80Q1120 47 1097 24T1040 0Q1007 0 984 23T960 80V145Q810 0 600
+0Q390 0 240 145V-400Q240 -433 217 -456T160 -480Q127 -480 104 -457T80 -400V1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V520Z" />
+<glyph unicode="&#xb6;" glyph-name="paragraph" horiz-adv-x="1120" d="M960 80Q960 47 937 24T880 0Q847 0 824 23T800 80V1440H640V80Q640 47 617 24T560 0Q527 0 504 23T480 80V800Q314 800 197 917T80 1200Q80 1366 197 1483T480 1600H960Q993 1600 1016
+1577T1040 1520Q1040 1487 1017 1464T960 1440V80Z" />
+<glyph unicode="&#xb7;" glyph-name="middot" horiz-adv-x="400" d="M320 760Q320 710 285 675T200 640Q150 640 115 675T80 760Q80 810 115 845T200 880Q250 880 285 845T320 760Z" />
+<glyph unicode="&#xb8;" glyph-name="cedilla" horiz-adv-x="640" d="M304 57Q327 80 360 80Q393 80 416 57T440 0Q440 -10 438 -19L421 -79Q458 -94 490 -120Q560 -181 560 -270Q560 -359 490 -419T320 -480Q261 -480 206 -451L115 -397Q80 -368 80 -330Q80 -297
+103 -274T160 -250Q184 -250 203 -262L281 -310Q300 -320 320 -320Q353 -320 376 -307T400 -270Q400 -247 377 -234T320 -220Q287 -220 264 -197T240 -140Q240 -126 244 -114L283 23Q289 42 304 57Z" />
+<glyph unicode="&#xb9;" glyph-name="uni00B9" horiz-adv-x="480" d="M319 845Q319 828 307 817T279 805Q263 805 251 816T239 845V1505L175 1484Q168 1481 160 1481Q143 1481 132 1492T120 1521Q120 1537 132 1549Q138 1555 145 1558L265 1598Q271 1600 279 1600Q295
+1600 307 1589T319 1560V845Z" />
+<glyph unicode="&#xba;" glyph-name="ordmasculine" horiz-adv-x="640" d="M80 1203Q80 1441 178 1542Q236 1600 319 1600Q401 1600 459 1542Q557 1441 557 1203Q557 964 459 863Q401 805 319 805Q236 805 178 863Q80 964 80 1203ZM319 1521Q269 1521 234 1485Q160
+1401 160 1203Q160 1004 234 920Q269 885 319 885Q368 885 403 920Q478 1004 478 1203Q478 1401 403 1485Q368 1521 319 1521Z" />
+<glyph unicode="&#xbb;" glyph-name="guillemotright" horiz-adv-x="960" d="M880 559Q880 538 868 516L634 49Q628 35 616 24Q593 0 560 0Q527 0 504 23T480 80Q480 98 487 114L710 560L487 1005Q480 1021 480 1039Q480 1072 503 1095T560 1119Q593 1119 616
+1096Q628 1084 634 1070L870 598Q880 579 880 559ZM480 559Q480 538 468 516L234 49Q228 35 216 24Q193 0 160 0Q127 0 104 23T80 80Q80 98 87 114L310 560L87 1005Q80 1021 80 1039Q80 1072 103 1095T160 1119Q193 1119 216 1096Q228 1084 234 1070L470 598Q480
+579 480 559Z" />
+<glyph unicode="&#xbc;" glyph-name="onequarter" horiz-adv-x="1440" d="M1200 1600Q1233 1600 1256 1577T1280 1520Q1280 1496 1268 1477L310 41Q283 0 240 0Q207 0 184 23T160 80Q160 104 172 123L1136 1569Q1157 1600 1200 1600ZM320 688Q320 668 306 654T272
+640Q252 640 238 654T224 688V1486L147 1460Q138 1457 128 1457Q108 1457 94 1471T80 1505Q80 1525 94 1539Q102 1546 111 1550L255 1598Q263 1601 272 1601Q292 1601 306 1587T320 1553V688ZM1120 336V758L828 336H1120ZM736 240Q716 240 702 254T688 288Q688
+304 697 316L1129 940Q1131 943 1134 946Q1148 960 1168 960Q1188 960 1202 946T1216 912V336H1312Q1332 336 1346 322T1360 288Q1360 268 1346 254T1312 240H1216V48Q1216 28 1202 14T1168 0Q1148 0 1134 14T1120 48V240H736Z" />
+<glyph unicode="&#xbd;" glyph-name="onehalf" horiz-adv-x="1600" d="M1200 1600Q1233 1600 1256 1577T1280 1520Q1280 1496 1268 1477L310 41Q283 0 240 0Q207 0 184 23T160 80Q160 104 172 123L1136 1569Q1157 1600 1200 1600ZM320 688Q320 668 306 654T272
+640Q252 640 238 654T224 688V1486L147 1460Q138 1457 128 1457Q108 1457 94 1471T80 1505Q80 1525 94 1539Q102 1546 111 1550L255 1598Q263 1601 272 1601Q292 1601 306 1587T320 1553V688ZM1472 96Q1491 96 1505 82T1520 48Q1520 28 1506 14T1472 0H991Q971
+0 957 14T943 48Q943 68 957 82L1367 536Q1424 593 1424 673Q1424 753 1368 809T1231 865Q1151 865 1095 809T1039 673Q1039 653 1025 639T991 625Q971 625 957 639T943 673Q943 792 1027 876T1231 961Q1351 961 1435 877T1520 673Q1520 553 1435 468L1100 96H1472Z"
+/>
+<glyph unicode="&#xbe;" glyph-name="threequarters" horiz-adv-x="1600" d="M1360 1600Q1393 1600 1416 1577T1440 1520Q1440 1496 1428 1477L470 41Q443 0 400 0Q367 0 344 23T320 80Q320 104 332 123L1296 1569Q1317 1600 1360 1600ZM1280 336V758L988 336H1280ZM896
+240Q876 240 862 254T848 288Q848 304 857 316L1289 940Q1291 943 1294 946Q1308 960 1328 960Q1348 960 1362 946T1376 912V336H1472Q1492 336 1506 322T1520 288Q1520 268 1506 254T1472 240H1376V48Q1376 28 1362 14T1328 0Q1308 0 1294 14T1280 48V240H896ZM367
+1119Q347 1119 333 1133T319 1167Q319 1186 333 1200T367 1214Q426 1214 468 1256T511 1358Q511 1417 469 1459T367 1501Q308 1501 266 1459T224 1358Q224 1338 210 1324T176 1310Q156 1310 142 1324T128 1358Q128 1457 198 1527T367 1597Q466 1597 536 1527T606
+1358Q606 1259 536 1189Q527 1180 518 1172Q546 1155 570 1131Q654 1046 654 927Q654 808 570 724T367 640Q248 640 164 724T80 927Q80 947 94 961T128 975Q148 975 162 961T176 927Q176 848 231 792T367 736Q447 736 502 792T558 927Q558 1007 503 1063T367 1119Z"
+/>
+<glyph unicode="&#xbf;" glyph-name="questiondown" horiz-adv-x="1120" d="M560 -320Q693 -320 786 -227T880 0Q880 133 786 227L621 380Q480 521 480 720Q480 753 503 776T560 800Q593 800 616 777T640 720Q640 587 734 493L899 340Q1040 199 1040 0Q1040 -199
+900 -339T560 -480Q361 -480 221 -340T80 0Q80 33 103 56T160 80Q193 80 216 57T240 0Q240 -133 333 -226T560 -320ZM560 879Q510 879 475 914T440 999Q440 1049 475 1084T560 1119Q610 1119 645 1084T680 999Q680 949 645 914T560 879Z" />
+<glyph unicode="&#xc0;" glyph-name="Agrave" horiz-adv-x="1440" d="M433 560L234 49Q228 35 217 23Q193 0 160 0Q127 0 104 23T80 80Q80 99 87 114L643 1544Q649 1562 664 1577Q687 1600 720 1600Q753 1600 777 1577Q791 1562 797 1544L1353 114Q1360 99 1360
+80Q1360 47 1337 24T1280 0Q1247 0 1224 23Q1212 35 1206 49L1007 560H433ZM945 720L720 1299L495 720H945ZM453 2000Q453 2033 476 2056T533 2080Q566 2080 590 2057L833 1814Q853 1791 853 1760Q853 1727 830 1704T773 1680Q741 1680 718 1701L475 1944Q453 1968
+453 2000Z" />
+<glyph unicode="&#xc1;" glyph-name="Aacute" horiz-adv-x="1440" d="M433 560L234 49Q228 35 217 23Q193 0 160 0Q127 0 104 23T80 80Q80 99 87 114L643 1544Q649 1562 664 1577Q687 1600 720 1600Q753 1600 777 1577Q791 1562 797 1544L1353 114Q1360 99 1360
+80Q1360 47 1337 24T1280 0Q1247 0 1224 23Q1212 35 1206 49L1007 560H433ZM945 720L720 1299L495 720H945ZM965 1944L722 1701Q699 1680 667 1680Q634 1680 611 1703T587 1760Q587 1791 607 1814L850 2057Q874 2080 907 2080Q940 2080 963 2057T987 2000Q987 1968
+965 1944Z" />
+<glyph unicode="&#xc2;" glyph-name="Acircumflex" horiz-adv-x="1440" d="M433 560L234 49Q228 35 217 23Q193 0 160 0Q127 0 104 23T80 80Q80 99 87 114L643 1544Q649 1562 664 1577Q687 1600 720 1600Q753 1600 777 1577Q791 1562 797 1544L1353 114Q1360 99
+1360 80Q1360 47 1337 24T1280 0Q1247 0 1224 23Q1212 35 1206 49L1007 560H433ZM945 720L720 1299L495 720H945ZM761 2029L1000 1870Q1040 1840 1040 1800Q1040 1767 1017 1744T960 1720Q931 1720 910 1737L720 1863L530 1737Q509 1720 480 1720Q447 1720 424
+1743T400 1800Q400 1840 440 1870L679 2029Q697 2040 720 2040Q743 2040 761 2029Z" />
+<glyph unicode="&#xc3;" glyph-name="Atilde" horiz-adv-x="1440" d="M433 560L234 49Q228 35 217 23Q193 0 160 0Q127 0 104 23T80 80Q80 99 87 114L643 1544Q649 1562 664 1577Q687 1600 720 1600Q753 1600 777 1577Q791 1562 797 1544L1353 114Q1360 99 1360
+80Q1360 47 1337 24T1280 0Q1247 0 1224 23Q1212 35 1206 49L1007 560H433ZM945 720L720 1299L495 720H945ZM769 1801Q679 1721 557 1721Q424 1721 330 1815Q308 1839 308 1871Q308 1904 331 1927T388 1951Q420 1951 444 1929Q491 1881 557 1881Q613 1881 657 1916Q746
+1996 869 1996Q1002 1996 1096 1902Q1118 1878 1118 1846Q1118 1813 1095 1790T1038 1766Q1006 1766 982 1788Q935 1836 869 1836Q812 1836 769 1801Z" />
+<glyph unicode="&#xc4;" glyph-name="Adieresis" horiz-adv-x="1440" d="M433 560L234 49Q228 35 217 23Q193 0 160 0Q127 0 104 23T80 80Q80 99 87 114L643 1544Q649 1562 664 1577Q687 1600 720 1600Q753 1600 777 1577Q791 1562 797 1544L1353 114Q1360 99
+1360 80Q1360 47 1337 24T1280 0Q1247 0 1224 23Q1212 35 1206 49L1007 560H433ZM945 720L720 1299L495 720H945ZM580 1840Q580 1799 551 1770T480 1740Q439 1740 410 1769T380 1840Q380 1881 409 1910T480 1940Q521 1940 550 1911T580 1840ZM1060 1840Q1060 1799
+1031 1770T960 1740Q919 1740 890 1769T860 1840Q860 1881 889 1910T960 1940Q1001 1940 1030 1911T1060 1840Z" />
+<glyph unicode="&#xc5;" glyph-name="Aring" horiz-adv-x="1440" d="M433 560L234 49Q228 35 217 23Q193 0 160 0Q127 0 104 23T80 80Q80 99 87 114L643 1544Q649 1562 664 1577Q687 1600 720 1600Q753 1600 777 1577Q791 1562 797 1544L1353 114Q1360 99 1360
+80Q1360 47 1337 24T1280 0Q1247 0 1224 23Q1212 35 1206 49L1007 560H433ZM945 720L720 1299L495 720H945ZM921 1879Q921 1795 862 1736T720 1677Q636 1677 577 1736T518 1879Q518 1962 577 2021T720 2080Q803 2080 862 2021T921 1879ZM720 1979Q678 1979 649
+1950T619 1879Q619 1837 648 1808T720 1778Q761 1778 790 1807T820 1879Q820 1920 791 1949T720 1979Z" />
+<glyph unicode="&#xc6;" glyph-name="AE" horiz-adv-x="1760" d="M880 1210L652 800H880V1210ZM1600 1600Q1633 1600 1656 1577T1680 1520Q1680 1487 1657 1464T1600 1440H1040V800H1440Q1473 800 1496 777T1520 720Q1520 687 1497 664T1440 640H1040V160H1600Q1633
+160 1656 137T1680 80Q1680 47 1657 24T1600 0H960Q927 0 904 23T880 80V640H563L228 37Q203 0 160 0Q127 0 104 23T80 80Q80 102 90 119L892 1563Q915 1600 960 1600H1600Z" />
+<glyph unicode="&#xc7;" glyph-name="Ccedilla" horiz-adv-x="1480" d="M1326 314Q1359 314 1382 291T1406 234Q1406 201 1383 178Q1160 0 880 0Q549 0 315 234T80 800Q80 1131 314 1365T880 1600Q1166 1600 1389 1417Q1412 1393 1412 1360Q1412 1327 1389 1304T1332
+1280Q1299 1280 1275 1304Q1106 1440 880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1109 160 1280 300Q1300 314 1326 314ZM730 57Q753 80 786 80Q819 80 842 57T866 0Q866 -10 864 -19L847 -79Q884 -94 916 -120Q986 -181 986 -270Q986 -359 916
+-419T746 -480Q687 -480 632 -451L541 -397Q506 -368 506 -330Q506 -297 529 -274T586 -250Q610 -250 629 -262L707 -310Q726 -320 746 -320Q779 -320 802 -307T826 -270Q826 -247 803 -234T746 -220Q713 -220 690 -197T666 -140Q666 -126 670 -114L709 23Q715
+42 730 57Z" />
+<glyph unicode="&#xc8;" glyph-name="Egrave" horiz-adv-x="1280" d="M161 1600H1121Q1154 1600 1177 1577T1201 1520Q1201 1487 1178 1464T1121 1440H241V880H881Q914 880 937 857T961 800Q961 767 938 744T881 720H241V160H1121Q1154 160 1177 137T1201 80Q1201
+47 1178 24T1121 0H161Q128 0 105 23T81 80V1520Q81 1553 104 1576T161 1600ZM375 2000Q375 2033 398 2056T455 2080Q488 2080 512 2057L755 1814Q775 1791 775 1760Q775 1727 752 1704T695 1680Q663 1680 640 1701L397 1944Q375 1968 375 2000Z" />
+<glyph unicode="&#xc9;" glyph-name="Eacute" horiz-adv-x="1280" d="M161 1600H1121Q1154 1600 1177 1577T1201 1520Q1201 1487 1178 1464T1121 1440H241V880H881Q914 880 937 857T961 800Q961 767 938 744T881 720H241V160H1121Q1154 160 1177 137T1201 80Q1201
+47 1178 24T1121 0H161Q128 0 105 23T81 80V1520Q81 1553 104 1576T161 1600ZM887 1944L644 1701Q621 1680 589 1680Q556 1680 533 1703T509 1760Q509 1791 529 1814L772 2057Q796 2080 829 2080Q862 2080 885 2057T909 2000Q909 1968 887 1944Z" />
+<glyph unicode="&#xca;" glyph-name="Ecircumflex" horiz-adv-x="1280" d="M161 1600H1121Q1154 1600 1177 1577T1201 1520Q1201 1487 1178 1464T1121 1440H241V880H881Q914 880 937 857T961 800Q961 767 938 744T881 720H241V160H1121Q1154 160 1177 137T1201
+80Q1201 47 1178 24T1121 0H161Q128 0 105 23T81 80V1520Q81 1553 104 1576T161 1600ZM681 2029L920 1870Q960 1840 960 1800Q960 1767 937 1744T880 1720Q851 1720 830 1737L640 1863L450 1737Q429 1720 400 1720Q367 1720 344 1743T320 1800Q320 1840 360 1870L599
+2029Q617 2040 640 2040Q663 2040 681 2029Z" />
+<glyph unicode="&#xcb;" glyph-name="Edieresis" horiz-adv-x="1280" d="M161 1600H1121Q1154 1600 1177 1577T1201 1520Q1201 1487 1178 1464T1121 1440H241V880H881Q914 880 937 857T961 800Q961 767 938 744T881 720H241V160H1121Q1154 160 1177 137T1201 80Q1201
+47 1178 24T1121 0H161Q128 0 105 23T81 80V1520Q81 1553 104 1576T161 1600ZM502 1840Q502 1799 473 1770T402 1740Q361 1740 332 1769T302 1840Q302 1881 331 1910T402 1940Q443 1940 472 1911T502 1840ZM982 1840Q982 1799 953 1770T882 1740Q841 1740 812 1769T782
+1840Q782 1881 811 1910T882 1940Q923 1940 952 1911T982 1840Z" />
+<glyph unicode="&#xcc;" glyph-name="Igrave" horiz-adv-x="480" d="M160 1520Q160 1553 183 1576T240 1600Q273 1600 296 1577T320 1520V80Q320 47 297 24T240 0Q207 0 184 23T160 80V1520ZM-26 2000Q-26 2033 -3 2056T54 2080Q87 2080 111 2057L354 1814Q374
+1791 374 1760Q374 1727 351 1704T294 1680Q262 1680 239 1701L-4 1944Q-26 1968 -26 2000Z" />
+<glyph unicode="&#xcd;" glyph-name="Iacute" horiz-adv-x="480" d="M160 1520Q160 1553 183 1576T240 1600Q273 1600 296 1577T320 1520V80Q320 47 297 24T240 0Q207 0 184 23T160 80V1520ZM485 1944L242 1701Q219 1680 187 1680Q154 1680 131 1703T107 1760Q107
+1791 127 1814L370 2057Q394 2080 427 2080Q460 2080 483 2057T507 2000Q507 1968 485 1944Z" />
+<glyph unicode="&#xce;" glyph-name="Icircumflex" horiz-adv-x="480" d="M160 1520Q160 1553 183 1576T240 1600Q273 1600 296 1577T320 1520V80Q320 47 297 24T240 0Q207 0 184 23T160 80V1520ZM282 2029L521 1870Q561 1840 561 1800Q561 1767 538 1744T481
+1720Q452 1720 431 1737L241 1863L51 1737Q30 1720 1 1720Q-32 1720 -55 1743T-79 1800Q-79 1840 -39 1870L200 2029Q218 2040 241 2040Q264 2040 282 2029Z" />
+<glyph unicode="&#xcf;" glyph-name="Idieresis" horiz-adv-x="480" d="M160 1520Q160 1553 183 1576T240 1600Q273 1600 296 1577T320 1520V80Q320 47 297 24T240 0Q207 0 184 23T160 80V1520ZM101 1840Q101 1799 72 1770T1 1740Q-40 1740 -69 1769T-99 1840Q-99
+1881 -70 1910T1 1940Q42 1940 71 1911T101 1840ZM581 1840Q581 1799 552 1770T481 1740Q440 1740 411 1769T381 1840Q381 1881 410 1910T481 1940Q522 1940 551 1911T581 1840Z" />
+<glyph unicode="&#xd0;" glyph-name="Eth" horiz-adv-x="1520" d="M239 880V1520Q239 1553 262 1576T319 1600H639Q970 1600 1204 1366T1439 800Q1439 469 1205 235T639 0H319Q286 0 263 23T239 80V720H80Q47 720 24 743T0 800Q0 833 23 856T80 880H239ZM399 880H719Q752
+880 775 857T799 800Q799 767 776 744T719 720H399V160H639Q904 160 1091 347T1279 800Q1279 1065 1092 1252T639 1440H399V880Z" />
+<glyph unicode="&#xd1;" glyph-name="Ntilde" horiz-adv-x="1440" d="M240 80Q240 47 217 24T160 0Q127 0 104 23T80 80V1520Q80 1553 103 1576T160 1600Q196 1600 222 1571L1200 313V1520Q1200 1553 1223 1576T1280 1600Q1313 1600 1336 1577T1360 1520V80Q1360
+47 1337 24T1280 0Q1245 0 1220 26L240 1286V80ZM769 1801Q679 1721 557 1721Q424 1721 330 1815Q308 1839 308 1871Q308 1904 331 1927T388 1951Q420 1951 444 1929Q491 1881 557 1881Q613 1881 657 1916Q746 1996 869 1996Q1002 1996 1096 1902Q1118 1878 1118
+1846Q1118 1813 1095 1790T1038 1766Q1006 1766 982 1788Q935 1836 869 1836Q812 1836 769 1801Z" />
+<glyph unicode="&#xd2;" glyph-name="Ograve" horiz-adv-x="1760" d="M880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1145 160 1332 347T1520 800Q1520 1065 1333 1252T880 1440ZM1680 800Q1680 469 1446 235T880 0Q549 0 315 234T80 800Q80 1131
+314 1365T880 1600Q1211 1600 1445 1366T1680 800ZM693 2000Q693 2033 716 2056T773 2080Q806 2080 830 2057L1073 1814Q1093 1791 1093 1760Q1093 1727 1070 1704T1013 1680Q981 1680 958 1701L715 1944Q693 1968 693 2000Z" />
+<glyph unicode="&#xd3;" glyph-name="Oacute" horiz-adv-x="1760" d="M880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1145 160 1332 347T1520 800Q1520 1065 1333 1252T880 1440ZM1680 800Q1680 469 1446 235T880 0Q549 0 315 234T80 800Q80 1131
+314 1365T880 1600Q1211 1600 1445 1366T1680 800ZM1055 1944L812 1701Q789 1680 757 1680Q724 1680 701 1703T677 1760Q677 1791 697 1814L940 2057Q964 2080 997 2080Q1030 2080 1053 2057T1077 2000Q1077 1968 1055 1944Z" />
+<glyph unicode="&#xd4;" glyph-name="Ocircumflex" horiz-adv-x="1760" d="M880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1145 160 1332 347T1520 800Q1520 1065 1333 1252T880 1440ZM1680 800Q1680 469 1446 235T880 0Q549 0 315 234T80 800Q80
+1131 314 1365T880 1600Q1211 1600 1445 1366T1680 800ZM921 2029L1160 1870Q1200 1840 1200 1800Q1200 1767 1177 1744T1120 1720Q1091 1720 1070 1737L880 1863L690 1737Q669 1720 640 1720Q607 1720 584 1743T560 1800Q560 1840 600 1870L839 2029Q857 2040
+880 2040Q903 2040 921 2029Z" />
+<glyph unicode="&#xd5;" glyph-name="Otilde" horiz-adv-x="1760" d="M880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1145 160 1332 347T1520 800Q1520 1065 1333 1252T880 1440ZM1680 800Q1680 469 1446 235T880 0Q549 0 315 234T80 800Q80 1131
+314 1365T880 1600Q1211 1600 1445 1366T1680 800ZM929 1801Q839 1721 717 1721Q584 1721 490 1815Q468 1839 468 1871Q468 1904 491 1927T548 1951Q580 1951 604 1929Q651 1881 717 1881Q773 1881 817 1916Q906 1996 1029 1996Q1162 1996 1256 1902Q1278 1878
+1278 1846Q1278 1813 1255 1790T1198 1766Q1166 1766 1142 1788Q1095 1836 1029 1836Q972 1836 929 1801Z" />
+<glyph unicode="&#xd6;" glyph-name="Odieresis" horiz-adv-x="1760" d="M880 1440Q615 1440 428 1253T240 800Q240 535 427 348T880 160Q1145 160 1332 347T1520 800Q1520 1065 1333 1252T880 1440ZM1680 800Q1680 469 1446 235T880 0Q549 0 315 234T80 800Q80
+1131 314 1365T880 1600Q1211 1600 1445 1366T1680 800ZM740 1840Q740 1799 711 1770T640 1740Q599 1740 570 1769T540 1840Q540 1881 569 1910T640 1940Q681 1940 710 1911T740 1840ZM1220 1840Q1220 1799 1191 1770T1120 1740Q1079 1740 1050 1769T1020 1840Q1020
+1881 1049 1910T1120 1940Q1161 1940 1190 1911T1220 1840Z" />
+<glyph unicode="&#xd7;" glyph-name="multiply" horiz-adv-x="960" d="M366 720L102 984Q80 1008 80 1040Q80 1073 103 1096T160 1120Q193 1120 218 1096L480 834L742 1096Q767 1120 800 1120Q833 1120 856 1097T880 1040Q880 1008 858 984L594 720L858 456Q880
+432 880 400Q880 367 857 344T800 320Q768 320 745 341L480 606L215 341Q192 320 160 320Q127 320 104 343T80 400Q80 432 102 456L366 720Z" />
+<glyph unicode="&#xd8;" glyph-name="Oslash" horiz-adv-x="1760" d="M1500 1306Q1680 1090 1680 800Q1680 469 1446 235T880 0Q590 0 374 180L217 23Q193 0 160 0Q127 0 104 23T80 80Q80 112 101 135L260 294Q80 510 80 800Q80 1131 314 1365T880 1600Q1170 1600
+1386 1420L1543 1577Q1567 1600 1600 1600Q1633 1600 1656 1577T1680 1520Q1680 1491 1662 1469L1500 1306ZM374 408L1272 1306Q1104 1440 880 1440Q615 1440 428 1253T240 800Q240 576 374 408ZM1386 1193L488 294Q656 160 880 160Q1145 160 1332 347T1520 800Q1520
+1024 1386 1193Z" />
+<glyph unicode="&#xd9;" glyph-name="Ugrave" horiz-adv-x="1280" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V560Q240 394 357 277T640 160Q806 160 923 277T1040 560V1520Q1040 1553 1063 1576T1120 1600Q1153 1600 1176 1577T1200
+1520V560Q1200 328 1036 164T640 0Q408 0 244 164T80 560V1520ZM373 2000Q373 2033 396 2056T453 2080Q486 2080 510 2057L753 1814Q773 1791 773 1760Q773 1727 750 1704T693 1680Q661 1680 638 1701L395 1944Q373 1968 373 2000Z" />
+<glyph unicode="&#xda;" glyph-name="Uacute" horiz-adv-x="1280" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V560Q240 394 357 277T640 160Q806 160 923 277T1040 560V1520Q1040 1553 1063 1576T1120 1600Q1153 1600 1176 1577T1200
+1520V560Q1200 328 1036 164T640 0Q408 0 244 164T80 560V1520ZM885 1944L642 1701Q619 1680 587 1680Q554 1680 531 1703T507 1760Q507 1791 527 1814L770 2057Q794 2080 827 2080Q860 2080 883 2057T907 2000Q907 1968 885 1944Z" />
+<glyph unicode="&#xdb;" glyph-name="Ucircumflex" horiz-adv-x="1280" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V560Q240 394 357 277T640 160Q806 160 923 277T1040 560V1520Q1040 1553 1063 1576T1120 1600Q1153 1600 1176 1577T1200
+1520V560Q1200 328 1036 164T640 0Q408 0 244 164T80 560V1520ZM681 2029L920 1870Q960 1840 960 1800Q960 1767 937 1744T880 1720Q851 1720 830 1737L640 1863L450 1737Q429 1720 400 1720Q367 1720 344 1743T320 1800Q320 1840 360 1870L599 2029Q617 2040 640
+2040Q663 2040 681 2029Z" />
+<glyph unicode="&#xdc;" glyph-name="Udieresis" horiz-adv-x="1280" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V560Q240 394 357 277T640 160Q806 160 923 277T1040 560V1520Q1040 1553 1063 1576T1120 1600Q1153 1600 1176 1577T1200
+1520V560Q1200 328 1036 164T640 0Q408 0 244 164T80 560V1520ZM500 1840Q500 1799 471 1770T400 1740Q359 1740 330 1769T300 1840Q300 1881 329 1910T400 1940Q441 1940 470 1911T500 1840ZM980 1840Q980 1799 951 1770T880 1740Q839 1740 810 1769T780 1840Q780
+1881 809 1910T880 1940Q921 1940 950 1911T980 1840Z" />
+<glyph unicode="&#xdd;" glyph-name="Yacute" horiz-adv-x="1280" d="M720 80Q720 47 697 24T640 0Q607 0 584 23T560 80V776L93 1475Q80 1495 80 1520Q80 1553 103 1576T160 1600Q201 1600 225 1567L640 945L1055 1567Q1079 1600 1120 1600Q1153 1600 1176 1577T1200
+1520Q1200 1495 1187 1475L720 776V80ZM885 1944L642 1701Q619 1680 587 1680Q554 1680 531 1703T507 1760Q507 1791 527 1814L770 2057Q794 2080 827 2080Q860 2080 883 2057T907 2000Q907 1968 885 1944Z" />
+<glyph unicode="&#xde;" glyph-name="Thorn" horiz-adv-x="1280" d="M80 1520Q80 1553 103 1576T160 1600Q193 1600 216 1577T240 1520V1280H720Q919 1280 1059 1140T1200 800Q1200 601 1060 461T720 320H240V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1520ZM720
+480Q853 480 946 573T1040 800Q1040 933 947 1026T720 1120H240V480H720Z" />
+<glyph unicode="&#xdf;" glyph-name="germandbls" horiz-adv-x="1120" d="M240 80Q240 47 217 24T160 0Q127 0 104 23T80 80V1200Q80 1366 197 1483Q314 1600 480 1600Q646 1600 763 1483T880 1200Q880 1053 788 945Q763 911 763 867Q763 790 819 759Q875 731
+923 683Q1040 566 1040 400Q1040 234 923 117T640 0Q474 0 357 117Q331 143 331 176Q331 209 354 232T411 256Q444 256 471 231Q541 160 640 160Q739 160 809 230T880 400Q880 499 810 570Q781 598 748 617T684 667Q600 750 600 868Q600 975 672 1056Q720 1118
+720 1200Q720 1299 650 1369T480 1440Q381 1440 311 1370Q240 1299 240 1200V80Z" />
+<glyph unicode="&#xe0;" glyph-name="agrave" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1040 168Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872
+1120 1036 956T1200 560V80Q1200 47 1177 24T1120 0Q1087 0 1064 23T1040 80V168ZM400 1520Q400 1553 423 1576T480 1600Q513 1600 537 1577L780 1334Q800 1311 800 1280Q800 1247 777 1224T720 1200Q688 1200 665 1221L422 1464Q400 1488 400 1520Z" />
+<glyph unicode="&#xe1;" glyph-name="aacute" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1040 168Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872
+1120 1036 956T1200 560V80Q1200 47 1177 24T1120 0Q1087 0 1064 23T1040 80V168ZM858 1464L615 1221Q592 1200 560 1200Q527 1200 504 1223T480 1280Q480 1311 500 1334L743 1577Q767 1600 800 1600Q833 1600 856 1577T880 1520Q880 1488 858 1464Z" />
+<glyph unicode="&#xe2;" glyph-name="acircumflex" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1040 168Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872
+1120 1036 956T1200 560V80Q1200 47 1177 24T1120 0Q1087 0 1064 23T1040 80V168ZM681 1549L920 1390Q960 1360 960 1320Q960 1287 937 1264T880 1240Q851 1240 830 1257L640 1383L450 1257Q429 1240 400 1240Q367 1240 344 1263T320 1320Q320 1360 360 1390L599
+1549Q617 1560 640 1560Q663 1560 681 1549Z" />
+<glyph unicode="&#xe3;" glyph-name="atilde" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1040 168Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872
+1120 1036 956T1200 560V80Q1200 47 1177 24T1120 0Q1087 0 1064 23T1040 80V168ZM696 1321Q606 1241 484 1241Q351 1241 257 1335Q235 1359 235 1391Q235 1424 258 1447T315 1471Q347 1471 371 1449Q418 1401 484 1401Q540 1401 584 1436Q673 1516 796 1516Q929
+1516 1023 1422Q1045 1398 1045 1366Q1045 1333 1022 1310T965 1286Q933 1286 909 1308Q862 1356 796 1356Q739 1356 696 1321Z" />
+<glyph unicode="&#xe4;" glyph-name="adieresis" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1040 168Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872
+1120 1036 956T1200 560V80Q1200 47 1177 24T1120 0Q1087 0 1064 23T1040 80V168ZM500 1360Q500 1319 471 1290T400 1260Q359 1260 330 1289T300 1360Q300 1401 329 1430T400 1460Q441 1460 470 1431T500 1360ZM980 1360Q980 1319 951 1290T880 1260Q839 1260 810
+1289T780 1360Q780 1401 809 1430T880 1460Q921 1460 950 1431T980 1360Z" />
+<glyph unicode="&#xe5;" glyph-name="aring" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1040 168Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872
+1120 1036 956T1200 560V80Q1200 47 1177 24T1120 0Q1087 0 1064 23T1040 80V168ZM842 1399Q842 1315 783 1256T641 1197Q557 1197 498 1256T439 1399Q439 1482 498 1541T641 1600Q724 1600 783 1541T842 1399ZM641 1499Q599 1499 570 1470T540 1399Q540 1357 569
+1328T641 1298Q682 1298 711 1327T741 1399Q741 1440 712 1469T641 1499Z" />
+<glyph unicode="&#xe6;" glyph-name="ae" horiz-adv-x="2240" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM1993 640Q1971 755 1883 843Q1766 960 1600 960Q1434 960 1317 843Q1229 755
+1207 640H1993ZM1200 168V80Q1200 47 1177 24T1120 0Q1087 0 1064 23T1040 80V168Q872 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872 1120 1036 956Q1085 907 1120 851Q1155 907 1204 956Q1368 1120 1600 1120Q1832 1120 1996 956T2160 560Q2160
+527 2137 504T2080 480H1207Q1229 365 1317 277Q1434 160 1600 160Q1750 160 1858 255Q1880 272 1908 272Q1941 272 1964 249T1988 192Q1988 159 1965 135Q1810 0 1600 0Q1368 0 1200 168Z" />
+<glyph unicode="&#xe7;" glyph-name="ccedilla" horiz-adv-x="1120" d="M950 274Q983 274 1006 251T1030 194Q1030 161 1005 135Q850 0 640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q850 1120 1005 985Q1033 960 1033 923Q1033 890 1010 867T953 843Q924
+843 902 861Q790 960 640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q790 160 901 258Q922 274 950 274ZM541 57Q564 80 597 80Q630 80 653 57T677 0Q677 -10 675 -19L658 -79Q695 -94 727 -120Q797 -181 797 -270Q797 -359 727 -419T557 -480Q498 -480
+443 -451L352 -397Q317 -368 317 -330Q317 -297 340 -274T397 -250Q421 -250 440 -262L518 -310Q537 -320 557 -320Q590 -320 613 -307T637 -270Q637 -247 614 -234T557 -220Q524 -220 501 -197T477 -140Q477 -126 481 -114L520 23Q526 42 541 57Z" />
+<glyph unicode="&#xe8;" glyph-name="egrave" horiz-adv-x="1280" d="M1033 640Q1011 755 923 843Q806 960 640 960Q474 960 357 843Q269 755 247 640H1033ZM948 272Q981 272 1004 249T1028 192Q1028 159 1005 135Q850 0 640 0Q408 0 244 164T80 560Q80 792 244
+956T640 1120Q872 1120 1036 956T1200 560Q1200 527 1177 504T1120 480H247Q269 365 357 277Q474 160 640 160Q790 160 898 255Q920 272 948 272ZM400 1520Q400 1553 423 1576T480 1600Q513 1600 537 1577L780 1334Q800 1311 800 1280Q800 1247 777 1224T720 1200Q688
+1200 665 1221L422 1464Q400 1488 400 1520Z" />
+<glyph unicode="&#xe9;" glyph-name="eacute" horiz-adv-x="1280" d="M1033 640Q1011 755 923 843Q806 960 640 960Q474 960 357 843Q269 755 247 640H1033ZM948 272Q981 272 1004 249T1028 192Q1028 159 1005 135Q850 0 640 0Q408 0 244 164T80 560Q80 792 244
+956T640 1120Q872 1120 1036 956T1200 560Q1200 527 1177 504T1120 480H247Q269 365 357 277Q474 160 640 160Q790 160 898 255Q920 272 948 272ZM858 1464L615 1221Q592 1200 560 1200Q527 1200 504 1223T480 1280Q480 1311 500 1334L743 1577Q767 1600 800 1600Q833
+1600 856 1577T880 1520Q880 1488 858 1464Z" />
+<glyph unicode="&#xea;" glyph-name="ecircumflex" horiz-adv-x="1280" d="M1033 640Q1011 755 923 843Q806 960 640 960Q474 960 357 843Q269 755 247 640H1033ZM948 272Q981 272 1004 249T1028 192Q1028 159 1005 135Q850 0 640 0Q408 0 244 164T80 560Q80 792
+244 956T640 1120Q872 1120 1036 956T1200 560Q1200 527 1177 504T1120 480H247Q269 365 357 277Q474 160 640 160Q790 160 898 255Q920 272 948 272ZM681 1549L920 1390Q960 1360 960 1320Q960 1287 937 1264T880 1240Q851 1240 830 1257L640 1383L450 1257Q429
+1240 400 1240Q367 1240 344 1263T320 1320Q320 1360 360 1390L599 1549Q617 1560 640 1560Q663 1560 681 1549Z" />
+<glyph unicode="&#xeb;" glyph-name="edieresis" horiz-adv-x="1280" d="M1033 640Q1011 755 923 843Q806 960 640 960Q474 960 357 843Q269 755 247 640H1033ZM948 272Q981 272 1004 249T1028 192Q1028 159 1005 135Q850 0 640 0Q408 0 244 164T80 560Q80 792
+244 956T640 1120Q872 1120 1036 956T1200 560Q1200 527 1177 504T1120 480H247Q269 365 357 277Q474 160 640 160Q790 160 898 255Q920 272 948 272ZM500 1360Q500 1319 471 1290T400 1260Q359 1260 330 1289T300 1360Q300 1401 329 1430T400 1460Q441 1460 470
+1431T500 1360ZM980 1360Q980 1319 951 1290T880 1260Q839 1260 810 1289T780 1360Q780 1401 809 1430T880 1460Q921 1460 950 1431T980 1360Z" />
+<glyph unicode="&#xec;" glyph-name="igrave" horiz-adv-x="480" d="M160 1040Q160 1073 183 1096T240 1120Q273 1120 296 1097T320 1040V80Q320 47 297 24T240 0Q207 0 184 23T160 80V1040ZM257 1520Q257 1553 280 1576T337 1600Q370 1600 394 1577L637 1334Q657
+1311 657 1280Q657 1247 634 1224T577 1200Q545 1200 522 1221L279 1464Q257 1488 257 1520Z" />
+<glyph unicode="&#xed;" glyph-name="iacute" horiz-adv-x="480" d="M160 1040Q160 1073 183 1096T240 1120Q273 1120 296 1097T320 1040V80Q320 47 297 24T240 0Q207 0 184 23T160 80V1040ZM460 1464L217 1221Q194 1200 162 1200Q129 1200 106 1223T82 1280Q82
+1311 102 1334L345 1577Q369 1600 402 1600Q435 1600 458 1577T482 1520Q482 1488 460 1464Z" />
+<glyph unicode="&#xee;" glyph-name="icircumflex" horiz-adv-x="560" d="M201 1040Q201 1073 224 1096T281 1120Q314 1120 337 1097T361 1040V80Q361 47 338 24T281 0Q248 0 225 23T201 80V1040ZM578 1549L817 1390Q857 1360 857 1320Q857 1287 834 1264T777
+1240Q748 1240 727 1257L537 1383L347 1257Q326 1240 297 1240Q264 1240 241 1263T217 1320Q217 1360 257 1390L496 1549Q514 1560 537 1560Q560 1560 578 1549Z" />
+<glyph unicode="&#xef;" glyph-name="idieresis" horiz-adv-x="600" d="M220 1040Q220 1073 243 1096T300 1120Q333 1120 356 1097T380 1040V80Q380 47 357 24T300 0Q267 0 244 23T220 80V1040ZM162 1360Q162 1319 133 1290T62 1260Q21 1260 -8 1289T-38 1360Q-38
+1401 -9 1430T62 1460Q103 1460 132 1431T162 1360ZM642 1360Q642 1319 613 1290T542 1260Q501 1260 472 1289T442 1360Q442 1401 471 1430T542 1460Q583 1460 612 1431T642 1360Z" />
+<glyph unicode="&#xf0;" glyph-name="eth" horiz-adv-x="1280" d="M640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923 277T1040 560Q1040 726 923 843T640 960ZM606 1418L572 1476Q560 1498 560 1520Q560 1553 583 1576T640 1600Q686 1600
+708 1563L745 1500L881 1579Q909 1596 941 1588T990 1551Q1007 1522 999 1490T962 1441L825 1361L1133 829Q1200 708 1200 560Q1200 328 1036 164T640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q719 1120 790 1101L686 1280L547 1199Q519 1182 487 1190T438
+1227Q421 1256 429 1288T466 1337L606 1418Z" />
+<glyph unicode="&#xf1;" glyph-name="ntilde" horiz-adv-x="1200" d="M80 1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V975Q390 1120 600 1120Q815 1120 967 968T1120 600V80Q1120 47 1097 24T1040 0Q1007 0 984 23T960 80V600Q960 749 855 854T600
+960Q451 960 346 855T240 600V80Q240 47 217 24T160 0Q127 0 104 23T80 80V1040ZM661 1321Q571 1241 449 1241Q316 1241 222 1335Q200 1359 200 1391Q200 1424 223 1447T280 1471Q312 1471 336 1449Q383 1401 449 1401Q505 1401 549 1436Q638 1516 761 1516Q894
+1516 988 1422Q1010 1398 1010 1366Q1010 1333 987 1310T930 1286Q898 1286 874 1308Q827 1356 761 1356Q704 1356 661 1321Z" />
+<glyph unicode="&#xf2;" glyph-name="ograve" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164T640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872 1120 1036 956T1200 560ZM640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923
+277T1040 560Q1040 726 923 843T640 960ZM400 1520Q400 1553 423 1576T480 1600Q513 1600 537 1577L780 1334Q800 1311 800 1280Q800 1247 777 1224T720 1200Q688 1200 665 1221L422 1464Q400 1488 400 1520Z" />
+<glyph unicode="&#xf3;" glyph-name="oacute" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164T640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872 1120 1036 956T1200 560ZM640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923
+277T1040 560Q1040 726 923 843T640 960ZM858 1464L615 1221Q592 1200 560 1200Q527 1200 504 1223T480 1280Q480 1311 500 1334L743 1577Q767 1600 800 1600Q833 1600 856 1577T880 1520Q880 1488 858 1464Z" />
+<glyph unicode="&#xf4;" glyph-name="ocircumflex" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164T640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872 1120 1036 956T1200 560ZM640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160
+923 277T1040 560Q1040 726 923 843T640 960ZM681 1549L920 1390Q960 1360 960 1320Q960 1287 937 1264T880 1240Q851 1240 830 1257L640 1383L450 1257Q429 1240 400 1240Q367 1240 344 1263T320 1320Q320 1360 360 1390L599 1549Q617 1560 640 1560Q663 1560
+681 1549Z" />
+<glyph unicode="&#xf5;" glyph-name="otilde" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164T640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872 1120 1036 956T1200 560ZM640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923
+277T1040 560Q1040 726 923 843T640 960ZM696 1321Q606 1241 484 1241Q351 1241 257 1335Q235 1359 235 1391Q235 1424 258 1447T315 1471Q347 1471 371 1449Q418 1401 484 1401Q540 1401 584 1436Q673 1516 796 1516Q929 1516 1023 1422Q1045 1398 1045 1366Q1045
+1333 1022 1310T965 1286Q933 1286 909 1308Q862 1356 796 1356Q739 1356 696 1321Z" />
+<glyph unicode="&#xf6;" glyph-name="odieresis" horiz-adv-x="1280" d="M1200 560Q1200 328 1036 164T640 0Q408 0 244 164T80 560Q80 792 244 956T640 1120Q872 1120 1036 956T1200 560ZM640 960Q474 960 357 843T240 560Q240 394 357 277T640 160Q806 160 923
+277T1040 560Q1040 726 923 843T640 960ZM500 1360Q500 1319 471 1290T400 1260Q359 1260 330 1289T300 1360Q300 1401 329 1430T400 1460Q441 1460 470 1431T500 1360ZM980 1360Q980 1319 951 1290T880 1260Q839 1260 810 1289T780 1360Q780 1401 809 1430T880
+1460Q921 1460 950 1431T980 1360Z" />
+<glyph unicode="&#xf7;" glyph-name="divide" horiz-adv-x="960" d="M580 1020Q580 979 551 950T480 920Q439 920 410 949T380 1020Q380 1061 409 1090T480 1120Q521 1120 550 1091T580 1020ZM160 640Q127 640 104 663T80 720Q80 753 103 776T160 800H800Q833
+800 856 777T880 720Q880 687 857 664T800 640H160ZM580 420Q580 379 551 350T480 320Q439 320 410 349T380 420Q380 461 409 490T480 520Q521 520 550 491T580 420Z" />
+<glyph unicode="&#xf8;" glyph-name="oslash" horiz-adv-x="1280" d="M861 894Q764 960 640 960Q474 960 357 843T240 560Q240 436 305 339L861 894ZM975 781L419 225Q516 160 640 160Q806 160 923 277T1040 560Q1040 684 975 781ZM976 1009L1061 1094Q1087 1120
+1120 1120Q1153 1120 1176 1097T1200 1040Q1200 1008 1178 984L1089 895Q1200 751 1200 560Q1200 328 1036 164T640 0Q449 0 305 111L217 23Q193 0 160 0Q127 0 104 23T80 80Q80 112 102 136L191 225Q80 369 80 560Q80 792 244 956T640 1120Q831 1120 976 1009Z"
+/>
+<glyph unicode="&#xf9;" glyph-name="ugrave" horiz-adv-x="1200" d="M1120 80Q1120 47 1097 24T1040 0Q1007 0 984 23T960 80V145Q810 0 600 0Q385 0 233 152T80 520V1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V520Q240 371 345 266T600 160Q749
+160 854 265T960 520V1040Q960 1073 983 1096T1040 1120Q1073 1120 1096 1097T1120 1040V80ZM400 1520Q400 1553 423 1576T480 1600Q513 1600 537 1577L780 1334Q800 1311 800 1280Q800 1247 777 1224T720 1200Q688 1200 665 1221L422 1464Q400 1488 400 1520Z"
+/>
+<glyph unicode="&#xfa;" glyph-name="uacute" horiz-adv-x="1200" d="M1120 80Q1120 47 1097 24T1040 0Q1007 0 984 23T960 80V145Q810 0 600 0Q385 0 233 152T80 520V1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V520Q240 371 345 266T600 160Q749
+160 854 265T960 520V1040Q960 1073 983 1096T1040 1120Q1073 1120 1096 1097T1120 1040V80ZM778 1464L535 1221Q512 1200 480 1200Q447 1200 424 1223T400 1280Q400 1311 420 1334L663 1577Q687 1600 720 1600Q753 1600 776 1577T800 1520Q800 1488 778 1464Z"
+/>
+<glyph unicode="&#xfb;" glyph-name="ucircumflex" horiz-adv-x="1200" d="M1120 80Q1120 47 1097 24T1040 0Q1007 0 984 23T960 80V145Q810 0 600 0Q385 0 233 152T80 520V1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V520Q240 371 345 266T600
+160Q749 160 854 265T960 520V1040Q960 1073 983 1096T1040 1120Q1073 1120 1096 1097T1120 1040V80ZM641 1549L880 1390Q920 1360 920 1320Q920 1287 897 1264T840 1240Q811 1240 790 1257L600 1383L410 1257Q389 1240 360 1240Q327 1240 304 1263T280 1320Q280
+1360 320 1390L559 1549Q577 1560 600 1560Q623 1560 641 1549Z" />
+<glyph unicode="&#xfc;" glyph-name="udieresis" horiz-adv-x="1200" d="M1120 80Q1120 47 1097 24T1040 0Q1007 0 984 23T960 80V145Q810 0 600 0Q385 0 233 152T80 520V1040Q80 1073 103 1096T160 1120Q193 1120 216 1097T240 1040V520Q240 371 345 266T600
+160Q749 160 854 265T960 520V1040Q960 1073 983 1096T1040 1120Q1073 1120 1096 1097T1120 1040V80ZM460 1360Q460 1319 431 1290T360 1260Q319 1260 290 1289T260 1360Q260 1401 289 1430T360 1460Q401 1460 430 1431T460 1360ZM940 1360Q940 1319 911 1290T840
+1260Q799 1260 770 1289T740 1360Q740 1401 769 1430T840 1460Q881 1460 910 1431T940 1360Z" />
+<glyph unicode="&#xfd;" glyph-name="yacute" horiz-adv-x="1120" d="M473 81L89 1003Q80 1020 80 1040Q80 1073 103 1096T160 1120Q193 1120 217 1097Q230 1083 236 1067L560 290L884 1067Q890 1083 904 1097Q927 1120 960 1120Q993 1120 1016 1097T1040 1040Q1040
+1020 1031 1003L435 -427Q429 -443 416 -456Q392 -480 359 -480Q326 -480 303 -457T279 -400Q279 -380 288 -363L473 81ZM805 1464L562 1221Q539 1200 507 1200Q474 1200 451 1223T427 1280Q427 1311 447 1334L690 1577Q714 1600 747 1600Q780 1600 803 1577T827
+1520Q827 1488 805 1464Z" />
+<glyph unicode="&#xfe;" glyph-name="thorn" horiz-adv-x="1280" d="M240 562Q240 396 357 279T640 162Q806 162 923 279T1040 562Q1040 728 923 845T640 962Q474 962 357 845T240 562ZM240 954Q408 1122 640 1122Q872 1122 1036 958T1200 562Q1200 330 1036 166T640
+2Q408 2 240 170V-400Q240 -433 217 -456T160 -480Q127 -480 104 -457T80 -400V1522Q80 1555 103 1578T160 1602Q193 1602 216 1579T240 1522V954Z" />
+<glyph unicode="&#xff;" glyph-name="ydieresis" horiz-adv-x="1120" d="M473 81L89 1003Q80 1020 80 1040Q80 1073 103 1096T160 1120Q193 1120 217 1097Q230 1083 236 1067L560 290L884 1067Q890 1083 904 1097Q927 1120 960 1120Q993 1120 1016 1097T1040 1040Q1040
+1020 1031 1003L435 -427Q429 -443 416 -456Q392 -480 359 -480Q326 -480 303 -457T279 -400Q279 -380 288 -363L473 81ZM420 1360Q420 1319 391 1290T320 1260Q279 1260 250 1289T220 1360Q220 1401 249 1430T320 1460Q361 1460 390 1431T420 1360ZM900 1360Q900
+1319 871 1290T800 1260Q759 1260 730 1289T700 1360Q700 1401 729 1430T800 1460Q841 1460 870 1431T900 1360Z" />
+<glyph unicode="&#x2013;" glyph-name="endash" horiz-adv-x="800" d="M0 480Q-33 480 -56 503T-80 560Q-80 593 -57 616T0 640H800Q833 640 856 617T880 560Q880 527 857 504T800 480H0Z" />
+<glyph unicode="&#x2014;" glyph-name="emdash" horiz-adv-x="1920" d="M0 480Q-33 480 -56 503T-80 560Q-80 593 -57 616T0 640H1920Q1953 640 1976 617T2000 560Q2000 527 1977 504T1920 480H0Z" />
+<glyph unicode="&#x2018;" glyph-name="quoteleft" horiz-adv-x="480" d="M373 1040Q373 999 344 970T273 940Q211 940 183 998Q120 1110 120 1225Q120 1400 272 1583Q289 1600 314 1600Q338 1600 355 1583T373 1541Q373 1527 368 1515Q270 1278 365 1080Q373
+1062 373 1040Z" />
+<glyph unicode="&#x2019;" glyph-name="quoteright" horiz-adv-x="480" d="M120 1500Q120 1541 149 1570T220 1600Q282 1600 310 1542Q373 1430 373 1315Q373 1140 221 957Q204 940 179 940Q155 940 138 957T120 999Q120 1013 125 1025Q223 1262 128 1460Q120
+1478 120 1500Z" />
+<glyph unicode="&#x201a;" glyph-name="quotesinglbase" horiz-adv-x="480" d="M120 219Q120 260 149 289T220 319Q282 319 310 261Q373 149 373 34Q373 -141 221 -324Q204 -341 179 -341Q155 -341 138 -324T120 -282Q120 -268 125 -256Q223 -19 128 179Q120 197
+120 219Z" />
+<glyph unicode="&#x201c;" glyph-name="quotedblleft" horiz-adv-x="760" d="M333 1042Q333 1001 304 972T233 942Q171 942 143 1000Q80 1112 80 1227Q80 1402 232 1585Q249 1602 274 1602Q298 1602 315 1585T333 1543Q333 1529 328 1517Q230 1280 325 1082Q333
+1064 333 1042ZM680 1042Q680 1001 651 972T580 942Q518 942 490 1000Q427 1112 427 1227Q427 1402 579 1585Q596 1602 621 1602Q645 1602 662 1585T680 1543Q680 1529 675 1517Q577 1280 672 1082Q680 1064 680 1042Z" />
+<glyph unicode="&#x201d;" glyph-name="quotedblright" horiz-adv-x="760" d="M427 1502Q427 1543 456 1572T527 1602Q589 1602 617 1544Q680 1432 680 1317Q680 1142 528 959Q511 942 486 942Q462 942 445 959T427 1001Q427 1015 432 1027Q530 1264 435 1462Q427
+1480 427 1502ZM80 1502Q80 1543 109 1572T180 1602Q242 1602 270 1544Q333 1432 333 1317Q333 1142 181 959Q164 942 139 942Q115 942 98 959T80 1001Q80 1015 85 1027Q183 1264 88 1462Q80 1480 80 1502Z" />
+<glyph unicode="&#x201e;" glyph-name="quotedblbase" horiz-adv-x="760" d="M427 220Q427 261 456 290T527 320Q589 320 617 262Q680 150 680 35Q680 -140 528 -323Q511 -340 486 -340Q462 -340 445 -323T427 -281Q427 -267 432 -255Q530 -18 435 180Q427 198
+427 220ZM80 220Q80 261 109 290T180 320Q242 320 270 262Q333 150 333 35Q333 -140 181 -323Q164 -340 139 -340Q115 -340 98 -323T80 -281Q80 -267 85 -255Q183 -18 88 180Q80 198 80 220Z" />
+<glyph unicode="&#x2022;" glyph-name="bullet" horiz-adv-x="800" d="M640 800Q640 701 570 631T400 560Q301 560 231 630T160 800Q160 899 230 969T400 1040Q499 1040 569 970T640 800Z" />
+<glyph unicode="&#x2039;" glyph-name="guilsinglleft" horiz-adv-x="560" d="M90 598L326 1070Q332 1084 344 1096Q367 1119 400 1119Q433 1119 456 1096T480 1039Q480 1021 473 1005L250 560L473 114Q480 98 480 80Q480 47 457 24T400 0Q367 0 344 24Q332 35
+326 49L92 516Q80 538 80 559Q80 579 90 598Z" />
+<glyph unicode="&#x203a;" glyph-name="guilsinglright" horiz-adv-x="560" d="M480 559Q480 538 468 516L234 49Q228 35 216 24Q193 0 160 0Q127 0 104 23T80 80Q80 98 87 114L310 560L87 1005Q80 1021 80 1039Q80 1072 103 1095T160 1119Q193 1119 216 1096Q228
+1084 234 1070L470 598Q480 579 480 559Z" />
+<hkern g1="A" g2="C" k="98" />
+<hkern g1="A" g2="G" k="98" />
+<hkern g1="A" g2="O" k="69" />
+<hkern g1="A" g2="Q" k="69" />
+<hkern g1="A" g2="T" k="179" />
+<hkern g1="A" g2="V" k="189" />
+<hkern g1="A" g2="W" k="116" />
+<hkern g1="A" g2="Y" k="179" />
+<hkern g1="A" g2="f" k="64" />
+<hkern g1="A" g2="j" k="186" />
+<hkern g1="A" g2="t" k="148" />
+<hkern g1="A" g2="v" k="225" />
+<hkern g1="A" g2="w" k="199" />
+<hkern g1="A" g2="y" k="256" />
+<hkern g1="A" g2="Ccedilla" k="98" />
+<hkern g1="A" g2="Eth" k="52" />
+<hkern g1="A" g2="Ograve" k="69" />
+<hkern g1="A" g2="Oacute" k="69" />
+<hkern g1="A" g2="Ocircumflex" k="69" />
+<hkern g1="A" g2="Otilde" k="69" />
+<hkern g1="A" g2="Odieresis" k="69" />
+<hkern g1="A" g2="Yacute" k="179" />
+<hkern g1="A" g2="yacute" k="256" />
+<hkern g1="A" g2="ydieresis" k="256" />
+<hkern g1="B" g2="T" k="158" />
+<hkern g1="B" g2="V" k="127" />
+<hkern g1="B" g2="W" k="100" />
+<hkern g1="B" g2="Y" k="157" />
+<hkern g1="B" g2="j" k="230" />
+<hkern g1="B" g2="x" k="65" />
+<hkern g1="B" g2="y" k="65" />
+<hkern g1="B" g2="Yacute" k="157" />
+<hkern g1="B" g2="yacute" k="65" />
+<hkern g1="B" g2="ydieresis" k="65" />
+<hkern g1="C" g2="C" k="74" />
+<hkern g1="C" g2="G" k="74" />
+<hkern g1="C" g2="O" k="45" />
+<hkern g1="C" g2="Q" k="45" />
+<hkern g1="C" g2="f" k="91" />
+<hkern g1="C" g2="j" k="256" />
+<hkern g1="C" g2="t" k="40" />
+<hkern g1="C" g2="v" k="84" />
+<hkern g1="C" g2="w" k="143" />
+<hkern g1="C" g2="y" k="116" />
+<hkern g1="C" g2="Ccedilla" k="74" />
+<hkern g1="C" g2="Ograve" k="45" />
+<hkern g1="C" g2="Oacute" k="45" />
+<hkern g1="C" g2="Ocircumflex" k="45" />
+<hkern g1="C" g2="Otilde" k="45" />
+<hkern g1="C" g2="Odieresis" k="45" />
+<hkern g1="C" g2="yacute" k="79" />
+<hkern g1="C" g2="ydieresis" k="62" />
+<hkern g1="D" g2="A" k="113" />
+<hkern g1="D" g2="T" k="143" />
+<hkern g1="D" g2="V" k="113" />
+<hkern g1="D" g2="X" k="175" />
+<hkern g1="D" g2="Y" k="175" />
+<hkern g1="D" g2="Z" k="207" />
+<hkern g1="D" g2="j" k="276" />
+<hkern g1="D" g2="Agrave" k="113" />
+<hkern g1="D" g2="Aacute" k="113" />
+<hkern g1="D" g2="Acircumflex" k="113" />
+<hkern g1="D" g2="Atilde" k="113" />
+<hkern g1="D" g2="Adieresis" k="113" />
+<hkern g1="D" g2="Aring" k="113" />
+<hkern g1="D" g2="AE" k="116" />
+<hkern g1="D" g2="Yacute" k="175" />
+<hkern g1="E" g2="C" k="128" />
+<hkern g1="E" g2="G" k="128" />
+<hkern g1="E" g2="O" k="130" />
+<hkern g1="E" g2="Q" k="130" />
+<hkern g1="E" g2="c" k="65" />
+<hkern g1="E" g2="f" k="62" />
+<hkern g1="E" g2="j" k="184" />
+<hkern g1="E" g2="t" k="62" />
+<hkern g1="E" g2="v" k="90" />
+<hkern g1="E" g2="w" k="166" />
+<hkern g1="E" g2="y" k="122" />
+<hkern g1="E" g2="Ccedilla" k="128" />
+<hkern g1="E" g2="Eth" k="50" />
+<hkern g1="E" g2="Ograve" k="130" />
+<hkern g1="E" g2="Oacute" k="130" />
+<hkern g1="E" g2="Ocircumflex" k="130" />
+<hkern g1="E" g2="Otilde" k="130" />
+<hkern g1="E" g2="Odieresis" k="130" />
+<hkern g1="E" g2="ae" k="48" />
+<hkern g1="E" g2="ccedilla" k="65" />
+<hkern g1="E" g2="eth" k="57" />
+<hkern g1="E" g2="yacute" k="109" />
+<hkern g1="E" g2="ydieresis" k="65" />
+<hkern g1="F" g2="A" k="183" />
+<hkern g1="F" g2="C" k="128" />
+<hkern g1="F" g2="G" k="128" />
+<hkern g1="F" g2="J" k="148" />
+<hkern g1="F" g2="O" k="130" />
+<hkern g1="F" g2="Q" k="130" />
+<hkern g1="F" g2="S" k="99" />
+<hkern g1="F" g2="a" k="206" />
+<hkern g1="F" g2="c" k="217" />
+<hkern g1="F" g2="d" k="225" />
+<hkern g1="F" g2="e" k="206" />
+<hkern g1="F" g2="f" k="157" />
+<hkern g1="F" g2="g" k="162" />
+<hkern g1="F" g2="j" k="222" />
+<hkern g1="F" g2="m" k="136" />
+<hkern g1="F" g2="n" k="129" />
+<hkern g1="F" g2="o" k="162" />
+<hkern g1="F" g2="p" k="162" />
+<hkern g1="F" g2="q" k="162" />
+<hkern g1="F" g2="r" k="126" />
+<hkern g1="F" g2="s" k="127" />
+<hkern g1="F" g2="t" k="62" />
+<hkern g1="F" g2="u" k="179" />
+<hkern g1="F" g2="v" k="192" />
+<hkern g1="F" g2="w" k="166" />
+<hkern g1="F" g2="x" k="254" />
+<hkern g1="F" g2="y" k="223" />
+<hkern g1="F" g2="z" k="60" />
+<hkern g1="F" g2="Agrave" k="183" />
+<hkern g1="F" g2="Aacute" k="175" />
+<hkern g1="F" g2="Acircumflex" k="183" />
+<hkern g1="F" g2="Atilde" k="167" />
+<hkern g1="F" g2="Adieresis" k="183" />
+<hkern g1="F" g2="Aring" k="198" />
+<hkern g1="F" g2="AE" k="285" />
+<hkern g1="F" g2="Ccedilla" k="128" />
+<hkern g1="F" g2="Eth" k="50" />
+<hkern g1="F" g2="Ograve" k="130" />
+<hkern g1="F" g2="Oacute" k="130" />
+<hkern g1="F" g2="Ocircumflex" k="130" />
+<hkern g1="F" g2="Otilde" k="130" />
+<hkern g1="F" g2="Odieresis" k="130" />
+<hkern g1="F" g2="Oslash" k="130" />
+<hkern g1="F" g2="agrave" k="162" />
+<hkern g1="F" g2="aacute" k="162" />
+<hkern g1="F" g2="acircumflex" k="162" />
+<hkern g1="F" g2="adieresis" k="130" />
+<hkern g1="F" g2="aring" k="162" />
+<hkern g1="F" g2="ae" k="174" />
+<hkern g1="F" g2="ccedilla" k="160" />
+<hkern g1="F" g2="egrave" k="162" />
+<hkern g1="F" g2="eacute" k="162" />
+<hkern g1="F" g2="ecircumflex" k="162" />
+<hkern g1="F" g2="edieresis" k="130" />
+<hkern g1="F" g2="eth" k="152" />
+<hkern g1="F" g2="ograve" k="162" />
+<hkern g1="F" g2="oacute" k="162" />
+<hkern g1="F" g2="ocircumflex" k="162" />
+<hkern g1="F" g2="odieresis" k="130" />
+<hkern g1="F" g2="oslash" k="162" />
+<hkern g1="F" g2="ugrave" k="129" />
+<hkern g1="F" g2="uacute" k="129" />
+<hkern g1="F" g2="ucircumflex" k="98" />
+<hkern g1="F" g2="udieresis" k="66" />
+<hkern g1="F" g2="yacute" k="223" />
+<hkern g1="F" g2="ydieresis" k="65" />
+<hkern g1="F" g2="dotlessi" k="196" />
+<hkern g1="G" g2="f" k="60" />
+<hkern g1="G" g2="j" k="198" />
+<hkern g1="G" g2="t" k="60" />
+<hkern g1="H" g2="j" k="159" />
+<hkern g1="I" g2="I" k="26" />
+<hkern g1="I" g2="j" k="192" />
+<hkern g1="I" g2="Igrave" k="60" />
+<hkern g1="I" g2="Iacute" k="66" />
+<hkern g1="I" g2="Icircumflex" k="73" />
+<hkern g1="I" g2="Idieresis" k="52" />
+<hkern g1="I" g2="dotlessi" k="51" />
+<hkern g1="J" g2="j" k="145" />
+<hkern g1="K" g2="C" k="194" />
+<hkern g1="K" g2="G" k="207" />
+<hkern g1="K" g2="O" k="177" />
+<hkern g1="K" g2="Q" k="177" />
+<hkern g1="K" g2="a" k="89" />
+<hkern g1="K" g2="c" k="81" />
+<hkern g1="K" g2="d" k="89" />
+<hkern g1="K" g2="e" k="83" />
+<hkern g1="K" g2="f" k="65" />
+<hkern g1="K" g2="j" k="180" />
+<hkern g1="K" g2="o" k="83" />
+<hkern g1="K" g2="q" k="83" />
+<hkern g1="K" g2="t" k="71" />
+<hkern g1="K" g2="v" k="117" />
+<hkern g1="K" g2="w" k="181" />
+<hkern g1="K" g2="y" k="71" />
+<hkern g1="K" g2="Ccedilla" k="105" />
+<hkern g1="K" g2="Ograve" k="177" />
+<hkern g1="K" g2="Oacute" k="177" />
+<hkern g1="K" g2="Ocircumflex" k="177" />
+<hkern g1="K" g2="Otilde" k="177" />
+<hkern g1="K" g2="Odieresis" k="177" />
+<hkern g1="K" g2="agrave" k="101" />
+<hkern g1="K" g2="aacute" k="83" />
+<hkern g1="K" g2="acircumflex" k="76" />
+<hkern g1="K" g2="atilde" k="70" />
+<hkern g1="K" g2="adieresis" k="83" />
+<hkern g1="K" g2="aring" k="76" />
+<hkern g1="K" g2="ae" k="95" />
+<hkern g1="K" g2="ccedilla" k="87" />
+<hkern g1="K" g2="egrave" k="76" />
+<hkern g1="K" g2="eacute" k="76" />
+<hkern g1="K" g2="ecircumflex" k="95" />
+<hkern g1="K" g2="edieresis" k="95" />
+<hkern g1="K" g2="eth" k="85" />
+<hkern g1="K" g2="ograve" k="76" />
+<hkern g1="K" g2="oacute" k="89" />
+<hkern g1="K" g2="ocircumflex" k="83" />
+<hkern g1="K" g2="otilde" k="76" />
+<hkern g1="K" g2="odieresis" k="95" />
+<hkern g1="K" g2="yacute" k="143" />
+<hkern g1="K" g2="ydieresis" k="158" />
+<hkern g1="L" g2="C" k="166" />
+<hkern g1="L" g2="G" k="151" />
+<hkern g1="L" g2="O" k="166" />
+<hkern g1="L" g2="Q" k="143" />
+<hkern g1="L" g2="T" k="316" />
+<hkern g1="L" g2="U" k="79" />
+<hkern g1="L" g2="V" k="277" />
+<hkern g1="L" g2="W" k="229" />
+<hkern g1="L" g2="Y" k="309" />
+<hkern g1="L" g2="a" k="51" />
+<hkern g1="L" g2="b" k="51" />
+<hkern g1="L" g2="c" k="81" />
+<hkern g1="L" g2="d" k="51" />
+<hkern g1="L" g2="e" k="51" />
+<hkern g1="L" g2="f" k="46" />
+<hkern g1="L" g2="j" k="221" />
+<hkern g1="L" g2="o" k="51" />
+<hkern g1="L" g2="q" k="51" />
+<hkern g1="L" g2="t" k="109" />
+<hkern g1="L" g2="v" k="238" />
+<hkern g1="L" g2="w" k="181" />
+<hkern g1="L" g2="y" k="145" />
+<hkern g1="L" g2="Ccedilla" k="141" />
+<hkern g1="L" g2="Ograve" k="166" />
+<hkern g1="L" g2="Oacute" k="158" />
+<hkern g1="L" g2="Ocircumflex" k="182" />
+<hkern g1="L" g2="Otilde" k="151" />
+<hkern g1="L" g2="Odieresis" k="189" />
+<hkern g1="L" g2="Ugrave" k="79" />
+<hkern g1="L" g2="Uacute" k="79" />
+<hkern g1="L" g2="Ucircumflex" k="79" />
+<hkern g1="L" g2="Udieresis" k="79" />
+<hkern g1="L" g2="Yacute" k="277" />
+<hkern g1="L" g2="agrave" k="51" />
+<hkern g1="L" g2="aacute" k="51" />
+<hkern g1="L" g2="acircumflex" k="51" />
+<hkern g1="L" g2="atilde" k="51" />
+<hkern g1="L" g2="adieresis" k="51" />
+<hkern g1="L" g2="aring" k="51" />
+<hkern g1="L" g2="ae" k="63" />
+<hkern g1="L" g2="ccedilla" k="81" />
+<hkern g1="L" g2="egrave" k="51" />
+<hkern g1="L" g2="eacute" k="51" />
+<hkern g1="L" g2="ecircumflex" k="51" />
+<hkern g1="L" g2="edieresis" k="51" />
+<hkern g1="L" g2="eth" k="41" />
+<hkern g1="L" g2="ograve" k="51" />
+<hkern g1="L" g2="oacute" k="51" />
+<hkern g1="L" g2="ocircumflex" k="51" />
+<hkern g1="L" g2="otilde" k="51" />
+<hkern g1="L" g2="odieresis" k="51" />
+<hkern g1="L" g2="yacute" k="131" />
+<hkern g1="L" g2="ydieresis" k="154" />
+<hkern g1="M" g2="j" k="189" />
+<hkern g1="N" g2="j" k="177" />
+<hkern g1="O" g2="A" k="131" />
+<hkern g1="O" g2="S" k="65" />
+<hkern g1="O" g2="T" k="106" />
+<hkern g1="O" g2="V" k="131" />
+<hkern g1="O" g2="W" k="73" />
+<hkern g1="O" g2="X" k="224" />
+<hkern g1="O" g2="Y" k="224" />
+<hkern g1="O" g2="Z" k="225" />
+<hkern g1="O" g2="j" k="255" />
+<hkern g1="O" g2="Agrave" k="131" />
+<hkern g1="O" g2="Aacute" k="131" />
+<hkern g1="O" g2="Acircumflex" k="131" />
+<hkern g1="O" g2="Atilde" k="131" />
+<hkern g1="O" g2="Adieresis" k="131" />
+<hkern g1="O" g2="Aring" k="131" />
+<hkern g1="O" g2="AE" k="165" />
+<hkern g1="O" g2="Yacute" k="224" />
+<hkern g1="P" g2="A" k="226" />
+<hkern g1="P" g2="J" k="176" />
+<hkern g1="P" g2="T" k="55" />
+<hkern g1="P" g2="X" k="54" />
+<hkern g1="P" g2="Y" k="54" />
+<hkern g1="P" g2="Z" k="55" />
+<hkern g1="P" g2="j" k="243" />
+<hkern g1="P" g2="Agrave" k="195" />
+<hkern g1="P" g2="Aacute" k="242" />
+<hkern g1="P" g2="Acircumflex" k="250" />
+<hkern g1="P" g2="Atilde" k="211" />
+<hkern g1="P" g2="Adieresis" k="203" />
+<hkern g1="P" g2="Aring" k="234" />
+<hkern g1="P" g2="AE" k="321" />
+<hkern g1="P" g2="Yacute" k="54" />
+<hkern g1="Q" g2="T" k="139" />
+<hkern g1="Q" g2="V" k="131" />
+<hkern g1="Q" g2="W" k="73" />
+<hkern g1="Q" g2="Y" k="224" />
+<hkern g1="Q" g2="j" k="163" />
+<hkern g1="Q" g2="Yacute" k="224" />
+<hkern g1="R" g2="J" k="95" />
+<hkern g1="R" g2="T" k="111" />
+<hkern g1="R" g2="V" k="80" />
+<hkern g1="R" g2="Y" k="110" />
+<hkern g1="R" g2="a" k="101" />
+<hkern g1="R" g2="c" k="106" />
+<hkern g1="R" g2="d" k="89" />
+<hkern g1="R" g2="e" k="95" />
+<hkern g1="R" g2="j" k="150" />
+<hkern g1="R" g2="o" k="89" />
+<hkern g1="R" g2="q" k="76" />
+<hkern g1="R" g2="Yacute" k="110" />
+<hkern g1="R" g2="agrave" k="83" />
+<hkern g1="R" g2="aacute" k="89" />
+<hkern g1="R" g2="acircumflex" k="76" />
+<hkern g1="R" g2="atilde" k="76" />
+<hkern g1="R" g2="adieresis" k="76" />
+<hkern g1="R" g2="aring" k="76" />
+<hkern g1="R" g2="ae" k="82" />
+<hkern g1="R" g2="ccedilla" k="81" />
+<hkern g1="R" g2="egrave" k="83" />
+<hkern g1="R" g2="eacute" k="95" />
+<hkern g1="R" g2="ecircumflex" k="89" />
+<hkern g1="R" g2="edieresis" k="83" />
+<hkern g1="R" g2="eth" k="73" />
+<hkern g1="R" g2="ograve" k="95" />
+<hkern g1="R" g2="oacute" k="95" />
+<hkern g1="R" g2="ocircumflex" k="83" />
+<hkern g1="R" g2="otilde" k="70" />
+<hkern g1="R" g2="odieresis" k="76" />
+<hkern g1="S" g2="j" k="179" />
+<hkern g1="S" g2="y" k="68" />
+<hkern g1="S" g2="yacute" k="68" />
+<hkern g1="S" g2="ydieresis" k="68" />
+<hkern g1="T" g2="A" k="324" />
+<hkern g1="T" g2="C" k="190" />
+<hkern g1="T" g2="G" k="159" />
+<hkern g1="T" g2="J" k="269" />
+<hkern g1="T" g2="O" k="128" />
+<hkern g1="T" g2="Q" k="167" />
+<hkern g1="T" g2="S" k="46" />
+<hkern g1="T" g2="a" k="277" />
+<hkern g1="T" g2="c" k="308" />
+<hkern g1="T" g2="d" k="238" />
+<hkern g1="T" g2="e" k="285" />
+<hkern g1="T" g2="f" k="190" />
+<hkern g1="T" g2="g" k="243" />
+<hkern g1="T" g2="j" k="270" />
+<hkern g1="T" g2="m" k="204" />
+<hkern g1="T" g2="n" k="182" />
+<hkern g1="T" g2="o" k="238" />
+<hkern g1="T" g2="p" k="244" />
+<hkern g1="T" g2="q" k="258" />
+<hkern g1="T" g2="r" k="95" />
+<hkern g1="T" g2="s" k="137" />
+<hkern g1="T" g2="t" k="47" />
+<hkern g1="T" g2="u" k="114" />
+<hkern g1="T" g2="v" k="152" />
+<hkern g1="T" g2="w" k="114" />
+<hkern g1="T" g2="x" k="137" />
+<hkern g1="T" g2="y" k="146" />
+<hkern g1="T" g2="z" k="90" />
+<hkern g1="T" g2="Agrave" k="168" />
+<hkern g1="T" g2="Aacute" k="152" />
+<hkern g1="T" g2="Acircumflex" k="160" />
+<hkern g1="T" g2="Atilde" k="191" />
+<hkern g1="T" g2="Adieresis" k="176" />
+<hkern g1="T" g2="Aring" k="191" />
+<hkern g1="T" g2="AE" k="277" />
+<hkern g1="T" g2="Ccedilla" k="94" />
+<hkern g1="T" g2="Ograve" k="151" />
+<hkern g1="T" g2="Oacute" k="174" />
+<hkern g1="T" g2="Ocircumflex" k="151" />
+<hkern g1="T" g2="Otilde" k="159" />
+<hkern g1="T" g2="Odieresis" k="174" />
+<hkern g1="T" g2="Oslash" k="174" />
+<hkern g1="T" g2="agrave" k="214" />
+<hkern g1="T" g2="aacute" k="238" />
+<hkern g1="T" g2="acircumflex" k="175" />
+<hkern g1="T" g2="atilde" k="147" />
+<hkern g1="T" g2="adieresis" k="238" />
+<hkern g1="T" g2="aring" k="112" />
+<hkern g1="T" g2="ae" k="277" />
+<hkern g1="T" g2="ccedilla" k="278" />
+<hkern g1="T" g2="egrave" k="214" />
+<hkern g1="T" g2="eacute" k="238" />
+<hkern g1="T" g2="ecircumflex" k="175" />
+<hkern g1="T" g2="edieresis" k="238" />
+<hkern g1="T" g2="idieresis" k="17" />
+<hkern g1="T" g2="eth" k="175" />
+<hkern g1="T" g2="ograve" k="175" />
+<hkern g1="T" g2="oacute" k="160" />
+<hkern g1="T" g2="ocircumflex" k="175" />
+<hkern g1="T" g2="otilde" k="52" />
+<hkern g1="T" g2="odieresis" k="152" />
+<hkern g1="T" g2="oslash" k="152" />
+<hkern g1="T" g2="ugrave" k="82" />
+<hkern g1="T" g2="uacute" k="145" />
+<hkern g1="T" g2="ucircumflex" k="175" />
+<hkern g1="T" g2="udieresis" k="121" />
+<hkern g1="T" g2="yacute" k="171" />
+<hkern g1="T" g2="ydieresis" k="162" />
+<hkern g1="T" g2="dotlessi" k="288" />
+<hkern g1="U" g2="j" k="187" />
+<hkern g1="V" g2="A" k="232" />
+<hkern g1="V" g2="C" k="98" />
+<hkern g1="V" g2="G" k="98" />
+<hkern g1="V" g2="J" k="214" />
+<hkern g1="V" g2="O" k="69" />
+<hkern g1="V" g2="Q" k="69" />
+<hkern g1="V" g2="S" k="63" />
+<hkern g1="V" g2="a" k="195" />
+<hkern g1="V" g2="c" k="224" />
+<hkern g1="V" g2="d" k="195" />
+<hkern g1="V" g2="e" k="195" />
+<hkern g1="V" g2="f" k="95" />
+<hkern g1="V" g2="g" k="195" />
+<hkern g1="V" g2="j" k="270" />
+<hkern g1="V" g2="m" k="75" />
+<hkern g1="V" g2="o" k="195" />
+<hkern g1="V" g2="p" k="195" />
+<hkern g1="V" g2="q" k="195" />
+<hkern g1="V" g2="r" k="65" />
+<hkern g1="V" g2="s" k="160" />
+<hkern g1="V" g2="t" k="64" />
+<hkern g1="V" g2="w" k="73" />
+<hkern g1="V" g2="x" k="67" />
+<hkern g1="V" g2="y" k="67" />
+<hkern g1="V" g2="z" k="67" />
+<hkern g1="V" g2="Agrave" k="232" />
+<hkern g1="V" g2="Aacute" k="232" />
+<hkern g1="V" g2="Acircumflex" k="232" />
+<hkern g1="V" g2="Atilde" k="232" />
+<hkern g1="V" g2="Adieresis" k="232" />
+<hkern g1="V" g2="Aring" k="232" />
+<hkern g1="V" g2="AE" k="239" />
+<hkern g1="V" g2="Ccedilla" k="98" />
+<hkern g1="V" g2="Eth" k="52" />
+<hkern g1="V" g2="Ograve" k="69" />
+<hkern g1="V" g2="Oacute" k="69" />
+<hkern g1="V" g2="Ocircumflex" k="69" />
+<hkern g1="V" g2="Otilde" k="69" />
+<hkern g1="V" g2="Odieresis" k="69" />
+<hkern g1="V" g2="Oslash" k="69" />
+<hkern g1="V" g2="agrave" k="195" />
+<hkern g1="V" g2="aacute" k="195" />
+<hkern g1="V" g2="acircumflex" k="163" />
+<hkern g1="V" g2="adieresis" k="132" />
+<hkern g1="V" g2="aring" k="195" />
+<hkern g1="V" g2="ae" k="207" />
+<hkern g1="V" g2="ccedilla" k="130" />
+<hkern g1="V" g2="egrave" k="195" />
+<hkern g1="V" g2="eacute" k="195" />
+<hkern g1="V" g2="ecircumflex" k="163" />
+<hkern g1="V" g2="edieresis" k="132" />
+<hkern g1="V" g2="eth" k="216" />
+<hkern g1="V" g2="ograve" k="195" />
+<hkern g1="V" g2="oacute" k="195" />
+<hkern g1="V" g2="ocircumflex" k="163" />
+<hkern g1="V" g2="odieresis" k="132" />
+<hkern g1="V" g2="oslash" k="195" />
+<hkern g1="V" g2="yacute" k="67" />
+<hkern g1="V" g2="ydieresis" k="67" />
+<hkern g1="V" g2="dotlessi" k="135" />
+<hkern g1="W" g2="A" k="151" />
+<hkern g1="W" g2="C" k="101" />
+<hkern g1="W" g2="G" k="101" />
+<hkern g1="W" g2="J" k="191" />
+<hkern g1="W" g2="O" k="71" />
+<hkern g1="W" g2="Q" k="71" />
+<hkern g1="W" g2="S" k="65" />
+<hkern g1="W" g2="a" k="134" />
+<hkern g1="W" g2="c" k="164" />
+<hkern g1="W" g2="d" k="134" />
+<hkern g1="W" g2="e" k="134" />
+<hkern g1="W" g2="f" k="66" />
+<hkern g1="W" g2="g" k="134" />
+<hkern g1="W" g2="j" k="222" />
+<hkern g1="W" g2="m" k="46" />
+<hkern g1="W" g2="o" k="134" />
+<hkern g1="W" g2="p" k="134" />
+<hkern g1="W" g2="q" k="134" />
+<hkern g1="W" g2="r" k="67" />
+<hkern g1="W" g2="s" k="131" />
+<hkern g1="W" g2="t" k="66" />
+<hkern g1="W" g2="w" k="44" />
+<hkern g1="W" g2="x" k="69" />
+<hkern g1="W" g2="y" k="69" />
+<hkern g1="W" g2="z" k="69" />
+<hkern g1="W" g2="Agrave" k="159" />
+<hkern g1="W" g2="Aacute" k="159" />
+<hkern g1="W" g2="Acircumflex" k="183" />
+<hkern g1="W" g2="Atilde" k="159" />
+<hkern g1="W" g2="Adieresis" k="136" />
+<hkern g1="W" g2="Aring" k="190" />
+<hkern g1="W" g2="AE" k="167" />
+<hkern g1="W" g2="Ccedilla" k="101" />
+<hkern g1="W" g2="Ograve" k="71" />
+<hkern g1="W" g2="Oacute" k="71" />
+<hkern g1="W" g2="Ocircumflex" k="71" />
+<hkern g1="W" g2="Otilde" k="71" />
+<hkern g1="W" g2="Odieresis" k="71" />
+<hkern g1="W" g2="Oslash" k="71" />
+<hkern g1="W" g2="agrave" k="134" />
+<hkern g1="W" g2="aacute" k="134" />
+<hkern g1="W" g2="acircumflex" k="134" />
+<hkern g1="W" g2="atilde" k="71" />
+<hkern g1="W" g2="adieresis" k="134" />
+<hkern g1="W" g2="aring" k="134" />
+<hkern g1="W" g2="ae" k="178" />
+<hkern g1="W" g2="ccedilla" k="164" />
+<hkern g1="W" g2="egrave" k="134" />
+<hkern g1="W" g2="eacute" k="134" />
+<hkern g1="W" g2="ecircumflex" k="134" />
+<hkern g1="W" g2="edieresis" k="134" />
+<hkern g1="W" g2="eth" k="156" />
+<hkern g1="W" g2="ograve" k="134" />
+<hkern g1="W" g2="oacute" k="134" />
+<hkern g1="W" g2="ocircumflex" k="134" />
+<hkern g1="W" g2="otilde" k="71" />
+<hkern g1="W" g2="odieresis" k="134" />
+<hkern g1="W" g2="oslash" k="134" />
+<hkern g1="W" g2="yacute" k="69" />
+<hkern g1="W" g2="ydieresis" k="69" />
+<hkern g1="W" g2="dotlessi" k="106" />
+<hkern g1="X" g2="C" k="194" />
+<hkern g1="X" g2="G" k="140" />
+<hkern g1="X" g2="O" k="164" />
+<hkern g1="X" g2="Q" k="164" />
+<hkern g1="X" g2="c" k="68" />
+<hkern g1="X" g2="f" k="65" />
+<hkern g1="X" g2="j" k="133" />
+<hkern g1="X" g2="t" k="65" />
+<hkern g1="X" g2="v" k="163" />
+<hkern g1="X" g2="w" k="200" />
+<hkern g1="X" g2="y" k="103" />
+<hkern g1="X" g2="Ccedilla" k="114" />
+<hkern g1="X" g2="Eth" k="53" />
+<hkern g1="X" g2="Ograve" k="109" />
+<hkern g1="X" g2="Oacute" k="164" />
+<hkern g1="X" g2="Ocircumflex" k="109" />
+<hkern g1="X" g2="Otilde" k="109" />
+<hkern g1="X" g2="Odieresis" k="164" />
+<hkern g1="X" g2="ae" k="82" />
+<hkern g1="X" g2="ccedilla" k="68" />
+<hkern g1="X" g2="eth" k="60" />
+<hkern g1="X" g2="yacute" k="128" />
+<hkern g1="X" g2="ydieresis" k="111" />
+<hkern g1="Y" g2="A" k="240" />
+<hkern g1="Y" g2="C" k="160" />
+<hkern g1="Y" g2="G" k="160" />
+<hkern g1="Y" g2="J" k="193" />
+<hkern g1="Y" g2="O" k="130" />
+<hkern g1="Y" g2="Q" k="130" />
+<hkern g1="Y" g2="S" k="61" />
+<hkern g1="Y" g2="a" k="170" />
+<hkern g1="Y" g2="c" k="162" />
+<hkern g1="Y" g2="d" k="162" />
+<hkern g1="Y" g2="e" k="162" />
+<hkern g1="Y" g2="f" k="157" />
+<hkern g1="Y" g2="g" k="167" />
+<hkern g1="Y" g2="j" k="201" />
+<hkern g1="Y" g2="m" k="168" />
+<hkern g1="Y" g2="n" k="129" />
+<hkern g1="Y" g2="o" k="193" />
+<hkern g1="Y" g2="p" k="168" />
+<hkern g1="Y" g2="q" k="182" />
+<hkern g1="Y" g2="r" k="158" />
+<hkern g1="Y" g2="s" k="131" />
+<hkern g1="Y" g2="t" k="62" />
+<hkern g1="Y" g2="u" k="129" />
+<hkern g1="Y" g2="v" k="129" />
+<hkern g1="Y" g2="w" k="166" />
+<hkern g1="Y" g2="x" k="160" />
+<hkern g1="Y" g2="y" k="160" />
+<hkern g1="Y" g2="z" k="160" />
+<hkern g1="Y" g2="Agrave" k="193" />
+<hkern g1="Y" g2="Aacute" k="162" />
+<hkern g1="Y" g2="Acircumflex" k="162" />
+<hkern g1="Y" g2="Atilde" k="162" />
+<hkern g1="Y" g2="Adieresis" k="162" />
+<hkern g1="Y" g2="Aring" k="162" />
+<hkern g1="Y" g2="AE" k="162" />
+<hkern g1="Y" g2="Ccedilla" k="160" />
+<hkern g1="Y" g2="Eth" k="50" />
+<hkern g1="Y" g2="Ograve" k="130" />
+<hkern g1="Y" g2="Oacute" k="130" />
+<hkern g1="Y" g2="Ocircumflex" k="130" />
+<hkern g1="Y" g2="Otilde" k="130" />
+<hkern g1="Y" g2="Odieresis" k="130" />
+<hkern g1="Y" g2="Oslash" k="130" />
+<hkern g1="Y" g2="agrave" k="162" />
+<hkern g1="Y" g2="aacute" k="162" />
+<hkern g1="Y" g2="acircumflex" k="131" />
+<hkern g1="Y" g2="atilde" k="67" />
+<hkern g1="Y" g2="adieresis" k="131" />
+<hkern g1="Y" g2="aring" k="99" />
+<hkern g1="Y" g2="ae" k="162" />
+<hkern g1="Y" g2="ccedilla" k="171" />
+<hkern g1="Y" g2="egrave" k="162" />
+<hkern g1="Y" g2="eacute" k="162" />
+<hkern g1="Y" g2="ecircumflex" k="131" />
+<hkern g1="Y" g2="edieresis" k="131" />
+<hkern g1="Y" g2="eth" k="162" />
+<hkern g1="Y" g2="ograve" k="162" />
+<hkern g1="Y" g2="oacute" k="162" />
+<hkern g1="Y" g2="ocircumflex" k="131" />
+<hkern g1="Y" g2="otilde" k="67" />
+<hkern g1="Y" g2="odieresis" k="131" />
+<hkern g1="Y" g2="oslash" k="162" />
+<hkern g1="Y" g2="ugrave" k="129" />
+<hkern g1="Y" g2="uacute" k="129" />
+<hkern g1="Y" g2="ucircumflex" k="129" />
+<hkern g1="Y" g2="udieresis" k="98" />
+<hkern g1="Y" g2="yacute" k="160" />
+<hkern g1="Y" g2="ydieresis" k="97" />
+<hkern g1="Y" g2="dotlessi" k="228" />
+<hkern g1="Z" g2="C" k="193" />
+<hkern g1="Z" g2="G" k="193" />
+<hkern g1="Z" g2="O" k="163" />
+<hkern g1="Z" g2="Q" k="163" />
+<hkern g1="Z" g2="a" k="69" />
+<hkern g1="Z" g2="c" k="98" />
+<hkern g1="Z" g2="d" k="69" />
+<hkern g1="Z" g2="e" k="69" />
+<hkern g1="Z" g2="f" k="64" />
+<hkern g1="Z" g2="j" k="115" />
+<hkern g1="Z" g2="o" k="69" />
+<hkern g1="Z" g2="q" k="69" />
+<hkern g1="Z" g2="t" k="64" />
+<hkern g1="Z" g2="v" k="162" />
+<hkern g1="Z" g2="w" k="199" />
+<hkern g1="Z" g2="y" k="193" />
+<hkern g1="Z" g2="Ccedilla" k="193" />
+<hkern g1="Z" g2="Eth" k="52" />
+<hkern g1="Z" g2="Ograve" k="163" />
+<hkern g1="Z" g2="Oacute" k="163" />
+<hkern g1="Z" g2="Ocircumflex" k="163" />
+<hkern g1="Z" g2="Otilde" k="163" />
+<hkern g1="Z" g2="Odieresis" k="163" />
+<hkern g1="Z" g2="agrave" k="69" />
+<hkern g1="Z" g2="aacute" k="69" />
+<hkern g1="Z" g2="acircumflex" k="69" />
+<hkern g1="Z" g2="adieresis" k="69" />
+<hkern g1="Z" g2="aring" k="69" />
+<hkern g1="Z" g2="ae" k="81" />
+<hkern g1="Z" g2="ccedilla" k="98" />
+<hkern g1="Z" g2="egrave" k="69" />
+<hkern g1="Z" g2="eacute" k="69" />
+<hkern g1="Z" g2="ecircumflex" k="69" />
+<hkern g1="Z" g2="edieresis" k="69" />
+<hkern g1="Z" g2="eth" k="59" />
+<hkern g1="Z" g2="ograve" k="69" />
+<hkern g1="Z" g2="oacute" k="69" />
+<hkern g1="Z" g2="ocircumflex" k="69" />
+<hkern g1="Z" g2="odieresis" k="69" />
+<hkern g1="Z" g2="yacute" k="193" />
+<hkern g1="Z" g2="ydieresis" k="67" />
+<hkern g1="underscore" g2="underscore" k="39" />
+<hkern g1="a" g2="T" k="353" />
+<hkern g1="a" g2="V" k="249" />
+<hkern g1="a" g2="W" k="160" />
+<hkern g1="a" g2="Y" k="306" />
+<hkern g1="a" g2="f" k="58" />
+<hkern g1="a" g2="j" k="259" />
+<hkern g1="a" g2="t" k="90" />
+<hkern g1="a" g2="v" k="62" />
+<hkern g1="a" g2="y" k="61" />
+<hkern g1="a" g2="Yacute" k="298" />
+<hkern g1="a" g2="icircumflex" k="58" />
+<hkern g1="a" g2="idieresis" k="65" />
+<hkern g1="a" g2="yacute" k="61" />
+<hkern g1="a" g2="ydieresis" k="61" />
+<hkern g1="b" g2="A" k="60" />
+<hkern g1="b" g2="T" k="279" />
+<hkern g1="b" g2="V" k="129" />
+<hkern g1="b" g2="W" k="160" />
+<hkern g1="b" g2="X" k="122" />
+<hkern g1="b" g2="Y" k="294" />
+<hkern g1="b" g2="Z" k="123" />
+<hkern g1="b" g2="f" k="58" />
+<hkern g1="b" g2="j" k="199" />
+<hkern g1="b" g2="t" k="90" />
+<hkern g1="b" g2="v" k="62" />
+<hkern g1="b" g2="x" k="93" />
+<hkern g1="b" g2="y" k="61" />
+<hkern g1="b" g2="z" k="93" />
+<hkern g1="b" g2="Agrave" k="60" />
+<hkern g1="b" g2="Aacute" k="60" />
+<hkern g1="b" g2="Acircumflex" k="60" />
+<hkern g1="b" g2="Atilde" k="60" />
+<hkern g1="b" g2="Adieresis" k="60" />
+<hkern g1="b" g2="Aring" k="60" />
+<hkern g1="b" g2="AE" k="63" />
+<hkern g1="b" g2="Yacute" k="256" />
+<hkern g1="b" g2="icircumflex" k="58" />
+<hkern g1="b" g2="idieresis" k="65" />
+<hkern g1="b" g2="yacute" k="61" />
+<hkern g1="b" g2="ydieresis" k="61" />
+<hkern g1="c" g2="T" k="281" />
+<hkern g1="c" g2="V" k="123" />
+<hkern g1="c" g2="Y" k="148" />
+<hkern g1="c" g2="j" k="172" />
+<hkern g1="c" g2="Yacute" k="148" />
+<hkern g1="d" g2="A" k="60" />
+<hkern g1="d" g2="j" k="154" />
+<hkern g1="d" g2="Agrave" k="60" />
+<hkern g1="d" g2="Aacute" k="60" />
+<hkern g1="d" g2="Acircumflex" k="60" />
+<hkern g1="d" g2="Atilde" k="60" />
+<hkern g1="d" g2="Adieresis" k="60" />
+<hkern g1="d" g2="Aring" k="60" />
+<hkern g1="d" g2="AE" k="63" />
+<hkern g1="e" g2="A" k="92" />
+<hkern g1="e" g2="T" k="316" />
+<hkern g1="e" g2="V" k="249" />
+<hkern g1="e" g2="W" k="160" />
+<hkern g1="e" g2="X" k="122" />
+<hkern g1="e" g2="Y" k="246" />
+<hkern g1="e" g2="Z" k="123" />
+<hkern g1="e" g2="f" k="58" />
+<hkern g1="e" g2="j" k="229" />
+<hkern g1="e" g2="t" k="90" />
+<hkern g1="e" g2="v" k="62" />
+<hkern g1="e" g2="x" k="93" />
+<hkern g1="e" g2="y" k="61" />
+<hkern g1="e" g2="z" k="93" />
+<hkern g1="e" g2="Agrave" k="92" />
+<hkern g1="e" g2="Aacute" k="92" />
+<hkern g1="e" g2="Acircumflex" k="92" />
+<hkern g1="e" g2="Atilde" k="92" />
+<hkern g1="e" g2="Adieresis" k="92" />
+<hkern g1="e" g2="Aring" k="92" />
+<hkern g1="e" g2="AE" k="95" />
+<hkern g1="e" g2="Yacute" k="215" />
+<hkern g1="e" g2="icircumflex" k="58" />
+<hkern g1="e" g2="idieresis" k="65" />
+<hkern g1="e" g2="yacute" k="61" />
+<hkern g1="e" g2="ydieresis" k="61" />
+<hkern g1="f" g2="A" k="124" />
+<hkern g1="f" g2="J" k="178" />
+<hkern g1="f" g2="j" k="242" />
+<hkern g1="f" g2="Agrave" k="124" />
+<hkern g1="f" g2="Aacute" k="77" />
+<hkern g1="f" g2="Acircumflex" k="77" />
+<hkern g1="f" g2="Atilde" k="77" />
+<hkern g1="f" g2="Adieresis" k="77" />
+<hkern g1="f" g2="Aring" k="77" />
+<hkern g1="f" g2="AE" k="139" />
+<hkern g1="g" g2="T" k="285" />
+<hkern g1="g" g2="V" k="249" />
+<hkern g1="g" g2="W" k="160" />
+<hkern g1="g" g2="Y" k="254" />
+<hkern g1="g" g2="f" k="58" />
+<hkern g1="g" g2="t" k="90" />
+<hkern g1="g" g2="v" k="62" />
+<hkern g1="g" g2="y" k="61" />
+<hkern g1="g" g2="Yacute" k="254" />
+<hkern g1="g" g2="icircumflex" k="58" />
+<hkern g1="g" g2="idieresis" k="65" />
+<hkern g1="g" g2="yacute" k="61" />
+<hkern g1="g" g2="ydieresis" k="61" />
+<hkern g1="h" g2="T" k="308" />
+<hkern g1="h" g2="V" k="233" />
+<hkern g1="h" g2="W" k="144" />
+<hkern g1="h" g2="Y" k="261" />
+<hkern g1="h" g2="f" k="42" />
+<hkern g1="h" g2="j" k="198" />
+<hkern g1="h" g2="t" k="74" />
+<hkern g1="h" g2="v" k="46" />
+<hkern g1="h" g2="y" k="45" />
+<hkern g1="h" g2="Yacute" k="261" />
+<hkern g1="h" g2="icircumflex" k="42" />
+<hkern g1="h" g2="idieresis" k="49" />
+<hkern g1="h" g2="yacute" k="45" />
+<hkern g1="h" g2="ydieresis" k="45" />
+<hkern g1="i" g2="j" k="171" />
+<hkern g1="k" g2="T" k="251" />
+<hkern g1="k" g2="V" k="91" />
+<hkern g1="k" g2="Y" k="185" />
+<hkern g1="k" g2="a" k="63" />
+<hkern g1="k" g2="c" k="92" />
+<hkern g1="k" g2="d" k="63" />
+<hkern g1="k" g2="e" k="63" />
+<hkern g1="k" g2="j" k="156" />
+<hkern g1="k" g2="o" k="63" />
+<hkern g1="k" g2="q" k="63" />
+<hkern g1="k" g2="Yacute" k="185" />
+<hkern g1="k" g2="agrave" k="63" />
+<hkern g1="k" g2="aacute" k="63" />
+<hkern g1="k" g2="acircumflex" k="63" />
+<hkern g1="k" g2="atilde" k="63" />
+<hkern g1="k" g2="adieresis" k="63" />
+<hkern g1="k" g2="aring" k="63" />
+<hkern g1="k" g2="ae" k="75" />
+<hkern g1="k" g2="ccedilla" k="92" />
+<hkern g1="k" g2="egrave" k="63" />
+<hkern g1="k" g2="eacute" k="63" />
+<hkern g1="k" g2="ecircumflex" k="63" />
+<hkern g1="k" g2="edieresis" k="63" />
+<hkern g1="k" g2="eth" k="53" />
+<hkern g1="k" g2="ograve" k="63" />
+<hkern g1="k" g2="oacute" k="63" />
+<hkern g1="k" g2="ocircumflex" k="63" />
+<hkern g1="k" g2="otilde" k="63" />
+<hkern g1="k" g2="odieresis" k="63" />
+<hkern g1="l" g2="j" k="153" />
+<hkern g1="l" g2="ae" k="41" />
+<hkern g1="m" g2="T" k="260" />
+<hkern g1="m" g2="V" k="219" />
+<hkern g1="m" g2="W" k="130" />
+<hkern g1="m" g2="Y" k="221" />
+<hkern g1="m" g2="j" k="166" />
+<hkern g1="m" g2="t" k="60" />
+<hkern g1="m" g2="y" k="63" />
+<hkern g1="m" g2="Yacute" k="229" />
+<hkern g1="m" g2="icircumflex" k="60" />
+<hkern g1="m" g2="idieresis" k="67" />
+<hkern g1="m" g2="yacute" k="63" />
+<hkern g1="m" g2="ydieresis" k="63" />
+<hkern g1="n" g2="T" k="221" />
+<hkern g1="n" g2="V" k="233" />
+<hkern g1="n" g2="W" k="144" />
+<hkern g1="n" g2="Y" k="190" />
+<hkern g1="n" g2="f" k="42" />
+<hkern g1="n" g2="j" k="126" />
+<hkern g1="n" g2="t" k="74" />
+<hkern g1="n" g2="v" k="46" />
+<hkern g1="n" g2="y" k="45" />
+<hkern g1="n" g2="Yacute" k="221" />
+<hkern g1="n" g2="icircumflex" k="42" />
+<hkern g1="n" g2="idieresis" k="49" />
+<hkern g1="n" g2="yacute" k="45" />
+<hkern g1="n" g2="ydieresis" k="45" />
+<hkern g1="o" g2="A" k="60" />
+<hkern g1="o" g2="T" k="256" />
+<hkern g1="o" g2="V" k="249" />
+<hkern g1="o" g2="W" k="160" />
+<hkern g1="o" g2="X" k="122" />
+<hkern g1="o" g2="Y" k="225" />
+<hkern g1="o" g2="Z" k="123" />
+<hkern g1="o" g2="f" k="58" />
+<hkern g1="o" g2="j" k="201" />
+<hkern g1="o" g2="t" k="90" />
+<hkern g1="o" g2="v" k="62" />
+<hkern g1="o" g2="x" k="93" />
+<hkern g1="o" g2="y" k="61" />
+<hkern g1="o" g2="z" k="93" />
+<hkern g1="o" g2="Agrave" k="60" />
+<hkern g1="o" g2="Aacute" k="60" />
+<hkern g1="o" g2="Acircumflex" k="60" />
+<hkern g1="o" g2="Atilde" k="60" />
+<hkern g1="o" g2="Adieresis" k="60" />
+<hkern g1="o" g2="Aring" k="60" />
+<hkern g1="o" g2="AE" k="63" />
+<hkern g1="o" g2="Yacute" k="225" />
+<hkern g1="o" g2="icircumflex" k="58" />
+<hkern g1="o" g2="idieresis" k="65" />
+<hkern g1="o" g2="yacute" k="61" />
+<hkern g1="o" g2="ydieresis" k="61" />
+<hkern g1="p" g2="A" k="60" />
+<hkern g1="p" g2="T" k="297" />
+<hkern g1="p" g2="V" k="249" />
+<hkern g1="p" g2="W" k="160" />
+<hkern g1="p" g2="X" k="122" />
+<hkern g1="p" g2="Y" k="227" />
+<hkern g1="p" g2="Z" k="123" />
+<hkern g1="p" g2="f" k="58" />
+<hkern g1="p" g2="j" k="180" />
+<hkern g1="p" g2="t" k="90" />
+<hkern g1="p" g2="v" k="62" />
+<hkern g1="p" g2="x" k="93" />
+<hkern g1="p" g2="y" k="61" />
+<hkern g1="p" g2="z" k="93" />
+<hkern g1="p" g2="Agrave" k="60" />
+<hkern g1="p" g2="Aacute" k="60" />
+<hkern g1="p" g2="Acircumflex" k="60" />
+<hkern g1="p" g2="Atilde" k="60" />
+<hkern g1="p" g2="Adieresis" k="60" />
+<hkern g1="p" g2="Aring" k="60" />
+<hkern g1="p" g2="AE" k="63" />
+<hkern g1="p" g2="Yacute" k="227" />
+<hkern g1="p" g2="icircumflex" k="58" />
+<hkern g1="p" g2="idieresis" k="65" />
+<hkern g1="p" g2="yacute" k="61" />
+<hkern g1="p" g2="ydieresis" k="61" />
+<hkern g1="q" g2="T" k="263" />
+<hkern g1="q" g2="V" k="120" />
+<hkern g1="q" g2="W" k="160" />
+<hkern g1="q" g2="Y" k="247" />
+<hkern g1="q" g2="f" k="58" />
+<hkern g1="q" g2="t" k="90" />
+<hkern g1="q" g2="v" k="62" />
+<hkern g1="q" g2="y" k="61" />
+<hkern g1="q" g2="Yacute" k="247" />
+<hkern g1="q" g2="icircumflex" k="58" />
+<hkern g1="q" g2="idieresis" k="65" />
+<hkern g1="q" g2="yacute" k="61" />
+<hkern g1="q" g2="ydieresis" k="61" />
+<hkern g1="r" g2="A" k="185" />
+<hkern g1="r" g2="J" k="233" />
+<hkern g1="r" g2="T" k="224" />
+<hkern g1="r" g2="V" k="59" />
+<hkern g1="r" g2="X" k="216" />
+<hkern g1="r" g2="Y" k="153" />
+<hkern g1="r" g2="Z" k="201" />
+<hkern g1="r" g2="j" k="168" />
+<hkern g1="r" g2="Agrave" k="185" />
+<hkern g1="r" g2="Aacute" k="185" />
+<hkern g1="r" g2="Acircumflex" k="185" />
+<hkern g1="r" g2="Atilde" k="185" />
+<hkern g1="r" g2="Adieresis" k="185" />
+<hkern g1="r" g2="Aring" k="185" />
+<hkern g1="r" g2="AE" k="239" />
+<hkern g1="r" g2="Yacute" k="153" />
+<hkern g1="s" g2="T" k="233" />
+<hkern g1="s" g2="V" k="158" />
+<hkern g1="s" g2="W" k="69" />
+<hkern g1="s" g2="Y" k="256" />
+<hkern g1="s" g2="j" k="186" />
+<hkern g1="s" g2="Yacute" k="202" />
+<hkern g1="t" g2="T" k="184" />
+<hkern g1="t" g2="V" k="152" />
+<hkern g1="t" g2="W" k="63" />
+<hkern g1="t" g2="Y" k="183" />
+<hkern g1="t" g2="a" k="61" />
+<hkern g1="t" g2="c" k="90" />
+<hkern g1="t" g2="d" k="61" />
+<hkern g1="t" g2="e" k="61" />
+<hkern g1="t" g2="j" k="143" />
+<hkern g1="t" g2="o" k="61" />
+<hkern g1="t" g2="q" k="61" />
+<hkern g1="t" g2="Yacute" k="183" />
+<hkern g1="t" g2="agrave" k="61" />
+<hkern g1="t" g2="aacute" k="61" />
+<hkern g1="t" g2="acircumflex" k="61" />
+<hkern g1="t" g2="atilde" k="61" />
+<hkern g1="t" g2="adieresis" k="61" />
+<hkern g1="t" g2="aring" k="61" />
+<hkern g1="t" g2="ae" k="73" />
+<hkern g1="t" g2="ccedilla" k="90" />
+<hkern g1="t" g2="egrave" k="61" />
+<hkern g1="t" g2="eacute" k="61" />
+<hkern g1="t" g2="ecircumflex" k="61" />
+<hkern g1="t" g2="edieresis" k="61" />
+<hkern g1="t" g2="eth" k="51" />
+<hkern g1="t" g2="ograve" k="61" />
+<hkern g1="t" g2="oacute" k="61" />
+<hkern g1="t" g2="ocircumflex" k="61" />
+<hkern g1="t" g2="otilde" k="61" />
+<hkern g1="t" g2="odieresis" k="61" />
+<hkern g1="u" g2="T" k="248" />
+<hkern g1="u" g2="V" k="107" />
+<hkern g1="u" g2="W" k="49" />
+<hkern g1="u" g2="Y" k="201" />
+<hkern g1="u" g2="j" k="154" />
+<hkern g1="u" g2="Yacute" k="201" />
+<hkern g1="u" g2="icircumflex" k="42" />
+<hkern g1="u" g2="idieresis" k="49" />
+<hkern g1="v" g2="A" k="161" />
+<hkern g1="v" g2="J" k="167" />
+<hkern g1="v" g2="T" k="248" />
+<hkern g1="v" g2="V" k="107" />
+<hkern g1="v" g2="W" k="49" />
+<hkern g1="v" g2="X" k="232" />
+<hkern g1="v" g2="Y" k="201" />
+<hkern g1="v" g2="Z" k="240" />
+<hkern g1="v" g2="a" k="47" />
+<hkern g1="v" g2="c" k="77" />
+<hkern g1="v" g2="d" k="47" />
+<hkern g1="v" g2="e" k="47" />
+<hkern g1="v" g2="g" k="47" />
+<hkern g1="v" g2="j" k="216" />
+<hkern g1="v" g2="o" k="47" />
+<hkern g1="v" g2="p" k="47" />
+<hkern g1="v" g2="q" k="47" />
+<hkern g1="v" g2="Agrave" k="153" />
+<hkern g1="v" g2="Aacute" k="146" />
+<hkern g1="v" g2="Acircumflex" k="153" />
+<hkern g1="v" g2="Atilde" k="146" />
+<hkern g1="v" g2="Adieresis" k="161" />
+<hkern g1="v" g2="Aring" k="177" />
+<hkern g1="v" g2="AE" k="201" />
+<hkern g1="v" g2="Yacute" k="201" />
+<hkern g1="v" g2="agrave" k="47" />
+<hkern g1="v" g2="aacute" k="47" />
+<hkern g1="v" g2="acircumflex" k="47" />
+<hkern g1="v" g2="atilde" k="47" />
+<hkern g1="v" g2="adieresis" k="47" />
+<hkern g1="v" g2="aring" k="47" />
+<hkern g1="v" g2="ae" k="91" />
+<hkern g1="v" g2="ccedilla" k="77" />
+<hkern g1="v" g2="egrave" k="47" />
+<hkern g1="v" g2="eacute" k="47" />
+<hkern g1="v" g2="ecircumflex" k="47" />
+<hkern g1="v" g2="edieresis" k="47" />
+<hkern g1="v" g2="icircumflex" k="42" />
+<hkern g1="v" g2="idieresis" k="49" />
+<hkern g1="v" g2="eth" k="69" />
+<hkern g1="v" g2="ograve" k="47" />
+<hkern g1="v" g2="oacute" k="47" />
+<hkern g1="v" g2="ocircumflex" k="47" />
+<hkern g1="v" g2="otilde" k="47" />
+<hkern g1="v" g2="odieresis" k="47" />
+<hkern g1="v" g2="oslash" k="47" />
+<hkern g1="w" g2="A" k="250" />
+<hkern g1="w" g2="J" k="90" />
+<hkern g1="w" g2="T" k="330" />
+<hkern g1="w" g2="V" k="124" />
+<hkern g1="w" g2="X" k="218" />
+<hkern g1="w" g2="Y" k="133" />
+<hkern g1="w" g2="Z" k="219" />
+<hkern g1="w" g2="j" k="220" />
+<hkern g1="w" g2="Agrave" k="250" />
+<hkern g1="w" g2="Aacute" k="250" />
+<hkern g1="w" g2="Acircumflex" k="250" />
+<hkern g1="w" g2="Atilde" k="250" />
+<hkern g1="w" g2="Adieresis" k="250" />
+<hkern g1="w" g2="Aring" k="250" />
+<hkern g1="w" g2="AE" k="222" />
+<hkern g1="w" g2="Yacute" k="148" />
+<hkern g1="w" g2="ae" k="45" />
+<hkern g1="w" g2="icircumflex" k="59" />
+<hkern g1="w" g2="idieresis" k="66" />
+<hkern g1="x" g2="T" k="210" />
+<hkern g1="x" g2="V" k="91" />
+<hkern g1="x" g2="Y" k="185" />
+<hkern g1="x" g2="a" k="63" />
+<hkern g1="x" g2="c" k="92" />
+<hkern g1="x" g2="d" k="63" />
+<hkern g1="x" g2="e" k="63" />
+<hkern g1="x" g2="j" k="154" />
+<hkern g1="x" g2="o" k="63" />
+<hkern g1="x" g2="q" k="63" />
+<hkern g1="x" g2="Yacute" k="185" />
+<hkern g1="x" g2="agrave" k="63" />
+<hkern g1="x" g2="aacute" k="63" />
+<hkern g1="x" g2="acircumflex" k="63" />
+<hkern g1="x" g2="atilde" k="63" />
+<hkern g1="x" g2="adieresis" k="63" />
+<hkern g1="x" g2="aring" k="63" />
+<hkern g1="x" g2="ae" k="75" />
+<hkern g1="x" g2="ccedilla" k="92" />
+<hkern g1="x" g2="egrave" k="63" />
+<hkern g1="x" g2="eacute" k="63" />
+<hkern g1="x" g2="ecircumflex" k="63" />
+<hkern g1="x" g2="edieresis" k="63" />
+<hkern g1="x" g2="eth" k="53" />
+<hkern g1="x" g2="ograve" k="63" />
+<hkern g1="x" g2="oacute" k="63" />
+<hkern g1="x" g2="ocircumflex" k="63" />
+<hkern g1="x" g2="otilde" k="63" />
+<hkern g1="x" g2="odieresis" k="63" />
+<hkern g1="y" g2="A" k="125" />
+<hkern g1="y" g2="J" k="88" />
+<hkern g1="y" g2="T" k="306" />
+<hkern g1="y" g2="V" k="91" />
+<hkern g1="y" g2="X" k="78" />
+<hkern g1="y" g2="Y" k="94" />
+<hkern g1="y" g2="Z" k="118" />
+<hkern g1="y" g2="j" k="180" />
+<hkern g1="y" g2="Agrave" k="86" />
+<hkern g1="y" g2="Aacute" k="86" />
+<hkern g1="y" g2="Acircumflex" k="86" />
+<hkern g1="y" g2="Atilde" k="86" />
+<hkern g1="y" g2="Adieresis" k="86" />
+<hkern g1="y" g2="Aring" k="86" />
+<hkern g1="y" g2="AE" k="118" />
+<hkern g1="y" g2="Yacute" k="55" />
+<hkern g1="z" g2="T" k="299" />
+<hkern g1="z" g2="V" k="91" />
+<hkern g1="z" g2="Y" k="63" />
+<hkern g1="z" g2="a" k="63" />
+<hkern g1="z" g2="c" k="92" />
+<hkern g1="z" g2="d" k="63" />
+<hkern g1="z" g2="e" k="63" />
+<hkern g1="z" g2="j" k="180" />
+<hkern g1="z" g2="o" k="63" />
+<hkern g1="z" g2="q" k="63" />
+<hkern g1="z" g2="Yacute" k="149" />
+<hkern g1="z" g2="agrave" k="63" />
+<hkern g1="z" g2="aacute" k="63" />
+<hkern g1="z" g2="acircumflex" k="63" />
+<hkern g1="z" g2="atilde" k="63" />
+<hkern g1="z" g2="adieresis" k="63" />
+<hkern g1="z" g2="aring" k="63" />
+<hkern g1="z" g2="ae" k="75" />
+<hkern g1="z" g2="ccedilla" k="92" />
+<hkern g1="z" g2="egrave" k="63" />
+<hkern g1="z" g2="eacute" k="63" />
+<hkern g1="z" g2="ecircumflex" k="63" />
+<hkern g1="z" g2="edieresis" k="63" />
+<hkern g1="z" g2="eth" k="53" />
+<hkern g1="z" g2="ograve" k="63" />
+<hkern g1="z" g2="oacute" k="63" />
+<hkern g1="z" g2="ocircumflex" k="63" />
+<hkern g1="z" g2="otilde" k="63" />
+<hkern g1="z" g2="odieresis" k="63" />
+<hkern g1="Agrave" g2="C" k="98" />
+<hkern g1="Agrave" g2="G" k="98" />
+<hkern g1="Agrave" g2="O" k="69" />
+<hkern g1="Agrave" g2="Q" k="69" />
+<hkern g1="Agrave" g2="T" k="208" />
+<hkern g1="Agrave" g2="V" k="247" />
+<hkern g1="Agrave" g2="W" k="121" />
+<hkern g1="Agrave" g2="Y" k="247" />
+<hkern g1="Agrave" g2="f" k="64" />
+<hkern g1="Agrave" g2="j" k="200" />
+<hkern g1="Agrave" g2="t" k="95" />
+<hkern g1="Agrave" g2="v" k="137" />
+<hkern g1="Agrave" g2="w" k="199" />
+<hkern g1="Agrave" g2="y" k="256" />
+<hkern g1="Agrave" g2="Ccedilla" k="98" />
+<hkern g1="Agrave" g2="Eth" k="52" />
+<hkern g1="Agrave" g2="Ograve" k="69" />
+<hkern g1="Agrave" g2="Oacute" k="69" />
+<hkern g1="Agrave" g2="Ocircumflex" k="69" />
+<hkern g1="Agrave" g2="Otilde" k="69" />
+<hkern g1="Agrave" g2="Odieresis" k="69" />
+<hkern g1="Agrave" g2="Yacute" k="224" />
+<hkern g1="Agrave" g2="yacute" k="124" />
+<hkern g1="Agrave" g2="ydieresis" k="61" />
+<hkern g1="Aacute" g2="C" k="98" />
+<hkern g1="Aacute" g2="G" k="98" />
+<hkern g1="Aacute" g2="O" k="69" />
+<hkern g1="Aacute" g2="Q" k="69" />
+<hkern g1="Aacute" g2="T" k="247" />
+<hkern g1="Aacute" g2="V" k="200" />
+<hkern g1="Aacute" g2="W" k="159" />
+<hkern g1="Aacute" g2="Y" k="239" />
+<hkern g1="Aacute" g2="f" k="64" />
+<hkern g1="Aacute" g2="j" k="207" />
+<hkern g1="Aacute" g2="t" k="95" />
+<hkern g1="Aacute" g2="v" k="225" />
+<hkern g1="Aacute" g2="w" k="199" />
+<hkern g1="Aacute" g2="y" k="256" />
+<hkern g1="Aacute" g2="Ccedilla" k="98" />
+<hkern g1="Aacute" g2="Eth" k="52" />
+<hkern g1="Aacute" g2="Ograve" k="69" />
+<hkern g1="Aacute" g2="Oacute" k="69" />
+<hkern g1="Aacute" g2="Ocircumflex" k="69" />
+<hkern g1="Aacute" g2="Otilde" k="69" />
+<hkern g1="Aacute" g2="Odieresis" k="69" />
+<hkern g1="Aacute" g2="Yacute" k="200" />
+<hkern g1="Aacute" g2="yacute" k="62" />
+<hkern g1="Aacute" g2="ydieresis" k="53" />
+<hkern g1="Acircumflex" g2="C" k="98" />
+<hkern g1="Acircumflex" g2="G" k="98" />
+<hkern g1="Acircumflex" g2="O" k="69" />
+<hkern g1="Acircumflex" g2="Q" k="69" />
+<hkern g1="Acircumflex" g2="T" k="216" />
+<hkern g1="Acircumflex" g2="V" k="200" />
+<hkern g1="Acircumflex" g2="W" k="121" />
+<hkern g1="Acircumflex" g2="Y" k="200" />
+<hkern g1="Acircumflex" g2="f" k="64" />
+<hkern g1="Acircumflex" g2="j" k="106" />
+<hkern g1="Acircumflex" g2="t" k="95" />
+<hkern g1="Acircumflex" g2="v" k="225" />
+<hkern g1="Acircumflex" g2="w" k="199" />
+<hkern g1="Acircumflex" g2="y" k="256" />
+<hkern g1="Acircumflex" g2="Ccedilla" k="98" />
+<hkern g1="Acircumflex" g2="Eth" k="52" />
+<hkern g1="Acircumflex" g2="Ograve" k="69" />
+<hkern g1="Acircumflex" g2="Oacute" k="69" />
+<hkern g1="Acircumflex" g2="Ocircumflex" k="69" />
+<hkern g1="Acircumflex" g2="Otilde" k="69" />
+<hkern g1="Acircumflex" g2="Odieresis" k="69" />
+<hkern g1="Acircumflex" g2="Yacute" k="200" />
+<hkern g1="Acircumflex" g2="yacute" k="62" />
+<hkern g1="Acircumflex" g2="ydieresis" k="53" />
+<hkern g1="Atilde" g2="C" k="98" />
+<hkern g1="Atilde" g2="G" k="98" />
+<hkern g1="Atilde" g2="O" k="69" />
+<hkern g1="Atilde" g2="Q" k="69" />
+<hkern g1="Atilde" g2="T" k="204" />
+<hkern g1="Atilde" g2="V" k="204" />
+<hkern g1="Atilde" g2="W" k="78" />
+<hkern g1="Atilde" g2="Y" k="204" />
+<hkern g1="Atilde" g2="f" k="64" />
+<hkern g1="Atilde" g2="j" k="110" />
+<hkern g1="Atilde" g2="t" k="95" />
+<hkern g1="Atilde" g2="v" k="225" />
+<hkern g1="Atilde" g2="w" k="199" />
+<hkern g1="Atilde" g2="y" k="256" />
+<hkern g1="Atilde" g2="Ccedilla" k="98" />
+<hkern g1="Atilde" g2="Eth" k="52" />
+<hkern g1="Atilde" g2="Ograve" k="69" />
+<hkern g1="Atilde" g2="Oacute" k="69" />
+<hkern g1="Atilde" g2="Ocircumflex" k="69" />
+<hkern g1="Atilde" g2="Otilde" k="69" />
+<hkern g1="Atilde" g2="Odieresis" k="69" />
+<hkern g1="Atilde" g2="Yacute" k="204" />
+<hkern g1="Atilde" g2="yacute" k="66" />
+<hkern g1="Atilde" g2="ydieresis" k="57" />
+<hkern g1="Adieresis" g2="C" k="98" />
+<hkern g1="Adieresis" g2="G" k="98" />
+<hkern g1="Adieresis" g2="O" k="69" />
+<hkern g1="Adieresis" g2="Q" k="69" />
+<hkern g1="Adieresis" g2="T" k="236" />
+<hkern g1="Adieresis" g2="V" k="213" />
+<hkern g1="Adieresis" g2="W" k="188" />
+<hkern g1="Adieresis" g2="Y" k="213" />
+<hkern g1="Adieresis" g2="f" k="64" />
+<hkern g1="Adieresis" g2="j" k="158" />
+<hkern g1="Adieresis" g2="t" k="95" />
+<hkern g1="Adieresis" g2="v" k="157" />
+<hkern g1="Adieresis" g2="w" k="199" />
+<hkern g1="Adieresis" g2="y" k="256" />
+<hkern g1="Adieresis" g2="Ccedilla" k="98" />
+<hkern g1="Adieresis" g2="Eth" k="52" />
+<hkern g1="Adieresis" g2="Ograve" k="69" />
+<hkern g1="Adieresis" g2="Oacute" k="69" />
+<hkern g1="Adieresis" g2="Ocircumflex" k="69" />
+<hkern g1="Adieresis" g2="Otilde" k="69" />
+<hkern g1="Adieresis" g2="Odieresis" k="69" />
+<hkern g1="Adieresis" g2="Yacute" k="213" />
+<hkern g1="Adieresis" g2="yacute" k="75" />
+<hkern g1="Adieresis" g2="ydieresis" k="66" />
+<hkern g1="Aring" g2="C" k="98" />
+<hkern g1="Aring" g2="G" k="98" />
+<hkern g1="Aring" g2="O" k="69" />
+<hkern g1="Aring" g2="Q" k="69" />
+<hkern g1="Aring" g2="T" k="223" />
+<hkern g1="Aring" g2="V" k="230" />
+<hkern g1="Aring" g2="W" k="182" />
+<hkern g1="Aring" g2="Y" k="246" />
+<hkern g1="Aring" g2="f" k="64" />
+<hkern g1="Aring" g2="j" k="191" />
+<hkern g1="Aring" g2="t" k="95" />
+<hkern g1="Aring" g2="v" k="167" />
+<hkern g1="Aring" g2="w" k="199" />
+<hkern g1="Aring" g2="y" k="256" />
+<hkern g1="Aring" g2="Ccedilla" k="98" />
+<hkern g1="Aring" g2="Eth" k="52" />
+<hkern g1="Aring" g2="Ograve" k="69" />
+<hkern g1="Aring" g2="Oacute" k="69" />
+<hkern g1="Aring" g2="Ocircumflex" k="69" />
+<hkern g1="Aring" g2="Otilde" k="69" />
+<hkern g1="Aring" g2="Odieresis" k="69" />
+<hkern g1="Aring" g2="Yacute" k="207" />
+<hkern g1="Aring" g2="yacute" k="92" />
+<hkern g1="Aring" g2="ydieresis" k="83" />
+<hkern g1="AE" g2="C" k="100" />
+<hkern g1="AE" g2="G" k="100" />
+<hkern g1="AE" g2="J" k="65" />
+<hkern g1="AE" g2="O" k="102" />
+<hkern g1="AE" g2="Q" k="102" />
+<hkern g1="AE" g2="a" k="102" />
+<hkern g1="AE" g2="c" k="132" />
+<hkern g1="AE" g2="d" k="102" />
+<hkern g1="AE" g2="e" k="102" />
+<hkern g1="AE" g2="f" k="97" />
+<hkern g1="AE" g2="g" k="71" />
+<hkern g1="AE" g2="j" k="206" />
+<hkern g1="AE" g2="o" k="102" />
+<hkern g1="AE" g2="q" k="102" />
+<hkern g1="AE" g2="t" k="97" />
+<hkern g1="AE" g2="u" k="70" />
+<hkern g1="AE" g2="v" k="196" />
+<hkern g1="AE" g2="w" k="169" />
+<hkern g1="AE" g2="y" k="195" />
+<hkern g1="AE" g2="Ccedilla" k="100" />
+<hkern g1="AE" g2="Ograve" k="102" />
+<hkern g1="AE" g2="Oacute" k="102" />
+<hkern g1="AE" g2="Ocircumflex" k="102" />
+<hkern g1="AE" g2="Otilde" k="102" />
+<hkern g1="AE" g2="Odieresis" k="102" />
+<hkern g1="AE" g2="agrave" k="102" />
+<hkern g1="AE" g2="aacute" k="102" />
+<hkern g1="AE" g2="acircumflex" k="102" />
+<hkern g1="AE" g2="atilde" k="102" />
+<hkern g1="AE" g2="adieresis" k="102" />
+<hkern g1="AE" g2="aring" k="102" />
+<hkern g1="AE" g2="ae" k="114" />
+<hkern g1="AE" g2="ccedilla" k="132" />
+<hkern g1="AE" g2="egrave" k="102" />
+<hkern g1="AE" g2="eacute" k="102" />
+<hkern g1="AE" g2="ecircumflex" k="102" />
+<hkern g1="AE" g2="edieresis" k="102" />
+<hkern g1="AE" g2="eth" k="92" />
+<hkern g1="AE" g2="ograve" k="102" />
+<hkern g1="AE" g2="oacute" k="102" />
+<hkern g1="AE" g2="ocircumflex" k="102" />
+<hkern g1="AE" g2="otilde" k="102" />
+<hkern g1="AE" g2="odieresis" k="102" />
+<hkern g1="AE" g2="ugrave" k="70" />
+<hkern g1="AE" g2="uacute" k="70" />
+<hkern g1="AE" g2="ucircumflex" k="70" />
+<hkern g1="AE" g2="udieresis" k="70" />
+<hkern g1="AE" g2="yacute" k="195" />
+<hkern g1="AE" g2="ydieresis" k="132" />
+<hkern g1="Ccedilla" g2="C" k="91" />
+<hkern g1="Ccedilla" g2="G" k="138" />
+<hkern g1="Ccedilla" g2="O" k="91" />
+<hkern g1="Ccedilla" g2="Q" k="91" />
+<hkern g1="Ccedilla" g2="f" k="154" />
+<hkern g1="Ccedilla" g2="j" k="208" />
+<hkern g1="Ccedilla" g2="t" k="130" />
+<hkern g1="Ccedilla" g2="v" k="248" />
+<hkern g1="Ccedilla" g2="w" k="122" />
+<hkern g1="Ccedilla" g2="y" k="202" />
+<hkern g1="Ccedilla" g2="Ccedilla" k="104" />
+<hkern g1="Ccedilla" g2="Igrave" k="75" />
+<hkern g1="Ccedilla" g2="Iacute" k="105" />
+<hkern g1="Ccedilla" g2="Icircumflex" k="96" />
+<hkern g1="Ccedilla" g2="Idieresis" k="76" />
+<hkern g1="Ccedilla" g2="Eth" k="59" />
+<hkern g1="Ccedilla" g2="Ograve" k="91" />
+<hkern g1="Ccedilla" g2="Oacute" k="137" />
+<hkern g1="Ccedilla" g2="Ocircumflex" k="91" />
+<hkern g1="Ccedilla" g2="Otilde" k="91" />
+<hkern g1="Ccedilla" g2="Odieresis" k="91" />
+<hkern g1="Ccedilla" g2="iacute" k="53" />
+<hkern g1="Ccedilla" g2="yacute" k="204" />
+<hkern g1="Ccedilla" g2="ydieresis" k="164" />
+<hkern g1="Egrave" g2="C" k="127" />
+<hkern g1="Egrave" g2="G" k="127" />
+<hkern g1="Egrave" g2="O" k="129" />
+<hkern g1="Egrave" g2="Q" k="129" />
+<hkern g1="Egrave" g2="c" k="64" />
+<hkern g1="Egrave" g2="j" k="184" />
+<hkern g1="Egrave" g2="v" k="59" />
+<hkern g1="Egrave" g2="w" k="165" />
+<hkern g1="Egrave" g2="y" k="76" />
+<hkern g1="Egrave" g2="Ccedilla" k="127" />
+<hkern g1="Egrave" g2="Ograve" k="129" />
+<hkern g1="Egrave" g2="Oacute" k="129" />
+<hkern g1="Egrave" g2="Ocircumflex" k="129" />
+<hkern g1="Egrave" g2="Otilde" k="129" />
+<hkern g1="Egrave" g2="Odieresis" k="129" />
+<hkern g1="Egrave" g2="ae" k="47" />
+<hkern g1="Egrave" g2="ccedilla" k="64" />
+<hkern g1="Egrave" g2="eth" k="56" />
+<hkern g1="Egrave" g2="yacute" k="78" />
+<hkern g1="Egrave" g2="ydieresis" k="64" />
+<hkern g1="Eacute" g2="C" k="127" />
+<hkern g1="Eacute" g2="G" k="127" />
+<hkern g1="Eacute" g2="O" k="129" />
+<hkern g1="Eacute" g2="Q" k="129" />
+<hkern g1="Eacute" g2="c" k="64" />
+<hkern g1="Eacute" g2="j" k="182" />
+<hkern g1="Eacute" g2="v" k="191" />
+<hkern g1="Eacute" g2="w" k="165" />
+<hkern g1="Eacute" g2="y" k="51" />
+<hkern g1="Eacute" g2="Ccedilla" k="127" />
+<hkern g1="Eacute" g2="Ograve" k="129" />
+<hkern g1="Eacute" g2="Oacute" k="129" />
+<hkern g1="Eacute" g2="Ocircumflex" k="129" />
+<hkern g1="Eacute" g2="Otilde" k="129" />
+<hkern g1="Eacute" g2="Odieresis" k="129" />
+<hkern g1="Eacute" g2="ae" k="47" />
+<hkern g1="Eacute" g2="ccedilla" k="64" />
+<hkern g1="Eacute" g2="eth" k="56" />
+<hkern g1="Eacute" g2="yacute" k="53" />
+<hkern g1="Eacute" g2="ydieresis" k="64" />
+<hkern g1="Ecircumflex" g2="C" k="127" />
+<hkern g1="Ecircumflex" g2="G" k="127" />
+<hkern g1="Ecircumflex" g2="O" k="129" />
+<hkern g1="Ecircumflex" g2="Q" k="129" />
+<hkern g1="Ecircumflex" g2="c" k="64" />
+<hkern g1="Ecircumflex" g2="j" k="175" />
+<hkern g1="Ecircumflex" g2="v" k="191" />
+<hkern g1="Ecircumflex" g2="w" k="165" />
+<hkern g1="Ecircumflex" g2="y" k="51" />
+<hkern g1="Ecircumflex" g2="Ccedilla" k="127" />
+<hkern g1="Ecircumflex" g2="Ograve" k="129" />
+<hkern g1="Ecircumflex" g2="Oacute" k="129" />
+<hkern g1="Ecircumflex" g2="Ocircumflex" k="129" />
+<hkern g1="Ecircumflex" g2="Otilde" k="129" />
+<hkern g1="Ecircumflex" g2="Odieresis" k="129" />
+<hkern g1="Ecircumflex" g2="ae" k="47" />
+<hkern g1="Ecircumflex" g2="ccedilla" k="64" />
+<hkern g1="Ecircumflex" g2="eth" k="56" />
+<hkern g1="Ecircumflex" g2="yacute" k="53" />
+<hkern g1="Ecircumflex" g2="ydieresis" k="64" />
+<hkern g1="Edieresis" g2="C" k="127" />
+<hkern g1="Edieresis" g2="G" k="127" />
+<hkern g1="Edieresis" g2="O" k="129" />
+<hkern g1="Edieresis" g2="Q" k="129" />
+<hkern g1="Edieresis" g2="c" k="64" />
+<hkern g1="Edieresis" g2="j" k="180" />
+<hkern g1="Edieresis" g2="v" k="191" />
+<hkern g1="Edieresis" g2="w" k="165" />
+<hkern g1="Edieresis" g2="y" k="87" />
+<hkern g1="Edieresis" g2="Ccedilla" k="127" />
+<hkern g1="Edieresis" g2="Ograve" k="129" />
+<hkern g1="Edieresis" g2="Oacute" k="129" />
+<hkern g1="Edieresis" g2="Ocircumflex" k="129" />
+<hkern g1="Edieresis" g2="Otilde" k="129" />
+<hkern g1="Edieresis" g2="Odieresis" k="129" />
+<hkern g1="Edieresis" g2="ae" k="47" />
+<hkern g1="Edieresis" g2="ccedilla" k="64" />
+<hkern g1="Edieresis" g2="eth" k="56" />
+<hkern g1="Edieresis" g2="yacute" k="66" />
+<hkern g1="Edieresis" g2="ydieresis" k="64" />
+<hkern g1="Igrave" g2="I" k="42" />
+<hkern g1="Igrave" g2="j" k="283" />
+<hkern g1="Igrave" g2="dotlessi" k="42" />
+<hkern g1="Iacute" g2="j" k="199" />
+<hkern g1="Icircumflex" g2="j" k="207" />
+<hkern g1="Idieresis" g2="I" k="50" />
+<hkern g1="Idieresis" g2="j" k="227" />
+<hkern g1="Idieresis" g2="dotlessi" k="50" />
+<hkern g1="Eth" g2="A" k="128" />
+<hkern g1="Eth" g2="T" k="223" />
+<hkern g1="Eth" g2="V" k="128" />
+<hkern g1="Eth" g2="X" k="190" />
+<hkern g1="Eth" g2="Y" k="190" />
+<hkern g1="Eth" g2="Z" k="223" />
+<hkern g1="Eth" g2="j" k="176" />
+<hkern g1="Eth" g2="Agrave" k="128" />
+<hkern g1="Eth" g2="Aacute" k="128" />
+<hkern g1="Eth" g2="Acircumflex" k="128" />
+<hkern g1="Eth" g2="Atilde" k="128" />
+<hkern g1="Eth" g2="Adieresis" k="128" />
+<hkern g1="Eth" g2="Aring" k="128" />
+<hkern g1="Eth" g2="AE" k="131" />
+<hkern g1="Eth" g2="Yacute" k="190" />
+<hkern g1="Ntilde" g2="j" k="182" />
+<hkern g1="Ograve" g2="A" k="131" />
+<hkern g1="Ograve" g2="S" k="65" />
+<hkern g1="Ograve" g2="T" k="136" />
+<hkern g1="Ograve" g2="V" k="131" />
+<hkern g1="Ograve" g2="W" k="73" />
+<hkern g1="Ograve" g2="X" k="224" />
+<hkern g1="Ograve" g2="Y" k="224" />
+<hkern g1="Ograve" g2="Z" k="225" />
+<hkern g1="Ograve" g2="j" k="160" />
+<hkern g1="Ograve" g2="Agrave" k="131" />
+<hkern g1="Ograve" g2="Aacute" k="131" />
+<hkern g1="Ograve" g2="Acircumflex" k="131" />
+<hkern g1="Ograve" g2="Atilde" k="131" />
+<hkern g1="Ograve" g2="Adieresis" k="131" />
+<hkern g1="Ograve" g2="Aring" k="131" />
+<hkern g1="Ograve" g2="AE" k="165" />
+<hkern g1="Ograve" g2="Yacute" k="224" />
+<hkern g1="Oacute" g2="A" k="131" />
+<hkern g1="Oacute" g2="S" k="65" />
+<hkern g1="Oacute" g2="T" k="133" />
+<hkern g1="Oacute" g2="V" k="131" />
+<hkern g1="Oacute" g2="W" k="73" />
+<hkern g1="Oacute" g2="X" k="224" />
+<hkern g1="Oacute" g2="Y" k="224" />
+<hkern g1="Oacute" g2="Z" k="225" />
+<hkern g1="Oacute" g2="j" k="173" />
+<hkern g1="Oacute" g2="Agrave" k="131" />
+<hkern g1="Oacute" g2="Aacute" k="131" />
+<hkern g1="Oacute" g2="Acircumflex" k="131" />
+<hkern g1="Oacute" g2="Atilde" k="131" />
+<hkern g1="Oacute" g2="Adieresis" k="131" />
+<hkern g1="Oacute" g2="Aring" k="131" />
+<hkern g1="Oacute" g2="AE" k="165" />
+<hkern g1="Oacute" g2="Yacute" k="224" />
+<hkern g1="Ocircumflex" g2="A" k="131" />
+<hkern g1="Ocircumflex" g2="S" k="65" />
+<hkern g1="Ocircumflex" g2="T" k="109" />
+<hkern g1="Ocircumflex" g2="V" k="131" />
+<hkern g1="Ocircumflex" g2="W" k="73" />
+<hkern g1="Ocircumflex" g2="X" k="224" />
+<hkern g1="Ocircumflex" g2="Y" k="224" />
+<hkern g1="Ocircumflex" g2="Z" k="225" />
+<hkern g1="Ocircumflex" g2="j" k="187" />
+<hkern g1="Ocircumflex" g2="Agrave" k="131" />
+<hkern g1="Ocircumflex" g2="Aacute" k="131" />
+<hkern g1="Ocircumflex" g2="Acircumflex" k="131" />
+<hkern g1="Ocircumflex" g2="Atilde" k="131" />
+<hkern g1="Ocircumflex" g2="Adieresis" k="131" />
+<hkern g1="Ocircumflex" g2="Aring" k="131" />
+<hkern g1="Ocircumflex" g2="AE" k="165" />
+<hkern g1="Ocircumflex" g2="Yacute" k="224" />
+<hkern g1="Otilde" g2="A" k="131" />
+<hkern g1="Otilde" g2="S" k="65" />
+<hkern g1="Otilde" g2="T" k="137" />
+<hkern g1="Otilde" g2="V" k="131" />
+<hkern g1="Otilde" g2="W" k="73" />
+<hkern g1="Otilde" g2="X" k="224" />
+<hkern g1="Otilde" g2="Y" k="224" />
+<hkern g1="Otilde" g2="Z" k="225" />
+<hkern g1="Otilde" g2="j" k="169" />
+<hkern g1="Otilde" g2="Agrave" k="131" />
+<hkern g1="Otilde" g2="Aacute" k="131" />
+<hkern g1="Otilde" g2="Acircumflex" k="131" />
+<hkern g1="Otilde" g2="Atilde" k="131" />
+<hkern g1="Otilde" g2="Adieresis" k="131" />
+<hkern g1="Otilde" g2="Aring" k="131" />
+<hkern g1="Otilde" g2="AE" k="165" />
+<hkern g1="Otilde" g2="Yacute" k="224" />
+<hkern g1="Odieresis" g2="A" k="131" />
+<hkern g1="Odieresis" g2="S" k="65" />
+<hkern g1="Odieresis" g2="T" k="149" />
+<hkern g1="Odieresis" g2="V" k="131" />
+<hkern g1="Odieresis" g2="W" k="73" />
+<hkern g1="Odieresis" g2="X" k="224" />
+<hkern g1="Odieresis" g2="Y" k="110" />
+<hkern g1="Odieresis" g2="Z" k="225" />
+<hkern g1="Odieresis" g2="j" k="196" />
+<hkern g1="Odieresis" g2="Agrave" k="131" />
+<hkern g1="Odieresis" g2="Aacute" k="131" />
+<hkern g1="Odieresis" g2="Acircumflex" k="131" />
+<hkern g1="Odieresis" g2="Atilde" k="131" />
+<hkern g1="Odieresis" g2="Adieresis" k="131" />
+<hkern g1="Odieresis" g2="Aring" k="131" />
+<hkern g1="Odieresis" g2="AE" k="165" />
+<hkern g1="Odieresis" g2="Yacute" k="95" />
+<hkern g1="Oslash" g2="A" k="131" />
+<hkern g1="Oslash" g2="S" k="65" />
+<hkern g1="Oslash" g2="j" k="179" />
+<hkern g1="Oslash" g2="Agrave" k="131" />
+<hkern g1="Oslash" g2="Aacute" k="131" />
+<hkern g1="Oslash" g2="Acircumflex" k="131" />
+<hkern g1="Oslash" g2="Atilde" k="131" />
+<hkern g1="Oslash" g2="Adieresis" k="131" />
+<hkern g1="Oslash" g2="Aring" k="131" />
+<hkern g1="Oslash" g2="AE" k="165" />
+<hkern g1="Ugrave" g2="j" k="170" />
+<hkern g1="Uacute" g2="j" k="158" />
+<hkern g1="Ucircumflex" g2="j" k="175" />
+<hkern g1="Udieresis" g2="j" k="187" />
+<hkern g1="Yacute" g2="A" k="205" />
+<hkern g1="Yacute" g2="C" k="160" />
+<hkern g1="Yacute" g2="G" k="160" />
+<hkern g1="Yacute" g2="J" k="212" />
+<hkern g1="Yacute" g2="O" k="130" />
+<hkern g1="Yacute" g2="Q" k="130" />
+<hkern g1="Yacute" g2="S" k="61" />
+<hkern g1="Yacute" g2="a" k="181" />
+<hkern g1="Yacute" g2="c" k="181" />
+<hkern g1="Yacute" g2="d" k="205" />
+<hkern g1="Yacute" g2="e" k="197" />
+<hkern g1="Yacute" g2="f" k="157" />
+<hkern g1="Yacute" g2="g" k="186" />
+<hkern g1="Yacute" g2="j" k="197" />
+<hkern g1="Yacute" g2="m" k="168" />
+<hkern g1="Yacute" g2="n" k="129" />
+<hkern g1="Yacute" g2="o" k="181" />
+<hkern g1="Yacute" g2="p" k="187" />
+<hkern g1="Yacute" g2="q" k="178" />
+<hkern g1="Yacute" g2="r" k="158" />
+<hkern g1="Yacute" g2="s" k="127" />
+<hkern g1="Yacute" g2="t" k="62" />
+<hkern g1="Yacute" g2="u" k="129" />
+<hkern g1="Yacute" g2="v" k="129" />
+<hkern g1="Yacute" g2="w" k="166" />
+<hkern g1="Yacute" g2="x" k="160" />
+<hkern g1="Yacute" g2="y" k="160" />
+<hkern g1="Yacute" g2="z" k="160" />
+<hkern g1="Yacute" g2="Agrave" k="197" />
+<hkern g1="Yacute" g2="Aacute" k="205" />
+<hkern g1="Yacute" g2="Acircumflex" k="228" />
+<hkern g1="Yacute" g2="Atilde" k="197" />
+<hkern g1="Yacute" g2="Adieresis" k="197" />
+<hkern g1="Yacute" g2="Aring" k="189" />
+<hkern g1="Yacute" g2="AE" k="189" />
+<hkern g1="Yacute" g2="Ccedilla" k="160" />
+<hkern g1="Yacute" g2="Eth" k="50" />
+<hkern g1="Yacute" g2="Ograve" k="130" />
+<hkern g1="Yacute" g2="Oacute" k="130" />
+<hkern g1="Yacute" g2="Ocircumflex" k="130" />
+<hkern g1="Yacute" g2="Otilde" k="130" />
+<hkern g1="Yacute" g2="Odieresis" k="130" />
+<hkern g1="Yacute" g2="Oslash" k="130" />
+<hkern g1="Yacute" g2="agrave" k="174" />
+<hkern g1="Yacute" g2="aacute" k="189" />
+<hkern g1="Yacute" g2="acircumflex" k="166" />
+<hkern g1="Yacute" g2="atilde" k="67" />
+<hkern g1="Yacute" g2="adieresis" k="158" />
+<hkern g1="Yacute" g2="aring" k="126" />
+<hkern g1="Yacute" g2="ae" k="197" />
+<hkern g1="Yacute" g2="ccedilla" k="190" />
+<hkern g1="Yacute" g2="egrave" k="174" />
+<hkern g1="Yacute" g2="eacute" k="205" />
+<hkern g1="Yacute" g2="ecircumflex" k="150" />
+<hkern g1="Yacute" g2="edieresis" k="150" />
+<hkern g1="Yacute" g2="eth" k="166" />
+<hkern g1="Yacute" g2="ograve" k="181" />
+<hkern g1="Yacute" g2="oacute" k="174" />
+<hkern g1="Yacute" g2="ocircumflex" k="143" />
+<hkern g1="Yacute" g2="otilde" k="67" />
+<hkern g1="Yacute" g2="odieresis" k="158" />
+<hkern g1="Yacute" g2="oslash" k="181" />
+<hkern g1="Yacute" g2="ugrave" k="129" />
+<hkern g1="Yacute" g2="uacute" k="129" />
+<hkern g1="Yacute" g2="ucircumflex" k="129" />
+<hkern g1="Yacute" g2="udieresis" k="98" />
+<hkern g1="Yacute" g2="yacute" k="160" />
+<hkern g1="Yacute" g2="ydieresis" k="97" />
+<hkern g1="Yacute" g2="dotlessi" k="228" />
+<hkern g1="Thorn" g2="A" k="127" />
+<hkern g1="Thorn" g2="T" k="280" />
+<hkern g1="Thorn" g2="V" k="127" />
+<hkern g1="Thorn" g2="X" k="170" />
+<hkern g1="Thorn" g2="Y" k="186" />
+<hkern g1="Thorn" g2="Z" k="186" />
+<hkern g1="Thorn" g2="j" k="288" />
+<hkern g1="Thorn" g2="Agrave" k="127" />
+<hkern g1="Thorn" g2="Aacute" k="127" />
+<hkern g1="Thorn" g2="Acircumflex" k="127" />
+<hkern g1="Thorn" g2="Atilde" k="127" />
+<hkern g1="Thorn" g2="Adieresis" k="127" />
+<hkern g1="Thorn" g2="Aring" k="127" />
+<hkern g1="Thorn" g2="AE" k="161" />
+<hkern g1="Thorn" g2="Yacute" k="186" />
+<hkern g1="germandbls" g2="T" k="84" />
+<hkern g1="germandbls" g2="V" k="123" />
+<hkern g1="germandbls" g2="W" k="96" />
+<hkern g1="germandbls" g2="Y" k="108" />
+<hkern g1="germandbls" g2="j" k="194" />
+<hkern g1="germandbls" g2="y" k="61" />
+<hkern g1="germandbls" g2="Yacute" k="92" />
+<hkern g1="germandbls" g2="yacute" k="61" />
+<hkern g1="germandbls" g2="ydieresis" k="61" />
+<hkern g1="agrave" g2="T" k="154" />
+<hkern g1="agrave" g2="V" k="249" />
+<hkern g1="agrave" g2="W" k="160" />
+<hkern g1="agrave" g2="Y" k="223" />
+<hkern g1="agrave" g2="f" k="58" />
+<hkern g1="agrave" g2="j" k="146" />
+<hkern g1="agrave" g2="t" k="90" />
+<hkern g1="agrave" g2="v" k="62" />
+<hkern g1="agrave" g2="y" k="61" />
+<hkern g1="agrave" g2="Yacute" k="208" />
+<hkern g1="agrave" g2="icircumflex" k="58" />
+<hkern g1="agrave" g2="idieresis" k="65" />
+<hkern g1="agrave" g2="yacute" k="61" />
+<hkern g1="agrave" g2="ydieresis" k="61" />
+<hkern g1="aacute" g2="T" k="102" />
+<hkern g1="aacute" g2="V" k="249" />
+<hkern g1="aacute" g2="W" k="160" />
+<hkern g1="aacute" g2="Y" k="125" />
+<hkern g1="aacute" g2="f" k="58" />
+<hkern g1="aacute" g2="j" k="181" />
+<hkern g1="aacute" g2="t" k="90" />
+<hkern g1="aacute" g2="v" k="62" />
+<hkern g1="aacute" g2="y" k="61" />
+<hkern g1="aacute" g2="Yacute" k="118" />
+<hkern g1="aacute" g2="icircumflex" k="58" />
+<hkern g1="aacute" g2="idieresis" k="65" />
+<hkern g1="aacute" g2="yacute" k="61" />
+<hkern g1="aacute" g2="ydieresis" k="61" />
+<hkern g1="acircumflex" g2="T" k="214" />
+<hkern g1="acircumflex" g2="V" k="88" />
+<hkern g1="acircumflex" g2="W" k="160" />
+<hkern g1="acircumflex" g2="Y" k="199" />
+<hkern g1="acircumflex" g2="f" k="58" />
+<hkern g1="acircumflex" g2="j" k="207" />
+<hkern g1="acircumflex" g2="t" k="90" />
+<hkern g1="acircumflex" g2="v" k="62" />
+<hkern g1="acircumflex" g2="y" k="61" />
+<hkern g1="acircumflex" g2="Yacute" k="168" />
+<hkern g1="acircumflex" g2="yacute" k="61" />
+<hkern g1="acircumflex" g2="ydieresis" k="61" />
+<hkern g1="atilde" g2="T" k="123" />
+<hkern g1="atilde" g2="V" k="123" />
+<hkern g1="atilde" g2="W" k="97" />
+<hkern g1="atilde" g2="Y" k="122" />
+<hkern g1="atilde" g2="f" k="58" />
+<hkern g1="atilde" g2="j" k="181" />
+<hkern g1="atilde" g2="t" k="90" />
+<hkern g1="atilde" g2="v" k="62" />
+<hkern g1="atilde" g2="y" k="61" />
+<hkern g1="atilde" g2="Yacute" k="122" />
+<hkern g1="atilde" g2="yacute" k="61" />
+<hkern g1="atilde" g2="ydieresis" k="61" />
+<hkern g1="adieresis" g2="T" k="289" />
+<hkern g1="adieresis" g2="V" k="108" />
+<hkern g1="adieresis" g2="W" k="160" />
+<hkern g1="adieresis" g2="Y" k="179" />
+<hkern g1="adieresis" g2="f" k="58" />
+<hkern g1="adieresis" g2="j" k="195" />
+<hkern g1="adieresis" g2="t" k="90" />
+<hkern g1="adieresis" g2="v" k="62" />
+<hkern g1="adieresis" g2="y" k="61" />
+<hkern g1="adieresis" g2="Yacute" k="156" />
+<hkern g1="adieresis" g2="yacute" k="61" />
+<hkern g1="adieresis" g2="ydieresis" k="61" />
+<hkern g1="aring" g2="T" k="111" />
+<hkern g1="aring" g2="V" k="95" />
+<hkern g1="aring" g2="W" k="160" />
+<hkern g1="aring" g2="Y" k="111" />
+<hkern g1="aring" g2="f" k="58" />
+<hkern g1="aring" g2="j" k="190" />
+<hkern g1="aring" g2="t" k="90" />
+<hkern g1="aring" g2="v" k="62" />
+<hkern g1="aring" g2="y" k="61" />
+<hkern g1="aring" g2="Yacute" k="119" />
+<hkern g1="aring" g2="icircumflex" k="58" />
+<hkern g1="aring" g2="idieresis" k="65" />
+<hkern g1="aring" g2="yacute" k="61" />
+<hkern g1="aring" g2="ydieresis" k="61" />
+<hkern g1="ae" g2="A" k="126" />
+<hkern g1="ae" g2="S" k="123" />
+<hkern g1="ae" g2="T" k="225" />
+<hkern g1="ae" g2="V" k="284" />
+<hkern g1="ae" g2="W" k="163" />
+<hkern g1="ae" g2="X" k="157" />
+<hkern g1="ae" g2="Y" k="225" />
+<hkern g1="ae" g2="Z" k="158" />
+<hkern g1="ae" g2="f" k="93" />
+<hkern g1="ae" g2="i" k="50" />
+<hkern g1="ae" g2="j" k="192" />
+<hkern g1="ae" g2="t" k="124" />
+<hkern g1="ae" g2="v" k="97" />
+<hkern g1="ae" g2="w" k="70" />
+<hkern g1="ae" g2="x" k="127" />
+<hkern g1="ae" g2="y" k="96" />
+<hkern g1="ae" g2="z" k="127" />
+<hkern g1="ae" g2="Agrave" k="126" />
+<hkern g1="ae" g2="Aacute" k="126" />
+<hkern g1="ae" g2="Acircumflex" k="126" />
+<hkern g1="ae" g2="Atilde" k="126" />
+<hkern g1="ae" g2="Adieresis" k="126" />
+<hkern g1="ae" g2="Aring" k="126" />
+<hkern g1="ae" g2="AE" k="129" />
+<hkern g1="ae" g2="Igrave" k="47" />
+<hkern g1="ae" g2="Iacute" k="53" />
+<hkern g1="ae" g2="Icircumflex" k="60" />
+<hkern g1="ae" g2="Yacute" k="256" />
+<hkern g1="ae" g2="igrave" k="42" />
+<hkern g1="ae" g2="icircumflex" k="93" />
+<hkern g1="ae" g2="idieresis" k="100" />
+<hkern g1="ae" g2="yacute" k="96" />
+<hkern g1="ae" g2="ydieresis" k="96" />
+<hkern g1="ccedilla" g2="T" k="248" />
+<hkern g1="ccedilla" g2="V" k="123" />
+<hkern g1="ccedilla" g2="Y" k="185" />
+<hkern g1="ccedilla" g2="j" k="41" />
+<hkern g1="ccedilla" g2="Yacute" k="170" />
+<hkern g1="egrave" g2="A" k="92" />
+<hkern g1="egrave" g2="S" k="120" />
+<hkern g1="egrave" g2="T" k="210" />
+<hkern g1="egrave" g2="V" k="75" />
+<hkern g1="egrave" g2="W" k="160" />
+<hkern g1="egrave" g2="X" k="122" />
+<hkern g1="egrave" g2="Y" k="178" />
+<hkern g1="egrave" g2="Z" k="123" />
+<hkern g1="egrave" g2="f" k="58" />
+<hkern g1="egrave" g2="j" k="186" />
+<hkern g1="egrave" g2="t" k="90" />
+<hkern g1="egrave" g2="v" k="62" />
+<hkern g1="egrave" g2="x" k="93" />
+<hkern g1="egrave" g2="y" k="61" />
+<hkern g1="egrave" g2="z" k="93" />
+<hkern g1="egrave" g2="Agrave" k="92" />
+<hkern g1="egrave" g2="Aacute" k="92" />
+<hkern g1="egrave" g2="Acircumflex" k="92" />
+<hkern g1="egrave" g2="Atilde" k="92" />
+<hkern g1="egrave" g2="Adieresis" k="92" />
+<hkern g1="egrave" g2="Aring" k="92" />
+<hkern g1="egrave" g2="AE" k="95" />
+<hkern g1="egrave" g2="Yacute" k="209" />
+<hkern g1="egrave" g2="icircumflex" k="58" />
+<hkern g1="egrave" g2="idieresis" k="65" />
+<hkern g1="egrave" g2="yacute" k="61" />
+<hkern g1="egrave" g2="ydieresis" k="61" />
+<hkern g1="eacute" g2="A" k="92" />
+<hkern g1="eacute" g2="S" k="120" />
+<hkern g1="eacute" g2="T" k="129" />
+<hkern g1="eacute" g2="V" k="249" />
+<hkern g1="eacute" g2="W" k="160" />
+<hkern g1="eacute" g2="X" k="122" />
+<hkern g1="eacute" g2="Y" k="122" />
+<hkern g1="eacute" g2="Z" k="123" />
+<hkern g1="eacute" g2="f" k="58" />
+<hkern g1="eacute" g2="j" k="185" />
+<hkern g1="eacute" g2="t" k="90" />
+<hkern g1="eacute" g2="v" k="62" />
+<hkern g1="eacute" g2="x" k="93" />
+<hkern g1="eacute" g2="y" k="61" />
+<hkern g1="eacute" g2="z" k="93" />
+<hkern g1="eacute" g2="Agrave" k="92" />
+<hkern g1="eacute" g2="Aacute" k="92" />
+<hkern g1="eacute" g2="Acircumflex" k="92" />
+<hkern g1="eacute" g2="Atilde" k="92" />
+<hkern g1="eacute" g2="Adieresis" k="92" />
+<hkern g1="eacute" g2="Aring" k="92" />
+<hkern g1="eacute" g2="AE" k="95" />
+<hkern g1="eacute" g2="Yacute" k="106" />
+<hkern g1="eacute" g2="icircumflex" k="58" />
+<hkern g1="eacute" g2="idieresis" k="65" />
+<hkern g1="eacute" g2="yacute" k="61" />
+<hkern g1="eacute" g2="ydieresis" k="61" />
+<hkern g1="ecircumflex" g2="A" k="92" />
+<hkern g1="ecircumflex" g2="S" k="120" />
+<hkern g1="ecircumflex" g2="T" k="203" />
+<hkern g1="ecircumflex" g2="V" k="100" />
+<hkern g1="ecircumflex" g2="W" k="160" />
+<hkern g1="ecircumflex" g2="X" k="122" />
+<hkern g1="ecircumflex" g2="Y" k="164" />
+<hkern g1="ecircumflex" g2="Z" k="123" />
+<hkern g1="ecircumflex" g2="f" k="58" />
+<hkern g1="ecircumflex" g2="j" k="195" />
+<hkern g1="ecircumflex" g2="t" k="90" />
+<hkern g1="ecircumflex" g2="v" k="62" />
+<hkern g1="ecircumflex" g2="x" k="93" />
+<hkern g1="ecircumflex" g2="y" k="61" />
+<hkern g1="ecircumflex" g2="z" k="93" />
+<hkern g1="ecircumflex" g2="Agrave" k="92" />
+<hkern g1="ecircumflex" g2="Aacute" k="92" />
+<hkern g1="ecircumflex" g2="Acircumflex" k="92" />
+<hkern g1="ecircumflex" g2="Atilde" k="92" />
+<hkern g1="ecircumflex" g2="Adieresis" k="92" />
+<hkern g1="ecircumflex" g2="Aring" k="92" />
+<hkern g1="ecircumflex" g2="AE" k="95" />
+<hkern g1="ecircumflex" g2="Yacute" k="164" />
+<hkern g1="ecircumflex" g2="yacute" k="61" />
+<hkern g1="ecircumflex" g2="ydieresis" k="61" />
+<hkern g1="edieresis" g2="A" k="92" />
+<hkern g1="edieresis" g2="S" k="120" />
+<hkern g1="edieresis" g2="T" k="190" />
+<hkern g1="edieresis" g2="V" k="186" />
+<hkern g1="edieresis" g2="W" k="160" />
+<hkern g1="edieresis" g2="X" k="122" />
+<hkern g1="edieresis" g2="Y" k="142" />
+<hkern g1="edieresis" g2="Z" k="123" />
+<hkern g1="edieresis" g2="f" k="58" />
+<hkern g1="edieresis" g2="j" k="189" />
+<hkern g1="edieresis" g2="t" k="90" />
+<hkern g1="edieresis" g2="v" k="62" />
+<hkern g1="edieresis" g2="x" k="93" />
+<hkern g1="edieresis" g2="y" k="61" />
+<hkern g1="edieresis" g2="z" k="93" />
+<hkern g1="edieresis" g2="Agrave" k="92" />
+<hkern g1="edieresis" g2="Aacute" k="92" />
+<hkern g1="edieresis" g2="Acircumflex" k="92" />
+<hkern g1="edieresis" g2="Atilde" k="92" />
+<hkern g1="edieresis" g2="Adieresis" k="92" />
+<hkern g1="edieresis" g2="Aring" k="92" />
+<hkern g1="edieresis" g2="AE" k="95" />
+<hkern g1="edieresis" g2="Yacute" k="88" />
+<hkern g1="edieresis" g2="yacute" k="61" />
+<hkern g1="edieresis" g2="ydieresis" k="61" />
+<hkern g1="igrave" g2="T" k="40" />
+<hkern g1="igrave" g2="j" k="264" />
+<hkern g1="igrave" g2="dotlessi" k="46" />
+<hkern g1="iacute" g2="j" k="224" />
+<hkern g1="iacute" g2="dotlessi" k="49" />
+<hkern g1="icircumflex" g2="j" k="173" />
+<hkern g1="icircumflex" g2="dotlessi" k="44" />
+<hkern g1="idieresis" g2="A" k="40" />
+<hkern g1="idieresis" g2="T" k="-19" />
+<hkern g1="idieresis" g2="a" k="43" />
+<hkern g1="idieresis" g2="c" k="41" />
+<hkern g1="idieresis" g2="d" k="43" />
+<hkern g1="idieresis" g2="e" k="43" />
+<hkern g1="idieresis" g2="g" k="43" />
+<hkern g1="idieresis" g2="j" k="182" />
+<hkern g1="idieresis" g2="m" k="49" />
+<hkern g1="idieresis" g2="n" k="42" />
+<hkern g1="idieresis" g2="o" k="43" />
+<hkern g1="idieresis" g2="p" k="43" />
+<hkern g1="idieresis" g2="q" k="43" />
+<hkern g1="idieresis" g2="s" k="40" />
+<hkern g1="idieresis" g2="u" k="42" />
+<hkern g1="idieresis" g2="v" k="42" />
+<hkern g1="idieresis" g2="w" k="47" />
+<hkern g1="idieresis" g2="x" k="41" />
+<hkern g1="idieresis" g2="y" k="41" />
+<hkern g1="idieresis" g2="z" k="41" />
+<hkern g1="idieresis" g2="Agrave" k="40" />
+<hkern g1="idieresis" g2="Aacute" k="40" />
+<hkern g1="idieresis" g2="Acircumflex" k="40" />
+<hkern g1="idieresis" g2="Atilde" k="40" />
+<hkern g1="idieresis" g2="Adieresis" k="40" />
+<hkern g1="idieresis" g2="Aring" k="40" />
+<hkern g1="idieresis" g2="AE" k="43" />
+<hkern g1="idieresis" g2="agrave" k="43" />
+<hkern g1="idieresis" g2="aacute" k="43" />
+<hkern g1="idieresis" g2="aring" k="43" />
+<hkern g1="idieresis" g2="ae" k="55" />
+<hkern g1="idieresis" g2="ccedilla" k="41" />
+<hkern g1="idieresis" g2="egrave" k="43" />
+<hkern g1="idieresis" g2="eacute" k="43" />
+<hkern g1="idieresis" g2="ograve" k="43" />
+<hkern g1="idieresis" g2="oacute" k="43" />
+<hkern g1="idieresis" g2="oslash" k="43" />
+<hkern g1="idieresis" g2="ugrave" k="42" />
+<hkern g1="idieresis" g2="uacute" k="42" />
+<hkern g1="idieresis" g2="yacute" k="41" />
+<hkern g1="idieresis" g2="dotlessi" k="109" />
+<hkern g1="eth" g2="T" k="133" />
+<hkern g1="eth" g2="V" k="133" />
+<hkern g1="eth" g2="W" k="107" />
+<hkern g1="eth" g2="X" k="101" />
+<hkern g1="eth" g2="Y" k="132" />
+<hkern g1="eth" g2="Z" k="102" />
+<hkern g1="eth" g2="j" k="200" />
+<hkern g1="eth" g2="t" k="68" />
+<hkern g1="eth" g2="x" k="71" />
+<hkern g1="eth" g2="y" k="40" />
+<hkern g1="eth" g2="z" k="71" />
+<hkern g1="eth" g2="AE" k="42" />
+<hkern g1="eth" g2="Yacute" k="132" />
+<hkern g1="eth" g2="idieresis" k="44" />
+<hkern g1="eth" g2="yacute" k="40" />
+<hkern g1="eth" g2="ydieresis" k="40" />
+<hkern g1="ntilde" g2="T" k="76" />
+<hkern g1="ntilde" g2="V" k="76" />
+<hkern g1="ntilde" g2="W" k="49" />
+<hkern g1="ntilde" g2="Y" k="75" />
+<hkern g1="ntilde" g2="f" k="42" />
+<hkern g1="ntilde" g2="j" k="190" />
+<hkern g1="ntilde" g2="t" k="74" />
+<hkern g1="ntilde" g2="v" k="46" />
+<hkern g1="ntilde" g2="y" k="45" />
+<hkern g1="ntilde" g2="Yacute" k="75" />
+<hkern g1="ntilde" g2="yacute" k="45" />
+<hkern g1="ntilde" g2="ydieresis" k="45" />
+<hkern g1="ograve" g2="A" k="60" />
+<hkern g1="ograve" g2="T" k="115" />
+<hkern g1="ograve" g2="V" k="249" />
+<hkern g1="ograve" g2="W" k="160" />
+<hkern g1="ograve" g2="X" k="122" />
+<hkern g1="ograve" g2="Y" k="169" />
+<hkern g1="ograve" g2="Z" k="123" />
+<hkern g1="ograve" g2="f" k="58" />
+<hkern g1="ograve" g2="j" k="239" />
+<hkern g1="ograve" g2="t" k="90" />
+<hkern g1="ograve" g2="v" k="62" />
+<hkern g1="ograve" g2="x" k="93" />
+<hkern g1="ograve" g2="y" k="61" />
+<hkern g1="ograve" g2="z" k="93" />
+<hkern g1="ograve" g2="Agrave" k="60" />
+<hkern g1="ograve" g2="Aacute" k="60" />
+<hkern g1="ograve" g2="Acircumflex" k="60" />
+<hkern g1="ograve" g2="Atilde" k="60" />
+<hkern g1="ograve" g2="Adieresis" k="60" />
+<hkern g1="ograve" g2="Aring" k="60" />
+<hkern g1="ograve" g2="AE" k="63" />
+<hkern g1="ograve" g2="Yacute" k="169" />
+<hkern g1="ograve" g2="icircumflex" k="58" />
+<hkern g1="ograve" g2="idieresis" k="65" />
+<hkern g1="ograve" g2="yacute" k="61" />
+<hkern g1="ograve" g2="ydieresis" k="61" />
+<hkern g1="oacute" g2="A" k="60" />
+<hkern g1="oacute" g2="T" k="114" />
+<hkern g1="oacute" g2="V" k="249" />
+<hkern g1="oacute" g2="W" k="160" />
+<hkern g1="oacute" g2="X" k="122" />
+<hkern g1="oacute" g2="Y" k="160" />
+<hkern g1="oacute" g2="Z" k="123" />
+<hkern g1="oacute" g2="f" k="58" />
+<hkern g1="oacute" g2="j" k="216" />
+<hkern g1="oacute" g2="t" k="90" />
+<hkern g1="oacute" g2="v" k="62" />
+<hkern g1="oacute" g2="x" k="93" />
+<hkern g1="oacute" g2="y" k="61" />
+<hkern g1="oacute" g2="z" k="93" />
+<hkern g1="oacute" g2="Agrave" k="60" />
+<hkern g1="oacute" g2="Aacute" k="60" />
+<hkern g1="oacute" g2="Acircumflex" k="60" />
+<hkern g1="oacute" g2="Atilde" k="60" />
+<hkern g1="oacute" g2="Adieresis" k="60" />
+<hkern g1="oacute" g2="Aring" k="60" />
+<hkern g1="oacute" g2="AE" k="63" />
+<hkern g1="oacute" g2="Yacute" k="106" />
+<hkern g1="oacute" g2="icircumflex" k="58" />
+<hkern g1="oacute" g2="idieresis" k="65" />
+<hkern g1="oacute" g2="yacute" k="61" />
+<hkern g1="oacute" g2="ydieresis" k="61" />
+<hkern g1="ocircumflex" g2="A" k="60" />
+<hkern g1="ocircumflex" g2="T" k="169" />
+<hkern g1="ocircumflex" g2="V" k="218" />
+<hkern g1="ocircumflex" g2="W" k="160" />
+<hkern g1="ocircumflex" g2="X" k="122" />
+<hkern g1="ocircumflex" g2="Y" k="138" />
+<hkern g1="ocircumflex" g2="Z" k="123" />
+<hkern g1="ocircumflex" g2="f" k="58" />
+<hkern g1="ocircumflex" g2="j" k="224" />
+<hkern g1="ocircumflex" g2="t" k="90" />
+<hkern g1="ocircumflex" g2="v" k="62" />
+<hkern g1="ocircumflex" g2="x" k="93" />
+<hkern g1="ocircumflex" g2="y" k="61" />
+<hkern g1="ocircumflex" g2="z" k="93" />
+<hkern g1="ocircumflex" g2="Agrave" k="60" />
+<hkern g1="ocircumflex" g2="Aacute" k="60" />
+<hkern g1="ocircumflex" g2="Acircumflex" k="60" />
+<hkern g1="ocircumflex" g2="Atilde" k="60" />
+<hkern g1="ocircumflex" g2="Adieresis" k="60" />
+<hkern g1="ocircumflex" g2="Aring" k="60" />
+<hkern g1="ocircumflex" g2="AE" k="63" />
+<hkern g1="ocircumflex" g2="Yacute" k="138" />
+<hkern g1="ocircumflex" g2="yacute" k="61" />
+<hkern g1="ocircumflex" g2="ydieresis" k="61" />
+<hkern g1="otilde" g2="A" k="60" />
+<hkern g1="otilde" g2="T" k="83" />
+<hkern g1="otilde" g2="V" k="123" />
+<hkern g1="otilde" g2="W" k="97" />
+<hkern g1="otilde" g2="X" k="122" />
+<hkern g1="otilde" g2="Y" k="122" />
+<hkern g1="otilde" g2="Z" k="123" />
+<hkern g1="otilde" g2="f" k="58" />
+<hkern g1="otilde" g2="j" k="192" />
+<hkern g1="otilde" g2="t" k="90" />
+<hkern g1="otilde" g2="v" k="62" />
+<hkern g1="otilde" g2="x" k="93" />
+<hkern g1="otilde" g2="y" k="61" />
+<hkern g1="otilde" g2="z" k="93" />
+<hkern g1="otilde" g2="Agrave" k="60" />
+<hkern g1="otilde" g2="Aacute" k="60" />
+<hkern g1="otilde" g2="Acircumflex" k="60" />
+<hkern g1="otilde" g2="Atilde" k="60" />
+<hkern g1="otilde" g2="Adieresis" k="60" />
+<hkern g1="otilde" g2="Aring" k="60" />
+<hkern g1="otilde" g2="AE" k="63" />
+<hkern g1="otilde" g2="Yacute" k="122" />
+<hkern g1="otilde" g2="yacute" k="61" />
+<hkern g1="otilde" g2="ydieresis" k="61" />
+<hkern g1="odieresis" g2="A" k="60" />
+<hkern g1="odieresis" g2="T" k="228" />
+<hkern g1="odieresis" g2="V" k="186" />
+<hkern g1="odieresis" g2="W" k="160" />
+<hkern g1="odieresis" g2="X" k="122" />
+<hkern g1="odieresis" g2="Y" k="133" />
+<hkern g1="odieresis" g2="Z" k="123" />
+<hkern g1="odieresis" g2="f" k="58" />
+<hkern g1="odieresis" g2="j" k="227" />
+<hkern g1="odieresis" g2="t" k="90" />
+<hkern g1="odieresis" g2="v" k="62" />
+<hkern g1="odieresis" g2="x" k="93" />
+<hkern g1="odieresis" g2="y" k="61" />
+<hkern g1="odieresis" g2="z" k="93" />
+<hkern g1="odieresis" g2="Agrave" k="60" />
+<hkern g1="odieresis" g2="Aacute" k="60" />
+<hkern g1="odieresis" g2="Acircumflex" k="60" />
+<hkern g1="odieresis" g2="Atilde" k="60" />
+<hkern g1="odieresis" g2="Adieresis" k="60" />
+<hkern g1="odieresis" g2="Aring" k="60" />
+<hkern g1="odieresis" g2="AE" k="63" />
+<hkern g1="odieresis" g2="Yacute" k="118" />
+<hkern g1="odieresis" g2="yacute" k="61" />
+<hkern g1="odieresis" g2="ydieresis" k="61" />
+<hkern g1="oslash" g2="A" k="60" />
+<hkern g1="oslash" g2="T" k="163" />
+<hkern g1="oslash" g2="V" k="123" />
+<hkern g1="oslash" g2="X" k="122" />
+<hkern g1="oslash" g2="Y" k="217" />
+<hkern g1="oslash" g2="Z" k="123" />
+<hkern g1="oslash" g2="j" k="186" />
+<hkern g1="oslash" g2="Agrave" k="60" />
+<hkern g1="oslash" g2="Aacute" k="60" />
+<hkern g1="oslash" g2="Acircumflex" k="60" />
+<hkern g1="oslash" g2="Atilde" k="60" />
+<hkern g1="oslash" g2="Adieresis" k="60" />
+<hkern g1="oslash" g2="Aring" k="60" />
+<hkern g1="oslash" g2="AE" k="63" />
+<hkern g1="oslash" g2="Yacute" k="217" />
+<hkern g1="oslash" g2="icircumflex" k="58" />
+<hkern g1="oslash" g2="idieresis" k="65" />
+<hkern g1="ugrave" g2="T" k="192" />
+<hkern g1="ugrave" g2="V" k="107" />
+<hkern g1="ugrave" g2="W" k="49" />
+<hkern g1="ugrave" g2="Y" k="97" />
+<hkern g1="ugrave" g2="j" k="199" />
+<hkern g1="ugrave" g2="Yacute" k="97" />
+<hkern g1="ugrave" g2="icircumflex" k="42" />
+<hkern g1="ugrave" g2="idieresis" k="49" />
+<hkern g1="uacute" g2="T" k="93" />
+<hkern g1="uacute" g2="V" k="107" />
+<hkern g1="uacute" g2="W" k="49" />
+<hkern g1="uacute" g2="Y" k="62" />
+<hkern g1="uacute" g2="j" k="195" />
+<hkern g1="uacute" g2="Yacute" k="62" />
+<hkern g1="uacute" g2="icircumflex" k="42" />
+<hkern g1="uacute" g2="idieresis" k="49" />
+<hkern g1="ucircumflex" g2="T" k="134" />
+<hkern g1="ucircumflex" g2="V" k="107" />
+<hkern g1="ucircumflex" g2="W" k="49" />
+<hkern g1="ucircumflex" g2="Y" k="71" />
+<hkern g1="ucircumflex" g2="j" k="204" />
+<hkern g1="ucircumflex" g2="Yacute" k="71" />
+<hkern g1="udieresis" g2="T" k="216" />
+<hkern g1="udieresis" g2="V" k="107" />
+<hkern g1="udieresis" g2="W" k="49" />
+<hkern g1="udieresis" g2="Y" k="97" />
+<hkern g1="udieresis" g2="j" k="222" />
+<hkern g1="udieresis" g2="Yacute" k="97" />
+<hkern g1="yacute" g2="A" k="132" />
+<hkern g1="yacute" g2="J" k="88" />
+<hkern g1="yacute" g2="T" k="91" />
+<hkern g1="yacute" g2="V" k="91" />
+<hkern g1="yacute" g2="X" k="90" />
+<hkern g1="yacute" g2="Y" k="90" />
+<hkern g1="yacute" g2="Z" k="91" />
+<hkern g1="yacute" g2="j" k="226" />
+<hkern g1="yacute" g2="Agrave" k="139" />
+<hkern g1="yacute" g2="Aacute" k="116" />
+<hkern g1="yacute" g2="Acircumflex" k="124" />
+<hkern g1="yacute" g2="Atilde" k="116" />
+<hkern g1="yacute" g2="Adieresis" k="116" />
+<hkern g1="yacute" g2="Aring" k="124" />
+<hkern g1="yacute" g2="AE" k="125" />
+<hkern g1="yacute" g2="Yacute" k="90" />
+<hkern g1="thorn" g2="A" k="60" />
+<hkern g1="thorn" g2="T" k="251" />
+<hkern g1="thorn" g2="V" k="249" />
+<hkern g1="thorn" g2="W" k="160" />
+<hkern g1="thorn" g2="X" k="122" />
+<hkern g1="thorn" g2="Y" k="258" />
+<hkern g1="thorn" g2="Z" k="123" />
+<hkern g1="thorn" g2="f" k="58" />
+<hkern g1="thorn" g2="j" k="250" />
+<hkern g1="thorn" g2="t" k="90" />
+<hkern g1="thorn" g2="v" k="62" />
+<hkern g1="thorn" g2="x" k="93" />
+<hkern g1="thorn" g2="y" k="61" />
+<hkern g1="thorn" g2="z" k="93" />
+<hkern g1="thorn" g2="Agrave" k="60" />
+<hkern g1="thorn" g2="Aacute" k="60" />
+<hkern g1="thorn" g2="Acircumflex" k="60" />
+<hkern g1="thorn" g2="Atilde" k="60" />
+<hkern g1="thorn" g2="Adieresis" k="60" />
+<hkern g1="thorn" g2="Aring" k="60" />
+<hkern g1="thorn" g2="AE" k="63" />
+<hkern g1="thorn" g2="Yacute" k="243" />
+<hkern g1="thorn" g2="icircumflex" k="58" />
+<hkern g1="thorn" g2="idieresis" k="65" />
+<hkern g1="thorn" g2="yacute" k="61" />
+<hkern g1="thorn" g2="ydieresis" k="61" />
+<hkern g1="ydieresis" g2="A" k="125" />
+<hkern g1="ydieresis" g2="J" k="88" />
+<hkern g1="ydieresis" g2="T" k="166" />
+<hkern g1="ydieresis" g2="V" k="60" />
+<hkern g1="ydieresis" g2="X" k="55" />
+<hkern g1="ydieresis" g2="Y" k="63" />
+<hkern g1="ydieresis" g2="Z" k="133" />
+<hkern g1="ydieresis" g2="j" k="227" />
+<hkern g1="ydieresis" g2="Agrave" k="117" />
+<hkern g1="ydieresis" g2="Aacute" k="102" />
+<hkern g1="ydieresis" g2="Acircumflex" k="125" />
+<hkern g1="ydieresis" g2="Atilde" k="117" />
+<hkern g1="ydieresis" g2="Adieresis" k="125" />
+<hkern g1="ydieresis" g2="Aring" k="94" />
+<hkern g1="ydieresis" g2="AE" k="141" />
+<hkern g1="ydieresis" g2="Yacute" k="86" />
+<hkern g1="dotlessi" g2="I" k="51" />
+<hkern g1="dotlessi" g2="T" k="486" />
+<hkern g1="dotlessi" g2="V" k="171" />
+<hkern g1="dotlessi" g2="W" k="81" />
+<hkern g1="dotlessi" g2="Y" k="265" />
+<hkern g1="dotlessi" g2="i" k="63" />
+<hkern g1="dotlessi" g2="j" k="278" />
+<hkern g1="dotlessi" g2="Igrave" k="60" />
+<hkern g1="dotlessi" g2="Iacute" k="66" />
+<hkern g1="dotlessi" g2="Icircumflex" k="73" />
+<hkern g1="dotlessi" g2="Idieresis" k="52" />
+<hkern g1="dotlessi" g2="Yacute" k="265" />
+<hkern g1="dotlessi" g2="igrave" k="55" />
+<hkern g1="dotlessi" g2="iacute" k="52" />
+<hkern g1="dotlessi" g2="icircumflex" k="106" />
+<hkern g1="dotlessi" g2="idieresis" k="113" />
+<hkern g1="dotlessi" g2="dotlessi" k="51" />
+</font>
+</defs>
+</svg>
diff --git a/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.ttf b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.ttf
new file mode 100644
index 0000000..f68d1cc
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.ttf differ
diff --git a/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.woff b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.woff
new file mode 100644
index 0000000..1057958
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.woff differ
diff --git a/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.woff2 b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.woff2
new file mode 100644
index 0000000..14c5487
Binary files /dev/null and b/hubs/static/css/fonts/Comfortaa-regular/Comfortaa-regular.woff2 differ
diff --git a/hubs/static/css/fonts/Comfortaa-regular/LICENSE.txt b/hubs/static/css/fonts/Comfortaa-regular/LICENSE.txt
new file mode 100644
index 0000000..e0bfe25
--- /dev/null
+++ b/hubs/static/css/fonts/Comfortaa-regular/LICENSE.txt
@@ -0,0 +1,94 @@
+Copyright (c) 2010, 2011 Johan Aakerlund (aajohan@gmail.com),
+with Reserved Font Name "Comfortaa".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded, 
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.

From 45f398ce692c9ac03fff0a7d5854f0b1fa254428 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Sep 06 2015 00:43:35 +0000
Subject: [PATCH 219/1001] Added @font-face definitions to style.css for Comfortaa


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 655d2cb..1d8a9aa 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -309,3 +309,45 @@ font-size: 32pt;
 .navbar-nav > li.idle-year    > a { color: #AAA; }
 .navbar-nav > li.idle-2years  > a { color: #BBB; }
 .navbar-nav > li.idle-5years  > a { color: #CCC; }
+
+@font-face {
+  font-family: 'Comfortaa';
+  font-weight: 300;
+  font-style: normal;
+  src: url('/fonts/Comfortaa-300/Comfortaa-300.eot');
+  src: url('/fonts/Comfortaa-300/Comfortaa-300.eot?#iefix') format('embedded-opentype'),
+       local('Comfortaa Light'),
+       local('Comfortaa-300'),
+       url('/fonts/Comfortaa-300/Comfortaa-300.woff2') format('woff2'),
+       url('/fonts/Comfortaa-300/Comfortaa-300.woff') format('woff'),
+       url('/fonts/Comfortaa-300/Comfortaa-300.ttf') format('truetype'),
+       url('/fonts/Comfortaa-300/Comfortaa-300.svg#Comfortaa') format('svg');
+}
+
+@font-face {
+  font-family: 'Comfortaa';
+  font-weight: 400;
+  font-style: normal;
+  src: url('/fonts/Comfortaa-regular/Comfortaa-regular.eot');
+  src: url('/fonts/Comfortaa-regular/Comfortaa-regular.eot?#iefix') format('embedded-opentype'),
+       local('Comfortaa'),
+       local('Comfortaa-regular'),
+       url('/fonts/Comfortaa-regular/Comfortaa-regular.woff2') format('woff2'),
+       url('/fonts/Comfortaa-regular/Comfortaa-regular.woff') format('woff'),
+       url('/fonts/Comfortaa-regular/Comfortaa-regular.ttf') format('truetype'),
+       url('/fonts/Comfortaa-regular/Comfortaa-regular.svg#Comfortaa') format('svg');
+}
+
+@font-face {
+  font-family: 'Comfortaa';
+  font-weight: 700;
+  font-style: normal;
+  src: url('/fonts/Comfortaa-700/Comfortaa-700.eot');
+  src: url('/fonts/Comfortaa-700/Comfortaa-700.eot?#iefix') format('embedded-opentype'),
+       local('Comfortaa Bold'),
+       local('Comfortaa-700'),
+       url('/fonts/Comfortaa-700/Comfortaa-700.woff2') format('woff2'),
+       url('/fonts/Comfortaa-700/Comfortaa-700.woff') format('woff'),
+       url('/fonts/Comfortaa-700/Comfortaa-700.ttf') format('truetype'),
+       url('/fonts/Comfortaa-700/Comfortaa-700.svg#Comfortaa') format('svg');
+}

From 1e57f4329ea9a26e2eb8d291bb3b98f5e7388bf6 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Sep 06 2015 00:44:55 +0000
Subject: [PATCH 220/1001] Removed Google Fonts Link from hubs.html template


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index bf6f021..1e87956 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -4,8 +4,6 @@
   <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
-  <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic|Comfortaa' rel='stylesheet' type='text/css'>
-<!--I added google fonts!!!! Sorry if I wasn't supposed to do that!!! -->
 </head>
 <script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
 <body>

From 98e1a2d34039e5aa3e0d3d24eb8f413e73e7d64e Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Sep 06 2015 00:45:45 +0000
Subject: [PATCH 221/1001] Remove extra Comfortaa files


---

diff --git a/hubs/static/css/fonts/Comfortaa_Bold-webfont.eot b/hubs/static/css/fonts/Comfortaa_Bold-webfont.eot
deleted file mode 100644
index 5f40449..0000000
Binary files a/hubs/static/css/fonts/Comfortaa_Bold-webfont.eot and /dev/null differ
diff --git a/hubs/static/css/fonts/Comfortaa_Bold-webfont.svg b/hubs/static/css/fonts/Comfortaa_Bold-webfont.svg
deleted file mode 100644
index 8b25d69..0000000
--- a/hubs/static/css/fonts/Comfortaa_Bold-webfont.svg
+++ /dev/null
@@ -1,504 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata>
-This is a custom SVG webfont generated by Font Squirrel.
-Designer    : Johan Aakerlund - aajohan
-</metadata>
-<defs>
-<font id="webfontjkcnhWWT" horiz-adv-x="1014" >
-<font-face units-per-em="2048" ascent="1638" descent="-410" />
-<missing-glyph horiz-adv-x="508" />
-<glyph unicode=" "  horiz-adv-x="508" />
-<glyph unicode="&#x09;" horiz-adv-x="508" />
-<glyph unicode="&#xa0;" horiz-adv-x="508" />
-<glyph unicode="!" horiz-adv-x="511" d="M245 1472h12q84 0 103 -96v-961q-24 -99 -110 -99q-108 16 -108 99v965q19 92 103 92zM236 236h10q131 -19 131 -122v-22q0 -95 -122 -122h-15q-104 0 -130 133q27 133 126 133z" />
-<glyph unicode="&#x22;" horiz-adv-x="557" d="M193 1589q102 -26 102 -99q-23 -341 -77 -341l-28 -8q-83 0 -91 152l-20 187q22 109 114 109zM435 1589q76 0 105 -103q-32 -329 -63 -329q-17 -16 -44 -16h-4q-86 0 -86 164l-20 184q0 81 112 100z" />
-<glyph unicode="#" horiz-adv-x="1336" d="M1030 1461q94 -26 94 -94v-11q0 -32 -69 -359h71l34 4q81 0 104 -106q-21 -105 -106 -105h-145l-26 -132h104q116 -11 116 -109q-19 -98 -72 -98v-11l-52 11h-138q-79 -399 -97 -435q-36 -48 -86 -48h-11q-94 20 -94 98v6l76 379h-178q4 0 4 -17q0 -45 -28 -205 q-43 -213 -61 -224q-29 -41 -84 -41q-103 20 -103 108l76 379h-62l-22 -4q-85 0 -105 106v7q0 75 102 98h133l26 132h-102q-102 20 -102 107q17 100 67 100v7l70 -7h109q82 438 113 438q28 22 67 22q87 0 101 -106l-69 -354h158q77 397 96 423q38 41 91 41zM644 790 l-26 -132h157l26 132h-157z" />
-<glyph unicode="$" d="M622 210q99 73 99 180v39q0 126 -99 187v-406zM336 1091v-31q0 -106 76 -148v316q-76 -38 -76 -137zM507 1682h20q75 0 95 -100v-103q76 -6 200 -118q52 -53 52 -88v-23q0 -76 -101 -92q-46 0 -119 81q-27 23 -32 24v-398q169 -62 249 -213q61 -116 61 -222 q0 -298 -307 -432h-3v-106q-24 -100 -106 -100q-104 22 -104 104v104q0 -13 -29 -13q-15 0 -37 3q-186 63 -269 200l-6 34q18 104 104 104q55 0 129 -93q76 -50 108 -52v526q-120 37 -175 116q-108 111 -108 258v28q0 206 210 331q72 35 73 35v115q28 90 95 90z" />
-<glyph unicode="%" horiz-adv-x="1610" d="M462 1486h19q182 0 308 -164q74 -109 74 -223q0 -252 -262 -372q-75 -21 -124 -21h-7q-228 0 -349 220q-41 84 -41 170q0 256 270 372q56 18 112 18zM1316 1466h14q95 -20 95 -99v-15q0 -32 -146 -219l-864 -1142q-42 -21 -65 -21h-7q-99 21 -99 94v16q0 42 112 178 l897 1184q35 24 63 24zM288 1097v-5q0 -128 142 -175l33 -3h18q125 0 171 146l4 37q0 131 -140 178l-44 7q-129 0 -178 -136zM1209 743q229 0 361 -237q29 -87 29 -152v-12q0 -229 -241 -352q-75 -30 -149 -30h-7q-200 0 -328 192q-55 94 -55 186v23q0 207 205 333 q99 49 185 49zM1023 352q0 -127 133 -178l48 -6h13q122 0 171 140l3 29v24q0 127 -150 171l-34 4q-135 0 -181 -154z" />
-<glyph unicode="&#x26;" horiz-adv-x="1457" d="M529 655q-176 -158 -176 -228l-4 -31v-17q0 -126 145 -183l51 -7q114 0 226 142l41 41zM530 959q120 106 120 160v15q0 75 -91 111l-33 3q-71 0 -106 -79l-6 -23v-27q0 -61 116 -160zM966 525l137 139q36 26 69 26q97 0 110 -112q0 -58 -142 -182l-21 -23l197 -198 q23 -29 23 -61v-15q-21 -99 -102 -99h-11q-56 0 -163 123l-98 96q-204 -222 -279 -222q-66 -27 -139 -27q-237 0 -376 236q-41 97 -41 185q0 208 221 389l25 26q-174 162 -174 230q-8 0 -8 98q0 206 220 312q61 17 106 17h19q213 0 314 -233q12 -54 12 -92v-19 q0 -160 -165 -292l-16 -18z" />
-<glyph unicode="'" horiz-adv-x="346" d="M206 1576q102 -26 102 -99q-23 -341 -77 -341l-28 -8q-83 0 -91 152l-20 187q22 109 114 109z" />
-<glyph unicode="(" horiz-adv-x="758" d="M633 1626h14q96 -18 96 -98v-17l-78 -208q-129 -348 -129 -714q0 -456 205 -905l7 -24q-20 -108 -104 -108h-7q-88 0 -132 158q-178 413 -178 883q0 505 227 995q41 38 79 38z" />
-<glyph unicode=")" horiz-adv-x="758" d="M171 1630h15q75 0 124 -158q178 -423 178 -876q0 -534 -236 -1014q-43 -28 -73 -28h-8q-85 0 -104 110l84 210q128 362 128 718q0 447 -205 906l-7 24q19 108 104 108z" />
-<glyph unicode="*" horiz-adv-x="1024" d="M474 1366l-32 104v13q0 83 111 107q105 -27 105 -107v-13l-32 -102l103 64l35 5q106 -20 106 -106v-12q0 -60 -84 -98l-118 4l93 -76l17 -45v-25q0 -84 -103 -102q-102 0 -120 135l-3 10l-25 -84q-41 -61 -102 -61q-103 23 -103 98v16q0 64 105 125l9 7l-121 -2 q-85 34 -85 106v4q0 86 107 106q39 0 137 -71z" />
-<glyph unicode="+" d="M542 1147h12q84 0 102 -103v-197h183q121 -10 121 -113q-20 -103 -76 -103v-11l-53 11h-175v-201q-19 -103 -106 -103h-7q-103 20 -103 98v206h-172l-24 -4q-87 0 -108 111v7q0 78 107 102h197v201q19 99 102 99z" />
-<glyph unicode="," horiz-adv-x="557" d="M283 -28q-177 30 -177 174v4q0 102 122 151q21 11 56 11h19q163 -34 163 -154l1 -31l7 -47v-18q0 -203 -199 -302q-43 -28 -75 -28q-67 0 -82 88q0 74 103 94q30 17 62 58z" />
-<glyph unicode="-" horiz-adv-x="670" d="M175 698h400q83 0 106 -110q-25 -106 -106 -106h-400q-92 0 -107 116q28 100 107 100z" />
-<glyph unicode="&#xad;" horiz-adv-x="670" d="M175 698h400q83 0 106 -110q-25 -106 -106 -106h-400q-92 0 -107 116q28 100 107 100z" />
-<glyph unicode="." horiz-adv-x="557" d="M299 304q129 0 165 -151v-28q0 -94 -113 -145q-20 -10 -52 -10h-4q-137 0 -165 167q0 110 118 157q19 10 51 10z" />
-<glyph unicode="/" horiz-adv-x="770" d="M661 1547q103 -18 103 -102v-25q-506 -1395 -560 -1527q-43 -46 -86 -46h-8q-87 0 -106 110q5 34 560 1540q49 50 97 50z" />
-<glyph unicode="0" horiz-adv-x="989" d="M476 1467q266 0 406 -284q74 -227 74 -419v-87q0 -237 -98 -479q-148 -228 -374 -228h-12q-246 0 -386 259q-86 220 -86 486v11q0 282 102 513q151 228 374 228zM196 737v-41q0 -253 90 -422q81 -100 183 -100h11q229 0 269 367q11 61 15 181q0 214 -73 407 q-84 134 -211 134q-155 0 -229 -173q-55 -183 -55 -353z" />
-<glyph unicode="1" horiz-adv-x="568" d="M331 1467h19q95 -21 95 -95v-1303q-18 -99 -102 -99h-7q-99 21 -99 94v1156q-67 -22 -103 -22q-71 0 -94 95v23q0 80 175 116z" />
-<glyph unicode="2" horiz-adv-x="976" d="M461 1466q218 0 379 -194q85 -129 85 -267q0 -210 -201 -399l-375 -429h497q81 0 98 -98v-9q-15 -100 -102 -100h-736q-98 18 -98 102v4q0 49 79 123l584 666q43 60 43 140q0 171 -180 240q-28 9 -66 9h-11q-164 0 -237 -176q-9 -36 -13 -96q-37 -75 -98 -75h-10 q-99 18 -99 98q0 242 230 396q123 65 231 65z" />
-<glyph unicode="3" horiz-adv-x="955" d="M474 1462q183 0 315 -163q74 -100 74 -221v-15q0 -170 -118 -273q178 -129 178 -360q0 -239 -225 -396q-117 -64 -231 -64h-11q-270 0 -420 278q-36 103 -36 185q0 78 106 98q86 0 101 -103q0 -146 153 -231q54 -20 107 -20q150 0 228 159q17 46 17 79v30q0 141 -157 219 l-127 28q-55 42 -55 92v4q0 101 132 101q60 0 128 84q26 55 26 101q0 104 -104 162q-37 19 -84 19q-120 0 -171 -128q-14 -132 -42 -132q-27 -30 -69 -30q-102 23 -102 94v19q0 213 212 339q81 41 175 45z" />
-<glyph unicode="4" horiz-adv-x="1103" d="M748 1455h23q62 0 95 -90l-5 -43v-720h86l34 3q76 0 102 -101q0 -76 -90 -109l-61 4h-71v-335q0 -73 -98 -94h-10q-99 18 -99 101v328h-476l-98 -4q-80 34 -80 98v15q0 41 46 77q599 779 633 832q35 38 69 38zM320 602h334v435z" />
-<glyph unicode="5" d="M183 1460l45 -5h573q85 0 105 -105q0 -85 -106 -108h-497v-319h185q270 0 422 -276q47 -114 47 -201q0 -247 -234 -409q-121 -67 -239 -67h-12q-279 0 -435 288q-37 110 -37 189q35 96 108 96q113 0 113 -158q43 -129 134 -174q74 -28 121 -28q176 0 250 180q14 35 14 83 q0 192 -203 256l-85 8h-261q-74 0 -101 89v563q0 63 93 98z" />
-<glyph unicode="6" horiz-adv-x="951" d="M211 446v-35q0 -137 158 -217q45 -13 92 -17q169 0 241 178l10 65v13q0 177 -191 242l-66 7q-164 0 -238 -181zM440 889h38q222 0 376 -221q69 -122 69 -238q0 -229 -209 -383q-119 -77 -247 -77h-19q-220 0 -379 218q-69 124 -69 242q0 155 111 303l410 706q45 27 78 27 q75 0 98 -103q0 -42 -95 -192z" />
-<glyph unicode="7" horiz-adv-x="964" d="M679 1252h-535q-103 20 -103 108q22 99 94 99h731q95 -20 95 -90v-19q0 -29 -42 -92l-712 -1260q-42 -28 -72 -28h-6q-99 18 -99 102v15q12 44 649 1165z" />
-<glyph unicode="8" horiz-adv-x="972" d="M477 1469q186 0 315 -164q74 -101 74 -222v-19q0 -163 -118 -270q179 -130 179 -362q0 -230 -210 -385q-119 -77 -248 -77h-19q-221 0 -381 218q-69 125 -69 244q0 240 192 375q-62 48 -93 172q-12 31 -12 85v19q0 206 197 332q98 54 193 54zM295 1066q0 -120 146 -169 l37 -4q127 0 174 136l7 48q0 133 -143 176l-44 4q-123 0 -171 -132zM208 433q0 -177 189 -246q23 -9 72 -9q167 0 240 186l7 51v36q0 142 -167 221q-46 14 -84 14q-182 0 -247 -186z" />
-<glyph unicode="9" horiz-adv-x="972" d="M210 1023v-34q0 -131 148 -213q43 -19 103 -19q144 0 221 137q26 50 26 110v4q0 170 -179 238q-23 9 -64 9h-23q-140 0 -219 -161q-13 -46 -13 -71zM430 548q-239 17 -377 247q-53 109 -53 213q0 255 248 404q108 53 213 53q240 0 393 -229q64 -122 64 -228 q0 -172 -138 -334l-504 -677q-39 -27 -73 -27q-102 20 -102 105q0 45 126 198z" />
-<glyph unicode=":" horiz-adv-x="557" d="M322 982q111 0 154 -129v-37q0 -96 -129 -142h-27q-152 23 -152 157q30 151 154 151zM310 314h16q119 0 150 -139v-23q0 -111 -149 -147q-159 28 -159 162q32 147 142 147z" />
-<glyph unicode=";" horiz-adv-x="557" d="M297 956q111 0 154 -129v-37q0 -96 -129 -142h-27q-152 23 -152 157q30 151 154 151zM321 288q158 0 158 -222v-4q0 -208 -249 -290h-28q-75 16 -75 78v20q19 74 88 74l17 -3q61 33 72 33q3 0 3 -2l21 7q-165 26 -165 155q0 109 125 154h33z" />
-<glyph unicode="&#x37e;" horiz-adv-x="557" d="M297 956q111 0 154 -129v-37q0 -96 -129 -142h-27q-152 23 -152 157q30 151 154 151zM321 288q158 0 158 -222v-4q0 -208 -249 -290h-28q-75 16 -75 78v20q19 74 88 74l17 -3q61 33 72 33q3 0 3 -2l21 7q-165 26 -165 155q0 109 125 154h33z" />
-<glyph unicode="&#x3c;" d="M425 625q23 -10 507 -312q34 -40 34 -79v-4q0 -91 -108 -106q-42 0 -166 85l-539 334q-39 42 -39 83q0 79 128 135q576 371 610 371h12q102 -26 102 -106v-8q0 -76 -140 -143q-5 -7 -401 -250z" />
-<glyph unicode="=" d="M243 863h612q83 0 106 -110q-25 -106 -106 -106h-612q-92 0 -107 116q28 100 107 100zM243 531h611q107 -21 107 -113q-22 -103 -106 -103h-620q-82 0 -98 112q0 80 106 104z" />
-<glyph unicode="&#x3e;" d="M247 1150q38 0 252 -141q430 -265 466 -296q24 -32 24 -65v-8q0 -76 -112 -123q-588 -375 -618 -375h-19q-103 19 -103 106v4q0 77 143 146l390 249q-478 293 -506 322q-27 37 -27 74q21 107 110 107z" />
-<glyph unicode="?" horiz-adv-x="980" d="M527 1463q193 0 349 -169q109 -138 109 -300q0 -203 -183 -362q-162 -89 -162 -258q-15 -103 -108 -103q-99 22 -99 94v30q0 253 261 414q83 82 83 196q0 143 -152 229q-68 21 -109 21q-149 0 -233 -158l-27 -132q-45 -58 -95 -58q-103 22 -103 102q0 219 215 381 q131 73 254 73zM520 228h19q88 0 124 -108v-34q-23 -122 -139 -122q-125 27 -125 128q0 112 121 136z" />
-<glyph unicode="@" horiz-adv-x="2019" d="M568 635v-12q0 -220 222 -332q69 -26 124 -26h32q183 0 302 185q44 86 44 165v16q0 212 -211 325q-73 33 -151 33h-4q-223 0 -336 -233q-22 -72 -22 -121zM1293 174q-133 -125 -347 -125h-32q-295 0 -490 295q-72 143 -72 287q0 323 316 511q135 63 262 63 q328 0 519 -320q59 -132 59 -270v-358q129 0 203 131q37 90 37 199v52q0 312 -262 557q-228 189 -500 189q-402 0 -651 -355q-119 -192 -119 -411v-4q0 -364 300 -608q215 -158 470 -158q215 0 437 134l31 7q110 -22 110 -111q0 -121 -358 -221q-98 -25 -192 -25h-52 q-359 0 -661 272q-305 308 -305 718q0 418 338 734q289 244 632 244h36q430 0 747 -367q219 -280 219 -615q0 -426 -294 -544q-77 -34 -156 -34h-28q-158 0 -193 72l-5 28z" />
-<glyph unicode="A" horiz-adv-x="1191" d="M709 744l-121 317l-117 -317h238zM586 1458q93 0 131 -160q454 -1183 459 -1217v-13q0 -81 -98 -98h-7q-90 0 -123 149l-161 418h-398l-202 -533q-45 -34 -78 -34h-11q-98 18 -98 101v9l130 352q335 872 365 973q48 53 91 53z" />
-<glyph unicode="B" horiz-adv-x="943" d="M72 1467l50 -8h225l15 3q190 0 321 -175q67 -98 67 -213v-11q0 -140 -85 -237q228 -125 228 -400q0 -276 -286 -424q-93 -32 -166 -32h-342q-99 18 -99 102v1287q15 100 72 100v8zM207 1252v-363h109q165 0 210 113q13 33 13 65v11q0 124 -145 170l-75 4h-112zM207 682 v-505h166q199 0 265 110q44 63 44 139v7q0 181 -198 242l-101 7h-176z" />
-<glyph unicode="C" horiz-adv-x="1300" d="M744 1466q233 0 439 -146q22 -42 22 -65v-8q0 -91 -107 -102h-13l-136 70q-126 40 -205 40q-255 0 -440 -233q-93 -156 -93 -304q0 -298 280 -473q123 -64 246 -64h11q157 0 327 106h35q95 -21 95 -98v-11q0 -102 -275 -184q-83 -24 -174 -24h-19q-370 0 -619 342 q-118 199 -118 406q0 389 354 633q190 115 390 115z" />
-<glyph unicode="D" horiz-adv-x="1140" d="M72 1478l52 -11h189l42 4q338 0 585 -292q159 -206 159 -466q0 -359 -315 -604q-201 -139 -424 -139h-261q-99 18 -99 102v1295q15 100 72 100v11zM208 1263v-1085h133q342 0 507 331q43 112 43 215q0 247 -220 432q-134 107 -406 107h-57z" />
-<glyph unicode="E" horiz-adv-x="1031" d="M72 1479l52 -11h737l15 4q95 0 110 -114q-21 -98 -113 -98h-665v-452h424l54 4q76 0 99 -103q0 -73 -86 -109l-82 4h-409v-426h683q79 0 96 -112q-29 -96 -99 -96h-789q-99 18 -99 102v1296q15 100 72 100v11z" />
-<glyph unicode="F" horiz-adv-x="959" d="M72 1479l52 -11h737l15 4q95 0 110 -114q-21 -98 -113 -98h-665v-452h424l54 4q76 0 99 -103q0 -73 -86 -109l-82 4h-409v-506l5 -27q-24 -101 -103 -101h-11q-99 18 -99 102v1296q15 100 72 100v11z" />
-<glyph unicode="G" horiz-adv-x="1250" d="M733 1466q238 0 433 -136q28 -38 28 -71v-4q0 -83 -103 -102q-22 0 -162 66q-82 32 -158 32h-61q-198 0 -381 -193q-118 -162 -118 -332v-15q0 -278 258 -455q134 -75 268 -75h15q132 0 250 64v296h-246q-98 17 -98 102v5q17 100 101 100h352q81 0 98 -100v-421 q0 -111 -61 -140q-199 -117 -389 -117h-22q-370 0 -619 342q-118 195 -118 406q0 376 334 622q206 126 399 126z" />
-<glyph unicode="H" horiz-adv-x="1100" d="M94 1463h18q95 -20 95 -90v-568h652v560q17 98 98 98h14q95 -18 95 -98v-1301q0 -73 -99 -94h-10q-98 18 -98 102v530h-652v-534q0 -81 -98 -98h-7q-83 0 -102 103v1279q12 111 94 111z" />
-<glyph unicode="I" horiz-adv-x="539" d="M160 1479l23 -4h137l18 4q106 -23 106 -110q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10q-18 -99 -102 -99h-183q-99 18 -99 102v7q21 100 95 100h-7v1087h14q-90 0 -102 108v6q0 70 100 99z" />
-<glyph unicode="J" horiz-adv-x="976" d="M846 1469h12q80 0 98 -99v-926q0 -255 -238 -409q-113 -65 -232 -65h-19q-236 0 -394 227q-73 121 -73 254q22 99 95 99h15q102 0 102 -147q5 -70 89 -161q81 -64 177 -64q190 0 260 199q10 35 10 71v926q18 95 98 95z" />
-<glyph unicode="K" horiz-adv-x="1070" d="M122 1464h5q100 -17 100 -98v-581q658 657 674 657l27 4h12q95 -18 95 -98v-12q0 -51 -89 -124l-445 -448l522 -646l4 -33v-13q0 -81 -98 -98h-7q-61 0 -149 129l-423 513l-123 -126v-422q0 -81 -100 -98h-5q-83 0 -102 102v1290q19 102 102 102z" />
-<glyph unicode="L" horiz-adv-x="951" d="M94 1463h18q95 -20 95 -90v-1196h587q87 0 103 -111q-29 -96 -103 -96h-692q-83 0 -102 103v1279q12 111 94 111z" />
-<glyph unicode="M" horiz-adv-x="1490" d="M267 874v-806q0 -81 -98 -98h-7q-83 0 -102 103v1278q12 111 94 111h15q83 0 111 -118l459 -1026q9 35 302 703l188 405q34 36 74 36h15q82 0 94 -111v-1278q-19 -103 -102 -103h-7q-98 17 -98 98v807q-372 -842 -389 -869q-41 -36 -80 -36q-88 0 -145 178z" />
-<glyph unicode="N" horiz-adv-x="1283" d="M998 374v992q18 95 98 95h11q81 0 98 -98v-1288q0 -87 -107 -105q-61 0 -158 144l-733 936v-978q0 -81 -100 -98h-5q-83 0 -102 102v1274q12 111 94 111h15q67 0 108 -88q53 -60 781 -999z" />
-<glyph unicode="O" horiz-adv-x="1536" d="M748 1465q378 0 632 -350q115 -199 115 -401q0 -374 -338 -622q-192 -122 -402 -122h-15q-386 0 -629 358q-111 182 -111 393q0 358 314 602q205 142 434 142zM207 710q0 -259 230 -437q142 -96 303 -96h19q253 0 429 226q100 144 100 315q0 293 -269 464 q-132 76 -271 76q-268 0 -445 -234q-96 -138 -96 -314z" />
-<glyph unicode="P" horiz-adv-x="917" d="M94 1468h346q218 0 371 -224q57 -115 57 -208v-27q0 -203 -183 -350q-125 -86 -245 -86h-232v-505q0 -80 -99 -98h-7q-83 0 -102 103v1283q12 112 94 112zM208 1260v-479h205q170 0 234 163q13 33 13 80q0 148 -154 220q-35 16 -85 16h-213z" />
-<glyph unicode="Q" horiz-adv-x="1553" d="M1206 426q82 135 82 292q0 293 -269 465q-131 75 -271 75q-268 0 -445 -234q-96 -138 -96 -314q0 -259 230 -437q142 -96 303 -96h19q177 0 300 98q-133 145 -156 181v38q18 95 98 95h11q52 0 147 -116zM1348 273q151 -149 151 -194v-7q0 -80 -103 -102q-61 0 -167 130 q-28 21 -29 21q-194 -151 -445 -151h-15q-385 0 -629 358q-111 182 -111 393q0 358 314 602q206 142 434 142q378 0 633 -350q114 -198 114 -401q0 -237 -147 -441z" />
-<glyph unicode="R" horiz-adv-x="934" d="M94 1465h315q218 0 355 -228q45 -89 45 -185v-15q0 -214 -208 -351l-10 -5q332 -573 332 -594v-19q0 -81 -100 -98h-6q-73 0 -140 145l-301 514h-168v-561q0 -81 -100 -98h-6q-83 0 -102 103v1280q12 112 94 112zM208 1261v-425h185q156 0 206 169l3 27v28 q0 123 -140 188q-39 13 -129 13h-125z" />
-<glyph unicode="S" horiz-adv-x="892" d="M451 1467q201 0 337 -185l7 -25v-27q0 -74 -101 -91q-46 0 -125 88q-55 35 -106 35h-23q-108 0 -164 -117q-12 -26 -12 -52v-31q0 -124 150 -180q131 0 287 -126q151 -153 151 -336q0 -225 -193 -368q-118 -82 -261 -82q-232 0 -387 204l-11 43q19 103 104 103 q54 0 123 -88q83 -57 152 -57h34q134 0 217 153q13 49 13 73v38q0 133 -154 217l-195 54q-236 136 -236 356v27q0 218 231 340q87 34 162 34z" />
-<glyph unicode="T" horiz-adv-x="1187" d="M94 1466h936q95 -18 95 -98v-15q0 -82 -111 -94h-348v-1191q0 -81 -100 -98h-5q-83 0 -102 103v1186h-356q-103 20 -103 108q22 99 94 99z" />
-<glyph unicode="U" horiz-adv-x="1168" d="M134 1463h18q95 -20 95 -90v-806q0 -243 135 -323q86 -67 191 -67q202 0 305 208q21 65 21 137v843q17 98 98 98h14q95 -18 95 -98v-881q0 -240 -228 -417q-145 -97 -294 -97h-26q-250 0 -434 244q-84 132 -84 323v815q12 111 94 111z" />
-<glyph unicode="V" horiz-adv-x="1212" d="M585 378l393 1050q45 43 87 43h4q83 0 103 -109l-480 -1295q-22 -97 -105 -97h-3q-92 0 -132 169q-452 1194 -452 1222v8q0 86 108 102q87 0 133 -180z" />
-<glyph unicode="W" horiz-adv-x="1739" d="M850 993l-280 -973q-41 -50 -88 -50h-15q-88 0 -114 167q-324 1105 -353 1227q23 102 95 102h16q89 0 112 -137l254 -885q270 949 292 985q36 37 77 37h11q93 0 116 -159q25 -69 250 -861l282 970q39 50 80 50h18q95 -20 95 -90v-23l-387 -1339q-45 -44 -86 -44h-4 q-97 0 -121 164z" />
-<glyph unicode="X" horiz-adv-x="1271" d="M95 1467h16q62 0 97 -70l400 -510l438 562q32 18 58 18h12q80 0 98 -99v-6q0 -44 -109 -171l-368 -474l466 -597l11 -40v-11q-18 -99 -102 -99h-4q-68 0 -109 86l-391 498l-438 -561q-31 -23 -63 -23h-7q-99 18 -99 102v11q0 36 169 243l308 398q-458 580 -472 610l-6 32 q23 101 95 101z" />
-<glyph unicode="Y" horiz-adv-x="1111" d="M536 897q353 531 372 545q28 21 52 21h23q69 0 94 -98q0 -46 -135 -230l-301 -450v-604q-13 -111 -94 -111h-16q-72 0 -98 86v626q0 5 -154 234l-273 411l-6 35q23 101 95 101h16q69 0 105 -88z" />
-<glyph unicode="Z" horiz-adv-x="1237" d="M94 1467h1021q80 0 98 -99v-6q0 -40 -90 -145l-804 -1039h794q100 -15 100 -102v-7q-18 -99 -102 -99h-1009q-86 0 -102 108q0 41 188 275l703 907h-788q-103 20 -103 108q22 99 94 99z" />
-<glyph unicode="[" horiz-adv-x="779" d="M319 1614l71 -7h290l49 4q98 -34 98 -102v-12q0 -70 -89 -106l-74 4h-201v-1632h265q99 -22 99 -98v-12q0 -93 -112 -106h-361q-107 21 -107 110v1833q9 117 72 117v7z" />
-<glyph unicode="\" horiz-adv-x="691" d="M107 1578h4q99 0 144 -193l511 -1394q-20 -113 -107 -113h-16q-85 0 -133 189q-472 1271 -510 1399q17 112 107 112z" />
-<glyph unicode="]" horiz-adv-x="758" d="M120 1611l65 -4h274l48 4q99 -27 99 -106v-1860q0 -78 -103 -98h-371q-93 0 -106 112v6q0 71 105 103l24 -5h235v1632h-189l-81 -4q-94 31 -94 110q0 76 94 110z" />
-<glyph unicode="^" horiz-adv-x="942" d="M409 1464h21q71 0 138 -131q236 -357 236 -387v-24q0 -82 -112 -98q-70 0 -168 182l-101 150l-200 -309q-48 -23 -77 -23q-78 0 -102 107q0 44 85 168q211 333 240 350z" />
-<glyph unicode="_" horiz-adv-x="958" d="M106 1h887q102 -18 102 -100v-15q-20 -97 -100 -97h-889q-90 0 -105 114q28 98 105 98z" />
-<glyph unicode="`" horiz-adv-x="752" d="M310 1441h15q53 0 130 -93q188 -177 188 -210l5 -23q-23 -106 -107 -106h-8q-58 0 -185 145q-137 118 -137 177v12q0 76 99 98z" />
-<glyph unicode="a" horiz-adv-x="1202" d="M206 519v-11q0 -205 206 -308q64 -24 115 -24h29q170 0 281 171q40 80 40 153v15q0 197 -195 302q-67 30 -140 30h-4q-207 0 -312 -216q-20 -66 -20 -112zM878 84q-122 -114 -322 -114h-29q-276 0 -460 276q-67 134 -67 269q0 302 296 479q126 59 246 59q307 0 486 -300 q55 -123 55 -253v-433q0 -80 -98 -97h-7q-68 0 -101 80v11z" />
-<glyph unicode="b" horiz-adv-x="1201" d="M139 1462h17q95 -21 95 -95v-420q123 118 341 118q211 0 383 -160q164 -172 164 -387q0 -308 -291 -484q-127 -64 -245 -64h-30q-222 0 -412 207q-117 156 -117 367v823q0 74 95 95zM251 529v-19q0 -212 223 -316q58 -17 106 -17h23q206 0 312 222q17 67 17 103v23 q0 211 -226 316q-69 17 -107 17h-15q-206 0 -312 -219q-21 -61 -21 -110z" />
-<glyph unicode="c" horiz-adv-x="1002" d="M543 1056q210 0 384 -160q17 -31 17 -57v-7q-18 -98 -101 -98h-4q-37 0 -136 75q-74 38 -149 38h-22q-199 0 -302 -210q-24 -71 -24 -128q0 -203 211 -309q62 -24 134 -24q118 0 240 103l41 9h15q80 0 97 -98v-6q0 -98 -262 -198q-86 -16 -128 -16h-30q-220 0 -408 206 q-116 163 -116 337q0 265 234 444q149 99 309 99z" />
-<glyph unicode="d" horiz-adv-x="1166" d="M978 1462h18q95 -20 95 -91v-748l4 -128q0 -158 -128 -329q-181 -196 -408 -196h-30q-222 0 -412 207q-117 165 -117 341q0 266 236 447q150 100 312 100q208 0 340 -118v359l-4 65q29 91 94 91zM207 529v-19q0 -212 223 -316q58 -17 106 -17h23q206 0 312 222 q17 67 17 103v23q0 211 -226 316q-69 17 -107 17h-15q-206 0 -312 -219q-21 -61 -21 -110z" />
-<glyph unicode="e" horiz-adv-x="1132" d="M539 1055q313 0 486 -297q60 -117 60 -253v-22q-18 -102 -101 -102h-749q29 -99 163 -171q79 -30 148 -30q80 0 192 56h32q94 -18 94 -98v-11q0 -118 -297 -157h-28q-292 0 -468 273q-71 129 -71 270q0 298 281 474q137 68 258 68zM217 587h655q0 37 -83 149 q-112 106 -220 106h-41q-164 0 -270 -162q-37 -64 -41 -93z" />
-<glyph unicode="f" horiz-adv-x="837" d="M596 1467h94q78 0 94 -108q0 -77 -103 -100h-60q-115 0 -152 -127l-3 -75v-22h132l60 3q73 0 96 -99v-14q0 -72 -95 -95h-193v-719l3 -42q0 -76 -102 -99q-76 0 -109 90l4 51v719h-168q-78 0 -94 108q0 59 85 100l82 -3h91v38q0 274 244 377z" />
-<glyph unicode="g" horiz-adv-x="1145" d="M544 1051q241 0 417 -200q122 -167 122 -317l-4 -126v-449q0 -141 -206 -299q-157 -103 -329 -103q-294 0 -486 262q-38 64 -38 91v11q0 73 94 94h14q71 0 111 -108q122 -153 305 -153q219 0 328 196l6 40v97q-123 -114 -323 -114h-30q-218 0 -405 204q-115 162 -115 335 q0 263 232 440q148 99 307 99zM210 523v-18q0 -208 219 -310q57 -17 104 -17h22q203 0 307 218q16 65 16 101v23q0 207 -221 310q-69 16 -106 16h-14q-203 0 -307 -215q-20 -59 -20 -108z" />
-<glyph unicode="h" horiz-adv-x="1100" d="M142 1460h18q95 -20 95 -90v-396q104 90 280 90q268 0 429 -253q61 -113 61 -215v-528q0 -81 -100 -98h-5q-77 0 -102 94v510q0 184 -191 266q-45 13 -92 13q-189 0 -267 -203q-13 -43 -13 -148v-434q0 -81 -100 -98h-5q-77 0 -102 94v1298q21 98 94 98z" />
-<glyph unicode="i" horiz-adv-x="431" d="M211 1316q99 -25 99 -94v-22q0 -79 -107 -94q-77 0 -101 105q21 105 109 105zM211 1060q99 -25 99 -94v-898q0 -81 -100 -98h-6q-82 0 -101 102v874q12 114 108 114z" />
-<glyph unicode="j" horiz-adv-x="656" d="M104 -438q-89 0 -104 109q0 83 109 99q188 0 249 186l8 106v894q0 84 105 100q99 -19 99 -100v-928q0 -295 -280 -431q-90 -32 -167 -35h-19zM465 1308q105 -21 105 -105q0 -88 -110 -105q-94 27 -94 94v22q0 68 99 94z" />
-<glyph unicode="k" horiz-adv-x="1056" d="M410 518l-125 -80v-370q0 -81 -100 -98h-6q-77 0 -102 94v1302q21 99 94 99h18q96 -21 96 -91v-690q489 324 586 379h27q86 0 102 -107q0 -66 -136 -138l-276 -189l406 -514l6 -33v-9q-18 -99 -102 -99h-7q-60 0 -157 140z" />
-<glyph unicode="l" horiz-adv-x="473" d="M159 1457h18q95 -20 95 -90v-1190h49q73 0 94 -99v-8q-17 -100 -102 -100h-146q-83 0 -102 102v1275q12 110 94 110z" />
-<glyph unicode="m" horiz-adv-x="1725" d="M171 1036q75 0 96 -66q81 66 235 66q204 0 329 -152q43 80 241 140l88 12q249 0 392 -236q48 -99 48 -190v-548q0 -73 -97 -92h-9q-97 17 -97 100v532q0 160 -168 221l-46 6h-35q-133 0 -204 -156q-9 -33 -9 -56v-547q-18 -100 -99 -100h-7q-97 17 -97 96v452 q0 175 -43 215q-72 96 -184 96h-11q-154 0 -217 -166q-10 -40 -10 -109v-488q0 -79 -97 -96h-6q-81 0 -100 100v853q11 113 107 113z" />
-<glyph unicode="n" horiz-adv-x="1197" d="M187 1053q97 -25 97 -94v-15q120 109 324 109q224 0 397 -186q126 -156 126 -329v-475q0 -74 -98 -93h-10q-98 18 -98 101v418q0 260 -221 341q-54 14 -96 14h-11q-185 0 -287 -193q-26 -57 -26 -192v-392q0 -80 -98 -97h-7q-82 0 -101 102v867q12 114 109 114z" />
-<glyph unicode="o" horiz-adv-x="1111" d="M539 1048q209 0 378 -158q161 -169 161 -381q0 -303 -286 -476q-125 -63 -242 -63h-30q-218 0 -405 204q-115 162 -115 335q0 263 232 440q148 99 307 99zM209 520v-18q0 -187 181 -290q64 -33 138 -33h22q193 0 296 201q23 62 23 122v18q0 155 -143 262q-83 57 -191 57 q-211 0 -310 -222q-16 -52 -16 -97z" />
-<glyph unicode="p" horiz-adv-x="1172" d="M595 1050q209 0 377 -157q161 -169 161 -380q0 -302 -285 -474q-125 -63 -241 -63h-30q-188 0 -314 114v-443q0 -71 -101 -93q-80 0 -103 101v825q0 405 383 546q49 16 153 24zM267 524v-19q0 -185 180 -288q64 -33 138 -33h22q193 0 295 200q23 62 23 121v19 q0 154 -142 261q-84 57 -191 57q-210 0 -308 -222q-17 -53 -17 -96z" />
-<glyph unicode="q" horiz-adv-x="1153" d="M555 1040q207 0 375 -155q160 -156 160 -413v-821q-23 -101 -103 -101q-101 22 -101 93v440q-122 -113 -320 -113h-29q-217 0 -403 203q-114 161 -114 332q0 261 230 437q148 98 305 98zM227 516v-18q0 -185 180 -287q63 -33 137 -33h22q192 0 294 199q23 62 23 121v18 q0 153 -143 260q-82 57 -189 57q-209 0 -307 -221q-17 -52 -17 -96z" />
-<glyph unicode="r" horiz-adv-x="925" d="M208 1061q98 -25 98 -94v-16q124 110 323 110q107 0 232 -54q43 -44 43 -85v-7q-17 -98 -101 -98h-9q-103 33 -150 33h-22q-202 0 -296 -210q-20 -55 -20 -128v-444q0 -81 -100 -98h-6q-82 0 -101 102v874q12 115 109 115z" />
-<glyph unicode="s" horiz-adv-x="968" d="M704 327q-1 20 -41 24q-506 113 -540 144q-103 78 -103 193q0 156 218 296q120 63 237 63q274 0 433 -253l4 -37v-6q0 -85 -102 -100q-68 0 -126 96q-91 89 -209 89q-154 0 -241 -144l-2 -10q0 -20 86 -27q430 -104 475 -121q123 -81 123 -205v-3q0 -171 -242 -309 q-105 -47 -221 -47q-240 0 -405 224q-21 30 -21 58v22q0 81 110 93q53 0 125 -103q88 -82 206 -82q140 0 232 131z" />
-<glyph unicode="t" horiz-adv-x="691" d="M287 1420h17q93 -20 93 -89v-300h119l33 4q77 0 101 -100q0 -75 -88 -107l-60 4h-105v-509q0 -120 68 -143l79 -7h40q73 0 92 -97v-9q-17 -97 -100 -97h-77q-194 0 -288 210q-17 53 -17 121v531h-42l-64 -4q-88 31 -88 106q17 97 66 97v7l69 -7h59v280q12 109 93 109z " />
-<glyph unicode="u" horiz-adv-x="1188" d="M921 80q-141 -110 -311 -110h-26q-248 0 -430 242q-84 131 -84 320v411q12 114 109 114q97 -25 97 -94v-401q0 -240 133 -320q86 -66 190 -66q199 0 301 206q21 67 21 135v438q20 102 108 102q98 -22 98 -101v-892q0 -75 -98 -94h-10q-98 18 -98 101v9z" />
-<glyph unicode="v" horiz-adv-x="1103" d="M98 1059h7q80 0 130 -142l294 -604q325 690 352 719q36 27 72 27q102 -19 102 -101v-4q0 -26 -168 -374l-281 -577q-44 -33 -77 -33h-3q-85 0 -141 162q-363 741 -385 806v26q18 95 98 95z" />
-<glyph unicode="w" horiz-adv-x="1382" d="M658 600l-188 -581q-37 -49 -86 -49h-3q-74 0 -103 87l-278 876q21 106 105 106q93 0 124 -171l153 -468q183 580 201 604q35 30 76 35q93 0 119 -145l160 -494q174 550 194 593q43 46 87 46q101 -20 101 -109l-295 -918q-45 -42 -85 -42h-3q-93 0 -125 166z" />
-<glyph unicode="x" horiz-adv-x="930" d="M450 662q52 61 279 346q21 20 70 29q99 -24 99 -93v-22q0 -34 -139 -196l-180 -227q319 -382 319 -411v-22q0 -79 -98 -96h-5q-60 0 -121 96l-224 275q-273 -341 -293 -355q-26 -16 -53 -16h-3q-85 0 -100 105q0 42 147 208l171 220l-309 387l-10 43q21 103 104 103 q61 0 138 -118q164 -196 208 -256z" />
-<glyph unicode="y" horiz-adv-x="926" d="M455 383q249 607 269 630q35 29 73 29q96 -18 96 -96v-6q-4 -31 -347 -849q-163 -405 -188 -437q-25 -19 -65 -30q-101 22 -101 91v17q0 19 155 393l-330 805v12q19 96 100 96t129 -158z" />
-<glyph unicode="z" horiz-adv-x="980" d="M66 1045l69 -7h635l39 5q93 -29 93 -94v-22q0 -35 -92 -135l-493 -618h492q93 -18 93 -96v-12q0 -79 -97 -96h-705q-85 0 -100 106q0 42 158 224l427 538h-432l-64 -4q-89 31 -89 107q17 97 66 97v7z" />
-<glyph unicode="{" d="M712 1620h141q90 0 114 -87v-27q0 -72 -95 -94h-148q-42 0 -42 -46v-579q0 -56 -39 -118q42 -47 42 -133v-586q0 -31 43 -31h144q95 -20 95 -98v-15q0 -74 -99 -95h-152q-172 0 -235 191l-4 55v575q0 26 -26 31h-84q-103 20 -103 109q22 100 95 100h61q53 0 53 23v574 q0 188 192 247z" />
-<glyph unicode="|" d="M534 1649h11q96 -18 96 -99v-1908q0 -72 -104 -95q-86 0 -106 108v1890q18 104 103 104z" />
-<glyph unicode="}" d="M207 1608h154q162 0 228 -180l4 -39v-582q0 -34 56 -34h65q85 -26 85 -97v-15q0 -75 -98 -94h-82q-30 0 -30 -64v-554q0 -147 -180 -217l-50 -4h-154q-99 15 -99 101v7q17 98 97 98h139q41 0 41 30v562q0 96 42 147q-38 55 -38 119v580q0 30 -41 30h-143q-80 0 -97 101 q15 105 101 105z" />
-<glyph unicode="~" d="M403 881h24q101 0 225 -83l29 -8h16l98 30q128 -25 128 -127q0 -123 -210 -150h-36q-100 0 -223 84l-30 7h-17l-91 -24h-17q-113 22 -113 117v14q0 96 127 125q42 15 90 15z" />
-<glyph unicode="&#xa1;" horiz-adv-x="672" d="M330 1357h14q83 0 116 -84l8 -33q0 -115 -129 -132q-103 0 -123 129q26 120 114 120zM338 1095h9q93 -16 93 -96v-931q-14 -94 -96 -94h-9q-91 17 -91 93v935q0 77 94 93z" />
-<glyph unicode="&#xa2;" horiz-adv-x="1105" d="M529 825q-164 -19 -255 -202q-23 -70 -23 -124q0 -128 87 -220zM802 1417h14q93 -17 93 -96v-16l-110 -322q172 -79 172 -163v-6q-17 -97 -99 -97h-4q-37 0 -132 74l-4 1l-214 -615q9 -3 68 -3q115 0 235 99l39 11h15q79 0 96 -97v-7q0 -95 -256 -193q-84 -16 -125 -16 h-29q-53 0 -112 16q-88 -269 -119 -291l-60 -22q-105 24 -105 104q0 19 100 296q-217 162 -217 428q0 287 275 465q136 66 261 66l18 -1q113 341 134 356q31 29 66 29z" />
-<glyph unicode="&#xa3;" horiz-adv-x="946" d="M227 804q-94 180 -94 290q0 249 262 384q83 25 123 25h39q197 0 338 -188l6 -40q-25 -106 -108 -106q-49 0 -121 81q-56 42 -115 42h-23q-132 0 -186 -157l-4 -45q0 -69 126 -286h218q104 -20 104 -110q-23 -101 -96 -101h-170l-1 5v-52q0 -133 -111 -353l-1 -3h345 q-4 0 -4 6q0 15 21 62q45 44 90 44q105 -22 105 -108q0 -35 -80 -181q-40 -34 -78 -34h-568q-84 0 -103 104q0 28 152 358q22 63 22 116l-2 36h-134q-100 19 -100 107q20 104 107 104h41z" />
-<glyph unicode="&#xa4;" d="M442 715q0 -79 91 -110h23q85 0 106 97v22q-23 97 -99 97l-9 3q-112 -18 -112 -109zM689 423q-61 -30 -141 -30q-59 0 -131 30q-60 -74 -117 -74h-11q-99 19 -99 102v12q0 56 72 116q-28 56 -28 120v20q0 76 28 132q-72 59 -72 112v25q28 89 94 89h20q49 0 114 -72 q50 28 118 28h24q81 0 129 -28q62 72 107 72h33q89 -28 89 -102v-8q0 -51 -73 -118q29 -56 29 -134q0 -69 -30 -139q74 -59 74 -113v-21q-29 -93 -98 -93h-20q-38 0 -111 74z" />
-<glyph unicode="&#xa5;" horiz-adv-x="1262" d="M538 445h-326l-36 -4q-106 22 -106 104q0 85 104 104h239q-57 87 -57 100q0 2 2 2h-196q-92 26 -92 100q0 92 114 103h27q-68 107 -67 107q-74 32 -74 103q0 73 101 96h172q86 0 104 -104q0 -73 -53 -88l250 -378q259 376 276 376q1 0 1 -2h18q-63 38 -63 85v22 q27 89 104 89h144q87 0 103 -105q0 -51 -67 -94l-72 -107h18q114 -11 114 -100v-7q0 -78 -97 -96h-175l-67 -102h235q104 -20 104 -100v-4q0 -86 -74 -96v-12l-68 8h-322v-379q0 -73 -101 -96h-6q-83 0 -115 84l4 69v322z" />
-<glyph unicode="&#xa6;" horiz-adv-x="770" d="M389 1645h11q96 -18 96 -99v-681q0 -81 -100 -99h-7q-84 0 -103 104v671q18 104 103 104zM397 426q99 -26 99 -95v-693q0 -72 -104 -95q-86 0 -106 108v659q12 116 111 116z" />
-<glyph unicode="&#xa7;" d="M541 1470h35q179 0 319 -168l6 -36q-14 -93 -84 -93h-19q-32 0 -113 76q-57 37 -124 37q-159 0 -211 -176v-42q0 -135 153 -200q195 -30 250 -90q133 -118 133 -254v-50q0 -130 -118 -232q145 -110 145 -304q0 -221 -210 -348q-94 -47 -181 -47h-12q-196 0 -334 172 l-6 35q0 80 98 94q39 0 107 -69q66 -48 135 -48q142 0 204 150l11 60q0 157 -179 216q-124 15 -180 51q-181 122 -181 293v19q0 174 119 255q-142 112 -142 297v15q0 222 214 344q83 43 165 43zM373 518v-13q0 -111 125 -154l34 -3h21q102 0 146 125l3 34q0 118 -139 158 l-35 4q-107 0 -152 -121z" />
-<glyph unicode="&#xa8;" horiz-adv-x="1024" d="M326 1339q106 -25 106 -113q-21 -107 -113 -107q-107 21 -107 114q25 106 114 106zM778 1339q106 -25 106 -113q-21 -107 -113 -107q-107 21 -107 114q25 106 114 106z" />
-<glyph unicode="&#xa9;" horiz-adv-x="1674" d="M833 1441q361 0 599 -324q120 -183 120 -399q0 -386 -358 -621q-171 -98 -369 -98q-325 0 -561 279q-154 206 -154 440q0 352 309 591q196 132 414 132zM219 729v-18q0 -324 309 -528q157 -79 305 -79q314 0 516 283q98 158 98 335q0 318 -294 523q-157 87 -301 87h-38 q-281 0 -482 -256q-113 -163 -113 -347zM844 1230q189 0 350 -143q15 -20 15 -41v-8q0 -64 -79 -71h-3q-15 0 -125 79q-95 37 -165 37q-227 0 -343 -233q-23 -65 -23 -124v-27q0 -183 185 -305q95 -49 181 -49q134 0 267 110l30 7q75 -10 75 -71v-8q0 -72 -218 -162 q-96 -22 -154 -22q-298 0 -463 289q-53 116 -53 230q0 267 248 437q123 75 275 75z" />
-<glyph unicode="&#xaa;" horiz-adv-x="648" d="M318 1427h33q169 0 257 -188l17 -84l-4 -67v-137l5 -27q-13 -48 -53 -65h-18q-39 0 -66 46v-8q-45 -38 -142 -38h-8q-206 0 -276 216q-10 24 -10 70q0 197 219 277zM189 1136q0 -106 130 -141h28q96 0 139 117l3 34q0 97 -110 142l-42 7q-99 0 -144 -113z" />
-<glyph unicode="&#xab;" horiz-adv-x="944" d="M661 492q184 -215 201 -249v-30q-13 -67 -70 -67h-4q-47 0 -128 115q-170 193 -170 227v30q213 269 269 314l42 7q61 -32 61 -75v-4q0 -32 -201 -268zM545 842q69 -22 69 -62v-20q0 -31 -191 -255l-8 -12q203 -232 203 -272q-13 -71 -70 -71h-30q-46 34 -270 313l-6 30 q0 36 127 182q128 163 151 163l4 4h21z" />
-<glyph unicode="&#xac;" d="M177 782h715q99 -19 99 -102v-348q0 -78 -103 -98h-10q-103 19 -103 106v226h-589q-107 21 -107 113q23 103 98 103z" />
-<glyph unicode="&#xae;" horiz-adv-x="1674" d="M828 1446q364 0 604 -325q121 -184 121 -400q0 -387 -360 -623q-173 -98 -372 -98q-328 0 -565 279q-156 208 -156 442q0 353 311 593q198 132 417 132zM210 732v-18q0 -325 311 -529q158 -79 307 -79q317 0 520 283q99 159 99 336q0 319 -296 525q-158 87 -304 87h-38 q-283 0 -485 -257q-114 -164 -114 -348zM616 1216h186q205 0 269 -208q8 -21 8 -64q0 -149 -156 -234q225 -388 235 -416v-7q-16 -45 -45 -45h-15q-34 0 -80 98l-201 347h-148v-396q-7 -49 -42 -49h-26q-34 19 -34 45v876q8 53 49 53zM669 1114v-329h95q160 0 197 98 q15 35 15 72q0 106 -121 151q-17 8 -49 8h-137z" />
-<glyph unicode="&#xaf;" horiz-adv-x="806" d="M18 1806h847q97 -18 97 -100v-15q-18 -97 -97 -97h-847q-86 0 -100 114q27 98 100 98z" />
-<glyph unicode="&#xb0;" horiz-adv-x="674" d="M370 1311q-62 0 -106 -44t-44 -106t43.5 -105t106.5 -43t105.5 42.5t42.5 105.5t-43.5 106.5t-104.5 43.5zM369 1472q127 0 217 -90.5t90 -217.5q0 -126 -91 -217t-218 -91q-130 0 -218.5 90t-88.5 218t90.5 218t218.5 90z" />
-<glyph unicode="&#xb1;" d="M543 1218h24q64 0 99 -94l-5 -45v-161h196q108 -17 108 -106v-8q0 -79 -100 -107l-32 5h-172v-157l4 -44q0 -79 -107 -103q-79 0 -113 94l4 53v157h-172l-27 -5q-105 27 -105 107v8q0 86 107 106h197v160l-5 41q31 99 99 99zM239 398l53 -4h533l40 4q100 -27 100 -106v-8 q0 -71 -89 -106l-74 4h-494l-69 -4q-94 31 -94 106v8q0 71 94 106z" />
-<glyph unicode="&#xb2;" d="M536 1567q109 0 190 -98q43 -65 43 -134q0 -106 -98 -198l-153 -174h198q51 0 62 -60v-7q-9 -62 -64 -62h-346q-60 11 -60 64v2q0 29 41 68l272 311q17 23 17 56q0 69 -73 97q-11 3 -26 3h-5q-66 0 -95 -70q-4 -16 -7 -45q-22 -47 -61 -47h-6q-61 11 -61 62 q0 122 116 199q61 33 116 33z" />
-<glyph unicode="&#xb3;" d="M532 1573q95 0 163 -84q38 -52 38 -115v-7q0 -87 -46 -129q75 -54 75 -172q0 -122 -114 -201q-60 -34 -119 -34h-5q-138 0 -215 142q-18 53 -18 94q0 49 65 63q56 0 65 -64q0 -61 64 -97q22 -8 44 -8q62 0 94 66q7 19 7 32v14q0 57 -64 90l-62 13q-35 27 -35 58v2 q0 64 78 64q21 0 48 33q10 21 10 40q0 40 -41 63q-14 7 -33 7q-46 0 -66 -49q-8 -75 -28 -75q-12 -14 -42 -14q-63 14 -63 60v9q0 111 110 175q42 22 90 24z" />
-<glyph unicode="&#xb4;" horiz-adv-x="889" d="M546 1444q94 0 110 -116q0 -55 -192 -227q-76 -93 -130 -93h-15q-99 19 -99 102v16q0 47 149 181q120 137 177 137z" />
-<glyph unicode="&#xb5;" horiz-adv-x="1180" d="M966 77q-141 -110 -310 -110h-26q-187 0 -306 108v-440q0 -71 -101 -93q-84 0 -104 105v1289q12 113 109 113q96 -25 96 -93v-399q0 -240 133 -318q85 -66 188 -66q199 0 300 205q21 66 21 134v436q20 101 107 101q98 -22 98 -101v-887q0 -73 -98 -94h-9q-98 18 -98 101 v9z" />
-<glyph unicode="&#xb6;" horiz-adv-x="1024" d="M433 1465h465q95 -21 95 -91v-19q0 -81 -83 -98v-1184q-19 -103 -102 -103h-6q-100 17 -100 98v1189h-80v-1187q-17 -100 -102 -100h-7q-99 18 -99 102v644q-184 0 -307 212q-37 83 -37 166q0 219 220 337q69 34 143 34z" />
-<glyph unicode="&#xb7;" horiz-adv-x="508" d="M305 776q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9z" />
-<glyph unicode="&#x2219;" horiz-adv-x="508" d="M305 776q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9z" />
-<glyph unicode="&#xb8;" horiz-adv-x="1024" d="M578 68q96 -19 96 -90v-40q104 -69 104 -186q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82v111q0 78 100 97z" />
-<glyph unicode="&#xb9;" d="M561 1594h12q59 -13 59 -61v-614q-11 -61 -64 -61h-4q-61 13 -61 60v522q-13 -4 -33 -4q-45 0 -60 58v13q0 50 95 70z" />
-<glyph unicode="&#xba;" horiz-adv-x="718" d="M400 1573q126 0 192 -134q33 -102 33 -188v-38q0 -106 -44 -215q-70 -108 -177 -108h-6q-116 0 -182 122q-39 99 -39 218v5q0 125 46 230q72 108 177 108zM296 1239v-17q0 -107 36 -174q29 -36 65 -36h5q84 0 99 145q5 26 7 77q0 89 -30 168q-31 48 -76 48q-56 0 -83 -63 q-23 -76 -23 -148z" />
-<glyph unicode="&#xbb;" horiz-adv-x="944" d="M282 829q48 0 150 -139q151 -169 151 -207q0 -33 -210 -278q-47 -68 -88 -68h-7q-71 13 -71 74q0 36 115 167l88 108q-183 213 -199 246v27q0 57 71 70zM658 485q-203 234 -203 273q16 75 74 75q46 0 131 -119q167 -188 167 -223v-30q-203 -260 -275 -320h-46 q-35 16 -51 51v27q0 36 203 266z" />
-<glyph unicode="&#xbc;" horiz-adv-x="1470" d="M1215 1472h12q81 0 98 -100v-6q0 -45 -131 -198q-96 -133 -906 -1176q-37 -22 -74 -22q-94 26 -94 95v23q0 34 151 220q814 1061 881 1141q31 23 63 23zM345 1464q45 0 78 -57l-3 -65v-652l3 -39q-21 -68 -75 -68q-44 0 -72 53v654l-32 -7h-29q-53 28 -53 71q0 74 110 91 q0 3 73 19zM1109 563l-150 -198h150v198zM1185 859q49 0 75 -63l-3 -44v-387h57q61 0 73 -84q-27 -64 -77 -64h-53v-195q-31 -52 -75 -52q-73 14 -73 76v171h-311q-65 14 -65 68v29q341 439 389 510q24 35 63 35z" />
-<glyph unicode="&#xbd;" horiz-adv-x="1492" d="M1202 1467h11q81 0 98 -100v-6q0 -45 -131 -197q-95 -132 -902 -1172q-37 -22 -74 -22q-94 26 -94 94v23q0 34 150 220q812 1057 879 1137q31 23 63 23zM334 1459q45 0 80 -56l-5 -66v-649l5 -39q-23 -69 -77 -69q-43 0 -72 53v652l-31 -7h-29q-53 28 -53 72q0 73 110 90 q0 3 72 19zM1105 845q194 0 275 -209l3 -44v-42q0 -111 -163 -268l-143 -165h227l20 5q71 -23 71 -61v-22q-14 -65 -68 -65h-417q-58 0 -72 72q0 30 190 236q204 227 204 247l4 27v29q-26 113 -125 113q-88 0 -126 -97q0 -79 -59 -100h-20q-47 0 -72 62q0 186 197 270z" />
-<glyph unicode="&#xbe;" horiz-adv-x="1541" d="M396 1468q144 0 216 -146q18 -42 18 -77v-22q0 -96 -58 -151q92 -64 92 -208q0 -198 -220 -271l-58 -4h-8q-187 0 -264 220l-4 58q0 38 52 69h27q67 0 75 -107q35 -93 117 -93h12q90 0 122 108l3 26q0 86 -104 123q-93 0 -93 83q16 67 91 67q52 0 72 80v22q0 50 -74 76 h-17q-63 0 -87 -73v-36q-28 -53 -68 -53h-14q-65 12 -65 67v8q0 164 186 230zM1298 1460h12q80 0 98 -99v-6q0 -45 -131 -197q-95 -132 -898 -1166q-37 -22 -73 -22q-94 26 -94 94v23q0 34 149 219q808 1052 875 1131q31 23 62 23zM1193 557l-148 -195h148v195zM1268 853 q49 0 75 -63l-3 -44v-384h56q61 0 73 -83q-27 -64 -76 -64h-53v-193q-31 -52 -75 -52q-72 14 -72 75v170h-309q-65 14 -65 68v29q339 435 386 505q25 36 63 36z" />
-<glyph unicode="&#xbf;" horiz-adv-x="977" d="M471 1110h11q107 0 128 -135q-23 -128 -132 -128h-4q-109 0 -131 125v9q24 129 128 129zM474 805q102 -18 102 -102v-7q0 -273 -257 -424q-86 -82 -86 -198q0 -148 155 -228q58 -21 101 -21q146 0 227 147q18 30 31 140q50 60 101 60q101 -24 101 -102q0 -225 -221 -383 q-123 -69 -239 -69q-229 0 -378 197q-85 120 -85 266q0 261 257 416q90 81 90 246q46 62 101 62z" />
-<glyph unicode="&#xc0;" horiz-adv-x="1220" d="M507 1836h7q62 0 156 -136q67 -71 67 -116q-18 -103 -101 -103h-16q-52 0 -162 153q-53 45 -53 108q26 94 102 94zM715 749l-123 320l-118 -320h241zM590 1468q93 0 131 -161q458 -1191 463 -1226v-13q0 -81 -100 -98h-6q-90 0 -123 150l-163 421h-400l-205 -537 q-45 -34 -78 -34h-10q-99 18 -99 102v9l131 354q338 878 368 980q48 53 91 53z" />
-<glyph unicode="&#xc1;" horiz-adv-x="1212" d="M652 1828h6q99 -19 99 -94v-15q0 -44 -85 -136q-73 -109 -133 -109h-12q-80 0 -97 100v6q0 49 122 184q41 64 100 64zM711 746l-121 317l-118 -317h239zM588 1462q92 0 130 -161q456 -1186 461 -1220v-13q0 -81 -100 -98h-5q-91 0 -124 149l-161 420h-399l-203 -535 q-45 -34 -78 -34h-10q-99 18 -99 102v8l130 353q337 874 367 976q46 53 91 53z" />
-<glyph unicode="&#xc2;" horiz-adv-x="1212" d="M593 1550q-71 -93 -122 -93h-11q-83 0 -102 102q0 47 123 187q44 65 99 65h30q51 0 148 -132q67 -71 67 -117v-5q-15 -100 -102 -100h-7q-56 0 -123 93zM711 746l-121 317l-118 -317h239zM588 1462q92 0 130 -161q456 -1186 461 -1220v-13q0 -81 -100 -98h-5 q-91 0 -124 149l-161 420h-399l-203 -535q-45 -34 -78 -34h-10q-99 18 -99 102v8l130 353q337 874 367 976q46 53 91 53z" />
-<glyph unicode="&#xc3;" horiz-adv-x="1216" d="M479 1765q91 0 202 -72l20 -2l75 22h13q100 -17 100 -102v-4q0 -96 -150 -120l-40 -4q-91 0 -194 73l-17 2l-84 -23q-106 20 -106 102v8q0 99 164 117zM711 746l-121 317l-118 -317h239zM588 1462q92 0 130 -161q456 -1186 461 -1220v-13q0 -81 -100 -98h-5 q-91 0 -124 149l-161 420h-399l-203 -535q-45 -34 -78 -34h-10q-99 18 -99 102v8l130 353q337 874 367 976q46 53 91 53z" />
-<glyph unicode="&#xc4;" horiz-adv-x="1225" d="M438 1744h17q95 -21 95 -94v-11q0 -86 -107 -102q-100 19 -100 102v11q0 73 95 94zM727 1744h15q79 0 94 -107q0 -77 -104 -101q-103 19 -103 99v24q27 85 98 85zM711 746l-121 317l-118 -317h239zM588 1462q92 0 130 -161q456 -1186 461 -1220v-13q0 -81 -100 -98h-5 q-91 0 -124 149l-161 420h-399l-203 -535q-45 -34 -78 -34h-10q-99 18 -99 102v8l130 353q337 874 367 976q46 53 91 53z" />
-<glyph unicode="&#xc5;" horiz-adv-x="1219" d="M581 1862h15q127 0 182 -152l4 -39v-11q0 -124 -145 -182l-45 -8q-120 0 -182 117q-20 42 -20 83q0 132 153 188zM531 1666q10 -55 53 -55q58 9 58 51v10q-8 49 -45 49h-16q-41 0 -50 -55zM713 748l-122 319l-118 -319h240zM589 1466q93 0 131 -161q457 -1190 462 -1224 v-13q0 -81 -100 -98h-6q-90 0 -123 149l-162 421h-400l-204 -536q-45 -34 -78 -34h-10q-99 18 -99 102v9l130 353q338 877 368 979q48 53 91 53z" />
-<glyph unicode="&#xc6;" horiz-adv-x="1565" d="M810 1465h595q69 0 95 -101q-21 -106 -107 -106h-470v-508h363q96 -21 96 -91v-19q0 -81 -100 -98h-359v-364h474q83 0 102 -103q0 -83 -103 -105h-578q-83 0 -102 103v469h-233q-9 -11 -154 -281l-147 -257q-39 -34 -76 -34h-4q-86 0 -102 108q0 32 246 463l496 891 q40 33 68 33zM600 750h116v207z" />
-<glyph unicode="&#xc7;" horiz-adv-x="1399" d="M743 1462q233 0 425 -142q28 -37 28 -73q-18 -101 -104 -101q-25 0 -146 66q-112 41 -203 41q-249 0 -430 -228q-92 -152 -92 -298q0 -291 274 -463q120 -63 241 -63h11q153 0 312 98l26 6h14q97 -17 97 -100v-4q0 -116 -318 -197l-42 -4v-31q112 -74 112 -198 q0 -180 -210 -230l-55 4h-53l-65 -4q-89 29 -89 93v18q18 94 97 94h130q40 0 40 25v4q0 17 -46 26q-65 31 -65 85v114q-125 12 -302 120q-317 246 -317 607q0 382 348 622q186 113 382 113z" />
-<glyph unicode="&#xc8;" horiz-adv-x="1039" d="M72 1473l52 -11h733l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-785q-99 18 -99 102v1290q15 100 72 100v11zM385 1859h8q61 0 155 -136q67 -71 67 -116 q-18 -103 -101 -103h-15q-54 0 -162 153q-54 45 -54 108q28 94 102 94z" />
-<glyph unicode="&#xc9;" d="M72 1473l52 -11h733l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-785q-99 18 -99 102v1290q15 100 72 100v11zM506 1859h7q102 -20 102 -106q0 -44 -96 -151 q-69 -98 -119 -98h-22q-79 0 -95 108q0 40 124 182q44 65 99 65z" />
-<glyph unicode="&#xca;" d="M72 1473l52 -11h733l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-785q-99 18 -99 102v1290q15 100 72 100v11zM488 1837h22q61 0 140 -113q83 -91 83 -128v-18 q-20 -95 -91 -95h-26q-47 0 -116 92q-63 -92 -115 -92h-26q-71 0 -91 95v18q0 44 174 231z" />
-<glyph unicode="&#xcb;" horiz-adv-x="1027" d="M72 1473l52 -11h733l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-785q-99 18 -99 102v1290q15 100 72 100v11zM333 1734h17q95 -21 95 -94v-11q0 -86 -106 -102 q-101 19 -101 102v11q0 73 95 94zM623 1734h15q79 0 95 -107q0 -77 -105 -101q-103 18 -103 99v24q27 85 98 85z" />
-<glyph unicode="&#xcc;" horiz-adv-x="657" d="M246 1848q63 0 147 -120q78 -84 78 -135q-20 -102 -105 -102q-61 0 -130 102q-92 104 -92 139v22q0 75 102 94zM211 1462l22 -5h133l18 5q106 -24 106 -110q-18 -102 -102 -102h15v-1073h-7q73 0 94 -99v-9q-18 -99 -102 -99h-179q-99 18 -99 102v6q21 99 94 99h-7v1073 h15q-90 0 -102 107v6q0 68 101 99z" />
-<glyph unicode="&#xcd;" horiz-adv-x="657" d="M404 1858h7q102 -20 102 -106q0 -44 -96 -151q-69 -98 -119 -98h-22q-79 0 -94 108q0 40 123 182q44 65 99 65zM241 1466l23 -5h132l18 5q107 -23 107 -109q-18 -103 -102 -103h15v-1077h-7q73 0 94 -98v-10q-18 -99 -102 -99h-180q-99 18 -99 102v7q21 98 94 98h-7v1077 h15q-90 0 -102 107v6q0 70 101 99z" />
-<glyph unicode="&#xce;" horiz-adv-x="657" d="M246 1467l23 -5h133l18 5q106 -24 106 -110q-18 -103 -101 -103h15v-1077h-8q75 0 94 -98v-9q-17 -100 -101 -100h-181q-99 18 -99 102v7q21 98 95 98h-8v1077h15q-90 0 -102 108v6q0 68 101 99zM334 1573q-64 -95 -125 -95h-9q-100 17 -100 102v4q0 47 119 181 q48 68 96 68h30q64 0 159 -139q64 -66 64 -113q-18 -103 -102 -103h-7q-59 0 -125 95z" />
-<glyph unicode="&#xcf;" horiz-adv-x="657" d="M174 1713h18q95 -20 95 -90v-19q0 -80 -102 -99q-105 21 -105 110q22 98 94 98zM461 1713h17q95 -21 95 -94v-11q0 -86 -106 -102q-101 19 -101 102v11q0 73 95 94zM241 1462l23 -5h132l18 5q106 -23 106 -110q-18 -102 -101 -102h15v-1073h-8q75 0 94 -99v-8 q-17 -100 -101 -100h-180q-99 18 -99 102v6q21 99 94 99h-7v1073h15q-90 0 -102 107v6q0 68 101 99z" />
-<glyph unicode="&#xd0;" horiz-adv-x="1275" d="M500 1460q346 0 593 -301q149 -204 149 -448q0 -389 -364 -639q-188 -102 -374 -102h-252q-76 0 -101 94v561h-56q-95 21 -95 98v15q0 73 99 94h52v526q21 99 94 99h221zM357 1254v-422h256q98 -18 98 -98v-14q-18 -95 -98 -95h-256v-448h125q345 0 503 314 q50 107 50 224q0 290 -272 468q-113 71 -364 71h-42z" />
-<glyph unicode="&#xd1;" horiz-adv-x="1288" d="M480 1731q91 0 203 -73l21 -2l69 22h19q100 -15 100 -102v-4q0 -96 -151 -120l-40 -4q-91 0 -194 73l-18 2l-84 -23q-106 20 -106 103v7q0 99 164 117zM1002 370v997q18 95 98 95h11q81 0 98 -98v-1295q-18 -99 -102 -99h-4q-68 0 -142 119l-754 962v-983q0 -81 -98 -98 h-7q-77 0 -102 94v1300q21 98 94 98h15q65 0 105 -82z" />
-<glyph unicode="&#xd2;" horiz-adv-x="1519" d="M676 1851h22q49 0 125 -105q89 -98 89 -146q-19 -102 -105 -102h-3q-63 0 -144 124q-78 76 -78 131q22 98 94 98zM744 1457q376 0 629 -348q114 -198 114 -399q0 -372 -336 -619q-192 -121 -400 -121h-15q-383 0 -626 356q-110 181 -110 391q0 356 312 599 q205 141 432 141zM206 706q0 -258 229 -434q141 -96 301 -96h19q251 0 426 225q100 143 100 313q0 292 -268 462q-130 75 -269 75q-267 0 -442 -233q-96 -137 -96 -312z" />
-<glyph unicode="&#xd3;" horiz-adv-x="1532" d="M798 1856h18q99 -21 99 -101q0 -51 -129 -190q-32 -62 -101 -62q-82 0 -101 102q0 52 115 175q47 76 99 76zM746 1461q377 0 631 -349q114 -198 114 -400q0 -373 -337 -620q-192 -122 -401 -122h-15q-384 0 -628 357q-110 182 -110 392q0 357 313 600q205 142 433 142z M207 708q0 -259 229 -435q141 -96 302 -96h19q252 0 428 225q99 143 99 314q0 292 -268 463q-131 75 -270 75q-268 0 -443 -233q-96 -138 -96 -313z" />
-<glyph unicode="&#xd4;" horiz-adv-x="1523" d="M744 1457q376 0 629 -348q114 -198 114 -399q0 -372 -336 -619q-192 -121 -400 -121h-15q-383 0 -626 356q-110 181 -110 391q0 356 312 599q205 141 432 141zM206 706q0 -258 229 -434q141 -96 301 -96h19q251 0 426 225q100 143 100 313q0 292 -268 462 q-130 75 -269 75q-267 0 -442 -233q-96 -137 -96 -312zM741 1583q-71 -93 -121 -93h-12q-82 0 -101 102q0 47 122 187q45 64 99 64h31q50 0 146 -132q68 -71 68 -116v-7q-17 -98 -102 -98h-7q-57 0 -123 93z" />
-<glyph unicode="&#xd5;" horiz-adv-x="1528" d="M620 1802h18q81 0 179 -65l21 -6h10l79 24q106 -21 106 -106q0 -102 -171 -124h-28q-80 0 -178 66l-21 5h-11l-72 -19h-14q-95 20 -95 98v11q0 81 105 104q33 12 72 12zM744 1457q376 0 629 -348q114 -198 114 -399q0 -372 -336 -619q-192 -121 -400 -121h-15 q-383 0 -626 356q-110 181 -110 391q0 356 312 599q205 141 432 141zM206 706q0 -258 229 -434q141 -96 301 -96h19q251 0 426 225q100 143 100 313q0 292 -268 462q-130 75 -269 75q-267 0 -442 -233q-96 -137 -96 -312z" />
-<glyph unicode="&#xd6;" horiz-adv-x="1540" d="M536 1736q77 0 101 -105q-24 -106 -105 -106q-103 23 -103 94v23q0 78 107 94zM962 1736q77 0 101 -105q-24 -106 -106 -106q-102 23 -102 94v23q0 78 107 94zM746 1461q377 0 631 -349q114 -198 114 -400q0 -373 -337 -620q-192 -122 -401 -122h-15q-384 0 -628 357 q-110 182 -110 392q0 357 313 600q205 142 433 142zM207 708q0 -259 229 -435q141 -96 302 -96h19q252 0 428 225q99 143 99 314q0 292 -268 463q-131 75 -270 75q-268 0 -443 -233q-96 -138 -96 -313z" />
-<glyph unicode="&#xd7;" d="M725 638q151 -139 151 -180l6 -23q-29 -126 -127 -126q-65 0 -179 134l-25 21q-132 -150 -198 -150h-29q-102 32 -102 106v24q0 61 110 152l41 44q-151 149 -151 183v32q22 113 116 113h15q62 0 175 -134l20 -18q148 152 183 152h39q84 0 111 -118q0 -71 -156 -212z" />
-<glyph unicode="&#xd8;" horiz-adv-x="1561" d="M1215 971l-762 -713q117 -82 283 -82h18q252 0 427 225q99 142 99 312q0 135 -65 258zM1083 1131q-155 119 -340 119q-266 0 -441 -232q-96 -138 -96 -312q0 -184 101 -305zM301 116q-147 -142 -174 -142l-19 -4h-7q-85 0 -101 107q0 52 129 159q4 12 23 25 q-152 194 -152 456q0 355 312 598q205 141 431 141q278 0 490 -187q138 142 182 142h12q97 -25 97 -101v-7q0 -57 -115 -147l-42 -41q119 -182 119 -406q0 -371 -335 -618q-192 -121 -400 -121h-15q-236 0 -435 146z" />
-<glyph unicode="&#xd9;" horiz-adv-x="1103" d="M471 1849q67 0 166 -142q60 -58 60 -106v-8q0 -83 -103 -101q-64 0 -158 135q-67 69 -67 113v8q0 79 102 101zM94 1458h18q95 -20 95 -91v-802q0 -242 134 -322q85 -66 190 -66q201 0 303 207q21 64 21 136v839q18 99 98 99h14q95 -18 95 -98v-878q0 -239 -227 -416 q-145 -96 -293 -96h-26q-249 0 -432 243q-84 132 -84 322v824q21 99 94 99z" />
-<glyph unicode="&#xda;" horiz-adv-x="1107" d="M598 1849q99 -21 99 -101v-8q0 -47 -101 -153q-59 -95 -125 -95q-102 22 -102 101v8q0 48 100 154q60 94 129 94zM94 1458h18q95 -20 95 -91v-802q0 -242 134 -322q85 -66 190 -66q201 0 303 207q21 64 21 136v839q18 99 98 99h14q95 -18 95 -98v-878q0 -239 -227 -416 q-145 -96 -293 -96h-26q-249 0 -432 243q-84 132 -84 322v824q21 99 94 99z" />
-<glyph unicode="&#xdb;" horiz-adv-x="1124" d="M94 1463h18q95 -20 95 -90v-806q0 -243 135 -323q86 -67 191 -67q202 0 305 208q21 65 21 137v843q17 98 98 98h14q95 -18 95 -98v-881q0 -240 -228 -417q-145 -97 -294 -97h-26q-250 0 -434 244q-84 132 -84 323v828q21 98 94 98zM543 1563q-72 -84 -88 -84l-23 -8h-24 q-80 0 -98 99v7q0 50 132 194q0 44 100 55h10q65 0 159 -135q68 -70 68 -121q-23 -99 -95 -99h-19q-57 0 -118 91q-2 0 -4 1z" />
-<glyph unicode="&#xdc;" horiz-adv-x="1128" d="M379 1721h17q95 -21 95 -95v-11q0 -86 -106 -102q-101 19 -101 102v11q0 74 95 95zM669 1721h15q79 0 95 -108q0 -77 -105 -101q-103 19 -103 99v24q27 86 98 86zM94 1463h18q95 -20 95 -90v-806q0 -243 135 -323q86 -67 191 -67q202 0 305 208q21 65 21 137v843 q17 98 98 98h14q95 -18 95 -98v-881q0 -240 -228 -417q-145 -97 -294 -97h-26q-250 0 -434 244q-84 132 -84 323v828q21 98 94 98z" />
-<glyph unicode="&#xdd;" horiz-adv-x="1107" d="M536 897q353 531 372 545q28 21 52 21h23q69 0 94 -98q0 -46 -135 -230l-301 -450v-604q-13 -111 -94 -111h-16q-72 0 -98 86v626q0 5 -154 234l-273 411l-6 35q23 101 95 101h16q69 0 105 -88zM629 1827h7q102 -20 102 -105q0 -45 -98 -152q-68 -98 -117 -98h-23 q-78 0 -94 108q0 40 123 182q45 65 100 65z" />
-<glyph unicode="&#xde;" horiz-adv-x="1100" d="M114 1466h19q95 -20 95 -91v-250h360q317 0 422 -278q21 -65 21 -120v-18q0 -214 -208 -345q-107 -53 -188 -53l-26 4h-381v-247q0 -81 -100 -98h-6q-83 0 -102 103v1282q12 111 94 111zM228 917v-394h405q140 0 186 161l4 37q0 133 -145 186q-39 10 -101 10h-349z" />
-<glyph unicode="&#xdf;" horiz-adv-x="1061" d="M409 1455h41q192 0 327 -181q74 -109 74 -234q0 -96 -60 -220v-31q0 -26 116 -156q97 -118 97 -255v-15q0 -237 -241 -360q-76 -33 -156 -33h-3q-199 0 -329 176l-4 39q22 99 101 99h7q47 0 110 -70q59 -38 118 -38q133 0 185 145l6 48v5q0 84 -100 189 q-117 121 -117 241q0 63 55 188q5 11 5 37v33q0 101 -119 168q-37 19 -90 19q-145 0 -199 -159l-7 -103v-912q0 -80 -98 -98h-7q-82 0 -101 102v942q0 304 286 414q58 20 103 20z" />
-<glyph unicode="&#xe0;" horiz-adv-x="1118" d="M493 1415h29q47 0 169 -160q36 -38 36 -77v-8q0 -81 -100 -99q-63 0 -129 100q-90 99 -90 134v15q0 71 85 95zM202 507v-11q0 -199 201 -301q62 -23 112 -23h29q165 0 273 167q40 78 40 150v14q0 192 -191 294q-66 30 -136 30h-4q-201 0 -304 -211q-20 -65 -20 -109z M858 81q-118 -111 -314 -111h-29q-270 0 -449 270q-66 131 -66 263q0 296 289 468q124 58 241 58q300 0 475 -293q54 -121 54 -247v-423q0 -79 -96 -96h-7q-67 0 -99 79v9z" />
-<glyph unicode="&#xe1;" horiz-adv-x="1114" d="M627 1419q100 -23 100 -99v-7q0 -42 -86 -139q-68 -103 -137 -103h-4q-70 0 -92 96v11q0 44 120 179q46 62 99 62zM202 507v-11q0 -199 201 -301q62 -23 112 -23h29q165 0 273 167q40 78 40 150v14q0 192 -191 294q-66 30 -136 30h-4q-201 0 -304 -211q-20 -65 -20 -109z M858 81q-118 -111 -314 -111h-29q-270 0 -449 270q-66 131 -66 263q0 296 289 468q124 58 241 58q300 0 475 -293q54 -121 54 -247v-423q0 -79 -96 -96h-7q-67 0 -99 79v9z" />
-<glyph unicode="&#xe2;" horiz-adv-x="1140" d="M203 509v-11q0 -200 202 -301q62 -24 112 -24h30q166 0 274 168q40 78 40 150v15q0 192 -192 295q-66 30 -137 30h-4q-202 0 -305 -212q-20 -65 -20 -110zM862 81q-120 -111 -315 -111h-30q-271 0 -451 271q-66 132 -66 265q0 297 291 470q124 58 241 58q302 0 478 -294 q54 -122 54 -249v-425q0 -79 -97 -96h-6q-68 0 -100 79v11zM538 1421q71 -8 145 -116q77 -82 77 -132q-18 -100 -103 -100q-56 0 -125 93q-64 -93 -128 -93q-100 19 -100 103q0 49 109 165q48 74 112 80l1 1h11z" />
-<glyph unicode="&#xe3;" horiz-adv-x="1122" d="M438 1384h19q79 0 174 -65l21 -5h10l77 23q105 -21 105 -105q0 -100 -168 -122h-28q-78 0 -174 65l-21 5h-11l-70 -18h-14q-93 18 -93 96v11q0 79 102 103q33 12 71 12zM203 511v-11q0 -201 203 -303q63 -24 113 -24h30q167 0 275 169q41 79 41 151v15q0 193 -193 296 q-67 31 -138 31h-4q-203 0 -306 -213q-21 -66 -21 -111zM866 83q-120 -113 -317 -113h-30q-272 0 -452 273q-67 132 -67 265q0 298 292 472q125 58 242 58q303 0 479 -296q55 -121 55 -249v-427q0 -79 -97 -96h-7q-67 0 -99 79v10z" />
-<glyph unicode="&#xe4;" horiz-adv-x="1136" d="M382 1276h17q93 -21 93 -92v-11q0 -85 -104 -100q-99 18 -99 100v11q0 71 93 92zM664 1276h15q77 0 92 -105q0 -75 -102 -99q-101 18 -101 97v22q26 85 96 85zM203 509v-11q0 -200 202 -301q62 -24 112 -24h30q166 0 274 168q40 78 40 150v15q0 192 -192 295 q-66 30 -137 30h-4q-202 0 -305 -212q-20 -65 -20 -110zM862 81q-120 -111 -315 -111h-30q-271 0 -451 271q-66 132 -66 265q0 297 291 470q124 58 241 58q302 0 478 -294q54 -122 54 -249v-425q0 -79 -97 -96h-6q-68 0 -100 79v11z" />
-<glyph unicode="&#xe5;" horiz-adv-x="1131" d="M546 1477q124 0 193 -127q21 -45 21 -90q0 -144 -166 -204l-42 -5h-16q-139 0 -198 166l-5 41v13q0 146 175 203zM497 1266v-14q12 -43 39 -43h18q40 0 48 52q-9 53 -48 53q-57 -9 -57 -48zM203 509v-11q0 -200 202 -301q62 -24 112 -24h30q166 0 274 168q40 78 40 150 v15q0 192 -192 295q-66 30 -137 30h-4q-202 0 -305 -212q-20 -65 -20 -110zM862 81q-120 -111 -315 -111h-30q-271 0 -451 271q-66 132 -66 265q0 297 291 470q124 58 241 58q302 0 478 -294q54 -122 54 -249v-425q0 -79 -97 -96h-6q-68 0 -100 79v11z" />
-<glyph unicode="&#xe6;" horiz-adv-x="1961" d="M1707 574q-14 75 -105 171q-102 79 -214 79q-171 0 -277 -160q-40 -75 -40 -90h636zM202 511v-11q0 -199 201 -300q63 -24 113 -24h29q165 0 273 168q40 77 40 149v14q0 192 -191 295q-66 30 -137 30h-3q-202 0 -305 -211q-20 -65 -20 -110zM859 84q-118 -110 -314 -110 h-29q-271 0 -450 270q-66 131 -66 263q0 297 290 469q124 58 240 58q266 0 432 -223q88 133 271 196q89 23 159 23q296 0 468 -286q58 -120 58 -226v-50q-17 -96 -99 -96h-726q36 -85 115 -139q87 -57 180 -57q81 0 188 54l29 5q102 -24 102 -104q0 -119 -268 -157l-54 -4 q-205 0 -325 111v-12q0 -89 -105 -99h-5q-58 0 -92 83z" />
-<glyph unicode="&#xe7;" horiz-adv-x="986" d="M537 1026q205 0 373 -156q17 -30 17 -56v-6q-17 -96 -99 -96h-4q-36 0 -132 73q-72 36 -144 36h-22q-192 0 -292 -203q-23 -69 -23 -123q0 -198 204 -300q60 -23 129 -23q115 0 234 100l39 9h15q78 0 95 -96v-7q0 -95 -255 -192l-54 -8v-6q109 -72 109 -194 q0 -177 -206 -226l-54 4h-53l-63 -4q-88 29 -88 92v17q18 93 96 93h127q39 0 39 24v4q0 16 -45 25q-64 31 -64 84v90q-71 10 -210 104q-197 177 -197 413q0 258 228 431q145 97 300 97z" />
-<glyph unicode="&#xe8;" horiz-adv-x="1127" d="M528 1034q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30q77 0 187 55h32q93 -18 93 -96v-11q0 -117 -292 -155h-28q-286 0 -458 268q-70 127 -70 264q0 293 275 466q135 66 253 66zM214 576h640q0 35 -81 144 q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90zM490 1411h31q47 0 170 -161q36 -38 36 -77v-8q0 -82 -101 -99q-63 0 -129 100q-90 99 -90 135v14q0 70 83 96z" />
-<glyph unicode="&#xe9;" horiz-adv-x="1118" d="M528 1034q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30q77 0 187 55h32q93 -18 93 -96v-11q0 -117 -292 -155h-28q-286 0 -458 268q-70 127 -70 264q0 293 275 466q135 66 253 66zM214 576h640q0 35 -81 144 q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90zM627 1415q100 -23 100 -100v-7q0 -41 -87 -139q-68 -103 -137 -103h-4q-71 0 -92 96v11q0 44 120 180q46 62 100 62z" />
-<glyph unicode="&#xea;" horiz-adv-x="1144" d="M528 1034q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30q77 0 187 55h32q93 -18 93 -96v-11q0 -117 -292 -155h-28q-286 0 -458 268q-70 127 -70 264q0 293 275 466q135 66 253 66zM214 576h640q0 35 -81 144 q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90zM538 1421q71 -8 145 -116q77 -82 77 -132q-18 -100 -103 -100q-56 0 -125 93q-64 -93 -128 -93q-100 19 -100 103q0 49 109 165q48 74 112 80l1 1h11z" />
-<glyph unicode="&#xeb;" horiz-adv-x="1122" d="M382 1293h17q92 -21 92 -92v-11q0 -83 -104 -100q-98 19 -98 100v11q0 71 93 92zM662 1293h15q77 0 92 -105q0 -75 -102 -99q-100 18 -100 97v24q26 83 95 83zM527 1032q306 0 476 -290q59 -115 59 -248v-22q-18 -100 -100 -100h-731q29 -96 159 -166q77 -30 145 -30 q77 0 186 55h32q93 -18 93 -96v-11q0 -116 -291 -154h-28q-285 0 -457 267q-70 127 -70 264q0 292 275 465q134 66 252 66zM214 575h638q0 35 -81 143q-109 104 -215 104h-40q-159 0 -263 -158q-36 -62 -39 -89z" />
-<glyph unicode="&#xec;" horiz-adv-x="514" d="M175 1404h29q47 0 170 -161q36 -39 36 -78v-7q0 -82 -100 -100q-64 0 -130 100q-90 101 -90 135v15q0 70 85 96zM271 1033q96 -23 96 -92v-875q0 -79 -97 -96h-6q-81 0 -100 100v851q12 112 107 112z" />
-<glyph unicode="&#xed;" horiz-adv-x="514" d="M340 1403q101 -23 101 -100v-7q0 -42 -87 -140q-69 -104 -138 -104h-4q-71 0 -92 97v11q0 44 121 180q46 63 99 63zM272 1037q95 -25 95 -92v-879q0 -79 -96 -96h-7q-81 0 -100 101v854q12 112 108 112z" />
-<glyph unicode="&#xee;" horiz-adv-x="514" d="M267 1042q96 -25 96 -93v-882q0 -80 -97 -97h-6q-82 0 -101 101v858q12 113 108 113zM263 1397q74 -8 149 -117q77 -83 77 -132q-18 -101 -104 -101q-57 0 -124 93q-66 -93 -130 -93q-101 19 -101 104q0 48 109 165q49 75 111 81l1 1h11z" />
-<glyph unicode="&#xef;" horiz-adv-x="514" d="M271 1038q96 -25 96 -93v-879q0 -79 -97 -96h-7q-81 0 -100 101v854q12 113 108 113zM113 1303h17q93 -21 93 -93v-11q0 -83 -104 -100q-99 19 -99 100v11q0 72 93 93zM396 1303h14q78 0 93 -106q0 -75 -103 -99q-100 18 -100 97v23q26 85 96 85z" />
-<glyph unicode="&#xf0;" horiz-adv-x="1118" d="M578 1029l-29 44q-40 -25 -70 -42q27 3 55 3zM207 513v-18q0 -184 178 -286q63 -32 136 -32h22q190 0 291 198q23 61 23 120v18q0 127 -118 241q-91 73 -211 73q-208 0 -305 -219q-16 -52 -16 -95zM360 1003q-51 14 -67 93v7q0 69 126 129l20 12q-29 43 -29 71v24 q26 83 96 83h15q53 0 94 -69q131 80 163 80h10q93 -20 93 -96v-14q0 -62 -158 -144l263 -405q78 -131 78 -272q0 -299 -282 -469q-124 -63 -239 -63h-29q-216 0 -401 202q-113 159 -113 330q0 259 229 434q65 43 131 67z" />
-<glyph unicode="&#xf1;" horiz-adv-x="1108" d="M429 1391h18q79 0 174 -64l20 -6h11l75 23q105 -20 105 -104q0 -101 -167 -121h-28q-78 0 -173 64l-21 5h-10l-70 -18h-14q-93 18 -93 96v11q0 79 102 102q33 12 71 12zM107 1032q96 -25 96 -92v-13q118 105 317 105q219 0 389 -182q124 -153 124 -323v-465 q0 -73 -96 -92h-10q-97 17 -97 100v409q0 254 -216 333q-53 14 -94 14h-11q-181 0 -280 -188q-26 -57 -26 -188v-384q0 -79 -97 -96h-6q-81 0 -100 100v849q11 113 107 113z" />
-<glyph unicode="&#xf2;" horiz-adv-x="1118" d="M532 1034q206 0 373 -156q159 -166 159 -376q0 -299 -282 -469q-124 -63 -239 -63h-29q-216 0 -401 202q-113 159 -113 330q0 259 229 434q147 98 303 98zM207 513v-18q0 -184 178 -286q63 -32 136 -32h22q190 0 291 198q23 61 23 120v18q0 152 -140 258q-83 56 -189 56 q-208 0 -305 -219q-16 -52 -16 -95zM495 1422h30q46 0 169 -160q37 -39 37 -78v-8q0 -83 -102 -99q-63 0 -128 100q-91 99 -91 135v14q0 70 85 96z" />
-<glyph unicode="&#xf3;" horiz-adv-x="1118" d="M627 1419q100 -23 100 -99v-7q0 -42 -86 -139q-68 -103 -137 -103h-4q-70 0 -92 96v11q0 44 120 179q46 62 99 62zM530 1029q204 0 371 -155q158 -166 158 -374q0 -298 -281 -468q-123 -62 -238 -62h-29q-214 0 -398 201q-113 159 -113 329q0 258 228 432q146 97 302 97z M206 510v-18q0 -182 177 -284q63 -32 136 -32h21q190 0 290 197q23 61 23 119v18q0 152 -140 257q-82 56 -187 56q-207 0 -304 -218q-16 -52 -16 -95z" />
-<glyph unicode="&#xf4;" horiz-adv-x="1118" d="M530 1029q204 0 371 -155q158 -166 158 -374q0 -298 -281 -468q-123 -62 -238 -62h-29q-214 0 -398 201q-113 159 -113 329q0 258 228 432q146 97 302 97zM206 510v-18q0 -182 177 -284q63 -32 136 -32h21q190 0 290 197q23 61 23 119v18q0 152 -140 257q-82 56 -187 56 q-207 0 -304 -218q-16 -52 -16 -95zM533 1414q73 -8 147 -115q76 -82 76 -131q-17 -101 -103 -101q-56 0 -122 93q-65 -93 -128 -93q-100 21 -100 103q0 49 108 164q46 74 109 80l1 1h11z" />
-<glyph unicode="&#xf5;" horiz-adv-x="1118" d="M532 1034q206 0 373 -156q159 -166 159 -376q0 -299 -282 -469q-124 -63 -239 -63h-29q-216 0 -401 202q-113 159 -113 330q0 259 229 434q147 98 303 98zM207 513v-18q0 -184 178 -286q63 -32 136 -32h22q190 0 291 198q23 61 23 120v18q0 152 -140 258q-83 56 -189 56 q-208 0 -305 -219q-16 -52 -16 -95zM437 1378h18q79 0 173 -64l21 -5h11l76 23q104 -22 104 -104q0 -102 -167 -122h-27q-78 0 -175 64l-20 6h-10l-70 -19h-14q-93 18 -93 96v11q0 79 102 102q33 12 71 12z" />
-<glyph unicode="&#xf6;" horiz-adv-x="1114" d="M381 1270h17q92 -21 92 -92v-11q0 -83 -104 -100q-98 19 -98 100v11q0 71 93 92zM661 1270h14q77 0 92 -105q0 -75 -102 -99q-100 18 -100 97v22q26 85 96 85zM530 1029q204 0 371 -155q158 -166 158 -374q0 -298 -281 -468q-123 -62 -238 -62h-29q-214 0 -398 201 q-113 159 -113 329q0 258 228 432q146 97 302 97zM206 510v-18q0 -182 177 -284q63 -32 136 -32h21q190 0 290 197q23 61 23 119v18q0 152 -140 257q-82 56 -187 56q-207 0 -304 -218q-16 -52 -16 -95z" />
-<glyph unicode="&#xf7;" d="M552 1162h4q117 0 142 -127v-22q-28 -127 -130 -127h-10q-136 14 -136 138v12q30 126 130 126zM253 830h614q103 -19 103 -106v-12q0 -73 -98 -98h-623q-99 19 -99 102v16q0 78 103 98zM553 558h11q113 0 134 -140v-6q0 -105 -138 -135q-138 30 -138 131v20 q0 100 131 130z" />
-<glyph unicode="&#xf8;" horiz-adv-x="1161" d="M277 357l426 440q-35 24 -136 24q-207 0 -303 -217q-16 -52 -16 -95v-18q0 -71 29 -134zM852 660l-435 -450q56 -34 143 -34h21q189 0 289 196q23 61 23 119v18q0 98 -41 151zM985 1042h4q84 0 99 -105q0 -44 -91 -131q102 -125 102 -307q0 -298 -281 -467 q-122 -62 -237 -62h-29q-146 0 -278 92q-73 -88 -126 -88h-14q-77 0 -92 104q0 45 88 130q-88 121 -88 291q0 257 228 431q145 97 301 97q155 0 277 -81q78 96 137 96z" />
-<glyph unicode="&#xf9;" horiz-adv-x="1109" d="M494 1419h29q47 0 170 -161q36 -38 36 -77v-8q0 -82 -101 -99q-63 0 -129 100q-90 99 -90 135v14q0 70 85 96zM830 77q-138 -107 -303 -107h-25q-242 0 -420 236q-82 128 -82 313v399q11 114 107 114q96 -25 96 -93v-391q0 -234 129 -311q83 -64 184 -64q195 0 294 200 q20 65 20 131v427q19 101 107 101q95 -23 95 -100v-870q0 -73 -96 -92h-10q-96 17 -96 99v8z" />
-<glyph unicode="&#xfa;" horiz-adv-x="1105" d="M632 1429q100 -22 100 -99v-8q0 -41 -87 -139q-68 -104 -138 -104h-3q-71 0 -93 97v10q0 45 121 181q46 62 100 62zM834 78q-138 -108 -304 -108h-26q-243 0 -422 237q-82 129 -82 315v401q11 113 107 113q96 -23 96 -92v-393q0 -235 130 -313q84 -65 186 -65 q195 0 295 202q20 65 20 132v429q19 100 106 100q97 -22 97 -99v-875q0 -73 -97 -92h-9q-97 17 -97 100v8z" />
-<glyph unicode="&#xfb;" horiz-adv-x="1114" d="M838 78q-139 -108 -306 -108h-26q-244 0 -423 238q-83 129 -83 316v405q12 113 108 113q96 -25 96 -93v-395q0 -237 131 -315q84 -65 186 -65q197 0 297 202q20 65 20 133v432q20 101 108 101q96 -23 96 -101v-878q0 -74 -97 -93h-10q-97 18 -97 100v8zM541 1432 q74 -11 147 -117q77 -83 77 -132q-16 -102 -104 -102q-56 0 -124 94q-66 -94 -130 -94q-101 20 -101 104q0 49 110 166q45 72 107 81l1 1h16z" />
-<glyph unicode="&#xfc;" horiz-adv-x="1109" d="M830 76q-138 -106 -303 -106h-25q-242 0 -420 236q-82 128 -82 313v400q11 113 107 113q96 -25 96 -92v-391q0 -235 129 -312q83 -64 185 -64q194 0 293 200q20 65 20 132v427q21 100 107 100q96 -22 96 -99v-871q0 -73 -96 -92h-10q-97 17 -97 100v6zM663 1274h14 q77 0 93 -105q0 -75 -103 -99q-100 18 -100 97v22q26 85 96 85zM382 1274h17q93 -21 93 -92v-11q0 -85 -105 -100q-98 19 -98 100v11q0 71 93 92z" />
-<glyph unicode="&#xfd;" horiz-adv-x="990" d="M650 1436q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM478 352q263 641 283 664q36 31 75 31q101 -19 101 -100v-5q-5 -33 -365 -893q-172 -424 -197 -457q-26 -22 -69 -32q-104 23 -104 93v19q0 19 163 412 l-346 846v13q21 100 103 100q85 0 135 -166z" />
-<glyph unicode="&#xfe;" horiz-adv-x="1131" d="M103 1424h17q93 -20 93 -89v-412q119 114 331 114q207 0 374 -156q160 -167 160 -378q0 -300 -284 -471q-123 -63 -239 -63h-29q-188 0 -313 113v-439q0 -71 -100 -93q-83 0 -103 104v1661q12 109 93 109zM217 514v-18q0 -184 179 -287q63 -32 137 -32h22q191 0 293 199 q23 62 23 120v18q0 153 -142 260q-83 56 -189 56q-209 0 -306 -220q-17 -52 -17 -96z" />
-<glyph unicode="&#xff;" horiz-adv-x="990" d="M329 1271h17q93 -21 93 -92v-11q0 -83 -104 -100q-99 19 -99 100v11q0 71 93 92zM609 1271h15q77 0 92 -105q0 -75 -102 -99q-100 18 -100 97v22q26 85 95 85zM467 338q262 638 281 661q36 31 76 31q100 -19 100 -100v-5q-5 -33 -363 -889q-171 -422 -196 -455 q-26 -22 -70 -32q-103 23 -103 93v18q0 19 163 411l-345 842v13q19 100 103 100q85 0 134 -166z" />
-<glyph unicode="&#x100;" horiz-adv-x="1184" d="M709 744l-121 317l-117 -317h238zM586 1458q93 0 131 -160q454 -1183 459 -1217v-13q0 -81 -98 -98h-7q-90 0 -123 149l-161 418h-398l-202 -533q-45 -34 -78 -34h-11q-98 18 -98 101v9l130 352q335 872 365 973q48 53 91 53zM172 1727h847q97 -18 97 -100v-15 q-18 -97 -97 -97h-847q-87 0 -100 114q26 98 100 98z" />
-<glyph unicode="&#x101;" horiz-adv-x="1100" d="M206 519v-11q0 -205 206 -308q64 -24 115 -24h29q170 0 281 171q40 80 40 153v15q0 197 -195 302q-67 30 -140 30h-4q-207 0 -312 -216q-20 -66 -20 -112zM878 84q-122 -114 -322 -114h-29q-276 0 -460 276q-67 134 -67 269q0 302 296 479q126 59 246 59q307 0 486 -300 q55 -123 55 -253v-433q0 -80 -98 -97h-7q-68 0 -101 80v11zM132 1327h847q97 -18 97 -100v-15q-18 -97 -97 -97h-847q-87 0 -100 114q26 98 100 98z" />
-<glyph unicode="&#x102;" horiz-adv-x="1202" d="M380 1836h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM709 744l-121 317l-117 -317h238zM586 1458q93 0 131 -160q454 -1183 459 -1217v-13q0 -81 -98 -98h-7 q-90 0 -123 149l-161 418h-398l-202 -533q-45 -34 -78 -34h-11q-98 18 -98 101v9l130 352q335 872 365 973q48 53 91 53z" />
-<glyph unicode="&#x103;" horiz-adv-x="1118" d="M336 1444h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM206 519v-11q0 -205 206 -308q64 -24 115 -24h29q170 0 281 171q40 80 40 153v15q0 197 -195 302 q-67 30 -140 30h-4q-207 0 -312 -216q-20 -66 -20 -112zM878 84q-122 -114 -322 -114h-29q-276 0 -460 276q-67 134 -67 269q0 302 296 479q126 59 246 59q307 0 486 -300q55 -123 55 -253v-433q0 -80 -98 -97h-7q-68 0 -101 80v11z" />
-<glyph unicode="&#x104;" horiz-adv-x="1338" d="M729 739l-125 326l-120 -326h245zM602 1467q92 0 129 -151q480 -1250 480 -1276l4 -27v-97q0 -90 -104 -106q-11 -6 -11 -21v-8q0 -15 30 -19h146q100 -18 100 -103v-7q-21 -100 -95 -100h-161q-167 0 -225 184l-8 51q0 130 119 206q-15 62 -198 537h-407l-207 -545 q-45 -34 -78 -34h-11q-100 18 -100 103v8l132 359q343 890 373 993q49 53 92 53z" />
-<glyph unicode="&#x105;" horiz-adv-x="1241" d="M210 501v-11q0 -205 207 -309q64 -24 115 -24h30q171 0 282 172q41 80 41 154v15q0 197 -197 302q-68 31 -141 31h-3q-208 0 -313 -217q-21 -67 -21 -113zM884 64q-123 -113 -322 -113h-30q-277 0 -460 277q-68 134 -68 270q0 303 297 480q127 59 246 59q309 0 488 -300 q56 -125 56 -254v-566q0 -84 -107 -107q-6 -4 -6 -9v-16q4 -18 26 -18h143q83 0 102 -106q-23 -100 -95 -100h-157q-165 0 -225 185l-4 50q0 125 116 197l-3 36z" />
-<glyph unicode="&#x106;" horiz-adv-x="1251" d="M680 1463q32 3 64 3q233 0 439 -146q22 -42 22 -65v-8q0 -91 -107 -102h-13l-136 70q-126 40 -205 40q-255 0 -440 -233q-93 -156 -93 -304q0 -298 280 -473q123 -64 246 -64h11q157 0 327 106h35q95 -21 95 -98v-11q0 -102 -275 -184q-83 -24 -174 -24h-19 q-370 0 -619 342q-118 199 -118 406q0 389 354 633q138 83 281 106q-98 20 -98 102v16q0 47 149 181q120 137 177 137q94 0 110 -116q0 -55 -192 -227q-57 -69 -101 -87z" />
-<glyph unicode="&#x107;" horiz-adv-x="973" d="M652 1497q94 0 110 -116q0 -55 -192 -227q-76 -93 -130 -93h-15q-99 19 -99 102v16q0 47 149 181q120 137 177 137zM543 1056q210 0 384 -160q17 -31 17 -57v-7q-18 -98 -101 -98h-4q-37 0 -136 75q-74 38 -149 38h-22q-199 0 -302 -210q-24 -71 -24 -128 q0 -203 211 -309q62 -24 134 -24q118 0 240 103l41 9h15q80 0 97 -98v-6q0 -98 -262 -198q-86 -16 -128 -16h-30q-220 0 -408 206q-116 163 -116 337q0 265 234 444q149 99 309 99z" />
-<glyph unicode="&#x108;" horiz-adv-x="1254" d="M716 1572q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM744 1466q233 0 439 -146q22 -42 22 -65v-8q0 -91 -107 -102h-13l-136 70q-126 40 -205 40q-255 0 -440 -233 q-93 -156 -93 -304q0 -298 280 -473q123 -64 246 -64h11q157 0 327 106h35q95 -21 95 -98v-11q0 -102 -275 -184q-83 -24 -174 -24h-19q-370 0 -619 342q-118 199 -118 406q0 389 354 633q190 115 390 115z" />
-<glyph unicode="&#x109;" horiz-adv-x="982" d="M553 1207q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM543 1056q210 0 384 -160q17 -31 17 -57v-7q-18 -98 -101 -98h-4q-37 0 -136 75q-74 38 -149 38h-22 q-199 0 -302 -210q-24 -71 -24 -128q0 -203 211 -309q62 -24 134 -24q118 0 240 103l41 9h15q80 0 97 -98v-6q0 -98 -262 -198q-86 -16 -128 -16h-30q-220 0 -408 206q-116 163 -116 337q0 265 234 444q149 99 309 99z" />
-<glyph unicode="&#x10a;" horiz-adv-x="1259" d="M749 1810q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM744 1466q233 0 439 -146q22 -42 22 -65v-8q0 -91 -107 -102h-13l-136 70q-126 40 -205 40q-255 0 -440 -233q-93 -156 -93 -304q0 -298 280 -473 q123 -64 246 -64h11q157 0 327 106h35q95 -21 95 -98v-11q0 -102 -275 -184q-83 -24 -174 -24h-19q-370 0 -619 342q-118 199 -118 406q0 389 354 633q190 115 390 115z" />
-<glyph unicode="&#x10b;" horiz-adv-x="973" d="M564 1409q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM543 1056q210 0 384 -160q17 -31 17 -57v-7q-18 -98 -101 -98h-4q-37 0 -136 75q-74 38 -149 38h-22q-199 0 -302 -210q-24 -71 -24 -128q0 -203 211 -309 q62 -24 134 -24q118 0 240 103l41 9h15q80 0 97 -98v-6q0 -98 -262 -198q-86 -16 -128 -16h-30q-220 0 -408 206q-116 163 -116 337q0 265 234 444q149 99 309 99z" />
-<glyph unicode="&#x10c;" horiz-adv-x="1241" d="M728 1743q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM744 1466q233 0 439 -146q22 -42 22 -65v-8q0 -91 -107 -102h-13l-136 70q-126 40 -205 40q-255 0 -440 -233 q-93 -156 -93 -304q0 -298 280 -473q123 -64 246 -64h11q157 0 327 106h35q95 -21 95 -98v-11q0 -102 -275 -184q-83 -24 -174 -24h-19q-370 0 -619 342q-118 199 -118 406q0 389 354 633q190 115 390 115z" />
-<glyph unicode="&#x10d;" horiz-adv-x="990" d="M535 1369q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM543 1056q210 0 384 -160q17 -31 17 -57v-7q-18 -98 -101 -98h-4q-37 0 -136 75q-74 38 -149 38h-22 q-199 0 -302 -210q-24 -71 -24 -128q0 -203 211 -309q62 -24 134 -24q118 0 240 103l41 9h15q80 0 97 -98v-6q0 -98 -262 -198q-86 -16 -128 -16h-30q-220 0 -408 206q-116 163 -116 337q0 265 234 444q149 99 309 99z" />
-<glyph unicode="&#x10e;" horiz-adv-x="1162" d="M494 1748q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM72 1478l52 -11h189l42 4q338 0 585 -292q159 -206 159 -466q0 -359 -315 -604q-201 -139 -424 -139h-261 q-99 18 -99 102v1295q15 100 72 100v11zM208 1263v-1085h133q342 0 507 331q43 112 43 215q0 247 -220 432q-134 107 -406 107h-57z" />
-<glyph unicode="&#x10f;" horiz-adv-x="1396" d="M1204 1544h28q110 0 142 -264v-22q0 -143 -157 -273q-38 -21 -67 -21q-33 13 -52 46v26q60 144 60 230v12q0 54 -48 136v31q21 99 94 99zM978 1462h18q95 -20 95 -91v-748l4 -128q0 -158 -128 -329q-181 -196 -408 -196h-30q-222 0 -412 207q-117 165 -117 341 q0 266 236 447q150 100 312 100q208 0 340 -118v359l-4 65q29 91 94 91zM207 529v-19q0 -212 223 -316q58 -17 106 -17h23q206 0 312 222q17 67 17 103v23q0 211 -226 316q-69 17 -107 17h-15q-206 0 -312 -219q-21 -61 -21 -110z" />
-<glyph unicode="&#x110;" horiz-adv-x="1303" d="M185 877v490q15 100 72 100v11l52 -11h189l42 4q338 0 585 -292q159 -206 159 -466q0 -359 -315 -604q-201 -139 -424 -139h-261q-99 18 -99 102v593h-18l-69 -4q-94 33 -94 113q18 103 102 103h79zM393 877h151l36 4q81 0 108 -106q0 -80 -94 -114l-65 4h-136v-487h133 q342 0 507 331q43 112 43 215q0 247 -220 432q-134 107 -406 107h-57v-386z" />
-<glyph unicode="&#x111;" horiz-adv-x="1343" d="M238 529v-19q0 -212 223 -316q58 -17 106 -17h23q206 0 312 222q17 67 17 103v23q0 211 -226 316q-69 17 -107 17h-15q-206 0 -312 -219q-21 -61 -21 -110zM917 1339l-2 32q29 91 94 91h18q95 -20 95 -91v-32h95l36 4q81 0 108 -106q0 -80 -94 -114l-65 4h-80v-504 l4 -128q0 -158 -128 -329q-181 -196 -408 -196h-30q-222 0 -412 207q-117 165 -117 341q0 266 236 447q150 100 312 100q208 0 340 -118v180h-79l-69 -4q-94 33 -94 113q18 103 72 103v7l71 -7h97z" />
-<glyph unicode="&#x112;" horiz-adv-x="1100" d="M115 1757h847q97 -18 97 -100v-15q-18 -97 -97 -97h-847q-86 0 -100 114q27 98 100 98zM129 1473l53 -11h733l15 4q95 0 110 -114q-21 -97 -114 -97h-662v-450h424l53 3q75 0 98 -102q0 -72 -85 -109l-81 4h-409v-424h681q78 0 95 -111q-28 -96 -99 -96h-784 q-100 18 -100 102v1290q16 100 72 100v11z" />
-<glyph unicode="&#x113;" horiz-adv-x="1105" d="M528 1034q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30q77 0 187 55h32q93 -18 93 -96v-11q0 -117 -292 -155h-28q-286 0 -458 268q-70 127 -70 264q0 293 275 466q135 66 253 66zM214 576h640q0 35 -81 144 q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90zM115 1348h847q97 -18 97 -100v-15q-18 -97 -97 -97h-847q-87 0 -100 114q26 98 100 98z" />
-<glyph unicode="&#x114;" horiz-adv-x="1052" d="M107 1473l52 -11h733l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-785q-99 18 -99 102v1290q15 100 72 100v11zM322 1854h12q73 0 110 -98q40 -46 94 -46q82 0 122 98 q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99z" />
-<glyph unicode="&#x115;" horiz-adv-x="1101" d="M537 1034q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30q77 0 187 55h32q93 -18 93 -96v-11q0 -117 -292 -155h-28q-286 0 -458 268q-70 127 -70 264q0 293 275 466q135 66 253 66zM223 576h640q0 35 -81 144 q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90zM331 1466h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99z" />
-<glyph unicode="&#x116;" horiz-adv-x="1070" d="M534 1815q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM155 1462h733l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-785 q-99 18 -99 102v1290q15 100 72 100h52z" />
-<glyph unicode="&#x117;" horiz-adv-x="1105" d="M550 1034q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30q77 0 187 55h32q93 -18 93 -96v-11q0 -117 -292 -155h-28q-286 0 -458 268q-70 127 -70 264q0 293 275 466q135 66 253 66zM236 576h640q0 35 -81 144 q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90zM573 1379q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9z" />
-<glyph unicode="&#x118;" horiz-adv-x="1052" d="M594 -43l-1 13h-463q-99 18 -99 102v1290q15 100 72 100h785l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-118q-4 18 -5 23v-106q0 -84 -99 -99q-7 -4 -7 -17q0 -23 37 -23 h98l18 5q101 -23 101 -98v-7q0 -67 -81 -97l-80 4h-34l-56 -4q-86 0 -170 106q-30 57 -30 100v28q0 113 105 172z" />
-<glyph unicode="&#x119;" horiz-adv-x="1122" d="M236 576h640q0 35 -81 144q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90zM516 -29q-262 15 -424 267q-70 127 -70 264q0 293 275 466q135 66 253 66q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30 q77 0 187 55h32q93 -18 93 -96v-11q0 -93 -142 -127l-6 -93q0 -84 -99 -99q-7 -4 -7 -17q0 -23 37 -23h98l18 5q101 -23 101 -98v-7q0 -67 -81 -97l-80 4h-34l-56 -4q-86 0 -170 106q-30 57 -30 100v28q0 109 97 168z" />
-<glyph unicode="&#x11a;" horiz-adv-x="1065" d="M529 1748q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM159 1462h733l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4 h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-785q-99 18 -99 102v1290q15 100 72 100h52z" />
-<glyph unicode="&#x11b;" horiz-adv-x="1136" d="M572 1034q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30q77 0 187 55h32q93 -18 93 -96v-11q0 -117 -292 -155h-28q-286 0 -458 268q-70 127 -70 264q0 293 275 466q135 66 253 66zM258 576h640q0 35 -81 144 q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90zM587 1352q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100z" />
-<glyph unicode="&#x11c;" horiz-adv-x="1285" d="M751 1594q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM768 1466q238 0 433 -136q28 -38 28 -71v-4q0 -83 -103 -102q-22 0 -162 66q-82 32 -158 32h-61 q-198 0 -381 -193q-118 -162 -118 -332v-15q0 -278 258 -455q134 -75 268 -75h15q132 0 250 64v296h-246q-98 17 -98 102v5q17 100 101 100h352q81 0 98 -100v-421q0 -111 -61 -140q-199 -117 -389 -117h-22q-370 0 -619 342q-118 195 -118 406q0 376 334 622 q206 126 399 126z" />
-<glyph unicode="&#x11d;" horiz-adv-x="1167" d="M571 1212q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM562 1051q241 0 417 -200q122 -167 122 -317l-4 -126v-449q0 -141 -206 -299q-157 -103 -329 -103 q-294 0 -486 262q-38 64 -38 91v11q0 73 94 94h14q71 0 111 -108q122 -153 305 -153q219 0 328 196l6 40v97q-123 -114 -323 -114h-30q-218 0 -405 204q-115 162 -115 335q0 263 232 440q148 99 307 99zM228 523v-18q0 -208 219 -310q57 -17 104 -17h22q203 0 307 218 q16 65 16 101v23q0 207 -221 310q-69 16 -106 16h-14q-203 0 -307 -215q-20 -59 -20 -108z" />
-<glyph unicode="&#x11e;" horiz-adv-x="1246" d="M520 1837h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM755 1466q238 0 433 -136q28 -38 28 -71v-4q0 -83 -103 -102q-22 0 -162 66q-82 32 -158 32h-61 q-198 0 -381 -193q-118 -162 -118 -332v-15q0 -278 258 -455q134 -75 268 -75h15q132 0 250 64v296h-246q-98 17 -98 102v5q17 100 101 100h352q81 0 98 -100v-421q0 -111 -61 -140q-199 -117 -389 -117h-22q-370 0 -619 342q-118 195 -118 406q0 376 334 622 q206 126 399 126z" />
-<glyph unicode="&#x11f;" horiz-adv-x="1140" d="M366 1466h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM575 1051q241 0 417 -200q122 -167 122 -317l-4 -126v-449q0 -141 -206 -299q-157 -103 -329 -103 q-294 0 -486 262q-38 64 -38 91v11q0 73 94 94h14q71 0 111 -108q122 -153 305 -153q219 0 328 196l6 40v97q-123 -114 -323 -114h-30q-218 0 -405 204q-115 162 -115 335q0 263 232 440q148 99 307 99zM241 523v-18q0 -208 219 -310q57 -17 104 -17h22q203 0 307 218 q16 65 16 101v23q0 207 -221 310q-69 16 -106 16h-14q-203 0 -307 -215q-20 -59 -20 -108z" />
-<glyph unicode="&#x120;" horiz-adv-x="1272" d="M780 1823q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM759 1466q238 0 433 -136q28 -38 28 -71v-4q0 -83 -103 -102q-22 0 -162 66q-82 32 -158 32h-61q-198 0 -381 -193q-118 -162 -118 -332v-15q0 -278 258 -455 q134 -75 268 -75h15q132 0 250 64v296h-246q-98 17 -98 102v5q17 100 101 100h352q81 0 98 -100v-421q0 -111 -61 -140q-199 -117 -389 -117h-22q-370 0 -619 342q-118 195 -118 406q0 376 334 622q206 126 399 126z" />
-<glyph unicode="&#x121;" horiz-adv-x="1149" d="M609 1437q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM584 1051q241 0 417 -200q122 -167 122 -317l-4 -126v-449q0 -141 -206 -299q-157 -103 -329 -103q-294 0 -486 262q-38 64 -38 91v11q0 73 94 94h14 q71 0 111 -108q122 -153 305 -153q219 0 328 196l6 40v97q-123 -114 -323 -114h-30q-218 0 -405 204q-115 162 -115 335q0 263 232 440q148 99 307 99zM250 523v-18q0 -208 219 -310q57 -17 104 -17h22q203 0 307 218q16 65 16 101v23q0 207 -221 310q-69 16 -106 16h-14 q-203 0 -307 -215q-20 -59 -20 -108z" />
-<glyph unicode="&#x122;" horiz-adv-x="1276" d="M883 -25q88 -67 88 -174q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82v67q-294 28 -518 336q-118 195 -118 406q0 376 334 622q206 126 399 126q238 0 433 -136q28 -38 28 -71v-4q0 -83 -103 -102 q-22 0 -162 66q-82 32 -158 32h-61q-198 0 -381 -193q-118 -162 -118 -332v-15q0 -278 258 -455q134 -75 268 -75h15q132 0 250 64v296h-246q-98 17 -98 102v5q17 100 101 100h352q81 0 98 -100v-421q0 -111 -61 -140q-165 -97 -300 -112z" />
-<glyph unicode="&#x123;" horiz-adv-x="1184" d="M665 1701q59 -17 59 -64v-14q-59 -141 -60 -238q0 -52 46 -129l6 -28q0 -92 -111 -113q-126 0 -157 280q0 150 159 284zM597 1051q241 0 417 -200q122 -167 122 -317l-4 -126v-449q0 -141 -206 -299q-157 -103 -329 -103q-294 0 -486 262q-38 64 -38 91v11q0 73 94 94h14 q71 0 111 -108q122 -153 305 -153q219 0 328 196l6 40v97q-123 -114 -323 -114h-30q-218 0 -405 204q-115 162 -115 335q0 263 232 440q148 99 307 99zM263 523v-18q0 -208 219 -310q57 -17 104 -17h22q203 0 307 218q16 65 16 101v23q0 207 -221 310q-69 16 -106 16h-14 q-203 0 -307 -215q-20 -59 -20 -108z" />
-<glyph unicode="&#x124;" horiz-adv-x="1176" d="M602 1594q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM134 1463h18q95 -20 95 -90v-568h652v560q17 98 98 98h14q95 -18 95 -98v-1301q0 -73 -99 -94h-10 q-98 18 -98 102v530h-652v-534q0 -81 -98 -98h-7q-83 0 -102 103v1279q12 111 94 111z" />
-<glyph unicode="&#x125;" horiz-adv-x="1074" d="M562 1510q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM129 1460h18q95 -20 95 -90v-396q104 90 280 90q268 0 429 -253q61 -113 61 -215v-528q0 -81 -100 -98h-5 q-77 0 -102 94v510q0 184 -191 266q-45 13 -92 13q-189 0 -267 -203q-13 -43 -13 -148v-434q0 -81 -100 -98h-5q-77 0 -102 94v1298q21 98 94 98z" />
-<glyph unicode="&#x126;" horiz-adv-x="1303" d="M137 1225v127q12 111 94 111h18q95 -20 95 -90v-153h652v145q17 98 98 98h14q95 -18 95 -98v-140l-7 -1q102 0 132 -106q0 -78 -111 -114h-14v-940q0 -73 -99 -94h-10q-98 18 -98 102v530h-652v-534q0 -81 -98 -98h-7q-83 0 -102 103v931h-2q-117 31 -117 113 q23 103 95 103v7zM344 1008v-203h652v203h-652z" />
-<glyph unicode="&#x127;" horiz-adv-x="1330" d="M291 1317v45q21 98 94 98h18q95 -20 95 -90v-53h393l36 4q85 0 108 -107q0 -75 -89 -113l-74 4h-374v-131q104 90 280 90q268 0 429 -253q61 -113 61 -215v-528q0 -81 -100 -98h-5q-77 0 -102 94v510q0 184 -191 266q-45 13 -92 13q-189 0 -267 -203q-13 -43 -13 -148 v-434q0 -81 -100 -98h-5q-77 0 -102 94v1041h-97l-69 -4q-94 33 -94 113q18 103 72 103v7l71 -7h117z" />
-<glyph unicode="&#x128;" horiz-adv-x="621" d="M220 1769q91 0 202 -72l20 -2l75 22h13q100 -17 100 -102v-4q0 -96 -150 -120l-40 -4q-91 0 -194 73l-17 2l-84 -23q-106 20 -106 102v8q0 99 164 117zM222 1479l23 -4h137l18 4q106 -23 106 -110q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10q-18 -99 -102 -99 h-183q-99 18 -99 102v7q21 100 95 100h-7v1087h14q-90 0 -102 108v6q0 70 100 99z" />
-<glyph unicode="&#x129;" horiz-adv-x="616" d="M220 1359q91 0 202 -72l20 -2l75 22h13q100 -17 100 -102v-4q0 -96 -150 -120l-40 -4q-91 0 -194 73l-17 2l-84 -23q-106 20 -106 102v8q0 99 164 117zM330 1060q98 -25 98 -94v-898q0 -81 -100 -98h-6q-82 0 -101 102v874q12 114 109 114z" />
-<glyph unicode="&#x12a;" horiz-adv-x="683" d="M94 1751l71 -7h397l36 4q81 0 108 -106q0 -80 -94 -114l-65 4h-362l-69 -4q-94 33 -94 113q18 103 72 103v7zM266 1479l23 -4h137l18 4q106 -23 106 -110q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10q-18 -99 -102 -99h-183q-99 18 -99 102v7q21 100 95 100h-7 v1087h14q-90 0 -102 108v6q0 70 100 99z" />
-<glyph unicode="&#x12b;" horiz-adv-x="744" d="M116 1346l71 -7h397l36 4q81 0 108 -106q0 -80 -94 -114l-65 4h-362l-69 -4q-94 33 -94 113q18 103 72 103v7zM383 1060q98 -25 98 -94v-898q0 -81 -100 -98h-6q-82 0 -101 102v874q12 114 109 114z" />
-<glyph unicode="&#x12c;" horiz-adv-x="647" d="M132 1862h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM252 1479l23 -4h137l18 4q106 -23 106 -110q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10 q-18 -99 -102 -99h-183q-99 18 -99 102v7q21 100 95 100h-7v1087h14q-90 0 -102 108v6q0 70 100 99z" />
-<glyph unicode="&#x12d;" horiz-adv-x="647" d="M124 1452h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM330 1060q98 -25 98 -94v-898q0 -81 -100 -98h-6q-82 0 -101 102v874q12 114 109 114z" />
-<glyph unicode="&#x12e;" horiz-adv-x="511" d="M131 -23q-71 24 -71 95v7q21 100 95 100h-7v1087h14q-90 0 -102 108v6q0 70 100 99l23 -4h137l18 4q106 -23 106 -110q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10q-18 -99 -102 -99h28v-35q0 -84 -99 -99q-7 -4 -7 -17q0 -23 37 -23h98l18 5q101 -23 101 -98v-7 q0 -67 -81 -97l-80 4h-34l-56 -4q-86 0 -170 106q-30 57 -30 100v28q0 89 64 144z" />
-<glyph unicode="&#x12f;" horiz-adv-x="466" d="M237 1316q98 -25 98 -94v-22q0 -79 -107 -94q-77 0 -101 105q21 105 110 105zM137 15l-2 29q-3 9 -7 28v874q12 114 109 114q98 -25 98 -94v-898q0 -8 -1 -14q1 0 1 -1v-108q0 -84 -99 -99q-7 -4 -7 -17q0 -23 37 -23h98l18 5q101 -23 101 -98v-7q0 -67 -81 -97l-80 4 h-34l-56 -4q-86 0 -170 106q-30 57 -30 100v28q0 113 105 172z" />
-<glyph unicode="&#x130;" horiz-adv-x="462" d="M265 1823q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM160 1479l23 -4h137l18 4q106 -23 106 -110q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10q-18 -99 -102 -99h-183q-99 18 -99 102v7q21 100 95 100h-7v1087 h14q-90 0 -102 108v6q0 70 100 99z" />
-<glyph unicode="&#x131;" horiz-adv-x="514" d="M335 1000h15q73 -16 73 -73v-881q-14 -76 -79 -76h-5q-76 16 -76 73v767q-34 -11 -60 -11q-56 0 -73 74v16q0 63 126 88z" />
-<glyph unicode="&#x132;" horiz-adv-x="1435" d="M1290 1473h12q80 0 98 -99v-926q0 -255 -238 -409q-113 -65 -232 -65h-19q-236 0 -394 227q-73 121 -73 254q22 99 95 99h15q102 0 102 -147q5 -70 89 -161q81 -64 177 -64q190 0 260 199q10 35 10 71v926q18 95 98 95zM160 1479l23 -4h137l18 4q106 -23 106 -110 q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10q-18 -99 -102 -99h-183q-99 18 -99 102v7q21 100 95 100h-7v1087h14q-90 0 -102 108v6q0 70 100 99z" />
-<glyph unicode="&#x133;" horiz-adv-x="761" d="M189 1316q99 -25 99 -94v-22q0 -79 -107 -94q-77 0 -101 105q21 105 109 105zM189 1060q99 -25 99 -94v-898q0 -81 -100 -98h-6q-82 0 -101 102v874q12 114 108 114zM580 1308q105 -21 105 -105q0 -88 -110 -105q-94 27 -94 94v22q0 68 99 94zM219 -438q-90 0 -104 109 q0 83 108 99q189 0 250 186l8 106v894q0 84 104 100q100 -19 100 -100v-928q0 -295 -281 -431q-88 -31 -166 -35h-19z" />
-<glyph unicode="&#x134;" horiz-adv-x="1166" d="M905 1568q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM907 1473h12q80 0 98 -99v-926q0 -255 -238 -409q-113 -65 -232 -65h-19q-236 0 -394 227q-73 121 -73 254 q22 99 95 99h15q102 0 102 -147q5 -70 89 -161q81 -64 177 -64q190 0 260 199q10 35 10 71v926q18 95 98 95z" />
-<glyph unicode="&#x135;" horiz-adv-x="810" d="M522 1163q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM532 1056q99 -19 99 -100v-928q0 -295 -280 -431q-99 -35 -183 -35l-4 4h23l-3 -4h-19q-89 0 -104 109 q0 83 109 99q188 0 249 186l8 106v894q0 84 105 100z" />
-<glyph unicode="&#x136;" horiz-adv-x="1104" d="M148 1464h5q100 -17 100 -98v-581q658 657 674 657l27 4h12q95 -18 95 -98v-12q0 -51 -89 -124l-445 -448l522 -646l4 -33v-13q0 -81 -98 -98h-7q-61 0 -149 129l-423 513l-123 -126v-422q0 -81 -100 -98h-5q-83 0 -102 102v1290q19 102 102 102zM506 79q22 8 45 8 q38 0 78 -21q119 -79 119 -196q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82q0 79 58 101z" />
-<glyph unicode="&#x137;" horiz-adv-x="1026" d="M393 518l-125 -80v-370q0 -81 -100 -98h-6q-77 0 -102 94v1302q21 99 94 99h18q96 -21 96 -91v-690q489 324 586 379h27q86 0 102 -107q0 -66 -136 -138l-276 -189l406 -514l6 -33v-9q-18 -99 -102 -99h-7q-60 0 -157 140zM471 88q22 8 45 8q38 0 78 -21 q119 -79 119 -196q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82q0 79 58 101z" />
-<glyph unicode="&#x138;" horiz-adv-x="1043" d="M406 518l-125 -80v-370q0 -81 -100 -98h-6q-77 0 -102 94v934q16 87 93 105l28 1q82 -20 87 -110v-310q489 324 586 379h27q86 0 102 -107q0 -66 -136 -138l-276 -189l406 -514l6 -33v-9q-18 -99 -102 -99h-7q-60 0 -157 140z" />
-<glyph unicode="&#x139;" horiz-adv-x="947" d="M528 1854q94 0 110 -116q0 -55 -192 -227q-76 -93 -130 -93h-15q-99 19 -99 102v16q0 47 149 181q120 137 177 137zM125 1463h18q95 -20 95 -90v-1196h587q87 0 103 -111q-29 -96 -103 -96h-692q-83 0 -102 103v1279q12 111 94 111z" />
-<glyph unicode="&#x13a;" horiz-adv-x="466" d="M172 1457h18q95 -20 95 -90v-1190h49q73 0 94 -99v-8q-17 -100 -102 -100h-146q-83 0 -102 102v1275q12 110 94 110zM325 1867q89 0 104 -110q0 -52 -182 -215q-72 -88 -123 -88h-14q-94 18 -94 97v15q0 44 141 171q114 130 168 130z" />
-<glyph unicode="&#x13b;" horiz-adv-x="929" d="M443 -30h-319q-83 0 -102 103v1279q12 111 94 111h18q95 -20 95 -90v-1196h587q87 0 103 -111q-29 -96 -103 -96h-227q119 -79 119 -196q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82q0 61 35 88z" />
-<glyph unicode="&#x13c;" horiz-adv-x="515" d="M366 -30l8 -4q119 -79 119 -196q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82q0 66 40 92h-4q-83 0 -102 102v1275q12 110 94 110h18q95 -20 95 -90v-1190h49q73 0 94 -99v-8q-17 -100 -102 -100h-9z " />
-<glyph unicode="&#x13d;" horiz-adv-x="973" d="M749 1606h28q110 0 142 -264v-22q0 -143 -157 -273q-38 -21 -67 -21q-33 13 -52 46v26q60 144 60 230v12q0 54 -48 136v31q21 99 94 99zM160 1463h18q95 -20 95 -90v-1196h587q87 0 103 -111q-29 -96 -103 -96h-692q-83 0 -102 103v1279q12 111 94 111z" />
-<glyph unicode="&#x13e;" horiz-adv-x="559" d="M402 1597h28q110 0 142 -264v-22q0 -143 -157 -273q-38 -21 -67 -21q-33 13 -52 46v26q60 144 60 230v12q0 54 -48 136v31q21 99 94 99zM168 1457h18q95 -20 95 -90v-1190h49q73 0 94 -99v-8q-17 -100 -102 -100h-146q-83 0 -102 102v1275q12 110 94 110z" />
-<glyph unicode="&#x13f;" horiz-adv-x="1004" d="M665 899q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM160 1463h18q95 -20 95 -90v-1196h587q87 0 103 -111q-29 -96 -103 -96h-692q-83 0 -102 103v1279q12 111 94 111z" />
-<glyph unicode="&#x140;" horiz-adv-x="665" d="M498 864q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM159 1457h18q95 -20 95 -90v-1190h49q73 0 94 -99v-8q-17 -100 -102 -100h-146q-83 0 -102 102v1275q12 110 94 110z" />
-<glyph unicode="&#x141;" horiz-adv-x="1079" d="M185 714v638q12 111 94 111h18q95 -20 95 -90v-509q198 145 230 145h20q73 0 98 -98v-16q0 -66 -133 -145l-215 -155v-418h587q87 0 103 -111q-29 -96 -103 -96h-692q-83 0 -102 103v376q-6 -4 -16 -4l-23 -5q-110 22 -110 111q0 74 149 163z" />
-<glyph unicode="&#x142;" horiz-adv-x="695" d="M430 830q144 104 173 104h20q73 0 98 -98v-16q0 -66 -133 -145l-158 -114v-384h49q73 0 94 -99v-8q-17 -100 -102 -100h-146q-83 0 -102 102v340q-61 -42 -73 -42l-23 -5q-110 22 -110 111q0 75 165 173l41 30v668q12 110 94 110h18q95 -20 95 -90v-537z" />
-<glyph unicode="&#x143;" horiz-adv-x="1285" d="M854 1788q94 0 110 -116q0 -55 -192 -227q-76 -93 -130 -93h-15q-99 19 -99 102v16q0 47 149 181q120 137 177 137zM1033 374v992q18 95 98 95h11q81 0 98 -98v-1288q0 -87 -107 -105q-61 0 -158 144l-733 936v-978q0 -81 -100 -98h-5q-83 0 -102 102v1274q12 111 94 111 h15q67 0 108 -88q53 -60 781 -999z" />
-<glyph unicode="&#x144;" horiz-adv-x="1096" d="M678 1555q94 0 110 -116q0 -55 -192 -227q-76 -93 -130 -93h-15q-99 19 -99 102v16q0 47 149 181q120 137 177 137zM138 1032q96 -25 96 -92v-13q118 105 317 105q219 0 389 -182q124 -153 124 -323v-465q0 -73 -96 -92h-10q-97 17 -97 100v409q0 254 -216 333 q-53 14 -94 14h-11q-181 0 -280 -188q-26 -57 -26 -188v-384q0 -79 -97 -96h-6q-81 0 -100 100v849q11 113 107 113z" />
-<glyph unicode="&#x145;" horiz-adv-x="1307" d="M1064 374v992q18 95 98 95h11q81 0 98 -98v-1288q0 -87 -107 -105q-61 0 -158 144l-733 936v-978q0 -81 -100 -98h-5q-83 0 -102 102v1274q12 111 94 111h15q67 0 108 -88q53 -60 781 -999zM655 88q22 8 45 8q38 0 78 -21q119 -79 119 -196q0 -169 -197 -218l-53 3h-50 l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82q0 79 58 101z" />
-<glyph unicode="&#x146;" horiz-adv-x="1140" d="M514 84q22 8 45 8q38 0 78 -21q119 -79 119 -196q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82q0 79 58 101zM142 1032q96 -25 96 -92v-13q118 105 317 105q219 0 389 -182q124 -153 124 -323v-465 q0 -73 -96 -92h-10q-97 17 -97 100v409q0 254 -216 333q-53 14 -94 14h-11q-181 0 -280 -188q-26 -57 -26 -188v-384q0 -79 -97 -96h-6q-81 0 -100 100v849q11 113 107 113z" />
-<glyph unicode="&#x147;" horiz-adv-x="1321" d="M670 1620q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM1051 374v992q18 95 98 95h11q81 0 98 -98v-1288q0 -87 -107 -105q-61 0 -158 144l-733 936v-978 q0 -81 -100 -98h-5q-83 0 -102 102v1274q12 111 94 111h15q67 0 108 -88q53 -60 781 -999z" />
-<glyph unicode="&#x148;" horiz-adv-x="1114" d="M578 1369q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM147 1032q96 -25 96 -92v-13q118 105 317 105q219 0 389 -182q124 -153 124 -323v-465q0 -73 -96 -92h-10 q-97 17 -97 100v409q0 254 -216 333q-53 14 -94 14h-11q-181 0 -280 -188q-26 -57 -26 -188v-384q0 -79 -97 -96h-6q-81 0 -100 100v849q11 113 107 113z" />
-<glyph unicode="&#x149;" horiz-adv-x="1427" d="M119 1306h28q110 0 142 -264v-22q0 -143 -157 -273q-38 -21 -67 -21q-33 13 -52 46v26q60 144 60 230v12q0 54 -48 136v31q21 99 94 99zM398 1032q96 -25 96 -92v-13q118 105 317 105q219 0 389 -182q124 -153 124 -323v-465q0 -73 -96 -92h-10q-97 17 -97 100v409 q0 254 -216 333q-53 14 -94 14h-11q-181 0 -280 -188q-26 -57 -26 -188v-384q0 -79 -97 -96h-6q-81 0 -100 100v849q11 113 107 113z" />
-<glyph unicode="&#x14a;" horiz-adv-x="1268" d="M643 1463q242 0 437 -190q142 -165 159 -319l7 -51l-3 -119v-207l3 -99q-15 -141 -96 -255q-161 -196 -394 -196q-167 0 -294 107l-11 48v17q18 95 98 95h13l126 -50l70 -7h6q155 0 243 152q32 48 32 199v230q0 304 -255 410q-74 24 -126 24h-22q-220 0 -348 -219 q-41 -75 -41 -237v-728q0 -81 -100 -98h-5q-83 0 -102 102v1276q12 111 94 111h18q95 -20 95 -90v-55q147 149 396 149z" />
-<glyph unicode="&#x14b;" horiz-adv-x="1140" d="M1072 47q-4 -230 -250 -325l-96 -17q-102 23 -102 93v22q0 82 112 91q90 0 131 113q0 20 3 39v416q0 254 -216 333q-53 14 -94 14h-11q-181 0 -280 -188q-26 -57 -26 -188v-384q0 -79 -97 -96h-6q-81 0 -100 100v849q11 113 107 113q96 -25 96 -92v-13q118 105 317 105 q219 0 389 -182q124 -153 124 -323v-465q0 -8 -1 -15z" />
-<glyph unicode="&#x14c;" horiz-adv-x="1580" d="M779 1465q378 0 632 -350q115 -199 115 -401q0 -374 -338 -622q-192 -122 -402 -122h-15q-386 0 -629 358q-111 182 -111 393q0 358 314 602q205 142 434 142zM238 710q0 -259 230 -437q142 -96 303 -96h19q253 0 429 226q100 144 100 315q0 293 -269 464 q-132 76 -271 76q-268 0 -445 -234q-96 -138 -96 -314zM370 1734h847q97 -18 97 -100v-15q-18 -97 -97 -97h-847q-87 0 -100 114q26 98 100 98z" />
-<glyph unicode="&#x14d;" horiz-adv-x="1188" d="M583 1048q209 0 378 -158q161 -169 161 -381q0 -303 -286 -476q-125 -63 -242 -63h-30q-218 0 -405 204q-115 162 -115 335q0 263 232 440q148 99 307 99zM253 520v-18q0 -187 181 -290q64 -33 138 -33h22q193 0 296 201q23 62 23 122v18q0 155 -143 262q-83 57 -191 57 q-211 0 -310 -222q-16 -52 -16 -97zM163 1355h847q97 -18 97 -100v-15q-18 -97 -97 -97h-847q-87 0 -100 114q26 98 100 98z" />
-<glyph unicode="&#x14e;" horiz-adv-x="1563" d="M587 1866h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM788 1465q378 0 632 -350q115 -199 115 -401q0 -374 -338 -622q-192 -122 -402 -122h-15 q-386 0 -629 358q-111 182 -111 393q0 358 314 602q205 142 434 142zM247 710q0 -259 230 -437q142 -96 303 -96h19q253 0 429 226q100 144 100 315q0 293 -269 464q-132 76 -271 76q-268 0 -445 -234q-96 -138 -96 -314z" />
-<glyph unicode="&#x14f;" horiz-adv-x="1127" d="M371 1466h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM579 1048q209 0 378 -158q161 -169 161 -381q0 -303 -286 -476q-125 -63 -242 -63h-30 q-218 0 -405 204q-115 162 -115 335q0 263 232 440q148 99 307 99zM249 520v-18q0 -187 181 -290q64 -33 138 -33h22q193 0 296 201q23 62 23 122v18q0 155 -143 262q-83 57 -191 57q-211 0 -310 -222q-16 -52 -16 -97z" />
-<glyph unicode="&#x150;" horiz-adv-x="1580" d="M597 1873h7q103 -18 103 -102v-20q0 -31 -175 -259q-28 -31 -59 -31h-8q-56 0 -74 70v18q110 275 140 302q37 22 66 22zM238 710q0 -259 230 -437q142 -96 303 -96h19q253 0 429 226q100 144 100 315q0 293 -269 464q-132 76 -271 76q-268 0 -445 -234q-96 -138 -96 -314 zM758 1465h21q378 0 632 -350q115 -199 115 -401q0 -374 -338 -622q-192 -122 -402 -122h-15q-386 0 -629 358q-111 182 -111 393q0 358 314 602q158 109 330 134q-28 16 -40 62q0 27 117 293q47 49 96 49q107 -21 107 -110q0 -42 -114 -185q-48 -74 -83 -101z" />
-<glyph unicode="&#x151;" horiz-adv-x="1135" d="M460 1499h7q103 -18 103 -102v-20q0 -31 -175 -259q-28 -31 -59 -31h-8q-56 0 -74 70v18q110 275 140 302q37 22 66 22zM711 1487q107 -21 107 -110q0 -42 -114 -185q-75 -117 -120 -117h-12q-56 0 -74 70q0 27 117 293q47 49 96 49zM574 1048q209 0 378 -158 q161 -169 161 -381q0 -303 -286 -476q-125 -63 -242 -63h-30q-218 0 -405 204q-115 162 -115 335q0 263 232 440q148 99 307 99zM244 520v-18q0 -187 181 -290q64 -33 138 -33h22q193 0 296 201q23 62 23 122v18q0 155 -143 262q-83 57 -191 57q-211 0 -310 -222 q-16 -52 -16 -97z" />
-<glyph unicode="&#x152;" horiz-adv-x="2157" d="M264 710q0 -261 189 -439q114 -94 242 -94h16q203 0 345 223q83 146 83 318q0 294 -220 466q-106 74 -217 74q-215 0 -358 -231q-80 -140 -80 -317zM1141 186q-6 -10 -99 -92q-160 -124 -334 -124h-13q-321 0 -521 360q-90 181 -90 391q0 356 257 600q170 144 361 144 q293 0 439 -221v124q15 100 72 100v11l52 -11h737l15 4q95 0 110 -114q-21 -98 -113 -98h-665v-452h424l54 4q76 0 99 -103q0 -73 -86 -109l-82 4h-409v-426h683q79 0 96 -112q-29 -96 -99 -96h-789q-99 18 -99 102v114z" />
-<glyph unicode="&#x153;" horiz-adv-x="2025" d="M253 525v-18q0 -187 181 -290q64 -33 138 -33h22q193 0 296 201q23 62 23 122v18q0 155 -143 262q-83 57 -191 57q-211 0 -310 -222q-16 -52 -16 -97zM1133 581h640q0 35 -81 144q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90zM1020 195q-46 -74 -184 -157 q-125 -63 -242 -63h-30q-218 0 -405 204q-115 162 -115 335q0 263 232 440q148 99 307 99q209 0 378 -158q52 -54 62 -70q41 67 171 148q135 66 253 66q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30q77 0 187 55h32 q93 -18 93 -96v-11q0 -117 -292 -155h-28q-282 0 -427 220z" />
-<glyph unicode="&#x154;" horiz-adv-x="986" d="M243 1261v-425h185q156 0 206 169l3 27v28q0 123 -140 188q-39 13 -129 13h-125zM411 1465h33q218 0 355 -228q45 -89 45 -185v-15q0 -214 -208 -351l-10 -5q332 -573 332 -594v-19q0 -81 -100 -98h-6q-73 0 -140 145l-301 514h-168v-561q0 -81 -100 -98h-6 q-83 0 -102 103v1280q12 112 94 112h185q-59 26 -59 90v16q0 47 149 181q120 137 177 137q94 0 110 -116q0 -55 -192 -227q-49 -60 -88 -81z" />
-<glyph unicode="&#x155;" horiz-adv-x="928" d="M603 1537q94 0 110 -116q0 -55 -192 -227q-76 -93 -130 -93h-15q-99 19 -99 102v16q0 47 149 181q120 137 177 137zM177 1061q98 -25 98 -94v-16q124 110 323 110q107 0 232 -54q43 -44 43 -85v-7q-17 -98 -101 -98h-9q-103 33 -150 33h-22q-202 0 -296 -210 q-20 -55 -20 -128v-444q0 -81 -100 -98h-6q-82 0 -101 102v874q12 115 109 115z" />
-<glyph unicode="&#x156;" horiz-adv-x="995" d="M134 1465h315q218 0 355 -228q45 -89 45 -185v-15q0 -214 -208 -351l-10 -5q332 -573 332 -594v-19q0 -81 -100 -98h-6q-73 0 -140 145l-301 514h-168v-561q0 -81 -100 -98h-6q-83 0 -102 103v1280q12 112 94 112zM248 1261v-425h185q156 0 206 169l3 27v28 q0 123 -140 188q-39 13 -129 13h-125zM466 120q22 8 45 8q38 0 78 -21q119 -79 119 -196q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82q0 79 58 101z" />
-<glyph unicode="&#x157;" horiz-adv-x="854" d="M129 1061q98 -25 98 -94v-16q124 110 323 110q107 0 232 -54q43 -44 43 -85v-7q-17 -98 -101 -98h-9q-103 33 -150 33h-22q-202 0 -296 -210q-20 -55 -20 -128v-444q0 -81 -100 -98h-6q-82 0 -101 102v874q12 115 109 115zM303 115q22 8 45 8q38 0 78 -21 q119 -79 119 -196q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82q0 79 58 101z" />
-<glyph unicode="&#x158;" horiz-adv-x="1003" d="M388 1761q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM129 1465h315q218 0 355 -228q45 -89 45 -185v-15q0 -214 -208 -351l-10 -5q332 -573 332 -594v-19 q0 -81 -100 -98h-6q-73 0 -140 145l-301 514h-168v-561q0 -81 -100 -98h-6q-83 0 -102 103v1280q12 112 94 112zM243 1261v-425h185q156 0 206 169l3 27v28q0 123 -140 188q-39 13 -129 13h-125z" />
-<glyph unicode="&#x159;" horiz-adv-x="885" d="M433 1361q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM147 1061q98 -25 98 -94v-16q124 110 323 110q107 0 232 -54q43 -44 43 -85v-7q-17 -98 -101 -98h-9 q-103 33 -150 33h-22q-202 0 -296 -210q-20 -55 -20 -128v-444q0 -81 -100 -98h-6q-82 0 -101 102v874q12 115 109 115z" />
-<glyph unicode="&#x15a;" horiz-adv-x="929" d="M513 1467q201 0 337 -185l7 -25v-27q0 -74 -101 -91q-46 0 -125 88q-55 35 -106 35h-23q-108 0 -164 -117q-12 -26 -12 -52v-31q0 -124 150 -180q131 0 287 -126q151 -153 151 -336q0 -225 -193 -368q-118 -82 -261 -82q-232 0 -387 204l-11 43q19 103 104 103 q54 0 123 -88q83 -57 152 -57h34q134 0 217 153q13 49 13 73v38q0 133 -154 217l-195 54q-236 136 -236 356v27q0 218 231 340q87 34 162 34zM618 1893q94 0 110 -116q0 -55 -193 -227q-75 -93 -129 -93h-15q-99 19 -99 102v16q0 47 148 181q121 137 178 137z" />
-<glyph unicode="&#x15b;" horiz-adv-x="980" d="M612 1474q94 0 110 -116q0 -55 -192 -227q-76 -93 -130 -93h-15q-99 19 -99 102v16q0 47 149 181q120 137 177 137zM744 327q-1 20 -41 24q-506 113 -540 144q-103 78 -103 193q0 156 218 296q120 63 237 63q274 0 433 -253l4 -37v-6q0 -85 -102 -100q-68 0 -126 96 q-91 89 -209 89q-154 0 -241 -144l-2 -10q0 -20 86 -27q430 -104 475 -121q123 -81 123 -205v-3q0 -171 -242 -309q-105 -47 -221 -47q-240 0 -405 224q-21 30 -21 58v22q0 81 110 93q53 0 125 -103q88 -82 206 -82q140 0 232 131z" />
-<glyph unicode="&#x15c;" horiz-adv-x="885" d="M491 1467q201 0 337 -185l7 -25v-27q0 -74 -101 -91q-46 0 -125 88q-55 35 -106 35h-23q-108 0 -164 -117q-12 -26 -12 -52v-31q0 -124 150 -180q131 0 287 -126q151 -153 151 -336q0 -225 -193 -368q-118 -82 -261 -82q-232 0 -387 204l-11 43q19 103 104 103 q54 0 123 -88q83 -57 152 -57h34q134 0 217 153q13 49 13 73v38q0 133 -154 217l-195 54q-236 136 -236 356v27q0 218 231 340q87 34 162 34zM480 1564q-75 -101 -130 -101h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q63 0 159 -139q71 -71 71 -119v-15 q-21 -99 -102 -99h-12q-56 0 -130 101z" />
-<glyph unicode="&#x15d;" horiz-adv-x="969" d="M518 1149q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM744 327q-1 20 -41 24q-506 113 -540 144q-103 78 -103 193q0 156 218 296q120 63 237 63q274 0 433 -253 l4 -37v-6q0 -85 -102 -100q-68 0 -126 96q-91 89 -209 89q-154 0 -241 -144l-2 -10q0 -20 86 -27q430 -104 475 -121q123 -81 123 -205v-3q0 -171 -242 -309q-105 -47 -221 -47q-240 0 -405 224q-21 30 -21 58v22q0 81 110 93q53 0 125 -103q88 -82 206 -82q140 0 232 131z " />
-<glyph unicode="&#x15e;" horiz-adv-x="903" d="M558 -15q102 -68 102 -184q0 -169 -198 -218l-52 3h-51l-60 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -42 23q-62 30 -62 82v66q-171 17 -309 199l-11 43q19 103 104 103q54 0 123 -88q83 -57 152 -57h34q134 0 217 153q13 49 13 73v38q0 133 -154 217 l-195 54q-236 136 -236 356v27q0 218 231 340q87 34 162 34q201 0 337 -185l7 -25v-27q0 -74 -101 -91q-46 0 -125 88q-55 35 -106 35h-23q-108 0 -164 -117q-12 -26 -12 -52v-31q0 -124 150 -180q131 0 287 -126q151 -153 151 -336q0 -225 -193 -368q-77 -53 -141 -67z" />
-<glyph unicode="&#x15f;" horiz-adv-x="978" d="M748 327q-1 20 -41 24q-506 113 -540 144q-103 78 -103 193q0 156 218 296q120 63 237 63q274 0 433 -253l4 -37v-6q0 -85 -102 -100q-68 0 -126 96q-91 89 -209 89q-154 0 -241 -144l-2 -10q0 -20 86 -27q430 -104 475 -121q123 -81 123 -205v-3q0 -171 -242 -309 q-63 -28 -105 -35v-4q104 -69 104 -186q0 -169 -197 -218l-53 3h-50l-61 -3q-85 28 -85 89v17q17 90 93 90h121q36 0 36 22v3q0 15 -41 23q-63 30 -63 82v76q-179 20 -325 218q-21 30 -21 58v22q0 81 110 93q53 0 125 -103q88 -82 206 -82q140 0 232 131z" />
-<glyph unicode="&#x160;" horiz-adv-x="924" d="M486 1467q201 0 337 -185l7 -25v-27q0 -74 -101 -91q-46 0 -125 88q-55 35 -106 35h-23q-108 0 -164 -117q-12 -26 -12 -52v-31q0 -124 150 -180q131 0 287 -126q151 -153 151 -336q0 -225 -193 -368q-118 -82 -261 -82q-232 0 -387 204l-11 43q19 103 104 103 q54 0 123 -88q83 -57 152 -57h34q134 0 217 153q13 49 13 73v38q0 133 -154 217l-195 54q-236 136 -236 356v27q0 218 231 340q87 34 162 34zM481 1751q75 101 131 101h15q99 -21 99 -102v-12q0 -47 -103 -159q-67 -99 -127 -99h-28q-63 0 -155 135q-75 75 -75 123v15 q20 99 102 99h12q55 0 129 -101z" />
-<glyph unicode="&#x161;" horiz-adv-x="977" d="M512 1374q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM735 327q-1 20 -41 24q-506 113 -540 144q-103 78 -103 193q0 156 218 296q120 63 237 63q274 0 433 -253 l4 -37v-6q0 -85 -102 -100q-68 0 -126 96q-91 89 -209 89q-154 0 -241 -144l-2 -10q0 -20 86 -27q430 -104 475 -121q123 -81 123 -205v-3q0 -171 -242 -309q-105 -47 -221 -47q-240 0 -405 224q-21 30 -21 58v22q0 81 110 93q53 0 125 -103q88 -82 206 -82q140 0 232 131z " />
-<glyph unicode="&#x162;" horiz-adv-x="1219" d="M138 1466h936q95 -18 95 -98v-15q0 -82 -111 -94h-348v-1191q0 -81 -100 -98h-5q-83 0 -102 103v1186h-356q-103 20 -103 108q22 99 94 99zM563 -43h28q108 0 142 -170v-15q0 -97 -162 -178q-36 -12 -59 -12q-31 7 -55 33v28q60 87 60 134v7q0 26 -48 75v29q24 69 94 69z " />
-<glyph unicode="&#x163;" horiz-adv-x="730" d="M322 1420h17q93 -20 93 -89v-300h119l33 4q77 0 101 -100q0 -75 -88 -107l-60 4h-105v-509q0 -120 68 -143l79 -7h40q73 0 92 -97v-9q-17 -97 -100 -97h-77q-194 0 -288 210q-17 53 -17 121v531h-42l-64 -4q-88 31 -88 106q17 97 66 97v7l69 -7h59v280q12 109 93 109z M422 -27h28q108 0 142 -170v-15q0 -97 -162 -178q-36 -12 -59 -12q-31 7 -55 33v28q60 87 60 134v7q0 26 -48 75v29q24 69 94 69z" />
-<glyph unicode="&#x164;" horiz-adv-x="1224" d="M618 1766q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM147 1466h936q95 -18 95 -98v-15q0 -82 -111 -94h-348v-1191q0 -81 -100 -98h-5q-83 0 -102 103v1186h-356 q-103 20 -103 108q22 99 94 99z" />
-<glyph unicode="&#x165;" horiz-adv-x="757" d="M367 1730q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM349 1420h17q93 -20 93 -89v-300h119l33 4q77 0 101 -100q0 -75 -88 -107l-60 4h-105v-509q0 -120 68 -143 l79 -7h40q73 0 92 -97v-9q-17 -97 -100 -97h-77q-194 0 -288 210q-17 53 -17 121v531h-42l-64 -4q-88 31 -88 106q17 97 66 97v7l69 -7h59v280q12 109 93 109z" />
-<glyph unicode="&#x166;" horiz-adv-x="1197" d="M507 611h-254l-69 -4q-94 33 -94 113q18 103 72 103v7l71 -7h274v436h-356q-103 20 -103 108q22 99 94 99h936q95 -18 95 -98v-15q0 -82 -111 -94h-348v-436h236l36 4q85 0 108 -107q0 -75 -89 -113l-74 4h-217v-543q0 -81 -100 -98h-5q-83 0 -102 103v538z" />
-<glyph unicode="&#x167;" horiz-adv-x="748" d="M242 648v184h-42l-64 -4q-88 31 -88 106q17 97 66 97v7l69 -7h59v280q12 109 93 109h17q93 -20 93 -89v-300h119l33 4q77 0 101 -100q0 -75 -88 -107l-60 4h-105v-184h116l34 4q78 0 103 -106q0 -79 -89 -114l-62 4h-102v-113q0 -120 68 -143l79 -7h40q73 0 92 -97v-9 q-17 -97 -100 -97h-77q-194 0 -288 210q-17 53 -17 121v135h-35l-65 -4q-90 33 -90 112q16 104 68 104v7l69 -7h53z" />
-<glyph unicode="&#x168;" horiz-adv-x="1219" d="M160 1463h18q95 -20 95 -90v-806q0 -243 135 -323q86 -67 191 -67q202 0 305 208q21 65 21 137v843q17 98 98 98h14q95 -18 95 -98v-881q0 -240 -228 -417q-145 -97 -294 -97h-26q-250 0 -434 244q-84 132 -84 323v815q12 111 94 111zM491 1745h19q79 0 174 -65l21 -5h10 l77 23q105 -21 105 -105q0 -100 -168 -122h-28q-78 0 -174 65l-21 5h-11l-70 -18h-14q-93 18 -93 96v11q0 79 102 103q33 12 71 12z" />
-<glyph unicode="&#x169;" horiz-adv-x="1131" d="M451 1344h19q79 0 174 -65l21 -5h10l77 23q105 -21 105 -105q0 -100 -168 -122h-28q-78 0 -174 65l-21 5h-11l-70 -18h-14q-93 18 -93 96v11q0 79 102 103q33 12 71 12zM874 77q-138 -107 -303 -107h-25q-242 0 -420 236q-82 128 -82 313v399q11 114 107 114 q96 -25 96 -93v-391q0 -234 129 -311q83 -64 184 -64q195 0 294 200q20 65 20 131v427q19 101 107 101q95 -23 95 -100v-870q0 -73 -96 -92h-10q-96 17 -96 99v8z" />
-<glyph unicode="&#x16a;" horiz-adv-x="1135" d="M129 1463h18q95 -20 95 -90v-806q0 -243 135 -323q86 -67 191 -67q202 0 305 208q21 65 21 137v843q17 98 98 98h14q95 -18 95 -98v-881q0 -240 -228 -417q-145 -97 -294 -97h-26q-250 0 -434 244q-84 132 -84 323v815q12 111 94 111zM208 1746l65 -8h602l30 4 q77 0 96 -107q0 -73 -78 -114l-64 5h-570l-60 -4q-82 34 -82 112q15 104 61 104v8z" />
-<glyph unicode="&#x16b;" horiz-adv-x="1135" d="M282 1329l524 1q107 -19 107 -101v-14q-13 -98 -106 -98h-538q-92 0 -101 113q18 99 114 99zM865 77q-138 -107 -303 -107h-25q-242 0 -420 236q-82 128 -82 313v399q11 114 107 114q96 -25 96 -93v-391q0 -234 129 -311q83 -64 184 -64q195 0 294 200q20 65 20 131v427 q19 101 107 101q95 -23 95 -100v-870q0 -73 -96 -92h-10q-96 17 -96 99v8z" />
-<glyph unicode="&#x16c;" horiz-adv-x="1149" d="M371 1830h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM129 1463h18q95 -20 95 -90v-806q0 -243 135 -323q86 -67 191 -67q202 0 305 208q21 65 21 137v843 q17 98 98 98h14q95 -18 95 -98v-881q0 -240 -228 -417q-145 -97 -294 -97h-26q-250 0 -434 244q-84 132 -84 323v815q12 111 94 111z" />
-<glyph unicode="&#x16d;" horiz-adv-x="1171" d="M358 1426h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99zM892 77q-138 -107 -303 -107h-25q-242 0 -420 236q-82 128 -82 313v399q11 114 107 114q96 -25 96 -93 v-391q0 -234 129 -311q83 -64 184 -64q195 0 294 200q20 65 20 131v427q19 101 107 101q95 -23 95 -100v-870q0 -73 -96 -92h-10q-96 17 -96 99v8z" />
-<glyph unicode="&#x16e;" horiz-adv-x="1127" d="M125 1463h18q95 -20 95 -90v-806q0 -243 135 -323q86 -67 191 -67q202 0 305 208q21 65 21 137v843q17 98 98 98h14q95 -18 95 -98v-881q0 -240 -228 -417q-145 -97 -294 -97h-26q-250 0 -434 244q-84 132 -84 323v815q12 111 94 111zM570 1862h17q142 0 203 -170l5 -43 v-13q0 -138 -162 -203l-50 -9q-134 0 -204 131q-22 47 -22 92q0 148 171 210zM534 1643q8 -41 40 -41q44 7 44 38v8q-6 37 -34 37h-12q-31 0 -38 -42z" />
-<glyph unicode="&#x16f;" horiz-adv-x="1180" d="M575 1435h17q142 0 203 -170l5 -43v-13q0 -138 -162 -203l-50 -9q-134 0 -204 131q-22 47 -22 92q0 148 171 210zM539 1216q8 -41 40 -41q44 7 44 38v8q-6 37 -34 37h-12q-31 0 -38 -42zM892 77q-138 -107 -303 -107h-25q-242 0 -420 236q-82 128 -82 313v399 q11 114 107 114q96 -25 96 -93v-391q0 -234 129 -311q83 -64 184 -64q195 0 294 200q20 65 20 131v427q19 101 107 101q95 -23 95 -100v-870q0 -73 -96 -92h-10q-96 17 -96 99v8z" />
-<glyph unicode="&#x170;" horiz-adv-x="1175" d="M585 1864h7q103 -18 103 -102v-20q0 -31 -175 -259q-28 -31 -59 -31h-8q-56 0 -74 70v18q110 275 140 302q37 22 66 22zM836 1852q107 -21 107 -110q0 -42 -114 -185q-75 -117 -120 -117h-12q-56 0 -74 70q0 27 117 293q47 49 96 49zM151 1463h18q95 -20 95 -90v-806 q0 -243 135 -323q86 -67 191 -67q202 0 305 208q21 65 21 137v843q17 98 98 98h14q95 -18 95 -98v-881q0 -240 -228 -417q-145 -97 -294 -97h-26q-250 0 -434 244q-84 132 -84 323v815q12 111 94 111z" />
-<glyph unicode="&#x171;" horiz-adv-x="1144" d="M545 1433h7q103 -18 103 -102v-20q0 -31 -175 -259q-28 -31 -59 -31h-8q-56 0 -74 70v18q110 275 140 302q37 22 66 22zM796 1421q107 -21 107 -110q0 -42 -114 -185q-75 -117 -120 -117h-12q-56 0 -74 70q0 27 117 293q47 49 96 49zM874 77q-138 -107 -303 -107h-25 q-242 0 -420 236q-82 128 -82 313v399q11 114 107 114q96 -25 96 -93v-391q0 -234 129 -311q83 -64 184 -64q195 0 294 200q20 65 20 131v427q19 101 107 101q95 -23 95 -100v-870q0 -73 -96 -92h-10q-96 17 -96 99v8z" />
-<glyph unicode="&#x172;" horiz-adv-x="1202" d="M493 -23q-186 25 -347 237q-84 132 -84 323v815q12 111 94 111h18q95 -20 95 -90v-806q0 -243 135 -323q86 -67 191 -67q202 0 305 208q21 65 21 137v843q17 98 98 98h14q95 -18 95 -98v-881q0 -240 -228 -417q-114 -76 -204 -89v-69q0 -84 -99 -99q-7 -4 -7 -17 q0 -23 37 -23h98l18 5q101 -23 101 -98v-7q0 -67 -81 -97l-80 4h-34l-56 -4q-86 0 -170 106q-30 57 -30 100v28q0 111 100 170z" />
-<glyph unicode="&#x173;" horiz-adv-x="1211" d="M883 77q-138 -107 -303 -107h-25q-242 0 -420 236q-82 128 -82 313v399q11 114 107 114q96 -25 96 -93v-391q0 -234 129 -311q83 -64 184 -64q195 0 294 200q20 65 20 131v427q19 101 107 101q95 -23 95 -100v-858q1 -4 3 -16v-105q0 -84 -99 -99q-7 -4 -7 -17 q0 -23 37 -23h98l18 5q101 -23 101 -98v-7q0 -67 -81 -97l-80 4h-34l-56 -4q-86 0 -170 106q-30 57 -30 100v28q0 113 105 172l-1 9q-6 13 -6 37v8z" />
-<glyph unicode="&#x174;" horiz-adv-x="1778" d="M906 1598q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM898 993l-280 -973q-41 -50 -88 -50h-15q-88 0 -114 167q-324 1105 -353 1227q23 102 95 102h16 q89 0 112 -137l254 -885q270 949 292 985q36 37 77 37h11q93 0 116 -159q25 -69 250 -861l282 970q39 50 80 50h18q95 -20 95 -90v-23l-387 -1339q-45 -44 -86 -44h-4q-97 0 -121 164z" />
-<glyph unicode="&#x175;" horiz-adv-x="1422" d="M712 1127q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM702 600l-188 -581q-37 -49 -86 -49h-3q-74 0 -103 87l-278 876q21 106 105 106q93 0 124 -171l153 -468 q183 580 201 604q35 30 76 35q93 0 119 -145l160 -494q174 550 194 593q43 46 87 46q101 -20 101 -109l-295 -918q-45 -42 -85 -42h-3q-93 0 -125 166z" />
-<glyph unicode="&#x176;" horiz-adv-x="1167" d="M576 897q353 531 372 545q28 21 52 21h23q69 0 94 -98q0 -46 -135 -230l-301 -450v-604q-13 -111 -94 -111h-16q-72 0 -98 86v626q0 5 -154 234l-273 411l-6 35q23 101 95 101h16q69 0 105 -88zM581 1551q-75 -101 -130 -101h-16q-98 21 -98 102v12q0 50 126 186 q45 72 104 72h28q63 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 101z" />
-<glyph unicode="&#x177;" horiz-adv-x="964" d="M519 1153q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100zM499 383q249 607 269 630q35 29 73 29q96 -18 96 -96v-6q-4 -31 -347 -849q-163 -405 -188 -437 q-25 -19 -65 -30q-101 22 -101 91v17q0 19 155 393l-330 805v12q19 96 100 96t129 -158z" />
-<glyph unicode="&#x178;" horiz-adv-x="1149" d="M576 897q353 531 372 545q28 21 52 21h23q69 0 94 -98q0 -46 -135 -230l-301 -450v-604q-13 -111 -94 -111h-16q-72 0 -98 86v626q0 5 -154 234l-273 411l-6 35q23 101 95 101h16q69 0 105 -88zM426 1717h18q95 -20 95 -90v-19q0 -80 -103 -99q-104 21 -104 110 q22 98 94 98zM712 1717h18q95 -21 95 -94v-11q0 -86 -106 -102q-101 19 -101 102v11q0 73 94 94z" />
-<glyph unicode="&#x179;" horiz-adv-x="1272" d="M734 1837q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM125 1467h1021q80 0 98 -99v-6q0 -40 -90 -145l-804 -1039h794q100 -15 100 -102v-7q-18 -99 -102 -99h-1009q-86 0 -102 108q0 41 188 275l703 907 h-788q-103 20 -103 108q22 99 94 99z" />
-<glyph unicode="&#x17a;" horiz-adv-x="973" d="M601 1419q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM110 1045l69 -7h635l39 5q93 -29 93 -94v-22q0 -35 -92 -135l-493 -618h492q93 -18 93 -96v-12q0 -79 -97 -96h-705q-85 0 -100 106q0 42 158 224 l427 538h-432l-64 -4q-89 31 -89 107q17 97 66 97v7z" />
-<glyph unicode="&#x17b;" horiz-adv-x="1325" d="M670 1827q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM138 1467h1021q80 0 98 -99v-6q0 -40 -90 -145l-804 -1039h794q100 -15 100 -102v-7q-18 -99 -102 -99h-1009q-86 0 -102 108q0 41 188 275l703 907h-788 q-103 20 -103 108q22 99 94 99z" />
-<glyph unicode="&#x17c;" horiz-adv-x="1004" d="M512 1387q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9zM106 1045l69 -7h635l39 5q93 -29 93 -94v-22q0 -35 -92 -135l-493 -618h492q93 -18 93 -96v-12q0 -79 -97 -96h-705q-85 0 -100 106q0 42 158 224l427 538h-432 l-64 -4q-89 31 -89 107q17 97 66 97v7z" />
-<glyph unicode="&#x17d;" horiz-adv-x="1294" d="M666 1766q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM142 1467h1021q80 0 98 -99v-6q0 -40 -90 -145l-804 -1039h794q100 -15 100 -102v-7q-18 -99 -102 -99h-1009 q-86 0 -102 108q0 41 188 275l703 907h-788q-103 20 -103 108q22 99 94 99z" />
-<glyph unicode="&#x17e;" horiz-adv-x="978" d="M521 1388q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100zM106 1045l69 -7h635l39 5q93 -29 93 -94v-22q0 -35 -92 -135l-493 -618h492q93 -18 93 -96v-12q0 -79 -97 -96 h-705q-85 0 -100 106q0 42 158 224l427 538h-432l-64 -4q-89 31 -89 107q17 97 66 97v7z" />
-<glyph unicode="&#x17f;" horiz-adv-x="616" d="M413 1467h93q78 0 94 -108q0 -77 -102 -100h-61q-115 0 -152 -127l-3 -75v-946l3 -42q0 -76 -101 -99q-76 0 -110 90l4 51v749l-4 145v68q0 274 245 377z" />
-<glyph unicode="&#x192;" horiz-adv-x="973" d="M732 1454h98q82 0 98 -112q0 -80 -106 -104h-64q-123 0 -162 -135l-4 -80v-25h141l64 4q76 0 99 -103v-15q0 -73 -98 -98h-206v-729l4 -98q-16 -117 -87 -210q-128 -135 -279 -135h-84q-84 0 -102 106q17 110 106 110h52q117 0 165 102q13 35 13 124v730h-178 q-82 0 -98 112q0 61 88 104l87 -4h97v42q0 289 258 397z" />
-<glyph unicode="&#x1fa;" horiz-adv-x="1266" d="M756 716l-120 303l-118 -303h238zM585 1474q9 -46 46 -46q52 9 52 40v12q-6 39 -38 39h-16q-36 0 -44 -45zM745 1309q5 -8 19 -63q457 -1136 462 -1169v-12q0 -80 -100 -95h-6q-90 0 -123 143l-161 401h-402l-203 -511q-45 -33 -78 -33h-9q-100 17 -100 99v10l130 336 q319 791 354 893q-30 16 -65 81q-19 43 -19 81q0 103 54 136h1q2 0 2 4q0 11 -8 45v9q0 41 109 164q42 58 92 58q93 -21 93 -93v-6q0 -40 -79 -127q-8 -12 -8 -15h1q2 0 15 14q56 0 111 -149l3 -39v-10q0 -110 -85 -152z" />
-<glyph unicode="&#x1fb;" horiz-adv-x="1171" d="M586 1477q124 0 193 -127q21 -45 21 -90q0 -144 -166 -204l-42 -5h-16q-139 0 -198 166l-5 41v13q0 146 175 203zM547 1268v-11q9 -32 29 -32h14q30 0 36 39q-7 40 -36 40q-43 -7 -43 -36zM671 1828q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4 q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM243 509v-11q0 -200 202 -301q62 -24 112 -24h30q166 0 274 168q40 78 40 150v15q0 192 -192 295q-66 30 -137 30h-4q-202 0 -305 -212q-20 -65 -20 -110zM902 81q-120 -111 -315 -111h-30q-271 0 -451 271q-66 132 -66 265 q0 297 291 470q124 58 241 58q302 0 478 -294q54 -122 54 -249v-425q0 -79 -97 -96h-6q-68 0 -100 79v11z" />
-<glyph unicode="&#x1fc;" horiz-adv-x="1615" d="M1062 1860q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM867 1465h595q69 0 95 -101q-21 -106 -107 -106h-470v-508h363q96 -21 96 -91v-19q0 -81 -100 -98h-359v-364h474q83 0 102 -103q0 -83 -103 -105h-578 q-83 0 -102 103v469h-233q-9 -11 -154 -281l-147 -257q-39 -34 -76 -34h-4q-86 0 -102 108q0 32 246 463l496 891q40 33 68 33zM657 750h116v207z" />
-<glyph unicode="&#x1fd;" horiz-adv-x="2042" d="M1115 1393q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM246 511v-11q0 -199 201 -300q63 -24 113 -24h29q165 0 273 168q40 77 40 149v14q0 192 -191 295q-66 30 -137 30h-3q-202 0 -305 -211 q-20 -65 -20 -110zM1115 574h638v-26q0 84 -107 197q-102 79 -214 79q-171 0 -277 -160q-40 -75 -40 -90zM903 84q-118 -110 -314 -110h-29q-271 0 -450 270q-66 131 -66 263q0 297 290 469q124 58 240 58q266 0 432 -223q88 133 271 196q89 23 159 23q296 0 468 -286 q58 -120 58 -226v-50q-17 -96 -99 -96h-726q36 -85 115 -139q87 -57 180 -57q81 0 188 54l29 5q102 -24 102 -104q0 -119 -268 -157l-54 -4q-205 0 -325 111v-12q0 -89 -105 -99h-5q-58 0 -92 83z" />
-<glyph unicode="&#x1fe;" horiz-adv-x="1655" d="M909 1855q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM1277 971l-762 -713q117 -82 283 -82h18q252 0 427 225q99 142 99 312q0 135 -65 258zM1145 1131q-155 119 -340 119q-266 0 -441 -232 q-96 -138 -96 -312q0 -184 101 -305zM363 116q-147 -142 -174 -142l-19 -4h-7q-85 0 -101 107q0 52 129 159q4 12 23 25q-152 194 -152 456q0 355 312 598q205 141 431 141q278 0 490 -187q138 142 182 142h12q97 -25 97 -101v-7q0 -57 -115 -147l-42 -41q119 -182 119 -406 q0 -371 -335 -618q-192 -121 -400 -121h-15q-236 0 -435 146z" />
-<glyph unicode="&#x1ff;" horiz-adv-x="1188" d="M683 1442q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM283 357l426 440q-35 24 -136 24q-207 0 -303 -217q-16 -52 -16 -95v-18q0 -71 29 -134zM858 660l-435 -450q56 -34 143 -34h21q189 0 289 196 q23 61 23 119v18q0 98 -41 151zM991 1042h4q84 0 99 -105q0 -44 -91 -131q102 -125 102 -307q0 -298 -281 -467q-122 -62 -237 -62h-29q-146 0 -278 92q-73 -88 -126 -88h-14q-77 0 -92 104q0 45 88 130q-88 121 -88 291q0 257 228 431q145 97 301 97q155 0 277 -81 q78 96 137 96z" />
-<glyph unicode="&#x2c6;" horiz-adv-x="1024" d="M557 1189q-74 -100 -130 -100h-15q-99 21 -99 102v12q0 50 126 186q45 72 104 72h28q64 0 159 -139q71 -71 71 -119v-15q-21 -99 -102 -99h-12q-56 0 -130 100z" />
-<glyph unicode="&#x2c7;" horiz-adv-x="1024" d="M530 1360q74 100 130 100h15q99 -21 99 -102v-12q0 -47 -102 -159q-68 -99 -128 -99h-28q-63 0 -155 135q-75 75 -75 123v15q21 99 102 99h12q56 0 130 -100z" />
-<glyph unicode="&#x2c9;" horiz-adv-x="1059" d="M309 1355l71 -7h397l36 4q81 0 108 -106q0 -80 -94 -114l-65 4h-362l-69 -4q-94 33 -94 113q18 103 72 103v7z" />
-<glyph unicode="&#x2d8;" horiz-adv-x="1024" d="M331 1395h12q73 0 110 -98q40 -46 94 -46q82 0 122 98q43 46 86 46h11q103 -18 103 -106v-4q0 -98 -172 -219q-84 -31 -146 -31h-8q-211 0 -314 228v33q21 99 102 99z" />
-<glyph unicode="&#x2d9;" horiz-adv-x="1024" d="M569 1392q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9z" />
-<glyph unicode="&#x2da;" horiz-adv-x="1024" d="M546 1477q124 0 193 -127q21 -45 21 -90q0 -144 -166 -204l-42 -5h-16q-139 0 -198 166l-5 41v13q0 146 175 203zM507 1268v-11q9 -32 29 -32h14q30 0 36 39q-7 40 -36 40q-43 -7 -43 -36z" />
-<glyph unicode="&#x2db;" horiz-adv-x="1024" d="M436 -56l-3 47q30 86 97 86h7q79 0 97 -97v-106q0 -84 -99 -99q-7 -4 -7 -17q0 -23 37 -23h98l18 5q101 -23 101 -98v-7q0 -67 -81 -97l-80 4h-34l-56 -4q-86 0 -170 106q-30 57 -30 100v28q0 113 105 172z" />
-<glyph unicode="&#x2dc;" horiz-adv-x="1024" d="M479 1725q91 0 202 -72l20 -2l75 22h13q100 -17 100 -102v-4q0 -96 -150 -120l-40 -4q-91 0 -194 73l-17 2l-84 -23q-106 20 -106 102v8q0 99 164 117z" />
-<glyph unicode="&#x2dd;" horiz-adv-x="1024" d="M470 1459h7q103 -18 103 -102v-20q0 -31 -175 -259q-28 -31 -59 -31h-8q-56 0 -74 70v18q110 275 140 302q37 22 66 22zM721 1447q107 -21 107 -110q0 -42 -114 -185q-75 -117 -120 -117h-12q-56 0 -74 70q0 27 117 293q47 49 96 49z" />
-<glyph unicode="&#x384;" horiz-adv-x="392" d="M314 1455q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63z" />
-<glyph unicode="&#x385;" horiz-adv-x="797" d="M507 1420q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM186 1339q106 -25 106 -113q-21 -107 -113 -107q-107 21 -107 114q25 106 114 106zM698 1339q106 -25 106 -113q-21 -107 -113 -107q-107 21 -107 114 q25 106 114 106z" />
-<glyph unicode="&#x386;" horiz-adv-x="1254" d="M402 1551q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM744 744l-121 317l-117 -317h238zM621 1458q93 0 131 -160q454 -1183 459 -1217v-13q0 -81 -98 -98h-7q-90 0 -123 149l-161 418h-398l-202 -533 q-45 -34 -78 -34h-11q-98 18 -98 101v9l130 352q335 872 365 973q48 53 91 53z" />
-<glyph unicode="&#x387;" horiz-adv-x="405" d="M234 1032q114 0 146 -133v-25q0 -83 -99 -128q-18 -9 -47 -9h-3q-121 0 -146 146q0 99 104 140q17 9 45 9z" />
-<glyph unicode="&#x388;" horiz-adv-x="1347" d="M393 1473l52 -11h733l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-785q-99 18 -99 102v1290q15 100 72 100v11zM222 1490q100 -23 100 -100v-7q0 -43 -87 -139 q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63z" />
-<glyph unicode="&#x389;" horiz-adv-x="1466" d="M221 1455q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM420 1467h18q95 -20 95 -90v-568h652v560q17 98 98 98h14q95 -18 95 -98v-1301q0 -73 -99 -94h-10q-98 18 -98 102v530h-652v-534q0 -81 -98 -98h-7 q-83 0 -102 103v1279q12 111 94 111z" />
-<glyph unicode="&#x38a;" horiz-adv-x="748" d="M213 1482q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM420 1479l23 -4h137l18 4q106 -23 106 -110q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10q-18 -99 -102 -99h-183q-99 18 -99 102v7q21 100 95 100 h-7v1087h14q-90 0 -102 108v6q0 70 100 99z" />
-<glyph unicode="&#x38c;" horiz-adv-x="1734" d="M252 1478q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM942 1465q378 0 632 -350q115 -199 115 -401q0 -374 -338 -622q-192 -122 -402 -122h-15q-386 0 -629 358q-111 182 -111 393q0 358 314 602 q205 142 434 142zM401 710q0 -259 230 -437q142 -96 303 -96h19q253 0 429 226q100 144 100 315q0 293 -269 464q-132 76 -271 76q-268 0 -445 -234q-96 -138 -96 -314z" />
-<glyph unicode="&#x38e;" horiz-adv-x="1457" d="M270 1473q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM911 896q352 532 371 546q28 21 52 21h23q69 0 94 -98q0 -46 -134 -230l-302 -450v-604q-12 -111 -94 -111h-16q-71 0 -98 86v626q0 5 -154 234 l-272 411l-7 35q23 101 95 101h16q69 0 106 -88z" />
-<glyph unicode="&#x38f;" horiz-adv-x="1646" d="M279 179q-58 56 -111 137q-111 194 -111 408q0 351 321 603q208 140 433 140q382 0 638 -354q116 -206 116 -389q0 -314 -223 -542h93q100 -19 100 -94v-19q-21 -95 -99 -95h-492q-86 0 -103 112q27 96 100 96q95 0 268 148q151 177 151 386q0 258 -232 445 q-153 97 -302 97h-30q-258 0 -436 -235q-98 -151 -98 -307q0 -314 291 -488q48 -30 168 -58q67 -28 67 -105q-27 -95 -103 -95h-487q-103 20 -103 109q23 100 103 100h81zM237 1469q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180 q46 63 100 63z" />
-<glyph unicode="&#x390;" horiz-adv-x="740" d="M450 1827q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM129 1746q106 -25 106 -113q-21 -107 -113 -107q-107 21 -107 114q25 106 114 106zM641 1746q106 -25 106 -113q-21 -107 -113 -107q-107 21 -107 114 q25 106 114 106zM297 1479l23 -4h137l18 4q106 -23 106 -110q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10q-18 -99 -102 -99h-183q-99 18 -99 102v7q21 100 95 100h-7v1087h14q-90 0 -102 108v6q0 70 100 99z" />
-<glyph unicode="&#x391;" horiz-adv-x="1246" d="M744 744l-121 317l-117 -317h238zM621 1458q93 0 131 -160q454 -1183 459 -1217v-13q0 -81 -98 -98h-7q-90 0 -123 149l-161 418h-398l-202 -533q-45 -34 -78 -34h-11q-98 18 -98 101v9l130 352q335 872 365 973q48 53 91 53z" />
-<glyph unicode="&#x392;" horiz-adv-x="991" d="M125 1467l50 -8h225l15 3q190 0 321 -175q67 -98 67 -213v-11q0 -140 -85 -237q228 -125 228 -400q0 -276 -286 -424q-93 -32 -166 -32h-342q-99 18 -99 102v1287q15 100 72 100v8zM260 1252v-363h109q165 0 210 113q13 33 13 65v11q0 124 -145 170l-75 4h-112zM260 682 v-505h166q199 0 265 110q44 63 44 139v7q0 181 -198 242l-101 7h-176z" />
-<glyph unicode="&#x393;" horiz-adv-x="1030" d="M151 1463h733q95 -20 95 -90v-19q0 -81 -100 -98h-615v-1188q0 -81 -98 -98h-7q-83 0 -102 103v1279q12 111 94 111z" />
-<glyph unicode="&#x394;" horiz-adv-x="1242" d="M645 1104l-351 -923h674q-319 847 -323 923zM625 1462h12q83 0 116 -138q460 -1201 469 -1245v-7q0 -67 -81 -102l-90 4h-840l-86 -4q-85 31 -85 114l503 1334q41 44 82 44z" />
-<glyph unicode="&#x395;" horiz-adv-x="1109" d="M129 1473l52 -11h733l15 4q95 0 110 -114q-21 -97 -113 -97h-662v-450h423l53 3q76 0 99 -102q0 -72 -85 -109l-82 4h-408v-424h681q78 0 95 -111q-29 -96 -99 -96h-785q-99 18 -99 102v1290q15 100 72 100v11z" />
-<glyph unicode="&#x396;" horiz-adv-x="1342" d="M177 1467h1021q80 0 98 -99v-6q0 -40 -90 -145l-804 -1039h794q100 -15 100 -102v-7q-18 -99 -102 -99h-1009q-86 0 -102 108q0 41 188 275l703 907h-788q-103 20 -103 108q22 99 94 99z" />
-<glyph unicode="&#x397;" horiz-adv-x="1223" d="M169 1467h18q95 -20 95 -90v-568h652v560q17 98 98 98h14q95 -18 95 -98v-1301q0 -73 -99 -94h-10q-98 18 -98 102v530h-652v-534q0 -81 -98 -98h-7q-83 0 -102 103v1279q12 111 94 111z" />
-<glyph unicode="&#x398;" horiz-adv-x="1611" d="M816 1461q377 0 631 -349q114 -198 114 -400q0 -373 -337 -620q-192 -122 -401 -122h-15q-384 0 -628 357q-110 182 -110 392q0 357 313 600q205 142 433 142zM277 708q0 -259 229 -435q141 -96 302 -96h19q252 0 428 225q99 143 99 314q0 292 -268 463q-131 75 -270 75 q-268 0 -443 -233q-96 -138 -96 -313zM455 817h721q99 -18 99 -101v-7q-18 -99 -102 -99h-722q-95 21 -95 98v15q0 73 99 94z" />
-<glyph unicode="&#x399;" horiz-adv-x="581" d="M209 1479l23 -4h137l18 4q106 -23 106 -110q-18 -103 -102 -103h14v-1087h-7q74 0 95 -100v-10q-18 -99 -102 -99h-183q-99 18 -99 102v7q21 100 95 100h-7v1087h14q-90 0 -102 108v6q0 70 100 99z" />
-<glyph unicode="&#x39a;" horiz-adv-x="1118" d="M148 1464h5q100 -17 100 -98v-581q658 657 674 657l27 4h12q95 -18 95 -98v-12q0 -51 -89 -124l-445 -448l522 -646l4 -33v-13q0 -81 -98 -98h-7q-61 0 -149 129l-423 513l-123 -126v-422q0 -81 -100 -98h-5q-83 0 -102 102v1290q19 102 102 102z" />
-<glyph unicode="&#x39b;" horiz-adv-x="1232" d="M646 1116l-417 -1103q-45 -43 -87 -43h-4q-86 0 -103 113l506 1341q41 44 83 44h11q84 0 116 -138q463 -1206 472 -1251v-10q-18 -99 -102 -99h-4q-73 0 -104 88q-365 975 -367 1058z" />
-<glyph unicode="&#x39c;" horiz-adv-x="1479" d="M267 874v-806q0 -81 -98 -98h-7q-83 0 -102 103v1278q12 111 94 111h15q83 0 111 -118l459 -1026q9 35 302 703l188 405q34 36 74 36h15q82 0 94 -111v-1278q-19 -103 -102 -103h-7q-98 17 -98 98v807q-372 -842 -389 -869q-41 -36 -80 -36q-88 0 -145 178z" />
-<glyph unicode="&#x39d;" horiz-adv-x="1329" d="M1064 374v992q18 95 98 95h11q81 0 98 -98v-1288q0 -87 -107 -105q-61 0 -158 144l-733 936v-978q0 -81 -100 -98h-5q-83 0 -102 102v1274q12 111 94 111h15q67 0 108 -88q53 -60 781 -999z" />
-<glyph unicode="&#x39e;" horiz-adv-x="1158" d="M139 1462h879q95 -18 95 -98v-15q0 -82 -112 -94h-853q-103 20 -103 108q22 99 94 99zM261 833h638q100 -17 100 -102v-6q-18 -99 -102 -99h-636q-83 0 -103 106q25 101 103 101zM147 178h866q100 -18 100 -98v-15q-19 -95 -98 -95h-868q-83 0 -103 107q25 101 103 101z " />
-<glyph unicode="&#x39f;" horiz-adv-x="1620" d="M823 1465q378 0 632 -350q115 -199 115 -401q0 -374 -338 -622q-192 -122 -402 -122h-15q-386 0 -629 358q-111 182 -111 393q0 358 314 602q205 142 434 142zM282 710q0 -259 230 -437q142 -96 303 -96h19q253 0 429 226q100 144 100 315q0 293 -269 464 q-132 76 -271 76q-268 0 -445 -234q-96 -138 -96 -314z" />
-<glyph unicode="&#x3a0;" horiz-adv-x="1184" d="M160 1461h875q95 -18 95 -98v-1299q0 -73 -99 -94h-9q-99 18 -99 102v1181h-650v-1185q0 -81 -100 -98h-5q-83 0 -102 102v1277q12 112 94 112z" />
-<glyph unicode="&#x3a1;" horiz-adv-x="946" d="M151 1468h346q218 0 371 -224q57 -115 57 -208v-27q0 -203 -183 -350q-125 -86 -245 -86h-232v-505q0 -80 -99 -98h-7q-83 0 -102 103v1283q12 112 94 112zM265 1260v-479h205q170 0 234 163q13 33 13 80q0 148 -154 220q-35 16 -85 16h-213z" />
-<glyph unicode="&#x3a3;" horiz-adv-x="1124" d="M395 166h569q93 -17 93 -93v-13q-17 -90 -92 -90h-797q-78 0 -96 97q0 46 86 121l401 466l-472 543q-15 27 -15 55q21 93 89 93h807q89 -17 89 -93v-14q0 -77 -104 -89h-566q369 -422 395 -460l4 -29v-13q0 -46 -85 -125z" />
-<glyph unicode="&#x3a4;" horiz-adv-x="1262" d="M159 1466h936q95 -18 95 -98v-15q0 -82 -111 -94h-348v-1191q0 -81 -100 -98h-5q-83 0 -102 103v1186h-356q-103 20 -103 108q22 99 94 99z" />
-<glyph unicode="&#x3a5;" horiz-adv-x="1237" d="M614 897q353 531 372 545q28 21 52 21h23q69 0 94 -98q0 -46 -135 -230l-301 -450v-604q-13 -111 -94 -111h-16q-72 0 -98 86v626q0 5 -154 234l-273 411l-6 35q23 101 95 101h16q69 0 105 -88z" />
-<glyph unicode="&#x3a6;" horiz-adv-x="1629" d="M913 301q128 11 292 125q145 134 145 277v34q0 192 -233 334q-81 49 -204 67v-837zM267 722q0 -243 296 -383q117 -39 142 -39v839q-145 -16 -286 -122q-152 -136 -152 -295zM803 1469h14q96 -18 96 -98v-48q163 -13 362 -125q287 -201 287 -480q0 -262 -263 -457 q-119 -91 -352 -139h-6q-28 0 -28 19v-76q0 -74 -99 -95h-10q-99 18 -99 102v46h26q-146 0 -361 110q-311 199 -311 494q0 280 290 476q121 89 356 123v48q17 100 98 100z" />
-<glyph unicode="&#x3a7;" horiz-adv-x="1338" d="M162 1467h16q62 0 97 -70l400 -510l438 562q32 18 58 18h12q80 0 98 -99v-6q0 -44 -109 -171l-368 -474l466 -597l11 -40v-11q-18 -99 -102 -99h-4q-68 0 -109 86l-391 498l-438 -561q-31 -23 -63 -23h-7q-99 18 -99 102v11q0 36 169 243l308 398q-458 580 -472 610 l-6 32q23 101 95 101z" />
-<glyph unicode="&#x3a8;" horiz-adv-x="1342" d="M767 652q84 18 195 120q102 121 102 312v288q18 95 98 95h11q81 0 99 -99v-337q0 -342 -340 -542q-145 -56 -165 -56v-365q0 -80 -99 -98h-6q-83 0 -103 103v362q-66 6 -217 85q-283 197 -283 534v302q12 111 94 111h19q95 -20 95 -91v-313q10 -128 39 -193 q80 -155 224 -204l29 -8v698q13 111 95 111h18q95 -20 95 -91v-724z" />
-<glyph unicode="&#x3a9;" horiz-adv-x="1658" d="M279 179q-58 56 -111 137q-111 194 -111 408q0 351 321 603q208 140 433 140q382 0 638 -354q116 -206 116 -389q0 -314 -223 -542h93q100 -19 100 -94v-19q-21 -95 -99 -95h-492q-86 0 -103 112q27 96 100 96q95 0 268 148q151 177 151 386q0 258 -232 445 q-153 97 -302 97h-30q-258 0 -436 -235q-98 -151 -98 -307q0 -314 291 -488q48 -30 168 -58q67 -28 67 -105q-27 -95 -103 -95h-487q-103 20 -103 109q23 100 103 100h81z" />
-<glyph unicode="&#x3aa;" horiz-adv-x="648" d="M174 1713h18q95 -20 95 -90v-19q0 -80 -102 -99q-105 21 -105 110q22 98 94 98zM461 1713h17q95 -21 95 -94v-11q0 -86 -106 -102q-101 19 -101 102v11q0 73 95 94zM241 1462l23 -5h132l18 5q106 -23 106 -110q-18 -102 -101 -102h15v-1073h-8q75 0 94 -99v-8 q-17 -100 -101 -100h-180q-99 18 -99 102v6q21 99 94 99h-7v1073h15q-90 0 -102 107v6q0 68 101 99z" />
-<glyph unicode="&#x3ab;" horiz-adv-x="1216" d="M593 897q353 531 372 545q28 21 52 21h23q69 0 94 -98q0 -46 -135 -230l-301 -450v-604q-13 -111 -94 -111h-16q-72 0 -98 86v626q0 5 -154 234l-273 411l-6 35q23 101 95 101h16q69 0 105 -88zM443 1717h18q95 -20 95 -90v-19q0 -80 -103 -99q-104 21 -104 110 q22 98 94 98zM729 1717h18q95 -21 95 -94v-11q0 -86 -106 -102q-101 19 -101 102v11q0 73 94 94z" />
-<glyph unicode="&#x3ac;" horiz-adv-x="1414" d="M268 508q0 -201 200 -307q71 -26 140 -26q191 0 299 200l47 134q-58 201 -159 266q-88 62 -183 62h-19q-179 0 -285 -173q-40 -83 -40 -156zM1061 228q-48 -86 -150 -156q-133 -102 -314 -102h-15q-218 0 -405 204q-114 161 -114 334q0 290 278 470q138 67 263 67 q272 0 452 -255l6 -12q7 29 75 214q39 53 93 53q101 -19 101 -107q-5 -28 -157 -430q157 -409 157 -437q-23 -101 -104 -101q-91 0 -137 180zM706 1450q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63z" />
-<glyph unicode="&#x3ad;" horiz-adv-x="900" d="M400 1047h40q174 0 339 -173q34 -36 34 -75v-8q0 -85 -114 -102q-64 0 -134 92q-84 57 -138 57h-21q-73 0 -112 -87v-44q0 -51 90 -87q11 -5 35 -5h70q110 -17 110 -103v-7q0 -99 -142 -99q-107 0 -143 -72l-10 -44q21 -111 128 -111h4q94 0 204 128q41 21 70 21 q100 0 116 -108v-11q-34 -103 -196 -190q-97 -49 -194 -49h-17q-202 0 -319 202q-24 69 -24 122q0 128 88 210q-101 86 -101 226q0 211 263 308zM546 1446q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63z" />
-<glyph unicode="&#x3ae;" horiz-adv-x="1191" d="M166 1030q96 -25 96 -92v-14q119 106 319 106q219 0 390 -182q124 -154 124 -325v-881q0 -77 -109 -93q-94 27 -94 101v825q0 255 -218 335q-52 13 -93 13h-11q-182 0 -282 -188q-26 -57 -26 -189v-385q0 -79 -97 -96h-6q-81 0 -100 100v852q11 113 107 113zM660 1429 q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63z" />
-<glyph unicode="&#x3af;" horiz-adv-x="467" d="M237 1038q96 -25 96 -93v-879q0 -79 -97 -96h-7q-81 0 -100 101v854q12 113 108 113zM310 1421q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63z" />
-<glyph unicode="&#x3b0;" horiz-adv-x="1203" d="M191 1034q96 -25 96 -92v-392q0 -235 130 -312q83 -65 184 -65q195 0 295 201q20 65 20 132v428q19 100 106 100q97 -22 97 -100v-465q0 -233 -221 -405q-141 -94 -286 -94h-25q-242 0 -421 237q-82 128 -82 313v401q11 113 107 113zM671 1420q100 -23 100 -100v-7 q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63zM350 1339q106 -25 106 -113q-21 -107 -113 -107q-107 21 -107 114q25 106 114 106zM862 1339q106 -25 106 -113q-21 -107 -113 -107q-107 21 -107 114q25 106 114 106z" />
-<glyph unicode="&#x3b1;" horiz-adv-x="1414" d="M281 508q0 -201 200 -307q71 -26 140 -26q191 0 299 200l47 134q-58 201 -159 266q-88 62 -183 62h-19q-179 0 -285 -173q-40 -83 -40 -156zM1074 228q-48 -86 -150 -156q-133 -102 -314 -102h-15q-218 0 -405 204q-114 161 -114 334q0 290 278 470q138 67 263 67 q272 0 452 -255l6 -12q7 29 75 214q39 53 93 53q101 -19 101 -107q-5 -28 -157 -430q157 -409 157 -437q-23 -101 -104 -101q-91 0 -137 180z" />
-<glyph unicode="&#x3b2;" horiz-adv-x="999" d="M278 998v-597q0 -103 99 -177q56 -39 131 -39q166 0 224 170l7 48v13q0 161 -179 220l-49 3h-131q-101 17 -101 102v16q0 71 95 94h69q177 0 229 124q13 42 13 69v19q0 133 -160 186l-45 4q-143 0 -195 -154zM776 759q176 -125 176 -351q0 -247 -254 -394 q-106 -41 -194 -41q-137 0 -226 63v-383q-3 -104 -98 -107q-4 -1 -7 -1q-90 0 -105 93v1433q0 209 223 348q97 45 190 45h4q254 0 384 -256q30 -74 30 -149v-15q0 -160 -123 -285z" />
-<glyph unicode="&#x3b3;" horiz-adv-x="1057" d="M549 337q259 650 279 672q44 28 75 29q101 -20 101 -105q0 -25 -348 -879l-6 -24v-396q0 -85 -105 -101q-101 19 -101 101v411q0 16 -346 854l-5 35q21 104 105 104q87 0 133 -162z" />
-<glyph unicode="&#x3b4;" horiz-adv-x="1233" d="M173 1468l68 -6h709q102 -20 102 -102v-11q-18 -95 -68 -95v-7l-58 7h-398l441 -324q189 -181 189 -412q0 -308 -291 -484q-127 -64 -245 -64h-30q-222 0 -412 207q-117 165 -117 341q0 295 279 475q106 51 106 61q0 3 -7 3l-310 233q-26 38 -26 72q17 100 68 100v6z M274 529v-19q0 -190 184 -295q66 -34 141 -34h23q197 0 301 205q24 64 24 124v19q0 157 -146 267q-85 58 -194 58q-216 0 -316 -227q-17 -54 -17 -98z" />
-<glyph unicode="&#x3b5;" horiz-adv-x="896" d="M400 1047h40q174 0 339 -173q34 -36 34 -75v-8q0 -85 -114 -102q-64 0 -134 92q-84 57 -138 57h-21q-73 0 -112 -87v-44q0 -51 90 -87q11 -5 35 -5h70q110 -17 110 -103v-7q0 -99 -142 -99q-107 0 -143 -72l-10 -44q21 -111 128 -111h4q94 0 204 128q41 21 70 21 q100 0 116 -108v-11q-34 -103 -196 -190q-97 -49 -194 -49h-17q-202 0 -319 202q-24 69 -24 122q0 128 88 210q-101 86 -101 226q0 211 263 308z" />
-<glyph unicode="&#x3b6;" horiz-adv-x="1052" d="M304 1465h588q96 -19 96 -90v-19q0 -63 -85 -105q-437 -387 -485 -439q-84 -111 -84 -247q0 -218 206 -342q83 -50 232 -50q140 -34 202 -118q67 -90 67 -193v-4q0 -223 -249 -307h-16q-99 21 -99 95v15q0 78 109 108q51 33 51 93q0 67 -68 98l-30 8l-26 -3 q-251 0 -455 224q-132 179 -132 357v42q0 279 285 502l187 167h-289q-103 19 -103 102v6q17 100 98 100z" />
-<glyph unicode="&#x3b7;" horiz-adv-x="1178" d="M166 1030q96 -25 96 -92v-14q119 106 319 106q219 0 390 -182q124 -154 124 -325v-881q0 -77 -109 -93q-94 27 -94 101v825q0 255 -218 335q-52 13 -93 13h-11q-182 0 -282 -188q-26 -57 -26 -189v-385q0 -79 -97 -96h-6q-81 0 -100 100v852q11 113 107 113z" />
-<glyph unicode="&#x3b8;" horiz-adv-x="1158" d="M588 1460q265 0 404 -282q74 -226 74 -418v-86q0 -236 -97 -477q-148 -227 -373 -227h-12q-245 0 -384 258q-86 219 -86 483v12q0 280 102 510q150 227 372 227zM314 820h557q0 127 -77 318q-84 119 -202 119q-138 0 -214 -140q-59 -163 -61 -272zM310 614 q3 -112 68 -307q81 -134 203 -134h11q214 0 260 318q19 104 19 123h-561z" />
-<glyph unicode="&#x3b9;" horiz-adv-x="442" d="M225 1038q96 -25 96 -93v-879q0 -79 -97 -96h-7q-81 0 -100 101v854q12 113 108 113z" />
-<glyph unicode="&#x3ba;" horiz-adv-x="1086" d="M406 518l-125 -80v-370q0 -81 -100 -98h-6q-77 0 -102 94v934q16 87 93 105l28 1q82 -20 87 -110v-310q489 324 586 379h27q86 0 102 -107q0 -66 -136 -138l-276 -189l406 -514l6 -33v-9q-18 -99 -102 -99h-7q-60 0 -157 140z" />
-<glyph unicode="&#x3bb;" horiz-adv-x="1120" d="M568 679q-293 -626 -327 -671q-35 -44 -82 -44q-28 0 -59 15q-52 23 -52 81q0 39 25 95l236 499l134 282l-164 354q-12 38 -12 68q0 75 75 94q21 5 40 5q71 0 98 -79l602 -1262q3 -23 3 -42q0 -96 -76 -101h-13q-81 0 -121 68z" />
-<glyph unicode="&#x3bc;" horiz-adv-x="1199" d="M904 76q-138 -107 -304 -107h-26q-184 0 -300 105v-428q0 -70 -100 -92q-83 0 -103 104v1263q11 113 107 113q96 -25 96 -92v-393q0 -235 130 -313q83 -64 185 -64q195 0 295 201q20 65 20 132v429q19 100 106 100q97 -22 97 -100v-873q0 -73 -97 -92h-9q-97 17 -97 99v8 z" />
-<glyph unicode="&#x3bd;" horiz-adv-x="1220" d="M186 1059h7q80 0 130 -142l294 -604q325 690 352 719q36 27 72 27q102 -19 102 -101v-4q0 -26 -168 -374l-281 -577q-44 -33 -77 -33h-3q-85 0 -141 162q-363 741 -385 806v26q18 95 98 95z" />
-<glyph unicode="&#x3be;" horiz-adv-x="951" d="M437 1463h185q100 -18 100 -102v-7q-18 -100 -103 -100h-167q-120 0 -154 -106l-7 -36q22 -144 146 -144l96 20q101 -26 101 -96v-23q0 -82 -135 -105q-189 -96 -189 -271v-27q0 -171 183 -267q29 -19 206 -34q232 -92 232 -304v-4q0 -222 -250 -308h-15q-100 21 -100 95 v15q0 79 109 108q51 34 51 91q-18 110 -102 110l-11 -4q-260 0 -437 246q-78 142 -78 267q0 206 134 347q-149 88 -149 293q0 202 211 316q65 30 143 30z" />
-<glyph unicode="&#x3bf;" horiz-adv-x="1245" d="M616 1034q206 0 373 -156q159 -166 159 -376q0 -299 -282 -469q-124 -63 -239 -63h-29q-216 0 -401 202q-113 159 -113 330q0 259 229 434q147 98 303 98zM291 513v-18q0 -184 178 -286q63 -32 136 -32h22q190 0 291 198q23 61 23 120v18q0 152 -140 258q-83 56 -189 56 q-208 0 -305 -219q-16 -52 -16 -95z" />
-<glyph unicode="&#x3c0;" horiz-adv-x="1165" d="M207 835l-51 -3q-89 31 -89 107q17 97 66 97v6l68 -6h768l46 3q92 -30 92 -96v-11q0 -71 -89 -100l-51 3v-769q0 -79 -97 -96h-7q-81 0 -100 101v765h-352v-773q0 -74 -97 -93h-10q-97 17 -97 100v765z" />
-<glyph unicode="&#x3c1;" horiz-adv-x="1187" d="M595 1050q209 0 377 -157q161 -169 161 -380q0 -302 -285 -474q-125 -63 -241 -63h-30q-188 0 -314 114v-443q0 -71 -101 -93q-80 0 -103 101v825q0 405 383 546q49 16 153 24zM267 524v-19q0 -185 180 -288q64 -33 138 -33h22q193 0 295 200q23 62 23 121v19 q0 154 -142 261q-84 57 -191 57q-210 0 -308 -222q-17 -53 -17 -96z" />
-<glyph unicode="&#x3c2;" horiz-adv-x="997" d="M614 1048q202 0 202 -114v-24q-25 -90 -102 -90h-14l-84 12q-205 0 -303 -210q-14 -34 -21 -117q0 -203 216 -303q54 -13 197 -27q243 -95 243 -317v-4q0 -234 -261 -322h-16q-103 20 -103 98v16q0 82 114 112q54 36 54 100q0 79 -90 111l-14 2l-9 -3q-308 0 -483 291 q-60 119 -60 223v44q0 272 275 454q141 68 259 68z" />
-<glyph unicode="&#x3c3;" horiz-adv-x="1355" d="M571 1036l80 -4h515l38 5q93 -29 93 -94v-22q0 -60 -84 -92l-68 4h-139q115 -122 115 -330q0 -269 -244 -447q-142 -86 -278 -86h-29q-228 0 -406 209q-109 152 -109 309v33q0 244 242 429q156 86 274 86zM258 503q0 -202 205 -306q66 -20 107 -20h33q162 0 267 162 q44 76 44 171q0 176 -176 283q-71 36 -157 36q-176 0 -283 -172q-40 -81 -40 -154z" />
-<glyph unicode="&#x3c4;" horiz-adv-x="1187" d="M146 1045l69 -7h776l37 5q94 -27 94 -101v-8q0 -68 -84 -100l-68 4h-265v-767q-19 -101 -100 -101h-7q-97 17 -97 96v772h-268l-64 -4q-89 32 -89 107q17 97 66 97v7z" />
-<glyph unicode="&#x3c5;" horiz-adv-x="1216" d="M191 1034q96 -25 96 -92v-392q0 -235 130 -312q83 -65 184 -65q195 0 295 201q20 65 20 132v428q19 100 106 100q97 -22 97 -100v-465q0 -233 -221 -405q-141 -94 -286 -94h-25q-242 0 -421 237q-82 128 -82 313v401q11 113 107 113z" />
-<glyph unicode="&#x3c6;" horiz-adv-x="1213" d="M685 198q73 18 167 102q85 110 85 214v42q0 155 -160 269l-29 6q-43 0 -60 -47l-3 -28v-558zM729 1041h33q162 0 315 -235q74 -134 74 -269q0 -324 -310 -505q-129 -53 -156 -53v-332q0 -90 -113 -108q-98 27 -98 100v347q-84 10 -227 107q-212 186 -212 448t240 448 q31 21 60 21h14q97 -18 97 -99v-16q0 -50 -88 -107q-109 -116 -109 -232v-42q0 -176 183 -289l42 -15v570q0 161 187 248z" />
-<glyph unicode="&#x3c7;" horiz-adv-x="1237" d="M629 98q-318 -506 -348 -535q-27 -21 -66 -26q-83 0 -103 105v11q13 49 286 460q25 51 109 172l-395 625v27q20 101 104 101q72 0 138 -134l274 -428q292 466 347 535q30 23 67 27q103 -20 103 -104q0 -43 -187 -317l-209 -334q-1 2 313 -481q83 -126 83 -164 q-22 -101 -101 -101q-77 0 -141 134q-47 64 -274 427z" />
-<glyph unicode="&#x3c8;" horiz-adv-x="1376" d="M800 194q82 17 186 111q110 112 110 308v336q18 100 103 100h4q106 0 106 -141v-326q0 -370 -366 -565q-126 -44 -143 -44v-288q0 -81 -100 -99h-7q-84 0 -103 104v285q-75 6 -235 95q-271 202 -271 531v336q17 112 107 112h6q100 -15 100 -103v-303q0 -245 122 -346 q61 -69 171 -99v735q12 112 95 112h19q96 -19 96 -91v-760z" />
-<glyph unicode="&#x3c9;" horiz-adv-x="1321" d="M332 1046h10q95 -17 95 -99v-4q0 -20 -85 -196q-84 -219 -84 -404v-29q0 -95 108 -133l34 -6q107 0 141 119l4 83v316l-4 44q30 92 95 92h11q87 0 98 -112v-372l5 -37l-5 -13q0 -68 99 -118l47 -6q100 0 138 113l3 31v28q0 260 -169 574v29q17 96 98 96h4q77 0 133 -141 q139 -290 139 -587q0 -212 -217 -319q-61 -25 -120 -25h-22q-142 0 -237 101q-83 -97 -233 -97h-14q-215 0 -321 228q-20 66 -20 112q0 359 194 694q35 38 75 38z" />
-<glyph unicode="&#x3ca;" horiz-adv-x="589" d="M330 1038q96 -25 96 -93v-879q0 -79 -97 -96h-7q-81 0 -100 101v854q12 113 108 113zM168 1266h18q95 -20 95 -90v-19q0 -80 -102 -99q-105 21 -105 110q22 98 94 98zM455 1266h17q95 -21 95 -94v-11q0 -86 -106 -102q-101 19 -101 102v11q0 73 95 94z" />
-<glyph unicode="&#x3cb;" horiz-adv-x="1208" d="M191 1034q96 -25 96 -92v-392q0 -235 130 -312q83 -65 184 -65q195 0 295 201q20 65 20 132v428q19 100 106 100q97 -22 97 -100v-465q0 -233 -221 -405q-141 -94 -286 -94h-25q-242 0 -421 237q-82 128 -82 313v401q11 113 107 113zM437 1301h18q95 -20 95 -90v-19 q0 -80 -102 -99q-105 21 -105 110q22 98 94 98zM724 1301h17q95 -21 95 -94v-11q0 -86 -106 -102q-101 19 -101 102v11q0 73 95 94z" />
-<glyph unicode="&#x3cc;" horiz-adv-x="1229" d="M616 1034q206 0 373 -156q159 -166 159 -376q0 -299 -282 -469q-124 -63 -239 -63h-29q-216 0 -401 202q-113 159 -113 330q0 259 229 434q147 98 303 98zM291 513v-18q0 -184 178 -286q63 -32 136 -32h22q190 0 291 198q23 61 23 120v18q0 152 -140 258q-83 56 -189 56 q-208 0 -305 -219q-16 -52 -16 -95zM654 1417q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63z" />
-<glyph unicode="&#x3cd;" horiz-adv-x="1178" d="M191 1034q96 -25 96 -92v-392q0 -235 130 -312q83 -65 184 -65q195 0 295 201q20 65 20 132v428q19 100 106 100q97 -22 97 -100v-465q0 -233 -221 -405q-141 -94 -286 -94h-25q-242 0 -421 237q-82 128 -82 313v401q11 113 107 113zM659 1443q100 -23 100 -100v-7 q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180q46 63 100 63z" />
-<glyph unicode="&#x3ce;" horiz-adv-x="1309" d="M332 1046h10q95 -17 95 -99v-4q0 -20 -85 -196q-84 -219 -84 -404v-29q0 -95 108 -133l34 -6q107 0 141 119l4 83v316l-4 44q30 92 95 92h11q87 0 98 -112v-372l5 -37l-5 -13q0 -68 99 -118l47 -6q100 0 138 113l3 31v28q0 260 -169 574v29q17 96 98 96h4q77 0 133 -141 q139 -290 139 -587q0 -212 -217 -319q-61 -25 -120 -25h-22q-142 0 -237 101q-83 -97 -233 -97h-14q-215 0 -321 228q-20 66 -20 112q0 359 194 694q35 38 75 38zM739 1430q100 -23 100 -100v-7q0 -43 -87 -139q-68 -104 -137 -104h-4q-71 0 -92 97v10q0 44 120 180 q46 63 100 63z" />
-<glyph unicode="&#x2000;" horiz-adv-x="946" />
-<glyph unicode="&#x2001;" horiz-adv-x="1893" />
-<glyph unicode="&#x2002;" horiz-adv-x="946" />
-<glyph unicode="&#x2003;" horiz-adv-x="1893" />
-<glyph unicode="&#x2004;" horiz-adv-x="631" />
-<glyph unicode="&#x2005;" horiz-adv-x="473" />
-<glyph unicode="&#x2006;" horiz-adv-x="315" />
-<glyph unicode="&#x2007;" horiz-adv-x="315" />
-<glyph unicode="&#x2008;" horiz-adv-x="236" />
-<glyph unicode="&#x2009;" horiz-adv-x="378" />
-<glyph unicode="&#x200a;" horiz-adv-x="105" />
-<glyph unicode="&#x2010;" horiz-adv-x="670" d="M175 698h400q83 0 106 -110q-25 -106 -106 -106h-400q-92 0 -107 116q28 100 107 100z" />
-<glyph unicode="&#x2011;" horiz-adv-x="670" d="M175 698h400q83 0 106 -110q-25 -106 -106 -106h-400q-92 0 -107 116q28 100 107 100z" />
-<glyph unicode="&#x2013;" horiz-adv-x="1108" d="M156 545l71 -7h717l36 4q85 0 108 -107q0 -75 -89 -113l-74 4h-678l-69 -4q-94 33 -94 113q18 103 72 103v7z" />
-<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M72 613l71 -7h1821l36 4q85 0 108 -107q0 -75 -89 -113l-74 4h-1782l-69 -4q-94 33 -94 113q18 103 72 103v7z" />
-<glyph unicode="&#x2015;" horiz-adv-x="2007" d="M165 652l71 -7h1597l40 4q100 -27 100 -106v-8q0 -71 -89 -106l-74 4h-1554l-69 -4q-94 33 -94 113q18 103 72 103v7z" />
-<glyph unicode="&#x2017;" horiz-adv-x="951" d="M102 1h887q102 -18 102 -100v-15q-20 -97 -100 -97h-889q-90 0 -105 114q28 98 105 98z" />
-<glyph unicode="&#x2018;" horiz-adv-x="557" d="M393 1599q59 -17 59 -64v-14q-59 -141 -60 -238q0 -52 46 -129l6 -28q0 -92 -111 -113q-126 0 -157 280q0 150 159 284z" />
-<glyph unicode="&#x2019;" horiz-adv-x="557" d="M291 1588h28q110 0 142 -264v-22q0 -143 -157 -273q-38 -21 -67 -21q-33 13 -52 46v26q60 144 60 230v12q0 54 -48 136v31q21 99 94 99z" />
-<glyph unicode="&#x201a;" horiz-adv-x="557" d="M286 250h28q110 0 142 -264v-22q0 -143 -157 -273q-38 -21 -67 -21q-33 13 -52 46v26q60 144 60 230v12q0 54 -48 136v31q21 99 94 99z" />
-<glyph unicode="&#x201b;" horiz-adv-x="450" d="M373 1479v-31q-49 -82 -49 -136v-12q0 -86 61 -230v-26q-19 -33 -52 -46q-28 0 -68 21q-158 130 -158 273v22q32 264 143 264h28q74 0 95 -99z" />
-<glyph unicode="&#x201c;" horiz-adv-x="910" d="M441 1620q59 -17 59 -64v-14q-59 -141 -60 -238q0 -52 46 -129l6 -28q0 -92 -111 -113q-126 0 -157 280q0 150 159 284zM736 1610q52 -22 52 -72q-64 -142 -64 -238q0 -53 52 -144v-23q-19 -103 -102 -103h-16q-107 0 -146 232v70q0 120 147 251q37 27 77 27z" />
-<glyph unicode="&#x201d;" horiz-adv-x="910" d="M326 1611h28q110 0 142 -264v-22q0 -143 -157 -273q-38 -21 -67 -21q-33 13 -52 46v26q60 144 60 230v12q0 54 -48 136v31q21 99 94 99zM630 1615h12q121 0 150 -272v-10q0 -146 -158 -278l-50 -20q-68 0 -68 62v10q60 141 60 242q0 54 -48 132v44q25 90 102 90z" />
-<glyph unicode="&#x201e;" horiz-adv-x="910" d="M308 265h28q110 0 142 -264v-22q0 -143 -157 -273q-38 -21 -67 -21q-33 13 -52 46v26q60 144 60 230v12q0 54 -48 136v31q21 99 94 99zM612 269h12q121 0 150 -272v-10q0 -146 -158 -278l-50 -20q-68 0 -68 62v10q60 141 60 242q0 54 -48 132v44q25 90 102 90z" />
-<glyph unicode="&#x2020;" d="M539 1471h12q84 0 102 -103v-261h160l36 4q81 0 108 -106q0 -80 -94 -114l-65 4h-145v-1194q0 -93 -116 -111q-100 27 -100 103v1202h-141l-69 -4q-94 33 -94 113q18 103 72 103v7l71 -7h161v265q19 99 102 99z" />
-<glyph unicode="&#x2021;" d="M542 1471h12q84 0 102 -103v-261h160l36 4q81 0 108 -106q0 -80 -94 -114l-65 4h-145v-724h206q72 0 99 -105q-22 -111 -111 -111h-194v-254q0 -93 -116 -111q-100 27 -100 103v262h-197q-107 21 -107 113q23 103 98 103h206v724h-141l-69 -4q-94 33 -94 113 q18 103 72 103v7l71 -7h161v265q19 99 102 99z" />
-<glyph unicode="&#x2022;" horiz-adv-x="1024" d="M216 718q0 123 87 209t210 86q122 0 208.5 -86.5t86.5 -208.5t-87.5 -209.5t-209.5 -87.5q-123 0 -209 87t-86 210z" />
-<glyph unicode="&#x2026;" horiz-adv-x="2048" d="M1663 304q129 0 165 -151v-28q0 -94 -113 -145q-20 -10 -52 -10h-4q-137 0 -165 167q0 110 118 157q19 10 51 10zM972 300q129 0 165 -151v-28q0 -94 -113 -145q-20 -10 -52 -10h-4q-137 0 -165 167q0 110 118 157q19 10 51 10zM299 304q129 0 165 -151v-28 q0 -94 -113 -145q-20 -10 -52 -10h-4q-137 0 -165 167q0 110 118 157q19 10 51 10z" />
-<glyph unicode="&#x202f;" horiz-adv-x="378" />
-<glyph unicode="&#x2030;" horiz-adv-x="2494" d="M509 1476h19q182 0 308 -164q74 -109 74 -223q0 -252 -262 -372q-75 -21 -124 -21h-7q-228 0 -349 220q-41 84 -41 170q0 256 270 372q56 18 112 18zM1363 1466h14q95 -20 95 -99v-15q0 -32 -146 -219l-864 -1142q-42 -21 -65 -21h-7q-99 21 -99 94v16q0 42 112 178 l897 1184q35 24 63 24zM335 1087v-5q0 -128 142 -175l33 -3h18q125 0 171 146l4 37q0 131 -140 178l-44 7q-129 0 -178 -136zM1246 743q229 0 361 -237q29 -87 29 -152v-12q0 -229 -241 -352q-75 -30 -149 -30h-7q-200 0 -328 192q-55 94 -55 186v23q0 207 205 333 q99 49 185 49zM1060 352q0 -127 133 -178l48 -6h13q122 0 171 140l3 29v24q0 127 -150 171l-34 4q-135 0 -181 -154zM2039 748q229 0 361 -237q29 -87 29 -152v-12q0 -229 -241 -352q-75 -30 -149 -30h-7q-200 0 -328 192q-55 94 -55 186v23q0 207 205 333q99 49 185 49z M1853 357q0 -127 133 -178l48 -6h13q122 0 171 140l3 29v24q0 127 -150 171l-34 4q-135 0 -181 -154z" />
-<glyph unicode="&#x2032;" horiz-adv-x="455" d="M306 1459h7q103 -18 103 -102v-20q0 -31 -175 -259q-28 -31 -59 -31h-8q-56 0 -74 70v18q110 275 140 302q37 22 66 22z" />
-<glyph unicode="&#x2033;" horiz-adv-x="673" d="M314 1459h7q103 -18 103 -102v-20q0 -31 -175 -259q-28 -31 -59 -31h-8q-56 0 -74 70v18q110 275 140 302q37 22 66 22zM565 1447q107 -21 107 -110q0 -42 -114 -185q-75 -117 -120 -117h-12q-56 0 -74 70q0 27 117 293q47 49 96 49z" />
-<glyph unicode="&#x2039;" horiz-adv-x="631" d="M439 470q101 -74 101 -135v-7q-18 -103 -102 -103h-20q-42 0 -238 177l-12 41v48q0 53 158 167q51 55 100 55h10q104 -16 104 -106v-4q0 -61 -101 -133z" />
-<glyph unicode="&#x203a;" horiz-adv-x="631" d="M193 460q-101 73 -101 135v7q21 107 110 107q50 0 186 -126q76 -46 76 -100v-36q0 -62 -123 -147q-87 -83 -139 -83h-7q-103 19 -103 106v4q0 62 101 133z" />
-<glyph unicode="&#x203c;" horiz-adv-x="850" d="M649 1472h12q84 0 103 -96v-961q-24 -99 -110 -99q-108 16 -108 99v965q19 92 103 92zM640 236h10q131 -19 131 -122v-22q0 -95 -122 -122h-15q-104 0 -130 133q27 133 126 133zM245 1472h12q84 0 103 -96v-961q-24 -99 -110 -99q-108 16 -108 99v965q19 92 103 92z M236 236h10q131 -19 131 -122v-22q0 -95 -122 -122h-15q-104 0 -130 133q27 133 126 133z" />
-<glyph unicode="&#x203e;" horiz-adv-x="837" d="M186 1395l71 -7h397l36 4q81 0 108 -106q0 -80 -94 -114l-65 4h-362l-69 -4q-94 33 -94 113q18 103 72 103v7z" />
-<glyph unicode="&#x2044;" horiz-adv-x="462" d="M665 1483h12q84 0 102 -103v-7q0 -44 -123 -191q-974 -1264 -994 -1276l-40 -15h-21q-74 0 -102 89v25q0 45 123 191l978 1262q32 25 65 25z" />
-<glyph unicode="&#x2215;" horiz-adv-x="462" d="M665 1483h12q84 0 102 -103v-7q0 -44 -123 -191q-974 -1264 -994 -1276l-40 -15h-21q-74 0 -102 89v25q0 45 123 191l978 1262q32 25 65 25z" />
-<glyph unicode="&#x205f;" horiz-adv-x="473" />
-<glyph unicode="&#x207f;" horiz-adv-x="787" d="M156 1095q68 -18 68 -68v19q54 49 180 49q137 0 244 -114q77 -96 77 -203v-281q0 -54 -69 -67h-8q-69 13 -69 72v247q0 145 -122 190q-30 8 -53 8h-7q-102 0 -159 -107q-14 -31 -14 -109v-231q0 -58 -70 -70h-4q-59 0 -72 71v514q8 80 78 80z" />
-<glyph unicode="&#x20a3;" horiz-adv-x="1127" d="M250 1474l51 -11h712l15 4q92 0 107 -114q-21 -97 -111 -97h-641v-451h409l51 4q75 0 97 -103q0 -71 -82 -108l-81 4h-394v-198h89l33 4q80 0 102 -102q0 -73 -84 -109l-68 4h-72v-103l5 -27q-23 -101 -101 -101h-10q-97 18 -97 102v129h-68l-64 -4q-88 28 -88 102v7 q0 73 89 103l42 -5h89v959q15 100 70 100v11z" />
-<glyph unicode="&#x20a4;" horiz-adv-x="946" d="M244 411h-109q-95 18 -95 98v11q0 80 100 86l121 -2l-5 16h-117q-99 13 -99 99q20 102 105 102h16q-68 119 -68 238q0 243 256 374q80 25 120 25h38q192 0 330 -184l6 -39q-24 -105 -106 -105q-49 0 -119 80q-53 41 -111 41h-23q-128 0 -181 -153l-3 -44q0 -51 72 -186 l22 -47h240q103 -20 103 -108q-22 -99 -94 -93l-174 -1v-11h167q97 -8 97 -92v-7q-18 -98 -102 -98h-173q-5 0 -5 -19q0 -12 -4 -32l-81 -183h335q-4 0 -4 7q0 14 20 59q44 43 89 43q102 -20 102 -105q0 -35 -78 -177q-39 -34 -76 -34h-554q-83 0 -102 104q3 29 144 337z " />
-<glyph unicode="&#x20a7;" horiz-adv-x="2028" d="M1172 832h-71v-509q0 -120 68 -143h-2q9 -9 10 -9q0 3 -17 27q-20 30 -20 58v22q0 81 110 93q53 0 125 -103q88 -82 206 -82q140 0 232 131l4 14q-1 20 -41 24q-506 113 -540 144q-103 78 -103 193q0 96 39 140zM208 1260v-479h205q170 0 234 163q13 33 13 80 q0 148 -154 220q-35 16 -85 16h-213zM1341 984q-6 -4 -6 -5h1q1 0 15 9q120 63 237 63q274 0 433 -253l4 -37v-6q0 -85 -102 -100q-68 0 -126 96q-91 89 -209 89q-154 0 -241 -144l-2 -10q0 -20 86 -27q430 -104 475 -121q123 -81 123 -205v-3q0 -171 -242 -309 q-105 -47 -221 -47q-126 0 -197 41q-10 -45 -89 -45h-77q-194 0 -288 210q-17 53 -17 121v531h-69q-36 -87 -144 -173q-125 -86 -245 -86h-232v-505q0 -80 -99 -98h-7q-83 0 -102 103v1283q12 112 94 112h346q218 0 371 -224q57 -115 57 -208v-5h30v280q12 109 93 109h17 q93 -20 93 -89v-300h119l33 4q75 0 88 -51z" />
-<glyph unicode="&#x20ac;" horiz-adv-x="1193" d="M755 1487q236 0 445 -148q22 -42 22 -66v-7q0 -92 -110 -103h-11l-139 71q-127 40 -207 40q-250 0 -436 -222q-40 -61 -52 -90h701q101 -17 101 -103v-7q-18 -100 -103 -100h-751l-2 -23l2 -28h753q101 -15 101 -103v-7q-18 -99 -103 -99h-700q68 -168 267 -262 q111 -47 214 -47h12q159 0 332 108h35q96 -21 96 -99v-12q0 -103 -279 -186q-84 -24 -177 -24h-19q-375 0 -627 347q-120 202 -120 412q0 394 359 642q193 116 396 116z" />
-<glyph unicode="&#x2105;" horiz-adv-x="1768" d="M1374 1460h12q80 0 98 -99v-6q0 -45 -131 -197q-95 -132 -898 -1166q-37 -22 -73 -22q-94 26 -94 94v23q0 34 149 219q808 1052 875 1131q31 23 62 23zM441 1460q150 0 275 -115q14 -25 14 -46v-5q-14 -77 -80 -77h-3q-29 0 -100 54q-49 25 -99 25h-15q-134 0 -203 -141 q-16 -48 -16 -86q0 -137 142 -208q41 -16 90 -16q79 0 164 71l31 7h12q63 0 77 -76v-5q0 -75 -190 -148q-62 -11 -92 -11h-21q-157 0 -292 147q-83 118 -83 242q0 189 167 317q107 71 222 71zM1346 739q147 0 267 -112q114 -119 114 -269q0 -215 -202 -337q-89 -45 -172 -45 h-21q-154 0 -286 145q-82 114 -82 237q0 186 164 311q105 70 218 70zM1127 365v-13q0 -123 120 -192q42 -21 91 -21h15q128 0 196 133q15 41 15 80v13q0 102 -94 174q-56 37 -127 37q-140 0 -206 -147q-10 -34 -10 -64z" />
-<glyph unicode="&#x2113;" horiz-adv-x="846" d="M562 1462q196 0 272 -206l9 -59v-21q0 -102 -130 -263l-213 -319v-353q0 -60 34 -60h13q62 26 85 26q75 0 99 -105q-30 -132 -197 -132q-157 0 -232 180l-9 78v48q-26 -42 -87 -42h-7q-86 0 -102 107q0 37 192 308l4 7v512q0 218 215 286zM500 964q132 185 132 204v34 q0 36 -67 50h-1q-52 0 -64 -78v-210z" />
-<glyph unicode="&#x2116;" horiz-adv-x="2271" d="M998 374v992q18 95 98 95h11q81 0 98 -98v-1288q0 -87 -107 -105q-61 0 -158 144l-733 936v-978q0 -81 -100 -98h-5q-83 0 -102 102v1274q12 111 94 111h15q67 0 108 -88q53 -60 781 -999zM1287 452l71 -7h717l36 4q85 0 108 -107q0 -75 -89 -113l-74 4h-678l-69 -4 q-94 33 -94 113q18 103 72 103v7zM1712 1306q165 0 299 -125q127 -133 127 -301q0 -240 -226 -376q-99 -50 -191 -50h-24q-172 0 -320 161q-91 128 -91 265q0 208 183 348q117 78 243 78zM1462 889v-14q0 -142 137 -220q48 -25 104 -25h18q146 0 223 152q18 47 18 93v14 q0 117 -108 198q-63 43 -145 43q-160 0 -235 -167q-12 -40 -12 -74z" />
-<glyph unicode="&#x2122;" horiz-adv-x="1497" d="M214 1471h438q59 -11 59 -62v-7q0 -51 -67 -60h-147v-539q0 -51 -61 -62h-4q-52 0 -64 62v539h-152q-62 12 -62 70q14 59 60 59zM891 1102v-308q0 -51 -61 -62h-5q-52 0 -64 63v608q7 67 60 67h8q50 0 67 -66l204 -456q12 43 127 304l90 194q24 24 48 24h8q53 0 60 -67 v-608q-12 -63 -64 -63h-5q-61 11 -61 62v307q-147 -333 -156 -346q-25 -23 -50 -23q-53 0 -83 94z" />
-<glyph unicode="&#x2126;" horiz-adv-x="1709" d="M317 179q-58 56 -111 137q-111 194 -111 408q0 351 321 603q208 140 433 140q382 0 638 -354q116 -206 116 -389q0 -314 -223 -542h93q100 -19 100 -94v-19q-21 -95 -99 -95h-492q-86 0 -103 112q27 96 100 96q95 0 268 148q151 177 151 386q0 258 -232 445 q-153 97 -302 97h-30q-258 0 -436 -235q-98 -151 -98 -307q0 -314 291 -488q48 -30 168 -58q67 -28 67 -105q-27 -95 -103 -95h-487q-103 20 -103 109q23 100 103 100h81z" />
-<glyph unicode="&#x212e;" horiz-adv-x="1174" d="M596 1034q307 0 477 -291q59 -115 59 -248v-22q-18 -100 -100 -100h-733q29 -95 160 -166q77 -30 145 -30q77 0 187 55h32q93 -18 93 -96v-11q0 -117 -292 -155h-28q-286 0 -458 268q-70 127 -70 264q0 293 275 466q135 66 253 66zM282 576h640q0 35 -81 144 q-110 104 -215 104h-41q-160 0 -263 -158q-37 -63 -40 -90z" />
-<glyph unicode="&#x215b;" horiz-adv-x="1498" d="M1223 1472h12q81 0 98 -100v-6q0 -45 -131 -198q-96 -133 -906 -1176q-37 -22 -74 -22q-94 26 -94 95v23q0 34 151 220q814 1061 881 1141q31 23 63 23zM353 1464q45 0 78 -57l-3 -65v-652l3 -39q-21 -68 -75 -68q-44 0 -72 53v654l-32 -7h-29q-53 28 -53 71q0 74 110 91 q0 3 73 19zM1191 836q111 0 187 -98q45 -60 45 -132v-11q0 -98 -59 -151q93 -68 93 -205q0 -136 -124 -227q-70 -46 -147 -46h-11q-131 0 -225 129q-41 74 -41 144q0 141 99 212q-25 19 -43 92q-7 20 -7 52v11q0 123 117 198q59 32 116 32zM1101 595q0 -57 72 -81l19 -2 q61 0 84 66l4 25q0 64 -70 85l-23 2q-59 0 -83 -64zM1052 239q0 -90 97 -126q11 -4 37 -4q86 0 123 94l3 27v20q0 71 -86 112q-23 7 -42 7q-93 0 -127 -95z" />
-<glyph unicode="&#x215c;" horiz-adv-x="1523" d="M1265 1472h12q81 0 98 -100v-6q0 -45 -131 -198q-96 -133 -906 -1176q-37 -22 -74 -22q-94 26 -94 95v23q0 34 151 220q814 1061 881 1141q31 23 63 23zM1233 836q111 0 187 -98q45 -60 45 -132v-11q0 -98 -59 -151q93 -68 93 -205q0 -136 -124 -227q-70 -46 -147 -46 h-11q-131 0 -225 129q-41 74 -41 144q0 141 99 212q-25 19 -43 92q-7 20 -7 52v11q0 123 117 198q59 32 116 32zM1143 595q0 -57 72 -81l19 -2q61 0 84 66l4 25q0 64 -70 85l-23 2q-59 0 -83 -64zM1094 239q0 -90 97 -126q11 -4 37 -4q86 0 123 94l3 27v20q0 71 -86 112 q-23 7 -42 7q-93 0 -127 -95zM356 1548q144 0 216 -146q18 -42 18 -77v-22q0 -96 -58 -151q92 -64 92 -208q0 -198 -220 -271l-58 -4h-8q-187 0 -264 220l-4 58q0 38 52 69h27q67 0 75 -107q35 -93 117 -93h12q90 0 122 108l3 26q0 86 -104 123q-93 0 -93 83q16 67 91 67 q52 0 72 80v22q0 50 -74 76h-17q-63 0 -87 -73v-36q-28 -53 -68 -53h-14q-65 12 -65 67v8q0 164 186 230z" />
-<glyph unicode="&#x215d;" horiz-adv-x="1569" d="M1324 1472h12q81 0 98 -100v-6q0 -45 -131 -198q-96 -133 -906 -1176q-37 -22 -74 -22q-94 26 -94 95v23q0 34 151 220q814 1061 881 1141q31 23 63 23zM1292 836q111 0 187 -98q45 -60 45 -132v-11q0 -98 -59 -151q93 -68 93 -205q0 -136 -124 -227q-70 -46 -147 -46 h-11q-131 0 -225 129q-41 74 -41 144q0 141 99 212q-25 19 -43 92q-7 20 -7 52v11q0 123 117 198q59 32 116 32zM1202 595q0 -57 72 -81l19 -2q61 0 84 66l4 25q0 64 -70 85l-23 2q-59 0 -83 -64zM1153 239q0 -90 97 -126q11 -4 37 -4q86 0 123 94l3 27v20q0 71 -86 112 q-23 7 -42 7q-93 0 -127 -95zM168 1468l26 -3h321q57 0 72 -71q0 -59 -72 -75h-265v-151h90q159 0 247 -162q28 -67 28 -118q0 -145 -137 -240q-71 -39 -140 -39h-7q-164 0 -255 169q-22 64 -22 114q24 63 74 63q76 0 76 -99q21 -64 67 -87q39 -15 62 -15q90 0 127 92 q7 18 7 42q0 97 -102 130l-46 4h-145q-51 0 -70 60v318q0 44 64 68z" />
-<glyph unicode="&#x215e;" horiz-adv-x="1494" d="M1215 1472h12q81 0 98 -100v-6q0 -45 -131 -198q-96 -133 -906 -1176q-37 -22 -74 -22q-94 26 -94 95v23q0 34 151 220q814 1061 881 1141q31 23 63 23zM1183 836q111 0 187 -98q45 -60 45 -132v-11q0 -98 -59 -151q93 -68 93 -205q0 -136 -124 -227q-70 -46 -147 -46 h-11q-131 0 -225 129q-41 74 -41 144q0 141 99 212q-25 19 -43 92q-7 20 -7 52v11q0 123 117 198q59 32 116 32zM1093 595q0 -57 72 -81l19 -2q61 0 84 66l4 25q0 64 -70 85l-23 2q-59 0 -83 -64zM1044 239q0 -90 97 -126q11 -4 37 -4q86 0 123 94l3 27v20q0 71 -86 112 q-23 7 -42 7q-93 0 -127 -95zM461 1315h-284q-71 15 -71 76q15 68 67 68h417q66 -14 66 -64v-11q0 -20 -27 -59l-405 -720q-30 -20 -51 -20h-5q-68 13 -68 71v11q8 27 361 648z" />
-<glyph unicode="&#x2190;" horiz-adv-x="1923" d="M532 778h1284q94 -20 94 -100q-19 -97 -97 -97h-1280l150 -97q21 -41 21 -64v-10q-17 -90 -93 -90h-22q-42 11 -428 260q-77 25 -77 98q0 72 135 135q345 226 381 226h10q94 -17 94 -97v-7q0 -66 -159 -149z" />
-<glyph unicode="&#x2191;" horiz-adv-x="833" d="M348 1019q-100 -166 -136 -166l-17 -3h-25q-82 25 -82 86v17q0 32 100 185l180 294q28 28 73 36q74 0 138 -135q225 -346 225 -380v-13q-19 -90 -93 -90h-18q-56 0 -120 123l-29 44v-1274q0 -76 -93 -93h-10q-93 17 -93 97v1272z" />
-<glyph unicode="&#x2192;" horiz-adv-x="1910" d="M1443 778q-128 77 -161 110l-9 44v17q0 70 93 90q45 0 319 -180q154 -89 194 -131l11 -36v-25q0 -58 -90 -97q-392 -250 -419 -250h-17q-91 17 -91 93v15q0 60 174 153h-1282q-82 0 -98 106q25 91 94 91h1282z" />
-<glyph unicode="&#x2193;" horiz-adv-x="808" d="M426 1474q72 0 104 -84l-3 -66v-1215l98 151q37 22 63 22h7q93 -17 93 -97v-7q0 -31 -99 -183l-183 -297q-37 -31 -72 -31h-4q-69 0 -130 130q-220 339 -224 372v20q0 76 93 93h7q69 0 120 -114l38 -57v1213l-3 56q0 69 95 94z" />
-<glyph unicode="&#x2194;" horiz-adv-x="1961" d="M543 772h933q-111 70 -150 104l-14 40v22q0 76 93 93h7q39 0 289 -166q182 -108 214 -138l13 -51q0 -73 -86 -108q-371 -236 -415 -251h-34q-81 26 -81 86v17q0 67 137 135q3 4 30 21h-951q124 -76 160 -109q16 -29 16 -54v-7q0 -79 -97 -96q-37 0 -337 193 q-166 96 -178 135l-4 29v5q0 68 89 104q363 233 415 251h14q98 -15 98 -96v-7q0 -67 -120 -124q-23 -15 -41 -28z" />
-<glyph unicode="&#x2195;" horiz-adv-x="825" d="M338 1028q-75 -123 -108 -160l-51 -15q-91 0 -103 101v10q17 52 258 427q29 71 93 71h7q69 0 103 -88q240 -377 248 -412v-13q-19 -96 -99 -96q-74 0 -126 119l-27 40v-916l81 128q39 34 78 34q96 -19 96 -99q0 -38 -146 -261q-129 -213 -160 -240l-42 -8h-13 q-66 0 -110 105q-238 365 -238 401v6q19 96 99 96q70 0 130 -122l30 -48v940z" />
-<glyph unicode="&#x21a8;" horiz-adv-x="879" d="M367 1028q-75 -123 -108 -160l-51 -15q-91 0 -103 101v10q17 52 258 427q29 71 93 71h7q69 0 103 -88q240 -377 248 -412v-13q-19 -96 -99 -96q-74 0 -126 119l-27 40v-916l81 128q39 34 78 34q96 -19 96 -99q0 -38 -146 -261q-129 -213 -160 -240l-42 -8h-13 q-66 0 -110 105q-238 365 -238 401v6q19 96 99 96q70 0 130 -122l30 -48v940z" />
-<glyph unicode="&#x2202;" horiz-adv-x="1131" d="M243 499q0 -198 196 -298q65 -28 130 -28q194 0 295 192q28 64 28 138q0 191 -199 294q-75 25 -124 25q-191 0 -294 -188q-32 -74 -32 -135zM728 1003q-119 146 -342 222q-111 30 -195 30l-46 -4q-75 0 -97 97v18q18 96 99 96q565 0 839 -483q109 -176 109 -514 q0 -174 -164 -351q-166 -144 -354 -144h-23q-254 0 -435 250q-79 140 -79 279q0 281 267 456q127 70 262 70q91 0 159 -22z" />
-<glyph unicode="&#x2206;" horiz-adv-x="1144" d="M601 1068l-339 -888h677zM595 1473h12q85 0 113 -137q477 -1229 477 -1255v-12q0 -81 -101 -99h-992q-87 0 -104 114l512 1344q40 45 83 45z" />
-<glyph unicode="&#x220f;" horiz-adv-x="1378" d="M178 1473h1007q103 -19 103 -102v-7q-21 -99 -94 -99h-50v-1510h41q103 -20 103 -109q-18 -99 -68 -99l-323 -4q-85 0 -105 107v6q0 76 103 99h41v1510h-509v-1510h41q103 -20 103 -108q-17 -100 -68 -100h-300l-23 -4q-85 0 -105 107v6q0 76 103 99h41v1510h-50 q-78 0 -94 108q0 77 103 100z" />
-<glyph unicode="&#x2211;" horiz-adv-x="1206" d="M744 497l-665 811l-9 41v14q0 73 94 94h859q95 -20 95 -90v-19q0 -80 -98 -97h-625l582 -709l6 -38v-13q0 -39 -168 -228l-409 -501h621q102 -19 102 -94v-22q0 -64 -94 -95l-32 5h-791l-27 -5q-100 27 -100 95v22q0 39 168 229z" />
-<glyph unicode="&#x2212;" horiz-adv-x="1092" d="M162 804l71 -7h717l36 4q85 0 108 -107q0 -75 -89 -113l-74 4h-678l-69 -4q-94 33 -94 113q18 103 72 103v7z" />
-<glyph unicode="&#x221a;" horiz-adv-x="1127" d="M254 300q621 1254 647 1284l55 25l44 -4h89l38 3q95 -26 95 -102v-7q0 -74 -90 -102l-66 4h-44q0 -22 -666 -1365q-31 -66 -95 -66h-4q-80 0 -133 142q-124 206 -124 248v7q0 78 106 98q74 0 125 -123z" />
-<glyph unicode="&#x221e;" horiz-adv-x="1313" d="M436 1013q150 0 253 -100q107 100 259 100q231 0 352 -259l14 -109v-6q0 -262 -287 -361l-81 -9q-154 0 -257 99q-100 -99 -255 -99q-245 0 -356 268l-14 104q0 247 268 358zM798 626q0 -93 126 -141h63q77 0 127 109l9 55q0 107 -126 155h-62q-93 0 -137 -136v-42z M254 622q0 -93 126 -141h63q77 0 127 109l9 55q0 107 -126 155h-62q-93 0 -137 -136v-42z" />
-<glyph unicode="&#x221f;" horiz-adv-x="1431" d="M191 1280q96 -25 96 -92v-1015h1008q85 0 100 -109q-27 -94 -100 -94h-1112q-80 0 -99 100v1097q11 113 107 113z" />
-<glyph unicode="&#x2229;" horiz-adv-x="1221" d="M609 1467q306 0 481 -300q52 -122 52 -222v-881q0 -73 -99 -94h-10q-98 21 -98 94v798q0 218 -93 292q-95 102 -233 102q-209 0 -302 -211q-24 -40 -24 -183v-794q0 -81 -98 -98h-10q-99 18 -99 102v873q0 263 256 446q142 76 277 76z" />
-<glyph unicode="&#x222b;" horiz-adv-x="920" d="M724 1687h15q155 0 228 -172v-15q-15 -99 -97 -99h-7q-62 0 -102 77q-7 6 -32 11q-49 0 -49 -99l-182 -1495q-84 -166 -227 -166h-18q-163 0 -235 195v12q21 94 90 94h18q68 0 99 -90q17 -13 32 -13h11q48 0 48 110l178 1480q80 170 230 170z" />
-<glyph unicode="&#x2248;" d="M353 1056h6q55 0 356 -84h24q35 0 97 61l47 12q98 -23 98 -91v-16q0 -78 -161 -149l-83 -13h-10q-53 0 -356 84h-20q-36 0 -84 -49q-32 -23 -67 -23q-95 18 -95 98v12q0 77 182 149zM375 756q45 0 356 -84h28q28 0 103 66l38 7q97 -21 97 -99v-8q0 -81 -174 -153l-66 -9 h-30q-34 0 -344 84h-4q-49 0 -96 -48q-31 -24 -67 -24q-95 20 -95 90v16q0 61 90 110q76 52 164 52z" />
-<glyph unicode="&#x2260;" horiz-adv-x="1028" d="M445 647h-202q-92 0 -107 116q28 100 107 100h202v89q0 78 94 91h8q94 -13 94 -95v-85h214q83 0 106 -110q-25 -106 -106 -106h-214v-116h213q107 -21 107 -113q-22 -103 -106 -103h-214v-90q-14 -97 -96 -97h-10q-90 14 -90 97v90h-210q-82 0 -98 112q0 80 106 104h202 v116z" />
-<glyph unicode="&#x2261;" horiz-adv-x="1161" d="M151 314l71 -7h717l36 4q85 0 108 -107q0 -75 -89 -113l-74 4h-678l-69 -4q-94 33 -94 113q18 103 72 103v7zM156 1093l71 -7h717l36 4q85 0 108 -107q0 -75 -89 -113l-74 4h-678l-69 -4q-94 33 -94 113q18 103 72 103v7zM156 705l71 -7h717l36 4q85 0 108 -107 q0 -75 -89 -113l-74 4h-678l-69 -4q-94 33 -94 113q18 103 72 103v7z" />
-<glyph unicode="&#x2264;" d="M846 1196q103 -22 103 -106v-8q0 -74 -111 -126l-422 -262l503 -321q30 -33 30 -71v-12q0 -87 -108 -102q-43 0 -162 81l-553 347q-29 40 -29 74q0 79 164 158q543 348 570 348h15zM187 186h668q79 0 94 -100v-17q-18 -99 -90 -99h-664q-86 0 -98 111q18 105 90 105z" />
-<glyph unicode="&#x2265;" d="M200 191h668q78 0 94 -95v-22q-18 -99 -90 -99h-672q-73 0 -90 110q17 106 90 106zM646 697q-468 286 -507 321q-29 33 -29 81q0 77 107 102q46 0 335 -193q353 -210 392 -251q18 -30 18 -58v-16q0 -63 -135 -130q-562 -356 -581 -356l-30 -4q-106 16 -106 106v4 q0 80 152 150z" />
-<glyph unicode="&#xf001;" horiz-adv-x="1021" d="M619 1466q204 0 327 -207l17 -61q0 -84 -102 -106q-78 0 -123 108q-54 55 -122 55q-95 0 -141 -107l-11 -80v-37h132l60 4q73 0 96 -99v-14q0 -70 -94 -94h-194v-717l4 -42q0 -76 -102 -99q-76 0 -109 90l4 51v717h-167q-78 0 -94 107q0 59 84 100l83 -4h90v42 q0 266 229 364q42 21 133 29zM864 1069q103 -20 103 -105v-891q-18 -99 -102 -99h-7q-98 19 -98 94v902q21 99 104 99z" />
-<glyph unicode="&#xfb01;" horiz-adv-x="1021" d="M619 1466q204 0 327 -207l17 -61q0 -84 -102 -106q-78 0 -123 108q-54 55 -122 55q-95 0 -141 -107l-11 -80v-37h132l60 4q73 0 96 -99v-14q0 -70 -94 -94h-194v-717l4 -42q0 -76 -102 -99q-76 0 -109 90l4 51v717h-167q-78 0 -94 107q0 59 84 100l83 -4h90v42 q0 266 229 364q42 21 133 29zM864 1069q103 -20 103 -105v-891q-18 -99 -102 -99h-7q-98 19 -98 94v902q21 99 104 99z" />
-<glyph unicode="&#xf002;" horiz-adv-x="1081" d="M621 1473q206 0 328 -207l19 -51l-4 -50v-983h49q74 0 95 -99v-10q-18 -99 -102 -99h-148q-83 0 -102 103v1099q-26 75 -138 85q-94 0 -141 -107l-11 -81v-37h133l60 4q74 0 96 -99v-15q0 -70 -94 -94h-195v-721l4 -42q0 -76 -103 -99q-76 0 -109 91l4 50v721h-167 q-79 0 -95 108q0 59 85 100l83 -4h90v42q0 268 230 365q43 21 133 30z" />
-<glyph unicode="&#xfb02;" horiz-adv-x="1081" d="M621 1473q206 0 328 -207l19 -51l-4 -50v-983h49q74 0 95 -99v-10q-18 -99 -102 -99h-148q-83 0 -102 103v1099q-26 75 -138 85q-94 0 -141 -107l-11 -81v-37h133l60 4q74 0 96 -99v-15q0 -70 -94 -94h-195v-721l4 -42q0 -76 -103 -99q-76 0 -109 91l4 50v721h-167 q-79 0 -95 108q0 59 85 100l83 -4h90v42q0 268 230 365q43 21 133 30z" />
-<glyph horiz-adv-x="0" />
-</font>
-</defs></svg> 
\ No newline at end of file
diff --git a/hubs/static/css/fonts/Comfortaa_Bold-webfont.ttf b/hubs/static/css/fonts/Comfortaa_Bold-webfont.ttf
deleted file mode 100644
index d10f756..0000000
Binary files a/hubs/static/css/fonts/Comfortaa_Bold-webfont.ttf and /dev/null differ
diff --git a/hubs/static/css/fonts/Comfortaa_Bold-webfont.woff b/hubs/static/css/fonts/Comfortaa_Bold-webfont.woff
deleted file mode 100644
index 7d3d8aa..0000000
Binary files a/hubs/static/css/fonts/Comfortaa_Bold-webfont.woff and /dev/null differ
diff --git a/hubs/static/css/fonts/Comfortaa_Regular-webfont.eot b/hubs/static/css/fonts/Comfortaa_Regular-webfont.eot
deleted file mode 100644
index 224ec8e..0000000
Binary files a/hubs/static/css/fonts/Comfortaa_Regular-webfont.eot and /dev/null differ
diff --git a/hubs/static/css/fonts/Comfortaa_Regular-webfont.svg b/hubs/static/css/fonts/Comfortaa_Regular-webfont.svg
deleted file mode 100644
index b1b9d23..0000000
--- a/hubs/static/css/fonts/Comfortaa_Regular-webfont.svg
+++ /dev/null
@@ -1,505 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata>
-This is a custom SVG webfont generated by Font Squirrel.
-Designer    : Johan Aakerlund - aajohan
-Foundry     : Johan Aakerlund
-</metadata>
-<defs>
-<font id="webfontxbL3cos8" horiz-adv-x="1014" >
-<font-face units-per-em="2048" ascent="1638" descent="-410" />
-<missing-glyph horiz-adv-x="508" />
-<glyph unicode=" "  horiz-adv-x="508" />
-<glyph unicode="&#x09;" horiz-adv-x="508" />
-<glyph unicode="&#xa0;" horiz-adv-x="508" />
-<glyph unicode="!" horiz-adv-x="511" d="M214 1442h12q60 0 73 -69v-955q-17 -72 -77 -72q-81 12 -81 69v962q14 65 73 65zM205 206h8q103 -15 103 -92v-22q0 -71 -95 -92h-12q-79 0 -99 103q21 103 95 103z" />
-<glyph unicode="&#x22;" horiz-adv-x="557" d="M159 1559q76 -19 76 -68q-21 -312 -52 -312l-28 -8q-50 0 -56 124l-20 184q16 80 80 80zM407 1559q51 0 72 -76q-29 -296 -44 -296q-17 -16 -32 -16h-4q-56 0 -56 136l-20 184q0 54 84 68z" />
-<glyph unicode="#" horiz-adv-x="1336" d="M996 1431q68 -19 68 -64v-11q0 -29 -76 -389h110l34 4q55 0 71 -76q-15 -75 -75 -75h-170l-37 -192h139q87 -8 87 -76q-14 -71 -72 -71v-4l-19 4h-166q-83 -419 -98 -449q-25 -34 -60 -34h-8q-67 14 -67 68v3l83 412h-215q-10 0 -53 -246q-41 -200 -53 -207 q-24 -34 -60 -34q-76 15 -76 75l83 412h-102l-22 -4q-57 0 -72 79v4q0 51 75 68h155l38 192h-136q-75 15 -75 75q12 72 67 72v4l38 -4h136q82 438 98 438q28 22 57 22q61 0 71 -75l-75 -385h219q80 415 94 434q28 30 64 30zM589 820l-38 -192h219l37 192h-218z" />
-<glyph unicode="$" d="M477 1652h20q50 0 65 -73v-128q93 -7 209 -112q43 -43 43 -66v-23q0 -50 -74 -62q-30 0 -96 73q-33 28 -82 43v-460q177 -65 252 -206q58 -109 58 -208q0 -278 -286 -403l-24 -4v-127q-18 -74 -73 -74q-77 16 -77 74v104q0 6 -89 19q-173 59 -248 182l-4 23q13 74 74 74 q40 0 108 -85q87 -57 159 -62v580q-132 41 -182 113q-101 104 -101 239v28q0 189 194 305q64 31 89 31v140q20 65 65 65zM276 1091v-31q0 -124 136 -198v414q-136 -67 -136 -185zM562 669v-511h4q155 91 155 232v39q0 143 -159 240z" />
-<glyph unicode="%" horiz-adv-x="1610" d="M452 1436h19q167 0 284 -152q68 -100 68 -205q0 -233 -242 -344q-69 -19 -114 -19h-7q-210 0 -322 204q-38 77 -38 156q0 236 250 344q51 16 102 16zM1286 1436h11q68 -14 68 -69v-15q0 -22 -140 -201l-860 -1136q-29 -15 -45 -15h-4q-72 15 -72 64v16q0 31 106 159 l894 1181q23 16 42 16zM248 1079v-7q0 -150 166 -205l38 -3h19q147 0 201 170l4 42q0 154 -163 208l-49 8q-152 0 -209 -159zM1149 723q211 0 333 -219q27 -80 27 -140v-12q0 -211 -223 -325q-69 -27 -137 -27h-7q-184 0 -303 178q-50 86 -50 170v23q0 190 190 307 q91 45 170 45zM933 364q0 -150 156 -209l53 -7h15q143 0 200 163l4 34v26q0 149 -174 201l-38 4q-159 0 -212 -178z" />
-<glyph unicode="&#x26;" horiz-adv-x="1457" d="M490 1433h19q193 0 285 -212q11 -48 11 -83v-19q0 -146 -155 -270l-38 -41l322 -323h4l155 156q26 19 49 19q70 0 80 -84q0 -42 -133 -159l-41 -45l216 -217q15 -19 15 -41v-12q-15 -72 -72 -72h-11q-42 0 -141 114l-121 118q-216 -235 -284 -235q-66 -27 -133 -27 q-220 0 -349 220q-38 89 -38 171q0 194 212 367l46 50q-186 173 -186 258q-8 0 -8 68q0 187 201 284q54 15 95 15zM354 1149v-30q0 -77 144 -198h4q148 128 148 198v15q0 95 -114 140l-38 4q-92 0 -137 -99zM289 398v-19q0 -147 167 -212l57 -8q131 0 250 152l61 61 l-322 322h-4q-205 -182 -205 -265z" />
-<glyph unicode="'" horiz-adv-x="346" d="M172 1546q76 -19 76 -68q-21 -312 -52 -312l-28 -8q-50 0 -56 124l-20 184q16 80 80 80z" />
-<glyph unicode="(" horiz-adv-x="758" d="M603 1596h11q69 -13 69 -68v-12l-76 -203q-131 -353 -131 -724q0 -463 207 -915l4 -15q-14 -77 -73 -77h-7q-65 0 -104 138q-176 409 -176 873q0 498 222 977q28 26 54 26z" />
-<glyph unicode=")" horiz-adv-x="758" d="M140 1600h15q53 0 96 -138q176 -419 176 -866q0 -527 -229 -993q-29 -19 -50 -19h-8q-60 0 -73 77l81 202q130 368 130 729q0 453 -207 916l-4 15q13 77 73 77z" />
-<glyph unicode="*" horiz-adv-x="1024" d="M522 1559q76 -19 76 -76v-8l-52 -168v-4h4l160 100l24 4q76 -15 76 -76v-12q0 -41 -60 -68l-124 4h-72l152 -124l12 -32v-20q0 -59 -76 -72q-73 0 -88 112l-32 96h-4l-48 -164q-30 -44 -72 -44q-76 17 -76 68v16q0 47 92 100l76 64h-4l-196 -4q-60 24 -60 76v4 q0 61 80 76q29 0 136 -80l48 -24v4l-52 168v8q0 59 80 76z" />
-<glyph unicode="+" d="M512 1117h12q59 0 72 -76v-224h212q92 -8 92 -80q-15 -76 -76 -76v-4l-20 4h-208v-228q-14 -76 -76 -76h-4q-76 15 -76 68v236h-204l-24 -4q-60 0 -76 84v4q0 54 80 72h224v228q14 72 72 72z" />
-<glyph unicode="," horiz-adv-x="557" d="M254 282h16q136 -28 136 -136l4 -4l-4 -4v-4l8 -56v-16q0 -184 -184 -276q-37 -24 -60 -24q-42 0 -52 60q0 47 84 64q42 24 84 80l16 44l-48 -8q-148 25 -148 144v4q0 82 104 124q16 8 44 8z" />
-<glyph unicode="-" horiz-adv-x="670" d="M144 648h400q59 0 76 -80q-18 -76 -76 -76h-400q-65 0 -76 84q20 72 76 72z" />
-<glyph unicode="&#xad;" horiz-adv-x="670" d="M144 648h400q59 0 76 -80q-18 -76 -76 -76h-400q-65 0 -76 84q20 72 76 72z" />
-<glyph unicode="." horiz-adv-x="557" d="M269 274q105 0 135 -125v-24q0 -75 -96 -118q-14 -7 -39 -7h-4q-112 0 -135 139q0 88 100 128q14 7 39 7z" />
-<glyph unicode="/" horiz-adv-x="770" d="M628 1517q76 -13 76 -72v-20q-504 -1389 -556 -1516q-30 -32 -60 -32h-8q-62 0 -76 80q4 27 556 1524q35 36 68 36z" />
-<glyph unicode="0" horiz-adv-x="989" d="M446 1437q247 0 378 -265q72 -221 72 -408v-87q0 -231 -95 -465q-137 -212 -347 -212h-12q-228 0 -359 242q-83 213 -83 473v11q0 276 98 499q141 212 348 212zM136 737v-41q0 -261 95 -439q92 -113 208 -113h11q256 0 299 393q11 62 15 185q0 219 -76 420 q-94 151 -238 151q-175 0 -257 -193q-57 -189 -57 -363z" />
-<glyph unicode="1" horiz-adv-x="568" d="M305 1437h12q68 -15 68 -65v-1300q-13 -72 -72 -72h-4q-72 15 -72 64v1198q-102 -34 -133 -34q-47 0 -64 69v19q0 56 152 87z" />
-<glyph unicode="2" horiz-adv-x="976" d="M431 1436q204 0 355 -182q79 -120 79 -249q0 -197 -193 -378l-419 -480h563q56 0 68 -71v-4q-11 -72 -72 -72h-733q-71 13 -71 72v4q0 36 71 102l586 668q49 70 49 159q0 192 -200 268q-33 11 -76 11h-11q-184 0 -265 -196q-11 -41 -15 -98q-26 -53 -68 -53h-7 q-72 13 -72 68q0 226 215 370q115 61 216 61z" />
-<glyph unicode="3" horiz-adv-x="955" d="M445 1432q168 0 290 -151q68 -92 68 -203v-15q0 -156 -136 -275q196 -142 196 -358q0 -223 -211 -370q-109 -60 -215 -60h-11q-252 0 -392 260q-34 96 -34 173q0 53 79 68q57 0 68 -75q0 -162 170 -256q62 -23 120 -23q169 0 256 177q19 53 19 91v30q0 160 -177 248 l-124 27q-38 29 -38 64v4q0 71 102 71q74 0 154 98q30 64 30 117q0 122 -120 188q-43 23 -98 23q-140 0 -200 -151q-12 -109 -26 -109q-27 -30 -53 -30q-75 17 -75 64v19q0 196 196 313q75 37 162 41z" />
-<glyph unicode="4" horiz-adv-x="1103" d="M718 1425h23q41 0 64 -64l-4 -37v-752h117l34 3q52 0 71 -75q0 -51 -64 -75l-56 4h-102v-365q0 -49 -71 -64h-4q-72 13 -72 71v358h-507l-91 -4q-56 24 -56 68v15q0 26 38 56q602 783 635 835q24 26 45 26zM229 572h425v553z" />
-<glyph unicode="5" d="M157 1429l39 -4h575q60 0 75 -78q0 -58 -79 -75h-524v-379h215q252 0 395 -259q44 -107 44 -188q0 -231 -220 -383q-113 -63 -223 -63h-12q-261 0 -407 270q-35 103 -35 172q26 71 78 71q83 0 83 -133q49 -145 152 -196q80 -31 133 -31q196 0 278 199q16 40 16 94 q0 214 -227 286l-90 8h-262q-52 0 -71 63v559q0 42 67 67z" />
-<glyph unicode="6" horiz-adv-x="951" d="M569 1436q51 0 68 -76q0 -30 -91 -173l-188 -328v-4l57 4h33q206 0 351 -207q64 -114 64 -222q0 -214 -196 -358q-111 -72 -230 -72h-19q-205 0 -354 204q-64 116 -64 226q0 145 106 286l407 701q31 19 56 19zM151 448v-37q0 -155 177 -245q50 -15 102 -19q190 0 271 200 l11 71v15q0 198 -215 272l-71 7q-185 0 -268 -203z" />
-<glyph unicode="7" horiz-adv-x="964" d="M105 1429h728q68 -14 68 -60v-19q0 -20 -38 -76l-709 -1255q-28 -19 -49 -19h-3q-72 13 -72 72v11q10 36 660 1180l7 19h-580q-76 15 -76 75q16 72 64 72z" />
-<glyph unicode="8" horiz-adv-x="972" d="M447 1439q171 0 291 -152q68 -93 68 -204v-19q0 -150 -136 -273q197 -142 197 -359q0 -215 -197 -360q-111 -72 -231 -72h-19q-206 0 -356 204q-64 117 -64 228q0 224 212 374q-85 66 -114 182q-11 28 -11 76v19q0 190 182 306q91 50 178 50zM235 1068q0 -143 170 -201 l42 -4q149 0 204 159l8 53q0 157 -167 208l-49 4q-145 0 -201 -155zM148 435q0 -200 208 -276q28 -11 83 -11q188 0 269 208l8 57v38q0 161 -186 249q-52 16 -95 16q-203 0 -276 -209z" />
-<glyph unicode="9" horiz-adv-x="972" d="M431 1435q224 0 367 -214q60 -114 60 -213q0 -161 -131 -315l-502 -674q-27 -19 -49 -19q-75 15 -75 75q0 34 120 180l240 326h-4l-22 -4q-246 0 -386 232q-49 102 -49 199q0 238 232 378q101 49 199 49zM150 1023v-34q0 -149 165 -240q50 -22 116 -22q162 0 247 153 q30 57 30 124v4q0 191 -198 266q-28 11 -75 11h-23q-159 0 -247 -180q-15 -53 -15 -82z" />
-<glyph unicode=":" horiz-adv-x="557" d="M292 952q89 0 124 -104v-32q0 -75 -104 -112h-20q-124 19 -124 124q25 124 124 124zM280 284h16q95 0 120 -112v-20q0 -87 -120 -116q-128 22 -128 128q26 120 112 120z" />
-<glyph unicode=";" horiz-adv-x="557" d="M267 926q89 0 124 -104v-32q0 -75 -104 -112h-20q-124 19 -124 124q25 124 124 124zM291 258q128 0 128 -192v-4q0 -186 -224 -260h-20q-48 10 -48 48v16q12 48 56 48l24 -4q100 53 100 104l-12 -4q-132 21 -132 124q0 88 100 124h28z" />
-<glyph unicode="&#x37e;" horiz-adv-x="557" d="M267 926q89 0 124 -104v-32q0 -75 -104 -112h-20q-124 19 -124 124q25 124 124 124zM291 258q128 0 128 -192v-4q0 -186 -224 -260h-20q-48 10 -48 48v16q12 48 56 48l24 -4q100 53 100 104l-12 -4q-132 21 -132 124q0 88 100 124h28z" />
-<glyph unicode="&#x3c;" d="M830 1102q76 -19 76 -76v-8q0 -57 -132 -120q-5 -9 -428 -268q17 -17 536 -340q24 -28 24 -56v-4q0 -65 -80 -76q-31 0 -148 80l-536 332q-28 31 -28 60q0 59 112 108q571 368 596 368h8z" />
-<glyph unicode="=" d="M212 833h612q59 0 76 -80q-18 -76 -76 -76h-612q-65 0 -76 84q20 72 76 72zM216 501h604q80 -16 80 -80q-16 -76 -76 -76h-620q-56 0 -68 84q0 54 80 72z" />
-<glyph unicode="&#x3e;" d="M217 1120q29 0 236 -136q428 -264 460 -292q16 -21 16 -44v-8q0 -56 -96 -96q-583 -372 -604 -372h-16q-76 14 -76 76v4q0 58 128 120l432 276q-516 316 -540 340q-20 28 -20 52q16 80 80 80z" />
-<glyph unicode="?" horiz-adv-x="980" d="M497 1433q180 0 326 -159q102 -128 102 -280q0 -189 -170 -337q-175 -96 -175 -281q-11 -75 -75 -75q-72 16 -72 64v30q0 236 250 390q94 93 94 220q0 161 -170 257q-76 23 -121 23q-167 0 -261 -178l-27 -129q-32 -41 -64 -41q-76 16 -76 72q0 204 201 356 q123 68 238 68zM493 198h16q66 0 94 -83v-26q-18 -95 -106 -95q-98 21 -98 98q0 87 94 106z" />
-<glyph unicode="@" horiz-adv-x="2019" d="M936 1571h36q416 0 724 -356q212 -271 212 -596q0 -406 -276 -516q-71 -32 -144 -32h-28q-139 0 -164 52l-4 20l4 100v4q-176 -168 -380 -168h-32q-279 0 -464 280q-68 135 -68 272q0 306 300 484q128 60 248 60q311 0 492 -304q56 -124 56 -256v-384l28 -4 q149 0 232 148q40 97 40 212v52q0 325 -272 580q-237 196 -520 196q-418 0 -676 -368q-124 -200 -124 -428v-4q0 -378 312 -632q223 -164 488 -164q223 0 448 136l20 4q80 -16 80 -80q0 -98 -336 -192q-94 -24 -184 -24h-52q-347 0 -640 264q-296 298 -296 696 q0 405 328 712q280 236 612 236zM508 635v-12q0 -238 240 -360q76 -28 136 -28h32q199 0 328 200q48 94 48 180v16q0 230 -228 352q-79 36 -164 36h-4q-242 0 -364 -252q-24 -78 -24 -132z" />
-<glyph unicode="A" horiz-adv-x="1191" d="M556 1428q69 0 102 -139q454 -1182 458 -1210v-11q0 -56 -71 -68h-4q-66 0 -94 128l-169 439h-440l-206 -544q-30 -23 -53 -23h-8q-71 13 -71 71v4l128 346q335 873 364 969q34 38 64 38zM556 1142l-158 -428h323v4l-161 424h-4z" />
-<glyph unicode="B" horiz-adv-x="998" d="M127 1432l18 -3h230l15 3q172 0 294 -162q61 -90 61 -196v-11q0 -129 -102 -245q245 -135 245 -392q0 -258 -268 -396q-86 -30 -154 -30h-339q-72 13 -72 72v1285q11 72 72 72v3zM202 1282v-423h139q185 0 238 132q15 38 15 76v11q0 146 -170 200l-79 4h-143zM202 712 v-565h196q216 0 290 124q49 69 49 155v7q0 203 -222 272l-106 7h-207z" />
-<glyph unicode="C" horiz-adv-x="1363" d="M777 1436q223 0 416 -136q15 -29 15 -45v-8q0 -64 -79 -72h-4l-132 68q-132 42 -216 42q-269 0 -465 -246q-98 -165 -98 -321q0 -315 295 -499q131 -68 261 -68h11q166 0 336 106h23q68 -15 68 -68v-11q0 -80 -253 -155q-79 -23 -166 -23h-19q-355 0 -594 329 q-113 190 -113 389q0 373 340 608q182 110 374 110z" />
-<glyph unicode="D" horiz-adv-x="1195" d="M127 1441l19 -4h193l42 4q323 0 561 -281q152 -197 152 -447q0 -344 -303 -580q-192 -133 -406 -133h-258q-72 13 -72 72v1293q11 72 72 72v4zM203 1293v-1145h163q361 0 535 349q45 119 45 227q0 261 -231 455q-143 114 -425 114h-87z" />
-<glyph unicode="E" horiz-adv-x="1094" d="M135 1442l19 -4h744l15 4q65 0 76 -83q-15 -69 -83 -69h-695v-512h455l54 4q51 0 68 -76q0 -50 -61 -76l-76 4h-440v-486h713q53 0 65 -80q-20 -68 -68 -68h-786q-72 13 -72 72v1294q11 72 72 72v4z" />
-<glyph unicode="F" horiz-adv-x="1031" d="M127 1442l19 -4h744l15 4q65 0 76 -83q-15 -69 -83 -69h-695v-512h455l54 4q51 0 68 -76q0 -50 -61 -76l-76 4h-440v-539l4 -23q-17 -72 -72 -72h-8q-72 13 -72 72v1294q11 72 72 72v4z" />
-<glyph unicode="G" horiz-adv-x="1292" d="M745 1436q229 0 412 -128q19 -26 19 -49v-4q0 -58 -76 -72q-12 0 -147 64q-88 34 -170 34h-61q-211 0 -404 -204q-125 -171 -125 -351v-15q0 -294 272 -480q142 -80 284 -80h15q140 0 280 76v344h-273q-71 12 -71 72v3q12 72 71 72h352q56 0 68 -72v-419q0 -92 -45 -114 q-193 -113 -375 -113h-22q-355 0 -594 329q-113 186 -113 389q0 361 321 597q197 121 382 121z" />
-<glyph unicode="H" horiz-adv-x="1186" d="M110 1433h15q68 -14 68 -60v-598h712v587q12 71 68 71h11q68 -13 68 -68v-1301q0 -49 -72 -64h-4q-71 13 -71 72v560h-712v-564q0 -56 -71 -68h-4q-58 0 -72 76v1274q9 83 64 83z" />
-<glyph unicode="I" horiz-adv-x="539" d="M132 1448l19 -3h142l15 3q76 -16 76 -76q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72h-180q-72 13 -72 72v4q15 73 65 73h23v1147h-16q-63 0 -72 80v4q0 47 72 68z" />
-<glyph unicode="J" horiz-adv-x="1022" d="M862 1439h12q55 0 68 -72v-923q0 -239 -224 -383q-105 -61 -216 -61h-19q-220 0 -369 213q-68 113 -68 235q16 72 65 72h15q72 0 72 -118q6 -82 99 -182q91 -72 197 -72q211 0 289 220q11 40 11 80v923q13 68 68 68z" />
-<glyph unicode="K" horiz-adv-x="1112" d="M134 1434h3q72 -12 72 -68v-653q700 699 706 699l27 4h7q68 -13 68 -68v-12q0 -37 -79 -102l-465 -468l533 -660l3 -23v-11q0 -56 -71 -68h-4q-45 0 -125 117l-445 540l-155 -159v-434q0 -56 -72 -68h-3q-58 0 -72 75v1284q14 75 72 75z" />
-<glyph unicode="L" horiz-adv-x="997" d="M110 1433h15q68 -14 68 -60v-1226h617q61 0 72 -79q-20 -68 -72 -68h-692q-58 0 -72 76v1274q9 83 64 83z" />
-<glyph unicode="M" horiz-adv-x="1490" d="M124 1432h15q59 0 83 -98l480 -1073q19 22 336 748l186 400q22 23 49 23h15q55 0 64 -83v-1273q-14 -76 -72 -76h-4q-71 12 -71 68v941h-4q-423 -960 -438 -983q-29 -26 -57 -26q-66 0 -117 159l-378 846h-4v-937q0 -56 -71 -68h-4q-58 0 -72 76v1273q9 83 64 83z" />
-<glyph unicode="N" horiz-adv-x="1321" d="M102 1431h15q48 0 83 -75q56 -63 821 -1051q8 0 8 -11l3 -4h4v1073q13 68 68 68h11q56 0 68 -71v-1285q0 -62 -79 -75q-43 0 -132 132l-787 1005v-1065q0 -56 -72 -68h-3q-58 0 -72 75v1269q9 83 64 83z" />
-<glyph unicode="O" horiz-adv-x="1595" d="M756 1435q363 0 607 -336q110 -191 110 -385q0 -359 -325 -597q-184 -117 -385 -117h-15q-370 0 -604 344q-106 174 -106 377q0 343 302 578q196 136 416 136zM185 710q0 -274 242 -461q151 -102 321 -102h19q268 0 453 238q106 153 106 333q0 309 -283 490 q-140 80 -287 80q-283 0 -469 -246q-102 -147 -102 -332z" />
-<glyph unicode="P" horiz-adv-x="963" d="M110 1438h346q202 0 345 -209q53 -107 53 -193v-27q0 -189 -171 -326q-116 -80 -227 -80h-262v-535q0 -55 -72 -68h-4q-58 0 -72 76v1278q9 84 64 84zM194 1290v-539h235q190 0 262 182q15 38 15 91q0 167 -171 247q-42 19 -98 19h-243z" />
-<glyph unicode="Q" horiz-adv-x="1599" d="M764 1435q363 0 608 -336q109 -190 109 -385q0 -233 -155 -442v-4q159 -156 159 -189v-7q0 -56 -76 -72q-44 0 -143 121q-29 23 -42 45q-212 -166 -453 -166h-15q-369 0 -604 344q-106 174 -106 377q0 343 302 578q197 136 416 136zM193 710q0 -274 242 -461 q151 -102 321 -102h19q188 0 344 125q-153 166 -170 193v26q13 68 68 68h11q38 0 125 -106l71 -72h4q106 162 106 337q0 309 -283 491q-139 79 -287 79q-283 0 -469 -246q-102 -147 -102 -332z" />
-<glyph unicode="R" horiz-adv-x="976" d="M106 1435h315q201 0 329 -212q41 -82 41 -171v-15q0 -198 -193 -325l-37 -19q344 -593 344 -606v-19q0 -56 -72 -68h-4q-54 0 -113 129l-311 530h-215v-591q0 -56 -72 -68h-4q-58 0 -72 76v1275q9 84 64 84zM190 1291v-485h215q179 0 235 193l4 31v30q0 142 -159 216 q-45 15 -140 15h-155z" />
-<glyph unicode="S" horiz-adv-x="926" d="M454 1437q186 0 310 -168l4 -16v-23q0 -49 -73 -61q-30 0 -103 81q-66 42 -126 42h-23q-126 0 -191 -134q-15 -32 -15 -65v-31q0 -145 175 -210q126 0 272 -118q141 -143 141 -314q0 -210 -180 -344q-110 -76 -244 -76q-217 0 -359 187l-8 31q13 72 73 72q40 0 103 -80 q94 -65 172 -65h34q152 0 245 172q15 56 15 84v38q0 151 -172 245l-195 54q-218 125 -218 328v27q0 200 214 313q80 31 149 31z" />
-<glyph unicode="T" horiz-adv-x="1225" d="M102 1436h933q68 -13 68 -68v-15q0 -55 -83 -64h-376v-1221q0 -56 -72 -68h-3q-58 0 -72 76v1213h-383q-76 15 -76 75q16 72 64 72z" />
-<glyph unicode="U" horiz-adv-x="1168" d="M104 1433h15q68 -14 68 -60v-806q0 -260 148 -348q93 -72 208 -72q221 0 333 227q23 71 23 148v840q12 71 68 71h11q68 -13 68 -68v-881q0 -225 -216 -393q-136 -91 -276 -91h-26q-235 0 -409 231q-79 124 -79 306v813q9 83 64 83z" />
-<glyph unicode="V" horiz-adv-x="1246" d="M114 1441q62 0 102 -159l372 -986h3l417 1115q31 30 61 30h4q58 0 72 -76l-478 -1289q-17 -76 -76 -76h-3q-68 0 -103 148q-451 1190 -451 1213v8q0 60 80 72z" />
-<glyph unicode="W" horiz-adv-x="1777" d="M102 1436h16q64 0 83 -114l280 -973h8q292 1031 311 1061q25 26 53 26h11q67 0 87 -136q27 -74 277 -955h4l307 1057q27 34 53 34h15q68 -14 68 -60v-19l-383 -1327q-31 -30 -60 -30h-4q-71 0 -91 140q-246 836 -277 959h-3l-307 -1065q-28 -34 -61 -34h-15 q-62 0 -84 144q-325 1106 -352 1220q16 72 64 72z" />
-<glyph unicode="X" horiz-adv-x="1300" d="M93 1437h16q44 0 72 -56l425 -543l458 588q20 11 38 11h12q55 0 68 -72v-3q0 -33 -102 -152l-383 -493l477 -611l8 -30v-4q-13 -72 -72 -72h-4q-49 0 -83 72l-417 531l-459 -588q-20 -15 -42 -15h-4q-72 13 -72 72v11q0 25 163 224l322 417q-470 596 -481 619l-4 22 q16 72 64 72z" />
-<glyph unicode="Y" horiz-adv-x="1153" d="M106 1433h16q49 0 79 -72l345 -516h4q372 562 387 573q20 15 34 15h23q46 0 64 -72q0 -32 -129 -209l-307 -458v-611q-9 -83 -64 -83h-16q-49 0 -68 61v621q0 14 -159 251l-269 405l-4 23q16 72 64 72z" />
-<glyph unicode="Z" horiz-adv-x="1271" d="M98 1437h1021q55 0 68 -72v-3q0 -29 -83 -126l-842 -1088h853q72 -11 72 -72v-4q-13 -72 -72 -72h-1009q-60 0 -72 80q0 28 182 254l740 956h-846q-76 15 -76 75q16 72 64 72z" />
-<glyph unicode="[" horiz-adv-x="779" d="M319 1581l40 -4h292l44 4q72 -25 72 -72v-12q0 -50 -64 -76l-68 4h-232v-1692h292q72 -16 72 -68v-12q0 -66 -84 -76h-356q-80 16 -80 80v1832q7 88 72 88v4z" />
-<glyph unicode="\" horiz-adv-x="691" d="M76 1548h4q76 0 116 -172l508 -1388q-14 -80 -76 -80h-16q-61 0 -104 168q-472 1272 -508 1392q12 80 76 80z" />
-<glyph unicode="]" horiz-adv-x="758" d="M94 1581l60 -4h276l44 4q72 -20 72 -76v-1860q0 -53 -76 -68h-368q-66 0 -76 84v4q0 49 76 72l20 -4h268v1692h-220l-76 -4q-68 23 -68 80q0 55 68 80z" />
-<glyph unicode="^" horiz-adv-x="942" d="M384 1434h16q53 0 112 -116q232 -351 232 -372v-24q0 -56 -84 -68q-50 0 -140 168l-128 188l-220 -340q-34 -16 -56 -16q-54 0 -72 80q0 32 80 148q207 328 228 340z" />
-<glyph unicode="_" horiz-adv-x="958" d="M75 -29h885q74 -13 74 -70v-12q-14 -70 -70 -70h-889q-63 0 -74 82q20 70 74 70z" />
-<glyph unicode="`" horiz-adv-x="752" d="M283 1411h12q39 0 108 -84q180 -169 180 -192l4 -20q-16 -76 -76 -76h-8q-44 0 -164 136q-128 111 -128 156v12q0 52 72 68z" />
-<glyph unicode="a" horiz-adv-x="1199" d="M554 1023q290 0 459 -284q52 -115 52 -239v-433q0 -55 -71 -67h-4q-48 0 -71 56v4l4 93v4q-165 -157 -355 -157h-29q-260 0 -434 261q-63 126 -63 254q0 285 280 452q119 56 232 56zM188 519v-11q0 -223 224 -336q71 -26 127 -26h29q186 0 307 186q44 88 44 168v15 q0 215 -212 329q-74 33 -153 33h-4q-226 0 -340 -235q-22 -73 -22 -123z" />
-<glyph unicode="b" horiz-adv-x="1230" d="M141 1432h11q68 -15 68 -65v-491q165 159 371 159q199 0 362 -151q155 -163 155 -366q0 -291 -276 -458q-119 -60 -230 -60h-30q-209 0 -389 196q-110 147 -110 348v823q0 50 68 65zM220 529v-19q0 -231 242 -344q65 -19 117 -19h23q225 0 340 242q19 73 19 113v23 q0 230 -246 344q-75 19 -117 19h-15q-225 0 -340 -238q-23 -67 -23 -121z" />
-<glyph unicode="c" horiz-adv-x="1036" d="M547 1026q198 0 360 -149q11 -20 11 -38v-4q-13 -71 -71 -71h-4q-27 0 -120 71q-83 42 -165 42h-22q-218 0 -330 -229q-26 -77 -26 -139q0 -222 229 -337q69 -26 146 -26q129 0 254 105l30 7h12q55 0 67 -71v-3q0 -77 -240 -169q-81 -15 -120 -15h-30q-207 0 -385 195 q-109 154 -109 318q0 250 221 420q141 93 292 93z" />
-<glyph unicode="d" horiz-adv-x="1200" d="M982 1432h15q68 -14 68 -61v-748l4 -128q0 -148 -121 -310q-171 -185 -385 -185h-30q-209 0 -389 196q-110 156 -110 322q0 251 223 423q142 94 295 94q197 0 370 -155v427l-4 60q21 65 64 65zM181 529v-19q0 -231 242 -344q65 -19 117 -19h23q225 0 340 242 q19 73 19 113v23q0 230 -246 344q-75 19 -117 19h-15q-225 0 -340 -238q-23 -67 -23 -121z" />
-<glyph unicode="e" horiz-adv-x="1166" d="M543 1025q296 0 460 -281q56 -110 56 -239v-19q-13 -75 -71 -75h-789q44 -149 190 -228q86 -33 161 -33q87 0 199 56h22q67 -13 67 -68v-11q0 -92 -269 -127h-26q-276 0 -442 258q-67 122 -67 255q0 281 266 448q129 64 243 64zM187 557h719q0 77 -90 199 q-123 116 -243 116h-41q-180 0 -296 -176q-40 -70 -49 -139z" />
-<glyph unicode="f" horiz-adv-x="866" d="M598 1437h91q52 0 64 -80q0 -51 -76 -68h-57q-138 0 -182 -152l-3 -79v-53h163l60 3q48 0 65 -72v-11q0 -48 -69 -65h-219v-750l3 -42q0 -51 -75 -68q-52 0 -76 64l4 46v750h-198q-52 0 -64 80q0 38 61 68l75 -3h122v68q0 254 223 348z" />
-<glyph unicode="g" horiz-adv-x="1208" d="M548 1021q227 0 394 -189q115 -158 115 -298l-4 -126v-449q0 -126 -193 -275q-149 -97 -312 -97q-279 0 -461 249q-33 55 -33 74v11q0 49 67 64h11q50 0 85 -93q134 -168 331 -168q237 0 357 216l7 48v167q-165 -152 -353 -152h-30q-205 0 -382 193q-108 153 -108 316 q0 248 219 416q140 93 290 93zM184 523v-18q0 -227 238 -338q64 -19 115 -19h22q222 0 335 238q18 71 18 111v23q0 226 -241 338q-75 18 -116 18h-14q-222 0 -335 -234q-22 -65 -22 -119z" />
-<glyph unicode="h" horiz-adv-x="1125" d="M137 1430h15q68 -14 68 -60v-461q145 125 310 125q252 0 403 -238q57 -106 57 -200v-528q0 -56 -72 -68h-3q-54 0 -72 68v506q0 204 -211 294q-51 15 -102 15q-210 0 -295 -223q-15 -48 -15 -158v-434q0 -56 -72 -68h-3q-54 0 -72 68v1291q15 71 64 71z" />
-<glyph unicode="i" horiz-adv-x="431" d="M177 1286q72 -18 72 -64v-22q0 -53 -79 -64q-51 0 -68 75q15 75 75 75zM177 1030q72 -18 72 -64v-898q0 -56 -72 -68h-4q-57 0 -71 75v869q9 86 75 86z" />
-<glyph unicode="j" horiz-adv-x="656" d="M436 1277q74 -15 74 -74q0 -62 -78 -74q-66 19 -66 63v22q0 45 70 63zM440 1026q70 -14 70 -70v-928q0 -276 -262 -403q-92 -33 -159 -33l-4 4h-4l-3 -4h-4q-63 0 -74 81q0 55 81 67q208 0 277 210l8 111v895q0 58 74 70z" />
-<glyph unicode="k" horiz-adv-x="1056" d="M141 1435h15q69 -15 69 -61v-746q535 354 624 405h19q60 0 72 -79q0 -46 -121 -110q-294 -199 -307 -201v-3l424 -538l4 -23v-3q-13 -72 -72 -72h-7q-44 0 -133 128l-341 424h-3l-159 -102v-386q0 -56 -72 -68h-4q-54 0 -72 68v1295q15 72 64 72z" />
-<glyph unicode="l" horiz-adv-x="473" d="M129 1427h15q68 -14 68 -60v-1220h79q49 0 64 -72v-3q-12 -72 -72 -72h-146q-58 0 -72 75v1270q9 82 64 82z" />
-<glyph unicode="m" horiz-adv-x="1675" d="M137 1006q70 -18 70 -62v-37q122 99 265 99q190 0 334 -176q59 109 242 165l84 11q230 0 364 -220q44 -92 44 -176v-548q0 -48 -70 -62h-3q-70 12 -70 70v532q0 181 -191 250l-51 7h-37q-152 0 -232 -176q-11 -39 -11 -66v-544q-13 -73 -69 -73h-4q-70 12 -70 66v452 q0 188 -51 235q-79 106 -206 106h-11q-175 0 -246 -187q-11 -45 -11 -118v-488q0 -54 -70 -66h-3q-56 0 -70 73v849q8 84 73 84z" />
-<glyph unicode="n" horiz-adv-x="1197" d="M153 1023q71 -18 71 -64v-82q162 146 354 146q211 0 374 -176q119 -147 119 -309v-475q0 -49 -71 -63h-4q-71 13 -71 71v418q0 281 -242 370q-59 15 -105 15h-11q-203 0 -314 -210q-29 -64 -29 -205v-392q0 -55 -71 -67h-4q-57 0 -71 75v862q9 86 75 86z" />
-<glyph unicode="o" horiz-adv-x="1170" d="M547 1018q197 0 357 -149q152 -160 152 -360q0 -286 -271 -450q-117 -59 -227 -59h-30q-205 0 -382 193q-108 153 -108 316q0 248 219 416q140 93 290 93zM187 520v-18q0 -204 197 -316q71 -37 152 -37h22q211 0 323 219q26 69 26 134v18q0 170 -156 286q-91 63 -208 63 q-231 0 -338 -241q-18 -59 -18 -108z" />
-<glyph unicode="p" horiz-adv-x="1172" d="M566 1020q196 0 355 -148q152 -160 152 -359q0 -285 -270 -448q-117 -59 -226 -59h-30q-176 0 -344 152v-511q0 -47 -74 -63q-53 0 -70 74v822q0 384 363 518q45 14 144 22zM207 524v-19q0 -202 196 -314q71 -37 152 -37h22q211 0 322 218q26 69 26 133v19 q0 169 -155 285q-92 63 -208 63q-230 0 -336 -241q-19 -59 -19 -107z" />
-<glyph unicode="q" horiz-adv-x="1178" d="M550 1010q195 0 354 -147q151 -147 151 -391v-818q-17 -74 -70 -74q-74 16 -74 63v508q-164 -151 -350 -151h-29q-204 0 -380 192q-107 152 -107 313q0 246 217 413q140 92 288 92zM192 516v-18q0 -202 196 -313q70 -37 151 -37h22q210 0 321 217q26 69 26 133v18 q0 168 -155 284q-91 63 -207 63q-229 0 -335 -240q-19 -58 -19 -107z" />
-<glyph unicode="r" horiz-adv-x="925" d="M174 1031q72 -18 72 -64v-83q165 147 353 147q101 0 215 -49q30 -31 30 -60v-4q-12 -71 -71 -71h-4q-103 33 -155 33h-22q-221 0 -324 -229q-22 -61 -22 -139v-444q0 -56 -72 -68h-4q-57 0 -71 75v869q9 87 75 87z" />
-<glyph unicode="s" horiz-adv-x="968" d="M445 1017q257 0 404 -233l3 -29v-4q0 -59 -74 -70q-49 0 -100 85q-103 100 -233 100q-171 0 -270 -163l-3 -19q0 -49 111 -59q426 -103 466 -118q107 -70 107 -178v-3q0 -154 -226 -282q-97 -44 -207 -44q-225 0 -381 211q-15 22 -15 41v22q0 54 82 63q35 0 100 -93 q99 -92 229 -92q156 0 259 148l7 22v4q0 48 -66 55q-497 111 -526 137q-92 70 -92 170q0 140 203 270q112 59 222 59z" />
-<glyph unicode="t" horiz-adv-x="704" d="M270 1390h14q66 -14 66 -59v-330h151l33 4q51 0 69 -74q0 -50 -62 -73l-55 4h-136v-539q0 -141 92 -173l84 -7h41q48 0 62 -70v-3q-12 -70 -70 -70h-77q-175 0 -260 191q-15 47 -15 110v561h-73l-59 -4q-62 22 -62 73q12 70 66 70v4l37 -4h91v308q9 81 63 81z" />
-<glyph unicode="u" horiz-adv-x="1188" d="M145 1027q71 -18 71 -64v-401q0 -257 146 -345q93 -71 207 -71q218 0 329 225q23 73 23 146v435q15 75 75 75q71 -16 71 -71v-892q0 -50 -71 -64h-4q-71 13 -71 71v71h-4q-156 -142 -337 -142h-26q-233 0 -405 229q-79 123 -79 303v409q9 86 75 86z" />
-<glyph unicode="v" horiz-adv-x="1132" d="M97 1029h7q59 0 102 -124l322 -661q350 742 372 766q26 19 49 19q75 -14 75 -71v-4q0 -19 -165 -361l-278 -570q-30 -23 -53 -23h-3q-64 0 -113 143q-363 742 -383 800v18q13 68 68 68z" />
-<glyph unicode="w" horiz-adv-x="1416" d="M108 1009q68 0 95 -148l181 -555h3q207 659 221 677q26 22 56 26q66 0 88 -122l188 -581h3q199 631 217 670q31 33 59 33q74 -15 74 -74l-291 -906q-31 -29 -59 -29h-3q-68 0 -96 144q-177 536 -177 552h-7l-214 -663q-25 -33 -59 -33h-3q-52 0 -74 66l-276 869 q15 74 74 74z" />
-<glyph unicode="x" horiz-adv-x="968" d="M111 1006q45 0 114 -106q188 -225 228 -283h4q32 32 301 371q13 12 47 18q70 -17 70 -62v-22q0 -23 -132 -177l-195 -246q327 -393 327 -411v-22q0 -54 -70 -66h-3q-43 0 -96 84l-249 305q-294 -367 -309 -378q-18 -11 -37 -11h-3q-59 0 -70 77q0 29 140 187l187 239 l-320 400l-7 30q15 73 73 73z" />
-<glyph unicode="y" horiz-adv-x="913" d="M751 1012q69 -13 69 -66v-4q-3 -25 -345 -840q-161 -401 -181 -426q-18 -14 -45 -21q-70 15 -70 60v17q0 13 157 391v3l-332 810v3q14 69 70 69q59 0 101 -138q227 -538 234 -566h3q274 669 290 687q25 21 49 21z" />
-<glyph unicode="z" horiz-adv-x="1018" d="M104 1012l37 -4h639l34 4q66 -20 66 -63v-22q0 -23 -85 -115l-532 -668h551q66 -13 66 -66v-12q0 -54 -70 -66h-702q-59 0 -70 78q0 29 151 203l466 587h-495l-59 -4q-63 22 -63 74q12 70 66 70v4z" />
-<glyph unicode="{" d="M683 1590h140q67 0 84 -61v-23q0 -48 -68 -64h-145q-72 0 -72 -76v-579q0 -47 -46 -121q49 -55 49 -130v-586q0 -61 73 -61h141q68 -14 68 -68v-15q0 -50 -72 -65h-149q-150 0 -205 167l-4 50v574q0 50 -53 61h-84q-76 15 -76 76q16 73 65 73h61q83 0 83 53v574 q0 166 168 217z" />
-<glyph unicode="|" d="M504 1619h8q69 -13 69 -69v-1908q0 -48 -77 -65q-58 0 -73 81v1884q13 77 73 77z" />
-<glyph unicode="}" d="M177 1578h154q141 0 198 -157l4 -34v-580q0 -64 86 -64h60q60 -18 60 -67v-15q0 -50 -71 -64h-79q-60 0 -60 -94v-554q0 -126 -157 -187l-45 -4h-150q-71 11 -71 71v4q12 71 67 71h139q71 0 71 60v562q0 85 49 146q-45 65 -45 120v580q0 60 -71 60h-143q-55 0 -67 71 q11 75 71 75z" />
-<glyph unicode="~" d="M373 851h24q92 0 212 -81l38 -10h24l96 29q96 -19 96 -96q0 -97 -182 -120h-34q-91 0 -211 82l-39 9h-24l-91 -24h-10q-86 17 -86 87v14q0 72 106 96q38 14 81 14z" />
-<glyph unicode="&#xa1;" horiz-adv-x="672" d="M300 1327h14q62 0 87 -63l7 -28q0 -85 -101 -98q-76 0 -91 98q20 91 84 91zM310 1065h4q66 -11 66 -66v-929q-10 -66 -66 -66h-7q-63 12 -63 63v935q0 52 66 63z" />
-<glyph unicode="&#xa2;" horiz-adv-x="1105" d="M772 1387h11q66 -12 66 -66v-11l-117 -343q179 -82 179 -147v-3q-12 -70 -69 -70h-4q-27 0 -117 70l-37 14l-234 -673q42 -14 106 -14q126 0 249 102l29 8h11q54 0 66 -70v-4q0 -74 -234 -164q-79 -15 -117 -15h-29q-49 0 -132 22q-93 -286 -113 -300l-48 -18 q-73 17 -73 73q0 14 106 307q-223 166 -223 417q0 271 260 439q128 62 245 62l40 -3q117 354 132 365q24 22 47 22zM191 499q0 -156 128 -271h3l220 629h-4q-212 0 -322 -223q-25 -76 -25 -135z" />
-<glyph unicode="&#xa3;" horiz-adv-x="946" d="M488 1473h39q182 0 309 -170l4 -27q-18 -77 -77 -77q-36 0 -101 73q-66 50 -135 50h-23q-153 0 -216 -181l-4 -50q0 -78 139 -317h232q77 -15 77 -77q-17 -74 -66 -74h-205l4 -27v-50q0 -126 -108 -340l-19 -46h390q7 0 42 81q32 31 62 31q78 -16 78 -78q0 -27 -74 -162 q-27 -23 -54 -23h-568q-59 0 -73 77q0 18 150 344q24 69 24 128l-4 65h-159q-73 14 -73 74q15 77 77 77h89v4q-112 204 -112 316q0 231 243 356q76 23 112 23z" />
-<glyph unicode="&#xa4;" d="M254 1047h20q36 0 108 -80q64 36 124 36h24q73 0 136 -36q69 80 100 80h28q64 -20 64 -72v-8q0 -38 -80 -112q36 -69 36 -140q0 -63 -36 -148q80 -64 80 -104v-16q-21 -68 -68 -68h-20q-27 0 -104 80h-4q-64 -36 -144 -36q-53 0 -140 36q-65 -80 -108 -80h-8 q-72 14 -72 72v12q0 42 80 108q-36 71 -36 128v20q0 69 36 140q-80 65 -80 104v20q20 64 64 64zM382 715q0 -100 116 -140h28q109 0 136 124v28q-29 124 -124 124l-12 4q-144 -24 -144 -140z" />
-<glyph unicode="&#xa5;" horiz-adv-x="1262" d="M144 1230h169q61 0 74 -77q0 -47 -70 -67q223 -344 294 -442h8q302 438 302 450h-4q-41 25 -41 55v18q19 63 74 63h144q61 0 73 -77q0 -33 -58 -70l-107 -159h73q85 -8 85 -70v-7q0 -53 -70 -66h-188l-107 -162h288q77 -15 77 -70v-4q0 -60 -74 -70v-4l-36 4h-354v-409 q0 -49 -74 -66h-3q-62 0 -85 59l4 63v346l-8 7h-350l-33 -4q-77 16 -77 74q0 60 77 74h291q-105 162 -110 162h-192q-66 19 -66 70q0 65 85 73h81q-105 165 -114 166q-52 23 -52 74q0 49 74 66z" />
-<glyph unicode="&#xa6;" horiz-adv-x="770" d="M359 1615h8q69 -13 69 -69v-681q0 -56 -73 -69h-4q-59 0 -73 77v665q13 77 73 77zM363 396q73 -19 73 -65v-693q0 -48 -77 -65q-58 0 -73 81v654q9 88 77 88z" />
-<glyph unicode="&#xa7;" d="M511 1440h35q165 0 291 -151l4 -23q-10 -63 -54 -63h-19q-20 0 -94 70q-67 43 -143 43q-181 0 -241 -202v-46q0 -155 175 -229q188 -29 237 -82q124 -110 124 -233v-50q0 -116 -136 -233q163 -124 163 -303q0 -204 -194 -322q-87 -43 -167 -43h-12q-182 0 -306 155l-4 24 q0 52 70 62q24 0 85 -62q76 -55 155 -55q162 0 233 171l12 66q0 182 -202 248q-121 15 -171 47q-167 113 -167 268v19q0 158 140 253q-163 129 -163 299v15q0 205 198 318q76 39 151 39zM313 520v-15q0 -132 148 -183l39 -4h23q123 0 175 148l4 39q0 143 -163 190l-39 4 q-130 0 -183 -144z" />
-<glyph unicode="&#xa8;" horiz-adv-x="1024" d="M292 1309q80 -19 80 -80q-16 -80 -80 -80q-80 16 -80 80q19 80 80 80zM744 1309q80 -19 80 -80q-16 -80 -80 -80q-80 16 -80 80q19 80 80 80z" />
-<glyph unicode="&#xa9;" horiz-adv-x="1674" d="M833 1441q361 0 599 -324q120 -183 120 -399q0 -386 -358 -621q-171 -98 -369 -98q-325 0 -561 279q-154 206 -154 440q0 352 309 591q196 132 414 132zM219 729v-18q0 -324 309 -528q157 -79 305 -79q314 0 516 283q98 158 98 335q0 318 -294 523q-157 87 -301 87h-38 q-281 0 -482 -256q-113 -163 -113 -347zM844 1230q189 0 350 -143q15 -20 15 -41v-8q0 -64 -79 -71h-3q-15 0 -125 79q-95 37 -165 37q-227 0 -343 -233q-23 -65 -23 -124v-27q0 -183 185 -305q95 -49 181 -49q134 0 267 110l30 7q75 -10 75 -71v-8q0 -72 -218 -162 q-96 -22 -154 -22q-298 0 -463 289q-53 116 -53 230q0 267 248 437q123 75 275 75z" />
-<glyph unicode="&#xaa;" horiz-adv-x="648" d="M289 1397h32q150 0 228 -168l16 -76l-4 -64v-140l4 -24q-7 -27 -28 -36h-12q-22 0 -36 24v48q-86 -72 -172 -72h-8q-184 0 -248 196q-8 20 -8 60q0 176 196 248zM129 1137q0 -130 156 -172h32q117 0 168 140l4 40q0 118 -132 172l-48 8q-121 0 -176 -136z" />
-<glyph unicode="&#xab;" horiz-adv-x="944" d="M510 812q44 -14 44 -32v-20q0 -20 -184 -236l-24 -32q212 -242 212 -268q-8 -44 -40 -44h-20q-35 26 -252 296l-4 20q0 22 120 160q120 152 140 152l4 4h4zM766 808q36 -19 36 -44v-4q0 -21 -204 -260l-4 -12q196 -228 208 -252v-20q-8 -40 -40 -40h-4q-31 0 -104 104 q-164 185 -164 208v20q204 258 252 296z" />
-<glyph unicode="&#xac;" d="M147 752h712q72 -14 72 -72v-348q0 -53 -76 -68h-4q-76 14 -76 76v256h-616q-80 16 -80 80q17 76 68 76z" />
-<glyph unicode="&#xae;" horiz-adv-x="1674" d="M828 1446q364 0 604 -325q121 -184 121 -400q0 -387 -360 -623q-173 -98 -372 -98q-328 0 -565 279q-156 208 -156 442q0 353 311 593q198 132 417 132zM210 732v-18q0 -325 311 -529q158 -79 307 -79q317 0 520 283q99 159 99 336q0 319 -296 525q-158 87 -304 87h-38 q-283 0 -485 -257q-114 -164 -114 -348zM616 1216h186q205 0 269 -208q8 -21 8 -64q0 -149 -156 -234q225 -388 235 -416v-7q-16 -45 -45 -45h-15q-34 0 -80 98l-201 347h-148v-396q-7 -49 -42 -49h-26q-34 19 -34 45v876q8 53 49 53zM669 1114v-329h95q160 0 197 98 q15 35 15 72q0 106 -121 151q-17 8 -49 8h-137z" />
-<glyph unicode="&#xaf;" horiz-adv-x="806" d="M-12 1776h844q70 -13 70 -70v-12q-13 -70 -67 -70h-847q-60 0 -70 82q19 70 70 70z" />
-<glyph unicode="&#xb0;" horiz-adv-x="674" d="M340 1341q-74 0 -127 -52.5t-53 -127.5t52.5 -126.5t127.5 -51.5t126.5 51.5t51.5 126.5t-52 127.5t-126 52.5zM339 1442q115 0 196 -81.5t81 -196.5q0 -114 -82 -196t-197 -82q-117 0 -197 81t-80 197t81.5 197t197.5 81z" />
-<glyph unicode="&#xb1;" d="M513 1188h24q43 0 68 -68l-4 -40v-192h224q80 -13 80 -76v-8q0 -56 -72 -76l-28 4h-204v-188l4 -44q0 -54 -80 -72q-55 0 -80 68l4 48v188h-204l-24 -4q-76 19 -76 76v8q0 61 80 76h224v192l-4 36q22 72 68 72zM213 368l48 -4h536l36 4q72 -20 72 -76v-8q0 -51 -64 -76 l-68 4h-496l-64 -4q-68 23 -68 76v8q0 50 68 76z" />
-<glyph unicode="&#xb2;" d="M506 1537q95 0 166 -86q37 -56 37 -116q0 -93 -90 -177l-197 -225h264q26 0 32 -33v-2q-5 -34 -34 -34h-343q-33 6 -33 34v2q0 16 33 47l274 313q23 33 23 75q0 90 -93 125q-16 5 -36 5h-5q-86 0 -124 -91q-5 -20 -7 -46q-12 -25 -32 -25h-3q-34 6 -34 32q0 106 101 173 q54 29 101 29z" />
-<glyph unicode="&#xb3;" d="M503 1543q80 0 138 -72q32 -44 32 -97v-7q0 -74 -64 -131q93 -67 93 -170q0 -106 -100 -176q-52 -29 -103 -29h-5q-120 0 -187 124q-16 46 -16 82q0 25 38 33q27 0 32 -36q0 -77 81 -122q30 -11 57 -11q81 0 122 84q9 26 9 44v14q0 76 -84 118l-59 13q-18 14 -18 30v2 q0 34 48 34q35 0 74 47q14 30 14 56q0 58 -57 89q-21 11 -47 11q-67 0 -95 -72q-6 -52 -13 -52q-12 -14 -25 -14q-36 8 -36 30v9q0 94 94 149q36 18 77 20z" />
-<glyph unicode="&#xb4;" horiz-adv-x="889" d="M516 1414q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128z" />
-<glyph unicode="&#xb5;" horiz-adv-x="1180" d="M194 1019q70 -18 70 -63v-399q0 -257 146 -343q92 -71 205 -71q218 0 328 224q23 72 23 145v433q15 74 74 74q71 -16 71 -71v-887q0 -49 -71 -64h-3q-71 13 -71 71v71h-4q-156 -142 -336 -142h-26q-175 0 -336 146v-508q0 -47 -74 -63q-56 0 -71 78v1284q9 85 75 85z" />
-<glyph unicode="&#xb6;" horiz-adv-x="1024" d="M403 1435h462q68 -15 68 -61v-19q0 -56 -72 -68h-11v-1211q-14 -76 -72 -76h-4q-72 12 -72 68v1219h-140v-1215q-12 -72 -72 -72h-4q-72 13 -72 72v674h-11q-186 0 -299 196q-34 75 -34 152q0 201 204 310q62 31 129 31z" />
-<glyph unicode="&#xb7;" horiz-adv-x="508" d="M275 746q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6z" />
-<glyph unicode="&#x2219;" horiz-adv-x="508" d="M275 746q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6z" />
-<glyph unicode="&#xb8;" horiz-adv-x="1024" d="M548 37q66 -13 66 -59v-56q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53v111q0 53 70 66z" />
-<glyph unicode="&#xb9;" d="M535 1564h5q32 -7 32 -31v-611q-6 -34 -34 -34h-1q-34 7 -34 30v564q-48 -16 -63 -16q-22 0 -30 32v9q0 26 72 41z" />
-<glyph unicode="&#xba;" horiz-adv-x="718" d="M370 1543q107 0 164 -115q31 -96 31 -177v-38q0 -100 -41 -201q-59 -92 -150 -92h-6q-98 0 -155 105q-36 92 -36 205v5q0 119 42 216q62 92 151 92zM236 1239v-17q0 -114 41 -191q40 -49 90 -49h5q111 0 129 171q5 27 7 80q0 95 -33 182q-41 65 -103 65q-76 0 -111 -83 q-25 -82 -25 -158z" />
-<glyph unicode="&#xbb;" horiz-adv-x="944" d="M499 803q31 0 108 -108q160 -180 160 -204v-20q-195 -249 -256 -300h-28q-19 9 -28 28v20q0 25 204 256l4 16q-208 239 -208 264q10 48 44 48zM255 799q30 0 124 -128q144 -161 144 -188q0 -22 -204 -260q-39 -56 -64 -56h-4q-44 8 -44 44q0 25 108 148l104 128 q-197 229 -208 252v20q0 32 44 40z" />
-<glyph unicode="&#xbc;" horiz-adv-x="1470" d="M1185 1442h12q56 0 68 -72v-4q0 -34 -125 -179q-96 -134 -902 -1172q-25 -15 -50 -15q-68 19 -68 65v23q0 23 145 201q813 1061 878 1138q20 15 42 15zM318 1434q25 0 45 -34l-3 -57v-654l3 -35q-13 -41 -45 -41q-26 0 -42 30v685l-65 -15h-19q-30 16 -30 41q0 48 110 65 q0 5 46 15zM1155 829q29 0 45 -38l-3 -38v-418h87q35 0 42 -50q-16 -38 -46 -38h-83v-217q-18 -30 -42 -30q-46 9 -46 46v201h-338q-38 8 -38 38v19q335 431 384 503q15 22 38 22zM1105 647l-236 -312h240v312h-4z" />
-<glyph unicode="&#xbd;" horiz-adv-x="1492" d="M1172 1437h11q56 0 68 -72v-4q0 -34 -125 -178q-95 -133 -898 -1168q-25 -15 -50 -15q-68 19 -68 64v23q0 23 144 201q811 1057 876 1134q20 15 42 15zM307 1429q25 0 46 -34l-4 -57v-652l4 -34q-14 -42 -46 -42q-25 0 -42 31v682l-64 -15h-19q-30 16 -30 42q0 47 110 64 q0 5 45 15zM1077 815q171 0 243 -186l3 -38v-41q0 -98 -155 -247l-186 -216h296l15 4q42 -14 42 -30v-19q-8 -38 -38 -38h-417q-33 0 -42 45q0 15 182 213q212 235 212 265l4 27v34q-32 140 -155 140q-108 0 -156 -121q0 -64 -34 -76h-15q-27 0 -42 38q0 160 175 235z" />
-<glyph unicode="&#xbe;" horiz-adv-x="1541" d="M367 1438q124 0 188 -129q15 -35 15 -64v-22q0 -83 -75 -155q109 -76 109 -204q0 -176 -196 -241l-53 -4h-7q-166 0 -234 196l-4 53q0 20 30 38h19q39 0 45 -83q44 -117 147 -117h12q112 0 151 132l4 30q0 109 -129 155q-68 0 -68 49q10 41 61 41q76 0 102 106v26 q0 71 -99 106h-22q-85 0 -117 -98v-34q-16 -30 -38 -30h-11q-38 7 -38 37v8q0 143 162 200zM1268 1430h12q55 0 68 -72v-3q0 -34 -125 -178q-95 -133 -894 -1162q-25 -15 -49 -15q-68 19 -68 64v23q0 23 143 200q807 1052 872 1128q20 15 41 15zM1238 823q29 0 45 -38 l-3 -38v-415h86q35 0 42 -49q-16 -38 -45 -38h-83v-215q-18 -30 -42 -30q-45 9 -45 45v200h-336q-38 8 -38 38v19q333 427 381 498q16 23 38 23zM1189 641l-234 -309h238v309h-4z" />
-<glyph unicode="&#xbf;" horiz-adv-x="977" d="M441 1080h11q81 0 98 -105q-18 -98 -102 -98h-4q-84 0 -101 98v3q19 102 98 102zM441 775q75 -13 75 -72v-7q0 -256 -245 -400q-98 -93 -98 -222q0 -166 173 -256q65 -23 113 -23q164 0 253 162q21 35 34 143q35 42 68 42q75 -18 75 -72q0 -210 -207 -358 q-115 -64 -223 -64q-214 0 -354 185q-79 112 -79 248q0 244 245 392q102 92 102 260q31 42 68 42z" />
-<glyph unicode="&#xc0;" horiz-adv-x="1220" d="M477 1786h7q46 0 133 -125q60 -64 60 -94q-13 -76 -71 -76h-16q-37 0 -140 144q-45 38 -45 83q19 68 72 68zM560 1438q69 0 102 -140q458 -1190 462 -1219v-11q0 -56 -72 -68h-4q-66 0 -94 129l-171 442h-442l-209 -548q-30 -23 -53 -23h-7q-72 13 -72 72v4l129 348 q338 879 367 976q34 38 64 38zM560 1150l-159 -431h326v4l-163 427h-4z" />
-<glyph unicode="&#xc1;" horiz-adv-x="1212" d="M622 1778h3q72 -14 72 -64v-15q0 -32 -79 -117q-65 -98 -109 -98h-12q-55 0 -67 72v4q0 37 116 166q33 52 76 52zM558 1432q68 0 101 -140q456 -1185 460 -1213v-11q0 -56 -72 -68h-3q-67 0 -95 128l-169 441h-441l-207 -546q-30 -23 -53 -23h-7q-72 13 -72 72v3l128 347 q337 875 366 972q33 38 64 38zM558 1145l-159 -429h324v4l-162 425h-3z" />
-<glyph unicode="&#xc2;" horiz-adv-x="1212" d="M550 1771h30q36 0 125 -121q60 -64 60 -98v-3q-11 -72 -72 -72h-7q-46 0 -121 113h-4q-80 -113 -120 -113h-11q-58 0 -72 75q0 33 117 166q36 53 75 53zM558 1432q68 0 101 -140q456 -1185 460 -1213v-11q0 -56 -72 -68h-3q-67 0 -95 128l-169 441h-441l-207 -546 q-30 -23 -53 -23h-7q-72 13 -72 72v3l128 347q337 875 366 972q33 38 64 38zM558 1145l-159 -429h324v4l-162 425h-3z" />
-<glyph unicode="&#xc3;" horiz-adv-x="1216" d="M452 1695q79 0 189 -71l33 -4l76 23h7q72 -12 72 -72v-4q0 -70 -124 -90l-38 -4q-79 0 -181 72l-30 4l-83 -23q-75 14 -75 71v8q0 72 139 87zM558 1432q68 0 101 -140q456 -1185 460 -1213v-11q0 -56 -72 -68h-3q-67 0 -95 128l-169 441h-441l-207 -546q-30 -23 -53 -23 h-7q-72 13 -72 72v3l128 347q337 875 366 972q33 38 64 38zM558 1145l-159 -429h324v4l-162 425h-3z" />
-<glyph unicode="&#xc4;" horiz-adv-x="1225" d="M411 1684h11q68 -15 68 -64v-11q0 -60 -76 -72q-71 14 -71 72v11q0 49 68 64zM697 1684h15q53 0 64 -79q0 -51 -75 -68q-72 13 -72 68v19q19 60 68 60zM558 1432q68 0 101 -140q456 -1185 460 -1213v-11q0 -56 -72 -68h-3q-67 0 -95 128l-169 441h-441l-207 -546 q-30 -23 -53 -23h-7q-72 13 -72 72v3l128 347q337 875 366 972q33 38 64 38zM558 1145l-159 -429h324v4l-162 425h-3z" />
-<glyph unicode="&#xc5;" horiz-adv-x="1219" d="M555 1832h15q121 0 174 -147l4 -38v-11q0 -118 -140 -174l-45 -8q-113 0 -174 114q-19 41 -19 79q0 127 148 181zM487 1643q13 -71 72 -71q72 12 72 68v11q-11 64 -64 64h-12q-57 0 -68 -72zM559 1436q69 0 102 -140q457 -1189 461 -1217v-11q0 -56 -72 -68h-4 q-66 0 -94 128l-170 442h-442l-208 -547q-30 -23 -53 -23h-7q-72 13 -72 72v4l128 347q338 878 367 975q34 38 64 38zM559 1148l-159 -430h325v4l-162 426h-4z" />
-<glyph unicode="&#xc6;" horiz-adv-x="1565" d="M780 1435h595q46 0 64 -72q-15 -75 -76 -75h-500v-568h390q69 -15 69 -61v-19q0 -56 -72 -68h-387v-424h504q58 0 72 -76q0 -56 -76 -72h-575q-58 0 -72 76v496h-277q-20 -24 -166 -296l-144 -253q-27 -23 -53 -23h-4q-60 0 -72 80q0 22 242 446l493 886q28 23 45 23z M519 720h197v352z" />
-<glyph unicode="&#xc7;" horiz-adv-x="1399" d="M713 1432q223 0 404 -134q19 -25 19 -48q-13 -74 -74 -74q-17 0 -134 63q-119 44 -215 44q-264 0 -455 -241q-97 -161 -97 -315q0 -308 289 -489q128 -67 256 -67h11q162 0 323 100l18 4h8q70 -12 70 -70v-4q0 -93 -293 -167l-67 -7v-74q112 -74 112 -182 q0 -156 -182 -200l-52 4h-55l-60 -4q-63 21 -63 63v15q13 67 67 67h130q70 0 70 55v4q0 42 -67 55q-44 21 -44 56v141q-145 14 -315 118q-304 236 -304 582q0 366 334 597q178 108 366 108z" />
-<glyph unicode="&#xc8;" horiz-adv-x="1039" d="M72 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4zM355 1829h8q45 0 132 -125q60 -64 60 -94q-13 -76 -71 -76h-15 q-38 0 -140 144q-46 38 -46 83q20 68 72 68z" />
-<glyph unicode="&#xc9;" d="M72 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4zM476 1829h4q75 -15 75 -76q0 -32 -90 -132q-61 -87 -95 -87h-22 q-53 0 -65 80q0 27 118 162q36 53 75 53z" />
-<glyph unicode="&#xca;" d="M72 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4zM461 1787h19q45 0 117 -102q76 -84 76 -109v-15q-14 -68 -61 -68h-26 q-32 0 -117 113q-78 -113 -114 -113h-26q-47 0 -61 68v15q0 32 159 204z" />
-<glyph unicode="&#xcb;" horiz-adv-x="1027" d="M72 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4zM306 1704h11q68 -15 68 -64v-11q0 -60 -75 -72q-72 14 -72 72v11 q0 49 68 64zM593 1704h15q53 0 65 -79q0 -51 -76 -68q-72 12 -72 68v19q19 60 68 60z" />
-<glyph unicode="&#xcc;" horiz-adv-x="657" d="M219 1818q44 0 121 -109q71 -77 71 -113q-15 -75 -75 -75q-45 0 -106 90q-86 97 -86 121v22q0 50 75 64zM182 1431l18 -4h140l15 4q75 -17 75 -76q-13 -75 -72 -75h-15v-1133h23q49 0 64 -72v-3q-13 -72 -72 -72h-176q-72 13 -72 72v3q15 72 64 72h23v1133h-15 q-63 0 -72 79v4q0 46 72 68z" />
-<glyph unicode="&#xcd;" horiz-adv-x="657" d="M374 1828h4q75 -15 75 -76q0 -32 -90 -132q-61 -87 -95 -87h-22q-53 0 -64 80q0 27 117 162q36 53 75 53zM212 1435l19 -4h139l15 4q76 -16 76 -75q-13 -76 -72 -76h-15v-1137h23q49 0 64 -71v-4q-13 -72 -72 -72h-177q-72 13 -72 72v4q15 71 64 71h23v1137h-15 q-63 0 -72 79v4q0 47 72 68z" />
-<glyph unicode="&#xce;" horiz-adv-x="657" d="M285 1783h30q48 0 136 -128q57 -59 57 -91q-13 -76 -72 -76h-7q-48 0 -114 102l-15 12q-74 -114 -121 -114h-7q-72 12 -72 72v4q0 36 113 162q40 57 72 57zM217 1436l19 -4h140l15 4q75 -17 75 -76q-13 -76 -71 -76h-15v-1137h22q50 0 64 -71v-4q-12 -72 -71 -72h-178 q-72 13 -72 72v4q15 71 65 71h22v1137h-15q-63 0 -72 80v4q0 46 72 68z" />
-<glyph unicode="&#xcf;" horiz-adv-x="657" d="M144 1683h15q68 -14 68 -60v-19q0 -55 -72 -68q-75 15 -75 76q16 71 64 71zM434 1683h11q68 -15 68 -64v-11q0 -60 -75 -72q-72 14 -72 72v11q0 49 68 64zM212 1431l19 -4h139l15 4q75 -16 75 -76q-13 -75 -71 -75h-15v-1133h22q50 0 64 -72v-3q-12 -72 -71 -72h-177 q-72 13 -72 72v3q15 72 64 72h23v1133h-15q-63 0 -72 79v4q0 46 72 68z" />
-<glyph unicode="&#xd0;" horiz-adv-x="1275" d="M471 1430q331 0 568 -289q143 -196 143 -430q0 -373 -350 -613q-180 -98 -358 -98h-252q-53 0 -71 68v587h-83q-68 15 -68 68v15q0 49 72 64h79v553q15 72 64 72h222zM297 1284v-482h283q71 -13 71 -68v-11q-13 -68 -68 -68h-286v-508h155q363 0 530 331q53 113 53 237 q0 306 -286 493q-120 76 -380 76h-72z" />
-<glyph unicode="&#xd1;" horiz-adv-x="1288" d="M454 1701q78 0 189 -72l34 -4l71 23h12q72 -11 72 -72v-4q0 -70 -125 -90l-38 -4q-79 0 -181 72l-31 3l-83 -22q-75 14 -75 72v7q0 72 139 87zM64 1432h15q46 0 80 -68l839 -1077h4v1077q13 68 68 68h11q56 0 68 -71v-1289q-13 -72 -72 -72h-4q-51 0 -117 106l-809 1032 v-1070q0 -56 -71 -68h-4q-54 0 -72 68v1293q15 71 64 71z" />
-<glyph unicode="&#xd2;" horiz-adv-x="1519" d="M646 1821h22q34 0 102 -94q82 -91 82 -124q-14 -75 -75 -75h-3q-47 0 -121 113q-71 70 -71 109q16 71 64 71zM714 1427q361 0 604 -334q109 -190 109 -383q0 -357 -323 -594q-184 -116 -383 -116h-15q-367 0 -601 342q-105 173 -105 375q0 341 300 575q196 135 414 135z M146 706q0 -273 241 -458q150 -102 319 -102h19q266 0 450 237q106 152 106 331q0 308 -282 488q-138 79 -285 79q-282 0 -466 -245q-102 -146 -102 -330z" />
-<glyph unicode="&#xd3;" horiz-adv-x="1532" d="M768 1826h15q72 -15 72 -71q0 -39 -124 -173q-25 -49 -76 -49q-57 0 -71 75q0 37 109 154q40 64 75 64zM716 1431q362 0 606 -335q109 -190 109 -384q0 -358 -324 -595q-184 -117 -384 -117h-15q-368 0 -603 343q-105 174 -105 376q0 342 301 576q196 136 415 136z M147 708q0 -274 241 -459q150 -102 320 -102h19q267 0 452 237q105 152 105 332q0 308 -282 489q-139 79 -286 79q-283 0 -467 -245q-102 -147 -102 -331z" />
-<glyph unicode="&#xd4;" horiz-adv-x="1523" d="M698 1803h31q35 0 123 -121q61 -64 61 -97v-4q-12 -71 -72 -71h-7q-46 0 -120 112h-4q-80 -112 -120 -112h-12q-57 0 -71 75q0 33 116 165q37 53 75 53zM714 1427q361 0 604 -334q109 -190 109 -383q0 -357 -323 -594q-184 -116 -383 -116h-15q-367 0 -601 342 q-105 173 -105 375q0 341 300 575q196 135 414 135zM146 706q0 -273 241 -458q150 -102 319 -102h19q266 0 450 237q106 152 106 331q0 308 -282 488q-138 79 -285 79q-282 0 -466 -245q-102 -146 -102 -330z" />
-<glyph unicode="&#xd5;" horiz-adv-x="1528" d="M590 1772h18q72 0 166 -63l30 -8h18l76 23q75 -15 75 -75q0 -76 -143 -94h-26q-71 0 -166 64l-30 7h-18l-72 -19h-7q-68 14 -68 68v11q0 57 83 75q30 11 64 11zM714 1427q361 0 604 -334q109 -190 109 -383q0 -357 -323 -594q-184 -116 -383 -116h-15q-367 0 -601 342 q-105 173 -105 375q0 341 300 575q196 135 414 135zM146 706q0 -273 241 -458q150 -102 319 -102h19q266 0 450 237q106 152 106 331q0 308 -282 488q-138 79 -285 79q-282 0 -466 -245q-102 -146 -102 -330z" />
-<glyph unicode="&#xd6;" horiz-adv-x="1540" d="M508 1706q51 0 68 -75q-17 -76 -71 -76q-76 17 -76 64v23q0 52 79 64zM934 1706q51 0 68 -75q-17 -76 -72 -76q-75 17 -75 64v23q0 52 79 64zM716 1431q362 0 606 -335q109 -190 109 -384q0 -358 -324 -595q-184 -117 -384 -117h-15q-368 0 -603 343q-105 174 -105 376 q0 342 301 576q196 136 415 136zM147 708q0 -274 241 -459q150 -102 320 -102h19q267 0 452 237q105 152 105 332q0 308 -282 489q-139 79 -286 79q-283 0 -467 -245q-102 -147 -102 -331z" />
-<glyph unicode="&#xd7;" d="M308 938h15q48 0 153 -125l43 -38q160 163 182 163h39q60 0 81 -91q0 -58 -163 -201l-5 -5v-5q163 -148 163 -182l5 -19q-22 -96 -96 -96q-51 0 -158 125l-48 43q-144 -163 -196 -163h-24q-77 24 -77 76v24q0 47 101 130l62 67q-163 161 -163 182v29q17 86 86 86z" />
-<glyph unicode="&#xd8;" horiz-adv-x="1561" d="M713 1426q267 0 492 -198q149 153 180 153h8q71 -18 71 -71v-7q0 -42 -105 -124l-60 -60q127 -195 127 -410q0 -356 -322 -593q-184 -116 -383 -116h-15q-232 0 -436 154h-3q-154 -150 -173 -150l-19 -4h-4q-59 0 -71 79q0 36 124 139q4 11 41 37q-165 210 -165 462 q0 340 300 574q196 135 413 135zM146 706q0 -195 128 -349l822 773v4q-179 146 -383 146q-281 0 -465 -244q-102 -147 -102 -330zM375 255q156 -109 331 -109h18q267 0 451 237q105 151 105 330q0 152 -86 304h-4z" />
-<glyph unicode="&#xd9;" horiz-adv-x="1103" d="M444 1819q48 0 140 -131q53 -52 53 -87v-8q0 -58 -76 -71q-45 0 -132 124q-60 62 -60 94v8q0 55 75 71zM64 1428h15q68 -14 68 -61v-802q0 -259 147 -347q92 -71 207 -71q220 0 331 226q23 70 23 147v836q13 72 68 72h11q68 -13 68 -68v-878q0 -224 -215 -392 q-136 -90 -275 -90h-26q-234 0 -407 230q-79 124 -79 305v821q15 72 64 72z" />
-<glyph unicode="&#xda;" horiz-adv-x="1107" d="M565 1819q72 -15 72 -71v-8q0 -35 -95 -135q-52 -83 -98 -83q-75 16 -75 71v8q0 36 94 136q52 82 102 82zM64 1428h15q68 -14 68 -61v-802q0 -259 147 -347q92 -71 207 -71q220 0 331 226q23 70 23 147v836q13 72 68 72h11q68 -13 68 -68v-878q0 -224 -215 -392 q-136 -90 -275 -90h-26q-234 0 -407 230q-79 124 -79 305v821q15 72 64 72z" />
-<glyph unicode="&#xdb;" horiz-adv-x="1124" d="M514 1796h8q49 0 136 -124q61 -63 61 -99q-17 -72 -65 -72h-19q-41 0 -102 91q-5 0 -11 15l-4 4h-4q-85 -102 -94 -102l-23 -8h-19q-55 0 -68 72v4q0 38 132 182q0 29 72 37zM64 1433h15q68 -14 68 -60v-806q0 -260 148 -348q93 -72 208 -72q221 0 333 227q23 71 23 148 v840q12 71 68 71h11q68 -13 68 -68v-881q0 -225 -216 -393q-136 -91 -276 -91h-26q-235 0 -409 231q-79 124 -79 306v825q15 71 64 71z" />
-<glyph unicode="&#xdc;" horiz-adv-x="1128" d="M352 1691h11q68 -15 68 -65v-11q0 -60 -75 -72q-72 14 -72 72v11q0 50 68 65zM639 1691h15q53 0 65 -80q0 -51 -76 -68q-72 13 -72 68v19q19 61 68 61zM64 1433h15q68 -14 68 -60v-806q0 -260 148 -348q93 -72 208 -72q221 0 333 227q23 71 23 148v840q12 71 68 71h11 q68 -13 68 -68v-881q0 -225 -216 -393q-136 -91 -276 -91h-26q-235 0 -409 231q-79 124 -79 306v825q15 71 64 71z" />
-<glyph unicode="&#xdd;" horiz-adv-x="1107" d="M64 1433h16q49 0 79 -72l345 -516h4q372 562 387 573q20 15 34 15h23q46 0 64 -72q0 -32 -129 -209l-307 -458v-611q-9 -83 -64 -83h-16q-49 0 -68 61v621q0 14 -159 251l-269 405l-4 23q16 72 64 72zM598 1797h4q75 -15 75 -75q0 -33 -91 -133q-60 -87 -94 -87h-23 q-52 0 -64 80q0 27 117 162q37 53 76 53z" />
-<glyph unicode="&#xde;" horiz-adv-x="1100" d="M84 1436h16q68 -14 68 -61v-280h390q296 0 394 -258q19 -60 19 -110v-18q0 -197 -193 -319q-99 -49 -171 -49l-26 4h-413v-277q0 -56 -72 -68h-4q-58 0 -72 76v1277q9 83 64 83zM168 947v-454h435q162 0 216 185l4 42q0 155 -166 216q-44 11 -110 11h-379z" />
-<glyph unicode="&#xdf;" horiz-adv-x="1061" d="M379 1425h41q177 0 303 -168q68 -101 68 -217q0 -89 -60 -213v-38q0 -37 123 -175q90 -110 90 -236v-15q0 -219 -224 -333q-69 -30 -143 -30h-3q-184 0 -300 157l-3 26q16 71 71 71h7q34 0 90 -63q70 -45 138 -45q154 0 214 168l7 53v7q0 96 -108 210q-109 112 -109 220 q0 57 53 176q7 17 7 49v33q0 119 -135 195q-44 22 -104 22q-166 0 -229 -183l-7 -108v-913q0 -55 -71 -68h-4q-57 0 -71 75v939q0 283 266 386q53 18 93 18z" />
-<glyph unicode="&#xe0;" horiz-adv-x="1147" d="M496 1385h25q32 0 146 -149q29 -31 29 -58v-8q0 -56 -73 -69q-44 0 -102 88q-84 93 -84 116v15q0 48 59 65zM529 999q283 0 448 -277q51 -113 51 -233v-423q0 -54 -69 -66h-4q-47 0 -69 55v3l3 91v4q-160 -153 -346 -153h-29q-254 0 -423 255q-62 123 -62 248 q0 279 273 441q117 55 227 55zM171 507v-11q0 -217 219 -328q69 -26 124 -26h29q181 0 299 182q44 86 44 165v14q0 210 -208 321q-72 33 -149 33h-4q-220 0 -332 -230q-22 -71 -22 -120z" />
-<glyph unicode="&#xe1;" horiz-adv-x="1114" d="M594 1389q73 -17 73 -69v-7q0 -31 -80 -121q-60 -91 -113 -91h-4q-46 0 -62 69v8q0 33 113 160q38 51 73 51zM500 999q283 0 448 -277q51 -113 51 -233v-423q0 -54 -69 -66h-4q-47 0 -69 55v3l3 91v4q-160 -153 -346 -153h-29q-254 0 -423 255q-62 123 -62 248 q0 279 273 441q117 55 227 55zM142 507v-11q0 -217 219 -328q69 -26 124 -26h29q181 0 299 182q44 86 44 165v14q0 210 -208 321q-72 33 -149 33h-4q-220 0 -332 -230q-22 -71 -22 -120z" />
-<glyph unicode="&#xe2;" horiz-adv-x="1140" d="M495 1392l3 -3h4l4 3q51 0 124 -106q70 -75 70 -110q-13 -73 -73 -73q-48 0 -118 106l-3 4h-8q-70 -110 -121 -110q-73 14 -73 73q0 37 103 147q44 69 88 69zM502 1004q285 0 451 -278q51 -114 51 -235v-425q0 -54 -70 -66h-3q-48 0 -70 55v4l4 91v4q-162 -154 -348 -154 h-30q-255 0 -425 256q-62 124 -62 250q0 280 275 443q117 55 227 55zM143 509v-11q0 -218 220 -329q69 -26 124 -26h30q182 0 300 183q44 86 44 165v15q0 210 -209 322q-72 33 -150 33h-4q-221 0 -333 -231q-22 -71 -22 -121z" />
-<glyph unicode="&#xe3;" horiz-adv-x="1122" d="M408 1354h19q70 0 162 -63l29 -7h18l74 22q74 -15 74 -74q0 -74 -140 -92h-26q-69 0 -162 63l-29 7h-19l-70 -18h-7q-66 13 -66 66v11q0 55 81 74q29 11 62 11zM504 1008q286 0 452 -280q52 -114 52 -235v-427q0 -54 -70 -66h-4q-47 0 -69 55v4l3 92v4 q-162 -155 -349 -155h-30q-256 0 -426 258q-63 124 -63 250q0 281 276 445q118 55 228 55zM143 511v-11q0 -219 221 -331q70 -26 125 -26h30q183 0 301 184q45 87 45 166v15q0 211 -210 323q-73 34 -151 34h-4q-222 0 -334 -232q-23 -72 -23 -122z" />
-<glyph unicode="&#xe4;" horiz-adv-x="1136" d="M355 1246h11q66 -15 66 -62v-11q0 -59 -73 -70q-70 13 -70 70v11q0 47 66 62zM634 1246h15q51 0 62 -77q0 -49 -73 -66q-70 12 -70 66v18q18 59 66 59zM502 1004q285 0 451 -278q51 -114 51 -235v-425q0 -54 -70 -66h-3q-48 0 -70 55v4l4 91v4q-162 -154 -348 -154h-30 q-255 0 -425 256q-62 124 -62 250q0 280 275 443q117 55 227 55zM143 509v-11q0 -218 220 -329q69 -26 124 -26h30q182 0 300 183q44 86 44 165v15q0 210 -209 322q-72 33 -150 33h-4q-221 0 -333 -231q-22 -71 -22 -121z" />
-<glyph unicode="&#xe5;" horiz-adv-x="1131" d="M517 1447q105 0 165 -110q18 -39 18 -77q0 -123 -143 -175l-37 -4h-14q-118 0 -169 143l-4 36v11q0 124 151 173zM447 1268v-15q17 -58 59 -58h14q56 0 66 69q-12 70 -69 70q-70 -12 -70 -66zM502 1004q285 0 451 -278q51 -114 51 -235v-425q0 -54 -70 -66h-3 q-48 0 -70 55v4l4 91v4q-162 -154 -348 -154h-30q-255 0 -425 256q-62 124 -62 250q0 280 275 443q117 55 227 55zM143 509v-11q0 -218 220 -329q69 -26 124 -26h30q182 0 300 183q44 86 44 165v15q0 210 -209 322q-72 33 -150 33h-4q-221 0 -333 -231q-22 -71 -22 -121z " />
-<glyph unicode="&#xe6;" horiz-adv-x="1961" d="M500 1004q263 0 431 -245h4q90 155 277 219q84 22 150 22q279 0 442 -270q54 -113 54 -212v-47q-12 -69 -69 -69h-767v-4q37 -121 139 -190q95 -62 197 -62q88 0 197 55l19 3q73 -17 73 -73q0 -93 -241 -127l-52 -4q-192 0 -354 150v-81q0 -62 -76 -69h-4q-38 0 -62 58 l4 88v11q-161 -153 -347 -153h-29q-255 0 -424 255q-62 123 -62 248q0 280 274 442q117 55 226 55zM142 511v-11q0 -217 219 -328q70 -26 125 -26h29q181 0 299 183q44 85 44 164v14q0 210 -208 322q-72 33 -150 33h-3q-221 0 -333 -230q-22 -72 -22 -121zM1011 544h698v4 q0 96 -117 219q-112 87 -234 87q-187 0 -303 -175q-44 -82 -44 -135z" />
-<glyph unicode="&#xe7;" horiz-adv-x="986" d="M507 996q193 0 349 -145q11 -19 11 -37v-3q-12 -69 -69 -69h-4q-26 0 -116 69q-81 40 -160 40h-22q-211 0 -320 -222q-25 -75 -25 -134q0 -216 222 -328q67 -25 141 -25q126 0 248 102l29 7h11q53 0 65 -69v-4q0 -74 -233 -163l-76 -11v-48q109 -72 109 -178 q0 -153 -178 -196l-51 4h-55l-58 -4q-62 21 -62 62v14q13 66 66 66h127q69 0 69 54v4q0 41 -65 54q-44 21 -44 55v116q-90 13 -222 102q-185 166 -185 389q0 243 215 407q137 91 283 91z" />
-<glyph unicode="&#xe8;" horiz-adv-x="1127" d="M498 1004q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55h22q66 -13 66 -66v-11q0 -91 -264 -125h-26q-270 0 -432 253q-66 120 -66 249q0 276 260 440q127 62 238 62zM150 546h704q0 75 -88 194 q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136zM465 1381h26q32 0 147 -150q29 -31 29 -58v-8q0 -57 -73 -69q-45 0 -103 88q-84 93 -84 117v14q0 48 58 66z" />
-<glyph unicode="&#xe9;" horiz-adv-x="1118" d="M498 1004q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55h22q66 -13 66 -66v-11q0 -91 -264 -125h-26q-270 0 -432 253q-66 120 -66 249q0 276 260 440q127 62 238 62zM150 546h704q0 75 -88 194 q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136zM594 1385q73 -17 73 -70v-7q0 -30 -81 -121q-60 -91 -113 -91h-4q-47 0 -62 69v8q0 33 113 161q38 51 74 51z" />
-<glyph unicode="&#xea;" horiz-adv-x="1144" d="M498 1004q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55h22q66 -13 66 -66v-11q0 -91 -264 -125h-26q-270 0 -432 253q-66 120 -66 249q0 276 260 440q127 62 238 62zM150 546h704q0 75 -88 194 q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136zM495 1392l3 -3h4l4 3q51 0 124 -106q70 -75 70 -110q-13 -73 -73 -73q-48 0 -118 106l-3 4h-8q-70 -110 -121 -110q-73 14 -73 73q0 37 103 147q44 69 88 69z" />
-<glyph unicode="&#xeb;" horiz-adv-x="1122" d="M355 1243h11q65 -15 65 -62v-11q0 -58 -73 -70q-69 14 -69 70v11q0 47 66 62zM632 1243h15q51 0 62 -77q0 -49 -73 -66q-69 12 -69 66v19q18 58 65 58zM497 1002q289 0 450 -274q55 -108 55 -234v-19q-13 -73 -70 -73h-771q44 -146 186 -223q84 -33 158 -33q84 0 193 55 h22q66 -13 66 -66v-11q0 -90 -263 -124h-26q-269 0 -431 252q-66 120 -66 249q0 275 260 439q126 62 237 62zM150 545h702q0 75 -88 193q-120 114 -238 114h-40q-175 0 -289 -172q-39 -68 -47 -135z" />
-<glyph unicode="&#xec;" horiz-adv-x="514" d="M139 1344h25q32 0 147 -150q29 -32 29 -59v-7q0 -57 -73 -70q-45 0 -103 88q-84 94 -84 117v15q0 48 59 66zM237 1003q70 -17 70 -62v-875q0 -54 -70 -66h-3q-56 0 -70 73v846q9 84 73 84z" />
-<glyph unicode="&#xed;" horiz-adv-x="514" d="M307 1353q74 -17 74 -70v-7q0 -31 -81 -122q-61 -92 -114 -92h-4q-47 0 -62 70v8q0 33 114 161q38 52 73 52zM238 1007q69 -18 69 -62v-879q0 -54 -69 -66h-4q-56 0 -70 74v849q9 84 74 84z" />
-<glyph unicode="&#xee;" horiz-adv-x="514" d="M222 1348l4 -3h4l3 3q52 0 126 -107q70 -76 70 -110q-13 -74 -74 -74q-48 0 -118 107l-4 3h-7q-71 -110 -122 -110q-74 14 -74 74q0 36 103 147q45 70 89 70zM233 1012q70 -18 70 -63v-882q0 -55 -70 -67h-3q-57 0 -71 74v853q9 85 74 85z" />
-<glyph unicode="&#xef;" horiz-adv-x="514" d="M237 1008q70 -18 70 -63v-879q0 -54 -70 -66h-4q-56 0 -70 74v849q9 85 74 85zM86 1273h11q66 -15 66 -63v-11q0 -58 -73 -70q-70 14 -70 70v11q0 48 66 63zM366 1273h14q52 0 63 -78q0 -49 -74 -66q-69 12 -69 66v19q18 59 66 59z" />
-<glyph unicode="&#xf0;" horiz-adv-x="1118" d="M748 1403h7q66 -14 66 -66v-14q0 -46 -169 -132v-4l279 -429q73 -123 73 -256q0 -282 -267 -443q-116 -59 -224 -59h-29q-203 0 -378 191q-106 150 -106 311q0 244 216 410q139 92 286 92l103 -11v4l-77 117q-132 -84 -158 -84h-15q-48 0 -62 69v4q0 50 110 103l48 29 q-41 61 -41 80v19q18 58 66 58h15q36 0 84 -80q149 91 173 91zM147 513v-18q0 -201 194 -312q70 -36 150 -36h22q208 0 319 216q25 68 25 132v18q0 140 -128 264q-101 80 -231 80q-228 0 -333 -238q-18 -58 -18 -106z" />
-<glyph unicode="&#xf1;" horiz-adv-x="1108" d="M399 1361h18q70 0 161 -62l29 -8h19l73 22q73 -14 73 -73q0 -74 -139 -91h-26q-69 0 -161 62l-29 7h-18l-70 -18h-7q-66 13 -66 66v11q0 55 81 73q29 11 62 11zM73 1002q70 -18 70 -62v-80q159 142 347 142q206 0 366 -172q117 -144 117 -303v-465q0 -48 -69 -62h-4 q-70 12 -70 70v409q0 275 -237 362q-58 15 -103 15h-11q-199 0 -307 -205q-29 -63 -29 -201v-384q0 -54 -70 -66h-3q-56 0 -70 73v845q8 84 73 84z" />
-<glyph unicode="&#xf2;" horiz-adv-x="1118" d="M502 1004q194 0 352 -147q150 -157 150 -355q0 -282 -267 -443q-116 -59 -224 -59h-29q-203 0 -378 191q-106 150 -106 311q0 244 216 410q139 92 286 92zM147 513v-18q0 -201 194 -312q70 -36 150 -36h22q208 0 319 216q25 68 25 132v18q0 167 -153 282q-91 62 -206 62 q-228 0 -333 -238q-18 -58 -18 -106zM469 1392h26q31 0 146 -150q30 -31 30 -58v-8q0 -57 -74 -69q-45 0 -102 88q-85 93 -85 117v14q0 48 59 66z" />
-<glyph unicode="&#xf3;" horiz-adv-x="1118" d="M594 1389q73 -17 73 -69v-7q0 -31 -80 -121q-60 -91 -113 -91h-4q-46 0 -62 69v8q0 33 113 160q38 51 73 51zM500 999q192 0 350 -146q149 -157 149 -353q0 -281 -266 -442q-115 -58 -223 -58h-29q-201 0 -375 190q-106 150 -106 310q0 243 215 408q138 91 285 91z M146 510v-18q0 -199 193 -310q70 -36 150 -36h21q208 0 318 215q25 68 25 131v18q0 167 -153 281q-90 62 -204 62q-227 0 -332 -237q-18 -58 -18 -106z" />
-<glyph unicode="&#xf4;" horiz-adv-x="1118" d="M492 1385l4 -3h4l3 3q51 0 124 -105q69 -75 69 -110q-12 -73 -73 -73q-47 0 -116 106l-4 4h-7q-70 -110 -120 -110q-73 15 -73 73q0 37 102 146q43 69 87 69zM500 999q192 0 350 -146q149 -157 149 -353q0 -281 -266 -442q-115 -58 -223 -58h-29q-201 0 -375 190 q-106 150 -106 310q0 243 215 408q138 91 285 91zM146 510v-18q0 -199 193 -310q70 -36 150 -36h21q208 0 318 215q25 68 25 131v18q0 167 -153 281q-90 62 -204 62q-227 0 -332 -237q-18 -58 -18 -106z" />
-<glyph unicode="&#xf5;" horiz-adv-x="1118" d="M502 1004q194 0 352 -147q150 -157 150 -355q0 -282 -267 -443q-116 -59 -224 -59h-29q-203 0 -378 191q-106 150 -106 311q0 244 216 410q139 92 286 92zM147 513v-18q0 -201 194 -312q70 -36 150 -36h22q208 0 319 216q25 68 25 132v18q0 167 -153 282q-91 62 -206 62 q-228 0 -333 -238q-18 -58 -18 -106zM407 1348h18q70 0 161 -62l30 -7h18l73 22q73 -15 73 -73q0 -75 -139 -92h-25q-69 0 -162 62l-29 8h-18l-70 -19h-7q-66 13 -66 66v11q0 55 80 73q30 11 63 11z" />
-<glyph unicode="&#xf6;" horiz-adv-x="1114" d="M354 1240h11q65 -15 65 -62v-11q0 -58 -73 -70q-69 14 -69 70v11q0 47 66 62zM631 1240h14q51 0 62 -77q0 -49 -73 -66q-69 12 -69 66v18q18 59 66 59zM500 999q192 0 350 -146q149 -157 149 -353q0 -281 -266 -442q-115 -58 -223 -58h-29q-201 0 -375 190 q-106 150 -106 310q0 243 215 408q138 91 285 91zM146 510v-18q0 -199 193 -310q70 -36 150 -36h21q208 0 318 215q25 68 25 131v18q0 167 -153 281q-90 62 -204 62q-227 0 -332 -237q-18 -58 -18 -106z" />
-<glyph unicode="&#xf7;" d="M522 1132h4q92 0 112 -100v-16q-22 -100 -100 -100h-8q-108 11 -108 108v8q24 100 100 100zM226 800h608q76 -14 76 -76v-12q0 -50 -72 -68h-616q-72 14 -72 72v16q0 53 76 68zM526 528h8q87 0 104 -112v-4q0 -81 -108 -104q-108 23 -108 100v20q0 76 104 100z" />
-<glyph unicode="&#xf8;" horiz-adv-x="1169" d="M963 1012h4q58 0 69 -77q0 -29 -102 -127q113 -138 113 -309q0 -281 -266 -441q-114 -58 -222 -58h-29q-137 0 -284 102q-81 -98 -120 -98h-14q-51 0 -62 76q0 30 98 124q-98 135 -98 295q0 242 215 407q137 91 284 91q146 0 283 -91q86 106 131 106zM196 509v-18 q0 -90 50 -182h4l477 492q-72 50 -182 50q-227 0 -331 -236q-18 -58 -18 -106zM832 706l-484 -502q94 -58 190 -58h21q207 0 317 214q25 68 25 131v18q0 108 -69 197z" />
-<glyph unicode="&#xf9;" horiz-adv-x="1109" d="M468 1389h25q32 0 147 -150q29 -31 29 -58v-8q0 -57 -73 -69q-45 0 -103 88q-84 93 -84 117v14q0 48 59 66zM73 1002q70 -18 70 -63v-391q0 -251 142 -336q90 -69 201 -69q214 0 322 219q22 71 22 142v424q14 74 73 74q69 -17 69 -70v-870q0 -48 -69 -62h-4 q-69 12 -69 69v70h-4q-153 -139 -329 -139h-25q-227 0 -395 223q-77 120 -77 296v398q8 85 73 85z" />
-<glyph unicode="&#xfa;" horiz-adv-x="1105" d="M599 1399q73 -16 73 -69v-8q0 -30 -81 -121q-60 -92 -114 -92h-3q-47 0 -63 70v7q0 34 114 162q38 51 74 51zM73 1006q70 -17 70 -62v-393q0 -252 143 -338q91 -70 203 -70q214 0 323 221q22 71 22 143v426q14 73 73 73q70 -16 70 -69v-875q0 -48 -70 -62h-3 q-70 12 -70 70v70h-4q-153 -140 -330 -140h-26q-228 0 -397 224q-77 121 -77 298v400q8 84 73 84z" />
-<glyph unicode="&#xfb;" horiz-adv-x="1114" d="M498 1403l4 -4h4l3 4q52 0 126 -107q70 -76 70 -111q-12 -74 -74 -74q-47 0 -118 107l-4 4h-7q-71 -111 -122 -111q-74 15 -74 74q0 37 104 148q44 70 88 70zM74 1012q70 -18 70 -63v-395q0 -254 144 -340q91 -70 203 -70q216 0 325 221q22 72 22 144v429q15 74 74 74 q70 -17 70 -71v-878q0 -49 -70 -63h-4q-70 13 -70 70v70h-4q-154 -140 -332 -140h-26q-229 0 -398 225q-78 121 -78 299v403q9 85 74 85z" />
-<glyph unicode="&#xfc;" horiz-adv-x="1109" d="M355 1244h11q66 -15 66 -62v-11q0 -59 -74 -70q-69 14 -69 70v11q0 47 66 62zM633 1244h14q51 0 63 -77q0 -49 -74 -66q-69 12 -69 66v18q18 59 66 59zM73 1002q70 -18 70 -62v-391q0 -252 142 -337q90 -69 202 -69q213 0 321 219q22 71 22 143v424q15 73 74 73 q69 -16 69 -69v-871q0 -48 -69 -62h-4q-70 12 -70 70v69h-3q-153 -139 -330 -139h-25q-227 0 -395 223q-77 120 -77 296v399q8 84 73 84z" />
-<glyph unicode="&#xfd;" horiz-adv-x="990" d="M617 1406q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM803 1017q74 -14 74 -70v-3q-4 -27 -363 -884q-170 -420 -191 -447q-18 -15 -47 -22q-74 16 -74 62v19q0 13 165 410v4l-348 850v4q15 73 73 73q63 0 107 -146 q238 -565 245 -594h4q288 703 304 722q26 22 51 22z" />
-<glyph unicode="&#xfe;" horiz-adv-x="1131" d="M73 1394h14q66 -14 66 -59v-482q161 154 361 154q195 0 353 -147q151 -158 151 -357q0 -283 -269 -445q-115 -59 -224 -59h-29q-176 0 -343 151v-507q0 -47 -73 -63q-55 0 -70 77v1656q9 81 63 81zM157 514v-18q0 -201 195 -313q70 -36 151 -36h22q209 0 320 217 q26 68 26 132v18q0 168 -155 284q-91 62 -206 62q-229 0 -334 -239q-19 -58 -19 -107z" />
-<glyph unicode="&#xff;" horiz-adv-x="990" d="M302 1241h11q66 -15 66 -62v-11q0 -58 -73 -70q-70 14 -70 70v11q0 47 66 62zM579 1241h15q51 0 62 -77q0 -49 -73 -66q-69 12 -69 66v18q18 59 65 59zM791 1000q73 -14 73 -70v-3q-4 -27 -361 -880q-169 -418 -190 -445q-18 -15 -48 -22q-73 16 -73 62v18q0 13 165 409 v4l-347 846v4q14 73 73 73q63 0 106 -146q237 -562 244 -591h4q287 700 303 719q25 22 51 22z" />
-<glyph unicode="&#x100;" horiz-adv-x="1184" d="M142 1697h844q70 -13 70 -70v-12q-13 -70 -67 -70h-847q-60 0 -70 82q19 70 70 70zM556 1428q69 0 102 -139q454 -1182 458 -1210v-11q0 -56 -71 -68h-4q-66 0 -94 128l-169 439h-440l-206 -544q-30 -23 -53 -23h-8q-71 13 -71 71v4l128 346q335 873 364 969q34 38 64 38 zM556 1142l-158 -428h323v4l-161 424h-4z" />
-<glyph unicode="&#x101;" horiz-adv-x="1199" d="M144 1297h844q70 -13 70 -70v-12q-13 -70 -67 -70h-847q-60 0 -70 82q19 70 70 70zM554 1023q290 0 459 -284q52 -115 52 -239v-433q0 -55 -71 -67h-4q-48 0 -71 56v4l4 93v4q-165 -157 -355 -157h-29q-260 0 -434 261q-63 126 -63 254q0 285 280 452q119 56 232 56z M188 519v-11q0 -223 224 -336q71 -26 127 -26h29q186 0 307 186q44 88 44 168v15q0 215 -212 329q-74 33 -153 33h-4q-226 0 -340 -235q-22 -73 -22 -123z" />
-<glyph unicode="&#x102;" horiz-adv-x="1202" d="M350 1806h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM556 1428q69 0 102 -139q454 -1182 458 -1210v-11q0 -56 -71 -68h-4q-66 0 -94 128l-169 439h-440 l-206 -544q-30 -23 -53 -23h-8q-71 13 -71 71v4l128 346q335 873 364 969q34 38 64 38zM556 1142l-158 -428h323v4l-161 424h-4z" />
-<glyph unicode="&#x103;" horiz-adv-x="1118" d="M306 1414h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM512 1023q290 0 459 -284q52 -115 52 -239v-433q0 -55 -71 -67h-4q-48 0 -71 56v4l4 93v4 q-165 -157 -355 -157h-29q-260 0 -434 261q-63 126 -63 254q0 285 280 452q119 56 232 56zM146 519v-11q0 -223 224 -336q71 -26 127 -26h29q186 0 307 186q44 88 44 168v15q0 215 -212 329q-74 33 -153 33h-4q-226 0 -340 -235q-22 -73 -22 -123z" />
-<glyph unicode="&#x104;" horiz-adv-x="1338" d="M572 1437q68 0 100 -130q479 -1247 479 -1269l4 -27v-95q0 -64 -84 -77q-31 -18 -31 -50v-8q0 -42 58 -49h145q73 -13 73 -73v-4q-15 -73 -65 -73h-161q-145 0 -196 161l-7 46q0 112 119 188v19q-16 68 -207 564h-449l-211 -556q-30 -23 -53 -23h-8q-73 13 -73 73v3 l130 353q343 891 372 989q35 38 65 38zM572 1146l-161 -437h330v4l-165 433h-4z" />
-<glyph unicode="&#x105;" horiz-adv-x="1241" d="M517 1007q292 0 461 -284q53 -117 53 -240v-446l-4 -4l4 -4v-112q0 -60 -90 -79q-23 -17 -23 -37v-19q10 -45 56 -45h143q58 0 71 -75q-16 -71 -64 -71h-157q-143 0 -195 161l-4 45q0 107 117 180l-4 52l7 90v19q-165 -157 -356 -157h-30q-261 0 -434 262 q-64 126 -64 255q0 286 281 453q120 56 232 56zM150 501v-11q0 -223 225 -337q71 -26 127 -26h30q187 0 308 187q45 88 45 169v15q0 215 -214 329q-74 34 -154 34h-3q-227 0 -341 -236q-23 -73 -23 -124z" />
-<glyph unicode="&#x106;" horiz-adv-x="1251" d="M833 1863q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM714 1436q223 0 416 -136q15 -29 15 -45v-8q0 -64 -79 -72h-4l-132 68q-132 42 -216 42q-269 0 -465 -246q-98 -165 -98 -321q0 -315 295 -499 q131 -68 261 -68h11q166 0 336 106h23q68 -15 68 -68v-11q0 -80 -253 -155q-79 -23 -166 -23h-19q-355 0 -594 329q-113 190 -113 389q0 373 340 608q182 110 374 110z" />
-<glyph unicode="&#x107;" horiz-adv-x="973" d="M622 1467q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM513 1026q198 0 360 -149q11 -20 11 -38v-4q-13 -71 -71 -71h-4q-27 0 -120 71q-83 42 -165 42h-22q-218 0 -330 -229q-26 -77 -26 -139q0 -222 229 -337 q69 -26 146 -26q129 0 254 105l30 7h12q55 0 67 -71v-3q0 -77 -240 -169q-81 -15 -120 -15h-30q-207 0 -385 195q-109 154 -109 318q0 250 221 420q141 93 292 93z" />
-<glyph unicode="&#x108;" horiz-adv-x="1254" d="M672 1814h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM714 1436q223 0 416 -136q15 -29 15 -45v-8q0 -64 -79 -72h-4l-132 68q-132 42 -216 42q-269 0 -465 -246 q-98 -165 -98 -321q0 -315 295 -499q131 -68 261 -68h11q166 0 336 106h23q68 -15 68 -68v-11q0 -80 -253 -155q-79 -23 -166 -23h-19q-355 0 -594 329q-113 190 -113 389q0 373 340 608q182 110 374 110z" />
-<glyph unicode="&#x109;" horiz-adv-x="982" d="M509 1449h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM513 1026q198 0 360 -149q11 -20 11 -38v-4q-13 -71 -71 -71h-4q-27 0 -120 71q-83 42 -165 42h-22 q-218 0 -330 -229q-26 -77 -26 -139q0 -222 229 -337q69 -26 146 -26q129 0 254 105l30 7h12q55 0 67 -71v-3q0 -77 -240 -169q-81 -15 -120 -15h-30q-207 0 -385 195q-109 154 -109 318q0 250 221 420q141 93 292 93z" />
-<glyph unicode="&#x10a;" horiz-adv-x="1259" d="M719 1780q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6zM714 1436q223 0 416 -136q15 -29 15 -45v-8q0 -64 -79 -72h-4l-132 68q-132 42 -216 42q-269 0 -465 -246q-98 -165 -98 -321q0 -315 295 -499q131 -68 261 -68h11 q166 0 336 106h23q68 -15 68 -68v-11q0 -80 -253 -155q-79 -23 -166 -23h-19q-355 0 -594 329q-113 190 -113 389q0 373 340 608q182 110 374 110z" />
-<glyph unicode="&#x10b;" horiz-adv-x="973" d="M534 1379q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6zM513 1026q198 0 360 -149q11 -20 11 -38v-4q-13 -71 -71 -71h-4q-27 0 -120 71q-83 42 -165 42h-22q-218 0 -330 -229q-26 -77 -26 -139q0 -222 229 -337 q69 -26 146 -26q129 0 254 105l30 7h12q55 0 67 -71v-3q0 -77 -240 -169q-81 -15 -120 -15h-30q-207 0 -385 195q-109 154 -109 318q0 250 221 420q141 93 292 93z" />
-<glyph unicode="&#x10c;" horiz-adv-x="1241" d="M556 1813h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM714 1436q223 0 416 -136q15 -29 15 -45v-8q0 -64 -79 -72h-4l-132 68q-132 42 -216 42q-269 0 -465 -246 q-98 -165 -98 -321q0 -315 295 -499q131 -68 261 -68h11q166 0 336 106h23q68 -15 68 -68v-11q0 -80 -253 -155q-79 -23 -166 -23h-19q-355 0 -594 329q-113 190 -113 389q0 373 340 608q182 110 374 110z" />
-<glyph unicode="&#x10d;" horiz-adv-x="990" d="M363 1439h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM513 1026q198 0 360 -149q11 -20 11 -38v-4q-13 -71 -71 -71h-4q-27 0 -120 71q-83 42 -165 42h-22 q-218 0 -330 -229q-26 -77 -26 -139q0 -222 229 -337q69 -26 146 -26q129 0 254 105l30 7h12q55 0 67 -71v-3q0 -77 -240 -169q-81 -15 -120 -15h-30q-207 0 -385 195q-109 154 -109 318q0 250 221 420q141 93 292 93z" />
-<glyph unicode="&#x10e;" horiz-adv-x="1162" d="M322 1818h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM72 1441l19 -4h193l42 4q323 0 561 -281q152 -197 152 -447q0 -344 -303 -580q-192 -133 -406 -133h-258 q-72 13 -72 72v1293q11 72 72 72v4zM148 1293v-1145h163q361 0 535 349q45 119 45 227q0 261 -231 455q-143 114 -425 114h-87z" />
-<glyph unicode="&#x10f;" horiz-adv-x="1343" d="M1154 1514h28q83 0 112 -236v-20q0 -129 -144 -248q-29 -16 -44 -16q-18 7 -28 24v12q60 144 60 236v12q0 62 -48 144v20q15 72 64 72zM948 1432h15q68 -14 68 -61v-748l4 -128q0 -148 -121 -310q-171 -185 -385 -185h-30q-209 0 -389 196q-110 156 -110 322 q0 251 223 423q142 94 295 94q197 0 370 -155v427l-4 60q21 65 64 65zM147 529v-19q0 -231 242 -344q65 -19 117 -19h23q225 0 340 242q19 73 19 113v23q0 230 -246 344q-75 19 -117 19h-15q-225 0 -340 -238q-23 -67 -23 -121z" />
-<glyph unicode="&#x110;" horiz-adv-x="1303" d="M185 847v518q11 72 72 72v4l19 -4h193l42 4q323 0 561 -281q152 -197 152 -447q0 -344 -303 -580q-192 -133 -406 -133h-258q-72 13 -72 72v623h-49l-64 -4q-68 24 -68 80q13 76 72 76h109zM333 847h183l36 4q56 0 76 -80q0 -55 -68 -80l-60 4h-167v-547h163 q361 0 535 349q45 119 45 227q0 261 -231 455q-143 114 -425 114h-87v-446z" />
-<glyph unicode="&#x111;" horiz-adv-x="1343" d="M178 529v-19q0 -231 242 -344q65 -19 117 -19h23q225 0 340 242q19 73 19 113v23q0 230 -246 344q-75 19 -117 19h-15q-225 0 -340 -238q-23 -67 -23 -121zM919 1309l-4 58q21 65 64 65h15q68 -14 68 -61v-62h127l36 4q56 0 76 -80q0 -55 -68 -80l-60 4h-111v-534l4 -128 q0 -148 -121 -310q-171 -185 -385 -185h-30q-209 0 -389 196q-110 156 -110 322q0 251 223 423q142 94 295 94q197 0 370 -155v277h-110l-64 -4q-68 24 -68 80q13 76 72 76v4l40 -4h130z" />
-<glyph unicode="&#x112;" horiz-adv-x="1100" d="M129 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4zM85 1727h844q70 -13 70 -70v-12q-13 -70 -67 -70h-847q-60 0 -70 82 q19 70 70 70z" />
-<glyph unicode="&#x113;" horiz-adv-x="1105" d="M498 1004q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55h22q66 -13 66 -66v-11q0 -91 -264 -125h-26q-270 0 -432 253q-66 120 -66 249q0 276 260 440q127 62 238 62zM150 546h704q0 75 -88 194 q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136zM85 1318h844q70 -13 70 -70v-12q-13 -70 -67 -70h-847q-60 0 -70 82q19 70 70 70z" />
-<glyph unicode="&#x114;" horiz-adv-x="1052" d="M107 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4zM292 1824h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8 q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72z" />
-<glyph unicode="&#x115;" horiz-adv-x="1101" d="M507 1004q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55h22q66 -13 66 -66v-11q0 -91 -264 -125h-26q-270 0 -432 253q-66 120 -66 249q0 276 260 440q127 62 238 62zM159 546h704q0 75 -88 194 q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136zM301 1436h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72z" />
-<glyph unicode="&#x116;" horiz-adv-x="1070" d="M103 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4zM504 1785q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3 q-96 0 -116 119q0 76 86 110q12 6 33 6z" />
-<glyph unicode="&#x117;" horiz-adv-x="1105" d="M520 1004q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55h22q66 -13 66 -66v-11q0 -91 -264 -125h-26q-270 0 -432 253q-66 120 -66 249q0 276 260 440q127 62 238 62zM172 546h704q0 75 -88 194 q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136zM543 1349q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6z" />
-<glyph unicode="&#x118;" horiz-adv-x="1052" d="M591 0h-488q-72 13 -72 72v1288q11 72 72 72v4l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-155l2 -10v-103q0 -58 -81 -70q-25 -18 -25 -46q0 -53 67 -53h102l15 4 q70 -16 70 -67v-7q0 -46 -56 -67l-74 4h-36l-56 -4q-71 0 -144 92q-25 48 -25 84v28q0 96 106 155v4z" />
-<glyph unicode="&#x119;" horiz-adv-x="1122" d="M172 546h704q0 75 -88 194q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136zM522 0h-2q-270 0 -432 253q-66 120 -66 249q0 276 260 440q127 62 238 62q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55 h22q66 -13 66 -66v-11q0 -69 -151 -105q2 -6 3 -12v-103q0 -58 -81 -70q-25 -18 -25 -46q0 -53 67 -53h102l15 4q70 -16 70 -67v-7q0 -46 -56 -67l-74 4h-36l-56 -4q-71 0 -144 92q-25 48 -25 84v28q0 96 106 155v4z" />
-<glyph unicode="&#x11a;" horiz-adv-x="1065" d="M107 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4zM357 1818h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12 q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72z" />
-<glyph unicode="&#x11b;" horiz-adv-x="1136" d="M542 1004q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55h22q66 -13 66 -66v-11q0 -91 -264 -125h-26q-270 0 -432 253q-66 120 -66 249q0 276 260 440q127 62 238 62zM194 546h704q0 75 -88 194 q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136zM415 1422h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72z" />
-<glyph unicode="&#x11c;" horiz-adv-x="1285" d="M707 1836h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM738 1436q229 0 412 -128q19 -26 19 -49v-4q0 -58 -76 -72q-12 0 -147 64q-88 34 -170 34h-61 q-211 0 -404 -204q-125 -171 -125 -351v-15q0 -294 272 -480q142 -80 284 -80h15q140 0 280 76v344h-273q-71 12 -71 72v3q12 72 71 72h352q56 0 68 -72v-419q0 -92 -45 -114q-193 -113 -375 -113h-22q-355 0 -594 329q-113 186 -113 389q0 361 321 597q197 121 382 121z " />
-<glyph unicode="&#x11d;" horiz-adv-x="1167" d="M527 1454h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM532 1021q227 0 394 -189q115 -158 115 -298l-4 -126v-449q0 -126 -193 -275q-149 -97 -312 -97 q-279 0 -461 249q-33 55 -33 74v11q0 49 67 64h11q50 0 85 -93q134 -168 331 -168q237 0 357 216l7 48v167q-165 -152 -353 -152h-30q-205 0 -382 193q-108 153 -108 316q0 248 219 416q140 93 290 93zM168 523v-18q0 -227 238 -338q64 -19 115 -19h22q222 0 335 238 q18 71 18 111v23q0 226 -241 338q-75 18 -116 18h-14q-222 0 -335 -234q-22 -65 -22 -119z" />
-<glyph unicode="&#x11e;" horiz-adv-x="1246" d="M490 1807h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM725 1436q229 0 412 -128q19 -26 19 -49v-4q0 -58 -76 -72q-12 0 -147 64q-88 34 -170 34h-61 q-211 0 -404 -204q-125 -171 -125 -351v-15q0 -294 272 -480q142 -80 284 -80h15q140 0 280 76v344h-273q-71 12 -71 72v3q12 72 71 72h352q56 0 68 -72v-419q0 -92 -45 -114q-193 -113 -375 -113h-22q-355 0 -594 329q-113 186 -113 389q0 361 321 597q197 121 382 121z " />
-<glyph unicode="&#x11f;" horiz-adv-x="1140" d="M336 1436h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM545 1021q227 0 394 -189q115 -158 115 -298l-4 -126v-449q0 -126 -193 -275q-149 -97 -312 -97 q-279 0 -461 249q-33 55 -33 74v11q0 49 67 64h11q50 0 85 -93q134 -168 331 -168q237 0 357 216l7 48v167q-165 -152 -353 -152h-30q-205 0 -382 193q-108 153 -108 316q0 248 219 416q140 93 290 93zM181 523v-18q0 -227 238 -338q64 -19 115 -19h22q222 0 335 238 q18 71 18 111v23q0 226 -241 338q-75 18 -116 18h-14q-222 0 -335 -234q-22 -65 -22 -119z" />
-<glyph unicode="&#x120;" horiz-adv-x="1272" d="M750 1793q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6zM729 1436q229 0 412 -128q19 -26 19 -49v-4q0 -58 -76 -72q-12 0 -147 64q-88 34 -170 34h-61q-211 0 -404 -204q-125 -171 -125 -351v-15q0 -294 272 -480 q142 -80 284 -80h15q140 0 280 76v344h-273q-71 12 -71 72v3q12 72 71 72h352q56 0 68 -72v-419q0 -92 -45 -114q-193 -113 -375 -113h-22q-355 0 -594 329q-113 186 -113 389q0 361 321 597q197 121 382 121z" />
-<glyph unicode="&#x121;" horiz-adv-x="1149" d="M579 1407q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6zM554 1021q227 0 394 -189q115 -158 115 -298l-4 -126v-449q0 -126 -193 -275q-149 -97 -312 -97q-279 0 -461 249q-33 55 -33 74v11q0 49 67 64h11q50 0 85 -93 q134 -168 331 -168q237 0 357 216l7 48v167q-165 -152 -353 -152h-30q-205 0 -382 193q-108 153 -108 316q0 248 219 416q140 93 290 93zM190 523v-18q0 -227 238 -338q64 -19 115 -19h22q222 0 335 238q18 71 18 111v23q0 226 -241 338q-75 18 -116 18h-14 q-222 0 -335 -234q-22 -65 -22 -119z" />
-<glyph unicode="&#x122;" horiz-adv-x="1276" d="M671 3q-308 30 -523 326q-113 186 -113 389q0 361 321 597q197 121 382 121q229 0 412 -128q19 -26 19 -49v-4q0 -58 -76 -72q-12 0 -147 64q-88 34 -170 34h-61q-211 0 -404 -204q-125 -171 -125 -351v-15q0 -294 272 -480q142 -80 284 -80h15q140 0 280 76v344h-273 q-71 12 -71 72v3q12 72 71 72h352q56 0 68 -72v-419q0 -92 -45 -114q-170 -100 -332 -111v-31q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53v94z" />
-<glyph unicode="&#x123;" horiz-adv-x="1184" d="M636 1669q28 -8 28 -32v-8q-59 -141 -60 -244q0 -60 48 -140l4 -20q0 -64 -84 -80q-96 0 -124 252q0 134 144 256zM567 1021q227 0 394 -189q115 -158 115 -298l-4 -126v-449q0 -126 -193 -275q-149 -97 -312 -97q-279 0 -461 249q-33 55 -33 74v11q0 49 67 64h11 q50 0 85 -93q134 -168 331 -168q237 0 357 216l7 48v167q-165 -152 -353 -152h-30q-205 0 -382 193q-108 153 -108 316q0 248 219 416q140 93 290 93zM203 523v-18q0 -227 238 -338q64 -19 115 -19h22q222 0 335 238q18 71 18 111v23q0 226 -241 338q-75 18 -116 18h-14 q-222 0 -335 -234q-22 -65 -22 -119z" />
-<glyph unicode="&#x124;" horiz-adv-x="1176" d="M558 1836h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM104 1433h15q68 -14 68 -60v-598h712v587q12 71 68 71h11q68 -13 68 -68v-1301q0 -49 -72 -64h-4 q-71 13 -71 72v560h-712v-564q0 -56 -71 -68h-4q-58 0 -72 76v1274q9 83 64 83z" />
-<glyph unicode="&#x125;" horiz-adv-x="1074" d="M518 1752h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM99 1430h15q68 -14 68 -60v-461q145 125 310 125q252 0 403 -238q57 -106 57 -200v-528q0 -56 -72 -68h-3 q-54 0 -72 68v506q0 204 -211 294q-51 15 -102 15q-210 0 -295 -223q-15 -48 -15 -158v-434q0 -56 -72 -68h-3q-54 0 -72 68v1291q15 71 64 71z" />
-<glyph unicode="&#x126;" horiz-adv-x="1303" d="M137 1192v158q9 83 64 83h15q68 -14 68 -60v-183h712v172q12 71 68 71h11q68 -13 68 -68v-173l24 2q78 0 101 -80q0 -52 -85 -80l-40 2v-972q0 -49 -72 -64h-4q-71 13 -71 72v560h-712v-564q0 -56 -71 -68h-4q-58 0 -72 76v959l-29 -1q-90 24 -90 80q17 76 95 76v4z M284 1038v-263h712v263h-712z" />
-<glyph unicode="&#x127;" horiz-adv-x="1330" d="M291 1287v72q15 71 64 71h15q68 -14 68 -60v-83h425l36 4q59 0 76 -80q0 -52 -64 -80l-68 4h-405v-226q145 125 310 125q252 0 403 -238q57 -106 57 -200v-528q0 -56 -72 -68h-3q-54 0 -72 68v506q0 204 -211 294q-51 15 -102 15q-210 0 -295 -223q-15 -48 -15 -158v-434 q0 -56 -72 -68h-3q-54 0 -72 68v1067h-128l-64 -4q-68 24 -68 80q13 76 72 76v4l40 -4h148z" />
-<glyph unicode="&#x128;" horiz-adv-x="621" d="M193 1739q79 0 189 -71l33 -4l76 23h7q72 -12 72 -72v-4q0 -70 -124 -90l-38 -4q-79 0 -181 72l-30 4l-83 -23q-75 14 -75 71v8q0 72 139 87zM194 1448l19 -3h142l15 3q76 -16 76 -76q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72h-180q-72 13 -72 72v4 q15 73 65 73h23v1147h-16q-63 0 -72 80v4q0 47 72 68z" />
-<glyph unicode="&#x129;" horiz-adv-x="616" d="M193 1329q79 0 189 -71l33 -4l76 23h7q72 -12 72 -72v-4q0 -70 -124 -90l-38 -4q-79 0 -181 72l-30 4l-83 -23q-75 14 -75 71v8q0 72 139 87zM296 1030q72 -18 72 -64v-898q0 -56 -72 -68h-4q-57 0 -71 75v869q9 86 75 86z" />
-<glyph unicode="&#x12a;" horiz-adv-x="683" d="M94 1718l40 -4h400l36 4q56 0 76 -80q0 -55 -68 -80l-60 4h-364l-64 -4q-68 24 -68 80q13 76 72 76v4zM238 1448l19 -3h142l15 3q76 -16 76 -76q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72h-180q-72 13 -72 72v4q15 73 65 73h23v1147h-16 q-63 0 -72 80v4q0 47 72 68z" />
-<glyph unicode="&#x12b;" horiz-adv-x="744" d="M116 1313l40 -4h400l36 4q56 0 76 -80q0 -55 -68 -80l-60 4h-364l-64 -4q-68 24 -68 80q13 76 72 76v4zM349 1030q72 -18 72 -64v-898q0 -56 -72 -68h-4q-57 0 -71 75v869q9 86 75 86z" />
-<glyph unicode="&#x12c;" horiz-adv-x="647" d="M102 1832h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM224 1448l19 -3h142l15 3q76 -16 76 -76q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72 h-180q-72 13 -72 72v4q15 73 65 73h23v1147h-16q-63 0 -72 80v4q0 47 72 68z" />
-<glyph unicode="&#x12d;" horiz-adv-x="647" d="M94 1422h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM296 1030q72 -18 72 -64v-898q0 -56 -72 -68h-4q-57 0 -71 75v869q9 86 75 86z" />
-<glyph unicode="&#x12e;" horiz-adv-x="511" d="M172 0h-40q-72 13 -72 72v4q15 73 65 73h23v1147h-16q-63 0 -72 80v4q0 47 72 68l19 -3h142l15 3q76 -16 76 -76q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72h-2v-65q0 -58 -81 -70q-25 -18 -25 -46q0 -53 67 -53h102l15 4q70 -16 70 -67v-7 q0 -46 -56 -67l-74 4h-36l-56 -4q-71 0 -144 92q-25 48 -25 84v28q0 96 106 155v4z" />
-<glyph unicode="&#x12f;" horiz-adv-x="466" d="M203 1286q72 -18 72 -64v-22q0 -53 -79 -64q-51 0 -68 75q15 75 75 75zM135 50q-4 11 -7 25v869q9 86 75 86q72 -18 72 -64v-898q0 -7 -1 -14q0 -3 1 -6v-103q0 -58 -81 -70q-25 -18 -25 -46q0 -53 67 -53h102l15 4q70 -16 70 -67v-7q0 -46 -56 -67l-74 4h-36l-56 -4 q-71 0 -144 92q-25 48 -25 84v28q0 96 106 155v4z" />
-<glyph unicode="&#x130;" horiz-adv-x="462" d="M235 1793q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6zM132 1448l19 -3h142l15 3q76 -16 76 -76q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72h-180q-72 13 -72 72v4q15 73 65 73h23v1147h-16 q-63 0 -72 80v4q0 47 72 68z" />
-<glyph unicode="&#x131;" horiz-adv-x="514" d="M309 970h8q46 -10 46 -43v-878q-9 -49 -49 -49h-2q-49 10 -49 43v809q-69 -23 -90 -23q-32 0 -43 47v13q0 38 103 59z" />
-<glyph unicode="&#x132;" horiz-adv-x="1435" d="M1260 1443h12q55 0 68 -72v-923q0 -239 -224 -383q-105 -61 -216 -61h-19q-220 0 -369 213q-68 113 -68 235q16 72 65 72h15q72 0 72 -118q6 -82 99 -182q91 -72 197 -72q211 0 289 220q11 40 11 80v923q13 68 68 68zM132 1448l19 -3h142l15 3q76 -16 76 -76 q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72h-180q-72 13 -72 72v4q15 73 65 73h23v1147h-16q-63 0 -72 80v4q0 47 72 68z" />
-<glyph unicode="&#x133;" horiz-adv-x="761" d="M550 1277q74 -15 74 -74q0 -62 -78 -74q-66 19 -66 63v22q0 45 70 63zM554 1026q70 -14 70 -70v-928q0 -276 -262 -403q-92 -33 -159 -33l-4 4h-4l-3 -4h-4q-63 0 -74 81q0 55 81 67q208 0 277 210l8 111v895q0 58 74 70zM155 1286q72 -18 72 -64v-22q0 -53 -79 -64 q-51 0 -68 75q15 75 75 75zM155 1030q72 -18 72 -64v-898q0 -56 -72 -68h-4q-57 0 -71 75v869q9 86 75 86z" />
-<glyph unicode="&#x134;" horiz-adv-x="1166" d="M861 1810h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM877 1443h12q55 0 68 -72v-923q0 -239 -224 -383q-105 -61 -216 -61h-19q-220 0 -369 213q-68 113 -68 235 q16 72 65 72h15q72 0 72 -118q6 -82 99 -182q91 -72 197 -72q211 0 289 220q11 40 11 80v923q13 68 68 68z" />
-<glyph unicode="&#x135;" horiz-adv-x="810" d="M478 1405h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM501 1026q70 -14 70 -70v-928q0 -276 -262 -403q-92 -33 -159 -33l-4 4h-4l-3 -4h-4q-63 0 -74 81 q0 55 81 67q208 0 277 210l8 111v895q0 58 74 70z" />
-<glyph unicode="&#x136;" horiz-adv-x="1104" d="M118 1434h3q72 -12 72 -68v-653q700 699 706 699l27 4h7q68 -13 68 -68v-12q0 -37 -79 -102l-465 -468l533 -660l3 -23v-11q0 -56 -71 -68h-4q-45 0 -125 117l-445 540l-155 -159v-434q0 -56 -72 -68h-3q-58 0 -72 75v1284q14 75 72 75zM584 40q104 -69 104 -170 q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53q0 58 41.5 73.5t94.5 -11.5z" />
-<glyph unicode="&#x137;" horiz-adv-x="1026" d="M124 1435h15q69 -15 69 -61v-746q535 354 624 405h19q60 0 72 -79q0 -46 -121 -110q-294 -199 -307 -201v-3l424 -538l4 -23v-3q-13 -72 -72 -72h-7q-44 0 -133 128l-341 424h-3l-159 -102v-386q0 -56 -72 -68h-4q-54 0 -72 68v1295q15 72 64 72zM549 49 q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53q0 58 41.5 73.5t94.5 -11.5z" />
-<glyph unicode="&#x138;" horiz-adv-x="1043" d="M140 1073l21 1q56 -14 60 -81v-365q535 354 624 405h19q60 0 72 -79q0 -46 -121 -110q-294 -199 -307 -201v-3l424 -538l4 -23v-3q-13 -72 -72 -72h-7q-44 0 -133 128l-341 424h-3l-159 -102v-386q0 -56 -72 -68h-4q-54 0 -72 68v927q12 65 67 78z" />
-<glyph unicode="&#x139;" horiz-adv-x="947" d="M498 1824q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM95 1433h15q68 -14 68 -60v-1226h617q61 0 72 -79q-20 -68 -72 -68h-692q-58 0 -72 76v1274q9 83 64 83z" />
-<glyph unicode="&#x13a;" horiz-adv-x="466" d="M312 1837q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM142 1427h15q68 -14 68 -60v-1220h79q49 0 64 -72v-3q-12 -72 -72 -72h-146q-58 0 -72 75v1270q9 82 64 82z" />
-<glyph unicode="&#x13b;" horiz-adv-x="929" d="M86 1433h15q68 -14 68 -60v-1226h617q61 0 72 -79q-20 -68 -72 -68h-692q-58 0 -72 76v1274q9 83 64 83zM544 -56q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53q0 58 41.5 73.5 t94.5 -11.5z" />
-<glyph unicode="&#x13c;" horiz-adv-x="515" d="M191 1427h15q68 -14 68 -60v-1220h79q49 0 64 -72v-3q-12 -72 -72 -72h-146q-58 0 -72 75v1270q9 82 64 82zM329 -60q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53q0 58 41.5 73.5 t94.5 -11.5z" />
-<glyph unicode="&#x13d;" horiz-adv-x="973" d="M719 1576h28q83 0 112 -236v-20q0 -129 -144 -248q-29 -16 -44 -16q-18 7 -28 24v12q60 144 60 236v12q0 62 -48 144v20q15 72 64 72zM130 1433h15q68 -14 68 -60v-1226h617q61 0 72 -79q-20 -68 -72 -68h-692q-58 0 -72 76v1274q9 83 64 83z" />
-<glyph unicode="&#x13e;" horiz-adv-x="559" d="M372 1567h28q83 0 112 -236v-20q0 -129 -144 -248q-29 -16 -44 -16q-18 7 -28 24v12q60 144 60 236v12q0 62 -48 144v20q15 72 64 72zM138 1427h15q68 -14 68 -60v-1220h79q49 0 64 -72v-3q-12 -72 -72 -72h-146q-58 0 -72 75v1270q9 82 64 82z" />
-<glyph unicode="&#x13f;" horiz-adv-x="1004" d="M635 869q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6zM130 1433h15q68 -14 68 -60v-1226h617q61 0 72 -79q-20 -68 -72 -68h-692q-58 0 -72 76v1274q9 83 64 83z" />
-<glyph unicode="&#x140;" horiz-adv-x="665" d="M468 834q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6zM129 1427h15q68 -14 68 -60v-1220h79q49 0 64 -72v-3q-12 -72 -72 -72h-146q-58 0 -72 75v1270q9 82 64 82z" />
-<glyph unicode="&#x141;" horiz-adv-x="1079" d="M185 697v653q9 83 64 83h15q68 -14 68 -60v-568q238 174 260 174h20q50 0 68 -72v-12q0 -49 -120 -120l-228 -165v-463h617q61 0 72 -79q-20 -68 -72 -68h-692q-58 0 -72 76v430q-45 -31 -49 -31l-20 -4q-80 16 -80 80q0 57 149 146z" />
-<glyph unicode="&#x142;" horiz-adv-x="695" d="M370 772q184 132 203 132h20q50 0 68 -72v-12q0 -49 -120 -120l-171 -124v-429h79q49 0 64 -72v-3q-12 -72 -72 -72h-146q-58 0 -72 75v395q-100 -70 -106 -70l-20 -4q-80 16 -80 80q0 58 152 148l54 40v681q9 82 64 82h15q68 -14 68 -60v-595z" />
-<glyph unicode="&#x143;" horiz-adv-x="1285" d="M824 1758q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM99 1431h15q48 0 83 -75q56 -63 821 -1051q8 0 8 -11l3 -4h4v1073q13 68 68 68h11q56 0 68 -71v-1285q0 -62 -79 -75q-43 0 -132 132l-787 1005v-1065 q0 -56 -72 -68h-3q-58 0 -72 75v1269q9 83 64 83z" />
-<glyph unicode="&#x144;" horiz-adv-x="1096" d="M648 1525q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM104 1002q70 -18 70 -62v-80q159 142 347 142q206 0 366 -172q117 -144 117 -303v-465q0 -48 -69 -62h-4q-70 12 -70 70v409q0 275 -237 362q-58 15 -103 15 h-11q-199 0 -307 -205q-29 -63 -29 -201v-384q0 -54 -70 -66h-3q-56 0 -70 73v845q8 84 73 84z" />
-<glyph unicode="&#x145;" horiz-adv-x="1307" d="M130 1431h15q48 0 83 -75q56 -63 821 -1051q8 0 8 -11l3 -4h4v1073q13 68 68 68h11q56 0 68 -71v-1285q0 -62 -79 -75q-43 0 -132 132l-787 1005v-1065q0 -56 -72 -68h-3q-58 0 -72 75v1269q9 83 64 83zM733 49q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3 q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53q0 58 41.5 73.5t94.5 -11.5z" />
-<glyph unicode="&#x146;" horiz-adv-x="1140" d="M592 45q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53q0 58 41.5 73.5t94.5 -11.5zM108 1002q70 -18 70 -62v-80q159 142 347 142q206 0 366 -172q117 -144 117 -303v-465 q0 -48 -69 -62h-4q-70 12 -70 70v409q0 275 -237 362q-58 15 -103 15h-11q-199 0 -307 -205q-29 -63 -29 -201v-384q0 -54 -70 -66h-3q-56 0 -70 73v845q8 84 73 84z" />
-<glyph unicode="&#x147;" horiz-adv-x="1321" d="M498 1690h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM117 1431h15q48 0 83 -75q56 -63 821 -1051q8 0 8 -11l3 -4h4v1073q13 68 68 68h11q56 0 68 -71v-1285 q0 -62 -79 -75q-43 0 -132 132l-787 1005v-1065q0 -56 -72 -68h-3q-58 0 -72 75v1269q9 83 64 83z" />
-<glyph unicode="&#x148;" horiz-adv-x="1114" d="M406 1439h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM113 1002q70 -18 70 -62v-80q159 142 347 142q206 0 366 -172q117 -144 117 -303v-465q0 -48 -69 -62h-4 q-70 12 -70 70v409q0 275 -237 362q-58 15 -103 15h-11q-199 0 -307 -205q-29 -63 -29 -201v-384q0 -54 -70 -66h-3q-56 0 -70 73v845q8 84 73 84z" />
-<glyph unicode="&#x149;" horiz-adv-x="1427" d="M129 1276h28q83 0 112 -236v-20q0 -129 -144 -248q-29 -16 -44 -16q-18 7 -28 24v12q60 144 60 236v12q0 62 -48 144v20q15 72 64 72zM364 1002q70 -18 70 -62v-80q159 142 347 142q206 0 366 -172q117 -144 117 -303v-465q0 -48 -69 -62h-4q-70 12 -70 70v409 q0 275 -237 362q-58 15 -103 15h-11q-199 0 -307 -205q-29 -63 -29 -201v-384q0 -54 -70 -66h-3q-56 0 -70 73v845q8 84 73 84z" />
-<glyph unicode="&#x14a;" horiz-adv-x="1268" d="M613 1433q230 0 415 -181q135 -157 151 -302l7 -49l-3 -117v-207l3 -98q-14 -131 -90 -238q-151 -184 -370 -184q-156 0 -267 94l-8 34v11q13 68 68 68h7l125 -49l75 -8h8q172 0 268 166q37 55 37 215v230q0 324 -275 438q-79 26 -136 26h-22q-237 0 -374 -234 q-45 -82 -45 -252v-728q0 -56 -72 -68h-3q-58 0 -72 75v1271q9 83 64 83h15q68 -14 68 -60v-128q190 192 426 192z" />
-<glyph unicode="&#x14b;" horiz-adv-x="1140" d="M1012 50q-4 -212 -228 -299l-87 -15q-73 16 -73 62v22q0 54 83 61q110 0 160 138q0 23 3 42v418q0 275 -237 362q-58 15 -103 15h-11q-199 0 -307 -205q-29 -63 -29 -201v-384q0 -54 -70 -66h-3q-56 0 -70 73v845q8 84 73 84q70 -18 70 -62v-80q159 142 347 142 q206 0 366 -172q117 -144 117 -303v-465q0 -6 -1 -12z" />
-<glyph unicode="&#x14c;" horiz-adv-x="1580" d="M340 1704h844q70 -13 70 -70v-12q-13 -70 -67 -70h-847q-60 0 -70 82q19 70 70 70zM749 1435q363 0 607 -336q110 -191 110 -385q0 -359 -325 -597q-184 -117 -385 -117h-15q-370 0 -604 344q-106 174 -106 377q0 343 302 578q196 136 416 136zM178 710q0 -274 242 -461 q151 -102 321 -102h19q268 0 453 238q106 153 106 333q0 309 -283 490q-140 80 -287 80q-283 0 -469 -246q-102 -147 -102 -332z" />
-<glyph unicode="&#x14d;" horiz-adv-x="1188" d="M133 1325h844q70 -13 70 -70v-12q-13 -70 -67 -70h-847q-60 0 -70 82q19 70 70 70zM553 1018q197 0 357 -149q152 -160 152 -360q0 -286 -271 -450q-117 -59 -227 -59h-30q-205 0 -382 193q-108 153 -108 316q0 248 219 416q140 93 290 93zM193 520v-18q0 -204 197 -316 q71 -37 152 -37h22q211 0 323 219q26 69 26 134v18q0 170 -156 286q-91 63 -208 63q-231 0 -338 -241q-18 -59 -18 -108z" />
-<glyph unicode="&#x14e;" horiz-adv-x="1563" d="M557 1836h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM758 1435q363 0 607 -336q110 -191 110 -385q0 -359 -325 -597q-184 -117 -385 -117h-15q-370 0 -604 344 q-106 174 -106 377q0 343 302 578q196 136 416 136zM187 710q0 -274 242 -461q151 -102 321 -102h19q268 0 453 238q106 153 106 333q0 309 -283 490q-140 80 -287 80q-283 0 -469 -246q-102 -147 -102 -332z" />
-<glyph unicode="&#x14f;" horiz-adv-x="1127" d="M341 1436h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM549 1018q197 0 357 -149q152 -160 152 -360q0 -286 -271 -450q-117 -59 -227 -59h-30q-205 0 -382 193 q-108 153 -108 316q0 248 219 416q140 93 290 93zM189 520v-18q0 -204 197 -316q71 -37 152 -37h22q211 0 323 219q26 69 26 134v18q0 170 -156 286q-91 63 -208 63q-231 0 -338 -241q-18 -59 -18 -108z" />
-<glyph unicode="&#x150;" horiz-adv-x="1580" d="M567 1843h4q76 -13 76 -72v-20q0 -21 -168 -240q-18 -20 -36 -20h-8q-33 0 -44 44v8q105 263 128 284q27 16 48 16zM815 1831q80 -16 80 -80q0 -32 -108 -168q-67 -104 -96 -104h-12q-33 0 -44 44q0 17 112 272q35 36 68 36zM749 1435q363 0 607 -336q110 -191 110 -385 q0 -359 -325 -597q-184 -117 -385 -117h-15q-370 0 -604 344q-106 174 -106 377q0 343 302 578q196 136 416 136zM178 710q0 -274 242 -461q151 -102 321 -102h19q268 0 453 238q106 153 106 333q0 309 -283 490q-140 80 -287 80q-283 0 -469 -246q-102 -147 -102 -332z" />
-<glyph unicode="&#x151;" horiz-adv-x="1135" d="M430 1469h4q76 -13 76 -72v-20q0 -21 -168 -240q-18 -20 -36 -20h-8q-33 0 -44 44v8q105 263 128 284q27 16 48 16zM678 1457q80 -16 80 -80q0 -32 -108 -168q-67 -104 -96 -104h-12q-33 0 -44 44q0 17 112 272q35 36 68 36zM544 1018q197 0 357 -149q152 -160 152 -360 q0 -286 -271 -450q-117 -59 -227 -59h-30q-205 0 -382 193q-108 153 -108 316q0 248 219 416q140 93 290 93zM184 520v-18q0 -204 197 -316q71 -37 152 -37h22q211 0 323 219q26 69 26 134v18q0 170 -156 286q-91 63 -208 63q-231 0 -338 -241q-18 -59 -18 -108z" />
-<glyph unicode="&#x152;" horiz-adv-x="2157" d="M204 710q0 -274 199 -461q123 -102 262 -102h16q219 0 371 238q87 153 87 333q0 309 -232 490q-115 80 -235 80q-232 0 -384 -246q-84 -147 -84 -332zM1141 289q-59 -93 -148 -172q-151 -117 -315 -117h-13q-303 0 -494 344q-87 174 -87 377q0 343 247 578 q161 136 341 136q277 0 469 -291v222q11 72 72 72v4l19 -4h744l15 4q65 0 76 -83q-15 -69 -83 -69h-695v-512h455l54 4q51 0 68 -76q0 -50 -61 -76l-76 4h-440v-486h713q53 0 65 -80q-20 -68 -68 -68h-786q-72 13 -72 72v217z" />
-<glyph unicode="&#x153;" horiz-adv-x="2025" d="M193 525v-18q0 -204 197 -316q71 -37 152 -37h22q211 0 323 219q26 69 26 134v18q0 170 -156 286q-91 63 -208 63q-231 0 -338 -241q-18 -59 -18 -108zM1069 551h704q0 75 -88 194q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136zM990 251q-68 -108 -199 -187 q-117 -59 -227 -59h-30q-205 0 -382 193q-108 153 -108 316q0 248 219 416q140 93 290 93q197 0 357 -149q49 -51 82 -106q64 102 187 179q127 62 238 62q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55h22 q66 -13 66 -66v-11q0 -91 -264 -125h-26q-266 0 -427 246z" />
-<glyph unicode="&#x154;" horiz-adv-x="986" d="M551 1859q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM99 1435h315q201 0 329 -212q41 -82 41 -171v-15q0 -198 -193 -325l-37 -19q344 -593 344 -606v-19q0 -56 -72 -68h-4q-54 0 -113 129l-311 530h-215v-591 q0 -56 -72 -68h-4q-58 0 -72 76v1275q9 84 64 84zM183 1291v-485h215q179 0 235 193l4 31v30q0 142 -159 216q-45 15 -140 15h-155z" />
-<glyph unicode="&#x155;" horiz-adv-x="928" d="M573 1507q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM143 1031q72 -18 72 -64v-83q165 147 353 147q101 0 215 -49q30 -31 30 -60v-4q-12 -71 -71 -71h-4q-103 33 -155 33h-22q-221 0 -324 -229 q-22 -61 -22 -139v-444q0 -56 -72 -68h-4q-57 0 -71 75v869q9 87 75 87z" />
-<glyph unicode="&#x156;" horiz-adv-x="995" d="M104 1435h315q201 0 329 -212q41 -82 41 -171v-15q0 -198 -193 -325l-37 -19q344 -593 344 -606v-19q0 -56 -72 -68h-4q-54 0 -113 129l-311 530h-215v-591q0 -56 -72 -68h-4q-58 0 -72 76v1275q9 84 64 84zM188 1291v-485h215q179 0 235 193l4 31v30q0 142 -159 216 q-45 15 -140 15h-155zM544 81q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53q0 58 41.5 73.5t94.5 -11.5z" />
-<glyph unicode="&#x157;" horiz-adv-x="854" d="M95 1031q72 -18 72 -64v-83q165 147 353 147q101 0 215 -49q30 -31 30 -60v-4q-12 -71 -71 -71h-4q-103 33 -155 33h-22q-221 0 -324 -229q-22 -61 -22 -139v-444q0 -56 -72 -68h-4q-57 0 -71 75v869q9 87 75 87zM381 76q104 -69 104 -170q0 -146 -170 -188l-49 3h-52 l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53q0 58 41.5 73.5t94.5 -11.5z" />
-<glyph unicode="&#x158;" horiz-adv-x="1003" d="M216 1831h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM99 1435h315q201 0 329 -212q41 -82 41 -171v-15q0 -198 -193 -325l-37 -19q344 -593 344 -606v-19 q0 -56 -72 -68h-4q-54 0 -113 129l-311 530h-215v-591q0 -56 -72 -68h-4q-58 0 -72 76v1275q9 84 64 84zM183 1291v-485h215q179 0 235 193l4 31v30q0 142 -159 216q-45 15 -140 15h-155z" />
-<glyph unicode="&#x159;" horiz-adv-x="885" d="M261 1431h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM113 1031q72 -18 72 -64v-83q165 147 353 147q101 0 215 -49q30 -31 30 -60v-4q-12 -71 -71 -71h-4 q-103 33 -155 33h-22q-221 0 -324 -229q-22 -61 -22 -139v-444q0 -56 -72 -68h-4q-57 0 -71 75v869q9 87 75 87z" />
-<glyph unicode="&#x15a;" horiz-adv-x="929" d="M587 1863q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM482 1437q186 0 310 -168l4 -16v-23q0 -49 -73 -61q-30 0 -103 81q-66 42 -126 42h-23q-126 0 -191 -134q-15 -32 -15 -65v-31q0 -145 175 -210 q126 0 272 -118q141 -143 141 -314q0 -210 -180 -344q-110 -76 -244 -76q-217 0 -359 187l-8 31q13 72 73 72q40 0 103 -80q94 -65 172 -65h34q152 0 245 172q15 56 15 84v38q0 151 -172 245l-195 54q-218 125 -218 328v27q0 200 214 313q80 31 149 31z" />
-<glyph unicode="&#x15b;" horiz-adv-x="980" d="M582 1444q68 0 80 -88q0 -40 -184 -204q-68 -84 -108 -84h-12q-72 14 -72 72v16q0 34 140 160q113 128 156 128zM485 1017q257 0 404 -233l3 -29v-4q0 -59 -74 -70q-49 0 -100 85q-103 100 -233 100q-171 0 -270 -163l-3 -19q0 -49 111 -59q426 -103 466 -118 q107 -70 107 -178v-3q0 -154 -226 -282q-97 -44 -207 -44q-225 0 -381 211q-15 22 -15 41v22q0 54 82 63q35 0 100 -93q99 -92 229 -92q156 0 259 148l7 22v4q0 48 -66 55q-497 111 -526 137q-92 70 -92 170q0 140 203 270q112 59 222 59z" />
-<glyph unicode="&#x15c;" horiz-adv-x="885" d="M435 1805h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM460 1437q186 0 310 -168l4 -16v-23q0 -49 -73 -61q-30 0 -103 81q-66 42 -126 42h-23q-126 0 -191 -134 q-15 -32 -15 -65v-31q0 -145 175 -210q126 0 272 -118q141 -143 141 -314q0 -210 -180 -344q-110 -76 -244 -76q-217 0 -359 187l-8 31q13 72 73 72q40 0 103 -80q94 -65 172 -65h34q152 0 245 172q15 56 15 84v38q0 151 -172 245l-195 54q-218 125 -218 328v27 q0 200 214 313q80 31 149 31z" />
-<glyph unicode="&#x15d;" horiz-adv-x="969" d="M474 1391h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM485 1017q257 0 404 -233l3 -29v-4q0 -59 -74 -70q-49 0 -100 85q-103 100 -233 100q-171 0 -270 -163 l-3 -19q0 -49 111 -59q426 -103 466 -118q107 -70 107 -178v-3q0 -154 -226 -282q-97 -44 -207 -44q-225 0 -381 211q-15 22 -15 41v22q0 54 82 63q35 0 100 -93q99 -92 229 -92q156 0 259 148l7 22v4q0 48 -66 55q-497 111 -526 137q-92 70 -92 170q0 140 203 270 q112 59 222 59z" />
-<glyph unicode="&#x15e;" horiz-adv-x="903" d="M359 2q-185 19 -311 185l-8 31q13 72 73 72q40 0 103 -80q94 -65 172 -65h34q152 0 245 172q15 56 15 84v38q0 151 -172 245l-195 54q-218 125 -218 328v27q0 200 214 313q80 31 149 31q186 0 310 -168l4 -16v-23q0 -49 -73 -61q-30 0 -103 81q-66 42 -126 42h-23 q-126 0 -191 -134q-15 -32 -15 -65v-31q0 -145 175 -210q126 0 272 -118q141 -143 141 -314q0 -210 -180 -344q-73 -50 -156 -67v-38q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53v93z " />
-<glyph unicode="&#x15f;" horiz-adv-x="978" d="M553 7v-45q104 -69 104 -170q0 -146 -170 -188l-49 3h-52l-56 -3q-59 20 -59 59v14q12 63 63 63h121q66 0 66 52v3q0 40 -62 52q-42 20 -42 53v103q-193 21 -331 208q-15 22 -15 41v22q0 54 82 63q35 0 100 -93q99 -92 229 -92q156 0 259 148l7 22v4q0 48 -66 55 q-497 111 -526 137q-92 70 -92 170q0 140 203 270q112 59 222 59q257 0 404 -233l3 -29v-4q0 -59 -74 -70q-49 0 -100 85q-103 100 -233 100q-171 0 -270 -163l-3 -19q0 -49 111 -59q426 -103 466 -118q107 -70 107 -178v-3q0 -154 -226 -282q-58 -26 -121 -37z" />
-<glyph unicode="&#x160;" horiz-adv-x="924" d="M309 1822h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM455 1437q186 0 310 -168l4 -16v-23q0 -49 -73 -61q-30 0 -103 81q-66 42 -126 42h-23q-126 0 -191 -134 q-15 -32 -15 -65v-31q0 -145 175 -210q126 0 272 -118q141 -143 141 -314q0 -210 -180 -344q-110 -76 -244 -76q-217 0 -359 187l-8 31q13 72 73 72q40 0 103 -80q94 -65 172 -65h34q152 0 245 172q15 56 15 84v38q0 151 -172 245l-195 54q-218 125 -218 328v27 q0 200 214 313q80 31 149 31z" />
-<glyph unicode="&#x161;" horiz-adv-x="977" d="M340 1444h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM476 1017q257 0 404 -233l3 -29v-4q0 -59 -74 -70q-49 0 -100 85q-103 100 -233 100q-171 0 -270 -163l-3 -19 q0 -49 111 -59q426 -103 466 -118q107 -70 107 -178v-3q0 -154 -226 -282q-97 -44 -207 -44q-225 0 -381 211q-15 22 -15 41v22q0 54 82 63q35 0 100 -93q99 -92 229 -92q156 0 259 148l7 22v4q0 48 -66 55q-497 111 -526 137q-92 70 -92 170q0 140 203 270q112 59 222 59z " />
-<glyph unicode="&#x162;" horiz-adv-x="1219" d="M108 1436h933q68 -13 68 -68v-15q0 -55 -83 -64h-376v-1221q0 -56 -72 -68h-3q-58 0 -72 76v1213h-383q-76 15 -76 75q16 72 64 72zM533 -73h28q83 0 112 -143v-12q0 -78 -144 -150q-29 -10 -44 -10q-18 4 -28 15v7q60 87 60 143v7q0 38 -48 87v12q15 44 64 44z" />
-<glyph unicode="&#x163;" horiz-adv-x="730" d="M292 1390h14q66 -14 66 -59v-330h151l33 4q51 0 69 -74q0 -50 -62 -73l-55 4h-136v-539q0 -141 92 -173l84 -7h41q48 0 62 -70v-3q-12 -70 -70 -70h-77q-175 0 -260 191q-15 47 -15 110v561h-73l-59 -4q-62 22 -62 73q12 70 66 70v4l37 -4h91v308q9 81 63 81zM392 -47h28 q83 0 112 -143v-12q0 -78 -144 -150q-29 -10 -44 -10q-18 4 -28 15v7q60 87 60 143v7q0 38 -48 87v12q15 44 64 44z" />
-<glyph unicode="&#x164;" horiz-adv-x="1224" d="M446 1836h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM117 1436h933q68 -13 68 -68v-15q0 -55 -83 -64h-376v-1221q0 -56 -72 -68h-3q-58 0 -72 76v1213h-383 q-76 15 -76 75q16 72 64 72z" />
-<glyph unicode="&#x165;" horiz-adv-x="757" d="M195 1800h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM319 1390h14q66 -14 66 -59v-330h151l33 4q51 0 69 -74q0 -50 -62 -73l-55 4h-136v-539q0 -141 92 -173l84 -7 h41q48 0 62 -70v-3q-12 -70 -70 -70h-77q-175 0 -260 191q-15 47 -15 110v561h-73l-59 -4q-62 22 -62 73q12 70 66 70v4l37 -4h91v308q9 81 63 81z" />
-<glyph unicode="&#x166;" horiz-adv-x="1197" d="M507 641h-285l-64 -4q-68 24 -68 80q13 76 72 76v4l40 -4h305v496h-383q-76 15 -76 75q16 72 64 72h933q68 -13 68 -68v-15q0 -55 -83 -64h-376v-496h268l36 4q59 0 76 -80q0 -52 -64 -80l-68 4h-248v-573q0 -56 -72 -68h-3q-58 0 -72 76v565z" />
-<glyph unicode="&#x167;" horiz-adv-x="748" d="M242 618v244h-73l-59 -4q-62 22 -62 73q12 70 66 70v4l37 -4h91v308q9 81 63 81h14q66 -14 66 -59v-330h151l33 4q51 0 69 -74q0 -50 -62 -73l-55 4h-136v-244h148l34 4q52 0 71 -80q0 -55 -64 -80l-56 4h-133v-143q0 -141 92 -173l84 -7h41q48 0 62 -70v-3 q-12 -70 -70 -70h-77q-175 0 -260 191q-15 47 -15 110v165h-66l-60 -4q-64 24 -64 80q12 76 68 76v4l37 -4h85z" />
-<glyph unicode="&#x168;" horiz-adv-x="1219" d="M130 1433h15q68 -14 68 -60v-806q0 -260 148 -348q93 -72 208 -72q221 0 333 227q23 71 23 148v840q12 71 68 71h11q68 -13 68 -68v-881q0 -225 -216 -393q-136 -91 -276 -91h-26q-235 0 -409 231q-79 124 -79 306v813q9 83 64 83zM461 1715h19q70 0 162 -63l29 -7h18 l74 22q74 -15 74 -74q0 -74 -140 -92h-26q-69 0 -162 63l-29 7h-19l-70 -18h-7q-66 13 -66 66v11q0 55 81 74q29 11 62 11z" />
-<glyph unicode="&#x169;" horiz-adv-x="1131" d="M421 1314h19q70 0 162 -63l29 -7h18l74 22q74 -15 74 -74q0 -74 -140 -92h-26q-69 0 -162 63l-29 7h-19l-70 -18h-7q-66 13 -66 66v11q0 55 81 74q29 11 62 11zM117 1002q70 -18 70 -63v-391q0 -251 142 -336q90 -69 201 -69q214 0 322 219q22 71 22 142v424q14 74 73 74 q69 -17 69 -70v-870q0 -48 -69 -62h-4q-69 12 -69 69v70h-4q-153 -139 -329 -139h-25q-227 0 -395 223q-77 120 -77 296v398q8 85 73 85z" />
-<glyph unicode="&#x16a;" horiz-adv-x="1135" d="M99 1433h15q68 -14 68 -60v-806q0 -260 148 -348q93 -72 208 -72q221 0 333 227q23 71 23 148v840q12 71 68 71h11q68 -13 68 -68v-881q0 -225 -216 -393q-136 -91 -276 -91h-26q-235 0 -409 231q-79 124 -79 306v813q9 83 64 83zM208 1712l33 -4h606l30 4q50 0 64 -80 q0 -52 -54 -80l-57 4h-572l-54 -4q-57 24 -57 80q11 76 61 76v4z" />
-<glyph unicode="&#x16b;" horiz-adv-x="1135" d="M108 1002q70 -18 70 -63v-391q0 -251 142 -336q90 -69 201 -69q214 0 322 219q22 71 22 142v424q14 74 73 74q69 -17 69 -70v-870q0 -48 -69 -62h-4q-69 12 -69 69v70h-4q-153 -139 -329 -139h-25q-227 0 -395 223q-77 120 -77 296v398q8 85 73 85zM252 1299l521 1 q80 -14 80 -71v-12q-9 -70 -76 -70h-538q-64 0 -71 82q13 70 84 70z" />
-<glyph unicode="&#x16c;" horiz-adv-x="1149" d="M341 1800h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM99 1433h15q68 -14 68 -60v-806q0 -260 148 -348q93 -72 208 -72q221 0 333 227q23 71 23 148v840 q12 71 68 71h11q68 -13 68 -68v-881q0 -225 -216 -393q-136 -91 -276 -91h-26q-235 0 -409 231q-79 124 -79 306v813q9 83 64 83z" />
-<glyph unicode="&#x16d;" horiz-adv-x="1171" d="M328 1396h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72zM135 1002q70 -18 70 -63v-391q0 -251 142 -336q90 -69 201 -69q214 0 322 219q22 71 22 142v424 q14 74 73 74q69 -17 69 -70v-870q0 -48 -69 -62h-4q-69 12 -69 69v70h-4q-153 -139 -329 -139h-25q-227 0 -395 223q-77 120 -77 296v398q8 85 73 85z" />
-<glyph unicode="&#x16e;" horiz-adv-x="1127" d="M95 1433h15q68 -14 68 -60v-806q0 -260 148 -348q93 -72 208 -72q221 0 333 227q23 71 23 148v840q12 71 68 71h11q68 -13 68 -68v-881q0 -225 -216 -393q-136 -91 -276 -91h-26q-235 0 -409 231q-79 124 -79 306v813q9 83 64 83zM542 1832h15q121 0 174 -147l4 -38v-11 q0 -118 -140 -174l-45 -8q-113 0 -174 114q-19 41 -19 79q0 127 148 181zM474 1643q13 -71 72 -71q72 12 72 68v11q-11 64 -64 64h-12q-57 0 -68 -72z" />
-<glyph unicode="&#x16f;" horiz-adv-x="1180" d="M135 1002q70 -18 70 -63v-391q0 -251 142 -336q90 -69 201 -69q214 0 322 219q22 71 22 142v424q14 74 73 74q69 -17 69 -70v-870q0 -48 -69 -62h-4q-69 12 -69 69v70h-4q-153 -139 -329 -139h-25q-227 0 -395 223q-77 120 -77 296v398q8 85 73 85zM547 1405h15 q121 0 174 -147l4 -38v-11q0 -118 -140 -174l-45 -8q-113 0 -174 114q-19 41 -19 79q0 127 148 181zM479 1216q13 -71 72 -71q72 12 72 68v11q-11 64 -64 64h-12q-57 0 -68 -72z" />
-<glyph unicode="&#x170;" horiz-adv-x="1175" d="M555 1834h4q76 -13 76 -72v-20q0 -21 -168 -240q-18 -20 -36 -20h-8q-33 0 -44 44v8q105 263 128 284q27 16 48 16zM803 1822q80 -16 80 -80q0 -32 -108 -168q-67 -104 -96 -104h-12q-33 0 -44 44q0 17 112 272q35 36 68 36zM121 1433h15q68 -14 68 -60v-806 q0 -260 148 -348q93 -72 208 -72q221 0 333 227q23 71 23 148v840q12 71 68 71h11q68 -13 68 -68v-881q0 -225 -216 -393q-136 -91 -276 -91h-26q-235 0 -409 231q-79 124 -79 306v813q9 83 64 83z" />
-<glyph unicode="&#x171;" horiz-adv-x="1144" d="M515 1403h4q76 -13 76 -72v-20q0 -21 -168 -240q-18 -20 -36 -20h-8q-33 0 -44 44v8q105 263 128 284q27 16 48 16zM763 1391q80 -16 80 -80q0 -32 -108 -168q-67 -104 -96 -104h-12q-33 0 -44 44q0 17 112 272q35 36 68 36zM117 1002q70 -18 70 -63v-391 q0 -251 142 -336q90 -69 201 -69q214 0 322 219q22 71 22 142v424q14 74 73 74q69 -17 69 -70v-870q0 -48 -69 -62h-4q-69 12 -69 69v70h-4q-153 -139 -329 -139h-25q-227 0 -395 223q-77 120 -77 296v398q8 85 73 85z" />
-<glyph unicode="&#x172;" horiz-adv-x="1202" d="M496 3q-201 24 -355 228q-79 124 -79 306v813q9 83 64 83h15q68 -14 68 -60v-806q0 -260 148 -348q93 -72 208 -72q221 0 333 227q23 71 23 148v840q12 71 68 71h11q68 -13 68 -68v-881q0 -225 -216 -393q-107 -71 -216 -87v-95q0 -58 -81 -70q-25 -18 -25 -46 q0 -53 67 -53h102l15 4q70 -16 70 -67v-7q0 -46 -56 -67l-74 4h-36l-56 -4q-71 0 -144 92q-25 48 -25 84v28q0 96 106 155v4z" />
-<glyph unicode="&#x173;" horiz-adv-x="1211" d="M1025 69q2 -6 3 -13v-103q0 -58 -81 -70q-25 -18 -25 -46q0 -53 67 -53h102l15 4q70 -16 70 -67v-7q0 -46 -56 -67l-74 4h-36l-56 -4q-71 0 -144 92q-25 48 -25 84v28q0 96 106 155v4l-2 30q-6 12 -6 29v70h-4q-153 -139 -329 -139h-25q-227 0 -395 223q-77 120 -77 296 v398q8 85 73 85q70 -18 70 -63v-391q0 -251 142 -336q90 -69 201 -69q214 0 322 219q22 71 22 142v424q14 74 73 74q69 -17 69 -70v-863z" />
-<glyph unicode="&#x174;" horiz-adv-x="1778" d="M861 1840h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM112 1436h16q64 0 83 -114l280 -973h8q292 1031 311 1061q25 26 53 26h11q67 0 87 -136q27 -74 277 -955h4 l307 1057q27 34 53 34h15q68 -14 68 -60v-19l-383 -1327q-31 -30 -60 -30h-4q-71 0 -91 140q-246 836 -277 959h-3l-307 -1065q-28 -34 -61 -34h-15q-62 0 -84 144q-325 1106 -352 1220q16 72 64 72z" />
-<glyph unicode="&#x175;" horiz-adv-x="1422" d="M667 1369h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM118 1009q68 0 95 -148l181 -555h3q207 659 221 677q26 22 56 26q66 0 88 -122l188 -581h3q199 631 217 670 q31 33 59 33q74 -15 74 -74l-291 -906q-31 -29 -59 -29h-3q-68 0 -96 144q-177 536 -177 552h-7l-214 -663q-25 -33 -59 -33h-3q-52 0 -74 66l-276 869q15 74 74 74z" />
-<glyph unicode="&#x176;" horiz-adv-x="1167" d="M536 1792h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM104 1433h16q49 0 79 -72l345 -516h4q372 562 387 573q20 15 34 15h23q46 0 64 -72q0 -32 -129 -209 l-307 -458v-611q-9 -83 -64 -83h-16q-49 0 -68 61v621q0 14 -159 251l-269 405l-4 23q16 72 64 72z" />
-<glyph unicode="&#x177;" horiz-adv-x="964" d="M475 1395h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60zM808 1012q69 -13 69 -66v-4q-3 -25 -345 -840q-161 -401 -181 -426q-18 -14 -45 -21q-70 15 -70 60v17 q0 13 157 391v3l-332 810v3q14 69 70 69q59 0 101 -138q227 -538 234 -566h3q274 669 290 687q25 21 49 21z" />
-<glyph unicode="&#x178;" horiz-adv-x="1149" d="M104 1433h16q49 0 79 -72l345 -516h4q372 562 387 573q20 15 34 15h23q46 0 64 -72q0 -32 -129 -209l-307 -458v-611q-9 -83 -64 -83h-16q-49 0 -68 61v621q0 14 -159 251l-269 405l-4 23q16 72 64 72zM395 1687h15q68 -14 68 -60v-19q0 -55 -72 -68q-75 15 -75 76 q16 71 64 71zM685 1687h11q68 -15 68 -64v-11q0 -60 -75 -72q-72 14 -72 72v11q0 49 68 64z" />
-<glyph unicode="&#x179;" horiz-adv-x="1272" d="M701 1807q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM95 1437h1021q55 0 68 -72v-3q0 -29 -83 -126l-842 -1088h853q72 -11 72 -72v-4q-13 -72 -72 -72h-1009q-60 0 -72 80q0 28 182 254l740 956h-846 q-76 15 -76 75q16 72 64 72z" />
-<glyph unicode="&#x17a;" horiz-adv-x="973" d="M568 1389q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM110 1012l37 -4h639l34 4q66 -20 66 -63v-22q0 -23 -85 -115l-532 -668h551q66 -13 66 -66v-12q0 -54 -70 -66h-702q-59 0 -70 78q0 29 151 203l466 587h-495 l-59 -4q-63 22 -63 74q12 70 66 70v4z" />
-<glyph unicode="&#x17b;" horiz-adv-x="1325" d="M640 1797q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6zM108 1437h1021q55 0 68 -72v-3q0 -29 -83 -126l-842 -1088h853q72 -11 72 -72v-4q-13 -72 -72 -72h-1009q-60 0 -72 80q0 28 182 254l740 956h-846q-76 15 -76 75 q16 72 64 72z" />
-<glyph unicode="&#x17c;" horiz-adv-x="1004" d="M482 1357q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6zM106 1012l37 -4h639l34 4q66 -20 66 -63v-22q0 -23 -85 -115l-532 -668h551q66 -13 66 -66v-12q0 -54 -70 -66h-702q-59 0 -70 78q0 29 151 203l466 587h-495l-59 -4 q-63 22 -63 74q12 70 66 70v4z" />
-<glyph unicode="&#x17d;" horiz-adv-x="1294" d="M494 1836h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM112 1437h1021q55 0 68 -72v-3q0 -29 -83 -126l-842 -1088h853q72 -11 72 -72v-4q-13 -72 -72 -72h-1009 q-60 0 -72 80q0 28 182 254l740 956h-846q-76 15 -76 75q16 72 64 72z" />
-<glyph unicode="&#x17e;" horiz-adv-x="978" d="M349 1458h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72zM106 1012l37 -4h639l34 4q66 -20 66 -63v-22q0 -23 -85 -115l-532 -668h551q66 -13 66 -66v-12q0 -54 -70 -66 h-702q-59 0 -70 78q0 29 151 203l466 587h-495l-59 -4q-63 22 -63 74q12 70 66 70v4z" />
-<glyph unicode="&#x17f;" horiz-adv-x="616" d="M385 1437h91q52 0 64 -80q0 -51 -76 -68h-57q-138 0 -182 -152l-3 -79v-53v-145v-750l3 -42q0 -51 -75 -68q-52 0 -76 64l4 46v750l-4 145v68q0 254 223 348z" />
-<glyph unicode="&#x192;" horiz-adv-x="973" d="M704 1424h96q56 0 68 -84q0 -54 -80 -72h-60q-146 0 -192 -160l-4 -84v-56h172l64 4q51 0 68 -76v-12q0 -50 -72 -68h-232v-760l4 -96q-15 -106 -80 -192q-118 -124 -256 -124h-84q-59 0 -72 76q12 80 76 80h52q136 0 192 120q16 41 16 136v760h-208q-56 0 -68 84 q0 40 64 72l80 -4h128v72q0 269 236 368z" />
-<glyph unicode="&#x1fa;" horiz-adv-x="1266" d="M545 1467q11 -61 62 -61q62 10 62 58v10q-9 55 -55 55h-10q-50 0 -59 -62zM603 1096l-159 -410h325v3l-162 407h-4zM673 1322q19 -32 32 -85q457 -1135 461 -1162v-10q0 -54 -72 -65h-4q-66 0 -94 122l-170 422h-442l-208 -522q-30 -22 -53 -22h-7q-72 12 -72 69v4 l128 331q319 791 363 918q-45 24 -75 80q-16 36 -16 68q0 86 78 133q-20 15 -29 55v6q0 30 102 145q34 47 66 47q66 -15 66 -63v-6q0 -28 -73 -109q-19 -29 -37 -48q104 -1 150 -127l3 -33v-9q0 -91 -97 -139z" />
-<glyph unicode="&#x1fb;" horiz-adv-x="1171" d="M638 1798q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM557 1447q105 0 165 -110q18 -39 18 -77q0 -123 -143 -175l-37 -4h-14q-118 0 -169 143l-4 36v11q0 124 151 173zM487 1268v-15q17 -58 59 -58h14q56 0 66 69 q-12 70 -69 70q-70 -12 -70 -66zM542 1004q285 0 451 -278q51 -114 51 -235v-425q0 -54 -70 -66h-3q-48 0 -70 55v4l4 91v4q-162 -154 -348 -154h-30q-255 0 -425 256q-62 124 -62 250q0 280 275 443q117 55 227 55zM183 509v-11q0 -218 220 -329q69 -26 124 -26h30 q182 0 300 183q44 86 44 165v15q0 210 -209 322q-72 33 -150 33h-4q-221 0 -333 -231q-22 -71 -22 -121z" />
-<glyph unicode="&#x1fc;" horiz-adv-x="1615" d="M1029 1830q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM837 1435h595q46 0 64 -72q-15 -75 -76 -75h-500v-568h390q69 -15 69 -61v-19q0 -56 -72 -68h-387v-424h504q58 0 72 -76q0 -56 -76 -72h-575q-58 0 -72 76 v496h-277q-20 -24 -166 -296l-144 -253q-27 -23 -53 -23h-4q-60 0 -72 80q0 22 242 446l493 886q28 23 45 23zM576 720h197v352z" />
-<glyph unicode="&#x1fd;" horiz-adv-x="2042" d="M1082 1363q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM544 1004q263 0 431 -245h4q90 155 277 219q84 22 150 22q279 0 442 -270q54 -113 54 -212v-47q-12 -69 -69 -69h-767v-4q37 -121 139 -190q95 -62 197 -62 q88 0 197 55l19 3q73 -17 73 -73q0 -93 -241 -127l-52 -4q-192 0 -354 150v-81q0 -62 -76 -69h-4q-38 0 -62 58l4 88v11q-161 -153 -347 -153h-29q-255 0 -424 255q-62 123 -62 248q0 280 274 442q117 55 226 55zM186 511v-11q0 -217 219 -328q70 -26 125 -26h29 q181 0 299 183q44 85 44 164v14q0 210 -208 322q-72 33 -150 33h-3q-221 0 -333 -230q-22 -72 -22 -121zM1055 544h698v4q0 96 -117 219q-112 87 -234 87q-187 0 -303 -175q-44 -82 -44 -135z" />
-<glyph unicode="&#x1fe;" horiz-adv-x="1655" d="M876 1825q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM775 1426q267 0 492 -198q149 153 180 153h8q71 -18 71 -71v-7q0 -42 -105 -124l-60 -60q127 -195 127 -410q0 -356 -322 -593q-184 -116 -383 -116h-15 q-232 0 -436 154h-3q-154 -150 -173 -150l-19 -4h-4q-59 0 -71 79q0 36 124 139q4 11 41 37q-165 210 -165 462q0 340 300 574q196 135 413 135zM208 706q0 -195 128 -349l822 773v4q-179 146 -383 146q-281 0 -465 -244q-102 -147 -102 -330zM437 255q156 -109 331 -109h18 q267 0 451 237q105 151 105 330q0 152 -86 304h-4z" />
-<glyph unicode="&#x1ff;" horiz-adv-x="1188" d="M650 1412q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM961 1012h4q58 0 69 -77q0 -29 -102 -127q113 -138 113 -309q0 -281 -266 -441q-114 -58 -222 -58h-29q-137 0 -284 102q-81 -98 -120 -98h-14q-51 0 -62 76 q0 30 98 124q-98 135 -98 295q0 242 215 407q137 91 284 91q146 0 283 -91q86 106 131 106zM194 509v-18q0 -90 50 -182h4l477 492q-72 50 -182 50q-227 0 -331 -236q-18 -58 -18 -106zM830 706l-484 -502q94 -58 190 -58h21q207 0 317 214q25 68 25 131v18q0 108 -69 197z " />
-<glyph unicode="&#x2c6;" horiz-adv-x="1024" d="M513 1431h28q48 0 136 -128q64 -64 64 -100v-12q-15 -72 -72 -72h-12q-45 0 -128 120h-4q-83 -120 -128 -120h-12q-72 15 -72 72v12q0 38 120 168q38 60 80 60z" />
-<glyph unicode="&#x2c7;" horiz-adv-x="1024" d="M358 1430h12q45 0 128 -120h4q83 120 128 120h12q72 -15 72 -72v-12q0 -35 -96 -140q-60 -88 -104 -88h-28q-47 0 -132 124q-68 68 -68 104v12q15 72 72 72z" />
-<glyph unicode="&#x2c9;" horiz-adv-x="1059" d="M309 1322l40 -4h400l36 4q56 0 76 -80q0 -55 -68 -80l-60 4h-364l-64 -4q-68 24 -68 80q13 76 72 76v4z" />
-<glyph unicode="&#x2d8;" horiz-adv-x="1024" d="M301 1365h12q52 0 84 -84q52 -60 120 -60q102 0 148 112q30 32 60 32h8q76 -13 76 -76v-4q0 -82 -156 -192q-75 -28 -132 -28h-8q-192 0 -284 204v24q15 72 72 72z" />
-<glyph unicode="&#x2d9;" horiz-adv-x="1024" d="M539 1362q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6z" />
-<glyph unicode="&#x2da;" horiz-adv-x="1024" d="M517 1447q105 0 165 -110q18 -39 18 -77q0 -123 -143 -175l-37 -4h-14q-118 0 -169 143l-4 36v11q0 124 151 173zM447 1268v-15q17 -58 59 -58h14q56 0 66 69q-12 70 -69 70q-70 -12 -70 -66z" />
-<glyph unicode="&#x2db;" horiz-adv-x="1024" d="M500 47h7q54 0 67 -70v-103q0 -58 -81 -70q-25 -18 -25 -46q0 -53 67 -53h102l15 4q70 -16 70 -67v-7q0 -46 -56 -67l-74 4h-36l-56 -4q-71 0 -144 92q-25 48 -25 84v28q0 96 106 155v4l-4 56q21 60 67 60z" />
-<glyph unicode="&#x2dc;" horiz-adv-x="1024" d="M452 1695q79 0 189 -71l33 -4l76 23h7q72 -12 72 -72v-4q0 -70 -124 -90l-38 -4q-79 0 -181 72l-30 4l-83 -23q-75 14 -75 71v8q0 72 139 87z" />
-<glyph unicode="&#x2dd;" horiz-adv-x="1024" d="M440 1429h4q76 -13 76 -72v-20q0 -21 -168 -240q-18 -20 -36 -20h-8q-33 0 -44 44v8q105 263 128 284q27 16 48 16zM688 1417q80 -16 80 -80q0 -32 -108 -168q-67 -104 -96 -104h-12q-33 0 -44 44q0 17 112 272q35 36 68 36z" />
-<glyph unicode="&#x384;" horiz-adv-x="392" d="M281 1425q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52z" />
-<glyph unicode="&#x385;" horiz-adv-x="797" d="M474 1390q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM182 1309q80 -19 80 -80q-16 -80 -80 -80q-80 16 -80 80q19 80 80 80zM634 1309q80 -19 80 -80q-16 -80 -80 -80q-80 16 -80 80q19 80 80 80z" />
-<glyph unicode="&#x386;" horiz-adv-x="1254" d="M369 1521q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM591 1428q69 0 102 -139q454 -1182 458 -1210v-11q0 -56 -71 -68h-4q-66 0 -94 128l-169 439h-440l-206 -544q-30 -23 -53 -23h-8q-71 13 -71 71v4l128 346 q335 873 364 969q34 38 64 38zM591 1142l-158 -428h323v4l-161 424h-4z" />
-<glyph unicode="&#x387;" horiz-adv-x="405" d="M204 1002q90 0 116 -107v-21q0 -64 -82 -101q-12 -6 -34 -6h-3q-96 0 -116 119q0 76 86 110q12 6 33 6z" />
-<glyph unicode="&#x388;" horiz-adv-x="1347" d="M393 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4zM219 1460q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4 q-47 0 -62 70v7q0 33 113 161q38 52 74 52z" />
-<glyph unicode="&#x389;" horiz-adv-x="1466" d="M228 1425q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM390 1437h15q68 -14 68 -60v-598h712v587q12 71 68 71h11q68 -13 68 -68v-1301q0 -49 -72 -64h-4q-71 13 -71 72v560h-712v-564q0 -56 -71 -68h-4q-58 0 -72 76 v1274q9 83 64 83z" />
-<glyph unicode="&#x38a;" horiz-adv-x="748" d="M210 1452q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM392 1448l19 -3h142l15 3q76 -16 76 -76q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72h-180q-72 13 -72 72v4q15 73 65 73h23v1147h-16 q-63 0 -72 80v4q0 47 72 68z" />
-<glyph unicode="&#x38c;" horiz-adv-x="1734" d="M219 1448q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM912 1435q363 0 607 -336q110 -191 110 -385q0 -359 -325 -597q-184 -117 -385 -117h-15q-370 0 -604 344q-106 174 -106 377q0 343 302 578q196 136 416 136z M341 710q0 -274 242 -461q151 -102 321 -102h19q268 0 453 238q106 153 106 333q0 309 -283 490q-140 80 -287 80q-283 0 -469 -246q-102 -147 -102 -332z" />
-<glyph unicode="&#x38e;" horiz-adv-x="1457" d="M237 1443q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM439 1433h16q49 0 79 -72l345 -516h4q372 562 387 573q20 15 34 15h23q46 0 64 -72q0 -32 -129 -209l-307 -458v-611q-9 -83 -64 -83h-16q-49 0 -68 61v621 q0 14 -159 251l-269 405l-4 23q16 72 64 72z" />
-<glyph unicode="&#x38f;" horiz-adv-x="1646" d="M781 1437q367 0 613 -340q111 -198 111 -373q0 -339 -263 -568h-4v-4h164q73 -14 73 -64v-16q-15 -68 -69 -68h-492q-60 0 -72 80q19 68 69 68q106 0 289 157q160 187 160 407q0 272 -244 469q-162 103 -320 103h-30q-273 0 -461 -248q-103 -159 -103 -324 q0 -331 305 -514q52 -32 175 -61q46 -19 46 -72q-20 -69 -73 -69h-484q-76 15 -76 76q17 73 73 73h160v3q-93 70 -164 180q-107 186 -107 392q0 336 309 579q199 134 415 134zM204 1439q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161 q38 52 74 52z" />
-<glyph unicode="&#x390;" horiz-adv-x="740" d="M417 1777q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM125 1696q80 -19 80 -80q-16 -80 -80 -80q-80 16 -80 80q19 80 80 80zM577 1696q80 -19 80 -80q-16 -80 -80 -80q-80 16 -80 80q19 80 80 80zM269 1448l19 -3 h142l15 3q76 -16 76 -76q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72h-180q-72 13 -72 72v4q15 73 65 73h23v1147h-16q-63 0 -72 80v4q0 47 72 68z" />
-<glyph unicode="&#x391;" horiz-adv-x="1246" d="M591 1428q69 0 102 -139q454 -1182 458 -1210v-11q0 -56 -71 -68h-4q-66 0 -94 128l-169 439h-440l-206 -544q-30 -23 -53 -23h-8q-71 13 -71 71v4l128 346q335 873 364 969q34 38 64 38zM591 1142l-158 -428h323v4l-161 424h-4z" />
-<glyph unicode="&#x392;" horiz-adv-x="991" d="M125 1432l18 -3h230l15 3q172 0 294 -162q61 -90 61 -196v-11q0 -129 -102 -245q245 -135 245 -392q0 -258 -268 -396q-86 -30 -154 -30h-339q-72 13 -72 72v1285q11 72 72 72v3zM200 1282v-423h139q185 0 238 132q15 38 15 76v11q0 146 -170 200l-79 4h-143zM200 712 v-565h196q216 0 290 124q49 69 49 155v7q0 203 -222 272l-106 7h-207z" />
-<glyph unicode="&#x393;" horiz-adv-x="1030" d="M121 1433h730q68 -14 68 -60v-19q0 -56 -72 -68h-643v-1218q0 -56 -71 -68h-4q-58 0 -72 76v1274q9 83 64 83z" />
-<glyph unicode="&#x394;" horiz-adv-x="1242" d="M595 1432h12q59 0 87 -117q460 -1200 468 -1239v-4q0 -47 -57 -72l-83 4h-842l-80 -4q-60 22 -60 79l499 1323q28 30 56 30zM599 1148l-378 -997h760q-374 995 -382 997z" />
-<glyph unicode="&#x395;" horiz-adv-x="1109" d="M129 1436l19 -4h740l15 4q65 0 76 -83q-15 -68 -83 -68h-692v-510h454l53 3q51 0 68 -75q0 -49 -61 -76l-75 4h-439v-484h711q52 0 64 -79q-20 -68 -68 -68h-782q-72 13 -72 72v1288q11 72 72 72v4z" />
-<glyph unicode="&#x396;" horiz-adv-x="1342" d="M147 1437h1021q55 0 68 -72v-3q0 -29 -83 -126l-842 -1088h853q72 -11 72 -72v-4q-13 -72 -72 -72h-1009q-60 0 -72 80q0 28 182 254l740 956h-846q-76 15 -76 75q16 72 64 72z" />
-<glyph unicode="&#x397;" horiz-adv-x="1223" d="M139 1437h15q68 -14 68 -60v-598h712v587q12 71 68 71h11q68 -13 68 -68v-1301q0 -49 -72 -64h-4q-71 13 -71 72v560h-712v-564q0 -56 -71 -68h-4q-58 0 -72 76v1274q9 83 64 83z" />
-<glyph unicode="&#x398;" horiz-adv-x="1611" d="M786 1431q362 0 606 -335q109 -190 109 -384q0 -358 -324 -595q-184 -117 -384 -117h-15q-368 0 -603 343q-105 174 -105 376q0 342 301 576q196 136 415 136zM217 708q0 -274 241 -459q150 -102 320 -102h19q267 0 452 237q105 152 105 332q0 308 -282 489 q-139 79 -286 79q-283 0 -467 -245q-102 -147 -102 -331zM428 787h715q72 -13 72 -71v-4q-13 -72 -72 -72h-719q-68 15 -68 68v15q0 49 72 64z" />
-<glyph unicode="&#x399;" horiz-adv-x="581" d="M181 1448l19 -3h142l15 3q76 -16 76 -76q-13 -76 -72 -76h-16v-1147h23q50 0 65 -73v-4q-13 -72 -72 -72h-180q-72 13 -72 72v4q15 73 65 73h23v1147h-16q-63 0 -72 80v4q0 47 72 68z" />
-<glyph unicode="&#x39a;" horiz-adv-x="1118" d="M118 1434h3q72 -12 72 -68v-653q700 699 706 699l27 4h7q68 -13 68 -68v-12q0 -37 -79 -102l-465 -468l533 -660l3 -23v-11q0 -56 -71 -68h-4q-45 0 -125 117l-445 540l-155 -159v-434q0 -56 -72 -68h-3q-58 0 -72 75v1284q14 75 72 75z" />
-<glyph unicode="&#x39b;" horiz-adv-x="1232" d="M593 1438h11q60 0 87 -117q463 -1205 471 -1245v-4q-13 -72 -72 -72h-4q-52 0 -76 68q-406 1086 -413 1086l-425 -1124q-31 -30 -61 -30h-4q-60 0 -72 80l501 1328q28 30 57 30z" />
-<glyph unicode="&#x39c;" horiz-adv-x="1479" d="M124 1432h15q59 0 83 -98l480 -1073q19 22 336 748l186 400q22 23 49 23h15q55 0 64 -83v-1273q-14 -76 -72 -76h-4q-71 12 -71 68v941h-4q-423 -960 -438 -983q-29 -26 -57 -26q-66 0 -117 159l-378 846h-4v-937q0 -56 -71 -68h-4q-58 0 -72 76v1273q9 83 64 83z" />
-<glyph unicode="&#x39d;" horiz-adv-x="1329" d="M130 1431h15q48 0 83 -75q56 -63 821 -1051q8 0 8 -11l3 -4h4v1073q13 68 68 68h11q56 0 68 -71v-1285q0 -62 -79 -75q-43 0 -132 132l-787 1005v-1065q0 -56 -72 -68h-3q-58 0 -72 75v1269q9 83 64 83z" />
-<glyph unicode="&#x39e;" horiz-adv-x="1158" d="M108 1432h876q68 -13 68 -68v-15q0 -55 -83 -64h-849q-76 15 -76 75q16 72 64 72zM230 803h636q72 -12 72 -72v-3q-13 -72 -72 -72h-636q-58 0 -72 75q18 72 72 72zM116 148h864q72 -13 72 -68v-12q-13 -68 -68 -68h-868q-58 0 -72 76q18 72 72 72z" />
-<glyph unicode="&#x39f;" horiz-adv-x="1620" d="M793 1435q363 0 607 -336q110 -191 110 -385q0 -359 -325 -597q-184 -117 -385 -117h-15q-370 0 -604 344q-106 174 -106 377q0 343 302 578q196 136 416 136zM222 710q0 -274 242 -461q151 -102 321 -102h19q268 0 453 238q106 153 106 333q0 309 -283 490 q-140 80 -287 80q-283 0 -469 -246q-102 -147 -102 -332z" />
-<glyph unicode="&#x3a0;" horiz-adv-x="1184" d="M130 1431h872q68 -13 68 -68v-1299q0 -49 -72 -64h-3q-72 13 -72 72v1211h-710v-1215q0 -56 -72 -68h-3q-58 0 -72 75v1272q9 84 64 84z" />
-<glyph unicode="&#x3a1;" horiz-adv-x="946" d="M121 1438h346q202 0 345 -209q53 -107 53 -193v-27q0 -189 -171 -326q-116 -80 -227 -80h-262v-535q0 -55 -72 -68h-4q-58 0 -72 76v1278q9 84 64 84zM205 1290v-539h235q190 0 262 182q15 38 15 91q0 167 -171 247q-42 19 -98 19h-243z" />
-<glyph unicode="&#x3a3;" horiz-adv-x="1124" d="M131 1315h804q62 -12 62 -63v-14q0 -50 -76 -59h-630q411 -470 432 -501l3 -20v-11q0 -33 -77 -104l-347 -404v-3h629q66 -12 66 -63v-10q-12 -63 -62 -63h-797q-53 0 -66 70q0 29 77 97l420 487l-487 560q-10 18 -10 35q15 66 59 66z" />
-<glyph unicode="&#x3a4;" horiz-adv-x="1262" d="M129 1436h933q68 -13 68 -68v-15q0 -55 -83 -64h-376v-1221q0 -56 -72 -68h-3q-58 0 -72 76v1213h-383q-76 15 -76 75q16 72 64 72z" />
-<glyph unicode="&#x3a5;" horiz-adv-x="1237" d="M142 1433h16q49 0 79 -72l345 -516h4q372 562 387 573q20 15 34 15h23q46 0 64 -72q0 -32 -129 -209l-307 -458v-611q-9 -83 -64 -83h-16q-49 0 -68 61v621q0 14 -159 251l-269 405l-4 23q16 72 64 72z" />
-<glyph unicode="&#x3a6;" horiz-adv-x="1629" d="M773 1439h11q69 -13 69 -68v-76q184 -14 376 -122q273 -192 273 -455q0 -247 -251 -433q-114 -87 -338 -133q-60 -3 -60 -11v-76q0 -50 -72 -65h-4q-72 13 -72 72v76h-4q-139 0 -346 106q-296 189 -296 468q0 264 277 451q116 85 369 122v72q12 72 68 72zM207 722 q0 -262 315 -411q123 -41 183 -41v903q-186 -21 -335 -133q-163 -146 -163 -318zM853 1173v-903h3q147 0 338 133q156 144 156 300v34q0 209 -247 360q-87 52 -250 76z" />
-<glyph unicode="&#x3a7;" horiz-adv-x="1338" d="M131 1437h16q44 0 72 -56l425 -543l458 588q20 11 38 11h12q55 0 68 -72v-3q0 -33 -102 -152l-383 -493l477 -611l8 -30v-4q-13 -72 -72 -72h-4q-49 0 -83 72l-417 531l-459 -588q-20 -15 -42 -15h-4q-72 13 -72 72v11q0 25 163 224l322 417q-470 596 -481 619l-4 22 q16 72 64 72z" />
-<glyph unicode="&#x3a8;" horiz-adv-x="1342" d="M123 1437h16q68 -14 68 -61v-314q11 -134 42 -205q86 -167 242 -220l68 -19v736q10 83 65 83h15q68 -14 68 -61v-758h4q103 6 243 133q110 131 110 333v285q13 68 68 68h11q56 0 69 -72v-334q0 -325 -323 -515q-138 -53 -182 -53v-395q0 -55 -72 -68h-3q-58 0 -73 76v387 q-87 7 -231 83q-269 187 -269 508v300q9 83 64 83z" />
-<glyph unicode="&#x3a9;" horiz-adv-x="1658" d="M781 1437q367 0 613 -340q111 -198 111 -373q0 -339 -263 -568h-4v-4h164q73 -14 73 -64v-16q-15 -68 -69 -68h-492q-60 0 -72 80q19 68 69 68q106 0 289 157q160 187 160 407q0 272 -244 469q-162 103 -320 103h-30q-273 0 -461 -248q-103 -159 -103 -324 q0 -331 305 -514q52 -32 175 -61q46 -19 46 -72q-20 -69 -73 -69h-484q-76 15 -76 76q17 73 73 73h160v3q-93 70 -164 180q-107 186 -107 392q0 336 309 579q199 134 415 134z" />
-<glyph unicode="&#x3aa;" horiz-adv-x="648" d="M144 1683h15q68 -14 68 -60v-19q0 -55 -72 -68q-75 15 -75 76q16 71 64 71zM434 1683h11q68 -15 68 -64v-11q0 -60 -75 -72q-72 14 -72 72v11q0 49 68 64zM212 1431l19 -4h139l15 4q75 -16 75 -76q-13 -75 -71 -75h-15v-1133h22q50 0 64 -72v-3q-12 -72 -71 -72h-177 q-72 13 -72 72v3q15 72 64 72h23v1133h-15q-63 0 -72 79v4q0 46 72 68z" />
-<glyph unicode="&#x3ab;" horiz-adv-x="1216" d="M121 1433h16q49 0 79 -72l345 -516h4q372 562 387 573q20 15 34 15h23q46 0 64 -72q0 -32 -129 -209l-307 -458v-611q-9 -83 -64 -83h-16q-49 0 -68 61v621q0 14 -159 251l-269 405l-4 23q16 72 64 72zM412 1687h15q68 -14 68 -60v-19q0 -55 -72 -68q-75 15 -75 76 q16 71 64 71zM702 1687h11q68 -15 68 -64v-11q0 -60 -75 -72q-72 14 -72 72v11q0 49 68 64z" />
-<glyph unicode="&#x3ac;" horiz-adv-x="1414" d="M574 1015q256 0 426 -241l30 -59q15 24 104 263q27 37 63 37q74 -14 74 -74q-4 -23 -159 -433q159 -415 159 -434q-17 -74 -74 -74q-68 0 -108 159l-51 137h-8q-49 -119 -167 -200q-125 -96 -296 -96h-15q-205 0 -382 193q-107 152 -107 315q0 274 263 444q130 63 248 63 zM208 508q0 -219 218 -334q78 -29 152 -29q209 0 326 218l52 145q-64 221 -174 292q-95 67 -200 67h-19q-196 0 -311 -189q-44 -90 -44 -170zM673 1420q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52z" />
-<glyph unicode="&#x3ad;" horiz-adv-x="900" d="M372 1017h38q161 0 317 -164q26 -27 26 -54v-8q0 -59 -86 -72q-47 0 -111 84q-96 65 -159 65h-21q-93 0 -142 -111v-50q0 -71 108 -114q16 -8 47 -8h68q82 -13 82 -73v-7q0 -69 -112 -69q-126 0 -171 -92l-13 -53q27 -142 159 -142h4q108 0 223 134q29 15 51 15 q74 0 86 -80v-4q-29 -87 -180 -168q-90 -46 -180 -46h-17q-185 0 -292 184q-21 62 -21 110q0 115 103 211q-116 99 -116 225q0 190 240 279zM513 1416q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52z" />
-<glyph unicode="&#x3ae;" horiz-adv-x="1191" d="M132 1000q70 -18 70 -62v-81q160 143 349 143q206 0 367 -172q117 -145 117 -305v-881q0 -51 -77 -62q-66 19 -66 70v825q0 276 -239 364q-57 14 -102 14h-11q-200 0 -309 -205q-29 -64 -29 -202v-385q0 -54 -70 -66h-3q-56 0 -70 73v848q8 84 73 84zM627 1399 q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52z" />
-<glyph unicode="&#x3af;" horiz-adv-x="467" d="M203 1008q70 -18 70 -63v-879q0 -54 -70 -66h-4q-56 0 -70 74v849q9 85 74 85zM277 1391q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52z" />
-<glyph unicode="&#x3b0;" horiz-adv-x="1203" d="M157 1004q70 -18 70 -62v-392q0 -252 143 -337q90 -70 201 -70q214 0 323 220q22 71 22 143v425q14 73 73 73q70 -16 70 -70v-465q0 -218 -209 -381q-132 -88 -268 -88h-25q-227 0 -396 224q-77 120 -77 296v400q8 84 73 84zM638 1390q73 -17 73 -70v-7q0 -31 -81 -121 q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52zM346 1309q80 -19 80 -80q-16 -80 -80 -80q-80 16 -80 80q19 80 80 80zM798 1309q80 -19 80 -80q-16 -80 -80 -80q-80 16 -80 80q19 80 80 80z" />
-<glyph unicode="&#x3b1;" horiz-adv-x="1414" d="M587 1015q256 0 426 -241l30 -59q15 24 104 263q27 37 63 37q74 -14 74 -74q-4 -23 -159 -433q159 -415 159 -434q-17 -74 -74 -74q-68 0 -108 159l-51 137h-8q-49 -119 -167 -200q-125 -96 -296 -96h-15q-205 0 -382 193q-107 152 -107 315q0 274 263 444q130 63 248 63 zM221 508q0 -219 218 -334q78 -29 152 -29q209 0 326 218l52 145q-64 221 -174 292q-95 67 -200 67h-19q-196 0 -311 -189q-44 -90 -44 -170z" />
-<glyph unicode="&#x3b2;" horiz-adv-x="999" d="M451 1434h4q236 0 357 -238q27 -68 27 -137v-15q0 -157 -138 -287v-4q191 -126 191 -345q0 -230 -237 -367q-99 -38 -181 -38q-127 0 -256 91v-441q-2 -75 -70.5 -77.5t-79.5 64.5v79v629v132v591q0 192 207 322q90 41 176 41zM218 999v-598q0 -118 111 -201 q65 -45 149 -45q187 0 253 193l8 53v15q0 183 -203 250l-54 3h-130q-73 12 -73 72v16q0 47 69 64h65q197 0 257 144q15 47 15 79v19q0 155 -184 216l-50 4q-166 0 -226 -178z" />
-<glyph unicode="&#x3b3;" horiz-adv-x="1057" d="M168 1008q64 0 104 -142l243 -601h7q280 705 295 721q34 21 53 22q74 -15 74 -75q0 -19 -347 -870l-7 -30v-399q0 -59 -75 -71q-71 14 -71 71v411q0 22 -347 862l-4 26q15 75 75 75z" />
-<glyph unicode="&#x3b4;" horiz-adv-x="1233" d="M173 1435l37 -3h707q75 -15 75 -72v-8q-13 -68 -68 -68v-3l-26 3h-491l513 -377q178 -171 178 -389q0 -291 -276 -458q-119 -60 -230 -60h-30q-209 0 -389 196q-110 156 -110 322q0 279 264 449q124 60 174 60l-378 284q-18 26 -18 49q12 72 68 72v3zM214 529v-19 q0 -207 200 -321q73 -38 155 -38h23q215 0 328 223q27 70 27 136v19q0 172 -159 291q-93 64 -211 64q-236 0 -344 -246q-19 -60 -19 -109z" />
-<glyph unicode="&#x3b5;" horiz-adv-x="896" d="M372 1017h38q161 0 317 -164q26 -27 26 -54v-8q0 -59 -86 -72q-47 0 -111 84q-96 65 -159 65h-21q-93 0 -142 -111v-50q0 -71 108 -114q16 -8 47 -8h68q82 -13 82 -73v-7q0 -69 -112 -69q-126 0 -171 -92l-13 -53q27 -142 159 -142h4q108 0 223 134q29 15 51 15 q74 0 86 -80v-4q-29 -87 -180 -168q-90 -46 -180 -46h-17q-185 0 -292 184q-21 62 -21 110q0 115 103 211q-116 99 -116 225q0 190 240 279z" />
-<glyph unicode="&#x3b6;" horiz-adv-x="1052" d="M274 1435h585q69 -14 69 -60v-19q0 -44 -72 -80q-441 -391 -491 -445q-91 -120 -91 -266q0 -235 221 -368q90 -54 243 -54q126 -31 182 -106q61 -82 61 -175v-4q0 -201 -224 -277h-8q-72 15 -72 65v15q0 55 91 80q69 45 69 121q0 86 -88 126l-38 11l-30 -4 q-236 0 -430 213q-125 170 -125 338v42q0 264 274 479l247 220h-365q-76 14 -76 72v4q12 72 68 72z" />
-<glyph unicode="&#x3b7;" horiz-adv-x="1178" d="M132 1000q70 -18 70 -62v-81q160 143 349 143q206 0 367 -172q117 -145 117 -305v-881q0 -51 -77 -62q-66 19 -66 70v825q0 276 -239 364q-57 14 -102 14h-11q-200 0 -309 -205q-29 -64 -29 -202v-385q0 -54 -70 -66h-3q-56 0 -70 73v848q8 84 73 84z" />
-<glyph unicode="&#x3b8;" horiz-adv-x="1158" d="M558 1430q246 0 376 -263q72 -220 72 -407v-86q0 -230 -94 -463q-137 -211 -346 -211h-12q-227 0 -357 241q-83 212 -83 470v12q0 274 98 496q140 211 346 211zM249 790h622q0 163 -80 362q-95 135 -229 135q-156 0 -241 -158q-62 -169 -64 -282zM249 644q4 -147 72 -350 q91 -151 230 -151h11q240 0 290 343q19 106 19 158h-622z" />
-<glyph unicode="&#x3b9;" horiz-adv-x="442" d="M191 1008q70 -18 70 -63v-879q0 -54 -70 -66h-4q-56 0 -70 74v849q9 85 74 85z" />
-<glyph unicode="&#x3ba;" horiz-adv-x="1086" d="M140 1073l21 1q56 -14 60 -81v-365q535 354 624 405h19q60 0 72 -79q0 -46 -121 -110q-294 -199 -307 -201v-3l424 -538l4 -23v-3q-13 -72 -72 -72h-7q-44 0 -133 128l-341 424h-3l-159 -102v-386q0 -56 -72 -68h-4q-54 0 -72 68v927q12 65 67 78z" />
-<glyph unicode="&#x3bb;" horiz-adv-x="1120" d="M413 1367l601 -1260q13 -100 -53 -104.5t-99 52.5l-331 689h-5q-315 -674 -348 -718q-40 -51 -102.5 -21.5t-14.5 138.5l236 498l140 295l-169 365q-31 103 44 121.5t101 -55.5z" />
-<glyph unicode="&#x3bc;" horiz-adv-x="1199" d="M144 1004q70 -18 70 -62v-393q0 -252 143 -338q90 -69 202 -69q214 0 323 220q22 71 22 143v426q14 73 73 73q70 -16 70 -70v-873q0 -48 -70 -62h-3q-70 12 -70 69v70h-4q-153 -139 -330 -139h-26q-172 0 -330 143v-496q0 -46 -73 -62q-55 0 -70 77v1259q8 84 73 84z" />
-<glyph unicode="&#x3bd;" horiz-adv-x="1220" d="M156 1029h7q59 0 102 -124l322 -661q350 742 372 766q26 19 49 19q75 -14 75 -71v-4q0 -19 -165 -361l-278 -570q-30 -23 -53 -23h-3q-64 0 -113 143q-363 742 -383 800v18q13 68 68 68z" />
-<glyph unicode="&#x3be;" horiz-adv-x="951" d="M407 1433h182q73 -13 73 -72v-4q-13 -73 -73 -73h-167q-142 0 -183 -129l-8 -42q26 -175 176 -175h3l92 19q72 -18 72 -65v-23q0 -57 -114 -76q-210 -107 -210 -300v-27q0 -189 198 -293q34 -22 214 -38q209 -82 209 -274v-4q0 -201 -225 -278h-7q-73 15 -73 65v15 q0 56 92 80q68 46 68 122q-23 137 -137 137l-11 -4q-240 0 -407 232q-73 134 -73 251q0 194 152 354q-167 98 -167 286q0 184 194 289q59 27 130 27z" />
-<glyph unicode="&#x3bf;" horiz-adv-x="1245" d="M586 1004q194 0 352 -147q150 -157 150 -355q0 -282 -267 -443q-116 -59 -224 -59h-29q-203 0 -378 191q-106 150 -106 311q0 244 216 410q139 92 286 92zM231 513v-18q0 -201 194 -312q70 -36 150 -36h22q208 0 319 216q25 68 25 132v18q0 167 -153 282q-91 62 -206 62 q-228 0 -333 -238q-18 -58 -18 -106z" />
-<glyph unicode="&#x3c0;" horiz-adv-x="1165" d="M133 1009l37 -3h770l41 3q66 -22 66 -66v-11q0 -49 -63 -70l-59 4h-18v-800q0 -54 -70 -66h-4q-56 0 -70 74v792h-412v-803q0 -49 -70 -63h-4q-70 12 -70 70v796h-18l-59 -4q-63 22 -63 74q12 70 66 70v3z" />
-<glyph unicode="&#x3c1;" horiz-adv-x="1187" d="M566 1020q196 0 355 -148q152 -160 152 -359q0 -285 -270 -448q-117 -59 -226 -59h-30q-176 0 -344 152v-511q0 -47 -74 -63q-53 0 -70 74v822q0 384 363 518q45 14 144 22zM207 524v-19q0 -202 196 -314q71 -37 152 -37h22q211 0 322 218q26 69 26 133v19 q0 169 -155 285q-92 63 -208 63q-230 0 -336 -241q-19 -59 -19 -107z" />
-<glyph unicode="&#x3c2;" horiz-adv-x="997" d="M584 1018q172 0 172 -84v-20q-18 -64 -72 -64h-12l-84 12q-226 0 -332 -228q-16 -39 -24 -128q0 -223 236 -332q59 -15 200 -28q220 -86 220 -288v-4q0 -212 -236 -292h-8q-76 15 -76 68v16q0 59 96 84q72 48 72 128q0 100 -112 140l-24 4l-12 -4q-286 0 -452 276 q-56 111 -56 208v44q0 256 260 428q133 64 244 64z" />
-<glyph unicode="&#x3c3;" horiz-adv-x="1355" d="M540 1006l80 -4h518l33 4q66 -20 66 -63v-22q0 -39 -59 -62l-62 4h-209q154 -164 154 -360q0 -254 -231 -422q-133 -81 -261 -81h-29q-214 0 -382 198q-103 143 -103 290v33q0 229 228 404q148 81 257 81zM198 503q0 -220 224 -334q73 -22 118 -22h33q178 0 293 176 q48 84 48 187q0 193 -191 309q-79 40 -172 40q-193 0 -309 -187q-44 -89 -44 -169z" />
-<glyph unicode="&#x3c4;" horiz-adv-x="1187" d="M146 1012l37 -4h780l33 4q66 -19 66 -70v-8q0 -47 -59 -70l-62 4h-296v-794q-14 -74 -70 -74h-4q-70 12 -70 66v802h-299l-59 -4q-63 23 -63 74q12 70 66 70v4z" />
-<glyph unicode="&#x3c5;" horiz-adv-x="1216" d="M157 1004q70 -18 70 -62v-392q0 -252 143 -337q90 -70 201 -70q214 0 323 220q22 71 22 143v425q14 73 73 73q70 -16 70 -70v-465q0 -218 -209 -381q-132 -88 -268 -88h-25q-227 0 -396 224q-77 120 -77 296v400q8 84 73 84z" />
-<glyph unicode="&#x3c6;" horiz-adv-x="1213" d="M702 1011h30q146 0 289 -220q70 -127 70 -254q0 -307 -293 -478q-122 -50 -173 -50v-362q0 -64 -81 -77q-70 19 -70 69v374q-103 12 -239 104q-200 176 -200 424q0 247 227 424q23 15 43 15h11q70 -13 70 -69v-16q0 -34 -77 -84q-120 -127 -120 -255v-42q0 -193 200 -316 l85 -31v613q0 142 166 219zM625 757v-594h3q93 7 216 116q93 121 93 235v42q0 170 -178 297l-38 8q-67 0 -93 -70z" />
-<glyph unicode="&#x3c7;" horiz-adv-x="1237" d="M187 1008q53 0 112 -119l297 -464h7q312 498 364 564q21 16 45 19q74 -15 74 -74q0 -34 -182 -301l-215 -342q0 -15 319 -505q78 -119 78 -145q-16 -74 -71 -74q-58 0 -115 119q-49 68 -297 464h-7q-336 -538 -364 -564q-19 -15 -48 -19q-56 0 -71 78v4q11 40 282 449 q25 51 119 186l-401 635v15q15 74 74 74z" />
-<glyph unicode="&#x3c8;" horiz-adv-x="1376" d="M161 1019h4q72 -11 72 -73v-303q0 -259 131 -368q71 -80 203 -111l19 -4v771q9 84 65 84h16q69 -14 69 -61v-794h3q103 6 234 123q119 122 119 330v333q13 73 73 73h4q76 0 76 -111v-326q0 -352 -348 -537q-119 -42 -161 -42v-318q0 -56 -73 -69h-4q-59 0 -73 77v310 q-96 7 -249 92q-257 192 -257 506v334q13 84 77 84z" />
-<glyph unicode="&#x3c9;" horiz-adv-x="1321" d="M302 1016h7q68 -12 68 -69v-4q0 -13 -83 -184q-86 -225 -86 -416v-29q0 -116 130 -162l39 -7q132 0 174 144l4 87v318l-4 40q22 65 65 65h11q60 0 68 -83v-373l4 -32l-4 -11q0 -91 120 -152l54 -7q124 0 170 137l3 36v29q0 268 -169 582v18q12 69 68 69h4q57 0 105 -123 q137 -285 137 -575q0 -193 -199 -292q-55 -22 -108 -22h-22q-129 0 -238 116q-96 -112 -232 -112h-14q-196 0 -293 209q-18 59 -18 101q0 351 188 676q24 26 51 26z" />
-<glyph unicode="&#x3ca;" horiz-adv-x="589" d="M296 1008q70 -18 70 -63v-879q0 -54 -70 -66h-4q-56 0 -70 74v849q9 85 74 85zM138 1236h15q68 -14 68 -60v-19q0 -55 -72 -68q-75 15 -75 76q16 71 64 71zM428 1236h11q68 -15 68 -64v-11q0 -60 -75 -72q-72 14 -72 72v11q0 49 68 64z" />
-<glyph unicode="&#x3cb;" horiz-adv-x="1208" d="M157 1004q70 -18 70 -62v-392q0 -252 143 -337q90 -70 201 -70q214 0 323 220q22 71 22 143v425q14 73 73 73q70 -16 70 -70v-465q0 -218 -209 -381q-132 -88 -268 -88h-25q-227 0 -396 224q-77 120 -77 296v400q8 84 73 84zM407 1271h15q68 -14 68 -60v-19 q0 -55 -72 -68q-75 15 -75 76q16 71 64 71zM697 1271h11q68 -15 68 -64v-11q0 -60 -75 -72q-72 14 -72 72v11q0 49 68 64z" />
-<glyph unicode="&#x3cc;" horiz-adv-x="1229" d="M586 1004q194 0 352 -147q150 -157 150 -355q0 -282 -267 -443q-116 -59 -224 -59h-29q-203 0 -378 191q-106 150 -106 311q0 244 216 410q139 92 286 92zM231 513v-18q0 -201 194 -312q70 -36 150 -36h22q208 0 319 216q25 68 25 132v18q0 167 -153 282q-91 62 -206 62 q-228 0 -333 -238q-18 -58 -18 -106zM621 1387q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52z" />
-<glyph unicode="&#x3cd;" horiz-adv-x="1178" d="M157 1004q70 -18 70 -62v-392q0 -252 143 -337q90 -70 201 -70q214 0 323 220q22 71 22 143v425q14 73 73 73q70 -16 70 -70v-465q0 -218 -209 -381q-132 -88 -268 -88h-25q-227 0 -396 224q-77 120 -77 296v400q8 84 73 84zM626 1413q73 -17 73 -70v-7q0 -31 -81 -121 q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52z" />
-<glyph unicode="&#x3ce;" horiz-adv-x="1309" d="M302 1016h7q68 -12 68 -69v-4q0 -13 -83 -184q-86 -225 -86 -416v-29q0 -116 130 -162l39 -7q132 0 174 144l4 87v318l-4 40q22 65 65 65h11q60 0 68 -83v-373l4 -32l-4 -11q0 -91 120 -152l54 -7q124 0 170 137l3 36v29q0 268 -169 582v18q12 69 68 69h4q57 0 105 -123 q137 -285 137 -575q0 -193 -199 -292q-55 -22 -108 -22h-22q-129 0 -238 116q-96 -112 -232 -112h-14q-196 0 -293 209q-18 59 -18 101q0 351 188 676q24 26 51 26zM706 1400q73 -17 73 -70v-7q0 -31 -81 -121q-60 -92 -113 -92h-4q-47 0 -62 70v7q0 33 113 161q38 52 74 52 z" />
-<glyph unicode="&#x2000;" horiz-adv-x="931" />
-<glyph unicode="&#x2001;" horiz-adv-x="1863" />
-<glyph unicode="&#x2002;" horiz-adv-x="931" />
-<glyph unicode="&#x2003;" horiz-adv-x="1863" />
-<glyph unicode="&#x2004;" horiz-adv-x="621" />
-<glyph unicode="&#x2005;" horiz-adv-x="465" />
-<glyph unicode="&#x2006;" horiz-adv-x="310" />
-<glyph unicode="&#x2007;" horiz-adv-x="310" />
-<glyph unicode="&#x2008;" horiz-adv-x="232" />
-<glyph unicode="&#x2009;" horiz-adv-x="372" />
-<glyph unicode="&#x200a;" horiz-adv-x="103" />
-<glyph unicode="&#x2010;" horiz-adv-x="670" d="M144 648h400q59 0 76 -80q-18 -76 -76 -76h-400q-65 0 -76 84q20 72 76 72z" />
-<glyph unicode="&#x2011;" horiz-adv-x="670" d="M144 648h400q59 0 76 -80q-18 -76 -76 -76h-400q-65 0 -76 84q20 72 76 72z" />
-<glyph unicode="&#x2013;" horiz-adv-x="1108" d="M156 512l40 -4h720l36 4q59 0 76 -80q0 -52 -64 -80l-68 4h-680l-64 -4q-68 24 -68 80q13 76 72 76v4z" />
-<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M72 580l40 -4h1824l36 4q59 0 76 -80q0 -52 -64 -80l-68 4h-1784l-64 -4q-68 24 -68 80q13 76 72 76v4z" />
-<glyph unicode="&#x2015;" horiz-adv-x="2007" d="M165 619l40 -4h1600l36 4q72 -20 72 -76v-8q0 -51 -64 -76l-68 4h-1556l-64 -4q-68 24 -68 80q13 76 72 76v4z" />
-<glyph unicode="&#x2017;" horiz-adv-x="951" d="M71 -29h885q74 -13 74 -70v-12q-14 -70 -70 -70h-889q-63 0 -74 82q20 70 74 70z" />
-<glyph unicode="&#x2018;" horiz-adv-x="557" d="M364 1567q28 -8 28 -32v-8q-59 -141 -60 -244q0 -60 48 -140l4 -20q0 -64 -84 -80q-96 0 -124 252q0 134 144 256z" />
-<glyph unicode="&#x2019;" horiz-adv-x="557" d="M261 1558h28q83 0 112 -236v-20q0 -129 -144 -248q-29 -16 -44 -16q-18 7 -28 24v12q60 144 60 236v12q0 62 -48 144v20q15 72 64 72z" />
-<glyph unicode="&#x201a;" horiz-adv-x="557" d="M256 220h28q83 0 112 -236v-20q0 -129 -144 -248q-29 -16 -44 -16q-18 7 -28 24v12q60 144 60 236v12q0 62 -48 144v20q15 72 64 72z" />
-<glyph unicode="&#x201b;" horiz-adv-x="450" d="M313 1476v-20q-49 -82 -49 -144v-12q0 -92 61 -236v-12q-10 -17 -28 -24q-15 0 -45 16q-145 119 -145 248v20q29 236 113 236h28q50 0 65 -72z" />
-<glyph unicode="&#x201c;" horiz-adv-x="910" d="M412 1588q28 -8 28 -32v-8q-59 -141 -60 -244q0 -60 48 -140l4 -20q0 -64 -84 -80q-96 0 -124 252q0 134 144 256zM700 1580q28 -12 28 -36q-64 -142 -64 -244q0 -61 52 -152v-12q-14 -76 -72 -76h-16q-82 0 -116 204v68q0 107 136 228q28 20 52 20z" />
-<glyph unicode="&#x201d;" horiz-adv-x="910" d="M296 1581h28q83 0 112 -236v-20q0 -129 -144 -248q-29 -16 -44 -16q-18 7 -28 24v12q60 144 60 236v12q0 62 -48 144v20q15 72 64 72zM600 1585h12q94 0 120 -244v-8q0 -132 -144 -252l-40 -16q-32 0 -32 32v4q60 141 60 248q0 62 -48 140v32q18 64 72 64z" />
-<glyph unicode="&#x201e;" horiz-adv-x="910" d="M278 235h28q83 0 112 -236v-20q0 -129 -144 -248q-29 -16 -44 -16q-18 7 -28 24v12q60 144 60 236v12q0 62 -48 144v20q15 72 64 72zM582 239h12q94 0 120 -244v-8q0 -132 -144 -252l-40 -16q-32 0 -32 32v4q60 141 60 248q0 62 -48 140v32q18 64 72 64z" />
-<glyph unicode="&#x2020;" d="M509 1441h12q59 0 72 -76v-288h192l36 4q56 0 76 -80q0 -55 -68 -80l-60 4h-176v-1224q0 -67 -84 -80q-72 19 -72 72v1232h-172l-64 -4q-68 24 -68 80q13 76 72 76v4l40 -4h192v292q14 72 72 72z" />
-<glyph unicode="&#x2021;" d="M512 1441h12q59 0 72 -76v-288h192l36 4q56 0 76 -80q0 -55 -68 -80l-60 4h-176v-784h236q49 0 68 -76q-16 -80 -80 -80h-224v-284q0 -67 -84 -80q-72 19 -72 72v292h-224q-80 16 -80 80q17 76 68 76h236v784h-172l-64 -4q-68 24 -68 80q13 76 72 76v4l40 -4h192v292 q14 72 72 72z" />
-<glyph unicode="&#x2022;" horiz-adv-x="1024" d="M216 718q0 123 87 209t210 86q122 0 208.5 -86.5t86.5 -208.5t-87.5 -209.5t-209.5 -87.5q-123 0 -209 87t-86 210z" />
-<glyph unicode="&#x2026;" horiz-adv-x="2048" d="M1633 274q105 0 135 -125v-24q0 -75 -96 -118q-14 -7 -39 -7h-4q-112 0 -135 139q0 88 100 128q14 7 39 7zM942 270q105 0 135 -125v-24q0 -75 -96 -118q-14 -7 -39 -7h-4q-112 0 -135 139q0 88 100 128q14 7 39 7zM269 274q105 0 135 -125v-24q0 -75 -96 -118 q-14 -7 -39 -7h-4q-112 0 -135 139q0 88 100 128q14 7 39 7z" />
-<glyph unicode="&#x202f;" horiz-adv-x="372" />
-<glyph unicode="&#x2030;" horiz-adv-x="2494" d="M499 1436h19q167 0 284 -152q68 -100 68 -205q0 -233 -242 -344q-69 -19 -114 -19h-7q-210 0 -322 204q-38 77 -38 156q0 236 250 344q51 16 102 16zM1333 1436h11q68 -14 68 -69v-15q0 -22 -140 -201l-860 -1136q-29 -15 -45 -15h-4q-72 15 -72 64v16q0 31 106 159 l894 1181q23 16 42 16zM295 1079v-7q0 -150 166 -205l38 -3h19q147 0 201 170l4 42q0 154 -163 208l-49 8q-152 0 -209 -159zM1196 723q211 0 333 -219q27 -80 27 -140v-12q0 -211 -223 -325q-69 -27 -137 -27h-7q-184 0 -303 178q-50 86 -50 170v23q0 190 190 307 q91 45 170 45zM980 364q0 -150 156 -209l53 -7h15q143 0 200 163l4 34v26q0 149 -174 201l-38 4q-159 0 -212 -178zM1989 728q211 0 333 -219q27 -80 27 -140v-12q0 -211 -223 -325q-69 -27 -137 -27h-7q-184 0 -303 178q-50 86 -50 170v23q0 190 190 307q91 45 170 45z M1773 369q0 -150 156 -209l53 -7h15q143 0 200 163l4 34v26q0 149 -174 201l-38 4q-159 0 -212 -178z" />
-<glyph unicode="&#x2032;" horiz-adv-x="455" d="M276 1429h4q76 -13 76 -72v-20q0 -21 -168 -240q-18 -20 -36 -20h-8q-33 0 -44 44v8q105 263 128 284q27 16 48 16z" />
-<glyph unicode="&#x2033;" horiz-adv-x="673" d="M284 1429h4q76 -13 76 -72v-20q0 -21 -168 -240q-18 -20 -36 -20h-8q-33 0 -44 44v8q105 263 128 284q27 16 48 16zM532 1417q80 -16 80 -80q0 -32 -108 -168q-67 -104 -96 -104h-12q-33 0 -44 44q0 17 112 272q35 36 68 36z" />
-<glyph unicode="&#x2039;" horiz-adv-x="631" d="M396 683h8q76 -12 76 -76v-4q0 -52 -116 -128l-4 -4v-4q120 -82 120 -132v-4q-13 -76 -72 -76h-20q-30 0 -212 164l-8 28v44q0 38 148 144q44 48 80 48z" />
-<glyph unicode="&#x203a;" horiz-adv-x="631" d="M172 679q38 0 168 -120q64 -39 64 -76v-36q0 -46 -112 -124q-80 -76 -120 -76h-4q-76 14 -76 76v4q0 51 112 124l8 12q-120 84 -120 132v4q16 80 80 80z" />
-<glyph unicode="&#x203c;" horiz-adv-x="850" d="M618 1442h12q60 0 73 -69v-955q-17 -72 -77 -72q-81 12 -81 69v962q14 65 73 65zM609 206h8q103 -15 103 -92v-22q0 -71 -95 -92h-12q-79 0 -99 103q21 103 95 103zM214 1442h12q60 0 73 -69v-955q-17 -72 -77 -72q-81 12 -81 69v962q14 65 73 65zM205 206h8 q103 -15 103 -92v-22q0 -71 -95 -92h-12q-79 0 -99 103q21 103 95 103z" />
-<glyph unicode="&#x203e;" horiz-adv-x="837" d="M186 1362l40 -4h400l36 4q56 0 76 -80q0 -55 -68 -80l-60 4h-364l-64 -4q-68 24 -68 80q13 76 72 76v4z" />
-<glyph unicode="&#x2044;" horiz-adv-x="462" d="M635 1453h12q59 0 72 -76v-4q0 -33 -116 -172q-971 -1260 -984 -1268l-32 -12h-16q-52 0 -72 64v20q0 34 116 172l976 1260q21 16 44 16z" />
-<glyph unicode="&#x2215;" horiz-adv-x="462" d="M635 1453h12q59 0 72 -76v-4q0 -33 -116 -172q-971 -1260 -984 -1268l-32 -12h-16q-52 0 -72 64v20q0 34 116 172l976 1260q21 16 44 16z" />
-<glyph unicode="&#x205f;" horiz-adv-x="465" />
-<glyph unicode="&#x207f;" horiz-adv-x="787" d="M122 1065q42 -11 42 -38v-49q96 87 210 87q124 0 221 -104q70 -87 70 -183v-281q0 -29 -42 -37h-2q-42 8 -42 42v247q0 166 -143 219q-35 9 -62 9h-7q-120 0 -186 -124q-17 -38 -17 -122v-231q0 -33 -42 -40h-2q-34 0 -42 44v510q5 51 44 51z" />
-<glyph unicode="&#x20a3;" horiz-adv-x="1127" d="M250 1437l18 -4h719l15 4q62 0 73 -83q-15 -68 -81 -68h-671v-511h440l51 4q50 0 66 -76q0 -49 -58 -75l-74 4h-425v-258h121l33 4q54 0 70 -75q0 -50 -59 -76l-62 4h-103v-136l4 -23q-16 -72 -70 -72h-7q-70 13 -70 72v159h-99l-59 -4q-62 20 -62 72v7q0 51 62 72l37 -4 h121v987q11 72 70 72v4z" />
-<glyph unicode="&#x20a4;" horiz-adv-x="946" d="M439 1428h38q177 0 301 -166l4 -26q-17 -76 -75 -76q-35 0 -98 72q-64 49 -132 49h-23q-149 0 -211 -177l-3 -49q0 -59 75 -200l30 -64h256q76 -15 76 -75q-16 -72 -64 -72h-208l8 -56h188q72 -13 72 -72v-4q-13 -71 -72 -71h-188q-7 0 -23 -72l-98 -222h381q6 0 41 79 q31 30 61 30q75 -15 75 -75q0 -27 -72 -158q-26 -23 -52 -23h-554q-58 0 -72 75q2 20 143 328l12 38h-147q-68 13 -68 68v11q0 55 72 68h154l-11 56h-143q-72 14 -72 72q15 75 75 75h68q-90 157 -90 268q0 225 237 346q74 23 109 23z" />
-<glyph unicode="&#x20a7;" horiz-adv-x="2028" d="M148 1290v-539h235q190 0 262 182q15 38 15 91q0 167 -171 247q-42 19 -98 19h-243zM1293 933q20 15 43 29q112 59 222 59q257 0 404 -233l3 -29v-4q0 -59 -74 -70q-49 0 -100 85q-103 100 -233 100q-171 0 -270 -163l-3 -19q0 -49 111 -59q426 -103 466 -118 q107 -70 107 -178v-3q0 -154 -226 -282q-97 -44 -207 -44q-118 0 -218 58q-13 -62 -68 -62h-77q-175 0 -260 191q-15 47 -15 110v561h-119q-41 -98 -142 -179q-116 -80 -227 -80h-262v-535q0 -55 -72 -68h-4q-58 0 -72 76v1278q9 84 64 84h346q202 0 345 -209 q53 -107 53 -193v-35h90v308q9 81 63 81h14q66 -14 66 -59v-330h151l33 4q50 0 68 -72zM1216 143q-32 32 -61 72q-15 22 -15 41v22q0 54 82 63q35 0 100 -93q99 -92 229 -92q156 0 259 148l7 22v4q0 48 -66 55q-497 111 -526 137q-92 70 -92 170q0 86 76 168l-32 2h-136 v-539q0 -141 92 -173z" />
-<glyph unicode="&#x20ac;" horiz-adv-x="1193" d="M725 1457q226 0 422 -138q15 -29 15 -46v-7q0 -65 -81 -73h-3l-135 69q-133 42 -218 42q-264 0 -460 -234q-43 -65 -73 -138h744q73 -12 73 -73v-4q-13 -73 -73 -73h-779l-4 -53l4 -58h779q73 -11 73 -73v-4q-13 -72 -73 -72h-744q89 -220 299 -319q117 -50 226 -50h12 q168 0 341 108h23q69 -15 69 -69v-12q0 -81 -257 -157q-80 -23 -169 -23h-19q-360 0 -602 334q-115 193 -115 395q0 378 345 617q185 111 380 111z" />
-<glyph unicode="&#x2105;" horiz-adv-x="1768" d="M1344 1430h12q55 0 68 -72v-3q0 -34 -125 -178q-95 -133 -894 -1162q-25 -15 -49 -15q-68 19 -68 64v23q0 23 143 200q807 1052 872 1128q20 15 41 15zM411 1430q138 0 251 -104q8 -14 8 -27v-2q-9 -50 -50 -50h-3q-19 0 -84 50q-58 29 -115 29h-15q-153 0 -231 -160 q-18 -54 -18 -97q0 -155 160 -236q48 -18 102 -18q90 0 178 73l21 5h8q38 0 47 -49v-2q0 -54 -168 -119q-57 -10 -84 -10h-21q-144 0 -269 136q-76 108 -76 223q0 174 154 293q99 65 205 65zM1316 709q135 0 246 -103q105 -110 105 -248q0 -198 -187 -311q-81 -41 -157 -41 h-21q-141 0 -263 134q-75 105 -75 218q0 171 151 287q97 64 201 64zM1067 365v-13q0 -140 136 -218q49 -25 105 -25h15q146 0 224 151q17 48 17 92v13q0 117 -107 198q-64 43 -144 43q-160 0 -234 -167q-12 -40 -12 -74z" />
-<glyph unicode="&#x2113;" horiz-adv-x="846" d="M534 1432q173 0 241 -184l8 -53v-19q0 -91 -124 -245l-219 -328v-362q0 -90 64 -90h19q62 26 79 26q51 0 68 -75q-23 -102 -166 -102q-137 0 -203 158l-8 72v151q-73 -117 -117 -117h-7q-60 0 -72 79q0 25 188 290l8 15v520q0 196 192 257zM440 871q192 268 192 297v34 q0 61 -94 80h-4q-78 0 -94 -106v-305z" />
-<glyph unicode="&#x2116;" horiz-adv-x="2271" d="M64 1431h15q48 0 83 -75q56 -63 821 -1051q8 0 8 -11l3 -4h4v1073q13 68 68 68h11q56 0 68 -71v-1285q0 -62 -79 -75q-43 0 -132 132l-787 1005v-1065q0 -56 -72 -68h-3q-58 0 -72 75v1269q9 83 64 83zM1287 419l40 -4h720l36 4q59 0 76 -80q0 -52 -64 -80l-68 4h-680 l-64 -4q-68 24 -68 80q13 76 72 76v4zM1682 1276q153 0 278 -116q118 -124 118 -280q0 -223 -211 -350q-91 -46 -176 -46h-24q-159 0 -297 150q-84 119 -84 246q0 193 170 324q109 72 226 72zM1402 889v-14q0 -159 153 -246q55 -29 118 -29h18q164 0 251 170q20 54 20 105 v14q0 132 -121 222q-71 49 -162 49q-180 0 -263 -187q-14 -46 -14 -84z" />
-<glyph unicode="&#x2122;" horiz-adv-x="1497" d="M184 1441h435q32 -6 32 -32v-7q0 -25 -39 -30h-175v-569q0 -26 -34 -32h-1q-27 0 -34 35v566h-179q-35 7 -35 36q8 33 30 33zM791 1440h8q27 0 39 -46l227 -509q9 11 159 355l88 189q11 11 23 11h8q26 0 30 -39v-603q-7 -36 -34 -36h-2q-34 6 -34 32v446h-2 q-200 -455 -207 -465q-14 -13 -27 -13q-31 0 -55 75l-179 401h-2v-444q0 -26 -34 -32h-2q-27 0 -34 36v603q4 39 30 39z" />
-<glyph unicode="&#x2126;" horiz-adv-x="1709" d="M819 1437q367 0 613 -340q111 -198 111 -373q0 -339 -263 -568h-4v-4h164q73 -14 73 -64v-16q-15 -68 -69 -68h-492q-60 0 -72 80q19 68 69 68q106 0 289 157q160 187 160 407q0 272 -244 469q-162 103 -320 103h-30q-273 0 -461 -248q-103 -159 -103 -324 q0 -331 305 -514q52 -32 175 -61q46 -19 46 -72q-20 -69 -73 -69h-484q-76 15 -76 76q17 73 73 73h160v3q-93 70 -164 180q-107 186 -107 392q0 336 309 579q199 134 415 134z" />
-<glyph unicode="&#x212e;" horiz-adv-x="1174" d="M566 1004q290 0 451 -275q55 -108 55 -234v-19q-13 -73 -70 -73h-773q44 -146 187 -223q84 -33 158 -33q84 0 194 55h22q66 -13 66 -66v-11q0 -91 -264 -125h-26q-270 0 -432 253q-66 120 -66 249q0 276 260 440q127 62 238 62zM218 546h704q0 75 -88 194 q-121 114 -238 114h-41q-176 0 -289 -172q-40 -69 -48 -136z" />
-<glyph unicode="&#x215b;" horiz-adv-x="1498" d="M1193 1442h12q56 0 68 -72v-4q0 -34 -125 -179q-96 -134 -902 -1172q-25 -15 -50 -15q-68 19 -68 65v23q0 23 145 201q813 1061 878 1138q20 15 42 15zM326 1434q25 0 45 -34l-3 -57v-654l3 -35q-13 -41 -45 -41q-26 0 -42 30v685l-65 -15h-19q-30 16 -30 41q0 48 110 65 q0 5 46 15zM1161 806q96 0 163 -86q39 -52 39 -114v-11q0 -85 -77 -154q111 -80 111 -202q0 -121 -111 -202q-62 -41 -130 -41h-11q-116 0 -200 115q-36 66 -36 128q0 126 119 211q-48 37 -64 102q-6 16 -6 43v11q0 107 102 172q52 28 101 28zM1041 597q0 -80 96 -113l24 -2 q83 0 114 89l5 30q0 88 -94 117l-28 2q-81 0 -113 -87zM992 241q0 -113 117 -156q16 -6 47 -6q106 0 152 117l4 32v22q0 90 -105 140q-29 9 -53 9q-114 0 -156 -118z" />
-<glyph unicode="&#x215c;" horiz-adv-x="1523" d="M1235 1442h12q56 0 68 -72v-4q0 -34 -125 -179q-96 -134 -902 -1172q-25 -15 -50 -15q-68 19 -68 65v23q0 23 145 201q813 1061 878 1138q20 15 42 15zM1203 806q96 0 163 -86q39 -52 39 -114v-11q0 -85 -77 -154q111 -80 111 -202q0 -121 -111 -202q-62 -41 -130 -41 h-11q-116 0 -200 115q-36 66 -36 128q0 126 119 211q-48 37 -64 102q-6 16 -6 43v11q0 107 102 172q52 28 101 28zM1083 597q0 -80 96 -113l24 -2q83 0 114 89l5 30q0 88 -94 117l-28 2q-81 0 -113 -87zM1034 241q0 -113 117 -156q16 -6 47 -6q106 0 152 117l4 32v22 q0 90 -105 140q-29 9 -53 9q-114 0 -156 -118zM327 1518q124 0 188 -129q15 -35 15 -64v-22q0 -83 -75 -155q109 -76 109 -204q0 -176 -196 -241l-53 -4h-7q-166 0 -234 196l-4 53q0 20 30 38h19q39 0 45 -83q44 -117 147 -117h12q112 0 151 132l4 30q0 109 -129 155 q-68 0 -68 49q10 41 61 41q76 0 102 106v26q0 71 -99 106h-22q-85 0 -117 -98v-34q-16 -30 -38 -30h-11q-38 7 -38 37v8q0 143 162 200z" />
-<glyph unicode="&#x215d;" horiz-adv-x="1569" d="M1294 1442h12q56 0 68 -72v-4q0 -34 -125 -179q-96 -134 -902 -1172q-25 -15 -50 -15q-68 19 -68 65v23q0 23 145 201q813 1061 878 1138q20 15 42 15zM1262 806q96 0 163 -86q39 -52 39 -114v-11q0 -85 -77 -154q111 -80 111 -202q0 -121 -111 -202q-62 -41 -130 -41 h-11q-116 0 -200 115q-36 66 -36 128q0 126 119 211q-48 37 -64 102q-6 16 -6 43v11q0 107 102 172q52 28 101 28zM1142 597q0 -80 96 -113l24 -2q83 0 114 89l5 30q0 88 -94 117l-28 2q-81 0 -113 -87zM1093 241q0 -113 117 -156q16 -6 47 -6q106 0 152 117l4 32v22 q0 90 -105 140q-29 9 -53 9q-114 0 -156 -118zM142 1437l21 -2h322q33 0 42 -44q0 -32 -45 -42h-292v-211h120q141 0 220 -145q25 -60 25 -105q0 -129 -123 -214q-63 -35 -124 -35h-7q-146 0 -227 151q-20 57 -20 96q15 39 44 39q46 0 46 -74q27 -81 85 -109q45 -18 74 -18 q110 0 155 111q9 23 9 53q0 119 -126 160l-51 4h-146q-29 0 -40 35v313q0 23 38 37z" />
-<glyph unicode="&#x215e;" horiz-adv-x="1494" d="M1185 1442h12q56 0 68 -72v-4q0 -34 -125 -179q-96 -134 -902 -1172q-25 -15 -50 -15q-68 19 -68 65v23q0 23 145 201q813 1061 878 1138q20 15 42 15zM1153 806q96 0 163 -86q39 -52 39 -114v-11q0 -85 -77 -154q111 -80 111 -202q0 -121 -111 -202q-62 -41 -130 -41 h-11q-116 0 -200 115q-36 66 -36 128q0 126 119 211q-48 37 -64 102q-6 16 -6 43v11q0 107 102 172q52 28 101 28zM1033 597q0 -80 96 -113l24 -2q83 0 114 89l5 30q0 88 -94 117l-28 2q-81 0 -113 -87zM984 241q0 -113 117 -156q16 -6 47 -6q106 0 152 117l4 32v22 q0 90 -105 140q-29 9 -53 9q-114 0 -156 -118zM143 1429h414q39 -8 39 -34v-11q0 -11 -22 -43l-403 -715q-16 -11 -28 -11h-2q-41 8 -41 41v7q6 20 376 671l4 11h-330q-44 9 -44 43q9 41 37 41z" />
-<glyph unicode="&#x2190;" horiz-adv-x="1923" d="M577 1009q67 -12 67 -67v-7q0 -48 -144 -123l-99 -60v-4h1382q67 -14 67 -67q-14 -70 -67 -70h-1382l229 -148q14 -27 14 -43v-7q-12 -63 -63 -63h-18q-34 9 -419 257q-60 20 -60 71q0 53 120 109q339 222 366 222h7z" />
-<glyph unicode="&#x2191;" horiz-adv-x="833" d="M414 1438q52 0 109 -120q221 -340 221 -365v-10q-13 -63 -63 -63h-18q-38 0 -94 108l-85 130v-1375q0 -51 -66 -63h-4q-66 12 -66 67v1375h-4q-136 -239 -165 -239l-17 -3h-18q-56 17 -56 56v17q0 23 95 169l179 291q19 19 52 25z" />
-<glyph unicode="&#x2192;" horiz-adv-x="1910" d="M1339 1009q32 0 300 -176q151 -87 183 -120l7 -25v-21q0 -38 -74 -70q-386 -247 -405 -247h-14q-64 12 -64 63v15q0 43 166 130l77 53h-1381q-56 0 -67 74q17 63 63 63h1385v4q-204 119 -236 151l-7 32v14q0 46 67 60z" />
-<glyph unicode="&#x2193;" horiz-adv-x="808" d="M400 1444q47 0 70 -59l-3 -60v-1317l149 230q24 14 42 14h4q66 -12 66 -67v-7q0 -22 -94 -167l-181 -293q-25 -21 -49 -21h-4q-50 0 -104 115q-217 334 -220 359v18q0 51 66 63h4q50 0 94 -98l94 -143v1314l-3 56q0 45 69 63z" />
-<glyph unicode="&#x2194;" horiz-adv-x="1961" d="M1378 1001h4q30 0 273 -161q180 -107 203 -129l10 -39q0 -49 -70 -77q-370 -236 -406 -248h-24q-56 18 -56 56v17q0 48 129 112q5 9 112 70v4h-1157v-4q199 -117 238 -154q10 -18 10 -35v-7q0 -54 -70 -66q-25 0 -318 189q-157 90 -165 115l-3 25v3q0 48 73 77 q362 233 406 248h7q70 -11 70 -66v-7q0 -48 -105 -98q-119 -80 -129 -80v-4h1140q-197 124 -228 151l-10 28v17q0 51 66 63z" />
-<glyph unicode="&#x2195;" horiz-adv-x="825" d="M397 1432h7q48 0 76 -72q239 -375 245 -401v-7q-14 -69 -69 -69q-54 0 -100 104l-83 124v-1118l134 211q27 24 52 24q69 -14 69 -69q0 -29 -141 -245q-127 -209 -149 -228l-31 -6h-10q-46 0 -83 89q-235 360 -235 387v3q14 69 69 69q51 0 104 -107l83 -134h3v1145h-3 q-117 -199 -152 -238l-38 -11q-60 0 -69 73v3q14 44 255 418q22 55 66 55z" />
-<glyph unicode="&#x21a8;" horiz-adv-x="879" d="M426 1432h7q48 0 76 -72q239 -375 245 -401v-7q-14 -69 -69 -69q-54 0 -100 104l-83 124v-1118l134 211q27 24 52 24q69 -14 69 -69q0 -29 -141 -245q-127 -209 -149 -228l-31 -6h-10q-46 0 -83 89q-235 360 -235 387v3q14 69 69 69q51 0 104 -107l83 -134h3v1145h-3 q-117 -199 -152 -238l-38 -11q-60 0 -69 73v3q14 44 255 418q22 55 66 55z" />
-<glyph unicode="&#x2202;" horiz-adv-x="1131" d="M117 1432q548 0 813 -468q105 -170 105 -499q0 -162 -155 -329q-156 -136 -333 -136h-23q-239 0 -410 236q-74 132 -74 263q0 265 252 430q120 66 247 66q120 0 240 -62v4q-126 219 -414 317q-116 31 -205 31l-46 -4q-50 0 -66 70v12q13 69 69 69zM183 499 q0 -216 213 -325q72 -31 143 -31q212 0 322 209q31 71 31 151q0 209 -217 322q-82 27 -136 27q-209 0 -321 -205q-35 -81 -35 -148z" />
-<glyph unicode="&#x2206;" horiz-adv-x="1144" d="M564 1443h12q61 0 84 -115q476 -1227 476 -1247v-12q0 -56 -73 -69h-990q-61 0 -73 81l507 1331q28 31 57 31zM568 1148l-380 -998h764l-380 998h-4z" />
-<glyph unicode="&#x220f;" horiz-adv-x="1378" d="M151 1443h1001q76 -14 76 -72v-4q-15 -72 -64 -72h-80v-1570h68q76 -15 76 -76q-13 -72 -68 -72v-4l-27 4h-102l-19 -4l-23 4h-102l-23 -4q-57 0 -72 80v3q0 52 76 69h68v1570h-569v-1570h68q76 -15 76 -76q-12 -72 -68 -72v-4l-27 4h-102l-19 -4l-23 4h-102l-23 -4 q-57 0 -72 80v3q0 52 76 69h68v1570h-80q-52 0 -64 80q0 51 76 68z" />
-<glyph unicode="&#x2211;" horiz-adv-x="1206" d="M137 1427h853q68 -14 68 -60v-19q0 -55 -71 -67h-685l617 -752l4 -27v-11q0 -28 -161 -209l-449 -550h681q75 -14 75 -64v-22q0 -42 -67 -64l-27 4h-796l-23 -4q-71 19 -71 64v22q0 28 161 210l505 617v4l-674 823l-7 30v11q0 49 67 64z" />
-<glyph unicode="&#x2212;" horiz-adv-x="1092" d="M162 771l40 -4h720l36 4q59 0 76 -80q0 -52 -64 -80l-68 4h-680l-64 -4q-68 24 -68 80q13 76 72 76v4z" />
-<glyph unicode="&#x221a;" horiz-adv-x="1127" d="M931 1578l38 -3h91l34 3q68 -19 68 -72v-7q0 -52 -64 -72l-61 4h-45q-8 0 -693 -1382q-23 -49 -68 -49h-4q-59 0 -106 125q-121 201 -121 235v7q0 53 79 68q51 0 95 -106l49 -91h4q643 1299 662 1321z" />
-<glyph unicode="&#x221e;" horiz-adv-x="1313" d="M408 983q136 0 251 -112q119 112 259 112q212 0 323 -237l13 -103v-4q0 -241 -264 -332l-76 -8q-140 0 -255 111q-112 -111 -255 -111q-225 0 -327 246l-13 98q0 225 246 327zM738 626q0 -114 151 -171h68q96 0 156 130l10 62q0 130 -151 187h-67q-115 0 -167 -161v-47z M194 622q0 -114 151 -171h68q96 0 156 130l10 62q0 130 -151 187h-67q-115 0 -167 -161v-47z" />
-<glyph unicode="&#x221f;" horiz-adv-x="1431" d="M157 1250q70 -18 70 -62v-1045h1038q59 0 69 -77q-19 -66 -69 -66h-1112q-55 0 -69 73v1093q8 84 73 84z" />
-<glyph unicode="&#x2229;" horiz-adv-x="1221" d="M579 1437q289 0 454 -284q49 -114 49 -208v-881q0 -49 -72 -64h-4q-71 15 -71 64v798q0 232 -103 314q-102 110 -253 110q-228 0 -329 -227q-27 -46 -27 -197v-794q0 -56 -71 -68h-4q-72 13 -72 72v873q0 248 242 420q134 72 261 72z" />
-<glyph unicode="&#x222b;" horiz-adv-x="920" d="M694 1657h15q135 0 198 -148v-7q-11 -71 -67 -71h-7q-44 0 -78 67q-18 14 -53 21q-82 0 -82 -127l-181 -1488q-73 -145 -198 -145h-18q-142 0 -205 170v4q15 67 60 67h18q47 0 74 -78q32 -25 57 -25h11q78 0 78 138l177 1474q70 148 201 148z" />
-<glyph unicode="&#x2248;" d="M325 1026h4q51 0 352 -84h28q47 0 112 64l32 8q68 -16 68 -60v-16q0 -58 -140 -120l-76 -12h-8q-49 0 -352 84h-24q-48 0 -104 -56q-22 -16 -44 -16q-68 13 -68 68v12q0 57 160 120zM345 726q41 0 352 -84h32q39 0 116 68l24 4q68 -14 68 -68v-8q0 -61 -152 -124l-60 -8 h-28q-30 0 -340 84h-8q-62 0 -116 -56q-21 -16 -44 -16q-68 14 -68 60v16q0 43 76 84q69 48 148 48z" />
-<glyph unicode="&#x2260;" horiz-adv-x="1028" d="M444 677h-232q-65 0 -76 84q20 72 76 72h232v119q0 52 66 61h4q66 -9 66 -65v-115h244q59 0 76 -80q-18 -76 -76 -76h-244v-176h240q80 -16 80 -80q-16 -76 -76 -76h-244v-118q-10 -69 -66 -69h-7q-63 10 -63 67v120h-240q-56 0 -68 84q0 54 80 72h228v176z" />
-<glyph unicode="&#x2261;" horiz-adv-x="1161" d="M151 281l40 -4h720l36 4q59 0 76 -80q0 -52 -64 -80l-68 4h-680l-64 -4q-68 24 -68 80q13 76 72 76v4zM156 1060l40 -4h720l36 4q59 0 76 -80q0 -52 -64 -80l-68 4h-680l-64 -4q-68 24 -68 80q13 76 72 76v4zM156 672l40 -4h720l36 4q59 0 76 -80q0 -52 -64 -80l-68 4 h-680l-64 -4q-68 24 -68 80q13 76 72 76v4z" />
-<glyph unicode="&#x2264;" d="M813 1156q76 -16 76 -76v-8q0 -55 -96 -100l-464 -288l540 -344q20 -22 20 -48v-12q0 -61 -80 -72q-32 0 -144 76l-548 344q-20 28 -20 52q0 60 148 132q537 344 556 344h12zM157 156h668q53 0 64 -72v-12q-13 -72 -60 -72h-664q-59 0 -68 80q13 76 60 76z" />
-<glyph unicode="&#x2265;" d="M190 1161q34 0 316 -188q350 -209 384 -244q12 -20 12 -40v-16q0 -44 -120 -104q-556 -352 -568 -352l-28 -4q-76 12 -76 76v4q0 61 136 124l424 268v4q-503 307 -540 340q-20 23 -20 60q0 53 80 72zM170 161h668q52 0 64 -68v-16q-13 -72 -60 -72h-672q-48 0 -60 80 q12 76 60 76z" />
-<glyph unicode="&#xf001;" horiz-adv-x="1021" d="M590 1436q186 0 298 -189l15 -53q0 -56 -75 -72q-55 0 -95 95q-66 68 -147 68q-115 0 -170 -129l-12 -86v-69h163l60 4q48 0 65 -72v-11q0 -47 -68 -64h-220v-748l4 -42q0 -51 -75 -68q-52 0 -76 64l4 46v748h-197q-52 0 -64 79q0 38 60 68l76 -4h121v72q0 246 212 337 q37 19 121 26zM831 1039q76 -15 76 -75v-888q-13 -72 -72 -72h-4q-71 14 -71 64v899q15 72 71 72z" />
-<glyph unicode="&#xfb01;" horiz-adv-x="1021" d="M590 1436q186 0 298 -189l15 -53q0 -56 -75 -72q-55 0 -95 95q-66 68 -147 68q-115 0 -170 -129l-12 -86v-69h163l60 4q48 0 65 -72v-11q0 -47 -68 -64h-220v-748l4 -42q0 -51 -75 -68q-52 0 -76 64l4 46v748h-197q-52 0 -64 79q0 38 60 68l76 -4h121v72q0 246 212 337 q37 19 121 26zM831 1039q76 -15 76 -75v-888q-13 -72 -72 -72h-4q-71 14 -71 64v899q15 72 71 72z" />
-<glyph unicode="&#xf002;" horiz-adv-x="1081" d="M592 1443q188 0 300 -190l16 -42l-4 -45v-1014h79q50 0 65 -72v-4q-13 -72 -72 -72h-148q-58 0 -72 76v1101q-34 98 -167 110q-115 0 -171 -129l-12 -87v-69h164l60 4q49 0 65 -72v-12q0 -47 -68 -64h-221v-752l4 -42q0 -51 -76 -68q-52 0 -76 65l4 45v752h-197 q-53 0 -65 80q0 38 61 68l76 -4h121v72q0 248 213 338q38 19 121 27z" />
-<glyph unicode="&#xfb02;" horiz-adv-x="1081" d="M592 1443q188 0 300 -190l16 -42l-4 -45v-1014h79q50 0 65 -72v-4q-13 -72 -72 -72h-148q-58 0 -72 76v1101q-34 98 -167 110q-115 0 -171 -129l-12 -87v-69h164l60 4q49 0 65 -72v-12q0 -47 -68 -64h-221v-752l4 -42q0 -51 -76 -68q-52 0 -76 65l4 45v752h-197 q-53 0 -65 80q0 38 61 68l76 -4h121v72q0 248 213 338q38 19 121 27z" />
-<glyph horiz-adv-x="0" />
-</font>
-</defs></svg> 
\ No newline at end of file
diff --git a/hubs/static/css/fonts/Comfortaa_Regular-webfont.ttf b/hubs/static/css/fonts/Comfortaa_Regular-webfont.ttf
deleted file mode 100644
index b3f207e..0000000
Binary files a/hubs/static/css/fonts/Comfortaa_Regular-webfont.ttf and /dev/null differ
diff --git a/hubs/static/css/fonts/Comfortaa_Regular-webfont.woff b/hubs/static/css/fonts/Comfortaa_Regular-webfont.woff
deleted file mode 100644
index 59c5767..0000000
Binary files a/hubs/static/css/fonts/Comfortaa_Regular-webfont.woff and /dev/null differ
diff --git a/hubs/static/css/fonts/Comfortaa_Thin-webfont.eot b/hubs/static/css/fonts/Comfortaa_Thin-webfont.eot
deleted file mode 100644
index 46a6295..0000000
Binary files a/hubs/static/css/fonts/Comfortaa_Thin-webfont.eot and /dev/null differ
diff --git a/hubs/static/css/fonts/Comfortaa_Thin-webfont.svg b/hubs/static/css/fonts/Comfortaa_Thin-webfont.svg
deleted file mode 100644
index e099110..0000000
--- a/hubs/static/css/fonts/Comfortaa_Thin-webfont.svg
+++ /dev/null
@@ -1,505 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata>
-This is a custom SVG webfont generated by Font Squirrel.
-Designer    : Johan Aakerlund - aajohan
-Foundry     : Johan Aakerlund
-</metadata>
-<defs>
-<font id="webfontReo2lGxG" horiz-adv-x="1014" >
-<font-face units-per-em="2048" ascent="1638" descent="-410" />
-<missing-glyph horiz-adv-x="508" />
-<glyph unicode=" "  horiz-adv-x="508" />
-<glyph unicode="&#x09;" horiz-adv-x="508" />
-<glyph unicode="&#xa0;" horiz-adv-x="508" />
-<glyph unicode="!" horiz-adv-x="511" d="M189 1417h12q39 0 48 -46v-950q-12 -50 -51 -50q-57 9 -57 44v959q9 43 48 43zM180 181h6q80 -12 80 -67v-22q0 -51 -73 -67h-9q-59 0 -74 78q16 78 70 78z" />
-<glyph unicode="&#x22;" horiz-adv-x="557" d="M131 1534q54 -14 54 -42q-20 -288 -31 -288l-28 -8q-22 0 -27 101l-20 181q11 56 52 56zM384 1534q30 0 44 -53q-26 -269 -28 -269q-17 -16 -22 -16h-4q-31 0 -31 112l-20 184q0 32 61 42z" />
-<glyph unicode="#" horiz-adv-x="1336" d="M968 1406q46 -13 46 -39v-11q0 -26 -82 -414h142l34 4q34 0 44 -51q-9 -50 -49 -50h-191l-46 -242h168q63 -6 63 -49q-10 -48 -72 -48v2l9 -2h-190q-86 -436 -98 -461q-17 -22 -39 -22h-5q-45 9 -45 43v1l89 439h-246q-31 0 -78 -266q-38 -189 -45 -193q-20 -28 -41 -28 q-53 11 -53 48l89 439h-135l-22 -4q-34 0 -45 56v2q0 31 53 43h173l47 242h-164q-52 10 -52 48q8 49 67 49v1l12 -1h158q82 438 86 438q28 22 48 22q39 0 46 -49l-80 -411h270q82 430 92 443q20 21 42 21zM543 845l-47 -242h270l46 242h-269z" />
-<glyph unicode="$" d="M452 1627h20q29 0 40 -51v-148q107 -8 216 -107q36 -35 36 -48v-23q0 -29 -51 -37q-17 0 -77 66q-38 32 -124 59v-511q184 -68 255 -201q55 -103 55 -196q0 -262 -269 -379l-41 -7v-145q-13 -52 -46 -52q-54 11 -54 49v104q0 28 -108 43q-163 56 -231 167l-2 14 q9 49 49 49q28 0 91 -79q95 -62 201 -70v625q-142 44 -188 111q-95 98 -95 223v28q0 175 181 283q57 28 102 28v161q13 44 40 44zM226 1091v-31q0 -139 186 -240v496q-186 -91 -186 -225zM512 714v-581h35q174 102 174 257v39q0 157 -209 285z" />
-<glyph unicode="%" horiz-adv-x="1610" d="M427 1411h19q155 0 264 -142q63 -93 63 -190q0 -217 -226 -320q-63 -18 -105 -18h-7q-195 0 -300 191q-35 71 -35 144q0 220 234 321q46 14 93 14zM1261 1411h8q46 -9 46 -44v-15q0 -13 -135 -186l-857 -1131q-18 -10 -28 -10h-1q-50 10 -50 39v16q0 22 101 143l892 1179 q13 9 24 9zM198 1081v-9q0 -168 186 -230l42 -3h20q165 0 226 190l4 46q0 173 -182 233l-53 9q-172 0 -235 -178zM1124 698q196 0 310 -204q25 -74 25 -130v-12q0 -196 -208 -302q-64 -25 -127 -25h-7q-171 0 -282 166q-46 80 -46 157v23q0 176 177 285q85 42 158 42z M883 365q0 -168 175 -234l57 -8h17q161 0 225 182l4 39v27q0 168 -194 226l-42 4q-179 0 -238 -198z" />
-<glyph unicode="&#x26;" horiz-adv-x="1457" d="M465 1408h19q177 0 261 -195q10 -43 10 -75v-19q0 -134 -147 -252l-56 -60l347 -347h24l161 162q18 13 33 13q48 0 55 -60q0 -30 -126 -140l-58 -64l232 -233q9 -11 9 -24v-9q-10 -50 -47 -50h-11q-31 0 -123 106l-140 137q-226 -246 -288 -246q-66 -27 -128 -27 q-206 0 -327 206q-35 83 -35 160q0 182 204 349l64 69q-196 183 -196 282q-8 0 -8 43q0 171 185 261q48 13 86 13zM304 1152v-33q0 -89 160 -223h22q164 142 164 223v15q0 112 -133 165l-43 4q-109 0 -162 -116zM239 400v-21q0 -164 186 -236l61 -9q145 0 271 160l77 78 l-347 347h-23q-221 -196 -221 -288z" />
-<glyph unicode="'" horiz-adv-x="346" d="M144 1521q54 -14 54 -42q-20 -288 -31 -288l-28 -8q-22 0 -27 101l-20 181q11 56 52 56z" />
-<glyph unicode="(" horiz-adv-x="758" d="M578 1571h9q46 -9 46 -43v-7l-74 -199q-133 -358 -133 -733q0 -468 208 -923l2 -8q-9 -51 -47 -51h-7q-46 0 -80 121q-175 406 -175 865q0 492 218 962q17 16 33 16z" />
-<glyph unicode=")" horiz-adv-x="758" d="M114 1575h15q35 0 73 -122q174 -415 174 -857q0 -521 -223 -976q-17 -11 -31 -11h-8q-38 0 -47 49l79 196q131 373 131 738q0 458 -208 924l-2 8q9 51 47 51z" />
-<glyph unicode="*" horiz-adv-x="1024" d="M497 1533q51 -13 51 -50v-4l-52 -168v-33h36l162 101l15 3q51 -11 51 -51v-12q0 -25 -40 -43l-119 4h-142l201 -164l8 -22v-15q0 -38 -53 -47q-49 0 -62 93l-38 115h-41l-52 -178q-20 -30 -46 -30q-54 12 -54 43v16q0 33 81 79l130 110h-72l-191 -4q-40 16 -40 51v4 q0 40 57 51q19 0 121 -76l86 -43v48l-52 168v4q0 39 55 50z" />
-<glyph unicode="+" d="M487 1092h12q38 0 47 -53v-247h236q68 -6 68 -53q-11 -53 -76 -53v1l7 -1h-235v-251q-10 -53 -51 -53h-2q-53 11 -53 43v261h-231l-24 -4q-37 0 -49 61v2q0 34 58 47h246v251q10 49 47 49z" />
-<glyph unicode="," horiz-adv-x="557" d="M229 257h13q114 -23 114 -121l-6 6l6 6v-16l8 -56v-14q0 -169 -171 -254q-32 -21 -48 -21q-21 0 -27 37q0 25 68 38q50 29 97 92l32 88l-86 -15q-123 21 -123 119v4q0 65 89 101q12 6 34 6z" />
-<glyph unicode="-" horiz-adv-x="670" d="M119 623h400q38 0 50 -55q-12 -51 -50 -51h-400q-44 0 -51 57q14 49 51 49z" />
-<glyph unicode="&#xad;" horiz-adv-x="670" d="M119 623h400q38 0 50 -55q-12 -51 -50 -51h-400q-44 0 -51 57q14 49 51 49z" />
-<glyph unicode="." horiz-adv-x="557" d="M244 249q85 0 110 -103v-21q0 -59 -82 -95q-9 -5 -28 -5h-4q-91 0 -110 116q0 69 85 103q10 5 29 5z" />
-<glyph unicode="/" horiz-adv-x="770" d="M601 1492q53 -9 53 -47v-16q-503 -1384 -553 -1506q-19 -21 -38 -21h-8q-41 0 -51 55q3 21 552 1510q24 25 45 25z" />
-<glyph unicode="0" horiz-adv-x="989" d="M421 1412q231 0 355 -249q70 -216 70 -399v-87q0 -226 -92 -453q-129 -199 -325 -199h-12q-213 0 -336 228q-81 207 -81 462v11q0 271 95 487q132 199 326 199zM86 737v-41q0 -267 99 -453q101 -124 229 -124h11q278 0 324 414q11 63 15 189q0 224 -78 431 q-103 165 -261 165q-192 0 -281 -209q-58 -194 -58 -372z" />
-<glyph unicode="1" horiz-adv-x="568" d="M284 1412h5q46 -10 46 -40v-1298q-9 -49 -47 -49h-1q-50 10 -50 39v1233q-131 -44 -158 -44t-39 47v16q0 36 133 63z" />
-<glyph unicode="2" horiz-adv-x="976" d="M406 1411q192 0 335 -172q74 -112 74 -234q0 -186 -186 -361l-456 -522h618q35 0 43 -48q-7 -49 -47 -49h-731q-48 9 -48 47v4q0 25 64 85l588 670q54 77 54 174q0 209 -217 292q-37 12 -84 12h-11q-201 0 -289 -213q-12 -45 -16 -99q-17 -35 -43 -35h-5q-49 9 -49 43 q0 213 203 349q108 57 203 57z" />
-<glyph unicode="3" horiz-adv-x="955" d="M421 1407q155 0 269 -141q63 -85 63 -188v-15q0 -145 -151 -277q211 -153 211 -356q0 -210 -199 -349q-102 -56 -202 -56h-11q-237 0 -369 245q-32 90 -32 163q0 32 56 43q33 0 41 -52q0 -175 185 -277q68 -25 130 -25q185 0 279 192q21 59 21 101v30q0 175 -194 272 l-121 26q-24 18 -24 41v4q0 46 77 46q86 0 175 110q34 71 34 130q0 137 -133 210q-49 26 -110 26q-157 0 -224 -170q-10 -90 -13 -90q-27 -30 -39 -30q-53 12 -53 39v19q0 182 183 291q69 34 151 38z" />
-<glyph unicode="4" horiz-adv-x="1103" d="M693 1400h23q23 0 39 -42l-4 -33v-778h143l34 3q32 0 45 -53q0 -31 -43 -47l-51 4h-128v-390q0 -29 -49 -39h1q-49 9 -49 46v383h-533l-85 -4q-36 15 -36 43v15q0 14 31 38q605 787 637 838q15 16 25 16zM153 547h501v652z" />
-<glyph unicode="5" d="M135 1404l35 -4h576q39 0 50 -55q0 -36 -57 -48h-546v-429h240q237 0 372 -245q42 -101 42 -177q0 -218 -208 -362q-106 -59 -210 -59h-12q-246 0 -384 255q-33 97 -33 158q18 50 53 50q58 0 58 -112q54 -159 167 -215q85 -33 143 -33q213 0 301 215q18 44 18 103 q0 232 -247 311l-94 8h-263q-33 0 -46 42v555q0 25 45 42z" />
-<glyph unicode="6" horiz-adv-x="951" d="M544 1411q31 0 43 -54q0 -20 -87 -157l-192 -334v-38l83 6h32q193 0 330 -195q60 -108 60 -209q0 -201 -185 -337q-104 -68 -216 -68h-19q-192 0 -333 192q-60 109 -60 213q0 137 102 272l404 697q20 12 38 12zM101 449v-38q0 -170 193 -268q54 -17 110 -21 q208 0 296 218l12 76v17q0 216 -235 297l-75 7q-203 0 -293 -222z" />
-<glyph unicode="7" horiz-adv-x="964" d="M80 1404h725q46 -9 46 -35v-19q0 -12 -34 -63l-707 -1251q-17 -11 -30 -11h-1q-49 9 -49 47v8q8 29 658 1172l20 55h-614q-53 11 -53 47q11 50 39 50z" />
-<glyph unicode="8" horiz-adv-x="972" d="M422 1414q159 0 271 -142q63 -86 63 -189v-19q0 -139 -151 -275q212 -153 212 -357q0 -202 -186 -339q-104 -68 -217 -68h-19q-193 0 -335 192q-60 110 -60 215q0 211 229 373q-105 81 -132 191q-10 25 -10 68v19q0 176 170 284q84 47 165 47zM185 1069q0 -162 190 -227 l46 -4q168 0 229 178l9 57q0 178 -187 235l-53 4q-164 0 -227 -174zM98 437q0 -219 224 -301q32 -13 92 -13q205 0 293 227l9 61v40q0 177 -202 272q-57 18 -104 18q-221 0 -300 -228z" />
-<glyph unicode="9" horiz-adv-x="972" d="M406 1410q211 0 345 -202q57 -107 57 -200q0 -152 -126 -299l-500 -672q-17 -12 -29 -12q-52 10 -52 50q0 25 115 165l269 366h-55l-22 -4q-230 0 -362 219q-46 96 -46 187q0 224 219 356q95 46 187 46zM100 1023v-34q0 -164 179 -262q56 -25 127 -25q177 0 269 166 q33 63 33 136v4q0 208 -214 289q-32 13 -84 13h-23q-175 0 -270 -196q-17 -59 -17 -91z" />
-<glyph unicode=":" horiz-adv-x="557" d="M267 927q71 0 99 -83v-28q0 -57 -83 -87h-14q-101 15 -101 97q20 101 99 101zM255 259h16q75 0 95 -90v-17q0 -67 -96 -90q-102 17 -102 99q21 98 87 98z" />
-<glyph unicode=";" horiz-adv-x="557" d="M242 901q71 0 99 -83v-28q0 -57 -83 -87h-14q-101 15 -101 97q20 101 99 101zM266 233q103 0 103 -167v-4q0 -168 -203 -235h-13q-26 5 -26 23v13q7 26 29 26l30 -5q121 64 121 165l-39 -13q-105 16 -105 98q0 70 79 99h24z" />
-<glyph unicode="&#x37e;" horiz-adv-x="557" d="M242 901q71 0 99 -83v-28q0 -57 -83 -87h-14q-101 15 -101 97q20 101 99 101zM266 233q103 0 103 -167v-4q0 -168 -203 -235h-13q-26 5 -26 23v13q7 26 29 26l30 -5q121 64 121 165l-39 -13q-105 16 -105 98q0 70 79 99h24z" />
-<glyph unicode="&#x3c;" d="M802 1077q54 -14 54 -51v-8q0 -41 -125 -101q-6 -10 -450 -282q41 -42 560 -364q15 -18 15 -37v-4q0 -43 -57 -51q-21 0 -132 76l-534 330q-19 22 -19 41q0 43 99 86q566 365 584 365h5z" />
-<glyph unicode="=" d="M187 808h612q39 0 50 -55q-12 -51 -50 -51h-612q-43 0 -51 57q14 49 51 49zM194 476h599q57 -11 57 -52q-11 -54 -51 -54h-620q-34 0 -43 61q0 32 58 45z" />
-<glyph unicode="&#x3e;" d="M192 1095q22 0 223 -132q426 -263 455 -288q9 -12 9 -27v-8q0 -39 -83 -74q-578 -369 -592 -369h-14q-53 10 -53 51v4q0 42 115 98l467 298q-547 336 -568 356q-14 20 -14 34q11 57 55 57z" />
-<glyph unicode="?" horiz-adv-x="980" d="M472 1408q169 0 307 -150q96 -121 96 -264q0 -178 -159 -316q-186 -102 -186 -300q-8 -52 -47 -52q-50 11 -50 39v30q0 222 241 370q103 103 103 240q0 176 -185 280q-82 25 -131 25q-182 0 -285 -194l-26 -127q-21 -27 -38 -27q-54 11 -54 47q0 192 190 335 q115 64 224 64zM471 173h13q48 0 69 -62v-20q-14 -72 -78 -72q-76 16 -76 73q0 67 72 81z" />
-<glyph unicode="@" horiz-adv-x="2019" d="M911 1546h36q405 0 705 -347q206 -264 206 -580q0 -389 -261 -493q-66 -30 -134 -30h-28q-123 0 -140 35l-3 14l4 98v62q-211 -201 -405 -201h-32q-266 0 -442 268q-65 128 -65 259q0 292 287 462q122 57 236 57q297 0 470 -291q53 -117 53 -244v-406l51 -7 q166 0 257 162q42 103 42 223v52q0 336 -280 599q-245 202 -537 202q-431 0 -697 -379q-128 -207 -128 -442v-4q0 -390 322 -652q230 -169 503 -169q230 0 457 137l11 3q55 -11 55 -55q0 -79 -317 -168q-91 -23 -178 -23h-52q-337 0 -623 257q-288 290 -288 678 q0 394 320 693q272 230 595 230zM458 635v-12q0 -253 255 -383q82 -30 146 -30h32q213 0 350 213q51 100 51 192v16q0 245 -242 374q-85 39 -175 39h-4q-258 0 -387 -268q-26 -83 -26 -141z" />
-<glyph unicode="A" horiz-adv-x="1191" d="M531 1403q49 0 78 -121q454 -1181 457 -1205v-9q0 -35 -48 -43h-2q-46 0 -70 110l-176 457h-474l-210 -553q-17 -14 -32 -14h-6q-48 9 -48 46l126 341q336 874 363 965q23 26 42 26zM514 1167l-177 -478h384v34l-169 444h-38z" />
-<glyph unicode="B" horiz-adv-x="998" d="M127 1402l-9 2h234l15 3q158 0 272 -152q56 -83 56 -181v-11q0 -120 -116 -252q259 -143 259 -385q0 -243 -253 -373q-80 -28 -144 -28h-337q-49 9 -49 47v1283q7 49 72 49v-2zM152 1307v-473h164q202 0 261 148q17 42 17 85v11q0 164 -191 225l-82 4h-169zM152 737v-615 h221q230 0 311 135q53 75 53 169v7q0 221 -242 297l-110 7h-233z" />
-<glyph unicode="C" horiz-adv-x="1363" d="M752 1411q215 0 397 -128q9 -18 9 -28v-8q0 -41 -55 -47h3l-128 66q-138 44 -226 44q-281 0 -486 -257q-102 -172 -102 -335q0 -329 308 -521q137 -71 273 -71h11q173 0 343 106h13q46 -10 46 -43v-11q0 -61 -235 -131q-76 -22 -159 -22h-19q-342 0 -573 318 q-109 183 -109 375q0 360 329 587q175 106 360 106z" />
-<glyph unicode="D" horiz-adv-x="1195" d="M127 1410l-9 2h197l42 4q310 0 541 -272q146 -190 146 -431q0 -332 -293 -560q-185 -128 -391 -128h-256q-49 9 -49 47v1291q7 49 72 49v-2zM153 1318v-1195h188q376 0 558 364q47 124 47 237q0 273 -240 474q-150 120 -441 120h-112z" />
-<glyph unicode="E" horiz-adv-x="1094" d="M135 1411l-9 2h750l15 4q40 0 48 -57q-10 -45 -58 -45h-720v-562h481l54 4q30 0 42 -54q0 -30 -40 -48l-71 4h-466v-536h738q31 0 39 -53q-13 -45 -42 -45h-784q-49 9 -49 47v1292q7 49 72 49v-2z" />
-<glyph unicode="F" horiz-adv-x="1031" d="M127 1411l-9 2h750l15 4q40 0 48 -57q-10 -45 -58 -45h-720v-562h481l54 4q30 0 42 -54q0 -30 -40 -48l-71 4h-466v-566l3 -20q-11 -48 -46 -48h-6q-49 9 -49 47v1292q7 49 72 49v-2z" />
-<glyph unicode="G" horiz-adv-x="1292" d="M720 1411q221 0 394 -121q12 -16 12 -31v-4q0 -37 -53 -47q-4 0 -135 62q-93 36 -180 36h-61q-222 0 -423 -213q-131 -179 -131 -367v-15q0 -307 284 -501q148 -84 297 -84h15q146 0 305 86v384h-296q-48 8 -48 47v1q8 49 46 49h352q35 0 43 -49v-417q0 -76 -32 -92 q-188 -110 -363 -110h-22q-342 0 -573 318q-109 179 -109 375q0 348 310 576q190 117 368 117z" />
-<glyph unicode="H" horiz-adv-x="1186" d="M85 1408h12q46 -9 46 -35v-623h762v610q8 48 43 48h9q45 -9 45 -43v-1301q0 -29 -50 -39h1q-48 9 -48 47v585h-762v-589q0 -35 -48 -43h-2q-37 0 -47 53v1271q6 59 39 59z" />
-<glyph unicode="I" horiz-adv-x="539" d="M109 1422l15 -2h146l13 2q51 -10 51 -48q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-178q-49 9 -49 47v1q10 51 40 51h48v1197h-41q-41 0 -47 56v3q0 28 49 42z" />
-<glyph unicode="J" horiz-adv-x="1022" d="M837 1414h12q34 0 43 -49v-921q0 -225 -212 -362q-99 -57 -203 -57h-19q-207 0 -348 202q-64 106 -64 218q11 50 40 50h15q47 0 47 -94q7 -92 107 -199q99 -79 214 -79q229 0 313 237q12 45 12 88v921q9 45 43 45z" />
-<glyph unicode="K" horiz-adv-x="1112" d="M109 1409h1q49 -8 49 -43v-713q735 734 733 734l27 4h3q45 -9 45 -43v-12q0 -25 -71 -83l-482 -485l543 -672l2 -15v-9q0 -35 -48 -43h-2q-32 0 -105 107l-463 562l-182 -186v-444q0 -35 -49 -43h-1q-37 0 -47 52v1280q10 52 47 52z" />
-<glyph unicode="L" horiz-adv-x="997" d="M85 1408h12q46 -9 46 -35v-1251h642q39 0 46 -52q-13 -45 -46 -45h-692q-37 0 -47 53v1271q6 59 39 59z" />
-<glyph unicode="M" horiz-adv-x="1490" d="M99 1407h15q39 0 59 -81l497 -1111q47 55 366 784l184 396q12 12 28 12h15q33 0 39 -59v-1270q-10 -53 -47 -53h-2q-48 8 -48 43v966h-45q-429 -973 -441 -992q-20 -17 -38 -17q-48 0 -94 143l-385 862h-45v-962q0 -35 -48 -43h-2q-37 0 -47 53v1270q6 59 39 59z" />
-<glyph unicode="N" horiz-adv-x="1321" d="M77 1406h15q32 0 62 -64q58 -65 830 -1062q-5 0 -5 6l16 -21h41v1096q9 45 43 45h11q35 0 43 -48v-1283q0 -41 -56 -50q-28 0 -110 122l-832 1062v-1137q0 -35 -49 -43h-1q-37 0 -47 52v1266q6 59 39 59z" />
-<glyph unicode="O" horiz-adv-x="1595" d="M731 1410q350 0 586 -325q106 -184 106 -371q0 -346 -314 -576q-177 -113 -371 -113h-15q-357 0 -583 333q-102 167 -102 363q0 331 292 558q189 131 401 131zM135 710q0 -286 252 -481q158 -107 336 -107h19q280 0 473 248q111 160 111 348q0 323 -295 511 q-146 84 -300 84q-295 0 -489 -256q-107 -154 -107 -347z" />
-<glyph unicode="P" horiz-adv-x="963" d="M85 1413h346q189 0 323 -197q50 -100 50 -180v-27q0 -177 -161 -306q-109 -75 -212 -75h-287v-560q0 -34 -49 -43h-2q-37 0 -47 53v1275q6 60 39 60zM144 1315v-589h260q207 0 285 198q17 42 17 100q0 183 -186 270q-47 21 -108 21h-268z" />
-<glyph unicode="Q" horiz-adv-x="1599" d="M739 1410q350 0 587 -325q105 -183 105 -371q0 -225 -155 -434v-22q159 -156 159 -179v-7q0 -36 -54 -47q-29 0 -122 114q-28 22 -53 64q-228 -178 -460 -178h-15q-356 0 -583 333q-102 167 -102 363q0 331 292 558q190 131 401 131zM143 710q0 -286 252 -481 q158 -107 336 -107h19q197 0 381 147q-170 184 -182 203v17q9 45 43 45h11q26 0 106 -98l80 -80h28q117 180 117 362q0 323 -295 512q-145 83 -300 83q-295 0 -489 -256q-107 -154 -107 -347z" />
-<glyph unicode="R" horiz-adv-x="976" d="M81 1410h315q187 0 307 -199q38 -76 38 -159v-15q0 -185 -181 -303l-59 -31q354 -610 354 -616v-19q0 -35 -49 -43h-2q-38 0 -91 116l-319 543h-254v-616q0 -35 -49 -43h-2q-37 0 -47 53v1272q6 60 39 60zM140 1316v-535h240q198 0 260 213l4 34v32q0 158 -175 239 q-50 17 -149 17h-180z" />
-<glyph unicode="S" horiz-adv-x="926" d="M428 1412q174 0 287 -154l2 -8v-20q0 -28 -50 -36q-16 0 -84 75q-75 48 -143 48h-23q-141 0 -213 -148q-18 -37 -18 -76v-31q0 -162 196 -235q122 0 260 -112q132 -134 132 -295q0 -197 -169 -324q-103 -71 -230 -71q-204 0 -336 173l-5 21q8 46 47 46q28 0 86 -73 q104 -72 189 -72h34q167 0 269 188q16 62 16 93v38q0 166 -187 268l-195 54q-203 116 -203 305v27q0 185 200 290q74 29 138 29z" />
-<glyph unicode="T" horiz-adv-x="1225" d="M77 1411h931q45 -9 45 -43v-15q0 -33 -59 -39h-400v-1246q0 -35 -49 -43h-1q-37 0 -47 53v1236h-406q-53 11 -53 47q11 50 39 50z" />
-<glyph unicode="U" horiz-adv-x="1168" d="M79 1408h12q46 -9 46 -35v-806q0 -274 159 -369q98 -76 222 -76q237 0 356 243q25 76 25 157v838q8 48 43 48h9q45 -9 45 -43v-881q0 -213 -206 -373q-129 -86 -261 -86h-26q-223 0 -388 220q-75 117 -75 292v812q6 59 39 59z" />
-<glyph unicode="V" horiz-adv-x="1246" d="M91 1416q41 0 76 -141l379 -1004h37l421 1126q20 19 40 19h4q37 0 46 -49l-476 -1284q-13 -58 -52 -58h-3q-48 0 -79 130q-450 1188 -450 1206v8q0 38 57 47z" />
-<glyph unicode="W" horiz-adv-x="1777" d="M76 1411h16q43 0 59 -95l286 -992h45q296 1046 312 1070q16 17 33 17h11q46 0 63 -117q28 -76 282 -974h42l311 1070q16 21 30 21h13q45 -9 45 -35v-15l-380 -1318q-19 -18 -38 -18h-4q-49 0 -66 120q-247 838 -282 979h-41l-311 -1078q-17 -21 -39 -21h-15 q-40 0 -59 124q-325 1107 -351 1215q10 47 38 47z" />
-<glyph unicode="X" horiz-adv-x="1300" d="M68 1412h16q29 0 51 -44l446 -571l475 610q9 5 21 5h12q34 0 43 -49v-1q0 -24 -96 -136l-396 -509l486 -622l6 -22v1q-9 -49 -47 -49h-4q-33 0 -62 60l-438 559l-477 -611q-10 -8 -24 -8h-2q-49 9 -49 47v11q0 16 158 208l334 433q-481 609 -489 627l-3 14q11 47 39 47z " />
-<glyph unicode="Y" horiz-adv-x="1153" d="M81 1408h16q32 0 56 -59l354 -529h31q377 569 388 578q14 10 20 10h23q26 0 39 -50q0 -21 -125 -192l-311 -464v-618q-7 -59 -39 -59h-16q-31 0 -43 40v617q0 22 -164 265l-266 400l-2 13q11 48 39 48z" />
-<glyph unicode="Z" horiz-adv-x="1271" d="M73 1412h1021q34 0 43 -49v-1q0 -20 -77 -110l-874 -1129h902q49 -7 49 -47v-2q-9 -49 -47 -49h-1009q-38 0 -47 57q0 17 177 237l771 996h-895q-53 11 -53 47q11 50 39 50z" />
-<glyph unicode="[" horiz-adv-x="779" d="M319 1553l14 -1h294l40 4q50 -18 50 -47v-12q0 -33 -43 -51l-63 4h-258v-1742h314q50 -11 50 -43v-12q0 -44 -60 -51h-353q-57 11 -57 55v1831q5 64 72 64v1z" />
-<glyph unicode="\" horiz-adv-x="691" d="M50 1523h4q57 0 92 -154l507 -1383q-10 -53 -51 -53h-16q-41 0 -80 150q-472 1273 -506 1387q8 53 50 53z" />
-<glyph unicode="]" horiz-adv-x="758" d="M73 1556l55 -4h278l41 4q49 -14 49 -51v-1860q0 -32 -53 -43h-366q-44 0 -51 60v3q0 30 52 46l17 -3h295v1742h-246l-72 -4q-46 16 -46 55q0 38 47 55z" />
-<glyph unicode="^" horiz-adv-x="942" d="M364 1409h11q38 0 90 -104q229 -346 229 -359v-24q0 -34 -61 -43q-33 0 -117 156l-150 220l-236 -365q-23 -11 -39 -11q-34 0 -47 58q0 21 76 131q204 323 218 331z" />
-<glyph unicode="_" horiz-adv-x="958" d="M50 -54h882q52 -9 52 -45v-10q-10 -47 -45 -47h-889q-42 0 -49 55q13 47 49 47z" />
-<glyph unicode="`" horiz-adv-x="752" d="M261 1386h9q27 0 90 -76q173 -163 173 -177l3 -18q-10 -51 -50 -51h-8q-33 0 -146 129q-121 104 -121 138v12q0 32 50 43z" />
-<glyph unicode="a" horiz-adv-x="1199" d="M529 998q276 0 437 -271q49 -108 49 -227v-433q0 -34 -48 -42h-2q-31 0 -46 36v-2l4 93v63q-200 -190 -380 -190h-29q-247 0 -412 249q-60 119 -60 241q0 271 267 430q113 53 220 53zM138 519v-11q0 -238 239 -359q77 -28 137 -28h29q200 0 329 199q47 94 47 180v15 q0 230 -226 351q-80 36 -164 36h-4q-242 0 -363 -251q-24 -78 -24 -132z" />
-<glyph unicode="b" horiz-adv-x="1230" d="M119 1407h5q46 -10 46 -40v-550q200 193 396 193q189 0 344 -144q148 -155 148 -348q0 -277 -263 -436q-113 -57 -218 -57h-30q-198 0 -370 187q-104 139 -104 332v823q0 30 46 40zM170 529v-19q0 -247 258 -367q70 -21 126 -21h23q241 0 364 258q20 79 20 122v23 q0 246 -263 368q-80 20 -125 20h-15q-241 0 -363 -253q-25 -73 -25 -131z" />
-<glyph unicode="c" horiz-adv-x="1036" d="M522 1001q188 0 340 -140q6 -10 6 -22v-2q-9 -48 -46 -48h-4q-19 0 -107 67q-90 46 -178 46h-22q-234 0 -353 -244q-28 -83 -28 -149q0 -237 244 -360q74 -28 156 -28q138 0 266 107l21 5h9q34 0 42 -48v-1q0 -60 -222 -145q-76 -14 -113 -14h-30q-196 0 -365 186 q-104 146 -104 302q0 238 211 400q134 88 277 88z" />
-<glyph unicode="d" horiz-adv-x="1200" d="M957 1407h12q46 -9 46 -36v-748l4 -128q0 -140 -115 -294q-163 -176 -366 -176h-30q-198 0 -369 187q-105 148 -105 306q0 239 213 403q135 89 280 89q187 0 395 -186v484l-4 56q14 43 39 43zM131 529v-19q0 -247 258 -367q70 -21 126 -21h23q241 0 364 258q20 79 20 122 v23q0 246 -263 368q-80 20 -125 20h-15q-241 0 -363 -253q-25 -73 -25 -131z" />
-<glyph unicode="e" horiz-adv-x="1166" d="M518 1000q282 0 438 -268q53 -104 53 -227v-17q-9 -52 -46 -52h-822q56 -191 213 -276q91 -35 171 -35q93 0 205 56h14q44 -9 44 -43v-11q0 -70 -246 -102h-24q-262 0 -421 246q-63 115 -63 242q0 267 253 426q123 61 231 61zM134 532h772q0 110 -96 241 q-132 124 -262 124h-41q-193 0 -317 -188q-43 -75 -56 -177z" />
-<glyph unicode="f" horiz-adv-x="866" d="M575 1412h89q30 0 39 -57q0 -29 -54 -41h-54q-157 0 -207 -173l-3 -83v-78h189l60 3q27 0 39 -50v-8q0 -28 -47 -40h-241v-776l3 -42q0 -30 -53 -42q-32 0 -48 42l4 42v776h-223q-30 0 -39 57q0 20 41 41l70 -3h147v93q0 237 205 324z" />
-<glyph unicode="g" horiz-adv-x="1208" d="M523 996q216 0 374 -180q110 -150 110 -282l-4 -126v-449q0 -114 -182 -255q-142 -92 -298 -92q-266 0 -440 238q-29 48 -29 60v11q0 29 45 39h8q33 0 63 -81q144 -180 353 -180q252 0 381 233l8 54v226q-200 -184 -378 -184h-30q-194 0 -362 184q-103 145 -103 300 q0 236 209 396q133 88 275 88zM134 523v-18q0 -243 254 -361q69 -21 124 -21h22q238 0 359 254q19 77 19 120v23q0 242 -258 362q-80 19 -124 19h-14q-238 0 -358 -250q-24 -70 -24 -128z" />
-<glyph unicode="h" horiz-adv-x="1125" d="M112 1405h12q46 -9 46 -35v-516q179 155 335 155q238 0 381 -226q54 -99 54 -187v-528q0 -35 -49 -43h-1q-35 0 -47 46v503q0 221 -228 318q-55 16 -110 16q-227 0 -319 -240q-16 -52 -16 -166v-434q0 -35 -49 -43h-1q-35 0 -47 46v1285q10 49 39 49z" />
-<glyph unicode="i" horiz-adv-x="431" d="M149 1261q50 -13 50 -39v-22q0 -31 -56 -39q-29 0 -40 50q9 50 46 50zM149 1005q50 -13 50 -39v-898q0 -35 -49 -43h-2q-36 0 -46 52v866q7 62 47 62z" />
-<glyph unicode="j" horiz-adv-x="656" d="M412 1251q48 -9 48 -48q0 -41 -51 -48q-43 12 -43 37v22q0 26 46 37zM415 1001q45 -9 45 -45v-928q0 -260 -247 -380q-86 -31 -139 -31l-4 4h-26l-3 -4h8q-41 0 -49 58q0 31 58 40q224 0 300 230l8 115v896q0 37 49 45z" />
-<glyph unicode="k" horiz-adv-x="1056" d="M116 1410h12q47 -10 47 -36v-793q573 380 656 427h12q39 0 47 -56q0 -29 -109 -87q-290 -196 -319 -201v-33l425 -540l3 -14v1q-9 -49 -47 -49h-7q-31 0 -113 118l-349 434h-22l-177 -113v-400q0 -35 -49 -43h-2q-35 0 -47 46v1289q10 50 39 50z" />
-<glyph unicode="l" horiz-adv-x="473" d="M104 1402h12q46 -9 46 -35v-1245h104q29 0 39 -50v2q-8 -49 -47 -49h-146q-37 0 -47 52v1267q6 58 39 58z" />
-<glyph unicode="m" horiz-adv-x="1675" d="M109 981q48 -12 48 -37v-89q156 126 290 126q178 0 338 -196q72 133 243 185l81 11q214 0 340 -207q41 -86 41 -164v-548q0 -28 -47 -37h1q-47 8 -47 45v532q0 199 -210 274l-55 8h-39q-168 0 -256 -192q-12 -45 -12 -75v-542q-9 -50 -44 -50h-2q-47 8 -47 41v452 q0 199 -57 252q-85 114 -225 114h-11q-192 0 -270 -205q-12 -49 -12 -125v-488q0 -33 -47 -41h-1q-35 0 -45 50v846q6 60 45 60z" />
-<glyph unicode="n" horiz-adv-x="1197" d="M125 998q49 -12 49 -39v-138q197 177 379 177q200 0 355 -167q113 -140 113 -293v-475q0 -28 -48 -38q-48 9 -48 46v418q0 298 -260 394q-63 16 -112 16h-11q-218 0 -336 -224q-32 -70 -32 -216v-392q0 -34 -48 -42h-2q-36 0 -46 52v859q7 62 47 62z" />
-<glyph unicode="o" horiz-adv-x="1170" d="M522 993q187 0 339 -142q145 -152 145 -342q0 -272 -258 -428q-111 -56 -215 -56h-30q-194 0 -362 184q-103 145 -103 300q0 236 209 396q133 88 275 88zM137 520v-18q0 -219 210 -338q77 -40 164 -40h22q226 0 346 234q28 74 28 144v18q0 183 -166 306q-98 68 -223 68 q-247 0 -361 -257q-20 -64 -20 -117z" />
-<glyph unicode="p" horiz-adv-x="1172" d="M542 995q185 0 336 -141q145 -152 145 -341q0 -271 -257 -426q-111 -56 -214 -56h-30q-166 0 -369 183v-567q0 -27 -52 -38q-30 0 -42 52v819q0 367 346 494q42 13 137 21zM157 524v-19q0 -217 209 -336q77 -40 164 -40h22q226 0 345 233q28 74 28 143v19q0 182 -165 305 q-99 68 -223 68q-246 0 -359 -257q-21 -64 -21 -116z" />
-<glyph unicode="q" horiz-adv-x="1178" d="M525 985q185 0 337 -140q143 -140 143 -373v-815q-12 -52 -42 -52q-52 11 -52 38v565q-199 -183 -375 -183h-29q-193 0 -360 183q-102 144 -102 297q0 234 207 393q132 87 273 87zM142 516v-18q0 -217 209 -335q76 -40 163 -40h22q225 0 344 232q28 74 28 143v18 q0 181 -165 304q-98 68 -222 68q-245 0 -358 -256q-21 -63 -21 -116z" />
-<glyph unicode="r" horiz-adv-x="925" d="M146 1006q50 -13 50 -39v-139q200 178 378 178q96 0 201 -45q19 -20 19 -39v-2q-8 -48 -46 -48q-103 33 -159 33h-22q-237 0 -347 -245q-24 -66 -24 -148v-444q0 -35 -49 -43h-2q-36 0 -46 52v866q7 63 47 63z" />
-<glyph unicode="s" horiz-adv-x="968" d="M420 992q243 0 380 -216l2 -22v-3q0 -37 -51 -45q-33 0 -78 76q-113 109 -253 109q-185 0 -294 -179l-4 -26q0 -74 132 -86q423 -102 459 -115q93 -62 93 -156v-3q0 -139 -212 -260q-91 -41 -196 -41q-212 0 -361 200q-10 16 -10 27v22q0 32 58 38q21 0 80 -85 q108 -100 248 -100q169 0 282 162l9 29v8q0 70 -87 80q-489 109 -514 131q-83 63 -83 151q0 126 191 248q105 56 209 56z" />
-<glyph unicode="t" horiz-adv-x="704" d="M245 1365h11q44 -9 44 -34v-355h178l33 4q29 0 42 -52q0 -30 -41 -45l-50 4h-162v-564q0 -159 112 -198l88 -7h42q28 0 37 -47v1q-8 -47 -45 -47h-77q-159 0 -237 175q-13 42 -13 101v586h-99l-55 -4q-40 15 -40 46q8 47 66 47v1l11 -1h117v332q6 57 38 57z" />
-<glyph unicode="u" horiz-adv-x="1188" d="M117 1002q49 -12 49 -39v-401q0 -271 157 -366q99 -75 221 -75q234 0 352 241q25 78 25 155v433q10 52 47 52q49 -11 49 -46v-892q0 -29 -48 -39q-48 9 -48 46v96h-39q-156 -142 -327 -142h-26q-221 0 -384 218q-75 116 -75 289v408q7 62 47 62z" />
-<glyph unicode="v" horiz-adv-x="1132" d="M72 1004h7q41 0 79 -109l345 -709q371 786 389 805q17 13 30 13q52 -10 52 -46v-4q0 -13 -162 -350l-276 -565q-18 -14 -33 -14h-3q-46 0 -90 128q-363 742 -381 794v12q9 45 43 45z" />
-<glyph unicode="w" horiz-adv-x="1416" d="M82 984q47 0 71 -129l187 -574h40q211 672 220 685q19 15 40 18q43 0 62 -103l194 -600h40q204 647 219 681q21 22 36 22q51 -10 51 -45l-288 -896q-19 -18 -37 -18h-3q-47 0 -72 125q-176 534 -176 571h-50l-218 -676q-15 -20 -37 -20h-3q-34 0 -50 49l-274 862 q10 48 48 48z" />
-<glyph unicode="x" horiz-adv-x="968" d="M86 981q31 0 94 -96q188 -225 235 -293h27q41 40 309 379q7 6 28 9q46 -11 46 -36v-22q0 -14 -126 -161l-208 -262q334 -402 334 -411v-22q0 -33 -47 -41h-1q-29 0 -76 74l-269 330q-311 -389 -323 -397q-11 -7 -23 -7h-3q-37 0 -45 54q0 18 134 169l200 255l-329 411 l-4 19q9 48 47 48z" />
-<glyph unicode="y" horiz-adv-x="913" d="M724 987q46 -9 46 -41v-3q-2 -20 -343 -832q-160 -397 -176 -417q-11 -9 -28 -13q-44 9 -44 34v17q0 8 157 386v13l-332 810v-5q9 47 45 47q40 0 77 -122q227 -537 238 -582h40q279 681 290 694q17 14 30 14z" />
-<glyph unicode="z" horiz-adv-x="1018" d="M104 984l11 -1h641l31 4q43 -14 43 -38v-22q0 -13 -79 -99l-565 -709h601q43 -9 43 -41v-12q0 -33 -47 -41h-700q-37 0 -45 55q0 18 145 185l499 628h-548l-55 -4q-41 15 -41 47q8 47 66 47v1z" />
-<glyph unicode="{" d="M659 1565h139q48 0 59 -39v-20q0 -28 -46 -39h-142q-97 0 -97 -101v-579q0 -40 -52 -124q55 -62 55 -127v-586q0 -86 98 -86h138q46 -9 46 -43v-15q0 -30 -50 -40h-146q-132 0 -180 147l-4 46v573q0 70 -75 86h-85q-53 11 -53 48q11 51 40 51h61q108 0 108 78v574 q0 147 148 192z" />
-<glyph unicode="|" d="M479 1594h6q46 -9 46 -44v-1908q0 -28 -55 -40q-34 0 -45 58v1880q9 54 48 54z" />
-<glyph unicode="}" d="M152 1553h154q123 0 174 -138l3 -29v-579q0 -89 111 -89h56q39 -12 39 -42v-15q0 -29 -48 -39h-77q-85 0 -85 -119v-554q0 -109 -138 -162l-40 -4h-147q-48 7 -48 46v2q8 48 42 48h139q96 0 96 85v562q0 76 55 145q-51 74 -51 121v580q0 85 -96 85h-143q-34 0 -42 46 q8 50 46 50z" />
-<glyph unicode="~" d="M348 826h24q84 0 202 -79l45 -12h31l93 28q70 -14 70 -70q0 -75 -159 -95h-32q-83 0 -201 80l-46 11h-30l-91 -24h-5q-63 13 -63 62v14q0 52 88 72q35 13 74 13z" />
-<glyph unicode="&#xa1;" horiz-adv-x="672" d="M275 1302h14q45 0 63 -46l6 -23q0 -60 -78 -70q-53 0 -64 72q15 67 59 67zM287 1040q43 -7 43 -41v-927q-7 -43 -41 -43h-5q-40 8 -40 38v935q0 31 43 38z" />
-<glyph unicode="&#xa2;" horiz-adv-x="1105" d="M747 1362h9q43 -8 43 -41v-7l-123 -360q185 -85 185 -134v-1q-8 -47 -44 -47h-4q-18 0 -105 67l-64 24l-251 -721q70 -23 138 -23q135 0 261 104l20 6h8q33 0 41 -47v-2q0 -57 -216 -140q-74 -14 -110 -14h-29q-46 0 -148 27q-98 -300 -109 -308l-38 -14q-46 11 -46 47 q0 10 111 316q-228 170 -228 408q0 257 247 417q122 59 232 59l59 -4q120 365 130 372q18 16 31 16zM141 499q0 -167 143 -296h31l237 679h-39q-228 0 -345 -239q-27 -81 -27 -144z" />
-<glyph unicode="&#xa3;" horiz-adv-x="946" d="M463 1448h39q169 0 285 -155l3 -16q-13 -53 -52 -53q-25 0 -84 66q-75 57 -152 57h-23q-171 0 -241 -201l-4 -54q0 -86 150 -343h244q54 -11 54 -49q-12 -52 -41 -52h-234l8 -54v-48q0 -120 -106 -330l-33 -81h427q23 0 63 92q21 20 38 20q56 -11 56 -53q0 -21 -69 -146 q-16 -14 -34 -14h-568q-38 0 -48 54q0 11 148 333q26 74 26 138l-5 89h-181q-50 10 -50 47q11 54 52 54h114v35q-112 204 -112 310q0 216 227 333q71 21 103 21z" />
-<glyph unicode="&#xa4;" d="M229 1022h20q25 0 103 -87q76 43 129 43h24q66 0 141 -43q75 87 95 87h24q43 -13 43 -47v-8q0 -27 -86 -107q42 -80 42 -145q0 -58 -41 -156q85 -68 85 -96v-12q-14 -47 -43 -47h-20q-16 0 -93 80h-22q-64 -36 -137 -36q-48 0 -148 41q-69 -85 -100 -85h-6q-49 10 -49 47 v12q0 30 86 101q-42 84 -42 135v20q0 63 42 147q-86 70 -86 97v16q13 43 39 43zM332 715q0 -118 137 -165h32q129 0 161 146v34q-34 146 -145 146l-14 5q-171 -29 -171 -166z" />
-<glyph unicode="&#xa5;" horiz-adv-x="1262" d="M122 1205h166q40 0 49 -54q0 -26 -84 -50q241 -373 320 -482h34q314 455 314 500h-22q-23 14 -23 30v14q13 42 49 42h144q40 0 48 -54q0 -17 -51 -50l-136 -202h119q61 -6 61 -45v-7q0 -32 -47 -41h-199l-140 -212h332q54 -11 54 -45v-4q0 -38 -74 -48v2l-10 1h-380v-434 q0 -29 -52 -41q-45 0 -60 38l4 58v358l-24 21h-361l-30 -4q-53 11 -53 49q0 39 54 49h335q-137 212 -156 212h-188q-45 13 -45 45q0 42 61 48h126q-136 214 -153 215q-34 15 -34 50q0 29 52 41z" />
-<glyph unicode="&#xa6;" horiz-adv-x="770" d="M334 1590h6q46 -9 46 -44v-681q0 -35 -50 -44h-2q-38 0 -48 54v661q9 54 48 54zM335 371q51 -13 51 -40v-693q0 -28 -55 -40q-34 0 -45 58v651q7 64 49 64z" />
-<glyph unicode="&#xa7;" d="M486 1415h35q153 0 268 -137l2 -12q-6 -38 -29 -38h-19q-10 0 -79 65q-75 48 -158 48q-200 0 -266 -223v-50q0 -172 193 -253q183 -28 226 -76q117 -103 117 -215v-50q0 -105 -151 -234q178 -135 178 -302q0 -190 -181 -300q-81 -40 -155 -40h-12q-170 0 -282 141l-3 15 q0 28 47 35q12 0 67 -56q84 -61 171 -61q179 0 257 189l13 71q0 202 -222 275q-117 14 -162 43q-156 105 -156 247v19q0 145 157 251q-180 143 -180 301v15q0 190 185 296q70 36 139 36zM263 521v-16q0 -150 168 -208l43 -4h24q141 0 200 168l4 43q0 163 -183 216l-43 4 q-148 0 -208 -163z" />
-<glyph unicode="&#xa8;" horiz-adv-x="1024" d="M264 1284q58 -14 58 -53q-11 -57 -53 -57q-57 11 -57 52q14 58 52 58zM716 1284q58 -14 58 -53q-11 -57 -53 -57q-57 11 -57 52q14 58 52 58z" />
-<glyph unicode="&#xa9;" horiz-adv-x="1674" d="M808 1416q348 0 578 -313q116 -176 116 -385q0 -373 -346 -600q-165 -94 -356 -94q-313 0 -541 270q-149 198 -149 424q0 340 299 571q189 127 399 127zM169 729v-18q0 -337 321 -550q164 -82 318 -82q327 0 537 294q102 165 102 349q0 331 -306 544q-164 91 -314 91h-38 q-293 0 -502 -266q-118 -170 -118 -362zM819 1205q180 0 332 -135q8 -11 8 -24v-8q0 -41 -55 -46h-2q-7 0 -113 76q-102 40 -177 40q-242 0 -366 -248q-25 -71 -25 -134v-27q0 -196 197 -327q102 -52 194 -52q143 0 278 112l20 5q49 -7 49 -46v-8q0 -55 -201 -138 q-91 -21 -146 -21q-283 0 -441 275q-50 110 -50 219q0 254 237 416q116 71 261 71z" />
-<glyph unicode="&#xaa;" horiz-adv-x="648" d="M289 1397h32q150 0 228 -168l16 -76l-4 -64v-140l4 -24q-7 -27 -28 -36h-12q-22 0 -36 24v48q-86 -72 -172 -72h-8q-184 0 -248 196q-8 20 -8 60q0 176 196 248zM129 1137q0 -130 156 -172h32q117 0 168 140l4 40q0 118 -132 172l-48 8q-121 0 -176 -136z" />
-<glyph unicode="&#xab;" horiz-adv-x="944" d="M481 787l23 -7v-20q0 -11 -179 -220l-36 -49q219 -250 219 -265q-4 -21 -15 -21h-12q-26 19 -237 282l-2 11q0 11 114 142q113 143 131 143l4 4h-10zM737 782q15 -8 15 -18v-4q0 -12 -201 -247l-10 -31q203 -236 211 -252v-12q-3 -17 -15 -17h-4q-18 0 -84 95 q-159 178 -159 192v11q197 249 237 281z" />
-<glyph unicode="&#xac;" d="M122 727h710q49 -10 49 -47v-348q0 -32 -53 -43q-53 10 -53 51v281h-639q-57 11 -57 52q12 54 43 54z" />
-<glyph unicode="&#xae;" horiz-adv-x="1674" d="M776 1453q351 0 583 -314q117 -177 117 -386q0 -373 -348 -602q-167 -94 -359 -94q-316 0 -545 270q-151 200 -151 426q0 341 301 573q191 127 402 127zM91 775v-18q0 -338 324 -551q164 -82 319 -82q330 0 541 294q103 166 103 350q0 332 -308 546q-165 91 -317 91h-38 q-295 0 -505 -267q-119 -171 -119 -363zM591 1191h186q187 0 245 -191q7 -18 7 -56q0 -134 -166 -224q237 -409 245 -430v1q-9 -24 -20 -24h-15q-18 0 -58 85l-209 360h-187v-419q-4 -26 -17 -26h-19q-16 9 -16 20v874q5 30 24 30zM619 1139v-379h120q177 0 220 114 q17 39 17 81q0 123 -136 174q-21 10 -59 10h-162z" />
-<glyph unicode="&#xaf;" horiz-adv-x="806" d="M-37 1751h841q48 -9 48 -45v-10q-9 -47 -42 -47h-847q-38 0 -45 55q13 47 45 47z" />
-<glyph unicode="&#xb0;" horiz-adv-x="674" d="M315 1366q-84 0 -144.5 -60t-60.5 -145t60 -144t145 -59t144 59t59 144t-59.5 145t-143.5 60zM314 1417q105 0 178.5 -74t73.5 -179q0 -104 -74.5 -178.5t-179.5 -74.5q-107 0 -179.5 73.5t-72.5 179.5t74 179.5t180 73.5z" />
-<glyph unicode="&#xb1;" d="M488 1163h24q26 0 43 -46l-4 -36v-218h247q57 -9 57 -51v-8q0 -37 -49 -51l-24 4h-231v-214l4 -44q0 -33 -58 -46q-35 0 -52 46l4 44v214h-231l-21 -3q-52 13 -52 50v8q0 40 57 51h247v218l-4 33q16 49 43 49zM192 343l43 -4h538l33 4q49 -14 49 -51v-8q0 -34 -43 -51 l-63 4h-498l-60 -4q-46 16 -46 51v8q0 33 47 51z" />
-<glyph unicode="&#xb2;" d="M506 1537q95 0 166 -86q37 -56 37 -116q0 -93 -90 -177l-197 -225h264q26 0 32 -33v-2q-5 -34 -34 -34h-343q-33 6 -33 34v2q0 16 33 47l274 313q23 33 23 75q0 90 -93 125q-16 5 -36 5h-5q-86 0 -124 -91q-5 -20 -7 -46q-12 -25 -32 -25h-3q-34 6 -34 32q0 106 101 173 q54 29 101 29z" />
-<glyph unicode="&#xb3;" d="M503 1543q80 0 138 -72q32 -44 32 -97v-7q0 -74 -64 -131q93 -67 93 -170q0 -106 -100 -176q-52 -29 -103 -29h-5q-120 0 -187 124q-16 46 -16 82q0 25 38 33q27 0 32 -36q0 -77 81 -122q30 -11 57 -11q81 0 122 84q9 26 9 44v14q0 76 -84 118l-59 13q-18 14 -18 30v2 q0 34 48 34q35 0 74 47q14 30 14 56q0 58 -57 89q-21 11 -47 11q-67 0 -95 -72q-6 -52 -13 -52q-12 -14 -25 -14q-36 8 -36 30v9q0 94 94 149q36 18 77 20z" />
-<glyph unicode="&#xb4;" horiz-adv-x="889" d="M491 1389q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121z" />
-<glyph unicode="&#xb5;" horiz-adv-x="1180" d="M166 994q48 -12 48 -38v-399q0 -271 157 -364q97 -75 219 -75q234 0 351 240q25 77 25 154v430q10 52 46 52q49 -11 49 -46v-887q0 -29 -49 -39h2q-48 9 -48 46v96h-39q-156 -142 -326 -142h-26q-165 0 -361 177v-564q0 -27 -52 -38q-32 0 -43 55v1281q6 61 47 61z" />
-<glyph unicode="&#xb6;" horiz-adv-x="1024" d="M378 1410h459q46 -10 46 -36v-19q0 -35 -49 -43h-34v-1234q-10 -53 -47 -53h-2q-49 8 -49 43v1244h-190v-1238q-8 -49 -47 -49h-2q-49 9 -49 47v699h-36q-172 0 -277 182q-31 69 -31 141q0 186 190 288q57 28 118 28z" />
-<glyph unicode="&#xb7;" horiz-adv-x="508" d="M250 721q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4z" />
-<glyph unicode="&#x2219;" horiz-adv-x="508" d="M250 721q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4z" />
-<glyph unicode="&#xb8;" horiz-adv-x="1024" d="M523 12q41 -9 41 -34v-69q104 -69 104 -157q0 -126 -147 -163l-46 3h-54l-52 -3q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29v111q0 32 45 41z" />
-<glyph unicode="&#xb9;" d="M535 1564h5q32 -7 32 -31v-611q-6 -34 -34 -34h-1q-34 7 -34 30v564q-48 -16 -63 -16q-22 0 -30 32v9q0 26 72 41z" />
-<glyph unicode="&#xba;" horiz-adv-x="718" d="M370 1543q107 0 164 -115q31 -96 31 -177v-38q0 -100 -41 -201q-59 -92 -150 -92h-6q-98 0 -155 105q-36 92 -36 205v5q0 119 42 216q62 92 151 92zM236 1239v-17q0 -114 41 -191q40 -49 90 -49h5q111 0 129 171q5 27 7 80q0 95 -33 182q-41 65 -103 65q-76 0 -111 -83 q-25 -82 -25 -158z" />
-<glyph unicode="&#xbb;" horiz-adv-x="944" d="M474 778q18 0 88 -99q155 -174 155 -188v-11q-188 -241 -240 -284h-13q-6 3 -9 9v14q0 16 202 244l8 35q-210 241 -210 254q5 26 19 26zM232 774q15 0 103 -119q138 -155 138 -172q0 -13 -199 -245q-32 -46 -44 -46h-2q-21 4 -21 19q0 16 102 132l118 144 q-209 243 -216 258v14q0 11 21 15z" />
-<glyph unicode="&#xbc;" horiz-adv-x="1470" d="M1160 1417h12q35 0 43 -49v-2q0 -25 -120 -164q-96 -134 -899 -1168q-15 -9 -30 -9q-46 13 -46 40v23q0 14 140 185q812 1061 875 1136q11 8 25 8zM296 1409q8 0 17 -15l-3 -50v-656l3 -31q-6 -19 -20 -19q-11 0 -17 11v710l-93 -21h-10q-11 6 -11 16q0 27 110 44 q0 6 24 11zM1130 804q12 0 20 -17l-3 -33v-444h112q13 0 16 -22q-7 -16 -20 -16h-108v-235q-7 -12 -15 -12q-23 5 -23 21v226h-360q-16 3 -16 13v10q330 425 380 498q7 11 17 11zM1068 672l-274 -362h315v362h-41z" />
-<glyph unicode="&#xbd;" horiz-adv-x="1492" d="M1147 1412h11q35 0 43 -49v-2q0 -25 -120 -163q-95 -133 -895 -1164q-15 -9 -30 -9q-46 13 -46 39v23q0 14 139 186q810 1056 873 1131q11 8 25 8zM285 1404q8 0 17 -15l-3 -50v-654l4 -30q-7 -20 -21 -20q-10 0 -17 12v708l-92 -22h-10q-11 6 -11 17q0 26 110 43 q0 6 23 11zM1054 790q152 0 216 -167l3 -33v-40q0 -87 -148 -230l-223 -258h354l11 3q18 -6 18 -4v-16q-3 -16 -13 -16h-417q-13 0 -17 22q0 3 175 194q219 242 219 280l4 27v39q-37 162 -180 162q-125 0 -181 -141q0 -51 -13 -56h-11q-10 0 -17 18q0 139 157 206z" />
-<glyph unicode="&#xbe;" horiz-adv-x="1541" d="M343 1413q107 0 164 -114q13 -30 13 -54v-22q0 -72 -89 -158q123 -86 123 -201q0 -158 -176 -216l-49 -4h-6q-148 0 -209 176l-4 49q0 5 12 12h12q16 0 20 -63q52 -137 172 -137h12q131 0 176 152l4 33q0 129 -150 182q-47 0 -47 21q5 19 36 19q96 0 127 128v29 q0 89 -120 131h-26q-103 0 -142 -119v-32q-6 -11 -13 -11h-9q-15 3 -15 12v8q0 125 142 175zM1243 1405h12q34 0 43 -49v-1q0 -25 -120 -163q-95 -133 -891 -1158q-15 -9 -29 -9q-46 13 -46 39v23q0 14 138 185q806 1051 869 1125q11 8 24 8zM1213 798q12 0 20 -17l-3 -33 v-441h111q13 0 16 -21q-7 -16 -19 -16h-108v-233q-7 -12 -15 -12q-22 4 -22 20v225h-358q-16 3 -16 13v10q328 421 377 493q8 12 17 12zM1152 666l-272 -359h313v359h-41z" />
-<glyph unicode="&#xbf;" horiz-adv-x="977" d="M416 1055h11q60 0 73 -80q-14 -73 -77 -73h-4q-63 0 -76 75v-1q15 79 73 79zM414 750q52 -9 52 -47v-7q0 -242 -235 -380q-108 -102 -108 -242q0 -181 188 -279q71 -25 123 -25q179 0 275 175q23 39 36 145q23 27 41 27q53 -13 53 -47q0 -197 -195 -337 q-108 -60 -210 -60q-202 0 -334 175q-74 105 -74 233q0 230 235 372q112 101 112 272q19 25 41 25z" />
-<glyph unicode="&#xc0;" horiz-adv-x="1220" d="M452 1761h7q33 0 114 -116q54 -58 54 -76q-9 -53 -46 -53h-16q-24 0 -121 136q-39 33 -39 63q13 46 47 46zM535 1413q49 0 78 -122q458 -1189 461 -1214v-9q0 -35 -49 -43h-2q-46 0 -70 111l-178 460h-476l-213 -557q-17 -14 -32 -14h-5q-49 9 -49 47l127 343 q339 880 366 972q23 26 42 26zM518 1175l-178 -481h387v34l-171 447h-38z" />
-<glyph unicode="&#xc1;" horiz-adv-x="1212" d="M597 1753h1q49 -10 49 -39v-15q0 -22 -74 -101q-58 -89 -89 -89h-12q-34 0 -42 49v2q0 27 111 151q27 42 56 42zM533 1407q48 0 77 -122q456 -1184 459 -1208v-9q0 -35 -49 -43h-1q-47 0 -71 110l-176 459h-475l-211 -555q-17 -14 -32 -14h-5q-49 9 -49 47v-1l126 342 q338 876 365 969q22 25 42 25zM516 1170l-178 -479h385v34l-170 445h-37z" />
-<glyph unicode="&#xc2;" horiz-adv-x="1212" d="M525 1746h30q23 0 106 -112q54 -58 54 -82v-1q-7 -49 -47 -49h-7q-33 0 -108 113h-30q-80 -113 -107 -113h-11q-37 0 -47 52q0 22 112 149q29 43 55 43zM533 1407q48 0 77 -122q456 -1184 459 -1208v-9q0 -35 -49 -43h-1q-47 0 -71 110l-176 459h-475l-211 -555 q-17 -14 -32 -14h-5q-49 9 -49 47v-1l126 342q338 876 365 969q22 25 42 25zM516 1170l-178 -479h385v34l-170 445h-37z" />
-<glyph unicode="&#xc3;" horiz-adv-x="1216" d="M429 1670q70 0 178 -70l44 -5l78 23h1q49 -8 49 -47v-4q0 -49 -102 -65l-36 -4q-70 0 -171 71l-41 5l-82 -22q-49 9 -49 45v8q0 50 118 62zM533 1407q48 0 77 -122q456 -1184 459 -1208v-9q0 -35 -49 -43h-1q-47 0 -71 110l-176 459h-475l-211 -555q-17 -14 -32 -14h-5 q-49 9 -49 47v-1l126 342q338 876 365 969q22 25 42 25zM516 1170l-178 -479h385v34l-170 445h-37z" />
-<glyph unicode="&#xc4;" horiz-adv-x="1225" d="M389 1659h5q46 -10 46 -39v-11q0 -39 -51 -47q-46 10 -46 47v11q0 29 46 39zM672 1659h15q31 0 39 -56q0 -29 -51 -40q-46 8 -46 42v15q12 39 43 39zM533 1407q48 0 77 -122q456 -1184 459 -1208v-9q0 -35 -49 -43h-1q-47 0 -71 110l-176 459h-475l-211 -555 q-17 -14 -32 -14h-5q-49 9 -49 47v-1l126 342q338 876 365 969q22 25 42 25zM516 1170l-178 -479h385v34l-170 445h-37z" />
-<glyph unicode="&#xc5;" horiz-adv-x="1219" d="M531 1807h14q103 0 149 -128l4 -33v-10q0 -101 -122 -150l-40 -7q-96 0 -150 100q-16 36 -16 68q0 110 129 156zM437 1643q17 -96 99 -96q95 16 95 93v13q-15 87 -89 87h-12q-78 0 -93 -97zM534 1411q49 0 78 -122q457 -1188 460 -1212v-9q0 -35 -49 -43h-2 q-46 0 -70 110l-177 460h-476l-212 -556q-17 -14 -32 -14h-5q-49 9 -49 47l126 342q339 879 366 971q23 26 42 26zM517 1173l-178 -480h386v34l-170 446h-38z" />
-<glyph unicode="&#xc6;" horiz-adv-x="1565" d="M755 1410h595q26 0 38 -48q-9 -49 -50 -49h-525v-618h412q47 -10 47 -36v-19q0 -35 -49 -43h-410v-474h529q37 0 47 -53q0 -34 -54 -45h-572q-37 0 -47 53v519h-314q-29 -35 -176 -309l-142 -249q-16 -14 -33 -14h-4q-38 0 -47 57q0 13 239 432l491 882q17 14 25 14z M451 695h265v473z" />
-<glyph unicode="&#xc7;" horiz-adv-x="1399" d="M688 1407q215 0 386 -127q12 -15 12 -28q-9 -51 -49 -51q-11 0 -124 61q-125 46 -225 46q-276 0 -476 -252q-101 -168 -101 -329q0 -322 302 -511q134 -70 268 -70h11q169 0 333 102l11 2h3q47 -8 47 -45v-4q0 -74 -272 -142l-88 -9v-110q112 -74 112 -169 q0 -136 -159 -175l-49 4h-57l-56 -4q-41 14 -41 38v13q9 44 42 44h130q95 0 95 80v4q0 63 -84 79q-27 13 -27 32v164q-162 15 -326 116q-293 227 -293 561q0 353 323 576q171 104 352 104z" />
-<glyph unicode="&#xc8;" horiz-adv-x="1039" d="M72 1405l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286q7 49 72 49v-2zM330 1804h8q32 0 113 -116q54 -58 54 -76q-9 -53 -46 -53h-15 q-25 0 -122 136q-39 33 -39 62q14 47 47 47z" />
-<glyph unicode="&#xc9;" d="M72 1405l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286q7 49 72 49v-2zM451 1804h2q52 -10 52 -51q0 -22 -85 -116q-54 -78 -75 -78h-22 q-31 0 -40 57q0 16 113 145q29 43 55 43z" />
-<glyph unicode="&#xca;" d="M72 1405l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286q7 49 72 49v-2zM439 1762h16q32 0 97 -93q71 -78 71 -93v-12q-9 -46 -36 -46h-26 q-20 0 -118 131q-90 -131 -113 -131h-26q-27 0 -36 46v12q0 22 147 181z" />
-<glyph unicode="&#xcb;" horiz-adv-x="1027" d="M72 1405l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286q7 49 72 49v-2zM284 1679h5q46 -10 46 -39v-11q0 -39 -50 -47q-47 10 -47 47v11 q0 29 46 39zM568 1679h15q32 0 40 -56q0 -29 -52 -41q-46 8 -46 43v15q12 39 43 39z" />
-<glyph unicode="&#xcc;" horiz-adv-x="657" d="M196 1793q29 0 100 -100q65 -71 65 -95q-10 -52 -50 -52q-32 0 -86 80q-81 91 -81 106v22q0 29 52 39zM158 1405l14 -3h146l12 3q50 -11 50 -48q-9 -52 -47 -52h-40v-1183h48q29 0 39 -50v2q-9 -49 -47 -49h-174q-49 9 -49 47q10 50 39 50h48v1183h-40q-41 0 -47 55v3 q0 27 48 42z" />
-<glyph unicode="&#xcd;" horiz-adv-x="657" d="M349 1803h2q52 -10 52 -51q0 -22 -85 -116q-54 -78 -75 -78h-22q-31 0 -39 57q0 16 112 145q29 43 55 43zM188 1409l15 -3h145l13 3q50 -10 50 -47q-9 -53 -47 -53h-40v-1187h48q29 0 39 -49v1q-9 -49 -47 -49h-175q-49 9 -49 47v1q10 49 39 49h48v1187h-40q-41 0 -47 55 v3q0 28 48 42z" />
-<glyph unicode="&#xce;" horiz-adv-x="657" d="M260 1758h30q35 0 117 -119q51 -53 51 -73q-9 -53 -47 -53h-7q-34 0 -95 94l-40 32q-82 -126 -115 -126h-5q-49 8 -49 47v4q0 26 108 146q33 48 52 48zM193 1410l15 -3h146l12 3q50 -11 50 -48q-9 -53 -46 -53h-40v-1187h47q29 0 39 -48q-8 -49 -46 -49h-176 q-49 9 -49 47v1q10 49 40 49h47v1187h-40q-41 0 -47 56v3q0 27 48 42z" />
-<glyph unicode="&#xcf;" horiz-adv-x="657" d="M119 1658h12q46 -9 46 -35v-19q0 -34 -47 -43q-50 10 -50 48q11 49 39 49zM412 1658h5q46 -10 46 -39v-11q0 -39 -50 -47q-47 10 -47 47v11q0 29 46 39zM188 1405l15 -3h145l13 3q49 -10 49 -48q-9 -52 -46 -52h-40v-1183h47q29 0 39 -49v1q-8 -49 -46 -49h-175 q-49 9 -49 47q10 50 39 50h48v1183h-40q-41 0 -47 55v3q0 27 48 42z" />
-<glyph unicode="&#xd0;" horiz-adv-x="1275" d="M447 1405q318 0 547 -279q138 -189 138 -415q0 -360 -338 -592q-173 -94 -345 -94h-252q-34 0 -46 46v609h-105q-46 10 -46 43v15q0 29 50 39h101v575q10 50 39 50h223zM247 1309v-532h306q48 -9 48 -43v-9q-9 -45 -43 -45h-311v-558h180q378 0 552 345q56 118 56 248 q0 320 -297 514q-127 80 -394 80h-97z" />
-<glyph unicode="&#xd1;" horiz-adv-x="1288" d="M432 1676q68 0 177 -71l46 -5l72 23h6q49 -7 49 -47v-4q0 -49 -103 -65l-36 -4q-70 0 -171 71l-42 4l-82 -21q-49 9 -49 46v7q0 50 118 62zM39 1407h15q31 0 59 -56l848 -1089h41v1100q9 45 43 45h11q35 0 43 -48v-1285q-9 -49 -47 -49h-4q-37 0 -96 95l-855 1090v-1142 q0 -35 -48 -43h-2q-35 0 -47 46v1287q10 49 39 49z" />
-<glyph unicode="&#xd2;" horiz-adv-x="1519" d="M621 1796h22q21 0 83 -85q76 -85 76 -106q-10 -52 -50 -52h-3q-33 0 -102 104q-65 64 -65 90q11 49 39 49zM689 1402q348 0 583 -323q105 -183 105 -369q0 -344 -312 -573q-177 -112 -369 -112h-15q-354 0 -580 331q-101 166 -101 361q0 329 290 555q189 130 399 130z M96 706q0 -285 251 -478q157 -107 334 -107h19q278 0 470 247q111 159 111 346q0 322 -294 509q-144 83 -298 83q-294 0 -486 -255q-107 -153 -107 -345z" />
-<glyph unicode="&#xd3;" horiz-adv-x="1532" d="M743 1801h12q50 -10 50 -46q0 -29 -120 -159q-19 -38 -55 -38t-46 52q0 25 104 137q34 54 55 54zM691 1406q349 0 585 -324q105 -183 105 -370q0 -345 -313 -574q-177 -113 -370 -113h-15q-355 0 -582 332q-101 167 -101 362q0 330 291 556q189 131 400 131zM97 708 q0 -286 251 -479q157 -107 335 -107h19q279 0 472 247q110 159 110 347q0 322 -294 510q-145 83 -299 83q-295 0 -487 -255q-107 -154 -107 -346z" />
-<glyph unicode="&#xd4;" horiz-adv-x="1523" d="M673 1778h31q22 0 104 -112q55 -58 55 -81v-2q-8 -48 -47 -48h-7q-33 0 -107 112h-30q-80 -112 -107 -112h-12q-36 0 -46 52q0 22 111 148q30 43 55 43zM689 1402q348 0 583 -323q105 -183 105 -369q0 -344 -312 -573q-177 -112 -369 -112h-15q-354 0 -580 331 q-101 166 -101 361q0 329 290 555q189 130 399 130zM96 706q0 -285 251 -478q157 -107 334 -107h19q278 0 470 247q111 159 111 346q0 322 -294 509q-144 83 -298 83q-294 0 -486 -255q-107 -153 -107 -345z" />
-<glyph unicode="&#xd5;" horiz-adv-x="1528" d="M565 1747h18q64 0 156 -61l37 -10h25l73 22q49 -9 49 -49q0 -54 -120 -69h-24q-63 0 -156 62l-37 9h-24l-72 -19h-1q-46 9 -46 43v11q0 37 65 51q27 10 57 10zM689 1402q348 0 583 -323q105 -183 105 -369q0 -344 -312 -573q-177 -112 -369 -112h-15q-354 0 -580 331 q-101 166 -101 361q0 329 290 555q189 130 399 130zM96 706q0 -285 251 -478q157 -107 334 -107h19q278 0 470 247q111 159 111 346q0 322 -294 509q-144 83 -298 83q-294 0 -486 -255q-107 -153 -107 -345z" />
-<glyph unicode="&#xd6;" horiz-adv-x="1540" d="M485 1681q29 0 40 -50q-11 -51 -42 -51q-54 12 -54 39v23q0 31 56 39zM911 1681q29 0 40 -50q-11 -51 -43 -51q-53 12 -53 39v23q0 31 56 39zM691 1406q349 0 585 -324q105 -183 105 -370q0 -345 -313 -574q-177 -113 -370 -113h-15q-355 0 -582 332q-101 167 -101 362 q0 330 291 556q189 131 400 131zM97 708q0 -286 251 -479q157 -107 335 -107h19q279 0 472 247q110 159 110 347q0 322 -294 510q-145 83 -299 83q-295 0 -487 -255q-107 -154 -107 -346z" />
-<glyph unicode="&#xd7;" d="M283 913h15q36 0 135 -118l62 -54q169 172 181 172h39q40 0 56 -69q0 -44 -155 -180l-13 -13v-26q163 -148 163 -174l4 -16q-16 -71 -70 -71q-39 0 -140 118l-68 60q-153 -173 -194 -173h-20q-56 17 -56 51v24q0 35 93 112l80 86q-173 170 -173 181v27q13 63 61 63z" />
-<glyph unicode="&#xd8;" horiz-adv-x="1561" d="M688 1401q258 0 493 -207q159 162 179 162h5q49 -12 49 -46v-7q0 -30 -97 -105l-75 -76q134 -205 134 -413q0 -343 -311 -572q-177 -112 -369 -112h-15q-224 0 -428 154h-21q-154 -150 -166 -150l-19 -4h-1q-38 0 -46 56q0 22 120 122q4 10 56 47q-176 224 -176 467 q0 328 290 554q189 130 398 130zM96 706q0 -204 151 -385l849 798v27q-195 159 -408 159q-293 0 -485 -254q-107 -154 -107 -345zM310 252q188 -131 371 -131h18q279 0 471 247q110 158 110 345q0 159 -96 329h-29z" />
-<glyph unicode="&#xd9;" horiz-adv-x="1103" d="M422 1794q32 0 118 -122q47 -46 47 -71v-8q0 -37 -53 -46q-30 0 -111 115q-54 56 -54 78v8q0 35 53 46zM39 1403h12q46 -9 46 -36v-802q0 -273 158 -368q97 -75 221 -75q236 0 354 242q25 75 25 156v834q9 49 43 49h9q45 -9 45 -43v-878q0 -212 -205 -372 q-129 -85 -260 -85h-26q-222 0 -386 219q-75 117 -75 291v818q10 50 39 50z" />
-<glyph unicode="&#xda;" horiz-adv-x="1107" d="M537 1794q50 -10 50 -46v-8q0 -25 -90 -120q-46 -73 -75 -73q-53 11 -53 46v8q0 26 89 121q46 72 79 72zM39 1403h12q46 -9 46 -36v-802q0 -273 158 -368q97 -75 221 -75q236 0 354 242q25 75 25 156v834q9 49 43 49h9q45 -9 45 -43v-878q0 -212 -205 -372 q-129 -85 -260 -85h-26q-222 0 -386 219q-75 117 -75 291v818q10 50 39 50z" />
-<glyph unicode="&#xdb;" horiz-adv-x="1124" d="M490 1771h7q36 0 117 -115q55 -57 55 -80q-12 -50 -40 -50h-19q-28 0 -89 91q-1 0 -3 4l-15 15h-26q-85 -102 -86 -102l-23 -8h-15q-34 0 -43 49v2q0 28 132 172q0 17 48 22zM39 1408h12q46 -9 46 -35v-806q0 -274 159 -369q98 -76 222 -76q237 0 356 243q25 76 25 157 v838q8 48 43 48h9q45 -9 45 -43v-881q0 -213 -206 -373q-129 -86 -261 -86h-26q-223 0 -388 220q-75 117 -75 292v822q10 49 39 49z" />
-<glyph unicode="&#xdc;" horiz-adv-x="1128" d="M330 1666h5q46 -10 46 -40v-11q0 -39 -50 -47q-47 10 -47 47v11q0 30 46 40zM614 1666h15q31 0 40 -57q0 -29 -52 -41q-46 9 -46 43v15q12 40 43 40zM39 1408h12q46 -9 46 -35v-806q0 -274 159 -369q98 -76 222 -76q237 0 356 243q25 76 25 157v838q8 48 43 48h9 q45 -9 45 -43v-881q0 -213 -206 -373q-129 -86 -261 -86h-26q-223 0 -388 220q-75 117 -75 292v822q10 49 39 49z" />
-<glyph unicode="&#xdd;" horiz-adv-x="1107" d="M39 1408h16q32 0 56 -59l354 -529h31q377 569 388 578q14 10 20 10h23q26 0 39 -50q0 -21 -125 -192l-311 -464v-618q-7 -59 -39 -59h-16q-31 0 -43 40v617q0 22 -164 265l-266 400l-2 13q11 48 39 48zM573 1772h1q53 -10 53 -50q0 -23 -86 -117q-54 -78 -74 -78h-23 q-31 0 -39 57q0 16 111 145q31 43 57 43z" />
-<glyph unicode="&#xde;" horiz-adv-x="1100" d="M59 1411h13q46 -9 46 -36v-305h415q279 0 370 -241q18 -56 18 -102v-18q0 -183 -180 -297q-93 -46 -157 -46l-26 4h-440v-302q0 -35 -49 -43h-2q-37 0 -47 53v1274q6 59 39 59zM118 972v-504h460q181 0 241 205l4 46q0 173 -184 241q-48 12 -117 12h-404z" />
-<glyph unicode="&#xdf;" horiz-adv-x="1061" d="M354 1400h41q165 0 283 -157q63 -95 63 -203q0 -83 -60 -207v-44q0 -47 129 -191q84 -103 84 -220v-15q0 -204 -210 -310q-63 -28 -132 -28h-3q-171 0 -276 141l-2 16q11 47 46 47h7q23 0 74 -57q79 -51 154 -51q172 0 238 187l8 57v9q0 106 -115 227q-102 105 -102 203 q0 52 51 166q9 22 9 59v33q0 134 -148 217q-50 25 -116 25q-184 0 -254 -203l-7 -112v-914q0 -34 -48 -43h-2q-36 0 -46 52v937q0 266 250 362q48 17 84 17z" />
-<glyph unicode="&#xe0;" horiz-adv-x="1147" d="M475 1360h21q20 0 127 -140q23 -25 23 -42v-8q0 -35 -50 -44q-29 0 -80 78q-79 88 -79 101v15q0 29 38 40zM504 974q269 0 426 -264q48 -106 48 -221v-423q0 -33 -46 -41h-2q-30 0 -44 35v-2l3 91v62q-195 -186 -371 -186h-29q-241 0 -401 243q-59 116 -59 235 q0 265 260 419q111 52 215 52zM121 507v-11q0 -232 234 -351q74 -28 134 -28h29q195 0 321 194q47 93 47 178v14q0 225 -222 343q-78 36 -160 36h-4q-236 0 -355 -246q-24 -76 -24 -129z" />
-<glyph unicode="&#xe1;" horiz-adv-x="1114" d="M566 1364q51 -12 51 -44v-7q0 -21 -75 -106q-53 -81 -93 -81h-4q-26 0 -37 47v5q0 23 107 144q32 42 51 42zM475 974q269 0 426 -264q48 -106 48 -221v-423q0 -33 -46 -41h-2q-30 0 -44 35v-2l3 91v62q-195 -186 -371 -186h-29q-241 0 -401 243q-59 116 -59 235 q0 265 260 419q111 52 215 52zM92 507v-11q0 -232 234 -351q74 -28 134 -28h29q195 0 321 194q47 93 47 178v14q0 225 -222 343q-78 36 -160 36h-4q-236 0 -355 -246q-24 -76 -24 -129z" />
-<glyph unicode="&#xe2;" horiz-adv-x="1140" d="M460 1367l3 -3h22l4 3q30 0 96 -97q65 -69 65 -92q-9 -50 -48 -50q-35 0 -98 95l-10 15h-35q-70 -110 -105 -110q-50 10 -50 48q0 27 98 132q38 59 58 59zM477 979q271 0 429 -265q48 -107 48 -223v-425q0 -33 -47 -41h-1q-31 0 -45 35v-2l4 91v63q-197 -187 -373 -187 h-30q-242 0 -403 244q-59 117 -59 237q0 266 262 421q111 52 215 52zM93 509v-11q0 -233 235 -352q74 -28 134 -28h30q196 0 322 196q47 92 47 177v15q0 225 -223 344q-78 36 -161 36h-4q-237 0 -356 -247q-24 -76 -24 -130z" />
-<glyph unicode="&#xe3;" horiz-adv-x="1122" d="M383 1329h19q62 0 152 -61l36 -9h25l71 21q48 -9 48 -48q0 -52 -117 -67h-24q-61 0 -152 61l-36 9h-25l-70 -18h-2q-43 9 -43 41v11q0 35 63 50q27 10 55 10zM479 983q272 0 430 -267q49 -107 49 -223v-427q0 -33 -47 -41h-2q-30 0 -44 35v-1l3 92v63 q-197 -189 -374 -189h-30q-243 0 -404 246q-60 117 -60 237q0 267 263 423q112 52 216 52zM93 511v-11q0 -234 236 -354q76 -28 135 -28h30q197 0 323 196q48 94 48 179v15q0 226 -224 345q-78 37 -162 37h-4q-238 0 -357 -248q-25 -77 -25 -131z" />
-<glyph unicode="&#xe4;" horiz-adv-x="1136" d="M333 1221h5q44 -10 44 -37v-11q0 -37 -48 -45q-45 9 -45 45v11q0 27 44 37zM609 1221h15q29 0 37 -54q0 -27 -49 -39q-44 8 -44 41v14q12 38 41 38zM477 979q271 0 429 -265q48 -107 48 -223v-425q0 -33 -47 -41h-1q-31 0 -45 35v-2l4 91v63q-197 -187 -373 -187h-30 q-242 0 -403 244q-59 117 -59 237q0 266 262 421q111 52 215 52zM93 509v-11q0 -233 235 -352q74 -28 134 -28h30q196 0 322 196q47 92 47 177v15q0 225 -223 344q-78 36 -161 36h-4q-237 0 -356 -247q-24 -76 -24 -130z" />
-<glyph unicode="&#xe5;" horiz-adv-x="1131" d="M493 1422q89 0 142 -96q15 -33 15 -66q0 -105 -124 -150l-32 -4h-13q-100 0 -144 124l-4 31v10q0 106 131 148zM397 1268v-19q23 -79 84 -79h14q78 0 91 94q-16 95 -96 95q-93 -16 -93 -91zM477 979q271 0 429 -265q48 -107 48 -223v-425q0 -33 -47 -41h-1q-31 0 -45 35 v-2l4 91v63q-197 -187 -373 -187h-30q-242 0 -403 244q-59 117 -59 237q0 266 262 421q111 52 215 52zM93 509v-11q0 -233 235 -352q74 -28 134 -28h30q196 0 322 196q47 92 47 177v15q0 225 -223 344q-78 36 -161 36h-4q-237 0 -356 -247q-24 -76 -24 -130z" />
-<glyph unicode="&#xe6;" horiz-adv-x="1961" d="M475 979q250 0 418 -245h31q93 159 270 220q80 21 143 21q265 0 420 -257q51 -107 51 -200v-45q-8 -46 -44 -46h-792v-33q41 -133 150 -207q102 -66 211 -66q94 0 205 56l10 2q49 -12 49 -48q0 -71 -219 -102l-50 -4q-181 0 -378 182v-138q0 -39 -52 -44h-3q-21 0 -37 37 l4 83v70q-196 -186 -372 -186h-29q-242 0 -402 243q-59 116 -59 235q0 266 261 420q111 52 214 52zM92 511v-11q0 -232 234 -351q76 -28 135 -28h29q195 0 321 195q47 92 47 177v14q0 225 -222 344q-78 36 -161 36h-3q-237 0 -356 -246q-24 -77 -24 -130zM961 519h748v29 q0 106 -125 238q-120 93 -251 93q-200 0 -324 -187q-48 -89 -48 -173z" />
-<glyph unicode="&#xe7;" horiz-adv-x="986" d="M482 971q183 0 329 -136q6 -10 6 -21v-1q-8 -46 -44 -46h-4q-18 0 -103 65q-88 44 -173 44h-22q-227 0 -343 -237q-27 -81 -27 -144q0 -231 237 -351q72 -27 151 -27q135 0 260 104l20 5h8q32 0 40 -46v-2q0 -57 -214 -139l-95 -13v-83q109 -72 109 -165 q0 -133 -155 -171l-48 4h-57l-54 -4q-40 14 -40 37v12q9 43 41 43h127q94 0 94 79v4q0 61 -82 78q-27 13 -27 31v138q-106 15 -232 100q-175 157 -175 369q0 231 205 387q130 86 268 86z" />
-<glyph unicode="&#xe8;" horiz-adv-x="1127" d="M473 979q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35q90 0 200 55h14q43 -9 43 -41v-11q0 -69 -241 -100h-24q-256 0 -410 241q-63 113 -63 236q0 262 247 418q121 59 226 59zM97 521h757q0 108 -94 236q-130 122 -257 122 h-41q-189 0 -310 -184q-43 -74 -55 -174zM444 1356h22q20 0 128 -141q23 -25 23 -42v-8q0 -36 -50 -44q-30 0 -81 78q-79 88 -79 102v14q0 30 37 41z" />
-<glyph unicode="&#xe9;" horiz-adv-x="1118" d="M473 979q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35q90 0 200 55h14q43 -9 43 -41v-11q0 -69 -241 -100h-24q-256 0 -410 241q-63 113 -63 236q0 262 247 418q121 59 226 59zM97 521h757q0 108 -94 236q-130 122 -257 122 h-41q-189 0 -310 -184q-43 -74 -55 -174zM566 1360q51 -12 51 -45v-7q0 -20 -76 -106q-53 -81 -93 -81h-4q-27 0 -37 47v5q0 24 107 145q32 42 52 42z" />
-<glyph unicode="&#xea;" horiz-adv-x="1144" d="M473 979q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35q90 0 200 55h14q43 -9 43 -41v-11q0 -69 -241 -100h-24q-256 0 -410 241q-63 113 -63 236q0 262 247 418q121 59 226 59zM97 521h757q0 108 -94 236q-130 122 -257 122 h-41q-189 0 -310 -184q-43 -74 -55 -174zM460 1367l3 -3h22l4 3q30 0 96 -97q65 -69 65 -92q-9 -50 -48 -50q-35 0 -98 95l-10 15h-35q-70 -110 -105 -110q-50 10 -50 48q0 27 98 132q38 59 58 59z" />
-<glyph unicode="&#xeb;" horiz-adv-x="1122" d="M333 1218h5q43 -10 43 -37v-11q0 -37 -48 -45q-44 9 -44 45v11q0 27 44 37zM607 1218h15q29 0 37 -54q0 -27 -49 -38q-43 7 -43 40v15q11 37 40 37zM472 977q275 0 428 -261q52 -102 52 -222v-17q-9 -50 -45 -50h-805q57 -188 209 -271q90 -35 169 -35q90 0 199 55h14 q43 -9 43 -41v-11q0 -68 -240 -99h-24q-255 0 -410 240q-62 113 -62 236q0 261 247 417q120 59 225 59zM97 520h755q0 108 -94 235q-129 122 -257 122h-40q-188 0 -310 -184q-42 -73 -54 -173z" />
-<glyph unicode="&#xec;" horiz-adv-x="514" d="M118 1319h21q20 0 128 -141q23 -26 23 -43v-7q0 -36 -50 -45q-30 0 -81 78q-79 89 -79 102v15q0 29 38 41zM209 978q48 -12 48 -37v-875q0 -33 -47 -41h-1q-35 0 -45 50v843q6 60 45 60z" />
-<glyph unicode="&#xed;" horiz-adv-x="514" d="M279 1328q52 -12 52 -45v-7q0 -21 -76 -107q-54 -82 -94 -82h-4q-27 0 -37 48v5q0 23 108 145q32 43 51 43zM210 982q47 -12 47 -37v-879q0 -33 -46 -41h-2q-35 0 -45 51v846q6 60 46 60z" />
-<glyph unicode="&#xee;" horiz-adv-x="514" d="M189 1323l4 -3h22l3 3q29 0 96 -98q65 -70 65 -92q-9 -51 -49 -51q-34 0 -99 99l-15 11h-29q-71 -110 -106 -110q-51 10 -51 49q0 26 98 132q39 60 61 60zM205 987q48 -12 48 -38v-882q0 -34 -47 -42h-1q-36 0 -46 51v850q6 61 46 61z" />
-<glyph unicode="&#xef;" horiz-adv-x="514" d="M209 983q48 -12 48 -38v-879q0 -33 -47 -41h-2q-35 0 -45 51v846q6 61 46 61zM64 1248h5q44 -10 44 -38v-11q0 -37 -48 -45q-45 9 -45 45v11q0 28 44 38zM341 1248h14q30 0 38 -55q0 -27 -50 -39q-43 8 -43 41v15q12 38 41 38z" />
-<glyph unicode="&#xf0;" horiz-adv-x="1118" d="M723 1378h4q44 -9 44 -41v-14q0 -31 -169 -117v-26l283 -435q69 -117 69 -243q0 -268 -254 -421q-110 -56 -212 -56h-29q-192 0 -358 182q-101 142 -101 295q0 232 206 390q132 87 270 87l129 -14v39l-95 144q-146 -93 -165 -93h-15q-28 0 -37 47v1q0 34 97 81l71 43 q-51 77 -51 88v15q11 37 41 37h15q22 0 76 -89q164 100 181 100zM97 513v-18q0 -215 207 -334q76 -39 162 -39h22q223 0 342 231q27 74 27 142v18q0 151 -137 283q-108 86 -247 86q-244 0 -356 -254q-20 -63 -20 -115z" />
-<glyph unicode="&#xf1;" horiz-adv-x="1108" d="M374 1336h18q62 0 150 -60l37 -10h26l70 21q47 -9 47 -47q0 -52 -116 -66h-24q-61 0 -151 60l-36 9h-24l-70 -18h-2q-43 9 -43 41v11q0 35 63 49q27 10 55 10zM45 977q48 -12 48 -37v-136q194 173 372 173q195 0 347 -163q111 -137 111 -287v-465q0 -28 -47 -37h1 q-47 8 -47 45v409q0 292 -255 386q-62 16 -110 16h-11q-214 0 -329 -219q-32 -69 -32 -212v-384q0 -33 -47 -41h-1q-35 0 -45 50v842q6 60 45 60z" />
-<glyph unicode="&#xf2;" horiz-adv-x="1118" d="M477 979q184 0 334 -140q143 -149 143 -337q0 -268 -254 -421q-110 -56 -212 -56h-29q-192 0 -358 182q-101 142 -101 295q0 232 206 390q132 87 271 87zM97 513v-18q0 -215 207 -334q76 -39 162 -39h22q223 0 342 231q27 74 27 142v18q0 179 -163 302q-98 67 -221 67 q-244 0 -356 -254q-20 -63 -20 -115zM448 1367h22q19 0 127 -141q24 -25 24 -42v-8q0 -36 -51 -44q-29 0 -80 78q-80 88 -80 102v14q0 29 38 41z" />
-<glyph unicode="&#xf3;" horiz-adv-x="1118" d="M566 1364q51 -12 51 -44v-7q0 -21 -75 -106q-53 -81 -93 -81h-4q-26 0 -37 47v5q0 23 107 144q32 42 51 42zM475 974q182 0 332 -139q142 -149 142 -335q0 -267 -253 -420q-109 -55 -211 -55h-29q-190 0 -355 181q-101 142 -101 294q0 231 205 388q131 86 270 86zM96 510 v-18q0 -213 206 -332q76 -39 162 -39h21q223 0 341 230q27 74 27 141v18q0 180 -163 301q-97 67 -219 67q-243 0 -355 -253q-20 -63 -20 -115z" />
-<glyph unicode="&#xf4;" horiz-adv-x="1118" d="M459 1360l4 -3h22l3 3q28 0 94 -96q64 -69 64 -92q-8 -50 -48 -50q-33 0 -96 97l-14 13h-31q-70 -110 -103 -110q-51 10 -51 48q0 27 97 131q37 59 59 59zM475 974q182 0 332 -139q142 -149 142 -335q0 -267 -253 -420q-109 -55 -211 -55h-29q-190 0 -355 181 q-101 142 -101 294q0 231 205 388q131 86 270 86zM96 510v-18q0 -213 206 -332q76 -39 162 -39h21q223 0 341 230q27 74 27 141v18q0 180 -163 301q-97 67 -219 67q-243 0 -355 -253q-20 -63 -20 -115z" />
-<glyph unicode="&#xf5;" horiz-adv-x="1118" d="M477 979q184 0 334 -140q143 -149 143 -337q0 -268 -254 -421q-110 -56 -212 -56h-29q-192 0 -358 182q-101 142 -101 295q0 232 206 390q132 87 271 87zM97 513v-18q0 -215 207 -334q76 -39 162 -39h22q223 0 342 231q27 74 27 142v18q0 179 -163 302q-98 67 -221 67 q-244 0 -356 -254q-20 -63 -20 -115zM382 1323h18q62 0 151 -60l37 -9h25l70 21q47 -9 47 -47q0 -53 -116 -67h-23q-61 0 -151 60l-37 10h-24l-70 -19h-2q-43 9 -43 41v11q0 35 62 49q27 10 56 10z" />
-<glyph unicode="&#xf6;" horiz-adv-x="1114" d="M332 1215h5q43 -10 43 -37v-11q0 -37 -48 -45q-44 9 -44 45v11q0 27 44 37zM606 1215h14q29 0 37 -54q0 -27 -49 -38q-43 7 -43 40v14q12 38 41 38zM475 974q182 0 332 -139q142 -149 142 -335q0 -267 -253 -420q-109 -55 -211 -55h-29q-190 0 -355 181 q-101 142 -101 294q0 231 205 388q131 86 270 86zM96 510v-18q0 -213 206 -332q76 -39 162 -39h21q223 0 341 230q27 74 27 141v18q0 180 -163 301q-97 67 -219 67q-243 0 -355 -253q-20 -63 -20 -115z" />
-<glyph unicode="&#xf7;" d="M497 1107h4q72 0 87 -77v-11q-17 -78 -75 -78h-7q-84 9 -84 83v5q19 78 75 78zM203 775h604q53 -10 53 -51v-12q0 -30 -50 -43h-611q-49 10 -49 47v16q0 32 53 43zM504 503h5q66 0 79 -89v-2q0 -61 -83 -78q-83 17 -83 74v20q0 56 82 75z" />
-<glyph unicode="&#xf8;" horiz-adv-x="1169" d="M938 987h4q36 0 44 -54q0 -16 -111 -123q122 -149 122 -311q0 -267 -253 -419q-108 -55 -210 -55h-29q-129 0 -289 111q-88 -107 -115 -107h-14q-29 0 -37 53q0 17 106 119q-106 146 -106 298q0 230 205 387q130 86 269 86q138 0 288 -99q93 114 126 114zM146 509v-18 q0 -96 60 -207h30l504 521q-102 71 -220 71q-243 0 -354 -252q-20 -63 -20 -115zM809 744l-526 -545q127 -78 230 -78h21q222 0 340 229q27 74 27 141v18q0 117 -92 235z" />
-<glyph unicode="&#xf9;" horiz-adv-x="1109" d="M447 1364h21q20 0 128 -141q23 -25 23 -42v-8q0 -36 -50 -44q-30 0 -81 78q-79 88 -79 102v14q0 29 38 41zM45 977q48 -12 48 -38v-391q0 -265 153 -357q96 -73 215 -73q230 0 345 235q24 76 24 151v422q10 51 45 51q47 -12 47 -45v-870q0 -28 -47 -37h1q-46 8 -46 44v95 h-39q-153 -139 -319 -139h-25q-215 0 -374 212q-73 113 -73 282v397q6 61 45 61z" />
-<glyph unicode="&#xfa;" horiz-adv-x="1105" d="M571 1374q51 -11 51 -44v-8q0 -20 -76 -106q-54 -82 -94 -82h-3q-27 0 -38 48v4q0 24 108 146q32 42 52 42zM45 981q48 -12 48 -37v-393q0 -266 154 -359q96 -74 217 -74q230 0 346 237q24 76 24 152v424q10 50 45 50q48 -11 48 -44v-875q0 -28 -47 -37h1q-47 8 -47 45 v95h-39q-153 -140 -320 -140h-26q-216 0 -376 213q-73 114 -73 284v399q6 60 45 60z" />
-<glyph unicode="&#xfb;" horiz-adv-x="1114" d="M463 1378l4 -4h27l3 4q26 0 93 -98q65 -70 65 -93q-8 -51 -49 -51q-34 0 -99 98l-13 13h-31q-71 -111 -105 -111q-52 10 -52 49q0 27 99 133q38 60 58 60zM46 987q48 -12 48 -38v-395q0 -268 155 -361q96 -74 217 -74q232 0 348 237q24 77 24 153v426q10 52 46 52 q48 -12 48 -46v-878q0 -29 -47 -38q-47 9 -47 45v95h-39q-154 -140 -322 -140h-26q-217 0 -377 214q-74 114 -74 285v402q6 61 46 61z" />
-<glyph unicode="&#xfc;" horiz-adv-x="1109" d="M333 1219h5q44 -10 44 -37v-11q0 -37 -48 -45q-45 9 -45 45v11q0 27 44 37zM608 1219h14q30 0 38 -54q0 -27 -50 -39q-43 8 -43 41v14q12 38 41 38zM45 977q48 -12 48 -37v-391q0 -266 153 -358q96 -73 216 -73q229 0 344 235q24 76 24 152v421q10 51 46 51 q47 -11 47 -44v-871q0 -28 -47 -37h1q-47 8 -47 45v94h-38q-153 -139 -320 -139h-25q-215 0 -374 212q-73 113 -73 282v398q6 60 45 60z" />
-<glyph unicode="&#xfd;" horiz-adv-x="990" d="M589 1381q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM776 992q51 -10 51 -45v-1q-3 -22 -361 -876q-169 -417 -186 -440q-12 -9 -29 -13q-49 10 -49 36v19q0 8 165 405v14l-348 850v-4q10 51 48 51q44 0 83 -129 q238 -565 249 -611h41q293 715 305 729q17 15 31 15z" />
-<glyph unicode="&#xfe;" horiz-adv-x="1131" d="M48 1369h11q44 -9 44 -34v-541q196 188 386 188q185 0 335 -140q144 -150 144 -339q0 -269 -256 -423q-109 -56 -212 -56h-29q-166 0 -368 182v-563q0 -27 -51 -38q-31 0 -42 54v1653q6 57 38 57zM107 514v-18q0 -215 208 -335q76 -39 163 -39h22q224 0 343 232 q28 73 28 142v18q0 181 -165 304q-98 67 -221 67q-245 0 -357 -255q-21 -63 -21 -116z" />
-<glyph unicode="&#xff;" horiz-adv-x="990" d="M280 1216h5q44 -10 44 -37v-11q0 -37 -48 -45q-45 9 -45 45v11q0 27 44 37zM554 1216h15q29 0 37 -54q0 -27 -49 -38q-43 7 -43 40v14q12 38 40 38zM764 975q50 -10 50 -45v-1q-3 -22 -359 -872q-168 -415 -185 -438q-11 -9 -30 -13q-48 10 -48 36v18q0 8 165 404v14 l-347 846v-3q10 50 48 50q44 0 82 -129q237 -562 248 -608h41q292 712 304 726q16 15 31 15z" />
-<glyph unicode="&#x100;" horiz-adv-x="1184" d="M531 1403q49 0 78 -121q454 -1181 457 -1205v-9q0 -35 -48 -43h-2q-46 0 -70 110l-176 457h-474l-210 -553q-17 -14 -32 -14h-6q-48 9 -48 46l126 341q336 874 363 965q23 26 42 26zM514 1167l-177 -478h384v34l-169 444h-38zM117 1672h842q47 -9 47 -45v-10 q-9 -47 -42 -47h-847q-38 0 -45 55q13 47 45 47z" />
-<glyph unicode="&#x101;" horiz-adv-x="1199" d="M529 998q276 0 437 -271q49 -108 49 -227v-433q0 -34 -48 -42h-2q-31 0 -46 36v-2l4 93v63q-200 -190 -380 -190h-29q-247 0 -412 249q-60 119 -60 241q0 271 267 430q113 53 220 53zM138 519v-11q0 -238 239 -359q77 -28 137 -28h29q200 0 329 199q47 94 47 180v15 q0 230 -226 351q-80 36 -164 36h-4q-242 0 -363 -251q-24 -78 -24 -132zM119 1272h842q47 -9 47 -45v-10q-9 -47 -42 -47h-847q-38 0 -45 55q13 47 45 47z" />
-<glyph unicode="&#x102;" horiz-adv-x="1202" d="M325 1781h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM531 1403q49 0 78 -121q454 -1181 457 -1205v-9q0 -35 -48 -43h-2q-46 0 -70 110l-176 457h-474l-210 -553 q-17 -14 -32 -14h-6q-48 9 -48 46l126 341q336 874 363 965q23 26 42 26zM514 1167l-177 -478h384v34l-169 444h-38z" />
-<glyph unicode="&#x103;" horiz-adv-x="1118" d="M281 1389h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM487 998q276 0 437 -271q49 -108 49 -227v-433q0 -34 -48 -42h-2q-31 0 -46 36v-2l4 93v63 q-200 -190 -380 -190h-29q-247 0 -412 249q-60 119 -60 241q0 271 267 430q113 53 220 53zM96 519v-11q0 -238 239 -359q77 -28 137 -28h29q200 0 329 199q47 94 47 180v15q0 230 -226 351q-80 36 -164 36h-4q-242 0 -363 -251q-24 -78 -24 -132z" />
-<glyph unicode="&#x104;" horiz-adv-x="1338" d="M547 1412q48 0 76 -112q478 -1245 478 -1264l4 -27v-93q0 -43 -67 -53q-48 -28 -48 -74v-8q0 -64 81 -74h145q50 -9 50 -48v-1q-10 -51 -40 -51h-161q-127 0 -172 142l-6 42q0 96 119 172v36q-17 72 -215 586h-483l-215 -565q-17 -14 -32 -14h-6q-50 9 -50 48v-1l128 348 q344 892 371 985q24 26 43 26zM530 1171l-180 -487h391v34l-173 453h-38z" />
-<glyph unicode="&#x105;" horiz-adv-x="1241" d="M492 982q278 0 439 -271q50 -110 50 -228v-566q0 -40 -75 -56q-38 -27 -38 -60v-22q15 -67 81 -67h143q37 0 46 -49q-11 -47 -39 -47h-157q-125 0 -170 141l-4 41q0 92 118 166l2 154v78q-200 -190 -381 -190h-30q-248 0 -412 250q-61 119 -61 242q0 272 268 431 q114 53 220 53zM100 501v-11q0 -238 240 -360q77 -28 137 -28h30q201 0 330 199q48 95 48 182v15q0 230 -228 351q-80 37 -165 37h-3q-243 0 -364 -252q-25 -78 -25 -133z" />
-<glyph unicode="&#x106;" horiz-adv-x="1251" d="M808 1838q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121zM689 1411q215 0 397 -128q9 -18 9 -28v-8q0 -41 -55 -47h3l-128 66q-138 44 -226 44q-281 0 -486 -257q-102 -172 -102 -335q0 -329 308 -521 q137 -71 273 -71h11q173 0 343 106h13q46 -10 46 -43v-11q0 -61 -235 -131q-76 -22 -159 -22h-19q-342 0 -573 318q-109 183 -109 375q0 360 329 587q175 106 360 106z" />
-<glyph unicode="&#x107;" horiz-adv-x="973" d="M597 1442q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121zM488 1001q188 0 340 -140q6 -10 6 -22v-2q-9 -48 -46 -48h-4q-19 0 -107 67q-90 46 -178 46h-22q-234 0 -353 -244q-28 -83 -28 -149q0 -237 244 -360 q74 -28 156 -28q138 0 266 107l21 5h9q34 0 42 -48v-1q0 -60 -222 -145q-76 -14 -113 -14h-30q-196 0 -365 186q-104 146 -104 302q0 238 211 400q134 88 277 88z" />
-<glyph unicode="&#x108;" horiz-adv-x="1254" d="M647 1789h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM689 1411q215 0 397 -128q9 -18 9 -28v-8q0 -41 -55 -47h3l-128 66q-138 44 -226 44q-281 0 -486 -257 q-102 -172 -102 -335q0 -329 308 -521q137 -71 273 -71h11q173 0 343 106h13q46 -10 46 -43v-11q0 -61 -235 -131q-76 -22 -159 -22h-19q-342 0 -573 318q-109 183 -109 375q0 360 329 587q175 106 360 106z" />
-<glyph unicode="&#x109;" horiz-adv-x="982" d="M484 1424h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM488 1001q188 0 340 -140q6 -10 6 -22v-2q-9 -48 -46 -48h-4q-19 0 -107 67q-90 46 -178 46h-22 q-234 0 -353 -244q-28 -83 -28 -149q0 -237 244 -360q74 -28 156 -28q138 0 266 107l21 5h9q34 0 42 -48v-1q0 -60 -222 -145q-76 -14 -113 -14h-30q-196 0 -365 186q-104 146 -104 302q0 238 211 400q134 88 277 88z" />
-<glyph unicode="&#x10a;" horiz-adv-x="1259" d="M694 1755q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4zM689 1411q215 0 397 -128q9 -18 9 -28v-8q0 -41 -55 -47h3l-128 66q-138 44 -226 44q-281 0 -486 -257q-102 -172 -102 -335q0 -329 308 -521q137 -71 273 -71h11 q173 0 343 106h13q46 -10 46 -43v-11q0 -61 -235 -131q-76 -22 -159 -22h-19q-342 0 -573 318q-109 183 -109 375q0 360 329 587q175 106 360 106z" />
-<glyph unicode="&#x10b;" horiz-adv-x="973" d="M509 1354q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4zM488 1001q188 0 340 -140q6 -10 6 -22v-2q-9 -48 -46 -48h-4q-19 0 -107 67q-90 46 -178 46h-22q-234 0 -353 -244q-28 -83 -28 -149q0 -237 244 -360q74 -28 156 -28 q138 0 266 107l21 5h9q34 0 42 -48v-1q0 -60 -222 -145q-76 -14 -113 -14h-30q-196 0 -365 186q-104 146 -104 302q0 238 211 400q134 88 277 88z" />
-<glyph unicode="&#x10c;" horiz-adv-x="1241" d="M531 1788h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM689 1411q215 0 397 -128q9 -18 9 -28v-8q0 -41 -55 -47h3l-128 66q-138 44 -226 44q-281 0 -486 -257 q-102 -172 -102 -335q0 -329 308 -521q137 -71 273 -71h11q173 0 343 106h13q46 -10 46 -43v-11q0 -61 -235 -131q-76 -22 -159 -22h-19q-342 0 -573 318q-109 183 -109 375q0 360 329 587q175 106 360 106z" />
-<glyph unicode="&#x10d;" horiz-adv-x="990" d="M338 1414h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM488 1001q188 0 340 -140q6 -10 6 -22v-2q-9 -48 -46 -48h-4q-19 0 -107 67q-90 46 -178 46h-22q-234 0 -353 -244 q-28 -83 -28 -149q0 -237 244 -360q74 -28 156 -28q138 0 266 107l21 5h9q34 0 42 -48v-1q0 -60 -222 -145q-76 -14 -113 -14h-30q-196 0 -365 186q-104 146 -104 302q0 238 211 400q134 88 277 88z" />
-<glyph unicode="&#x10e;" horiz-adv-x="1162" d="M297 1793h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM72 1410l-9 2h197l42 4q310 0 541 -272q146 -190 146 -431q0 -332 -293 -560q-185 -128 -391 -128h-256 q-49 9 -49 47v1291q7 49 72 49v-2zM98 1318v-1195h188q376 0 558 364q47 124 47 237q0 273 -240 474q-150 120 -441 120h-112z" />
-<glyph unicode="&#x10f;" horiz-adv-x="1343" d="M1129 1489h28q61 0 87 -213v-18q0 -117 -133 -227q-21 -12 -25 -12q-6 2 -8 6q60 144 60 241v12q0 69 -48 151v10q10 50 39 50zM923 1407h12q46 -9 46 -36v-748l4 -128q0 -140 -115 -294q-163 -176 -366 -176h-30q-198 0 -369 187q-105 148 -105 306q0 239 213 403 q135 89 280 89q187 0 395 -186v484l-4 56q14 43 39 43zM97 529v-19q0 -247 258 -367q70 -21 126 -21h23q241 0 364 258q20 79 20 122v23q0 246 -263 368q-80 20 -125 20h-15q-241 0 -363 -253q-25 -73 -25 -131z" />
-<glyph unicode="&#x110;" horiz-adv-x="1303" d="M185 822v541q7 49 72 49v-2l-9 2h197l42 4q310 0 541 -272q146 -190 146 -431q0 -332 -293 -560q-185 -128 -391 -128h-256q-49 9 -49 47v648h-75l-59 -4q-47 17 -47 53q9 53 47 53h134zM283 822h209l36 4q35 0 50 -58q0 -35 -47 -52l-55 4h-193v-597h188q376 0 558 364 q47 124 47 237q0 273 -240 474q-150 120 -441 120h-112v-496z" />
-<glyph unicode="&#x111;" horiz-adv-x="1343" d="M128 529v-19q0 -247 258 -367q70 -21 126 -21h23q241 0 364 258q20 79 20 122v23q0 246 -263 368q-80 20 -125 20h-15q-241 0 -363 -253q-25 -73 -25 -131zM921 1284l-6 80q14 43 39 43h12q46 -9 46 -36v-87h153l36 4q35 0 50 -58q0 -35 -47 -52l-55 4h-137v-559l4 -128 q0 -140 -115 -294q-163 -176 -366 -176h-30q-198 0 -369 187q-105 148 -105 306q0 239 213 403q135 89 280 89q187 0 395 -186v358h-136l-59 -4q-47 17 -47 53q9 53 72 53v1l14 -1h158z" />
-<glyph unicode="&#x112;" horiz-adv-x="1100" d="M60 1702h841q48 -9 48 -45v-10q-9 -47 -42 -47h-847q-38 0 -45 55q13 47 45 47zM129 1405l-9 2h746l15 4q40 0 47 -57q-9 -44 -57 -44h-717v-560h479l53 3q31 0 43 -53q0 -30 -41 -48l-70 4h-464v-534h736q30 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286 q7 49 72 49v-2z" />
-<glyph unicode="&#x113;" horiz-adv-x="1105" d="M473 979q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35q90 0 200 55h14q43 -9 43 -41v-11q0 -69 -241 -100h-24q-256 0 -410 241q-63 113 -63 236q0 262 247 418q121 59 226 59zM97 521h757q0 108 -94 236q-130 122 -257 122 h-41q-189 0 -310 -184q-43 -74 -55 -174zM60 1293h842q47 -9 47 -45v-10q-9 -47 -42 -47h-847q-38 0 -45 55q13 47 45 47z" />
-<glyph unicode="&#x114;" horiz-adv-x="1052" d="M107 1405l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286q7 49 72 49v-2zM267 1799h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6 q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50z" />
-<glyph unicode="&#x115;" horiz-adv-x="1101" d="M482 979q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35q90 0 200 55h14q43 -9 43 -41v-11q0 -69 -241 -100h-24q-256 0 -410 241q-63 113 -63 236q0 262 247 418q121 59 226 59zM106 521h757q0 108 -94 236 q-130 122 -257 122h-41q-189 0 -310 -184q-43 -74 -55 -174zM276 1411h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50z" />
-<glyph unicode="&#x116;" horiz-adv-x="1070" d="M103 1405l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286q7 49 72 49v-2zM479 1760q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96 q0 57 71 85q8 4 23 4z" />
-<glyph unicode="&#x117;" horiz-adv-x="1105" d="M495 979q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35q90 0 200 55h14q43 -9 43 -41v-11q0 -69 -241 -100h-24q-256 0 -410 241q-63 113 -63 236q0 262 247 418q121 59 226 59zM119 521h757q0 108 -94 236 q-130 122 -257 122h-41q-189 0 -310 -184q-43 -74 -55 -174zM518 1324q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4z" />
-<glyph unicode="&#x118;" horiz-adv-x="1052" d="M589 25h-509q-49 9 -49 47v1286q7 49 72 49v-2l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-185q6 -35 7 -37v-101q0 -36 -66 -46q-40 -29 -40 -70q0 -78 92 -78h105 l12 3q45 -10 45 -41v-7q0 -29 -35 -42l-69 4h-38l-56 -4q-58 0 -122 81q-21 40 -21 70v28q0 81 106 140v20z" />
-<glyph unicode="&#x119;" horiz-adv-x="1122" d="M119 521h757q0 108 -94 236q-130 122 -257 122h-41q-189 0 -310 -184q-43 -74 -55 -174zM520 25h-25q-256 0 -410 241q-63 113 -63 236q0 262 247 418q121 59 226 59q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35 q90 0 200 55h14q43 -9 43 -41v-11q0 -49 -158 -87q10 -30 10 -32v-101q0 -36 -66 -46q-40 -29 -40 -70q0 -78 92 -78h105l12 3q45 -10 45 -41v-7q0 -29 -35 -42l-69 4h-38l-56 -4q-58 0 -122 81q-21 40 -21 70v28q0 81 106 140v20z" />
-<glyph unicode="&#x11a;" horiz-adv-x="1065" d="M107 1405l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286q7 49 72 49v-2zM332 1793h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12 q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50z" />
-<glyph unicode="&#x11b;" horiz-adv-x="1136" d="M517 979q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35q90 0 200 55h14q43 -9 43 -41v-11q0 -69 -241 -100h-24q-256 0 -410 241q-63 113 -63 236q0 262 247 418q121 59 226 59zM141 521h757q0 108 -94 236 q-130 122 -257 122h-41q-189 0 -310 -184q-43 -74 -55 -174zM390 1397h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50z" />
-<glyph unicode="&#x11c;" horiz-adv-x="1285" d="M682 1811h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM713 1411q221 0 394 -121q12 -16 12 -31v-4q0 -37 -53 -47q-4 0 -135 62q-93 36 -180 36h-61q-222 0 -423 -213 q-131 -179 -131 -367v-15q0 -307 284 -501q148 -84 297 -84h15q146 0 305 86v384h-296q-48 8 -48 47v1q8 49 46 49h352q35 0 43 -49v-417q0 -76 -32 -92q-188 -110 -363 -110h-22q-342 0 -573 318q-109 179 -109 375q0 348 310 576q190 117 368 117z" />
-<glyph unicode="&#x11d;" horiz-adv-x="1167" d="M502 1429h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM507 996q216 0 374 -180q110 -150 110 -282l-4 -126v-449q0 -114 -182 -255q-142 -92 -298 -92 q-266 0 -440 238q-29 48 -29 60v11q0 29 45 39h8q33 0 63 -81q144 -180 353 -180q252 0 381 233l8 54v226q-200 -184 -378 -184h-30q-194 0 -362 184q-103 145 -103 300q0 236 209 396q133 88 275 88zM118 523v-18q0 -243 254 -361q69 -21 124 -21h22q238 0 359 254 q19 77 19 120v23q0 242 -258 362q-80 19 -124 19h-14q-238 0 -358 -250q-24 -70 -24 -128z" />
-<glyph unicode="&#x11e;" horiz-adv-x="1246" d="M465 1782h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM700 1411q221 0 394 -121q12 -16 12 -31v-4q0 -37 -53 -47q-4 0 -135 62q-93 36 -180 36h-61 q-222 0 -423 -213q-131 -179 -131 -367v-15q0 -307 284 -501q148 -84 297 -84h15q146 0 305 86v384h-296q-48 8 -48 47v1q8 49 46 49h352q35 0 43 -49v-417q0 -76 -32 -92q-188 -110 -363 -110h-22q-342 0 -573 318q-109 179 -109 375q0 348 310 576q190 117 368 117z" />
-<glyph unicode="&#x11f;" horiz-adv-x="1140" d="M311 1411h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM520 996q216 0 374 -180q110 -150 110 -282l-4 -126v-449q0 -114 -182 -255q-142 -92 -298 -92 q-266 0 -440 238q-29 48 -29 60v11q0 29 45 39h8q33 0 63 -81q144 -180 353 -180q252 0 381 233l8 54v226q-200 -184 -378 -184h-30q-194 0 -362 184q-103 145 -103 300q0 236 209 396q133 88 275 88zM131 523v-18q0 -243 254 -361q69 -21 124 -21h22q238 0 359 254 q19 77 19 120v23q0 242 -258 362q-80 19 -124 19h-14q-238 0 -358 -250q-24 -70 -24 -128z" />
-<glyph unicode="&#x120;" horiz-adv-x="1272" d="M725 1768q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4zM704 1411q221 0 394 -121q12 -16 12 -31v-4q0 -37 -53 -47q-4 0 -135 62q-93 36 -180 36h-61q-222 0 -423 -213q-131 -179 -131 -367v-15q0 -307 284 -501q148 -84 297 -84 h15q146 0 305 86v384h-296q-48 8 -48 47v1q8 49 46 49h352q35 0 43 -49v-417q0 -76 -32 -92q-188 -110 -363 -110h-22q-342 0 -573 318q-109 179 -109 375q0 348 310 576q190 117 368 117z" />
-<glyph unicode="&#x121;" horiz-adv-x="1149" d="M554 1382q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4zM529 996q216 0 374 -180q110 -150 110 -282l-4 -126v-449q0 -114 -182 -255q-142 -92 -298 -92q-266 0 -440 238q-29 48 -29 60v11q0 29 45 39h8q33 0 63 -81 q144 -180 353 -180q252 0 381 233l8 54v226q-200 -184 -378 -184h-30q-194 0 -362 184q-103 145 -103 300q0 236 209 396q133 88 275 88zM140 523v-18q0 -243 254 -361q69 -21 124 -21h22q238 0 359 254q19 77 19 120v23q0 242 -258 362q-80 19 -124 19h-14 q-238 0 -358 -250q-24 -70 -24 -128z" />
-<glyph unicode="&#x122;" horiz-adv-x="1276" d="M671 26q-319 31 -527 317q-109 179 -109 375q0 348 310 576q190 117 368 117q221 0 394 -121q12 -16 12 -31v-4q0 -37 -53 -47q-4 0 -135 62q-93 36 -180 36h-61q-222 0 -423 -213q-131 -179 -131 -367v-15q0 -307 284 -501q148 -84 297 -84h15q146 0 305 86v384h-296 q-48 8 -48 47v1q8 49 46 49h352q35 0 43 -49v-417q0 -76 -32 -92q-166 -97 -345 -110v-67q104 -69 104 -157q0 -126 -147 -163l-46 3h-54l-52 -3q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29v117z" />
-<glyph unicode="&#x123;" horiz-adv-x="1184" d="M612 1643q2 -1 2 -6v-3q-59 -141 -60 -249q0 -67 49 -149l3 -13q0 -41 -61 -53q-72 0 -97 228q0 121 132 233zM542 996q216 0 374 -180q110 -150 110 -282l-4 -126v-449q0 -114 -182 -255q-142 -92 -298 -92q-266 0 -440 238q-29 48 -29 60v11q0 29 45 39h8q33 0 63 -81 q144 -180 353 -180q252 0 381 233l8 54v226q-200 -184 -378 -184h-30q-194 0 -362 184q-103 145 -103 300q0 236 209 396q133 88 275 88zM153 523v-18q0 -243 254 -361q69 -21 124 -21h22q238 0 359 254q19 77 19 120v23q0 242 -258 362q-80 19 -124 19h-14 q-238 0 -358 -250q-24 -70 -24 -128z" />
-<glyph unicode="&#x124;" horiz-adv-x="1176" d="M533 1811h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM79 1408h12q46 -9 46 -35v-623h762v610q8 48 43 48h9q45 -9 45 -43v-1301q0 -29 -50 -39h1q-48 9 -48 47v585 h-762v-589q0 -35 -48 -43h-2q-37 0 -47 53v1271q6 59 39 59z" />
-<glyph unicode="&#x125;" horiz-adv-x="1074" d="M493 1727h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM74 1405h12q46 -9 46 -35v-516q179 155 335 155q238 0 381 -226q54 -99 54 -187v-528q0 -35 -49 -43h-1 q-35 0 -47 46v503q0 221 -228 318q-55 16 -110 16q-227 0 -319 -240q-16 -52 -16 -166v-434q0 -35 -49 -43h-1q-35 0 -47 46v1285q10 49 39 49z" />
-<glyph unicode="&#x126;" horiz-adv-x="1303" d="M137 1165v184q6 59 39 59h12q46 -9 46 -35v-208h762v195q8 48 43 48h9q45 -9 45 -43v-200l50 4q58 0 75 -59q0 -30 -63 -51l-62 3v-998q0 -29 -50 -39h1q-48 9 -48 47v585h-762v-589q0 -35 -48 -43h-2q-37 0 -47 53v983l-51 -2q-68 18 -68 52q12 54 95 54v2zM234 1063 v-313h762v313h-762z" />
-<glyph unicode="&#x127;" horiz-adv-x="1330" d="M291 1262v94q10 49 39 49h12q46 -9 46 -35v-108h451l36 4q38 0 50 -58q0 -33 -44 -52l-62 4h-431v-306q179 155 335 155q238 0 381 -226q54 -99 54 -187v-528q0 -35 -49 -43h-1q-35 0 -47 46v503q0 221 -228 318q-55 16 -110 16q-227 0 -319 -240q-16 -52 -16 -166v-434 q0 -35 -49 -43h-1q-35 0 -47 46v1089h-154l-59 -4q-47 17 -47 53q9 53 72 53v1l14 -1h174z" />
-<glyph unicode="&#x128;" horiz-adv-x="621" d="M170 1714q70 0 178 -70l44 -5l78 23h1q49 -8 49 -47v-4q0 -49 -102 -65l-36 -4q-70 0 -171 71l-41 5l-82 -22q-49 9 -49 45v8q0 50 118 62zM171 1422l15 -2h146l13 2q51 -10 51 -48q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-178q-49 9 -49 47v1 q10 51 40 51h48v1197h-41q-41 0 -47 56v3q0 28 49 42z" />
-<glyph unicode="&#x129;" horiz-adv-x="616" d="M170 1304q70 0 178 -70l44 -5l78 23h1q49 -8 49 -47v-4q0 -49 -102 -65l-36 -4q-70 0 -171 71l-41 5l-82 -22q-49 9 -49 45v8q0 50 118 62zM268 1005q50 -13 50 -39v-898q0 -35 -49 -43h-2q-36 0 -46 52v866q7 62 47 62z" />
-<glyph unicode="&#x12a;" horiz-adv-x="683" d="M94 1690l14 -1h402l36 4q35 0 50 -58q0 -35 -47 -52l-55 4h-366l-59 -4q-47 17 -47 53q9 53 72 53v1zM215 1422l15 -2h146l13 2q51 -10 51 -48q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-178q-49 9 -49 47v1q10 51 40 51h48v1197h-41q-41 0 -47 56v3 q0 28 49 42z" />
-<glyph unicode="&#x12b;" horiz-adv-x="744" d="M116 1285l14 -1h402l36 4q35 0 50 -58q0 -35 -47 -52l-55 4h-366l-59 -4q-47 17 -47 53q9 53 72 53v1zM321 1005q50 -13 50 -39v-898q0 -35 -49 -43h-2q-36 0 -46 52v866q7 62 47 62z" />
-<glyph unicode="&#x12c;" horiz-adv-x="647" d="M77 1807h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM201 1422l15 -2h146l13 2q51 -10 51 -48q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-178 q-49 9 -49 47v1q10 51 40 51h48v1197h-41q-41 0 -47 56v3q0 28 49 42z" />
-<glyph unicode="&#x12d;" horiz-adv-x="647" d="M69 1397h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM268 1005q50 -13 50 -39v-898q0 -35 -49 -43h-2q-36 0 -46 52v866q7 62 47 62z" />
-<glyph unicode="&#x12e;" horiz-adv-x="511" d="M169 25h-60q-49 9 -49 47v1q10 51 40 51h48v1197h-41q-41 0 -47 56v3q0 28 49 42l15 -2h146l13 2q51 -10 51 -48q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-27v-90q0 -36 -66 -46q-40 -29 -40 -70q0 -78 92 -78h105l12 3q45 -10 45 -41v-7 q0 -29 -35 -42l-69 4h-38l-56 -4q-58 0 -122 81q-21 40 -21 70v28q0 81 106 140v21z" />
-<glyph unicode="&#x12f;" horiz-adv-x="466" d="M175 1261q50 -13 50 -39v-22q0 -31 -56 -39q-29 0 -40 50q9 50 46 50zM135 55q-5 13 -7 23v865q7 62 47 62q50 -13 50 -39v-898q0 -5 -1 -12q0 -9 1 -12v-99q0 -36 -66 -46q-40 -29 -40 -70q0 -78 92 -78h105l12 3q45 -10 45 -41v-7q0 -29 -35 -42l-69 4h-38l-56 -4 q-58 0 -122 81q-21 40 -21 70v28q0 81 106 140v20z" />
-<glyph unicode="&#x130;" horiz-adv-x="462" d="M210 1768q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4zM109 1422l15 -2h146l13 2q51 -10 51 -48q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-178q-49 9 -49 47v1q10 51 40 51h48v1197h-41q-41 0 -47 56v3 q0 28 49 42z" />
-<glyph unicode="&#x131;" horiz-adv-x="514" d="M288 945h1q24 -5 24 -18v-876q-5 -26 -24 -26h1q-27 5 -27 18v844q-98 -33 -115 -33q-12 0 -18 25v10q0 18 84 35z" />
-<glyph unicode="&#x132;" horiz-adv-x="1435" d="M1235 1418h12q34 0 43 -49v-921q0 -225 -212 -362q-99 -57 -203 -57h-19q-207 0 -348 202q-64 106 -64 218q11 50 40 50h15q47 0 47 -94q7 -92 107 -199q99 -79 214 -79q229 0 313 237q12 45 12 88v921q9 45 43 45zM109 1422l15 -2h146l13 2q51 -10 51 -48 q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-178q-49 9 -49 47v1q10 51 40 51h48v1197h-41q-41 0 -47 56v3q0 28 49 42z" />
-<glyph unicode="&#x133;" horiz-adv-x="761" d="M526 1251q48 -9 48 -48q0 -41 -51 -48q-43 12 -43 37v22q0 26 46 37zM529 1001q45 -9 45 -45v-928q0 -260 -247 -380q-86 -31 -139 -31l-4 4h-26l-3 -4h8q-41 0 -49 58q0 31 58 40q224 0 300 230l8 115v896q0 37 49 45zM127 1261q50 -13 50 -39v-22q0 -31 -56 -39 q-29 0 -40 50q9 50 46 50zM127 1005q50 -13 50 -39v-898q0 -35 -49 -43h-2q-36 0 -46 52v866q7 62 47 62z" />
-<glyph unicode="&#x134;" horiz-adv-x="1166" d="M836 1785h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM852 1418h12q34 0 43 -49v-921q0 -225 -212 -362q-99 -57 -203 -57h-19q-207 0 -348 202q-64 106 -64 218 q11 50 40 50h15q47 0 47 -94q7 -92 107 -199q99 -79 214 -79q229 0 313 237q12 45 12 88v921q9 45 43 45z" />
-<glyph unicode="&#x135;" horiz-adv-x="810" d="M453 1380h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM476 1001q45 -9 45 -45v-928q0 -260 -247 -380q-86 -31 -139 -31l-4 4h-26l-3 -4h8q-41 0 -49 58q0 31 58 40 q224 0 300 230l8 115v896q0 37 49 45z" />
-<glyph unicode="&#x136;" horiz-adv-x="1104" d="M93 1409h1q49 -8 49 -43v-713q735 734 733 734l27 4h3q45 -9 45 -43v-12q0 -25 -71 -83l-482 -485l543 -672l2 -15v-9q0 -35 -48 -43h-2q-32 0 -105 107l-463 562l-182 -186v-444q0 -35 -49 -43h-1q-37 0 -47 52v1280q10 52 47 52zM546 18q92 -60 92 -148 q0 -126 -147 -163l-46 3h-54l-52 -3q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29q0 41 28 51.5t70 -11.5z" />
-<glyph unicode="&#x137;" horiz-adv-x="1026" d="M99 1410h12q47 -10 47 -36v-793q573 380 656 427h12q39 0 47 -56q0 -29 -109 -87q-290 -196 -319 -201v-33l425 -540l3 -14v1q-9 -49 -47 -49h-7q-31 0 -113 118l-349 434h-22l-177 -113v-400q0 -35 -49 -43h-2q-35 0 -47 46v1289q10 50 39 50zM511 27q92 -60 92 -148 q0 -126 -147 -163l-46 3h-54l-52 -3q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29q0 41 28 51.5t70 -11.5z" />
-<glyph unicode="&#x138;" horiz-adv-x="1043" d="M118 1048l16 1q34 -9 37 -57v-411q573 380 656 427h12q39 0 47 -56q0 -29 -109 -87q-290 -196 -319 -201v-33l425 -540l3 -14v1q-9 -49 -47 -49h-7q-31 0 -113 118l-349 434h-22l-177 -113v-400q0 -35 -49 -43h-2q-35 0 -47 46v922q9 46 45 55z" />
-<glyph unicode="&#x139;" horiz-adv-x="947" d="M473 1799q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121zM70 1408h12q46 -9 46 -35v-1251h642q39 0 46 -52q-13 -45 -46 -45h-692q-37 0 -47 53v1271q6 59 39 59z" />
-<glyph unicode="&#x13a;" horiz-adv-x="466" d="M287 1812q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121zM117 1402h12q46 -9 46 -35v-1245h104q29 0 39 -50v2q-8 -49 -47 -49h-146q-37 0 -47 52v1267q6 58 39 58z" />
-<glyph unicode="&#x13b;" horiz-adv-x="929" d="M61 1408h12q46 -9 46 -35v-1251h642q39 0 46 -52q-13 -45 -46 -45h-692q-37 0 -47 53v1271q6 59 39 59zM506 -78q92 -60 92 -148q0 -126 -147 -163l-46 3h-54l-52 -3q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29q0 41 28 51.5t70 -11.5z " />
-<glyph unicode="&#x13c;" horiz-adv-x="515" d="M166 1402h12q46 -9 46 -35v-1245h104q29 0 39 -50v2q-8 -49 -47 -49h-146q-37 0 -47 52v1267q6 58 39 58zM291 -82q92 -60 92 -148q0 -126 -147 -163l-46 3h-54l-52 -3q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29q0 41 28 51.5t70 -11.5z " />
-<glyph unicode="&#x13d;" horiz-adv-x="973" d="M694 1551h28q61 0 87 -213v-18q0 -117 -133 -227q-21 -12 -25 -12q-6 2 -8 6q60 144 60 241v12q0 69 -48 151v10q10 50 39 50zM105 1408h12q46 -9 46 -35v-1251h642q39 0 46 -52q-13 -45 -46 -45h-692q-37 0 -47 53v1271q6 59 39 59z" />
-<glyph unicode="&#x13e;" horiz-adv-x="559" d="M347 1542h28q61 0 87 -213v-18q0 -117 -133 -227q-21 -12 -25 -12q-6 2 -8 6q60 144 60 241v12q0 69 -48 151v10q10 50 39 50zM113 1402h12q46 -9 46 -35v-1245h104q29 0 39 -50v2q-8 -49 -47 -49h-146q-37 0 -47 52v1267q6 58 39 58z" />
-<glyph unicode="&#x13f;" horiz-adv-x="1004" d="M610 844q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4zM105 1408h12q46 -9 46 -35v-1251h642q39 0 46 -52q-13 -45 -46 -45h-692q-37 0 -47 53v1271q6 59 39 59z" />
-<glyph unicode="&#x140;" horiz-adv-x="665" d="M443 809q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4zM104 1402h12q46 -9 46 -35v-1245h104q29 0 39 -50v2q-8 -49 -47 -49h-146q-37 0 -47 52v1267q6 58 39 58z" />
-<glyph unicode="&#x141;" horiz-adv-x="1079" d="M185 683v666q6 59 39 59h12q46 -9 46 -35v-617q271 198 285 198h20q30 0 43 -50v-9q0 -35 -109 -99l-239 -173v-501h642q39 0 46 -52q-13 -45 -46 -45h-692q-37 0 -47 53v476q-78 -54 -76 -54l-18 -4q-55 11 -55 55q0 43 149 132z" />
-<glyph unicode="&#x142;" horiz-adv-x="695" d="M320 723q217 156 228 156h20q30 0 43 -50v-9q0 -35 -109 -99l-182 -132v-467h104q29 0 39 -50v2q-8 -49 -47 -49h-146q-37 0 -47 52v441l-133 -93l-18 -4q-55 11 -55 55t141 127l65 48v693q6 58 39 58h12q46 -9 46 -35v-644z" />
-<glyph unicode="&#x143;" horiz-adv-x="1285" d="M799 1733q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121zM74 1406h15q32 0 62 -64q58 -65 830 -1062q-5 0 -5 6l16 -21h41v1096q9 45 43 45h11q35 0 43 -48v-1283q0 -41 -56 -50q-28 0 -110 122l-832 1062v-1137 q0 -35 -49 -43h-1q-37 0 -47 52v1266q6 59 39 59z" />
-<glyph unicode="&#x144;" horiz-adv-x="1096" d="M623 1500q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121zM76 977q48 -12 48 -37v-136q194 173 372 173q195 0 347 -163q111 -137 111 -287v-465q0 -28 -47 -37h1q-47 8 -47 45v409q0 292 -255 386q-62 16 -110 16h-11 q-214 0 -329 -219q-32 -69 -32 -212v-384q0 -33 -47 -41h-1q-35 0 -45 50v842q6 60 45 60z" />
-<glyph unicode="&#x145;" horiz-adv-x="1307" d="M105 1406h15q32 0 62 -64q58 -65 830 -1062q-5 0 -5 6l16 -21h41v1096q9 45 43 45h11q35 0 43 -48v-1283q0 -41 -56 -50q-28 0 -110 122l-832 1062v-1137q0 -35 -49 -43h-1q-37 0 -47 52v1266q6 59 39 59zM695 27q92 -60 92 -148q0 -126 -147 -163l-46 3h-54l-52 -3 q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29q0 41 28 51.5t70 -11.5z" />
-<glyph unicode="&#x146;" horiz-adv-x="1140" d="M554 23q92 -60 92 -148q0 -126 -147 -163l-46 3h-54l-52 -3q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29q0 41 28 51.5t70 -11.5zM80 977q48 -12 48 -37v-136q194 173 372 173q195 0 347 -163q111 -137 111 -287v-465q0 -28 -47 -37h1 q-47 8 -47 45v409q0 292 -255 386q-62 16 -110 16h-11q-214 0 -329 -219q-32 -69 -32 -212v-384q0 -33 -47 -41h-1q-35 0 -45 50v842q6 60 45 60z" />
-<glyph unicode="&#x147;" horiz-adv-x="1321" d="M473 1665h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM92 1406h15q32 0 62 -64q58 -65 830 -1062q-5 0 -5 6l16 -21h41v1096q9 45 43 45h11q35 0 43 -48v-1283 q0 -41 -56 -50q-28 0 -110 122l-832 1062v-1137q0 -35 -49 -43h-1q-37 0 -47 52v1266q6 59 39 59z" />
-<glyph unicode="&#x148;" horiz-adv-x="1114" d="M381 1414h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM85 977q48 -12 48 -37v-136q194 173 372 173q195 0 347 -163q111 -137 111 -287v-465q0 -28 -47 -37h1 q-47 8 -47 45v409q0 292 -255 386q-62 16 -110 16h-11q-214 0 -329 -219q-32 -69 -32 -212v-384q0 -33 -47 -41h-1q-35 0 -45 50v842q6 60 45 60z" />
-<glyph unicode="&#x149;" horiz-adv-x="1427" d="M104 1251h28q61 0 87 -213v-18q0 -117 -133 -227q-21 -12 -25 -12q-6 2 -8 6q60 144 60 241v12q0 69 -48 151v10q10 50 39 50zM336 977q48 -12 48 -37v-136q194 173 372 173q195 0 347 -163q111 -137 111 -287v-465q0 -28 -47 -37h1q-47 8 -47 45v409q0 292 -255 386 q-62 16 -110 16h-11q-214 0 -329 -219q-32 -69 -32 -212v-384q0 -33 -47 -41h-1q-35 0 -45 50v842q6 60 45 60z" />
-<glyph unicode="&#x14a;" horiz-adv-x="1268" d="M588 1408q220 0 397 -173q129 -150 144 -288l7 -47l-3 -116v-207l3 -97q-13 -123 -85 -224q-143 -174 -350 -174q-147 0 -245 83l-5 23v6q9 45 43 45h2l124 -49l80 -8h9q186 0 289 178q41 60 41 228v230q0 341 -291 461q-84 28 -145 28h-22q-251 0 -396 -247 q-48 -88 -48 -264v-728q0 -35 -49 -43h-1q-37 0 -47 52v1268q6 59 39 59h12q46 -9 46 -35v-189q225 228 451 228z" />
-<glyph unicode="&#x14b;" horiz-adv-x="1140" d="M962 52q-4 -197 -210 -277l-79 -14q-49 11 -49 37v22q0 31 59 36q127 0 184 159q0 25 3 44v420q0 292 -255 386q-62 16 -110 16h-11q-214 0 -329 -219q-32 -69 -32 -212v-384q0 -33 -47 -41h-1q-35 0 -45 50v842q6 60 45 60q48 -12 48 -37v-136q194 173 372 173 q195 0 347 -163q111 -137 111 -287v-465q0 -4 -1 -10z" />
-<glyph unicode="&#x14c;" horiz-adv-x="1580" d="M724 1410q350 0 586 -325q106 -184 106 -371q0 -346 -314 -576q-177 -113 -371 -113h-15q-357 0 -583 333q-102 167 -102 363q0 331 292 558q189 131 401 131zM128 710q0 -286 252 -481q158 -107 336 -107h19q280 0 473 248q111 160 111 348q0 323 -295 511 q-146 84 -300 84q-295 0 -489 -256q-107 -154 -107 -347zM315 1679h842q47 -9 47 -45v-10q-9 -47 -42 -47h-847q-38 0 -45 55q13 47 45 47z" />
-<glyph unicode="&#x14d;" horiz-adv-x="1188" d="M528 993q187 0 339 -142q145 -152 145 -342q0 -272 -258 -428q-111 -56 -215 -56h-30q-194 0 -362 184q-103 145 -103 300q0 236 209 396q133 88 275 88zM143 520v-18q0 -219 210 -338q77 -40 164 -40h22q226 0 346 234q28 74 28 144v18q0 183 -166 306q-98 68 -223 68 q-247 0 -361 -257q-20 -64 -20 -117zM108 1300h842q47 -9 47 -45v-10q-9 -47 -42 -47h-847q-38 0 -45 55q13 47 45 47z" />
-<glyph unicode="&#x14e;" horiz-adv-x="1563" d="M532 1811h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM733 1410q350 0 586 -325q106 -184 106 -371q0 -346 -314 -576q-177 -113 -371 -113h-15q-357 0 -583 333 q-102 167 -102 363q0 331 292 558q189 131 401 131zM137 710q0 -286 252 -481q158 -107 336 -107h19q280 0 473 248q111 160 111 348q0 323 -295 511q-146 84 -300 84q-295 0 -489 -256q-107 -154 -107 -347z" />
-<glyph unicode="&#x14f;" horiz-adv-x="1127" d="M316 1411h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM524 993q187 0 339 -142q145 -152 145 -342q0 -272 -258 -428q-111 -56 -215 -56h-30q-194 0 -362 184 q-103 145 -103 300q0 236 209 396q133 88 275 88zM139 520v-18q0 -219 210 -338q77 -40 164 -40h22q226 0 346 234q28 74 28 144v18q0 183 -166 306q-98 68 -223 68q-247 0 -361 -257q-20 -64 -20 -117z" />
-<glyph unicode="&#x150;" horiz-adv-x="1580" d="M542 1818h2q53 -9 53 -47v-20q0 -13 -162 -224q-10 -11 -17 -11h-8q-13 0 -19 22q101 253 118 269q19 11 33 11zM788 1806q57 -11 57 -55q0 -23 -103 -153q-61 -94 -76 -94h-12q-13 0 -19 22q0 9 108 255q25 25 45 25zM724 1410q350 0 586 -325q106 -184 106 -371 q0 -346 -314 -576q-177 -113 -371 -113h-15q-357 0 -583 333q-102 167 -102 363q0 331 292 558q189 131 401 131zM128 710q0 -286 252 -481q158 -107 336 -107h19q280 0 473 248q111 160 111 348q0 323 -295 511q-146 84 -300 84q-295 0 -489 -256q-107 -154 -107 -347z" />
-<glyph unicode="&#x151;" horiz-adv-x="1135" d="M405 1444h2q53 -9 53 -47v-20q0 -13 -162 -224q-10 -11 -17 -11h-8q-13 0 -19 22q101 253 118 269q19 11 33 11zM651 1432q57 -11 57 -55q0 -23 -103 -153q-61 -94 -76 -94h-12q-13 0 -19 22q0 9 108 255q25 25 45 25zM519 993q187 0 339 -142q145 -152 145 -342 q0 -272 -258 -428q-111 -56 -215 -56h-30q-194 0 -362 184q-103 145 -103 300q0 236 209 396q133 88 275 88zM134 520v-18q0 -219 210 -338q77 -40 164 -40h22q226 0 346 234q28 74 28 144v18q0 183 -166 306q-98 68 -223 68q-247 0 -361 -257q-20 -64 -20 -117z" />
-<glyph unicode="&#x152;" horiz-adv-x="2157" d="M154 710q0 -285 207 -480q131 -108 279 -108h16q233 0 392 250q91 159 91 346q0 321 -242 510q-122 85 -250 85q-246 0 -405 -258q-88 -153 -88 -345zM1141 375q-103 -163 -189 -239q-144 -111 -299 -111h-13q-288 0 -472 331q-84 168 -84 365q0 332 239 559 q153 130 324 130q264 0 494 -349v303q7 49 72 49v-2l-9 2h750l15 4q40 0 48 -57q-10 -45 -58 -45h-720v-562h481l54 4q30 0 42 -54q0 -30 -40 -48l-71 4h-466v-536h738q31 0 39 -53q-13 -45 -42 -45h-784q-49 9 -49 47v303z" />
-<glyph unicode="&#x153;" horiz-adv-x="2025" d="M143 525v-18q0 -219 210 -338q77 -40 164 -40h22q226 0 346 234q28 74 28 144v18q0 183 -166 306q-98 68 -223 68q-247 0 -361 -257q-20 -64 -20 -117zM1016 526h757q0 108 -94 236q-130 122 -257 122h-41q-189 0 -310 -184q-43 -74 -55 -174zM965 297 q-86 -136 -211 -211q-111 -56 -215 -56h-30q-194 0 -362 184q-103 145 -103 300q0 236 209 396q133 88 275 88q187 0 339 -142q47 -48 100 -136q82 132 199 205q121 59 226 59q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35 q90 0 200 55h14q43 -9 43 -41v-11q0 -69 -241 -100h-24q-252 0 -427 267z" />
-<glyph unicode="&#x154;" horiz-adv-x="986" d="M526 1834q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121zM74 1410h315q187 0 307 -199q38 -76 38 -159v-15q0 -185 -181 -303l-59 -31q354 -610 354 -616v-19q0 -35 -49 -43h-2q-38 0 -91 116l-319 543h-254v-616 q0 -35 -49 -43h-2q-37 0 -47 53v1272q6 60 39 60zM133 1316v-535h240q198 0 260 213l4 34v32q0 158 -175 239q-50 17 -149 17h-180z" />
-<glyph unicode="&#x155;" horiz-adv-x="928" d="M548 1482q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121zM115 1006q50 -13 50 -39v-139q200 178 378 178q96 0 201 -45q19 -20 19 -39v-2q-8 -48 -46 -48q-103 33 -159 33h-22q-237 0 -347 -245q-24 -66 -24 -148 v-444q0 -35 -49 -43h-2q-36 0 -46 52v866q7 63 47 63z" />
-<glyph unicode="&#x156;" horiz-adv-x="995" d="M79 1410h315q187 0 307 -199q38 -76 38 -159v-15q0 -185 -181 -303l-59 -31q354 -610 354 -616v-19q0 -35 -49 -43h-2q-38 0 -91 116l-319 543h-254v-616q0 -35 -49 -43h-2q-37 0 -47 53v1272q6 60 39 60zM138 1316v-535h240q198 0 260 213l4 34v32q0 158 -175 239 q-50 17 -149 17h-180zM506 59q92 -60 92 -148q0 -126 -147 -163l-46 3h-54l-52 -3q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29q0 41 28 51.5t70 -11.5z" />
-<glyph unicode="&#x157;" horiz-adv-x="854" d="M67 1006q50 -13 50 -39v-139q200 178 378 178q96 0 201 -45q19 -20 19 -39v-2q-8 -48 -46 -48q-103 33 -159 33h-22q-237 0 -347 -245q-24 -66 -24 -148v-444q0 -35 -49 -43h-2q-36 0 -46 52v866q7 63 47 63zM343 54q92 -60 92 -148q0 -126 -147 -163l-46 3h-54l-52 -3 q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29q0 41 28 51.5t70 -11.5z" />
-<glyph unicode="&#x158;" horiz-adv-x="1003" d="M191 1806h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM74 1410h315q187 0 307 -199q38 -76 38 -159v-15q0 -185 -181 -303l-59 -31q354 -610 354 -616v-19q0 -35 -49 -43 h-2q-38 0 -91 116l-319 543h-254v-616q0 -35 -49 -43h-2q-37 0 -47 53v1272q6 60 39 60zM133 1316v-535h240q198 0 260 213l4 34v32q0 158 -175 239q-50 17 -149 17h-180z" />
-<glyph unicode="&#x159;" horiz-adv-x="885" d="M236 1406h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM85 1006q50 -13 50 -39v-139q200 178 378 178q96 0 201 -45q19 -20 19 -39v-2q-8 -48 -46 -48q-103 33 -159 33h-22 q-237 0 -347 -245q-24 -66 -24 -148v-444q0 -35 -49 -43h-2q-36 0 -46 52v866q7 63 47 63z" />
-<glyph unicode="&#x15a;" horiz-adv-x="929" d="M456 1412q174 0 287 -154l2 -8v-20q0 -28 -50 -36q-16 0 -84 75q-75 48 -143 48h-23q-141 0 -213 -148q-18 -37 -18 -76v-31q0 -162 196 -235q122 0 260 -112q132 -134 132 -295q0 -197 -169 -324q-103 -71 -230 -71q-204 0 -336 173l-5 21q8 46 47 46q28 0 86 -73 q104 -72 189 -72h34q167 0 269 188q16 62 16 93v38q0 166 -187 268l-195 54q-203 116 -203 305v27q0 185 200 290q74 29 138 29zM561 1838q47 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-9q-50 10 -50 47v16q0 23 133 142q107 121 138 121z" />
-<glyph unicode="&#x15b;" horiz-adv-x="980" d="M557 1419q46 0 55 -65q0 -27 -177 -185q-62 -76 -90 -76h-10q-49 10 -49 47v16q0 23 133 142q106 121 138 121zM460 992q243 0 380 -216l2 -22v-3q0 -37 -51 -45q-33 0 -78 76q-113 109 -253 109q-185 0 -294 -179l-4 -26q0 -74 132 -86q423 -102 459 -115 q93 -62 93 -156v-3q0 -139 -212 -260q-91 -41 -196 -41q-212 0 -361 200q-10 16 -10 27v22q0 32 58 38q21 0 80 -85q108 -100 248 -100q169 0 282 162l9 29v8q0 70 -87 80q-489 109 -514 131q-83 63 -83 151q0 126 191 248q105 56 209 56z" />
-<glyph unicode="&#x15c;" horiz-adv-x="885" d="M434 1412q174 0 287 -154l2 -8v-20q0 -28 -50 -36q-16 0 -84 75q-75 48 -143 48h-23q-141 0 -213 -148q-18 -37 -18 -76v-31q0 -162 196 -235q122 0 260 -112q132 -134 132 -295q0 -197 -169 -324q-103 -71 -230 -71q-204 0 -336 173l-5 21q8 46 47 46q28 0 86 -73 q104 -72 189 -72h34q167 0 269 188q16 62 16 93v38q0 166 -187 268l-195 54q-203 116 -203 305v27q0 185 200 290q74 29 138 29zM409 1780h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-31 0 -114 120h-31q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153 q32 50 60 50z" />
-<glyph unicode="&#x15d;" horiz-adv-x="969" d="M449 1366h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM460 992q243 0 380 -216l2 -22v-3q0 -37 -51 -45q-33 0 -78 76q-113 109 -253 109q-185 0 -294 -179l-4 -26 q0 -74 132 -86q423 -102 459 -115q93 -62 93 -156v-3q0 -139 -212 -260q-91 -41 -196 -41q-212 0 -361 200q-10 16 -10 27v22q0 32 58 38q21 0 80 -85q108 -100 248 -100q169 0 282 162l9 29v8q0 70 -87 80q-489 109 -514 131q-83 63 -83 151q0 126 191 248q105 56 209 56z " />
-<glyph unicode="&#x15e;" horiz-adv-x="903" d="M358 25q-196 20 -313 173l-5 21q8 46 47 46q28 0 86 -73q104 -72 189 -72h34q167 0 269 188q16 62 16 93v38q0 166 -187 268l-195 54q-203 116 -203 305v27q0 185 200 290q74 29 138 29q174 0 287 -154l2 -8v-20q0 -28 -50 -36q-16 0 -84 75q-75 48 -143 48h-23 q-141 0 -213 -148q-18 -37 -18 -76v-31q0 -162 196 -235q122 0 260 -112q132 -134 132 -295q0 -197 -169 -324q-69 -47 -167 -67v-71q104 -69 104 -157q0 -126 -147 -163l-46 3h-53l-52 -3q-38 13 -38 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29v116z " />
-<glyph unicode="&#x15f;" horiz-adv-x="978" d="M503 28v-79q104 -69 104 -157q0 -126 -147 -163l-46 3h-54l-52 -3q-37 13 -37 34v12q8 40 38 40h121q91 0 91 77v3q0 61 -79 76q-25 12 -25 29v125q-204 23 -336 200q-10 16 -10 27v22q0 32 58 38q21 0 80 -85q108 -100 248 -100q169 0 282 162l9 29v8q0 70 -87 80 q-489 109 -514 131q-83 63 -83 151q0 126 191 248q105 56 209 56q243 0 380 -216l2 -22v-3q0 -37 -51 -45q-33 0 -78 76q-113 109 -253 109q-185 0 -294 -179l-4 -26q0 -74 132 -86q423 -102 459 -115q93 -62 93 -156v-3q0 -139 -212 -260q-54 -24 -135 -38z" />
-<glyph unicode="&#x160;" horiz-adv-x="924" d="M429 1412q174 0 287 -154l2 -8v-20q0 -28 -50 -36q-16 0 -84 75q-75 48 -143 48h-23q-141 0 -213 -148q-18 -37 -18 -76v-31q0 -162 196 -235q122 0 260 -112q132 -134 132 -295q0 -197 -169 -324q-103 -71 -230 -71q-204 0 -336 173l-5 21q8 46 47 46q28 0 86 -73 q104 -72 189 -72h34q167 0 269 188q16 62 16 93v38q0 166 -187 268l-195 54q-203 116 -203 305v27q0 185 200 290q74 29 138 29zM283 1797h12q32 0 115 -120h31q83 120 114 120h10q49 -10 49 -47v-12q0 -25 -90 -124q-54 -79 -85 -79h-28q-33 0 -112 115q-63 62 -63 88v9 q11 50 47 50z" />
-<glyph unicode="&#x161;" horiz-adv-x="977" d="M315 1419h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM451 992q243 0 380 -216l2 -22v-3q0 -37 -51 -45q-33 0 -78 76q-113 109 -253 109q-185 0 -294 -179l-4 -26 q0 -74 132 -86q423 -102 459 -115q93 -62 93 -156v-3q0 -139 -212 -260q-91 -41 -196 -41q-212 0 -361 200q-10 16 -10 27v22q0 32 58 38q21 0 80 -85q108 -100 248 -100q169 0 282 162l9 29v8q0 70 -87 80q-489 109 -514 131q-83 63 -83 151q0 126 191 248q105 56 209 56z " />
-<glyph unicode="&#x162;" horiz-adv-x="1219" d="M83 1411h931q45 -9 45 -43v-15q0 -33 -59 -39h-400v-1246q0 -35 -49 -43h-1q-37 0 -47 53v1236h-406q-53 11 -53 47q11 50 39 50zM508 -98h28q63 0 87 -121v-9q0 -63 -129 -127q-23 -8 -31 -8q-8 2 -6 0v-11q60 87 60 151v7q0 48 -48 97v-2q8 23 39 23z" />
-<glyph unicode="&#x163;" horiz-adv-x="730" d="M367 -72h28q63 0 87 -121v-9q0 -63 -129 -127q-23 -8 -31 -8q-8 2 -6 0v-11q60 87 60 151v7q0 48 -48 97v-2q8 23 39 23zM267 1365h11q44 -9 44 -34v-355h178l33 4q29 0 42 -52q0 -30 -41 -45l-50 4h-162v-564q0 -159 112 -198l88 -7h42q28 0 37 -47v1q-8 -47 -45 -47 h-77q-159 0 -237 175q-13 42 -13 101v586h-99l-55 -4q-40 15 -40 46q8 47 66 47v1l11 -1h117v332q6 57 38 57z" />
-<glyph unicode="&#x164;" horiz-adv-x="1224" d="M421 1811h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM92 1411h931q45 -9 45 -43v-15q0 -33 -59 -39h-400v-1246q0 -35 -49 -43h-1q-37 0 -47 53v1236h-406q-53 11 -53 47 q11 50 39 50z" />
-<glyph unicode="&#x165;" horiz-adv-x="757" d="M170 1775h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM294 1365h11q44 -9 44 -34v-355h178l33 4q29 0 42 -52q0 -30 -41 -45l-50 4h-162v-564q0 -159 112 -198l88 -7h42 q28 0 37 -47v1q-8 -47 -45 -47h-77q-159 0 -237 175q-13 42 -13 101v586h-99l-55 -4q-40 15 -40 46q8 47 66 47v1l11 -1h117v332q6 57 38 57z" />
-<glyph unicode="&#x166;" horiz-adv-x="1197" d="M507 666h-311l-59 -4q-47 17 -47 53q9 53 72 53v1l14 -1h331v546h-406q-53 11 -53 47q11 50 39 50h931q45 -9 45 -43v-15q0 -33 -59 -39h-400v-546h294l36 4q38 0 50 -58q0 -33 -44 -52l-62 4h-274v-598q0 -35 -49 -43h-1q-37 0 -47 53v588z" />
-<glyph unicode="&#x167;" horiz-adv-x="748" d="M242 593v294h-99l-55 -4q-40 15 -40 46q8 47 66 47v1l11 -1h117v332q6 57 38 57h11q44 -9 44 -34v-355h178l33 4q29 0 42 -52q0 -30 -41 -45l-50 4h-162v-294h174l34 4q31 0 45 -58q0 -35 -43 -52l-51 4h-159v-168q0 -159 112 -198l88 -7h42q28 0 37 -47v1 q-8 -47 -45 -47h-77q-159 0 -237 175q-13 42 -13 101v190h-92l-55 -4q-43 16 -43 53q8 53 68 53v1l11 -1h111z" />
-<glyph unicode="&#x168;" horiz-adv-x="1219" d="M105 1408h12q46 -9 46 -35v-806q0 -274 159 -369q98 -76 222 -76q237 0 356 243q25 76 25 157v838q8 48 43 48h9q45 -9 45 -43v-881q0 -213 -206 -373q-129 -86 -261 -86h-26q-223 0 -388 220q-75 117 -75 292v812q6 59 39 59zM436 1690h19q62 0 152 -61l36 -9h25l71 21 q48 -9 48 -48q0 -52 -117 -67h-24q-61 0 -152 61l-36 9h-25l-70 -18h-2q-43 9 -43 41v11q0 35 63 50q27 10 55 10z" />
-<glyph unicode="&#x169;" horiz-adv-x="1131" d="M396 1289h19q62 0 152 -61l36 -9h25l71 21q48 -9 48 -48q0 -52 -117 -67h-24q-61 0 -152 61l-36 9h-25l-70 -18h-2q-43 9 -43 41v11q0 35 63 50q27 10 55 10zM89 977q48 -12 48 -38v-391q0 -265 153 -357q96 -73 215 -73q230 0 345 235q24 76 24 151v422q10 51 45 51 q47 -12 47 -45v-870q0 -28 -47 -37h1q-46 8 -46 44v95h-39q-153 -139 -319 -139h-25q-215 0 -374 212q-73 113 -73 282v397q6 61 45 61z" />
-<glyph unicode="&#x16a;" horiz-adv-x="1135" d="M74 1408h12q46 -9 46 -35v-806q0 -274 159 -369q98 -76 222 -76q237 0 356 243q25 76 25 157v838q8 48 43 48h9q45 -9 45 -43v-881q0 -213 -206 -373q-129 -86 -261 -86h-26q-223 0 -388 220q-75 117 -75 292v812q6 59 39 59zM208 1684l6 -1h610l30 4q27 0 37 -57 q0 -35 -34 -53l-51 4h-574l-49 -4q-36 16 -36 53q8 53 61 53v1z" />
-<glyph unicode="&#x16b;" horiz-adv-x="1135" d="M80 977q48 -12 48 -38v-391q0 -265 153 -357q96 -73 215 -73q230 0 345 235q24 76 24 151v422q10 51 45 51q47 -12 47 -45v-870q0 -28 -47 -37h1q-46 8 -46 44v95h-39q-153 -139 -319 -139h-25q-215 0 -374 212q-73 113 -73 282v397q6 61 45 61zM227 1274l519 1 q57 -10 57 -46v-10q-6 -47 -51 -47h-538q-41 0 -46 56q9 46 59 46z" />
-<glyph unicode="&#x16c;" horiz-adv-x="1149" d="M316 1775h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM74 1408h12q46 -9 46 -35v-806q0 -274 159 -369q98 -76 222 -76q237 0 356 243q25 76 25 157v838 q8 48 43 48h9q45 -9 45 -43v-881q0 -213 -206 -373q-129 -86 -261 -86h-26q-223 0 -388 220q-75 117 -75 292v812q6 59 39 59z" />
-<glyph unicode="&#x16d;" horiz-adv-x="1171" d="M303 1371h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50zM107 977q48 -12 48 -38v-391q0 -265 153 -357q96 -73 215 -73q230 0 345 235q24 76 24 151v422 q10 51 45 51q47 -12 47 -45v-870q0 -28 -47 -37h1q-46 8 -46 44v95h-39q-153 -139 -319 -139h-25q-215 0 -374 212q-73 113 -73 282v397q6 61 45 61z" />
-<glyph unicode="&#x16e;" horiz-adv-x="1127" d="M70 1408h12q46 -9 46 -35v-806q0 -274 159 -369q98 -76 222 -76q237 0 356 243q25 76 25 157v838q8 48 43 48h9q45 -9 45 -43v-881q0 -213 -206 -373q-129 -86 -261 -86h-26q-223 0 -388 220q-75 117 -75 292v812q6 59 39 59zM518 1807h14q103 0 149 -128l4 -33v-10 q0 -101 -122 -150l-40 -7q-96 0 -150 100q-16 36 -16 68q0 110 129 156zM424 1643q17 -96 99 -96q95 16 95 93v13q-15 87 -89 87h-12q-78 0 -93 -97z" />
-<glyph unicode="&#x16f;" horiz-adv-x="1180" d="M107 977q48 -12 48 -38v-391q0 -265 153 -357q96 -73 215 -73q230 0 345 235q24 76 24 151v422q10 51 45 51q47 -12 47 -45v-870q0 -28 -47 -37h1q-46 8 -46 44v95h-39q-153 -139 -319 -139h-25q-215 0 -374 212q-73 113 -73 282v397q6 61 45 61zM523 1380h14 q103 0 149 -128l4 -33v-10q0 -101 -122 -150l-40 -7q-96 0 -150 100q-16 36 -16 68q0 110 129 156zM429 1216q17 -96 99 -96q95 16 95 93v13q-15 87 -89 87h-12q-78 0 -93 -97z" />
-<glyph unicode="&#x170;" horiz-adv-x="1175" d="M530 1809h2q53 -9 53 -47v-20q0 -13 -162 -224q-10 -11 -17 -11h-8q-13 0 -19 22q101 253 118 269q19 11 33 11zM776 1797q57 -11 57 -55q0 -23 -103 -153q-61 -94 -76 -94h-12q-13 0 -19 22q0 9 108 255q25 25 45 25zM96 1408h12q46 -9 46 -35v-806q0 -274 159 -369 q98 -76 222 -76q237 0 356 243q25 76 25 157v838q8 48 43 48h9q45 -9 45 -43v-881q0 -213 -206 -373q-129 -86 -261 -86h-26q-223 0 -388 220q-75 117 -75 292v812q6 59 39 59z" />
-<glyph unicode="&#x171;" horiz-adv-x="1144" d="M490 1378h2q53 -9 53 -47v-20q0 -13 -162 -224q-10 -11 -17 -11h-8q-13 0 -19 22q101 253 118 269q19 11 33 11zM736 1366q57 -11 57 -55q0 -23 -103 -153q-61 -94 -76 -94h-12q-13 0 -19 22q0 9 108 255q25 25 45 25zM89 977q48 -12 48 -38v-391q0 -265 153 -357 q96 -73 215 -73q230 0 345 235q24 76 24 151v422q10 51 45 51q47 -12 47 -45v-870q0 -28 -47 -37h1q-46 8 -46 44v95h-39q-153 -139 -319 -139h-25q-215 0 -374 212q-73 113 -73 282v397q6 61 45 61z" />
-<glyph unicode="&#x172;" horiz-adv-x="1202" d="M494 25q-210 26 -357 220q-75 117 -75 292v812q6 59 39 59h12q46 -9 46 -35v-806q0 -274 159 -369q98 -76 222 -76q237 0 356 243q25 76 25 157v838q8 48 43 48h9q45 -9 45 -43v-881q0 -213 -206 -373q-101 -67 -226 -85v-117q0 -36 -66 -46q-40 -29 -40 -70 q0 -78 92 -78h105l12 3q45 -10 45 -41v-7q0 -29 -35 -42l-69 4h-38l-56 -4q-58 0 -122 81q-21 40 -21 70v28q0 81 106 140v20z" />
-<glyph unicode="&#x173;" horiz-adv-x="1211" d="M975 65q3 -8 3 -11v-101q0 -36 -66 -46q-40 -29 -40 -70q0 -78 92 -78h105l12 3q45 -10 45 -41v-7q0 -29 -35 -42l-69 4h-38l-56 -4q-58 0 -122 81q-21 40 -21 70v28q0 81 106 140v20l-2 36q-6 11 -6 22v95h-39q-153 -139 -319 -139h-25q-215 0 -374 212q-73 113 -73 282 v397q6 61 45 61q48 -12 48 -38v-391q0 -265 153 -357q96 -73 215 -73q230 0 345 235q24 76 24 151v422q10 51 45 51q47 -12 47 -45v-867z" />
-<glyph unicode="&#x174;" horiz-adv-x="1778" d="M835 1815h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM86 1411h16q43 0 59 -95l286 -992h45q296 1046 312 1070q16 17 33 17h11q46 0 63 -117q28 -76 282 -974h42 l311 1070q16 21 30 21h13q45 -9 45 -35v-15l-380 -1318q-19 -18 -38 -18h-4q-49 0 -66 120q-247 838 -282 979h-41l-311 -1078q-17 -21 -39 -21h-15q-40 0 -59 124q-325 1107 -351 1215q10 47 38 47z" />
-<glyph unicode="&#x175;" horiz-adv-x="1422" d="M641 1344h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM92 984q47 0 71 -129l187 -574h40q211 672 220 685q19 15 40 18q43 0 62 -103l194 -600h40q204 647 219 681 q21 22 36 22q51 -10 51 -45l-288 -896q-19 -18 -37 -18h-3q-47 0 -72 125q-176 534 -176 571h-50l-218 -676q-15 -20 -37 -20h-3q-34 0 -50 49l-274 862q10 48 48 48z" />
-<glyph unicode="&#x176;" horiz-adv-x="1167" d="M79 1408h16q32 0 56 -59l354 -529h31q377 569 388 578q14 10 20 10h23q26 0 39 -50q0 -21 -125 -192l-311 -464v-618q-7 -59 -39 -59h-16q-31 0 -43 40v617q0 22 -164 265l-266 400l-2 13q11 48 39 48zM511 1767h28q34 0 116 -119q59 -58 59 -84v-9q-11 -50 -47 -50h-12 q-32 0 -115 120h-31q-83 -120 -114 -120h-10q-49 10 -49 47v12q0 28 114 153q32 50 61 50z" />
-<glyph unicode="&#x177;" horiz-adv-x="964" d="M450 1370h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50zM781 987q46 -9 46 -41v-3q-2 -20 -343 -832q-160 -397 -176 -417q-11 -9 -28 -13q-44 9 -44 34v17q0 8 157 386 v13l-332 810v-5q9 47 45 47q40 0 77 -122q227 -537 238 -582h40q279 681 290 694q17 14 30 14z" />
-<glyph unicode="&#x178;" horiz-adv-x="1149" d="M79 1408h16q32 0 56 -59l354 -529h31q377 569 388 578q14 10 20 10h23q26 0 39 -50q0 -21 -125 -192l-311 -464v-618q-7 -59 -39 -59h-16q-31 0 -43 40v617q0 22 -164 265l-266 400l-2 13q11 48 39 48zM370 1662h12q46 -9 46 -35v-19q0 -34 -47 -43q-50 10 -50 48 q11 49 39 49zM662 1662h6q46 -10 46 -39v-11q0 -39 -50 -47q-47 10 -47 47v11q0 29 45 39z" />
-<glyph unicode="&#x179;" horiz-adv-x="1272" d="M673 1782q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM70 1412h1021q34 0 43 -49v-1q0 -20 -77 -110l-874 -1129h902q49 -7 49 -47v-2q-9 -49 -47 -49h-1009q-38 0 -47 57q0 17 177 237l771 996h-895q-53 11 -53 47 q11 50 39 50z" />
-<glyph unicode="&#x17a;" horiz-adv-x="973" d="M540 1364q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM110 984l11 -1h641l31 4q43 -14 43 -38v-22q0 -13 -79 -99l-565 -709h601q43 -9 43 -41v-12q0 -33 -47 -41h-700q-37 0 -45 55q0 18 145 185l499 628h-548 l-55 -4q-41 15 -41 47q8 47 66 47v1z" />
-<glyph unicode="&#x17b;" horiz-adv-x="1325" d="M615 1772q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4zM83 1412h1021q34 0 43 -49v-1q0 -20 -77 -110l-874 -1129h902q49 -7 49 -47v-2q-9 -49 -47 -49h-1009q-38 0 -47 57q0 17 177 237l771 996h-895q-53 11 -53 47q11 50 39 50z " />
-<glyph unicode="&#x17c;" horiz-adv-x="1004" d="M457 1332q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4zM106 984l11 -1h641l31 4q43 -14 43 -38v-22q0 -13 -79 -99l-565 -709h601q43 -9 43 -41v-12q0 -33 -47 -41h-700q-37 0 -45 55q0 18 145 185l499 628h-548l-55 -4 q-41 15 -41 47q8 47 66 47v1z" />
-<glyph unicode="&#x17d;" horiz-adv-x="1294" d="M469 1811h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM87 1412h1021q34 0 43 -49v-1q0 -20 -77 -110l-874 -1129h902q49 -7 49 -47v-2q-9 -49 -47 -49h-1009q-38 0 -47 57 q0 17 177 237l771 996h-895q-53 11 -53 47q11 50 39 50z" />
-<glyph unicode="&#x17e;" horiz-adv-x="978" d="M324 1433h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50zM106 984l11 -1h641l31 4q43 -14 43 -38v-22q0 -13 -79 -99l-565 -709h601q43 -9 43 -41v-12q0 -33 -47 -41h-700 q-37 0 -45 55q0 18 145 185l499 628h-548l-55 -4q-41 15 -41 47q8 47 66 47v1z" />
-<glyph unicode="&#x17f;" horiz-adv-x="616" d="M362 1412h89q30 0 39 -57q0 -29 -54 -41h-54q-157 0 -207 -173l-3 -83v-53v-145v-751l3 -42q0 -30 -53 -42q-32 0 -48 42l4 42v751l-4 145v68q0 237 205 324z" />
-<glyph unicode="&#x192;" horiz-adv-x="973" d="M681 1399h94q34 0 43 -61q0 -32 -58 -45h-57q-165 0 -217 -181l-4 -87v-82h197l64 4q31 0 43 -54v-9q0 -30 -50 -43h-254v-786l4 -94q-14 -97 -74 -177q-110 -115 -237 -115h-84q-38 0 -47 51q8 55 51 55h52q152 0 215 135q18 46 18 146v785h-233q-35 0 -43 61 q0 23 44 45l74 -4h154v97q0 252 218 344z" />
-<glyph unicode="&#x1fa;" horiz-adv-x="1266" d="M495 1467q15 -86 89 -86q85 14 85 83v12q-13 78 -80 78h-10q-72 0 -84 -87zM561 1121l-179 -460h387v33l-170 427h-38zM534 1607v-1h1zM534 1607q-36 28 -41 54v3q0 21 97 129q27 38 43 38q44 -10 44 -38v-6q0 -18 -68 -94q-19 -28 -75 -86zM535 1606q143 -2 182 -109 l3 -28v-8q0 -75 -107 -129q31 -52 43 -103q457 -1134 460 -1156v-8q0 -33 -49 -40h-2q-46 0 -70 105l-177 439h-476l-212 -531q-17 -13 -32 -13h-5q-48 8 -49 43l126 327q319 791 371 939q-58 30 -84 79q-13 30 -13 57q0 72 98 131q-4 3 -7 5z" />
-<glyph unicode="&#x1fb;" horiz-adv-x="1171" d="M610 1773q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM533 1422q89 0 142 -96q15 -33 15 -66q0 -105 -124 -150l-32 -4h-13q-100 0 -144 124l-4 31v10q0 106 131 148zM437 1268v-19q23 -79 84 -79h14q78 0 91 94 q-16 95 -96 95q-93 -16 -93 -91zM517 979q271 0 429 -265q48 -107 48 -223v-425q0 -33 -47 -41h-1q-31 0 -45 35v-2l4 91v63q-197 -187 -373 -187h-30q-242 0 -403 244q-59 117 -59 237q0 266 262 421q111 52 215 52zM133 509v-11q0 -233 235 -352q74 -28 134 -28h30 q196 0 322 196q47 92 47 177v15q0 225 -223 344q-78 36 -161 36h-4q-237 0 -356 -247q-24 -76 -24 -130z" />
-<glyph unicode="&#x1fc;" horiz-adv-x="1615" d="M1001 1805q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM812 1410h595q26 0 38 -48q-9 -49 -50 -49h-525v-618h412q47 -10 47 -36v-19q0 -35 -49 -43h-410v-474h529q37 0 47 -53q0 -34 -54 -45h-572q-37 0 -47 53v519 h-314q-29 -35 -176 -309l-142 -249q-16 -14 -33 -14h-4q-38 0 -47 57q0 13 239 432l491 882q17 14 25 14zM508 695h265v473z" />
-<glyph unicode="&#x1fd;" horiz-adv-x="2042" d="M1054 1338q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM519 979q250 0 418 -245h31q93 159 270 220q80 21 143 21q265 0 420 -257q51 -107 51 -200v-45q-8 -46 -44 -46h-792v-33q41 -133 150 -207q102 -66 211 -66 q94 0 205 56l10 2q49 -12 49 -48q0 -71 -219 -102l-50 -4q-181 0 -378 182v-138q0 -39 -52 -44h-3q-21 0 -37 37l4 83v70q-196 -186 -372 -186h-29q-242 0 -402 243q-59 116 -59 235q0 266 261 420q111 52 214 52zM136 511v-11q0 -232 234 -351q76 -28 135 -28h29 q195 0 321 195q47 92 47 177v14q0 225 -222 344q-78 36 -161 36h-3q-237 0 -356 -246q-24 -77 -24 -130zM1005 519h748v29q0 106 -125 238q-120 93 -251 93q-200 0 -324 -187q-48 -89 -48 -173z" />
-<glyph unicode="&#x1fe;" horiz-adv-x="1655" d="M848 1800q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM750 1401q258 0 493 -207q159 162 179 162h5q49 -12 49 -46v-7q0 -30 -97 -105l-75 -76q134 -205 134 -413q0 -343 -311 -572q-177 -112 -369 -112h-15 q-224 0 -428 154h-21q-154 -150 -166 -150l-19 -4h-1q-38 0 -46 56q0 22 120 122q4 10 56 47q-176 224 -176 467q0 328 290 554q189 130 398 130zM158 706q0 -204 151 -385l849 798v27q-195 159 -408 159q-293 0 -485 -254q-107 -154 -107 -345zM372 252q188 -131 371 -131 h18q279 0 471 247q110 158 110 345q0 159 -96 329h-29z" />
-<glyph unicode="&#x1ff;" horiz-adv-x="1188" d="M622 1387q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM936 987h4q36 0 44 -54q0 -16 -111 -123q122 -149 122 -311q0 -267 -253 -419q-108 -55 -210 -55h-29q-129 0 -289 111q-88 -107 -115 -107h-14q-29 0 -37 53 q0 17 106 119q-106 146 -106 298q0 230 205 387q130 86 269 86q138 0 288 -99q93 114 126 114zM144 509v-18q0 -96 60 -207h30l504 521q-102 71 -220 71q-243 0 -354 -252q-20 -63 -20 -115zM807 744l-526 -545q127 -78 230 -78h21q222 0 340 229q27 74 27 141v18 q0 117 -92 235z" />
-<glyph unicode="&#x2c6;" horiz-adv-x="1024" d="M488 1406h28q35 0 117 -119q58 -58 58 -84v-9q-10 -50 -47 -50h-12q-32 0 -115 120h-30q-83 -120 -115 -120h-9q-50 10 -50 47v12q0 28 115 153q32 50 60 50z" />
-<glyph unicode="&#x2c7;" horiz-adv-x="1024" d="M333 1405h12q32 0 115 -120h30q83 120 115 120h9q50 -10 50 -47v-12q0 -25 -91 -124q-53 -79 -84 -79h-28q-34 0 -113 115q-62 62 -62 88v9q10 50 47 50z" />
-<glyph unicode="&#x2c9;" horiz-adv-x="1059" d="M309 1294l14 -1h402l36 4q35 0 50 -58q0 -35 -47 -52l-55 4h-366l-59 -4q-47 17 -47 53q9 53 72 53v1z" />
-<glyph unicode="&#x2d8;" horiz-adv-x="1024" d="M276 1340h12q35 0 62 -72q63 -72 142 -72q119 0 169 123q20 21 39 21h6q53 -9 53 -51v-4q0 -69 -143 -170q-68 -25 -120 -25h-8q-176 0 -259 184v16q10 50 47 50z" />
-<glyph unicode="&#x2d9;" horiz-adv-x="1024" d="M514 1337q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4z" />
-<glyph unicode="&#x2da;" horiz-adv-x="1024" d="M493 1422q89 0 142 -96q15 -33 15 -66q0 -105 -124 -150l-32 -4h-13q-100 0 -144 124l-4 31v10q0 106 131 148zM397 1268v-19q23 -79 84 -79h14q78 0 91 94q-16 95 -96 95q-93 -16 -93 -91z" />
-<glyph unicode="&#x2db;" horiz-adv-x="1024" d="M475 22h7q33 0 42 -47v-101q0 -36 -66 -46q-40 -29 -40 -70q0 -78 92 -78h105l12 3q45 -10 45 -41v-7q0 -29 -35 -42l-69 4h-38l-56 -4q-58 0 -122 81q-21 40 -21 70v28q0 81 106 140v20l-4 52q14 38 42 38z" />
-<glyph unicode="&#x2dc;" horiz-adv-x="1024" d="M429 1670q70 0 178 -70l44 -5l78 23h1q49 -8 49 -47v-4q0 -49 -102 -65l-36 -4q-70 0 -171 71l-41 5l-82 -22q-49 9 -49 45v8q0 50 118 62z" />
-<glyph unicode="&#x2dd;" horiz-adv-x="1024" d="M415 1404h2q53 -9 53 -47v-20q0 -13 -162 -224q-10 -11 -17 -11h-8q-13 0 -19 22q101 253 118 269q19 11 33 11zM661 1392q57 -11 57 -55q0 -23 -103 -153q-61 -94 -76 -94h-12q-13 0 -19 22q0 9 108 255q25 25 45 25z" />
-<glyph unicode="&#x384;" horiz-adv-x="392" d="M253 1400q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43z" />
-<glyph unicode="&#x385;" horiz-adv-x="797" d="M446 1365q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM154 1284q58 -14 58 -53q-11 -57 -53 -57q-57 11 -57 52q14 58 52 58zM606 1284q58 -14 58 -53q-11 -57 -53 -57q-57 11 -57 52q14 58 52 58z" />
-<glyph unicode="&#x386;" horiz-adv-x="1254" d="M341 1496q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM566 1403q49 0 78 -121q454 -1181 457 -1205v-9q0 -35 -48 -43h-2q-46 0 -70 110l-176 457h-474l-210 -553q-17 -14 -32 -14h-6q-48 9 -48 46l126 341 q336 874 363 965q23 26 42 26zM549 1167l-177 -478h384v34l-169 444h-38z" />
-<glyph unicode="&#x387;" horiz-adv-x="405" d="M179 977q70 0 91 -85v-18q0 -48 -68 -78q-7 -4 -23 -4h-3q-75 0 -91 96q0 57 71 85q8 4 23 4z" />
-<glyph unicode="&#x388;" horiz-adv-x="1347" d="M393 1405l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286q7 49 72 49v-2zM191 1435q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4 q-27 0 -37 48v4q0 24 108 145q31 43 51 43z" />
-<glyph unicode="&#x389;" horiz-adv-x="1466" d="M200 1400q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM365 1412h12q46 -9 46 -35v-623h762v610q8 48 43 48h9q45 -9 45 -43v-1301q0 -29 -50 -39h1q-48 9 -48 47v585h-762v-589q0 -35 -48 -43h-2q-37 0 -47 53v1271 q6 59 39 59z" />
-<glyph unicode="&#x38a;" horiz-adv-x="748" d="M182 1427q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM369 1422l15 -2h146l13 2q51 -10 51 -48q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-178q-49 9 -49 47v1q10 51 40 51h48v1197h-41 q-41 0 -47 56v3q0 28 49 42z" />
-<glyph unicode="&#x38c;" horiz-adv-x="1734" d="M191 1423q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM887 1410q350 0 586 -325q106 -184 106 -371q0 -346 -314 -576q-177 -113 -371 -113h-15q-357 0 -583 333q-102 167 -102 363q0 331 292 558q189 131 401 131z M291 710q0 -286 252 -481q158 -107 336 -107h19q280 0 473 248q111 160 111 348q0 323 -295 511q-146 84 -300 84q-295 0 -489 -256q-107 -154 -107 -347z" />
-<glyph unicode="&#x38e;" horiz-adv-x="1457" d="M209 1418q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM414 1408h16q32 0 57 -59l354 -529h30q377 569 389 578q13 10 19 10h23q26 0 39 -50q0 -21 -124 -192l-312 -464v-618q-6 -59 -39 -59h-16q-31 0 -43 40v617 q0 22 -163 265l-266 400l-3 13q11 48 39 48z" />
-<glyph unicode="&#x38f;" horiz-adv-x="1646" d="M756 1412q354 0 592 -328q107 -192 107 -360q0 -328 -247 -543h-20v-54h187q50 -10 50 -39v-13q-10 -46 -44 -46h-492q-38 0 -46 53q12 45 43 45q115 0 307 164q167 196 167 425q0 284 -254 489q-170 108 -335 108h-30q-285 0 -481 -259q-108 -166 -108 -338 q0 -345 317 -535q55 -34 180 -64q29 -12 29 -44q-14 -48 -48 -48h-482q-53 11 -53 48q12 51 48 51h185v40q-99 75 -168 181q-103 180 -103 379q0 324 299 559q192 129 400 129zM176 1414q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145 q31 43 51 43z" />
-<glyph unicode="&#x390;" horiz-adv-x="740" d="M389 1752q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM97 1671q58 -14 58 -53q-11 -57 -53 -57q-57 11 -57 52q14 58 52 58zM549 1671q58 -14 58 -53q-11 -57 -53 -57q-57 11 -57 52q14 58 52 58zM246 1422l15 -2h146 l13 2q51 -10 51 -48q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-178q-49 9 -49 47v1q10 51 40 51h48v1197h-41q-41 0 -47 56v3q0 28 49 42z" />
-<glyph unicode="&#x391;" horiz-adv-x="1246" d="M566 1403q49 0 78 -121q454 -1181 457 -1205v-9q0 -35 -48 -43h-2q-46 0 -70 110l-176 457h-474l-210 -553q-17 -14 -32 -14h-6q-48 9 -48 46l126 341q336 874 363 965q23 26 42 26zM549 1167l-177 -478h384v34l-169 444h-38z" />
-<glyph unicode="&#x392;" horiz-adv-x="991" d="M125 1402l-9 2h234l15 3q158 0 272 -152q56 -83 56 -181v-11q0 -120 -116 -252q259 -143 259 -385q0 -243 -253 -373q-80 -28 -144 -28h-337q-49 9 -49 47v1283q7 49 72 49v-2zM150 1307v-473h164q202 0 261 148q17 42 17 85v11q0 164 -191 225l-82 4h-169zM150 737v-615 h221q230 0 311 135q53 75 53 169v7q0 221 -242 297l-110 7h-233z" />
-<glyph unicode="&#x393;" horiz-adv-x="1030" d="M96 1408h727q46 -9 46 -35v-19q0 -35 -49 -43h-666v-1243q0 -35 -48 -43h-2q-37 0 -47 53v1271q6 59 39 59z" />
-<glyph unicode="&#x394;" horiz-adv-x="1242" d="M570 1407h12q39 0 63 -99q460 -1200 467 -1235v-1q0 -31 -37 -47l-77 4h-844l-75 -4q-39 14 -39 49l496 1315q17 18 34 18zM559 1178l-399 -1052h832q-391 1041 -433 1052z" />
-<glyph unicode="&#x395;" horiz-adv-x="1109" d="M129 1405l-9 2h746l15 4q40 0 48 -57q-10 -44 -58 -44h-717v-560h480l53 3q30 0 42 -53q0 -30 -41 -48l-69 4h-465v-534h736q31 0 38 -52q-13 -45 -42 -45h-780q-49 9 -49 47v1286q7 49 72 49v-2z" />
-<glyph unicode="&#x396;" horiz-adv-x="1342" d="M122 1412h1021q34 0 43 -49v-1q0 -20 -77 -110l-874 -1129h902q49 -7 49 -47v-2q-9 -49 -47 -49h-1009q-38 0 -47 57q0 17 177 237l771 996h-895q-53 11 -53 47q11 50 39 50z" />
-<glyph unicode="&#x397;" horiz-adv-x="1223" d="M114 1412h12q46 -9 46 -35v-623h762v610q8 48 43 48h9q45 -9 45 -43v-1301q0 -29 -50 -39h1q-48 9 -48 47v585h-762v-589q0 -35 -48 -43h-2q-37 0 -47 53v1271q6 59 39 59z" />
-<glyph unicode="&#x398;" horiz-adv-x="1611" d="M761 1406q349 0 585 -324q105 -183 105 -370q0 -345 -313 -574q-177 -113 -370 -113h-15q-355 0 -582 332q-101 167 -101 362q0 330 291 556q189 131 400 131zM167 708q0 -286 251 -479q157 -107 335 -107h19q279 0 472 247q110 159 110 347q0 322 -294 510 q-145 83 -299 83q-295 0 -487 -255q-107 -154 -107 -346zM406 762h710q49 -9 49 -46v-2q-9 -49 -47 -49h-716q-46 10 -46 43v15q0 29 50 39z" />
-<glyph unicode="&#x399;" horiz-adv-x="581" d="M158 1422l15 -2h146l13 2q51 -10 51 -48q-9 -53 -47 -53h-41v-1197h48q30 0 40 -51v1q-9 -49 -47 -49h-178q-49 9 -49 47v1q10 51 40 51h48v1197h-41q-41 0 -47 56v3q0 28 49 42z" />
-<glyph unicode="&#x39a;" horiz-adv-x="1118" d="M93 1409h1q49 -8 49 -43v-713q735 734 733 734l27 4h3q45 -9 45 -43v-12q0 -25 -71 -83l-482 -485l543 -672l2 -15v-9q0 -35 -48 -43h-2q-32 0 -105 107l-463 562l-182 -186v-444q0 -35 -49 -43h-1q-37 0 -47 52v1280q10 52 47 52z" />
-<glyph unicode="&#x39b;" horiz-adv-x="1232" d="M567 1413h11q40 0 63 -99q463 -1205 470 -1240q-9 -49 -47 -49h-4q-34 0 -52 52q-412 1102 -454 1102l-429 -1135q-20 -19 -40 -19h-4q-38 0 -46 52l497 1318q17 18 35 18z" />
-<glyph unicode="&#x39c;" horiz-adv-x="1479" d="M99 1407h15q39 0 59 -81l497 -1111q47 55 366 784l184 396q12 12 28 12h15q33 0 39 -59v-1270q-10 -53 -47 -53h-2q-48 8 -48 43v966h-45q-429 -973 -441 -992q-20 -17 -38 -17q-48 0 -94 143l-385 862h-45v-962q0 -35 -48 -43h-2q-37 0 -47 53v1270q6 59 39 59z" />
-<glyph unicode="&#x39d;" horiz-adv-x="1329" d="M105 1406h15q32 0 62 -64q58 -65 830 -1062q-5 0 -5 6l16 -21h41v1096q9 45 43 45h11q35 0 43 -48v-1283q0 -41 -56 -50q-28 0 -110 122l-832 1062v-1137q0 -35 -49 -43h-1q-37 0 -47 52v1266q6 59 39 59z" />
-<glyph unicode="&#x39e;" horiz-adv-x="1158" d="M83 1407h874q45 -9 45 -43v-15q0 -33 -59 -39h-846q-53 11 -53 47q11 50 39 50zM205 778h634q49 -8 49 -47v-1q-9 -49 -47 -49h-636q-37 0 -46 49q12 48 46 48zM91 123h862q49 -9 49 -43v-10q-9 -45 -43 -45h-868q-37 0 -46 50q12 48 46 48z" />
-<glyph unicode="&#x39f;" horiz-adv-x="1620" d="M768 1410q350 0 586 -325q106 -184 106 -371q0 -346 -314 -576q-177 -113 -371 -113h-15q-357 0 -583 333q-102 167 -102 363q0 331 292 558q189 131 401 131zM172 710q0 -286 252 -481q158 -107 336 -107h19q280 0 473 248q111 160 111 348q0 323 -295 511 q-146 84 -300 84q-295 0 -489 -256q-107 -154 -107 -347z" />
-<glyph unicode="&#x3a0;" horiz-adv-x="1184" d="M105 1406h870q45 -9 45 -43v-1299q0 -29 -50 -39h2q-49 9 -49 47v1236h-760v-1240q0 -35 -49 -43h-1q-37 0 -47 52v1269q6 60 39 60z" />
-<glyph unicode="&#x3a1;" horiz-adv-x="946" d="M96 1413h346q189 0 323 -197q50 -100 50 -180v-27q0 -177 -161 -306q-109 -75 -212 -75h-287v-560q0 -34 -49 -43h-2q-37 0 -47 53v1275q6 60 39 60zM155 1315v-589h260q207 0 285 198q17 42 17 100q0 183 -186 270q-47 21 -108 21h-268z" />
-<glyph unicode="&#x3a3;" horiz-adv-x="1124" d="M106 1290h802q39 -8 39 -38v-14q0 -28 -52 -34h-684q446 -510 463 -535l2 -13v-9q0 -22 -70 -87l-354 -412v-37h652q43 -8 43 -38v-8q-8 -40 -37 -40h-797q-32 0 -41 47q0 16 70 77l435 505l-499 574q-6 10 -6 18q10 44 34 44z" />
-<glyph unicode="&#x3a4;" horiz-adv-x="1262" d="M104 1411h931q45 -9 45 -43v-15q0 -33 -59 -39h-400v-1246q0 -35 -49 -43h-1q-37 0 -47 53v1236h-406q-53 11 -53 47q11 50 39 50z" />
-<glyph unicode="&#x3a5;" horiz-adv-x="1237" d="M117 1408h16q32 0 56 -59l354 -529h31q377 569 388 578q14 10 20 10h23q26 0 39 -50q0 -21 -125 -192l-311 -464v-618q-7 -59 -39 -59h-16q-31 0 -43 40v617q0 22 -164 265l-266 400l-2 13q11 48 39 48z" />
-<glyph unicode="&#x3a6;" horiz-adv-x="1629" d="M748 1414h9q46 -9 46 -43v-99q202 -16 388 -120q261 -184 261 -434q0 -234 -241 -413q-110 -84 -326 -128q-82 -4 -82 -36v-76q0 -30 -50 -40h1q-49 9 -49 47v101h-29q-133 0 -334 103q-283 181 -283 446q0 251 266 431q112 81 380 120v92q8 49 43 49zM157 722 q0 -278 331 -434q128 -43 217 -43v956q-221 -25 -376 -142q-172 -154 -172 -337zM803 1202v-957h28q155 0 354 138q165 153 165 320v34q0 223 -259 381q-91 55 -288 84z" />
-<glyph unicode="&#x3a7;" horiz-adv-x="1338" d="M106 1412h16q29 0 51 -44l446 -571l475 610q9 5 21 5h12q34 0 43 -49v-1q0 -24 -96 -136l-396 -509l486 -622l6 -22v1q-9 -49 -47 -49h-4q-33 0 -62 60l-438 559l-477 -611q-10 -8 -24 -8h-2q-49 9 -49 47v11q0 16 158 208l334 433q-481 609 -489 627l-3 14q11 47 39 47z " />
-<glyph unicode="&#x3a8;" horiz-adv-x="1342" d="M98 1412h13q46 -9 46 -36v-315q11 -139 44 -215q91 -176 258 -233l100 -28v767q7 60 40 60h12q46 -9 46 -36v-783h30q112 7 260 141q117 139 117 350v283q9 45 43 45h11q35 0 44 -49v-332q0 -311 -309 -492q-132 -51 -196 -51v-420q0 -34 -49 -43h-1q-37 0 -48 53v408 q-105 9 -243 81q-257 179 -257 487v299q6 59 39 59z" />
-<glyph unicode="&#x3a9;" horiz-adv-x="1658" d="M756 1412q354 0 592 -328q107 -192 107 -360q0 -328 -247 -543h-20v-54h187q50 -10 50 -39v-13q-10 -46 -44 -46h-492q-38 0 -46 53q12 45 43 45q115 0 307 164q167 196 167 425q0 284 -254 489q-170 108 -335 108h-30q-285 0 -481 -259q-108 -166 -108 -338 q0 -345 317 -535q55 -34 180 -64q29 -12 29 -44q-14 -48 -48 -48h-482q-53 11 -53 48q12 51 48 51h185v40q-99 75 -168 181q-103 180 -103 379q0 324 299 559q192 129 400 129z" />
-<glyph unicode="&#x3aa;" horiz-adv-x="648" d="M119 1658h12q46 -9 46 -35v-19q0 -34 -47 -43q-50 10 -50 48q11 49 39 49zM412 1658h5q46 -10 46 -39v-11q0 -39 -50 -47q-47 10 -47 47v11q0 29 46 39zM188 1405l15 -3h145l13 3q49 -10 49 -48q-9 -52 -46 -52h-40v-1183h47q29 0 39 -49v1q-8 -49 -46 -49h-175 q-49 9 -49 47q10 50 39 50h48v1183h-40q-41 0 -47 55v3q0 27 48 42z" />
-<glyph unicode="&#x3ab;" horiz-adv-x="1216" d="M96 1408h16q32 0 56 -59l354 -529h31q377 569 388 578q14 10 20 10h23q26 0 39 -50q0 -21 -125 -192l-311 -464v-618q-7 -59 -39 -59h-16q-31 0 -43 40v617q0 22 -164 265l-266 400l-2 13q11 48 39 48zM387 1662h12q46 -9 46 -35v-19q0 -34 -47 -43q-50 10 -50 48 q11 49 39 49zM679 1662h6q46 -10 46 -39v-11q0 -39 -50 -47q-47 10 -47 47v11q0 29 45 39z" />
-<glyph unicode="&#x3ac;" horiz-adv-x="1414" d="M549 990q243 0 405 -229l49 -97q40 64 128 302q18 24 39 24q51 -10 51 -47q-3 -18 -161 -435q161 -420 161 -431q-12 -52 -49 -52q-49 0 -84 141l-58 155h-42q-52 -128 -165 -205q-118 -91 -281 -91h-15q-194 0 -362 184q-102 144 -102 299q0 260 250 422q124 60 236 60z M158 508q0 -234 233 -357q84 -31 162 -31q224 0 349 233l55 154q-69 238 -186 314q-101 71 -214 71h-19q-210 0 -333 -202q-47 -96 -47 -182zM645 1395q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43z" />
-<glyph unicode="&#x3ad;" horiz-adv-x="900" d="M348 992h37q150 0 299 -156q19 -20 19 -37v-8q0 -37 -63 -47q-33 0 -92 77q-105 72 -176 72h-21q-109 0 -167 -131v-55q0 -88 123 -137q20 -10 57 -10h66q59 -9 59 -48v-7q0 -44 -87 -44q-142 0 -195 -108l-15 -61q32 -168 185 -168h4q119 0 239 139q19 10 35 10 q52 0 61 -57v2q-25 -74 -167 -150q-84 -43 -168 -43h-17q-171 0 -269 169q-19 56 -19 100q0 104 116 212q-129 110 -129 224q0 173 221 255zM485 1391q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43z" />
-<glyph unicode="&#x3ae;" horiz-adv-x="1191" d="M104 975q48 -12 48 -37v-137q195 174 374 174q195 0 348 -163q111 -138 111 -289v-881q0 -29 -50 -36q-43 12 -43 44v825q0 293 -257 388q-61 15 -109 15h-11q-215 0 -331 -219q-32 -70 -32 -213v-385q0 -33 -47 -41h-1q-35 0 -45 50v845q6 60 45 60zM599 1374 q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43z" />
-<glyph unicode="&#x3af;" horiz-adv-x="467" d="M175 983q48 -12 48 -38v-879q0 -33 -47 -41h-2q-35 0 -45 51v846q6 61 46 61zM249 1366q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43z" />
-<glyph unicode="&#x3b0;" horiz-adv-x="1203" d="M129 979q48 -12 48 -37v-392q0 -266 154 -358q95 -74 215 -74q230 0 346 236q24 76 24 152v423q10 50 45 50q48 -11 48 -45v-465q0 -206 -199 -361q-125 -83 -253 -83h-25q-215 0 -375 213q-73 113 -73 282v399q6 60 45 60zM610 1365q51 -12 51 -45v-7q0 -21 -76 -106 q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43zM318 1284q58 -14 58 -53q-11 -57 -53 -57q-57 11 -57 52q14 58 52 58zM770 1284q58 -14 58 -53q-11 -57 -53 -57q-57 11 -57 52q14 58 52 58z" />
-<glyph unicode="&#x3b1;" horiz-adv-x="1414" d="M562 990q243 0 405 -229l49 -97q40 64 128 302q18 24 39 24q51 -10 51 -47q-3 -18 -161 -435q161 -420 161 -431q-12 -52 -49 -52q-49 0 -84 141l-58 155h-42q-52 -128 -165 -205q-118 -91 -281 -91h-15q-194 0 -362 184q-102 144 -102 299q0 260 250 422q124 60 236 60z M171 508q0 -234 233 -357q84 -31 162 -31q224 0 349 233l55 154q-69 238 -186 314q-101 71 -214 71h-19q-210 0 -333 -202q-47 -96 -47 -182z" />
-<glyph unicode="&#x3b2;" horiz-adv-x="999" d="M426 1409h4q221 0 334 -223q25 -63 25 -127v-15q0 -146 -138 -276v-28q191 -126 191 -332q0 -216 -223 -344q-93 -36 -170 -36q-119 0 -281 114v-489q-1 -51 -47 -52.5t-53 41.5v77v629v132v591q0 178 194 300q83 38 164 38zM168 1000v-599q0 -131 121 -221 q72 -50 164 -50q205 0 277 212l9 57v17q0 201 -223 275l-58 3h-129q-50 8 -50 47v16q0 27 47 39h62q214 0 280 160q17 52 17 88v19q0 173 -204 241l-54 4q-185 0 -252 -198z" />
-<glyph unicode="&#x3b3;" horiz-adv-x="1057" d="M143 983q45 0 80 -125l250 -618h41q284 716 294 726q25 16 35 17q51 -10 51 -50q0 -14 -346 -862l-8 -35v-402q0 -38 -50 -46q-46 10 -46 46v411q0 27 -348 869l-3 18q10 51 50 51z" />
-<glyph unicode="&#x3b4;" horiz-adv-x="1233" d="M173 1408l11 -1h706q52 -10 52 -47v-6q-9 -45 -68 -45h-568l573 -421q169 -163 169 -370q0 -277 -263 -436q-113 -57 -218 -57h-30q-198 0 -369 187q-105 148 -105 306q0 265 251 427q118 57 237 57l-435 327q-11 16 -11 29q8 49 68 49v1zM164 529v-19q0 -222 213 -343 q79 -41 167 -41h23q230 0 351 238q29 75 29 146v19q0 185 -169 311q-100 69 -226 69q-252 0 -367 -262q-21 -65 -21 -118z" />
-<glyph unicode="&#x3b5;" horiz-adv-x="896" d="M348 992h37q150 0 299 -156q19 -20 19 -37v-8q0 -37 -63 -47q-33 0 -92 77q-105 72 -176 72h-21q-109 0 -167 -131v-55q0 -88 123 -137q20 -10 57 -10h66q59 -9 59 -48v-7q0 -44 -87 -44q-142 0 -195 -108l-15 -61q32 -168 185 -168h4q119 0 239 139q19 10 35 10 q52 0 61 -57v2q-25 -74 -167 -150q-84 -43 -168 -43h-17q-171 0 -269 169q-19 56 -19 100q0 104 116 212q-129 110 -129 224q0 173 221 255z" />
-<glyph unicode="&#x3b6;" horiz-adv-x="1052" d="M249 1410h582q47 -9 47 -35v-19q0 -29 -61 -59q-445 -394 -496 -450q-97 -128 -97 -282q0 -249 233 -389q96 -58 253 -58q114 -28 165 -96q56 -75 56 -160v-4q0 -183 -203 -252h-1q-50 10 -50 40v15q0 36 76 57q84 54 84 144q0 102 -104 150l-45 12l-34 -4 q-223 0 -409 204q-119 162 -119 322v42q0 252 265 460l297 264h-429q-53 10 -53 47v2q8 49 43 49z" />
-<glyph unicode="&#x3b7;" horiz-adv-x="1178" d="M104 975q48 -12 48 -37v-137q195 174 374 174q195 0 348 -163q111 -138 111 -289v-881q0 -29 -50 -36q-43 12 -43 44v825q0 293 -257 388q-61 15 -109 15h-11q-215 0 -331 -219q-32 -70 -32 -213v-385q0 -33 -47 -41h-1q-35 0 -45 50v845q6 60 45 60z" />
-<glyph unicode="&#x3b8;" horiz-adv-x="1158" d="M533 1405q230 0 353 -247q70 -215 70 -398v-86q0 -225 -91 -451q-129 -198 -324 -198h-12q-212 0 -334 227q-81 206 -81 459v12q0 269 95 484q131 198 324 198zM195 765h676q0 193 -83 399q-104 148 -251 148q-171 0 -264 -173q-64 -174 -66 -290zM198 669 q5 -176 75 -386q100 -165 253 -165h11q262 0 315 364q19 108 19 187h-673z" />
-<glyph unicode="&#x3b9;" horiz-adv-x="442" d="M163 983q48 -12 48 -38v-879q0 -33 -47 -41h-2q-35 0 -45 51v846q6 61 46 61z" />
-<glyph unicode="&#x3ba;" horiz-adv-x="1086" d="M118 1048l16 1q34 -9 37 -57v-411q573 380 656 427h12q39 0 47 -56q0 -29 -109 -87q-290 -196 -319 -201v-33l425 -540l3 -14v1q-9 -49 -47 -49h-7q-31 0 -113 118l-349 434h-22l-177 -113v-400q0 -35 -49 -43h-2q-35 0 -47 46v922q9 46 45 55z" />
-<glyph unicode="&#x3bb;" horiz-adv-x="1120" d="M357 1357l600 -1257q9 -70 -36 -73t-70 40l-337 702h-37q-320 -686 -352 -728q-27 -35 -69.5 -15t-4.5 107l236 497l145 306l-173 374q-23 76 28 88.5t70 -41.5z" />
-<glyph unicode="&#x3bc;" horiz-adv-x="1199" d="M116 979q48 -12 48 -37v-393q0 -266 154 -359q96 -73 216 -73q230 0 346 236q24 76 24 152v424q10 50 45 50q48 -11 48 -45v-873q0 -28 -47 -37h1q-47 8 -47 44v95h-39q-153 -139 -320 -139h-26q-162 0 -355 174v-552q0 -26 -51 -37q-31 0 -42 54v1256q6 60 45 60z" />
-<glyph unicode="&#x3bd;" horiz-adv-x="1220" d="M131 1004h7q41 0 79 -109l345 -709q371 786 389 805q17 13 30 13q52 -10 52 -46v-4q0 -13 -162 -350l-276 -565q-18 -14 -33 -14h-3q-46 0 -90 128q-363 742 -381 794v12q9 45 43 45z" />
-<glyph unicode="&#x3be;" horiz-adv-x="951" d="M382 1408h180q50 -9 50 -47v-2q-9 -50 -48 -50h-167q-160 0 -207 -148l-9 -47q29 -201 201 -201h6l88 18q48 -12 48 -39v-23q0 -36 -97 -52q-227 -116 -227 -324v-27q0 -204 210 -315q39 -24 221 -41q190 -74 190 -249v-4q0 -183 -204 -253q-51 10 -51 40v15q0 37 77 57 q83 56 83 147q-27 160 -166 160l-11 -4q-223 0 -382 220q-69 127 -69 238q0 184 167 360q-182 106 -182 280q0 169 180 267q53 24 119 24z" />
-<glyph unicode="&#x3bf;" horiz-adv-x="1245" d="M561 979q184 0 334 -140q143 -149 143 -337q0 -268 -254 -421q-110 -56 -212 -56h-29q-192 0 -358 182q-101 142 -101 295q0 232 206 390q132 87 271 87zM181 513v-18q0 -215 207 -334q76 -39 162 -39h22q223 0 342 231q27 74 27 142v18q0 179 -163 302q-98 67 -221 67 q-244 0 -356 -254q-20 -63 -20 -115z" />
-<glyph unicode="&#x3c0;" horiz-adv-x="1165" d="M133 982l11 -1h772l37 3q44 -15 44 -41v-11q0 -31 -41 -45l-55 4h-44v-825q0 -33 -47 -41h-2q-35 0 -45 51v815h-462v-828q0 -29 -47 -38q-47 8 -47 45v821h-44l-55 -4q-41 15 -41 47q8 47 66 47v1z" />
-<glyph unicode="&#x3c1;" horiz-adv-x="1187" d="M542 995q185 0 336 -141q145 -152 145 -341q0 -271 -257 -426q-111 -56 -214 -56h-30q-166 0 -369 183v-567q0 -27 -52 -38q-30 0 -42 52v819q0 367 346 494q42 13 137 21zM157 524v-19q0 -217 209 -336q77 -40 164 -40h22q226 0 345 233q28 74 28 143v19q0 182 -165 305 q-99 68 -223 68q-246 0 -359 -257q-21 -64 -21 -116z" />
-<glyph unicode="&#x3c2;" horiz-adv-x="997" d="M559 993q147 0 147 -59v-17q-12 -42 -47 -42h-10l-84 12q-244 0 -357 -243q-18 -43 -26 -137q0 -240 253 -357q63 -16 202 -29q201 -78 201 -263v-4q0 -194 -215 -267h-2q-53 11 -53 43v16q0 40 81 61q87 58 87 151q0 118 -131 164l-32 6l-14 -5q-268 0 -426 263 q-53 105 -53 196v44q0 243 247 406q127 61 232 61z" />
-<glyph unicode="&#x3c3;" horiz-adv-x="1355" d="M514 981l80 -4h521l29 4q43 -14 43 -38v-22q0 -22 -38 -37l-57 4h-268q187 -199 187 -385q0 -241 -220 -401q-126 -77 -247 -77h-29q-202 0 -362 188q-98 136 -98 275v33q0 217 217 383q140 77 242 77zM148 503q0 -235 240 -357q78 -24 127 -24h33q192 0 314 188 q52 90 52 200q0 207 -204 331q-85 43 -184 43q-207 0 -331 -200q-47 -95 -47 -181z" />
-<glyph unicode="&#x3c4;" horiz-adv-x="1187" d="M146 984l11 -1h783l29 4q43 -13 43 -45v-8q0 -30 -38 -45l-57 4h-322v-817q-10 -51 -45 -51h-2q-47 8 -47 41v827h-325l-54 -4q-42 15 -42 47q8 47 66 47v1z" />
-<glyph unicode="&#x3c5;" horiz-adv-x="1216" d="M129 979q48 -12 48 -37v-392q0 -266 154 -358q95 -74 215 -74q230 0 346 236q24 76 24 152v423q10 50 45 50q48 -11 48 -45v-465q0 -206 -199 -361q-125 -83 -253 -83h-25q-215 0 -375 213q-73 113 -73 282v399q6 60 45 60z" />
-<glyph unicode="&#x3c6;" horiz-adv-x="1213" d="M679 986h28q132 0 268 -208q66 -120 66 -241q0 -293 -279 -456q-116 -47 -187 -47v-387q0 -43 -55 -51q-46 12 -46 43v396q-119 14 -249 102q-190 167 -190 404q0 235 217 404q15 10 28 10h9q47 -9 47 -44v-16q0 -20 -68 -65q-129 -136 -129 -274v-42q0 -207 214 -339 l121 -44v649q0 126 149 195zM575 758v-620h29q102 8 233 124q100 130 100 252v42q0 183 -193 320l-45 10q-87 0 -121 -89z" />
-<glyph unicode="&#x3c7;" horiz-adv-x="1237" d="M162 983q37 0 90 -106l305 -477h35q318 509 368 571q13 10 26 12q50 -10 50 -49q0 -26 -178 -287l-219 -349q0 -29 323 -526q74 -112 74 -128q-11 -52 -46 -52q-42 0 -93 107q-50 69 -305 476h-35q-341 -547 -366 -570q-13 -10 -34 -13q-33 0 -44 55v-1q9 33 279 440 q25 50 127 197l-406 643v5q10 52 49 52z" />
-<glyph unicode="&#x3c8;" horiz-adv-x="1376" d="M136 994h2q49 -7 49 -48v-303q0 -271 139 -386q75 -85 215 -117l49 -11v801q6 60 40 60h13q47 -9 47 -36v-819h29q112 7 250 130q127 130 127 348v331q9 50 48 50h4q51 0 51 -86v-326q0 -337 -333 -514q-113 -40 -176 -40v-343q0 -35 -50 -44h-2q-38 0 -48 54v331 q-114 9 -260 90q-246 184 -246 485v332q9 61 52 61z" />
-<glyph unicode="&#x3c9;" horiz-adv-x="1321" d="M277 991h5q45 -8 45 -44v-4q0 -7 -81 -174q-88 -230 -88 -426v-29q0 -134 149 -186l43 -8q153 0 201 165l4 90v320l-4 36q15 43 40 43h11q37 0 43 -59v-374l3 -27l-3 -10q0 -110 138 -180l59 -8q144 0 197 157l3 40v30q0 274 -169 588v10q8 46 43 46h4q40 0 82 -108 q135 -281 135 -565q0 -178 -184 -269q-50 -20 -98 -20h-22q-118 0 -239 128q-106 -124 -231 -124h-14q-180 0 -270 193q-16 54 -16 92q0 344 183 661q15 16 31 16z" />
-<glyph unicode="&#x3ca;" horiz-adv-x="589" d="M268 983q48 -12 48 -38v-879q0 -33 -47 -41h-2q-35 0 -45 51v846q6 61 46 61zM113 1211h12q46 -9 46 -35v-19q0 -34 -47 -43q-50 10 -50 48q11 49 39 49zM406 1211h5q46 -10 46 -39v-11q0 -39 -50 -47q-47 10 -47 47v11q0 29 46 39z" />
-<glyph unicode="&#x3cb;" horiz-adv-x="1208" d="M129 979q48 -12 48 -37v-392q0 -266 154 -358q95 -74 215 -74q230 0 346 236q24 76 24 152v423q10 50 45 50q48 -11 48 -45v-465q0 -206 -199 -361q-125 -83 -253 -83h-25q-215 0 -375 213q-73 113 -73 282v399q6 60 45 60zM382 1246h12q46 -9 46 -35v-19q0 -34 -47 -43 q-50 10 -50 48q11 49 39 49zM675 1246h5q46 -10 46 -39v-11q0 -39 -50 -47q-47 10 -47 47v11q0 29 46 39z" />
-<glyph unicode="&#x3cc;" horiz-adv-x="1229" d="M561 979q184 0 334 -140q143 -149 143 -337q0 -268 -254 -421q-110 -56 -212 -56h-29q-192 0 -358 182q-101 142 -101 295q0 232 206 390q132 87 271 87zM181 513v-18q0 -215 207 -334q76 -39 162 -39h22q223 0 342 231q27 74 27 142v18q0 179 -163 302q-98 67 -221 67 q-244 0 -356 -254q-20 -63 -20 -115zM593 1362q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43z" />
-<glyph unicode="&#x3cd;" horiz-adv-x="1178" d="M129 979q48 -12 48 -37v-392q0 -266 154 -358q95 -74 215 -74q230 0 346 236q24 76 24 152v423q10 50 45 50q48 -11 48 -45v-465q0 -206 -199 -361q-125 -83 -253 -83h-25q-215 0 -375 213q-73 113 -73 282v399q6 60 45 60zM598 1388q51 -12 51 -45v-7q0 -21 -76 -106 q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43z" />
-<glyph unicode="&#x3ce;" horiz-adv-x="1309" d="M277 991h5q45 -8 45 -44v-4q0 -7 -81 -174q-88 -230 -88 -426v-29q0 -134 149 -186l43 -8q153 0 201 165l4 90v320l-4 36q15 43 40 43h11q37 0 43 -59v-374l3 -27l-3 -10q0 -110 138 -180l59 -8q144 0 197 157l3 40v30q0 274 -169 588v10q8 46 43 46h4q40 0 82 -108 q135 -281 135 -565q0 -178 -184 -269q-50 -20 -98 -20h-22q-118 0 -239 128q-106 -124 -231 -124h-14q-180 0 -270 193q-16 54 -16 92q0 344 183 661q15 16 31 16zM678 1375q51 -12 51 -45v-7q0 -21 -76 -106q-54 -82 -93 -82h-4q-27 0 -37 48v4q0 24 108 145q31 43 51 43z " />
-<glyph unicode="&#x2000;" horiz-adv-x="919" />
-<glyph unicode="&#x2001;" horiz-adv-x="1838" />
-<glyph unicode="&#x2002;" horiz-adv-x="919" />
-<glyph unicode="&#x2003;" horiz-adv-x="1838" />
-<glyph unicode="&#x2004;" horiz-adv-x="612" />
-<glyph unicode="&#x2005;" horiz-adv-x="459" />
-<glyph unicode="&#x2006;" horiz-adv-x="306" />
-<glyph unicode="&#x2007;" horiz-adv-x="306" />
-<glyph unicode="&#x2008;" horiz-adv-x="229" />
-<glyph unicode="&#x2009;" horiz-adv-x="367" />
-<glyph unicode="&#x200a;" horiz-adv-x="102" />
-<glyph unicode="&#x2010;" horiz-adv-x="670" d="M119 623h400q38 0 50 -55q-12 -51 -50 -51h-400q-44 0 -51 57q14 49 51 49z" />
-<glyph unicode="&#x2011;" horiz-adv-x="670" d="M119 623h400q38 0 50 -55q-12 -51 -50 -51h-400q-44 0 -51 57q14 49 51 49z" />
-<glyph unicode="&#x2013;" horiz-adv-x="1108" d="M156 484l14 -1h722l36 4q38 0 50 -58q0 -33 -44 -52l-62 4h-682l-59 -4q-47 17 -47 53q9 53 72 53v1z" />
-<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M72 552l14 -1h1826l36 4q38 0 50 -58q0 -33 -44 -52l-62 4h-1786l-59 -4q-47 17 -47 53q9 53 72 53v1z" />
-<glyph unicode="&#x2015;" horiz-adv-x="2007" d="M165 591l14 -1h1602l33 4q49 -14 49 -51v-8q0 -34 -43 -51l-63 4h-1558l-59 -4q-47 17 -47 53q9 53 72 53v1z" />
-<glyph unicode="&#x2017;" horiz-adv-x="951" d="M46 -54h882q52 -9 52 -45v-10q-10 -47 -45 -47h-889q-42 0 -49 55q13 47 49 47z" />
-<glyph unicode="&#x2018;" horiz-adv-x="557" d="M340 1541q2 -1 2 -6v-3q-59 -141 -60 -249q0 -67 49 -149l3 -13q0 -41 -61 -53q-72 0 -97 228q0 121 132 233z" />
-<glyph unicode="&#x2019;" horiz-adv-x="557" d="M236 1533h28q61 0 87 -213v-18q0 -117 -133 -227q-21 -12 -25 -12q-6 2 -8 6q60 144 60 241v12q0 69 -48 151v10q10 50 39 50z" />
-<glyph unicode="&#x201a;" horiz-adv-x="557" d="M231 195h28q61 0 87 -213v-18q0 -117 -133 -227q-21 -12 -25 -12q-6 2 -8 6q60 144 60 241v12q0 69 -48 151v10q10 50 39 50z" />
-<glyph unicode="&#x201b;" horiz-adv-x="450" d="M263 1473v-10q-49 -82 -49 -151v-12q0 -97 61 -241q-2 -4 -8 -6q-4 0 -26 12q-134 110 -134 227v18q26 213 88 213h28q30 0 40 -50z" />
-<glyph unicode="&#x201c;" horiz-adv-x="910" d="M388 1562q2 -1 2 -6v-3q-59 -141 -60 -249q0 -67 49 -149l3 -13q0 -41 -61 -53q-72 0 -97 228q0 121 132 233zM670 1555q8 -3 8 -6q-64 -142 -64 -249q0 -68 52 -159v-3q-10 -53 -47 -53h-16q-61 0 -91 181v66q0 96 127 208q20 15 31 15z" />
-<glyph unicode="&#x201d;" horiz-adv-x="910" d="M271 1556h28q61 0 87 -213v-18q0 -117 -133 -227q-21 -12 -25 -12q-6 2 -8 6q60 144 60 241v12q0 69 -48 151v10q10 50 39 50zM575 1560h12q72 0 95 -220v-7q0 -120 -132 -230l-32 -13q-2 0 -2 7v-1q60 141 60 253q0 69 -48 147v22q12 42 47 42z" />
-<glyph unicode="&#x201e;" horiz-adv-x="910" d="M253 210h28q61 0 87 -213v-18q0 -117 -133 -227q-21 -12 -25 -12q-6 2 -8 6q60 144 60 241v12q0 69 -48 151v10q10 50 39 50zM557 214h12q72 0 95 -220v-7q0 -120 -132 -230l-32 -13q-2 0 -2 7v-1q60 141 60 253q0 69 -48 147v22q12 42 47 42z" />
-<glyph unicode="&#x2020;" d="M484 1416h12q38 0 47 -53v-311h218l36 4q35 0 50 -58q0 -35 -47 -52l-55 4h-202v-1249q0 -46 -58 -54q-48 12 -48 46v1257h-198l-59 -4q-47 17 -47 53q9 53 72 53v1l14 -1h218v315q10 49 47 49z" />
-<glyph unicode="&#x2021;" d="M487 1416h12q38 0 47 -53v-311h218l36 4q35 0 50 -58q0 -35 -47 -52l-55 4h-202v-834h261q29 0 42 -52q-10 -54 -54 -54h-249v-309q0 -46 -58 -54q-48 12 -48 46v317h-247q-57 11 -57 52q12 54 43 54h261v834h-198l-59 -4q-47 17 -47 53q9 53 72 53v1l14 -1h218v315 q10 49 47 49z" />
-<glyph unicode="&#x2022;" horiz-adv-x="1024" d="M216 718q0 113 79.5 191.5t192.5 78.5q112 0 191 -79t79 -191t-80 -192t-192 -80q-113 0 -191.5 79.5t-78.5 192.5z" />
-<glyph unicode="&#x2026;" horiz-adv-x="2048" d="M1608 249q85 0 110 -103v-21q0 -59 -82 -95q-9 -5 -28 -5h-4q-91 0 -110 116q0 69 85 103q10 5 29 5zM917 245q85 0 110 -103v-21q0 -59 -82 -95q-9 -5 -28 -5h-4q-91 0 -110 116q0 69 85 103q10 5 29 5zM244 249q85 0 110 -103v-21q0 -59 -82 -95q-9 -5 -28 -5h-4 q-91 0 -110 116q0 69 85 103q10 5 29 5z" />
-<glyph unicode="&#x202f;" horiz-adv-x="367" />
-<glyph unicode="&#x2030;" horiz-adv-x="2494" d="M474 1411h19q155 0 264 -142q63 -93 63 -190q0 -217 -226 -320q-63 -18 -105 -18h-7q-195 0 -300 191q-35 71 -35 144q0 220 234 321q46 14 93 14zM1308 1411h8q46 -9 46 -44v-15q0 -13 -135 -186l-857 -1131q-18 -10 -28 -10h-1q-50 10 -50 39v16q0 22 101 143l892 1179 q13 9 24 9zM245 1081v-9q0 -168 186 -230l42 -3h20q165 0 226 190l4 46q0 173 -182 233l-53 9q-172 0 -235 -178zM1171 698q196 0 310 -204q25 -74 25 -130v-12q0 -196 -208 -302q-64 -25 -127 -25h-7q-171 0 -282 166q-46 80 -46 157v23q0 176 177 285q85 42 158 42z M930 365q0 -168 175 -234l57 -8h17q161 0 225 182l4 39v27q0 168 -194 226l-42 4q-179 0 -238 -198zM1964 703q196 0 310 -204q25 -74 25 -130v-12q0 -196 -208 -302q-64 -25 -127 -25h-7q-171 0 -282 166q-46 80 -46 157v23q0 176 177 285q85 42 158 42zM1723 370 q0 -168 175 -234l57 -8h17q161 0 225 182l4 39v27q0 168 -194 226l-42 4q-179 0 -238 -198z" />
-<glyph unicode="&#x2032;" horiz-adv-x="455" d="M251 1404h2q53 -9 53 -47v-20q0 -13 -162 -224q-10 -11 -17 -11h-8q-13 0 -19 22q101 253 118 269q19 11 33 11z" />
-<glyph unicode="&#x2033;" horiz-adv-x="673" d="M259 1404h2q53 -9 53 -47v-20q0 -13 -162 -224q-10 -11 -17 -11h-8q-13 0 -19 22q101 253 118 269q19 11 33 11zM505 1392q57 -11 57 -55q0 -23 -103 -153q-61 -94 -76 -94h-12q-13 0 -19 22q0 9 108 255q25 25 45 25z" />
-<glyph unicode="&#x2039;" horiz-adv-x="631" d="M371 658h6q53 -8 53 -51v-4q0 -38 -107 -109l-13 -13v-27q120 -82 120 -119v-2q-9 -53 -47 -53h-20q-20 0 -190 153l-5 18v40q0 25 140 125q38 42 63 42z" />
-<glyph unicode="&#x203a;" horiz-adv-x="631" d="M147 654q28 0 153 -115q54 -33 54 -56v-36q0 -33 -103 -105q-74 -70 -104 -70h-2q-53 10 -53 51v4q0 37 105 106l24 36q-129 91 -129 126v2q11 57 55 57z" />
-<glyph unicode="&#x203c;" horiz-adv-x="850" d="M593 1417h12q39 0 48 -46v-950q-12 -50 -51 -50q-57 9 -57 44v959q9 43 48 43zM584 181h6q80 -12 80 -67v-22q0 -51 -73 -67h-9q-59 0 -74 78q16 78 70 78zM189 1417h12q39 0 48 -46v-950q-12 -50 -51 -50q-57 9 -57 44v959q9 43 48 43zM180 181h6q80 -12 80 -67v-22 q0 -51 -73 -67h-9q-59 0 -74 78q16 78 70 78z" />
-<glyph unicode="&#x203e;" horiz-adv-x="837" d="M186 1334l14 -1h402l36 4q35 0 50 -58q0 -35 -47 -52l-55 4h-366l-59 -4q-47 17 -47 53q9 53 72 53v1z" />
-<glyph unicode="&#x2044;" horiz-adv-x="462" d="M610 1428h12q38 0 47 -53v-2q0 -24 -111 -156q-968 -1257 -975 -1261l-26 -10h-11q-34 0 -47 43v16q0 25 110 156l975 1258q11 9 26 9z" />
-<glyph unicode="&#x2215;" horiz-adv-x="462" d="M610 1428h12q38 0 47 -53v-2q0 -24 -111 -156q-968 -1257 -975 -1261l-26 -10h-11q-34 0 -47 43v16q0 25 110 156l975 1258q11 9 26 9z" />
-<glyph unicode="&#x205f;" horiz-adv-x="459" />
-<glyph unicode="&#x207f;" horiz-adv-x="787" d="M94 1040q20 -5 20 -13v-105q131 118 235 118q113 0 202 -95q64 -80 64 -167v-281q0 -8 -19 -12h2q-19 4 -19 17v247q0 183 -161 243q-39 10 -69 10h-7q-135 0 -208 -138q-20 -44 -20 -133v-231q0 -12 -19 -15q-13 0 -17 21v507q3 27 16 27z" />
-<glyph unicode="&#x20a3;" horiz-adv-x="1127" d="M250 1406l-10 2h725l15 4q37 0 45 -57q-10 -44 -56 -44h-696v-561h466l51 4q29 0 40 -54q0 -30 -38 -47l-68 4h-451v-308h148l33 4q32 0 43 -53q0 -31 -38 -48l-57 4h-129v-163l4 -20q-11 -48 -45 -48h-5q-47 9 -47 47v184h-125l-55 -4q-40 13 -40 47v7q0 33 40 47l33 -4 h147v1010q7 49 70 49v-2z" />
-<glyph unicode="&#x20a4;" horiz-adv-x="946" d="M414 1403h38q164 0 277 -151l3 -15q-12 -52 -50 -52q-24 0 -81 65q-73 56 -149 56h-23q-167 0 -236 -197l-3 -53q0 -66 78 -212l36 -78h270q53 -11 53 -47q-11 -50 -39 -50h-237l15 -106h208q49 -9 49 -47v-2q-9 -48 -47 -48h-188q-27 0 -47 -89l-112 -255h419 q22 0 62 89q20 20 38 20q52 -10 52 -50q0 -21 -67 -142q-15 -14 -32 -14h-554q-37 0 -47 51q1 12 141 318l23 72h-179q-45 9 -45 43v11q0 34 49 43h182l-20 106h-162q-49 10 -49 45q10 52 50 52h111q-108 189 -108 293q0 210 221 323q69 21 100 21z" />
-<glyph unicode="&#x20a7;" horiz-adv-x="2028" d="M98 1315v-589h260q207 0 285 198q17 42 17 100q0 183 -186 270q-47 21 -108 21h-268zM1253 890q49 37 70 50q106 56 210 56q243 0 380 -216l2 -22v-3q0 -37 -51 -45q-33 0 -78 76q-113 109 -253 109q-185 0 -294 -179l-4 -26q0 -74 132 -86q423 -102 459 -115 q93 -62 93 -156v-3q0 -139 -212 -260q-91 -41 -196 -41q-111 0 -235 72q-16 -76 -51 -76h-77q-159 0 -237 175q-13 42 -13 101v586h-161q-45 -107 -140 -184q-109 -75 -212 -75h-287v-560q0 -34 -49 -43h-2q-37 0 -47 53v1275q6 60 39 60h346q189 0 323 -197 q50 -100 50 -180v-60h140v332q6 57 38 57h11q44 -9 44 -34v-355h178l33 4q28 0 51 -90zM1257 112q-79 79 -107 117q-10 16 -10 27v22q0 32 58 38q21 0 80 -85q108 -100 248 -100q169 0 282 162l9 29v8q0 70 -87 80q-489 109 -514 131q-83 63 -83 151q0 76 105 190l-85 5 h-162v-564q0 -159 112 -198z" />
-<glyph unicode="&#x20ac;" horiz-adv-x="1193" d="M700 1432q218 0 403 -130q9 -18 9 -29v-7q0 -42 -57 -48h4l-131 67q-139 44 -228 44q-276 0 -480 -244q-45 -68 -90 -178h779q50 -8 50 -48v-2q-9 -50 -48 -50h-802l-6 -78l6 -83h800q50 -8 50 -48v-2q-9 -49 -48 -49h-781q106 -263 326 -367q122 -52 236 -52h12 q175 0 348 108h13q47 -10 47 -44v-12q0 -62 -239 -133q-77 -22 -162 -22h-19q-347 0 -581 323q-111 186 -111 381q0 365 334 596q178 107 366 107z" />
-<glyph unicode="&#x2105;" horiz-adv-x="1768" d="M1319 1405h12q34 0 43 -49v-1q0 -25 -120 -163q-95 -133 -891 -1158q-15 -9 -29 -9q-46 13 -46 39v23q0 14 138 185q806 1051 869 1125q11 8 24 8zM386 1405q128 0 231 -95q3 -5 3 -11q-5 -27 -25 -27h-3q-10 0 -71 46q-65 33 -128 33h-15q-169 0 -254 -176 q-20 -59 -20 -106q0 -170 175 -259q53 -20 112 -20q99 0 189 75l13 3h5q17 0 22 -26q0 -37 -150 -95q-52 -9 -77 -9h-21q-133 0 -249 127q-71 100 -71 207q0 162 144 273q91 60 190 60zM1291 684q125 0 228 -96q98 -102 98 -230q0 -184 -174 -289q-75 -38 -145 -38h-21 q-130 0 -244 125q-69 97 -69 202q0 159 141 267q90 59 186 59zM1017 365v-13q0 -154 149 -240q55 -28 117 -28h15q161 0 247 166q19 54 19 102v13q0 129 -117 218q-71 48 -159 48q-176 0 -257 -183q-14 -45 -14 -83z" />
-<glyph unicode="&#x2113;" horiz-adv-x="846" d="M511 1407q154 0 215 -165l7 -49v-17q0 -82 -119 -230l-224 -335v-370q0 -115 89 -115h24q62 26 74 26q31 0 42 -50q-17 -77 -140 -77q-120 0 -179 139l-7 67v237q-112 -179 -142 -179h-7q-39 0 -47 56q0 15 184 275l12 22v526q0 178 173 233zM390 793q242 338 242 375v34 q0 81 -116 105h-7q-100 0 -119 -129v-385z" />
-<glyph unicode="&#x2116;" horiz-adv-x="2271" d="M39 1406h15q32 0 62 -64q58 -65 830 -1062q-5 0 -5 6l16 -21h41v1096q9 45 43 45h11q35 0 43 -48v-1283q0 -41 -56 -50q-28 0 -110 122l-832 1062v-1137q0 -35 -49 -43h-1q-37 0 -47 52v1266q6 59 39 59zM1287 391l14 -1h722l36 4q38 0 50 -58q0 -33 -44 -52l-62 4h-682 l-59 -4q-47 17 -47 53q9 53 72 53v1zM1657 1251q143 0 260 -109q111 -116 111 -262q0 -209 -198 -328q-85 -43 -164 -43h-24q-148 0 -278 141q-78 111 -78 230q0 181 160 304q102 67 211 67zM1352 889v-14q0 -174 166 -268q61 -32 130 -32h18q179 0 274 185q22 60 22 115v14 q0 145 -131 242q-78 54 -177 54q-196 0 -286 -203q-16 -51 -16 -93z" />
-<glyph unicode="&#x2122;" horiz-adv-x="1497" d="M159 1416h433q9 -2 9 -7v-7q0 -3 -16 -5h-198v-594q0 -5 -11 -7h1q-7 0 -9 12v589h-202q-12 2 -12 8q3 11 5 11zM766 1415h8q8 0 15 -29l245 -548q37 45 188 392l86 184q0 1 2 1h8q3 0 5 -15v-600q-3 -13 -9 -13q-11 2 -11 7v471h-43q-206 -468 -210 -473q-5 -5 -8 -5 q-13 0 -32 59l-186 417h-43v-469q0 -5 -11 -7q-6 0 -9 13v600q2 15 5 15z" />
-<glyph unicode="&#x2126;" horiz-adv-x="1709" d="M794 1412q354 0 592 -328q107 -192 107 -360q0 -328 -247 -543h-20v-54h187q50 -10 50 -39v-13q-10 -46 -44 -46h-492q-38 0 -46 53q12 45 43 45q115 0 307 164q167 196 167 425q0 284 -254 489q-170 108 -335 108h-30q-285 0 -481 -259q-108 -166 -108 -338 q0 -345 317 -535q55 -34 180 -64q29 -12 29 -44q-14 -48 -48 -48h-482q-53 11 -53 48q12 51 48 51h185v40q-99 75 -168 181q-103 180 -103 379q0 324 299 559q192 129 400 129z" />
-<glyph unicode="&#x212e;" horiz-adv-x="1174" d="M541 979q276 0 429 -262q52 -102 52 -222v-17q-9 -50 -45 -50h-807q57 -188 210 -271q90 -35 169 -35q90 0 200 55h14q43 -9 43 -41v-11q0 -69 -241 -100h-24q-256 0 -410 241q-63 113 -63 236q0 262 247 418q121 59 226 59zM165 521h757q0 108 -94 236 q-130 122 -257 122h-41q-189 0 -310 -184q-43 -74 -55 -174z" />
-<glyph unicode="&#x215b;" horiz-adv-x="1498" d="M1168 1417h12q35 0 43 -49v-2q0 -25 -120 -164q-96 -134 -899 -1168q-15 -9 -30 -9q-46 13 -46 40v23q0 14 140 185q812 1061 875 1136q11 8 25 8zM304 1409q8 0 17 -15l-3 -50v-656l3 -31q-6 -19 -20 -19q-11 0 -17 11v710l-93 -21h-10q-11 6 -11 16q0 27 110 44 q0 6 24 11zM1136 781q84 0 143 -76q34 -45 34 -99v-11q0 -74 -92 -156q126 -91 126 -200q0 -108 -100 -181q-56 -37 -116 -37h-11q-103 0 -179 103q-32 59 -32 115q0 113 136 210q-68 52 -82 110q-5 14 -5 36v11q0 93 90 150q45 25 88 25zM991 598q0 -99 116 -139l28 -2 q102 0 139 108l6 34q0 108 -114 144l-32 2q-99 0 -139 -106zM942 243q0 -132 133 -181q20 -8 56 -8q123 0 176 136l5 36v24q0 106 -121 163q-34 11 -62 11q-132 0 -180 -137z" />
-<glyph unicode="&#x215c;" horiz-adv-x="1523" d="M1210 1417h12q35 0 43 -49v-2q0 -25 -120 -164q-96 -134 -899 -1168q-15 -9 -30 -9q-46 13 -46 40v23q0 14 140 185q812 1061 875 1136q11 8 25 8zM1178 781q84 0 143 -76q34 -45 34 -99v-11q0 -74 -92 -156q126 -91 126 -200q0 -108 -100 -181q-56 -37 -116 -37h-11 q-103 0 -179 103q-32 59 -32 115q0 113 136 210q-68 52 -82 110q-5 14 -5 36v11q0 93 90 150q45 25 88 25zM1033 598q0 -99 116 -139l28 -2q102 0 139 108l6 34q0 108 -114 144l-32 2q-99 0 -139 -106zM984 243q0 -132 133 -181q20 -8 56 -8q123 0 176 136l5 36v24 q0 106 -121 163q-34 11 -62 11q-132 0 -180 -137zM303 1493q107 0 164 -114q13 -30 13 -54v-22q0 -72 -89 -158q123 -86 123 -201q0 -158 -176 -216l-49 -4h-6q-148 0 -209 176l-4 49q0 5 12 12h12q16 0 20 -63q52 -137 172 -137h12q131 0 176 152l4 33q0 129 -150 182 q-47 0 -47 21q5 19 36 19q96 0 127 128v29q0 89 -120 131h-26q-103 0 -142 -119v-32q-6 -11 -13 -11h-9q-15 3 -15 12v8q0 125 142 175z" />
-<glyph unicode="&#x215d;" horiz-adv-x="1569" d="M1269 1417h12q35 0 43 -49v-2q0 -25 -120 -164q-96 -134 -899 -1168q-15 -9 -30 -9q-46 13 -46 40v23q0 14 140 185q812 1061 875 1136q11 8 25 8zM1237 781q84 0 143 -76q34 -45 34 -99v-11q0 -74 -92 -156q126 -91 126 -200q0 -108 -100 -181q-56 -37 -116 -37h-11 q-103 0 -179 103q-32 59 -32 115q0 113 136 210q-68 52 -82 110q-5 14 -5 36v11q0 93 90 150q45 25 88 25zM1092 598q0 -99 116 -139l28 -2q102 0 139 108l6 34q0 108 -114 144l-32 2q-99 0 -139 -106zM1043 243q0 -132 133 -181q20 -8 56 -8q123 0 176 136l5 36v24 q0 106 -121 163q-34 11 -62 11q-132 0 -180 -137zM120 1412l17 -2h323q13 0 17 -22q0 -9 -23 -14h-314v-261h145q126 0 197 -131q23 -54 23 -94q0 -116 -111 -193q-56 -31 -111 -31h-7q-131 0 -204 136q-18 51 -18 81q7 19 19 19q21 0 21 -53q32 -95 100 -128q50 -20 84 -20 q127 0 178 127q11 27 11 62q0 137 -146 185l-55 4h-147q-11 0 -15 14v309q0 6 16 12z" />
-<glyph unicode="&#x215e;" horiz-adv-x="1494" d="M1160 1417h12q35 0 43 -49v-2q0 -25 -120 -164q-96 -134 -899 -1168q-15 -9 -30 -9q-46 13 -46 40v23q0 14 140 185q812 1061 875 1136q11 8 25 8zM1128 781q84 0 143 -76q34 -45 34 -99v-11q0 -74 -92 -156q126 -91 126 -200q0 -108 -100 -181q-56 -37 -116 -37h-11 q-103 0 -179 103q-32 59 -32 115q0 113 136 210q-68 52 -82 110q-5 14 -5 36v11q0 93 90 150q45 25 88 25zM983 598q0 -99 116 -139l28 -2q102 0 139 108l6 34q0 108 -114 144l-32 2q-99 0 -139 -106zM934 243q0 -132 133 -181q20 -8 56 -8q123 0 176 136l5 36v24 q0 106 -121 163q-34 11 -62 11q-132 0 -180 -137zM118 1404h411q17 -3 17 -9v-11q0 -3 -18 -30l-401 -711q-5 -3 -9 -3q-18 4 -18 16v3q4 14 374 664l17 47h-363q-22 4 -22 15q4 19 12 19z" />
-<glyph unicode="&#x2190;" horiz-adv-x="1923" d="M550 984q44 -8 44 -42v-7q0 -33 -131 -101l-112 -68l-67 -43h1471q45 -9 45 -40q-9 -47 -42 -47h-1467l295 -190q8 -16 8 -26v-5q-8 -40 -38 -40h-15q-27 7 -411 255q-46 15 -46 48q0 37 107 87q334 219 354 219h5z" />
-<glyph unicode="&#x2191;" horiz-adv-x="833" d="M391 1413q34 0 85 -107q218 -335 218 -353v-7q-8 -41 -38 -41h-18q-23 0 -72 96l-132 211v-1469q0 -30 -43 -38q-43 8 -43 42v1468l-44 -68q-136 -239 -152 -239l-17 -3h-12q-35 11 -35 31v17q0 16 91 156l178 288q11 12 34 16z" />
-<glyph unicode="&#x2192;" horiz-adv-x="1910" d="M1316 984q22 0 284 -172q149 -86 174 -112l5 -15v-18q0 -22 -61 -48q-382 -244 -393 -244h-12q-41 8 -41 38v15q0 28 153 109l157 99h-1473q-35 0 -42 48q11 39 38 39h1475l-65 43q-214 125 -239 149l-4 23v11q0 26 44 35z" />
-<glyph unicode="&#x2193;" horiz-adv-x="808" d="M378 1419q27 0 42 -38l-3 -55v-1403l192 296q13 8 24 8h2q43 -8 43 -42v-7q0 -15 -90 -154l-179 -289q-15 -13 -30 -13h-4q-34 0 -82 102q-215 331 -217 348v17q0 30 43 38h2q34 0 72 -85l141 -215v1399l-3 56q0 25 47 37z" />
-<glyph unicode="&#x2194;" horiz-adv-x="1961" d="M1355 976h2q22 0 260 -157q178 -106 194 -121l7 -29q0 -29 -56 -52q-370 -235 -399 -245h-16q-35 11 -35 31v17q0 32 122 93q5 10 119 74l78 44h-1360l75 -43q209 -123 243 -155q5 -9 5 -20v-7q0 -33 -47 -41q-16 0 -303 185q-149 86 -153 99l-3 21v2q0 31 59 55 q362 232 399 245h1q47 -7 47 -41v-7q0 -32 -92 -76l-142 -77l-90 -54h1352q-279 169 -304 191l-6 17v13q0 30 43 38z" />
-<glyph unicode="&#x2195;" horiz-adv-x="825" d="M372 1407h7q31 0 54 -58q238 -374 242 -393v-1q-9 -47 -44 -47q-38 0 -78 91l-130 215v-1318l178 292q18 15 30 15q47 -9 47 -44q0 -22 -137 -232q-125 -206 -139 -218l-22 -4h-8q-29 0 -61 76q-232 355 -232 375q9 47 44 47t82 -94l91 -147l42 -65v1329l-42 -69 q-123 -209 -152 -241l-28 -8q-34 0 -40 50v-3q12 37 252 410q17 42 44 42z" />
-<glyph unicode="&#x21a8;" horiz-adv-x="879" d="M401 1407h7q31 0 54 -58q238 -374 242 -393v-1q-9 -47 -44 -47q-38 0 -78 91l-130 207v-1299l178 281q18 15 30 15q47 -9 47 -44q0 -22 -137 -232q-125 -206 -139 -218l-22 -4h-8q-29 0 -61 76q-232 355 -232 375q9 47 44 47t82 -94l91 -147l42 -68v1329l-42 -66 q-123 -209 -152 -241l-28 -8q-34 0 -40 50v-3q12 37 252 410q17 42 44 42z" />
-<glyph unicode="&#x2202;" horiz-adv-x="1131" d="M92 1407q533 0 791 -456q102 -164 102 -486q0 -152 -147 -311q-148 -129 -316 -129h-23q-226 0 -389 224q-70 126 -70 250q0 251 240 409q113 62 234 62q114 0 265 -78v52q-134 233 -432 334q-120 32 -213 32l-46 -4q-29 0 -40 48v7q9 46 44 46zM133 499q0 -231 227 -348 q78 -33 154 -33q227 0 345 223q33 77 33 162q0 224 -232 345q-88 29 -146 29q-224 0 -343 -219q-38 -87 -38 -159z" />
-<glyph unicode="&#x2206;" horiz-adv-x="1144" d="M538 1418h12q41 0 60 -97q475 -1225 475 -1240v-12q0 -35 -50 -44h-988q-39 0 -47 53l503 1321q17 19 35 19zM525 1173l-399 -1048h837l-399 1048h-39z" />
-<glyph unicode="&#x220f;" horiz-adv-x="1378" d="M129 1418h996q53 -10 53 -47v-1q-10 -50 -39 -50h-105v-1620h91q53 -11 53 -49q-9 -49 -68 -49h-107l-16 -4l-21 4h-106l-23 -4q-34 0 -45 57v1q0 32 54 44h90v1620h-619v-1620h91q53 -11 53 -49q-8 -49 -68 -49h-107l-16 -4l-21 4h-106l-23 -4q-34 0 -45 57v1 q0 32 54 44h90v1620h-105q-30 0 -39 57q0 29 54 41z" />
-<glyph unicode="&#x2211;" horiz-adv-x="1206" d="M115 1402h847q46 -9 46 -35v-19q0 -34 -48 -42h-736l646 -788l3 -18v-9q0 -18 -155 -193l-483 -591h732q52 -10 52 -39v-22q0 -24 -44 -38l-23 3h-800l-20 -3q-47 12 -47 38v22q0 19 155 194l511 624v22l-676 825l-5 22v8q0 29 45 39z" />
-<glyph unicode="&#x2212;" horiz-adv-x="1092" d="M162 743l14 -1h722l36 4q38 0 50 -58q0 -33 -44 -52l-62 4h-682l-59 -4q-47 17 -47 53q9 53 72 53v1z" />
-<glyph unicode="&#x221a;" horiz-adv-x="1127" d="M910 1553l33 -3h93l31 3q45 -13 45 -47v-7q0 -34 -42 -47l-57 4h-46q-24 0 -716 -1396q-16 -35 -45 -35h-4q-42 0 -83 111q-119 197 -119 224v7q0 32 56 43q32 0 70 -92l57 -105h35q648 1310 661 1325z" />
-<glyph unicode="&#x221e;" horiz-adv-x="1313" d="M385 958q124 0 249 -122q129 122 259 122q196 0 299 -219l12 -98v-2q0 -223 -244 -307l-72 -8q-129 0 -254 121q-122 -121 -255 -121q-208 0 -303 228l-12 93q0 206 228 301zM688 626q0 -131 171 -196h73q112 0 180 148l11 67q0 149 -171 214h-72q-133 0 -192 -182v-51z M144 622q0 -131 171 -196h73q112 0 180 148l11 67q0 149 -171 214h-72q-133 0 -192 -182v-51z" />
-<glyph unicode="&#x221f;" horiz-adv-x="1431" d="M129 1225q48 -12 48 -37v-1070h1063q37 0 44 -50q-13 -43 -44 -43h-1112q-34 0 -44 50v1090q6 60 45 60z" />
-<glyph unicode="&#x2229;" horiz-adv-x="1221" d="M554 1412q275 0 432 -270q46 -108 46 -197v-881q0 -29 -50 -39h2q-49 10 -49 39v798q0 244 -111 332q-108 117 -270 117q-244 0 -351 -241q-30 -50 -30 -208v-794q0 -35 -48 -43q-49 9 -49 47v873q0 235 230 399q127 68 248 68z" />
-<glyph unicode="&#x222b;" horiz-adv-x="920" d="M669 1632h15q118 0 173 -128q-7 -48 -42 -48h-7q-29 0 -58 58q-27 21 -71 30q-109 0 -109 -150l-180 -1483q-64 -127 -174 -127h-18q-125 0 -180 149v-3q10 45 35 45h18q29 0 53 -68q44 -35 78 -35h11q103 0 103 162l176 1468q62 130 177 130z" />
-<glyph unicode="&#x2248;" d="M302 1001h2q48 0 349 -84h31q57 0 125 66l19 5q43 -10 43 -34v-16q0 -42 -122 -96l-71 -11h-6q-46 0 -349 84h-27q-58 0 -120 -62q-14 -10 -26 -10q-45 9 -45 43v12q0 40 141 96zM320 701q38 0 349 -84h35q48 0 127 70l13 2q43 -9 43 -43v-8q0 -44 -134 -100l-55 -7h-26 q-27 0 -337 84h-11q-73 0 -133 -62q-12 -10 -24 -10q-46 9 -46 35v16q0 28 64 63q64 44 135 44z" />
-<glyph unicode="&#x2260;" horiz-adv-x="1028" d="M444 702h-257q-43 0 -51 57q14 49 51 49h257v144q0 30 43 36q43 -6 43 -40v-140h269q39 0 50 -55q-12 -51 -50 -51h-269v-226h263q57 -11 57 -52q-11 -54 -51 -54h-269v-141q-7 -46 -41 -46h-5q-40 6 -40 42v145h-265q-34 0 -43 61q0 32 58 45h250v226z" />
-<glyph unicode="&#x2261;" horiz-adv-x="1161" d="M151 253l14 -1h722l36 4q38 0 50 -58q0 -33 -44 -52l-62 4h-682l-59 -4q-47 17 -47 53q9 53 72 53v1zM156 1032l14 -1h722l36 4q38 0 50 -58q0 -33 -44 -52l-62 4h-682l-59 -4q-47 17 -47 53q9 53 72 53v1zM156 644l14 -1h722l36 4q38 0 50 -58q0 -33 -44 -52l-62 4h-682 l-59 -4q-47 17 -47 53q9 53 72 53v1z" />
-<glyph unicode="&#x2264;" d="M785 1131q54 -11 54 -51v-8q0 -39 -83 -78l-499 -310l571 -363q11 -13 11 -29v-12q0 -39 -57 -47q-22 0 -128 72l-545 342q-12 17 -12 33q0 44 135 110q532 341 544 341h9zM132 131h668q32 0 39 -49v-8q-9 -49 -35 -49h-664q-37 0 -43 54q9 52 35 52z" />
-<glyph unicode="&#x2265;" d="M168 1136q23 0 300 -184q347 -208 377 -238q7 -12 7 -25v-16q0 -29 -107 -82q-551 -349 -558 -349l-26 -4q-51 8 -51 51v4q0 45 123 102l437 276v32q-513 313 -547 344q-13 14 -13 42q0 33 58 47zM145 136h668q31 0 39 -45v-12q-9 -49 -35 -49h-672q-26 0 -35 55 q8 51 35 51z" />
-<glyph unicode="&#xf001;" horiz-adv-x="1021" d="M566 1411q171 0 274 -174l13 -46q0 -33 -53 -44q-35 0 -71 84q-76 79 -168 79q-132 0 -194 -147l-13 -91v-96h189l60 4q27 0 39 -50v-8q0 -27 -46 -39h-242v-774l4 -42q0 -30 -53 -42q-32 0 -48 42l4 42v774h-222q-31 0 -39 56q0 21 40 41l70 -4h147v97q0 230 198 314 q33 17 111 24zM804 1014q53 -11 53 -50v-886q-9 -49 -47 -49h-2q-48 10 -48 39v896q10 50 44 50z" />
-<glyph unicode="&#xfb01;" horiz-adv-x="1021" d="M566 1411q171 0 274 -174l13 -46q0 -33 -53 -44q-35 0 -71 84q-76 79 -168 79q-132 0 -194 -147l-13 -91v-96h189l60 4q27 0 39 -50v-8q0 -27 -46 -39h-242v-774l4 -42q0 -30 -53 -42q-32 0 -48 42l4 42v774h-222q-31 0 -39 56q0 21 40 41l70 -4h147v97q0 230 198 314 q33 17 111 24zM804 1014q53 -11 53 -50v-886q-9 -49 -47 -49h-2q-48 10 -48 39v896q10 50 44 50z" />
-<glyph unicode="&#xf002;" horiz-adv-x="1081" d="M568 1418q173 0 276 -176l14 -35l-4 -40v-1040h104q30 0 40 -50v1q-9 -49 -47 -49h-148q-37 0 -47 53v1103q-41 117 -191 131q-132 0 -196 -147l-13 -92v-96h190l60 4q28 0 39 -50v-9q0 -27 -46 -39h-243v-778l4 -42q0 -30 -54 -42q-32 0 -48 43l4 41v778h-222 q-31 0 -40 57q0 20 41 41l70 -4h147v97q0 231 198 315q35 18 112 25z" />
-<glyph unicode="&#xfb02;" horiz-adv-x="1081" d="M568 1418q173 0 276 -176l14 -35l-4 -40v-1040h104q30 0 40 -50v1q-9 -49 -47 -49h-148q-37 0 -47 53v1103q-41 117 -191 131q-132 0 -196 -147l-13 -92v-96h190l60 4q28 0 39 -50v-9q0 -27 -46 -39h-243v-778l4 -42q0 -30 -54 -42q-32 0 -48 43l4 41v778h-222 q-31 0 -40 57q0 20 41 41l70 -4h147v97q0 231 198 315q35 18 112 25z" />
-<glyph horiz-adv-x="0" />
-</font>
-</defs></svg> 
\ No newline at end of file
diff --git a/hubs/static/css/fonts/Comfortaa_Thin-webfont.ttf b/hubs/static/css/fonts/Comfortaa_Thin-webfont.ttf
deleted file mode 100644
index 8289a85..0000000
Binary files a/hubs/static/css/fonts/Comfortaa_Thin-webfont.ttf and /dev/null differ
diff --git a/hubs/static/css/fonts/Comfortaa_Thin-webfont.woff b/hubs/static/css/fonts/Comfortaa_Thin-webfont.woff
deleted file mode 100644
index 8d75a95..0000000
Binary files a/hubs/static/css/fonts/Comfortaa_Thin-webfont.woff and /dev/null differ

From 426e9f8b0f6fbd3026a9c122ec835f2abe90efa7 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Oct 20 2015 08:14:26 +0000
Subject: [PATCH 222/1001] Defined url_for for easier access of flask.url_for


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index d3ae5b5..5f39e20 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -90,6 +90,7 @@ def get_site_vars():
     return dict(
         session=flask.app.session,
         g=flask.g,
+        url_for=flask.url_for,
     )
 
 

From daea24c3c12b0015417694fa9385e7786a845734 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Oct 20 2015 08:16:18 +0000
Subject: [PATCH 223/1001] Fixed issue #46: Added href tag to view owners hubs page


---

diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index ce50aff..9793207 100644
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -18,7 +18,8 @@ template = jinja2.Template("""
   <div class="row">
     {% for owner in owners %}
         <div class="col-sm-6">
-            <img class="img-circle" src="{{owners[owner]}}"/> {{owner}}
+            <img class="img-circle" src="{{owners[owner]}}"/>
+            <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
         </div>
     {% endfor %}
   </div>

From 1b4bcb71b436ce3477b5045f374a28324c206324 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Oct 25 2015 19:29:14 +0000
Subject: [PATCH 224/1001] Fixed issue #49: Updated the bodhiurl responsible for the bug


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 49b54e2..ea0a996 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -48,10 +48,9 @@ giveaway = 'can be pushed to stable now'
 def data(session, widget, username):
 
     # First, get all of my updates currently in testing.
-    bodhiurl = 'https://admin.fedoraproject.org/updates/'
-    baseurl = bodhiurl + 'list'
+    bodhiurl = 'https://bodhi.fedoraproject.org/updates/'
     query = '?username={username}&status=testing'.format(username=username)
-    url = baseurl + query
+    url = bodhiurl + query
     headers = {'Accept': 'application/json'}
     response = requests.get(url, headers=headers)
     data = response.json()

From 4c953064352d426a747e16730d41b2ac860608ba Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Oct 28 2015 21:05:36 +0000
Subject: [PATCH 225/1001] Added the parse_nvr function to extract the package name


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index ea0a996..7140fda 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -35,7 +35,7 @@ template = jinja2.Template("""
 
 from hubs.widgets.chrome import panel
 # If 'updates' is empty, then don't render any chrome.
-chrome = panel('Updates Ready for Stable', key='updates')
+chrome = panel('Updates Ready for Stable') #, key='updates')
 
 
 giveaway = 'can be pushed to stable now'
@@ -49,10 +49,11 @@ def data(session, widget, username):
 
     # First, get all of my updates currently in testing.
     bodhiurl = 'https://bodhi.fedoraproject.org/updates/'
-    query = '?username={username}&status=testing'.format(username=username)
+    query = '?user={username}&status=testing'.format(username=username)
     url = bodhiurl + query
     headers = {'Accept': 'application/json'}
     response = requests.get(url, headers=headers)
+    print response
     data = response.json()
 
     # Limit it this to only the updates that haven't already requested stable
@@ -66,13 +67,20 @@ def data(session, widget, username):
     # Stuff some useful information in there.
     baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
     for update in data['updates']:
-        package = update['builds'][0]['package']['name']
-        update['icon'] = baseurl + package + '.png'
+        nvr = update['builds'][0]
+        package = parse_nvr(nvr)
+        update['icon'] = baseurl + package[0] + '.png'
         update['link'] = bodhiurl + update['title']
 
     return data
 
 
+def parse_nvr(nvr):
+    # Return the [ name, version, release ] of a given name-ver-rel.
+    x = nvr.items()[0][1].split('-')
+    return ['-'.join(x[:-2]), x[-2], x[-1]]
+
+
 @hint(topics=[_('bodhi.update.comment')])
 def should_invalidate(message, session, widget):
     if giveaway in message['msg']['comment']['text']:

From 1fcc95464d0e91e80f5035c91c5388209224264c Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Oct 29 2015 11:16:38 +0000
Subject: [PATCH 226/1001] Removed few testing edits


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 7140fda..836b6ce 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -35,7 +35,7 @@ template = jinja2.Template("""
 
 from hubs.widgets.chrome import panel
 # If 'updates' is empty, then don't render any chrome.
-chrome = panel('Updates Ready for Stable') #, key='updates')
+chrome = panel('Updates Ready for Stable', key='updates')
 
 
 giveaway = 'can be pushed to stable now'
@@ -53,7 +53,6 @@ def data(session, widget, username):
     url = bodhiurl + query
     headers = {'Accept': 'application/json'}
     response = requests.get(url, headers=headers)
-    print response
     data = response.json()
 
     # Limit it this to only the updates that haven't already requested stable

From 26fd97a8aa754876ee2190a1afc51ba170753e16 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Oct 29 2015 12:04:53 +0000
Subject: [PATCH 227/1001] Edited the parse_nvr() function for a dict with more than one value


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 836b6ce..1a27be6 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -66,7 +66,8 @@ def data(session, widget, username):
     # Stuff some useful information in there.
     baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
     for update in data['updates']:
-        nvr = update['builds'][0]
+        build = update['builds'][0]
+        nvr = build['nvr']
         package = parse_nvr(nvr)
         update['icon'] = baseurl + package[0] + '.png'
         update['link'] = bodhiurl + update['title']
@@ -76,7 +77,7 @@ def data(session, widget, username):
 
 def parse_nvr(nvr):
     # Return the [ name, version, release ] of a given name-ver-rel.
-    x = nvr.items()[0][1].split('-')
+    x = nvr.split('-')
     return ['-'.join(x[:-2]), x[-2], x[-1]]
 
 

From b9d93906f27ceb17d278e758554afc243502364d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Oct 30 2015 18:34:25 +0000
Subject: [PATCH 228/1001] Add a requirement on pytz.


---

diff --git a/requirements.txt b/requirements.txt
index 5585e6c..844a2ec 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,3 +11,4 @@ fmn.rules
 datanommer.models
 psycopg2
 gunicorn
+pytz

From a93a640a44d411c649967c7d2b72239f95e3bb3d Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Nov 03 2015 17:05:05 +0000
Subject: [PATCH 229/1001] Fixed issue #53: Edited 'subscribes to' into clickable links


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 4b0df3a..36e830d 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -18,7 +18,11 @@ template = jinja2.Template("""
     {% endif %}
     <hr/>
     {% if subscriptions %}
-        <p><strong>Subscribes to:</strong> {{subscriptions_text}}</p>
+        <p><strong>Subscribes to:</strong>
+        {% for subscription in subscriptions %}
+        <a href="{{ url_for('hub', name=subscription)}}">
+        {{subscription}}</a>
+        {% endfor %}</p>
     {% endif %}
 {% endif %}
 """)

From 8cbbdbb84d071835e4660442b95c8ec55c0ed7a2 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Nov 03 2015 17:05:05 +0000
Subject: [PATCH 230/1001] Merge #51 `Fixed issue #49: Updated the bodhiurl responsible for the bug`


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 4b0df3a..36e830d 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -18,7 +18,11 @@ template = jinja2.Template("""
     {% endif %}
     <hr/>
     {% if subscriptions %}
-        <p><strong>Subscribes to:</strong> {{subscriptions_text}}</p>
+        <p><strong>Subscribes to:</strong>
+        {% for subscription in subscriptions %}
+        <a href="{{ url_for('hub', name=subscription)}}">
+        {{subscription}}</a>
+        {% endfor %}</p>
     {% endif %}
 {% endif %}
 """)
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 49b54e2..1a27be6 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -48,10 +48,9 @@ giveaway = 'can be pushed to stable now'
 def data(session, widget, username):
 
     # First, get all of my updates currently in testing.
-    bodhiurl = 'https://admin.fedoraproject.org/updates/'
-    baseurl = bodhiurl + 'list'
-    query = '?username={username}&status=testing'.format(username=username)
-    url = baseurl + query
+    bodhiurl = 'https://bodhi.fedoraproject.org/updates/'
+    query = '?user={username}&status=testing'.format(username=username)
+    url = bodhiurl + query
     headers = {'Accept': 'application/json'}
     response = requests.get(url, headers=headers)
     data = response.json()
@@ -67,13 +66,21 @@ def data(session, widget, username):
     # Stuff some useful information in there.
     baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
     for update in data['updates']:
-        package = update['builds'][0]['package']['name']
-        update['icon'] = baseurl + package + '.png'
+        build = update['builds'][0]
+        nvr = build['nvr']
+        package = parse_nvr(nvr)
+        update['icon'] = baseurl + package[0] + '.png'
         update['link'] = bodhiurl + update['title']
 
     return data
 
 
+def parse_nvr(nvr):
+    # Return the [ name, version, release ] of a given name-ver-rel.
+    x = nvr.split('-')
+    return ['-'.join(x[:-2]), x[-2], x[-1]]
+
+
 @hint(topics=[_('bodhi.update.comment')])
 def should_invalidate(message, session, widget):
     if giveaway in message['msg']['comment']['text']:

From ee18daa8fa38eef8ba61ca557bb90ae944ccb5e2 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Nov 04 2015 13:10:06 +0000
Subject: [PATCH 231/1001] Fixed issue #53: Added clickable links for subscribed hubs


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 4b0df3a..36e830d 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -18,7 +18,11 @@ template = jinja2.Template("""
     {% endif %}
     <hr/>
     {% if subscriptions %}
-        <p><strong>Subscribes to:</strong> {{subscriptions_text}}</p>
+        <p><strong>Subscribes to:</strong>
+        {% for subscription in subscriptions %}
+        <a href="{{ url_for('hub', name=subscription)}}">
+        {{subscription}}</a>
+        {% endfor %}</p>
     {% endif %}
 {% endif %}
 """)

From 2b6acc854a6a0bfe3ae298b2476df86162fe8bb3 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Nov 05 2015 19:23:11 +0000
Subject: [PATCH 232/1001] Added manage_subscriptions() to hyperlink subscriptions and memberships


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 36e830d..d32e47b 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -8,21 +8,20 @@ import hubs.models
 
 from fedmsg.meta.base import BaseConglomerator as BC
 
+import flask
 import jinja2
 
 chrome = panel('Hubs', key='associations')
 template = jinja2.Template("""
 {% if associations %}
     {% if memberships %}
-        <p><strong>Belongs to: </strong>{{memberships_text}}</p>
+        <p><strong>Belongs to: </strong>
+        {{memberships_text}}</p>
     {% endif %}
     <hr/>
     {% if subscriptions %}
         <p><strong>Subscribes to:</strong>
-        {% for subscription in subscriptions %}
-        <a href="{{ url_for('hub', name=subscription)}}">
-        {{subscription}}</a>
-        {% endfor %}</p>
+        {{subscriptions_text}}</p>
     {% endif %}
 {% endif %}
 """)
@@ -37,16 +36,29 @@ def data(session, widget, username):
     ownerships = [u.name for u in user.ownerships]
     memberships = [u.name for u in user.memberships]
     subscriptions = [u.name for u in user.subscriptions]
+    subs = subscriptions
+    mems = memberships
+    subscriptions_list = manage_subscriptions(subs)
+    memberships_list = manage_subscriptions(mems)
     return dict(
         associations=memberships + ownerships,
         ownerships=ownerships,
         memberships=memberships,
         subscriptions=subscriptions,
         ownerships_text=BC.list_to_series(ownerships),
-        memberships_text=BC.list_to_series(memberships),
-        subscriptions_text=BC.list_to_series(subscriptions),
+        memberships_text=BC.list_to_series(memberships_list),
+        subscriptions_text=BC.list_to_series(subscriptions_list),
     )
 
 
+# function hyperlinks
+def manage_subscriptions(s):
+    for j, i in enumerate(s[0:3]):
+        link = '<a href="{link}">{item}</a>'.format(link=flask.url_for(
+            'hub', name=i), item=i)
+        s[j] = link
+    return s
+
+
 def should_invalidate(message, session, widget):
     raise NotImplementedError()

From 6811d345beaea95c65b010186cc5288220ae198a Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Nov 05 2015 19:55:17 +0000
Subject: [PATCH 233/1001] Edited comments


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index d32e47b..25c670b 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -1,4 +1,4 @@
-#from hubs.hinting import hint, prefixed as _
+# from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
 
@@ -51,7 +51,7 @@ def data(session, widget, username):
     )
 
 
-# function hyperlinks
+# function hyperlinks the hubs in the subscription widget
 def manage_subscriptions(s):
     for j, i in enumerate(s[0:3]):
         link = '<a href="{link}">{item}</a>'.format(link=flask.url_for(

From f36cd76b3c8c8b019df373ed432285c027dfa674 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Nov 06 2015 20:46:30 +0000
Subject: [PATCH 234/1001] Added generator to avoid changes in json data


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 25c670b..aa9d394 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -15,13 +15,11 @@ chrome = panel('Hubs', key='associations')
 template = jinja2.Template("""
 {% if associations %}
     {% if memberships %}
-        <p><strong>Belongs to: </strong>
-        {{memberships_text}}</p>
+        <p><strong>Belongs to: </strong>{{memberships_text}}</p>
     {% endif %}
     <hr/>
     {% if subscriptions %}
-        <p><strong>Subscribes to:</strong>
-        {{subscriptions_text}}</p>
+        <p><strong>Subscribes to:</strong>{{subscriptions_text}}</p>
     {% endif %}
 {% endif %}
 """)
@@ -36,10 +34,8 @@ def data(session, widget, username):
     ownerships = [u.name for u in user.ownerships]
     memberships = [u.name for u in user.memberships]
     subscriptions = [u.name for u in user.subscriptions]
-    subs = subscriptions
-    mems = memberships
-    subscriptions_list = manage_subscriptions(subs)
-    memberships_list = manage_subscriptions(mems)
+    subscriptions_list = manage_subscriptions(subscriptions)
+    memberships_list = manage_subscriptions(memberships)
     return dict(
         associations=memberships + ownerships,
         ownerships=ownerships,
@@ -52,12 +48,11 @@ def data(session, widget, username):
 
 
 # function hyperlinks the hubs in the subscription widget
-def manage_subscriptions(s):
-    for j, i in enumerate(s[0:3]):
+def manage_subscriptions(items):
+    for index, item in enumerate(items[0:3]):
         link = '<a href="{link}">{item}</a>'.format(link=flask.url_for(
-            'hub', name=i), item=i)
-        s[j] = link
-    return s
+            'hub', name=item), item=item)
+        yield link
 
 
 def should_invalidate(message, session, widget):

From 46e0cbf917a3f9641dcd00fbce613a4902acba1f Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Nov 06 2015 21:02:44 +0000
Subject: [PATCH 235/1001] Edited typo


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index aa9d394..f5e51f1 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -15,11 +15,11 @@ chrome = panel('Hubs', key='associations')
 template = jinja2.Template("""
 {% if associations %}
     {% if memberships %}
-        <p><strong>Belongs to: </strong>{{memberships_text}}</p>
+        <p><strong>Belongs to: </strong> {{memberships_text}}</p>
     {% endif %}
     <hr/>
     {% if subscriptions %}
-        <p><strong>Subscribes to:</strong>{{subscriptions_text}}</p>
+        <p><strong>Subscribes to:</strong> {{subscriptions_text}}</p>
     {% endif %}
 {% endif %}
 """)

From 23497dc6be5af13cfbcb54b1e41c4c3282fe3f67 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Nov 06 2015 21:02:44 +0000
Subject: [PATCH 236/1001] Merge #54 `Fixed issue #53: Added clickable links for subscribed hubs`


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 36e830d..db23691 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -1,4 +1,4 @@
-#from hubs.hinting import hint, prefixed as _
+# from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
 
@@ -8,13 +8,14 @@ import hubs.models
 
 from fedmsg.meta.base import BaseConglomerator as BC
 
+import flask
 import jinja2
 
 chrome = panel('Hubs', key='associations')
 template = jinja2.Template("""
 {% if associations %}
     {% if memberships %}
-        <p><strong>Belongs to: </strong>{{memberships_text}}</p>
+        <p><strong>Belongs to: </strong> {{memberships_text}}</p>
     {% endif %}
     <hr/>
     {% if subscriptions %}
@@ -37,16 +38,26 @@ def data(session, widget, username):
     ownerships = [u.name for u in user.ownerships]
     memberships = [u.name for u in user.memberships]
     subscriptions = [u.name for u in user.subscriptions]
+    subscriptions_list = manage_subscriptions(subscriptions)
+    memberships_list = manage_subscriptions(memberships)
     return dict(
         associations=memberships + ownerships,
         ownerships=ownerships,
         memberships=memberships,
         subscriptions=subscriptions,
         ownerships_text=BC.list_to_series(ownerships),
-        memberships_text=BC.list_to_series(memberships),
-        subscriptions_text=BC.list_to_series(subscriptions),
+        memberships_text=BC.list_to_series(memberships_list),
+        subscriptions_text=BC.list_to_series(subscriptions_list),
     )
 
 
+# function hyperlinks the hubs in the subscription widget
+def manage_subscriptions(items):
+    for index, item in enumerate(items[0:3]):
+        link = '<a href="{link}">{item}</a>'.format(link=flask.url_for(
+            'hub', name=item), item=item)
+        yield link
+
+
 def should_invalidate(message, session, widget):
     raise NotImplementedError()

From aae7e26f50cb64cceafa1b5ac1a835ebbdf52ad1 Mon Sep 17 00:00:00 2001
From: Dhriti Shikhar <dhrish20@gmail.com>
Date: Nov 17 2015 05:36:17 +0000
Subject: [PATCH 237/1001] Adds a pagure pull requests widget


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index ce29c74..56a93c1 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -53,4 +53,11 @@ def add_user_widgets(session, hub, username, fullname):
             'username': username,
         }))
     hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='pagure_pr', index=5, 
+        _config=json.dumps({
+            'repo': 'pagure',
+        }))
+    hub.widgets.append(widget)
+
     return hub
diff --git a/hubs/validators.py b/hubs/validators.py
index 5bdf053..8248b29 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -22,3 +22,6 @@ def fmn_context(session, value):
     return value in [
         'irc', 'email', 'android', 'desktop', 'hubs',
     ]
+
+def repo(session, value):
+    return value
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index d3ae5b5..9865be6 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -11,6 +11,7 @@ from hubs.widgets import feed
 from hubs.widgets import subscriptions
 from hubs.widgets import cobwebs
 from hubs.widgets import meetings
+from hubs.widgets import pagure_pr
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -31,6 +32,7 @@ registry = {
     'subscriptions': subscriptions,
     'cobwebs': cobwebs,
     'meetings': meetings,
+    'pagure_pr': pagure_pr,    
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
new file mode 100644
index 0000000..f00ffd2
--- /dev/null
+++ b/hubs/widgets/pagure_pr.py
@@ -0,0 +1,80 @@
+from hubs.hinting import hint
+from hubs.widgets.chrome import panel
+import jinja2
+import requests
+from hubs.widgets.base import argument
+import hubs.validators as validators
+chrome = panel("Pagure: Newest Open Pull Requests")
+
+pagure_url = "https://pagure.io/api/0"
+
+template = jinja2.Template("""
+  <br />
+    <div class="container">
+      {% for i in range(0,total_req) %}
+        <div>
+          <table class="table-responsive table-condensed">
+            <tr>
+              <td valign="top" class="panel-heading">
+                <b>#{{ all_pr[i]['pr_id'] }}</b>
+              </td>
+              <td width="260px">
+                <b>{{ all_pr[i]['pr_title'] }} ...</b>
+              </td>
+            </tr>
+           </table>
+         <table class="table-responsive table-condensed">
+            <tr>
+              <td width="280px" >
+                <font size="2">
+                  <i>Opened by <a href="https://pagure.io/user/{{ all_pr[i]['pr_openedby'] }}" target="_blank">{{ all_pr[i]['pr_openedby'] }}</a>
+                  {% if all_pr[i]['pr_assignee'] %}
+                    <br>Assigned to <a href="https://pagure.io/user/{{ all_pr[i]['pr_assignee'] }}" target="_blank">{{ all_pr[i]['pr_assignee'] }}</a></i>
+                  {% endif %}
+                </font>
+              </td>
+              <td>
+                <a href="https://pagure.io/{{ repo }}/pull-request/{{ all_pr[i]['pr_id'] }}" target="_blank">
+                  <button type="button" class="btn btn-default" aria-label="Left Align">
+                    <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+                  </button>
+                </a>
+              </td>
+            </tr>
+          </table>
+        </div>
+      {%endfor%}
+    <br />
+    </div class="row">
+      <center><a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">All Pull-Requests</a><center>
+    </div>
+  </div>
+""")
+
+@argument(name="repo",
+          default=None,
+          validator=validators.repo,
+          help="Repo")
+def data(session, widget, repo):
+    repo="pagure"
+    url = '/'.join([pagure_url, repo, "pull-requests"])
+    response = requests.get(url)
+    data = response.json()
+    total_req = data['total_requests']
+    all_pr = list()
+    for i in range(0,total_req):
+      all_pr.append(dict(
+      pr_id=data['requests'][i]['id'],
+      pr_title=data['requests'][i]['title'][:45],
+      pr_openedby=data['requests'][i]['user']['name'],
+      pr_assignee=data['requests'][i]['assignee'],
+    ))
+    all_pr.reverse() 
+    return dict(all_pr=all_pr,
+    total_req=total_req,
+    repo=repo,		
+)
+
+@hint()
+def should_invalidate(message, session, widget):
+   raise NotImplementedError

From ffa3ecd8c3949bacfab2ccb646a803da0afb0b6f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Nov 17 2015 13:52:12 +0000
Subject: [PATCH 238/1001] Merge #56 `Adds a pagure pull requests widget`


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index ce29c74..56a93c1 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -53,4 +53,11 @@ def add_user_widgets(session, hub, username, fullname):
             'username': username,
         }))
     hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='pagure_pr', index=5, 
+        _config=json.dumps({
+            'repo': 'pagure',
+        }))
+    hub.widgets.append(widget)
+
     return hub
diff --git a/hubs/validators.py b/hubs/validators.py
index 5bdf053..8248b29 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -22,3 +22,6 @@ def fmn_context(session, value):
     return value in [
         'irc', 'email', 'android', 'desktop', 'hubs',
     ]
+
+def repo(session, value):
+    return value
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 5f39e20..416f7d6 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -11,6 +11,7 @@ from hubs.widgets import feed
 from hubs.widgets import subscriptions
 from hubs.widgets import cobwebs
 from hubs.widgets import meetings
+from hubs.widgets import pagure_pr
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -31,6 +32,7 @@ registry = {
     'subscriptions': subscriptions,
     'cobwebs': cobwebs,
     'meetings': meetings,
+    'pagure_pr': pagure_pr,    
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
new file mode 100644
index 0000000..f00ffd2
--- /dev/null
+++ b/hubs/widgets/pagure_pr.py
@@ -0,0 +1,80 @@
+from hubs.hinting import hint
+from hubs.widgets.chrome import panel
+import jinja2
+import requests
+from hubs.widgets.base import argument
+import hubs.validators as validators
+chrome = panel("Pagure: Newest Open Pull Requests")
+
+pagure_url = "https://pagure.io/api/0"
+
+template = jinja2.Template("""
+  <br />
+    <div class="container">
+      {% for i in range(0,total_req) %}
+        <div>
+          <table class="table-responsive table-condensed">
+            <tr>
+              <td valign="top" class="panel-heading">
+                <b>#{{ all_pr[i]['pr_id'] }}</b>
+              </td>
+              <td width="260px">
+                <b>{{ all_pr[i]['pr_title'] }} ...</b>
+              </td>
+            </tr>
+           </table>
+         <table class="table-responsive table-condensed">
+            <tr>
+              <td width="280px" >
+                <font size="2">
+                  <i>Opened by <a href="https://pagure.io/user/{{ all_pr[i]['pr_openedby'] }}" target="_blank">{{ all_pr[i]['pr_openedby'] }}</a>
+                  {% if all_pr[i]['pr_assignee'] %}
+                    <br>Assigned to <a href="https://pagure.io/user/{{ all_pr[i]['pr_assignee'] }}" target="_blank">{{ all_pr[i]['pr_assignee'] }}</a></i>
+                  {% endif %}
+                </font>
+              </td>
+              <td>
+                <a href="https://pagure.io/{{ repo }}/pull-request/{{ all_pr[i]['pr_id'] }}" target="_blank">
+                  <button type="button" class="btn btn-default" aria-label="Left Align">
+                    <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+                  </button>
+                </a>
+              </td>
+            </tr>
+          </table>
+        </div>
+      {%endfor%}
+    <br />
+    </div class="row">
+      <center><a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">All Pull-Requests</a><center>
+    </div>
+  </div>
+""")
+
+@argument(name="repo",
+          default=None,
+          validator=validators.repo,
+          help="Repo")
+def data(session, widget, repo):
+    repo="pagure"
+    url = '/'.join([pagure_url, repo, "pull-requests"])
+    response = requests.get(url)
+    data = response.json()
+    total_req = data['total_requests']
+    all_pr = list()
+    for i in range(0,total_req):
+      all_pr.append(dict(
+      pr_id=data['requests'][i]['id'],
+      pr_title=data['requests'][i]['title'][:45],
+      pr_openedby=data['requests'][i]['user']['name'],
+      pr_assignee=data['requests'][i]['assignee'],
+    ))
+    all_pr.reverse() 
+    return dict(all_pr=all_pr,
+    total_req=total_req,
+    repo=repo,		
+)
+
+@hint()
+def should_invalidate(message, session, widget):
+   raise NotImplementedError

From b95aee4d3c6688ac28bc6aa43c70b68ade5eab6b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Dec 14 2015 18:24:24 +0000
Subject: [PATCH 239/1001] Mark up feed entries with links to other hub users.


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index d3d0b4b..058c280 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -13,6 +13,8 @@ import jinja2
 import munch
 import requests
 
+import flask
+
 import hubs.validators as validators
 
 import datetime
@@ -39,7 +41,7 @@ template = jinja2.Template("""
         </a>
       </div>
       <div class="media-body">
-        <h4 class="media-heading">{{match['subtitle']}}</h4>
+        <h4 class="media-heading">{{match['markup']}}</h4>
         {{match['human_time']}}
       </div>
     </div>
@@ -106,6 +108,23 @@ def data(session, widget, username, fmn_context):
     # Smash multiple messages into single ones
     matches = fedmsg.meta.conglomerate(matches, **config)
 
+    # Apply some html markup to the subtitles for extra fanciness.
+    for match in matches:
+        match['markup'] = match['subtitle']
+        for username in match['usernames']:
+            match['markup'] = match['markup'].replace(
+                username, '<a href="{url}">@{username}</a>'.format(
+                    url=flask.url_for('hub', name=username),
+                    username=username,
+                ))
+        for package in match['packages']:
+            match['markup'] = match['markup'].replace(
+                package, '<a href="{url}">{package}</a>'.format(
+                    url='https://apps.fedoraproject.org/packages/' + package,
+                    package=package,
+                ))
+
+
     return dict(
         matches=matches,
     )

From 00d2f30b456b0d294898d10ead785459682c30f6 Mon Sep 17 00:00:00 2001
From: Shalini Roy <shaliniroy012@gmail.com>
Date: Jan 12 2016 21:08:49 +0000
Subject: [PATCH 240/1001] Handling response code while fetching widget from feed.py


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 058c280..b80775d 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -69,39 +69,42 @@ def data(session, widget, username, fmn_context):
     log.info("Getting FMN preferences from %s" % url)
     print(url)
     response = requests.get(url)
-    preference = response.json()
-    preference = rehydrate_preferences(preference)
-
-    # The smaller we make this, the faster it is.
-    delta = datetime.timedelta(days=365)
-    end = datetime.datetime.utcnow()
-
-    # We currently only support getting the first page.
-    # The widget framework as currently written doesn't support
-    # multiple pages yet.
-    page = 1
-
     messages = []
-    for filter in preference['filters']:
-        rules = filter['rules']
-        fmn_hinting = fmn.lib.hinting.gather_hinting(config, rules, paths)
-        total, pages, rows = datanommer.models.Message.grep(
-            start=end-delta,
-            end=end,
-            rows_per_page=bazillion,
-            page=page,
-            order='desc',
-            **fmn_hinting
-        )
-        messages.extend(rows)
-
     matches = []
-    for message in messages:
-        original = message.__json__()
-        recipients = fmn.lib.recipients(
-            [preference], message.__json__(), paths, config)
-        if recipients:
-            matches.append(original)
+    if response.status_code == 200:
+        preference = response.json()
+        preference = rehydrate_preferences(preference)
+
+        # The smaller we make this, the faster it is.
+        delta = datetime.timedelta(days=365)
+        end = datetime.datetime.utcnow()
+
+        # We currently only support getting the first page.
+        # The widget framework as currently written doesn't support
+        # multiple pages yet.
+        page = 1
+
+        for filter in preference['filters']:
+            rules = filter['rules']
+            fmn_hinting = fmn.lib.hinting.gather_hinting(config, rules, paths)
+            total, pages, rows = datanommer.models.Message.grep(
+                start=end-delta,
+                end=end,
+                rows_per_page=bazillion,
+                page=page,
+                order='desc',
+                **fmn_hinting
+            )
+            messages.extend(rows)
+
+        for message in messages:
+            original = message.__json__()
+            recipients = fmn.lib.recipients(
+                [preference], message.__json__(), paths, config)
+            if recipients:
+                matches.append(original)
+    else:
+        print("You don't have any preferences")
 
     # TODO - sort messages and remove duplicates
 

From 103b6f7def0015082716cf7a87fd53c7bafce43b Mon Sep 17 00:00:00 2001
From: Shalini Roy <shaliniroy012@gmail.com>
Date: Jan 12 2016 21:27:13 +0000
Subject: [PATCH 241/1001] Changed print to log.warn


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index b80775d..77a57ab 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -104,7 +104,7 @@ def data(session, widget, username, fmn_context):
             if recipients:
                 matches.append(original)
     else:
-        print("You don't have any preferences")
+        log.warn("You don't have any preferences. \n Url=%s" % url)
 
     # TODO - sort messages and remove duplicates
 

From 1a3150b1430a775848b8e74acd829cd7e4f7fddd Mon Sep 17 00:00:00 2001
From: Shalini Roy <shaliniroy012@gmail.com>
Date: Jan 12 2016 21:43:39 +0000
Subject: [PATCH 242/1001] Handling response in data method in updates2stable


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 1a27be6..0ee6c90 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -53,26 +53,30 @@ def data(session, widget, username):
     url = bodhiurl + query
     headers = {'Accept': 'application/json'}
     response = requests.get(url, headers=headers)
-    data = response.json()
-
-    # Limit it this to only the updates that haven't already requested stable
-    # but which can actually be pushed to stable now.
-    data['updates'] = [
-        update for update in data['updates']
-        if update['request'] is None and
-        any([giveaway in comment['text'] for comment in update['comments']])
-    ]
-
-    # Stuff some useful information in there.
-    baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
-    for update in data['updates']:
-        build = update['builds'][0]
-        nvr = build['nvr']
-        package = parse_nvr(nvr)
-        update['icon'] = baseurl + package[0] + '.png'
-        update['link'] = bodhiurl + update['title']
-
-    return data
+    if response.status_code == 200:
+        data = response.json()
+
+        # Limit it this to only the updates that haven't already requested stable
+        # but which can actually be pushed to stable now.
+        data['updates'] = [
+            update for update in data['updates']
+            if update['request'] is None and
+            any([giveaway in comment['text'] for comment in update['comments']])
+        ]
+
+        # Stuff some useful information in there.
+        baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
+        for update in data['updates']:
+            build = update['builds'][0]
+            nvr = build['nvr']
+            package = parse_nvr(nvr)
+            update['icon'] = baseurl + package[0] + '.png'
+            update['link'] = bodhiurl + update['title']
+
+        return data
+    else:
+        data = {}
+        return data
 
 
 def parse_nvr(nvr):

From 9dfc2a77018073ee69ffcd423ac881248ee745ca Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 13 2016 14:58:33 +0000
Subject: [PATCH 243/1001] Merge #69 `Handling response in data method in updates2stable`


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 1a27be6..0ee6c90 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -53,26 +53,30 @@ def data(session, widget, username):
     url = bodhiurl + query
     headers = {'Accept': 'application/json'}
     response = requests.get(url, headers=headers)
-    data = response.json()
-
-    # Limit it this to only the updates that haven't already requested stable
-    # but which can actually be pushed to stable now.
-    data['updates'] = [
-        update for update in data['updates']
-        if update['request'] is None and
-        any([giveaway in comment['text'] for comment in update['comments']])
-    ]
-
-    # Stuff some useful information in there.
-    baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
-    for update in data['updates']:
-        build = update['builds'][0]
-        nvr = build['nvr']
-        package = parse_nvr(nvr)
-        update['icon'] = baseurl + package[0] + '.png'
-        update['link'] = bodhiurl + update['title']
-
-    return data
+    if response.status_code == 200:
+        data = response.json()
+
+        # Limit it this to only the updates that haven't already requested stable
+        # but which can actually be pushed to stable now.
+        data['updates'] = [
+            update for update in data['updates']
+            if update['request'] is None and
+            any([giveaway in comment['text'] for comment in update['comments']])
+        ]
+
+        # Stuff some useful information in there.
+        baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
+        for update in data['updates']:
+            build = update['builds'][0]
+            nvr = build['nvr']
+            package = parse_nvr(nvr)
+            update['icon'] = baseurl + package[0] + '.png'
+            update['link'] = bodhiurl + update['title']
+
+        return data
+    else:
+        data = {}
+        return data
 
 
 def parse_nvr(nvr):

From fc3fa854cb92803f149eef58166f6acacc1ac099 Mon Sep 17 00:00:00 2001
From: Shalini Roy <shaliniroy012@gmail.com>
Date: Jan 13 2016 17:42:31 +0000
Subject: [PATCH 244/1001] Fixed typo


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 0ee6c90..8b0d802 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -56,7 +56,7 @@ def data(session, widget, username):
     if response.status_code == 200:
         data = response.json()
 
-        # Limit it this to only the updates that haven't already requested stable
+        # Limit this to only the updates that haven't already requested stable
         # but which can actually be pushed to stable now.
         data['updates'] = [
             update for update in data['updates']

From ca6927aadf2701e612395dd16be0fd3c8a720f54 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 13 2016 18:03:45 +0000
Subject: [PATCH 245/1001] Merge #70 `Fixed typo`


---

diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 0ee6c90..8b0d802 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -56,7 +56,7 @@ def data(session, widget, username):
     if response.status_code == 200:
         data = response.json()
 
-        # Limit it this to only the updates that haven't already requested stable
+        # Limit this to only the updates that haven't already requested stable
         # but which can actually be pushed to stable now.
         data['updates'] = [
             update for update in data['updates']

From 8cce3561d0fa8613d594a98fe0056c793eb1e35a Mon Sep 17 00:00:00 2001
From: Shalini Roy <shaliniroy012@gmail.com>
Date: Jan 13 2016 18:17:28 +0000
Subject: [PATCH 246/1001] Changed generator implementation to list in manage_subscription method


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index db23691..d1b59cf 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -53,10 +53,9 @@ def data(session, widget, username):
 
 # function hyperlinks the hubs in the subscription widget
 def manage_subscriptions(items):
-    for index, item in enumerate(items[0:3]):
-        link = '<a href="{link}">{item}</a>'.format(link=flask.url_for(
-            'hub', name=item), item=item)
-        yield link
+    return ['<a href="{link}">{item}</a>'.format(link=flask.url_for('hub',
+            name=item), item=item) for index, item
+            in enumerate(items[0:3])]
 
 
 def should_invalidate(message, session, widget):

From 64c07cdfc4a8c1a7d7f8f460331c597d52b3fda2 Mon Sep 17 00:00:00 2001
From: Shalini Roy <shaliniroy012@gmail.com>
Date: Jan 13 2016 18:36:25 +0000
Subject: [PATCH 247/1001] Splited into multiple lines for better readability


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index d1b59cf..395ee0c 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -53,9 +53,12 @@ def data(session, widget, username):
 
 # function hyperlinks the hubs in the subscription widget
 def manage_subscriptions(items):
-    return ['<a href="{link}">{item}</a>'.format(link=flask.url_for('hub',
-            name=item), item=item) for index, item
-            in enumerate(items[0:3])]
+    return [
+        '<a href="{link}">{item}</a>'.format(
+            link=flask.url_for('hub', name=item),
+            item=item,
+        ) for index, item in enumerate(items[0:3])
+    ]
 
 
 def should_invalidate(message, session, widget):

From 68c4ea2d019f9b8af47926a67bed247ba22c8644 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 13 2016 19:18:51 +0000
Subject: [PATCH 248/1001] Merge #71 `Changed generator implementation to list in manage_subscription method`


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index db23691..395ee0c 100644
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -53,10 +53,12 @@ def data(session, widget, username):
 
 # function hyperlinks the hubs in the subscription widget
 def manage_subscriptions(items):
-    for index, item in enumerate(items[0:3]):
-        link = '<a href="{link}">{item}</a>'.format(link=flask.url_for(
-            'hub', name=item), item=item)
-        yield link
+    return [
+        '<a href="{link}">{item}</a>'.format(
+            link=flask.url_for('hub', name=item),
+            item=item,
+        ) for index, item in enumerate(items[0:3])
+    ]
 
 
 def should_invalidate(message, session, widget):

From e10608c4354e189e089af0b238a4a062f87fde1c Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 14:29:46 +0000
Subject: [PATCH 249/1001] Also, in long_form.


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 77a57ab..68af7eb 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -115,17 +115,20 @@ def data(session, widget, username, fmn_context):
     for match in matches:
         match['markup'] = match['subtitle']
         for username in match['usernames']:
-            match['markup'] = match['markup'].replace(
-                username, '<a href="{url}">@{username}</a>'.format(
-                    url=flask.url_for('hub', name=username),
-                    username=username,
-                ))
+            args = (username, '<a href="{url}">@{username}</a>'.format(
+                url=flask.url_for('hub', name=username),
+                username=username,
+            ))
+            match['markup'] = match['markup'].replace(*args)
+            match['long_form'] = match['long_form'].replace(*args)
+
         for package in match['packages']:
-            match['markup'] = match['markup'].replace(
-                package, '<a href="{url}">{package}</a>'.format(
-                    url='https://apps.fedoraproject.org/packages/' + package,
-                    package=package,
-                ))
+            args = (package, '<a href="{url}">{package}</a>'.format(
+                url='https://apps.fedoraproject.org/packages/' + package,
+                package=package,
+            ))
+            match['markup'] = match['markup'].replace(*args)
+            match['long_form'] = match['long_form'].replace(*args)
 
 
     return dict(

From 3d86b68b89438b1230c4b531aabb44221ccc6726 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 16:00:40 +0000
Subject: [PATCH 250/1001] A first test for the test suite.


---

diff --git a/.gitignore b/.gitignore
index 0e32795..80d44bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ fedmsg.d/fas_credentials.py
 node*
 build/
 scratch/
+hubs/tests/vcr-request-data
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/tests/__init__.py
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
new file mode 100644
index 0000000..dcf90f9
--- /dev/null
+++ b/hubs/tests/test_widgets/__init__.py
@@ -0,0 +1,55 @@
+from os.path import dirname
+import unittest
+
+import vcr
+
+import hubs.models
+
+cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
+
+
+class WidgetTest(unittest.TestCase):
+    def setUp(self):
+        filename = cassette_dir + self.id()
+        self.vcr = vcr.use_cassette(filename, record_mode='new_episodes')
+        self.vcr.__enter__()
+
+        import hubs.app
+        hubs.app.fedmsg_config = {
+            'hubs.sqlalchemy.uri': 'sqlite://',  # in memory
+        }
+        hubs.app.session = hubs.models.init(
+            hubs.app.fedmsg_config['hubs.sqlalchemy.uri'],
+            create=True,
+        )
+        self.app = hubs.app.app.test_client()
+        self.app.testing = True
+        self.session = hubs.app.session
+        self.populate()
+
+    def tearDown(self):
+        self.vcr.__exit__()
+        self.session.remove()
+
+
+    def populate(self):
+        for user in ['devyani7', 'dhrish', 'shalini', 'ralph', 'decause']:
+            openid = '%s.id.fedoraproject.org' % user
+            fullname = user.title()
+            hubs.models.User.get_or_create(
+                hubs.app.session, openid=openid, fullname=fullname)
+
+        for team in ['i18n', 'infra']:
+            hub = hubs.models.Hub(name=team, summary="the %s team" % team)
+            hubs.app.session.add(hub)
+
+
+    # TODO - test that it is in the registry
+    # TODO - test that it has all the things it needs
+
+    def widget_instance(self, hubname, plugin):
+        hub = hubs.models.Hub.by_name(self.session, hubname)
+        for widget in hub.widgets:
+            if widget.plugin == plugin:
+                return widget
+        raise KeyError("No such widget found for %s/%s" % (hubname, plugin))
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
new file mode 100644
index 0000000..9005b2f
--- /dev/null
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -0,0 +1,15 @@
+import json
+
+import hubs.tests.test_widgets
+
+
+class TestBadges(hubs.tests.test_widgets.WidgetTest):
+    plugin = 'badges'  # The name in hubs.widgets.registry
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        response = self.app.get('/ralph/%i/json/' % widget.idx)
+        assert response.status_code == 200, response.status_code
+        data = json.loads(response.data)
+        self.assertEquals(data['plugin'], 'badges')
+        assert 'assertions' in data['data'], data['data'].keys()
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 416f7d6..c5d1e9a 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -32,7 +32,7 @@ registry = {
     'subscriptions': subscriptions,
     'cobwebs': cobwebs,
     'meetings': meetings,
-    'pagure_pr': pagure_pr,    
+    'pagure_pr': pagure_pr,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/test.py b/hubs/widgets/test.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/widgets/test.py
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..963de6b
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,4 @@
+[nosetests]
+verbosity=2
+nocapture=1
+with-yanc=1
diff --git a/test-requirements.txt b/test-requirements.txt
new file mode 100644
index 0000000..c1358b7
--- /dev/null
+++ b/test-requirements.txt
@@ -0,0 +1,4 @@
+nose
+vcrpy
+mock
+yanc

From 77da1c772f8f0b6200611e794bb07f29b4094201 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 16:11:43 +0000
Subject: [PATCH 251/1001] Some initial tests for should_invalidate


---

diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index dcf90f9..8b732c3 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -1,6 +1,7 @@
 from os.path import dirname
 import unittest
 
+import requests
 import vcr
 
 import hubs.models
@@ -31,7 +32,6 @@ class WidgetTest(unittest.TestCase):
         self.vcr.__exit__()
         self.session.remove()
 
-
     def populate(self):
         for user in ['devyani7', 'dhrish', 'shalini', 'ralph', 'decause']:
             openid = '%s.id.fedoraproject.org' % user
@@ -53,3 +53,11 @@ class WidgetTest(unittest.TestCase):
             if widget.plugin == plugin:
                 return widget
         raise KeyError("No such widget found for %s/%s" % (hubname, plugin))
+
+    @staticmethod
+    def get_fedmsg(idx):
+        url = 'https://apps.fedoraproject.org/datagrepper/id'
+        response = requests.get(url, params=dict(id=idx))
+        if not bool(response):
+            raise IOError("Failed to talk to %r %r" % (response.url, response))
+        return response.json()
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index 9005b2f..4f668b1 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -13,3 +13,24 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         self.assertEquals(data['plugin'], 'badges')
         assert 'assertions' in data['data'], data['data'].keys()
+
+    def test_should_invalidate_wrong_topic(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        msg = self.get_fedmsg('2016-ebb84660-59e9-4e68-af8f-4e6f49348b88')
+        module = hubs.widgets.registry[widget.plugin]
+        result = module.should_invalidate(msg, self.session, widget)
+        assert not result
+
+    def test_should_invalidate_wrong_user(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        msg = self.get_fedmsg('2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f')
+        module = hubs.widgets.registry[widget.plugin]
+        result = module.should_invalidate(msg, self.session, widget)
+        assert not result
+
+    def test_should_invalidate_good_match(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
+        module = hubs.widgets.registry[widget.plugin]
+        result = module.should_invalidate(msg, self.session, widget)
+        assert result

From bdb95af680cd1c637789f23120759390591eb1ef Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 16:17:18 +0000
Subject: [PATCH 252/1001] Tests instructions.


---

diff --git a/README.rst b/README.rst
index f07a965..5d45d4d 100644
--- a/README.rst
+++ b/README.rst
@@ -58,6 +58,20 @@ the db alltogether, re-populates it, and restarts the app::
 
     $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 240 --log-config logging.ini hubs.app:app
 
+Run the tests!
+--------------
+
+We have a test suite.  You should run it *before* you start working on some
+code, to make sure that nothing is broken before you start.  And you should run
+it after you finish your change, before you push, to verify that your change
+didn't inadvertently break something else.
+
+You can run it with::
+
+    $ pip install -r test-requirements.txt
+    $ PYTHONPATH=. nosetests
+
+
 Feed Widget - the Extra Mile
 ----------------------------
 

From 9ced943d4858c4b2f56c4e4a55d27adc80a3bbae Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 19:34:51 +0000
Subject: [PATCH 253/1001] Test the about widget.


---

diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 8b732c3..2238a4c 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -1,3 +1,4 @@
+import json
 from os.path import dirname
 import unittest
 
@@ -39,6 +40,16 @@ class WidgetTest(unittest.TestCase):
             hubs.models.User.get_or_create(
                 hubs.app.session, openid=openid, fullname=fullname)
 
+        hubs.app.session.flush()
+
+        hub = hubs.models.Hub.by_name(hubs.app.session, 'ralph')
+        widget = hubs.models.Widget(
+            plugin='about',
+            index=500,
+            _config=json.dumps({"text": "Testing."}),
+        )
+        hub.widgets.append(widget)
+
         for team in ['i18n', 'infra']:
             hub = hubs.models.Hub(name=team, summary="the %s team" % team)
             hubs.app.session.add(hub)
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
new file mode 100644
index 0000000..3586998
--- /dev/null
+++ b/hubs/tests/test_widgets/test_about.py
@@ -0,0 +1,18 @@
+import json
+
+import hubs.tests.test_widgets
+
+
+class TestBadges(hubs.tests.test_widgets.WidgetTest):
+    plugin = 'about'  # The name in hubs.widgets.registry
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        response = self.app.get('/ralph/%i/json/' % widget.idx)
+        assert response.status_code == 200, response.status_code
+        data = json.loads(response.data)
+        self.assertDictEqual(data['data'], {
+            u'source_url': u'/source/about/',
+            u'text': u'Testing.',
+            u'widget_url': u'/ralph/41/',
+        })
diff --git a/hubs/widgets/avatar.py b/hubs/widgets/avatar.py
deleted file mode 100644
index 10754df..0000000
--- a/hubs/widgets/avatar.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.base import argument
-from hubs.utils import username2avatar
-
-import jinja2
-
-import hubs.validators as validators
-
-
-template = jinja2.Template("""
-<img class="img-circle center-block" src="{{avatar}}">
-""")
-
-#from hubs.widgets.chrome import panel
-#chrome = panel("About")
-
-
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-def data(session, widget, username):
-    avatar = username2avatar(username)
-    return dict(username=username, avatar=avatar)
-
-
-@hint(topics=[_('hubs.widget.update')])
-def should_invalidate(message, session, widget):
-    if not message['topic'].endswith('hubs.widget.update'):
-        return False
-    if message['msg']['widget']['id'] != widget.id:
-        return False
-    return True

From 41b446d4116de1871cdd1c60ec70cd057bf83976 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 19:35:18 +0000
Subject: [PATCH 254/1001] Remove the avatar widget.


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index c5d1e9a..2ff7e92 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -3,7 +3,6 @@ from hubs.widgets import stats
 from hubs.widgets import rules
 from hubs.widgets import sticky
 from hubs.widgets import about
-from hubs.widgets import avatar
 from hubs.widgets import badges
 from hubs.widgets import fedmsgs
 from hubs.widgets import fedmsgstats
@@ -24,7 +23,6 @@ registry = {
     'rules': rules,
     'sticky': sticky,
     'about': about,
-    'avatar': avatar,
     'badges': badges,
     'fedmsgs': fedmsgs,
     'fedmsgstats': fedmsgstats,

From f486a0862343d0877c7985cd2767f3b023adb4f6 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 19:35:34 +0000
Subject: [PATCH 255/1001] Include these in tarballs.


---

diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..44ebdab
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,2 @@
+include requirements.txt
+include test-requirements.txt

From 8bbe2b50cd7053496481f6fa03774e8725596363 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 19:42:44 +0000
Subject: [PATCH 256/1001] Rename the fedmsgs widget to linechart.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 56a93c1..90b18db 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -6,7 +6,7 @@ import hubs.models
 def add_user_widgets(session, hub, username, fullname):
     """ Some defaults for an individual user's hub. """
     widget = hubs.models.Widget(
-        plugin='fedmsgs', index=0, left=True,
+        plugin='linechart', index=0, left=True,
         _config=json.dumps({
             'username': username,
         }))
@@ -54,7 +54,7 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='pagure_pr', index=5, 
+        plugin='pagure_pr', index=5,
         _config=json.dumps({
             'repo': 'pagure',
         }))
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 2ff7e92..20f3ca1 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -4,7 +4,7 @@ from hubs.widgets import rules
 from hubs.widgets import sticky
 from hubs.widgets import about
 from hubs.widgets import badges
-from hubs.widgets import fedmsgs
+from hubs.widgets import linechart
 from hubs.widgets import fedmsgstats
 from hubs.widgets import feed
 from hubs.widgets import subscriptions
@@ -24,7 +24,7 @@ registry = {
     'sticky': sticky,
     'about': about,
     'badges': badges,
-    'fedmsgs': fedmsgs,
+    'linechart': linechart,
     'fedmsgstats': fedmsgstats,
     'feed': feed,
     'subscriptions': subscriptions,
diff --git a/hubs/widgets/fedmsgs.py b/hubs/widgets/fedmsgs.py
deleted file mode 100644
index 0a3fb91..0000000
--- a/hubs/widgets/fedmsgs.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from hubs.hinting import hint
-from hubs.widgets.base import argument
-
-import jinja2
-
-import hubs.validators as validators
-
-import fedmsg.config
-config = fedmsg.config.load_config()
-
-
-template = jinja2.Template("""
-<div class="flex-container">
-
-    <img src="{{url}}" />
-
-</div>
-""")
-
-from hubs.widgets.chrome import panel
-chrome = panel("Weekly Activity")
-
-
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-def data(session, widget, username):
-    categories = ['git', 'Wiki', 'Copr', 'anitya', 'mirrormanager', 'ansible',
-                  'fedoratagger', 'Pkgdb', 'summershum', 'nuancier', 'Mailman',
-                  'fedbadges', 'FMN', 'koschei', 'compose', 'fedimg',
-                  'Jenkins', 'irc', 'FAS', 'buildsys', 'Askbot', 'pagure',
-                  'Bodhi', 'faf', 'kerneltest', 'github', 'Trac', 'meetbot',
-                  'planet', 'fedocal', 'hotness']
-    categories = [c.lower() for c in categories]
-    categories = "&".join(['category=%s' % c for c in categories ])
-    url = "https://apps.fedoraproject.org/datagrepper/charts/stackedline?delta=604800&N=12&style=clean&height=300&fill=true&user={username}&split_on=categories"
-    url = url + "&" + categories
-    url = url.format(username=username)
-    return dict(url=url)
-
-
-@hint(usernames=lambda widget: [widget.config['username']])
-def should_invalidate(message, session, widget):
-    usernames = fedmsg.meta.msg2usernames(message, **config)
-    username = widget.config['username']
-    return username in usernames
diff --git a/hubs/widgets/linechart.py b/hubs/widgets/linechart.py
new file mode 100644
index 0000000..0a3fb91
--- /dev/null
+++ b/hubs/widgets/linechart.py
@@ -0,0 +1,47 @@
+from hubs.hinting import hint
+from hubs.widgets.base import argument
+
+import jinja2
+
+import hubs.validators as validators
+
+import fedmsg.config
+config = fedmsg.config.load_config()
+
+
+template = jinja2.Template("""
+<div class="flex-container">
+
+    <img src="{{url}}" />
+
+</div>
+""")
+
+from hubs.widgets.chrome import panel
+chrome = panel("Weekly Activity")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    categories = ['git', 'Wiki', 'Copr', 'anitya', 'mirrormanager', 'ansible',
+                  'fedoratagger', 'Pkgdb', 'summershum', 'nuancier', 'Mailman',
+                  'fedbadges', 'FMN', 'koschei', 'compose', 'fedimg',
+                  'Jenkins', 'irc', 'FAS', 'buildsys', 'Askbot', 'pagure',
+                  'Bodhi', 'faf', 'kerneltest', 'github', 'Trac', 'meetbot',
+                  'planet', 'fedocal', 'hotness']
+    categories = [c.lower() for c in categories]
+    categories = "&".join(['category=%s' % c for c in categories ])
+    url = "https://apps.fedoraproject.org/datagrepper/charts/stackedline?delta=604800&N=12&style=clean&height=300&fill=true&user={username}&split_on=categories"
+    url = url + "&" + categories
+    url = url.format(username=username)
+    return dict(url=url)
+
+
+@hint(usernames=lambda widget: [widget.config['username']])
+def should_invalidate(message, session, widget):
+    usernames = fedmsg.meta.msg2usernames(message, **config)
+    username = widget.config['username']
+    return username in usernames

From 67337314ec2988384a1175b8565f35a4fe9d4c63 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 20:17:52 +0000
Subject: [PATCH 257/1001] Test the cobweb widget.


---

diff --git a/hubs/models.py b/hubs/models.py
index 79a481f..f56fc0d 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -133,13 +133,16 @@ class Hub(BASE):
     avatar = sa.Column(sa.String(256), default=placekitten)
     header_img = sa.Column(sa.String(256), default=randomheader)
 
+    # Timestamps about various kinds of "freshness"
+    last_refreshed = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
+    last_accessed = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
+    last_edited = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
+
     #fas_group = sa.Column(sa.String(32), nullable=False)
 
     @property
     def days_idle(self):
-        # TODO -- implement calculating time since this hub was active
-        import random
-        return random.randint(0, 356)
+        return (datetime.datetime.utcnow() - self.last_refreshed).days
 
     @property
     def activity_class(self):
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 2238a4c..0402c4f 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -1,4 +1,5 @@
 import json
+from datetime import datetime, timedelta
 from os.path import dirname
 import unittest
 
@@ -50,9 +51,18 @@ class WidgetTest(unittest.TestCase):
         )
         hub.widgets.append(widget)
 
-        for team in ['i18n', 'infra']:
+        for team in ['i18n', 'infra', 'old']:
             hub = hubs.models.Hub(name=team, summary="the %s team" % team)
+            if hub.name == 'old':
+                hub.last_refreshed = datetime.utcnow() - timedelta(days=100)
+                hub.last_updated = datetime.utcnow() - timedelta(days=200)
+
             hubs.app.session.add(hub)
+            widget = hubs.models.Widget(
+                plugin='cobwebs',
+                index=10,
+            )
+            hub.widgets.append(widget)
 
 
     # TODO - test that it is in the registry
@@ -60,6 +70,8 @@ class WidgetTest(unittest.TestCase):
 
     def widget_instance(self, hubname, plugin):
         hub = hubs.models.Hub.by_name(self.session, hubname)
+        if not hub:
+            raise ValueError("No such hub %r" % hubname)
         for widget in hub.widgets:
             if widget.plugin == plugin:
                 return widget
diff --git a/hubs/tests/test_widgets/test_cobwebs.py b/hubs/tests/test_widgets/test_cobwebs.py
new file mode 100644
index 0000000..d0f32ae
--- /dev/null
+++ b/hubs/tests/test_widgets/test_cobwebs.py
@@ -0,0 +1,37 @@
+import json
+
+import hubs.tests.test_widgets
+
+
+class TestBadges(hubs.tests.test_widgets.WidgetTest):
+    plugin = 'cobwebs'  # The name in hubs.widgets.registry
+
+    def test_data_old(self):
+        widget = self.widget_instance('old', self.plugin)
+        response = self.app.get('/old/%i/json/' % widget.idx)
+        assert response.status_code == 200, response.status_code
+        data = json.loads(response.data)
+        self.assertDictEqual(data['data'], {
+            u'days': 100,
+            u'old': True,
+            u'archived': False,
+            u'icon': u'/static/img/cobweb.png',
+            u'source_url': u'/source/cobwebs/',
+            u'then': '3 months ago',
+            u'widget_url': u'/old/44/',
+        })
+
+    def test_data_young(self):
+        widget = self.widget_instance('infra', self.plugin)
+        response = self.app.get('/infra/%i/json/' % widget.idx)
+        assert response.status_code == 200, response.status_code
+        data = json.loads(response.data)
+        self.assertDictEqual(data['data'], {
+            u'days': 0,
+            u'old': False,
+            u'archived': False,
+            u'icon': u'/static/img/cobweb.png',
+            u'source_url': u'/source/cobwebs/',
+            u'then': u'just now',
+            u'widget_url': u'/infra/43/',
+        })
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 995125c..f1f84cb 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -1,4 +1,5 @@
 import collections
+import datetime
 import functools
 import hashlib
 import json
@@ -66,7 +67,13 @@ def smartcache(func):
 
 def invalidate_cache(widget, *args, **kwargs):
     key = cache_key_generator(widget, *args, **kwargs)
-    log.debug("Deleting cache key %s", key)
+
+    if not cache.get(key, ignore_expiration=True):
+        log.debug("Not deleting cache key %s.  It is absent.", key)
+        return
+
+    widget.hub.last_refreshed = datetime.datetime.utcnow()
+    log.debug("Deleting cache key %s.", key)
     cache.delete(key)
 
 

From 7d27953019b7541265367ca610d4aa7b310af25f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 20:20:29 +0000
Subject: [PATCH 258/1001] Set last_edited.


---

diff --git a/hubs/app.py b/hubs/app.py
index 05794ba..39bea1f 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -99,6 +99,7 @@ def hub_edit_get(name):
 def hub_edit_post(name):
     #hub = get_hub(session, name)
     # TODO -- save things to the db ... and then redirect
+    hub.last_edited = datetime.datetime.utcnow()
     raise NotImplementedError('TODO - save changes to hub config')
     flask.redirect(flask.url_for('hub', name=name))
 
@@ -135,6 +136,7 @@ def widget_edit_get(hub, idx):
 def widget_edit_post(hub, idx):
     #widget = get_widget(session, hub, idx)
     # TODO -- save things to the db ... and then redirect
+    widget.hub.last_edited = datetime.datetime.utcnow()
     raise NotImplementedError('TODO - save changes to widget config')
     flask.redirect(flask.url_for('hub', name=hub))
 
diff --git a/hubs/models.py b/hubs/models.py
index f56fc0d..ed003e3 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -135,7 +135,6 @@ class Hub(BASE):
 
     # Timestamps about various kinds of "freshness"
     last_refreshed = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
-    last_accessed = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     last_edited = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
     #fas_group = sa.Column(sa.String(32), nullable=False)

From bb5140742dfeb4a6779c75b181d4170b9e0e8215 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 20:26:20 +0000
Subject: [PATCH 259/1001] Fix test name.


---

diff --git a/hubs/tests/test_widgets/test_cobwebs.py b/hubs/tests/test_widgets/test_cobwebs.py
index d0f32ae..8186959 100644
--- a/hubs/tests/test_widgets/test_cobwebs.py
+++ b/hubs/tests/test_widgets/test_cobwebs.py
@@ -3,7 +3,7 @@ import json
 import hubs.tests.test_widgets
 
 
-class TestBadges(hubs.tests.test_widgets.WidgetTest):
+class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
     plugin = 'cobwebs'  # The name in hubs.widgets.registry
 
     def test_data_old(self):

From 6679aa7277f1dab74b9440581be497ac7dce6055 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 20:32:54 +0000
Subject: [PATCH 260/1001] test fedmsg stats widget.


---

diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
new file mode 100644
index 0000000..a1ca9ca
--- /dev/null
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -0,0 +1,22 @@
+import json
+
+import hubs.tests.test_widgets
+
+
+class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
+    plugin = 'fedmsgstats'  # The name in hubs.widgets.registry
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        response = self.app.get('/ralph/%i/json/' % widget.idx)
+        assert response.status_code == 200, response.status_code
+        data = json.loads(response.data)
+        self.assertDictEqual(data['data'], {
+            u'fedmsgs': 83854,
+            u'fedmsgs_text': u'83,854',
+            u'source_url': u'/source/fedmsgstats/',
+            u'subscribers': 0,
+            u'subscribers_text': u'0',
+            u'username': u'ralph',
+            u'widget_url': u'/ralph/27/',
+        })

From c9741976b7f57bab737a34ef5a1f52a7428fd803 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 20:34:49 +0000
Subject: [PATCH 261/1001] A note to future self.


---

diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index 2d5258a..890fb18 100644
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -44,4 +44,8 @@ def data(session, widget):
 
 #@hint(topics=[_('hubs.widget.update')])
 def should_invalidate(message, session, widget):
+    # TODO -- this one is going to be to be reorganized, since there's no event
+    # that causes this one to flip.
+    # We could add a hack that forces the deletion of this key when other
+    # widgets on the same hub are updated...  but that would be very special.
     raise NotImplementedError()

From e9df96456932c62a28b67e5e65af76cce067b9d1 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 20:55:08 +0000
Subject: [PATCH 262/1001] Test linechart and meetings.


---

diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 0402c4f..8914ab6 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -58,10 +58,10 @@ class WidgetTest(unittest.TestCase):
                 hub.last_updated = datetime.utcnow() - timedelta(days=200)
 
             hubs.app.session.add(hub)
-            widget = hubs.models.Widget(
-                plugin='cobwebs',
-                index=10,
-            )
+            widget = hubs.models.Widget(plugin='cobwebs', index=10)
+            hub.widgets.append(widget)
+            widget = hubs.models.Widget(plugin='meetings', index=11,
+                                        _config=json.dumps({'calendar': team}))
             hub.widgets.append(widget)
 
 
diff --git a/hubs/tests/test_widgets/test_cobwebs.py b/hubs/tests/test_widgets/test_cobwebs.py
index 8186959..96f58f4 100644
--- a/hubs/tests/test_widgets/test_cobwebs.py
+++ b/hubs/tests/test_widgets/test_cobwebs.py
@@ -11,6 +11,7 @@ class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/old/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
         data = json.loads(response.data)
+        del data['data']['widget_url']  # changes oddly, so don't test
         self.assertDictEqual(data['data'], {
             u'days': 100,
             u'old': True,
@@ -18,7 +19,6 @@ class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
             u'icon': u'/static/img/cobweb.png',
             u'source_url': u'/source/cobwebs/',
             u'then': '3 months ago',
-            u'widget_url': u'/old/44/',
         })
 
     def test_data_young(self):
@@ -26,6 +26,7 @@ class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/infra/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
         data = json.loads(response.data)
+        del data['data']['widget_url']  # changes oddly, so don't test
         self.assertDictEqual(data['data'], {
             u'days': 0,
             u'old': False,
@@ -33,5 +34,4 @@ class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
             u'icon': u'/static/img/cobweb.png',
             u'source_url': u'/source/cobwebs/',
             u'then': u'just now',
-            u'widget_url': u'/infra/43/',
         })
diff --git a/hubs/tests/test_widgets/test_linechart.py b/hubs/tests/test_widgets/test_linechart.py
new file mode 100644
index 0000000..5bbfd5c
--- /dev/null
+++ b/hubs/tests/test_widgets/test_linechart.py
@@ -0,0 +1,15 @@
+import json
+
+import hubs.tests.test_widgets
+
+
+class TestLinechart(hubs.tests.test_widgets.WidgetTest):
+    plugin = 'linechart'
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        response = self.app.get('/ralph/%i/json/' % widget.idx)
+        assert response.status_code == 200, response.status_code
+        data = json.loads(response.data)
+        datagrepper = 'https://apps.fedoraproject.org/datagrepper'
+        assert data['data']['url'].startswith(datagrepper)
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
new file mode 100644
index 0000000..0274255
--- /dev/null
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -0,0 +1,17 @@
+import json
+
+import hubs.tests.test_widgets
+
+
+class TestMeetings(hubs.tests.test_widgets.WidgetTest):
+    plugin = 'meetings'
+
+    def test_data_simple(self):
+        team = 'i18n'
+        widget = self.widget_instance(team, self.plugin)
+        response = self.app.get('/%s/%i/json/' % (team, widget.idx))
+        assert response.status_code == 200, response.status_code
+        data = json.loads(response.data)
+        meetings = data['data']['meetings']["%s meeting" % team]
+        assert len(meetings) == 15, len(meetings)
+        assert team in meetings[0]['meeting_name']

From f2f54551930c79067e54ea3f3e7745146537304f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 21:06:14 +0000
Subject: [PATCH 263/1001] Another note to future self.


---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 26d5501..2ba21e6 100644
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -71,4 +71,14 @@ def data(session, widget, calendar):
 
 
 def should_invalidate(message, session, widget):
+    # TODO -- we have a hard problem here.
+    # There is no event which should invalidate this widget...
+    # but we do need to expire ourselves after the date of the meeting we
+    # cached has passed.
+    # Perhaps we should expand the should_invalidate API to return a tuple:
+    #  - True/False if we should or shouldn't invalidate.
+    #  - an expiry in seconds where -1 is default and means "never expire"
+    # with that.. we could have this function return the timestamp of the
+    # meeting in seconds.. such that once it has passed, our cache will free
+    # up.
     raise NotImplementedError()

From 5d4ace4a0351f14ec778b8c5b2666b4d407dafdf Mon Sep 17 00:00:00 2001
From: Dhriti Shikhar <dhrish20@gmail.com>
Date: Jan 21 2016 21:25:25 +0000
Subject: [PATCH 264/1001] Adds a github pull requests widget


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 90b18db..035eadd 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -59,5 +59,12 @@ def add_user_widgets(session, hub, username, fullname):
             'repo': 'pagure',
         }))
     hub.widgets.append(widget)
-
+    widget = hubs.models.Widget(
+        plugin='github_pr', index=7,
+        _config=json.dumps({
+             'display_number': 1,
+             'org': 'fedora-infra',
+             'repo': 'fas',
+        }))
+    hub.widgets.append(widget)
     return hub
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 20f3ca1..dff69f8 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -11,6 +11,7 @@ from hubs.widgets import subscriptions
 from hubs.widgets import cobwebs
 from hubs.widgets import meetings
 from hubs.widgets import pagure_pr
+from hubs.widgets import github_pr
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -31,6 +32,7 @@ registry = {
     'cobwebs': cobwebs,
     'meetings': meetings,
     'pagure_pr': pagure_pr,
+    'github_pr': github_pr,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
new file mode 100644
index 0000000..3ec8ab1
--- /dev/null
+++ b/hubs/widgets/github_pr.py
@@ -0,0 +1,85 @@
+from hubs.widgets.chrome import panel
+from hubs.hinting import hint
+from hubs.widgets.base import argument
+import hubs.validators as validators
+import jinja2
+import requests
+
+chrome = panel("Github: Open Pull Requests")
+
+template = jinja2.Template("""
+  <br />
+  {% for i in range(display_number) %}
+    <div>
+      <table class="table-responsive table-condensed">
+        <tr>
+          <td valign="top" class="panel-heading">
+            <b>#{{ all_pr[i]['num'] }}</b>
+          </td>
+          <td width="300px">
+            <b>{{ all_pr[i]['title'] }}</b>
+          </td>
+        </tr>
+      </table>
+      <table class="table-responsive table-condensed">
+        <tr>
+          <td width="300px">
+            <font size="2">
+              <i>Opened by <a href="https://github.com/{{ all_pr[i]['openedby'] }}" target="_blank">{{ all_pr[i]['openedby'] }}</a></i>
+              {% if all_pr[i]['assignee']|string() == "None" %}
+                <br /><i>Unclaimed</i>
+              {% else %}
+                 <br /><i>Assigned by <a href="https://github.com/{{ all_pr[i]['assignee'] }}" target="_blank">{{ all_pr[i]['assignee'] }}</a></i>
+              {% endif %}
+            </font>
+          </td>
+          <td>
+             <a href="https://github.com/{{ org }}/{{ repo }}/pulls/{{ all_pr[i]['num'] }}" target="_blank">
+               <button type="button" class="btn btn-default" aria-label="Left Align">
+                 <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+               </button>
+             </a>
+          </td>
+        </tr>
+      </table>
+    </div>
+    {% endfor %}
+    <div class="row">
+      <a href="https://github.com/{{ org }}/{{ repo }}/pulls" target="_blank"><center>All Pull Requests</center></a>
+    </div>
+""")
+
+@argument(name="repo",
+	default=None,
+	validator=validators.repo,
+	help="Repo")
+def data(session, widget, display_number, org, repo):
+  url = '/'.join(['https://api.github.com/repos',org,repo,"pulls"])
+  pr_response = requests.get(url)
+  data = pr_response.json()
+  all_pr = list()
+  for i in range(0,1):
+    pr_details=dict()
+    pr_num=data[i]['number']
+    pr_title=data[i]['title']
+    pr_openedby=data[i]['user']['login']
+    if(data[i]['assignee']!=None):
+      pr_assignee=data[i]['assignee']['login']
+    else:
+      pr_assignee=data[i]['assignee']
+    pr_details['num']=pr_num
+    pr_details['title']=pr_title
+    pr_details['openedby']=pr_openedby
+    pr_details['assignee']=pr_assignee
+    all_pr.append(pr_details)
+  all_pr.reverse()
+  return dict(
+    org=org,
+    repo=repo,
+    all_pr=all_pr,
+    display_number=display_number,
+  )
+
+@hint()
+def should_invalidate(message, session, widget):
+  raise NotImplementedError

From 955a932f923e33328ca6f0da57bf2c04af1b4a96 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 21:26:28 +0000
Subject: [PATCH 265/1001] Remove some values from the tests that change regularly.


---

diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index 3586998..675dc6a 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -11,8 +11,8 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
         data = json.loads(response.data)
+        del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
             u'source_url': u'/source/about/',
             u'text': u'Testing.',
-            u'widget_url': u'/ralph/41/',
         })
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index a1ca9ca..ad8c0c3 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -11,6 +11,7 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
         data = json.loads(response.data)
+        del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
             u'fedmsgs': 83854,
             u'fedmsgs_text': u'83,854',
@@ -18,5 +19,4 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
             u'subscribers': 0,
             u'subscribers_text': u'0',
             u'username': u'ralph',
-            u'widget_url': u'/ralph/27/',
         })

From ec8d7b3eec7ba78f28b2b0b56bf8ba329348eeb5 Mon Sep 17 00:00:00 2001
From: Dhriti Shikhar <dhrish20@gmail.com>
Date: Jan 21 2016 21:29:22 +0000
Subject: [PATCH 266/1001] Adds a pagure issues widget


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index dff69f8..88ba8a7 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -12,6 +12,7 @@ from hubs.widgets import cobwebs
 from hubs.widgets import meetings
 from hubs.widgets import pagure_pr
 from hubs.widgets import github_pr
+from hubs.widgets import pagureissues
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -33,6 +34,7 @@ registry = {
     'meetings': meetings,
     'pagure_pr': pagure_pr,
     'github_pr': github_pr,
+    'pagureissues': pagureissues,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
new file mode 100644
index 0000000..f64f0b4
--- /dev/null
+++ b/hubs/widgets/pagureissues.py
@@ -0,0 +1,150 @@
+from hubs.hinting import hint
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import argument
+import hubs.validators as validators
+import jinja2
+import requests
+
+chrome = panel("Pagure: Newest Open Tickets")
+
+pagure_url = "https://pagure.io/api/0"
+
+template = jinja2.Template("""
+  <br /> 
+  {% if message == "None" %}
+    <div class="container">
+      {% if total<3 %}
+        {% for i in range(0,total) %}
+          <div> 
+            <table class="table-responsive table-condensed">
+              <tr>
+                <td valign="top" class="panel-heading">
+                  <b>#{{ all_issues[i]['id'] }}</b>
+                </td>
+                <td width="260px">
+                  <b>{{ all_issues[i]['title'] }}</b>
+                </td>
+              </tr>
+            </table>
+            <table class="table-responsive table-condensed">
+              <tr>
+                <td width="260px">
+                  <font size="2">
+                    <i>Opened by <a href="https://pagure.io/user/{{ all_issues[i]['user'] }}" target="_blank">{{ all_issues[i]['user'] }}</a></i>
+                    {% if all_issues[i]['assignee']|string() == "None" %}
+                      <br /><i>Unclaimed</i>
+                    {% else %}
+                      <br /><i>Assigned by <a href="https://pagure.io/user/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
+                    {% endif %}
+                  </font>               
+                </td>
+                <td>
+	          <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
+                    <button type="button" class="btn btn-default" aria-label="Left Align">
+                      <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+                    </button>
+	          </a>
+                </td>
+              </tr>
+            </table>
+          </div>
+        {% endfor %}
+      {% else %}
+        {% for i in range(0,3) %}
+          <div> 
+            <table class="table-responsive table-condensed">
+              <tr>
+                <td valign="top" class="panel-heading">
+                  <b>#{{ all_issues[i]['id'] }}</b>
+                </td>
+                <td width="260px">
+                  <b>{{ all_issues[i]['title'] }}</b>
+                </td>
+              </tr>
+            </table>
+            <table class="table-responsive table-condensed">
+              <tr>
+                <td width="260px">
+                  <font size="2">
+                    <i>Opened by <a href="https://pagure.io/user/{{ all_issues[i]['user'] }}" target="_blank">{{ all_issues[i]['user'] }}</a></i>
+                    {% if all_issues[i]['assignee']|string() == "None" %}
+                      <br /><i>Unclaimed</i>
+                    {% else %}
+                      <br /><i>Assigned to <a href="https://pagure.io/user/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
+                    {% endif %}
+                  </font>               
+                </td>
+                <td>
+	          <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
+                    <button type="button" class="btn btn-default" aria-label="Left Align">
+                      <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+                    </button>
+	          </a>
+                </td>
+              </tr>
+            </table>
+          </div>
+        {% endfor %}
+      {% endif %}
+    </div>    
+    <div class="row">
+      <a href="https://pagure.io/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
+    </div>
+  {% else %}
+    <div class="container">
+      <b>Not a valid repo</b>
+    </div>
+  {% endif %}
+""")
+
+@argument(name="repo",
+          default=None,
+          validator=validators.repo,
+          help="Repo")
+def data(session, widget, repo):
+    repo = "pagure"
+
+    projects_response = requests.get("https://pagure.io/api/0/projects")
+    projects_data = projects_response.json()
+    total_projects = projects_data['total_projects']
+    all_projects = list()
+    for i in range(0, total_projects):
+      all_projects.append(projects_data['projects'][i]['name'])
+    if repo not in all_projects:
+      message = "Not a valid project"
+      return dict(
+        message=message,
+      )
+    else:
+      message = "None"
+      url = '/'.join([pagure_url, repo, "issues"])
+      issue_response = requests.get(url)
+      data = issue_response.json()
+      total = data['total_issues']
+      all_issues = list()
+      for i in range(0,total):
+        issue_details = dict()
+        issue_id=data['issues'][i]['id']
+        issue_title=data['issues'][i]['title']
+        issue_user=data['issues'][i]['user']['name']
+        if(data['issues'][i]['assignee']!=None):
+          issue_assignee=data['issues'][i]['assignee']['name']
+        else:
+          issue_assignee=data['issues'][i]['assignee']
+        issue_details['id']=issue_id
+        issue_details['title']=issue_title
+        issue_details['user']=issue_user
+        issue_details['assignee']=issue_assignee
+        all_issues.append(issue_details)
+      all_issues.reverse()
+      return dict(
+        repo=repo,
+        total=total,
+        all_issues=all_issues,
+        message = message,
+      )
+ 
+
+@hint()
+def should_invalidate(message, session, widget):
+   raise NotImplementedError

From 1c0fb5d978a45a1be0aec977ead59f9f5ff8b326 Mon Sep 17 00:00:00 2001
From: Dhriti Shikhar <dhrish20@gmail.com>
Date: Jan 21 2016 21:31:48 +0000
Subject: [PATCH 267/1001] Adds a github issues widget


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 88ba8a7..03084ac 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -13,6 +13,7 @@ from hubs.widgets import meetings
 from hubs.widgets import pagure_pr
 from hubs.widgets import github_pr
 from hubs.widgets import pagureissues
+from hubs.widgets import githubissues
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -35,6 +36,7 @@ registry = {
     'pagure_pr': pagure_pr,
     'github_pr': github_pr,
     'pagureissues': pagureissues,
+    'githubissues': githubissues,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
new file mode 100644
index 0000000..3eef711
--- /dev/null
+++ b/hubs/widgets/githubissues.py
@@ -0,0 +1,85 @@
+from hubs.widgets.chrome import panel
+from hubs.hinting import hint
+from hubs.widgets.base import argument
+import hubs.validators as validators
+import jinja2
+import requests
+
+chrome = panel("Github: Newest Open Tickets")
+
+template = jinja2.Template("""
+  <br />
+  {% for i in range(display_number) %}
+    <div>
+      <table class="table-responsive table-condensed">
+        <tr>
+          <td valign="top" class="panel-heading">
+            <b>#{{ all_issues[i]['num'] }}</b>
+          </td>
+          <td width="300px">
+            <b>{{ all_issues[i]['title'] }}</b>
+          </td>
+        </tr>
+      </table>
+      <table class="table-responsive table-condensed">
+        <tr>
+          <td width="300px">
+            <font size="2">
+              <i>Opened by <a href="https://github.com/{{ all_issues[i]['openedby'] }}" target="_blank">{{ all_issues[i]['openedby'] }}</a></i>
+              {% if all_issues[i]['assignee']|string() == "None" %}
+                <br /><i>Unclaimed</i>
+              {% else %}
+                 <br /><i>Assigned by <a href="https://github.com/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
+              {% endif %}
+            </font>
+          </td>
+          <td>
+             <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
+               <button type="button" class="btn btn-default" aria-label="Left Align">
+                 <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+               </button>
+             </a>
+          </td>
+        </tr>
+      </table>
+    </div>
+    {% endfor %}
+    <div class="row">
+      <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
+    </div>
+""")
+
+@argument(name="repo",
+	default=None,
+	validator=validators.repo,
+	help="Repo")
+def data(session, widget, display_number, org, repo):
+  url = '/'.join(['https://api.github.com/repos',org,repo,"issues"])
+  issue_response = requests.get(url)
+  data = issue_response.json()
+  all_issues = list()
+  for i in range(0,10):
+    issue_details=dict()
+    issue_num=data[i]['number']
+    issue_title=data[i]['title']
+    issue_openedby=data[i]['user']['login']
+    if(data[i]['assignee']!=None):
+      issue_assignee=data[i]['assignee']['login']
+    else:
+      issue_assignee=data[i]['assignee']
+    issue_details['num']=issue_num
+    issue_details['title']=issue_title
+    issue_details['openedby']=issue_openedby
+    issue_details['assignee']=issue_assignee
+    all_issues.append(issue_details)
+  all_issues.reverse()
+  return dict(
+    org=org,
+    repo=repo,
+    all_issues=all_issues,
+    display_number=display_number,
+  )
+
+@hint()
+def should_invalidate(message, session, widget):
+  raise NotImplementedError

From 88cf4c67d22f7290ebd1fc636fc530a910711185 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 21 2016 21:57:55 +0000
Subject: [PATCH 268/1001] long_form isn't there yet.


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 68af7eb..093d551 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -120,7 +120,8 @@ def data(session, widget, username, fmn_context):
                 username=username,
             ))
             match['markup'] = match['markup'].replace(*args)
-            match['long_form'] = match['long_form'].replace(*args)
+            # TODO -- have to add these to conglomerate first
+            #match['long_form'] = match['long_form'].replace(*args)
 
         for package in match['packages']:
             args = (package, '<a href="{url}">{package}</a>'.format(
@@ -128,7 +129,8 @@ def data(session, widget, username, fmn_context):
                 package=package,
             ))
             match['markup'] = match['markup'].replace(*args)
-            match['long_form'] = match['long_form'].replace(*args)
+            # TODO -- have to add these to conglomerate first
+            #match['long_form'] = match['long_form'].replace(*args)
 
 
     return dict(

From 0bac6a7e507ef71aa5d9d85b23e1e29a6fd823e7 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 22 2016 14:41:56 +0000
Subject: [PATCH 269/1001] Whitespace.


---

diff --git a/fedmsg.d/base.py b/fedmsg.d/base.py
index 95612f9..6332b94 100644
--- a/fedmsg.d/base.py
+++ b/fedmsg.d/base.py
@@ -61,7 +61,7 @@ config = dict(
     zmq_tcp_keepalive_idle=60,
     zmq_tcp_keepalive_intvl=5,
 
-    # Number of miliseconds that zeromq will wait to reconnect until it gets 
+    # Number of miliseconds that zeromq will wait to reconnect until it gets
     # a connection if an endpoint is unavailable.
     zmq_reconnect_ivl=100,
     # Max delay that you can reconfigure to reduce reconnect storm spam. This
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index 3ec8ab1..c2ebfef 100644
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -50,9 +50,9 @@ template = jinja2.Template("""
 """)
 
 @argument(name="repo",
-	default=None,
-	validator=validators.repo,
-	help="Repo")
+          default=None,
+          validator=validators.repo,
+          help="Repo")
 def data(session, widget, display_number, org, repo):
   url = '/'.join(['https://api.github.com/repos',org,repo,"pulls"])
   pr_response = requests.get(url)
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
index 3eef711..f142bb3 100644
--- a/hubs/widgets/githubissues.py
+++ b/hubs/widgets/githubissues.py
@@ -50,9 +50,9 @@ template = jinja2.Template("""
 """)
 
 @argument(name="repo",
-	default=None,
-	validator=validators.repo,
-	help="Repo")
+          default=None,
+          validator=validators.repo,
+          help="Repo")
 def data(session, widget, display_number, org, repo):
   url = '/'.join(['https://api.github.com/repos',org,repo,"issues"])
   issue_response = requests.get(url)
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index f00ffd2..afd8b97 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -69,10 +69,10 @@ def data(session, widget, repo):
       pr_openedby=data['requests'][i]['user']['name'],
       pr_assignee=data['requests'][i]['assignee'],
     ))
-    all_pr.reverse() 
+    all_pr.reverse()
     return dict(all_pr=all_pr,
     total_req=total_req,
-    repo=repo,		
+    repo=repo,
 )
 
 @hint()
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index f64f0b4..8ec1608 100644
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -10,12 +10,12 @@ chrome = panel("Pagure: Newest Open Tickets")
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
-  <br /> 
+  <br />
   {% if message == "None" %}
     <div class="container">
       {% if total<3 %}
         {% for i in range(0,total) %}
-          <div> 
+          <div>
             <table class="table-responsive table-condensed">
               <tr>
                 <td valign="top" class="panel-heading">
@@ -36,14 +36,14 @@ template = jinja2.Template("""
                     {% else %}
                       <br /><i>Assigned by <a href="https://pagure.io/user/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
                     {% endif %}
-                  </font>               
+                  </font>
                 </td>
                 <td>
-	          <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
+                  <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
                     <button type="button" class="btn btn-default" aria-label="Left Align">
                       <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
                     </button>
-	          </a>
+                  </a>
                 </td>
               </tr>
             </table>
@@ -51,7 +51,7 @@ template = jinja2.Template("""
         {% endfor %}
       {% else %}
         {% for i in range(0,3) %}
-          <div> 
+          <div>
             <table class="table-responsive table-condensed">
               <tr>
                 <td valign="top" class="panel-heading">
@@ -72,21 +72,21 @@ template = jinja2.Template("""
                     {% else %}
                       <br /><i>Assigned to <a href="https://pagure.io/user/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
                     {% endif %}
-                  </font>               
+                  </font>
                 </td>
                 <td>
-	          <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
+                  <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
                     <button type="button" class="btn btn-default" aria-label="Left Align">
                       <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
                     </button>
-	          </a>
+                  </a>
                 </td>
               </tr>
             </table>
           </div>
         {% endfor %}
       {% endif %}
-    </div>    
+    </div>
     <div class="row">
       <a href="https://pagure.io/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
     </div>
@@ -143,7 +143,7 @@ def data(session, widget, repo):
         all_issues=all_issues,
         message = message,
       )
- 
+
 
 @hint()
 def should_invalidate(message, session, widget):

From 348ec745299d14fdbff1ed2cb33887532229be80 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 23 2016 02:45:13 +0000
Subject: [PATCH 270/1001] Clean up github PR widget.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 035eadd..326fe80 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -62,9 +62,8 @@ def add_user_widgets(session, hub, username, fullname):
     widget = hubs.models.Widget(
         plugin='github_pr', index=7,
         _config=json.dumps({
-             'display_number': 1,
-             'org': 'fedora-infra',
-             'repo': 'fas',
+            'organization': 'fedora-infra',
+            'display_number': 6,
         }))
     hub.widgets.append(widget)
     return hub
diff --git a/hubs/utils.py b/hubs/utils.py
index 0cbff18..f7f9e84 100644
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -1,7 +1,13 @@
+import logging
 from hashlib import sha256
 
+import arrow
+import requests
+
 from six.moves.urllib_parse import urlencode
 
+log = logging.getLogger(__name__)
+
 
 def username2avatar(username, s=312):
     query = urlencode({
@@ -16,3 +22,52 @@ def username2avatar(username, s=312):
 
 def commas(numeric):
     return "{:,}".format(numeric)
+
+def github_repos(token, username):
+    log.info("Finding github repos for %r" % username)
+    tmpl = "https://api.github.com/users/{username}/repos?per_page=100"
+    url = tmpl.format(username=username)
+    auth = dict(access_token=token)
+    for result in _github_results(url, auth):
+        yield result['name']
+
+
+def github_pulls(token, username, repo):
+    log.info("Finding github pull requests for %r %r" % (username, repo))
+    tmpl = "https://api.github.com/repos/{username}/{repo}/" + \
+        "pulls?per_page=100"
+    url = tmpl.format(username=username, repo=repo)
+    auth = dict(access_token=token)
+    for result in _github_results(url, auth):
+        yield dict(
+            user=result['user']['login'],
+            title=result['title'],
+            url=result['html_url'],
+            number=result['number'],
+            assignee=result['assignee'],
+            timestamp=arrow.get(result['created_at']).timestamp,
+        )
+
+
+def _github_results(url, auth):
+    link = dict(next=url)
+    while 'next' in link:
+        response = requests.get(link['next'], params=auth)
+
+        # And.. if we didn't get good results, just bail.
+        if not bool(response):
+            raise IOError("Failed on %r %r" % (link['next'], response))
+
+        results = response.json()
+        for result in results:
+            yield result
+
+        field = response.headers.get('link', None)
+        link = dict()
+        if field:
+            link = dict([
+                (
+                    part.split('; ')[1][5:-1],
+                    part.split('; ')[0][1:-1],
+                ) for part in field.split(', ')
+            ])
diff --git a/hubs/validators.py b/hubs/validators.py
index 8248b29..0dec579 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -9,6 +9,9 @@ def required(session, value):
 def text(session, value):
     return kitchen.text.converters.to_unicode(value)
 
+def integer(session, value):
+    return int(value)
+
 def link(session, value):
     # TODO -- verify that this is actually a link
     return value
@@ -17,6 +20,10 @@ def username(session, value):
     openid = 'http://%s.id.fedoraproject.org/' % value
     return not hubs.models.User.by_openid(session, openid) is None
 
+def github_organization(session, value):
+    # TODO -- implement this.
+    return True
+
 def fmn_context(session, value):
     # TODO get this from the fedmsg config.
     return value in [
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index c2ebfef..6a33091 100644
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -1,11 +1,20 @@
+import logging
+
 from hubs.widgets.chrome import panel
 from hubs.hinting import hint
 from hubs.widgets.base import argument
+
 import hubs.validators as validators
+import hubs.utils
+
+import fedmsg.config
+config = fedmsg.config.load_config()
+
 import jinja2
-import requests
 
-chrome = panel("Github: Open Pull Requests")
+log = logging.getLogger(__name__)
+
+chrome = panel("Github: Pull Requests")
 
 template = jinja2.Template("""
   <br />
@@ -14,10 +23,10 @@ template = jinja2.Template("""
       <table class="table-responsive table-condensed">
         <tr>
           <td valign="top" class="panel-heading">
-            <b>#{{ all_pr[i]['num'] }}</b>
+            <b>#{{ pulls[i]['number'] }}</b>
           </td>
           <td width="300px">
-            <b>{{ all_pr[i]['title'] }}</b>
+            <b>{{ pulls[i]['title'] }}</b>
           </td>
         </tr>
       </table>
@@ -25,16 +34,16 @@ template = jinja2.Template("""
         <tr>
           <td width="300px">
             <font size="2">
-              <i>Opened by <a href="https://github.com/{{ all_pr[i]['openedby'] }}" target="_blank">{{ all_pr[i]['openedby'] }}</a></i>
-              {% if all_pr[i]['assignee']|string() == "None" %}
+              <i>Opened by <a href="https://github.com/{{ pulls[i]['user'] }}" target="_blank">{{ pulls[i]['user'] }}</a></i>
+              {% if pulls[i]['assignee']|string() == "None" %}
                 <br /><i>Unclaimed</i>
               {% else %}
-                 <br /><i>Assigned by <a href="https://github.com/{{ all_pr[i]['assignee'] }}" target="_blank">{{ all_pr[i]['assignee'] }}</a></i>
+                 <br /><i>Assigned by <a href="https://github.com/{{ pulls[i]['assignee'] }}" target="_blank">{{ pulls[i]['assignee'] }}</a></i>
               {% endif %}
             </font>
           </td>
           <td>
-             <a href="https://github.com/{{ org }}/{{ repo }}/pulls/{{ all_pr[i]['num'] }}" target="_blank">
+             <a href="{{ pulls[i]['url'] }}" target="_blank">
                <button type="button" class="btn btn-default" aria-label="Left Align">
                  <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
                </button>
@@ -44,42 +53,48 @@ template = jinja2.Template("""
       </table>
     </div>
     {% endfor %}
+    {% if more != 0 %}
     <div class="row">
-      <a href="https://github.com/{{ org }}/{{ repo }}/pulls" target="_blank"><center>All Pull Requests</center></a>
+      <a href="https://github.com/{{ organization }}" target="_blank"><center>and {{ more }} more</center></a>
     </div>
+    {% endif %}
 """)
 
-@argument(name="repo",
+
+@argument(name="display_number",
+          default=6,
+          validator=validators.integer,
+          help="How many pull requests to display at max.")
+@argument(name="organization",
           default=None,
-          validator=validators.repo,
-          help="Repo")
-def data(session, widget, display_number, org, repo):
-  url = '/'.join(['https://api.github.com/repos',org,repo,"pulls"])
-  pr_response = requests.get(url)
-  data = pr_response.json()
-  all_pr = list()
-  for i in range(0,1):
-    pr_details=dict()
-    pr_num=data[i]['number']
-    pr_title=data[i]['title']
-    pr_openedby=data[i]['user']['login']
-    if(data[i]['assignee']!=None):
-      pr_assignee=data[i]['assignee']['login']
-    else:
-      pr_assignee=data[i]['assignee']
-    pr_details['num']=pr_num
-    pr_details['title']=pr_title
-    pr_details['openedby']=pr_openedby
-    pr_details['assignee']=pr_assignee
-    all_pr.append(pr_details)
-  all_pr.reverse()
-  return dict(
-    org=org,
-    repo=repo,
-    all_pr=all_pr,
-    display_number=display_number,
-  )
+          validator=validators.github_organization,
+          help="Github Organization or username")
+def data(session, widget, display_number, organization):
+    log.info("Getting GH prs for %r, (%r)" % (organization, display_number))
+    token = config['github.oauth_token']
+    org = organization
+    repos = hubs.utils.github_repos(token, org)
+    pulls = sum([
+        list(hubs.utils.github_pulls(token, org, repo))
+        for repo in repos
+    ], [])
+    # Reverse-sort by time (newest-first)
+    pulls.sort(lambda a, b: cmp(b['timestamp'], a['timestamp']))
+
+    # Some hints for display
+    display_number = min(display_number, len(pulls))
+    more = len(pulls) - display_number
+    if more < 0:
+        more = 0
+
+    return dict(
+        organization=org,
+        display_number=display_number,
+        more=more,
+        pulls=pulls,
+    )
+
 
 @hint()
 def should_invalidate(message, session, widget):
-  raise NotImplementedError
+    raise NotImplementedError

From 7d9dcd4bdc61fec5ad89e49f69fd037691448a3f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Jan 30 2016 19:08:16 +0000
Subject: [PATCH 271/1001] Crank this up for now.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 326fe80..3856d78 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -63,7 +63,7 @@ def add_user_widgets(session, hub, username, fullname):
         plugin='github_pr', index=7,
         _config=json.dumps({
             'organization': 'fedora-infra',
-            'display_number': 6,
+            'display_number': 15,
         }))
     hub.widgets.append(widget)
     return hub

From ad56f9ad6629e174d46288b08593340839941cba Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 15:14:38 +0000
Subject: [PATCH 272/1001] List html5lib as a dependency


---

diff --git a/requirements.txt b/requirements.txt
index 844a2ec..db88974 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,3 +12,4 @@ datanommer.models
 psycopg2
 gunicorn
 pytz
+html5lib

From 2a383508814a2a66372f3bc2694d2806a6daba59 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 15:15:11 +0000
Subject: [PATCH 273/1001] Sort the dependency list by alphabetical order


---

diff --git a/requirements.txt b/requirements.txt
index db88974..803a544 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,15 +1,15 @@
-flask
-sqlalchemy
-fedmsg
+arrow
+datanommer.models
 dogpile.cache
+fedmsg
 fedmsg_meta_fedora_infrastructure
+flask
 flask-openid
-munch
-arrow
 fmn.lib
 fmn.rules
-datanommer.models
-psycopg2
 gunicorn
-pytz
 html5lib
+munch
+psycopg2
+pytz
+sqlalchemy

From 78880b7e17d4e25bdeb20b28036d936a829554df Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 15:42:44 +0000
Subject: [PATCH 274/1001] Rename the pagure repo validator to pagure_repo


As otherwise we could conflict with other repo (distgit, github...)

---

diff --git a/hubs/validators.py b/hubs/validators.py
index 0dec579..9c2c276 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -30,5 +30,5 @@ def fmn_context(session, value):
         'irc', 'email', 'android', 'desktop', 'hubs',
     ]
 
-def repo(session, value):
+def pagure_repo(session, value):
     return value
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index afd8b97..331bb7a 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -53,8 +53,8 @@ template = jinja2.Template("""
 
 @argument(name="repo",
           default=None,
-          validator=validators.repo,
-          help="Repo")
+          validator=validators.pagure_repo,
+          help="Pagure repo name")
 def data(session, widget, repo):
     repo="pagure"
     url = '/'.join([pagure_url, repo, "pull-requests"])

From 26512d02743b43209dada53ec8ed578cdd075dad Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 15:43:17 +0000
Subject: [PATCH 275/1001] Fix indentation


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 331bb7a..9e38b2a 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -63,17 +63,20 @@ def data(session, widget, repo):
     total_req = data['total_requests']
     all_pr = list()
     for i in range(0,total_req):
-      all_pr.append(dict(
-      pr_id=data['requests'][i]['id'],
-      pr_title=data['requests'][i]['title'][:45],
-      pr_openedby=data['requests'][i]['user']['name'],
-      pr_assignee=data['requests'][i]['assignee'],
-    ))
+        all_pr.append(
+            dict(
+                  pr_id=data['requests'][i]['id'],
+                  pr_title=data['requests'][i]['title'][:45],
+                  pr_openedby=data['requests'][i]['user']['name'],
+                  pr_assignee=data['requests'][i]['assignee'],
+            )
+        )
     all_pr.reverse()
-    return dict(all_pr=all_pr,
-    total_req=total_req,
-    repo=repo,
-)
+    return dict(
+        all_pr=all_pr,
+        total_req=total_req,
+        repo=repo,
+    )
 
 @hint()
 def should_invalidate(message, session, widget):

From e38c26d85e1cda0761a9cfa90e9e13c17e4520ac Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 15:44:20 +0000
Subject: [PATCH 276/1001] Adjust pagureissues to the new validator


---

diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index 8ec1608..d429c52 100644
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -99,8 +99,8 @@ template = jinja2.Template("""
 
 @argument(name="repo",
           default=None,
-          validator=validators.repo,
-          help="Repo")
+          validator=validators.pagure_repo,
+          help="Pagure repo name")
 def data(session, widget, repo):
     repo = "pagure"
 

From d7bcdf1c53d5c28fbe8aaa55fa3fd3f95afddb4e Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 15:44:32 +0000
Subject: [PATCH 277/1001] Be consistent in the github widget regarding help message and validator


---

diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
index f142bb3..feabd5e 100644
--- a/hubs/widgets/githubissues.py
+++ b/hubs/widgets/githubissues.py
@@ -51,8 +51,8 @@ template = jinja2.Template("""
 
 @argument(name="repo",
           default=None,
-          validator=validators.repo,
-          help="Repo")
+          validator=validators.github_organization,
+          help="Github Organization or username")
 def data(session, widget, display_number, org, repo):
   url = '/'.join(['https://api.github.com/repos',org,repo,"issues"])
   issue_response = requests.get(url)

From 9247c4df902b1c50fb7562db405158e25101e77d Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 15:48:24 +0000
Subject: [PATCH 278/1001] Indicate where the app is when running it with gunicorn


---

diff --git a/README.rst b/README.rst
index 5d45d4d..3897a15 100644
--- a/README.rst
+++ b/README.rst
@@ -53,6 +53,8 @@ If you want to test it with 8 worker threads, try ``gunicorn``::
     $ pip install gunicorn
     $ gunicorn -w 8 -t 60 --log-config logging.ini --reload hubs.app:app
 
+Note that then tje application is available at http://localhost:8000/
+
 When hacking on widgets, it is useful to have this one-liner handy.  It removes
 the db alltogether, re-populates it, and restarts the app::
 

From 5cc2bf3309f1b13091ac2cb58f3d6c53bd7e34e1 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 16:05:13 +0000
Subject: [PATCH 279/1001] Remove <br /> tags and fix indentation of the template


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 9e38b2a..f041113 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -9,42 +9,43 @@ chrome = panel("Pagure: Newest Open Pull Requests")
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
-  <br />
-    <div class="container">
-      {% for i in range(0,total_req) %}
-        <div>
-          <table class="table-responsive table-condensed">
-            <tr>
-              <td valign="top" class="panel-heading">
-                <b>#{{ all_pr[i]['pr_id'] }}</b>
-              </td>
-              <td width="260px">
-                <b>{{ all_pr[i]['pr_title'] }} ...</b>
-              </td>
-            </tr>
-           </table>
-         <table class="table-responsive table-condensed">
-            <tr>
-              <td width="280px" >
-                <font size="2">
-                  <i>Opened by <a href="https://pagure.io/user/{{ all_pr[i]['pr_openedby'] }}" target="_blank">{{ all_pr[i]['pr_openedby'] }}</a>
-                  {% if all_pr[i]['pr_assignee'] %}
-                    <br>Assigned to <a href="https://pagure.io/user/{{ all_pr[i]['pr_assignee'] }}" target="_blank">{{ all_pr[i]['pr_assignee'] }}</a></i>
-                  {% endif %}
-                </font>
-              </td>
-              <td>
-                <a href="https://pagure.io/{{ repo }}/pull-request/{{ all_pr[i]['pr_id'] }}" target="_blank">
-                  <button type="button" class="btn btn-default" aria-label="Left Align">
-                    <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-                  </button>
-                </a>
-              </td>
-            </tr>
-          </table>
-        </div>
-      {%endfor%}
-    <br />
+  <div class="container">
+    {% for i in range(0,total_req) %}
+      <div>
+        <table class="table-responsive table-condensed">
+          <tr>
+            <td valign="top" class="panel-heading">
+              <img src="{{ url_for(
+                  'static', filename='img/pagure_logo.png')
+                }}" alt="Pagure logo" />
+              <b>#{{ all_pr[i]['pr_id'] }}</b>
+            </td>
+            <td width="260px">
+              <b>{{ all_pr[i]['pr_title'] }} ...</b>
+            </td>
+          </tr>
+         </table>
+       <table class="table-responsive table-condensed">
+          <tr>
+            <td width="280px" >
+              <font size="2">
+                <i>Opened by <a href="https://pagure.io/user/{{ all_pr[i]['pr_openedby'] }}" target="_blank">{{ all_pr[i]['pr_openedby'] }}</a>
+                {% if all_pr[i]['pr_assignee'] %}
+                  <br>Assigned to <a href="https://pagure.io/user/{{ all_pr[i]['pr_assignee'] }}" target="_blank">{{ all_pr[i]['pr_assignee'] }}</a></i>
+                {% endif %}
+              </font>
+            </td>
+            <td>
+              <a href="https://pagure.io/{{ repo }}/pull-request/{{ all_pr[i]['pr_id'] }}" target="_blank">
+                <button type="button" class="btn btn-default" aria-label="Left Align">
+                  <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+                </button>
+              </a>
+            </td>
+          </tr>
+        </table>
+      </div>
+    {%endfor%}
     </div class="row">
       <center><a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">All Pull-Requests</a><center>
     </div>

From cd3b70b5220db284ab38e009f37b8e5924021f00 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 16:38:48 +0000
Subject: [PATCH 280/1001] Rework the pagure widget for open PR


- Adjust the HTML to be more consistent with the layout in pagure itself
and use the entire container.
- Include the project name since at the end we want to be able to list
Open PRs for multiple projects hosted on pagure.
- Change the title a little to not mis-lead that the PR are on pagure not
necessarily about pagure

---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index f041113..2c5207e 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -4,48 +4,66 @@ import jinja2
 import requests
 from hubs.widgets.base import argument
 import hubs.validators as validators
-chrome = panel("Pagure: Newest Open Pull Requests")
+chrome = panel("Newest Open Pull Requests on Pagure")
 
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
   <div class="container">
-    {% for i in range(0,total_req) %}
-      <div>
-        <table class="table-responsive table-condensed">
-          <tr>
-            <td valign="top" class="panel-heading">
-              <img src="{{ url_for(
-                  'static', filename='img/pagure_logo.png')
-                }}" alt="Pagure logo" />
-              <b>#{{ all_pr[i]['pr_id'] }}</b>
-            </td>
-            <td width="260px">
-              <b>{{ all_pr[i]['pr_title'] }} ...</b>
-            </td>
-          </tr>
-         </table>
-       <table class="table-responsive table-condensed">
-          <tr>
-            <td width="280px" >
-              <font size="2">
-                <i>Opened by <a href="https://pagure.io/user/{{ all_pr[i]['pr_openedby'] }}" target="_blank">{{ all_pr[i]['pr_openedby'] }}</a>
-                {% if all_pr[i]['pr_assignee'] %}
-                  <br>Assigned to <a href="https://pagure.io/user/{{ all_pr[i]['pr_assignee'] }}" target="_blank">{{ all_pr[i]['pr_assignee'] }}</a></i>
-                {% endif %}
-              </font>
-            </td>
-            <td>
-              <a href="https://pagure.io/{{ repo }}/pull-request/{{ all_pr[i]['pr_id'] }}" target="_blank">
-                <button type="button" class="btn btn-default" aria-label="Left Align">
-                  <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-                </button>
+    <table id="pagure-issues-list" class="table table-hover table-striped m-b-0">
+      <thead class="thead-default">
+        <tr>
+          <th id="pr-title">Project</th>
+          <th id="pr-title">Pull-Request</th>
+          <th class="open_by">Reporter</th>
+          <th class="assigned">Assignee</th>
+        </tr>
+      </thead>
+      <tfoot>
+      </tfoot>
+      <tbody>
+        {% for pr in all_pr %}
+        <tr>
+          <td>
+            {% if pr['pr_project_user'] %}
+            <a href="https://pagure.io/forks/{{
+                pr['pr_project_user'] }}/{{ pr['pr_project_name'] }}"
+              target="_blank">
+              {{ pr['pr_project_user'] }}/{{ pr['pr_project_name'] }}
+            {% else %}
+            <a href="https://pagure.io/{{ pr['pr_project_name'] }}"
+              target="_blank">
+              {{ pr['pr_project_name'] }}
+            {% endif %}
+            </a>
+          </td>
+          <td>
+            <span class="label label-default">#{{ pr['pr_id'] }}</span>
+            <a href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
+                target="_blank">
+              {{ pr['pr_title'] }} ...
+            </a>
+          </td>
+          <td>
+            <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
+                target="_blank">
+              {{ pr['pr_openedby'] }}
+            </a>
+          </td>
+          <td>
+            {% if pr['pr_assignee'] %}
+              <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
+                  target="_blank">
+                {{ pr['pr_assignee'] }}
               </a>
-            </td>
-          </tr>
-        </table>
-      </div>
-    {%endfor%}
+            {% else %}
+              <span class="text-muted">unassigned</span>
+            {% endif %}
+          </td>
+        </tr>
+        {% endfor %}
+      </tbody>
+    </table>
     </div class="row">
       <center><a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">All Pull-Requests</a><center>
     </div>
@@ -63,16 +81,22 @@ def data(session, widget, repo):
     data = response.json()
     total_req = data['total_requests']
     all_pr = list()
-    for i in range(0,total_req):
+    for i in range(0, total_req):
+        pr_project_user = None
+        if data['requests'][i]['project']['parent']:
+            pr_project_user = data['requests'][i]['project']['user']['username']
+
         all_pr.append(
             dict(
+                  pr_project_name=data['requests'][i]['project']['name'],
+                  pr_project_user=pr_project_user,
                   pr_id=data['requests'][i]['id'],
                   pr_title=data['requests'][i]['title'][:45],
                   pr_openedby=data['requests'][i]['user']['name'],
                   pr_assignee=data['requests'][i]['assignee'],
             )
         )
-    all_pr.reverse()
+
     return dict(
         all_pr=all_pr,
         total_req=total_req,

From 759f11e9899cd017382521e31bb3ebfec9c9192e Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 16:42:00 +0000
Subject: [PATCH 281/1001] Fix link in the icon in the feed widget


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 093d551..19b1c27 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -36,7 +36,7 @@ template = jinja2.Template("""
   <div class="panel-body">
     <div class="media">
       <div class="media-left">
-        <a href="{{match['link']}} target="_blank">
+        <a href="{{match['link']}}" target="_blank">
           <img class="media-object square-32 img-circle" src="{{match['secondary_icon']}}">
         </a>
       </div>

From 64225d46dbc8bc31530c547fa4f11b72e68e2d4e Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 16:53:12 +0000
Subject: [PATCH 282/1001] pep8 fixes


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 2c5207e..d86272c 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -10,7 +10,8 @@ pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
   <div class="container">
-    <table id="pagure-issues-list" class="table table-hover table-striped m-b-0">
+    <table id="pagure-issues-list"
+        class="table table-hover table-striped m-b-0">
       <thead class="thead-default">
         <tr>
           <th id="pr-title">Project</th>
@@ -31,16 +32,16 @@ template = jinja2.Template("""
               target="_blank">
               {{ pr['pr_project_user'] }}/{{ pr['pr_project_name'] }}
             {% else %}
-            <a href="https://pagure.io/{{ pr['pr_project_name'] }}"
-              target="_blank">
+            <a href="https://pagure.io/{{
+              pr['pr_project_name'] }}" target="_blank">
               {{ pr['pr_project_name'] }}
             {% endif %}
             </a>
           </td>
           <td>
             <span class="label label-default">#{{ pr['pr_id'] }}</span>
-            <a href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
-                target="_blank">
+            <a href="https://pagure.io/{{ repo }}/pull-request/{{
+              pr['pr_id'] }}" target="_blank">
               {{ pr['pr_title'] }} ...
             </a>
           </td>
@@ -65,17 +66,22 @@ template = jinja2.Template("""
       </tbody>
     </table>
     </div class="row">
-      <center><a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">All Pull-Requests</a><center>
+      <center>
+        <a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">
+          All Pull-Requests
+        </a>
+      <center>
     </div>
   </div>
 """)
 
+
 @argument(name="repo",
           default=None,
           validator=validators.pagure_repo,
           help="Pagure repo name")
 def data(session, widget, repo):
-    repo="pagure"
+    repo = "pagure"
     url = '/'.join([pagure_url, repo, "pull-requests"])
     response = requests.get(url)
     data = response.json()
@@ -84,16 +90,17 @@ def data(session, widget, repo):
     for i in range(0, total_req):
         pr_project_user = None
         if data['requests'][i]['project']['parent']:
-            pr_project_user = data['requests'][i]['project']['user']['username']
+            pr_project_user = \
+                data['requests'][i]['project']['user']['username']
 
         all_pr.append(
             dict(
-                  pr_project_name=data['requests'][i]['project']['name'],
-                  pr_project_user=pr_project_user,
-                  pr_id=data['requests'][i]['id'],
-                  pr_title=data['requests'][i]['title'][:45],
-                  pr_openedby=data['requests'][i]['user']['name'],
-                  pr_assignee=data['requests'][i]['assignee'],
+                pr_project_name=data['requests'][i]['project']['name'],
+                pr_project_user=pr_project_user,
+                pr_id=data['requests'][i]['id'],
+                pr_title=data['requests'][i]['title'][:45],
+                pr_openedby=data['requests'][i]['user']['name'],
+                pr_assignee=data['requests'][i]['assignee'],
             )
         )
 
@@ -103,6 +110,7 @@ def data(session, widget, repo):
         repo=repo,
     )
 
+
 @hint()
 def should_invalidate(message, session, widget):
-   raise NotImplementedError
+    raise NotImplementedError

From 3ce7a92b3f7e393f361cb1b05abf01f44ffb0c76 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 17:59:27 +0000
Subject: [PATCH 283/1001] Adjust CSS id in the HTML to reflect what they are


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index d86272c..0e99f56 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -10,11 +10,11 @@ pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
   <div class="container">
-    <table id="pagure-issues-list"
+    <table id="pagure-pr-list"
         class="table table-hover table-striped m-b-0">
       <thead class="thead-default">
         <tr>
-          <th id="pr-title">Project</th>
+          <th id="project-title">Project</th>
           <th id="pr-title">Pull-Request</th>
           <th class="open_by">Reporter</th>
           <th class="assigned">Assignee</th>

From a534b962416df1ed7a625f117f898ed23bde12dd Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 17:59:46 +0000
Subject: [PATCH 284/1001] Let's use a more pythonic loop rather than relying on range()


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 0e99f56..22b5e4b 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -81,26 +81,24 @@ template = jinja2.Template("""
           validator=validators.pagure_repo,
           help="Pagure repo name")
 def data(session, widget, repo):
-    repo = "pagure"
     url = '/'.join([pagure_url, repo, "pull-requests"])
     response = requests.get(url)
     data = response.json()
     total_req = data['total_requests']
     all_pr = list()
-    for i in range(0, total_req):
+    for request in data['requests']:
         pr_project_user = None
-        if data['requests'][i]['project']['parent']:
-            pr_project_user = \
-                data['requests'][i]['project']['user']['username']
+        if request['project']['parent']:
+            pr_project_user = request['project']['user']['username']
 
         all_pr.append(
             dict(
-                pr_project_name=data['requests'][i]['project']['name'],
+                pr_project_name=request['project']['name'],
                 pr_project_user=pr_project_user,
-                pr_id=data['requests'][i]['id'],
-                pr_title=data['requests'][i]['title'][:45],
-                pr_openedby=data['requests'][i]['user']['name'],
-                pr_assignee=data['requests'][i]['assignee'],
+                pr_id=request['id'],
+                pr_title=request['title'][:45],
+                pr_openedby=request['user']['name'],
+                pr_assignee=request['assignee'],
             )
         )
 

From 8ac2a2f6431436a4fbe041ac3e3e5b269361118f Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 18:27:03 +0000
Subject: [PATCH 285/1001] Rework the widget for issues on pagure


---

diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index 8ec1608..9fa8f76 100644
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -5,98 +5,78 @@ import hubs.validators as validators
 import jinja2
 import requests
 
-chrome = panel("Pagure: Newest Open Tickets")
+chrome = panel("Newest Open Tickets on Pagure")
 
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
-  <br />
-  {% if message == "None" %}
-    <div class="container">
-      {% if total<3 %}
-        {% for i in range(0,total) %}
-          <div>
-            <table class="table-responsive table-condensed">
-              <tr>
-                <td valign="top" class="panel-heading">
-                  <b>#{{ all_issues[i]['id'] }}</b>
-                </td>
-                <td width="260px">
-                  <b>{{ all_issues[i]['title'] }}</b>
-                </td>
-              </tr>
-            </table>
-            <table class="table-responsive table-condensed">
-              <tr>
-                <td width="260px">
-                  <font size="2">
-                    <i>Opened by <a href="https://pagure.io/user/{{ all_issues[i]['user'] }}" target="_blank">{{ all_issues[i]['user'] }}</a></i>
-                    {% if all_issues[i]['assignee']|string() == "None" %}
-                      <br /><i>Unclaimed</i>
-                    {% else %}
-                      <br /><i>Assigned by <a href="https://pagure.io/user/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
-                    {% endif %}
-                  </font>
-                </td>
-                <td>
-                  <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
-                    <button type="button" class="btn btn-default" aria-label="Left Align">
-                      <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-                    </button>
-                  </a>
-                </td>
-              </tr>
-            </table>
-          </div>
+  <div class="container">
+    <table id="pagure-issues-list"
+        class="table table-hover table-striped m-b-0">
+      <thead class="thead-default">
+        <tr>
+          <th id="project-title">Project</th>
+          <th id="issue-title">Issue</th>
+          <th class="open_by">Reporter</th>
+          <th class="assigned">Assignee</th>
+        </tr>
+      </thead>
+      <tfoot>
+      </tfoot>
+      <tbody>
+        {% for issue in all_issues %}
+        <tr>
+          <td>
+            {% if issue['issue_project_user'] %}
+            <a href="https://pagure.io/forks/{{
+                issue['issue_project_user'] }}/{{ issue['issue_project_name'] }}"
+              target="_blank">
+              {{ issue['issue_project_user'] }}/{{ issue['issue_project_name'] }}
+            {% else %}
+            <a href="https://pagure.io/{{
+              issue['issue_project_name'] }}" target="_blank">
+              {{ issue['issue_project_name'] }}
+            {% endif %}
+            </a>
+          </td>
+          <td>
+            <span class="label label-default">#{{ issue['issue_id'] }}</span>
+            <a href="https://pagure.io/{{ repo }}/pull-request/{{
+             issue['issue_id'] }}" target="_blank">
+              {{ issue['issue_title'] }} ...
+            </a>
+          </td>
+          <td>
+            <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
+                target="_blank">
+              {{ issue['issue_openedby'] }}
+            </a>
+          </td>
+          <td>
+            {% if issue['issue_assignee'] %}
+              <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
+                  target="_blank">
+                {{issue['issue_assignee'] }}
+              </a>
+            {% else %}
+              <span class="text-muted">unassigned</span>
+            {% endif %}
+          </td>
+        </tr>
         {% endfor %}
-      {% else %}
-        {% for i in range(0,3) %}
-          <div>
-            <table class="table-responsive table-condensed">
-              <tr>
-                <td valign="top" class="panel-heading">
-                  <b>#{{ all_issues[i]['id'] }}</b>
-                </td>
-                <td width="260px">
-                  <b>{{ all_issues[i]['title'] }}</b>
-                </td>
-              </tr>
-            </table>
-            <table class="table-responsive table-condensed">
-              <tr>
-                <td width="260px">
-                  <font size="2">
-                    <i>Opened by <a href="https://pagure.io/user/{{ all_issues[i]['user'] }}" target="_blank">{{ all_issues[i]['user'] }}</a></i>
-                    {% if all_issues[i]['assignee']|string() == "None" %}
-                      <br /><i>Unclaimed</i>
-                    {% else %}
-                      <br /><i>Assigned to <a href="https://pagure.io/user/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
-                    {% endif %}
-                  </font>
-                </td>
-                <td>
-                  <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
-                    <button type="button" class="btn btn-default" aria-label="Left Align">
-                      <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-                    </button>
-                  </a>
-                </td>
-              </tr>
-            </table>
-          </div>
-        {% endfor %}
-      {% endif %}
-    </div>
-    <div class="row">
-      <a href="https://pagure.io/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
-    </div>
-  {% else %}
-    <div class="container">
-      <b>Not a valid repo</b>
+      </tbody>
+    </table>
+    </div class="row">
+      <center>
+        <a href="https://pagure.io/{{ repo }}/issues" target="_blank">
+          All Issues
+        </a>
+      <center>
     </div>
-  {% endif %}
+  </div>
 """)
 
+
 @argument(name="repo",
           default=None,
           validator=validators.repo,
@@ -104,45 +84,44 @@ template = jinja2.Template("""
 def data(session, widget, repo):
     repo = "pagure"
 
-    projects_response = requests.get("https://pagure.io/api/0/projects")
-    projects_data = projects_response.json()
-    total_projects = projects_data['total_projects']
-    all_projects = list()
-    for i in range(0, total_projects):
-      all_projects.append(projects_data['projects'][i]['name'])
-    if repo not in all_projects:
-      message = "Not a valid project"
-      return dict(
-        message=message,
-      )
-    else:
-      message = "None"
-      url = '/'.join([pagure_url, repo, "issues"])
-      issue_response = requests.get(url)
-      data = issue_response.json()
-      total = data['total_issues']
-      all_issues = list()
-      for i in range(0,total):
-        issue_details = dict()
-        issue_id=data['issues'][i]['id']
-        issue_title=data['issues'][i]['title']
-        issue_user=data['issues'][i]['user']['name']
-        if(data['issues'][i]['assignee']!=None):
-          issue_assignee=data['issues'][i]['assignee']['name']
+    url = '/'.join([pagure_url, repo, "issues"])
+    issue_response = requests.get(url)
+    data = issue_response.json()
+    total = data['total_issues']
+
+    all_issues = list()
+    for issue in data['issues']:
+
+        issue_assignee = None
+        if issue['assignee']:
+            issue_assignee=issue['assignee']['name']
+
+        issue_project_user = None
+        if 'project' in issue:
+          issue_project_name = issue['project']['name']
+          if issue['project']['parent']:
+            issue_project_user = issue['project']['user']['username']
         else:
-          issue_assignee=data['issues'][i]['assignee']
-        issue_details['id']=issue_id
-        issue_details['title']=issue_title
-        issue_details['user']=issue_user
-        issue_details['assignee']=issue_assignee
-        all_issues.append(issue_details)
-      all_issues.reverse()
-      return dict(
+            issue_project_name = repo
+
+        all_issues.append(
+          dict(
+            issue_project_name=issue_project_name,
+            issue_project_user=issue_project_user,
+            issue_id=issue['id'],
+            issue_title=issue['title'],
+            issue_openedby=issue['user']['name'],
+            issue_assignee=issue_assignee,
+          )
+        )
+
+    all_issues.reverse()
+
+    return dict(
         repo=repo,
         total=total,
         all_issues=all_issues,
-        message = message,
-      )
+    )
 
 
 @hint()

From 068c67b9c04fa24e635a44a1fefe97106c52669f Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 18:31:34 +0000
Subject: [PATCH 286/1001] Allow the repo name to be a fork ie: <user>/<project>


---

diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index 9fa8f76..58a03fc 100644
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -102,7 +102,10 @@ def data(session, widget, repo):
           if issue['project']['parent']:
             issue_project_user = issue['project']['user']['username']
         else:
-            issue_project_name = repo
+            if '/' in repo:
+                issue_project_name, issue_project_user = repo.split('/', 1)
+            else:
+              issue_project_name = repo
 
         all_issues.append(
           dict(

From 263f2756f3bae81a531a3d509bec9a570a8e9b8d Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 18:35:08 +0000
Subject: [PATCH 287/1001] Use short title in the link but the full one in the title of the link


---

diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index 58a03fc..04294be 100644
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -42,7 +42,8 @@ template = jinja2.Template("""
           <td>
             <span class="label label-default">#{{ issue['issue_id'] }}</span>
             <a href="https://pagure.io/{{ repo }}/pull-request/{{
-             issue['issue_id'] }}" target="_blank">
+             issue['issue_id'] }}" target="_blank"
+             title="{{ issue['issue_title_full'] }}">>
               {{ issue['issue_title'] }} ...
             </a>
           </td>
@@ -112,7 +113,8 @@ def data(session, widget, repo):
             issue_project_name=issue_project_name,
             issue_project_user=issue_project_user,
             issue_id=issue['id'],
-            issue_title=issue['title'],
+            issue_title=issue['title'][:45],
+            issue_title_full=issue['title'],
             issue_openedby=issue['user']['name'],
             issue_assignee=issue_assignee,
           )

From bbcdf25fe5e5b908ac290ac85c6943ab6f01c353 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 09 2016 18:36:59 +0000
Subject: [PATCH 288/1001] Use short title in the link but the full one in the title of the link


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 22b5e4b..055d37a 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -41,7 +41,8 @@ template = jinja2.Template("""
           <td>
             <span class="label label-default">#{{ pr['pr_id'] }}</span>
             <a href="https://pagure.io/{{ repo }}/pull-request/{{
-              pr['pr_id'] }}" target="_blank">
+              pr['pr_id'] }}" target="_blank"
+              title="{{ pr['pr_title_full'] }}">
               {{ pr['pr_title'] }} ...
             </a>
           </td>
@@ -86,6 +87,7 @@ def data(session, widget, repo):
     data = response.json()
     total_req = data['total_requests']
     all_pr = list()
+
     for request in data['requests']:
         pr_project_user = None
         if request['project']['parent']:
@@ -97,6 +99,7 @@ def data(session, widget, repo):
                 pr_project_user=pr_project_user,
                 pr_id=request['id'],
                 pr_title=request['title'][:45],
+                pr_title_full=request['title'],
                 pr_openedby=request['user']['name'],
                 pr_assignee=request['assignee'],
             )

From 22cfbb4546d8a19276856cfe996eb0edb08ae575 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Feb 10 2016 09:46:30 +0000
Subject: [PATCH 289/1001] Merge #75 `Indicate where the app is when running it with gunicorn`


---

diff --git a/README.rst b/README.rst
index 5d45d4d..3897a15 100644
--- a/README.rst
+++ b/README.rst
@@ -53,6 +53,8 @@ If you want to test it with 8 worker threads, try ``gunicorn``::
     $ pip install gunicorn
     $ gunicorn -w 8 -t 60 --log-config logging.ini --reload hubs.app:app
 
+Note that then tje application is available at http://localhost:8000/
+
 When hacking on widgets, it is useful to have this one-liner handy.  It removes
 the db alltogether, re-populates it, and restarts the app::
 

From 96873279fe845c799a619e15f0a84f4ba76f5770 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Feb 10 2016 09:46:54 +0000
Subject: [PATCH 290/1001] Typofix.


---

diff --git a/README.rst b/README.rst
index 3897a15..264e5a2 100644
--- a/README.rst
+++ b/README.rst
@@ -53,7 +53,7 @@ If you want to test it with 8 worker threads, try ``gunicorn``::
     $ pip install gunicorn
     $ gunicorn -w 8 -t 60 --log-config logging.ini --reload hubs.app:app
 
-Note that then tje application is available at http://localhost:8000/
+Note that then the application is available at http://localhost:8000/
 
 When hacking on widgets, it is useful to have this one-liner handy.  It removes
 the db alltogether, re-populates it, and restarts the app::

From 8a2b179806e5b071fd00964e71c0e3c02b19dbb3 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Feb 10 2016 09:47:24 +0000
Subject: [PATCH 291/1001] Merge #76 `Fix link in the icon in the feed widget`


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 093d551..19b1c27 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -36,7 +36,7 @@ template = jinja2.Template("""
   <div class="panel-body">
     <div class="media">
       <div class="media-left">
-        <a href="{{match['link']}} target="_blank">
+        <a href="{{match['link']}}" target="_blank">
           <img class="media-object square-32 img-circle" src="{{match['secondary_icon']}}">
         </a>
       </div>

From 358a99a0e9bbf349c60f7c4fdefe03389a821f5b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Feb 10 2016 09:49:17 +0000
Subject: [PATCH 292/1001] Merge #77 `Rework the pagure PRs widget`


---

diff --git a/hubs/validators.py b/hubs/validators.py
index 0dec579..9c2c276 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -30,5 +30,5 @@ def fmn_context(session, value):
         'irc', 'email', 'android', 'desktop', 'hubs',
     ]
 
-def repo(session, value):
+def pagure_repo(session, value):
     return value
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
index f142bb3..feabd5e 100644
--- a/hubs/widgets/githubissues.py
+++ b/hubs/widgets/githubissues.py
@@ -51,8 +51,8 @@ template = jinja2.Template("""
 
 @argument(name="repo",
           default=None,
-          validator=validators.repo,
-          help="Repo")
+          validator=validators.github_organization,
+          help="Github Organization or username")
 def data(session, widget, display_number, org, repo):
   url = '/'.join(['https://api.github.com/repos',org,repo,"issues"])
   issue_response = requests.get(url)
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index afd8b97..055d37a 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -4,77 +4,114 @@ import jinja2
 import requests
 from hubs.widgets.base import argument
 import hubs.validators as validators
-chrome = panel("Pagure: Newest Open Pull Requests")
+chrome = panel("Newest Open Pull Requests on Pagure")
 
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
-  <br />
-    <div class="container">
-      {% for i in range(0,total_req) %}
-        <div>
-          <table class="table-responsive table-condensed">
-            <tr>
-              <td valign="top" class="panel-heading">
-                <b>#{{ all_pr[i]['pr_id'] }}</b>
-              </td>
-              <td width="260px">
-                <b>{{ all_pr[i]['pr_title'] }} ...</b>
-              </td>
-            </tr>
-           </table>
-         <table class="table-responsive table-condensed">
-            <tr>
-              <td width="280px" >
-                <font size="2">
-                  <i>Opened by <a href="https://pagure.io/user/{{ all_pr[i]['pr_openedby'] }}" target="_blank">{{ all_pr[i]['pr_openedby'] }}</a>
-                  {% if all_pr[i]['pr_assignee'] %}
-                    <br>Assigned to <a href="https://pagure.io/user/{{ all_pr[i]['pr_assignee'] }}" target="_blank">{{ all_pr[i]['pr_assignee'] }}</a></i>
-                  {% endif %}
-                </font>
-              </td>
-              <td>
-                <a href="https://pagure.io/{{ repo }}/pull-request/{{ all_pr[i]['pr_id'] }}" target="_blank">
-                  <button type="button" class="btn btn-default" aria-label="Left Align">
-                    <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-                  </button>
-                </a>
-              </td>
-            </tr>
-          </table>
-        </div>
-      {%endfor%}
-    <br />
+  <div class="container">
+    <table id="pagure-pr-list"
+        class="table table-hover table-striped m-b-0">
+      <thead class="thead-default">
+        <tr>
+          <th id="project-title">Project</th>
+          <th id="pr-title">Pull-Request</th>
+          <th class="open_by">Reporter</th>
+          <th class="assigned">Assignee</th>
+        </tr>
+      </thead>
+      <tfoot>
+      </tfoot>
+      <tbody>
+        {% for pr in all_pr %}
+        <tr>
+          <td>
+            {% if pr['pr_project_user'] %}
+            <a href="https://pagure.io/forks/{{
+                pr['pr_project_user'] }}/{{ pr['pr_project_name'] }}"
+              target="_blank">
+              {{ pr['pr_project_user'] }}/{{ pr['pr_project_name'] }}
+            {% else %}
+            <a href="https://pagure.io/{{
+              pr['pr_project_name'] }}" target="_blank">
+              {{ pr['pr_project_name'] }}
+            {% endif %}
+            </a>
+          </td>
+          <td>
+            <span class="label label-default">#{{ pr['pr_id'] }}</span>
+            <a href="https://pagure.io/{{ repo }}/pull-request/{{
+              pr['pr_id'] }}" target="_blank"
+              title="{{ pr['pr_title_full'] }}">
+              {{ pr['pr_title'] }} ...
+            </a>
+          </td>
+          <td>
+            <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
+                target="_blank">
+              {{ pr['pr_openedby'] }}
+            </a>
+          </td>
+          <td>
+            {% if pr['pr_assignee'] %}
+              <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
+                  target="_blank">
+                {{ pr['pr_assignee'] }}
+              </a>
+            {% else %}
+              <span class="text-muted">unassigned</span>
+            {% endif %}
+          </td>
+        </tr>
+        {% endfor %}
+      </tbody>
+    </table>
     </div class="row">
-      <center><a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">All Pull-Requests</a><center>
+      <center>
+        <a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">
+          All Pull-Requests
+        </a>
+      <center>
     </div>
   </div>
 """)
 
+
 @argument(name="repo",
           default=None,
-          validator=validators.repo,
-          help="Repo")
+          validator=validators.pagure_repo,
+          help="Pagure repo name")
 def data(session, widget, repo):
-    repo="pagure"
     url = '/'.join([pagure_url, repo, "pull-requests"])
     response = requests.get(url)
     data = response.json()
     total_req = data['total_requests']
     all_pr = list()
-    for i in range(0,total_req):
-      all_pr.append(dict(
-      pr_id=data['requests'][i]['id'],
-      pr_title=data['requests'][i]['title'][:45],
-      pr_openedby=data['requests'][i]['user']['name'],
-      pr_assignee=data['requests'][i]['assignee'],
-    ))
-    all_pr.reverse()
-    return dict(all_pr=all_pr,
-    total_req=total_req,
-    repo=repo,
-)
+
+    for request in data['requests']:
+        pr_project_user = None
+        if request['project']['parent']:
+            pr_project_user = request['project']['user']['username']
+
+        all_pr.append(
+            dict(
+                pr_project_name=request['project']['name'],
+                pr_project_user=pr_project_user,
+                pr_id=request['id'],
+                pr_title=request['title'][:45],
+                pr_title_full=request['title'],
+                pr_openedby=request['user']['name'],
+                pr_assignee=request['assignee'],
+            )
+        )
+
+    return dict(
+        all_pr=all_pr,
+        total_req=total_req,
+        repo=repo,
+    )
+
 
 @hint()
 def should_invalidate(message, session, widget):
-   raise NotImplementedError
+    raise NotImplementedError
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index 8ec1608..d429c52 100644
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -99,8 +99,8 @@ template = jinja2.Template("""
 
 @argument(name="repo",
           default=None,
-          validator=validators.repo,
-          help="Repo")
+          validator=validators.pagure_repo,
+          help="Pagure repo name")
 def data(session, widget, repo):
     repo = "pagure"
 

From f1469d6d89f5fc512b4d0a206b4634948865bf04 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Feb 10 2016 09:49:21 +0000
Subject: [PATCH 293/1001] Merge #78 `Rework the widget for issues on pagure`


---

diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index d429c52..fd52f16 100644
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -5,98 +5,79 @@ import hubs.validators as validators
 import jinja2
 import requests
 
-chrome = panel("Pagure: Newest Open Tickets")
+chrome = panel("Newest Open Tickets on Pagure")
 
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
-  <br />
-  {% if message == "None" %}
-    <div class="container">
-      {% if total<3 %}
-        {% for i in range(0,total) %}
-          <div>
-            <table class="table-responsive table-condensed">
-              <tr>
-                <td valign="top" class="panel-heading">
-                  <b>#{{ all_issues[i]['id'] }}</b>
-                </td>
-                <td width="260px">
-                  <b>{{ all_issues[i]['title'] }}</b>
-                </td>
-              </tr>
-            </table>
-            <table class="table-responsive table-condensed">
-              <tr>
-                <td width="260px">
-                  <font size="2">
-                    <i>Opened by <a href="https://pagure.io/user/{{ all_issues[i]['user'] }}" target="_blank">{{ all_issues[i]['user'] }}</a></i>
-                    {% if all_issues[i]['assignee']|string() == "None" %}
-                      <br /><i>Unclaimed</i>
-                    {% else %}
-                      <br /><i>Assigned by <a href="https://pagure.io/user/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
-                    {% endif %}
-                  </font>
-                </td>
-                <td>
-                  <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
-                    <button type="button" class="btn btn-default" aria-label="Left Align">
-                      <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-                    </button>
-                  </a>
-                </td>
-              </tr>
-            </table>
-          </div>
+  <div class="container">
+    <table id="pagure-issues-list"
+        class="table table-hover table-striped m-b-0">
+      <thead class="thead-default">
+        <tr>
+          <th id="project-title">Project</th>
+          <th id="issue-title">Issue</th>
+          <th class="open_by">Reporter</th>
+          <th class="assigned">Assignee</th>
+        </tr>
+      </thead>
+      <tfoot>
+      </tfoot>
+      <tbody>
+        {% for issue in all_issues %}
+        <tr>
+          <td>
+            {% if issue['issue_project_user'] %}
+            <a href="https://pagure.io/forks/{{
+                issue['issue_project_user'] }}/{{ issue['issue_project_name'] }}"
+              target="_blank">
+              {{ issue['issue_project_user'] }}/{{ issue['issue_project_name'] }}
+            {% else %}
+            <a href="https://pagure.io/{{
+              issue['issue_project_name'] }}" target="_blank">
+              {{ issue['issue_project_name'] }}
+            {% endif %}
+            </a>
+          </td>
+          <td>
+            <span class="label label-default">#{{ issue['issue_id'] }}</span>
+            <a href="https://pagure.io/{{ repo }}/pull-request/{{
+             issue['issue_id'] }}" target="_blank"
+             title="{{ issue['issue_title_full'] }}">>
+              {{ issue['issue_title'] }} ...
+            </a>
+          </td>
+          <td>
+            <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
+                target="_blank">
+              {{ issue['issue_openedby'] }}
+            </a>
+          </td>
+          <td>
+            {% if issue['issue_assignee'] %}
+              <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
+                  target="_blank">
+                {{issue['issue_assignee'] }}
+              </a>
+            {% else %}
+              <span class="text-muted">unassigned</span>
+            {% endif %}
+          </td>
+        </tr>
         {% endfor %}
-      {% else %}
-        {% for i in range(0,3) %}
-          <div>
-            <table class="table-responsive table-condensed">
-              <tr>
-                <td valign="top" class="panel-heading">
-                  <b>#{{ all_issues[i]['id'] }}</b>
-                </td>
-                <td width="260px">
-                  <b>{{ all_issues[i]['title'] }}</b>
-                </td>
-              </tr>
-            </table>
-            <table class="table-responsive table-condensed">
-              <tr>
-                <td width="260px">
-                  <font size="2">
-                    <i>Opened by <a href="https://pagure.io/user/{{ all_issues[i]['user'] }}" target="_blank">{{ all_issues[i]['user'] }}</a></i>
-                    {% if all_issues[i]['assignee']|string() == "None" %}
-                      <br /><i>Unclaimed</i>
-                    {% else %}
-                      <br /><i>Assigned to <a href="https://pagure.io/user/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
-                    {% endif %}
-                  </font>
-                </td>
-                <td>
-                  <a href="https://pagure.io/{{ repo }}/issue/{{ all_issues[i]['id'] }}" target="_blank">
-                    <button type="button" class="btn btn-default" aria-label="Left Align">
-                      <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-                    </button>
-                  </a>
-                </td>
-              </tr>
-            </table>
-          </div>
-        {% endfor %}
-      {% endif %}
-    </div>
-    <div class="row">
-      <a href="https://pagure.io/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
-    </div>
-  {% else %}
-    <div class="container">
-      <b>Not a valid repo</b>
+      </tbody>
+    </table>
+    </div class="row">
+      <center>
+        <a href="https://pagure.io/{{ repo }}/issues" target="_blank">
+          All Issues
+        </a>
+      <center>
     </div>
-  {% endif %}
+  </div>
 """)
 
+
 @argument(name="repo",
           default=None,
           validator=validators.pagure_repo,
@@ -104,45 +85,48 @@ template = jinja2.Template("""
 def data(session, widget, repo):
     repo = "pagure"
 
-    projects_response = requests.get("https://pagure.io/api/0/projects")
-    projects_data = projects_response.json()
-    total_projects = projects_data['total_projects']
-    all_projects = list()
-    for i in range(0, total_projects):
-      all_projects.append(projects_data['projects'][i]['name'])
-    if repo not in all_projects:
-      message = "Not a valid project"
-      return dict(
-        message=message,
-      )
-    else:
-      message = "None"
-      url = '/'.join([pagure_url, repo, "issues"])
-      issue_response = requests.get(url)
-      data = issue_response.json()
-      total = data['total_issues']
-      all_issues = list()
-      for i in range(0,total):
-        issue_details = dict()
-        issue_id=data['issues'][i]['id']
-        issue_title=data['issues'][i]['title']
-        issue_user=data['issues'][i]['user']['name']
-        if(data['issues'][i]['assignee']!=None):
-          issue_assignee=data['issues'][i]['assignee']['name']
+    url = '/'.join([pagure_url, repo, "issues"])
+    issue_response = requests.get(url)
+    data = issue_response.json()
+    total = data['total_issues']
+
+    all_issues = list()
+    for issue in data['issues']:
+
+        issue_assignee = None
+        if issue['assignee']:
+            issue_assignee=issue['assignee']['name']
+
+        issue_project_user = None
+        if 'project' in issue:
+          issue_project_name = issue['project']['name']
+          if issue['project']['parent']:
+            issue_project_user = issue['project']['user']['username']
         else:
-          issue_assignee=data['issues'][i]['assignee']
-        issue_details['id']=issue_id
-        issue_details['title']=issue_title
-        issue_details['user']=issue_user
-        issue_details['assignee']=issue_assignee
-        all_issues.append(issue_details)
-      all_issues.reverse()
-      return dict(
+            if '/' in repo:
+                issue_project_name, issue_project_user = repo.split('/', 1)
+            else:
+              issue_project_name = repo
+
+        all_issues.append(
+          dict(
+            issue_project_name=issue_project_name,
+            issue_project_user=issue_project_user,
+            issue_id=issue['id'],
+            issue_title=issue['title'][:45],
+            issue_title_full=issue['title'],
+            issue_openedby=issue['user']['name'],
+            issue_assignee=issue_assignee,
+          )
+        )
+
+    all_issues.reverse()
+
+    return dict(
         repo=repo,
         total=total,
         all_issues=all_issues,
-        message = message,
-      )
+    )
 
 
 @hint()

From cf15bae0093503ecfe7737a5dc3da48315142bc7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 10 2016 11:26:35 +0000
Subject: [PATCH 294/1001] Links issues with issues and remove remaining `>`


---

diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index fd52f16..3fb4a8c 100644
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -41,9 +41,9 @@ template = jinja2.Template("""
           </td>
           <td>
             <span class="label label-default">#{{ issue['issue_id'] }}</span>
-            <a href="https://pagure.io/{{ repo }}/pull-request/{{
+            <a href="https://pagure.io/{{ repo }}/issue/{{
              issue['issue_id'] }}" target="_blank"
-             title="{{ issue['issue_title_full'] }}">>
+             title="{{ issue['issue_title_full'] }}">
               {{ issue['issue_title'] }} ...
             </a>
           </td>

From 2bab4fd25d4b063a13648e833a918e60d599238c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 10 2016 13:40:25 +0000
Subject: [PATCH 295/1001] Make the pagure issues widget look closer to the workflow.updates2stables one


---

diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index 3fb4a8c..6eecf9b 100644
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -10,71 +10,53 @@ chrome = panel("Newest Open Tickets on Pagure")
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
-  <div class="container">
-    <table id="pagure-issues-list"
-        class="table table-hover table-striped m-b-0">
-      <thead class="thead-default">
-        <tr>
-          <th id="project-title">Project</th>
-          <th id="issue-title">Issue</th>
-          <th class="open_by">Reporter</th>
-          <th class="assigned">Assignee</th>
-        </tr>
-      </thead>
-      <tfoot>
-      </tfoot>
-      <tbody>
-        {% for issue in all_issues %}
-        <tr>
-          <td>
-            {% if issue['issue_project_user'] %}
-            <a href="https://pagure.io/forks/{{
-                issue['issue_project_user'] }}/{{ issue['issue_project_name'] }}"
-              target="_blank">
-              {{ issue['issue_project_user'] }}/{{ issue['issue_project_name'] }}
-            {% else %}
-            <a href="https://pagure.io/{{
-              issue['issue_project_name'] }}" target="_blank">
-              {{ issue['issue_project_name'] }}
-            {% endif %}
-            </a>
-          </td>
-          <td>
-            <span class="label label-default">#{{ issue['issue_id'] }}</span>
-            <a href="https://pagure.io/{{ repo }}/issue/{{
-             issue['issue_id'] }}" target="_blank"
-             title="{{ issue['issue_title_full'] }}">
-              {{ issue['issue_title'] }} ...
-            </a>
-          </td>
-          <td>
-            <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
-                target="_blank">
-              {{ issue['issue_openedby'] }}
-            </a>
-          </td>
-          <td>
-            {% if issue['issue_assignee'] %}
-              <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
-                  target="_blank">
-                {{issue['issue_assignee'] }}
-              </a>
-            {% else %}
-              <span class="text-muted">unassigned</span>
-            {% endif %}
-          </td>
-        </tr>
-        {% endfor %}
-      </tbody>
-    </table>
-    </div class="row">
-      <center>
-        <a href="https://pagure.io/{{ repo }}/issues" target="_blank">
-          All Issues
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/issues">
+  All Issues
+</a>
+<hr/>
+
+<ul class="media-list">
+  {% for issue in all_issues[:10] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://pagure.io/{{ repo }}/issue/{{ issue['issue_id'] }}"
+            target="_blank">
+          {{ issue['issue_project_name'] }}
+        <span class="label label-default">#{{ issue['issue_id'] }}</span>
         </a>
-      <center>
-    </div>
-  </div>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <span title="{{ issue['issue_title_full'] }}">
+            {{ issue['issue_title'] }} {% if
+              issue['issue_title_full'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
+              target="_blank">
+            {{ issue['issue_openedby'] }}
+          </a>
+        --
+        {% if issue['issue_assignee'] %}
+          Assigned to:
+          <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
+              target="_blank">
+            {{issue['issue_assignee'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_issues | length > 10 %}
+  <li>
+    And {{ all_issues | length - 10 }} more ...
+  </li>
+  {% endif %}
+</ul>
 """)
 
 

From e68e92abd39428f78c66c71f84063da9c5318b71 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Feb 10 2016 14:10:31 +0000
Subject: [PATCH 296/1001] Make the pagure PR widget graphically closer to the updates2stable one


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 055d37a..462d94d 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -9,71 +9,53 @@ chrome = panel("Newest Open Pull Requests on Pagure")
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
-  <div class="container">
-    <table id="pagure-pr-list"
-        class="table table-hover table-striped m-b-0">
-      <thead class="thead-default">
-        <tr>
-          <th id="project-title">Project</th>
-          <th id="pr-title">Pull-Request</th>
-          <th class="open_by">Reporter</th>
-          <th class="assigned">Assignee</th>
-        </tr>
-      </thead>
-      <tfoot>
-      </tfoot>
-      <tbody>
-        {% for pr in all_pr %}
-        <tr>
-          <td>
-            {% if pr['pr_project_user'] %}
-            <a href="https://pagure.io/forks/{{
-                pr['pr_project_user'] }}/{{ pr['pr_project_name'] }}"
-              target="_blank">
-              {{ pr['pr_project_user'] }}/{{ pr['pr_project_name'] }}
-            {% else %}
-            <a href="https://pagure.io/{{
-              pr['pr_project_name'] }}" target="_blank">
-              {{ pr['pr_project_name'] }}
-            {% endif %}
-            </a>
-          </td>
-          <td>
-            <span class="label label-default">#{{ pr['pr_id'] }}</span>
-            <a href="https://pagure.io/{{ repo }}/pull-request/{{
-              pr['pr_id'] }}" target="_blank"
-              title="{{ pr['pr_title_full'] }}">
-              {{ pr['pr_title'] }} ...
-            </a>
-          </td>
-          <td>
-            <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
-                target="_blank">
-              {{ pr['pr_openedby'] }}
-            </a>
-          </td>
-          <td>
-            {% if pr['pr_assignee'] %}
-              <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
-                  target="_blank">
-                {{ pr['pr_assignee'] }}
-              </a>
-            {% else %}
-              <span class="text-muted">unassigned</span>
-            {% endif %}
-          </td>
-        </tr>
-        {% endfor %}
-      </tbody>
-    </table>
-    </div class="row">
-      <center>
-        <a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">
-          All Pull-Requests
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/pull-requests">
+  All Pull-Requests
+</a>
+<hr/>
+
+<ul class="media-list">
+  {% for pr in all_pr[:10] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
+            target="_blank">
+          {{ pr['pr_project_name'] }}
+        <span class="label label-default">#{{ pr['pr_id'] }}</span>
         </a>
-      <center>
-    </div>
-  </div>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <span title="{{ pr['pr_title_full'] }}">
+            {{ pr['pr_title'] }} {% if
+              pr['pr_title_full'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
+              target="_blank">
+            {{ pr['pr_openedby'] }}
+          </a>
+        --
+        {% if pr['pr_assignee'] %}
+          Assigned to:
+          <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
+              target="_blank">
+            {{ pr['pr_assignee'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_pr | length > 10 %}
+  <li>
+    And {{ all_pr | length - 10 }} more ...
+  </li>
+  {% endif %}
+</ul>
 """)
 
 

From 99c992a9e16efaf7366b6022996d9da2006a1e22 Mon Sep 17 00:00:00 2001
From: Dhriti Shikhar <dhrish20@gmail.com>
Date: Feb 21 2016 12:16:46 +0000
Subject: [PATCH 297/1001] Adds a bugzilla widget


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 3856d78..a0a2641 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -66,4 +66,10 @@ def add_user_widgets(session, hub, username, fullname):
             'display_number': 15,
         }))
     hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='bugzilla', index=8,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
     return hub
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 03084ac..cc7007c 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -14,6 +14,7 @@ from hubs.widgets import pagure_pr
 from hubs.widgets import github_pr
 from hubs.widgets import pagureissues
 from hubs.widgets import githubissues
+from hubs.widgets import bugzilla
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -37,6 +38,7 @@ registry = {
     'github_pr': github_pr,
     'pagureissues': pagureissues,
     'githubissues': githubissues,
+    'bugzilla': bugzilla,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
new file mode 100644
index 0000000..b8d2d5a
--- /dev/null
+++ b/hubs/widgets/bugzilla.py
@@ -0,0 +1,81 @@
+import operator
+import requests
+from hubs.hinting import hint, prefixed as _
+from hubs.widgets.base import argument
+import jinja2
+import hubs.validators as validators
+from hubs.widgets.chrome import panel
+import pkgwat.api
+
+chrome = panel("Bugzilla: Issues")
+
+template = jinja2.Template("""
+  {% for i in range(0,3) %}
+  <br />
+  <div class="container">
+    <table class="table-responsive table-condensed">
+      <tr>
+        <td valign="top" class="panel-heading">
+          <b>{{ all_issues[i]['issue_title'] }}</b>
+        </td>
+      </tr>
+    </table>
+    <table class="table-responsive table-condensed">
+      <tr>
+        <td>
+          <font size="2"><i>package: </i></font>
+        </td>
+        <td>
+          <font size="2"><i><a href="https://admin.fedoraproject.org/pkgdb/package/rpms/{{ all_issues[i]['pkg_name'] }}" target="_blank">{{ all_issues[i]['pkg_name'] }}</a></i></font>
+        </td>
+      </tr>
+    </table>
+  </div>
+  {% endfor %}
+""")
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    username=username
+    pkgdb_url = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
+    url = "/".join([pkgdb_url, username])
+    response = requests.get(url)
+    data = response.json()
+    total_poc = len(data["point of contact"])
+    total_co_main = len(data["co-maintained"])
+    
+    all_issues = list()
+    
+    for package in data["point of contact"]:
+      pkg_details=pkgwat.api.bugs(package['name'])
+      total_issues=pkg_details['total_rows']
+      for i in range(0,total_issues):
+        all_issues.append(
+          dict(
+            pkg_name=package['name'],
+            issue_title=pkg_details['rows'][i]['description'],
+          )
+        ) 
+      
+    for package in data["co-maintained"]:
+      pkg_details=pkgwat.api.bugs(package['name'])
+      total_issues=pkg_details['total_rows']
+      for i in range(0,total_issues):
+        all_issues.append(
+          dict(
+            pkg_name=package['name'],
+            issue_title=pkg_details['rows'][i]['description'],
+          )
+        )
+
+    return dict(
+      username=username,
+      all_issues=all_issues,
+    )
+
+@hint()
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 836ae7a95e0861f5eccf9a544d1eceb4a0ad8082 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Feb 26 2016 15:54:23 +0000
Subject: [PATCH 298/1001] Merge #80 `Make the pagure PR widget graphically closer to the updates2stable one`


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 055d37a..462d94d 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -9,71 +9,53 @@ chrome = panel("Newest Open Pull Requests on Pagure")
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
-  <div class="container">
-    <table id="pagure-pr-list"
-        class="table table-hover table-striped m-b-0">
-      <thead class="thead-default">
-        <tr>
-          <th id="project-title">Project</th>
-          <th id="pr-title">Pull-Request</th>
-          <th class="open_by">Reporter</th>
-          <th class="assigned">Assignee</th>
-        </tr>
-      </thead>
-      <tfoot>
-      </tfoot>
-      <tbody>
-        {% for pr in all_pr %}
-        <tr>
-          <td>
-            {% if pr['pr_project_user'] %}
-            <a href="https://pagure.io/forks/{{
-                pr['pr_project_user'] }}/{{ pr['pr_project_name'] }}"
-              target="_blank">
-              {{ pr['pr_project_user'] }}/{{ pr['pr_project_name'] }}
-            {% else %}
-            <a href="https://pagure.io/{{
-              pr['pr_project_name'] }}" target="_blank">
-              {{ pr['pr_project_name'] }}
-            {% endif %}
-            </a>
-          </td>
-          <td>
-            <span class="label label-default">#{{ pr['pr_id'] }}</span>
-            <a href="https://pagure.io/{{ repo }}/pull-request/{{
-              pr['pr_id'] }}" target="_blank"
-              title="{{ pr['pr_title_full'] }}">
-              {{ pr['pr_title'] }} ...
-            </a>
-          </td>
-          <td>
-            <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
-                target="_blank">
-              {{ pr['pr_openedby'] }}
-            </a>
-          </td>
-          <td>
-            {% if pr['pr_assignee'] %}
-              <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
-                  target="_blank">
-                {{ pr['pr_assignee'] }}
-              </a>
-            {% else %}
-              <span class="text-muted">unassigned</span>
-            {% endif %}
-          </td>
-        </tr>
-        {% endfor %}
-      </tbody>
-    </table>
-    </div class="row">
-      <center>
-        <a href="https://pagure.io/{{ repo }}/pull-requests" target="_blank">
-          All Pull-Requests
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/pull-requests">
+  All Pull-Requests
+</a>
+<hr/>
+
+<ul class="media-list">
+  {% for pr in all_pr[:10] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
+            target="_blank">
+          {{ pr['pr_project_name'] }}
+        <span class="label label-default">#{{ pr['pr_id'] }}</span>
         </a>
-      <center>
-    </div>
-  </div>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <span title="{{ pr['pr_title_full'] }}">
+            {{ pr['pr_title'] }} {% if
+              pr['pr_title_full'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
+              target="_blank">
+            {{ pr['pr_openedby'] }}
+          </a>
+        --
+        {% if pr['pr_assignee'] %}
+          Assigned to:
+          <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
+              target="_blank">
+            {{ pr['pr_assignee'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_pr | length > 10 %}
+  <li>
+    And {{ all_pr | length - 10 }} more ...
+  </li>
+  {% endif %}
+</ul>
 """)
 
 

From d945bd50fd34294e5bfb590dc142220724d648f1 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 04 2016 15:17:15 +0000
Subject: [PATCH 299/1001] Some notes about credentials.


---

diff --git a/.gitignore b/.gitignore
index 80d44bf..793965a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 *.pyc
 *.egg*
 fedmsg.d/fas_credentials.py
+fedmsg.d/credentials.py
 node*
 build/
 scratch/
diff --git a/README.rst b/README.rst
index 264e5a2..a87b918 100644
--- a/README.rst
+++ b/README.rst
@@ -73,6 +73,29 @@ You can run it with::
     $ pip install -r test-requirements.txt
     $ PYTHONPATH=. nosetests
 
+Some credentials...
+-------------------
+
+You need to add a new file to the ``fedmsg.d/`` directory.
+Call it ``fedmsg.d/credentials.py``.  It should have some
+secrets in it that you don't want to accidentally share with
+anyone else.. so be sure to keep it private.  It should have
+contents like this::
+
+    config = {
+        # Put your FAS credentials here...
+        'fas_credentials': {
+            'username': 'YOUR_FAS_USERNAME',
+            'password': 'YOUR_FAS_PASSWORD',
+        },
+
+        # Go and generate a token for this here:
+        # https://github.com/settings/tokens
+        'github.oauth_token': 'YOUR_GITHUB_TOKEN',
+    }
+
+Some widgets will work without the above info being present..
+but it is needed for a subset of them.
 
 Feed Widget - the Extra Mile
 ----------------------------

From 2f3f6d63fd4a2795171730f321152017f823c98b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 04 2016 15:31:30 +0000
Subject: [PATCH 300/1001] Add a note about the "workon" command.


---

diff --git a/README.rst b/README.rst
index a87b918..6e7e937 100644
--- a/README.rst
+++ b/README.rst
@@ -22,7 +22,14 @@ refresh your bash profile::
 
     $ source ~/.bashrc
 
-Install the dependencies from PyPI::
+Note that, you only have to type ``mkvirtualenv`` the *very
+first time* you set up hubs.  When you try go to work on hubs
+a second time (and every time after that..) you only have to
+type ``workon hubs``, which will re-activate the virtual
+environment that you *made* last time.  (The ``mk`` in
+``mkvirtualenv`` stands for "make".)
+
+OK -- with that done, now install the dependencies from PyPI::
 
     $ pip install -r requirements.txt
 

From 20c3162377e15131c9ed76c6ba849343f1403f79 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 04 2016 15:47:19 +0000
Subject: [PATCH 301/1001] Move pagure project name.


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 462d94d..e1f9315 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -21,12 +21,12 @@ template = jinja2.Template("""
       <div class="media-left">
         <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
             target="_blank">
-          {{ pr['pr_project_name'] }}
         <span class="label label-default">#{{ pr['pr_id'] }}</span>
         </a>
       </div>
       <div class="media-body">
         <h4 class="media-heading">
+          {{ pr['pr_project_name'] }} -
           <span title="{{ pr['pr_title_full'] }}">
             {{ pr['pr_title'] }} {% if
               pr['pr_title_full'] | length > 45 %} ... {% endif %}

From 636c1c41fcfc304bcdfa2c85ef413f1554577d23 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 06 2016 03:45:00 +0000
Subject: [PATCH 302/1001] Add a release events calendar to everybody's page.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 3856d78..3629062 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -24,6 +24,13 @@ def add_user_widgets(session, hub, username, fullname):
 
     # Right Side Widgets
     widget = hubs.models.Widget(
+        plugin='meetings', index=-1,
+        _config=json.dumps({
+            'calendar': 'Fedora release',
+        }))
+    hub.widgets.append(widget)
+
+    widget = hubs.models.Widget(
         plugin='fedmsgstats', index=0,
         _config=json.dumps({
             'username': username,

From 962bfe23a3b3b2c255555377015e6e97522832bb Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 06 2016 03:45:25 +0000
Subject: [PATCH 303/1001] Add markdown info from meetings API.


---

diff --git a/hubs/utils.py b/hubs/utils.py
index f7f9e84..6eb43b7 100644
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -2,6 +2,7 @@ import logging
 from hashlib import sha256
 
 import arrow
+import markdown
 import requests
 
 from six.moves.urllib_parse import urlencode
@@ -9,6 +10,11 @@ from six.moves.urllib_parse import urlencode
 log = logging.getLogger(__name__)
 
 
+def markup(text):
+    return markdown.markdown(text, safe_mode="replace",
+                             html_replacement_text="--RAW HTML NOT ALLOWED--")
+
+
 def username2avatar(username, s=312):
     query = urlencode({
         'd': 'retro',
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 2ba21e6..1dfd8ec 100644
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -3,6 +3,7 @@ from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
 
 from hubs import validators
+from hubs import utils
 
 import arrow
 import collections
@@ -43,7 +44,8 @@ template = jinja2_environment.from_string("""
         <h1 class='inline'>{{next.start_date}}</h1>
         <div class='inline'>
             @{{next.start_time}}<br/>
-            {{next.location}}
+            {{next.location}}<br/>
+            {{next.meeting_information_html}}
         </div>
         {% endif %}
         {% if meetings | length > 1 %}
@@ -65,6 +67,8 @@ def data(session, widget, calendar):
 
     meetings = collections.defaultdict(list)
     for meeting in response['meetings']:
+        meeting['meeting_information_html'] = utils.markup(
+            meeting['meeting_information'])
         meetings[meeting['meeting_name']].append(meeting)
 
     return dict(meetings=dict(meetings))
diff --git a/requirements.txt b/requirements.txt
index 803a544..75e9e09 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,3 +13,4 @@ munch
 psycopg2
 pytz
 sqlalchemy
+markdown

From 34e26b64c8661b4ff23de26c8d4e095c8e712cc9 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Mar 06 2016 06:59:02 +0000
Subject: [PATCH 304/1001] Added a default hub for CommOps. Closes #97


---

diff --git a/populate.py b/populate.py
index 4bb1b21..9f1816c 100755
--- a/populate.py
+++ b/populate.py
@@ -12,7 +12,7 @@ session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
          'abompard', 'decause', 'ralph', 'lmacken', 'croberts', 'mattdm',
-         'pravins']
+         'pravins', 'keekri', 'linuxmodder', 'bee2502', 'jflory7']
 for username in users:
     fullname = 'Full Name Goes Here'
     openid = '%s.id.fedoraproject.org' % username
@@ -67,6 +67,53 @@ hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproje
 
 session.commit()
 
+############## CommOps
+hub = hubs.models.Hub(name='commops', summary='The Fedora Community Operations Team')
+session.add(hub)
+
+widget = hubs.models.Widget(plugin='stats', index=0)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='rules', index=1,
+                            _config=json.dumps({
+                                'link': 'https://fedoraproject.org/wiki/CommOps',
+                                'schedule_text': None,
+                                'schedule_link': None,
+                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=commops&type=team',
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='meetings', index=2,
+                            _config=json.dumps({'calendar': 'commops'}))
+hub.widgets.append(widget)
+
+# Added a hubs about widget
+widget = hubs.models.Widget(plugin='about', index=3,
+                            _config=json.dumps({
+                                "text": "Community + Operations = CommOps",
+                            }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
+                            _config=json.dumps({
+                                'text': "Bringing more heat and light to Fedora, so you don't have to choose between 'building things' and 'building communities that build things.'",
+                            }))
+hub.widgets.append(widget)
+widget = hubs.models.Widget(plugin='dummy', index=2, left=True)
+hub.widgets.append(widget)
+
+
+# Set up some memberships
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'jflory7.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'bee2502.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'keekri.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'linuxmodder.id.fedoraproject.org'), 'member')
+
+
+session.commit()
+
 ############## Marketing team
 hub = hubs.models.Hub(name='marketing', summary='The Fedora Marketing Team')
 session.add(hub)

From 6e6e9de7a17fb5c39ca0ac8e1812624a89d2c0e4 Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Mar 06 2016 07:00:17 +0000
Subject: [PATCH 305/1001] Added rm /var/tmp/fedora-hubs-cache.db to the 'all-in-one' restart


---

diff --git a/README.rst b/README.rst
index 6e7e937..bb0f74a 100644
--- a/README.rst
+++ b/README.rst
@@ -65,7 +65,7 @@ Note that then the application is available at http://localhost:8000/
 When hacking on widgets, it is useful to have this one-liner handy.  It removes
 the db alltogether, re-populates it, and restarts the app::
 
-    $ rm /var/tmp/hubs.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 240 --log-config logging.ini hubs.app:app
+    $ rm /var/tmp/hubs.db; rm /var/tmp/fedora-hubs-cache.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 240 --log-config logging.ini hubs.app:app
 
 Run the tests!
 --------------

From 46a636bc51ff0673d420cc974e356aecdf9e471f Mon Sep 17 00:00:00 2001
From: Remy DeCausemaker <decause@redhat.com>
Date: Mar 06 2016 07:08:34 +0000
Subject: [PATCH 306/1001] Added some install reqs. shoutou @jflory7


---

diff --git a/README.rst b/README.rst
index bb0f74a..3117649 100644
--- a/README.rst
+++ b/README.rst
@@ -7,7 +7,7 @@ Hacking
 =======
 Install fedora dependencies::
 
-    $ sudo dnf install gcc gcc-c++ sqlite-devel 
+    $ sudo dnf install gcc gcc-c++ sqlite-devel libffi-devel openssl-devel
 
 Hubs should work on either python2 **or** python3.  These instructions will
 show the way for python2 only, though.

From 1e1b6dcf38331e264f70ad84690743744b0c3c33 Mon Sep 17 00:00:00 2001
From: Dhriti Shikhar <dhrish20@gmail.com>
Date: Mar 06 2016 15:17:59 +0000
Subject: [PATCH 307/1001] Adds a bugzilla widget


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 3629062..c37b6cb 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -73,4 +73,10 @@ def add_user_widgets(session, hub, username, fullname):
             'display_number': 15,
         }))
     hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='bugzilla', index=8,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
     return hub
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 03084ac..cc7007c 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -14,6 +14,7 @@ from hubs.widgets import pagure_pr
 from hubs.widgets import github_pr
 from hubs.widgets import pagureissues
 from hubs.widgets import githubissues
+from hubs.widgets import bugzilla
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -37,6 +38,7 @@ registry = {
     'github_pr': github_pr,
     'pagureissues': pagureissues,
     'githubissues': githubissues,
+    'bugzilla': bugzilla,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
new file mode 100644
index 0000000..bce887d
--- /dev/null
+++ b/hubs/widgets/bugzilla.py
@@ -0,0 +1,76 @@
+import operator
+import requests
+from hubs.hinting import hint, prefixed as _
+from hubs.widgets.base import argument
+import jinja2
+import hubs.validators as validators
+from hubs.widgets.chrome import panel
+import pkgwat.api
+
+chrome = panel("Bugzilla: Issues")
+
+template = jinja2.Template("""
+<ul class="media-list">
+  {% for issue in all_issues[:3] %}
+    <li class="media">
+      <div class="media-left">
+        <a href="https://bugzilla.redhat.com/show_bug.cgi?id={{ issue['id'] }}" target="_blank">
+	  <span class="label label-default">#{{ issue['id'] }}</span>
+	</a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <a href="https://admin.fedoraproject.org/pkgdb/package/rpms/{{ issue['pkg_name'] }}" target="_blank">{{ issue['pkg_name'] }}</a> -
+          {{ issue['title'] }}
+        </h4>
+      </div>
+    </li>
+  {% endfor %}
+</ul>
+""")
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    username=username
+    pkgdb_url = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
+    url = "/".join([pkgdb_url, username])
+    response = requests.get(url)
+    data = response.json()
+    total_poc = len(data["point of contact"])
+    total_co_main = len(data["co-maintained"])
+    
+    all_issues = list()
+    
+    for package in data["point of contact"]:
+      pkg_details=pkgwat.api.bugs(package['name'])
+      for row in pkg_details['rows']:
+        all_issues.append(
+          dict(
+            pkg_name=package['name'],
+            id=row['id'],
+            title=row['description'],
+          )
+        ) 
+      
+    for package in data["co-maintained"]:
+      pkg_details=pkgwat.api.bugs(package['name'])
+      for row in pkg_details['rows']:
+        all_issues.append(
+          dict(
+            pkg_name=package['name'],
+            id=row['id'],
+            title=row['description'],
+          )
+        )
+
+    return dict(
+      username=username,
+      all_issues=all_issues,
+    )
+
+@hint()
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 5081705bb0adaf260a8a25693d900b58098eec8b Mon Sep 17 00:00:00 2001
From: Maria Leonova <marialeonova.design@gmail.com>
Date: Mar 10 2016 18:31:40 +0000
Subject: [PATCH 308/1001] changed all pull request button position


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index e1f9315..0ee7de9 100644
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -9,12 +9,6 @@ chrome = panel("Newest Open Pull Requests on Pagure")
 pagure_url = "https://pagure.io/api/0"
 
 template = jinja2.Template("""
-<a class="btn btn-success" target="_blank"
-    href="https://pagure.io/{{ repo }}/pull-requests">
-  All Pull-Requests
-</a>
-<hr/>
-
 <ul class="media-list">
   {% for pr in all_pr[:10] %}
     <li class="media">
@@ -56,6 +50,13 @@ template = jinja2.Template("""
   </li>
   {% endif %}
 </ul>
+
+<hr/>
+
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/pull-requests">
+  All Pull-Requests
+</a>
 """)
 
 

From 9ece57e716c3a7d1468994624bb113e12ac1b2d1 Mon Sep 17 00:00:00 2001
From: Dhriti Shikhar <dhrish20@gmail.com>
Date: Mar 10 2016 21:16:47 +0000
Subject: [PATCH 309/1001] Removes redudent instructions in README.md for fas_credentials.py and credentials.py


---

diff --git a/README.rst b/README.rst
index 3117649..bd86786 100644
--- a/README.rst
+++ b/README.rst
@@ -33,21 +33,6 @@ OK -- with that done, now install the dependencies from PyPI::
 
     $ pip install -r requirements.txt
 
-Give fedora-hubs some FAS credentials.  It's going to need these to query FAS
-for information about other users.  When we deploy this thing to production,
-we'll use a system account for this but for now, just use your personal
-account.  Copy the following into a new file under the fedmsg.d directory
-called fas_credentials.py (``fedmsg.d/fas_credentials.py``) ::
-
-    config = {
-        'fas_credentials': {
-            'username': 'YOUR_FAS_USERNAME_GOES_HERE',
-            'password': 'YOUR_FAS_PASSWORD_GOES_HERE',
-        }
-    }
-
-Make sure to leave the '' around you username and password - don't delete them!
-
 With that, try running the app with::
 
     $ PYTHONPATH=. python populate.py  # To create the db
@@ -84,9 +69,11 @@ Some credentials...
 -------------------
 
 You need to add a new file to the ``fedmsg.d/`` directory.
-Call it ``fedmsg.d/credentials.py``.  It should have some
-secrets in it that you don't want to accidentally share with
-anyone else.. so be sure to keep it private.  It should have
+Call it ``fedmsg.d/credentials.py``.  It's needed to query FAS 
+for information about other users. When we deploy this thing to
+production, we'll use a system account for this but for now, just
+use your personal account. You don't want to accidentally share this
+with anyone else. so be sure to keep it private.  It should have 
 contents like this::
 
     config = {
@@ -101,7 +88,7 @@ contents like this::
         'github.oauth_token': 'YOUR_GITHUB_TOKEN',
     }
 
-Some widgets will work without the above info being present..
+Make sure to leave the '' around you username and password - don't delete them! Some widgets will work without the above info being present..
 but it is needed for a subset of them.
 
 Feed Widget - the Extra Mile

From ca432888050e919865a275bd3a70b079704b4372 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 10 2016 21:19:05 +0000
Subject: [PATCH 310/1001] Merge #103 `Removes redudent instructions in README.md for fas_credentials.py and credentials.py`


---

diff --git a/README.rst b/README.rst
index 3117649..bd86786 100644
--- a/README.rst
+++ b/README.rst
@@ -33,21 +33,6 @@ OK -- with that done, now install the dependencies from PyPI::
 
     $ pip install -r requirements.txt
 
-Give fedora-hubs some FAS credentials.  It's going to need these to query FAS
-for information about other users.  When we deploy this thing to production,
-we'll use a system account for this but for now, just use your personal
-account.  Copy the following into a new file under the fedmsg.d directory
-called fas_credentials.py (``fedmsg.d/fas_credentials.py``) ::
-
-    config = {
-        'fas_credentials': {
-            'username': 'YOUR_FAS_USERNAME_GOES_HERE',
-            'password': 'YOUR_FAS_PASSWORD_GOES_HERE',
-        }
-    }
-
-Make sure to leave the '' around you username and password - don't delete them!
-
 With that, try running the app with::
 
     $ PYTHONPATH=. python populate.py  # To create the db
@@ -84,9 +69,11 @@ Some credentials...
 -------------------
 
 You need to add a new file to the ``fedmsg.d/`` directory.
-Call it ``fedmsg.d/credentials.py``.  It should have some
-secrets in it that you don't want to accidentally share with
-anyone else.. so be sure to keep it private.  It should have
+Call it ``fedmsg.d/credentials.py``.  It's needed to query FAS 
+for information about other users. When we deploy this thing to
+production, we'll use a system account for this but for now, just
+use your personal account. You don't want to accidentally share this
+with anyone else. so be sure to keep it private.  It should have 
 contents like this::
 
     config = {
@@ -101,7 +88,7 @@ contents like this::
         'github.oauth_token': 'YOUR_GITHUB_TOKEN',
     }
 
-Some widgets will work without the above info being present..
+Make sure to leave the '' around you username and password - don't delete them! Some widgets will work without the above info being present..
 but it is needed for a subset of them.
 
 Feed Widget - the Extra Mile

From e775aa21158b6b997c71b94075ead1f0c2ed38e1 Mon Sep 17 00:00:00 2001
From: Bhagyashree <bhagyashree.iitg@gmail.com>
Date: Mar 12 2016 19:33:37 +0000
Subject: [PATCH 311/1001] Fixing Issue #96


---

diff --git a/hubs/__init__.py b/hubs/__init__.py
old mode 100644
new mode 100755
diff --git a/hubs/app.py b/hubs/app.py
old mode 100644
new mode 100755
diff --git a/hubs/consumer.py b/hubs/consumer.py
old mode 100644
new mode 100755
diff --git a/hubs/default_config.py b/hubs/default_config.py
old mode 100644
new mode 100755
diff --git a/hubs/defaults.py b/hubs/defaults.py
old mode 100644
new mode 100755
diff --git a/hubs/hinting.py b/hubs/hinting.py
old mode 100644
new mode 100755
diff --git a/hubs/models.py b/hubs/models.py
old mode 100644
new mode 100755
diff --git a/hubs/utils.py b/hubs/utils.py
old mode 100644
new mode 100755
diff --git a/hubs/validators.py b/hubs/validators.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/linechart.py b/hubs/widgets/linechart.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
old mode 100644
new mode 100755
index 1dfd8ec..c3a8382
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -16,19 +16,31 @@ chrome = panel('Reminders', key='meetings')
 def next_meeting(meetings):
     now = datetime.datetime.utcnow()
     for meeting in meetings:
-        string = "%s %s" % (meeting['meeting_date'],
+        start_string = "%s %s" % (meeting['meeting_date'],
                             meeting['meeting_time_start'])
-        dt = datetime.datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
+        start_dt = datetime.datetime.strptime(start_string, "%Y-%m-%d %H:%M:%S")
 
-        if now < dt:
-            meeting['human_time'] = arrow.get(dt).humanize()
-            meeting['start_date'] = dt.strftime('%b %d')
+        stop_string = "%s %s" % (meeting['meeting_date_end'],
+                            meeting['meeting_time_stop'])
+        stop_dt = datetime.datetime.strptime(stop_string, "%Y-%m-%d %H:%M:%S")
+
+        if now < start_dt:
+            meeting['human_time'] = arrow.get(start_dt).humanize()
+            meeting['start_date'] = start_dt.strftime('%b %d')
+            meeting['stop_date'] = stop_dt.strftime('%b %d')
+            meeting['display_time'] = True
+            meeting['display_duration'] = False            
             # Just UTC for now until we do this on the client and can access
             # their local with moment.js.
             meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
+            meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
             meeting['location'] = meeting['meeting_location']
             if '@' in meeting['location']:
                 meeting['location'] = '#' + meeting['location'].split('@')[0]
+            if stop_dt - start_dt >= datetime.timedelta(hours=24) :
+                meeting['display_time'] = False
+                if stop_dt - start_dt > datetime.timedelta(hours=24) :
+                    meeting['display_duration'] = True
             return meeting
 
     return None
@@ -41,9 +53,15 @@ template = jinja2_environment.from_string("""
         {% set next = items | next_meeting %}
         {% if next %}
         <p>The {{ next.meeting_name }} is {{ next.human_time }}</p>
+        {% if next.display_duration %}
+        <h1 class='inline'>{{next.start_date}} - {{next.stop_date}}</h1>
+        {% else %}
         <h1 class='inline'>{{next.start_date}}</h1>
+        {% endif %}
         <div class='inline'>
+            {% if next.display_time %}
             @{{next.start_time}}<br/>
+            {% endif %}
             {{next.location}}<br/>
             {{next.meeting_information_html}}
         </div>
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/test.py b/hubs/widgets/test.py
old mode 100644
new mode 100755

From 7228454834dce91447271366f26ed129d15d91f2 Mon Sep 17 00:00:00 2001
From: Bhagyashree <bhagyashree.iitg@gmail.com>
Date: Mar 12 2016 19:41:57 +0000
Subject: [PATCH 312/1001] Revert Changes : Fixing Issue #96


---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
old mode 100755
new mode 100644
index c3a8382..1dfd8ec
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -16,31 +16,19 @@ chrome = panel('Reminders', key='meetings')
 def next_meeting(meetings):
     now = datetime.datetime.utcnow()
     for meeting in meetings:
-        start_string = "%s %s" % (meeting['meeting_date'],
+        string = "%s %s" % (meeting['meeting_date'],
                             meeting['meeting_time_start'])
-        start_dt = datetime.datetime.strptime(start_string, "%Y-%m-%d %H:%M:%S")
+        dt = datetime.datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
 
-        stop_string = "%s %s" % (meeting['meeting_date_end'],
-                            meeting['meeting_time_stop'])
-        stop_dt = datetime.datetime.strptime(stop_string, "%Y-%m-%d %H:%M:%S")
-
-        if now < start_dt:
-            meeting['human_time'] = arrow.get(start_dt).humanize()
-            meeting['start_date'] = start_dt.strftime('%b %d')
-            meeting['stop_date'] = stop_dt.strftime('%b %d')
-            meeting['display_time'] = True
-            meeting['display_duration'] = False            
+        if now < dt:
+            meeting['human_time'] = arrow.get(dt).humanize()
+            meeting['start_date'] = dt.strftime('%b %d')
             # Just UTC for now until we do this on the client and can access
             # their local with moment.js.
             meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
-            meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
             meeting['location'] = meeting['meeting_location']
             if '@' in meeting['location']:
                 meeting['location'] = '#' + meeting['location'].split('@')[0]
-            if stop_dt - start_dt >= datetime.timedelta(hours=24) :
-                meeting['display_time'] = False
-                if stop_dt - start_dt > datetime.timedelta(hours=24) :
-                    meeting['display_duration'] = True
             return meeting
 
     return None
@@ -53,15 +41,9 @@ template = jinja2_environment.from_string("""
         {% set next = items | next_meeting %}
         {% if next %}
         <p>The {{ next.meeting_name }} is {{ next.human_time }}</p>
-        {% if next.display_duration %}
-        <h1 class='inline'>{{next.start_date}} - {{next.stop_date}}</h1>
-        {% else %}
         <h1 class='inline'>{{next.start_date}}</h1>
-        {% endif %}
         <div class='inline'>
-            {% if next.display_time %}
             @{{next.start_time}}<br/>
-            {% endif %}
             {{next.location}}<br/>
             {{next.meeting_information_html}}
         </div>

From 682f69918139a5a9685420266593e01cec9ef61e Mon Sep 17 00:00:00 2001
From: Bhagyashree <bhagyashree.iitg@gmail.com>
Date: Mar 12 2016 19:44:31 +0000
Subject: [PATCH 313/1001] Fixing Issue #96 - No extra files in commit this time


---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
old mode 100644
new mode 100755
index 1dfd8ec..c3a8382
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -16,19 +16,31 @@ chrome = panel('Reminders', key='meetings')
 def next_meeting(meetings):
     now = datetime.datetime.utcnow()
     for meeting in meetings:
-        string = "%s %s" % (meeting['meeting_date'],
+        start_string = "%s %s" % (meeting['meeting_date'],
                             meeting['meeting_time_start'])
-        dt = datetime.datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
+        start_dt = datetime.datetime.strptime(start_string, "%Y-%m-%d %H:%M:%S")
 
-        if now < dt:
-            meeting['human_time'] = arrow.get(dt).humanize()
-            meeting['start_date'] = dt.strftime('%b %d')
+        stop_string = "%s %s" % (meeting['meeting_date_end'],
+                            meeting['meeting_time_stop'])
+        stop_dt = datetime.datetime.strptime(stop_string, "%Y-%m-%d %H:%M:%S")
+
+        if now < start_dt:
+            meeting['human_time'] = arrow.get(start_dt).humanize()
+            meeting['start_date'] = start_dt.strftime('%b %d')
+            meeting['stop_date'] = stop_dt.strftime('%b %d')
+            meeting['display_time'] = True
+            meeting['display_duration'] = False            
             # Just UTC for now until we do this on the client and can access
             # their local with moment.js.
             meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
+            meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
             meeting['location'] = meeting['meeting_location']
             if '@' in meeting['location']:
                 meeting['location'] = '#' + meeting['location'].split('@')[0]
+            if stop_dt - start_dt >= datetime.timedelta(hours=24) :
+                meeting['display_time'] = False
+                if stop_dt - start_dt > datetime.timedelta(hours=24) :
+                    meeting['display_duration'] = True
             return meeting
 
     return None
@@ -41,9 +53,15 @@ template = jinja2_environment.from_string("""
         {% set next = items | next_meeting %}
         {% if next %}
         <p>The {{ next.meeting_name }} is {{ next.human_time }}</p>
+        {% if next.display_duration %}
+        <h1 class='inline'>{{next.start_date}} - {{next.stop_date}}</h1>
+        {% else %}
         <h1 class='inline'>{{next.start_date}}</h1>
+        {% endif %}
         <div class='inline'>
+            {% if next.display_time %}
             @{{next.start_time}}<br/>
+            {% endif %}
             {{next.location}}<br/>
             {{next.meeting_information_html}}
         </div>

From 5f0f7e814910805c2e399e49a27f7849880b4319 Mon Sep 17 00:00:00 2001
From: Bhagyashree <bhagyashree.iitg@gmail.com>
Date: Mar 12 2016 21:10:01 +0000
Subject: [PATCH 314/1001] Updated Design for github PR widget(like Pagure PR widget)


---

diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index 6a33091..ff890aa 100755
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -17,47 +17,52 @@ log = logging.getLogger(__name__)
 chrome = panel("Github: Pull Requests")
 
 template = jinja2.Template("""
-  <br />
-  {% for i in range(display_number) %}
-    <div>
-      <table class="table-responsive table-condensed">
-        <tr>
-          <td valign="top" class="panel-heading">
-            <b>#{{ pulls[i]['number'] }}</b>
-          </td>
-          <td width="300px">
-            <b>{{ pulls[i]['title'] }}</b>
-          </td>
-        </tr>
-      </table>
-      <table class="table-responsive table-condensed">
-        <tr>
-          <td width="300px">
-            <font size="2">
-              <i>Opened by <a href="https://github.com/{{ pulls[i]['user'] }}" target="_blank">{{ pulls[i]['user'] }}</a></i>
-              {% if pulls[i]['assignee']|string() == "None" %}
-                <br /><i>Unclaimed</i>
-              {% else %}
-                 <br /><i>Assigned by <a href="https://github.com/{{ pulls[i]['assignee'] }}" target="_blank">{{ pulls[i]['assignee'] }}</a></i>
-              {% endif %}
-            </font>
-          </td>
-          <td>
-             <a href="{{ pulls[i]['url'] }}" target="_blank">
-               <button type="button" class="btn btn-default" aria-label="Left Align">
-                 <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-               </button>
-             </a>
-          </td>
-        </tr>
-      </table>
-    </div>
-    {% endfor %}
-    {% if more != 0 %}
-    <div class="row">
-      <a href="https://github.com/{{ organization }}" target="_blank"><center>and {{ more }} more</center></a>
-    </div>
-    {% endif %}
+<a class="btn btn-success" target="_blank"
+    href="https://github.com/{{ organization }}" >
+  Organization Github Page
+</a>
+<hr/>
+
+  {% for pr in pulls[:display_number] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="{{ pr['url'] }}" 
+            target="_blank">
+        <span class="label label-default">#{{ pr['number'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          {{ organization }} -
+          <span title="{{ pr['title'] }}">
+            {{ pr['title'] }} {% if
+              pr['title'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://github.com/{{ pr['user'] }}" 
+              target="_blank">
+            {{ pr['user'] }}
+          </a>
+        --
+        {% if pr['assignee'] %}
+          Assigned to:
+          <a href="https://github.com/{{ pr['assignee'] }}"
+              target="_blank">
+            {{ pr['assignee'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_pr | length > display_number %}
+  <li>
+    And {{ all_pr | length - display_number }} more ...
+  </li>
+  {% endif %}
+</ul>
 """)
 
 

From 8c4b9da4c039143940e0defcb9af08ac6a31efb2 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 14 2016 15:58:06 +0000
Subject: [PATCH 315/1001] Initial stubbing out of the groups page.


---

diff --git a/hubs/app.py b/hubs/app.py
index 39bea1f..6e4661d 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -70,6 +70,29 @@ def index():
     return flask.redirect(flask.url_for('hub', name=flask.g.auth.nickname))
 
 
+@app.route('/groups')
+def groups():
+    if not flask.g.auth.logged_in:
+        return flask.redirect(flask.url_for('login_fedora'))
+
+    # Get the list of promoted and non-promoted group hubs from the DB
+    promoted_names = app.config.get('PROMOTED_GROUPS')
+    groups = hubs.models.Hub.all_group_hubs(session)
+    promoted = [g for g in groups if g.name in promoted_names]
+    secondary = [g for g in groups if g.name not in promoted_names]
+
+    name_of_the_month = app.config.get('HUB_OF_THE_MONTH')
+    hub_of_the_month = hubs.models.Hub.by_name(session, name_of_the_month)
+
+    return flask.render_template(
+        'groups.html',
+        promoted=promoted,
+        secondary=secondary,
+        hub_of_the_month=hub_of_the_month,
+        session=session,
+    )
+
+
 @app.route('/<name>')
 @app.route('/<name>/')
 def hub(name):
diff --git a/hubs/default_config.py b/hubs/default_config.py
index 39d7fce..a21f138 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -1 +1,8 @@
 SECRET_KEY = 'changemeforreal'
+
+PROMOTED_GROUPS = [
+    'infra',
+    'i18n',
+]
+
+HUB_OF_THE_MONTH = 'commops'
diff --git a/hubs/models.py b/hubs/models.py
index ed003e3..cbe6371 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -209,6 +209,14 @@ class Hub(BASE):
     get = by_name
 
     @classmethod
+    def all_group_hubs(cls, session):
+        return session.query(cls).filter_by(user_hub=False).all()
+
+    @classmethod
+    def all_user_hubs(cls, session):
+        return session.query(cls).filter_by(user_hub=True).all()
+
+    @classmethod
     def create_user_hub(cls, session, username, fullname):
         hub = cls(name=username, summary=fullname,
                   avatar=username2avatar(username),
diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
new file mode 100644
index 0000000..4ef9e3d
--- /dev/null
+++ b/hubs/templates/groups.html
@@ -0,0 +1,113 @@
+<html>
+<head>
+  <title>Groups</title>
+  <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
+</head>
+<script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
+<body>
+<div class="super-header">
+  <div class="row">
+	  <div class="col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
+    <div class="col-sm-4 col-sm-push-4 col-xs-8">
+      {% if g.auth.logged_in %}
+        <div class="dropdown pull-right">
+          <img class = "icon" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
+        <span class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+          <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
+          {# Logged in as #} {{ g.auth.nickname }}
+          <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
+        </span>
+        <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
+          <li class="dropdown-header">Account Information</li>
+          <li><a href="#">Full Name: {{ g.auth.fullname }}</a></li>
+          <li><a href="#">Email: {{ g.auth.email }}</a></li>
+          <li role="separator" class="divider"></li>
+          <li><a href="#">Separated link</a></li>
+        </ul>
+      </div>
+      {% else %}
+        Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
+      {% endif %}
+    </div>
+    <div class="col-sm-4 col-sm-pull-4 col-xs-12">
+      <!-- NOT HOOKED UP TO ANYTHING XOXO -->
+      <div class="input-group">
+        <input type="search" placeholder="Search across all hubs ..."></input>
+        <span class="input-group-addon">
+          <span class="glyphicon glyphicon-search"></span>
+        </span>
+    </div>
+    </div>
+  </div>
+</div>
+<div class="bookmarks">
+  <nav class="navbar navbar-default">
+    <div class="container-fluid">
+      <div class="navbar-header">
+        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+          <span class="sr-only">Toggle navigation</span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+        </button>
+      </div>
+
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav">
+          {% if g.auth.logged_in %}
+          <li {% if request.path.endswith('/' + g.auth.user.username + '/') %}class='active'{% endif %}>
+            <a href="/{{g.auth.user.username}}">me</a></li>
+          {% for hub in g.auth.user.bookmarks %}
+          <li class='idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
+          <a href="/{{hub.name}}">{{hub.name}}</a></li>
+          {% endfor %}
+          {% endif %}
+        </ul>
+      </div><!-- /.navbar-collapse -->
+    </div><!-- /.container-fluid -->
+  </nav>
+</div>
+<div class="header">
+  <div class="img-wrap">
+    <img src="#" />
+  </div>
+  <h3 class="team">Groups</h3>
+</div>
+<div class="container">
+  <div class="row">
+  </div>
+  <div class="row">
+    <div class="col-md-12">
+      {% for group in promoted %}
+      {{ group.name }} is a promoted group, and it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
+      {% endfor %}
+    </div>
+  </div>
+
+  <hr/>
+
+  <div class="row">
+    <div class="col-md-12">
+      ZOMG - {{ hub_of_the_month.name }} is the Hub Of The Month! <br/>
+      It has {{ hub_of_the_month.subscribers | length }} subscribers and {{ hub_of_the_month.members | length }} members, and {{hub_of_the_month.owners | length }} owners
+    </div>
+  </div>
+
+  <hr/>
+
+  <div class="row">
+    <div class="col-md-12">
+      {% for group in secondary %}
+        {{ group.name }} is not a promoted group
+        but it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
+      {% endfor %}
+    </div>
+  </div>
+</div>
+
+<script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
+</body></html>
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 1e87956..3fe5702 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -64,6 +64,8 @@
           <li class='idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
           <a href="/{{hub.name}}">{{hub.name}}</a></li>
           {% endfor %}
+          <!-- At the end of the list, tack on a link to all groups -->
+          <li><a href="/groups">all</a></li>
           {% endif %}
         </ul>
       </div><!-- /.navbar-collapse -->

From 25abd48ef338097325da65d04ad5696db07edf82 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 14 2016 16:06:21 +0000
Subject: [PATCH 316/1001] Show how to display avatar images for each group in the groups layout.


---

diff --git a/hubs/app.py b/hubs/app.py
index 6e4661d..851e850 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -17,6 +17,10 @@ from hubs.utils import username2avatar
 
 app = flask.Flask(__name__)
 
+# Register a global filter, useful for displaying user images
+app.template_filter('avatar')(hubs.widgets.base.avatar)
+
+
 logging.basicConfig()
 
 
diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
index 4ef9e3d..db3ea4c 100644
--- a/hubs/templates/groups.html
+++ b/hubs/templates/groups.html
@@ -93,6 +93,13 @@
     <div class="col-md-12">
       ZOMG - {{ hub_of_the_month.name }} is the Hub Of The Month! <br/>
       It has {{ hub_of_the_month.subscribers | length }} subscribers and {{ hub_of_the_month.members | length }} members, and {{hub_of_the_month.owners | length }} owners
+      <h6>group owners</h6>
+      {% for owner in hub_of_the_month.owners %}
+          <div class="col-sm-6">
+              <img class="img-circle" src="{{owner.username | avatar}}"/>
+              <a href="{{ url_for('hub', name=owner.username)}}">{{owner.username}}</a>
+          </div>
+      {% endfor %}
     </div>
   </div>
 

From 6dc762fa29e6b15b67b34dd3cfbde8ba7c9749ae Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 14 2016 16:58:05 +0000
Subject: [PATCH 317/1001] Add VCR test data.


---

diff --git a/.gitignore b/.gitignore
index 793965a..a8c634a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,3 @@ fedmsg.d/credentials.py
 node*
 build/
 scratch/
-hubs/tests/vcr-request-data
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_data_simple
new file mode 100644
index 0000000..94b3210
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_data_simple
@@ -0,0 +1,808 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"percent_earned": 47.05882352941176, "assertions":
+        [{"description": "You attended Flock 2013, the Fedora Contributor Conference",
+        "tags": "flock,event,", "issued": 1375373082.0, "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "gnokii", "last_awarded": 1386188828.0, "percent_earned": 0.404551201011378,
+        "id": "flock-2013-attendee", "times_awarded": 80, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bitlord", "last_awarded": 1452636478.0, "percent_earned": 1.1276864728192162,
+        "id": "tagger-tagger-ii", "times_awarded": 223, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bitlord", "last_awarded": 1452632614.0, "percent_earned": 1.7496839443742098,
+        "id": "junior-tagger-tagger-i", "times_awarded": 346, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "kldymcx", "last_awarded": 1453391986.0, "percent_earned": 58.063211125158034,
+        "id": "involvement", "times_awarded": 11482, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "leifmadsen",
+        "last_awarded": 1453305829.0, "percent_earned": 7.509481668773704, "id": "speak-up!",
+        "times_awarded": 1485, "name": "Speak Up!"}, {"description": "Edited at least
+        10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0, "image":
+        "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "cnangel",
+        "last_awarded": 1453350349.0, "percent_earned": 4.783817951959545, "id": "junior-editor",
+        "times_awarded": 946, "name": "Junior Editor"}, {"description": "Edited at
+        least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0, "image":
+        "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "raven",
+        "last_awarded": 1452869625.0, "percent_earned": 3.27180783817952, "id": "associate-editor",
+        "times_awarded": 647, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "farhaan",
+        "last_awarded": 1453312868.0, "percent_earned": 2.735777496839444, "id": "secretary-general",
+        "times_awarded": 541, "name": "Secretary General"}, {"description": "Voted
+        on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "mastaiza", "last_awarded": 1451951597.0, "percent_earned": 0.5309734513274336,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 105, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "fale", "last_awarded": 1453273101.0, "percent_earned": 0.9506953223767384,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 188, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "cstratak",
+        "last_awarded": 1453310380.0, "percent_earned": 5.734513274336283, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1134, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "eischmann", "last_awarded": 1453239619.0, "percent_earned": 4.621997471554994,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 914, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "gnat",
+        "last_awarded": 1452623672.0, "percent_earned": 2.634639696586599, "id": "if-you-build-it...-koji-success-iii",
+        "times_awarded": 521, "name": "If you build it... (Koji Success III)"}, {"description":
+        "Ten or more questions and answers on the Ask Fedora system.", "tags": "ask
+        fedora,community,", "issued": 1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedelibre", "last_awarded": 1453367297.0, "percent_earned": 2.5082174462705433,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 496, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "panos", "last_awarded": 1453375409.0, "percent_earned": 16.293299620733247,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 3222, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "quinnrm", "last_awarded": 1453389677.0, "percent_earned": 3.1554993678887486,
+        "id": "riddle-me-this", "times_awarded": 624, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "cockpit", "last_awarded": 1453321371.0, "percent_earned": 3.919089759797725,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 775, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "eischmann", "last_awarded": 1453239295.0, "percent_earned": 3.8280657395701643,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 757, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "suraia",
+        "last_awarded": 1452800930.0, "percent_earned": 5.350189633375474, "id": "you-can-call-me-patches-scm-i",
+        "times_awarded": 1058, "name": "You can call me \"Patches\" (SCM I)"}, {"description":
+        "Pushed 400 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png",
+        "first_awarded": 1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "lvrabec", "last_awarded": 1452698912.0, "percent_earned": 0.8748419721871049,
+        "id": "you-can-call-me-patches-scm-iv", "times_awarded": 173, "name": "You
+        can call me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to
+        a Fedora package repository.", "tags": "development,", "issued": 1376076329.0,
+        "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png",
+        "first_awarded": 1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person":
+        "pschiffe", "last_awarded": 1453290910.0, "percent_earned": 2.47787610619469,
+        "id": "you-can-call-me-patches-scm-iii", "times_awarded": 490, "name": "You
+        can call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more
+        koji builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "ankursinha", "last_awarded": 1452452682.0, "percent_earned": 1.1833122629582806,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 234, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "pkilambi", "last_awarded": 1453335472.0, "percent_earned": 2.5486725663716814,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 504, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "lvrabec", "last_awarded": 1452777318.0, "percent_earned": 0.9152970922882426,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 181, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "dhabben", "last_awarded": 1453392166.0, "percent_earned": 4.723135271807838,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 934, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "lovetide", "last_awarded": 1453389567.0, "percent_earned": 11.97471554993679,
+        "id": "junior-badger-badger-i", "times_awarded": 2368, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "jortel", "last_awarded": 1453223123.0, "percent_earned": 5.006321112515803,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 990, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "fmuellner", "last_awarded": 1453226784.0, "percent_earned": 2.831858407079646,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 560, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "heffer",
+        "last_awarded": 1453162247.0, "percent_earned": 0.6776232616940581, "id":
+        "like-a-rock-updates-stable-iii", "times_awarded": 134, "name": "Like a Rock
+        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
+        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "nshaikh", "last_awarded": 1453381228.0, "percent_earned": 11.625790139064476,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2299, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "gnat",
+        "last_awarded": 1453138519.0, "percent_earned": 2.260429835651075, "id": "like-a-rock-updates-stable-ii",
+        "times_awarded": 447, "name": "Like a Rock (Updates-Stable II)"}, {"description":
+        "Partied with Flock 2013 (at the South Carolina Aquarium)", "tags": "party,flock,event,",
+        "issued": 1376252202.0, "image": "https://badges.fedoraproject.org/pngs/tanked.png",
+        "first_awarded": 1376252202.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "gnokii", "last_awarded": 1411656869.0, "percent_earned": 0.3135271807838179,
+        "id": "tanked!", "times_awarded": 62, "name": "Tanked!"}, {"description":
+        "You proposed a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,",
+        "issued": 1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jsmith", "last_awarded": 1453126870.0, "percent_earned": 0.5967130214917826,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 118, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "drsn0w", "last_awarded": 1453260519.0, "percent_earned": 9.982300884955752,
+        "id": "bona-fide", "times_awarded": 1974, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.13147914032869784,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "jmlich", "last_awarded": 1453380139.0, "percent_earned": 1.2541087231352717,
+        "id": "senior-badger-badger-ii", "times_awarded": 248, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "cstratak",
+        "last_awarded": 1453371252.0, "percent_earned": 5.3198482932996205, "id":
+        "is-this-thing-on-updates-testing-i", "times_awarded": 1052, "name": "Is this
+        thing on? (Updates-Testing I)"}, {"description": "Pushed 20 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "rcritten", "last_awarded": 1452870021.0, "percent_earned": 2.786346396965866,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 551, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "bmbouter",
+        "last_awarded": 1453326365.0, "percent_earned": 3.1099873577749686, "id":
+        "partners-in-crime", "times_awarded": 615, "name": "Partners in Crime"}, {"description":
+        "*(a great struggle, repeated escapes, discipline required)*\nTested and added
+        karma to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "rbarlow", "last_awarded": 1452797003.0, "percent_earned": 1.592920353982301,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 315, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "jibecfed", "last_awarded":
+        1451517381.0, "percent_earned": 0.2427307206068268, "id": "master-tagger-tagger-iv",
+        "times_awarded": 48, "name": "Master Tagger (Tagger IV)"}, {"description":
+        "A member of the sysadmin-badges group.  Nothing to see here..  move along.",
+        "tags": "infrastructure,badges,community,", "issued": 1378319150.0, "image":
+        "https://badges.fedoraproject.org/pngs/fas-inside-job.png", "first_awarded":
+        1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "decause", "last_awarded": 1435781009.0, "percent_earned": 0.025284450063211124,
+        "id": "inside-job", "times_awarded": 5, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "jvasallo", "last_awarded": 1453390587.0, "percent_earned": 12.303413400758533,
+        "id": "white-rabbit", "times_awarded": 2433, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "redandrei", "last_awarded": 1453393896.0, "percent_earned": 4.632111251580278,
+        "id": "mugshot", "times_awarded": 916, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.08596713021491784,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "sayanchowdhury", "last_awarded": 1449249202.0, "percent_earned": 0.16687737041719342,
+        "id": "maestro", "times_awarded": 33, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "aniketkhisti", "last_awarded": 1453384257.0, "percent_earned": 7.691529709228824,
+        "id": "let-me-introduce-myself", "times_awarded": 1521, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "suraia", "last_awarded": 1452876478.0, "percent_earned": 1.3299620733249051,
+        "id": "binary-star", "times_awarded": 263, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "cweyl", "last_awarded": 1451604516.0, "percent_earned": 0.6826801517067004,
+        "id": "packager-sponsor", "times_awarded": 135, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "jmlich", "last_awarded": 1453380114.0, "percent_earned": 2.857142857142857,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 565, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "fale", "last_awarded": 1452955260.0, "percent_earned": 2.427307206068268,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 480, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "m4rtink", "last_awarded": 1451904147.0, "percent_earned": 3.372945638432364,
+        "id": "bloggin-it!-planet-i", "times_awarded": 667, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jcajka", "last_awarded": 1452784301.0, "percent_earned": 1.729456384323641,
+        "id": "white-hat", "times_awarded": 342, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.3994943109987358,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "coralatlas", "last_awarded": 1453259601.0, "percent_earned": 27.95954487989886,
+        "id": "embryo", "times_awarded": 5529, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mastaiza", "last_awarded": 1453293512.0, "percent_earned": 0.8798988621997471,
+        "id": "taming-the-bull-tester-v", "times_awarded": 174, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "fale", "last_awarded": 1451379096.0, "percent_earned": 0.27307206068268014,
+        "id": "common-bugs-contributor", "times_awarded": 54, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "tomh", "last_awarded": 1453387927.0, "percent_earned": 8.56637168141593,
+        "id": "baby-badger", "times_awarded": 1694, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "piotrp", "last_awarded": 1449068505.0, "percent_earned": 0.1213653603034134,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 24, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pfrields", "last_awarded": 1453230770.0, "percent_earned": 1.0821744627054362,
+        "id": "old-yeller", "times_awarded": 214, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.35903919089759795,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "paulcarroty", "last_awarded": 1451415976.0, "percent_earned": 1.5423514538558787,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 305, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "tomh", "last_awarded": 1453043511.0, "percent_earned": 1.6940581542351456,
+        "id": "senior-editor", "times_awarded": 335, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "nilix007", "last_awarded": 1449026189.0, "percent_earned": 17.754740834386855,
+        "id": "tadpole", "times_awarded": 3511, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "rajalakshmi", "last_awarded": 1449029694.0, "percent_earned": 37.67888748419722,
+        "id": "egg", "times_awarded": 7451, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "jdulaney", "last_awarded": 1446505520.0, "percent_earned": 9.780025284450062,
+        "id": "tadpole-with-legs", "times_awarded": 1934, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "sayanchowdhury", "last_awarded": 1449715315.0, "percent_earned": 0.1011378002528445,
+        "id": "badge-off!", "times_awarded": 20, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vinumoses", "last_awarded": 1451694870.0, "percent_earned": 0.4753476611883692,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 94, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "aryasaatvik", "last_awarded": 1452796719.0, "percent_earned": 0.6624525916561315,
+        "id": "no-longer-a-ronin", "times_awarded": 131, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jibecfed", "last_awarded": 1451496270.0, "percent_earned": 0.2579013906447535,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 51, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bitlord", "last_awarded": 1452632607.0, "percent_earned": 1.4563843236409608,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 288, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "duffy", "last_awarded": 1451767725.0, "percent_earned": 0.5208596713021492,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 103, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mastaiza", "last_awarded": 1453367728.0, "percent_earned": 0.9254108723135273,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 183, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "event,speaker,", "issued": 1390422108.0, "image":
+        "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.23261694058154236, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "valtri", "last_awarded": 1452814661.0, "percent_earned": 0.38432364096080907,
+        "id": "patches-scm-v", "times_awarded": 76, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "cstratak", "last_awarded": 1453371384.0, "percent_earned": 1.4007585335018964,
+        "id": "override,-you-say", "times_awarded": 277, "name": "Override, you say?"},
+        {"description": "You attended devconf.cz, a yearly Linux and JBoss conference
+        in the Czech Republic", "tags": "event,devconf,", "issued": 1391763090.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png", "first_awarded":
+        1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.3135271807838179,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "nb", "last_awarded": 1439569573.0, "percent_earned":
+        0.0606826801517067, "id": "videographer", "times_awarded": 12, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "sagitter", "last_awarded": 1450261520.0, "percent_earned": 0.2376738305941846,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 47,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "tkral", "last_awarded": 1453372187.0, "percent_earned": 5.719342604298356,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1131, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "plfiorini", "last_awarded": 1453366379.0, "percent_earned": 3.706700379266751,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 733, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "catanzaro",
+        "last_awarded": 1453387064.0, "percent_earned": 3.3426042983565107, "id":
+        "it-still-works!", "times_awarded": 661, "name": "It still works!"}, {"description":
+        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
+        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cstratak", "last_awarded": 1453371258.0, "percent_earned": 4.1466498103666245,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 820, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "bochecha", "last_awarded": 1452463312.0, "percent_earned": 0.6624525916561315,
+        "id": "bob-loblaw-planet-v", "times_awarded": 131, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "piotrp", "last_awarded": 1452692980.0, "percent_earned": 0.11125158027812895,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 22, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "potty", "last_awarded": 1448485603.0, "percent_earned": 0.26801517067003794,
+        "id": "lets-do-lunch!", "times_awarded": 53, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "piotrp", "last_awarded":
+        1452501182.0, "percent_earned": 0.7433628318584071, "id": "vacation", "times_awarded":
+        147, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "event,python,", "issued": 1397168025.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png",
+        "first_awarded": 1397168025.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "abompard", "last_awarded": 1397573900.0, "percent_earned": 0.05056890012642225,
+        "id": "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 1.441213653603034,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "ilgrad", "last_awarded": 1452896392.0, "percent_earned": 2.0126422250316054,
+        "id": "helping-hand", "times_awarded": 398, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.46523388116308473,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "mcrha",
+        "last_awarded": 1453136709.0, "percent_earned": 0.34892541087231355, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 69, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "indexengines", "last_awarded": 1453392311.0, "percent_earned": 69.38558786346397,
+        "id": "paranoid-panda", "times_awarded": 13721, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.36915297092288246, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "swilkerson", "last_awarded": 1453199550.0, "percent_earned": 1.7951959544879899,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 355, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "siwinski",
+        "last_awarded": 1453319029.0, "percent_earned": 0.9810366624525916, "id":
+        "master-editor", "times_awarded": 194, "name": "Master Editor"}, {"description":
+        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mluscon", "last_awarded": 1450742624.0, "percent_earned": 0.5865992414664981,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 116, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405334492.0, "first_awarded_person": "sgallagh", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.6118836915297092,
+        "id": "flock-2014-attendee", "times_awarded": 121, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "devhen", "last_awarded": 1452673329.0, "percent_earned": 0.6573957016434893,
+        "id": "science-kernel-tester-i", "times_awarded": 130, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.450063211125158, "id": "party-pirate",
+        "times_awarded": 89, "name": "Party Pirate"}, {"description": "You submitted
+        200 Bodhi updates for an EPEL branch.", "tags": "development,epel,", "issued":
+        1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "limb", "last_awarded": 1452540830.0, "percent_earned": 0.05562579013906448,
+        "id": "corporate-overlord", "times_awarded": 11, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "greghellings", "last_awarded": 1453354804.0, "percent_earned": 0.34386852085967134,
+        "id": "corporate-shill", "times_awarded": 68, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "cstratak", "last_awarded": 1453390902.0, "percent_earned": 2.4829329962073325,
+        "id": "corporate-drone", "times_awarded": 491, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1452297195.0, "percent_earned": 0.17193426042983567,
+        "id": "master-badger-badger-iii", "times_awarded": 34, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "heikoada", "last_awarded":
+        1452772620.0, "percent_earned": 0.37926675094816686, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 75, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "chrisroberts", "last_awarded": 1439838603.0, "percent_earned": 0.15676359039190896,
+        "id": "dancing-with-toshio", "times_awarded": 31, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.5562579013906448, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "iaguis",
+        "last_awarded": 1452874718.0, "percent_earned": 2.0227560050568902, "id":
+        "consolation-prize", "times_awarded": 400, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "lovetide", "last_awarded": 1453389559.0, "percent_earned": 12.323640960809103,
+        "id": "crypto-panda", "times_awarded": 2437, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "paulotada", "last_awarded": 1453313558.0, "percent_earned": 3.2616940581542355,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 645, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "ppisar", "last_awarded": 1447066663.0, "percent_earned": 0.045512010113780026,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 9, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "ohaessler", "last_awarded": 1452768576.0, "percent_earned": 1.3046776232616941,
+        "id": "the-cat-came-back...", "times_awarded": 258, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "spot", "last_awarded": 1446145228.0, "percent_earned": 0.09102402022756005,
+        "id": "apprentice-badge-artist-i", "times_awarded": 18, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "sandeen", "last_awarded": 1439922999.0, "percent_earned": 0.2831858407079646,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 56, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.09102402022756005,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.3135271807838179,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "rdieter", "last_awarded": 1449536137.0, "percent_earned": 0.03034134007585335,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 6, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "icon", "last_awarded": 1453222652.0, "percent_earned": 4.101137800252844,
+        "id": "associate-badger-badger-1.5", "times_awarded": 811, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "jenneh", "last_awarded": 1441736246.0, "percent_earned": 0.3994943109987358,
+        "id": "flock-2015-attendee", "times_awarded": 79, "name": "FLOCK 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "mluscon", "last_awarded": 1453387739.0, "percent_earned": 2.2553729456384324,
+        "id": "macaron-cookie-i", "times_awarded": 446, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "walters",
+        "last_awarded": 1452199929.0, "percent_earned": 0.26801517067003794, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 53, "name": "Chocolate Chip (Cookie
+        II)"}, {"description": "Voted in the supplemental wallpapers election for
+        the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.4096080910240202,
+        "id": "nuancier-f22", "times_awarded": 81, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "jvasallo", "last_awarded": 1453390594.0, "percent_earned": 36.86472819216182,
+        "id": "origin", "times_awarded": 7290, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "tadej", "last_awarded": 1450046737.0, "percent_earned": 2.0480404551201015,
+        "id": "delivery", "times_awarded": 405, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "pabelanger", "last_awarded": 1453318849.0, "percent_earned": 0.9405815423514539,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 186,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "hguemar", "last_awarded": 1453303231.0, "percent_earned": 0.05056890012642225,
+        "id": "black-and-white-cookie-iii", "times_awarded": 10, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "piotrp", "last_awarded": 1451395906.0, "percent_earned": 0.12642225031605564,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 25, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433267989.0, "percent_earned": 0.0050568900126422255,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 1, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "eischmann", "last_awarded": 1452092327.0, "percent_earned": 0.035398230088495575,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 7, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "viveknrt", "last_awarded": 1452876035.0, "percent_earned": 0.11630847029077118,
+        "id": "badge-muse-badges-released-i", "times_awarded": 23, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "ralph", "last_awarded": 1433267996.0, "percent_earned": 0.010113780025284451,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 2, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.0050568900126422255,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "jenneh", "last_awarded": 1441736228.0, "percent_earned": 0.37420986093552466,
+        "id": "nom-nom-nom", "times_awarded": 74, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "alonid", "last_awarded": 1453299407.0, "percent_earned": 2.1238938053097343,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 420, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "onekopaka", "last_awarded": 1451613302.0, "percent_earned": 0.2528445006321113,
+        "id": "rock-the-web!", "times_awarded": 50, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and helped with porting stuff to Python 3", "tags":
+        "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "toshio", "last_awarded": 1447943130.0, "percent_earned": 0.21238938053097348,
+        "id": "parselmouth", "times_awarded": 42, "name": "Parselmouth"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "fale",
+        "last_awarded": 1453212624.0, "percent_earned": 0.38432364096080907, "id":
+        "chief-editor", "times_awarded": 76, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "pschultz", "last_awarded": 1449025570.0, "percent_earned": 5.926675094816688,
+        "id": "froglet", "times_awarded": 1172, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "puiterwijk", "last_awarded": 1450374896.0, "percent_earned": 0.015170670037926675,
+        "id": "pizzelle-cookie-iv", "times_awarded": 3, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1452873723.0, "percent_earned": 0.0050568900126422255,
+        "id": "silver", "times_awarded": 1, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "churchyard", "last_awarded": 1452875228.0, "percent_earned": 0.05056890012642225,
+        "id": "top-10", "times_awarded": 10, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "siwinski", "last_awarded": 1453319241.0, "percent_earned": 0.15676359039190896,
+        "id": "top-100", "times_awarded": 31, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1453212640.0, "percent_earned": 0.13147914032869784,
+        "id": "top-25", "times_awarded": 26, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mluscon", "last_awarded": 1453387764.0, "percent_earned": 0.3034134007585335,
+        "id": "top-500", "times_awarded": 60, "name": "Top 500"}], "user": "ralph",
+        "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png"}'}
+    headers:
+      appserver: [proxy11.fedoraproject.org]
+      apptime: [D=23056117]
+      connection: [Keep-Alive]
+      content-length: ['66178']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 21 Jan 2016 16:41:06 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_good_match b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_good_match
new file mode 100644
index 0000000..bfce42a
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_good_match
@@ -0,0 +1,60 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA4VW72+juBb9V6p+nZmODSUzGel9KASTkEKKwSZYkUaAaUgwPwq0SbOa/31v0s7s
+        vn3aeVIkYhvfe33uOQf/cZ0X/bh73OXpWFx/u74P0XgfYosy6UY7c0a5y0Im3AARRi9raLQq7IaM
+        l9T2Z0Gk5gIRPWSuKZCaBZyYElEas+5+02S4c9O52EcVoZQJizGiC42Yhe1PAtZZAhlxUBHBbTJw
+        FSwjTk4S+bAbfpy4dC2XESYTyom/aYKIzoOIcMrc24iVPGPiFCs5ZDWxKS/9QPH3db+N2DTMuOiT
+        vb9M7zqXVq6R7N1DRqoTW5f2pikqsgpqueKVa+aYWhnvhrjKj4XqIJ/pB5H5Ho1ANpleoqlylVWY
+        rubSZlzZlhKUrU2yaSTuRqgllI73mujlMq1ID9H7PC77lOWGPJlWgAnhKHml9bjj2hGzc1TSzVdr
+        JWL7r/o2DVuz5blyyGX5pLS5zQ4Ro7RgeEIj00/r4RjFx5fYpiyEMSXEgHXi2fgpPRE/c6aAsxBn
+        nAG3vyN915kZEex3SP8O503zb0hb9eIU1uX/IP07nCFaJHzqyL+QXpcXpOMYOyluX3nTLiMilyng
+        JJzjvohIF3O5ylW39uPRpzbHCZKtb+Nu0/gxTjl2tUTDjtT8cbUmKUe3h8hBRsGhr3/PFnT3rMK3
+        cY3jFKsRupJ6Skx+Zts0/y/fv2WzqiP8V2lR8TFiPqXIjzZNzmQUxosT9IqEFQljXgrYjRKe44B3
+        IwdWeKhrE1QuZU1g3FXBiZ+j76Um09U8X8JeEVbjy6aJK9XK2l+B3khQuTRgtIkj04yYmkP0F4pc
+        M9I65x55fbEuE8/ealnsWktti3LHCD1eNlIvmWcTa9PcH7o0YcY61VTP9pRH1tRf6oKIptI9p2MZ
+        OgYpLkPPUaG03UYwfuut+c7D8ile89pvOi2pchQ6ibFpvHm594DvKZcTqz6WCRJ+crp74U23knFJ
+        C6KaTBdRYQtXrMtlFvPjvUZ2mdN1YiaeAi7MXNGEr00dlFW1xwywEzHwtREVXZchC4dlNlNE2sIL
+        0fGU7Es7iKUPDDep1jUCiQSQcIGnv3wmJC54CHDsKWDA8ROoG8sZxb5JUd5TpixAl4pD56Qz7kB3
+        Vj47xqEC40LuIlY5zhx/pHsTek4aFrkxeEhM55mDS46MVtiSS1S+KWpvPkBXwByEz+ypnjCMrUb2
+        4iR3Z/+Qc3dCGV3noDBmly7Uutg0oJAmUmLBECZC8w7Q9X3OiEN1anJd9Az5bkZa7MXGENSCB5At
+        t78uRVPSIJ4KquFDyOTTmQPAXoRprsvZ2ae4Av9FXA+V4MBKL2Kkp8g+csZnQYXhvKNfgMsEbPrT
+        KfbgFJbHgI+VhJPmpH0VeumAmuOfas4wtVN8UTOoS0WBIvssUkfwihU40S+XPGePbK6D0s56QZvG
+        qi8u+V/eEPHfefAY/sODoxgcK+BquWlCbZqGcakl6BZmwHcr0QqnTOmJHJJ6PEdds0bswcf0RENG
+        DuNob3pQqxHvqQt6eYgUWaQaDYAhzRZT8F3IZ3qcV+G5+qDzAeF5gPwTRYRy+JZJhGeA4+mCY0xt
+        Ce4erKUbOhJwNCyhjcdNkzpjR09K92zXZJw7wL0HODENatf197lhNSKUcYJS3Z8zTFgQcZPaxsGv
+        q0MUqyCK5SJvVJ9UxmHTRK9DH2njJGu4t9S7OOcJjm11knO1DCO3zG1g4cw3M4aWAeJ1gNV85VSn
+        XGsPGVImAxdI9ur+/vUr6BQU24O6A3CYiY/vDlQ7PmTOAaUzdx3N/XmOcOkTQEMj1Hc6FVojTbdt
+        72nlElzKj/elyglP/TnvQadz/5Wi6SJHPvJrY5kpdcr2nK/m/EGe0NTavd0eKDPshe0Tpih8K843
+        Bkrebh0Ienn98Xp3/Q1/vK6H7fW3P66zVG6LX3++7yTcUYadeil6eFMWQ97vunHXNjCdtM9XZaHk
+        1VDkbSOvOpXmxVXbXI1lcUUK2fbplXmOMlypIpVFn7VpL88J6xRCP/cKgpTj2A3fPn++pBtuHi/b
+        ur7dF/l40/bbz12zHT5r39/K0W/RDUxAjCatz9en8K20Hx+vnwd4/qx7+H4eXqrX3pbe3+9T1ZXX
+        P35czvt2Og3hySf8mGUY68anyVecfbqVevZpmt6iTxI9TopM6lh/vIWsw27bpONzfw7VGkZIH3T4
+        HB0dMqZO6Gok+KL7UdKWyXHfDlU7fUnkbqk+YKuV9/TDc2Edl9vxuDtNHvsiEaYeLF6/5HcPcHNr
+        qVf029l0+7JzZnGirz+vjbtbNf+Appr6emfN1WcVRbFZj0VjDWbiPfdOUFgxkONY48Nhm3fbZw1N
+        59sPu03zwViejKdFoYrmOcULuymD/1x6PbTPfV58f0dDpmPatHV9ae77EsA5vPUX3UxuDFgYd3Ux
+        jGndAU9uDe3rF/2Lpt8gWGi7XX5Got/+o3HwlOep965eHjfp4dz+H38CIdnL2QILAAA=
+    headers:
+      appserver: [proxy08.fedoraproject.org]
+      apptime: [D=55142]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1874']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:41:30 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_topic b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_topic
new file mode 100644
index 0000000..25e7a53
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_topic
@@ -0,0 +1,59 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=98106]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1823']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:41:31 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_user b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_user
new file mode 100644
index 0000000..44ea8bf
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_user
@@ -0,0 +1,62 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f
+  response:
+    body:
+      string: !!binary |
+        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
+        CwAA
+    headers:
+      appserver: [proxy10.phx2.fedoraproject.org]
+      apptime: [D=12673]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1941']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:41:31 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_data_simple
new file mode 100644
index 0000000..e4c8d8d
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_data_simple
@@ -0,0 +1,810 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"percent_earned": 47.05882352941176, "assertions":
+        [{"description": "You attended Flock 2013, the Fedora Contributor Conference",
+        "tags": "flock,event,", "issued": 1375373082.0, "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "gnokii", "last_awarded": 1386188828.0, "percent_earned": 0.4045921205684519,
+        "id": "flock-2013-attendee", "times_awarded": 80, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bitlord", "last_awarded": 1452636478.0, "percent_earned": 1.1278005360845598,
+        "id": "tagger-tagger-ii", "times_awarded": 223, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bitlord", "last_awarded": 1452632614.0, "percent_earned": 1.7498609214585545,
+        "id": "junior-tagger-tagger-i", "times_awarded": 346, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "fishers1967", "last_awarded": 1453390941.0, "percent_earned": 58.06402670307996,
+        "id": "involvement", "times_awarded": 11481, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "leifmadsen",
+        "last_awarded": 1453305829.0, "percent_earned": 7.510241238051889, "id": "speak-up!",
+        "times_awarded": 1485, "name": "Speak Up!"}, {"description": "Edited at least
+        10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0, "image":
+        "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "cnangel",
+        "last_awarded": 1453350349.0, "percent_earned": 4.784301825721944, "id": "junior-editor",
+        "times_awarded": 946, "name": "Junior Editor"}, {"description": "Edited at
+        least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0, "image":
+        "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "raven",
+        "last_awarded": 1452869625.0, "percent_earned": 3.272138775097355, "id": "associate-editor",
+        "times_awarded": 647, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "farhaan",
+        "last_awarded": 1453312868.0, "percent_earned": 2.7360542153441565, "id":
+        "secretary-general", "times_awarded": 541, "name": "Secretary General"}, {"description":
+        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
+        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "mastaiza", "last_awarded": 1451951597.0, "percent_earned": 0.5310271582460933,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 105, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "fale", "last_awarded": 1453273101.0, "percent_earned": 0.950791483335862,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 188, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "cstratak",
+        "last_awarded": 1453310380.0, "percent_earned": 5.735093309057806, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1134, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "eischmann", "last_awarded": 1453239619.0, "percent_earned": 4.622464977494563,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 914, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "gnat",
+        "last_awarded": 1452623672.0, "percent_earned": 2.6349061852020434, "id":
+        "if-you-build-it...-koji-success-iii", "times_awarded": 521, "name": "If you
+        build it... (Koji Success III)"}, {"description": "Ten or more questions and
+        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
+        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedelibre", "last_awarded": 1453367297.0, "percent_earned": 2.508471147524402,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 496, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "panos", "last_awarded": 1453375409.0, "percent_earned": 16.2949476558944,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 3222, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "quinnrm", "last_awarded": 1453389677.0, "percent_earned": 3.155818540433925,
+        "id": "riddle-me-this", "times_awarded": 624, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "cockpit", "last_awarded": 1453321371.0, "percent_earned": 3.919486168006878,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 775, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "eischmann", "last_awarded": 1453239295.0, "percent_earned": 3.8284529408789765,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 757, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "suraia",
+        "last_awarded": 1452800930.0, "percent_earned": 5.3507307945177764, "id":
+        "you-can-call-me-patches-scm-i", "times_awarded": 1058, "name": "You can call
+        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
+        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "lvrabec",
+        "last_awarded": 1452698912.0, "percent_earned": 0.8749304607292773, "id":
+        "you-can-call-me-patches-scm-iv", "times_awarded": 173, "name": "You can call
+        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
+        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "pschiffe",
+        "last_awarded": 1453290910.0, "percent_earned": 2.4781267384817682, "id":
+        "you-can-call-me-patches-scm-iii", "times_awarded": 490, "name": "You can
+        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "ankursinha", "last_awarded": 1452452682.0, "percent_earned": 1.183431952662722,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 234, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "pkilambi", "last_awarded": 1453335472.0, "percent_earned": 2.548930359581247,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 504, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "lvrabec", "last_awarded": 1452777318.0, "percent_earned": 0.9153896727861224,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 181, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "stevenmerrill", "last_awarded": 1453314068.0, "percent_earned": 4.718555606129571,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 933, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "lovetide", "last_awarded": 1453389567.0, "percent_earned": 11.975926768826177,
+        "id": "junior-badger-badger-i", "times_awarded": 2368, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "jortel", "last_awarded": 1453223123.0, "percent_earned": 5.006827492034593,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 990, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "fmuellner", "last_awarded": 1453226784.0, "percent_earned": 2.8321448439791634,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 560, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "heffer",
+        "last_awarded": 1453162247.0, "percent_earned": 0.677691801952157, "id": "like-a-rock-updates-stable-iii",
+        "times_awarded": 134, "name": "Like a Rock (Updates-Stable III)"}, {"description":
+        "*(aimless searching, only the sound of cicadas)*\nTested and added karma
+        to 1 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,", "issued":
+        1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "nshaikh", "last_awarded": 1453381228.0, "percent_earned": 11.626966064835887,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2299, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "gnat",
+        "last_awarded": 1453138519.0, "percent_earned": 2.260658473676225, "id": "like-a-rock-updates-stable-ii",
+        "times_awarded": 447, "name": "Like a Rock (Updates-Stable II)"}, {"description":
+        "Partied with Flock 2013 (at the South Carolina Aquarium)", "tags": "party,flock,event,",
+        "issued": 1376252202.0, "image": "https://badges.fedoraproject.org/pngs/tanked.png",
+        "first_awarded": 1376252202.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "gnokii", "last_awarded": 1411656869.0, "percent_earned": 0.31355889344055027,
+        "id": "tanked!", "times_awarded": 62, "name": "Tanked!"}, {"description":
+        "You proposed a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,",
+        "issued": 1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jsmith", "last_awarded": 1453126870.0, "percent_earned": 0.5967733778384666,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 118, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "drsn0w", "last_awarded": 1453260519.0, "percent_earned": 9.98331057502655,
+        "id": "bona-fide", "times_awarded": 1974, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.13149243918474687,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "jmlich", "last_awarded": 1453380139.0, "percent_earned": 1.254235573762201,
+        "id": "senior-badger-badger-ii", "times_awarded": 248, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "cstratak",
+        "last_awarded": 1453371252.0, "percent_earned": 5.3203863854751425, "id":
+        "is-this-thing-on-updates-testing-i", "times_awarded": 1052, "name": "Is this
+        thing on? (Updates-Testing I)"}, {"description": "Pushed 20 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "rcritten", "last_awarded": 1452870021.0, "percent_earned": 2.7866282304152126,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 551, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "bmbouter",
+        "last_awarded": 1453326365.0, "percent_earned": 3.1103019268699743, "id":
+        "partners-in-crime", "times_awarded": 615, "name": "Partners in Crime"}, {"description":
+        "*(a great struggle, repeated escapes, discipline required)*\nTested and added
+        karma to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "rbarlow", "last_awarded": 1452797003.0, "percent_earned": 1.5930814747382795,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 315, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "jibecfed", "last_awarded":
+        1451517381.0, "percent_earned": 0.24275527234107114, "id": "master-tagger-tagger-iv",
+        "times_awarded": 48, "name": "Master Tagger (Tagger IV)"}, {"description":
+        "A member of the sysadmin-badges group.  Nothing to see here..  move along.",
+        "tags": "infrastructure,badges,community,", "issued": 1378319150.0, "image":
+        "https://badges.fedoraproject.org/pngs/fas-inside-job.png", "first_awarded":
+        1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "decause", "last_awarded": 1435781009.0, "percent_earned": 0.025287007535528244,
+        "id": "inside-job", "times_awarded": 5, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "jvasallo", "last_awarded": 1453390587.0, "percent_earned": 12.304657866788045,
+        "id": "white-rabbit", "times_awarded": 2433, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "hahnsaja", "last_awarded": 1453391469.0, "percent_earned": 4.617407575987458,
+        "id": "mugshot", "times_awarded": 913, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.08597582562079603,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "sayanchowdhury", "last_awarded": 1449249202.0, "percent_earned": 0.1668942497344864,
+        "id": "maestro", "times_awarded": 33, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "aniketkhisti", "last_awarded": 1453384257.0, "percent_earned": 7.6923076923076925,
+        "id": "let-me-introduce-myself", "times_awarded": 1521, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "suraia", "last_awarded": 1452876478.0, "percent_earned": 1.3300965963687856,
+        "id": "binary-star", "times_awarded": 263, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "cweyl", "last_awarded": 1451604516.0, "percent_earned": 0.6827492034592627,
+        "id": "packager-sponsor", "times_awarded": 135, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "jmlich", "last_awarded": 1453380114.0, "percent_earned": 2.8574318515146917,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 565, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "fale", "last_awarded": 1452955260.0, "percent_earned": 2.4275527234107117,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 480, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "m4rtink", "last_awarded": 1451904147.0, "percent_earned": 3.373286805239468,
+        "id": "bloggin-it!-planet-i", "times_awarded": 667, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jcajka", "last_awarded": 1452784301.0, "percent_earned": 1.729631315430132,
+        "id": "white-hat", "times_awarded": 342, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.3995347190613463,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "coralatlas", "last_awarded": 1453259601.0, "percent_earned": 27.962372932787133,
+        "id": "embryo", "times_awarded": 5529, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mastaiza", "last_awarded": 1453293512.0, "percent_earned": 0.8799878622363829,
+        "id": "taming-the-bull-tester-v", "times_awarded": 174, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "fale", "last_awarded": 1451379096.0, "percent_earned": 0.27309968138370505,
+        "id": "common-bugs-contributor", "times_awarded": 54, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "tomh", "last_awarded": 1453387927.0, "percent_earned": 8.56723815303697,
+        "id": "baby-badger", "times_awarded": 1694, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "piotrp", "last_awarded": 1449068505.0, "percent_earned": 0.12137763617053557,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 24, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pfrields", "last_awarded": 1453230770.0, "percent_earned": 1.082283922520609,
+        "id": "old-yeller", "times_awarded": 214, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.3590755070045011,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "paulcarroty", "last_awarded": 1451415976.0, "percent_earned": 1.542507459667223,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 305, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "tomh", "last_awarded": 1453043511.0, "percent_earned": 1.6942295048803926,
+        "id": "senior-editor", "times_awarded": 335, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "nilix007", "last_awarded": 1449026189.0, "percent_earned": 17.756536691447934,
+        "id": "tadpole", "times_awarded": 3511, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "rajalakshmi", "last_awarded": 1449029694.0, "percent_earned": 37.68269862944419,
+        "id": "egg", "times_awarded": 7451, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "jdulaney", "last_awarded": 1446505520.0, "percent_earned": 9.781014514742326,
+        "id": "tadpole-with-legs", "times_awarded": 1934, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "sayanchowdhury", "last_awarded": 1449715315.0, "percent_earned": 0.10114803014211297,
+        "id": "badge-off!", "times_awarded": 20, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vinumoses", "last_awarded": 1451694870.0, "percent_earned": 0.475395741667931,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 94, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "aryasaatvik", "last_awarded": 1452796719.0, "percent_earned": 0.66251959743084,
+        "id": "no-longer-a-ronin", "times_awarded": 131, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jibecfed", "last_awarded": 1451496270.0, "percent_earned": 0.2579274768623881,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 51, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bitlord", "last_awarded": 1452632607.0, "percent_earned": 1.456531634046427,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 288, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "duffy", "last_awarded": 1451767725.0, "percent_earned": 0.5209123552318818,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 103, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mastaiza", "last_awarded": 1453367728.0, "percent_earned": 0.9255044758003338,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 183, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "event,speaker,", "issued": 1390422108.0, "image":
+        "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.23264046932685986, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "valtri", "last_awarded": 1452814661.0, "percent_earned": 0.38436251454002934,
+        "id": "patches-scm-v", "times_awarded": 76, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "cstratak", "last_awarded": 1453371384.0, "percent_earned": 1.4009002174682648,
+        "id": "override,-you-say", "times_awarded": 277, "name": "Override, you say?"},
+        {"description": "You attended devconf.cz, a yearly Linux and JBoss conference
+        in the Czech Republic", "tags": "event,devconf,", "issued": 1391763090.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png", "first_awarded":
+        1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.31355889344055027,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "nb", "last_awarded": 1439569573.0, "percent_earned":
+        0.060688818085267784, "id": "videographer", "times_awarded": 12, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "sagitter", "last_awarded": 1450261520.0, "percent_earned": 0.2376978708339655,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 47,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "tkral", "last_awarded": 1453372187.0, "percent_earned": 5.719921104536489,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1131, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "plfiorini", "last_awarded": 1453366379.0, "percent_earned": 3.7070753047084413,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 733, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "catanzaro",
+        "last_awarded": 1453387064.0, "percent_earned": 3.342942396196834, "id": "it-still-works!",
+        "times_awarded": 661, "name": "It still works!"}, {"description": "You submitted
+        an update to bodhi with one or more bugzilla bug numbers attached", "tags":
+        "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cstratak", "last_awarded": 1453371258.0, "percent_earned": 4.147069235826632,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 820, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "bochecha", "last_awarded": 1452463312.0, "percent_earned": 0.66251959743084,
+        "id": "bob-loblaw-planet-v", "times_awarded": 131, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "piotrp", "last_awarded": 1452692980.0, "percent_earned": 0.11126283315632428,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 22, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "potty", "last_awarded": 1448485603.0, "percent_earned": 0.2680422798765994,
+        "id": "lets-do-lunch!", "times_awarded": 53, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "piotrp", "last_awarded":
+        1452501182.0, "percent_earned": 0.7434380215445304, "id": "vacation", "times_awarded":
+        147, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "event,python,", "issued": 1397168025.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png",
+        "first_awarded": 1397168025.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "abompard", "last_awarded": 1397573900.0, "percent_earned": 0.05057401507105649,
+        "id": "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 1.44135942952511,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "ilgrad", "last_awarded": 1452896392.0, "percent_earned": 2.0128457998280487,
+        "id": "helping-hand", "times_awarded": 398, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.4652809386537197,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "mcrha",
+        "last_awarded": 1453136709.0, "percent_earned": 0.3489607039902898, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 69, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "fishers1967", "last_awarded": 1453390883.0, "percent_earned": 69.3824912759824,
+        "id": "paranoid-panda", "times_awarded": 13719, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.3691903100187124, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "swilkerson", "last_awarded": 1453199550.0, "percent_earned": 1.7953775350225056,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 355, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "siwinski",
+        "last_awarded": 1453319029.0, "percent_earned": 0.981135892378496, "id": "master-editor",
+        "times_awarded": 194, "name": "Master Editor"}, {"description": "You have
+        received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mluscon", "last_awarded": 1450742624.0, "percent_earned": 0.5866585748242553,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 116, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405334492.0, "first_awarded_person": "sgallagh", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.6119455823597835,
+        "id": "flock-2014-attendee", "times_awarded": 121, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "devhen", "last_awarded": 1452673329.0, "percent_earned": 0.6574621959237344,
+        "id": "science-kernel-tester-i", "times_awarded": 130, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.4501087341324028, "id":
+        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
+        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
+        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "limb", "last_awarded": 1452540830.0, "percent_earned": 0.05563141657816214,
+        "id": "corporate-overlord", "times_awarded": 11, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "greghellings", "last_awarded": 1453354804.0, "percent_earned": 0.3439033024831841,
+        "id": "corporate-shill", "times_awarded": 68, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "cstratak", "last_awarded": 1453390902.0, "percent_earned": 2.483184139988874,
+        "id": "corporate-drone", "times_awarded": 491, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1452297195.0, "percent_earned": 0.17195165124159206,
+        "id": "master-badger-badger-iii", "times_awarded": 34, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "heikoada", "last_awarded":
+        1452772620.0, "percent_earned": 0.3793051130329237, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 75, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "chrisroberts", "last_awarded": 1439838603.0, "percent_earned": 0.15677944672027513,
+        "id": "dancing-with-toshio", "times_awarded": 31, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.5563141657816214, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "iaguis",
+        "last_awarded": 1452874718.0, "percent_earned": 2.0229606028422595, "id":
+        "consolation-prize", "times_awarded": 400, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "lovetide", "last_awarded": 1453389559.0, "percent_earned": 12.324887472816467,
+        "id": "crypto-panda", "times_awarded": 2437, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "paulotada", "last_awarded": 1453313558.0, "percent_earned": 3.262023972083144,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 645, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "ppisar", "last_awarded": 1447066663.0, "percent_earned": 0.04551661356395084,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 9, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "ohaessler", "last_awarded": 1452768576.0, "percent_earned": 1.3048095888332576,
+        "id": "the-cat-came-back...", "times_awarded": 258, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "spot", "last_awarded": 1446145228.0, "percent_earned": 0.09103322712790168,
+        "id": "apprentice-badge-artist-i", "times_awarded": 18, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "sandeen", "last_awarded": 1439922999.0, "percent_earned": 0.28321448439791636,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 56, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.09103322712790168,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.31355889344055027,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "rdieter", "last_awarded": 1449536137.0, "percent_earned": 0.030344409042633892,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 6, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "icon", "last_awarded": 1453222652.0, "percent_earned": 4.101552622262681,
+        "id": "associate-badger-badger-1.5", "times_awarded": 811, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "jenneh", "last_awarded": 1441736246.0, "percent_earned": 0.3995347190613463,
+        "id": "flock-2015-attendee", "times_awarded": 79, "name": "FLOCK 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "mluscon", "last_awarded": 1453387739.0, "percent_earned": 2.2556010721691195,
+        "id": "macaron-cookie-i", "times_awarded": 446, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "walters",
+        "last_awarded": 1452199929.0, "percent_earned": 0.2680422798765994, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 53, "name": "Chocolate Chip (Cookie
+        II)"}, {"description": "Voted in the supplemental wallpapers election for
+        the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.40964952207555755,
+        "id": "nuancier-f22", "times_awarded": 81, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "jvasallo", "last_awarded": 1453390594.0, "percent_earned": 36.86845698680018,
+        "id": "origin", "times_awarded": 7290, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "tadej", "last_awarded": 1450046737.0, "percent_earned": 2.048247610377788,
+        "id": "delivery", "times_awarded": 405, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "pabelanger", "last_awarded": 1453318849.0, "percent_earned": 0.9406766803216507,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 186,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "hguemar", "last_awarded": 1453303231.0, "percent_earned": 0.05057401507105649,
+        "id": "black-and-white-cookie-iii", "times_awarded": 10, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "piotrp", "last_awarded": 1451395906.0, "percent_earned": 0.12643503767764122,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 25, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433267989.0, "percent_earned": 0.005057401507105649,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 1, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "eischmann", "last_awarded": 1452092327.0, "percent_earned": 0.035401810549739544,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 7, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "viveknrt", "last_awarded": 1452876035.0, "percent_earned": 0.11632023466342993,
+        "id": "badge-muse-badges-released-i", "times_awarded": 23, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "ralph", "last_awarded": 1433267996.0, "percent_earned": 0.010114803014211297,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 2, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.005057401507105649,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "jenneh", "last_awarded": 1441736228.0, "percent_earned": 0.37424771152581804,
+        "id": "nom-nom-nom", "times_awarded": 74, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "alonid", "last_awarded": 1453299407.0, "percent_earned": 2.124108632984373,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 420, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "onekopaka", "last_awarded": 1451613302.0, "percent_earned": 0.25287007535528244,
+        "id": "rock-the-web!", "times_awarded": 50, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and helped with porting stuff to Python 3", "tags":
+        "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "toshio", "last_awarded": 1447943130.0, "percent_earned": 0.21241086329843728,
+        "id": "parselmouth", "times_awarded": 42, "name": "Parselmouth"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "fale",
+        "last_awarded": 1453212624.0, "percent_earned": 0.38436251454002934, "id":
+        "chief-editor", "times_awarded": 76, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "pschultz", "last_awarded": 1449025570.0, "percent_earned": 5.927274566327821,
+        "id": "froglet", "times_awarded": 1172, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "puiterwijk", "last_awarded": 1450374896.0, "percent_earned": 0.015172204521316946,
+        "id": "pizzelle-cookie-iv", "times_awarded": 3, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1452873723.0, "percent_earned": 0.005057401507105649,
+        "id": "silver", "times_awarded": 1, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "churchyard", "last_awarded": 1452875228.0, "percent_earned": 0.05057401507105649,
+        "id": "top-10", "times_awarded": 10, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "siwinski", "last_awarded": 1453319241.0, "percent_earned": 0.15677944672027513,
+        "id": "top-100", "times_awarded": 31, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1453212640.0, "percent_earned": 0.13149243918474687,
+        "id": "top-25", "times_awarded": 26, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mluscon", "last_awarded": 1453387764.0, "percent_earned": 0.30344409042633896,
+        "id": "top-500", "times_awarded": 60, "name": "Top 500"}], "user": "ralph",
+        "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png"}'}
+    headers:
+      appserver: [proxy10.phx2.fedoraproject.org]
+      apptime: [D=14564110]
+      connection: [Keep-Alive]
+      content-length: ['66175']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 21 Jan 2016 15:58:44 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_good_match b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_good_match
new file mode 100644
index 0000000..141bebb
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_good_match
@@ -0,0 +1,117 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy11.fedoraproject.org]
+      apptime: [D=168454]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1823']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:06:58 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA4VW72+juBb9V6p+nZmODSUzGel9KASTkEKKwSZYkUaAaUgwPwq0SbOa/31v0s7s
+        vn3aeVIkYhvfe33uOQf/cZ0X/bh73OXpWFx/u74P0XgfYosy6UY7c0a5y0Im3AARRi9raLQq7IaM
+        l9T2Z0Gk5gIRPWSuKZCaBZyYElEas+5+02S4c9O52EcVoZQJizGiC42Yhe1PAtZZAhlxUBHBbTJw
+        FSwjTk4S+bAbfpy4dC2XESYTyom/aYKIzoOIcMrc24iVPGPiFCs5ZDWxKS/9QPH3db+N2DTMuOiT
+        vb9M7zqXVq6R7N1DRqoTW5f2pikqsgpqueKVa+aYWhnvhrjKj4XqIJ/pB5H5Ho1ANpleoqlylVWY
+        rubSZlzZlhKUrU2yaSTuRqgllI73mujlMq1ID9H7PC77lOWGPJlWgAnhKHml9bjj2hGzc1TSzVdr
+        JWL7r/o2DVuz5blyyGX5pLS5zQ4Ro7RgeEIj00/r4RjFx5fYpiyEMSXEgHXi2fgpPRE/c6aAsxBn
+        nAG3vyN915kZEex3SP8O503zb0hb9eIU1uX/IP07nCFaJHzqyL+QXpcXpOMYOyluX3nTLiMilyng
+        JJzjvohIF3O5ylW39uPRpzbHCZKtb+Nu0/gxTjl2tUTDjtT8cbUmKUe3h8hBRsGhr3/PFnT3rMK3
+        cY3jFKsRupJ6Skx+Zts0/y/fv2WzqiP8V2lR8TFiPqXIjzZNzmQUxosT9IqEFQljXgrYjRKe44B3
+        IwdWeKhrE1QuZU1g3FXBiZ+j76Um09U8X8JeEVbjy6aJK9XK2l+B3khQuTRgtIkj04yYmkP0F4pc
+        M9I65x55fbEuE8/ealnsWktti3LHCD1eNlIvmWcTa9PcH7o0YcY61VTP9pRH1tRf6oKIptI9p2MZ
+        OgYpLkPPUaG03UYwfuut+c7D8ile89pvOi2pchQ6ibFpvHm594DvKZcTqz6WCRJ+crp74U23knFJ
+        C6KaTBdRYQtXrMtlFvPjvUZ2mdN1YiaeAi7MXNGEr00dlFW1xwywEzHwtREVXZchC4dlNlNE2sIL
+        0fGU7Es7iKUPDDep1jUCiQSQcIGnv3wmJC54CHDsKWDA8ROoG8sZxb5JUd5TpixAl4pD56Qz7kB3
+        Vj47xqEC40LuIlY5zhx/pHsTek4aFrkxeEhM55mDS46MVtiSS1S+KWpvPkBXwByEz+ypnjCMrUb2
+        4iR3Z/+Qc3dCGV3noDBmly7Uutg0oJAmUmLBECZC8w7Q9X3OiEN1anJd9Az5bkZa7MXGENSCB5At
+        t78uRVPSIJ4KquFDyOTTmQPAXoRprsvZ2ae4Av9FXA+V4MBKL2Kkp8g+csZnQYXhvKNfgMsEbPrT
+        KfbgFJbHgI+VhJPmpH0VeumAmuOfas4wtVN8UTOoS0WBIvssUkfwihU40S+XPGePbK6D0s56QZvG
+        qi8u+V/eEPHfefAY/sODoxgcK+BquWlCbZqGcakl6BZmwHcr0QqnTOmJHJJ6PEdds0bswcf0RENG
+        DuNob3pQqxHvqQt6eYgUWaQaDYAhzRZT8F3IZ3qcV+G5+qDzAeF5gPwTRYRy+JZJhGeA4+mCY0xt
+        Ce4erKUbOhJwNCyhjcdNkzpjR09K92zXZJw7wL0HODENatf197lhNSKUcYJS3Z8zTFgQcZPaxsGv
+        q0MUqyCK5SJvVJ9UxmHTRK9DH2njJGu4t9S7OOcJjm11knO1DCO3zG1g4cw3M4aWAeJ1gNV85VSn
+        XGsPGVImAxdI9ur+/vUr6BQU24O6A3CYiY/vDlQ7PmTOAaUzdx3N/XmOcOkTQEMj1Hc6FVojTbdt
+        72nlElzKj/elyglP/TnvQadz/5Wi6SJHPvJrY5kpdcr2nK/m/EGe0NTavd0eKDPshe0Tpih8K843
+        Bkrebh0Ienn98Xp3/Q1/vK6H7fW3P66zVG6LX3++7yTcUYadeil6eFMWQ97vunHXNjCdtM9XZaHk
+        1VDkbSOvOpXmxVXbXI1lcUUK2fbplXmOMlypIpVFn7VpL88J6xRCP/cKgpTj2A3fPn++pBtuHi/b
+        ur7dF/l40/bbz12zHT5r39/K0W/RDUxAjCatz9en8K20Hx+vnwd4/qx7+H4eXqrX3pbe3+9T1ZXX
+        P35czvt2Og3hySf8mGUY68anyVecfbqVevZpmt6iTxI9TopM6lh/vIWsw27bpONzfw7VGkZIH3T4
+        HB0dMqZO6Gok+KL7UdKWyXHfDlU7fUnkbqk+YKuV9/TDc2Edl9vxuDtNHvsiEaYeLF6/5HcPcHNr
+        qVf029l0+7JzZnGirz+vjbtbNf+Appr6emfN1WcVRbFZj0VjDWbiPfdOUFgxkONY48Nhm3fbZw1N
+        59sPu03zwViejKdFoYrmOcULuymD/1x6PbTPfV58f0dDpmPatHV9ae77EsA5vPUX3UxuDFgYd3Ux
+        jGndAU9uDe3rF/2Lpt8gWGi7XX5Got/+o3HwlOep965eHjfp4dz+H38CIdnL2QILAAA=
+    headers:
+      appserver: [proxy03.fedoraproject.org]
+      apptime: [D=99135]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1874']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:11:16 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_topic b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_topic
new file mode 100644
index 0000000..26d99fc
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_topic
@@ -0,0 +1,59 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy03.fedoraproject.org]
+      apptime: [D=107470]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1823']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:06:59 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_user b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_user
new file mode 100644
index 0000000..7f29a67
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_user
@@ -0,0 +1,119 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy01.phx2.fedoraproject.org]
+      apptime: [D=4994]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1823']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:07:00 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f
+  response:
+    body:
+      string: !!binary |
+        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
+        CwAA
+    headers:
+      appserver: [proxy12.fedoraproject.org]
+      apptime: [D=143566]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1941']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:11:17 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_old b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_old
new file mode 100644
index 0000000..2c37a30
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_old
@@ -0,0 +1,247 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        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
+        ubkEsJUZnCGJf/9/FQ8wekRjAQA=
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=8742172]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 21 Jan 2016 20:30:43 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_simple
new file mode 100644
index 0000000..8f957b0
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_simple
@@ -0,0 +1,247 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA+ybe4+juLLAv0or/85kwpuw0pXukEDeZDBgEm4ftQw2gfAMkOfRfvdj0j3v7ZmR
+        7mqPzlk0rWmMcbkoVxX1a8M/e6jaHTOSN3Xvt3/2AtSQXVHFhLb+7x9ve0GRNyjOX1qYpA3q/ZYf
+        0/Rtj+T44+GuKo4loc0QpTV528tIe1k7Ii+ap29ltudKFCRo9+WZpijj4Iv2sSbVS7OoMKl6v9Hp
+        66D3tvf12JIe9n5j3/aq4lw/laR6ej7DiW97dYOq5qOSX07wUXivQmkZ9f7xe3unx7x5HlY+S+d5
+        kTYqdH7KSF2/zEhNRKomDuP2rqhOS4tplhY7Ag6e27E6BnDuWI43NxndAfc+phkl7NxyoA00Y2za
+        eOoxOm85c9Vj0rHpejfMAOA65fIx99lyjqbe3k50ABxv5Dg673G6SjRDMp1y5DGiaya6BzW9hqm5
+        sKFORxt0NP2B+hxs8MJmdQlA3XjMTRtMTVuHwJkLthNB3/FuboprP9M1ACPDTOFLv1HYjmL50Ku2
+        e2OB3pdzkMzF7X5+9vXk5mwi7TEnib42M7yGyVwNWDDyYVm7SXAhaUnnUw3TVl+k6XQ2jO7S0mjt
+        JyxYT7HmwFQbpR5wNqr+mGO2bKguFp6srls+WqBEr6j0KnCjCjmBiG/qyGR1HTLbK8iaGHIX1mml
+        6uV0vUk9V/us32PubJxFqzmda2TokQY152I7ABJN0YBtGChbXWxbP7kacCxbN4AOBTsF+ophD9ub
+        bqxchdoZeK2dqd2+tPT7UvV1z/mRpX9k58f8NUuPstnNyqLvLP0jO1NpGzofhz9b2o32gPGOnh4t
+        fO2yNbPdwt0bLoGlY26i1ctokcB0a+ZpvMrV2rUNgN0ZtZuViYbDKbzF6B7Qn9eGOB7vQpysXKOB
+        G/BZ+vvSABpk3Yx1EXfXfW9pJbd1aTsD48fc2Hh73zUEKytVxMxzxOsF4lK6XsHZTAwAIF3tpPUK
+        XGOoT93sgsAtFUfpa7pZDs5sRzsDxrADB9sW7QG6rtOVAdDRVUPDa9MBYzNLabDNc8cxREC1ADm+
+        uE6ycDY7bu2WBZWmzbck0S4wLQtb312thApIMFhP0qW/0TdU2BRBqLnTaBw4oETsStzmhgh19Whw
+        no3cLesk4tRJPOq93rlc0DkPIG7QilHACkaiyc6rLZtcVgxcOuN56VNpnstcglzlnWzH+9zuukpV
+        D40dwZrqy7Vbn4wJTqg0WG7gZMWZmb6nuQIEiVeuUj3yXXhYsl4JXHaBIeYWt90VxU1ucOAGWc+w
+        Wz/UdGA685OhpSOYl3QVaOZx7Q0et/EG09kZanPV2gQLaicVa/Pcn2C6KnhE80xBrwUrDc7NNE2d
+        FE9IBu0VNCA9lzv7uUvjFJZbutIJYL2K5rC1PzGOTq4i370cXBhZrVeY++fI9zSQOxCPzFS/eoxy
+        QFRfyIg37LJnX2Ntmt82cxbzNC5tOIMaXbe9/hxRe/VgJunMbjOl1uRmOr+OUn0S7KHucekCcjBx
+        9xC4Y11FY3UJJ4LwmFMPWAJmfg6gMfL5knoBjXbnYphu8zEeabQZLkxYweRL1UrmuZ1uF9R7cppB
+        K8MBhpPoPJhgj0ZW6/9OpGMO2NT/BX+ib7yJYjiZwYP0JT6cRsc3OL1nrsxogIvhpxjYlQmND7P1
+        VyqNob7mwDHR2OlzxMy3dhttdsRTD36RBvRv8uCX0T9GL9H/mI/ScrralIgksKF3BL6NByvRLboa
+        HmTnzBYGrAnLBtKsuWLKYstEC5zptF0m5g1yj/mWY1OT5jIwKRbQmbGWDoQtBy1qE+d57simumvU
+        t5a0nQfUbvenkWtopluqttba0ZvRe6GxQK1pmMyMMTf3HL+wOAVZZllQ+6xNqOs0v1EPBTlNm6q1
+        jxw4wavVdB55fDrCaSGCVI1wXHOeJqo0Fm7aDVGtzXxbuZZyIY5S2QxAeKqf125xGiU4WU8dlmTm
+        GSb6GW/S2SrX1e1txwZOcEUarLeMd3CuzeUxXzuKuM2ahGaXs3nTxSBJb8BqOJR4NGd7B5Sal9Ue
+        SpjXqN66AVnnbMHd1c5LDnOpELiXrcGWl4ALaEZaTWdn47Y7OVPjgz0BS5tqD11A73w+caYe5/OR
+        CaZlbdsrATmaMoqfn//AEbWZZuhOCmi2p898CKjdnisHZvGY05omvpcwWb27F2FFlsVNe0SLjrYo
+        6e1o823Pr1AeRLRZkbAeRATheoDJiaRFSXtJhuK07fQJyv+3IjhCzTsqqtfWY/f6hXbq8eWhIXXz
+        kKOMvKNd7W96HrR10INKR94LrKadZVBXpwGdeVCRsqjj5l7CDUKCiwr1o6Nfv3tWq+1ulcW0InoK
+        KkJ/0VKwxwo8L/DDoTTsvb2XblVcNnGRt1rcZTxMqYz23unVIvNJlS8muOtS3U3wXMPVpGnifHcv
+        VbU8LKqAPNXxLie4X4Th07Ph6qc4fyrp9f2KHI70Zj/Vpas4j7Nj9lQHRUVoxUkLu2pHvrm2Txdi
+        nafXJ1TfRdN7QvkfXvki1SV+PyqKpP6oZVzXRyq+onVqW7c21ZFeVVbFngTNEy6Ce7mNnm3x0knH
+        Pb3IrZ9P0pK0Qbt7kfpikTgPK9R7qV5bC4R01Mf1I9n1YUxGiPZlqJ32kz0xCdqzvd9/b5fqRM/4
+        vsgKjCxwOCS+gCRZVgJZ9NkhiwVWZnyFMGTIsWKvNTjJP90oLaefKSGMU3I/aBdp0PrT8/9P5xjv
+        yMdGUPhnQr2kvN5dGeO4veX67umUJMjnVhrnrTyuVbEpGpT+bMCLAt8MrY9ZhqrrH7l5a7Jne7RL
+        1F5MY+2p9bwex7BSXyEBz4iS0pcUupqCLAn9IeL5PpKxxPoiQmTItuagDoGaY3Wv/AuoZWCmyISt
+        BatY73Es5fpqlpmBvhOGu+t0KOnhtOL8sNZ32UU7TC/j4WxWrkz50Oy5eNcchPGoMt6PrMfczufr
+        aq7aJ0mRbtFiG4XscXtVGUsCwmbGr8QTVEeiOB5gneM1L38zXbPzkxsuXGUVBB/mb2YZArp/HvOb
+        +DEfxtFVi9bMbE3eb9PdLZ/O/ueeZ+ri2MbMR9dADcppzNzd5aXrRMnoOUqZd9K71geamOaPBmUl
+        Nbgg8tRzlKH4jnkhKnphXLyjyESt8o46Of54TJPDu4oEJD5R33vbcVPHTR03ddzUcVPHTR03ddz0
+        H8ZNgLQl00MTkQdajdP56ofnWvehKR7aGjSIUNV0QPX3BKqh7xPOF5kAywwtkBVJGLKhFCKGl2WB
+        DGVOFBWJl/hfBCpMQnRMmz8gJ+4rEOI+4Y9AVbkP/QhgT3TJ4ubp6f8h4sXPv5fAfCVBkD+LkL+V
+        8TkyvpPSjvtCDPOllFcwUPyaA8XPICh8Gs0y36Dgr0fuzxgxZEJEfIXvC6HP9oUhQn0/kJg+HwpB
+        GIa+TMLgG0bEGTs+T0p3ze38ydYVVC9MRW6DqtDYGamxbMbF3sN8kuZFYZ23tjBDo2RlhJ7sM0nN
+        DvIZu4veS8S8WjSPouvFPIjLa+OVk2aFptOrpItox+xwHU9PGcftJG10BspEVUCVNBNWvcbX3fC4
+        qczpSZKiNQBBbReFmMYbSpwa3m4Yd18a8dl9D5lLUfyZjCjxHSN2jNgxYseIHSN2jNgxYseI/0ZG
+        5P8KRrRoTZmiunkitGIluIPBvycMypiTFZFnWMWXRYHlJJGX5ABJLIMFhGSfZxkUcmL4izCIyvJn
+        EMd8sQ32AmBZQft/ym6f98/Y15iLe2Xr7TM48l/z1h9Ewc/AijIVH0qE6StDKegLGPv9ISNx/YDH
+        UoB5biiRbzffwtkh8w/aEo/Zm1CvUIxXhze5qPJcPj0sJJe6mJr6HhNt4tkNRSAbDGi5m2rD1Fas
+        zX6fOfI682dowG2Vx/w6Pwu30zB2GHvwZkUWZAKa4a2aZ8PBan5bsqOq1vaXwVXZSZNjCkWCNtny
+        fcouzwk3Z+M1fLN6Q2aG5KVn+rCzTeFaATQ9uXaF/ZkbH//UzbcOrDqw6sCqA6sOrDqw6sCqA6t/
+        K1hxfwVY2e2bXO0f8J/fKHv5+33HV39PvpJknpd5ViABpwyH/FBALCuL/lCUxJAXkRASBQvBL2+2
+        vUZK0lfgw3/CHeUjYv3Ba4+v77qx/GvgJfxA3o9fo+Rf20Hjv9uH81FNvhcwfEUn5TUYlISvN+D+
+        YP9NUr7Gwddj92dUKPiir7CS2GckhPsCJ1FQZES+zwYi/ceLrIiFb6hQna8nC6PIcndWldJ6zC75
+        oGoWkhpWH9aT6ry4avIgPM9VYcFK5VYbkMF0tLdHieyw6xEyt4q4SeRJcWIOJq0M9XkUOrE2D/dR
+        XWpj4Ff6dZsHknoYX4+SaTEViK7jpWWnA+F2ZHJXR7fbCJABt0qFgZXzN1yQ0YScEeWa0GpWqjxr
+        TGs3uyrwJEtJR4UdFXZU2FFhR4UdFXZU2FHhfw0V/iWvZM7yID3i+5tdNXmI84cGVT5KaS3fgeHf
+        EgxDYSghZihxdH0wM5TloP1QKcCcLMkh7zMcj7AvhNLPwXD13pjpmmW/i/Nf3nj7pf0z5uefrv3Q
+        rX/GTCKhkcTLSl/EQ74vyEOxP+R5tq9gUZAEiQjcd68obuvRm8wezJWq3DZe1uQkhsNjXX9gXSYf
+        jbbz2W50+KDbEi1kfcaqiCdO3cFtM4LKaYQX8Vp9A+OIM0NFozkP+80xtlL+uGH5eiV/+DCey2Mp
+        l2fKRb1Es3BhuMWbM2iUfPZ+bPlvQLHSyq3MarA5mpultImi6Y0rP/C8S5//yUHaDIYnZsSQiWUU
+        mwkv/InMJCi80jFTx0wdM3XM1DFTx0wdM3XM9F++k0br6eL0/DEMOtGqqer20v7WyCSwviBIWGBZ
+        CRN2KLMBxmwgMSSQmQAzouyHQ16RfwGZfvHrM+aVr89e5afvBvyMn37k4j99ETHwcSizpM8zLKL4
+        pMh9RebpeXnIyDwniCIjffsiouyBRh7PgtEmPaJ9MGDVWRqRZZEQPc6GNC+DD1l+oqC0FxSUK6qx
+        Ze1M45aLcX7ZQAMci3Cw5Rte9+PHfNocbrgKp3iibxN3u4d7D9lHe/JhLmwjOLcHVbABzBuTSJeV
+        rdIqSwLL8fH2XtbEupKyA4JsOSnX+3VeDR/z6IALNV4GSLwyAs2i/uDPxSdO6PCpw6cOnzp86vCp
+        w6f/NHz6FwAAAP//7Z15s6LI1q+/inHeP06f2G3JPFTEe+8VBRUVBZkk9o2KZFCQUQZR33u++03U
+        PXYNXXOfLiK6ojcISQ4rk/X8MlnZ4tPfCZ9+yJTT42ImYKdV2bLTL81OrOO5LIG7BEMyDmFjG5Jy
+        CI8AJOliNHAdBgG4bQPvy6MofmQ5IfqBeSgU/dRywovpvidF5kMpMq8XE16x6lNshz8tmcTxD86O
+        sX+451YrT3dT2AdWFL7uhJ+cHMMZhPHo5jMzBO8SNk52bZzxGs4jUAf3NiTBvKI7obfbnCuzFO42
+        O39PjBw1jxdjXZwYu+wu31dxFnHUZBzB91DPQHVQ9XeVERVbEeThgKRUeeKo8BVGuHQ2uE9yPzkG
+        RyMnD9IuZpl8moSyVUz0k3LyfMkf4NKAmR/PfTNkR8uzYOrnPbss1nuqzkM0mwgERztZieSLjPXv
+        IUqS/Xh/mqlIsEeSkbzN5/+5dBeAsKG7KHpJd6LU0t13oLsa0h2kNXKvqOJCF3RcRawb3XGQ7iJC
+        NTNhHpKabrpLJW7ozsL/A+hOjSRlLD3VtMqBeVzXa803gIaWRlxPb1eTc4P0DUE8WIIrejd/z+DJ
+        Sm28SkMa3ydgqEhA1ctHbzVxd7YaHeHxYs4fS1jT0KPUSHjHWakzbq7rwgoVpbmQnuwh568EK1MN
+        9NIq0Ptp/E9VqNaN148p5gre/cwKeMXUdwq2RVQjRGGpTC2BNAhZcgCfvDAFoCNErY4QSKKXkhqo
+        BC1gLKPSUUElEbYvr2n6VNZFyxAieLfi62ed+xBtSuZ6Cv3YnYu5APp542e+p+Fja4TkYGoNiXCN
+        dz/nhYYlp7LBjmG7zwFyHNmajM5NDig8urZRayzHaGnrrgjzVmc7dSg2JYB2czyseOeox+RQSqCF
+        Jimqquu6uQP27BCyWqphkrDWteMaEeJ5YpWSGpFSaI3tiItgX4gmiHp2cAvayyCJFgCROEeTxpqh
+        Uwbv86vQN9eGtDdMLrA0l9CMIw8iZQyJzwejYwgp/gwta6WfRei7A3WNAZhjL9kedVOcQl986Qnz
+        qR5xc2UE2yuCPDva1vPRce3tIgK2BByJ0IGsCWMAfXkl8mFNQFY0M+htX4kIevIhKjSevayhwznv
+        DnUE5g8Rxkqd5gq8GjKGYiFWKmkW7JsEqgrWFLr2qhz6ALZSAVtiBC1EgK1uuMo8skiLhz3EEEz1
+        wo46vroyz2oO3WJIm8IgtEYgllEXIxfSOCpmp1JXx5BKYslamNkBpqYhx4XZ5NY3HqhE1fRkfeZg
+        q0hHWYMtwAumG5eqjESFsdOONuwfcmzpMuIrDs/GniBwNhqNG/LkRAXLGitIXvX2cdPb9UinXrKj
+        NICkpQEEJRRIzmr9OGrsIHnykyO0yABScW3sxMTjLUrWrYcrDpCd8gd1w4B0CsnpqQ/oPHF9J1ye
+        Pod0F+o4tHNwobezuPN4Bb4PyIfUJEjw5TU1gTKSTNB4lIOt9NhfFfSp99/D0kmWi2ScoaUv+4NR
+        DhTYGkBoWJILACJ+dGSQ+GjajJbsAlJxbgncyBvqI1WDz7uOFeEqEhRVQzkbcYcyDkctOBDD8Q6H
+        9SbJpvSgCeCwJ3IuEk0g3SGwJsPXylCj5VjQ9tjBIHYVWe2ji+GalARp7gicafMOZmjHwBj6woJ3
+        cWcULefQ24HvrNiS5iNBm/OSLiV9Qo6Pc7DzVddQdm6iW0oEe7imxFbCT6GthEZYUvMw0gyNwPWA
+        DR2+3CkIqaz4CNqbO9LOM5Q/rVTf9Ebb03yElnOEjXSUI2HPgVal1ItVWahGOZL4Ce6ZCqL1sxQM
+        t2fLjDBlHKIglNFVwuf3iTPUzdVwXhsDNtXVCbE6lTsjioZaJC7kUJxaQwmOYxa+VJHpzcsQ1FDe
+        ykjD4dFopUkcfM9dPAzIivItstkLTgTOjaOcKC0ga0HXExTvHpzIq4f+HBkuHAkd4Xdpvn334pff
+        r9sINeTYEORlS6F/3wDm8qQbAj2QjZ26p0sAcUg7nSgIvU7jpG0hAWZe3gmK5J9lxwdZdoLObel3
+        IJNApMlPb+9hzfhlmRVve01YiOLNNRc3JnoD89V7llAvB3Xvf1/8t/+GP726+OrFhVvXfnPbT+nN
+        xRH3moc0/7jGt4Y5SztZZUdB4d9WpD3shdT5DUSln1Zbv5NDuoxOnUmnebT3rxf5vNZZQ9K953V2
+        iy74rtkp6laZ7y4/FJDanMb77tlRaj8A+p+4/Mo7txKd/mtGM81UzbVt34HyAQIQtIuhKsq+Ram3
+        OGI1lzTO8WX7K8gcN/D+4w3UW5J5i1HNDX4ZR++qvFELPlXK581xMYeih9LMjdZRjGYplmYgeUFf
+        wIuK695UUQqB99leWg0PlWnyaD1JFdsNucKErjDpPbfhMiij5kTj0HchHzVclLnvL9OzSnhZHJAF
+        b54V6aJc/MmCPVD1Nr9i4pW/Pllr2SkLkm1aPVYNgSB4UzHptlmD+Y9nvxdB6b0Dbhw8IXV5ypoy
+        a8UFcj5alsvOX0+PaygRdg6QBOeblPA/71dZJi+srROD5NIJYGoNTP3esasAerWdMk0jeAQSt3M1
+        paKTeHUH9taooaIGc5u4k4240LmlfDPxxgY7oFPEaQr7fJOAt4EkFTSnYWd1YLd7c6sdHEcpqvn6
+        76F2Xo1GH60AWNqXbfmPf1/Fp4s2dWH6150AbwwGZVUMewtthsCsixR1iVH67lFVe5LSXtbfWFWX
+        nf5y0tmkeecJRi8lfArKCeuv0angNeFjqzYHl4ietz/f3bZou5xopJ6XUtcfDLMxOjiiu2mdRClw
+        iweZqDl5tdnnZ26bvt2e3ZypgzB4OpHG3nVjuX98xhD8xaPFraVpGmEpkmoGiGRbXR+/PMFhN3mm
+        TL24K8285LF0zIvjh/prztbJF3XTV4b2Z4zxw9118bzf/alu+9psszw4XMa/W8JZVfjP7Jbsokhj
+        tyj+FmPfkoR1yc4ZXk+SNHbdHnALzjDlR9Oi/zhcwlSwLkKoGPKWQN7i9FcOl/DuGpSOf9mAsHne
+        w9FTHhq5y0vcL2qhJ0/ksXnw5wPp89+/xUj6lN57vuD1AOYgLNt1bYroEpQNuoyLMV0XALz5dJvA
+        HPf1F7ybNJmd8ynNr84blRwzs2DEF4GVrXPJGOipd7ZXUV4bCFoXyDCdRr5KLLfJVPKnuoroJKJ4
+        IuFbhoXzR+h+T2yNQrjtdlDycjHReQ6C3kJkVG3b39pSfB54YK+eFhS/oLZVbxtZ9JoPdI2eTucZ
+        ze52ytrJWU1w5il0aRY2fgd6BNpbbJOkmsnmEvmGghtOs9hzwe0DLtutAS49+s3trd8qb63y1ipv
+        rfLWKm+t8tYqb63y9p+jvN2WOTyKMM2vN3VsMf29M/ln3NmmkNQbZr44OxAZg6KTJt6bTkdt/oT/
+        gQ5MpkgTYEdeB/q01YUomlsaJ6vTTBIHyZs3bzq/FUHieJ2gUdcuGF54IHcaYSu/6FiQYHMIV7fn
+        bYILoTYPbeKZQlCtn8Sv0gdlx00bpc47BkX5r4bNPygePRNavlo8+q/Ln7f66qI0TtEMhREPwsnD
+        8Q+TfR7ks97zrHyhCvRz4aWVf1v5t5V/W/m3lX9b+beVf1v5t5V/v07+3XiAZRiX6ja7i3cJArhd
+        QNJEl/IoFAUuwpDka/nXJ8JNPR2mU/xsLDYlxjMq5qFatI/n8aivONpw7xPFtB8qfTGQhwXvjwXF
+        pZzB4LRTzflRT0JT6SUmO8aN++Q8XMzOAMQM3t/Vfdq3B9wR5YrsRA/HRLkgI8o990OwPyvnAogz
+        oyxswiqJhTqkSTnbDGT6QG1XFsmwC+k+WcbknSQpy02tUXc+Th9233K95RfJvzdoavXfVv9t9d9W
+        /23131b/bfXfVv/9a+q/2Ofpv6vm+5JO5w79mLDKQFf+LcF8pizjRd4lB0Wv+WKsR1Lv0VRxAnsU
+        ah6OP6KlPMvI58LBU27eq6jeMtIqqp9WVC8TAiCK0vqisrh5ml00BtfLGp5KnFMnTTqxFzsAIpd7
+        0SDcdJsFkde9nLqcKfy0iuD/Mg9eUmXNcX2ZEoC/P7RVp9EC3rwUGK9ZeZIT0Y/YLfmWpKHj/7V2
+        +0xJJCkMR75MSWwEhuefTl4+Sfy6XH15H2jSKJpE/v2kbjYixjNtc1WmudeBpYNNfbruLQDbLWh6
+        ZvHPjtBfdS4o9oN667W8rez5d5Q9MfguaHRyjIBP/yzZ84/114wa/IPxPK+aD+ie+CvZE/+I6vlo
+        lH9G83wmcf5p0fM6YHzJoHBrPAYjSWjdH1Uyn9/zQsdE36tjor+Kjvm+t8ZVx2SbD6b/KGNS71Ux
+        0S5Cqii0ZOym4X/x0PdCw6T+KGFSfxcFk8DAhmEwp4sSNtElHJLosht606VsCmPIjeu5pP16ASsf
+        L7iVi26jTCM2oRiZh7wHhp46yEhilTKH9Z2TUsSwtJS01kse9xBkQ5LhfqMUdZIykyHPxQtTGtD6
+        4D5h3btjbGzNHeJ7Wr1ZLINldK56U9441PEgRzQsW214Kz6pa1cLiGRzopiyrA0HTa0RkbB3/tA+
+        I2KRYwG4T6oNc1ehJdo3pgepppix+y0VTIwk2J+iYOpXBdNFXyiYekq0Cub3UjBdhNVWZiQpI6dW
+        9RcKJq7GmehpKG+dOUm/KJg69x+gYJqWJJ+f1bSB7uaohVu6O3VjZThXJ9MmrtH8ITJYKB4sTRHd
+        98QKuk8eogU1Sp/HHynZVG4ll3Kdzyp1J+xWo2MG61Zx+1nYlMwSXN1FUFUyXX81ckl19KBgvm4X
+        zdSb51VPikk2e27hABFHYKSk17hHLxUTWNL3qqnSwE6y92ocyk3jAJHAuZhrAWQ+tdBIgLVQ3CeO
+        Qa5snItgHc2tASt7oThZocpsoUsC7It7YBx9BxEWThiN5og0ALGIuXEpLEyOcHS/gnkCWozOZC1a
+        3ifzfjZ3VS5YDd1ghroaiP3Q4uXTDNEFRSuP1kgX9TCarmJBA/xRsXVlvEo43BhFssXPjwvVWoJx
+        hiuCf4S9Xsh0oFmhNpT2g9DNlKFAWvr6LOPSAQwVQwp90UgiQodjvYUo6VzXR3PV8qcYf5JVHl2N
+        pGp6drk1HgmXyGA4tAxurbFwdLEaBTdRmrFCE/JLvCqjiUclDOEx5yLHZuSxVnomynoUSIKQKBo5
+        gGmYq1Fp3CdgND8DXNFtnhzAMSy0R2KpJ7CdBRFapTRQ+hkw+LRe6y5whPCk7DgAR6fwpigqEq+P
+        LFTQbb2PwtQGpWXzR1ESMnF69vm5gRKrkWAYvHWEpcdhXkNduyhv4SCMcA0RKZ2XBp7BcrrB13LM
+        51oYiUC3KlhvkRvp2prUtCiUsQKdIdACMD9ZG0IOR00JpubD1h/CHjV96FGGLk9l42joPKo4+EP8
+        NEG5T2Dp8FXIKl6oK6rGI7fYXgOPRye6gY4cNDPtEekrvL5WNVF/iP0FeHSpNSp6nV16Fxz94RvR
+        MyYnZ3S05qhAKOOrxaqRNZBNSZPja4+5xfqSr7HvLqlx74sk1iiYj3pmDUcecNX/ld08/vw4fPeJ
+        ofuDa/7q6UMkvlVMJhZWctJQ4Cx9Ui8EfwJQHYdPu+rKoyPMu4vLsGettBI3NHEAX2kTaG+mK8KR
+        Eb9FeJMvfRGOms14+v6ofuJDVL+BrIWklfBwrBZFYESLRvn1czVWDnM+41XTOqh6RMmrkreGsIRj
+        joNWMZyifrw+S9AOhVw9u6bLF2c5jAhYbzN156dgJy2sUMnvmwhzO9ibhvK5T6zDObpCrIWCuKt1
+        rKg6GpWqqkzWpiADwZmucC4DO3HgRJIJezHn7ARd0oXYPkeWxwsafMugIWIjiqWZjXrJn7Shdlrx
+        R2gZ3NkWosEM19faWaqUkSCCJKqgVav6Nls7OLdcGaXu9dOLPzDTdFhSZfABb2H7349aJEk+iZFl
+        2biqV31qdeFQLxfyxda6MBewgbv1cpRl2UuEIxC5IPPK/LLnobsNojht/L4m9lFa8pD1Gmf7Aich
+        9OKbgEdNJKO4CWKVXC6L3TQuGnZsYnUFeQDBj2lQxg2Sxue8XJ/ZeWoHSZFeb8kgmnrNLTDXN4J/
+        izXnK+j/5nWwC6+RlHIvgh7W5ZYCnEDy/5q1rOElxSKGRcwuKTSsvb1mudxElwsw+KcPn3EV3BoK
+        OqeunZbX3S4dHwT5pXpeVMaVLJ+q4Hr8WNTr4WNpr4e3At/CdT0r5e3MrXAP4byeinc981DA69FD
+        Qa5HzwpwC/wF850kXgMA/3XjmNjzmsBnF1ovQRBdCtWEmbqCSfNXUsVN5ZJNXh344FuWr/7uu0df
+        F0OYN0jDC9cU3z04va8Ek9+e8O1f/3jk1ac0b3ctIN12hChNXzILRJYmfdgQ71ln9LJIvacH9V6u
+        jHzz9EsXhZlG/vEHzHEp1kEZxukSCMl2iQ3Au7Cl6e6GooC7YWzAeq8Xaix6PcLgA7Y3QozVcKUN
+        e9MppTnMFL4NljsFUAGHJpNFuJqyq7CIZ/vhnWiG8522IUp7wtytAROjC0G0EyeDr4jzOXG5iFpX
+        Q1c1q8p2iAQLicmE9sTJiOgnNHtXokGVjHa6LFInLKgxFNST/c7qS544L5NKnrLaaLm0oUsyPuvF
+        0CGFEyvvVqFJeNL2W2LOpek/iTkPDXdrn4Z0smZ9bYs6Leq0qNOiTos6Leq0qNOizvdHHeL7o84n
+        +IZiP59v0Nd8g347vsF/Rb55wRiPpINSzMdJB6UQ+u9DOiRC0BsbbLo4jSFdgqSRLkAB6AJ247EM
+        wFGAv94fU58AcSj3hnhhL5U1yEOv2OdnOvb0wM1P1BA5lbP+jDzwkzjiBgZyl3P0RtzOyYDpsSIl
+        sSSVrlYGnzsHOJqslVNIDc/JABvPV+aJujNjw+CO/YCWyNWSQ+PQkfr4UNNWBrku1a3Tv0v3g7W1
+        X2Xrnm1j532eJSo7WBmIDPu/g/WZ+THK1jI45+7KM5lvSDrXpv9s0rlc/uY6AdnSTks7Le20tNPS
+        Tks7Le20tPP9aQf/+bRDfj7tUC9pAP2Gkznorwg7w9QpOk4EE2hWcNeeF3Z+u8BCx4W//P5yZeqL
+        vWR+7zRLIP/VLBS/4gTeRZhm8erDEUq84Kdm8fRH+Ymg2W/ITyq0nM7Qs8uO0RRKgQabFlmzLu/g
+        /RSiAoiHMi6guxTSLJHbbJgua5NeF0VsFLNJBGfc13NH23g6xnryLApUVKtcOpYdxe8J1mgkHgR+
+        5k/3AZATfX8XIvIAM2hNR2eHfWrku6SY95b72dzKxwJ0Rzdz/z4ZCXfLal+GDGURfe44H9f8MBdP
+        uN47FLuBNBZncbAAsxVDrDOpR2JOraFOdBxQanwqdvt07Xq5tidykelBX0Cf9DaMSjOTceWNxV4/
+        D74pUV2M4bOJCvac+A1smbTFqRanWpxqcarFqRanWpxqcer74xT603Gq+WjoCaewD+MU+oQcr+aO
+        qA/TFPopmkJfwAj2K8LUJ5jjkYXoTyyaQ3CK/DujkMvgtMPiZJekMa9L2BTo2q5Ddxkbo20WYaCZ
+        gdfxjgp0yNkze6cYTpVGB9ORLVexI1Glt1va14d7bUWs131li1jT/mmw6RGDOuSd885NjwtlPd8t
+        1Gzuqef9IrxP/CqIiOOR85Viue4zYjhVuRScZw6xHC0t4GqLoDiQC9KSDjrfH03XvkwlKnonaDSN
+        EzU5Me68CnpZaCFB710tjsNB6gmDwdglsDVqyOtviEJXY2gnl1oaammopaGWhloaammopaG/OA0h
+        P52GcLaloZ9LQw/BBKKgKN8X/7fZUQASSHG54BVE/J8P3XSLqt6bjDiTXvenE2y1pAbrISmtxFl/
+        ODFXBqGa+Lz3greIT/EW+S15S1ijVKeZiihuuyM0QeGrrGN7myYezyWYc1A4IOqcPJB3YPcoOt1O
+        6B2C5KfgmI17gN7gRJcgKLdL0Cjogg3tdB13Y28cCmA4Tb3CMZW2Zsphiq3B5C5Ue/xEJ41los9k
+        6mixxPqEl5hfO6HdA3tXkZPJhgPLMxYt+lJAqf39cbaykJOXuUdhB18TO6EXYWZi7jaW5mDbSb/2
+        TXciBeEe2Q588jxMh1qMwVGLVO7c9REhq8RlplE4VrfWcF/bs4BcCfFinyynCXwhRjSdRxwHSVDd
+        W4tZZcnfFMfIL8Gxy8zUZWhoWaxlsZbFWhZrWaxlsZbFWhb73ixG0O9nse9GXthfibyQX5m8/kgN
+        zZK93jXk4js+2cLLvbzBhwZZ3i2jS6y4R2wi2Y9hE86yDPEtv3j6T8MmQCIbd4Oj3Y2LOF2CJOAp
+        GqO7hEuwGwKFl6De61ksMiGMYmQa9RFBnOlpNT7kuOwXY+fIKMISGyMjO5crflwcDx78ta6TSjhn
+        +ZKyovW2L1RLN/cUKz7QnnmfMH4xqM67wWY0ci1jbicVqqajPMKK1dhJqvMwvkNUYRwN87u+NZkl
+        qESZ4/52JprpdsPt+aPc53XO2gl5E8We2iFE1PPuctEf5kcfbNVvt6DvwVZabGqxqcWmFptabGqx
+        qcWmFpv+ythE/Whsolps+rnY9HUA8oRNH/3QqXGFEfwXxiaSIRx0Q+Bdm0GoLgEA3mW8DdPd2DhN
+        Yw7p0eD1bFNFnvGid3dyhGXF9UN5FOzDoTZR7kxquDX6i1M2SzZiUhXsKmRMa8d6VtUj5iszWK8H
+        wUApFVkufKIwZUGHb8LazOPjwPNN3YnhMLKjtQlX4SiPZqc+q5z14ED6M4c7UxWtjKogWo42mSnc
+        De56i37MehHRyygrrUaHMfSVCjguJXVN4w5T5xXJHdT+N8WmxlbaxX8tObXk1JJTS04tObXk1JLT
+        X5ycPhBZ4vuRE/rV5IS/JKcvIyXmlyElw+skad3xwcHrgE4WgZOdpmHDH6Aq0xiUwXXLuasHCvkj
+        j2sAYSRNOkMvijp2evRu26DVATyusm0OXK/ZkrCTbhpmiZ8TFfFEVM/K+RqrKOJbxo+A1ZFWieNd
+        9ii85LSJK5DHf9y96keBE+s5OOqSdpcErN18NQURCrrhXUBQHuNiKEki+Ctwql11WW85hEPGhO65
+        eSalhIVuo2O5KwuVKfk7uuoHspBRujNCTXd5Tsq6FA5kFStrMTat/UD1V5vxnnWhwzo1puXgLrrj
+        yGNSVdAijZ2kD9fOZp5Nxlv6eJDL8VwTS6+n76px5rvcZM1u5GlaibNccM7Y0qmWfSsu0rv4Ppmg
+        voMtjAkjskuX3tAiT3xLcKL+1B5LbQCJlppaamqpqaWmlppaamqp6SdSE/ajqenrw0VgLTV97rI8
+        CAt1Xb8pnPx02dSzV6e5m+VeUfQuOb8QQg9BeyjdA91DUJTdMu2C7i35xht2IJF4+YsPnIiPfuAE
+        vWGSJf7WbISzuOM4CNNl8A3aJQBlQ1xivS66oYBLoohDEa/3n11EWysH8XA9Xfj52ERtaSsSViD7
+        onaM1sUsmjps1DshkEyV8Dz3anK1N3GaU9X53hqgBDrgRLGo5HATRPdJHh8muDquiGHtz0fFRkxw
+        2zPP2nCFVCM1X/no1Da9SD4Cd37oEyI6M1Ex7MFs8/KIE3na327F7aCYlX3IRlwsnke7zaxa6BRY
+        JiuD/6Zr8S7W0K7Fa9moZaOWjVo2atmoZaOWjf7KbPSB4HrfjY3Qr/+EqWWjz5tRytPSa5atNSTR
+        AXZalR3o0HaegKcDYSgoOxFsxkuc8rfvW3vXzD3+0iAEcA91McbrsjbNdgnXcbu2zSJdx6VcimVd
+        lCDIVyAUiEA4n/nMNOslpgtDE77k/AhzaKkUheN0PIxjXqa0fk9W2CmnI/vxZoiTgVxJ/WWen6bJ
+        CDWQCcmuSx96P3I8NohNDzWJSkMyoKvb5RoOCKdkj1GnJYqYtYOwEKY4txK3581IPU5zZLBAduM7
+        Mg5rA5DOOMZz8cQc6/vkPPN4PPEO5DSuBit6vxx809V1XwFC7SRRC0ItCLUg1IJQC0ItCLUg9GNA
+        6ANx9b4fCDEtCP3MpXUxSCoQvVhhV5wSp7MBRce1O5s8jTuNj9rp/q9OUW7fi0TYJ5EI+1sjEeYB
+        D8VxAl6F4F2CoO0uSwK2y+AsQlIovmHR11vZZrI1nS4W1Ko+I/FGWRhAQtzRwtDugrXRX9cYu0+r
+        tD9SYxNN5nMimmyJ4s4akhUJ/Hp88Nn9oZir6VKQOfhe0urxHQZAIE1OY4IdrkwzWNTbHU2O9yM6
+        ioWBxNDSyFoft3NrvkL28x6Vc5JgYFKZzZW7ZX9CYMRKyosJHPsjN0EPmEufOKEWUAywVPFtkQhr
+        kahFohaJWiRqkahFohaJWiT6SyMR/qPjNKBEi0Q/Fok+hRSPqIMzvzjq4DTwKMpGuw5B2l0CIYku
+        cBzQJVyccSiaJinidUg66KiXFI3f9YwMGe7uthi2PQ5RZnUm8PNdz/RqoNy50BtYG5ZFqnzue/qK
+        oUlDN3GUIlywP5xHfSVMpnzh3ifrcTY8SHfUqS7LiXes94E92i2nOfQgdtXBt8YzHA4VaW3i1ugA
+        lstNOlmHOn4+FmM654ST1q9HQlr5tjFKYP+PkWN9J09wpAYev0dC6tttrPTFqNPGVmhpp6WdlnZa
+        2mlpp6WdlnZ+LO386GDeKNnSzo+lnX6WRYHn3mInXIK6xWlRdmB5fHhF0fnNrspOknZyz07TsvjX
+        +yZ98E+F7v67kxDiuCyKOxCJNg4K+cd2ugBsQNdjEcfxkA3qIq8nfXLFkc5zIh6ux9NzxGZuLztW
+        op6UK5WcMUdDS+disNngQrmyJmNrQBUrKc3sPY3S/WRhH0joklZiTRprb3+fkEImnI+7k7Ao04Vu
+        kGNRNKNNLZmDZDwojemWmA8mdwN24ZqIhc3jLTsNlofjpNzwe/7s5gIxWIXqXoBVO71PeumYrP2K
+        sXAsdpfINOLSn09C7aRPi0EtBrUY1GJQi0EtBrUY9AMxiP3RGES3GPRjMchJ4ywtvPxNs6wtKC6L
+        4q4bF3UwvPMbpCIfvvk7dVD6naxKtgHRqdM8fC8NNd+P/dI0RG1IwoPOYxehN0yXQDdOl3EYD97E
+        IDhO2TS9eR0eoaCDM8HFvF1X4dhdwTGV8g9ButYlfocV0dmCfoGNHc6p2D+knhXk42x8TlcjNq7R
+        FBuLcBC0TN/b0Fpxuk/KozOSvHw3xNZqCEwvUhbV8SiQ5JRPOVecYAKhLUeSKt1NWE+oSHR4OmKm
+        j1d5LI3WhNvf+4OTFSLcyIJu7UqaFtNKUKTQBvsQ31hTpKWhloZaGmppqKWhloZaGmpp6JeiIeZH
+        09DXb1XU0tDnLYFzXc/tFGnsdYoMOF4zK5Rlzu+dAmeRayBtkMedMN0FnaKEqW2994IQ8quDELFB
+        NyTwuhjNuF2CsZEus6HZruMAxyZIABz29eZDXnGeH4/F7oAPWUDJBpL0LY0cCsIOkTCqLnXOXMER
+        mjMnqZ4GxyPB6aF1FpPlFNucjPlJPfTXfMX1xIiU75OhoSbawrKX7tJcO6bt+71KwwZm5R2LShsM
+        7AHF2f3+/LQ4KHvfJLzx0cQWAJQL36LKTBAWQyH39xDK1tDP8/tzwrHYQbQsl5Y8HlZz/i8FQv+3
+        ubkEsJUZnCGJf/9/FQ8wekRjAQA=
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=1554107]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 21 Jan 2016 20:32:22 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_data_simple
new file mode 100644
index 0000000..c896aa4
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_data_simple
@@ -0,0 +1,43 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=i18n
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA+2ZTW/bIBiA/8ornzYp2IZ8NqdpO+3QnTYp1TpFzH6TstoQYdJqi/LfB20aEdYd
+        Jk1wQcIH8/XwvjySkTkUPaIRcjsUS/h6eHlbG9HjejBcG1tf1LNlXdtSjODcQ7S2hV5Nar9ObpTu
+        uRFKumHvBXlEvO9+wqkD2GYQdCFBY8cNttCKodkPgx0wlLf6VrrnWmkEbyrgD1x0/HuHwM0S7ozZ
+        Dcuq2mCrNN9p9QMbUyq9rR7Fvag+0sWn6voUVMVqOiGrFbm5AYA3qxUQ6JU0dyOwNQRau4jyrQur
+        4R3Kluu15D26xbtl+vGeMqJ2TwmZ/5kQN9fazuHaLXZKKCNs7PfoVHPOzfPqyanpndBNudGIUrVY
+        SjT+sJ5LvkXtNqjYaf4g5FB8C8B/h/rxvOxDGNcvJZ/6fPn8oTiOIGvw/zSYkZqSehZXg1egWYP0
+        GrA6gQaX0KxBag0YqSN/FF6BZg3Sa0DnCTS4hGYNUmswtpsSXYMQmjVIrwGNf0QMoVmD9BqM4x8R
+        Q2jWILUGE0LjHxFDaNYgvQYs/hExhGYNUmswJZRG1yCEZg3Sa8CmCTS4hGYNUmtgyyK6BiE0a5Be
+        Axb/v0EIzRqk1mCe4mophP6zBm5qrrf7HqVx986H4uzB+Q6T+SnzsxXET69cpRe33Hfd8fgbBWYL
+        WtgeAAA=
+    headers:
+      accept-ranges: [bytes]
+      age: ['0']
+      appserver: [proxy12.fedoraproject.org]
+      apptime: [D=179808]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['518']
+      content-type: [application/json]
+      date: ['Thu, 21 Jan 2016 20:50:48 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.CYLWKA._XkgyD4SujeEkonmfv7CP91G1mM;
+          Expires=Thu, 21-Jan-2016 21:50:48 GMT; Secure; HttpOnly; Path=/calendar']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+      via: [1.1 varnish-v4]
+      x-varnish: ['22710494']
+    status: {code: 200, message: OK}
+version: 1

From b7ebac116ee7cce59492d90570039177fbf0ce80 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Mar 14 2016 18:21:47 +0000
Subject: [PATCH 318/1001] Removed conflict in models file


---

diff --git a/hubs/models.py b/hubs/models.py
index ed003e3..2b94422 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -137,7 +137,7 @@ class Hub(BASE):
     last_refreshed = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     last_edited = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
-    #fas_group = sa.Column(sa.String(32), nullable=False)
+    # fas_group = sa.Column(sa.String(32), nullable=False)
 
     @property
     def days_idle(self):
@@ -168,7 +168,7 @@ class Hub(BASE):
     @property
     def members(self):
         return [assoc.user for assoc in self.associations
-                if assoc.role == 'member' or assoc.role =='owner']
+                if assoc.role == 'member' or assoc.role == 'owner']
 
     @property
     def subscribers(self):
@@ -250,6 +250,7 @@ class Hub(BASE):
             'subscribers': [u.username for u in self.subscribers],
         }
 
+
 def _config_default(context):
     plugin_name = context.current_parameters['plugin']
     plugin = hubs.widgets.registry[plugin_name]
@@ -306,7 +307,6 @@ class User(BASE):
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
-
     def __json__(self, session):
         return {
             'username': self.username,
@@ -315,17 +315,18 @@ class User(BASE):
             'fullname': self.fullname,
             'created_on': self.created_on,
             # We'll need hubs subscribed to, owned, etc..
-            #'hubs': [hub.idx for hub in self.hubx],
+            # 'hubs': [hub.idx for hub in self.hubx],
         }
 
     @property
     def ownerships(self):
         return [assoc.hub for assoc in self.associations
                 if assoc.role == 'owner']
+
     @property
     def memberships(self):
         return [assoc.hub for assoc in self.associations
-                if assoc.role == 'member' or assoc.role =='owner']
+                if assoc.role == 'member' or assoc.role == 'owner']
 
     @property
     def subscriptions(self):

From bcb0015c78dbf18d5d5efab2d328e941704eec3e Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Mar 14 2016 18:22:07 +0000
Subject: [PATCH 319/1001] Fixed issue #10: Added Subscribed_to stats and Subscribe/Unsubscribe button


---

diff --git a/hubs/models.py b/hubs/models.py
index 2b94422..0696266 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -125,6 +125,7 @@ class Hub(BASE):
     summary = sa.Column(sa.String(128))
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     widgets = relation('Widget', backref=backref('hub'))
+    users = relation('Association', backref=backref('hubs'))
     left_width = sa.Column(sa.Integer, nullable=False, default=8)
     archived = sa.Column(sa.Boolean, default=False)
     user_hub = sa.Column(sa.Boolean, default=False)
@@ -306,6 +307,7 @@ class User(BASE):
     openid = sa.Column(sa.Text, primary_key=True)
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
+    hubs = relation('Association', backref=backref('users'))
 
     def __json__(self, session):
         return {
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index b81a2cd..5ff412f 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -3,6 +3,7 @@ from hubs.widgets.chrome import panel
 
 from hubs.utils import commas
 
+import flask
 import jinja2
 import requests
 
@@ -16,13 +17,21 @@ template = jinja2.Template("""
 <div class="stats-container row">
   <div class="col-sm-7 col-md-12 col-lg-7">
   <table class="stats-table">
-    <tr><th>FedMsgs</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{{fedmsgs_text}}</td><td class="text-right">{{subscribers_text}}</td></tr>
+    <tr><th>subscribers</th><th>Subscribed_to</th></tr>
+    <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
   </table>
   </div>
   <div class="col-sm-5 col-md-12 col-lg-5">
   {% if session['nickname'] != username %}
-  <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+    {% if session['nickname'] in subscribers %}
+    <li><form action="{{hub_unsubscribe_url}}" method="POST">
+        <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
+    </form></li>
+    {% else %}
+    <li><form action="{{hub_subscribe_url}}" method="POST">
+        <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
+    </form></li>
+    {% endif %}
   {% endif %}
   </div>
 </div>
@@ -34,12 +43,19 @@ def data(session, widget, username):
     url = url.format(username=username)
     response = requests.get(url)
     fedmsgs = response.json()['total']
+    for assoc in widget.hub.users:
+        sub_list = [u.name for u in assoc.user.subscriptions]
+    subscribers = [u.username for u in widget.hub.subscribers]
     return dict(
         username=username,
         fedmsgs=fedmsgs,
-        subscribers=len(widget.hub.subscribers),
+        subscribers=subscribers,
+        subscribed_to=sub_list,
         fedmsgs_text=commas(fedmsgs),
-        subscribers_text=commas(len(widget.hub.subscribers)),
+        subscribers_text=commas(len(subscribers)),
+        subscribed_text=commas(len(sub_list)),
+        hub_subscribe_url=flask.url_for('hub_subscribe', hub=widget.hub.name),
+        hub_unsubscribe_url=flask.url_for('hub_unsubscribe', hub=widget.hub.name),
     )
 
 

From 2df2ecdf37fe0654d7edf8507b8c139bd7c05d54 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Mar 14 2016 18:48:08 +0000
Subject: [PATCH 320/1001] Removed redundant users association relation with hubs


---

diff --git a/hubs/models.py b/hubs/models.py
index 0696266..b94a31f 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -125,7 +125,7 @@ class Hub(BASE):
     summary = sa.Column(sa.String(128))
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     widgets = relation('Widget', backref=backref('hub'))
-    users = relation('Association', backref=backref('hubs'))
+    # users = relation('Association', backref=backref('hubs'))
     left_width = sa.Column(sa.Integer, nullable=False, default=8)
     archived = sa.Column(sa.Boolean, default=False)
     user_hub = sa.Column(sa.Boolean, default=False)
@@ -307,7 +307,7 @@ class User(BASE):
     openid = sa.Column(sa.Text, primary_key=True)
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
-    hubs = relation('Association', backref=backref('users'))
+    # hubs = relation('Association', backref=backref('users'))
 
     def __json__(self, session):
         return {

From 7624b3f983a71f513643963f052debb49e771d83 Mon Sep 17 00:00:00 2001
From: Dhriti Shikhar <dhrish20@gmail.com>
Date: Mar 14 2016 19:41:32 +0000
Subject: [PATCH 321/1001] Adds a bugzilla widget


1. Changes the variable name allissues to issues
2. Changes according to PEP8

---

diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
index bce887d..5482829 100644
--- a/hubs/widgets/bugzilla.py
+++ b/hubs/widgets/bugzilla.py
@@ -1,27 +1,30 @@
-import operator
 import requests
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.base import argument
 import jinja2
+import pkgwat.api
+
 import hubs.validators as validators
+from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
-import pkgwat.api
+from hubs.hinting import hint, prefixed as _
 
 chrome = panel("Bugzilla: Issues")
 
 template = jinja2.Template("""
 <ul class="media-list">
-  {% for issue in all_issues[:3] %}
+  {% for item in issues %}
     <li class="media">
       <div class="media-left">
-        <a href="https://bugzilla.redhat.com/show_bug.cgi?id={{ issue['id'] }}" target="_blank">
-	  <span class="label label-default">#{{ issue['id'] }}</span>
-	</a>
+        <a href="https://bugzilla.redhat.com/show_bug.cgi?id=
+        {{ item['id'] }}" target="_blank">
+        <span class="label label-default">#{{ item['id'] }}</span>
+        </a>
       </div>
       <div class="media-body">
         <h4 class="media-heading">
-          <a href="https://admin.fedoraproject.org/pkgdb/package/rpms/{{ issue['pkg_name'] }}" target="_blank">{{ issue['pkg_name'] }}</a> -
-          {{ issue['title'] }}
+          <a href="https://admin.fedoraproject.org/pkgdb/
+          package/rpms/{{ item['pkg_name'] }}" target=
+          "_blank">{{ item['pkg_name'] }}</a>:
+          {{ item['title'] }}
         </h4>
       </div>
     </li>
@@ -29,48 +32,59 @@ template = jinja2.Template("""
 </ul>
 """)
 
+
 @argument(name="username",
           default=None,
           validator=validators.username,
           help="A FAS username.")
 def data(session, widget, username):
-    username=username
     pkgdb_url = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
     url = "/".join([pkgdb_url, username])
     response = requests.get(url)
     data = response.json()
-    total_poc = len(data["point of contact"])
-    total_co_main = len(data["co-maintained"])
-    
-    all_issues = list()
-    
+
+    issues = []
+
     for package in data["point of contact"]:
-      pkg_details=pkgwat.api.bugs(package['name'])
-      for row in pkg_details['rows']:
-        all_issues.append(
-          dict(
-            pkg_name=package['name'],
-            id=row['id'],
-            title=row['description'],
-          )
-        ) 
-      
+        if len(issues) == 3:
+            break
+        else:
+            pkg_details=pkgwat.api.bugs(package['name'])
+            for row in pkg_details['rows']:
+                if len(issues) == 3:
+                    break
+                else:
+                    issues.append(
+                        dict(
+                          id=row['id'],
+                          title=row['description'],
+                          pkg_name=package['name'],
+                          )
+                        )
+
     for package in data["co-maintained"]:
-      pkg_details=pkgwat.api.bugs(package['name'])
-      for row in pkg_details['rows']:
-        all_issues.append(
-          dict(
-            pkg_name=package['name'],
-            id=row['id'],
-            title=row['description'],
-          )
-        )
+        if len(issues) == 3:
+            break
+        else:
+            pkg_details=pkgwat.api.bugs(package['name'])
+            for row in pkg_details['rows']:
+                if len(issues) == 3:
+                    break
+                else:
+                    issues.append(
+                        dict(
+                            id=row['id'],
+                            title=row['description'],
+                            pkg_name=package['name'],
+                            )
+                        )
 
     return dict(
       username=username,
-      all_issues=all_issues,
+      issues=issues,
     )
 
+
 @hint()
 def should_invalidate(message, session, widget):
     raise NotImplementedError

From 1b1e94abc21b42ad0a7877ca033acdd949747283 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Mar 14 2016 21:05:06 +0000
Subject: [PATCH 322/1001] Removed redundant associations in models and fedmsgstats files


---

diff --git a/hubs/models.py b/hubs/models.py
index b94a31f..2b94422 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -125,7 +125,6 @@ class Hub(BASE):
     summary = sa.Column(sa.String(128))
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     widgets = relation('Widget', backref=backref('hub'))
-    # users = relation('Association', backref=backref('hubs'))
     left_width = sa.Column(sa.Integer, nullable=False, default=8)
     archived = sa.Column(sa.Boolean, default=False)
     user_hub = sa.Column(sa.Boolean, default=False)
@@ -307,7 +306,6 @@ class User(BASE):
     openid = sa.Column(sa.Text, primary_key=True)
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
-    # hubs = relation('Association', backref=backref('users'))
 
     def __json__(self, session):
         return {
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 5ff412f..2a3c643 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -43,7 +43,8 @@ def data(session, widget, username):
     url = url.format(username=username)
     response = requests.get(url)
     fedmsgs = response.json()['total']
-    for assoc in widget.hub.users:
+    print dir(widget.hub.name)
+    for assoc in widget.hub.associations:
         sub_list = [u.name for u in assoc.user.subscriptions]
     subscribers = [u.username for u in widget.hub.subscribers]
     return dict(

From d8875a0937d9a624f27c7efdd529fda5167b4831 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Mar 14 2016 22:01:43 +0000
Subject: [PATCH 323/1001] Modified the fedmsgstats tests according to code changes


---

diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index ad8c0c3..39bd99e 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -16,7 +16,11 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
             u'fedmsgs': 83854,
             u'fedmsgs_text': u'83,854',
             u'source_url': u'/source/fedmsgstats/',
-            u'subscribers': 0,
+            u'subscribers': [],
+            u'subscribed_to': [],
             u'subscribers_text': u'0',
+            u'subscribed_text': u'0',
             u'username': u'ralph',
+            u'hub_subscribe_url': u'/api/hub/ralph/subscribe',
+            u'hub_unsubscribe_url': u'/api/hub/ralph/unsubscribe',
         })
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 2a3c643..a71f1b0 100644
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -43,7 +43,6 @@ def data(session, widget, username):
     url = url.format(username=username)
     response = requests.get(url)
     fedmsgs = response.json()['total']
-    print dir(widget.hub.name)
     for assoc in widget.hub.associations:
         sub_list = [u.name for u in assoc.user.subscriptions]
     subscribers = [u.username for u in widget.hub.subscribers]

From d41d135c2fdbb9cf28f7a03ea05d23be4084d5e9 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 13:33:24 +0000
Subject: [PATCH 324/1001] Merge #82 `Adds a bugzilla widget`


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 3629062..c37b6cb 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -73,4 +73,10 @@ def add_user_widgets(session, hub, username, fullname):
             'display_number': 15,
         }))
     hub.widgets.append(widget)
+    widget = hubs.models.Widget(
+        plugin='bugzilla', index=8,
+        _config=json.dumps({
+            'username': username,
+        }))
+    hub.widgets.append(widget)
     return hub
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 03084ac..cc7007c 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -14,6 +14,7 @@ from hubs.widgets import pagure_pr
 from hubs.widgets import github_pr
 from hubs.widgets import pagureissues
 from hubs.widgets import githubissues
+from hubs.widgets import bugzilla
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -37,6 +38,7 @@ registry = {
     'github_pr': github_pr,
     'pagureissues': pagureissues,
     'githubissues': githubissues,
+    'bugzilla': bugzilla,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
new file mode 100644
index 0000000..5482829
--- /dev/null
+++ b/hubs/widgets/bugzilla.py
@@ -0,0 +1,90 @@
+import requests
+import jinja2
+import pkgwat.api
+
+import hubs.validators as validators
+from hubs.widgets.base import argument
+from hubs.widgets.chrome import panel
+from hubs.hinting import hint, prefixed as _
+
+chrome = panel("Bugzilla: Issues")
+
+template = jinja2.Template("""
+<ul class="media-list">
+  {% for item in issues %}
+    <li class="media">
+      <div class="media-left">
+        <a href="https://bugzilla.redhat.com/show_bug.cgi?id=
+        {{ item['id'] }}" target="_blank">
+        <span class="label label-default">#{{ item['id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <a href="https://admin.fedoraproject.org/pkgdb/
+          package/rpms/{{ item['pkg_name'] }}" target=
+          "_blank">{{ item['pkg_name'] }}</a>:
+          {{ item['title'] }}
+        </h4>
+      </div>
+    </li>
+  {% endfor %}
+</ul>
+""")
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username):
+    pkgdb_url = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
+    url = "/".join([pkgdb_url, username])
+    response = requests.get(url)
+    data = response.json()
+
+    issues = []
+
+    for package in data["point of contact"]:
+        if len(issues) == 3:
+            break
+        else:
+            pkg_details=pkgwat.api.bugs(package['name'])
+            for row in pkg_details['rows']:
+                if len(issues) == 3:
+                    break
+                else:
+                    issues.append(
+                        dict(
+                          id=row['id'],
+                          title=row['description'],
+                          pkg_name=package['name'],
+                          )
+                        )
+
+    for package in data["co-maintained"]:
+        if len(issues) == 3:
+            break
+        else:
+            pkg_details=pkgwat.api.bugs(package['name'])
+            for row in pkg_details['rows']:
+                if len(issues) == 3:
+                    break
+                else:
+                    issues.append(
+                        dict(
+                            id=row['id'],
+                            title=row['description'],
+                            pkg_name=package['name'],
+                            )
+                        )
+
+    return dict(
+      username=username,
+      issues=issues,
+    )
+
+
+@hint()
+def should_invalidate(message, session, widget):
+    raise NotImplementedError

From 3f98b22b98a92f728b70438d4432fd2dd31b4830 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 13:38:46 +0000
Subject: [PATCH 325/1001] New requirement.


---

diff --git a/requirements.txt b/requirements.txt
index 75e9e09..5dca1ce 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -14,3 +14,4 @@ psycopg2
 pytz
 sqlalchemy
 markdown
+pkgwat.api

From ed3929dfe7bcf4505c3a639f27be27fd155310c6 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 14:30:18 +0000
Subject: [PATCH 326/1001] Allow feed entries to expand/collapse if they are conglomerates.


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 19b1c27..492fdbd 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -43,17 +43,75 @@ template = jinja2.Template("""
       <div class="media-body">
         <h4 class="media-heading">{{match['markup']}}</h4>
         {{match['human_time']}}
+        {% if match['msg_ids'] | length > 1 %}
+            <div class="pull-right">
+                <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');">
+                    <span class="glyphicon glyphicon-chevron-down"></span>
+                    expand
+                </a>
+                <a id="collapse-{{match['dom_id']}}" href="javascript:collapse_feed_entries('{{match['dom_id']}}');" class="hidden">
+                    <span class="glyphicon glyphicon-chevron-up"></span>
+                    collapse
+                </a>
+            </div>
+            <ul id="content-{{match['dom_id']}}" class="hidden list-unstyled">
+                {% for idx, constituent in match['msg_ids'].items() %}
+                <li>
+                    {{ constituent['markup'] }}
+                    {% if constituent['link'] %}
+                    <a href="{{constituent['link']}}" target="_blank">
+                        <span class="glyphicon glyphicon-new-window"></span>
+                    </a>
+                    {% endif %}
+                </li>
+                {% endfor %}
+            </ul>
+        {% endif %}
       </div>
     </div>
   </div>
 </div>
 {% endfor %}
+<script>
+var expand_feed_entries = function(idx) {
+    $("#expand-" + idx).addClass('hidden');
+    $("#collapse-" + idx).removeClass('hidden');
+    $("#content-" + idx).removeClass('hidden');
+}
+var collapse_feed_entries = function(idx) {
+    $("#expand-" + idx).removeClass('hidden');
+    $("#collapse-" + idx).addClass('hidden');
+    $("#content-" + idx).addClass('hidden');
+}
+</script>
 """)
 
 # No chrome around the feed.
 #from hubs.widgets.chrome import panel
 #chrome = panel()
 
+def apply_markup(match):
+    markup = match['subtitle']
+    for username in match['usernames']:
+        args = (username, '<a href="{url}">@{username}</a>'.format(
+            url=flask.url_for('hub', name=username),
+            username=username,
+        ))
+        markup = markup.replace(*args)
+        # TODO -- have to add these to conglomerate first
+        #match['long_form'] = match['long_form'].replace(*args)
+
+    for package in match['packages']:
+        args = (package, '<a href="{url}">{package}</a>'.format(
+            url='https://apps.fedoraproject.org/packages/' + package,
+            package=package,
+        ))
+        markup = markup.replace(*args)
+        # TODO -- have to add these to conglomerate first
+        #match['long_form'] = match['long_form'].replace(*args)
+
+    return markup
+
 
 @argument(name="username",
           default=None,
@@ -113,25 +171,9 @@ def data(session, widget, username, fmn_context):
 
     # Apply some html markup to the subtitles for extra fanciness.
     for match in matches:
-        match['markup'] = match['subtitle']
-        for username in match['usernames']:
-            args = (username, '<a href="{url}">@{username}</a>'.format(
-                url=flask.url_for('hub', name=username),
-                username=username,
-            ))
-            match['markup'] = match['markup'].replace(*args)
-            # TODO -- have to add these to conglomerate first
-            #match['long_form'] = match['long_form'].replace(*args)
-
-        for package in match['packages']:
-            args = (package, '<a href="{url}">{package}</a>'.format(
-                url='https://apps.fedoraproject.org/packages/' + package,
-                package=package,
-            ))
-            match['markup'] = match['markup'].replace(*args)
-            # TODO -- have to add these to conglomerate first
-            #match['long_form'] = match['long_form'].replace(*args)
-
+        match['markup'] = apply_markup(match)
+        for idx, constituent in match['msg_ids'].items():
+            constituent['markup'] = apply_markup(constituent)
 
     return dict(
         matches=matches,

From c1b34b045647318bd29fdcb2982ed6ff6a77f678 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 14:34:37 +0000
Subject: [PATCH 327/1001] Linebreak, as per review.


---

diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
index db3ea4c..e3368b0 100644
--- a/hubs/templates/groups.html
+++ b/hubs/templates/groups.html
@@ -110,6 +110,7 @@
       {% for group in secondary %}
         {{ group.name }} is not a promoted group
         but it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
+        <br/>
       {% endfor %}
     </div>
   </div>

From ec5a01985fdb72604b86845f7a54459132c885ee Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 14:43:11 +0000
Subject: [PATCH 328/1001] Drop print statement.


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 492fdbd..f777965 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -125,7 +125,6 @@ def data(session, widget, username, fmn_context):
     openid = '%s.id.fedoraproject.org' % username
     url = '/'.join([fmn_url, 'api', openid, fmn_context])
     log.info("Getting FMN preferences from %s" % url)
-    print(url)
     response = requests.get(url)
     messages = []
     matches = []

From aa8d0d18f89ae1c9f06c8b975735b9c9a2537f40 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 14:58:22 +0000
Subject: [PATCH 329/1001] Merge #109 `Stubbing out the groups page`


---

diff --git a/hubs/app.py b/hubs/app.py
index 39bea1f..851e850 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -17,6 +17,10 @@ from hubs.utils import username2avatar
 
 app = flask.Flask(__name__)
 
+# Register a global filter, useful for displaying user images
+app.template_filter('avatar')(hubs.widgets.base.avatar)
+
+
 logging.basicConfig()
 
 
@@ -70,6 +74,29 @@ def index():
     return flask.redirect(flask.url_for('hub', name=flask.g.auth.nickname))
 
 
+@app.route('/groups')
+def groups():
+    if not flask.g.auth.logged_in:
+        return flask.redirect(flask.url_for('login_fedora'))
+
+    # Get the list of promoted and non-promoted group hubs from the DB
+    promoted_names = app.config.get('PROMOTED_GROUPS')
+    groups = hubs.models.Hub.all_group_hubs(session)
+    promoted = [g for g in groups if g.name in promoted_names]
+    secondary = [g for g in groups if g.name not in promoted_names]
+
+    name_of_the_month = app.config.get('HUB_OF_THE_MONTH')
+    hub_of_the_month = hubs.models.Hub.by_name(session, name_of_the_month)
+
+    return flask.render_template(
+        'groups.html',
+        promoted=promoted,
+        secondary=secondary,
+        hub_of_the_month=hub_of_the_month,
+        session=session,
+    )
+
+
 @app.route('/<name>')
 @app.route('/<name>/')
 def hub(name):
diff --git a/hubs/default_config.py b/hubs/default_config.py
index 39d7fce..a21f138 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -1 +1,8 @@
 SECRET_KEY = 'changemeforreal'
+
+PROMOTED_GROUPS = [
+    'infra',
+    'i18n',
+]
+
+HUB_OF_THE_MONTH = 'commops'
diff --git a/hubs/models.py b/hubs/models.py
index ed003e3..cbe6371 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -209,6 +209,14 @@ class Hub(BASE):
     get = by_name
 
     @classmethod
+    def all_group_hubs(cls, session):
+        return session.query(cls).filter_by(user_hub=False).all()
+
+    @classmethod
+    def all_user_hubs(cls, session):
+        return session.query(cls).filter_by(user_hub=True).all()
+
+    @classmethod
     def create_user_hub(cls, session, username, fullname):
         hub = cls(name=username, summary=fullname,
                   avatar=username2avatar(username),
diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
new file mode 100644
index 0000000..e3368b0
--- /dev/null
+++ b/hubs/templates/groups.html
@@ -0,0 +1,121 @@
+<html>
+<head>
+  <title>Groups</title>
+  <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
+</head>
+<script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
+<body>
+<div class="super-header">
+  <div class="row">
+	  <div class="col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
+    <div class="col-sm-4 col-sm-push-4 col-xs-8">
+      {% if g.auth.logged_in %}
+        <div class="dropdown pull-right">
+          <img class = "icon" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
+        <span class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+          <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
+          {# Logged in as #} {{ g.auth.nickname }}
+          <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
+        </span>
+        <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
+          <li class="dropdown-header">Account Information</li>
+          <li><a href="#">Full Name: {{ g.auth.fullname }}</a></li>
+          <li><a href="#">Email: {{ g.auth.email }}</a></li>
+          <li role="separator" class="divider"></li>
+          <li><a href="#">Separated link</a></li>
+        </ul>
+      </div>
+      {% else %}
+        Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
+      {% endif %}
+    </div>
+    <div class="col-sm-4 col-sm-pull-4 col-xs-12">
+      <!-- NOT HOOKED UP TO ANYTHING XOXO -->
+      <div class="input-group">
+        <input type="search" placeholder="Search across all hubs ..."></input>
+        <span class="input-group-addon">
+          <span class="glyphicon glyphicon-search"></span>
+        </span>
+    </div>
+    </div>
+  </div>
+</div>
+<div class="bookmarks">
+  <nav class="navbar navbar-default">
+    <div class="container-fluid">
+      <div class="navbar-header">
+        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+          <span class="sr-only">Toggle navigation</span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+        </button>
+      </div>
+
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav">
+          {% if g.auth.logged_in %}
+          <li {% if request.path.endswith('/' + g.auth.user.username + '/') %}class='active'{% endif %}>
+            <a href="/{{g.auth.user.username}}">me</a></li>
+          {% for hub in g.auth.user.bookmarks %}
+          <li class='idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
+          <a href="/{{hub.name}}">{{hub.name}}</a></li>
+          {% endfor %}
+          {% endif %}
+        </ul>
+      </div><!-- /.navbar-collapse -->
+    </div><!-- /.container-fluid -->
+  </nav>
+</div>
+<div class="header">
+  <div class="img-wrap">
+    <img src="#" />
+  </div>
+  <h3 class="team">Groups</h3>
+</div>
+<div class="container">
+  <div class="row">
+  </div>
+  <div class="row">
+    <div class="col-md-12">
+      {% for group in promoted %}
+      {{ group.name }} is a promoted group, and it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
+      {% endfor %}
+    </div>
+  </div>
+
+  <hr/>
+
+  <div class="row">
+    <div class="col-md-12">
+      ZOMG - {{ hub_of_the_month.name }} is the Hub Of The Month! <br/>
+      It has {{ hub_of_the_month.subscribers | length }} subscribers and {{ hub_of_the_month.members | length }} members, and {{hub_of_the_month.owners | length }} owners
+      <h6>group owners</h6>
+      {% for owner in hub_of_the_month.owners %}
+          <div class="col-sm-6">
+              <img class="img-circle" src="{{owner.username | avatar}}"/>
+              <a href="{{ url_for('hub', name=owner.username)}}">{{owner.username}}</a>
+          </div>
+      {% endfor %}
+    </div>
+  </div>
+
+  <hr/>
+
+  <div class="row">
+    <div class="col-md-12">
+      {% for group in secondary %}
+        {{ group.name }} is not a promoted group
+        but it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
+        <br/>
+      {% endfor %}
+    </div>
+  </div>
+</div>
+
+<script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
+</body></html>
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 1e87956..3fe5702 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -64,6 +64,8 @@
           <li class='idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
           <a href="/{{hub.name}}">{{hub.name}}</a></li>
           {% endfor %}
+          <!-- At the end of the list, tack on a link to all groups -->
+          <li><a href="/groups">all</a></li>
           {% endif %}
         </ul>
       </div><!-- /.navbar-collapse -->

From d5a5a58e2e89aff06609be9ed5078832f13bdf0e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 14:59:41 +0000
Subject: [PATCH 330/1001] Merge #105 `Fixing issue #96(Meetings Widget: Conditional display of Timestamp) and Issue #106 ( layout of github PR widget)`


---

diff --git a/hubs/__init__.py b/hubs/__init__.py
old mode 100644
new mode 100755
diff --git a/hubs/app.py b/hubs/app.py
old mode 100644
new mode 100755
diff --git a/hubs/consumer.py b/hubs/consumer.py
old mode 100644
new mode 100755
diff --git a/hubs/default_config.py b/hubs/default_config.py
old mode 100644
new mode 100755
diff --git a/hubs/defaults.py b/hubs/defaults.py
old mode 100644
new mode 100755
diff --git a/hubs/hinting.py b/hubs/hinting.py
old mode 100644
new mode 100755
diff --git a/hubs/models.py b/hubs/models.py
old mode 100644
new mode 100755
diff --git a/hubs/utils.py b/hubs/utils.py
old mode 100644
new mode 100755
diff --git a/hubs/validators.py b/hubs/validators.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
old mode 100644
new mode 100755
index 6a33091..ff890aa
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -17,47 +17,52 @@ log = logging.getLogger(__name__)
 chrome = panel("Github: Pull Requests")
 
 template = jinja2.Template("""
-  <br />
-  {% for i in range(display_number) %}
-    <div>
-      <table class="table-responsive table-condensed">
-        <tr>
-          <td valign="top" class="panel-heading">
-            <b>#{{ pulls[i]['number'] }}</b>
-          </td>
-          <td width="300px">
-            <b>{{ pulls[i]['title'] }}</b>
-          </td>
-        </tr>
-      </table>
-      <table class="table-responsive table-condensed">
-        <tr>
-          <td width="300px">
-            <font size="2">
-              <i>Opened by <a href="https://github.com/{{ pulls[i]['user'] }}" target="_blank">{{ pulls[i]['user'] }}</a></i>
-              {% if pulls[i]['assignee']|string() == "None" %}
-                <br /><i>Unclaimed</i>
-              {% else %}
-                 <br /><i>Assigned by <a href="https://github.com/{{ pulls[i]['assignee'] }}" target="_blank">{{ pulls[i]['assignee'] }}</a></i>
-              {% endif %}
-            </font>
-          </td>
-          <td>
-             <a href="{{ pulls[i]['url'] }}" target="_blank">
-               <button type="button" class="btn btn-default" aria-label="Left Align">
-                 <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-               </button>
-             </a>
-          </td>
-        </tr>
-      </table>
-    </div>
-    {% endfor %}
-    {% if more != 0 %}
-    <div class="row">
-      <a href="https://github.com/{{ organization }}" target="_blank"><center>and {{ more }} more</center></a>
-    </div>
-    {% endif %}
+<a class="btn btn-success" target="_blank"
+    href="https://github.com/{{ organization }}" >
+  Organization Github Page
+</a>
+<hr/>
+
+  {% for pr in pulls[:display_number] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="{{ pr['url'] }}" 
+            target="_blank">
+        <span class="label label-default">#{{ pr['number'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          {{ organization }} -
+          <span title="{{ pr['title'] }}">
+            {{ pr['title'] }} {% if
+              pr['title'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://github.com/{{ pr['user'] }}" 
+              target="_blank">
+            {{ pr['user'] }}
+          </a>
+        --
+        {% if pr['assignee'] %}
+          Assigned to:
+          <a href="https://github.com/{{ pr['assignee'] }}"
+              target="_blank">
+            {{ pr['assignee'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_pr | length > display_number %}
+  <li>
+    And {{ all_pr | length - display_number }} more ...
+  </li>
+  {% endif %}
+</ul>
 """)
 
 
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/linechart.py b/hubs/widgets/linechart.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
old mode 100644
new mode 100755
index 1dfd8ec..c3a8382
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -16,19 +16,31 @@ chrome = panel('Reminders', key='meetings')
 def next_meeting(meetings):
     now = datetime.datetime.utcnow()
     for meeting in meetings:
-        string = "%s %s" % (meeting['meeting_date'],
+        start_string = "%s %s" % (meeting['meeting_date'],
                             meeting['meeting_time_start'])
-        dt = datetime.datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
+        start_dt = datetime.datetime.strptime(start_string, "%Y-%m-%d %H:%M:%S")
 
-        if now < dt:
-            meeting['human_time'] = arrow.get(dt).humanize()
-            meeting['start_date'] = dt.strftime('%b %d')
+        stop_string = "%s %s" % (meeting['meeting_date_end'],
+                            meeting['meeting_time_stop'])
+        stop_dt = datetime.datetime.strptime(stop_string, "%Y-%m-%d %H:%M:%S")
+
+        if now < start_dt:
+            meeting['human_time'] = arrow.get(start_dt).humanize()
+            meeting['start_date'] = start_dt.strftime('%b %d')
+            meeting['stop_date'] = stop_dt.strftime('%b %d')
+            meeting['display_time'] = True
+            meeting['display_duration'] = False            
             # Just UTC for now until we do this on the client and can access
             # their local with moment.js.
             meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
+            meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
             meeting['location'] = meeting['meeting_location']
             if '@' in meeting['location']:
                 meeting['location'] = '#' + meeting['location'].split('@')[0]
+            if stop_dt - start_dt >= datetime.timedelta(hours=24) :
+                meeting['display_time'] = False
+                if stop_dt - start_dt > datetime.timedelta(hours=24) :
+                    meeting['display_duration'] = True
             return meeting
 
     return None
@@ -41,9 +53,15 @@ template = jinja2_environment.from_string("""
         {% set next = items | next_meeting %}
         {% if next %}
         <p>The {{ next.meeting_name }} is {{ next.human_time }}</p>
+        {% if next.display_duration %}
+        <h1 class='inline'>{{next.start_date}} - {{next.stop_date}}</h1>
+        {% else %}
         <h1 class='inline'>{{next.start_date}}</h1>
+        {% endif %}
         <div class='inline'>
+            {% if next.display_time %}
             @{{next.start_time}}<br/>
+            {% endif %}
             {{next.location}}<br/>
             {{next.meeting_information_html}}
         </div>
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
old mode 100644
new mode 100755
diff --git a/hubs/widgets/test.py b/hubs/widgets/test.py
old mode 100644
new mode 100755

From 96823453fc43d6e8399782d726d1482b2d2c507e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 15:01:13 +0000
Subject: [PATCH 331/1001] Merge #111 `Fixes #10 : Added the subscribed_to stats and Subscribe/Unsubscribe button`


---

diff --git a/hubs/models.py b/hubs/models.py
index cbe6371..9bbbe80 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -137,7 +137,7 @@ class Hub(BASE):
     last_refreshed = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     last_edited = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
-    #fas_group = sa.Column(sa.String(32), nullable=False)
+    # fas_group = sa.Column(sa.String(32), nullable=False)
 
     @property
     def days_idle(self):
@@ -168,7 +168,7 @@ class Hub(BASE):
     @property
     def members(self):
         return [assoc.user for assoc in self.associations
-                if assoc.role == 'member' or assoc.role =='owner']
+                if assoc.role == 'member' or assoc.role == 'owner']
 
     @property
     def subscribers(self):
@@ -258,6 +258,7 @@ class Hub(BASE):
             'subscribers': [u.username for u in self.subscribers],
         }
 
+
 def _config_default(context):
     plugin_name = context.current_parameters['plugin']
     plugin = hubs.widgets.registry[plugin_name]
@@ -314,7 +315,6 @@ class User(BASE):
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
-
     def __json__(self, session):
         return {
             'username': self.username,
@@ -323,17 +323,18 @@ class User(BASE):
             'fullname': self.fullname,
             'created_on': self.created_on,
             # We'll need hubs subscribed to, owned, etc..
-            #'hubs': [hub.idx for hub in self.hubx],
+            # 'hubs': [hub.idx for hub in self.hubx],
         }
 
     @property
     def ownerships(self):
         return [assoc.hub for assoc in self.associations
                 if assoc.role == 'owner']
+
     @property
     def memberships(self):
         return [assoc.hub for assoc in self.associations
-                if assoc.role == 'member' or assoc.role =='owner']
+                if assoc.role == 'member' or assoc.role == 'owner']
 
     @property
     def subscriptions(self):
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index ad8c0c3..39bd99e 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -16,7 +16,11 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
             u'fedmsgs': 83854,
             u'fedmsgs_text': u'83,854',
             u'source_url': u'/source/fedmsgstats/',
-            u'subscribers': 0,
+            u'subscribers': [],
+            u'subscribed_to': [],
             u'subscribers_text': u'0',
+            u'subscribed_text': u'0',
             u'username': u'ralph',
+            u'hub_subscribe_url': u'/api/hub/ralph/subscribe',
+            u'hub_unsubscribe_url': u'/api/hub/ralph/unsubscribe',
         })
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index b81a2cd..a71f1b0 100755
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -3,6 +3,7 @@ from hubs.widgets.chrome import panel
 
 from hubs.utils import commas
 
+import flask
 import jinja2
 import requests
 
@@ -16,13 +17,21 @@ template = jinja2.Template("""
 <div class="stats-container row">
   <div class="col-sm-7 col-md-12 col-lg-7">
   <table class="stats-table">
-    <tr><th>FedMsgs</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{{fedmsgs_text}}</td><td class="text-right">{{subscribers_text}}</td></tr>
+    <tr><th>subscribers</th><th>Subscribed_to</th></tr>
+    <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
   </table>
   </div>
   <div class="col-sm-5 col-md-12 col-lg-5">
   {% if session['nickname'] != username %}
-  <div class="pull-right"><button class="btn btn-info">Subscribe</button></div>
+    {% if session['nickname'] in subscribers %}
+    <li><form action="{{hub_unsubscribe_url}}" method="POST">
+        <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
+    </form></li>
+    {% else %}
+    <li><form action="{{hub_subscribe_url}}" method="POST">
+        <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
+    </form></li>
+    {% endif %}
   {% endif %}
   </div>
 </div>
@@ -34,12 +43,19 @@ def data(session, widget, username):
     url = url.format(username=username)
     response = requests.get(url)
     fedmsgs = response.json()['total']
+    for assoc in widget.hub.associations:
+        sub_list = [u.name for u in assoc.user.subscriptions]
+    subscribers = [u.username for u in widget.hub.subscribers]
     return dict(
         username=username,
         fedmsgs=fedmsgs,
-        subscribers=len(widget.hub.subscribers),
+        subscribers=subscribers,
+        subscribed_to=sub_list,
         fedmsgs_text=commas(fedmsgs),
-        subscribers_text=commas(len(widget.hub.subscribers)),
+        subscribers_text=commas(len(subscribers)),
+        subscribed_text=commas(len(sub_list)),
+        hub_subscribe_url=flask.url_for('hub_subscribe', hub=widget.hub.name),
+        hub_unsubscribe_url=flask.url_for('hub_unsubscribe', hub=widget.hub.name),
     )
 
 

From 3c64200295918d9931c0607d63e9e63d2acb1d88 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 15:02:41 +0000
Subject: [PATCH 332/1001] Text cleanup.


---

diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index a71f1b0..cbb920f 100755
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -17,7 +17,7 @@ template = jinja2.Template("""
 <div class="stats-container row">
   <div class="col-sm-7 col-md-12 col-lg-7">
   <table class="stats-table">
-    <tr><th>subscribers</th><th>Subscribed_to</th></tr>
+    <tr><th>subscribers</th><th>subscribed to</th></tr>
     <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
   </table>
   </div>

From c2f4c4208bc7898c93726d91bf83dd103d3237eb Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 15:05:01 +0000
Subject: [PATCH 333/1001] Fix invalid CSS.


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 1d8a9aa..ea92360 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -273,7 +273,7 @@
 }
 
 .stats-table {
-width: 180px
+width: 180px;
 padding: 0px;
 margin: 0px;
 display: inline-block;

From b6c708771be004f7b352f163c8e326e30823e178 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 15:05:14 +0000
Subject: [PATCH 334/1001] We can afford more width here.


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index ea92360..a2c5e2a 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -273,7 +273,7 @@
 }
 
 .stats-table {
-width: 180px;
+width: 250px;
 padding: 0px;
 margin: 0px;
 display: inline-block;

From 8c44c6287edd0cbafc62d42f856c8f47bb4badaa Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 16:51:50 +0000
Subject: [PATCH 335/1001] Move js functions out into their own file.


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 1e87956..5d09b04 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -143,6 +143,7 @@
 
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
+<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
 <script>
 var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
 $.each(widgets, function(i, widget) {
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index f777965..e7cd4da 100644
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -72,18 +72,6 @@ template = jinja2.Template("""
   </div>
 </div>
 {% endfor %}
-<script>
-var expand_feed_entries = function(idx) {
-    $("#expand-" + idx).addClass('hidden');
-    $("#collapse-" + idx).removeClass('hidden');
-    $("#content-" + idx).removeClass('hidden');
-}
-var collapse_feed_entries = function(idx) {
-    $("#expand-" + idx).removeClass('hidden');
-    $("#collapse-" + idx).addClass('hidden');
-    $("#content-" + idx).addClass('hidden');
-}
-</script>
 """)
 
 # No chrome around the feed.

From 810381335c903fefd8bd0d6a4d59bcc4122028fc Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 15 2016 17:04:31 +0000
Subject: [PATCH 336/1001] Add forgotten file, because threebean doesn't know how to git.


---

diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
new file mode 100644
index 0000000..1e97046
--- /dev/null
+++ b/hubs/static/js/utils.js
@@ -0,0 +1,12 @@
+// These two functions are used by the feed widget to expand and collapse
+// entries.
+var expand_feed_entries = function(idx) {
+    $("#expand-" + idx).addClass('hidden');
+    $("#collapse-" + idx).removeClass('hidden');
+    $("#content-" + idx).removeClass('hidden');
+}
+var collapse_feed_entries = function(idx) {
+    $("#expand-" + idx).removeClass('hidden');
+    $("#collapse-" + idx).addClass('hidden');
+    $("#content-" + idx).addClass('hidden');
+}

From d2ad1b9b5c7ab595e646d45f3d6a40aff3300909 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 16 2016 17:28:12 +0000
Subject: [PATCH 337/1001] Merge #112 `Allow feed entries to expand/collapse if they are conglomerates.`


---

diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
new file mode 100644
index 0000000..1e97046
--- /dev/null
+++ b/hubs/static/js/utils.js
@@ -0,0 +1,12 @@
+// These two functions are used by the feed widget to expand and collapse
+// entries.
+var expand_feed_entries = function(idx) {
+    $("#expand-" + idx).addClass('hidden');
+    $("#collapse-" + idx).removeClass('hidden');
+    $("#content-" + idx).removeClass('hidden');
+}
+var collapse_feed_entries = function(idx) {
+    $("#expand-" + idx).removeClass('hidden');
+    $("#collapse-" + idx).addClass('hidden');
+    $("#content-" + idx).addClass('hidden');
+}
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 3fe5702..e5ea07e 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -145,6 +145,7 @@
 
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
+<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
 <script>
 var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
 $.each(widgets, function(i, widget) {
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 19b1c27..e7cd4da 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -43,6 +43,30 @@ template = jinja2.Template("""
       <div class="media-body">
         <h4 class="media-heading">{{match['markup']}}</h4>
         {{match['human_time']}}
+        {% if match['msg_ids'] | length > 1 %}
+            <div class="pull-right">
+                <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');">
+                    <span class="glyphicon glyphicon-chevron-down"></span>
+                    expand
+                </a>
+                <a id="collapse-{{match['dom_id']}}" href="javascript:collapse_feed_entries('{{match['dom_id']}}');" class="hidden">
+                    <span class="glyphicon glyphicon-chevron-up"></span>
+                    collapse
+                </a>
+            </div>
+            <ul id="content-{{match['dom_id']}}" class="hidden list-unstyled">
+                {% for idx, constituent in match['msg_ids'].items() %}
+                <li>
+                    {{ constituent['markup'] }}
+                    {% if constituent['link'] %}
+                    <a href="{{constituent['link']}}" target="_blank">
+                        <span class="glyphicon glyphicon-new-window"></span>
+                    </a>
+                    {% endif %}
+                </li>
+                {% endfor %}
+            </ul>
+        {% endif %}
       </div>
     </div>
   </div>
@@ -54,6 +78,28 @@ template = jinja2.Template("""
 #from hubs.widgets.chrome import panel
 #chrome = panel()
 
+def apply_markup(match):
+    markup = match['subtitle']
+    for username in match['usernames']:
+        args = (username, '<a href="{url}">@{username}</a>'.format(
+            url=flask.url_for('hub', name=username),
+            username=username,
+        ))
+        markup = markup.replace(*args)
+        # TODO -- have to add these to conglomerate first
+        #match['long_form'] = match['long_form'].replace(*args)
+
+    for package in match['packages']:
+        args = (package, '<a href="{url}">{package}</a>'.format(
+            url='https://apps.fedoraproject.org/packages/' + package,
+            package=package,
+        ))
+        markup = markup.replace(*args)
+        # TODO -- have to add these to conglomerate first
+        #match['long_form'] = match['long_form'].replace(*args)
+
+    return markup
+
 
 @argument(name="username",
           default=None,
@@ -67,7 +113,6 @@ def data(session, widget, username, fmn_context):
     openid = '%s.id.fedoraproject.org' % username
     url = '/'.join([fmn_url, 'api', openid, fmn_context])
     log.info("Getting FMN preferences from %s" % url)
-    print(url)
     response = requests.get(url)
     messages = []
     matches = []
@@ -113,25 +158,9 @@ def data(session, widget, username, fmn_context):
 
     # Apply some html markup to the subtitles for extra fanciness.
     for match in matches:
-        match['markup'] = match['subtitle']
-        for username in match['usernames']:
-            args = (username, '<a href="{url}">@{username}</a>'.format(
-                url=flask.url_for('hub', name=username),
-                username=username,
-            ))
-            match['markup'] = match['markup'].replace(*args)
-            # TODO -- have to add these to conglomerate first
-            #match['long_form'] = match['long_form'].replace(*args)
-
-        for package in match['packages']:
-            args = (package, '<a href="{url}">{package}</a>'.format(
-                url='https://apps.fedoraproject.org/packages/' + package,
-                package=package,
-            ))
-            match['markup'] = match['markup'].replace(*args)
-            # TODO -- have to add these to conglomerate first
-            #match['long_form'] = match['long_form'].replace(*args)
-
+        match['markup'] = apply_markup(match)
+        for idx, constituent in match['msg_ids'].items():
+            constituent['markup'] = apply_markup(constituent)
 
     return dict(
         matches=matches,

From 493b440af3daee21d0855e5a3bed41263ce96ace Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 16 2016 17:29:50 +0000
Subject: [PATCH 338/1001] Instruct people to leave these commented out.


---

diff --git a/README.rst b/README.rst
index bd86786..2fcf565 100644
--- a/README.rst
+++ b/README.rst
@@ -78,10 +78,14 @@ contents like this::
 
     config = {
         # Put your FAS credentials here...
-        'fas_credentials': {
-            'username': 'YOUR_FAS_USERNAME',
-            'password': 'YOUR_FAS_PASSWORD',
-        },
+        # but leave them commented out.  Note that, if you leave your fas
+        # credentials out, some widgets won't be as accurate as they could be..
+        # but it also makes the app faster than it would otherwise be (which is
+        # nice for development).
+        #'fas_credentials': {
+        #    'username': 'YOUR_FAS_USERNAME',
+        #    'password': 'YOUR_FAS_PASSWORD',
+        #},
 
         # Go and generate a token for this here:
         # https://github.com/settings/tokens

From 36a826afc2634d0d91d3b6d8d5f96fa2492eb061 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 17 2016 14:47:20 +0000
Subject: [PATCH 339/1001] Move jinja templates out into their own files.


---

diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index 84b8de7..061ec6e 100755
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -1,16 +1,13 @@
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
-
-import jinja2
+from hubs.widgets import templating
 
 import hubs.validators as validators
 
 
-template = jinja2.Template("""
-    <p>{{text}}</p>
-    """)
 chrome = panel("<span class='glyphicon glyphicon-info-sign' aria-hidden='true'></span> About")
+template = templating.environment.get_template('templates/about.html')
 
 
 @argument(name="text", default="I am a Fedora user, and this is my about",
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index 1018c3d..f65c4fb 100755
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -4,24 +4,13 @@ import requests
 
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
-
-import jinja2
-
+from hubs.widgets import templating
 
 import hubs.validators as validators
 
-
-template = jinja2.Template("""
-<div class="flex-container">
-{% for badge in assertions[:10] %}
-  <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
-    <img width="60px" src="{{badge['image']}}"/></a>
-{%endfor%}
-</div>
-""")
-
 from hubs.widgets.chrome import panel
 chrome = panel("Badges")
+template = templating.environment.get_template('templates/badges.html')
 
 
 @argument(name="username",
diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
index 5482829..d524833 100644
--- a/hubs/widgets/bugzilla.py
+++ b/hubs/widgets/bugzilla.py
@@ -1,36 +1,14 @@
 import requests
-import jinja2
 import pkgwat.api
 
 import hubs.validators as validators
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
+from hubs.widgets import templating
 from hubs.hinting import hint, prefixed as _
 
 chrome = panel("Bugzilla: Issues")
-
-template = jinja2.Template("""
-<ul class="media-list">
-  {% for item in issues %}
-    <li class="media">
-      <div class="media-left">
-        <a href="https://bugzilla.redhat.com/show_bug.cgi?id=
-        {{ item['id'] }}" target="_blank">
-        <span class="label label-default">#{{ item['id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <a href="https://admin.fedoraproject.org/pkgdb/
-          package/rpms/{{ item['pkg_name'] }}" target=
-          "_blank">{{ item['pkg_name'] }}</a>:
-          {{ item['title'] }}
-        </h4>
-      </div>
-    </li>
-  {% endfor %}
-</ul>
-""")
+template = templating.environment.get_template('templates/bugzilla.html')
 
 
 @argument(name="username",
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 7dd7a96..f74b32c 100755
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -1,29 +1,8 @@
 from hubs.widgets.base import wraps
+from hubs.widgets import templating
 
-import jinja2
-
-_panel_template = jinja2.Template("""
-<div class="panel {{klass}}">
-  {{heading}}
-  <div class="pull-right widget-buttons">
-    <!-- the AGPLv3 wrapper puts the source url in all responses -->
-    <a href="{{source_url}}"><span class="glyphicon glyphicon-eye-open"></span></a>
-    <a href="{{widget_url}}"><span class="glyphicon glyphicon-new-window"></span></a>
-    <a href="#"><span class="glyphicon glyphicon-edit"></span></a>
-  </div>
-  <div class="panel-body">
-    {{content}}
-  </div> <!-- end panel-body -->
-</div> <!-- end panel -->
-""")
-
-_panel_heading_template = jinja2.Template("""
-  <div class="panel-heading">
-    <h3 class="panel-title">
-      {{title}}
-    </h3>
-  </div> <!-- end panel-heading -->
-""")
+_panel_template = templating.environment.get_template('templates/panel.html')
+_panel_heading_template = templating.environment.get_template('templates/panel_heading.html')
 
 
 def panel(title=None, klass="panel-default", key=None):
diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index 890fb18..f03aa86 100755
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -2,30 +2,12 @@ from hubs.hinting import hint, prefixed as _
 
 import arrow
 import datetime
-import jinja2
 
+from hubs.widgets import templating
 from hubs.widgets.chrome import panel
 klass_switcher = lambda data: 'panel-danger' if data['archived'] else 'panel-info'
 chrome = panel(None, key='old', klass=klass_switcher)
-
-template = jinja2.Template("""
-{% if old %}
-<ul class="media-list">
-    <li class="media">
-        <div class="media-left">
-            <img class="media-object square-32" src="{{icon}}"/>
-        </div>
-        <div class="media-body">
-        {% if archived %}
-            This hub has been archived and locked.
-        {% else %}
-            Cobweb alert!  This hub was last active {{then}}.
-        {% endif %}
-        </div>
-    </li>
-</ul>
-{% endif %}
-""")
+template = templating.environment.get_template('templates/cobwebs.html')
 
 
 def data(session, widget):
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index 28f48fb..c6fbb90 100755
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,14 +1,12 @@
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
-
-import jinja2
+from hubs.widgets import templating
 
 import hubs.validators as validators
 
-
-template = jinja2.Template("{{text}}")
 chrome = panel("This is a dummy widget")
+template = templating.environment.get_template('templates/dummy.html')
 
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index cbb920f..d06f398 100755
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -1,10 +1,10 @@
 from hubs.hinting import hint
 from hubs.widgets.chrome import panel
+from hubs.widgets import templating
 
 from hubs.utils import commas
 
 import flask
-import jinja2
 import requests
 
 import fedmsg.config
@@ -13,29 +13,7 @@ import fedmsg.meta
 config = fedmsg.config.load_config()
 
 chrome = panel()
-template = jinja2.Template("""
-<div class="stats-container row">
-  <div class="col-sm-7 col-md-12 col-lg-7">
-  <table class="stats-table">
-    <tr><th>subscribers</th><th>subscribed to</th></tr>
-    <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
-  </table>
-  </div>
-  <div class="col-sm-5 col-md-12 col-lg-5">
-  {% if session['nickname'] != username %}
-    {% if session['nickname'] in subscribers %}
-    <li><form action="{{hub_unsubscribe_url}}" method="POST">
-        <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
-    </form></li>
-    {% else %}
-    <li><form action="{{hub_subscribe_url}}" method="POST">
-        <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
-    </form></li>
-    {% endif %}
-  {% endif %}
-  </div>
-</div>
-""")
+template = templating.environment.get_template('templates/fedmsgstats.html')
 
 
 def data(session, widget, username):
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index e7cd4da..486ef68 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -2,6 +2,7 @@ from __future__ import print_function
 
 from hubs.hinting import hint
 from hubs.widgets.base import argument
+from hubs.widgets import templating
 
 import fmn.lib
 import fmn.lib.hinting
@@ -9,7 +10,6 @@ import fmn.lib.hinting
 import datanommer.models
 
 import arrow
-import jinja2
 import munch
 import requests
 
@@ -29,54 +29,10 @@ fmn_url = config['fmn.url']
 bazillion = 1000
 paths = fmn.lib.load_rules(root='fmn.rules')
 
-
-template = jinja2.Template("""
-{% for match in matches %}
-<div class="panel panel-default">
-  <div class="panel-body">
-    <div class="media">
-      <div class="media-left">
-        <a href="{{match['link']}}" target="_blank">
-          <img class="media-object square-32 img-circle" src="{{match['secondary_icon']}}">
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">{{match['markup']}}</h4>
-        {{match['human_time']}}
-        {% if match['msg_ids'] | length > 1 %}
-            <div class="pull-right">
-                <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');">
-                    <span class="glyphicon glyphicon-chevron-down"></span>
-                    expand
-                </a>
-                <a id="collapse-{{match['dom_id']}}" href="javascript:collapse_feed_entries('{{match['dom_id']}}');" class="hidden">
-                    <span class="glyphicon glyphicon-chevron-up"></span>
-                    collapse
-                </a>
-            </div>
-            <ul id="content-{{match['dom_id']}}" class="hidden list-unstyled">
-                {% for idx, constituent in match['msg_ids'].items() %}
-                <li>
-                    {{ constituent['markup'] }}
-                    {% if constituent['link'] %}
-                    <a href="{{constituent['link']}}" target="_blank">
-                        <span class="glyphicon glyphicon-new-window"></span>
-                    </a>
-                    {% endif %}
-                </li>
-                {% endfor %}
-            </ul>
-        {% endif %}
-      </div>
-    </div>
-  </div>
-</div>
-{% endfor %}
-""")
-
 # No chrome around the feed.
 #from hubs.widgets.chrome import panel
 #chrome = panel()
+template = templating.environment.get_template('templates/feed.html')
 
 def apply_markup(match):
     markup = match['subtitle']
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index ff890aa..905924c 100755
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -3,6 +3,7 @@ import logging
 from hubs.widgets.chrome import panel
 from hubs.hinting import hint
 from hubs.widgets.base import argument
+from hubs.widgets import templating
 
 import hubs.validators as validators
 import hubs.utils
@@ -10,60 +11,10 @@ import hubs.utils
 import fedmsg.config
 config = fedmsg.config.load_config()
 
-import jinja2
-
 log = logging.getLogger(__name__)
 
 chrome = panel("Github: Pull Requests")
-
-template = jinja2.Template("""
-<a class="btn btn-success" target="_blank"
-    href="https://github.com/{{ organization }}" >
-  Organization Github Page
-</a>
-<hr/>
-
-  {% for pr in pulls[:display_number] %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="{{ pr['url'] }}" 
-            target="_blank">
-        <span class="label label-default">#{{ pr['number'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          {{ organization }} -
-          <span title="{{ pr['title'] }}">
-            {{ pr['title'] }} {% if
-              pr['title'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-          <a href="https://github.com/{{ pr['user'] }}" 
-              target="_blank">
-            {{ pr['user'] }}
-          </a>
-        --
-        {% if pr['assignee'] %}
-          Assigned to:
-          <a href="https://github.com/{{ pr['assignee'] }}"
-              target="_blank">
-            {{ pr['assignee'] }}
-          </a>
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if all_pr | length > display_number %}
-  <li>
-    And {{ all_pr | length - display_number }} more ...
-  </li>
-  {% endif %}
-</ul>
-""")
+template = templating.environment.get_template('templates/github_pr.html')
 
 
 @argument(name="display_number",
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
index feabd5e..35536f7 100755
--- a/hubs/widgets/githubissues.py
+++ b/hubs/widgets/githubissues.py
@@ -1,53 +1,13 @@
 from hubs.widgets.chrome import panel
 from hubs.hinting import hint
 from hubs.widgets.base import argument
+from hubs.widgets import templating
 import hubs.validators as validators
-import jinja2
 import requests
 
 chrome = panel("Github: Newest Open Tickets")
+template = templating.environment.get_template('templates/githubissues.html')
 
-template = jinja2.Template("""
-  <br />
-  {% for i in range(display_number) %}
-    <div>
-      <table class="table-responsive table-condensed">
-        <tr>
-          <td valign="top" class="panel-heading">
-            <b>#{{ all_issues[i]['num'] }}</b>
-          </td>
-          <td width="300px">
-            <b>{{ all_issues[i]['title'] }}</b>
-          </td>
-        </tr>
-      </table>
-      <table class="table-responsive table-condensed">
-        <tr>
-          <td width="300px">
-            <font size="2">
-              <i>Opened by <a href="https://github.com/{{ all_issues[i]['openedby'] }}" target="_blank">{{ all_issues[i]['openedby'] }}</a></i>
-              {% if all_issues[i]['assignee']|string() == "None" %}
-                <br /><i>Unclaimed</i>
-              {% else %}
-                 <br /><i>Assigned by <a href="https://github.com/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
-              {% endif %}
-            </font>
-          </td>
-          <td>
-             <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
-               <button type="button" class="btn btn-default" aria-label="Left Align">
-                 <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-               </button>
-             </a>
-          </td>
-        </tr>
-      </table>
-    </div>
-    {% endfor %}
-    <div class="row">
-      <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
-    </div>
-""")
 
 @argument(name="repo",
           default=None,
diff --git a/hubs/widgets/linechart.py b/hubs/widgets/linechart.py
index 0a3fb91..ee47d85 100755
--- a/hubs/widgets/linechart.py
+++ b/hubs/widgets/linechart.py
@@ -1,24 +1,15 @@
 from hubs.hinting import hint
 from hubs.widgets.base import argument
-
-import jinja2
+from hubs.widgets import templating
 
 import hubs.validators as validators
 
 import fedmsg.config
 config = fedmsg.config.load_config()
 
-
-template = jinja2.Template("""
-<div class="flex-container">
-
-    <img src="{{url}}" />
-
-</div>
-""")
-
 from hubs.widgets.chrome import panel
 chrome = panel("Weekly Activity")
+template = templating.environment.get_template('templates/linechart.html')
 
 
 @argument(name="username",
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index c3a8382..37c11ee 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -1,6 +1,7 @@
 #from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
+from hubs.widgets import templating
 
 from hubs import validators
 from hubs import utils
@@ -8,10 +9,8 @@ from hubs import utils
 import arrow
 import collections
 import datetime
-import jinja2
 import requests
 
-chrome = panel('Reminders', key='meetings')
 
 def next_meeting(meetings):
     now = datetime.datetime.utcnow()
@@ -29,7 +28,7 @@ def next_meeting(meetings):
             meeting['start_date'] = start_dt.strftime('%b %d')
             meeting['stop_date'] = stop_dt.strftime('%b %d')
             meeting['display_time'] = True
-            meeting['display_duration'] = False            
+            meeting['display_duration'] = False
             # Just UTC for now until we do this on the client and can access
             # their local with moment.js.
             meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
@@ -45,33 +44,10 @@ def next_meeting(meetings):
 
     return None
 
-jinja2_environment = jinja2.Environment()
-jinja2_environment.filters['next_meeting'] = next_meeting
-template = jinja2_environment.from_string("""
-{% if meetings %}
-    {% for title, items in meetings.items() %}
-        {% set next = items | next_meeting %}
-        {% if next %}
-        <p>The {{ next.meeting_name }} is {{ next.human_time }}</p>
-        {% if next.display_duration %}
-        <h1 class='inline'>{{next.start_date}} - {{next.stop_date}}</h1>
-        {% else %}
-        <h1 class='inline'>{{next.start_date}}</h1>
-        {% endif %}
-        <div class='inline'>
-            {% if next.display_time %}
-            @{{next.start_time}}<br/>
-            {% endif %}
-            {{next.location}}<br/>
-            {{next.meeting_information_html}}
-        </div>
-        {% endif %}
-        {% if meetings | length > 1 %}
-        <hr/>
-        {% endif %}
-    {% endfor %}
-{% endif %}
-""")
+
+chrome = panel('Reminders', key='meetings')
+templating.environment.filters['next_meeting'] = next_meeting
+template = templating.environment.get_template('templates/meetings.html')
 
 
 @argument(name="calendar",
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 0ee7de9..59444db 100755
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -1,63 +1,16 @@
 from hubs.hinting import hint
 from hubs.widgets.chrome import panel
-import jinja2
-import requests
 from hubs.widgets.base import argument
-import hubs.validators as validators
-chrome = panel("Newest Open Pull Requests on Pagure")
+from hubs.widgets import templating
 
-pagure_url = "https://pagure.io/api/0"
+import hubs.validators as validators
 
-template = jinja2.Template("""
-<ul class="media-list">
-  {% for pr in all_pr[:10] %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
-            target="_blank">
-        <span class="label label-default">#{{ pr['pr_id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          {{ pr['pr_project_name'] }} -
-          <span title="{{ pr['pr_title_full'] }}">
-            {{ pr['pr_title'] }} {% if
-              pr['pr_title_full'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-          <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
-              target="_blank">
-            {{ pr['pr_openedby'] }}
-          </a>
-        --
-        {% if pr['pr_assignee'] %}
-          Assigned to:
-          <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
-              target="_blank">
-            {{ pr['pr_assignee'] }}
-          </a>
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if all_pr | length > 10 %}
-  <li>
-    And {{ all_pr | length - 10 }} more ...
-  </li>
-  {% endif %}
-</ul>
+import requests
 
-<hr/>
+pagure_url = "https://pagure.io/api/0"
 
-<a class="btn btn-success" target="_blank"
-    href="https://pagure.io/{{ repo }}/pull-requests">
-  All Pull-Requests
-</a>
-""")
+chrome = panel("Newest Open Pull Requests on Pagure")
+template = templating.environment.get_template('templates/pagure_pr.html')
 
 
 @argument(name="repo",
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index 6eecf9b..ab13903 100755
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -1,63 +1,14 @@
 from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
+from hubs.widgets import templating
 import hubs.validators as validators
-import jinja2
 import requests
 
-chrome = panel("Newest Open Tickets on Pagure")
-
 pagure_url = "https://pagure.io/api/0"
 
-template = jinja2.Template("""
-<a class="btn btn-success" target="_blank"
-    href="https://pagure.io/{{ repo }}/issues">
-  All Issues
-</a>
-<hr/>
-
-<ul class="media-list">
-  {% for issue in all_issues[:10] %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="https://pagure.io/{{ repo }}/issue/{{ issue['issue_id'] }}"
-            target="_blank">
-          {{ issue['issue_project_name'] }}
-        <span class="label label-default">#{{ issue['issue_id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <span title="{{ issue['issue_title_full'] }}">
-            {{ issue['issue_title'] }} {% if
-              issue['issue_title_full'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-          <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
-              target="_blank">
-            {{ issue['issue_openedby'] }}
-          </a>
-        --
-        {% if issue['issue_assignee'] %}
-          Assigned to:
-          <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
-              target="_blank">
-            {{issue['issue_assignee'] }}
-          </a>
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if all_issues | length > 10 %}
-  <li>
-    And {{ all_issues | length - 10 }} more ...
-  </li>
-  {% endif %}
-</ul>
-""")
+chrome = panel("Newest Open Tickets on Pagure")
+template = templating.environment.get_template('templates/pagureissues.html')
 
 
 @argument(name="repo",
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 9793207..4b17931 100755
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -1,58 +1,14 @@
 from collections import OrderedDict as ordereddict
 
-import jinja2
-
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument, avatar
+from hubs.widgets import templating
 from hubs import validators
 
 chrome = panel()
-template = jinja2.Template("""
-<div class="rules-container">
-  {% if link %}
-  <h6>community rules</h6>
-  <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
-  {% endif %}
-  <h6>group owners</h6>
-  <div class="row">
-    {% for owner in owners %}
-        <div class="col-sm-6">
-            <img class="img-circle" src="{{owners[owner]}}"/>
-            <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
-        </div>
-    {% endfor %}
-  </div>
-  {% if schedule_text or schedule_link or minutes_link %}
-  <h6>meetings</h6>
-  {% if schedule_text %}
-  <p>{{schedule_text}}</p>
-  {% endif %}
-  <p>
-  {% if schedule_link %}
-  <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
-  {% endif %}
-  {% if schedule_link and minutes_link %}
-  &#8214;
-  {% endif %}
-  {% if minutes_link %}
-  <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
-  {% endif %}
-  </p>
-  {% endif %}
-</div>
-<style>
-  .rules-table {
-    width: 180px
-    padding: 0px;
-    margin: 0px;
-    display: inline-block;
-  }
-  .rules-table td {
-    font-size: 32pt;
-  }
-</style>
-""")
+template = templating.environment.get_template('templates/rules.html')
+
 
 @argument(name='link', default=None,
           validator=validators.link,
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 3523e84..7f329cf 100755
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,55 +1,13 @@
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
+from hubs.widgets import templating
 
 from hubs.utils import commas
 
 import flask
-import jinja2
 
 chrome = panel()
-template = jinja2.Template("""
-<div class="stats-container row">
-<div class="col-md-7">
-  <table class="stats-table">
-    <tr><th>Members</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{{members_text}}</td><td class="text-right">{{subscribers_text}}</td></tr>
-  </table>
-</div>
-<div class="col-md-5">
-  <ul class="list-unstyled">
-  {% if g.auth.nickname in subscribers %}
-  <li><form action="{{hub_unsubscribe_url}}" method="POST">
-      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
-  </form></li>
-  {% else %}
-  <li><form action="{{hub_subscribe_url}}" method="POST">
-      <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
-  </form></li>
-  {% endif %}
-
-  {% if g.auth.nickname in stargazers %}
-  <li><form action="{{hub_unstar_url}}" method="POST">
-      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unstar Hub</button>
-  </form></li>
-  {% else %}
-  <li><form action="{{hub_star_url}}" method="POST">
-      <button class="btn btn-default"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Star Hub</button>
-  </form></li>
-  {% endif %}
-
-  {% if g.auth.nickname in members %}
-  <li><form action="{{hub_leave_url}}" method="POST">
-      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Leave Hub</button>
-  </form></li>
-  {% else %}
-  <li><form action="{{hub_join_url}}" method="POST">
-      <button class="btn btn-default"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Join Hub</button>
-  </form></li>
-  {% endif %}
-  </ul>
-</div>
-</div>
-""")
+template = templating.environment.get_template('templates/stats.html')
 
 
 def data(session, widget):
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 885108d..95bd2dc 100755
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -1,14 +1,13 @@
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
-
-import jinja2
+from hubs.widgets import templating
 
 import hubs.validators as validators
 
-template = jinja2.Template("{{text}}")
-
 chrome = panel(title='Sticky Note', klass="panel-info")
+template = templating.environment.get_template('templates/sticky.html')
+
 
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 395ee0c..6d7e52f 100755
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -1,6 +1,7 @@
 # from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
+from hubs.widgets import templating
 
 from hubs import validators
 
@@ -9,24 +10,9 @@ import hubs.models
 from fedmsg.meta.base import BaseConglomerator as BC
 
 import flask
-import jinja2
 
 chrome = panel('Hubs', key='associations')
-template = jinja2.Template("""
-{% if associations %}
-    {% if memberships %}
-        <p><strong>Belongs to: </strong> {{memberships_text}}</p>
-    {% endif %}
-    <hr/>
-    {% if subscriptions %}
-        <p><strong>Subscribes to:</strong>
-        {% for subscription in subscriptions %}
-        <a href="{{ url_for('hub', name=subscription)}}">
-        {{subscription}}</a>
-        {% endfor %}</p>
-    {% endif %}
-{% endif %}
-""")
+template = templating.environment.get_template('templates/subscriptions.html')
 
 
 @argument(name="username",
diff --git a/hubs/widgets/templates/about.html b/hubs/widgets/templates/about.html
new file mode 100644
index 0000000..f73bbab
--- /dev/null
+++ b/hubs/widgets/templates/about.html
@@ -0,0 +1 @@
+<p>{{text}}</p>
diff --git a/hubs/widgets/templates/badges.html b/hubs/widgets/templates/badges.html
new file mode 100644
index 0000000..9901f43
--- /dev/null
+++ b/hubs/widgets/templates/badges.html
@@ -0,0 +1,6 @@
+<div class="flex-container">
+{% for badge in assertions[:10] %}
+  <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
+    <img width="60px" src="{{badge['image']}}"/></a>
+{%endfor%}
+</div>
diff --git a/hubs/widgets/templates/bugzilla.html b/hubs/widgets/templates/bugzilla.html
new file mode 100644
index 0000000..21eceb7
--- /dev/null
+++ b/hubs/widgets/templates/bugzilla.html
@@ -0,0 +1,20 @@
+<ul class="media-list">
+  {% for item in issues %}
+    <li class="media">
+      <div class="media-left">
+        <a href="https://bugzilla.redhat.com/show_bug.cgi?id=
+        {{ item['id'] }}" target="_blank">
+        <span class="label label-default">#{{ item['id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <a href="https://admin.fedoraproject.org/pkgdb/
+          package/rpms/{{ item['pkg_name'] }}" target=
+          "_blank">{{ item['pkg_name'] }}</a>:
+          {{ item['title'] }}
+        </h4>
+      </div>
+    </li>
+  {% endfor %}
+</ul>
diff --git a/hubs/widgets/templates/cobwebs.html b/hubs/widgets/templates/cobwebs.html
new file mode 100644
index 0000000..d4b2e7b
--- /dev/null
+++ b/hubs/widgets/templates/cobwebs.html
@@ -0,0 +1,16 @@
+{% if old %}
+<ul class="media-list">
+    <li class="media">
+        <div class="media-left">
+            <img class="media-object square-32" src="{{icon}}"/>
+        </div>
+        <div class="media-body">
+        {% if archived %}
+            This hub has been archived and locked.
+        {% else %}
+            Cobweb alert!  This hub was last active {{then}}.
+        {% endif %}
+        </div>
+    </li>
+</ul>
+{% endif %}
diff --git a/hubs/widgets/templates/dummy.html b/hubs/widgets/templates/dummy.html
new file mode 100644
index 0000000..8d15644
--- /dev/null
+++ b/hubs/widgets/templates/dummy.html
@@ -0,0 +1 @@
+{{text}}
diff --git a/hubs/widgets/templates/fedmsgstats.html b/hubs/widgets/templates/fedmsgstats.html
new file mode 100644
index 0000000..37d6c42
--- /dev/null
+++ b/hubs/widgets/templates/fedmsgstats.html
@@ -0,0 +1,21 @@
+<div class="stats-container row">
+  <div class="col-sm-7 col-md-12 col-lg-7">
+  <table class="stats-table">
+    <tr><th>subscribers</th><th>subscribed to</th></tr>
+    <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
+  </table>
+  </div>
+  <div class="col-sm-5 col-md-12 col-lg-5">
+  {% if session['nickname'] != username %}
+    {% if session['nickname'] in subscribers %}
+    <li><form action="{{hub_unsubscribe_url}}" method="POST">
+        <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
+    </form></li>
+    {% else %}
+    <li><form action="{{hub_subscribe_url}}" method="POST">
+        <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
+    </form></li>
+    {% endif %}
+  {% endif %}
+  </div>
+</div>
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
new file mode 100644
index 0000000..a0dd732
--- /dev/null
+++ b/hubs/widgets/templates/feed.html
@@ -0,0 +1,41 @@
+{% for match in matches %}
+<div class="panel panel-default">
+  <div class="panel-body">
+    <div class="media">
+      <div class="media-left">
+        <a href="{{match['link']}}" target="_blank">
+          <img class="media-object square-32 img-circle" src="{{match['secondary_icon']}}">
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">{{match['markup']}}</h4>
+        {{match['human_time']}}
+        {% if match['msg_ids'] | length > 1 %}
+            <div class="pull-right">
+                <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');">
+                    <span class="glyphicon glyphicon-chevron-down"></span>
+                    expand
+                </a>
+                <a id="collapse-{{match['dom_id']}}" href="javascript:collapse_feed_entries('{{match['dom_id']}}');" class="hidden">
+                    <span class="glyphicon glyphicon-chevron-up"></span>
+                    collapse
+                </a>
+            </div>
+            <ul id="content-{{match['dom_id']}}" class="hidden list-unstyled">
+                {% for idx, constituent in match['msg_ids'].items() %}
+                <li>
+                    {{ constituent['markup'] }}
+                    {% if constituent['link'] %}
+                    <a href="{{constituent['link']}}" target="_blank">
+                        <span class="glyphicon glyphicon-new-window"></span>
+                    </a>
+                    {% endif %}
+                </li>
+                {% endfor %}
+            </ul>
+        {% endif %}
+      </div>
+    </div>
+  </div>
+</div>
+{% endfor %}
diff --git a/hubs/widgets/templates/github_pr.html b/hubs/widgets/templates/github_pr.html
new file mode 100644
index 0000000..8b4a105
--- /dev/null
+++ b/hubs/widgets/templates/github_pr.html
@@ -0,0 +1,46 @@
+<a class="btn btn-success" target="_blank"
+    href="https://github.com/{{ organization }}" >
+  Organization Github Page
+</a>
+<hr/>
+<ul class="media-list">
+{% for pr in pulls[:display_number] %}
+  <li class="media">
+    <div class="media-left">
+      <a  href="{{ pr['url'] }}" 
+          target="_blank">
+      <span class="label label-default">#{{ pr['number'] }}</span>
+      </a>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">
+        {{ organization }} -
+        <span title="{{ pr['title'] }}">
+          {{ pr['title'] }} {% if
+            pr['title'] | length > 45 %} ... {% endif %}
+        </span>
+      </h4>
+      Opened by:
+        <a href="https://github.com/{{ pr['user'] }}" 
+            target="_blank">
+          {{ pr['user'] }}
+        </a>
+      --
+      {% if pr['assignee'] %}
+        Assigned to:
+        <a href="https://github.com/{{ pr['assignee'] }}"
+            target="_blank">
+          {{ pr['assignee'] }}
+        </a>
+      {% else %}
+        <span class="text-muted">Unassigned</span>
+      {% endif %}
+    </div>
+  </li>
+{% endfor %}
+{% if all_pr | length > display_number %}
+  <li>
+    And {{ all_pr | length - display_number }} more ...
+  </li>
+{% endif %}
+</ul>
diff --git a/hubs/widgets/templates/githubissues.html b/hubs/widgets/templates/githubissues.html
new file mode 100644
index 0000000..cd5de9d
--- /dev/null
+++ b/hubs/widgets/templates/githubissues.html
@@ -0,0 +1,38 @@
+{% for i in range(display_number) %}
+<div>
+  <table class="table-responsive table-condensed">
+    <tr>
+      <td valign="top" class="panel-heading">
+        <b>#{{ all_issues[i]['num'] }}</b>
+      </td>
+      <td width="300px">
+        <b>{{ all_issues[i]['title'] }}</b>
+      </td>
+    </tr>
+  </table>
+  <table class="table-responsive table-condensed">
+    <tr>
+      <td width="300px">
+        <font size="2">
+          <i>Opened by <a href="https://github.com/{{ all_issues[i]['openedby'] }}" target="_blank">{{ all_issues[i]['openedby'] }}</a></i>
+          {% if all_issues[i]['assignee']|string() == "None" %}
+            <br /><i>Unclaimed</i>
+          {% else %}
+             <br /><i>Assigned by <a href="https://github.com/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
+          {% endif %}
+        </font>
+      </td>
+      <td>
+         <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
+           <button type="button" class="btn btn-default" aria-label="Left Align">
+             <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+           </button>
+         </a>
+      </td>
+    </tr>
+  </table>
+</div>
+{% endfor %}
+<div class="row">
+  <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
+</div>
diff --git a/hubs/widgets/templates/linechart.html b/hubs/widgets/templates/linechart.html
new file mode 100644
index 0000000..5b4e756
--- /dev/null
+++ b/hubs/widgets/templates/linechart.html
@@ -0,0 +1,3 @@
+<div class="flex-container">
+    <img src="{{url}}" />
+</div>
diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
new file mode 100644
index 0000000..76a4c1b
--- /dev/null
+++ b/hubs/widgets/templates/meetings.html
@@ -0,0 +1,23 @@
+{% if meetings %}
+    {% for title, items in meetings.items() %}
+        {% set next = items | next_meeting %}
+        {% if next %}
+        <p>The {{ next.meeting_name }} is {{ next.human_time }}</p>
+        {% if next.display_duration %}
+        <h1 class='inline'>{{next.start_date}} - {{next.stop_date}}</h1>
+        {% else %}
+        <h1 class='inline'>{{next.start_date}}</h1>
+        {% endif %}
+        <div class='inline'>
+            {% if next.display_time %}
+            @{{next.start_time}}<br/>
+            {% endif %}
+            {{next.location}}<br/>
+            {{next.meeting_information_html}}
+        </div>
+        {% endif %}
+        {% if meetings | length > 1 %}
+        <hr/>
+        {% endif %}
+    {% endfor %}
+{% endif %}
diff --git a/hubs/widgets/templates/pagure_pr.html b/hubs/widgets/templates/pagure_pr.html
new file mode 100644
index 0000000..5508cb7
--- /dev/null
+++ b/hubs/widgets/templates/pagure_pr.html
@@ -0,0 +1,48 @@
+<ul class="media-list">
+  {% for pr in all_pr[:10] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
+            target="_blank">
+        <span class="label label-default">#{{ pr['pr_id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          {{ pr['pr_project_name'] }} -
+          <span title="{{ pr['pr_title_full'] }}">
+            {{ pr['pr_title'] }} {% if
+              pr['pr_title_full'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
+              target="_blank">
+            {{ pr['pr_openedby'] }}
+          </a>
+        --
+        {% if pr['pr_assignee'] %}
+          Assigned to:
+          <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
+              target="_blank">
+            {{ pr['pr_assignee'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_pr | length > 10 %}
+  <li>
+    And {{ all_pr | length - 10 }} more ...
+  </li>
+  {% endif %}
+</ul>
+
+<hr/>
+
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/pull-requests">
+  All Pull-Requests
+</a>
diff --git a/hubs/widgets/templates/pagureissues.html b/hubs/widgets/templates/pagureissues.html
new file mode 100644
index 0000000..258d37e
--- /dev/null
+++ b/hubs/widgets/templates/pagureissues.html
@@ -0,0 +1,47 @@
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/issues">
+  All Issues
+</a>
+<hr/>
+
+<ul class="media-list">
+  {% for issue in all_issues[:10] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://pagure.io/{{ repo }}/issue/{{ issue['issue_id'] }}"
+            target="_blank">
+          {{ issue['issue_project_name'] }}
+        <span class="label label-default">#{{ issue['issue_id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <span title="{{ issue['issue_title_full'] }}">
+            {{ issue['issue_title'] }} {% if
+              issue['issue_title_full'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
+              target="_blank">
+            {{ issue['issue_openedby'] }}
+          </a>
+        --
+        {% if issue['issue_assignee'] %}
+          Assigned to:
+          <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
+              target="_blank">
+            {{issue['issue_assignee'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_issues | length > 10 %}
+  <li>
+    And {{ all_issues | length - 10 }} more ...
+  </li>
+  {% endif %}
+</ul>
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
new file mode 100644
index 0000000..ba6dff2
--- /dev/null
+++ b/hubs/widgets/templates/panel.html
@@ -0,0 +1,12 @@
+<div class="panel {{klass}}">
+  {{heading}}
+  <div class="pull-right widget-buttons">
+    <!-- the AGPLv3 wrapper puts the source url in all responses -->
+    <a href="{{source_url}}"><span class="glyphicon glyphicon-eye-open"></span></a>
+    <a href="{{widget_url}}"><span class="glyphicon glyphicon-new-window"></span></a>
+    <a href="#"><span class="glyphicon glyphicon-edit"></span></a>
+  </div>
+  <div class="panel-body">
+    {{content}}
+  </div> <!-- end panel-body -->
+</div> <!-- end panel -->
diff --git a/hubs/widgets/templates/panel_heading.html b/hubs/widgets/templates/panel_heading.html
new file mode 100644
index 0000000..d7d26f3
--- /dev/null
+++ b/hubs/widgets/templates/panel_heading.html
@@ -0,0 +1,5 @@
+<div class="panel-heading">
+  <h3 class="panel-title">
+    {{title}}
+  </h3>
+</div> <!-- end panel-heading -->
diff --git a/hubs/widgets/templates/rules.html b/hubs/widgets/templates/rules.html
new file mode 100644
index 0000000..2d986d1
--- /dev/null
+++ b/hubs/widgets/templates/rules.html
@@ -0,0 +1,43 @@
+<div class="rules-container">
+  {% if link %}
+  <h6>community rules</h6>
+  <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
+  {% endif %}
+  <h6>group owners</h6>
+  <div class="row">
+    {% for owner in owners %}
+        <div class="col-sm-6">
+            <img class="img-circle" src="{{owners[owner]}}"/>
+            <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
+        </div>
+    {% endfor %}
+  </div>
+  {% if schedule_text or schedule_link or minutes_link %}
+  <h6>meetings</h6>
+  {% if schedule_text %}
+  <p>{{schedule_text}}</p>
+  {% endif %}
+  <p>
+  {% if schedule_link %}
+  <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
+  {% endif %}
+  {% if schedule_link and minutes_link %}
+  &#8214;
+  {% endif %}
+  {% if minutes_link %}
+  <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
+  {% endif %}
+  </p>
+  {% endif %}
+</div>
+<style>
+  .rules-table {
+    width: 180px
+    padding: 0px;
+    margin: 0px;
+    display: inline-block;
+  }
+  .rules-table td {
+    font-size: 32pt;
+  }
+</style>
diff --git a/hubs/widgets/templates/stats.html b/hubs/widgets/templates/stats.html
new file mode 100644
index 0000000..a8f0a8a
--- /dev/null
+++ b/hubs/widgets/templates/stats.html
@@ -0,0 +1,41 @@
+<div class="stats-container row">
+<div class="col-md-7">
+  <table class="stats-table">
+    <tr><th>Members</th><th>Subscribers</th></tr>
+    <tr class="text-info"><td>{{members_text}}</td><td class="text-right">{{subscribers_text}}</td></tr>
+  </table>
+</div>
+<div class="col-md-5">
+  <ul class="list-unstyled">
+  {% if g.auth.nickname in subscribers %}
+  <li><form action="{{hub_unsubscribe_url}}" method="POST">
+      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
+  </form></li>
+  {% else %}
+  <li><form action="{{hub_subscribe_url}}" method="POST">
+      <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
+  </form></li>
+  {% endif %}
+
+  {% if g.auth.nickname in stargazers %}
+  <li><form action="{{hub_unstar_url}}" method="POST">
+      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unstar Hub</button>
+  </form></li>
+  {% else %}
+  <li><form action="{{hub_star_url}}" method="POST">
+      <button class="btn btn-default"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Star Hub</button>
+  </form></li>
+  {% endif %}
+
+  {% if g.auth.nickname in members %}
+  <li><form action="{{hub_leave_url}}" method="POST">
+      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Leave Hub</button>
+  </form></li>
+  {% else %}
+  <li><form action="{{hub_join_url}}" method="POST">
+      <button class="btn btn-default"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Join Hub</button>
+  </form></li>
+  {% endif %}
+  </ul>
+</div>
+</div>
diff --git a/hubs/widgets/templates/sticky.html b/hubs/widgets/templates/sticky.html
new file mode 100644
index 0000000..8d15644
--- /dev/null
+++ b/hubs/widgets/templates/sticky.html
@@ -0,0 +1 @@
+{{text}}
diff --git a/hubs/widgets/templates/subscriptions.html b/hubs/widgets/templates/subscriptions.html
new file mode 100644
index 0000000..74e46f2
--- /dev/null
+++ b/hubs/widgets/templates/subscriptions.html
@@ -0,0 +1,13 @@
+{% if associations %}
+    {% if memberships %}
+        <p><strong>Belongs to: </strong> {{memberships_text}}</p>
+    {% endif %}
+    <hr/>
+    {% if subscriptions %}
+        <p><strong>Subscribes to:</strong>
+        {% for subscription in subscriptions %}
+        <a href="{{ url_for('hub', name=subscription)}}">
+        {{subscription}}</a>
+        {% endfor %}</p>
+    {% endif %}
+{% endif %}
diff --git a/hubs/widgets/templates/workflow/pendingacls.html b/hubs/widgets/templates/workflow/pendingacls.html
new file mode 100644
index 0000000..c419d61
--- /dev/null
+++ b/hubs/widgets/templates/workflow/pendingacls.html
@@ -0,0 +1,20 @@
+{% if pending_acls %}
+{% if session['nickname'] == username %}
+<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/pkgdb/acl/pending/">Manage requests</a>
+<hr/>
+{% endif %}
+<ul class="media-list">
+{% for acl in pending_acls %}
+    <li class="media">
+        <div class="media-left">
+            <img class="media-object img-circle" src="{{acl['avatar']}}"/>
+        </div>
+        <div class="media-body">
+            <h4 class="media-heading">{{acl['user']}} is {{acl['status']}}</h4>
+            for {{acl['acl']}} on
+            {{acl['package']}}({{acl['collection']}})
+        </div>
+    </li>
+{% endfor %}
+</ul>
+{% endif %}
diff --git a/hubs/widgets/templates/workflow/updates2stable.html b/hubs/widgets/templates/workflow/updates2stable.html
new file mode 100644
index 0000000..35e2d25
--- /dev/null
+++ b/hubs/widgets/templates/workflow/updates2stable.html
@@ -0,0 +1,21 @@
+{% if updates %}
+{% if session['nickname'] == username %}
+<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
+<hr/>
+{% endif %}
+<ul class="media-list">
+{% for update in updates %}
+    <li class="media">
+        <div class="media-left">
+            <a href="{{update['link']}}" target="_blank">
+                <img class="media-object square-32" src="{{update['icon']}}"/>
+            </a>
+        </div>
+        <div class="media-body">
+            <h4 class="media-heading">{{update['title']}} (karma {{update['karma']}})</h4>
+            can be pushed to stable
+        </div>
+    </li>
+{% endfor %}
+</ul>
+{% endif %}
diff --git a/hubs/widgets/templating.py b/hubs/widgets/templating.py
new file mode 100644
index 0000000..98b29cd
--- /dev/null
+++ b/hubs/widgets/templating.py
@@ -0,0 +1,10 @@
+import os
+
+import jinja2
+
+here = os.path.dirname(os.path.abspath(__file__))
+
+environment = jinja2.Environment(
+    loader=jinja2.FileSystemLoader(here),
+    trim_blocks=True,
+)
diff --git a/hubs/widgets/test.py b/hubs/widgets/test.py
deleted file mode 100755
index e69de29..0000000
--- a/hubs/widgets/test.py
+++ /dev/null
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 958d034..6f0e678 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -2,40 +2,16 @@ import requests
 
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
+from hubs.widgets import templating
 from hubs.utils import username2avatar
 
-import jinja2
-
-
 import hubs.validators as validators
 
-# TODO -- add approve/deny buttons or just link through to pkgdb
-template = jinja2.Template("""
-{% if pending_acls %}
-{% if session['nickname'] == username %}
-<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/pkgdb/acl/pending/">Manage requests</a>
-<hr/>
-{% endif %}
-<ul class="media-list">
-{% for acl in pending_acls %}
-    <li class="media">
-        <div class="media-left">
-            <img class="media-object img-circle" src="{{acl['avatar']}}"/>
-        </div>
-        <div class="media-body">
-            <h4 class="media-heading">{{acl['user']}} is {{acl['status']}}</h4>
-            for {{acl['acl']}} on
-            {{acl['package']}}({{acl['collection']}})
-        </div>
-    </li>
-{% endfor %}
-</ul>
-{% endif %}
-""")
-
 from hubs.widgets.chrome import panel
 # If 'pending_acls' is empty, then don't render any chrome.
 chrome = panel('Pending ACL Requests', key='pending_acls')
+# TODO -- add approve/deny buttons or just link through to pkgdb
+template = templating.environment.get_template('templates/workflow/pendingacls.html')
 
 
 @argument(name="username",
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 8b0d802..64a8316 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -2,42 +2,17 @@ import requests
 
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
-
-import jinja2
-
-
+from hubs.widgets import templating
 import hubs.validators as validators
 
-# TODO -- add approve/deny buttons or just link through to pkgdb
-template = jinja2.Template("""
-{% if updates %}
-{% if session['nickname'] == username %}
-<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
-<hr/>
-{% endif %}
-<ul class="media-list">
-{% for update in updates %}
-    <li class="media">
-        <div class="media-left">
-            <a href="{{update['link']}}" target="_blank">
-                <img class="media-object square-32" src="{{update['icon']}}"/>
-            </a>
-        </div>
-        <div class="media-body">
-            <h4 class="media-heading">{{update['title']}} (karma {{update['karma']}})</h4>
-            can be pushed to stable
-        </div>
-    </li>
-{% endfor %}
-</ul>
-{% endif %}
-""")
 
 from hubs.widgets.chrome import panel
 # If 'updates' is empty, then don't render any chrome.
 chrome = panel('Updates Ready for Stable', key='updates')
+# TODO -- add approve/deny buttons or just link through to pkgdb
+template = templating.environment.get_template('templates/workflow/updates2stable.html')
 
-
+# TODO - the bodhi api exposes a new flag we can use instead of scraping comments...
 giveaway = 'can be pushed to stable now'
 
 

From 1350158428ba35ecd5905067ecb9d245cf5caf36 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 17 2016 19:28:24 +0000
Subject: [PATCH 340/1001] Add long-form stuff with the new lexer interface from fedmsg.meta.


---

diff --git a/hubs/static/css/pygments/default.css b/hubs/static/css/pygments/default.css
new file mode 100644
index 0000000..ef95359
--- /dev/null
+++ b/hubs/static/css/pygments/default.css
@@ -0,0 +1,62 @@
+.codehilite .hll { background-color: #ffffcc }
+.codehilite  { background: #f8f8f8; }
+.codehilite .c { color: #408080; font-style: italic } /* Comment */
+.codehilite .err { border: 1px solid #FF0000 } /* Error */
+.codehilite .k { color: #008000; font-weight: bold } /* Keyword */
+.codehilite .o { color: #666666 } /* Operator */
+.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
+.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
+.codehilite .gd { color: #A00000 } /* Generic.Deleted */
+.codehilite .ge { font-style: italic } /* Generic.Emph */
+.codehilite .gr { color: #FF0000 } /* Generic.Error */
+.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.codehilite .gi { color: #00A000 } /* Generic.Inserted */
+.codehilite .go { color: #808080 } /* Generic.Output */
+.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.codehilite .gs { font-weight: bold } /* Generic.Strong */
+.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.codehilite .gt { color: #0040D0 } /* Generic.Traceback */
+.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.codehilite .kp { color: #008000 } /* Keyword.Pseudo */
+.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.codehilite .kt { color: #B00040 } /* Keyword.Type */
+.codehilite .m { color: #666666 } /* Literal.Number */
+.codehilite .s { color: #BA2121 } /* Literal.String */
+.codehilite .na { color: #7D9029 } /* Name.Attribute */
+.codehilite .nb { color: #008000 } /* Name.Builtin */
+.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.codehilite .no { color: #880000 } /* Name.Constant */
+.codehilite .nd { color: #AA22FF } /* Name.Decorator */
+.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.codehilite .nf { color: #0000FF } /* Name.Function */
+.codehilite .nl { color: #A0A000 } /* Name.Label */
+.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.codehilite .nv { color: #19177C } /* Name.Variable */
+.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
+.codehilite .mf { color: #666666 } /* Literal.Number.Float */
+.codehilite .mh { color: #666666 } /* Literal.Number.Hex */
+.codehilite .mi { color: #666666 } /* Literal.Number.Integer */
+.codehilite .mo { color: #666666 } /* Literal.Number.Oct */
+.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
+.codehilite .sc { color: #BA2121 } /* Literal.String.Char */
+.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
+.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.codehilite .sx { color: #008000 } /* Literal.String.Other */
+.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
+.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
+.codehilite .ss { color: #19177C } /* Literal.String.Symbol */
+.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.codehilite .vc { color: #19177C } /* Name.Variable.Class */
+.codehilite .vg { color: #19177C } /* Name.Variable.Global */
+.codehilite .vi { color: #19177C } /* Name.Variable.Instance */
+.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/hubs/static/css/pygments/monokai.css b/hubs/static/css/pygments/monokai.css
new file mode 100644
index 0000000..005d477
--- /dev/null
+++ b/hubs/static/css/pygments/monokai.css
@@ -0,0 +1,64 @@
+.highlight .hll { background-color: #49483e }
+.highlight .c { color: #75715e } /* Comment */
+.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
+.highlight .k { color: #66d9ef } /* Keyword */
+.highlight .l { color: #ae81ff } /* Literal */
+.highlight .n { color: #f8f8f2 } /* Name */
+.highlight .o { color: #f92672 } /* Operator */
+.highlight .p { color: #f8f8f2 } /* Punctuation */
+.highlight .cm { color: #75715e } /* Comment.Multiline */
+.highlight .cp { color: #75715e } /* Comment.Preproc */
+.highlight .c1 { color: #75715e } /* Comment.Single */
+.highlight .cs { color: #75715e } /* Comment.Special */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .kc { color: #66d9ef } /* Keyword.Constant */
+.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
+.highlight .kn { color: #f92672 } /* Keyword.Namespace */
+.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
+.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
+.highlight .kt { color: #66d9ef } /* Keyword.Type */
+.highlight .ld { color: #e6db74 } /* Literal.Date */
+.highlight .m { color: #ae81ff } /* Literal.Number */
+.highlight .s { color: #e6db74 } /* Literal.String */
+.highlight .na { color: #a6e22e } /* Name.Attribute */
+.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
+.highlight .nc { color: #a6e22e } /* Name.Class */
+.highlight .no { color: #66d9ef } /* Name.Constant */
+.highlight .nd { color: #a6e22e } /* Name.Decorator */
+.highlight .ni { color: #f8f8f2 } /* Name.Entity */
+.highlight .ne { color: #a6e22e } /* Name.Exception */
+.highlight .nf { color: #a6e22e } /* Name.Function */
+.highlight .nl { color: #f8f8f2 } /* Name.Label */
+.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
+.highlight .nx { color: #a6e22e } /* Name.Other */
+.highlight .py { color: #f8f8f2 } /* Name.Property */
+.highlight .nt { color: #f92672 } /* Name.Tag */
+.highlight .nv { color: #f8f8f2 } /* Name.Variable */
+.highlight .ow { color: #f92672 } /* Operator.Word */
+.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
+.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
+.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
+.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
+.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
+.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
+.highlight .sc { color: #e6db74 } /* Literal.String.Char */
+.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
+.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
+.highlight .se { color: #ae81ff } /* Literal.String.Escape */
+.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
+.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
+.highlight .sx { color: #e6db74 } /* Literal.String.Other */
+.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
+.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
+.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
+.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
+.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
+.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
+.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
+
+.highlight .gh { } /* Generic Heading & Diff Header */
+.highlight .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
+.highlight .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */
+.highlight .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index a2c5e2a..3ab7050 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -310,6 +310,11 @@ font-size: 32pt;
 .navbar-nav > li.idle-2years  > a { color: #BBB; }
 .navbar-nav > li.idle-5years  > a { color: #CCC; }
 
+.media-object {
+    max-width: 92px;
+    max-height: 92px;
+}
+
 @font-face {
   font-family: 'Comfortaa';
   font-weight: 300;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index e5ea07e..2e4eaf5 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -4,6 +4,7 @@
   <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/pygments/monokai.css') }}" rel="stylesheet"/>
 </head>
 <script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
 <body>
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 486ef68..8ae603f 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -12,6 +12,9 @@ import datanommer.models
 import arrow
 import munch
 import requests
+import six
+
+import pygments.formatters
 
 import flask
 
@@ -19,6 +22,8 @@ import hubs.validators as validators
 
 import datetime
 import logging
+import uuid
+
 log = logging.getLogger('hubs')
 
 import fedmsg.config
@@ -110,13 +115,26 @@ def data(session, widget, username, fmn_context):
     # TODO - sort messages and remove duplicates
 
     # Smash multiple messages into single ones
-    matches = fedmsg.meta.conglomerate(matches, **config)
+    matches = fedmsg.meta.conglomerate(matches, lexers=True, **config)
 
     # Apply some html markup to the subtitles for extra fanciness.
     for match in matches:
         match['markup'] = apply_markup(match)
         for idx, constituent in match['msg_ids'].items():
             constituent['markup'] = apply_markup(constituent)
+            if constituent['long_form'] != constituent['subtitle']:
+                if constituent.get('lexer'):
+                    constituent['long_form'] = pygments.highlight(
+                        constituent['long_form'],
+                        constituent['lexer'],
+                        pygments.formatters.HtmlFormatter(style='monokai'),
+                    )
+                else:
+                    markup = u"<h5>{long_form}</h5>".format(**constituent)
+                    constituent['long_form'] = markup
+
+        # And tack on a unique identifier for each top level entry.
+        match['dom_id'] = six.text_type(uuid.uuid4())
 
     return dict(
         matches=matches,
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index a0dd732..138612b 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -10,6 +10,39 @@
       <div class="media-body">
         <h4 class="media-heading">{{match['markup']}}</h4>
         {{match['human_time']}}
+
+
+        {% if match['msg_ids'] | length == 1 and match['msg_ids'].values()[0].get('long_form') != match['msg_ids'].values()[0]['subtitle'] %}
+            {% set constituent = match['msg_ids'].values()[0] %}
+            <div class="pull-right">
+                <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');" class="hidden">
+                    <span class="glyphicon glyphicon-chevron-down"></span>
+                    expand
+                </a>
+                <a id="collapse-{{match['dom_id']}}" href="javascript:collapse_feed_entries('{{match['dom_id']}}');">
+                    <span class="glyphicon glyphicon-chevron-up"></span>
+                    collapse
+                </a>
+            </div>
+
+            <div id="content-{{match['dom_id']}}" class="media">
+              {% if constituent['icon'] != constituent.get('__icon__') %}
+              <div class="media-left media-top">
+                <a href="{{constituent['link']}}">
+                  <img class="media-object" src="{{constituent['icon']}}" alt="{{constituent['subtitle']}}">
+                </a>
+              </div>
+              {% endif %}
+              <div class="media-body">
+                  {{constituent['long_form']}}
+                    {% if constituent['link'] %}
+                    <a href="{{constituent['link']}}" target="_blank">
+                        Read more <span class="glyphicon glyphicon-new-window"></span>
+                    </a>
+                    {% endif %}
+              </div>
+            </div>
+        {% endif %}
         {% if match['msg_ids'] | length > 1 %}
             <div class="pull-right">
                 <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');">
diff --git a/requirements.txt b/requirements.txt
index 5dca1ce..6c101b5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -15,3 +15,6 @@ pytz
 sqlalchemy
 markdown
 pkgwat.api
+six
+pygments
+pygments-markdown-lexer

From 3704095da807fc94f6ceff2f9d3c8d1de4888c22 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 18 2016 18:06:24 +0000
Subject: [PATCH 341/1001] We need this to match our locally-stored datanommer topics so that the feed works.


---

diff --git a/fedmsg.d/base.py b/fedmsg.d/base.py
index 6332b94..ddc1a81 100644
--- a/fedmsg.d/base.py
+++ b/fedmsg.d/base.py
@@ -22,7 +22,7 @@ import os
 config = dict(
     # Set this to dev if you're hacking on fedmsg or an app.
     # Set to stg or prod if running in the Fedora Infrastructure
-    environment="dev",
+    environment="prod",
 
     # Default is 0
     high_water_mark=0,

From 39b49cf2fbc62720f2a0cf3602ad47088efce881 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 21 2016 13:14:28 +0000
Subject: [PATCH 342/1001] Merge #122 `Add long-form stuff with the new lexer interface from fedmsg.meta.`


---

diff --git a/hubs/static/css/pygments/default.css b/hubs/static/css/pygments/default.css
new file mode 100644
index 0000000..ef95359
--- /dev/null
+++ b/hubs/static/css/pygments/default.css
@@ -0,0 +1,62 @@
+.codehilite .hll { background-color: #ffffcc }
+.codehilite  { background: #f8f8f8; }
+.codehilite .c { color: #408080; font-style: italic } /* Comment */
+.codehilite .err { border: 1px solid #FF0000 } /* Error */
+.codehilite .k { color: #008000; font-weight: bold } /* Keyword */
+.codehilite .o { color: #666666 } /* Operator */
+.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
+.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
+.codehilite .gd { color: #A00000 } /* Generic.Deleted */
+.codehilite .ge { font-style: italic } /* Generic.Emph */
+.codehilite .gr { color: #FF0000 } /* Generic.Error */
+.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.codehilite .gi { color: #00A000 } /* Generic.Inserted */
+.codehilite .go { color: #808080 } /* Generic.Output */
+.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.codehilite .gs { font-weight: bold } /* Generic.Strong */
+.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.codehilite .gt { color: #0040D0 } /* Generic.Traceback */
+.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.codehilite .kp { color: #008000 } /* Keyword.Pseudo */
+.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.codehilite .kt { color: #B00040 } /* Keyword.Type */
+.codehilite .m { color: #666666 } /* Literal.Number */
+.codehilite .s { color: #BA2121 } /* Literal.String */
+.codehilite .na { color: #7D9029 } /* Name.Attribute */
+.codehilite .nb { color: #008000 } /* Name.Builtin */
+.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.codehilite .no { color: #880000 } /* Name.Constant */
+.codehilite .nd { color: #AA22FF } /* Name.Decorator */
+.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.codehilite .nf { color: #0000FF } /* Name.Function */
+.codehilite .nl { color: #A0A000 } /* Name.Label */
+.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.codehilite .nv { color: #19177C } /* Name.Variable */
+.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
+.codehilite .mf { color: #666666 } /* Literal.Number.Float */
+.codehilite .mh { color: #666666 } /* Literal.Number.Hex */
+.codehilite .mi { color: #666666 } /* Literal.Number.Integer */
+.codehilite .mo { color: #666666 } /* Literal.Number.Oct */
+.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
+.codehilite .sc { color: #BA2121 } /* Literal.String.Char */
+.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
+.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.codehilite .sx { color: #008000 } /* Literal.String.Other */
+.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
+.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
+.codehilite .ss { color: #19177C } /* Literal.String.Symbol */
+.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.codehilite .vc { color: #19177C } /* Name.Variable.Class */
+.codehilite .vg { color: #19177C } /* Name.Variable.Global */
+.codehilite .vi { color: #19177C } /* Name.Variable.Instance */
+.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/hubs/static/css/pygments/monokai.css b/hubs/static/css/pygments/monokai.css
new file mode 100644
index 0000000..005d477
--- /dev/null
+++ b/hubs/static/css/pygments/monokai.css
@@ -0,0 +1,64 @@
+.highlight .hll { background-color: #49483e }
+.highlight .c { color: #75715e } /* Comment */
+.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
+.highlight .k { color: #66d9ef } /* Keyword */
+.highlight .l { color: #ae81ff } /* Literal */
+.highlight .n { color: #f8f8f2 } /* Name */
+.highlight .o { color: #f92672 } /* Operator */
+.highlight .p { color: #f8f8f2 } /* Punctuation */
+.highlight .cm { color: #75715e } /* Comment.Multiline */
+.highlight .cp { color: #75715e } /* Comment.Preproc */
+.highlight .c1 { color: #75715e } /* Comment.Single */
+.highlight .cs { color: #75715e } /* Comment.Special */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .kc { color: #66d9ef } /* Keyword.Constant */
+.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
+.highlight .kn { color: #f92672 } /* Keyword.Namespace */
+.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
+.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
+.highlight .kt { color: #66d9ef } /* Keyword.Type */
+.highlight .ld { color: #e6db74 } /* Literal.Date */
+.highlight .m { color: #ae81ff } /* Literal.Number */
+.highlight .s { color: #e6db74 } /* Literal.String */
+.highlight .na { color: #a6e22e } /* Name.Attribute */
+.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
+.highlight .nc { color: #a6e22e } /* Name.Class */
+.highlight .no { color: #66d9ef } /* Name.Constant */
+.highlight .nd { color: #a6e22e } /* Name.Decorator */
+.highlight .ni { color: #f8f8f2 } /* Name.Entity */
+.highlight .ne { color: #a6e22e } /* Name.Exception */
+.highlight .nf { color: #a6e22e } /* Name.Function */
+.highlight .nl { color: #f8f8f2 } /* Name.Label */
+.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
+.highlight .nx { color: #a6e22e } /* Name.Other */
+.highlight .py { color: #f8f8f2 } /* Name.Property */
+.highlight .nt { color: #f92672 } /* Name.Tag */
+.highlight .nv { color: #f8f8f2 } /* Name.Variable */
+.highlight .ow { color: #f92672 } /* Operator.Word */
+.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
+.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
+.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
+.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
+.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
+.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
+.highlight .sc { color: #e6db74 } /* Literal.String.Char */
+.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
+.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
+.highlight .se { color: #ae81ff } /* Literal.String.Escape */
+.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
+.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
+.highlight .sx { color: #e6db74 } /* Literal.String.Other */
+.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
+.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
+.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
+.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
+.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
+.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
+.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
+
+.highlight .gh { } /* Generic Heading & Diff Header */
+.highlight .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
+.highlight .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */
+.highlight .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index a2c5e2a..3ab7050 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -310,6 +310,11 @@ font-size: 32pt;
 .navbar-nav > li.idle-2years  > a { color: #BBB; }
 .navbar-nav > li.idle-5years  > a { color: #CCC; }
 
+.media-object {
+    max-width: 92px;
+    max-height: 92px;
+}
+
 @font-face {
   font-family: 'Comfortaa';
   font-weight: 300;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index e5ea07e..2e4eaf5 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -4,6 +4,7 @@
   <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/pygments/monokai.css') }}" rel="stylesheet"/>
 </head>
 <script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
 <body>
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 486ef68..8ae603f 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -12,6 +12,9 @@ import datanommer.models
 import arrow
 import munch
 import requests
+import six
+
+import pygments.formatters
 
 import flask
 
@@ -19,6 +22,8 @@ import hubs.validators as validators
 
 import datetime
 import logging
+import uuid
+
 log = logging.getLogger('hubs')
 
 import fedmsg.config
@@ -110,13 +115,26 @@ def data(session, widget, username, fmn_context):
     # TODO - sort messages and remove duplicates
 
     # Smash multiple messages into single ones
-    matches = fedmsg.meta.conglomerate(matches, **config)
+    matches = fedmsg.meta.conglomerate(matches, lexers=True, **config)
 
     # Apply some html markup to the subtitles for extra fanciness.
     for match in matches:
         match['markup'] = apply_markup(match)
         for idx, constituent in match['msg_ids'].items():
             constituent['markup'] = apply_markup(constituent)
+            if constituent['long_form'] != constituent['subtitle']:
+                if constituent.get('lexer'):
+                    constituent['long_form'] = pygments.highlight(
+                        constituent['long_form'],
+                        constituent['lexer'],
+                        pygments.formatters.HtmlFormatter(style='monokai'),
+                    )
+                else:
+                    markup = u"<h5>{long_form}</h5>".format(**constituent)
+                    constituent['long_form'] = markup
+
+        # And tack on a unique identifier for each top level entry.
+        match['dom_id'] = six.text_type(uuid.uuid4())
 
     return dict(
         matches=matches,
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index a0dd732..138612b 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -10,6 +10,39 @@
       <div class="media-body">
         <h4 class="media-heading">{{match['markup']}}</h4>
         {{match['human_time']}}
+
+
+        {% if match['msg_ids'] | length == 1 and match['msg_ids'].values()[0].get('long_form') != match['msg_ids'].values()[0]['subtitle'] %}
+            {% set constituent = match['msg_ids'].values()[0] %}
+            <div class="pull-right">
+                <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');" class="hidden">
+                    <span class="glyphicon glyphicon-chevron-down"></span>
+                    expand
+                </a>
+                <a id="collapse-{{match['dom_id']}}" href="javascript:collapse_feed_entries('{{match['dom_id']}}');">
+                    <span class="glyphicon glyphicon-chevron-up"></span>
+                    collapse
+                </a>
+            </div>
+
+            <div id="content-{{match['dom_id']}}" class="media">
+              {% if constituent['icon'] != constituent.get('__icon__') %}
+              <div class="media-left media-top">
+                <a href="{{constituent['link']}}">
+                  <img class="media-object" src="{{constituent['icon']}}" alt="{{constituent['subtitle']}}">
+                </a>
+              </div>
+              {% endif %}
+              <div class="media-body">
+                  {{constituent['long_form']}}
+                    {% if constituent['link'] %}
+                    <a href="{{constituent['link']}}" target="_blank">
+                        Read more <span class="glyphicon glyphicon-new-window"></span>
+                    </a>
+                    {% endif %}
+              </div>
+            </div>
+        {% endif %}
         {% if match['msg_ids'] | length > 1 %}
             <div class="pull-right">
                 <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');">
diff --git a/requirements.txt b/requirements.txt
index 5dca1ce..6c101b5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -15,3 +15,6 @@ pytz
 sqlalchemy
 markdown
 pkgwat.api
+six
+pygments
+pygments-markdown-lexer

From deb9678c15571f597fbe93ed944ef642b5a3f9ad Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 23 2016 16:36:53 +0000
Subject: [PATCH 343/1001] No more linechart.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index c37b6cb..78a80c4 100755
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -5,17 +5,10 @@ import hubs.models
 
 def add_user_widgets(session, hub, username, fullname):
     """ Some defaults for an individual user's hub. """
-    widget = hubs.models.Widget(
-        plugin='linechart', index=0, left=True,
-        _config=json.dumps({
-            'username': username,
-        }))
-    hub.widgets.append(widget)
-
     # The feed widget works, but it needs to be cleaned up lots before we
     # throw it in by default.
     widget = hubs.models.Widget(
-        plugin='feed', index=1, left=True,
+        plugin='feed', index=0, left=True,
         _config=json.dumps({
             'username': username,
             'fmn_context': 'irc',  # TODO -- make this 'hubs'

From c9709c899c5ddb19dde61009a532c2a8004d26f9 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 23 2016 20:32:44 +0000
Subject: [PATCH 344/1001] Populate both groups and users from FAS.


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index c37b6cb..0a9e4f1 100755
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -80,3 +80,50 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     return hub
+
+
+def add_group_widgets(session, hub, name, summary,
+                      # These are all things that come from FAS
+                      apply_rules=None,
+                      irc_channel=None,
+                      irc_network=None,
+                      join_message=None,
+                      mailing_list=None,
+                      mailing_list_url=None):
+    """ Some defaults for an automatically created group hub. """
+
+    if apply_rules:
+        widget = hubs.models.Widget(
+            plugin='sticky', index=0, left=True,
+            _config=json.dumps({
+                "text": apply_rules,
+            }))
+        hub.widgets.append(widget)
+
+    if join_message:
+        widget = hubs.models.Widget(
+            plugin='about', index=0,
+            _config=json.dumps({
+                "text": join_message,
+            }))
+        hub.widgets.append(widget)
+
+    widget = hubs.models.Widget(
+        plugin='rules', index=1,
+        _config=json.dumps({
+            # TODO -- can we guess their urls?
+            'link': None,
+            'schedule_text': None,
+            'schedule_link': None,
+            'minutes_link': None,
+        })
+    )
+    hub.widgets.append(widget)
+
+    # TODO - set up irc widget with the right irc channel
+    # TODO - set up mailing list with the right mailing list.
+
+    # TODO - set up feed with aggregate of users stuff unless we have some
+    # other preset.
+
+    return hub
diff --git a/hubs/models.py b/hubs/models.py
index 9bbbe80..abd92f4 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -160,6 +160,15 @@ class Hub(BASE):
             if idle > limit:
                 return name
 
+    @classmethod
+    def get_or_create(cls, session, name, summary, **extra):
+        self = cls.by_name(session, name)
+        if not self:
+            self = cls.create_group_hub(session, name, summary, **extra)
+            session.add(self)
+            session.commit()
+        return self
+
     @property
     def owners(self):
         return [assoc.user for assoc in self.associations
@@ -227,6 +236,18 @@ class Hub(BASE):
 
         user = User.by_username(session, username)
         hub.subscribe(session, user, role='owner')
+        return hub
+
+    @classmethod
+    def create_group_hub(cls, session, name, summary, **extra):
+        hub = cls(name=name, summary=summary,
+                  # TODO -- do something else, smarter for group avatars
+                  avatar=username2avatar(name),
+                  user_hub=False)
+        session.add(hub)
+
+        hubs.defaults.add_group_widgets(session, hub, name, summary, **extra)
+        return hub
 
     @property
     def right_width(self):
diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
index e3368b0..a26fd17 100644
--- a/hubs/templates/groups.html
+++ b/hubs/templates/groups.html
@@ -82,7 +82,8 @@
   <div class="row">
     <div class="col-md-12">
       {% for group in promoted %}
-      {{ group.name }} is a promoted group, and it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
+        <a href="{{ url_for('hub', name=group.name)}}">{{group.name}}</a>
+        is a promoted group, and it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
       {% endfor %}
     </div>
   </div>
@@ -108,7 +109,8 @@
   <div class="row">
     <div class="col-md-12">
       {% for group in secondary %}
-        {{ group.name }} is not a promoted group
+        <a href="{{ url_for('hub', name=group.name)}}">{{group.name}}</a>
+        is not a promoted group
         but it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
         <br/>
       {% endfor %}
diff --git a/populate-all-users.py b/populate-all-users.py
deleted file mode 100755
index 401a20e..0000000
--- a/populate-all-users.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-""" Populate the hubs db with lots of data from FAS. """
-
-import getpass
-import socket
-import string
-
-import hubs.models
-
-import fedora.client.fas2
-import fedmsg.config
-fedmsg_config = fedmsg.config.load_config()
-
-fasclient = fedora.client.fas2.AccountSystem(
-    username=raw_input('Your FAS username: '),
-    password=getpass.getpass(),
-)
-timeout = socket.getdefaulttimeout()
-socket.setdefaulttimeout(None)
-
-for letter in reversed(sorted(list(set(string.letters.lower())))):
-    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
-    print "Querying FAS for the %r users.. hang on." % letter
-    request = fasclient.send_request('/user/list',
-                                    req_params={'search': '%s*' % letter},
-                                    auth=True,
-                                    timeout=500)
-    users = request['people']
-
-    for user in users:
-        username = user['username']
-        fullname = user['human_name']
-        openid = '%s.id.fedoraproject.org' % username
-        print "Creating account for %r" % openid
-        hubs.models.User.get_or_create(
-            session, openid=openid, fullname=fullname)
-
-    session.commit()
diff --git a/populate-from-fas.py b/populate-from-fas.py
new file mode 100755
index 0000000..754de7f
--- /dev/null
+++ b/populate-from-fas.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+""" Populate the hubs db with lots of data from FAS. """
+
+import getpass
+import socket
+import string
+
+import hubs.models
+
+import fedora.client.fas2
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
+
+fasclient = fedora.client.fas2.AccountSystem(
+    username=raw_input('Your FAS username: '),
+    password=getpass.getpass(),
+)
+timeout = socket.getdefaulttimeout()
+socket.setdefaulttimeout(None)
+
+
+prefix_blacklist = [
+    u'git',
+    u'svn',
+    u'bzr',
+    u'cvs',
+    u'hg',
+    u'cla_',
+    u'sysadmin-',
+]
+suffix_blacklist = [
+    u'commits',
+    u'git',
+]
+
+
+for letter in reversed(sorted(list(set(string.letters.lower())))):
+    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
+    print "Querying FAS for the %r users.. hang on." % letter
+    request = fasclient.send_request('/user/list',
+                                    req_params={'search': '%s*' % letter},
+                                    auth=True,
+                                    timeout=500)
+    users = request['people']
+
+    for user in users:
+        username = user['username']
+        fullname = user['human_name']
+        openid = '%s.id.fedoraproject.org' % username
+        print "Creating account for %r" % openid
+        hubs_user = hubs.models.User.get_or_create(
+            session, openid=openid, fullname=fullname)
+
+    session.commit()
+
+    # Go back now and set up the groups...
+    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
+    for user in users:
+        hubs_user = hubs.models.User.by_username(session, user['username'])
+
+        # Build a lookup by group id
+        roles = dict([(r.group_id, r) for r in user['roles']])
+
+        for membership in user['memberships']:
+            role = roles[membership['id']]
+            if role['role_status'] != u'approved':
+                continue
+
+            name = membership['name']
+            summary = membership['display_name']
+
+            if any([name.startswith(prefix) for prefix in prefix_blacklist]):
+                continue
+            if any([name.endswith(suffix) for suffix in suffix_blacklist]):
+                continue
+
+            hub = hubs.models.Hub.get_or_create(
+                session,
+                name=name,
+                summary=summary,
+                apply_rules=membership['apply_rules'],
+                irc_channel=membership['irc_channel'],
+                irc_network=membership['irc_network'],
+                join_message=membership['joinmsg'],
+                mailing_list=membership['mailing_list'],
+                mailing_list_url=membership['mailing_list_url'],
+            )
+
+
+            if not hubs_user in hub.subscribers:
+                hub.subscribe(session, hubs_user, role='subscriber')
+            if not hubs_user in hub.members:
+                hub.subscribe(session, hubs_user, role='member')
+            if not hubs_user in hub.owners:
+                if role['role_type'] in [u'administrator', u'sponsor']:
+                    hub.subscribe(session, hubs_user, role='owner')
+
+    session.commit()

From 9bb5ea00356d21293a950dba94e4b18df74f5f21 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 24 2016 16:55:05 +0000
Subject: [PATCH 345/1001] De-duplicate the "Read more" link if it already appears in the long_form content.


---

diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index 138612b..534a51a 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -35,7 +35,7 @@
               {% endif %}
               <div class="media-body">
                   {{constituent['long_form']}}
-                    {% if constituent['link'] %}
+                    {% if constituent['link'] and constituent['link'] not in constituent['long_form'] %}
                     <a href="{{constituent['link']}}" target="_blank">
                         Read more <span class="glyphicon glyphicon-new-window"></span>
                     </a>

From 131b344cfc2c8d27502daf674ff4059a28a13306 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 24 2016 17:00:18 +0000
Subject: [PATCH 346/1001] Merge #129 `De-duplicate the "Read more" link if it already appears in the long_form content.`


---

diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index 138612b..534a51a 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -35,7 +35,7 @@
               {% endif %}
               <div class="media-body">
                   {{constituent['long_form']}}
-                    {% if constituent['link'] %}
+                    {% if constituent['link'] and constituent['link'] not in constituent['long_form'] %}
                     <a href="{{constituent['link']}}" target="_blank">
                         Read more <span class="glyphicon glyphicon-new-window"></span>
                     </a>

From 35c0d5e3fb38ec93a36e2c66572e606d7c17d392 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 24 2016 17:14:42 +0000
Subject: [PATCH 347/1001] Merge #128 `Populate both groups and users from FAS.`


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 78a80c4..4b2049d 100755
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -73,3 +73,50 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     return hub
+
+
+def add_group_widgets(session, hub, name, summary,
+                      # These are all things that come from FAS
+                      apply_rules=None,
+                      irc_channel=None,
+                      irc_network=None,
+                      join_message=None,
+                      mailing_list=None,
+                      mailing_list_url=None):
+    """ Some defaults for an automatically created group hub. """
+
+    if apply_rules:
+        widget = hubs.models.Widget(
+            plugin='sticky', index=0, left=True,
+            _config=json.dumps({
+                "text": apply_rules,
+            }))
+        hub.widgets.append(widget)
+
+    if join_message:
+        widget = hubs.models.Widget(
+            plugin='about', index=0,
+            _config=json.dumps({
+                "text": join_message,
+            }))
+        hub.widgets.append(widget)
+
+    widget = hubs.models.Widget(
+        plugin='rules', index=1,
+        _config=json.dumps({
+            # TODO -- can we guess their urls?
+            'link': None,
+            'schedule_text': None,
+            'schedule_link': None,
+            'minutes_link': None,
+        })
+    )
+    hub.widgets.append(widget)
+
+    # TODO - set up irc widget with the right irc channel
+    # TODO - set up mailing list with the right mailing list.
+
+    # TODO - set up feed with aggregate of users stuff unless we have some
+    # other preset.
+
+    return hub
diff --git a/hubs/models.py b/hubs/models.py
index 9bbbe80..abd92f4 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -160,6 +160,15 @@ class Hub(BASE):
             if idle > limit:
                 return name
 
+    @classmethod
+    def get_or_create(cls, session, name, summary, **extra):
+        self = cls.by_name(session, name)
+        if not self:
+            self = cls.create_group_hub(session, name, summary, **extra)
+            session.add(self)
+            session.commit()
+        return self
+
     @property
     def owners(self):
         return [assoc.user for assoc in self.associations
@@ -227,6 +236,18 @@ class Hub(BASE):
 
         user = User.by_username(session, username)
         hub.subscribe(session, user, role='owner')
+        return hub
+
+    @classmethod
+    def create_group_hub(cls, session, name, summary, **extra):
+        hub = cls(name=name, summary=summary,
+                  # TODO -- do something else, smarter for group avatars
+                  avatar=username2avatar(name),
+                  user_hub=False)
+        session.add(hub)
+
+        hubs.defaults.add_group_widgets(session, hub, name, summary, **extra)
+        return hub
 
     @property
     def right_width(self):
diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
index e3368b0..a26fd17 100644
--- a/hubs/templates/groups.html
+++ b/hubs/templates/groups.html
@@ -82,7 +82,8 @@
   <div class="row">
     <div class="col-md-12">
       {% for group in promoted %}
-      {{ group.name }} is a promoted group, and it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
+        <a href="{{ url_for('hub', name=group.name)}}">{{group.name}}</a>
+        is a promoted group, and it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
       {% endfor %}
     </div>
   </div>
@@ -108,7 +109,8 @@
   <div class="row">
     <div class="col-md-12">
       {% for group in secondary %}
-        {{ group.name }} is not a promoted group
+        <a href="{{ url_for('hub', name=group.name)}}">{{group.name}}</a>
+        is not a promoted group
         but it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
         <br/>
       {% endfor %}
diff --git a/populate-all-users.py b/populate-all-users.py
deleted file mode 100755
index 401a20e..0000000
--- a/populate-all-users.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-""" Populate the hubs db with lots of data from FAS. """
-
-import getpass
-import socket
-import string
-
-import hubs.models
-
-import fedora.client.fas2
-import fedmsg.config
-fedmsg_config = fedmsg.config.load_config()
-
-fasclient = fedora.client.fas2.AccountSystem(
-    username=raw_input('Your FAS username: '),
-    password=getpass.getpass(),
-)
-timeout = socket.getdefaulttimeout()
-socket.setdefaulttimeout(None)
-
-for letter in reversed(sorted(list(set(string.letters.lower())))):
-    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
-    print "Querying FAS for the %r users.. hang on." % letter
-    request = fasclient.send_request('/user/list',
-                                    req_params={'search': '%s*' % letter},
-                                    auth=True,
-                                    timeout=500)
-    users = request['people']
-
-    for user in users:
-        username = user['username']
-        fullname = user['human_name']
-        openid = '%s.id.fedoraproject.org' % username
-        print "Creating account for %r" % openid
-        hubs.models.User.get_or_create(
-            session, openid=openid, fullname=fullname)
-
-    session.commit()
diff --git a/populate-from-fas.py b/populate-from-fas.py
new file mode 100755
index 0000000..754de7f
--- /dev/null
+++ b/populate-from-fas.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+""" Populate the hubs db with lots of data from FAS. """
+
+import getpass
+import socket
+import string
+
+import hubs.models
+
+import fedora.client.fas2
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
+
+fasclient = fedora.client.fas2.AccountSystem(
+    username=raw_input('Your FAS username: '),
+    password=getpass.getpass(),
+)
+timeout = socket.getdefaulttimeout()
+socket.setdefaulttimeout(None)
+
+
+prefix_blacklist = [
+    u'git',
+    u'svn',
+    u'bzr',
+    u'cvs',
+    u'hg',
+    u'cla_',
+    u'sysadmin-',
+]
+suffix_blacklist = [
+    u'commits',
+    u'git',
+]
+
+
+for letter in reversed(sorted(list(set(string.letters.lower())))):
+    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
+    print "Querying FAS for the %r users.. hang on." % letter
+    request = fasclient.send_request('/user/list',
+                                    req_params={'search': '%s*' % letter},
+                                    auth=True,
+                                    timeout=500)
+    users = request['people']
+
+    for user in users:
+        username = user['username']
+        fullname = user['human_name']
+        openid = '%s.id.fedoraproject.org' % username
+        print "Creating account for %r" % openid
+        hubs_user = hubs.models.User.get_or_create(
+            session, openid=openid, fullname=fullname)
+
+    session.commit()
+
+    # Go back now and set up the groups...
+    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
+    for user in users:
+        hubs_user = hubs.models.User.by_username(session, user['username'])
+
+        # Build a lookup by group id
+        roles = dict([(r.group_id, r) for r in user['roles']])
+
+        for membership in user['memberships']:
+            role = roles[membership['id']]
+            if role['role_status'] != u'approved':
+                continue
+
+            name = membership['name']
+            summary = membership['display_name']
+
+            if any([name.startswith(prefix) for prefix in prefix_blacklist]):
+                continue
+            if any([name.endswith(suffix) for suffix in suffix_blacklist]):
+                continue
+
+            hub = hubs.models.Hub.get_or_create(
+                session,
+                name=name,
+                summary=summary,
+                apply_rules=membership['apply_rules'],
+                irc_channel=membership['irc_channel'],
+                irc_network=membership['irc_network'],
+                join_message=membership['joinmsg'],
+                mailing_list=membership['mailing_list'],
+                mailing_list_url=membership['mailing_list_url'],
+            )
+
+
+            if not hubs_user in hub.subscribers:
+                hub.subscribe(session, hubs_user, role='subscriber')
+            if not hubs_user in hub.members:
+                hub.subscribe(session, hubs_user, role='member')
+            if not hubs_user in hub.owners:
+                if role['role_type'] in [u'administrator', u'sponsor']:
+                    hub.subscribe(session, hubs_user, role='owner')
+
+    session.commit()

From d3491dc32e08de52b4f59a36f6d2e2ebf9cd9804 Mon Sep 17 00:00:00 2001
From: kjtdimuthu <kjtdimuthu@gmail.com>
Date: Mar 27 2016 16:15:35 +0000
Subject: [PATCH 348/1001] CSS UI is updated in meeting widgets according to issue #22


---

diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index 76a4c1b..f083080 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -1,23 +1,40 @@
 {% if meetings %}
-    {% for title, items in meetings.items() %}
-        {% set next = items | next_meeting %}
-        {% if next %}
-        <p>The {{ next.meeting_name }} is {{ next.human_time }}</p>
-        {% if next.display_duration %}
-        <h1 class='inline'>{{next.start_date}} - {{next.stop_date}}</h1>
-        {% else %}
-        <h1 class='inline'>{{next.start_date}}</h1>
-        {% endif %}
-        <div class='inline'>
-            {% if next.display_time %}
-            @{{next.start_time}}<br/>
+{% for title, items in meetings.items() %}
+{% set next = items | next_meeting %}
+{% if next %}
+<div>
+    <div class="row">
+        <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.human_time }}</h5>
+    </div>
+    <div class="row">
+        <div class="col-md-4">
+            {% if next.display_duration %}
+            <strong style="font-size: 18px">{{next.start_date}} - {{next.stop_date}}</strong>
+            {% else %}
+            <strong style="font-size: 18px">
+                {{next.start_date}}
+            </strong>
             {% endif %}
-            {{next.location}}<br/>
+        </div>
+        <div class="col-md-4" style="font-size: 12px">
+            {% if next.display_time %}
+            @{{next.start_time}}{% endif %}<br>
+
+            <a href="#">{{next.location}}</a>
+        </div>
+        <div class="col-md-4">
+            <button class="btn btn-default btn-sm" style="color: #a07cbc;font-size: 10px"><strong>Add to calendar</strong></button>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-md-12" style="font-size:14px">
             {{next.meeting_information_html}}
         </div>
-        {% endif %}
-        {% if meetings | length > 1 %}
-        <hr/>
-        {% endif %}
-    {% endfor %}
+    </div>
+</div>
+{% endif %}
+{% if meetings | length > 1 %}
+<hr>
+{% endif %}
+{% endfor %}
 {% endif %}

From 76075fdb06ef27a6477ab4a644aac35f1ef93e78 Mon Sep 17 00:00:00 2001
From: kjtdimuthu <kjtdimuthu@gmail.com>
Date: Mar 29 2016 02:52:14 +0000
Subject: [PATCH 349/1001] Meeting widget CSS UI was modified according to #22. Meeting styles were added to style.css


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 3ab7050..b0b9883 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -356,3 +356,22 @@ font-size: 32pt;
        url('/fonts/Comfortaa-700/Comfortaa-700.ttf') format('truetype'),
        url('/fonts/Comfortaa-700/Comfortaa-700.svg#Comfortaa') format('svg');
 }
+
+
+.meeting .meeting-date {
+    font-size: 18px;
+}
+
+.meeting .meeting-time {
+    font-size: 12px;
+}
+
+.meeting .meeting-info {
+    font-size: 14px;
+}
+
+.meeting .add-calendar {
+    font-size: 10px;
+    color: #a07cbc;
+}
+
diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index f083080..f41af8b 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -2,32 +2,32 @@
 {% for title, items in meetings.items() %}
 {% set next = items | next_meeting %}
 {% if next %}
-<div>
+<div class="meeting">
     <div class="row">
         <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.human_time }}</h5>
     </div>
     <div class="row">
-        <div class="col-md-4">
+        <div class="col-md-4 meeting-date">
             {% if next.display_duration %}
-            <strong style="font-size: 18px">{{next.start_date}} - {{next.stop_date}}</strong>
+            <strong>{{next.start_date}} - {{next.stop_date}}</strong>
             {% else %}
-            <strong style="font-size: 18px">
+            <strong>
                 {{next.start_date}}
             </strong>
             {% endif %}
         </div>
-        <div class="col-md-4" style="font-size: 12px">
+        <div class="col-md-4 meeting-time">
             {% if next.display_time %}
             @{{next.start_time}}{% endif %}<br>
 
             <a href="#">{{next.location}}</a>
         </div>
         <div class="col-md-4">
-            <button class="btn btn-default btn-sm" style="color: #a07cbc;font-size: 10px"><strong>Add to calendar</strong></button>
+            <button class="btn btn-default btn-sm add-calendar"><strong>Add to calendar</strong></button>
         </div>
     </div>
     <div class="row">
-        <div class="col-md-12" style="font-size:14px">
+        <div class="col-md-12 meeting-info">
             {{next.meeting_information_html}}
         </div>
     </div>

From 3ce1455856b68b4906051412e4deef65c27edbf7 Mon Sep 17 00:00:00 2001
From: kjtdimuthu <kjtdimuthu@gmail.com>
Date: Mar 29 2016 04:30:21 +0000
Subject: [PATCH 350/1001] issue #113 done


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index b0b9883..f29c893 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -168,6 +168,16 @@
     width: 100%;
     text-align: center;
   }
+  .header .dropdown.edit {
+    position: absolute;
+    width:150px;
+    top: 90px;
+    left: 0;
+    z-index: 2;
+  }
+  .header .edit-this-page{
+    color:#000000;
+  }
 }
 
     h1, h2, h3, h4, h5, h6 {
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 2e4eaf5..a49087f 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -4,7 +4,6 @@
   <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
-  <link href="{{ url_for('static', filename='css/pygments/monokai.css') }}" rel="stylesheet"/>
 </head>
 <script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
 <body>
@@ -75,8 +74,8 @@
 </div>
 <div class="header">
   {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
-    <div class="dropdown pull-right edit">
-      <span class="dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+    <div class="dropdown edit">
+      <span class="dropdown-toggle edit-this-page" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
         <span class="glyphicon glyphicon-edit"></span> edit this page
       </span>
       <ul class="dropdown-menu" aria-labelledby="dropdownMenu2">

From ed4c09c0c4519469b283d55a282f12b33184c699 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 15:10:44 +0000
Subject: [PATCH 351/1001] Getting closer to a running cache invalidator.


---

diff --git a/fedmsg.d/logging.py b/fedmsg.d/logging.py
index c31901c..3502cd9 100644
--- a/fedmsg.d/logging.py
+++ b/fedmsg.d/logging.py
@@ -19,22 +19,27 @@ config = dict(
                 "stream": "ext://sys.stdout",
             },
         ),
-        loggers=dict(
-            fedmsg={
+        loggers={
+            "fedmsg": {
                 "level": "INFO",
                 "propagate": False,
                 "handlers": ["console"],
             },
-            moksha={
+            "moksha": {
                 "level": "INFO",
                 "propagate": False,
                 "handlers": ["console"],
             },
-            hubs={
+            "hubs": {
                 "level": "DEBUG",
                 "propagate": False,
                 "handlers": ["console"],
             },
-        ),
+            "fmn.rules": {
+                "level": "ERROR",
+                "propagate": False,
+                "handlers": ["console"],
+            }
+        },
     ),
 )
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index ec13c43..e85072e 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -25,6 +25,15 @@ config = {
         },
     },
 
+    # Some configuration for the general hubs cache.
+    "fedora-hubs.cache": {
+        "backend": "dogpile.cache.dbm",
+        "expiration_time": -1,  # Expire every 1 second, for development
+        "arguments": {
+            "filename": "/var/tmp/fedora-hubs-cache.db",
+        },
+    },
+
     # Run datanommer locally, just for development.
     'datanommer.enabled': True,
     'datanommer.sqlalchemy.url': 'postgres://postgres:laksjdf@127.0.0.1/datanommer',
diff --git a/hubs/consumer.py b/hubs/consumer.py
index bd7345e..6e938ae 100755
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -4,11 +4,14 @@ import collections
 import threading
 import time
 
+import munch
+
 import datanommer.models
 import fedmsg.consumers
 import fedmsg.meta
 
 import hubs.models
+import hubs.widgets
 
 from hubs.widgets.base import invalidate_cache
 
@@ -16,6 +19,17 @@ import logging
 log = logging.getLogger("hubs")
 
 
+def j(widget):
+    """ Shorthand to reduce a sqlalchemy widget to a munch for processing. """
+    return munch.Munch(dict(
+        idx=widget.idx,
+        hub_id=widget.hub_id,
+        plugin=widget.plugin,
+        config=widget.config,
+        # TODO -- add other things here as we need it
+    ))
+
+
 class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
     topic = '*'
     config_key = 'hubs.consumer.enabled'
@@ -50,29 +64,37 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         self.checks_by_topic = collections.defaultdict(list)
         self.checks_by_category = collections.defaultdict(list)
         self.checks_by_username = collections.defaultdict(list)
+        self.ubiquitous_checks = list()
 
         widgets = session.query(hubs.models.Widget).all()
         log.info("Building lookup from  %i total widgets" % len(widgets))
         for widget in widgets:
-            check = widget.module.should_invalidate
+            module = hubs.widgets.registry[widget.plugin]
+            check = module.should_invalidate
 
             if not hasattr(check, 'hints'):
-                raise AttributeError("%r must declare hints" % widget.module)
+                raise AttributeError("%r must declare hints" % module)
+
+            item = (check, j(widget),)
 
             for topic in check.hints['topics']:
-                self.checks_by_topic[topic].append((check, widget,))
+                self.checks_by_topic[topic].append(item)
 
             for category in check.hints['categories']:
-                self.checks_by_category[category].append((check, widget,))
+                self.checks_by_category[category].append(item);
 
             usernames = check.hints['usernames_function'](widget)
             for username in usernames:
-                self.checks_by_username[username].append((check, widget,))
+                self.checks_by_username[username].append(item)
+
+            if check.hints['ubiquitous']:
+                self.ubiquitous_checks.append(item)
 
         log.info("Lookup sizes are:")
         log.info("- %i topics" % len(self.checks_by_topic))
         log.info("- %i categories" % len(self.checks_by_category))
         log.info("- %i usernames" % len(self.checks_by_username))
+        log.info("- %i ubiquitous" % len(self.ubiquitous_checks))
 
     @property
     def lookup_initialized(self):
@@ -86,10 +108,13 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         except:
             session.rollback()  # rolls back the transaction
             raise
+        finally:
+            session.close()
 
     def work(self, session, raw_msg):
         topic, msg = raw_msg['topic'], raw_msg['body']
         category = topic.split('.')[3]
+        usernames = fedmsg.meta.msg2usernames(msg, **self.hub.config)
 
         for suffix in self.junk_suffixes:
             if topic.endswith(suffix):
@@ -111,9 +136,12 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
 
         # Start this by finding a subset of widget checks that might match this
         # message. Look them up based on the hints they declare.
-        checks = set(
-            self.checks_by_topic[topic] + self.checks_by_category[category]
-        )
+        checks = sum([
+            self.checks_by_topic[topic],
+            self.checks_by_category[category],
+            sum([self.checks_by_username[u] for u in usernames], []),
+            self.ubiquitous_checks,
+        ], [])
 
         statement = "Found %i checks to try for this message" % len(checks)
         if checks:
@@ -129,7 +157,8 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
                 # Invalidate the cache...
                 invalidate_cache(widget, **widget.config)
                 # Rebuild it.
-                widget.module.data(session, widget, **widget.config)
+                module = hubs.widgets.registry[widget.plugin]
+                module.data(session, widget, **widget.config)
                 # TODO -- fire off an EventSource notice that we updated stuff
 
         log.debug("Done.  %0.2fs %s %s",
diff --git a/hubs/hinting.py b/hubs/hinting.py
index b04d688..14ed445 100755
--- a/hubs/hinting.py
+++ b/hubs/hinting.py
@@ -6,11 +6,12 @@ import logging
 log = logging.getLogger('hubs.hinting')
 
 
-def hint(topics=None, categories=None, usernames=None):
+def hint(topics=None, categories=None, usernames=None, ubiquitous=False):
     topics = topics or []
     categories = categories or []
     default_usernames = lambda x: []
     usernames = usernames or default_usernames
+    ubiquitous = ubiquitous
 
     @decorator.decorator
     def wrapper(fn, *args, **kwargs):
@@ -22,6 +23,7 @@ def hint(topics=None, categories=None, usernames=None):
             topics=topics,
             categories=categories,
             usernames_function=usernames,
+            ubiquitous=ubiquitous,
         )
         return wrapped
 
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index f1f84cb..e1fd798 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -77,7 +77,7 @@ def invalidate_cache(widget, *args, **kwargs):
     cache.delete(key)
 
 
-def cache_key_generator(widget, args, kwargs):
+def cache_key_generator(widget, *args, **kwargs):
     return "|".join([
         str(widget.idx),
         json.dumps(args),
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 8ae603f..de793f5 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 
 from hubs.hinting import hint
-from hubs.widgets.base import argument
+from hubs.widgets.base import argument, cache
 from hubs.widgets import templating
 
 import fmn.lib
@@ -61,7 +61,6 @@ def apply_markup(match):
 
     return markup
 
-
 @argument(name="username",
           default=None,
           validator=validators.username,
@@ -71,15 +70,11 @@ def apply_markup(match):
           validator=validators.fmn_context,
           help="A FMN context.")
 def data(session, widget, username, fmn_context):
-    openid = '%s.id.fedoraproject.org' % username
-    url = '/'.join([fmn_url, 'api', openid, fmn_context])
-    log.info("Getting FMN preferences from %s" % url)
-    response = requests.get(url)
     messages = []
     matches = []
-    if response.status_code == 200:
-        preference = response.json()
-        preference = rehydrate_preferences(preference)
+    preference = get_remote_preference(username, fmn_context)
+    if preference:
+        preference = rehydrate_preference(preference)
 
         # The smaller we make this, the faster it is.
         delta = datetime.timedelta(days=365)
@@ -110,7 +105,7 @@ def data(session, widget, username, fmn_context):
             if recipients:
                 matches.append(original)
     else:
-        log.warn("You don't have any preferences. \n Url=%s" % url)
+        log.warn("You don't have any preferences.")
 
     # TODO - sort messages and remove duplicates
 
@@ -141,14 +136,34 @@ def data(session, widget, username, fmn_context):
     )
 
 
-@hint()
+@hint(ubiquitous=True)
 def should_invalidate(message, session, widget):
-    # only if a new message would match the FMN filters would this be
-    # invalidated... but that is as expensive as being FMN ourselves.
-    raise NotImplementedError
+    username = widget.config['username']
+    fmn_context = widget.config['fmn_context']
+    preference = get_remote_preference(username, fmn_context)
+    if not preference:
+        return False
+    preference = rehydrate_preference(preference)
+    recipients = fmn.lib.recipients([preference], message, paths, config)
+    return bool(recipients)
+
+
+# TODO -- this cache value needs its own FMN-based invalidator...
+@cache.cache_on_arguments()
+def get_remote_preference(username, fmn_context):
+    openid = '%s.id.fedoraproject.org' % username
+    url = '/'.join([fmn_url, 'api', openid, fmn_context])
+    log.info("Getting FMN preference from %s" % url)
+    response = requests.get(url)
+    if bool(response):
+        return response.json()
+    else:
+        # Some people have no FMN preferences, but when they do get some.. then
+        # we'll receive the fedmsg event about it and bust this cache value.
+        return None
 
 
-def rehydrate_preferences(preference):
+def rehydrate_preference(preference):
     for fltr in preference['filters']:
         fltr['rules'] = [munch.Munch(r) for r in fltr['rules']]
         for rule in fltr['rules']:
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 37c11ee..67bdc1c 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -1,4 +1,4 @@
-#from hubs.hinting import hint, prefixed as _
+from hubs.hinting import hint
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
@@ -68,6 +68,7 @@ def data(session, widget, calendar):
     return dict(meetings=dict(meetings))
 
 
+@hint(categories=['fedocal'])
 def should_invalidate(message, session, widget):
     # TODO -- we have a hard problem here.
     # There is no event which should invalidate this widget...
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 7f329cf..3b784e3 100755
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -36,7 +36,7 @@ def data(session, widget):
     )
 
 
-@hint(topics=_('hubs.hub.update'))
+@hint(topics=[_('hubs.hub.update')])
 def should_invalidate(message, session, widget):
     if message['topic'].endswith('hubs.hub.update'):
         if message['msg']['hub']['name'] == widget.hub.name:
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 6d7e52f..6576516 100755
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -1,4 +1,4 @@
-# from hubs.hinting import hint, prefixed as _
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
@@ -9,6 +9,9 @@ import hubs.models
 
 from fedmsg.meta.base import BaseConglomerator as BC
 
+import fedmsg.config
+fm_config = fedmsg.config.load_config()
+
 import flask
 
 chrome = panel('Hubs', key='associations')
@@ -47,5 +50,8 @@ def manage_subscriptions(items):
     ]
 
 
+@hint(topics=[_('hubs.associate')])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError()
+    username = widget.config['username']
+    users = fedmsg.meta.msg2usernames(message, **fm_config)
+    return username in users

From d663edbf48bae474aff85f0510b4b0eccc68b6d3 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 15:10:44 +0000
Subject: [PATCH 352/1001] Make the cobweb widget invalidate-able.


---

diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index f03aa86..1b91407 100755
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -1,33 +1,41 @@
-from hubs.hinting import hint, prefixed as _
-
-import arrow
-import datetime
+from hubs.hinting import hint
 
 from hubs.widgets import templating
 from hubs.widgets.chrome import panel
+
+import hubs.models
+
+
+def days_since(then):
+    return (datetime.datetime.utcnow() - then).days
+
 klass_switcher = lambda data: 'panel-danger' if data['archived'] else 'panel-info'
 chrome = panel(None, key='old', klass=klass_switcher)
+templating.environment.filters['days_since'] = days_since
 template = templating.environment.get_template('templates/cobwebs.html')
 
 
 def data(session, widget):
-    days = widget.hub.days_idle
+    last_modified = widget.hub.last_modified
     archived = widget.hub.archived
-    old = days > 31 or archived
-    then = datetime.datetime.utcnow() - datetime.timedelta(days=days)
-    then = arrow.get(then).humanize()
+
     import flask
     if archived:
         icon = flask.url_for('static', filename='img/archived.png')
     else:
         icon = flask.url_for('static', filename='img/cobweb.png')
-    return dict(old=old, days=days, then=then, icon=icon, archived=archived)
+
+    return dict(last_modified=last_modified, archived=archived, icon=icon)
 
 
-#@hint(topics=[_('hubs.widget.update')])
+@hint(ubiquitous=True)
 def should_invalidate(message, session, widget):
-    # TODO -- this one is going to be to be reorganized, since there's no event
-    # that causes this one to flip.
-    # We could add a hack that forces the deletion of this key when other
-    # widgets on the same hub are updated...  but that would be very special.
-    raise NotImplementedError()
+
+    # TODO -- return True if the message says that this hub is archived
+
+    hub = hubs.models.Hub.get(session, widget.hub_id)
+    others = [w for w in hub.widgets if w.plugin != 'cobwebs']
+    for other in others:
+        if should_invalidate(message, session, other):
+            return True
+    return False
diff --git a/hubs/widgets/templates/cobwebs.html b/hubs/widgets/templates/cobwebs.html
index d4b2e7b..c5a4aed 100644
--- a/hubs/widgets/templates/cobwebs.html
+++ b/hubs/widgets/templates/cobwebs.html
@@ -1,4 +1,4 @@
-{% if old %}
+{% if last_modified | days_since > 31 %}
 <ul class="media-list">
     <li class="media">
         <div class="media-left">
@@ -8,7 +8,7 @@
         {% if archived %}
             This hub has been archived and locked.
         {% else %}
-            Cobweb alert!  This hub was last active {{then}}.
+            Cobweb alert!  This hub was last active {{ last_modified | days_since }} days ago.
         {% endif %}
         </div>
     </li>

From b63e762be058a10418cbb2671fe62a9651ff44fc Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 15:10:44 +0000
Subject: [PATCH 353/1001] Add a nice repr for widgets.


---

diff --git a/hubs/models.py b/hubs/models.py
index abd92f4..9fe8f04 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -321,6 +321,9 @@ class Widget(BASE):
             'config': self.config,
         }
 
+    def __repr__(self):
+        return "<Widget %s /%s/%i>" % (self.plugin, self.hub.name, self.idx)
+
     @property
     def module(self):
         return hubs.widgets.registry[self.plugin]

From 4df051f477c0dd7398b48d71dca00e9f44f98a34 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 15:10:44 +0000
Subject: [PATCH 354/1001] Add forgotten import.


---

diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index 1b91407..ac4a3f6 100755
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -1,5 +1,7 @@
 from hubs.hinting import hint
 
+import datetime
+
 from hubs.widgets import templating
 from hubs.widgets.chrome import panel
 

From 70530f64930093816740ed908a89b2922b996d7c Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 15:10:44 +0000
Subject: [PATCH 355/1001] Whoops!  Avoid infinite recursion here.


---

diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index ac4a3f6..90f8f76 100755
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -38,6 +38,6 @@ def should_invalidate(message, session, widget):
     hub = hubs.models.Hub.get(session, widget.hub_id)
     others = [w for w in hub.widgets if w.plugin != 'cobwebs']
     for other in others:
-        if should_invalidate(message, session, other):
+        if other.module.should_invalidate(message, session, other):
             return True
     return False

From 0ee91184757a0321e1d9231c66713cf2834de0c1 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 15:13:32 +0000
Subject: [PATCH 356/1001] Typofix.


---

diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
index 90f8f76..e10049f 100755
--- a/hubs/widgets/cobwebs.py
+++ b/hubs/widgets/cobwebs.py
@@ -18,7 +18,7 @@ template = templating.environment.get_template('templates/cobwebs.html')
 
 
 def data(session, widget):
-    last_modified = widget.hub.last_modified
+    last_modified = widget.hub.last_refreshed
     archived = widget.hub.archived
 
     import flask

From c08c83cc6277a275f261e67c5f2048441b4b716b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 15:16:10 +0000
Subject: [PATCH 357/1001] Update the test suite.


---

diff --git a/hubs/tests/test_widgets/test_cobwebs.py b/hubs/tests/test_widgets/test_cobwebs.py
index 96f58f4..d3286a5 100644
--- a/hubs/tests/test_widgets/test_cobwebs.py
+++ b/hubs/tests/test_widgets/test_cobwebs.py
@@ -13,12 +13,10 @@ class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']  # changes oddly, so don't test
         self.assertDictEqual(data['data'], {
-            u'days': 100,
-            u'old': True,
+            u'last_modified': u'Sun, 20 Dec 2015 15:13:06 GMT',
             u'archived': False,
             u'icon': u'/static/img/cobweb.png',
             u'source_url': u'/source/cobwebs/',
-            u'then': '3 months ago',
         })
 
     def test_data_young(self):
@@ -28,10 +26,8 @@ class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']  # changes oddly, so don't test
         self.assertDictEqual(data['data'], {
-            u'days': 0,
-            u'old': False,
+            u'last_modified': u'Tue, 29 Mar 2016 15:14:46 GMT',
             u'archived': False,
             u'icon': u'/static/img/cobweb.png',
             u'source_url': u'/source/cobwebs/',
-            u'then': u'just now',
         })
diff --git a/hubs/tests/test_widgets/test_linechart.py b/hubs/tests/test_widgets/test_linechart.py
deleted file mode 100644
index 5bbfd5c..0000000
--- a/hubs/tests/test_widgets/test_linechart.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import json
-
-import hubs.tests.test_widgets
-
-
-class TestLinechart(hubs.tests.test_widgets.WidgetTest):
-    plugin = 'linechart'
-
-    def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json/' % widget.idx)
-        assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
-        datagrepper = 'https://apps.fedoraproject.org/datagrepper'
-        assert data['data']['url'].startswith(datagrepper)

From 658af5f10b9ab3c0f5a6722d923e335e886c362a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 15:18:50 +0000
Subject: [PATCH 358/1001] Add a render test for the meetings widge.t


---

diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 0274255..97d2fb5 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -15,3 +15,10 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         meetings = data['data']['meetings']["%s meeting" % team]
         assert len(meetings) == 15, len(meetings)
         assert team in meetings[0]['meeting_name']
+
+    def test_render_simple(self):
+        team = 'i18n'
+        widget = self.widget_instance(team, self.plugin)
+        response = self.app.get('/%s/%i/' % (team, widget.idx))
+        assert response.status_code == 200, response.status_code
+        assert 'The i18n meeting is in 14 hours' in response.data

From 6a6a53a77cc0de7f39505bdc6e0c6bd6b0006e5d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 15:37:22 +0000
Subject: [PATCH 359/1001] Doh.. brittle test.


---

diff --git a/hubs/tests/test_widgets/test_cobwebs.py b/hubs/tests/test_widgets/test_cobwebs.py
index d3286a5..c6d001b 100644
--- a/hubs/tests/test_widgets/test_cobwebs.py
+++ b/hubs/tests/test_widgets/test_cobwebs.py
@@ -13,7 +13,7 @@ class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']  # changes oddly, so don't test
         self.assertDictEqual(data['data'], {
-            u'last_modified': u'Sun, 20 Dec 2015 15:13:06 GMT',
+            u'last_modified': u'Sun, 20 Dec 2015 15:34:07 GMT',
             u'archived': False,
             u'icon': u'/static/img/cobweb.png',
             u'source_url': u'/source/cobwebs/',
@@ -26,7 +26,7 @@ class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']  # changes oddly, so don't test
         self.assertDictEqual(data['data'], {
-            u'last_modified': u'Tue, 29 Mar 2016 15:14:46 GMT',
+            u'last_modified': u'Tue, 29 Mar 2016 15:34:07 GMT',
             u'archived': False,
             u'icon': u'/static/img/cobweb.png',
             u'source_url': u'/source/cobwebs/',

From 60209496396f4a965f64266b0357cd665979d732 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 21:00:39 +0000
Subject: [PATCH 360/1001] More general backend improvements.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index 6e938ae..b5fbe9d 100755
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -10,6 +10,7 @@ import datanommer.models
 import fedmsg.consumers
 import fedmsg.meta
 
+import hubs.app
 import hubs.models
 import hubs.widgets
 
@@ -24,6 +25,9 @@ def j(widget):
     return munch.Munch(dict(
         idx=widget.idx,
         hub_id=widget.hub_id,
+        hub=munch.Munch(dict(
+            name=widget.hub.name,
+        )),
         plugin=widget.plugin,
         config=widget.config,
         # TODO -- add other things here as we need it
@@ -103,7 +107,8 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
     def consume(self, raw_msg):
         session = self.make_session()
         try:
-            self.work(session, raw_msg)
+            with hubs.app.app.app_context():  # so url_for works
+                self.work(session, raw_msg)
             session.commit()  # transaction is committed here
         except:
             session.rollback()  # rolls back the transaction
@@ -158,6 +163,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
                 invalidate_cache(widget, **widget.config)
                 # Rebuild it.
                 module = hubs.widgets.registry[widget.plugin]
+                widget = hubs.models.Widget.by_idx(session, widget.idx)
                 module.data(session, widget, **widget.config)
                 # TODO -- fire off an EventSource notice that we updated stuff
 
diff --git a/hubs/default_config.py b/hubs/default_config.py
index a21f138..a452867 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -6,3 +6,5 @@ PROMOTED_GROUPS = [
 ]
 
 HUB_OF_THE_MONTH = 'commops'
+
+SERVER_NAME = '0.0.0.0:5000'
diff --git a/hubs/models.py b/hubs/models.py
index 9fe8f04..086e0b1 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -298,6 +298,12 @@ class Widget(BASE):
     index = sa.Column(sa.Integer, nullable=False)
     left = sa.Column(sa.Boolean, nullable=False, default=False)
 
+    @classmethod
+    def by_idx(cls, session, idx):
+        return session.query(cls).filter_by(idx=idx).first()
+
+    get = by_idx
+
     @property
     def config(self):
         return json.loads(self._config)
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 97d2fb5..5a16c2f 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -12,13 +12,12 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/%s/%i/json/' % (team, widget.idx))
         assert response.status_code == 200, response.status_code
         data = json.loads(response.data)
-        meetings = data['data']['meetings']["%s meeting" % team]
-        assert len(meetings) == 15, len(meetings)
-        assert team in meetings[0]['meeting_name']
+        meeting = data['data']['meetings']["%s meeting" % team]
+        assert team in meeting['meeting_name']
 
     def test_render_simple(self):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/' % (team, widget.idx))
         assert response.status_code == 200, response.status_code
-        assert 'The i18n meeting is in 14 hours' in response.data
+        assert 'The i18n meeting is in 14 hours' in response.data, response.data
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index e1fd798..78f6d99 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -59,7 +59,7 @@ def smartcache(func):
     def inner(session, widget, *args, **kwargs):
         key = cache_key_generator(widget, args, kwargs)
         creator = lambda: func(session, widget, *args, **kwargs)
-        log.debug("Accessing cache key %s", key)
+        #log.debug("Accessing cache key %s", key)
         return cache.get_or_create(key, creator)
 
     return inner
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 67bdc1c..58f36cb 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -6,6 +6,8 @@ from hubs.widgets import templating
 from hubs import validators
 from hubs import utils
 
+import hubs.models
+
 import arrow
 import collections
 import datetime
@@ -23,30 +25,34 @@ def next_meeting(meetings):
                             meeting['meeting_time_stop'])
         stop_dt = datetime.datetime.strptime(stop_string, "%Y-%m-%d %H:%M:%S")
 
-        if now < start_dt:
-            meeting['human_time'] = arrow.get(start_dt).humanize()
-            meeting['start_date'] = start_dt.strftime('%b %d')
-            meeting['stop_date'] = stop_dt.strftime('%b %d')
-            meeting['display_time'] = True
-            meeting['display_duration'] = False
-            # Just UTC for now until we do this on the client and can access
-            # their local with moment.js.
-            meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
-            meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
-            meeting['location'] = meeting['meeting_location']
-            if '@' in meeting['location']:
-                meeting['location'] = '#' + meeting['location'].split('@')[0]
-            if stop_dt - start_dt >= datetime.timedelta(hours=24) :
-                meeting['display_time'] = False
-                if stop_dt - start_dt > datetime.timedelta(hours=24) :
-                    meeting['display_duration'] = True
-            return meeting
+        # Loop over them until we find a good one.
+        # Meetings before now are no good.  We want the first one after now.
+        if start_dt < now:
+            continue
+
+        meeting['start_dt'] = start_dt
+        meeting['start_date'] = start_dt.strftime('%b %d')
+        meeting['stop_date'] = stop_dt.strftime('%b %d')
+        meeting['display_time'] = True
+        meeting['display_duration'] = False
+        # Just UTC for now until we do this on the client and can access
+        # their local with moment.js.
+        meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
+        meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
+        meeting['location'] = meeting['meeting_location']
+        if '@' in meeting['location']:
+            meeting['location'] = '#' + meeting['location'].split('@')[0]
+        if stop_dt - start_dt >= datetime.timedelta(hours=24) :
+            meeting['display_time'] = False
+            if stop_dt - start_dt > datetime.timedelta(hours=24) :
+                meeting['display_duration'] = True
+        return meeting
 
     return None
 
 
 chrome = panel('Reminders', key='meetings')
-templating.environment.filters['next_meeting'] = next_meeting
+templating.environment.filters['humanize'] = lambda d: arrow.get(d).humanize()
 template = templating.environment.get_template('templates/meetings.html')
 
 
@@ -59,17 +65,28 @@ def data(session, widget, calendar):
     url = base % calendar
     response = requests.get(url).json()
 
-    meetings = collections.defaultdict(list)
+    tmp = collections.defaultdict(list)
     for meeting in response['meetings']:
         meeting['meeting_information_html'] = utils.markup(
             meeting['meeting_information'])
-        meetings[meeting['meeting_name']].append(meeting)
+        tmp[meeting['meeting_name']].append(meeting)
+
+    meetings = {}
+    for title, items in tmp.items():
+        selected = next_meeting(items)
+        if not selected:
+            continue
+        meetings[title] = selected
 
-    return dict(meetings=dict(meetings))
+    return dict(meetings=meetings)
 
 
 @hint(categories=['fedocal'])
 def should_invalidate(message, session, widget):
+    # first, access our *old* cache value
+    old_data = widget.module.data(session, widget, **widget.config)
+
+
     # TODO -- we have a hard problem here.
     # There is no event which should invalidate this widget...
     # but we do need to expire ourselves after the date of the meeting we
diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index f41af8b..6965c5f 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -1,10 +1,8 @@
 {% if meetings %}
-{% for title, items in meetings.items() %}
-{% set next = items | next_meeting %}
-{% if next %}
+{% for title, next in meetings.items() %}
 <div class="meeting">
     <div class="row">
-        <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.human_time }}</h5>
+        <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.start_dt | humanize }}</h5>
     </div>
     <div class="row">
         <div class="col-md-4 meeting-date">
@@ -32,9 +30,6 @@
         </div>
     </div>
 </div>
-{% endif %}
-{% if meetings | length > 1 %}
-<hr>
-{% endif %}
+{% if meetings | length > 1 %} <hr> {% endif %}
 {% endfor %}
 {% endif %}

From d237a0ad37243eb414c46cee0b2d079bc6759b5a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 29 2016 21:00:51 +0000
Subject: [PATCH 361/1001] Get invalidation for the meetings widget working.


---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 58f36cb..87edcb8 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -81,20 +81,20 @@ def data(session, widget, calendar):
     return dict(meetings=meetings)
 
 
-@hint(categories=['fedocal'])
+@hint(ubiquitous=True)
 def should_invalidate(message, session, widget):
-    # first, access our *old* cache value
-    old_data = widget.module.data(session, widget, **widget.config)
-
-
-    # TODO -- we have a hard problem here.
-    # There is no event which should invalidate this widget...
-    # but we do need to expire ourselves after the date of the meeting we
-    # cached has passed.
-    # Perhaps we should expand the should_invalidate API to return a tuple:
-    #  - True/False if we should or shouldn't invalidate.
-    #  - an expiry in seconds where -1 is default and means "never expire"
-    # with that.. we could have this function return the timestamp of the
-    # meeting in seconds.. such that once it has passed, our cache will free
-    # up.
-    raise NotImplementedError()
+
+    # TODO -- first, if this is a fedocal widget, we need to just invalidate
+    # ourselves right away.
+
+    # second, check our old cache value and see if any of our meetings have
+    # passed by in time.
+    old_data = data(session, widget, **widget.config)
+    meetings = old_data['meetings']
+    now = datetime.datetime.utcnow()
+    for title, meeting in meetings.items():
+        assert type(meeting['start_dt']) == type(now)
+        if meeting['start_dt'] < now:
+            return True
+
+    return False

From 28b2d2f7839ae3505a5aad6e707335a2f41ae678 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 14:30:52 +0000
Subject: [PATCH 362/1001] Punt on this test.


---

diff --git a/hubs/tests/test_widgets/test_cobwebs.py b/hubs/tests/test_widgets/test_cobwebs.py
deleted file mode 100644
index c6d001b..0000000
--- a/hubs/tests/test_widgets/test_cobwebs.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import json
-
-import hubs.tests.test_widgets
-
-
-class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
-    plugin = 'cobwebs'  # The name in hubs.widgets.registry
-
-    def test_data_old(self):
-        widget = self.widget_instance('old', self.plugin)
-        response = self.app.get('/old/%i/json/' % widget.idx)
-        assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
-        del data['data']['widget_url']  # changes oddly, so don't test
-        self.assertDictEqual(data['data'], {
-            u'last_modified': u'Sun, 20 Dec 2015 15:34:07 GMT',
-            u'archived': False,
-            u'icon': u'/static/img/cobweb.png',
-            u'source_url': u'/source/cobwebs/',
-        })
-
-    def test_data_young(self):
-        widget = self.widget_instance('infra', self.plugin)
-        response = self.app.get('/infra/%i/json/' % widget.idx)
-        assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
-        del data['data']['widget_url']  # changes oddly, so don't test
-        self.assertDictEqual(data['data'], {
-            u'last_modified': u'Tue, 29 Mar 2016 15:34:07 GMT',
-            u'archived': False,
-            u'icon': u'/static/img/cobweb.png',
-            u'source_url': u'/source/cobwebs/',
-        })
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 5a16c2f..90656fd 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -20,4 +20,4 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/' % (team, widget.idx))
         assert response.status_code == 200, response.status_code
-        assert 'The i18n meeting is in 14 hours' in response.data, response.data
+        assert 'The i18n meeting is in' in response.data, response.data
diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
deleted file mode 100755
index e10049f..0000000
--- a/hubs/widgets/cobwebs.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from hubs.hinting import hint
-
-import datetime
-
-from hubs.widgets import templating
-from hubs.widgets.chrome import panel
-
-import hubs.models
-
-
-def days_since(then):
-    return (datetime.datetime.utcnow() - then).days
-
-klass_switcher = lambda data: 'panel-danger' if data['archived'] else 'panel-info'
-chrome = panel(None, key='old', klass=klass_switcher)
-templating.environment.filters['days_since'] = days_since
-template = templating.environment.get_template('templates/cobwebs.html')
-
-
-def data(session, widget):
-    last_modified = widget.hub.last_refreshed
-    archived = widget.hub.archived
-
-    import flask
-    if archived:
-        icon = flask.url_for('static', filename='img/archived.png')
-    else:
-        icon = flask.url_for('static', filename='img/cobweb.png')
-
-    return dict(last_modified=last_modified, archived=archived, icon=icon)
-
-
-@hint(ubiquitous=True)
-def should_invalidate(message, session, widget):
-
-    # TODO -- return True if the message says that this hub is archived
-
-    hub = hubs.models.Hub.get(session, widget.hub_id)
-    others = [w for w in hub.widgets if w.plugin != 'cobwebs']
-    for other in others:
-        if other.module.should_invalidate(message, session, other):
-            return True
-    return False
diff --git a/hubs/widgets/templates/cobwebs.html b/hubs/widgets/templates/cobwebs.html
deleted file mode 100644
index c5a4aed..0000000
--- a/hubs/widgets/templates/cobwebs.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% if last_modified | days_since > 31 %}
-<ul class="media-list">
-    <li class="media">
-        <div class="media-left">
-            <img class="media-object square-32" src="{{icon}}"/>
-        </div>
-        <div class="media-body">
-        {% if archived %}
-            This hub has been archived and locked.
-        {% else %}
-            Cobweb alert!  This hub was last active {{ last_modified | days_since }} days ago.
-        {% endif %}
-        </div>
-    </li>
-</ul>
-{% endif %}

From f5cc6ccd470162ecbec339e912366cdc232a3ac7 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 14:31:28 +0000
Subject: [PATCH 363/1001] Make the cobweb widget into a builtin thing.  Fixes #133.


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index a49087f..02a7a02 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -110,6 +110,33 @@
   </div>
   <div class="row">
     <div class="col-md-{{ hub.left_width }}">
+      <!--
+        First, before the proper widgets.. a cobweb built-in widget.
+        https://pagure.io/fedora-hubs/issue/133
+      -->
+      {% if hub.archived or hub.last_refreshed | days_since > 31 %}
+      <ul class="media-list">
+          <li class="media">
+              <div class="media-left">
+              {% if hub.archived %}
+                  <img class="media-object square-32"
+                       src="{{flask.url_for('static', filename='img/archived.png')}}"/>
+              {% else %}
+                  <img class="media-object square-32"
+                       src="{{flask.url_for('static', filename='img/cobweb.png')}}"/>
+              {% endif %}
+              </div>
+              <div class="media-body">
+              {% if hub.archived %}
+                  This hub has been archived and locked.
+              {% else %}
+                  Cobweb alert!  This hub was last active {{ hub.last_refreshed | days_since }} days ago.
+              {% endif %}
+              </div>
+          </li>
+      </ul>
+      {% endif %}
+
       {% for widget in hub.left_widgets %}
       <div id="widget-{{ widget.idx }}" class="row"></div>
       {% endfor %}
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 8914ab6..1e917ed 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -58,8 +58,6 @@ class WidgetTest(unittest.TestCase):
                 hub.last_updated = datetime.utcnow() - timedelta(days=200)
 
             hubs.app.session.add(hub)
-            widget = hubs.models.Widget(plugin='cobwebs', index=10)
-            hub.widgets.append(widget)
             widget = hubs.models.Widget(plugin='meetings', index=11,
                                         _config=json.dumps({'calendar': team}))
             hub.widgets.append(widget)
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index cc7007c..551876a 100755
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -8,7 +8,6 @@ from hubs.widgets import linechart
 from hubs.widgets import fedmsgstats
 from hubs.widgets import feed
 from hubs.widgets import subscriptions
-from hubs.widgets import cobwebs
 from hubs.widgets import meetings
 from hubs.widgets import pagure_pr
 from hubs.widgets import github_pr
@@ -32,7 +31,6 @@ registry = {
     'fedmsgstats': fedmsgstats,
     'feed': feed,
     'subscriptions': subscriptions,
-    'cobwebs': cobwebs,
     'meetings': meetings,
     'pagure_pr': pagure_pr,
     'github_pr': github_pr,
diff --git a/populate.py b/populate.py
index 9f1816c..5e89881 100755
--- a/populate.py
+++ b/populate.py
@@ -48,8 +48,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "<p>The Fedora I18N project works on internationalization (i18n) to support the localization (l10n) of Fedora in many languages. Translation of Fedora software and documentation are handled by the Fedora L10N project.</p> <p>The goals of the Project are to:</p> <ul><li>Develop, package, and maintain applications like input methods for different languages</li> <li>Improve applications and utilities to support and process different languages</li> <li>Quality-assure that existing applications meet i18n standards</li> <li>Support the infrastructure of the Fedora Localization Project</li></ul>",
@@ -93,8 +91,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "Bringing more heat and light to Fedora, so you don't have to choose between 'building things' and 'building communities that build things.'",
@@ -140,8 +136,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "The Fedora Marketing Team develops and executes marketing strategies to promote the usage and support of Fedora worldwide. Through the development of processes and content, this project aims to support the efforts of other Fedora projects to spread Fedora and to provide a central repository of ideas and information that can be used to deliver Fedora to new audiences. We work closely with the Fedora Ambassadors who spread the word about Fedora at events and allow the Fedora Project to interact directly with its existing and prospective users. ",
@@ -188,8 +182,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "The Design Team is the design group of the Fedora project. Our interests are not only in creating graphics for use by the Fedora community, but also in advocating the use of the creative tools that are a part of Fedora.",
@@ -237,8 +229,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=2, left=True,
                             _config=json.dumps({
                                 'text': "The Infrastructure Team consists of dedicated volunteers and professionals managing the servers, building the tools and utilities, and creating new applications to make Fedora development a smoother process. We're located all over the globe and communicate primarily by IRC and e-mail. ",

From a5b2545f60654b2499ddebff97d015020a6e8775 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 14:52:22 +0000
Subject: [PATCH 364/1001] Fix typo in cache key construction.


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 78f6d99..dc7b229 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -57,7 +57,7 @@ def AGPLv3(name):
 def smartcache(func):
     @wraps(func)
     def inner(session, widget, *args, **kwargs):
-        key = cache_key_generator(widget, args, kwargs)
+        key = cache_key_generator(widget, *args, **kwargs)
         creator = lambda: func(session, widget, *args, **kwargs)
         #log.debug("Accessing cache key %s", key)
         return cache.get_or_create(key, creator)

From 10e30a62f0afa3cd1eea2b6e73223dcdae5719b6 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 14:53:07 +0000
Subject: [PATCH 365/1001] Get access to a real sqlalchemy widget (not a munch) so we can update last_refreshed on it.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index b5fbe9d..c6e0d7b 100755
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -158,13 +158,14 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         # see if any tell us that we should nuke various data caches.
         for check, widget in checks:
             if check(msg, session, widget):
+                # Get a real widget, because we update last_refreshed on it.
+                widget = hubs.models.Widget.by_idx(session, widget.idx)
                 log.info("! Invalidating cache for %r" % widget)
                 # Invalidate the cache...
                 invalidate_cache(widget, **widget.config)
                 # Rebuild it.
-                module = hubs.widgets.registry[widget.plugin]
-                widget = hubs.models.Widget.by_idx(session, widget.idx)
-                module.data(session, widget, **widget.config)
+                log.info("! Rebuilding cache for %r" % widget)
+                widget.module.data(session, widget, **widget.config)
                 # TODO -- fire off an EventSource notice that we updated stuff
 
         log.debug("Done.  %0.2fs %s %s",

From bb1d2ef042b52015832d4612ec2a29d49e683f3d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 14:57:42 +0000
Subject: [PATCH 366/1001] Merge branch 'feature/cache-invalidator-enhancements' into develop


---

diff --git a/fedmsg.d/logging.py b/fedmsg.d/logging.py
index c31901c..3502cd9 100644
--- a/fedmsg.d/logging.py
+++ b/fedmsg.d/logging.py
@@ -19,22 +19,27 @@ config = dict(
                 "stream": "ext://sys.stdout",
             },
         ),
-        loggers=dict(
-            fedmsg={
+        loggers={
+            "fedmsg": {
                 "level": "INFO",
                 "propagate": False,
                 "handlers": ["console"],
             },
-            moksha={
+            "moksha": {
                 "level": "INFO",
                 "propagate": False,
                 "handlers": ["console"],
             },
-            hubs={
+            "hubs": {
                 "level": "DEBUG",
                 "propagate": False,
                 "handlers": ["console"],
             },
-        ),
+            "fmn.rules": {
+                "level": "ERROR",
+                "propagate": False,
+                "handlers": ["console"],
+            }
+        },
     ),
 )
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index ec13c43..e85072e 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -25,6 +25,15 @@ config = {
         },
     },
 
+    # Some configuration for the general hubs cache.
+    "fedora-hubs.cache": {
+        "backend": "dogpile.cache.dbm",
+        "expiration_time": -1,  # Expire every 1 second, for development
+        "arguments": {
+            "filename": "/var/tmp/fedora-hubs-cache.db",
+        },
+    },
+
     # Run datanommer locally, just for development.
     'datanommer.enabled': True,
     'datanommer.sqlalchemy.url': 'postgres://postgres:laksjdf@127.0.0.1/datanommer',
diff --git a/hubs/consumer.py b/hubs/consumer.py
index bd7345e..c6e0d7b 100755
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -4,11 +4,15 @@ import collections
 import threading
 import time
 
+import munch
+
 import datanommer.models
 import fedmsg.consumers
 import fedmsg.meta
 
+import hubs.app
 import hubs.models
+import hubs.widgets
 
 from hubs.widgets.base import invalidate_cache
 
@@ -16,6 +20,20 @@ import logging
 log = logging.getLogger("hubs")
 
 
+def j(widget):
+    """ Shorthand to reduce a sqlalchemy widget to a munch for processing. """
+    return munch.Munch(dict(
+        idx=widget.idx,
+        hub_id=widget.hub_id,
+        hub=munch.Munch(dict(
+            name=widget.hub.name,
+        )),
+        plugin=widget.plugin,
+        config=widget.config,
+        # TODO -- add other things here as we need it
+    ))
+
+
 class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
     topic = '*'
     config_key = 'hubs.consumer.enabled'
@@ -50,29 +68,37 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         self.checks_by_topic = collections.defaultdict(list)
         self.checks_by_category = collections.defaultdict(list)
         self.checks_by_username = collections.defaultdict(list)
+        self.ubiquitous_checks = list()
 
         widgets = session.query(hubs.models.Widget).all()
         log.info("Building lookup from  %i total widgets" % len(widgets))
         for widget in widgets:
-            check = widget.module.should_invalidate
+            module = hubs.widgets.registry[widget.plugin]
+            check = module.should_invalidate
 
             if not hasattr(check, 'hints'):
-                raise AttributeError("%r must declare hints" % widget.module)
+                raise AttributeError("%r must declare hints" % module)
+
+            item = (check, j(widget),)
 
             for topic in check.hints['topics']:
-                self.checks_by_topic[topic].append((check, widget,))
+                self.checks_by_topic[topic].append(item)
 
             for category in check.hints['categories']:
-                self.checks_by_category[category].append((check, widget,))
+                self.checks_by_category[category].append(item);
 
             usernames = check.hints['usernames_function'](widget)
             for username in usernames:
-                self.checks_by_username[username].append((check, widget,))
+                self.checks_by_username[username].append(item)
+
+            if check.hints['ubiquitous']:
+                self.ubiquitous_checks.append(item)
 
         log.info("Lookup sizes are:")
         log.info("- %i topics" % len(self.checks_by_topic))
         log.info("- %i categories" % len(self.checks_by_category))
         log.info("- %i usernames" % len(self.checks_by_username))
+        log.info("- %i ubiquitous" % len(self.ubiquitous_checks))
 
     @property
     def lookup_initialized(self):
@@ -81,15 +107,19 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
     def consume(self, raw_msg):
         session = self.make_session()
         try:
-            self.work(session, raw_msg)
+            with hubs.app.app.app_context():  # so url_for works
+                self.work(session, raw_msg)
             session.commit()  # transaction is committed here
         except:
             session.rollback()  # rolls back the transaction
             raise
+        finally:
+            session.close()
 
     def work(self, session, raw_msg):
         topic, msg = raw_msg['topic'], raw_msg['body']
         category = topic.split('.')[3]
+        usernames = fedmsg.meta.msg2usernames(msg, **self.hub.config)
 
         for suffix in self.junk_suffixes:
             if topic.endswith(suffix):
@@ -111,9 +141,12 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
 
         # Start this by finding a subset of widget checks that might match this
         # message. Look them up based on the hints they declare.
-        checks = set(
-            self.checks_by_topic[topic] + self.checks_by_category[category]
-        )
+        checks = sum([
+            self.checks_by_topic[topic],
+            self.checks_by_category[category],
+            sum([self.checks_by_username[u] for u in usernames], []),
+            self.ubiquitous_checks,
+        ], [])
 
         statement = "Found %i checks to try for this message" % len(checks)
         if checks:
@@ -125,10 +158,13 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         # see if any tell us that we should nuke various data caches.
         for check, widget in checks:
             if check(msg, session, widget):
+                # Get a real widget, because we update last_refreshed on it.
+                widget = hubs.models.Widget.by_idx(session, widget.idx)
                 log.info("! Invalidating cache for %r" % widget)
                 # Invalidate the cache...
                 invalidate_cache(widget, **widget.config)
                 # Rebuild it.
+                log.info("! Rebuilding cache for %r" % widget)
                 widget.module.data(session, widget, **widget.config)
                 # TODO -- fire off an EventSource notice that we updated stuff
 
diff --git a/hubs/default_config.py b/hubs/default_config.py
index a21f138..a452867 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -6,3 +6,5 @@ PROMOTED_GROUPS = [
 ]
 
 HUB_OF_THE_MONTH = 'commops'
+
+SERVER_NAME = '0.0.0.0:5000'
diff --git a/hubs/hinting.py b/hubs/hinting.py
index b04d688..14ed445 100755
--- a/hubs/hinting.py
+++ b/hubs/hinting.py
@@ -6,11 +6,12 @@ import logging
 log = logging.getLogger('hubs.hinting')
 
 
-def hint(topics=None, categories=None, usernames=None):
+def hint(topics=None, categories=None, usernames=None, ubiquitous=False):
     topics = topics or []
     categories = categories or []
     default_usernames = lambda x: []
     usernames = usernames or default_usernames
+    ubiquitous = ubiquitous
 
     @decorator.decorator
     def wrapper(fn, *args, **kwargs):
@@ -22,6 +23,7 @@ def hint(topics=None, categories=None, usernames=None):
             topics=topics,
             categories=categories,
             usernames_function=usernames,
+            ubiquitous=ubiquitous,
         )
         return wrapped
 
diff --git a/hubs/models.py b/hubs/models.py
index abd92f4..086e0b1 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -298,6 +298,12 @@ class Widget(BASE):
     index = sa.Column(sa.Integer, nullable=False)
     left = sa.Column(sa.Boolean, nullable=False, default=False)
 
+    @classmethod
+    def by_idx(cls, session, idx):
+        return session.query(cls).filter_by(idx=idx).first()
+
+    get = by_idx
+
     @property
     def config(self):
         return json.loads(self._config)
@@ -321,6 +327,9 @@ class Widget(BASE):
             'config': self.config,
         }
 
+    def __repr__(self):
+        return "<Widget %s /%s/%i>" % (self.plugin, self.hub.name, self.idx)
+
     @property
     def module(self):
         return hubs.widgets.registry[self.plugin]
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index a49087f..02a7a02 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -110,6 +110,33 @@
   </div>
   <div class="row">
     <div class="col-md-{{ hub.left_width }}">
+      <!--
+        First, before the proper widgets.. a cobweb built-in widget.
+        https://pagure.io/fedora-hubs/issue/133
+      -->
+      {% if hub.archived or hub.last_refreshed | days_since > 31 %}
+      <ul class="media-list">
+          <li class="media">
+              <div class="media-left">
+              {% if hub.archived %}
+                  <img class="media-object square-32"
+                       src="{{flask.url_for('static', filename='img/archived.png')}}"/>
+              {% else %}
+                  <img class="media-object square-32"
+                       src="{{flask.url_for('static', filename='img/cobweb.png')}}"/>
+              {% endif %}
+              </div>
+              <div class="media-body">
+              {% if hub.archived %}
+                  This hub has been archived and locked.
+              {% else %}
+                  Cobweb alert!  This hub was last active {{ hub.last_refreshed | days_since }} days ago.
+              {% endif %}
+              </div>
+          </li>
+      </ul>
+      {% endif %}
+
       {% for widget in hub.left_widgets %}
       <div id="widget-{{ widget.idx }}" class="row"></div>
       {% endfor %}
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 8914ab6..1e917ed 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -58,8 +58,6 @@ class WidgetTest(unittest.TestCase):
                 hub.last_updated = datetime.utcnow() - timedelta(days=200)
 
             hubs.app.session.add(hub)
-            widget = hubs.models.Widget(plugin='cobwebs', index=10)
-            hub.widgets.append(widget)
             widget = hubs.models.Widget(plugin='meetings', index=11,
                                         _config=json.dumps({'calendar': team}))
             hub.widgets.append(widget)
diff --git a/hubs/tests/test_widgets/test_cobwebs.py b/hubs/tests/test_widgets/test_cobwebs.py
deleted file mode 100644
index 96f58f4..0000000
--- a/hubs/tests/test_widgets/test_cobwebs.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import json
-
-import hubs.tests.test_widgets
-
-
-class TestCobwebs(hubs.tests.test_widgets.WidgetTest):
-    plugin = 'cobwebs'  # The name in hubs.widgets.registry
-
-    def test_data_old(self):
-        widget = self.widget_instance('old', self.plugin)
-        response = self.app.get('/old/%i/json/' % widget.idx)
-        assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
-        del data['data']['widget_url']  # changes oddly, so don't test
-        self.assertDictEqual(data['data'], {
-            u'days': 100,
-            u'old': True,
-            u'archived': False,
-            u'icon': u'/static/img/cobweb.png',
-            u'source_url': u'/source/cobwebs/',
-            u'then': '3 months ago',
-        })
-
-    def test_data_young(self):
-        widget = self.widget_instance('infra', self.plugin)
-        response = self.app.get('/infra/%i/json/' % widget.idx)
-        assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
-        del data['data']['widget_url']  # changes oddly, so don't test
-        self.assertDictEqual(data['data'], {
-            u'days': 0,
-            u'old': False,
-            u'archived': False,
-            u'icon': u'/static/img/cobweb.png',
-            u'source_url': u'/source/cobwebs/',
-            u'then': u'just now',
-        })
diff --git a/hubs/tests/test_widgets/test_linechart.py b/hubs/tests/test_widgets/test_linechart.py
deleted file mode 100644
index 5bbfd5c..0000000
--- a/hubs/tests/test_widgets/test_linechart.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import json
-
-import hubs.tests.test_widgets
-
-
-class TestLinechart(hubs.tests.test_widgets.WidgetTest):
-    plugin = 'linechart'
-
-    def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json/' % widget.idx)
-        assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
-        datagrepper = 'https://apps.fedoraproject.org/datagrepper'
-        assert data['data']['url'].startswith(datagrepper)
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 0274255..90656fd 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -12,6 +12,12 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/%s/%i/json/' % (team, widget.idx))
         assert response.status_code == 200, response.status_code
         data = json.loads(response.data)
-        meetings = data['data']['meetings']["%s meeting" % team]
-        assert len(meetings) == 15, len(meetings)
-        assert team in meetings[0]['meeting_name']
+        meeting = data['data']['meetings']["%s meeting" % team]
+        assert team in meeting['meeting_name']
+
+    def test_render_simple(self):
+        team = 'i18n'
+        widget = self.widget_instance(team, self.plugin)
+        response = self.app.get('/%s/%i/' % (team, widget.idx))
+        assert response.status_code == 200, response.status_code
+        assert 'The i18n meeting is in' in response.data, response.data
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index cc7007c..551876a 100755
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -8,7 +8,6 @@ from hubs.widgets import linechart
 from hubs.widgets import fedmsgstats
 from hubs.widgets import feed
 from hubs.widgets import subscriptions
-from hubs.widgets import cobwebs
 from hubs.widgets import meetings
 from hubs.widgets import pagure_pr
 from hubs.widgets import github_pr
@@ -32,7 +31,6 @@ registry = {
     'fedmsgstats': fedmsgstats,
     'feed': feed,
     'subscriptions': subscriptions,
-    'cobwebs': cobwebs,
     'meetings': meetings,
     'pagure_pr': pagure_pr,
     'github_pr': github_pr,
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index f1f84cb..dc7b229 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -57,9 +57,9 @@ def AGPLv3(name):
 def smartcache(func):
     @wraps(func)
     def inner(session, widget, *args, **kwargs):
-        key = cache_key_generator(widget, args, kwargs)
+        key = cache_key_generator(widget, *args, **kwargs)
         creator = lambda: func(session, widget, *args, **kwargs)
-        log.debug("Accessing cache key %s", key)
+        #log.debug("Accessing cache key %s", key)
         return cache.get_or_create(key, creator)
 
     return inner
@@ -77,7 +77,7 @@ def invalidate_cache(widget, *args, **kwargs):
     cache.delete(key)
 
 
-def cache_key_generator(widget, args, kwargs):
+def cache_key_generator(widget, *args, **kwargs):
     return "|".join([
         str(widget.idx),
         json.dumps(args),
diff --git a/hubs/widgets/cobwebs.py b/hubs/widgets/cobwebs.py
deleted file mode 100755
index f03aa86..0000000
--- a/hubs/widgets/cobwebs.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from hubs.hinting import hint, prefixed as _
-
-import arrow
-import datetime
-
-from hubs.widgets import templating
-from hubs.widgets.chrome import panel
-klass_switcher = lambda data: 'panel-danger' if data['archived'] else 'panel-info'
-chrome = panel(None, key='old', klass=klass_switcher)
-template = templating.environment.get_template('templates/cobwebs.html')
-
-
-def data(session, widget):
-    days = widget.hub.days_idle
-    archived = widget.hub.archived
-    old = days > 31 or archived
-    then = datetime.datetime.utcnow() - datetime.timedelta(days=days)
-    then = arrow.get(then).humanize()
-    import flask
-    if archived:
-        icon = flask.url_for('static', filename='img/archived.png')
-    else:
-        icon = flask.url_for('static', filename='img/cobweb.png')
-    return dict(old=old, days=days, then=then, icon=icon, archived=archived)
-
-
-#@hint(topics=[_('hubs.widget.update')])
-def should_invalidate(message, session, widget):
-    # TODO -- this one is going to be to be reorganized, since there's no event
-    # that causes this one to flip.
-    # We could add a hack that forces the deletion of this key when other
-    # widgets on the same hub are updated...  but that would be very special.
-    raise NotImplementedError()
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 8ae603f..de793f5 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 
 from hubs.hinting import hint
-from hubs.widgets.base import argument
+from hubs.widgets.base import argument, cache
 from hubs.widgets import templating
 
 import fmn.lib
@@ -61,7 +61,6 @@ def apply_markup(match):
 
     return markup
 
-
 @argument(name="username",
           default=None,
           validator=validators.username,
@@ -71,15 +70,11 @@ def apply_markup(match):
           validator=validators.fmn_context,
           help="A FMN context.")
 def data(session, widget, username, fmn_context):
-    openid = '%s.id.fedoraproject.org' % username
-    url = '/'.join([fmn_url, 'api', openid, fmn_context])
-    log.info("Getting FMN preferences from %s" % url)
-    response = requests.get(url)
     messages = []
     matches = []
-    if response.status_code == 200:
-        preference = response.json()
-        preference = rehydrate_preferences(preference)
+    preference = get_remote_preference(username, fmn_context)
+    if preference:
+        preference = rehydrate_preference(preference)
 
         # The smaller we make this, the faster it is.
         delta = datetime.timedelta(days=365)
@@ -110,7 +105,7 @@ def data(session, widget, username, fmn_context):
             if recipients:
                 matches.append(original)
     else:
-        log.warn("You don't have any preferences. \n Url=%s" % url)
+        log.warn("You don't have any preferences.")
 
     # TODO - sort messages and remove duplicates
 
@@ -141,14 +136,34 @@ def data(session, widget, username, fmn_context):
     )
 
 
-@hint()
+@hint(ubiquitous=True)
 def should_invalidate(message, session, widget):
-    # only if a new message would match the FMN filters would this be
-    # invalidated... but that is as expensive as being FMN ourselves.
-    raise NotImplementedError
+    username = widget.config['username']
+    fmn_context = widget.config['fmn_context']
+    preference = get_remote_preference(username, fmn_context)
+    if not preference:
+        return False
+    preference = rehydrate_preference(preference)
+    recipients = fmn.lib.recipients([preference], message, paths, config)
+    return bool(recipients)
+
+
+# TODO -- this cache value needs its own FMN-based invalidator...
+@cache.cache_on_arguments()
+def get_remote_preference(username, fmn_context):
+    openid = '%s.id.fedoraproject.org' % username
+    url = '/'.join([fmn_url, 'api', openid, fmn_context])
+    log.info("Getting FMN preference from %s" % url)
+    response = requests.get(url)
+    if bool(response):
+        return response.json()
+    else:
+        # Some people have no FMN preferences, but when they do get some.. then
+        # we'll receive the fedmsg event about it and bust this cache value.
+        return None
 
 
-def rehydrate_preferences(preference):
+def rehydrate_preference(preference):
     for fltr in preference['filters']:
         fltr['rules'] = [munch.Munch(r) for r in fltr['rules']]
         for rule in fltr['rules']:
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 37c11ee..87edcb8 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -1,4 +1,4 @@
-#from hubs.hinting import hint, prefixed as _
+from hubs.hinting import hint
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
@@ -6,6 +6,8 @@ from hubs.widgets import templating
 from hubs import validators
 from hubs import utils
 
+import hubs.models
+
 import arrow
 import collections
 import datetime
@@ -23,30 +25,34 @@ def next_meeting(meetings):
                             meeting['meeting_time_stop'])
         stop_dt = datetime.datetime.strptime(stop_string, "%Y-%m-%d %H:%M:%S")
 
-        if now < start_dt:
-            meeting['human_time'] = arrow.get(start_dt).humanize()
-            meeting['start_date'] = start_dt.strftime('%b %d')
-            meeting['stop_date'] = stop_dt.strftime('%b %d')
-            meeting['display_time'] = True
-            meeting['display_duration'] = False
-            # Just UTC for now until we do this on the client and can access
-            # their local with moment.js.
-            meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
-            meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
-            meeting['location'] = meeting['meeting_location']
-            if '@' in meeting['location']:
-                meeting['location'] = '#' + meeting['location'].split('@')[0]
-            if stop_dt - start_dt >= datetime.timedelta(hours=24) :
-                meeting['display_time'] = False
-                if stop_dt - start_dt > datetime.timedelta(hours=24) :
-                    meeting['display_duration'] = True
-            return meeting
+        # Loop over them until we find a good one.
+        # Meetings before now are no good.  We want the first one after now.
+        if start_dt < now:
+            continue
+
+        meeting['start_dt'] = start_dt
+        meeting['start_date'] = start_dt.strftime('%b %d')
+        meeting['stop_date'] = stop_dt.strftime('%b %d')
+        meeting['display_time'] = True
+        meeting['display_duration'] = False
+        # Just UTC for now until we do this on the client and can access
+        # their local with moment.js.
+        meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
+        meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
+        meeting['location'] = meeting['meeting_location']
+        if '@' in meeting['location']:
+            meeting['location'] = '#' + meeting['location'].split('@')[0]
+        if stop_dt - start_dt >= datetime.timedelta(hours=24) :
+            meeting['display_time'] = False
+            if stop_dt - start_dt > datetime.timedelta(hours=24) :
+                meeting['display_duration'] = True
+        return meeting
 
     return None
 
 
 chrome = panel('Reminders', key='meetings')
-templating.environment.filters['next_meeting'] = next_meeting
+templating.environment.filters['humanize'] = lambda d: arrow.get(d).humanize()
 template = templating.environment.get_template('templates/meetings.html')
 
 
@@ -59,24 +65,36 @@ def data(session, widget, calendar):
     url = base % calendar
     response = requests.get(url).json()
 
-    meetings = collections.defaultdict(list)
+    tmp = collections.defaultdict(list)
     for meeting in response['meetings']:
         meeting['meeting_information_html'] = utils.markup(
             meeting['meeting_information'])
-        meetings[meeting['meeting_name']].append(meeting)
+        tmp[meeting['meeting_name']].append(meeting)
 
-    return dict(meetings=dict(meetings))
+    meetings = {}
+    for title, items in tmp.items():
+        selected = next_meeting(items)
+        if not selected:
+            continue
+        meetings[title] = selected
 
+    return dict(meetings=meetings)
 
+
+@hint(ubiquitous=True)
 def should_invalidate(message, session, widget):
-    # TODO -- we have a hard problem here.
-    # There is no event which should invalidate this widget...
-    # but we do need to expire ourselves after the date of the meeting we
-    # cached has passed.
-    # Perhaps we should expand the should_invalidate API to return a tuple:
-    #  - True/False if we should or shouldn't invalidate.
-    #  - an expiry in seconds where -1 is default and means "never expire"
-    # with that.. we could have this function return the timestamp of the
-    # meeting in seconds.. such that once it has passed, our cache will free
-    # up.
-    raise NotImplementedError()
+
+    # TODO -- first, if this is a fedocal widget, we need to just invalidate
+    # ourselves right away.
+
+    # second, check our old cache value and see if any of our meetings have
+    # passed by in time.
+    old_data = data(session, widget, **widget.config)
+    meetings = old_data['meetings']
+    now = datetime.datetime.utcnow()
+    for title, meeting in meetings.items():
+        assert type(meeting['start_dt']) == type(now)
+        if meeting['start_dt'] < now:
+            return True
+
+    return False
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 7f329cf..3b784e3 100755
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -36,7 +36,7 @@ def data(session, widget):
     )
 
 
-@hint(topics=_('hubs.hub.update'))
+@hint(topics=[_('hubs.hub.update')])
 def should_invalidate(message, session, widget):
     if message['topic'].endswith('hubs.hub.update'):
         if message['msg']['hub']['name'] == widget.hub.name:
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 6d7e52f..6576516 100755
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -1,4 +1,4 @@
-# from hubs.hinting import hint, prefixed as _
+from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
@@ -9,6 +9,9 @@ import hubs.models
 
 from fedmsg.meta.base import BaseConglomerator as BC
 
+import fedmsg.config
+fm_config = fedmsg.config.load_config()
+
 import flask
 
 chrome = panel('Hubs', key='associations')
@@ -47,5 +50,8 @@ def manage_subscriptions(items):
     ]
 
 
+@hint(topics=[_('hubs.associate')])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError()
+    username = widget.config['username']
+    users = fedmsg.meta.msg2usernames(message, **fm_config)
+    return username in users
diff --git a/hubs/widgets/templates/cobwebs.html b/hubs/widgets/templates/cobwebs.html
deleted file mode 100644
index d4b2e7b..0000000
--- a/hubs/widgets/templates/cobwebs.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% if old %}
-<ul class="media-list">
-    <li class="media">
-        <div class="media-left">
-            <img class="media-object square-32" src="{{icon}}"/>
-        </div>
-        <div class="media-body">
-        {% if archived %}
-            This hub has been archived and locked.
-        {% else %}
-            Cobweb alert!  This hub was last active {{then}}.
-        {% endif %}
-        </div>
-    </li>
-</ul>
-{% endif %}
diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index f41af8b..6965c5f 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -1,10 +1,8 @@
 {% if meetings %}
-{% for title, items in meetings.items() %}
-{% set next = items | next_meeting %}
-{% if next %}
+{% for title, next in meetings.items() %}
 <div class="meeting">
     <div class="row">
-        <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.human_time }}</h5>
+        <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.start_dt | humanize }}</h5>
     </div>
     <div class="row">
         <div class="col-md-4 meeting-date">
@@ -32,9 +30,6 @@
         </div>
     </div>
 </div>
-{% endif %}
-{% if meetings | length > 1 %}
-<hr>
-{% endif %}
+{% if meetings | length > 1 %} <hr> {% endif %}
 {% endfor %}
 {% endif %}
diff --git a/populate.py b/populate.py
index 9f1816c..5e89881 100755
--- a/populate.py
+++ b/populate.py
@@ -48,8 +48,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "<p>The Fedora I18N project works on internationalization (i18n) to support the localization (l10n) of Fedora in many languages. Translation of Fedora software and documentation are handled by the Fedora L10N project.</p> <p>The goals of the Project are to:</p> <ul><li>Develop, package, and maintain applications like input methods for different languages</li> <li>Improve applications and utilities to support and process different languages</li> <li>Quality-assure that existing applications meet i18n standards</li> <li>Support the infrastructure of the Fedora Localization Project</li></ul>",
@@ -93,8 +91,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "Bringing more heat and light to Fedora, so you don't have to choose between 'building things' and 'building communities that build things.'",
@@ -140,8 +136,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "The Fedora Marketing Team develops and executes marketing strategies to promote the usage and support of Fedora worldwide. Through the development of processes and content, this project aims to support the efforts of other Fedora projects to spread Fedora and to provide a central repository of ideas and information that can be used to deliver Fedora to new audiences. We work closely with the Fedora Ambassadors who spread the word about Fedora at events and allow the Fedora Project to interact directly with its existing and prospective users. ",
@@ -188,8 +182,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
                             _config=json.dumps({
                                 'text': "The Design Team is the design group of the Fedora project. Our interests are not only in creating graphics for use by the Fedora community, but also in advocating the use of the creative tools that are a part of Fedora.",
@@ -237,8 +229,6 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='cobwebs', index=0, left=True)
-hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='sticky', index=2, left=True,
                             _config=json.dumps({
                                 'text': "The Infrastructure Team consists of dedicated volunteers and professionals managing the servers, building the tools and utilities, and creating new applications to make Fedora development a smoother process. We're located all over the globe and communicate primarily by IRC and e-mail. ",

From b5883a9e4561a6a691b1253a613c5070796e9b7d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 16:49:16 +0000
Subject: [PATCH 367/1001] Try splitting out cache work into its own process, mediated by redis.


---

diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index e85072e..c2f68a1 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -4,6 +4,9 @@ config = {
     # Production ready.
     'hubs.sqlalchemy.uri': 'sqlite:////var/tmp/hubs.db',
 
+    # For communication between fedmsg-hub and the cache worker farm
+    'hubs.redis.work-queue-name': 'fedora-hubs-work-queue',
+
     'endpoints': {
         "fedora-infrastructure": [
             "tcp://hub.fedoraproject.org:9940",
diff --git a/hubs/consumer.py b/hubs/consumer.py
index c6e0d7b..ef4b6e2 100755
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -1,8 +1,8 @@
 # The fedora hubs backend daemon
 
 import collections
+import json
 import threading
-import time
 
 import munch
 
@@ -10,12 +10,13 @@ import datanommer.models
 import fedmsg.consumers
 import fedmsg.meta
 
+import retask.task
+import retask.queue
+
 import hubs.app
 import hubs.models
 import hubs.widgets
 
-from hubs.widgets.base import invalidate_cache
-
 import logging
 log = logging.getLogger("hubs")
 
@@ -43,10 +44,13 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         super(CacheInvalidatorExtraordinaire, self).__init__(*args, **kwargs)
 
         self.uri = self.hub.config.get('hubs.sqlalchemy.uri', None)
+        self.queue_name = self.hub.config.get('hubs.redis.work-queue-name', None)
         self.junk_suffixes = self.hub.config.get('hubs.junk_suffixes', [])
 
         if not self.uri:
             raise ValueError('hubs.sqlalchemy.uri must be present')
+        if not self.queue_name:
+            raise ValueError('hubs.sqlalchemy.uri must be present')
 
         fedmsg.meta.make_processors(**self.hub.config)
 
@@ -64,6 +68,11 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
     def make_session(self):
         return hubs.models.init(self.uri)
 
+    def make_queue(self):
+        queue = retask.queue.Queue(self.queue_name)
+        queue.connect()
+        return queue
+
     def rebuild_hubs_hint_lookups(self, session):
         self.checks_by_topic = collections.defaultdict(list)
         self.checks_by_category = collections.defaultdict(list)
@@ -105,10 +114,11 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         return self.checks_by_topic and self.checks_by_category
 
     def consume(self, raw_msg):
+        queue = self.make_queue()
         session = self.make_session()
         try:
             with hubs.app.app.app_context():  # so url_for works
-                self.work(session, raw_msg)
+                self.work(session, queue, raw_msg)
             session.commit()  # transaction is committed here
         except:
             session.rollback()  # rolls back the transaction
@@ -116,7 +126,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         finally:
             session.close()
 
-    def work(self, session, raw_msg):
+    def work(self, session, queue, raw_msg):
         topic, msg = raw_msg['topic'], raw_msg['body']
         category = topic.split('.')[3]
         usernames = fedmsg.meta.msg2usernames(msg, **self.hub.config)
@@ -126,7 +136,6 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
                 log.info("Dropping %r", topic)
                 return
 
-        start = time.time()
         log.debug("CacheInvalidatorExtraordinaire received %s %s",
                   msg['msg_id'], msg['topic'])
 
@@ -158,18 +167,10 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         # see if any tell us that we should nuke various data caches.
         for check, widget in checks:
             if check(msg, session, widget):
-                # Get a real widget, because we update last_refreshed on it.
-                widget = hubs.models.Widget.by_idx(session, widget.idx)
-                log.info("! Invalidating cache for %r" % widget)
-                # Invalidate the cache...
-                invalidate_cache(widget, **widget.config)
-                # Rebuild it.
-                log.info("! Rebuilding cache for %r" % widget)
-                widget.module.data(session, widget, **widget.config)
-                # TODO -- fire off an EventSource notice that we updated stuff
-
-        log.debug("Done.  %0.2fs %s %s",
-                  time.time() - start, msg['msg_id'], msg['topic'])
+                task = retask.task.Task(json.dumps({'idx': widget.idx}))
+                log.debug("  Sending %r to workers. (backlog is %r)" % (
+                    task, queue.length))
+                queue.enqueue(task)
 
     def stop(self):
         log.info("Cleaning up CacheInvalidatorExtraordinaire.")
diff --git a/hubs/worker.py b/hubs/worker.py
new file mode 100755
index 0000000..78807dc
--- /dev/null
+++ b/hubs/worker.py
@@ -0,0 +1,68 @@
+import hubs.app
+import hubs.models
+
+import hubs.widgets.base
+
+import fedmsg.config
+config = fedmsg.config.load_config()
+
+import retask.queue
+
+import json
+import sys
+import logging
+import logging.config
+log = logging.getLogger('hubs.worker')
+
+
+def work(session, widget_idx):
+    # Get a real widget, because we update last_refreshed on it.
+    widget = hubs.models.Widget.by_idx(session, widget_idx)
+    log.info("! Invalidating cache for %r" % widget)
+    # Invalidate the cache...
+    hubs.widgets.base.invalidate_cache(widget, **widget.config)
+    # Rebuild it.
+    log.info("! Rebuilding cache for %r" % widget)
+    widget.module.data(session, widget, **widget.config)
+    # TODO -- fire off an EventSource notice that we updated stuff
+
+def handle(idx):
+    session = hubs.models.init(config['hubs.sqlalchemy.uri'])
+
+    try:
+        with hubs.app.app.app_context():  # so url_for works
+            work(session, idx)
+        session.commit()  # transaction is committed here
+    except:
+        session.rollback()  # rolls back the transaction
+        raise
+    finally:
+        session.close()
+
+def main(args):
+
+    # TODO -- manage signal handling for clean shutdown
+
+    logging.config.dictConfig(config['logging'])
+    logging.basicConfig()
+
+    name = config['hubs.redis.work-queue-name']
+    log.info("Worker starting, connecting to retask queue %r." % name)
+    queue = retask.queue.Queue(name)
+    queue.connect()
+
+    try:
+        log.info("Entering work loop.")
+        while True:
+            task = queue.wait()  # Wait forever...  timeout is optional.
+            log.info("Working on %r" % task)
+            item = json.loads(task.data)
+            idx = item['idx']  # A widget ID
+            handle(idx)
+    except KeyboardInterrupt:
+        pass
+
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
diff --git a/requirements.txt b/requirements.txt
index 6c101b5..c3666e6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,3 +18,4 @@ pkgwat.api
 six
 pygments
 pygments-markdown-lexer
+retask

From 23f135711bb0a8318ad8177e3935256659b5671f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 17:27:59 +0000
Subject: [PATCH 368/1001] Resuscitate missing jinja filter.


---

diff --git a/hubs/app.py b/hubs/app.py
index 851e850..47099c4 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,3 +1,4 @@
+import datetime
 import functools
 import logging
 import os
@@ -17,10 +18,12 @@ from hubs.utils import username2avatar
 
 app = flask.Flask(__name__)
 
-# Register a global filter, useful for displaying user images
+# Register some useful global filters.
+def days_since(then):
+    return (datetime.datetime.utcnow() - then).days
+app.template_filter('days_since')(days_since)
 app.template_filter('avatar')(hubs.widgets.base.avatar)
 
-
 logging.basicConfig()
 
 

From 57fc443b58f1cf0ed6a77f41975fb9cf0d6d4c3f Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 17:28:15 +0000
Subject: [PATCH 369/1001] Only set SERVER_NAME artificially for backend components.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index ef4b6e2..48c64f3 100755
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -63,6 +63,9 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
 
         datanommer.models.init(self.hub.config['datanommer.sqlalchemy.uri'])
 
+        # XXX - for flask.url_for to work
+        hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
+
         log.debug("CacheInvalidatorExtraordinaire initialized")
 
     def make_session(self):
diff --git a/hubs/default_config.py b/hubs/default_config.py
index a452867..a21f138 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -6,5 +6,3 @@ PROMOTED_GROUPS = [
 ]
 
 HUB_OF_THE_MONTH = 'commops'
-
-SERVER_NAME = '0.0.0.0:5000'
diff --git a/hubs/worker.py b/hubs/worker.py
index 78807dc..bec32b2 100755
--- a/hubs/worker.py
+++ b/hubs/worker.py
@@ -46,6 +46,9 @@ def main(args):
     logging.config.dictConfig(config['logging'])
     logging.basicConfig()
 
+    # XXX - for flask.url_for to work
+    hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
+
     name = config['hubs.redis.work-queue-name']
     log.info("Worker starting, connecting to retask queue %r." % name)
     queue = retask.queue.Queue(name)

From ee5a3ef46981c93126f93a2cbbcdcb48fcbdce8b Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 17:28:35 +0000
Subject: [PATCH 370/1001] Pass msg_id on to redis and the cache workers, just for logging's sake.


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index 48c64f3..bde01c7 100755
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -160,17 +160,16 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
             self.ubiquitous_checks,
         ], [])
 
-        statement = "Found %i checks to try for this message" % len(checks)
-        if checks:
-            log.info(statement)
-        else:
-            log.debug(statement)
+        log.debug("Found %i checks to try for this message" % len(checks))
 
         # Then, with that hopefully smaller list of checks, try them all and
         # see if any tell us that we should nuke various data caches.
         for check, widget in checks:
             if check(msg, session, widget):
-                task = retask.task.Task(json.dumps({'idx': widget.idx}))
+                task = retask.task.Task(json.dumps({
+                    'idx': widget.idx,
+                    'msg_id': msg['msg_id'],
+                }))
                 log.debug("  Sending %r to workers. (backlog is %r)" % (
                     task, queue.length))
                 queue.enqueue(task)

From 1a9e5aa236a1a9259dc504f339b4816ae02cfe48 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 17:44:53 +0000
Subject: [PATCH 371/1001] Check explicitly for dogpile.cache.api.NoValue.


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index dc7b229..e784ef1 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -68,7 +68,8 @@ def smartcache(func):
 def invalidate_cache(widget, *args, **kwargs):
     key = cache_key_generator(widget, *args, **kwargs)
 
-    if not cache.get(key, ignore_expiration=True):
+    value = cache.get(key, ignore_expiration=True)
+    if isinstance(value, dogpile.cache.api.NoValue):
         log.debug("Not deleting cache key %s.  It is absent.", key)
         return
 

From 452a58e4aabfad1bf2fe37c01b7b5324aa193b9d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 17:45:03 +0000
Subject: [PATCH 372/1001] Add a handy cache-coverage sanity check script.


---

diff --git a/cache-coverage.py b/cache-coverage.py
new file mode 100755
index 0000000..8aad708
--- /dev/null
+++ b/cache-coverage.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+""" cache coverage checker.
+
+Runs through all possible cache keys and checks if there is a corresponding
+value already cached for it.
+
+Useful as a sanity check during development.
+
+Could make a good nagios check one day.  If the cache coverage is below 50%,
+then the site will be very slow.  We should run some sort of script that
+forcibly re-warms the cache.
+
+Authors:    Ralph Bean <rbean@redhat.com>
+"""
+
+import sys
+import dogpile.cache
+
+import hubs.widgets.base
+import hubs.models
+
+import fedmsg.config
+
+config = fedmsg.config.load_config()
+
+empty, full = 0, 0
+session = hubs.models.init(config['hubs.sqlalchemy.uri'])
+for widget in session.query(hubs.models.Widget).all():
+    key = hubs.widgets.base.cache_key_generator(widget, **widget.config)
+    result = hubs.widgets.base.cache.get(key, ignore_expiration=True)
+    if isinstance(result, dogpile.cache.api.NoValue):
+        empty += 1
+    else:
+        full += 1
+    sys.stdout.write('.')
+    sys.stdout.flush()
+sys.stdout.write('\n')
+sys.stdout.flush()
+
+total = empty + full
+print full, "cache values found. ", empty, "are missing."
+print full / float(total) * 100, "percent cache coverage."
+

From 364db51a33ba323cf7505ad138671e104d8cb975 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 17:48:16 +0000
Subject: [PATCH 373/1001] Useful info in this log statement.


---

diff --git a/hubs/worker.py b/hubs/worker.py
index bec32b2..ae38f00 100755
--- a/hubs/worker.py
+++ b/hubs/worker.py
@@ -58,7 +58,7 @@ def main(args):
         log.info("Entering work loop.")
         while True:
             task = queue.wait()  # Wait forever...  timeout is optional.
-            log.info("Working on %r" % task)
+            log.info("Working on %r.  (backlog is %r)" % (task, queue.length))
             item = json.loads(task.data)
             idx = item['idx']  # A widget ID
             handle(idx)

From 5652a1360c676c891b3d92c826d10b354ccdbc5d Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 18:00:25 +0000
Subject: [PATCH 374/1001] Note when the worker is done with a task.


---

diff --git a/hubs/worker.py b/hubs/worker.py
index ae38f00..fa63856 100755
--- a/hubs/worker.py
+++ b/hubs/worker.py
@@ -62,6 +62,7 @@ def main(args):
             item = json.loads(task.data)
             idx = item['idx']  # A widget ID
             handle(idx)
+            log.debug("  Done.")
     except KeyboardInterrupt:
         pass
 

From 90a70ac1023ff71c59a28e9160bf30334e0afc55 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 18:13:38 +0000
Subject: [PATCH 375/1001] Merge branch 'feature/redis-workload' into develop


---

diff --git a/cache-coverage.py b/cache-coverage.py
new file mode 100755
index 0000000..8aad708
--- /dev/null
+++ b/cache-coverage.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+""" cache coverage checker.
+
+Runs through all possible cache keys and checks if there is a corresponding
+value already cached for it.
+
+Useful as a sanity check during development.
+
+Could make a good nagios check one day.  If the cache coverage is below 50%,
+then the site will be very slow.  We should run some sort of script that
+forcibly re-warms the cache.
+
+Authors:    Ralph Bean <rbean@redhat.com>
+"""
+
+import sys
+import dogpile.cache
+
+import hubs.widgets.base
+import hubs.models
+
+import fedmsg.config
+
+config = fedmsg.config.load_config()
+
+empty, full = 0, 0
+session = hubs.models.init(config['hubs.sqlalchemy.uri'])
+for widget in session.query(hubs.models.Widget).all():
+    key = hubs.widgets.base.cache_key_generator(widget, **widget.config)
+    result = hubs.widgets.base.cache.get(key, ignore_expiration=True)
+    if isinstance(result, dogpile.cache.api.NoValue):
+        empty += 1
+    else:
+        full += 1
+    sys.stdout.write('.')
+    sys.stdout.flush()
+sys.stdout.write('\n')
+sys.stdout.flush()
+
+total = empty + full
+print full, "cache values found. ", empty, "are missing."
+print full / float(total) * 100, "percent cache coverage."
+
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index e85072e..c2f68a1 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -4,6 +4,9 @@ config = {
     # Production ready.
     'hubs.sqlalchemy.uri': 'sqlite:////var/tmp/hubs.db',
 
+    # For communication between fedmsg-hub and the cache worker farm
+    'hubs.redis.work-queue-name': 'fedora-hubs-work-queue',
+
     'endpoints': {
         "fedora-infrastructure": [
             "tcp://hub.fedoraproject.org:9940",
diff --git a/hubs/app.py b/hubs/app.py
index 851e850..47099c4 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,3 +1,4 @@
+import datetime
 import functools
 import logging
 import os
@@ -17,10 +18,12 @@ from hubs.utils import username2avatar
 
 app = flask.Flask(__name__)
 
-# Register a global filter, useful for displaying user images
+# Register some useful global filters.
+def days_since(then):
+    return (datetime.datetime.utcnow() - then).days
+app.template_filter('days_since')(days_since)
 app.template_filter('avatar')(hubs.widgets.base.avatar)
 
-
 logging.basicConfig()
 
 
diff --git a/hubs/consumer.py b/hubs/consumer.py
index c6e0d7b..bde01c7 100755
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -1,8 +1,8 @@
 # The fedora hubs backend daemon
 
 import collections
+import json
 import threading
-import time
 
 import munch
 
@@ -10,12 +10,13 @@ import datanommer.models
 import fedmsg.consumers
 import fedmsg.meta
 
+import retask.task
+import retask.queue
+
 import hubs.app
 import hubs.models
 import hubs.widgets
 
-from hubs.widgets.base import invalidate_cache
-
 import logging
 log = logging.getLogger("hubs")
 
@@ -43,10 +44,13 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         super(CacheInvalidatorExtraordinaire, self).__init__(*args, **kwargs)
 
         self.uri = self.hub.config.get('hubs.sqlalchemy.uri', None)
+        self.queue_name = self.hub.config.get('hubs.redis.work-queue-name', None)
         self.junk_suffixes = self.hub.config.get('hubs.junk_suffixes', [])
 
         if not self.uri:
             raise ValueError('hubs.sqlalchemy.uri must be present')
+        if not self.queue_name:
+            raise ValueError('hubs.sqlalchemy.uri must be present')
 
         fedmsg.meta.make_processors(**self.hub.config)
 
@@ -59,11 +63,19 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
 
         datanommer.models.init(self.hub.config['datanommer.sqlalchemy.uri'])
 
+        # XXX - for flask.url_for to work
+        hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
+
         log.debug("CacheInvalidatorExtraordinaire initialized")
 
     def make_session(self):
         return hubs.models.init(self.uri)
 
+    def make_queue(self):
+        queue = retask.queue.Queue(self.queue_name)
+        queue.connect()
+        return queue
+
     def rebuild_hubs_hint_lookups(self, session):
         self.checks_by_topic = collections.defaultdict(list)
         self.checks_by_category = collections.defaultdict(list)
@@ -105,10 +117,11 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         return self.checks_by_topic and self.checks_by_category
 
     def consume(self, raw_msg):
+        queue = self.make_queue()
         session = self.make_session()
         try:
             with hubs.app.app.app_context():  # so url_for works
-                self.work(session, raw_msg)
+                self.work(session, queue, raw_msg)
             session.commit()  # transaction is committed here
         except:
             session.rollback()  # rolls back the transaction
@@ -116,7 +129,7 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
         finally:
             session.close()
 
-    def work(self, session, raw_msg):
+    def work(self, session, queue, raw_msg):
         topic, msg = raw_msg['topic'], raw_msg['body']
         category = topic.split('.')[3]
         usernames = fedmsg.meta.msg2usernames(msg, **self.hub.config)
@@ -126,7 +139,6 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
                 log.info("Dropping %r", topic)
                 return
 
-        start = time.time()
         log.debug("CacheInvalidatorExtraordinaire received %s %s",
                   msg['msg_id'], msg['topic'])
 
@@ -148,28 +160,19 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
             self.ubiquitous_checks,
         ], [])
 
-        statement = "Found %i checks to try for this message" % len(checks)
-        if checks:
-            log.info(statement)
-        else:
-            log.debug(statement)
+        log.debug("Found %i checks to try for this message" % len(checks))
 
         # Then, with that hopefully smaller list of checks, try them all and
         # see if any tell us that we should nuke various data caches.
         for check, widget in checks:
             if check(msg, session, widget):
-                # Get a real widget, because we update last_refreshed on it.
-                widget = hubs.models.Widget.by_idx(session, widget.idx)
-                log.info("! Invalidating cache for %r" % widget)
-                # Invalidate the cache...
-                invalidate_cache(widget, **widget.config)
-                # Rebuild it.
-                log.info("! Rebuilding cache for %r" % widget)
-                widget.module.data(session, widget, **widget.config)
-                # TODO -- fire off an EventSource notice that we updated stuff
-
-        log.debug("Done.  %0.2fs %s %s",
-                  time.time() - start, msg['msg_id'], msg['topic'])
+                task = retask.task.Task(json.dumps({
+                    'idx': widget.idx,
+                    'msg_id': msg['msg_id'],
+                }))
+                log.debug("  Sending %r to workers. (backlog is %r)" % (
+                    task, queue.length))
+                queue.enqueue(task)
 
     def stop(self):
         log.info("Cleaning up CacheInvalidatorExtraordinaire.")
diff --git a/hubs/default_config.py b/hubs/default_config.py
index a452867..a21f138 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -6,5 +6,3 @@ PROMOTED_GROUPS = [
 ]
 
 HUB_OF_THE_MONTH = 'commops'
-
-SERVER_NAME = '0.0.0.0:5000'
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index dc7b229..e784ef1 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -68,7 +68,8 @@ def smartcache(func):
 def invalidate_cache(widget, *args, **kwargs):
     key = cache_key_generator(widget, *args, **kwargs)
 
-    if not cache.get(key, ignore_expiration=True):
+    value = cache.get(key, ignore_expiration=True)
+    if isinstance(value, dogpile.cache.api.NoValue):
         log.debug("Not deleting cache key %s.  It is absent.", key)
         return
 
diff --git a/hubs/worker.py b/hubs/worker.py
new file mode 100755
index 0000000..fa63856
--- /dev/null
+++ b/hubs/worker.py
@@ -0,0 +1,72 @@
+import hubs.app
+import hubs.models
+
+import hubs.widgets.base
+
+import fedmsg.config
+config = fedmsg.config.load_config()
+
+import retask.queue
+
+import json
+import sys
+import logging
+import logging.config
+log = logging.getLogger('hubs.worker')
+
+
+def work(session, widget_idx):
+    # Get a real widget, because we update last_refreshed on it.
+    widget = hubs.models.Widget.by_idx(session, widget_idx)
+    log.info("! Invalidating cache for %r" % widget)
+    # Invalidate the cache...
+    hubs.widgets.base.invalidate_cache(widget, **widget.config)
+    # Rebuild it.
+    log.info("! Rebuilding cache for %r" % widget)
+    widget.module.data(session, widget, **widget.config)
+    # TODO -- fire off an EventSource notice that we updated stuff
+
+def handle(idx):
+    session = hubs.models.init(config['hubs.sqlalchemy.uri'])
+
+    try:
+        with hubs.app.app.app_context():  # so url_for works
+            work(session, idx)
+        session.commit()  # transaction is committed here
+    except:
+        session.rollback()  # rolls back the transaction
+        raise
+    finally:
+        session.close()
+
+def main(args):
+
+    # TODO -- manage signal handling for clean shutdown
+
+    logging.config.dictConfig(config['logging'])
+    logging.basicConfig()
+
+    # XXX - for flask.url_for to work
+    hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
+
+    name = config['hubs.redis.work-queue-name']
+    log.info("Worker starting, connecting to retask queue %r." % name)
+    queue = retask.queue.Queue(name)
+    queue.connect()
+
+    try:
+        log.info("Entering work loop.")
+        while True:
+            task = queue.wait()  # Wait forever...  timeout is optional.
+            log.info("Working on %r.  (backlog is %r)" % (task, queue.length))
+            item = json.loads(task.data)
+            idx = item['idx']  # A widget ID
+            handle(idx)
+            log.debug("  Done.")
+    except KeyboardInterrupt:
+        pass
+
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
diff --git a/requirements.txt b/requirements.txt
index 6c101b5..c3666e6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,3 +18,4 @@ pkgwat.api
 six
 pygments
 pygments-markdown-lexer
+retask

From d50ee98873cc79c754c01a6274f5c475a761ab2a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 18:14:24 +0000
Subject: [PATCH 376/1001] Mention mailing list in the README.


Fixes #119.

---

diff --git a/README.rst b/README.rst
index 2fcf565..cb7baac 100644
--- a/README.rst
+++ b/README.rst
@@ -3,6 +3,8 @@ Source on Pagure.io
 
 The latest source is not on GitHub, it is on pagure.io.  You can find it at https://pagure.io/fedora-hubs
 
+We have a mailing list here: https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org/
+
 Hacking
 =======
 Install fedora dependencies::

From 4c79f89d71c1193e4f0b1329c08877db04009f56 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 19:07:11 +0000
Subject: [PATCH 377/1001] Another handy health check script.


---

diff --git a/cache-coverage.py b/cache-coverage.py
deleted file mode 100755
index 8aad708..0000000
--- a/cache-coverage.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env python
-""" cache coverage checker.
-
-Runs through all possible cache keys and checks if there is a corresponding
-value already cached for it.
-
-Useful as a sanity check during development.
-
-Could make a good nagios check one day.  If the cache coverage is below 50%,
-then the site will be very slow.  We should run some sort of script that
-forcibly re-warms the cache.
-
-Authors:    Ralph Bean <rbean@redhat.com>
-"""
-
-import sys
-import dogpile.cache
-
-import hubs.widgets.base
-import hubs.models
-
-import fedmsg.config
-
-config = fedmsg.config.load_config()
-
-empty, full = 0, 0
-session = hubs.models.init(config['hubs.sqlalchemy.uri'])
-for widget in session.query(hubs.models.Widget).all():
-    key = hubs.widgets.base.cache_key_generator(widget, **widget.config)
-    result = hubs.widgets.base.cache.get(key, ignore_expiration=True)
-    if isinstance(result, dogpile.cache.api.NoValue):
-        empty += 1
-    else:
-        full += 1
-    sys.stdout.write('.')
-    sys.stdout.flush()
-sys.stdout.write('\n')
-sys.stdout.flush()
-
-total = empty + full
-print full, "cache values found. ", empty, "are missing."
-print full / float(total) * 100, "percent cache coverage."
-
diff --git a/check-cache-coverage.py b/check-cache-coverage.py
new file mode 100755
index 0000000..8aad708
--- /dev/null
+++ b/check-cache-coverage.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+""" cache coverage checker.
+
+Runs through all possible cache keys and checks if there is a corresponding
+value already cached for it.
+
+Useful as a sanity check during development.
+
+Could make a good nagios check one day.  If the cache coverage is below 50%,
+then the site will be very slow.  We should run some sort of script that
+forcibly re-warms the cache.
+
+Authors:    Ralph Bean <rbean@redhat.com>
+"""
+
+import sys
+import dogpile.cache
+
+import hubs.widgets.base
+import hubs.models
+
+import fedmsg.config
+
+config = fedmsg.config.load_config()
+
+empty, full = 0, 0
+session = hubs.models.init(config['hubs.sqlalchemy.uri'])
+for widget in session.query(hubs.models.Widget).all():
+    key = hubs.widgets.base.cache_key_generator(widget, **widget.config)
+    result = hubs.widgets.base.cache.get(key, ignore_expiration=True)
+    if isinstance(result, dogpile.cache.api.NoValue):
+        empty += 1
+    else:
+        full += 1
+    sys.stdout.write('.')
+    sys.stdout.flush()
+sys.stdout.write('\n')
+sys.stdout.flush()
+
+total = empty + full
+print full, "cache values found. ", empty, "are missing."
+print full / float(total) * 100, "percent cache coverage."
+
diff --git a/check-queue-length.py b/check-queue-length.py
new file mode 100755
index 0000000..7121257
--- /dev/null
+++ b/check-queue-length.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+""" redis queue length checker.
+
+Simply prints out the length of the redis queue for our cache workers.
+
+Useful as a sanity check during development.
+
+Could make a good nagios check one day.  If the queue is going up and up, we
+should alert nagios.  We just need to spin up more cache workers.
+
+We could also graph this in collectd, for fun and profit.
+
+Authors:    Ralph Bean <rbean@redhat.com>
+"""
+
+import fedmsg.config
+config = fedmsg.config.load_config()
+
+import retask
+queue = retask.queue.Queue(config['hubs.redis.work-queue-name'])
+queue.connect()
+
+print 'Cache worker queue length is', queue.length

From c39d8890ce05dbf54f795fbe6cb68016bdf3fab6 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 19:42:03 +0000
Subject: [PATCH 378/1001] Try not to run out of memory when building the mega lookup.


---

diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index c2f68a1..43e4c53 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -40,4 +40,7 @@ config = {
     # Run datanommer locally, just for development.
     'datanommer.enabled': True,
     'datanommer.sqlalchemy.url': 'postgres://postgres:laksjdf@127.0.0.1/datanommer',
+
+    # Only do one of these so we can try to not run out of memory.
+    'moksha.workers_per_consumer': 1,
 }

From b50ac080e65deaf30cce9eb614aaf08258f8fb55 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 30 2016 19:51:38 +0000
Subject: [PATCH 379/1001] Use "or" not "and" here...


---

diff --git a/hubs/consumer.py b/hubs/consumer.py
index bde01c7..137d37f 100755
--- a/hubs/consumer.py
+++ b/hubs/consumer.py
@@ -114,7 +114,12 @@ class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
 
     @property
     def lookup_initialized(self):
-        return self.checks_by_topic and self.checks_by_category
+        return any([
+            self.checks_by_topic,
+            self.checks_by_category,
+            self.checks_by_username,
+            self.ubiquitous_checks,
+        ])
 
     def consume(self, raw_msg):
         queue = self.make_queue()

From 66927b32bbf318c590e4d7ad5b0ca10d62ffca88 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 31 2016 19:35:29 +0000
Subject: [PATCH 380/1001] Add a second tier of workers to the cascade.


---

diff --git a/check-queue-length.py b/check-queue-length.py
index 7121257..4fc7098 100755
--- a/check-queue-length.py
+++ b/check-queue-length.py
@@ -17,7 +17,8 @@ import fedmsg.config
 config = fedmsg.config.load_config()
 
 import retask
-queue = retask.queue.Queue(config['hubs.redis.work-queue-name'])
-queue.connect()
 
-print 'Cache worker queue length is', queue.length
+for item in ['triage', 'work']:
+    queue = retask.queue.Queue(config['hubs.redis.%s-queue-name' % item])
+    queue.connect()
+    print ' (%s) queue length is %i' % (item, queue.length)
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index 43e4c53..1f45487 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -5,8 +5,16 @@ config = {
     'hubs.sqlalchemy.uri': 'sqlite:////var/tmp/hubs.db',
 
     # For communication between fedmsg-hub and the cache worker farm
+    'hubs.redis.triage-queue-name': 'fedora-hubs-triage-queue',
     'hubs.redis.work-queue-name': 'fedora-hubs-work-queue',
 
+    # Junk junk junk.. that we don't care about.  Drop it!
+    'hubs.junk_suffixes': [
+        'buildsys.tag',
+        'buildsys.untag',
+        'buildsys.rpm.sign',
+    ],
+
     'endpoints': {
         "fedora-infrastructure": [
             "tcp://hub.fedoraproject.org:9940",
diff --git a/hubs/backend/consumer.py b/hubs/backend/consumer.py
new file mode 100755
index 0000000..9d73ef1
--- /dev/null
+++ b/hubs/backend/consumer.py
@@ -0,0 +1,34 @@
+# The fedora hubs backend daemon
+
+import fedmsg.consumers
+import fedmsg.meta
+
+import retask.task
+import retask.queue
+
+import logging
+log = logging.getLogger("hubs")
+
+
+class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
+    topic = '*'
+    config_key = 'hubs.consumer.enabled'
+
+    def __init__(self, *args, **kwargs):
+        log.debug("CacheInvalidatorExtraordinaire initializing")
+        super(CacheInvalidatorExtraordinaire, self).__init__(*args, **kwargs)
+
+        self.queue_name = self.hub.config['hubs.redis.triage-queue-name']
+
+        log.debug("CacheInvalidatorExtraordinaire initialized")
+
+    def consume(self, raw_msg):
+        msg = raw_msg['body']
+        queue = retask.queue.Queue(self.queue_name)
+        queue.connect()
+        task = retask.task.Task(fedmsg.encoding.dumps(msg))
+        queue.enqueue(task)
+
+    def stop(self):
+        log.info("Cleaning up CacheInvalidatorExtraordinaire.")
+        super(CacheInvalidatorExtraordinaire, self).stop()
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
new file mode 100755
index 0000000..11c3342
--- /dev/null
+++ b/hubs/backend/worker.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+""" hubs backend worker process.
+
+This is step 3 of the backend cascading pipeline.
+
+consumer -> redis --+-> triage process -+-> redis --+-> worker process
+                    |          .        |           |          .
+                    +-> triage process -+           +-> worker process
+                               .                               .
+                               .                               .
+                               .                               .
+
+We expect to have lots of worker processes running, and that we will add more
+to scale out as our workload, usage of fedora-hubs, and the general bus volume
+all increase over time.
+
+The worker process is a last step in the pipeline.  It pulls tasks off of a
+redis queue fed by the triage worker farm.  For each item, it simply
+invalidates a cache value and then calls the appropriate widget `data()`
+function to rebuild that value.
+
+This isn't implemented yet, but at the end of the day it should *also* notify
+another redis queue so that an EventSource server can update any connected web
+clients with the new content produced here.
+"""
+
+import hubs.app
+import hubs.models
+
+import hubs.widgets.base
+
+import fedmsg.config
+import fedmsg.meta
+config = fedmsg.config.load_config()
+
+import retask.queue
+
+import json
+import sys
+import logging
+import logging.config
+log = logging.getLogger('hubs.backend.worker')
+
+
+def work(session, widget_idx):
+    # Get a real widget, because we update last_refreshed on it.
+    widget = hubs.models.Widget.by_idx(session, widget_idx)
+    log.info("! Invalidating cache for %r" % widget)
+    # Invalidate the cache...
+    hubs.widgets.base.invalidate_cache(widget, **widget.config)
+    # Rebuild it.
+    log.info("! Rebuilding cache for %r" % widget)
+    widget.module.data(session, widget, **widget.config)
+    # TODO -- fire off an EventSource notice that we updated stuff
+
+
+def handle(idx):
+    session = hubs.models.init(config['hubs.sqlalchemy.uri'])
+
+    try:
+        with hubs.app.app.app_context():  # so url_for works
+            work(session, idx)
+        session.commit()  # transaction is committed here
+    except:
+        session.rollback()  # rolls back the transaction
+        raise
+    finally:
+        session.close()
+
+
+def main(args):
+    logging.config.dictConfig(config['logging'])
+    logging.basicConfig()
+
+    fedmsg.meta.make_processors(**config)
+
+    # XXX - for flask.url_for to work
+    hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
+
+    name = config['hubs.redis.work-queue-name']
+    log.info("Worker starting, connecting to retask queue %r." % name)
+    queue = retask.queue.Queue(name)
+    queue.connect()
+
+    try:
+        log.info("Entering work loop.")
+        while True:
+            task = queue.wait()  # Wait forever...  timeout is optional.
+            log.info("Working on %r.  (backlog is %r)" % (task, queue.length))
+            item = json.loads(task.data)
+            idx = item['idx']  # A widget ID
+            handle(idx)
+            log.debug("  Done.")
+    except KeyboardInterrupt:
+        pass
+
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
diff --git a/hubs/consumer.py b/hubs/consumer.py
deleted file mode 100755
index 137d37f..0000000
--- a/hubs/consumer.py
+++ /dev/null
@@ -1,184 +0,0 @@
-# The fedora hubs backend daemon
-
-import collections
-import json
-import threading
-
-import munch
-
-import datanommer.models
-import fedmsg.consumers
-import fedmsg.meta
-
-import retask.task
-import retask.queue
-
-import hubs.app
-import hubs.models
-import hubs.widgets
-
-import logging
-log = logging.getLogger("hubs")
-
-
-def j(widget):
-    """ Shorthand to reduce a sqlalchemy widget to a munch for processing. """
-    return munch.Munch(dict(
-        idx=widget.idx,
-        hub_id=widget.hub_id,
-        hub=munch.Munch(dict(
-            name=widget.hub.name,
-        )),
-        plugin=widget.plugin,
-        config=widget.config,
-        # TODO -- add other things here as we need it
-    ))
-
-
-class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
-    topic = '*'
-    config_key = 'hubs.consumer.enabled'
-
-    def __init__(self, *args, **kwargs):
-        log.debug("CacheInvalidatorExtraordinaire initializing")
-        super(CacheInvalidatorExtraordinaire, self).__init__(*args, **kwargs)
-
-        self.uri = self.hub.config.get('hubs.sqlalchemy.uri', None)
-        self.queue_name = self.hub.config.get('hubs.redis.work-queue-name', None)
-        self.junk_suffixes = self.hub.config.get('hubs.junk_suffixes', [])
-
-        if not self.uri:
-            raise ValueError('hubs.sqlalchemy.uri must be present')
-        if not self.queue_name:
-            raise ValueError('hubs.sqlalchemy.uri must be present')
-
-        fedmsg.meta.make_processors(**self.hub.config)
-
-        self.hint_lookup_lock = threading.Lock()
-        session = self.make_session()
-        with self.hint_lookup_lock:
-            self.rebuild_hubs_hint_lookups(session)
-        session.commit()  # transaction is committed here
-        session.close()
-
-        datanommer.models.init(self.hub.config['datanommer.sqlalchemy.uri'])
-
-        # XXX - for flask.url_for to work
-        hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
-
-        log.debug("CacheInvalidatorExtraordinaire initialized")
-
-    def make_session(self):
-        return hubs.models.init(self.uri)
-
-    def make_queue(self):
-        queue = retask.queue.Queue(self.queue_name)
-        queue.connect()
-        return queue
-
-    def rebuild_hubs_hint_lookups(self, session):
-        self.checks_by_topic = collections.defaultdict(list)
-        self.checks_by_category = collections.defaultdict(list)
-        self.checks_by_username = collections.defaultdict(list)
-        self.ubiquitous_checks = list()
-
-        widgets = session.query(hubs.models.Widget).all()
-        log.info("Building lookup from  %i total widgets" % len(widgets))
-        for widget in widgets:
-            module = hubs.widgets.registry[widget.plugin]
-            check = module.should_invalidate
-
-            if not hasattr(check, 'hints'):
-                raise AttributeError("%r must declare hints" % module)
-
-            item = (check, j(widget),)
-
-            for topic in check.hints['topics']:
-                self.checks_by_topic[topic].append(item)
-
-            for category in check.hints['categories']:
-                self.checks_by_category[category].append(item);
-
-            usernames = check.hints['usernames_function'](widget)
-            for username in usernames:
-                self.checks_by_username[username].append(item)
-
-            if check.hints['ubiquitous']:
-                self.ubiquitous_checks.append(item)
-
-        log.info("Lookup sizes are:")
-        log.info("- %i topics" % len(self.checks_by_topic))
-        log.info("- %i categories" % len(self.checks_by_category))
-        log.info("- %i usernames" % len(self.checks_by_username))
-        log.info("- %i ubiquitous" % len(self.ubiquitous_checks))
-
-    @property
-    def lookup_initialized(self):
-        return any([
-            self.checks_by_topic,
-            self.checks_by_category,
-            self.checks_by_username,
-            self.ubiquitous_checks,
-        ])
-
-    def consume(self, raw_msg):
-        queue = self.make_queue()
-        session = self.make_session()
-        try:
-            with hubs.app.app.app_context():  # so url_for works
-                self.work(session, queue, raw_msg)
-            session.commit()  # transaction is committed here
-        except:
-            session.rollback()  # rolls back the transaction
-            raise
-        finally:
-            session.close()
-
-    def work(self, session, queue, raw_msg):
-        topic, msg = raw_msg['topic'], raw_msg['body']
-        category = topic.split('.')[3]
-        usernames = fedmsg.meta.msg2usernames(msg, **self.hub.config)
-
-        for suffix in self.junk_suffixes:
-            if topic.endswith(suffix):
-                log.info("Dropping %r", topic)
-                return
-
-        log.debug("CacheInvalidatorExtraordinaire received %s %s",
-                  msg['msg_id'], msg['topic'])
-
-        if category == 'hubs' or not self.lookup_initialized:
-            # Someone has modified an object in the hubs database, so let's
-            # rebuild our lookup table of our own database.
-            with self.hint_lookup_lock:
-                self.rebuild_hubs_hint_lookups(session)
-
-        # Begin our real work.
-        # Find which widgets should have their caches nuked and make it so.
-
-        # Start this by finding a subset of widget checks that might match this
-        # message. Look them up based on the hints they declare.
-        checks = sum([
-            self.checks_by_topic[topic],
-            self.checks_by_category[category],
-            sum([self.checks_by_username[u] for u in usernames], []),
-            self.ubiquitous_checks,
-        ], [])
-
-        log.debug("Found %i checks to try for this message" % len(checks))
-
-        # Then, with that hopefully smaller list of checks, try them all and
-        # see if any tell us that we should nuke various data caches.
-        for check, widget in checks:
-            if check(msg, session, widget):
-                task = retask.task.Task(json.dumps({
-                    'idx': widget.idx,
-                    'msg_id': msg['msg_id'],
-                }))
-                log.debug("  Sending %r to workers. (backlog is %r)" % (
-                    task, queue.length))
-                queue.enqueue(task)
-
-    def stop(self):
-        log.info("Cleaning up CacheInvalidatorExtraordinaire.")
-        super(CacheInvalidatorExtraordinaire, self).stop()
diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
index d524833..2576963 100644
--- a/hubs/widgets/bugzilla.py
+++ b/hubs/widgets/bugzilla.py
@@ -5,7 +5,7 @@ import hubs.validators as validators
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
-from hubs.hinting import hint, prefixed as _
+from hubs.hinting import hint
 
 chrome = panel("Bugzilla: Issues")
 template = templating.environment.get_template('templates/bugzilla.html')
@@ -63,6 +63,18 @@ def data(session, widget, username):
     )
 
 
-@hint()
+@hint(categories=['bugzilla'])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    # TODO -- wrap this pkgdb pull in another invalidatible cache.
+    username = widget.config['username']
+    pkgdb_url = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
+    url = "/".join([pkgdb_url, username])
+    response = requests.get(url)
+    data = response.json()
+
+    owned = data['point of contact'] + data['co-maintained']
+    owned = [p['name'] for p in owned]
+    if message['msg']['bug']['component'] in owned:
+        return True
+
+    return False
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index 905924c..89c8766 100755
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -51,6 +51,13 @@ def data(session, widget, display_number, organization):
     )
 
 
-@hint()
+@hint(categories=['github'])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    owner = message['msg']['repository']['owner']
+
+    if 'login' in owner:
+        owner = owner['login']
+    else:
+        owner = owner['name']
+
+    return owner == widget.config['organization']
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 59444db..350291d 100755
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -48,6 +48,7 @@ def data(session, widget, repo):
     )
 
 
-@hint()
+# TODO -- this hint could be honed in more to just PRs
+@hint(categories=['pagure'])
 def should_invalidate(message, session, widget):
-    raise NotImplementedError
+    return message['msg']['project']['name'] == widget.config['repo']
diff --git a/hubs/worker.py b/hubs/worker.py
deleted file mode 100755
index fa63856..0000000
--- a/hubs/worker.py
+++ /dev/null
@@ -1,72 +0,0 @@
-import hubs.app
-import hubs.models
-
-import hubs.widgets.base
-
-import fedmsg.config
-config = fedmsg.config.load_config()
-
-import retask.queue
-
-import json
-import sys
-import logging
-import logging.config
-log = logging.getLogger('hubs.worker')
-
-
-def work(session, widget_idx):
-    # Get a real widget, because we update last_refreshed on it.
-    widget = hubs.models.Widget.by_idx(session, widget_idx)
-    log.info("! Invalidating cache for %r" % widget)
-    # Invalidate the cache...
-    hubs.widgets.base.invalidate_cache(widget, **widget.config)
-    # Rebuild it.
-    log.info("! Rebuilding cache for %r" % widget)
-    widget.module.data(session, widget, **widget.config)
-    # TODO -- fire off an EventSource notice that we updated stuff
-
-def handle(idx):
-    session = hubs.models.init(config['hubs.sqlalchemy.uri'])
-
-    try:
-        with hubs.app.app.app_context():  # so url_for works
-            work(session, idx)
-        session.commit()  # transaction is committed here
-    except:
-        session.rollback()  # rolls back the transaction
-        raise
-    finally:
-        session.close()
-
-def main(args):
-
-    # TODO -- manage signal handling for clean shutdown
-
-    logging.config.dictConfig(config['logging'])
-    logging.basicConfig()
-
-    # XXX - for flask.url_for to work
-    hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
-
-    name = config['hubs.redis.work-queue-name']
-    log.info("Worker starting, connecting to retask queue %r." % name)
-    queue = retask.queue.Queue(name)
-    queue.connect()
-
-    try:
-        log.info("Entering work loop.")
-        while True:
-            task = queue.wait()  # Wait forever...  timeout is optional.
-            log.info("Working on %r.  (backlog is %r)" % (task, queue.length))
-            item = json.loads(task.data)
-            idx = item['idx']  # A widget ID
-            handle(idx)
-            log.debug("  Done.")
-    except KeyboardInterrupt:
-        pass
-
-    return 0
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv))
diff --git a/setup.py b/setup.py
index 5a66e3e..6ddbd37 100644
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,7 @@ setup(
     ],
     entry_points={
         'moksha.consumer': [
-            "cache_invalidator = hubs.consumer:CacheInvalidatorExtraordinaire",
+            "cache_invalidator = hubs.backend.consumer:CacheInvalidatorExtraordinaire",
         ],
     },
 )

From 712e07f2beb42ee6a4163d88daea1ee9a6e466b3 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 31 2016 19:51:49 +0000
Subject: [PATCH 381/1001] Add forgotten files.


---

diff --git a/hubs/backend/__init__.py b/hubs/backend/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/backend/__init__.py
diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
new file mode 100755
index 0000000..fac1bb0
--- /dev/null
+++ b/hubs/backend/triage.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+""" hubs backend triage process.
+
+This is step 2 of the backend cascading pipeline.
+
+consumer -> redis --+-> triage process -+-> redis --+-> worker process
+                    |          .        |           |          .
+                    +-> triage process -+           +-> worker process
+                               .                               .
+                               .                               .
+                               .                               .
+
+There could be multiple triage processing running as a farm that pulls work
+from a redis queue, fed by the fedmsg consumer.  The job of the triage process
+is to take raw fedmsg messages and decide if any widgets should be invalidated
+by them.  They don't actually do the invalidating and rebuilding themselves,
+though.  If they see that invalidation is required, they put a new task on an
+'outbound' redis queue for a worker process from the worker farm to pick up and
+handle.
+"""
+
+import hubs.app
+import hubs.models
+
+import hubs.widgets.base
+
+import fedmsg.config
+import fedmsg.meta
+config = fedmsg.config.load_config()
+
+import retask.queue
+
+import json
+import random
+import sys
+import logging
+import logging.config
+log = logging.getLogger('hubs.backend.triage')
+
+def triage(session, outbound, msg):
+    topic = msg['topic']
+    category = topic.split('.')[3]
+
+    for suffix in config['hubs.junk_suffixes']:
+        if topic.endswith(suffix):
+            log.debug("  Dropping junk %r", topic)
+            return
+
+    # Get a list of all our widgets:
+    log.debug("Querying for all widgets.")
+    widgets = session.query(hubs.models.Widget).all()
+
+    # Randomize so that all the triage daemons work on widgets in different
+    # orders.  This should hopefully prevent cache thrashing.
+    log.debug("Randomizing list of all widgets.")
+    random.shuffle(widgets)
+
+    log.debug("Checking should_invalidate for all widgets.")
+    for widget in widgets:
+
+        check = widget.module.should_invalidate
+
+        # Do some pre-flight checks before calling should_invalidate
+        if hasattr(check, 'hints'):
+            if check.hints['topics']:
+                if topic not in check.hints['topics']:
+                    continue
+            if check.hints['categories']:
+                if category not in check.hints['categories']:
+                    continue
+
+        if check(msg, session, widget):
+            yield retask.task.Task(json.dumps({
+                'idx': widget.idx,
+                'msg_id': msg['msg_id'],
+            }))
+
+
+def main(args):
+    logging.config.dictConfig(config['logging'])
+    logging.basicConfig()
+
+    fedmsg.meta.make_processors(**config)
+
+    # XXX - for flask.url_for to work
+    hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
+
+    inbound_name = config['hubs.redis.triage-queue-name']
+    outbound_name = config['hubs.redis.work-queue-name']
+
+    log.info("Triage proc starting.  Moving from %r to %r." % (inbound_name, outbound_name))
+
+    inbound = retask.queue.Queue(inbound_name)
+    inbound.connect()
+    outbound = retask.queue.Queue(outbound_name)
+    outbound.connect()
+
+    try:
+        log.info("Entering triage loop.")
+        while True:
+            task = inbound.wait()  # Wait forever...  timeout is optional.
+            msg = json.loads(task.data)
+            log.info(
+                "(triage backlog: %r, work backlog: %r)  Working on %r %r",
+                inbound.length, outbound.length, msg['msg_id'], msg['topic'],
+            )
+            session = hubs.models.init(config['hubs.sqlalchemy.uri'])
+            with hubs.app.app.app_context():  # so url_for works
+                for task in triage(session, outbound, msg):
+                    log.debug("  Triage sending %r to workers." % task)
+                    outbound.enqueue(task)
+            log.debug("  Done with triage of %r.", msg['msg_id'])
+    except KeyboardInterrupt:
+        pass
+
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))

From 8cf81b6d2a901317268ac686a1d4c7457b12cc0e Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Mar 31 2016 20:04:20 +0000
Subject: [PATCH 382/1001] systemd service files.


---

diff --git a/systemd/README b/systemd/README
new file mode 100644
index 0000000..6d055ec
--- /dev/null
+++ b/systemd/README
@@ -0,0 +1,3 @@
+This are service files used for the demo cloud node.
+
+We should revise them once we're closer to ready for production.
diff --git a/systemd/hubs-triage@.service b/systemd/hubs-triage@.service
new file mode 100644
index 0000000..c94f838
--- /dev/null
+++ b/systemd/hubs-triage@.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=fedora-hubs triage worker #%i
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart=/srv/git/fedora-hubs/venv-hubs/bin/python /srv/git/fedora-hubs/hubs/backend/triage.py
+WorkingDir=/srv/git/fedora-hubs/
+Type=simple
+User=root
+Group=root
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/systemd/hubs-webapp.service b/systemd/hubs-webapp.service
new file mode 100644
index 0000000..0993f22
--- /dev/null
+++ b/systemd/hubs-webapp.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=fedora-hubs frontend webapp
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart=/srv/git/fedora-hubs/venv-hubs/bin/gunicorn -b 0.0.0.0:80 --threads 12 --log-config logging.ini --reload hubs.app:app
+WorkingDir=/srv/git/fedora-hubs/
+Type=simple
+User=root
+Group=root
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/systemd/hubs-worker@.service b/systemd/hubs-worker@.service
new file mode 100644
index 0000000..ce263b7
--- /dev/null
+++ b/systemd/hubs-worker@.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=fedora-hubs cache worker #%i
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart=/srv/git/fedora-hubs/venv-hubs/bin/python /srv/git/fedora-hubs/hubs/backend/worker.py
+WorkingDir=/srv/git/fedora-hubs/
+Type=simple
+User=root
+Group=root
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target

From 98d111ab9a5797ee1e4d2a3ec1121a2bbf758f81 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 01 2016 14:30:03 +0000
Subject: [PATCH 383/1001] Link to the dev instance.


---

diff --git a/README.rst b/README.rst
index cb7baac..a7cfa52 100644
--- a/README.rst
+++ b/README.rst
@@ -5,6 +5,8 @@ The latest source is not on GitHub, it is on pagure.io.  You can find it at http
 
 We have a mailing list here: https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org/
 
+We have a dev instance up at http://209.132.184.97/
+
 Hacking
 =======
 Install fedora dependencies::

From fe4c80ea06cf7c511e013f888e7b2da63adff4a1 Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 01 2016 17:17:26 +0000
Subject: [PATCH 384/1001] No more venv in the demo instance.


---

diff --git a/systemd/hubs-triage@.service b/systemd/hubs-triage@.service
index c94f838..6dcd212 100644
--- a/systemd/hubs-triage@.service
+++ b/systemd/hubs-triage@.service
@@ -4,7 +4,7 @@ After=network.target
 Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
-ExecStart=/srv/git/fedora-hubs/venv-hubs/bin/python /srv/git/fedora-hubs/hubs/backend/triage.py
+ExecStart=/srv/git/fedora-hubs/hubs/backend/triage.py
 WorkingDir=/srv/git/fedora-hubs/
 Type=simple
 User=root
diff --git a/systemd/hubs-webapp.service b/systemd/hubs-webapp.service
index 0993f22..623efd9 100644
--- a/systemd/hubs-webapp.service
+++ b/systemd/hubs-webapp.service
@@ -4,7 +4,7 @@ After=network.target
 Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
-ExecStart=/srv/git/fedora-hubs/venv-hubs/bin/gunicorn -b 0.0.0.0:80 --threads 12 --log-config logging.ini --reload hubs.app:app
+ExecStart=/usr/bin/gunicorn -b 0.0.0.0:80 --threads 12 --log-config logging.ini --reload hubs.app:app
 WorkingDir=/srv/git/fedora-hubs/
 Type=simple
 User=root
diff --git a/systemd/hubs-worker@.service b/systemd/hubs-worker@.service
index ce263b7..a8e2867 100644
--- a/systemd/hubs-worker@.service
+++ b/systemd/hubs-worker@.service
@@ -4,7 +4,7 @@ After=network.target
 Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
-ExecStart=/srv/git/fedora-hubs/venv-hubs/bin/python /srv/git/fedora-hubs/hubs/backend/worker.py
+ExecStart=/srv/git/fedora-hubs/hubs/backend/worker.py
 WorkingDir=/srv/git/fedora-hubs/
 Type=simple
 User=root

From c51c306a3406bf63a1c37fbcb5dac0e074e5501a Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 01 2016 17:20:45 +0000
Subject: [PATCH 385/1001] Better name?


---

diff --git a/systemd/hubs-triage@.service b/systemd/hubs-triage@.service
index 6dcd212..c88ebde 100644
--- a/systemd/hubs-triage@.service
+++ b/systemd/hubs-triage@.service
@@ -5,7 +5,7 @@ Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
 ExecStart=/srv/git/fedora-hubs/hubs/backend/triage.py
-WorkingDir=/srv/git/fedora-hubs/
+WorkingDirectory=/srv/git/fedora-hubs/
 Type=simple
 User=root
 Group=root
diff --git a/systemd/hubs-webapp.service b/systemd/hubs-webapp.service
index 623efd9..5c66951 100644
--- a/systemd/hubs-webapp.service
+++ b/systemd/hubs-webapp.service
@@ -5,7 +5,7 @@ Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
 ExecStart=/usr/bin/gunicorn -b 0.0.0.0:80 --threads 12 --log-config logging.ini --reload hubs.app:app
-WorkingDir=/srv/git/fedora-hubs/
+WorkingDirectory=/srv/git/fedora-hubs/
 Type=simple
 User=root
 Group=root
diff --git a/systemd/hubs-worker@.service b/systemd/hubs-worker@.service
index a8e2867..bf6f0ef 100644
--- a/systemd/hubs-worker@.service
+++ b/systemd/hubs-worker@.service
@@ -5,7 +5,7 @@ Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
 ExecStart=/srv/git/fedora-hubs/hubs/backend/worker.py
-WorkingDir=/srv/git/fedora-hubs/
+WorkingDirectory=/srv/git/fedora-hubs/
 Type=simple
 User=root
 Group=root

From 11f8e0bbbc9a30f35fd2cea9186ddcd32cbeddec Mon Sep 17 00:00:00 2001
From: Ralph Bean <rbean@redhat.com>
Date: Apr 01 2016 17:33:05 +0000
Subject: [PATCH 386/1001] Change in URL.


---

diff --git a/README.rst b/README.rst
index a7cfa52..41551fb 100644
--- a/README.rst
+++ b/README.rst
@@ -5,7 +5,7 @@ The latest source is not on GitHub, it is on pagure.io.  You can find it at http
 
 We have a mailing list here: https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org/
 
-We have a dev instance up at http://209.132.184.97/
+We have a dev instance up at http://209.132.184.98
 
 Hacking
 =======

From b9c39b6a6d79c1fb2672026ed13bef0f0679d517 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 13 2016 22:27:31 +0000
Subject: [PATCH 387/1001] Let's ignore error when importing preferences


This happens if the library used locally is outdated compared to the
one in prod. Let's just ignore this.

---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index de793f5..92b0773 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -74,7 +74,10 @@ def data(session, widget, username, fmn_context):
     matches = []
     preference = get_remote_preference(username, fmn_context)
     if preference:
-        preference = rehydrate_preference(preference)
+        try:
+            preference = rehydrate_preference(preference)
+        except ImportError:
+            pass
 
         # The smaller we make this, the faster it is.
         delta = datetime.timedelta(days=365)

From 17da2872e0388cc6d88b83ca4ac84abda4e99db3 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 13 2016 22:27:31 +0000
Subject: [PATCH 388/1001] Only return something in the GitHub PR widget if there is a token set


---

diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index 89c8766..24c2dc8 100755
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -27,21 +27,25 @@ template = templating.environment.get_template('templates/github_pr.html')
           help="Github Organization or username")
 def data(session, widget, display_number, organization):
     log.info("Getting GH prs for %r, (%r)" % (organization, display_number))
-    token = config['github.oauth_token']
+    token = config.get('github.oauth_token')
     org = organization
-    repos = hubs.utils.github_repos(token, org)
-    pulls = sum([
-        list(hubs.utils.github_pulls(token, org, repo))
-        for repo in repos
-    ], [])
-    # Reverse-sort by time (newest-first)
-    pulls.sort(lambda a, b: cmp(b['timestamp'], a['timestamp']))
-
-    # Some hints for display
-    display_number = min(display_number, len(pulls))
-    more = len(pulls) - display_number
-    if more < 0:
-        more = 0
+    pulls = []
+    display_number = 0
+    more = 0
+    if token:
+        repos = hubs.utils.github_repos(token, org)
+        pulls = sum([
+            list(hubs.utils.github_pulls(token, org, repo))
+            for repo in repos
+        ], [])
+        # Reverse-sort by time (newest-first)
+        pulls.sort(lambda a, b: cmp(b['timestamp'], a['timestamp']))
+
+        # Some hints for display
+        display_number = min(display_number, len(pulls))
+        more = len(pulls) - display_number
+        if more < 0:
+            more = 0
 
     return dict(
         organization=org,

From b8a1700f0b2a78723b2b463e5117e49fa7039e43 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:20:42 +0000
Subject: [PATCH 389/1001] Optimization and code style changed as suggested by @sayanchowdhury


---

diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index 24c2dc8..5ee081a 100755
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -42,10 +42,9 @@ def data(session, widget, display_number, organization):
         pulls.sort(lambda a, b: cmp(b['timestamp'], a['timestamp']))
 
         # Some hints for display
-        display_number = min(display_number, len(pulls))
-        more = len(pulls) - display_number
-        if more < 0:
-            more = 0
+        len_pulls = len(pulls)
+        display_number = min(display_number, len_pulls)
+        more = max(len_pulls - display_number, 0)
 
     return dict(
         organization=org,

From 5f693fdf84a3f6e7978b0107a5432f16ce62e103 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:24:20 +0000
Subject: [PATCH 390/1001] Adjust the routes so that we support both url with and without a trailing slash


---

diff --git a/hubs/app.py b/hubs/app.py
index 47099c4..6d3e2e6 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -100,15 +100,16 @@ def groups():
     )
 
 
-@app.route('/<name>')
 @app.route('/<name>/')
+@app.route('/<name>')
 def hub(name):
     hub = get_hub(session, name)
     return flask.render_template(
         'hubs.html', hub=hub, session=session, edit=False)
 
-@app.route('/<name>/json')
+
 @app.route('/<name>/json/')
+@app.route('/<name>/json')
 def hub_json(name):
     hub = get_hub(session, name)
     response = flask.jsonify(hub.__json__(session))
@@ -116,16 +117,16 @@ def hub_json(name):
     return response
 
 
-@app.route('/<name>/edit', methods=['GET'])
 @app.route('/<name>/edit/', methods=['GET'])
+@app.route('/<name>/edit', methods=['GET'])
 def hub_edit_get(name):
     hub = get_hub(session, name)
     return flask.render_template(
         'hubs.html', hub=hub, session=session, edit=True)
 
 
-@app.route('/<name>/edit', methods=['POST'])
 @app.route('/<name>/edit/', methods=['POST'])
+@app.route('/<name>/edit', methods=['POST'])
 def hub_edit_post(name):
     #hub = get_hub(session, name)
     # TODO -- save things to the db ... and then redirect
@@ -134,8 +135,8 @@ def hub_edit_post(name):
     flask.redirect(flask.url_for('hub', name=name))
 
 
-@app.route('/<hub>/<idx>')
 @app.route('/<hub>/<idx>/')
+@app.route('/<hub>/<idx>')
 def widget_render(hub, idx):
     widget = get_widget(session, hub, idx)
     return widget.render(session)#, edit=False)
@@ -151,8 +152,8 @@ def widget_json(hub, idx):
     return response
 
 
-@app.route('/<hub>/<idx>/edit', methods=['GET'])
 @app.route('/<hub>/<idx>/edit/', methods=['GET'])
+@app.route('/<hub>/<idx>/edit', methods=['GET'])
 def widget_edit_get(hub, idx):
     widget = get_widget(session, hub, idx)
     raise NotImplementedError('next step is to get the widgets to render '
@@ -161,8 +162,8 @@ def widget_edit_get(hub, idx):
     return widget.render(session, edit=True)
 
 
-@app.route('/<hub>/<idx>/edit', methods=['POST'])
 @app.route('/<hub>/<idx>/edit/', methods=['POST'])
+@app.route('/<hub>/<idx>/edit', methods=['POST'])
 def widget_edit_post(hub, idx):
     #widget = get_widget(session, hub, idx)
     # TODO -- save things to the db ... and then redirect
@@ -171,8 +172,8 @@ def widget_edit_post(hub, idx):
     flask.redirect(flask.url_for('hub', name=hub))
 
 
-@app.route('/source/<name>')
 @app.route('/source/<name>/')
+@app.route('/source/<name>')
 def widget_source(name):
     from hubs.widgets import registry
     base = '/hubs/'
@@ -319,6 +320,7 @@ def hub_subscribe(hub):
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
+
 @app.route('/api/hub/<hub>/unsubscribe', methods=['POST'])
 @login_required
 def hub_unsubscribe(hub):
@@ -331,6 +333,7 @@ def hub_unsubscribe(hub):
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
+
 @app.route('/api/hub/<hub>/star', methods=['POST'])
 @login_required
 def hub_star(hub):
@@ -340,6 +343,7 @@ def hub_star(hub):
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
+
 @app.route('/api/hub/<hub>/unstar', methods=['POST'])
 @login_required
 def hub_unstar(hub):
@@ -352,6 +356,7 @@ def hub_unstar(hub):
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
+
 @app.route('/api/hub/<hub>/join', methods=['POST'])
 @login_required
 def hub_join(hub):
@@ -361,6 +366,7 @@ def hub_join(hub):
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
+
 @app.route('/api/hub/<hub>/leave', methods=['POST'])
 @login_required
 def hub_leave(hub):

From d6883063b276e38ae9732f9094c642f8d7b2e2fb Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:24:20 +0000
Subject: [PATCH 391/1001] Adjust indentation in the html


---

diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
index a26fd17..230e54a 100644
--- a/hubs/templates/groups.html
+++ b/hubs/templates/groups.html
@@ -9,12 +9,15 @@
 <body>
 <div class="super-header">
   <div class="row">
-	  <div class="col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
+    <div class="col-xs-4" id="logo">
+      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs">
+    </div>
     <div class="col-sm-4 col-sm-push-4 col-xs-8">
       {% if g.auth.logged_in %}
         <div class="dropdown pull-right">
           <img class = "icon" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
-        <span class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+        <span class="dropdown-toggle" type="button" id="dropdownMenu1"
+            data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
           <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
           {# Logged in as #} {{ g.auth.nickname }}
           <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
@@ -46,7 +49,9 @@
   <nav class="navbar navbar-default">
     <div class="container-fluid">
       <div class="navbar-header">
-        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+        <button type="button" class="navbar-toggle collapsed"
+            data-toggle="collapse"
+            data-target="#bs-example-navbar-collapse-1">
           <span class="sr-only">Toggle navigation</span>
           <span class="icon-bar"></span>
           <span class="icon-bar"></span>
@@ -83,7 +88,10 @@
     <div class="col-md-12">
       {% for group in promoted %}
         <a href="{{ url_for('hub', name=group.name)}}">{{group.name}}</a>
-        is a promoted group, and it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
+        is a promoted group, and it has {{
+            group.subscribers | length }} subscribers and {{
+            group.members | length }} members, and {{
+            group.owners | length }} owners
       {% endfor %}
     </div>
   </div>
@@ -93,7 +101,9 @@
   <div class="row">
     <div class="col-md-12">
       ZOMG - {{ hub_of_the_month.name }} is the Hub Of The Month! <br/>
-      It has {{ hub_of_the_month.subscribers | length }} subscribers and {{ hub_of_the_month.members | length }} members, and {{hub_of_the_month.owners | length }} owners
+      It has {{ hub_of_the_month.subscribers | length }} subscribers and {{
+        hub_of_the_month.members | length }} members, and {{
+        hub_of_the_month.owners | length }} owners
       <h6>group owners</h6>
       {% for owner in hub_of_the_month.owners %}
           <div class="col-sm-6">
@@ -111,7 +121,9 @@
       {% for group in secondary %}
         <a href="{{ url_for('hub', name=group.name)}}">{{group.name}}</a>
         is not a promoted group
-        but it has {{ group.subscribers | length }} subscribers and {{ group.members | length }} members, and {{group.owners | length }} owners
+        but it has {{ group.subscribers | length }} subscribers and {{
+            group.members | length }} members, and {{
+            group.owners | length }} owners
         <br/>
       {% endfor %}
     </div>
@@ -120,4 +132,5 @@
 
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
-</body></html>
+</body>
+</html>
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 02a7a02..fecf7f1 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -75,7 +75,9 @@
 <div class="header">
   {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
     <div class="dropdown edit">
-      <span class="dropdown-toggle edit-this-page" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+      <span class="dropdown-toggle edit-this-page" type="button"
+            id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
+            aria-expanded="true">
         <span class="glyphicon glyphicon-edit"></span> edit this page
       </span>
       <ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
@@ -116,24 +118,24 @@
       -->
       {% if hub.archived or hub.last_refreshed | days_since > 31 %}
       <ul class="media-list">
-          <li class="media">
-              <div class="media-left">
-              {% if hub.archived %}
-                  <img class="media-object square-32"
-                       src="{{flask.url_for('static', filename='img/archived.png')}}"/>
-              {% else %}
-                  <img class="media-object square-32"
-                       src="{{flask.url_for('static', filename='img/cobweb.png')}}"/>
-              {% endif %}
-              </div>
-              <div class="media-body">
-              {% if hub.archived %}
-                  This hub has been archived and locked.
-              {% else %}
-                  Cobweb alert!  This hub was last active {{ hub.last_refreshed | days_since }} days ago.
-              {% endif %}
-              </div>
-          </li>
+        <li class="media">
+          <div class="media-left">
+          {% if hub.archived %}
+            <img class="media-object square-32"
+              src="{{flask.url_for('static', filename='img/archived.png')}}"/>
+          {% else %}
+            <img class="media-object square-32"
+              src="{{flask.url_for('static', filename='img/cobweb.png')}}"/>
+          {% endif %}
+          </div>
+          <div class="media-body">
+          {% if hub.archived %}
+            This hub has been archived and locked.
+          {% else %}
+            Cobweb alert!  This hub was last active {{ hub.last_refreshed | days_since }} days ago.
+          {% endif %}
+          </div>
+        </li>
       </ul>
       {% endif %}
 

From c226963e082b797bac5507b3a7c7a6729712c933 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:24:20 +0000
Subject: [PATCH 392/1001] Redirects from /user to /user/ as otherwise it breaks quite a bit of JS


---

diff --git a/hubs/app.py b/hubs/app.py
index 6d3e2e6..c57cdb4 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -100,8 +100,8 @@ def groups():
     )
 
 
-@app.route('/<name>/')
 @app.route('/<name>')
+@app.route('/<name>/')
 def hub(name):
     hub = get_hub(session, name)
     return flask.render_template(

From 7b2035ff24118ff08276f591dd0bea6032db6c95 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:24:20 +0000
Subject: [PATCH 393/1001] More style changes (line length)


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index fecf7f1..3b04247 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -9,12 +9,15 @@
 <body>
 <div class="super-header">
   <div class="row">
-	  <div class="col-xs-4" id="logo"><img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs"></div>
+    <div class="col-xs-4" id="logo">
+      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs">
+    </div>
     <div class="col-sm-4 col-sm-push-4 col-xs-8">
       {% if g.auth.logged_in %}
         <div class="dropdown pull-right">
           <img class = "icon" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
-        <span class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+        <span class="dropdown-toggle" type="button" id="dropdownMenu1"
+          data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
           <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
           {# Logged in as #} {{ g.auth.nickname }}
           <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
@@ -46,7 +49,8 @@
   <nav class="navbar navbar-default">
     <div class="container-fluid">
       <div class="navbar-header">
-        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+        <button type="button" class="navbar-toggle collapsed"
+            data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
           <span class="sr-only">Toggle navigation</span>
           <span class="icon-bar"></span>
           <span class="icon-bar"></span>
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index f74b32c..f5a40a9 100755
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -1,8 +1,10 @@
 from hubs.widgets.base import wraps
 from hubs.widgets import templating
 
-_panel_template = templating.environment.get_template('templates/panel.html')
-_panel_heading_template = templating.environment.get_template('templates/panel_heading.html')
+_panel_template = templating.environment.get_template(
+    'templates/panel.html')
+_panel_heading_template = templating.environment.get_template(
+    'templates/panel_heading.html')
 
 
 def panel(title=None, klass="panel-default", key=None):
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 64a8316..668fcc7 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -10,7 +10,8 @@ from hubs.widgets.chrome import panel
 # If 'updates' is empty, then don't render any chrome.
 chrome = panel('Updates Ready for Stable', key='updates')
 # TODO -- add approve/deny buttons or just link through to pkgdb
-template = templating.environment.get_template('templates/workflow/updates2stable.html')
+template = templating.environment.get_template(
+    'templates/workflow/updates2stable.html')
 
 # TODO - the bodhi api exposes a new flag we can use instead of scraping comments...
 giveaway = 'can be pushed to stable now'

From 79aa34d2af8a3430c174b0d01e98ceb211b33618 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:25:22 +0000
Subject: [PATCH 394/1001] Fix setting the configuration of a widget


---

diff --git a/hubs/models.py b/hubs/models.py
index 086e0b1..059ad28 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -309,7 +309,7 @@ class Widget(BASE):
         return json.loads(self._config)
 
     @config.setter
-    def config_setter(self, config):
+    def config(self, config):
         self._config = json.dumps(config)
 
     def __json__(self, session):

From 3d1ec7bbc8aba94de6b72f77a6a8e0dce9c45322 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:25:22 +0000
Subject: [PATCH 395/1001] Let's have the edit_url and the widget idx in the panel template


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index e784ef1..a842baf 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -48,6 +48,9 @@ def AGPLv3(name):
             result['source_url'] = flask.url_for('widget_source', name=name)
             result['widget_url'] = flask.url_for(
                 'widget_render', hub=widget.hub.name, idx=widget.idx)
+            result['edit_url'] = flask.url_for(
+                'widget_edit_get', hub=widget.hub.name, idx=widget.idx)
+            result['widget_idx'] = widget.idx
             return result
 
         return inner

From 9b2bb1885f85cd935c591c707459f578de24e32c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:25:22 +0000
Subject: [PATCH 396/1001] Fix the edit button in the panel of the widgets


---

diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index ba6dff2..9af630b 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -1,12 +1,16 @@
-<div class="panel {{klass}}">
-  {{heading}}
+<div class="panel {{ klass }}">
+  {{ heading }}
   <div class="pull-right widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
-    <a href="{{source_url}}"><span class="glyphicon glyphicon-eye-open"></span></a>
-    <a href="{{widget_url}}"><span class="glyphicon glyphicon-new-window"></span></a>
-    <a href="#"><span class="glyphicon glyphicon-edit"></span></a>
+    <a href="{{ source_url }}"><span class="glyphicon glyphicon-eye-open"></span></a>
+    <a href="{{ widget_url }}"><span class="glyphicon glyphicon-new-window"></span></a>
+    <a data-target="#edit_modal" data-toggle="modal" type="button"
+        class="edit_widget" data-idx="{{ widget_idx }}">
+      <span class="glyphicon glyphicon-edit"></span>
+    </a>
+    </a>
   </div>
   <div class="panel-body">
-    {{content}}
+    {{ content }}
   </div> <!-- end panel-body -->
 </div> <!-- end panel -->

From 4d22eaa688fb8b2190203087edd2b483767f40e8 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:25:22 +0000
Subject: [PATCH 397/1001] Show the flashed message in the hubs template


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 3b04247..8cf43ba 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -111,6 +111,32 @@
     <h3 class="team">{{hub.name}}</h3>
   {% endif %}
 </div>
+
+{%- with messages = get_flashed_messages(with_categories=true) -%}
+  {%- if category, messages -%}
+  <div class="container">
+    <div class="row">
+      <div class="col-md-6 col-md-offset-3">
+        <ul id="flashes" class="list-group">
+          {%- for category, message in messages -%}
+            <div class="alert {%
+              if category == 'error' %}alert-warning{%
+              else %}alert-info{%
+              endif %} alert-dismissible" role="alert">
+              <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+                <span class="sr-only">Close</span>
+              </button>
+              {{ message }}
+            </div>
+          {%- endfor -%}
+        </ul>
+      </div>
+    </div>
+  </div>
+  {%- endif -%}
+{%- endwith -%}
+
 <div class="container">
   <div class="row">
   </div>

From 7ea1395c24147429400b4429dd45b850091dfab0 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 14 2016 18:25:22 +0000
Subject: [PATCH 398/1001] Implement configuring widgets directly in the UI


---

diff --git a/hubs/app.py b/hubs/app.py
index c57cdb4..75c53ed 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -156,20 +156,47 @@ def widget_json(hub, idx):
 @app.route('/<hub>/<idx>/edit', methods=['GET'])
 def widget_edit_get(hub, idx):
     widget = get_widget(session, hub, idx)
-    raise NotImplementedError('next step is to get the widgets to render '
-                              'editable versions of themselves with their '
-                              'declared @arguments, etc...')
-    return widget.render(session, edit=True)
+    if not widget.module.data.widget_arguments:
+        flask.abort(404, 'Nothing to configure for this hub.')
+    return flask.render_template(
+        'edit.html',
+        hub=hub,
+        widget=widget,
+        url_to=flask.url_for('widget_edit_post', hub=hub, idx=idx)
+    )
 
 
 @app.route('/<hub>/<idx>/edit/', methods=['POST'])
 @app.route('/<hub>/<idx>/edit', methods=['POST'])
 def widget_edit_post(hub, idx):
-    #widget = get_widget(session, hub, idx)
-    # TODO -- save things to the db ... and then redirect
-    widget.hub.last_edited = datetime.datetime.utcnow()
-    raise NotImplementedError('TODO - save changes to widget config')
-    flask.redirect(flask.url_for('hub', name=hub))
+    widget = get_widget(session, hub, idx)
+    error = False
+    config = {}
+    for arg in widget.module.data.widget_arguments:
+        val = flask.request.form.get(arg.name)
+        if not val:
+            flask.flash(
+                'You must provide a value for: %s' % arg.name, 'error')
+            error = True
+            break
+        try:
+            arg.validator(session, val)
+            config[arg.name] = val
+        except Exception as err:
+            flask.flash('Invalid data provided, error: %s' % err, 'error')
+            error = True
+    if not error:
+        widget.config = config
+        widget.hub.last_edited = datetime.datetime.utcnow()
+        session.add(widget)
+        try:
+            session.commit()
+        except Exception as err:
+            flask.flash(
+                'Could not save the configuration to the database '\
+                'if the error persists, please warn an admin',
+                'error')
+    return flask.redirect(flask.url_for('hub', name=hub))
 
 
 @app.route('/source/<name>/')
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
new file mode 100644
index 0000000..f4c2718
--- /dev/null
+++ b/hubs/templates/edit.html
@@ -0,0 +1,35 @@
+
+<div class="modal-dialog" id="edit_form">
+  <form method="post" action="{{ url_to }}">
+    <!-- Modal content-->
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        <h4 class="modal-title">Configure {{ name }}</h4>
+      </div>
+      <div class="modal-body">
+        {% for arg in widget.module.data.widget_arguments %}
+          <fieldset class="form-group ">
+            <strong>{{ arg.name | capitalize }}</strong>
+            <input id="{{ arg.name }}" class="form-control" type="text"
+              value="{{ widget.config.get(arg.name, arg.default if arg.default else '') }}"
+              name="{{ arg.name }}" />
+          </fieldset>
+          {% if arg.help %}
+            <div>
+              <small class="text-muted">{{ arg.help }}</small>
+            </div>
+          {% endif %}
+        {% endfor %}
+      </div>
+      <div class="modal-footer">
+        <button type="submit" class="btn btn-default">
+          Save
+        </button>
+        <button type="button" class="btn btn-default" data-dismiss="modal">
+          Close
+        </button>
+      </div>
+    </div>
+  </form>
+</div>
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 8cf43ba..d00c71c 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -202,31 +202,64 @@
   </div>
 </div>
 
+<div id="edit_modal" class="modal fade" role="dialog">
+  <div class="modal-dialog" id="edit_modal_content">
+  </div>
+</div>
+
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
 <script src="{{ url_for('static', filename='js/utils.js') }}"></script>
-<script>
-var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
-$.each(widgets, function(i, widget) {
+<script type="text/javascript">
+function setup_edit_btns() {
+  $(".edit_widget").unbind();
+  $(".edit_widget").click(function() {
+    console.log($(this));
+    var _idx = $(this).attr('data-idx');
+
     $.ajax({
-      {% if edit %}
-      url: widget + '/edit/',
-      {% else %}
-      url: widget,
-      {% endif %}
+      url: _idx + '/edit',
       dataType: 'html',
       success: function(html) {
-        $('#widget-' + widget).html(html);
-        setTimeout(function() {
-          $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
-        }, 100);
+        $('#edit_modal_content').html(html);
+        $('#edit_modal').modal();
       },
       error: function() {
-        $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
+        $('#edit_modal_content').html(
+          '<div class="modal-dialog"><div class="modal-content"> \
+          <div class="modal-body"> \
+          Nothing to configure for this widget\
+          </div></div></div>'
+        );
         console.log('error');
         console.trace();
+        $('#edit_modal').modal();
       },
     });
+    return false;
+  });
+}
+var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
+$.each(widgets, function(i, widget) {
+  $.ajax({
+    url: widget,
+    dataType: 'html',
+    success: function(html) {
+      $('#widget-' + widget).html(html);
+      setTimeout(function() {
+        $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
+      }, 100);
+      setup_edit_btns()
+    },
+    error: function() {
+      $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
+      console.log('error');
+      console.trace();
+    },
+  });
+  setup_edit_btns();
 });
+
+
 </script>
 </body></html>

From daf156eba7f17ee361dae2d30948091aacb7f8b8 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 15 2016 08:41:04 +0000
Subject: [PATCH 399/1001] Be a little more careful on how we update the widget configuration


---

diff --git a/hubs/app.py b/hubs/app.py
index 75c53ed..8fa873e 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -186,6 +186,8 @@ def widget_edit_post(hub, idx):
             flask.flash('Invalid data provided, error: %s' % err, 'error')
             error = True
     if not error:
+        cur_config = widget.config
+        cur_config.update(config)
         widget.config = config
         widget.hub.last_edited = datetime.datetime.utcnow()
         session.add(widget)

From 3f0474bcb7558503c44dd133451b31b3c51c6a0f Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 20 2016 08:33:11 +0000
Subject: [PATCH 400/1001] Fix typo seen by @sayanchowdhury


---

diff --git a/hubs/app.py b/hubs/app.py
index 8fa873e..8fb079b 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -188,7 +188,7 @@ def widget_edit_post(hub, idx):
     if not error:
         cur_config = widget.config
         cur_config.update(config)
-        widget.config = config
+        widget.config = cur_config
         widget.hub.last_edited = datetime.datetime.utcnow()
         session.add(widget)
         try:

From 2fdf7dad893048f4be92596e63ce95af857c2c01 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 20 2016 09:20:50 +0000
Subject: [PATCH 401/1001] Updated the readme, removing part about pagure.io


---

diff --git a/README.rst b/README.rst
index 41551fb..c4b5f3d 100644
--- a/README.rst
+++ b/README.rst
@@ -1,11 +1,15 @@
-Source on Pagure.io
-===================
+Fedora Hubs will provide a communication and collaboration center for Fedora 
+contributors of all types. The idea is that contributors will be able to visit 
+Hubs to check on their involvements across Fedora, discover new places that they 
+can contribute, and more.
 
-The latest source is not on GitHub, it is on pagure.io.  You can find it at https://pagure.io/fedora-hubs
+Hubs is currently under development, and you can see the progress on the 
+Development instance here: http://209.132.184.98
 
+Mailing List
+============
 We have a mailing list here: https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org/
 
-We have a dev instance up at http://209.132.184.98
 
 Hacking
 =======

From 3582355f189ae7055729a1fe8a7b0ab57c67e46e Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 21 2016 20:03:25 +0000
Subject: [PATCH 402/1001] Few HTML fixes on the main hubs template


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index d00c71c..55485f5 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -1,11 +1,12 @@
-<html>
+<!DOCTYPE html>
+<html lang='en'>
 <head>
   <title>{{ hub.name }}</title>
   <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
+  <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
 </head>
-<script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
 <body>
 <div class="super-header">
   <div class="row">
@@ -37,7 +38,7 @@
     <div class="col-sm-4 col-sm-pull-4 col-xs-12">
       <!-- NOT HOOKED UP TO ANYTHING XOXO -->
       <div class="input-group">
-        <input type="search" placeholder="Search across all hubs ..."></input>
+        <input type="search" placeholder="Search across all hubs ..." />
         <span class="input-group-addon">
           <span class="glyphicon glyphicon-search"></span>
         </span>
@@ -207,9 +208,12 @@
   </div>
 </div>
 
-<script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
-<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
-<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+<script type="text/javascript" src="{{
+  url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/utils.js') }}"></script>
 <script type="text/javascript">
 function setup_edit_btns() {
   $(".edit_widget").unbind();
@@ -260,6 +264,6 @@ $.each(widgets, function(i, widget) {
   setup_edit_btns();
 });
 
-
-</script>
-</body></html>
+s</script>
+</body>
+</html>

From 2bf93eb30b7896aa0a5db28d083cbd0f56cca69b Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 21 2016 20:03:25 +0000
Subject: [PATCH 403/1001] Let's pass the entire widget object instead of just the id


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index a842baf..49ca5b2 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -50,7 +50,7 @@ def AGPLv3(name):
                 'widget_render', hub=widget.hub.name, idx=widget.idx)
             result['edit_url'] = flask.url_for(
                 'widget_edit_get', hub=widget.hub.name, idx=widget.idx)
-            result['widget_idx'] = widget.idx
+            result['widget'] = widget
             return result
 
         return inner
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index 9af630b..fb78326 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -5,10 +5,9 @@
     <a href="{{ source_url }}"><span class="glyphicon glyphicon-eye-open"></span></a>
     <a href="{{ widget_url }}"><span class="glyphicon glyphicon-new-window"></span></a>
     <a data-target="#edit_modal" data-toggle="modal" type="button"
-        class="edit_widget" data-idx="{{ widget_idx }}">
+        class="edit_widget" data-idx="{{ widget.idx }}">
       <span class="glyphicon glyphicon-edit"></span>
     </a>
-    </a>
   </div>
   <div class="panel-body">
     {{ content }}

From ad68ecee0e3f0ed523f74fb0cd1680ff55374d55 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 21 2016 20:03:25 +0000
Subject: [PATCH 404/1001] Add endpoint to delete a widget from a hub


---

diff --git a/hubs/app.py b/hubs/app.py
index 8fb079b..3b60380 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -201,6 +201,22 @@ def widget_edit_post(hub, idx):
     return flask.redirect(flask.url_for('hub', name=hub))
 
 
+@app.route('/<hub>/<idx>/delete/', methods=['POST'])
+@app.route('/<hub>/<idx>/delete', methods=['POST'])
+def widget_edit_delete(hub, idx):
+    ''' Remove a widget from a hub. '''
+    widget = get_widget(session, hub, idx)
+    session.delete(widget)
+    try:
+        session.commit()
+    except Exception as err:
+        flask.flash(
+            'Could not delete this widget from this hub in the database '\
+            'if the error persists, please warn an admin',
+            'error')
+    return flask.redirect(flask.url_for('hub', name=hub))
+
+
 @app.route('/source/<name>/')
 @app.route('/source/<name>')
 def widget_source(name):

From 645396371fbb168ecd85fcbaa7f50e3f819f05fd Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 21 2016 20:03:25 +0000
Subject: [PATCH 405/1001] Adjust the panel layout to show a 'Remove this widget' button


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index f29c893..135fdb3 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -385,3 +385,9 @@ font-size: 32pt;
     color: #a07cbc;
 }
 
+.modal-footer button {
+  float: right;
+}
+button[name='delete_hub'] {
+  float: left;
+}
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index f4c2718..77bd072 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -1,8 +1,8 @@
 
 <div class="modal-dialog" id="edit_form">
-  <form method="post" action="{{ url_to }}">
+  <div class="modal-content">
+    <form method="post" action="{{ url_to }}">
     <!-- Modal content-->
-    <div class="modal-content">
       <div class="modal-header">
         <button type="button" class="close" data-dismiss="modal">&times;</button>
         <h4 class="modal-title">Configure {{ name }}</h4>
@@ -23,13 +23,19 @@
         {% endfor %}
       </div>
       <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">
+          Close
+        </button>
         <button type="submit" class="btn btn-default">
           Save
         </button>
-        <button type="button" class="btn btn-default" data-dismiss="modal">
-          Close
+    </form>
+    <form method="POST" action="{{ url_for(
+        'widget_edit_delete', hub=widget.hub.name, idx=widget.idx) }}">
+        <button type="submit" class="btn btn-danger">
+          Remove this widget
         </button>
+    <form>
       </div>
-    </div>
-  </form>
+  </div>
 </div>

From 66e43bcfb0c7d5e59dcfa4590a80d28eaf46862c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 21 2016 20:03:25 +0000
Subject: [PATCH 406/1001] Let's not return a 404 if there is nothing to configure


This is required since even if there is nothing to configure we want
to show the panel so that the widget can be removed from the hub if
desired.

---

diff --git a/hubs/app.py b/hubs/app.py
index 3b60380..2cbaffe 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -156,8 +156,6 @@ def widget_json(hub, idx):
 @app.route('/<hub>/<idx>/edit', methods=['GET'])
 def widget_edit_get(hub, idx):
     widget = get_widget(session, hub, idx)
-    if not widget.module.data.widget_arguments:
-        flask.abort(404, 'Nothing to configure for this hub.')
     return flask.render_template(
         'edit.html',
         hub=hub,

From 25668c112ae3b407a82ea2fb768eddced45c0a26 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 21 2016 20:03:25 +0000
Subject: [PATCH 407/1001] Fix placing the delete widget button on the left


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 135fdb3..5b47b54 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -388,6 +388,6 @@ font-size: 32pt;
 .modal-footer button {
   float: right;
 }
-button[name='delete_hub'] {
+button[id='delete_widget'] {
   float: left;
 }
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index 77bd072..0905913 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -32,7 +32,7 @@
     </form>
     <form method="POST" action="{{ url_for(
         'widget_edit_delete', hub=widget.hub.name, idx=widget.idx) }}">
-        <button type="submit" class="btn btn-danger">
+        <button type="submit" class="btn btn-danger" id="delete_widget">
           Remove this widget
         </button>
     <form>

From 82889d6a9f00a95e9f65fc9263202add915dce4d Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 21 2016 20:03:25 +0000
Subject: [PATCH 408/1001] Show something if there is nothing to configure, but then hide the save button


---

diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index 0905913..aa4f6fd 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -8,6 +8,7 @@
         <h4 class="modal-title">Configure {{ name }}</h4>
       </div>
       <div class="modal-body">
+      {% if widget.module.data.widget_arguments %}
         {% for arg in widget.module.data.widget_arguments %}
           <fieldset class="form-group ">
             <strong>{{ arg.name | capitalize }}</strong>
@@ -21,14 +22,19 @@
             </div>
           {% endif %}
         {% endfor %}
+      {% else %}
+        <p>Nothing to configure</p>
+      {% endif %}
       </div>
       <div class="modal-footer">
         <button type="button" class="btn btn-default" data-dismiss="modal">
           Close
         </button>
+        {% if widget.module.data.widget_arguments %}
         <button type="submit" class="btn btn-default">
           Save
         </button>
+        {% endif %}
     </form>
     <form method="POST" action="{{ url_for(
         'widget_edit_delete', hub=widget.hub.name, idx=widget.idx) }}">

From 634e5cd8253acf36bc238f18464c37f432c10a8c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 21 2016 20:03:25 +0000
Subject: [PATCH 409/1001] Small style fix


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 5b47b54..a35632a 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -388,6 +388,7 @@ font-size: 32pt;
 .modal-footer button {
   float: right;
 }
+
 button[id='delete_widget'] {
   float: left;
 }

From 8dd927b995a65f3ea24844193ca10f65108ac483 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 21 2016 20:03:25 +0000
Subject: [PATCH 410/1001] Fix typo in the hubs template


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 55485f5..ba68a0d 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -264,6 +264,6 @@ $.each(widgets, function(i, widget) {
   setup_edit_btns();
 });
 
-s</script>
+</script>
 </body>
 </html>

From 5d993792d20b2b5e729f5af6957b769ec0619e66 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 05:56:27 +0000
Subject: [PATCH 411/1001] Adjust the edit template as per @sayanchowdhury's suggestion


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index a35632a..6905d53 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -389,6 +389,7 @@ font-size: 32pt;
   float: right;
 }
 
-button[id='delete_widget'] {
-  float: left;
+.p-abs {
+  position: absolute;
+  bottom: 0;
 }
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index aa4f6fd..e31087a 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -35,13 +35,14 @@
           Save
         </button>
         {% endif %}
+      </div>
     </form>
     <form method="POST" action="{{ url_for(
-        'widget_edit_delete', hub=widget.hub.name, idx=widget.idx) }}">
+        'widget_edit_delete', hub=widget.hub.name, idx=widget.idx) }}"
+        class="modal-footer p-abs" >
         <button type="submit" class="btn btn-danger" id="delete_widget">
           Remove this widget
         </button>
     <form>
-      </div>
   </div>
 </div>

From df1d18ea7cbcf2d618b0511d6602b6716464155e Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 05:57:05 +0000
Subject: [PATCH 412/1001] Add a little space in between the Save and Close button in the panel


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 6905d53..5411960 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -387,6 +387,7 @@ font-size: 32pt;
 
 .modal-footer button {
   float: right;
+  margin-left: 1em;
 }
 
 .p-abs {

From f88c283e0ba68689992dbce232abe1883ecebe68 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 413/1001] Implement the endpoint used to update the ordering of the widget in a hub


---

diff --git a/hubs/app.py b/hubs/app.py
index 2cbaffe..abd610b 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -125,14 +125,57 @@ def hub_edit_get(name):
         'hubs.html', hub=hub, session=session, edit=True)
 
 
-@app.route('/<name>/edit/', methods=['POST'])
-@app.route('/<name>/edit', methods=['POST'])
+@app.route('/<name>/save/', methods=['POST'])
+@app.route('/<name>/save', methods=['POST'])
 def hub_edit_post(name):
-    #hub = get_hub(session, name)
-    # TODO -- save things to the db ... and then redirect
-    hub.last_edited = datetime.datetime.utcnow()
-    raise NotImplementedError('TODO - save changes to hub config')
-    flask.redirect(flask.url_for('hub', name=name))
+    hub = get_hub(session, name)
+
+    error = False
+    # Check the input submitted
+    widget_ids = [
+        w.strip().replace('widget-', '') for w in flask.request.form.getlist('widgets[]')
+        if w.strip()
+    ]
+    try:
+        widget_ids = [int(w) for w in widget_ids]
+    except:
+        flask.flash('Invalid widget identifiers submitted', 'error')
+        error = True
+
+    indexes = [
+        i.strip() for i in flask.request.form.getlist('indexes[]')
+        if i.strip()
+    ]
+
+    try:
+        indexes = [int(i) for i in indexes]
+    except:
+        flask.flash('Invalid indexes submitted', 'error')
+        error = True
+
+    if len(widget_ids) != len(indexes):
+        flask.flash(
+            'The number of indexes and the number of widgets are not of '
+            'the same length', 'error')
+        error = True
+
+    # If all good, update the database
+    if not error:
+        for cnt, wid in enumerate(widget_ids):
+            widget = hubs.models.Widget.get(session, wid)
+            if widget.index != indexes[cnt]:
+                widget.index = indexes[cnt]
+                session.add(widget)
+        hub.last_edited = datetime.datetime.utcnow()
+        session.add(hub)
+        try:
+            session.commit()
+        except Exception as err:
+            flask.flash(
+                'Could not save your changes to the database '\
+                'if the error persists, please warn an admin',
+                'error')
+    return flask.redirect(flask.url_for('hub', name=name))
 
 
 @app.route('/<hub>/<idx>/')

From 2b61fe4d866ce8496345b0693ad7a63f977856b7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 414/1001] Show a different button in the top right if we're in edit mode


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index ba68a0d..98e0f60 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -78,25 +78,41 @@
   </nav>
 </div>
 <div class="header">
-  {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
-    <div class="dropdown edit">
-      <span class="dropdown-toggle edit-this-page" type="button"
-            id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
-            aria-expanded="true">
-        <span class="glyphicon glyphicon-edit"></span> edit this page
-      </span>
-      <ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
-        <li><a href="#">Customize Header</a></li>
-        <li role="separator" class="divider"></li>
-        <li><a href="#">Configure Widgets</a></li>
-        {% if not hub.user_hub %}
-        <li role="separator" class="divider"></li>
-        <li><a href="#">Manage Members</a></li>
-        <li role="separator" class="divider"></li>
-        <li><a href="#">Archive Hub</a></li>
-        {% endif %}
-      </ul>
-    </div>
+  {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
+    {% if not edit %}
+      <div class="dropdown edit">
+        <span class="dropdown-toggle edit-this-page" type="button"
+              id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
+              aria-expanded="true">
+          <a href="{{ url_for('hub_edit_get', name=hub.name) }}">
+            <span class="glyphicon glyphicon-edit"></span> edit this page
+          </a>
+        </span>
+        <ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
+          <li><a href="#">Customize Header</a></li>
+          <li role="separator" class="divider"></li>
+          <li>
+            <a href="{{ url_for('hub_edit_get', name=hub.name) }}">
+              Configure hub
+            </a>
+          </li>
+          {% if not hub.user_hub %}
+          <li role="separator" class="divider"></li>
+          <li><a href="#">Manage Members</a></li>
+          <li role="separator" class="divider"></li>
+          <li><a href="#">Archive Hub</a></li>
+          {% endif %}
+        </ul>
+      </div>
+    {% else %}
+      <div class="dropdown edit">
+        <span id="dropdownMenu2">
+          <span id="save_edits_btn">
+            <span class="glyphicon glyphicon-save"></span> Save changes
+          </span>
+        </span>
+      </div>
+    {% endif %}
   {% endif %}
   {% if hub.user_hub %}
     <div class="padded center-block medium-wide">

From 983732ed1a43493702122b6d2d6fb9a288b3b0ea Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 415/1001] Simple code style changes


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 98e0f60..97309f9 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -116,16 +116,16 @@
   {% endif %}
   {% if hub.user_hub %}
     <div class="padded center-block medium-wide">
-      <img src="{{hub.avatar}}" class="avatar" />
-      <h3>{{hub.name}}</h3>
-      <h5>{{hub.summary}}</h5>
+      <img src="{{ hub.avatar }}" class="avatar" />
+      <h3>{{ hub.name }}</h3>
+      <h5>{{ hub.summary }}</h5>
       <div class="clearfix"></div>
     </div>
     {% else %}
     <div class="img-wrap">
-      <img src="{{hub.header_img}}" />
+      <img src="{{ hub.header_img }}" />
     </div>
-    <h3 class="team">{{hub.name}}</h3>
+    <h3 class="team">{{ hub.name }}</h3>
   {% endif %}
 </div>
 
@@ -179,7 +179,8 @@
           {% if hub.archived %}
             This hub has been archived and locked.
           {% else %}
-            Cobweb alert!  This hub was last active {{ hub.last_refreshed | days_since }} days ago.
+            Cobweb alert!  This hub was last active {{
+                hub.last_refreshed | days_since }} days ago.
           {% endif %}
           </div>
         </li>
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 92b0773..2e61dc7 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -39,6 +39,7 @@ paths = fmn.lib.load_rules(root='fmn.rules')
 #chrome = panel()
 template = templating.environment.get_template('templates/feed.html')
 
+
 def apply_markup(match):
     markup = match['subtitle']
     for username in match['usernames']:
@@ -175,6 +176,7 @@ def rehydrate_preference(preference):
 
     return preference
 
+
 def make_result(msg, d):
     return {
         'icon': fedmsg.meta.msg2icon(d, **config),

From b69eff53b84af0117fb74376425d382e74f34497 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 416/1001] Put the 'Add a widget' buttons at the top of the columns in edit mode


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 97309f9..5014c44 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -187,36 +187,44 @@
       </ul>
       {% endif %}
 
-      {% for widget in hub.left_widgets %}
-      <div id="widget-{{ widget.idx }}" class="row"></div>
-      {% endfor %}
-
       {% if edit %}
       <div id='add-widget-left' class='widget row'>
         <div class="panel panel-default panel-visible">
           <div class="panel-body">
-            <h4><a href="#"><span class="glyphicon glyphicon-plus"></span> Add a widget</a></h4>
+            <h4>
+              <a href="#"><span class="glyphicon glyphicon-plus">
+              </span> Add a widget</a>
+            </h4>
           </div>
         </div>
       </div>
       {% endif %}
-    </div>
 
-    <div class="col-md-{{ hub.right_width }}">
-      {% for widget in hub.right_widgets %}
-      <div id="widget-{{ widget.idx }}" class="widget row"></div>
+      {% for widget in hub.left_widgets %}
+      <div id="widget-{{ widget.idx }}" class="row"></div>
       {% endfor %}
+    </div>
 
+    <div class="col-md-{{ hub.right_width }}">
       {% if edit %}
       <div id='add-widget-right' class='widget row'>
         <div class="panel panel-default panel-visible">
           <div class="panel-body">
-            <h4><a href="#"><span class="glyphicon glyphicon-plus"></span> Add a widget</a></h4>
+            <h4>
+              <a href="#"><span class="glyphicon glyphicon-plus">
+              </span> Add a widget</a>
+            </h4>
           </div>
         </div>
       </div>
       {% endif %}
+
+      {% for widget in hub.right_widgets %}
+      <div id="widget-{{ widget.idx }}" class="widget row"></div>
+      {% endfor %}
+
     </div>
+
   </div>
 </div>
 

From f2f8850981f40f63e652fea1fb92054f35769db4 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 417/1001] Place the widgets in both columns into a specific div/section


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 5014c44..533282f 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -200,9 +200,11 @@
       </div>
       {% endif %}
 
-      {% for widget in hub.left_widgets %}
-      <div id="widget-{{ widget.idx }}" class="row"></div>
-      {% endfor %}
+      <div id="left_widgets">
+        {% for widget in hub.left_widgets %}
+        <div id="widget-{{ widget.idx }}" class="row"></div>
+        {% endfor %}
+      </div>
     </div>
 
     <div class="col-md-{{ hub.right_width }}">
@@ -219,10 +221,11 @@
       </div>
       {% endif %}
 
-      {% for widget in hub.right_widgets %}
-      <div id="widget-{{ widget.idx }}" class="widget row"></div>
-      {% endfor %}
-
+      <div id="right_widgets">
+        {% for widget in hub.right_widgets %}
+        <div id="widget-{{ widget.idx }}" class="widget row"></div>
+        {% endfor %}
+      </div>
     </div>
 
   </div>

From 6b845c2b4609c717060215078e4941d298d97bbe Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 418/1001] Make setting up the widget a dedicated function


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 533282f..39dd5bc 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -271,26 +271,34 @@ function setup_edit_btns() {
     return false;
   });
 }
-var widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
-$.each(widgets, function(i, widget) {
-  $.ajax({
-    url: widget,
-    dataType: 'html',
-    success: function(html) {
-      $('#widget-' + widget).html(html);
-      setTimeout(function() {
-        $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
-      }, 100);
-      setup_edit_btns()
-    },
-    error: function() {
-      $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
-      console.log('error');
-      console.trace();
-    },
+
+function setup_widgets(widgets) {
+  var all_widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
+  if (widgets == undefined) {
+    var widgets = all_widgets;
+  }
+  $.each(widgets, function(i, widget) {
+    $.ajax({
+      url: widget,
+      dataType: 'html',
+      success: function(html) {
+        $('#widget-' + widget).html(html);
+        setTimeout(function() {
+          $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
+        }, 100);
+        setup_edit_btns()
+      },
+      error: function() {
+        $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
+        console.log('error');
+        console.trace();
+      },
+    });
+    setup_edit_btns();
   });
-  setup_edit_btns();
-});
+}
+
+setup_widgets();
 
 </script>
 </body>

From 189128829ab3a63f29926e240c8d58a8c296bf6a Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 419/1001] Add the Sortable JS library


---

diff --git a/hubs/static/js/Sortable.min.js b/hubs/static/js/Sortable.min.js
new file mode 100644
index 0000000..e95d2a3
--- /dev/null
+++ b/hubs/static/js/Sortable.min.js
@@ -0,0 +1,2 @@
+/*! Sortable 1.4.2 - MIT | git://github.com/rubaxa/Sortable.git */
+!function(a){"use strict";"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=a():"undefined"!=typeof Package?Sortable=a():window.Sortable=a()}(function(){"use strict";function a(a,b){if(!a||!a.nodeType||1!==a.nodeType)throw"Sortable: `el` must be HTMLElement, and not "+{}.toString.call(a);this.el=a,this.options=b=r({},b),a[L]=this;var c={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[uo]l/i.test(a.nodeName)?"li":">*",ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",ignore:"a, img",filter:null,animation:0,setData:function(a,b){a.setData("Text",b.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1};for(var d in c)!(d in b)&&(b[d]=c[d]);V(b);for(var f in this)"_"===f.charAt(0)&&(this[f]=this[f].bind(this));this.nativeDraggable=b.forceFallback?!1:P,e(a,"mousedown",this._onTapStart),e(a,"touchstart",this._onTapStart),this.nativeDraggable&&(e(a,"dragover",this),e(a,"dragenter",this)),T.push(this._onDragOver),b.store&&this.sort(b.store.get(this))}function b(a){v&&v.state!==a&&(h(v,"display",a?"none":""),!a&&v.state&&w.insertBefore(v,s),v.state=a)}function c(a,b,c){if(a){c=c||N,b=b.split(".");var d=b.shift().toUpperCase(),e=new RegExp("\\s("+b.join("|")+")(?=\\s)","g");do if(">*"===d&&a.parentNode===c||(""===d||a.nodeName.toUpperCase()==d)&&(!b.length||((" "+a.className+" ").match(e)||[]).length==b.length))return a;while(a!==c&&(a=a.parentNode))}return null}function d(a){a.dataTransfer&&(a.dataTransfer.dropEffect="move"),a.preventDefault()}function e(a,b,c){a.addEventListener(b,c,!1)}function f(a,b,c){a.removeEventListener(b,c,!1)}function g(a,b,c){if(a)if(a.classList)a.classList[c?"add":"remove"](b);else{var d=(" "+a.className+" ").replace(K," ").replace(" "+b+" "," ");a.className=(d+(c?" "+b:"")).replace(K," ")}}function h(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return N.defaultView&&N.defaultView.getComputedStyle?c=N.defaultView.getComputedStyle(a,""):a.currentStyle&&(c=a.currentStyle),void 0===b?c:c[b];b in d||(b="-webkit-"+b),d[b]=c+("string"==typeof c?"":"px")}}function i(a,b,c){if(a){var d=a.getElementsByTagName(b),e=0,f=d.length;if(c)for(;f>e;e++)c(d[e],e);return d}return[]}function j(a,b,c,d,e,f,g){var h=N.createEvent("Event"),i=(a||b[L]).options,j="on"+c.charAt(0).toUpperCase()+c.substr(1);h.initEvent(c,!0,!0),h.to=b,h.from=e||b,h.item=d||b,h.clone=v,h.oldIndex=f,h.newIndex=g,b.dispatchEvent(h),i[j]&&i[j].call(a,h)}function k(a,b,c,d,e,f){var g,h,i=a[L],j=i.options.onMove;return g=N.createEvent("Event"),g.initEvent("move",!0,!0),g.to=b,g.from=a,g.dragged=c,g.draggedRect=d,g.related=e||b,g.relatedRect=f||b.getBoundingClientRect(),a.dispatchEvent(g),j&&(h=j.call(i,g)),h}function l(a){a.draggable=!1}function m(){R=!1}function n(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return(b.clientY-(d.top+d.height)>5||b.clientX-(d.right+d.width)>5)&&c}function o(a){for(var b=a.tagName+a.className+a.src+a.href+a.textContent,c=b.length,d=0;c--;)d+=b.charCodeAt(c);return d.toString(36)}function p(a){var b=0;if(!a||!a.parentNode)return-1;for(;a&&(a=a.previousElementSibling);)"TEMPLATE"!==a.nodeName.toUpperCase()&&b++;return b}function q(a,b){var c,d;return function(){void 0===c&&(c=arguments,d=this,setTimeout(function(){1===c.length?a.call(d,c[0]):a.apply(d,c),c=void 0},b))}}function r(a,b){if(a&&b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}var s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J={},K=/\s+/g,L="Sortable"+(new Date).getTime(),M=window,N=M.document,O=M.parseInt,P=!!("draggable"in N.createElement("div")),Q=function(a){return a=N.createElement("x"),a.style.cssText="pointer-events:auto","auto"===a.style.pointerEvents}(),R=!1,S=Math.abs,T=([].slice,[]),U=q(function(a,b,c){if(c&&b.scroll){var d,e,f,g,h=b.scrollSensitivity,i=b.scrollSpeed,j=a.clientX,k=a.clientY,l=window.innerWidth,m=window.innerHeight;if(z!==c&&(y=b.scroll,z=c,y===!0)){y=c;do if(y.offsetWidth<y.scrollWidth||y.offsetHeight<y.scrollHeight)break;while(y=y.parentNode)}y&&(d=y,e=y.getBoundingClientRect(),f=(S(e.right-j)<=h)-(S(e.left-j)<=h),g=(S(e.bottom-k)<=h)-(S(e.top-k)<=h)),f||g||(f=(h>=l-j)-(h>=j),g=(h>=m-k)-(h>=k),(f||g)&&(d=M)),(J.vx!==f||J.vy!==g||J.el!==d)&&(J.el=d,J.vx=f,J.vy=g,clearInterval(J.pid),d&&(J.pid=setInterval(function(){d===M?M.scrollTo(M.pageXOffset+f*i,M.pageYOffset+g*i):(g&&(d.scrollTop+=g*i),f&&(d.scrollLeft+=f*i))},24)))}},30),V=function(a){var b=a.group;b&&"object"==typeof b||(b=a.group={name:b}),["pull","put"].forEach(function(a){a in b||(b[a]=!0)}),a.groups=" "+b.name+(b.put.join?" "+b.put.join(" "):"")+" "};return a.prototype={constructor:a,_onTapStart:function(a){var b=this,d=this.el,e=this.options,f=a.type,g=a.touches&&a.touches[0],h=(g||a).target,i=h,k=e.filter;if(!("mousedown"===f&&0!==a.button||e.disabled)&&(h=c(h,e.draggable,d))){if(D=p(h),"function"==typeof k){if(k.call(this,a,h,this))return j(b,i,"filter",h,d,D),void a.preventDefault()}else if(k&&(k=k.split(",").some(function(a){return a=c(i,a.trim(),d),a?(j(b,a,"filter",h,d,D),!0):void 0})))return void a.preventDefault();(!e.handle||c(i,e.handle,d))&&this._prepareDragStart(a,g,h)}},_prepareDragStart:function(a,b,c){var d,f=this,h=f.el,j=f.options,k=h.ownerDocument;c&&!s&&c.parentNode===h&&(G=a,w=h,s=c,t=s.parentNode,x=s.nextSibling,F=j.group,d=function(){f._disableDelayedDrag(),s.draggable=!0,g(s,f.options.chosenClass,!0),f._triggerDragStart(b)},j.ignore.split(",").forEach(function(a){i(s,a.trim(),l)}),e(k,"mouseup",f._onDrop),e(k,"touchend",f._onDrop),e(k,"touchcancel",f._onDrop),j.delay?(e(k,"mouseup",f._disableDelayedDrag),e(k,"touchend",f._disableDelayedDrag),e(k,"touchcancel",f._disableDelayedDrag),e(k,"mousemove",f._disableDelayedDrag),e(k,"touchmove",f._disableDelayedDrag),f._dragStartTimer=setTimeout(d,j.delay)):d())},_disableDelayedDrag:function(){var a=this.el.ownerDocument;clearTimeout(this._dragStartTimer),f(a,"mouseup",this._disableDelayedDrag),f(a,"touchend",this._disableDelayedDrag),f(a,"touchcancel",this._disableDelayedDrag),f(a,"mousemove",this._disableDelayedDrag),f(a,"touchmove",this._disableDelayedDrag)},_triggerDragStart:function(a){a?(G={target:s,clientX:a.clientX,clientY:a.clientY},this._onDragStart(G,"touch")):this.nativeDraggable?(e(s,"dragend",this),e(w,"dragstart",this._onDragStart)):this._onDragStart(G,!0);try{N.selection?N.selection.empty():window.getSelection().removeAllRanges()}catch(b){}},_dragStarted:function(){w&&s&&(g(s,this.options.ghostClass,!0),a.active=this,j(this,w,"start",s,w,D))},_emulateDragOver:function(){if(H){if(this._lastX===H.clientX&&this._lastY===H.clientY)return;this._lastX=H.clientX,this._lastY=H.clientY,Q||h(u,"display","none");var a=N.elementFromPoint(H.clientX,H.clientY),b=a,c=" "+this.options.group.name,d=T.length;if(b)do{if(b[L]&&b[L].options.groups.indexOf(c)>-1){for(;d--;)T[d]({clientX:H.clientX,clientY:H.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);Q||h(u,"display","")}},_onTouchMove:function(b){if(G){a.active||this._dragStarted(),this._appendGhost();var c=b.touches?b.touches[0]:b,d=c.clientX-G.clientX,e=c.clientY-G.clientY,f=b.touches?"translate3d("+d+"px,"+e+"px,0)":"translate("+d+"px,"+e+"px)";I=!0,H=c,h(u,"webkitTransform",f),h(u,"mozTransform",f),h(u,"msTransform",f),h(u,"transform",f),b.preventDefault()}},_appendGhost:function(){if(!u){var a,b=s.getBoundingClientRect(),c=h(s),d=this.options;u=s.cloneNode(!0),g(u,d.ghostClass,!1),g(u,d.fallbackClass,!0),h(u,"top",b.top-O(c.marginTop,10)),h(u,"left",b.left-O(c.marginLeft,10)),h(u,"width",b.width),h(u,"height",b.height),h(u,"opacity","0.8"),h(u,"position","fixed"),h(u,"zIndex","100000"),h(u,"pointerEvents","none"),d.fallbackOnBody&&N.body.appendChild(u)||w.appendChild(u),a=u.getBoundingClientRect(),h(u,"width",2*b.width-a.width),h(u,"height",2*b.height-a.height)}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;this._offUpEvents(),"clone"==F.pull&&(v=s.cloneNode(!0),h(v,"display","none"),w.insertBefore(v,s)),b?("touch"===b?(e(N,"touchmove",this._onTouchMove),e(N,"touchend",this._onDrop),e(N,"touchcancel",this._onDrop)):(e(N,"mousemove",this._onTouchMove),e(N,"mouseup",this._onDrop)),this._loopId=setInterval(this._emulateDragOver,50)):(c&&(c.effectAllowed="move",d.setData&&d.setData.call(this,c,s)),e(N,"drop",this),setTimeout(this._dragStarted,0))},_onDragOver:function(a){var d,e,f,g=this.el,i=this.options,j=i.group,l=j.put,o=F===j,p=i.sort;if(void 0!==a.preventDefault&&(a.preventDefault(),!i.dragoverBubble&&a.stopPropagation()),I=!0,F&&!i.disabled&&(o?p||(f=!w.contains(s)):F.pull&&l&&(F.name===j.name||l.indexOf&&~l.indexOf(F.name)))&&(void 0===a.rootEl||a.rootEl===this.el)){if(U(a,i,this.el),R)return;if(d=c(a.target,i.draggable,g),e=s.getBoundingClientRect(),f)return b(!0),void(v||x?w.insertBefore(s,v||x):p||w.appendChild(s));if(0===g.children.length||g.children[0]===u||g===a.target&&(d=n(g,a))){if(d){if(d.animated)return;r=d.getBoundingClientRect()}b(o),k(w,g,s,e,d,r)!==!1&&(s.contains(g)||(g.appendChild(s),t=g),this._animate(e,s),d&&this._animate(r,d))}else if(d&&!d.animated&&d!==s&&void 0!==d.parentNode[L]){A!==d&&(A=d,B=h(d),C=h(d.parentNode));var q,r=d.getBoundingClientRect(),y=r.right-r.left,z=r.bottom-r.top,D=/left|right|inline/.test(B.cssFloat+B.display)||"flex"==C.display&&0===C["flex-direction"].indexOf("row"),E=d.offsetWidth>s.offsetWidth,G=d.offsetHeight>s.offsetHeight,H=(D?(a.clientX-r.left)/y:(a.clientY-r.top)/z)>.5,J=d.nextElementSibling,K=k(w,g,s,e,d,r);if(K!==!1){if(R=!0,setTimeout(m,30),b(o),1===K||-1===K)q=1===K;else if(D){var M=s.offsetTop,N=d.offsetTop;q=M===N?d.previousElementSibling===s&&!E||H&&E:N>M}else q=J!==s&&!G||H&&G;s.contains(g)||(q&&!J?g.appendChild(s):d.parentNode.insertBefore(s,q?J:d)),t=s.parentNode,this._animate(e,s),this._animate(r,d)}}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();h(b,"transition","none"),h(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,h(b,"transition","all "+c+"ms"),h(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){h(b,"transition",""),h(b,"transform",""),b.animated=!1},c)}},_offUpEvents:function(){var a=this.el.ownerDocument;f(N,"touchmove",this._onTouchMove),f(a,"mouseup",this._onDrop),f(a,"touchend",this._onDrop),f(a,"touchcancel",this._onDrop)},_onDrop:function(b){var c=this.el,d=this.options;clearInterval(this._loopId),clearInterval(J.pid),clearTimeout(this._dragStartTimer),f(N,"mousemove",this._onTouchMove),this.nativeDraggable&&(f(N,"drop",this),f(c,"dragstart",this._onDragStart)),this._offUpEvents(),b&&(I&&(b.preventDefault(),!d.dropBubble&&b.stopPropagation()),u&&u.parentNode.removeChild(u),s&&(this.nativeDraggable&&f(s,"dragend",this),l(s),g(s,this.options.ghostClass,!1),g(s,this.options.chosenClass,!1),w!==t?(E=p(s),E>=0&&(j(null,t,"sort",s,w,D,E),j(this,w,"sort",s,w,D,E),j(null,t,"add",s,w,D,E),j(this,w,"remove",s,w,D,E))):(v&&v.parentNode.removeChild(v),s.nextSibling!==x&&(E=p(s),E>=0&&(j(this,w,"update",s,w,D,E),j(this,w,"sort",s,w,D,E)))),a.active&&((null===E||-1===E)&&(E=D),j(this,w,"end",s,w,D,E),this.save())),w=s=t=u=x=v=y=z=G=H=I=E=A=B=F=a.active=null)},handleEvent:function(a){var b=a.type;"dragover"===b||"dragenter"===b?s&&(this._onDragOver(a),d(a)):("drop"===b||"dragend"===b)&&this._onDrop(a)},toArray:function(){for(var a,b=[],d=this.el.children,e=0,f=d.length,g=this.options;f>e;e++)a=d[e],c(a,g.draggable,this.el)&&b.push(a.getAttribute(g.dataIdAttr)||o(a));return b},sort:function(a){var b={},d=this.el;this.toArray().forEach(function(a,e){var f=d.children[e];c(f,this.options.draggable,d)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(d.removeChild(b[a]),d.appendChild(b[a]))})},save:function(){var a=this.options.store;a&&a.set(this)},closest:function(a,b){return c(a,b||this.options.draggable,this.el)},option:function(a,b){var c=this.options;return void 0===b?c[a]:(c[a]=b,void("group"===a&&V(c)))},destroy:function(){var a=this.el;a[L]=null,f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),this.nativeDraggable&&(f(a,"dragover",this),f(a,"dragenter",this)),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),T.splice(T.indexOf(this._onDragOver),1),this._onDrop(),this.el=a=null}},a.utils={on:e,off:f,css:h,find:i,is:function(a,b){return!!c(a,b,a)},extend:r,throttle:q,closest:c,toggleClass:g,index:p},a.create=function(b,c){return new a(b,c)},a.version="1.4.2",a});
\ No newline at end of file

From 04989290119c7e28e6e8d80024558a7bede37e4d Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 420/1001] Add the logic to move widgets around and save the order when clicking on the button


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 39dd5bc..8812893 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -242,6 +242,40 @@
   url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
 <script type="text/javascript" src="{{
   url_for('static', filename='js/utils.js') }}"></script>
+
+{% if edit %}
+<script type="text/javascript" src="{{
+  url_for('static', filename='bootstrap/js/Sortable.min.js') }}"></script>
+<script type="text/javascript">
+
+function make_widget_sortable() {
+  var byId = function (id) { return document.getElementById(id); }
+
+  Sortable.create(byId('right_widgets'), {
+    animation: 150,
+    draggable: '.widget',
+    handle: '.panel',
+  });
+
+};
+
+$('#save_edits_btn').click(function() {
+  var _indexes = [];
+  var _widgets = [];
+  $.each($('#right_widgets .widget'), function(i, el) {
+    _indexes.push(i);
+    _widgets.push($(el).attr('id').split('widget-')[1])
+  });
+
+  $.post(
+    '{{ url_for("hub_edit_post", name=hub.name) }}',
+    {'indexes': _indexes, 'widgets': _widgets},
+    setup_widgets(_widgets)
+  );
+});
+</script>
+{% endif %}
+
 <script type="text/javascript">
 function setup_edit_btns() {
   $(".edit_widget").unbind();
@@ -296,6 +330,10 @@ function setup_widgets(widgets) {
     });
     setup_edit_btns();
   });
+
+  {% if edit -%}
+  make_widget_sortable();
+  {%- endif %}
 }
 
 setup_widgets();

From cff0cff04ffd7ffea96441ef1dd3cc9de14827ee Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 421/1001] Make the `Save changes` button appear as clickable


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 5411960..0015476 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -394,3 +394,7 @@ font-size: 32pt;
   position: absolute;
   bottom: 0;
 }
+
+#save_edits_btn {
+    cursor: pointer;
+}

From 10f2baba277672f1c72977117974dca7a31c4e3c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 422/1001] Fix the path to the Sortable library


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 8812893..ebdb6b2 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -245,7 +245,7 @@
 
 {% if edit %}
 <script type="text/javascript" src="{{
-  url_for('static', filename='bootstrap/js/Sortable.min.js') }}"></script>
+  url_for('static', filename='js/Sortable.min.js') }}"></script>
 <script type="text/javascript">
 
 function make_widget_sortable() {

From 961115e384c666586936eb45e5872056a0884bb2 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:22:07 +0000
Subject: [PATCH 423/1001] Use a single hub_edit endpoint for both GET and POST requests


Somehow, the approach of splitting hub_edit into hub_edit_get and
hub_edit_post one accepted GET only and the other POST only did not
work (while it does for editing widget). I am not sure why.
This commit move to use a single endpoint for both GET and POST but
the logic remain split into two different methods.

---

diff --git a/hubs/app.py b/hubs/app.py
index abd610b..7b725a1 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -117,16 +117,20 @@ def hub_json(name):
     return response
 
 
-@app.route('/<name>/edit/', methods=['GET'])
-@app.route('/<name>/edit', methods=['GET'])
+@app.route('/<name>/edit/', methods=['GET', 'POST'])
+@app.route('/<name>/edit', methods=['GET', 'POST'])
+def hub_edit(name):
+    if flask.request.method == 'POST':
+        return hub_edit_post(name)
+    else:
+        return hub_edit_get(name)
+
+
 def hub_edit_get(name):
     hub = get_hub(session, name)
     return flask.render_template(
         'hubs.html', hub=hub, session=session, edit=True)
 
-
-@app.route('/<name>/save/', methods=['POST'])
-@app.route('/<name>/save', methods=['POST'])
 def hub_edit_post(name):
     hub = get_hub(session, name)
 
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index ebdb6b2..b9ab929 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -92,7 +92,7 @@
           <li><a href="#">Customize Header</a></li>
           <li role="separator" class="divider"></li>
           <li>
-            <a href="{{ url_for('hub_edit_get', name=hub.name) }}">
+            <a href="{{ url_for('hub_edit', name=hub.name) }}">
               Configure hub
             </a>
           </li>
@@ -268,7 +268,7 @@ $('#save_edits_btn').click(function() {
   });
 
   $.post(
-    '{{ url_for("hub_edit_post", name=hub.name) }}',
+    '{{ url_for("hub_edit", name=hub.name) }}',
     {'indexes': _indexes, 'widgets': _widgets},
     setup_widgets(_widgets)
   );

From 2ddf810909179d1cf959e2aea3b187cd3ce9d194 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:30:39 +0000
Subject: [PATCH 424/1001] Adjust hub_edit_post behavior for request made from javascript


If a POST request is made from javascript, we do not want to flash
messages, as they will appear the next time someone load a page,
potentially a completely different page.
So, we will assume request made from JS will declare themselves as such
using js=true and for them we will make things easier: work (200 OK) or
does not work (400), no message flashed.

---

diff --git a/hubs/app.py b/hubs/app.py
index 7b725a1..375816d 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -133,6 +133,7 @@ def hub_edit_get(name):
 
 def hub_edit_post(name):
     hub = get_hub(session, name)
+    is_js = flask.request.form.get('js', False)
 
     error = False
     # Check the input submitted
@@ -154,13 +155,15 @@ def hub_edit_post(name):
     try:
         indexes = [int(i) for i in indexes]
     except:
-        flask.flash('Invalid indexes submitted', 'error')
+        if not is_js:
+            flask.flash('Invalid indexes submitted', 'error')
         error = True
 
     if len(widget_ids) != len(indexes):
-        flask.flash(
-            'The number of indexes and the number of widgets are not of '
-            'the same length', 'error')
+        if not is_js:
+            flask.flash(
+                'The number of indexes and the number of widgets are not of '
+                'the same length', 'error')
         error = True
 
     # If all good, update the database
@@ -175,11 +178,20 @@ def hub_edit_post(name):
         try:
             session.commit()
         except Exception as err:
-            flask.flash(
-                'Could not save your changes to the database '\
-                'if the error persists, please warn an admin',
-                'error')
-    return flask.redirect(flask.url_for('hub', name=name))
+            error = True
+            if not is_js:
+                flask.flash(
+                    'Could not save your changes to the database '\
+                    'if the error persists, please warn an admin',
+                    'error')
+    if is_js:
+        if error:
+            flask.abort(400)
+        else:
+            return ('ok', 200)
+    else:
+        return flask.redirect(flask.url_for('hub', name=name))
+
 
 
 @app.route('/<hub>/<idx>/')

From 215081529b26c0ef7058266334f8f647f331cdfe Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:34:36 +0000
Subject: [PATCH 425/1001] Once we saved the changes, redirect to the normal page


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index b9ab929..508a62d 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -269,8 +269,8 @@ $('#save_edits_btn').click(function() {
 
   $.post(
     '{{ url_for("hub_edit", name=hub.name) }}',
-    {'indexes': _indexes, 'widgets': _widgets},
-    setup_widgets(_widgets)
+    {'indexes': _indexes, 'widgets': _widgets, 'js': true},
+    function(){ window.location = '{{ url_for("hub", name=hub.name) }}' }
   );
 });
 </script>

From e7e1615a13e60e57b2f58ad371c5658b1c8d952c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 22 2016 06:35:35 +0000
Subject: [PATCH 426/1001] Adjust HTML on the drop down menu to customize the hub


* Drop the link to hub_edit_get on the button since it is in fact
in the drop-down menu
* Fix case for Configure Hub

---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 508a62d..0b6f5a9 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -84,7 +84,7 @@
         <span class="dropdown-toggle edit-this-page" type="button"
               id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
               aria-expanded="true">
-          <a href="{{ url_for('hub_edit_get', name=hub.name) }}">
+          <a href="#">
             <span class="glyphicon glyphicon-edit"></span> edit this page
           </a>
         </span>
@@ -93,7 +93,7 @@
           <li role="separator" class="divider"></li>
           <li>
             <a href="{{ url_for('hub_edit', name=hub.name) }}">
-              Configure hub
+              Configure Hub
             </a>
           </li>
           {% if not hub.user_hub %}

From de17e44bf91f05446f1fd33c8eab01d4aa7ec577 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 06:26:16 +0000
Subject: [PATCH 427/1001] add runserver.py script with host & port args


This changes the way you run a dev server, with the
addition of runserver.py in the root dir of the project.

runserver.py now also has two arguments port and host
allowing the developer to choose the port and host that
their dev instance is running on.

The Readme is also updated adding the new way to start
the devserver, and also removing a few trailing white
spaces

---

diff --git a/README.rst b/README.rst
index c4b5f3d..2cf15e9 100644
--- a/README.rst
+++ b/README.rst
@@ -1,14 +1,15 @@
-Fedora Hubs will provide a communication and collaboration center for Fedora 
-contributors of all types. The idea is that contributors will be able to visit 
-Hubs to check on their involvements across Fedora, discover new places that they 
+Fedora Hubs will provide a communication and collaboration center for Fedora
+contributors of all types. The idea is that contributors will be able to visit
+Hubs to check on their involvements across Fedora, discover new places that they
 can contribute, and more.
 
-Hubs is currently under development, and you can see the progress on the 
+Hubs is currently under development, and you can see the progress on the
 Development instance here: http://209.132.184.98
 
 Mailing List
 ============
-We have a mailing list here: https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org/
+We have a mailing list here:
+https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org
 
 
 Hacking
@@ -44,7 +45,7 @@ OK -- with that done, now install the dependencies from PyPI::
 With that, try running the app with::
 
     $ PYTHONPATH=. python populate.py  # To create the db
-    $ PYTHONPATH=. python hubs/app.py  # To run the dev server
+    $ PYTHONPATH=. python runserver.py  # To run the dev server
 
 And then navigate to http://localhost:5000/
 
@@ -77,11 +78,11 @@ Some credentials...
 -------------------
 
 You need to add a new file to the ``fedmsg.d/`` directory.
-Call it ``fedmsg.d/credentials.py``.  It's needed to query FAS 
+Call it ``fedmsg.d/credentials.py``.  It's needed to query FAS
 for information about other users. When we deploy this thing to
 production, we'll use a system account for this but for now, just
 use your personal account. You don't want to accidentally share this
-with anyone else. so be sure to keep it private.  It should have 
+with anyone else. so be sure to keep it private.  It should have
 contents like this::
 
     config = {
diff --git a/hubs/app.py b/hubs/app.py
index 375816d..3732eea 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -480,7 +480,3 @@ def hub_leave(hub):
         return flask.abort(400)
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-if __name__ == '__main__':
-    app.run(debug=True)
diff --git a/runserver.py b/runserver.py
new file mode 100755
index 0000000..54e1c5f
--- /dev/null
+++ b/runserver.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python2
+
+import argparse
+import sys
+import os
+
+parser = argparse.ArgumentParser(
+    description='Run the Hubs app')
+parser.add_argument(
+    '--port', '-p', default=5000,
+    help='Port for Hubs to run on.')
+parser.add_argument(
+    '--host', default="127.0.0.1",
+    help='Hostname to listen on. When set to 0.0.0.0 the server is available \
+          externally. Defaults to 127.0.0.1 making the it only visible on \
+          localhost')
+
+args = parser.parse_args()
+
+from hubs.app import app
+
+app.run(debug=True, host=args.host, port=int(args.port))

From 4c96779dae6bf0fc4179c029ade2511092eea4ee Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 06:26:16 +0000
Subject: [PATCH 428/1001] removed the PYTHONPATH bit from the readme


---

diff --git a/README.rst b/README.rst
index 2cf15e9..7fe3e92 100644
--- a/README.rst
+++ b/README.rst
@@ -44,8 +44,8 @@ OK -- with that done, now install the dependencies from PyPI::
 
 With that, try running the app with::
 
-    $ PYTHONPATH=. python populate.py  # To create the db
-    $ PYTHONPATH=. python runserver.py  # To run the dev server
+    $ python populate.py  # To create the db
+    $ python runserver.py  # To run the dev server
 
 And then navigate to http://localhost:5000/
 

From 5c08a452642e1e641c39fdc6d418d32ef56029a4 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:13:22 +0000
Subject: [PATCH 429/1001] Changed bootstrap to use fedora-bootstrap


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 0b6f5a9..73aaad6 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -2,7 +2,7 @@
 <html lang='en'>
 <head>
   <title>{{ hub.name }}</title>
-  <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
+  <link href="https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
@@ -238,8 +238,7 @@
 
 <script type="text/javascript" src="{{
   url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
-<script type="text/javascript" src="{{
-  url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
+<script src="https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js"></script>
 <script type="text/javascript" src="{{
   url_for('static', filename='js/utils.js') }}"></script>
 

From 00aaaa1b56616096b4d264d48f3fdd6e08544ef1 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:13:22 +0000
Subject: [PATCH 430/1001] changed widget panels to cards


in bootstrap 4, there are no panel classes anymore, these
are replaced by "cards"

---

diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index fb78326..8a263df 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -1,4 +1,4 @@
-<div class="panel {{ klass }}">
+<div class="card {{ klass }}">
   {{ heading }}
   <div class="pull-right widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
@@ -9,7 +9,7 @@
       <span class="glyphicon glyphicon-edit"></span>
     </a>
   </div>
-  <div class="panel-body">
+  <div class="card-body">
     {{ content }}
-  </div> <!-- end panel-body -->
-</div> <!-- end panel -->
+  </div> <!-- end card-body -->
+</div> <!-- end card -->
diff --git a/hubs/widgets/templates/panel_heading.html b/hubs/widgets/templates/panel_heading.html
index d7d26f3..eab2086 100644
--- a/hubs/widgets/templates/panel_heading.html
+++ b/hubs/widgets/templates/panel_heading.html
@@ -1,5 +1,3 @@
-<div class="panel-heading">
-  <h3 class="panel-title">
+<div class="card-header">
     {{title}}
-  </h3>
-</div> <!-- end panel-heading -->
+</div> <!-- end card-header -->

From 793aed75b54af3d0a5e7f313fe2d6124c4c5bf43 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:15:13 +0000
Subject: [PATCH 431/1001] added a prebuilt version of fedora-bootstrap


---

diff --git a/hubs/static/fedora-bootstrap/fedora-bootstrap.css b/hubs/static/fedora-bootstrap/fedora-bootstrap.css
new file mode 100644
index 0000000..becb558
--- /dev/null
+++ b/hubs/static/fedora-bootstrap/fedora-bootstrap.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v4.0.0-alpha.2 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*,:after,:before{text-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]:after{content:" (" attr(title) ")"}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}@-moz-viewport{width:device-width}@-ms-viewport{width:device-width}@-o-viewport{width:device-width}@-webkit-viewport{width:device-width}@viewport{width:device-width}html{font-size:14px;-webkit-tap-highlight-color:transparent}body{font-family:Open Sans;font-size:1rem;line-height:1.5;color:#373a3c;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #818a91}address{font-style:normal;line-height:inherit}address,dl,ol,ul{margin-bottom:1rem}dl,ol,ul{margin-top:0}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}a{color:#0275d8;text-decoration:none}a:focus,a:hover{color:#014c8c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}pre{margin-top:0;margin-bottom:1rem}figure{margin:0 0 1rem}img{vertical-align:middle}[role=button]{cursor:pointer}[role=button],a,area,button,input,label,select,summary,textarea{touch-action:manipulation}table{background-color:transparent}caption{padding-top:.75rem;padding-bottom:.75rem;color:#818a91;caption-side:bottom}caption,th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,select,textarea{margin:0;line-height:inherit;border-radius:0}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}input[type=search]{box-sizing:inherit;-webkit-appearance:none}output{display:inline-block}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1{font-size:2rem}h2{font-size:1.75rem}h3{font-size:1.5rem}h4{font-size:1.25rem}h5,h6{font-size:1rem}.h1{font-size:2rem}.h2{font-size:1.75rem}.h3{font-size:1.5rem}.h4{font-size:1.25rem}.h5,.h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300}.display-2{font-size:5.5rem;font-weight:300}.display-3{font-size:4.5rem;font-weight:300}.display-4{font-size:3.5rem;font-weight:300}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.dl-horizontal{margin-right:-1.875rem;margin-left:-1.875rem}.dl-horizontal:after{content:"";display:table;clear:both}.initialism{font-size:90%;text-transform:uppercase}.blockquote{padding:.5rem 1rem;margin-bottom:1rem;font-size:1.25rem;border-left:.25rem solid #eceeef}.blockquote-footer{display:block;font-size:80%;line-height:1.5;color:#818a91}.blockquote-footer:before{content:"\2014   \A0"}.blockquote-reverse{padding-right:1rem;padding-left:0;text-align:right;border-right:.25rem solid #eceeef;border-left:0}.blockquote-reverse .blockquote-footer:before{content:""}.blockquote-reverse .blockquote-footer:after{content:"\A0   \2014"}.carousel-inner>.carousel-item>a>img,.carousel-inner>.carousel-item>img,.img-fluid{display:block;max-width:100%;height:auto}.img-rounded{border-radius:.3rem}.img-thumbnail{padding:.25rem;line-height:1.5;background-color:#fff;border:1px solid #ddd;border-radius:.25rem;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#818a91}code,kbd,pre,samp{font-family:Hack,monospace}code{color:#bd4147;background-color:#f7f7f9;border-radius:.25rem}code,kbd{padding:.2rem .4rem;font-size:90%}kbd{color:#fff;background-color:#333;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;margin-top:0;margin-bottom:1rem;font-size:90%;line-height:1.5;color:#586e75}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-left:auto;margin-right:auto;padding-left:.9375rem;padding-right:.9375rem}.container:after{content:"";display:table;clear:both}@media (min-width:544px){.container{max-width:6in}}@media (min-width:768px){.container{max-width:45pc}}@media (min-width:992px){.container{max-width:940px}}@media (min-width:1200px){.container{max-width:855pt}}.container-fluid{margin-left:auto;margin-right:auto;padding-left:.9375rem;padding-right:.9375rem}.container-fluid:after{content:"";display:table;clear:both}.row{margin-left:-.9375rem;margin-right:-.9375rem}.row:after{content:"";display:table;clear:both}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{position:relative;min-height:1px;padding-left:.9375rem;padding-right:.9375rem}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-1{width:8.33333%}.col-xs-2{width:16.66667%}.col-xs-3{width:25%}.col-xs-4{width:33.33333%}.col-xs-5{width:41.66667%}.col-xs-6{width:50%}.col-xs-7{width:58.33333%}.col-xs-8{width:66.66667%}.col-xs-9{width:75%}.col-xs-10{width:83.33333%}.col-xs-11{width:91.66667%}.col-xs-12{width:100%}.col-xs-pull-0{right:auto}.col-xs-pull-1{right:8.33333%}.col-xs-pull-2{right:16.66667%}.col-xs-pull-3{right:25%}.col-xs-pull-4{right:33.33333%}.col-xs-pull-5{right:41.66667%}.col-xs-pull-6{right:50%}.col-xs-pull-7{right:58.33333%}.col-xs-pull-8{right:66.66667%}.col-xs-pull-9{right:75%}.col-xs-pull-10{right:83.33333%}.col-xs-pull-11{right:91.66667%}.col-xs-pull-12{right:100%}.col-xs-push-0{left:auto}.col-xs-push-1{left:8.33333%}.col-xs-push-2{left:16.66667%}.col-xs-push-3{left:25%}.col-xs-push-4{left:33.33333%}.col-xs-push-5{left:41.66667%}.col-xs-push-6{left:50%}.col-xs-push-7{left:58.33333%}.col-xs-push-8{left:66.66667%}.col-xs-push-9{left:75%}.col-xs-push-10{left:83.33333%}.col-xs-push-11{left:91.66667%}.col-xs-push-12{left:100%}.col-xs-offset-0{margin-left:0}.col-xs-offset-1{margin-left:8.33333%}.col-xs-offset-2{margin-left:16.66667%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-4{margin-left:33.33333%}.col-xs-offset-5{margin-left:41.66667%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-7{margin-left:58.33333%}.col-xs-offset-8{margin-left:66.66667%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-10{margin-left:83.33333%}.col-xs-offset-11{margin-left:91.66667%}.col-xs-offset-12{margin-left:100%}@media (min-width:544px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-1{width:8.33333%}.col-sm-2{width:16.66667%}.col-sm-3{width:25%}.col-sm-4{width:33.33333%}.col-sm-5{width:41.66667%}.col-sm-6{width:50%}.col-sm-7{width:58.33333%}.col-sm-8{width:66.66667%}.col-sm-9{width:75%}.col-sm-10{width:83.33333%}.col-sm-11{width:91.66667%}.col-sm-12{width:100%}.col-sm-pull-0{right:auto}.col-sm-pull-1{right:8.33333%}.col-sm-pull-2{right:16.66667%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.33333%}.col-sm-pull-5{right:41.66667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.33333%}.col-sm-pull-8{right:66.66667%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.33333%}.col-sm-pull-11{right:91.66667%}.col-sm-pull-12{right:100%}.col-sm-push-0{left:auto}.col-sm-push-1{left:8.33333%}.col-sm-push-2{left:16.66667%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.33333%}.col-sm-push-5{left:41.66667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.33333%}.col-sm-push-8{left:66.66667%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.33333%}.col-sm-push-11{left:91.66667%}.col-sm-push-12{left:100%}.col-sm-offset-0{margin-left:0}.col-sm-offset-1{margin-left:8.33333%}.col-sm-offset-2{margin-left:16.66667%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.33333%}.col-sm-offset-5{margin-left:41.66667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.33333%}.col-sm-offset-8{margin-left:66.66667%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.33333%}.col-sm-offset-11{margin-left:91.66667%}.col-sm-offset-12{margin-left:100%}}@media (min-width:768px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-1{width:8.33333%}.col-md-2{width:16.66667%}.col-md-3{width:25%}.col-md-4{width:33.33333%}.col-md-5{width:41.66667%}.col-md-6{width:50%}.col-md-7{width:58.33333%}.col-md-8{width:66.66667%}.col-md-9{width:75%}.col-md-10{width:83.33333%}.col-md-11{width:91.66667%}.col-md-12{width:100%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.33333%}.col-md-pull-2{right:16.66667%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.33333%}.col-md-pull-5{right:41.66667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.33333%}.col-md-pull-8{right:66.66667%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.33333%}.col-md-pull-11{right:91.66667%}.col-md-pull-12{right:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.33333%}.col-md-push-2{left:16.66667%}.col-md-push-3{left:25%}.col-md-push-4{left:33.33333%}.col-md-push-5{left:41.66667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.33333%}.col-md-push-8{left:66.66667%}.col-md-push-9{left:75%}.col-md-push-10{left:83.33333%}.col-md-push-11{left:91.66667%}.col-md-push-12{left:100%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.33333%}.col-md-offset-2{margin-left:16.66667%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.33333%}.col-md-offset-5{margin-left:41.66667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.33333%}.col-md-offset-8{margin-left:66.66667%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.33333%}.col-md-offset-11{margin-left:91.66667%}.col-md-offset-12{margin-left:100%}}@media (min-width:992px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-1{width:8.33333%}.col-lg-2{width:16.66667%}.col-lg-3{width:25%}.col-lg-4{width:33.33333%}.col-lg-5{width:41.66667%}.col-lg-6{width:50%}.col-lg-7{width:58.33333%}.col-lg-8{width:66.66667%}.col-lg-9{width:75%}.col-lg-10{width:83.33333%}.col-lg-11{width:91.66667%}.col-lg-12{width:100%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.33333%}.col-lg-pull-2{right:16.66667%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.33333%}.col-lg-pull-5{right:41.66667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.33333%}.col-lg-pull-8{right:66.66667%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.33333%}.col-lg-pull-11{right:91.66667%}.col-lg-pull-12{right:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.33333%}.col-lg-push-2{left:16.66667%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.33333%}.col-lg-push-5{left:41.66667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.33333%}.col-lg-push-8{left:66.66667%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.33333%}.col-lg-push-11{left:91.66667%}.col-lg-push-12{left:100%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.33333%}.col-lg-offset-2{margin-left:16.66667%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.33333%}.col-lg-offset-5{margin-left:41.66667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.33333%}.col-lg-offset-8{margin-left:66.66667%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.33333%}.col-lg-offset-11{margin-left:91.66667%}.col-lg-offset-12{margin-left:100%}}@media (min-width:1200px){.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{float:left}.col-xl-1{width:8.33333%}.col-xl-2{width:16.66667%}.col-xl-3{width:25%}.col-xl-4{width:33.33333%}.col-xl-5{width:41.66667%}.col-xl-6{width:50%}.col-xl-7{width:58.33333%}.col-xl-8{width:66.66667%}.col-xl-9{width:75%}.col-xl-10{width:83.33333%}.col-xl-11{width:91.66667%}.col-xl-12{width:100%}.col-xl-pull-0{right:auto}.col-xl-pull-1{right:8.33333%}.col-xl-pull-2{right:16.66667%}.col-xl-pull-3{right:25%}.col-xl-pull-4{right:33.33333%}.col-xl-pull-5{right:41.66667%}.col-xl-pull-6{right:50%}.col-xl-pull-7{right:58.33333%}.col-xl-pull-8{right:66.66667%}.col-xl-pull-9{right:75%}.col-xl-pull-10{right:83.33333%}.col-xl-pull-11{right:91.66667%}.col-xl-pull-12{right:100%}.col-xl-push-0{left:auto}.col-xl-push-1{left:8.33333%}.col-xl-push-2{left:16.66667%}.col-xl-push-3{left:25%}.col-xl-push-4{left:33.33333%}.col-xl-push-5{left:41.66667%}.col-xl-push-6{left:50%}.col-xl-push-7{left:58.33333%}.col-xl-push-8{left:66.66667%}.col-xl-push-9{left:75%}.col-xl-push-10{left:83.33333%}.col-xl-push-11{left:91.66667%}.col-xl-push-12{left:100%}.col-xl-offset-0{margin-left:0}.col-xl-offset-1{margin-left:8.33333%}.col-xl-offset-2{margin-left:16.66667%}.col-xl-offset-3{margin-left:25%}.col-xl-offset-4{margin-left:33.33333%}.col-xl-offset-5{margin-left:41.66667%}.col-xl-offset-6{margin-left:50%}.col-xl-offset-7{margin-left:58.33333%}.col-xl-offset-8{margin-left:66.66667%}.col-xl-offset-9{margin-left:75%}.col-xl-offset-10{margin-left:83.33333%}.col-xl-offset-11{margin-left:91.66667%}.col-xl-offset-12{margin-left:100%}}.table{width:100%;max-width:100%;margin-bottom:1rem}.table td,.table th{padding:.75rem;line-height:1.5;vertical-align:top;border-top:1px solid #eceeef}.table thead th{vertical-align:bottom;border-bottom:2px solid #eceeef}.table tbody+tbody{border-top:2px solid #eceeef}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #eceeef}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:#f9f9f9}.table-active,.table-active>td,.table-active>th,.table-hover tbody tr:hover{background-color:#f5f5f5}.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:#e8e8e8}.table-success,.table-success>td,.table-success>th{background-color:#dff0d8}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#d0e9c6}.table-info,.table-info>td,.table-info>th{background-color:#d9edf7}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#c4e3f3}.table-warning,.table-warning>td,.table-warning>th{background-color:#fcf8e3}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#faf2cc}.table-danger,.table-danger>td,.table-danger>th{background-color:#f2dede}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#ebcccc}.table-responsive{display:block;width:100%;min-height:.01%;overflow-x:auto}.thead-inverse th{color:#fff;background-color:#373a3c}.thead-default th{color:#55595c;background-color:#eceeef}.table-inverse{color:#eceeef;background-color:#373a3c}.table-inverse.table-bordered{border:0}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#55595c}.table-reflow thead{float:left}.table-reflow tbody{display:block;white-space:nowrap}.table-reflow td,.table-reflow th{border-top:1px solid #eceeef;border-left:1px solid #eceeef}.table-reflow td:last-child,.table-reflow th:last-child{border-right:1px solid #eceeef}.table-reflow tbody:last-child tr:last-child td,.table-reflow tbody:last-child tr:last-child th,.table-reflow tfoot:last-child tr:last-child td,.table-reflow tfoot:last-child tr:last-child th,.table-reflow thead:last-child tr:last-child td,.table-reflow thead:last-child tr:last-child th{border-bottom:1px solid #eceeef}.table-reflow tr{float:left}.table-reflow tr td,.table-reflow tr th{display:block!important;border:1px solid #eceeef}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#55595c;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:.25rem}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{border-color:#66afe9;outline:0}.form-control::placeholder{color:#999;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#eceeef;opacity:1}.form-control:disabled{cursor:not-allowed}.form-control-file,.form-control-range{display:block}.form-control-label{padding:.375rem .75rem;margin-bottom:0}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{line-height:2.25rem}.input-group-sm input[type=date].form-control,.input-group-sm input[type=datetime-local].form-control,.input-group-sm input[type=month].form-control,.input-group-sm input[type=time].form-control,input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:1.8625rem}.input-group-lg input[type=date].form-control,.input-group-lg input[type=datetime-local].form-control,.input-group-lg input[type=month].form-control,.input-group-lg input[type=time].form-control,input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:3.16667rem}}.form-control-static{min-height:2.25rem;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0}.form-control-static.form-control-lg,.form-control-static.form-control-sm,.input-group-lg>.form-control-static.form-control,.input-group-lg>.form-control-static.input-group-addon,.input-group-lg>.input-group-btn>.form-control-static.btn,.input-group-sm>.form-control-static.form-control,.input-group-sm>.form-control-static.input-group-addon,.input-group-sm>.input-group-btn>.form-control-static.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.275rem .75rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.75rem 1.25rem;font-size:1.25rem;line-height:1.33333;border-radius:.3rem}.form-group{margin-bottom:1rem}.checkbox,.radio{position:relative;display:block;margin-bottom:.75rem}.checkbox label,.radio label{padding-left:1.25rem;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox label input:only-child,.radio label input:only-child{position:static}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:.25rem;margin-left:-1.25rem}.checkbox+.checkbox,.radio+.radio{margin-top:-.25rem}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:1.25rem;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:.75rem}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,input[type=checkbox].disabled,input[type=checkbox]:disabled,input[type=radio].disabled,input[type=radio]:disabled{cursor:not-allowed}.form-control-danger,.form-control-success,.form-control-warning{padding-right:2.25rem;background-repeat:no-repeat;background-position:center right .5625rem;background-size:1.4625rem 1.4625rem}.has-success .checkbox,.has-success .checkbox-inline,.has-success .form-control-label,.has-success .radio,.has-success .radio-inline,.has-success .text-help,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#5cb85c}.has-success .form-control{border-color:#5cb85c}.has-success .input-group-addon{color:#5cb85c;border-color:#5cb85c;background-color:#eaf6ea}.has-success .form-control-feedback{color:#5cb85c}.has-success .form-control-success{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjNWNiODVjIiBkPSJNMjMzLjggNjEwYy0xMy4zIDAtMjYtNi0zNC0xNi44TDkwLjUgNDQ4LjhDNzYuMyA0MzAgODAgNDAzLjMgOTguOCAzODljMTguOC0xNC4yIDQ1LjUtMTAuNCA1OS44IDguNGw3MiA5NUw0NTEuMyAyNDJjMTIuNS0yMCAzOC44LTI2LjIgNTguOC0xMy43IDIwIDEyLjQgMjYgMzguNyAxMy43IDU4LjhMMjcwIDU5MGMtNy40IDEyLTIwLjIgMTkuNC0zNC4zIDIwaC0yeiIvPjwvc3ZnPg==")}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .form-control-label,.has-warning .radio,.has-warning .radio-inline,.has-warning .text-help,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#f0ad4e}.has-warning .form-control{border-color:#f0ad4e}.has-warning .input-group-addon{color:#f0ad4e;border-color:#f0ad4e;background-color:#fff}.has-warning .form-control-feedback{color:#f0ad4e}.has-warning .form-control-warning{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZjBhZDRlIiBkPSJNNjAzIDY0MC4ybC0yNzguNS01MDljLTMuOC02LjYtMTAuOC0xMC42LTE4LjUtMTAuNnMtMTQuNyA0LTE4LjUgMTAuNkw5IDY0MC4yYy0zLjcgNi41LTMuNiAxNC40LjIgMjAuOCAzLjggNi41IDEwLjggMTAuNCAxOC4zIDEwLjRoNTU3YzcuNiAwIDE0LjYtNCAxOC40LTEwLjQgMy41LTYuNCAzLjYtMTQuNCAwLTIwLjh6bS0yNjYuNC0zMGgtNjEuMlY1NDloNjEuMnY2MS4yem0wLTEwN2gtNjEuMlYzMDRoNjEuMnYxOTl6Ii8+PC9zdmc+")}.has-danger .checkbox,.has-danger .checkbox-inline,.has-danger .form-control-label,.has-danger .radio,.has-danger .radio-inline,.has-danger .text-help,.has-danger.checkbox label,.has-danger.checkbox-inline label,.has-danger.radio label,.has-danger.radio-inline label{color:#d9534f}.has-danger .form-control{border-color:#d9534f}.has-danger .input-group-addon{color:#d9534f;border-color:#d9534f;background-color:#fdf7f7}.has-danger .form-control-feedback{color:#d9534f}.has-danger .form-control-danger{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZDk1MzRmIiBkPSJNNDQ3IDU0NC40Yy0xNC40IDE0LjQtMzcuNiAxNC40LTUyIDBsLTg5LTkyLjctODkgOTIuN2MtMTQuNSAxNC40LTM3LjcgMTQuNC01MiAwLTE0LjQtMTQuNC0xNC40LTM3LjYgMC01Mmw5Mi40LTk2LjMtOTIuNC05Ni4zYy0xNC40LTE0LjQtMTQuNC0zNy42IDAtNTJzMzcuNi0xNC4zIDUyIDBsODkgOTIuOCA4OS4yLTkyLjdjMTQuNC0xNC40IDM3LjYtMTQuNCA1MiAwIDE0LjMgMTQuNCAxNC4zIDM3LjYgMCA1MkwzNTQuNiAzOTZsOTIuNCA5Ni40YzE0LjQgMTQuNCAxNC40IDM3LjYgMCA1MnoiLz48L3N2Zz4=")}@media (min-width:544px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .form-control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;user-select:none;border:1px solid transparent;padding:.375rem 1rem;font-size:1rem;line-height:1.5;border-radius:.25rem}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0}.btn.disabled,.btn:disabled{cursor:not-allowed;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary.focus,.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#025aa5;border-color:#01549b}.btn-primary.active,.btn-primary:active,.open>.btn-primary.dropdown-toggle{color:#fff;background-color:#025aa5;border-color:#01549b;background-image:none}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.btn-primary.dropdown-toggle.focus,.open>.btn-primary.dropdown-toggle:focus,.open>.btn-primary.dropdown-toggle:hover{color:#fff;background-color:#014682;border-color:#01315a}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary:disabled.focus,.btn-primary:disabled:focus,.btn-primary:disabled:hover{background-color:#0275d8;border-color:#0275d8}.btn-secondary{color:#373a3c;background-color:#fff;border-color:#ccc}.btn-secondary.focus,.btn-secondary:focus,.btn-secondary:hover{color:#373a3c;background-color:#e6e6e6;border-color:#adadad}.btn-secondary.active,.btn-secondary:active,.open>.btn-secondary.dropdown-toggle{color:#373a3c;background-color:#e6e6e6;border-color:#adadad;background-image:none}.btn-secondary.active.focus,.btn-secondary.active:focus,.btn-secondary.active:hover,.btn-secondary:active.focus,.btn-secondary:active:focus,.btn-secondary:active:hover,.open>.btn-secondary.dropdown-toggle.focus,.open>.btn-secondary.dropdown-toggle:focus,.open>.btn-secondary.dropdown-toggle:hover{color:#373a3c;background-color:#d4d4d4;border-color:#8c8c8c}.btn-secondary.disabled.focus,.btn-secondary.disabled:focus,.btn-secondary.disabled:hover,.btn-secondary:disabled.focus,.btn-secondary:disabled:focus,.btn-secondary:disabled:hover{background-color:#fff;border-color:#ccc}.btn-info{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info.focus,.btn-info:focus,.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#2aabd2}.btn-info.active,.btn-info:active,.open>.btn-info.dropdown-toggle{color:#fff;background-color:#31b0d5;border-color:#2aabd2;background-image:none}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.btn-info.dropdown-toggle.focus,.open>.btn-info.dropdown-toggle:focus,.open>.btn-info.dropdown-toggle:hover{color:#fff;background-color:#269abc;border-color:#1f7e9a}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info:disabled.focus,.btn-info:disabled:focus,.btn-info:disabled:hover{background-color:#5bc0de;border-color:#5bc0de}.btn-success{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success.focus,.btn-success:focus,.btn-success:hover{color:#fff;background-color:#449d44;border-color:#419641}.btn-success.active,.btn-success:active,.open>.btn-success.dropdown-toggle{color:#fff;background-color:#449d44;border-color:#419641;background-image:none}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.btn-success.dropdown-toggle.focus,.open>.btn-success.dropdown-toggle:focus,.open>.btn-success.dropdown-toggle:hover{color:#fff;background-color:#398439;border-color:#2d672d}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success:disabled.focus,.btn-success:disabled:focus,.btn-success:disabled:hover{background-color:#5cb85c;border-color:#5cb85c}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning.focus,.btn-warning:focus,.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#eb9316}.btn-warning.active,.btn-warning:active,.open>.btn-warning.dropdown-toggle{color:#fff;background-color:#ec971f;border-color:#eb9316;background-image:none}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.btn-warning.dropdown-toggle.focus,.open>.btn-warning.dropdown-toggle:focus,.open>.btn-warning.dropdown-toggle:hover{color:#fff;background-color:#d58512;border-color:#b06d0f}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning:disabled.focus,.btn-warning:disabled:focus,.btn-warning:disabled:hover{background-color:#f0ad4e;border-color:#f0ad4e}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger.focus,.btn-danger:focus,.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#c12e2a}.btn-danger.active,.btn-danger:active,.open>.btn-danger.dropdown-toggle{color:#fff;background-color:#c9302c;border-color:#c12e2a;background-image:none}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.btn-danger.dropdown-toggle.focus,.open>.btn-danger.dropdown-toggle:focus,.open>.btn-danger.dropdown-toggle:hover{color:#fff;background-color:#ac2925;border-color:#8b211e}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger:disabled.focus,.btn-danger:disabled:focus,.btn-danger:disabled:hover{background-color:#d9534f;border-color:#d9534f}.btn-primary-outline{color:#0275d8;background-image:none;background-color:transparent;border-color:#0275d8}.btn-primary-outline.active,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline:focus,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary-outline.disabled.focus,.btn-primary-outline.disabled:focus,.btn-primary-outline.disabled:hover,.btn-primary-outline:disabled.focus,.btn-primary-outline:disabled:focus,.btn-primary-outline:disabled:hover{border-color:#43a7fd}.btn-secondary-outline{color:#ccc;background-image:none;background-color:transparent;border-color:#ccc}.btn-secondary-outline.active,.btn-secondary-outline.focus,.btn-secondary-outline:active,.btn-secondary-outline:focus,.btn-secondary-outline:hover,.open>.btn-secondary-outline.dropdown-toggle{color:#fff;background-color:#ccc;border-color:#ccc}.btn-secondary-outline.disabled.focus,.btn-secondary-outline.disabled:focus,.btn-secondary-outline.disabled:hover,.btn-secondary-outline:disabled.focus,.btn-secondary-outline:disabled:focus,.btn-secondary-outline:disabled:hover{border-color:#fff}.btn-info-outline{color:#5bc0de;background-image:none;background-color:transparent;border-color:#5bc0de}.btn-info-outline.active,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline:focus,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info-outline.disabled.focus,.btn-info-outline.disabled:focus,.btn-info-outline.disabled:hover,.btn-info-outline:disabled.focus,.btn-info-outline:disabled:focus,.btn-info-outline:disabled:hover{border-color:#b0e1ef}.btn-success-outline{color:#5cb85c;background-image:none;background-color:transparent;border-color:#5cb85c}.btn-success-outline.active,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline:focus,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success-outline.disabled.focus,.btn-success-outline.disabled:focus,.btn-success-outline.disabled:hover,.btn-success-outline:disabled.focus,.btn-success-outline:disabled:focus,.btn-success-outline:disabled:hover{border-color:#a3d7a3}.btn-warning-outline{color:#f0ad4e;background-image:none;background-color:transparent;border-color:#f0ad4e}.btn-warning-outline.active,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline:focus,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning-outline.disabled.focus,.btn-warning-outline.disabled:focus,.btn-warning-outline.disabled:hover,.btn-warning-outline:disabled.focus,.btn-warning-outline:disabled:focus,.btn-warning-outline:disabled:hover{border-color:#f8d9ac}.btn-danger-outline{color:#d9534f;background-image:none;background-color:transparent;border-color:#d9534f}.btn-danger-outline.active,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline:focus,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger-outline.disabled.focus,.btn-danger-outline.disabled:focus,.btn-danger-outline.disabled:hover,.btn-danger-outline:disabled.focus,.btn-danger-outline:disabled:focus,.btn-danger-outline:disabled:hover{border-color:#eba5a3}.btn-link{font-weight:400;color:#0275d8;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#014c8c;text-decoration:underline;background-color:transparent}.btn-link:disabled:focus,.btn-link:disabled:hover{color:#818a91;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.75rem 1.25rem;font-size:1.25rem;line-height:1.33333;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .75rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{height:0;overflow:hidden;transition-timing-function:ease;transition-duration:.35s;transition-property:height}.collapsing,.dropdown,.dropup{position:relative}.dropdown-toggle:after{display:inline-block;width:0;height:0;margin-right:.25rem;margin-left:.25rem;vertical-align:middle;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:focus{outline:0}.dropup .dropdown-toggle:after{border-top:0;border-bottom:.3em solid}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10pc;padding:5px 0;margin:2px 0 0;font-size:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-divider{height:1px;margin:.5rem 0;overflow:hidden;background-color:#e5e5e5}.dropdown-item{display:block;width:100%;padding:3px 20px;clear:both;font-weight:400;line-height:1.5;color:#373a3c;text-align:inherit;white-space:nowrap;background:none;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#2b2d2f;text-decoration:none;background-color:#f5f5f5}.dropdown-item.active,.dropdown-item.active:focus,.dropdown-item.active:hover{color:#fff;text-decoration:none;background-color:#0275d8;outline:0}.dropdown-item.disabled,.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{color:#818a91}.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:"progid:DXImageTransform.Microsoft.gradient(enabled = false)"}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:.875rem;line-height:1.5;color:#818a91;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:.3em solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar:after{content:"";display:table;clear:both}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group-lg.btn-group>.btn+.dropdown-toggle,.btn-group>.btn-lg+.dropdown-toggle{padding-right:9pt;padding-left:9pt}.btn .caret{margin-left:0}.btn-group-lg>.btn .caret,.btn-lg .caret{border-width:.3em .3em 0;border-bottom-width:0}.dropup .btn-group-lg>.btn .caret,.dropup .btn-lg .caret{border-width:0 .3em .3em}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:after{content:"";display:table;clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:.25rem;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:.25rem;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover{z-index:3}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1;color:#55595c;text-align:center;background-color:#eceeef;border:1px solid #ccc;border-radius:.25rem}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.275rem .75rem;font-size:.875rem;border-radius:.2rem}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.75rem 1.25rem;font-size:1.25rem;border-radius:.3rem}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{font-size:0;white-space:nowrap}.input-group-btn,.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.input-group-btn:last-child>.btn-group:active,.input-group-btn:last-child>.btn-group:focus,.input-group-btn:last-child>.btn-group:hover,.input-group-btn:last-child>.btn:active,.input-group-btn:last-child>.btn:focus,.input-group-btn:last-child>.btn:hover{z-index:3}.c-input{position:relative;display:inline;padding-left:1.5rem;color:#555;cursor:pointer}.c-input>input{position:absolute;z-index:-1;opacity:0}.c-input>input:checked~.c-indicator{color:#fff;background-color:#0074d9}.c-input>input:focus~.c-indicator{box-shadow:0 0 0 .075rem #fff,0 0 0 .2rem #0074d9}.c-input>input:active~.c-indicator{color:#fff;background-color:#84c6ff}.c-input+.c-input{margin-left:1rem}.c-indicator{position:absolute;top:0;left:0;display:block;width:1rem;height:1rem;font-size:65%;line-height:1rem;color:#eee;text-align:center;user-select:none;background-color:#eee;background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.c-checkbox .c-indicator{border-radius:.25rem}.c-checkbox input:checked~.c-indicator{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgOCA4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA4IDgiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTYuNCwxTDUuNywxLjdMMi45LDQuNUwyLjEsMy43TDEuNCwzTDAsNC40bDAuNywwLjdsMS41LDEuNWwwLjcsMC43bDAuNy0wLjdsMy41LTMuNWwwLjctMC43TDYuNCwxTDYuNCwxeiINCgkvPg0KPC9zdmc+DQo=)}.c-checkbox input:indeterminate~.c-indicator{background-color:#0074d9;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iOHB4IiBoZWlnaHQ9IjhweCIgdmlld0JveD0iMCAwIDggOCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOCA4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0wLDN2Mmg4VjNIMHoiLz4NCjwvc3ZnPg0K)}.c-radio .c-indicator{border-radius:50%}.c-radio input:checked~.c-indicator{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgOCA4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA4IDgiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTQsMUMyLjMsMSwxLDIuMywxLDRzMS4zLDMsMywzczMtMS4zLDMtM1M1LjcsMSw0LDF6Ii8+DQo8L3N2Zz4NCg==)}.c-inputs-stacked .c-input{display:inline}.c-inputs-stacked .c-input:after{display:block;margin-bottom:.25rem;content:""}.c-inputs-stacked .c-input+.c-input{margin-left:0}.c-select{display:inline-block;max-width:100%;padding:.375rem 1.75rem .375rem .75rem;padding-right:.75rem\9;color:#55595c;vertical-align:middle;background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAUCAMAAACzvE1FAAAADFBMVEUzMzMzMzMzMzMzMzMKAG/3AAAAA3RSTlMAf4C/aSLHAAAAPElEQVR42q3NMQ4AIAgEQTn//2cLdRKppSGzBYwzVXvznNWs8C58CiussPJj8h6NwgorrKRdTvuV9v16Afn0AYFOB7aYAAAAAElFTkSuQmCC) no-repeat right .75rem center;background-image:none\9;background-size:8px 10px;border:1px solid #ccc;-moz-appearance:none;-webkit-appearance:none}.c-select:focus{border-color:#51a7e8;outline:0}.c-select::-ms-expand{opacity:0}.c-select-sm{padding-top:3px;padding-bottom:3px;font-size:9pt}.c-select-sm:not([multiple]){height:26px;min-height:26px}.file{position:relative;display:inline-block;height:2.5rem;cursor:pointer}.file input{min-width:14rem;margin:0;filter:alpha(opacity=0);opacity:0}.file-custom{position:absolute;top:0;right:0;left:0;z-index:5;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#555;user-select:none;background-color:#fff;border:1px solid #ddd;border-radius:.25rem}.file-custom:after{content:"Choose file..."}.file-custom:before{position:absolute;top:-.075rem;right:-.075rem;bottom:-.075rem;z-index:6;display:block;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#555;content:"Browse";background-color:#eee;border:1px solid #ddd;border-radius:0 .25rem .25rem 0}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:inline-block}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#818a91}.nav-link.disabled,.nav-link.disabled:focus,.nav-link.disabled:hover{color:#818a91;cursor:not-allowed;background-color:transparent}.nav-inline .nav-item{display:inline-block}.nav-inline .nav-item+.nav-item,.nav-inline .nav-link+.nav-link{margin-left:1rem}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs:after{content:"";display:table;clear:both}.nav-tabs .nav-item{float:left;margin-bottom:-1px}.nav-tabs .nav-item+.nav-item{margin-left:.2rem}.nav-tabs .nav-link{display:block;padding:.5em 1em;border:1px solid transparent;border-radius:.25rem .25rem 0 0}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#eceeef #eceeef #ddd}.nav-tabs .nav-link.disabled,.nav-tabs .nav-link.disabled:focus,.nav-tabs .nav-link.disabled:hover{color:#818a91;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.open .nav-link,.nav-tabs .nav-item.open .nav-link:focus,.nav-tabs .nav-item.open .nav-link:hover,.nav-tabs .nav-link.active,.nav-tabs .nav-link.active:focus,.nav-tabs .nav-link.active:hover{color:#55595c;background-color:#fff;border-color:#ddd #ddd transparent}.nav-pills:after{content:"";display:table;clear:both}.nav-pills .nav-item{float:left}.nav-pills .nav-item+.nav-item{margin-left:.2rem}.nav-pills .nav-link{display:block;padding:.5em 1em;border-radius:.25rem}.nav-pills .nav-item.open .nav-link,.nav-pills .nav-item.open .nav-link:focus,.nav-pills .nav-item.open .nav-link:hover,.nav-pills .nav-link.active,.nav-pills .nav-link.active:focus,.nav-pills .nav-link.active:hover{color:#fff;cursor:default;background-color:#0275d8}.nav-stacked .nav-item{display:block;float:none}.nav-stacked .nav-item+.nav-item{margin-top:.2rem;margin-left:0}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;padding:.5rem 1rem}.navbar:after{content:"";display:table;clear:both}@media (min-width:544px){.navbar{border-radius:.25rem}}.navbar-full{z-index:1000}@media (min-width:544px){.navbar-full{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:544px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0}.navbar-fixed-bottom{bottom:0}.navbar-sticky-top{position:sticky;top:0;z-index:1030;width:100%}@media (min-width:544px){.navbar-sticky-top{border-radius:0}}.navbar-brand{float:left;padding-top:.25rem;padding-bottom:.25rem;margin-right:1rem;font-size:1.25rem}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}.navbar-divider{float:left;width:1px;padding-top:.425rem;padding-bottom:.425rem;margin-right:1rem;margin-left:1rem;overflow:hidden}.navbar-divider:before{content:"\A0"}.navbar-toggler{padding:.5rem .75rem;font-size:1.25rem;line-height:1;background:none;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}@media (min-width:544px){.navbar-toggleable-xs{display:block!important}}@media (min-width:768px){.navbar-toggleable-sm{display:block!important}}@media (min-width:992px){.navbar-toggleable-md{display:block!important}}.navbar-nav .nav-item{float:left}.navbar-nav .nav-link{display:block;padding-top:.425rem;padding-bottom:.425rem}.navbar-nav .nav-item+.nav-item,.navbar-nav .nav-link+.nav-link{margin-left:1rem}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.8)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.6)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .active>.nav-link:focus,.navbar-light .navbar-nav .active>.nav-link:hover,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.active:focus,.navbar-light .navbar-nav .nav-link.active:hover,.navbar-light .navbar-nav .nav-link.open,.navbar-light .navbar-nav .nav-link.open:focus,.navbar-light .navbar-nav .nav-link.open:hover,.navbar-light .navbar-nav .open>.nav-link,.navbar-light .navbar-nav .open>.nav-link:focus,.navbar-light .navbar-nav .open>.nav-link:hover{color:rgba(0,0,0,.8)}.navbar-light .navbar-divider{background-color:rgba(0,0,0,.075)}.navbar-dark .navbar-brand,.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:hsla(0,0%,100%,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:hsla(0,0%,100%,.75)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .active>.nav-link:focus,.navbar-dark .navbar-nav .active>.nav-link:hover,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.active:focus,.navbar-dark .navbar-nav .nav-link.active:hover,.navbar-dark .navbar-nav .nav-link.open,.navbar-dark .navbar-nav .nav-link.open:focus,.navbar-dark .navbar-nav .nav-link.open:hover,.navbar-dark .navbar-nav .open>.nav-link,.navbar-dark .navbar-nav .open>.nav-link:focus,.navbar-dark .navbar-nav .open>.nav-link:hover{color:#fff}.navbar-dark .navbar-divider{background-color:hsla(0,0%,100%,.075)}.card{position:relative;display:block;margin-bottom:.75rem;background-color:#fff;border:1px solid #e5e5e5;border-radius:.25rem}.card-block{padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem}.card-subtitle,.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card>.list-group:first-child .list-group-item:first-child{border-radius:.25rem .25rem 0 0}.card>.list-group:last-child .list-group-item:last-child{border-radius:0 0 .25rem .25rem}.card-header{padding:.75rem 1.25rem;background-color:#f5f5f5;border-bottom:1px solid #e5e5e5}.card-header:first-child{border-radius:.25rem .25rem 0 0}.card-footer{padding:.75rem 1.25rem;background-color:#f5f5f5;border-top:1px solid #e5e5e5}.card-footer:last-child{border-radius:0 0 .25rem .25rem}.card-primary{background-color:#0275d8;border-color:#0275d8}.card-success{background-color:#5cb85c;border-color:#5cb85c}.card-info{background-color:#5bc0de;border-color:#5bc0de}.card-warning{background-color:#f0ad4e;border-color:#f0ad4e}.card-danger{background-color:#d9534f;border-color:#d9534f}.card-primary-outline{background-color:transparent;border-color:#0275d8}.card-secondary-outline{background-color:transparent;border-color:#ccc}.card-info-outline{background-color:transparent;border-color:#5bc0de}.card-success-outline{background-color:transparent;border-color:#5cb85c}.card-warning-outline{background-color:transparent;border-color:#f0ad4e}.card-danger-outline{background-color:transparent;border-color:#d9534f}.card-inverse .card-footer,.card-inverse .card-header{border-bottom:1px solid hsla(0,0%,100%,.2)}.card-inverse .card-blockquote,.card-inverse .card-footer,.card-inverse .card-header,.card-inverse .card-title{color:#fff}.card-inverse .card-blockquote>footer,.card-inverse .card-link,.card-inverse .card-text{color:hsla(0,0%,100%,.65)}.card-inverse .card-link:focus,.card-inverse .card-link:hover{color:#fff}.card-blockquote{padding:0;margin-bottom:0;border-left:0}.card-img{border-radius:.25rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img-top{border-radius:.25rem .25rem 0 0}.card-img-bottom{border-radius:0 0 .25rem .25rem}@media (min-width:544px){.card-deck{display:table;table-layout:fixed;border-spacing:1.25rem 0}.card-deck .card{display:table-cell;width:1%;vertical-align:top}.card-deck-wrapper{margin-right:-1.25rem;margin-left:-1.25rem}}@media (min-width:544px){.card-group{display:table;width:100%;table-layout:fixed}.card-group .card{display:table-cell;vertical-align:top}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-bottom-right-radius:0;border-top-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-bottom-left-radius:0;border-top-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child),.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}}@media (min-width:544px){.card-columns{column-count:3;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#eceeef;border-radius:.25rem}.breadcrumb:after{content:"";display:table;clear:both}.breadcrumb>li{float:left}.breadcrumb>li+li:before{padding-right:.5rem;padding-left:.5rem;color:#818a91;content:"/"}.breadcrumb>.active{color:#818a91}.pagination{display:inline-block;padding-left:0;margin-top:1rem;margin-bottom:1rem;border-radius:.25rem}.page-item{display:inline}.page-item:first-child .page-link{margin-left:0;border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.page-item:last-child .page-link{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.page-item.active .page-link,.page-item.active .page-link:focus,.page-item.active .page-link:hover{z-index:2;color:#fff;cursor:default;background-color:#0275d8;border-color:#0275d8}.page-item.disabled .page-link,.page-item.disabled .page-link:focus,.page-item.disabled .page-link:hover{color:#818a91;cursor:not-allowed;background-color:#fff;border-color:#ddd}.page-link{position:relative;float:left;padding:.5rem .75rem;margin-left:-1px;line-height:1.5;color:#0275d8;text-decoration:none;background-color:#fff;border:1px solid #ddd}.page-link:focus,.page-link:hover{color:#014c8c;background-color:#eceeef;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.33333}.pagination-lg .page-item:first-child .page-link{border-bottom-left-radius:.3rem;border-top-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-bottom-right-radius:.3rem;border-top-right-radius:.3rem}.pagination-sm .page-link{padding:.275rem .75rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-bottom-left-radius:.2rem;border-top-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-bottom-right-radius:.2rem;border-top-right-radius:.2rem}.pager{padding-left:0;margin-top:1rem;margin-bottom:1rem;text-align:center;list-style:none}.pager:after{content:"";display:table;clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eceeef}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#818a91;cursor:not-allowed;background-color:#fff}.pager-next>a,.pager-next>span{float:right}.pager-prev>a,.pager-prev>span{float:left}.label{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.label:empty{display:none}.btn .label{position:relative;top:-1px}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.label-default{background-color:#818a91}.label-default[href]:focus,.label-default[href]:hover{background-color:#687077}.label-primary{background-color:#0275d8}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#025aa5}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#eceeef;border-radius:.3rem}@media (min-width:544px){.jumbotron{padding:4rem 2rem}}.jumbotron-hr{border-top-color:#d0d5d8}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:15px;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:35px}.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d0e9c6;color:#3c763d}.alert-success hr{border-top-color:#c1e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.alert-info hr{border-top-color:#a6d5ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faf2cc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7ecb5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebcccc;color:#a94442}.alert-danger hr{border-top-color:#e4b9b9}.alert-danger .alert-link{color:#843534}@keyframes progress-bar-stripes{0%{background-position:1rem 0}to{background-position:0 0}}.progress{display:block;width:100%;height:1rem;margin-bottom:1rem}.progress[value]{color:#0074d9;border:0;appearance:none}.progress[value]::-webkit-progress-bar{background-color:#eee;border-radius:.25rem}.progress[value]::-webkit-progress-value:before{content:attr(value)}.progress[value]::-webkit-progress-value{background-color:#0074d9;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.progress[value="100"]::-webkit-progress-value{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}@media screen and (min-width:0\0){.progress{background-color:#eee;border-radius:.25rem}.progress-bar{display:inline-block;height:1rem;text-indent:-999rem;background-color:#0074d9;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.progress[width^="0"]{min-width:2rem;color:#818a91;background-color:transparent;background-image:none}.progress[width="100%"]{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}}.progress-striped[value]::-webkit-progress-value{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 25%,transparent 50%,hsla(0,0%,100%,.15) 50%,hsla(0,0%,100%,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-striped[value]::-moz-progress-bar{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 25%,transparent 50%,hsla(0,0%,100%,.15) 50%,hsla(0,0%,100%,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}@media screen and (min-width:0\0){.progress-bar-striped{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 25%,transparent 50%,hsla(0,0%,100%,.15) 50%,hsla(0,0%,100%,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}}.progress-animated[value]::-webkit-progress-value{animation:progress-bar-stripes 2s linear infinite}.progress-animated[value]::-moz-progress-bar{animation:progress-bar-stripes 2s linear infinite}@media screen and (min-width:0\0){.progress-animated .progress-bar-striped{animation:progress-bar-stripes 2s linear infinite}}.progress-success[value]::-webkit-progress-value{background-color:#5cb85c}.progress-success[value]::-moz-progress-bar{background-color:#5cb85c}@media screen and (min-width:0\0){.progress-success .progress-bar{background-color:#5cb85c}}.progress-info[value]::-webkit-progress-value{background-color:#5bc0de}.progress-info[value]::-moz-progress-bar{background-color:#5bc0de}@media screen and (min-width:0\0){.progress-info .progress-bar{background-color:#5bc0de}}.progress-warning[value]::-webkit-progress-value{background-color:#f0ad4e}.progress-warning[value]::-moz-progress-bar{background-color:#f0ad4e}@media screen and (min-width:0\0){.progress-warning .progress-bar{background-color:#f0ad4e}}.progress-danger[value]::-webkit-progress-value{background-color:#d9534f}.progress-danger[value]::-moz-progress-bar{background-color:#d9534f}@media screen and (min-width:0\0){.progress-danger .progress-bar{background-color:#d9534f}}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:625pc}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right{padding-left:10px}.media-left{padding-right:10px}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:0}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:.25rem;border-top-left-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-flush .list-group-item{border-width:1px 0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}a.list-group-item,button.list-group-item{width:100%;color:#555;text-align:inherit}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#818a91;cursor:not-allowed;background-color:#eceeef}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#818a91}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#0275d8;border-color:#0275d8}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#a8d6fe}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9{padding-bottom:42.85714%}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.embed-responsive-1by1{padding-bottom:100%}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal,.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;outline:0;-webkit-overflow-scrolling:touch}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -25%)}.modal.in .modal-dialog{transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.in{opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header:after{content:"";display:table;clear:both}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.5}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:after{content:"";display:table;clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:544px){.modal-dialog{width:600px;margin:30px auto}.modal-sm{width:300px}}@media (min-width:768px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Open Sans;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:.875rem;opacity:0}.tooltip.in{opacity:.9}.tooltip.bs-tether-element-attached-bottom,.tooltip.tooltip-top{padding:5px 0;margin-top:-3px}.tooltip.bs-tether-element-attached-bottom .tooltip-arrow,.tooltip.tooltip-top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.bs-tether-element-attached-left,.tooltip.tooltip-right{padding:0 5px;margin-left:3px}.tooltip.bs-tether-element-attached-left .tooltip-arrow,.tooltip.tooltip-right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.bs-tether-element-attached-top,.tooltip.tooltip-bottom{padding:5px 0;margin-top:3px}.tooltip.bs-tether-element-attached-top .tooltip-arrow,.tooltip.tooltip-bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bs-tether-element-attached-right,.tooltip.tooltip-left{padding:0 5px;margin-left:-3px}.tooltip.bs-tether-element-attached-right .tooltip-arrow,.tooltip.tooltip-left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;padding:1px;font-family:Open Sans;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:.875rem;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover.bs-tether-element-attached-bottom,.popover.popover-top{margin-top:-10px}.popover.bs-tether-element-attached-bottom .popover-arrow,.popover.popover-top .popover-arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.bs-tether-element-attached-bottom .popover-arrow:after,.popover.popover-top .popover-arrow:after{bottom:1px;margin-left:-10px;content:"";border-top-color:#fff;border-bottom-width:0}.popover.bs-tether-element-attached-left,.popover.popover-right{margin-left:10px}.popover.bs-tether-element-attached-left .popover-arrow,.popover.popover-right .popover-arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.bs-tether-element-attached-left .popover-arrow:after,.popover.popover-right .popover-arrow:after{bottom:-10px;left:1px;content:"";border-right-color:#fff;border-left-width:0}.popover.bs-tether-element-attached-top,.popover.popover-bottom{margin-top:10px}.popover.bs-tether-element-attached-top .popover-arrow,.popover.popover-bottom .popover-arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-top .popover-arrow:after,.popover.popover-bottom .popover-arrow:after{top:1px;margin-left:-10px;content:"";border-top-width:0;border-bottom-color:#fff}.popover.bs-tether-element-attached-right,.popover.popover-left{margin-left:-10px}.popover.bs-tether-element-attached-right .popover-arrow,.popover.popover-left .popover-arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-right .popover-arrow:after,.popover.popover-left .popover-arrow:after{right:1px;bottom:-10px;content:"";border-right-width:0;border-left-color:#fff}.popover-title{padding:8px 14px;margin:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:-.7rem -.7rem 0 0}.popover-content{padding:9px 14px}.popover-arrow,.popover-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover-arrow{border-width:11px}.popover-arrow:after{content:"";border-width:10px}.carousel,.carousel-inner{position:relative}.carousel-inner{width:100%;overflow:hidden}.carousel-inner>.carousel-item{position:relative;display:none;transition:.6s ease-in-out left}.carousel-inner>.carousel-item>a>img,.carousel-inner>.carousel-item>img{line-height:1}@media (-webkit-transform-3d),all and (transform-3d){.carousel-inner>.carousel-item{transition:transform .6s ease-in-out;backface-visibility:hidden;perspective:750pt}.carousel-inner>.carousel-item.active.right,.carousel-inner>.carousel-item.next{left:0;transform:translate3d(100%,0,0)}.carousel-inner>.carousel-item.active.left,.carousel-inner>.carousel-item.prev{left:0;transform:translate3d(-100%,0,0)}.carousel-inner>.carousel-item.active,.carousel-inner>.carousel-item.next.left,.carousel-inner>.carousel-item.prev.right{left:0;transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);opacity:.5}.carousel-control.left{background-image:linear-gradient(to right,rgba(0,0,0,.5) 0%,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0%,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-prev:before{content:"\2039"}.carousel-control .icon-next:before{content:"\203A"}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:transparent;border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:9pt;height:9pt;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media (min-width:544px){.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .icon-prev{margin-left:-15px}.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:after{content:"";display:table;clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-xs-left{float:left!important}.pull-xs-right{float:right!important}.pull-xs-none{float:none!important}@media (min-width:544px){.pull-sm-left{float:left!important}.pull-sm-right{float:right!important}.pull-sm-none{float:none!important}}@media (min-width:768px){.pull-md-left{float:left!important}.pull-md-right{float:right!important}.pull-md-none{float:none!important}}@media (min-width:992px){.pull-lg-left{float:left!important}.pull-lg-right{float:right!important}.pull-lg-none{float:none!important}}@media (min-width:1200px){.pull-xl-left{float:left!important}.pull-xl-right{float:right!important}.pull-xl-none{float:none!important}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.invisible{visibility:hidden!important}.text-hide{font:0\/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-xs-left{text-align:left!important}.text-xs-right{text-align:right!important}.text-xs-center{text-align:center!important}@media (min-width:544px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-muted{color:#818a91}.text-primary{color:#0275d8!important}a.text-primary:focus,a.text-primary:hover{color:#025aa5}.text-success{color:#5cb85c!important}a.text-success:focus,a.text-success:hover{color:#449d44}.text-info{color:#5bc0de!important}a.text-info:focus,a.text-info:hover{color:#31b0d5}.text-warning{color:#f0ad4e!important}a.text-warning:focus,a.text-warning:hover{color:#ec971f}.text-danger{color:#d9534f!important}a.text-danger:focus,a.text-danger:hover{color:#c9302c}.bg-inverse{color:#eceeef;background-color:#373a3c}.bg-faded{background-color:#f7f7f9}.bg-primary{color:#fff!important;background-color:#0275d8!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#025aa5}.bg-success{color:#fff!important;background-color:#5cb85c!important}a.bg-success:focus,a.bg-success:hover{background-color:#449d44}.bg-info{color:#fff!important;background-color:#5bc0de!important}a.bg-info:focus,a.bg-info:hover{background-color:#31b0d5}.bg-warning{color:#fff!important;background-color:#f0ad4e!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#ec971f}.bg-danger{color:#fff!important;background-color:#d9534f!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#c9302c}.m-x-auto{margin-right:auto!important;margin-left:auto!important}.m-a-0{margin:0!important}.m-t-0{margin-top:0!important}.m-r-0{margin-right:0!important}.m-b-0{margin-bottom:0!important}.m-l-0,.m-x-0{margin-left:0!important}.m-x-0{margin-right:0!important}.m-y-0{margin-top:0!important;margin-bottom:0!important}.m-a-1{margin:1rem!important}.m-t-1{margin-top:1rem!important}.m-r-1{margin-right:1rem!important}.m-b-1{margin-bottom:1rem!important}.m-l-1,.m-x-1{margin-left:1rem!important}.m-x-1{margin-right:1rem!important}.m-y-1{margin-top:1rem!important;margin-bottom:1rem!important}.m-a-2{margin:1.5rem!important}.m-t-2{margin-top:1.5rem!important}.m-r-2{margin-right:1.5rem!important}.m-b-2{margin-bottom:1.5rem!important}.m-l-2,.m-x-2{margin-left:1.5rem!important}.m-x-2{margin-right:1.5rem!important}.m-y-2{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-a-3{margin:3rem!important}.m-t-3{margin-top:3rem!important}.m-r-3{margin-right:3rem!important}.m-b-3{margin-bottom:3rem!important}.m-l-3,.m-x-3{margin-left:3rem!important}.m-x-3{margin-right:3rem!important}.m-y-3{margin-top:3rem!important;margin-bottom:3rem!important}.p-a-0{padding:0!important}.p-t-0{padding-top:0!important}.p-r-0{padding-right:0!important}.p-b-0{padding-bottom:0!important}.p-l-0,.p-x-0{padding-left:0!important}.p-x-0{padding-right:0!important}.p-y-0{padding-top:0!important;padding-bottom:0!important}.p-a-1{padding:1rem!important}.p-t-1{padding-top:1rem!important}.p-r-1{padding-right:1rem!important}.p-b-1{padding-bottom:1rem!important}.p-l-1,.p-x-1{padding-left:1rem!important}.p-x-1{padding-right:1rem!important}.p-y-1{padding-top:1rem!important;padding-bottom:1rem!important}.p-a-2{padding:1.5rem!important}.p-t-2{padding-top:1.5rem!important}.p-r-2{padding-right:1.5rem!important}.p-b-2{padding-bottom:1.5rem!important}.p-l-2,.p-x-2{padding-left:1.5rem!important}.p-x-2{padding-right:1.5rem!important}.p-y-2{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-a-3{padding:3rem!important}.p-t-3{padding-top:3rem!important}.p-r-3{padding-right:3rem!important}.p-b-3{padding-bottom:3rem!important}.p-l-3,.p-x-3{padding-left:3rem!important}.p-x-3{padding-right:3rem!important}.p-y-3{padding-top:3rem!important;padding-bottom:3rem!important}.pos-f-t{position:fixed;top:0;right:0;left:0;z-index:1030}.hidden-xs-up{display:none!important}@media (max-width:543px){.hidden-xs-down{display:none!important}}@media (min-width:544px){.hidden-sm-up{display:none!important}}@media (max-width:767px){.hidden-sm-down{display:none!important}}@media (min-width:768px){.hidden-md-up{display:none!important}}@media (max-width:991px){.hidden-md-down{display:none!important}}@media (min-width:992px){.hidden-lg-up{display:none!important}}@media (max-width:1199px){.hidden-lg-down{display:none!important}}@media (min-width:1200px){.hidden-xl-up{display:none!important}}.hidden-xl-down,.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}.container-narrow{margin-left:auto;margin-right:auto;padding-left:.9375rem;padding-right:.9375rem}.container-narrow:after{content:"";display:table;clear:both}@media (min-width:544px){.container-narrow{max-width:34rem}}@media (min-width:768px){.container-narrow{max-width:45rem}}@media (min-width:992px){.container-narrow{max-width:45rem}}@media (min-width:1200px){.container-narrow{max-width:45rem}}.nav-justified{width:100%}.nav-justified>li{display:table-cell;width:1%;float:none!important;text-align:center}.nav-underline .nav-item.active,.nav-underline .nav-item.active:hover{box-shadow:0 -3px 0 0 #0275d8 inset}.nav-underline .nav-item.active .nav-link,.nav-underline .nav-item.active:hover .nav-link{color:#0275d8}.nav-underline li:hover{box-shadow:0 -3px 0 0 #ddd inset}.nav-underline li{padding-top:.2rem;padding-bottom:.2rem}.navbar-underline{background-color:#d5d5d5;border-top:1px solid #c8c8c8}pre{background-color:#fdf6e3;padding:1rem}.table-expand-col{min-width:100%}body{background-color:#373a3c}.card-success{background-color:#dff0d8;border-color:#d0e9c6;color:#3c763d}.card-success hr{border-top-color:#c1e2b3}.card-success .alert-link{color:#2b542c}.card-success .card-header{background-color:#d0e9c6;border-bottom:1px solid #c1e2b3}.card-info{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.card-info hr{border-top-color:#a6d5ec}.card-info .alert-link{color:#245269}.card-info .card-header{background-color:#c4e3f3;border-bottom:1px solid #afd9ee}.card-warning{background-color:#fcf8e3;border-color:#faf2cc;color:#8a6d3b}.card-warning hr{border-top-color:#f7ecb5}.card-warning .alert-link{color:#66512c}.card-warning .card-header{background-color:#faf2cc;border-bottom:1px solid #f7ecb5}.card-danger{background-color:#f2dede;border-color:#ebcccc;color:#a94442}.card-danger hr{border-top-color:#e4b9b9}.card-danger .alert-link{color:#843534}.card-danger .card-header{background-color:#ebcccc;border-bottom:1px solid #e4b9b9}.masthead{background-image:linear-gradient(to bottom,#eee 0%,#ddd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE',endColorstr='#FFDDDDDD',GradientType=0);padding-top:10px;padding-bottom:10px}.footer{background-color:#373a3c}.bodycontent{background:#fff}.document-docutils>.section{padding-bottom:1rem}.document-docutils pre .comment{color:#586e75}.document-docutils pre .error,.document-docutils pre .generic{color:#93a1a1}.document-docutils pre .keyword{color:#859900}.document-docutils pre .literal,.document-docutils pre .name{color:#93a1a1}.document-docutils pre .operator{color:#859900}.document-docutils pre .other{color:#cb4b16}.document-docutils pre .punctuation{color:#93a1a1}.document-docutils pre .comment.multiline{color:#586e75}.document-docutils pre .comment.preproc{color:#859900}.document-docutils pre .comment.single{color:#586e75}.document-docutils pre .comment.special{color:#859900}.document-docutils pre .generic.deleted{color:#2aa198}.document-docutils pre .generic.emph{color:#93a1a1;font-style:italic}.document-docutils pre .generic.error{color:#dc322f}.document-docutils pre .generic.heading{color:#cb4b16}.document-docutils pre .generic.inserted{color:#859900}.document-docutils pre .generic.output,.document-docutils pre .generic.prompt{color:#93a1a1}.document-docutils pre .generic.strong{color:#93a1a1;font-weight:700}.document-docutils pre .generic.subheading{color:#cb4b16}.document-docutils pre .generic.traceback{color:#93a1a1}.document-docutils pre .keyword.constant{color:#cb4b16}.document-docutils pre .keyword.declaration{color:#268bd2}.document-docutils pre .keyword.namespace,.document-docutils pre .keyword.pseudo{color:#859900}.document-docutils pre .keyword.reserved{color:#268bd2}.document-docutils pre .keyword.type{color:#dc322f}.document-docutils pre .literal.date{color:#93a1a1}.document-docutils pre .literal.number,.document-docutils pre .literal.string{color:#2aa198}.document-docutils pre .name.attribute{color:#93a1a1}.document-docutils pre .name.builtin{color:#b58900}.document-docutils pre .name.class{color:#268bd2}.document-docutils pre .name.constant{color:#cb4b16}.document-docutils pre .name.decorator{color:#268bd2}.document-docutils pre .name.entity,.document-docutils pre .name.exception{color:#cb4b16}.document-docutils pre .name.function{color:#268bd2}.document-docutils pre .name.label,.document-docutils pre .name.namespace,.document-docutils pre .name.other,.document-docutils pre .name.property{color:#93a1a1}.document-docutils pre .name.tag,.document-docutils pre .name.variable{color:#268bd2}.document-docutils pre .operator.word{color:#859900}.document-docutils pre .text.whitespace{color:#93a1a1}.document-docutils pre .literal.number.float,.document-docutils pre .literal.number.hex,.document-docutils pre .literal.number.integer,.document-docutils pre .literal.number.oct{color:#2aa198}.document-docutils pre .literal.string.backtick{color:#586e75}.document-docutils pre .literal.string.char{color:#2aa198}.document-docutils pre .literal.string.doc{color:#93a1a1}.document-docutils pre .literal.string.double{color:#2aa198}.document-docutils pre .literal.string.escape{color:#cb4b16}.document-docutils pre .literal.string.heredoc{color:#93a1a1}.document-docutils pre .literal.string.interpol,.document-docutils pre .literal.string.other{color:#2aa198}.document-docutils pre .literal.string.regex{color:#dc322f}.document-docutils pre .literal.string.single,.document-docutils pre .literal.string.symbol{color:#2aa198}.document-docutils pre .name.builtin.pseudo,.document-docutils pre .name.variable.class,.document-docutils pre .name.variable.global,.document-docutils pre .name.variable.instance{color:#268bd2}.document-docutils pre .literal.number.integer.long{color:#2aa198}
\ No newline at end of file
diff --git a/hubs/static/fedora-bootstrap/fedora-bootstrap.js b/hubs/static/fedora-bootstrap/fedora-bootstrap.js
new file mode 100644
index 0000000..347d583
--- /dev/null
+++ b/hubs/static/fedora-bootstrap/fedora-bootstrap.js
@@ -0,0 +1,4 @@
+!function(t){function e(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return t[i].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";n(2),n(4),n(14),console.log("Hello World")},function(t,e,n){var i,o,r;!function(n,s){o=[e,t],i=s,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e){"use strict";var n=function(t){function e(t){return{}.toString.call(t).match(/\s([a-zA-Z]+)/)[1].toLowerCase()}function n(t){return(t[0]||t).nodeType}function i(){return{bindType:a.end,delegateType:a.end,handle:function(e){return t(e.target).is(this)?e.handleObj.handler.apply(this,arguments):void 0}}}function o(){if(window.QUnit)return!1;var t=document.createElement("bootstrap");for(var e in l)if(void 0!==t.style[e])return{end:l[e]};return!1}function r(e){var n=this,i=!1;return t(this).one(u.TRANSITION_END,function(){i=!0}),setTimeout(function(){i||u.triggerTransitionEnd(n)},e),this}function s(){a=o(),t.fn.emulateTransitionEnd=r,u.supportsTransitionEnd()&&(t.event.special[u.TRANSITION_END]=i())}var a=!1,l={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},u={TRANSITION_END:"bsTransitionEnd",getUID:function(t){do t+=~~(1e6*Math.random());while(document.getElementById(t));return t},getSelectorFromElement:function(t){var e=t.getAttribute("data-target");return e||(e=t.getAttribute("href")||"",e=/^#[a-z]/i.test(e)?e:null),e},reflow:function(t){new Function("bs","return bs")(t.offsetHeight)},triggerTransitionEnd:function(e){t(e).trigger(a.end)},supportsTransitionEnd:function(){return Boolean(a)},typeCheckConfig:function(t,i,o){for(var r in o)if(o.hasOwnProperty(r)){var s=o[r],a=i[r],l=void 0;if(l=a&&n(a)?"element":e(a),!new RegExp(s).test(l))throw new Error(t.toUpperCase()+": "+('Option "'+r+'" provided type "'+l+'" ')+('but expected type "'+s+'".'))}}};return s(),u}(jQuery);e.exports=n})},function(t,e,n){var i,o;/*! tether 1.2.3 */
+!function(r,s){i=s,o="function"==typeof i?i.call(e,n,e,t):i,!(void 0!==o&&(t.exports=o))}(this,function(t,e,n){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t){var e=getComputedStyle(t)||{},n=e.position,i=[];if("fixed"===n)return[t];for(var o=t;o=o.parentNode;){var r=void 0;try{r=getComputedStyle(o)}catch(s){}if("undefined"==typeof r||null===r)return i.push(o),i;var a=r,l=a.overflow,u=a.overflowX,f=a.overflowY;/(auto|scroll)/.test(l+f+u)&&("absolute"!==n||["relative","absolute","fixed"].indexOf(r.position)>=0)&&i.push(o)}return i.push(document.body),i}function r(t){var e=void 0;t===document?(e=document,t=document.documentElement):e=t.ownerDocument;var n=e.documentElement,i={},o=t.getBoundingClientRect();for(var r in o)i[r]=o[r];var s=I(e);return i.top-=s.top,i.left-=s.left,"undefined"==typeof i.width&&(i.width=document.body.scrollWidth-i.left-i.right),"undefined"==typeof i.height&&(i.height=document.body.scrollHeight-i.top-i.bottom),i.top=i.top-n.clientTop,i.left=i.left-n.clientLeft,i.right=e.body.clientWidth-i.width-i.left,i.bottom=e.body.clientHeight-i.height-i.top,i}function s(t){return t.offsetParent||document.documentElement}function a(){var t=document.createElement("div");t.style.width="100%",t.style.height="200px";var e=document.createElement("div");l(e.style,{position:"absolute",top:0,left:0,pointerEvents:"none",visibility:"hidden",width:"200px",height:"150px",overflow:"hidden"}),e.appendChild(t),document.body.appendChild(e);var n=t.offsetWidth;e.style.overflow="scroll";var i=t.offsetWidth;n===i&&(i=e.clientWidth),document.body.removeChild(e);var o=n-i;return{width:o,height:o}}function l(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],e=[];return Array.prototype.push.apply(e,arguments),e.slice(1).forEach(function(e){if(e)for(var n in e)({}).hasOwnProperty.call(e,n)&&(t[n]=e[n])}),t}function u(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.remove(e)});else{var n=new RegExp("(^| )"+e.split(" ").join("|")+"( |$)","gi"),i=c(t).replace(n," ");d(t,i)}}function f(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.add(e)});else{u(t,e);var n=c(t)+(" "+e);d(t,n)}}function h(t,e){if("undefined"!=typeof t.classList)return t.classList.contains(e);var n=c(t);return new RegExp("(^| )"+e+"( |$)","gi").test(n)}function c(t){return t.className instanceof SVGAnimatedString?t.className.baseVal:t.className}function d(t,e){t.setAttribute("class",e)}function p(t,e,n){n.forEach(function(n){-1===e.indexOf(n)&&h(t,n)&&u(t,n)}),e.forEach(function(e){h(t,e)||f(t,e)})}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function g(t,e){var n=arguments.length<=2||void 0===arguments[2]?1:arguments[2];return t+n>=e&&e>=t-n}function v(){return"undefined"!=typeof performance&&"undefined"!=typeof performance.now?performance.now():+new Date}function m(){for(var t={top:0,left:0},e=arguments.length,n=Array(e),i=0;e>i;i++)n[i]=arguments[i];return n.forEach(function(e){var n=e.top,i=e.left;"string"==typeof n&&(n=parseFloat(n,10)),"string"==typeof i&&(i=parseFloat(i,10)),t.top+=n,t.left+=i}),t}function _(t,e){return"string"==typeof t.left&&-1!==t.left.indexOf("%")&&(t.left=parseFloat(t.left,10)/100*e.width),"string"==typeof t.top&&-1!==t.top.indexOf("%")&&(t.top=parseFloat(t.top,10)/100*e.height),t}function y(t,e){return"scrollParent"===e?e=t.scrollParents[0]:"window"===e&&(e=[pageXOffset,pageYOffset,innerWidth+pageXOffset,innerHeight+pageYOffset]),e===document&&(e=e.documentElement),"undefined"!=typeof e.nodeType&&!function(){var t=r(e),n=t,i=getComputedStyle(e);e=[n.left,n.top,t.width+n.left,t.height+n.top],B.forEach(function(t,n){t=t[0].toUpperCase()+t.substr(1),"Top"===t||"Left"===t?e[n]+=parseFloat(i["border"+t+"Width"]):e[n]-=parseFloat(i["border"+t+"Width"])})}(),e}var E=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),T=void 0;"undefined"==typeof T&&(T={modules:[]});var C=function(){var t=0;return function(){return++t}}(),b={},I=function(t){var e=t._tetherZeroElement;"undefined"==typeof e&&(e=t.createElement("div"),e.setAttribute("data-tether-id",C()),l(e.style,{top:0,left:0,position:"absolute"}),t.body.appendChild(e),t._tetherZeroElement=e);var n=e.getAttribute("data-tether-id");if("undefined"==typeof b[n]){b[n]={};var i=e.getBoundingClientRect();for(var o in i)b[n][o]=i[o];O(function(){delete b[n]})}return b[n]},A=[],O=function(t){A.push(t)},D=function(){for(var t=void 0;t=A.pop();)t()},w=function(){function t(){i(this,t)}return E(t,[{key:"on",value:function(t,e,n){var i=arguments.length<=3||void 0===arguments[3]?!1:arguments[3];"undefined"==typeof this.bindings&&(this.bindings={}),"undefined"==typeof this.bindings[t]&&(this.bindings[t]=[]),this.bindings[t].push({handler:e,ctx:n,once:i})}},{key:"once",value:function(t,e,n){this.on(t,e,n,!0)}},{key:"off",value:function(t,e){if("undefined"==typeof this.bindings||"undefined"==typeof this.bindings[t])if("undefined"==typeof e)delete this.bindings[t];else for(var n=0;n<this.bindings[t].length;)this.bindings[t][n].handler===e?this.bindings[t].splice(n,1):++n}},{key:"trigger",value:function(t){if("undefined"!=typeof this.bindings&&this.bindings[t]){for(var e=0,n=arguments.length,i=Array(n>1?n-1:0),o=1;n>o;o++)i[o-1]=arguments[o];for(;e<this.bindings[t].length;){var r=this.bindings[t][e],s=r.handler,a=r.ctx,l=r.once,u=a;"undefined"==typeof u&&(u=this),s.apply(u,i),l?this.bindings[t].splice(e,1):++e}}}}]),t}();T.Utils={getScrollParents:o,getBounds:r,getOffsetParent:s,extend:l,addClass:f,removeClass:u,hasClass:h,updateClasses:p,defer:O,flush:D,uniqueId:C,Evented:w,getScrollBarSize:a};var S=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(l){o=!0,r=l}finally{try{!i&&a["return"]&&a["return"]()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),E=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}();if("undefined"==typeof T)throw new Error("You must include the utils.js file before tether.js");var N=T.Utils,o=N.getScrollParents,r=N.getBounds,s=N.getOffsetParent,l=N.extend,f=N.addClass,u=N.removeClass,p=N.updateClasses,O=N.defer,D=N.flush,a=N.getScrollBarSize,k=function(){if("undefined"==typeof document)return"";for(var t=document.createElement("div"),e=["transform","webkitTransform","OTransform","MozTransform","msTransform"],n=0;n<e.length;++n){var i=e[n];if(void 0!==t.style[i])return i}}(),L=[],P=function(){L.forEach(function(t){t.position(!1)}),D()};!function(){var t=null,e=null,n=null,i=function o(){return"undefined"!=typeof e&&e>16?(e=Math.min(e-16,250),void(n=setTimeout(o,250))):void("undefined"!=typeof t&&v()-t<10||("undefined"!=typeof n&&(clearTimeout(n),n=null),t=v(),P(),e=v()-t))};"undefined"!=typeof window&&"undefined"!=typeof window.addEventListener&&["resize","scroll","touchmove"].forEach(function(t){window.addEventListener(t,i)})}();var x={center:"center",left:"right",right:"left"},R={middle:"middle",top:"bottom",bottom:"top"},H={top:0,left:0,middle:"50%",center:"50%",bottom:"100%",right:"100%"},W=function(t,e){var n=t.left,i=t.top;return"auto"===n&&(n=x[e.left]),"auto"===i&&(i=R[e.top]),{left:n,top:i}},M=function(t){var e=t.left,n=t.top;return"undefined"!=typeof H[t.left]&&(e=H[t.left]),"undefined"!=typeof H[t.top]&&(n=H[t.top]),{left:e,top:n}},j=function(t){var e=t.split(" "),n=S(e,2),i=n[0],o=n[1];return{top:i,left:o}},V=j,U=function(){function t(e){var n=this;i(this,t),this.position=this.position.bind(this),L.push(this),this.history=[],this.setOptions(e,!1),T.modules.forEach(function(t){"undefined"!=typeof t.initialize&&t.initialize.call(n)}),this.position()}return E(t,[{key:"getClass",value:function(){var t=arguments.length<=0||void 0===arguments[0]?"":arguments[0],e=this.options.classes;return"undefined"!=typeof e&&e[t]?this.options.classes[t]:this.options.classPrefix?this.options.classPrefix+"-"+t:t}},{key:"setOptions",value:function(t){var e=this,n=arguments.length<=1||void 0===arguments[1]?!0:arguments[1],i={offset:"0 0",targetOffset:"0 0",targetAttachment:"auto auto",classPrefix:"tether"};this.options=l(i,t);var r=this.options,s=r.element,a=r.target,u=r.targetModifier;if(this.element=s,this.target=a,this.targetModifier=u,"viewport"===this.target?(this.target=document.body,this.targetModifier="visible"):"scroll-handle"===this.target&&(this.target=document.body,this.targetModifier="scroll-handle"),["element","target"].forEach(function(t){if("undefined"==typeof e[t])throw new Error("Tether Error: Both element and target must be defined");"undefined"!=typeof e[t].jquery?e[t]=e[t][0]:"string"==typeof e[t]&&(e[t]=document.querySelector(e[t]))}),f(this.element,this.getClass("element")),this.options.addTargetClasses!==!1&&f(this.target,this.getClass("target")),!this.options.attachment)throw new Error("Tether Error: You must provide an attachment");this.targetAttachment=V(this.options.targetAttachment),this.attachment=V(this.options.attachment),this.offset=j(this.options.offset),this.targetOffset=j(this.options.targetOffset),"undefined"!=typeof this.scrollParents&&this.disable(),"scroll-handle"===this.targetModifier?this.scrollParents=[this.target]:this.scrollParents=o(this.target),this.options.enabled!==!1&&this.enable(n)}},{key:"getTargetBounds",value:function(){if("undefined"==typeof this.targetModifier)return r(this.target);if("visible"===this.targetModifier){if(this.target===document.body)return{top:pageYOffset,left:pageXOffset,height:innerHeight,width:innerWidth};var t=r(this.target),e={height:t.height,width:t.width,top:t.top,left:t.left};return e.height=Math.min(e.height,t.height-(pageYOffset-t.top)),e.height=Math.min(e.height,t.height-(t.top+t.height-(pageYOffset+innerHeight))),e.height=Math.min(innerHeight,e.height),e.height-=2,e.width=Math.min(e.width,t.width-(pageXOffset-t.left)),e.width=Math.min(e.width,t.width-(t.left+t.width-(pageXOffset+innerWidth))),e.width=Math.min(innerWidth,e.width),e.width-=2,e.top<pageYOffset&&(e.top=pageYOffset),e.left<pageXOffset&&(e.left=pageXOffset),e}if("scroll-handle"===this.targetModifier){var t=void 0,n=this.target;n===document.body?(n=document.documentElement,t={left:pageXOffset,top:pageYOffset,height:innerHeight,width:innerWidth}):t=r(n);var i=getComputedStyle(n),o=n.scrollWidth>n.clientWidth||[i.overflow,i.overflowX].indexOf("scroll")>=0||this.target!==document.body,s=0;o&&(s=15);var a=t.height-parseFloat(i.borderTopWidth)-parseFloat(i.borderBottomWidth)-s,e={width:15,height:.975*a*(a/n.scrollHeight),left:t.left+t.width-parseFloat(i.borderLeftWidth)-15},l=0;408>a&&this.target===document.body&&(l=-11e-5*Math.pow(a,2)-.00727*a+22.58),this.target!==document.body&&(e.height=Math.max(e.height,24));var u=this.target.scrollTop/(n.scrollHeight-a);return e.top=u*(a-e.height-l)+t.top+parseFloat(i.borderTopWidth),this.target===document.body&&(e.height=Math.max(e.height,24)),e}}},{key:"clearCache",value:function(){this._cache={}}},{key:"cache",value:function(t,e){return"undefined"==typeof this._cache&&(this._cache={}),"undefined"==typeof this._cache[t]&&(this._cache[t]=e.call(this)),this._cache[t]}},{key:"enable",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]?!0:arguments[0];this.options.addTargetClasses!==!1&&f(this.target,this.getClass("enabled")),f(this.element,this.getClass("enabled")),this.enabled=!0,this.scrollParents.forEach(function(e){e!==document&&e.addEventListener("scroll",t.position)}),e&&this.position()}},{key:"disable",value:function(){var t=this;u(this.target,this.getClass("enabled")),u(this.element,this.getClass("enabled")),this.enabled=!1,"undefined"!=typeof this.scrollParents&&this.scrollParents.forEach(function(e){e.removeEventListener("scroll",t.position)})}},{key:"destroy",value:function(){var t=this;this.disable(),L.forEach(function(e,n){return e===t?void L.splice(n,1):void 0})}},{key:"updateAttachClasses",value:function(t,e){var n=this;t=t||this.attachment,e=e||this.targetAttachment;var i=["left","top","bottom","right","middle","center"];"undefined"!=typeof this._addAttachClasses&&this._addAttachClasses.length&&this._addAttachClasses.splice(0,this._addAttachClasses.length),"undefined"==typeof this._addAttachClasses&&(this._addAttachClasses=[]);var o=this._addAttachClasses;t.top&&o.push(this.getClass("element-attached")+"-"+t.top),t.left&&o.push(this.getClass("element-attached")+"-"+t.left),e.top&&o.push(this.getClass("target-attached")+"-"+e.top),e.left&&o.push(this.getClass("target-attached")+"-"+e.left);var r=[];i.forEach(function(t){r.push(n.getClass("element-attached")+"-"+t),r.push(n.getClass("target-attached")+"-"+t)}),O(function(){"undefined"!=typeof n._addAttachClasses&&(p(n.element,n._addAttachClasses,r),n.options.addTargetClasses!==!1&&p(n.target,n._addAttachClasses,r),delete n._addAttachClasses)})}},{key:"position",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]?!0:arguments[0];if(this.enabled){this.clearCache();var n=W(this.targetAttachment,this.attachment);this.updateAttachClasses(this.attachment,n);var i=this.cache("element-bounds",function(){return r(t.element)}),o=i.width,l=i.height;if(0===o&&0===l&&"undefined"!=typeof this.lastSize){var u=this.lastSize;o=u.width,l=u.height}else this.lastSize={width:o,height:l};var f=this.cache("target-bounds",function(){return t.getTargetBounds()}),h=f,c=_(M(this.attachment),{width:o,height:l}),d=_(M(n),h),p=_(this.offset,{width:o,height:l}),g=_(this.targetOffset,h);c=m(c,p),d=m(d,g);for(var v=f.left+d.left-c.left,y=f.top+d.top-c.top,E=0;E<T.modules.length;++E){var C=T.modules[E],b=C.position.call(this,{left:v,top:y,targetAttachment:n,targetPos:f,elementPos:i,offset:c,targetOffset:d,manualOffset:p,manualTargetOffset:g,scrollbarSize:A,attachment:this.attachment});if(b===!1)return!1;"undefined"!=typeof b&&"object"==typeof b&&(y=b.top,v=b.left)}var I={page:{top:y,left:v},viewport:{top:y-pageYOffset,bottom:pageYOffset-y-l+innerHeight,left:v-pageXOffset,right:pageXOffset-v-o+innerWidth}},A=void 0;return document.body.scrollWidth>window.innerWidth&&(A=this.cache("scrollbar-size",a),I.viewport.bottom-=A.height),document.body.scrollHeight>window.innerHeight&&(A=this.cache("scrollbar-size",a),I.viewport.right-=A.width),-1!==["","static"].indexOf(document.body.style.position)&&-1!==["","static"].indexOf(document.body.parentElement.style.position)||(I.page.bottom=document.body.scrollHeight-y-l,I.page.right=document.body.scrollWidth-v-o),"undefined"!=typeof this.options.optimizations&&this.options.optimizations.moveElement!==!1&&"undefined"==typeof this.targetModifier&&!function(){var e=t.cache("target-offsetparent",function(){return s(t.target)}),n=t.cache("target-offsetparent-bounds",function(){return r(e)}),i=getComputedStyle(e),o=n,a={};if(["Top","Left","Bottom","Right"].forEach(function(t){a[t.toLowerCase()]=parseFloat(i["border"+t+"Width"])}),n.right=document.body.scrollWidth-n.left-o.width+a.right,n.bottom=document.body.scrollHeight-n.top-o.height+a.bottom,I.page.top>=n.top+a.top&&I.page.bottom>=n.bottom&&I.page.left>=n.left+a.left&&I.page.right>=n.right){var l=e.scrollTop,u=e.scrollLeft;I.offset={top:I.page.top-n.top+l-a.top,left:I.page.left-n.left+u-a.left}}}(),this.move(I),this.history.unshift(I),this.history.length>3&&this.history.pop(),e&&D(),!0}}},{key:"move",value:function(t){var e=this;if("undefined"!=typeof this.element.parentNode){var n={};for(var i in t){n[i]={};for(var o in t[i]){for(var r=!1,a=0;a<this.history.length;++a){var u=this.history[a];if("undefined"!=typeof u[i]&&!g(u[i][o],t[i][o])){r=!0;break}}r||(n[i][o]=!0)}}var f={top:"",left:"",right:"",bottom:""},h=function(t,n){var i="undefined"!=typeof e.options.optimizations,o=i?e.options.optimizations.gpu:null;if(o!==!1){var r=void 0,s=void 0;t.top?(f.top=0,r=n.top):(f.bottom=0,r=-n.bottom),t.left?(f.left=0,s=n.left):(f.right=0,s=-n.right),f[k]="translateX("+Math.round(s)+"px) translateY("+Math.round(r)+"px)","msTransform"!==k&&(f[k]+=" translateZ(0)")}else t.top?f.top=n.top+"px":f.bottom=n.bottom+"px",t.left?f.left=n.left+"px":f.right=n.right+"px"},c=!1;if((n.page.top||n.page.bottom)&&(n.page.left||n.page.right)?(f.position="absolute",h(n.page,t.page)):(n.viewport.top||n.viewport.bottom)&&(n.viewport.left||n.viewport.right)?(f.position="fixed",h(n.viewport,t.viewport)):"undefined"!=typeof n.offset&&n.offset.top&&n.offset.left?!function(){f.position="absolute";var i=e.cache("target-offsetparent",function(){return s(e.target)});s(e.element)!==i&&O(function(){e.element.parentNode.removeChild(e.element),i.appendChild(e.element)}),h(n.offset,t.offset),c=!0}():(f.position="absolute",h({top:!0,left:!0},t.page)),!c){for(var d=!0,p=this.element.parentNode;p&&"BODY"!==p.tagName;){if("static"!==getComputedStyle(p).position){d=!1;break}p=p.parentNode}d||(this.element.parentNode.removeChild(this.element),document.body.appendChild(this.element))}var v={},m=!1;for(var o in f){var _=f[o],y=this.element.style[o];y!==_&&(m=!0,v[o]=_)}m&&O(function(){l(e.element.style,v)})}}}]),t}();U.modules=[],T.position=P;var F=l(U,T),S=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(l){o=!0,r=l}finally{try{!i&&a["return"]&&a["return"]()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),N=T.Utils,r=N.getBounds,l=N.extend,p=N.updateClasses,O=N.defer,B=["left","top","right","bottom"];T.modules.push({position:function(t){var e=this,n=t.top,i=t.left,o=t.targetAttachment;if(!this.options.constraints)return!0;var s=this.cache("element-bounds",function(){return r(e.element)}),a=s.height,u=s.width;if(0===u&&0===a&&"undefined"!=typeof this.lastSize){var f=this.lastSize;u=f.width,a=f.height}var h=this.cache("target-bounds",function(){return e.getTargetBounds()}),c=h.height,d=h.width,g=[this.getClass("pinned"),this.getClass("out-of-bounds")];this.options.constraints.forEach(function(t){var e=t.outOfBoundsClass,n=t.pinnedClass;e&&g.push(e),n&&g.push(n)}),g.forEach(function(t){["left","top","right","bottom"].forEach(function(e){g.push(t+"-"+e)})});var v=[],m=l({},o),_=l({},this.attachment);return this.options.constraints.forEach(function(t){var r=t.to,s=t.attachment,l=t.pin;"undefined"==typeof s&&(s="");var f=void 0,h=void 0;if(s.indexOf(" ")>=0){var p=s.split(" "),g=S(p,2);h=g[0],f=g[1]}else f=h=s;var E=y(e,r);"target"!==h&&"both"!==h||(n<E[1]&&"top"===m.top&&(n+=c,m.top="bottom"),n+a>E[3]&&"bottom"===m.top&&(n-=c,m.top="top")),"together"===h&&("top"===m.top&&("bottom"===_.top&&n<E[1]?(n+=c,m.top="bottom",n+=a,_.top="top"):"top"===_.top&&n+a>E[3]&&n-(a-c)>=E[1]&&(n-=a-c,m.top="bottom",_.top="bottom")),"bottom"===m.top&&("top"===_.top&&n+a>E[3]?(n-=c,m.top="top",n-=a,_.top="bottom"):"bottom"===_.top&&n<E[1]&&n+(2*a-c)<=E[3]&&(n+=a-c,m.top="top",_.top="top")),"middle"===m.top&&(n+a>E[3]&&"top"===_.top?(n-=a,_.top="bottom"):n<E[1]&&"bottom"===_.top&&(n+=a,_.top="top"))),"target"!==f&&"both"!==f||(i<E[0]&&"left"===m.left&&(i+=d,m.left="right"),i+u>E[2]&&"right"===m.left&&(i-=d,m.left="left")),"together"===f&&(i<E[0]&&"left"===m.left?"right"===_.left?(i+=d,m.left="right",i+=u,_.left="left"):"left"===_.left&&(i+=d,m.left="right",i-=u,_.left="right"):i+u>E[2]&&"right"===m.left?"left"===_.left?(i-=d,m.left="left",i-=u,_.left="right"):"right"===_.left&&(i-=d,m.left="left",i+=u,_.left="left"):"center"===m.left&&(i+u>E[2]&&"left"===_.left?(i-=u,_.left="right"):i<E[0]&&"right"===_.left&&(i+=u,_.left="left"))),"element"!==h&&"both"!==h||(n<E[1]&&"bottom"===_.top&&(n+=a,_.top="top"),n+a>E[3]&&"top"===_.top&&(n-=a,_.top="bottom")),"element"!==f&&"both"!==f||(i<E[0]&&("right"===_.left?(i+=u,_.left="left"):"center"===_.left&&(i+=u/2,_.left="left")),i+u>E[2]&&("left"===_.left?(i-=u,_.left="right"):"center"===_.left&&(i-=u/2,_.left="right"))),"string"==typeof l?l=l.split(",").map(function(t){return t.trim()}):l===!0&&(l=["top","left","right","bottom"]),l=l||[];var T=[],C=[];n<E[1]&&(l.indexOf("top")>=0?(n=E[1],T.push("top")):C.push("top")),n+a>E[3]&&(l.indexOf("bottom")>=0?(n=E[3]-a,T.push("bottom")):C.push("bottom")),i<E[0]&&(l.indexOf("left")>=0?(i=E[0],T.push("left")):C.push("left")),i+u>E[2]&&(l.indexOf("right")>=0?(i=E[2]-u,T.push("right")):C.push("right")),T.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.pinnedClass?e.options.pinnedClass:e.getClass("pinned"),v.push(t),T.forEach(function(e){v.push(t+"-"+e)})}(),C.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.outOfBoundsClass?e.options.outOfBoundsClass:e.getClass("out-of-bounds"),v.push(t),C.forEach(function(e){v.push(t+"-"+e)})}(),(T.indexOf("left")>=0||T.indexOf("right")>=0)&&(_.left=m.left=!1),(T.indexOf("top")>=0||T.indexOf("bottom")>=0)&&(_.top=m.top=!1),m.top===o.top&&m.left===o.left&&_.top===e.attachment.top&&_.left===e.attachment.left||e.updateAttachClasses(_,m)}),O(function(){e.options.addTargetClasses!==!1&&p(e.target,v,g),p(e.element,v,g)}),{top:n,left:i}}});var N=T.Utils,r=N.getBounds,p=N.updateClasses,O=N.defer;T.modules.push({position:function(t){var e=this,n=t.top,i=t.left,o=this.cache("element-bounds",function(){return r(e.element)}),s=o.height,a=o.width,l=this.getTargetBounds(),u=n+s,f=i+a,h=[];n<=l.bottom&&u>=l.top&&["left","right"].forEach(function(t){var e=l[t];e!==i&&e!==f||h.push(t)}),i<=l.right&&f>=l.left&&["top","bottom"].forEach(function(t){var e=l[t];e!==n&&e!==u||h.push(t)});var c=[],d=[],g=["left","top","right","bottom"];return c.push(this.getClass("abutted")),g.forEach(function(t){c.push(e.getClass("abutted")+"-"+t)}),h.length&&d.push(this.getClass("abutted")),h.forEach(function(t){d.push(e.getClass("abutted")+"-"+t)}),O(function(){e.options.addTargetClasses!==!1&&p(e.target,d,c),p(e.element,d,c)}),!0}});var S=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(l){o=!0,r=l}finally{try{!i&&a["return"]&&a["return"]()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();return T.modules.push({position:function(t){var e=t.top,n=t.left;if(this.options.shift){var i=this.options.shift;"function"==typeof this.options.shift&&(i=this.options.shift.call(this,{top:e,left:n}));var o=void 0,r=void 0;if("string"==typeof i){i=i.split(" "),i[1]=i[1]||i[0];var s=i,a=S(s,2);o=a[0],r=a[1],o=parseFloat(o,10),r=parseFloat(r,10)}else o=i.top,r=i.left;return e+=o,n+=r,{top:e,left:n}}}}),F})},function(t,e,n){var i,o,r;(function(s,a){!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),l=i(n),u=function(t){if(void 0===s)throw new Error("Bootstrap tooltips require Tether (http://github.hubspot.com/tether/)");var e="tooltip",n="4.0.0-alpha",i="bs.tooltip",u="."+i,f=t.fn[e],h=150,c="bs-tether",d={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:"0 0",constraints:[]},p={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"string",constraints:"array"},g={TOP:"bottom center",RIGHT:"middle left",BOTTOM:"top center",LEFT:"middle right"},v={IN:"in",OUT:"out"},m={HIDE:"hide"+u,HIDDEN:"hidden"+u,SHOW:"show"+u,SHOWN:"shown"+u,INSERTED:"inserted"+u,CLICK:"click"+u,FOCUSIN:"focusin"+u,FOCUSOUT:"focusout"+u,MOUSEENTER:"mouseenter"+u,MOUSELEAVE:"mouseleave"+u},_={FADE:"fade",IN:"in"},y={TOOLTIP:".tooltip",TOOLTIP_INNER:".tooltip-inner"},E={element:!1,enabled:!1},T={HOVER:"hover",FOCUS:"focus",CLICK:"click",MANUAL:"manual"},C=function(){function s(t,e){o(this,s),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._tether=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}return r(s,[{key:"enable",value:function(){this._isEnabled=!0}},{key:"disable",value:function(){this._isEnabled=!1}},{key:"toggleEnabled",value:function(){this._isEnabled=!this._isEnabled}},{key:"toggle",value:function(e){if(e){var n=this.constructor.DATA_KEY,i=t(e.currentTarget).data(n);i||(i=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(n,i)),i._activeTrigger.click=!i._activeTrigger.click,i._isWithActiveTrigger()?i._enter(null,i):i._leave(null,i)}else{if(t(this.getTipElement()).hasClass(_.IN))return void this._leave(null,this);this._enter(null,this)}}},{key:"dispose",value:function(){clearTimeout(this._timeout),this.cleanupTether(),t.removeData(this.element,this.constructor.DATA_KEY),t(this.element).off(this.constructor.EVENT_KEY),this.tip&&t(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._tether=null,this.element=null,this.config=null,this.tip=null}},{key:"show",value:function(){var e=this,n=t.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){t(this.element).trigger(n);var i=t.contains(this.element.ownerDocument.documentElement,this.element);if(n.isDefaultPrevented()||!i)return;var o=this.getTipElement(),r=l["default"].getUID(this.constructor.NAME);o.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&t(o).addClass(_.FADE);var u="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,f=this._getAttachment(u);t(o).data(this.constructor.DATA_KEY,this).appendTo(document.body),t(this.element).trigger(this.constructor.Event.INSERTED),this._tether=new a({attachment:f,element:o,target:this.element,classes:E,classPrefix:c,offset:this.config.offset,constraints:this.config.constraints,addTargetClasses:!1}),l["default"].reflow(o),this._tether.position(),t(o).addClass(_.IN);var h=function(){var n=e._hoverState;e._hoverState=null,t(e.element).trigger(e.constructor.Event.SHOWN),n===v.OUT&&e._leave(null,e)};if(l["default"].supportsTransitionEnd()&&t(this.tip).hasClass(_.FADE))return void t(this.tip).one(l["default"].TRANSITION_END,h).emulateTransitionEnd(s._TRANSITION_DURATION);h()}}},{key:"hide",value:function(e){var n=this,i=this.getTipElement(),o=t.Event(this.constructor.Event.HIDE),r=function(){n._hoverState!==v.IN&&i.parentNode&&i.parentNode.removeChild(i),n.element.removeAttribute("aria-describedby"),t(n.element).trigger(n.constructor.Event.HIDDEN),n.cleanupTether(),e&&e()};t(this.element).trigger(o),o.isDefaultPrevented()||(t(i).removeClass(_.IN),l["default"].supportsTransitionEnd()&&t(this.tip).hasClass(_.FADE)?t(i).one(l["default"].TRANSITION_END,r).emulateTransitionEnd(h):r(),this._hoverState="")}},{key:"isWithContent",value:function(){return Boolean(this.getTitle())}},{key:"getTipElement",value:function(){return this.tip=this.tip||t(this.config.template)[0]}},{key:"setContent",value:function(){var e=t(this.getTipElement());this.setElementContent(e.find(y.TOOLTIP_INNER),this.getTitle()),e.removeClass(_.FADE).removeClass(_.IN),this.cleanupTether()}},{key:"setElementContent",value:function(e,n){var i=this.config.html;"object"==typeof n&&(n.nodeType||n.jquery)?i?t(n).parent().is(e)||e.empty().append(n):e.text(t(n).text()):e[i?"html":"text"](n)}},{key:"getTitle",value:function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t}},{key:"cleanupTether",value:function(){this._tether&&this._tether.destroy()}},{key:"_getAttachment",value:function(t){return g[t.toUpperCase()]}},{key:"_setListeners",value:function(){var e=this,n=this.config.trigger.split(" ");n.forEach(function(n){if("click"===n)t(e.element).on(e.constructor.Event.CLICK,e.config.selector,t.proxy(e.toggle,e));else if(n!==T.MANUAL){var i=n===T.HOVER?e.constructor.Event.MOUSEENTER:e.constructor.Event.FOCUSIN,o=n===T.HOVER?e.constructor.Event.MOUSELEAVE:e.constructor.Event.FOCUSOUT;t(e.element).on(i,e.config.selector,t.proxy(e._enter,e)).on(o,e.config.selector,t.proxy(e._leave,e))}}),this.config.selector?this.config=t.extend({},this.config,{trigger:"manual",selector:""}):this._fixTitle()}},{key:"_fixTitle",value:function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))}},{key:"_enter",value:function(e,n){var i=this.constructor.DATA_KEY;return n=n||t(e.currentTarget).data(i),n||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusin"===e.type?T.FOCUS:T.HOVER]=!0),t(n.getTipElement()).hasClass(_.IN)||n._hoverState===v.IN?void(n._hoverState=v.IN):(clearTimeout(n._timeout),n._hoverState=v.IN,n.config.delay&&n.config.delay.show?void(n._timeout=setTimeout(function(){n._hoverState===v.IN&&n.show()},n.config.delay.show)):void n.show())}},{key:"_leave",value:function(e,n){var i=this.constructor.DATA_KEY;return n=n||t(e.currentTarget).data(i),n||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusout"===e.type?T.FOCUS:T.HOVER]=!1),n._isWithActiveTrigger()?void 0:(clearTimeout(n._timeout),n._hoverState=v.OUT,n.config.delay&&n.config.delay.hide?void(n._timeout=setTimeout(function(){n._hoverState===v.OUT&&n.hide()},n.config.delay.hide)):void n.hide())}},{key:"_isWithActiveTrigger",value:function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}},{key:"_getConfig",value:function(n){return n=t.extend({},this.constructor.Default,t(this.element).data(),n),n.delay&&"number"==typeof n.delay&&(n.delay={show:n.delay,hide:n.delay}),l["default"].typeCheckConfig(e,n,this.constructor.DefaultType),n}},{key:"_getDelegateConfig",value:function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t}}],[{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this).data(i),o="object"==typeof e?e:null;if((n||!/destroy|hide/.test(e))&&(n||(n=new s(this,o),t(this).data(i,n)),"string"==typeof e)){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return d}},{key:"NAME",get:function(){return e}},{key:"DATA_KEY",get:function(){return i}},{key:"Event",get:function(){return m}},{key:"EVENT_KEY",get:function(){return u}},{key:"DefaultType",get:function(){return p}}]),s}();return t.fn[e]=C._jQueryInterface,t.fn[e].Constructor=C,
+t.fn[e].noConflict=function(){return t.fn[e]=f,C._jQueryInterface},C}(jQuery);e.exports=u})}).call(e,n(2),n(2))},function(t,e,n){n(1),n(5),n(6),n(7),n(8),n(9),n(10),n(12),n(13),n(3),n(11)},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="alert",n="4.0.0-alpha",i="bs.alert",a="."+i,l=".data-api",u=t.fn[e],f=150,h={DISMISS:'[data-dismiss="alert"]'},c={CLOSE:"close"+a,CLOSED:"closed"+a,CLICK_DATA_API:"click"+a+l},d={ALERT:"alert",FADE:"fade",IN:"in"},p=function(){function e(t){o(this,e),this._element=t}return r(e,[{key:"close",value:function(t){t=t||this._element;var e=this._getRootElement(t),n=this._triggerCloseEvent(e);n.isDefaultPrevented()||this._removeElement(e)}},{key:"dispose",value:function(){t.removeData(this._element,i),this._element=null}},{key:"_getRootElement",value:function(e){var n=s["default"].getSelectorFromElement(e),i=!1;return n&&(i=t(n)[0]),i||(i=t(e).closest("."+d.ALERT)[0]),i}},{key:"_triggerCloseEvent",value:function(e){var n=t.Event(c.CLOSE);return t(e).trigger(n),n}},{key:"_removeElement",value:function(e){return t(e).removeClass(d.IN),s["default"].supportsTransitionEnd()&&t(e).hasClass(d.FADE)?void t(e).one(s["default"].TRANSITION_END,t.proxy(this._destroyElement,this,e)).emulateTransitionEnd(f):void this._destroyElement(e)}},{key:"_destroyElement",value:function(e){t(e).detach().trigger(c.CLOSED).remove()}}],[{key:"_jQueryInterface",value:function(n){return this.each(function(){var o=t(this),r=o.data(i);r||(r=new e(this),o.data(i,r)),"close"===n&&r[n](this)})}},{key:"_handleDismiss",value:function(t){return function(e){e&&e.preventDefault(),t.close(this)}}},{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(c.CLICK_DATA_API,h.DISMISS,p._handleDismiss(new p)),t.fn[e]=p._jQueryInterface,t.fn[e].Constructor=p,t.fn[e].noConflict=function(){return t.fn[e]=u,p._jQueryInterface},p}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(n,s){o=[e,t],i=s,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),o=function(t){var e="button",o="4.0.0-alpha",r="bs.button",s="."+r,a=".data-api",l=t.fn[e],u={ACTIVE:"active",BUTTON:"btn",FOCUS:"focus"},f={DATA_TOGGLE_CARROT:'[data-toggle^="button"]',DATA_TOGGLE:'[data-toggle="buttons"]',INPUT:"input",ACTIVE:".active",BUTTON:".btn"},h={CLICK_DATA_API:"click"+s+a,FOCUS_BLUR_DATA_API:"focus"+s+a+" "+("blur"+s+a)},c=function(){function e(t){n(this,e),this._element=t}return i(e,[{key:"toggle",value:function(){var e=!0,n=t(this._element).closest(f.DATA_TOGGLE)[0];if(n){var i=t(this._element).find(f.INPUT)[0];if(i){if("radio"===i.type)if(i.checked&&t(this._element).hasClass(u.ACTIVE))e=!1;else{var o=t(n).find(f.ACTIVE)[0];o&&t(o).removeClass(u.ACTIVE)}e&&(i.checked=!t(this._element).hasClass(u.ACTIVE),t(this._element).trigger("change"))}}else this._element.setAttribute("aria-pressed",!t(this._element).hasClass(u.ACTIVE));e&&t(this._element).toggleClass(u.ACTIVE)}},{key:"dispose",value:function(){t.removeData(this._element,r),this._element=null}}],[{key:"_jQueryInterface",value:function(n){return this.each(function(){var i=t(this).data(r);i||(i=new e(this),t(this).data(r,i)),"toggle"===n&&i[n]()})}},{key:"VERSION",get:function(){return o}}]),e}();return t(document).on(h.CLICK_DATA_API,f.DATA_TOGGLE_CARROT,function(e){e.preventDefault();var n=e.target;t(n).hasClass(u.BUTTON)||(n=t(n).closest(f.BUTTON)),c._jQueryInterface.call(t(n),"toggle")}).on(h.FOCUS_BLUR_DATA_API,f.DATA_TOGGLE_CARROT,function(e){var n=t(e.target).closest(f.BUTTON)[0];t(n).toggleClass(u.FOCUS,/^focus(in)?$/.test(e.type))}),t.fn[e]=c._jQueryInterface,t.fn[e].Constructor=c,t.fn[e].noConflict=function(){return t.fn[e]=l,c._jQueryInterface},c}(jQuery);e.exports=o})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="carousel",n="4.0.0-alpha",i="bs.carousel",a="."+i,l=".data-api",u=t.fn[e],f=600,h={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0},c={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean"},d={NEXT:"next",PREVIOUS:"prev"},p={SLIDE:"slide"+a,SLID:"slid"+a,KEYDOWN:"keydown"+a,MOUSEENTER:"mouseenter"+a,MOUSELEAVE:"mouseleave"+a,LOAD_DATA_API:"load"+a+l,CLICK_DATA_API:"click"+a+l},g={CAROUSEL:"carousel",ACTIVE:"active",SLIDE:"slide",RIGHT:"right",LEFT:"left",ITEM:"carousel-item"},v={ACTIVE:".active",ACTIVE_ITEM:".active.carousel-item",ITEM:".carousel-item",NEXT_PREV:".next, .prev",INDICATORS:".carousel-indicators",DATA_SLIDE:"[data-slide], [data-slide-to]",DATA_RIDE:'[data-ride="carousel"]'},m=function(){function l(e,n){o(this,l),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this._config=this._getConfig(n),this._element=t(e)[0],this._indicatorsElement=t(this._element).find(v.INDICATORS)[0],this._addEventListeners()}return r(l,[{key:"next",value:function(){this._isSliding||this._slide(d.NEXT)}},{key:"nextWhenVisible",value:function(){document.hidden||this.next()}},{key:"prev",value:function(){this._isSliding||this._slide(d.PREVIOUS)}},{key:"pause",value:function(e){e||(this._isPaused=!0),t(this._element).find(v.NEXT_PREV)[0]&&s["default"].supportsTransitionEnd()&&(s["default"].triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}},{key:"cycle",value:function(e){e||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval(t.proxy(document.visibilityState?this.nextWhenVisible:this.next,this),this._config.interval))}},{key:"to",value:function(e){var n=this;this._activeElement=t(this._element).find(v.ACTIVE_ITEM)[0];var i=this._getItemIndex(this._activeElement);if(!(e>this._items.length-1||0>e)){if(this._isSliding)return void t(this._element).one(p.SLID,function(){return n.to(e)});if(i===e)return this.pause(),void this.cycle();var o=e>i?d.NEXT:d.PREVIOUS;this._slide(o,this._items[e])}}},{key:"dispose",value:function(){t(this._element).off(a),t.removeData(this._element,i),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null}},{key:"_getConfig",value:function(n){return n=t.extend({},h,n),s["default"].typeCheckConfig(e,n,c),n}},{key:"_addEventListeners",value:function(){this._config.keyboard&&t(this._element).on(p.KEYDOWN,t.proxy(this._keydown,this)),"hover"!==this._config.pause||"ontouchstart"in document.documentElement||t(this._element).on(p.MOUSEENTER,t.proxy(this.pause,this)).on(p.MOUSELEAVE,t.proxy(this.cycle,this))}},{key:"_keydown",value:function(t){if(t.preventDefault(),!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:this.prev();break;case 39:this.next();break;default:return}}},{key:"_getItemIndex",value:function(e){return this._items=t.makeArray(t(e).parent().find(v.ITEM)),this._items.indexOf(e)}},{key:"_getItemByDirection",value:function(t,e){var n=t===d.NEXT,i=t===d.PREVIOUS,o=this._getItemIndex(e),r=this._items.length-1,s=i&&0===o||n&&o===r;if(s&&!this._config.wrap)return e;var a=t===d.PREVIOUS?-1:1,l=(o+a)%this._items.length;return-1===l?this._items[this._items.length-1]:this._items[l]}},{key:"_triggerSlideEvent",value:function(e,n){var i=t.Event(p.SLIDE,{relatedTarget:e,direction:n});return t(this._element).trigger(i),i}},{key:"_setActiveIndicatorElement",value:function(e){if(this._indicatorsElement){t(this._indicatorsElement).find(v.ACTIVE).removeClass(g.ACTIVE);var n=this._indicatorsElement.children[this._getItemIndex(e)];n&&t(n).addClass(g.ACTIVE)}}},{key:"_slide",value:function(e,n){var i=this,o=t(this._element).find(v.ACTIVE_ITEM)[0],r=n||o&&this._getItemByDirection(e,o),a=Boolean(this._interval),l=e===d.NEXT?g.LEFT:g.RIGHT;if(r&&t(r).hasClass(g.ACTIVE))return void(this._isSliding=!1);var u=this._triggerSlideEvent(r,l);if(!u.isDefaultPrevented()&&o&&r){this._isSliding=!0,a&&this.pause(),this._setActiveIndicatorElement(r);var h=t.Event(p.SLID,{relatedTarget:r,direction:l});s["default"].supportsTransitionEnd()&&t(this._element).hasClass(g.SLIDE)?(t(r).addClass(e),s["default"].reflow(r),t(o).addClass(l),t(r).addClass(l),t(o).one(s["default"].TRANSITION_END,function(){t(r).removeClass(l).removeClass(e),t(r).addClass(g.ACTIVE),t(o).removeClass(g.ACTIVE).removeClass(e).removeClass(l),i._isSliding=!1,setTimeout(function(){return t(i._element).trigger(h)},0)}).emulateTransitionEnd(f)):(t(o).removeClass(g.ACTIVE),t(r).addClass(g.ACTIVE),this._isSliding=!1,t(this._element).trigger(h)),a&&this.cycle()}}}],[{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this).data(i),o=t.extend({},h,t(this).data());"object"==typeof e&&t.extend(o,e);var r="string"==typeof e?e:o.slide;if(n||(n=new l(this,o),t(this).data(i,n)),"number"==typeof e)n.to(e);else if("string"==typeof r){if(void 0===n[r])throw new Error('No method named "'+r+'"');n[r]()}else o.interval&&(n.pause(),n.cycle())})}},{key:"_dataApiClickHandler",value:function(e){var n=s["default"].getSelectorFromElement(this);if(n){var o=t(n)[0];if(o&&t(o).hasClass(g.CAROUSEL)){var r=t.extend({},t(o).data(),t(this).data()),a=this.getAttribute("data-slide-to");a&&(r.interval=!1),l._jQueryInterface.call(t(o),r),a&&t(o).data(i).to(a),e.preventDefault()}}}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return h}}]),l}();return t(document).on(p.CLICK_DATA_API,v.DATA_SLIDE,m._dataApiClickHandler),t(window).on(p.LOAD_DATA_API,function(){t(v.DATA_RIDE).each(function(){var e=t(this);m._jQueryInterface.call(e,e.data())})}),t.fn[e]=m._jQueryInterface,t.fn[e].Constructor=m,t.fn[e].noConflict=function(){return t.fn[e]=u,m._jQueryInterface},m}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="collapse",n="4.0.0-alpha",i="bs.collapse",a="."+i,l=".data-api",u=t.fn[e],f=600,h={toggle:!0,parent:""},c={toggle:"boolean",parent:"string"},d={SHOW:"show"+a,SHOWN:"shown"+a,HIDE:"hide"+a,HIDDEN:"hidden"+a,CLICK_DATA_API:"click"+a+l},p={IN:"in",COLLAPSE:"collapse",COLLAPSING:"collapsing",COLLAPSED:"collapsed"},g={WIDTH:"width",HEIGHT:"height"},v={ACTIVES:".panel > .in, .panel > .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},m=function(){function a(e,n){o(this,a),this._isTransitioning=!1,this._element=e,this._config=this._getConfig(n),this._triggerArray=t.makeArray(t('[data-toggle="collapse"][href="#'+e.id+'"],'+('[data-toggle="collapse"][data-target="#'+e.id+'"]'))),this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}return r(a,[{key:"toggle",value:function(){t(this._element).hasClass(p.IN)?this.hide():this.show()}},{key:"show",value:function(){var e=this;if(!this._isTransitioning&&!t(this._element).hasClass(p.IN)){var n=void 0,o=void 0;if(this._parent&&(n=t.makeArray(t(v.ACTIVES)),n.length||(n=null)),!(n&&(o=t(n).data(i),o&&o._isTransitioning))){var r=t.Event(d.SHOW);if(t(this._element).trigger(r),!r.isDefaultPrevented()){n&&(a._jQueryInterface.call(t(n),"hide"),o||t(n).data(i,null));var l=this._getDimension();t(this._element).removeClass(p.COLLAPSE).addClass(p.COLLAPSING),this._element.style[l]=0,this._element.setAttribute("aria-expanded",!0),this._triggerArray.length&&t(this._triggerArray).removeClass(p.COLLAPSED).attr("aria-expanded",!0),this.setTransitioning(!0);var u=function(){t(e._element).removeClass(p.COLLAPSING).addClass(p.COLLAPSE).addClass(p.IN),e._element.style[l]="",e.setTransitioning(!1),t(e._element).trigger(d.SHOWN)};if(!s["default"].supportsTransitionEnd())return void u();var h=l[0].toUpperCase()+l.slice(1),c="scroll"+h;t(this._element).one(s["default"].TRANSITION_END,u).emulateTransitionEnd(f),this._element.style[l]=this._element[c]+"px"}}}}},{key:"hide",value:function(){var e=this;if(!this._isTransitioning&&t(this._element).hasClass(p.IN)){var n=t.Event(d.HIDE);if(t(this._element).trigger(n),!n.isDefaultPrevented()){var i=this._getDimension(),o=i===g.WIDTH?"offsetWidth":"offsetHeight";this._element.style[i]=this._element[o]+"px",s["default"].reflow(this._element),t(this._element).addClass(p.COLLAPSING).removeClass(p.COLLAPSE).removeClass(p.IN),this._element.setAttribute("aria-expanded",!1),this._triggerArray.length&&t(this._triggerArray).addClass(p.COLLAPSED).attr("aria-expanded",!1),this.setTransitioning(!0);var r=function(){e.setTransitioning(!1),t(e._element).removeClass(p.COLLAPSING).addClass(p.COLLAPSE).trigger(d.HIDDEN)};return this._element.style[i]=0,s["default"].supportsTransitionEnd()?void t(this._element).one(s["default"].TRANSITION_END,r).emulateTransitionEnd(f):void r()}}}},{key:"setTransitioning",value:function(t){this._isTransitioning=t}},{key:"dispose",value:function(){t.removeData(this._element,i),this._config=null,this._parent=null,this._element=null,this._triggerArray=null,this._isTransitioning=null}},{key:"_getConfig",value:function(n){return n=t.extend({},h,n),n.toggle=Boolean(n.toggle),s["default"].typeCheckConfig(e,n,c),n}},{key:"_getDimension",value:function(){var e=t(this._element).hasClass(g.WIDTH);return e?g.WIDTH:g.HEIGHT}},{key:"_getParent",value:function(){var e=this,n=t(this._config.parent)[0],i='[data-toggle="collapse"][data-parent="'+this._config.parent+'"]';return t(n).find(i).each(function(t,n){e._addAriaAndCollapsedClass(a._getTargetFromElement(n),[n])}),n}},{key:"_addAriaAndCollapsedClass",value:function(e,n){if(e){var i=t(e).hasClass(p.IN);e.setAttribute("aria-expanded",i),n.length&&t(n).toggleClass(p.COLLAPSED,!i).attr("aria-expanded",i)}}}],[{key:"_getTargetFromElement",value:function(e){var n=s["default"].getSelectorFromElement(e);return n?t(n)[0]:null}},{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this),o=n.data(i),r=t.extend({},h,n.data(),"object"==typeof e&&e);if(!o&&r.toggle&&/show|hide/.test(e)&&(r.toggle=!1),o||(o=new a(this,r),n.data(i,o)),"string"==typeof e){if(void 0===o[e])throw new Error('No method named "'+e+'"');o[e]()}})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return h}}]),a}();return t(document).on(d.CLICK_DATA_API,v.DATA_TOGGLE,function(e){e.preventDefault();var n=m._getTargetFromElement(this),o=t(n).data(i),r=o?"toggle":t(this).data();m._jQueryInterface.call(t(n),r)}),t.fn[e]=m._jQueryInterface,t.fn[e].Constructor=m,t.fn[e].noConflict=function(){return t.fn[e]=u,m._jQueryInterface},m}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="dropdown",n="4.0.0-alpha",i="bs.dropdown",a="."+i,l=".data-api",u=t.fn[e],f={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,CLICK:"click"+a,CLICK_DATA_API:"click"+a+l,KEYDOWN_DATA_API:"keydown"+a+l},h={BACKDROP:"dropdown-backdrop",DISABLED:"disabled",OPEN:"open"},c={BACKDROP:".dropdown-backdrop",DATA_TOGGLE:'[data-toggle="dropdown"]',FORM_CHILD:".dropdown form",ROLE_MENU:'[role="menu"]',ROLE_LISTBOX:'[role="listbox"]',NAVBAR_NAV:".navbar-nav",VISIBLE_ITEMS:'[role="menu"] li:not(.disabled) a, [role="listbox"] li:not(.disabled) a'},d=function(){function e(t){o(this,e),this._element=t,this._addEventListeners()}return r(e,[{key:"toggle",value:function(){if(this.disabled||t(this).hasClass(h.DISABLED))return!1;var n=e._getParentFromElement(this),i=t(n).hasClass(h.OPEN);if(e._clearMenus(),i)return!1;if("ontouchstart"in document.documentElement&&!t(n).closest(c.NAVBAR_NAV).length){var o=document.createElement("div");o.className=h.BACKDROP,t(o).insertBefore(this),t(o).on("click",e._clearMenus)}var r={relatedTarget:this},s=t.Event(f.SHOW,r);return t(n).trigger(s),s.isDefaultPrevented()?!1:(this.focus(),this.setAttribute("aria-expanded","true"),t(n).toggleClass(h.OPEN),t(n).trigger(t.Event(f.SHOWN,r)),!1)}},{key:"dispose",value:function(){t.removeData(this._element,i),t(this._element).off(a),this._element=null}},{key:"_addEventListeners",value:function(){t(this._element).on(f.CLICK,this.toggle)}}],[{key:"_jQueryInterface",value:function(n){return this.each(function(){var o=t(this).data(i);if(o||t(this).data(i,o=new e(this)),"string"==typeof n){if(void 0===o[n])throw new Error('No method named "'+n+'"');o[n].call(this)}})}},{key:"_clearMenus",value:function(n){if(!n||3!==n.which){var i=t(c.BACKDROP)[0];i&&i.parentNode.removeChild(i);for(var o=t.makeArray(t(c.DATA_TOGGLE)),r=0;r<o.length;r++){var s=e._getParentFromElement(o[r]),a={relatedTarget:o[r]};if(t(s).hasClass(h.OPEN)&&!(n&&"click"===n.type&&/input|textarea/i.test(n.target.tagName)&&t.contains(s,n.target))){var l=t.Event(f.HIDE,a);t(s).trigger(l),l.isDefaultPrevented()||(o[r].setAttribute("aria-expanded","false"),t(s).removeClass(h.OPEN).trigger(t.Event(f.HIDDEN,a)))}}}}},{key:"_getParentFromElement",value:function(e){var n=void 0,i=s["default"].getSelectorFromElement(e);return i&&(n=t(i)[0]),n||e.parentNode}},{key:"_dataApiKeydownHandler",value:function(n){if(/(38|40|27|32)/.test(n.which)&&!/input|textarea/i.test(n.target.tagName)&&(n.preventDefault(),n.stopPropagation(),!this.disabled&&!t(this).hasClass(h.DISABLED))){var i=e._getParentFromElement(this),o=t(i).hasClass(h.OPEN);if(!o&&27!==n.which||o&&27===n.which){if(27===n.which){var r=t(i).find(c.DATA_TOGGLE)[0];t(r).trigger("focus")}return void t(this).trigger("click")}var s=t.makeArray(t(c.VISIBLE_ITEMS));if(s=s.filter(function(t){return t.offsetWidth||t.offsetHeight}),s.length){var a=s.indexOf(n.target);38===n.which&&a>0&&a--,40===n.which&&a<s.length-1&&a++,~a||(a=0),s[a].focus()}}}},{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(f.KEYDOWN_DATA_API,c.DATA_TOGGLE,d._dataApiKeydownHandler).on(f.KEYDOWN_DATA_API,c.ROLE_MENU,d._dataApiKeydownHandler).on(f.KEYDOWN_DATA_API,c.ROLE_LISTBOX,d._dataApiKeydownHandler).on(f.CLICK_DATA_API,d._clearMenus).on(f.CLICK_DATA_API,c.DATA_TOGGLE,d.prototype.toggle).on(f.CLICK_DATA_API,c.FORM_CHILD,function(t){t.stopPropagation()}),t.fn[e]=d._jQueryInterface,t.fn[e].Constructor=d,t.fn[e].noConflict=function(){return t.fn[e]=u,d._jQueryInterface},d}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="modal",n="4.0.0-alpha",i="bs.modal",a="."+i,l=".data-api",u=t.fn[e],f=300,h=150,c={backdrop:!0,keyboard:!0,focus:!0,show:!0},d={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean",show:"boolean"},p={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,FOCUSIN:"focusin"+a,RESIZE:"resize"+a,CLICK_DISMISS:"click.dismiss"+a,KEYDOWN_DISMISS:"keydown.dismiss"+a,MOUSEUP_DISMISS:"mouseup.dismiss"+a,MOUSEDOWN_DISMISS:"mousedown.dismiss"+a,CLICK_DATA_API:"click"+a+l},g={SCROLLBAR_MEASURER:"modal-scrollbar-measure",BACKDROP:"modal-backdrop",OPEN:"modal-open",FADE:"fade",IN:"in"},v={DIALOG:".modal-dialog",DATA_TOGGLE:'[data-toggle="modal"]',DATA_DISMISS:'[data-dismiss="modal"]',FIXED_CONTENT:".navbar-fixed-top, .navbar-fixed-bottom, .is-fixed"},m=function(){function l(e,n){o(this,l),this._config=this._getConfig(n),this._element=e,this._dialog=t(e).find(v.DIALOG)[0],this._backdrop=null,this._isShown=!1,this._isBodyOverflowing=!1,this._ignoreBackdropClick=!1,this._originalBodyPadding=0,this._scrollbarWidth=0}return r(l,[{key:"toggle",value:function(t){return this._isShown?this.hide():this.show(t)}},{key:"show",value:function(e){var n=this,i=t.Event(p.SHOW,{relatedTarget:e});t(this._element).trigger(i),this._isShown||i.isDefaultPrevented()||(this._isShown=!0,this._checkScrollbar(),this._setScrollbar(),t(document.body).addClass(g.OPEN),this._setEscapeEvent(),this._setResizeEvent(),t(this._element).on(p.CLICK_DISMISS,v.DATA_DISMISS,t.proxy(this.hide,this)),t(this._dialog).on(p.MOUSEDOWN_DISMISS,function(){t(n._element).one(p.MOUSEUP_DISMISS,function(e){t(e.target).is(n._element)&&(n._ignoreBackdropClick=!0)})}),this._showBackdrop(t.proxy(this._showElement,this,e)))}},{key:"hide",value:function(e){e&&e.preventDefault();var n=t.Event(p.HIDE);t(this._element).trigger(n),this._isShown&&!n.isDefaultPrevented()&&(this._isShown=!1,this._setEscapeEvent(),this._setResizeEvent(),t(document).off(p.FOCUSIN),t(this._element).removeClass(g.IN),t(this._element).off(p.CLICK_DISMISS),t(this._dialog).off(p.MOUSEDOWN_DISMISS),s["default"].supportsTransitionEnd()&&t(this._element).hasClass(g.FADE)?t(this._element).one(s["default"].TRANSITION_END,t.proxy(this._hideModal,this)).emulateTransitionEnd(f):this._hideModal())}},{key:"dispose",value:function(){t.removeData(this._element,i),t(window).off(a),t(document).off(a),t(this._element).off(a),t(this._backdrop).off(a),this._config=null,this._element=null,this._dialog=null,this._backdrop=null,this._isShown=null,this._isBodyOverflowing=null,this._ignoreBackdropClick=null,this._originalBodyPadding=null,this._scrollbarWidth=null}},{key:"_getConfig",value:function(n){return n=t.extend({},c,n),s["default"].typeCheckConfig(e,n,d),n}},{key:"_showElement",value:function(e){var n=this,i=s["default"].supportsTransitionEnd()&&t(this._element).hasClass(g.FADE);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.scrollTop=0,i&&s["default"].reflow(this._element),t(this._element).addClass(g.IN),this._config.focus&&this._enforceFocus();var o=t.Event(p.SHOWN,{relatedTarget:e}),r=function(){n._config.focus&&n._element.focus(),t(n._element).trigger(o)};i?t(this._dialog).one(s["default"].TRANSITION_END,r).emulateTransitionEnd(f):r()}},{key:"_enforceFocus",value:function(){var e=this;t(document).off(p.FOCUSIN).on(p.FOCUSIN,function(n){e._element===n.target||t(e._element).has(n.target).length||e._element.focus()})}},{key:"_setEscapeEvent",value:function(){var e=this;this._isShown&&this._config.keyboard?t(this._element).on(p.KEYDOWN_DISMISS,function(t){27===t.which&&e.hide()}):this._isShown||t(this._element).off(p.KEYDOWN_DISMISS)}},{key:"_setResizeEvent",value:function(){this._isShown?t(window).on(p.RESIZE,t.proxy(this._handleUpdate,this)):t(window).off(p.RESIZE)}},{key:"_hideModal",value:function(){var e=this;this._element.style.display="none",this._showBackdrop(function(){t(document.body).removeClass(g.OPEN),e._resetAdjustments(),e._resetScrollbar(),t(e._element).trigger(p.HIDDEN)})}},{key:"_removeBackdrop",value:function(){this._backdrop&&(t(this._backdrop).remove(),this._backdrop=null)}},{key:"_showBackdrop",value:function(e){var n=this,i=t(this._element).hasClass(g.FADE)?g.FADE:"";if(this._isShown&&this._config.backdrop){var o=s["default"].supportsTransitionEnd()&&i;if(this._backdrop=document.createElement("div"),this._backdrop.className=g.BACKDROP,i&&t(this._backdrop).addClass(i),t(this._backdrop).appendTo(document.body),t(this._element).on(p.CLICK_DISMISS,function(t){return n._ignoreBackdropClick?void(n._ignoreBackdropClick=!1):void(t.target===t.currentTarget&&("static"===n._config.backdrop?n._element.focus():n.hide()))}),o&&s["default"].reflow(this._backdrop),t(this._backdrop).addClass(g.IN),!e)return;if(!o)return void e();t(this._backdrop).one(s["default"].TRANSITION_END,e).emulateTransitionEnd(h)}else if(!this._isShown&&this._backdrop){t(this._backdrop).removeClass(g.IN);var r=function(){n._removeBackdrop(),e&&e()};s["default"].supportsTransitionEnd()&&t(this._element).hasClass(g.FADE)?t(this._backdrop).one(s["default"].TRANSITION_END,r).emulateTransitionEnd(h):r()}else e&&e()}},{key:"_handleUpdate",value:function(){this._adjustDialog()}},{key:"_adjustDialog",value:function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px~")}},{key:"_resetAdjustments",value:function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}},{key:"_checkScrollbar",value:function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this._isBodyOverflowing=document.body.clientWidth<t,this._scrollbarWidth=this._getScrollbarWidth()}},{key:"_setScrollbar",value:function(){var e=parseInt(t(v.FIXED_CONTENT).css("padding-right")||0,10);this._originalBodyPadding=document.body.style.paddingRight||"",this._isBodyOverflowing&&(document.body.style.paddingRight=e+this._scrollbarWidth+"px")}},{key:"_resetScrollbar",value:function(){document.body.style.paddingRight=this._originalBodyPadding}},{key:"_getScrollbarWidth",value:function(){var t=document.createElement("div");t.className=g.SCROLLBAR_MEASURER,document.body.appendChild(t);var e=t.offsetWidth-t.clientWidth;return document.body.removeChild(t),e}}],[{key:"_jQueryInterface",value:function(e,n){return this.each(function(){var o=t(this).data(i),r=t.extend({},l.Default,t(this).data(),"object"==typeof e&&e);if(o||(o=new l(this,r),t(this).data(i,o)),"string"==typeof e){if(void 0===o[e])throw new Error('No method named "'+e+'"');o[e](n)}else r.show&&o.show(n)})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return c}}]),l}();return t(document).on(p.CLICK_DATA_API,v.DATA_TOGGLE,function(e){var n=this,o=void 0,r=s["default"].getSelectorFromElement(this);r&&(o=t(r)[0]);var a=t(o).data(i)?"toggle":t.extend({},t(o).data(),t(this).data());"A"===this.tagName&&e.preventDefault();var l=t(o).one(p.SHOW,function(e){e.isDefaultPrevented()||l.one(p.HIDDEN,function(){t(n).is(":visible")&&n.focus()})});m._jQueryInterface.call(t(o),a,this)}),t.fn[e]=m._jQueryInterface,t.fn[e].Constructor=m,t.fn[e].noConflict=function(){return t.fn[e]=u,m._jQueryInterface},m}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(3)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var s=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),a=function(t,e,n){for(var i=!0;i;){var o=t,r=e,s=n;i=!1,null===o&&(o=Function.prototype);var a=Object.getOwnPropertyDescriptor(o,r);if(void 0!==a){if("value"in a)return a.value;var l=a.get;if(void 0===l)return;return l.call(s)}var u=Object.getPrototypeOf(o);if(null===u)return;t=u,e=r,n=s,i=!0,a=u=void 0}},l=i(n),u=function(t){var e="popover",n="4.0.0-alpha",i="bs.popover",u="."+i,f=t.fn[e],h=t.extend({},l["default"].Default,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c=t.extend({},l["default"].DefaultType,{content:"(string|element|function)"}),d={FADE:"fade",IN:"in"},p={TITLE:".popover-title",CONTENT:".popover-content",ARROW:".popover-arrow"},g={HIDE:"hide"+u,HIDDEN:"hidden"+u,SHOW:"show"+u,SHOWN:"shown"+u,INSERTED:"inserted"+u,CLICK:"click"+u,FOCUSIN:"focusin"+u,FOCUSOUT:"focusout"+u,MOUSEENTER:"mouseenter"+u,MOUSELEAVE:"mouseleave"+u},v=function(l){function f(){o(this,f),a(Object.getPrototypeOf(f.prototype),"constructor",this).apply(this,arguments)}return r(f,l),s(f,[{key:"isWithContent",value:function(){return this.getTitle()||this._getContent()}},{key:"getTipElement",value:function(){return this.tip=this.tip||t(this.config.template)[0]}},{key:"setContent",value:function(){var e=t(this.getTipElement());this.setElementContent(e.find(p.TITLE),this.getTitle()),this.setElementContent(e.find(p.CONTENT),this._getContent()),e.removeClass(d.FADE).removeClass(d.IN),this.cleanupTether()}},{key:"_getContent",value:function(){return this.element.getAttribute("data-content")||("function"==typeof this.config.content?this.config.content.call(this.element):this.config.content)}}],[{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this).data(i),o="object"==typeof e?e:null;if((n||!/destroy|hide/.test(e))&&(n||(n=new f(this,o),t(this).data(i,n)),"string"==typeof e)){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return h}},{key:"NAME",get:function(){return e}},{key:"DATA_KEY",get:function(){return i}},{key:"Event",get:function(){return g}},{key:"EVENT_KEY",get:function(){return u}},{key:"DefaultType",get:function(){return c}}]),f}(l["default"]);return t.fn[e]=v._jQueryInterface,t.fn[e].Constructor=v,t.fn[e].noConflict=function(){return t.fn[e]=f,v._jQueryInterface},v}(jQuery);e.exports=u})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){
+"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="scrollspy",n="4.0.0-alpha",i="bs.scrollspy",a="."+i,l=".data-api",u=t.fn[e],f={offset:10,method:"auto",target:""},h={offset:"number",method:"string",target:"(string|element)"},c={ACTIVATE:"activate"+a,SCROLL:"scroll"+a,LOAD_DATA_API:"load"+a+l},d={DROPDOWN_ITEM:"dropdown-item",DROPDOWN_MENU:"dropdown-menu",NAV_LINK:"nav-link",NAV:"nav",ACTIVE:"active"},p={DATA_SPY:'[data-spy="scroll"]',ACTIVE:".active",LIST_ITEM:".list-item",LI:"li",LI_DROPDOWN:"li.dropdown",NAV_LINKS:".nav-link",DROPDOWN:".dropdown",DROPDOWN_ITEMS:".dropdown-item",DROPDOWN_TOGGLE:".dropdown-toggle"},g={OFFSET:"offset",POSITION:"position"},v=function(){function l(e,n){o(this,l),this._element=e,this._scrollElement="BODY"===e.tagName?window:e,this._config=this._getConfig(n),this._selector=this._config.target+" "+p.NAV_LINKS+","+(this._config.target+" "+p.DROPDOWN_ITEMS),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,t(this._scrollElement).on(c.SCROLL,t.proxy(this._process,this)),this.refresh(),this._process()}return r(l,[{key:"refresh",value:function(){var e=this,n=this._scrollElement!==this._scrollElement.window?g.POSITION:g.OFFSET,i="auto"===this._config.method?n:this._config.method,o=i===g.POSITION?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight();var r=t.makeArray(t(this._selector));r.map(function(e){var n=void 0,r=s["default"].getSelectorFromElement(e);return r&&(n=t(r)[0]),n&&(n.offsetWidth||n.offsetHeight)?[t(n)[i]().top+o,r]:void 0}).filter(function(t){return t}).sort(function(t,e){return t[0]-e[0]}).forEach(function(t){e._offsets.push(t[0]),e._targets.push(t[1])})}},{key:"dispose",value:function(){t.removeData(this._element,i),t(this._scrollElement).off(a),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null}},{key:"_getConfig",value:function(n){if(n=t.extend({},f,n),"string"!=typeof n.target){var i=t(n.target).attr("id");i||(i=s["default"].getUID(e),t(n.target).attr("id",i)),n.target="#"+i}return s["default"].typeCheckConfig(e,n,h),n}},{key:"_getScrollTop",value:function(){return this._scrollElement===window?this._scrollElement.scrollY:this._scrollElement.scrollTop}},{key:"_getScrollHeight",value:function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}},{key:"_process",value:function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._scrollElement.offsetHeight;if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}if(this._activeTarget&&t<this._offsets[0])return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;){var r=this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&(void 0===this._offsets[o+1]||t<this._offsets[o+1]);r&&this._activate(this._targets[o])}}},{key:"_activate",value:function(e){this._activeTarget=e,this._clear();var n=this._selector.split(",");n=n.map(function(t){return t+'[data-target="'+e+'"],'+(t+'[href="'+e+'"]')});var i=t(n.join(","));i.hasClass(d.DROPDOWN_ITEM)?(i.closest(p.DROPDOWN).find(p.DROPDOWN_TOGGLE).addClass(d.ACTIVE),i.addClass(d.ACTIVE)):i.parents(p.LI).find(p.NAV_LINKS).addClass(d.ACTIVE),t(this._scrollElement).trigger(c.ACTIVATE,{relatedTarget:e})}},{key:"_clear",value:function(){t(this._selector).filter(p.ACTIVE).removeClass(d.ACTIVE)}}],[{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this).data(i),o="object"==typeof e&&e||null;if(n||(n=new l(this,o),t(this).data(i,n)),"string"==typeof e){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return f}}]),l}();return t(window).on(c.LOAD_DATA_API,function(){for(var e=t.makeArray(t(p.DATA_SPY)),n=e.length;n--;){var i=t(e[n]);v._jQueryInterface.call(i,i.data())}}),t.fn[e]=v._jQueryInterface,t.fn[e].Constructor=v,t.fn[e].noConflict=function(){return t.fn[e]=u,v._jQueryInterface},v}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="tab",n="4.0.0-alpha",i="bs.tab",a="."+i,l=".data-api",u=t.fn[e],f=150,h={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,CLICK_DATA_API:"click"+a+l},c={DROPDOWN_MENU:"dropdown-menu",ACTIVE:"active",FADE:"fade",IN:"in"},d={A:"a",LI:"li",DROPDOWN:".dropdown",UL:"ul:not(.dropdown-menu)",FADE_CHILD:"> .nav-item .fade, > .fade",ACTIVE:".active",ACTIVE_CHILD:"> .nav-item > .active, > .active",DATA_TOGGLE:'[data-toggle="tab"], [data-toggle="pill"]',DROPDOWN_TOGGLE:".dropdown-toggle",DROPDOWN_ACTIVE_CHILD:"> .dropdown-menu .active"},p=function(){function e(t){o(this,e),this._element=t}return r(e,[{key:"show",value:function(){var e=this;if(!this._element.parentNode||this._element.parentNode.nodeType!==Node.ELEMENT_NODE||!t(this._element).hasClass(c.ACTIVE)){var n=void 0,i=void 0,o=t(this._element).closest(d.UL)[0],r=s["default"].getSelectorFromElement(this._element);o&&(i=t.makeArray(t(o).find(d.ACTIVE)),i=i[i.length-1]);var a=t.Event(h.HIDE,{relatedTarget:this._element}),l=t.Event(h.SHOW,{relatedTarget:i});if(i&&t(i).trigger(a),t(this._element).trigger(l),!l.isDefaultPrevented()&&!a.isDefaultPrevented()){r&&(n=t(r)[0]),this._activate(this._element,o);var u=function(){var n=t.Event(h.HIDDEN,{relatedTarget:e._element}),o=t.Event(h.SHOWN,{relatedTarget:i});t(i).trigger(n),t(e._element).trigger(o)};n?this._activate(n,n.parentNode,u):u()}}}},{key:"dispose",value:function(){t.removeClass(this._element,i),this._element=null}},{key:"_activate",value:function(e,n,i){var o=t(n).find(d.ACTIVE_CHILD)[0],r=i&&s["default"].supportsTransitionEnd()&&(o&&t(o).hasClass(c.FADE)||Boolean(t(n).find(d.FADE_CHILD)[0])),a=t.proxy(this._transitionComplete,this,e,o,r,i);o&&r?t(o).one(s["default"].TRANSITION_END,a).emulateTransitionEnd(f):a(),o&&t(o).removeClass(c.IN)}},{key:"_transitionComplete",value:function(e,n,i,o){if(n){t(n).removeClass(c.ACTIVE);var r=t(n).find(d.DROPDOWN_ACTIVE_CHILD)[0];r&&t(r).removeClass(c.ACTIVE),n.setAttribute("aria-expanded",!1)}if(t(e).addClass(c.ACTIVE),e.setAttribute("aria-expanded",!0),i?(s["default"].reflow(e),t(e).addClass(c.IN)):t(e).removeClass(c.FADE),e.parentNode&&t(e.parentNode).hasClass(c.DROPDOWN_MENU)){var a=t(e).closest(d.DROPDOWN)[0];a&&t(a).find(d.DROPDOWN_TOGGLE).addClass(c.ACTIVE),e.setAttribute("aria-expanded",!0)}o&&o()}}],[{key:"_jQueryInterface",value:function(n){return this.each(function(){var o=t(this),r=o.data(i);if(r||(r=r=new e(this),o.data(i,r)),"string"==typeof n){if(void 0===r[n])throw new Error('No method named "'+n+'"');r[n]()}})}},{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(h.CLICK_DATA_API,d.DATA_TOGGLE,function(e){e.preventDefault(),p._jQueryInterface.call(t(this),"show")}),t.fn[e]=p._jQueryInterface,t.fn[e].Constructor=p,t.fn[e].noConflict=function(){return t.fn[e]=u,p._jQueryInterface},p}(jQuery);e.exports=a})},function(t,e){}]);
\ No newline at end of file
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 73aaad6..0cc8ebc 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -2,7 +2,7 @@
 <html lang='en'>
 <head>
   <title>{{ hub.name }}</title>
-  <link href="https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
@@ -238,7 +238,8 @@
 
 <script type="text/javascript" src="{{
   url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
-<script src="https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js"></script>
+  <script type="text/javascript" src="{{
+  url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
 <script type="text/javascript" src="{{
   url_for('static', filename='js/utils.js') }}"></script>
 

From 9c2451dd23898d4d195d614d76330e853d4665a0 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:15:13 +0000
Subject: [PATCH 432/1001] changes to cards


---

diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index f5a40a9..1d5e126 100755
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -7,7 +7,7 @@ _panel_heading_template = templating.environment.get_template(
     'templates/panel_heading.html')
 
 
-def panel(title=None, klass="panel-default", key=None):
+def panel(title=None, klass="card-default", key=None):
     def decorator(func):
         @wraps(func)
         def inner(*args, **kwargs):
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 87edcb8..f2dfb6b 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -51,7 +51,7 @@ def next_meeting(meetings):
     return None
 
 
-chrome = panel('Reminders', key='meetings')
+chrome = panel('Reminders', klass="card-info", key='meetings')
 templating.environment.filters['humanize'] = lambda d: arrow.get(d).humanize()
 template = templating.environment.get_template('templates/meetings.html')
 
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index 8a263df..b80fb30 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -9,7 +9,7 @@
       <span class="glyphicon glyphicon-edit"></span>
     </a>
   </div>
-  <div class="card-body">
+  <div class="card-block">
     {{ content }}
-  </div> <!-- end card-body -->
+  </div> <!-- end card-block -->
 </div> <!-- end card -->

From 6d381ecf53904128dfaed2791a6f7a47190ba916 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:18:44 +0000
Subject: [PATCH 433/1001] converted the bookmarks nav bar to the fedora-bootstrap one


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 0015476..8e055af 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -1,8 +1,10 @@
+@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic);
+
    body {
       background-color: #d1d3d4;
     }
 
-    .super-header {
+    /*.super-header {
       background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
       background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
       background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
@@ -10,32 +12,32 @@
       padding: 5px 12px 5px 12px;
       font-family: 'Open Sans', 'sans-serif';
       font-size: 12pt;
-    }
+    }*/
 
-    .super-header img.avatar {
+    .masthead img.avatar {
       margin-right: 10px;
       width: 22.5px;
     }
 
-    .super-header .glyphicon-chevron-down {
+    .masthead .glyphicon-chevron-down {
       color: #58595b;
       margin: 5px 0 0 10px;
       font-size: 18px;
     }
-    .super-header .dropdown {
+    .masthead .dropdown {
       border-radius: 0;
     }
-    .super-header .dropdown img.icon {
+    .masthead .dropdown img.icon {
       margin-right: 20px;
       height: 30px;
       width: auto;
     }
-    .super-header .dropdown .dropdown-header {
+    .masthead .dropdown .dropdown-header {
       font-weight: 700;
       font-size: 16px;
     }
 
-    .super-header input {
+    .masthead input {
       width: 100%;
       border-radius: 0;
       font-family: 'Open Sans', sans-serif;
@@ -43,7 +45,7 @@
       border: 1px solid #d1d3d4;
     }
 
-    .super-header .input-group-addon {
+    .masthead .input-group-addon {
       background-color: #3C6EB4;
       color: #fff;
       border: 0;
@@ -51,36 +53,13 @@
     }
 
     @media (max-width: 768px) {
-      .super-header .input-group {
+      .masthead .input-group {
         margin-top: 20px;
       }
     }
 
     #logo { text-align: left; }
 
-    .bookmarks .navbar.navbar-default {
-      font-family: 'Open Sans', sans-serif;
-      background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
-      background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
-      background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
-      background: linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
-      margin-bottom: 0;
-      text-align: center;
-    }
-
-    .bookmarks .navbar-nav > li > a {
-      padding-bottom: 4.5px;
-      padding-top: 4.5px;
-    }
-
-    /* Bookmarks Bar: active nav item styling */
-    .bookmarks .nav > .active > a,
-    .bookmarks .nav > .active > a:hover,
-    .bookmarks .nav > .active > a:focus {
-      color: #3c6eb4;
-      background-color: transparent;
-      border-bottom: 3px solid #3c6eb4;
-    }
 
     .navbar-default .navbar-toggle {
       border: none;
@@ -90,11 +69,6 @@
       background-color: none;
     }
     @media (max-width:768px) {
-      .bookmarks .nav > .active > a, .bookmarks .nav > .active > a:hover {
-        border-bottom: none;
-        color: #3C6EB4;
-        font-weight: 700;
-      }
       .header .dropdown.edit {
         top: 140px !important;
       }
@@ -384,7 +358,6 @@ font-size: 32pt;
     font-size: 10px;
     color: #a07cbc;
 }
-
 .modal-footer button {
   float: right;
   margin-left: 1em;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 0cc8ebc..71fdf3a 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -8,7 +8,7 @@
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
 </head>
 <body>
-<div class="super-header">
+<div class="masthead">
   <div class="row">
     <div class="col-xs-4" id="logo">
       <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs">
@@ -46,37 +46,33 @@
     </div>
   </div>
 </div>
-<div class="bookmarks">
-  <nav class="navbar navbar-default">
-    <div class="container-fluid">
-      <div class="navbar-header">
-        <button type="button" class="navbar-toggle collapsed"
+<div class="bodycontent">
+
+  <nav class="navbar navbar-light navbar-underline p-t-0 p-b-0">
+        <button type="button" class="navbar-toggler hidden-sm-up"
             data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
           <span class="sr-only">Toggle navigation</span>
-          <span class="icon-bar"></span>
-          <span class="icon-bar"></span>
-          <span class="icon-bar"></span>
+          <span class="icon-bar">_</span>
+          <span class="icon-bar">_</span>
+          <span class="icon-bar">_</span>
         </button>
-      </div>
 
       <!-- Collect the nav links, forms, and other content for toggling -->
-      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
-        <ul class="nav navbar-nav">
+      <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav nav-underline">
           {% if g.auth.logged_in %}
-          <li {% if request.path.endswith('/' + g.auth.user.username + '/') %}class='active'{% endif %}>
-            <a href="/{{g.auth.user.username}}">me</a></li>
+          <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
+            <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
           {% for hub in g.auth.user.bookmarks %}
-          <li class='idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
-          <a href="/{{hub.name}}">{{hub.name}}</a></li>
+          <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
+          <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
           {% endfor %}
           <!-- At the end of the list, tack on a link to all groups -->
-          <li><a href="/groups">all</a></li>
+          <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
           {% endif %}
         </ul>
       </div><!-- /.navbar-collapse -->
-    </div><!-- /.container-fluid -->
   </nav>
-</div>
 <div class="header">
   {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
     {% if not edit %}
@@ -236,6 +232,8 @@
   </div>
 </div>
 
+</div> <!--end bodycontent-->
+
 <script type="text/javascript" src="{{
   url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
   <script type="text/javascript" src="{{

From 9dfeb0b111dd9922f3cf3d697e37ac091480eeff Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:18:44 +0000
Subject: [PATCH 434/1001] added a quick sample logo


---

diff --git a/hubs/static/img/logo-hubs.png b/hubs/static/img/logo-hubs.png
index 88f5ffc..5319490 100644
Binary files a/hubs/static/img/logo-hubs.png and b/hubs/static/img/logo-hubs.png differ
diff --git a/hubs/static/img/logo_hubs.svg b/hubs/static/img/logo_hubs.svg
new file mode 100644
index 0000000..ea7164e
--- /dev/null
+++ b/hubs/static/img/logo_hubs.svg
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="38.887249mm"
+   height="10.583333mm"
+   viewBox="0 0 38.887249 10.583333"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="logo_hubs.svg"
+   inkscape:export-filename="/home/rlerch/Source/fedora-hubs/hubs/static/img/logo-hubs.png"
+   inkscape:export-xdpi="192"
+   inkscape:export-ydpi="192">
+  <defs
+     id="defs4">
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath4574">
+      <circle
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ce5c00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75063962;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="circle4576"
+         cx="93.498596"
+         cy="-16.921354"
+         r="5.5046906"
+         transform="rotate(60)" />
+    </clipPath>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="33.725636"
+     inkscape:cy="8.9793668"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1920"
+     inkscape:window-height="1136"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-48.766898,-31.073162)">
+    <g
+       id="g4714">
+      <g
+         transform="matrix(0.45619308,0,0,0.45619308,25.303771,-9.145808)"
+         id="g4595">
+        <g
+           transform="matrix(0.92003825,0,0,0.92003825,3.8994993,8.9046582)"
+           id="g4624">
+          <text
+             transform="matrix(1.4613695,0,0,1.4613695,-4.7135332,46.848388)"
+             xml:space="preserve"
+             style="font-style:normal;font-weight:normal;font-size:8.11766624px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#555753;fill-opacity:1;stroke:none;stroke-width:0.20294166px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+             x="59.199654"
+             y="40.575024"
+             id="text4225"
+             sodipodi:linespacing="125%"><tspan
+               sodipodi:role="line"
+               id="tspan4227"
+               x="59.199654"
+               y="40.575024"
+               style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#555753;fill-opacity:1;stroke-width:0.20294166px">HUBS</tspan></text>
+          <g
+             id="g4488"
+             transform="matrix(0.13021808,0,0,0.13021808,82.276708,87.323483)">
+            <g
+               id="layer1-0"
+               transform="translate(-266.55899,-345.34488)">
+              <path
+                 style="fill:#3c6eb4"
+                 id="path11"
+                 d="m 316.7736,397.581 c 0,0 0,0 -20.53889,0 0.3327,4.45245 3.92157,7.77609 8.70715,7.77609 3.38983,0 6.31456,-1.39616 8.64094,-3.65507 0.46553,-0.46679 0.99726,-0.59962 1.59519,-0.59962 0.79781,0 1.59561,0.39932 2.12692,1.06388 0.3327,0.46553 0.53216,0.99726 0.53216,1.52857 0,0.73118 -0.3327,1.52857 -0.93106,2.12734 -2.7919,2.99052 -7.51086,4.98503 -12.16403,4.98503 -8.44149,0 -15.22074,-6.77967 -15.22074,-15.22158 0,-8.44149 6.58022,-15.22074 15.02171,-15.22074 8.37529,0 14.62323,6.51317 14.62323,15.08749 0,1.26418 -1.12924,2.12861 -2.39258,2.12861 z m -12.23065,-11.76512 c -4.45329,0 -7.51085,2.92473 -8.17499,7.17731 10.03626,0 16.35083,0 16.35083,0 -0.59836,-4.05355 -3.78874,-7.17731 -8.17584,-7.17731 z"
+                 inkscape:connector-curvature="0" />
+              <path
+                 style="fill:#3c6eb4"
+                 id="path13"
+                 d="m 375.46344,410.80807 c -8.44106,0 -15.22074,-6.77968 -15.22074,-15.22159 0,-8.44149 6.77968,-15.22074 15.22074,-15.22074 8.44234,0 15.22159,6.77925 15.22159,15.22074 -4.2e-4,8.44149 -6.77968,15.22159 -15.22159,15.22159 z m 0,-24.65992 c -5.31688,0 -8.77377,4.25427 -8.77377,9.43833 0,5.18364 3.45689,9.43833 8.77377,9.43833 5.31731,0 8.77504,-4.25469 8.77504,-9.43833 -4.2e-4,-5.18406 -3.45773,-9.43833 -8.77504,-9.43833 z"
+                 inkscape:connector-curvature="0" />
+              <path
+                 style="fill:#3c6eb4"
+                 id="path15"
+                 d="m 412.66183,380.36574 c -4.45963,0 -7.40966,1.319 -10.01391,4.62956 l -0.24036,-1.53995 0,0 c -0.20198,-1.60743 -1.57326,-2.84926 -3.23382,-2.84926 -1.80139,0 -3.26206,1.459 -3.26206,3.26081 0,0.003 0,0.005 0,0.008 l 0,0 0,0.003 0,0 0,23.40712 c 0,1.79464 1.46194,3.25743 3.257,3.25743 1.79465,0 3.25744,-1.46279 3.25744,-3.25743 l 0,-12.56209 c 0,-5.71621 4.98502,-8.57432 10.23613,-8.57432 1.59519,0 2.85726,-1.32953 2.85726,-2.92515 0,-1.59561 -1.26207,-2.85726 -2.85768,-2.85726 z"
+                 inkscape:connector-curvature="0" />
+              <path
+                 style="fill:#3c6eb4"
+                 id="path17"
+                 d="m 447.02614,395.58648 c 0.0666,-8.17541 -5.78326,-15.22074 -15.222,-15.22074 -8.44192,0 -15.28779,6.77925 -15.28779,15.22074 0,8.44191 6.64684,15.22159 14.68985,15.22159 4.01434,0 7.62682,-2.06621 9.23846,-4.22518 l 0.79359,2.01434 0,0 c 0.42589,1.13177 1.5176,1.93717 2.7978,1.93717 1.65001,0 2.98756,-1.33671 2.99009,-2.98545 l 0,0 0,-7.80687 0,0 0,-4.1556 z m -15.222,9.43833 c -5.31773,0 -8.77419,-4.25469 -8.77419,-9.43833 0,-5.18406 3.45604,-9.43833 8.77419,-9.43833 5.3173,0 8.77419,4.25427 8.77419,9.43833 0,5.18364 -3.45689,9.43833 -8.77419,9.43833 z"
+                 inkscape:connector-curvature="0" />
+              <path
+                 style="fill:#3c6eb4"
+                 id="path19"
+                 d="m 355.01479,368.3337 c 0,-1.7938 -1.46194,-3.18997 -3.25659,-3.18997 -1.79422,0 -3.25743,1.39659 -3.25743,3.18997 l 0,17.1499 c -1.66097,-3.05756 -5.25026,-5.11786 -9.50495,-5.11786 -8.64052,0 -14.42336,6.51318 -14.42336,15.22074 0,8.70757 5.98229,15.22159 14.42336,15.22159 3.76555,0 7.03057,-1.55429 8.98587,-4.25554 l 0.72317,1.83428 c 0.44782,1.25912 1.64917,2.16024 3.06051,2.16024 1.78621,0 3.24984,-1.45435 3.24984,-3.24815 0,-0.005 0,-0.009 0,-0.0139 l 0,0 0,-38.95128 -4.2e-4,0 z m -15.22116,36.69111 c -5.31731,0 -8.70715,-4.25469 -8.70715,-9.43833 0,-5.18406 3.38984,-9.43833 8.70715,-9.43833 5.31773,0 8.70714,4.0544 8.70714,9.43833 0,5.38309 -3.38941,9.43833 -8.70714,9.43833 z"
+                 inkscape:connector-curvature="0" />
+              <path
+                 style="fill:#3c6eb4"
+                 id="path21"
+                 d="m 287.21553,365.34023 c -0.59414,-0.0877 -1.19966,-0.13198 -1.80097,-0.13198 -6.73118,0 -12.20746,5.4767 -12.20746,12.20788 l 0,3.8132 -3.98903,0 c -1.46237,0 -2.65908,1.19671 -2.65908,2.65781 0,1.46321 1.19671,2.93738 2.65908,2.93738 l 3.98819,0 0,20.46004 c 0,1.79464 1.46236,3.25743 3.25658,3.25743 1.79507,0 3.25744,-1.46279 3.25744,-3.25743 l 0,-20.46004 4.40986,0 c 1.46194,0 2.65823,-1.47417 2.65823,-2.93738 0,-1.46152 -1.19629,-2.65823 -2.65823,-2.65823 l -4.40733,0 0,-3.8132 c 0,-3.13852 2.55323,-6.11469 5.69175,-6.11469 0.28294,0 0.56757,0.0211 0.84672,0.062 1.78031,0.26355 3.4358,-0.54269 3.70019,-2.32342 0.2627,-1.77904 -0.96606,-3.43538 -2.74594,-3.69935 z"
+                 inkscape:connector-curvature="0" />
+            </g>
+            <path
+               style="fill:#294172;enable-background:new"
+               id="path2391"
+               d="m 181.98344,61.675273 2.81558,0 0,0.37898 -1.18152,0 0,2.94935 -0.45254,0 0,-2.94935 -1.18152,0 0,-0.37898 m 3.26144,0 0.67101,0 0.84937,2.26496 0.85381,-2.26496 0.67102,0 0,3.32833 -0.43917,0 0,-2.9226 -0.85828,2.28279 -0.45255,0 -0.85827,-2.28279 0,2.9226 -0.43694,0 0,-3.32833"
+               inkscape:connector-curvature="0" />
+          </g>
+        </g>
+      </g>
+    </g>
+    <path
+       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.31506309;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="M 8.6191406 3.4980469 L 7.7265625 4.1699219 L 14.023438 12.560547 C 14.291168 12.2999 14.572508 12.057879 14.871094 11.835938 L 8.6191406 3.4980469 z M 28.880859 4.5917969 L 24.427734 11.716797 C 24.742969 11.920204 25.047311 12.138844 25.333984 12.378906 L 29.830078 5.1875 L 28.880859 4.5917969 z M 19.386719 6.6757812 L 18.273438 6.7851562 L 18.625 10.341797 C 18.934929 10.305579 19.250168 10.28125 19.574219 10.28125 C 19.631633 10.28125 19.686977 10.287983 19.744141 10.289062 L 19.386719 6.6757812 z M 19.574219 12.322266 C 19.32096 12.322266 19.070316 12.337075 18.824219 12.363281 L 19.365234 17.830078 L 15.986328 13.324219 C 15.667163 13.516812 15.362813 13.730843 15.080078 13.970703 L 18.833984 18.972656 L 13.121094 16.701172 C 12.98469 17.044848 12.871838 17.40117 12.791016 17.769531 L 17.697266 19.720703 L 12.625 21.205078 L 12.625 21.796875 L 12.625 22.367188 L 18.777344 20.564453 L 14.115234 26.21875 L 15.558594 26.21875 L 19.669922 21.236328 L 20.001953 26.197266 C 20.380191 26.174218 20.750145 26.123675 21.109375 26.042969 L 20.785156 21.208984 L 24.058594 24.580078 C 24.342769 24.340094 24.605473 24.077151 24.847656 23.794922 L 21.574219 20.425781 L 26.248047 21.197266 C 26.349896 20.842083 26.424239 20.476015 26.46875 20.099609 L 21.960938 19.353516 L 26.179688 17.113281 C 26.063571 16.755305 25.917897 16.411578 25.748047 16.082031 L 21.65625 18.259766 L 24.242188 14.125 C 23.964835 13.87337 23.667275 13.643915 23.351562 13.439453 L 20.507812 17.990234 L 19.947266 12.339844 C 19.822736 12.333262 19.700446 12.322266 19.574219 12.322266 z M 32.382812 12.550781 L 27.542969 15.126953 C 27.714672 15.455553 27.861521 15.797747 27.992188 16.148438 L 32.902344 13.541016 L 32.382812 12.550781 z M 6.9296875 14.240234 L 6.5214844 15.277344 L 10.583984 16.892578 L 10.583984 16.730469 L 10.837891 16.994141 L 11.392578 17.214844 C 11.486387 16.851437 11.595421 16.494068 11.724609 16.146484 L 6.9296875 14.240234 z M 28.126953 20.375 C 28.074825 20.747649 27.998258 21.111997 27.90625 21.470703 L 34.396484 22.542969 L 34.578125 21.443359 L 28.126953 20.375 z M 10.583984 21.802734 L 3.6777344 23.824219 L 3.9882812 24.896484 L 10.583984 22.964844 L 10.583984 21.802734 z M 26.105469 25.089844 C 25.870846 25.380941 25.625044 25.660021 25.357422 25.917969 L 28.820312 29.484375 L 29.623047 28.710938 L 26.105469 25.089844 z M 21.248047 28.09375 C 20.888857 28.166383 20.516063 28.207613 20.138672 28.232422 L 20.507812 33.742188 L 21.623047 33.666016 L 21.248047 28.09375 z M 12.560547 28.105469 L 11.166016 29.796875 L 12.023438 30.501953 L 13.873047 28.259766 L 13.427734 28.259766 L 13.414062 28.259766 L 13.054688 28.259766 L 12.994141 28.208984 C 12.845055 28.186127 12.701352 28.150827 12.560547 28.105469 z "
+       transform="matrix(0.28222224,0,0,0.28222224,48.766898,31.073161)"
+       id="path4769" />
+    <path
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4791"
+       d="m 57.554918,32.601226 c 0,-0.339586 -0.27527,-0.61487 -0.614856,-0.61487 -0.339415,0 -0.614614,0.275057 -0.614842,0.614429 l -1.4e-5,-1.5e-5 0,0.475828 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139441 0.139797,0.139441 2.34e-4,0 4.22e-4,-2.9e-5 6.56e-4,-2.9e-5 l 3.4e-5,2.9e-5 0.474603,0 0,0 c 0.339458,-1.35e-4 0.6146,-0.275327 0.6146,-0.614827 z"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4793"
+       d="m 58.668834,34.866188 c 0,-0.339586 -0.27527,-0.61487 -0.614856,-0.61487 -0.339415,0 -0.614614,0.275058 -0.614841,0.614429 l -1.5e-5,-1.4e-5 0,0.475828 1.5e-5,1.4e-5 c 1.71e-4,0.07706 0.06268,0.13944 0.139796,0.13944 2.35e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474604,0 0,0 c 0.339457,-1.34e-4 0.614599,-0.275326 0.614599,-0.614827 z"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4795"
+       d="m 59.1144,37.316804 c 0,-0.339586 -0.27527,-0.61487 -0.614856,-0.61487 -0.339415,0 -0.614613,0.275058 -0.614841,0.614429 l -1.4e-5,-1.4e-5 0,0.475827 1.4e-5,1.5e-5 c 1.72e-4,0.07706 0.06268,0.13944 0.139797,0.13944 2.34e-4,0 4.21e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.3e-5,2.8e-5 0.474604,0 0,0 c 0.339458,-1.34e-4 0.6146,-0.275326 0.6146,-0.614827 z"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4797"
+       d="m 57.74057,39.321853 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339414,0 -0.614613,0.275056 -0.614841,0.614429 l -1.4e-5,-1.6e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139443 0.139797,0.139443 2.34e-4,0 4.21e-4,-2.9e-5 6.56e-4,-2.9e-5 l 3.3e-5,2.9e-5 0.474604,0 0,0 c 0.339458,-1.36e-4 0.6146,-0.275327 0.6146,-0.614828 z"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4799"
+       d="m 55.252824,40.547161 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339414,0 -0.614613,0.275056 -0.614841,0.614429 l -1.4e-5,-1.6e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139442 0.139797,0.139442 2.34e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474603,0 0,0 c 0.339458,-1.35e-4 0.6146,-0.275326 0.6146,-0.614827 z"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4801"
+       d="m 52.181451,40.104467 c 0,-0.339587 -0.27527,-0.61487 -0.614856,-0.61487 -0.339414,0 -0.614613,0.275056 -0.614841,0.614428 l -1.4e-5,-1.4e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.13944 0.139797,0.13944 2.34e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474603,0 0,0 c 0.339458,-1.34e-4 0.6146,-0.275326 0.6146,-0.614825 z"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4803"
+       d="m 50.611507,37.985154 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339415,0 -0.614614,0.275056 -0.614841,0.614429 l -1.4e-5,-1.6e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139442 0.139796,0.139442 2.35e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474604,0 0,0 c 0.339457,-1.36e-4 0.614599,-0.275326 0.614599,-0.614827 z"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4805"
+       d="m 51.168465,35.237494 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339415,0 -0.614613,0.275056 -0.614841,0.614429 l -1.4e-5,-1.6e-5 0,0.475828 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139442 0.139797,0.139442 2.34e-4,0 4.21e-4,-3e-5 6.56e-4,-3e-5 l 3.3e-5,3e-5 0.474604,0 0,0 c 0.339457,-1.36e-4 0.6146,-0.275328 0.6146,-0.614828 z"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4807"
+       d="m 51.762554,32.22992 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339415,0 -0.614614,0.275056 -0.614842,0.614429 l -1.4e-5,-1.5e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139441 0.139797,0.139441 2.34e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474603,0 0,0 c 0.339458,-1.34e-4 0.6146,-0.275326 0.6146,-0.614827 z"
+       inkscape:connector-curvature="0" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 54.732997,32.786878 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339415,0 -0.614614,0.275056 -0.614841,0.614429 l -1.5e-5,-1.5e-5 0,0.475827 1.5e-5,1.4e-5 c 1.71e-4,0.07706 0.06268,0.139441 0.139796,0.139441 2.35e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474604,0 0,0 c 0.339457,-1.34e-4 0.614599,-0.275326 0.614599,-0.614827 z"
+       id="path4809"
+       style="fill:#ffffff;stroke:#ffffff;stroke-width:0.30319569;stroke-miterlimit:4;stroke-dasharray:none" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 56.540131,36.512176 c 0,-1.242182 -1.006917,-2.249152 -2.249097,-2.249152 -1.241555,0 -2.248213,1.006137 -2.249045,2.247538 l -5.2e-5,-5.4e-5 0,1.740539 5.2e-5,5e-5 c 6.58e-4,0.281881 0.22928,0.510069 0.511365,0.510069 8.52e-4,0 0.0015,-1.04e-4 0.0024,-1.04e-4 l 1.23e-4,1.04e-4 1.736064,0 0,0 c 1.241712,-3.87e-4 2.248161,-1.007128 2.248161,-2.24899 z"
+       id="path25"
+       style="fill:#888a85" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 57.554918,32.601226 c 0,-0.339586 -0.27527,-0.61487 -0.614856,-0.61487 -0.339415,0 -0.614614,0.275057 -0.614842,0.614429 l -1.4e-5,-1.5e-5 0,0.475828 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139441 0.139797,0.139441 2.34e-4,0 4.22e-4,-2.9e-5 6.56e-4,-2.9e-5 l 3.4e-5,2.9e-5 0.474603,0 0,0 c 0.339458,-1.35e-4 0.6146,-0.275327 0.6146,-0.614827 z"
+       id="path4773"
+       style="fill:#888a85;fill-opacity:1" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 58.668834,34.866188 c 0,-0.339586 -0.27527,-0.61487 -0.614856,-0.61487 -0.339415,0 -0.614614,0.275058 -0.614841,0.614429 l -1.5e-5,-1.4e-5 0,0.475828 1.5e-5,1.4e-5 c 1.71e-4,0.07706 0.06268,0.13944 0.139796,0.13944 2.35e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474604,0 0,0 c 0.339457,-1.34e-4 0.614599,-0.275326 0.614599,-0.614827 z"
+       id="path4775"
+       style="fill:#888a85;fill-opacity:1" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 59.1144,37.316804 c 0,-0.339586 -0.27527,-0.61487 -0.614856,-0.61487 -0.339415,0 -0.614613,0.275058 -0.614841,0.614429 l -1.4e-5,-1.4e-5 0,0.475827 1.4e-5,1.5e-5 c 1.72e-4,0.07706 0.06268,0.13944 0.139797,0.13944 2.34e-4,0 4.21e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.3e-5,2.8e-5 0.474604,0 0,0 c 0.339458,-1.34e-4 0.6146,-0.275326 0.6146,-0.614827 z"
+       id="path4777"
+       style="fill:#888a85;fill-opacity:1" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 57.74057,39.321853 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339414,0 -0.614613,0.275056 -0.614841,0.614429 l -1.4e-5,-1.6e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139443 0.139797,0.139443 2.34e-4,0 4.21e-4,-2.9e-5 6.56e-4,-2.9e-5 l 3.3e-5,2.9e-5 0.474604,0 0,0 c 0.339458,-1.36e-4 0.6146,-0.275327 0.6146,-0.614828 z"
+       id="path4779"
+       style="fill:#888a85;fill-opacity:1" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 55.252824,40.547161 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339414,0 -0.614613,0.275056 -0.614841,0.614429 l -1.4e-5,-1.6e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139442 0.139797,0.139442 2.34e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474603,0 0,0 c 0.339458,-1.35e-4 0.6146,-0.275326 0.6146,-0.614827 z"
+       id="path4781"
+       style="fill:#888a85;fill-opacity:1" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 52.181451,40.104467 c 0,-0.339587 -0.27527,-0.61487 -0.614856,-0.61487 -0.339414,0 -0.614613,0.275056 -0.614841,0.614428 l -1.4e-5,-1.4e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.13944 0.139797,0.13944 2.34e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474603,0 0,0 c 0.339458,-1.34e-4 0.6146,-0.275326 0.6146,-0.614825 z"
+       id="path4783"
+       style="fill:#888a85;fill-opacity:1" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 50.611507,37.985154 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339415,0 -0.614614,0.275056 -0.614841,0.614429 l -1.4e-5,-1.6e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139442 0.139796,0.139442 2.35e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474604,0 0,0 c 0.339457,-1.36e-4 0.614599,-0.275326 0.614599,-0.614827 z"
+       id="path4785"
+       style="fill:#888a85;fill-opacity:1" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 51.168465,35.237494 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339415,0 -0.614613,0.275056 -0.614841,0.614429 l -1.4e-5,-1.6e-5 0,0.475828 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139442 0.139797,0.139442 2.34e-4,0 4.21e-4,-3e-5 6.56e-4,-3e-5 l 3.3e-5,3e-5 0.474604,0 0,0 c 0.339457,-1.36e-4 0.6146,-0.275328 0.6146,-0.614828 z"
+       id="path4787"
+       style="fill:#888a85;fill-opacity:1" />
+    <path
+       inkscape:connector-curvature="0"
+       d="m 51.762554,32.22992 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339415,0 -0.614614,0.275056 -0.614842,0.614429 l -1.4e-5,-1.5e-5 0,0.475827 1.4e-5,1.4e-5 c 1.72e-4,0.07706 0.06268,0.139441 0.139797,0.139441 2.34e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474603,0 0,0 c 0.339458,-1.34e-4 0.6146,-0.275326 0.6146,-0.614827 z"
+       id="path4789"
+       style="fill:#888a85;fill-opacity:1" />
+    <path
+       style="fill:#888a85;fill-opacity:1"
+       id="path4771"
+       d="m 54.732997,32.786878 c 0,-0.339585 -0.27527,-0.614869 -0.614856,-0.614869 -0.339415,0 -0.614614,0.275056 -0.614841,0.614429 l -1.5e-5,-1.5e-5 0,0.475827 1.5e-5,1.4e-5 c 1.71e-4,0.07706 0.06268,0.139441 0.139796,0.139441 2.35e-4,0 4.22e-4,-2.8e-5 6.56e-4,-2.8e-5 l 3.4e-5,2.8e-5 0.474604,0 0,0 c 0.339457,-1.34e-4 0.614599,-0.275326 0.614599,-0.614827 z"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 71fdf3a..d940c00 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -11,7 +11,7 @@
 <div class="masthead">
   <div class="row">
     <div class="col-xs-4" id="logo">
-      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs">
+      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs" height="40px" class="p-l-1">
     </div>
     <div class="col-sm-4 col-sm-push-4 col-xs-8">
       {% if g.auth.logged_in %}

From 2328f811cf50426ca938aedcfbd92f48333fdc2c Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:19:27 +0000
Subject: [PATCH 435/1001] fixed a menu


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 8e055af..f04cffb 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -14,29 +14,12 @@
       font-size: 12pt;
     }*/
 
-    .masthead img.avatar {
-      margin-right: 10px;
-      width: 22.5px;
-    }
-
-    .masthead .glyphicon-chevron-down {
-      color: #58595b;
-      margin: 5px 0 0 10px;
-      font-size: 18px;
-    }
-    .masthead .dropdown {
-      border-radius: 0;
-    }
-    .masthead .dropdown img.icon {
-      margin-right: 20px;
+    .masthead img#chaticon, .masthead img#avatar {
       height: 30px;
       width: auto;
     }
-    .masthead .dropdown .dropdown-header {
-      font-weight: 700;
-      font-size: 16px;
-    }
 
+/*
     .masthead input {
       width: 100%;
       border-radius: 0;
@@ -51,7 +34,7 @@
       border: 0;
       border-radius: 0;
     }
-
+*/
     @media (max-width: 768px) {
       .masthead .input-group {
         margin-top: 20px;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index d940c00..de3d8eb 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -6,31 +6,31 @@
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
+  <link href="{{ url_for('static', filename='open_iconic_1.1.0/css/open-iconic.min.css') }}"
+        type="text/css" rel="stylesheet" />
 </head>
 <body>
 <div class="masthead">
-  <div class="row">
+  <div class="row p-a-0">
     <div class="col-xs-4" id="logo">
       <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs" height="40px" class="p-l-1">
     </div>
     <div class="col-sm-4 col-sm-push-4 col-xs-8">
       {% if g.auth.logged_in %}
-        <div class="dropdown pull-right">
-          <img class = "icon" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
-        <span class="dropdown-toggle" type="button" id="dropdownMenu1"
-          data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
-          <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
-          {# Logged in as #} {{ g.auth.nickname }}
-          <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
-        </span>
-        <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
-          <li class="dropdown-header">Account Information</li>
-          <li><a href="#">Full Name: {{ g.auth.fullname }}</a></li>
-          <li><a href="#">Email: {{ g.auth.email }}</a></li>
-          <li role="separator" class="divider"></li>
-          <li><a href="#">Separated link</a></li>
-        </ul>
-      </div>
+        <div class="dropdown pull-xs-right">
+          <span class="dropdown-toggle m-r-1" type="button" id="dropdownMenu1"
+            data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+            <img src="{{ g.auth.avatar }}" id="avatar" alt="User Icon"/>
+          </span>
+          <div class="dropdown-menu dropdown-menu-right m-r-1" aria-labelledby="dropdownMenu1">
+            <h6 class="dropdown-header">Account Information</h6>
+            <a href="#" class="dropdown-item">Full Name: {{ g.auth.fullname }}</a>
+            <a href="#" class="dropdown-item">Email: {{ g.auth.email }}</a>
+            <div class="dropdown-divider"></div>
+            <a href="#" class="dropdown-item">Separated link</a>
+          </div>
+        </div>
+        <img id="chaticon" class="pull-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
       {% else %}
         Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
       {% endif %}
@@ -38,9 +38,15 @@
     <div class="col-sm-4 col-sm-pull-4 col-xs-12">
       <!-- NOT HOOKED UP TO ANYTHING XOXO -->
       <div class="input-group">
+<<<<<<< 9dfeb0b111dd9922f3cf3d697e37ac091480eeff
         <input type="search" placeholder="Search across all hubs ..." />
         <span class="input-group-addon">
           <span class="glyphicon glyphicon-search"></span>
+=======
+        <input type="search" class="form-control" placeholder="Search across all hubs ..." aria-describedby="searchform-addon"></input>
+        <span class="input-group-addon" id="searchform-addon">
+          <span class="oi" data-glyph="magnifying-glass" / >
+>>>>>>> fixed a menu
         </span>
     </div>
     </div>
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index f2dfb6b..87edcb8 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -51,7 +51,7 @@ def next_meeting(meetings):
     return None
 
 
-chrome = panel('Reminders', klass="card-info", key='meetings')
+chrome = panel('Reminders', key='meetings')
 templating.environment.filters['humanize'] = lambda d: arrow.get(d).humanize()
 template = templating.environment.get_template('templates/meetings.html')
 
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 95bd2dc..4176c97 100755
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -5,7 +5,7 @@ from hubs.widgets import templating
 
 import hubs.validators as validators
 
-chrome = panel(title='Sticky Note', klass="panel-info")
+chrome = panel(title='Sticky Note', klass="card-info")
 template = templating.environment.get_template('templates/sticky.html')
 
 

From 1d99c122aa39aa9381701762794367378cd7911c Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:27:22 +0000
Subject: [PATCH 436/1001] fixed the edit menu and moved it slightly


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index de3d8eb..5401530 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -38,15 +38,9 @@
     <div class="col-sm-4 col-sm-pull-4 col-xs-12">
       <!-- NOT HOOKED UP TO ANYTHING XOXO -->
       <div class="input-group">
-<<<<<<< 9dfeb0b111dd9922f3cf3d697e37ac091480eeff
-        <input type="search" placeholder="Search across all hubs ..." />
-        <span class="input-group-addon">
-          <span class="glyphicon glyphicon-search"></span>
-=======
         <input type="search" class="form-control" placeholder="Search across all hubs ..." aria-describedby="searchform-addon"></input>
         <span class="input-group-addon" id="searchform-addon">
           <span class="oi" data-glyph="magnifying-glass" / >
->>>>>>> fixed a menu
         </span>
     </div>
     </div>
@@ -58,9 +52,7 @@
         <button type="button" class="navbar-toggler hidden-sm-up"
             data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
           <span class="sr-only">Toggle navigation</span>
-          <span class="icon-bar">_</span>
-          <span class="icon-bar">_</span>
-          <span class="icon-bar">_</span>
+          <span class="oi" data-glyph="menu"></span>
         </button>
 
       <!-- Collect the nav links, forms, and other content for toggling -->
@@ -80,42 +72,6 @@
       </div><!-- /.navbar-collapse -->
   </nav>
 <div class="header">
-  {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
-    {% if not edit %}
-      <div class="dropdown edit">
-        <span class="dropdown-toggle edit-this-page" type="button"
-              id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
-              aria-expanded="true">
-          <a href="#">
-            <span class="glyphicon glyphicon-edit"></span> edit this page
-          </a>
-        </span>
-        <ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
-          <li><a href="#">Customize Header</a></li>
-          <li role="separator" class="divider"></li>
-          <li>
-            <a href="{{ url_for('hub_edit', name=hub.name) }}">
-              Configure Hub
-            </a>
-          </li>
-          {% if not hub.user_hub %}
-          <li role="separator" class="divider"></li>
-          <li><a href="#">Manage Members</a></li>
-          <li role="separator" class="divider"></li>
-          <li><a href="#">Archive Hub</a></li>
-          {% endif %}
-        </ul>
-      </div>
-    {% else %}
-      <div class="dropdown edit">
-        <span id="dropdownMenu2">
-          <span id="save_edits_btn">
-            <span class="glyphicon glyphicon-save"></span> Save changes
-          </span>
-        </span>
-      </div>
-    {% endif %}
-  {% endif %}
   {% if hub.user_hub %}
     <div class="padded center-block medium-wide">
       <img src="{{ hub.avatar }}" class="avatar" />
@@ -157,8 +113,43 @@
 {%- endwith -%}
 
 <div class="container">
-  <div class="row">
-  </div>
+  {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
+      <div class="row">
+        {% if not edit %}
+          <div class="dropdown edit pull-xs-right">
+            <span class="dropdown-toggle edit-this-page" type="button"
+                  id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
+                  aria-expanded="true">
+              <span class="oi" data-glyph="pencil"></span> edit this page
+            </span>
+            <div class="dropdown-menu" aria-labelledby="dropdownMenu2">
+              <a class="dropdown-item" href="#">Customize Header</a>
+              <div class="dropdown-divider"></div>
+              <a class="dropdown-divider"
+                  href="{{ url_for('hub_edit', name=hub.name) }}">
+                Configure Hub
+              </a>
+              {% if not hub.user_hub %}
+              <div class="dropdown-divider"></div>
+              <a class="dropdown-item" href="#">Manage Members</a>
+              <div class="dropdown-divider"></div>
+              <a class="dropdown-item" href="#">Archive Hub</a>
+              {% endif %}
+            </div>
+          </div>
+        {% else %}
+          <div class="dropdown edit">
+            <span id="dropdownMenu2">
+              <span id="save_edits_btn">
+                <span class="glyphicon glyphicon-save"></span> Save changes
+              </span>
+            </span>
+          </div>
+        {% endif %}
+      </div>
+  {% endif %}
+
+
   <div class="row">
     <div class="col-md-{{ hub.left_width }}">
       <!--

From d84e12fcfc2980ea4df7f4bdec742e6fad69bb8b Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:27:22 +0000
Subject: [PATCH 437/1001] added openiconic font


---

diff --git a/hubs/static/open_iconic_1.1.0/css/open-iconic.min.css b/hubs/static/open_iconic_1.1.0/css/open-iconic.min.css
new file mode 100644
index 0000000..1f6afb8
--- /dev/null
+++ b/hubs/static/open_iconic_1.1.0/css/open-iconic.min.css
@@ -0,0 +1 @@
+@font-face{font-family:Icons;src:url(../fonts/open-iconic.eot);src:url(../fonts/open-iconic.eot?#iconic-sm) format('embedded-opentype'),url(../fonts/open-iconic.woff) format('woff'),url(../fonts/open-iconic.ttf) format('truetype'),url(../fonts/open-iconic.otf) format('opentype'),url(../fonts/open-iconic.svg#iconic-sm) format('svg');font-weight:400;font-style:normal}.oi[data-glyph].oi-text-replace{font-size:0;line-height:0}.oi[data-glyph].oi-text-replace:before{width:1em;text-align:center}.oi[data-glyph]:before{font-family:Icons;display:inline-block;speak:none;line-height:1;vertical-align:baseline;font-weight:400;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.oi[data-glyph]:empty:before{width:1em;text-align:center;box-sizing:content-box}.oi[data-glyph].oi-align-left:before{text-align:left}.oi[data-glyph].oi-align-right:before{text-align:right}.oi[data-glyph].oi-align-center:before{text-align:center}.oi[data-glyph].oi-flip-horizontal:before{-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.oi[data-glyph].oi-flip-vertical:before{-webkit-transform:scale(1,-1);-ms-transform:scale(-1,1);transform:scale(1,-1)}.oi[data-glyph].oi-flip-horizontal-vertical:before{-webkit-transform:scale(-1,-1);-ms-transform:scale(-1,1);transform:scale(-1,-1)}.oi[data-glyph=account-login]:before{content:'\e000'}.oi[data-glyph=account-logout]:before{content:'\e001'}.oi[data-glyph=action-redo]:before{content:'\e002'}.oi[data-glyph=action-undo]:before{content:'\e003'}.oi[data-glyph=align-center]:before{content:'\e004'}.oi[data-glyph=align-left]:before{content:'\e005'}.oi[data-glyph=align-right]:before{content:'\e006'}.oi[data-glyph=aperture]:before{content:'\e007'}.oi[data-glyph=arrow-bottom]:before{content:'\e008'}.oi[data-glyph=arrow-circle-bottom]:before{content:'\e009'}.oi[data-glyph=arrow-circle-left]:before{content:'\e00a'}.oi[data-glyph=arrow-circle-right]:before{content:'\e00b'}.oi[data-glyph=arrow-circle-top]:before{content:'\e00c'}.oi[data-glyph=arrow-left]:before{content:'\e00d'}.oi[data-glyph=arrow-right]:before{content:'\e00e'}.oi[data-glyph=arrow-thick-bottom]:before{content:'\e00f'}.oi[data-glyph=arrow-thick-left]:before{content:'\e010'}.oi[data-glyph=arrow-thick-right]:before{content:'\e011'}.oi[data-glyph=arrow-thick-top]:before{content:'\e012'}.oi[data-glyph=arrow-top]:before{content:'\e013'}.oi[data-glyph=audio-spectrum]:before{content:'\e014'}.oi[data-glyph=audio]:before{content:'\e015'}.oi[data-glyph=badge]:before{content:'\e016'}.oi[data-glyph=ban]:before{content:'\e017'}.oi[data-glyph=bar-chart]:before{content:'\e018'}.oi[data-glyph=basket]:before{content:'\e019'}.oi[data-glyph=battery-empty]:before{content:'\e01a'}.oi[data-glyph=battery-full]:before{content:'\e01b'}.oi[data-glyph=beaker]:before{content:'\e01c'}.oi[data-glyph=bell]:before{content:'\e01d'}.oi[data-glyph=bluetooth]:before{content:'\e01e'}.oi[data-glyph=bold]:before{content:'\e01f'}.oi[data-glyph=bolt]:before{content:'\e020'}.oi[data-glyph=book]:before{content:'\e021'}.oi[data-glyph=bookmark]:before{content:'\e022'}.oi[data-glyph=box]:before{content:'\e023'}.oi[data-glyph=briefcase]:before{content:'\e024'}.oi[data-glyph=british-pound]:before{content:'\e025'}.oi[data-glyph=browser]:before{content:'\e026'}.oi[data-glyph=brush]:before{content:'\e027'}.oi[data-glyph=bug]:before{content:'\e028'}.oi[data-glyph=bullhorn]:before{content:'\e029'}.oi[data-glyph=calculator]:before{content:'\e02a'}.oi[data-glyph=calendar]:before{content:'\e02b'}.oi[data-glyph=camera-slr]:before{content:'\e02c'}.oi[data-glyph=caret-bottom]:before{content:'\e02d'}.oi[data-glyph=caret-left]:before{content:'\e02e'}.oi[data-glyph=caret-right]:before{content:'\e02f'}.oi[data-glyph=caret-top]:before{content:'\e030'}.oi[data-glyph=cart]:before{content:'\e031'}.oi[data-glyph=chat]:before{content:'\e032'}.oi[data-glyph=check]:before{content:'\e033'}.oi[data-glyph=chevron-bottom]:before{content:'\e034'}.oi[data-glyph=chevron-left]:before{content:'\e035'}.oi[data-glyph=chevron-right]:before{content:'\e036'}.oi[data-glyph=chevron-top]:before{content:'\e037'}.oi[data-glyph=circle-check]:before{content:'\e038'}.oi[data-glyph=circle-x]:before{content:'\e039'}.oi[data-glyph=clipboard]:before{content:'\e03a'}.oi[data-glyph=clock]:before{content:'\e03b'}.oi[data-glyph=cloud-download]:before{content:'\e03c'}.oi[data-glyph=cloud-upload]:before{content:'\e03d'}.oi[data-glyph=cloud]:before{content:'\e03e'}.oi[data-glyph=cloudy]:before{content:'\e03f'}.oi[data-glyph=code]:before{content:'\e040'}.oi[data-glyph=cog]:before{content:'\e041'}.oi[data-glyph=collapse-down]:before{content:'\e042'}.oi[data-glyph=collapse-left]:before{content:'\e043'}.oi[data-glyph=collapse-right]:before{content:'\e044'}.oi[data-glyph=collapse-up]:before{content:'\e045'}.oi[data-glyph=command]:before{content:'\e046'}.oi[data-glyph=comment-square]:before{content:'\e047'}.oi[data-glyph=compass]:before{content:'\e048'}.oi[data-glyph=contrast]:before{content:'\e049'}.oi[data-glyph=copywriting]:before{content:'\e04a'}.oi[data-glyph=credit-card]:before{content:'\e04b'}.oi[data-glyph=crop]:before{content:'\e04c'}.oi[data-glyph=dashboard]:before{content:'\e04d'}.oi[data-glyph=data-transfer-download]:before{content:'\e04e'}.oi[data-glyph=data-transfer-upload]:before{content:'\e04f'}.oi[data-glyph=delete]:before{content:'\e050'}.oi[data-glyph=dial]:before{content:'\e051'}.oi[data-glyph=document]:before{content:'\e052'}.oi[data-glyph=dollar]:before{content:'\e053'}.oi[data-glyph=double-quote-sans-left]:before{content:'\e054'}.oi[data-glyph=double-quote-sans-right]:before{content:'\e055'}.oi[data-glyph=double-quote-serif-left]:before{content:'\e056'}.oi[data-glyph=double-quote-serif-right]:before{content:'\e057'}.oi[data-glyph=droplet]:before{content:'\e058'}.oi[data-glyph=eject]:before{content:'\e059'}.oi[data-glyph=elevator]:before{content:'\e05a'}.oi[data-glyph=ellipses]:before{content:'\e05b'}.oi[data-glyph=envelope-closed]:before{content:'\e05c'}.oi[data-glyph=envelope-open]:before{content:'\e05d'}.oi[data-glyph=euro]:before{content:'\e05e'}.oi[data-glyph=excerpt]:before{content:'\e05f'}.oi[data-glyph=expand-down]:before{content:'\e060'}.oi[data-glyph=expand-left]:before{content:'\e061'}.oi[data-glyph=expand-right]:before{content:'\e062'}.oi[data-glyph=expand-up]:before{content:'\e063'}.oi[data-glyph=external-link]:before{content:'\e064'}.oi[data-glyph=eye]:before{content:'\e065'}.oi[data-glyph=eyedropper]:before{content:'\e066'}.oi[data-glyph=file]:before{content:'\e067'}.oi[data-glyph=fire]:before{content:'\e068'}.oi[data-glyph=flag]:before{content:'\e069'}.oi[data-glyph=flash]:before{content:'\e06a'}.oi[data-glyph=folder]:before{content:'\e06b'}.oi[data-glyph=fork]:before{content:'\e06c'}.oi[data-glyph=fullscreen-enter]:before{content:'\e06d'}.oi[data-glyph=fullscreen-exit]:before{content:'\e06e'}.oi[data-glyph=globe]:before{content:'\e06f'}.oi[data-glyph=graph]:before{content:'\e070'}.oi[data-glyph=grid-four-up]:before{content:'\e071'}.oi[data-glyph=grid-three-up]:before{content:'\e072'}.oi[data-glyph=grid-two-up]:before{content:'\e073'}.oi[data-glyph=hard-drive]:before{content:'\e074'}.oi[data-glyph=header]:before{content:'\e075'}.oi[data-glyph=headphones]:before{content:'\e076'}.oi[data-glyph=heart]:before{content:'\e077'}.oi[data-glyph=home]:before{content:'\e078'}.oi[data-glyph=image]:before{content:'\e079'}.oi[data-glyph=inbox]:before{content:'\e07a'}.oi[data-glyph=infinity]:before{content:'\e07b'}.oi[data-glyph=info]:before{content:'\e07c'}.oi[data-glyph=italic]:before{content:'\e07d'}.oi[data-glyph=justify-center]:before{content:'\e07e'}.oi[data-glyph=justify-left]:before{content:'\e07f'}.oi[data-glyph=justify-right]:before{content:'\e080'}.oi[data-glyph=key]:before{content:'\e081'}.oi[data-glyph=laptop]:before{content:'\e082'}.oi[data-glyph=layers]:before{content:'\e083'}.oi[data-glyph=lightbulb]:before{content:'\e084'}.oi[data-glyph=link-broken]:before{content:'\e085'}.oi[data-glyph=link-intact]:before{content:'\e086'}.oi[data-glyph=list-rich]:before{content:'\e087'}.oi[data-glyph=list]:before{content:'\e088'}.oi[data-glyph=location]:before{content:'\e089'}.oi[data-glyph=lock-locked]:before{content:'\e08a'}.oi[data-glyph=lock-unlocked]:before{content:'\e08b'}.oi[data-glyph=loop-circular]:before{content:'\e08c'}.oi[data-glyph=loop-square]:before{content:'\e08d'}.oi[data-glyph=loop]:before{content:'\e08e'}.oi[data-glyph=magnifying-glass]:before{content:'\e08f'}.oi[data-glyph=map-marker]:before{content:'\e090'}.oi[data-glyph=map]:before{content:'\e091'}.oi[data-glyph=media-pause]:before{content:'\e092'}.oi[data-glyph=media-play]:before{content:'\e093'}.oi[data-glyph=media-record]:before{content:'\e094'}.oi[data-glyph=media-skip-backward]:before{content:'\e095'}.oi[data-glyph=media-skip-forward]:before{content:'\e096'}.oi[data-glyph=media-step-backward]:before{content:'\e097'}.oi[data-glyph=media-step-forward]:before{content:'\e098'}.oi[data-glyph=media-stop]:before{content:'\e099'}.oi[data-glyph=medical-cross]:before{content:'\e09a'}.oi[data-glyph=menu]:before{content:'\e09b'}.oi[data-glyph=microphone]:before{content:'\e09c'}.oi[data-glyph=minus]:before{content:'\e09d'}.oi[data-glyph=monitor]:before{content:'\e09e'}.oi[data-glyph=moon]:before{content:'\e09f'}.oi[data-glyph=move]:before{content:'\e0a0'}.oi[data-glyph=musical-note]:before{content:'\e0a1'}.oi[data-glyph=paperclip]:before{content:'\e0a2'}.oi[data-glyph=pencil]:before{content:'\e0a3'}.oi[data-glyph=people]:before{content:'\e0a4'}.oi[data-glyph=person]:before{content:'\e0a5'}.oi[data-glyph=phone]:before{content:'\e0a6'}.oi[data-glyph=pie-chart]:before{content:'\e0a7'}.oi[data-glyph=pin]:before{content:'\e0a8'}.oi[data-glyph=play-circle]:before{content:'\e0a9'}.oi[data-glyph=plus]:before{content:'\e0aa'}.oi[data-glyph=power-standby]:before{content:'\e0ab'}.oi[data-glyph=print]:before{content:'\e0ac'}.oi[data-glyph=project]:before{content:'\e0ad'}.oi[data-glyph=pulse]:before{content:'\e0ae'}.oi[data-glyph=puzzle-piece]:before{content:'\e0af'}.oi[data-glyph=question-mark]:before{content:'\e0b0'}.oi[data-glyph=rain]:before{content:'\e0b1'}.oi[data-glyph=random]:before{content:'\e0b2'}.oi[data-glyph=reload]:before{content:'\e0b3'}.oi[data-glyph=resize-both]:before{content:'\e0b4'}.oi[data-glyph=resize-height]:before{content:'\e0b5'}.oi[data-glyph=resize-width]:before{content:'\e0b6'}.oi[data-glyph=rss-alt]:before{content:'\e0b7'}.oi[data-glyph=rss]:before{content:'\e0b8'}.oi[data-glyph=script]:before{content:'\e0b9'}.oi[data-glyph=share-boxed]:before{content:'\e0ba'}.oi[data-glyph=share]:before{content:'\e0bb'}.oi[data-glyph=shield]:before{content:'\e0bc'}.oi[data-glyph=signal]:before{content:'\e0bd'}.oi[data-glyph=signpost]:before{content:'\e0be'}.oi[data-glyph=sort-ascending]:before{content:'\e0bf'}.oi[data-glyph=sort-descending]:before{content:'\e0c0'}.oi[data-glyph=spreadsheet]:before{content:'\e0c1'}.oi[data-glyph=star]:before{content:'\e0c2'}.oi[data-glyph=sun]:before{content:'\e0c3'}.oi[data-glyph=tablet]:before{content:'\e0c4'}.oi[data-glyph=tag]:before{content:'\e0c5'}.oi[data-glyph=tags]:before{content:'\e0c6'}.oi[data-glyph=target]:before{content:'\e0c7'}.oi[data-glyph=task]:before{content:'\e0c8'}.oi[data-glyph=terminal]:before{content:'\e0c9'}.oi[data-glyph=text]:before{content:'\e0ca'}.oi[data-glyph=thumb-down]:before{content:'\e0cb'}.oi[data-glyph=thumb-up]:before{content:'\e0cc'}.oi[data-glyph=timer]:before{content:'\e0cd'}.oi[data-glyph=transfer]:before{content:'\e0ce'}.oi[data-glyph=trash]:before{content:'\e0cf'}.oi[data-glyph=underline]:before{content:'\e0d0'}.oi[data-glyph=vertical-align-bottom]:before{content:'\e0d1'}.oi[data-glyph=vertical-align-center]:before{content:'\e0d2'}.oi[data-glyph=vertical-align-top]:before{content:'\e0d3'}.oi[data-glyph=video]:before{content:'\e0d4'}.oi[data-glyph=volume-high]:before{content:'\e0d5'}.oi[data-glyph=volume-low]:before{content:'\e0d6'}.oi[data-glyph=volume-off]:before{content:'\e0d7'}.oi[data-glyph=warning]:before{content:'\e0d8'}.oi[data-glyph=wifi]:before{content:'\e0d9'}.oi[data-glyph=wrench]:before{content:'\e0da'}.oi[data-glyph=x]:before{content:'\e0db'}.oi[data-glyph=yen]:before{content:'\e0dc'}.oi[data-glyph=zoom-in]:before{content:'\e0dd'}.oi[data-glyph=zoom-out]:before{content:'\e0de'}
\ No newline at end of file
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.eot b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.eot
new file mode 100644
index 0000000..f98177d
Binary files /dev/null and b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.eot differ
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.otf b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.otf
new file mode 100644
index 0000000..f6bd684
Binary files /dev/null and b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.otf differ
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.svg b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.svg
new file mode 100644
index 0000000..559edd9
--- /dev/null
+++ b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.svg
@@ -0,0 +1,543 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<!--
+2014-7-1: Created.
+-->
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+Created by FontForge 20120731 at Tue Jul  1 20:39:22 2014
+ By P.J. Onori
+Created by P.J. Onori with FontForge 2.0 (http://fontforge.sf.net)
+</metadata>
+<defs>
+<font id="open-iconic" horiz-adv-x="800" >
+  <font-face
+    font-family="Icons"
+    font-weight="400"
+    font-stretch="normal"
+    units-per-em="800"
+    panose-1="2 0 5 3 0 0 0 0 0 0"
+    ascent="800"
+    descent="0"
+    bbox="-0.5 -101 802 800.126"
+    underline-thickness="50"
+    underline-position="-100"
+    unicode-range="U+E000-E0DE"
+  />
+    <missing-glyph />
+    <glyph glyph-name="" unicode="&#xe000;"
+d="M300 700h500v-700h-500v100h400v500h-400v100zM400 500l200 -150l-200 -150v100h-400v100h400v100z" />
+    <glyph glyph-name="1" unicode="&#xe001;"
+d="M300 700h500v-700h-500v100h400v500h-400v100zM200 500v-100h400v-100h-400v-100l-200 150z" />
+    <glyph glyph-name="2" unicode="&#xe002;"
+d="M350 700c193 0 350 -157 350 -350v-50h100l-200 -200l-200 200h100v50c0 138 -112 250 -250 250s-250 -112 -250 -250c0 193 157 350 350 350z" />
+    <glyph glyph-name="3" unicode="&#xe003;"
+d="M450 700c193 0 350 -157 350 -350c0 138 -112 250 -250 250s-250 -112 -250 -250v-50h100l-200 -200l-200 200h100v50c0 193 157 350 350 350z" />
+    <glyph glyph-name="4" unicode="&#xe004;"
+d="M0 700h800v-100h-800v100zM100 500h600v-100h-600v100zM0 300h800v-100h-800v100zM100 100h600v-100h-600v100z" />
+    <glyph glyph-name="5" unicode="&#xe005;"
+d="M0 700h800v-100h-800v100zM0 500h600v-100h-600v100zM0 300h800v-100h-800v100zM0 100h600v-100h-600v100z" />
+    <glyph glyph-name="6" unicode="&#xe006;"
+d="M0 700h800v-100h-800v100zM200 500h600v-100h-600v100zM0 300h800v-100h-800v100zM200 100h600v-100h-600v100z" />
+    <glyph glyph-name="7" unicode="&#xe007;"
+d="M400 700c75 0 146 -23 206 -59l-75 -225l-322 234c57 31 122 50 191 50zM125 588l191 -138l-310 -222c-4 24 -6 47 -6 72c0 114 49 215 125 288zM688 575c69 -72 112 -168 112 -275c0 -35 -8 -68 -16 -100h-218zM216 253l112 -347c-128 23 -232 109 -287 222zM372 100
+h372c-64 -109 -177 -185 -310 -197z" />
+    <glyph glyph-name="8" unicode="&#xe008;" horiz-adv-x="600"
+d="M200 800h100v-500h200l-247 -300l-253 300h200v500z" />
+    <glyph glyph-name="9" unicode="&#xe009;"
+d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM300 700v-300h-200l300 -300l300 300h-200v300h-200z" />
+    <glyph glyph-name="a" unicode="&#xe00a;"
+d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700l-300 -300l300 -300v200h300v200h-300v200z" />
+    <glyph glyph-name="b" unicode="&#xe00b;"
+d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700v-200h-300v-200h300v-200l300 300z" />
+    <glyph glyph-name="c" unicode="&#xe00c;"
+d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700l-300 -300h200v-300h200v300h200z" />
+    <glyph glyph-name="d" unicode="&#xe00d;"
+d="M300 600v-200h500v-100h-500v-200l-300 247z" />
+    <glyph glyph-name="e" unicode="&#xe00e;"
+d="M500 600l300 -247l-300 -253v200h-500v100h500v200z" />
+    <glyph glyph-name="f" unicode="&#xe00f;" horiz-adv-x="600"
+d="M200 800h200v-500h200l-297 -300l-303 300h200v500z" />
+    <glyph glyph-name="10" unicode="&#xe010;"
+d="M300 700v-200h500v-200h-500v-200l-300 297z" />
+    <glyph glyph-name="11" unicode="&#xe011;"
+d="M500 700l300 -297l-300 -303v200h-500v200h500v200z" />
+    <glyph glyph-name="12" unicode="&#xe012;" horiz-adv-x="600"
+d="M297 800l303 -300h-200v-500h-200v500h-200z" />
+    <glyph glyph-name="13" unicode="&#xe013;" horiz-adv-x="600"
+d="M247 800l253 -300h-200v-500h-100v500h-200z" />
+    <glyph glyph-name="14" unicode="&#xe014;"
+d="M400 800h100v-800h-100v800zM200 700h100v-600h-100v600zM600 600h100v-400h-100v400zM0 500h100v-200h-100v200z" />
+    <glyph glyph-name="15" unicode="&#xe015;"
+d="M116 600l72 -72c-54 -54 -88 -126 -88 -209s34 -159 88 -213l-72 -72c-72 72 -116 175 -116 285s44 209 116 281zM684 600c72 -72 116 -171 116 -281s-44 -213 -116 -285l-72 72c54 54 88 130 88 213s-34 155 -88 209zM259 460l69 -72c-18 -18 -28 -41 -28 -69
+s10 -54 28 -72l-69 -72c-36 36 -59 89 -59 144s23 105 59 141zM541 459c36 -36 59 -85 59 -140s-23 -108 -59 -144l-69 72c18 18 28 44 28 72s-10 51 -28 69z" />
+    <glyph glyph-name="16" unicode="&#xe016;" horiz-adv-x="400"
+d="M200 800c110 0 200 -90 200 -200s-90 -200 -200 -200s-200 90 -200 200s90 200 200 200zM100 319c31 -11 65 -19 100 -19s68 8 100 19v-319l-100 100l-100 -100v319z" />
+    <glyph glyph-name="17" unicode="&#xe017;"
+d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300c0 -66 21 -126 56 -175l419 419c-49 35 -109 56 -175 56zM644 575l-419 -419c49 -35 109 -56 175 -56c166 0 300 134 300 300
+c0 66 -21 126 -56 175z" />
+    <glyph glyph-name="18" unicode="&#xe018;"
+d="M0 700h100v-600h700v-100h-800v700zM500 700h200v-500h-200v500zM200 500h200v-300h-200v300z" />
+    <glyph glyph-name="19" unicode="&#xe019;"
+d="M397 800c13 1 23 -4 34 -13c2 -2 214 -254 241 -287h128v-100h-100v-366c0 -18 -16 -34 -34 -34h-532c-18 0 -34 16 -34 34v366h-100v100h128l234 281c9 11 22 18 35 19zM400 672l-144 -172h288zM250 300c-28 0 -50 -22 -50 -50v-100c0 -28 22 -50 50 -50s50 22 50 50
+v100c0 28 -22 50 -50 50zM550 300c-28 0 -50 -22 -50 -50v-100c0 -28 22 -50 50 -50s50 22 50 50v100c0 28 -22 50 -50 50z" />
+    <glyph glyph-name="1a" unicode="&#xe01a;"
+d="M9 700h682c6 0 9 -4 9 -10v-190h100v-200h-100v-191c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v582c0 6 3 9 9 9zM100 600v-400h500v400h-500z" />
+    <glyph glyph-name="1b" unicode="&#xe01b;"
+d="M9 700h682c6 0 9 -4 9 -10v-190h100v-200h-100v-191c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v582c0 6 3 9 9 9z" />
+    <glyph glyph-name="1c" unicode="&#xe01c;"
+d="M92 650c0 23 19 50 45 50h3h5h5h500c28 0 50 -22 50 -50s-22 -50 -50 -50h-50v-141c9 -17 120 -231 166 -309c16 -26 34 -61 34 -106c0 -39 -15 -77 -41 -103h-3c-26 -25 -62 -41 -100 -41h-512c-39 0 -77 15 -103 41s-41 64 -41 103c0 46 18 80 34 106
+c46 78 157 292 166 309v141h-50c-2 0 -6 -1 -8 -1c-28 0 -50 23 -50 51zM500 600h-200v-162l-6 -10s-63 -123 -119 -228h450c-56 105 -119 228 -119 228l-6 10v162z" />
+    <glyph glyph-name="1d" unicode="&#xe01d;"
+d="M400 800c110 0 200 -90 200 -200c0 -104 52 -198 134 -266c41 -34 66 -82 66 -134h-800c0 52 25 100 66 134c82 68 134 162 134 266c0 110 90 200 200 200zM300 100h200c0 -55 -45 -100 -100 -100s-100 45 -100 100z" />
+    <glyph glyph-name="1e" unicode="&#xe01e;" horiz-adv-x="600"
+d="M150 800h50l350 -250l-225 -147l225 -153l-350 -250h-50v250l-75 -75l-75 75l150 150l-150 150l75 75l75 -75v250zM250 650v-200l150 100zM250 350v-200l150 100z" />
+    <glyph glyph-name="1f" unicode="&#xe01f;"
+d="M0 800h500c110 0 200 -90 200 -200c0 -47 -17 -91 -44 -125c85 -40 144 -125 144 -225c0 -138 -112 -250 -250 -250h-550v100c55 0 100 45 100 100v400c0 55 -45 100 -100 100v100zM300 700v-200h100c55 0 100 45 100 100s-45 100 -100 100h-100zM300 400v-300h150
+c83 0 150 67 150 150s-67 150 -150 150h-150z" />
+    <glyph glyph-name="20" unicode="&#xe020;" horiz-adv-x="600"
+d="M300 800v-300h200l-300 -500v300h-200z" />
+    <glyph glyph-name="21" unicode="&#xe021;"
+d="M100 800h300v-300l100 100l100 -100v300h50c28 0 50 -22 50 -50v-550h-550c-28 0 -50 -22 -50 -50s22 -50 50 -50h550v-100h-550c-83 0 -150 67 -150 150v550l3 19c8 39 39 70 78 78z" />
+    <glyph glyph-name="22" unicode="&#xe022;" horiz-adv-x="400"
+d="M0 800h400v-800l-200 200l-200 -200v800z" />
+    <glyph glyph-name="23" unicode="&#xe023;"
+d="M0 800h800v-100h-800v100zM0 600h300v-103h203v103h297v-591c0 -6 -3 -9 -9 -9h-782c-6 0 -9 3 -9 9v591z" />
+    <glyph glyph-name="24" unicode="&#xe024;"
+d="M300 800h200c55 0 100 -45 100 -100v-100h191c6 0 9 -3 9 -9v-241c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v241c0 6 3 9 9 9h191v100c0 55 45 100 100 100zM300 700v-100h200v100h-200zM0 209c16 -6 32 -9 50 -9h700c18 0 34 3 50 9v-200c0 -6 -3 -9 -9 -9h-782
+c-6 0 -9 3 -9 9v200z" />
+    <glyph glyph-name="25" unicode="&#xe025;" horiz-adv-x="600"
+d="M300 800c58 0 110 -16 147 -53s53 -89 53 -147h-100c0 39 -11 61 -25 75s-36 25 -75 25c-35 0 -55 -10 -72 -31s-28 -55 -28 -94c0 -51 20 -107 28 -175h172v-100h-178c-14 -60 -49 -127 -113 -200h491v-100h-600v122l16 12c69 69 95 121 106 166h-122v100h125
+c-8 50 -25 106 -25 175c0 58 16 114 50 156c34 43 88 69 150 69z" />
+    <glyph glyph-name="26" unicode="&#xe026;"
+d="M34 700h4h3h4h5h700c28 0 50 -22 50 -50v-700c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v700v2c0 20 15 42 34 48zM150 600c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50zM350 600c-28 0 -50 -22 -50 -50s22 -50 50 -50h300c28 0 50 22 50 50
+s-22 50 -50 50h-300zM100 400v-400h600v400h-600z" />
+    <glyph glyph-name="27" unicode="&#xe027;"
+d="M744 797l6 -3l44 -44c4 -4 3 -8 0 -12l-266 -375l-15 -13l-25 -12c-23 72 -78 127 -150 150l12 25l13 15l375 266zM266 400c74 0 134 -60 134 -134c0 -147 -119 -266 -266 -266c-48 0 -95 12 -134 34c80 46 134 133 134 232c0 74 58 134 132 134z" />
+    <glyph glyph-name="28" unicode="&#xe028;"
+d="M9 451c0 23 19 50 46 50c8 0 19 -3 26 -7l131 -66l29 22c-79 81 -1 250 118 250s197 -167 119 -250l28 -22l131 66c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-115 -56c9 -16 19 -33 25 -50h68c28 0 50 -22 50 -50s-22 -50 -50 -50h-50
+c0 -23 -2 -45 -6 -66l78 -40c21 -5 37 -28 37 -49c0 -28 -22 -50 -50 -50c-10 0 -23 5 -31 11l-65 35c-24 -46 -62 -86 -103 -110c-35 19 -60 45 -60 72v135v4v5v6v5v5v87c0 28 -22 50 -50 50c-24 0 -45 -17 -50 -40c1 -3 1 -8 1 -11s0 -8 -1 -11v-82v-4v-5v-144
+c0 -28 -24 -53 -59 -72c-41 25 -79 64 -103 110l-66 -35c-8 -6 -21 -11 -31 -11c-28 0 -50 22 -50 50c0 21 16 44 37 49l78 40c-4 21 -6 43 -6 66h-50h-5c-28 0 -50 22 -50 50c0 26 22 50 50 50h5h69c6 17 16 34 25 50l-116 56c-16 7 -28 27 -28 45z" />
+    <glyph glyph-name="29" unicode="&#xe029;"
+d="M600 700h91c6 0 9 -3 9 -9v-582c0 -6 -3 -9 -9 -9h-91v600zM210 503l290 147v-500l-250 125v-3c-15 0 -25 -8 -28 -22l75 -178c11 -25 0 -58 -25 -69s-58 0 -69 25l-103 272h-91c-6 0 -9 3 -9 9v182c0 6 3 9 9 9h182z" />
+    <glyph glyph-name="2a" unicode="&#xe02a;"
+d="M9 800h682c6 0 9 -3 9 -9v-782c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v782c0 6 3 9 9 9zM100 700v-200h500v200h-500zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400v-300h100v300h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100z" />
+    <glyph glyph-name="2b" unicode="&#xe02b;"
+d="M0 800h700v-200h-700v200zM0 500h700v-491c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v491zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100z" />
+    <glyph glyph-name="2c" unicode="&#xe02c;"
+d="M409 800h182c6 0 10 -4 12 -9l94 -182c2 -5 6 -9 12 -9h82c6 0 9 -3 9 -9v-582c0 -6 -3 -9 -9 -9h-782c-6 0 -9 3 -9 9v441c0 83 67 150 150 150h141c6 0 10 4 12 9l94 182c2 5 6 9 12 9zM150 500c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z
+M500 500c-110 0 -200 -90 -200 -200s90 -200 200 -200s200 90 200 200s-90 200 -200 200zM500 400c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100s45 100 100 100z" />
+    <glyph glyph-name="2d" unicode="&#xe02d;"
+d="M0 600h800l-400 -400z" />
+    <glyph glyph-name="2e" unicode="&#xe02e;" horiz-adv-x="400"
+d="M400 800v-800l-400 400z" />
+    <glyph glyph-name="2f" unicode="&#xe02f;" horiz-adv-x="400"
+d="M0 800l400 -400l-400 -400v800z" />
+    <glyph glyph-name="30" unicode="&#xe030;"
+d="M400 600l400 -400h-800z" />
+    <glyph glyph-name="31" unicode="&#xe031;"
+d="M0 550c0 23 20 50 46 50h3h5h4h200c17 0 37 -13 44 -28l38 -72h444c14 0 19 -12 15 -25l-81 -250c-4 -13 -21 -25 -35 -25h-350c-14 0 -30 12 -34 25c-27 83 -54 167 -81 250l-10 25h-150c-2 0 -5 -1 -7 -1c-28 0 -51 23 -51 51zM358 100c28 0 50 -22 50 -50
+s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM658 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
+    <glyph glyph-name="32" unicode="&#xe032;"
+d="M0 700h500v-100h-300v-300h-100l-100 -100v500zM300 500h500v-500l-100 100h-400v400z" />
+    <glyph glyph-name="33" unicode="&#xe033;"
+d="M641 700l143 -141l-493 -493c-71 76 -146 148 -219 222l-72 71l141 141c50 -51 101 -101 153 -150c116 117 234 231 347 350z" />
+    <glyph glyph-name="34" unicode="&#xe034;"
+d="M150 600l250 -250l250 250l150 -150l-400 -400l-400 400z" />
+    <glyph glyph-name="35" unicode="&#xe035;" horiz-adv-x="600"
+d="M400 800l150 -150l-250 -250l250 -250l-150 -150l-400 400z" />
+    <glyph glyph-name="36" unicode="&#xe036;" horiz-adv-x="600"
+d="M150 800l400 -400l-400 -400l-150 150l250 250l-250 250z" />
+    <glyph glyph-name="37" unicode="&#xe037;"
+d="M400 600l400 -400l-150 -150l-250 250l-250 -250l-150 150z" />
+    <glyph glyph-name="38" unicode="&#xe038;"
+d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM600 622l-250 -250l-100 100l-72 -72l172 -172l322 322z" />
+    <glyph glyph-name="39" unicode="&#xe039;"
+d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM250 622l-72 -72l150 -150l-150 -150l72 -72l150 150l150 -150l72 72l-150 150l150 150l-72 72l-150 -150z" />
+    <glyph glyph-name="3a" unicode="&#xe03a;"
+d="M350 800c28 0 50 -22 50 -50v-50h75c14 0 25 -11 25 -25v-75h-300v75c0 14 11 25 25 25h75v50c0 28 22 50 50 50zM25 700h75v-200h500v200h75c14 0 25 -11 25 -25v-650c0 -14 -11 -25 -25 -25h-650c-14 0 -25 11 -25 25v650c0 14 11 25 25 25z" />
+    <glyph glyph-name="3b" unicode="&#xe03b;"
+d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM350 600h100v-181c23 -24 47 -47 72 -69l-72 -72c-27 30 -55 59 -84 88l-16 12
+v222z" />
+    <glyph glyph-name="3c" unicode="&#xe03c;"
+d="M450 800c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -18 -3 -34 -9 -50h-191v50c0 83 -67 150 -150 150s-150 -67 -150 -150v-50h-272c-17 30 -28 63 -28 100c0 110 90 200 200 200c23 114 129 200 250 200zM434 400h3h4c3 0 6 1 9 1c28 0 50 -22 50 -50v-1
+v-150h150l-200 -200l-200 200h150v150v2c0 20 15 42 34 48z" />
+    <glyph glyph-name="3d" unicode="&#xe03d;"
+d="M450 800c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -18 -3 -34 -9 -50h-141l-200 200l-200 -200h-222c-17 30 -28 63 -28 100c0 110 90 200 200 200c23 114 129 200 250 200zM450 350l250 -250h-200v-50c0 -28 -22 -50 -50 -50s-50 22 -50 50v50h-200z" />
+    <glyph glyph-name="3e" unicode="&#xe03e;"
+d="M450 700c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -83 -67 -150 -150 -150h-450c-110 0 -200 90 -200 200s90 200 200 200c23 114 129 200 250 200z" />
+    <glyph glyph-name="3f" unicode="&#xe03f;"
+d="M250 800c82 0 154 -40 200 -100c-143 0 -270 -85 -325 -209c-36 -10 -70 -25 -100 -47c-16 33 -25 67 -25 106c0 138 112 250 250 250zM450 600c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -83 -67 -150 -150 -150h-450c-110 0 -200 90 -200 200
+s90 200 200 200c23 114 129 200 250 200z" />
+    <glyph glyph-name="40" unicode="&#xe040;"
+d="M500 700h100l-300 -600h-100zM100 600h100l-100 -200l100 -200h-100l-100 200zM600 600h100l100 -200l-100 -200h-100l100 200z" />
+    <glyph glyph-name="41" unicode="&#xe041;"
+d="M350 800h100l50 -119l28 -12l119 50l72 -72l-50 -119l12 -28l119 -50v-100l-119 -50l-12 -28l50 -119l-72 -72l-119 50l-28 -12l-50 -119h-100l-50 119l-28 12l-119 -50l-72 72l50 119l-12 28l-119 50v100l119 50l12 28l-50 119l72 72l119 -50l28 12zM400 550
+c-83 0 -150 -67 -150 -150s67 -150 150 -150s150 67 150 150s-67 150 -150 150z" />
+    <glyph glyph-name="42" unicode="&#xe042;"
+d="M0 800h800v-200h-800v200zM200 500h400l-200 -200zM0 100h800v-100h-800v100z" />
+    <glyph glyph-name="43" unicode="&#xe043;"
+d="M0 800h100v-800h-100v800zM600 800h200v-800h-200v800zM500 600v-400l-200 200z" />
+    <glyph glyph-name="44" unicode="&#xe044;"
+d="M0 800h200v-800h-200v800zM700 800h100v-800h-100v800zM300 600l200 -200l-200 -200v400z" />
+    <glyph glyph-name="45" unicode="&#xe045;"
+d="M0 800h800v-100h-800v100zM400 500l200 -200h-400zM0 200h800v-200h-800v200z" />
+    <glyph glyph-name="46" unicode="&#xe046;"
+d="M150 700c83 0 150 -67 150 -150v-50h100v50c0 83 67 150 150 150s150 -67 150 -150s-67 -150 -150 -150h-50v-100h50c83 0 150 -67 150 -150s-67 -150 -150 -150s-150 67 -150 150v50h-100v-50c0 -83 -67 -150 -150 -150s-150 67 -150 150s67 150 150 150h50v100h-50
+c-83 0 -150 67 -150 150s67 150 150 150zM150 600c-28 0 -50 -22 -50 -50s22 -50 50 -50h50v50c0 28 -22 50 -50 50zM550 600c-28 0 -50 -22 -50 -50v-50h50c28 0 50 22 50 50s-22 50 -50 50zM300 400v-100h100v100h-100zM150 200c-28 0 -50 -22 -50 -50s22 -50 50 -50
+s50 22 50 50v50h-50zM500 200v-50c0 -28 22 -50 50 -50s50 22 50 50s-22 50 -50 50h-50z" />
+    <glyph glyph-name="47" unicode="&#xe047;"
+d="M0 791c0 5 4 9 9 9h782c6 0 9 -4 9 -10v-790l-200 200h-591c-6 0 -9 3 -9 9v582z" />
+    <glyph glyph-name="48" unicode="&#xe048;"
+d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM600 600l-100 -300l-300 -100l100 300zM400 450c-28 0 -50 -22 -50 -50
+s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
+    <glyph glyph-name="49" unicode="&#xe049;"
+d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700v-600c166 0 300 134 300 300s-134 300 -300 300z" />
+    <glyph glyph-name="4a" unicode="&#xe04a;"
+d="M0 800h800v-100h-800v100zM0 600h500v-100h-500v100zM0 300h800v-100h-800v100zM0 100h600v-100h-600v100zM750 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
+    <glyph glyph-name="4b" unicode="&#xe04b;"
+d="M25 700h750c14 0 25 -11 25 -25v-75h-800v75c0 14 11 25 25 25zM0 500h800v-375c0 -14 -11 -25 -25 -25h-750c-14 0 -25 11 -25 25v375zM100 300v-100h100v100h-100zM300 300v-100h100v100h-100z" />
+    <glyph glyph-name="4c" unicode="&#xe04c;"
+d="M100 800h100v-100h450l100 100l50 -50l-100 -100v-450h100v-100h-100v-100h-100v100h-500v500h-100v100h100v100zM200 600v-350l350 350h-350zM600 550l-350 -350h350v350z" />
+    <glyph glyph-name="4d" unicode="&#xe04d;"
+d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM400 600c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z
+M200 452c0 20 15 42 34 48h3h3h8c12 0 28 -7 36 -16l91 -90l25 6c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100l6 25l-90 91c-9 8 -16 24 -16 36zM550 500c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
+    <glyph glyph-name="4e" unicode="&#xe04e;"
+d="M300 800h200v-300h200l-300 -300l-300 300h200v300zM0 100h800v-100h-800v100z" />
+    <glyph glyph-name="4f" unicode="&#xe04f;"
+d="M0 800h800v-100h-800v100zM400 600l300 -300h-200v-300h-200v300h-200z" />
+    <glyph glyph-name="50" unicode="&#xe050;"
+d="M200 700h600v-600h-600l-200 300zM350 622l-72 -72l150 -150l-150 -150l72 -72l150 150l150 -150l72 72l-150 150l150 150l-72 72l-150 -150z" />
+    <glyph glyph-name="51" unicode="&#xe051;"
+d="M400 700c220 0 400 -180 400 -400h-100c0 166 -134 300 -300 300s-300 -134 -300 -300h-100c0 220 180 400 400 400zM341 491l59 -88l59 88c81 -25 141 -101 141 -191c0 -110 -90 -200 -200 -200s-200 90 -200 200c0 90 60 166 141 191z" />
+    <glyph glyph-name="52" unicode="&#xe052;"
+d="M0 800h300v-400h400v-400h-700v800zM400 800l300 -300h-300v300zM100 600v-100h100v100h-100zM100 400v-100h100v100h-100zM100 200v-100h400v100h-400z" />
+    <glyph glyph-name="53" unicode="&#xe053;" horiz-adv-x="600"
+d="M200 700h100v-100h75c30 0 58 -6 81 -22s44 -44 44 -78v-100h-100v94c-4 3 -13 6 -25 6h-250c-14 0 -25 -11 -25 -25v-50c0 -15 20 -40 34 -44l257 -65c66 -16 109 -73 109 -141v-50c0 -68 -57 -125 -125 -125h-75v-100h-100v100h-75c-30 0 -58 6 -81 22s-44 44 -44 78
+v100h100v-94c4 -3 13 -6 25 -6h250c14 0 25 11 25 25v50c0 15 -20 40 -34 44l-257 65c-66 16 -109 73 -109 141v50c0 68 57 125 125 125h75v100z" />
+    <glyph glyph-name="54" unicode="&#xe054;"
+d="M0 700h300v-300l-300 -300v600zM500 700h300v-300l-300 -300v600z" />
+    <glyph glyph-name="55" unicode="&#xe055;"
+d="M300 700v-600h-300v300zM800 700v-600h-300v300z" />
+    <glyph glyph-name="56" unicode="&#xe056;"
+d="M300 700v-100c-111 0 -200 -89 -200 -200h200v-300h-300v300c0 165 135 300 300 300zM800 700v-100c-111 0 -200 -89 -200 -200h200v-300h-300v300c0 165 135 300 300 300z" />
+    <glyph glyph-name="57" unicode="&#xe057;"
+d="M0 700h300v-300c0 -165 -135 -300 -300 -300v100c111 0 200 89 200 200h-200v300zM500 700h300v-300c0 -165 -135 -300 -300 -300v100c111 0 200 89 200 200h-200v300z" />
+    <glyph glyph-name="58" unicode="&#xe058;" horiz-adv-x="600"
+d="M300 800l34 -34c11 -11 266 -270 266 -488c0 -165 -135 -300 -300 -300s-300 135 -300 300c0 218 255 477 266 488zM150 328c-28 0 -50 -22 -50 -50c0 -110 90 -200 200 -200c28 0 50 22 50 50s-22 50 -50 50c-55 0 -100 45 -100 100c0 28 -22 50 -50 50z" />
+    <glyph glyph-name="59" unicode="&#xe059;"
+d="M400 800l400 -500h-800zM0 200h800v-200h-800v200z" />
+    <glyph glyph-name="5a" unicode="&#xe05a;" horiz-adv-x="600"
+d="M300 800l300 -300h-600zM0 300h600l-300 -300z" />
+    <glyph glyph-name="5b" unicode="&#xe05b;"
+d="M0 500h200v-200h-200v200zM300 500h200v-200h-200v200zM600 500h200v-200h-200v200z" />
+    <glyph glyph-name="5c" unicode="&#xe05c;"
+d="M0 700h800v-100l-400 -200l-400 200v100zM0 500l400 -200l400 200v-400h-800v400z" />
+    <glyph glyph-name="5d" unicode="&#xe05d;"
+d="M400 800l400 -200v-600h-800v600zM400 688l-300 -150v-188l300 -150l300 150v188zM200 500h400v-100l-200 -100l-200 100v100z" />
+    <glyph glyph-name="5e" unicode="&#xe05e;"
+d="M600 700c69 0 134 -19 191 -50l-16 -106c-49 35 -109 56 -175 56c-131 0 -240 -84 -281 -200h331l-16 -100h-334c0 -36 8 -68 19 -100h297l-16 -100h-222c55 -61 133 -100 222 -100c78 0 147 30 200 78v-122c-59 -35 -127 -56 -200 -56c-147 0 -274 82 -344 200h-256
+l19 100h197c-8 32 -16 66 -16 100h-200l25 100h191c45 172 198 300 384 300z" />
+    <glyph glyph-name="5f" unicode="&#xe05f;"
+d="M0 700h700v-100h-700v100zM0 500h500v-100h-500v100zM0 300h800v-100h-800v100zM0 100h100v-100h-100v100zM200 100h100v-100h-100v100zM400 100h100v-100h-100v100z" />
+    <glyph glyph-name="60" unicode="&#xe060;"
+d="M0 800h800v-100h-800v100zM200 600h400l-200 -200zM0 200h800v-200h-800v200z" />
+    <glyph glyph-name="61" unicode="&#xe061;"
+d="M0 800h100v-800h-100v800zM600 800h200v-800h-200v800zM200 600l200 -200l-200 -200v400z" />
+    <glyph glyph-name="62" unicode="&#xe062;"
+d="M0 800h200v-800h-200v800zM700 800h100v-800h-100v800zM600 600v-400l-200 200z" />
+    <glyph glyph-name="63" unicode="&#xe063;"
+d="M0 800h800v-200h-800v200zM400 400l200 -200h-400zM0 100h800v-100h-800v100z" />
+    <glyph glyph-name="64" unicode="&#xe064;"
+d="M0 800h200v-100h-100v-600h600v100h100v-200h-800v800zM400 800h400v-400l-150 150l-250 -250l-100 100l250 250z" />
+    <glyph glyph-name="65" unicode="&#xe065;"
+d="M403 700c247 0 397 -300 397 -300s-150 -300 -397 -300c-253 0 -403 300 -403 300s150 300 403 300zM400 600c-110 0 -200 -90 -200 -200s90 -200 200 -200s200 90 200 200s-90 200 -200 200zM400 500c10 0 19 -3 28 -6c-16 -8 -28 -24 -28 -44c0 -28 22 -50 50 -50
+c20 0 36 12 44 28c3 -9 6 -18 6 -28c0 -55 -45 -100 -100 -100s-100 45 -100 100s45 100 100 100z" />
+    <glyph glyph-name="66" unicode="&#xe066;" horiz-adv-x="900"
+d="M331 700h3h3c3 1 7 1 10 1c12 0 29 -8 37 -17l94 -93l66 65c57 57 155 57 212 0c58 -58 58 -154 0 -212l-65 -66l93 -94c10 -8 18 -25 18 -38c0 -28 -22 -50 -50 -50c-13 0 -32 9 -40 20l-62 65l-381 -381h-269v272l375 381l-63 63c-9 8 -16 24 -16 36c0 20 16 42 35 48z
+M447 481l-313 -315l128 -132l316 316z" />
+    <glyph glyph-name="67" unicode="&#xe067;"
+d="M0 800h300v-400h400v-400h-700v800zM400 800l300 -300h-300v300z" />
+    <glyph glyph-name="68" unicode="&#xe068;"
+d="M200 800c0 0 200 -100 200 -300s-298 -302 -200 -500c0 0 -200 100 -200 300s300 300 200 500zM500 500c0 0 200 -100 200 -300c0 -150 -60 -200 -100 -200h-300c0 200 300 300 200 500z" />
+    <glyph glyph-name="69" unicode="&#xe069;"
+d="M0 800h100v-800h-100v800zM200 800h300v-100h300l-200 -203l200 -197h-400v100h-200v400z" />
+    <glyph glyph-name="6a" unicode="&#xe06a;" horiz-adv-x="400"
+d="M150 800h150l-100 -200h200l-150 -300h150l-300 -300l-100 300h134l66 200h-200z" />
+    <glyph glyph-name="6b" unicode="&#xe06b;"
+d="M0 800h300v-100h500v-100h-800v200zM0 500h800v-450c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v450z" />
+    <glyph glyph-name="6c" unicode="&#xe06c;"
+d="M150 800c83 0 150 -67 150 -150c0 -66 -41 -121 -100 -141v-118c15 5 33 9 50 9h200c28 0 50 22 50 50v59c-59 20 -100 75 -100 141c0 83 67 150 150 150s150 -67 150 -150c0 -66 -41 -121 -100 -141v-59c0 -82 -68 -150 -150 -150h-200c-14 0 -25 -7 -34 -16
+c50 -24 84 -74 84 -134c0 -83 -67 -150 -150 -150s-150 67 -150 150c0 66 41 121 100 141v218c-59 20 -100 75 -100 141c0 83 67 150 150 150z" />
+    <glyph glyph-name="6d" unicode="&#xe06d;"
+d="M0 800h400l-150 -150l150 -150l-100 -100l-150 150l-150 -150v400zM500 400l150 -150l150 150v-400h-400l150 150l-150 150z" />
+    <glyph glyph-name="6e" unicode="&#xe06e;"
+d="M100 800l150 -150l150 150v-400h-400l150 150l-150 150zM400 400h400l-150 -150l150 -150l-100 -100l-150 150l-150 -150v400z" />
+    <glyph glyph-name="6f" unicode="&#xe06f;"
+d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700c-56 0 -108 -17 -153 -44l22 -19c33 -18 13 -48 -13 -59c-30 -13 -77 10 -65 -41c13 -55 -27 -3 -47 -15c-42 -26 49 -152 31 -156l-59 34c-8 0 -13 -5 -16 -10
+c1 -30 10 -57 19 -84c28 -11 77 -2 100 -25c47 -28 97 -115 75 -159c34 -13 68 -22 106 -22c101 0 193 48 247 125c3 24 -8 44 -50 44c-69 0 -156 13 -153 97c2 46 101 108 66 143c-30 30 12 39 12 66c0 37 -65 32 -69 50s20 36 41 56c-30 10 -60 19 -94 19zM631 591
+c-38 -11 -94 -35 -87 -53c6 -15 52 -1 65 -13c11 -10 16 -59 44 -31l22 22v3c-11 26 -26 50 -44 72z" />
+    <glyph glyph-name="70" unicode="&#xe070;"
+d="M703 800l97 -100l-400 -400l-100 100l-200 -203l-100 100l300 303l100 -100zM0 100h800v-100h-800v100z" />
+    <glyph glyph-name="71" unicode="&#xe071;"
+d="M0 700h100v-100h-100v100zM200 700h100v-100h-100v100zM400 700h100v-100h-100v100zM600 700h100v-100h-100v100zM0 500h100v-100h-100v100zM200 500h100v-100h-100v100zM400 500h100v-100h-100v100zM600 500h100v-100h-100v100zM0 300h100v-100h-100v100zM200 300h100
+v-100h-100v100zM400 300h100v-100h-100v100zM600 300h100v-100h-100v100zM0 100h100v-100h-100v100zM200 100h100v-100h-100v100zM400 100h100v-100h-100v100zM600 100h100v-100h-100v100z" />
+    <glyph glyph-name="72" unicode="&#xe072;"
+d="M0 800h200v-200h-200v200zM300 800h200v-200h-200v200zM600 800h200v-200h-200v200zM0 500h200v-200h-200v200zM300 500h200v-200h-200v200zM600 500h200v-200h-200v200zM0 200h200v-200h-200v200zM300 200h200v-200h-200v200zM600 200h200v-200h-200v200z" />
+    <glyph glyph-name="73" unicode="&#xe073;"
+d="M0 800h300v-300h-300v300zM500 800h300v-300h-300v300zM0 300h300v-300h-300v300zM500 300h300v-300h-300v300z" />
+    <glyph glyph-name="74" unicode="&#xe074;"
+d="M19 800h662c11 0 19 -8 19 -19v-331c0 -28 -22 -50 -50 -50h-600c-28 0 -50 22 -50 50v331c0 11 8 19 19 19zM0 309c16 -6 32 -9 50 -9h600c18 0 34 3 50 9v-290c0 -11 -8 -19 -19 -19h-662c-11 0 -19 8 -19 19v290zM550 200c-28 0 -50 -22 -50 -50s22 -50 50 -50
+s50 22 50 50s-22 50 -50 50z" />
+    <glyph glyph-name="75" unicode="&#xe075;"
+d="M0 700h300v-100h-50c-28 0 -50 -22 -50 -50v-150h300v150c0 28 -22 50 -50 50h-50v100h300v-100h-50c-28 0 -50 -22 -50 -50v-400c0 -28 22 -50 50 -50h50v-100h-300v100h50c28 0 50 22 50 50v150h-300v-150c0 -28 22 -50 50 -50h50v-100h-300v100h50c28 0 50 22 50 50
+v400c0 28 -22 50 -50 50h-50v100z" />
+    <glyph glyph-name="76" unicode="&#xe076;"
+d="M400 700c165 0 300 -135 300 -300v-100h50c28 0 50 -22 50 -50v-200c0 -28 -22 -50 -50 -50h-100c-28 0 -50 22 -50 50v350c0 111 -89 200 -200 200s-200 -89 -200 -200v-350c0 -28 -22 -50 -50 -50h-100c-28 0 -50 22 -50 50v200c0 28 22 50 50 50h50v100
+c0 165 135 300 300 300z" />
+    <glyph glyph-name="77" unicode="&#xe077;"
+d="M0 500c0 109 91 200 200 200s200 -91 200 -200c0 109 91 200 200 200s200 -91 200 -200c0 -55 -23 -105 -59 -141l-341 -340l-341 340c-36 36 -59 86 -59 141z" />
+    <glyph glyph-name="78" unicode="&#xe078;"
+d="M400 700l400 -300l-100 3v-403h-200v200h-200v-200h-200v400h-100z" />
+    <glyph glyph-name="79" unicode="&#xe079;"
+d="M0 800h800v-800h-800v800zM100 700v-300l100 100l400 -400h100v100l-200 200l100 100l100 -100v300h-600z" />
+    <glyph glyph-name="7a" unicode="&#xe07a;"
+d="M19 800h762c11 0 19 -8 19 -19v-762c0 -11 -8 -19 -19 -19h-762c-11 0 -19 8 -19 19v762c0 11 8 19 19 19zM100 600v-300h100l100 -100h200l100 100h100v300h-600z" />
+    <glyph glyph-name="7b" unicode="&#xe07b;"
+d="M200 600c80 0 142 -56 200 -122c58 66 119 122 200 122c131 0 200 -101 200 -200s-69 -200 -200 -200c-81 0 -142 56 -200 122c-58 -66 -121 -122 -200 -122c-131 0 -200 101 -200 200s69 200 200 200zM200 500c-74 0 -100 -54 -100 -100s26 -100 100 -100
+c42 0 88 47 134 100c-46 53 -92 100 -134 100zM600 500c-43 0 -88 -47 -134 -100c46 -53 91 -100 134 -100c74 0 100 54 100 100s-26 100 -100 100z" />
+    <glyph glyph-name="7c" unicode="&#xe07c;" horiz-adv-x="400"
+d="M300 800c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100s45 100 100 100zM150 550c83 0 150 -69 150 -150c0 -66 -100 -214 -100 -250c0 -28 22 -50 50 -50s50 22 50 50h100c0 -83 -67 -150 -150 -150s-150 64 -150 150s100 222 100 250s-22 50 -50 50
+s-50 -22 -50 -50h-100c0 83 67 150 150 150z" />
+    <glyph glyph-name="7d" unicode="&#xe07d;"
+d="M200 800h500v-100h-122c-77 -197 -156 -392 -234 -588l-6 -12h162v-100h-500v100h122c77 197 156 392 234 588l7 12h-163v100z" />
+    <glyph glyph-name="7e" unicode="&#xe07e;"
+d="M0 700h800v-100h-800v100zM0 500h800v-100h-800v100zM0 300h800v-100h-800v100zM100 100h600v-100h-600v100z" />
+    <glyph glyph-name="7f" unicode="&#xe07f;"
+d="M0 700h800v-100h-800v100zM0 500h800v-100h-800v100zM0 300h800v-100h-800v100zM0 100h600v-100h-600v100z" />
+    <glyph glyph-name="80" unicode="&#xe080;"
+d="M0 700h800v-100h-800v100zM0 500h800v-100h-800v100zM0 300h800v-100h-800v100zM200 100h600v-100h-600v100z" />
+    <glyph glyph-name="81" unicode="&#xe081;"
+d="M550 800c138 0 250 -112 250 -250s-112 -250 -250 -250c-16 0 -32 0 -47 3l-3 -3v-100h-200v-200h-300v200l303 303c-3 15 -3 31 -3 47c0 138 112 250 250 250zM600 700c-55 0 -100 -45 -100 -100s45 -100 100 -100s100 45 100 100s-45 100 -100 100z" />
+    <glyph glyph-name="82" unicode="&#xe082;"
+d="M134 600h3h4h4h5h500c28 0 50 -22 50 -50v-350h100v-150c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v150h100v350v2c0 20 15 42 34 48zM200 500v-300h100v-100h200v100h100v300h-400z" />
+    <glyph glyph-name="83" unicode="&#xe083;"
+d="M0 800h400v-400h-400v400zM500 600h100v-400h-400v100h300v300zM700 400h100v-400h-400v100h300v300z" />
+    <glyph glyph-name="84" unicode="&#xe084;" horiz-adv-x="600"
+d="M337 694c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-300 -150c-8 -6 -21 -11 -31 -11c-28 0 -50 22 -50 50c0 21 16 44 37 49zM437 544c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-400 -200c-8 -6 -21 -11 -31 -11c-28 0 -50 22 -50 50
+c0 21 16 44 37 49zM437 344c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-106 -56c24 -4 43 -26 43 -50c0 -28 -23 -51 -51 -51c-2 0 -6 1 -8 1h-200c-26 1 -48 24 -48 50c0 16 12 36 26 44zM151 -50c0 23 20 50 46 50h3h4h5h100c28 0 50 -22 50 -50
+s-22 -50 -50 -50h-100c-2 0 -6 -1 -8 -1c-28 0 -50 23 -50 51z" />
+    <glyph glyph-name="85" unicode="&#xe085;"
+d="M199 800h100v-200h-200v100h100v100zM586 797h1c18 1 38 1 56 -3c36 -8 69 -26 97 -54c78 -78 78 -203 0 -281l-150 -150c-8 -13 -28 -24 -43 -24c-28 0 -50 22 -50 50c0 15 11 35 24 43l150 150c40 40 39 105 0 144c-41 41 -110 34 -144 0l-44 -44
+c-8 -13 -27 -24 -42 -24c-28 0 -50 22 -50 50c0 15 11 35 24 43l43 44c32 33 72 53 128 56zM208 490c4 5 14 16 22 16h3c2 0 6 1 8 1c28 0 50 -22 50 -50c0 -11 -6 -27 -14 -35l-150 -150c-40 -40 -39 -105 0 -144c41 -41 110 -34 144 0l44 44c8 13 27 24 42 24
+c28 0 50 -22 50 -50c0 -15 -11 -35 -24 -43l-43 -44c-22 -22 -48 -37 -75 -47c-70 -25 -151 -9 -207 47c-78 78 -78 203 0 281zM499 200h200v-100h-100v-100h-100v200z" />
+    <glyph glyph-name="86" unicode="&#xe086;"
+d="M586 797c18 1 39 1 57 -3c36 -8 69 -26 97 -54c78 -78 78 -203 0 -281l-150 -150c-62 -62 -132 -81 -182 -78s-69 17 -84 25s-26 27 -26 44c0 28 22 51 50 51c8 0 19 -3 26 -7c0 0 15 -11 41 -13s62 3 106 47l150 150c40 40 39 105 0 144c-41 41 -110 34 -144 0
+c-8 -13 -28 -24 -43 -24c-28 0 -50 22 -50 50c0 15 11 35 24 43c32 33 72 53 128 56zM386 566c50 -2 64 -17 85 -22s37 -28 37 -49c0 -28 -22 -50 -50 -50c-10 0 -23 5 -31 11c0 0 -19 9 -47 10s-63 -4 -103 -44l-150 -150c-40 -40 -39 -105 0 -144c41 -41 110 -34 144 0
+c8 13 27 24 42 24c28 0 50 -22 50 -50c0 -15 -10 -35 -23 -43c-22 -22 -48 -37 -75 -47c-70 -25 -151 -9 -207 47c-78 78 -78 203 0 281l150 150c60 60 128 78 178 76z" />
+    <glyph glyph-name="87" unicode="&#xe087;"
+d="M0 700h300v-300h-300v300zM400 700h400v-100h-400v100zM400 500h300v-100h-300v100zM0 300h300v-300h-300v300zM400 300h400v-100h-400v100zM400 100h300v-100h-300v100z" />
+    <glyph glyph-name="88" unicode="&#xe088;"
+d="M50 700c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM200 700h600v-100h-600v100zM50 500c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM200 500h600v-100h-600v100zM50 300c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50
+s22 50 50 50zM200 300h600v-100h-600v100zM50 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM200 100h600v-100h-600v100z" />
+    <glyph glyph-name="89" unicode="&#xe089;"
+d="M800 800l-400 -800l-100 300l-300 100z" />
+    <glyph glyph-name="8a" unicode="&#xe08a;" horiz-adv-x="600"
+d="M300 700c110 0 200 -90 200 -200v-100h100v-400h-600v400h100v100c0 110 90 200 200 200zM300 600c-56 0 -100 -44 -100 -100v-100h200v100c0 56 -44 100 -100 100z" />
+    <glyph glyph-name="8b" unicode="&#xe08b;" horiz-adv-x="600"
+d="M300 800c110 0 200 -90 200 -200v-200h100v-400h-600v400h400v200c0 56 -44 100 -100 100s-100 -44 -100 -100h-100c0 110 90 200 200 200z" />
+    <glyph glyph-name="8c" unicode="&#xe08c;"
+d="M400 700v-100c-111 0 -200 -89 -200 -200h100l-150 -200l-150 200h100c0 165 135 300 300 300zM650 600l150 -200h-100c0 -165 -135 -300 -300 -300v100c111 0 200 89 200 200h-100z" />
+    <glyph glyph-name="8d" unicode="&#xe08d;"
+d="M100 800h600v-300h100l-150 -250l-150 250h100v200h-400v-100h-100v200zM150 550l150 -250h-100v-200h400v100h100v-200h-600v300h-100z" />
+    <glyph glyph-name="8e" unicode="&#xe08e;"
+d="M600 700l200 -150l-200 -150v100h-500v-100h-100v100c0 55 45 100 100 100h500v100zM200 300v-100h500v100h100v-100c0 -55 -45 -100 -100 -100h-500v-100l-200 150z" />
+    <glyph glyph-name="8f" unicode="&#xe08f;" horiz-adv-x="900"
+d="M350 800c193 0 350 -157 350 -350c0 -60 -17 -117 -44 -166c5 -3 12 -8 16 -12l100 -100c16 -16 30 -49 30 -72c0 -56 -46 -102 -102 -102c-23 0 -56 14 -72 30l-100 100c-4 3 -9 9 -12 13c-49 -26 -107 -41 -166 -41c-193 0 -350 157 -350 350s157 350 350 350zM350 200
+c142 0 250 108 250 250c0 139 -111 250 -250 250s-250 -111 -250 -250s111 -250 250 -250z" />
+    <glyph glyph-name="90" unicode="&#xe090;" horiz-adv-x="600"
+d="M300 800c166 0 300 -134 300 -300c0 -200 -300 -500 -300 -500s-300 300 -300 500c0 166 134 300 300 300zM300 700c-110 0 -200 -90 -200 -200s90 -200 200 -200s200 90 200 200s-90 200 -200 200z" />
+    <glyph glyph-name="91" unicode="&#xe091;" horiz-adv-x="900"
+d="M0 800h800v-541c1 -3 1 -8 1 -11s0 -7 -1 -10v-238h-800v800zM495 250c0 26 22 50 50 50h5h150v400h-600v-600h600v100h-150h-5c-28 0 -50 22 -50 50zM350 600c83 0 150 -67 150 -150c0 -100 -150 -250 -150 -250s-150 150 -150 250c0 83 67 150 150 150zM350 500
+c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
+    <glyph glyph-name="92" unicode="&#xe092;" horiz-adv-x="600"
+d="M0 700h200v-600h-200v600zM400 700h200v-600h-200v600z" />
+    <glyph glyph-name="93" unicode="&#xe093;" horiz-adv-x="600"
+d="M0 700l600 -300l-600 -300v600z" />
+    <glyph glyph-name="94" unicode="&#xe094;" horiz-adv-x="600"
+d="M300 700c166 0 300 -134 300 -300s-134 -300 -300 -300s-300 134 -300 300s134 300 300 300z" />
+    <glyph glyph-name="95" unicode="&#xe095;"
+d="M400 700v-600l-400 300zM400 400l400 300v-600z" />
+    <glyph glyph-name="96" unicode="&#xe096;"
+d="M0 700l400 -300l-400 -300v600zM400 100v600l400 -300z" />
+    <glyph glyph-name="97" unicode="&#xe097;"
+d="M0 700h200v-600h-200v600zM200 400l500 300v-600z" />
+    <glyph glyph-name="98" unicode="&#xe098;"
+d="M0 700l500 -300l-500 -300v600zM500 100v600h200v-600h-200z" />
+    <glyph glyph-name="99" unicode="&#xe099;" horiz-adv-x="600"
+d="M0 700h600v-600h-600v600z" />
+    <glyph glyph-name="9a" unicode="&#xe09a;"
+d="M200 800h400v-200h200v-400h-200v-200h-400v200h-200v400h200v200z" />
+    <glyph glyph-name="9b" unicode="&#xe09b;"
+d="M0 700h800v-100h-800v100zM0 403h800v-100h-800v100zM0 103h800v-100h-800v100z" />
+    <glyph glyph-name="9c" unicode="&#xe09c;" horiz-adv-x="600"
+d="M278 700c7 2 13 4 22 4c55 0 100 -45 100 -100v-4v-200c0 -55 -45 -100 -100 -100s-100 45 -100 100v200v2c0 44 35 88 78 98zM34 500h4h3c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-50c0 -111 89 -200 200 -200s200 89 200 200v50c0 28 22 50 50 50s50 -22 50 -50v-50
+c0 -148 -109 -270 -250 -294v-106h50c55 0 100 -45 100 -100h-400c0 55 45 100 100 100h50v106c-141 24 -250 146 -250 294v50v2c0 20 15 42 34 48z" />
+    <glyph glyph-name="9d" unicode="&#xe09d;"
+d="M0 500h800v-200h-800v200z" />
+    <glyph glyph-name="9e" unicode="&#xe09e;"
+d="M34 700h4h3h4h5h700c28 0 50 -22 50 -50v-500c0 -28 -22 -50 -50 -50h-250v-100h100c55 0 100 -45 100 -100h-600c0 55 45 100 100 100h100v100h-250c-28 0 -50 22 -50 50v500v2c0 20 15 42 34 48zM100 600v-400h600v400h-600z" />
+    <glyph glyph-name="9f" unicode="&#xe09f;"
+d="M272 700c-14 -40 -22 -83 -22 -128c0 -221 179 -400 400 -400c45 0 88 8 128 22c-53 -158 -202 -272 -378 -272c-221 0 -400 179 -400 400c0 176 114 325 272 378z" />
+    <glyph glyph-name="a0" unicode="&#xe0a0;"
+d="M350 700l150 -150h-100v-150h150v100l150 -150l-150 -150v100h-150v-150h100l-150 -150l-150 150h100v150h-150v-100l-150 150l150 150v-100h150v150h-100z" />
+    <glyph glyph-name="a1" unicode="&#xe0a1;"
+d="M800 800v-550c0 -83 -67 -150 -150 -150s-150 67 -150 150s67 150 150 150c17 0 35 -4 50 -9v206c-201 -6 -327 -27 -400 -50v-397c0 -83 -67 -150 -150 -150s-150 67 -150 150s67 150 150 150c17 0 35 -4 50 -9v409s100 100 600 100z" />
+    <glyph glyph-name="a2" unicode="&#xe0a2;" horiz-adv-x="700"
+d="M499 700c51 0 102 -20 141 -59c78 -78 78 -203 0 -281l-250 -244c-48 -48 -127 -48 -175 0s-48 127 0 175l96 97l69 -69l-90 -94l-7 -3c-10 -10 -10 -28 0 -38s28 -10 38 0l250 247c37 40 39 102 0 141s-104 40 -144 0l-278 -275c-66 -69 -68 -179 0 -247
+c69 -69 181 -69 250 0l9 12l116 113l69 -69l-125 -125c-107 -107 -281 -107 -388 0s-107 281 0 388l278 272c39 39 90 59 141 59z" />
+    <glyph glyph-name="a3" unicode="&#xe0a3;"
+d="M600 800l200 -200l-100 -100l-200 200zM400 600l200 -200l-400 -400h-200v200z" />
+    <glyph glyph-name="a4" unicode="&#xe0a4;"
+d="M550 800c83 0 150 -90 150 -200s-67 -200 -150 -200c-22 0 -40 8 -59 19c6 26 9 52 9 81c0 84 -27 158 -72 212c27 52 71 88 122 88zM250 700c83 0 150 -90 150 -200s-67 -200 -150 -200s-150 90 -150 200s67 200 150 200zM725 384c44 -22 75 -66 75 -118v-166h-200v66
+c0 50 -17 96 -44 134c66 2 126 33 169 84zM75 284c45 -53 106 -84 175 -84s130 31 175 84c44 -22 75 -66 75 -118v-166h-500v166c0 52 31 96 75 118z" />
+    <glyph glyph-name="a5" unicode="&#xe0a5;"
+d="M400 800c110 0 200 -112 200 -250s-90 -250 -200 -250s-200 112 -200 250s90 250 200 250zM191 300c54 -61 128 -100 209 -100s155 39 209 100c106 -5 191 -92 191 -200v-100h-800v100c0 108 85 195 191 200z" />
+    <glyph glyph-name="a6" unicode="&#xe0a6;" horiz-adv-x="600"
+d="M19 800h462c11 0 19 -8 19 -19v-762c0 -11 -8 -19 -19 -19h-462c-11 0 -19 8 -19 19v762c0 11 8 19 19 19zM100 700v-500h300v500h-300zM250 150c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
+    <glyph glyph-name="a7" unicode="&#xe0a7;"
+d="M350 800c17 0 34 -1 50 -3v-397l-297 297c63 64 150 103 247 103zM500 694c169 -25 300 -168 300 -344c0 -193 -157 -350 -350 -350c-85 0 -161 31 -222 81l272 272v341zM91 562l237 -234l-212 -212c-70 55 -116 138 -116 234c0 84 35 158 91 212z" />
+    <glyph glyph-name="a8" unicode="&#xe0a8;"
+d="M92 650c0 23 20 50 46 50h3h4h5h400c28 0 50 -22 50 -50s-22 -50 -50 -50h-50v-200h100c55 0 100 -45 100 -100h-300v-300l-56 -100l-44 100v300h-300c0 55 45 100 100 100h100v200h-50c-2 0 -6 -1 -8 -1c-28 0 -50 23 -50 51z" />
+    <glyph glyph-name="a9" unicode="&#xe0a9;"
+d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM300 600v-400l300 200z" />
+    <glyph glyph-name="aa" unicode="&#xe0aa;"
+d="M300 800h200v-300h300v-200h-300v-300h-200v300h-300v200h300v300z" />
+    <glyph glyph-name="ab" unicode="&#xe0ab;"
+d="M300 800h100v-400h-100v400zM172 656l62 -78l-40 -31c-58 -46 -94 -117 -94 -197c0 -139 111 -250 250 -250s250 111 250 250c0 80 -39 151 -97 197l-37 31l62 78l38 -31c82 -64 134 -164 134 -275c0 -193 -157 -350 -350 -350s-350 157 -350 350c0 111 53 211 134 275z
+" />
+    <glyph glyph-name="ac" unicode="&#xe0ac;"
+d="M200 800h400v-200h-400v200zM9 500h782c6 0 9 -3 9 -9v-282c0 -6 -3 -9 -9 -9h-91v200h-600v-200h-91c-6 0 -9 3 -9 9v282c0 6 3 9 9 9zM200 300h400v-300h-400v300z" />
+    <glyph glyph-name="ad" unicode="&#xe0ad;"
+d="M0 700h100v-700h-100v700zM700 700h100v-700h-100v700zM200 600h200v-100h-200v100zM300 400h200v-100h-200v100zM400 200h200v-100h-200v100z" />
+    <glyph glyph-name="ae" unicode="&#xe0ae;"
+d="M325 700c42 -141 87 -280 131 -419c29 74 59 148 88 222c30 -57 58 -114 87 -172h169v-100h-231l-13 28c-37 -92 -74 -184 -112 -275c-38 129 -79 257 -119 385c-42 -133 -83 -267 -125 -400c-28 88 -56 175 -84 262h-116v100h188l9 -34l3 -6c42 137 83 273 125 409z" />
+    <glyph glyph-name="af" unicode="&#xe0af;"
+d="M200 600c0 57 43 100 100 100s100 -43 100 -100c0 -28 -18 -48 -28 -72c-3 -6 -3 -16 -3 -28h231v-231c12 0 22 0 28 3c24 10 44 28 72 28c57 0 100 -43 100 -100s-43 -100 -100 -100c-28 0 -48 18 -72 28c-6 3 -16 3 -28 3v-231h-231c0 12 0 22 3 28c10 24 28 44 28 72
+c0 57 -43 100 -100 100s-100 -43 -100 -100c0 -28 18 -48 28 -72c3 -6 3 -16 3 -28h-231v600h231c0 12 0 22 -3 28c-10 24 -28 44 -28 72z" />
+    <glyph glyph-name="b0" unicode="&#xe0b0;" horiz-adv-x="500"
+d="M247 700c84 0 148 -20 191 -59s59 -93 59 -141c0 -117 -69 -181 -119 -225s-81 -67 -81 -150v-25h-100v25c0 117 65 181 115 225s85 67 85 150c0 25 -8 48 -28 66s-56 34 -122 34s-97 -18 -116 -37s-27 -43 -31 -69l-100 12c5 38 19 88 59 128s103 66 188 66zM197 0h100
+v-100h-100v100z" />
+    <glyph glyph-name="b1" unicode="&#xe0b1;"
+d="M450 800c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -69 -48 -127 -112 -144c-22 55 -75 94 -138 94c-20 0 -39 -5 -56 -12c-17 64 -75 112 -144 112s-127 -48 -144 -112c-17 7 -36 12 -56 12c-37 0 -71 -12 -97 -34c-33 36 -53 82 -53 134
+c0 110 90 200 200 200c23 114 129 200 250 200zM334 300h4h3c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-200c0 -28 -22 -50 -50 -50s-50 22 -50 50v200v2c0 20 15 42 34 48zM134 200h4h3c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-100c0 -28 -22 -50 -50 -50s-50 22 -50 50v100v2
+c0 20 15 42 34 48zM534 200h3h4c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-100c0 -28 -22 -50 -50 -50s-50 22 -50 50v100v2c0 20 15 42 34 48z" />
+    <glyph glyph-name="b2" unicode="&#xe0b2;"
+d="M600 800l200 -150l-200 -150v100h-50l-153 -191l175 -206l6 -3h22v100l200 -150l-200 -150v100h-25c-35 0 -56 12 -78 38l-166 190l-153 -190c-22 -27 -43 -38 -78 -38h-100v100h100l166 206l-163 191l-3 3h-100v100h100c34 0 56 -12 78 -38l153 -178l141 178
+c22 27 43 38 78 38h50v100z" />
+    <glyph glyph-name="b3" unicode="&#xe0b3;"
+d="M400 800c110 0 209 -47 281 -119l119 119v-300h-300l109 109c-54 55 -126 91 -209 91c-166 0 -300 -134 -300 -300s134 -300 300 -300c83 0 158 34 212 88l72 -72c-72 -72 -174 -116 -284 -116c-220 0 -400 180 -400 400s180 400 400 400z" />
+    <glyph glyph-name="b4" unicode="&#xe0b4;"
+d="M400 800h400v-400l-166 166l-400 -400l166 -166h-400v400l166 -166l400 400z" />
+    <glyph glyph-name="b5" unicode="&#xe0b5;" horiz-adv-x="600"
+d="M250 800l250 -300h-200v-200h200l-250 -300l-250 300h200v200h-200z" />
+    <glyph glyph-name="b6" unicode="&#xe0b6;"
+d="M300 600v-200h200v200l300 -250l-300 -250v200h-200v-200l-300 250z" />
+    <glyph glyph-name="b7" unicode="&#xe0b7;"
+d="M0 800c441 0 800 -359 800 -800h-200c0 333 -267 600 -600 600v200zM0 500c275 0 500 -225 500 -500h-200c0 167 -133 300 -300 300v200zM0 200c110 0 200 -90 200 -200h-200v200z" />
+    <glyph glyph-name="b8" unicode="&#xe0b8;"
+d="M100 800c386 0 700 -314 700 -700h-100c0 332 -268 600 -600 600v100zM100 600c276 0 500 -224 500 -500h-100c0 222 -178 400 -400 400v100zM100 400c165 0 300 -135 300 -300h-100c0 111 -89 200 -200 200v100zM100 200c55 0 100 -45 100 -100s-45 -100 -100 -100
+s-100 45 -100 100s45 100 100 100z" />
+    <glyph glyph-name="b9" unicode="&#xe0b9;"
+d="M300 800h400c55 0 100 -45 100 -100v-200h-400v150c0 28 -22 50 -50 50s-50 -22 -50 -50v-250h400v-300c0 -55 -45 -100 -100 -100h-500c-55 0 -100 45 -100 100v200h100v-150c0 -28 22 -50 50 -50s50 22 50 50v550c0 55 45 100 100 100z" />
+    <glyph glyph-name="ba" unicode="&#xe0ba;"
+d="M75 700h225v-100h-200v-500h400v100h100v-125c0 -41 -34 -75 -75 -75h-450c-41 0 -75 34 -75 75v550c0 41 34 75 75 75zM600 700l200 -200l-200 -200v100h-200c-94 0 -173 -65 -194 -153c23 199 189 353 394 353v100z" />
+    <glyph glyph-name="bb" unicode="&#xe0bb;"
+d="M500 700l300 -284l-300 -316v200h-100c-200 0 -348 -102 -400 -300c0 295 100 500 500 500v200z" />
+    <glyph glyph-name="bc" unicode="&#xe0bc;"
+d="M381 791l19 9l19 -9c127 -53 253 -108 381 -160v-31c0 -166 -67 -313 -147 -419c-40 -53 -83 -97 -125 -128s-82 -53 -128 -53s-86 22 -128 53s-85 75 -125 128c-80 107 -147 253 -147 419v31c128 52 254 107 381 160zM400 100v591l-294 -122c8 -126 58 -243 122 -328
+c35 -46 73 -86 106 -110s62 -31 66 -31z" />
+    <glyph glyph-name="bd" unicode="&#xe0bd;"
+d="M600 800h100v-800h-100v800zM400 700h100v-700h-100v700zM200 500h100v-500h-100v500zM0 300h100v-300h-100v300z" />
+    <glyph glyph-name="be" unicode="&#xe0be;"
+d="M300 800h100v-200h200l100 -100l-100 -100h-200v-400h-100v500h-200l-100 100l100 100h200v100z" />
+    <glyph glyph-name="bf" unicode="&#xe0bf;"
+d="M200 800h100v-600h200l-250 -200l-250 200h200v600zM400 800h200v-100h-200v100zM400 600h300v-100h-300v100zM400 400h400v-100h-400v100z" />
+    <glyph glyph-name="c0" unicode="&#xe0c0;"
+d="M200 800h100v-600h200l-250 -200l-250 200h200v600zM400 800h400v-100h-400v100zM400 600h300v-100h-300v100zM400 400h200v-100h-200v100z" />
+    <glyph glyph-name="c1" unicode="&#xe0c1;"
+d="M75 700h650c41 0 75 -34 75 -75v-550c0 -41 -34 -75 -75 -75h-650c-41 0 -75 34 -75 75v550c0 41 34 75 75 75zM100 600v-100h100v100h-100zM300 600v-100h400v100h-400zM100 400v-100h100v100h-100zM300 400v-100h400v100h-400zM100 200v-100h100v100h-100zM300 200
+v-100h400v100h-400z" />
+    <glyph glyph-name="c2" unicode="&#xe0c2;"
+d="M400 800l100 -300h300l-250 -200l100 -300l-250 200l-250 -200l100 300l-250 200h300z" />
+    <glyph glyph-name="c3" unicode="&#xe0c3;"
+d="M400 800c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM150 700c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM650 700c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM400 600c110 0 200 -90 200 -200
+s-90 -200 -200 -200s-200 90 -200 200s90 200 200 200zM50 450c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM750 450c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM150 200c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50
+s22 50 50 50zM650 200c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM400 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
+    <glyph glyph-name="c4" unicode="&#xe0c4;"
+d="M34 800h632c18 0 34 -16 34 -34v-732c0 -18 -16 -34 -34 -34h-632c-18 0 -34 16 -34 34v732c0 18 16 34 34 34zM100 700v-500h500v500h-500zM350 150c-38 0 -63 -42 -44 -75s69 -33 88 0s-6 75 -44 75z" />
+    <glyph glyph-name="c5" unicode="&#xe0c5;"
+d="M0 800h300l500 -500l-300 -300l-500 500v300zM200 700c-55 0 -100 -45 -100 -100s45 -100 100 -100s100 45 100 100s-45 100 -100 100z" />
+    <glyph glyph-name="c6" unicode="&#xe0c6;"
+d="M0 600h200l300 -300l-200 -200l-300 300v200zM340 600h160l300 -300l-200 -200l-78 78l119 122zM150 500c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
+    <glyph glyph-name="c7" unicode="&#xe0c7;"
+d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM400 600c110 0 200 -90 200 -200s-90 -200 -200 -200s-200 90 -200 200
+s90 200 200 200zM400 500c-56 0 -100 -44 -100 -100s44 -100 100 -100s100 44 100 100s-44 100 -100 100z" />
+    <glyph glyph-name="c8" unicode="&#xe0c8;"
+d="M0 700h559l-100 -100h-359v-500h500v159l100 100v-359h-700v700zM700 700l100 -100l-400 -400l-200 200l100 100l100 -100z" />
+    <glyph glyph-name="c9" unicode="&#xe0c9;"
+d="M9 800h782c6 0 9 -3 9 -9v-782c0 -6 -3 -9 -9 -9h-782c-6 0 -9 3 -9 9v782c0 6 3 9 9 9zM150 722l-72 -72l100 -100l-100 -100l72 -72l172 172zM400 500v-100h300v100h-300z" />
+    <glyph glyph-name="ca" unicode="&#xe0ca;"
+d="M0 800h800v-200h-50c0 55 -45 100 -100 100h-150v-550c0 -28 22 -50 50 -50h50v-100h-400v100h50c28 0 50 22 50 50v550h-150c-55 0 -100 -45 -100 -100h-50v200z" />
+    <glyph glyph-name="cb" unicode="&#xe0cb;"
+d="M0 700h100v-400h-100v400zM200 700h350c21 0 39 -13 47 -31c0 0 103 -291 103 -319s-22 -50 -50 -50h-150c-28 0 -50 -25 -50 -50s39 -158 47 -184s-5 -55 -31 -63s-52 5 -66 31s-109 219 -128 238s-44 28 -72 28v400z" />
+    <glyph glyph-name="cc" unicode="&#xe0cc;"
+d="M400 666c10 19 28 32 47 34l19 -3c26 -8 39 -37 31 -63s-47 -159 -47 -184s22 -50 50 -50h150c28 0 50 -22 50 -50s-103 -319 -103 -319c-8 -18 -26 -31 -47 -31h-350v400c28 0 53 9 72 28s114 212 128 238zM0 400h100v-400h-100v400z" />
+    <glyph glyph-name="cd" unicode="&#xe0cd;"
+d="M200 700h300v-100h-100v-6c25 -4 50 -8 72 -16l-34 -94c-28 11 -58 16 -88 16c-139 0 -250 -111 -250 -250s111 -250 250 -250s250 111 250 250c0 31 -5 60 -16 88l91 37c14 -38 25 -81 25 -125c0 -193 -157 -350 -350 -350s-350 157 -350 350c0 176 130 323 300 347v3
+h-100v100zM700 584c0 0 -296 -348 -316 -368s-48 -20 -68 0s-20 48 0 68s384 300 384 300z" />
+    <glyph glyph-name="ce" unicode="&#xe0ce;"
+d="M600 700l200 -150l-200 -150v100h-600v100h600v100zM200 300v-100h600v-100h-600v-100l-200 150z" />
+    <glyph glyph-name="cf" unicode="&#xe0cf;"
+d="M300 800h100c55 0 100 -45 100 -100h100c55 0 100 -45 100 -100h-700c0 55 45 100 100 100h100c0 55 45 100 100 100zM100 500h100v-350c0 -28 22 -50 50 -50s50 22 50 50v350h100v-350c0 -28 22 -50 50 -50s50 22 50 50v350h100v-481c0 -11 -8 -19 -19 -19h-462
+c-11 0 -19 8 -19 19v481z" />
+    <glyph glyph-name="d0" unicode="&#xe0d0;"
+d="M100 800h200v-400c0 -55 45 -100 100 -100s100 45 100 100v400h100v-400c0 -110 -90 -200 -200 -200h-50c-138 0 -250 90 -250 200v400zM0 100h700v-100h-700v100z" />
+    <glyph glyph-name="d1" unicode="&#xe0d1;"
+d="M9 700h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v482c0 6 3 9 9 9zM609 700h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v482c0 6 3 9 9 9zM309 500h182c6 0 9 -3 9 -9v-282c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v282
+c0 6 3 9 9 9zM0 100h800v-100h-800v100z" />
+    <glyph glyph-name="d2" unicode="&#xe0d2;"
+d="M10 700h181c6 0 9 -3 9 -9v-191h-200v191c0 6 4 9 10 9zM610 700h181c6 0 9 -3 9 -9v-191h-200v191c0 6 5 9 10 9zM310 600h181c6 0 9 -3 9 -9v-91h-200v91c0 6 4 9 10 9zM0 400h800v-100h-800v100zM0 200h200v-191c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v191zM300 200
+h200v-91c0 -6 -3 -9 -9 -9h-181c-6 0 -10 3 -10 9v91zM600 200h200v-191c0 -6 -3 -9 -9 -9h-181c-6 0 -10 3 -10 9v191z" />
+    <glyph glyph-name="d3" unicode="&#xe0d3;"
+d="M0 700h800v-100h-800v100zM9 500h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v482c0 6 3 9 9 9zM309 500h182c6 0 9 -3 9 -9v-282c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v282c0 6 3 9 9 9zM609 500h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182
+c-6 0 -9 3 -9 9v482c0 6 3 9 9 9z" />
+    <glyph glyph-name="d4" unicode="&#xe0d4;"
+d="M50 600h500c28 0 50 -22 50 -50v-150l100 100h100v-300h-100l-100 100v-150c0 -28 -22 -50 -50 -50h-500c-28 0 -50 22 -50 50v400c0 28 22 50 50 50z" />
+    <glyph glyph-name="d5" unicode="&#xe0d5;"
+d="M334 800h66v-800h-66l-134 200h-200v400h200zM500 600v100c26 0 52 -4 75 -10c130 -33 225 -150 225 -290s-95 -258 -225 -291h-3c-23 -6 -47 -9 -72 -9v100c17 0 34 2 50 6c86 22 150 100 150 194s-64 172 -150 194c-16 4 -33 6 -50 6zM500 500l25 -3
+c44 -11 75 -51 75 -97s-32 -86 -75 -97l-25 -3v200z" />
+    <glyph glyph-name="d6" unicode="&#xe0d6;" horiz-adv-x="600"
+d="M334 800h66v-800h-66l-134 200h-200v400h200zM500 500l25 -3c44 -11 75 -51 75 -97s-32 -86 -75 -97l-25 -3v200z" />
+    <glyph glyph-name="d7" unicode="&#xe0d7;" horiz-adv-x="400"
+d="M334 800h66v-800h-66l-134 200h-200v400h200z" />
+    <glyph glyph-name="d8" unicode="&#xe0d8;"
+d="M309 800h82c6 0 10 -4 12 -9l294 -682l3 -19v-81c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v81l3 19l294 682c2 5 6 9 12 9zM300 500v-200h100v200h-100zM300 200v-100h100v100h-100z" />
+    <glyph glyph-name="d9" unicode="&#xe0d9;"
+d="M375 800c138 0 269 -39 378 -109l-53 -82c-93 60 -205 91 -325 91c-119 0 -229 -32 -322 -91l-53 82c109 70 237 109 375 109zM375 500c78 0 154 -23 216 -62l-53 -85c-46 30 -104 47 -163 47c-60 0 -112 -17 -159 -47l-54 85c62 40 134 62 213 62zM375 200
+c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100s45 100 100 100z" />
+    <glyph glyph-name="da" unicode="&#xe0da;" horiz-adv-x="900"
+d="M551 800c16 0 32 0 47 -3l-97 -97v-200h200l97 97c3 -15 3 -31 3 -47c0 -138 -112 -250 -250 -250c-32 0 -62 8 -90 19l-288 -291c-20 -20 -46 -28 -72 -28s-52 8 -72 28c-39 39 -39 105 0 144l291 287c-11 28 -19 59 -19 91c0 138 112 250 250 250zM101 150
+c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
+    <glyph glyph-name="db" unicode="&#xe0db;"
+d="M141 700c84 -84 169 -167 253 -250c82 83 167 165 247 250l143 -141l-253 -253c84 -82 167 -166 253 -247l-143 -143c-81 86 -165 169 -247 253l-253 -253l-141 143c85 80 167 164 250 247c-83 84 -166 169 -250 253z" />
+    <glyph glyph-name="dc" unicode="&#xe0dc;"
+d="M0 800h100l231 -300h38l231 300h100l-225 -300h225v-100h-300v-100h300v-100h-300v-200h-100v200h-300v100h300v100h-300v100h225z" />
+    <glyph glyph-name="dd" unicode="&#xe0dd;" horiz-adv-x="900"
+d="M350 800c193 0 350 -157 350 -350c0 -61 -17 -119 -44 -169c4 -2 10 -6 13 -9l103 -100c16 -16 30 -49 30 -72c0 -56 -46 -102 -102 -102c-23 0 -56 14 -72 30l-100 103c-3 3 -7 9 -9 13c-50 -28 -108 -44 -169 -44c-193 0 -350 157 -350 350s157 350 350 350zM350 700
+c-139 0 -250 -111 -250 -250s111 -250 250 -250c62 0 119 23 163 60c7 11 19 25 31 31l3 3c34 43 53 97 53 156c0 139 -111 250 -250 250zM300 600h100v-100h100v-100h-100v-100h-100v100h-100v100h100v100z" />
+    <glyph glyph-name="de" unicode="&#xe0de;" horiz-adv-x="900"
+d="M350 800c193 0 350 -157 350 -350c0 -61 -17 -119 -44 -169c4 -2 10 -6 13 -9l103 -100c16 -16 30 -49 30 -72c0 -56 -46 -102 -102 -102c-23 0 -56 14 -72 30l-100 103c-3 3 -7 9 -9 13c-50 -28 -108 -44 -169 -44c-193 0 -350 157 -350 350s157 350 350 350zM350 700
+c-139 0 -250 -111 -250 -250s111 -250 250 -250c62 0 119 23 163 60c7 11 19 25 31 31l3 3c34 43 53 97 53 156c0 139 -111 250 -250 250zM200 500h300v-100h-300v100z" />
+  </font>
+</defs></svg>
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.ttf b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.ttf
new file mode 100644
index 0000000..fab6048
Binary files /dev/null and b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.ttf differ
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.woff b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.woff
new file mode 100644
index 0000000..f930998
Binary files /dev/null and b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.woff differ

From 712ece7acd5ec0a2608bd928ead243ede6e38c31 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:30:49 +0000
Subject: [PATCH 438/1001] made the pointer show on menus


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index f04cffb..854ff32 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -19,6 +19,8 @@
       width: auto;
     }
 
+    .showpointer{cursor:pointer;}
+
 /*
     .masthead input {
       width: 100%;
@@ -67,12 +69,12 @@
       font-family: 'Open Sans', sans-serif;
     }
 
-    .header .dropdown.edit {
+    /*.header .dropdown.edit {
       position: absolute;
       top: 90px;
       right: 0;
       z-index: 2;
-    }
+    }*/
 
     .header .img-wrap {
       max-height: 100px;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 5401530..ee181c5 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -17,7 +17,7 @@
     </div>
     <div class="col-sm-4 col-sm-push-4 col-xs-8">
       {% if g.auth.logged_in %}
-        <div class="dropdown pull-xs-right">
+        <div class="dropdown pull-xs-right showpointer">
           <span class="dropdown-toggle m-r-1" type="button" id="dropdownMenu1"
             data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
             <img src="{{ g.auth.avatar }}" id="avatar" alt="User Icon"/>
@@ -116,7 +116,7 @@
   {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
       <div class="row">
         {% if not edit %}
-          <div class="dropdown edit pull-xs-right">
+          <div class="dropdown edit pull-xs-right showpointer">
             <span class="dropdown-toggle edit-this-page" type="button"
                   id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
                   aria-expanded="true">

From 56daee78d98fd0f84433744f0e6c396f2130f564 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 23 2016 07:57:23 +0000
Subject: [PATCH 439/1001] converting add widget content to fedora-bootstrap


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index ee181c5..1813be1 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -113,7 +113,7 @@
 {%- endwith -%}
 
 <div class="container">
-  {% if g.auth.logged_in and not edit and hub.is_admin(g.auth.user) %}
+  {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
       <div class="row">
         {% if not edit %}
           <div class="dropdown edit pull-xs-right showpointer">
@@ -125,7 +125,7 @@
             <div class="dropdown-menu" aria-labelledby="dropdownMenu2">
               <a class="dropdown-item" href="#">Customize Header</a>
               <div class="dropdown-divider"></div>
-              <a class="dropdown-divider"
+              <a class="dropdown-item"
                   href="{{ url_for('hub_edit', name=hub.name) }}">
                 Configure Hub
               </a>
@@ -138,12 +138,8 @@
             </div>
           </div>
         {% else %}
-          <div class="dropdown edit">
-            <span id="dropdownMenu2">
-              <span id="save_edits_btn">
-                <span class="glyphicon glyphicon-save"></span> Save changes
-              </span>
-            </span>
+          <div id="save_edits_btn" class="pull-xs-right">
+            <span class="oi" data-glyph="data-transfer-download"></span> Save changes
           </div>
         {% endif %}
       </div>
@@ -182,11 +178,13 @@
 
       {% if edit %}
       <div id='add-widget-left' class='widget row'>
-        <div class="panel panel-default panel-visible">
-          <div class="panel-body">
+        <div class="card">
+          <div class="card-block">
             <h4>
-              <a href="#"><span class="glyphicon glyphicon-plus">
-              </span> Add a widget</a>
+              <a href="#">
+                <span class="oi"
+                      data-glyph="plus"></span> Add a widget
+              </a>
             </h4>
           </div>
         </div>
@@ -203,11 +201,13 @@
     <div class="col-md-{{ hub.right_width }}">
       {% if edit %}
       <div id='add-widget-right' class='widget row'>
-        <div class="panel panel-default panel-visible">
-          <div class="panel-body">
+        <div class="card">
+          <div class="card-block">
             <h4>
-              <a href="#"><span class="glyphicon glyphicon-plus">
-              </span> Add a widget</a>
+              <a href="#">
+                <span class="oi"
+                      data-glyph="plus"></span> Add a widget
+              </a>
             </h4>
           </div>
         </div>

From a96f61c95202e95f21b61bb39dd3f5f0cf26135e Mon Sep 17 00:00:00 2001
From: kjtdimuthu <kjtdimuthu@gmail.com>
Date: Apr 24 2016 15:01:42 +0000
Subject: [PATCH 440/1001] A footer for is added with request button in meeting widget


---

diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 1d5e126..717e047 100755
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -7,19 +7,23 @@ _panel_heading_template = templating.environment.get_template(
     'templates/panel_heading.html')
 
 
-def panel(title=None, klass="card-default", key=None):
+def panel(title=None, klass="panel-default", key=None, footer_template=None):
     def decorator(func):
         @wraps(func)
         def inner(*args, **kwargs):
             heading = ''
+            footer = ''
             if title:
                 heading = _panel_heading_template.render(title=title)
+            if footer_template:
+                footer = footer_template.render(**kwargs)
             content = func(*args, **kwargs)
             if key and not kwargs.get(key):
                 return content
             return _panel_template.render(
                 content=content,
                 heading=heading,
+                footer=footer,
                 klass=klass(kwargs) if callable(klass) else klass,
                 **kwargs)
         return inner
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 87edcb8..3a40832 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -51,7 +51,8 @@ def next_meeting(meetings):
     return None
 
 
-chrome = panel('Reminders', key='meetings')
+footer_template = templating.environment.get_template('templates/meeting_footer.html')
+chrome = panel(title = 'Reminders', key='meetings', footer_template=footer_template)
 templating.environment.filters['humanize'] = lambda d: arrow.get(d).humanize()
 template = templating.environment.get_template('templates/meetings.html')
 
diff --git a/hubs/widgets/templates/meeting_footer.html b/hubs/widgets/templates/meeting_footer.html
new file mode 100644
index 0000000..52b13e2
--- /dev/null
+++ b/hubs/widgets/templates/meeting_footer.html
@@ -0,0 +1,5 @@
+<div class="panel-footer panel-heading">
+	<div class="row" align="center">
+		<a class="btn btn-default" style="color: #a07cbc" id="modalBtn" href="#modal"><strong>Request A New Meeting</strong></a>
+	</div>
+</div>
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index b80fb30..8e64bb9 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -12,4 +12,7 @@
   <div class="card-block">
     {{ content }}
   </div> <!-- end card-block -->
+{% if footer %}
+    {{footer}}
+{% endif %} 
 </div> <!-- end card -->

From 2bdfb643997bbe79b2479f244c49f1d2ca11fe3c Mon Sep 17 00:00:00 2001
From: kjtdimuthu <kjtdimuthu@gmail.com>
Date: Apr 25 2016 15:30:30 +0000
Subject: [PATCH 441/1001] styles and id of request button was removed


---

diff --git a/hubs/widgets/templates/meeting_footer.html b/hubs/widgets/templates/meeting_footer.html
index 52b13e2..f45acc0 100644
--- a/hubs/widgets/templates/meeting_footer.html
+++ b/hubs/widgets/templates/meeting_footer.html
@@ -1,5 +1,5 @@
 <div class="panel-footer panel-heading">
 	<div class="row" align="center">
-		<a class="btn btn-default" style="color: #a07cbc" id="modalBtn" href="#modal"><strong>Request A New Meeting</strong></a>
+		<a class="btn btn-default" href="#"><strong>Request A New Meeting</strong></a>
 	</div>
 </div>

From 69c320cbef2c205cd89f5802b1915c144d686604 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 08:30:58 +0000
Subject: [PATCH 442/1001] Fix HTML indentation and fix re-ordering the widget in a hub in edit mode


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 1813be1..5d3891b 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -98,7 +98,8 @@
               if category == 'error' %}alert-warning{%
               else %}alert-info{%
               endif %} alert-dismissible" role="alert">
-              <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+              <button type="button" class="close" data-dismiss="alert"
+                  aria-label="Close">
                 <span aria-hidden="true">&times;</span>
                 <span class="sr-only">Close</span>
               </button>
@@ -139,7 +140,8 @@
           </div>
         {% else %}
           <div id="save_edits_btn" class="pull-xs-right">
-            <span class="oi" data-glyph="data-transfer-download"></span> Save changes
+            <span class="oi" data-glyph="data-transfer-download"></span>
+            Save changes
           </div>
         {% endif %}
       </div>
@@ -182,8 +184,7 @@
           <div class="card-block">
             <h4>
               <a href="#">
-                <span class="oi"
-                      data-glyph="plus"></span> Add a widget
+                <span class="oi" data-glyph="plus"></span> Add a widget
               </a>
             </h4>
           </div>
@@ -205,8 +206,7 @@
           <div class="card-block">
             <h4>
               <a href="#">
-                <span class="oi"
-                      data-glyph="plus"></span> Add a widget
+                <span class="oi" data-glyph="plus"></span> Add a widget
               </a>
             </h4>
           </div>
@@ -249,7 +249,7 @@ function make_widget_sortable() {
   Sortable.create(byId('right_widgets'), {
     animation: 150,
     draggable: '.widget',
-    handle: '.panel',
+    handle: '.card',
   });
 
 };

From 5adbae33557a48164c110a2ca4037b6529d98f0b Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 09:25:42 +0000
Subject: [PATCH 443/1001] Add a script to remove the cache of one or more widgets as needed


---

diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
new file mode 100755
index 0000000..b1b32c5
--- /dev/null
+++ b/smart_cache_invalidator.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+
+"""
+Small script to remove the cache of one or more widgets while keeping the
+other ones un-touched.
+
+This is really useful for development purposes as it allow seeing changes
+made to a widget without dropping the entire cache database.
+"""
+
+
+import argparse
+import os
+
+import anydbm
+import fedmsg.config
+import fedmsg.meta
+
+import hubs.models
+
+# get the DB session
+fedmsg_config = fedmsg.config.load_config()
+fedmsg.meta.make_processors(**fedmsg_config)
+
+session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+
+
+def do_list(args):
+    ''' List the different widget for which there is data cached. '''
+    db = anydbm.open(args.cache_db)
+    for key in db.keys():
+        widget_id = key.split('|')[0]
+        widget = hubs.models.Widget.get(session, widget_id)
+        if widget:
+            print '- Widget cached %s (#%s) in %s' % (
+                widget.hub_id, widget_id, widget.plugin)
+    db.close()
+
+
+def do_clean(args):
+    ''' Clean the widget for which there is data cached. '''
+    for ext in ['.dogpile.lock', '.rw.lock']:
+        filename = args.cache_db + ext
+        if os.path.exists(filename):
+            os.unlink(filename)
+
+    db = anydbm.open(args.cache_db, 'w')
+    for key in db.keys():
+        widget_id = key.split('|')[0]
+        widget = hubs.models.Widget.get(session, widget_id)
+        if args.widget in [widget.plugin if widget else '', widget_id]:
+            del(db[key])
+            break
+    db.close()
+
+
+def setup_parser():
+    '''
+    Set the main arguments.
+    '''
+    parser = argparse.ArgumentParser(prog="smart_cache_invalidator")
+    # General connection options
+    parser.add_argument('--cache-db', dest="cache_db",
+                        default='/var/tmp/fedora-hubs-cache.db',
+                        help="The Fedora-hubs cache database")
+
+    subparsers = parser.add_subparsers(title='actions')
+
+    # List
+    parser_list = subparsers.add_parser(
+        'list',
+        help='List the different widgets for which there is cached data')
+    parser_list.set_defaults(func=do_list)
+
+    # Clean
+    parser_clean = subparsers.add_parser(
+        'clean', help='Clean the specified widget')
+    parser_clean.add_argument(
+        'widget', help="Identifier or name of the widget to clean")
+    parser_clean.set_defaults(func=do_clean)
+
+    return parser
+
+
+def main():
+    ''' Main function '''
+    return_code = 0
+
+    # Set up parser for global args
+    parser = setup_parser()
+
+    # Parse the commandline
+    try:
+        arg = parser.parse_args()
+    except argparse.ArgumentTypeError as err:
+        print("\nError: {0}".format(err))
+        return 1
+
+    if not os.path.exists(arg.cache_db):
+        print('No cache DB found')
+        return 2
+
+    try:
+        arg.func(arg)
+    except KeyboardInterrupt:
+        print("\nInterrupted by user.")
+        return_code = 3
+    except argparse.ArgumentError as err:
+        print('{0}'.format(err.message))
+        return_code = 4
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        return_code = 5
+
+    return return_code
+
+
+if __name__ == '__main__':
+    main()

From 175998a6ef9a426ed561ddf1747f074e3b74c2d6 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 09:25:42 +0000
Subject: [PATCH 444/1001] Fix printing using the print function


---

diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index b1b32c5..ee8f298 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -8,6 +8,7 @@ This is really useful for development purposes as it allow seeing changes
 made to a widget without dropping the entire cache database.
 """
 
+from __future__ import print_function
 
 import argparse
 import os
@@ -32,8 +33,8 @@ def do_list(args):
         widget_id = key.split('|')[0]
         widget = hubs.models.Widget.get(session, widget_id)
         if widget:
-            print '- Widget cached %s (#%s) in %s' % (
-                widget.hub_id, widget_id, widget.plugin)
+            print('- Widget cached {0} (#{1}) in {2}'.format(
+                      widget.hub_id, widget_id, widget.plugin))
     db.close()
 
 

From d102cc4c4c8f167bab1fed3356f3f3764009de27 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 09:25:42 +0000
Subject: [PATCH 445/1001] Allow cleaning the cache of multiple widgets at once


---

diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index ee8f298..7e53851 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -46,12 +46,15 @@ def do_clean(args):
             os.unlink(filename)
 
     db = anydbm.open(args.cache_db, 'w')
-    for key in db.keys():
-        widget_id = key.split('|')[0]
-        widget = hubs.models.Widget.get(session, widget_id)
-        if args.widget in [widget.plugin if widget else '', widget_id]:
-            del(db[key])
-            break
+    for widget in args.widgets:
+        for key in db.keys():
+            widget_id = key.split('|')[0]
+            wid_obj = hubs.models.Widget.get(session, widget_id)
+            if widget in [wid_obj.plugin if wid_obj else '', widget_id]:
+                print('- Removing cached {0} (#{1}) in {2}'.format(
+                      widget.hub_id, widget_id, widget.plugin))
+                del(db[key])
+                break
     db.close()
 
 
@@ -77,7 +80,8 @@ def setup_parser():
     parser_clean = subparsers.add_parser(
         'clean', help='Clean the specified widget')
     parser_clean.add_argument(
-        'widget', help="Identifier or name of the widget to clean")
+        'widgets', nargs="+",
+        help="Identifier or name of the one or moe widgets to clean")
     parser_clean.set_defaults(func=do_clean)
 
     return parser

From 79adf552ad245cdee178816e7fed5e6df7fd5bf7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 09:25:42 +0000
Subject: [PATCH 446/1001] Adjust the smart_cache_invalidator script to rely on the base widget


The methods present in the base widget allow easy interacting with the
cache database without having to do anything manually.

---

diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index 7e53851..08737ee 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -13,11 +13,13 @@ from __future__ import print_function
 import argparse
 import os
 
-import anydbm
+import dogpile.cache
 import fedmsg.config
 import fedmsg.meta
 
+
 import hubs.models
+import hubs.widgets.base
 
 # get the DB session
 fedmsg_config = fedmsg.config.load_config()
@@ -28,34 +30,26 @@ session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 
 def do_list(args):
     ''' List the different widget for which there is data cached. '''
-    db = anydbm.open(args.cache_db)
-    for key in db.keys():
-        widget_id = key.split('|')[0]
-        widget = hubs.models.Widget.get(session, widget_id)
-        if widget:
+    for widget in session.query(hubs.models.Widget).all():
+        key = hubs.widgets.base.cache_key_generator(widget, **widget.config)
+        result = hubs.widgets.base.cache.get(key, ignore_expiration=True)
+        if not isinstance(result, dogpile.cache.api.NoValue):
             print('- Widget cached {0} (#{1}) in {2}'.format(
-                      widget.hub_id, widget_id, widget.plugin))
-    db.close()
+                      widget.hub_id, widget.idx, widget.plugin))
 
 
 def do_clean(args):
     ''' Clean the widget for which there is data cached. '''
-    for ext in ['.dogpile.lock', '.rw.lock']:
-        filename = args.cache_db + ext
-        if os.path.exists(filename):
-            os.unlink(filename)
-
-    db = anydbm.open(args.cache_db, 'w')
     for widget in args.widgets:
-        for key in db.keys():
-            widget_id = key.split('|')[0]
-            wid_obj = hubs.models.Widget.get(session, widget_id)
-            if widget in [wid_obj.plugin if wid_obj else '', widget_id]:
-                print('- Removing cached {0} (#{1}) in {2}'.format(
-                      widget.hub_id, widget_id, widget.plugin))
-                del(db[key])
-                break
-    db.close()
+        wid_obj = hubs.models.Widget.get(session, widget)
+        if not wid_obj:
+            wid_obj = session.query(cls).filter_by(plugin=widget).first()
+        if not wid_obj:
+            print('No widget found for {0}'.format(widget))
+
+        print('- Removing cached {0} (#{1}) in {2}'.format(
+              wid_obj.hub_id, wid_obj.idx, wid_obj.plugin))
+        result = hubs.widgets.base.invalidate_cache(wid_obj, **wid_obj.config)
 
 
 def setup_parser():

From 7240c9b397759610a8d3b749126004fdfaa7be14 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 09:25:42 +0000
Subject: [PATCH 447/1001] Simplify the arguments accepted by the script


We can do this now that we rely on hubs itself to point us to where
the cache is.

---

diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index 08737ee..77021fc 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -42,8 +42,11 @@ def do_clean(args):
     ''' Clean the widget for which there is data cached. '''
     for widget in args.widgets:
         wid_obj = hubs.models.Widget.get(session, widget)
+
         if not wid_obj:
-            wid_obj = session.query(cls).filter_by(plugin=widget).first()
+            wid_obj = session.query(hubs.models.Widget).filter_by(
+                plugin=widget).first()
+
         if not wid_obj:
             print('No widget found for {0}'.format(widget))
 
@@ -57,11 +60,6 @@ def setup_parser():
     Set the main arguments.
     '''
     parser = argparse.ArgumentParser(prog="smart_cache_invalidator")
-    # General connection options
-    parser.add_argument('--cache-db', dest="cache_db",
-                        default='/var/tmp/fedora-hubs-cache.db',
-                        help="The Fedora-hubs cache database")
-
     subparsers = parser.add_subparsers(title='actions')
 
     # List
@@ -95,21 +93,14 @@ def main():
         print("\nError: {0}".format(err))
         return 1
 
-    if not os.path.exists(arg.cache_db):
-        print('No cache DB found')
-        return 2
-
     try:
         arg.func(arg)
     except KeyboardInterrupt:
         print("\nInterrupted by user.")
-        return_code = 3
-    except argparse.ArgumentError as err:
-        print('{0}'.format(err.message))
-        return_code = 4
+        return_code = 2
     except Exception as err:
         print('Error: {0}'.format(err))
-        return_code = 5
+        return_code = 3
 
     return return_code
 

From b3ae3955634ed643472bf9ff93e1437934264e39 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 09:39:03 +0000
Subject: [PATCH 448/1001] Bring back the source/widget/edit buttons for each panel


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 854ff32..c39f680 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -356,3 +356,15 @@ font-size: 32pt;
 #save_edits_btn {
     cursor: pointer;
 }
+
+.pull-right {
+  float: right;
+}
+
+.widget-buttons {
+  font-size: 10px;
+}
+
+.edit_widget {
+  cursor: pointer;
+}
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index 8e64bb9..b4270f0 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -1,18 +1,18 @@
 <div class="card {{ klass }}">
-  {{ heading }}
   <div class="pull-right widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
-    <a href="{{ source_url }}"><span class="glyphicon glyphicon-eye-open"></span></a>
-    <a href="{{ widget_url }}"><span class="glyphicon glyphicon-new-window"></span></a>
+    <a href="{{ source_url }}"><span class="oi" data-glyph="eye"></span></a>
+    <a href="{{ widget_url }}"><span class="oi" data-glyph="external-link"></span></a>
     <a data-target="#edit_modal" data-toggle="modal" type="button"
         class="edit_widget" data-idx="{{ widget.idx }}">
-      <span class="glyphicon glyphicon-edit"></span>
+      <span class="oi" data-glyph="pencil"></span>
     </a>
   </div>
+  {{ heading }}
   <div class="card-block">
     {{ content }}
   </div> <!-- end card-block -->
 {% if footer %}
-    {{footer}}
-{% endif %} 
+  {{footer}}
+{% endif %}
 </div> <!-- end card -->

From b8889cf68accb7a53d776cf6ead06a11d0840f7e Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 09:49:39 +0000
Subject: [PATCH 449/1001] Fix indentation in the HTML


---

diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index b4270f0..71cb1f6 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -12,7 +12,7 @@
   <div class="card-block">
     {{ content }}
   </div> <!-- end card-block -->
-{% if footer %}
-  {{footer}}
-{% endif %}
+  {% if footer %}
+    {{footer}}
+  {% endif %}
 </div> <!-- end card -->

From e7e827ce915ef2b9974c424dc2a5cfbb7ce59cf3 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 10:09:50 +0000
Subject: [PATCH 450/1001] Remove the old bootstrap files we're no longer using


---

diff --git a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap-theme.css b/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap-theme.css
deleted file mode 100644
index b2e1981..0000000
--- a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap-theme.css
+++ /dev/null
@@ -1,347 +0,0 @@
-/*!
- * Bootstrap v3.1.1 (http://getbootstrap.com)
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-.btn-default,
-.btn-primary,
-.btn-success,
-.btn-info,
-.btn-warning,
-.btn-danger {
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
-}
-.btn-default:active,
-.btn-primary:active,
-.btn-success:active,
-.btn-info:active,
-.btn-warning:active,
-.btn-danger:active,
-.btn-default.active,
-.btn-primary.active,
-.btn-success.active,
-.btn-info.active,
-.btn-warning.active,
-.btn-danger.active {
-  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-}
-.btn:active,
-.btn.active {
-  background-image: none;
-}
-.btn-default {
-  text-shadow: 0 1px 0 #fff;
-  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
-  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #dbdbdb;
-  border-color: #ccc;
-}
-.btn-default:hover,
-.btn-default:focus {
-  background-color: #e0e0e0;
-  background-position: 0 -15px;
-}
-.btn-default:active,
-.btn-default.active {
-  background-color: #e0e0e0;
-  border-color: #dbdbdb;
-}
-.btn-primary {
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
-  background-image:         linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #2b669a;
-}
-.btn-primary:hover,
-.btn-primary:focus {
-  background-color: #2d6ca2;
-  background-position: 0 -15px;
-}
-.btn-primary:active,
-.btn-primary.active {
-  background-color: #2d6ca2;
-  border-color: #2b669a;
-}
-.btn-success {
-  background-image: -webkit-linear-gradient(top, #79db32 0%, #5cb11f 100%);
-  background-image:         linear-gradient(to bottom, #79db32 0%, #5cb11f 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff5cb11f', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #58a81e;
-}
-.btn-success:hover,
-.btn-success:focus {
-  background-color: #5cb11f;
-  background-position: 0 -15px;
-}
-.btn-success:active,
-.btn-success.active {
-  background-color: #5cb11f;
-  border-color: #58a81e;
-}
-.btn-info {
-  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #8255a6 100%);
-  background-image:         linear-gradient(to bottom, #a07cbc 0%, #8255a6 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff8255a6', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #7d519f;
-}
-.btn-info:hover,
-.btn-info:focus {
-  background-color: #8255a6;
-  background-position: 0 -15px;
-}
-.btn-info:active,
-.btn-info.active {
-  background-color: #8255a6;
-  border-color: #7d519f;
-}
-.btn-warning {
-  background-image: -webkit-linear-gradient(top, #e59728 0%, #b97616 100%);
-  background-image:         linear-gradient(to bottom, #e59728 0%, #b97616 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffb97616', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #b07015;
-}
-.btn-warning:hover,
-.btn-warning:focus {
-  background-color: #b97616;
-  background-position: 0 -15px;
-}
-.btn-warning:active,
-.btn-warning.active {
-  background-color: #b97616;
-  border-color: #b07015;
-}
-.btn-danger {
-  background-image: -webkit-linear-gradient(top, #db3279 0%, #b11f5c 100%);
-  background-image:         linear-gradient(to bottom, #db3279 0%, #b11f5c 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb11f5c', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #a81e58;
-}
-.btn-danger:hover,
-.btn-danger:focus {
-  background-color: #b11f5c;
-  background-position: 0 -15px;
-}
-.btn-danger:active,
-.btn-danger.active {
-  background-color: #b11f5c;
-  border-color: #a81e58;
-}
-.thumbnail,
-.img-thumbnail {
-  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-}
-.dropdown-menu > li > a:hover,
-.dropdown-menu > li > a:focus {
-  background-color: #e8e8e8;
-  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
-  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
-  background-repeat: repeat-x;
-}
-.dropdown-menu > .active > a,
-.dropdown-menu > .active > a:hover,
-.dropdown-menu > .active > a:focus {
-  background-color: #357ebd;
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
-  background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
-  background-repeat: repeat-x;
-}
-.navbar-default {
-  background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
-  background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
-}
-.navbar-default .navbar-nav > .active > a {
-  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
-  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
-  background-repeat: repeat-x;
-  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
-}
-.navbar-brand,
-.navbar-nav > li > a {
-  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
-}
-.navbar-inverse {
-  background-image: -webkit-linear-gradient(top, #365698 0%, #294172 100%);
-  background-image:         linear-gradient(to bottom, #365698 0%, #294172 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff365698', endColorstr='#ff294172', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-}
-.navbar-inverse .navbar-nav > .active > a {
-  background-image: -webkit-linear-gradient(top, #294172 0%, #2c467b 100%);
-  background-image:         linear-gradient(to bottom, #294172 0%, #2c467b 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff294172', endColorstr='#ff2c467b', GradientType=0);
-  background-repeat: repeat-x;
-  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
-          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
-}
-.navbar-inverse .navbar-brand,
-.navbar-inverse .navbar-nav > li > a {
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
-}
-.navbar-static-top,
-.navbar-fixed-top,
-.navbar-fixed-bottom {
-  border-radius: 0;
-}
-.alert {
-  text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
-}
-.alert-success {
-  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #c7f0a9 100%);
-  background-image:         linear-gradient(to bottom, #dcf6ca 0%, #c7f0a9 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffc7f0a9', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #b2ea89;
-}
-.alert-info {
-  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e3d9eb 100%);
-  background-image:         linear-gradient(to bottom, #f6f2f8 0%, #e3d9eb 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe3d9eb', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #d1bfdf;
-}
-.alert-warning {
-  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f4d4a5 100%);
-  background-image:         linear-gradient(to bottom, #f8e4c7 0%, #f4d4a5 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff4d4a5', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #f0c383;
-}
-.alert-danger {
-  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f0a9c7 100%);
-  background-image:         linear-gradient(to bottom, #f6cadc 0%, #f0a9c7 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff0a9c7', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #ea89b2;
-}
-.progress {
-  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
-  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar {
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
-  background-image:         linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar-success {
-  background-image: -webkit-linear-gradient(top, #79db32 0%, #61b921 100%);
-  background-image:         linear-gradient(to bottom, #79db32 0%, #61b921 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff61b921', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar-info {
-  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #885aab 100%);
-  background-image:         linear-gradient(to bottom, #a07cbc 0%, #885aab 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff885aab', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar-warning {
-  background-image: -webkit-linear-gradient(top, #e59728 0%, #c27c18 100%);
-  background-image:         linear-gradient(to bottom, #e59728 0%, #c27c18 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffc27c18', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar-danger {
-  background-image: -webkit-linear-gradient(top, #db3279 0%, #b92161 100%);
-  background-image:         linear-gradient(to bottom, #db3279 0%, #b92161 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb92161', GradientType=0);
-  background-repeat: repeat-x;
-}
-.list-group {
-  border-radius: 4px;
-  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-}
-.list-group-item.active,
-.list-group-item.active:hover,
-.list-group-item.active:focus {
-  text-shadow: 0 -1px 0 #3071a9;
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
-  background-image:         linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #3278b3;
-}
-.panel {
-  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
-          box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
-}
-.panel-default > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
-  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-primary > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
-  background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-success > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #cef2b4 100%);
-  background-image:         linear-gradient(to bottom, #dcf6ca 0%, #cef2b4 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffcef2b4', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-info > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e9e1f0 100%);
-  background-image:         linear-gradient(to bottom, #f6f2f8 0%, #e9e1f0 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe9e1f0', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-warning > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f6d9b0 100%);
-  background-image:         linear-gradient(to bottom, #f8e4c7 0%, #f6d9b0 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff6d9b0', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-danger > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f2b4ce 100%);
-  background-image:         linear-gradient(to bottom, #f6cadc 0%, #f2b4ce 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff2b4ce', GradientType=0);
-  background-repeat: repeat-x;
-}
-.well {
-  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
-  background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #dcdcdc;
-  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
-          box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
-}
-/*# sourceMappingURL=bootstrap-theme.css.map */
diff --git a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap-theme.css.map b/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap-theme.css.map
deleted file mode 100644
index b36fc9a..0000000
--- a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap-theme.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["less/theme.less","less/mixins.less"],"names":[],"mappings":"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","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n  text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n  @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n  .box-shadow(@shadow);\n\n  // Reset the shadow\n  &:active,\n  &.active {\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n  #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n  .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n  background-repeat: repeat-x;\n  border-color: darken(@btn-color, 14%);\n\n  &:hover,\n  &:focus  {\n    background-color: darken(@btn-color, 12%);\n    background-position: 0 -15px;\n  }\n\n  &:active,\n  &.active {\n    background-color: darken(@btn-color, 12%);\n    border-color: darken(@btn-color, 14%);\n  }\n}\n\n// Common styles\n.btn {\n  // Remove the gradient for the pressed/active state\n  &:active,\n  &.active {\n    background-image: none;\n  }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info    { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger  { .btn-styles(@btn-danger-bg); }\n\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n  .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n  background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n  background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n  .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n  border-radius: @navbar-border-radius;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n  .box-shadow(@shadow);\n\n  .navbar-nav > .active > a {\n    #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));\n    .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n  }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n  #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n  .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n  .navbar-nav > .active > a {\n    #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));\n    .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n  }\n\n  .navbar-brand,\n  .navbar-nav > li > a {\n    text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n  }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n  text-shadow: 0 1px 0 rgba(255,255,255,.2);\n  @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n  .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n  border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success    { .alert-styles(@alert-success-bg); }\n.alert-info       { .alert-styles(@alert-info-bg); }\n.alert-warning    { .alert-styles(@alert-warning-bg); }\n.alert-danger     { .alert-styles(@alert-danger-bg); }\n\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n  #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar            { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success    { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info       { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning    { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger     { .progress-bar-styles(@progress-bar-danger-bg); }\n\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n  border-radius: @border-radius-base;\n  .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n  #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n  border-color: darken(@list-group-active-border, 7.5%);\n}\n\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n  .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading   { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading   { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading   { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading      { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading   { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading    { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n  #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n  border-color: darken(@well-bg, 10%);\n  @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n}\n","//\n// Mixins\n// --------------------------------------------------\n\n\n// Utilities\n// -------------------------\n\n// Clearfix\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n//    contenteditable attribute is included anywhere else in the document.\n//    Otherwise it causes space to appear at the top and bottom of elements\n//    that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n//    `:before` to contain the top-margins of child elements.\n.clearfix() {\n  &:before,\n  &:after {\n    content: \" \"; // 1\n    display: table; // 2\n  }\n  &:after {\n    clear: both;\n  }\n}\n\n// WebKit-style focus\n.tab-focus() {\n  // Default\n  outline: thin dotted;\n  // WebKit\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n// Center-align a block level element\n.center-block() {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n\n// Sizing shortcuts\n.size(@width; @height) {\n  width: @width;\n  height: @height;\n}\n.square(@size) {\n  .size(@size; @size);\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n  &::-moz-placeholder           { color: @color;   // Firefox\n                                  opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n  &:-ms-input-placeholder       { color: @color; } // Internet Explorer 10+\n  &::-webkit-input-placeholder  { color: @color; } // Safari and Chrome\n}\n\n// Text overflow\n// Requires inline-block or block for proper styling\n.text-overflow() {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note\n// that we cannot chain the mixins together in Less, so they are repeated.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n  font: ~\"0/0\" a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n// New mixin to use as of v3.0.1\n.text-hide() {\n  .hide-text();\n}\n\n\n\n// CSS3 PROPERTIES\n// --------------------------------------------------\n\n// Single side border-radius\n.border-top-radius(@radius) {\n  border-top-right-radius: @radius;\n   border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n  border-bottom-right-radius: @radius;\n     border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n  border-bottom-right-radius: @radius;\n   border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n  border-bottom-left-radius: @radius;\n     border-top-left-radius: @radius;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n//   supported browsers that have box shadow capabilities now support the\n//   standard `box-shadow` property.\n.box-shadow(@shadow) {\n  -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n          box-shadow: @shadow;\n}\n\n// Transitions\n.transition(@transition) {\n  -webkit-transition: @transition;\n          transition: @transition;\n}\n.transition-property(@transition-property) {\n  -webkit-transition-property: @transition-property;\n          transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n  -webkit-transition-delay: @transition-delay;\n          transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n  -webkit-transition-duration: @transition-duration;\n          transition-duration: @transition-duration;\n}\n.transition-transform(@transition) {\n  -webkit-transition: -webkit-transform @transition;\n     -moz-transition: -moz-transform @transition;\n       -o-transition: -o-transform @transition;\n          transition: transform @transition;\n}\n\n// Transformations\n.rotate(@degrees) {\n  -webkit-transform: rotate(@degrees);\n      -ms-transform: rotate(@degrees); // IE9 only\n          transform: rotate(@degrees);\n}\n.scale(@ratio; @ratio-y...) {\n  -webkit-transform: scale(@ratio, @ratio-y);\n      -ms-transform: scale(@ratio, @ratio-y); // IE9 only\n          transform: scale(@ratio, @ratio-y);\n}\n.translate(@x; @y) {\n  -webkit-transform: translate(@x, @y);\n      -ms-transform: translate(@x, @y); // IE9 only\n          transform: translate(@x, @y);\n}\n.skew(@x; @y) {\n  -webkit-transform: skew(@x, @y);\n      -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n          transform: skew(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n  -webkit-transform: translate3d(@x, @y, @z);\n          transform: translate3d(@x, @y, @z);\n}\n\n.rotateX(@degrees) {\n  -webkit-transform: rotateX(@degrees);\n      -ms-transform: rotateX(@degrees); // IE9 only\n          transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n  -webkit-transform: rotateY(@degrees);\n      -ms-transform: rotateY(@degrees); // IE9 only\n          transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n  -webkit-perspective: @perspective;\n     -moz-perspective: @perspective;\n          perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n  -webkit-perspective-origin: @perspective;\n     -moz-perspective-origin: @perspective;\n          perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n  -webkit-transform-origin: @origin;\n     -moz-transform-origin: @origin;\n      -ms-transform-origin: @origin; // IE9 only\n          transform-origin: @origin;\n}\n\n// Animations\n.animation(@animation) {\n  -webkit-animation: @animation;\n          animation: @animation;\n}\n.animation-name(@name) {\n  -webkit-animation-name: @name;\n          animation-name: @name;\n}\n.animation-duration(@duration) {\n  -webkit-animation-duration: @duration;\n          animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n  -webkit-animation-timing-function: @timing-function;\n          animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n  -webkit-animation-delay: @delay;\n          animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n  -webkit-animation-iteration-count: @iteration-count;\n          animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n  -webkit-animation-direction: @direction;\n          animation-direction: @direction;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n.backface-visibility(@visibility){\n  -webkit-backface-visibility: @visibility;\n     -moz-backface-visibility: @visibility;\n          backface-visibility: @visibility;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n  -webkit-box-sizing: @boxmodel;\n     -moz-box-sizing: @boxmodel;\n          box-sizing: @boxmodel;\n}\n\n// User select\n// For selecting text on the page\n.user-select(@select) {\n  -webkit-user-select: @select;\n     -moz-user-select: @select;\n      -ms-user-select: @select; // IE10+\n          user-select: @select;\n}\n\n// Resize anything\n.resizable(@direction) {\n  resize: @direction; // Options: horizontal, vertical, both\n  overflow: auto; // Safari fix\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n  -webkit-column-count: @column-count;\n     -moz-column-count: @column-count;\n          column-count: @column-count;\n  -webkit-column-gap: @column-gap;\n     -moz-column-gap: @column-gap;\n          column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n  word-wrap: break-word;\n  -webkit-hyphens: @mode;\n     -moz-hyphens: @mode;\n      -ms-hyphens: @mode; // IE10+\n       -o-hyphens: @mode;\n          hyphens: @mode;\n}\n\n// Opacity\n.opacity(@opacity) {\n  opacity: @opacity;\n  // IE8 filter\n  @opacity-ie: (@opacity * 100);\n  filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n\n\n\n// GRADIENTS\n// --------------------------------------------------\n\n#gradient {\n\n  // Horizontal gradient, from left to right\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+\n    background-image:  linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  // Vertical gradient, from top to bottom\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Safari 5.1-6, Chrome 10+\n    background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n    background-repeat: repeat-x;\n    background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n    background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n  }\n  .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .radial(@inner-color: #555; @outer-color: #333) {\n    background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n    background-image: radial-gradient(circle, @inner-color, @outer-color);\n    background-repeat: no-repeat;\n  }\n  .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n    background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n  }\n}\n\n// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n.reset-filter() {\n  filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n\n\n\n// Retina images\n//\n// Short retina mixin for setting background-image and -size\n\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n  background-image: url(\"@{file-1x}\");\n\n  @media\n  only screen and (-webkit-min-device-pixel-ratio: 2),\n  only screen and (   min--moz-device-pixel-ratio: 2),\n  only screen and (     -o-min-device-pixel-ratio: 2/1),\n  only screen and (        min-device-pixel-ratio: 2),\n  only screen and (                min-resolution: 192dpi),\n  only screen and (                min-resolution: 2dppx) {\n    background-image: url(\"@{file-2x}\");\n    background-size: @width-1x @height-1x;\n  }\n}\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n.img-responsive(@display: block) {\n  display: @display;\n  max-width: 100%; // Part 1: Set a maximum relative to the parent\n  height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// COMPONENT MIXINS\n// --------------------------------------------------\n\n// Horizontal dividers\n// -------------------------\n// Dividers (basically an hr) within dropdowns and nav lists\n.nav-divider(@color: #e5e5e5) {\n  height: 1px;\n  margin: ((@line-height-computed / 2) - 1) 0;\n  overflow: hidden;\n  background-color: @color;\n}\n\n// Panels\n// -------------------------\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n  border-color: @border;\n\n  & > .panel-heading {\n    color: @heading-text-color;\n    background-color: @heading-bg-color;\n    border-color: @heading-border;\n\n    + .panel-collapse .panel-body {\n      border-top-color: @border;\n    }\n  }\n  & > .panel-footer {\n    + .panel-collapse .panel-body {\n      border-bottom-color: @border;\n    }\n  }\n}\n\n// Alerts\n// -------------------------\n.alert-variant(@background; @border; @text-color) {\n  background-color: @background;\n  border-color: @border;\n  color: @text-color;\n\n  hr {\n    border-top-color: darken(@border, 5%);\n  }\n  .alert-link {\n    color: darken(@text-color, 10%);\n  }\n}\n\n// Tables\n// -------------------------\n.table-row-variant(@state; @background) {\n  // Exact selectors below required to override `.table-striped` and prevent\n  // inheritance to nested tables.\n  .table > thead > tr,\n  .table > tbody > tr,\n  .table > tfoot > tr {\n    > td.@{state},\n    > th.@{state},\n    &.@{state} > td,\n    &.@{state} > th {\n      background-color: @background;\n    }\n  }\n\n  // Hover states for `.table-hover`\n  // Note: this is not available for cells or rows within `thead` or `tfoot`.\n  .table-hover > tbody > tr {\n    > td.@{state}:hover,\n    > th.@{state}:hover,\n    &.@{state}:hover > td,\n    &.@{state}:hover > th {\n      background-color: darken(@background, 5%);\n    }\n  }\n}\n\n// List Groups\n// -------------------------\n.list-group-item-variant(@state; @background; @color) {\n  .list-group-item-@{state} {\n    color: @color;\n    background-color: @background;\n\n    a& {\n      color: @color;\n\n      .list-group-item-heading { color: inherit; }\n\n      &:hover,\n      &:focus {\n        color: @color;\n        background-color: darken(@background, 5%);\n      }\n      &.active,\n      &.active:hover,\n      &.active:focus {\n        color: #fff;\n        background-color: @color;\n        border-color: @color;\n      }\n    }\n  }\n}\n\n// Button variants\n// -------------------------\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n.button-variant(@color; @background; @border) {\n  color: @color;\n  background-color: @background;\n  border-color: @border;\n\n  &:hover,\n  &:focus,\n  &:active,\n  &.active,\n  .open .dropdown-toggle& {\n    color: @color;\n    background-color: darken(@background, 8%);\n        border-color: darken(@border, 12%);\n  }\n  &:active,\n  &.active,\n  .open .dropdown-toggle& {\n    background-image: none;\n  }\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    &,\n    &:hover,\n    &:focus,\n    &:active,\n    &.active {\n      background-color: @background;\n          border-color: @border;\n    }\n  }\n\n  .badge {\n    color: @background;\n    background-color: @color;\n  }\n}\n\n// Button sizes\n// -------------------------\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n}\n\n// Pagination\n// -------------------------\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n  > li {\n    > a,\n    > span {\n      padding: @padding-vertical @padding-horizontal;\n      font-size: @font-size;\n    }\n    &:first-child {\n      > a,\n      > span {\n        .border-left-radius(@border-radius);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius);\n      }\n    }\n  }\n}\n\n// Labels\n// -------------------------\n.label-variant(@color) {\n  background-color: @color;\n  &[href] {\n    &:hover,\n    &:focus {\n      background-color: darken(@color, 10%);\n    }\n  }\n}\n\n// Contextual backgrounds\n// -------------------------\n.bg-variant(@color) {\n  background-color: @color;\n  a&:hover {\n    background-color: darken(@color, 10%);\n  }\n}\n\n// Typography\n// -------------------------\n.text-emphasis-variant(@color) {\n  color: @color;\n  a&:hover {\n    color: darken(@color, 10%);\n  }\n}\n\n// Navbar vertical align\n// -------------------------\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n.navbar-vertical-align(@element-height) {\n  margin-top: ((@navbar-height - @element-height) / 2);\n  margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n\n// Progress bars\n// -------------------------\n.progress-bar-variant(@color) {\n  background-color: @color;\n  .progress-striped & {\n    #gradient > .striped();\n  }\n}\n\n// Responsive utilities\n// -------------------------\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n  display: block !important;\n  table&  { display: table; }\n  tr&     { display: table-row !important; }\n  th&,\n  td&     { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n  display: none !important;\n}\n\n\n// Grid System\n// -----------\n\n// Centered container element\n.container-fixed() {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left:  (@grid-gutter-width / 2);\n  padding-right: (@grid-gutter-width / 2);\n  &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n  margin-left:  (@gutter / -2);\n  margin-right: (@gutter / -2);\n  &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  float: left;\n  width: percentage((@columns / @grid-columns));\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n  @media (min-width: @screen-xs-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-xs-column-push(@columns) {\n  @media (min-width: @screen-xs-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-xs-column-pull(@columns) {\n  @media (min-width: @screen-xs-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-sm-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-offset(@columns) {\n  @media (min-width: @screen-sm-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-push(@columns) {\n  @media (min-width: @screen-sm-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-pull(@columns) {\n  @media (min-width: @screen-sm-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-md-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-offset(@columns) {\n  @media (min-width: @screen-md-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-push(@columns) {\n  @media (min-width: @screen-md-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-pull(@columns) {\n  @media (min-width: @screen-md-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-lg-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-offset(@columns) {\n  @media (min-width: @screen-lg-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-push(@columns) {\n  @media (min-width: @screen-lg-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-pull(@columns) {\n  @media (min-width: @screen-lg-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n  // Common styles for all sizes of grid columns, widths 1-12\n  .col(@index) when (@index = 1) { // initial\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      position: relative;\n      // Prevent columns from collapsing when empty\n      min-height: 1px;\n      // Inner gutter via padding\n      padding-left:  (@grid-gutter-width / 2);\n      padding-right: (@grid-gutter-width / 2);\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n  .col(@index) when (@index = 1) { // initial\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      float: left;\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n  .col-@{class}-@{index} {\n    width: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) {\n  .col-@{class}-push-@{index} {\n    left: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) {\n  .col-@{class}-pull-@{index} {\n    right: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n  .col-@{class}-offset-@{index} {\n    margin-left: percentage((@index / @grid-columns));\n  }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n  .calc-grid-column(@index, @class, @type);\n  // next iteration\n  .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n  .float-grid-columns(@class);\n  .loop-grid-columns(@grid-columns, @class, width);\n  .loop-grid-columns(@grid-columns, @class, pull);\n  .loop-grid-columns(@grid-columns, @class, push);\n  .loop-grid-columns(@grid-columns, @class, offset);\n}\n\n// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n  // Color the label and help text\n  .help-block,\n  .control-label,\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline  {\n    color: @text-color;\n  }\n  // Set the border and box shadow on specific inputs to match\n  .form-control {\n    border-color: @border-color;\n    .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n    &:focus {\n      border-color: darken(@border-color, 10%);\n      @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n      .box-shadow(@shadow);\n    }\n  }\n  // Set validation states also for addons\n  .input-group-addon {\n    color: @text-color;\n    border-color: @border-color;\n    background-color: @background-color;\n  }\n  // Optional feedback icon\n  .form-control-feedback {\n    color: @text-color;\n  }\n}\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-focus-border` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n\n.form-control-focus(@color: @input-border-focus) {\n  @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n  &:focus {\n    border-color: @color;\n    outline: 0;\n    .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n  }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  height: @input-height;\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n\n  select& {\n    height: @input-height;\n    line-height: @input-height;\n  }\n\n  textarea&,\n  select[multiple]& {\n    height: auto;\n  }\n}\n"]}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap-theme.min.css b/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap-theme.min.css
deleted file mode 100644
index ca83770..0000000
--- a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap-theme.min.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * Bootstrap v3.1.1 (http://getbootstrap.com)
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#79db32 0,#5cb11f 100%);background-image:linear-gradient(to bottom,#79db32 0,#5cb11f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff5cb11f', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#58a81e}.btn-success:hover,.btn-success:focus{background-color:#5cb11f;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#5cb11f;border-color:#58a81e}.btn-info{background-image:-webkit-linear-gradient(top,#a07cbc 0,#8255a6 100%);background-image:linear-gradient(to bottom,#a07cbc 0,#8255a6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff8255a6', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#7d519f}.btn-info:hover,.btn-info:focus{background-color:#8255a6;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#8255a6;border-color:#7d519f}.btn-warning{background-image:-webkit-linear-gradient(top,#e59728 0,#b97616 100%);background-image:linear-gradient(to bottom,#e59728 0,#b97616 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffb97616', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b07015}.btn-warning:hover,.btn-warning:focus{background-color:#b97616;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#b97616;border-color:#b07015}.btn-danger{background-image:-webkit-linear-gradient(top,#db3279 0,#b11f5c 100%);background-image:linear-gradient(to bottom,#db3279 0,#b11f5c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb11f5c', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#a81e58}.btn-danger:hover,.btn-danger:focus{background-color:#b11f5c;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#b11f5c;border-color:#a81e58}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-color:#357ebd}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#365698 0,#294172 100%);background-image:linear-gradient(to bottom,#365698 0,#294172 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff365698', endColorstr='#ff294172', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#294172 0,#2c467b 100%);background-image:linear-gradient(to bottom,#294172 0,#2c467b 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff294172', endColorstr='#ff2c467b', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dcf6ca 0,#c7f0a9 100%);background-image:linear-gradient(to bottom,#dcf6ca 0,#c7f0a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffc7f0a9', GradientType=0);border-color:#b2ea89}.alert-info{background-image:-webkit-linear-gradient(top,#f6f2f8 0,#e3d9eb 100%);background-image:linear-gradient(to bottom,#f6f2f8 0,#e3d9eb 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe3d9eb', GradientType=0);border-color:#d1bfdf}.alert-warning{background-image:-webkit-linear-gradient(top,#f8e4c7 0,#f4d4a5 100%);background-image:linear-gradient(to bottom,#f8e4c7 0,#f4d4a5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff4d4a5', GradientType=0);border-color:#f0c383}.alert-danger{background-image:-webkit-linear-gradient(top,#f6cadc 0,#f0a9c7 100%);background-image:linear-gradient(to bottom,#f6cadc 0,#f0a9c7 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff0a9c7', GradientType=0);border-color:#ea89b2}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#79db32 0,#61b921 100%);background-image:linear-gradient(to bottom,#79db32 0,#61b921 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff61b921', GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#a07cbc 0,#885aab 100%);background-image:linear-gradient(to bottom,#a07cbc 0,#885aab 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff885aab', GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#e59728 0,#c27c18 100%);background-image:linear-gradient(to bottom,#e59728 0,#c27c18 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffc27c18', GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#db3279 0,#b92161 100%);background-image:linear-gradient(to bottom,#db3279 0,#b92161 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb92161', GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dcf6ca 0,#cef2b4 100%);background-image:linear-gradient(to bottom,#dcf6ca 0,#cef2b4 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffcef2b4', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#f6f2f8 0,#e9e1f0 100%);background-image:linear-gradient(to bottom,#f6f2f8 0,#e9e1f0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe9e1f0', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#f8e4c7 0,#f6d9b0 100%);background-image:linear-gradient(to bottom,#f8e4c7 0,#f6d9b0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff6d9b0', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f6cadc 0,#f2b4ce 100%);background-image:linear-gradient(to bottom,#f6cadc 0,#f2b4ce 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff2b4ce', GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap.css b/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap.css
deleted file mode 100644
index b3e4060..0000000
--- a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap.css
+++ /dev/null
@@ -1,5787 +0,0 @@
-/*!
- * Bootstrap v3.1.1 (http://getbootstrap.com)
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-/*! normalize.css v3.0.0 | MIT License | git.io/normalize */
-html {
-  font-family: sans-serif;
-  -webkit-text-size-adjust: 100%;
-      -ms-text-size-adjust: 100%;
-}
-body {
-  margin: 0;
-}
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-nav,
-section,
-summary {
-  display: block;
-}
-audio,
-canvas,
-progress,
-video {
-  display: inline-block;
-  vertical-align: baseline;
-}
-audio:not([controls]) {
-  display: none;
-  height: 0;
-}
-[hidden],
-template {
-  display: none;
-}
-a {
-  background: transparent;
-}
-a:active,
-a:hover {
-  outline: 0;
-}
-abbr[title] {
-  border-bottom: 1px dotted;
-}
-b,
-strong {
-  font-weight: bold;
-}
-dfn {
-  font-style: italic;
-}
-h1 {
-  margin: .67em 0;
-  font-size: 2em;
-}
-mark {
-  color: #000;
-  background: #ff0;
-}
-small {
-  font-size: 80%;
-}
-sub,
-sup {
-  position: relative;
-  font-size: 75%;
-  line-height: 0;
-  vertical-align: baseline;
-}
-sup {
-  top: -.5em;
-}
-sub {
-  bottom: -.25em;
-}
-img {
-  border: 0;
-}
-svg:not(:root) {
-  overflow: hidden;
-}
-figure {
-  margin: 1em 40px;
-}
-hr {
-  height: 0;
-  -moz-box-sizing: content-box;
-       box-sizing: content-box;
-}
-pre {
-  overflow: auto;
-}
-code,
-kbd,
-pre,
-samp {
-  font-family: monospace, monospace;
-  font-size: 1em;
-}
-button,
-input,
-optgroup,
-select,
-textarea {
-  margin: 0;
-  font: inherit;
-  color: inherit;
-}
-button {
-  overflow: visible;
-}
-button,
-select {
-  text-transform: none;
-}
-button,
-html input[type="button"],
-input[type="reset"],
-input[type="submit"] {
-  -webkit-appearance: button;
-  cursor: pointer;
-}
-button[disabled],
-html input[disabled] {
-  cursor: default;
-}
-button::-moz-focus-inner,
-input::-moz-focus-inner {
-  padding: 0;
-  border: 0;
-}
-input {
-  line-height: normal;
-}
-input[type="checkbox"],
-input[type="radio"] {
-  box-sizing: border-box;
-  padding: 0;
-}
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
-  height: auto;
-}
-input[type="search"] {
-  -webkit-box-sizing: content-box;
-     -moz-box-sizing: content-box;
-          box-sizing: content-box;
-  -webkit-appearance: textfield;
-}
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
-  -webkit-appearance: none;
-}
-fieldset {
-  padding: .35em .625em .75em;
-  margin: 0 2px;
-  border: 1px solid #c0c0c0;
-}
-legend {
-  padding: 0;
-  border: 0;
-}
-textarea {
-  overflow: auto;
-}
-optgroup {
-  font-weight: bold;
-}
-table {
-  border-spacing: 0;
-  border-collapse: collapse;
-}
-td,
-th {
-  padding: 0;
-}
-@media print {
-  * {
-    color: #000 !important;
-    text-shadow: none !important;
-    background: transparent !important;
-    box-shadow: none !important;
-  }
-  a,
-  a:visited {
-    text-decoration: underline;
-  }
-  a[href]:after {
-    content: " (" attr(href) ")";
-  }
-  abbr[title]:after {
-    content: " (" attr(title) ")";
-  }
-  a[href^="javascript:"]:after,
-  a[href^="#"]:after {
-    content: "";
-  }
-  pre,
-  blockquote {
-    border: 1px solid #999;
-
-    page-break-inside: avoid;
-  }
-  thead {
-    display: table-header-group;
-  }
-  tr,
-  img {
-    page-break-inside: avoid;
-  }
-  img {
-    max-width: 100% !important;
-  }
-  p,
-  h2,
-  h3 {
-    orphans: 3;
-    widows: 3;
-  }
-  h2,
-  h3 {
-    page-break-after: avoid;
-  }
-  select {
-    background: #fff !important;
-  }
-  .navbar {
-    display: none;
-  }
-  .table td,
-  .table th {
-    background-color: #fff !important;
-  }
-  .btn > .caret,
-  .dropup > .btn > .caret {
-    border-top-color: #000 !important;
-  }
-  .label {
-    border: 1px solid #000;
-  }
-  .table {
-    border-collapse: collapse !important;
-  }
-  .table-bordered th,
-  .table-bordered td {
-    border: 1px solid #ddd !important;
-  }
-}
-* {
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-}
-*:before,
-*:after {
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-}
-html {
-  font-size: 62.5%;
-
-  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-}
-body {
-  font-family: Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 14px;
-  line-height: 1.42857143;
-  color: #333;
-  background-color: #fff;
-}
-input,
-button,
-select,
-textarea {
-  font-family: inherit;
-  font-size: inherit;
-  line-height: inherit;
-}
-a {
-  color: #428bca;
-  text-decoration: none;
-}
-a:hover,
-a:focus {
-  color: #2a6496;
-  text-decoration: underline;
-}
-a:focus {
-  outline: thin dotted;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-figure {
-  margin: 0;
-}
-img {
-  vertical-align: middle;
-}
-.img-responsive,
-.thumbnail > img,
-.thumbnail a > img,
-.carousel-inner > .item > img,
-.carousel-inner > .item > a > img {
-  display: block;
-  max-width: 100%;
-  height: auto;
-}
-.img-rounded {
-  border-radius: 6px;
-}
-.img-thumbnail {
-  display: inline-block;
-  max-width: 100%;
-  height: auto;
-  padding: 4px;
-  line-height: 1.42857143;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  -webkit-transition: all .2s ease-in-out;
-          transition: all .2s ease-in-out;
-}
-.img-circle {
-  border-radius: 50%;
-}
-hr {
-  margin-top: 20px;
-  margin-bottom: 20px;
-  border: 0;
-  border-top: 1px solid #eee;
-}
-.sr-only {
-  position: absolute;
-  width: 1px;
-  height: 1px;
-  padding: 0;
-  margin: -1px;
-  overflow: hidden;
-  clip: rect(0, 0, 0, 0);
-  border: 0;
-}
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
-.h1,
-.h2,
-.h3,
-.h4,
-.h5,
-.h6 {
-  font-family: inherit;
-  font-weight: 500;
-  line-height: 1.1;
-  color: inherit;
-}
-h1 small,
-h2 small,
-h3 small,
-h4 small,
-h5 small,
-h6 small,
-.h1 small,
-.h2 small,
-.h3 small,
-.h4 small,
-.h5 small,
-.h6 small,
-h1 .small,
-h2 .small,
-h3 .small,
-h4 .small,
-h5 .small,
-h6 .small,
-.h1 .small,
-.h2 .small,
-.h3 .small,
-.h4 .small,
-.h5 .small,
-.h6 .small {
-  font-weight: normal;
-  line-height: 1;
-  color: #999;
-}
-h1,
-.h1,
-h2,
-.h2,
-h3,
-.h3 {
-  margin-top: 20px;
-  margin-bottom: 10px;
-}
-h1 small,
-.h1 small,
-h2 small,
-.h2 small,
-h3 small,
-.h3 small,
-h1 .small,
-.h1 .small,
-h2 .small,
-.h2 .small,
-h3 .small,
-.h3 .small {
-  font-size: 65%;
-}
-h4,
-.h4,
-h5,
-.h5,
-h6,
-.h6 {
-  margin-top: 10px;
-  margin-bottom: 10px;
-}
-h4 small,
-.h4 small,
-h5 small,
-.h5 small,
-h6 small,
-.h6 small,
-h4 .small,
-.h4 .small,
-h5 .small,
-.h5 .small,
-h6 .small,
-.h6 .small {
-  font-size: 75%;
-}
-h1,
-.h1 {
-  font-size: 36px;
-}
-h2,
-.h2 {
-  font-size: 30px;
-}
-h3,
-.h3 {
-  font-size: 24px;
-}
-h4,
-.h4 {
-  font-size: 18px;
-}
-h5,
-.h5 {
-  font-size: 14px;
-}
-h6,
-.h6 {
-  font-size: 12px;
-}
-p {
-  margin: 0 0 10px;
-}
-.lead {
-  margin-bottom: 20px;
-  font-size: 16px;
-  font-weight: 200;
-  line-height: 1.4;
-}
-@media (min-width: 768px) {
-  .lead {
-    font-size: 21px;
-  }
-}
-small,
-.small {
-  font-size: 85%;
-}
-cite {
-  font-style: normal;
-}
-.text-left {
-  text-align: left;
-}
-.text-right {
-  text-align: right;
-}
-.text-center {
-  text-align: center;
-}
-.text-justify {
-  text-align: justify;
-}
-.text-muted {
-  color: #999;
-}
-.text-primary {
-  color: #428bca;
-}
-a.text-primary:hover {
-  color: #3071a9;
-}
-.text-success {
-  color: #3f7815;
-}
-a.text-success:hover {
-  color: #284d0e;
-}
-.text-info {
-  color: #603e7a;
-}
-a.text-info:hover {
-  color: #452d58;
-}
-.text-warning {
-  color: #7e500f;
-}
-a.text-warning:hover {
-  color: #51330a;
-}
-.text-danger {
-  color: #78153f;
-}
-a.text-danger:hover {
-  color: #4d0e28;
-}
-.bg-primary {
-  color: #fff;
-  background-color: #428bca;
-}
-a.bg-primary:hover {
-  background-color: #3071a9;
-}
-.bg-success {
-  background-color: #dcf6ca;
-}
-a.bg-success:hover {
-  background-color: #c0ee9e;
-}
-.bg-info {
-  background-color: #f6f2f8;
-}
-a.bg-info:hover {
-  background-color: #ddd0e7;
-}
-.bg-warning {
-  background-color: #f8e4c7;
-}
-a.bg-warning:hover {
-  background-color: #f3ce9a;
-}
-.bg-danger {
-  background-color: #f6cadc;
-}
-a.bg-danger:hover {
-  background-color: #ee9ec0;
-}
-.page-header {
-  padding-bottom: 9px;
-  margin: 40px 0 20px;
-  border-bottom: 1px solid #eee;
-}
-ul,
-ol {
-  margin-top: 0;
-  margin-bottom: 10px;
-}
-ul ul,
-ol ul,
-ul ol,
-ol ol {
-  margin-bottom: 0;
-}
-.list-unstyled {
-  padding-left: 0;
-  list-style: none;
-}
-.list-inline {
-  padding-left: 0;
-  margin-left: -5px;
-  list-style: none;
-}
-.list-inline > li {
-  display: inline-block;
-  padding-right: 5px;
-  padding-left: 5px;
-}
-dl {
-  margin-top: 0;
-  margin-bottom: 20px;
-}
-dt,
-dd {
-  line-height: 1.42857143;
-}
-dt {
-  font-weight: bold;
-}
-dd {
-  margin-left: 0;
-}
-@media (min-width: 768px) {
-  .dl-horizontal dt {
-    float: left;
-    width: 160px;
-    overflow: hidden;
-    clear: left;
-    text-align: right;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-  }
-  .dl-horizontal dd {
-    margin-left: 180px;
-  }
-}
-abbr[title],
-abbr[data-original-title] {
-  cursor: help;
-  border-bottom: 1px dotted #999;
-}
-.initialism {
-  font-size: 90%;
-  text-transform: uppercase;
-}
-blockquote {
-  padding: 10px 20px;
-  margin: 0 0 20px;
-  font-size: 17.5px;
-  border-left: 5px solid #eee;
-}
-blockquote p:last-child,
-blockquote ul:last-child,
-blockquote ol:last-child {
-  margin-bottom: 0;
-}
-blockquote footer,
-blockquote small,
-blockquote .small {
-  display: block;
-  font-size: 80%;
-  line-height: 1.42857143;
-  color: #999;
-}
-blockquote footer:before,
-blockquote small:before,
-blockquote .small:before {
-  content: '\2014 \00A0';
-}
-.blockquote-reverse,
-blockquote.pull-right {
-  padding-right: 15px;
-  padding-left: 0;
-  text-align: right;
-  border-right: 5px solid #eee;
-  border-left: 0;
-}
-.blockquote-reverse footer:before,
-blockquote.pull-right footer:before,
-.blockquote-reverse small:before,
-blockquote.pull-right small:before,
-.blockquote-reverse .small:before,
-blockquote.pull-right .small:before {
-  content: '';
-}
-.blockquote-reverse footer:after,
-blockquote.pull-right footer:after,
-.blockquote-reverse small:after,
-blockquote.pull-right small:after,
-.blockquote-reverse .small:after,
-blockquote.pull-right .small:after {
-  content: '\00A0 \2014';
-}
-blockquote:before,
-blockquote:after {
-  content: "";
-}
-address {
-  margin-bottom: 20px;
-  font-style: normal;
-  line-height: 1.42857143;
-}
-code,
-kbd,
-pre,
-samp {
-  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
-}
-code {
-  padding: 2px 4px;
-  font-size: 90%;
-  color: #c7254e;
-  white-space: nowrap;
-  background-color: #f9f2f4;
-  border-radius: 4px;
-}
-kbd {
-  padding: 2px 4px;
-  font-size: 90%;
-  color: #fff;
-  background-color: #333;
-  border-radius: 3px;
-  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
-}
-pre {
-  display: block;
-  padding: 9.5px;
-  margin: 0 0 10px;
-  font-size: 13px;
-  line-height: 1.42857143;
-  color: #333;
-  word-break: break-all;
-  word-wrap: break-word;
-  background-color: #f5f5f5;
-  border: 1px solid #ccc;
-  border-radius: 4px;
-}
-pre code {
-  padding: 0;
-  font-size: inherit;
-  color: inherit;
-  white-space: pre-wrap;
-  background-color: transparent;
-  border-radius: 0;
-}
-.pre-scrollable {
-  max-height: 340px;
-  overflow-y: scroll;
-}
-.container {
-  padding-right: 15px;
-  padding-left: 15px;
-  margin-right: auto;
-  margin-left: auto;
-}
-@media (min-width: 768px) {
-  .container {
-    width: 750px;
-  }
-}
-@media (min-width: 992px) {
-  .container {
-    width: 970px;
-  }
-}
-@media (min-width: 1200px) {
-  .container {
-    width: 1170px;
-  }
-}
-.container-fluid {
-  padding-right: 15px;
-  padding-left: 15px;
-  margin-right: auto;
-  margin-left: auto;
-}
-.row {
-  margin-right: -15px;
-  margin-left: -15px;
-}
-.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
-  position: relative;
-  min-height: 1px;
-  padding-right: 15px;
-  padding-left: 15px;
-}
-.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
-  float: left;
-}
-.col-xs-12 {
-  width: 100%;
-}
-.col-xs-11 {
-  width: 91.66666667%;
-}
-.col-xs-10 {
-  width: 83.33333333%;
-}
-.col-xs-9 {
-  width: 75%;
-}
-.col-xs-8 {
-  width: 66.66666667%;
-}
-.col-xs-7 {
-  width: 58.33333333%;
-}
-.col-xs-6 {
-  width: 50%;
-}
-.col-xs-5 {
-  width: 41.66666667%;
-}
-.col-xs-4 {
-  width: 33.33333333%;
-}
-.col-xs-3 {
-  width: 25%;
-}
-.col-xs-2 {
-  width: 16.66666667%;
-}
-.col-xs-1 {
-  width: 8.33333333%;
-}
-.col-xs-pull-12 {
-  right: 100%;
-}
-.col-xs-pull-11 {
-  right: 91.66666667%;
-}
-.col-xs-pull-10 {
-  right: 83.33333333%;
-}
-.col-xs-pull-9 {
-  right: 75%;
-}
-.col-xs-pull-8 {
-  right: 66.66666667%;
-}
-.col-xs-pull-7 {
-  right: 58.33333333%;
-}
-.col-xs-pull-6 {
-  right: 50%;
-}
-.col-xs-pull-5 {
-  right: 41.66666667%;
-}
-.col-xs-pull-4 {
-  right: 33.33333333%;
-}
-.col-xs-pull-3 {
-  right: 25%;
-}
-.col-xs-pull-2 {
-  right: 16.66666667%;
-}
-.col-xs-pull-1 {
-  right: 8.33333333%;
-}
-.col-xs-pull-0 {
-  right: 0;
-}
-.col-xs-push-12 {
-  left: 100%;
-}
-.col-xs-push-11 {
-  left: 91.66666667%;
-}
-.col-xs-push-10 {
-  left: 83.33333333%;
-}
-.col-xs-push-9 {
-  left: 75%;
-}
-.col-xs-push-8 {
-  left: 66.66666667%;
-}
-.col-xs-push-7 {
-  left: 58.33333333%;
-}
-.col-xs-push-6 {
-  left: 50%;
-}
-.col-xs-push-5 {
-  left: 41.66666667%;
-}
-.col-xs-push-4 {
-  left: 33.33333333%;
-}
-.col-xs-push-3 {
-  left: 25%;
-}
-.col-xs-push-2 {
-  left: 16.66666667%;
-}
-.col-xs-push-1 {
-  left: 8.33333333%;
-}
-.col-xs-push-0 {
-  left: 0;
-}
-.col-xs-offset-12 {
-  margin-left: 100%;
-}
-.col-xs-offset-11 {
-  margin-left: 91.66666667%;
-}
-.col-xs-offset-10 {
-  margin-left: 83.33333333%;
-}
-.col-xs-offset-9 {
-  margin-left: 75%;
-}
-.col-xs-offset-8 {
-  margin-left: 66.66666667%;
-}
-.col-xs-offset-7 {
-  margin-left: 58.33333333%;
-}
-.col-xs-offset-6 {
-  margin-left: 50%;
-}
-.col-xs-offset-5 {
-  margin-left: 41.66666667%;
-}
-.col-xs-offset-4 {
-  margin-left: 33.33333333%;
-}
-.col-xs-offset-3 {
-  margin-left: 25%;
-}
-.col-xs-offset-2 {
-  margin-left: 16.66666667%;
-}
-.col-xs-offset-1 {
-  margin-left: 8.33333333%;
-}
-.col-xs-offset-0 {
-  margin-left: 0;
-}
-@media (min-width: 768px) {
-  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
-    float: left;
-  }
-  .col-sm-12 {
-    width: 100%;
-  }
-  .col-sm-11 {
-    width: 91.66666667%;
-  }
-  .col-sm-10 {
-    width: 83.33333333%;
-  }
-  .col-sm-9 {
-    width: 75%;
-  }
-  .col-sm-8 {
-    width: 66.66666667%;
-  }
-  .col-sm-7 {
-    width: 58.33333333%;
-  }
-  .col-sm-6 {
-    width: 50%;
-  }
-  .col-sm-5 {
-    width: 41.66666667%;
-  }
-  .col-sm-4 {
-    width: 33.33333333%;
-  }
-  .col-sm-3 {
-    width: 25%;
-  }
-  .col-sm-2 {
-    width: 16.66666667%;
-  }
-  .col-sm-1 {
-    width: 8.33333333%;
-  }
-  .col-sm-pull-12 {
-    right: 100%;
-  }
-  .col-sm-pull-11 {
-    right: 91.66666667%;
-  }
-  .col-sm-pull-10 {
-    right: 83.33333333%;
-  }
-  .col-sm-pull-9 {
-    right: 75%;
-  }
-  .col-sm-pull-8 {
-    right: 66.66666667%;
-  }
-  .col-sm-pull-7 {
-    right: 58.33333333%;
-  }
-  .col-sm-pull-6 {
-    right: 50%;
-  }
-  .col-sm-pull-5 {
-    right: 41.66666667%;
-  }
-  .col-sm-pull-4 {
-    right: 33.33333333%;
-  }
-  .col-sm-pull-3 {
-    right: 25%;
-  }
-  .col-sm-pull-2 {
-    right: 16.66666667%;
-  }
-  .col-sm-pull-1 {
-    right: 8.33333333%;
-  }
-  .col-sm-pull-0 {
-    right: 0;
-  }
-  .col-sm-push-12 {
-    left: 100%;
-  }
-  .col-sm-push-11 {
-    left: 91.66666667%;
-  }
-  .col-sm-push-10 {
-    left: 83.33333333%;
-  }
-  .col-sm-push-9 {
-    left: 75%;
-  }
-  .col-sm-push-8 {
-    left: 66.66666667%;
-  }
-  .col-sm-push-7 {
-    left: 58.33333333%;
-  }
-  .col-sm-push-6 {
-    left: 50%;
-  }
-  .col-sm-push-5 {
-    left: 41.66666667%;
-  }
-  .col-sm-push-4 {
-    left: 33.33333333%;
-  }
-  .col-sm-push-3 {
-    left: 25%;
-  }
-  .col-sm-push-2 {
-    left: 16.66666667%;
-  }
-  .col-sm-push-1 {
-    left: 8.33333333%;
-  }
-  .col-sm-push-0 {
-    left: 0;
-  }
-  .col-sm-offset-12 {
-    margin-left: 100%;
-  }
-  .col-sm-offset-11 {
-    margin-left: 91.66666667%;
-  }
-  .col-sm-offset-10 {
-    margin-left: 83.33333333%;
-  }
-  .col-sm-offset-9 {
-    margin-left: 75%;
-  }
-  .col-sm-offset-8 {
-    margin-left: 66.66666667%;
-  }
-  .col-sm-offset-7 {
-    margin-left: 58.33333333%;
-  }
-  .col-sm-offset-6 {
-    margin-left: 50%;
-  }
-  .col-sm-offset-5 {
-    margin-left: 41.66666667%;
-  }
-  .col-sm-offset-4 {
-    margin-left: 33.33333333%;
-  }
-  .col-sm-offset-3 {
-    margin-left: 25%;
-  }
-  .col-sm-offset-2 {
-    margin-left: 16.66666667%;
-  }
-  .col-sm-offset-1 {
-    margin-left: 8.33333333%;
-  }
-  .col-sm-offset-0 {
-    margin-left: 0;
-  }
-}
-@media (min-width: 992px) {
-  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
-    float: left;
-  }
-  .col-md-12 {
-    width: 100%;
-  }
-  .col-md-11 {
-    width: 91.66666667%;
-  }
-  .col-md-10 {
-    width: 83.33333333%;
-  }
-  .col-md-9 {
-    width: 75%;
-  }
-  .col-md-8 {
-    width: 66.66666667%;
-  }
-  .col-md-7 {
-    width: 58.33333333%;
-  }
-  .col-md-6 {
-    width: 50%;
-  }
-  .col-md-5 {
-    width: 41.66666667%;
-  }
-  .col-md-4 {
-    width: 33.33333333%;
-  }
-  .col-md-3 {
-    width: 25%;
-  }
-  .col-md-2 {
-    width: 16.66666667%;
-  }
-  .col-md-1 {
-    width: 8.33333333%;
-  }
-  .col-md-pull-12 {
-    right: 100%;
-  }
-  .col-md-pull-11 {
-    right: 91.66666667%;
-  }
-  .col-md-pull-10 {
-    right: 83.33333333%;
-  }
-  .col-md-pull-9 {
-    right: 75%;
-  }
-  .col-md-pull-8 {
-    right: 66.66666667%;
-  }
-  .col-md-pull-7 {
-    right: 58.33333333%;
-  }
-  .col-md-pull-6 {
-    right: 50%;
-  }
-  .col-md-pull-5 {
-    right: 41.66666667%;
-  }
-  .col-md-pull-4 {
-    right: 33.33333333%;
-  }
-  .col-md-pull-3 {
-    right: 25%;
-  }
-  .col-md-pull-2 {
-    right: 16.66666667%;
-  }
-  .col-md-pull-1 {
-    right: 8.33333333%;
-  }
-  .col-md-pull-0 {
-    right: 0;
-  }
-  .col-md-push-12 {
-    left: 100%;
-  }
-  .col-md-push-11 {
-    left: 91.66666667%;
-  }
-  .col-md-push-10 {
-    left: 83.33333333%;
-  }
-  .col-md-push-9 {
-    left: 75%;
-  }
-  .col-md-push-8 {
-    left: 66.66666667%;
-  }
-  .col-md-push-7 {
-    left: 58.33333333%;
-  }
-  .col-md-push-6 {
-    left: 50%;
-  }
-  .col-md-push-5 {
-    left: 41.66666667%;
-  }
-  .col-md-push-4 {
-    left: 33.33333333%;
-  }
-  .col-md-push-3 {
-    left: 25%;
-  }
-  .col-md-push-2 {
-    left: 16.66666667%;
-  }
-  .col-md-push-1 {
-    left: 8.33333333%;
-  }
-  .col-md-push-0 {
-    left: 0;
-  }
-  .col-md-offset-12 {
-    margin-left: 100%;
-  }
-  .col-md-offset-11 {
-    margin-left: 91.66666667%;
-  }
-  .col-md-offset-10 {
-    margin-left: 83.33333333%;
-  }
-  .col-md-offset-9 {
-    margin-left: 75%;
-  }
-  .col-md-offset-8 {
-    margin-left: 66.66666667%;
-  }
-  .col-md-offset-7 {
-    margin-left: 58.33333333%;
-  }
-  .col-md-offset-6 {
-    margin-left: 50%;
-  }
-  .col-md-offset-5 {
-    margin-left: 41.66666667%;
-  }
-  .col-md-offset-4 {
-    margin-left: 33.33333333%;
-  }
-  .col-md-offset-3 {
-    margin-left: 25%;
-  }
-  .col-md-offset-2 {
-    margin-left: 16.66666667%;
-  }
-  .col-md-offset-1 {
-    margin-left: 8.33333333%;
-  }
-  .col-md-offset-0 {
-    margin-left: 0;
-  }
-}
-@media (min-width: 1200px) {
-  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
-    float: left;
-  }
-  .col-lg-12 {
-    width: 100%;
-  }
-  .col-lg-11 {
-    width: 91.66666667%;
-  }
-  .col-lg-10 {
-    width: 83.33333333%;
-  }
-  .col-lg-9 {
-    width: 75%;
-  }
-  .col-lg-8 {
-    width: 66.66666667%;
-  }
-  .col-lg-7 {
-    width: 58.33333333%;
-  }
-  .col-lg-6 {
-    width: 50%;
-  }
-  .col-lg-5 {
-    width: 41.66666667%;
-  }
-  .col-lg-4 {
-    width: 33.33333333%;
-  }
-  .col-lg-3 {
-    width: 25%;
-  }
-  .col-lg-2 {
-    width: 16.66666667%;
-  }
-  .col-lg-1 {
-    width: 8.33333333%;
-  }
-  .col-lg-pull-12 {
-    right: 100%;
-  }
-  .col-lg-pull-11 {
-    right: 91.66666667%;
-  }
-  .col-lg-pull-10 {
-    right: 83.33333333%;
-  }
-  .col-lg-pull-9 {
-    right: 75%;
-  }
-  .col-lg-pull-8 {
-    right: 66.66666667%;
-  }
-  .col-lg-pull-7 {
-    right: 58.33333333%;
-  }
-  .col-lg-pull-6 {
-    right: 50%;
-  }
-  .col-lg-pull-5 {
-    right: 41.66666667%;
-  }
-  .col-lg-pull-4 {
-    right: 33.33333333%;
-  }
-  .col-lg-pull-3 {
-    right: 25%;
-  }
-  .col-lg-pull-2 {
-    right: 16.66666667%;
-  }
-  .col-lg-pull-1 {
-    right: 8.33333333%;
-  }
-  .col-lg-pull-0 {
-    right: 0;
-  }
-  .col-lg-push-12 {
-    left: 100%;
-  }
-  .col-lg-push-11 {
-    left: 91.66666667%;
-  }
-  .col-lg-push-10 {
-    left: 83.33333333%;
-  }
-  .col-lg-push-9 {
-    left: 75%;
-  }
-  .col-lg-push-8 {
-    left: 66.66666667%;
-  }
-  .col-lg-push-7 {
-    left: 58.33333333%;
-  }
-  .col-lg-push-6 {
-    left: 50%;
-  }
-  .col-lg-push-5 {
-    left: 41.66666667%;
-  }
-  .col-lg-push-4 {
-    left: 33.33333333%;
-  }
-  .col-lg-push-3 {
-    left: 25%;
-  }
-  .col-lg-push-2 {
-    left: 16.66666667%;
-  }
-  .col-lg-push-1 {
-    left: 8.33333333%;
-  }
-  .col-lg-push-0 {
-    left: 0;
-  }
-  .col-lg-offset-12 {
-    margin-left: 100%;
-  }
-  .col-lg-offset-11 {
-    margin-left: 91.66666667%;
-  }
-  .col-lg-offset-10 {
-    margin-left: 83.33333333%;
-  }
-  .col-lg-offset-9 {
-    margin-left: 75%;
-  }
-  .col-lg-offset-8 {
-    margin-left: 66.66666667%;
-  }
-  .col-lg-offset-7 {
-    margin-left: 58.33333333%;
-  }
-  .col-lg-offset-6 {
-    margin-left: 50%;
-  }
-  .col-lg-offset-5 {
-    margin-left: 41.66666667%;
-  }
-  .col-lg-offset-4 {
-    margin-left: 33.33333333%;
-  }
-  .col-lg-offset-3 {
-    margin-left: 25%;
-  }
-  .col-lg-offset-2 {
-    margin-left: 16.66666667%;
-  }
-  .col-lg-offset-1 {
-    margin-left: 8.33333333%;
-  }
-  .col-lg-offset-0 {
-    margin-left: 0;
-  }
-}
-table {
-  max-width: 100%;
-  background-color: transparent;
-}
-th {
-  text-align: left;
-}
-.table {
-  width: 100%;
-  margin-bottom: 20px;
-}
-.table > thead > tr > th,
-.table > tbody > tr > th,
-.table > tfoot > tr > th,
-.table > thead > tr > td,
-.table > tbody > tr > td,
-.table > tfoot > tr > td {
-  padding: 8px;
-  line-height: 1.42857143;
-  vertical-align: top;
-  border-top: 1px solid #ddd;
-}
-.table > thead > tr > th {
-  vertical-align: bottom;
-  border-bottom: 2px solid #ddd;
-}
-.table > caption + thead > tr:first-child > th,
-.table > colgroup + thead > tr:first-child > th,
-.table > thead:first-child > tr:first-child > th,
-.table > caption + thead > tr:first-child > td,
-.table > colgroup + thead > tr:first-child > td,
-.table > thead:first-child > tr:first-child > td {
-  border-top: 0;
-}
-.table > tbody + tbody {
-  border-top: 2px solid #ddd;
-}
-.table .table {
-  background-color: #fff;
-}
-.table-condensed > thead > tr > th,
-.table-condensed > tbody > tr > th,
-.table-condensed > tfoot > tr > th,
-.table-condensed > thead > tr > td,
-.table-condensed > tbody > tr > td,
-.table-condensed > tfoot > tr > td {
-  padding: 5px;
-}
-.table-bordered {
-  border: 1px solid #ddd;
-}
-.table-bordered > thead > tr > th,
-.table-bordered > tbody > tr > th,
-.table-bordered > tfoot > tr > th,
-.table-bordered > thead > tr > td,
-.table-bordered > tbody > tr > td,
-.table-bordered > tfoot > tr > td {
-  border: 1px solid #ddd;
-}
-.table-bordered > thead > tr > th,
-.table-bordered > thead > tr > td {
-  border-bottom-width: 2px;
-}
-.table-striped > tbody > tr:nth-child(odd) > td,
-.table-striped > tbody > tr:nth-child(odd) > th {
-  background-color: #f9f9f9;
-}
-.table-hover > tbody > tr:hover > td,
-.table-hover > tbody > tr:hover > th {
-  background-color: #f5f5f5;
-}
-table col[class*="col-"] {
-  position: static;
-  display: table-column;
-  float: none;
-}
-table td[class*="col-"],
-table th[class*="col-"] {
-  position: static;
-  display: table-cell;
-  float: none;
-}
-.table > thead > tr > td.active,
-.table > tbody > tr > td.active,
-.table > tfoot > tr > td.active,
-.table > thead > tr > th.active,
-.table > tbody > tr > th.active,
-.table > tfoot > tr > th.active,
-.table > thead > tr.active > td,
-.table > tbody > tr.active > td,
-.table > tfoot > tr.active > td,
-.table > thead > tr.active > th,
-.table > tbody > tr.active > th,
-.table > tfoot > tr.active > th {
-  background-color: #f5f5f5;
-}
-.table-hover > tbody > tr > td.active:hover,
-.table-hover > tbody > tr > th.active:hover,
-.table-hover > tbody > tr.active:hover > td,
-.table-hover > tbody > tr.active:hover > th {
-  background-color: #e8e8e8;
-}
-.table > thead > tr > td.success,
-.table > tbody > tr > td.success,
-.table > tfoot > tr > td.success,
-.table > thead > tr > th.success,
-.table > tbody > tr > th.success,
-.table > tfoot > tr > th.success,
-.table > thead > tr.success > td,
-.table > tbody > tr.success > td,
-.table > tfoot > tr.success > td,
-.table > thead > tr.success > th,
-.table > tbody > tr.success > th,
-.table > tfoot > tr.success > th {
-  background-color: #dcf6ca;
-}
-.table-hover > tbody > tr > td.success:hover,
-.table-hover > tbody > tr > th.success:hover,
-.table-hover > tbody > tr.success:hover > td,
-.table-hover > tbody > tr.success:hover > th {
-  background-color: #cef2b4;
-}
-.table > thead > tr > td.info,
-.table > tbody > tr > td.info,
-.table > tfoot > tr > td.info,
-.table > thead > tr > th.info,
-.table > tbody > tr > th.info,
-.table > tfoot > tr > th.info,
-.table > thead > tr.info > td,
-.table > tbody > tr.info > td,
-.table > tfoot > tr.info > td,
-.table > thead > tr.info > th,
-.table > tbody > tr.info > th,
-.table > tfoot > tr.info > th {
-  background-color: #f6f2f8;
-}
-.table-hover > tbody > tr > td.info:hover,
-.table-hover > tbody > tr > th.info:hover,
-.table-hover > tbody > tr.info:hover > td,
-.table-hover > tbody > tr.info:hover > th {
-  background-color: #e9e1f0;
-}
-.table > thead > tr > td.warning,
-.table > tbody > tr > td.warning,
-.table > tfoot > tr > td.warning,
-.table > thead > tr > th.warning,
-.table > tbody > tr > th.warning,
-.table > tfoot > tr > th.warning,
-.table > thead > tr.warning > td,
-.table > tbody > tr.warning > td,
-.table > tfoot > tr.warning > td,
-.table > thead > tr.warning > th,
-.table > tbody > tr.warning > th,
-.table > tfoot > tr.warning > th {
-  background-color: #f8e4c7;
-}
-.table-hover > tbody > tr > td.warning:hover,
-.table-hover > tbody > tr > th.warning:hover,
-.table-hover > tbody > tr.warning:hover > td,
-.table-hover > tbody > tr.warning:hover > th {
-  background-color: #f6d9b0;
-}
-.table > thead > tr > td.danger,
-.table > tbody > tr > td.danger,
-.table > tfoot > tr > td.danger,
-.table > thead > tr > th.danger,
-.table > tbody > tr > th.danger,
-.table > tfoot > tr > th.danger,
-.table > thead > tr.danger > td,
-.table > tbody > tr.danger > td,
-.table > tfoot > tr.danger > td,
-.table > thead > tr.danger > th,
-.table > tbody > tr.danger > th,
-.table > tfoot > tr.danger > th {
-  background-color: #f6cadc;
-}
-.table-hover > tbody > tr > td.danger:hover,
-.table-hover > tbody > tr > th.danger:hover,
-.table-hover > tbody > tr.danger:hover > td,
-.table-hover > tbody > tr.danger:hover > th {
-  background-color: #f2b4ce;
-}
-@media (max-width: 767px) {
-  .table-responsive {
-    width: 100%;
-    margin-bottom: 15px;
-    overflow-x: scroll;
-    overflow-y: hidden;
-    -webkit-overflow-scrolling: touch;
-    -ms-overflow-style: -ms-autohiding-scrollbar;
-    border: 1px solid #ddd;
-  }
-  .table-responsive > .table {
-    margin-bottom: 0;
-  }
-  .table-responsive > .table > thead > tr > th,
-  .table-responsive > .table > tbody > tr > th,
-  .table-responsive > .table > tfoot > tr > th,
-  .table-responsive > .table > thead > tr > td,
-  .table-responsive > .table > tbody > tr > td,
-  .table-responsive > .table > tfoot > tr > td {
-    white-space: nowrap;
-  }
-  .table-responsive > .table-bordered {
-    border: 0;
-  }
-  .table-responsive > .table-bordered > thead > tr > th:first-child,
-  .table-responsive > .table-bordered > tbody > tr > th:first-child,
-  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
-  .table-responsive > .table-bordered > thead > tr > td:first-child,
-  .table-responsive > .table-bordered > tbody > tr > td:first-child,
-  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
-    border-left: 0;
-  }
-  .table-responsive > .table-bordered > thead > tr > th:last-child,
-  .table-responsive > .table-bordered > tbody > tr > th:last-child,
-  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
-  .table-responsive > .table-bordered > thead > tr > td:last-child,
-  .table-responsive > .table-bordered > tbody > tr > td:last-child,
-  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
-    border-right: 0;
-  }
-  .table-responsive > .table-bordered > tbody > tr:last-child > th,
-  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
-  .table-responsive > .table-bordered > tbody > tr:last-child > td,
-  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
-    border-bottom: 0;
-  }
-}
-fieldset {
-  min-width: 0;
-  padding: 0;
-  margin: 0;
-  border: 0;
-}
-legend {
-  display: block;
-  width: 100%;
-  padding: 0;
-  margin-bottom: 20px;
-  font-size: 21px;
-  line-height: inherit;
-  color: #333;
-  border: 0;
-  border-bottom: 1px solid #e5e5e5;
-}
-label {
-  display: inline-block;
-  margin-bottom: 5px;
-  font-weight: bold;
-}
-input[type="search"] {
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-}
-input[type="radio"],
-input[type="checkbox"] {
-  margin: 4px 0 0;
-  margin-top: 1px \9;
-  /* IE8-9 */
-  line-height: normal;
-}
-input[type="file"] {
-  display: block;
-}
-input[type="range"] {
-  display: block;
-  width: 100%;
-}
-select[multiple],
-select[size] {
-  height: auto;
-}
-input[type="file"]:focus,
-input[type="radio"]:focus,
-input[type="checkbox"]:focus {
-  outline: thin dotted;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-output {
-  display: block;
-  padding-top: 7px;
-  font-size: 14px;
-  line-height: 1.42857143;
-  color: #555;
-}
-.form-control {
-  display: block;
-  width: 100%;
-  height: 34px;
-  padding: 6px 12px;
-  font-size: 14px;
-  line-height: 1.42857143;
-  color: #555;
-  background-color: #fff;
-  background-image: none;
-  border: 1px solid #ccc;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
-          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
-}
-.form-control:focus {
-  border-color: #66afe9;
-  outline: 0;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
-          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
-}
-.form-control::-moz-placeholder {
-  color: #999;
-  opacity: 1;
-}
-.form-control:-ms-input-placeholder {
-  color: #999;
-}
-.form-control::-webkit-input-placeholder {
-  color: #999;
-}
-.form-control[disabled],
-.form-control[readonly],
-fieldset[disabled] .form-control {
-  cursor: not-allowed;
-  background-color: #eee;
-  opacity: 1;
-}
-textarea.form-control {
-  height: auto;
-}
-input[type="search"] {
-  -webkit-appearance: none;
-}
-input[type="date"] {
-  line-height: 34px;
-}
-.form-group {
-  margin-bottom: 15px;
-}
-.radio,
-.checkbox {
-  display: block;
-  min-height: 20px;
-  padding-left: 20px;
-  margin-top: 10px;
-  margin-bottom: 10px;
-}
-.radio label,
-.checkbox label {
-  display: inline;
-  font-weight: normal;
-  cursor: pointer;
-}
-.radio input[type="radio"],
-.radio-inline input[type="radio"],
-.checkbox input[type="checkbox"],
-.checkbox-inline input[type="checkbox"] {
-  float: left;
-  margin-left: -20px;
-}
-.radio + .radio,
-.checkbox + .checkbox {
-  margin-top: -5px;
-}
-.radio-inline,
-.checkbox-inline {
-  display: inline-block;
-  padding-left: 20px;
-  margin-bottom: 0;
-  font-weight: normal;
-  vertical-align: middle;
-  cursor: pointer;
-}
-.radio-inline + .radio-inline,
-.checkbox-inline + .checkbox-inline {
-  margin-top: 0;
-  margin-left: 10px;
-}
-input[type="radio"][disabled],
-input[type="checkbox"][disabled],
-.radio[disabled],
-.radio-inline[disabled],
-.checkbox[disabled],
-.checkbox-inline[disabled],
-fieldset[disabled] input[type="radio"],
-fieldset[disabled] input[type="checkbox"],
-fieldset[disabled] .radio,
-fieldset[disabled] .radio-inline,
-fieldset[disabled] .checkbox,
-fieldset[disabled] .checkbox-inline {
-  cursor: not-allowed;
-}
-.input-sm {
-  height: 30px;
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-select.input-sm {
-  height: 30px;
-  line-height: 30px;
-}
-textarea.input-sm,
-select[multiple].input-sm {
-  height: auto;
-}
-.input-lg {
-  height: 46px;
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.33;
-  border-radius: 6px;
-}
-select.input-lg {
-  height: 46px;
-  line-height: 46px;
-}
-textarea.input-lg,
-select[multiple].input-lg {
-  height: auto;
-}
-.has-feedback {
-  position: relative;
-}
-.has-feedback .form-control {
-  padding-right: 42.5px;
-}
-.has-feedback .form-control-feedback {
-  position: absolute;
-  top: 25px;
-  right: 0;
-  display: block;
-  width: 34px;
-  height: 34px;
-  line-height: 34px;
-  text-align: center;
-}
-.has-success .help-block,
-.has-success .control-label,
-.has-success .radio,
-.has-success .checkbox,
-.has-success .radio-inline,
-.has-success .checkbox-inline {
-  color: #3f7815;
-}
-.has-success .form-control {
-  border-color: #3f7815;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-}
-.has-success .form-control:focus {
-  border-color: #284d0e;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #6ccf24;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #6ccf24;
-}
-.has-success .input-group-addon {
-  color: #3f7815;
-  background-color: #dcf6ca;
-  border-color: #3f7815;
-}
-.has-success .form-control-feedback {
-  color: #3f7815;
-}
-.has-warning .help-block,
-.has-warning .control-label,
-.has-warning .radio,
-.has-warning .checkbox,
-.has-warning .radio-inline,
-.has-warning .checkbox-inline {
-  color: #7e500f;
-}
-.has-warning .form-control {
-  border-color: #7e500f;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-}
-.has-warning .form-control:focus {
-  border-color: #51330a;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #d98a1a;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #d98a1a;
-}
-.has-warning .input-group-addon {
-  color: #7e500f;
-  background-color: #f8e4c7;
-  border-color: #7e500f;
-}
-.has-warning .form-control-feedback {
-  color: #7e500f;
-}
-.has-error .help-block,
-.has-error .control-label,
-.has-error .radio,
-.has-error .checkbox,
-.has-error .radio-inline,
-.has-error .checkbox-inline {
-  color: #78153f;
-}
-.has-error .form-control {
-  border-color: #78153f;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-}
-.has-error .form-control:focus {
-  border-color: #4d0e28;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #cf246c;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #cf246c;
-}
-.has-error .input-group-addon {
-  color: #78153f;
-  background-color: #f6cadc;
-  border-color: #78153f;
-}
-.has-error .form-control-feedback {
-  color: #78153f;
-}
-.form-control-static {
-  margin-bottom: 0;
-}
-.help-block {
-  display: block;
-  margin-top: 5px;
-  margin-bottom: 10px;
-  color: #737373;
-}
-@media (min-width: 768px) {
-  .form-inline .form-group {
-    display: inline-block;
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .form-inline .form-control {
-    display: inline-block;
-    width: auto;
-    vertical-align: middle;
-  }
-  .form-inline .input-group > .form-control {
-    width: 100%;
-  }
-  .form-inline .control-label {
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .form-inline .radio,
-  .form-inline .checkbox {
-    display: inline-block;
-    padding-left: 0;
-    margin-top: 0;
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .form-inline .radio input[type="radio"],
-  .form-inline .checkbox input[type="checkbox"] {
-    float: none;
-    margin-left: 0;
-  }
-  .form-inline .has-feedback .form-control-feedback {
-    top: 0;
-  }
-}
-.form-horizontal .control-label,
-.form-horizontal .radio,
-.form-horizontal .checkbox,
-.form-horizontal .radio-inline,
-.form-horizontal .checkbox-inline {
-  padding-top: 7px;
-  margin-top: 0;
-  margin-bottom: 0;
-}
-.form-horizontal .radio,
-.form-horizontal .checkbox {
-  min-height: 27px;
-}
-.form-horizontal .form-group {
-  margin-right: -15px;
-  margin-left: -15px;
-}
-.form-horizontal .form-control-static {
-  padding-top: 7px;
-}
-@media (min-width: 768px) {
-  .form-horizontal .control-label {
-    text-align: right;
-  }
-}
-.form-horizontal .has-feedback .form-control-feedback {
-  top: 0;
-  right: 15px;
-}
-.btn {
-  display: inline-block;
-  padding: 6px 12px;
-  margin-bottom: 0;
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 1.42857143;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: middle;
-  cursor: pointer;
-  -webkit-user-select: none;
-     -moz-user-select: none;
-      -ms-user-select: none;
-          user-select: none;
-  background-image: none;
-  border: 1px solid transparent;
-  border-radius: 4px;
-}
-.btn:focus,
-.btn:active:focus,
-.btn.active:focus {
-  outline: thin dotted;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-.btn:hover,
-.btn:focus {
-  color: #333;
-  text-decoration: none;
-}
-.btn:active,
-.btn.active {
-  background-image: none;
-  outline: 0;
-  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-}
-.btn.disabled,
-.btn[disabled],
-fieldset[disabled] .btn {
-  pointer-events: none;
-  cursor: not-allowed;
-  filter: alpha(opacity=65);
-  -webkit-box-shadow: none;
-          box-shadow: none;
-  opacity: .65;
-}
-.btn-default {
-  color: #333;
-  background-color: #fff;
-  border-color: #ccc;
-}
-.btn-default:hover,
-.btn-default:focus,
-.btn-default:active,
-.btn-default.active,
-.open .dropdown-toggle.btn-default {
-  color: #333;
-  background-color: #ebebeb;
-  border-color: #adadad;
-}
-.btn-default:active,
-.btn-default.active,
-.open .dropdown-toggle.btn-default {
-  background-image: none;
-}
-.btn-default.disabled,
-.btn-default[disabled],
-fieldset[disabled] .btn-default,
-.btn-default.disabled:hover,
-.btn-default[disabled]:hover,
-fieldset[disabled] .btn-default:hover,
-.btn-default.disabled:focus,
-.btn-default[disabled]:focus,
-fieldset[disabled] .btn-default:focus,
-.btn-default.disabled:active,
-.btn-default[disabled]:active,
-fieldset[disabled] .btn-default:active,
-.btn-default.disabled.active,
-.btn-default[disabled].active,
-fieldset[disabled] .btn-default.active {
-  background-color: #fff;
-  border-color: #ccc;
-}
-.btn-default .badge {
-  color: #fff;
-  background-color: #333;
-}
-.btn-primary {
-  color: #fff;
-  background-color: #428bca;
-  border-color: #357ebd;
-}
-.btn-primary:hover,
-.btn-primary:focus,
-.btn-primary:active,
-.btn-primary.active,
-.open .dropdown-toggle.btn-primary {
-  color: #fff;
-  background-color: #3276b1;
-  border-color: #285e8e;
-}
-.btn-primary:active,
-.btn-primary.active,
-.open .dropdown-toggle.btn-primary {
-  background-image: none;
-}
-.btn-primary.disabled,
-.btn-primary[disabled],
-fieldset[disabled] .btn-primary,
-.btn-primary.disabled:hover,
-.btn-primary[disabled]:hover,
-fieldset[disabled] .btn-primary:hover,
-.btn-primary.disabled:focus,
-.btn-primary[disabled]:focus,
-fieldset[disabled] .btn-primary:focus,
-.btn-primary.disabled:active,
-.btn-primary[disabled]:active,
-fieldset[disabled] .btn-primary:active,
-.btn-primary.disabled.active,
-.btn-primary[disabled].active,
-fieldset[disabled] .btn-primary.active {
-  background-color: #428bca;
-  border-color: #357ebd;
-}
-.btn-primary .badge {
-  color: #428bca;
-  background-color: #fff;
-}
-.btn-success {
-  color: #fff;
-  background-color: #79db32;
-  border-color: #6ccf24;
-}
-.btn-success:hover,
-.btn-success:focus,
-.btn-success:active,
-.btn-success.active,
-.open .dropdown-toggle.btn-success {
-  color: #fff;
-  background-color: #65c222;
-  border-color: #519b1b;
-}
-.btn-success:active,
-.btn-success.active,
-.open .dropdown-toggle.btn-success {
-  background-image: none;
-}
-.btn-success.disabled,
-.btn-success[disabled],
-fieldset[disabled] .btn-success,
-.btn-success.disabled:hover,
-.btn-success[disabled]:hover,
-fieldset[disabled] .btn-success:hover,
-.btn-success.disabled:focus,
-.btn-success[disabled]:focus,
-fieldset[disabled] .btn-success:focus,
-.btn-success.disabled:active,
-.btn-success[disabled]:active,
-fieldset[disabled] .btn-success:active,
-.btn-success.disabled.active,
-.btn-success[disabled].active,
-fieldset[disabled] .btn-success.active {
-  background-color: #79db32;
-  border-color: #6ccf24;
-}
-.btn-success .badge {
-  color: #79db32;
-  background-color: #fff;
-}
-.btn-info {
-  color: #fff;
-  background-color: #a07cbc;
-  border-color: #946bb3;
-}
-.btn-info:hover,
-.btn-info:focus,
-.btn-info:active,
-.btn-info.active,
-.open .dropdown-toggle.btn-info {
-  color: #fff;
-  background-color: #8c61ae;
-  border-color: #754c95;
-}
-.btn-info:active,
-.btn-info.active,
-.open .dropdown-toggle.btn-info {
-  background-image: none;
-}
-.btn-info.disabled,
-.btn-info[disabled],
-fieldset[disabled] .btn-info,
-.btn-info.disabled:hover,
-.btn-info[disabled]:hover,
-fieldset[disabled] .btn-info:hover,
-.btn-info.disabled:focus,
-.btn-info[disabled]:focus,
-fieldset[disabled] .btn-info:focus,
-.btn-info.disabled:active,
-.btn-info[disabled]:active,
-fieldset[disabled] .btn-info:active,
-.btn-info.disabled.active,
-.btn-info[disabled].active,
-fieldset[disabled] .btn-info.active {
-  background-color: #a07cbc;
-  border-color: #946bb3;
-}
-.btn-info .badge {
-  color: #a07cbc;
-  background-color: #fff;
-}
-.btn-warning {
-  color: #fff;
-  background-color: #e59728;
-  border-color: #d98a1a;
-}
-.btn-warning:hover,
-.btn-warning:focus,
-.btn-warning:active,
-.btn-warning.active,
-.open .dropdown-toggle.btn-warning {
-  color: #fff;
-  background-color: #cc8219;
-  border-color: #a36814;
-}
-.btn-warning:active,
-.btn-warning.active,
-.open .dropdown-toggle.btn-warning {
-  background-image: none;
-}
-.btn-warning.disabled,
-.btn-warning[disabled],
-fieldset[disabled] .btn-warning,
-.btn-warning.disabled:hover,
-.btn-warning[disabled]:hover,
-fieldset[disabled] .btn-warning:hover,
-.btn-warning.disabled:focus,
-.btn-warning[disabled]:focus,
-fieldset[disabled] .btn-warning:focus,
-.btn-warning.disabled:active,
-.btn-warning[disabled]:active,
-fieldset[disabled] .btn-warning:active,
-.btn-warning.disabled.active,
-.btn-warning[disabled].active,
-fieldset[disabled] .btn-warning.active {
-  background-color: #e59728;
-  border-color: #d98a1a;
-}
-.btn-warning .badge {
-  color: #e59728;
-  background-color: #fff;
-}
-.btn-danger {
-  color: #fff;
-  background-color: #db3279;
-  border-color: #cf246c;
-}
-.btn-danger:hover,
-.btn-danger:focus,
-.btn-danger:active,
-.btn-danger.active,
-.open .dropdown-toggle.btn-danger {
-  color: #fff;
-  background-color: #c22265;
-  border-color: #9b1b51;
-}
-.btn-danger:active,
-.btn-danger.active,
-.open .dropdown-toggle.btn-danger {
-  background-image: none;
-}
-.btn-danger.disabled,
-.btn-danger[disabled],
-fieldset[disabled] .btn-danger,
-.btn-danger.disabled:hover,
-.btn-danger[disabled]:hover,
-fieldset[disabled] .btn-danger:hover,
-.btn-danger.disabled:focus,
-.btn-danger[disabled]:focus,
-fieldset[disabled] .btn-danger:focus,
-.btn-danger.disabled:active,
-.btn-danger[disabled]:active,
-fieldset[disabled] .btn-danger:active,
-.btn-danger.disabled.active,
-.btn-danger[disabled].active,
-fieldset[disabled] .btn-danger.active {
-  background-color: #db3279;
-  border-color: #cf246c;
-}
-.btn-danger .badge {
-  color: #db3279;
-  background-color: #fff;
-}
-.btn-link {
-  font-weight: normal;
-  color: #428bca;
-  cursor: pointer;
-  border-radius: 0;
-}
-.btn-link,
-.btn-link:active,
-.btn-link[disabled],
-fieldset[disabled] .btn-link {
-  background-color: transparent;
-  -webkit-box-shadow: none;
-          box-shadow: none;
-}
-.btn-link,
-.btn-link:hover,
-.btn-link:focus,
-.btn-link:active {
-  border-color: transparent;
-}
-.btn-link:hover,
-.btn-link:focus {
-  color: #2a6496;
-  text-decoration: underline;
-  background-color: transparent;
-}
-.btn-link[disabled]:hover,
-fieldset[disabled] .btn-link:hover,
-.btn-link[disabled]:focus,
-fieldset[disabled] .btn-link:focus {
-  color: #999;
-  text-decoration: none;
-}
-.btn-lg,
-.btn-group-lg > .btn {
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.33;
-  border-radius: 6px;
-}
-.btn-sm,
-.btn-group-sm > .btn {
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-.btn-xs,
-.btn-group-xs > .btn {
-  padding: 1px 5px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-.btn-block {
-  display: block;
-  width: 100%;
-  padding-right: 0;
-  padding-left: 0;
-}
-.btn-block + .btn-block {
-  margin-top: 5px;
-}
-input[type="submit"].btn-block,
-input[type="reset"].btn-block,
-input[type="button"].btn-block {
-  width: 100%;
-}
-.fade {
-  opacity: 0;
-  -webkit-transition: opacity .15s linear;
-          transition: opacity .15s linear;
-}
-.fade.in {
-  opacity: 1;
-}
-.collapse {
-  display: none;
-}
-.collapse.in {
-  display: block;
-}
-.collapsing {
-  position: relative;
-  height: 0;
-  overflow: hidden;
-  -webkit-transition: height .35s ease;
-          transition: height .35s ease;
-}
-@font-face {
-  font-family: 'Glyphicons Halflings';
-
-  src: url('../fonts/glyphicons-halflings-regular.eot');
-  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
-}
-.glyphicon {
-  position: relative;
-  top: 1px;
-  display: inline-block;
-  font-family: 'Glyphicons Halflings';
-  font-style: normal;
-  font-weight: normal;
-  line-height: 1;
-
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-.glyphicon-asterisk:before {
-  content: "\2a";
-}
-.glyphicon-plus:before {
-  content: "\2b";
-}
-.glyphicon-euro:before {
-  content: "\20ac";
-}
-.glyphicon-minus:before {
-  content: "\2212";
-}
-.glyphicon-cloud:before {
-  content: "\2601";
-}
-.glyphicon-envelope:before {
-  content: "\2709";
-}
-.glyphicon-pencil:before {
-  content: "\270f";
-}
-.glyphicon-glass:before {
-  content: "\e001";
-}
-.glyphicon-music:before {
-  content: "\e002";
-}
-.glyphicon-search:before {
-  content: "\e003";
-}
-.glyphicon-heart:before {
-  content: "\e005";
-}
-.glyphicon-star:before {
-  content: "\e006";
-}
-.glyphicon-star-empty:before {
-  content: "\e007";
-}
-.glyphicon-user:before {
-  content: "\e008";
-}
-.glyphicon-film:before {
-  content: "\e009";
-}
-.glyphicon-th-large:before {
-  content: "\e010";
-}
-.glyphicon-th:before {
-  content: "\e011";
-}
-.glyphicon-th-list:before {
-  content: "\e012";
-}
-.glyphicon-ok:before {
-  content: "\e013";
-}
-.glyphicon-remove:before {
-  content: "\e014";
-}
-.glyphicon-zoom-in:before {
-  content: "\e015";
-}
-.glyphicon-zoom-out:before {
-  content: "\e016";
-}
-.glyphicon-off:before {
-  content: "\e017";
-}
-.glyphicon-signal:before {
-  content: "\e018";
-}
-.glyphicon-cog:before {
-  content: "\e019";
-}
-.glyphicon-trash:before {
-  content: "\e020";
-}
-.glyphicon-home:before {
-  content: "\e021";
-}
-.glyphicon-file:before {
-  content: "\e022";
-}
-.glyphicon-time:before {
-  content: "\e023";
-}
-.glyphicon-road:before {
-  content: "\e024";
-}
-.glyphicon-download-alt:before {
-  content: "\e025";
-}
-.glyphicon-download:before {
-  content: "\e026";
-}
-.glyphicon-upload:before {
-  content: "\e027";
-}
-.glyphicon-inbox:before {
-  content: "\e028";
-}
-.glyphicon-play-circle:before {
-  content: "\e029";
-}
-.glyphicon-repeat:before {
-  content: "\e030";
-}
-.glyphicon-refresh:before {
-  content: "\e031";
-}
-.glyphicon-list-alt:before {
-  content: "\e032";
-}
-.glyphicon-lock:before {
-  content: "\e033";
-}
-.glyphicon-flag:before {
-  content: "\e034";
-}
-.glyphicon-headphones:before {
-  content: "\e035";
-}
-.glyphicon-volume-off:before {
-  content: "\e036";
-}
-.glyphicon-volume-down:before {
-  content: "\e037";
-}
-.glyphicon-volume-up:before {
-  content: "\e038";
-}
-.glyphicon-qrcode:before {
-  content: "\e039";
-}
-.glyphicon-barcode:before {
-  content: "\e040";
-}
-.glyphicon-tag:before {
-  content: "\e041";
-}
-.glyphicon-tags:before {
-  content: "\e042";
-}
-.glyphicon-book:before {
-  content: "\e043";
-}
-.glyphicon-bookmark:before {
-  content: "\e044";
-}
-.glyphicon-print:before {
-  content: "\e045";
-}
-.glyphicon-camera:before {
-  content: "\e046";
-}
-.glyphicon-font:before {
-  content: "\e047";
-}
-.glyphicon-bold:before {
-  content: "\e048";
-}
-.glyphicon-italic:before {
-  content: "\e049";
-}
-.glyphicon-text-height:before {
-  content: "\e050";
-}
-.glyphicon-text-width:before {
-  content: "\e051";
-}
-.glyphicon-align-left:before {
-  content: "\e052";
-}
-.glyphicon-align-center:before {
-  content: "\e053";
-}
-.glyphicon-align-right:before {
-  content: "\e054";
-}
-.glyphicon-align-justify:before {
-  content: "\e055";
-}
-.glyphicon-list:before {
-  content: "\e056";
-}
-.glyphicon-indent-left:before {
-  content: "\e057";
-}
-.glyphicon-indent-right:before {
-  content: "\e058";
-}
-.glyphicon-facetime-video:before {
-  content: "\e059";
-}
-.glyphicon-picture:before {
-  content: "\e060";
-}
-.glyphicon-map-marker:before {
-  content: "\e062";
-}
-.glyphicon-adjust:before {
-  content: "\e063";
-}
-.glyphicon-tint:before {
-  content: "\e064";
-}
-.glyphicon-edit:before {
-  content: "\e065";
-}
-.glyphicon-share:before {
-  content: "\e066";
-}
-.glyphicon-check:before {
-  content: "\e067";
-}
-.glyphicon-move:before {
-  content: "\e068";
-}
-.glyphicon-step-backward:before {
-  content: "\e069";
-}
-.glyphicon-fast-backward:before {
-  content: "\e070";
-}
-.glyphicon-backward:before {
-  content: "\e071";
-}
-.glyphicon-play:before {
-  content: "\e072";
-}
-.glyphicon-pause:before {
-  content: "\e073";
-}
-.glyphicon-stop:before {
-  content: "\e074";
-}
-.glyphicon-forward:before {
-  content: "\e075";
-}
-.glyphicon-fast-forward:before {
-  content: "\e076";
-}
-.glyphicon-step-forward:before {
-  content: "\e077";
-}
-.glyphicon-eject:before {
-  content: "\e078";
-}
-.glyphicon-chevron-left:before {
-  content: "\e079";
-}
-.glyphicon-chevron-right:before {
-  content: "\e080";
-}
-.glyphicon-plus-sign:before {
-  content: "\e081";
-}
-.glyphicon-minus-sign:before {
-  content: "\e082";
-}
-.glyphicon-remove-sign:before {
-  content: "\e083";
-}
-.glyphicon-ok-sign:before {
-  content: "\e084";
-}
-.glyphicon-question-sign:before {
-  content: "\e085";
-}
-.glyphicon-info-sign:before {
-  content: "\e086";
-}
-.glyphicon-screenshot:before {
-  content: "\e087";
-}
-.glyphicon-remove-circle:before {
-  content: "\e088";
-}
-.glyphicon-ok-circle:before {
-  content: "\e089";
-}
-.glyphicon-ban-circle:before {
-  content: "\e090";
-}
-.glyphicon-arrow-left:before {
-  content: "\e091";
-}
-.glyphicon-arrow-right:before {
-  content: "\e092";
-}
-.glyphicon-arrow-up:before {
-  content: "\e093";
-}
-.glyphicon-arrow-down:before {
-  content: "\e094";
-}
-.glyphicon-share-alt:before {
-  content: "\e095";
-}
-.glyphicon-resize-full:before {
-  content: "\e096";
-}
-.glyphicon-resize-small:before {
-  content: "\e097";
-}
-.glyphicon-exclamation-sign:before {
-  content: "\e101";
-}
-.glyphicon-gift:before {
-  content: "\e102";
-}
-.glyphicon-leaf:before {
-  content: "\e103";
-}
-.glyphicon-fire:before {
-  content: "\e104";
-}
-.glyphicon-eye-open:before {
-  content: "\e105";
-}
-.glyphicon-eye-close:before {
-  content: "\e106";
-}
-.glyphicon-warning-sign:before {
-  content: "\e107";
-}
-.glyphicon-plane:before {
-  content: "\e108";
-}
-.glyphicon-calendar:before {
-  content: "\e109";
-}
-.glyphicon-random:before {
-  content: "\e110";
-}
-.glyphicon-comment:before {
-  content: "\e111";
-}
-.glyphicon-magnet:before {
-  content: "\e112";
-}
-.glyphicon-chevron-up:before {
-  content: "\e113";
-}
-.glyphicon-chevron-down:before {
-  content: "\e114";
-}
-.glyphicon-retweet:before {
-  content: "\e115";
-}
-.glyphicon-shopping-cart:before {
-  content: "\e116";
-}
-.glyphicon-folder-close:before {
-  content: "\e117";
-}
-.glyphicon-folder-open:before {
-  content: "\e118";
-}
-.glyphicon-resize-vertical:before {
-  content: "\e119";
-}
-.glyphicon-resize-horizontal:before {
-  content: "\e120";
-}
-.glyphicon-hdd:before {
-  content: "\e121";
-}
-.glyphicon-bullhorn:before {
-  content: "\e122";
-}
-.glyphicon-bell:before {
-  content: "\e123";
-}
-.glyphicon-certificate:before {
-  content: "\e124";
-}
-.glyphicon-thumbs-up:before {
-  content: "\e125";
-}
-.glyphicon-thumbs-down:before {
-  content: "\e126";
-}
-.glyphicon-hand-right:before {
-  content: "\e127";
-}
-.glyphicon-hand-left:before {
-  content: "\e128";
-}
-.glyphicon-hand-up:before {
-  content: "\e129";
-}
-.glyphicon-hand-down:before {
-  content: "\e130";
-}
-.glyphicon-circle-arrow-right:before {
-  content: "\e131";
-}
-.glyphicon-circle-arrow-left:before {
-  content: "\e132";
-}
-.glyphicon-circle-arrow-up:before {
-  content: "\e133";
-}
-.glyphicon-circle-arrow-down:before {
-  content: "\e134";
-}
-.glyphicon-globe:before {
-  content: "\e135";
-}
-.glyphicon-wrench:before {
-  content: "\e136";
-}
-.glyphicon-tasks:before {
-  content: "\e137";
-}
-.glyphicon-filter:before {
-  content: "\e138";
-}
-.glyphicon-briefcase:before {
-  content: "\e139";
-}
-.glyphicon-fullscreen:before {
-  content: "\e140";
-}
-.glyphicon-dashboard:before {
-  content: "\e141";
-}
-.glyphicon-paperclip:before {
-  content: "\e142";
-}
-.glyphicon-heart-empty:before {
-  content: "\e143";
-}
-.glyphicon-link:before {
-  content: "\e144";
-}
-.glyphicon-phone:before {
-  content: "\e145";
-}
-.glyphicon-pushpin:before {
-  content: "\e146";
-}
-.glyphicon-usd:before {
-  content: "\e148";
-}
-.glyphicon-gbp:before {
-  content: "\e149";
-}
-.glyphicon-sort:before {
-  content: "\e150";
-}
-.glyphicon-sort-by-alphabet:before {
-  content: "\e151";
-}
-.glyphicon-sort-by-alphabet-alt:before {
-  content: "\e152";
-}
-.glyphicon-sort-by-order:before {
-  content: "\e153";
-}
-.glyphicon-sort-by-order-alt:before {
-  content: "\e154";
-}
-.glyphicon-sort-by-attributes:before {
-  content: "\e155";
-}
-.glyphicon-sort-by-attributes-alt:before {
-  content: "\e156";
-}
-.glyphicon-unchecked:before {
-  content: "\e157";
-}
-.glyphicon-expand:before {
-  content: "\e158";
-}
-.glyphicon-collapse-down:before {
-  content: "\e159";
-}
-.glyphicon-collapse-up:before {
-  content: "\e160";
-}
-.glyphicon-log-in:before {
-  content: "\e161";
-}
-.glyphicon-flash:before {
-  content: "\e162";
-}
-.glyphicon-log-out:before {
-  content: "\e163";
-}
-.glyphicon-new-window:before {
-  content: "\e164";
-}
-.glyphicon-record:before {
-  content: "\e165";
-}
-.glyphicon-save:before {
-  content: "\e166";
-}
-.glyphicon-open:before {
-  content: "\e167";
-}
-.glyphicon-saved:before {
-  content: "\e168";
-}
-.glyphicon-import:before {
-  content: "\e169";
-}
-.glyphicon-export:before {
-  content: "\e170";
-}
-.glyphicon-send:before {
-  content: "\e171";
-}
-.glyphicon-floppy-disk:before {
-  content: "\e172";
-}
-.glyphicon-floppy-saved:before {
-  content: "\e173";
-}
-.glyphicon-floppy-remove:before {
-  content: "\e174";
-}
-.glyphicon-floppy-save:before {
-  content: "\e175";
-}
-.glyphicon-floppy-open:before {
-  content: "\e176";
-}
-.glyphicon-credit-card:before {
-  content: "\e177";
-}
-.glyphicon-transfer:before {
-  content: "\e178";
-}
-.glyphicon-cutlery:before {
-  content: "\e179";
-}
-.glyphicon-header:before {
-  content: "\e180";
-}
-.glyphicon-compressed:before {
-  content: "\e181";
-}
-.glyphicon-earphone:before {
-  content: "\e182";
-}
-.glyphicon-phone-alt:before {
-  content: "\e183";
-}
-.glyphicon-tower:before {
-  content: "\e184";
-}
-.glyphicon-stats:before {
-  content: "\e185";
-}
-.glyphicon-sd-video:before {
-  content: "\e186";
-}
-.glyphicon-hd-video:before {
-  content: "\e187";
-}
-.glyphicon-subtitles:before {
-  content: "\e188";
-}
-.glyphicon-sound-stereo:before {
-  content: "\e189";
-}
-.glyphicon-sound-dolby:before {
-  content: "\e190";
-}
-.glyphicon-sound-5-1:before {
-  content: "\e191";
-}
-.glyphicon-sound-6-1:before {
-  content: "\e192";
-}
-.glyphicon-sound-7-1:before {
-  content: "\e193";
-}
-.glyphicon-copyright-mark:before {
-  content: "\e194";
-}
-.glyphicon-registration-mark:before {
-  content: "\e195";
-}
-.glyphicon-cloud-download:before {
-  content: "\e197";
-}
-.glyphicon-cloud-upload:before {
-  content: "\e198";
-}
-.glyphicon-tree-conifer:before {
-  content: "\e199";
-}
-.glyphicon-tree-deciduous:before {
-  content: "\e200";
-}
-.caret {
-  display: inline-block;
-  width: 0;
-  height: 0;
-  margin-left: 2px;
-  vertical-align: middle;
-  border-top: 4px solid;
-  border-right: 4px solid transparent;
-  border-left: 4px solid transparent;
-}
-.dropdown {
-  position: relative;
-}
-.dropdown-toggle:focus {
-  outline: 0;
-}
-.dropdown-menu {
-  position: absolute;
-  top: 100%;
-  left: 0;
-  z-index: 1000;
-  display: none;
-  float: left;
-  min-width: 160px;
-  padding: 5px 0;
-  margin: 2px 0 0;
-  font-size: 14px;
-  list-style: none;
-  background-color: #fff;
-  background-clip: padding-box;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, .15);
-  border-radius: 4px;
-  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
-          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
-}
-.dropdown-menu.pull-right {
-  right: 0;
-  left: auto;
-}
-.dropdown-menu .divider {
-  height: 1px;
-  margin: 9px 0;
-  overflow: hidden;
-  background-color: #e5e5e5;
-}
-.dropdown-menu > li > a {
-  display: block;
-  padding: 3px 20px;
-  clear: both;
-  font-weight: normal;
-  line-height: 1.42857143;
-  color: #333;
-  white-space: nowrap;
-}
-.dropdown-menu > li > a:hover,
-.dropdown-menu > li > a:focus {
-  color: #262626;
-  text-decoration: none;
-  background-color: #f5f5f5;
-}
-.dropdown-menu > .active > a,
-.dropdown-menu > .active > a:hover,
-.dropdown-menu > .active > a:focus {
-  color: #fff;
-  text-decoration: none;
-  background-color: #428bca;
-  outline: 0;
-}
-.dropdown-menu > .disabled > a,
-.dropdown-menu > .disabled > a:hover,
-.dropdown-menu > .disabled > a:focus {
-  color: #999;
-}
-.dropdown-menu > .disabled > a:hover,
-.dropdown-menu > .disabled > a:focus {
-  text-decoration: none;
-  cursor: not-allowed;
-  background-color: transparent;
-  background-image: none;
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-}
-.open > .dropdown-menu {
-  display: block;
-}
-.open > a {
-  outline: 0;
-}
-.dropdown-menu-right {
-  right: 0;
-  left: auto;
-}
-.dropdown-menu-left {
-  right: auto;
-  left: 0;
-}
-.dropdown-header {
-  display: block;
-  padding: 3px 20px;
-  font-size: 12px;
-  line-height: 1.42857143;
-  color: #999;
-}
-.dropdown-backdrop {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 990;
-}
-.pull-right > .dropdown-menu {
-  right: 0;
-  left: auto;
-}
-.dropup .caret,
-.navbar-fixed-bottom .dropdown .caret {
-  content: "";
-  border-top: 0;
-  border-bottom: 4px solid;
-}
-.dropup .dropdown-menu,
-.navbar-fixed-bottom .dropdown .dropdown-menu {
-  top: auto;
-  bottom: 100%;
-  margin-bottom: 1px;
-}
-@media (min-width: 768px) {
-  .navbar-right .dropdown-menu {
-    right: 0;
-    left: auto;
-  }
-  .navbar-right .dropdown-menu-left {
-    right: auto;
-    left: 0;
-  }
-}
-.btn-group,
-.btn-group-vertical {
-  position: relative;
-  display: inline-block;
-  vertical-align: middle;
-}
-.btn-group > .btn,
-.btn-group-vertical > .btn {
-  position: relative;
-  float: left;
-}
-.btn-group > .btn:hover,
-.btn-group-vertical > .btn:hover,
-.btn-group > .btn:focus,
-.btn-group-vertical > .btn:focus,
-.btn-group > .btn:active,
-.btn-group-vertical > .btn:active,
-.btn-group > .btn.active,
-.btn-group-vertical > .btn.active {
-  z-index: 2;
-}
-.btn-group > .btn:focus,
-.btn-group-vertical > .btn:focus {
-  outline: none;
-}
-.btn-group .btn + .btn,
-.btn-group .btn + .btn-group,
-.btn-group .btn-group + .btn,
-.btn-group .btn-group + .btn-group {
-  margin-left: -1px;
-}
-.btn-toolbar {
-  margin-left: -5px;
-}
-.btn-toolbar .btn-group,
-.btn-toolbar .input-group {
-  float: left;
-}
-.btn-toolbar > .btn,
-.btn-toolbar > .btn-group,
-.btn-toolbar > .input-group {
-  margin-left: 5px;
-}
-.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
-  border-radius: 0;
-}
-.btn-group > .btn:first-child {
-  margin-left: 0;
-}
-.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-.btn-group > .btn:last-child:not(:first-child),
-.btn-group > .dropdown-toggle:not(:first-child) {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group > .btn-group {
-  float: left;
-}
-.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
-  border-radius: 0;
-}
-.btn-group > .btn-group:first-child > .btn:last-child,
-.btn-group > .btn-group:first-child > .dropdown-toggle {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-.btn-group > .btn-group:last-child > .btn:first-child {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group .dropdown-toggle:active,
-.btn-group.open .dropdown-toggle {
-  outline: 0;
-}
-.btn-group > .btn + .dropdown-toggle {
-  padding-right: 8px;
-  padding-left: 8px;
-}
-.btn-group > .btn-lg + .dropdown-toggle {
-  padding-right: 12px;
-  padding-left: 12px;
-}
-.btn-group.open .dropdown-toggle {
-  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-}
-.btn-group.open .dropdown-toggle.btn-link {
-  -webkit-box-shadow: none;
-          box-shadow: none;
-}
-.btn .caret {
-  margin-left: 0;
-}
-.btn-lg .caret {
-  border-width: 5px 5px 0;
-  border-bottom-width: 0;
-}
-.dropup .btn-lg .caret {
-  border-width: 0 5px 5px;
-}
-.btn-group-vertical > .btn,
-.btn-group-vertical > .btn-group,
-.btn-group-vertical > .btn-group > .btn {
-  display: block;
-  float: none;
-  width: 100%;
-  max-width: 100%;
-}
-.btn-group-vertical > .btn-group > .btn {
-  float: none;
-}
-.btn-group-vertical > .btn + .btn,
-.btn-group-vertical > .btn + .btn-group,
-.btn-group-vertical > .btn-group + .btn,
-.btn-group-vertical > .btn-group + .btn-group {
-  margin-top: -1px;
-  margin-left: 0;
-}
-.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
-  border-radius: 0;
-}
-.btn-group-vertical > .btn:first-child:not(:last-child) {
-  border-top-right-radius: 4px;
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group-vertical > .btn:last-child:not(:first-child) {
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-  border-bottom-left-radius: 4px;
-}
-.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
-  border-radius: 0;
-}
-.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
-.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.btn-group-justified {
-  display: table;
-  width: 100%;
-  table-layout: fixed;
-  border-collapse: separate;
-}
-.btn-group-justified > .btn,
-.btn-group-justified > .btn-group {
-  display: table-cell;
-  float: none;
-  width: 1%;
-}
-.btn-group-justified > .btn-group .btn {
-  width: 100%;
-}
-[data-toggle="buttons"] > .btn > input[type="radio"],
-[data-toggle="buttons"] > .btn > input[type="checkbox"] {
-  display: none;
-}
-.input-group {
-  position: relative;
-  display: table;
-  border-collapse: separate;
-}
-.input-group[class*="col-"] {
-  float: none;
-  padding-right: 0;
-  padding-left: 0;
-}
-.input-group .form-control {
-  position: relative;
-  z-index: 2;
-  float: left;
-  width: 100%;
-  margin-bottom: 0;
-}
-.input-group-lg > .form-control,
-.input-group-lg > .input-group-addon,
-.input-group-lg > .input-group-btn > .btn {
-  height: 46px;
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.33;
-  border-radius: 6px;
-}
-select.input-group-lg > .form-control,
-select.input-group-lg > .input-group-addon,
-select.input-group-lg > .input-group-btn > .btn {
-  height: 46px;
-  line-height: 46px;
-}
-textarea.input-group-lg > .form-control,
-textarea.input-group-lg > .input-group-addon,
-textarea.input-group-lg > .input-group-btn > .btn,
-select[multiple].input-group-lg > .form-control,
-select[multiple].input-group-lg > .input-group-addon,
-select[multiple].input-group-lg > .input-group-btn > .btn {
-  height: auto;
-}
-.input-group-sm > .form-control,
-.input-group-sm > .input-group-addon,
-.input-group-sm > .input-group-btn > .btn {
-  height: 30px;
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-select.input-group-sm > .form-control,
-select.input-group-sm > .input-group-addon,
-select.input-group-sm > .input-group-btn > .btn {
-  height: 30px;
-  line-height: 30px;
-}
-textarea.input-group-sm > .form-control,
-textarea.input-group-sm > .input-group-addon,
-textarea.input-group-sm > .input-group-btn > .btn,
-select[multiple].input-group-sm > .form-control,
-select[multiple].input-group-sm > .input-group-addon,
-select[multiple].input-group-sm > .input-group-btn > .btn {
-  height: auto;
-}
-.input-group-addon,
-.input-group-btn,
-.input-group .form-control {
-  display: table-cell;
-}
-.input-group-addon:not(:first-child):not(:last-child),
-.input-group-btn:not(:first-child):not(:last-child),
-.input-group .form-control:not(:first-child):not(:last-child) {
-  border-radius: 0;
-}
-.input-group-addon,
-.input-group-btn {
-  width: 1%;
-  white-space: nowrap;
-  vertical-align: middle;
-}
-.input-group-addon {
-  padding: 6px 12px;
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 1;
-  color: #555;
-  text-align: center;
-  background-color: #eee;
-  border: 1px solid #ccc;
-  border-radius: 4px;
-}
-.input-group-addon.input-sm {
-  padding: 5px 10px;
-  font-size: 12px;
-  border-radius: 3px;
-}
-.input-group-addon.input-lg {
-  padding: 10px 16px;
-  font-size: 18px;
-  border-radius: 6px;
-}
-.input-group-addon input[type="radio"],
-.input-group-addon input[type="checkbox"] {
-  margin-top: 0;
-}
-.input-group .form-control:first-child,
-.input-group-addon:first-child,
-.input-group-btn:first-child > .btn,
-.input-group-btn:first-child > .btn-group > .btn,
-.input-group-btn:first-child > .dropdown-toggle,
-.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
-.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-.input-group-addon:first-child {
-  border-right: 0;
-}
-.input-group .form-control:last-child,
-.input-group-addon:last-child,
-.input-group-btn:last-child > .btn,
-.input-group-btn:last-child > .btn-group > .btn,
-.input-group-btn:last-child > .dropdown-toggle,
-.input-group-btn:first-child > .btn:not(:first-child),
-.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.input-group-addon:last-child {
-  border-left: 0;
-}
-.input-group-btn {
-  position: relative;
-  font-size: 0;
-  white-space: nowrap;
-}
-.input-group-btn > .btn {
-  position: relative;
-}
-.input-group-btn > .btn + .btn {
-  margin-left: -1px;
-}
-.input-group-btn > .btn:hover,
-.input-group-btn > .btn:focus,
-.input-group-btn > .btn:active {
-  z-index: 2;
-}
-.input-group-btn:first-child > .btn,
-.input-group-btn:first-child > .btn-group {
-  margin-right: -1px;
-}
-.input-group-btn:last-child > .btn,
-.input-group-btn:last-child > .btn-group {
-  margin-left: -1px;
-}
-.nav {
-  padding-left: 0;
-  margin-bottom: 0;
-  list-style: none;
-}
-.nav > li {
-  position: relative;
-  display: block;
-}
-.nav > li > a {
-  position: relative;
-  display: block;
-  padding: 10px 15px;
-}
-.nav > li > a:hover,
-.nav > li > a:focus {
-  text-decoration: none;
-  background-color: #eee;
-}
-.nav > li.disabled > a {
-  color: #999;
-}
-.nav > li.disabled > a:hover,
-.nav > li.disabled > a:focus {
-  color: #999;
-  text-decoration: none;
-  cursor: not-allowed;
-  background-color: transparent;
-}
-.nav .open > a,
-.nav .open > a:hover,
-.nav .open > a:focus {
-  background-color: #eee;
-  border-color: #428bca;
-}
-.nav .nav-divider {
-  height: 1px;
-  margin: 9px 0;
-  overflow: hidden;
-  background-color: #e5e5e5;
-}
-.nav > li > a > img {
-  max-width: none;
-}
-.nav-tabs {
-  border-bottom: 1px solid #ddd;
-}
-.nav-tabs > li {
-  float: left;
-  margin-bottom: -1px;
-}
-.nav-tabs > li > a {
-  margin-right: 2px;
-  line-height: 1.42857143;
-  border: 1px solid transparent;
-  border-radius: 4px 4px 0 0;
-}
-.nav-tabs > li > a:hover {
-  border-color: #eee #eee #ddd;
-}
-.nav-tabs > li.active > a,
-.nav-tabs > li.active > a:hover,
-.nav-tabs > li.active > a:focus {
-  color: #555;
-  cursor: default;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-bottom-color: transparent;
-}
-.nav-tabs.nav-justified {
-  width: 100%;
-  border-bottom: 0;
-}
-.nav-tabs.nav-justified > li {
-  float: none;
-}
-.nav-tabs.nav-justified > li > a {
-  margin-bottom: 5px;
-  text-align: center;
-}
-.nav-tabs.nav-justified > .dropdown .dropdown-menu {
-  top: auto;
-  left: auto;
-}
-@media (min-width: 768px) {
-  .nav-tabs.nav-justified > li {
-    display: table-cell;
-    width: 1%;
-  }
-  .nav-tabs.nav-justified > li > a {
-    margin-bottom: 0;
-  }
-}
-.nav-tabs.nav-justified > li > a {
-  margin-right: 0;
-  border-radius: 4px;
-}
-.nav-tabs.nav-justified > .active > a,
-.nav-tabs.nav-justified > .active > a:hover,
-.nav-tabs.nav-justified > .active > a:focus {
-  border: 1px solid #ddd;
-}
-@media (min-width: 768px) {
-  .nav-tabs.nav-justified > li > a {
-    border-bottom: 1px solid #ddd;
-    border-radius: 4px 4px 0 0;
-  }
-  .nav-tabs.nav-justified > .active > a,
-  .nav-tabs.nav-justified > .active > a:hover,
-  .nav-tabs.nav-justified > .active > a:focus {
-    border-bottom-color: #fff;
-  }
-}
-.nav-pills > li {
-  float: left;
-}
-.nav-pills > li > a {
-  border-radius: 4px;
-}
-.nav-pills > li + li {
-  margin-left: 2px;
-}
-.nav-pills > li.active > a,
-.nav-pills > li.active > a:hover,
-.nav-pills > li.active > a:focus {
-  color: #fff;
-  background-color: #428bca;
-}
-.nav-stacked > li {
-  float: none;
-}
-.nav-stacked > li + li {
-  margin-top: 2px;
-  margin-left: 0;
-}
-.nav-justified {
-  width: 100%;
-}
-.nav-justified > li {
-  float: none;
-}
-.nav-justified > li > a {
-  margin-bottom: 5px;
-  text-align: center;
-}
-.nav-justified > .dropdown .dropdown-menu {
-  top: auto;
-  left: auto;
-}
-@media (min-width: 768px) {
-  .nav-justified > li {
-    display: table-cell;
-    width: 1%;
-  }
-  .nav-justified > li > a {
-    margin-bottom: 0;
-  }
-}
-.nav-tabs-justified {
-  border-bottom: 0;
-}
-.nav-tabs-justified > li > a {
-  margin-right: 0;
-  border-radius: 4px;
-}
-.nav-tabs-justified > .active > a,
-.nav-tabs-justified > .active > a:hover,
-.nav-tabs-justified > .active > a:focus {
-  border: 1px solid #ddd;
-}
-@media (min-width: 768px) {
-  .nav-tabs-justified > li > a {
-    border-bottom: 1px solid #ddd;
-    border-radius: 4px 4px 0 0;
-  }
-  .nav-tabs-justified > .active > a,
-  .nav-tabs-justified > .active > a:hover,
-  .nav-tabs-justified > .active > a:focus {
-    border-bottom-color: #fff;
-  }
-}
-.tab-content > .tab-pane {
-  display: none;
-}
-.tab-content > .active {
-  display: block;
-}
-.nav-tabs .dropdown-menu {
-  margin-top: -1px;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.navbar {
-  position: relative;
-  min-height: 50px;
-  margin-bottom: 20px;
-  border: 1px solid transparent;
-}
-@media (min-width: 768px) {
-  .navbar {
-    border-radius: 4px;
-  }
-}
-@media (min-width: 768px) {
-  .navbar-header {
-    float: left;
-  }
-}
-.navbar-collapse {
-  max-height: 340px;
-  padding-right: 15px;
-  padding-left: 15px;
-  overflow-x: visible;
-  -webkit-overflow-scrolling: touch;
-  border-top: 1px solid transparent;
-  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
-}
-.navbar-collapse.in {
-  overflow-y: auto;
-}
-@media (min-width: 768px) {
-  .navbar-collapse {
-    width: auto;
-    border-top: 0;
-    box-shadow: none;
-  }
-  .navbar-collapse.collapse {
-    display: block !important;
-    height: auto !important;
-    padding-bottom: 0;
-    overflow: visible !important;
-  }
-  .navbar-collapse.in {
-    overflow-y: visible;
-  }
-  .navbar-fixed-top .navbar-collapse,
-  .navbar-static-top .navbar-collapse,
-  .navbar-fixed-bottom .navbar-collapse {
-    padding-right: 0;
-    padding-left: 0;
-  }
-}
-.container > .navbar-header,
-.container-fluid > .navbar-header,
-.container > .navbar-collapse,
-.container-fluid > .navbar-collapse {
-  margin-right: -15px;
-  margin-left: -15px;
-}
-@media (min-width: 768px) {
-  .container > .navbar-header,
-  .container-fluid > .navbar-header,
-  .container > .navbar-collapse,
-  .container-fluid > .navbar-collapse {
-    margin-right: 0;
-    margin-left: 0;
-  }
-}
-.navbar-static-top {
-  z-index: 1000;
-  border-width: 0 0 1px;
-}
-@media (min-width: 768px) {
-  .navbar-static-top {
-    border-radius: 0;
-  }
-}
-.navbar-fixed-top,
-.navbar-fixed-bottom {
-  position: fixed;
-  right: 0;
-  left: 0;
-  z-index: 1030;
-}
-@media (min-width: 768px) {
-  .navbar-fixed-top,
-  .navbar-fixed-bottom {
-    border-radius: 0;
-  }
-}
-.navbar-fixed-top {
-  top: 0;
-  border-width: 0 0 1px;
-}
-.navbar-fixed-bottom {
-  bottom: 0;
-  margin-bottom: 0;
-  border-width: 1px 0 0;
-}
-.navbar-brand {
-  float: left;
-  height: 50px;
-  padding: 15px 15px;
-  font-family: Comfortaa, "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 18px;
-  font-weight: bold;
-  line-height: 20px;
-}
-.navbar-brand:hover,
-.navbar-brand:focus {
-  text-decoration: none;
-}
-@media (min-width: 768px) {
-  .navbar > .container .navbar-brand,
-  .navbar > .container-fluid .navbar-brand {
-    margin-left: -15px;
-  }
-}
-.navbar-toggle {
-  position: relative;
-  float: right;
-  padding: 9px 10px;
-  margin-top: 8px;
-  margin-right: 15px;
-  margin-bottom: 8px;
-  background-color: transparent;
-  background-image: none;
-  border: 1px solid transparent;
-  border-radius: 4px;
-}
-.navbar-toggle:focus {
-  outline: none;
-}
-.navbar-toggle .icon-bar {
-  display: block;
-  width: 22px;
-  height: 2px;
-  border-radius: 1px;
-}
-.navbar-toggle .icon-bar + .icon-bar {
-  margin-top: 4px;
-}
-@media (min-width: 768px) {
-  .navbar-toggle {
-    display: none;
-  }
-}
-.navbar-nav {
-  margin: 7.5px -15px;
-}
-.navbar-nav > li > a {
-  padding-top: 10px;
-  padding-bottom: 10px;
-  line-height: 20px;
-}
-@media (max-width: 767px) {
-  .navbar-nav .open .dropdown-menu {
-    position: static;
-    float: none;
-    width: auto;
-    margin-top: 0;
-    background-color: transparent;
-    border: 0;
-    box-shadow: none;
-  }
-  .navbar-nav .open .dropdown-menu > li > a,
-  .navbar-nav .open .dropdown-menu .dropdown-header {
-    padding: 5px 15px 5px 25px;
-  }
-  .navbar-nav .open .dropdown-menu > li > a {
-    line-height: 20px;
-  }
-  .navbar-nav .open .dropdown-menu > li > a:hover,
-  .navbar-nav .open .dropdown-menu > li > a:focus {
-    background-image: none;
-  }
-}
-@media (min-width: 768px) {
-  .navbar-nav {
-    float: left;
-    margin: 0;
-  }
-  .navbar-nav > li {
-    float: left;
-  }
-  .navbar-nav > li > a {
-    padding-top: 15px;
-    padding-bottom: 15px;
-  }
-  .navbar-nav.navbar-right:last-child {
-    margin-right: -15px;
-  }
-}
-@media (min-width: 768px) {
-  .navbar-left {
-    float: left !important;
-  }
-  .navbar-right {
-    float: right !important;
-  }
-}
-.navbar-form {
-  padding: 10px 15px;
-  margin-top: 8px;
-  margin-right: -15px;
-  margin-bottom: 8px;
-  margin-left: -15px;
-  border-top: 1px solid transparent;
-  border-bottom: 1px solid transparent;
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
-}
-@media (min-width: 768px) {
-  .navbar-form .form-group {
-    display: inline-block;
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .navbar-form .form-control {
-    display: inline-block;
-    width: auto;
-    vertical-align: middle;
-  }
-  .navbar-form .input-group > .form-control {
-    width: 100%;
-  }
-  .navbar-form .control-label {
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .navbar-form .radio,
-  .navbar-form .checkbox {
-    display: inline-block;
-    padding-left: 0;
-    margin-top: 0;
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .navbar-form .radio input[type="radio"],
-  .navbar-form .checkbox input[type="checkbox"] {
-    float: none;
-    margin-left: 0;
-  }
-  .navbar-form .has-feedback .form-control-feedback {
-    top: 0;
-  }
-}
-@media (max-width: 767px) {
-  .navbar-form .form-group {
-    margin-bottom: 5px;
-  }
-}
-@media (min-width: 768px) {
-  .navbar-form {
-    width: auto;
-    padding-top: 0;
-    padding-bottom: 0;
-    margin-right: 0;
-    margin-left: 0;
-    border: 0;
-    -webkit-box-shadow: none;
-            box-shadow: none;
-  }
-  .navbar-form.navbar-right:last-child {
-    margin-right: -15px;
-  }
-}
-.navbar-nav > li > .dropdown-menu {
-  margin-top: 0;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.navbar-btn {
-  margin-top: 8px;
-  margin-bottom: 8px;
-}
-.navbar-btn.btn-sm {
-  margin-top: 10px;
-  margin-bottom: 10px;
-}
-.navbar-btn.btn-xs {
-  margin-top: 14px;
-  margin-bottom: 14px;
-}
-.navbar-text {
-  margin-top: 15px;
-  margin-bottom: 15px;
-}
-@media (min-width: 768px) {
-  .navbar-text {
-    float: left;
-    margin-right: 15px;
-    margin-left: 15px;
-  }
-  .navbar-text.navbar-right:last-child {
-    margin-right: 0;
-  }
-}
-.navbar-default {
-  background-color: #f8f8f8;
-  border-color: #e7e7e7;
-}
-.navbar-default .navbar-brand {
-  color: #777;
-}
-.navbar-default .navbar-brand:hover,
-.navbar-default .navbar-brand:focus {
-  color: #5e5e5e;
-  background-color: transparent;
-}
-.navbar-default .navbar-text {
-  color: #777;
-}
-.navbar-default .navbar-nav > li > a {
-  color: #777;
-}
-.navbar-default .navbar-nav > li > a:hover,
-.navbar-default .navbar-nav > li > a:focus {
-  color: #333;
-  background-color: transparent;
-}
-.navbar-default .navbar-nav > .active > a,
-.navbar-default .navbar-nav > .active > a:hover,
-.navbar-default .navbar-nav > .active > a:focus {
-  color: #db3279;
-  background-color: #e7e7e7;
-}
-.navbar-default .navbar-nav > .disabled > a,
-.navbar-default .navbar-nav > .disabled > a:hover,
-.navbar-default .navbar-nav > .disabled > a:focus {
-  color: #ccc;
-  background-color: transparent;
-}
-.navbar-default .navbar-toggle {
-  border-color: #ddd;
-}
-.navbar-default .navbar-toggle:hover,
-.navbar-default .navbar-toggle:focus {
-  background-color: #ddd;
-}
-.navbar-default .navbar-toggle .icon-bar {
-  background-color: #888;
-}
-.navbar-default .navbar-collapse,
-.navbar-default .navbar-form {
-  border-color: #e7e7e7;
-}
-.navbar-default .navbar-nav > .open > a,
-.navbar-default .navbar-nav > .open > a:hover,
-.navbar-default .navbar-nav > .open > a:focus {
-  color: #db3279;
-  background-color: #e7e7e7;
-}
-@media (max-width: 767px) {
-  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
-    color: #777;
-  }
-  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
-  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
-    color: #333;
-    background-color: transparent;
-  }
-  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
-  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
-  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
-    color: #db3279;
-    background-color: #e7e7e7;
-  }
-  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
-  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
-  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
-    color: #ccc;
-    background-color: transparent;
-  }
-}
-.navbar-default .navbar-link {
-  color: #777;
-}
-.navbar-default .navbar-link:hover {
-  color: #333;
-}
-.navbar-inverse {
-  background-color: #294172;
-  border-color: #1c2c4c;
-}
-.navbar-inverse .navbar-brand {
-  color: #999;
-}
-.navbar-inverse .navbar-brand:hover,
-.navbar-inverse .navbar-brand:focus {
-  color: #fff;
-  background-color: transparent;
-}
-.navbar-inverse .navbar-text {
-  color: #999;
-}
-.navbar-inverse .navbar-nav > li > a {
-  color: #999;
-}
-.navbar-inverse .navbar-nav > li > a:hover,
-.navbar-inverse .navbar-nav > li > a:focus {
-  color: #fff;
-  background-color: transparent;
-}
-.navbar-inverse .navbar-nav > .active > a,
-.navbar-inverse .navbar-nav > .active > a:hover,
-.navbar-inverse .navbar-nav > .active > a:focus {
-  color: #fff;
-  background-color: #1c2c4c;
-}
-.navbar-inverse .navbar-nav > .disabled > a,
-.navbar-inverse .navbar-nav > .disabled > a:hover,
-.navbar-inverse .navbar-nav > .disabled > a:focus {
-  color: #444;
-  background-color: transparent;
-}
-.navbar-inverse .navbar-toggle {
-  border-color: #333;
-}
-.navbar-inverse .navbar-toggle:hover,
-.navbar-inverse .navbar-toggle:focus {
-  background-color: #333;
-}
-.navbar-inverse .navbar-toggle .icon-bar {
-  background-color: #fff;
-}
-.navbar-inverse .navbar-collapse,
-.navbar-inverse .navbar-form {
-  border-color: #203258;
-}
-.navbar-inverse .navbar-nav > .open > a,
-.navbar-inverse .navbar-nav > .open > a:hover,
-.navbar-inverse .navbar-nav > .open > a:focus {
-  color: #fff;
-  background-color: #1c2c4c;
-}
-@media (max-width: 767px) {
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
-    border-color: #1c2c4c;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
-    background-color: #1c2c4c;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
-    color: #999;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
-    color: #fff;
-    background-color: transparent;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
-    color: #fff;
-    background-color: #1c2c4c;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
-    color: #444;
-    background-color: transparent;
-  }
-}
-.navbar-inverse .navbar-link {
-  color: #999;
-}
-.navbar-inverse .navbar-link:hover {
-  color: #fff;
-}
-.breadcrumb {
-  padding: 8px 15px;
-  margin-bottom: 20px;
-  list-style: none;
-  background-color: #f5f5f5;
-  border-radius: 4px;
-}
-.breadcrumb > li {
-  display: inline-block;
-}
-.breadcrumb > li + li:before {
-  padding: 0 5px;
-  color: #ccc;
-  content: "/\00a0";
-}
-.breadcrumb > .active {
-  color: #999;
-}
-.pagination {
-  display: inline-block;
-  padding-left: 0;
-  margin: 20px 0;
-  border-radius: 4px;
-}
-.pagination > li {
-  display: inline;
-}
-.pagination > li > a,
-.pagination > li > span {
-  position: relative;
-  float: left;
-  padding: 6px 12px;
-  margin-left: -1px;
-  line-height: 1.42857143;
-  color: #428bca;
-  text-decoration: none;
-  background-color: #fff;
-  border: 1px solid #ddd;
-}
-.pagination > li:first-child > a,
-.pagination > li:first-child > span {
-  margin-left: 0;
-  border-top-left-radius: 4px;
-  border-bottom-left-radius: 4px;
-}
-.pagination > li:last-child > a,
-.pagination > li:last-child > span {
-  border-top-right-radius: 4px;
-  border-bottom-right-radius: 4px;
-}
-.pagination > li > a:hover,
-.pagination > li > span:hover,
-.pagination > li > a:focus,
-.pagination > li > span:focus {
-  color: #2a6496;
-  background-color: #eee;
-  border-color: #ddd;
-}
-.pagination > .active > a,
-.pagination > .active > span,
-.pagination > .active > a:hover,
-.pagination > .active > span:hover,
-.pagination > .active > a:focus,
-.pagination > .active > span:focus {
-  z-index: 2;
-  color: #fff;
-  cursor: default;
-  background-color: #428bca;
-  border-color: #428bca;
-}
-.pagination > .disabled > span,
-.pagination > .disabled > span:hover,
-.pagination > .disabled > span:focus,
-.pagination > .disabled > a,
-.pagination > .disabled > a:hover,
-.pagination > .disabled > a:focus {
-  color: #999;
-  cursor: not-allowed;
-  background-color: #fff;
-  border-color: #ddd;
-}
-.pagination-lg > li > a,
-.pagination-lg > li > span {
-  padding: 10px 16px;
-  font-size: 18px;
-}
-.pagination-lg > li:first-child > a,
-.pagination-lg > li:first-child > span {
-  border-top-left-radius: 6px;
-  border-bottom-left-radius: 6px;
-}
-.pagination-lg > li:last-child > a,
-.pagination-lg > li:last-child > span {
-  border-top-right-radius: 6px;
-  border-bottom-right-radius: 6px;
-}
-.pagination-sm > li > a,
-.pagination-sm > li > span {
-  padding: 5px 10px;
-  font-size: 12px;
-}
-.pagination-sm > li:first-child > a,
-.pagination-sm > li:first-child > span {
-  border-top-left-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.pagination-sm > li:last-child > a,
-.pagination-sm > li:last-child > span {
-  border-top-right-radius: 3px;
-  border-bottom-right-radius: 3px;
-}
-.pager {
-  padding-left: 0;
-  margin: 20px 0;
-  text-align: center;
-  list-style: none;
-}
-.pager li {
-  display: inline;
-}
-.pager li > a,
-.pager li > span {
-  display: inline-block;
-  padding: 5px 14px;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-radius: 15px;
-}
-.pager li > a:hover,
-.pager li > a:focus {
-  text-decoration: none;
-  background-color: #eee;
-}
-.pager .next > a,
-.pager .next > span {
-  float: right;
-}
-.pager .previous > a,
-.pager .previous > span {
-  float: left;
-}
-.pager .disabled > a,
-.pager .disabled > a:hover,
-.pager .disabled > a:focus,
-.pager .disabled > span {
-  color: #999;
-  cursor: not-allowed;
-  background-color: #fff;
-}
-.label {
-  display: inline;
-  padding: .2em .6em .3em;
-  font-size: 75%;
-  font-weight: bold;
-  line-height: 1;
-  color: #fff;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: baseline;
-  border-radius: .25em;
-}
-.label[href]:hover,
-.label[href]:focus {
-  color: #fff;
-  text-decoration: none;
-  cursor: pointer;
-}
-.label:empty {
-  display: none;
-}
-.btn .label {
-  position: relative;
-  top: -1px;
-}
-.label-default {
-  background-color: #999;
-}
-.label-default[href]:hover,
-.label-default[href]:focus {
-  background-color: #808080;
-}
-.label-primary {
-  background-color: #428bca;
-}
-.label-primary[href]:hover,
-.label-primary[href]:focus {
-  background-color: #3071a9;
-}
-.label-success {
-  background-color: #79db32;
-}
-.label-success[href]:hover,
-.label-success[href]:focus {
-  background-color: #61b921;
-}
-.label-info {
-  background-color: #a07cbc;
-}
-.label-info[href]:hover,
-.label-info[href]:focus {
-  background-color: #885aab;
-}
-.label-warning {
-  background-color: #e59728;
-}
-.label-warning[href]:hover,
-.label-warning[href]:focus {
-  background-color: #c27c18;
-}
-.label-danger {
-  background-color: #db3279;
-}
-.label-danger[href]:hover,
-.label-danger[href]:focus {
-  background-color: #b92161;
-}
-.badge {
-  display: inline-block;
-  min-width: 10px;
-  padding: 3px 7px;
-  font-size: 12px;
-  font-weight: bold;
-  line-height: 1;
-  color: #fff;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: baseline;
-  background-color: #999;
-  border-radius: 10px;
-}
-.badge:empty {
-  display: none;
-}
-.btn .badge {
-  position: relative;
-  top: -1px;
-}
-.btn-xs .badge {
-  top: 0;
-  padding: 1px 5px;
-}
-a.badge:hover,
-a.badge:focus {
-  color: #fff;
-  text-decoration: none;
-  cursor: pointer;
-}
-a.list-group-item.active > .badge,
-.nav-pills > .active > a > .badge {
-  color: #428bca;
-  background-color: #fff;
-}
-.nav-pills > li > a > .badge {
-  margin-left: 3px;
-}
-.jumbotron {
-  padding: 30px;
-  margin-bottom: 30px;
-  color: inherit;
-  background-color: #eee;
-}
-.jumbotron h1,
-.jumbotron .h1 {
-  color: inherit;
-}
-.jumbotron p {
-  margin-bottom: 15px;
-  font-size: 21px;
-  font-weight: 200;
-}
-.container .jumbotron {
-  border-radius: 6px;
-}
-.jumbotron .container {
-  max-width: 100%;
-}
-@media screen and (min-width: 768px) {
-  .jumbotron {
-    padding-top: 48px;
-    padding-bottom: 48px;
-  }
-  .container .jumbotron {
-    padding-right: 60px;
-    padding-left: 60px;
-  }
-  .jumbotron h1,
-  .jumbotron .h1 {
-    font-size: 63px;
-  }
-}
-.thumbnail {
-  display: block;
-  padding: 4px;
-  margin-bottom: 20px;
-  line-height: 1.42857143;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  -webkit-transition: all .2s ease-in-out;
-          transition: all .2s ease-in-out;
-}
-.thumbnail > img,
-.thumbnail a > img {
-  margin-right: auto;
-  margin-left: auto;
-}
-a.thumbnail:hover,
-a.thumbnail:focus,
-a.thumbnail.active {
-  border-color: #428bca;
-}
-.thumbnail .caption {
-  padding: 9px;
-  color: #333;
-}
-.alert {
-  padding: 15px;
-  margin-bottom: 20px;
-  border: 1px solid transparent;
-  border-radius: 4px;
-}
-.alert h4 {
-  margin-top: 0;
-  color: inherit;
-}
-.alert .alert-link {
-  font-weight: bold;
-}
-.alert > p,
-.alert > ul {
-  margin-bottom: 0;
-}
-.alert > p + p {
-  margin-top: 5px;
-}
-.alert-dismissable {
-  padding-right: 35px;
-}
-.alert-dismissable .close {
-  position: relative;
-  top: -2px;
-  right: -21px;
-  color: inherit;
-}
-.alert-success {
-  color: #3f7815;
-  background-color: #dcf6ca;
-  border-color: #d8f2b4;
-}
-.alert-success hr {
-  border-top-color: #cdee9e;
-}
-.alert-success .alert-link {
-  color: #284d0e;
-}
-.alert-info {
-  color: #603e7a;
-  background-color: #f6f2f8;
-  border-color: #e7e1f0;
-}
-.alert-info hr {
-  border-top-color: #d9d0e7;
-}
-.alert-info .alert-link {
-  color: #452d58;
-}
-.alert-warning {
-  color: #7e500f;
-  background-color: #f8e4c7;
-  border-color: #f6ceb0;
-}
-.alert-warning hr {
-  border-top-color: #f3bf9a;
-}
-.alert-warning .alert-link {
-  color: #51330a;
-}
-.alert-danger {
-  color: #78153f;
-  background-color: #f6cadc;
-  border-color: #f2b4d8;
-}
-.alert-danger hr {
-  border-top-color: #ee9ecd;
-}
-.alert-danger .alert-link {
-  color: #4d0e28;
-}
-@-webkit-keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-@keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-.progress {
-  height: 20px;
-  margin-bottom: 20px;
-  overflow: hidden;
-  background-color: #f5f5f5;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
-          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
-}
-.progress-bar {
-  float: left;
-  width: 0;
-  height: 100%;
-  font-size: 12px;
-  line-height: 20px;
-  color: #fff;
-  text-align: center;
-  background-color: #428bca;
-  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
-          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
-  -webkit-transition: width .6s ease;
-          transition: width .6s ease;
-}
-.progress-striped .progress-bar {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-size: 40px 40px;
-}
-.progress.active .progress-bar {
-  -webkit-animation: progress-bar-stripes 2s linear infinite;
-          animation: progress-bar-stripes 2s linear infinite;
-}
-.progress-bar-success {
-  background-color: #79db32;
-}
-.progress-striped .progress-bar-success {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.progress-bar-info {
-  background-color: #a07cbc;
-}
-.progress-striped .progress-bar-info {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.progress-bar-warning {
-  background-color: #e59728;
-}
-.progress-striped .progress-bar-warning {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.progress-bar-danger {
-  background-color: #db3279;
-}
-.progress-striped .progress-bar-danger {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.media,
-.media-body {
-  overflow: hidden;
-  zoom: 1;
-}
-.media,
-.media .media {
-  margin-top: 15px;
-}
-.media:first-child {
-  margin-top: 0;
-}
-.media-object {
-  display: block;
-}
-.media-heading {
-  margin: 0 0 5px;
-}
-.media > .pull-left {
-  margin-right: 10px;
-}
-.media > .pull-right {
-  margin-left: 10px;
-}
-.media-list {
-  padding-left: 0;
-  list-style: none;
-}
-.list-group {
-  padding-left: 0;
-  margin-bottom: 20px;
-}
-.list-group-item {
-  position: relative;
-  display: block;
-  padding: 10px 15px;
-  margin-bottom: -1px;
-  background-color: #fff;
-  border: 1px solid #ddd;
-}
-.list-group-item:first-child {
-  border-top-left-radius: 4px;
-  border-top-right-radius: 4px;
-}
-.list-group-item:last-child {
-  margin-bottom: 0;
-  border-bottom-right-radius: 4px;
-  border-bottom-left-radius: 4px;
-}
-.list-group-item > .badge {
-  float: right;
-}
-.list-group-item > .badge + .badge {
-  margin-right: 5px;
-}
-a.list-group-item {
-  color: #555;
-}
-a.list-group-item .list-group-item-heading {
-  color: #333;
-}
-a.list-group-item:hover,
-a.list-group-item:focus {
-  text-decoration: none;
-  background-color: #f5f5f5;
-}
-a.list-group-item.active,
-a.list-group-item.active:hover,
-a.list-group-item.active:focus {
-  z-index: 2;
-  color: #fff;
-  background-color: #428bca;
-  border-color: #428bca;
-}
-a.list-group-item.active .list-group-item-heading,
-a.list-group-item.active:hover .list-group-item-heading,
-a.list-group-item.active:focus .list-group-item-heading {
-  color: inherit;
-}
-a.list-group-item.active .list-group-item-text,
-a.list-group-item.active:hover .list-group-item-text,
-a.list-group-item.active:focus .list-group-item-text {
-  color: #e1edf7;
-}
-.list-group-item-success {
-  color: #3f7815;
-  background-color: #dcf6ca;
-}
-a.list-group-item-success {
-  color: #3f7815;
-}
-a.list-group-item-success .list-group-item-heading {
-  color: inherit;
-}
-a.list-group-item-success:hover,
-a.list-group-item-success:focus {
-  color: #3f7815;
-  background-color: #cef2b4;
-}
-a.list-group-item-success.active,
-a.list-group-item-success.active:hover,
-a.list-group-item-success.active:focus {
-  color: #fff;
-  background-color: #3f7815;
-  border-color: #3f7815;
-}
-.list-group-item-info {
-  color: #603e7a;
-  background-color: #f6f2f8;
-}
-a.list-group-item-info {
-  color: #603e7a;
-}
-a.list-group-item-info .list-group-item-heading {
-  color: inherit;
-}
-a.list-group-item-info:hover,
-a.list-group-item-info:focus {
-  color: #603e7a;
-  background-color: #e9e1f0;
-}
-a.list-group-item-info.active,
-a.list-group-item-info.active:hover,
-a.list-group-item-info.active:focus {
-  color: #fff;
-  background-color: #603e7a;
-  border-color: #603e7a;
-}
-.list-group-item-warning {
-  color: #7e500f;
-  background-color: #f8e4c7;
-}
-a.list-group-item-warning {
-  color: #7e500f;
-}
-a.list-group-item-warning .list-group-item-heading {
-  color: inherit;
-}
-a.list-group-item-warning:hover,
-a.list-group-item-warning:focus {
-  color: #7e500f;
-  background-color: #f6d9b0;
-}
-a.list-group-item-warning.active,
-a.list-group-item-warning.active:hover,
-a.list-group-item-warning.active:focus {
-  color: #fff;
-  background-color: #7e500f;
-  border-color: #7e500f;
-}
-.list-group-item-danger {
-  color: #78153f;
-  background-color: #f6cadc;
-}
-a.list-group-item-danger {
-  color: #78153f;
-}
-a.list-group-item-danger .list-group-item-heading {
-  color: inherit;
-}
-a.list-group-item-danger:hover,
-a.list-group-item-danger:focus {
-  color: #78153f;
-  background-color: #f2b4ce;
-}
-a.list-group-item-danger.active,
-a.list-group-item-danger.active:hover,
-a.list-group-item-danger.active:focus {
-  color: #fff;
-  background-color: #78153f;
-  border-color: #78153f;
-}
-.list-group-item-heading {
-  margin-top: 0;
-  margin-bottom: 5px;
-}
-.list-group-item-text {
-  margin-bottom: 0;
-  line-height: 1.3;
-}
-.panel {
-  margin-bottom: 20px;
-  background-color: #fff;
-  border: 1px solid transparent;
-  border-radius: 4px;
-  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
-          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
-}
-.panel-body {
-  padding: 15px;
-}
-.panel-heading {
-  padding: 10px 15px;
-  border-bottom: 1px solid transparent;
-  border-top-left-radius: 3px;
-  border-top-right-radius: 3px;
-}
-.panel-heading > .dropdown .dropdown-toggle {
-  color: inherit;
-}
-.panel-title {
-  margin-top: 0;
-  margin-bottom: 0;
-  font-size: 16px;
-  color: inherit;
-}
-.panel-title > a {
-  color: inherit;
-}
-.panel-footer {
-  padding: 10px 15px;
-  background-color: #f5f5f5;
-  border-top: 1px solid #ddd;
-  border-bottom-right-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.panel > .list-group {
-  margin-bottom: 0;
-}
-.panel > .list-group .list-group-item {
-  border-width: 1px 0;
-  border-radius: 0;
-}
-.panel > .list-group:first-child .list-group-item:first-child {
-  border-top: 0;
-  border-top-left-radius: 3px;
-  border-top-right-radius: 3px;
-}
-.panel > .list-group:last-child .list-group-item:last-child {
-  border-bottom: 0;
-  border-bottom-right-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.panel-heading + .list-group .list-group-item:first-child {
-  border-top-width: 0;
-}
-.panel > .table,
-.panel > .table-responsive > .table {
-  margin-bottom: 0;
-}
-.panel > .table:first-child,
-.panel > .table-responsive:first-child > .table:first-child {
-  border-top-left-radius: 3px;
-  border-top-right-radius: 3px;
-}
-.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
-.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
-.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
-.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
-.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
-.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
-.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
-.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
-  border-top-left-radius: 3px;
-}
-.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
-.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
-.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
-.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
-.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
-.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
-.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
-.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
-  border-top-right-radius: 3px;
-}
-.panel > .table:last-child,
-.panel > .table-responsive:last-child > .table:last-child {
-  border-bottom-right-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
-.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
-.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
-.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
-.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
-.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
-.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
-.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
-  border-bottom-left-radius: 3px;
-}
-.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
-.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
-.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
-.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
-  border-bottom-right-radius: 3px;
-}
-.panel > .panel-body + .table,
-.panel > .panel-body + .table-responsive {
-  border-top: 1px solid #ddd;
-}
-.panel > .table > tbody:first-child > tr:first-child th,
-.panel > .table > tbody:first-child > tr:first-child td {
-  border-top: 0;
-}
-.panel > .table-bordered,
-.panel > .table-responsive > .table-bordered {
-  border: 0;
-}
-.panel > .table-bordered > thead > tr > th:first-child,
-.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
-.panel > .table-bordered > tbody > tr > th:first-child,
-.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
-.panel > .table-bordered > tfoot > tr > th:first-child,
-.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
-.panel > .table-bordered > thead > tr > td:first-child,
-.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
-.panel > .table-bordered > tbody > tr > td:first-child,
-.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
-.panel > .table-bordered > tfoot > tr > td:first-child,
-.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
-  border-left: 0;
-}
-.panel > .table-bordered > thead > tr > th:last-child,
-.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
-.panel > .table-bordered > tbody > tr > th:last-child,
-.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
-.panel > .table-bordered > tfoot > tr > th:last-child,
-.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
-.panel > .table-bordered > thead > tr > td:last-child,
-.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
-.panel > .table-bordered > tbody > tr > td:last-child,
-.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
-.panel > .table-bordered > tfoot > tr > td:last-child,
-.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
-  border-right: 0;
-}
-.panel > .table-bordered > thead > tr:first-child > td,
-.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
-.panel > .table-bordered > tbody > tr:first-child > td,
-.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
-.panel > .table-bordered > thead > tr:first-child > th,
-.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
-.panel > .table-bordered > tbody > tr:first-child > th,
-.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
-  border-bottom: 0;
-}
-.panel > .table-bordered > tbody > tr:last-child > td,
-.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
-.panel > .table-bordered > tfoot > tr:last-child > td,
-.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
-.panel > .table-bordered > tbody > tr:last-child > th,
-.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
-.panel > .table-bordered > tfoot > tr:last-child > th,
-.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
-  border-bottom: 0;
-}
-.panel > .table-responsive {
-  margin-bottom: 0;
-  border: 0;
-}
-.panel-group {
-  margin-bottom: 20px;
-}
-.panel-group .panel {
-  margin-bottom: 0;
-  overflow: hidden;
-  border-radius: 4px;
-}
-.panel-group .panel + .panel {
-  margin-top: 5px;
-}
-.panel-group .panel-heading {
-  border-bottom: 0;
-}
-.panel-group .panel-heading + .panel-collapse .panel-body {
-  border-top: 1px solid #ddd;
-}
-.panel-group .panel-footer {
-  border-top: 0;
-}
-.panel-group .panel-footer + .panel-collapse .panel-body {
-  border-bottom: 1px solid #ddd;
-}
-.panel-default {
-  border-color: #ddd;
-}
-.panel-default > .panel-heading {
-  color: #333;
-  background-color: #f5f5f5;
-  border-color: #ddd;
-}
-.panel-default > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #ddd;
-}
-.panel-default > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #ddd;
-}
-.panel-primary {
-  border-color: #428bca;
-}
-.panel-primary > .panel-heading {
-  color: #fff;
-  background-color: #428bca;
-  border-color: #428bca;
-}
-.panel-primary > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #428bca;
-}
-.panel-primary > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #428bca;
-}
-.panel-success {
-  border-color: #d8f2b4;
-}
-.panel-success > .panel-heading {
-  color: #3f7815;
-  background-color: #dcf6ca;
-  border-color: #d8f2b4;
-}
-.panel-success > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #d8f2b4;
-}
-.panel-success > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #d8f2b4;
-}
-.panel-info {
-  border-color: #e7e1f0;
-}
-.panel-info > .panel-heading {
-  color: #603e7a;
-  background-color: #f6f2f8;
-  border-color: #e7e1f0;
-}
-.panel-info > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #e7e1f0;
-}
-.panel-info > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #e7e1f0;
-}
-.panel-warning {
-  border-color: #f6ceb0;
-}
-.panel-warning > .panel-heading {
-  color: #7e500f;
-  background-color: #f8e4c7;
-  border-color: #f6ceb0;
-}
-.panel-warning > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #f6ceb0;
-}
-.panel-warning > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #f6ceb0;
-}
-.panel-danger {
-  border-color: #f2b4d8;
-}
-.panel-danger > .panel-heading {
-  color: #78153f;
-  background-color: #f6cadc;
-  border-color: #f2b4d8;
-}
-.panel-danger > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #f2b4d8;
-}
-.panel-danger > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #f2b4d8;
-}
-.well {
-  min-height: 20px;
-  padding: 19px;
-  margin-bottom: 20px;
-  background-color: #f5f5f5;
-  border: 1px solid #e3e3e3;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
-}
-.well blockquote {
-  border-color: #ddd;
-  border-color: rgba(0, 0, 0, .15);
-}
-.well-lg {
-  padding: 24px;
-  border-radius: 6px;
-}
-.well-sm {
-  padding: 9px;
-  border-radius: 3px;
-}
-.close {
-  float: right;
-  font-size: 21px;
-  font-weight: bold;
-  line-height: 1;
-  color: #000;
-  text-shadow: 0 1px 0 #fff;
-  filter: alpha(opacity=20);
-  opacity: .2;
-}
-.close:hover,
-.close:focus {
-  color: #000;
-  text-decoration: none;
-  cursor: pointer;
-  filter: alpha(opacity=50);
-  opacity: .5;
-}
-button.close {
-  -webkit-appearance: none;
-  padding: 0;
-  cursor: pointer;
-  background: transparent;
-  border: 0;
-}
-.modal-open {
-  overflow: hidden;
-}
-.modal {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 1050;
-  display: none;
-  overflow: auto;
-  overflow-y: scroll;
-  -webkit-overflow-scrolling: touch;
-  outline: 0;
-}
-.modal.fade .modal-dialog {
-  -webkit-transition: -webkit-transform .3s ease-out;
-     -moz-transition:    -moz-transform .3s ease-out;
-       -o-transition:      -o-transform .3s ease-out;
-          transition:         transform .3s ease-out;
-  -webkit-transform: translate(0, -25%);
-      -ms-transform: translate(0, -25%);
-          transform: translate(0, -25%);
-}
-.modal.in .modal-dialog {
-  -webkit-transform: translate(0, 0);
-      -ms-transform: translate(0, 0);
-          transform: translate(0, 0);
-}
-.modal-dialog {
-  position: relative;
-  width: auto;
-  margin: 10px;
-}
-.modal-content {
-  position: relative;
-  background-color: #fff;
-  background-clip: padding-box;
-  border: 1px solid #999;
-  border: 1px solid rgba(0, 0, 0, .2);
-  border-radius: 6px;
-  outline: none;
-  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
-          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
-}
-.modal-backdrop {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 1040;
-  background-color: #000;
-}
-.modal-backdrop.fade {
-  filter: alpha(opacity=0);
-  opacity: 0;
-}
-.modal-backdrop.in {
-  filter: alpha(opacity=50);
-  opacity: .5;
-}
-.modal-header {
-  min-height: 16.42857143px;
-  padding: 15px;
-  border-bottom: 1px solid #e5e5e5;
-}
-.modal-header .close {
-  margin-top: -2px;
-}
-.modal-title {
-  margin: 0;
-  line-height: 1.42857143;
-}
-.modal-body {
-  position: relative;
-  padding: 20px;
-}
-.modal-footer {
-  padding: 19px 20px 20px;
-  margin-top: 15px;
-  text-align: right;
-  border-top: 1px solid #e5e5e5;
-}
-.modal-footer .btn + .btn {
-  margin-bottom: 0;
-  margin-left: 5px;
-}
-.modal-footer .btn-group .btn + .btn {
-  margin-left: -1px;
-}
-.modal-footer .btn-block + .btn-block {
-  margin-left: 0;
-}
-@media (min-width: 768px) {
-  .modal-dialog {
-    width: 600px;
-    margin: 30px auto;
-  }
-  .modal-content {
-    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
-            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
-  }
-  .modal-sm {
-    width: 300px;
-  }
-}
-@media (min-width: 992px) {
-  .modal-lg {
-    width: 900px;
-  }
-}
-.tooltip {
-  position: absolute;
-  z-index: 1030;
-  display: block;
-  font-size: 12px;
-  line-height: 1.4;
-  visibility: visible;
-  filter: alpha(opacity=0);
-  opacity: 0;
-}
-.tooltip.in {
-  filter: alpha(opacity=90);
-  opacity: .9;
-}
-.tooltip.top {
-  padding: 5px 0;
-  margin-top: -3px;
-}
-.tooltip.right {
-  padding: 0 5px;
-  margin-left: 3px;
-}
-.tooltip.bottom {
-  padding: 5px 0;
-  margin-top: 3px;
-}
-.tooltip.left {
-  padding: 0 5px;
-  margin-left: -3px;
-}
-.tooltip-inner {
-  max-width: 200px;
-  padding: 3px 8px;
-  color: #fff;
-  text-align: center;
-  text-decoration: none;
-  background-color: #000;
-  border-radius: 4px;
-}
-.tooltip-arrow {
-  position: absolute;
-  width: 0;
-  height: 0;
-  border-color: transparent;
-  border-style: solid;
-}
-.tooltip.top .tooltip-arrow {
-  bottom: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-width: 5px 5px 0;
-  border-top-color: #000;
-}
-.tooltip.top-left .tooltip-arrow {
-  bottom: 0;
-  left: 5px;
-  border-width: 5px 5px 0;
-  border-top-color: #000;
-}
-.tooltip.top-right .tooltip-arrow {
-  right: 5px;
-  bottom: 0;
-  border-width: 5px 5px 0;
-  border-top-color: #000;
-}
-.tooltip.right .tooltip-arrow {
-  top: 50%;
-  left: 0;
-  margin-top: -5px;
-  border-width: 5px 5px 5px 0;
-  border-right-color: #000;
-}
-.tooltip.left .tooltip-arrow {
-  top: 50%;
-  right: 0;
-  margin-top: -5px;
-  border-width: 5px 0 5px 5px;
-  border-left-color: #000;
-}
-.tooltip.bottom .tooltip-arrow {
-  top: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-width: 0 5px 5px;
-  border-bottom-color: #000;
-}
-.tooltip.bottom-left .tooltip-arrow {
-  top: 0;
-  left: 5px;
-  border-width: 0 5px 5px;
-  border-bottom-color: #000;
-}
-.tooltip.bottom-right .tooltip-arrow {
-  top: 0;
-  right: 5px;
-  border-width: 0 5px 5px;
-  border-bottom-color: #000;
-}
-.popover {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1010;
-  display: none;
-  max-width: 276px;
-  padding: 1px;
-  text-align: left;
-  white-space: normal;
-  background-color: #fff;
-  background-clip: padding-box;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, .2);
-  border-radius: 6px;
-  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
-          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
-}
-.popover.top {
-  margin-top: -10px;
-}
-.popover.right {
-  margin-left: 10px;
-}
-.popover.bottom {
-  margin-top: 10px;
-}
-.popover.left {
-  margin-left: -10px;
-}
-.popover-title {
-  padding: 8px 14px;
-  margin: 0;
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 18px;
-  background-color: #f7f7f7;
-  border-bottom: 1px solid #ebebeb;
-  border-radius: 5px 5px 0 0;
-}
-.popover-content {
-  padding: 9px 14px;
-}
-.popover > .arrow,
-.popover > .arrow:after {
-  position: absolute;
-  display: block;
-  width: 0;
-  height: 0;
-  border-color: transparent;
-  border-style: solid;
-}
-.popover > .arrow {
-  border-width: 11px;
-}
-.popover > .arrow:after {
-  content: "";
-  border-width: 10px;
-}
-.popover.top > .arrow {
-  bottom: -11px;
-  left: 50%;
-  margin-left: -11px;
-  border-top-color: #999;
-  border-top-color: rgba(0, 0, 0, .25);
-  border-bottom-width: 0;
-}
-.popover.top > .arrow:after {
-  bottom: 1px;
-  margin-left: -10px;
-  content: " ";
-  border-top-color: #fff;
-  border-bottom-width: 0;
-}
-.popover.right > .arrow {
-  top: 50%;
-  left: -11px;
-  margin-top: -11px;
-  border-right-color: #999;
-  border-right-color: rgba(0, 0, 0, .25);
-  border-left-width: 0;
-}
-.popover.right > .arrow:after {
-  bottom: -10px;
-  left: 1px;
-  content: " ";
-  border-right-color: #fff;
-  border-left-width: 0;
-}
-.popover.bottom > .arrow {
-  top: -11px;
-  left: 50%;
-  margin-left: -11px;
-  border-top-width: 0;
-  border-bottom-color: #999;
-  border-bottom-color: rgba(0, 0, 0, .25);
-}
-.popover.bottom > .arrow:after {
-  top: 1px;
-  margin-left: -10px;
-  content: " ";
-  border-top-width: 0;
-  border-bottom-color: #fff;
-}
-.popover.left > .arrow {
-  top: 50%;
-  right: -11px;
-  margin-top: -11px;
-  border-right-width: 0;
-  border-left-color: #999;
-  border-left-color: rgba(0, 0, 0, .25);
-}
-.popover.left > .arrow:after {
-  right: 1px;
-  bottom: -10px;
-  content: " ";
-  border-right-width: 0;
-  border-left-color: #fff;
-}
-.carousel {
-  position: relative;
-}
-.carousel-inner {
-  position: relative;
-  width: 100%;
-  overflow: hidden;
-}
-.carousel-inner > .item {
-  position: relative;
-  display: none;
-  -webkit-transition: .6s ease-in-out left;
-          transition: .6s ease-in-out left;
-}
-.carousel-inner > .item > img,
-.carousel-inner > .item > a > img {
-  line-height: 1;
-}
-.carousel-inner > .active,
-.carousel-inner > .next,
-.carousel-inner > .prev {
-  display: block;
-}
-.carousel-inner > .active {
-  left: 0;
-}
-.carousel-inner > .next,
-.carousel-inner > .prev {
-  position: absolute;
-  top: 0;
-  width: 100%;
-}
-.carousel-inner > .next {
-  left: 100%;
-}
-.carousel-inner > .prev {
-  left: -100%;
-}
-.carousel-inner > .next.left,
-.carousel-inner > .prev.right {
-  left: 0;
-}
-.carousel-inner > .active.left {
-  left: -100%;
-}
-.carousel-inner > .active.right {
-  left: 100%;
-}
-.carousel-control {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  left: 0;
-  width: 15%;
-  font-size: 20px;
-  color: #fff;
-  text-align: center;
-  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
-  filter: alpha(opacity=50);
-  opacity: .5;
-}
-.carousel-control.left {
-  background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, .5) 0%), color-stop(rgba(0, 0, 0, .0001) 100%));
-  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
-  background-repeat: repeat-x;
-}
-.carousel-control.right {
-  right: 0;
-  left: auto;
-  background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, .0001) 0%), color-stop(rgba(0, 0, 0, .5) 100%));
-  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
-  background-repeat: repeat-x;
-}
-.carousel-control:hover,
-.carousel-control:focus {
-  color: #fff;
-  text-decoration: none;
-  filter: alpha(opacity=90);
-  outline: none;
-  opacity: .9;
-}
-.carousel-control .icon-prev,
-.carousel-control .icon-next,
-.carousel-control .glyphicon-chevron-left,
-.carousel-control .glyphicon-chevron-right {
-  position: absolute;
-  top: 50%;
-  z-index: 5;
-  display: inline-block;
-}
-.carousel-control .icon-prev,
-.carousel-control .glyphicon-chevron-left {
-  left: 50%;
-}
-.carousel-control .icon-next,
-.carousel-control .glyphicon-chevron-right {
-  right: 50%;
-}
-.carousel-control .icon-prev,
-.carousel-control .icon-next {
-  width: 20px;
-  height: 20px;
-  margin-top: -10px;
-  margin-left: -10px;
-  font-family: serif;
-}
-.carousel-control .icon-prev:before {
-  content: '\2039';
-}
-.carousel-control .icon-next:before {
-  content: '\203a';
-}
-.carousel-indicators {
-  position: absolute;
-  bottom: 10px;
-  left: 50%;
-  z-index: 15;
-  width: 60%;
-  padding-left: 0;
-  margin-left: -30%;
-  text-align: center;
-  list-style: none;
-}
-.carousel-indicators li {
-  display: inline-block;
-  width: 10px;
-  height: 10px;
-  margin: 1px;
-  text-indent: -999px;
-  cursor: pointer;
-  background-color: #000 \9;
-  background-color: rgba(0, 0, 0, 0);
-  border: 1px solid #fff;
-  border-radius: 10px;
-}
-.carousel-indicators .active {
-  width: 12px;
-  height: 12px;
-  margin: 0;
-  background-color: #fff;
-}
-.carousel-caption {
-  position: absolute;
-  right: 15%;
-  bottom: 20px;
-  left: 15%;
-  z-index: 10;
-  padding-top: 20px;
-  padding-bottom: 20px;
-  color: #fff;
-  text-align: center;
-  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
-}
-.carousel-caption .btn {
-  text-shadow: none;
-}
-@media screen and (min-width: 768px) {
-  .carousel-control .glyphicon-chevron-left,
-  .carousel-control .glyphicon-chevron-right,
-  .carousel-control .icon-prev,
-  .carousel-control .icon-next {
-    width: 30px;
-    height: 30px;
-    margin-top: -15px;
-    margin-left: -15px;
-    font-size: 30px;
-  }
-  .carousel-caption {
-    right: 20%;
-    left: 20%;
-    padding-bottom: 30px;
-  }
-  .carousel-indicators {
-    bottom: 20px;
-  }
-}
-.clearfix:before,
-.clearfix:after,
-.container:before,
-.container:after,
-.container-fluid:before,
-.container-fluid:after,
-.row:before,
-.row:after,
-.form-horizontal .form-group:before,
-.form-horizontal .form-group:after,
-.btn-toolbar:before,
-.btn-toolbar:after,
-.btn-group-vertical > .btn-group:before,
-.btn-group-vertical > .btn-group:after,
-.nav:before,
-.nav:after,
-.navbar:before,
-.navbar:after,
-.navbar-header:before,
-.navbar-header:after,
-.navbar-collapse:before,
-.navbar-collapse:after,
-.pager:before,
-.pager:after,
-.panel-body:before,
-.panel-body:after,
-.modal-footer:before,
-.modal-footer:after {
-  display: table;
-  content: " ";
-}
-.clearfix:after,
-.container:after,
-.container-fluid:after,
-.row:after,
-.form-horizontal .form-group:after,
-.btn-toolbar:after,
-.btn-group-vertical > .btn-group:after,
-.nav:after,
-.navbar:after,
-.navbar-header:after,
-.navbar-collapse:after,
-.pager:after,
-.panel-body:after,
-.modal-footer:after {
-  clear: both;
-}
-.center-block {
-  display: block;
-  margin-right: auto;
-  margin-left: auto;
-}
-.pull-right {
-  float: right !important;
-}
-.pull-left {
-  float: left !important;
-}
-.hide {
-  display: none !important;
-}
-.show {
-  display: block !important;
-}
-.invisible {
-  visibility: hidden;
-}
-.text-hide {
-  font: 0/0 a;
-  color: transparent;
-  text-shadow: none;
-  background-color: transparent;
-  border: 0;
-}
-.hidden {
-  display: none !important;
-  visibility: hidden !important;
-}
-.affix {
-  position: fixed;
-}
-@-ms-viewport {
-  width: device-width;
-}
-.visible-xs,
-.visible-sm,
-.visible-md,
-.visible-lg {
-  display: none !important;
-}
-@media (max-width: 767px) {
-  .visible-xs {
-    display: block !important;
-  }
-  table.visible-xs {
-    display: table;
-  }
-  tr.visible-xs {
-    display: table-row !important;
-  }
-  th.visible-xs,
-  td.visible-xs {
-    display: table-cell !important;
-  }
-}
-@media (min-width: 768px) and (max-width: 991px) {
-  .visible-sm {
-    display: block !important;
-  }
-  table.visible-sm {
-    display: table;
-  }
-  tr.visible-sm {
-    display: table-row !important;
-  }
-  th.visible-sm,
-  td.visible-sm {
-    display: table-cell !important;
-  }
-}
-@media (min-width: 992px) and (max-width: 1199px) {
-  .visible-md {
-    display: block !important;
-  }
-  table.visible-md {
-    display: table;
-  }
-  tr.visible-md {
-    display: table-row !important;
-  }
-  th.visible-md,
-  td.visible-md {
-    display: table-cell !important;
-  }
-}
-@media (min-width: 1200px) {
-  .visible-lg {
-    display: block !important;
-  }
-  table.visible-lg {
-    display: table;
-  }
-  tr.visible-lg {
-    display: table-row !important;
-  }
-  th.visible-lg,
-  td.visible-lg {
-    display: table-cell !important;
-  }
-}
-@media (max-width: 767px) {
-  .hidden-xs {
-    display: none !important;
-  }
-}
-@media (min-width: 768px) and (max-width: 991px) {
-  .hidden-sm {
-    display: none !important;
-  }
-}
-@media (min-width: 992px) and (max-width: 1199px) {
-  .hidden-md {
-    display: none !important;
-  }
-}
-@media (min-width: 1200px) {
-  .hidden-lg {
-    display: none !important;
-  }
-}
-.visible-print {
-  display: none !important;
-}
-@media print {
-  .visible-print {
-    display: block !important;
-  }
-  table.visible-print {
-    display: table;
-  }
-  tr.visible-print {
-    display: table-row !important;
-  }
-  th.visible-print,
-  td.visible-print {
-    display: table-cell !important;
-  }
-}
-@media print {
-  .hidden-print {
-    display: none !important;
-  }
-}
-/*# sourceMappingURL=bootstrap.css.map */
diff --git a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap.css.map b/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap.css.map
deleted file mode 100644
index 5368918..0000000
--- a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["less/normalize.less","less/print.less","less/scaffolding.less","less/mixins.less","less/variables.less","less/thumbnails.less","less/carousel.less","less/type.less","less/code.less","less/grid.less","less/tables.less","less/forms.less","less/buttons.less","less/button-groups.less","less/component-animations.less","less/glyphicons.less","less/dropdowns.less","less/input-groups.less","less/navs.less","less/navbar.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/pager.less","less/labels.less","less/badges.less","less/jumbotron.less","less/alerts.less","less/progress-bars.less","less/media.less","less/list-group.less","less/panels.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/popovers.less","less/responsive-utilities.less"],"names":[],"mappings":"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","sourcesContent":["/*! normalize.css v3.0.0 | MIT License | git.io/normalize */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS text size adjust after orientation change, without disabling\n//    user zoom.\n//\n\nhtml {\n  font-family: sans-serif; // 1\n  -ms-text-size-adjust: 100%; // 2\n  -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n  margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined in IE 8/9.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; // 1\n  vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9.\n// Hide the `template` element in IE, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n  background: transparent;\n}\n\n//\n// Improve readability when focused and also mouse hovered in all browsers.\n//\n\na:active,\na:hover {\n  outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9, Safari 5, and Chrome.\n//\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.\n//\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n//\n// Address styling not present in Safari 5 and Chrome.\n//\n\ndfn {\n  font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari 5, and Chrome.\n//\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n  font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9.\n//\n\nimg {\n  border: 0;\n}\n\n//\n// Correct overflow displayed oddly in IE 9.\n//\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari 5.\n//\n\nfigure {\n  margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n  overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n//    Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; // 1\n  font: inherit; // 2\n  margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10.\n//\n\nbutton {\n  overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8+, and Opera\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n//    and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n//    `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; // 2\n  cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n  line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; // 1\n  padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome\n//    (include `-moz` to future-proof).\n//\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; // 1\n  -moz-box-sizing: content-box;\n  -webkit-box-sizing: content-box; // 2\n  box-sizing: content-box;\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n  border: 0; // 1\n  padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9.\n//\n\ntextarea {\n  overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n  font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}","//\n// Basic print styles\n// --------------------------------------------------\n// Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css\n\n@media print {\n\n  * {\n    text-shadow: none !important;\n    color: #000 !important; // Black prints faster: h5bp.com/s\n    background: transparent !important;\n    box-shadow: none !important;\n  }\n\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n\n  // Don't show links for images, or javascript/internal links\n  a[href^=\"javascript:\"]:after,\n  a[href^=\"#\"]:after {\n    content: \"\";\n  }\n\n  pre,\n  blockquote {\n    border: 1px solid #999;\n    page-break-inside: avoid;\n  }\n\n  thead {\n    display: table-header-group; // h5bp.com/t\n  }\n\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n\n  img {\n    max-width: 100% !important;\n  }\n\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n\n  // Chrome (OSX) fix for https://github.com/twbs/bootstrap/issues/11245\n  // Once fixed, we can just straight up remove this.\n  select {\n    background: #fff !important;\n  }\n\n  // Bootstrap components\n  .navbar {\n    display: none;\n  }\n  .table {\n    td,\n    th {\n      background-color: #fff !important;\n    }\n  }\n  .btn,\n  .dropup > .btn {\n    > .caret {\n      border-top-color: #000 !important;\n    }\n  }\n  .label {\n    border: 1px solid #000;\n  }\n\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table-bordered {\n    th,\n    td {\n      border: 1px solid #ddd !important;\n    }\n  }\n\n}\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n  .box-sizing(border-box);\n}\n*:before,\n*:after {\n  .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n  font-size: 62.5%;\n  -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n  font-family: @font-family-base;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @text-color;\n  background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\n\n// Links\n\na {\n  color: @link-color;\n  text-decoration: none;\n\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: underline;\n  }\n\n  &:focus {\n    .tab-focus();\n  }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n  margin: 0;\n}\n\n\n// Images\n\nimg {\n  vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n  .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n  border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n  padding: @thumbnail-padding;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(all .2s ease-in-out);\n\n  // Keep them at most 100% wide\n  .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n  border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n  margin-top:    @line-height-computed;\n  margin-bottom: @line-height-computed;\n  border: 0;\n  border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0,0,0,0);\n  border: 0;\n}\n","//\n// Mixins\n// --------------------------------------------------\n\n\n// Utilities\n// -------------------------\n\n// Clearfix\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n//    contenteditable attribute is included anywhere else in the document.\n//    Otherwise it causes space to appear at the top and bottom of elements\n//    that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n//    `:before` to contain the top-margins of child elements.\n.clearfix() {\n  &:before,\n  &:after {\n    content: \" \"; // 1\n    display: table; // 2\n  }\n  &:after {\n    clear: both;\n  }\n}\n\n// WebKit-style focus\n.tab-focus() {\n  // Default\n  outline: thin dotted;\n  // WebKit\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n// Center-align a block level element\n.center-block() {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n\n// Sizing shortcuts\n.size(@width; @height) {\n  width: @width;\n  height: @height;\n}\n.square(@size) {\n  .size(@size; @size);\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n  &::-moz-placeholder           { color: @color;   // Firefox\n                                  opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n  &:-ms-input-placeholder       { color: @color; } // Internet Explorer 10+\n  &::-webkit-input-placeholder  { color: @color; } // Safari and Chrome\n}\n\n// Text overflow\n// Requires inline-block or block for proper styling\n.text-overflow() {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note\n// that we cannot chain the mixins together in Less, so they are repeated.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n  font: ~\"0/0\" a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n// New mixin to use as of v3.0.1\n.text-hide() {\n  .hide-text();\n}\n\n\n\n// CSS3 PROPERTIES\n// --------------------------------------------------\n\n// Single side border-radius\n.border-top-radius(@radius) {\n  border-top-right-radius: @radius;\n   border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n  border-bottom-right-radius: @radius;\n     border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n  border-bottom-right-radius: @radius;\n   border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n  border-bottom-left-radius: @radius;\n     border-top-left-radius: @radius;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n//   supported browsers that have box shadow capabilities now support the\n//   standard `box-shadow` property.\n.box-shadow(@shadow) {\n  -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n          box-shadow: @shadow;\n}\n\n// Transitions\n.transition(@transition) {\n  -webkit-transition: @transition;\n          transition: @transition;\n}\n.transition-property(@transition-property) {\n  -webkit-transition-property: @transition-property;\n          transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n  -webkit-transition-delay: @transition-delay;\n          transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n  -webkit-transition-duration: @transition-duration;\n          transition-duration: @transition-duration;\n}\n.transition-transform(@transition) {\n  -webkit-transition: -webkit-transform @transition;\n     -moz-transition: -moz-transform @transition;\n       -o-transition: -o-transform @transition;\n          transition: transform @transition;\n}\n\n// Transformations\n.rotate(@degrees) {\n  -webkit-transform: rotate(@degrees);\n      -ms-transform: rotate(@degrees); // IE9 only\n          transform: rotate(@degrees);\n}\n.scale(@ratio; @ratio-y...) {\n  -webkit-transform: scale(@ratio, @ratio-y);\n      -ms-transform: scale(@ratio, @ratio-y); // IE9 only\n          transform: scale(@ratio, @ratio-y);\n}\n.translate(@x; @y) {\n  -webkit-transform: translate(@x, @y);\n      -ms-transform: translate(@x, @y); // IE9 only\n          transform: translate(@x, @y);\n}\n.skew(@x; @y) {\n  -webkit-transform: skew(@x, @y);\n      -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n          transform: skew(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n  -webkit-transform: translate3d(@x, @y, @z);\n          transform: translate3d(@x, @y, @z);\n}\n\n.rotateX(@degrees) {\n  -webkit-transform: rotateX(@degrees);\n      -ms-transform: rotateX(@degrees); // IE9 only\n          transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n  -webkit-transform: rotateY(@degrees);\n      -ms-transform: rotateY(@degrees); // IE9 only\n          transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n  -webkit-perspective: @perspective;\n     -moz-perspective: @perspective;\n          perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n  -webkit-perspective-origin: @perspective;\n     -moz-perspective-origin: @perspective;\n          perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n  -webkit-transform-origin: @origin;\n     -moz-transform-origin: @origin;\n      -ms-transform-origin: @origin; // IE9 only\n          transform-origin: @origin;\n}\n\n// Animations\n.animation(@animation) {\n  -webkit-animation: @animation;\n          animation: @animation;\n}\n.animation-name(@name) {\n  -webkit-animation-name: @name;\n          animation-name: @name;\n}\n.animation-duration(@duration) {\n  -webkit-animation-duration: @duration;\n          animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n  -webkit-animation-timing-function: @timing-function;\n          animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n  -webkit-animation-delay: @delay;\n          animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n  -webkit-animation-iteration-count: @iteration-count;\n          animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n  -webkit-animation-direction: @direction;\n          animation-direction: @direction;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n.backface-visibility(@visibility){\n  -webkit-backface-visibility: @visibility;\n     -moz-backface-visibility: @visibility;\n          backface-visibility: @visibility;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n  -webkit-box-sizing: @boxmodel;\n     -moz-box-sizing: @boxmodel;\n          box-sizing: @boxmodel;\n}\n\n// User select\n// For selecting text on the page\n.user-select(@select) {\n  -webkit-user-select: @select;\n     -moz-user-select: @select;\n      -ms-user-select: @select; // IE10+\n          user-select: @select;\n}\n\n// Resize anything\n.resizable(@direction) {\n  resize: @direction; // Options: horizontal, vertical, both\n  overflow: auto; // Safari fix\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n  -webkit-column-count: @column-count;\n     -moz-column-count: @column-count;\n          column-count: @column-count;\n  -webkit-column-gap: @column-gap;\n     -moz-column-gap: @column-gap;\n          column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n  word-wrap: break-word;\n  -webkit-hyphens: @mode;\n     -moz-hyphens: @mode;\n      -ms-hyphens: @mode; // IE10+\n       -o-hyphens: @mode;\n          hyphens: @mode;\n}\n\n// Opacity\n.opacity(@opacity) {\n  opacity: @opacity;\n  // IE8 filter\n  @opacity-ie: (@opacity * 100);\n  filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n\n\n\n// GRADIENTS\n// --------------------------------------------------\n\n#gradient {\n\n  // Horizontal gradient, from left to right\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+\n    background-image:  linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  // Vertical gradient, from top to bottom\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Safari 5.1-6, Chrome 10+\n    background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n    background-repeat: repeat-x;\n    background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n    background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n  }\n  .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .radial(@inner-color: #555; @outer-color: #333) {\n    background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n    background-image: radial-gradient(circle, @inner-color, @outer-color);\n    background-repeat: no-repeat;\n  }\n  .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n    background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n  }\n}\n\n// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n.reset-filter() {\n  filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n\n\n\n// Retina images\n//\n// Short retina mixin for setting background-image and -size\n\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n  background-image: url(\"@{file-1x}\");\n\n  @media\n  only screen and (-webkit-min-device-pixel-ratio: 2),\n  only screen and (   min--moz-device-pixel-ratio: 2),\n  only screen and (     -o-min-device-pixel-ratio: 2/1),\n  only screen and (        min-device-pixel-ratio: 2),\n  only screen and (                min-resolution: 192dpi),\n  only screen and (                min-resolution: 2dppx) {\n    background-image: url(\"@{file-2x}\");\n    background-size: @width-1x @height-1x;\n  }\n}\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n.img-responsive(@display: block) {\n  display: @display;\n  max-width: 100%; // Part 1: Set a maximum relative to the parent\n  height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// COMPONENT MIXINS\n// --------------------------------------------------\n\n// Horizontal dividers\n// -------------------------\n// Dividers (basically an hr) within dropdowns and nav lists\n.nav-divider(@color: #e5e5e5) {\n  height: 1px;\n  margin: ((@line-height-computed / 2) - 1) 0;\n  overflow: hidden;\n  background-color: @color;\n}\n\n// Panels\n// -------------------------\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n  border-color: @border;\n\n  & > .panel-heading {\n    color: @heading-text-color;\n    background-color: @heading-bg-color;\n    border-color: @heading-border;\n\n    + .panel-collapse .panel-body {\n      border-top-color: @border;\n    }\n  }\n  & > .panel-footer {\n    + .panel-collapse .panel-body {\n      border-bottom-color: @border;\n    }\n  }\n}\n\n// Alerts\n// -------------------------\n.alert-variant(@background; @border; @text-color) {\n  background-color: @background;\n  border-color: @border;\n  color: @text-color;\n\n  hr {\n    border-top-color: darken(@border, 5%);\n  }\n  .alert-link {\n    color: darken(@text-color, 10%);\n  }\n}\n\n// Tables\n// -------------------------\n.table-row-variant(@state; @background) {\n  // Exact selectors below required to override `.table-striped` and prevent\n  // inheritance to nested tables.\n  .table > thead > tr,\n  .table > tbody > tr,\n  .table > tfoot > tr {\n    > td.@{state},\n    > th.@{state},\n    &.@{state} > td,\n    &.@{state} > th {\n      background-color: @background;\n    }\n  }\n\n  // Hover states for `.table-hover`\n  // Note: this is not available for cells or rows within `thead` or `tfoot`.\n  .table-hover > tbody > tr {\n    > td.@{state}:hover,\n    > th.@{state}:hover,\n    &.@{state}:hover > td,\n    &.@{state}:hover > th {\n      background-color: darken(@background, 5%);\n    }\n  }\n}\n\n// List Groups\n// -------------------------\n.list-group-item-variant(@state; @background; @color) {\n  .list-group-item-@{state} {\n    color: @color;\n    background-color: @background;\n\n    a& {\n      color: @color;\n\n      .list-group-item-heading { color: inherit; }\n\n      &:hover,\n      &:focus {\n        color: @color;\n        background-color: darken(@background, 5%);\n      }\n      &.active,\n      &.active:hover,\n      &.active:focus {\n        color: #fff;\n        background-color: @color;\n        border-color: @color;\n      }\n    }\n  }\n}\n\n// Button variants\n// -------------------------\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n.button-variant(@color; @background; @border) {\n  color: @color;\n  background-color: @background;\n  border-color: @border;\n\n  &:hover,\n  &:focus,\n  &:active,\n  &.active,\n  .open .dropdown-toggle& {\n    color: @color;\n    background-color: darken(@background, 8%);\n        border-color: darken(@border, 12%);\n  }\n  &:active,\n  &.active,\n  .open .dropdown-toggle& {\n    background-image: none;\n  }\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    &,\n    &:hover,\n    &:focus,\n    &:active,\n    &.active {\n      background-color: @background;\n          border-color: @border;\n    }\n  }\n\n  .badge {\n    color: @background;\n    background-color: @color;\n  }\n}\n\n// Button sizes\n// -------------------------\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n}\n\n// Pagination\n// -------------------------\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n  > li {\n    > a,\n    > span {\n      padding: @padding-vertical @padding-horizontal;\n      font-size: @font-size;\n    }\n    &:first-child {\n      > a,\n      > span {\n        .border-left-radius(@border-radius);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius);\n      }\n    }\n  }\n}\n\n// Labels\n// -------------------------\n.label-variant(@color) {\n  background-color: @color;\n  &[href] {\n    &:hover,\n    &:focus {\n      background-color: darken(@color, 10%);\n    }\n  }\n}\n\n// Contextual backgrounds\n// -------------------------\n.bg-variant(@color) {\n  background-color: @color;\n  a&:hover {\n    background-color: darken(@color, 10%);\n  }\n}\n\n// Typography\n// -------------------------\n.text-emphasis-variant(@color) {\n  color: @color;\n  a&:hover {\n    color: darken(@color, 10%);\n  }\n}\n\n// Navbar vertical align\n// -------------------------\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n.navbar-vertical-align(@element-height) {\n  margin-top: ((@navbar-height - @element-height) / 2);\n  margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n\n// Progress bars\n// -------------------------\n.progress-bar-variant(@color) {\n  background-color: @color;\n  .progress-striped & {\n    #gradient > .striped();\n  }\n}\n\n// Responsive utilities\n// -------------------------\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n  display: block !important;\n  table&  { display: table; }\n  tr&     { display: table-row !important; }\n  th&,\n  td&     { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n  display: none !important;\n}\n\n\n// Grid System\n// -----------\n\n// Centered container element\n.container-fixed() {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left:  (@grid-gutter-width / 2);\n  padding-right: (@grid-gutter-width / 2);\n  &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n  margin-left:  (@gutter / -2);\n  margin-right: (@gutter / -2);\n  &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  float: left;\n  width: percentage((@columns / @grid-columns));\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n  @media (min-width: @screen-xs-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-xs-column-push(@columns) {\n  @media (min-width: @screen-xs-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-xs-column-pull(@columns) {\n  @media (min-width: @screen-xs-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-sm-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-offset(@columns) {\n  @media (min-width: @screen-sm-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-push(@columns) {\n  @media (min-width: @screen-sm-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-pull(@columns) {\n  @media (min-width: @screen-sm-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-md-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-offset(@columns) {\n  @media (min-width: @screen-md-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-push(@columns) {\n  @media (min-width: @screen-md-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-pull(@columns) {\n  @media (min-width: @screen-md-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-lg-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-offset(@columns) {\n  @media (min-width: @screen-lg-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-push(@columns) {\n  @media (min-width: @screen-lg-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-pull(@columns) {\n  @media (min-width: @screen-lg-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n  // Common styles for all sizes of grid columns, widths 1-12\n  .col(@index) when (@index = 1) { // initial\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      position: relative;\n      // Prevent columns from collapsing when empty\n      min-height: 1px;\n      // Inner gutter via padding\n      padding-left:  (@grid-gutter-width / 2);\n      padding-right: (@grid-gutter-width / 2);\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n  .col(@index) when (@index = 1) { // initial\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      float: left;\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n  .col-@{class}-@{index} {\n    width: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) {\n  .col-@{class}-push-@{index} {\n    left: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) {\n  .col-@{class}-pull-@{index} {\n    right: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n  .col-@{class}-offset-@{index} {\n    margin-left: percentage((@index / @grid-columns));\n  }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n  .calc-grid-column(@index, @class, @type);\n  // next iteration\n  .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n  .float-grid-columns(@class);\n  .loop-grid-columns(@grid-columns, @class, width);\n  .loop-grid-columns(@grid-columns, @class, pull);\n  .loop-grid-columns(@grid-columns, @class, push);\n  .loop-grid-columns(@grid-columns, @class, offset);\n}\n\n// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n  // Color the label and help text\n  .help-block,\n  .control-label,\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline  {\n    color: @text-color;\n  }\n  // Set the border and box shadow on specific inputs to match\n  .form-control {\n    border-color: @border-color;\n    .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n    &:focus {\n      border-color: darken(@border-color, 10%);\n      @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n      .box-shadow(@shadow);\n    }\n  }\n  // Set validation states also for addons\n  .input-group-addon {\n    color: @text-color;\n    border-color: @border-color;\n    background-color: @background-color;\n  }\n  // Optional feedback icon\n  .form-control-feedback {\n    color: @text-color;\n  }\n}\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-focus-border` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n\n.form-control-focus(@color: @input-border-focus) {\n  @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n  &:focus {\n    border-color: @color;\n    outline: 0;\n    .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n  }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  height: @input-height;\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n\n  select& {\n    height: @input-height;\n    line-height: @input-height;\n  }\n\n  textarea&,\n  select[multiple]& {\n    height: auto;\n  }\n}\n","//\n// Variables\n// --------------------------------------------------\n\n\n//== Colors\n//\n//## Gray and brand colors for use across Bootstrap.\n\n@gray-darker:            lighten(#000, 13.5%); // #222\n@gray-dark:              lighten(#000, 20%);   // #333\n@gray:                   lighten(#000, 33.5%); // #555\n@gray-light:             lighten(#000, 60%);   // #999\n@gray-lighter:           lighten(#000, 93.5%); // #eee\n\n@brand-primary:         #428bca;\n@brand-success:         #79db32;\n@brand-info:            #a07cbc;\n@brand-warning:         #e59728;\n@brand-danger:          #db3279;\n\n\n//== Scaffolding\n//\n// ## Settings for some of the most global styles.\n\n//** Background color for `<body>`.\n@body-bg:               #fff;\n//** Global text color on `<body>`.\n@text-color:            @gray-dark;\n\n//** Global textual link color.\n@link-color:            @brand-primary;\n//** Link hover color set via `darken()` function.\n@link-hover-color:      darken(@link-color, 15%);\n\n\n//== Typography\n//\n//## Font, line-height, and color for body text, headings, and more.\n\n@font-family-sans-serif:  Cantarell, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n@font-family-serif:       Cantarell, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.\n@font-family-monospace:   Menlo, Monaco, Consolas, \"Courier New\", monospace;\n@font-family-base:        @font-family-sans-serif;\n@font-family-brand:       Comfortaa, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n\n@font-size-base:          14px;\n@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px\n@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px\n\n@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px\n@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px\n@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px\n@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px\n@font-size-h5:            @font-size-base;\n@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px\n\n//** Unit-less `line-height` for use in components like buttons.\n@line-height-base:        1.428571429; // 20/14\n//** Computed \"line-height\" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.\n@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px\n\n//** By default, this inherits from the `<body>`.\n@headings-font-family:    inherit;\n@headings-font-weight:    500;\n@headings-line-height:    1.1;\n@headings-color:          inherit;\n\n\n//-- Iconography\n//\n//## Specify custom locations of the include Glyphicons icon font. Useful for those including Bootstrap via Bower.\n\n@icon-font-path:          \"../fonts/\";\n@icon-font-name:          \"glyphicons-halflings-regular\";\n@icon-font-svg-id:        \"glyphicons_halflingsregular\";\n\n//== Components\n//\n//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).\n\n@padding-base-vertical:     6px;\n@padding-base-horizontal:   12px;\n\n@padding-large-vertical:    10px;\n@padding-large-horizontal:  16px;\n\n@padding-small-vertical:    5px;\n@padding-small-horizontal:  10px;\n\n@padding-xs-vertical:       1px;\n@padding-xs-horizontal:     5px;\n\n@line-height-large:         1.33;\n@line-height-small:         1.5;\n\n@border-radius-base:        4px;\n@border-radius-large:       6px;\n@border-radius-small:       3px;\n\n//** Global color for active items (e.g., navs or dropdowns).\n@component-active-color:    #fff;\n//** Global background color for active items (e.g., navs or dropdowns).\n@component-active-bg:       @brand-primary;\n\n//** Width of the `border` for generating carets that indicator dropdowns.\n@caret-width-base:          4px;\n//** Carets increase slightly in size for larger components.\n@caret-width-large:         5px;\n\n\n//== Tables\n//\n//## Customizes the `.table` component with basic values, each used across all table variations.\n\n//** Padding for `<th>`s and `<td>`s.\n@table-cell-padding:            8px;\n//** Padding for cells in `.table-condensed`.\n@table-condensed-cell-padding:  5px;\n\n//** Default background color used for all tables.\n@table-bg:                      transparent;\n//** Background color used for `.table-striped`.\n@table-bg-accent:               #f9f9f9;\n//** Background color used for `.table-hover`.\n@table-bg-hover:                #f5f5f5;\n@table-bg-active:               @table-bg-hover;\n\n//** Border color for table and cell borders.\n@table-border-color:            #ddd;\n\n\n//== Buttons\n//\n//## For each of Bootstrap's buttons, define text, background and border color.\n\n@btn-font-weight:                normal;\n\n@btn-default-color:              #333;\n@btn-default-bg:                 #fff;\n@btn-default-border:             #ccc;\n\n@btn-primary-color:              #fff;\n@btn-primary-bg:                 @brand-primary;\n@btn-primary-border:             darken(@btn-primary-bg, 5%);\n\n@btn-success-color:              #fff;\n@btn-success-bg:                 @brand-success;\n@btn-success-border:             darken(@btn-success-bg, 5%);\n\n@btn-info-color:                 #fff;\n@btn-info-bg:                    @brand-info;\n@btn-info-border:                darken(@btn-info-bg, 5%);\n\n@btn-warning-color:              #fff;\n@btn-warning-bg:                 @brand-warning;\n@btn-warning-border:             darken(@btn-warning-bg, 5%);\n\n@btn-danger-color:               #fff;\n@btn-danger-bg:                  @brand-danger;\n@btn-danger-border:              darken(@btn-danger-bg, 5%);\n\n@btn-link-disabled-color:        @gray-light;\n\n\n//== Forms\n//\n//##\n\n//** `<input>` background color\n@input-bg:                       #fff;\n//** `<input disabled>` background color\n@input-bg-disabled:              @gray-lighter;\n\n//** Text color for `<input>`s\n@input-color:                    @gray;\n//** `<input>` border color\n@input-border:                   #ccc;\n//** `<input>` border radius\n@input-border-radius:            @border-radius-base;\n//** Border color for inputs on focus\n@input-border-focus:             #66afe9;\n\n//** Placeholder text color\n@input-color-placeholder:        @gray-light;\n\n//** Default `.form-control` height\n@input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);\n//** Large `.form-control` height\n@input-height-large:             (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);\n//** Small `.form-control` height\n@input-height-small:             (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);\n\n@legend-color:                   @gray-dark;\n@legend-border-color:            #e5e5e5;\n\n//** Background color for textual input addons\n@input-group-addon-bg:           @gray-lighter;\n//** Border color for textual input addons\n@input-group-addon-border-color: @input-border;\n\n\n//== Dropdowns\n//\n//## Dropdown menu container and contents.\n\n//** Background for the dropdown menu.\n@dropdown-bg:                    #fff;\n//** Dropdown menu `border-color`.\n@dropdown-border:                rgba(0,0,0,.15);\n//** Dropdown menu `border-color` **for IE8**.\n@dropdown-fallback-border:       #ccc;\n//** Divider color for between dropdown items.\n@dropdown-divider-bg:            #e5e5e5;\n\n//** Dropdown link text color.\n@dropdown-link-color:            @gray-dark;\n//** Hover color for dropdown links.\n@dropdown-link-hover-color:      darken(@gray-dark, 5%);\n//** Hover background for dropdown links.\n@dropdown-link-hover-bg:         #f5f5f5;\n\n//** Active dropdown menu item text color.\n@dropdown-link-active-color:     @component-active-color;\n//** Active dropdown menu item background color.\n@dropdown-link-active-bg:        @component-active-bg;\n\n//** Disabled dropdown menu item background color.\n@dropdown-link-disabled-color:   @gray-light;\n\n//** Text color for headers within dropdown menus.\n@dropdown-header-color:          @gray-light;\n\n// Note: Deprecated @dropdown-caret-color as of v3.1.0\n@dropdown-caret-color:           #000;\n\n\n//-- Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n//\n// Note: These variables are not generated into the Customizer.\n\n@zindex-navbar:            1000;\n@zindex-dropdown:          1000;\n@zindex-popover:           1010;\n@zindex-tooltip:           1030;\n@zindex-navbar-fixed:      1030;\n@zindex-modal-background:  1040;\n@zindex-modal:             1050;\n\n\n//== Media queries breakpoints\n//\n//## Define the breakpoints at which your layout will change, adapting to different screen sizes.\n\n// Extra small screen / phone\n// Note: Deprecated @screen-xs and @screen-phone as of v3.0.1\n@screen-xs:                  480px;\n@screen-xs-min:              @screen-xs;\n@screen-phone:               @screen-xs-min;\n\n// Small screen / tablet\n// Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1\n@screen-sm:                  768px;\n@screen-sm-min:              @screen-sm;\n@screen-tablet:              @screen-sm-min;\n\n// Medium screen / desktop\n// Note: Deprecated @screen-md and @screen-desktop as of v3.0.1\n@screen-md:                  992px;\n@screen-md-min:              @screen-md;\n@screen-desktop:             @screen-md-min;\n\n// Large screen / wide desktop\n// Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1\n@screen-lg:                  1200px;\n@screen-lg-min:              @screen-lg;\n@screen-lg-desktop:          @screen-lg-min;\n\n// So media queries don't overlap when required, provide a maximum\n@screen-xs-max:              (@screen-sm-min - 1);\n@screen-sm-max:              (@screen-md-min - 1);\n@screen-md-max:              (@screen-lg-min - 1);\n\n\n//== Grid system\n//\n//## Define your custom responsive grid.\n\n//** Number of columns in the grid.\n@grid-columns:              12;\n//** Padding between columns. Gets divided in half for the left and right.\n@grid-gutter-width:         30px;\n// Navbar collapse\n//** Point at which the navbar becomes uncollapsed.\n@grid-float-breakpoint:     @screen-sm-min;\n//** Point at which the navbar begins collapsing.\n@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);\n\n\n//== Container sizes\n//\n//## Define the maximum width of `.container` for different screen sizes.\n\n// Small screen / tablet\n@container-tablet:             ((720px + @grid-gutter-width));\n//** For `@screen-sm-min` and up.\n@container-sm:                 @container-tablet;\n\n// Medium screen / desktop\n@container-desktop:            ((940px + @grid-gutter-width));\n//** For `@screen-md-min` and up.\n@container-md:                 @container-desktop;\n\n// Large screen / wide desktop\n@container-large-desktop:      ((1140px + @grid-gutter-width));\n//** For `@screen-lg-min` and up.\n@container-lg:                 @container-large-desktop;\n\n\n//== Navbar\n//\n//##\n\n// Basics of a navbar\n@navbar-height:                    50px;\n@navbar-margin-bottom:             @line-height-computed;\n@navbar-border-radius:             @border-radius-base;\n@navbar-padding-horizontal:        floor((@grid-gutter-width / 2));\n@navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);\n@navbar-collapse-max-height:       340px;\n\n@navbar-default-color:             #777;\n@navbar-default-bg:                #f8f8f8;\n@navbar-default-border:            darken(@navbar-default-bg, 6.5%);\n\n// Navbar links\n@navbar-default-link-color:                #777;\n@navbar-default-link-hover-color:          #333;\n@navbar-default-link-hover-bg:             transparent;\n@navbar-default-link-active-color:         #db3279;\n@navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);\n@navbar-default-link-disabled-color:       #ccc;\n@navbar-default-link-disabled-bg:          transparent;\n\n// Navbar brand label\n@navbar-default-brand-color:               @navbar-default-link-color;\n@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);\n@navbar-default-brand-hover-bg:            transparent;\n\n// Navbar toggle\n@navbar-default-toggle-hover-bg:           #ddd;\n@navbar-default-toggle-icon-bar-bg:        #888;\n@navbar-default-toggle-border-color:       #ddd;\n\n\n// Inverted navbar\n// Reset inverted navbar basics\n@navbar-inverse-color:                      @gray-light;\n@navbar-inverse-bg:                         #294172;\n@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);\n\n// Inverted navbar links\n@navbar-inverse-link-color:                 @gray-light;\n@navbar-inverse-link-hover-color:           #fff;\n@navbar-inverse-link-hover-bg:              transparent;\n@navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;\n@navbar-inverse-link-active-bg:             darken(@navbar-inverse-bg, 10%);\n@navbar-inverse-link-disabled-color:        #444;\n@navbar-inverse-link-disabled-bg:           transparent;\n\n// Inverted navbar brand label\n@navbar-inverse-brand-color:                @navbar-inverse-link-color;\n@navbar-inverse-brand-hover-color:          #fff;\n@navbar-inverse-brand-hover-bg:             transparent;\n\n// Inverted navbar toggle\n@navbar-inverse-toggle-hover-bg:            #333;\n@navbar-inverse-toggle-icon-bar-bg:         #fff;\n@navbar-inverse-toggle-border-color:        #333;\n\n\n//== Navs\n//\n//##\n\n//=== Shared nav styles\n@nav-link-padding:                          10px 15px;\n@nav-link-hover-bg:                         @gray-lighter;\n\n@nav-disabled-link-color:                   @gray-light;\n@nav-disabled-link-hover-color:             @gray-light;\n\n@nav-open-link-hover-color:                 #fff;\n\n//== Tabs\n@nav-tabs-border-color:                     #ddd;\n\n@nav-tabs-link-hover-border-color:          @gray-lighter;\n\n@nav-tabs-active-link-hover-bg:             @body-bg;\n@nav-tabs-active-link-hover-color:          @gray;\n@nav-tabs-active-link-hover-border-color:   #ddd;\n\n@nav-tabs-justified-link-border-color:            #ddd;\n@nav-tabs-justified-active-link-border-color:     @body-bg;\n\n//== Pills\n@nav-pills-border-radius:                   @border-radius-base;\n@nav-pills-active-link-hover-bg:            @component-active-bg;\n@nav-pills-active-link-hover-color:         @component-active-color;\n\n\n//== Pagination\n//\n//##\n\n@pagination-color:                     @link-color;\n@pagination-bg:                        #fff;\n@pagination-border:                    #ddd;\n\n@pagination-hover-color:               @link-hover-color;\n@pagination-hover-bg:                  @gray-lighter;\n@pagination-hover-border:              #ddd;\n\n@pagination-active-color:              #fff;\n@pagination-active-bg:                 @brand-primary;\n@pagination-active-border:             @brand-primary;\n\n@pagination-disabled-color:            @gray-light;\n@pagination-disabled-bg:               #fff;\n@pagination-disabled-border:           #ddd;\n\n\n//== Pager\n//\n//##\n\n@pager-bg:                             @pagination-bg;\n@pager-border:                         @pagination-border;\n@pager-border-radius:                  15px;\n\n@pager-hover-bg:                       @pagination-hover-bg;\n\n@pager-active-bg:                      @pagination-active-bg;\n@pager-active-color:                   @pagination-active-color;\n\n@pager-disabled-color:                 @pagination-disabled-color;\n\n\n//== Jumbotron\n//\n//##\n\n@jumbotron-padding:              30px;\n@jumbotron-color:                inherit;\n@jumbotron-bg:                   @gray-lighter;\n@jumbotron-heading-color:        inherit;\n@jumbotron-font-size:            ceil((@font-size-base * 1.5));\n\n\n//== Form states and alerts\n//\n//## Define colors for form feedback states and, by default, alerts.\n\n@state-success-text:             darken(@brand-success, 25%);\n@state-success-bg:               lighten(@brand-success, 35%);\n@state-success-border:           darken(spin(@state-success-bg, -10), 5%);\n\n@state-info-text:                darken(@brand-info, 25%);\n@state-info-bg:                  lighten(@brand-info, 35%);\n@state-info-border:              darken(spin(@state-info-bg, -10), 5%);\n\n@state-warning-text:             darken(@brand-warning, 25%);\n@state-warning-bg:               lighten(@brand-warning, 35%);\n@state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);\n\n@state-danger-text:              darken(@brand-danger, 25%);\n@state-danger-bg:                lighten(@brand-danger, 35%);\n@state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);\n\n\n//== Tooltips\n//\n//##\n\n//** Tooltip max width\n@tooltip-max-width:           200px;\n//** Tooltip text color\n@tooltip-color:               #fff;\n//** Tooltip background color\n@tooltip-bg:                  #000;\n@tooltip-opacity:             .9;\n\n//** Tooltip arrow width\n@tooltip-arrow-width:         5px;\n//** Tooltip arrow color\n@tooltip-arrow-color:         @tooltip-bg;\n\n\n//== Popovers\n//\n//##\n\n//** Popover body background color\n@popover-bg:                          #fff;\n//** Popover maximum width\n@popover-max-width:                   276px;\n//** Popover border color\n@popover-border-color:                rgba(0,0,0,.2);\n//** Popover fallback border color\n@popover-fallback-border-color:       #ccc;\n\n//** Popover title background color\n@popover-title-bg:                    darken(@popover-bg, 3%);\n\n//** Popover arrow width\n@popover-arrow-width:                 10px;\n//** Popover arrow color\n@popover-arrow-color:                 #fff;\n\n//** Popover outer arrow width\n@popover-arrow-outer-width:           (@popover-arrow-width + 1);\n//** Popover outer arrow color\n@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);\n//** Popover outer arrow fallback color\n@popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);\n\n\n//== Labels\n//\n//##\n\n//** Default label background color\n@label-default-bg:            @gray-light;\n//** Primary label background color\n@label-primary-bg:            @brand-primary;\n//** Success label background color\n@label-success-bg:            @brand-success;\n//** Info label background color\n@label-info-bg:               @brand-info;\n//** Warning label background color\n@label-warning-bg:            @brand-warning;\n//** Danger label background color\n@label-danger-bg:             @brand-danger;\n\n//** Default label text color\n@label-color:                 #fff;\n//** Default text color of a linked label\n@label-link-hover-color:      #fff;\n\n\n//== Modals\n//\n//##\n\n//** Padding applied to the modal body\n@modal-inner-padding:         20px;\n\n//** Padding applied to the modal title\n@modal-title-padding:         15px;\n//** Modal title line-height\n@modal-title-line-height:     @line-height-base;\n\n//** Background color of modal content area\n@modal-content-bg:                             #fff;\n//** Modal content border color\n@modal-content-border-color:                   rgba(0,0,0,.2);\n//** Modal content border color **for IE8**\n@modal-content-fallback-border-color:          #999;\n\n//** Modal backdrop background color\n@modal-backdrop-bg:           #000;\n//** Modal backdrop opacity\n@modal-backdrop-opacity:      .5;\n//** Modal header border color\n@modal-header-border-color:   #e5e5e5;\n//** Modal footer border color\n@modal-footer-border-color:   @modal-header-border-color;\n\n@modal-lg:                    900px;\n@modal-md:                    600px;\n@modal-sm:                    300px;\n\n\n//== Alerts\n//\n//## Define alert colors, border radius, and padding.\n\n@alert-padding:               15px;\n@alert-border-radius:         @border-radius-base;\n@alert-link-font-weight:      bold;\n\n@alert-success-bg:            @state-success-bg;\n@alert-success-text:          @state-success-text;\n@alert-success-border:        @state-success-border;\n\n@alert-info-bg:               @state-info-bg;\n@alert-info-text:             @state-info-text;\n@alert-info-border:           @state-info-border;\n\n@alert-warning-bg:            @state-warning-bg;\n@alert-warning-text:          @state-warning-text;\n@alert-warning-border:        @state-warning-border;\n\n@alert-danger-bg:             @state-danger-bg;\n@alert-danger-text:           @state-danger-text;\n@alert-danger-border:         @state-danger-border;\n\n\n//== Progress bars\n//\n//##\n\n//** Background color of the whole progress component\n@progress-bg:                 #f5f5f5;\n//** Progress bar text color\n@progress-bar-color:          #fff;\n\n//** Default progress bar color\n@progress-bar-bg:             @brand-primary;\n//** Success progress bar color\n@progress-bar-success-bg:     @brand-success;\n//** Warning progress bar color\n@progress-bar-warning-bg:     @brand-warning;\n//** Danger progress bar color\n@progress-bar-danger-bg:      @brand-danger;\n//** Info progress bar color\n@progress-bar-info-bg:        @brand-info;\n\n\n//== List group\n//\n//##\n\n//** Background color on `.list-group-item`\n@list-group-bg:                 #fff;\n//** `.list-group-item` border color\n@list-group-border:             #ddd;\n//** List group border radius\n@list-group-border-radius:      @border-radius-base;\n\n//** Background color of single list elements on hover\n@list-group-hover-bg:           #f5f5f5;\n//** Text color of active list elements\n@list-group-active-color:       @component-active-color;\n//** Background color of active list elements\n@list-group-active-bg:          @component-active-bg;\n//** Border color of active list elements\n@list-group-active-border:      @list-group-active-bg;\n@list-group-active-text-color:  lighten(@list-group-active-bg, 40%);\n\n@list-group-link-color:         #555;\n@list-group-link-heading-color: #333;\n\n\n//== Panels\n//\n//##\n\n@panel-bg:                    #fff;\n@panel-body-padding:          15px;\n@panel-border-radius:         @border-radius-base;\n\n//** Border color for elements within panels\n@panel-inner-border:          #ddd;\n@panel-footer-bg:             #f5f5f5;\n\n@panel-default-text:          @gray-dark;\n@panel-default-border:        #ddd;\n@panel-default-heading-bg:    #f5f5f5;\n\n@panel-primary-text:          #fff;\n@panel-primary-border:        @brand-primary;\n@panel-primary-heading-bg:    @brand-primary;\n\n@panel-success-text:          @state-success-text;\n@panel-success-border:        @state-success-border;\n@panel-success-heading-bg:    @state-success-bg;\n\n@panel-info-text:             @state-info-text;\n@panel-info-border:           @state-info-border;\n@panel-info-heading-bg:       @state-info-bg;\n\n@panel-warning-text:          @state-warning-text;\n@panel-warning-border:        @state-warning-border;\n@panel-warning-heading-bg:    @state-warning-bg;\n\n@panel-danger-text:           @state-danger-text;\n@panel-danger-border:         @state-danger-border;\n@panel-danger-heading-bg:     @state-danger-bg;\n\n\n//== Thumbnails\n//\n//##\n\n//** Padding around the thumbnail image\n@thumbnail-padding:           4px;\n//** Thumbnail background color\n@thumbnail-bg:                @body-bg;\n//** Thumbnail border color\n@thumbnail-border:            #ddd;\n//** Thumbnail border radius\n@thumbnail-border-radius:     @border-radius-base;\n\n//** Custom text color for thumbnail captions\n@thumbnail-caption-color:     @text-color;\n//** Padding around the thumbnail caption\n@thumbnail-caption-padding:   9px;\n\n\n//== Wells\n//\n//##\n\n@well-bg:                     #f5f5f5;\n@well-border:                 darken(@well-bg, 7%);\n\n\n//== Badges\n//\n//##\n\n@badge-color:                 #fff;\n//** Linked badge text color on hover\n@badge-link-hover-color:      #fff;\n@badge-bg:                    @gray-light;\n\n//** Badge text color in active nav link\n@badge-active-color:          @link-color;\n//** Badge background color in active nav link\n@badge-active-bg:             #fff;\n\n@badge-font-weight:           bold;\n@badge-line-height:           1;\n@badge-border-radius:         10px;\n\n\n//== Breadcrumbs\n//\n//##\n\n@breadcrumb-padding-vertical:   8px;\n@breadcrumb-padding-horizontal: 15px;\n//** Breadcrumb background color\n@breadcrumb-bg:                 #f5f5f5;\n//** Breadcrumb text color\n@breadcrumb-color:              #ccc;\n//** Text color of current page in the breadcrumb\n@breadcrumb-active-color:       @gray-light;\n//** Textual separator for between breadcrumb elements\n@breadcrumb-separator:          \"/\";\n\n\n//== Carousel\n//\n//##\n\n@carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);\n\n@carousel-control-color:                      #fff;\n@carousel-control-width:                      15%;\n@carousel-control-opacity:                    .5;\n@carousel-control-font-size:                  20px;\n\n@carousel-indicator-active-bg:                #fff;\n@carousel-indicator-border-color:             #fff;\n\n@carousel-caption-color:                      #fff;\n\n\n//== Close\n//\n//##\n\n@close-font-weight:           bold;\n@close-color:                 #000;\n@close-text-shadow:           0 1px 0 #fff;\n\n\n//== Code\n//\n//##\n\n@code-color:                  #c7254e;\n@code-bg:                     #f9f2f4;\n\n@kbd-color:                   #fff;\n@kbd-bg:                      #333;\n\n@pre-bg:                      #f5f5f5;\n@pre-color:                   @gray-dark;\n@pre-border-color:            #ccc;\n@pre-scrollable-max-height:   340px;\n\n\n//== Type\n//\n//##\n\n//** Text muted color\n@text-muted:                  @gray-light;\n//** Abbreviations and acronyms border color\n@abbr-border-color:           @gray-light;\n//** Headings small color\n@headings-small-color:        @gray-light;\n//** Blockquote small color\n@blockquote-small-color:      @gray-light;\n//** Blockquote font size\n@blockquote-font-size:        (@font-size-base * 1.25);\n//** Blockquote border color\n@blockquote-border-color:     @gray-lighter;\n//** Page header border color\n@page-header-border-color:    @gray-lighter;\n\n\n//== Miscellaneous\n//\n//##\n\n//** Horizontal line color.\n@hr-border:                   @gray-lighter;\n\n//** Horizontal offset for forms and lists.\n@component-offset-horizontal: 180px;\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n  display: block;\n  padding: @thumbnail-padding;\n  margin-bottom: @line-height-computed;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(all .2s ease-in-out);\n\n  > img,\n  a > img {\n    &:extend(.img-responsive);\n    margin-left: auto;\n    margin-right: auto;\n  }\n\n  // Add a hover state for linked versions only\n  a&:hover,\n  a&:focus,\n  a&.active {\n    border-color: @link-color;\n  }\n\n  // Image captions\n  .caption {\n    padding: @thumbnail-caption-padding;\n    color: @thumbnail-caption-color;\n  }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n  position: relative;\n}\n\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n\n  > .item {\n    display: none;\n    position: relative;\n    .transition(.6s ease-in-out left);\n\n    // Account for jankitude on images\n    > img,\n    > a > img {\n      &:extend(.img-responsive);\n      line-height: 1;\n    }\n  }\n\n  > .active,\n  > .next,\n  > .prev { display: block; }\n\n  > .active {\n    left: 0;\n  }\n\n  > .next,\n  > .prev {\n    position: absolute;\n    top: 0;\n    width: 100%;\n  }\n\n  > .next {\n    left: 100%;\n  }\n  > .prev {\n    left: -100%;\n  }\n  > .next.left,\n  > .prev.right {\n    left: 0;\n  }\n\n  > .active.left {\n    left: -100%;\n  }\n  > .active.right {\n    left: 100%;\n  }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: @carousel-control-width;\n  .opacity(@carousel-control-opacity);\n  font-size: @carousel-control-font-size;\n  color: @carousel-control-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  // We can't have this transition here because WebKit cancels the carousel\n  // animation if you trip this while in the middle of another animation.\n\n  // Set gradients for backgrounds\n  &.left {\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n  }\n  &.right {\n    left: auto;\n    right: 0;\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n  }\n\n  // Hover/focus state\n  &:hover,\n  &:focus {\n    outline: none;\n    color: @carousel-control-color;\n    text-decoration: none;\n    .opacity(.9);\n  }\n\n  // Toggles\n  .icon-prev,\n  .icon-next,\n  .glyphicon-chevron-left,\n  .glyphicon-chevron-right {\n    position: absolute;\n    top: 50%;\n    z-index: 5;\n    display: inline-block;\n  }\n  .icon-prev,\n  .glyphicon-chevron-left {\n    left: 50%;\n  }\n  .icon-next,\n  .glyphicon-chevron-right {\n    right: 50%;\n  }\n  .icon-prev,\n  .icon-next {\n    width:  20px;\n    height: 20px;\n    margin-top: -10px;\n    margin-left: -10px;\n    font-family: serif;\n  }\n\n  .icon-prev {\n    &:before {\n      content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n    }\n  }\n  .icon-next {\n    &:before {\n      content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n    }\n  }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n\n  li {\n    display: inline-block;\n    width:  10px;\n    height: 10px;\n    margin: 1px;\n    text-indent: -999px;\n    border: 1px solid @carousel-indicator-border-color;\n    border-radius: 10px;\n    cursor: pointer;\n\n    // IE8-9 hack for event handling\n    //\n    // Internet Explorer 8-9 does not support clicks on elements without a set\n    // `background-color`. We cannot use `filter` since that's not viewed as a\n    // background color by the browser. Thus, a hack is needed.\n    //\n    // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n    // set alpha transparency for the best results possible.\n    background-color: #000 \\9; // IE8\n    background-color: rgba(0,0,0,0); // IE9\n  }\n  .active {\n    margin: 0;\n    width:  12px;\n    height: 12px;\n    background-color: @carousel-indicator-active-bg;\n  }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: @carousel-caption-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  & .btn {\n    text-shadow: none; // No shadow for button elements in carousel-caption\n  }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n  // Scale up the controls a smidge\n  .carousel-control {\n    .glyphicon-chevron-left,\n    .glyphicon-chevron-right,\n    .icon-prev,\n    .icon-next {\n      width: 30px;\n      height: 30px;\n      margin-top: -15px;\n      margin-left: -15px;\n      font-size: 30px;\n    }\n  }\n\n  // Show and left align the captions\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n\n  // Move up the indicators\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n  font-family: @headings-font-family;\n  font-weight: @headings-font-weight;\n  line-height: @headings-line-height;\n  color: @headings-color;\n\n  small,\n  .small {\n    font-weight: normal;\n    line-height: 1;\n    color: @headings-small-color;\n  }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n  margin-top: @line-height-computed;\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 65%;\n  }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n  margin-top: (@line-height-computed / 2);\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 75%;\n  }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n  margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n  margin-bottom: @line-height-computed;\n  font-size: floor((@font-size-base * 1.15));\n  font-weight: 200;\n  line-height: 1.4;\n\n  @media (min-width: @screen-sm-min) {\n    font-size: (@font-size-base * 1.5);\n  }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: 14px base font * 85% = about 12px\nsmall,\n.small  { font-size: 85%; }\n\n// Undo browser default styling\ncite    { font-style: normal; }\n\n// Alignment\n.text-left           { text-align: left; }\n.text-right          { text-align: right; }\n.text-center         { text-align: center; }\n.text-justify        { text-align: justify; }\n\n// Contextual colors\n.text-muted {\n  color: @text-muted;\n}\n.text-primary {\n  .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n  .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n  .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n  .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n  .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n  // Given the contrast here, this is the only class to have its color inverted\n  // automatically.\n  color: #fff;\n  .bg-variant(@brand-primary);\n}\n.bg-success {\n  .bg-variant(@state-success-bg);\n}\n.bg-info {\n  .bg-variant(@state-info-bg);\n}\n.bg-warning {\n  .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n  .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n  padding-bottom: ((@line-height-computed / 2) - 1);\n  margin: (@line-height-computed * 2) 0 @line-height-computed;\n  border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// --------------------------------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n  margin-top: 0;\n  margin-bottom: (@line-height-computed / 2);\n  ul,\n  ol {\n    margin-bottom: 0;\n  }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n  .list-unstyled();\n  margin-left: -5px;\n\n  > li {\n    display: inline-block;\n    padding-left: 5px;\n    padding-right: 5px;\n  }\n}\n\n// Description Lists\ndl {\n  margin-top: 0; // Remove browser default\n  margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n  line-height: @line-height-base;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n@media (min-width: @grid-float-breakpoint) {\n  .dl-horizontal {\n    dt {\n      float: left;\n      width: (@component-offset-horizontal - 20);\n      clear: left;\n      text-align: right;\n      .text-overflow();\n    }\n    dd {\n      margin-left: @component-offset-horizontal;\n      &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n    }\n  }\n}\n\n// MISC\n// ----\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\n// Blockquotes\nblockquote {\n  padding: (@line-height-computed / 2) @line-height-computed;\n  margin: 0 0 @line-height-computed;\n  font-size: @blockquote-font-size;\n  border-left: 5px solid @blockquote-border-color;\n\n  p,\n  ul,\n  ol {\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  // Note: Deprecated small and .small as of v3.1.0\n  // Context: https://github.com/twbs/bootstrap/issues/11660\n  footer,\n  small,\n  .small {\n    display: block;\n    font-size: 80%; // back to default font-size\n    line-height: @line-height-base;\n    color: @blockquote-small-color;\n\n    &:before {\n      content: '\\2014 \\00A0'; // em dash, nbsp\n    }\n  }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid @blockquote-border-color;\n  border-left: 0;\n  text-align: right;\n\n  // Account for citation\n  footer,\n  small,\n  .small {\n    &:before { content: ''; }\n    &:after {\n      content: '\\00A0 \\2014'; // nbsp, em dash\n    }\n  }\n}\n\n// Quotes\nblockquote:before,\nblockquote:after {\n  content: \"\";\n}\n\n// Addresses\naddress {\n  margin-bottom: @line-height-computed;\n  font-style: normal;\n  line-height: @line-height-base;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n  font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @code-color;\n  background-color: @code-bg;\n  white-space: nowrap;\n  border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @kbd-color;\n  background-color: @kbd-bg;\n  border-radius: @border-radius-small;\n  box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n}\n\n// Blocks of code\npre {\n  display: block;\n  padding: ((@line-height-computed - 1) / 2);\n  margin: 0 0 (@line-height-computed / 2);\n  font-size: (@font-size-base - 1); // 14px to 13px\n  line-height: @line-height-base;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: @pre-color;\n  background-color: @pre-bg;\n  border: 1px solid @pre-border-color;\n  border-radius: @border-radius-base;\n\n  // Account for some code outputs that place code tags in pre tags\n  code {\n    padding: 0;\n    font-size: inherit;\n    color: inherit;\n    white-space: pre-wrap;\n    background-color: transparent;\n    border-radius: 0;\n  }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n  max-height: @pre-scrollable-max-height;\n  overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n  .container-fixed();\n\n  @media (min-width: @screen-sm-min) {\n    width: @container-sm;\n  }\n  @media (min-width: @screen-md-min) {\n    width: @container-md;\n  }\n  @media (min-width: @screen-lg-min) {\n    width: @container-lg;\n  }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n  .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n  .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n  .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n  .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n  .make-grid(lg);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n  max-width: 100%;\n  background-color: @table-bg;\n}\nth {\n  text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n  width: 100%;\n  margin-bottom: @line-height-computed;\n  // Cells\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-cell-padding;\n        line-height: @line-height-base;\n        vertical-align: top;\n        border-top: 1px solid @table-border-color;\n      }\n    }\n  }\n  // Bottom align for column headings\n  > thead > tr > th {\n    vertical-align: bottom;\n    border-bottom: 2px solid @table-border-color;\n  }\n  // Remove top border from thead by default\n  > caption + thead,\n  > colgroup + thead,\n  > thead:first-child {\n    > tr:first-child {\n      > th,\n      > td {\n        border-top: 0;\n      }\n    }\n  }\n  // Account for multiple tbody instances\n  > tbody + tbody {\n    border-top: 2px solid @table-border-color;\n  }\n\n  // Nesting\n  .table {\n    background-color: @body-bg;\n  }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-condensed-cell-padding;\n      }\n    }\n  }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n  border: 1px solid @table-border-color;\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        border: 1px solid @table-border-color;\n      }\n    }\n  }\n  > thead > tr {\n    > th,\n    > td {\n      border-bottom-width: 2px;\n    }\n  }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n  > tbody > tr:nth-child(odd) {\n    > td,\n    > th {\n      background-color: @table-bg-accent;\n    }\n  }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n  > tbody > tr:hover {\n    > td,\n    > th {\n      background-color: @table-bg-hover;\n    }\n  }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n  position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n  float: none;\n  display: table-column;\n}\ntable {\n  td,\n  th {\n    &[class*=\"col-\"] {\n      position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n      float: none;\n      display: table-cell;\n    }\n  }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n@media (max-width: @screen-xs-max) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: (@line-height-computed * 0.75);\n    overflow-y: hidden;\n    overflow-x: scroll;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid @table-border-color;\n    -webkit-overflow-scrolling: touch;\n\n    // Tighten up spacing\n    > .table {\n      margin-bottom: 0;\n\n      // Ensure the content doesn't wrap\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th,\n          > td {\n            white-space: nowrap;\n          }\n        }\n      }\n    }\n\n    // Special overrides for the bordered tables\n    > .table-bordered {\n      border: 0;\n\n      // Nuke the appropriate borders so that the parent can handle them\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th:first-child,\n          > td:first-child {\n            border-left: 0;\n          }\n          > th:last-child,\n          > td:last-child {\n            border-right: 0;\n          }\n        }\n      }\n\n      // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n      // chances are there will be only one `tr` in a `thead` and that would\n      // remove the border altogether.\n      > tbody,\n      > tfoot {\n        > tr:last-child {\n          > th,\n          > td {\n            border-bottom: 0;\n          }\n        }\n      }\n\n    }\n  }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  // Chrome and Firefox set a `min-width: -webkit-min-content;` on fieldsets,\n  // so we reset that to ensure it behaves more like a standard block element.\n  // See https://github.com/twbs/bootstrap/issues/12359.\n  min-width: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: @line-height-computed;\n  font-size: (@font-size-base * 1.5);\n  line-height: inherit;\n  color: @legend-color;\n  border: 0;\n  border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n  display: inline-block;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n  .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9; /* IE8-9 */\n  line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n  display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  .tab-focus();\n}\n\n// Adjust output element\noutput {\n  display: block;\n  padding-top: (@padding-base-vertical + 1);\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n  display: block;\n  width: 100%;\n  height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n  background-color: @input-bg;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid @input-border;\n  border-radius: @input-border-radius;\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n  .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n  // Customize the `:focus` state to imitate native WebKit styles.\n  .form-control-focus();\n\n  // Placeholder\n  .placeholder();\n\n  // Disabled and read-only inputs\n  //\n  // HTML5 says that controls under a fieldset > legend:first-child won't be\n  // disabled if the fieldset is disabled. Due to implementation difficulty, we\n  // don't honor that edge case; we style them as disabled anyway.\n  &[disabled],\n  &[readonly],\n  fieldset[disabled] & {\n    cursor: not-allowed;\n    background-color: @input-bg-disabled;\n    opacity: 1; // iOS fix for unreadable disabled content\n  }\n\n  // Reset height for `textarea`s\n  textarea& {\n    height: auto;\n  }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n\n\n// Special styles for iOS date input\n//\n// In Mobile Safari, date inputs require a pixel line-height that matches the\n// given height of the input.\n\ninput[type=\"date\"] {\n  line-height: @input-height-base;\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n  margin-bottom: 15px;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n  display: block;\n  min-height: @line-height-computed; // clear the floating input if there is no label text\n  margin-top: 10px;\n  margin-bottom: 10px;\n  padding-left: 20px;\n  label {\n    display: inline;\n    font-weight: normal;\n    cursor: pointer;\n  }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"],\n.radio,\n.radio-inline,\n.checkbox,\n.checkbox-inline {\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: not-allowed;\n  }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n\n.input-sm {\n  .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n.input-lg {\n  .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n  // Enable absolute positioning\n  position: relative;\n\n  // Ensure icons don't overlap text\n  .form-control {\n    padding-right: (@input-height-base * 1.25);\n  }\n\n  // Feedback icon (requires .glyphicon classes)\n  .form-control-feedback {\n    position: absolute;\n    top: (@line-height-computed + 5); // Height of the `label` and its margin\n    right: 0;\n    display: block;\n    width: @input-height-base;\n    height: @input-height-base;\n    line-height: @input-height-base;\n    text-align: center;\n  }\n}\n\n// Feedback states\n.has-success {\n  .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n  .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n  .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n  margin-bottom: 0; // Remove default margin from `p`\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n  display: block; // account for any element using help-block\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n  // Kick in the inline\n  @media (min-width: @screen-sm-min) {\n    // Inline-block all the things for \"inline\"\n    .form-group {\n      display: inline-block;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // In navbar-form, allow folks to *not* use `.form-group`\n    .form-control {\n      display: inline-block;\n      width: auto; // Prevent labels from stacking above inputs in `.form-group`\n      vertical-align: middle;\n    }\n    // Input groups need that 100% width though\n    .input-group > .form-control {\n      width: 100%;\n    }\n\n    .control-label {\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // Remove default margin on radios/checkboxes that were used for stacking, and\n    // then undo the floating of radios and checkboxes to match (which also avoids\n    // a bug in WebKit: https://github.com/twbs/bootstrap/issues/1969).\n    .radio,\n    .checkbox {\n      display: inline-block;\n      margin-top: 0;\n      margin-bottom: 0;\n      padding-left: 0;\n      vertical-align: middle;\n    }\n    .radio input[type=\"radio\"],\n    .checkbox input[type=\"checkbox\"] {\n      float: none;\n      margin-left: 0;\n    }\n\n    // Validation states\n    //\n    // Reposition the icon because it's now within a grid column and columns have\n    // `position: relative;` on them. Also accounts for the grid gutter padding.\n    .has-feedback .form-control-feedback {\n      top: 0;\n    }\n  }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n  // Consistent vertical alignment of labels, radios, and checkboxes\n  .control-label,\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline {\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n  }\n  // Account for padding we're adding to ensure the alignment and of help text\n  // and other content below items\n  .radio,\n  .checkbox {\n    min-height: (@line-height-computed + (@padding-base-vertical + 1));\n  }\n\n  // Make form groups behave like rows\n  .form-group {\n    .make-row();\n  }\n\n  .form-control-static {\n    padding-top: (@padding-base-vertical + 1);\n  }\n\n  // Only right align form labels here when the columns stop stacking\n  @media (min-width: @screen-sm-min) {\n    .control-label {\n      text-align: right;\n    }\n  }\n\n  // Validation states\n  //\n  // Reposition the icon because it's now within a grid column and columns have\n  // `position: relative;` on them. Also accounts for the grid gutter padding.\n  .has-feedback .form-control-feedback {\n    top: 0;\n    right: (@grid-gutter-width / 2);\n  }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n  display: inline-block;\n  margin-bottom: 0; // For input.btn\n  font-weight: @btn-font-weight;\n  text-align: center;\n  vertical-align: middle;\n  cursor: pointer;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  white-space: nowrap;\n  .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);\n  .user-select(none);\n\n  &,\n  &:active,\n  &.active {\n    &:focus {\n      .tab-focus();\n    }\n  }\n\n  &:hover,\n  &:focus {\n    color: @btn-default-color;\n    text-decoration: none;\n  }\n\n  &:active,\n  &.active {\n    outline: 0;\n    background-image: none;\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: not-allowed;\n    pointer-events: none; // Future-proof disabling of clicks\n    .opacity(.65);\n    .box-shadow(none);\n  }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n  .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n  .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n  .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n  .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n  .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n  .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n  color: @link-color;\n  font-weight: normal;\n  cursor: pointer;\n  border-radius: 0;\n\n  &,\n  &:active,\n  &[disabled],\n  fieldset[disabled] & {\n    background-color: transparent;\n    .box-shadow(none);\n  }\n  &,\n  &:hover,\n  &:focus,\n  &:active {\n    border-color: transparent;\n  }\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: underline;\n    background-color: transparent;\n  }\n  &[disabled],\n  fieldset[disabled] & {\n    &:hover,\n    &:focus {\n      color: @btn-link-disabled-color;\n      text-decoration: none;\n    }\n  }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n  // line-height: ensure even-numbered height of button next to large input\n  .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n.btn-sm {\n  // line-height: ensure proper height of button next to small input\n  .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n.btn-xs {\n  .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n  display: block;\n  width: 100%;\n  padding-left: 0;\n  padding-right: 0;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n  &.btn-block {\n    width: 100%;\n  }\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle; // match .btn alignment given font-size hack above\n  > .btn {\n    position: relative;\n    float: left;\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active,\n    &.active {\n      z-index: 2;\n    }\n    &:focus {\n      // Remove focus outline when dropdown JS adds it after closing the menu\n      outline: none;\n    }\n  }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n  .btn + .btn,\n  .btn + .btn-group,\n  .btn-group + .btn,\n  .btn-group + .btn-group {\n    margin-left: -1px;\n  }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n  margin-left: -5px; // Offset the first child's margin\n  &:extend(.clearfix all);\n\n  .btn-group,\n  .input-group {\n    float: left;\n  }\n  > .btn,\n  > .btn-group,\n  > .input-group {\n    margin-left: 5px;\n  }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  &:not(:last-child):not(.dropdown-toggle) {\n    .border-right-radius(0);\n  }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-right-radius(0);\n  }\n}\n.btn-group > .btn-group:last-child > .btn:first-child {\n  .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n  .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n  // Show no shadow for `.btn-link` since it has no other button styles.\n  &.btn-link {\n    .box-shadow(none);\n  }\n}\n\n\n// Reposition the caret\n.btn .caret {\n  margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n  border-width: @caret-width-large @caret-width-large 0;\n  border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n  border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n  > .btn,\n  > .btn-group,\n  > .btn-group > .btn {\n    display: block;\n    float: none;\n    width: 100%;\n    max-width: 100%;\n  }\n\n  // Clear floats so dropdown menus can be properly placed\n  > .btn-group {\n    &:extend(.clearfix all);\n    > .btn {\n      float: none;\n    }\n  }\n\n  > .btn + .btn,\n  > .btn + .btn-group,\n  > .btn-group + .btn,\n  > .btn-group + .btn-group {\n    margin-top: -1px;\n    margin-left: 0;\n  }\n}\n\n.btn-group-vertical > .btn {\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n  &:first-child:not(:last-child) {\n    border-top-right-radius: @border-radius-base;\n    .border-bottom-radius(0);\n  }\n  &:last-child:not(:first-child) {\n    border-bottom-left-radius: @border-radius-base;\n    .border-top-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-bottom-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  .border-top-radius(0);\n}\n\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n  > .btn,\n  > .btn-group {\n    float: none;\n    display: table-cell;\n    width: 1%;\n  }\n  > .btn-group .btn {\n    width: 100%;\n  }\n}\n\n\n// Checkbox and radio options\n[data-toggle=\"buttons\"] > .btn > input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn > input[type=\"checkbox\"] {\n  display: none;\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twitter/bootstrap/pull/3552.\n\n.fade {\n  opacity: 0;\n  .transition(opacity .15s linear);\n  &.in {\n    opacity: 1;\n  }\n}\n\n.collapse {\n  display: none;\n  &.in {\n    display: block;\n  }\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  .transition(height .35s ease);\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// <a href=\"#\"><span class=\"glyphicon glyphicon-star\"></span> Star</a>\n\n// Import the fonts\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: ~\"url('@{icon-font-path}@{icon-font-name}.eot')\";\n  src: ~\"url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype')\",\n       ~\"url('@{icon-font-path}@{icon-font-name}.woff') format('woff')\",\n       ~\"url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype')\",\n       ~\"url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg')\";\n}\n\n// Catchall baseclass\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk               { &:before { content: \"\\2a\"; } }\n.glyphicon-plus                   { &:before { content: \"\\2b\"; } }\n.glyphicon-euro                   { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus                  { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud                  { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope               { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil                 { &:before { content: \"\\270f\"; } }\n.glyphicon-glass                  { &:before { content: \"\\e001\"; } }\n.glyphicon-music                  { &:before { content: \"\\e002\"; } }\n.glyphicon-search                 { &:before { content: \"\\e003\"; } }\n.glyphicon-heart                  { &:before { content: \"\\e005\"; } }\n.glyphicon-star                   { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty             { &:before { content: \"\\e007\"; } }\n.glyphicon-user                   { &:before { content: \"\\e008\"; } }\n.glyphicon-film                   { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large               { &:before { content: \"\\e010\"; } }\n.glyphicon-th                     { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list                { &:before { content: \"\\e012\"; } }\n.glyphicon-ok                     { &:before { content: \"\\e013\"; } }\n.glyphicon-remove                 { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in                { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out               { &:before { content: \"\\e016\"; } }\n.glyphicon-off                    { &:before { content: \"\\e017\"; } }\n.glyphicon-signal                 { &:before { content: \"\\e018\"; } }\n.glyphicon-cog                    { &:before { content: \"\\e019\"; } }\n.glyphicon-trash                  { &:before { content: \"\\e020\"; } }\n.glyphicon-home                   { &:before { content: \"\\e021\"; } }\n.glyphicon-file                   { &:before { content: \"\\e022\"; } }\n.glyphicon-time                   { &:before { content: \"\\e023\"; } }\n.glyphicon-road                   { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt           { &:before { content: \"\\e025\"; } }\n.glyphicon-download               { &:before { content: \"\\e026\"; } }\n.glyphicon-upload                 { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox                  { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle            { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat                 { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh                { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt               { &:before { content: \"\\e032\"; } }\n.glyphicon-lock                   { &:before { content: \"\\e033\"; } }\n.glyphicon-flag                   { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones             { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off             { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down            { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up              { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode                 { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode                { &:before { content: \"\\e040\"; } }\n.glyphicon-tag                    { &:before { content: \"\\e041\"; } }\n.glyphicon-tags                   { &:before { content: \"\\e042\"; } }\n.glyphicon-book                   { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark               { &:before { content: \"\\e044\"; } }\n.glyphicon-print                  { &:before { content: \"\\e045\"; } }\n.glyphicon-camera                 { &:before { content: \"\\e046\"; } }\n.glyphicon-font                   { &:before { content: \"\\e047\"; } }\n.glyphicon-bold                   { &:before { content: \"\\e048\"; } }\n.glyphicon-italic                 { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height            { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width             { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left             { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center           { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right            { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify          { &:before { content: \"\\e055\"; } }\n.glyphicon-list                   { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left            { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right           { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video         { &:before { content: \"\\e059\"; } }\n.glyphicon-picture                { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker             { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust                 { &:before { content: \"\\e063\"; } }\n.glyphicon-tint                   { &:before { content: \"\\e064\"; } }\n.glyphicon-edit                   { &:before { content: \"\\e065\"; } }\n.glyphicon-share                  { &:before { content: \"\\e066\"; } }\n.glyphicon-check                  { &:before { content: \"\\e067\"; } }\n.glyphicon-move                   { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward          { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward          { &:before { content: \"\\e070\"; } }\n.glyphicon-backward               { &:before { content: \"\\e071\"; } }\n.glyphicon-play                   { &:before { content: \"\\e072\"; } }\n.glyphicon-pause                  { &:before { content: \"\\e073\"; } }\n.glyphicon-stop                   { &:before { content: \"\\e074\"; } }\n.glyphicon-forward                { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward           { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward           { &:before { content: \"\\e077\"; } }\n.glyphicon-eject                  { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left           { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right          { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign              { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign             { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign            { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign                { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign          { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign              { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot             { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle          { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle              { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle             { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left             { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right            { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up               { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down             { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt              { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full            { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small           { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign       { &:before { content: \"\\e101\"; } }\n.glyphicon-gift                   { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf                   { &:before { content: \"\\e103\"; } }\n.glyphicon-fire                   { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open               { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close              { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign           { &:before { content: \"\\e107\"; } }\n.glyphicon-plane                  { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar               { &:before { content: \"\\e109\"; } }\n.glyphicon-random                 { &:before { content: \"\\e110\"; } }\n.glyphicon-comment                { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet                 { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up             { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down           { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet                { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart          { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close           { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open            { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical        { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal      { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd                    { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn               { &:before { content: \"\\e122\"; } }\n.glyphicon-bell                   { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate            { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up              { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down            { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right             { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left              { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up                { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down              { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right     { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left      { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up        { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down      { &:before { content: \"\\e134\"; } }\n.glyphicon-globe                  { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench                 { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks                  { &:before { content: \"\\e137\"; } }\n.glyphicon-filter                 { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase              { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen             { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard              { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip              { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty            { &:before { content: \"\\e143\"; } }\n.glyphicon-link                   { &:before { content: \"\\e144\"; } }\n.glyphicon-phone                  { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin                { &:before { content: \"\\e146\"; } }\n.glyphicon-usd                    { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp                    { &:before { content: \"\\e149\"; } }\n.glyphicon-sort                   { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet       { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt   { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order          { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt      { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes     { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked              { &:before { content: \"\\e157\"; } }\n.glyphicon-expand                 { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down          { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up            { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in                 { &:before { content: \"\\e161\"; } }\n.glyphicon-flash                  { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out                { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window             { &:before { content: \"\\e164\"; } }\n.glyphicon-record                 { &:before { content: \"\\e165\"; } }\n.glyphicon-save                   { &:before { content: \"\\e166\"; } }\n.glyphicon-open                   { &:before { content: \"\\e167\"; } }\n.glyphicon-saved                  { &:before { content: \"\\e168\"; } }\n.glyphicon-import                 { &:before { content: \"\\e169\"; } }\n.glyphicon-export                 { &:before { content: \"\\e170\"; } }\n.glyphicon-send                   { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk            { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved           { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove          { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save            { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open            { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card            { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer               { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery                { &:before { content: \"\\e179\"; } }\n.glyphicon-header                 { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed             { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone               { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt              { &:before { content: \"\\e183\"; } }\n.glyphicon-tower                  { &:before { content: \"\\e184\"; } }\n.glyphicon-stats                  { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video               { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video               { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles              { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo           { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby            { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1              { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1              { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1              { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark         { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark      { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download         { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload           { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer           { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous         { &:before { content: \"\\e200\"; } }\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top:   @caret-width-base solid;\n  border-right: @caret-width-base solid transparent;\n  border-left:  @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropdown {\n  position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n  outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: @zindex-dropdown;\n  display: none; // none by default, but block on \"open\" of the menu\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0; // override default ul\n  list-style: none;\n  font-size: @font-size-base;\n  background-color: @dropdown-bg;\n  border: 1px solid @dropdown-fallback-border; // IE8 fallback\n  border: 1px solid @dropdown-border;\n  border-radius: @border-radius-base;\n  .box-shadow(0 6px 12px rgba(0,0,0,.175));\n  background-clip: padding-box;\n\n  // Aligns the dropdown menu to right\n  //\n  // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n  &.pull-right {\n    right: 0;\n    left: auto;\n  }\n\n  // Dividers (basically an hr) within the dropdown\n  .divider {\n    .nav-divider(@dropdown-divider-bg);\n  }\n\n  // Links within the dropdown menu\n  > li > a {\n    display: block;\n    padding: 3px 20px;\n    clear: both;\n    font-weight: normal;\n    line-height: @line-height-base;\n    color: @dropdown-link-color;\n    white-space: nowrap; // prevent links from randomly breaking onto new lines\n  }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    color: @dropdown-link-hover-color;\n    background-color: @dropdown-link-hover-bg;\n  }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-active-color;\n    text-decoration: none;\n    outline: 0;\n    background-color: @dropdown-link-active-bg;\n  }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-disabled-color;\n  }\n}\n// Nuke hover/focus effects\n.dropdown-menu > .disabled > a {\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    background-color: transparent;\n    background-image: none; // Remove CSS gradient\n    .reset-filter();\n    cursor: not-allowed;\n  }\n}\n\n// Open state for the dropdown\n.open {\n  // Show the menu\n  > .dropdown-menu {\n    display: block;\n  }\n\n  // Remove the outline when :focus is triggered\n  > a {\n    outline: 0;\n  }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n  left: auto; // Reset the default from `.dropdown-menu`\n  right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: @font-size-small;\n  line-height: @line-height-base;\n  color: @dropdown-header-color;\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n  // Reverse the caret\n  .caret {\n    border-top: 0;\n    border-bottom: @caret-width-base solid;\n    content: \"\";\n  }\n  // Different positioning for bottom up menu\n  .dropdown-menu {\n    top: auto;\n    bottom: 100%;\n    margin-bottom: 1px;\n  }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-right {\n    .dropdown-menu {\n      .dropdown-menu-right();\n    }\n    // Necessary for overrides of the default right aligned menu.\n    // Will remove come v4 in all likelihood.\n    .dropdown-menu-left {\n      .dropdown-menu-left();\n    }\n  }\n}\n\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n  position: relative; // For dropdowns\n  display: table;\n  border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n  // Undo padding and float of grid classes\n  &[class*=\"col-\"] {\n    float: none;\n    padding-left: 0;\n    padding-right: 0;\n  }\n\n  .form-control {\n    // Ensure that the input is always above the *appended* addon button for\n    // proper border colors.\n    position: relative;\n    z-index: 2;\n\n    // IE9 fubars the placeholder attribute in text inputs and the arrows on\n    // select elements in input groups. To fix it, we float the input. Details:\n    // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n    float: left;\n\n    width: 100%;\n    margin-bottom: 0;\n  }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn { .input-lg(); }\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn { .input-sm(); }\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  font-weight: normal;\n  line-height: 1;\n  color: @input-color;\n  text-align: center;\n  background-color: @input-group-addon-bg;\n  border: 1px solid @input-group-addon-border-color;\n  border-radius: @border-radius-base;\n\n  // Sizing\n  &.input-sm {\n    padding: @padding-small-vertical @padding-small-horizontal;\n    font-size: @font-size-small;\n    border-radius: @border-radius-small;\n  }\n  &.input-lg {\n    padding: @padding-large-vertical @padding-large-horizontal;\n    font-size: @font-size-large;\n    border-radius: @border-radius-large;\n  }\n\n  // Nuke default margins from checkboxes and radios to vertically center within.\n  input[type=\"radio\"],\n  input[type=\"checkbox\"] {\n    margin-top: 0;\n  }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  .border-right-radius(0);\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  .border-left-radius(0);\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n  position: relative;\n  // Jankily prevent input button groups from wrapping with `white-space` and\n  // `font-size` in combination with `inline-block` on buttons.\n  font-size: 0;\n  white-space: nowrap;\n\n  // Negative margin for spacing, position for bringing hovered/focused/actived\n  // element above the siblings.\n  > .btn {\n    position: relative;\n    + .btn {\n      margin-left: -1px;\n    }\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active {\n      z-index: 2;\n    }\n  }\n\n  // Negative margin to only have a 1px border between the two\n  &:first-child {\n    > .btn,\n    > .btn-group {\n      margin-right: -1px;\n    }\n  }\n  &:last-child {\n    > .btn,\n    > .btn-group {\n      margin-left: -1px;\n    }\n  }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n  margin-bottom: 0;\n  padding-left: 0; // Override default ul/ol\n  list-style: none;\n  &:extend(.clearfix all);\n\n  > li {\n    position: relative;\n    display: block;\n\n    > a {\n      position: relative;\n      display: block;\n      padding: @nav-link-padding;\n      &:hover,\n      &:focus {\n        text-decoration: none;\n        background-color: @nav-link-hover-bg;\n      }\n    }\n\n    // Disabled state sets text to gray and nukes hover/tab effects\n    &.disabled > a {\n      color: @nav-disabled-link-color;\n\n      &:hover,\n      &:focus {\n        color: @nav-disabled-link-hover-color;\n        text-decoration: none;\n        background-color: transparent;\n        cursor: not-allowed;\n      }\n    }\n  }\n\n  // Open dropdowns\n  .open > a {\n    &,\n    &:hover,\n    &:focus {\n      background-color: @nav-link-hover-bg;\n      border-color: @link-color;\n    }\n  }\n\n  // Nav dividers (deprecated with v3.0.1)\n  //\n  // This should have been removed in v3 with the dropping of `.nav-list`, but\n  // we missed it. We don't currently support this anywhere, but in the interest\n  // of maintaining backward compatibility in case you use it, it's deprecated.\n  .nav-divider {\n    .nav-divider();\n  }\n\n  // Prevent IE8 from misplacing imgs\n  //\n  // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n  > li > a > img {\n    max-width: none;\n  }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n  border-bottom: 1px solid @nav-tabs-border-color;\n  > li {\n    float: left;\n    // Make the list-items overlay the bottom border\n    margin-bottom: -1px;\n\n    // Actual tabs (as links)\n    > a {\n      margin-right: 2px;\n      line-height: @line-height-base;\n      border: 1px solid transparent;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n      &:hover {\n        border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n      }\n    }\n\n    // Active state, and its :hover to override normal :hover\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-tabs-active-link-hover-color;\n        background-color: @nav-tabs-active-link-hover-bg;\n        border: 1px solid @nav-tabs-active-link-hover-border-color;\n        border-bottom-color: transparent;\n        cursor: default;\n      }\n    }\n  }\n  // pulling this in mainly for less shorthand\n  &.nav-justified {\n    .nav-justified();\n    .nav-tabs-justified();\n  }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n  > li {\n    float: left;\n\n    // Links rendered as pills\n    > a {\n      border-radius: @nav-pills-border-radius;\n    }\n    + li {\n      margin-left: 2px;\n    }\n\n    // Active state\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-pills-active-link-hover-color;\n        background-color: @nav-pills-active-link-hover-bg;\n      }\n    }\n  }\n}\n\n\n// Stacked pills\n.nav-stacked {\n  > li {\n    float: none;\n    + li {\n      margin-top: 2px;\n      margin-left: 0; // no need for this gap between nav items\n    }\n  }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n  width: 100%;\n\n  > li {\n    float: none;\n     > a {\n      text-align: center;\n      margin-bottom: 5px;\n    }\n  }\n\n  > .dropdown .dropdown-menu {\n    top: auto;\n    left: auto;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li {\n      display: table-cell;\n      width: 1%;\n      > a {\n        margin-bottom: 0;\n      }\n    }\n  }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n  border-bottom: 0;\n\n  > li > a {\n    // Override margin from .nav-tabs\n    margin-right: 0;\n    border-radius: @border-radius-base;\n  }\n\n  > .active > a,\n  > .active > a:hover,\n  > .active > a:focus {\n    border: 1px solid @nav-tabs-justified-link-border-color;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li > a {\n      border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n    }\n    > .active > a,\n    > .active > a:hover,\n    > .active > a:focus {\n      border-bottom-color: @nav-tabs-justified-active-link-border-color;\n    }\n  }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n  > .tab-pane {\n    display: none;\n  }\n  > .active {\n    display: block;\n  }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n  // make dropdown border overlap tab border\n  margin-top: -1px;\n  // Remove the top rounded corners here since there is a hard edge above the menu\n  .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n  position: relative;\n  min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n  margin-bottom: @navbar-margin-bottom;\n  border: 1px solid transparent;\n\n  // Prevent floats from breaking the navbar\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: @navbar-border-radius;\n  }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n  }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n  max-height: @navbar-collapse-max-height;\n  overflow-x: visible;\n  padding-right: @navbar-padding-horizontal;\n  padding-left:  @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n  &:extend(.clearfix all);\n  -webkit-overflow-scrolling: touch;\n\n  &.in {\n    overflow-y: auto;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n\n    &.collapse {\n      display: block !important;\n      height: auto !important;\n      padding-bottom: 0; // Override default setting\n      overflow: visible !important;\n    }\n\n    &.in {\n      overflow-y: visible;\n    }\n\n    // Undo the collapse side padding for navbars with containers to ensure\n    // alignment of right-aligned contents.\n    .navbar-fixed-top &,\n    .navbar-static-top &,\n    .navbar-fixed-bottom & {\n      padding-left: 0;\n      padding-right: 0;\n    }\n  }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n  > .navbar-header,\n  > .navbar-collapse {\n    margin-right: -@navbar-padding-horizontal;\n    margin-left:  -@navbar-padding-horizontal;\n\n    @media (min-width: @grid-float-breakpoint) {\n      margin-right: 0;\n      margin-left:  0;\n    }\n  }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n  z-index: @zindex-navbar;\n  border-width: 0 0 1px;\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: @zindex-navbar-fixed;\n\n  // Undo the rounded corners\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0; // override .navbar defaults\n  border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n  float: left;\n  padding: @navbar-padding-vertical @navbar-padding-horizontal;\n  font-size: @font-size-large;\n  line-height: @line-height-computed;\n  height: @navbar-height;\n  font-family: @font-family-brand;\n  font-weight: bold;\n\n  &:hover,\n  &:focus {\n    text-decoration: none;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    .navbar > .container &,\n    .navbar > .container-fluid & {\n      margin-left: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: @navbar-padding-horizontal;\n  padding: 9px 10px;\n  .navbar-vertical-align(34px);\n  background-color: transparent;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  border-radius: @border-radius-base;\n\n  // We remove the `outline` here, but later compensate by attaching `:hover`\n  // styles to `:focus`.\n  &:focus {\n    outline: none;\n  }\n\n  // Bars\n  .icon-bar {\n    display: block;\n    width: 22px;\n    height: 2px;\n    border-radius: 1px;\n  }\n  .icon-bar + .icon-bar {\n    margin-top: 4px;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    display: none;\n  }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n  margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n  > li > a {\n    padding-top:    10px;\n    padding-bottom: 10px;\n    line-height: @line-height-computed;\n  }\n\n  @media (max-width: @grid-float-breakpoint-max) {\n    // Dropdowns get custom display when collapsed\n    .open .dropdown-menu {\n      position: static;\n      float: none;\n      width: auto;\n      margin-top: 0;\n      background-color: transparent;\n      border: 0;\n      box-shadow: none;\n      > li > a,\n      .dropdown-header {\n        padding: 5px 15px 5px 25px;\n      }\n      > li > a {\n        line-height: @line-height-computed;\n        &:hover,\n        &:focus {\n          background-image: none;\n        }\n      }\n    }\n  }\n\n  // Uncollapse the nav\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin: 0;\n\n    > li {\n      float: left;\n      > a {\n        padding-top:    @navbar-padding-vertical;\n        padding-bottom: @navbar-padding-vertical;\n      }\n    }\n\n    &.navbar-right:last-child {\n      margin-right: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-left  { .pull-left(); }\n  .navbar-right { .pull-right(); }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n  margin-left: -@navbar-padding-horizontal;\n  margin-right: -@navbar-padding-horizontal;\n  padding: 10px @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n\n  // Mixin behavior for optimum display\n  .form-inline();\n\n  .form-group {\n    @media (max-width: @grid-float-breakpoint-max) {\n      margin-bottom: 5px;\n    }\n  }\n\n  // Vertically center in expanded, horizontal navbar\n  .navbar-vertical-align(@input-height-base);\n\n  // Undo 100% width for pull classes\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    .box-shadow(none);\n\n    // Outdent the form if last child to line up with content down the page\n    &.navbar-right:last-child {\n      margin-right: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n  .navbar-vertical-align(@input-height-base);\n\n  &.btn-sm {\n    .navbar-vertical-align(@input-height-small);\n  }\n  &.btn-xs {\n    .navbar-vertical-align(22);\n  }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n  .navbar-vertical-align(@line-height-computed);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin-left: @navbar-padding-horizontal;\n    margin-right: @navbar-padding-horizontal;\n\n    // Outdent the form if last child to line up with content down the page\n    &.navbar-right:last-child {\n      margin-right: 0;\n    }\n  }\n}\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  background-color: @navbar-default-bg;\n  border-color: @navbar-default-border;\n\n  .navbar-brand {\n    color: @navbar-default-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-default-brand-hover-color;\n      background-color: @navbar-default-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-default-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-default-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-hover-color;\n        background-color: @navbar-default-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-active-color;\n        background-color: @navbar-default-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-disabled-color;\n        background-color: @navbar-default-link-disabled-bg;\n      }\n    }\n  }\n\n  .navbar-toggle {\n    border-color: @navbar-default-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-default-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-default-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: @navbar-default-border;\n  }\n\n  // Dropdown menu items\n  .navbar-nav {\n    // Remove background color from open dropdown\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-default-link-active-bg;\n        color: @navbar-default-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display when collapsed\n      .open .dropdown-menu {\n        > li > a {\n          color: @navbar-default-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-hover-color;\n            background-color: @navbar-default-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-active-color;\n            background-color: @navbar-default-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-disabled-color;\n            background-color: @navbar-default-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n\n  // Links in navbars\n  //\n  // Add a class to ensure links outside the navbar nav are colored correctly.\n\n  .navbar-link {\n    color: @navbar-default-link-color;\n    &:hover {\n      color: @navbar-default-link-hover-color;\n    }\n  }\n\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n  background-color: @navbar-inverse-bg;\n  border-color: @navbar-inverse-border;\n\n  .navbar-brand {\n    color: @navbar-inverse-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-inverse-brand-hover-color;\n      background-color: @navbar-inverse-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-inverse-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-inverse-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-hover-color;\n        background-color: @navbar-inverse-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-active-color;\n        background-color: @navbar-inverse-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-disabled-color;\n        background-color: @navbar-inverse-link-disabled-bg;\n      }\n    }\n  }\n\n  // Darken the responsive nav toggle\n  .navbar-toggle {\n    border-color: @navbar-inverse-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-inverse-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-inverse-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: darken(@navbar-inverse-bg, 7%);\n  }\n\n  // Dropdowns\n  .navbar-nav {\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-inverse-link-active-bg;\n        color: @navbar-inverse-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display\n      .open .dropdown-menu {\n        > .dropdown-header {\n          border-color: @navbar-inverse-border;\n        }\n        .divider {\n          background-color: @navbar-inverse-border;\n        }\n        > li > a {\n          color: @navbar-inverse-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-hover-color;\n            background-color: @navbar-inverse-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-active-color;\n            background-color: @navbar-inverse-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-disabled-color;\n            background-color: @navbar-inverse-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n  .navbar-link {\n    color: @navbar-inverse-link-color;\n    &:hover {\n      color: @navbar-inverse-link-hover-color;\n    }\n  }\n\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n  .clearfix();\n}\n.center-block {\n  .center-block();\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n  display: none !important;\n  visibility: hidden !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n  position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n  padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n  margin-bottom: @line-height-computed;\n  list-style: none;\n  background-color: @breadcrumb-bg;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline-block;\n\n    + li:before {\n      content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n      padding: 0 5px;\n      color: @breadcrumb-color;\n    }\n  }\n\n  > .active {\n    color: @breadcrumb-active-color;\n  }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline; // Remove list-style and block-level defaults\n    > a,\n    > span {\n      position: relative;\n      float: left; // Collapse white-space\n      padding: @padding-base-vertical @padding-base-horizontal;\n      line-height: @line-height-base;\n      text-decoration: none;\n      color: @pagination-color;\n      background-color: @pagination-bg;\n      border: 1px solid @pagination-border;\n      margin-left: -1px;\n    }\n    &:first-child {\n      > a,\n      > span {\n        margin-left: 0;\n        .border-left-radius(@border-radius-base);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius-base);\n      }\n    }\n  }\n\n  > li > a,\n  > li > span {\n    &:hover,\n    &:focus {\n      color: @pagination-hover-color;\n      background-color: @pagination-hover-bg;\n      border-color: @pagination-hover-border;\n    }\n  }\n\n  > .active > a,\n  > .active > span {\n    &,\n    &:hover,\n    &:focus {\n      z-index: 2;\n      color: @pagination-active-color;\n      background-color: @pagination-active-bg;\n      border-color: @pagination-active-border;\n      cursor: default;\n    }\n  }\n\n  > .disabled {\n    > span,\n    > span:hover,\n    > span:focus,\n    > a,\n    > a:hover,\n    > a:focus {\n      color: @pagination-disabled-color;\n      background-color: @pagination-disabled-bg;\n      border-color: @pagination-disabled-border;\n      cursor: not-allowed;\n    }\n  }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n  .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n  .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  list-style: none;\n  text-align: center;\n  &:extend(.clearfix all);\n  li {\n    display: inline;\n    > a,\n    > span {\n      display: inline-block;\n      padding: 5px 14px;\n      background-color: @pager-bg;\n      border: 1px solid @pager-border;\n      border-radius: @pager-border-radius;\n    }\n\n    > a:hover,\n    > a:focus {\n      text-decoration: none;\n      background-color: @pager-hover-bg;\n    }\n  }\n\n  .next {\n    > a,\n    > span {\n      float: right;\n    }\n  }\n\n  .previous {\n    > a,\n    > span {\n      float: left;\n    }\n  }\n\n  .disabled {\n    > a,\n    > a:hover,\n    > a:focus,\n    > span {\n      color: @pager-disabled-color;\n      background-color: @pager-bg;\n      cursor: not-allowed;\n    }\n  }\n\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: @label-color;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n\n  // Add hover effects, but only for links\n  &[href] {\n    &:hover,\n    &:focus {\n      color: @label-link-hover-color;\n      text-decoration: none;\n      cursor: pointer;\n    }\n  }\n\n  // Empty labels collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for labels in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n  .label-variant(@label-default-bg);\n}\n\n.label-primary {\n  .label-variant(@label-primary-bg);\n}\n\n.label-success {\n  .label-variant(@label-success-bg);\n}\n\n.label-info {\n  .label-variant(@label-info-bg);\n}\n\n.label-warning {\n  .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n  .label-variant(@label-danger-bg);\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base classes\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: @font-size-small;\n  font-weight: @badge-font-weight;\n  color: @badge-color;\n  line-height: @badge-line-height;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: @badge-bg;\n  border-radius: @badge-border-radius;\n\n  // Empty badges collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for badges in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n  .btn-xs & {\n    top: 0;\n    padding: 1px 5px;\n  }\n}\n\n// Hover state, but only for links\na.badge {\n  &:hover,\n  &:focus {\n    color: @badge-link-hover-color;\n    text-decoration: none;\n    cursor: pointer;\n  }\n}\n\n// Account for counters in navs\na.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: @badge-active-color;\n  background-color: @badge-active-bg;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n  padding: @jumbotron-padding;\n  margin-bottom: @jumbotron-padding;\n  color: @jumbotron-color;\n  background-color: @jumbotron-bg;\n\n  h1,\n  .h1 {\n    color: @jumbotron-heading-color;\n  }\n  p {\n    margin-bottom: (@jumbotron-padding / 2);\n    font-size: @jumbotron-font-size;\n    font-weight: 200;\n  }\n\n  .container & {\n    border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n  }\n\n  .container {\n    max-width: 100%;\n  }\n\n  @media screen and (min-width: @screen-sm-min) {\n    padding-top:    (@jumbotron-padding * 1.6);\n    padding-bottom: (@jumbotron-padding * 1.6);\n\n    .container & {\n      padding-left:  (@jumbotron-padding * 2);\n      padding-right: (@jumbotron-padding * 2);\n    }\n\n    h1,\n    .h1 {\n      font-size: (@font-size-base * 4.5);\n    }\n  }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n  padding: @alert-padding;\n  margin-bottom: @line-height-computed;\n  border: 1px solid transparent;\n  border-radius: @alert-border-radius;\n\n  // Headings for larger alerts\n  h4 {\n    margin-top: 0;\n    // Specified for the h4 to prevent conflicts of changing @headings-color\n    color: inherit;\n  }\n  // Provide class for links that match alerts\n  .alert-link {\n    font-weight: @alert-link-font-weight;\n  }\n\n  // Improve alignment and spacing of inner content\n  > p,\n  > ul {\n    margin-bottom: 0;\n  }\n  > p + p {\n    margin-top: 5px;\n  }\n}\n\n// Dismissable alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable {\n padding-right: (@alert-padding + 20);\n\n  // Adjust close link position\n  .close {\n    position: relative;\n    top: -2px;\n    right: -21px;\n    color: inherit;\n  }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n  .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n.alert-info {\n  .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n.alert-warning {\n  .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n.alert-danger {\n  .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n  overflow: hidden;\n  height: @line-height-computed;\n  margin-bottom: @line-height-computed;\n  background-color: @progress-bg;\n  border-radius: @border-radius-base;\n  .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: @font-size-small;\n  line-height: @line-height-computed;\n  color: @progress-bar-color;\n  text-align: center;\n  background-color: @progress-bar-bg;\n  .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n  .transition(width .6s ease);\n}\n\n// Striped bars\n.progress-striped .progress-bar {\n  #gradient > .striped();\n  background-size: 40px 40px;\n}\n\n// Call animation for the active one\n.progress.active .progress-bar {\n  .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n  .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n  .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n  .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n  .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Media objects\n// Source: http://stubbornella.org/content/?p=497\n// --------------------------------------------------\n\n\n// Common styles\n// -------------------------\n\n// Clear the floats\n.media,\n.media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n\n// Proper spacing between instances of .media\n.media,\n.media .media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n\n// For images and videos, set to block\n.media-object {\n  display: block;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n  margin: 0 0 5px;\n}\n\n\n// Media image alignment\n// -------------------------\n\n.media {\n  > .pull-left {\n    margin-right: 10px;\n  }\n  > .pull-right {\n    margin-left: 10px;\n  }\n}\n\n\n// Media list variation\n// -------------------------\n\n// Undo default ul/ol styles\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n  // No need to set list-style: none; since .list-group-item is block level\n  margin-bottom: 20px;\n  padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  // Place the border on the list items and negative margin up for better styling\n  margin-bottom: -1px;\n  background-color: @list-group-bg;\n  border: 1px solid @list-group-border;\n\n  // Round the first and last items\n  &:first-child {\n    .border-top-radius(@list-group-border-radius);\n  }\n  &:last-child {\n    margin-bottom: 0;\n    .border-bottom-radius(@list-group-border-radius);\n  }\n\n  // Align badges within list items\n  > .badge {\n    float: right;\n  }\n  > .badge + .badge {\n    margin-right: 5px;\n  }\n}\n\n\n// Linked list items\n//\n// Use anchor elements instead of `li`s or `div`s to create linked list items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item {\n  color: @list-group-link-color;\n\n  .list-group-item-heading {\n    color: @list-group-link-heading-color;\n  }\n\n  // Hover state\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    background-color: @list-group-hover-bg;\n  }\n\n  // Active class on item itself, not parent\n  &.active,\n  &.active:hover,\n  &.active:focus {\n    z-index: 2; // Place active items above their siblings for proper border styling\n    color: @list-group-active-color;\n    background-color: @list-group-active-bg;\n    border-color: @list-group-active-border;\n\n    // Force color to inherit for custom content\n    .list-group-item-heading {\n      color: inherit;\n    }\n    .list-group-item-text {\n      color: @list-group-active-text-color;\n    }\n  }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n","//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n  margin-bottom: @line-height-computed;\n  background-color: @panel-bg;\n  border: 1px solid transparent;\n  border-radius: @panel-border-radius;\n  .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n  padding: @panel-body-padding;\n  &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  .border-top-radius((@panel-border-radius - 1));\n\n  > .dropdown .dropdown-toggle {\n    color: inherit;\n  }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: ceil((@font-size-base * 1.125));\n  color: inherit;\n\n  > a {\n    color: inherit;\n  }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n  padding: 10px 15px;\n  background-color: @panel-footer-bg;\n  border-top: 1px solid @panel-inner-border;\n  .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n  > .list-group {\n    margin-bottom: 0;\n\n    .list-group-item {\n      border-width: 1px 0;\n      border-radius: 0;\n    }\n\n    // Add border top radius for first one\n    &:first-child {\n      .list-group-item:first-child {\n        border-top: 0;\n        .border-top-radius((@panel-border-radius - 1));\n      }\n    }\n    // Add border bottom radius for last one\n    &:last-child {\n      .list-group-item:last-child {\n        border-bottom: 0;\n        .border-bottom-radius((@panel-border-radius - 1));\n      }\n    }\n  }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n  .list-group-item:first-child {\n    border-top-width: 0;\n  }\n}\n\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n  > .table,\n  > .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  // Add border top radius for first one\n  > .table:first-child,\n  > .table-responsive:first-child > .table:first-child {\n    .border-top-radius((@panel-border-radius - 1));\n\n    > thead:first-child,\n    > tbody:first-child {\n      > tr:first-child {\n        td:first-child,\n        th:first-child {\n          border-top-left-radius: (@panel-border-radius - 1);\n        }\n        td:last-child,\n        th:last-child {\n          border-top-right-radius: (@panel-border-radius - 1);\n        }\n      }\n    }\n  }\n  // Add border bottom radius for last one\n  > .table:last-child,\n  > .table-responsive:last-child > .table:last-child {\n    .border-bottom-radius((@panel-border-radius - 1));\n\n    > tbody:last-child,\n    > tfoot:last-child {\n      > tr:last-child {\n        td:first-child,\n        th:first-child {\n          border-bottom-left-radius: (@panel-border-radius - 1);\n        }\n        td:last-child,\n        th:last-child {\n          border-bottom-right-radius: (@panel-border-radius - 1);\n        }\n      }\n    }\n  }\n  > .panel-body + .table,\n  > .panel-body + .table-responsive {\n    border-top: 1px solid @table-border-color;\n  }\n  > .table > tbody:first-child > tr:first-child th,\n  > .table > tbody:first-child > tr:first-child td {\n    border-top: 0;\n  }\n  > .table-bordered,\n  > .table-responsive > .table-bordered {\n    border: 0;\n    > thead,\n    > tbody,\n    > tfoot {\n      > tr {\n        > th:first-child,\n        > td:first-child {\n          border-left: 0;\n        }\n        > th:last-child,\n        > td:last-child {\n          border-right: 0;\n        }\n      }\n    }\n    > thead,\n    > tbody {\n      > tr:first-child {\n        > td,\n        > th {\n          border-bottom: 0;\n        }\n      }\n    }\n    > tbody,\n    > tfoot {\n      > tr:last-child {\n        > td,\n        > th {\n          border-bottom: 0;\n        }\n      }\n    }\n  }\n  > .table-responsive {\n    border: 0;\n    margin-bottom: 0;\n  }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n  margin-bottom: @line-height-computed;\n\n  // Tighten up margin so it's only between panels\n  .panel {\n    margin-bottom: 0;\n    border-radius: @panel-border-radius;\n    overflow: hidden; // crop contents when collapsed\n    + .panel {\n      margin-top: 5px;\n    }\n  }\n\n  .panel-heading {\n    border-bottom: 0;\n    + .panel-collapse .panel-body {\n      border-top: 1px solid @panel-inner-border;\n    }\n  }\n  .panel-footer {\n    border-top: 0;\n    + .panel-collapse .panel-body {\n      border-bottom: 1px solid @panel-inner-border;\n    }\n  }\n}\n\n\n// Contextual variations\n.panel-default {\n  .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n  .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n  .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n  .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n  .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n  .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: @well-bg;\n  border: 1px solid @well-border;\n  border-radius: @border-radius-base;\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n  blockquote {\n    border-color: #ddd;\n    border-color: rgba(0,0,0,.15);\n  }\n}\n\n// Sizes\n.well-lg {\n  padding: 24px;\n  border-radius: @border-radius-large;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: @border-radius-small;\n}\n","//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n  float: right;\n  font-size: (@font-size-base * 1.5);\n  font-weight: @close-font-weight;\n  line-height: 1;\n  color: @close-color;\n  text-shadow: @close-text-shadow;\n  .opacity(.2);\n\n  &:hover,\n  &:focus {\n    color: @close-color;\n    text-decoration: none;\n    cursor: pointer;\n    .opacity(.5);\n  }\n\n  // Additional properties for button version\n  // iOS requires the button element instead of an anchor tag.\n  // If you want the anchor version, it requires `href=\"#\"`.\n  button& {\n    padding: 0;\n    cursor: pointer;\n    background: transparent;\n    border: 0;\n    -webkit-appearance: none;\n  }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open      - body class for killing the scroll\n// .modal           - container to scroll within\n// .modal-dialog    - positioning shell for the actual modal\n// .modal-content   - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n  overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n  display: none;\n  overflow: auto;\n  overflow-y: scroll;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-modal;\n  -webkit-overflow-scrolling: touch;\n\n  // Prevent Chrome on Windows from adding a focus outline. For details, see\n  // https://github.com/twbs/bootstrap/pull/10951.\n  outline: 0;\n\n  // When fading in the modal, animate it to slide down\n  &.fade .modal-dialog {\n    .translate(0, -25%);\n    .transition-transform(~\"0.3s ease-out\");\n  }\n  &.in .modal-dialog { .translate(0, 0)}\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n  position: relative;\n  background-color: @modal-content-bg;\n  border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n  border: 1px solid @modal-content-border-color;\n  border-radius: @border-radius-large;\n  .box-shadow(0 3px 9px rgba(0,0,0,.5));\n  background-clip: padding-box;\n  // Remove focus outline from opened modal\n  outline: none;\n}\n\n// Modal background\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-modal-background;\n  background-color: @modal-backdrop-bg;\n  // Fade for backdrop\n  &.fade { .opacity(0); }\n  &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n  padding: @modal-title-padding;\n  border-bottom: 1px solid @modal-header-border-color;\n  min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n  margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n  margin: 0;\n  line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n  position: relative;\n  padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n  margin-top: 15px;\n  padding: (@modal-inner-padding - 1) @modal-inner-padding @modal-inner-padding;\n  text-align: right; // right align buttons\n  border-top: 1px solid @modal-footer-border-color;\n  &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n  // Properly space out buttons\n  .btn + .btn {\n    margin-left: 5px;\n    margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n  }\n  // but override that for button groups\n  .btn-group .btn + .btn {\n    margin-left: -1px;\n  }\n  // and override it for block buttons as well\n  .btn-block + .btn-block {\n    margin-left: 0;\n  }\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n  // Automatically set modal's width for larger viewports\n  .modal-dialog {\n    width: @modal-md;\n    margin: 30px auto;\n  }\n  .modal-content {\n    .box-shadow(0 5px 15px rgba(0,0,0,.5));\n  }\n\n  // Modal sizes\n  .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n  .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n  position: absolute;\n  z-index: @zindex-tooltip;\n  display: block;\n  visibility: visible;\n  font-size: @font-size-small;\n  line-height: 1.4;\n  .opacity(0);\n\n  &.in     { .opacity(@tooltip-opacity); }\n  &.top    { margin-top:  -3px; padding: @tooltip-arrow-width 0; }\n  &.right  { margin-left:  3px; padding: 0 @tooltip-arrow-width; }\n  &.bottom { margin-top:   3px; padding: @tooltip-arrow-width 0; }\n  &.left   { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n  max-width: @tooltip-max-width;\n  padding: 3px 8px;\n  color: @tooltip-color;\n  text-align: center;\n  text-decoration: none;\n  background-color: @tooltip-bg;\n  border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.tooltip {\n  &.top .tooltip-arrow {\n    bottom: 0;\n    left: 50%;\n    margin-left: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.top-left .tooltip-arrow {\n    bottom: 0;\n    left: @tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.top-right .tooltip-arrow {\n    bottom: 0;\n    right: @tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.right .tooltip-arrow {\n    top: 50%;\n    left: 0;\n    margin-top: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-right-color: @tooltip-arrow-color;\n  }\n  &.left .tooltip-arrow {\n    top: 50%;\n    right: 0;\n    margin-top: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-left-color: @tooltip-arrow-color;\n  }\n  &.bottom .tooltip-arrow {\n    top: 0;\n    left: 50%;\n    margin-left: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n  &.bottom-left .tooltip-arrow {\n    top: 0;\n    left: @tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n  &.bottom-right .tooltip-arrow {\n    top: 0;\n    right: @tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: @zindex-popover;\n  display: none;\n  max-width: @popover-max-width;\n  padding: 1px;\n  text-align: left; // Reset given new insertion method\n  background-color: @popover-bg;\n  background-clip: padding-box;\n  border: 1px solid @popover-fallback-border-color;\n  border: 1px solid @popover-border-color;\n  border-radius: @border-radius-large;\n  .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n  // Overrides for proper insertion\n  white-space: normal;\n\n  // Offset the popover to account for the popover arrow\n  &.top     { margin-top: -@popover-arrow-width; }\n  &.right   { margin-left: @popover-arrow-width; }\n  &.bottom  { margin-top: @popover-arrow-width; }\n  &.left    { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n  margin: 0; // reset heading margin\n  padding: 8px 14px;\n  font-size: @font-size-base;\n  font-weight: normal;\n  line-height: 18px;\n  background-color: @popover-title-bg;\n  border-bottom: 1px solid darken(@popover-title-bg, 5%);\n  border-radius: 5px 5px 0 0;\n}\n\n.popover-content {\n  padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n  &,\n  &:after {\n    position: absolute;\n    display: block;\n    width: 0;\n    height: 0;\n    border-color: transparent;\n    border-style: solid;\n  }\n}\n.popover > .arrow {\n  border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n  border-width: @popover-arrow-width;\n  content: \"\";\n}\n\n.popover {\n  &.top > .arrow {\n    left: 50%;\n    margin-left: -@popover-arrow-outer-width;\n    border-bottom-width: 0;\n    border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-top-color: @popover-arrow-outer-color;\n    bottom: -@popover-arrow-outer-width;\n    &:after {\n      content: \" \";\n      bottom: 1px;\n      margin-left: -@popover-arrow-width;\n      border-bottom-width: 0;\n      border-top-color: @popover-arrow-color;\n    }\n  }\n  &.right > .arrow {\n    top: 50%;\n    left: -@popover-arrow-outer-width;\n    margin-top: -@popover-arrow-outer-width;\n    border-left-width: 0;\n    border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-right-color: @popover-arrow-outer-color;\n    &:after {\n      content: \" \";\n      left: 1px;\n      bottom: -@popover-arrow-width;\n      border-left-width: 0;\n      border-right-color: @popover-arrow-color;\n    }\n  }\n  &.bottom > .arrow {\n    left: 50%;\n    margin-left: -@popover-arrow-outer-width;\n    border-top-width: 0;\n    border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-bottom-color: @popover-arrow-outer-color;\n    top: -@popover-arrow-outer-width;\n    &:after {\n      content: \" \";\n      top: 1px;\n      margin-left: -@popover-arrow-width;\n      border-top-width: 0;\n      border-bottom-color: @popover-arrow-color;\n    }\n  }\n\n  &.left > .arrow {\n    top: 50%;\n    right: -@popover-arrow-outer-width;\n    margin-top: -@popover-arrow-outer-width;\n    border-right-width: 0;\n    border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-left-color: @popover-arrow-outer-color;\n    &:after {\n      content: \" \";\n      right: 1px;\n      border-right-width: 0;\n      border-left-color: @popover-arrow-color;\n      bottom: -@popover-arrow-width;\n    }\n  }\n\n}\n","//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#browsers\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n  width: device-width;\n}\n\n\n// Visibility utilities\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  .responsive-invisibility();\n}\n\n.visible-xs {\n  @media (max-width: @screen-xs-max) {\n    .responsive-visibility();\n  }\n}\n.visible-sm {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    .responsive-visibility();\n  }\n}\n.visible-md {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    .responsive-visibility();\n  }\n}\n.visible-lg {\n  @media (min-width: @screen-lg-min) {\n    .responsive-visibility();\n  }\n}\n\n.hidden-xs {\n  @media (max-width: @screen-xs-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-sm {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-md {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-lg {\n  @media (min-width: @screen-lg-min) {\n    .responsive-invisibility();\n  }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n.visible-print {\n  .responsive-invisibility();\n\n  @media print {\n    .responsive-visibility();\n  }\n}\n\n.hidden-print {\n  @media print {\n    .responsive-invisibility();\n  }\n}\n"]}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap.min.css b/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap.min.css
deleted file mode 100644
index dfe34fe..0000000
--- a/hubs/static/bootstrap-3.1.1-fedora/css/bootstrap.min.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * Bootstrap v3.1.1 (http://getbootstrap.com)
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-/*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none!important;color:#000!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:Cantarell,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#999}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-muted{color:#999}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3f7815}a.text-success:hover{color:#284d0e}.text-info{color:#603e7a}a.text-info:hover{color:#452d58}.text-warning{color:#7e500f}a.text-warning:hover{color:#51330a}.text-danger{color:#78153f}a.text-danger:hover{color:#4d0e28}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dcf6ca}a.bg-success:hover{background-color:#c0ee9e}.bg-info{background-color:#f6f2f8}a.bg-info:hover{background-color:#ddd0e7}.bg-warning{background-color:#f8e4c7}a.bg-warning:hover{background-color:#f3ce9a}.bg-danger{background-color:#f6cadc}a.bg-danger:hover{background-color:#ee9ec0}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#999}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;white-space:nowrap;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dcf6ca}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#cef2b4}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#f6f2f8}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th{background-color:#e9e1f0}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#f8e4c7}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#f6d9b0}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f6cadc}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#f2b4ce}@media (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}input[type=date]{line-height:34px}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;margin-top:10px;margin-bottom:10px;padding-left:20px}.radio label,.checkbox label{display:inline;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.has-feedback .form-control-feedback{position:absolute;top:25px;right:0;display:block;width:34px;height:34px;line-height:34px;text-align:center}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3f7815}.has-success .form-control{border-color:#3f7815;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#284d0e;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #6ccf24;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #6ccf24}.has-success .input-group-addon{color:#3f7815;border-color:#3f7815;background-color:#dcf6ca}.has-success .form-control-feedback{color:#3f7815}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#7e500f}.has-warning .form-control{border-color:#7e500f;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#51330a;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d98a1a;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d98a1a}.has-warning .input-group-addon{color:#7e500f;border-color:#7e500f;background-color:#f8e4c7}.has-warning .form-control-feedback{color:#7e500f}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#78153f}.has-error .form-control{border-color:#78153f;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#4d0e28;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #cf246c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #cf246c}.has-error .input-group-addon{color:#78153f;border-color:#78153f;background-color:#f6cadc}.has-error .form-control-feedback{color:#78153f}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{float:none;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .form-control-static{padding-top:7px}@media (min-width:768px){.form-horizontal .control-label{text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#79db32;border-color:#6ccf24}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#65c222;border-color:#519b1b}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#79db32;border-color:#6ccf24}.btn-success .badge{color:#79db32;background-color:#fff}.btn-info{color:#fff;background-color:#a07cbc;border-color:#946bb3}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#8c61ae;border-color:#754c95}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#a07cbc;border-color:#946bb3}.btn-info .badge{color:#a07cbc;background-color:#fff}.btn-warning{color:#fff;background-color:#e59728;border-color:#d98a1a}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#cc8219;border-color:#a36814}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#e59728;border-color:#d98a1a}.btn-warning .badge{color:#e59728;background-color:#fff}.btn-danger{color:#fff;background-color:#db3279;border-color:#cf246c}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#c22265;border-color:#9b1b51}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#db3279;border-color:#cf246c}.btn-danger .badge{color:#db3279;background-color:#fff}.btn-link{color:#428bca;font-weight:400;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-left:0;padding-right:0}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#999}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle=buttons]>.btn>input[type=radio],[data-toggle=buttons]>.btn>input[type=checkbox]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:50px;font-family:Comfortaa,"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:700}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{float:none;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#db3279;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#db3279}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#db3279;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#294172;border-color:#1c2c4c}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#1c2c4c}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#203258}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#1c2c4c;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#1c2c4c}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#1c2c4c}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#1c2c4c}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.42857143;text-decoration:none;color:#428bca;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:gray}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#79db32}.label-success[href]:hover,.label-success[href]:focus{background-color:#61b921}.label-info{background-color:#a07cbc}.label-info[href]:hover,.label-info[href]:focus{background-color:#885aab}.label-warning{background-color:#e59728}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#c27c18}.label-danger{background-color:#db3279}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#b92161}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dcf6ca;border-color:#d8f2b4;color:#3f7815}.alert-success hr{border-top-color:#cdee9e}.alert-success .alert-link{color:#284d0e}.alert-info{background-color:#f6f2f8;border-color:#e7e1f0;color:#603e7a}.alert-info hr{border-top-color:#d9d0e7}.alert-info .alert-link{color:#452d58}.alert-warning{background-color:#f8e4c7;border-color:#f6ceb0;color:#7e500f}.alert-warning hr{border-top-color:#f3bf9a}.alert-warning .alert-link{color:#51330a}.alert-danger{background-color:#f6cadc;border-color:#f2b4d8;color:#78153f}.alert-danger hr{border-top-color:#ee9ecd}.alert-danger .alert-link{color:#4d0e28}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#79db32}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent)}.progress-bar-info{background-color:#a07cbc}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#e59728}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#db3279}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3f7815;background-color:#dcf6ca}a.list-group-item-success{color:#3f7815}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3f7815;background-color:#cef2b4}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3f7815;border-color:#3f7815}.list-group-item-info{color:#603e7a;background-color:#f6f2f8}a.list-group-item-info{color:#603e7a}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#603e7a;background-color:#e9e1f0}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#603e7a;border-color:#603e7a}.list-group-item-warning{color:#7e500f;background-color:#f8e4c7}a.list-group-item-warning{color:#7e500f}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#7e500f;background-color:#f6d9b0}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#7e500f;border-color:#7e500f}.list-group-item-danger{color:#78153f;background-color:#f6cadc}a.list-group-item-danger{color:#78153f}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#78153f;background-color:#f2b4ce}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#78153f;border-color:#78153f}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px;overflow:hidden}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d8f2b4}.panel-success>.panel-heading{color:#3f7815;background-color:#dcf6ca;border-color:#d8f2b4}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d8f2b4}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d8f2b4}.panel-info{border-color:#e7e1f0}.panel-info>.panel-heading{color:#603e7a;background-color:#f6f2f8;border-color:#e7e1f0}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#e7e1f0}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#e7e1f0}.panel-warning{border-color:#f6ceb0}.panel-warning>.panel-heading{color:#7e500f;background-color:#f8e4c7;border-color:#f6ceb0}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#f6ceb0}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#f6ceb0}.panel-danger{border-color:#f2b4d8}.panel-danger>.panel-heading{color:#78153f;background-color:#f6cadc;border-color:#f2b4d8}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#f2b4d8}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#f2b4d8}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:auto;overflow-y:scroll;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.43px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:20px}.modal-footer{margin-top:15px;padding:19px 20px 20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.5)0),color-stop(rgba(0,0,0,.0001)100%));background-image:linear-gradient(to right,rgba(0,0,0,.5)0,rgba(0,0,0,.0001)100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.0001)0),color-stop(rgba(0,0,0,.5)100%));background-image:linear-gradient(to right,rgba(0,0,0,.0001)0,rgba(0,0,0,.5)100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}@media print{.hidden-print{display:none!important}}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.eot b/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.eot
deleted file mode 100644
index 4a4ca86..0000000
Binary files a/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.eot and /dev/null differ
diff --git a/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.svg b/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.svg
deleted file mode 100644
index e3e2dc7..0000000
--- a/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.svg
+++ /dev/null
@@ -1,229 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata></metadata>
-<defs>
-<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
-<font-face units-per-em="1200" ascent="960" descent="-240" />
-<missing-glyph horiz-adv-x="500" />
-<glyph />
-<glyph />
-<glyph unicode="&#xd;" />
-<glyph unicode=" " />
-<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
-<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
-<glyph unicode="&#xa0;" />
-<glyph unicode="&#x2000;" horiz-adv-x="652" />
-<glyph unicode="&#x2001;" horiz-adv-x="1304" />
-<glyph unicode="&#x2002;" horiz-adv-x="652" />
-<glyph unicode="&#x2003;" horiz-adv-x="1304" />
-<glyph unicode="&#x2004;" horiz-adv-x="434" />
-<glyph unicode="&#x2005;" horiz-adv-x="326" />
-<glyph unicode="&#x2006;" horiz-adv-x="217" />
-<glyph unicode="&#x2007;" horiz-adv-x="217" />
-<glyph unicode="&#x2008;" horiz-adv-x="163" />
-<glyph unicode="&#x2009;" horiz-adv-x="260" />
-<glyph unicode="&#x200a;" horiz-adv-x="72" />
-<glyph unicode="&#x202f;" horiz-adv-x="260" />
-<glyph unicode="&#x205f;" horiz-adv-x="326" />
-<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
-<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" />
-<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
-<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
-<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
-<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
-<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
-<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
-<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
-<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
-<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
-<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
-<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
-<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
-<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
-<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
-<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
-<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
-<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
-<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
-<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
-<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
-<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
-<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
-<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
-<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
-<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
-<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
-<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
-<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
-<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
-<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
-<glyph unicode="&#xe028;" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
-<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
-<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
-<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
-<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
-<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
-<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
-<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
-<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
-<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
-<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
-<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
-<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
-<glyph unicode="&#xe041;" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
-<glyph unicode="&#xe042;" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
-<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
-<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
-<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
-<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
-<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
-<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
-<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
-<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
-<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
-<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
-<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
-<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
-<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
-<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
-<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
-<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
-<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
-<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
-<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
-<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
-<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
-<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
-<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
-<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
-<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
-<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
-<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
-<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
-<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" />
-<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
-<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
-<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
-<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
-<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
-<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
-<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
-<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
-<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
-<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
-<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
-<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
-<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
-<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
-<glyph unicode="&#xe087;" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
-<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
-<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
-<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
-<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" />
-<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
-<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
-<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" />
-<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
-<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
-<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
-<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
-<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
-<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
-<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
-<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
-<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
-<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
-<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
-<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
-<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
-<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
-<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
-<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
-<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
-<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
-<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
-<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
-<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
-<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
-<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
-<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
-<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
-<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
-<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
-<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
-<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
-<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
-<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
-<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
-<glyph unicode="&#xe130;" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
-<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
-<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
-<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
-<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
-<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
-<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
-<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
-<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
-<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
-<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
-<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
-<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
-<glyph unicode="&#xe143;" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
-<glyph unicode="&#xe144;" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
-<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
-<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
-<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
-<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
-<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
-<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
-<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
-<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
-<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
-<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
-<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
-<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
-<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
-<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
-<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
-<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
-<glyph unicode="&#xe162;" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
-<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
-<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
-<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
-<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
-<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
-<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
-<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
-<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
-<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
-<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
-<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
-<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
-<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
-<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
-<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
-<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
-<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
-<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
-<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
-<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
-<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
-<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
-<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
-<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
-<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
-<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
-<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
-<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
-<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
-<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
-<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
-<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
-<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
-<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
-<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
-<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
-<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
-</font>
-</defs></svg> 
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.ttf b/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.ttf
deleted file mode 100644
index 67fa00b..0000000
Binary files a/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.ttf and /dev/null differ
diff --git a/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.woff b/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.woff
deleted file mode 100644
index 8c54182..0000000
Binary files a/hubs/static/bootstrap-3.1.1-fedora/fonts/glyphicons-halflings-regular.woff and /dev/null differ
diff --git a/hubs/static/bootstrap-3.1.1-fedora/js/bootstrap.js b/hubs/static/bootstrap-3.1.1-fedora/js/bootstrap.js
deleted file mode 100644
index 8ae571b..0000000
--- a/hubs/static/bootstrap-3.1.1-fedora/js/bootstrap.js
+++ /dev/null
@@ -1,1951 +0,0 @@
-/*!
- * Bootstrap v3.1.1 (http://getbootstrap.com)
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') }
-
-/* ========================================================================
- * Bootstrap: transition.js v3.1.1
- * http://getbootstrap.com/javascript/#transitions
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
-  // ============================================================
-
-  function transitionEnd() {
-    var el = document.createElement('bootstrap')
-
-    var transEndEventNames = {
-      'WebkitTransition' : 'webkitTransitionEnd',
-      'MozTransition'    : 'transitionend',
-      'OTransition'      : 'oTransitionEnd otransitionend',
-      'transition'       : 'transitionend'
-    }
-
-    for (var name in transEndEventNames) {
-      if (el.style[name] !== undefined) {
-        return { end: transEndEventNames[name] }
-      }
-    }
-
-    return false // explicit for ie8 (  ._.)
-  }
-
-  // http://blog.alexmaccaw.com/css-transitions
-  $.fn.emulateTransitionEnd = function (duration) {
-    var called = false, $el = this
-    $(this).one($.support.transition.end, function () { called = true })
-    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
-    setTimeout(callback, duration)
-    return this
-  }
-
-  $(function () {
-    $.support.transition = transitionEnd()
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: alert.js v3.1.1
- * http://getbootstrap.com/javascript/#alerts
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // ALERT CLASS DEFINITION
-  // ======================
-
-  var dismiss = '[data-dismiss="alert"]'
-  var Alert   = function (el) {
-    $(el).on('click', dismiss, this.close)
-  }
-
-  Alert.prototype.close = function (e) {
-    var $this    = $(this)
-    var selector = $this.attr('data-target')
-
-    if (!selector) {
-      selector = $this.attr('href')
-      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
-    }
-
-    var $parent = $(selector)
-
-    if (e) e.preventDefault()
-
-    if (!$parent.length) {
-      $parent = $this.hasClass('alert') ? $this : $this.parent()
-    }
-
-    $parent.trigger(e = $.Event('close.bs.alert'))
-
-    if (e.isDefaultPrevented()) return
-
-    $parent.removeClass('in')
-
-    function removeElement() {
-      $parent.trigger('closed.bs.alert').remove()
-    }
-
-    $.support.transition && $parent.hasClass('fade') ?
-      $parent
-        .one($.support.transition.end, removeElement)
-        .emulateTransitionEnd(150) :
-      removeElement()
-  }
-
-
-  // ALERT PLUGIN DEFINITION
-  // =======================
-
-  var old = $.fn.alert
-
-  $.fn.alert = function (option) {
-    return this.each(function () {
-      var $this = $(this)
-      var data  = $this.data('bs.alert')
-
-      if (!data) $this.data('bs.alert', (data = new Alert(this)))
-      if (typeof option == 'string') data[option].call($this)
-    })
-  }
-
-  $.fn.alert.Constructor = Alert
-
-
-  // ALERT NO CONFLICT
-  // =================
-
-  $.fn.alert.noConflict = function () {
-    $.fn.alert = old
-    return this
-  }
-
-
-  // ALERT DATA-API
-  // ==============
-
-  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: button.js v3.1.1
- * http://getbootstrap.com/javascript/#buttons
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // BUTTON PUBLIC CLASS DEFINITION
-  // ==============================
-
-  var Button = function (element, options) {
-    this.$element  = $(element)
-    this.options   = $.extend({}, Button.DEFAULTS, options)
-    this.isLoading = false
-  }
-
-  Button.DEFAULTS = {
-    loadingText: 'loading...'
-  }
-
-  Button.prototype.setState = function (state) {
-    var d    = 'disabled'
-    var $el  = this.$element
-    var val  = $el.is('input') ? 'val' : 'html'
-    var data = $el.data()
-
-    state = state + 'Text'
-
-    if (!data.resetText) $el.data('resetText', $el[val]())
-
-    $el[val](data[state] || this.options[state])
-
-    // push to event loop to allow forms to submit
-    setTimeout($.proxy(function () {
-      if (state == 'loadingText') {
-        this.isLoading = true
-        $el.addClass(d).attr(d, d)
-      } else if (this.isLoading) {
-        this.isLoading = false
-        $el.removeClass(d).removeAttr(d)
-      }
-    }, this), 0)
-  }
-
-  Button.prototype.toggle = function () {
-    var changed = true
-    var $parent = this.$element.closest('[data-toggle="buttons"]')
-
-    if ($parent.length) {
-      var $input = this.$element.find('input')
-      if ($input.prop('type') == 'radio') {
-        if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
-        else $parent.find('.active').removeClass('active')
-      }
-      if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
-    }
-
-    if (changed) this.$element.toggleClass('active')
-  }
-
-
-  // BUTTON PLUGIN DEFINITION
-  // ========================
-
-  var old = $.fn.button
-
-  $.fn.button = function (option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.button')
-      var options = typeof option == 'object' && option
-
-      if (!data) $this.data('bs.button', (data = new Button(this, options)))
-
-      if (option == 'toggle') data.toggle()
-      else if (option) data.setState(option)
-    })
-  }
-
-  $.fn.button.Constructor = Button
-
-
-  // BUTTON NO CONFLICT
-  // ==================
-
-  $.fn.button.noConflict = function () {
-    $.fn.button = old
-    return this
-  }
-
-
-  // BUTTON DATA-API
-  // ===============
-
-  $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
-    var $btn = $(e.target)
-    if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
-    $btn.button('toggle')
-    e.preventDefault()
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: carousel.js v3.1.1
- * http://getbootstrap.com/javascript/#carousel
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // CAROUSEL CLASS DEFINITION
-  // =========================
-
-  var Carousel = function (element, options) {
-    this.$element    = $(element)
-    this.$indicators = this.$element.find('.carousel-indicators')
-    this.options     = options
-    this.paused      =
-    this.sliding     =
-    this.interval    =
-    this.$active     =
-    this.$items      = null
-
-    this.options.pause == 'hover' && this.$element
-      .on('mouseenter', $.proxy(this.pause, this))
-      .on('mouseleave', $.proxy(this.cycle, this))
-  }
-
-  Carousel.DEFAULTS = {
-    interval: 5000,
-    pause: 'hover',
-    wrap: true
-  }
-
-  Carousel.prototype.cycle =  function (e) {
-    e || (this.paused = false)
-
-    this.interval && clearInterval(this.interval)
-
-    this.options.interval
-      && !this.paused
-      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
-
-    return this
-  }
-
-  Carousel.prototype.getActiveIndex = function () {
-    this.$active = this.$element.find('.item.active')
-    this.$items  = this.$active.parent().children()
-
-    return this.$items.index(this.$active)
-  }
-
-  Carousel.prototype.to = function (pos) {
-    var that        = this
-    var activeIndex = this.getActiveIndex()
-
-    if (pos > (this.$items.length - 1) || pos < 0) return
-
-    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) })
-    if (activeIndex == pos) return this.pause().cycle()
-
-    return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
-  }
-
-  Carousel.prototype.pause = function (e) {
-    e || (this.paused = true)
-
-    if (this.$element.find('.next, .prev').length && $.support.transition) {
-      this.$element.trigger($.support.transition.end)
-      this.cycle(true)
-    }
-
-    this.interval = clearInterval(this.interval)
-
-    return this
-  }
-
-  Carousel.prototype.next = function () {
-    if (this.sliding) return
-    return this.slide('next')
-  }
-
-  Carousel.prototype.prev = function () {
-    if (this.sliding) return
-    return this.slide('prev')
-  }
-
-  Carousel.prototype.slide = function (type, next) {
-    var $active   = this.$element.find('.item.active')
-    var $next     = next || $active[type]()
-    var isCycling = this.interval
-    var direction = type == 'next' ? 'left' : 'right'
-    var fallback  = type == 'next' ? 'first' : 'last'
-    var that      = this
-
-    if (!$next.length) {
-      if (!this.options.wrap) return
-      $next = this.$element.find('.item')[fallback]()
-    }
-
-    if ($next.hasClass('active')) return this.sliding = false
-
-    var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction })
-    this.$element.trigger(e)
-    if (e.isDefaultPrevented()) return
-
-    this.sliding = true
-
-    isCycling && this.pause()
-
-    if (this.$indicators.length) {
-      this.$indicators.find('.active').removeClass('active')
-      this.$element.one('slid.bs.carousel', function () {
-        var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
-        $nextIndicator && $nextIndicator.addClass('active')
-      })
-    }
-
-    if ($.support.transition && this.$element.hasClass('slide')) {
-      $next.addClass(type)
-      $next[0].offsetWidth // force reflow
-      $active.addClass(direction)
-      $next.addClass(direction)
-      $active
-        .one($.support.transition.end, function () {
-          $next.removeClass([type, direction].join(' ')).addClass('active')
-          $active.removeClass(['active', direction].join(' '))
-          that.sliding = false
-          setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0)
-        })
-        .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
-    } else {
-      $active.removeClass('active')
-      $next.addClass('active')
-      this.sliding = false
-      this.$element.trigger('slid.bs.carousel')
-    }
-
-    isCycling && this.cycle()
-
-    return this
-  }
-
-
-  // CAROUSEL PLUGIN DEFINITION
-  // ==========================
-
-  var old = $.fn.carousel
-
-  $.fn.carousel = function (option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.carousel')
-      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
-      var action  = typeof option == 'string' ? option : options.slide
-
-      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
-      if (typeof option == 'number') data.to(option)
-      else if (action) data[action]()
-      else if (options.interval) data.pause().cycle()
-    })
-  }
-
-  $.fn.carousel.Constructor = Carousel
-
-
-  // CAROUSEL NO CONFLICT
-  // ====================
-
-  $.fn.carousel.noConflict = function () {
-    $.fn.carousel = old
-    return this
-  }
-
-
-  // CAROUSEL DATA-API
-  // =================
-
-  $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
-    var $this   = $(this), href
-    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
-    var options = $.extend({}, $target.data(), $this.data())
-    var slideIndex = $this.attr('data-slide-to')
-    if (slideIndex) options.interval = false
-
-    $target.carousel(options)
-
-    if (slideIndex = $this.attr('data-slide-to')) {
-      $target.data('bs.carousel').to(slideIndex)
-    }
-
-    e.preventDefault()
-  })
-
-  $(window).on('load', function () {
-    $('[data-ride="carousel"]').each(function () {
-      var $carousel = $(this)
-      $carousel.carousel($carousel.data())
-    })
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: collapse.js v3.1.1
- * http://getbootstrap.com/javascript/#collapse
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // COLLAPSE PUBLIC CLASS DEFINITION
-  // ================================
-
-  var Collapse = function (element, options) {
-    this.$element      = $(element)
-    this.options       = $.extend({}, Collapse.DEFAULTS, options)
-    this.transitioning = null
-
-    if (this.options.parent) this.$parent = $(this.options.parent)
-    if (this.options.toggle) this.toggle()
-  }
-
-  Collapse.DEFAULTS = {
-    toggle: true
-  }
-
-  Collapse.prototype.dimension = function () {
-    var hasWidth = this.$element.hasClass('width')
-    return hasWidth ? 'width' : 'height'
-  }
-
-  Collapse.prototype.show = function () {
-    if (this.transitioning || this.$element.hasClass('in')) return
-
-    var startEvent = $.Event('show.bs.collapse')
-    this.$element.trigger(startEvent)
-    if (startEvent.isDefaultPrevented()) return
-
-    var actives = this.$parent && this.$parent.find('> .panel > .in')
-
-    if (actives && actives.length) {
-      var hasData = actives.data('bs.collapse')
-      if (hasData && hasData.transitioning) return
-      actives.collapse('hide')
-      hasData || actives.data('bs.collapse', null)
-    }
-
-    var dimension = this.dimension()
-
-    this.$element
-      .removeClass('collapse')
-      .addClass('collapsing')
-      [dimension](0)
-
-    this.transitioning = 1
-
-    var complete = function () {
-      this.$element
-        .removeClass('collapsing')
-        .addClass('collapse in')
-        [dimension]('auto')
-      this.transitioning = 0
-      this.$element.trigger('shown.bs.collapse')
-    }
-
-    if (!$.support.transition) return complete.call(this)
-
-    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
-
-    this.$element
-      .one($.support.transition.end, $.proxy(complete, this))
-      .emulateTransitionEnd(350)
-      [dimension](this.$element[0][scrollSize])
-  }
-
-  Collapse.prototype.hide = function () {
-    if (this.transitioning || !this.$element.hasClass('in')) return
-
-    var startEvent = $.Event('hide.bs.collapse')
-    this.$element.trigger(startEvent)
-    if (startEvent.isDefaultPrevented()) return
-
-    var dimension = this.dimension()
-
-    this.$element
-      [dimension](this.$element[dimension]())
-      [0].offsetHeight
-
-    this.$element
-      .addClass('collapsing')
-      .removeClass('collapse')
-      .removeClass('in')
-
-    this.transitioning = 1
-
-    var complete = function () {
-      this.transitioning = 0
-      this.$element
-        .trigger('hidden.bs.collapse')
-        .removeClass('collapsing')
-        .addClass('collapse')
-    }
-
-    if (!$.support.transition) return complete.call(this)
-
-    this.$element
-      [dimension](0)
-      .one($.support.transition.end, $.proxy(complete, this))
-      .emulateTransitionEnd(350)
-  }
-
-  Collapse.prototype.toggle = function () {
-    this[this.$element.hasClass('in') ? 'hide' : 'show']()
-  }
-
-
-  // COLLAPSE PLUGIN DEFINITION
-  // ==========================
-
-  var old = $.fn.collapse
-
-  $.fn.collapse = function (option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.collapse')
-      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
-
-      if (!data && options.toggle && option == 'show') option = !option
-      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.collapse.Constructor = Collapse
-
-
-  // COLLAPSE NO CONFLICT
-  // ====================
-
-  $.fn.collapse.noConflict = function () {
-    $.fn.collapse = old
-    return this
-  }
-
-
-  // COLLAPSE DATA-API
-  // =================
-
-  $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
-    var $this   = $(this), href
-    var target  = $this.attr('data-target')
-        || e.preventDefault()
-        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
-    var $target = $(target)
-    var data    = $target.data('bs.collapse')
-    var option  = data ? 'toggle' : $this.data()
-    var parent  = $this.attr('data-parent')
-    var $parent = parent && $(parent)
-
-    if (!data || !data.transitioning) {
-      if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed')
-      $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
-    }
-
-    $target.collapse(option)
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: dropdown.js v3.1.1
- * http://getbootstrap.com/javascript/#dropdowns
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // DROPDOWN CLASS DEFINITION
-  // =========================
-
-  var backdrop = '.dropdown-backdrop'
-  var toggle   = '[data-toggle=dropdown]'
-  var Dropdown = function (element) {
-    $(element).on('click.bs.dropdown', this.toggle)
-  }
-
-  Dropdown.prototype.toggle = function (e) {
-    var $this = $(this)
-
-    if ($this.is('.disabled, :disabled')) return
-
-    var $parent  = getParent($this)
-    var isActive = $parent.hasClass('open')
-
-    clearMenus()
-
-    if (!isActive) {
-      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
-        // if mobile we use a backdrop because click events don't delegate
-        $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
-      }
-
-      var relatedTarget = { relatedTarget: this }
-      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
-
-      if (e.isDefaultPrevented()) return
-
-      $parent
-        .toggleClass('open')
-        .trigger('shown.bs.dropdown', relatedTarget)
-
-      $this.focus()
-    }
-
-    return false
-  }
-
-  Dropdown.prototype.keydown = function (e) {
-    if (!/(38|40|27)/.test(e.keyCode)) return
-
-    var $this = $(this)
-
-    e.preventDefault()
-    e.stopPropagation()
-
-    if ($this.is('.disabled, :disabled')) return
-
-    var $parent  = getParent($this)
-    var isActive = $parent.hasClass('open')
-
-    if (!isActive || (isActive && e.keyCode == 27)) {
-      if (e.which == 27) $parent.find(toggle).focus()
-      return $this.click()
-    }
-
-    var desc = ' li:not(.divider):visible a'
-    var $items = $parent.find('[role=menu]' + desc + ', [role=listbox]' + desc)
-
-    if (!$items.length) return
-
-    var index = $items.index($items.filter(':focus'))
-
-    if (e.keyCode == 38 && index > 0)                 index--                        // up
-    if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
-    if (!~index)                                      index = 0
-
-    $items.eq(index).focus()
-  }
-
-  function clearMenus(e) {
-    $(backdrop).remove()
-    $(toggle).each(function () {
-      var $parent = getParent($(this))
-      var relatedTarget = { relatedTarget: this }
-      if (!$parent.hasClass('open')) return
-      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
-      if (e.isDefaultPrevented()) return
-      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
-    })
-  }
-
-  function getParent($this) {
-    var selector = $this.attr('data-target')
-
-    if (!selector) {
-      selector = $this.attr('href')
-      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
-    }
-
-    var $parent = selector && $(selector)
-
-    return $parent && $parent.length ? $parent : $this.parent()
-  }
-
-
-  // DROPDOWN PLUGIN DEFINITION
-  // ==========================
-
-  var old = $.fn.dropdown
-
-  $.fn.dropdown = function (option) {
-    return this.each(function () {
-      var $this = $(this)
-      var data  = $this.data('bs.dropdown')
-
-      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
-      if (typeof option == 'string') data[option].call($this)
-    })
-  }
-
-  $.fn.dropdown.Constructor = Dropdown
-
-
-  // DROPDOWN NO CONFLICT
-  // ====================
-
-  $.fn.dropdown.noConflict = function () {
-    $.fn.dropdown = old
-    return this
-  }
-
-
-  // APPLY TO STANDARD DROPDOWN ELEMENTS
-  // ===================================
-
-  $(document)
-    .on('click.bs.dropdown.data-api', clearMenus)
-    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
-    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
-    .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu], [role=listbox]', Dropdown.prototype.keydown)
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: modal.js v3.1.1
- * http://getbootstrap.com/javascript/#modals
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // MODAL CLASS DEFINITION
-  // ======================
-
-  var Modal = function (element, options) {
-    this.options   = options
-    this.$element  = $(element)
-    this.$backdrop =
-    this.isShown   = null
-
-    if (this.options.remote) {
-      this.$element
-        .find('.modal-content')
-        .load(this.options.remote, $.proxy(function () {
-          this.$element.trigger('loaded.bs.modal')
-        }, this))
-    }
-  }
-
-  Modal.DEFAULTS = {
-    backdrop: true,
-    keyboard: true,
-    show: true
-  }
-
-  Modal.prototype.toggle = function (_relatedTarget) {
-    return this[!this.isShown ? 'show' : 'hide'](_relatedTarget)
-  }
-
-  Modal.prototype.show = function (_relatedTarget) {
-    var that = this
-    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
-
-    this.$element.trigger(e)
-
-    if (this.isShown || e.isDefaultPrevented()) return
-
-    this.isShown = true
-
-    this.escape()
-
-    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
-
-    this.backdrop(function () {
-      var transition = $.support.transition && that.$element.hasClass('fade')
-
-      if (!that.$element.parent().length) {
-        that.$element.appendTo(document.body) // don't move modals dom position
-      }
-
-      that.$element
-        .show()
-        .scrollTop(0)
-
-      if (transition) {
-        that.$element[0].offsetWidth // force reflow
-      }
-
-      that.$element
-        .addClass('in')
-        .attr('aria-hidden', false)
-
-      that.enforceFocus()
-
-      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
-
-      transition ?
-        that.$element.find('.modal-dialog') // wait for modal to slide in
-          .one($.support.transition.end, function () {
-            that.$element.focus().trigger(e)
-          })
-          .emulateTransitionEnd(300) :
-        that.$element.focus().trigger(e)
-    })
-  }
-
-  Modal.prototype.hide = function (e) {
-    if (e) e.preventDefault()
-
-    e = $.Event('hide.bs.modal')
-
-    this.$element.trigger(e)
-
-    if (!this.isShown || e.isDefaultPrevented()) return
-
-    this.isShown = false
-
-    this.escape()
-
-    $(document).off('focusin.bs.modal')
-
-    this.$element
-      .removeClass('in')
-      .attr('aria-hidden', true)
-      .off('click.dismiss.bs.modal')
-
-    $.support.transition && this.$element.hasClass('fade') ?
-      this.$element
-        .one($.support.transition.end, $.proxy(this.hideModal, this))
-        .emulateTransitionEnd(300) :
-      this.hideModal()
-  }
-
-  Modal.prototype.enforceFocus = function () {
-    $(document)
-      .off('focusin.bs.modal') // guard against infinite focus loop
-      .on('focusin.bs.modal', $.proxy(function (e) {
-        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
-          this.$element.focus()
-        }
-      }, this))
-  }
-
-  Modal.prototype.escape = function () {
-    if (this.isShown && this.options.keyboard) {
-      this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
-        e.which == 27 && this.hide()
-      }, this))
-    } else if (!this.isShown) {
-      this.$element.off('keyup.dismiss.bs.modal')
-    }
-  }
-
-  Modal.prototype.hideModal = function () {
-    var that = this
-    this.$element.hide()
-    this.backdrop(function () {
-      that.removeBackdrop()
-      that.$element.trigger('hidden.bs.modal')
-    })
-  }
-
-  Modal.prototype.removeBackdrop = function () {
-    this.$backdrop && this.$backdrop.remove()
-    this.$backdrop = null
-  }
-
-  Modal.prototype.backdrop = function (callback) {
-    var animate = this.$element.hasClass('fade') ? 'fade' : ''
-
-    if (this.isShown && this.options.backdrop) {
-      var doAnimate = $.support.transition && animate
-
-      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
-        .appendTo(document.body)
-
-      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
-        if (e.target !== e.currentTarget) return
-        this.options.backdrop == 'static'
-          ? this.$element[0].focus.call(this.$element[0])
-          : this.hide.call(this)
-      }, this))
-
-      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
-
-      this.$backdrop.addClass('in')
-
-      if (!callback) return
-
-      doAnimate ?
-        this.$backdrop
-          .one($.support.transition.end, callback)
-          .emulateTransitionEnd(150) :
-        callback()
-
-    } else if (!this.isShown && this.$backdrop) {
-      this.$backdrop.removeClass('in')
-
-      $.support.transition && this.$element.hasClass('fade') ?
-        this.$backdrop
-          .one($.support.transition.end, callback)
-          .emulateTransitionEnd(150) :
-        callback()
-
-    } else if (callback) {
-      callback()
-    }
-  }
-
-
-  // MODAL PLUGIN DEFINITION
-  // =======================
-
-  var old = $.fn.modal
-
-  $.fn.modal = function (option, _relatedTarget) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.modal')
-      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
-
-      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
-      if (typeof option == 'string') data[option](_relatedTarget)
-      else if (options.show) data.show(_relatedTarget)
-    })
-  }
-
-  $.fn.modal.Constructor = Modal
-
-
-  // MODAL NO CONFLICT
-  // =================
-
-  $.fn.modal.noConflict = function () {
-    $.fn.modal = old
-    return this
-  }
-
-
-  // MODAL DATA-API
-  // ==============
-
-  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
-    var $this   = $(this)
-    var href    = $this.attr('href')
-    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
-    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
-
-    if ($this.is('a')) e.preventDefault()
-
-    $target
-      .modal(option, this)
-      .one('hide', function () {
-        $this.is(':visible') && $this.focus()
-      })
-  })
-
-  $(document)
-    .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') })
-    .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: tooltip.js v3.1.1
- * http://getbootstrap.com/javascript/#tooltip
- * Inspired by the original jQuery.tipsy by Jason Frame
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // TOOLTIP PUBLIC CLASS DEFINITION
-  // ===============================
-
-  var Tooltip = function (element, options) {
-    this.type       =
-    this.options    =
-    this.enabled    =
-    this.timeout    =
-    this.hoverState =
-    this.$element   = null
-
-    this.init('tooltip', element, options)
-  }
-
-  Tooltip.DEFAULTS = {
-    animation: true,
-    placement: 'top',
-    selector: false,
-    template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
-    trigger: 'hover focus',
-    title: '',
-    delay: 0,
-    html: false,
-    container: false
-  }
-
-  Tooltip.prototype.init = function (type, element, options) {
-    this.enabled  = true
-    this.type     = type
-    this.$element = $(element)
-    this.options  = this.getOptions(options)
-
-    var triggers = this.options.trigger.split(' ')
-
-    for (var i = triggers.length; i--;) {
-      var trigger = triggers[i]
-
-      if (trigger == 'click') {
-        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
-      } else if (trigger != 'manual') {
-        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
-        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
-
-        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
-        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
-      }
-    }
-
-    this.options.selector ?
-      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
-      this.fixTitle()
-  }
-
-  Tooltip.prototype.getDefaults = function () {
-    return Tooltip.DEFAULTS
-  }
-
-  Tooltip.prototype.getOptions = function (options) {
-    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
-
-    if (options.delay && typeof options.delay == 'number') {
-      options.delay = {
-        show: options.delay,
-        hide: options.delay
-      }
-    }
-
-    return options
-  }
-
-  Tooltip.prototype.getDelegateOptions = function () {
-    var options  = {}
-    var defaults = this.getDefaults()
-
-    this._options && $.each(this._options, function (key, value) {
-      if (defaults[key] != value) options[key] = value
-    })
-
-    return options
-  }
-
-  Tooltip.prototype.enter = function (obj) {
-    var self = obj instanceof this.constructor ?
-      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
-
-    clearTimeout(self.timeout)
-
-    self.hoverState = 'in'
-
-    if (!self.options.delay || !self.options.delay.show) return self.show()
-
-    self.timeout = setTimeout(function () {
-      if (self.hoverState == 'in') self.show()
-    }, self.options.delay.show)
-  }
-
-  Tooltip.prototype.leave = function (obj) {
-    var self = obj instanceof this.constructor ?
-      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
-
-    clearTimeout(self.timeout)
-
-    self.hoverState = 'out'
-
-    if (!self.options.delay || !self.options.delay.hide) return self.hide()
-
-    self.timeout = setTimeout(function () {
-      if (self.hoverState == 'out') self.hide()
-    }, self.options.delay.hide)
-  }
-
-  Tooltip.prototype.show = function () {
-    var e = $.Event('show.bs.' + this.type)
-
-    if (this.hasContent() && this.enabled) {
-      this.$element.trigger(e)
-
-      if (e.isDefaultPrevented()) return
-      var that = this;
-
-      var $tip = this.tip()
-
-      this.setContent()
-
-      if (this.options.animation) $tip.addClass('fade')
-
-      var placement = typeof this.options.placement == 'function' ?
-        this.options.placement.call(this, $tip[0], this.$element[0]) :
-        this.options.placement
-
-      var autoToken = /\s?auto?\s?/i
-      var autoPlace = autoToken.test(placement)
-      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
-
-      $tip
-        .detach()
-        .css({ top: 0, left: 0, display: 'block' })
-        .addClass(placement)
-
-      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
-
-      var pos          = this.getPosition()
-      var actualWidth  = $tip[0].offsetWidth
-      var actualHeight = $tip[0].offsetHeight
-
-      if (autoPlace) {
-        var $parent = this.$element.parent()
-
-        var orgPlacement = placement
-        var docScroll    = document.documentElement.scrollTop || document.body.scrollTop
-        var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth()
-        var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
-        var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left
-
-        placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
-                    placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
-                    placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
-                    placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
-                    placement
-
-        $tip
-          .removeClass(orgPlacement)
-          .addClass(placement)
-      }
-
-      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
-
-      this.applyPlacement(calculatedOffset, placement)
-      this.hoverState = null
-
-      var complete = function() {
-        that.$element.trigger('shown.bs.' + that.type)
-      }
-
-      $.support.transition && this.$tip.hasClass('fade') ?
-        $tip
-          .one($.support.transition.end, complete)
-          .emulateTransitionEnd(150) :
-        complete()
-    }
-  }
-
-  Tooltip.prototype.applyPlacement = function (offset, placement) {
-    var replace
-    var $tip   = this.tip()
-    var width  = $tip[0].offsetWidth
-    var height = $tip[0].offsetHeight
-
-    // manually read margins because getBoundingClientRect includes difference
-    var marginTop = parseInt($tip.css('margin-top'), 10)
-    var marginLeft = parseInt($tip.css('margin-left'), 10)
-
-    // we must check for NaN for ie 8/9
-    if (isNaN(marginTop))  marginTop  = 0
-    if (isNaN(marginLeft)) marginLeft = 0
-
-    offset.top  = offset.top  + marginTop
-    offset.left = offset.left + marginLeft
-
-    // $.fn.offset doesn't round pixel values
-    // so we use setOffset directly with our own function B-0
-    $.offset.setOffset($tip[0], $.extend({
-      using: function (props) {
-        $tip.css({
-          top: Math.round(props.top),
-          left: Math.round(props.left)
-        })
-      }
-    }, offset), 0)
-
-    $tip.addClass('in')
-
-    // check to see if placing tip in new offset caused the tip to resize itself
-    var actualWidth  = $tip[0].offsetWidth
-    var actualHeight = $tip[0].offsetHeight
-
-    if (placement == 'top' && actualHeight != height) {
-      replace = true
-      offset.top = offset.top + height - actualHeight
-    }
-
-    if (/bottom|top/.test(placement)) {
-      var delta = 0
-
-      if (offset.left < 0) {
-        delta       = offset.left * -2
-        offset.left = 0
-
-        $tip.offset(offset)
-
-        actualWidth  = $tip[0].offsetWidth
-        actualHeight = $tip[0].offsetHeight
-      }
-
-      this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
-    } else {
-      this.replaceArrow(actualHeight - height, actualHeight, 'top')
-    }
-
-    if (replace) $tip.offset(offset)
-  }
-
-  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
-    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
-  }
-
-  Tooltip.prototype.setContent = function () {
-    var $tip  = this.tip()
-    var title = this.getTitle()
-
-    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
-    $tip.removeClass('fade in top bottom left right')
-  }
-
-  Tooltip.prototype.hide = function () {
-    var that = this
-    var $tip = this.tip()
-    var e    = $.Event('hide.bs.' + this.type)
-
-    function complete() {
-      if (that.hoverState != 'in') $tip.detach()
-      that.$element.trigger('hidden.bs.' + that.type)
-    }
-
-    this.$element.trigger(e)
-
-    if (e.isDefaultPrevented()) return
-
-    $tip.removeClass('in')
-
-    $.support.transition && this.$tip.hasClass('fade') ?
-      $tip
-        .one($.support.transition.end, complete)
-        .emulateTransitionEnd(150) :
-      complete()
-
-    this.hoverState = null
-
-    return this
-  }
-
-  Tooltip.prototype.fixTitle = function () {
-    var $e = this.$element
-    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
-      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
-    }
-  }
-
-  Tooltip.prototype.hasContent = function () {
-    return this.getTitle()
-  }
-
-  Tooltip.prototype.getPosition = function () {
-    var el = this.$element[0]
-    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
-      width: el.offsetWidth,
-      height: el.offsetHeight
-    }, this.$element.offset())
-  }
-
-  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
-    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
-           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
-           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
-        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
-  }
-
-  Tooltip.prototype.getTitle = function () {
-    var title
-    var $e = this.$element
-    var o  = this.options
-
-    title = $e.attr('data-original-title')
-      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
-
-    return title
-  }
-
-  Tooltip.prototype.tip = function () {
-    return this.$tip = this.$tip || $(this.options.template)
-  }
-
-  Tooltip.prototype.arrow = function () {
-    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
-  }
-
-  Tooltip.prototype.validate = function () {
-    if (!this.$element[0].parentNode) {
-      this.hide()
-      this.$element = null
-      this.options  = null
-    }
-  }
-
-  Tooltip.prototype.enable = function () {
-    this.enabled = true
-  }
-
-  Tooltip.prototype.disable = function () {
-    this.enabled = false
-  }
-
-  Tooltip.prototype.toggleEnabled = function () {
-    this.enabled = !this.enabled
-  }
-
-  Tooltip.prototype.toggle = function (e) {
-    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
-    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
-  }
-
-  Tooltip.prototype.destroy = function () {
-    clearTimeout(this.timeout)
-    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
-  }
-
-
-  // TOOLTIP PLUGIN DEFINITION
-  // =========================
-
-  var old = $.fn.tooltip
-
-  $.fn.tooltip = function (option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.tooltip')
-      var options = typeof option == 'object' && option
-
-      if (!data && option == 'destroy') return
-      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.tooltip.Constructor = Tooltip
-
-
-  // TOOLTIP NO CONFLICT
-  // ===================
-
-  $.fn.tooltip.noConflict = function () {
-    $.fn.tooltip = old
-    return this
-  }
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: popover.js v3.1.1
- * http://getbootstrap.com/javascript/#popovers
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // POPOVER PUBLIC CLASS DEFINITION
-  // ===============================
-
-  var Popover = function (element, options) {
-    this.init('popover', element, options)
-  }
-
-  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
-
-  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
-    placement: 'right',
-    trigger: 'click',
-    content: '',
-    template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
-  })
-
-
-  // NOTE: POPOVER EXTENDS tooltip.js
-  // ================================
-
-  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
-
-  Popover.prototype.constructor = Popover
-
-  Popover.prototype.getDefaults = function () {
-    return Popover.DEFAULTS
-  }
-
-  Popover.prototype.setContent = function () {
-    var $tip    = this.tip()
-    var title   = this.getTitle()
-    var content = this.getContent()
-
-    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
-    $tip.find('.popover-content')[ // we use append for html objects to maintain js events
-      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
-    ](content)
-
-    $tip.removeClass('fade top bottom left right in')
-
-    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
-    // this manually by checking the contents.
-    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
-  }
-
-  Popover.prototype.hasContent = function () {
-    return this.getTitle() || this.getContent()
-  }
-
-  Popover.prototype.getContent = function () {
-    var $e = this.$element
-    var o  = this.options
-
-    return $e.attr('data-content')
-      || (typeof o.content == 'function' ?
-            o.content.call($e[0]) :
-            o.content)
-  }
-
-  Popover.prototype.arrow = function () {
-    return this.$arrow = this.$arrow || this.tip().find('.arrow')
-  }
-
-  Popover.prototype.tip = function () {
-    if (!this.$tip) this.$tip = $(this.options.template)
-    return this.$tip
-  }
-
-
-  // POPOVER PLUGIN DEFINITION
-  // =========================
-
-  var old = $.fn.popover
-
-  $.fn.popover = function (option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.popover')
-      var options = typeof option == 'object' && option
-
-      if (!data && option == 'destroy') return
-      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.popover.Constructor = Popover
-
-
-  // POPOVER NO CONFLICT
-  // ===================
-
-  $.fn.popover.noConflict = function () {
-    $.fn.popover = old
-    return this
-  }
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: scrollspy.js v3.1.1
- * http://getbootstrap.com/javascript/#scrollspy
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // SCROLLSPY CLASS DEFINITION
-  // ==========================
-
-  function ScrollSpy(element, options) {
-    var href
-    var process  = $.proxy(this.process, this)
-
-    this.$element       = $(element).is('body') ? $(window) : $(element)
-    this.$body          = $('body')
-    this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
-    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
-    this.selector       = (this.options.target
-      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
-      || '') + ' .nav li > a'
-    this.offsets        = $([])
-    this.targets        = $([])
-    this.activeTarget   = null
-
-    this.refresh()
-    this.process()
-  }
-
-  ScrollSpy.DEFAULTS = {
-    offset: 10
-  }
-
-  ScrollSpy.prototype.refresh = function () {
-    var offsetMethod = this.$element[0] == window ? 'offset' : 'position'
-
-    this.offsets = $([])
-    this.targets = $([])
-
-    var self     = this
-    var $targets = this.$body
-      .find(this.selector)
-      .map(function () {
-        var $el   = $(this)
-        var href  = $el.data('target') || $el.attr('href')
-        var $href = /^#./.test(href) && $(href)
-
-        return ($href
-          && $href.length
-          && $href.is(':visible')
-          && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
-      })
-      .sort(function (a, b) { return a[0] - b[0] })
-      .each(function () {
-        self.offsets.push(this[0])
-        self.targets.push(this[1])
-      })
-  }
-
-  ScrollSpy.prototype.process = function () {
-    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
-    var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
-    var maxScroll    = scrollHeight - this.$scrollElement.height()
-    var offsets      = this.offsets
-    var targets      = this.targets
-    var activeTarget = this.activeTarget
-    var i
-
-    if (scrollTop >= maxScroll) {
-      return activeTarget != (i = targets.last()[0]) && this.activate(i)
-    }
-
-    if (activeTarget && scrollTop <= offsets[0]) {
-      return activeTarget != (i = targets[0]) && this.activate(i)
-    }
-
-    for (i = offsets.length; i--;) {
-      activeTarget != targets[i]
-        && scrollTop >= offsets[i]
-        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
-        && this.activate( targets[i] )
-    }
-  }
-
-  ScrollSpy.prototype.activate = function (target) {
-    this.activeTarget = target
-
-    $(this.selector)
-      .parentsUntil(this.options.target, '.active')
-      .removeClass('active')
-
-    var selector = this.selector +
-        '[data-target="' + target + '"],' +
-        this.selector + '[href="' + target + '"]'
-
-    var active = $(selector)
-      .parents('li')
-      .addClass('active')
-
-    if (active.parent('.dropdown-menu').length) {
-      active = active
-        .closest('li.dropdown')
-        .addClass('active')
-    }
-
-    active.trigger('activate.bs.scrollspy')
-  }
-
-
-  // SCROLLSPY PLUGIN DEFINITION
-  // ===========================
-
-  var old = $.fn.scrollspy
-
-  $.fn.scrollspy = function (option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.scrollspy')
-      var options = typeof option == 'object' && option
-
-      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.scrollspy.Constructor = ScrollSpy
-
-
-  // SCROLLSPY NO CONFLICT
-  // =====================
-
-  $.fn.scrollspy.noConflict = function () {
-    $.fn.scrollspy = old
-    return this
-  }
-
-
-  // SCROLLSPY DATA-API
-  // ==================
-
-  $(window).on('load', function () {
-    $('[data-spy="scroll"]').each(function () {
-      var $spy = $(this)
-      $spy.scrollspy($spy.data())
-    })
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: tab.js v3.1.1
- * http://getbootstrap.com/javascript/#tabs
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // TAB CLASS DEFINITION
-  // ====================
-
-  var Tab = function (element) {
-    this.element = $(element)
-  }
-
-  Tab.prototype.show = function () {
-    var $this    = this.element
-    var $ul      = $this.closest('ul:not(.dropdown-menu)')
-    var selector = $this.data('target')
-
-    if (!selector) {
-      selector = $this.attr('href')
-      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
-    }
-
-    if ($this.parent('li').hasClass('active')) return
-
-    var previous = $ul.find('.active:last a')[0]
-    var e        = $.Event('show.bs.tab', {
-      relatedTarget: previous
-    })
-
-    $this.trigger(e)
-
-    if (e.isDefaultPrevented()) return
-
-    var $target = $(selector)
-
-    this.activate($this.parent('li'), $ul)
-    this.activate($target, $target.parent(), function () {
-      $this.trigger({
-        type: 'shown.bs.tab',
-        relatedTarget: previous
-      })
-    })
-  }
-
-  Tab.prototype.activate = function (element, container, callback) {
-    var $active    = container.find('> .active')
-    var transition = callback
-      && $.support.transition
-      && $active.hasClass('fade')
-
-    function next() {
-      $active
-        .removeClass('active')
-        .find('> .dropdown-menu > .active')
-        .removeClass('active')
-
-      element.addClass('active')
-
-      if (transition) {
-        element[0].offsetWidth // reflow for transition
-        element.addClass('in')
-      } else {
-        element.removeClass('fade')
-      }
-
-      if (element.parent('.dropdown-menu')) {
-        element.closest('li.dropdown').addClass('active')
-      }
-
-      callback && callback()
-    }
-
-    transition ?
-      $active
-        .one($.support.transition.end, next)
-        .emulateTransitionEnd(150) :
-      next()
-
-    $active.removeClass('in')
-  }
-
-
-  // TAB PLUGIN DEFINITION
-  // =====================
-
-  var old = $.fn.tab
-
-  $.fn.tab = function ( option ) {
-    return this.each(function () {
-      var $this = $(this)
-      var data  = $this.data('bs.tab')
-
-      if (!data) $this.data('bs.tab', (data = new Tab(this)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.tab.Constructor = Tab
-
-
-  // TAB NO CONFLICT
-  // ===============
-
-  $.fn.tab.noConflict = function () {
-    $.fn.tab = old
-    return this
-  }
-
-
-  // TAB DATA-API
-  // ============
-
-  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
-    e.preventDefault()
-    $(this).tab('show')
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: affix.js v3.1.1
- * http://getbootstrap.com/javascript/#affix
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // AFFIX CLASS DEFINITION
-  // ======================
-
-  var Affix = function (element, options) {
-    this.options = $.extend({}, Affix.DEFAULTS, options)
-    this.$window = $(window)
-      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
-      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
-
-    this.$element     = $(element)
-    this.affixed      =
-    this.unpin        =
-    this.pinnedOffset = null
-
-    this.checkPosition()
-  }
-
-  Affix.RESET = 'affix affix-top affix-bottom'
-
-  Affix.DEFAULTS = {
-    offset: 0
-  }
-
-  Affix.prototype.getPinnedOffset = function () {
-    if (this.pinnedOffset) return this.pinnedOffset
-    this.$element.removeClass(Affix.RESET).addClass('affix')
-    var scrollTop = this.$window.scrollTop()
-    var position  = this.$element.offset()
-    return (this.pinnedOffset = position.top - scrollTop)
-  }
-
-  Affix.prototype.checkPositionWithEventLoop = function () {
-    setTimeout($.proxy(this.checkPosition, this), 1)
-  }
-
-  Affix.prototype.checkPosition = function () {
-    if (!this.$element.is(':visible')) return
-
-    var scrollHeight = $(document).height()
-    var scrollTop    = this.$window.scrollTop()
-    var position     = this.$element.offset()
-    var offset       = this.options.offset
-    var offsetTop    = offset.top
-    var offsetBottom = offset.bottom
-
-    if (this.affixed == 'top') position.top += scrollTop
-
-    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
-    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
-    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
-
-    var affix = this.unpin   != null && (scrollTop + this.unpin <= position.top) ? false :
-                offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
-                offsetTop    != null && (scrollTop <= offsetTop) ? 'top' : false
-
-    if (this.affixed === affix) return
-    if (this.unpin) this.$element.css('top', '')
-
-    var affixType = 'affix' + (affix ? '-' + affix : '')
-    var e         = $.Event(affixType + '.bs.affix')
-
-    this.$element.trigger(e)
-
-    if (e.isDefaultPrevented()) return
-
-    this.affixed = affix
-    this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
-
-    this.$element
-      .removeClass(Affix.RESET)
-      .addClass(affixType)
-      .trigger($.Event(affixType.replace('affix', 'affixed')))
-
-    if (affix == 'bottom') {
-      this.$element.offset({ top: scrollHeight - offsetBottom - this.$element.height() })
-    }
-  }
-
-
-  // AFFIX PLUGIN DEFINITION
-  // =======================
-
-  var old = $.fn.affix
-
-  $.fn.affix = function (option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.affix')
-      var options = typeof option == 'object' && option
-
-      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.affix.Constructor = Affix
-
-
-  // AFFIX NO CONFLICT
-  // =================
-
-  $.fn.affix.noConflict = function () {
-    $.fn.affix = old
-    return this
-  }
-
-
-  // AFFIX DATA-API
-  // ==============
-
-  $(window).on('load', function () {
-    $('[data-spy="affix"]').each(function () {
-      var $spy = $(this)
-      var data = $spy.data()
-
-      data.offset = data.offset || {}
-
-      if (data.offsetBottom) data.offset.bottom = data.offsetBottom
-      if (data.offsetTop)    data.offset.top    = data.offsetTop
-
-      $spy.affix(data)
-    })
-  })
-
-}(jQuery);
diff --git a/hubs/static/bootstrap-3.1.1-fedora/js/bootstrap.min.js b/hubs/static/bootstrap-3.1.1-fedora/js/bootstrap.min.js
deleted file mode 100644
index b04a0e8..0000000
--- a/hubs/static/bootstrap-3.1.1-fedora/js/bootstrap.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*!
- * Bootstrap v3.1.1 (http://getbootstrap.com)
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.isLoading=!1};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",f.resetText||d.data("resetText",d[e]()),d[e](f[b]||this.options[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},b.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});return this.$element.trigger(j),j.isDefaultPrevented()?void 0:(this.sliding=!0,f&&this.pause(),this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid.bs.carousel",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid.bs.carousel")},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid.bs.carousel")),f&&this.cycle(),this)};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("collapse in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);!e&&f.toggle&&"show"==c&&(c=!c),e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(b){a(d).remove(),a(e).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown",h),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=" li:not(.divider):visible a",i=f.find("[role=menu]"+h+", [role=listbox]"+h);if(i.length){var j=i.index(i.filter(":focus"));38==b.keyCode&&j>0&&j--,40==b.keyCode&&j<i.length-1&&j++,~j||(j=0),i.eq(j).focus()}}}};var g=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.dropdown.Constructor=f,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=g,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu], [role=listbox]",f.prototype.keydown)}(jQuery),+function(a){"use strict";var b=function(b,c){this.options=c,this.$element=a(b),this.$backdrop=this.isShown=null,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this[this.isShown?"hide":"show"](a)},b.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(document.body),c.$element.show().scrollTop(0),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one(a.support.transition.end,function(){c.$element.focus().trigger(e)}).emulateTransitionEnd(300):c.$element.focus().trigger(e)}))},b.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one(a.support.transition.end,a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.focus()},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden.bs.modal")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},b.prototype.backdrop=function(b){var c=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var d=a.support.transition&&c;if(this.$backdrop=a('<div class="modal-backdrop '+c+'" />').appendTo(document.body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());c.is("a")&&b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.focus()})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this,d=this.tip();this.setContent(),this.options.animation&&d.addClass("fade");var e="function"==typeof this.options.placement?this.options.placement.call(this,d[0],this.$element[0]):this.options.placement,f=/\s?auto?\s?/i,g=f.test(e);g&&(e=e.replace(f,"")||"top"),d.detach().css({top:0,left:0,display:"block"}).addClass(e),this.options.container?d.appendTo(this.options.container):d.insertAfter(this.$element);var h=this.getPosition(),i=d[0].offsetWidth,j=d[0].offsetHeight;if(g){var k=this.$element.parent(),l=e,m=document.documentElement.scrollTop||document.body.scrollTop,n="body"==this.options.container?window.innerWidth:k.outerWidth(),o="body"==this.options.container?window.innerHeight:k.outerHeight(),p="body"==this.options.container?0:k.offset().left;e="bottom"==e&&h.top+h.height+j-m>o?"top":"top"==e&&h.top-m-j<0?"bottom":"right"==e&&h.right+i>n?"left":"left"==e&&h.left-i<p?"right":e,d.removeClass(l).addClass(e)}var q=this.getCalculatedOffset(e,h,i,j);this.applyPlacement(q,e),this.hoverState=null;var r=function(){c.$element.trigger("shown.bs."+c.type)};a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,r).emulateTransitionEnd(150):r()}},b.prototype.applyPlacement=function(b,c){var d,e=this.tip(),f=e[0].offsetWidth,g=e[0].offsetHeight,h=parseInt(e.css("margin-top"),10),i=parseInt(e.css("margin-left"),10);isNaN(h)&&(h=0),isNaN(i)&&(i=0),b.top=b.top+h,b.left=b.left+i,a.offset.setOffset(e[0],a.extend({using:function(a){e.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),e.addClass("in");var j=e[0].offsetWidth,k=e[0].offsetHeight;if("top"==c&&k!=g&&(d=!0,b.top=b.top+g-k),/bottom|top/.test(c)){var l=0;b.left<0&&(l=-2*b.left,b.left=0,e.offset(b),j=e[0].offsetWidth,k=e[0].offsetHeight),this.replaceArrow(l-f+j,j,"left")}else this.replaceArrow(k-g,k,"top");d&&e.offset(b)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach(),c.$element.trigger("hidden.bs."+c.type)}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.hoverState=null,this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){clearTimeout(this.timeout),this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;(e||"destroy"!=c)&&(e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]())})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;(e||"destroy"!=c)&&(e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]())})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(a(c).is("body")?window:c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);{var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})}},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);if(g&&b<=e[0])return g!=(a=f[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parentsUntil(this.options.target,".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(b.RESET).addClass("affix");var a=this.$window.scrollTop(),c=this.$element.offset();return this.pinnedOffset=c.top-a},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"top"==this.affixed&&(e.top+=d),"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top(this.$element)),"function"==typeof h&&(h=f.bottom(this.$element));var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;if(this.affixed!==i){this.unpin&&this.$element.css("top","");var j="affix"+(i?"-"+i:""),k=a.Event(j+".bs.affix");this.$element.trigger(k),k.isDefaultPrevented()||(this.affixed=i,this.unpin="bottom"==i?this.getPinnedOffset():null,this.$element.removeClass(b.RESET).addClass(j).trigger(a.Event(j.replace("affix","affixed"))),"bottom"==i&&this.$element.offset({top:c-h-this.$element.height()}))}}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery);
\ No newline at end of file

From 2b42a211dc425ac6c8ff54401ef43f62f7b7eb23 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 10:09:50 +0000
Subject: [PATCH 451/1001] Remove the old bootstrap files that we no longer use


Instead everything from bootstrap should come from fedora-bootstrap

---

diff --git a/hubs/static/bootstrap b/hubs/static/bootstrap
deleted file mode 120000
index 41ec0f8..0000000
--- a/hubs/static/bootstrap
+++ /dev/null
@@ -1 +0,0 @@
-bootstrap-3.3.4-fedora
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css
deleted file mode 100644
index 5365111..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css
+++ /dev/null
@@ -1,587 +0,0 @@
-/*!
- * Bootstrap v3.3.4 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-.btn-default,
-.btn-primary,
-.btn-success,
-.btn-info,
-.btn-warning,
-.btn-danger {
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
-}
-.btn-default:active,
-.btn-primary:active,
-.btn-success:active,
-.btn-info:active,
-.btn-warning:active,
-.btn-danger:active,
-.btn-default.active,
-.btn-primary.active,
-.btn-success.active,
-.btn-info.active,
-.btn-warning.active,
-.btn-danger.active {
-  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-}
-.btn-default.disabled,
-.btn-primary.disabled,
-.btn-success.disabled,
-.btn-info.disabled,
-.btn-warning.disabled,
-.btn-danger.disabled,
-.btn-default[disabled],
-.btn-primary[disabled],
-.btn-success[disabled],
-.btn-info[disabled],
-.btn-warning[disabled],
-.btn-danger[disabled],
-fieldset[disabled] .btn-default,
-fieldset[disabled] .btn-primary,
-fieldset[disabled] .btn-success,
-fieldset[disabled] .btn-info,
-fieldset[disabled] .btn-warning,
-fieldset[disabled] .btn-danger {
-  -webkit-box-shadow: none;
-          box-shadow: none;
-}
-.btn-default .badge,
-.btn-primary .badge,
-.btn-success .badge,
-.btn-info .badge,
-.btn-warning .badge,
-.btn-danger .badge {
-  text-shadow: none;
-}
-.btn:active,
-.btn.active {
-  background-image: none;
-}
-.btn-default {
-  text-shadow: 0 1px 0 #fff;
-  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
-  background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
-  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #dbdbdb;
-  border-color: #ccc;
-}
-.btn-default:hover,
-.btn-default:focus {
-  background-color: #e0e0e0;
-  background-position: 0 -15px;
-}
-.btn-default:active,
-.btn-default.active {
-  background-color: #e0e0e0;
-  border-color: #dbdbdb;
-}
-.btn-default.disabled,
-.btn-default[disabled],
-fieldset[disabled] .btn-default,
-.btn-default.disabled:hover,
-.btn-default[disabled]:hover,
-fieldset[disabled] .btn-default:hover,
-.btn-default.disabled:focus,
-.btn-default[disabled]:focus,
-fieldset[disabled] .btn-default:focus,
-.btn-default.disabled.focus,
-.btn-default[disabled].focus,
-fieldset[disabled] .btn-default.focus,
-.btn-default.disabled:active,
-.btn-default[disabled]:active,
-fieldset[disabled] .btn-default:active,
-.btn-default.disabled.active,
-.btn-default[disabled].active,
-fieldset[disabled] .btn-default.active {
-  background-color: #e0e0e0;
-  background-image: none;
-}
-.btn-primary {
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
-  background-image:      -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2));
-  background-image:         linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #2b669a;
-}
-.btn-primary:hover,
-.btn-primary:focus {
-  background-color: #2d6ca2;
-  background-position: 0 -15px;
-}
-.btn-primary:active,
-.btn-primary.active {
-  background-color: #2d6ca2;
-  border-color: #2b669a;
-}
-.btn-primary.disabled,
-.btn-primary[disabled],
-fieldset[disabled] .btn-primary,
-.btn-primary.disabled:hover,
-.btn-primary[disabled]:hover,
-fieldset[disabled] .btn-primary:hover,
-.btn-primary.disabled:focus,
-.btn-primary[disabled]:focus,
-fieldset[disabled] .btn-primary:focus,
-.btn-primary.disabled.focus,
-.btn-primary[disabled].focus,
-fieldset[disabled] .btn-primary.focus,
-.btn-primary.disabled:active,
-.btn-primary[disabled]:active,
-fieldset[disabled] .btn-primary:active,
-.btn-primary.disabled.active,
-.btn-primary[disabled].active,
-fieldset[disabled] .btn-primary.active {
-  background-color: #2d6ca2;
-  background-image: none;
-}
-.btn-success {
-  background-image: -webkit-linear-gradient(top, #79db32 0%, #5cb11f 100%);
-  background-image:      -o-linear-gradient(top, #79db32 0%, #5cb11f 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#79db32), to(#5cb11f));
-  background-image:         linear-gradient(to bottom, #79db32 0%, #5cb11f 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff5cb11f', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #58a81e;
-}
-.btn-success:hover,
-.btn-success:focus {
-  background-color: #5cb11f;
-  background-position: 0 -15px;
-}
-.btn-success:active,
-.btn-success.active {
-  background-color: #5cb11f;
-  border-color: #58a81e;
-}
-.btn-success.disabled,
-.btn-success[disabled],
-fieldset[disabled] .btn-success,
-.btn-success.disabled:hover,
-.btn-success[disabled]:hover,
-fieldset[disabled] .btn-success:hover,
-.btn-success.disabled:focus,
-.btn-success[disabled]:focus,
-fieldset[disabled] .btn-success:focus,
-.btn-success.disabled.focus,
-.btn-success[disabled].focus,
-fieldset[disabled] .btn-success.focus,
-.btn-success.disabled:active,
-.btn-success[disabled]:active,
-fieldset[disabled] .btn-success:active,
-.btn-success.disabled.active,
-.btn-success[disabled].active,
-fieldset[disabled] .btn-success.active {
-  background-color: #5cb11f;
-  background-image: none;
-}
-.btn-info {
-  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #8255a6 100%);
-  background-image:      -o-linear-gradient(top, #a07cbc 0%, #8255a6 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#a07cbc), to(#8255a6));
-  background-image:         linear-gradient(to bottom, #a07cbc 0%, #8255a6 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff8255a6', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #7d519f;
-}
-.btn-info:hover,
-.btn-info:focus {
-  background-color: #8255a6;
-  background-position: 0 -15px;
-}
-.btn-info:active,
-.btn-info.active {
-  background-color: #8255a6;
-  border-color: #7d519f;
-}
-.btn-info.disabled,
-.btn-info[disabled],
-fieldset[disabled] .btn-info,
-.btn-info.disabled:hover,
-.btn-info[disabled]:hover,
-fieldset[disabled] .btn-info:hover,
-.btn-info.disabled:focus,
-.btn-info[disabled]:focus,
-fieldset[disabled] .btn-info:focus,
-.btn-info.disabled.focus,
-.btn-info[disabled].focus,
-fieldset[disabled] .btn-info.focus,
-.btn-info.disabled:active,
-.btn-info[disabled]:active,
-fieldset[disabled] .btn-info:active,
-.btn-info.disabled.active,
-.btn-info[disabled].active,
-fieldset[disabled] .btn-info.active {
-  background-color: #8255a6;
-  background-image: none;
-}
-.btn-warning {
-  background-image: -webkit-linear-gradient(top, #e59728 0%, #b97616 100%);
-  background-image:      -o-linear-gradient(top, #e59728 0%, #b97616 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#e59728), to(#b97616));
-  background-image:         linear-gradient(to bottom, #e59728 0%, #b97616 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffb97616', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #b07015;
-}
-.btn-warning:hover,
-.btn-warning:focus {
-  background-color: #b97616;
-  background-position: 0 -15px;
-}
-.btn-warning:active,
-.btn-warning.active {
-  background-color: #b97616;
-  border-color: #b07015;
-}
-.btn-warning.disabled,
-.btn-warning[disabled],
-fieldset[disabled] .btn-warning,
-.btn-warning.disabled:hover,
-.btn-warning[disabled]:hover,
-fieldset[disabled] .btn-warning:hover,
-.btn-warning.disabled:focus,
-.btn-warning[disabled]:focus,
-fieldset[disabled] .btn-warning:focus,
-.btn-warning.disabled.focus,
-.btn-warning[disabled].focus,
-fieldset[disabled] .btn-warning.focus,
-.btn-warning.disabled:active,
-.btn-warning[disabled]:active,
-fieldset[disabled] .btn-warning:active,
-.btn-warning.disabled.active,
-.btn-warning[disabled].active,
-fieldset[disabled] .btn-warning.active {
-  background-color: #b97616;
-  background-image: none;
-}
-.btn-danger {
-  background-image: -webkit-linear-gradient(top, #db3279 0%, #b11f5c 100%);
-  background-image:      -o-linear-gradient(top, #db3279 0%, #b11f5c 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#db3279), to(#b11f5c));
-  background-image:         linear-gradient(to bottom, #db3279 0%, #b11f5c 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb11f5c', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-color: #a81e58;
-}
-.btn-danger:hover,
-.btn-danger:focus {
-  background-color: #b11f5c;
-  background-position: 0 -15px;
-}
-.btn-danger:active,
-.btn-danger.active {
-  background-color: #b11f5c;
-  border-color: #a81e58;
-}
-.btn-danger.disabled,
-.btn-danger[disabled],
-fieldset[disabled] .btn-danger,
-.btn-danger.disabled:hover,
-.btn-danger[disabled]:hover,
-fieldset[disabled] .btn-danger:hover,
-.btn-danger.disabled:focus,
-.btn-danger[disabled]:focus,
-fieldset[disabled] .btn-danger:focus,
-.btn-danger.disabled.focus,
-.btn-danger[disabled].focus,
-fieldset[disabled] .btn-danger.focus,
-.btn-danger.disabled:active,
-.btn-danger[disabled]:active,
-fieldset[disabled] .btn-danger:active,
-.btn-danger.disabled.active,
-.btn-danger[disabled].active,
-fieldset[disabled] .btn-danger.active {
-  background-color: #b11f5c;
-  background-image: none;
-}
-.thumbnail,
-.img-thumbnail {
-  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-}
-.dropdown-menu > li > a:hover,
-.dropdown-menu > li > a:focus {
-  background-color: #e8e8e8;
-  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
-  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
-  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
-  background-repeat: repeat-x;
-}
-.dropdown-menu > .active > a,
-.dropdown-menu > .active > a:hover,
-.dropdown-menu > .active > a:focus {
-  background-color: #357ebd;
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
-  background-image:      -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
-  background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
-  background-repeat: repeat-x;
-}
-.navbar-default {
-  background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
-  background-image:      -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
-  background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
-}
-.navbar-default .navbar-nav > .open > a,
-.navbar-default .navbar-nav > .active > a {
-  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
-  background-image:      -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
-  background-image:         linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
-  background-repeat: repeat-x;
-  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
-}
-.navbar-brand,
-.navbar-nav > li > a {
-  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
-}
-.navbar-inverse {
-  background-image: -webkit-linear-gradient(top, #365698 0%, #294172 100%);
-  background-image:      -o-linear-gradient(top, #365698 0%, #294172 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#365698), to(#294172));
-  background-image:         linear-gradient(to bottom, #365698 0%, #294172 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff365698', endColorstr='#ff294172', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-  background-repeat: repeat-x;
-}
-.navbar-inverse .navbar-nav > .open > a,
-.navbar-inverse .navbar-nav > .active > a {
-  background-image: -webkit-linear-gradient(top, #1c2c4c 0%, #1f3156 100%);
-  background-image:      -o-linear-gradient(top, #1c2c4c 0%, #1f3156 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#1c2c4c), to(#1f3156));
-  background-image:         linear-gradient(to bottom, #1c2c4c 0%, #1f3156 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1c2c4c', endColorstr='#ff1f3156', GradientType=0);
-  background-repeat: repeat-x;
-  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
-          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
-}
-.navbar-inverse .navbar-brand,
-.navbar-inverse .navbar-nav > li > a {
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
-}
-.navbar-static-top,
-.navbar-fixed-top,
-.navbar-fixed-bottom {
-  border-radius: 0;
-}
-@media (max-width: 767px) {
-  .navbar .navbar-nav .open .dropdown-menu > .active > a,
-  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
-  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
-    color: #fff;
-    background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
-    background-image:      -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
-    background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
-    background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
-    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
-    background-repeat: repeat-x;
-  }
-}
-.alert {
-  text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
-}
-.alert-success {
-  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #c7f0a9 100%);
-  background-image:      -o-linear-gradient(top, #dcf6ca 0%, #c7f0a9 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#dcf6ca), to(#c7f0a9));
-  background-image:         linear-gradient(to bottom, #dcf6ca 0%, #c7f0a9 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffc7f0a9', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #b2ea89;
-}
-.alert-info {
-  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e3d9eb 100%);
-  background-image:      -o-linear-gradient(top, #f6f2f8 0%, #e3d9eb 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#f6f2f8), to(#e3d9eb));
-  background-image:         linear-gradient(to bottom, #f6f2f8 0%, #e3d9eb 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe3d9eb', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #d1bfdf;
-}
-.alert-warning {
-  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f4d4a5 100%);
-  background-image:      -o-linear-gradient(top, #f8e4c7 0%, #f4d4a5 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#f8e4c7), to(#f4d4a5));
-  background-image:         linear-gradient(to bottom, #f8e4c7 0%, #f4d4a5 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff4d4a5', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #f0c383;
-}
-.alert-danger {
-  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f0a9c7 100%);
-  background-image:      -o-linear-gradient(top, #f6cadc 0%, #f0a9c7 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#f6cadc), to(#f0a9c7));
-  background-image:         linear-gradient(to bottom, #f6cadc 0%, #f0a9c7 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff0a9c7', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #ea89b2;
-}
-.progress {
-  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
-  background-image:      -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
-  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar {
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
-  background-image:      -o-linear-gradient(top, #428bca 0%, #3071a9 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9));
-  background-image:         linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar-success {
-  background-image: -webkit-linear-gradient(top, #79db32 0%, #61b921 100%);
-  background-image:      -o-linear-gradient(top, #79db32 0%, #61b921 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#79db32), to(#61b921));
-  background-image:         linear-gradient(to bottom, #79db32 0%, #61b921 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff61b921', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar-info {
-  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #885aab 100%);
-  background-image:      -o-linear-gradient(top, #a07cbc 0%, #885aab 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#a07cbc), to(#885aab));
-  background-image:         linear-gradient(to bottom, #a07cbc 0%, #885aab 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff885aab', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar-warning {
-  background-image: -webkit-linear-gradient(top, #e59728 0%, #c27c18 100%);
-  background-image:      -o-linear-gradient(top, #e59728 0%, #c27c18 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#e59728), to(#c27c18));
-  background-image:         linear-gradient(to bottom, #e59728 0%, #c27c18 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffc27c18', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar-danger {
-  background-image: -webkit-linear-gradient(top, #db3279 0%, #b92161 100%);
-  background-image:      -o-linear-gradient(top, #db3279 0%, #b92161 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#db3279), to(#b92161));
-  background-image:         linear-gradient(to bottom, #db3279 0%, #b92161 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb92161', GradientType=0);
-  background-repeat: repeat-x;
-}
-.progress-bar-striped {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.list-group {
-  border-radius: 4px;
-  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-}
-.list-group-item.active,
-.list-group-item.active:hover,
-.list-group-item.active:focus {
-  text-shadow: 0 -1px 0 #3071a9;
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
-  background-image:      -o-linear-gradient(top, #428bca 0%, #3278b3 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3));
-  background-image:         linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #3278b3;
-}
-.list-group-item.active .badge,
-.list-group-item.active:hover .badge,
-.list-group-item.active:focus .badge {
-  text-shadow: none;
-}
-.panel {
-  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
-          box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
-}
-.panel-default > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
-  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
-  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-primary > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
-  background-image:      -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
-  background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-success > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #cef2b4 100%);
-  background-image:      -o-linear-gradient(top, #dcf6ca 0%, #cef2b4 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#dcf6ca), to(#cef2b4));
-  background-image:         linear-gradient(to bottom, #dcf6ca 0%, #cef2b4 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffcef2b4', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-info > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e9e1f0 100%);
-  background-image:      -o-linear-gradient(top, #f6f2f8 0%, #e9e1f0 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#f6f2f8), to(#e9e1f0));
-  background-image:         linear-gradient(to bottom, #f6f2f8 0%, #e9e1f0 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe9e1f0', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-warning > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f6d9b0 100%);
-  background-image:      -o-linear-gradient(top, #f8e4c7 0%, #f6d9b0 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#f8e4c7), to(#f6d9b0));
-  background-image:         linear-gradient(to bottom, #f8e4c7 0%, #f6d9b0 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff6d9b0', GradientType=0);
-  background-repeat: repeat-x;
-}
-.panel-danger > .panel-heading {
-  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f2b4ce 100%);
-  background-image:      -o-linear-gradient(top, #f6cadc 0%, #f2b4ce 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#f6cadc), to(#f2b4ce));
-  background-image:         linear-gradient(to bottom, #f6cadc 0%, #f2b4ce 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff2b4ce', GradientType=0);
-  background-repeat: repeat-x;
-}
-.well {
-  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
-  background-image:      -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
-  background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
-  background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
-  background-repeat: repeat-x;
-  border-color: #dcdcdc;
-  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
-          box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
-}
-/*# sourceMappingURL=bootstrap-theme.css.map */
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css.map b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css.map
deleted file mode 100644
index 1fade89..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","bootstrap-theme.css","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAcA;;;;;;EAME,0CAAA;ECgDA,6FAAA;EACQ,qFAAA;EC5DT;AFgBC;;;;;;;;;;;;EC2CA,0DAAA;EACQ,kDAAA;EC7CT;AFMC;;;;;;;;;;;;;;;;;;ECsCA,0BAAA;EACQ,kBAAA;ECxBT;AF/BD;;;;;;EAuBI,mBAAA;EEgBH;AFyBC;;EAEE,wBAAA;EEvBH;AF4BD;EGhEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJuCA,6BAAA;EACA,uBAAA;EAuC2C,2BAAA;EAA2B,oBAAA;EEjBvE;AFpBC;;EAEE,2BAAA;EACA,8BAAA;EEsBH;AFnBC;;EAEE,2BAAA;EACA,uBAAA;EEqBH;AFfG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACA,wBAAA;EE6BL;AFbD;EGjEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJuCA,6BAAA;EACA,uBAAA;EE8DD;AF5DC;;EAEE,2BAAA;EACA,8BAAA;EE8DH;AF3DC;;EAEE,2BAAA;EACA,uBAAA;EE6DH;AFvDG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACA,wBAAA;EEqEL;AFpDD;EGlEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJuCA,6BAAA;EACA,uBAAA;EEsGD;AFpGC;;EAEE,2BAAA;EACA,8BAAA;EEsGH;AFnGC;;EAEE,2BAAA;EACA,uBAAA;EEqGH;AF/FG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACA,wBAAA;EE6GL;AF3FD;EGnEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJuCA,6BAAA;EACA,uBAAA;EE8ID;AF5IC;;EAEE,2BAAA;EACA,8BAAA;EE8IH;AF3IC;;EAEE,2BAAA;EACA,uBAAA;EE6IH;AFvIG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACA,wBAAA;EEqJL;AFlID;EGpEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJuCA,6BAAA;EACA,uBAAA;EEsLD;AFpLC;;EAEE,2BAAA;EACA,8BAAA;EEsLH;AFnLC;;EAEE,2BAAA;EACA,uBAAA;EEqLH;AF/KG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACA,wBAAA;EE6LL;AFzKD;EGrEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJuCA,6BAAA;EACA,uBAAA;EE8ND;AF5NC;;EAEE,2BAAA;EACA,8BAAA;EE8NH;AF3NC;;EAEE,2BAAA;EACA,uBAAA;EE6NH;AFvNG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACA,wBAAA;EEqOL;AF1MD;;EC7BE,oDAAA;EACQ,4CAAA;EC2OT;AFrMD;;EGtFI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHqFF,2BAAA;EE2MD;AFzMD;;;EG3FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH2FF,2BAAA;EE+MD;AFtMD;EGxGI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EJ0HA,oBAAA;EC5DA,6FAAA;EACQ,qFAAA;ECyQT;AFjND;;EGxGI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,0DAAA;EACQ,kDAAA;ECmRT;AF9MD;;EAEE,gDAAA;EEgND;AF5MD;EG3HI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EF8VD;AFpND;;EG3HI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,yDAAA;EACQ,iDAAA;ECyST;AF9ND;;EAYI,2CAAA;EEsNH;AFjND;;;EAGE,kBAAA;EEmND;AF9LD;EAfI;;;IAGE,aAAA;IGxJF,0EAAA;IACA,qEAAA;IACA,+FAAA;IAAA,wEAAA;IACA,6BAAA;IACA,wHAAA;IDyWD;EACF;AF1MD;EACE,+CAAA;ECtHA,4FAAA;EACQ,oFAAA;ECmUT;AFlMD;EGjLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHyKF,uBAAA;EE8MD;AFzMD;EGlLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHyKF,uBAAA;EEsND;AFhND;EGnLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHyKF,uBAAA;EE8ND;AFvND;EGpLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHyKF,uBAAA;EEsOD;AFvND;EG5LI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDsZH;AFpND;EGtMI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED6ZH;AF1ND;EGvMI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDoaH;AFhOD;EGxMI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED2aH;AFtOD;EGzMI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDkbH;AF5OD;EG1MI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDybH;AF/OD;EG7KI,+MAAA;EACA,0MAAA;EACA,uMAAA;ED+ZH;AF3OD;EACE,oBAAA;ECzKA,oDAAA;EACQ,4CAAA;ECuZT;AF5OD;;;EAGE,+BAAA;EG9NE,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH4NF,uBAAA;EEkPD;AFvPD;;;EAQI,mBAAA;EEoPH;AF1OD;EC9LE,mDAAA;EACQ,2CAAA;EC2aT;AFpOD;EGvPI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8dH;AF1OD;EGxPI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDqeH;AFhPD;EGzPI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED4eH;AFtPD;EG1PI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDmfH;AF5PD;EG3PI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED0fH;AFlQD;EG5PI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDigBH;AFlQD;EGnQI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHiQF,uBAAA;ECtNA,2FAAA;EACQ,mFAAA;EC+dT","file":"bootstrap-theme.css","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n  text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n  @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n  .box-shadow(@shadow);\n\n  // Reset the shadow\n  &:active,\n  &.active {\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    .box-shadow(none);\n  }\n\n  .badge {\n    text-shadow: none;\n  }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n  #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n  .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n  background-repeat: repeat-x;\n  border-color: darken(@btn-color, 14%);\n\n  &:hover,\n  &:focus  {\n    background-color: darken(@btn-color, 12%);\n    background-position: 0 -15px;\n  }\n\n  &:active,\n  &.active {\n    background-color: darken(@btn-color, 12%);\n    border-color: darken(@btn-color, 14%);\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    &,\n    &:hover,\n    &:focus,\n    &.focus,\n    &:active,\n    &.active {\n      background-color: darken(@btn-color, 12%);\n      background-image: none;\n    }\n  }\n}\n\n// Common styles\n.btn {\n  // Remove the gradient for the pressed/active state\n  &:active,\n  &.active {\n    background-image: none;\n  }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info    { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger  { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n  .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n  background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n  background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n  .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n  border-radius: @navbar-border-radius;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n  .box-shadow(@shadow);\n\n  .navbar-nav > .open > a,\n  .navbar-nav > .active > a {\n    #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n    .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n  }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n  #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n  .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n\n  .navbar-nav > .open > a,\n  .navbar-nav > .active > a {\n    #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n    .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n  }\n\n  .navbar-brand,\n  .navbar-nav > li > a {\n    text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n  }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n  .navbar .navbar-nav .open .dropdown-menu > .active > a {\n    &,\n    &:hover,\n    &:focus {\n      color: #fff;\n      #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n    }\n  }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n  text-shadow: 0 1px 0 rgba(255,255,255,.2);\n  @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n  .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n  border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success    { .alert-styles(@alert-success-bg); }\n.alert-info       { .alert-styles(@alert-info-bg); }\n.alert-warning    { .alert-styles(@alert-warning-bg); }\n.alert-danger     { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n  #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar            { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success    { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info       { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning    { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger     { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n  #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n  border-radius: @border-radius-base;\n  .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n  #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n  border-color: darken(@list-group-active-border, 7.5%);\n\n  .badge {\n    text-shadow: none;\n  }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n  .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading   { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading   { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading   { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading      { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading   { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading    { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n  #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n  border-color: darken(@well-bg, 10%);\n  @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n  -webkit-animation: @animation;\n       -o-animation: @animation;\n          animation: @animation;\n}\n.animation-name(@name) {\n  -webkit-animation-name: @name;\n          animation-name: @name;\n}\n.animation-duration(@duration) {\n  -webkit-animation-duration: @duration;\n          animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n  -webkit-animation-timing-function: @timing-function;\n          animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n  -webkit-animation-delay: @delay;\n          animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n  -webkit-animation-iteration-count: @iteration-count;\n          animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n  -webkit-animation-direction: @direction;\n          animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n  -webkit-animation-fill-mode: @fill-mode;\n          animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n  -webkit-backface-visibility: @visibility;\n     -moz-backface-visibility: @visibility;\n          backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n  -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n          box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n  -webkit-box-sizing: @boxmodel;\n     -moz-box-sizing: @boxmodel;\n          box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n  -webkit-column-count: @column-count;\n     -moz-column-count: @column-count;\n          column-count: @column-count;\n  -webkit-column-gap: @column-gap;\n     -moz-column-gap: @column-gap;\n          column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n  word-wrap: break-word;\n  -webkit-hyphens: @mode;\n     -moz-hyphens: @mode;\n      -ms-hyphens: @mode; // IE10+\n       -o-hyphens: @mode;\n          hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n  // Firefox\n  &::-moz-placeholder {\n    color: @color;\n    opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n  }\n  &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n  &::-webkit-input-placeholder  { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n  -webkit-transform: scale(@ratio);\n      -ms-transform: scale(@ratio); // IE9 only\n       -o-transform: scale(@ratio);\n          transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n  -webkit-transform: scale(@ratioX, @ratioY);\n      -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n       -o-transform: scale(@ratioX, @ratioY);\n          transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n  -webkit-transform: scaleX(@ratio);\n      -ms-transform: scaleX(@ratio); // IE9 only\n       -o-transform: scaleX(@ratio);\n          transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n  -webkit-transform: scaleY(@ratio);\n      -ms-transform: scaleY(@ratio); // IE9 only\n       -o-transform: scaleY(@ratio);\n          transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n  -webkit-transform: skewX(@x) skewY(@y);\n      -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n       -o-transform: skewX(@x) skewY(@y);\n          transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n  -webkit-transform: translate(@x, @y);\n      -ms-transform: translate(@x, @y); // IE9 only\n       -o-transform: translate(@x, @y);\n          transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n  -webkit-transform: translate3d(@x, @y, @z);\n          transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n  -webkit-transform: rotate(@degrees);\n      -ms-transform: rotate(@degrees); // IE9 only\n       -o-transform: rotate(@degrees);\n          transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n  -webkit-transform: rotateX(@degrees);\n      -ms-transform: rotateX(@degrees); // IE9 only\n       -o-transform: rotateX(@degrees);\n          transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n  -webkit-transform: rotateY(@degrees);\n      -ms-transform: rotateY(@degrees); // IE9 only\n       -o-transform: rotateY(@degrees);\n          transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n  -webkit-perspective: @perspective;\n     -moz-perspective: @perspective;\n          perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n  -webkit-perspective-origin: @perspective;\n     -moz-perspective-origin: @perspective;\n          perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n  -webkit-transform-origin: @origin;\n     -moz-transform-origin: @origin;\n      -ms-transform-origin: @origin; // IE9 only\n          transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n  -webkit-transition: @transition;\n       -o-transition: @transition;\n          transition: @transition;\n}\n.transition-property(@transition-property) {\n  -webkit-transition-property: @transition-property;\n          transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n  -webkit-transition-delay: @transition-delay;\n          transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n  -webkit-transition-duration: @transition-duration;\n          transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n  -webkit-transition-timing-function: @timing-function;\n          transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n  -webkit-transition: -webkit-transform @transition;\n     -moz-transition: -moz-transform @transition;\n       -o-transition: -o-transform @transition;\n          transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n  -webkit-user-select: @select;\n     -moz-user-select: @select;\n      -ms-user-select: @select; // IE10+\n          user-select: @select;\n}\n",".btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n  text-shadow: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n}\n.btn-default {\n  background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n  background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n  background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #dbdbdb;\n  text-shadow: 0 1px 0 #fff;\n  border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n  background-color: #e0e0e0;\n  background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n  background-color: #e0e0e0;\n  border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #e0e0e0;\n  background-image: none;\n}\n.btn-primary {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #2b669a;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n  background-color: #2d6ca2;\n  background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n  background-color: #2d6ca2;\n  border-color: #2b669a;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #2d6ca2;\n  background-image: none;\n}\n.btn-success {\n  background-image: -webkit-linear-gradient(top, #79db32 0%, #5cb11f 100%);\n  background-image: -o-linear-gradient(top, #79db32 0%, #5cb11f 100%);\n  background-image: linear-gradient(to bottom, #79db32 0%, #5cb11f 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff5cb11f', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #58a81e;\n}\n.btn-success:hover,\n.btn-success:focus {\n  background-color: #5cb11f;\n  background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n  background-color: #5cb11f;\n  border-color: #58a81e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #5cb11f;\n  background-image: none;\n}\n.btn-info {\n  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #8255a6 100%);\n  background-image: -o-linear-gradient(top, #a07cbc 0%, #8255a6 100%);\n  background-image: linear-gradient(to bottom, #a07cbc 0%, #8255a6 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff8255a6', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #7d519f;\n}\n.btn-info:hover,\n.btn-info:focus {\n  background-color: #8255a6;\n  background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n  background-color: #8255a6;\n  border-color: #7d519f;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #8255a6;\n  background-image: none;\n}\n.btn-warning {\n  background-image: -webkit-linear-gradient(top, #e59728 0%, #b97616 100%);\n  background-image: -o-linear-gradient(top, #e59728 0%, #b97616 100%);\n  background-image: linear-gradient(to bottom, #e59728 0%, #b97616 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffb97616', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #b07015;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n  background-color: #b97616;\n  background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n  background-color: #b97616;\n  border-color: #b07015;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #b97616;\n  background-image: none;\n}\n.btn-danger {\n  background-image: -webkit-linear-gradient(top, #db3279 0%, #b11f5c 100%);\n  background-image: -o-linear-gradient(top, #db3279 0%, #b11f5c 100%);\n  background-image: linear-gradient(to bottom, #db3279 0%, #b11f5c 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb11f5c', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #a81e58;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n  background-color: #b11f5c;\n  background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n  background-color: #b11f5c;\n  border-color: #a81e58;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #b11f5c;\n  background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n  background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);\n  background-color: #357ebd;\n}\n.navbar-default {\n  background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n  background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n  background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n  background-image: -webkit-linear-gradient(top, #365698 0%, #294172 100%);\n  background-image: -o-linear-gradient(top, #365698 0%, #294172 100%);\n  background-image: linear-gradient(to bottom, #365698 0%, #294172 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff365698', endColorstr='#ff294172', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #1c2c4c 0%, #1f3156 100%);\n  background-image: -o-linear-gradient(top, #1c2c4c 0%, #1f3156 100%);\n  background-image: linear-gradient(to bottom, #1c2c4c 0%, #1f3156 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1c2c4c', endColorstr='#ff1f3156', GradientType=0);\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n  box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n@media (max-width: 767px) {\n  .navbar .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n    background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n    background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n    background-repeat: repeat-x;\n    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);\n  }\n}\n.alert {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #c7f0a9 100%);\n  background-image: -o-linear-gradient(top, #dcf6ca 0%, #c7f0a9 100%);\n  background-image: linear-gradient(to bottom, #dcf6ca 0%, #c7f0a9 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffc7f0a9', GradientType=0);\n  border-color: #b2ea89;\n}\n.alert-info {\n  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e3d9eb 100%);\n  background-image: -o-linear-gradient(top, #f6f2f8 0%, #e3d9eb 100%);\n  background-image: linear-gradient(to bottom, #f6f2f8 0%, #e3d9eb 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe3d9eb', GradientType=0);\n  border-color: #d1bfdf;\n}\n.alert-warning {\n  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f4d4a5 100%);\n  background-image: -o-linear-gradient(top, #f8e4c7 0%, #f4d4a5 100%);\n  background-image: linear-gradient(to bottom, #f8e4c7 0%, #f4d4a5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff4d4a5', GradientType=0);\n  border-color: #f0c383;\n}\n.alert-danger {\n  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f0a9c7 100%);\n  background-image: -o-linear-gradient(top, #f6cadc 0%, #f0a9c7 100%);\n  background-image: linear-gradient(to bottom, #f6cadc 0%, #f0a9c7 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff0a9c7', GradientType=0);\n  border-color: #ea89b2;\n}\n.progress {\n  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);\n}\n.progress-bar-success {\n  background-image: -webkit-linear-gradient(top, #79db32 0%, #61b921 100%);\n  background-image: -o-linear-gradient(top, #79db32 0%, #61b921 100%);\n  background-image: linear-gradient(to bottom, #79db32 0%, #61b921 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff61b921', GradientType=0);\n}\n.progress-bar-info {\n  background-image: -webkit-linear-gradient(top, #a07cbc 0%, #885aab 100%);\n  background-image: -o-linear-gradient(top, #a07cbc 0%, #885aab 100%);\n  background-image: linear-gradient(to bottom, #a07cbc 0%, #885aab 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff885aab', GradientType=0);\n}\n.progress-bar-warning {\n  background-image: -webkit-linear-gradient(top, #e59728 0%, #c27c18 100%);\n  background-image: -o-linear-gradient(top, #e59728 0%, #c27c18 100%);\n  background-image: linear-gradient(to bottom, #e59728 0%, #c27c18 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffc27c18', GradientType=0);\n}\n.progress-bar-danger {\n  background-image: -webkit-linear-gradient(top, #db3279 0%, #b92161 100%);\n  background-image: -o-linear-gradient(top, #db3279 0%, #b92161 100%);\n  background-image: linear-gradient(to bottom, #db3279 0%, #b92161 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb92161', GradientType=0);\n}\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  text-shadow: 0 -1px 0 #3071a9;\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);\n  border-color: #3278b3;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n  text-shadow: none;\n}\n.panel {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n  background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);\n}\n.panel-success > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #dcf6ca 0%, #cef2b4 100%);\n  background-image: -o-linear-gradient(top, #dcf6ca 0%, #cef2b4 100%);\n  background-image: linear-gradient(to bottom, #dcf6ca 0%, #cef2b4 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffcef2b4', GradientType=0);\n}\n.panel-info > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f6f2f8 0%, #e9e1f0 100%);\n  background-image: -o-linear-gradient(top, #f6f2f8 0%, #e9e1f0 100%);\n  background-image: linear-gradient(to bottom, #f6f2f8 0%, #e9e1f0 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe9e1f0', GradientType=0);\n}\n.panel-warning > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f8e4c7 0%, #f6d9b0 100%);\n  background-image: -o-linear-gradient(top, #f8e4c7 0%, #f6d9b0 100%);\n  background-image: linear-gradient(to bottom, #f8e4c7 0%, #f6d9b0 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff6d9b0', GradientType=0);\n}\n.panel-danger > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f6cadc 0%, #f2b4ce 100%);\n  background-image: -o-linear-gradient(top, #f6cadc 0%, #f2b4ce 100%);\n  background-image: linear-gradient(to bottom, #f6cadc 0%, #f2b4ce 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff2b4ce', GradientType=0);\n}\n.well {\n  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n  border-color: #dcdcdc;\n  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","// Gradients\n\n#gradient {\n\n  // Horizontal gradient, from left to right\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n    background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  // Vertical gradient, from top to bottom\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Opera 12\n    background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n    background-repeat: repeat-x;\n    background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n    background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n  }\n  .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .radial(@inner-color: #555; @outer-color: #333) {\n    background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n    background-image: radial-gradient(circle, @inner-color, @outer-color);\n    background-repeat: no-repeat;\n  }\n  .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n    background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n  }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n  filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.min.css b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.min.css
deleted file mode 100644
index 2222295..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap-theme.min.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/*!
- * Bootstrap v3.3.4 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:focus,.btn-primary:hover{background-color:#2d6ca2;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#2d6ca2;border-color:#2b669a}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#79db32 0,#5cb11f 100%);background-image:-o-linear-gradient(top,#79db32 0,#5cb11f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#79db32),to(#5cb11f));background-image:linear-gradient(to bottom,#79db32 0,#5cb11f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff5cb11f', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#58a81e}.btn-success:focus,.btn-success:hover{background-color:#5cb11f;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#5cb11f;border-color:#58a81e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb11f;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#a07cbc 0,#8255a6 100%);background-image:-o-linear-gradient(top,#a07cbc 0,#8255a6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#a07cbc),to(#8255a6));background-image:linear-gradient(to bottom,#a07cbc 0,#8255a6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff8255a6', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#7d519f}.btn-info:focus,.btn-info:hover{background-color:#8255a6;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#8255a6;border-color:#7d519f}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#8255a6;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#e59728 0,#b97616 100%);background-image:-o-linear-gradient(top,#e59728 0,#b97616 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e59728),to(#b97616));background-image:linear-gradient(to bottom,#e59728 0,#b97616 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffb97616', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b07015}.btn-warning:focus,.btn-warning:hover{background-color:#b97616;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#b97616;border-color:#b07015}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#b97616;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#db3279 0,#b11f5c 100%);background-image:-o-linear-gradient(top,#db3279 0,#b11f5c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#db3279),to(#b11f5c));background-image:linear-gradient(to bottom,#db3279 0,#b11f5c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb11f5c', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#a81e58}.btn-danger:focus,.btn-danger:hover{background-color:#b11f5c;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#b11f5c;border-color:#a81e58}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#b11f5c;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#365698 0,#294172 100%);background-image:-o-linear-gradient(top,#365698 0,#294172 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#365698),to(#294172));background-image:linear-gradient(to bottom,#365698 0,#294172 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff365698', endColorstr='#ff294172', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#1c2c4c 0,#1f3156 100%);background-image:-o-linear-gradient(top,#1c2c4c 0,#1f3156 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#1c2c4c),to(#1f3156));background-image:linear-gradient(to bottom,#1c2c4c 0,#1f3156 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1c2c4c', endColorstr='#ff1f3156', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dcf6ca 0,#c7f0a9 100%);background-image:-o-linear-gradient(top,#dcf6ca 0,#c7f0a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dcf6ca),to(#c7f0a9));background-image:linear-gradient(to bottom,#dcf6ca 0,#c7f0a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffc7f0a9', GradientType=0);background-repeat:repeat-x;border-color:#b2ea89}.alert-info{background-image:-webkit-linear-gradient(top,#f6f2f8 0,#e3d9eb 100%);background-image:-o-linear-gradient(top,#f6f2f8 0,#e3d9eb 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f6f2f8),to(#e3d9eb));background-image:linear-gradient(to bottom,#f6f2f8 0,#e3d9eb 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe3d9eb', GradientType=0);background-repeat:repeat-x;border-color:#d1bfdf}.alert-warning{background-image:-webkit-linear-gradient(top,#f8e4c7 0,#f4d4a5 100%);background-image:-o-linear-gradient(top,#f8e4c7 0,#f4d4a5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f8e4c7),to(#f4d4a5));background-image:linear-gradient(to bottom,#f8e4c7 0,#f4d4a5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff4d4a5', GradientType=0);background-repeat:repeat-x;border-color:#f0c383}.alert-danger{background-image:-webkit-linear-gradient(top,#f6cadc 0,#f0a9c7 100%);background-image:-o-linear-gradient(top,#f6cadc 0,#f0a9c7 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f6cadc),to(#f0a9c7));background-image:linear-gradient(to bottom,#f6cadc 0,#f0a9c7 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff0a9c7', GradientType=0);background-repeat:repeat-x;border-color:#ea89b2}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#79db32 0,#61b921 100%);background-image:-o-linear-gradient(top,#79db32 0,#61b921 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#79db32),to(#61b921));background-image:linear-gradient(to bottom,#79db32 0,#61b921 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff79db32', endColorstr='#ff61b921', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#a07cbc 0,#885aab 100%);background-image:-o-linear-gradient(top,#a07cbc 0,#885aab 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#a07cbc),to(#885aab));background-image:linear-gradient(to bottom,#a07cbc 0,#885aab 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa07cbc', endColorstr='#ff885aab', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#e59728 0,#c27c18 100%);background-image:-o-linear-gradient(top,#e59728 0,#c27c18 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e59728),to(#c27c18));background-image:linear-gradient(to bottom,#e59728 0,#c27c18 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe59728', endColorstr='#ffc27c18', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#db3279 0,#b92161 100%);background-image:-o-linear-gradient(top,#db3279 0,#b92161 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#db3279),to(#b92161));background-image:linear-gradient(to bottom,#db3279 0,#b92161 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdb3279', endColorstr='#ffb92161', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dcf6ca 0,#cef2b4 100%);background-image:-o-linear-gradient(top,#dcf6ca 0,#cef2b4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dcf6ca),to(#cef2b4));background-image:linear-gradient(to bottom,#dcf6ca 0,#cef2b4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdcf6ca', endColorstr='#ffcef2b4', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#f6f2f8 0,#e9e1f0 100%);background-image:-o-linear-gradient(top,#f6f2f8 0,#e9e1f0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f6f2f8),to(#e9e1f0));background-image:linear-gradient(to bottom,#f6f2f8 0,#e9e1f0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6f2f8', endColorstr='#ffe9e1f0', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#f8e4c7 0,#f6d9b0 100%);background-image:-o-linear-gradient(top,#f8e4c7 0,#f6d9b0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f8e4c7),to(#f6d9b0));background-image:linear-gradient(to bottom,#f8e4c7 0,#f6d9b0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff8e4c7', endColorstr='#fff6d9b0', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f6cadc 0,#f2b4ce 100%);background-image:-o-linear-gradient(top,#f6cadc 0,#f2b4ce 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f6cadc),to(#f2b4ce));background-image:linear-gradient(to bottom,#f6cadc 0,#f2b4ce 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff6cadc', endColorstr='#fff2b4ce', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css
deleted file mode 100644
index f463649..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css
+++ /dev/null
@@ -1,6764 +0,0 @@
-/*!
- * Bootstrap v3.3.4 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
-html {
-  font-family: sans-serif;
-  -webkit-text-size-adjust: 100%;
-      -ms-text-size-adjust: 100%;
-}
-body {
-  margin: 0;
-}
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-menu,
-nav,
-section,
-summary {
-  display: block;
-}
-audio,
-canvas,
-progress,
-video {
-  display: inline-block;
-  vertical-align: baseline;
-}
-audio:not([controls]) {
-  display: none;
-  height: 0;
-}
-[hidden],
-template {
-  display: none;
-}
-a {
-  background-color: transparent;
-}
-a:active,
-a:hover {
-  outline: 0;
-}
-abbr[title] {
-  border-bottom: 1px dotted;
-}
-b,
-strong {
-  font-weight: bold;
-}
-dfn {
-  font-style: italic;
-}
-h1 {
-  margin: .67em 0;
-  font-size: 2em;
-}
-mark {
-  color: #000;
-  background: #ff0;
-}
-small {
-  font-size: 80%;
-}
-sub,
-sup {
-  position: relative;
-  font-size: 75%;
-  line-height: 0;
-  vertical-align: baseline;
-}
-sup {
-  top: -.5em;
-}
-sub {
-  bottom: -.25em;
-}
-img {
-  border: 0;
-}
-svg:not(:root) {
-  overflow: hidden;
-}
-figure {
-  margin: 1em 40px;
-}
-hr {
-  height: 0;
-  -webkit-box-sizing: content-box;
-     -moz-box-sizing: content-box;
-          box-sizing: content-box;
-}
-pre {
-  overflow: auto;
-}
-code,
-kbd,
-pre,
-samp {
-  font-family: monospace, monospace;
-  font-size: 1em;
-}
-button,
-input,
-optgroup,
-select,
-textarea {
-  margin: 0;
-  font: inherit;
-  color: inherit;
-}
-button {
-  overflow: visible;
-}
-button,
-select {
-  text-transform: none;
-}
-button,
-html input[type="button"],
-input[type="reset"],
-input[type="submit"] {
-  -webkit-appearance: button;
-  cursor: pointer;
-}
-button[disabled],
-html input[disabled] {
-  cursor: default;
-}
-button::-moz-focus-inner,
-input::-moz-focus-inner {
-  padding: 0;
-  border: 0;
-}
-input {
-  line-height: normal;
-}
-input[type="checkbox"],
-input[type="radio"] {
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-  padding: 0;
-}
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
-  height: auto;
-}
-input[type="search"] {
-  -webkit-box-sizing: content-box;
-     -moz-box-sizing: content-box;
-          box-sizing: content-box;
-  -webkit-appearance: textfield;
-}
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
-  -webkit-appearance: none;
-}
-fieldset {
-  padding: .35em .625em .75em;
-  margin: 0 2px;
-  border: 1px solid #c0c0c0;
-}
-legend {
-  padding: 0;
-  border: 0;
-}
-textarea {
-  overflow: auto;
-}
-optgroup {
-  font-weight: bold;
-}
-table {
-  border-spacing: 0;
-  border-collapse: collapse;
-}
-td,
-th {
-  padding: 0;
-}
-/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
-@media print {
-  *,
-  *:before,
-  *:after {
-    color: #000 !important;
-    text-shadow: none !important;
-    background: transparent !important;
-    -webkit-box-shadow: none !important;
-            box-shadow: none !important;
-  }
-  a,
-  a:visited {
-    text-decoration: underline;
-  }
-  a[href]:after {
-    content: " (" attr(href) ")";
-  }
-  abbr[title]:after {
-    content: " (" attr(title) ")";
-  }
-  a[href^="#"]:after,
-  a[href^="javascript:"]:after {
-    content: "";
-  }
-  pre,
-  blockquote {
-    border: 1px solid #999;
-
-    page-break-inside: avoid;
-  }
-  thead {
-    display: table-header-group;
-  }
-  tr,
-  img {
-    page-break-inside: avoid;
-  }
-  img {
-    max-width: 100% !important;
-  }
-  p,
-  h2,
-  h3 {
-    orphans: 3;
-    widows: 3;
-  }
-  h2,
-  h3 {
-    page-break-after: avoid;
-  }
-  .navbar {
-    display: none;
-  }
-  .btn > .caret,
-  .dropup > .btn > .caret {
-    border-top-color: #000 !important;
-  }
-  .label {
-    border: 1px solid #000;
-  }
-  .table {
-    border-collapse: collapse !important;
-  }
-  .table td,
-  .table th {
-    background-color: #fff !important;
-  }
-  .table-bordered th,
-  .table-bordered td {
-    border: 1px solid #ddd !important;
-  }
-}
-@font-face {
-  font-family: 'Glyphicons Halflings';
-
-  src: url('../fonts/glyphicons-halflings-regular.eot');
-  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
-}
-.glyphicon {
-  position: relative;
-  top: 1px;
-  display: inline-block;
-  font-family: 'Glyphicons Halflings';
-  font-style: normal;
-  font-weight: normal;
-  line-height: 1;
-
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-.glyphicon-asterisk:before {
-  content: "\2a";
-}
-.glyphicon-plus:before {
-  content: "\2b";
-}
-.glyphicon-euro:before,
-.glyphicon-eur:before {
-  content: "\20ac";
-}
-.glyphicon-minus:before {
-  content: "\2212";
-}
-.glyphicon-cloud:before {
-  content: "\2601";
-}
-.glyphicon-envelope:before {
-  content: "\2709";
-}
-.glyphicon-pencil:before {
-  content: "\270f";
-}
-.glyphicon-glass:before {
-  content: "\e001";
-}
-.glyphicon-music:before {
-  content: "\e002";
-}
-.glyphicon-search:before {
-  content: "\e003";
-}
-.glyphicon-heart:before {
-  content: "\e005";
-}
-.glyphicon-star:before {
-  content: "\e006";
-}
-.glyphicon-star-empty:before {
-  content: "\e007";
-}
-.glyphicon-user:before {
-  content: "\e008";
-}
-.glyphicon-film:before {
-  content: "\e009";
-}
-.glyphicon-th-large:before {
-  content: "\e010";
-}
-.glyphicon-th:before {
-  content: "\e011";
-}
-.glyphicon-th-list:before {
-  content: "\e012";
-}
-.glyphicon-ok:before {
-  content: "\e013";
-}
-.glyphicon-remove:before {
-  content: "\e014";
-}
-.glyphicon-zoom-in:before {
-  content: "\e015";
-}
-.glyphicon-zoom-out:before {
-  content: "\e016";
-}
-.glyphicon-off:before {
-  content: "\e017";
-}
-.glyphicon-signal:before {
-  content: "\e018";
-}
-.glyphicon-cog:before {
-  content: "\e019";
-}
-.glyphicon-trash:before {
-  content: "\e020";
-}
-.glyphicon-home:before {
-  content: "\e021";
-}
-.glyphicon-file:before {
-  content: "\e022";
-}
-.glyphicon-time:before {
-  content: "\e023";
-}
-.glyphicon-road:before {
-  content: "\e024";
-}
-.glyphicon-download-alt:before {
-  content: "\e025";
-}
-.glyphicon-download:before {
-  content: "\e026";
-}
-.glyphicon-upload:before {
-  content: "\e027";
-}
-.glyphicon-inbox:before {
-  content: "\e028";
-}
-.glyphicon-play-circle:before {
-  content: "\e029";
-}
-.glyphicon-repeat:before {
-  content: "\e030";
-}
-.glyphicon-refresh:before {
-  content: "\e031";
-}
-.glyphicon-list-alt:before {
-  content: "\e032";
-}
-.glyphicon-lock:before {
-  content: "\e033";
-}
-.glyphicon-flag:before {
-  content: "\e034";
-}
-.glyphicon-headphones:before {
-  content: "\e035";
-}
-.glyphicon-volume-off:before {
-  content: "\e036";
-}
-.glyphicon-volume-down:before {
-  content: "\e037";
-}
-.glyphicon-volume-up:before {
-  content: "\e038";
-}
-.glyphicon-qrcode:before {
-  content: "\e039";
-}
-.glyphicon-barcode:before {
-  content: "\e040";
-}
-.glyphicon-tag:before {
-  content: "\e041";
-}
-.glyphicon-tags:before {
-  content: "\e042";
-}
-.glyphicon-book:before {
-  content: "\e043";
-}
-.glyphicon-bookmark:before {
-  content: "\e044";
-}
-.glyphicon-print:before {
-  content: "\e045";
-}
-.glyphicon-camera:before {
-  content: "\e046";
-}
-.glyphicon-font:before {
-  content: "\e047";
-}
-.glyphicon-bold:before {
-  content: "\e048";
-}
-.glyphicon-italic:before {
-  content: "\e049";
-}
-.glyphicon-text-height:before {
-  content: "\e050";
-}
-.glyphicon-text-width:before {
-  content: "\e051";
-}
-.glyphicon-align-left:before {
-  content: "\e052";
-}
-.glyphicon-align-center:before {
-  content: "\e053";
-}
-.glyphicon-align-right:before {
-  content: "\e054";
-}
-.glyphicon-align-justify:before {
-  content: "\e055";
-}
-.glyphicon-list:before {
-  content: "\e056";
-}
-.glyphicon-indent-left:before {
-  content: "\e057";
-}
-.glyphicon-indent-right:before {
-  content: "\e058";
-}
-.glyphicon-facetime-video:before {
-  content: "\e059";
-}
-.glyphicon-picture:before {
-  content: "\e060";
-}
-.glyphicon-map-marker:before {
-  content: "\e062";
-}
-.glyphicon-adjust:before {
-  content: "\e063";
-}
-.glyphicon-tint:before {
-  content: "\e064";
-}
-.glyphicon-edit:before {
-  content: "\e065";
-}
-.glyphicon-share:before {
-  content: "\e066";
-}
-.glyphicon-check:before {
-  content: "\e067";
-}
-.glyphicon-move:before {
-  content: "\e068";
-}
-.glyphicon-step-backward:before {
-  content: "\e069";
-}
-.glyphicon-fast-backward:before {
-  content: "\e070";
-}
-.glyphicon-backward:before {
-  content: "\e071";
-}
-.glyphicon-play:before {
-  content: "\e072";
-}
-.glyphicon-pause:before {
-  content: "\e073";
-}
-.glyphicon-stop:before {
-  content: "\e074";
-}
-.glyphicon-forward:before {
-  content: "\e075";
-}
-.glyphicon-fast-forward:before {
-  content: "\e076";
-}
-.glyphicon-step-forward:before {
-  content: "\e077";
-}
-.glyphicon-eject:before {
-  content: "\e078";
-}
-.glyphicon-chevron-left:before {
-  content: "\e079";
-}
-.glyphicon-chevron-right:before {
-  content: "\e080";
-}
-.glyphicon-plus-sign:before {
-  content: "\e081";
-}
-.glyphicon-minus-sign:before {
-  content: "\e082";
-}
-.glyphicon-remove-sign:before {
-  content: "\e083";
-}
-.glyphicon-ok-sign:before {
-  content: "\e084";
-}
-.glyphicon-question-sign:before {
-  content: "\e085";
-}
-.glyphicon-info-sign:before {
-  content: "\e086";
-}
-.glyphicon-screenshot:before {
-  content: "\e087";
-}
-.glyphicon-remove-circle:before {
-  content: "\e088";
-}
-.glyphicon-ok-circle:before {
-  content: "\e089";
-}
-.glyphicon-ban-circle:before {
-  content: "\e090";
-}
-.glyphicon-arrow-left:before {
-  content: "\e091";
-}
-.glyphicon-arrow-right:before {
-  content: "\e092";
-}
-.glyphicon-arrow-up:before {
-  content: "\e093";
-}
-.glyphicon-arrow-down:before {
-  content: "\e094";
-}
-.glyphicon-share-alt:before {
-  content: "\e095";
-}
-.glyphicon-resize-full:before {
-  content: "\e096";
-}
-.glyphicon-resize-small:before {
-  content: "\e097";
-}
-.glyphicon-exclamation-sign:before {
-  content: "\e101";
-}
-.glyphicon-gift:before {
-  content: "\e102";
-}
-.glyphicon-leaf:before {
-  content: "\e103";
-}
-.glyphicon-fire:before {
-  content: "\e104";
-}
-.glyphicon-eye-open:before {
-  content: "\e105";
-}
-.glyphicon-eye-close:before {
-  content: "\e106";
-}
-.glyphicon-warning-sign:before {
-  content: "\e107";
-}
-.glyphicon-plane:before {
-  content: "\e108";
-}
-.glyphicon-calendar:before {
-  content: "\e109";
-}
-.glyphicon-random:before {
-  content: "\e110";
-}
-.glyphicon-comment:before {
-  content: "\e111";
-}
-.glyphicon-magnet:before {
-  content: "\e112";
-}
-.glyphicon-chevron-up:before {
-  content: "\e113";
-}
-.glyphicon-chevron-down:before {
-  content: "\e114";
-}
-.glyphicon-retweet:before {
-  content: "\e115";
-}
-.glyphicon-shopping-cart:before {
-  content: "\e116";
-}
-.glyphicon-folder-close:before {
-  content: "\e117";
-}
-.glyphicon-folder-open:before {
-  content: "\e118";
-}
-.glyphicon-resize-vertical:before {
-  content: "\e119";
-}
-.glyphicon-resize-horizontal:before {
-  content: "\e120";
-}
-.glyphicon-hdd:before {
-  content: "\e121";
-}
-.glyphicon-bullhorn:before {
-  content: "\e122";
-}
-.glyphicon-bell:before {
-  content: "\e123";
-}
-.glyphicon-certificate:before {
-  content: "\e124";
-}
-.glyphicon-thumbs-up:before {
-  content: "\e125";
-}
-.glyphicon-thumbs-down:before {
-  content: "\e126";
-}
-.glyphicon-hand-right:before {
-  content: "\e127";
-}
-.glyphicon-hand-left:before {
-  content: "\e128";
-}
-.glyphicon-hand-up:before {
-  content: "\e129";
-}
-.glyphicon-hand-down:before {
-  content: "\e130";
-}
-.glyphicon-circle-arrow-right:before {
-  content: "\e131";
-}
-.glyphicon-circle-arrow-left:before {
-  content: "\e132";
-}
-.glyphicon-circle-arrow-up:before {
-  content: "\e133";
-}
-.glyphicon-circle-arrow-down:before {
-  content: "\e134";
-}
-.glyphicon-globe:before {
-  content: "\e135";
-}
-.glyphicon-wrench:before {
-  content: "\e136";
-}
-.glyphicon-tasks:before {
-  content: "\e137";
-}
-.glyphicon-filter:before {
-  content: "\e138";
-}
-.glyphicon-briefcase:before {
-  content: "\e139";
-}
-.glyphicon-fullscreen:before {
-  content: "\e140";
-}
-.glyphicon-dashboard:before {
-  content: "\e141";
-}
-.glyphicon-paperclip:before {
-  content: "\e142";
-}
-.glyphicon-heart-empty:before {
-  content: "\e143";
-}
-.glyphicon-link:before {
-  content: "\e144";
-}
-.glyphicon-phone:before {
-  content: "\e145";
-}
-.glyphicon-pushpin:before {
-  content: "\e146";
-}
-.glyphicon-usd:before {
-  content: "\e148";
-}
-.glyphicon-gbp:before {
-  content: "\e149";
-}
-.glyphicon-sort:before {
-  content: "\e150";
-}
-.glyphicon-sort-by-alphabet:before {
-  content: "\e151";
-}
-.glyphicon-sort-by-alphabet-alt:before {
-  content: "\e152";
-}
-.glyphicon-sort-by-order:before {
-  content: "\e153";
-}
-.glyphicon-sort-by-order-alt:before {
-  content: "\e154";
-}
-.glyphicon-sort-by-attributes:before {
-  content: "\e155";
-}
-.glyphicon-sort-by-attributes-alt:before {
-  content: "\e156";
-}
-.glyphicon-unchecked:before {
-  content: "\e157";
-}
-.glyphicon-expand:before {
-  content: "\e158";
-}
-.glyphicon-collapse-down:before {
-  content: "\e159";
-}
-.glyphicon-collapse-up:before {
-  content: "\e160";
-}
-.glyphicon-log-in:before {
-  content: "\e161";
-}
-.glyphicon-flash:before {
-  content: "\e162";
-}
-.glyphicon-log-out:before {
-  content: "\e163";
-}
-.glyphicon-new-window:before {
-  content: "\e164";
-}
-.glyphicon-record:before {
-  content: "\e165";
-}
-.glyphicon-save:before {
-  content: "\e166";
-}
-.glyphicon-open:before {
-  content: "\e167";
-}
-.glyphicon-saved:before {
-  content: "\e168";
-}
-.glyphicon-import:before {
-  content: "\e169";
-}
-.glyphicon-export:before {
-  content: "\e170";
-}
-.glyphicon-send:before {
-  content: "\e171";
-}
-.glyphicon-floppy-disk:before {
-  content: "\e172";
-}
-.glyphicon-floppy-saved:before {
-  content: "\e173";
-}
-.glyphicon-floppy-remove:before {
-  content: "\e174";
-}
-.glyphicon-floppy-save:before {
-  content: "\e175";
-}
-.glyphicon-floppy-open:before {
-  content: "\e176";
-}
-.glyphicon-credit-card:before {
-  content: "\e177";
-}
-.glyphicon-transfer:before {
-  content: "\e178";
-}
-.glyphicon-cutlery:before {
-  content: "\e179";
-}
-.glyphicon-header:before {
-  content: "\e180";
-}
-.glyphicon-compressed:before {
-  content: "\e181";
-}
-.glyphicon-earphone:before {
-  content: "\e182";
-}
-.glyphicon-phone-alt:before {
-  content: "\e183";
-}
-.glyphicon-tower:before {
-  content: "\e184";
-}
-.glyphicon-stats:before {
-  content: "\e185";
-}
-.glyphicon-sd-video:before {
-  content: "\e186";
-}
-.glyphicon-hd-video:before {
-  content: "\e187";
-}
-.glyphicon-subtitles:before {
-  content: "\e188";
-}
-.glyphicon-sound-stereo:before {
-  content: "\e189";
-}
-.glyphicon-sound-dolby:before {
-  content: "\e190";
-}
-.glyphicon-sound-5-1:before {
-  content: "\e191";
-}
-.glyphicon-sound-6-1:before {
-  content: "\e192";
-}
-.glyphicon-sound-7-1:before {
-  content: "\e193";
-}
-.glyphicon-copyright-mark:before {
-  content: "\e194";
-}
-.glyphicon-registration-mark:before {
-  content: "\e195";
-}
-.glyphicon-cloud-download:before {
-  content: "\e197";
-}
-.glyphicon-cloud-upload:before {
-  content: "\e198";
-}
-.glyphicon-tree-conifer:before {
-  content: "\e199";
-}
-.glyphicon-tree-deciduous:before {
-  content: "\e200";
-}
-.glyphicon-cd:before {
-  content: "\e201";
-}
-.glyphicon-save-file:before {
-  content: "\e202";
-}
-.glyphicon-open-file:before {
-  content: "\e203";
-}
-.glyphicon-level-up:before {
-  content: "\e204";
-}
-.glyphicon-copy:before {
-  content: "\e205";
-}
-.glyphicon-paste:before {
-  content: "\e206";
-}
-.glyphicon-alert:before {
-  content: "\e209";
-}
-.glyphicon-equalizer:before {
-  content: "\e210";
-}
-.glyphicon-king:before {
-  content: "\e211";
-}
-.glyphicon-queen:before {
-  content: "\e212";
-}
-.glyphicon-pawn:before {
-  content: "\e213";
-}
-.glyphicon-bishop:before {
-  content: "\e214";
-}
-.glyphicon-knight:before {
-  content: "\e215";
-}
-.glyphicon-baby-formula:before {
-  content: "\e216";
-}
-.glyphicon-tent:before {
-  content: "\26fa";
-}
-.glyphicon-blackboard:before {
-  content: "\e218";
-}
-.glyphicon-bed:before {
-  content: "\e219";
-}
-.glyphicon-apple:before {
-  content: "\f8ff";
-}
-.glyphicon-erase:before {
-  content: "\e221";
-}
-.glyphicon-hourglass:before {
-  content: "\231b";
-}
-.glyphicon-lamp:before {
-  content: "\e223";
-}
-.glyphicon-duplicate:before {
-  content: "\e224";
-}
-.glyphicon-piggy-bank:before {
-  content: "\e225";
-}
-.glyphicon-scissors:before {
-  content: "\e226";
-}
-.glyphicon-bitcoin:before {
-  content: "\e227";
-}
-.glyphicon-btc:before {
-  content: "\e227";
-}
-.glyphicon-xbt:before {
-  content: "\e227";
-}
-.glyphicon-yen:before {
-  content: "\00a5";
-}
-.glyphicon-jpy:before {
-  content: "\00a5";
-}
-.glyphicon-ruble:before {
-  content: "\20bd";
-}
-.glyphicon-rub:before {
-  content: "\20bd";
-}
-.glyphicon-scale:before {
-  content: "\e230";
-}
-.glyphicon-ice-lolly:before {
-  content: "\e231";
-}
-.glyphicon-ice-lolly-tasted:before {
-  content: "\e232";
-}
-.glyphicon-education:before {
-  content: "\e233";
-}
-.glyphicon-option-horizontal:before {
-  content: "\e234";
-}
-.glyphicon-option-vertical:before {
-  content: "\e235";
-}
-.glyphicon-menu-hamburger:before {
-  content: "\e236";
-}
-.glyphicon-modal-window:before {
-  content: "\e237";
-}
-.glyphicon-oil:before {
-  content: "\e238";
-}
-.glyphicon-grain:before {
-  content: "\e239";
-}
-.glyphicon-sunglasses:before {
-  content: "\e240";
-}
-.glyphicon-text-size:before {
-  content: "\e241";
-}
-.glyphicon-text-color:before {
-  content: "\e242";
-}
-.glyphicon-text-background:before {
-  content: "\e243";
-}
-.glyphicon-object-align-top:before {
-  content: "\e244";
-}
-.glyphicon-object-align-bottom:before {
-  content: "\e245";
-}
-.glyphicon-object-align-horizontal:before {
-  content: "\e246";
-}
-.glyphicon-object-align-left:before {
-  content: "\e247";
-}
-.glyphicon-object-align-vertical:before {
-  content: "\e248";
-}
-.glyphicon-object-align-right:before {
-  content: "\e249";
-}
-.glyphicon-triangle-right:before {
-  content: "\e250";
-}
-.glyphicon-triangle-left:before {
-  content: "\e251";
-}
-.glyphicon-triangle-bottom:before {
-  content: "\e252";
-}
-.glyphicon-triangle-top:before {
-  content: "\e253";
-}
-.glyphicon-console:before {
-  content: "\e254";
-}
-.glyphicon-superscript:before {
-  content: "\e255";
-}
-.glyphicon-subscript:before {
-  content: "\e256";
-}
-.glyphicon-menu-left:before {
-  content: "\e257";
-}
-.glyphicon-menu-right:before {
-  content: "\e258";
-}
-.glyphicon-menu-down:before {
-  content: "\e259";
-}
-.glyphicon-menu-up:before {
-  content: "\e260";
-}
-* {
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-}
-*:before,
-*:after {
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-}
-html {
-  font-size: 10px;
-
-  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-}
-body {
-  font-family: Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 14px;
-  line-height: 1.42857143;
-  color: #333;
-  background-color: #fff;
-}
-input,
-button,
-select,
-textarea {
-  font-family: inherit;
-  font-size: inherit;
-  line-height: inherit;
-}
-a {
-  color: #428bca;
-  text-decoration: none;
-}
-a:hover,
-a:focus {
-  color: #2a6496;
-  text-decoration: underline;
-}
-a:focus {
-  outline: thin dotted;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-figure {
-  margin: 0;
-}
-img {
-  vertical-align: middle;
-}
-.img-responsive,
-.thumbnail > img,
-.thumbnail a > img,
-.carousel-inner > .item > img,
-.carousel-inner > .item > a > img {
-  display: block;
-  max-width: 100%;
-  height: auto;
-}
-.img-rounded {
-  border-radius: 6px;
-}
-.img-thumbnail {
-  display: inline-block;
-  max-width: 100%;
-  height: auto;
-  padding: 4px;
-  line-height: 1.42857143;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  -webkit-transition: all .2s ease-in-out;
-       -o-transition: all .2s ease-in-out;
-          transition: all .2s ease-in-out;
-}
-.img-circle {
-  border-radius: 50%;
-}
-hr {
-  margin-top: 20px;
-  margin-bottom: 20px;
-  border: 0;
-  border-top: 1px solid #eee;
-}
-.sr-only {
-  position: absolute;
-  width: 1px;
-  height: 1px;
-  padding: 0;
-  margin: -1px;
-  overflow: hidden;
-  clip: rect(0, 0, 0, 0);
-  border: 0;
-}
-.sr-only-focusable:active,
-.sr-only-focusable:focus {
-  position: static;
-  width: auto;
-  height: auto;
-  margin: 0;
-  overflow: visible;
-  clip: auto;
-}
-[role="button"] {
-  cursor: pointer;
-}
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
-.h1,
-.h2,
-.h3,
-.h4,
-.h5,
-.h6 {
-  font-family: inherit;
-  font-weight: 500;
-  line-height: 1.1;
-  color: inherit;
-}
-h1 small,
-h2 small,
-h3 small,
-h4 small,
-h5 small,
-h6 small,
-.h1 small,
-.h2 small,
-.h3 small,
-.h4 small,
-.h5 small,
-.h6 small,
-h1 .small,
-h2 .small,
-h3 .small,
-h4 .small,
-h5 .small,
-h6 .small,
-.h1 .small,
-.h2 .small,
-.h3 .small,
-.h4 .small,
-.h5 .small,
-.h6 .small {
-  font-weight: normal;
-  line-height: 1;
-  color: #777;
-}
-h1,
-.h1,
-h2,
-.h2,
-h3,
-.h3 {
-  margin-top: 20px;
-  margin-bottom: 10px;
-}
-h1 small,
-.h1 small,
-h2 small,
-.h2 small,
-h3 small,
-.h3 small,
-h1 .small,
-.h1 .small,
-h2 .small,
-.h2 .small,
-h3 .small,
-.h3 .small {
-  font-size: 65%;
-}
-h4,
-.h4,
-h5,
-.h5,
-h6,
-.h6 {
-  margin-top: 10px;
-  margin-bottom: 10px;
-}
-h4 small,
-.h4 small,
-h5 small,
-.h5 small,
-h6 small,
-.h6 small,
-h4 .small,
-.h4 .small,
-h5 .small,
-.h5 .small,
-h6 .small,
-.h6 .small {
-  font-size: 75%;
-}
-h1,
-.h1 {
-  font-size: 36px;
-}
-h2,
-.h2 {
-  font-size: 30px;
-}
-h3,
-.h3 {
-  font-size: 24px;
-}
-h4,
-.h4 {
-  font-size: 18px;
-}
-h5,
-.h5 {
-  font-size: 14px;
-}
-h6,
-.h6 {
-  font-size: 12px;
-}
-p {
-  margin: 0 0 10px;
-}
-.lead {
-  margin-bottom: 20px;
-  font-size: 16px;
-  font-weight: 300;
-  line-height: 1.4;
-}
-@media (min-width: 768px) {
-  .lead {
-    font-size: 21px;
-  }
-}
-small,
-.small {
-  font-size: 85%;
-}
-mark,
-.mark {
-  padding: .2em;
-  background-color: #f8e4c7;
-}
-.text-left {
-  text-align: left;
-}
-.text-right {
-  text-align: right;
-}
-.text-center {
-  text-align: center;
-}
-.text-justify {
-  text-align: justify;
-}
-.text-nowrap {
-  white-space: nowrap;
-}
-.text-lowercase {
-  text-transform: lowercase;
-}
-.text-uppercase {
-  text-transform: uppercase;
-}
-.text-capitalize {
-  text-transform: capitalize;
-}
-.text-muted {
-  color: #777;
-}
-.text-primary {
-  color: #428bca;
-}
-a.text-primary:hover,
-a.text-primary:focus {
-  color: #3071a9;
-}
-.text-success {
-  color: #3f7815;
-}
-a.text-success:hover,
-a.text-success:focus {
-  color: #284d0e;
-}
-.text-info {
-  color: #603e7a;
-}
-a.text-info:hover,
-a.text-info:focus {
-  color: #452d58;
-}
-.text-warning {
-  color: #7e500f;
-}
-a.text-warning:hover,
-a.text-warning:focus {
-  color: #51330a;
-}
-.text-danger {
-  color: #78153f;
-}
-a.text-danger:hover,
-a.text-danger:focus {
-  color: #4d0e28;
-}
-.bg-primary {
-  color: #fff;
-  background-color: #428bca;
-}
-a.bg-primary:hover,
-a.bg-primary:focus {
-  background-color: #3071a9;
-}
-.bg-success {
-  background-color: #dcf6ca;
-}
-a.bg-success:hover,
-a.bg-success:focus {
-  background-color: #c0ee9e;
-}
-.bg-info {
-  background-color: #f6f2f8;
-}
-a.bg-info:hover,
-a.bg-info:focus {
-  background-color: #ddd0e7;
-}
-.bg-warning {
-  background-color: #f8e4c7;
-}
-a.bg-warning:hover,
-a.bg-warning:focus {
-  background-color: #f3ce9a;
-}
-.bg-danger {
-  background-color: #f6cadc;
-}
-a.bg-danger:hover,
-a.bg-danger:focus {
-  background-color: #ee9ec0;
-}
-.page-header {
-  padding-bottom: 9px;
-  margin: 40px 0 20px;
-  border-bottom: 1px solid #eee;
-}
-ul,
-ol {
-  margin-top: 0;
-  margin-bottom: 10px;
-}
-ul ul,
-ol ul,
-ul ol,
-ol ol {
-  margin-bottom: 0;
-}
-.list-unstyled {
-  padding-left: 0;
-  list-style: none;
-}
-.list-inline {
-  padding-left: 0;
-  margin-left: -5px;
-  list-style: none;
-}
-.list-inline > li {
-  display: inline-block;
-  padding-right: 5px;
-  padding-left: 5px;
-}
-dl {
-  margin-top: 0;
-  margin-bottom: 20px;
-}
-dt,
-dd {
-  line-height: 1.42857143;
-}
-dt {
-  font-weight: bold;
-}
-dd {
-  margin-left: 0;
-}
-@media (min-width: 768px) {
-  .dl-horizontal dt {
-    float: left;
-    width: 160px;
-    overflow: hidden;
-    clear: left;
-    text-align: right;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-  }
-  .dl-horizontal dd {
-    margin-left: 180px;
-  }
-}
-abbr[title],
-abbr[data-original-title] {
-  cursor: help;
-  border-bottom: 1px dotted #777;
-}
-.initialism {
-  font-size: 90%;
-  text-transform: uppercase;
-}
-blockquote {
-  padding: 10px 20px;
-  margin: 0 0 20px;
-  font-size: 17.5px;
-  border-left: 5px solid #eee;
-}
-blockquote p:last-child,
-blockquote ul:last-child,
-blockquote ol:last-child {
-  margin-bottom: 0;
-}
-blockquote footer,
-blockquote small,
-blockquote .small {
-  display: block;
-  font-size: 80%;
-  line-height: 1.42857143;
-  color: #777;
-}
-blockquote footer:before,
-blockquote small:before,
-blockquote .small:before {
-  content: '\2014 \00A0';
-}
-.blockquote-reverse,
-blockquote.pull-right {
-  padding-right: 15px;
-  padding-left: 0;
-  text-align: right;
-  border-right: 5px solid #eee;
-  border-left: 0;
-}
-.blockquote-reverse footer:before,
-blockquote.pull-right footer:before,
-.blockquote-reverse small:before,
-blockquote.pull-right small:before,
-.blockquote-reverse .small:before,
-blockquote.pull-right .small:before {
-  content: '';
-}
-.blockquote-reverse footer:after,
-blockquote.pull-right footer:after,
-.blockquote-reverse small:after,
-blockquote.pull-right small:after,
-.blockquote-reverse .small:after,
-blockquote.pull-right .small:after {
-  content: '\00A0 \2014';
-}
-address {
-  margin-bottom: 20px;
-  font-style: normal;
-  line-height: 1.42857143;
-}
-code,
-kbd,
-pre,
-samp {
-  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
-}
-code {
-  padding: 2px 4px;
-  font-size: 90%;
-  color: #c7254e;
-  background-color: #f9f2f4;
-  border-radius: 4px;
-}
-kbd {
-  padding: 2px 4px;
-  font-size: 90%;
-  color: #fff;
-  background-color: #333;
-  border-radius: 3px;
-  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
-          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
-}
-kbd kbd {
-  padding: 0;
-  font-size: 100%;
-  font-weight: bold;
-  -webkit-box-shadow: none;
-          box-shadow: none;
-}
-pre {
-  display: block;
-  padding: 9.5px;
-  margin: 0 0 10px;
-  font-size: 13px;
-  line-height: 1.42857143;
-  color: #333;
-  word-break: break-all;
-  word-wrap: break-word;
-  background-color: #f5f5f5;
-  border: 1px solid #ccc;
-  border-radius: 4px;
-}
-pre code {
-  padding: 0;
-  font-size: inherit;
-  color: inherit;
-  white-space: pre-wrap;
-  background-color: transparent;
-  border-radius: 0;
-}
-.pre-scrollable {
-  max-height: 340px;
-  overflow-y: scroll;
-}
-.container {
-  padding-right: 15px;
-  padding-left: 15px;
-  margin-right: auto;
-  margin-left: auto;
-}
-@media (min-width: 768px) {
-  .container {
-    width: 750px;
-  }
-}
-@media (min-width: 992px) {
-  .container {
-    width: 970px;
-  }
-}
-@media (min-width: 1200px) {
-  .container {
-    width: 1170px;
-  }
-}
-.container-fluid {
-  padding-right: 15px;
-  padding-left: 15px;
-  margin-right: auto;
-  margin-left: auto;
-}
-.row {
-  margin-right: -15px;
-  margin-left: -15px;
-}
-.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
-  position: relative;
-  min-height: 1px;
-  padding-right: 15px;
-  padding-left: 15px;
-}
-.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
-  float: left;
-}
-.col-xs-12 {
-  width: 100%;
-}
-.col-xs-11 {
-  width: 91.66666667%;
-}
-.col-xs-10 {
-  width: 83.33333333%;
-}
-.col-xs-9 {
-  width: 75%;
-}
-.col-xs-8 {
-  width: 66.66666667%;
-}
-.col-xs-7 {
-  width: 58.33333333%;
-}
-.col-xs-6 {
-  width: 50%;
-}
-.col-xs-5 {
-  width: 41.66666667%;
-}
-.col-xs-4 {
-  width: 33.33333333%;
-}
-.col-xs-3 {
-  width: 25%;
-}
-.col-xs-2 {
-  width: 16.66666667%;
-}
-.col-xs-1 {
-  width: 8.33333333%;
-}
-.col-xs-pull-12 {
-  right: 100%;
-}
-.col-xs-pull-11 {
-  right: 91.66666667%;
-}
-.col-xs-pull-10 {
-  right: 83.33333333%;
-}
-.col-xs-pull-9 {
-  right: 75%;
-}
-.col-xs-pull-8 {
-  right: 66.66666667%;
-}
-.col-xs-pull-7 {
-  right: 58.33333333%;
-}
-.col-xs-pull-6 {
-  right: 50%;
-}
-.col-xs-pull-5 {
-  right: 41.66666667%;
-}
-.col-xs-pull-4 {
-  right: 33.33333333%;
-}
-.col-xs-pull-3 {
-  right: 25%;
-}
-.col-xs-pull-2 {
-  right: 16.66666667%;
-}
-.col-xs-pull-1 {
-  right: 8.33333333%;
-}
-.col-xs-pull-0 {
-  right: auto;
-}
-.col-xs-push-12 {
-  left: 100%;
-}
-.col-xs-push-11 {
-  left: 91.66666667%;
-}
-.col-xs-push-10 {
-  left: 83.33333333%;
-}
-.col-xs-push-9 {
-  left: 75%;
-}
-.col-xs-push-8 {
-  left: 66.66666667%;
-}
-.col-xs-push-7 {
-  left: 58.33333333%;
-}
-.col-xs-push-6 {
-  left: 50%;
-}
-.col-xs-push-5 {
-  left: 41.66666667%;
-}
-.col-xs-push-4 {
-  left: 33.33333333%;
-}
-.col-xs-push-3 {
-  left: 25%;
-}
-.col-xs-push-2 {
-  left: 16.66666667%;
-}
-.col-xs-push-1 {
-  left: 8.33333333%;
-}
-.col-xs-push-0 {
-  left: auto;
-}
-.col-xs-offset-12 {
-  margin-left: 100%;
-}
-.col-xs-offset-11 {
-  margin-left: 91.66666667%;
-}
-.col-xs-offset-10 {
-  margin-left: 83.33333333%;
-}
-.col-xs-offset-9 {
-  margin-left: 75%;
-}
-.col-xs-offset-8 {
-  margin-left: 66.66666667%;
-}
-.col-xs-offset-7 {
-  margin-left: 58.33333333%;
-}
-.col-xs-offset-6 {
-  margin-left: 50%;
-}
-.col-xs-offset-5 {
-  margin-left: 41.66666667%;
-}
-.col-xs-offset-4 {
-  margin-left: 33.33333333%;
-}
-.col-xs-offset-3 {
-  margin-left: 25%;
-}
-.col-xs-offset-2 {
-  margin-left: 16.66666667%;
-}
-.col-xs-offset-1 {
-  margin-left: 8.33333333%;
-}
-.col-xs-offset-0 {
-  margin-left: 0;
-}
-@media (min-width: 768px) {
-  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
-    float: left;
-  }
-  .col-sm-12 {
-    width: 100%;
-  }
-  .col-sm-11 {
-    width: 91.66666667%;
-  }
-  .col-sm-10 {
-    width: 83.33333333%;
-  }
-  .col-sm-9 {
-    width: 75%;
-  }
-  .col-sm-8 {
-    width: 66.66666667%;
-  }
-  .col-sm-7 {
-    width: 58.33333333%;
-  }
-  .col-sm-6 {
-    width: 50%;
-  }
-  .col-sm-5 {
-    width: 41.66666667%;
-  }
-  .col-sm-4 {
-    width: 33.33333333%;
-  }
-  .col-sm-3 {
-    width: 25%;
-  }
-  .col-sm-2 {
-    width: 16.66666667%;
-  }
-  .col-sm-1 {
-    width: 8.33333333%;
-  }
-  .col-sm-pull-12 {
-    right: 100%;
-  }
-  .col-sm-pull-11 {
-    right: 91.66666667%;
-  }
-  .col-sm-pull-10 {
-    right: 83.33333333%;
-  }
-  .col-sm-pull-9 {
-    right: 75%;
-  }
-  .col-sm-pull-8 {
-    right: 66.66666667%;
-  }
-  .col-sm-pull-7 {
-    right: 58.33333333%;
-  }
-  .col-sm-pull-6 {
-    right: 50%;
-  }
-  .col-sm-pull-5 {
-    right: 41.66666667%;
-  }
-  .col-sm-pull-4 {
-    right: 33.33333333%;
-  }
-  .col-sm-pull-3 {
-    right: 25%;
-  }
-  .col-sm-pull-2 {
-    right: 16.66666667%;
-  }
-  .col-sm-pull-1 {
-    right: 8.33333333%;
-  }
-  .col-sm-pull-0 {
-    right: auto;
-  }
-  .col-sm-push-12 {
-    left: 100%;
-  }
-  .col-sm-push-11 {
-    left: 91.66666667%;
-  }
-  .col-sm-push-10 {
-    left: 83.33333333%;
-  }
-  .col-sm-push-9 {
-    left: 75%;
-  }
-  .col-sm-push-8 {
-    left: 66.66666667%;
-  }
-  .col-sm-push-7 {
-    left: 58.33333333%;
-  }
-  .col-sm-push-6 {
-    left: 50%;
-  }
-  .col-sm-push-5 {
-    left: 41.66666667%;
-  }
-  .col-sm-push-4 {
-    left: 33.33333333%;
-  }
-  .col-sm-push-3 {
-    left: 25%;
-  }
-  .col-sm-push-2 {
-    left: 16.66666667%;
-  }
-  .col-sm-push-1 {
-    left: 8.33333333%;
-  }
-  .col-sm-push-0 {
-    left: auto;
-  }
-  .col-sm-offset-12 {
-    margin-left: 100%;
-  }
-  .col-sm-offset-11 {
-    margin-left: 91.66666667%;
-  }
-  .col-sm-offset-10 {
-    margin-left: 83.33333333%;
-  }
-  .col-sm-offset-9 {
-    margin-left: 75%;
-  }
-  .col-sm-offset-8 {
-    margin-left: 66.66666667%;
-  }
-  .col-sm-offset-7 {
-    margin-left: 58.33333333%;
-  }
-  .col-sm-offset-6 {
-    margin-left: 50%;
-  }
-  .col-sm-offset-5 {
-    margin-left: 41.66666667%;
-  }
-  .col-sm-offset-4 {
-    margin-left: 33.33333333%;
-  }
-  .col-sm-offset-3 {
-    margin-left: 25%;
-  }
-  .col-sm-offset-2 {
-    margin-left: 16.66666667%;
-  }
-  .col-sm-offset-1 {
-    margin-left: 8.33333333%;
-  }
-  .col-sm-offset-0 {
-    margin-left: 0;
-  }
-}
-@media (min-width: 992px) {
-  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
-    float: left;
-  }
-  .col-md-12 {
-    width: 100%;
-  }
-  .col-md-11 {
-    width: 91.66666667%;
-  }
-  .col-md-10 {
-    width: 83.33333333%;
-  }
-  .col-md-9 {
-    width: 75%;
-  }
-  .col-md-8 {
-    width: 66.66666667%;
-  }
-  .col-md-7 {
-    width: 58.33333333%;
-  }
-  .col-md-6 {
-    width: 50%;
-  }
-  .col-md-5 {
-    width: 41.66666667%;
-  }
-  .col-md-4 {
-    width: 33.33333333%;
-  }
-  .col-md-3 {
-    width: 25%;
-  }
-  .col-md-2 {
-    width: 16.66666667%;
-  }
-  .col-md-1 {
-    width: 8.33333333%;
-  }
-  .col-md-pull-12 {
-    right: 100%;
-  }
-  .col-md-pull-11 {
-    right: 91.66666667%;
-  }
-  .col-md-pull-10 {
-    right: 83.33333333%;
-  }
-  .col-md-pull-9 {
-    right: 75%;
-  }
-  .col-md-pull-8 {
-    right: 66.66666667%;
-  }
-  .col-md-pull-7 {
-    right: 58.33333333%;
-  }
-  .col-md-pull-6 {
-    right: 50%;
-  }
-  .col-md-pull-5 {
-    right: 41.66666667%;
-  }
-  .col-md-pull-4 {
-    right: 33.33333333%;
-  }
-  .col-md-pull-3 {
-    right: 25%;
-  }
-  .col-md-pull-2 {
-    right: 16.66666667%;
-  }
-  .col-md-pull-1 {
-    right: 8.33333333%;
-  }
-  .col-md-pull-0 {
-    right: auto;
-  }
-  .col-md-push-12 {
-    left: 100%;
-  }
-  .col-md-push-11 {
-    left: 91.66666667%;
-  }
-  .col-md-push-10 {
-    left: 83.33333333%;
-  }
-  .col-md-push-9 {
-    left: 75%;
-  }
-  .col-md-push-8 {
-    left: 66.66666667%;
-  }
-  .col-md-push-7 {
-    left: 58.33333333%;
-  }
-  .col-md-push-6 {
-    left: 50%;
-  }
-  .col-md-push-5 {
-    left: 41.66666667%;
-  }
-  .col-md-push-4 {
-    left: 33.33333333%;
-  }
-  .col-md-push-3 {
-    left: 25%;
-  }
-  .col-md-push-2 {
-    left: 16.66666667%;
-  }
-  .col-md-push-1 {
-    left: 8.33333333%;
-  }
-  .col-md-push-0 {
-    left: auto;
-  }
-  .col-md-offset-12 {
-    margin-left: 100%;
-  }
-  .col-md-offset-11 {
-    margin-left: 91.66666667%;
-  }
-  .col-md-offset-10 {
-    margin-left: 83.33333333%;
-  }
-  .col-md-offset-9 {
-    margin-left: 75%;
-  }
-  .col-md-offset-8 {
-    margin-left: 66.66666667%;
-  }
-  .col-md-offset-7 {
-    margin-left: 58.33333333%;
-  }
-  .col-md-offset-6 {
-    margin-left: 50%;
-  }
-  .col-md-offset-5 {
-    margin-left: 41.66666667%;
-  }
-  .col-md-offset-4 {
-    margin-left: 33.33333333%;
-  }
-  .col-md-offset-3 {
-    margin-left: 25%;
-  }
-  .col-md-offset-2 {
-    margin-left: 16.66666667%;
-  }
-  .col-md-offset-1 {
-    margin-left: 8.33333333%;
-  }
-  .col-md-offset-0 {
-    margin-left: 0;
-  }
-}
-@media (min-width: 1200px) {
-  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
-    float: left;
-  }
-  .col-lg-12 {
-    width: 100%;
-  }
-  .col-lg-11 {
-    width: 91.66666667%;
-  }
-  .col-lg-10 {
-    width: 83.33333333%;
-  }
-  .col-lg-9 {
-    width: 75%;
-  }
-  .col-lg-8 {
-    width: 66.66666667%;
-  }
-  .col-lg-7 {
-    width: 58.33333333%;
-  }
-  .col-lg-6 {
-    width: 50%;
-  }
-  .col-lg-5 {
-    width: 41.66666667%;
-  }
-  .col-lg-4 {
-    width: 33.33333333%;
-  }
-  .col-lg-3 {
-    width: 25%;
-  }
-  .col-lg-2 {
-    width: 16.66666667%;
-  }
-  .col-lg-1 {
-    width: 8.33333333%;
-  }
-  .col-lg-pull-12 {
-    right: 100%;
-  }
-  .col-lg-pull-11 {
-    right: 91.66666667%;
-  }
-  .col-lg-pull-10 {
-    right: 83.33333333%;
-  }
-  .col-lg-pull-9 {
-    right: 75%;
-  }
-  .col-lg-pull-8 {
-    right: 66.66666667%;
-  }
-  .col-lg-pull-7 {
-    right: 58.33333333%;
-  }
-  .col-lg-pull-6 {
-    right: 50%;
-  }
-  .col-lg-pull-5 {
-    right: 41.66666667%;
-  }
-  .col-lg-pull-4 {
-    right: 33.33333333%;
-  }
-  .col-lg-pull-3 {
-    right: 25%;
-  }
-  .col-lg-pull-2 {
-    right: 16.66666667%;
-  }
-  .col-lg-pull-1 {
-    right: 8.33333333%;
-  }
-  .col-lg-pull-0 {
-    right: auto;
-  }
-  .col-lg-push-12 {
-    left: 100%;
-  }
-  .col-lg-push-11 {
-    left: 91.66666667%;
-  }
-  .col-lg-push-10 {
-    left: 83.33333333%;
-  }
-  .col-lg-push-9 {
-    left: 75%;
-  }
-  .col-lg-push-8 {
-    left: 66.66666667%;
-  }
-  .col-lg-push-7 {
-    left: 58.33333333%;
-  }
-  .col-lg-push-6 {
-    left: 50%;
-  }
-  .col-lg-push-5 {
-    left: 41.66666667%;
-  }
-  .col-lg-push-4 {
-    left: 33.33333333%;
-  }
-  .col-lg-push-3 {
-    left: 25%;
-  }
-  .col-lg-push-2 {
-    left: 16.66666667%;
-  }
-  .col-lg-push-1 {
-    left: 8.33333333%;
-  }
-  .col-lg-push-0 {
-    left: auto;
-  }
-  .col-lg-offset-12 {
-    margin-left: 100%;
-  }
-  .col-lg-offset-11 {
-    margin-left: 91.66666667%;
-  }
-  .col-lg-offset-10 {
-    margin-left: 83.33333333%;
-  }
-  .col-lg-offset-9 {
-    margin-left: 75%;
-  }
-  .col-lg-offset-8 {
-    margin-left: 66.66666667%;
-  }
-  .col-lg-offset-7 {
-    margin-left: 58.33333333%;
-  }
-  .col-lg-offset-6 {
-    margin-left: 50%;
-  }
-  .col-lg-offset-5 {
-    margin-left: 41.66666667%;
-  }
-  .col-lg-offset-4 {
-    margin-left: 33.33333333%;
-  }
-  .col-lg-offset-3 {
-    margin-left: 25%;
-  }
-  .col-lg-offset-2 {
-    margin-left: 16.66666667%;
-  }
-  .col-lg-offset-1 {
-    margin-left: 8.33333333%;
-  }
-  .col-lg-offset-0 {
-    margin-left: 0;
-  }
-}
-table {
-  background-color: transparent;
-}
-caption {
-  padding-top: 8px;
-  padding-bottom: 8px;
-  color: #777;
-  text-align: left;
-}
-th {
-  text-align: left;
-}
-.table {
-  width: 100%;
-  max-width: 100%;
-  margin-bottom: 20px;
-}
-.table > thead > tr > th,
-.table > tbody > tr > th,
-.table > tfoot > tr > th,
-.table > thead > tr > td,
-.table > tbody > tr > td,
-.table > tfoot > tr > td {
-  padding: 8px;
-  line-height: 1.42857143;
-  vertical-align: top;
-  border-top: 1px solid #ddd;
-}
-.table > thead > tr > th {
-  vertical-align: bottom;
-  border-bottom: 2px solid #ddd;
-}
-.table > caption + thead > tr:first-child > th,
-.table > colgroup + thead > tr:first-child > th,
-.table > thead:first-child > tr:first-child > th,
-.table > caption + thead > tr:first-child > td,
-.table > colgroup + thead > tr:first-child > td,
-.table > thead:first-child > tr:first-child > td {
-  border-top: 0;
-}
-.table > tbody + tbody {
-  border-top: 2px solid #ddd;
-}
-.table .table {
-  background-color: #fff;
-}
-.table-condensed > thead > tr > th,
-.table-condensed > tbody > tr > th,
-.table-condensed > tfoot > tr > th,
-.table-condensed > thead > tr > td,
-.table-condensed > tbody > tr > td,
-.table-condensed > tfoot > tr > td {
-  padding: 5px;
-}
-.table-bordered {
-  border: 1px solid #ddd;
-}
-.table-bordered > thead > tr > th,
-.table-bordered > tbody > tr > th,
-.table-bordered > tfoot > tr > th,
-.table-bordered > thead > tr > td,
-.table-bordered > tbody > tr > td,
-.table-bordered > tfoot > tr > td {
-  border: 1px solid #ddd;
-}
-.table-bordered > thead > tr > th,
-.table-bordered > thead > tr > td {
-  border-bottom-width: 2px;
-}
-.table-striped > tbody > tr:nth-of-type(odd) {
-  background-color: #f9f9f9;
-}
-.table-hover > tbody > tr:hover {
-  background-color: #f5f5f5;
-}
-table col[class*="col-"] {
-  position: static;
-  display: table-column;
-  float: none;
-}
-table td[class*="col-"],
-table th[class*="col-"] {
-  position: static;
-  display: table-cell;
-  float: none;
-}
-.table > thead > tr > td.active,
-.table > tbody > tr > td.active,
-.table > tfoot > tr > td.active,
-.table > thead > tr > th.active,
-.table > tbody > tr > th.active,
-.table > tfoot > tr > th.active,
-.table > thead > tr.active > td,
-.table > tbody > tr.active > td,
-.table > tfoot > tr.active > td,
-.table > thead > tr.active > th,
-.table > tbody > tr.active > th,
-.table > tfoot > tr.active > th {
-  background-color: #f5f5f5;
-}
-.table-hover > tbody > tr > td.active:hover,
-.table-hover > tbody > tr > th.active:hover,
-.table-hover > tbody > tr.active:hover > td,
-.table-hover > tbody > tr:hover > .active,
-.table-hover > tbody > tr.active:hover > th {
-  background-color: #e8e8e8;
-}
-.table > thead > tr > td.success,
-.table > tbody > tr > td.success,
-.table > tfoot > tr > td.success,
-.table > thead > tr > th.success,
-.table > tbody > tr > th.success,
-.table > tfoot > tr > th.success,
-.table > thead > tr.success > td,
-.table > tbody > tr.success > td,
-.table > tfoot > tr.success > td,
-.table > thead > tr.success > th,
-.table > tbody > tr.success > th,
-.table > tfoot > tr.success > th {
-  background-color: #dcf6ca;
-}
-.table-hover > tbody > tr > td.success:hover,
-.table-hover > tbody > tr > th.success:hover,
-.table-hover > tbody > tr.success:hover > td,
-.table-hover > tbody > tr:hover > .success,
-.table-hover > tbody > tr.success:hover > th {
-  background-color: #cef2b4;
-}
-.table > thead > tr > td.info,
-.table > tbody > tr > td.info,
-.table > tfoot > tr > td.info,
-.table > thead > tr > th.info,
-.table > tbody > tr > th.info,
-.table > tfoot > tr > th.info,
-.table > thead > tr.info > td,
-.table > tbody > tr.info > td,
-.table > tfoot > tr.info > td,
-.table > thead > tr.info > th,
-.table > tbody > tr.info > th,
-.table > tfoot > tr.info > th {
-  background-color: #f6f2f8;
-}
-.table-hover > tbody > tr > td.info:hover,
-.table-hover > tbody > tr > th.info:hover,
-.table-hover > tbody > tr.info:hover > td,
-.table-hover > tbody > tr:hover > .info,
-.table-hover > tbody > tr.info:hover > th {
-  background-color: #e9e1f0;
-}
-.table > thead > tr > td.warning,
-.table > tbody > tr > td.warning,
-.table > tfoot > tr > td.warning,
-.table > thead > tr > th.warning,
-.table > tbody > tr > th.warning,
-.table > tfoot > tr > th.warning,
-.table > thead > tr.warning > td,
-.table > tbody > tr.warning > td,
-.table > tfoot > tr.warning > td,
-.table > thead > tr.warning > th,
-.table > tbody > tr.warning > th,
-.table > tfoot > tr.warning > th {
-  background-color: #f8e4c7;
-}
-.table-hover > tbody > tr > td.warning:hover,
-.table-hover > tbody > tr > th.warning:hover,
-.table-hover > tbody > tr.warning:hover > td,
-.table-hover > tbody > tr:hover > .warning,
-.table-hover > tbody > tr.warning:hover > th {
-  background-color: #f6d9b0;
-}
-.table > thead > tr > td.danger,
-.table > tbody > tr > td.danger,
-.table > tfoot > tr > td.danger,
-.table > thead > tr > th.danger,
-.table > tbody > tr > th.danger,
-.table > tfoot > tr > th.danger,
-.table > thead > tr.danger > td,
-.table > tbody > tr.danger > td,
-.table > tfoot > tr.danger > td,
-.table > thead > tr.danger > th,
-.table > tbody > tr.danger > th,
-.table > tfoot > tr.danger > th {
-  background-color: #f6cadc;
-}
-.table-hover > tbody > tr > td.danger:hover,
-.table-hover > tbody > tr > th.danger:hover,
-.table-hover > tbody > tr.danger:hover > td,
-.table-hover > tbody > tr:hover > .danger,
-.table-hover > tbody > tr.danger:hover > th {
-  background-color: #f2b4ce;
-}
-.table-responsive {
-  min-height: .01%;
-  overflow-x: auto;
-}
-@media screen and (max-width: 767px) {
-  .table-responsive {
-    width: 100%;
-    margin-bottom: 15px;
-    overflow-y: hidden;
-    -ms-overflow-style: -ms-autohiding-scrollbar;
-    border: 1px solid #ddd;
-  }
-  .table-responsive > .table {
-    margin-bottom: 0;
-  }
-  .table-responsive > .table > thead > tr > th,
-  .table-responsive > .table > tbody > tr > th,
-  .table-responsive > .table > tfoot > tr > th,
-  .table-responsive > .table > thead > tr > td,
-  .table-responsive > .table > tbody > tr > td,
-  .table-responsive > .table > tfoot > tr > td {
-    white-space: nowrap;
-  }
-  .table-responsive > .table-bordered {
-    border: 0;
-  }
-  .table-responsive > .table-bordered > thead > tr > th:first-child,
-  .table-responsive > .table-bordered > tbody > tr > th:first-child,
-  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
-  .table-responsive > .table-bordered > thead > tr > td:first-child,
-  .table-responsive > .table-bordered > tbody > tr > td:first-child,
-  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
-    border-left: 0;
-  }
-  .table-responsive > .table-bordered > thead > tr > th:last-child,
-  .table-responsive > .table-bordered > tbody > tr > th:last-child,
-  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
-  .table-responsive > .table-bordered > thead > tr > td:last-child,
-  .table-responsive > .table-bordered > tbody > tr > td:last-child,
-  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
-    border-right: 0;
-  }
-  .table-responsive > .table-bordered > tbody > tr:last-child > th,
-  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
-  .table-responsive > .table-bordered > tbody > tr:last-child > td,
-  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
-    border-bottom: 0;
-  }
-}
-fieldset {
-  min-width: 0;
-  padding: 0;
-  margin: 0;
-  border: 0;
-}
-legend {
-  display: block;
-  width: 100%;
-  padding: 0;
-  margin-bottom: 20px;
-  font-size: 21px;
-  line-height: inherit;
-  color: #333;
-  border: 0;
-  border-bottom: 1px solid #e5e5e5;
-}
-label {
-  display: inline-block;
-  max-width: 100%;
-  margin-bottom: 5px;
-  font-weight: bold;
-}
-input[type="search"] {
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-}
-input[type="radio"],
-input[type="checkbox"] {
-  margin: 4px 0 0;
-  margin-top: 1px \9;
-  line-height: normal;
-}
-input[type="file"] {
-  display: block;
-}
-input[type="range"] {
-  display: block;
-  width: 100%;
-}
-select[multiple],
-select[size] {
-  height: auto;
-}
-input[type="file"]:focus,
-input[type="radio"]:focus,
-input[type="checkbox"]:focus {
-  outline: thin dotted;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-output {
-  display: block;
-  padding-top: 7px;
-  font-size: 14px;
-  line-height: 1.42857143;
-  color: #555;
-}
-.form-control {
-  display: block;
-  width: 100%;
-  height: 34px;
-  padding: 6px 12px;
-  font-size: 14px;
-  line-height: 1.42857143;
-  color: #555;
-  background-color: #fff;
-  background-image: none;
-  border: 1px solid #ccc;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
-       -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
-          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
-}
-.form-control:focus {
-  border-color: #66afe9;
-  outline: 0;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
-          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
-}
-.form-control::-moz-placeholder {
-  color: #999;
-  opacity: 1;
-}
-.form-control:-ms-input-placeholder {
-  color: #999;
-}
-.form-control::-webkit-input-placeholder {
-  color: #999;
-}
-.form-control[disabled],
-.form-control[readonly],
-fieldset[disabled] .form-control {
-  background-color: #eee;
-  opacity: 1;
-}
-.form-control[disabled],
-fieldset[disabled] .form-control {
-  cursor: not-allowed;
-}
-textarea.form-control {
-  height: auto;
-}
-input[type="search"] {
-  -webkit-appearance: none;
-}
-@media screen and (-webkit-min-device-pixel-ratio: 0) {
-  input[type="date"],
-  input[type="time"],
-  input[type="datetime-local"],
-  input[type="month"] {
-    line-height: 34px;
-  }
-  input[type="date"].input-sm,
-  input[type="time"].input-sm,
-  input[type="datetime-local"].input-sm,
-  input[type="month"].input-sm,
-  .input-group-sm input[type="date"],
-  .input-group-sm input[type="time"],
-  .input-group-sm input[type="datetime-local"],
-  .input-group-sm input[type="month"] {
-    line-height: 30px;
-  }
-  input[type="date"].input-lg,
-  input[type="time"].input-lg,
-  input[type="datetime-local"].input-lg,
-  input[type="month"].input-lg,
-  .input-group-lg input[type="date"],
-  .input-group-lg input[type="time"],
-  .input-group-lg input[type="datetime-local"],
-  .input-group-lg input[type="month"] {
-    line-height: 46px;
-  }
-}
-.form-group {
-  margin-bottom: 15px;
-}
-.radio,
-.checkbox {
-  position: relative;
-  display: block;
-  margin-top: 10px;
-  margin-bottom: 10px;
-}
-.radio label,
-.checkbox label {
-  min-height: 20px;
-  padding-left: 20px;
-  margin-bottom: 0;
-  font-weight: normal;
-  cursor: pointer;
-}
-.radio input[type="radio"],
-.radio-inline input[type="radio"],
-.checkbox input[type="checkbox"],
-.checkbox-inline input[type="checkbox"] {
-  position: absolute;
-  margin-top: 4px \9;
-  margin-left: -20px;
-}
-.radio + .radio,
-.checkbox + .checkbox {
-  margin-top: -5px;
-}
-.radio-inline,
-.checkbox-inline {
-  position: relative;
-  display: inline-block;
-  padding-left: 20px;
-  margin-bottom: 0;
-  font-weight: normal;
-  vertical-align: middle;
-  cursor: pointer;
-}
-.radio-inline + .radio-inline,
-.checkbox-inline + .checkbox-inline {
-  margin-top: 0;
-  margin-left: 10px;
-}
-input[type="radio"][disabled],
-input[type="checkbox"][disabled],
-input[type="radio"].disabled,
-input[type="checkbox"].disabled,
-fieldset[disabled] input[type="radio"],
-fieldset[disabled] input[type="checkbox"] {
-  cursor: not-allowed;
-}
-.radio-inline.disabled,
-.checkbox-inline.disabled,
-fieldset[disabled] .radio-inline,
-fieldset[disabled] .checkbox-inline {
-  cursor: not-allowed;
-}
-.radio.disabled label,
-.checkbox.disabled label,
-fieldset[disabled] .radio label,
-fieldset[disabled] .checkbox label {
-  cursor: not-allowed;
-}
-.form-control-static {
-  min-height: 34px;
-  padding-top: 7px;
-  padding-bottom: 7px;
-  margin-bottom: 0;
-}
-.form-control-static.input-lg,
-.form-control-static.input-sm {
-  padding-right: 0;
-  padding-left: 0;
-}
-.input-sm {
-  height: 30px;
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-select.input-sm {
-  height: 30px;
-  line-height: 30px;
-}
-textarea.input-sm,
-select[multiple].input-sm {
-  height: auto;
-}
-.form-group-sm .form-control {
-  height: 30px;
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-.form-group-sm select.form-control {
-  height: 30px;
-  line-height: 30px;
-}
-.form-group-sm textarea.form-control,
-.form-group-sm select[multiple].form-control {
-  height: auto;
-}
-.form-group-sm .form-control-static {
-  height: 30px;
-  min-height: 32px;
-  padding: 6px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-}
-.input-lg {
-  height: 46px;
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-  border-radius: 6px;
-}
-select.input-lg {
-  height: 46px;
-  line-height: 46px;
-}
-textarea.input-lg,
-select[multiple].input-lg {
-  height: auto;
-}
-.form-group-lg .form-control {
-  height: 46px;
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-  border-radius: 6px;
-}
-.form-group-lg select.form-control {
-  height: 46px;
-  line-height: 46px;
-}
-.form-group-lg textarea.form-control,
-.form-group-lg select[multiple].form-control {
-  height: auto;
-}
-.form-group-lg .form-control-static {
-  height: 46px;
-  min-height: 38px;
-  padding: 11px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-}
-.has-feedback {
-  position: relative;
-}
-.has-feedback .form-control {
-  padding-right: 42.5px;
-}
-.form-control-feedback {
-  position: absolute;
-  top: 0;
-  right: 0;
-  z-index: 2;
-  display: block;
-  width: 34px;
-  height: 34px;
-  line-height: 34px;
-  text-align: center;
-  pointer-events: none;
-}
-.input-lg + .form-control-feedback,
-.input-group-lg + .form-control-feedback {
-  width: 46px;
-  height: 46px;
-  line-height: 46px;
-}
-.input-sm + .form-control-feedback,
-.input-group-sm + .form-control-feedback {
-  width: 30px;
-  height: 30px;
-  line-height: 30px;
-}
-.has-success .help-block,
-.has-success .control-label,
-.has-success .radio,
-.has-success .checkbox,
-.has-success .radio-inline,
-.has-success .checkbox-inline,
-.has-success.radio label,
-.has-success.checkbox label,
-.has-success.radio-inline label,
-.has-success.checkbox-inline label {
-  color: #3f7815;
-}
-.has-success .form-control {
-  border-color: #3f7815;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-}
-.has-success .form-control:focus {
-  border-color: #284d0e;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #6ccf24;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #6ccf24;
-}
-.has-success .input-group-addon {
-  color: #3f7815;
-  background-color: #dcf6ca;
-  border-color: #3f7815;
-}
-.has-success .form-control-feedback {
-  color: #3f7815;
-}
-.has-warning .help-block,
-.has-warning .control-label,
-.has-warning .radio,
-.has-warning .checkbox,
-.has-warning .radio-inline,
-.has-warning .checkbox-inline,
-.has-warning.radio label,
-.has-warning.checkbox label,
-.has-warning.radio-inline label,
-.has-warning.checkbox-inline label {
-  color: #7e500f;
-}
-.has-warning .form-control {
-  border-color: #7e500f;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-}
-.has-warning .form-control:focus {
-  border-color: #51330a;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #d98a1a;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #d98a1a;
-}
-.has-warning .input-group-addon {
-  color: #7e500f;
-  background-color: #f8e4c7;
-  border-color: #7e500f;
-}
-.has-warning .form-control-feedback {
-  color: #7e500f;
-}
-.has-error .help-block,
-.has-error .control-label,
-.has-error .radio,
-.has-error .checkbox,
-.has-error .radio-inline,
-.has-error .checkbox-inline,
-.has-error.radio label,
-.has-error.checkbox label,
-.has-error.radio-inline label,
-.has-error.checkbox-inline label {
-  color: #78153f;
-}
-.has-error .form-control {
-  border-color: #78153f;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-}
-.has-error .form-control:focus {
-  border-color: #4d0e28;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #cf246c;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #cf246c;
-}
-.has-error .input-group-addon {
-  color: #78153f;
-  background-color: #f6cadc;
-  border-color: #78153f;
-}
-.has-error .form-control-feedback {
-  color: #78153f;
-}
-.has-feedback label ~ .form-control-feedback {
-  top: 25px;
-}
-.has-feedback label.sr-only ~ .form-control-feedback {
-  top: 0;
-}
-.help-block {
-  display: block;
-  margin-top: 5px;
-  margin-bottom: 10px;
-  color: #737373;
-}
-@media (min-width: 768px) {
-  .form-inline .form-group {
-    display: inline-block;
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .form-inline .form-control {
-    display: inline-block;
-    width: auto;
-    vertical-align: middle;
-  }
-  .form-inline .form-control-static {
-    display: inline-block;
-  }
-  .form-inline .input-group {
-    display: inline-table;
-    vertical-align: middle;
-  }
-  .form-inline .input-group .input-group-addon,
-  .form-inline .input-group .input-group-btn,
-  .form-inline .input-group .form-control {
-    width: auto;
-  }
-  .form-inline .input-group > .form-control {
-    width: 100%;
-  }
-  .form-inline .control-label {
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .form-inline .radio,
-  .form-inline .checkbox {
-    display: inline-block;
-    margin-top: 0;
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .form-inline .radio label,
-  .form-inline .checkbox label {
-    padding-left: 0;
-  }
-  .form-inline .radio input[type="radio"],
-  .form-inline .checkbox input[type="checkbox"] {
-    position: relative;
-    margin-left: 0;
-  }
-  .form-inline .has-feedback .form-control-feedback {
-    top: 0;
-  }
-}
-.form-horizontal .radio,
-.form-horizontal .checkbox,
-.form-horizontal .radio-inline,
-.form-horizontal .checkbox-inline {
-  padding-top: 7px;
-  margin-top: 0;
-  margin-bottom: 0;
-}
-.form-horizontal .radio,
-.form-horizontal .checkbox {
-  min-height: 27px;
-}
-.form-horizontal .form-group {
-  margin-right: -15px;
-  margin-left: -15px;
-}
-@media (min-width: 768px) {
-  .form-horizontal .control-label {
-    padding-top: 7px;
-    margin-bottom: 0;
-    text-align: right;
-  }
-}
-.form-horizontal .has-feedback .form-control-feedback {
-  right: 15px;
-}
-@media (min-width: 768px) {
-  .form-horizontal .form-group-lg .control-label {
-    padding-top: 14.333333px;
-    font-size: 18px;
-  }
-}
-@media (min-width: 768px) {
-  .form-horizontal .form-group-sm .control-label {
-    padding-top: 6px;
-    font-size: 12px;
-  }
-}
-.btn {
-  display: inline-block;
-  padding: 6px 12px;
-  margin-bottom: 0;
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 1.42857143;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: middle;
-  -ms-touch-action: manipulation;
-      touch-action: manipulation;
-  cursor: pointer;
-  -webkit-user-select: none;
-     -moz-user-select: none;
-      -ms-user-select: none;
-          user-select: none;
-  background-image: none;
-  border: 1px solid transparent;
-  border-radius: 4px;
-}
-.btn:focus,
-.btn:active:focus,
-.btn.active:focus,
-.btn.focus,
-.btn:active.focus,
-.btn.active.focus {
-  outline: thin dotted;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-.btn:hover,
-.btn:focus,
-.btn.focus {
-  color: #333;
-  text-decoration: none;
-}
-.btn:active,
-.btn.active {
-  background-image: none;
-  outline: 0;
-  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-}
-.btn.disabled,
-.btn[disabled],
-fieldset[disabled] .btn {
-  cursor: not-allowed;
-  filter: alpha(opacity=65);
-  -webkit-box-shadow: none;
-          box-shadow: none;
-  opacity: .65;
-}
-a.btn.disabled,
-fieldset[disabled] a.btn {
-  pointer-events: none;
-}
-.btn-default {
-  color: #333;
-  background-color: #fff;
-  border-color: #ccc;
-}
-.btn-default:focus,
-.btn-default.focus {
-  color: #333;
-  background-color: #e6e6e6;
-  border-color: #8c8c8c;
-}
-.btn-default:hover {
-  color: #333;
-  background-color: #e6e6e6;
-  border-color: #adadad;
-}
-.btn-default:active,
-.btn-default.active,
-.open > .dropdown-toggle.btn-default {
-  color: #333;
-  background-color: #e6e6e6;
-  border-color: #adadad;
-}
-.btn-default:active:hover,
-.btn-default.active:hover,
-.open > .dropdown-toggle.btn-default:hover,
-.btn-default:active:focus,
-.btn-default.active:focus,
-.open > .dropdown-toggle.btn-default:focus,
-.btn-default:active.focus,
-.btn-default.active.focus,
-.open > .dropdown-toggle.btn-default.focus {
-  color: #333;
-  background-color: #d4d4d4;
-  border-color: #8c8c8c;
-}
-.btn-default:active,
-.btn-default.active,
-.open > .dropdown-toggle.btn-default {
-  background-image: none;
-}
-.btn-default.disabled,
-.btn-default[disabled],
-fieldset[disabled] .btn-default,
-.btn-default.disabled:hover,
-.btn-default[disabled]:hover,
-fieldset[disabled] .btn-default:hover,
-.btn-default.disabled:focus,
-.btn-default[disabled]:focus,
-fieldset[disabled] .btn-default:focus,
-.btn-default.disabled.focus,
-.btn-default[disabled].focus,
-fieldset[disabled] .btn-default.focus,
-.btn-default.disabled:active,
-.btn-default[disabled]:active,
-fieldset[disabled] .btn-default:active,
-.btn-default.disabled.active,
-.btn-default[disabled].active,
-fieldset[disabled] .btn-default.active {
-  background-color: #fff;
-  border-color: #ccc;
-}
-.btn-default .badge {
-  color: #fff;
-  background-color: #333;
-}
-.btn-primary {
-  color: #fff;
-  background-color: #428bca;
-  border-color: #357ebd;
-}
-.btn-primary:focus,
-.btn-primary.focus {
-  color: #fff;
-  background-color: #3071a9;
-  border-color: #193c5a;
-}
-.btn-primary:hover {
-  color: #fff;
-  background-color: #3071a9;
-  border-color: #285e8e;
-}
-.btn-primary:active,
-.btn-primary.active,
-.open > .dropdown-toggle.btn-primary {
-  color: #fff;
-  background-color: #3071a9;
-  border-color: #285e8e;
-}
-.btn-primary:active:hover,
-.btn-primary.active:hover,
-.open > .dropdown-toggle.btn-primary:hover,
-.btn-primary:active:focus,
-.btn-primary.active:focus,
-.open > .dropdown-toggle.btn-primary:focus,
-.btn-primary:active.focus,
-.btn-primary.active.focus,
-.open > .dropdown-toggle.btn-primary.focus {
-  color: #fff;
-  background-color: #285e8e;
-  border-color: #193c5a;
-}
-.btn-primary:active,
-.btn-primary.active,
-.open > .dropdown-toggle.btn-primary {
-  background-image: none;
-}
-.btn-primary.disabled,
-.btn-primary[disabled],
-fieldset[disabled] .btn-primary,
-.btn-primary.disabled:hover,
-.btn-primary[disabled]:hover,
-fieldset[disabled] .btn-primary:hover,
-.btn-primary.disabled:focus,
-.btn-primary[disabled]:focus,
-fieldset[disabled] .btn-primary:focus,
-.btn-primary.disabled.focus,
-.btn-primary[disabled].focus,
-fieldset[disabled] .btn-primary.focus,
-.btn-primary.disabled:active,
-.btn-primary[disabled]:active,
-fieldset[disabled] .btn-primary:active,
-.btn-primary.disabled.active,
-.btn-primary[disabled].active,
-fieldset[disabled] .btn-primary.active {
-  background-color: #428bca;
-  border-color: #357ebd;
-}
-.btn-primary .badge {
-  color: #428bca;
-  background-color: #fff;
-}
-.btn-success {
-  color: #fff;
-  background-color: #79db32;
-  border-color: #6ccf24;
-}
-.btn-success:focus,
-.btn-success.focus {
-  color: #fff;
-  background-color: #61b921;
-  border-color: #346311;
-}
-.btn-success:hover {
-  color: #fff;
-  background-color: #61b921;
-  border-color: #519b1b;
-}
-.btn-success:active,
-.btn-success.active,
-.open > .dropdown-toggle.btn-success {
-  color: #fff;
-  background-color: #61b921;
-  border-color: #519b1b;
-}
-.btn-success:active:hover,
-.btn-success.active:hover,
-.open > .dropdown-toggle.btn-success:hover,
-.btn-success:active:focus,
-.btn-success.active:focus,
-.open > .dropdown-toggle.btn-success:focus,
-.btn-success:active.focus,
-.btn-success.active.focus,
-.open > .dropdown-toggle.btn-success.focus {
-  color: #fff;
-  background-color: #519b1b;
-  border-color: #346311;
-}
-.btn-success:active,
-.btn-success.active,
-.open > .dropdown-toggle.btn-success {
-  background-image: none;
-}
-.btn-success.disabled,
-.btn-success[disabled],
-fieldset[disabled] .btn-success,
-.btn-success.disabled:hover,
-.btn-success[disabled]:hover,
-fieldset[disabled] .btn-success:hover,
-.btn-success.disabled:focus,
-.btn-success[disabled]:focus,
-fieldset[disabled] .btn-success:focus,
-.btn-success.disabled.focus,
-.btn-success[disabled].focus,
-fieldset[disabled] .btn-success.focus,
-.btn-success.disabled:active,
-.btn-success[disabled]:active,
-fieldset[disabled] .btn-success:active,
-.btn-success.disabled.active,
-.btn-success[disabled].active,
-fieldset[disabled] .btn-success.active {
-  background-color: #79db32;
-  border-color: #6ccf24;
-}
-.btn-success .badge {
-  color: #79db32;
-  background-color: #fff;
-}
-.btn-info {
-  color: #fff;
-  background-color: #a07cbc;
-  border-color: #946bb3;
-}
-.btn-info:focus,
-.btn-info.focus {
-  color: #fff;
-  background-color: #885aab;
-  border-color: #533669;
-}
-.btn-info:hover {
-  color: #fff;
-  background-color: #885aab;
-  border-color: #754c95;
-}
-.btn-info:active,
-.btn-info.active,
-.open > .dropdown-toggle.btn-info {
-  color: #fff;
-  background-color: #885aab;
-  border-color: #754c95;
-}
-.btn-info:active:hover,
-.btn-info.active:hover,
-.open > .dropdown-toggle.btn-info:hover,
-.btn-info:active:focus,
-.btn-info.active:focus,
-.open > .dropdown-toggle.btn-info:focus,
-.btn-info:active.focus,
-.btn-info.active.focus,
-.open > .dropdown-toggle.btn-info.focus {
-  color: #fff;
-  background-color: #754c95;
-  border-color: #533669;
-}
-.btn-info:active,
-.btn-info.active,
-.open > .dropdown-toggle.btn-info {
-  background-image: none;
-}
-.btn-info.disabled,
-.btn-info[disabled],
-fieldset[disabled] .btn-info,
-.btn-info.disabled:hover,
-.btn-info[disabled]:hover,
-fieldset[disabled] .btn-info:hover,
-.btn-info.disabled:focus,
-.btn-info[disabled]:focus,
-fieldset[disabled] .btn-info:focus,
-.btn-info.disabled.focus,
-.btn-info[disabled].focus,
-fieldset[disabled] .btn-info.focus,
-.btn-info.disabled:active,
-.btn-info[disabled]:active,
-fieldset[disabled] .btn-info:active,
-.btn-info.disabled.active,
-.btn-info[disabled].active,
-fieldset[disabled] .btn-info.active {
-  background-color: #a07cbc;
-  border-color: #946bb3;
-}
-.btn-info .badge {
-  color: #a07cbc;
-  background-color: #fff;
-}
-.btn-warning {
-  color: #fff;
-  background-color: #e59728;
-  border-color: #d98a1a;
-}
-.btn-warning:focus,
-.btn-warning.focus {
-  color: #fff;
-  background-color: #c27c18;
-  border-color: #67420d;
-}
-.btn-warning:hover {
-  color: #fff;
-  background-color: #c27c18;
-  border-color: #a36814;
-}
-.btn-warning:active,
-.btn-warning.active,
-.open > .dropdown-toggle.btn-warning {
-  color: #fff;
-  background-color: #c27c18;
-  border-color: #a36814;
-}
-.btn-warning:active:hover,
-.btn-warning.active:hover,
-.open > .dropdown-toggle.btn-warning:hover,
-.btn-warning:active:focus,
-.btn-warning.active:focus,
-.open > .dropdown-toggle.btn-warning:focus,
-.btn-warning:active.focus,
-.btn-warning.active.focus,
-.open > .dropdown-toggle.btn-warning.focus {
-  color: #fff;
-  background-color: #a36814;
-  border-color: #67420d;
-}
-.btn-warning:active,
-.btn-warning.active,
-.open > .dropdown-toggle.btn-warning {
-  background-image: none;
-}
-.btn-warning.disabled,
-.btn-warning[disabled],
-fieldset[disabled] .btn-warning,
-.btn-warning.disabled:hover,
-.btn-warning[disabled]:hover,
-fieldset[disabled] .btn-warning:hover,
-.btn-warning.disabled:focus,
-.btn-warning[disabled]:focus,
-fieldset[disabled] .btn-warning:focus,
-.btn-warning.disabled.focus,
-.btn-warning[disabled].focus,
-fieldset[disabled] .btn-warning.focus,
-.btn-warning.disabled:active,
-.btn-warning[disabled]:active,
-fieldset[disabled] .btn-warning:active,
-.btn-warning.disabled.active,
-.btn-warning[disabled].active,
-fieldset[disabled] .btn-warning.active {
-  background-color: #e59728;
-  border-color: #d98a1a;
-}
-.btn-warning .badge {
-  color: #e59728;
-  background-color: #fff;
-}
-.btn-danger {
-  color: #fff;
-  background-color: #db3279;
-  border-color: #cf246c;
-}
-.btn-danger:focus,
-.btn-danger.focus {
-  color: #fff;
-  background-color: #b92161;
-  border-color: #631134;
-}
-.btn-danger:hover {
-  color: #fff;
-  background-color: #b92161;
-  border-color: #9b1b51;
-}
-.btn-danger:active,
-.btn-danger.active,
-.open > .dropdown-toggle.btn-danger {
-  color: #fff;
-  background-color: #b92161;
-  border-color: #9b1b51;
-}
-.btn-danger:active:hover,
-.btn-danger.active:hover,
-.open > .dropdown-toggle.btn-danger:hover,
-.btn-danger:active:focus,
-.btn-danger.active:focus,
-.open > .dropdown-toggle.btn-danger:focus,
-.btn-danger:active.focus,
-.btn-danger.active.focus,
-.open > .dropdown-toggle.btn-danger.focus {
-  color: #fff;
-  background-color: #9b1b51;
-  border-color: #631134;
-}
-.btn-danger:active,
-.btn-danger.active,
-.open > .dropdown-toggle.btn-danger {
-  background-image: none;
-}
-.btn-danger.disabled,
-.btn-danger[disabled],
-fieldset[disabled] .btn-danger,
-.btn-danger.disabled:hover,
-.btn-danger[disabled]:hover,
-fieldset[disabled] .btn-danger:hover,
-.btn-danger.disabled:focus,
-.btn-danger[disabled]:focus,
-fieldset[disabled] .btn-danger:focus,
-.btn-danger.disabled.focus,
-.btn-danger[disabled].focus,
-fieldset[disabled] .btn-danger.focus,
-.btn-danger.disabled:active,
-.btn-danger[disabled]:active,
-fieldset[disabled] .btn-danger:active,
-.btn-danger.disabled.active,
-.btn-danger[disabled].active,
-fieldset[disabled] .btn-danger.active {
-  background-color: #db3279;
-  border-color: #cf246c;
-}
-.btn-danger .badge {
-  color: #db3279;
-  background-color: #fff;
-}
-.btn-link {
-  font-weight: normal;
-  color: #428bca;
-  border-radius: 0;
-}
-.btn-link,
-.btn-link:active,
-.btn-link.active,
-.btn-link[disabled],
-fieldset[disabled] .btn-link {
-  background-color: transparent;
-  -webkit-box-shadow: none;
-          box-shadow: none;
-}
-.btn-link,
-.btn-link:hover,
-.btn-link:focus,
-.btn-link:active {
-  border-color: transparent;
-}
-.btn-link:hover,
-.btn-link:focus {
-  color: #2a6496;
-  text-decoration: underline;
-  background-color: transparent;
-}
-.btn-link[disabled]:hover,
-fieldset[disabled] .btn-link:hover,
-.btn-link[disabled]:focus,
-fieldset[disabled] .btn-link:focus {
-  color: #777;
-  text-decoration: none;
-}
-.btn-lg,
-.btn-group-lg > .btn {
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-  border-radius: 6px;
-}
-.btn-sm,
-.btn-group-sm > .btn {
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-.btn-xs,
-.btn-group-xs > .btn {
-  padding: 1px 5px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-.btn-block {
-  display: block;
-  width: 100%;
-}
-.btn-block + .btn-block {
-  margin-top: 5px;
-}
-input[type="submit"].btn-block,
-input[type="reset"].btn-block,
-input[type="button"].btn-block {
-  width: 100%;
-}
-.fade {
-  opacity: 0;
-  -webkit-transition: opacity .15s linear;
-       -o-transition: opacity .15s linear;
-          transition: opacity .15s linear;
-}
-.fade.in {
-  opacity: 1;
-}
-.collapse {
-  display: none;
-}
-.collapse.in {
-  display: block;
-}
-tr.collapse.in {
-  display: table-row;
-}
-tbody.collapse.in {
-  display: table-row-group;
-}
-.collapsing {
-  position: relative;
-  height: 0;
-  overflow: hidden;
-  -webkit-transition-timing-function: ease;
-       -o-transition-timing-function: ease;
-          transition-timing-function: ease;
-  -webkit-transition-duration: .35s;
-       -o-transition-duration: .35s;
-          transition-duration: .35s;
-  -webkit-transition-property: height, visibility;
-       -o-transition-property: height, visibility;
-          transition-property: height, visibility;
-}
-.caret {
-  display: inline-block;
-  width: 0;
-  height: 0;
-  margin-left: 2px;
-  vertical-align: middle;
-  border-top: 4px dashed;
-  border-right: 4px solid transparent;
-  border-left: 4px solid transparent;
-}
-.dropup,
-.dropdown {
-  position: relative;
-}
-.dropdown-toggle:focus {
-  outline: 0;
-}
-.dropdown-menu {
-  position: absolute;
-  top: 100%;
-  left: 0;
-  z-index: 1000;
-  display: none;
-  float: left;
-  min-width: 160px;
-  padding: 5px 0;
-  margin: 2px 0 0;
-  font-size: 14px;
-  text-align: left;
-  list-style: none;
-  background-color: #fff;
-  -webkit-background-clip: padding-box;
-          background-clip: padding-box;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, .15);
-  border-radius: 4px;
-  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
-          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
-}
-.dropdown-menu.pull-right {
-  right: 0;
-  left: auto;
-}
-.dropdown-menu .divider {
-  height: 1px;
-  margin: 9px 0;
-  overflow: hidden;
-  background-color: #e5e5e5;
-}
-.dropdown-menu > li > a {
-  display: block;
-  padding: 3px 20px;
-  clear: both;
-  font-weight: normal;
-  line-height: 1.42857143;
-  color: #333;
-  white-space: nowrap;
-}
-.dropdown-menu > li > a:hover,
-.dropdown-menu > li > a:focus {
-  color: #262626;
-  text-decoration: none;
-  background-color: #f5f5f5;
-}
-.dropdown-menu > .active > a,
-.dropdown-menu > .active > a:hover,
-.dropdown-menu > .active > a:focus {
-  color: #fff;
-  text-decoration: none;
-  background-color: #428bca;
-  outline: 0;
-}
-.dropdown-menu > .disabled > a,
-.dropdown-menu > .disabled > a:hover,
-.dropdown-menu > .disabled > a:focus {
-  color: #777;
-}
-.dropdown-menu > .disabled > a:hover,
-.dropdown-menu > .disabled > a:focus {
-  text-decoration: none;
-  cursor: not-allowed;
-  background-color: transparent;
-  background-image: none;
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-}
-.open > .dropdown-menu {
-  display: block;
-}
-.open > a {
-  outline: 0;
-}
-.dropdown-menu-right {
-  right: 0;
-  left: auto;
-}
-.dropdown-menu-left {
-  right: auto;
-  left: 0;
-}
-.dropdown-header {
-  display: block;
-  padding: 3px 20px;
-  font-size: 12px;
-  line-height: 1.42857143;
-  color: #777;
-  white-space: nowrap;
-}
-.dropdown-backdrop {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 990;
-}
-.pull-right > .dropdown-menu {
-  right: 0;
-  left: auto;
-}
-.dropup .caret,
-.navbar-fixed-bottom .dropdown .caret {
-  content: "";
-  border-top: 0;
-  border-bottom: 4px solid;
-}
-.dropup .dropdown-menu,
-.navbar-fixed-bottom .dropdown .dropdown-menu {
-  top: auto;
-  bottom: 100%;
-  margin-bottom: 2px;
-}
-@media (min-width: 768px) {
-  .navbar-right .dropdown-menu {
-    right: 0;
-    left: auto;
-  }
-  .navbar-right .dropdown-menu-left {
-    right: auto;
-    left: 0;
-  }
-}
-.btn-group,
-.btn-group-vertical {
-  position: relative;
-  display: inline-block;
-  vertical-align: middle;
-}
-.btn-group > .btn,
-.btn-group-vertical > .btn {
-  position: relative;
-  float: left;
-}
-.btn-group > .btn:hover,
-.btn-group-vertical > .btn:hover,
-.btn-group > .btn:focus,
-.btn-group-vertical > .btn:focus,
-.btn-group > .btn:active,
-.btn-group-vertical > .btn:active,
-.btn-group > .btn.active,
-.btn-group-vertical > .btn.active {
-  z-index: 2;
-}
-.btn-group .btn + .btn,
-.btn-group .btn + .btn-group,
-.btn-group .btn-group + .btn,
-.btn-group .btn-group + .btn-group {
-  margin-left: -1px;
-}
-.btn-toolbar {
-  margin-left: -5px;
-}
-.btn-toolbar .btn,
-.btn-toolbar .btn-group,
-.btn-toolbar .input-group {
-  float: left;
-}
-.btn-toolbar > .btn,
-.btn-toolbar > .btn-group,
-.btn-toolbar > .input-group {
-  margin-left: 5px;
-}
-.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
-  border-radius: 0;
-}
-.btn-group > .btn:first-child {
-  margin-left: 0;
-}
-.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-.btn-group > .btn:last-child:not(:first-child),
-.btn-group > .dropdown-toggle:not(:first-child) {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group > .btn-group {
-  float: left;
-}
-.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
-  border-radius: 0;
-}
-.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
-.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group .dropdown-toggle:active,
-.btn-group.open .dropdown-toggle {
-  outline: 0;
-}
-.btn-group > .btn + .dropdown-toggle {
-  padding-right: 8px;
-  padding-left: 8px;
-}
-.btn-group > .btn-lg + .dropdown-toggle {
-  padding-right: 12px;
-  padding-left: 12px;
-}
-.btn-group.open .dropdown-toggle {
-  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-}
-.btn-group.open .dropdown-toggle.btn-link {
-  -webkit-box-shadow: none;
-          box-shadow: none;
-}
-.btn .caret {
-  margin-left: 0;
-}
-.btn-lg .caret {
-  border-width: 5px 5px 0;
-  border-bottom-width: 0;
-}
-.dropup .btn-lg .caret {
-  border-width: 0 5px 5px;
-}
-.btn-group-vertical > .btn,
-.btn-group-vertical > .btn-group,
-.btn-group-vertical > .btn-group > .btn {
-  display: block;
-  float: none;
-  width: 100%;
-  max-width: 100%;
-}
-.btn-group-vertical > .btn-group > .btn {
-  float: none;
-}
-.btn-group-vertical > .btn + .btn,
-.btn-group-vertical > .btn + .btn-group,
-.btn-group-vertical > .btn-group + .btn,
-.btn-group-vertical > .btn-group + .btn-group {
-  margin-top: -1px;
-  margin-left: 0;
-}
-.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
-  border-radius: 0;
-}
-.btn-group-vertical > .btn:first-child:not(:last-child) {
-  border-top-right-radius: 4px;
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group-vertical > .btn:last-child:not(:first-child) {
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-  border-bottom-left-radius: 4px;
-}
-.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
-  border-radius: 0;
-}
-.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
-.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.btn-group-justified {
-  display: table;
-  width: 100%;
-  table-layout: fixed;
-  border-collapse: separate;
-}
-.btn-group-justified > .btn,
-.btn-group-justified > .btn-group {
-  display: table-cell;
-  float: none;
-  width: 1%;
-}
-.btn-group-justified > .btn-group .btn {
-  width: 100%;
-}
-.btn-group-justified > .btn-group .dropdown-menu {
-  left: auto;
-}
-[data-toggle="buttons"] > .btn input[type="radio"],
-[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
-[data-toggle="buttons"] > .btn input[type="checkbox"],
-[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
-  position: absolute;
-  clip: rect(0, 0, 0, 0);
-  pointer-events: none;
-}
-.input-group {
-  position: relative;
-  display: table;
-  border-collapse: separate;
-}
-.input-group[class*="col-"] {
-  float: none;
-  padding-right: 0;
-  padding-left: 0;
-}
-.input-group .form-control {
-  position: relative;
-  z-index: 2;
-  float: left;
-  width: 100%;
-  margin-bottom: 0;
-}
-.input-group-lg > .form-control,
-.input-group-lg > .input-group-addon,
-.input-group-lg > .input-group-btn > .btn {
-  height: 46px;
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-  border-radius: 6px;
-}
-select.input-group-lg > .form-control,
-select.input-group-lg > .input-group-addon,
-select.input-group-lg > .input-group-btn > .btn {
-  height: 46px;
-  line-height: 46px;
-}
-textarea.input-group-lg > .form-control,
-textarea.input-group-lg > .input-group-addon,
-textarea.input-group-lg > .input-group-btn > .btn,
-select[multiple].input-group-lg > .form-control,
-select[multiple].input-group-lg > .input-group-addon,
-select[multiple].input-group-lg > .input-group-btn > .btn {
-  height: auto;
-}
-.input-group-sm > .form-control,
-.input-group-sm > .input-group-addon,
-.input-group-sm > .input-group-btn > .btn {
-  height: 30px;
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-select.input-group-sm > .form-control,
-select.input-group-sm > .input-group-addon,
-select.input-group-sm > .input-group-btn > .btn {
-  height: 30px;
-  line-height: 30px;
-}
-textarea.input-group-sm > .form-control,
-textarea.input-group-sm > .input-group-addon,
-textarea.input-group-sm > .input-group-btn > .btn,
-select[multiple].input-group-sm > .form-control,
-select[multiple].input-group-sm > .input-group-addon,
-select[multiple].input-group-sm > .input-group-btn > .btn {
-  height: auto;
-}
-.input-group-addon,
-.input-group-btn,
-.input-group .form-control {
-  display: table-cell;
-}
-.input-group-addon:not(:first-child):not(:last-child),
-.input-group-btn:not(:first-child):not(:last-child),
-.input-group .form-control:not(:first-child):not(:last-child) {
-  border-radius: 0;
-}
-.input-group-addon,
-.input-group-btn {
-  width: 1%;
-  white-space: nowrap;
-  vertical-align: middle;
-}
-.input-group-addon {
-  padding: 6px 12px;
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 1;
-  color: #555;
-  text-align: center;
-  background-color: #eee;
-  border: 1px solid #ccc;
-  border-radius: 4px;
-}
-.input-group-addon.input-sm {
-  padding: 5px 10px;
-  font-size: 12px;
-  border-radius: 3px;
-}
-.input-group-addon.input-lg {
-  padding: 10px 16px;
-  font-size: 18px;
-  border-radius: 6px;
-}
-.input-group-addon input[type="radio"],
-.input-group-addon input[type="checkbox"] {
-  margin-top: 0;
-}
-.input-group .form-control:first-child,
-.input-group-addon:first-child,
-.input-group-btn:first-child > .btn,
-.input-group-btn:first-child > .btn-group > .btn,
-.input-group-btn:first-child > .dropdown-toggle,
-.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
-.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-.input-group-addon:first-child {
-  border-right: 0;
-}
-.input-group .form-control:last-child,
-.input-group-addon:last-child,
-.input-group-btn:last-child > .btn,
-.input-group-btn:last-child > .btn-group > .btn,
-.input-group-btn:last-child > .dropdown-toggle,
-.input-group-btn:first-child > .btn:not(:first-child),
-.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.input-group-addon:last-child {
-  border-left: 0;
-}
-.input-group-btn {
-  position: relative;
-  font-size: 0;
-  white-space: nowrap;
-}
-.input-group-btn > .btn {
-  position: relative;
-}
-.input-group-btn > .btn + .btn {
-  margin-left: -1px;
-}
-.input-group-btn > .btn:hover,
-.input-group-btn > .btn:focus,
-.input-group-btn > .btn:active {
-  z-index: 2;
-}
-.input-group-btn:first-child > .btn,
-.input-group-btn:first-child > .btn-group {
-  margin-right: -1px;
-}
-.input-group-btn:last-child > .btn,
-.input-group-btn:last-child > .btn-group {
-  z-index: 2;
-  margin-left: -1px;
-}
-.nav {
-  padding-left: 0;
-  margin-bottom: 0;
-  list-style: none;
-}
-.nav > li {
-  position: relative;
-  display: block;
-}
-.nav > li > a {
-  position: relative;
-  display: block;
-  padding: 10px 15px;
-}
-.nav > li > a:hover,
-.nav > li > a:focus {
-  text-decoration: none;
-  background-color: #eee;
-}
-.nav > li.disabled > a {
-  color: #777;
-}
-.nav > li.disabled > a:hover,
-.nav > li.disabled > a:focus {
-  color: #777;
-  text-decoration: none;
-  cursor: not-allowed;
-  background-color: transparent;
-}
-.nav .open > a,
-.nav .open > a:hover,
-.nav .open > a:focus {
-  background-color: #eee;
-  border-color: #428bca;
-}
-.nav .nav-divider {
-  height: 1px;
-  margin: 9px 0;
-  overflow: hidden;
-  background-color: #e5e5e5;
-}
-.nav > li > a > img {
-  max-width: none;
-}
-.nav-tabs {
-  border-bottom: 1px solid #ddd;
-}
-.nav-tabs > li {
-  float: left;
-  margin-bottom: -1px;
-}
-.nav-tabs > li > a {
-  margin-right: 2px;
-  line-height: 1.42857143;
-  border: 1px solid transparent;
-  border-radius: 4px 4px 0 0;
-}
-.nav-tabs > li > a:hover {
-  border-color: #eee #eee #ddd;
-}
-.nav-tabs > li.active > a,
-.nav-tabs > li.active > a:hover,
-.nav-tabs > li.active > a:focus {
-  color: #555;
-  cursor: default;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-bottom-color: transparent;
-}
-.nav-tabs.nav-justified {
-  width: 100%;
-  border-bottom: 0;
-}
-.nav-tabs.nav-justified > li {
-  float: none;
-}
-.nav-tabs.nav-justified > li > a {
-  margin-bottom: 5px;
-  text-align: center;
-}
-.nav-tabs.nav-justified > .dropdown .dropdown-menu {
-  top: auto;
-  left: auto;
-}
-@media (min-width: 768px) {
-  .nav-tabs.nav-justified > li {
-    display: table-cell;
-    width: 1%;
-  }
-  .nav-tabs.nav-justified > li > a {
-    margin-bottom: 0;
-  }
-}
-.nav-tabs.nav-justified > li > a {
-  margin-right: 0;
-  border-radius: 4px;
-}
-.nav-tabs.nav-justified > .active > a,
-.nav-tabs.nav-justified > .active > a:hover,
-.nav-tabs.nav-justified > .active > a:focus {
-  border: 1px solid #ddd;
-}
-@media (min-width: 768px) {
-  .nav-tabs.nav-justified > li > a {
-    border-bottom: 1px solid #ddd;
-    border-radius: 4px 4px 0 0;
-  }
-  .nav-tabs.nav-justified > .active > a,
-  .nav-tabs.nav-justified > .active > a:hover,
-  .nav-tabs.nav-justified > .active > a:focus {
-    border-bottom-color: #fff;
-  }
-}
-.nav-pills > li {
-  float: left;
-}
-.nav-pills > li > a {
-  border-radius: 4px;
-}
-.nav-pills > li + li {
-  margin-left: 2px;
-}
-.nav-pills > li.active > a,
-.nav-pills > li.active > a:hover,
-.nav-pills > li.active > a:focus {
-  color: #fff;
-  background-color: #428bca;
-}
-.nav-stacked > li {
-  float: none;
-}
-.nav-stacked > li + li {
-  margin-top: 2px;
-  margin-left: 0;
-}
-.nav-justified {
-  width: 100%;
-}
-.nav-justified > li {
-  float: none;
-}
-.nav-justified > li > a {
-  margin-bottom: 5px;
-  text-align: center;
-}
-.nav-justified > .dropdown .dropdown-menu {
-  top: auto;
-  left: auto;
-}
-@media (min-width: 768px) {
-  .nav-justified > li {
-    display: table-cell;
-    width: 1%;
-  }
-  .nav-justified > li > a {
-    margin-bottom: 0;
-  }
-}
-.nav-tabs-justified {
-  border-bottom: 0;
-}
-.nav-tabs-justified > li > a {
-  margin-right: 0;
-  border-radius: 4px;
-}
-.nav-tabs-justified > .active > a,
-.nav-tabs-justified > .active > a:hover,
-.nav-tabs-justified > .active > a:focus {
-  border: 1px solid #ddd;
-}
-@media (min-width: 768px) {
-  .nav-tabs-justified > li > a {
-    border-bottom: 1px solid #ddd;
-    border-radius: 4px 4px 0 0;
-  }
-  .nav-tabs-justified > .active > a,
-  .nav-tabs-justified > .active > a:hover,
-  .nav-tabs-justified > .active > a:focus {
-    border-bottom-color: #fff;
-  }
-}
-.tab-content > .tab-pane {
-  display: none;
-}
-.tab-content > .active {
-  display: block;
-}
-.nav .caret {
-  border-top-color: #db3279;
-  border-bottom-color: #db3279;
-}
-.nav a:hover .caret {
-  border-top-color: #b92161;
-  border-bottom-color: #b92161;
-}
-.nav-tabs .dropdown-menu {
-  margin-top: -1px;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.navbar {
-  position: relative;
-  min-height: 35px;
-  margin-bottom: 20px;
-  border: 1px solid transparent;
-}
-@media (min-width: 768px) {
-  .navbar {
-    border-radius: 4px;
-  }
-}
-@media (min-width: 768px) {
-  .navbar-header {
-    float: left;
-  }
-}
-.navbar-collapse {
-  padding-right: 15px;
-  padding-left: 15px;
-  overflow-x: visible;
-  -webkit-overflow-scrolling: touch;
-  border-top: 1px solid transparent;
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
-}
-.navbar-collapse.in {
-  overflow-y: auto;
-}
-@media (min-width: 768px) {
-  .navbar-collapse {
-    width: auto;
-    border-top: 0;
-    -webkit-box-shadow: none;
-            box-shadow: none;
-  }
-  .navbar-collapse.collapse {
-    display: block !important;
-    height: auto !important;
-    padding-bottom: 0;
-    overflow: visible !important;
-  }
-  .navbar-collapse.in {
-    overflow-y: visible;
-  }
-  .navbar-fixed-top .navbar-collapse,
-  .navbar-static-top .navbar-collapse,
-  .navbar-fixed-bottom .navbar-collapse {
-    padding-right: 0;
-    padding-left: 0;
-  }
-}
-.navbar-fixed-top .navbar-collapse,
-.navbar-fixed-bottom .navbar-collapse {
-  max-height: 340px;
-}
-@media (max-device-width: 480px) and (orientation: landscape) {
-  .navbar-fixed-top .navbar-collapse,
-  .navbar-fixed-bottom .navbar-collapse {
-    max-height: 200px;
-  }
-}
-.container > .navbar-header,
-.container-fluid > .navbar-header,
-.container > .navbar-collapse,
-.container-fluid > .navbar-collapse {
-  margin-right: -15px;
-  margin-left: -15px;
-}
-@media (min-width: 768px) {
-  .container > .navbar-header,
-  .container-fluid > .navbar-header,
-  .container > .navbar-collapse,
-  .container-fluid > .navbar-collapse {
-    margin-right: 0;
-    margin-left: 0;
-  }
-}
-.navbar-static-top {
-  z-index: 1000;
-  border-width: 0 0 1px;
-}
-@media (min-width: 768px) {
-  .navbar-static-top {
-    border-radius: 0;
-  }
-}
-.navbar-fixed-top,
-.navbar-fixed-bottom {
-  position: fixed;
-  right: 0;
-  left: 0;
-  z-index: 1030;
-}
-@media (min-width: 768px) {
-  .navbar-fixed-top,
-  .navbar-fixed-bottom {
-    border-radius: 0;
-  }
-}
-.navbar-fixed-top {
-  top: 0;
-  border-width: 0 0 1px;
-}
-.navbar-fixed-bottom {
-  bottom: 0;
-  margin-bottom: 0;
-  border-width: 1px 0 0;
-}
-.navbar-brand {
-  float: left;
-  height: 35px;
-  padding: 7.5px 15px;
-  font-family: Comfortaa, "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 18px;
-  font-weight: bold;
-  line-height: 20px;
-}
-.navbar-brand:hover,
-.navbar-brand:focus {
-  text-decoration: none;
-}
-.navbar-brand > img {
-  display: block;
-}
-@media (min-width: 768px) {
-  .navbar > .container .navbar-brand,
-  .navbar > .container-fluid .navbar-brand {
-    margin-left: -15px;
-  }
-}
-.navbar-toggle {
-  position: relative;
-  float: right;
-  padding: 9px 10px;
-  margin-top: .5px;
-  margin-right: 15px;
-  margin-bottom: .5px;
-  background-color: transparent;
-  background-image: none;
-  border: 1px solid transparent;
-  border-radius: 4px;
-}
-.navbar-toggle:focus {
-  outline: 0;
-}
-.navbar-toggle .icon-bar {
-  display: block;
-  width: 22px;
-  height: 2px;
-  border-radius: 1px;
-}
-.navbar-toggle .icon-bar + .icon-bar {
-  margin-top: 4px;
-}
-@media (min-width: 768px) {
-  .navbar-toggle {
-    display: none;
-  }
-}
-.navbar-nav {
-  margin: 3.75px -15px;
-}
-.navbar-nav > li > a {
-  padding-top: 10px;
-  padding-bottom: 10px;
-  line-height: 20px;
-}
-@media (max-width: 767px) {
-  .navbar-nav .open .dropdown-menu {
-    position: static;
-    float: none;
-    width: auto;
-    margin-top: 0;
-    background-color: transparent;
-    border: 0;
-    -webkit-box-shadow: none;
-            box-shadow: none;
-  }
-  .navbar-nav .open .dropdown-menu > li > a,
-  .navbar-nav .open .dropdown-menu .dropdown-header {
-    padding: 5px 15px 5px 25px;
-  }
-  .navbar-nav .open .dropdown-menu > li > a {
-    line-height: 20px;
-  }
-  .navbar-nav .open .dropdown-menu > li > a:hover,
-  .navbar-nav .open .dropdown-menu > li > a:focus {
-    background-image: none;
-  }
-}
-@media (min-width: 768px) {
-  .navbar-nav {
-    float: left;
-    margin: 0;
-  }
-  .navbar-nav > li {
-    float: left;
-  }
-  .navbar-nav > li > a {
-    padding-top: 7.5px;
-    padding-bottom: 7.5px;
-  }
-}
-.navbar-form {
-  padding: 10px 15px;
-  margin-top: .5px;
-  margin-right: -15px;
-  margin-bottom: .5px;
-  margin-left: -15px;
-  border-top: 1px solid transparent;
-  border-bottom: 1px solid transparent;
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
-}
-@media (min-width: 768px) {
-  .navbar-form .form-group {
-    display: inline-block;
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .navbar-form .form-control {
-    display: inline-block;
-    width: auto;
-    vertical-align: middle;
-  }
-  .navbar-form .form-control-static {
-    display: inline-block;
-  }
-  .navbar-form .input-group {
-    display: inline-table;
-    vertical-align: middle;
-  }
-  .navbar-form .input-group .input-group-addon,
-  .navbar-form .input-group .input-group-btn,
-  .navbar-form .input-group .form-control {
-    width: auto;
-  }
-  .navbar-form .input-group > .form-control {
-    width: 100%;
-  }
-  .navbar-form .control-label {
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .navbar-form .radio,
-  .navbar-form .checkbox {
-    display: inline-block;
-    margin-top: 0;
-    margin-bottom: 0;
-    vertical-align: middle;
-  }
-  .navbar-form .radio label,
-  .navbar-form .checkbox label {
-    padding-left: 0;
-  }
-  .navbar-form .radio input[type="radio"],
-  .navbar-form .checkbox input[type="checkbox"] {
-    position: relative;
-    margin-left: 0;
-  }
-  .navbar-form .has-feedback .form-control-feedback {
-    top: 0;
-  }
-}
-@media (max-width: 767px) {
-  .navbar-form .form-group {
-    margin-bottom: 5px;
-  }
-  .navbar-form .form-group:last-child {
-    margin-bottom: 0;
-  }
-}
-@media (min-width: 768px) {
-  .navbar-form {
-    width: auto;
-    padding-top: 0;
-    padding-bottom: 0;
-    margin-right: 0;
-    margin-left: 0;
-    border: 0;
-    -webkit-box-shadow: none;
-            box-shadow: none;
-  }
-}
-.navbar-nav > li > .dropdown-menu {
-  margin-top: 0;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
-  margin-bottom: 0;
-  border-top-left-radius: 4px;
-  border-top-right-radius: 4px;
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.navbar-btn {
-  margin-top: .5px;
-  margin-bottom: .5px;
-}
-.navbar-btn.btn-sm {
-  margin-top: 2.5px;
-  margin-bottom: 2.5px;
-}
-.navbar-btn.btn-xs {
-  margin-top: 6.5px;
-  margin-bottom: 6.5px;
-}
-.navbar-text {
-  margin-top: 7.5px;
-  margin-bottom: 7.5px;
-}
-@media (min-width: 768px) {
-  .navbar-text {
-    float: left;
-    margin-right: 15px;
-    margin-left: 15px;
-  }
-}
-@media (min-width: 768px) {
-  .navbar-left {
-    float: left !important;
-  }
-  .navbar-right {
-    float: right !important;
-    margin-right: -15px;
-  }
-  .navbar-right ~ .navbar-right {
-    margin-right: 0;
-  }
-}
-.navbar-default {
-  background-color: #f8f8f8;
-  border-color: #e7e7e7;
-}
-.navbar-default .navbar-brand {
-  color: #777;
-}
-.navbar-default .navbar-brand:hover,
-.navbar-default .navbar-brand:focus {
-  color: #5e5e5e;
-  background-color: transparent;
-}
-.navbar-default .navbar-text {
-  color: #777;
-}
-.navbar-default .navbar-nav > li > a {
-  color: #777;
-}
-.navbar-default .navbar-nav > li > a:hover,
-.navbar-default .navbar-nav > li > a:focus {
-  color: #333;
-  background-color: transparent;
-}
-.navbar-default .navbar-nav > .active > a,
-.navbar-default .navbar-nav > .active > a:hover,
-.navbar-default .navbar-nav > .active > a:focus {
-  color: #db3279;
-  background-color: #e7e7e7;
-}
-.navbar-default .navbar-nav > .disabled > a,
-.navbar-default .navbar-nav > .disabled > a:hover,
-.navbar-default .navbar-nav > .disabled > a:focus {
-  color: #ccc;
-  background-color: transparent;
-}
-.navbar-default .navbar-toggle {
-  border-color: #ddd;
-}
-.navbar-default .navbar-toggle:hover,
-.navbar-default .navbar-toggle:focus {
-  background-color: #ddd;
-}
-.navbar-default .navbar-toggle .icon-bar {
-  background-color: #888;
-}
-.navbar-default .navbar-collapse,
-.navbar-default .navbar-form {
-  border-color: #e7e7e7;
-}
-.navbar-default .navbar-nav > .open > a,
-.navbar-default .navbar-nav > .open > a:hover,
-.navbar-default .navbar-nav > .open > a:focus {
-  color: #db3279;
-  background-color: #e7e7e7;
-}
-@media (max-width: 767px) {
-  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
-    color: #777;
-  }
-  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
-  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
-    color: #333;
-    background-color: transparent;
-  }
-  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
-  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
-  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
-    color: #db3279;
-    background-color: #e7e7e7;
-  }
-  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
-  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
-  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
-    color: #ccc;
-    background-color: transparent;
-  }
-}
-.navbar-default .navbar-link {
-  color: #777;
-}
-.navbar-default .navbar-link:hover {
-  color: #333;
-}
-.navbar-default .btn-link {
-  color: #777;
-}
-.navbar-default .btn-link:hover,
-.navbar-default .btn-link:focus {
-  color: #333;
-}
-.navbar-default .btn-link[disabled]:hover,
-fieldset[disabled] .navbar-default .btn-link:hover,
-.navbar-default .btn-link[disabled]:focus,
-fieldset[disabled] .navbar-default .btn-link:focus {
-  color: #ccc;
-}
-.navbar-inverse {
-  background-color: #294172;
-  border-color: #1c2c4c;
-}
-.navbar-inverse .navbar-brand {
-  color: #9d9d9d;
-}
-.navbar-inverse .navbar-brand:hover,
-.navbar-inverse .navbar-brand:focus {
-  color: #fff;
-  background-color: transparent;
-}
-.navbar-inverse .navbar-text {
-  color: #777;
-}
-.navbar-inverse .navbar-nav > li > a {
-  color: #9d9d9d;
-}
-.navbar-inverse .navbar-nav > li > a:hover,
-.navbar-inverse .navbar-nav > li > a:focus {
-  color: #fff;
-  background-color: transparent;
-}
-.navbar-inverse .navbar-nav > .active > a,
-.navbar-inverse .navbar-nav > .active > a:hover,
-.navbar-inverse .navbar-nav > .active > a:focus {
-  color: #fff;
-  background-color: #1c2c4c;
-}
-.navbar-inverse .navbar-nav > .disabled > a,
-.navbar-inverse .navbar-nav > .disabled > a:hover,
-.navbar-inverse .navbar-nav > .disabled > a:focus {
-  color: #444;
-  background-color: transparent;
-}
-.navbar-inverse .navbar-toggle {
-  border-color: #333;
-}
-.navbar-inverse .navbar-toggle:hover,
-.navbar-inverse .navbar-toggle:focus {
-  background-color: #333;
-}
-.navbar-inverse .navbar-toggle .icon-bar {
-  background-color: #fff;
-}
-.navbar-inverse .navbar-collapse,
-.navbar-inverse .navbar-form {
-  border-color: #203258;
-}
-.navbar-inverse .navbar-nav > .open > a,
-.navbar-inverse .navbar-nav > .open > a:hover,
-.navbar-inverse .navbar-nav > .open > a:focus {
-  color: #fff;
-  background-color: #1c2c4c;
-}
-@media (max-width: 767px) {
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
-    border-color: #1c2c4c;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
-    background-color: #1c2c4c;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
-    color: #9d9d9d;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
-    color: #fff;
-    background-color: transparent;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
-    color: #fff;
-    background-color: #1c2c4c;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
-    color: #444;
-    background-color: transparent;
-  }
-}
-.navbar-inverse .navbar-link {
-  color: #9d9d9d;
-}
-.navbar-inverse .navbar-link:hover {
-  color: #fff;
-}
-.navbar-inverse .btn-link {
-  color: #9d9d9d;
-}
-.navbar-inverse .btn-link:hover,
-.navbar-inverse .btn-link:focus {
-  color: #fff;
-}
-.navbar-inverse .btn-link[disabled]:hover,
-fieldset[disabled] .navbar-inverse .btn-link:hover,
-.navbar-inverse .btn-link[disabled]:focus,
-fieldset[disabled] .navbar-inverse .btn-link:focus {
-  color: #444;
-}
-.breadcrumb {
-  padding: 8px 15px;
-  margin-bottom: 20px;
-  list-style: none;
-  background-color: #f5f5f5;
-  border-radius: 4px;
-}
-.breadcrumb > li {
-  display: inline-block;
-}
-.breadcrumb > li + li:before {
-  padding: 0 5px;
-  color: #ccc;
-  content: "/\00a0";
-}
-.breadcrumb > .active {
-  color: #777;
-}
-.pagination {
-  display: inline-block;
-  padding-left: 0;
-  margin: 20px 0;
-  border-radius: 4px;
-}
-.pagination > li {
-  display: inline;
-}
-.pagination > li > a,
-.pagination > li > span {
-  position: relative;
-  float: left;
-  padding: 6px 12px;
-  margin-left: -1px;
-  line-height: 1.42857143;
-  color: #428bca;
-  text-decoration: none;
-  background-color: #fff;
-  border: 1px solid #ddd;
-}
-.pagination > li:first-child > a,
-.pagination > li:first-child > span {
-  margin-left: 0;
-  border-top-left-radius: 4px;
-  border-bottom-left-radius: 4px;
-}
-.pagination > li:last-child > a,
-.pagination > li:last-child > span {
-  border-top-right-radius: 4px;
-  border-bottom-right-radius: 4px;
-}
-.pagination > li > a:hover,
-.pagination > li > span:hover,
-.pagination > li > a:focus,
-.pagination > li > span:focus {
-  z-index: 3;
-  color: #2a6496;
-  background-color: #eee;
-  border-color: #ddd;
-}
-.pagination > .active > a,
-.pagination > .active > span,
-.pagination > .active > a:hover,
-.pagination > .active > span:hover,
-.pagination > .active > a:focus,
-.pagination > .active > span:focus {
-  z-index: 2;
-  color: #fff;
-  cursor: default;
-  background-color: #428bca;
-  border-color: #428bca;
-}
-.pagination > .disabled > span,
-.pagination > .disabled > span:hover,
-.pagination > .disabled > span:focus,
-.pagination > .disabled > a,
-.pagination > .disabled > a:hover,
-.pagination > .disabled > a:focus {
-  color: #777;
-  cursor: not-allowed;
-  background-color: #fff;
-  border-color: #ddd;
-}
-.pagination-lg > li > a,
-.pagination-lg > li > span {
-  padding: 10px 16px;
-  font-size: 18px;
-}
-.pagination-lg > li:first-child > a,
-.pagination-lg > li:first-child > span {
-  border-top-left-radius: 6px;
-  border-bottom-left-radius: 6px;
-}
-.pagination-lg > li:last-child > a,
-.pagination-lg > li:last-child > span {
-  border-top-right-radius: 6px;
-  border-bottom-right-radius: 6px;
-}
-.pagination-sm > li > a,
-.pagination-sm > li > span {
-  padding: 5px 10px;
-  font-size: 12px;
-}
-.pagination-sm > li:first-child > a,
-.pagination-sm > li:first-child > span {
-  border-top-left-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.pagination-sm > li:last-child > a,
-.pagination-sm > li:last-child > span {
-  border-top-right-radius: 3px;
-  border-bottom-right-radius: 3px;
-}
-.pager {
-  padding-left: 0;
-  margin: 20px 0;
-  text-align: center;
-  list-style: none;
-}
-.pager li {
-  display: inline;
-}
-.pager li > a,
-.pager li > span {
-  display: inline-block;
-  padding: 5px 14px;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-radius: 15px;
-}
-.pager li > a:hover,
-.pager li > a:focus {
-  text-decoration: none;
-  background-color: #eee;
-}
-.pager .next > a,
-.pager .next > span {
-  float: right;
-}
-.pager .previous > a,
-.pager .previous > span {
-  float: left;
-}
-.pager .disabled > a,
-.pager .disabled > a:hover,
-.pager .disabled > a:focus,
-.pager .disabled > span {
-  color: #777;
-  cursor: not-allowed;
-  background-color: #fff;
-}
-.label {
-  display: inline;
-  padding: .2em .6em .3em;
-  font-size: 75%;
-  font-weight: bold;
-  line-height: 1;
-  color: #fff;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: baseline;
-  border-radius: .25em;
-}
-a.label:hover,
-a.label:focus {
-  color: #fff;
-  text-decoration: none;
-  cursor: pointer;
-}
-.label:empty {
-  display: none;
-}
-.btn .label {
-  position: relative;
-  top: -1px;
-}
-.label-default {
-  background-color: #777;
-}
-.label-default[href]:hover,
-.label-default[href]:focus {
-  background-color: #5e5e5e;
-}
-.label-primary {
-  background-color: #428bca;
-}
-.label-primary[href]:hover,
-.label-primary[href]:focus {
-  background-color: #3071a9;
-}
-.label-success {
-  background-color: #79db32;
-}
-.label-success[href]:hover,
-.label-success[href]:focus {
-  background-color: #61b921;
-}
-.label-info {
-  background-color: #a07cbc;
-}
-.label-info[href]:hover,
-.label-info[href]:focus {
-  background-color: #885aab;
-}
-.label-warning {
-  background-color: #e59728;
-}
-.label-warning[href]:hover,
-.label-warning[href]:focus {
-  background-color: #c27c18;
-}
-.label-danger {
-  background-color: #db3279;
-}
-.label-danger[href]:hover,
-.label-danger[href]:focus {
-  background-color: #b92161;
-}
-.badge {
-  display: inline-block;
-  min-width: 10px;
-  padding: 3px 7px;
-  font-size: 12px;
-  font-weight: bold;
-  line-height: 1;
-  color: #fff;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: baseline;
-  background-color: #777;
-  border-radius: 10px;
-}
-.badge:empty {
-  display: none;
-}
-.btn .badge {
-  position: relative;
-  top: -1px;
-}
-.btn-xs .badge,
-.btn-group-xs > .btn .badge {
-  top: 0;
-  padding: 1px 5px;
-}
-a.badge:hover,
-a.badge:focus {
-  color: #fff;
-  text-decoration: none;
-  cursor: pointer;
-}
-.list-group-item.active > .badge,
-.nav-pills > .active > a > .badge {
-  color: #428bca;
-  background-color: #fff;
-}
-.list-group-item > .badge {
-  float: right;
-}
-.list-group-item > .badge + .badge {
-  margin-right: 5px;
-}
-.nav-pills > li > a > .badge {
-  margin-left: 3px;
-}
-.jumbotron {
-  padding: 30px 15px;
-  margin-bottom: 30px;
-  color: inherit;
-  background-color: #eee;
-}
-.jumbotron h1,
-.jumbotron .h1 {
-  color: inherit;
-}
-.jumbotron p {
-  margin-bottom: 15px;
-  font-size: 21px;
-  font-weight: 200;
-}
-.jumbotron > hr {
-  border-top-color: #d5d5d5;
-}
-.container .jumbotron,
-.container-fluid .jumbotron {
-  border-radius: 6px;
-}
-.jumbotron .container {
-  max-width: 100%;
-}
-@media screen and (min-width: 768px) {
-  .jumbotron {
-    padding: 48px 0;
-  }
-  .container .jumbotron,
-  .container-fluid .jumbotron {
-    padding-right: 60px;
-    padding-left: 60px;
-  }
-  .jumbotron h1,
-  .jumbotron .h1 {
-    font-size: 63px;
-  }
-}
-.thumbnail {
-  display: block;
-  padding: 4px;
-  margin-bottom: 20px;
-  line-height: 1.42857143;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  -webkit-transition: border .2s ease-in-out;
-       -o-transition: border .2s ease-in-out;
-          transition: border .2s ease-in-out;
-}
-.thumbnail > img,
-.thumbnail a > img {
-  margin-right: auto;
-  margin-left: auto;
-}
-a.thumbnail:hover,
-a.thumbnail:focus,
-a.thumbnail.active {
-  border-color: #428bca;
-}
-.thumbnail .caption {
-  padding: 9px;
-  color: #333;
-}
-.alert {
-  padding: 15px;
-  margin-bottom: 20px;
-  border: 1px solid transparent;
-  border-radius: 4px;
-}
-.alert h4 {
-  margin-top: 0;
-  color: inherit;
-}
-.alert .alert-link {
-  font-weight: bold;
-}
-.alert > p,
-.alert > ul {
-  margin-bottom: 0;
-}
-.alert > p + p {
-  margin-top: 5px;
-}
-.alert-dismissable,
-.alert-dismissible {
-  padding-right: 35px;
-}
-.alert-dismissable .close,
-.alert-dismissible .close {
-  position: relative;
-  top: -2px;
-  right: -21px;
-  color: inherit;
-}
-.alert-success {
-  color: #3f7815;
-  background-color: #dcf6ca;
-  border-color: #d8f2b4;
-}
-.alert-success hr {
-  border-top-color: #cdee9e;
-}
-.alert-success .alert-link {
-  color: #284d0e;
-}
-.alert-info {
-  color: #603e7a;
-  background-color: #f6f2f8;
-  border-color: #e7e1f0;
-}
-.alert-info hr {
-  border-top-color: #d9d0e7;
-}
-.alert-info .alert-link {
-  color: #452d58;
-}
-.alert-warning {
-  color: #7e500f;
-  background-color: #f8e4c7;
-  border-color: #f6ceb0;
-}
-.alert-warning hr {
-  border-top-color: #f3bf9a;
-}
-.alert-warning .alert-link {
-  color: #51330a;
-}
-.alert-danger {
-  color: #78153f;
-  background-color: #f6cadc;
-  border-color: #f2b4d8;
-}
-.alert-danger hr {
-  border-top-color: #ee9ecd;
-}
-.alert-danger .alert-link {
-  color: #4d0e28;
-}
-@-webkit-keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-@-o-keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-@keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-.progress {
-  height: 20px;
-  margin-bottom: 20px;
-  overflow: hidden;
-  background-color: #f5f5f5;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
-          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
-}
-.progress-bar {
-  float: left;
-  width: 0;
-  height: 100%;
-  font-size: 12px;
-  line-height: 20px;
-  color: #fff;
-  text-align: center;
-  background-color: #428bca;
-  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
-          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
-  -webkit-transition: width .6s ease;
-       -o-transition: width .6s ease;
-          transition: width .6s ease;
-}
-.progress-striped .progress-bar,
-.progress-bar-striped {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  -webkit-background-size: 40px 40px;
-          background-size: 40px 40px;
-}
-.progress.active .progress-bar,
-.progress-bar.active {
-  -webkit-animation: progress-bar-stripes 2s linear infinite;
-       -o-animation: progress-bar-stripes 2s linear infinite;
-          animation: progress-bar-stripes 2s linear infinite;
-}
-.progress-bar-success {
-  background-color: #79db32;
-}
-.progress-striped .progress-bar-success {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.progress-bar-info {
-  background-color: #a07cbc;
-}
-.progress-striped .progress-bar-info {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.progress-bar-warning {
-  background-color: #e59728;
-}
-.progress-striped .progress-bar-warning {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.progress-bar-danger {
-  background-color: #db3279;
-}
-.progress-striped .progress-bar-danger {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.media {
-  margin-top: 15px;
-}
-.media:first-child {
-  margin-top: 0;
-}
-.media,
-.media-body {
-  overflow: hidden;
-  zoom: 1;
-}
-.media-body {
-  width: 10000px;
-}
-.media-object {
-  display: block;
-}
-.media-right,
-.media > .pull-right {
-  padding-left: 10px;
-}
-.media-left,
-.media > .pull-left {
-  padding-right: 10px;
-}
-.media-left,
-.media-right,
-.media-body {
-  display: table-cell;
-  vertical-align: top;
-}
-.media-middle {
-  vertical-align: middle;
-}
-.media-bottom {
-  vertical-align: bottom;
-}
-.media-heading {
-  margin-top: 0;
-  margin-bottom: 5px;
-}
-.media-list {
-  padding-left: 0;
-  list-style: none;
-}
-.list-group {
-  padding-left: 0;
-  margin-bottom: 20px;
-}
-.list-group-item {
-  position: relative;
-  display: block;
-  padding: 10px 15px;
-  margin-bottom: -1px;
-  background-color: #fff;
-  border: 1px solid #ddd;
-}
-.list-group-item:first-child {
-  border-top-left-radius: 4px;
-  border-top-right-radius: 4px;
-}
-.list-group-item:last-child {
-  margin-bottom: 0;
-  border-bottom-right-radius: 4px;
-  border-bottom-left-radius: 4px;
-}
-a.list-group-item {
-  color: #555;
-}
-a.list-group-item .list-group-item-heading {
-  color: #333;
-}
-a.list-group-item:hover,
-a.list-group-item:focus {
-  color: #555;
-  text-decoration: none;
-  background-color: #f5f5f5;
-}
-.list-group-item.disabled,
-.list-group-item.disabled:hover,
-.list-group-item.disabled:focus {
-  color: #777;
-  cursor: not-allowed;
-  background-color: #eee;
-}
-.list-group-item.disabled .list-group-item-heading,
-.list-group-item.disabled:hover .list-group-item-heading,
-.list-group-item.disabled:focus .list-group-item-heading {
-  color: inherit;
-}
-.list-group-item.disabled .list-group-item-text,
-.list-group-item.disabled:hover .list-group-item-text,
-.list-group-item.disabled:focus .list-group-item-text {
-  color: #777;
-}
-.list-group-item.active,
-.list-group-item.active:hover,
-.list-group-item.active:focus {
-  z-index: 2;
-  color: #fff;
-  background-color: #428bca;
-  border-color: #428bca;
-}
-.list-group-item.active .list-group-item-heading,
-.list-group-item.active:hover .list-group-item-heading,
-.list-group-item.active:focus .list-group-item-heading,
-.list-group-item.active .list-group-item-heading > small,
-.list-group-item.active:hover .list-group-item-heading > small,
-.list-group-item.active:focus .list-group-item-heading > small,
-.list-group-item.active .list-group-item-heading > .small,
-.list-group-item.active:hover .list-group-item-heading > .small,
-.list-group-item.active:focus .list-group-item-heading > .small {
-  color: inherit;
-}
-.list-group-item.active .list-group-item-text,
-.list-group-item.active:hover .list-group-item-text,
-.list-group-item.active:focus .list-group-item-text {
-  color: #e1edf7;
-}
-.list-group-item-success {
-  color: #3f7815;
-  background-color: #dcf6ca;
-}
-a.list-group-item-success {
-  color: #3f7815;
-}
-a.list-group-item-success .list-group-item-heading {
-  color: inherit;
-}
-a.list-group-item-success:hover,
-a.list-group-item-success:focus {
-  color: #3f7815;
-  background-color: #cef2b4;
-}
-a.list-group-item-success.active,
-a.list-group-item-success.active:hover,
-a.list-group-item-success.active:focus {
-  color: #fff;
-  background-color: #3f7815;
-  border-color: #3f7815;
-}
-.list-group-item-info {
-  color: #603e7a;
-  background-color: #f6f2f8;
-}
-a.list-group-item-info {
-  color: #603e7a;
-}
-a.list-group-item-info .list-group-item-heading {
-  color: inherit;
-}
-a.list-group-item-info:hover,
-a.list-group-item-info:focus {
-  color: #603e7a;
-  background-color: #e9e1f0;
-}
-a.list-group-item-info.active,
-a.list-group-item-info.active:hover,
-a.list-group-item-info.active:focus {
-  color: #fff;
-  background-color: #603e7a;
-  border-color: #603e7a;
-}
-.list-group-item-warning {
-  color: #7e500f;
-  background-color: #f8e4c7;
-}
-a.list-group-item-warning {
-  color: #7e500f;
-}
-a.list-group-item-warning .list-group-item-heading {
-  color: inherit;
-}
-a.list-group-item-warning:hover,
-a.list-group-item-warning:focus {
-  color: #7e500f;
-  background-color: #f6d9b0;
-}
-a.list-group-item-warning.active,
-a.list-group-item-warning.active:hover,
-a.list-group-item-warning.active:focus {
-  color: #fff;
-  background-color: #7e500f;
-  border-color: #7e500f;
-}
-.list-group-item-danger {
-  color: #78153f;
-  background-color: #f6cadc;
-}
-a.list-group-item-danger {
-  color: #78153f;
-}
-a.list-group-item-danger .list-group-item-heading {
-  color: inherit;
-}
-a.list-group-item-danger:hover,
-a.list-group-item-danger:focus {
-  color: #78153f;
-  background-color: #f2b4ce;
-}
-a.list-group-item-danger.active,
-a.list-group-item-danger.active:hover,
-a.list-group-item-danger.active:focus {
-  color: #fff;
-  background-color: #78153f;
-  border-color: #78153f;
-}
-.list-group-item-heading {
-  margin-top: 0;
-  margin-bottom: 5px;
-}
-.list-group-item-text {
-  margin-bottom: 0;
-  line-height: 1.3;
-}
-.panel {
-  margin-bottom: 20px;
-  background-color: #fff;
-  border: 1px solid transparent;
-  border-radius: 4px;
-  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
-          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
-}
-.panel-body {
-  padding: 15px;
-}
-.panel-heading {
-  padding: 10px 15px;
-  border-bottom: 1px solid transparent;
-  border-top-left-radius: 3px;
-  border-top-right-radius: 3px;
-}
-.panel-heading > .dropdown .dropdown-toggle {
-  color: inherit;
-}
-.panel-title {
-  margin-top: 0;
-  margin-bottom: 0;
-  font-size: 16px;
-  color: inherit;
-}
-.panel-title > a,
-.panel-title > small,
-.panel-title > .small,
-.panel-title > small > a,
-.panel-title > .small > a {
-  color: inherit;
-}
-.panel-footer {
-  padding: 10px 15px;
-  background-color: #f5f5f5;
-  border-top: 1px solid #ddd;
-  border-bottom-right-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.panel > .list-group,
-.panel > .panel-collapse > .list-group {
-  margin-bottom: 0;
-}
-.panel > .list-group .list-group-item,
-.panel > .panel-collapse > .list-group .list-group-item {
-  border-width: 1px 0;
-  border-radius: 0;
-}
-.panel > .list-group:first-child .list-group-item:first-child,
-.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
-  border-top: 0;
-  border-top-left-radius: 3px;
-  border-top-right-radius: 3px;
-}
-.panel > .list-group:last-child .list-group-item:last-child,
-.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
-  border-bottom: 0;
-  border-bottom-right-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.panel-heading + .list-group .list-group-item:first-child {
-  border-top-width: 0;
-}
-.list-group + .panel-footer {
-  border-top-width: 0;
-}
-.panel > .table,
-.panel > .table-responsive > .table,
-.panel > .panel-collapse > .table {
-  margin-bottom: 0;
-}
-.panel > .table caption,
-.panel > .table-responsive > .table caption,
-.panel > .panel-collapse > .table caption {
-  padding-right: 15px;
-  padding-left: 15px;
-}
-.panel > .table:first-child,
-.panel > .table-responsive:first-child > .table:first-child {
-  border-top-left-radius: 3px;
-  border-top-right-radius: 3px;
-}
-.panel > .table:first-child > thead:first-child > tr:first-child,
-.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
-.panel > .table:first-child > tbody:first-child > tr:first-child,
-.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
-  border-top-left-radius: 3px;
-  border-top-right-radius: 3px;
-}
-.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
-.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
-.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
-.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
-.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
-.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
-.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
-.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
-  border-top-left-radius: 3px;
-}
-.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
-.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
-.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
-.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
-.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
-.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
-.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
-.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
-  border-top-right-radius: 3px;
-}
-.panel > .table:last-child,
-.panel > .table-responsive:last-child > .table:last-child {
-  border-bottom-right-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.panel > .table:last-child > tbody:last-child > tr:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
-.panel > .table:last-child > tfoot:last-child > tr:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
-  border-bottom-right-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
-.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
-.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
-.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
-.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
-.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
-.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
-.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
-  border-bottom-left-radius: 3px;
-}
-.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
-.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
-.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
-.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
-.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
-  border-bottom-right-radius: 3px;
-}
-.panel > .panel-body + .table,
-.panel > .panel-body + .table-responsive,
-.panel > .table + .panel-body,
-.panel > .table-responsive + .panel-body {
-  border-top: 1px solid #ddd;
-}
-.panel > .table > tbody:first-child > tr:first-child th,
-.panel > .table > tbody:first-child > tr:first-child td {
-  border-top: 0;
-}
-.panel > .table-bordered,
-.panel > .table-responsive > .table-bordered {
-  border: 0;
-}
-.panel > .table-bordered > thead > tr > th:first-child,
-.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
-.panel > .table-bordered > tbody > tr > th:first-child,
-.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
-.panel > .table-bordered > tfoot > tr > th:first-child,
-.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
-.panel > .table-bordered > thead > tr > td:first-child,
-.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
-.panel > .table-bordered > tbody > tr > td:first-child,
-.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
-.panel > .table-bordered > tfoot > tr > td:first-child,
-.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
-  border-left: 0;
-}
-.panel > .table-bordered > thead > tr > th:last-child,
-.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
-.panel > .table-bordered > tbody > tr > th:last-child,
-.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
-.panel > .table-bordered > tfoot > tr > th:last-child,
-.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
-.panel > .table-bordered > thead > tr > td:last-child,
-.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
-.panel > .table-bordered > tbody > tr > td:last-child,
-.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
-.panel > .table-bordered > tfoot > tr > td:last-child,
-.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
-  border-right: 0;
-}
-.panel > .table-bordered > thead > tr:first-child > td,
-.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
-.panel > .table-bordered > tbody > tr:first-child > td,
-.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
-.panel > .table-bordered > thead > tr:first-child > th,
-.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
-.panel > .table-bordered > tbody > tr:first-child > th,
-.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
-  border-bottom: 0;
-}
-.panel > .table-bordered > tbody > tr:last-child > td,
-.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
-.panel > .table-bordered > tfoot > tr:last-child > td,
-.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
-.panel > .table-bordered > tbody > tr:last-child > th,
-.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
-.panel > .table-bordered > tfoot > tr:last-child > th,
-.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
-  border-bottom: 0;
-}
-.panel > .table-responsive {
-  margin-bottom: 0;
-  border: 0;
-}
-.panel-group {
-  margin-bottom: 20px;
-}
-.panel-group .panel {
-  margin-bottom: 0;
-  border-radius: 4px;
-}
-.panel-group .panel + .panel {
-  margin-top: 5px;
-}
-.panel-group .panel-heading {
-  border-bottom: 0;
-}
-.panel-group .panel-heading + .panel-collapse > .panel-body,
-.panel-group .panel-heading + .panel-collapse > .list-group {
-  border-top: 1px solid #ddd;
-}
-.panel-group .panel-footer {
-  border-top: 0;
-}
-.panel-group .panel-footer + .panel-collapse .panel-body {
-  border-bottom: 1px solid #ddd;
-}
-.panel-default {
-  border-color: #ddd;
-}
-.panel-default > .panel-heading {
-  color: #333;
-  background-color: #f5f5f5;
-  border-color: #ddd;
-}
-.panel-default > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #ddd;
-}
-.panel-default > .panel-heading .badge {
-  color: #f5f5f5;
-  background-color: #333;
-}
-.panel-default > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #ddd;
-}
-.panel-primary {
-  border-color: #428bca;
-}
-.panel-primary > .panel-heading {
-  color: #fff;
-  background-color: #428bca;
-  border-color: #428bca;
-}
-.panel-primary > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #428bca;
-}
-.panel-primary > .panel-heading .badge {
-  color: #428bca;
-  background-color: #fff;
-}
-.panel-primary > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #428bca;
-}
-.panel-success {
-  border-color: #d8f2b4;
-}
-.panel-success > .panel-heading {
-  color: #3f7815;
-  background-color: #dcf6ca;
-  border-color: #d8f2b4;
-}
-.panel-success > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #d8f2b4;
-}
-.panel-success > .panel-heading .badge {
-  color: #dcf6ca;
-  background-color: #3f7815;
-}
-.panel-success > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #d8f2b4;
-}
-.panel-info {
-  border-color: #e7e1f0;
-}
-.panel-info > .panel-heading {
-  color: #603e7a;
-  background-color: #f6f2f8;
-  border-color: #e7e1f0;
-}
-.panel-info > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #e7e1f0;
-}
-.panel-info > .panel-heading .badge {
-  color: #f6f2f8;
-  background-color: #603e7a;
-}
-.panel-info > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #e7e1f0;
-}
-.panel-warning {
-  border-color: #f6ceb0;
-}
-.panel-warning > .panel-heading {
-  color: #7e500f;
-  background-color: #f8e4c7;
-  border-color: #f6ceb0;
-}
-.panel-warning > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #f6ceb0;
-}
-.panel-warning > .panel-heading .badge {
-  color: #f8e4c7;
-  background-color: #7e500f;
-}
-.panel-warning > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #f6ceb0;
-}
-.panel-danger {
-  border-color: #f2b4d8;
-}
-.panel-danger > .panel-heading {
-  color: #78153f;
-  background-color: #f6cadc;
-  border-color: #f2b4d8;
-}
-.panel-danger > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #f2b4d8;
-}
-.panel-danger > .panel-heading .badge {
-  color: #f6cadc;
-  background-color: #78153f;
-}
-.panel-danger > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #f2b4d8;
-}
-.embed-responsive {
-  position: relative;
-  display: block;
-  height: 0;
-  padding: 0;
-  overflow: hidden;
-}
-.embed-responsive .embed-responsive-item,
-.embed-responsive iframe,
-.embed-responsive embed,
-.embed-responsive object,
-.embed-responsive video {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  border: 0;
-}
-.embed-responsive-16by9 {
-  padding-bottom: 56.25%;
-}
-.embed-responsive-4by3 {
-  padding-bottom: 75%;
-}
-.well {
-  min-height: 20px;
-  padding: 19px;
-  margin-bottom: 20px;
-  background-color: #f5f5f5;
-  border: 1px solid #e3e3e3;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
-}
-.well blockquote {
-  border-color: #ddd;
-  border-color: rgba(0, 0, 0, .15);
-}
-.well-lg {
-  padding: 24px;
-  border-radius: 6px;
-}
-.well-sm {
-  padding: 9px;
-  border-radius: 3px;
-}
-.close {
-  float: right;
-  font-size: 21px;
-  font-weight: bold;
-  line-height: 1;
-  color: #000;
-  text-shadow: 0 1px 0 #fff;
-  filter: alpha(opacity=20);
-  opacity: .2;
-}
-.close:hover,
-.close:focus {
-  color: #000;
-  text-decoration: none;
-  cursor: pointer;
-  filter: alpha(opacity=50);
-  opacity: .5;
-}
-button.close {
-  -webkit-appearance: none;
-  padding: 0;
-  cursor: pointer;
-  background: transparent;
-  border: 0;
-}
-.modal-open {
-  overflow: hidden;
-}
-.modal {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 1050;
-  display: none;
-  overflow: hidden;
-  -webkit-overflow-scrolling: touch;
-  outline: 0;
-}
-.modal.fade .modal-dialog {
-  -webkit-transition: -webkit-transform .3s ease-out;
-       -o-transition:      -o-transform .3s ease-out;
-          transition:         transform .3s ease-out;
-  -webkit-transform: translate(0, -25%);
-      -ms-transform: translate(0, -25%);
-       -o-transform: translate(0, -25%);
-          transform: translate(0, -25%);
-}
-.modal.in .modal-dialog {
-  -webkit-transform: translate(0, 0);
-      -ms-transform: translate(0, 0);
-       -o-transform: translate(0, 0);
-          transform: translate(0, 0);
-}
-.modal-open .modal {
-  overflow-x: hidden;
-  overflow-y: auto;
-}
-.modal-dialog {
-  position: relative;
-  width: auto;
-  margin: 10px;
-}
-.modal-content {
-  position: relative;
-  background-color: #fff;
-  -webkit-background-clip: padding-box;
-          background-clip: padding-box;
-  border: 1px solid #999;
-  border: 1px solid rgba(0, 0, 0, .2);
-  border-radius: 6px;
-  outline: 0;
-  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
-          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
-}
-.modal-backdrop {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 1040;
-  background-color: #000;
-}
-.modal-backdrop.fade {
-  filter: alpha(opacity=0);
-  opacity: 0;
-}
-.modal-backdrop.in {
-  filter: alpha(opacity=50);
-  opacity: .5;
-}
-.modal-header {
-  min-height: 16.42857143px;
-  padding: 15px;
-  border-bottom: 1px solid #e5e5e5;
-}
-.modal-header .close {
-  margin-top: -2px;
-}
-.modal-title {
-  margin: 0;
-  line-height: 1.42857143;
-}
-.modal-body {
-  position: relative;
-  padding: 15px;
-}
-.modal-footer {
-  padding: 15px;
-  text-align: right;
-  border-top: 1px solid #e5e5e5;
-}
-.modal-footer .btn + .btn {
-  margin-bottom: 0;
-  margin-left: 5px;
-}
-.modal-footer .btn-group .btn + .btn {
-  margin-left: -1px;
-}
-.modal-footer .btn-block + .btn-block {
-  margin-left: 0;
-}
-.modal-scrollbar-measure {
-  position: absolute;
-  top: -9999px;
-  width: 50px;
-  height: 50px;
-  overflow: scroll;
-}
-@media (min-width: 768px) {
-  .modal-dialog {
-    width: 600px;
-    margin: 30px auto;
-  }
-  .modal-content {
-    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
-            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
-  }
-  .modal-sm {
-    width: 300px;
-  }
-}
-@media (min-width: 992px) {
-  .modal-lg {
-    width: 900px;
-  }
-}
-.tooltip {
-  position: absolute;
-  z-index: 1070;
-  display: block;
-  font-family: Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 12px;
-  font-style: normal;
-  font-weight: normal;
-  line-height: 1.42857143;
-  text-align: left;
-  text-align: start;
-  text-decoration: none;
-  text-shadow: none;
-  text-transform: none;
-  letter-spacing: normal;
-  word-break: normal;
-  word-spacing: normal;
-  word-wrap: normal;
-  white-space: normal;
-  filter: alpha(opacity=0);
-  opacity: 0;
-
-  line-break: auto;
-}
-.tooltip.in {
-  filter: alpha(opacity=90);
-  opacity: .9;
-}
-.tooltip.top {
-  padding: 5px 0;
-  margin-top: -3px;
-}
-.tooltip.right {
-  padding: 0 5px;
-  margin-left: 3px;
-}
-.tooltip.bottom {
-  padding: 5px 0;
-  margin-top: 3px;
-}
-.tooltip.left {
-  padding: 0 5px;
-  margin-left: -3px;
-}
-.tooltip-inner {
-  max-width: 200px;
-  padding: 3px 8px;
-  color: #fff;
-  text-align: center;
-  background-color: #000;
-  border-radius: 4px;
-}
-.tooltip-arrow {
-  position: absolute;
-  width: 0;
-  height: 0;
-  border-color: transparent;
-  border-style: solid;
-}
-.tooltip.top .tooltip-arrow {
-  bottom: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-width: 5px 5px 0;
-  border-top-color: #000;
-}
-.tooltip.top-left .tooltip-arrow {
-  right: 5px;
-  bottom: 0;
-  margin-bottom: -5px;
-  border-width: 5px 5px 0;
-  border-top-color: #000;
-}
-.tooltip.top-right .tooltip-arrow {
-  bottom: 0;
-  left: 5px;
-  margin-bottom: -5px;
-  border-width: 5px 5px 0;
-  border-top-color: #000;
-}
-.tooltip.right .tooltip-arrow {
-  top: 50%;
-  left: 0;
-  margin-top: -5px;
-  border-width: 5px 5px 5px 0;
-  border-right-color: #000;
-}
-.tooltip.left .tooltip-arrow {
-  top: 50%;
-  right: 0;
-  margin-top: -5px;
-  border-width: 5px 0 5px 5px;
-  border-left-color: #000;
-}
-.tooltip.bottom .tooltip-arrow {
-  top: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-width: 0 5px 5px;
-  border-bottom-color: #000;
-}
-.tooltip.bottom-left .tooltip-arrow {
-  top: 0;
-  right: 5px;
-  margin-top: -5px;
-  border-width: 0 5px 5px;
-  border-bottom-color: #000;
-}
-.tooltip.bottom-right .tooltip-arrow {
-  top: 0;
-  left: 5px;
-  margin-top: -5px;
-  border-width: 0 5px 5px;
-  border-bottom-color: #000;
-}
-.popover {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1060;
-  display: none;
-  max-width: 276px;
-  padding: 1px;
-  font-family: Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 14px;
-  font-style: normal;
-  font-weight: normal;
-  line-height: 1.42857143;
-  text-align: left;
-  text-align: start;
-  text-decoration: none;
-  text-shadow: none;
-  text-transform: none;
-  letter-spacing: normal;
-  word-break: normal;
-  word-spacing: normal;
-  word-wrap: normal;
-  white-space: normal;
-  background-color: #fff;
-  -webkit-background-clip: padding-box;
-          background-clip: padding-box;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, .2);
-  border-radius: 6px;
-  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
-          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
-
-  line-break: auto;
-}
-.popover.top {
-  margin-top: -10px;
-}
-.popover.right {
-  margin-left: 10px;
-}
-.popover.bottom {
-  margin-top: 10px;
-}
-.popover.left {
-  margin-left: -10px;
-}
-.popover-title {
-  padding: 8px 14px;
-  margin: 0;
-  font-size: 14px;
-  background-color: #f7f7f7;
-  border-bottom: 1px solid #ebebeb;
-  border-radius: 5px 5px 0 0;
-}
-.popover-content {
-  padding: 9px 14px;
-}
-.popover > .arrow,
-.popover > .arrow:after {
-  position: absolute;
-  display: block;
-  width: 0;
-  height: 0;
-  border-color: transparent;
-  border-style: solid;
-}
-.popover > .arrow {
-  border-width: 11px;
-}
-.popover > .arrow:after {
-  content: "";
-  border-width: 10px;
-}
-.popover.top > .arrow {
-  bottom: -11px;
-  left: 50%;
-  margin-left: -11px;
-  border-top-color: #999;
-  border-top-color: rgba(0, 0, 0, .25);
-  border-bottom-width: 0;
-}
-.popover.top > .arrow:after {
-  bottom: 1px;
-  margin-left: -10px;
-  content: " ";
-  border-top-color: #fff;
-  border-bottom-width: 0;
-}
-.popover.right > .arrow {
-  top: 50%;
-  left: -11px;
-  margin-top: -11px;
-  border-right-color: #999;
-  border-right-color: rgba(0, 0, 0, .25);
-  border-left-width: 0;
-}
-.popover.right > .arrow:after {
-  bottom: -10px;
-  left: 1px;
-  content: " ";
-  border-right-color: #fff;
-  border-left-width: 0;
-}
-.popover.bottom > .arrow {
-  top: -11px;
-  left: 50%;
-  margin-left: -11px;
-  border-top-width: 0;
-  border-bottom-color: #999;
-  border-bottom-color: rgba(0, 0, 0, .25);
-}
-.popover.bottom > .arrow:after {
-  top: 1px;
-  margin-left: -10px;
-  content: " ";
-  border-top-width: 0;
-  border-bottom-color: #fff;
-}
-.popover.left > .arrow {
-  top: 50%;
-  right: -11px;
-  margin-top: -11px;
-  border-right-width: 0;
-  border-left-color: #999;
-  border-left-color: rgba(0, 0, 0, .25);
-}
-.popover.left > .arrow:after {
-  right: 1px;
-  bottom: -10px;
-  content: " ";
-  border-right-width: 0;
-  border-left-color: #fff;
-}
-.carousel {
-  position: relative;
-}
-.carousel-inner {
-  position: relative;
-  width: 100%;
-  overflow: hidden;
-}
-.carousel-inner > .item {
-  position: relative;
-  display: none;
-  -webkit-transition: .6s ease-in-out left;
-       -o-transition: .6s ease-in-out left;
-          transition: .6s ease-in-out left;
-}
-.carousel-inner > .item > img,
-.carousel-inner > .item > a > img {
-  line-height: 1;
-}
-@media all and (transform-3d), (-webkit-transform-3d) {
-  .carousel-inner > .item {
-    -webkit-transition: -webkit-transform .6s ease-in-out;
-         -o-transition:      -o-transform .6s ease-in-out;
-            transition:         transform .6s ease-in-out;
-
-    -webkit-backface-visibility: hidden;
-            backface-visibility: hidden;
-    -webkit-perspective: 1000px;
-            perspective: 1000px;
-  }
-  .carousel-inner > .item.next,
-  .carousel-inner > .item.active.right {
-    left: 0;
-    -webkit-transform: translate3d(100%, 0, 0);
-            transform: translate3d(100%, 0, 0);
-  }
-  .carousel-inner > .item.prev,
-  .carousel-inner > .item.active.left {
-    left: 0;
-    -webkit-transform: translate3d(-100%, 0, 0);
-            transform: translate3d(-100%, 0, 0);
-  }
-  .carousel-inner > .item.next.left,
-  .carousel-inner > .item.prev.right,
-  .carousel-inner > .item.active {
-    left: 0;
-    -webkit-transform: translate3d(0, 0, 0);
-            transform: translate3d(0, 0, 0);
-  }
-}
-.carousel-inner > .active,
-.carousel-inner > .next,
-.carousel-inner > .prev {
-  display: block;
-}
-.carousel-inner > .active {
-  left: 0;
-}
-.carousel-inner > .next,
-.carousel-inner > .prev {
-  position: absolute;
-  top: 0;
-  width: 100%;
-}
-.carousel-inner > .next {
-  left: 100%;
-}
-.carousel-inner > .prev {
-  left: -100%;
-}
-.carousel-inner > .next.left,
-.carousel-inner > .prev.right {
-  left: 0;
-}
-.carousel-inner > .active.left {
-  left: -100%;
-}
-.carousel-inner > .active.right {
-  left: 100%;
-}
-.carousel-control {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  left: 0;
-  width: 15%;
-  font-size: 20px;
-  color: #fff;
-  text-align: center;
-  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
-  filter: alpha(opacity=50);
-  opacity: .5;
-}
-.carousel-control.left {
-  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
-  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
-  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));
-  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
-  background-repeat: repeat-x;
-}
-.carousel-control.right {
-  right: 0;
-  left: auto;
-  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
-  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
-  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));
-  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
-  background-repeat: repeat-x;
-}
-.carousel-control:hover,
-.carousel-control:focus {
-  color: #fff;
-  text-decoration: none;
-  filter: alpha(opacity=90);
-  outline: 0;
-  opacity: .9;
-}
-.carousel-control .icon-prev,
-.carousel-control .icon-next,
-.carousel-control .glyphicon-chevron-left,
-.carousel-control .glyphicon-chevron-right {
-  position: absolute;
-  top: 50%;
-  z-index: 5;
-  display: inline-block;
-}
-.carousel-control .icon-prev,
-.carousel-control .glyphicon-chevron-left {
-  left: 50%;
-  margin-left: -10px;
-}
-.carousel-control .icon-next,
-.carousel-control .glyphicon-chevron-right {
-  right: 50%;
-  margin-right: -10px;
-}
-.carousel-control .icon-prev,
-.carousel-control .icon-next {
-  width: 20px;
-  height: 20px;
-  margin-top: -10px;
-  font-family: serif;
-  line-height: 1;
-}
-.carousel-control .icon-prev:before {
-  content: '\2039';
-}
-.carousel-control .icon-next:before {
-  content: '\203a';
-}
-.carousel-indicators {
-  position: absolute;
-  bottom: 10px;
-  left: 50%;
-  z-index: 15;
-  width: 60%;
-  padding-left: 0;
-  margin-left: -30%;
-  text-align: center;
-  list-style: none;
-}
-.carousel-indicators li {
-  display: inline-block;
-  width: 10px;
-  height: 10px;
-  margin: 1px;
-  text-indent: -999px;
-  cursor: pointer;
-  background-color: #000 \9;
-  background-color: rgba(0, 0, 0, 0);
-  border: 1px solid #fff;
-  border-radius: 10px;
-}
-.carousel-indicators .active {
-  width: 12px;
-  height: 12px;
-  margin: 0;
-  background-color: #fff;
-}
-.carousel-caption {
-  position: absolute;
-  right: 15%;
-  bottom: 20px;
-  left: 15%;
-  z-index: 10;
-  padding-top: 20px;
-  padding-bottom: 20px;
-  color: #fff;
-  text-align: center;
-  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
-}
-.carousel-caption .btn {
-  text-shadow: none;
-}
-@media screen and (min-width: 768px) {
-  .carousel-control .glyphicon-chevron-left,
-  .carousel-control .glyphicon-chevron-right,
-  .carousel-control .icon-prev,
-  .carousel-control .icon-next {
-    width: 30px;
-    height: 30px;
-    margin-top: -15px;
-    font-size: 30px;
-  }
-  .carousel-control .glyphicon-chevron-left,
-  .carousel-control .icon-prev {
-    margin-left: -15px;
-  }
-  .carousel-control .glyphicon-chevron-right,
-  .carousel-control .icon-next {
-    margin-right: -15px;
-  }
-  .carousel-caption {
-    right: 20%;
-    left: 20%;
-    padding-bottom: 30px;
-  }
-  .carousel-indicators {
-    bottom: 20px;
-  }
-}
-.clearfix:before,
-.clearfix:after,
-.dl-horizontal dd:before,
-.dl-horizontal dd:after,
-.container:before,
-.container:after,
-.container-fluid:before,
-.container-fluid:after,
-.row:before,
-.row:after,
-.form-horizontal .form-group:before,
-.form-horizontal .form-group:after,
-.btn-toolbar:before,
-.btn-toolbar:after,
-.btn-group-vertical > .btn-group:before,
-.btn-group-vertical > .btn-group:after,
-.nav:before,
-.nav:after,
-.navbar:before,
-.navbar:after,
-.navbar-header:before,
-.navbar-header:after,
-.navbar-collapse:before,
-.navbar-collapse:after,
-.pager:before,
-.pager:after,
-.panel-body:before,
-.panel-body:after,
-.modal-footer:before,
-.modal-footer:after {
-  display: table;
-  content: " ";
-}
-.clearfix:after,
-.dl-horizontal dd:after,
-.container:after,
-.container-fluid:after,
-.row:after,
-.form-horizontal .form-group:after,
-.btn-toolbar:after,
-.btn-group-vertical > .btn-group:after,
-.nav:after,
-.navbar:after,
-.navbar-header:after,
-.navbar-collapse:after,
-.pager:after,
-.panel-body:after,
-.modal-footer:after {
-  clear: both;
-}
-.center-block {
-  display: block;
-  margin-right: auto;
-  margin-left: auto;
-}
-.pull-right {
-  float: right !important;
-}
-.pull-left {
-  float: left !important;
-}
-.hide {
-  display: none !important;
-}
-.show {
-  display: block !important;
-}
-.invisible {
-  visibility: hidden;
-}
-.text-hide {
-  font: 0/0 a;
-  color: transparent;
-  text-shadow: none;
-  background-color: transparent;
-  border: 0;
-}
-.hidden {
-  display: none !important;
-}
-.affix {
-  position: fixed;
-}
-@-ms-viewport {
-  width: device-width;
-}
-.visible-xs,
-.visible-sm,
-.visible-md,
-.visible-lg {
-  display: none !important;
-}
-.visible-xs-block,
-.visible-xs-inline,
-.visible-xs-inline-block,
-.visible-sm-block,
-.visible-sm-inline,
-.visible-sm-inline-block,
-.visible-md-block,
-.visible-md-inline,
-.visible-md-inline-block,
-.visible-lg-block,
-.visible-lg-inline,
-.visible-lg-inline-block {
-  display: none !important;
-}
-@media (max-width: 767px) {
-  .visible-xs {
-    display: block !important;
-  }
-  table.visible-xs {
-    display: table !important;
-  }
-  tr.visible-xs {
-    display: table-row !important;
-  }
-  th.visible-xs,
-  td.visible-xs {
-    display: table-cell !important;
-  }
-}
-@media (max-width: 767px) {
-  .visible-xs-block {
-    display: block !important;
-  }
-}
-@media (max-width: 767px) {
-  .visible-xs-inline {
-    display: inline !important;
-  }
-}
-@media (max-width: 767px) {
-  .visible-xs-inline-block {
-    display: inline-block !important;
-  }
-}
-@media (min-width: 768px) and (max-width: 991px) {
-  .visible-sm {
-    display: block !important;
-  }
-  table.visible-sm {
-    display: table !important;
-  }
-  tr.visible-sm {
-    display: table-row !important;
-  }
-  th.visible-sm,
-  td.visible-sm {
-    display: table-cell !important;
-  }
-}
-@media (min-width: 768px) and (max-width: 991px) {
-  .visible-sm-block {
-    display: block !important;
-  }
-}
-@media (min-width: 768px) and (max-width: 991px) {
-  .visible-sm-inline {
-    display: inline !important;
-  }
-}
-@media (min-width: 768px) and (max-width: 991px) {
-  .visible-sm-inline-block {
-    display: inline-block !important;
-  }
-}
-@media (min-width: 992px) and (max-width: 1199px) {
-  .visible-md {
-    display: block !important;
-  }
-  table.visible-md {
-    display: table !important;
-  }
-  tr.visible-md {
-    display: table-row !important;
-  }
-  th.visible-md,
-  td.visible-md {
-    display: table-cell !important;
-  }
-}
-@media (min-width: 992px) and (max-width: 1199px) {
-  .visible-md-block {
-    display: block !important;
-  }
-}
-@media (min-width: 992px) and (max-width: 1199px) {
-  .visible-md-inline {
-    display: inline !important;
-  }
-}
-@media (min-width: 992px) and (max-width: 1199px) {
-  .visible-md-inline-block {
-    display: inline-block !important;
-  }
-}
-@media (min-width: 1200px) {
-  .visible-lg {
-    display: block !important;
-  }
-  table.visible-lg {
-    display: table !important;
-  }
-  tr.visible-lg {
-    display: table-row !important;
-  }
-  th.visible-lg,
-  td.visible-lg {
-    display: table-cell !important;
-  }
-}
-@media (min-width: 1200px) {
-  .visible-lg-block {
-    display: block !important;
-  }
-}
-@media (min-width: 1200px) {
-  .visible-lg-inline {
-    display: inline !important;
-  }
-}
-@media (min-width: 1200px) {
-  .visible-lg-inline-block {
-    display: inline-block !important;
-  }
-}
-@media (max-width: 767px) {
-  .hidden-xs {
-    display: none !important;
-  }
-}
-@media (min-width: 768px) and (max-width: 991px) {
-  .hidden-sm {
-    display: none !important;
-  }
-}
-@media (min-width: 992px) and (max-width: 1199px) {
-  .hidden-md {
-    display: none !important;
-  }
-}
-@media (min-width: 1200px) {
-  .hidden-lg {
-    display: none !important;
-  }
-}
-.visible-print {
-  display: none !important;
-}
-@media print {
-  .visible-print {
-    display: block !important;
-  }
-  table.visible-print {
-    display: table !important;
-  }
-  tr.visible-print {
-    display: table-row !important;
-  }
-  th.visible-print,
-  td.visible-print {
-    display: table-cell !important;
-  }
-}
-.visible-print-block {
-  display: none !important;
-}
-@media print {
-  .visible-print-block {
-    display: block !important;
-  }
-}
-.visible-print-inline {
-  display: none !important;
-}
-@media print {
-  .visible-print-inline {
-    display: inline !important;
-  }
-}
-.visible-print-inline-block {
-  display: none !important;
-}
-@media print {
-  .visible-print-inline-block {
-    display: inline-block !important;
-  }
-}
-@media print {
-  .hidden-print {
-    display: none !important;
-  }
-}
-/*# sourceMappingURL=bootstrap.css.map */
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css.map b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css.map
deleted file mode 100644
index 5683d20..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["bootstrap.css","less/normalize.less","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/mixins/reset-text.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"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kBAAA;EHiR9C;AGhRmC;EAAW,kBAAA;EHmR9C;AGlRmC;EAAW,kBAAA;EHqR9C;AGpRmC;EAAW,kBAAA;EHuR9C;AGtRmC;EAAW,kBAAA;EHyR9C;AGxRmC;EAAW,kBAAA;EH2R9C;AG1RmC;EAAW,kBAAA;EH6R9C;AG5RmC;EAAW,kBAAA;EH+R9C;AG9RmC;EAAW,kBAAA;EHiS9C;AGhSmC;EAAW,kBAAA;EHmS9C;AGlSmC;EAAW,kBAAA;EHqS9C;AGpSmC;EAAW,kBAAA;EHuS9C;AGtSmC;EAAW,kBAAA;EHyS9C;AGxSmC;EAAW,kBAAA;EH2S9C;AG1SmC;EAAW,kBAAA;EH6S9C;AG5SmC;EAAW,kBAAA;EH+S9C;AG9SmC;EAAW,kBAAA;EHiT9C;AGhTmC;EAAW,kBAAA;EHmT9C;AGlTmC;EAAW,kBAAA;EHqT9C;AGpTmC;EAAW,kBAAA;EHuT9C;AGtTmC;EAAW,kBAAA;EHyT9C;AGxTmC;EAAW,kBAAA;EH2T9C;AG1TmC;EAAW,kBAAA;EH6T9C;AG5TmC;EAAW,kBAAA;EH+T9C;AG9TmC;EAAW,kBAAA;EHiU9C;AGhUmC;EAAW,kBAAA;EHmU9C;AGlUmC;EAAW,kBAAA;EHqU9C;AGpUmC;EAAW,kBAAA;EHuU9C;AGtUmC;EAAW,kBAAA;EHyU9C;AGxUmC;EAAW,kBAAA;EH2U9C;AG1UmC;EAAW,kBAAA;EH6U9C;AG5UmC;EAAW,kBAAA;EH+U9C;AG9UmC;EAAW,kBAAA;EHiV9C;AGhVmC;EAAW,kBAAA;EHmV9C;AGlVmC;EAAW,kBAAA;EHqV9C;AGpVmC;EAAW,kBAAA;EHuV9C;AGtVmC;EAAW,kBAAA;EHyV9C;AGxVmC;EAAW,kBAAA;EH2V9C;AG1VmC;EAAW,kBAAA;EH6V9C;AG5VmC;EAAW,kBAAA;EH+V9C;AG9VmC;EAAW,kBAAA;EHiW9C;AGhWmC;EAAW,kBAAA;EHmW9C;AGlWmC;EAAW,kBAAA;EHqW9C;AGpWmC;EAAW,kBAAA;EHuW9C;AGtWmC;EAAW,kBAAA;EHyW9C;AGxWmC;EAAW,kBAAA;EH2W9C;AG1WmC;EAAW,kBAAA;EH6W9C;AG5WmC;EAAW,kBAAA;EH+W9C;AG9WmC;EAAW,kBAAA;EHiX9C;AGhXmC;EAAW,kBAAA;EHmX9C;AGlXmC;EAAW,kBAAA;EHqX9C;AGpXmC;EAAW,kBAAA;EHuX9C;AGtXmC;EAAW,kBAAA;EHyX9C;AGxXmC;EAAW,kBAAA;EH2X9C;AG1XmC;EAAW,kBAAA;EH6X9C;AG5XmC;EAAW,kBAAA;EH+X9C;AG9XmC;EAAW,kBAAA;EHiY9C;AGhYmC;EAAW,kBAAA;EHmY9C;AGlYmC;EAAW,kBAAA;EHqY9C;AGpYmC;EAAW,kBAAA;EHuY9C;AGtYmC;EAAW,kBAAA;EHyY9C;AGxYmC;EAAW,kBAAA;EH2Y9C;AG1YmC;EAAW,kBAAA;EH6Y9C;AG5YmC;EAAW,kBAAA;EH+Y9C;AG9YmC;EAAW,kBAAA;EHiZ9C;AGhZmC;EAAW,kBAAA;EHmZ9C;AGlZmC;EAAW,kBAAA;EHqZ9C;AGpZmC;EAAW,kBAAA;EHuZ9C;AGtZmC;EAAW,kBAAA;EHyZ9C;AGxZmC;EAAW,kBAAA;EH2Z9C;AG1ZmC;EAAW,kBAAA;EH6Z9C;AG5ZmC;EAAW,kBAAA;EH+Z9C;AG9ZmC;EAAW,kBAAA;EHia9C;AGhamC;EAAW,kBAAA;EHma9C;AGlamC;EAAW,kBAAA;EHqa9C;AGpamC;EAAW,kBAAA;EHua9C;AGtamC;EAAW,kBAAA;EHya9C;AGxamC;EAAW,kBAAA;EH2a9C;AG1amC;EAAW,kBAAA;EH6a9C;AG5amC;EAAW,kBAAA;EH+a9C;AG9amC;EAAW,kBAAA;EHib9C;AGhbmC;EAAW,kBAAA;EHmb9C;AGlbmC;EAAW,kBAAA;EHqb9C;AGpbmC;EAAW,kBAAA;EHub9C;AGtbmC;EAAW,kBAAA;EHyb9C;AGxbmC;EAAW,kBAAA;EH2b9C;AG1bmC;EAAW,kBAAA;EH6b9C;AG5bmC;EAAW,kBAAA;EH+b9C;AG9bmC;EAAW,kBAAA;EHic9C;AGhcmC;EAAW,kBAAA;EHmc9C;AGlcmC;EAAW,kBAAA;EHqc9C;AGpcmC;EAAW,kBAAA;EHuc9C;AGtcmC;EAAW,kBAAA;EHyc9C;AGxcmC;EAAW,kBAAA;EH2c9C;AG1cmC;EAAW,kBAAA;EH6c9C;AG5cmC;EAAW,kBAAA;EH+c9C;AG9cmC;EAAW,kBAAA;EHid9C;AGhdmC;EAAW,kBAAA;EHmd9C;AGldmC;EAAW,kBAAA;EHqd9C;AGpdmC;EAAW,kBAAA;EHud9C;AGtdmC;EAAW,kBAAA;EHyd9C;AGxdmC;EAAW,kBAAA;EH2d9C;AG1dmC;EAAW,kBAAA;EH6d9C;AG5dmC;EAAW,kBAAA;EH+d9C;AG9dmC;EAAW,kBAAA;EHie9C;AGhemC;EAAW,kBAAA;EHme9C;AGlemC;EAAW,kBAAA;EHqe9C;AGpemC;EAAW,kBAAA;EHue9C;AGtemC;EAAW,kBAAA;EHye9C;AGxemC;EAAW,kBAAA;EH2e9C;AG1emC;EAAW,kBAAA;EH6e9C;AG5emC;EAAW,kBAAA;EH+e9C;AG9emC;EAAW,kBAAA;EHif9C;AGhfmC;EAAW,kBAAA;EHmf9C;AGlfmC;EAAW,kBAAA;EHqf9C;AGpfmC;EAAW,kBAAA;EHuf9C;AGtfmC;EAAW,kBAAA;EHyf9C;AGxfmC;EAAW,kBAAA;EH2f9C;AG1fmC;EAAW,kBAAA;EH6f9C;AG5fmC;EAAW,kBAAA;EH+f9C;AG9fmC;EAAW,kBAAA;EHigB9C;AGhgBmC;EAAW,kBAAA;EHmgB9C;AGlgBmC;EAAW,kBAAA;EHqgB9C;AGpgBmC;EAAW,kBAAA;EHugB9C;AGtgBmC;EAAW,kBAAA;EHygB9C;AGxgBmC;EAAW,kBAAA;EH2gB9C;AG1gBmC;EAAW,kBAAA;EH6gB9C;AG5gBmC;EAAW,kBAAA;EH+gB9C;AG9gBmC;EAAW,kBAAA;EHihB9C;AGhhBmC;EAAW,kBAAA;EHmhB9C;AGlhBmC;EAAW,kBAAA;EHqhB9C;AGphBmC;EAAW,kBAAA;EHuhB9C;AGthBmC;EAAW,kBAAA;EHyhB9C;AGxhBmC;EAAW,kBAAA;EH2hB9C;AG1hBmC;EAAW,kBAAA;EH6hB9C;AG5hBmC;EAAW,kBAAA;EH+hB9C;AG9hBmC;EAAW,kBAAA;EHiiB9C;AGhiBmC;EAAW,kBAAA;EHmiB9C;AGliBmC;EAAW,kBAAA;EHqiB9C;AGpiBmC;EAAW,kBAAA;EHuiB9C;AGtiBmC;EAAW,kBAAA;EHyiB9C;AGxiBmC;EAAW,kBAAA;EH2iB9C;AG1iBmC;EAAW,kBAAA;EH6iB9C;AG5iBmC;EAAW,kBAAA;EH+iB9C;AG9iBmC;EAAW,kBAAA;EHijB9C;AGhjBmC;EAAW,kBAAA;EHmjB9C;AGljBmC;EAAW,kBAAA;EHqjB9C;AGpjBmC;EAAW,kBAAA;EHujB9C;AGtjBmC;EAAW,kBAAA;EHyjB9C;AGxjBmC;EAAW,kBAAA;EH2jB9C;AG1jBmC;EAAW,kBAAA;EH6jB9C;AG5jBmC;EAAW,kBAAA;EH+jB9C;AG9jBmC;EAAW,kBAAA;EHikB9C;AGhkBmC;EAAW,kBAAA;EHmkB9C;AGlkBmC;EAAW,kBAAA;EHqkB9C;AGpkBmC;EAAW,kBAAA;EHukB9C;AGtkBmC;EAAW,kBAAA;EHykB9C;AGxkBmC;EAAW,kBAAA;EH2kB9C;AG1kBmC;EAAW,kBAAA;EH6kB9C;AG5kBmC;EAAW,kBAAA;EH+kB9C;AG9kBmC;EAAW,kBAAA;EHilB9C;AGhlBmC;EAAW,kBAAA;EHmlB9C;AGllBmC;EAAW,kBAAA;EHqlB9C;AGplBmC;EAAW,kBAAA;EHulB9C;AGtlBmC;EAAW,kBAAA;EHylB9C;AGxlBmC;EAAW,kBAAA;EH2lB9C;AG1lBmC;EAAW,kBAAA;EH6lB9C;AG5lBmC;EAAW,kBAAA;EH+lB9C;AG9lBmC;EAAW,kBAAA;EHimB9C;AGhmBmC;EAAW,kBAAA;EHmmB9C;AGlmBmC;EAAW,kBAAA;EHqmB9C;AGpmBmC;EAAW,kBAAA;EHumB9C;AGtmBmC;EAAW,kBAAA;EHymB9C;AGxmBmC;EAAW,kBAAA;EH2mB9C;AG1mBmC;EAAW,kBAAA;EH6mB9C;AG5mBmC;EAAW,kBAAA;EH+mB9C;AG9mBmC;EAAW,kBAAA;EHinB9C;AGhnBmC;EAAW,kBAAA;EHmnB9C;AGlnBmC;EAAW,kBAAA;EHqnB9C;AGpnBmC;EAAW,kBAAA;EHunB9C;AGtnBmC;EAAW,kBAAA;EHynB9C;AGxnBmC;EAAW,kBAAA;EH2nB9C;AG1nBmC;EAAW,kBAAA;EH6nB9C;AG5nBmC;EAAW,kBAAA;EH+nB9C;AG9nBmC;EAAW,kBAAA;EHioB9C;AGhoBmC;EAAW,kBAAA;EHmoB9C;AG1nBmC;EAAW,kBAAA;EH6nB9C;AG5nBmC;EAAW,kBAAA;EH+nB9C;AG9nBmC;EAAW,kBAAA;EHioB9C;AGhoBmC;EAAW,kBAAA;EHmoB9C;AGloBmC;EAAW,kBAAA;EHqoB9C;AGpoBmC;EAAW,kBAAA;EHuoB9C;AGtoBmC;EAAW,kBAAA;EHyoB9C;AGxoBmC;EAAW,kBAAA;EH2oB9C;AG1oBmC;EAAW,kBAAA;EH6oB9C;AG5oBmC;EAAW,kBAAA;EH+oB9C;AG9oBmC;EAAW,kBAAA;EHipB9C;AGhpBmC;EAAW,kBAAA;EHmpB9C;AGlpBmC;EAAW,kBAAA;EHqpB9C;AGppBmC;EAAW,kBAAA;EHupB9C;AGtpBmC;EAAW,kBAAA;EHypB9C;AGxpBmC;EAAW,kBAAA;EH2pB9C;AG1pBmC;EAAW,kBAAA;EH6pB9C;AG5pBmC;EAAW,kBAAA;EH+pB9C;AG9pBmC;EAAW,kBAAA;EHiqB9C;AGhqBmC;EAAW,kBAAA;EHmqB9C;AGlqBmC;EAAW,kBAAA;EHqqB9C;AGpqBmC;EAAW,kBAAA;EHuqB9C;AGtqBmC;EAAW,kBAAA;EHyqB9C;AGxqBmC;EAAW,kBAAA;EH2qB9C;AG1qBmC;EAAW,kBAAA;EH6qB9C;AG5qBmC;EAAW,kBAAA;EH+qB9C;AG9qBmC;EAAW,kBAAA;EHirB9C;AGhrBmC;EAAW,kBAAA;EHmrB9C;AGlrBmC;EAAW,kBAAA;EHqrB9C;AGprBmC;EAAW,kBAAA;EHurB9C;AGtrBmC;EAAW,kBAAA;EHyrB9C;AGxrBmC;EAAW,kBAAA;EH2rB9C;AG1rBmC;EAAW,kBAAA;EH6rB9C;AG5rBmC;EAAW,kBAAA;EH+rB9C;AG9rBmC;EAAW,kBAAA;EHisB9C;AGhsBmC;EAAW,kBAAA;EHmsB9C;AGlsBmC;EAAW,kBAAA;EHqsB9C;AGpsBmC;EAAW,kBAAA;EHusB9C;AGtsBmC;EAAW,kBAAA;EHysB9C;AGxsBmC;EAAW,kBAAA;EH2sB9C;AG1sBmC;EAAW,kBAAA;EH6sB9C;AG5sBmC;EAAW,kBAAA;EH+sB9C;AG9sBmC;EAAW,kBAAA;EHitB9C;AGhtBmC;EAAW,kBAAA;EHmtB9C;AGltBmC;EAAW,kBAAA;EHqtB9C;AGptBmC;EAAW,kBA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EfgkDH;AejkDC;EACE,qBAAA;EfmkDH;AepkDC;EACE,qBAAA;EfskDH;AevkDC;EACE,YAAA;EfykDH;Ae1kDC;EACE,qBAAA;Ef4kDH;Ae7kDC;EACE,oBAAA;Ef+kDH;Ae3kDC;EACE,aAAA;Ef6kDH;Ae7lDC;EACE,YAAA;Ef+lDH;AehmDC;EACE,oBAAA;EfkmDH;AenmDC;EACE,oBAAA;EfqmDH;AetmDC;EACE,WAAA;EfwmDH;AezmDC;EACE,oBAAA;Ef2mDH;Ae5mDC;EACE,oBAAA;Ef8mDH;Ae/mDC;EACE,WAAA;EfinDH;AelnDC;EACE,oBAAA;EfonDH;AernDC;EACE,oBAAA;EfunDH;AexnDC;EACE,WAAA;Ef0nDH;Ae3nDC;EACE,oBAAA;Ef6nDH;Ae9nDC;EACE,mBAAA;EfgoDH;Ae5nDC;EACE,YAAA;Ef8nDH;AehnDC;EACE,mBAAA;EfknDH;AennDC;EACE,2BAAA;EfqnDH;AetnDC;EACE,2BAAA;EfwnDH;AeznDC;EACE,kBAAA;Ef2nDH;Ae5nDC;EACE,2BAAA;Ef8nDH;Ae/nDC;EACE,2BAAA;EfioDH;AeloDC;EACE,kBAAA;EfooDH;AeroDC;EACE,2BAAA;EfuoDH;AexoDC;EACE,2BAAA;Ef0oDH;Ae3oDC;EACE,kBAAA;Ef6oDH;Ae9oDC;EACE,2BAAA;EfgpDH;AejpDC;EACE,0BAAA;EfmpDH;AeppDC;EACE,iBAAA;EfspDH;AatpDD;EElCI;IACE,aAAA;If2rDH;EeprDD;IACE,aAAA;IfsrDD;EevrDD;IACE,qBAAA;IfyrDD;Ee1rDD;IACE,qBAAA;If4rDD;Ee7rDD;IACE,YAAA;If+rDD;EehsDD;IACE,qBAAA;IfksDD;EensDD;IACE,qBAAA;IfqsDD;EetsDD;IACE,YAAA;IfwsDD;EezsDD;IACE,qBAAA;If2sDD;Ee5sDD;IACE,qBAAA;If8sDD;Ee/sDD;IACE,YAAA;IfitDD;EeltDD;IACE,qBAAA;IfotDD;EertDD;IACE,oBAAA;IfutDD;EezsDD;IACE,aAAA;If2sDD;Ee5sDD;IACE,qBAAA;If8sDD;Ee/sDD;IACE,qBAAA;IfitDD;EeltDD;IACE,YAAA;IfotDD;EertDD;IACE,qBAAA;IfutDD;EextDD;IACE,qBAAA;If0tDD;Ee3tDD;IACE,YAAA;If6tDD;Ee9tDD;IACE,qBAAA;IfguDD;EejuDD;IACE,qBAAA;IfmuDD;EepuDD;IACE,YAAA;IfsuDD;EevuDD;IACE,qBAAA;IfyuDD;Ee1uDD;IACE,oBAAA;If4uDD;EexuDD;IACE,aAAA;If0uDD;Ee1vDD;IACE,YAAA;If4vDD;Ee7vDD;IACE,oBAAA;If+vDD;EehwDD;IACE,oBAAA;IfkwDD;EenwDD;IACE,WAAA;IfqwDD;EetwDD;IACE,oBAAA;IfwwDD;EezwDD;IACE,oBAAA;If2wDD;Ee5wDD;IACE,WAAA;If8wDD;Ee/wDD;IACE,oBAAA;IfixDD;EelxDD;IACE,oBAAA;IfoxDD;EerxDD;IACE,WAAA;IfuxDD;EexxDD;IACE,oBAAA;If0xDD;Ee3xDD;IACE,mBAAA;If6xDD;EezxDD;IACE,YAAA;If2xDD;Ee7wDD;IACE,mBAAA;If+wDD;EehxDD;IACE,2BAAA;IfkxDD;EenxDD;IACE,2BAAA;IfqxDD;EetxDD;IACE,kBAAA;IfwxDD;EezxDD;IACE,2BAAA;If2xDD;Ee5xDD;IACE,2BAAA;If8xDD;Ee/xDD;IACE,kBAAA;IfiyDD;EelyDD;IACE,2BAAA;IfoyDD;EeryDD;IACE,2BAAA;IfuyDD;EexyDD;IACE,kBAAA;If0yDD;Ee3yDD;IACE,2BAAA;If6yDD;Ee9yDD;IACE,0BAAA;IfgzDD;EejzDD;IACE,iBAAA;IfmzDD;EACF;Aa3yDD;EE3CI;IACE,aAAA;Ify1DH;Eel1DD;IACE,aAAA;Ifo1DD;Eer1DD;IACE,qBAAA;Ifu1DD;Eex1DD;IACE,qBAAA;If01DD;Ee31DD;IACE,YAAA;If61DD;Ee91DD;IACE,qBAAA;Ifg2DD;Eej2DD;IACE,qBAAA;Ifm2DD;Eep2DD;IACE,YAAA;Ifs2DD;Eev2DD;IACE,qBAAA;Ify2DD;Ee12DD;IACE,qBAAA;If42DD;Ee72DD;IACE,YAAA;If+2DD;Eeh3DD;IACE,qBAAA;Ifk3DD;Een3DD;IACE,oBAAA;Ifq3DD;Eev2DD;IACE,aAAA;Ify2DD;Ee12DD;IACE,qBAAA;If42DD;Ee72DD;IACE,qBAAA;If+2DD;Eeh3DD;IACE,YAAA;Ifk3DD;Een3DD;IACE,qBAAA;Ifq3DD;Eet3DD;IACE,qBAAA;Ifw3DD;Eez3DD;IACE,YAAA;If23DD;Ee53DD;IACE,qBAAA;If83DD;Ee/3DD;IACE,qBAAA;Ifi4DD;Eel4DD;IACE,YAAA;Ifo4DD;Eer4DD;IACE,qBAAA;Ifu4DD;Eex4DD;IACE,oBAAA;If04DD;Eet4DD;IACE,aAAA;Ifw4DD;Eex5DD;IACE,YAAA;If05DD;Ee35DD;IACE,oBAAA;If65DD;Ee95DD;IACE,oBAAA;Ifg6DD;Eej6DD;IACE,WAAA;Ifm6DD;Eep6DD;IACE,oBAAA;Ifs6DD;Eev6DD;IACE,oBAAA;Ify6DD;Ee16DD;IACE,WAAA;If46DD;Ee76DD;IACE,oBAAA;If+6DD;Eeh7DD;IACE,oBAAA;Ifk7DD;Een7DD;IACE,WAAA;Ifq7DD;Eet7DD;IACE,oBAAA;Ifw7DD;Eez7DD;IACE,mBAAA;If27DD;Eev7DD;IACE,YAAA;Ify7DD;Ee36DD;IACE,mBAAA;If66DD;Ee96DD;IACE,2BAAA;Ifg7DD;Eej7DD;IACE,2BAAA;Ifm7DD;Eep7DD;IACE,kBAAA;Ifs7DD;Eev7DD;IACE,2BAAA;Ify7DD;Ee17DD;IACE,2BAAA;If47DD;Ee77DD;IACE,kBAAA;If+7DD;Eeh8DD;IACE,2BAAA;Ifk8DD;Een8DD;IACE,2BAAA;Ifq8DD;Eet8DD;IACE,kBAAA;Ifw8DD;Eez8DD;IACE,2BAAA;If28DD;Ee58DD;IACE,0BAAA;If88DD;Ee/8DD;IACE,iBAAA;Ifi9DD;EACF;Aat8DD;EE9CI;IACE,aAAA;Ifu/DH;Eeh/DD;IACE,aAAA;Ifk/DD;Een/DD;IACE,qBAAA;Ifq/DD;Eet/DD;IACE,qBAAA;Ifw/DD;Eez/DD;IACE,YAAA;If2/DD;Ee5/DD;IACE,qBAAA;If8/DD;Ee//DD;IACE,qBAAA;IfigED;EelgED;IACE,YAAA;IfogED;EergED;IACE,qBAAA;IfugED;EexgED;IACE,qBAAA;If0gED;Ee3gED;IACE,YAAA;If6gED;Ee9gED;IACE,qBAAA;IfghED;EejhED;IACE,oBAAA;IfmhED;EergED;IACE,aAAA;IfugED;EexgED;IACE,qBAAA;If0gED;Ee3gED;IACE,qBAAA;If6gED;Ee9gED;IACE,YAAA;IfghED;EejhED;IACE,qBAAA;IfmhED;EephED;IACE,qBAAA;IfshED;EevhED;IACE,YAAA;IfyhED;Ee1hED;IACE,qBAAA;If4hED;Ee7hED;IACE,qBAAA;If+hED;EehiED;IACE,YAAA;IfkiED;EeniED;IACE,qBAAA;IfqiED;EetiED;IACE,oBAAA;IfwiED;EepiED;IACE,aAAA;IfsiED;EetjED;IACE,YAAA;IfwjED;EezjED;IACE,oBAAA;If2jED;Ee5jED;IACE,oBAAA;If8jED;Ee/jED;IACE,WAAA;IfikED;EelkED;IACE,oBAAA;IfokED;EerkED;IACE,oBAAA;IfukED;EexkED;IACE,WAAA;If0kED;Ee3kED;IACE,oBAAA;If6kED;Ee9kED;IACE,oBAAA;IfglED;EejlED;IACE,WAAA;IfmlED;EeplED;IACE,oBAAA;IfslED;EevlED;IACE,mBAAA;IfylED;EerlED;IACE,YAAA;IfulED;EezkED;IACE,mBAAA;If2kED;Ee5kED;IACE,2BAAA;If8kED;Ee/kED;IACE,2BAAA;IfilED;EellED;IACE,kBAAA;IfolED;EerlED;IACE,2BAAA;IfulED;EexlED;IACE,2BAAA;If0lED;Ee3lED;IACE,kBAAA;If6lED;Ee9lED;IACE,2BAAA;IfgmED;EejmED;IACE,2BAAA;IfmmED;EepmED;IACE,kBAAA;IfsmED;EevmED;IACE,2BAAA;IfymED;Ee1mED;IACE,0BAAA;If4mED;Ee7mED;IACE,iBAAA;If+mED;EACF;AgBnrED;EACE,+BAAA;EhBqrED;AgBnrED;EACE,kBAAA;EACA,qBAAA;EACA,gBAAA;EACA,kBAAA;EhBqrED;AgBnrED;EACE,kBAAA;EhBqrE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","file":"bootstrap.css","sourcesContent":["/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n  font-family: sans-serif;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\nbody {\n  margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n[hidden],\ntemplate {\n  display: none;\n}\na {\n  background-color: transparent;\n}\na:active,\na:hover {\n  outline: 0;\n}\nabbr[title] {\n  border-bottom: 1px dotted;\n}\nb,\nstrong {\n  font-weight: bold;\n}\ndfn {\n  font-style: italic;\n}\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\nmark {\n  background: #ff0;\n  color: #000;\n}\nsmall {\n  font-size: 80%;\n}\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\nsup {\n  top: -0.5em;\n}\nsub {\n  bottom: -0.25em;\n}\nimg {\n  border: 0;\n}\nsvg:not(:root) {\n  overflow: hidden;\n}\nfigure {\n  margin: 1em 40px;\n}\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\npre {\n  overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit;\n  font: inherit;\n  margin: 0;\n}\nbutton {\n  overflow: visible;\n}\nbutton,\nselect {\n  text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\ninput {\n  line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: textfield;\n  box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n  border: 0;\n  padding: 0;\n}\ntextarea {\n  overflow: auto;\n}\noptgroup {\n  font-weight: bold;\n}\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\ntd,\nth {\n  padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n  *,\n  *:before,\n  *:after {\n    background: transparent !important;\n    color: #000 !important;\n    box-shadow: none !important;\n    text-shadow: none !important;\n  }\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  a[href^=\"#\"]:after,\n  a[href^=\"javascript:\"]:after {\n    content: \"\";\n  }\n  pre,\n  blockquote {\n    border: 1px solid #999;\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  img {\n    max-width: 100% !important;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n  .navbar {\n    display: none;\n  }\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .label {\n    border: 1px solid #000;\n  }\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: url('../fonts/glyphicons-halflings-regular.eot');\n  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n  content: \"\\2a\";\n}\n.glyphicon-plus:before {\n  content: \"\\2b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n  content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n.glyphicon-cd:before {\n  content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n  content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n  content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n  content: \"\\e204\";\n}\n.glyphicon-copy:before {\n  content: \"\\e205\";\n}\n.glyphicon-paste:before {\n  content: \"\\e206\";\n}\n.glyphicon-alert:before {\n  content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n  content: \"\\e210\";\n}\n.glyphicon-king:before {\n  content: \"\\e211\";\n}\n.glyphicon-queen:before {\n  content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n  content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n  content: \"\\e214\";\n}\n.glyphicon-knight:before {\n  content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n  content: \"\\e216\";\n}\n.glyphicon-tent:before {\n  content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n  content: \"\\e218\";\n}\n.glyphicon-bed:before {\n  content: \"\\e219\";\n}\n.glyphicon-apple:before {\n  content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n  content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n  content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n  content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n  content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n  content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n  content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n  content: \"\\e227\";\n}\n.glyphicon-btc:before {\n  content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n  content: \"\\e227\";\n}\n.glyphicon-yen:before {\n  content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n  content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n  content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n  content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n  content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n  content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n  content: \"\\e232\";\n}\n.glyphicon-education:before {\n  content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n  content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n  content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n  content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n  content: \"\\e237\";\n}\n.glyphicon-oil:before {\n  content: \"\\e238\";\n}\n.glyphicon-grain:before {\n  content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n  content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n  content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n  content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n  content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n  content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n  content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n  content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n  content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n  content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n  content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n  content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n  content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n  content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n  content: \"\\e253\";\n}\n.glyphicon-console:before {\n  content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n  content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n  content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n  content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n  content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n  content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n  content: \"\\e260\";\n}\n* {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\nhtml {\n  font-size: 10px;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n  font-family: Cantarell, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #333333;\n  background-color: #ffffff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\na {\n  color: #428bca;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #2a6496;\n  text-decoration: underline;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\nfigure {\n  margin: 0;\n}\nimg {\n  vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.img-rounded {\n  border-radius: 6px;\n}\n.img-thumbnail {\n  padding: 4px;\n  line-height: 1.42857143;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 4px;\n  -webkit-transition: all 0.2s ease-in-out;\n  -o-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n}\n.img-circle {\n  border-radius: 50%;\n}\nhr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n  position: static;\n  width: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  clip: auto;\n}\n[role=\"button\"] {\n  cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n  font-family: inherit;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n  font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n  font-size: 75%;\n}\nh1,\n.h1 {\n  font-size: 36px;\n}\nh2,\n.h2 {\n  font-size: 30px;\n}\nh3,\n.h3 {\n  font-size: 24px;\n}\nh4,\n.h4 {\n  font-size: 18px;\n}\nh5,\n.h5 {\n  font-size: 14px;\n}\nh6,\n.h6 {\n  font-size: 12px;\n}\np {\n  margin: 0 0 10px;\n}\n.lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 21px;\n  }\n}\nsmall,\n.small {\n  font-size: 85%;\n}\nmark,\n.mark {\n  background-color: #f8e4c7;\n  padding: .2em;\n}\n.text-left {\n  text-align: left;\n}\n.text-right {\n  text-align: right;\n}\n.text-center {\n  text-align: center;\n}\n.text-justify {\n  text-align: justify;\n}\n.text-nowrap {\n  white-space: nowrap;\n}\n.text-lowercase {\n  text-transform: lowercase;\n}\n.text-uppercase {\n  text-transform: uppercase;\n}\n.text-capitalize {\n  text-transform: capitalize;\n}\n.text-muted {\n  color: #777777;\n}\n.text-primary {\n  color: #428bca;\n}\na.text-primary:hover,\na.text-primary:focus {\n  color: #3071a9;\n}\n.text-success {\n  color: #3f7815;\n}\na.text-success:hover,\na.text-success:focus {\n  color: #284d0e;\n}\n.text-info {\n  color: #603e7a;\n}\na.text-info:hover,\na.text-info:focus {\n  color: #452d58;\n}\n.text-warning {\n  color: #7e500f;\n}\na.text-warning:hover,\na.text-warning:focus {\n  color: #51330a;\n}\n.text-danger {\n  color: #78153f;\n}\na.text-danger:hover,\na.text-danger:focus {\n  color: #4d0e28;\n}\n.bg-primary {\n  color: #fff;\n  background-color: #428bca;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n  background-color: #3071a9;\n}\n.bg-success {\n  background-color: #dcf6ca;\n}\na.bg-success:hover,\na.bg-success:focus {\n  background-color: #c0ee9e;\n}\n.bg-info {\n  background-color: #f6f2f8;\n}\na.bg-info:hover,\na.bg-info:focus {\n  background-color: #ddd0e7;\n}\n.bg-warning {\n  background-color: #f8e4c7;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n  background-color: #f3ce9a;\n}\n.bg-danger {\n  background-color: #f6cadc;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n  background-color: #ee9ec0;\n}\n.page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n  margin-bottom: 0;\n}\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.list-inline {\n  padding-left: 0;\n  list-style: none;\n  margin-left: -5px;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\ndl {\n  margin-top: 0;\n  margin-bottom: 20px;\n}\ndt,\ndd {\n  line-height: 1.42857143;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    clear: left;\n    text-align: right;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #777777;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\nblockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  font-size: 17.5px;\n  border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.42857143;\n  color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n  text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n  content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\naddress {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #ffffff;\n  background-color: #333333;\n  border-radius: 3px;\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: bold;\n  box-shadow: none;\n}\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: #333333;\n  background-color: #f5f5f5;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n}\npre code {\n  padding: 0;\n  font-size: inherit;\n  color: inherit;\n  white-space: pre-wrap;\n  background-color: transparent;\n  border-radius: 0;\n}\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.container {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 750px;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 970px;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n.container-fluid {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.row {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n  float: left;\n}\n.col-xs-12 {\n  width: 100%;\n}\n.col-xs-11 {\n  width: 91.66666667%;\n}\n.col-xs-10 {\n  width: 83.33333333%;\n}\n.col-xs-9 {\n  width: 75%;\n}\n.col-xs-8 {\n  width: 66.66666667%;\n}\n.col-xs-7 {\n  width: 58.33333333%;\n}\n.col-xs-6 {\n  width: 50%;\n}\n.col-xs-5 {\n  width: 41.66666667%;\n}\n.col-xs-4 {\n  width: 33.33333333%;\n}\n.col-xs-3 {\n  width: 25%;\n}\n.col-xs-2 {\n  width: 16.66666667%;\n}\n.col-xs-1 {\n  width: 8.33333333%;\n}\n.col-xs-pull-12 {\n  right: 100%;\n}\n.col-xs-pull-11 {\n  right: 91.66666667%;\n}\n.col-xs-pull-10 {\n  right: 83.33333333%;\n}\n.col-xs-pull-9 {\n  right: 75%;\n}\n.col-xs-pull-8 {\n  right: 66.66666667%;\n}\n.col-xs-pull-7 {\n  right: 58.33333333%;\n}\n.col-xs-pull-6 {\n  right: 50%;\n}\n.col-xs-pull-5 {\n  right: 41.66666667%;\n}\n.col-xs-pull-4 {\n  right: 33.33333333%;\n}\n.col-xs-pull-3 {\n  right: 25%;\n}\n.col-xs-pull-2 {\n  right: 16.66666667%;\n}\n.col-xs-pull-1 {\n  right: 8.33333333%;\n}\n.col-xs-pull-0 {\n  right: auto;\n}\n.col-xs-push-12 {\n  left: 100%;\n}\n.col-xs-push-11 {\n  left: 91.66666667%;\n}\n.col-xs-push-10 {\n  left: 83.33333333%;\n}\n.col-xs-push-9 {\n  left: 75%;\n}\n.col-xs-push-8 {\n  left: 66.66666667%;\n}\n.col-xs-push-7 {\n  left: 58.33333333%;\n}\n.col-xs-push-6 {\n  left: 50%;\n}\n.col-xs-push-5 {\n  left: 41.66666667%;\n}\n.col-xs-push-4 {\n  left: 33.33333333%;\n}\n.col-xs-push-3 {\n  left: 25%;\n}\n.col-xs-push-2 {\n  left: 16.66666667%;\n}\n.col-xs-push-1 {\n  left: 8.33333333%;\n}\n.col-xs-push-0 {\n  left: auto;\n}\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n.col-xs-offset-11 {\n  margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n  margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n.col-xs-offset-8 {\n  margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n  margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n.col-xs-offset-5 {\n  margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n  margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n.col-xs-offset-2 {\n  margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n  margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n  margin-left: 0%;\n}\n@media (min-width: 768px) {\n  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n    float: left;\n  }\n  .col-sm-12 {\n    width: 100%;\n  }\n  .col-sm-11 {\n    width: 91.66666667%;\n  }\n  .col-sm-10 {\n    width: 83.33333333%;\n  }\n  .col-sm-9 {\n    width: 75%;\n  }\n  .col-sm-8 {\n    width: 66.66666667%;\n  }\n  .col-sm-7 {\n    width: 58.33333333%;\n  }\n  .col-sm-6 {\n    width: 50%;\n  }\n  .col-sm-5 {\n    width: 41.66666667%;\n  }\n  .col-sm-4 {\n    width: 33.33333333%;\n  }\n  .col-sm-3 {\n    width: 25%;\n  }\n  .col-sm-2 {\n    width: 16.66666667%;\n  }\n  .col-sm-1 {\n    width: 8.33333333%;\n  }\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n  .col-sm-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-sm-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n  .col-sm-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-sm-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n  .col-sm-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-sm-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n  .col-sm-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-sm-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-sm-pull-0 {\n    right: auto;\n  }\n  .col-sm-push-12 {\n    left: 100%;\n  }\n  .col-sm-push-11 {\n    left: 91.66666667%;\n  }\n  .col-sm-push-10 {\n    left: 83.33333333%;\n  }\n  .col-sm-push-9 {\n    left: 75%;\n  }\n  .col-sm-push-8 {\n    left: 66.66666667%;\n  }\n  .col-sm-push-7 {\n    left: 58.33333333%;\n  }\n  .col-sm-push-6 {\n    left: 50%;\n  }\n  .col-sm-push-5 {\n    left: 41.66666667%;\n  }\n  .col-sm-push-4 {\n    left: 33.33333333%;\n  }\n  .col-sm-push-3 {\n    left: 25%;\n  }\n  .col-sm-push-2 {\n    left: 16.66666667%;\n  }\n  .col-sm-push-1 {\n    left: 8.33333333%;\n  }\n  .col-sm-push-0 {\n    left: auto;\n  }\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .col-sm-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-sm-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .col-sm-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-sm-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .col-sm-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-sm-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .col-sm-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-sm-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-sm-offset-0 {\n    margin-left: 0%;\n  }\n}\n@media (min-width: 992px) {\n  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n    float: left;\n  }\n  .col-md-12 {\n    width: 100%;\n  }\n  .col-md-11 {\n    width: 91.66666667%;\n  }\n  .col-md-10 {\n    width: 83.33333333%;\n  }\n  .col-md-9 {\n    width: 75%;\n  }\n  .col-md-8 {\n    width: 66.66666667%;\n  }\n  .col-md-7 {\n    width: 58.33333333%;\n  }\n  .col-md-6 {\n    width: 50%;\n  }\n  .col-md-5 {\n    width: 41.66666667%;\n  }\n  .col-md-4 {\n    width: 33.33333333%;\n  }\n  .col-md-3 {\n    width: 25%;\n  }\n  .col-md-2 {\n    width: 16.66666667%;\n  }\n  .col-md-1 {\n    width: 8.33333333%;\n  }\n  .col-md-pull-12 {\n    right: 100%;\n  }\n  .col-md-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-md-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-md-pull-9 {\n    right: 75%;\n  }\n  .col-md-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-md-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-md-pull-6 {\n    right: 50%;\n  }\n  .col-md-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-md-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-md-pull-3 {\n    right: 25%;\n  }\n  .col-md-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-md-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-md-pull-0 {\n    right: auto;\n  }\n  .col-md-push-12 {\n    left: 100%;\n  }\n  .col-md-push-11 {\n    left: 91.66666667%;\n  }\n  .col-md-push-10 {\n    left: 83.33333333%;\n  }\n  .col-md-push-9 {\n    left: 75%;\n  }\n  .col-md-push-8 {\n    left: 66.66666667%;\n  }\n  .col-md-push-7 {\n    left: 58.33333333%;\n  }\n  .col-md-push-6 {\n    left: 50%;\n  }\n  .col-md-push-5 {\n    left: 41.66666667%;\n  }\n  .col-md-push-4 {\n    left: 33.33333333%;\n  }\n  .col-md-push-3 {\n    left: 25%;\n  }\n  .col-md-push-2 {\n    left: 16.66666667%;\n  }\n  .col-md-push-1 {\n    left: 8.33333333%;\n  }\n  .col-md-push-0 {\n    left: auto;\n  }\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .col-md-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-md-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .col-md-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-md-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .col-md-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-md-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .col-md-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-md-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-md-offset-0 {\n    margin-left: 0%;\n  }\n}\n@media (min-width: 1200px) {\n  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n    float: left;\n  }\n  .col-lg-12 {\n    width: 100%;\n  }\n  .col-lg-11 {\n    width: 91.66666667%;\n  }\n  .col-lg-10 {\n    width: 83.33333333%;\n  }\n  .col-lg-9 {\n    width: 75%;\n  }\n  .col-lg-8 {\n    width: 66.66666667%;\n  }\n  .col-lg-7 {\n    width: 58.33333333%;\n  }\n  .col-lg-6 {\n    width: 50%;\n  }\n  .col-lg-5 {\n    width: 41.66666667%;\n  }\n  .col-lg-4 {\n    width: 33.33333333%;\n  }\n  .col-lg-3 {\n    width: 25%;\n  }\n  .col-lg-2 {\n    width: 16.66666667%;\n  }\n  .col-lg-1 {\n    width: 8.33333333%;\n  }\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n  .col-lg-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-lg-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n  .col-lg-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-lg-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n  .col-lg-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-lg-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n  .col-lg-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-lg-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-lg-pull-0 {\n    right: auto;\n  }\n  .col-lg-push-12 {\n    left: 100%;\n  }\n  .col-lg-push-11 {\n    left: 91.66666667%;\n  }\n  .col-lg-push-10 {\n    left: 83.33333333%;\n  }\n  .col-lg-push-9 {\n    left: 75%;\n  }\n  .col-lg-push-8 {\n    left: 66.66666667%;\n  }\n  .col-lg-push-7 {\n    left: 58.33333333%;\n  }\n  .col-lg-push-6 {\n    left: 50%;\n  }\n  .col-lg-push-5 {\n    left: 41.66666667%;\n  }\n  .col-lg-push-4 {\n    left: 33.33333333%;\n  }\n  .col-lg-push-3 {\n    left: 25%;\n  }\n  .col-lg-push-2 {\n    left: 16.66666667%;\n  }\n  .col-lg-push-1 {\n    left: 8.33333333%;\n  }\n  .col-lg-push-0 {\n    left: auto;\n  }\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .col-lg-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-lg-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .col-lg-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-lg-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .col-lg-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-lg-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .col-lg-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-lg-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-lg-offset-0 {\n    margin-left: 0%;\n  }\n}\ntable {\n  background-color: transparent;\n}\ncaption {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  color: #777777;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #dddddd;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #dddddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.table > tbody + tbody {\n  border-top: 2px solid #dddddd;\n}\n.table .table {\n  background-color: #ffffff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.table-bordered {\n  border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n  background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n  background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n  background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n  background-color: #dcf6ca;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n  background-color: #cef2b4;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n  background-color: #f6f2f8;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n  background-color: #e9e1f0;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n  background-color: #f8e4c7;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n  background-color: #f6d9b0;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n  background-color: #f6cadc;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n  background-color: #f2b4ce;\n}\n.table-responsive {\n  overflow-x: auto;\n  min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #dddddd;\n  }\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .table-responsive > .table > thead > tr > th,\n  .table-responsive > .table > tbody > tr > th,\n  .table-responsive > .table > tfoot > tr > th,\n  .table-responsive > .table > thead > tr > td,\n  .table-responsive > .table > tbody > tr > td,\n  .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  min-width: 0;\n}\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  line-height: normal;\n}\ninput[type=\"file\"] {\n  display: block;\n}\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\nselect[multiple],\nselect[size] {\n  height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555555;\n}\n.form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555555;\n  background-color: #ffffff;\n  background-image: none;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n  color: #999999;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #999999;\n}\n.form-control::-webkit-input-placeholder {\n  color: #999999;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #eeeeee;\n  opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n  cursor: not-allowed;\n}\ntextarea.form-control {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"],\n  input[type=\"time\"],\n  input[type=\"datetime-local\"],\n  input[type=\"month\"] {\n    line-height: 34px;\n  }\n  input[type=\"date\"].input-sm,\n  input[type=\"time\"].input-sm,\n  input[type=\"datetime-local\"].input-sm,\n  input[type=\"month\"].input-sm,\n  .input-group-sm input[type=\"date\"],\n  .input-group-sm input[type=\"time\"],\n  .input-group-sm input[type=\"datetime-local\"],\n  .input-group-sm input[type=\"month\"] {\n    line-height: 30px;\n  }\n  input[type=\"date\"].input-lg,\n  input[type=\"time\"].input-lg,\n  input[type=\"datetime-local\"].input-lg,\n  input[type=\"month\"].input-lg,\n  .input-group-lg input[type=\"date\"],\n  .input-group-lg input[type=\"time\"],\n  .input-group-lg input[type=\"datetime-local\"],\n  .input-group-lg input[type=\"month\"] {\n    line-height: 46px;\n  }\n}\n.form-group {\n  margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n  min-height: 20px;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  position: absolute;\n  margin-left: -20px;\n  margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n  cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n  cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n  cursor: not-allowed;\n}\n.form-control-static {\n  padding-top: 7px;\n  padding-bottom: 7px;\n  margin-bottom: 0;\n  min-height: 34px;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n  padding-left: 0;\n  padding-right: 0;\n}\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\n.form-group-sm .form-control {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.form-group-sm select.form-control {\n  height: 30px;\n  line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n  height: auto;\n}\n.form-group-sm .form-control-static {\n  height: 30px;\n  min-height: 32px;\n  padding: 6px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.input-lg {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-lg {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.form-group-lg .form-control {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.form-group-lg select.form-control {\n  height: 46px;\n  line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n  height: auto;\n}\n.form-group-lg .form-control-static {\n  height: 46px;\n  min-height: 38px;\n  padding: 11px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 42.5px;\n}\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 34px;\n  height: 34px;\n  line-height: 34px;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback {\n  width: 46px;\n  height: 46px;\n  line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback {\n  width: 30px;\n  height: 30px;\n  line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n  color: #3f7815;\n}\n.has-success .form-control {\n  border-color: #3f7815;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n  border-color: #284d0e;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #6ccf24;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #6ccf24;\n}\n.has-success .input-group-addon {\n  color: #3f7815;\n  border-color: #3f7815;\n  background-color: #dcf6ca;\n}\n.has-success .form-control-feedback {\n  color: #3f7815;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n  color: #7e500f;\n}\n.has-warning .form-control {\n  border-color: #7e500f;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n  border-color: #51330a;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d98a1a;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d98a1a;\n}\n.has-warning .input-group-addon {\n  color: #7e500f;\n  border-color: #7e500f;\n  background-color: #f8e4c7;\n}\n.has-warning .form-control-feedback {\n  color: #7e500f;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n  color: #78153f;\n}\n.has-error .form-control {\n  border-color: #78153f;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n  border-color: #4d0e28;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #cf246c;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #cf246c;\n}\n.has-error .input-group-addon {\n  color: #78153f;\n  border-color: #78153f;\n  background-color: #f6cadc;\n}\n.has-error .form-control-feedback {\n  color: #78153f;\n}\n.has-feedback label ~ .form-control-feedback {\n  top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n  top: 0;\n}\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n@media (min-width: 768px) {\n  .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .form-control-static {\n    display: inline-block;\n  }\n  .form-inline .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .form-inline .input-group .input-group-addon,\n  .form-inline .input-group .input-group-btn,\n  .form-inline .input-group .form-control {\n    width: auto;\n  }\n  .form-inline .input-group > .form-control {\n    width: 100%;\n  }\n  .form-inline .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio,\n  .form-inline .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio label,\n  .form-inline .checkbox label {\n    padding-left: 0;\n  }\n  .form-inline .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .form-inline .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 27px;\n}\n.form-horizontal .form-group {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    text-align: right;\n    margin-bottom: 0;\n    padding-top: 7px;\n  }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  right: 15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 14.333333px;\n    font-size: 18px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-sm .control-label {\n    padding-top: 6px;\n    font-size: 12px;\n  }\n}\n.btn {\n  display: inline-block;\n  margin-bottom: 0;\n  font-weight: normal;\n  text-align: center;\n  vertical-align: middle;\n  touch-action: manipulation;\n  cursor: pointer;\n  background-image: none;\n  border: 1px solid transparent;\n  white-space: nowrap;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  border-radius: 4px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n  color: #333333;\n  text-decoration: none;\n}\n.btn:active,\n.btn.active {\n  outline: 0;\n  background-image: none;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  cursor: not-allowed;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n  pointer-events: none;\n}\n.btn-default {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #8c8c8c;\n}\n.btn-default:hover {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n  color: #333333;\n  background-color: #d4d4d4;\n  border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.btn-default .badge {\n  color: #ffffff;\n  background-color: #333333;\n}\n.btn-primary {\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n  color: #ffffff;\n  background-color: #3071a9;\n  border-color: #193c5a;\n}\n.btn-primary:hover {\n  color: #ffffff;\n  background-color: #3071a9;\n  border-color: #285e8e;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  color: #ffffff;\n  background-color: #3071a9;\n  border-color: #285e8e;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n  color: #ffffff;\n  background-color: #285e8e;\n  border-color: #193c5a;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.btn-primary .badge {\n  color: #428bca;\n  background-color: #ffffff;\n}\n.btn-success {\n  color: #ffffff;\n  background-color: #79db32;\n  border-color: #6ccf24;\n}\n.btn-success:focus,\n.btn-success.focus {\n  color: #ffffff;\n  background-color: #61b921;\n  border-color: #346311;\n}\n.btn-success:hover {\n  color: #ffffff;\n  background-color: #61b921;\n  border-color: #519b1b;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  color: #ffffff;\n  background-color: #61b921;\n  border-color: #519b1b;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n  color: #ffffff;\n  background-color: #519b1b;\n  border-color: #346311;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #79db32;\n  border-color: #6ccf24;\n}\n.btn-success .badge {\n  color: #79db32;\n  background-color: #ffffff;\n}\n.btn-info {\n  color: #ffffff;\n  background-color: #a07cbc;\n  border-color: #946bb3;\n}\n.btn-info:focus,\n.btn-info.focus {\n  color: #ffffff;\n  background-color: #885aab;\n  border-color: #533669;\n}\n.btn-info:hover {\n  color: #ffffff;\n  background-color: #885aab;\n  border-color: #754c95;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  color: #ffffff;\n  background-color: #885aab;\n  border-color: #754c95;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n  color: #ffffff;\n  background-color: #754c95;\n  border-color: #533669;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #a07cbc;\n  border-color: #946bb3;\n}\n.btn-info .badge {\n  color: #a07cbc;\n  background-color: #ffffff;\n}\n.btn-warning {\n  color: #ffffff;\n  background-color: #e59728;\n  border-color: #d98a1a;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n  color: #ffffff;\n  background-color: #c27c18;\n  border-color: #67420d;\n}\n.btn-warning:hover {\n  color: #ffffff;\n  background-color: #c27c18;\n  border-color: #a36814;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  color: #ffffff;\n  background-color: #c27c18;\n  border-color: #a36814;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n  color: #ffffff;\n  background-color: #a36814;\n  border-color: #67420d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #e59728;\n  border-color: #d98a1a;\n}\n.btn-warning .badge {\n  color: #e59728;\n  background-color: #ffffff;\n}\n.btn-danger {\n  color: #ffffff;\n  background-color: #db3279;\n  border-color: #cf246c;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n  color: #ffffff;\n  background-color: #b92161;\n  border-color: #631134;\n}\n.btn-danger:hover {\n  color: #ffffff;\n  background-color: #b92161;\n  border-color: #9b1b51;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  color: #ffffff;\n  background-color: #b92161;\n  border-color: #9b1b51;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n  color: #ffffff;\n  background-color: #9b1b51;\n  border-color: #631134;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #db3279;\n  border-color: #cf246c;\n}\n.btn-danger .badge {\n  color: #db3279;\n  background-color: #ffffff;\n}\n.btn-link {\n  color: #428bca;\n  font-weight: normal;\n  border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n  border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n  color: #2a6496;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #777777;\n  text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-block {\n  display: block;\n  width: 100%;\n}\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n  -o-transition: opacity 0.15s linear;\n  transition: opacity 0.15s linear;\n}\n.fade.in {\n  opacity: 1;\n}\n.collapse {\n  display: none;\n}\n.collapse.in {\n  display: block;\n}\ntr.collapse.in {\n  display: table-row;\n}\ntbody.collapse.in {\n  display: table-row-group;\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition-property: height, visibility;\n  transition-property: height, visibility;\n  -webkit-transition-duration: 0.35s;\n  transition-duration: 0.35s;\n  -webkit-transition-timing-function: ease;\n  transition-timing-function: ease;\n}\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px dashed;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n  position: relative;\n}\n.dropdown-toggle:focus {\n  outline: 0;\n}\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  list-style: none;\n  font-size: 14px;\n  text-align: left;\n  background-color: #ffffff;\n  border: 1px solid #cccccc;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.42857143;\n  color: #333333;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  text-decoration: none;\n  color: #262626;\n  background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #ffffff;\n  text-decoration: none;\n  outline: 0;\n  background-color: #428bca;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  cursor: not-allowed;\n}\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n.dropdown-menu-right {\n  left: auto;\n  right: 0;\n}\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #777777;\n  white-space: nowrap;\n}\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: 990;\n}\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px solid;\n  content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    left: auto;\n    right: 0;\n  }\n  .navbar-right .dropdown-menu-left {\n    left: 0;\n    right: auto;\n  }\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.btn-toolbar {\n  margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn .caret {\n  margin-left: 0;\n}\n.btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-bottom-left-radius: 4px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  float: none;\n  display: table-cell;\n  width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n  left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n  position: absolute;\n  clip: rect(0, 0, 0, 0);\n  pointer-events: none;\n}\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-left: 0;\n  padding-right: 0;\n}\n.input-group .form-control {\n  position: relative;\n  z-index: 2;\n  float: left;\n  width: 100%;\n  margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555555;\n  text-align: center;\n  background-color: #eeeeee;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n}\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.input-group-btn > .btn {\n  position: relative;\n}\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n  z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n  z-index: 2;\n  margin-left: -1px;\n}\n.nav {\n  margin-bottom: 0;\n  padding-left: 0;\n  list-style: none;\n}\n.nav > li {\n  position: relative;\n  display: block;\n}\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n  color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #777777;\n  text-decoration: none;\n  background-color: transparent;\n  cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #eeeeee;\n  border-color: #428bca;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.nav > li > a > img {\n  max-width: none;\n}\n.nav-tabs {\n  border-bottom: 1px solid #dddddd;\n}\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.42857143;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #dddddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #555555;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-bottom-color: transparent;\n  cursor: default;\n}\n.nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n  float: none;\n}\n.nav-tabs.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs.nav-justified > .active > a,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #ffffff;\n  }\n}\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 4px;\n}\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n  color: #ffffff;\n  background-color: #428bca;\n}\n.nav-stacked > li {\n  float: none;\n}\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.nav-justified {\n  width: 100%;\n}\n.nav-justified > li {\n  float: none;\n}\n.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs-justified {\n  border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #ffffff;\n  }\n}\n.tab-content > .tab-pane {\n  display: none;\n}\n.tab-content > .active {\n  display: block;\n}\n.nav .caret {\n  border-top-color: #db3279;\n  border-bottom-color: #db3279;\n}\n.nav a:hover .caret {\n  border-top-color: #b92161;\n  border-bottom-color: #b92161;\n}\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.navbar {\n  position: relative;\n  min-height: 35px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 4px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n.navbar-collapse {\n  overflow-x: visible;\n  padding-right: 15px;\n  padding-left: 15px;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n  -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n  }\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-static-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    padding-left: 0;\n    padding-right: 0;\n  }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n  max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    max-height: 200px;\n  }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .container > .navbar-header,\n  .container-fluid > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n}\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n.navbar-brand {\n  float: left;\n  padding: 7.5px 15px;\n  font-size: 18px;\n  line-height: 20px;\n  height: 35px;\n  font-family: Comfortaa, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-weight: bold;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n  text-decoration: none;\n}\n.navbar-brand > img {\n  display: block;\n}\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand,\n  .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: 15px;\n  padding: 9px 10px;\n  margin-top: 0.5px;\n  margin-bottom: 0.5px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.navbar-toggle:focus {\n  outline: 0;\n}\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n.navbar-nav {\n  margin: 3.75px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .navbar-nav .open .dropdown-menu {\n    position: static;\n    float: none;\n    width: auto;\n    margin-top: 0;\n    background-color: transparent;\n    border: 0;\n    box-shadow: none;\n  }\n  .navbar-nav .open .dropdown-menu > li > a,\n  .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .navbar-nav > li {\n    float: left;\n  }\n  .navbar-nav > li > a {\n    padding-top: 7.5px;\n    padding-bottom: 7.5px;\n  }\n}\n.navbar-form {\n  margin-left: -15px;\n  margin-right: -15px;\n  padding: 10px 15px;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  margin-top: 0.5px;\n  margin-bottom: 0.5px;\n}\n@media (min-width: 768px) {\n  .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control-static {\n    display: inline-block;\n  }\n  .navbar-form .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .navbar-form .input-group .input-group-addon,\n  .navbar-form .input-group .input-group-btn,\n  .navbar-form .input-group .form-control {\n    width: auto;\n  }\n  .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n  .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio,\n  .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio label,\n  .navbar-form .checkbox label {\n    padding-left: 0;\n  }\n  .navbar-form .radio input[type=\"radio\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n  .navbar-form .form-group:last-child {\n    margin-bottom: 0;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n  }\n}\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  border-top-right-radius: 4px;\n  border-top-left-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.navbar-btn {\n  margin-top: 0.5px;\n  margin-bottom: 0.5px;\n}\n.navbar-btn.btn-sm {\n  margin-top: 2.5px;\n  margin-bottom: 2.5px;\n}\n.navbar-btn.btn-xs {\n  margin-top: 6.5px;\n  margin-bottom: 6.5px;\n}\n.navbar-text {\n  margin-top: 7.5px;\n  margin-bottom: 7.5px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-left: 15px;\n    margin-right: 15px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n  .navbar-right {\n    float: right !important;\n    margin-right: -15px;\n  }\n  .navbar-right ~ .navbar-right {\n    margin-right: 0;\n  }\n}\n.navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n  color: #777777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.navbar-default .navbar-text {\n  color: #777777;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #777777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #333333;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n  color: #db3279;\n  background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n  color: #cccccc;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #dddddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #dddddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n  background-color: #e7e7e7;\n  color: #db3279;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777777;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333333;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #db3279;\n    background-color: #e7e7e7;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #cccccc;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #777777;\n}\n.navbar-default .navbar-link:hover {\n  color: #333333;\n}\n.navbar-default .btn-link {\n  color: #777777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n  color: #333333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n  color: #cccccc;\n}\n.navbar-inverse {\n  background-color: #294172;\n  border-color: #1c2c4c;\n}\n.navbar-inverse .navbar-brand {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n  color: #777777;\n}\n.navbar-inverse .navbar-nav > li > a {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n  color: #ffffff;\n  background-color: #1c2c4c;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444444;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #ffffff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #203258;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n  background-color: #1c2c4c;\n  color: #ffffff;\n}\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #1c2c4c;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #1c2c4c;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #ffffff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #ffffff;\n    background-color: #1c2c4c;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #444444;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #ffffff;\n}\n.navbar-inverse .btn-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n  color: #ffffff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n  color: #444444;\n}\n.breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  content: \"/\\00a0\";\n  padding: 0 5px;\n  color: #cccccc;\n}\n.breadcrumb > .active {\n  color: #777777;\n}\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.pagination > li {\n  display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  line-height: 1.42857143;\n  text-decoration: none;\n  color: #428bca;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-bottom-left-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-bottom-right-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n  z-index: 3;\n  color: #2a6496;\n  background-color: #eeeeee;\n  border-color: #dddddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n  cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n  color: #777777;\n  background-color: #ffffff;\n  border-color: #dddddd;\n  cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-bottom-left-radius: 6px;\n  border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-bottom-right-radius: 6px;\n  border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-bottom-left-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-bottom-right-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.pager {\n  padding-left: 0;\n  margin: 20px 0;\n  list-style: none;\n  text-align: center;\n}\n.pager li {\n  display: inline;\n}\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #777777;\n  background-color: #ffffff;\n  cursor: not-allowed;\n}\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #ffffff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.label:empty {\n  display: none;\n}\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n.label-default {\n  background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #5e5e5e;\n}\n.label-primary {\n  background-color: #428bca;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #3071a9;\n}\n.label-success {\n  background-color: #79db32;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #61b921;\n}\n.label-info {\n  background-color: #a07cbc;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #885aab;\n}\n.label-warning {\n  background-color: #e59728;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #c27c18;\n}\n.label-danger {\n  background-color: #db3279;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #b92161;\n}\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  color: #ffffff;\n  line-height: 1;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: #777777;\n  border-radius: 10px;\n}\n.badge:empty {\n  display: none;\n}\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n  top: 0;\n  padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #428bca;\n  background-color: #ffffff;\n}\n.list-group-item > .badge {\n  float: right;\n}\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.jumbotron {\n  padding: 30px 15px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 21px;\n  font-weight: 200;\n}\n.jumbotron > hr {\n  border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n  border-radius: 6px;\n}\n.jumbotron .container {\n  max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding: 48px 0;\n  }\n  .container .jumbotron,\n  .container-fluid .jumbotron {\n    padding-left: 60px;\n    padding-right: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 63px;\n  }\n}\n.thumbnail {\n  display: block;\n  padding: 4px;\n  margin-bottom: 20px;\n  line-height: 1.42857143;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 4px;\n  -webkit-transition: border 0.2s ease-in-out;\n  -o-transition: border 0.2s ease-in-out;\n  transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  margin-left: auto;\n  margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #428bca;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #333333;\n}\n.alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.alert .alert-link {\n  font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n.alert > p + p {\n  margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n  padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.alert-success {\n  background-color: #dcf6ca;\n  border-color: #d8f2b4;\n  color: #3f7815;\n}\n.alert-success hr {\n  border-top-color: #cdee9e;\n}\n.alert-success .alert-link {\n  color: #284d0e;\n}\n.alert-info {\n  background-color: #f6f2f8;\n  border-color: #e7e1f0;\n  color: #603e7a;\n}\n.alert-info hr {\n  border-top-color: #d9d0e7;\n}\n.alert-info .alert-link {\n  color: #452d58;\n}\n.alert-warning {\n  background-color: #f8e4c7;\n  border-color: #f6ceb0;\n  color: #7e500f;\n}\n.alert-warning hr {\n  border-top-color: #f3bf9a;\n}\n.alert-warning .alert-link {\n  color: #51330a;\n}\n.alert-danger {\n  background-color: #f6cadc;\n  border-color: #f2b4d8;\n  color: #78153f;\n}\n.alert-danger hr {\n  border-top-color: #ee9ecd;\n}\n.alert-danger .alert-link {\n  color: #4d0e28;\n}\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  overflow: hidden;\n  height: 20px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #428bca;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-transition: width 0.6s ease;\n  -o-transition: width 0.6s ease;\n  transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n  -o-animation: progress-bar-stripes 2s linear infinite;\n  animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n  background-color: #79db32;\n}\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n  background-color: #a07cbc;\n}\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n  background-color: #e59728;\n}\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n  background-color: #db3279;\n}\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n.media,\n.media-body {\n  zoom: 1;\n  overflow: hidden;\n}\n.media-body {\n  width: 10000px;\n}\n.media-object {\n  display: block;\n}\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n.media-middle {\n  vertical-align: middle;\n}\n.media-bottom {\n  vertical-align: bottom;\n}\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.list-group {\n  margin-bottom: 20px;\n  padding-left: 0;\n}\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n}\n.list-group-item:first-child {\n  border-top-right-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\na.list-group-item {\n  color: #555555;\n}\na.list-group-item .list-group-item-heading {\n  color: #333333;\n}\na.list-group-item:hover,\na.list-group-item:focus {\n  text-decoration: none;\n  color: #555555;\n  background-color: #f5f5f5;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n  background-color: #eeeeee;\n  color: #777777;\n  cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n  color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n  color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n  color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n  color: #e1edf7;\n}\n.list-group-item-success {\n  color: #3f7815;\n  background-color: #dcf6ca;\n}\na.list-group-item-success {\n  color: #3f7815;\n}\na.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-success:hover,\na.list-group-item-success:focus {\n  color: #3f7815;\n  background-color: #cef2b4;\n}\na.list-group-item-success.active,\na.list-group-item-success.active:hover,\na.list-group-item-success.active:focus {\n  color: #fff;\n  background-color: #3f7815;\n  border-color: #3f7815;\n}\n.list-group-item-info {\n  color: #603e7a;\n  background-color: #f6f2f8;\n}\na.list-group-item-info {\n  color: #603e7a;\n}\na.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-info:hover,\na.list-group-item-info:focus {\n  color: #603e7a;\n  background-color: #e9e1f0;\n}\na.list-group-item-info.active,\na.list-group-item-info.active:hover,\na.list-group-item-info.active:focus {\n  color: #fff;\n  background-color: #603e7a;\n  border-color: #603e7a;\n}\n.list-group-item-warning {\n  color: #7e500f;\n  background-color: #f8e4c7;\n}\na.list-group-item-warning {\n  color: #7e500f;\n}\na.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-warning:hover,\na.list-group-item-warning:focus {\n  color: #7e500f;\n  background-color: #f6d9b0;\n}\na.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus {\n  color: #fff;\n  background-color: #7e500f;\n  border-color: #7e500f;\n}\n.list-group-item-danger {\n  color: #78153f;\n  background-color: #f6cadc;\n}\na.list-group-item-danger {\n  color: #78153f;\n}\na.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-danger:hover,\na.list-group-item-danger:focus {\n  color: #78153f;\n  background-color: #f2b4ce;\n}\na.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus {\n  color: #fff;\n  background-color: #78153f;\n  border-color: #78153f;\n}\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.panel {\n  margin-bottom: 20px;\n  background-color: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n  padding: 15px;\n}\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n  color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n  color: inherit;\n}\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #dddddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n  margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n  border-width: 1px 0;\n  border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n  border-top: 0;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n  border-bottom: 0;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n  margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n  border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n  border-bottom-left-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n  border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n  border-top: 1px solid #dddddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n  border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n  border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n  border-bottom: 0;\n}\n.panel > .table-responsive {\n  border: 0;\n  margin-bottom: 0;\n}\n.panel-group {\n  margin-bottom: 20px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n}\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n  border-top: 1px solid #dddddd;\n}\n.panel-group .panel-footer {\n  border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #dddddd;\n}\n.panel-default {\n  border-color: #dddddd;\n}\n.panel-default > .panel-heading {\n  color: #333333;\n  background-color: #f5f5f5;\n  border-color: #dddddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #dddddd;\n}\n.panel-default > .panel-heading .badge {\n  color: #f5f5f5;\n  background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #dddddd;\n}\n.panel-primary {\n  border-color: #428bca;\n}\n.panel-primary > .panel-heading {\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #428bca;\n}\n.panel-primary > .panel-heading .badge {\n  color: #428bca;\n  background-color: #ffffff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #428bca;\n}\n.panel-success {\n  border-color: #d8f2b4;\n}\n.panel-success > .panel-heading {\n  color: #3f7815;\n  background-color: #dcf6ca;\n  border-color: #d8f2b4;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #d8f2b4;\n}\n.panel-success > .panel-heading .badge {\n  color: #dcf6ca;\n  background-color: #3f7815;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #d8f2b4;\n}\n.panel-info {\n  border-color: #e7e1f0;\n}\n.panel-info > .panel-heading {\n  color: #603e7a;\n  background-color: #f6f2f8;\n  border-color: #e7e1f0;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #e7e1f0;\n}\n.panel-info > .panel-heading .badge {\n  color: #f6f2f8;\n  background-color: #603e7a;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #e7e1f0;\n}\n.panel-warning {\n  border-color: #f6ceb0;\n}\n.panel-warning > .panel-heading {\n  color: #7e500f;\n  background-color: #f8e4c7;\n  border-color: #f6ceb0;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #f6ceb0;\n}\n.panel-warning > .panel-heading .badge {\n  color: #f8e4c7;\n  background-color: #7e500f;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #f6ceb0;\n}\n.panel-danger {\n  border-color: #f2b4d8;\n}\n.panel-danger > .panel-heading {\n  color: #78153f;\n  background-color: #f6cadc;\n  border-color: #f2b4d8;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #f2b4d8;\n}\n.panel-danger > .panel-heading .badge {\n  color: #f6cadc;\n  background-color: #78153f;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #f2b4d8;\n}\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  height: 100%;\n  width: 100%;\n  border: 0;\n}\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  display: none;\n  overflow: hidden;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transform: translate(0, -25%);\n  -ms-transform: translate(0, -25%);\n  -o-transform: translate(0, -25%);\n  transform: translate(0, -25%);\n  -webkit-transition: -webkit-transform 0.3s ease-out;\n  -moz-transition: -moz-transform 0.3s ease-out;\n  -o-transition: -o-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n  -ms-transform: translate(0, 0);\n  -o-transform: translate(0, 0);\n  transform: translate(0, 0);\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n.modal-content {\n  position: relative;\n  background-color: #ffffff;\n  border: 1px solid #999999;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  background-clip: padding-box;\n  outline: 0;\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000000;\n}\n.modal-backdrop.fade {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n  min-height: 16.42857143px;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.42857143;\n}\n.modal-body {\n  position: relative;\n  padding: 15px;\n}\n.modal-footer {\n  padding: 15px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n  margin-left: 5px;\n  margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n  }\n  .modal-sm {\n    width: 300px;\n  }\n}\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  font-family: Cantarell, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 12px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.tooltip.in {\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.tooltip.top {\n  margin-top: -3px;\n  padding: 5px 0;\n}\n.tooltip.right {\n  margin-left: 3px;\n  padding: 0 5px;\n}\n.tooltip.bottom {\n  margin-top: 3px;\n  padding: 5px 0;\n}\n.tooltip.left {\n  margin-left: -3px;\n  padding: 0 5px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #000000;\n  border-radius: 4px;\n}\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n  bottom: 0;\n  right: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #000000;\n}\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-width: 5px 0 5px 5px;\n  border-left-color: #000000;\n}\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1060;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  font-family: Cantarell, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 14px;\n  background-color: #ffffff;\n  background-clip: padding-box;\n  border: 1px solid #cccccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n  margin-top: -10px;\n}\n.popover.right {\n  margin-left: 10px;\n}\n.popover.bottom {\n  margin-top: 10px;\n}\n.popover.left {\n  margin-left: -10px;\n}\n.popover-title {\n  margin: 0;\n  padding: 8px 14px;\n  font-size: 14px;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  border-radius: 5px 5px 0 0;\n}\n.popover-content {\n  padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n  position: absolute;\n  display: block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.popover > .arrow {\n  border-width: 11px;\n}\n.popover > .arrow:after {\n  border-width: 10px;\n  content: \"\";\n}\n.popover.top > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-bottom-width: 0;\n  border-top-color: #999999;\n  border-top-color: rgba(0, 0, 0, 0.25);\n  bottom: -11px;\n}\n.popover.top > .arrow:after {\n  content: \" \";\n  bottom: 1px;\n  margin-left: -10px;\n  border-bottom-width: 0;\n  border-top-color: #ffffff;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-left-width: 0;\n  border-right-color: #999999;\n  border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n  content: \" \";\n  left: 1px;\n  bottom: -10px;\n  border-left-width: 0;\n  border-right-color: #ffffff;\n}\n.popover.bottom > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999999;\n  border-bottom-color: rgba(0, 0, 0, 0.25);\n  top: -11px;\n}\n.popover.bottom > .arrow:after {\n  content: \" \";\n  top: 1px;\n  margin-left: -10px;\n  border-top-width: 0;\n  border-bottom-color: #ffffff;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999999;\n  border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n  content: \" \";\n  right: 1px;\n  border-right-width: 0;\n  border-left-color: #ffffff;\n  bottom: -10px;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n}\n.carousel-inner > .item {\n  display: none;\n  position: relative;\n  -webkit-transition: 0.6s ease-in-out left;\n  -o-transition: 0.6s ease-in-out left;\n  transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n  .carousel-inner > .item {\n    -webkit-transition: -webkit-transform 0.6s ease-in-out;\n    -moz-transition: -moz-transform 0.6s ease-in-out;\n    -o-transition: -o-transform 0.6s ease-in-out;\n    transition: transform 0.6s ease-in-out;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    -webkit-perspective: 1000px;\n    -moz-perspective: 1000px;\n    perspective: 1000px;\n  }\n  .carousel-inner > .item.next,\n  .carousel-inner > .item.active.right {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n    left: 0;\n  }\n  .carousel-inner > .item.prev,\n  .carousel-inner > .item.active.left {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n    left: 0;\n  }\n  .carousel-inner > .item.next.left,\n  .carousel-inner > .item.prev.right,\n  .carousel-inner > .item.active {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    left: 0;\n  }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n.carousel-inner > .active {\n  left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel-inner > .next {\n  left: 100%;\n}\n.carousel-inner > .prev {\n  left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n.carousel-inner > .active.left {\n  left: -100%;\n}\n.carousel-inner > .active.right {\n  left: 100%;\n}\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: 15%;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-size: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n  left: auto;\n  right: 0;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  outline: 0;\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n  position: absolute;\n  top: 50%;\n  z-index: 5;\n  display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n  margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n  margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  margin-top: -10px;\n  line-height: 1;\n  font-family: serif;\n}\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  border: 1px solid #ffffff;\n  border-radius: 10px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n  margin: 0;\n  width: 12px;\n  height: 12px;\n  background-color: #ffffff;\n}\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -15px;\n    font-size: 30px;\n  }\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .icon-prev {\n    margin-left: -15px;\n  }\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-next {\n    margin-right: -15px;\n  }\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n  content: \" \";\n  display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n.hidden {\n  display: none !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n  table.visible-xs {\n    display: table !important;\n  }\n  tr.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-block {\n    display: block !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline {\n    display: inline !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n  table.visible-sm {\n    display: table !important;\n  }\n  tr.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-block {\n    display: block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n  table.visible-md {\n    display: table !important;\n  }\n  tr.visible-md {\n    display: table-row !important;\n  }\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-block {\n    display: block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n  table.visible-lg {\n    display: table !important;\n  }\n  tr.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-block {\n    display: block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n  table.visible-print {\n    display: table !important;\n  }\n  tr.visible-print {\n    display: table-row !important;\n  }\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n.visible-print-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-block {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline-block {\n    display: inline-block !important;\n  }\n}\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\n/*# sourceMappingURL=bootstrap.css.map */","/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS and IE text size adjust after device orientation change,\n//    without disabling user zoom.\n//\n\nhtml {\n  font-family: sans-serif; // 1\n  -ms-text-size-adjust: 100%; // 2\n  -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n  margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; // 1\n  vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n  background-color: transparent;\n}\n\n//\n// Improve readability of focused elements when they are also in an\n// active/hover state.\n//\n\na:active,\na:hover {\n  outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n  font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n  font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n  border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n  margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n  overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n//    Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; // 1\n  font: inherit; // 2\n  margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n  overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n//    and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n//    `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; // 2\n  cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n  line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; // 1\n  padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n//\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; // 1\n  box-sizing: content-box; //2\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n  border: 0; // 1\n  padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n  overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n  font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n","/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n    *,\n    *:before,\n    *:after {\n        background: transparent !important;\n        color: #000 !important; // Black prints faster: h5bp.com/s\n        box-shadow: none !important;\n        text-shadow: none !important;\n    }\n\n    a,\n    a:visited {\n        text-decoration: underline;\n    }\n\n    a[href]:after {\n        content: \" (\" attr(href) \")\";\n    }\n\n    abbr[title]:after {\n        content: \" (\" attr(title) \")\";\n    }\n\n    // Don't show links that are fragment identifiers,\n    // or use the `javascript:` pseudo protocol\n    a[href^=\"#\"]:after,\n    a[href^=\"javascript:\"]:after {\n        content: \"\";\n    }\n\n    pre,\n    blockquote {\n        border: 1px solid #999;\n        page-break-inside: avoid;\n    }\n\n    thead {\n        display: table-header-group; // h5bp.com/t\n    }\n\n    tr,\n    img {\n        page-break-inside: avoid;\n    }\n\n    img {\n        max-width: 100% !important;\n    }\n\n    p,\n    h2,\n    h3 {\n        orphans: 3;\n        widows: 3;\n    }\n\n    h2,\n    h3 {\n        page-break-after: avoid;\n    }\n\n    // Bootstrap specific changes start\n\n    // Bootstrap components\n    .navbar {\n        display: none;\n    }\n    .btn,\n    .dropup > .btn {\n        > .caret {\n            border-top-color: #000 !important;\n        }\n    }\n    .label {\n        border: 1px solid #000;\n    }\n\n    .table {\n        border-collapse: collapse !important;\n\n        td,\n        th {\n            background-color: #fff !important;\n        }\n    }\n    .table-bordered {\n        th,\n        td {\n            border: 1px solid #ddd !important;\n        }\n    }\n\n    // Bootstrap specific changes end\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// <a href=\"#\"><span class=\"glyphicon glyphicon-star\"></span> Star</a>\n\n// Import the fonts\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: url('@{icon-font-path}@{icon-font-name}.eot');\n  src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n       url('@{icon-font-path}@{icon-font-name}.woff2') format('woff2'),\n       url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n       url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n       url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk               { &:before { content: \"\\2a\"; } }\n.glyphicon-plus                   { &:before { content: \"\\2b\"; } }\n.glyphicon-euro,\n.glyphicon-eur                    { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus                  { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud                  { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope               { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil                 { &:before { content: \"\\270f\"; } }\n.glyphicon-glass                  { &:before { content: \"\\e001\"; } }\n.glyphicon-music                  { &:before { content: \"\\e002\"; } }\n.glyphicon-search                 { &:before { content: \"\\e003\"; } }\n.glyphicon-heart                  { &:before { content: \"\\e005\"; } }\n.glyphicon-star                   { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty             { &:before { content: \"\\e007\"; } }\n.glyphicon-user                   { &:before { content: \"\\e008\"; } }\n.glyphicon-film                   { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large               { &:before { content: \"\\e010\"; } }\n.glyphicon-th                     { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list                { &:before { content: \"\\e012\"; } }\n.glyphicon-ok                     { &:before { content: \"\\e013\"; } }\n.glyphicon-remove                 { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in                { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out               { &:before { content: \"\\e016\"; } }\n.glyphicon-off                    { &:before { content: \"\\e017\"; } }\n.glyphicon-signal                 { &:before { content: \"\\e018\"; } }\n.glyphicon-cog                    { &:before { content: \"\\e019\"; } }\n.glyphicon-trash                  { &:before { content: \"\\e020\"; } }\n.glyphicon-home                   { &:before { content: \"\\e021\"; } }\n.glyphicon-file                   { &:before { content: \"\\e022\"; } }\n.glyphicon-time                   { &:before { content: \"\\e023\"; } }\n.glyphicon-road                   { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt           { &:before { content: \"\\e025\"; } }\n.glyphicon-download               { &:before { content: \"\\e026\"; } }\n.glyphicon-upload                 { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox                  { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle            { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat                 { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh                { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt               { &:before { content: \"\\e032\"; } }\n.glyphicon-lock                   { &:before { content: \"\\e033\"; } }\n.glyphicon-flag                   { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones             { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off             { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down            { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up              { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode                 { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode                { &:before { content: \"\\e040\"; } }\n.glyphicon-tag                    { &:before { content: \"\\e041\"; } }\n.glyphicon-tags                   { &:before { content: \"\\e042\"; } }\n.glyphicon-book                   { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark               { &:before { content: \"\\e044\"; } }\n.glyphicon-print                  { &:before { content: \"\\e045\"; } }\n.glyphicon-camera                 { &:before { content: \"\\e046\"; } }\n.glyphicon-font                   { &:before { content: \"\\e047\"; } }\n.glyphicon-bold                   { &:before { content: \"\\e048\"; } }\n.glyphicon-italic                 { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height            { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width             { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left             { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center           { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right            { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify          { &:before { content: \"\\e055\"; } }\n.glyphicon-list                   { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left            { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right           { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video         { &:before { content: \"\\e059\"; } }\n.glyphicon-picture                { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker             { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust                 { &:before { content: \"\\e063\"; } }\n.glyphicon-tint                   { &:before { content: \"\\e064\"; } }\n.glyphicon-edit                   { &:before { content: \"\\e065\"; } }\n.glyphicon-share                  { &:before { content: \"\\e066\"; } }\n.glyphicon-check                  { &:before { content: \"\\e067\"; } }\n.glyphicon-move                   { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward          { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward          { &:before { content: \"\\e070\"; } }\n.glyphicon-backward               { &:before { content: \"\\e071\"; } }\n.glyphicon-play                   { &:before { content: \"\\e072\"; } }\n.glyphicon-pause                  { &:before { content: \"\\e073\"; } }\n.glyphicon-stop                   { &:before { content: \"\\e074\"; } }\n.glyphicon-forward                { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward           { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward           { &:before { content: \"\\e077\"; } }\n.glyphicon-eject                  { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left           { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right          { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign              { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign             { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign            { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign                { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign          { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign              { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot             { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle          { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle              { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle             { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left             { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right            { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up               { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down             { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt              { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full            { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small           { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign       { &:before { content: \"\\e101\"; } }\n.glyphicon-gift                   { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf                   { &:before { content: \"\\e103\"; } }\n.glyphicon-fire                   { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open               { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close              { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign           { &:before { content: \"\\e107\"; } }\n.glyphicon-plane                  { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar               { &:before { content: \"\\e109\"; } }\n.glyphicon-random                 { &:before { content: \"\\e110\"; } }\n.glyphicon-comment                { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet                 { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up             { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down           { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet                { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart          { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close           { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open            { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical        { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal      { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd                    { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn               { &:before { content: \"\\e122\"; } }\n.glyphicon-bell                   { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate            { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up              { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down            { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right             { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left              { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up                { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down              { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right     { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left      { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up        { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down      { &:before { content: \"\\e134\"; } }\n.glyphicon-globe                  { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench                 { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks                  { &:before { content: \"\\e137\"; } }\n.glyphicon-filter                 { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase              { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen             { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard              { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip              { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty            { &:before { content: \"\\e143\"; } }\n.glyphicon-link                   { &:before { content: \"\\e144\"; } }\n.glyphicon-phone                  { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin                { &:before { content: \"\\e146\"; } }\n.glyphicon-usd                    { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp                    { &:before { content: \"\\e149\"; } }\n.glyphicon-sort                   { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet       { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt   { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order          { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt      { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes     { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked              { &:before { content: \"\\e157\"; } }\n.glyphicon-expand                 { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down          { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up            { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in                 { &:before { content: \"\\e161\"; } }\n.glyphicon-flash                  { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out                { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window             { &:before { content: \"\\e164\"; } }\n.glyphicon-record                 { &:before { content: \"\\e165\"; } }\n.glyphicon-save                   { &:before { content: \"\\e166\"; } }\n.glyphicon-open                   { &:before { content: \"\\e167\"; } }\n.glyphicon-saved                  { &:before { content: \"\\e168\"; } }\n.glyphicon-import                 { &:before { content: \"\\e169\"; } }\n.glyphicon-export                 { &:before { content: \"\\e170\"; } }\n.glyphicon-send                   { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk            { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved           { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove          { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save            { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open            { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card            { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer               { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery                { &:before { content: \"\\e179\"; } }\n.glyphicon-header                 { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed             { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone               { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt              { &:before { content: \"\\e183\"; } }\n.glyphicon-tower                  { &:before { content: \"\\e184\"; } }\n.glyphicon-stats                  { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video               { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video               { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles              { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo           { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby            { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1              { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1              { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1              { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark         { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark      { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download         { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload           { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer           { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous         { &:before { content: \"\\e200\"; } }\n.glyphicon-cd                     { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file              { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file              { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up               { &:before { content: \"\\e204\"; } }\n.glyphicon-copy                   { &:before { content: \"\\e205\"; } }\n.glyphicon-paste                  { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door                   { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key                    { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert                  { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer              { &:before { content: \"\\e210\"; } }\n.glyphicon-king                   { &:before { content: \"\\e211\"; } }\n.glyphicon-queen                  { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn                   { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop                 { &:before { content: \"\\e214\"; } }\n.glyphicon-knight                 { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula           { &:before { content: \"\\e216\"; } }\n.glyphicon-tent                   { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard             { &:before { content: \"\\e218\"; } }\n.glyphicon-bed                    { &:before { content: \"\\e219\"; } }\n.glyphicon-apple                  { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase                  { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass              { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp                   { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate              { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank             { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors               { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin                { &:before { content: \"\\e227\"; } }\n.glyphicon-btc                    { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt                    { &:before { content: \"\\e227\"; } }\n.glyphicon-yen                    { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy                    { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble                  { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub                    { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale                  { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly              { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted       { &:before { content: \"\\e232\"; } }\n.glyphicon-education              { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal      { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical        { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger         { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window           { &:before { content: \"\\e237\"; } }\n.glyphicon-oil                    { &:before { content: \"\\e238\"; } }\n.glyphicon-grain                  { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses             { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size              { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color             { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background        { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top       { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom    { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left      { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical  { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right     { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right         { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left          { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom        { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top           { &:before { content: \"\\e253\"; } }\n.glyphicon-console                { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript            { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript              { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left              { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right             { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down              { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up                { &:before { content: \"\\e260\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n  .box-sizing(border-box);\n}\n*:before,\n*:after {\n  .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n  font-size: 10px;\n  -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n  font-family: @font-family-base;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @text-color;\n  background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\n\n// Links\n\na {\n  color: @link-color;\n  text-decoration: none;\n\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: @link-hover-decoration;\n  }\n\n  &:focus {\n    .tab-focus();\n  }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n  margin: 0;\n}\n\n\n// Images\n\nimg {\n  vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n  .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n  border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n  padding: @thumbnail-padding;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(all .2s ease-in-out);\n\n  // Keep them at most 100% wide\n  .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n  border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n  margin-top:    @line-height-computed;\n  margin-bottom: @line-height-computed;\n  border: 0;\n  border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0,0,0,0);\n  border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n  &:active,\n  &:focus {\n    position: static;\n    width: auto;\n    height: auto;\n    margin: 0;\n    overflow: visible;\n    clip: auto;\n  }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n// Upstream patch for normalize.css submitted: https://github.com/necolas/normalize.css/pull/379 - remove this fix once that is merged\n\n[role=\"button\"] {\n  cursor: pointer;\n}","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n  -webkit-animation: @animation;\n       -o-animation: @animation;\n          animation: @animation;\n}\n.animation-name(@name) {\n  -webkit-animation-name: @name;\n          animation-name: @name;\n}\n.animation-duration(@duration) {\n  -webkit-animation-duration: @duration;\n          animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n  -webkit-animation-timing-function: @timing-function;\n          animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n  -webkit-animation-delay: @delay;\n          animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n  -webkit-animation-iteration-count: @iteration-count;\n          animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n  -webkit-animation-direction: @direction;\n          animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n  -webkit-animation-fill-mode: @fill-mode;\n          animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n  -webkit-backface-visibility: @visibility;\n     -moz-backface-visibility: @visibility;\n          backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n  -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n          box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n  -webkit-box-sizing: @boxmodel;\n     -moz-box-sizing: @boxmodel;\n          box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n  -webkit-column-count: @column-count;\n     -moz-column-count: @column-count;\n          column-count: @column-count;\n  -webkit-column-gap: @column-gap;\n     -moz-column-gap: @column-gap;\n          column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n  word-wrap: break-word;\n  -webkit-hyphens: @mode;\n     -moz-hyphens: @mode;\n      -ms-hyphens: @mode; // IE10+\n       -o-hyphens: @mode;\n          hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n  // Firefox\n  &::-moz-placeholder {\n    color: @color;\n    opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n  }\n  &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n  &::-webkit-input-placeholder  { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n  -webkit-transform: scale(@ratio);\n      -ms-transform: scale(@ratio); // IE9 only\n       -o-transform: scale(@ratio);\n          transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n  -webkit-transform: scale(@ratioX, @ratioY);\n      -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n       -o-transform: scale(@ratioX, @ratioY);\n          transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n  -webkit-transform: scaleX(@ratio);\n      -ms-transform: scaleX(@ratio); // IE9 only\n       -o-transform: scaleX(@ratio);\n          transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n  -webkit-transform: scaleY(@ratio);\n      -ms-transform: scaleY(@ratio); // IE9 only\n       -o-transform: scaleY(@ratio);\n          transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n  -webkit-transform: skewX(@x) skewY(@y);\n      -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n       -o-transform: skewX(@x) skewY(@y);\n          transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n  -webkit-transform: translate(@x, @y);\n      -ms-transform: translate(@x, @y); // IE9 only\n       -o-transform: translate(@x, @y);\n          transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n  -webkit-transform: translate3d(@x, @y, @z);\n          transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n  -webkit-transform: rotate(@degrees);\n      -ms-transform: rotate(@degrees); // IE9 only\n       -o-transform: rotate(@degrees);\n          transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n  -webkit-transform: rotateX(@degrees);\n      -ms-transform: rotateX(@degrees); // IE9 only\n       -o-transform: rotateX(@degrees);\n          transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n  -webkit-transform: rotateY(@degrees);\n      -ms-transform: rotateY(@degrees); // IE9 only\n       -o-transform: rotateY(@degrees);\n          transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n  -webkit-perspective: @perspective;\n     -moz-perspective: @perspective;\n          perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n  -webkit-perspective-origin: @perspective;\n     -moz-perspective-origin: @perspective;\n          perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n  -webkit-transform-origin: @origin;\n     -moz-transform-origin: @origin;\n      -ms-transform-origin: @origin; // IE9 only\n          transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n  -webkit-transition: @transition;\n       -o-transition: @transition;\n          transition: @transition;\n}\n.transition-property(@transition-property) {\n  -webkit-transition-property: @transition-property;\n          transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n  -webkit-transition-delay: @transition-delay;\n          transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n  -webkit-transition-duration: @transition-duration;\n          transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n  -webkit-transition-timing-function: @timing-function;\n          transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n  -webkit-transition: -webkit-transform @transition;\n     -moz-transition: -moz-transform @transition;\n       -o-transition: -o-transform @transition;\n          transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n  -webkit-user-select: @select;\n     -moz-user-select: @select;\n      -ms-user-select: @select; // IE10+\n          user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n  // Default\n  outline: thin dotted;\n  // WebKit\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n  display: @display;\n  max-width: 100%; // Part 1: Set a maximum relative to the parent\n  height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n  background-image: url(\"@{file-1x}\");\n\n  @media\n  only screen and (-webkit-min-device-pixel-ratio: 2),\n  only screen and (   min--moz-device-pixel-ratio: 2),\n  only screen and (     -o-min-device-pixel-ratio: 2/1),\n  only screen and (        min-device-pixel-ratio: 2),\n  only screen and (                min-resolution: 192dpi),\n  only screen and (                min-resolution: 2dppx) {\n    background-image: url(\"@{file-2x}\");\n    background-size: @width-1x @height-1x;\n  }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n  font-family: @headings-font-family;\n  font-weight: @headings-font-weight;\n  line-height: @headings-line-height;\n  color: @headings-color;\n\n  small,\n  .small {\n    font-weight: normal;\n    line-height: 1;\n    color: @headings-small-color;\n  }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n  margin-top: @line-height-computed;\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 65%;\n  }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n  margin-top: (@line-height-computed / 2);\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 75%;\n  }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n  margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n  margin-bottom: @line-height-computed;\n  font-size: floor((@font-size-base * 1.15));\n  font-weight: 300;\n  line-height: 1.4;\n\n  @media (min-width: @screen-sm-min) {\n    font-size: (@font-size-base * 1.5);\n  }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n  font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n  background-color: @state-warning-bg;\n  padding: .2em;\n}\n\n// Alignment\n.text-left           { text-align: left; }\n.text-right          { text-align: right; }\n.text-center         { text-align: center; }\n.text-justify        { text-align: justify; }\n.text-nowrap         { white-space: nowrap; }\n\n// Transformation\n.text-lowercase      { text-transform: lowercase; }\n.text-uppercase      { text-transform: uppercase; }\n.text-capitalize     { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n  color: @text-muted;\n}\n.text-primary {\n  .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n  .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n  .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n  .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n  .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n  // Given the contrast here, this is the only class to have its color inverted\n  // automatically.\n  color: #fff;\n  .bg-variant(@brand-primary);\n}\n.bg-success {\n  .bg-variant(@state-success-bg);\n}\n.bg-info {\n  .bg-variant(@state-info-bg);\n}\n.bg-warning {\n  .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n  .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n  padding-bottom: ((@line-height-computed / 2) - 1);\n  margin: (@line-height-computed * 2) 0 @line-height-computed;\n  border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n  margin-top: 0;\n  margin-bottom: (@line-height-computed / 2);\n  ul,\n  ol {\n    margin-bottom: 0;\n  }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n  .list-unstyled();\n  margin-left: -5px;\n\n  > li {\n    display: inline-block;\n    padding-left: 5px;\n    padding-right: 5px;\n  }\n}\n\n// Description Lists\ndl {\n  margin-top: 0; // Remove browser default\n  margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n  line-height: @line-height-base;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n  dd {\n    &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    dt {\n      float: left;\n      width: (@dl-horizontal-offset - 20);\n      clear: left;\n      text-align: right;\n      .text-overflow();\n    }\n    dd {\n      margin-left: @dl-horizontal-offset;\n    }\n  }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n  font-size: 90%;\n  .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n  padding: (@line-height-computed / 2) @line-height-computed;\n  margin: 0 0 @line-height-computed;\n  font-size: @blockquote-font-size;\n  border-left: 5px solid @blockquote-border-color;\n\n  p,\n  ul,\n  ol {\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  // Note: Deprecated small and .small as of v3.1.0\n  // Context: https://github.com/twbs/bootstrap/issues/11660\n  footer,\n  small,\n  .small {\n    display: block;\n    font-size: 80%; // back to default font-size\n    line-height: @line-height-base;\n    color: @blockquote-small-color;\n\n    &:before {\n      content: '\\2014 \\00A0'; // em dash, nbsp\n    }\n  }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid @blockquote-border-color;\n  border-left: 0;\n  text-align: right;\n\n  // Account for citation\n  footer,\n  small,\n  .small {\n    &:before { content: ''; }\n    &:after {\n      content: '\\00A0 \\2014'; // nbsp, em dash\n    }\n  }\n}\n\n// Addresses\naddress {\n  margin-bottom: @line-height-computed;\n  font-style: normal;\n  line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n  color: @color;\n  a&:hover,\n  a&:focus {\n    color: darken(@color, 10%);\n  }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n  background-color: @color;\n  a&:hover,\n  a&:focus {\n    background-color: darken(@color, 10%);\n  }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n  font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @code-color;\n  background-color: @code-bg;\n  border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @kbd-color;\n  background-color: @kbd-bg;\n  border-radius: @border-radius-small;\n  box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n  kbd {\n    padding: 0;\n    font-size: 100%;\n    font-weight: bold;\n    box-shadow: none;\n  }\n}\n\n// Blocks of code\npre {\n  display: block;\n  padding: ((@line-height-computed - 1) / 2);\n  margin: 0 0 (@line-height-computed / 2);\n  font-size: (@font-size-base - 1); // 14px to 13px\n  line-height: @line-height-base;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: @pre-color;\n  background-color: @pre-bg;\n  border: 1px solid @pre-border-color;\n  border-radius: @border-radius-base;\n\n  // Account for some code outputs that place code tags in pre tags\n  code {\n    padding: 0;\n    font-size: inherit;\n    color: inherit;\n    white-space: pre-wrap;\n    background-color: transparent;\n    border-radius: 0;\n  }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n  max-height: @pre-scrollable-max-height;\n  overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n  .container-fixed();\n\n  @media (min-width: @screen-sm-min) {\n    width: @container-sm;\n  }\n  @media (min-width: @screen-md-min) {\n    width: @container-md;\n  }\n  @media (min-width: @screen-lg-min) {\n    width: @container-lg;\n  }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n  .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n  .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n  .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n  .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n  .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n  &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n  margin-left:  (@gutter / -2);\n  margin-right: (@gutter / -2);\n  &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  float: left;\n  width: percentage((@columns / @grid-columns));\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n  margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n  left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n  right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-sm-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-offset(@columns) {\n  @media (min-width: @screen-sm-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-push(@columns) {\n  @media (min-width: @screen-sm-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-pull(@columns) {\n  @media (min-width: @screen-sm-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-md-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-offset(@columns) {\n  @media (min-width: @screen-md-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-push(@columns) {\n  @media (min-width: @screen-md-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-pull(@columns) {\n  @media (min-width: @screen-md-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-lg-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-offset(@columns) {\n  @media (min-width: @screen-lg-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-push(@columns) {\n  @media (min-width: @screen-lg-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-pull(@columns) {\n  @media (min-width: @screen-lg-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n  // Common styles for all sizes of grid columns, widths 1-12\n  .col(@index) { // initial\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      position: relative;\n      // Prevent columns from collapsing when empty\n      min-height: 1px;\n      // Inner gutter via padding\n      padding-left:  (@grid-gutter-width / 2);\n      padding-right: (@grid-gutter-width / 2);\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n  .col(@index) { // initial\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      float: left;\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n  .col-@{class}-@{index} {\n    width: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n  .col-@{class}-push-@{index} {\n    left: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n  .col-@{class}-push-0 {\n    left: auto;\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n  .col-@{class}-pull-@{index} {\n    right: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n  .col-@{class}-pull-0 {\n    right: auto;\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n  .col-@{class}-offset-@{index} {\n    margin-left: percentage((@index / @grid-columns));\n  }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n  .calc-grid-column(@index, @class, @type);\n  // next iteration\n  .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n  .float-grid-columns(@class);\n  .loop-grid-columns(@grid-columns, @class, width);\n  .loop-grid-columns(@grid-columns, @class, pull);\n  .loop-grid-columns(@grid-columns, @class, push);\n  .loop-grid-columns(@grid-columns, @class, offset);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n  background-color: @table-bg;\n}\ncaption {\n  padding-top: @table-cell-padding;\n  padding-bottom: @table-cell-padding;\n  color: @text-muted;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: @line-height-computed;\n  // Cells\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-cell-padding;\n        line-height: @line-height-base;\n        vertical-align: top;\n        border-top: 1px solid @table-border-color;\n      }\n    }\n  }\n  // Bottom align for column headings\n  > thead > tr > th {\n    vertical-align: bottom;\n    border-bottom: 2px solid @table-border-color;\n  }\n  // Remove top border from thead by default\n  > caption + thead,\n  > colgroup + thead,\n  > thead:first-child {\n    > tr:first-child {\n      > th,\n      > td {\n        border-top: 0;\n      }\n    }\n  }\n  // Account for multiple tbody instances\n  > tbody + tbody {\n    border-top: 2px solid @table-border-color;\n  }\n\n  // Nesting\n  .table {\n    background-color: @body-bg;\n  }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-condensed-cell-padding;\n      }\n    }\n  }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n  border: 1px solid @table-border-color;\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        border: 1px solid @table-border-color;\n      }\n    }\n  }\n  > thead > tr {\n    > th,\n    > td {\n      border-bottom-width: 2px;\n    }\n  }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n  > tbody > tr:nth-of-type(odd) {\n    background-color: @table-bg-accent;\n  }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n  > tbody > tr:hover {\n    background-color: @table-bg-hover;\n  }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n  position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n  float: none;\n  display: table-column;\n}\ntable {\n  td,\n  th {\n    &[class*=\"col-\"] {\n      position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n      float: none;\n      display: table-cell;\n    }\n  }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n  overflow-x: auto;\n  min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n  @media screen and (max-width: @screen-xs-max) {\n    width: 100%;\n    margin-bottom: (@line-height-computed * 0.75);\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid @table-border-color;\n\n    // Tighten up spacing\n    > .table {\n      margin-bottom: 0;\n\n      // Ensure the content doesn't wrap\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th,\n          > td {\n            white-space: nowrap;\n          }\n        }\n      }\n    }\n\n    // Special overrides for the bordered tables\n    > .table-bordered {\n      border: 0;\n\n      // Nuke the appropriate borders so that the parent can handle them\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th:first-child,\n          > td:first-child {\n            border-left: 0;\n          }\n          > th:last-child,\n          > td:last-child {\n            border-right: 0;\n          }\n        }\n      }\n\n      // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n      // chances are there will be only one `tr` in a `thead` and that would\n      // remove the border altogether.\n      > tbody,\n      > tfoot {\n        > tr:last-child {\n          > th,\n          > td {\n            border-bottom: 0;\n          }\n        }\n      }\n\n    }\n  }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n  // Exact selectors below required to override `.table-striped` and prevent\n  // inheritance to nested tables.\n  .table > thead > tr,\n  .table > tbody > tr,\n  .table > tfoot > tr {\n    > td.@{state},\n    > th.@{state},\n    &.@{state} > td,\n    &.@{state} > th {\n      background-color: @background;\n    }\n  }\n\n  // Hover states for `.table-hover`\n  // Note: this is not available for cells or rows within `thead` or `tfoot`.\n  .table-hover > tbody > tr {\n    > td.@{state}:hover,\n    > th.@{state}:hover,\n    &.@{state}:hover > td,\n    &:hover > .@{state},\n    &.@{state}:hover > th {\n      background-color: darken(@background, 5%);\n    }\n  }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n  // so we reset that to ensure it behaves more like a standard block element.\n  // See https://github.com/twbs/bootstrap/issues/12359.\n  min-width: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: @line-height-computed;\n  font-size: (@font-size-base * 1.5);\n  line-height: inherit;\n  color: @legend-color;\n  border: 0;\n  border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n  display: inline-block;\n  max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n  .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9; // IE8-9\n  line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n  display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  .tab-focus();\n}\n\n// Adjust output element\noutput {\n  display: block;\n  padding-top: (@padding-base-vertical + 1);\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n  display: block;\n  width: 100%;\n  height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n  background-color: @input-bg;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid @input-border;\n  border-radius: @input-border-radius; // Note: This has no effect on <select>s in some browsers, due to the limited stylability of <select>s in CSS.\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n  .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n  // Customize the `:focus` state to imitate native WebKit styles.\n  .form-control-focus();\n\n  // Placeholder\n  .placeholder();\n\n  // Disabled and read-only inputs\n  //\n  // HTML5 says that controls under a fieldset > legend:first-child won't be\n  // disabled if the fieldset is disabled. Due to implementation difficulty, we\n  // don't honor that edge case; we style them as disabled anyway.\n  &[disabled],\n  &[readonly],\n  fieldset[disabled] & {\n    background-color: @input-bg-disabled;\n    opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655\n  }\n\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n  }\n\n  // Reset height for `textarea`s\n  textarea& {\n    height: auto;\n  }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n\n\n// Special styles for iOS temporal inputs\n//\n// In Mobile Safari, setting `display: block` on temporal inputs causes the\n// text within the input to become vertically misaligned. As a workaround, we\n// set a pixel line-height that matches the given height of the input, but only\n// for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848\n\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"],\n  input[type=\"time\"],\n  input[type=\"datetime-local\"],\n  input[type=\"month\"] {\n    line-height: @input-height-base;\n\n    &.input-sm,\n    .input-group-sm & {\n      line-height: @input-height-small;\n    }\n\n    &.input-lg,\n    .input-group-lg & {\n      line-height: @input-height-large;\n    }\n  }\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n  margin-bottom: @form-group-margin-bottom;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n\n  label {\n    min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text\n    padding-left: 20px;\n    margin-bottom: 0;\n    font-weight: normal;\n    cursor: pointer;\n  }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  position: absolute;\n  margin-left: -20px;\n  margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n// Some special care is needed because <label>s don't inherit their parent's `cursor`.\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  &[disabled],\n  &.disabled,\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n  }\n}\n// These classes are used directly on <label>s\n.radio-inline,\n.checkbox-inline {\n  &.disabled,\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n  }\n}\n// These classes are used on elements with <label> descendants\n.radio,\n.checkbox {\n  &.disabled,\n  fieldset[disabled] & {\n    label {\n      cursor: @cursor-disabled;\n    }\n  }\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n  // Size it appropriately next to real form controls\n  padding-top: (@padding-base-vertical + 1);\n  padding-bottom: (@padding-base-vertical + 1);\n  // Remove default margin from `p`\n  margin-bottom: 0;\n  min-height: (@line-height-computed + @font-size-base);\n\n  &.input-lg,\n  &.input-sm {\n    padding-left: 0;\n    padding-right: 0;\n  }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n//\n// The `.form-group-* form-control` variations are sadly duplicated to avoid the\n// issue documented in https://github.com/twbs/bootstrap/issues/15074.\n\n.input-sm {\n  .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @input-border-radius-small);\n}\n.form-group-sm {\n  .form-control {\n    height: @input-height-small;\n    padding: @padding-small-vertical @padding-small-horizontal;\n    font-size: @font-size-small;\n    line-height: @line-height-small;\n    border-radius: @input-border-radius-small;\n  }\n  select.form-control {\n    height: @input-height-small;\n    line-height: @input-height-small;\n  }\n  textarea.form-control,\n  select[multiple].form-control {\n    height: auto;\n  }\n  .form-control-static {\n    height: @input-height-small;\n    min-height: (@line-height-computed + @font-size-small);\n    padding: (@padding-small-vertical + 1) @padding-small-horizontal;\n    font-size: @font-size-small;\n    line-height: @line-height-small;\n  }\n}\n\n.input-lg {\n  .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @input-border-radius-large);\n}\n.form-group-lg {\n  .form-control {\n    height: @input-height-large;\n    padding: @padding-large-vertical @padding-large-horizontal;\n    font-size: @font-size-large;\n    line-height: @line-height-large;\n    border-radius: @input-border-radius-large;\n  }\n  select.form-control {\n    height: @input-height-large;\n    line-height: @input-height-large;\n  }\n  textarea.form-control,\n  select[multiple].form-control {\n    height: auto;\n  }\n  .form-control-static {\n    height: @input-height-large;\n    min-height: (@line-height-computed + @font-size-large);\n    padding: (@padding-large-vertical + 1) @padding-large-horizontal;\n    font-size: @font-size-large;\n    line-height: @line-height-large;\n  }\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n  // Enable absolute positioning\n  position: relative;\n\n  // Ensure icons don't overlap text\n  .form-control {\n    padding-right: (@input-height-base * 1.25);\n  }\n}\n// Feedback icon (requires .glyphicon classes)\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2; // Ensure icon is above input groups\n  display: block;\n  width: @input-height-base;\n  height: @input-height-base;\n  line-height: @input-height-base;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback {\n  width: @input-height-large;\n  height: @input-height-large;\n  line-height: @input-height-large;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback {\n  width: @input-height-small;\n  height: @input-height-small;\n  line-height: @input-height-small;\n}\n\n// Feedback states\n.has-success {\n  .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n  .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n  .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n// Reposition feedback icon if input has visible label above\n.has-feedback label {\n\n  & ~ .form-control-feedback {\n     top: (@line-height-computed + 5); // Height of the `label` and its margin\n  }\n  &.sr-only ~ .form-control-feedback {\n     top: 0;\n  }\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n  display: block; // account for any element using help-block\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n  // Kick in the inline\n  @media (min-width: @screen-sm-min) {\n    // Inline-block all the things for \"inline\"\n    .form-group {\n      display: inline-block;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // In navbar-form, allow folks to *not* use `.form-group`\n    .form-control {\n      display: inline-block;\n      width: auto; // Prevent labels from stacking above inputs in `.form-group`\n      vertical-align: middle;\n    }\n\n    // Make static controls behave like regular ones\n    .form-control-static {\n      display: inline-block;\n    }\n\n    .input-group {\n      display: inline-table;\n      vertical-align: middle;\n\n      .input-group-addon,\n      .input-group-btn,\n      .form-control {\n        width: auto;\n      }\n    }\n\n    // Input groups need that 100% width though\n    .input-group > .form-control {\n      width: 100%;\n    }\n\n    .control-label {\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // Remove default margin on radios/checkboxes that were used for stacking, and\n    // then undo the floating of radios and checkboxes to match.\n    .radio,\n    .checkbox {\n      display: inline-block;\n      margin-top: 0;\n      margin-bottom: 0;\n      vertical-align: middle;\n\n      label {\n        padding-left: 0;\n      }\n    }\n    .radio input[type=\"radio\"],\n    .checkbox input[type=\"checkbox\"] {\n      position: relative;\n      margin-left: 0;\n    }\n\n    // Re-override the feedback icon.\n    .has-feedback .form-control-feedback {\n      top: 0;\n    }\n  }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n  // Consistent vertical alignment of radios and checkboxes\n  //\n  // Labels also get some reset styles, but that is scoped to a media query below.\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline {\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n  }\n  // Account for padding we're adding to ensure the alignment and of help text\n  // and other content below items\n  .radio,\n  .checkbox {\n    min-height: (@line-height-computed + (@padding-base-vertical + 1));\n  }\n\n  // Make form groups behave like rows\n  .form-group {\n    .make-row();\n  }\n\n  // Reset spacing and right align labels, but scope to media queries so that\n  // labels on narrow viewports stack the same as a default form example.\n  @media (min-width: @screen-sm-min) {\n    .control-label {\n      text-align: right;\n      margin-bottom: 0;\n      padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n    }\n  }\n\n  // Validation states\n  //\n  // Reposition the icon because it's now within a grid column and columns have\n  // `position: relative;` on them. Also accounts for the grid gutter padding.\n  .has-feedback .form-control-feedback {\n    right: (@grid-gutter-width / 2);\n  }\n\n  // Form group sizes\n  //\n  // Quick utility class for applying `.input-lg` and `.input-sm` styles to the\n  // inputs and labels within a `.form-group`.\n  .form-group-lg {\n    @media (min-width: @screen-sm-min) {\n      .control-label {\n        padding-top: ((@padding-large-vertical * @line-height-large) + 1);\n        font-size: @font-size-large;\n      }\n    }\n  }\n  .form-group-sm {\n    @media (min-width: @screen-sm-min) {\n      .control-label {\n        padding-top: (@padding-small-vertical + 1);\n        font-size: @font-size-small;\n      }\n    }\n  }\n}\n","// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n  // Color the label and help text\n  .help-block,\n  .control-label,\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline,\n  &.radio label,\n  &.checkbox label,\n  &.radio-inline label,\n  &.checkbox-inline label  {\n    color: @text-color;\n  }\n  // Set the border and box shadow on specific inputs to match\n  .form-control {\n    border-color: @border-color;\n    .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n    &:focus {\n      border-color: darken(@border-color, 10%);\n      @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n      .box-shadow(@shadow);\n    }\n  }\n  // Set validation states also for addons\n  .input-group-addon {\n    color: @text-color;\n    border-color: @border-color;\n    background-color: @background-color;\n  }\n  // Optional feedback icon\n  .form-control-feedback {\n    color: @text-color;\n  }\n}\n\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-border-focus` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n.form-control-focus(@color: @input-border-focus) {\n  @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n  &:focus {\n    border-color: @color;\n    outline: 0;\n    .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n  }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  height: @input-height;\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n\n  select& {\n    height: @input-height;\n    line-height: @input-height;\n  }\n\n  textarea&,\n  select[multiple]& {\n    height: auto;\n  }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n  display: inline-block;\n  margin-bottom: 0; // For input.btn\n  font-weight: @btn-font-weight;\n  text-align: center;\n  vertical-align: middle;\n  touch-action: manipulation;\n  cursor: pointer;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  white-space: nowrap;\n  .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);\n  .user-select(none);\n\n  &,\n  &:active,\n  &.active {\n    &:focus,\n    &.focus {\n      .tab-focus();\n    }\n  }\n\n  &:hover,\n  &:focus,\n  &.focus {\n    color: @btn-default-color;\n    text-decoration: none;\n  }\n\n  &:active,\n  &.active {\n    outline: 0;\n    background-image: none;\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n    .opacity(.65);\n    .box-shadow(none);\n  }\n\n  a& {\n    &.disabled,\n    fieldset[disabled] & {\n      pointer-events: none; // Future-proof disabling of clicks on `<a>` elements\n    }\n  }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n  .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n  .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n  .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n  .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n  .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n  .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n  color: @link-color;\n  font-weight: normal;\n  border-radius: 0;\n\n  &,\n  &:active,\n  &.active,\n  &[disabled],\n  fieldset[disabled] & {\n    background-color: transparent;\n    .box-shadow(none);\n  }\n  &,\n  &:hover,\n  &:focus,\n  &:active {\n    border-color: transparent;\n  }\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: @link-hover-decoration;\n    background-color: transparent;\n  }\n  &[disabled],\n  fieldset[disabled] & {\n    &:hover,\n    &:focus {\n      color: @btn-link-disabled-color;\n      text-decoration: none;\n    }\n  }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n  // line-height: ensure even-numbered height of button next to large input\n  .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n.btn-sm {\n  // line-height: ensure proper height of button next to small input\n  .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n.btn-xs {\n  .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n  display: block;\n  width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n  &.btn-block {\n    width: 100%;\n  }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n  color: @color;\n  background-color: @background;\n  border-color: @border;\n\n  &:focus,\n  &.focus {\n    color: @color;\n    background-color: darken(@background, 10%);\n        border-color: darken(@border, 25%);\n  }\n  &:hover {\n    color: @color;\n    background-color: darken(@background, 10%);\n        border-color: darken(@border, 12%);\n  }\n  &:active,\n  &.active,\n  .open > .dropdown-toggle& {\n    color: @color;\n    background-color: darken(@background, 10%);\n        border-color: darken(@border, 12%);\n\n    &:hover,\n    &:focus,\n    &.focus {\n      color: @color;\n      background-color: darken(@background, 17%);\n          border-color: darken(@border, 25%);\n    }\n  }\n  &:active,\n  &.active,\n  .open > .dropdown-toggle& {\n    background-image: none;\n  }\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    &,\n    &:hover,\n    &:focus,\n    &.focus,\n    &:active,\n    &.active {\n      background-color: @background;\n          border-color: @border;\n    }\n  }\n\n  .badge {\n    color: @background;\n    background-color: @color;\n  }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n}\n","// Opacity\n\n.opacity(@opacity) {\n  opacity: @opacity;\n  // IE8 filter\n  @opacity-ie: (@opacity * 100);\n  filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n  opacity: 0;\n  .transition(opacity .15s linear);\n  &.in {\n    opacity: 1;\n  }\n}\n\n.collapse {\n  display: none;\n\n  &.in      { display: block; }\n  tr&.in    { display: table-row; }\n  tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  .transition-property(~\"height, visibility\");\n  .transition-duration(.35s);\n  .transition-timing-function(ease);\n}\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top:   @caret-width-base dashed;\n  border-right: @caret-width-base solid transparent;\n  border-left:  @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropup,\n.dropdown {\n  position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n  outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: @zindex-dropdown;\n  display: none; // none by default, but block on \"open\" of the menu\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0; // override default ul\n  list-style: none;\n  font-size: @font-size-base;\n  text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n  background-color: @dropdown-bg;\n  border: 1px solid @dropdown-fallback-border; // IE8 fallback\n  border: 1px solid @dropdown-border;\n  border-radius: @border-radius-base;\n  .box-shadow(0 6px 12px rgba(0,0,0,.175));\n  background-clip: padding-box;\n\n  // Aligns the dropdown menu to right\n  //\n  // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n  &.pull-right {\n    right: 0;\n    left: auto;\n  }\n\n  // Dividers (basically an hr) within the dropdown\n  .divider {\n    .nav-divider(@dropdown-divider-bg);\n  }\n\n  // Links within the dropdown menu\n  > li > a {\n    display: block;\n    padding: 3px 20px;\n    clear: both;\n    font-weight: normal;\n    line-height: @line-height-base;\n    color: @dropdown-link-color;\n    white-space: nowrap; // prevent links from randomly breaking onto new lines\n  }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    color: @dropdown-link-hover-color;\n    background-color: @dropdown-link-hover-bg;\n  }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-active-color;\n    text-decoration: none;\n    outline: 0;\n    background-color: @dropdown-link-active-bg;\n  }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-disabled-color;\n  }\n\n  // Nuke hover/focus effects\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    background-color: transparent;\n    background-image: none; // Remove CSS gradient\n    .reset-filter();\n    cursor: @cursor-disabled;\n  }\n}\n\n// Open state for the dropdown\n.open {\n  // Show the menu\n  > .dropdown-menu {\n    display: block;\n  }\n\n  // Remove the outline when :focus is triggered\n  > a {\n    outline: 0;\n  }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n  left: auto; // Reset the default from `.dropdown-menu`\n  right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: @font-size-small;\n  line-height: @line-height-base;\n  color: @dropdown-header-color;\n  white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n  // Reverse the caret\n  .caret {\n    border-top: 0;\n    border-bottom: @caret-width-base solid;\n    content: \"\";\n  }\n  // Different positioning for bottom up menu\n  .dropdown-menu {\n    top: auto;\n    bottom: 100%;\n    margin-bottom: 2px;\n  }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-right {\n    .dropdown-menu {\n      .dropdown-menu-right();\n    }\n    // Necessary for overrides of the default right aligned menu.\n    // Will remove come v4 in all likelihood.\n    .dropdown-menu-left {\n      .dropdown-menu-left();\n    }\n  }\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n  height: 1px;\n  margin: ((@line-height-computed / 2) - 1) 0;\n  overflow: hidden;\n  background-color: @color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n  filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle; // match .btn alignment given font-size hack above\n  > .btn {\n    position: relative;\n    float: left;\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active,\n    &.active {\n      z-index: 2;\n    }\n  }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n  .btn + .btn,\n  .btn + .btn-group,\n  .btn-group + .btn,\n  .btn-group + .btn-group {\n    margin-left: -1px;\n  }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n  margin-left: -5px; // Offset the first child's margin\n  &:extend(.clearfix all);\n\n  .btn,\n  .btn-group,\n  .input-group {\n    float: left;\n  }\n  > .btn,\n  > .btn-group,\n  > .input-group {\n    margin-left: 5px;\n  }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  &:not(:last-child):not(.dropdown-toggle) {\n    .border-right-radius(0);\n  }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-right-radius(0);\n  }\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n  .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n  // Show no shadow for `.btn-link` since it has no other button styles.\n  &.btn-link {\n    .box-shadow(none);\n  }\n}\n\n\n// Reposition the caret\n.btn .caret {\n  margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n  border-width: @caret-width-large @caret-width-large 0;\n  border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n  border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n  > .btn,\n  > .btn-group,\n  > .btn-group > .btn {\n    display: block;\n    float: none;\n    width: 100%;\n    max-width: 100%;\n  }\n\n  // Clear floats so dropdown menus can be properly placed\n  > .btn-group {\n    &:extend(.clearfix all);\n    > .btn {\n      float: none;\n    }\n  }\n\n  > .btn + .btn,\n  > .btn + .btn-group,\n  > .btn-group + .btn,\n  > .btn-group + .btn-group {\n    margin-top: -1px;\n    margin-left: 0;\n  }\n}\n\n.btn-group-vertical > .btn {\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n  &:first-child:not(:last-child) {\n    border-top-right-radius: @border-radius-base;\n    .border-bottom-radius(0);\n  }\n  &:last-child:not(:first-child) {\n    border-bottom-left-radius: @border-radius-base;\n    .border-top-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-bottom-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n  > .btn,\n  > .btn-group {\n    float: none;\n    display: table-cell;\n    width: 1%;\n  }\n  > .btn-group .btn {\n    width: 100%;\n  }\n\n  > .btn-group .dropdown-menu {\n    left: auto;\n  }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n  > .btn,\n  > .btn-group > .btn {\n    input[type=\"radio\"],\n    input[type=\"checkbox\"] {\n      position: absolute;\n      clip: rect(0,0,0,0);\n      pointer-events: none;\n    }\n  }\n}\n","// Single side border-radius\n\n.border-top-radius(@radius) {\n  border-top-right-radius: @radius;\n   border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n  border-bottom-right-radius: @radius;\n     border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n  border-bottom-right-radius: @radius;\n   border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n  border-bottom-left-radius: @radius;\n     border-top-left-radius: @radius;\n}\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n  position: relative; // For dropdowns\n  display: table;\n  border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n  // Undo padding and float of grid classes\n  &[class*=\"col-\"] {\n    float: none;\n    padding-left: 0;\n    padding-right: 0;\n  }\n\n  .form-control {\n    // Ensure that the input is always above the *appended* addon button for\n    // proper border colors.\n    position: relative;\n    z-index: 2;\n\n    // IE9 fubars the placeholder attribute in text inputs and the arrows on\n    // select elements in input groups. To fix it, we float the input. Details:\n    // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n    float: left;\n\n    width: 100%;\n    margin-bottom: 0;\n  }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  font-weight: normal;\n  line-height: 1;\n  color: @input-color;\n  text-align: center;\n  background-color: @input-group-addon-bg;\n  border: 1px solid @input-group-addon-border-color;\n  border-radius: @border-radius-base;\n\n  // Sizing\n  &.input-sm {\n    padding: @padding-small-vertical @padding-small-horizontal;\n    font-size: @font-size-small;\n    border-radius: @border-radius-small;\n  }\n  &.input-lg {\n    padding: @padding-large-vertical @padding-large-horizontal;\n    font-size: @font-size-large;\n    border-radius: @border-radius-large;\n  }\n\n  // Nuke default margins from checkboxes and radios to vertically center within.\n  input[type=\"radio\"],\n  input[type=\"checkbox\"] {\n    margin-top: 0;\n  }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  .border-right-radius(0);\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  .border-left-radius(0);\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n  position: relative;\n  // Jankily prevent input button groups from wrapping with `white-space` and\n  // `font-size` in combination with `inline-block` on buttons.\n  font-size: 0;\n  white-space: nowrap;\n\n  // Negative margin for spacing, position for bringing hovered/focused/actived\n  // element above the siblings.\n  > .btn {\n    position: relative;\n    + .btn {\n      margin-left: -1px;\n    }\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active {\n      z-index: 2;\n    }\n  }\n\n  // Negative margin to only have a 1px border between the two\n  &:first-child {\n    > .btn,\n    > .btn-group {\n      margin-right: -1px;\n    }\n  }\n  &:last-child {\n    > .btn,\n    > .btn-group {\n      z-index: 2;\n      margin-left: -1px;\n    }\n  }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n  margin-bottom: 0;\n  padding-left: 0; // Override default ul/ol\n  list-style: none;\n  &:extend(.clearfix all);\n\n  > li {\n    position: relative;\n    display: block;\n\n    > a {\n      position: relative;\n      display: block;\n      padding: @nav-link-padding;\n      &:hover,\n      &:focus {\n        text-decoration: none;\n        background-color: @nav-link-hover-bg;\n      }\n    }\n\n    // Disabled state sets text to gray and nukes hover/tab effects\n    &.disabled > a {\n      color: @nav-disabled-link-color;\n\n      &:hover,\n      &:focus {\n        color: @nav-disabled-link-hover-color;\n        text-decoration: none;\n        background-color: transparent;\n        cursor: @cursor-disabled;\n      }\n    }\n  }\n\n  // Open dropdowns\n  .open > a {\n    &,\n    &:hover,\n    &:focus {\n      background-color: @nav-link-hover-bg;\n      border-color: @link-color;\n    }\n  }\n\n  // Nav dividers (deprecated with v3.0.1)\n  //\n  // This should have been removed in v3 with the dropping of `.nav-list`, but\n  // we missed it. We don't currently support this anywhere, but in the interest\n  // of maintaining backward compatibility in case you use it, it's deprecated.\n  .nav-divider {\n    .nav-divider();\n  }\n\n  // Prevent IE8 from misplacing imgs\n  //\n  // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n  > li > a > img {\n    max-width: none;\n  }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n  border-bottom: 1px solid @nav-tabs-border-color;\n  > li {\n    float: left;\n    // Make the list-items overlay the bottom border\n    margin-bottom: -1px;\n\n    // Actual tabs (as links)\n    > a {\n      margin-right: 2px;\n      line-height: @line-height-base;\n      border: 1px solid transparent;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n      &:hover {\n        border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n      }\n    }\n\n    // Active state, and its :hover to override normal :hover\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-tabs-active-link-hover-color;\n        background-color: @nav-tabs-active-link-hover-bg;\n        border: 1px solid @nav-tabs-active-link-hover-border-color;\n        border-bottom-color: transparent;\n        cursor: default;\n      }\n    }\n  }\n  // pulling this in mainly for less shorthand\n  &.nav-justified {\n    .nav-justified();\n    .nav-tabs-justified();\n  }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n  > li {\n    float: left;\n\n    // Links rendered as pills\n    > a {\n      border-radius: @nav-pills-border-radius;\n    }\n    + li {\n      margin-left: 2px;\n    }\n\n    // Active state\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-pills-active-link-hover-color;\n        background-color: @nav-pills-active-link-hover-bg;\n      }\n    }\n  }\n}\n\n\n// Stacked pills\n.nav-stacked {\n  > li {\n    float: none;\n    + li {\n      margin-top: 2px;\n      margin-left: 0; // no need for this gap between nav items\n    }\n  }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n  width: 100%;\n\n  > li {\n    float: none;\n    > a {\n      text-align: center;\n      margin-bottom: 5px;\n    }\n  }\n\n  > .dropdown .dropdown-menu {\n    top: auto;\n    left: auto;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li {\n      display: table-cell;\n      width: 1%;\n      > a {\n        margin-bottom: 0;\n      }\n    }\n  }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n  border-bottom: 0;\n\n  > li > a {\n    // Override margin from .nav-tabs\n    margin-right: 0;\n    border-radius: @border-radius-base;\n  }\n\n  > .active > a,\n  > .active > a:hover,\n  > .active > a:focus {\n    border: 1px solid @nav-tabs-justified-link-border-color;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li > a {\n      border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n    }\n    > .active > a,\n    > .active > a:hover,\n    > .active > a:focus {\n      border-bottom-color: @nav-tabs-justified-active-link-border-color;\n    }\n  }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n  > .tab-pane {\n    display: none;\n  }\n  > .active {\n    display: block;\n  }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Make dropdown carets use link color in navs\n.nav .caret {\n  border-top-color: @brand-danger;\n  border-bottom-color: @brand-danger;\n}\n.nav a:hover .caret {\n  border-top-color: darken(@brand-danger, 10%);\n  border-bottom-color: darken(@brand-danger, 10%);\n}\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n  // make dropdown border overlap tab border\n  margin-top: -1px;\n  // Remove the top rounded corners here since there is a hard edge above the menu\n  .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n  position: relative;\n  min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n  margin-bottom: @navbar-margin-bottom;\n  border: 1px solid transparent;\n\n  // Prevent floats from breaking the navbar\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: @navbar-border-radius;\n  }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n  }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n  overflow-x: visible;\n  padding-right: @navbar-padding-horizontal;\n  padding-left:  @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n  &:extend(.clearfix all);\n  -webkit-overflow-scrolling: touch;\n\n  &.in {\n    overflow-y: auto;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n\n    &.collapse {\n      display: block !important;\n      height: auto !important;\n      padding-bottom: 0; // Override default setting\n      overflow: visible !important;\n    }\n\n    &.in {\n      overflow-y: visible;\n    }\n\n    // Undo the collapse side padding for navbars with containers to ensure\n    // alignment of right-aligned contents.\n    .navbar-fixed-top &,\n    .navbar-static-top &,\n    .navbar-fixed-bottom & {\n      padding-left: 0;\n      padding-right: 0;\n    }\n  }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  .navbar-collapse {\n    max-height: @navbar-collapse-max-height;\n\n    @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n      max-height: 200px;\n    }\n  }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n  > .navbar-header,\n  > .navbar-collapse {\n    margin-right: -@navbar-padding-horizontal;\n    margin-left:  -@navbar-padding-horizontal;\n\n    @media (min-width: @grid-float-breakpoint) {\n      margin-right: 0;\n      margin-left:  0;\n    }\n  }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n  z-index: @zindex-navbar;\n  border-width: 0 0 1px;\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: @zindex-navbar-fixed;\n\n  // Undo the rounded corners\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0; // override .navbar defaults\n  border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n  float: left;\n  padding: @navbar-padding-vertical @navbar-padding-horizontal;\n  font-size: @font-size-large;\n  line-height: @line-height-computed;\n  height: @navbar-height;\n  font-family: @font-family-brand;\n  font-weight: bold;\n\n  &:hover,\n  &:focus {\n    text-decoration: none;\n  }\n\n  > img {\n    display: block;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    .navbar > .container &,\n    .navbar > .container-fluid & {\n      margin-left: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: @navbar-padding-horizontal;\n  padding: 9px 10px;\n  .navbar-vertical-align(34px);\n  background-color: transparent;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  border-radius: @border-radius-base;\n\n  // We remove the `outline` here, but later compensate by attaching `:hover`\n  // styles to `:focus`.\n  &:focus {\n    outline: 0;\n  }\n\n  // Bars\n  .icon-bar {\n    display: block;\n    width: 22px;\n    height: 2px;\n    border-radius: 1px;\n  }\n  .icon-bar + .icon-bar {\n    margin-top: 4px;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    display: none;\n  }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n  margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n  > li > a {\n    padding-top:    10px;\n    padding-bottom: 10px;\n    line-height: @line-height-computed;\n  }\n\n  @media (max-width: @grid-float-breakpoint-max) {\n    // Dropdowns get custom display when collapsed\n    .open .dropdown-menu {\n      position: static;\n      float: none;\n      width: auto;\n      margin-top: 0;\n      background-color: transparent;\n      border: 0;\n      box-shadow: none;\n      > li > a,\n      .dropdown-header {\n        padding: 5px 15px 5px 25px;\n      }\n      > li > a {\n        line-height: @line-height-computed;\n        &:hover,\n        &:focus {\n          background-image: none;\n        }\n      }\n    }\n  }\n\n  // Uncollapse the nav\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin: 0;\n\n    > li {\n      float: left;\n      > a {\n        padding-top:    @navbar-padding-vertical;\n        padding-bottom: @navbar-padding-vertical;\n      }\n    }\n  }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n  margin-left: -@navbar-padding-horizontal;\n  margin-right: -@navbar-padding-horizontal;\n  padding: 10px @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n\n  // Mixin behavior for optimum display\n  .form-inline();\n\n  .form-group {\n    @media (max-width: @grid-float-breakpoint-max) {\n      margin-bottom: 5px;\n\n      &:last-child {\n        margin-bottom: 0;\n      }\n    }\n  }\n\n  // Vertically center in expanded, horizontal navbar\n  .navbar-vertical-align(@input-height-base);\n\n  // Undo 100% width for pull classes\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    .box-shadow(none);\n  }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  .border-top-radius(@navbar-border-radius);\n  .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n  .navbar-vertical-align(@input-height-base);\n\n  &.btn-sm {\n    .navbar-vertical-align(@input-height-small);\n  }\n  &.btn-xs {\n    .navbar-vertical-align(22);\n  }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n  .navbar-vertical-align(@line-height-computed);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin-left: @navbar-padding-horizontal;\n    margin-right: @navbar-padding-horizontal;\n  }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-left  { .pull-left(); }\n  .navbar-right {\n    .pull-right();\n    margin-right: -@navbar-padding-horizontal;\n\n    ~ .navbar-right {\n      margin-right: 0;\n    }\n  }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  background-color: @navbar-default-bg;\n  border-color: @navbar-default-border;\n\n  .navbar-brand {\n    color: @navbar-default-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-default-brand-hover-color;\n      background-color: @navbar-default-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-default-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-default-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-hover-color;\n        background-color: @navbar-default-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-active-color;\n        background-color: @navbar-default-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-disabled-color;\n        background-color: @navbar-default-link-disabled-bg;\n      }\n    }\n  }\n\n  .navbar-toggle {\n    border-color: @navbar-default-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-default-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-default-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: @navbar-default-border;\n  }\n\n  // Dropdown menu items\n  .navbar-nav {\n    // Remove background color from open dropdown\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-default-link-active-bg;\n        color: @navbar-default-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display when collapsed\n      .open .dropdown-menu {\n        > li > a {\n          color: @navbar-default-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-hover-color;\n            background-color: @navbar-default-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-active-color;\n            background-color: @navbar-default-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-disabled-color;\n            background-color: @navbar-default-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n\n  // Links in navbars\n  //\n  // Add a class to ensure links outside the navbar nav are colored correctly.\n\n  .navbar-link {\n    color: @navbar-default-link-color;\n    &:hover {\n      color: @navbar-default-link-hover-color;\n    }\n  }\n\n  .btn-link {\n    color: @navbar-default-link-color;\n    &:hover,\n    &:focus {\n      color: @navbar-default-link-hover-color;\n    }\n    &[disabled],\n    fieldset[disabled] & {\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-disabled-color;\n      }\n    }\n  }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n  background-color: @navbar-inverse-bg;\n  border-color: @navbar-inverse-border;\n\n  .navbar-brand {\n    color: @navbar-inverse-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-inverse-brand-hover-color;\n      background-color: @navbar-inverse-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-inverse-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-inverse-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-hover-color;\n        background-color: @navbar-inverse-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-active-color;\n        background-color: @navbar-inverse-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-disabled-color;\n        background-color: @navbar-inverse-link-disabled-bg;\n      }\n    }\n  }\n\n  // Darken the responsive nav toggle\n  .navbar-toggle {\n    border-color: @navbar-inverse-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-inverse-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-inverse-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: darken(@navbar-inverse-bg, 7%);\n  }\n\n  // Dropdowns\n  .navbar-nav {\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-inverse-link-active-bg;\n        color: @navbar-inverse-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display\n      .open .dropdown-menu {\n        > .dropdown-header {\n          border-color: @navbar-inverse-border;\n        }\n        .divider {\n          background-color: @navbar-inverse-border;\n        }\n        > li > a {\n          color: @navbar-inverse-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-hover-color;\n            background-color: @navbar-inverse-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-active-color;\n            background-color: @navbar-inverse-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-disabled-color;\n            background-color: @navbar-inverse-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n  .navbar-link {\n    color: @navbar-inverse-link-color;\n    &:hover {\n      color: @navbar-inverse-link-hover-color;\n    }\n  }\n\n  .btn-link {\n    color: @navbar-inverse-link-color;\n    &:hover,\n    &:focus {\n      color: @navbar-inverse-link-hover-color;\n    }\n    &[disabled],\n    fieldset[disabled] & {\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-disabled-color;\n      }\n    }\n  }\n}\n","// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n  margin-top: ((@navbar-height - @element-height) / 2);\n  margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n  .clearfix();\n}\n.center-block {\n  .center-block();\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n  display: none !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n  position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n  padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n  margin-bottom: @line-height-computed;\n  list-style: none;\n  background-color: @breadcrumb-bg;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline-block;\n\n    + li:before {\n      content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n      padding: 0 5px;\n      color: @breadcrumb-color;\n    }\n  }\n\n  > .active {\n    color: @breadcrumb-active-color;\n  }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline; // Remove list-style and block-level defaults\n    > a,\n    > span {\n      position: relative;\n      float: left; // Collapse white-space\n      padding: @padding-base-vertical @padding-base-horizontal;\n      line-height: @line-height-base;\n      text-decoration: none;\n      color: @pagination-color;\n      background-color: @pagination-bg;\n      border: 1px solid @pagination-border;\n      margin-left: -1px;\n    }\n    &:first-child {\n      > a,\n      > span {\n        margin-left: 0;\n        .border-left-radius(@border-radius-base);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius-base);\n      }\n    }\n  }\n\n  > li > a,\n  > li > span {\n    &:hover,\n    &:focus {\n      z-index: 3;\n      color: @pagination-hover-color;\n      background-color: @pagination-hover-bg;\n      border-color: @pagination-hover-border;\n    }\n  }\n\n  > .active > a,\n  > .active > span {\n    &,\n    &:hover,\n    &:focus {\n      z-index: 2;\n      color: @pagination-active-color;\n      background-color: @pagination-active-bg;\n      border-color: @pagination-active-border;\n      cursor: default;\n    }\n  }\n\n  > .disabled {\n    > span,\n    > span:hover,\n    > span:focus,\n    > a,\n    > a:hover,\n    > a:focus {\n      color: @pagination-disabled-color;\n      background-color: @pagination-disabled-bg;\n      border-color: @pagination-disabled-border;\n      cursor: @cursor-disabled;\n    }\n  }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n  .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n  .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);\n}\n","// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n  > li {\n    > a,\n    > span {\n      padding: @padding-vertical @padding-horizontal;\n      font-size: @font-size;\n    }\n    &:first-child {\n      > a,\n      > span {\n        .border-left-radius(@border-radius);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius);\n      }\n    }\n  }\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  list-style: none;\n  text-align: center;\n  &:extend(.clearfix all);\n  li {\n    display: inline;\n    > a,\n    > span {\n      display: inline-block;\n      padding: 5px 14px;\n      background-color: @pager-bg;\n      border: 1px solid @pager-border;\n      border-radius: @pager-border-radius;\n    }\n\n    > a:hover,\n    > a:focus {\n      text-decoration: none;\n      background-color: @pager-hover-bg;\n    }\n  }\n\n  .next {\n    > a,\n    > span {\n      float: right;\n    }\n  }\n\n  .previous {\n    > a,\n    > span {\n      float: left;\n    }\n  }\n\n  .disabled {\n    > a,\n    > a:hover,\n    > a:focus,\n    > span {\n      color: @pager-disabled-color;\n      background-color: @pager-bg;\n      cursor: @cursor-disabled;\n    }\n  }\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: @label-color;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n\n  // Add hover effects, but only for links\n  a& {\n    &:hover,\n    &:focus {\n      color: @label-link-hover-color;\n      text-decoration: none;\n      cursor: pointer;\n    }\n  }\n\n  // Empty labels collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for labels in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n  .label-variant(@label-default-bg);\n}\n\n.label-primary {\n  .label-variant(@label-primary-bg);\n}\n\n.label-success {\n  .label-variant(@label-success-bg);\n}\n\n.label-info {\n  .label-variant(@label-info-bg);\n}\n\n.label-warning {\n  .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n  .label-variant(@label-danger-bg);\n}\n","// Labels\n\n.label-variant(@color) {\n  background-color: @color;\n\n  &[href] {\n    &:hover,\n    &:focus {\n      background-color: darken(@color, 10%);\n    }\n  }\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: @font-size-small;\n  font-weight: @badge-font-weight;\n  color: @badge-color;\n  line-height: @badge-line-height;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: @badge-bg;\n  border-radius: @badge-border-radius;\n\n  // Empty badges collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for badges in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n\n  .btn-xs &,\n  .btn-group-xs > .btn & {\n    top: 0;\n    padding: 1px 5px;\n  }\n\n  // Hover state, but only for links\n  a& {\n    &:hover,\n    &:focus {\n      color: @badge-link-hover-color;\n      text-decoration: none;\n      cursor: pointer;\n    }\n  }\n\n  // Account for badges in navs\n  .list-group-item.active > &,\n  .nav-pills > .active > a > & {\n    color: @badge-active-color;\n    background-color: @badge-active-bg;\n  }\n\n  .list-group-item > & {\n    float: right;\n  }\n\n  .list-group-item > & + & {\n    margin-right: 5px;\n  }\n\n  .nav-pills > li > a > & {\n    margin-left: 3px;\n  }\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n  padding: @jumbotron-padding (@jumbotron-padding / 2);\n  margin-bottom: @jumbotron-padding;\n  color: @jumbotron-color;\n  background-color: @jumbotron-bg;\n\n  h1,\n  .h1 {\n    color: @jumbotron-heading-color;\n  }\n\n  p {\n    margin-bottom: (@jumbotron-padding / 2);\n    font-size: @jumbotron-font-size;\n    font-weight: 200;\n  }\n\n  > hr {\n    border-top-color: darken(@jumbotron-bg, 10%);\n  }\n\n  .container &,\n  .container-fluid & {\n    border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n  }\n\n  .container {\n    max-width: 100%;\n  }\n\n  @media screen and (min-width: @screen-sm-min) {\n    padding: (@jumbotron-padding * 1.6) 0;\n\n    .container &,\n    .container-fluid & {\n      padding-left:  (@jumbotron-padding * 2);\n      padding-right: (@jumbotron-padding * 2);\n    }\n\n    h1,\n    .h1 {\n      font-size: @jumbotron-heading-font-size;\n    }\n  }\n}\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n  display: block;\n  padding: @thumbnail-padding;\n  margin-bottom: @line-height-computed;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(border .2s ease-in-out);\n\n  > img,\n  a > img {\n    &:extend(.img-responsive);\n    margin-left: auto;\n    margin-right: auto;\n  }\n\n  // Add a hover state for linked versions only\n  a&:hover,\n  a&:focus,\n  a&.active {\n    border-color: @link-color;\n  }\n\n  // Image captions\n  .caption {\n    padding: @thumbnail-caption-padding;\n    color: @thumbnail-caption-color;\n  }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n  padding: @alert-padding;\n  margin-bottom: @line-height-computed;\n  border: 1px solid transparent;\n  border-radius: @alert-border-radius;\n\n  // Headings for larger alerts\n  h4 {\n    margin-top: 0;\n    // Specified for the h4 to prevent conflicts of changing @headings-color\n    color: inherit;\n  }\n\n  // Provide class for links that match alerts\n  .alert-link {\n    font-weight: @alert-link-font-weight;\n  }\n\n  // Improve alignment and spacing of inner content\n  > p,\n  > ul {\n    margin-bottom: 0;\n  }\n\n  > p + p {\n    margin-top: 5px;\n  }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissible {\n  padding-right: (@alert-padding + 20);\n\n  // Adjust close link position\n  .close {\n    position: relative;\n    top: -2px;\n    right: -21px;\n    color: inherit;\n  }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n  .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n\n.alert-info {\n  .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n\n.alert-warning {\n  .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n\n.alert-danger {\n  .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n  background-color: @background;\n  border-color: @border;\n  color: @text-color;\n\n  hr {\n    border-top-color: darken(@border, 5%);\n  }\n  .alert-link {\n    color: darken(@text-color, 10%);\n  }\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n  overflow: hidden;\n  height: @line-height-computed;\n  margin-bottom: @line-height-computed;\n  background-color: @progress-bg;\n  border-radius: @progress-border-radius;\n  .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: @font-size-small;\n  line-height: @line-height-computed;\n  color: @progress-bar-color;\n  text-align: center;\n  background-color: @progress-bar-bg;\n  .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n  .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  #gradient > .striped();\n  background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n  .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n  .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n  .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n  .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n  .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Gradients\n\n#gradient {\n\n  // Horizontal gradient, from left to right\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n    background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  // Vertical gradient, from top to bottom\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Opera 12\n    background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n    background-repeat: repeat-x;\n    background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n    background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n  }\n  .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .radial(@inner-color: #555; @outer-color: #333) {\n    background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n    background-image: radial-gradient(circle, @inner-color, @outer-color);\n    background-repeat: no-repeat;\n  }\n  .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n    background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n  }\n}\n","// Progress bars\n\n.progress-bar-variant(@color) {\n  background-color: @color;\n\n  // Deprecated parent class requirement as of v3.2.0\n  .progress-striped & {\n    #gradient > .striped();\n  }\n}\n",".media {\n  // Proper spacing between instances of .media\n  margin-top: 15px;\n\n  &:first-child {\n    margin-top: 0;\n  }\n}\n\n.media,\n.media-body {\n  zoom: 1;\n  overflow: hidden;\n}\n\n.media-body {\n  width: 10000px;\n}\n\n.media-object {\n  display: block;\n}\n\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n\n.media-middle {\n  vertical-align: middle;\n}\n\n.media-bottom {\n  vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n  // No need to set list-style: none; since .list-group-item is block level\n  margin-bottom: 20px;\n  padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  // Place the border on the list items and negative margin up for better styling\n  margin-bottom: -1px;\n  background-color: @list-group-bg;\n  border: 1px solid @list-group-border;\n\n  // Round the first and last items\n  &:first-child {\n    .border-top-radius(@list-group-border-radius);\n  }\n  &:last-child {\n    margin-bottom: 0;\n    .border-bottom-radius(@list-group-border-radius);\n  }\n}\n\n\n// Linked list items\n//\n// Use anchor elements instead of `li`s or `div`s to create linked list items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item {\n  color: @list-group-link-color;\n\n  .list-group-item-heading {\n    color: @list-group-link-heading-color;\n  }\n\n  // Hover state\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    color: @list-group-link-hover-color;\n    background-color: @list-group-hover-bg;\n  }\n}\n\n.list-group-item {\n  // Disabled state\n  &.disabled,\n  &.disabled:hover,\n  &.disabled:focus {\n    background-color: @list-group-disabled-bg;\n    color: @list-group-disabled-color;\n    cursor: @cursor-disabled;\n\n    // Force color to inherit for custom content\n    .list-group-item-heading {\n      color: inherit;\n    }\n    .list-group-item-text {\n      color: @list-group-disabled-text-color;\n    }\n  }\n\n  // Active class on item itself, not parent\n  &.active,\n  &.active:hover,\n  &.active:focus {\n    z-index: 2; // Place active items above their siblings for proper border styling\n    color: @list-group-active-color;\n    background-color: @list-group-active-bg;\n    border-color: @list-group-active-border;\n\n    // Force color to inherit for custom content\n    .list-group-item-heading,\n    .list-group-item-heading > small,\n    .list-group-item-heading > .small {\n      color: inherit;\n    }\n    .list-group-item-text {\n      color: @list-group-active-text-color;\n    }\n  }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n","// List Groups\n\n.list-group-item-variant(@state; @background; @color) {\n  .list-group-item-@{state} {\n    color: @color;\n    background-color: @background;\n\n    a& {\n      color: @color;\n\n      .list-group-item-heading {\n        color: inherit;\n      }\n\n      &:hover,\n      &:focus {\n        color: @color;\n        background-color: darken(@background, 5%);\n      }\n      &.active,\n      &.active:hover,\n      &.active:focus {\n        color: #fff;\n        background-color: @color;\n        border-color: @color;\n      }\n    }\n  }\n}\n","//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n  margin-bottom: @line-height-computed;\n  background-color: @panel-bg;\n  border: 1px solid transparent;\n  border-radius: @panel-border-radius;\n  .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n  padding: @panel-body-padding;\n  &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n  padding: @panel-heading-padding;\n  border-bottom: 1px solid transparent;\n  .border-top-radius((@panel-border-radius - 1));\n\n  > .dropdown .dropdown-toggle {\n    color: inherit;\n  }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: ceil((@font-size-base * 1.125));\n  color: inherit;\n\n  > a,\n  > small,\n  > .small,\n  > small > a,\n  > .small > a {\n    color: inherit;\n  }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n  padding: @panel-footer-padding;\n  background-color: @panel-footer-bg;\n  border-top: 1px solid @panel-inner-border;\n  .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n  > .list-group,\n  > .panel-collapse > .list-group {\n    margin-bottom: 0;\n\n    .list-group-item {\n      border-width: 1px 0;\n      border-radius: 0;\n    }\n\n    // Add border top radius for first one\n    &:first-child {\n      .list-group-item:first-child {\n        border-top: 0;\n        .border-top-radius((@panel-border-radius - 1));\n      }\n    }\n\n    // Add border bottom radius for last one\n    &:last-child {\n      .list-group-item:last-child {\n        border-bottom: 0;\n        .border-bottom-radius((@panel-border-radius - 1));\n      }\n    }\n  }\n  > .panel-heading + .panel-collapse > .list-group {\n    .list-group-item:first-child {\n      .border-top-radius(0);\n    }\n  }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n  .list-group-item:first-child {\n    border-top-width: 0;\n  }\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n  > .table,\n  > .table-responsive > .table,\n  > .panel-collapse > .table {\n    margin-bottom: 0;\n\n    caption {\n      padding-left: @panel-body-padding;\n      padding-right: @panel-body-padding;\n    }\n  }\n  // Add border top radius for first one\n  > .table:first-child,\n  > .table-responsive:first-child > .table:first-child {\n    .border-top-radius((@panel-border-radius - 1));\n\n    > thead:first-child,\n    > tbody:first-child {\n      > tr:first-child {\n        border-top-left-radius: (@panel-border-radius - 1);\n        border-top-right-radius: (@panel-border-radius - 1);\n\n        td:first-child,\n        th:first-child {\n          border-top-left-radius: (@panel-border-radius - 1);\n        }\n        td:last-child,\n        th:last-child {\n          border-top-right-radius: (@panel-border-radius - 1);\n        }\n      }\n    }\n  }\n  // Add border bottom radius for last one\n  > .table:last-child,\n  > .table-responsive:last-child > .table:last-child {\n    .border-bottom-radius((@panel-border-radius - 1));\n\n    > tbody:last-child,\n    > tfoot:last-child {\n      > tr:last-child {\n        border-bottom-left-radius: (@panel-border-radius - 1);\n        border-bottom-right-radius: (@panel-border-radius - 1);\n\n        td:first-child,\n        th:first-child {\n          border-bottom-left-radius: (@panel-border-radius - 1);\n        }\n        td:last-child,\n        th:last-child {\n          border-bottom-right-radius: (@panel-border-radius - 1);\n        }\n      }\n    }\n  }\n  > .panel-body + .table,\n  > .panel-body + .table-responsive,\n  > .table + .panel-body,\n  > .table-responsive + .panel-body {\n    border-top: 1px solid @table-border-color;\n  }\n  > .table > tbody:first-child > tr:first-child th,\n  > .table > tbody:first-child > tr:first-child td {\n    border-top: 0;\n  }\n  > .table-bordered,\n  > .table-responsive > .table-bordered {\n    border: 0;\n    > thead,\n    > tbody,\n    > tfoot {\n      > tr {\n        > th:first-child,\n        > td:first-child {\n          border-left: 0;\n        }\n        > th:last-child,\n        > td:last-child {\n          border-right: 0;\n        }\n      }\n    }\n    > thead,\n    > tbody {\n      > tr:first-child {\n        > td,\n        > th {\n          border-bottom: 0;\n        }\n      }\n    }\n    > tbody,\n    > tfoot {\n      > tr:last-child {\n        > td,\n        > th {\n          border-bottom: 0;\n        }\n      }\n    }\n  }\n  > .table-responsive {\n    border: 0;\n    margin-bottom: 0;\n  }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n  margin-bottom: @line-height-computed;\n\n  // Tighten up margin so it's only between panels\n  .panel {\n    margin-bottom: 0;\n    border-radius: @panel-border-radius;\n\n    + .panel {\n      margin-top: 5px;\n    }\n  }\n\n  .panel-heading {\n    border-bottom: 0;\n\n    + .panel-collapse > .panel-body,\n    + .panel-collapse > .list-group {\n      border-top: 1px solid @panel-inner-border;\n    }\n  }\n\n  .panel-footer {\n    border-top: 0;\n    + .panel-collapse .panel-body {\n      border-bottom: 1px solid @panel-inner-border;\n    }\n  }\n}\n\n\n// Contextual variations\n.panel-default {\n  .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n  .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n  .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n  .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n  .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n  .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","// Panels\n\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n  border-color: @border;\n\n  & > .panel-heading {\n    color: @heading-text-color;\n    background-color: @heading-bg-color;\n    border-color: @heading-border;\n\n    + .panel-collapse > .panel-body {\n      border-top-color: @border;\n    }\n    .badge {\n      color: @heading-bg-color;\n      background-color: @heading-text-color;\n    }\n  }\n  & > .panel-footer {\n    + .panel-collapse > .panel-body {\n      border-bottom-color: @border;\n    }\n  }\n}\n","// Embeds responsive\n//\n// Credit: Nicolas Gallagher and SUIT CSS.\n\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n\n  .embed-responsive-item,\n  iframe,\n  embed,\n  object,\n  video {\n    position: absolute;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    height: 100%;\n    width: 100%;\n    border: 0;\n  }\n}\n\n// Modifier class for 16:9 aspect ratio\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n\n// Modifier class for 4:3 aspect ratio\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: @well-bg;\n  border: 1px solid @well-border;\n  border-radius: @border-radius-base;\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n  blockquote {\n    border-color: #ddd;\n    border-color: rgba(0,0,0,.15);\n  }\n}\n\n// Sizes\n.well-lg {\n  padding: 24px;\n  border-radius: @border-radius-large;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: @border-radius-small;\n}\n","//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n  float: right;\n  font-size: (@font-size-base * 1.5);\n  font-weight: @close-font-weight;\n  line-height: 1;\n  color: @close-color;\n  text-shadow: @close-text-shadow;\n  .opacity(.2);\n\n  &:hover,\n  &:focus {\n    color: @close-color;\n    text-decoration: none;\n    cursor: pointer;\n    .opacity(.5);\n  }\n\n  // Additional properties for button version\n  // iOS requires the button element instead of an anchor tag.\n  // If you want the anchor version, it requires `href=\"#\"`.\n  // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n  button& {\n    padding: 0;\n    cursor: pointer;\n    background: transparent;\n    border: 0;\n    -webkit-appearance: none;\n  }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open      - body class for killing the scroll\n// .modal           - container to scroll within\n// .modal-dialog    - positioning shell for the actual modal\n// .modal-content   - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n  overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n  display: none;\n  overflow: hidden;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-modal;\n  -webkit-overflow-scrolling: touch;\n\n  // Prevent Chrome on Windows from adding a focus outline. For details, see\n  // https://github.com/twbs/bootstrap/pull/10951.\n  outline: 0;\n\n  // When fading in the modal, animate it to slide down\n  &.fade .modal-dialog {\n    .translate(0, -25%);\n    .transition-transform(~\"0.3s ease-out\");\n  }\n  &.in .modal-dialog { .translate(0, 0) }\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n  position: relative;\n  background-color: @modal-content-bg;\n  border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n  border: 1px solid @modal-content-border-color;\n  border-radius: @border-radius-large;\n  .box-shadow(0 3px 9px rgba(0,0,0,.5));\n  background-clip: padding-box;\n  // Remove focus outline from opened modal\n  outline: 0;\n}\n\n// Modal background\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-modal-background;\n  background-color: @modal-backdrop-bg;\n  // Fade for backdrop\n  &.fade { .opacity(0); }\n  &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n  padding: @modal-title-padding;\n  border-bottom: 1px solid @modal-header-border-color;\n  min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n  margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n  margin: 0;\n  line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n  position: relative;\n  padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n  padding: @modal-inner-padding;\n  text-align: right; // right align buttons\n  border-top: 1px solid @modal-footer-border-color;\n  &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n  // Properly space out buttons\n  .btn + .btn {\n    margin-left: 5px;\n    margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n  }\n  // but override that for button groups\n  .btn-group .btn + .btn {\n    margin-left: -1px;\n  }\n  // and override it for block buttons as well\n  .btn-block + .btn-block {\n    margin-left: 0;\n  }\n}\n\n// Measure scrollbar width for padding body during modal show/hide\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n  // Automatically set modal's width for larger viewports\n  .modal-dialog {\n    width: @modal-md;\n    margin: 30px auto;\n  }\n  .modal-content {\n    .box-shadow(0 5px 15px rgba(0,0,0,.5));\n  }\n\n  // Modal sizes\n  .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n  .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n  position: absolute;\n  z-index: @zindex-tooltip;\n  display: block;\n  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\n  // So reset our font and text properties to avoid inheriting weird values.\n  .reset-text();\n  font-size: @font-size-small;\n\n  .opacity(0);\n\n  &.in     { .opacity(@tooltip-opacity); }\n  &.top    { margin-top:  -3px; padding: @tooltip-arrow-width 0; }\n  &.right  { margin-left:  3px; padding: 0 @tooltip-arrow-width; }\n  &.bottom { margin-top:   3px; padding: @tooltip-arrow-width 0; }\n  &.left   { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n  max-width: @tooltip-max-width;\n  padding: 3px 8px;\n  color: @tooltip-color;\n  text-align: center;\n  background-color: @tooltip-bg;\n  border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1\n.tooltip {\n  &.top .tooltip-arrow {\n    bottom: 0;\n    left: 50%;\n    margin-left: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.top-left .tooltip-arrow {\n    bottom: 0;\n    right: @tooltip-arrow-width;\n    margin-bottom: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.top-right .tooltip-arrow {\n    bottom: 0;\n    left: @tooltip-arrow-width;\n    margin-bottom: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.right .tooltip-arrow {\n    top: 50%;\n    left: 0;\n    margin-top: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-right-color: @tooltip-arrow-color;\n  }\n  &.left .tooltip-arrow {\n    top: 50%;\n    right: 0;\n    margin-top: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-left-color: @tooltip-arrow-color;\n  }\n  &.bottom .tooltip-arrow {\n    top: 0;\n    left: 50%;\n    margin-left: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n  &.bottom-left .tooltip-arrow {\n    top: 0;\n    right: @tooltip-arrow-width;\n    margin-top: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n  &.bottom-right .tooltip-arrow {\n    top: 0;\n    left: @tooltip-arrow-width;\n    margin-top: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n}\n",".reset-text() {\n  font-family: @font-family-base;\n  // We deliberately do NOT reset font-size.\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\n  line-height: @line-height-base;\n  text-align: left; // Fallback for where `start` is not supported\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: @zindex-popover;\n  display: none;\n  max-width: @popover-max-width;\n  padding: 1px;\n  // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element.\n  // So reset our font and text properties to avoid inheriting weird values.\n  .reset-text();\n  font-size: @font-size-base;\n\n  background-color: @popover-bg;\n  background-clip: padding-box;\n  border: 1px solid @popover-fallback-border-color;\n  border: 1px solid @popover-border-color;\n  border-radius: @border-radius-large;\n  .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n  // Offset the popover to account for the popover arrow\n  &.top     { margin-top: -@popover-arrow-width; }\n  &.right   { margin-left: @popover-arrow-width; }\n  &.bottom  { margin-top: @popover-arrow-width; }\n  &.left    { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n  margin: 0; // reset heading margin\n  padding: 8px 14px;\n  font-size: @font-size-base;\n  background-color: @popover-title-bg;\n  border-bottom: 1px solid darken(@popover-title-bg, 5%);\n  border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0;\n}\n\n.popover-content {\n  padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n  &,\n  &:after {\n    position: absolute;\n    display: block;\n    width: 0;\n    height: 0;\n    border-color: transparent;\n    border-style: solid;\n  }\n}\n.popover > .arrow {\n  border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n  border-width: @popover-arrow-width;\n  content: \"\";\n}\n\n.popover {\n  &.top > .arrow {\n    left: 50%;\n    margin-left: -@popover-arrow-outer-width;\n    border-bottom-width: 0;\n    border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-top-color: @popover-arrow-outer-color;\n    bottom: -@popover-arrow-outer-width;\n    &:after {\n      content: \" \";\n      bottom: 1px;\n      margin-left: -@popover-arrow-width;\n      border-bottom-width: 0;\n      border-top-color: @popover-arrow-color;\n    }\n  }\n  &.right > .arrow {\n    top: 50%;\n    left: -@popover-arrow-outer-width;\n    margin-top: -@popover-arrow-outer-width;\n    border-left-width: 0;\n    border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-right-color: @popover-arrow-outer-color;\n    &:after {\n      content: \" \";\n      left: 1px;\n      bottom: -@popover-arrow-width;\n      border-left-width: 0;\n      border-right-color: @popover-arrow-color;\n    }\n  }\n  &.bottom > .arrow {\n    left: 50%;\n    margin-left: -@popover-arrow-outer-width;\n    border-top-width: 0;\n    border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-bottom-color: @popover-arrow-outer-color;\n    top: -@popover-arrow-outer-width;\n    &:after {\n      content: \" \";\n      top: 1px;\n      margin-left: -@popover-arrow-width;\n      border-top-width: 0;\n      border-bottom-color: @popover-arrow-color;\n    }\n  }\n\n  &.left > .arrow {\n    top: 50%;\n    right: -@popover-arrow-outer-width;\n    margin-top: -@popover-arrow-outer-width;\n    border-right-width: 0;\n    border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-left-color: @popover-arrow-outer-color;\n    &:after {\n      content: \" \";\n      right: 1px;\n      border-right-width: 0;\n      border-left-color: @popover-arrow-color;\n      bottom: -@popover-arrow-width;\n    }\n  }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n  position: relative;\n}\n\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n\n  > .item {\n    display: none;\n    position: relative;\n    .transition(.6s ease-in-out left);\n\n    // Account for jankitude on images\n    > img,\n    > a > img {\n      &:extend(.img-responsive);\n      line-height: 1;\n    }\n\n    // WebKit CSS3 transforms for supported devices\n    @media all and (transform-3d), (-webkit-transform-3d) {\n      .transition-transform(~'0.6s ease-in-out');\n      .backface-visibility(~'hidden');\n      .perspective(1000px);\n\n      &.next,\n      &.active.right {\n        .translate3d(100%, 0, 0);\n        left: 0;\n      }\n      &.prev,\n      &.active.left {\n        .translate3d(-100%, 0, 0);\n        left: 0;\n      }\n      &.next.left,\n      &.prev.right,\n      &.active {\n        .translate3d(0, 0, 0);\n        left: 0;\n      }\n    }\n  }\n\n  > .active,\n  > .next,\n  > .prev {\n    display: block;\n  }\n\n  > .active {\n    left: 0;\n  }\n\n  > .next,\n  > .prev {\n    position: absolute;\n    top: 0;\n    width: 100%;\n  }\n\n  > .next {\n    left: 100%;\n  }\n  > .prev {\n    left: -100%;\n  }\n  > .next.left,\n  > .prev.right {\n    left: 0;\n  }\n\n  > .active.left {\n    left: -100%;\n  }\n  > .active.right {\n    left: 100%;\n  }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: @carousel-control-width;\n  .opacity(@carousel-control-opacity);\n  font-size: @carousel-control-font-size;\n  color: @carousel-control-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  // We can't have this transition here because WebKit cancels the carousel\n  // animation if you trip this while in the middle of another animation.\n\n  // Set gradients for backgrounds\n  &.left {\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n  }\n  &.right {\n    left: auto;\n    right: 0;\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n  }\n\n  // Hover/focus state\n  &:hover,\n  &:focus {\n    outline: 0;\n    color: @carousel-control-color;\n    text-decoration: none;\n    .opacity(.9);\n  }\n\n  // Toggles\n  .icon-prev,\n  .icon-next,\n  .glyphicon-chevron-left,\n  .glyphicon-chevron-right {\n    position: absolute;\n    top: 50%;\n    z-index: 5;\n    display: inline-block;\n  }\n  .icon-prev,\n  .glyphicon-chevron-left {\n    left: 50%;\n    margin-left: -10px;\n  }\n  .icon-next,\n  .glyphicon-chevron-right {\n    right: 50%;\n    margin-right: -10px;\n  }\n  .icon-prev,\n  .icon-next {\n    width:  20px;\n    height: 20px;\n    margin-top: -10px;\n    line-height: 1;\n    font-family: serif;\n  }\n\n\n  .icon-prev {\n    &:before {\n      content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n    }\n  }\n  .icon-next {\n    &:before {\n      content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n    }\n  }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n\n  li {\n    display: inline-block;\n    width:  10px;\n    height: 10px;\n    margin: 1px;\n    text-indent: -999px;\n    border: 1px solid @carousel-indicator-border-color;\n    border-radius: 10px;\n    cursor: pointer;\n\n    // IE8-9 hack for event handling\n    //\n    // Internet Explorer 8-9 does not support clicks on elements without a set\n    // `background-color`. We cannot use `filter` since that's not viewed as a\n    // background color by the browser. Thus, a hack is needed.\n    // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer\n    //\n    // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n    // set alpha transparency for the best results possible.\n    background-color: #000 \\9; // IE8\n    background-color: rgba(0,0,0,0); // IE9\n  }\n  .active {\n    margin: 0;\n    width:  12px;\n    height: 12px;\n    background-color: @carousel-indicator-active-bg;\n  }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: @carousel-caption-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  & .btn {\n    text-shadow: none; // No shadow for button elements in carousel-caption\n  }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n  // Scale up the controls a smidge\n  .carousel-control {\n    .glyphicon-chevron-left,\n    .glyphicon-chevron-right,\n    .icon-prev,\n    .icon-next {\n      width: 30px;\n      height: 30px;\n      margin-top: -15px;\n      font-size: 30px;\n    }\n    .glyphicon-chevron-left,\n    .icon-prev {\n      margin-left: -15px;\n    }\n    .glyphicon-chevron-right,\n    .icon-next {\n      margin-right: -15px;\n    }\n  }\n\n  // Show and left align the captions\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n\n  // Move up the indicators\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n","// Clearfix\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n//    contenteditable attribute is included anywhere else in the document.\n//    Otherwise it causes space to appear at the top and bottom of elements\n//    that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n//    `:before` to contain the top-margins of child elements.\n//\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n\n.clearfix() {\n  &:before,\n  &:after {\n    content: \" \"; // 1\n    display: table; // 2\n  }\n  &:after {\n    clear: both;\n  }\n}\n","// Center-align a block level element\n\n.center-block() {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n","// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n  font: ~\"0/0\" a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n// New mixin to use as of v3.0.1\n.text-hide() {\n  .hide-text();\n}\n","//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#support-ie10-width\n// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n  width: device-width;\n}\n\n\n// Visibility utilities\n// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  .responsive-invisibility();\n}\n\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n\n.visible-xs {\n  @media (max-width: @screen-xs-max) {\n    .responsive-visibility();\n  }\n}\n.visible-xs-block {\n  @media (max-width: @screen-xs-max) {\n    display: block !important;\n  }\n}\n.visible-xs-inline {\n  @media (max-width: @screen-xs-max) {\n    display: inline !important;\n  }\n}\n.visible-xs-inline-block {\n  @media (max-width: @screen-xs-max) {\n    display: inline-block !important;\n  }\n}\n\n.visible-sm {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    .responsive-visibility();\n  }\n}\n.visible-sm-block {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    display: block !important;\n  }\n}\n.visible-sm-inline {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    display: inline !important;\n  }\n}\n.visible-sm-inline-block {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    display: inline-block !important;\n  }\n}\n\n.visible-md {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    .responsive-visibility();\n  }\n}\n.visible-md-block {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    display: block !important;\n  }\n}\n.visible-md-inline {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    display: inline !important;\n  }\n}\n.visible-md-inline-block {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    display: inline-block !important;\n  }\n}\n\n.visible-lg {\n  @media (min-width: @screen-lg-min) {\n    .responsive-visibility();\n  }\n}\n.visible-lg-block {\n  @media (min-width: @screen-lg-min) {\n    display: block !important;\n  }\n}\n.visible-lg-inline {\n  @media (min-width: @screen-lg-min) {\n    display: inline !important;\n  }\n}\n.visible-lg-inline-block {\n  @media (min-width: @screen-lg-min) {\n    display: inline-block !important;\n  }\n}\n\n.hidden-xs {\n  @media (max-width: @screen-xs-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-sm {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-md {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-lg {\n  @media (min-width: @screen-lg-min) {\n    .responsive-invisibility();\n  }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n// Note: Deprecated .visible-print as of v3.2.0\n.visible-print {\n  .responsive-invisibility();\n\n  @media print {\n    .responsive-visibility();\n  }\n}\n.visible-print-block {\n  display: none !important;\n\n  @media print {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n\n  @media print {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n\n  @media print {\n    display: inline-block !important;\n  }\n}\n\n.hidden-print {\n  @media print {\n    .responsive-invisibility();\n  }\n}\n","// Responsive utilities\n\n//\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n  display: block !important;\n  table&  { display: table !important; }\n  tr&     { display: table-row !important; }\n  th&,\n  td&     { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n  display: none !important;\n}\n"]}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.min.css b/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.min.css
deleted file mode 100644
index be7e906..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/css/bootstrap.min.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/*!
- * Bootstrap v3.3.4 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:Cantarell,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:focus,a:hover{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#f8e4c7}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:focus,a.text-primary:hover{color:#3071a9}.text-success{color:#3f7815}a.text-success:focus,a.text-success:hover{color:#284d0e}.text-info{color:#603e7a}a.text-info:focus,a.text-info:hover{color:#452d58}.text-warning{color:#7e500f}a.text-warning:focus,a.text-warning:hover{color:#51330a}.text-danger{color:#78153f}a.text-danger:focus,a.text-danger:hover{color:#4d0e28}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:focus,a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dcf6ca}a.bg-success:focus,a.bg-success:hover{background-color:#c0ee9e}.bg-info{background-color:#f6f2f8}a.bg-info:focus,a.bg-info:hover{background-color:#ddd0e7}.bg-warning{background-color:#f8e4c7}a.bg-warning:focus,a.bg-warning:hover{background-color:#f3ce9a}.bg-danger{background-color:#f6cadc}a.bg-danger:focus,a.bg-danger:hover{background-color:#ee9ec0}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dcf6ca}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#cef2b4}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#f6f2f8}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#e9e1f0}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#f8e4c7}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#f6d9b0}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f6cadc}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#f2b4ce}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px \9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3f7815}.has-success .form-control{border-color:#3f7815;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#284d0e;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #6ccf24;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #6ccf24}.has-success .input-group-addon{color:#3f7815;background-color:#dcf6ca;border-color:#3f7815}.has-success .form-control-feedback{color:#3f7815}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#7e500f}.has-warning .form-control{border-color:#7e500f;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#51330a;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d98a1a;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d98a1a}.has-warning .input-group-addon{color:#7e500f;background-color:#f8e4c7;border-color:#7e500f}.has-warning .form-control-feedback{color:#7e500f}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#78153f}.has-error .form-control{border-color:#78153f;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#4d0e28;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #cf246c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #cf246c}.has-error .input-group-addon{color:#78153f;background-color:#f6cadc;border-color:#78153f}.has-error .form-control-feedback{color:#78153f}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#3071a9;border-color:#193c5a}.btn-primary:hover{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#285e8e;border-color:#193c5a}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#79db32;border-color:#6ccf24}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#61b921;border-color:#346311}.btn-success:hover{color:#fff;background-color:#61b921;border-color:#519b1b}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#61b921;border-color:#519b1b}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#519b1b;border-color:#346311}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#79db32;border-color:#6ccf24}.btn-success .badge{color:#79db32;background-color:#fff}.btn-info{color:#fff;background-color:#a07cbc;border-color:#946bb3}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#885aab;border-color:#533669}.btn-info:hover{color:#fff;background-color:#885aab;border-color:#754c95}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#885aab;border-color:#754c95}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#754c95;border-color:#533669}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#a07cbc;border-color:#946bb3}.btn-info .badge{color:#a07cbc;background-color:#fff}.btn-warning{color:#fff;background-color:#e59728;border-color:#d98a1a}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#c27c18;border-color:#67420d}.btn-warning:hover{color:#fff;background-color:#c27c18;border-color:#a36814}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#c27c18;border-color:#a36814}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#a36814;border-color:#67420d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#e59728;border-color:#d98a1a}.btn-warning .badge{color:#e59728;background-color:#fff}.btn-danger{color:#fff;background-color:#db3279;border-color:#cf246c}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#b92161;border-color:#631134}.btn-danger:hover{color:#fff;background-color:#b92161;border-color:#9b1b51}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#b92161;border-color:#9b1b51}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#9b1b51;border-color:#631134}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#db3279;border-color:#cf246c}.btn-danger .badge{color:#db3279;background-color:#fff}.btn-link{font-weight:400;color:#428bca;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#db3279;border-bottom-color:#db3279}.nav a:hover .caret{border-top-color:#b92161;border-bottom-color:#b92161}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:35px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px)and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:35px;padding:7.5px 15px;font-family:Comfortaa,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:18px;font-weight:700;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:.5px;margin-right:15px;margin-bottom:.5px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:3.75px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:7.5px;padding-bottom:7.5px}}.navbar-form{padding:10px 15px;margin-top:.5px;margin-right:-15px;margin-bottom:.5px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:.5px;margin-bottom:.5px}.navbar-btn.btn-sm{margin-top:2.5px;margin-bottom:2.5px}.navbar-btn.btn-xs{margin-top:6.5px;margin-bottom:6.5px}.navbar-text{margin-top:7.5px;margin-bottom:7.5px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#db3279;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#db3279;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#db3279;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#294172;border-color:#1c2c4c}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#777}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#1c2c4c}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#203258}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#1c2c4c}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#1c2c4c}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#1c2c4c}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#1c2c4c}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#428bca;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#3071a9}.label-success{background-color:#79db32}.label-success[href]:focus,.label-success[href]:hover{background-color:#61b921}.label-info{background-color:#a07cbc}.label-info[href]:focus,.label-info[href]:hover{background-color:#885aab}.label-warning{background-color:#e59728}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#c27c18}.label-danger{background-color:#db3279}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#b92161}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3f7815;background-color:#dcf6ca;border-color:#d8f2b4}.alert-success hr{border-top-color:#cdee9e}.alert-success .alert-link{color:#284d0e}.alert-info{color:#603e7a;background-color:#f6f2f8;border-color:#e7e1f0}.alert-info hr{border-top-color:#d9d0e7}.alert-info .alert-link{color:#452d58}.alert-warning{color:#7e500f;background-color:#f8e4c7;border-color:#f6ceb0}.alert-warning hr{border-top-color:#f3bf9a}.alert-warning .alert-link{color:#51330a}.alert-danger{color:#78153f;background-color:#f6cadc;border-color:#f2b4d8}.alert-danger hr{border-top-color:#ee9ecd}.alert-danger .alert-link{color:#4d0e28}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#79db32}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#a07cbc}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#e59728}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#db3279}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3f7815;background-color:#dcf6ca}a.list-group-item-success{color:#3f7815}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3f7815;background-color:#cef2b4}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3f7815;border-color:#3f7815}.list-group-item-info{color:#603e7a;background-color:#f6f2f8}a.list-group-item-info{color:#603e7a}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#603e7a;background-color:#e9e1f0}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#603e7a;border-color:#603e7a}.list-group-item-warning{color:#7e500f;background-color:#f8e4c7}a.list-group-item-warning{color:#7e500f}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#7e500f;background-color:#f6d9b0}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#7e500f;border-color:#7e500f}.list-group-item-danger{color:#78153f;background-color:#f6cadc}a.list-group-item-danger{color:#78153f}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#78153f;background-color:#f2b4ce}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#78153f;border-color:#78153f}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d8f2b4}.panel-success>.panel-heading{color:#3f7815;background-color:#dcf6ca;border-color:#d8f2b4}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d8f2b4}.panel-success>.panel-heading .badge{color:#dcf6ca;background-color:#3f7815}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d8f2b4}.panel-info{border-color:#e7e1f0}.panel-info>.panel-heading{color:#603e7a;background-color:#f6f2f8;border-color:#e7e1f0}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#e7e1f0}.panel-info>.panel-heading .badge{color:#f6f2f8;background-color:#603e7a}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#e7e1f0}.panel-warning{border-color:#f6ceb0}.panel-warning>.panel-heading{color:#7e500f;background-color:#f8e4c7;border-color:#f6ceb0}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f6ceb0}.panel-warning>.panel-heading .badge{color:#f8e4c7;background-color:#7e500f}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f6ceb0}.panel-danger{border-color:#f2b4d8}.panel-danger>.panel-heading{color:#78153f;background-color:#f6cadc;border-color:#f2b4d8}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f2b4d8}.panel-danger>.panel-heading .badge{color:#f6cadc;background-color:#78153f}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f2b4d8}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Cantarell,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:Cantarell,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px)and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px)and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.eot b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.eot
deleted file mode 100644
index b93a495..0000000
Binary files a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.eot and /dev/null differ
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.svg b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.svg
deleted file mode 100644
index 94fb549..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.svg
+++ /dev/null
@@ -1,288 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata></metadata>
-<defs>
-<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
-<font-face units-per-em="1200" ascent="960" descent="-240" />
-<missing-glyph horiz-adv-x="500" />
-<glyph horiz-adv-x="0" />
-<glyph horiz-adv-x="400" />
-<glyph unicode=" " />
-<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
-<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xa0;" />
-<glyph unicode="&#xa5;" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
-<glyph unicode="&#x2000;" horiz-adv-x="650" />
-<glyph unicode="&#x2001;" horiz-adv-x="1300" />
-<glyph unicode="&#x2002;" horiz-adv-x="650" />
-<glyph unicode="&#x2003;" horiz-adv-x="1300" />
-<glyph unicode="&#x2004;" horiz-adv-x="433" />
-<glyph unicode="&#x2005;" horiz-adv-x="325" />
-<glyph unicode="&#x2006;" horiz-adv-x="216" />
-<glyph unicode="&#x2007;" horiz-adv-x="216" />
-<glyph unicode="&#x2008;" horiz-adv-x="162" />
-<glyph unicode="&#x2009;" horiz-adv-x="260" />
-<glyph unicode="&#x200a;" horiz-adv-x="72" />
-<glyph unicode="&#x202f;" horiz-adv-x="260" />
-<glyph unicode="&#x205f;" horiz-adv-x="325" />
-<glyph unicode="&#x20ac;" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
-<glyph unicode="&#x20bd;" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
-<glyph unicode="&#x2212;" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#x231b;" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
-<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
-<glyph unicode="&#x2601;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
-<glyph unicode="&#x26fa;" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
-<glyph unicode="&#x2709;" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
-<glyph unicode="&#x270f;" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
-<glyph unicode="&#xe001;" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
-<glyph unicode="&#xe002;" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
-<glyph unicode="&#xe003;" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
-<glyph unicode="&#xe005;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
-<glyph unicode="&#xe006;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
-<glyph unicode="&#xe007;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
-<glyph unicode="&#xe008;" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
-<glyph unicode="&#xe009;" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
-<glyph unicode="&#xe010;" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe011;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
-<glyph unicode="&#xe012;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe013;" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
-<glyph unicode="&#xe014;" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
-<glyph unicode="&#xe015;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
-<glyph unicode="&#xe016;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
-<glyph unicode="&#xe017;" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
-<glyph unicode="&#xe018;" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
-<glyph unicode="&#xe019;" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
-<glyph unicode="&#xe020;" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
-<glyph unicode="&#xe021;" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
-<glyph unicode="&#xe022;" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
-<glyph unicode="&#xe023;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
-<glyph unicode="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
-<glyph unicode="&#xe025;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
-<glyph unicode="&#xe026;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
-<glyph unicode="&#xe027;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
-<glyph unicode="&#xe028;" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
-<glyph unicode="&#xe029;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
-<glyph unicode="&#xe030;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
-<glyph unicode="&#xe031;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
-<glyph unicode="&#xe032;" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
-<glyph unicode="&#xe033;" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
-<glyph unicode="&#xe034;" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
-<glyph unicode="&#xe035;" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
-<glyph unicode="&#xe036;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
-<glyph unicode="&#xe037;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
-<glyph unicode="&#xe038;" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
-<glyph unicode="&#xe039;" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
-<glyph unicode="&#xe040;" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
-<glyph unicode="&#xe041;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
-<glyph unicode="&#xe042;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
-<glyph unicode="&#xe043;" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
-<glyph unicode="&#xe044;" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe045;" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
-<glyph unicode="&#xe046;" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
-<glyph unicode="&#xe047;" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
-<glyph unicode="&#xe048;" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
-<glyph unicode="&#xe049;" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
-<glyph unicode="&#xe050;" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
-<glyph unicode="&#xe051;" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
-<glyph unicode="&#xe052;" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe053;" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe054;" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
-<glyph unicode="&#xe055;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe056;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe057;" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe058;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe059;" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
-<glyph unicode="&#xe060;" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
-<glyph unicode="&#xe062;" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
-<glyph unicode="&#xe063;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
-<glyph unicode="&#xe064;" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
-<glyph unicode="&#xe065;" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
-<glyph unicode="&#xe066;" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
-<glyph unicode="&#xe067;" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
-<glyph unicode="&#xe068;" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
-<glyph unicode="&#xe069;" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe070;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe071;" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
-<glyph unicode="&#xe072;" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
-<glyph unicode="&#xe073;" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe074;" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
-<glyph unicode="&#xe075;" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
-<glyph unicode="&#xe076;" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe077;" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe078;" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
-<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
-<glyph unicode="&#xe081;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
-<glyph unicode="&#xe082;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
-<glyph unicode="&#xe083;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
-<glyph unicode="&#xe084;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
-<glyph unicode="&#xe085;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
-<glyph unicode="&#xe086;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
-<glyph unicode="&#xe087;" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
-<glyph unicode="&#xe088;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
-<glyph unicode="&#xe089;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
-<glyph unicode="&#xe090;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
-<glyph unicode="&#xe091;" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
-<glyph unicode="&#xe092;" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
-<glyph unicode="&#xe093;" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
-<glyph unicode="&#xe094;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe095;" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
-<glyph unicode="&#xe096;" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
-<glyph unicode="&#xe097;" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
-<glyph unicode="&#xe101;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
-<glyph unicode="&#xe102;" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
-<glyph unicode="&#xe103;" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
-<glyph unicode="&#xe104;" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
-<glyph unicode="&#xe105;" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
-<glyph unicode="&#xe106;" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
-<glyph unicode="&#xe107;" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
-<glyph unicode="&#xe108;" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
-<glyph unicode="&#xe109;" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
-<glyph unicode="&#xe110;" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
-<glyph unicode="&#xe111;" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
-<glyph unicode="&#xe112;" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
-<glyph unicode="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
-<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
-<glyph unicode="&#xe115;" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
-<glyph unicode="&#xe116;" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
-<glyph unicode="&#xe117;" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
-<glyph unicode="&#xe118;" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
-<glyph unicode="&#xe119;" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
-<glyph unicode="&#xe120;" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
-<glyph unicode="&#xe121;" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
-<glyph unicode="&#xe122;" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
-<glyph unicode="&#xe123;" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
-<glyph unicode="&#xe124;" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
-<glyph unicode="&#xe125;" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe126;" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
-<glyph unicode="&#xe127;" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe128;" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe129;" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe130;" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
-<glyph unicode="&#xe131;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
-<glyph unicode="&#xe132;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
-<glyph unicode="&#xe133;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
-<glyph unicode="&#xe134;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
-<glyph unicode="&#xe135;" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
-<glyph unicode="&#xe136;" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
-<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
-<glyph unicode="&#xe138;" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
-<glyph unicode="&#xe139;" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
-<glyph unicode="&#xe140;" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
-<glyph unicode="&#xe141;" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
-<glyph unicode="&#xe142;" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
-<glyph unicode="&#xe143;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
-<glyph unicode="&#xe144;" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
-<glyph unicode="&#xe145;" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
-<glyph unicode="&#xe146;" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
-<glyph unicode="&#xe148;" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
-<glyph unicode="&#xe149;" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
-<glyph unicode="&#xe150;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
-<glyph unicode="&#xe151;" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
-<glyph unicode="&#xe152;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
-<glyph unicode="&#xe153;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
-<glyph unicode="&#xe154;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
-<glyph unicode="&#xe155;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
-<glyph unicode="&#xe156;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
-<glyph unicode="&#xe157;" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
-<glyph unicode="&#xe158;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
-<glyph unicode="&#xe159;" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
-<glyph unicode="&#xe160;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
-<glyph unicode="&#xe161;" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
-<glyph unicode="&#xe162;" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
-<glyph unicode="&#xe163;" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
-<glyph unicode="&#xe164;" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
-<glyph unicode="&#xe165;" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
-<glyph unicode="&#xe166;" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
-<glyph unicode="&#xe167;" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
-<glyph unicode="&#xe168;" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
-<glyph unicode="&#xe169;" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
-<glyph unicode="&#xe170;" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
-<glyph unicode="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
-<glyph unicode="&#xe172;" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
-<glyph unicode="&#xe173;" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
-<glyph unicode="&#xe174;" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
-<glyph unicode="&#xe175;" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe176;" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
-<glyph unicode="&#xe177;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
-<glyph unicode="&#xe178;" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
-<glyph unicode="&#xe179;" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
-<glyph unicode="&#xe180;" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
-<glyph unicode="&#xe181;" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
-<glyph unicode="&#xe182;" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
-<glyph unicode="&#xe183;" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
-<glyph unicode="&#xe184;" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe185;" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
-<glyph unicode="&#xe186;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
-<glyph unicode="&#xe187;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
-<glyph unicode="&#xe188;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
-<glyph unicode="&#xe189;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
-<glyph unicode="&#xe190;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
-<glyph unicode="&#xe191;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
-<glyph unicode="&#xe192;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
-<glyph unicode="&#xe193;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
-<glyph unicode="&#xe194;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
-<glyph unicode="&#xe195;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
-<glyph unicode="&#xe197;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
-<glyph unicode="&#xe198;" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
-<glyph unicode="&#xe199;" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
-<glyph unicode="&#xe200;" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
-<glyph unicode="&#xe201;" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
-<glyph unicode="&#xe202;" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
-<glyph unicode="&#xe203;" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
-<glyph unicode="&#xe204;" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
-<glyph unicode="&#xe205;" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
-<glyph unicode="&#xe206;" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
-<glyph unicode="&#xe209;" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
-<glyph unicode="&#xe210;" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
-<glyph unicode="&#xe211;" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe212;" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe213;" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe214;" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe215;" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe216;" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
-<glyph unicode="&#xe218;" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
-<glyph unicode="&#xe219;" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
-<glyph unicode="&#xe221;" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe223;" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
-<glyph unicode="&#xe224;" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
-<glyph unicode="&#xe225;" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
-<glyph unicode="&#xe226;" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
-<glyph unicode="&#xe227;" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
-<glyph unicode="&#xe230;" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
-<glyph unicode="&#xe231;" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
-<glyph unicode="&#xe232;" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
-<glyph unicode="&#xe233;" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
-<glyph unicode="&#xe234;" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
-<glyph unicode="&#xe235;" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
-<glyph unicode="&#xe236;" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
-<glyph unicode="&#xe237;" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
-<glyph unicode="&#xe238;" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe239;" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
-<glyph unicode="&#xe240;" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
-<glyph unicode="&#xe241;" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
-<glyph unicode="&#xe242;" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
-<glyph unicode="&#xe243;" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
-<glyph unicode="&#xe244;" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
-<glyph unicode="&#xe245;" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
-<glyph unicode="&#xe246;" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
-<glyph unicode="&#xe247;" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe248;" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
-<glyph unicode="&#xe249;" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
-<glyph unicode="&#xe250;" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
-<glyph unicode="&#xe251;" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
-<glyph unicode="&#xe252;" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
-<glyph unicode="&#xe253;" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
-<glyph unicode="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
-<glyph unicode="&#xe255;" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
-<glyph unicode="&#xe256;" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
-<glyph unicode="&#xe257;" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
-<glyph unicode="&#xe258;" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
-<glyph unicode="&#xe259;" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
-<glyph unicode="&#xe260;" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
-<glyph unicode="&#xf8ff;" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
-<glyph unicode="&#x1f511;" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
-<glyph unicode="&#x1f6aa;" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
-</font>
-</defs></svg> 
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.ttf b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.ttf
deleted file mode 100644
index 1413fc6..0000000
Binary files a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.ttf and /dev/null differ
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff
deleted file mode 100644
index 9e61285..0000000
Binary files a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff and /dev/null differ
diff --git a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff2 b/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff2
deleted file mode 100644
index 64539b5..0000000
Binary files a/hubs/static/bootstrap-3.3.4-fedora/fonts/glyphicons-halflings-regular.woff2 and /dev/null differ
diff --git a/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.js b/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.js
deleted file mode 100644
index 335cc61..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.js
+++ /dev/null
@@ -1,2319 +0,0 @@
-/*!
- * Bootstrap v3.3.4 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-if (typeof jQuery === 'undefined') {
-  throw new Error('Bootstrap\'s JavaScript requires jQuery')
-}
-
-+function ($) {
-  'use strict';
-  var version = $.fn.jquery.split(' ')[0].split('.')
-  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
-    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
-  }
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: transition.js v3.3.4
- * http://getbootstrap.com/javascript/#transitions
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
-  // ============================================================
-
-  function transitionEnd() {
-    var el = document.createElement('bootstrap')
-
-    var transEndEventNames = {
-      WebkitTransition : 'webkitTransitionEnd',
-      MozTransition    : 'transitionend',
-      OTransition      : 'oTransitionEnd otransitionend',
-      transition       : 'transitionend'
-    }
-
-    for (var name in transEndEventNames) {
-      if (el.style[name] !== undefined) {
-        return { end: transEndEventNames[name] }
-      }
-    }
-
-    return false // explicit for ie8 (  ._.)
-  }
-
-  // http://blog.alexmaccaw.com/css-transitions
-  $.fn.emulateTransitionEnd = function (duration) {
-    var called = false
-    var $el = this
-    $(this).one('bsTransitionEnd', function () { called = true })
-    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
-    setTimeout(callback, duration)
-    return this
-  }
-
-  $(function () {
-    $.support.transition = transitionEnd()
-
-    if (!$.support.transition) return
-
-    $.event.special.bsTransitionEnd = {
-      bindType: $.support.transition.end,
-      delegateType: $.support.transition.end,
-      handle: function (e) {
-        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
-      }
-    }
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: alert.js v3.3.4
- * http://getbootstrap.com/javascript/#alerts
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // ALERT CLASS DEFINITION
-  // ======================
-
-  var dismiss = '[data-dismiss="alert"]'
-  var Alert   = function (el) {
-    $(el).on('click', dismiss, this.close)
-  }
-
-  Alert.VERSION = '3.3.4'
-
-  Alert.TRANSITION_DURATION = 150
-
-  Alert.prototype.close = function (e) {
-    var $this    = $(this)
-    var selector = $this.attr('data-target')
-
-    if (!selector) {
-      selector = $this.attr('href')
-      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
-    }
-
-    var $parent = $(selector)
-
-    if (e) e.preventDefault()
-
-    if (!$parent.length) {
-      $parent = $this.closest('.alert')
-    }
-
-    $parent.trigger(e = $.Event('close.bs.alert'))
-
-    if (e.isDefaultPrevented()) return
-
-    $parent.removeClass('in')
-
-    function removeElement() {
-      // detach from parent, fire event then clean up data
-      $parent.detach().trigger('closed.bs.alert').remove()
-    }
-
-    $.support.transition && $parent.hasClass('fade') ?
-      $parent
-        .one('bsTransitionEnd', removeElement)
-        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
-      removeElement()
-  }
-
-
-  // ALERT PLUGIN DEFINITION
-  // =======================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this = $(this)
-      var data  = $this.data('bs.alert')
-
-      if (!data) $this.data('bs.alert', (data = new Alert(this)))
-      if (typeof option == 'string') data[option].call($this)
-    })
-  }
-
-  var old = $.fn.alert
-
-  $.fn.alert             = Plugin
-  $.fn.alert.Constructor = Alert
-
-
-  // ALERT NO CONFLICT
-  // =================
-
-  $.fn.alert.noConflict = function () {
-    $.fn.alert = old
-    return this
-  }
-
-
-  // ALERT DATA-API
-  // ==============
-
-  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: button.js v3.3.4
- * http://getbootstrap.com/javascript/#buttons
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // BUTTON PUBLIC CLASS DEFINITION
-  // ==============================
-
-  var Button = function (element, options) {
-    this.$element  = $(element)
-    this.options   = $.extend({}, Button.DEFAULTS, options)
-    this.isLoading = false
-  }
-
-  Button.VERSION  = '3.3.4'
-
-  Button.DEFAULTS = {
-    loadingText: 'loading...'
-  }
-
-  Button.prototype.setState = function (state) {
-    var d    = 'disabled'
-    var $el  = this.$element
-    var val  = $el.is('input') ? 'val' : 'html'
-    var data = $el.data()
-
-    state = state + 'Text'
-
-    if (data.resetText == null) $el.data('resetText', $el[val]())
-
-    // push to event loop to allow forms to submit
-    setTimeout($.proxy(function () {
-      $el[val](data[state] == null ? this.options[state] : data[state])
-
-      if (state == 'loadingText') {
-        this.isLoading = true
-        $el.addClass(d).attr(d, d)
-      } else if (this.isLoading) {
-        this.isLoading = false
-        $el.removeClass(d).removeAttr(d)
-      }
-    }, this), 0)
-  }
-
-  Button.prototype.toggle = function () {
-    var changed = true
-    var $parent = this.$element.closest('[data-toggle="buttons"]')
-
-    if ($parent.length) {
-      var $input = this.$element.find('input')
-      if ($input.prop('type') == 'radio') {
-        if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
-        else $parent.find('.active').removeClass('active')
-      }
-      if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
-    } else {
-      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
-    }
-
-    if (changed) this.$element.toggleClass('active')
-  }
-
-
-  // BUTTON PLUGIN DEFINITION
-  // ========================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.button')
-      var options = typeof option == 'object' && option
-
-      if (!data) $this.data('bs.button', (data = new Button(this, options)))
-
-      if (option == 'toggle') data.toggle()
-      else if (option) data.setState(option)
-    })
-  }
-
-  var old = $.fn.button
-
-  $.fn.button             = Plugin
-  $.fn.button.Constructor = Button
-
-
-  // BUTTON NO CONFLICT
-  // ==================
-
-  $.fn.button.noConflict = function () {
-    $.fn.button = old
-    return this
-  }
-
-
-  // BUTTON DATA-API
-  // ===============
-
-  $(document)
-    .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
-      var $btn = $(e.target)
-      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
-      Plugin.call($btn, 'toggle')
-      e.preventDefault()
-    })
-    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
-      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
-    })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: carousel.js v3.3.4
- * http://getbootstrap.com/javascript/#carousel
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // CAROUSEL CLASS DEFINITION
-  // =========================
-
-  var Carousel = function (element, options) {
-    this.$element    = $(element)
-    this.$indicators = this.$element.find('.carousel-indicators')
-    this.options     = options
-    this.paused      = null
-    this.sliding     = null
-    this.interval    = null
-    this.$active     = null
-    this.$items      = null
-
-    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
-
-    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
-      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
-      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
-  }
-
-  Carousel.VERSION  = '3.3.4'
-
-  Carousel.TRANSITION_DURATION = 600
-
-  Carousel.DEFAULTS = {
-    interval: 5000,
-    pause: 'hover',
-    wrap: true,
-    keyboard: true
-  }
-
-  Carousel.prototype.keydown = function (e) {
-    if (/input|textarea/i.test(e.target.tagName)) return
-    switch (e.which) {
-      case 37: this.prev(); break
-      case 39: this.next(); break
-      default: return
-    }
-
-    e.preventDefault()
-  }
-
-  Carousel.prototype.cycle = function (e) {
-    e || (this.paused = false)
-
-    this.interval && clearInterval(this.interval)
-
-    this.options.interval
-      && !this.paused
-      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
-
-    return this
-  }
-
-  Carousel.prototype.getItemIndex = function (item) {
-    this.$items = item.parent().children('.item')
-    return this.$items.index(item || this.$active)
-  }
-
-  Carousel.prototype.getItemForDirection = function (direction, active) {
-    var activeIndex = this.getItemIndex(active)
-    var willWrap = (direction == 'prev' && activeIndex === 0)
-                || (direction == 'next' && activeIndex == (this.$items.length - 1))
-    if (willWrap && !this.options.wrap) return active
-    var delta = direction == 'prev' ? -1 : 1
-    var itemIndex = (activeIndex + delta) % this.$items.length
-    return this.$items.eq(itemIndex)
-  }
-
-  Carousel.prototype.to = function (pos) {
-    var that        = this
-    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
-
-    if (pos > (this.$items.length - 1) || pos < 0) return
-
-    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
-    if (activeIndex == pos) return this.pause().cycle()
-
-    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
-  }
-
-  Carousel.prototype.pause = function (e) {
-    e || (this.paused = true)
-
-    if (this.$element.find('.next, .prev').length && $.support.transition) {
-      this.$element.trigger($.support.transition.end)
-      this.cycle(true)
-    }
-
-    this.interval = clearInterval(this.interval)
-
-    return this
-  }
-
-  Carousel.prototype.next = function () {
-    if (this.sliding) return
-    return this.slide('next')
-  }
-
-  Carousel.prototype.prev = function () {
-    if (this.sliding) return
-    return this.slide('prev')
-  }
-
-  Carousel.prototype.slide = function (type, next) {
-    var $active   = this.$element.find('.item.active')
-    var $next     = next || this.getItemForDirection(type, $active)
-    var isCycling = this.interval
-    var direction = type == 'next' ? 'left' : 'right'
-    var that      = this
-
-    if ($next.hasClass('active')) return (this.sliding = false)
-
-    var relatedTarget = $next[0]
-    var slideEvent = $.Event('slide.bs.carousel', {
-      relatedTarget: relatedTarget,
-      direction: direction
-    })
-    this.$element.trigger(slideEvent)
-    if (slideEvent.isDefaultPrevented()) return
-
-    this.sliding = true
-
-    isCycling && this.pause()
-
-    if (this.$indicators.length) {
-      this.$indicators.find('.active').removeClass('active')
-      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
-      $nextIndicator && $nextIndicator.addClass('active')
-    }
-
-    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
-    if ($.support.transition && this.$element.hasClass('slide')) {
-      $next.addClass(type)
-      $next[0].offsetWidth // force reflow
-      $active.addClass(direction)
-      $next.addClass(direction)
-      $active
-        .one('bsTransitionEnd', function () {
-          $next.removeClass([type, direction].join(' ')).addClass('active')
-          $active.removeClass(['active', direction].join(' '))
-          that.sliding = false
-          setTimeout(function () {
-            that.$element.trigger(slidEvent)
-          }, 0)
-        })
-        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
-    } else {
-      $active.removeClass('active')
-      $next.addClass('active')
-      this.sliding = false
-      this.$element.trigger(slidEvent)
-    }
-
-    isCycling && this.cycle()
-
-    return this
-  }
-
-
-  // CAROUSEL PLUGIN DEFINITION
-  // ==========================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.carousel')
-      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
-      var action  = typeof option == 'string' ? option : options.slide
-
-      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
-      if (typeof option == 'number') data.to(option)
-      else if (action) data[action]()
-      else if (options.interval) data.pause().cycle()
-    })
-  }
-
-  var old = $.fn.carousel
-
-  $.fn.carousel             = Plugin
-  $.fn.carousel.Constructor = Carousel
-
-
-  // CAROUSEL NO CONFLICT
-  // ====================
-
-  $.fn.carousel.noConflict = function () {
-    $.fn.carousel = old
-    return this
-  }
-
-
-  // CAROUSEL DATA-API
-  // =================
-
-  var clickHandler = function (e) {
-    var href
-    var $this   = $(this)
-    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
-    if (!$target.hasClass('carousel')) return
-    var options = $.extend({}, $target.data(), $this.data())
-    var slideIndex = $this.attr('data-slide-to')
-    if (slideIndex) options.interval = false
-
-    Plugin.call($target, options)
-
-    if (slideIndex) {
-      $target.data('bs.carousel').to(slideIndex)
-    }
-
-    e.preventDefault()
-  }
-
-  $(document)
-    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
-    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
-
-  $(window).on('load', function () {
-    $('[data-ride="carousel"]').each(function () {
-      var $carousel = $(this)
-      Plugin.call($carousel, $carousel.data())
-    })
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: collapse.js v3.3.4
- * http://getbootstrap.com/javascript/#collapse
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // COLLAPSE PUBLIC CLASS DEFINITION
-  // ================================
-
-  var Collapse = function (element, options) {
-    this.$element      = $(element)
-    this.options       = $.extend({}, Collapse.DEFAULTS, options)
-    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
-                           '[data-toggle="collapse"][data-target="#' + element.id + '"]')
-    this.transitioning = null
-
-    if (this.options.parent) {
-      this.$parent = this.getParent()
-    } else {
-      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
-    }
-
-    if (this.options.toggle) this.toggle()
-  }
-
-  Collapse.VERSION  = '3.3.4'
-
-  Collapse.TRANSITION_DURATION = 350
-
-  Collapse.DEFAULTS = {
-    toggle: true
-  }
-
-  Collapse.prototype.dimension = function () {
-    var hasWidth = this.$element.hasClass('width')
-    return hasWidth ? 'width' : 'height'
-  }
-
-  Collapse.prototype.show = function () {
-    if (this.transitioning || this.$element.hasClass('in')) return
-
-    var activesData
-    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
-
-    if (actives && actives.length) {
-      activesData = actives.data('bs.collapse')
-      if (activesData && activesData.transitioning) return
-    }
-
-    var startEvent = $.Event('show.bs.collapse')
-    this.$element.trigger(startEvent)
-    if (startEvent.isDefaultPrevented()) return
-
-    if (actives && actives.length) {
-      Plugin.call(actives, 'hide')
-      activesData || actives.data('bs.collapse', null)
-    }
-
-    var dimension = this.dimension()
-
-    this.$element
-      .removeClass('collapse')
-      .addClass('collapsing')[dimension](0)
-      .attr('aria-expanded', true)
-
-    this.$trigger
-      .removeClass('collapsed')
-      .attr('aria-expanded', true)
-
-    this.transitioning = 1
-
-    var complete = function () {
-      this.$element
-        .removeClass('collapsing')
-        .addClass('collapse in')[dimension]('')
-      this.transitioning = 0
-      this.$element
-        .trigger('shown.bs.collapse')
-    }
-
-    if (!$.support.transition) return complete.call(this)
-
-    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
-
-    this.$element
-      .one('bsTransitionEnd', $.proxy(complete, this))
-      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
-  }
-
-  Collapse.prototype.hide = function () {
-    if (this.transitioning || !this.$element.hasClass('in')) return
-
-    var startEvent = $.Event('hide.bs.collapse')
-    this.$element.trigger(startEvent)
-    if (startEvent.isDefaultPrevented()) return
-
-    var dimension = this.dimension()
-
-    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
-
-    this.$element
-      .addClass('collapsing')
-      .removeClass('collapse in')
-      .attr('aria-expanded', false)
-
-    this.$trigger
-      .addClass('collapsed')
-      .attr('aria-expanded', false)
-
-    this.transitioning = 1
-
-    var complete = function () {
-      this.transitioning = 0
-      this.$element
-        .removeClass('collapsing')
-        .addClass('collapse')
-        .trigger('hidden.bs.collapse')
-    }
-
-    if (!$.support.transition) return complete.call(this)
-
-    this.$element
-      [dimension](0)
-      .one('bsTransitionEnd', $.proxy(complete, this))
-      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
-  }
-
-  Collapse.prototype.toggle = function () {
-    this[this.$element.hasClass('in') ? 'hide' : 'show']()
-  }
-
-  Collapse.prototype.getParent = function () {
-    return $(this.options.parent)
-      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
-      .each($.proxy(function (i, element) {
-        var $element = $(element)
-        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
-      }, this))
-      .end()
-  }
-
-  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
-    var isOpen = $element.hasClass('in')
-
-    $element.attr('aria-expanded', isOpen)
-    $trigger
-      .toggleClass('collapsed', !isOpen)
-      .attr('aria-expanded', isOpen)
-  }
-
-  function getTargetFromTrigger($trigger) {
-    var href
-    var target = $trigger.attr('data-target')
-      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
-
-    return $(target)
-  }
-
-
-  // COLLAPSE PLUGIN DEFINITION
-  // ==========================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.collapse')
-      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
-
-      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
-      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  var old = $.fn.collapse
-
-  $.fn.collapse             = Plugin
-  $.fn.collapse.Constructor = Collapse
-
-
-  // COLLAPSE NO CONFLICT
-  // ====================
-
-  $.fn.collapse.noConflict = function () {
-    $.fn.collapse = old
-    return this
-  }
-
-
-  // COLLAPSE DATA-API
-  // =================
-
-  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
-    var $this   = $(this)
-
-    if (!$this.attr('data-target')) e.preventDefault()
-
-    var $target = getTargetFromTrigger($this)
-    var data    = $target.data('bs.collapse')
-    var option  = data ? 'toggle' : $this.data()
-
-    Plugin.call($target, option)
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: dropdown.js v3.3.4
- * http://getbootstrap.com/javascript/#dropdowns
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // DROPDOWN CLASS DEFINITION
-  // =========================
-
-  var backdrop = '.dropdown-backdrop'
-  var toggle   = '[data-toggle="dropdown"]'
-  var Dropdown = function (element) {
-    $(element).on('click.bs.dropdown', this.toggle)
-  }
-
-  Dropdown.VERSION = '3.3.4'
-
-  Dropdown.prototype.toggle = function (e) {
-    var $this = $(this)
-
-    if ($this.is('.disabled, :disabled')) return
-
-    var $parent  = getParent($this)
-    var isActive = $parent.hasClass('open')
-
-    clearMenus()
-
-    if (!isActive) {
-      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
-        // if mobile we use a backdrop because click events don't delegate
-        $(document.createElement('div'))
-          .addClass('dropdown-backdrop')
-          .insertAfter($(this))
-          .on('click', clearMenus)
-      }
-
-      var relatedTarget = { relatedTarget: this }
-      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
-
-      if (e.isDefaultPrevented()) return
-
-      $this
-        .trigger('focus')
-        .attr('aria-expanded', 'true')
-
-      $parent
-        .toggleClass('open')
-        .trigger('shown.bs.dropdown', relatedTarget)
-    }
-
-    return false
-  }
-
-  Dropdown.prototype.keydown = function (e) {
-    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
-
-    var $this = $(this)
-
-    e.preventDefault()
-    e.stopPropagation()
-
-    if ($this.is('.disabled, :disabled')) return
-
-    var $parent  = getParent($this)
-    var isActive = $parent.hasClass('open')
-
-    if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
-      if (e.which == 27) $parent.find(toggle).trigger('focus')
-      return $this.trigger('click')
-    }
-
-    var desc = ' li:not(.disabled):visible a'
-    var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
-
-    if (!$items.length) return
-
-    var index = $items.index(e.target)
-
-    if (e.which == 38 && index > 0)                 index--                        // up
-    if (e.which == 40 && index < $items.length - 1) index++                        // down
-    if (!~index)                                      index = 0
-
-    $items.eq(index).trigger('focus')
-  }
-
-  function clearMenus(e) {
-    if (e && e.which === 3) return
-    $(backdrop).remove()
-    $(toggle).each(function () {
-      var $this         = $(this)
-      var $parent       = getParent($this)
-      var relatedTarget = { relatedTarget: this }
-
-      if (!$parent.hasClass('open')) return
-
-      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
-
-      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
-
-      if (e.isDefaultPrevented()) return
-
-      $this.attr('aria-expanded', 'false')
-      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
-    })
-  }
-
-  function getParent($this) {
-    var selector = $this.attr('data-target')
-
-    if (!selector) {
-      selector = $this.attr('href')
-      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
-    }
-
-    var $parent = selector && $(selector)
-
-    return $parent && $parent.length ? $parent : $this.parent()
-  }
-
-
-  // DROPDOWN PLUGIN DEFINITION
-  // ==========================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this = $(this)
-      var data  = $this.data('bs.dropdown')
-
-      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
-      if (typeof option == 'string') data[option].call($this)
-    })
-  }
-
-  var old = $.fn.dropdown
-
-  $.fn.dropdown             = Plugin
-  $.fn.dropdown.Constructor = Dropdown
-
-
-  // DROPDOWN NO CONFLICT
-  // ====================
-
-  $.fn.dropdown.noConflict = function () {
-    $.fn.dropdown = old
-    return this
-  }
-
-
-  // APPLY TO STANDARD DROPDOWN ELEMENTS
-  // ===================================
-
-  $(document)
-    .on('click.bs.dropdown.data-api', clearMenus)
-    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
-    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
-    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
-    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: modal.js v3.3.4
- * http://getbootstrap.com/javascript/#modals
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // MODAL CLASS DEFINITION
-  // ======================
-
-  var Modal = function (element, options) {
-    this.options             = options
-    this.$body               = $(document.body)
-    this.$element            = $(element)
-    this.$dialog             = this.$element.find('.modal-dialog')
-    this.$backdrop           = null
-    this.isShown             = null
-    this.originalBodyPad     = null
-    this.scrollbarWidth      = 0
-    this.ignoreBackdropClick = false
-
-    if (this.options.remote) {
-      this.$element
-        .find('.modal-content')
-        .load(this.options.remote, $.proxy(function () {
-          this.$element.trigger('loaded.bs.modal')
-        }, this))
-    }
-  }
-
-  Modal.VERSION  = '3.3.4'
-
-  Modal.TRANSITION_DURATION = 300
-  Modal.BACKDROP_TRANSITION_DURATION = 150
-
-  Modal.DEFAULTS = {
-    backdrop: true,
-    keyboard: true,
-    show: true
-  }
-
-  Modal.prototype.toggle = function (_relatedTarget) {
-    return this.isShown ? this.hide() : this.show(_relatedTarget)
-  }
-
-  Modal.prototype.show = function (_relatedTarget) {
-    var that = this
-    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
-
-    this.$element.trigger(e)
-
-    if (this.isShown || e.isDefaultPrevented()) return
-
-    this.isShown = true
-
-    this.checkScrollbar()
-    this.setScrollbar()
-    this.$body.addClass('modal-open')
-
-    this.escape()
-    this.resize()
-
-    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
-
-    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
-      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
-        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
-      })
-    })
-
-    this.backdrop(function () {
-      var transition = $.support.transition && that.$element.hasClass('fade')
-
-      if (!that.$element.parent().length) {
-        that.$element.appendTo(that.$body) // don't move modals dom position
-      }
-
-      that.$element
-        .show()
-        .scrollTop(0)
-
-      that.adjustDialog()
-
-      if (transition) {
-        that.$element[0].offsetWidth // force reflow
-      }
-
-      that.$element.addClass('in')
-
-      that.enforceFocus()
-
-      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
-
-      transition ?
-        that.$dialog // wait for modal to slide in
-          .one('bsTransitionEnd', function () {
-            that.$element.trigger('focus').trigger(e)
-          })
-          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
-        that.$element.trigger('focus').trigger(e)
-    })
-  }
-
-  Modal.prototype.hide = function (e) {
-    if (e) e.preventDefault()
-
-    e = $.Event('hide.bs.modal')
-
-    this.$element.trigger(e)
-
-    if (!this.isShown || e.isDefaultPrevented()) return
-
-    this.isShown = false
-
-    this.escape()
-    this.resize()
-
-    $(document).off('focusin.bs.modal')
-
-    this.$element
-      .removeClass('in')
-      .off('click.dismiss.bs.modal')
-      .off('mouseup.dismiss.bs.modal')
-
-    this.$dialog.off('mousedown.dismiss.bs.modal')
-
-    $.support.transition && this.$element.hasClass('fade') ?
-      this.$element
-        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
-        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
-      this.hideModal()
-  }
-
-  Modal.prototype.enforceFocus = function () {
-    $(document)
-      .off('focusin.bs.modal') // guard against infinite focus loop
-      .on('focusin.bs.modal', $.proxy(function (e) {
-        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
-          this.$element.trigger('focus')
-        }
-      }, this))
-  }
-
-  Modal.prototype.escape = function () {
-    if (this.isShown && this.options.keyboard) {
-      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
-        e.which == 27 && this.hide()
-      }, this))
-    } else if (!this.isShown) {
-      this.$element.off('keydown.dismiss.bs.modal')
-    }
-  }
-
-  Modal.prototype.resize = function () {
-    if (this.isShown) {
-      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
-    } else {
-      $(window).off('resize.bs.modal')
-    }
-  }
-
-  Modal.prototype.hideModal = function () {
-    var that = this
-    this.$element.hide()
-    this.backdrop(function () {
-      that.$body.removeClass('modal-open')
-      that.resetAdjustments()
-      that.resetScrollbar()
-      that.$element.trigger('hidden.bs.modal')
-    })
-  }
-
-  Modal.prototype.removeBackdrop = function () {
-    this.$backdrop && this.$backdrop.remove()
-    this.$backdrop = null
-  }
-
-  Modal.prototype.backdrop = function (callback) {
-    var that = this
-    var animate = this.$element.hasClass('fade') ? 'fade' : ''
-
-    if (this.isShown && this.options.backdrop) {
-      var doAnimate = $.support.transition && animate
-
-      this.$backdrop = $(document.createElement('div'))
-        .addClass('modal-backdrop ' + animate)
-        .appendTo(this.$body)
-
-      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
-        if (this.ignoreBackdropClick) {
-          this.ignoreBackdropClick = false
-          return
-        }
-        if (e.target !== e.currentTarget) return
-        this.options.backdrop == 'static'
-          ? this.$element[0].focus()
-          : this.hide()
-      }, this))
-
-      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
-
-      this.$backdrop.addClass('in')
-
-      if (!callback) return
-
-      doAnimate ?
-        this.$backdrop
-          .one('bsTransitionEnd', callback)
-          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
-        callback()
-
-    } else if (!this.isShown && this.$backdrop) {
-      this.$backdrop.removeClass('in')
-
-      var callbackRemove = function () {
-        that.removeBackdrop()
-        callback && callback()
-      }
-      $.support.transition && this.$element.hasClass('fade') ?
-        this.$backdrop
-          .one('bsTransitionEnd', callbackRemove)
-          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
-        callbackRemove()
-
-    } else if (callback) {
-      callback()
-    }
-  }
-
-  // these following methods are used to handle overflowing modals
-
-  Modal.prototype.handleUpdate = function () {
-    this.adjustDialog()
-  }
-
-  Modal.prototype.adjustDialog = function () {
-    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
-
-    this.$element.css({
-      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
-      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
-    })
-  }
-
-  Modal.prototype.resetAdjustments = function () {
-    this.$element.css({
-      paddingLeft: '',
-      paddingRight: ''
-    })
-  }
-
-  Modal.prototype.checkScrollbar = function () {
-    var fullWindowWidth = window.innerWidth
-    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
-      var documentElementRect = document.documentElement.getBoundingClientRect()
-      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
-    }
-    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
-    this.scrollbarWidth = this.measureScrollbar()
-  }
-
-  Modal.prototype.setScrollbar = function () {
-    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
-    this.originalBodyPad = document.body.style.paddingRight || ''
-    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
-  }
-
-  Modal.prototype.resetScrollbar = function () {
-    this.$body.css('padding-right', this.originalBodyPad)
-  }
-
-  Modal.prototype.measureScrollbar = function () { // thx walsh
-    var scrollDiv = document.createElement('div')
-    scrollDiv.className = 'modal-scrollbar-measure'
-    this.$body.append(scrollDiv)
-    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
-    this.$body[0].removeChild(scrollDiv)
-    return scrollbarWidth
-  }
-
-
-  // MODAL PLUGIN DEFINITION
-  // =======================
-
-  function Plugin(option, _relatedTarget) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.modal')
-      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
-
-      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
-      if (typeof option == 'string') data[option](_relatedTarget)
-      else if (options.show) data.show(_relatedTarget)
-    })
-  }
-
-  var old = $.fn.modal
-
-  $.fn.modal             = Plugin
-  $.fn.modal.Constructor = Modal
-
-
-  // MODAL NO CONFLICT
-  // =================
-
-  $.fn.modal.noConflict = function () {
-    $.fn.modal = old
-    return this
-  }
-
-
-  // MODAL DATA-API
-  // ==============
-
-  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
-    var $this   = $(this)
-    var href    = $this.attr('href')
-    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
-    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
-
-    if ($this.is('a')) e.preventDefault()
-
-    $target.one('show.bs.modal', function (showEvent) {
-      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
-      $target.one('hidden.bs.modal', function () {
-        $this.is(':visible') && $this.trigger('focus')
-      })
-    })
-    Plugin.call($target, option, this)
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: tooltip.js v3.3.4
- * http://getbootstrap.com/javascript/#tooltip
- * Inspired by the original jQuery.tipsy by Jason Frame
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // TOOLTIP PUBLIC CLASS DEFINITION
-  // ===============================
-
-  var Tooltip = function (element, options) {
-    this.type       = null
-    this.options    = null
-    this.enabled    = null
-    this.timeout    = null
-    this.hoverState = null
-    this.$element   = null
-
-    this.init('tooltip', element, options)
-  }
-
-  Tooltip.VERSION  = '3.3.4'
-
-  Tooltip.TRANSITION_DURATION = 150
-
-  Tooltip.DEFAULTS = {
-    animation: true,
-    placement: 'top',
-    selector: false,
-    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
-    trigger: 'hover focus',
-    title: '',
-    delay: 0,
-    html: false,
-    container: false,
-    viewport: {
-      selector: 'body',
-      padding: 0
-    }
-  }
-
-  Tooltip.prototype.init = function (type, element, options) {
-    this.enabled   = true
-    this.type      = type
-    this.$element  = $(element)
-    this.options   = this.getOptions(options)
-    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
-
-    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
-      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
-    }
-
-    var triggers = this.options.trigger.split(' ')
-
-    for (var i = triggers.length; i--;) {
-      var trigger = triggers[i]
-
-      if (trigger == 'click') {
-        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
-      } else if (trigger != 'manual') {
-        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
-        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
-
-        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
-        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
-      }
-    }
-
-    this.options.selector ?
-      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
-      this.fixTitle()
-  }
-
-  Tooltip.prototype.getDefaults = function () {
-    return Tooltip.DEFAULTS
-  }
-
-  Tooltip.prototype.getOptions = function (options) {
-    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
-
-    if (options.delay && typeof options.delay == 'number') {
-      options.delay = {
-        show: options.delay,
-        hide: options.delay
-      }
-    }
-
-    return options
-  }
-
-  Tooltip.prototype.getDelegateOptions = function () {
-    var options  = {}
-    var defaults = this.getDefaults()
-
-    this._options && $.each(this._options, function (key, value) {
-      if (defaults[key] != value) options[key] = value
-    })
-
-    return options
-  }
-
-  Tooltip.prototype.enter = function (obj) {
-    var self = obj instanceof this.constructor ?
-      obj : $(obj.currentTarget).data('bs.' + this.type)
-
-    if (self && self.$tip && self.$tip.is(':visible')) {
-      self.hoverState = 'in'
-      return
-    }
-
-    if (!self) {
-      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
-      $(obj.currentTarget).data('bs.' + this.type, self)
-    }
-
-    clearTimeout(self.timeout)
-
-    self.hoverState = 'in'
-
-    if (!self.options.delay || !self.options.delay.show) return self.show()
-
-    self.timeout = setTimeout(function () {
-      if (self.hoverState == 'in') self.show()
-    }, self.options.delay.show)
-  }
-
-  Tooltip.prototype.leave = function (obj) {
-    var self = obj instanceof this.constructor ?
-      obj : $(obj.currentTarget).data('bs.' + this.type)
-
-    if (!self) {
-      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
-      $(obj.currentTarget).data('bs.' + this.type, self)
-    }
-
-    clearTimeout(self.timeout)
-
-    self.hoverState = 'out'
-
-    if (!self.options.delay || !self.options.delay.hide) return self.hide()
-
-    self.timeout = setTimeout(function () {
-      if (self.hoverState == 'out') self.hide()
-    }, self.options.delay.hide)
-  }
-
-  Tooltip.prototype.show = function () {
-    var e = $.Event('show.bs.' + this.type)
-
-    if (this.hasContent() && this.enabled) {
-      this.$element.trigger(e)
-
-      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
-      if (e.isDefaultPrevented() || !inDom) return
-      var that = this
-
-      var $tip = this.tip()
-
-      var tipId = this.getUID(this.type)
-
-      this.setContent()
-      $tip.attr('id', tipId)
-      this.$element.attr('aria-describedby', tipId)
-
-      if (this.options.animation) $tip.addClass('fade')
-
-      var placement = typeof this.options.placement == 'function' ?
-        this.options.placement.call(this, $tip[0], this.$element[0]) :
-        this.options.placement
-
-      var autoToken = /\s?auto?\s?/i
-      var autoPlace = autoToken.test(placement)
-      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
-
-      $tip
-        .detach()
-        .css({ top: 0, left: 0, display: 'block' })
-        .addClass(placement)
-        .data('bs.' + this.type, this)
-
-      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
-
-      var pos          = this.getPosition()
-      var actualWidth  = $tip[0].offsetWidth
-      var actualHeight = $tip[0].offsetHeight
-
-      if (autoPlace) {
-        var orgPlacement = placement
-        var $container   = this.options.container ? $(this.options.container) : this.$element.parent()
-        var containerDim = this.getPosition($container)
-
-        placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top'    :
-                    placement == 'top'    && pos.top    - actualHeight < containerDim.top    ? 'bottom' :
-                    placement == 'right'  && pos.right  + actualWidth  > containerDim.width  ? 'left'   :
-                    placement == 'left'   && pos.left   - actualWidth  < containerDim.left   ? 'right'  :
-                    placement
-
-        $tip
-          .removeClass(orgPlacement)
-          .addClass(placement)
-      }
-
-      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
-
-      this.applyPlacement(calculatedOffset, placement)
-
-      var complete = function () {
-        var prevHoverState = that.hoverState
-        that.$element.trigger('shown.bs.' + that.type)
-        that.hoverState = null
-
-        if (prevHoverState == 'out') that.leave(that)
-      }
-
-      $.support.transition && this.$tip.hasClass('fade') ?
-        $tip
-          .one('bsTransitionEnd', complete)
-          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
-        complete()
-    }
-  }
-
-  Tooltip.prototype.applyPlacement = function (offset, placement) {
-    var $tip   = this.tip()
-    var width  = $tip[0].offsetWidth
-    var height = $tip[0].offsetHeight
-
-    // manually read margins because getBoundingClientRect includes difference
-    var marginTop = parseInt($tip.css('margin-top'), 10)
-    var marginLeft = parseInt($tip.css('margin-left'), 10)
-
-    // we must check for NaN for ie 8/9
-    if (isNaN(marginTop))  marginTop  = 0
-    if (isNaN(marginLeft)) marginLeft = 0
-
-    offset.top  = offset.top  + marginTop
-    offset.left = offset.left + marginLeft
-
-    // $.fn.offset doesn't round pixel values
-    // so we use setOffset directly with our own function B-0
-    $.offset.setOffset($tip[0], $.extend({
-      using: function (props) {
-        $tip.css({
-          top: Math.round(props.top),
-          left: Math.round(props.left)
-        })
-      }
-    }, offset), 0)
-
-    $tip.addClass('in')
-
-    // check to see if placing tip in new offset caused the tip to resize itself
-    var actualWidth  = $tip[0].offsetWidth
-    var actualHeight = $tip[0].offsetHeight
-
-    if (placement == 'top' && actualHeight != height) {
-      offset.top = offset.top + height - actualHeight
-    }
-
-    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
-
-    if (delta.left) offset.left += delta.left
-    else offset.top += delta.top
-
-    var isVertical          = /top|bottom/.test(placement)
-    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
-    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
-
-    $tip.offset(offset)
-    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
-  }
-
-  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
-    this.arrow()
-      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
-      .css(isVertical ? 'top' : 'left', '')
-  }
-
-  Tooltip.prototype.setContent = function () {
-    var $tip  = this.tip()
-    var title = this.getTitle()
-
-    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
-    $tip.removeClass('fade in top bottom left right')
-  }
-
-  Tooltip.prototype.hide = function (callback) {
-    var that = this
-    var $tip = $(this.$tip)
-    var e    = $.Event('hide.bs.' + this.type)
-
-    function complete() {
-      if (that.hoverState != 'in') $tip.detach()
-      that.$element
-        .removeAttr('aria-describedby')
-        .trigger('hidden.bs.' + that.type)
-      callback && callback()
-    }
-
-    this.$element.trigger(e)
-
-    if (e.isDefaultPrevented()) return
-
-    $tip.removeClass('in')
-
-    $.support.transition && $tip.hasClass('fade') ?
-      $tip
-        .one('bsTransitionEnd', complete)
-        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
-      complete()
-
-    this.hoverState = null
-
-    return this
-  }
-
-  Tooltip.prototype.fixTitle = function () {
-    var $e = this.$element
-    if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
-      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
-    }
-  }
-
-  Tooltip.prototype.hasContent = function () {
-    return this.getTitle()
-  }
-
-  Tooltip.prototype.getPosition = function ($element) {
-    $element   = $element || this.$element
-
-    var el     = $element[0]
-    var isBody = el.tagName == 'BODY'
-
-    var elRect    = el.getBoundingClientRect()
-    if (elRect.width == null) {
-      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
-      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
-    }
-    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()
-    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
-    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
-
-    return $.extend({}, elRect, scroll, outerDims, elOffset)
-  }
-
-  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
-    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
-           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
-           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
-        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
-
-  }
-
-  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
-    var delta = { top: 0, left: 0 }
-    if (!this.$viewport) return delta
-
-    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
-    var viewportDimensions = this.getPosition(this.$viewport)
-
-    if (/right|left/.test(placement)) {
-      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
-      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
-      if (topEdgeOffset < viewportDimensions.top) { // top overflow
-        delta.top = viewportDimensions.top - topEdgeOffset
-      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
-        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
-      }
-    } else {
-      var leftEdgeOffset  = pos.left - viewportPadding
-      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
-      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
-        delta.left = viewportDimensions.left - leftEdgeOffset
-      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
-        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
-      }
-    }
-
-    return delta
-  }
-
-  Tooltip.prototype.getTitle = function () {
-    var title
-    var $e = this.$element
-    var o  = this.options
-
-    title = $e.attr('data-original-title')
-      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
-
-    return title
-  }
-
-  Tooltip.prototype.getUID = function (prefix) {
-    do prefix += ~~(Math.random() * 1000000)
-    while (document.getElementById(prefix))
-    return prefix
-  }
-
-  Tooltip.prototype.tip = function () {
-    return (this.$tip = this.$tip || $(this.options.template))
-  }
-
-  Tooltip.prototype.arrow = function () {
-    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
-  }
-
-  Tooltip.prototype.enable = function () {
-    this.enabled = true
-  }
-
-  Tooltip.prototype.disable = function () {
-    this.enabled = false
-  }
-
-  Tooltip.prototype.toggleEnabled = function () {
-    this.enabled = !this.enabled
-  }
-
-  Tooltip.prototype.toggle = function (e) {
-    var self = this
-    if (e) {
-      self = $(e.currentTarget).data('bs.' + this.type)
-      if (!self) {
-        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
-        $(e.currentTarget).data('bs.' + this.type, self)
-      }
-    }
-
-    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
-  }
-
-  Tooltip.prototype.destroy = function () {
-    var that = this
-    clearTimeout(this.timeout)
-    this.hide(function () {
-      that.$element.off('.' + that.type).removeData('bs.' + that.type)
-    })
-  }
-
-
-  // TOOLTIP PLUGIN DEFINITION
-  // =========================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.tooltip')
-      var options = typeof option == 'object' && option
-
-      if (!data && /destroy|hide/.test(option)) return
-      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  var old = $.fn.tooltip
-
-  $.fn.tooltip             = Plugin
-  $.fn.tooltip.Constructor = Tooltip
-
-
-  // TOOLTIP NO CONFLICT
-  // ===================
-
-  $.fn.tooltip.noConflict = function () {
-    $.fn.tooltip = old
-    return this
-  }
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: popover.js v3.3.4
- * http://getbootstrap.com/javascript/#popovers
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // POPOVER PUBLIC CLASS DEFINITION
-  // ===============================
-
-  var Popover = function (element, options) {
-    this.init('popover', element, options)
-  }
-
-  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
-
-  Popover.VERSION  = '3.3.4'
-
-  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
-    placement: 'right',
-    trigger: 'click',
-    content: '',
-    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
-  })
-
-
-  // NOTE: POPOVER EXTENDS tooltip.js
-  // ================================
-
-  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
-
-  Popover.prototype.constructor = Popover
-
-  Popover.prototype.getDefaults = function () {
-    return Popover.DEFAULTS
-  }
-
-  Popover.prototype.setContent = function () {
-    var $tip    = this.tip()
-    var title   = this.getTitle()
-    var content = this.getContent()
-
-    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
-    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
-      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
-    ](content)
-
-    $tip.removeClass('fade top bottom left right in')
-
-    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
-    // this manually by checking the contents.
-    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
-  }
-
-  Popover.prototype.hasContent = function () {
-    return this.getTitle() || this.getContent()
-  }
-
-  Popover.prototype.getContent = function () {
-    var $e = this.$element
-    var o  = this.options
-
-    return $e.attr('data-content')
-      || (typeof o.content == 'function' ?
-            o.content.call($e[0]) :
-            o.content)
-  }
-
-  Popover.prototype.arrow = function () {
-    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
-  }
-
-
-  // POPOVER PLUGIN DEFINITION
-  // =========================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.popover')
-      var options = typeof option == 'object' && option
-
-      if (!data && /destroy|hide/.test(option)) return
-      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  var old = $.fn.popover
-
-  $.fn.popover             = Plugin
-  $.fn.popover.Constructor = Popover
-
-
-  // POPOVER NO CONFLICT
-  // ===================
-
-  $.fn.popover.noConflict = function () {
-    $.fn.popover = old
-    return this
-  }
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: scrollspy.js v3.3.4
- * http://getbootstrap.com/javascript/#scrollspy
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // SCROLLSPY CLASS DEFINITION
-  // ==========================
-
-  function ScrollSpy(element, options) {
-    this.$body          = $(document.body)
-    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
-    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
-    this.selector       = (this.options.target || '') + ' .nav li > a'
-    this.offsets        = []
-    this.targets        = []
-    this.activeTarget   = null
-    this.scrollHeight   = 0
-
-    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
-    this.refresh()
-    this.process()
-  }
-
-  ScrollSpy.VERSION  = '3.3.4'
-
-  ScrollSpy.DEFAULTS = {
-    offset: 10
-  }
-
-  ScrollSpy.prototype.getScrollHeight = function () {
-    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
-  }
-
-  ScrollSpy.prototype.refresh = function () {
-    var that          = this
-    var offsetMethod  = 'offset'
-    var offsetBase    = 0
-
-    this.offsets      = []
-    this.targets      = []
-    this.scrollHeight = this.getScrollHeight()
-
-    if (!$.isWindow(this.$scrollElement[0])) {
-      offsetMethod = 'position'
-      offsetBase   = this.$scrollElement.scrollTop()
-    }
-
-    this.$body
-      .find(this.selector)
-      .map(function () {
-        var $el   = $(this)
-        var href  = $el.data('target') || $el.attr('href')
-        var $href = /^#./.test(href) && $(href)
-
-        return ($href
-          && $href.length
-          && $href.is(':visible')
-          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
-      })
-      .sort(function (a, b) { return a[0] - b[0] })
-      .each(function () {
-        that.offsets.push(this[0])
-        that.targets.push(this[1])
-      })
-  }
-
-  ScrollSpy.prototype.process = function () {
-    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
-    var scrollHeight = this.getScrollHeight()
-    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
-    var offsets      = this.offsets
-    var targets      = this.targets
-    var activeTarget = this.activeTarget
-    var i
-
-    if (this.scrollHeight != scrollHeight) {
-      this.refresh()
-    }
-
-    if (scrollTop >= maxScroll) {
-      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
-    }
-
-    if (activeTarget && scrollTop < offsets[0]) {
-      this.activeTarget = null
-      return this.clear()
-    }
-
-    for (i = offsets.length; i--;) {
-      activeTarget != targets[i]
-        && scrollTop >= offsets[i]
-        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
-        && this.activate(targets[i])
-    }
-  }
-
-  ScrollSpy.prototype.activate = function (target) {
-    this.activeTarget = target
-
-    this.clear()
-
-    var selector = this.selector +
-      '[data-target="' + target + '"],' +
-      this.selector + '[href="' + target + '"]'
-
-    var active = $(selector)
-      .parents('li')
-      .addClass('active')
-
-    if (active.parent('.dropdown-menu').length) {
-      active = active
-        .closest('li.dropdown')
-        .addClass('active')
-    }
-
-    active.trigger('activate.bs.scrollspy')
-  }
-
-  ScrollSpy.prototype.clear = function () {
-    $(this.selector)
-      .parentsUntil(this.options.target, '.active')
-      .removeClass('active')
-  }
-
-
-  // SCROLLSPY PLUGIN DEFINITION
-  // ===========================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.scrollspy')
-      var options = typeof option == 'object' && option
-
-      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  var old = $.fn.scrollspy
-
-  $.fn.scrollspy             = Plugin
-  $.fn.scrollspy.Constructor = ScrollSpy
-
-
-  // SCROLLSPY NO CONFLICT
-  // =====================
-
-  $.fn.scrollspy.noConflict = function () {
-    $.fn.scrollspy = old
-    return this
-  }
-
-
-  // SCROLLSPY DATA-API
-  // ==================
-
-  $(window).on('load.bs.scrollspy.data-api', function () {
-    $('[data-spy="scroll"]').each(function () {
-      var $spy = $(this)
-      Plugin.call($spy, $spy.data())
-    })
-  })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: tab.js v3.3.4
- * http://getbootstrap.com/javascript/#tabs
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // TAB CLASS DEFINITION
-  // ====================
-
-  var Tab = function (element) {
-    this.element = $(element)
-  }
-
-  Tab.VERSION = '3.3.4'
-
-  Tab.TRANSITION_DURATION = 150
-
-  Tab.prototype.show = function () {
-    var $this    = this.element
-    var $ul      = $this.closest('ul:not(.dropdown-menu)')
-    var selector = $this.data('target')
-
-    if (!selector) {
-      selector = $this.attr('href')
-      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
-    }
-
-    if ($this.parent('li').hasClass('active')) return
-
-    var $previous = $ul.find('.active:last a')
-    var hideEvent = $.Event('hide.bs.tab', {
-      relatedTarget: $this[0]
-    })
-    var showEvent = $.Event('show.bs.tab', {
-      relatedTarget: $previous[0]
-    })
-
-    $previous.trigger(hideEvent)
-    $this.trigger(showEvent)
-
-    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
-
-    var $target = $(selector)
-
-    this.activate($this.closest('li'), $ul)
-    this.activate($target, $target.parent(), function () {
-      $previous.trigger({
-        type: 'hidden.bs.tab',
-        relatedTarget: $this[0]
-      })
-      $this.trigger({
-        type: 'shown.bs.tab',
-        relatedTarget: $previous[0]
-      })
-    })
-  }
-
-  Tab.prototype.activate = function (element, container, callback) {
-    var $active    = container.find('> .active')
-    var transition = callback
-      && $.support.transition
-      && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
-
-    function next() {
-      $active
-        .removeClass('active')
-        .find('> .dropdown-menu > .active')
-          .removeClass('active')
-        .end()
-        .find('[data-toggle="tab"]')
-          .attr('aria-expanded', false)
-
-      element
-        .addClass('active')
-        .find('[data-toggle="tab"]')
-          .attr('aria-expanded', true)
-
-      if (transition) {
-        element[0].offsetWidth // reflow for transition
-        element.addClass('in')
-      } else {
-        element.removeClass('fade')
-      }
-
-      if (element.parent('.dropdown-menu').length) {
-        element
-          .closest('li.dropdown')
-            .addClass('active')
-          .end()
-          .find('[data-toggle="tab"]')
-            .attr('aria-expanded', true)
-      }
-
-      callback && callback()
-    }
-
-    $active.length && transition ?
-      $active
-        .one('bsTransitionEnd', next)
-        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
-      next()
-
-    $active.removeClass('in')
-  }
-
-
-  // TAB PLUGIN DEFINITION
-  // =====================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this = $(this)
-      var data  = $this.data('bs.tab')
-
-      if (!data) $this.data('bs.tab', (data = new Tab(this)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  var old = $.fn.tab
-
-  $.fn.tab             = Plugin
-  $.fn.tab.Constructor = Tab
-
-
-  // TAB NO CONFLICT
-  // ===============
-
-  $.fn.tab.noConflict = function () {
-    $.fn.tab = old
-    return this
-  }
-
-
-  // TAB DATA-API
-  // ============
-
-  var clickHandler = function (e) {
-    e.preventDefault()
-    Plugin.call($(this), 'show')
-  }
-
-  $(document)
-    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
-    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: affix.js v3.3.4
- * http://getbootstrap.com/javascript/#affix
- * ========================================================================
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
-  'use strict';
-
-  // AFFIX CLASS DEFINITION
-  // ======================
-
-  var Affix = function (element, options) {
-    this.options = $.extend({}, Affix.DEFAULTS, options)
-
-    this.$target = $(this.options.target)
-      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
-      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
-
-    this.$element     = $(element)
-    this.affixed      = null
-    this.unpin        = null
-    this.pinnedOffset = null
-
-    this.checkPosition()
-  }
-
-  Affix.VERSION  = '3.3.4'
-
-  Affix.RESET    = 'affix affix-top affix-bottom'
-
-  Affix.DEFAULTS = {
-    offset: 0,
-    target: window
-  }
-
-  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
-    var scrollTop    = this.$target.scrollTop()
-    var position     = this.$element.offset()
-    var targetHeight = this.$target.height()
-
-    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
-
-    if (this.affixed == 'bottom') {
-      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
-      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
-    }
-
-    var initializing   = this.affixed == null
-    var colliderTop    = initializing ? scrollTop : position.top
-    var colliderHeight = initializing ? targetHeight : height
-
-    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
-    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
-
-    return false
-  }
-
-  Affix.prototype.getPinnedOffset = function () {
-    if (this.pinnedOffset) return this.pinnedOffset
-    this.$element.removeClass(Affix.RESET).addClass('affix')
-    var scrollTop = this.$target.scrollTop()
-    var position  = this.$element.offset()
-    return (this.pinnedOffset = position.top - scrollTop)
-  }
-
-  Affix.prototype.checkPositionWithEventLoop = function () {
-    setTimeout($.proxy(this.checkPosition, this), 1)
-  }
-
-  Affix.prototype.checkPosition = function () {
-    if (!this.$element.is(':visible')) return
-
-    var height       = this.$element.height()
-    var offset       = this.options.offset
-    var offsetTop    = offset.top
-    var offsetBottom = offset.bottom
-    var scrollHeight = $(document.body).height()
-
-    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
-    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
-    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
-
-    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
-
-    if (this.affixed != affix) {
-      if (this.unpin != null) this.$element.css('top', '')
-
-      var affixType = 'affix' + (affix ? '-' + affix : '')
-      var e         = $.Event(affixType + '.bs.affix')
-
-      this.$element.trigger(e)
-
-      if (e.isDefaultPrevented()) return
-
-      this.affixed = affix
-      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
-
-      this.$element
-        .removeClass(Affix.RESET)
-        .addClass(affixType)
-        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
-    }
-
-    if (affix == 'bottom') {
-      this.$element.offset({
-        top: scrollHeight - height - offsetBottom
-      })
-    }
-  }
-
-
-  // AFFIX PLUGIN DEFINITION
-  // =======================
-
-  function Plugin(option) {
-    return this.each(function () {
-      var $this   = $(this)
-      var data    = $this.data('bs.affix')
-      var options = typeof option == 'object' && option
-
-      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  var old = $.fn.affix
-
-  $.fn.affix             = Plugin
-  $.fn.affix.Constructor = Affix
-
-
-  // AFFIX NO CONFLICT
-  // =================
-
-  $.fn.affix.noConflict = function () {
-    $.fn.affix = old
-    return this
-  }
-
-
-  // AFFIX DATA-API
-  // ==============
-
-  $(window).on('load', function () {
-    $('[data-spy="affix"]').each(function () {
-      var $spy = $(this)
-      var data = $spy.data()
-
-      data.offset = data.offset || {}
-
-      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
-      if (data.offsetTop    != null) data.offset.top    = data.offsetTop
-
-      Plugin.call($spy, data)
-    })
-  })
-
-}(jQuery);
diff --git a/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.min.js b/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.min.js
deleted file mode 100644
index 156b6b5..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/js/bootstrap.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * Bootstrap v3.3.4 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.4",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.4",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.4",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(b&&"click"==b.type&&/input|textarea/i.test(b.target.tagName)&&a.contains(e[0],b.target)||(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.4",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27|32)/.test(b.which)&&!/input|textarea/i.test(b.target.tagName)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g&&27!=b.which||g&&27==b.which)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(b.target);38==b.which&&j>0&&j--,40==b.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport),this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-m<p.top?"bottom":"right"==h&&k.right+l>p.width?"left":"left"==h&&k.left-l<p.left?"right":h,f.removeClass(n).addClass(h)}var q=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(q,h);var r=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",r).emulateTransitionEnd(c.TRANSITION_DURATION):r()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.4",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.4",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),
-!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.4",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a(document.body).height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
\ No newline at end of file
diff --git a/hubs/static/bootstrap-3.3.4-fedora/js/npm.js b/hubs/static/bootstrap-3.3.4-fedora/js/npm.js
deleted file mode 100644
index bf6aa80..0000000
--- a/hubs/static/bootstrap-3.3.4-fedora/js/npm.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
-require('../../js/transition.js')
-require('../../js/alert.js')
-require('../../js/button.js')
-require('../../js/carousel.js')
-require('../../js/collapse.js')
-require('../../js/dropdown.js')
-require('../../js/modal.js')
-require('../../js/tooltip.js')
-require('../../js/popover.js')
-require('../../js/scrollspy.js')
-require('../../js/tab.js')
-require('../../js/affix.js')
\ No newline at end of file

From f4a563c7a40690fb9825b6bddd5662429a192b60 Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 26 2016 10:27:35 +0000
Subject: [PATCH 452/1001] added master template


added a master template, and changed hub.html and groups.html
to use the new master tempate

---

diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
index 230e54a..0d3bc20 100644
--- a/hubs/templates/groups.html
+++ b/hubs/templates/groups.html
@@ -1,80 +1,8 @@
-<html>
-<head>
-  <title>Groups</title>
-  <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet" />
-  <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
-  <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
-</head>
-<script src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
-<body>
-<div class="super-header">
-  <div class="row">
-    <div class="col-xs-4" id="logo">
-      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs">
-    </div>
-    <div class="col-sm-4 col-sm-push-4 col-xs-8">
-      {% if g.auth.logged_in %}
-        <div class="dropdown pull-right">
-          <img class = "icon" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
-        <span class="dropdown-toggle" type="button" id="dropdownMenu1"
-            data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
-          <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
-          {# Logged in as #} {{ g.auth.nickname }}
-          <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
-        </span>
-        <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
-          <li class="dropdown-header">Account Information</li>
-          <li><a href="#">Full Name: {{ g.auth.fullname }}</a></li>
-          <li><a href="#">Email: {{ g.auth.email }}</a></li>
-          <li role="separator" class="divider"></li>
-          <li><a href="#">Separated link</a></li>
-        </ul>
-      </div>
-      {% else %}
-        Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
-      {% endif %}
-    </div>
-    <div class="col-sm-4 col-sm-pull-4 col-xs-12">
-      <!-- NOT HOOKED UP TO ANYTHING XOXO -->
-      <div class="input-group">
-        <input type="search" placeholder="Search across all hubs ..."></input>
-        <span class="input-group-addon">
-          <span class="glyphicon glyphicon-search"></span>
-        </span>
-    </div>
-    </div>
-  </div>
-</div>
-<div class="bookmarks">
-  <nav class="navbar navbar-default">
-    <div class="container-fluid">
-      <div class="navbar-header">
-        <button type="button" class="navbar-toggle collapsed"
-            data-toggle="collapse"
-            data-target="#bs-example-navbar-collapse-1">
-          <span class="sr-only">Toggle navigation</span>
-          <span class="icon-bar"></span>
-          <span class="icon-bar"></span>
-          <span class="icon-bar"></span>
-        </button>
-      </div>
+{% extends "master.html" %}
+
+{% block title %}Groups{% endblock %}
+{% block content %}
 
-      <!-- Collect the nav links, forms, and other content for toggling -->
-      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
-        <ul class="nav navbar-nav">
-          {% if g.auth.logged_in %}
-          <li {% if request.path.endswith('/' + g.auth.user.username + '/') %}class='active'{% endif %}>
-            <a href="/{{g.auth.user.username}}">me</a></li>
-          {% for hub in g.auth.user.bookmarks %}
-          <li class='idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
-          <a href="/{{hub.name}}">{{hub.name}}</a></li>
-          {% endfor %}
-          {% endif %}
-        </ul>
-      </div><!-- /.navbar-collapse -->
-    </div><!-- /.container-fluid -->
-  </nav>
-</div>
 <div class="header">
   <div class="img-wrap">
     <img src="#" />
@@ -129,8 +57,4 @@
     </div>
   </div>
 </div>
-
-<script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
-<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
-</body>
-</html>
+{% endblock %}
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 5d3891b..f4fa36b 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -1,76 +1,7 @@
-<!DOCTYPE html>
-<html lang='en'>
-<head>
-  <title>{{ hub.name }}</title>
-  <link href="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.css') }}" rel="stylesheet" />
-  <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
-  <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
-  <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
-  <link href="{{ url_for('static', filename='open_iconic_1.1.0/css/open-iconic.min.css') }}"
-        type="text/css" rel="stylesheet" />
-</head>
-<body>
-<div class="masthead">
-  <div class="row p-a-0">
-    <div class="col-xs-4" id="logo">
-      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs" height="40px" class="p-l-1">
-    </div>
-    <div class="col-sm-4 col-sm-push-4 col-xs-8">
-      {% if g.auth.logged_in %}
-        <div class="dropdown pull-xs-right showpointer">
-          <span class="dropdown-toggle m-r-1" type="button" id="dropdownMenu1"
-            data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
-            <img src="{{ g.auth.avatar }}" id="avatar" alt="User Icon"/>
-          </span>
-          <div class="dropdown-menu dropdown-menu-right m-r-1" aria-labelledby="dropdownMenu1">
-            <h6 class="dropdown-header">Account Information</h6>
-            <a href="#" class="dropdown-item">Full Name: {{ g.auth.fullname }}</a>
-            <a href="#" class="dropdown-item">Email: {{ g.auth.email }}</a>
-            <div class="dropdown-divider"></div>
-            <a href="#" class="dropdown-item">Separated link</a>
-          </div>
-        </div>
-        <img id="chaticon" class="pull-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
-      {% else %}
-        Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
-      {% endif %}
-    </div>
-    <div class="col-sm-4 col-sm-pull-4 col-xs-12">
-      <!-- NOT HOOKED UP TO ANYTHING XOXO -->
-      <div class="input-group">
-        <input type="search" class="form-control" placeholder="Search across all hubs ..." aria-describedby="searchform-addon"></input>
-        <span class="input-group-addon" id="searchform-addon">
-          <span class="oi" data-glyph="magnifying-glass" / >
-        </span>
-    </div>
-    </div>
-  </div>
-</div>
-<div class="bodycontent">
-
-  <nav class="navbar navbar-light navbar-underline p-t-0 p-b-0">
-        <button type="button" class="navbar-toggler hidden-sm-up"
-            data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
-          <span class="sr-only">Toggle navigation</span>
-          <span class="oi" data-glyph="menu"></span>
-        </button>
+{% extends "master.html" %}
 
-      <!-- Collect the nav links, forms, and other content for toggling -->
-      <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
-        <ul class="nav navbar-nav nav-underline">
-          {% if g.auth.logged_in %}
-          <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
-            <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
-          {% for hub in g.auth.user.bookmarks %}
-          <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
-          <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
-          {% endfor %}
-          <!-- At the end of the list, tack on a link to all groups -->
-          <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
-          {% endif %}
-        </ul>
-      </div><!-- /.navbar-collapse -->
-  </nav>
+{% block title %}{{ hub.name }}{% endblock %}
+{% block content %}
 <div class="header">
   {% if hub.user_hub %}
     <div class="padded center-block medium-wide">
@@ -229,12 +160,10 @@
   </div>
 </div>
 
-</div> <!--end bodycontent-->
+{% endblock %}
 
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
-  <script type="text/javascript" src="{{
-  url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
+{% block jscripts %}
+{{ super() }}
 <script type="text/javascript" src="{{
   url_for('static', filename='js/utils.js') }}"></script>
 
@@ -334,5 +263,4 @@ function setup_widgets(widgets) {
 setup_widgets();
 
 </script>
-</body>
-</html>
+{% endblock %}
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
new file mode 100644
index 0000000..ba26ba7
--- /dev/null
+++ b/hubs/templates/master.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+  <title>{% block title %}{% endblock %}</title>
+  <link href="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
+  <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
+  <link href="{{ url_for('static', filename='open_iconic_1.1.0/css/open-iconic.min.css') }}"
+        type="text/css" rel="stylesheet" />
+</head>
+<body>
+<div class="masthead">
+  <div class="row p-a-0">
+    <div class="col-xs-4" id="logo">
+      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs" height="40px" class="p-l-1">
+    </div>
+    <div class="col-sm-4 col-sm-push-4 col-xs-8">
+      {% if g.auth.logged_in %}
+        <div class="dropdown pull-xs-right showpointer">
+          <span class="dropdown-toggle m-r-1" type="button" id="dropdownMenu1"
+            data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+            <img src="{{ g.auth.avatar }}" id="avatar" alt="User Icon"/>
+          </span>
+          <div class="dropdown-menu dropdown-menu-right m-r-1" aria-labelledby="dropdownMenu1">
+            <h6 class="dropdown-header">Account Information</h6>
+            <a href="#" class="dropdown-item">Full Name: {{ g.auth.fullname }}</a>
+            <a href="#" class="dropdown-item">Email: {{ g.auth.email }}</a>
+            <div class="dropdown-divider"></div>
+            <a href="#" class="dropdown-item">Separated link</a>
+          </div>
+        </div>
+        <img id="chaticon" class="pull-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
+      {% else %}
+        Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
+      {% endif %}
+    </div>
+    <div class="col-sm-4 col-sm-pull-4 col-xs-12">
+      <!-- NOT HOOKED UP TO ANYTHING XOXO -->
+      <div class="input-group">
+        <input type="search" class="form-control" placeholder="Search across all hubs ..." aria-describedby="searchform-addon"></input>
+        <span class="input-group-addon" id="searchform-addon">
+          <span class="oi" data-glyph="magnifying-glass" / >
+        </span>
+    </div>
+    </div>
+  </div>
+</div>
+<div class="bodycontent">
+
+  <nav class="navbar navbar-light navbar-underline p-t-0 p-b-0">
+        <button type="button" class="navbar-toggler hidden-sm-up"
+            data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+          <span class="sr-only">Toggle navigation</span>
+          <span class="oi" data-glyph="menu"></span>
+        </button>
+
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav nav-underline">
+          {% if g.auth.logged_in %}
+          <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
+            <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
+          {% for hub in g.auth.user.bookmarks %}
+          <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
+          <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
+          {% endfor %}
+          <!-- At the end of the list, tack on a link to all groups -->
+          <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
+          {% endif %}
+        </ul>
+      </div><!-- /.navbar-collapse -->
+  </nav>
+{% block content %}{% endblock %}
+
+</div> <!--end bodycontent-->
+{% block jscripts %}
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+  <script type="text/javascript" src="{{
+  url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
+{% endblock %}
+
+</body>
+</html>

From 6e2d26bb88aea654c6e5975e7344351e66ca00d3 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 13:47:08 +0000
Subject: [PATCH 453/1001] Enforce that each widget has a position that must be in 'left', 'right' or 'both'


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 551876a..2e72e00 100755
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -57,6 +57,13 @@ def validate_registry(registry):
         if not callable(module.template.render):
             raise TypeError('%r\'s template.render not callable' % module)
 
+        if not hasattr(module, 'position'):
+            raise AttributeError('%r has not "position" function' % module)
+        if module.position not in ['left', 'right', 'both']:
+            raise TypeError(
+                '%r\'s "position" is not: `left`, `right` or `both`'
+                % module)
+
         if not hasattr(module, 'data'):
             raise AttributeError('%r has not "data" function' % module)
         if not callable(module.data):

From 4c983f4c868a2f2fbef3c14e1f09c1c39b3ea58b Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 13:47:08 +0000
Subject: [PATCH 454/1001] Set a position to each existing widget


---

diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index 061ec6e..2383081 100755
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -8,7 +8,7 @@ import hubs.validators as validators
 
 chrome = panel("<span class='glyphicon glyphicon-info-sign' aria-hidden='true'></span> About")
 template = templating.environment.get_template('templates/about.html')
-
+position = 'both'
 
 @argument(name="text", default="I am a Fedora user, and this is my about",
           validator=validators.text,
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index f65c4fb..4ddbb3d 100755
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -11,7 +11,7 @@ import hubs.validators as validators
 from hubs.widgets.chrome import panel
 chrome = panel("Badges")
 template = templating.environment.get_template('templates/badges.html')
-
+position = 'right'
 
 @argument(name="username",
           default=None,
diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
index 2576963..856f975 100644
--- a/hubs/widgets/bugzilla.py
+++ b/hubs/widgets/bugzilla.py
@@ -9,7 +9,7 @@ from hubs.hinting import hint
 
 chrome = panel("Bugzilla: Issues")
 template = templating.environment.get_template('templates/bugzilla.html')
-
+position = 'right'
 
 @argument(name="username",
           default=None,
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index c6fbb90..f25f65a 100755
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -7,6 +7,7 @@ import hubs.validators as validators
 
 chrome = panel("This is a dummy widget")
 template = templating.environment.get_template('templates/dummy.html')
+position = 'both'
 
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index d06f398..9cd15fd 100755
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -14,6 +14,7 @@ config = fedmsg.config.load_config()
 
 chrome = panel()
 template = templating.environment.get_template('templates/fedmsgstats.html')
+position = 'both'
 
 
 def data(session, widget, username):
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 2e61dc7..282a400 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -38,7 +38,7 @@ paths = fmn.lib.load_rules(root='fmn.rules')
 #from hubs.widgets.chrome import panel
 #chrome = panel()
 template = templating.environment.get_template('templates/feed.html')
-
+position = 'left'
 
 def apply_markup(match):
     markup = match['subtitle']
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index 5ee081a..b2d1788 100755
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -15,6 +15,7 @@ log = logging.getLogger(__name__)
 
 chrome = panel("Github: Pull Requests")
 template = templating.environment.get_template('templates/github_pr.html')
+position = 'right'
 
 
 @argument(name="display_number",
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
index 35536f7..2bd6c87 100755
--- a/hubs/widgets/githubissues.py
+++ b/hubs/widgets/githubissues.py
@@ -7,6 +7,7 @@ import requests
 
 chrome = panel("Github: Newest Open Tickets")
 template = templating.environment.get_template('templates/githubissues.html')
+position = 'right'
 
 
 @argument(name="repo",
diff --git a/hubs/widgets/linechart.py b/hubs/widgets/linechart.py
index ee47d85..2c5562f 100755
--- a/hubs/widgets/linechart.py
+++ b/hubs/widgets/linechart.py
@@ -10,6 +10,7 @@ config = fedmsg.config.load_config()
 from hubs.widgets.chrome import panel
 chrome = panel("Weekly Activity")
 template = templating.environment.get_template('templates/linechart.html')
+position = 'left'
 
 
 @argument(name="username",
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 3a40832..5812f94 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -55,6 +55,7 @@ footer_template = templating.environment.get_template('templates/meeting_footer.
 chrome = panel(title = 'Reminders', key='meetings', footer_template=footer_template)
 templating.environment.filters['humanize'] = lambda d: arrow.get(d).humanize()
 template = templating.environment.get_template('templates/meetings.html')
+position = 'both'
 
 
 @argument(name="calendar",
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index 350291d..cdb8365 100755
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -11,6 +11,7 @@ pagure_url = "https://pagure.io/api/0"
 
 chrome = panel("Newest Open Pull Requests on Pagure")
 template = templating.environment.get_template('templates/pagure_pr.html')
+position = 'right'
 
 
 @argument(name="repo",
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index ab13903..3975253 100755
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -9,6 +9,7 @@ pagure_url = "https://pagure.io/api/0"
 
 chrome = panel("Newest Open Tickets on Pagure")
 template = templating.environment.get_template('templates/pagureissues.html')
+position = 'right'
 
 
 @argument(name="repo",
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 4b17931..d0bfad7 100755
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -8,6 +8,7 @@ from hubs import validators
 
 chrome = panel()
 template = templating.environment.get_template('templates/rules.html')
+position = 'both'
 
 
 @argument(name='link', default=None,
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 3b784e3..319e287 100755
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -8,6 +8,7 @@ import flask
 
 chrome = panel()
 template = templating.environment.get_template('templates/stats.html')
+position = 'right'
 
 
 def data(session, widget):
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 4176c97..55cc6a1 100755
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -7,6 +7,7 @@ import hubs.validators as validators
 
 chrome = panel(title='Sticky Note', klass="card-info")
 template = templating.environment.get_template('templates/sticky.html')
+position = 'both'
 
 
 @argument(name="text", default="Lorem ipsum dolor...",
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 6576516..82fce66 100755
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -16,6 +16,7 @@ import flask
 
 chrome = panel('Hubs', key='associations')
 template = templating.environment.get_template('templates/subscriptions.html')
+position = 'right'
 
 
 @argument(name="username",
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 6f0e678..8538999 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -12,6 +12,7 @@ from hubs.widgets.chrome import panel
 chrome = panel('Pending ACL Requests', key='pending_acls')
 # TODO -- add approve/deny buttons or just link through to pkgdb
 template = templating.environment.get_template('templates/workflow/pendingacls.html')
+position = 'right'
 
 
 @argument(name="username",
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 668fcc7..675d793 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -12,6 +12,7 @@ chrome = panel('Updates Ready for Stable', key='updates')
 # TODO -- add approve/deny buttons or just link through to pkgdb
 template = templating.environment.get_template(
     'templates/workflow/updates2stable.html')
+position = 'right'
 
 # TODO - the bodhi api exposes a new flag we can use instead of scraping comments...
 giveaway = 'can be pushed to stable now'

From c16ea2ae9932dc25a5ca73eb7503d577abe1c8d1 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 26 2016 13:47:08 +0000
Subject: [PATCH 455/1001] Code style fixes


---

diff --git a/hubs/utils.py b/hubs/utils.py
index 6eb43b7..ed00d80 100755
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -11,8 +11,10 @@ log = logging.getLogger(__name__)
 
 
 def markup(text):
-    return markdown.markdown(text, safe_mode="replace",
-                             html_replacement_text="--RAW HTML NOT ALLOWED--")
+    return markdown.markdown(
+        text,
+        safe_mode="replace",
+        html_replacement_text="--RAW HTML NOT ALLOWED--")
 
 
 def username2avatar(username, s=312):
@@ -29,6 +31,7 @@ def username2avatar(username, s=312):
 def commas(numeric):
     return "{:,}".format(numeric)
 
+
 def github_repos(token, username):
     log.info("Finding github repos for %r" % username)
     tmpl = "https://api.github.com/users/{username}/repos?per_page=100"
diff --git a/hubs/validators.py b/hubs/validators.py
index 9c2c276..f6da8dc 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -6,29 +6,36 @@ import hubs.models
 def required(session, value):
     return bool(value)
 
+
 def text(session, value):
     return kitchen.text.converters.to_unicode(value)
 
+
 def integer(session, value):
     return int(value)
 
+
 def link(session, value):
     # TODO -- verify that this is actually a link
     return value
 
+
 def username(session, value):
     openid = 'http://%s.id.fedoraproject.org/' % value
     return not hubs.models.User.by_openid(session, openid) is None
 
+
 def github_organization(session, value):
     # TODO -- implement this.
     return True
 
+
 def fmn_context(session, value):
     # TODO get this from the fedmsg config.
     return value in [
         'irc', 'email', 'android', 'desktop', 'hubs',
     ]
 
+
 def pagure_repo(session, value):
     return value

From cb02e1433b70143b204a43441bd023a1246a2ecf Mon Sep 17 00:00:00 2001
From: Ryan Lerch <rlerch@redhat.com>
Date: Apr 27 2016 11:06:21 +0000
Subject: [PATCH 456/1001] sprited the badges


ultimately we want to host the sprites on badges, but keeping
here for now.

---

diff --git a/hubs/static/badges/b.css b/hubs/static/badges/b.css
new file mode 100644
index 0000000..ed9be96
--- /dev/null
+++ b/hubs/static/badges/b.css
@@ -0,0 +1,2581 @@
+/* glue: 0.11.1 hash: 39ffd1cfd5 */
+        .f-b-zomg-tagger-tagger-vii,
+.f-b-zomg-package-tagger-package-tagger-vii,
+.f-b-your-call-may-be-monitored-for-quality-assurance,
+.f-b-you-can-pry-it-from-my-cold-undead-hands,
+.f-b-you-can-pry-it-from-my-cold-dead-hands,
+.f-b-you-can-call-me-wikipedia-brown-ask-fedora-v,
+.f-b-you-can-call-me-patches-scm-iv,
+.f-b-you-can-call-me-patches-scm-iii,
+.f-b-you-can-call-me-patches-scm-ii,
+.f-b-you-can-call-me-patches-scm-i,
+.f-b-xfce-sig,
+.f-b-working-a-beat-beat-writer-iv,
+.f-b-working-a-beat-beat-writer-iii,
+.f-b-working-a-beat-beat-writer-ii,
+.f-b-working-a-beat-beat-writer-i,
+.f-b-wordstorm-wordsmith-v,
+.f-b-white-rabbit,
+.f-b-white-hat,
+.f-b-what-goes-up-koji-failure-iv,
+.f-b-what-goes-up-koji-failure-iii,
+.f-b-what-goes-up-koji-failure-ii,
+.f-b-what-goes-up-koji-failure-i,
+.f-b-what-goes-around-comes-around-karma-iv,
+.f-b-what-goes-around-comes-around-karma-iii,
+.f-b-what-goes-around-comes-around-karma-ii,
+.f-b-what-goes-around-comes-around-karma-i,
+.f-b-websitesnext,
+.f-b-web-warrior,
+.f-b-we-can-do-it,
+.f-b-vitruvian-badger-badge-artist-v,
+.f-b-videographer,
+.f-b-vacation,
+.f-b-united-packages-of-fedora,
+.f-b-unicorn-poop-cookie-vi,
+.f-b-trust-me-i-know-what-i-am-doing,
+.f-b-town-hall-moderator,
+.f-b-tournant-cookbook-ii,
+.f-b-top-500,
+.f-b-top-25,
+.f-b-top-100,
+.f-b-top-10,
+.f-b-the-write-stuff,
+.f-b-the-tower-of-babel-koji-success-vii,
+.f-b-the-panda-is-in,
+.f-b-the-last-argument-of-kings,
+.f-b-the-cat-came-back,
+.f-b-the-bull-transcended-tester-vii,
+.f-b-the-blessing-of-the-fpl,
+.f-b-telegraphist-upstream-release-monitoring-i,
+.f-b-tectonic-updates-stable-v,
+.f-b-tanked,
+.f-b-taming-the-bull-tester-v,
+.f-b-taming-the-beasts,
+.f-b-take-this-and-call-me-in-the-morning,
+.f-b-tagger-tagger-ii,
+.f-b-tadpole,
+.f-b-tadpole-with-legs,
+.f-b-summer-coder,
+.f-b-stop-that-update,
+.f-b-speak-up,
+.f-b-sistine-badgers-badge-artist-iv,
+.f-b-singapore-fad-2015,
+.f-b-silver,
+.f-b-shellshocked,
+.f-b-sfd-organizer,
+.f-b-sensei,
+.f-b-senior-tagger-tagger-iii,
+.f-b-senior-package-tagger-package-tagger-iii,
+.f-b-senior-editor,
+.f-b-senior-badger-badger-ii,
+.f-b-self-2016,
+.f-b-secretary-general,
+.f-b-science-kernel-tester-iv,
+.f-b-science-kernel-tester-iii,
+.f-b-science-kernel-tester-ii,
+.f-b-science-kernel-tester-i,
+.f-b-saucier-cookbook-iv,
+.f-b-rock-the-web,
+.f-b-riding-the-bull-home-tester-vi,
+.f-b-riddle-me-this,
+.f-b-return-to-society-tester-x,
+.f-b-readiness,
+.f-b-reaching-the-source-tester-ix,
+.f-b-rainbow-cookie-v,
+.f-b-pycon-2014-attendee,
+.f-b-proven-tester,
+.f-b-proven-packager,
+.f-b-prolific,
+.f-b-portrait-of-badger-design-team-iv,
+.f-b-pop-badger-design-team-iii,
+.f-b-pizzelle-cookie-iv,
+.f-b-pixel-ninja,
+.f-b-phoenix-down,
+.f-b-persistence-of-badger-design-team-v,
+.f-b-perceiving-the-bull-tester-iii,
+.f-b-patches-scm-v,
+.f-b-party-pirate,
+.f-b-partners-in-crime,
+.f-b-parselmouth,
+.f-b-paranoid-panda,
+.f-b-packager-sponsor,
+.f-b-package-tagger-package-tagger-ii,
+.f-b-override-you-say,
+.f-b-oscon-2015-attendee,
+.f-b-oscal-2016-attendee,
+.f-b-origin,
+.f-b-old-yeller,
+.f-b-nuancier,
+.f-b-nuancier-f24,
+.f-b-nuancier-f23,
+.f-b-nuancier-f22,
+.f-b-nuancier-21,
+.f-b-novice-wordsmith-i,
+.f-b-nom-nom-nom,
+.f-b-no-longer-a-ronin,
+.f-b-mugshot,
+.f-b-missed-the-train,
+.f-b-mirror-mirror-on-the-wall,
+.f-b-mic-check-updates-testing-v,
+.f-b-master-wordsmith-iv,
+.f-b-master-tagger-tagger-iv,
+.f-b-master-package-tagger-package-tagger-iv,
+.f-b-master-editor,
+.f-b-master-badger-badger-iii,
+.f-b-master-badge-artist-vii,
+.f-b-maestro,
+.f-b-mad-science-kernel-tester-v,
+.f-b-macklemore-tagger-v,
+.f-b-macaron-cookie-i,
+.f-b-m-maybe-design-design-team-ii,
+.f-b-like-a-rock-updates-stable-iv,
+.f-b-like-a-rock-updates-stable-iii,
+.f-b-like-a-rock-updates-stable-ii,
+.f-b-like-a-rock-updates-stable-i,
+.f-b-lets-have-a-party-fedora-23,
+.f-b-lets-have-a-party-fedora-21,
+.f-b-lets-have-a-party-fedora-20,
+.f-b-lets-do-lunch,
+.f-b-let-me-introduce-myself,
+.f-b-khmer-translation-hero,
+.f-b-keepin-fedora-beautiful-f24,
+.f-b-keepin-fedora-beautiful-f23,
+.f-b-keepin-fedora-beautiful-f22,
+.f-b-keepin-fedora-beautiful-f21,
+.f-b-keepin-fedora-beautiful-f20,
+.f-b-keepin-fedora-beautiful-f19,
+.f-b-kde-sig,
+.f-b-junior-tagger-tagger-i,
+.f-b-junior-package-tagger-package-tagger-i,
+.f-b-junior-editor,
+.f-b-junior-badger-badger-i,
+.f-b-journeyman-wordsmith-iii,
+.f-b-its-over-9000-koji-success-vi,
+.f-b-it-still-works,
+.f-b-is-this-thing-on-updates-testing-iv,
+.f-b-is-this-thing-on-updates-testing-iii,
+.f-b-is-this-thing-on-updates-testing-ii,
+.f-b-is-this-thing-on-updates-testing-i,
+.f-b-involvement,
+.f-b-internationalization-team-member,
+.f-b-inside-job,
+.f-b-in-search-of-the-bull-tester-i,
+.f-b-if-you-build-it-koji-success-iv,
+.f-b-if-you-build-it-koji-success-iii,
+.f-b-if-you-build-it-koji-success-ii,
+.f-b-if-you-build-it-koji-success-i,
+.f-b-i18n-test-day-participant,
+.f-b-horcrux,
+.f-b-hindenburg-koji-failure-v,
+.f-b-helping-hand,
+.f-b-heartbleed-buster,
+.f-b-grillardin-cookbook-iii,
+.f-b-grandmaster-package-tagger-package-tagger-v,
+.f-b-grandmaster-editor,
+.f-b-gold,
+.f-b-fudcon-pune-2015-volunteer,
+.f-b-fudcon-pune-2015-speaker,
+.f-b-fudcon-pune-2015-attendee,
+.f-b-fudcon-managua,
+.f-b-fudcon-cusco,
+.f-b-fudcon-cordoba-2015-volunteer,
+.f-b-fudcon-cordoba-2015-speaker,
+.f-b-fudcon-cordoba-2015-attendee,
+.f-b-fudcon-beijing,
+.f-b-froscon-2015-attendee,
+.f-b-froscon-2014-attendee,
+.f-b-froglet,
+.f-b-free-the-fedora,
+.f-b-free-the-fedora-v,
+.f-b-free-the-fedora-iv,
+.f-b-free-the-fedora-iii,
+.f-b-free-the-fedora-ii,
+.f-b-four-badgers-design-team-i,
+.f-b-fosscomm-2014-attendee,
+.f-b-fossasia-2014-speaker,
+.f-b-fossasia-2014-attendee,
+.f-b-fosdem-2016-attendee,
+.f-b-fosdem-2015-attendee,
+.f-b-fosdem-2014-attendee,
+.f-b-flock-paparazzi,
+.f-b-flock-2015-speaker,
+.f-b-flock-2015-organizer,
+.f-b-flock-2015-attendee,
+.f-b-flock-2014-speaker,
+.f-b-flock-2014-organizer,
+.f-b-flock-2014-attendee,
+.f-b-flock-2013-speaker,
+.f-b-flock-2013-organizer,
+.f-b-flock-2013-attendee,
+.f-b-flisol-2015-speaker,
+.f-b-flisol-2015-organizer,
+.f-b-flisol-2015-attendee,
+.f-b-flisol-2014-organizer,
+.f-b-flisol-2014-attendee,
+.f-b-fel-member,
+.f-b-fedora-treasurer,
+.f-b-fedora-scholar,
+.f-b-fedora-ni-author,
+.f-b-fedora-legal-badge-of-doom,
+.f-b-fedora-it-author,
+.f-b-fedora-docs-fad-2014,
+.f-b-fedora-cz-author,
+.f-b-fedora-at-rh-summit-2015,
+.f-b-fedora-25-change-accepted,
+.f-b-fedora-24-translation-sprint,
+.f-b-fedora-24-change-accepted,
+.f-b-fedora-23-change-accepted,
+.f-b-fedora-22-change-accepted,
+.f-b-fedora-21-change-accepted,
+.f-b-fedora-20-change-accepted,
+.f-b-famsco-member,
+.f-b-fad-rheinfelden-2013-attendee,
+.f-b-fad-phnom-penh-2014-attendee,
+.f-b-fad-managua-2013,
+.f-b-extra--extra,
+.f-b-embryo,
+.f-b-egg,
+.f-b-dont-call-it-a-comeback,
+.f-b-domo-arigato,
+.f-b-docs-fad-2016,
+.f-b-discovery-of-the-footprints-tester-ii,
+.f-b-devendorizor,
+.f-b-devconf-attendee,
+.f-b-devconf-2016-speaker,
+.f-b-devconf-2016-attendee,
+.f-b-devconf-2015-speaker,
+.f-b-devconf-2015-attendee,
+.f-b-devconf-2014-speaker,
+.f-b-design-ninja,
+.f-b-delivery,
+.f-b-def-keepin-fedora-beautiful-f24,
+.f-b-def-keepin-fedora-beautiful-f23,
+.f-b-def-keepin-fedora-beautiful-f22,
+.f-b-def-keepin-fedora-beautiful-f21,
+.f-b-def-keepin-fedora-beautiful-f20,
+.f-b-def-keepin-fedora-beautiful-f19,
+.f-b-dancing-with-toshio,
+.f-b-curious-penguin-ask-fedora-iv,
+.f-b-curious-penguin-ask-fedora-iii,
+.f-b-curious-penguin-ask-fedora-ii,
+.f-b-curious-penguin-ask-fedora-i,
+.f-b-crypto-panda,
+.f-b-crypto-badger,
+.f-b-creation-of-badger-badge-artist-vi,
+.f-b-corporate-shill,
+.f-b-corporate-overlord,
+.f-b-corporate-drone,
+.f-b-consolation-prize,
+.f-b-common-bugs-contributor,
+.f-b-commis-cookbook-i,
+.f-b-clickbait-fedora-magazine-iii,
+.f-b-clickbait-fedora-magazine-ii,
+.f-b-clickbait-fedora-magazine-i,
+.f-b-civic-duty,
+.f-b-chocolate-chip-cookie-ii,
+.f-b-chief-tagger-tagger-vi,
+.f-b-chief-package-tagger-package-tagger-vi,
+.f-b-chief-editor,
+.f-b-chemnitzer-linux-tage-2016,
+.f-b-catching-the-bull-tester-iv,
+.f-b-building-the-outer-ring-copr-build-vii,
+.f-b-building-the-outer-ring-copr-build-vi,
+.f-b-building-the-outer-ring-copr-build-v,
+.f-b-building-the-outer-ring-copr-build-iv,
+.f-b-building-the-outer-ring-copr-build-iii,
+.f-b-building-the-outer-ring-copr-build-ii,
+.f-b-building-the-outer-ring-copr-build-i,
+.f-b-bronze,
+.f-b-both-bull-and-self-transcended-tester-viii,
+.f-b-bona-fide,
+.f-b-bob-loblaw-planet-v,
+.f-b-bloggin-it-planet-iv,
+.f-b-bloggin-it-planet-iii,
+.f-b-bloggin-it-planet-ii,
+.f-b-bloggin-it-planet-i,
+.f-b-blog-lobber-planet-vi,
+.f-b-blag-dragster-planet-vii,
+.f-b-black-and-white-cookie-iii,
+.f-b-bitcamp-2016,
+.f-b-birth-of-badger-badge-artist-iii,
+.f-b-binary-star,
+.f-b-badger-of-urbino-badge-artist-ii,
+.f-b-badge-off,
+.f-b-badge-muse-badges-released-v,
+.f-b-badge-muse-badges-released-iv,
+.f-b-badge-muse-badges-released-iii,
+.f-b-badge-muse-badges-released-ii,
+.f-b-badge-muse-badges-released-i,
+.f-b-badge-muse-badge-ideas-i,
+.f-b-badge-junkie-badger-iv,
+.f-b-baby-badger,
+.f-b-associate-editor,
+.f-b-associate-badger-badger-15,
+.f-b-apprentice-wordsmith-ii,
+.f-b-apprentice-badge-artist-i,
+.f-b-appdata-tributary,
+.f-b-apex,
+.f-b-ambassadors-sponsor,
+.f-b-ambassador,
+.f-b-all-your--are-belong-to-us-koji-success-v,
+.f-b-adult-frog {
+            background-image: url('b.png');
+            background-repeat: no-repeat;
+            display: inline-block;
+        }
+        
+        .f-b-zomg-tagger-tagger-vii {
+            background-position: 0 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-zomg-package-tagger-package-tagger-vii {
+            background-position: -60px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-your-call-may-be-monitored-for-quality-assurance {
+            background-position: 0 -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-you-can-pry-it-from-my-cold-undead-hands {
+            background-position: -60px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-you-can-pry-it-from-my-cold-dead-hands {
+            background-position: -120px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-you-can-call-me-wikipedia-brown-ask-fedora-v {
+            background-position: -120px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-you-can-call-me-patches-scm-iv {
+            background-position: 0 -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-you-can-call-me-patches-scm-iii {
+            background-position: -60px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-you-can-call-me-patches-scm-ii {
+            background-position: -120px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-you-can-call-me-patches-scm-i {
+            background-position: -180px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-xfce-sig {
+            background-position: -180px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-working-a-beat-beat-writer-iv {
+            background-position: -180px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-working-a-beat-beat-writer-iii {
+            background-position: 0 -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-working-a-beat-beat-writer-ii {
+            background-position: -60px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-working-a-beat-beat-writer-i {
+            background-position: -120px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-wordstorm-wordsmith-v {
+            background-position: -180px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-white-rabbit {
+            background-position: -240px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-white-hat {
+            background-position: -240px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-what-goes-up-koji-failure-iv {
+            background-position: -240px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-what-goes-up-koji-failure-iii {
+            background-position: -240px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-what-goes-up-koji-failure-ii {
+            background-position: 0 -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-what-goes-up-koji-failure-i {
+            background-position: -60px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-what-goes-around-comes-around-karma-iv {
+            background-position: -120px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-what-goes-around-comes-around-karma-iii {
+            background-position: -180px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-what-goes-around-comes-around-karma-ii {
+            background-position: -240px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-what-goes-around-comes-around-karma-i {
+            background-position: -300px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-websitesnext {
+            background-position: -300px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-web-warrior {
+            background-position: -300px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-we-can-do-it {
+            background-position: -300px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-vitruvian-badger-badge-artist-v {
+            background-position: -300px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-videographer {
+            background-position: 0 -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-vacation {
+            background-position: -60px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-united-packages-of-fedora {
+            background-position: -120px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-unicorn-poop-cookie-vi {
+            background-position: -180px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-trust-me-i-know-what-i-am-doing {
+            background-position: -240px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-town-hall-moderator {
+            background-position: -300px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-tournant-cookbook-ii {
+            background-position: -360px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-top-500 {
+            background-position: -360px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-top-25 {
+            background-position: -360px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-top-100 {
+            background-position: -360px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-top-10 {
+            background-position: -360px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-the-write-stuff {
+            background-position: -360px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-the-tower-of-babel-koji-success-vii {
+            background-position: 0 -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-the-panda-is-in {
+            background-position: -60px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-the-last-argument-of-kings {
+            background-position: -120px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-the-cat-came-back {
+            background-position: -180px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-the-bull-transcended-tester-vii {
+            background-position: -240px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-the-blessing-of-the-fpl {
+            background-position: -300px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-telegraphist-upstream-release-monitoring-i {
+            background-position: -360px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-tectonic-updates-stable-v {
+            background-position: -420px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-tanked {
+            background-position: -420px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-taming-the-bull-tester-v {
+            background-position: -420px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-taming-the-beasts {
+            background-position: -420px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-take-this-and-call-me-in-the-morning {
+            background-position: -420px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-tagger-tagger-ii {
+            background-position: -420px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-tadpole {
+            background-position: -420px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-tadpole-with-legs {
+            background-position: 0 -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-summer-coder {
+            background-position: -60px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-stop-that-update {
+            background-position: -120px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-speak-up {
+            background-position: -180px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-sistine-badgers-badge-artist-iv {
+            background-position: -240px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-singapore-fad-2015 {
+            background-position: -300px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-silver {
+            background-position: -360px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-shellshocked {
+            background-position: -420px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-sfd-organizer {
+            background-position: -480px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-sensei {
+            background-position: -480px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-senior-tagger-tagger-iii {
+            background-position: -480px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-senior-package-tagger-package-tagger-iii {
+            background-position: -480px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-senior-editor {
+            background-position: -480px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-senior-badger-badger-ii {
+            background-position: -480px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-self-2016 {
+            background-position: -480px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-secretary-general {
+            background-position: -480px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-science-kernel-tester-iv {
+            background-position: 0 -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-science-kernel-tester-iii {
+            background-position: -60px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-science-kernel-tester-ii {
+            background-position: -120px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-science-kernel-tester-i {
+            background-position: -180px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-saucier-cookbook-iv {
+            background-position: -240px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-rock-the-web {
+            background-position: -300px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-riding-the-bull-home-tester-vi {
+            background-position: -360px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-riddle-me-this {
+            background-position: -420px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-return-to-society-tester-x {
+            background-position: -480px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-readiness {
+            background-position: -540px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-reaching-the-source-tester-ix {
+            background-position: -540px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-rainbow-cookie-v {
+            background-position: -540px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-pycon-2014-attendee {
+            background-position: -540px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-proven-tester {
+            background-position: -540px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-proven-packager {
+            background-position: -540px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-prolific {
+            background-position: -540px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-portrait-of-badger-design-team-iv {
+            background-position: -540px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-pop-badger-design-team-iii {
+            background-position: -540px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-pizzelle-cookie-iv {
+            background-position: 0 -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-pixel-ninja {
+            background-position: -60px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-phoenix-down {
+            background-position: -120px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-persistence-of-badger-design-team-v {
+            background-position: -180px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-perceiving-the-bull-tester-iii {
+            background-position: -240px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-patches-scm-v {
+            background-position: -300px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-party-pirate {
+            background-position: -360px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-partners-in-crime {
+            background-position: -420px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-parselmouth {
+            background-position: -480px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-paranoid-panda {
+            background-position: -540px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-packager-sponsor {
+            background-position: -600px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-package-tagger-package-tagger-ii {
+            background-position: -600px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-override-you-say {
+            background-position: -600px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-oscon-2015-attendee {
+            background-position: -600px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-oscal-2016-attendee {
+            background-position: -600px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-origin {
+            background-position: -600px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-old-yeller {
+            background-position: -600px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-nuancier {
+            background-position: -600px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-nuancier-f24 {
+            background-position: -600px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-nuancier-f23 {
+            background-position: -600px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-nuancier-f22 {
+            background-position: 0 -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-nuancier-21 {
+            background-position: -60px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-novice-wordsmith-i {
+            background-position: -120px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-nom-nom-nom {
+            background-position: -180px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-no-longer-a-ronin {
+            background-position: -240px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-mugshot {
+            background-position: -300px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-missed-the-train {
+            background-position: -360px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-mirror-mirror-on-the-wall {
+            background-position: -420px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-mic-check-updates-testing-v {
+            background-position: -480px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-master-wordsmith-iv {
+            background-position: -540px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-master-tagger-tagger-iv {
+            background-position: -600px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-master-package-tagger-package-tagger-iv {
+            background-position: -660px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-master-editor {
+            background-position: -660px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-master-badger-badger-iii {
+            background-position: -660px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-master-badge-artist-vii {
+            background-position: -660px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-maestro {
+            background-position: -660px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-mad-science-kernel-tester-v {
+            background-position: -660px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-macklemore-tagger-v {
+            background-position: -660px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-macaron-cookie-i {
+            background-position: -660px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-m-maybe-design-design-team-ii {
+            background-position: -660px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-like-a-rock-updates-stable-iv {
+            background-position: -660px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-like-a-rock-updates-stable-iii {
+            background-position: -660px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-like-a-rock-updates-stable-ii {
+            background-position: 0 -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-like-a-rock-updates-stable-i {
+            background-position: -60px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-lets-have-a-party-fedora-23 {
+            background-position: -120px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-lets-have-a-party-fedora-21 {
+            background-position: -180px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-lets-have-a-party-fedora-20 {
+            background-position: -240px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-lets-do-lunch {
+            background-position: -300px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-let-me-introduce-myself {
+            background-position: -360px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-khmer-translation-hero {
+            background-position: -420px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-keepin-fedora-beautiful-f24 {
+            background-position: -480px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-keepin-fedora-beautiful-f23 {
+            background-position: -540px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-keepin-fedora-beautiful-f22 {
+            background-position: -600px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-keepin-fedora-beautiful-f21 {
+            background-position: -660px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-keepin-fedora-beautiful-f20 {
+            background-position: -720px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-keepin-fedora-beautiful-f19 {
+            background-position: -720px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-kde-sig {
+            background-position: -720px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-junior-tagger-tagger-i {
+            background-position: -720px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-junior-package-tagger-package-tagger-i {
+            background-position: -720px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-junior-editor {
+            background-position: -720px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-junior-badger-badger-i {
+            background-position: -720px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-journeyman-wordsmith-iii {
+            background-position: -720px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-its-over-9000-koji-success-vi {
+            background-position: -720px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-it-still-works {
+            background-position: -720px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-is-this-thing-on-updates-testing-iv {
+            background-position: -720px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-is-this-thing-on-updates-testing-iii {
+            background-position: -720px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-is-this-thing-on-updates-testing-ii {
+            background-position: 0 -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-is-this-thing-on-updates-testing-i {
+            background-position: -60px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-involvement {
+            background-position: -120px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-internationalization-team-member {
+            background-position: -180px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-inside-job {
+            background-position: -240px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-in-search-of-the-bull-tester-i {
+            background-position: -300px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-if-you-build-it-koji-success-iv {
+            background-position: -360px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-if-you-build-it-koji-success-iii {
+            background-position: -420px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-if-you-build-it-koji-success-ii {
+            background-position: -480px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-if-you-build-it-koji-success-i {
+            background-position: -540px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-i18n-test-day-participant {
+            background-position: -600px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-horcrux {
+            background-position: -660px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-hindenburg-koji-failure-v {
+            background-position: -720px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-helping-hand {
+            background-position: -780px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-heartbleed-buster {
+            background-position: -780px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-grillardin-cookbook-iii {
+            background-position: -780px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-grandmaster-package-tagger-package-tagger-v {
+            background-position: -780px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-grandmaster-editor {
+            background-position: -780px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-gold {
+            background-position: -780px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fudcon-pune-2015-volunteer {
+            background-position: -780px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fudcon-pune-2015-speaker {
+            background-position: -780px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fudcon-pune-2015-attendee {
+            background-position: -780px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fudcon-managua {
+            background-position: -780px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fudcon-cusco {
+            background-position: -780px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fudcon-cordoba-2015-volunteer {
+            background-position: -780px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fudcon-cordoba-2015-speaker {
+            background-position: -780px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fudcon-cordoba-2015-attendee {
+            background-position: 0 -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fudcon-beijing {
+            background-position: -60px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-froscon-2015-attendee {
+            background-position: -120px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-froscon-2014-attendee {
+            background-position: -180px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-froglet {
+            background-position: -240px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-free-the-fedora {
+            background-position: -300px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-free-the-fedora-v {
+            background-position: -360px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-free-the-fedora-iv {
+            background-position: -420px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-free-the-fedora-iii {
+            background-position: -480px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-free-the-fedora-ii {
+            background-position: -540px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-four-badgers-design-team-i {
+            background-position: -600px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fosscomm-2014-attendee {
+            background-position: -660px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fossasia-2014-speaker {
+            background-position: -720px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fossasia-2014-attendee {
+            background-position: -780px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fosdem-2016-attendee {
+            background-position: -840px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fosdem-2015-attendee {
+            background-position: -840px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fosdem-2014-attendee {
+            background-position: -840px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-paparazzi {
+            background-position: -840px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-2015-speaker {
+            background-position: -840px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-2015-organizer {
+            background-position: -840px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-2015-attendee {
+            background-position: -840px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-2014-speaker {
+            background-position: -840px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-2014-organizer {
+            background-position: -840px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-2014-attendee {
+            background-position: -840px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-2013-speaker {
+            background-position: -840px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-2013-organizer {
+            background-position: -840px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flock-2013-attendee {
+            background-position: -840px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flisol-2015-speaker {
+            background-position: -840px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flisol-2015-organizer {
+            background-position: 0 -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flisol-2015-attendee {
+            background-position: -60px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flisol-2014-organizer {
+            background-position: -120px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-flisol-2014-attendee {
+            background-position: -180px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fel-member {
+            background-position: -240px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-treasurer {
+            background-position: -300px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-scholar {
+            background-position: -360px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-ni-author {
+            background-position: -420px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-legal-badge-of-doom {
+            background-position: -480px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-it-author {
+            background-position: -540px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-docs-fad-2014 {
+            background-position: -600px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-cz-author {
+            background-position: -660px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-at-rh-summit-2015 {
+            background-position: -720px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-25-change-accepted {
+            background-position: -780px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-24-translation-sprint {
+            background-position: -840px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-24-change-accepted {
+            background-position: -900px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-23-change-accepted {
+            background-position: -900px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-22-change-accepted {
+            background-position: -900px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-21-change-accepted {
+            background-position: -900px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fedora-20-change-accepted {
+            background-position: -900px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-famsco-member {
+            background-position: -900px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fad-rheinfelden-2013-attendee {
+            background-position: -900px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fad-phnom-penh-2014-attendee {
+            background-position: -900px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-fad-managua-2013 {
+            background-position: -900px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-extra--extra {
+            background-position: -900px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-embryo {
+            background-position: -900px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-egg {
+            background-position: -900px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-dont-call-it-a-comeback {
+            background-position: -900px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-domo-arigato {
+            background-position: -900px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-docs-fad-2016 {
+            background-position: -900px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-discovery-of-the-footprints-tester-ii {
+            background-position: 0 -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-devendorizor {
+            background-position: -60px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-devconf-attendee {
+            background-position: -120px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-devconf-2016-speaker {
+            background-position: -180px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-devconf-2016-attendee {
+            background-position: -240px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-devconf-2015-speaker {
+            background-position: -300px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-devconf-2015-attendee {
+            background-position: -360px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-devconf-2014-speaker {
+            background-position: -420px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-design-ninja {
+            background-position: -480px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-delivery {
+            background-position: -540px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-def-keepin-fedora-beautiful-f24 {
+            background-position: -600px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-def-keepin-fedora-beautiful-f23 {
+            background-position: -660px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-def-keepin-fedora-beautiful-f22 {
+            background-position: -720px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-def-keepin-fedora-beautiful-f21 {
+            background-position: -780px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-def-keepin-fedora-beautiful-f20 {
+            background-position: -840px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-def-keepin-fedora-beautiful-f19 {
+            background-position: -900px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-dancing-with-toshio {
+            background-position: -960px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-curious-penguin-ask-fedora-iv {
+            background-position: -960px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-curious-penguin-ask-fedora-iii {
+            background-position: -960px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-curious-penguin-ask-fedora-ii {
+            background-position: -960px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-curious-penguin-ask-fedora-i {
+            background-position: -960px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-crypto-panda {
+            background-position: -960px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-crypto-badger {
+            background-position: -960px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-creation-of-badger-badge-artist-vi {
+            background-position: -960px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-corporate-shill {
+            background-position: -960px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-corporate-overlord {
+            background-position: -960px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-corporate-drone {
+            background-position: -960px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-consolation-prize {
+            background-position: -960px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-common-bugs-contributor {
+            background-position: -960px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-commis-cookbook-i {
+            background-position: -960px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-clickbait-fedora-magazine-iii {
+            background-position: -960px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-clickbait-fedora-magazine-ii {
+            background-position: -960px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-clickbait-fedora-magazine-i {
+            background-position: 0 -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-civic-duty {
+            background-position: -60px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-chocolate-chip-cookie-ii {
+            background-position: -120px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-chief-tagger-tagger-vi {
+            background-position: -180px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-chief-package-tagger-package-tagger-vi {
+            background-position: -240px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-chief-editor {
+            background-position: -300px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-chemnitzer-linux-tage-2016 {
+            background-position: -360px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-catching-the-bull-tester-iv {
+            background-position: -420px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-building-the-outer-ring-copr-build-vii {
+            background-position: -480px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-building-the-outer-ring-copr-build-vi {
+            background-position: -540px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-building-the-outer-ring-copr-build-v {
+            background-position: -600px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-building-the-outer-ring-copr-build-iv {
+            background-position: -660px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-building-the-outer-ring-copr-build-iii {
+            background-position: -720px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-building-the-outer-ring-copr-build-ii {
+            background-position: -780px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-building-the-outer-ring-copr-build-i {
+            background-position: -840px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-bronze {
+            background-position: -900px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-both-bull-and-self-transcended-tester-viii {
+            background-position: -960px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-bona-fide {
+            background-position: -1020px 0;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-bob-loblaw-planet-v {
+            background-position: -1020px -60px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-bloggin-it-planet-iv {
+            background-position: -1020px -120px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-bloggin-it-planet-iii {
+            background-position: -1020px -180px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-bloggin-it-planet-ii {
+            background-position: -1020px -240px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-bloggin-it-planet-i {
+            background-position: -1020px -300px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-blog-lobber-planet-vi {
+            background-position: -1020px -360px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-blag-dragster-planet-vii {
+            background-position: -1020px -420px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-black-and-white-cookie-iii {
+            background-position: -1020px -480px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-bitcamp-2016 {
+            background-position: -1020px -540px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-birth-of-badger-badge-artist-iii {
+            background-position: -1020px -600px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-binary-star {
+            background-position: -1020px -660px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-badger-of-urbino-badge-artist-ii {
+            background-position: -1020px -720px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-badge-off {
+            background-position: -1020px -780px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-badge-muse-badges-released-v {
+            background-position: -1020px -840px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-badge-muse-badges-released-iv {
+            background-position: -1020px -900px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-badge-muse-badges-released-iii {
+            background-position: -1020px -960px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-badge-muse-badges-released-ii {
+            background-position: 0 -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-badge-muse-badges-released-i {
+            background-position: -60px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-badge-muse-badge-ideas-i {
+            background-position: -120px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-badge-junkie-badger-iv {
+            background-position: -180px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-baby-badger {
+            background-position: -240px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-associate-editor {
+            background-position: -300px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-associate-badger-badger-15 {
+            background-position: -360px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-apprentice-wordsmith-ii {
+            background-position: -420px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-apprentice-badge-artist-i {
+            background-position: -480px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-appdata-tributary {
+            background-position: -540px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-apex {
+            background-position: -600px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-ambassadors-sponsor {
+            background-position: -660px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-ambassador {
+            background-position: -720px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-all-your--are-belong-to-us-koji-success-v {
+            background-position: -780px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        .f-b-adult-frog {
+            background-position: -840px -1020px;
+            width: 60px;
+            height: 60px;
+        }
+
+        @media screen and (-webkit-min-device-pixel-ratio: 1.0), screen and (min--moz-device-pixel-ratio: 1.0), screen and (-o-min-device-pixel-ratio: 100/100), screen and (min-device-pixel-ratio: 1.0), screen and (min-resolution: 1.0dppx) {
+            .f-b-zomg-tagger-tagger-vii,
+    .f-b-zomg-package-tagger-package-tagger-vii,
+    .f-b-your-call-may-be-monitored-for-quality-assurance,
+    .f-b-you-can-pry-it-from-my-cold-undead-hands,
+    .f-b-you-can-pry-it-from-my-cold-dead-hands,
+    .f-b-you-can-call-me-wikipedia-brown-ask-fedora-v,
+    .f-b-you-can-call-me-patches-scm-iv,
+    .f-b-you-can-call-me-patches-scm-iii,
+    .f-b-you-can-call-me-patches-scm-ii,
+    .f-b-you-can-call-me-patches-scm-i,
+    .f-b-xfce-sig,
+    .f-b-working-a-beat-beat-writer-iv,
+    .f-b-working-a-beat-beat-writer-iii,
+    .f-b-working-a-beat-beat-writer-ii,
+    .f-b-working-a-beat-beat-writer-i,
+    .f-b-wordstorm-wordsmith-v,
+    .f-b-white-rabbit,
+    .f-b-white-hat,
+    .f-b-what-goes-up-koji-failure-iv,
+    .f-b-what-goes-up-koji-failure-iii,
+    .f-b-what-goes-up-koji-failure-ii,
+    .f-b-what-goes-up-koji-failure-i,
+    .f-b-what-goes-around-comes-around-karma-iv,
+    .f-b-what-goes-around-comes-around-karma-iii,
+    .f-b-what-goes-around-comes-around-karma-ii,
+    .f-b-what-goes-around-comes-around-karma-i,
+    .f-b-websitesnext,
+    .f-b-web-warrior,
+    .f-b-we-can-do-it,
+    .f-b-vitruvian-badger-badge-artist-v,
+    .f-b-videographer,
+    .f-b-vacation,
+    .f-b-united-packages-of-fedora,
+    .f-b-unicorn-poop-cookie-vi,
+    .f-b-trust-me-i-know-what-i-am-doing,
+    .f-b-town-hall-moderator,
+    .f-b-tournant-cookbook-ii,
+    .f-b-top-500,
+    .f-b-top-25,
+    .f-b-top-100,
+    .f-b-top-10,
+    .f-b-the-write-stuff,
+    .f-b-the-tower-of-babel-koji-success-vii,
+    .f-b-the-panda-is-in,
+    .f-b-the-last-argument-of-kings,
+    .f-b-the-cat-came-back,
+    .f-b-the-bull-transcended-tester-vii,
+    .f-b-the-blessing-of-the-fpl,
+    .f-b-telegraphist-upstream-release-monitoring-i,
+    .f-b-tectonic-updates-stable-v,
+    .f-b-tanked,
+    .f-b-taming-the-bull-tester-v,
+    .f-b-taming-the-beasts,
+    .f-b-take-this-and-call-me-in-the-morning,
+    .f-b-tagger-tagger-ii,
+    .f-b-tadpole,
+    .f-b-tadpole-with-legs,
+    .f-b-summer-coder,
+    .f-b-stop-that-update,
+    .f-b-speak-up,
+    .f-b-sistine-badgers-badge-artist-iv,
+    .f-b-singapore-fad-2015,
+    .f-b-silver,
+    .f-b-shellshocked,
+    .f-b-sfd-organizer,
+    .f-b-sensei,
+    .f-b-senior-tagger-tagger-iii,
+    .f-b-senior-package-tagger-package-tagger-iii,
+    .f-b-senior-editor,
+    .f-b-senior-badger-badger-ii,
+    .f-b-self-2016,
+    .f-b-secretary-general,
+    .f-b-science-kernel-tester-iv,
+    .f-b-science-kernel-tester-iii,
+    .f-b-science-kernel-tester-ii,
+    .f-b-science-kernel-tester-i,
+    .f-b-saucier-cookbook-iv,
+    .f-b-rock-the-web,
+    .f-b-riding-the-bull-home-tester-vi,
+    .f-b-riddle-me-this,
+    .f-b-return-to-society-tester-x,
+    .f-b-readiness,
+    .f-b-reaching-the-source-tester-ix,
+    .f-b-rainbow-cookie-v,
+    .f-b-pycon-2014-attendee,
+    .f-b-proven-tester,
+    .f-b-proven-packager,
+    .f-b-prolific,
+    .f-b-portrait-of-badger-design-team-iv,
+    .f-b-pop-badger-design-team-iii,
+    .f-b-pizzelle-cookie-iv,
+    .f-b-pixel-ninja,
+    .f-b-phoenix-down,
+    .f-b-persistence-of-badger-design-team-v,
+    .f-b-perceiving-the-bull-tester-iii,
+    .f-b-patches-scm-v,
+    .f-b-party-pirate,
+    .f-b-partners-in-crime,
+    .f-b-parselmouth,
+    .f-b-paranoid-panda,
+    .f-b-packager-sponsor,
+    .f-b-package-tagger-package-tagger-ii,
+    .f-b-override-you-say,
+    .f-b-oscon-2015-attendee,
+    .f-b-oscal-2016-attendee,
+    .f-b-origin,
+    .f-b-old-yeller,
+    .f-b-nuancier,
+    .f-b-nuancier-f24,
+    .f-b-nuancier-f23,
+    .f-b-nuancier-f22,
+    .f-b-nuancier-21,
+    .f-b-novice-wordsmith-i,
+    .f-b-nom-nom-nom,
+    .f-b-no-longer-a-ronin,
+    .f-b-mugshot,
+    .f-b-missed-the-train,
+    .f-b-mirror-mirror-on-the-wall,
+    .f-b-mic-check-updates-testing-v,
+    .f-b-master-wordsmith-iv,
+    .f-b-master-tagger-tagger-iv,
+    .f-b-master-package-tagger-package-tagger-iv,
+    .f-b-master-editor,
+    .f-b-master-badger-badger-iii,
+    .f-b-master-badge-artist-vii,
+    .f-b-maestro,
+    .f-b-mad-science-kernel-tester-v,
+    .f-b-macklemore-tagger-v,
+    .f-b-macaron-cookie-i,
+    .f-b-m-maybe-design-design-team-ii,
+    .f-b-like-a-rock-updates-stable-iv,
+    .f-b-like-a-rock-updates-stable-iii,
+    .f-b-like-a-rock-updates-stable-ii,
+    .f-b-like-a-rock-updates-stable-i,
+    .f-b-lets-have-a-party-fedora-23,
+    .f-b-lets-have-a-party-fedora-21,
+    .f-b-lets-have-a-party-fedora-20,
+    .f-b-lets-do-lunch,
+    .f-b-let-me-introduce-myself,
+    .f-b-khmer-translation-hero,
+    .f-b-keepin-fedora-beautiful-f24,
+    .f-b-keepin-fedora-beautiful-f23,
+    .f-b-keepin-fedora-beautiful-f22,
+    .f-b-keepin-fedora-beautiful-f21,
+    .f-b-keepin-fedora-beautiful-f20,
+    .f-b-keepin-fedora-beautiful-f19,
+    .f-b-kde-sig,
+    .f-b-junior-tagger-tagger-i,
+    .f-b-junior-package-tagger-package-tagger-i,
+    .f-b-junior-editor,
+    .f-b-junior-badger-badger-i,
+    .f-b-journeyman-wordsmith-iii,
+    .f-b-its-over-9000-koji-success-vi,
+    .f-b-it-still-works,
+    .f-b-is-this-thing-on-updates-testing-iv,
+    .f-b-is-this-thing-on-updates-testing-iii,
+    .f-b-is-this-thing-on-updates-testing-ii,
+    .f-b-is-this-thing-on-updates-testing-i,
+    .f-b-involvement,
+    .f-b-internationalization-team-member,
+    .f-b-inside-job,
+    .f-b-in-search-of-the-bull-tester-i,
+    .f-b-if-you-build-it-koji-success-iv,
+    .f-b-if-you-build-it-koji-success-iii,
+    .f-b-if-you-build-it-koji-success-ii,
+    .f-b-if-you-build-it-koji-success-i,
+    .f-b-i18n-test-day-participant,
+    .f-b-horcrux,
+    .f-b-hindenburg-koji-failure-v,
+    .f-b-helping-hand,
+    .f-b-heartbleed-buster,
+    .f-b-grillardin-cookbook-iii,
+    .f-b-grandmaster-package-tagger-package-tagger-v,
+    .f-b-grandmaster-editor,
+    .f-b-gold,
+    .f-b-fudcon-pune-2015-volunteer,
+    .f-b-fudcon-pune-2015-speaker,
+    .f-b-fudcon-pune-2015-attendee,
+    .f-b-fudcon-managua,
+    .f-b-fudcon-cusco,
+    .f-b-fudcon-cordoba-2015-volunteer,
+    .f-b-fudcon-cordoba-2015-speaker,
+    .f-b-fudcon-cordoba-2015-attendee,
+    .f-b-fudcon-beijing,
+    .f-b-froscon-2015-attendee,
+    .f-b-froscon-2014-attendee,
+    .f-b-froglet,
+    .f-b-free-the-fedora,
+    .f-b-free-the-fedora-v,
+    .f-b-free-the-fedora-iv,
+    .f-b-free-the-fedora-iii,
+    .f-b-free-the-fedora-ii,
+    .f-b-four-badgers-design-team-i,
+    .f-b-fosscomm-2014-attendee,
+    .f-b-fossasia-2014-speaker,
+    .f-b-fossasia-2014-attendee,
+    .f-b-fosdem-2016-attendee,
+    .f-b-fosdem-2015-attendee,
+    .f-b-fosdem-2014-attendee,
+    .f-b-flock-paparazzi,
+    .f-b-flock-2015-speaker,
+    .f-b-flock-2015-organizer,
+    .f-b-flock-2015-attendee,
+    .f-b-flock-2014-speaker,
+    .f-b-flock-2014-organizer,
+    .f-b-flock-2014-attendee,
+    .f-b-flock-2013-speaker,
+    .f-b-flock-2013-organizer,
+    .f-b-flock-2013-attendee,
+    .f-b-flisol-2015-speaker,
+    .f-b-flisol-2015-organizer,
+    .f-b-flisol-2015-attendee,
+    .f-b-flisol-2014-organizer,
+    .f-b-flisol-2014-attendee,
+    .f-b-fel-member,
+    .f-b-fedora-treasurer,
+    .f-b-fedora-scholar,
+    .f-b-fedora-ni-author,
+    .f-b-fedora-legal-badge-of-doom,
+    .f-b-fedora-it-author,
+    .f-b-fedora-docs-fad-2014,
+    .f-b-fedora-cz-author,
+    .f-b-fedora-at-rh-summit-2015,
+    .f-b-fedora-25-change-accepted,
+    .f-b-fedora-24-translation-sprint,
+    .f-b-fedora-24-change-accepted,
+    .f-b-fedora-23-change-accepted,
+    .f-b-fedora-22-change-accepted,
+    .f-b-fedora-21-change-accepted,
+    .f-b-fedora-20-change-accepted,
+    .f-b-famsco-member,
+    .f-b-fad-rheinfelden-2013-attendee,
+    .f-b-fad-phnom-penh-2014-attendee,
+    .f-b-fad-managua-2013,
+    .f-b-extra--extra,
+    .f-b-embryo,
+    .f-b-egg,
+    .f-b-dont-call-it-a-comeback,
+    .f-b-domo-arigato,
+    .f-b-docs-fad-2016,
+    .f-b-discovery-of-the-footprints-tester-ii,
+    .f-b-devendorizor,
+    .f-b-devconf-attendee,
+    .f-b-devconf-2016-speaker,
+    .f-b-devconf-2016-attendee,
+    .f-b-devconf-2015-speaker,
+    .f-b-devconf-2015-attendee,
+    .f-b-devconf-2014-speaker,
+    .f-b-design-ninja,
+    .f-b-delivery,
+    .f-b-def-keepin-fedora-beautiful-f24,
+    .f-b-def-keepin-fedora-beautiful-f23,
+    .f-b-def-keepin-fedora-beautiful-f22,
+    .f-b-def-keepin-fedora-beautiful-f21,
+    .f-b-def-keepin-fedora-beautiful-f20,
+    .f-b-def-keepin-fedora-beautiful-f19,
+    .f-b-dancing-with-toshio,
+    .f-b-curious-penguin-ask-fedora-iv,
+    .f-b-curious-penguin-ask-fedora-iii,
+    .f-b-curious-penguin-ask-fedora-ii,
+    .f-b-curious-penguin-ask-fedora-i,
+    .f-b-crypto-panda,
+    .f-b-crypto-badger,
+    .f-b-creation-of-badger-badge-artist-vi,
+    .f-b-corporate-shill,
+    .f-b-corporate-overlord,
+    .f-b-corporate-drone,
+    .f-b-consolation-prize,
+    .f-b-common-bugs-contributor,
+    .f-b-commis-cookbook-i,
+    .f-b-clickbait-fedora-magazine-iii,
+    .f-b-clickbait-fedora-magazine-ii,
+    .f-b-clickbait-fedora-magazine-i,
+    .f-b-civic-duty,
+    .f-b-chocolate-chip-cookie-ii,
+    .f-b-chief-tagger-tagger-vi,
+    .f-b-chief-package-tagger-package-tagger-vi,
+    .f-b-chief-editor,
+    .f-b-chemnitzer-linux-tage-2016,
+    .f-b-catching-the-bull-tester-iv,
+    .f-b-building-the-outer-ring-copr-build-vii,
+    .f-b-building-the-outer-ring-copr-build-vi,
+    .f-b-building-the-outer-ring-copr-build-v,
+    .f-b-building-the-outer-ring-copr-build-iv,
+    .f-b-building-the-outer-ring-copr-build-iii,
+    .f-b-building-the-outer-ring-copr-build-ii,
+    .f-b-building-the-outer-ring-copr-build-i,
+    .f-b-bronze,
+    .f-b-both-bull-and-self-transcended-tester-viii,
+    .f-b-bona-fide,
+    .f-b-bob-loblaw-planet-v,
+    .f-b-bloggin-it-planet-iv,
+    .f-b-bloggin-it-planet-iii,
+    .f-b-bloggin-it-planet-ii,
+    .f-b-bloggin-it-planet-i,
+    .f-b-blog-lobber-planet-vi,
+    .f-b-blag-dragster-planet-vii,
+    .f-b-black-and-white-cookie-iii,
+    .f-b-bitcamp-2016,
+    .f-b-birth-of-badger-badge-artist-iii,
+    .f-b-binary-star,
+    .f-b-badger-of-urbino-badge-artist-ii,
+    .f-b-badge-off,
+    .f-b-badge-muse-badges-released-v,
+    .f-b-badge-muse-badges-released-iv,
+    .f-b-badge-muse-badges-released-iii,
+    .f-b-badge-muse-badges-released-ii,
+    .f-b-badge-muse-badges-released-i,
+    .f-b-badge-muse-badge-ideas-i,
+    .f-b-badge-junkie-badger-iv,
+    .f-b-baby-badger,
+    .f-b-associate-editor,
+    .f-b-associate-badger-badger-15,
+    .f-b-apprentice-wordsmith-ii,
+    .f-b-apprentice-badge-artist-i,
+    .f-b-appdata-tributary,
+    .f-b-apex,
+    .f-b-ambassadors-sponsor,
+    .f-b-ambassador,
+    .f-b-all-your--are-belong-to-us-koji-success-v,
+    .f-b-adult-frog {
+                background-image: url('b.png');
+                -webkit-background-size: 1080px 1080px;
+                -moz-background-size: 1080px 1080px;
+                background-size: 1080px 1080px;
+            }
+        }
diff --git a/hubs/static/badges/b.png b/hubs/static/badges/b.png
new file mode 100644
index 0000000..72dbb01
Binary files /dev/null and b/hubs/static/badges/b.png differ
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index ba26ba7..b2fc833 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -8,6 +8,8 @@
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
   <link href="{{ url_for('static', filename='open_iconic_1.1.0/css/open-iconic.min.css') }}"
         type="text/css" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='badges/b.css') }}"
+        type="text/css" rel="stylesheet" />
 </head>
 <body>
 <div class="masthead">
diff --git a/hubs/widgets/templates/badges.html b/hubs/widgets/templates/badges.html
index 9901f43..926c8d0 100644
--- a/hubs/widgets/templates/badges.html
+++ b/hubs/widgets/templates/badges.html
@@ -1,6 +1,7 @@
 <div class="flex-container">
-{% for badge in assertions[:10] %}
+{% for badge in assertions %}
   <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
-    <img width="60px" src="{{badge['image']}}"/></a>
+    <span class="f-b-{{badge['id']}}"></span>
+  </a>
 {%endfor%}
 </div>

From e0a8b41c23e7fd8621aebb4d4353b9f83e8c30c8 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 28 2016 08:16:34 +0000
Subject: [PATCH 457/1001] Fix the URLs for when editing a widget


---

diff --git a/hubs/app.py b/hubs/app.py
index 3732eea..5f5f3b6 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -211,20 +211,25 @@ def widget_json(hub, idx):
     return response
 
 
-@app.route('/<hub>/<idx>/edit/', methods=['GET'])
-@app.route('/<hub>/<idx>/edit', methods=['GET'])
+@app.route('/<hub>/<idx>/edit/', methods=['GET', 'POST'])
+@app.route('/<hub>/<idx>/edit', methods=['GET', 'POST'])
+def widget_edit(hub, idx):
+    if flask.request.method == 'POST':
+        return widget_edit_post(hub, idx)
+    else:
+        return widget_edit_get(hub, idx)
+
+
 def widget_edit_get(hub, idx):
     widget = get_widget(session, hub, idx)
     return flask.render_template(
         'edit.html',
         hub=hub,
         widget=widget,
-        url_to=flask.url_for('widget_edit_post', hub=hub, idx=idx)
+        url_to=flask.url_for('widget_edit', hub=hub, idx=idx)
     )
 
 
-@app.route('/<hub>/<idx>/edit/', methods=['POST'])
-@app.route('/<hub>/<idx>/edit', methods=['POST'])
 def widget_edit_post(hub, idx):
     widget = get_widget(session, hub, idx)
     error = False
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 49ca5b2..fcce04a 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -49,7 +49,7 @@ def AGPLv3(name):
             result['widget_url'] = flask.url_for(
                 'widget_render', hub=widget.hub.name, idx=widget.idx)
             result['edit_url'] = flask.url_for(
-                'widget_edit_get', hub=widget.hub.name, idx=widget.idx)
+                'widget_edit', hub=widget.hub.name, idx=widget.idx)
             result['widget'] = widget
             return result
 

From f94340ee350277d3439ad8dce2f33013f564814f Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 28 2016 08:16:34 +0000
Subject: [PATCH 458/1001] Fix calls to url_for()


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f4fa36b..c0c93c5 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -91,10 +91,10 @@
           <div class="media-left">
           {% if hub.archived %}
             <img class="media-object square-32"
-              src="{{flask.url_for('static', filename='img/archived.png')}}"/>
+              src="{{ url_for('static', filename='img/archived.png') }}"/>
           {% else %}
             <img class="media-object square-32"
-              src="{{flask.url_for('static', filename='img/cobweb.png')}}"/>
+              src="{{ url_for('static', filename='img/cobweb.png') }}"/>
           {% endif %}
           </div>
           <div class="media-body">

From 6e87bee5fa0298f2b89c7cba2d8809c4f038693f Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 28 2016 08:16:35 +0000
Subject: [PATCH 459/1001] Fix allowing to order widgets on the right column


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index c0c93c5..b142fd6 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -125,7 +125,7 @@
 
       <div id="left_widgets">
         {% for widget in hub.left_widgets %}
-        <div id="widget-{{ widget.idx }}" class="row"></div>
+        <div id="widget-{{ widget.idx }}" class="widget row"></div>
         {% endfor %}
       </div>
     </div>
@@ -175,6 +175,12 @@
 function make_widget_sortable() {
   var byId = function (id) { return document.getElementById(id); }
 
+  Sortable.create(byId('left_widgets'), {
+    animation: 150,
+    draggable: '.widget',
+    handle: '.card',
+  });
+
   Sortable.create(byId('right_widgets'), {
     animation: 150,
     draggable: '.widget',
@@ -184,16 +190,23 @@ function make_widget_sortable() {
 };
 
 $('#save_edits_btn').click(function() {
-  var _indexes = [];
-  var _widgets = [];
+  var _r_indexes = [];
+  var _r_widgets = [];
   $.each($('#right_widgets .widget'), function(i, el) {
-    _indexes.push(i);
-    _widgets.push($(el).attr('id').split('widget-')[1])
+    _r_indexes.push(i);
+    _r_widgets.push($(el).attr('id').split('widget-')[1])
+  });
+
+  $.each($('#left_widgets .widget'), function(i, el) {
+    _l_indexes.push(i);
+    _l_widgets.push($(el).attr('id').split('widget-')[1])
   });
 
   $.post(
     '{{ url_for("hub_edit", name=hub.name) }}',
-    {'indexes': _indexes, 'widgets': _widgets, 'js': true},
+    {'right_indexes': _r_indexes, 'right_widgets': _r_widgets,
+     'left_indexes': _l_indexes, 'left_widgets': _l_widgets,
+     'js': true},
     function(){ window.location = '{{ url_for("hub", name=hub.name) }}' }
   );
 });

From 5095e60f7dd2235db50323a4d6ca12d0113e4740 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 28 2016 08:16:35 +0000
Subject: [PATCH 460/1001] Add the logic add a widget to a hub


---

diff --git a/hubs/app.py b/hubs/app.py
index 5f5f3b6..b5d3453 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -11,6 +11,7 @@ import six
 from flask.ext.openid import OpenID
 
 import hubs.models
+import hubs.widgets
 
 import datanommer.models
 
@@ -131,6 +132,7 @@ def hub_edit_get(name):
     return flask.render_template(
         'hubs.html', hub=hub, session=session, edit=True)
 
+
 def hub_edit_post(name):
     hub = get_hub(session, name)
     is_js = flask.request.form.get('js', False)
@@ -193,6 +195,106 @@ def hub_edit_post(name):
         return flask.redirect(flask.url_for('hub', name=name))
 
 
+@app.route('/<name>/add/', methods=['GET', 'POST'])
+@app.route('/<name>/add', methods=['GET', 'POST'])
+def hub_add_widgets(name):
+    if flask.request.method == 'POST':
+        return hub_add_widget_post(name)
+    else:
+        return hub_add_widget_get(name)
+
+
+@app.route('/<name>/add/<widget_name>/', methods=['GET'])
+@app.route('/<name>/add/<widget_name>', methods=['GET'])
+def hub_add_widget(name, widget_name):
+    hub = get_hub(session, name)
+    side = str(flask.request.args.get('position')).lower()
+    if side not in ['right', 'left']:
+        flask.abort(400, 'Invalid position provided')
+
+    widget = None
+    w_name = None
+    for widgt in hubs.widgets.registry:
+        if hubs.widgets.registry[widgt].position in ['both', side] \
+                and widgt == widget_name:
+            w_name = widgt
+            widget = hubs.widgets.registry[widgt]
+
+    return flask.render_template(
+        'add_widget.html',
+        hub=hub,
+        widget=widget,
+        widget_name=w_name,
+        side=side,
+        url_to=flask.url_for('hub_add_widgets', name=name),
+    )
+
+
+def hub_add_widget_get(name):
+    hub = get_hub(session, name)
+    side = str(flask.request.args.get('position')).lower()
+    if side not in ['right', 'left']:
+        flask.abort(400, 'Invalid position provided')
+
+    widgets = [
+        widget
+        for widget in hubs.widgets.registry
+        if hubs.widgets.registry[widget].position in ['both', side]
+    ]
+    return flask.render_template(
+        'add_widget.html',
+        hub=hub,
+        widgets=widgets,
+        side=side,
+    )
+
+
+def hub_add_widget_post(name):
+    print flask.request.form
+    widget_name = flask.request.form.get('widget_name')
+    position = flask.request.form.get('position', '').lower()
+    if not widget_name:
+        flask.abort(400, 'Invalid request sent')
+    if widget_name not in hubs.widgets.registry:
+        flask.abort(404, 'Unknown widget called')
+
+    hub = get_hub(session, name)
+
+    widget = widget = hubs.models.Widget(
+        plugin=widget_name, index=-1, left=position=='left')
+    error = False
+    config = {}
+    for arg in widget.module.data.widget_arguments:
+        val = flask.request.form.get(arg.name)
+        if not val:
+            flask.flash(
+                'You must provide a value for: %s' % arg.name, 'error')
+            error = True
+            break
+        try:
+            arg.validator(session, val)
+            config[arg.name] = val
+        except Exception as err:
+            flask.flash('Invalid data provided, error: %s' % err, 'error')
+            error = True
+    if not error:
+        widget.hub = hub
+        widget.config = config
+        try:
+            session.add(widget)
+            session.flush()
+            widget.hub.last_edited = datetime.datetime.utcnow()
+            session.commit()
+        except Exception as err:
+            print err
+            flask.flash(
+                'Could not save the configuration to the database '\
+                'if the error persists, please warn an admin',
+                'error')
+
+    return flask.render_template(
+        'hubs.html', hub=hub, session=session, edit=True)
+
 
 @app.route('/<hub>/<idx>/')
 @app.route('/<hub>/<idx>')
diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
new file mode 100644
index 0000000..6aa0dfa
--- /dev/null
+++ b/hubs/templates/add_widget.html
@@ -0,0 +1,84 @@
+
+<div class="modal-dialog" id="adding_form">
+  <div class="modal-content">
+    {% if widget %}
+    <form method="post" action="{{ url_to }}">
+    {% endif %}
+    <!-- Modal content-->
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        <h4 class="modal-title">
+          Adding widget {% if widget %}"{{ widget_name }}"{% endif -%} to hub: {{ hub.name }}
+        </h4>
+      </div>
+      <div class="modal-body">
+        {% if widgets %}
+        <select id="widget" class="c-select" name="widget">
+            {% for w in widgets %}
+            <option value="{{ w }}">{{ w }}</option>
+            {% endfor %}
+        </select>
+        {% elif widget %}
+        <input name="widget_name" type="hidden" value="{{ widget_name }}">
+        <input name="position" type="hidden" value="{{ side }}">
+        {% if widget.data.widget_arguments %}
+          {% for arg in widget.data.widget_arguments %}
+            <fieldset class="form-group ">
+              <strong>{{ arg.name | capitalize }}</strong>
+              <input id="{{ arg.name }}" class="form-control" type="text"
+                value="{{ arg.default if arg.default else '' }}"
+                name="{{ arg.name }}" />
+            </fieldset>
+            {% if arg.help %}
+              <div>
+                <small class="text-muted">{{ arg.help }}</small>
+              </div>
+            {% endif %}
+          {% endfor %}
+        {% else %}
+          <p>Nothing to configure</p>
+        {% endif %}
+        {% endif %}
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">
+          Close
+        </button>
+        <button type="submit" class="btn btn-default" id="submit_btn">
+          Add
+        </button>
+      </div>
+    {% if widget %}
+    </form>
+    {% endif %}
+  </div>
+</div>
+
+{% if widgets %}
+<script type="text/javascript">
+$("#submit_btn").unbind();
+$("#submit_btn").click(function() {
+  console.log($('#widget').val());
+
+  $.ajax({
+    url: 'add/' + $('#widget').val() + '?position={{ side }}',
+    dataType: 'html',
+    success: function(html) {
+      $('#adding_form').html(html);
+    },
+    error: function() {
+      $('#adding_form').html(
+        '<div class="modal-dialog"><div class="modal-content"> \
+        <div class="modal-body"> \
+        An error occured when trying to add a new widget\
+        </div></div></div>'
+      );
+      console.log('error');
+      console.trace();
+    },
+  });
+  return false;
+
+});
+</script>
+{% endif %}
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index b142fd6..a65f1d0 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -114,7 +114,7 @@
         <div class="card">
           <div class="card-block">
             <h4>
-              <a href="#">
+              <a href="#" class="add_widget" data-position="left">
                 <span class="oi" data-glyph="plus"></span> Add a widget
               </a>
             </h4>
@@ -136,7 +136,7 @@
         <div class="card">
           <div class="card-block">
             <h4>
-              <a href="#">
+              <a href="#" class="add_widget" data-position="right">
                 <span class="oi" data-glyph="plus"></span> Add a widget
               </a>
             </h4>
@@ -189,6 +189,35 @@ function make_widget_sortable() {
 
 };
 
+function setup_add_btns() {
+  $(".add_widget").unbind();
+  $(".add_widget").click(function() {
+    console.log($(this));
+    var _pos = $(this).attr('data-position');
+
+    $.ajax({
+      url: 'add?position=' + _pos,
+      dataType: 'html',
+      success: function(html) {
+        $('#edit_modal_content').html(html);
+        $('#edit_modal').modal();
+      },
+      error: function() {
+        $('#edit_modal_content').html(
+          '<div class="modal-dialog"><div class="modal-content"> \
+          <div class="modal-body"> \
+          An error occured when trying to add a new widget\
+          </div></div></div>'
+        );
+        console.log('error');
+        console.trace();
+        $('#edit_modal').modal();
+      },
+    });
+    return false;
+  });
+}
+
 $('#save_edits_btn').click(function() {
   var _r_indexes = [];
   var _r_widgets = [];
@@ -270,6 +299,7 @@ function setup_widgets(widgets) {
 
   {% if edit -%}
   make_widget_sortable();
+  setup_add_btns();
   {%- endif %}
 }
 

From 9001ba2a1f67bdbbe96dd6a6c1f943198b211cef Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 28 2016 08:16:35 +0000
Subject: [PATCH 461/1001] After adding a new widget, remain on edit mode so that it can be placed


---

diff --git a/hubs/app.py b/hubs/app.py
index b5d3453..ac35c48 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -378,7 +378,7 @@ def widget_edit_delete(hub, idx):
             'Could not delete this widget from this hub in the database '\
             'if the error persists, please warn an admin',
             'error')
-    return flask.redirect(flask.url_for('hub', name=hub))
+    return flask.redirect(flask.url_for('hub_edit', name=hub))
 
 
 @app.route('/source/<name>/')

From 9ef3e4f0474388dd77b022a5c617ee0da0cd6c34 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 28 2016 08:16:35 +0000
Subject: [PATCH 462/1001] Fix re-ordering the widgets on both left and right sides


---

diff --git a/hubs/app.py b/hubs/app.py
index ac35c48..a35dee8 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -138,30 +138,64 @@ def hub_edit_post(name):
     is_js = flask.request.form.get('js', False)
 
     error = False
+
     # Check the input submitted
-    widget_ids = [
-        w.strip().replace('widget-', '') for w in flask.request.form.getlist('widgets[]')
+    # Right side
+    r_widget_ids = [
+        w.strip().replace('widget-', '')
+        for w in flask.request.form.getlist('right_widgets[]')
         if w.strip()
     ]
     try:
-        widget_ids = [int(w) for w in widget_ids]
+        r_widget_ids = [int(w) for w in r_widget_ids]
     except:
         flask.flash('Invalid widget identifiers submitted', 'error')
         error = True
 
-    indexes = [
-        i.strip() for i in flask.request.form.getlist('indexes[]')
+    r_indexes = [
+        i.strip() for i in flask.request.form.getlist('right_indexes[]')
         if i.strip()
     ]
 
     try:
-        indexes = [int(i) for i in indexes]
+        r_indexes = [int(i) for i in r_indexes]
     except:
         if not is_js:
             flask.flash('Invalid indexes submitted', 'error')
         error = True
 
-    if len(widget_ids) != len(indexes):
+    if len(r_widget_ids) != len(r_indexes):
+        if not is_js:
+            flask.flash(
+                'The number of indexes and the number of widgets are not of '
+                'the same length', 'error')
+        error = True
+
+    # Left side
+    l_widget_ids = [
+        w.strip().replace('widget-', '')
+        for w in flask.request.form.getlist('left_widgets[]')
+        if w.strip()
+    ]
+    try:
+        l_widget_ids = [int(w) for w in l_widget_ids]
+    except:
+        flask.flash('Invalid widget identifiers submitted', 'error')
+        error = True
+
+    l_indexes = [
+        i.strip() for i in flask.request.form.getlist('left_indexes[]')
+        if i.strip()
+    ]
+
+    try:
+        l_indexes = [int(i) for i in l_indexes]
+    except:
+        if not is_js:
+            flask.flash('Invalid indexes submitted', 'error')
+        error = True
+
+    if len(l_widget_ids) != len(l_indexes):
         if not is_js:
             flask.flash(
                 'The number of indexes and the number of widgets are not of '
@@ -170,10 +204,15 @@ def hub_edit_post(name):
 
     # If all good, update the database
     if not error:
-        for cnt, wid in enumerate(widget_ids):
+        for cnt, wid in enumerate(r_widget_ids):
+            widget = hubs.models.Widget.get(session, wid)
+            if widget.index != r_indexes[cnt]:
+                widget.index = r_indexes[cnt]
+                session.add(widget)
+        for cnt, wid in enumerate(l_widget_ids):
             widget = hubs.models.Widget.get(session, wid)
-            if widget.index != indexes[cnt]:
-                widget.index = indexes[cnt]
+            if widget.index != l_indexes[cnt]:
+                widget.index = l_indexes[cnt]
                 session.add(widget)
         hub.last_edited = datetime.datetime.utcnow()
         session.add(hub)
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index a65f1d0..77c0135 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -226,6 +226,8 @@ $('#save_edits_btn').click(function() {
     _r_widgets.push($(el).attr('id').split('widget-')[1])
   });
 
+  var _l_indexes = [];
+  var _l_widgets = [];
   $.each($('#left_widgets .widget'), function(i, el) {
     _l_indexes.push(i);
     _l_widgets.push($(el).attr('id').split('widget-')[1])

From 477fdc3e4d55375c4e44ca578ebbf16bba51d698 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 28 2016 09:00:56 +0000
Subject: [PATCH 463/1001] Make the `Add to calendar` button in the meeting widget working


---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 5812f94..e6c68c1 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -17,13 +17,15 @@ import requests
 def next_meeting(meetings):
     now = datetime.datetime.utcnow()
     for meeting in meetings:
-        start_string = "%s %s" % (meeting['meeting_date'],
-                            meeting['meeting_time_start'])
-        start_dt = datetime.datetime.strptime(start_string, "%Y-%m-%d %H:%M:%S")
-
-        stop_string = "%s %s" % (meeting['meeting_date_end'],
-                            meeting['meeting_time_stop'])
-        stop_dt = datetime.datetime.strptime(stop_string, "%Y-%m-%d %H:%M:%S")
+        start_string = "%s %s" % (
+            meeting['meeting_date'], meeting['meeting_time_start'])
+        start_dt = datetime.datetime.strptime(
+            start_string, "%Y-%m-%d %H:%M:%S")
+
+        stop_string = "%s %s" % (
+            meeting['meeting_date_end'], meeting['meeting_time_stop'])
+        stop_dt = datetime.datetime.strptime(
+            stop_string, "%Y-%m-%d %H:%M:%S")
 
         # Loop over them until we find a good one.
         # Meetings before now are no good.  We want the first one after now.
diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index 6965c5f..0fc9601 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -1,34 +1,36 @@
 {% if meetings %}
 {% for title, next in meetings.items() %}
 <div class="meeting">
-    <div class="row">
-        <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.start_dt | humanize }}</h5>
+  <div class="row">
+      <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.start_dt | humanize }}</h5>
+  </div>
+  <div class="row">
+    <div class="col-md-4 meeting-date">
+      {% if next.display_duration %}
+      <strong>{{ next.start_date }} - {{ next.stop_date }}</strong>
+      {% else %}
+      <strong>{{next.start_date}}</strong>
+      {% endif %}
     </div>
-    <div class="row">
-        <div class="col-md-4 meeting-date">
-            {% if next.display_duration %}
-            <strong>{{next.start_date}} - {{next.stop_date}}</strong>
-            {% else %}
-            <strong>
-                {{next.start_date}}
-            </strong>
-            {% endif %}
-        </div>
-        <div class="col-md-4 meeting-time">
-            {% if next.display_time %}
-            @{{next.start_time}}{% endif %}<br>
+    <div class="col-md-4 meeting-time">
+      {% if next.display_time %}
+      @{{ next.start_time }}{% endif %}<br>
 
-            <a href="#">{{next.location}}</a>
-        </div>
-        <div class="col-md-4">
-            <button class="btn btn-default btn-sm add-calendar"><strong>Add to calendar</strong></button>
-        </div>
+      <a href="#">{{ next.location }}</a>
     </div>
-    <div class="row">
-        <div class="col-md-12 meeting-info">
-            {{next.meeting_information_html}}
-        </div>
+    <div class="col-md-4">
+      <a href="https://apps.fedoraproject.org/calendar/ical/calendar/meeting/{{ next.meeting_id }}/">
+        <button class="btn btn-default btn-sm add-calendar">
+          <strong>Add to calendar</strong>
+        </button>
+      </a>
     </div>
+  </div>
+  <div class="row">
+      <div class="col-md-12 meeting-info">
+        {{ next.meeting_information_html }}
+      </div>
+  </div>
 </div>
 {% if meetings | length > 1 %} <hr> {% endif %}
 {% endfor %}

From bbe25f145f64ebbc71e9da299b28f30ee095824c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 28 2016 14:16:40 +0000
Subject: [PATCH 464/1001] Keep the meeting description short


---

diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index 0fc9601..c075ded 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -28,7 +28,8 @@
   </div>
   <div class="row">
       <div class="col-md-12 meeting-info">
-        {{ next.meeting_information_html }}
+        {{ next.meeting_information_html[:150] }}{%
+          if next.meeting_information_html | length > 150 %}...{% endif %}
       </div>
   </div>
 </div>

From 2844984122ab746a90bf1039d0d321c2fe3af5bb Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 28 2016 14:20:55 +0000
Subject: [PATCH 465/1001] Link to the meeting detail page for more info


---

diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index c075ded..e863b58 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -28,8 +28,12 @@
   </div>
   <div class="row">
       <div class="col-md-12 meeting-info">
-        {{ next.meeting_information_html[:150] }}{%
-          if next.meeting_information_html | length > 150 %}...{% endif %}
+        {{ next.meeting_information_html[:150] }}
+        {%- if next.meeting_information_html | length > 150 %}...
+        <p>
+          <a href="https://apps.fedoraproject.org/calendar/meeting/{{ next.meeting_id }}/">Full description</a>
+        </p>
+        {% endif %}
       </div>
   </div>
 </div>

From 306b821548e689ccba9b4f5ad2801ff3cce5f475 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 29 2016 12:26:07 +0000
Subject: [PATCH 466/1001] HTML indentation clean up


---

diff --git a/hubs/widgets/templates/stats.html b/hubs/widgets/templates/stats.html
index a8f0a8a..63bf1e5 100644
--- a/hubs/widgets/templates/stats.html
+++ b/hubs/widgets/templates/stats.html
@@ -2,39 +2,72 @@
 <div class="col-md-7">
   <table class="stats-table">
     <tr><th>Members</th><th>Subscribers</th></tr>
-    <tr class="text-info"><td>{{members_text}}</td><td class="text-right">{{subscribers_text}}</td></tr>
+    <tr class="text-info">
+      <td>{{members_text}}</td>
+      <td class="text-right">{{subscribers_text}}</td>
+    </tr>
   </table>
 </div>
 <div class="col-md-5">
   <ul class="list-unstyled">
   {% if g.auth.nickname in subscribers %}
-  <li><form action="{{hub_unsubscribe_url}}" method="POST">
-      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
-  </form></li>
+  <li>
+    <form action="{{hub_unsubscribe_url}}" method="POST">
+      <button class="btn btn-info">
+        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
+        Unsubscribe
+      </button>
+    </form>
+  </li>
   {% else %}
-  <li><form action="{{hub_subscribe_url}}" method="POST">
-      <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
-  </form></li>
+  <li>
+    <form action="{{hub_subscribe_url}}" method="POST">
+      <button class="btn btn-default">
+        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
+        Subscribe
+      </button>
+    </form>
+  </li>
   {% endif %}
 
   {% if g.auth.nickname in stargazers %}
-  <li><form action="{{hub_unstar_url}}" method="POST">
-      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unstar Hub</button>
-  </form></li>
+  <li>
+    <form action="{{hub_unstar_url}}" method="POST">
+      <button class="btn btn-info">
+        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
+        Unstar Hub
+      </button>
+    </form>
+  </li>
   {% else %}
-  <li><form action="{{hub_star_url}}" method="POST">
-      <button class="btn btn-default"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Star Hub</button>
-  </form></li>
+  <li>
+    <form action="{{hub_star_url}}" method="POST">
+      <button class="btn btn-default">
+        <span class="glyphicon glyphicon-star" aria-hidden="true"></span>
+        Star Hub
+      </button>
+    </form>
+  </li>
   {% endif %}
 
   {% if g.auth.nickname in members %}
-  <li><form action="{{hub_leave_url}}" method="POST">
-      <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Leave Hub</button>
-  </form></li>
+  <li>
+    <form action="{{hub_leave_url}}" method="POST">
+      <button class="btn btn-info">
+        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
+        Leave Hub
+      </button>
+    </form>
+  </li>
   {% else %}
-  <li><form action="{{hub_join_url}}" method="POST">
-      <button class="btn btn-default"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Join Hub</button>
-  </form></li>
+  <li>
+    <form action="{{hub_join_url}}" method="POST">
+      <button class="btn btn-default">
+        <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
+        Join Hub
+      </button>
+    </form>
+  </li>
   {% endif %}
   </ul>
 </div>

From db682786bd72b8f5ebbddfd647409f2d34ea1551 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 02 2016 11:10:11 +0000
Subject: [PATCH 467/1001] Make the favicon be the user's avatar


---

diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index b2fc833..e4ae32e 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -10,6 +10,9 @@
         type="text/css" rel="stylesheet" />
   <link href="{{ url_for('static', filename='badges/b.css') }}"
         type="text/css" rel="stylesheet" />
+  <link rel="icon"
+      type="image/png"
+      href="{% if hub %}{{ hub.avatar }}{% else %}//fedoraproject.org/static/images/favicon.ico{% endif %}">
 </head>
 <body>
 <div class="masthead">

From 2847f9e9e2ebf32249bd4fb6595e190cf2c10241 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 02 2016 15:30:03 +0000
Subject: [PATCH 468/1001] Add a new endpoint serving and caching locally the user's avatar


---

diff --git a/hubs/app.py b/hubs/app.py
index a35dee8..2037a04 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -6,6 +6,7 @@ import os
 import flask
 import flask.json
 import munch
+import requests
 import six
 
 from flask.ext.openid import OpenID
@@ -78,6 +79,21 @@ def index():
     return flask.redirect(flask.url_for('hub', name=flask.g.auth.nickname))
 
 
+@app.route('/_avatar/<username>')
+def avatar(username):
+    favicon = os.path.join(
+        app.static_folder, 'cache', '%s.png' % username)
+    if not os.path.exists(favicon):
+        req = requests.get(hubs.utils.username2avatar(username, s=32))
+        if req:
+            with open(favicon, 'w') as stream:
+                stream.write(req.content)
+
+    return flask.redirect(
+        flask.url_for('static', filename='cache/%s.png' % username)
+    )
+
+
 @app.route('/groups')
 def groups():
     if not flask.g.auth.logged_in:

From 0ae15d4759901348cc0188d20b9feb9442a56e7f Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 02 2016 20:24:49 +0000
Subject: [PATCH 469/1001] Let hubs.widgets.base return the url to the avatar endpoint


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index fcce04a..e8efbdc 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -99,8 +99,4 @@ def wraps(original):
 
 
 def avatar(username, size=32):
-    openid = 'http://%s.id.fedoraproject.org/' % username
-    query = six.moves.urllib_parse.urlencode({'s': size, 'd': 'retro'})
-    hash = hashlib.sha256(openid.encode('utf-8')).hexdigest()
-    template = "https://seccdn.libravatar.org/avatar/%s?%s"
-    return template % (hash, query)
+    return flask.url_for('avatar', username=username)

From de8142f22bf29abc8c6a0043b31944e105d64a2f Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 02 2016 20:27:12 +0000
Subject: [PATCH 470/1001] Use the new endpoint for the avatar instead of username2avatar


---

diff --git a/hubs/models.py b/hubs/models.py
index 059ad28..d228464 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -41,7 +41,6 @@ import fedmsg.utils
 
 import hubs.defaults
 import hubs.widgets
-from hubs.utils import username2avatar
 
 
 class HubsBase(object):
@@ -228,7 +227,7 @@ class Hub(BASE):
     @classmethod
     def create_user_hub(cls, session, username, fullname):
         hub = cls(name=username, summary=fullname,
-                  avatar=username2avatar(username),
+                  avatar=hubs.widget.base.avatar(username),
                   user_hub=True)
         session.add(hub)
 
@@ -242,7 +241,7 @@ class Hub(BASE):
     def create_group_hub(cls, session, name, summary, **extra):
         hub = cls(name=name, summary=summary,
                   # TODO -- do something else, smarter for group avatars
-                  avatar=username2avatar(name),
+                  avatar=hubs.widget.base.avatar(username),
                   user_hub=False)
         session.add(hub)
 
@@ -349,7 +348,7 @@ class User(BASE):
         return {
             'username': self.username,
             'openid': self.openid,
-            'avatar': username2avatar(self.username),
+            'avatar': hubs.widget.base.avatar(self.username),
             'fullname': self.fullname,
             'created_on': self.created_on,
             # We'll need hubs subscribed to, owned, etc..

From dc5c703eca247eb6fe7ac53dbf08f9047b933bb8 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 02 2016 20:33:37 +0000
Subject: [PATCH 471/1001] Import our customize notificon JS library and fix html


---

diff --git a/hubs/static/notificon.js b/hubs/static/notificon.js
new file mode 100644
index 0000000..b7742a8
--- /dev/null
+++ b/hubs/static/notificon.js
@@ -0,0 +1,185 @@
+/*
+Notificon :: Client-side Favicon Notifications - Usage: Notificon(label='',favicon_url={default_favicon})
+=========================================================================================================
+
+Copyright (c) 2011 Matt Williams <matt@makeable.co.uk>. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright notice, this list
+      of conditions and the following disclaimer in the documentation and/or other materials
+      provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY MATT WILLIAMS ''AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATT WILLIAMS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the
+authors and should not be interpreted as representing official policies,
+either expressed or implied, of Matt Williams.
+
+Modified by Pierre-Yves Chibon <pingou@pingoured.fr> using code from the
+favicon-notification project (https://github.com/igorprado/favicon-notification)
+licensed under the MIT license.
+
+*/
+
+(function(){
+
+  var unsupported = false;
+  var _options = {};
+
+  var checkSupport = function checkSupport() {
+    if (unsupported) {
+        return false;
+    }
+    if (!document.createElement('canvas').getContext) {
+        unsupported = true;
+        if (console) {
+            console.log('Notificon: requires canvas support');
+        }
+        return false;
+    }
+    return true;
+  }
+
+
+  var _defaults = {
+    color: '#eb361e',
+    lineColor: '#ffffff'
+  };
+
+  var _setOptions = function(options) {
+    if (!options) {
+      _options = _defaults;
+      return;
+    }
+
+    _options = {};
+
+    for(var key in _defaults){
+         _options[key] = options.hasOwnProperty(key) ? options[key] : _defaults[key];
+    }
+  };
+
+  var findFaviconTag = function findFaviconTag(notificon) {
+    var link_tags = document.getElementsByTagName('link');
+    for (var i=0; i < link_tags.length; i++) {
+      if (notificon && (/\bnotificon\b/i).test(link_tags[i].getAttribute('rel'))) {
+        return link_tags[i];
+      } else if (!notificon && (/\bicon\b/i).test(link_tags[i].getAttribute('rel'))) {
+        return link_tags[i];
+      }
+    }
+    return false;
+  };
+
+  var getExistingFavicon = function getExistingFavicon() {
+    var favicon = findFaviconTag();
+    return favicon ? favicon.getAttribute('href') : '/favicon.ico';
+  };
+
+  var removeNotificon = function removeNotificon() {
+    var notificon = findFaviconTag(true);
+    if (notificon) {
+      notificon.parentNode.removeChild(notificon);
+      removeNotificon();
+    }
+  };
+
+  var changeFavicon = function changeFavicon(canvas) {
+    var link = document.createElement('link');
+    link.type = 'image/x-icon';
+    link.rel = 'icon notificon';
+    link.href = canvas.toDataURL("image/png");
+    removeNotificon();
+    document.getElementsByTagName('head')[0].appendChild(link);
+  };
+
+  var drawLabel = function drawLabel(canvas, label, favicon) {
+    var img = document.createElement('img');
+    img.src = favicon;
+
+    img.onload = function() {
+      var lineWidth = 2;
+
+      canvas.width = img.width;
+      canvas.height = img.height;
+
+      var context = canvas.getContext('2d');
+      context.clearRect(0, 0, img.width, img.height);
+      context.drawImage(img, 0, 0);
+
+      var centerX = img.width - (img.width / 4.5) - lineWidth;
+      var centerY = img.height - (img.height / 4.5) - lineWidth;
+      var radius = img.width / 4.5;
+
+      context.fillStyle = _options.color;
+      context.strokeStyle = _options.lineColor;
+      context.lineWidth = lineWidth;
+
+      context.beginPath();
+      context.arc(centerX, centerY, radius, 0, Math.PI * 2, false);
+      context.closePath();
+      context.fill();
+      context.stroke();
+
+      changeFavicon(canvas)
+    }
+  };
+
+  var imgToCanvas = function imgToCanvas(img) {
+    var canvas = document.createElement("canvas");
+    canvas.width = img.width;
+    canvas.height = img.height;
+    var context = canvas.getContext("2d");
+    context.drawImage(img, 0, 0);
+    return canvas;
+  };
+
+  var createNotificon = function createNotificon(label, favicon) {
+    if (!checkSupport()) {
+        return false;
+    }
+    if (!favicon) {
+      favicon = getExistingFavicon();
+    }
+    var img = document.createElement("img");
+    img.src = favicon;
+    img.onload = function() {
+      var canvas = imgToCanvas(img);
+      if (label) {
+        drawLabel(canvas, label, favicon);
+      }
+      try {
+        changeFavicon(canvas);
+      } catch(e) {
+        if (console) {
+          console.log(e)
+          console.log('Notificon: cannot use icons located on a different domain (' + favicon + ')');
+        }
+      }
+
+    };
+    img.onerror = function() {
+      if (console) {
+        console.log('Notificon: image not found (' + favicon + ')');
+      }
+    };
+  };
+
+  this.Notificon = function(label, favicon, options) {
+    _setOptions(options);
+    createNotificon(label, favicon);
+  };
+})();
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index e4ae32e..cb35ed6 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -6,6 +6,7 @@
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
+  <script type="text/javascript"  src="{{ url_for('static', filename='notificon.js') }}"></script>
   <link href="{{ url_for('static', filename='open_iconic_1.1.0/css/open-iconic.min.css') }}"
         type="text/css" rel="stylesheet" />
   <link href="{{ url_for('static', filename='badges/b.css') }}"
@@ -45,7 +46,7 @@
       <div class="input-group">
         <input type="search" class="form-control" placeholder="Search across all hubs ..." aria-describedby="searchform-addon"></input>
         <span class="input-group-addon" id="searchform-addon">
-          <span class="oi" data-glyph="magnifying-glass" / >
+          <span class="oi" data-glyph="magnifying-glass"></span>
         </span>
     </div>
     </div>

From 23bc2f764605a0adcaec76b4992de41769642c71 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 03 2016 05:46:43 +0000
Subject: [PATCH 472/1001] Let's provide the color of the notification as argument to Notificon


---

diff --git a/hubs/static/notificon.js b/hubs/static/notificon.js
index b7742a8..82322c8 100644
--- a/hubs/static/notificon.js
+++ b/hubs/static/notificon.js
@@ -106,7 +106,7 @@ licensed under the MIT license.
     document.getElementsByTagName('head')[0].appendChild(link);
   };
 
-  var drawLabel = function drawLabel(canvas, label, favicon) {
+  var drawLabel = function drawLabel(canvas, color, favicon) {
     var img = document.createElement('img');
     img.src = favicon;
 
@@ -124,7 +124,7 @@ licensed under the MIT license.
       var centerY = img.height - (img.height / 4.5) - lineWidth;
       var radius = img.width / 4.5;
 
-      context.fillStyle = _options.color;
+      context.fillStyle = color;
       context.strokeStyle = _options.lineColor;
       context.lineWidth = lineWidth;
 
@@ -147,7 +147,7 @@ licensed under the MIT license.
     return canvas;
   };
 
-  var createNotificon = function createNotificon(label, favicon) {
+  var createNotificon = function createNotificon(color, favicon) {
     if (!checkSupport()) {
         return false;
     }
@@ -158,8 +158,8 @@ licensed under the MIT license.
     img.src = favicon;
     img.onload = function() {
       var canvas = imgToCanvas(img);
-      if (label) {
-        drawLabel(canvas, label, favicon);
+      if (color) {
+        drawLabel(canvas, color, favicon);
       }
       try {
         changeFavicon(canvas);
@@ -178,8 +178,8 @@ licensed under the MIT license.
     };
   };
 
-  this.Notificon = function(label, favicon, options) {
+  this.Notificon = function(color, favicon, options) {
     _setOptions(options);
-    createNotificon(label, favicon);
+    createNotificon(color, favicon);
   };
 })();

From d1f4cd2db37e509a018c863023f9a059ee033ffa Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 03 2016 05:47:01 +0000
Subject: [PATCH 473/1001] Let's show then hide the notification, just as testing for now


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 77c0135..865c123 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -307,5 +307,11 @@ function setup_widgets(widgets) {
 
 setup_widgets();
 
+/* This is how to activate and remove (here after 13 sec) the favicon
+notification */
+Notificon('#33ff00');
+setTimeout(Notificon, 13000)
+
+
 </script>
 {% endblock %}

From 5a98296e97f8ccacb58df2a50f8e202347c3cff6 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 04 2016 13:27:31 +0000
Subject: [PATCH 474/1001] Drop the change for the avatar


Now all the avatar work is done in one location instead of two.

---

diff --git a/hubs/app.py b/hubs/app.py
index 2037a04..1a77545 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -6,7 +6,6 @@ import os
 import flask
 import flask.json
 import munch
-import requests
 import six
 
 from flask.ext.openid import OpenID
@@ -24,7 +23,7 @@ app = flask.Flask(__name__)
 def days_since(then):
     return (datetime.datetime.utcnow() - then).days
 app.template_filter('days_since')(days_since)
-app.template_filter('avatar')(hubs.widgets.base.avatar)
+app.template_filter('avatar')(username2avatar)
 
 logging.basicConfig()
 
@@ -79,21 +78,6 @@ def index():
     return flask.redirect(flask.url_for('hub', name=flask.g.auth.nickname))
 
 
-@app.route('/_avatar/<username>')
-def avatar(username):
-    favicon = os.path.join(
-        app.static_folder, 'cache', '%s.png' % username)
-    if not os.path.exists(favicon):
-        req = requests.get(hubs.utils.username2avatar(username, s=32))
-        if req:
-            with open(favicon, 'w') as stream:
-                stream.write(req.content)
-
-    return flask.redirect(
-        flask.url_for('static', filename='cache/%s.png' % username)
-    )
-
-
 @app.route('/groups')
 def groups():
     if not flask.g.auth.logged_in:
diff --git a/hubs/models.py b/hubs/models.py
index d228464..49a9503 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -41,6 +41,7 @@ import fedmsg.utils
 
 import hubs.defaults
 import hubs.widgets
+from hubs.utils import username2avatar
 
 
 class HubsBase(object):
@@ -227,7 +228,7 @@ class Hub(BASE):
     @classmethod
     def create_user_hub(cls, session, username, fullname):
         hub = cls(name=username, summary=fullname,
-                  avatar=hubs.widget.base.avatar(username),
+                  avatar=username2avatar(username),
                   user_hub=True)
         session.add(hub)
 
@@ -241,7 +242,7 @@ class Hub(BASE):
     def create_group_hub(cls, session, name, summary, **extra):
         hub = cls(name=name, summary=summary,
                   # TODO -- do something else, smarter for group avatars
-                  avatar=hubs.widget.base.avatar(username),
+                  avatar=username2avatar(username),
                   user_hub=False)
         session.add(hub)
 
@@ -348,7 +349,7 @@ class User(BASE):
         return {
             'username': self.username,
             'openid': self.openid,
-            'avatar': hubs.widget.base.avatar(self.username),
+            'avatar': username2avatar(self.username),
             'fullname': self.fullname,
             'created_on': self.created_on,
             # We'll need hubs subscribed to, owned, etc..
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index e8efbdc..91d3931 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -96,7 +96,3 @@ def wraps(original):
         subsequent.widget_arguments = getattr(original, 'widget_arguments', [])
         return subsequent
     return decorator
-
-
-def avatar(username, size=32):
-    return flask.url_for('avatar', username=username)
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index d0bfad7..edf141a 100755
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -2,8 +2,9 @@ from collections import OrderedDict as ordereddict
 
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
-from hubs.widgets.base import argument, avatar
+from hubs.widgets.base import argument
 from hubs.widgets import templating
+from hubs.utils import username2avatar
 from hubs import validators
 
 chrome = panel()
@@ -25,7 +26,9 @@ position = 'both'
           help="Link to meeting minutes from past meetings..")
 def data(session, widget, link, schedule_text, schedule_link, minutes_link):
     owners = widget.hub.owners
-    owners = ordereddict([(o.username, avatar(o.username)) for o in owners])
+    owners = ordereddict([
+        (o.username, username2avatar(o.username)) for o in owners
+    ])
     return dict(owners=owners, link=link,
                 schedule_text=schedule_text,
                 schedule_link=schedule_link,

From 86bc97d1e5dda2f2f3e6c2d8320108d3819eb299 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 04 2016 13:28:04 +0000
Subject: [PATCH 475/1001] Add a hubs favicon and make it present on all hubs


---

diff --git a/hubs/static/img/favicon.png b/hubs/static/img/favicon.png
new file mode 100644
index 0000000..bc35b8d
Binary files /dev/null and b/hubs/static/img/favicon.png differ
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index cb35ed6..899847c 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -11,9 +11,8 @@
         type="text/css" rel="stylesheet" />
   <link href="{{ url_for('static', filename='badges/b.css') }}"
         type="text/css" rel="stylesheet" />
-  <link rel="icon"
-      type="image/png"
-      href="{% if hub %}{{ hub.avatar }}{% else %}//fedoraproject.org/static/images/favicon.ico{% endif %}">
+  <link rel="icon" type="image/png"
+      href="{{ url_for('static', filename='img/favicon.png') }}">
 </head>
 <body>
 <div class="masthead">

From e71bfaa5cacea3aff5e5f08f195c4222787772f5 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 04 2016 13:29:16 +0000
Subject: [PATCH 476/1001] Show logic to toggle notification on and off


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 865c123..c18533b 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -309,8 +309,12 @@ setup_widgets();
 
 /* This is how to activate and remove (here after 13 sec) the favicon
 notification */
+console.log('Show notification');
 Notificon('#33ff00');
-setTimeout(Notificon, 13000)
+setTimeout(function(){console.log('Hide notification'); Notificon()}, 13000)
+setTimeout(function(){
+    console.log('Show notification'); Notificon('#eb361e')
+  }, 15000)
 
 
 </script>

From b09c41c3718f52ec42da377e7c802683e82a9377 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 04 2016 13:39:46 +0000
Subject: [PATCH 477/1001] Hide the notification at the end


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index c18533b..618c45a 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -315,7 +315,7 @@ setTimeout(function(){console.log('Hide notification'); Notificon()}, 13000)
 setTimeout(function(){
     console.log('Show notification'); Notificon('#eb361e')
   }, 15000)
-
+setTimeout(function(){console.log('Hide notification'); Notificon()}, 18000)
 
 </script>
 {% endblock %}

From 9cd74442c72eebce47980f89417d5edb71aa77b9 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 06 2016 09:16:21 +0000
Subject: [PATCH 478/1001] Fix typo found by @sayanchowdhury


---

diff --git a/hubs/models.py b/hubs/models.py
index 49a9503..059ad28 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -242,7 +242,7 @@ class Hub(BASE):
     def create_group_hub(cls, session, name, summary, **extra):
         hub = cls(name=name, summary=summary,
                   # TODO -- do something else, smarter for group avatars
-                  avatar=username2avatar(username),
+                  avatar=username2avatar(name),
                   user_hub=False)
         session.add(hub)
 

From 411b9de129d53cceb9949a61ea51ed94b30773cb Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 06 2016 09:38:17 +0000
Subject: [PATCH 479/1001] Fix the class of the panel footer and the 'Request A New Meeting' buttton


---

diff --git a/hubs/widgets/templates/meeting_footer.html b/hubs/widgets/templates/meeting_footer.html
index f45acc0..50b49ef 100644
--- a/hubs/widgets/templates/meeting_footer.html
+++ b/hubs/widgets/templates/meeting_footer.html
@@ -1,5 +1,7 @@
-<div class="panel-footer panel-heading">
-	<div class="row" align="center">
-		<a class="btn btn-default" href="#"><strong>Request A New Meeting</strong></a>
-	</div>
+<div class="panel-footer">
+  <div class="row" align="center">
+    <button class="btn btn-default">
+      <strong>Request A New Meeting</strong>
+    </button>
+  </div>
 </div>

From f1b9d9eafb5ea09c46ee7679ffb2de77e044f0f8 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: May 06 2016 09:38:41 +0000
Subject: [PATCH 480/1001] Make the widget meeting have a 'Meetings' title instead of 'Reminders'


---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index e6c68c1..e8fede6 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -54,7 +54,7 @@ def next_meeting(meetings):
 
 
 footer_template = templating.environment.get_template('templates/meeting_footer.html')
-chrome = panel(title = 'Reminders', key='meetings', footer_template=footer_template)
+chrome = panel(title = 'Meetings', key='meetings', footer_template=footer_template)
 templating.environment.filters['humanize'] = lambda d: arrow.get(d).humanize()
 template = templating.environment.get_template('templates/meetings.html')
 position = 'both'

From 2900f5ac0b8610ffb832841aa94e46b720757eaa Mon Sep 17 00:00:00 2001
From: skrzepto <skrzepto@localhost.localdomain>
Date: May 25 2016 19:41:16 +0000
Subject: [PATCH 481/1001] Added section about cloning repository, and also solution for missing redhat-hardened-cc1 when you try to install the requirements


---

diff --git a/README.rst b/README.rst
index 7fe3e92..9d50626 100644
--- a/README.rst
+++ b/README.rst
@@ -38,10 +38,23 @@ type ``workon hubs``, which will re-activate the virtual
 environment that you *made* last time.  (The ``mk`` in
 ``mkvirtualenv`` stands for "make".)
 
+Now we need to pull the project and change our working directory::
+
+    $ git clone https://pagure.io/fedora-hubs.git
+    $ cd ./fedora-hubs
+
 OK -- with that done, now install the dependencies from PyPI::
 
     $ pip install -r requirements.txt
 
+If you get an error::
+
+    gcc: error: /usr/lib/rpm/redhat/redhat-hardened-cc1: No such file or directory
+
+You need to install ``redhat-rpm-config`` and try again::
+
+    $ sudo dnf install redhat-rpm-config
+
 With that, try running the app with::
 
     $ python populate.py  # To create the db

From c40b960b7f87d62e8f90151ef8d0af760117b0ad Mon Sep 17 00:00:00 2001
From: skrzepto <skrzepto@localhost.localdomain>
Date: May 25 2016 20:15:50 +0000
Subject: [PATCH 482/1001] moved redhat-rpm-config to the install fedora section


---

diff --git a/README.rst b/README.rst
index 9d50626..5ec6862 100644
--- a/README.rst
+++ b/README.rst
@@ -16,7 +16,7 @@ Hacking
 =======
 Install fedora dependencies::
 
-    $ sudo dnf install gcc gcc-c++ sqlite-devel libffi-devel openssl-devel
+    $ sudo dnf install gcc gcc-c++ sqlite-devel libffi-devel openssl-devel redhat-rpm-config
 
 Hubs should work on either python2 **or** python3.  These instructions will
 show the way for python2 only, though.
@@ -47,14 +47,6 @@ OK -- with that done, now install the dependencies from PyPI::
 
     $ pip install -r requirements.txt
 
-If you get an error::
-
-    gcc: error: /usr/lib/rpm/redhat/redhat-hardened-cc1: No such file or directory
-
-You need to install ``redhat-rpm-config`` and try again::
-
-    $ sudo dnf install redhat-rpm-config
-
 With that, try running the app with::
 
     $ python populate.py  # To create the db

From 8d0b1ee81377ed3180346e51f42ee783f349f2fb Mon Sep 17 00:00:00 2001
From: Abhijeet Kasurde <akasurde@redhat.com>
Date: Jun 01 2016 07:28:25 +0000
Subject: [PATCH 483/1001] Fixed pep8 warnings


Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>

---

diff --git a/check-cache-coverage.py b/check-cache-coverage.py
index 8aad708..0f6c6f7 100755
--- a/check-cache-coverage.py
+++ b/check-cache-coverage.py
@@ -40,4 +40,3 @@ sys.stdout.flush()
 total = empty + full
 print full, "cache values found. ", empty, "are missing."
 print full / float(total) * 100, "percent cache coverage."
-
diff --git a/hubs/app.py b/hubs/app.py
index 1a77545..fe661ab 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -19,6 +19,7 @@ from hubs.utils import username2avatar
 
 app = flask.Flask(__name__)
 
+
 # Register some useful global filters.
 def days_since(then):
     return (datetime.datetime.utcnow() - then).days
@@ -33,6 +34,7 @@ logging.basicConfig()
 #        the right tag to link people to.  AGPL ftw.
 SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'#/hubs/widgets/badges.py'
 
+
 app.config.from_object('hubs.default_config')
 if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
@@ -222,7 +224,7 @@ def hub_edit_post(name):
             error = True
             if not is_js:
                 flask.flash(
-                    'Could not save your changes to the database '\
+                    'Could not save your changes to the database '
                     'if the error persists, please warn an admin',
                     'error')
     if is_js:
@@ -327,7 +329,7 @@ def hub_add_widget_post(name):
         except Exception as err:
             print err
             flask.flash(
-                'Could not save the configuration to the database '\
+                'Could not save the configuration to the database '
                 'if the error persists, please warn an admin',
                 'error')
 
@@ -398,7 +400,7 @@ def widget_edit_post(hub, idx):
             session.commit()
         except Exception as err:
             flask.flash(
-                'Could not save the configuration to the database '\
+                'Could not save the configuration to the database '
                 'if the error persists, please warn an admin',
                 'error')
     return flask.redirect(flask.url_for('hub', name=hub))
@@ -414,7 +416,7 @@ def widget_edit_delete(hub, idx):
         session.commit()
     except Exception as err:
         flask.flash(
-            'Could not delete this widget from this hub in the database '\
+            'Could not delete this widget from this hub in the database '
             'if the error persists, please warn an admin',
             'error')
     return flask.redirect(flask.url_for('hub_edit', name=hub))
@@ -532,7 +534,7 @@ def check_auth():
 def get_hub(session, name):
     """ Utility shorthand to get a hub and 404 if not found. """
     hub = session.query(hubs.models.Hub)\
-        .filter(hubs.models.Hub.name==name)\
+        .filter(hubs.models.Hub.name == name)\
         .first()
 
     if not hub:
diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index fac1bb0..ad86221 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -37,6 +37,7 @@ import logging
 import logging.config
 log = logging.getLogger('hubs.backend.triage')
 
+
 def triage(session, outbound, msg):
     topic = msg['topic']
     category = topic.split('.')[3]
@@ -88,7 +89,8 @@ def main(args):
     inbound_name = config['hubs.redis.triage-queue-name']
     outbound_name = config['hubs.redis.work-queue-name']
 
-    log.info("Triage proc starting.  Moving from %r to %r." % (inbound_name, outbound_name))
+    log.info("Triage proc starting. Moving from %r to %r."
+             % (inbound_name, outbound_name))
 
     inbound = retask.queue.Queue(inbound_name)
     inbound.connect()
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 1e917ed..38d77af 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -62,7 +62,6 @@ class WidgetTest(unittest.TestCase):
                                         _config=json.dumps({'calendar': team}))
             hub.widgets.append(widget)
 
-
     # TODO - test that it is in the registry
     # TODO - test that it has all the things it needs
 
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index 2383081..c1ff1f6 100755
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -5,11 +5,11 @@ from hubs.widgets import templating
 
 import hubs.validators as validators
 
-
 chrome = panel("<span class='glyphicon glyphicon-info-sign' aria-hidden='true'></span> About")
 template = templating.environment.get_template('templates/about.html')
 position = 'both'
 
+
 @argument(name="text", default="I am a Fedora user, and this is my about",
           validator=validators.text,
           help="Text about a user.")
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index 4ddbb3d..c5a18d0 100755
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -13,6 +13,7 @@ chrome = panel("Badges")
 template = templating.environment.get_template('templates/badges.html')
 position = 'right'
 
+
 @argument(name="username",
           default=None,
           validator=validators.username,
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index f25f65a..2e73bca 100755
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -9,6 +9,7 @@ chrome = panel("This is a dummy widget")
 template = templating.environment.get_template('templates/dummy.html')
 position = 'both'
 
+
 @argument(name="text", default="Lorem ipsum dolor...",
           validator=validators.text,
           help="Some dummy text to display.")
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 9cd15fd..986951b 100755
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -33,8 +33,10 @@ def data(session, widget, username):
         fedmsgs_text=commas(fedmsgs),
         subscribers_text=commas(len(subscribers)),
         subscribed_text=commas(len(sub_list)),
-        hub_subscribe_url=flask.url_for('hub_subscribe', hub=widget.hub.name),
-        hub_unsubscribe_url=flask.url_for('hub_unsubscribe', hub=widget.hub.name),
+        hub_subscribe_url=flask.url_for(
+            'hub_subscribe', hub=widget.hub.name),
+        hub_unsubscribe_url=flask.url_for(
+            'hub_unsubscribe', hub=widget.hub.name),
     )
 
 
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 282a400..f40e453 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -40,6 +40,7 @@ paths = fmn.lib.load_rules(root='fmn.rules')
 template = templating.environment.get_template('templates/feed.html')
 position = 'left'
 
+
 def apply_markup(match):
     markup = match['subtitle']
     for username in match['usernames']:
@@ -62,12 +63,13 @@ def apply_markup(match):
 
     return markup
 
+
 @argument(name="username",
           default=None,
           validator=validators.username,
           help="A FAS username.")
 @argument(name="fmn_context",
-          default="irc", # TODO - Make this 'hubs', or...
+          default="irc",  # TODO - Make this 'hubs', or...
           validator=validators.fmn_context,
           help="A FMN context.")
 def data(session, widget, username, fmn_context):
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
index 2bd6c87..295c76b 100755
--- a/hubs/widgets/githubissues.py
+++ b/hubs/widgets/githubissues.py
@@ -15,32 +15,33 @@ position = 'right'
           validator=validators.github_organization,
           help="Github Organization or username")
 def data(session, widget, display_number, org, repo):
-  url = '/'.join(['https://api.github.com/repos',org,repo,"issues"])
-  issue_response = requests.get(url)
-  data = issue_response.json()
-  all_issues = list()
-  for i in range(0,10):
-    issue_details=dict()
-    issue_num=data[i]['number']
-    issue_title=data[i]['title']
-    issue_openedby=data[i]['user']['login']
-    if(data[i]['assignee']!=None):
-      issue_assignee=data[i]['assignee']['login']
-    else:
-      issue_assignee=data[i]['assignee']
-    issue_details['num']=issue_num
-    issue_details['title']=issue_title
-    issue_details['openedby']=issue_openedby
-    issue_details['assignee']=issue_assignee
-    all_issues.append(issue_details)
-  all_issues.reverse()
-  return dict(
-    org=org,
-    repo=repo,
-    all_issues=all_issues,
-    display_number=display_number,
-  )
+    url = '/'.join(['https://api.github.com/repos', org, repo, "issues"])
+    issue_response = requests.get(url)
+    data = issue_response.json()
+    all_issues = list()
+    for i in range(0, 10):
+        issue_details = dict()
+        issue_num = data[i]['number']
+        issue_title = data[i]['title']
+        issue_openedby = data[i]['user']['login']
+        if(data[i]['assignee'] is not None):
+            issue_assignee = data[i]['assignee']['login']
+        else:
+            issue_assignee = data[i]['assignee']
+        issue_details['num'] = issue_num
+        issue_details['title'] = issue_title
+        issue_details['openedby'] = issue_openedby
+        issue_details['assignee'] = issue_assignee
+        all_issues.append(issue_details)
+    all_issues.reverse()
+    return dict(
+        org=org,
+        repo=repo,
+        all_issues=all_issues,
+        display_number=display_number,
+    )
+
 
 @hint()
 def should_invalidate(message, session, widget):
-  raise NotImplementedError
+    raise NotImplementedError
diff --git a/hubs/widgets/linechart.py b/hubs/widgets/linechart.py
index 2c5562f..f12ef8f 100755
--- a/hubs/widgets/linechart.py
+++ b/hubs/widgets/linechart.py
@@ -25,8 +25,10 @@ def data(session, widget, username):
                   'Bodhi', 'faf', 'kerneltest', 'github', 'Trac', 'meetbot',
                   'planet', 'fedocal', 'hotness']
     categories = [c.lower() for c in categories]
-    categories = "&".join(['category=%s' % c for c in categories ])
-    url = "https://apps.fedoraproject.org/datagrepper/charts/stackedline?delta=604800&N=12&style=clean&height=300&fill=true&user={username}&split_on=categories"
+    categories = "&".join(['category=%s' % c for c in categories])
+    url = "https://apps.fedoraproject.org/datagrepper/charts/stackedline" \
+          "?delta=604800&N=12&style=clean&height=300&fill=true"\
+          "&user={username}&split_on=categories"
     url = url + "&" + categories
     url = url.format(username=username)
     return dict(url=url)
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index 3975253..118f8d5 100755
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -29,29 +29,29 @@ def data(session, widget, repo):
 
         issue_assignee = None
         if issue['assignee']:
-            issue_assignee=issue['assignee']['name']
+            issue_assignee = issue['assignee']['name']
 
         issue_project_user = None
         if 'project' in issue:
-          issue_project_name = issue['project']['name']
-          if issue['project']['parent']:
-            issue_project_user = issue['project']['user']['username']
-        else:
-            if '/' in repo:
-                issue_project_name, issue_project_user = repo.split('/', 1)
+            issue_project_name = issue['project']['name']
+            if issue['project']['parent']:
+                issue_project_user = issue['project']['user']['username']
             else:
-              issue_project_name = repo
+                if '/' in repo:
+                    issue_project_name, issue_project_user = repo.split('/', 1)
+                else:
+                    issue_project_name = repo
 
         all_issues.append(
-          dict(
-            issue_project_name=issue_project_name,
-            issue_project_user=issue_project_user,
-            issue_id=issue['id'],
-            issue_title=issue['title'][:45],
-            issue_title_full=issue['title'],
-            issue_openedby=issue['user']['name'],
-            issue_assignee=issue_assignee,
-          )
+            dict(
+                issue_project_name=issue_project_name,
+                issue_project_user=issue_project_user,
+                issue_id=issue['id'],
+                issue_title=issue['title'][:45],
+                issue_title_full=issue['title'],
+                issue_openedby=issue['user']['name'],
+                issue_assignee=issue_assignee,
+            )
         )
 
     all_issues.reverse()
@@ -65,4 +65,4 @@ def data(session, widget, repo):
 
 @hint()
 def should_invalidate(message, session, widget):
-   raise NotImplementedError
+    raise NotImplementedError
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 319e287..55c90db 100755
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -33,7 +33,8 @@ def data(session, widget):
         hub_unstar_url=flask.url_for('hub_unstar', hub=widget.hub.name),
         hub_star_url=flask.url_for('hub_star', hub=widget.hub.name),
         hub_subscribe_url=flask.url_for('hub_subscribe', hub=widget.hub.name),
-        hub_unsubscribe_url=flask.url_for('hub_unsubscribe', hub=widget.hub.name),
+        hub_unsubscribe_url=flask.url_for(
+            'hub_unsubscribe', hub=widget.hub.name),
     )
 
 
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 8538999..581bd70 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -11,7 +11,8 @@ from hubs.widgets.chrome import panel
 # If 'pending_acls' is empty, then don't render any chrome.
 chrome = panel('Pending ACL Requests', key='pending_acls')
 # TODO -- add approve/deny buttons or just link through to pkgdb
-template = templating.environment.get_template('templates/workflow/pendingacls.html')
+template = templating.environment.get_template(
+    'templates/workflow/pendingacls.html')
 position = 'right'
 
 
diff --git a/populate-from-fas.py b/populate-from-fas.py
index 754de7f..8c3531b 100755
--- a/populate-from-fas.py
+++ b/populate-from-fas.py
@@ -35,12 +35,13 @@ suffix_blacklist = [
 
 
 for letter in reversed(sorted(list(set(string.letters.lower())))):
-    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
+    session = hubs.models.init(
+        fedmsg_config['hubs.sqlalchemy.uri'], True, True)
     print "Querying FAS for the %r users.. hang on." % letter
     request = fasclient.send_request('/user/list',
-                                    req_params={'search': '%s*' % letter},
-                                    auth=True,
-                                    timeout=500)
+                                     req_params={'search': '%s*' % letter},
+                                     auth=True,
+                                     timeout=500)
     users = request['people']
 
     for user in users:
@@ -54,7 +55,8 @@ for letter in reversed(sorted(list(set(string.letters.lower())))):
     session.commit()
 
     # Go back now and set up the groups...
-    session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
+    session = hubs.models.init(
+        fedmsg_config['hubs.sqlalchemy.uri'], True, True)
     for user in users:
         hubs_user = hubs.models.User.by_username(session, user['username'])
 
@@ -86,12 +88,11 @@ for letter in reversed(sorted(list(set(string.letters.lower())))):
                 mailing_list_url=membership['mailing_list_url'],
             )
 
-
-            if not hubs_user in hub.subscribers:
+            if hubs_user not in hub.subscribers:
                 hub.subscribe(session, hubs_user, role='subscriber')
-            if not hubs_user in hub.members:
+            if hubs_user not in hub.members:
                 hub.subscribe(session, hubs_user, role='member')
-            if not hubs_user in hub.owners:
+            if hubs_user not in hub.owners:
                 if role['role_type'] in [u'administrator', u'sponsor']:
                     hub.subscribe(session, hubs_user, role='owner')
 
diff --git a/populate.py b/populate.py
index 5e89881..9762426 100755
--- a/populate.py
+++ b/populate.py
@@ -23,7 +23,8 @@ for username in users:
 session.commit()
 
 ############## Internationalizationteam
-hub = hubs.models.Hub(name='i18n', summary='The Internationalization Team', archived=True)
+hub = hubs.models.Hub(
+    name='i18n', summary='The Internationalization Team', archived=True)
 session.add(hub)
 
 widget = hubs.models.Widget(plugin='stats', index=0)

From 7848912af62b054b33b47d2f4c038a2f4a09a9e7 Mon Sep 17 00:00:00 2001
From: Luke Macken <lmacken@redhat.com>
Date: Jun 04 2016 22:48:12 +0000
Subject: [PATCH 484/1001] bugzilla: Fix broken links due to whitespace, and link to fedora-packages instead of the pkgdb


---

diff --git a/hubs/widgets/templates/bugzilla.html b/hubs/widgets/templates/bugzilla.html
index 21eceb7..86891ec 100644
--- a/hubs/widgets/templates/bugzilla.html
+++ b/hubs/widgets/templates/bugzilla.html
@@ -2,16 +2,13 @@
   {% for item in issues %}
     <li class="media">
       <div class="media-left">
-        <a href="https://bugzilla.redhat.com/show_bug.cgi?id=
-        {{ item['id'] }}" target="_blank">
+        <a href="https://bugzilla.redhat.com/show_bug.cgi?id={{ item['id'] }}" target="_blank">
         <span class="label label-default">#{{ item['id'] }}</span>
         </a>
       </div>
       <div class="media-body">
         <h4 class="media-heading">
-          <a href="https://admin.fedoraproject.org/pkgdb/
-          package/rpms/{{ item['pkg_name'] }}" target=
-          "_blank">{{ item['pkg_name'] }}</a>:
+          <a href="https://apps.fedoraproject.org/packages/{{ item['pkg_name'] }}" target="_blank">{{ item['pkg_name'] }}</a>:
           {{ item['title'] }}
         </h4>
       </div>

From 2e695368f86e770240a93b7c6d0c6294f0f71e30 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jun 07 2016 15:09:06 +0000
Subject: [PATCH 485/1001] Add checks for None in meetings widget


There is some meetings data that has None for meeting_information and
meeting_location. Add checks that make sure the widget can load.

---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index e8fede6..04e0868 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -41,7 +41,7 @@ def next_meeting(meetings):
         # their local with moment.js.
         meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
         meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
-        meeting['location'] = meeting['meeting_location']
+        meeting['location'] = meeting['meeting_location'] or ''
         if '@' in meeting['location']:
             meeting['location'] = '#' + meeting['location'].split('@')[0]
         if stop_dt - start_dt >= datetime.timedelta(hours=24) :
@@ -71,8 +71,9 @@ def data(session, widget, calendar):
 
     tmp = collections.defaultdict(list)
     for meeting in response['meetings']:
-        meeting['meeting_information_html'] = utils.markup(
-            meeting['meeting_information'])
+        if meeting.get('meeting_information_html'):
+            meeting['meeting_information_html'] = utils.markup(
+                meeting['meeting_information'])
         tmp[meeting['meeting_name']].append(meeting)
 
     meetings = {}
diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index e863b58..7725729 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -26,6 +26,7 @@
       </a>
     </div>
   </div>
+  {% if next.get('meeting_information_html')  %}
   <div class="row">
       <div class="col-md-12 meeting-info">
         {{ next.meeting_information_html[:150] }}
@@ -36,6 +37,7 @@
         {% endif %}
       </div>
   </div>
+  {% endif  %}
 </div>
 {% if meetings | length > 1 %} <hr> {% endif %}
 {% endfor %}

From b7092f067db35e328033d61344723a50d4b387fe Mon Sep 17 00:00:00 2001
From: skrzepto <skrzepto@gmail.com>
Date: Jun 08 2016 12:22:58 +0000
Subject: [PATCH 486/1001] fixing unittests. the widget key in the data variable was causing errors to convert into json so i popped it off and made some minor string adjustments to pass the tests


---

diff --git a/hubs/models.py b/hubs/models.py
index 059ad28..8dee5ff 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -315,6 +315,7 @@ class Widget(BASE):
     def __json__(self, session):
         module = hubs.widgets.registry[self.plugin]
         data = module.data(session, self, **self.config)
+        data.pop('widget', None)
         return {
             'id': self.idx,
             # TODO -- use flask.url_for to get the url for this widget
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index 675dc6a..6890f7b 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -13,6 +13,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
-            u'source_url': u'/source/about/',
+            u'edit_url': u'/ralph/51/edit',
+            u'source_url': u'/source/about',
             u'text': u'Testing.',
         })
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index 39bd99e..8cd43e4 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -13,9 +13,10 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
+            u'edit_url': u'/ralph/33/edit',
             u'fedmsgs': 83854,
             u'fedmsgs_text': u'83,854',
-            u'source_url': u'/source/fedmsgstats/',
+            u'source_url': u'/source/fedmsgstats',
             u'subscribers': [],
             u'subscribed_to': [],
             u'subscribers_text': u'0',

From 53041da5cf11f12fe354041075f19cdba2064146 Mon Sep 17 00:00:00 2001
From: skrzepto <skrzepto@gmail.com>
Date: Jun 09 2016 18:47:41 +0000
Subject: [PATCH 487/1001] fixing the delete-user script by cascading the delete to other tables


---

diff --git a/hubs/models.py b/hubs/models.py
index 8dee5ff..742b113 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -107,7 +107,7 @@ class Association(BASE):
                         primary_key=True)
     role = sa.Column(sa.Enum(*roles), primary_key=True)
 
-    user = relation("User", backref="associations")
+    user = relation("User", backref=backref('associations', cascade="all, delete-orphan"))
     hub = relation("Hub", backref="associations")
 
     @classmethod

From 284a1384b629ca0ce967347e6758362f831c0527 Mon Sep 17 00:00:00 2001
From: skrzepto <skrzepto@gmail.com>
Date: Jun 10 2016 14:12:51 +0000
Subject: [PATCH 488/1001] when a hub is deleted, delete the association and also all its widgets are deleted as well. assumption is that a widget has one parent


---

diff --git a/hubs/models.py b/hubs/models.py
index 742b113..1731076 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -108,7 +108,7 @@ class Association(BASE):
     role = sa.Column(sa.Enum(*roles), primary_key=True)
 
     user = relation("User", backref=backref('associations', cascade="all, delete-orphan"))
-    hub = relation("Hub", backref="associations")
+    hub = relation("Hub", backref=backref('associations', cascade="all, delete-orphan"))
 
     @classmethod
     def get(cls, session, hub, user, role):
@@ -124,7 +124,8 @@ class Hub(BASE):
     name = sa.Column(sa.String(50), primary_key=True)
     summary = sa.Column(sa.String(128))
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
-    widgets = relation('Widget', backref=backref('hub'))
+    widgets = relation('Widget', cascade='all,delete-orphan', single_parent=True,
+                       backref=backref('hub', cascade='all'))
     left_width = sa.Column(sa.Integer, nullable=False, default=8)
     archived = sa.Column(sa.Boolean, default=False)
     user_hub = sa.Column(sa.Boolean, default=False)

From 7d6632e95220db8302e6910fad16ddacdd576f4a Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jun 14 2016 16:04:47 +0000
Subject: [PATCH 489/1001] pushing my work on unittesting up


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index e69de29..8dbca6c 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -0,0 +1,141 @@
+from contextlib import contextmanager
+import json
+from datetime import datetime, timedelta
+
+import munch
+from os.path import dirname
+import unittest
+
+import requests
+import vcr
+
+import hubs.models
+
+cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
+
+
+class APPTest(unittest.TestCase):
+    def setUp(self):
+        filename = cassette_dir + self.id()
+        self.vcr = vcr.use_cassette(filename, record_mode='new_episodes')
+        self.vcr.__enter__()
+
+        import hubs.app
+        hubs.app.fedmsg_config = {
+            'hubs.sqlalchemy.uri': 'sqlite://',  # in memory
+        }
+        hubs.app.session = hubs.models.init(
+            hubs.app.fedmsg_config['hubs.sqlalchemy.uri'],
+            create=True,
+        )
+        self.app = hubs.app.app.test_client()
+        self.app.testing = True
+        self.session = hubs.app.session
+        self.populate()
+
+    def tearDown(self):
+        self.vcr.__exit__()
+        self.session.remove()
+
+    def populate(self):
+        for user in ['devyani7', 'dhrish', 'shalini', 'ralph', 'decause']:
+            openid = '%s.id.fedoraproject.org' % user
+            fullname = user.title()
+            hubs.models.User.get_or_create(
+                hubs.app.session, openid=openid, fullname=fullname)
+
+        hubs.app.session.flush()
+
+        hub = hubs.models.Hub.by_name(hubs.app.session, 'ralph')
+        widget = hubs.models.Widget(
+            plugin='about',
+            index=500,
+            _config=json.dumps({"text": "Testing."}),
+        )
+        hub.widgets.append(widget)
+
+        for team in ['i18n', 'infra', 'old']:
+            hub = hubs.models.Hub(name=team, summary="the %s team" % team)
+            if hub.name == 'old':
+                hub.last_refreshed = datetime.utcnow() - timedelta(days=100)
+                hub.last_updated = datetime.utcnow() - timedelta(days=200)
+
+            hubs.app.session.add(hub)
+            widget = hubs.models.Widget(plugin='meetings', index=11,
+                                        _config=json.dumps({'calendar': team}))
+            hub.widgets.append(widget)
+        hubs.app.session.commit()
+
+    # TODO - test that it is in the registry
+    # TODO - test that it has all the things it needs
+
+    def widget_instance(self, hubname, plugin):
+        hub = hubs.models.Hub.by_name(self.session, hubname)
+        if not hub:
+            raise ValueError("No such hub %r" % hubname)
+        for widget in hub.widgets:
+            if widget.plugin == plugin:
+                return widget
+        raise KeyError("No such widget found for %s/%s" % (hubname, plugin))
+
+    @staticmethod
+    def get_fedmsg(idx):
+        url = 'https://apps.fedoraproject.org/datagrepper/id'
+        response = requests.get(url, params=dict(id=idx))
+        if not bool(response):
+            raise IOError("Failed to talk to %r %r" % (response.url, response))
+        return response.json()
+
+
+@contextmanager
+def auth_set(APP, auth):
+    """ Set the provided user as fas_user in the provided application."""
+
+    # Hack used to remove the before_request function set by
+    # flask.ext.fas_openid.FAS which otherwise kills our effort to set a
+    # flask.g.fas_user.
+    from flask import appcontext_pushed, g
+    APP.before_request_funcs[None] = []
+
+    def handler(sender, **kwargs):
+        g.auth = auth
+        if not auth:
+            munch.Munch(logged_in=False)
+
+    with appcontext_pushed.connected_to(handler, APP):
+        yield
+
+class FakeUser(object):
+    """ Fake user used to test the fedocallib library. """
+
+    def __init__(self, username='username'):
+        """ Constructor.
+        :arg groups: list of the groups in which this fake user is
+            supposed to be.
+        """
+        self.username = username
+        self.openid = username + 'id.fedoraproject.org'
+        self.booksmarks = []
+
+    def __getitem__(self, key):
+        return self.dic[key]
+
+
+class FakeAuthorization(object):
+    """ Fake user used to test the fedocallib library. """
+
+    def __init__(self, username='username'):
+        """ Constructor.
+        :arg groups: list of the groups in which this fake user is
+            supposed to be.
+        """
+        self.logged_in = True
+        self.fullname = 'fullname: ' + username
+        self.email = 'email: ' + username
+        self.openid = username + 'id.fedoraproject.org'
+        self.user = FakeUser(username)
+        self.avatar = 'avatar_src_url'
+        self.nickname = username
+
+    def __getitem__(self, key):
+        return self.dic[key]
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
new file mode 100644
index 0000000..bf79d06
--- /dev/null
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -0,0 +1,144 @@
+import unittest
+from urlparse import urlparse
+
+from flask import json
+from os.path import dirname
+import vcr
+
+import hubs
+from hubs import tests
+from hubs.app import app
+
+import hubs.models
+
+import fedmsg.config
+
+cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
+
+
+class HubsAPITest(hubs.tests.APPTest):
+    @unittest.skip("Can't seem to get redirected to the login in these tests")
+    def test_index_logged_out(self):
+        result = self.app.get('/', follow_redirects=True)
+        # its trying to redirect to login id.fedoraproject.org/openid
+        # assert the status code of the response
+        self.assertEqual(result.status_code, 200)
+
+    def test_index_logged_in(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/', follow_redirects=True)
+            # its trying to redirect to login id.fedoraproject.org/openid
+            # assert the status code of the response
+            self.assertEqual(result.status_code, 200)
+            self.assertFalse('Not logged in.  Click to <a href="/login/fedora">login</a>' in result.data)
+
+    def test_hub_logged_out(self):
+        with tests.auth_set(app, None):
+            # for some reason def check_auth() is not running and i need to set it to none so it won't crash
+            result = self.app.get('/ralph', follow_redirects=True)
+            # assert the status code of the response
+            self.assertEqual(result.status_code, 200)
+            self.assertTrue('Not logged in.  Click to <a href="/login/fedora">login</a>' in result.data)
+
+    @unittest.skip("Can't seem to get redirected to the login in these tests")
+    def test_groups_logged_out(self):
+        with tests.auth_set(app, None):
+            # for some reason def check_auth() is not running and i need to set it to none so it won't crash
+            result = self.app.get('/groups', follow_redirects=True)
+            # assert the status code of the response
+            self.assertEqual(result.status_code, 200)
+            # this will redirect to fedora.login which unittests can't handle atm
+            pass
+
+    def test_groups_logged_in(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/groups', follow_redirects=True)
+            # assert the status code of the response
+            self.assertEqual(result.status_code, 200)
+            self.assertTrue("ZOMG -  is the Hub Of The Month!" in result.data)
+
+    def test_hub_logged_in(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/ralph', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            self.assertFalse('Not logged in.  Click to <a href="/login/fedora">login</a>' in result.data)
+
+    def test_hub_json(self):
+        with tests.auth_set(app, None):
+            # for some reason def check_auth() is not running and i need to set it to none so it won't crash
+            result = self.app.get('/ralph/json', follow_redirects=True)
+            # assert the status code of the response
+            self.assertEqual(result.status_code, 200)
+            data = {
+                "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=312&d=retro",
+                "left_width": 8,
+                "members": ["ralph"],
+                "name": "ralph",
+                "owners": ["ralph"],
+                "subscribers": [],
+                "summary": "Ralph",
+                "widgets": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 51]
+            }
+            self.assertDictEqual(data, json.loads(result.data))
+
+    @unittest.skip("Authorization layer not present yet")
+    def test_hub_edit_get_logged_out(self):
+        # FAILING: Authorization layer not present yet
+        with tests.auth_set(app, None):
+            result = self.app.get('/ralph/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)  # failing right
+            # We do not have the authorization layer in place yet
+
+    @unittest.skip("Authorization layer not present yet")
+    def test_hub_edit_get_logged_in_not_owner(self):
+        # FAILING: Authorization layer not present yet
+        user = tests.FakeAuthorization('not_ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/ralph/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)  # failing right
+            # We do not have the authorization layer in place yet
+
+    def test_hub_edit_get_logged_in_owner(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/ralph/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            # We do not have the authorization layer in place yet so everyone can edit
+
+    @unittest.skip("Authorization layer not present yet")
+    def test_hub_edit_post_logged_out(self):
+        # FAILING: Authorization layer not present yet
+        with tests.auth_set(app, None):
+            result = self.app.post('/ralph/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)  # failing right
+            # We do not have the authorization layer in place yet
+
+    @unittest.skip("Authorization layer not present yet")
+    def test_hub_edit_post_logged_in_not_owner(self):
+        # FAILING: Authorization layer not present yet
+        user = tests.FakeAuthorization('not_ralph')
+        with tests.auth_set(app, user):
+            result = self.app.post('/ralph/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)  # failing right
+            # We do not have the authorization layer in place yet
+
+    # WIP: commenting out so I can push this updates to branch so others can contribute
+    '''
+    def test_hub_edit_post_logged_in_owner_no_data(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.post('/ralph/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            assert 'Invalid widget identifiers submitted' in result.data
+            assert 'Invalid indexes submitted' in result.data
+            assert 'The number of indexes and the number of widgets ' \
+                   'are not of the same length' in result.data
+            assert 'Invalid widget identifiers submitted' in result.data
+            assert 'Invalid indexes submitted' in result.data
+    '''
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index 6890f7b..38bddee 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -1,5 +1,7 @@
 import json
 
+from nose.tools import assert_dict_equal
+
 import hubs.tests.test_widgets
 
 
@@ -17,3 +19,32 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
             u'source_url': u'/source/about',
             u'text': u'Testing.',
         })
+
+    def test_should_invalidate_wrong_topic(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        msg = {'topic': 'hubs.widget.update.WRONG.TOPIC', 'msg': {'widget': {'id': widget.idx}}}
+        module = hubs.widgets.registry[widget.plugin]
+        result = module.should_invalidate(msg, self.session, widget)
+        assert not result
+
+    def test_should_invalidate_wrong_widget_id(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx+1}}}
+        module = hubs.widgets.registry[widget.plugin]
+        result = module.should_invalidate(msg, self.session, widget)
+        assert not result
+
+    def test_should_invalidate_good_match(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx}}}
+        module = hubs.widgets.registry[widget.plugin]
+        result = module.should_invalidate(msg, self.session, widget)
+        assert result
+
+    '''
+    def test_data(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        module = hubs.widgets.registry[widget.plugin]
+        result = module.data(self.session, widget, 'I love oss.')
+        assert_dict_equal({'text': 'I love oss.'}, result)
+    '''
\ No newline at end of file
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index 4f668b1..7edd96e 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -1,5 +1,6 @@
 import json
 
+from mock import patch, MagicMock
 import hubs.tests.test_widgets
 
 
@@ -16,21 +17,68 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
 
     def test_should_invalidate_wrong_topic(self):
         widget = self.widget_instance('ralph', self.plugin)
-        msg = self.get_fedmsg('2016-ebb84660-59e9-4e68-af8f-4e6f49348b88')
+        # msg = self.get_fedmsg('2016-ebb84660-59e9-4e68-af8f-4e6f49348b88')
+        msg = {'topic': 'hubs.widget.update.WRONG.TOPIC'}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
         assert not result
 
     def test_should_invalidate_wrong_user(self):
         widget = self.widget_instance('ralph', self.plugin)
-        msg = self.get_fedmsg('2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f')
+        # msg = self.get_fedmsg('2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f')
+        msg = {'topic': 'fedbadges.badge.award', 'msg': {'user': {'username': 'not_ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
         assert not result
 
-    def test_should_invalidate_good_match(self):
+    def test_should_invalidate_good_match_fedbadges(self):
         widget = self.widget_instance('ralph', self.plugin)
-        msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
+        # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
+        msg = {'topic': 'fedbadges.badge.award', 'msg': {'user': {'username': 'ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
         assert result
+
+    def test_should_invalidate_good_match_hubswidget(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
+        msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx + 1}}}
+        module = hubs.widgets.registry[widget.plugin]
+        result = module.should_invalidate(msg, self.session, widget)
+        assert result
+    '''
+    @patch('requests.get')
+    @patch('hubs.widgets.base.cache.get_or_create')
+    def test_data_good(self, cache_mock, requests_mock):
+        requests_mock.return_value = self.mock_response()
+        cache_mock.return_value = None
+        widget = self.widget_instance('ralph', self.plugin)
+        module = hubs.widgets.registry[widget.plugin]
+        result = module.data(self.session, widget, 'ralph')
+        assert result
+    '''
+    @staticmethod
+    def mock_response():
+        test_data_simple = '''{
+            "percent_earned": 47.05882352941176,
+            "assertions": [{
+                "description": "You attended Flock 2014, the Fedora Contributor Conference",
+                "tags": "flock,event,",
+                "issued": 1375373082.0,
+                "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+                "first_awarded": 1375373082.0,
+                "first_awarded_person": "ralph",
+                "last_awarded_person": "gnokii",
+                "last_awarded": 1386188828.0,
+                "percent_earned": 0.404551201011378,
+                "id": "flock-2013-attendee",
+                "times_awarded": 80,
+                "name": "Flock 2013 Attendee"
+            }],
+            "user": "ralph",
+            "avatar": ""
+        }'''
+
+        mock = MagicMock()
+        mock.json.return_value = json.loads(test_data_simple)
+        return mock
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 90656fd..bafb6a3 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -20,4 +20,4 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/' % (team, widget.idx))
         assert response.status_code == 200, response.status_code
-        assert 'The i18n meeting is in' in response.data, response.data
+        assert 'The i18n meeting is ' in response.data, response.data
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index c1ff1f6..7023139 100755
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -21,6 +21,6 @@ def data(session, widget, text):
 def should_invalidate(message, session, widget):
     if not message['topic'].endswith('hubs.widget.update'):
         return False
-    if message['msg']['widget']['id'] != widget.id:
+    if message['msg']['widget']['id'] != widget.idx:
         return False
     return True
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index c5a18d0..abf4b15 100755
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -30,7 +30,7 @@ def data(session, widget, username):
 @hint(topics=[_('hubs.widget.update'), _('fedbadges.badge.award')])
 def should_invalidate(message, session, widget):
     if message['topic'].endswith('hubs.widget.update'):
-        if message['msg']['widget']['id'] != widget.id:
+        if message['msg']['widget']['id'] != widget.idx:
             return True
 
     if message['topic'].endswith('fedbadges.badge.award'):

From 25e67a6787237e97fef12e6428089cf75ae852c3 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jun 14 2016 16:16:43 +0000
Subject: [PATCH 490/1001] Add fedmsg/markup route, and api tests


---

diff --git a/hubs/app.py b/hubs/app.py
index fe661ab..df33459 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,11 +1,15 @@
 import datetime
 import functools
+import json
 import logging
 import os
+import uuid
 
 import flask
 import flask.json
+import fmn.lib
 import munch
+import pygments.formatters
 import six
 
 from flask.ext.openid import OpenID
@@ -16,6 +20,10 @@ import hubs.widgets
 import datanommer.models
 
 from hubs.utils import username2avatar
+from hubs.widgets.feed import (
+    apply_markup, rehydrate_preference,
+    get_remote_preference
+)
 
 app = flask.Flask(__name__)
 
@@ -43,6 +51,7 @@ import fedmsg.config
 import fedmsg.meta
 fedmsg_config = fedmsg.config.load_config()
 fedmsg.meta.make_processors(**fedmsg_config)
+PATHS = fmn.lib.load_rules(root='fmn.rules')
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 datanommer.models.init(fedmsg_config['datanommer.sqlalchemy.uri'])
@@ -628,3 +637,50 @@ def hub_leave(hub):
         return flask.abort(400)
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/fedmsg/markup', methods=['GET'])
+def markup_fedmsg():
+    try:
+        data = flask.request.args['message']
+        plugin = flask.request.args['plugin']
+    except KeyError:
+        return flask.abort(400)
+    widget = hubs.models.Widget.by_plugin(session, plugin)
+    if not widget:
+        return flask.abort(400)
+    context = widget.config.get('fmn_context')
+    messages = []
+    message = json.loads(data)
+    try:
+        nickname = flask.g.auth.nickname
+    except AttributeError:      # Not logged in
+        return flask.abort(403)
+    preference = get_remote_preference(nickname, context)
+    if preference:
+        try:
+            preference = rehydrate_preference(preference)
+        except ImportError:
+            pass
+    recipients = fmn.lib.recipients(
+        [preference], message, PATHS, fedmsg_config)
+    if recipients:
+        messages.append(message)
+    matches = fedmsg.meta.conglomerate(messages, lexers=True, **fedmsg_config)
+    for match in matches:
+        match['markup'] = apply_markup(match)
+        for _, constituent in match['msg_ids'].items():
+            constituent['markup'] = apply_markup(constituent)
+            if constituent['long_form'] != constituent['subtitle']:
+                if constituent.get('lexer'):
+                    constituent['long_form'] = pygments.highlight(
+                        constituent['long_form'],
+                        constituent['lexer'],
+                        pygments.formatters.HtmlFormatter(style='monokai'),
+                    )
+                else:
+                    markup = u"<h5>{long_form}</h5>".format(**constituent)
+                    constituent['long_form'] = markup
+        # And tack on a unique identifier for each top level entry.
+        match['dom_id'] = six.text_type(uuid.uuid4())
+    return flask.jsonify(matches)
diff --git a/hubs/models.py b/hubs/models.py
index 1731076..32580a6 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -303,6 +303,10 @@ class Widget(BASE):
     def by_idx(cls, session, idx):
         return session.query(cls).filter_by(idx=idx).first()
 
+    @classmethod
+    def by_plugin(cls, session, plugin):
+        return session.query(cls).filter_by(plugin=plugin).first()
+
     get = by_idx
 
     @property
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 8dbca6c..7c9da28 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -88,6 +88,22 @@ class APPTest(unittest.TestCase):
 
 
 @contextmanager
+def user_set(APP, user):
+    """ Set the provided user as fas_user in the provided application."""
+    # Hack used to remove the before_request function set by
+    # flask.ext.fas_openid.FAS which otherwise kills our effort to set a
+    # flask.g.fas_user.
+    from flask import appcontext_pushed, g
+
+    def handler(sender, **kwargs):
+        g.fas_user = user
+        g.fas_session_id = b'123'
+
+    with appcontext_pushed.connected_to(handler, APP):
+        yield
+
+
+@contextmanager
 def auth_set(APP, auth):
     """ Set the provided user as fas_user in the provided application."""
 
@@ -105,6 +121,7 @@ def auth_set(APP, auth):
     with appcontext_pushed.connected_to(handler, APP):
         yield
 
+
 class FakeUser(object):
     """ Fake user used to test the fedocallib library. """
 
diff --git a/hubs/tests/test_api/test_fedmsg.py b/hubs/tests/test_api/test_fedmsg.py
new file mode 100644
index 0000000..c708073
--- /dev/null
+++ b/hubs/tests/test_api/test_fedmsg.py
@@ -0,0 +1,330 @@
+import json
+
+import hubs.tests
+import hubs.models
+
+
+class TestFeed(hubs.tests.APPTest):
+    # TODO this test relies on a specific filter for the atelic user
+    # It would be better to fake preferences on FAS
+    user = hubs.tests.FakeAuthorization('atelic')
+    message_involved = {
+        'timestamp': 1465567413.0,
+        'topic': 'io.pagure.prod.pagure.issue.new',
+        'msg_id': '2016-0490127f-473f-4d01-ASDF-a864a56dc302',
+        'msg': {
+            'action': 'created',
+            'comment': {
+                'body':
+                'hm, there is something odd, the stackage page is being inconsistent, one time the version number for LTS is linked, one time it isn\'t.\r\n\r\nIt\'s as if there are 2 servers running 2 different versions of the application',
+                'created_at': '2016-06-10T14:03:31Z',
+                'html_url':
+                'https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438',
+                'id': 225190438,
+                'updated_at': '2016-06-10T14:03:31Z',
+                'url':
+                'https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438',
+                'user': {
+                    'gravatar_id': '',
+                    'html_url': 'https://github.com/pypingou',
+                    'id': 1240038,
+                    'login': 'pypingou',
+                    'site_admin': False,
+                    'type': 'User',
+                    'url': 'https://api.github.com/users/pypingou'
+                }
+            },
+            'fas_usernames': {
+                'fedora-infra': 'github_org_fedora-infra',
+                'pypingou': 'pingou'
+            },
+            'issue': {
+                'assignee': None,
+                'body':
+                '@juhp it seems that the stackage backend is broken: https://release-monitoring.org/projects/updates/failed?name=&log=stackage want to look at it?',
+                'closed_at': '2016-04-29T14:53:10Z',
+                'comments': 8,
+                'created_at': '2016-04-15T16:15:57Z',
+                'html_url':
+                'https://github.com/fedora-infra/anitya/issues/283',
+                'id': 148703615,
+                'labels': [],
+                'locked': False,
+                'milestone': None,
+                'number': 283,
+                'state': 'closed',
+                'title': 'stackage backend broken',
+                'updated_at': '2016-06-10T14:03:31Z',
+                'url':
+                'https://api.github.com/repos/fedora-infra/anitya/issues/283',
+                'user': {
+                    'gravatar_id': '',
+                    'html_url': 'https://github.com/pypingou',
+                    'id': 1240038,
+                    'login': 'pypingou',
+                    'site_admin': False,
+                    'type': 'User',
+                    'url': 'https://api.github.com/users/pypingou'
+                }
+            },
+            'organization': {
+                'description': 'Fedora Infrastructure Team',
+                'id': 3316637,
+                'login': 'fedora-infra',
+                'url': 'https://api.github.com/orgs/fedora-infra'
+            },
+            'repository': {
+                'created_at': '2013-11-29T10:17:26Z',
+                'default_branch': 'master',
+                'description': 'A cross-distribution upstream release project',
+                'fork': False,
+                'forks': 33,
+                'forks_count': 33,
+                'full_name': 'fedora-infra/anitya',
+                'has_downloads': True,
+                'has_issues': True,
+                'has_pages': False,
+                'has_wiki': False,
+                'homepage': 'https://release-monitoring.org',
+                'html_url': 'https://github.com/fedora-infra/anitya',
+                'id': 14798348,
+                'language': 'Python',
+                'name': 'anitya',
+                'open_issues': 25,
+                'open_issues_count': 25,
+                'owner': {
+                    'gravatar_id': '',
+                    'html_url': 'https://github.com/fedora-infra',
+                    'id': 3316637,
+                    'login': 'fedora-infra',
+                    'site_admin': False,
+                    'type': 'Organization',
+                    'url': 'https://api.github.com/users/fedora-infra'
+                },
+                'private': False,
+                'pushed_at': '2016-06-05T18:16:15Z',
+                'size': 4364,
+                'stargazers_count': 56,
+                'updated_at': '2016-06-10T09:43:58Z',
+                'url': 'https://api.github.com/repos/fedora-infra/anitya',
+                'watchers': 56,
+                'watchers_count': 56
+            },
+            'sender': {
+                'gravatar_id': '',
+                'html_url': 'https://github.com/pypingou',
+                'id': 1240038,
+                'login': 'pypingou',
+                'site_admin': False,
+                'type': 'User',
+                'url': 'https://api.github.com/users/pypingou'
+            }
+        },
+        'arguments': {
+            'categories': [
+                'pagure'
+            ],
+            'contains': [],
+            'delta': 172800.0,
+            'end': 1465839365.0,
+            'grouped': False,
+            'meta': [],
+            'not_categories': [],
+            'not_packages': [],
+            'not_topics': [],
+            'not_users': [],
+            'order': 'desc',
+            'packages': [],
+            'page': 1,
+            'rows_per_page': 1,
+            'start': 1465666565.0,
+            'topics': [],
+            'users': []
+        },
+        'count': 1,
+        'pages': 225,
+        'total': 225
+    }
+    message_not_involved = {
+        'topic': 'org.fedoraproject.prod.github.issue.comment',
+        'i': 1,
+        'msg': {
+            'action': 'created',
+            'comment': {
+                'body':
+                'hm, there is something odd, the stackage page is being inconsistent, one time the version number for LTS is linked, one time it isn\'t.\r\n\r\nIt\'s as if there are 2 servers running 2 different versions of the application',
+                'created_at': '2016-06-10T14:03:31Z',
+                'html_url':
+                'https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438',
+                'id': 225190438,
+                'updated_at': '2016-06-10T14:03:31Z',
+                'url':
+                'https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438',
+                'user': {
+                    'gravatar_id': '',
+                    'html_url': 'https://github.com/pypingou',
+                    'id': 1240038,
+                    'login': 'pypingou',
+                    'site_admin': False,
+                    'type': 'User',
+                    'url': 'https://api.github.com/users/pypingou'
+                }
+            },
+            'fas_usernames': {
+                'fedora-infra': 'github_org_fedora-infra',
+                'pypingou': 'pingou'
+            },
+            'issue': {
+                'assignee': None,
+                'body':
+                '@juhp it seems that the stackage backend is broken: https://release-monitoring.org/projects/updates/failed?name=&log=stackage want to look at it?',
+                'closed_at': '2016-04-29T14:53:10Z',
+                'comments': 8,
+                'created_at': '2016-04-15T16:15:57Z',
+                'html_url':
+                'https://github.com/fedora-infra/anitya/issues/283',
+                'id': 148703615,
+                'labels': [],
+                'locked': False,
+                'milestone': None,
+                'number': 283,
+                'state': 'closed',
+                'title': 'stackage backend broken',
+                'updated_at': '2016-06-10T14:03:31Z',
+                'url':
+                'https://api.github.com/repos/fedora-infra/anitya/issues/283',
+                'user': {
+                    'gravatar_id': '',
+                    'html_url': 'https://github.com/pypingou',
+                    'id': 1240038,
+                    'login': 'pypingou',
+                    'site_admin': False,
+                    'type': 'User',
+                    'url': 'https://api.github.com/users/pypingou'
+                }
+            },
+            'organization': {
+                'description': 'Fedora Infrastructure Team',
+                'id': 3316637,
+                'login': 'fedora-infra',
+                'url': 'https://api.github.com/orgs/fedora-infra'
+            },
+            'repository': {
+                'created_at': '2013-11-29T10:17:26Z',
+                'default_branch': 'master',
+                'description':
+                'A cross-distribution upstream release monitoring project',
+                'fork': False,
+                'forks': 33,
+                'forks_count': 33,
+                'full_name': 'fedora-infra/anitya',
+                'has_downloads': True,
+                'has_issues': True,
+                'has_pages': False,
+                'has_wiki': False,
+                'homepage': 'https://release-monitoring.org',
+                'html_url': 'https://github.com/fedora-infra/anitya',
+                'id': 14798348,
+                'language': 'Python',
+                'name': 'anitya',
+                'open_issues': 25,
+                'open_issues_count': 25,
+                'owner': {
+                    'gravatar_id': '',
+                    'html_url': 'https://github.com/fedora-infra',
+                    'id': 3316637,
+                    'login': 'fedora-infra',
+                    'site_admin': False,
+                    'type': 'Organization',
+                    'url': 'https://api.github.com/users/fedora-infra'
+                },
+                'private': False,
+                'pushed_at': '2016-06-05T18:16:15Z',
+                'size': 4364,
+                'stargazers_count': 56,
+                'updated_at': '2016-06-10T09:43:58Z',
+                'url': 'https://api.github.com/repos/fedora-infra/anitya',
+                'watchers': 56,
+                'watchers_count': 56
+            },
+            'sender': {
+                'gravatar_id': '',
+                'html_url': 'https://github.com/pypingou',
+                'id': 1240038,
+                'login': 'pypingou',
+                'site_admin': False,
+                'type': 'User',
+                'url': 'https://api.github.com/users/pypingou'
+            }
+        },
+        'msg_id': '2016-0490127f-473f-4d01-8e3a-a864a56dc302',
+        'signature':
+        'MNpAVdrPW78dcSe94FOS+/6QFBYo/LkrV5ee9tQedkhurHY1BGpaFHlU5l8cNVEpB7rr/zhHgQ+V\nmE3zYPmW/aREgvUoQgz74TR5F6/nK4Q1cD97VkFgHCadxZC6kjXd4H3BahEYnD+erj1iaArcdZaI\nXyKLZUBJLYL4JiXlmec=\n',
+        'source_name': 'datanommer',
+        'source_version': '0.6.5',
+        'timestamp': 1465567413.0,
+        'topic': 'org.fedoraproject.prod.github.issue.comment'
+    }
+
+    plugin = 'feed'
+
+    def test_returns_400_when_no_message(self):
+        payload = {'plugin': 'feed'}
+        response = self.app.get('/api/fedmsg/markup', query_string=payload)
+        assert response.status_code == 400
+
+    def test_returns_400_when_no_plugin(self):
+        payload = {'message': json.dumps(self.message_involved)}
+        response = self.app.get('/api/fedmsg/markup', query_string=payload)
+        assert response.status_code == 400
+
+    def test_returns_400_when_bad_plugin_name(self):
+        payload = {
+            'message': json.dumps(self.message_involved),
+            'plugin': 'notarealplugin'
+        }
+        response = self.app.get('/api/fedmsg/markup', query_string=payload)
+        assert response.status_code == 400
+
+    def test_returns_403_when_not_logged_in(self):
+        payload = {
+            'message': json.dumps(self.message_involved),
+            'plugin': 'feed'
+        }
+        with hubs.tests.user_set(self.app, self.user):
+            response = self.app.get('/api/fedmsg/markup', query_string=payload)
+
+            assert response.status_code == 403
+
+    def test_returns_match_if_involved(self):
+        payload = {
+            'message': json.dumps(self.message_involved),
+            'plugin': 'feed'
+        }
+        with self.app.session_transaction() as sess:
+            sess['openid'] = 'atelic@fedoraproject.org'
+            sess['nickname'] = 'atelic'
+
+        with hubs.tests.user_set(self.app, self.user):
+            response = self.app.get('/api/fedmsg/markup', query_string=payload)
+
+            assert response.status_code == 200, response.status_code
+            data = json.loads(response.data)
+            self.assertTrue(data)
+            assert isinstance(data[0], dict)
+
+    def test_returns_no_match_if_not_involved(self):
+        payload = {
+            'message': json.dumps(self.message_not_involved),
+            'plugin': 'feed'
+        }
+        with self.app.session_transaction() as sess:
+            sess['openid'] = 'atelic@fedoraproject.org'
+            sess['nickname'] = 'atelic'
+
+        with hubs.tests.user_set(self.app, self.user):
+            response = self.app.get('/api/fedmsg/markup', query_string=payload)
+
+            assert response.status_code == 200, response.status_code
+            data = json.loads(response.data)
+            self.assertFalse(data)

From d4fcd3f05604b98fe20b20e74b6d3a375f871c76 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jun 16 2016 14:42:05 +0000
Subject: [PATCH 491/1001] Add tests for /api/hub/*


Still skipping tests that check logged out behavior until issues can be
worked out with testing redirecting

---

diff --git a/hubs/app.py b/hubs/app.py
index df33459..c283490 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -641,6 +641,12 @@ def hub_leave(hub):
 
 @app.route('/api/fedmsg/markup', methods=['GET'])
 def markup_fedmsg():
+    '''
+    This is a temporary endpoint to create a human-readable form of a message.
+    For now it serves as a development tool
+
+    This route will be removed once its functionality is integrated into FMN
+    '''
     try:
         data = flask.request.args['message']
         plugin = flask.request.args['plugin']
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 7c9da28..bafe0a1 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -88,28 +88,16 @@ class APPTest(unittest.TestCase):
 
 
 @contextmanager
-def user_set(APP, user):
-    """ Set the provided user as fas_user in the provided application."""
-    # Hack used to remove the before_request function set by
-    # flask.ext.fas_openid.FAS which otherwise kills our effort to set a
-    # flask.g.fas_user.
-    from flask import appcontext_pushed, g
-
-    def handler(sender, **kwargs):
-        g.fas_user = user
-        g.fas_session_id = b'123'
-
-    with appcontext_pushed.connected_to(handler, APP):
-        yield
-
-
-@contextmanager
 def auth_set(APP, auth):
-    """ Set the provided user as fas_user in the provided application."""
+    """
+    Set the provided user as g.auth in the provided application.
+    :param APP: A Flask instance. Cannot be a FlaskClient.
+    :param auth: A FakeAuthorization instance to set as g.auth.
+    """
 
     # Hack used to remove the before_request function set by
     # flask.ext.fas_openid.FAS which otherwise kills our effort to set a
-    # flask.g.fas_user.
+    # flask.g.auth.
     from flask import appcontext_pushed, g
     APP.before_request_funcs[None] = []
 
@@ -123,7 +111,7 @@ def auth_set(APP, auth):
 
 
 class FakeUser(object):
-    """ Fake user used to test the fedocallib library. """
+    """ Fake user to be attached to an Authorization. """
 
     def __init__(self, username='username'):
         """ Constructor.
@@ -131,7 +119,7 @@ class FakeUser(object):
             supposed to be.
         """
         self.username = username
-        self.openid = username + 'id.fedoraproject.org'
+        self.openid = username + '.id.fedoraproject.org'
         self.booksmarks = []
 
     def __getitem__(self, key):
@@ -139,7 +127,7 @@ class FakeUser(object):
 
 
 class FakeAuthorization(object):
-    """ Fake user used to test the fedocallib library. """
+    """ Fake Authorization used to set as flask.g.auth. """
 
     def __init__(self, username='username'):
         """ Constructor.
@@ -149,10 +137,11 @@ class FakeAuthorization(object):
         self.logged_in = True
         self.fullname = 'fullname: ' + username
         self.email = 'email: ' + username
-        self.openid = username + 'id.fedoraproject.org'
+        self.openid = username + '.id.fedoraproject.org'
         self.user = FakeUser(username)
         self.avatar = 'avatar_src_url'
         self.nickname = username
+        self.username = username
 
     def __getitem__(self, key):
         return self.dic[key]
diff --git a/hubs/tests/test_api/test_fedmsg.py b/hubs/tests/test_api/test_fedmsg.py
index c708073..ef3b6db 100644
--- a/hubs/tests/test_api/test_fedmsg.py
+++ b/hubs/tests/test_api/test_fedmsg.py
@@ -2,6 +2,7 @@ import json
 
 import hubs.tests
 import hubs.models
+from hubs.app import app
 
 
 class TestFeed(hubs.tests.APPTest):
@@ -271,12 +272,12 @@ class TestFeed(hubs.tests.APPTest):
     def test_returns_400_when_no_message(self):
         payload = {'plugin': 'feed'}
         response = self.app.get('/api/fedmsg/markup', query_string=payload)
-        assert response.status_code == 400
+        self.assertEqual(response.status_code, 400)
 
     def test_returns_400_when_no_plugin(self):
         payload = {'message': json.dumps(self.message_involved)}
         response = self.app.get('/api/fedmsg/markup', query_string=payload)
-        assert response.status_code == 400
+        self.assertEqual(response.status_code, 400)
 
     def test_returns_400_when_bad_plugin_name(self):
         payload = {
@@ -284,17 +285,16 @@ class TestFeed(hubs.tests.APPTest):
             'plugin': 'notarealplugin'
         }
         response = self.app.get('/api/fedmsg/markup', query_string=payload)
-        assert response.status_code == 400
+        self.assertEqual(response.status_code, 400)
 
     def test_returns_403_when_not_logged_in(self):
         payload = {
             'message': json.dumps(self.message_involved),
             'plugin': 'feed'
         }
-        with hubs.tests.user_set(self.app, self.user):
-            response = self.app.get('/api/fedmsg/markup', query_string=payload)
 
-            assert response.status_code == 403
+        response = self.app.get('/api/fedmsg/markup', query_string=payload)
+        self.assertEqual(response.status_code, 403)
 
     def test_returns_match_if_involved(self):
         payload = {
@@ -305,13 +305,13 @@ class TestFeed(hubs.tests.APPTest):
             sess['openid'] = 'atelic@fedoraproject.org'
             sess['nickname'] = 'atelic'
 
-        with hubs.tests.user_set(self.app, self.user):
+        with hubs.tests.auth_set(app, self.user):
             response = self.app.get('/api/fedmsg/markup', query_string=payload)
 
-            assert response.status_code == 200, response.status_code
+            self.assertEqual(response.status_code, 200)
             data = json.loads(response.data)
             self.assertTrue(data)
-            assert isinstance(data[0], dict)
+            self.assertTrue(isinstance(data[0], dict))
 
     def test_returns_no_match_if_not_involved(self):
         payload = {
@@ -322,9 +322,9 @@ class TestFeed(hubs.tests.APPTest):
             sess['openid'] = 'atelic@fedoraproject.org'
             sess['nickname'] = 'atelic'
 
-        with hubs.tests.user_set(self.app, self.user):
+        with hubs.tests.auth_set(app, self.user):
             response = self.app.get('/api/fedmsg/markup', query_string=payload)
 
-            assert response.status_code == 200, response.status_code
+            self.assertEqual(response.status_code, 200)
             data = json.loads(response.data)
             self.assertFalse(data)
diff --git a/hubs/tests/test_api/test_hub.py b/hubs/tests/test_api/test_hub.py
new file mode 100644
index 0000000..ee749d9
--- /dev/null
+++ b/hubs/tests/test_api/test_hub.py
@@ -0,0 +1,150 @@
+import flask
+import unittest
+
+import hubs.tests
+import hubs.models
+from hubs.app import app
+
+
+def usernames(collection): return [u.username for u in collection]
+
+
+class TestHubSubscribe(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    @unittest.skip('Need to handle redirects')
+    def test_subscribe_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        resp = self.app.post('/api/hub/{}/subscribe'.format(hub.idx))
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+
+    def test_subscribe_when_logged_in(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
+                                 follow_redirects=True)
+            self.assertEqual(resp.status_code, 200)
+            # Need to find the Hub again to avoid DetachedInstanceError
+            h = hubs.models.Hub.by_name(self.session, 'infra')
+            self.assertTrue(self.user.username in usernames(h.subscribers))
+
+
+class TestHubUnsubscribe(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    @unittest.skip('Need to handle redirects')
+    def test_unsubscribe_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.idx))
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+
+    def test_unsubscribe_when_logged_in(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        # Need a real user model to subscribe to the hub
+        User = hubs.models.User.by_username(self.session, self.user.username)
+        hub.subscribe(self.session, User)
+
+        self.assertTrue(self.user.username in usernames(hub.subscribers))
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
+                                 follow_redirects=True)
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name(self.session, 'infra')
+            self.assertTrue(self.user.username not in usernames(h.subscribers))
+
+
+class TestHubStar(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    @unittest.skip('Need to handle redirects')
+    def test_star_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        resp = self.app.post('/api/hub/{}/star'.format(hub.idx))
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+
+    def test_star_when_logged_in(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/star'.format(hub.name),
+                                 follow_redirects=True)
+
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name(self.session, 'infra')
+            self.assertTrue(self.user.username in usernames(h.stargazers))
+
+
+class TestHubUnstar(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    @unittest.skip('Need to handle redirects')
+    def test_unstar_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        resp = self.app.post('/api/hub/{}/unstar'.format(hub.idx))
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+
+    def test_unstar_when_logged_in(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        # Need a real user model to subscribe to the hub
+        User = hubs.models.User.by_username(self.session, self.user.username)
+        hub.subscribe(self.session, User, role='stargazer')
+
+        self.assertTrue(self.user.username in [u.username for
+                                               u in hub.stargazers])
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
+                                 follow_redirects=True)
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name(self.session, 'infra')
+            self.assertTrue(self.user.username not in usernames(h.stargazers))
+
+
+class TestHubJoin(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    @unittest.skip('Need to handle redirects')
+    def test_join_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        resp = self.app.post('/api/hub/{}/join'.format(hub.idx))
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+
+    def test_join_when_logged_in(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/join'.format(hub.name),
+                                 follow_redirects=True)
+
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name(self.session, 'infra')
+            self.assertTrue(self.user.username in usernames(h.members))
+
+
+class TestHubLeave(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    @unittest.skip('Need to handle redirects')
+    def test_leave_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        resp = self.app.post('/api/hub/{}/leave'.format(hub.idx))
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+
+    def test_star_when_logged_in(self):
+        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        # Need a real user model to subscribe to the hub
+        User = hubs.models.User.by_username(self.session, self.user.username)
+        hub.subscribe(self.session, User, role='member')
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
+                                 follow_redirects=True)
+
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name(self.session, 'infra')
+            self.assertTrue(self.user.username not in usernames(h.members))

From eaa718781c8cbeadd90929820bd07c5871ec4a00 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jun 16 2016 15:54:14 +0000
Subject: [PATCH 492/1001] Apply pep8 and move json data to their own files


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index bafe0a1..96379c2 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -1,6 +1,7 @@
 from contextlib import contextmanager
 import json
 from datetime import datetime, timedelta
+import os
 
 import munch
 from os.path import dirname
@@ -12,6 +13,8 @@ import vcr
 import hubs.models
 
 cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
+json_path = os.path.join(
+    os.path.join(os.path.dirname(os.path.abspath(__file__))), 'data/')
 
 
 class APPTest(unittest.TestCase):
diff --git a/hubs/tests/data/message_involved.json b/hubs/tests/data/message_involved.json
new file mode 100644
index 0000000..fdfd0db
--- /dev/null
+++ b/hubs/tests/data/message_involved.json
@@ -0,0 +1,137 @@
+{
+    "timestamp": 1465567413.0,
+    "topic": "io.pagure.prod.pagure.issue.new",
+    "msg_id": "2016-0490127f-473f-4d01-ASDF-a864a56dc302",
+    "msg": {
+        "action": "created",
+        "comment": {
+            "body":
+            "hm, there is something odd the stackage page is inconsistent",
+            "created_at": "2016-06-10T14:03:31Z",
+            "html_url":
+            "https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438",
+            "id": 225190438,
+            "updated_at": "2016-06-10T14:03:31Z",
+            "url":
+            "https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438",
+            "user": {
+                "gravatar_id": "",
+                "html_url": "https://github.com/pypingou",
+                "id": 1240038,
+                "login": "pypingou",
+                "site_admin": false,
+                "type": "User",
+                "url": "https://api.github.com/users/pypingou"
+            }
+        },
+        "fas_usernames": {
+            "fedora-infra": "github_org_fedora-infra",
+            "pypingou": "pingou"
+        },
+        "issue": {
+            "assignee": null,
+            "body":
+            "@juhp it seems that the stackage backend is broken:",
+            "closed_at": "2016-04-29T14:53:10Z",
+            "comments": 8,
+            "created_at": "2016-04-15T16:15:57Z",
+            "html_url":
+            "https://github.com/fedora-infra/anitya/issues/283",
+            "id": 148703615,
+            "labels": [],
+            "locked": false,
+            "milestone": null,
+            "number": 283,
+            "state": "closed",
+            "title": "stackage backend broken",
+            "updated_at": "2016-06-10T14:03:31Z",
+            "url":
+            "https://api.github.com/repos/fedora-infra/anitya/issues/283",
+            "user": {
+                "gravatar_id": "",
+                "html_url": "https://github.com/pypingou",
+                "id": 1240038,
+                "login": "pypingou",
+                "site_admin": false,
+                "type": "User",
+                "url": "https://api.github.com/users/pypingou"
+            }
+        },
+        "organization": {
+            "description": "Fedora Infrastructure Team",
+            "id": 3316637,
+            "login": "fedora-infra",
+            "url": "https://api.github.com/orgs/fedora-infra"
+        },
+        "repository": {
+            "created_at": "2013-11-29T10:17:26Z",
+            "default_branch": "master",
+            "description": "A cross-distribution upstream release project",
+            "fork": false,
+            "forks": 33,
+            "forks_count": 33,
+            "full_name": "fedora-infra/anitya",
+            "has_downloads": true,
+            "has_issues": true,
+            "has_pages": false,
+            "has_wiki": false,
+            "homepage": "https://release-monitoring.org",
+            "html_url": "https://github.com/fedora-infra/anitya",
+            "id": 14798348,
+            "language": "Python",
+            "name": "anitya",
+            "open_issues": 25,
+            "open_issues_count": 25,
+            "owner": {
+                "gravatar_id": "",
+                "html_url": "https://github.com/fedora-infra",
+                "id": 3316637,
+                "login": "fedora-infra",
+                "site_admin": false,
+                "type": "Organization",
+                "url": "https://api.github.com/users/fedora-infra"
+            },
+            "private": false,
+            "pushed_at": "2016-06-05T18:16:15Z",
+            "size": 4364,
+            "stargazers_count": 56,
+            "updated_at": "2016-06-10T09:43:58Z",
+            "url": "https://api.github.com/repos/fedora-infra/anitya",
+            "watchers": 56,
+            "watchers_count": 56
+        },
+        "sender": {
+            "gravatar_id": "",
+            "html_url": "https://github.com/pypingou",
+            "id": 1240038,
+            "login": "pypingou",
+            "site_admin": false,
+            "type": "User",
+            "url": "https://api.github.com/users/pypingou"
+        }
+    },
+    "arguments": {
+        "categories": [
+            "pagure"
+        ],
+        "contains": [],
+        "delta": 172800.0,
+        "end": 1465839365.0,
+        "grouped": false,
+        "meta": [],
+        "not_categories": [],
+        "not_packages": [],
+        "not_topics": [],
+        "not_users": [],
+        "order": "desc",
+        "packages": [],
+        "page": 1,
+        "rows_per_page": 1,
+        "start": 1465666565.0,
+        "topics": [],
+        "users": []
+    },
+    "count": 1,
+    "pages": 225,
+    "total": 225
+}
diff --git a/hubs/tests/data/message_not_involved.json b/hubs/tests/data/message_not_involved.json
new file mode 100644
index 0000000..e72439a
--- /dev/null
+++ b/hubs/tests/data/message_not_involved.json
@@ -0,0 +1,120 @@
+{
+    "topic": "org.fedoraproject.prod.github.issue.comment",
+    "i": 1,
+    "msg": {
+        "action": "created",
+        "comment": {
+            "body":
+            "hm, there is something odd the stackage page is inconsistent",
+            "created_at": "2016-06-10T14:03:31Z",
+            "html_url":
+            "https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438",
+            "id": 225190438,
+            "updated_at": "2016-06-10T14:03:31Z",
+            "url":
+            "https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438",
+            "user": {
+                "gravatar_id": "",
+                "html_url": "https://github.com/pypingou",
+                "id": 1240038,
+                "login": "pypingou",
+                "site_admin": false,
+                "type": "User",
+                "url": "https://api.github.com/users/pypingou"
+            }
+        },
+        "fas_usernames": {
+            "fedora-infra": "github_org_fedora-infra",
+            "pypingou": "pingou"
+        },
+        "issue": {
+            "assignee": null,
+            "body":
+            "@juhp it seems that the stackage backend is broken",
+            "closed_at": "2016-04-29T14:53:10Z",
+            "comments": 8,
+            "created_at": "2016-04-15T16:15:57Z",
+            "html_url":
+            "https://github.com/fedora-infra/anitya/issues/283",
+            "id": 148703615,
+            "labels": [],
+            "locked": false,
+            "milestone": null,
+            "number": 283,
+            "state": "closed",
+            "title": "stackage backend broken",
+            "updated_at": "2016-06-10T14:03:31Z",
+            "url":
+            "https://api.github.com/repos/fedora-infra/anitya/issues/283",
+            "user": {
+                "gravatar_id": "",
+                "html_url": "https://github.com/pypingou",
+                "id": 1240038,
+                "login": "pypingou",
+                "site_admin": false,
+                "type": "User",
+                "url": "https://api.github.com/users/pypingou"
+            }
+        },
+        "organization": {
+            "description": "Fedora Infrastructure Team",
+            "id": 3316637,
+            "login": "fedora-infra",
+            "url": "https://api.github.com/orgs/fedora-infra"
+        },
+        "repository": {
+            "created_at": "2013-11-29T10:17:26Z",
+            "default_branch": "master",
+            "description":
+            "A cross-distribution upstream release monitoring project",
+            "fork": false,
+            "forks": 33,
+            "forks_count": 33,
+            "full_name": "fedora-infra/anitya",
+            "has_downloads": true,
+            "has_issues": true,
+            "has_pages": false,
+            "has_wiki": false,
+            "homepage": "https://release-monitoring.org",
+            "html_url": "https://github.com/fedora-infra/anitya",
+            "id": 14798348,
+            "language": "Python",
+            "name": "anitya",
+            "open_issues": 25,
+            "open_issues_count": 25,
+            "owner": {
+                "gravatar_id": "",
+                "html_url": "https://github.com/fedora-infra",
+                "id": 3316637,
+                "login": "fedora-infra",
+                "site_admin": false,
+                "type": "Organization",
+                "url": "https://api.github.com/users/fedora-infra"
+            },
+            "private": false,
+            "pushed_at": "2016-06-05T18:16:15Z",
+            "size": 4364,
+            "stargazers_count": 56,
+            "updated_at": "2016-06-10T09:43:58Z",
+            "url": "https://api.github.com/repos/fedora-infra/anitya",
+            "watchers": 56,
+            "watchers_count": 56
+        },
+        "sender": {
+            "gravatar_id": "",
+            "html_url": "https://github.com/pypingou",
+            "id": 1240038,
+            "login": "pypingou",
+            "site_admin": false,
+            "type": "User",
+            "url": "https://api.github.com/users/pypingou"
+        }
+    },
+    "msg_id": "2016-0490127f-473f-4d01-8e3a-a864a56dc302",
+    "signature":
+    "MNpAVdrPW78dcSe94FOS+/6QFBYo/LkrV5ee9tQedkhurHY1BGpaFHlU5l8cNVEpB7rr",
+    "source_name": "datanommer",
+    "source_version": "0.6.5",
+    "timestamp": 1465567413.0,
+    "topic": "org.fedoraproject.prod.github.issue.comment"
+}
diff --git a/hubs/tests/test_api/test_fedmsg.py b/hubs/tests/test_api/test_fedmsg.py
index ef3b6db..d6e67ef 100644
--- a/hubs/tests/test_api/test_fedmsg.py
+++ b/hubs/tests/test_api/test_fedmsg.py
@@ -1,271 +1,23 @@
 import json
+import os
 
 import hubs.tests
 import hubs.models
 from hubs.app import app
+from hubs.tests import json_path
 
 
 class TestFeed(hubs.tests.APPTest):
+
+    with open(json_path + 'message_involved.json', 'r') as fp:
+        message_involved = json.loads(fp.read())
+
+    with open(json_path + 'message_not_involved.json', 'r') as fp:
+        message_not_involved = json.loads(fp.read())
+
     # TODO this test relies on a specific filter for the atelic user
     # It would be better to fake preferences on FAS
     user = hubs.tests.FakeAuthorization('atelic')
-    message_involved = {
-        'timestamp': 1465567413.0,
-        'topic': 'io.pagure.prod.pagure.issue.new',
-        'msg_id': '2016-0490127f-473f-4d01-ASDF-a864a56dc302',
-        'msg': {
-            'action': 'created',
-            'comment': {
-                'body':
-                'hm, there is something odd, the stackage page is being inconsistent, one time the version number for LTS is linked, one time it isn\'t.\r\n\r\nIt\'s as if there are 2 servers running 2 different versions of the application',
-                'created_at': '2016-06-10T14:03:31Z',
-                'html_url':
-                'https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438',
-                'id': 225190438,
-                'updated_at': '2016-06-10T14:03:31Z',
-                'url':
-                'https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438',
-                'user': {
-                    'gravatar_id': '',
-                    'html_url': 'https://github.com/pypingou',
-                    'id': 1240038,
-                    'login': 'pypingou',
-                    'site_admin': False,
-                    'type': 'User',
-                    'url': 'https://api.github.com/users/pypingou'
-                }
-            },
-            'fas_usernames': {
-                'fedora-infra': 'github_org_fedora-infra',
-                'pypingou': 'pingou'
-            },
-            'issue': {
-                'assignee': None,
-                'body':
-                '@juhp it seems that the stackage backend is broken: https://release-monitoring.org/projects/updates/failed?name=&log=stackage want to look at it?',
-                'closed_at': '2016-04-29T14:53:10Z',
-                'comments': 8,
-                'created_at': '2016-04-15T16:15:57Z',
-                'html_url':
-                'https://github.com/fedora-infra/anitya/issues/283',
-                'id': 148703615,
-                'labels': [],
-                'locked': False,
-                'milestone': None,
-                'number': 283,
-                'state': 'closed',
-                'title': 'stackage backend broken',
-                'updated_at': '2016-06-10T14:03:31Z',
-                'url':
-                'https://api.github.com/repos/fedora-infra/anitya/issues/283',
-                'user': {
-                    'gravatar_id': '',
-                    'html_url': 'https://github.com/pypingou',
-                    'id': 1240038,
-                    'login': 'pypingou',
-                    'site_admin': False,
-                    'type': 'User',
-                    'url': 'https://api.github.com/users/pypingou'
-                }
-            },
-            'organization': {
-                'description': 'Fedora Infrastructure Team',
-                'id': 3316637,
-                'login': 'fedora-infra',
-                'url': 'https://api.github.com/orgs/fedora-infra'
-            },
-            'repository': {
-                'created_at': '2013-11-29T10:17:26Z',
-                'default_branch': 'master',
-                'description': 'A cross-distribution upstream release project',
-                'fork': False,
-                'forks': 33,
-                'forks_count': 33,
-                'full_name': 'fedora-infra/anitya',
-                'has_downloads': True,
-                'has_issues': True,
-                'has_pages': False,
-                'has_wiki': False,
-                'homepage': 'https://release-monitoring.org',
-                'html_url': 'https://github.com/fedora-infra/anitya',
-                'id': 14798348,
-                'language': 'Python',
-                'name': 'anitya',
-                'open_issues': 25,
-                'open_issues_count': 25,
-                'owner': {
-                    'gravatar_id': '',
-                    'html_url': 'https://github.com/fedora-infra',
-                    'id': 3316637,
-                    'login': 'fedora-infra',
-                    'site_admin': False,
-                    'type': 'Organization',
-                    'url': 'https://api.github.com/users/fedora-infra'
-                },
-                'private': False,
-                'pushed_at': '2016-06-05T18:16:15Z',
-                'size': 4364,
-                'stargazers_count': 56,
-                'updated_at': '2016-06-10T09:43:58Z',
-                'url': 'https://api.github.com/repos/fedora-infra/anitya',
-                'watchers': 56,
-                'watchers_count': 56
-            },
-            'sender': {
-                'gravatar_id': '',
-                'html_url': 'https://github.com/pypingou',
-                'id': 1240038,
-                'login': 'pypingou',
-                'site_admin': False,
-                'type': 'User',
-                'url': 'https://api.github.com/users/pypingou'
-            }
-        },
-        'arguments': {
-            'categories': [
-                'pagure'
-            ],
-            'contains': [],
-            'delta': 172800.0,
-            'end': 1465839365.0,
-            'grouped': False,
-            'meta': [],
-            'not_categories': [],
-            'not_packages': [],
-            'not_topics': [],
-            'not_users': [],
-            'order': 'desc',
-            'packages': [],
-            'page': 1,
-            'rows_per_page': 1,
-            'start': 1465666565.0,
-            'topics': [],
-            'users': []
-        },
-        'count': 1,
-        'pages': 225,
-        'total': 225
-    }
-    message_not_involved = {
-        'topic': 'org.fedoraproject.prod.github.issue.comment',
-        'i': 1,
-        'msg': {
-            'action': 'created',
-            'comment': {
-                'body':
-                'hm, there is something odd, the stackage page is being inconsistent, one time the version number for LTS is linked, one time it isn\'t.\r\n\r\nIt\'s as if there are 2 servers running 2 different versions of the application',
-                'created_at': '2016-06-10T14:03:31Z',
-                'html_url':
-                'https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438',
-                'id': 225190438,
-                'updated_at': '2016-06-10T14:03:31Z',
-                'url':
-                'https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438',
-                'user': {
-                    'gravatar_id': '',
-                    'html_url': 'https://github.com/pypingou',
-                    'id': 1240038,
-                    'login': 'pypingou',
-                    'site_admin': False,
-                    'type': 'User',
-                    'url': 'https://api.github.com/users/pypingou'
-                }
-            },
-            'fas_usernames': {
-                'fedora-infra': 'github_org_fedora-infra',
-                'pypingou': 'pingou'
-            },
-            'issue': {
-                'assignee': None,
-                'body':
-                '@juhp it seems that the stackage backend is broken: https://release-monitoring.org/projects/updates/failed?name=&log=stackage want to look at it?',
-                'closed_at': '2016-04-29T14:53:10Z',
-                'comments': 8,
-                'created_at': '2016-04-15T16:15:57Z',
-                'html_url':
-                'https://github.com/fedora-infra/anitya/issues/283',
-                'id': 148703615,
-                'labels': [],
-                'locked': False,
-                'milestone': None,
-                'number': 283,
-                'state': 'closed',
-                'title': 'stackage backend broken',
-                'updated_at': '2016-06-10T14:03:31Z',
-                'url':
-                'https://api.github.com/repos/fedora-infra/anitya/issues/283',
-                'user': {
-                    'gravatar_id': '',
-                    'html_url': 'https://github.com/pypingou',
-                    'id': 1240038,
-                    'login': 'pypingou',
-                    'site_admin': False,
-                    'type': 'User',
-                    'url': 'https://api.github.com/users/pypingou'
-                }
-            },
-            'organization': {
-                'description': 'Fedora Infrastructure Team',
-                'id': 3316637,
-                'login': 'fedora-infra',
-                'url': 'https://api.github.com/orgs/fedora-infra'
-            },
-            'repository': {
-                'created_at': '2013-11-29T10:17:26Z',
-                'default_branch': 'master',
-                'description':
-                'A cross-distribution upstream release monitoring project',
-                'fork': False,
-                'forks': 33,
-                'forks_count': 33,
-                'full_name': 'fedora-infra/anitya',
-                'has_downloads': True,
-                'has_issues': True,
-                'has_pages': False,
-                'has_wiki': False,
-                'homepage': 'https://release-monitoring.org',
-                'html_url': 'https://github.com/fedora-infra/anitya',
-                'id': 14798348,
-                'language': 'Python',
-                'name': 'anitya',
-                'open_issues': 25,
-                'open_issues_count': 25,
-                'owner': {
-                    'gravatar_id': '',
-                    'html_url': 'https://github.com/fedora-infra',
-                    'id': 3316637,
-                    'login': 'fedora-infra',
-                    'site_admin': False,
-                    'type': 'Organization',
-                    'url': 'https://api.github.com/users/fedora-infra'
-                },
-                'private': False,
-                'pushed_at': '2016-06-05T18:16:15Z',
-                'size': 4364,
-                'stargazers_count': 56,
-                'updated_at': '2016-06-10T09:43:58Z',
-                'url': 'https://api.github.com/repos/fedora-infra/anitya',
-                'watchers': 56,
-                'watchers_count': 56
-            },
-            'sender': {
-                'gravatar_id': '',
-                'html_url': 'https://github.com/pypingou',
-                'id': 1240038,
-                'login': 'pypingou',
-                'site_admin': False,
-                'type': 'User',
-                'url': 'https://api.github.com/users/pypingou'
-            }
-        },
-        'msg_id': '2016-0490127f-473f-4d01-8e3a-a864a56dc302',
-        'signature':
-        'MNpAVdrPW78dcSe94FOS+/6QFBYo/LkrV5ee9tQedkhurHY1BGpaFHlU5l8cNVEpB7rr/zhHgQ+V\nmE3zYPmW/aREgvUoQgz74TR5F6/nK4Q1cD97VkFgHCadxZC6kjXd4H3BahEYnD+erj1iaArcdZaI\nXyKLZUBJLYL4JiXlmec=\n',
-        'source_name': 'datanommer',
-        'source_version': '0.6.5',
-        'timestamp': 1465567413.0,
-        'topic': 'org.fedoraproject.prod.github.issue.comment'
-    }
 
     plugin = 'feed'
 

From 0ffdc70ceaed8dbf395eaf66bf86fe48e946bdc4 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jun 17 2016 15:00:02 +0000
Subject: [PATCH 493/1001] increasing unittests, kindof figured out how to test redirection and pep8 the files


adding owner of hub editing hub with no data

hub edit succesful

adding another test for hubs/edit for invalid data

pep8 the file

pep8 files and added a new function to see if flask.g.auth is set

made authenticated function check if flask.g.auth is set and check what the logged_in bool is and return it

undoing a pep8 to one line, changed the authenticate function to be shorter

pep8 the authenticated function

---

diff --git a/hubs/app.py b/hubs/app.py
index c283490..4b72cee 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -31,17 +31,17 @@ app = flask.Flask(__name__)
 # Register some useful global filters.
 def days_since(then):
     return (datetime.datetime.utcnow() - then).days
+
+
 app.template_filter('days_since')(days_since)
 app.template_filter('avatar')(username2avatar)
 
 logging.basicConfig()
 
-
 # TODO - put this in config so we can migrate to pagure
 # TODO - instead of 'develop', use the version from pkg_resources to figure out
 #        the right tag to link people to.  AGPL ftw.
-SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'#/hubs/widgets/badges.py'
-
+SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'  # /hubs/widgets/badges.py'
 
 app.config.from_object('hubs.default_config')
 if 'HUBS_CONFIG' in os.environ:
@@ -49,6 +49,7 @@ if 'HUBS_CONFIG' in os.environ:
 
 import fedmsg.config
 import fedmsg.meta
+
 fedmsg_config = fedmsg.config.load_config()
 fedmsg.meta.make_processors(**fedmsg_config)
 PATHS = fmn.lib.load_rules(root='fmn.rules')
@@ -67,9 +68,17 @@ class CustomJSONEncoder(flask.json.JSONEncoder):
             return list(iterable)
         return flask.json.JSONEncoder.default(self, o)
 
+
 app.json_encoder = CustomJSONEncoder
 
 
+def authenticated():
+    """ Utility function checking if the current auth is set or not."""
+    return hasattr(flask.g, 'auth') \
+        and flask.g.auth is not None \
+        and flask.g.auth.logged_in
+
+
 @app.template_filter('commas')
 def commas(numeric):
     return "{:,.2f}".format(numeric)
@@ -83,7 +92,7 @@ def shutdown_session(exception=None):
 
 @app.route('/')
 def index():
-    if not flask.g.auth.logged_in:
+    if not authenticated():
         return flask.redirect(flask.url_for('login_fedora'))
 
     return flask.redirect(flask.url_for('hub', name=flask.g.auth.nickname))
@@ -91,7 +100,7 @@ def index():
 
 @app.route('/groups')
 def groups():
-    if not flask.g.auth.logged_in:
+    if not authenticated():
         return flask.redirect(flask.url_for('login_fedora'))
 
     # Get the list of promoted and non-promoted group hubs from the DB
@@ -156,7 +165,7 @@ def hub_edit_post(name):
         w.strip().replace('widget-', '')
         for w in flask.request.form.getlist('right_widgets[]')
         if w.strip()
-    ]
+        ]
     try:
         r_widget_ids = [int(w) for w in r_widget_ids]
     except:
@@ -166,7 +175,7 @@ def hub_edit_post(name):
     r_indexes = [
         i.strip() for i in flask.request.form.getlist('right_indexes[]')
         if i.strip()
-    ]
+        ]
 
     try:
         r_indexes = [int(i) for i in r_indexes]
@@ -187,7 +196,7 @@ def hub_edit_post(name):
         w.strip().replace('widget-', '')
         for w in flask.request.form.getlist('left_widgets[]')
         if w.strip()
-    ]
+        ]
     try:
         l_widget_ids = [int(w) for w in l_widget_ids]
     except:
@@ -197,7 +206,7 @@ def hub_edit_post(name):
     l_indexes = [
         i.strip() for i in flask.request.form.getlist('left_indexes[]')
         if i.strip()
-    ]
+        ]
 
     try:
         l_indexes = [int(i) for i in l_indexes]
@@ -290,7 +299,7 @@ def hub_add_widget_get(name):
         widget
         for widget in hubs.widgets.registry
         if hubs.widgets.registry[widget].position in ['both', side]
-    ]
+        ]
     return flask.render_template(
         'add_widget.html',
         hub=hub,
@@ -311,7 +320,7 @@ def hub_add_widget_post(name):
     hub = get_hub(session, name)
 
     widget = widget = hubs.models.Widget(
-        plugin=widget_name, index=-1, left=position=='left')
+        plugin=widget_name, index=-1, left=position == 'left')
     error = False
     config = {}
     for arg in widget.module.data.widget_arguments:
@@ -350,8 +359,8 @@ def hub_add_widget_post(name):
 @app.route('/<hub>/<idx>')
 def widget_render(hub, idx):
     widget = get_widget(session, hub, idx)
-    return widget.render(session)#, edit=False)
-    #was blocking all widgets from working, sorry!
+    return widget.render(session)  # , edit=False)
+    # was blocking all widgets from working, sorry!
 
 
 @app.route('/<hub>/<idx>/json')
@@ -454,7 +463,7 @@ oid = OpenID(app,
 def login():
     default = flask.url_for('index')
     next_url = flask.request.args.get('next', default)
-    if flask.g.auth.logged_in:
+    if authenticated():
         return flask.redirect(next_url)
 
     openid_server = flask.request.form.get('openid', None)
@@ -471,8 +480,8 @@ def login():
 @app.route('/login/fedora')
 @oid.loginhandler
 def login_fedora():
-    #default = flask.url_for('profile_redirect')
-    #next_url = flask.request.args.get('next', default)
+    # default = flask.url_for('profile_redirect')
+    # next_url = flask.request.args.get('next', default)
     return oid.try_login(
         'https://id.fedoraproject.org',
         ask_for=['email', 'fullname', 'nickname'],
@@ -509,15 +518,17 @@ def after_openid_login(resp):
 
 def login_required(function):
     """ Flask decorator to restrict access to logged-in users. """
+
     @functools.wraps(function)
     def decorated_function(*args, **kwargs):
         """ Decorated function, actually does the work. """
-        if not flask.g.auth.logged_in:
+        if not authenticated():
             flask.flash('Login required', 'errors')
             return flask.redirect(flask.url_for(
                 'login_fedora', next=flask.request.url))
 
         return function(*args, **kwargs)
+
     return decorated_function
 
 
@@ -542,8 +553,8 @@ def check_auth():
 
 def get_hub(session, name):
     """ Utility shorthand to get a hub and 404 if not found. """
-    hub = session.query(hubs.models.Hub)\
-        .filter(hubs.models.Hub.name == name)\
+    hub = session.query(hubs.models.Hub) \
+        .filter(hubs.models.Hub.name == name) \
         .first()
 
     if not hub:
@@ -568,8 +579,8 @@ def get_widget(session, hub, idx):
     flask.abort(404)
 
 
-## Here are a bunch of API methods that should probably be broken out into
-## their own file
+# Here are a bunch of API methods that should probably be broken out into
+# their own file
 @app.route('/api/hub/<hub>/subscribe', methods=['POST'])
 @login_required
 def hub_subscribe(hub):
@@ -660,7 +671,7 @@ def markup_fedmsg():
     message = json.loads(data)
     try:
         nickname = flask.g.auth.nickname
-    except AttributeError:      # Not logged in
+    except AttributeError:  # Not logged in
         return flask.abort(403)
     preference = get_remote_preference(nickname, context)
     if preference:
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 96379c2..5c10118 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -107,7 +107,7 @@ def auth_set(APP, auth):
     def handler(sender, **kwargs):
         g.auth = auth
         if not auth:
-            munch.Munch(logged_in=False)
+            g.auth = munch.Munch(logged_in=False)
 
     with appcontext_pushed.connected_to(handler, APP):
         yield
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index bf79d06..a0043f0 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -4,6 +4,7 @@ from urlparse import urlparse
 from flask import json
 from os.path import dirname
 import vcr
+from werkzeug.datastructures import ImmutableMultiDict
 
 import hubs
 from hubs import tests
@@ -17,12 +18,10 @@ cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
 
 
 class HubsAPITest(hubs.tests.APPTest):
-    @unittest.skip("Can't seem to get redirected to the login in these tests")
     def test_index_logged_out(self):
-        result = self.app.get('/', follow_redirects=True)
-        # its trying to redirect to login id.fedoraproject.org/openid
-        # assert the status code of the response
-        self.assertEqual(result.status_code, 200)
+        result = self.app.get('/', follow_redirects=False)
+        self.assertEqual(result.status_code, 302)
+        self.assertEqual(urlparse(result.location).path, "/login/fedora")
 
     def test_index_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -31,25 +30,27 @@ class HubsAPITest(hubs.tests.APPTest):
             # its trying to redirect to login id.fedoraproject.org/openid
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
-            self.assertFalse('Not logged in.  Click to <a href="/login/fedora">login</a>' in result.data)
+            self.assertFalse('Not logged in.  Click to <a href="'
+                             '/login/fedora">login</a>' in result.data)
 
     def test_hub_logged_out(self):
-        with tests.auth_set(app, None):
-            # for some reason def check_auth() is not running and i need to set it to none so it won't crash
+        with app.test_request_context('/ralph'):
+            # need to manually call the @app.before_request
+            # since unittest don't call it
+            hubs.app.check_auth()
             result = self.app.get('/ralph', follow_redirects=True)
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
-            self.assertTrue('Not logged in.  Click to <a href="/login/fedora">login</a>' in result.data)
+            str_expected = 'Not logged in.  Click to ' \
+                           '<a href="/login/fedora">login</a>'
+            self.assertTrue(str_expected in result.data)
 
-    @unittest.skip("Can't seem to get redirected to the login in these tests")
     def test_groups_logged_out(self):
-        with tests.auth_set(app, None):
-            # for some reason def check_auth() is not running and i need to set it to none so it won't crash
-            result = self.app.get('/groups', follow_redirects=True)
-            # assert the status code of the response
-            self.assertEqual(result.status_code, 200)
-            # this will redirect to fedora.login which unittests can't handle atm
-            pass
+        result = self.app.get('/groups', follow_redirects=False)
+        # assert the status code of the response
+        self.assertEqual(result.status_code, 302)
+        # this will redirect to fedora.login
+        self.assertEqual(urlparse(result.location).path, "/login/fedora")
 
     def test_groups_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -64,25 +65,26 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             result = self.app.get('/ralph', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            self.assertFalse('Not logged in.  Click to <a href="/login/fedora">login</a>' in result.data)
+            self.assertFalse('Not logged in.  Click to <a href="'
+                             '/login/fedora">login</a>' in result.data)
 
     def test_hub_json(self):
-        with tests.auth_set(app, None):
-            # for some reason def check_auth() is not running and i need to set it to none so it won't crash
-            result = self.app.get('/ralph/json', follow_redirects=True)
-            # assert the status code of the response
-            self.assertEqual(result.status_code, 200)
-            data = {
-                "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=312&d=retro",
-                "left_width": 8,
-                "members": ["ralph"],
-                "name": "ralph",
-                "owners": ["ralph"],
-                "subscribers": [],
-                "summary": "Ralph",
-                "widgets": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 51]
-            }
-            self.assertDictEqual(data, json.loads(result.data))
+        result = self.app.get('/ralph/json', follow_redirects=True)
+        # assert the status code of the response
+        self.assertEqual(result.status_code, 200)
+        data = {
+            "avatar": "https://seccdn.libravatar.org/avatar/"
+                      "9c9f7784935381befc302fe3c814f9136e7a339"
+                      "53d0318761669b8643f4df55c?s=312&d=retro",
+            "left_width": 8,
+            "members": ["ralph"],
+            "name": "ralph",
+            "owners": ["ralph"],
+            "subscribers": [],
+            "summary": "Ralph",
+            "widgets": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 51]
+        }
+        self.assertDictEqual(data, json.loads(result.data))
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_get_logged_out(self):
@@ -106,7 +108,7 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             result = self.app.get('/ralph/edit', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            # We do not have the authorization layer in place yet so everyone can edit
+            # We do not have the authorization layer so everyone can edit
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_post_logged_out(self):
@@ -125,20 +127,85 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 403)  # failing right
             # We do not have the authorization layer in place yet
 
-    # WIP: commenting out so I can push this updates to branch so others can contribute
-    '''
-    def test_hub_edit_post_logged_in_owner_no_data(self):
+    def test_hub_edit_post_logged_in_owner_empty_data(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            result = self.app.post('/ralph/edit', follow_redirects=True)
+            result = self.app.post('/ralph/edit', data={},
+                                   follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            assert 'Invalid widget identifiers submitted' in result.data
-            assert 'Invalid indexes submitted' in result.data
-            assert 'The number of indexes and the number of widgets ' \
-                   'are not of the same length' in result.data
-            assert 'Invalid widget identifiers submitted' in result.data
-            assert 'Invalid indexes submitted' in result.data
-    '''
+            self.assertFalse('Not logged in.  Click to <a href="'
+                             '/login/fedora">login</a>' in result.data)
+            self.assertTrue('<a href="#" class="dropdown-item">Full Name: '
+                            'fullname: ralph</a>' in result.data)
+
+    def test_hub_edit_post_logged_in_owner_valid_data(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            data = ImmutableMultiDict(
+                [('right_indexes[]', u'0'), ('right_indexes[]', u'1'),
+                 ('right_indexes[]', u'2'), ('right_indexes[]', u'3'),
+                 ('right_indexes[]', u'4'), ('right_indexes[]', u'5'),
+                 ('right_indexes[]', u'6'), ('right_indexes[]', u'7'),
+                 ('right_indexes[]', u'8'), ('right_widgets[]', u'32'),
+                 ('right_widgets[]', u'33'), ('right_widgets[]', u'34'),
+                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
+                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
+                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
+                 ('js', u'true'), ('left_indexes[]', u'0'),
+                 ('left_indexes[]', u'1'), ('left_widgets[]', u'31'),
+                 ('left_widgets[]', u'32')])
+            result = self.app.post('/ralph/edit', data=data,
+                                   follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            self.assertEqual(result.data, 'ok')
+
+    def test_hub_edit_post_logged_in_owner_invalid_data_1(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            # some indexes and widgets are not integers
+            data = ImmutableMultiDict(
+                [('right_indexes[]', u'0a'), ('right_indexes[]', u'1'),
+                 ('right_indexes[]', u'2'), ('right_indexes[]', u'3'),
+                 ('right_indexes[]', u'4'), ('right_indexes[]', u'5'),
+                 ('right_indexes[]', u'6'), ('right_indexes[]', u'7'),
+                 ('right_indexes[]', u'8'), ('right_widgets[]', u'32'),
+                 ('right_widgets[]', u'33a'), ('right_widgets[]', u'34'),
+                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
+                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
+                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
+                 ('js', u'true'), ('left_indexes[]', u'0a'),
+                 ('left_indexes[]', u'1'), ('left_widgets[]', u'31a'),
+                 ('left_widgets[]', u'32')])
+            result = self.app.post('/ralph/edit', data=data,
+                                   follow_redirects=True)
+            self.assertEqual(result.status_code, 400)
+
+    def test_hub_edit_post_logged_in_owner_invalid_data_2(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            # indexes len don't match widgets len
+            data = ImmutableMultiDict(
+                [('right_indexes[]', u'1'), ('right_indexes[]', u'2'),
+                 ('right_indexes[]', u'3'), ('right_indexes[]', u'4'),
+                 ('right_indexes[]', u'5'), ('right_indexes[]', u'6'),
+                 ('right_indexes[]', u'7'), ('right_indexes[]', u'8'),
+                 ('right_widgets[]', u'32'), ('right_widgets[]', u'34'),
+                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
+                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
+                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
+                 ('js', u'true'), ('left_indexes[]', u'0'),
+                 ('left_indexes[]', u'1'), ('left_widgets[]', u'32')])
+            result = self.app.post('/ralph/edit', data=data,
+                                   follow_redirects=True)
+            self.assertEqual(result.status_code, 400)
+
+    def test_login_already_loggedin(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/login', follow_redirects=False)
+            self.assertEqual(result.status_code, 302)
+            self.assertEqual(urlparse(result.location).path, "/")
+
 
 if __name__ == '__main__':
     unittest.main()

From f8497788b5ae571c0a18776817f511e0d2f54231 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jun 20 2016 14:47:52 +0000
Subject: [PATCH 494/1001] Test login redirection for hub actions


---

diff --git a/hubs/tests/test_api/test_hub.py b/hubs/tests/test_api/test_hub.py
index ee749d9..785aef3 100644
--- a/hubs/tests/test_api/test_hub.py
+++ b/hubs/tests/test_api/test_hub.py
@@ -1,5 +1,6 @@
 import flask
 import unittest
+from urlparse import urlparse
 
 import hubs.tests
 import hubs.models
@@ -12,12 +13,12 @@ def usernames(collection): return [u.username for u in collection]
 class TestHubSubscribe(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
-    @unittest.skip('Need to handle redirects')
     def test_subscribe_redirects_when_logged_out(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
-        resp = self.app.post('/api/hub/{}/subscribe'.format(hub.idx))
+        resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
+                             follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
 
     def test_subscribe_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -33,12 +34,12 @@ class TestHubSubscribe(hubs.tests.APPTest):
 class TestHubUnsubscribe(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
-    @unittest.skip('Need to handle redirects')
     def test_unsubscribe_redirects_when_logged_out(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
-        resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.idx))
+        resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
+                             follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
 
     def test_unsubscribe_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -59,12 +60,12 @@ class TestHubUnsubscribe(hubs.tests.APPTest):
 class TestHubStar(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
-    @unittest.skip('Need to handle redirects')
     def test_star_redirects_when_logged_out(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
-        resp = self.app.post('/api/hub/{}/star'.format(hub.idx))
+        resp = self.app.post('/api/hub/{}/star'.format(hub.name),
+                             follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
 
     def test_star_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -80,12 +81,12 @@ class TestHubStar(hubs.tests.APPTest):
 class TestHubUnstar(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
-    @unittest.skip('Need to handle redirects')
     def test_unstar_redirects_when_logged_out(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
-        resp = self.app.post('/api/hub/{}/unstar'.format(hub.idx))
+        resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
+                             follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
 
     def test_unstar_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -107,12 +108,12 @@ class TestHubUnstar(hubs.tests.APPTest):
 class TestHubJoin(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
-    @unittest.skip('Need to handle redirects')
     def test_join_redirects_when_logged_out(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
-        resp = self.app.post('/api/hub/{}/join'.format(hub.idx))
+        resp = self.app.post('/api/hub/{}/join'.format(hub.name),
+                             follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
 
     def test_join_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -128,12 +129,12 @@ class TestHubJoin(hubs.tests.APPTest):
 class TestHubLeave(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
-    @unittest.skip('Need to handle redirects')
     def test_leave_redirects_when_logged_out(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
-        resp = self.app.post('/api/hub/{}/leave'.format(hub.idx))
+        resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
+                             follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(resp.location, flask.url_for('fedora.login'))
+        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
 
     def test_star_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')

From f2a1fad40695a24bf298439fdae7960e80bdcf7f Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jun 20 2016 15:36:38 +0000
Subject: [PATCH 495/1001]     adding post tests for hub/add/ widget


    added hubs edit post with valid minimum valid data

    working on hubs edit widget testing

adjusting text to single quote from double

---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index a0043f0..d9d2325 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -206,6 +206,80 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 302)
             self.assertEqual(urlparse(result.location).path, "/")
 
+    def test_hub_add_widget_get_no_args(self):
+        result = self.app.get('/ralph/add', follow_redirects=False)
+        self.assertEqual(result.status_code, 400)
+        expected_str = 'Invalid position provided'
+        self.assertTrue(expected_str in result.data)
+
+    def test_hub_add_widget_get_with_args(self):
+        result = self.app.get('/ralph/add?position=right',
+                              follow_redirects=True)
+        self.assertEqual(result.status_code, 200)
+        expected_str = 'Adding widget to hub: ralph'
+        self.assertTrue(expected_str in result.data)
+        expected_str = "url: 'add/' + $('#widget').val() + '?position=right',"
+        self.assertTrue(expected_str in result.data)
+
+    def test_hub_add_widget_post_no_widget_name(self):
+        data = {}
+        result = self.app.post('/ralph/add', data=data, follow_redirects=False)
+        self.assertEqual(result.status_code, 400)
+        expected_str = 'Invalid request sent'
+        self.assertTrue(expected_str in result.data)
+
+    def test_hub_add_widget_post_invalid_widget_name(self):
+        data = {'widget_name': 'invalid_widget_name'}
+        result = self.app.post('/ralph/add', data=data, follow_redirects=False)
+        self.assertEqual(result.status_code, 404)
+        expected_str = 'Unknown widget called'
+        self.assertTrue(expected_str in result.data)
+
+    def test_hub_add_widget_post_valid_widget_name_no_args(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            data = {'widget_name': 'about'}
+            result = self.app.post('/ralph/add', data=data,
+                                   follow_redirects=False)
+            self.assertEqual(result.status_code, 200)
+            expected_str = '<h6 class="dropdown-header">Account Information</h6>'
+            self.assertTrue(expected_str in result.data)
+            expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
+            self.assertTrue(expected_str in result.data)
+
+    def test_hub_add_widget_post_valid_widget_name_with_args(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            data = {'widget_name': 'about', 'text': 'text of widget'}
+            result = self.app.post('/ralph/add', data=data,
+                                   follow_redirects=False)
+            self.assertEqual(result.status_code, 200)
+            expected_str = '<h6 class="dropdown-header">Account Information</h6>'
+            self.assertTrue(expected_str in result.data)
+            expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
+            self.assertTrue(expected_str in result.data)
+
+    def test_hub_edit_widget_get_logged_in(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/ralph/31/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            expected_str = '<input id="fmn_context" class="form-control" type="text"'
+            self.assertTrue(expected_str in result.data)
+
+    @unittest.skip("Authorization layer not present yet")
+    def test_hub_edit_widget_get_logged_out(self):
+        result = self.app.get('/ralph/31/edit', follow_redirects=True)
+        self.assertEqual(result.status_code, 403)
+
+    def test_hub_edit_widget_post_empty_data_logged_in(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            data = {}
+            url = '/ralph/31/edit'
+            result = self.app.post(url, data=data, follow_redirects=False)
+            self.assertEqual(result.status_code, 302)
+            self.assertEqual(urlparse(result.location).path, '/ralph/')
 
 if __name__ == '__main__':
     unittest.main()

From 865b26f3707b8d6c3f20caee12abe60a1bbe9146 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jun 20 2016 19:56:10 +0000
Subject: [PATCH 496/1001] Move hubs.feed and PATHS down to temp endpoint


---

diff --git a/hubs/app.py b/hubs/app.py
index 4b72cee..64e6b91 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -20,10 +20,6 @@ import hubs.widgets
 import datanommer.models
 
 from hubs.utils import username2avatar
-from hubs.widgets.feed import (
-    apply_markup, rehydrate_preference,
-    get_remote_preference
-)
 
 app = flask.Flask(__name__)
 
@@ -52,7 +48,6 @@ import fedmsg.meta
 
 fedmsg_config = fedmsg.config.load_config()
 fedmsg.meta.make_processors(**fedmsg_config)
-PATHS = fmn.lib.load_rules(root='fmn.rules')
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 datanommer.models.init(fedmsg_config['datanommer.sqlalchemy.uri'])
@@ -650,6 +645,9 @@ def hub_leave(hub):
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
 
+PATHS = fmn.lib.load_rules(root='fmn.rules')
+
+
 @app.route('/api/fedmsg/markup', methods=['GET'])
 def markup_fedmsg():
     '''
@@ -658,6 +656,10 @@ def markup_fedmsg():
 
     This route will be removed once its functionality is integrated into FMN
     '''
+    from hubs.widgets.feed import (
+        apply_markup, rehydrate_preference,
+        get_remote_preference
+    )
     try:
         data = flask.request.args['message']
         plugin = flask.request.args['plugin']

From 6922d8e8bc963ae1cc4582a28293c25e45d558e7 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jun 21 2016 12:51:32 +0000
Subject: [PATCH 497/1001] cleaning up current tests in the widgets folder


---

diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index 38bddee..a0ec275 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -25,26 +25,18 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         msg = {'topic': 'hubs.widget.update.WRONG.TOPIC', 'msg': {'widget': {'id': widget.idx}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
-        assert not result
+        self.assertFalse(result)
 
     def test_should_invalidate_wrong_widget_id(self):
         widget = self.widget_instance('ralph', self.plugin)
         msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx+1}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
-        assert not result
+        self.assertFalse(result)
 
     def test_should_invalidate_good_match(self):
         widget = self.widget_instance('ralph', self.plugin)
         msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
-        assert result
-
-    '''
-    def test_data(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        module = hubs.widgets.registry[widget.plugin]
-        result = module.data(self.session, widget, 'I love oss.')
-        assert_dict_equal({'text': 'I love oss.'}, result)
-    '''
\ No newline at end of file
+        self.assertTrue(result)
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index 7edd96e..b3b5197 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -13,7 +13,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         assert response.status_code == 200, response.status_code
         data = json.loads(response.data)
         self.assertEquals(data['plugin'], 'badges')
-        assert 'assertions' in data['data'], data['data'].keys()
+        self.assertIn('assertions', data['data'].keys())
 
     def test_should_invalidate_wrong_topic(self):
         widget = self.widget_instance('ralph', self.plugin)
@@ -21,7 +21,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         msg = {'topic': 'hubs.widget.update.WRONG.TOPIC'}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
-        assert not result
+        self.assertFalse(result)
 
     def test_should_invalidate_wrong_user(self):
         widget = self.widget_instance('ralph', self.plugin)
@@ -29,7 +29,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         msg = {'topic': 'fedbadges.badge.award', 'msg': {'user': {'username': 'not_ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
-        assert not result
+        self.assertFalse(result)
 
     def test_should_invalidate_good_match_fedbadges(self):
         widget = self.widget_instance('ralph', self.plugin)
@@ -37,7 +37,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         msg = {'topic': 'fedbadges.badge.award', 'msg': {'user': {'username': 'ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
-        assert result
+        self.assertTrue(result)
 
     def test_should_invalidate_good_match_hubswidget(self):
         widget = self.widget_instance('ralph', self.plugin)
@@ -45,40 +45,4 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx + 1}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
-        assert result
-    '''
-    @patch('requests.get')
-    @patch('hubs.widgets.base.cache.get_or_create')
-    def test_data_good(self, cache_mock, requests_mock):
-        requests_mock.return_value = self.mock_response()
-        cache_mock.return_value = None
-        widget = self.widget_instance('ralph', self.plugin)
-        module = hubs.widgets.registry[widget.plugin]
-        result = module.data(self.session, widget, 'ralph')
-        assert result
-    '''
-    @staticmethod
-    def mock_response():
-        test_data_simple = '''{
-            "percent_earned": 47.05882352941176,
-            "assertions": [{
-                "description": "You attended Flock 2014, the Fedora Contributor Conference",
-                "tags": "flock,event,",
-                "issued": 1375373082.0,
-                "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
-                "first_awarded": 1375373082.0,
-                "first_awarded_person": "ralph",
-                "last_awarded_person": "gnokii",
-                "last_awarded": 1386188828.0,
-                "percent_earned": 0.404551201011378,
-                "id": "flock-2013-attendee",
-                "times_awarded": 80,
-                "name": "Flock 2013 Attendee"
-            }],
-            "user": "ralph",
-            "avatar": ""
-        }'''
-
-        mock = MagicMock()
-        mock.json.return_value = json.loads(test_data_simple)
-        return mock
+        self.assertTrue(result)
\ No newline at end of file
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index bafb6a3..0a48a83 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -10,14 +10,14 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/json/' % (team, widget.idx))
-        assert response.status_code == 200, response.status_code
+        self.assertEqual(200, response.status_code)
         data = json.loads(response.data)
         meeting = data['data']['meetings']["%s meeting" % team]
-        assert team in meeting['meeting_name']
+        self.assertIn(team, meeting['meeting_name'])
 
     def test_render_simple(self):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/' % (team, widget.idx))
-        assert response.status_code == 200, response.status_code
-        assert 'The i18n meeting is ' in response.data, response.data
+        self.assertEqual(200, response.status_code)
+        self.assertIn('The i18n meeting is ', response.data)

From 1b7e63b601675cc02b515d02cd34368b68dff137 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jun 21 2016 13:19:44 +0000
Subject: [PATCH 498/1001] Fixing model relation ship


---

1. when running delete-user.py with the hubs section commented out. When I enter user: `decause` to delete. From the db I see that the users table and associations table is affected and the hub is still around like predicted

2. This is with user already deleted. When I uncomment the hubs section from delete-user.py and enter user: `decause` to delete hub. The db hub row is gone and all its widgets are also all deleted.

3. With user still in db. From the db widgets, hubs. Association is missing the rows with decause in it but decause is still found in the users table just like we want

---

diff --git a/hubs/models.py b/hubs/models.py
index 32580a6..ee52937 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -107,8 +107,8 @@ class Association(BASE):
                         primary_key=True)
     role = sa.Column(sa.Enum(*roles), primary_key=True)
 
-    user = relation("User", backref=backref('associations', cascade="all, delete-orphan"))
-    hub = relation("Hub", backref=backref('associations', cascade="all, delete-orphan"))
+    user = relation("User", backref=backref('associations', cascade="all, delete"))
+    hub = relation("Hub", backref=backref('associations', cascade="all, delete"))
 
     @classmethod
     def get(cls, session, hub, user, role):
@@ -124,8 +124,7 @@ class Hub(BASE):
     name = sa.Column(sa.String(50), primary_key=True)
     summary = sa.Column(sa.String(128))
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
-    widgets = relation('Widget', cascade='all,delete-orphan', single_parent=True,
-                       backref=backref('hub', cascade='all'))
+    widgets = relation('Widget', cascade='all,delete', backref='hub')
     left_width = sa.Column(sa.Integer, nullable=False, default=8)
     archived = sa.Column(sa.Boolean, default=False)
     user_hub = sa.Column(sa.Boolean, default=False)

From 7a8d6257b57e5e9a297a5cd75b1265b33f9a7f85 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jun 21 2016 17:36:14 +0000
Subject: [PATCH 499/1001] adding unittests to model modification


removed the long comment

---

diff --git a/hubs/models.py b/hubs/models.py
index ee52937..681048b 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -306,6 +306,10 @@ class Widget(BASE):
     def by_plugin(cls, session, plugin):
         return session.query(cls).filter_by(plugin=plugin).first()
 
+    @classmethod
+    def by_hub_id_all(cls, session, hub_id):
+        return session.query(cls).filter_by(hub_id=hub_id).all()
+
     get = by_idx
 
     @property
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
new file mode 100644
index 0000000..c836a51
--- /dev/null
+++ b/hubs/tests/test_models.py
@@ -0,0 +1,98 @@
+import hubs
+import hubs.models
+import hubs.tests
+import fedmsg.config
+
+fedmsg_config = fedmsg.config.load_config()
+
+
+class ModelTest(hubs.tests.APPTest):
+    def test_delete_user(self):
+        self.session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+
+        # verify user exists
+        username = 'ralph'
+        openid = '%s.id.fedoraproject.org' % username
+        user = hubs.models.User.get(self.session, openid)
+        self.assertIsNotNone(user)
+
+        # check if association exists
+        hub = hubs.models.Hub.get(self.session, username)
+        assoc = hubs.models.Association.get(self.session, hub, user, 'owner')
+        self.assertIsNotNone(assoc)
+
+        # delete the user
+        self.session.delete(user)
+        user = hubs.models.User.get(self.session, openid)
+        self.assertIsNone(user)
+
+        # checking to see if the hub is still intact
+        hub = hubs.models.Hub.get(self.session, username)
+        self.assertIsNotNone(hub)
+        self.assertEqual('ralph', hub.name)
+
+        # check if widgets still are intact
+        widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
+        self.assertEqual(8, len(widgets))
+
+    def test_delete_hubs(self):
+        self.session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+
+        # verify the hub exists
+        hub_name = 'ralph'
+        hub = hubs.models.Hub.get(self.session, hub_name)
+        self.assertIsNotNone(hub)
+
+        # check if association exists
+        username = 'ralph'
+        openid = '%s.id.fedoraproject.org' % username
+        user = hubs.models.User.get(self.session, openid)
+        assoc = hubs.models.Association.get(self.session, hub, user, 'owner')
+        self.assertIsNotNone(assoc)
+
+        # check if widgets exist
+        widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
+        self.assertEqual(8, len(widgets))
+
+        # delete the hub
+        self.session.delete(hub)
+
+        # check if association is removed
+        assoc = hubs.models.Association.get(self.session, hub, user, 'owner')
+        self.assertIsNone(assoc)
+
+        # check if widgets are removed
+        widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
+        self.assertEqual([], widgets)
+
+        # verify hub is deleted
+        hub = hubs.models.Hub.get(self.session, hub_name)
+        self.assertIsNone(hub)
+
+        # check if user is still intact
+        user = hubs.models.User.get(self.session, openid)
+        self.assertIsNotNone(user)
+        self.assertIn('ralph', user.openid)
+
+    def test_delete_user_then_hubs(self):
+        self.session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+        username = 'ralph'
+        openid = '%s.id.fedoraproject.org' % username
+        user = hubs.models.User.get(self.session, openid)
+        self.assertIsNotNone(user)
+        self.session.delete(user)
+        user = hubs.models.User.get(self.session, openid)
+        self.assertIsNone(user)
+
+        # checking to see if the hub is still intact
+        hub = hubs.models.Hub.get(self.session, username)
+        self.assertIsNotNone(hub)
+
+        self.session.delete(hub)
+
+        # check if widgets are removed
+        widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
+        self.assertEqual([], widgets)
+
+        hub = hubs.models.Hub.get(self.session, username)
+        self.assertIsNone(hub)

From 8a94f66ad3e27eb5713332616a3ac7f14bed6b31 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jun 24 2016 15:17:41 +0000
Subject: [PATCH 500/1001] Implements feed widget in Reactjs


Includes SSE functionality
Fixes JS that was causing errors
New React directory structure

---

diff --git a/.gitignore b/.gitignore
index a8c634a..7787cd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,5 @@ fedmsg.d/credentials.py
 node*
 build/
 scratch/
+
+npm-debug.log
diff --git a/README.rst b/README.rst
index 5ec6862..24d78eb 100644
--- a/README.rst
+++ b/README.rst
@@ -125,7 +125,11 @@ flexibility.  To get this working, you're going to set up:
 
 Start with some required packages::
 
-    $ sudo dnf install postgresql-server python-datanommer-consumer datanommer-commands fedmsg-hub
+    $ sudo dnf install postgresql-server python-datanommer-consumer datanommer-commands fedmsg-hub npm
+
+The Feed Widget runs on React so install those dependencies too::
+
+    $ cd hubs/static/client && npm install
 
 And there are some support libraries you'll also need::
 
@@ -184,6 +188,10 @@ will just grow and grow over time::
     [2015-07-01 14:33:21][    fedmsg    INFO] copr has 6 entries
     [2015-07-01 14:33:21][    fedmsg    INFO] askbot has 2 entries
 
+Build JavaScript assets. Add ``--w`` for live reloading::
+
+    $ cd hubs/static/client && node_modules/.bin/webpack
+
 **Lastly**, (fingers crossed) start up the fedora-hubs webapp and load your
 profile page.  Once there are some messages that get into your local database
 that *should* show up on your feed.. they should appear there.  (At very least,
diff --git a/ev-server/hubs-stream-server.py b/ev-server/hubs-stream-server.py
new file mode 100644
index 0000000..56d5b50
--- /dev/null
+++ b/ev-server/hubs-stream-server.py
@@ -0,0 +1,134 @@
+# encoding=utf8
+'''
+This file is for development purposes only.
+
+The end goal is for the streaming server to be implemented on the FMN side
+'''
+import json
+import logging
+import sys
+import trollius
+import trollius_redis
+import urllib2
+from concurrent.futures import TimeoutError
+from trollius import From
+
+reload(sys)
+sys.setdefaultencoding('utf8')
+
+log = logging.getLogger(__name__)
+SERVER = None
+REDIS_HOST = '0.0.0.0'
+REDIS_PORT = 6379
+REDIS_DB = 0
+EVENTSOURCE_PORT = 9090
+'''
+you need to
+
+pip install trollius trollius_redis
+
+dnf install redis httpie
+systemctl start redis
+
+
+usage: http get 0.0.0.0:9090/
+
+'''
+
+
+def get_recent_posts():
+    delta = "delta=86400"  # one day worth of data
+    rows_per_page = "rows_per_page=50"
+    url = "https://apps.fedoraproject.org/datagrepper/raw" + "?" + delta + "&" + rows_per_page
+    request = urllib2.Request(url)
+    contents = urllib2.urlopen(request).read()
+    json_response = json.loads(contents)
+    return json_response['raw_messages']
+
+
+@trollius.coroutine
+def handle_client(client_reader, client_writer):
+    origin = '*'
+    if origin.endswith('/'):
+        origin = origin[:-1]
+
+    client_writer.write(("HTTP/1.0 200 OK\n"
+                         "Content-Type: text/event-stream\n"
+                         "Cache: nocache\n"
+                         "Connection: keep-alive\n"
+                         "Access-Control-Allow-Origin: %s\n\n" % origin
+                         ).encode())
+
+    connection = yield trollius.From(trollius_redis.Connection.create(
+        host=REDIS_HOST, port=REDIS_PORT,
+        db=REDIS_DB))
+
+    try:
+        posts = get_recent_posts()
+
+        # send 50 latest posts
+        num_post_sent = 0
+        while num_post_sent < 50:
+            reply = posts[num_post_sent]
+            reply = json.dumps(reply)
+            log.info(reply)
+            log.info("Sending post %s %s", str(num_post_sent), reply)
+            client_writer.write(('data: %s\n\n' % reply).encode())
+            yield trollius.From(client_writer.drain())
+            num_post_sent += 1
+            yield From(trollius.sleep(2))
+
+    except trollius.ConnectionResetError:
+        log.exception("ERROR: ConnectionResetError in handle_client")
+    except Exception:
+        log.exception("ERROR: Exception in handle_client")
+    finally:
+        # Wathever happens, close the connection.
+        connection.close()
+        client_writer.close()
+
+
+def main():
+    global SERVER
+
+    try:
+        loop = trollius.get_event_loop()
+        coro = trollius.start_server(handle_client,
+                                     host=None,
+                                     port=EVENTSOURCE_PORT,
+                                     loop=loop)
+        SERVER = loop.run_until_complete(coro)
+        log.info('Serving server at {}'.format(SERVER.sockets[0].getsockname(
+        )))
+        loop.run_forever()
+    except KeyboardInterrupt:
+        pass
+    except trollius.ConnectionResetError as err:
+        log.exception("ERROR: ConnectionResetError in main")
+    except Exception as err:
+        log.exception("ERROR: Exception in main")
+    finally:
+        # Close the server
+        SERVER.close()
+        log.info("End Connection")
+        loop.run_until_complete(SERVER.wait_closed())
+        loop.close()
+        log.info("End")
+
+
+if __name__ == '__main__':
+    log = logging.getLogger("")
+    formatter = logging.Formatter(
+        "%(asctime)s %(levelname)s [%(module)s:%(lineno)d] %(message)s")
+
+    # setup console logging
+    log.setLevel(logging.DEBUG)
+    ch = logging.StreamHandler()
+    ch.setLevel(logging.DEBUG)
+
+    aslog = logging.getLogger("asyncio")
+    aslog.setLevel(logging.DEBUG)
+
+    ch.setFormatter(formatter)
+    log.addHandler(ch)
+    main()
diff --git a/hubs/app.py b/hubs/app.py
index 64e6b91..1f30e15 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -14,6 +14,7 @@ import six
 
 from flask.ext.openid import OpenID
 
+import fmn.lib
 import hubs.models
 import hubs.widgets
 
@@ -665,17 +666,27 @@ def markup_fedmsg():
         plugin = flask.request.args['plugin']
     except KeyError:
         return flask.abort(400)
+
     widget = hubs.models.Widget.by_plugin(session, plugin)
+
     if not widget:
         return flask.abort(400)
+
     context = widget.config.get('fmn_context')
+
     messages = []
     message = json.loads(data)
+
+    if 'topic' not in message:
+        return flask.abort(400)
+
     try:
         nickname = flask.g.auth.nickname
-    except AttributeError:  # Not logged in
+    except AttributeError:      # Not logged in
         return flask.abort(403)
+
     preference = get_remote_preference(nickname, context)
+
     if preference:
         try:
             preference = rehydrate_preference(preference)
@@ -686,6 +697,7 @@ def markup_fedmsg():
     if recipients:
         messages.append(message)
     matches = fedmsg.meta.conglomerate(messages, lexers=True, **fedmsg_config)
+
     for match in matches:
         match['markup'] = apply_markup(match)
         for _, constituent in match['msg_ids'].items():
@@ -700,6 +712,8 @@ def markup_fedmsg():
                 else:
                     markup = u"<h5>{long_form}</h5>".format(**constituent)
                     constituent['long_form'] = markup
+
         # And tack on a unique identifier for each top level entry.
         match['dom_id'] = six.text_type(uuid.uuid4())
+
     return flask.jsonify(matches)
diff --git a/hubs/static/client/.babelrc b/hubs/static/client/.babelrc
new file mode 100644
index 0000000..9926dbe
--- /dev/null
+++ b/hubs/static/client/.babelrc
@@ -0,0 +1,5 @@
+{
+  "presets" : ["es2015", "react"],
+  "plugins": ["transform-class-properties"]
+}
+
diff --git a/hubs/static/client/app/components/Constituent.jsx b/hubs/static/client/app/components/Constituent.jsx
new file mode 100644
index 0000000..17896a1
--- /dev/null
+++ b/hubs/static/client/app/components/Constituent.jsx
@@ -0,0 +1,52 @@
+import React from 'react';
+
+export default class Constituent extends React.Component {
+    render() {
+        const match = this.props.match;
+        const hasConstituent = (match['msg_ids'].length === 1 && Object.keys(match['msg_ids'])[0]['long_form'] !== Object.keys(match['msg_ids'])[0]['subtitle']);
+        if ( hasConstituent ) {
+            const constituentKey = Object.keys(match['msg_ids'])[0];
+            const constituent = match['msg_ids'][constituentKey];
+            const differentIcon = constituent['icon'] != constituent['__icon__'];
+            const longLink = ( constituent['link'] && constituent['long_form'].indexOf(constituent['link']) === -1 );
+
+            let constituentIcon;
+            if (differentIcon)
+                constituentIcon = (
+                    <div className="media-left media-top">
+                        <a href={constituent['link']}>
+                            <img className="media-object" src={constituent['icon']} alt={constituent['subtitle']}/>
+                        </a>
+                    </div>
+
+                )
+
+            let readMore;
+            if(longLink)
+                readMore = (
+                    <div className="media-body">
+                        {constituent['long_form']}
+                        <a href={constituent['link']} target="_blank">
+                            Read more <span class="glyphicon glyphicon-new-window"></span>
+                        </a>
+                    </div>
+                )
+
+            return (
+                <div id="content-{{match['dom_id']}}" className="media">
+                    <ExpandCollapse match={this.props.match} />
+                    {constituentIcon}
+                    {readMore}
+                </div>
+            )
+        } else if (match['msg_ids'].length > 1) {
+            <div id="content-{{match['dom_id']}}" className="media">
+                <ExpandCollapse match={this.props.match} />
+                <MessageList msgs={this.match['msg_ids']} />
+            </div>
+        }
+        else {
+            return null
+        }
+    }
+}
diff --git a/hubs/static/client/app/components/ExpandCollapse.jsx b/hubs/static/client/app/components/ExpandCollapse.jsx
new file mode 100644
index 0000000..80ab303
--- /dev/null
+++ b/hubs/static/client/app/components/ExpandCollapse.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+
+export default class ExpandCollapse extends React.Component {
+    render() {
+        return (
+            <div className="pull-right">
+                <a id="expand-{this.props.match['dom_id']}" href="javascript:expand_feed_entries({this.props.match['dom_id']});" className="hidden">
+                    <span className="glyphicon glyphicon-chevron-down"></span>
+                    expand
+                </a>
+                <a id="collapse-{this.props.match['dom_id']}" href="javascript:collapse_feed_entries('{this.props.match['dom_id']}');">
+                    <span className="glyphicon glyphicon-chevron-up"></span>
+                    collapse
+                </a>
+            </div>
+        )
+    }
+}
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
new file mode 100644
index 0000000..9e6cccb
--- /dev/null
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import {render} from 'react-dom';
+
+
+import Constituent from './Constituent.jsx';
+import ExpandCollapse from './ExpandCollapse.jsx';
+import Icon from './Icon.jsx';
+import Markup from './Markup.jsx';
+import {Message, MessageList} from './Messages.jsx';
+
+
+class Panel extends React.Component {
+    render() {
+        return (
+            <div className="panel panel-default">
+                <div className="panel-body">
+                    <Icon match={this.props.match} />
+                    <Markup match={this.props.match} />
+                    <Constituent match={this.props.match} />
+                </div>
+            </div>
+        );
+    }
+}
+
+export default class Feed extends React.Component {
+    constructor (props) {
+        super(props);
+        this.state = {
+            matches: this.props.matches,
+            sse: true,
+        }
+        this.source = (!!window.EventSource) ? new EventSource('http://localhost:9090') : {};
+        this.source.addEventListener('error', () => {
+            this.state.sse = false;
+        }, false);
+        window.onbeforeunload = () => {
+            this.source.close();
+        }
+        this.source.addEventListener('message', resp => {
+            $.get('/api/fedmsg/markup', {
+                message: resp.data,
+                plugin: 'feed',
+            }).done(data => {
+                if(!$.isEmptyObject(data)) {
+                    this.state.matches.push.apply(this.state.matches, data);
+                    this.setState({matches: this.state.matches});
+                }
+            });
+        }, false);
+    }
+    render() {
+        const feedNodes = this.state.matches.map(match => {
+            return <Panel match={match}/>
+        });
+        return (
+            <div>
+                {feedNodes}
+            </div>
+        )
+    }
+}
+
+
+window.Feed = Feed;
+window.React = React;
+window.reactRender = render;
diff --git a/hubs/static/client/app/components/Icon.jsx b/hubs/static/client/app/components/Icon.jsx
new file mode 100644
index 0000000..577050e
--- /dev/null
+++ b/hubs/static/client/app/components/Icon.jsx
@@ -0,0 +1,15 @@
+import React from 'react';
+
+export default class Icon extends React.Component {
+    render() {
+        return (
+            <div>
+                <div className="media-left">
+                    <a href={this.props.match['link'] ? this.props.match['link'] : '#'} target="_blank">
+                        <img className="media-object square-32 img-circle" src={this.props.match['secondary_icon']} />
+                    </a>
+                </div>
+            </div>
+        )
+    }
+}
diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
new file mode 100644
index 0000000..45ccbe3
--- /dev/null
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+
+export default class Markup extends React.Component {
+    createMarkup() {
+        return {__html: this.props.match['markup']};
+    }
+    render() {
+        return (
+            <div className="media-body">
+                <h4 className="media-heading"
+                    dangerouslySetInnerHTML={this.createMarkup()}
+                ></h4>
+                {this.props.match['human_time']}
+            </div>
+        )
+    }
+}
diff --git a/hubs/static/client/app/components/Messages.jsx b/hubs/static/client/app/components/Messages.jsx
new file mode 100644
index 0000000..f034a87
--- /dev/null
+++ b/hubs/static/client/app/components/Messages.jsx
@@ -0,0 +1,36 @@
+import React from 'react';
+
+class Message extends React.Component {
+    render() {
+        if(this.props.constituent['link']) {
+            return (
+                <li>
+                    {this.props.constituent['markup']}
+                    <a href={this.props.constituent['link']} target="_blank">
+                        <span className="glyphicon glyphicon-new-window"></span>
+                    </a>
+                </li>
+            )
+        } else {
+            return (<li>{ this.props.constituent['markup'] }</li>)
+        }
+    }
+}
+
+class MessageList extends React.Component {
+    render() {
+        const messageNodes =  this.props.items.map(function(item) {
+            return <Message constituent={item}/>;
+        });
+        return (
+            <ul id="content-{this.props.match['dom_id']}" className="hidden list-unstyled">
+                {messageNodes}
+            </ul>
+        )
+    }
+}
+
+module.exports = {
+    Message: Message,
+    MessageList: MessageList
+}
diff --git a/hubs/static/client/app/index.jsx b/hubs/static/client/app/index.jsx
new file mode 100644
index 0000000..d169745
--- /dev/null
+++ b/hubs/static/client/app/index.jsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import { render } from 'react-dom';
+
+import Feed from './components/Feed.jsx'
+
+
+render(
+    <Feed matches={[]} />,
+    document.getElementById('feed')
+);
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
new file mode 100644
index 0000000..abb023a
--- /dev/null
+++ b/hubs/static/client/package.json
@@ -0,0 +1,33 @@
+{
+  "name": "fedora-hubs",
+  "version": "0.0.0",
+  "description": "Fedora Hubs will provide a communication and collaboration center for Fedora contributors of all types. The idea is that contributors will be able to visit Hubs to check on their involvements across Fedora, discover new places that they can contribute, and more.",
+  "main": "webpack.config.js",
+  "directories": {
+    "doc": "docs"
+  },
+  "dependencies": {
+    "babel-core": "~6.9.1",
+    "babel-loader": "~6.2.4",
+    "babel-preset-es2015": "~6.9.0",
+    "babel-preset-react": "~6.5.0",
+    "react": "~15.1.0",
+    "react-dom": "~15.1.0",
+    "reactify": "~1.1.1",
+    "webpack": "~1.13.1"
+  },
+  "devDependencies": {
+    "eslint-config-airbnb": "~9.0.1",
+    "eslint-plugin-react": "~5.2.1",
+    "eslint-plugin-jsx-a11y": "~1.5.3",
+    "eslint-plugin-import": "~1.8.1",
+    "eslint": "~2.12.0"
+  },
+  "scripts": {
+    "dev": "webpack --watch",
+    "build": "webpack -p",
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "BSD"
+}
diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
new file mode 100644
index 0000000..065ce2f
--- /dev/null
+++ b/hubs/static/client/webpack.config.js
@@ -0,0 +1,27 @@
+const webpack = require('webpack');
+const path = require('path');
+
+const PATHS = {
+    app: path.join(__dirname, 'app'),
+    build: path.join(__dirname, '../js')
+};
+
+const config = {
+    entry: {
+        app: path.join(PATHS.app, 'index.jsx')
+    },
+    output: {
+        path: PATHS.build,
+        filename: 'hubs.js'
+    },
+    module : {
+        loaders : [{
+            test : /\.jsx?$/,
+            loader : 'babel',
+            exclude: /(node_modules|bowercomponents)/,
+            include : PATHS.app
+        }]
+    }
+};
+
+module.exports = config;
diff --git a/hubs/tests/test_widgets/test_feed.py b/hubs/tests/test_widgets/test_feed.py
new file mode 100644
index 0000000..88e4913
--- /dev/null
+++ b/hubs/tests/test_widgets/test_feed.py
@@ -0,0 +1,74 @@
+import json
+
+import hubs.tests.test_widgets
+from hubs.widgets.feed import PythonObjectEncoder
+
+
+encode = lambda o: json.dumps(o, cls=PythonObjectEncoder)
+
+class TestPythonObjectEncoder(hubs.tests.test_widgets.WidgetTest):
+    def test_python_object_encoder_encodes_set(self):
+        data = set([1,2,3, 'bar', 'foo'])
+        expected_str = '[1, 2, 3, "bar", "foo"]'
+        expected_list = list(data)
+
+        encoded = encode(data)
+        self.assertEqual(encoded, expected_str)
+
+        decoded = json.loads(encoded)
+        self.assertEqual(expected_list, decoded)
+
+    def test_python_object_encoder_encodes_tuple(self):
+        data = ('foo', 'bar', 'baz', 1)
+        expected_str = '["foo", "bar", "baz", 1]'
+        expected_list = list(data)
+
+        encoded = encode(data)
+        self.assertEqual(encoded, expected_str)
+
+        decoded = json.loads(encoded)
+        self.assertEqual(expected_list, decoded)
+
+
+    def test_python_object_encoder_encodes_object(self):
+        class Test(object):
+            def __init__(self):
+                self.x = 'x'
+
+        data = Test()
+        expected_str = '{"x": "x"}'
+        expected_dict = data.__dict__
+        encoded = encode(data)
+        self.assertEqual(encoded, expected_str)
+
+        decoded = json.loads(encoded)
+        self.assertEqual(expected_dict, decoded)
+
+    def test_python_object_encoder_encodes_deep_dict(self):
+        data = {
+            'some_dict': {
+                'one': 1,
+                'aset': set(['two', 'three']),
+                'four': 4.0,
+                'tupe': (5,6),
+            },
+            'regular': 'string'
+        }
+        expected_str = '{"some_dict": {"four": 4.0, "tupe": [5, 6], "aset": ["two", "three"], "one": 1}, "regular": "string"}'
+
+        expected_dict = {
+            'some_dict': {
+                'one': 1,
+                'aset': ['two', 'three'],
+                'four': 4.0,
+                'tupe': [5,6],
+            },
+            'regular': 'string'
+        }
+
+        encoded = encode(data)
+        self.assertEqual(expected_str, encoded)
+
+        decoded = json.loads(encoded)
+        self.assertEqual(expected_dict, decoded)
+
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index f40e453..c6e3797 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -21,6 +21,7 @@ import flask
 import hubs.validators as validators
 
 import datetime
+import json
 import logging
 import uuid
 
@@ -30,13 +31,12 @@ import fedmsg.config
 config = fedmsg.config.load_config()
 fmn_url = config['fmn.url']
 
-
 bazillion = 1000
 paths = fmn.lib.load_rules(root='fmn.rules')
 
 # No chrome around the feed.
-#from hubs.widgets.chrome import panel
-#chrome = panel()
+# from hubs.widgets.chrome import panel
+# chrome = panel()
 template = templating.environment.get_template('templates/feed.html')
 position = 'left'
 
@@ -50,7 +50,7 @@ def apply_markup(match):
         ))
         markup = markup.replace(*args)
         # TODO -- have to add these to conglomerate first
-        #match['long_form'] = match['long_form'].replace(*args)
+        # match['long_form'] = match['long_form'].replace(*args)
 
     for package in match['packages']:
         args = (package, '<a href="{url}">{package}</a>'.format(
@@ -59,11 +59,25 @@ def apply_markup(match):
         ))
         markup = markup.replace(*args)
         # TODO -- have to add these to conglomerate first
-        #match['long_form'] = match['long_form'].replace(*args)
+        # match['long_form'] = match['long_form'].replace(*args)
 
     return markup
 
 
+class PythonObjectEncoder(json.JSONEncoder):
+    ''' A JSON encoder that handles python data structures in encoding'''
+    def default(self, obj):
+        if isinstance(obj, (list, dict, str, unicode, int, float, bool,
+                            type(None))):
+            return json.JSONEncoder.default(self, obj)
+        if isinstance(obj, set) or isinstance(obj, tuple):
+            return list(obj)
+        if isinstance(obj, object):
+            return obj.__dict__
+        else:
+            raise TypeError
+
+
 @argument(name="username",
           default=None,
           validator=validators.username,
@@ -95,7 +109,7 @@ def data(session, widget, username, fmn_context):
             rules = filter['rules']
             fmn_hinting = fmn.lib.hinting.gather_hinting(config, rules, paths)
             total, pages, rows = datanommer.models.Message.grep(
-                start=end-delta,
+                start=end - delta,
                 end=end,
                 rows_per_page=bazillion,
                 page=page,
@@ -136,10 +150,8 @@ def data(session, widget, username, fmn_context):
 
         # And tack on a unique identifier for each top level entry.
         match['dom_id'] = six.text_type(uuid.uuid4())
-
-    return dict(
-        matches=matches,
-    )
+    matches = json.dumps(matches, cls=PythonObjectEncoder)
+    return dict(matches=matches)
 
 
 @hint(ubiquitous=True)
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index 534a51a..00fc7e2 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -1,74 +1,15 @@
-{% for match in matches %}
-<div class="panel panel-default">
-  <div class="panel-body">
-    <div class="media">
-      <div class="media-left">
-        <a href="{{match['link']}}" target="_blank">
-          <img class="media-object square-32 img-circle" src="{{match['secondary_icon']}}">
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">{{match['markup']}}</h4>
-        {{match['human_time']}}
+<div id="feed">
+</div>
 
+<script type="text/javascript"
+        src ="{{url_for('static', filename='js/hubs.js')}}"></script>
+<script>
+ (function() {
+     const FeedElement = React.createElement(Feed, {
+         matches: {{ matches }}
+     });
 
-        {% if match['msg_ids'] | length == 1 and match['msg_ids'].values()[0].get('long_form') != match['msg_ids'].values()[0]['subtitle'] %}
-            {% set constituent = match['msg_ids'].values()[0] %}
-            <div class="pull-right">
-                <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');" class="hidden">
-                    <span class="glyphicon glyphicon-chevron-down"></span>
-                    expand
-                </a>
-                <a id="collapse-{{match['dom_id']}}" href="javascript:collapse_feed_entries('{{match['dom_id']}}');">
-                    <span class="glyphicon glyphicon-chevron-up"></span>
-                    collapse
-                </a>
-            </div>
+     reactRender(FeedElement, document.getElementById('feed'));
+ })();
 
-            <div id="content-{{match['dom_id']}}" class="media">
-              {% if constituent['icon'] != constituent.get('__icon__') %}
-              <div class="media-left media-top">
-                <a href="{{constituent['link']}}">
-                  <img class="media-object" src="{{constituent['icon']}}" alt="{{constituent['subtitle']}}">
-                </a>
-              </div>
-              {% endif %}
-              <div class="media-body">
-                  {{constituent['long_form']}}
-                    {% if constituent['link'] and constituent['link'] not in constituent['long_form'] %}
-                    <a href="{{constituent['link']}}" target="_blank">
-                        Read more <span class="glyphicon glyphicon-new-window"></span>
-                    </a>
-                    {% endif %}
-              </div>
-            </div>
-        {% endif %}
-        {% if match['msg_ids'] | length > 1 %}
-            <div class="pull-right">
-                <a id="expand-{{match['dom_id']}}" href="javascript:expand_feed_entries('{{match['dom_id']}}');">
-                    <span class="glyphicon glyphicon-chevron-down"></span>
-                    expand
-                </a>
-                <a id="collapse-{{match['dom_id']}}" href="javascript:collapse_feed_entries('{{match['dom_id']}}');" class="hidden">
-                    <span class="glyphicon glyphicon-chevron-up"></span>
-                    collapse
-                </a>
-            </div>
-            <ul id="content-{{match['dom_id']}}" class="hidden list-unstyled">
-                {% for idx, constituent in match['msg_ids'].items() %}
-                <li>
-                    {{ constituent['markup'] }}
-                    {% if constituent['link'] %}
-                    <a href="{{constituent['link']}}" target="_blank">
-                        <span class="glyphicon glyphicon-new-window"></span>
-                    </a>
-                    {% endif %}
-                </li>
-                {% endfor %}
-            </ul>
-        {% endif %}
-      </div>
-    </div>
-  </div>
-</div>
-{% endfor %}
+</script>

From 9fa7eab5f66fb47f6e817574c13a0767246dbb03 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 09:55:41 +0000
Subject: [PATCH 501/1001] Replace openid by username in the model


With the move from openid to openid-connect, there are no more openid url
that we can rely on.
Apparently, there is also nothing else than the username we can use that
would uniquely identify the user while being stable over multiple hosts.

---

diff --git a/hubs/models.py b/hubs/models.py
index 681048b..ad3bc16 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -45,13 +45,13 @@ from hubs.utils import username2avatar
 
 
 class HubsBase(object):
-    def notify(self, openid, changed):
+    def notify(self, username, changed):
         obj = type(self).__name__.lower()
         topic = obj + ".update"
         fedmsg.publish(
             topic=topic,
             msg=dict(
-                openid=openid,
+                username=username,
                 changed=changed,
             )
         )
@@ -103,7 +103,7 @@ class Association(BASE):
                        sa.ForeignKey('hubs.name'),
                        primary_key=True)
     user_id = sa.Column(sa.Text,
-                        sa.ForeignKey('users.openid'),
+                        sa.ForeignKey('users.username'),
                         primary_key=True)
     role = sa.Column(sa.Enum(*roles), primary_key=True)
 
@@ -350,14 +350,13 @@ class Widget(BASE):
 
 class User(BASE):
     __tablename__ = 'users'
-    openid = sa.Column(sa.Text, primary_key=True)
+    username = sa.Column(sa.Text, primary_key=True)
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
     def __json__(self, session):
         return {
             'username': self.username,
-            'openid': self.openid,
             'avatar': username2avatar(self.username),
             'fullname': self.fullname,
             'created_on': self.created_on,
@@ -396,32 +395,24 @@ class User(BASE):
             and assoc.hub.name != self.username
         ])), key=operator.attrgetter('name'))
 
-    @property
-    def username(self):
-        return self.openid.split('.')[0]
-
     @classmethod
     def by_username(cls, session, username):
-        return cls.by_openid(session, "%s.id.fedoraproject.org" % username)
-
-    @classmethod
-    def by_openid(cls, session, openid):
-        return session.query(cls).filter_by(openid=openid).first()
+        return session.query(cls).filter_by(username=username).first()
 
-    get = by_openid
+    get = by_username
 
     @classmethod
     def all(cls, session):
         return session.query(cls).all()
 
     @classmethod
-    def get_or_create(cls, session, openid, fullname):
-        if not openid:
-            raise ValueError("Must provide openid, not %r" % openid)
+    def get_or_create(cls, session, username, fullname):
+        if not username:
+            raise ValueError("Must provide an username, not %r" % username)
 
-        self = cls.by_openid(session, openid)
+        self = cls.by_username(session, username)
         if not self:
-            self = cls(openid=openid, fullname=fullname)
+            self = cls(username=username, fullname=fullname)
             session.add(self)
             if not Hub.by_name(session, self.username):
                 Hub.create_user_hub(session, self.username, self.fullname)

From 3060feaa92bd94f4735420cefab1d286e15485bf Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 10:02:40 +0000
Subject: [PATCH 502/1001] Start porting hubs to OpenID-Connect from OpenID


---

diff --git a/hubs/app.py b/hubs/app.py
index 1f30e15..81c77d6 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -12,7 +12,7 @@ import munch
 import pygments.formatters
 import six
 
-from flask.ext.openid import OpenID
+from flask.ext.oidc import OpenIDConnect
 
 import fmn.lib
 import hubs.models
@@ -447,15 +447,12 @@ def widget_source(name):
 
 
 # Set up OpenID in stateless mode
-oid = OpenID(app,
-             safe_roots=[],
-             store_factory=lambda: None,
-             url_root_as_trust_root=True)
+FAS = OpenIDConnect(app, credentials_store=flask.session )
 
 
 @app.route('/login/', methods=('GET', 'POST'))
 @app.route('/login', methods=('GET', 'POST'))
-@oid.loginhandler
+@FAS.require_login
 def login():
     default = flask.url_for('index')
     next_url = flask.request.args.get('next', default)
@@ -530,21 +527,29 @@ def login_required(function):
 
 @app.before_request
 def check_auth():
+    flask.session.permanent = True
     flask.g.fedmsg_config = fedmsg_config
-    flask.g.auth = munch.Munch(logged_in=False)
-    if 'openid' in flask.session:
-        openid = flask.session.get('openid')
-        if isinstance(openid, six.binary_type):
-            openid = openid.decode('utf-8')
-        openid = openid.strip('/').split('/')[-1]
-        flask.g.auth.logged_in = True
-        flask.g.auth.openid = openid
-        flask.g.auth.user = hubs.models.User.by_openid(session, openid)
-        flask.g.auth.openid_url = flask.session.get('openid')
-        flask.g.auth.fullname = flask.session.get('fullname', None)
-        flask.g.auth.nickname = flask.session.get('nickname', None)
-        flask.g.auth.email = flask.session.get('email', None)
-        flask.g.auth.avatar = username2avatar(flask.g.auth.nickname)
+
+    if FAS.user_loggedin:
+        if not hasattr(flask.session, 'fas_user') or not flask.session.fas_user:
+            flask.session.auth = munch.Munch(
+                fullname=FAS.user_getfield('name'),
+                nickname=FAS.user_getfield('nickname'),
+                email=FAS.user_getfield('email'),
+                timezone=FAS.user_getfield('zoneinfo'),
+                cla_done=\
+                    'http://admin.fedoraproject.org/accounts/cla/done' \
+                    in FAS.user_getfield('cla'),
+                groups=FAS.user_getfield('groups'),
+                logged_in=True,
+            )
+            flask.session.auth.avatar=username2avatar(
+                flask.session.auth.nickname)
+            flask.session.auth.user = hubs.models.User.by_username(
+                session, flask.session.auth.nickname)
+        flask.g.auth = flask.session.auth
+    else:
+        flask.g.auth = munch.Munch(logged_in=False)
 
 
 def get_hub(session, name):
diff --git a/hubs/default_config.py b/hubs/default_config.py
index a21f138..b0d3eb7 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -1,3 +1,5 @@
+import os
+
 SECRET_KEY = 'changemeforreal'
 
 PROMOTED_GROUPS = [
@@ -6,3 +8,11 @@ PROMOTED_GROUPS = [
 ]
 
 HUB_OF_THE_MONTH = 'commops'
+
+
+OIDC_CLIENT_SECRETS = os.path.join(os.path.dirname(
+    os.path.abspath(__file__)), '..', 'client_secrets.json')
+OIDC_ID_TOKEN_COOKIE_SECURE = False
+OIDC_REQUIRE_VERIFIED_EMAIL = False
+OIDC_OPENID_REALM = 'http://localhost:5000/oidc_callback'
+OIDC_SCOPES = ['openid', 'email', 'profile', 'fedora']

From 80cb43833a8e9dd4bf88e70afb4337d70451f6c5 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 10:04:07 +0000
Subject: [PATCH 503/1001] Add a method to check if a given URL is safe to return to


---

diff --git a/hubs/app.py b/hubs/app.py
index 81c77d6..98c86a1 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -3,6 +3,7 @@ import functools
 import json
 import logging
 import os
+import urlparse
 import uuid
 
 import flask
@@ -75,6 +76,17 @@ def authenticated():
         and flask.g.auth.logged_in
 
 
+def is_safe_url(target):
+    """ Checks that the target url is safe and sending to the current
+    website not some other malicious one.
+    """
+    ref_url = urlparse.urlparse(flask.request.host_url)
+    test_url = urlparse.urlparse(
+        urlparse.urljoin(flask.request.host_url, target))
+    return test_url.scheme in ('http', 'https') and \
+        ref_url.netloc == test_url.netloc
+
+
 @app.template_filter('commas')
 def commas(numeric):
     return "{:,.2f}".format(numeric)

From 82b6b815f3d27d7b9da9abbd97cb05ccd13d048b Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 10:04:51 +0000
Subject: [PATCH 504/1001] Adjust the login and logout pages for OIDC


---

diff --git a/hubs/app.py b/hubs/app.py
index 98c86a1..74c751a 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -101,7 +101,7 @@ def shutdown_session(exception=None):
 @app.route('/')
 def index():
     if not authenticated():
-        return flask.redirect(flask.url_for('login_fedora'))
+        return flask.redirect(flask.url_for('login'))
 
     return flask.redirect(flask.url_for('hub', name=flask.g.auth.nickname))
 
@@ -468,56 +468,33 @@ FAS = OpenIDConnect(app, credentials_store=flask.session )
 def login():
     default = flask.url_for('index')
     next_url = flask.request.args.get('next', default)
-    if authenticated():
-        return flask.redirect(next_url)
-
-    openid_server = flask.request.form.get('openid', None)
-    if openid_server:
-        return oid.try_login(
-            openid_server, ask_for=['email', 'fullname', 'nickname'],
-            ask_for_optional=[])
-
-    return flask.render_template(
-        'login.html', next=oid.get_next_url(), error=oid.fetch_error())
+    if is_safe_url(next_url):
+        return_point = next_url
+    else:
+        return_point = default
 
+    hubs.models.User.get_or_create(
+        session, username=flask.g.auth.user, fullname=flask.g.auth.fullname)
 
-@app.route('/login/fedora/')
-@app.route('/login/fedora')
-@oid.loginhandler
-def login_fedora():
-    # default = flask.url_for('profile_redirect')
-    # next_url = flask.request.args.get('next', default)
-    return oid.try_login(
-        'https://id.fedoraproject.org',
-        ask_for=['email', 'fullname', 'nickname'],
-        ask_for_optional=[])
+    return flask.redirect(return_point)
 
 
 @app.route('/logout/')
 @app.route('/logout')
 def logout():
-    if 'openid' in flask.app.session:
-        flask.app.session.pop('openid')
-    return flask.redirect(flask.url_for('index'))
+    next_url = flask.url_for('index')
+    if 'next' in flask.request.values:  # pragma: no cover
+        if is_safe_url(flask.request.args['next']):
+            next_url = flask.request.values['next']
 
+    if next_url == flask.url_for('auth_login'):  # pragma: no cover
+        next_url = flask.url_for('index')
 
-@oid.after_login
-def after_openid_login(resp):
-    default = flask.url_for('index')
-    if not resp.identity_url:
-        return flask.redirect(default)
-
-    openid_url = resp.identity_url
-    flask.app.session['openid'] = openid_url
-    flask.app.session['fullname'] = resp.fullname
-    flask.app.session['nickname'] = resp.nickname or resp.fullname
-    flask.app.session['email'] = resp.email
-
-    openid = openid_url.strip('/').split('/')[-1]
-    hubs.models.User.get_or_create(
-        session, openid=openid, fullname=resp.fullname)
+    if authenticated():
+        FAS.logout()
+        flask.session.auth = None
+        flask.flash(gettext('You have been logged out'))
 
-    next_url = flask.request.args.get('next', default)
     return flask.redirect(next_url)
 
 
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 899847c..6fce42f 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -37,7 +37,7 @@
         </div>
         <img id="chaticon" class="pull-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
       {% else %}
-        Not logged in.  Click to <a href="{{url_for('login_fedora')}}">login</a>.
+        Not logged in.  Click to <a href="{{url_for('login')}}">login</a>.
       {% endif %}
     </div>
     <div class="col-sm-4 col-sm-pull-4 col-xs-12">

From 2a0657f6a444f2a102493da71d833af5b4681d21 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 10:17:23 +0000
Subject: [PATCH 505/1001] Fix typos in the app controller


---

diff --git a/hubs/app.py b/hubs/app.py
index 74c751a..9f731b3 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -474,7 +474,7 @@ def login():
         return_point = default
 
     hubs.models.User.get_or_create(
-        session, username=flask.g.auth.user, fullname=flask.g.auth.fullname)
+        session, username=flask.g.auth.nickname, fullname=flask.g.auth.fullname)
 
     return flask.redirect(return_point)
 
@@ -487,13 +487,13 @@ def logout():
         if is_safe_url(flask.request.args['next']):
             next_url = flask.request.values['next']
 
-    if next_url == flask.url_for('auth_login'):  # pragma: no cover
+    if next_url == flask.url_for('login'):  # pragma: no cover
         next_url = flask.url_for('index')
 
     if authenticated():
         FAS.logout()
         flask.session.auth = None
-        flask.flash(gettext('You have been logged out'))
+        flask.flash('You have been logged out')
 
     return flask.redirect(next_url)
 

From 1c90812ea4c4157b034f34f14d6433a3b0de8d79 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 10:18:57 +0000
Subject: [PATCH 506/1001] Retrieve the user by its username since there are no more openid url to use


---

diff --git a/hubs/app.py b/hubs/app.py
index 9f731b3..bddaa29 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -458,7 +458,7 @@ def widget_source(name):
     return flask.redirect(SOURCE_URL + fname)
 
 
-# Set up OpenID in stateless mode
+# Set up OpenIDConnect
 FAS = OpenIDConnect(app, credentials_store=flask.session )
 
 
@@ -575,7 +575,7 @@ def get_widget(session, hub, idx):
 @login_required
 def hub_subscribe(hub):
     hub = get_hub(session, hub)
-    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
     hub.subscribe(session, user)
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
@@ -585,7 +585,7 @@ def hub_subscribe(hub):
 @login_required
 def hub_unsubscribe(hub):
     hub = get_hub(session, hub)
-    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
     try:
         hub.unsubscribe(session, user)
     except KeyError:
@@ -598,7 +598,7 @@ def hub_unsubscribe(hub):
 @login_required
 def hub_star(hub):
     hub = get_hub(session, hub)
-    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
     hub.subscribe(session, user, role='stargazer')
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
@@ -608,7 +608,7 @@ def hub_star(hub):
 @login_required
 def hub_unstar(hub):
     hub = get_hub(session, hub)
-    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
     try:
         hub.unsubscribe(session, user, role='stargazer')
     except KeyError:
@@ -621,7 +621,7 @@ def hub_unstar(hub):
 @login_required
 def hub_join(hub):
     hub = get_hub(session, hub)
-    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
     hub.subscribe(session, user, role='member')
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
@@ -631,7 +631,7 @@ def hub_join(hub):
 @login_required
 def hub_leave(hub):
     hub = get_hub(session, hub)
-    user = hubs.models.User.by_openid(session, flask.g.auth.openid)
+    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
     try:
         hub.unsubscribe(session, user, role='member')
     except KeyError:

From baf268ad647f9cfdf304a6c6b648d1038d38ba44 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 10:27:57 +0000
Subject: [PATCH 507/1001] Adjust the username validator since we no longer use username


---

diff --git a/hubs/validators.py b/hubs/validators.py
index f6da8dc..c76c9f2 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -21,8 +21,7 @@ def link(session, value):
 
 
 def username(session, value):
-    openid = 'http://%s.id.fedoraproject.org/' % value
-    return not hubs.models.User.by_openid(session, openid) is None
+    return not hubs.models.User.by_username(session, value) is None
 
 
 def github_organization(session, value):

From 4c24033c3ca53104a7284dd1caec4991e256dbcc Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:05:32 +0000
Subject: [PATCH 508/1001] Fix calls to login_fedora


---

diff --git a/hubs/app.py b/hubs/app.py
index bddaa29..136c844 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -109,7 +109,7 @@ def index():
 @app.route('/groups')
 def groups():
     if not authenticated():
-        return flask.redirect(flask.url_for('login_fedora'))
+        return flask.redirect(flask.url_for('login'))
 
     # Get the list of promoted and non-promoted group hubs from the DB
     promoted_names = app.config.get('PROMOTED_GROUPS')
@@ -507,7 +507,7 @@ def login_required(function):
         if not authenticated():
             flask.flash('Login required', 'errors')
             return flask.redirect(flask.url_for(
-                'login_fedora', next=flask.request.url))
+                'login', next=flask.request.url))
 
         return function(*args, **kwargs)
 

From d907adba437fdc96a16dc7b10380d94581a9ab96 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:06:59 +0000
Subject: [PATCH 509/1001] Adjust the populate script to not use <username>.id.fp.o


This for the change to openid-connect where we no longer use the openid
url

---

diff --git a/populate-from-fas.py b/populate-from-fas.py
index 8c3531b..cab611e 100755
--- a/populate-from-fas.py
+++ b/populate-from-fas.py
@@ -38,19 +38,19 @@ for letter in reversed(sorted(list(set(string.letters.lower())))):
     session = hubs.models.init(
         fedmsg_config['hubs.sqlalchemy.uri'], True, True)
     print "Querying FAS for the %r users.. hang on." % letter
-    request = fasclient.send_request('/user/list',
-                                     req_params={'search': '%s*' % letter},
-                                     auth=True,
-                                     timeout=500)
+    request = fasclient.send_request(
+        '/user/list',
+        req_params={'search': '%s*' % letter, 'status': 'active'},
+        auth=True,
+        timeout=500)
     users = request['people']
 
     for user in users:
         username = user['username']
         fullname = user['human_name']
-        openid = '%s.id.fedoraproject.org' % username
         print "Creating account for %r" % openid
         hubs_user = hubs.models.User.get_or_create(
-            session, openid=openid, fullname=fullname)
+            session, username=username, fullname=fullname)
 
     session.commit()
 
diff --git a/populate.py b/populate.py
index 9762426..8487aa9 100755
--- a/populate.py
+++ b/populate.py
@@ -15,10 +15,9 @@ users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
          'pravins', 'keekri', 'linuxmodder', 'bee2502', 'jflory7']
 for username in users:
     fullname = 'Full Name Goes Here'
-    openid = '%s.id.fedoraproject.org' % username
-    print("Creating account for %r" % openid)
+    print("Creating account for %r" % username)
     hubs.models.User.get_or_create(
-        session, openid=openid, fullname=fullname)
+        session, username=username, fullname=fullname)
 
 session.commit()
 
@@ -59,9 +58,9 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_openid(session, 'pravins.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'pravins'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph'), 'subscriber')
 
 
 session.commit()
@@ -102,11 +101,11 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'jflory7.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'bee2502.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'keekri.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'linuxmodder.id.fedoraproject.org'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'jflory7'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'bee2502'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'keekri'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'linuxmodder'), 'member')
 
 
 session.commit()
@@ -147,12 +146,12 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_openid(session, 'croberts.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'mattdm.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'croberts'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'mattdm'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph'), 'subscriber')
 
 
 session.commit()
@@ -193,13 +192,13 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_openid(session, 'duffy.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'gnokii.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'subscriber')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'duffy'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'gnokii'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph'), 'subscriber')
 
 session.commit()
 
@@ -239,10 +238,10 @@ widget = hubs.models.Widget(plugin='dummy', index=3, left=True)
 hub.widgets.append(widget)
 
 
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'abompard.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'lmacken.id.fedoraproject.org'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0.id.fedoraproject.org'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause.id.fedoraproject.org'), 'subscriber')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'abompard'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'lmacken'), 'owner')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0'), 'member')
+hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'subscriber')
 
 session.commit()

From e7f108b958bd1a01e495aa7c8a592a29a0c42b53 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:11:57 +0000
Subject: [PATCH 510/1001] Fix tests for /login/fedora which we dropped


---

diff --git a/hubs/tests/test_api/test_hub.py b/hubs/tests/test_api/test_hub.py
index 785aef3..2fd513f 100644
--- a/hubs/tests/test_api/test_hub.py
+++ b/hubs/tests/test_api/test_hub.py
@@ -18,7 +18,7 @@ class TestHubSubscribe(hubs.tests.APPTest):
         resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
+        self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_subscribe_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -39,7 +39,7 @@ class TestHubUnsubscribe(hubs.tests.APPTest):
         resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
+        self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_unsubscribe_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -65,7 +65,7 @@ class TestHubStar(hubs.tests.APPTest):
         resp = self.app.post('/api/hub/{}/star'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
+        self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_star_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -86,7 +86,7 @@ class TestHubUnstar(hubs.tests.APPTest):
         resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
+        self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_unstar_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -113,7 +113,7 @@ class TestHubJoin(hubs.tests.APPTest):
         resp = self.app.post('/api/hub/{}/join'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
+        self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_join_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
@@ -134,7 +134,7 @@ class TestHubLeave(hubs.tests.APPTest):
         resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login/fedora')
+        self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_star_when_logged_in(self):
         hub = hubs.models.Hub.by_name(self.session, 'infra')
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index d9d2325..7500199 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -21,7 +21,7 @@ class HubsAPITest(hubs.tests.APPTest):
     def test_index_logged_out(self):
         result = self.app.get('/', follow_redirects=False)
         self.assertEqual(result.status_code, 302)
-        self.assertEqual(urlparse(result.location).path, "/login/fedora")
+        self.assertEqual(urlparse(result.location).path, "/login")
 
     def test_index_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -31,7 +31,7 @@ class HubsAPITest(hubs.tests.APPTest):
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
             self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login/fedora">login</a>' in result.data)
+                             '/login">login</a>' in result.data)
 
     def test_hub_logged_out(self):
         with app.test_request_context('/ralph'):
@@ -42,7 +42,7 @@ class HubsAPITest(hubs.tests.APPTest):
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
             str_expected = 'Not logged in.  Click to ' \
-                           '<a href="/login/fedora">login</a>'
+                           '<a href="/login">login</a>'
             self.assertTrue(str_expected in result.data)
 
     def test_groups_logged_out(self):
@@ -50,7 +50,7 @@ class HubsAPITest(hubs.tests.APPTest):
         # assert the status code of the response
         self.assertEqual(result.status_code, 302)
         # this will redirect to fedora.login
-        self.assertEqual(urlparse(result.location).path, "/login/fedora")
+        self.assertEqual(urlparse(result.location).path, "/login")
 
     def test_groups_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -66,7 +66,7 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get('/ralph', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login/fedora">login</a>' in result.data)
+                             '/login">login</a>' in result.data)
 
     def test_hub_json(self):
         result = self.app.get('/ralph/json', follow_redirects=True)
@@ -134,7 +134,7 @@ class HubsAPITest(hubs.tests.APPTest):
                                    follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login/fedora">login</a>' in result.data)
+                             '/login">login</a>' in result.data)
             self.assertTrue('<a href="#" class="dropdown-item">Full Name: '
                             'fullname: ralph</a>' in result.data)
 
@@ -204,7 +204,9 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             result = self.app.get('/login', follow_redirects=False)
             self.assertEqual(result.status_code, 302)
-            self.assertEqual(urlparse(result.location).path, "/")
+            self.assertEqual(
+                urlparse(result.location).path,
+                "/openidc/Authorization")
 
     def test_hub_add_widget_get_no_args(self):
         result = self.app.get('/ralph/add', follow_redirects=False)

From d3f277a029da435d865a2350fab7d044b712ef47 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:13:53 +0000
Subject: [PATCH 511/1001] Adjust the tests to drop the openid url in favor of the user's nickname


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 5c10118..f9faa42 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -42,10 +42,9 @@ class APPTest(unittest.TestCase):
 
     def populate(self):
         for user in ['devyani7', 'dhrish', 'shalini', 'ralph', 'decause']:
-            openid = '%s.id.fedoraproject.org' % user
             fullname = user.title()
             hubs.models.User.get_or_create(
-                hubs.app.session, openid=openid, fullname=fullname)
+                hubs.app.session, username=user, fullname=fullname)
 
         hubs.app.session.flush()
 
@@ -122,7 +121,6 @@ class FakeUser(object):
             supposed to be.
         """
         self.username = username
-        self.openid = username + '.id.fedoraproject.org'
         self.booksmarks = []
 
     def __getitem__(self, key):
@@ -140,7 +138,6 @@ class FakeAuthorization(object):
         self.logged_in = True
         self.fullname = 'fullname: ' + username
         self.email = 'email: ' + username
-        self.openid = username + '.id.fedoraproject.org'
         self.user = FakeUser(username)
         self.avatar = 'avatar_src_url'
         self.nickname = username
diff --git a/hubs/tests/test_api/test_fedmsg.py b/hubs/tests/test_api/test_fedmsg.py
index d6e67ef..332d4d1 100644
--- a/hubs/tests/test_api/test_fedmsg.py
+++ b/hubs/tests/test_api/test_fedmsg.py
@@ -54,7 +54,6 @@ class TestFeed(hubs.tests.APPTest):
             'plugin': 'feed'
         }
         with self.app.session_transaction() as sess:
-            sess['openid'] = 'atelic@fedoraproject.org'
             sess['nickname'] = 'atelic'
 
         with hubs.tests.auth_set(app, self.user):
@@ -71,7 +70,6 @@ class TestFeed(hubs.tests.APPTest):
             'plugin': 'feed'
         }
         with self.app.session_transaction() as sess:
-            sess['openid'] = 'atelic@fedoraproject.org'
             sess['nickname'] = 'atelic'
 
         with hubs.tests.auth_set(app, self.user):
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index c836a51..47a6eca 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -12,8 +12,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # verify user exists
         username = 'ralph'
-        openid = '%s.id.fedoraproject.org' % username
-        user = hubs.models.User.get(self.session, openid)
+        user = hubs.models.User.get(self.session, username)
         self.assertIsNotNone(user)
 
         # check if association exists
@@ -23,7 +22,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # delete the user
         self.session.delete(user)
-        user = hubs.models.User.get(self.session, openid)
+        user = hubs.models.User.get(self.session, username)
         self.assertIsNone(user)
 
         # checking to see if the hub is still intact
@@ -45,8 +44,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if association exists
         username = 'ralph'
-        openid = '%s.id.fedoraproject.org' % username
-        user = hubs.models.User.get(self.session, openid)
+        user = hubs.models.User.get(self.session, username)
         assoc = hubs.models.Association.get(self.session, hub, user, 'owner')
         self.assertIsNotNone(assoc)
 
@@ -70,18 +68,17 @@ class ModelTest(hubs.tests.APPTest):
         self.assertIsNone(hub)
 
         # check if user is still intact
-        user = hubs.models.User.get(self.session, openid)
+        user = hubs.models.User.get(self.session, username)
         self.assertIsNotNone(user)
-        self.assertIn('ralph', user.openid)
+        self.assertEqual('ralph', user.username)
 
     def test_delete_user_then_hubs(self):
         self.session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
         username = 'ralph'
-        openid = '%s.id.fedoraproject.org' % username
-        user = hubs.models.User.get(self.session, openid)
+        user = hubs.models.User.get(self.session, username)
         self.assertIsNotNone(user)
         self.session.delete(user)
-        user = hubs.models.User.get(self.session, openid)
+        user = hubs.models.User.get(self.session, username)
         self.assertIsNone(user)
 
         # checking to see if the hub is still intact
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 38d77af..b0b7d64 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -36,10 +36,9 @@ class WidgetTest(unittest.TestCase):
 
     def populate(self):
         for user in ['devyani7', 'dhrish', 'shalini', 'ralph', 'decause']:
-            openid = '%s.id.fedoraproject.org' % user
             fullname = user.title()
             hubs.models.User.get_or_create(
-                hubs.app.session, openid=openid, fullname=fullname)
+                hubs.app.session, username=user, fullname=fullname)
 
         hubs.app.session.flush()
 

From 820f95b928e4c36604f6e249f0b437892cddafd6 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:14:24 +0000
Subject: [PATCH 512/1001] Set a g.oidc_id_token to None by default to cover 'bug' in flask-oidc


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index f9faa42..153374a 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -105,6 +105,7 @@ def auth_set(APP, auth):
 
     def handler(sender, **kwargs):
         g.auth = auth
+        g.oidc_id_token = None
         if not auth:
             g.auth = munch.Munch(logged_in=False)
 
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 7500199..254b40e 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -35,6 +35,8 @@ class HubsAPITest(hubs.tests.APPTest):
 
     def test_hub_logged_out(self):
         with app.test_request_context('/ralph'):
+            import flask
+            flask.g.oidc_id_token = None
             # need to manually call the @app.before_request
             # since unittest don't call it
             hubs.app.check_auth()

From bdf32b9cf9fcacffaddf2e21c7873c8eee670dd6 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:14:49 +0000
Subject: [PATCH 513/1001] Use the test db instead of relying on the one from the populate script


---

diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index 47a6eca..e787c68 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -8,8 +8,6 @@ fedmsg_config = fedmsg.config.load_config()
 
 class ModelTest(hubs.tests.APPTest):
     def test_delete_user(self):
-        self.session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
-
         # verify user exists
         username = 'ralph'
         user = hubs.models.User.get(self.session, username)
@@ -32,11 +30,9 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets still are intact
         widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
-        self.assertEqual(8, len(widgets))
+        self.assertEqual(11, len(widgets))
 
     def test_delete_hubs(self):
-        self.session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
-
         # verify the hub exists
         hub_name = 'ralph'
         hub = hubs.models.Hub.get(self.session, hub_name)
@@ -50,7 +46,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets exist
         widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
-        self.assertEqual(8, len(widgets))
+        self.assertEqual(11, len(widgets))
 
         # delete the hub
         self.session.delete(hub)
@@ -73,7 +69,6 @@ class ModelTest(hubs.tests.APPTest):
         self.assertEqual('ralph', user.username)
 
     def test_delete_user_then_hubs(self):
-        self.session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
         username = 'ralph'
         user = hubs.models.User.get(self.session, username)
         self.assertIsNotNone(user)

From 2e2f31687642c1d2cdfb86e82aad984e29140b7b Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:24:39 +0000
Subject: [PATCH 514/1001] Replace the dependency on flask-openid by the one of flask-oidc


---

diff --git a/requirements.txt b/requirements.txt
index c3666e6..883cb24 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,7 +4,7 @@ dogpile.cache
 fedmsg
 fedmsg_meta_fedora_infrastructure
 flask
-flask-openid
+flask-oidc
 fmn.lib
 fmn.rules
 gunicorn

From 335c2c90f58bc8f1014a172cf27594f387992a3e Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:24:57 +0000
Subject: [PATCH 515/1001] Document how to registed the oidc server in the README


---

diff --git a/README.rst b/README.rst
index 24d78eb..b8c0aa7 100644
--- a/README.rst
+++ b/README.rst
@@ -47,6 +47,10 @@ OK -- with that done, now install the dependencies from PyPI::
 
     $ pip install -r requirements.txt
 
+Configure the project to authentify against iddev.fedorainfraclouid.org::
+
+    oidc-register --debug https://iddev.fedorainfracloud.org/ http://localhost:5000
+
 With that, try running the app with::
 
     $ python populate.py  # To create the db

From 77cdfe3fead47efab5993d4756bf77f8cdf37322 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:25:13 +0000
Subject: [PATCH 516/1001] Change the host to localhost since 127.0.0.1 won't work with oidc


---

diff --git a/runserver.py b/runserver.py
index 54e1c5f..e85a2b4 100755
--- a/runserver.py
+++ b/runserver.py
@@ -10,9 +10,9 @@ parser.add_argument(
     '--port', '-p', default=5000,
     help='Port for Hubs to run on.')
 parser.add_argument(
-    '--host', default="127.0.0.1",
+    '--host', default="localhost",
     help='Hostname to listen on. When set to 0.0.0.0 the server is available \
-          externally. Defaults to 127.0.0.1 making the it only visible on \
+          externally. Defaults to localhost making the it only visible on \
           localhost')
 
 args = parser.parse_args()

From f82873bf01fbc22c54f5015477b72935428ec4cc Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:27:17 +0000
Subject: [PATCH 517/1001] Adjust default value regarding HTTPS for cookie


---

diff --git a/hubs/default_config.py b/hubs/default_config.py
index b0d3eb7..0ce12f8 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -12,7 +12,10 @@ HUB_OF_THE_MONTH = 'commops'
 
 OIDC_CLIENT_SECRETS = os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..', 'client_secrets.json')
-OIDC_ID_TOKEN_COOKIE_SECURE = False
+# This settings means that the application needs to be run behind http*s* for
+# the cookie to be saved. For development you will likely need to make it
+# `False`
+OIDC_ID_TOKEN_COOKIE_SECURE = True
 OIDC_REQUIRE_VERIFIED_EMAIL = False
 OIDC_OPENID_REALM = 'http://localhost:5000/oidc_callback'
 OIDC_SCOPES = ['openid', 'email', 'profile', 'fedora']

From 05d5cd3283ad535b613042911ec6a3ff51cdc181 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:28:17 +0000
Subject: [PATCH 518/1001] Replace calls to by_openid to calls to by_username thanks @puiterwijk


---

diff --git a/populate.py b/populate.py
index 8487aa9..a9cbe39 100755
--- a/populate.py
+++ b/populate.py
@@ -58,9 +58,9 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_openid(session, 'pravins'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph'), 'subscriber')
+hub.subscribe(session, hubs.models.User.by_username(session, 'pravins'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'ralph'), 'subscriber')
 
 
 session.commit()
@@ -101,11 +101,11 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'jflory7'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'bee2502'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'keekri'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'linuxmodder'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'jflory7'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'bee2502'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'keekri'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'linuxmodder'), 'member')
 
 
 session.commit()
@@ -146,12 +146,12 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_openid(session, 'croberts'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'mattdm'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph'), 'subscriber')
+hub.subscribe(session, hubs.models.User.by_username(session, 'croberts'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'ryanlerch'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'mrichard'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'mattdm'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'ralph'), 'subscriber')
 
 
 session.commit()
@@ -192,13 +192,13 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_openid(session, 'duffy'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ryanlerch'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'gnokii'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'mrichard'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph'), 'subscriber')
+hub.subscribe(session, hubs.models.User.by_username(session, 'duffy'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'ryanlerch'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'gnokii'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'mrichard'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'nask0'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'ralph'), 'subscriber')
 
 session.commit()
 
@@ -238,10 +238,10 @@ widget = hubs.models.Widget(plugin='dummy', index=3, left=True)
 hub.widgets.append(widget)
 
 
-hub.subscribe(session, hubs.models.User.by_openid(session, 'ralph'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'abompard'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'lmacken'), 'owner')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'nask0'), 'member')
-hub.subscribe(session, hubs.models.User.by_openid(session, 'decause'), 'subscriber')
+hub.subscribe(session, hubs.models.User.by_username(session, 'ralph'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'abompard'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'lmacken'), 'owner')
+hub.subscribe(session, hubs.models.User.by_username(session, 'nask0'), 'member')
+hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'subscriber')
 
 session.commit()

From fc0f4d96a3c9d885a05d38e2d07c49545ab341ab Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jun 30 2016 11:37:28 +0000
Subject: [PATCH 519/1001] Rename FAS to OIDC and fix the test to flask.session.auth


---

diff --git a/hubs/app.py b/hubs/app.py
index 136c844..6cc095e 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -459,12 +459,12 @@ def widget_source(name):
 
 
 # Set up OpenIDConnect
-FAS = OpenIDConnect(app, credentials_store=flask.session )
+OIDC = OpenIDConnect(app, credentials_store=flask.session )
 
 
 @app.route('/login/', methods=('GET', 'POST'))
 @app.route('/login', methods=('GET', 'POST'))
-@FAS.require_login
+@OIDC.require_login
 def login():
     default = flask.url_for('index')
     next_url = flask.request.args.get('next', default)
@@ -491,7 +491,7 @@ def logout():
         next_url = flask.url_for('index')
 
     if authenticated():
-        FAS.logout()
+        OIDC.logout()
         flask.session.auth = None
         flask.flash('You have been logged out')
 
@@ -519,17 +519,17 @@ def check_auth():
     flask.session.permanent = True
     flask.g.fedmsg_config = fedmsg_config
 
-    if FAS.user_loggedin:
-        if not hasattr(flask.session, 'fas_user') or not flask.session.fas_user:
+    if OIDC.user_loggedin:
+        if not hasattr(flask.session, 'auth') or not flask.session.auth:
             flask.session.auth = munch.Munch(
-                fullname=FAS.user_getfield('name'),
-                nickname=FAS.user_getfield('nickname'),
-                email=FAS.user_getfield('email'),
-                timezone=FAS.user_getfield('zoneinfo'),
+                fullname=OIDC.user_getfield('name'),
+                nickname=OIDC.user_getfield('nickname'),
+                email=OIDC.user_getfield('email'),
+                timezone=OIDC.user_getfield('zoneinfo'),
                 cla_done=\
                     'http://admin.fedoraproject.org/accounts/cla/done' \
-                    in FAS.user_getfield('cla'),
-                groups=FAS.user_getfield('groups'),
+                    in OIDC.user_getfield('cla'),
+                groups=OIDC.user_getfield('groups'),
                 logged_in=True,
             )
             flask.session.auth.avatar=username2avatar(

From 18d8043cacfcec9b911a51a47e47b68fb8da7699 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 05 2016 08:24:04 +0000
Subject: [PATCH 520/1001] Fix issue with Feed elements not rendering


Don't bind Feed component to DOM twice

---

diff --git a/hubs/static/client/app/index.jsx b/hubs/static/client/app/index.jsx
index d169745..29f5129 100644
--- a/hubs/static/client/app/index.jsx
+++ b/hubs/static/client/app/index.jsx
@@ -3,8 +3,3 @@ import { render } from 'react-dom';
 
 import Feed from './components/Feed.jsx'
 
-
-render(
-    <Feed matches={[]} />,
-    document.getElementById('feed')
-);

From 06c532f1037f1c40ac2d7ace336969012affda31 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 05 2016 08:24:04 +0000
Subject: [PATCH 521/1001] Make the username validator's code a little easier to read


---

diff --git a/hubs/validators.py b/hubs/validators.py
index c76c9f2..bdc3c96 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -21,7 +21,7 @@ def link(session, value):
 
 
 def username(session, value):
-    return not hubs.models.User.by_username(session, value) is None
+    return hubs.models.User.by_username(session, value) is not None
 
 
 def github_organization(session, value):

From 9392d8929770921204d9e386be7b578877e80496 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 05 2016 08:24:04 +0000
Subject: [PATCH 522/1001] Fix typo found by @puiterwijk


---

diff --git a/README.rst b/README.rst
index b8c0aa7..d4ad78e 100644
--- a/README.rst
+++ b/README.rst
@@ -47,7 +47,7 @@ OK -- with that done, now install the dependencies from PyPI::
 
     $ pip install -r requirements.txt
 
-Configure the project to authentify against iddev.fedorainfraclouid.org::
+Configure the project to authenticate against iddev.fedorainfraclouid.org::
 
     oidc-register --debug https://iddev.fedorainfracloud.org/ http://localhost:5000
 

From d0684f0dcacf08b7365ff32aeeabd6a5df2b119b Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 05 2016 08:24:04 +0000
Subject: [PATCH 523/1001] Fall back to sub if there is no nickname provided by the auth system


---

diff --git a/hubs/app.py b/hubs/app.py
index 6cc095e..c975952 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -523,7 +523,8 @@ def check_auth():
         if not hasattr(flask.session, 'auth') or not flask.session.auth:
             flask.session.auth = munch.Munch(
                 fullname=OIDC.user_getfield('name'),
-                nickname=OIDC.user_getfield('nickname'),
+                nickname=OIDC.user_getfield('nickname') \
+                    or OIDC.user_getfield('sub'),
                 email=OIDC.user_getfield('email'),
                 timezone=OIDC.user_getfield('zoneinfo'),
                 cla_done=\

From 9cf87981f5f79a4d54685fc2264bb97fe35ae4e8 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 06 2016 13:41:01 +0000
Subject: [PATCH 524/1001] Make the app in debug mode earlier since it's not an argument of run()


---

diff --git a/runserver.py b/runserver.py
index e85a2b4..05e2594 100755
--- a/runserver.py
+++ b/runserver.py
@@ -19,4 +19,5 @@ args = parser.parse_args()
 
 from hubs.app import app
 
+app.debug = True
 app.run(debug=True, host=args.host, port=int(args.port))

From 0e906fba20c786cd43ed69eb98b6fd23f4d73724 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 06 2016 13:49:12 +0000
Subject: [PATCH 525/1001] Add a runtest.sh script to run the tests properly with the right config


---

diff --git a/hubs/tests/client_secrets.json b/hubs/tests/client_secrets.json
new file mode 100644
index 0000000..0ce3ce2
--- /dev/null
+++ b/hubs/tests/client_secrets.json
@@ -0,0 +1,12 @@
+{
+	"web": {
+		"redirect_uris": ["http://localhost:5002/oidc_callback"],
+		"token_uri": "https://iddev.fedorainfracloud.org/openidc/Token",
+		"auth_uri": "https://iddev.fedorainfracloud.org/openidc/Authorization",
+		"client_id": "client_id",
+		"client_secret": "client_secret",
+		"userinfo_uri": "https://iddev.fedorainfracloud.org/openidc/UserInfo",
+		"token_introspection_uri": "https://iddev.fedorainfracloud.org/openidc/TokenInfo",
+		"issuer": "https://iddev.fedorainfracloud.org/openidc/"
+	}
+}
diff --git a/hubs/tests/hubs_test.cfg b/hubs/tests/hubs_test.cfg
new file mode 100644
index 0000000..66ccd47
--- /dev/null
+++ b/hubs/tests/hubs_test.cfg
@@ -0,0 +1,11 @@
+### Secret key for the Flask application
+SECRET_KEY='<The web application secret key>'
+
+### url to the database server:
+import os
+DB_URL = 'sqlite:///%s/test.db' % (os.path.dirname(os.path.abspath(__file__)))
+#DB_URL='sqlite:////tmp/fedocal_dev.sqlite'
+
+import os
+OIDC_CLIENT_SECRETS = os.path.join(os.path.dirname(
+    os.path.abspath(__file__)), 'client_secrets.json')
diff --git a/nosetests b/nosetests
new file mode 100755
index 0000000..2f5271b
--- /dev/null
+++ b/nosetests
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+# EASY-INSTALL-ENTRY-SCRIPT: 'nose==0.10.4','console_scripts','nosetests'
+__requires__ = ['nose>=0.10.4', 'SQLAlchemy >= 0.7', 'jinja2 >= 2.4']
+import sys
+from pkg_resources import load_entry_point
+
+sys.exit(
+   load_entry_point('nose>=0.10.4', 'console_scripts', 'nosetests')()
+)
diff --git a/runtest.sh b/runtest.sh
new file mode 100755
index 0000000..ad0de9c
--- /dev/null
+++ b/runtest.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+HUBS_CONFIG=`pwd`/hubs/tests/hubs_test.cfg PYTHONPATH=. ./nosetests \
+    --with-coverage --cover-erase --cover-package=hubs $*

From aec647a51bf9995242e1f85d92530641acfbf665 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 06 2016 13:56:49 +0000
Subject: [PATCH 526/1001] Adjust the instructions on how to run the tests


---

diff --git a/README.rst b/README.rst
index d4ad78e..5379dad 100644
--- a/README.rst
+++ b/README.rst
@@ -81,7 +81,11 @@ didn't inadvertently break something else.
 You can run it with::
 
     $ pip install -r test-requirements.txt
-    $ PYTHONPATH=. nosetests
+    $ ./runtest.sh
+
+See the options available with::
+
+    $ ./runtest.sh --help
 
 Some credentials...
 -------------------

From 4112529d94a117845dabcae6e8be88448b88d27b Mon Sep 17 00:00:00 2001
From: Sayan Chowdhury <sayan.chowdhury2012@gmail.com>
Date: Jul 10 2016 08:57:09 +0000
Subject: [PATCH 527/1001] Update the README to specify the gunicorn port


---

diff --git a/README.rst b/README.rst
index 5379dad..d896932 100644
--- a/README.rst
+++ b/README.rst
@@ -61,14 +61,14 @@ And then navigate to http://localhost:5000/
 If you want to test it with 8 worker threads, try ``gunicorn``::
 
     $ pip install gunicorn
-    $ gunicorn -w 8 -t 60 --log-config logging.ini --reload hubs.app:app
+    $ gunicorn -w 8 -t 60 --log-config logging.ini --reload hubs.app:app -b :5000
 
 Note that then the application is available at http://localhost:8000/
 
 When hacking on widgets, it is useful to have this one-liner handy.  It removes
 the db alltogether, re-populates it, and restarts the app::
 
-    $ rm /var/tmp/hubs.db; rm /var/tmp/fedora-hubs-cache.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 240 --log-config logging.ini hubs.app:app
+    $ rm /var/tmp/hubs.db; rm /var/tmp/fedora-hubs-cache.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 240 --log-config logging.ini hubs.app:app -b :5000
 
 Run the tests!
 --------------

From 7487683460e1918b4cb927c13e77f5ced24ef390 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 12 2016 09:29:43 +0000
Subject: [PATCH 528/1001] Improve the instructions in the README for OpenID-Connect


---

diff --git a/README.rst b/README.rst
index d896932..499e7e3 100644
--- a/README.rst
+++ b/README.rst
@@ -51,10 +51,19 @@ Configure the project to authenticate against iddev.fedorainfraclouid.org::
 
     oidc-register --debug https://iddev.fedorainfracloud.org/ http://localhost:5000
 
+Replace httplib2's own ca cert file (to adjust as needed)::
+
+    cp /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
+        ~/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
+
+Create a local configuration file::
+
+    echo "OIDC_ID_TOKEN_COOKIE_SECURE = False" > config
+
 With that, try running the app with::
 
     $ python populate.py  # To create the db
-    $ python runserver.py  # To run the dev server
+    $ python runserver.py -c config  # To run the dev server with our local conf
 
 And then navigate to http://localhost:5000/
 

From c4b231e3375dce62c505c68ce2e8110836c01920 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 12 2016 13:24:49 +0000
Subject: [PATCH 529/1001] Add --config arg for runserver.py


---

diff --git a/runserver.py b/runserver.py
index 05e2594..dea56b0 100755
--- a/runserver.py
+++ b/runserver.py
@@ -14,10 +14,16 @@ parser.add_argument(
     help='Hostname to listen on. When set to 0.0.0.0 the server is available \
           externally. Defaults to localhost making the it only visible on \
           localhost')
+parser.add_argument(
+    '--config', '-c',
+    help='The configuration file to load from. Defaults to hubs.default_config. \
+          Write the config file name in object form. For example: hubs.my_config')
+
 
 args = parser.parse_args()
 
 from hubs.app import app
 
 app.debug = True
+app.config.from_object(args.config)
 app.run(debug=True, host=args.host, port=int(args.port))

From d230a2a5308cdedfc434bdd55a6d1890bff08c87 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 13 2016 12:33:18 +0000
Subject: [PATCH 530/1001] Fix retrieving the list of subscriptions to a hub


---

diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 986951b..533c563 100755
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -22,8 +22,10 @@ def data(session, widget, username):
     url = url.format(username=username)
     response = requests.get(url)
     fedmsgs = response.json()['total']
+    sub_list = []
     for assoc in widget.hub.associations:
-        sub_list = [u.name for u in assoc.user.subscriptions]
+        if assoc.user:
+            sub_list = [u.name for u in assoc.user.subscriptions]
     subscribers = [u.username for u in widget.hub.subscribers]
     return dict(
         username=username,

From ff3fa257a62e03bd0032cdf32398c5b23803d1c1 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 13 2016 12:34:22 +0000
Subject: [PATCH 531/1001] Fix specifying a configuration file in the runserver


---

diff --git a/runserver.py b/runserver.py
index dea56b0..713c407 100755
--- a/runserver.py
+++ b/runserver.py
@@ -22,8 +22,15 @@ parser.add_argument(
 
 args = parser.parse_args()
 
+if args.config:
+    config = args.config
+    if not config.startswith('/'):
+        here = os.path.join(os.path.dirname(os.path.abspath(__file__)))
+        config = os.path.join(here, config)
+    os.environ['HUBS_CONFIG'] = config
+
+
 from hubs.app import app
 
 app.debug = True
-app.config.from_object(args.config)
 app.run(debug=True, host=args.host, port=int(args.port))

From 87c976403ce74597fcf2102687044961b7fb743a Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 13 2016 14:05:09 +0000
Subject: [PATCH 532/1001] Adjust the help message for the config CLI argument


---

diff --git a/runserver.py b/runserver.py
index 713c407..9d4ece9 100755
--- a/runserver.py
+++ b/runserver.py
@@ -16,8 +16,8 @@ parser.add_argument(
           localhost')
 parser.add_argument(
     '--config', '-c',
-    help='The configuration file to load from. Defaults to hubs.default_config. \
-          Write the config file name in object form. For example: hubs.my_config')
+    help='A configuration file to load (alloing to override the default '
+    'configuraton)')
 
 
 args = parser.parse_args()

From 55bb069804fe31d7b5bf6936debf33b605fbd6aa Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 13 2016 14:06:34 +0000
Subject: [PATCH 533/1001] Typi, typo


---

diff --git a/runserver.py b/runserver.py
index 9d4ece9..fc2b237 100755
--- a/runserver.py
+++ b/runserver.py
@@ -16,7 +16,7 @@ parser.add_argument(
           localhost')
 parser.add_argument(
     '--config', '-c',
-    help='A configuration file to load (alloing to override the default '
+    help='A configuration file to load (allowing to override the default '
     'configuraton)')
 
 

From f2a4a284d1366f4e3c34ef1e705eeece2fec9281 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 14 2016 08:59:15 +0000
Subject: [PATCH 534/1001] Remove un-necessary os.path.join in runserver


---

diff --git a/runserver.py b/runserver.py
index fc2b237..5e5a4f2 100755
--- a/runserver.py
+++ b/runserver.py
@@ -25,7 +25,7 @@ args = parser.parse_args()
 if args.config:
     config = args.config
     if not config.startswith('/'):
-        here = os.path.join(os.path.dirname(os.path.abspath(__file__)))
+        here = os.path.dirname(os.path.abspath(__file__))
         config = os.path.join(here, config)
     os.environ['HUBS_CONFIG'] = config
 

From b84cbff976245faf3eec149c2c8ff889bd763a58 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 14 2016 14:40:39 +0000
Subject: [PATCH 535/1001] Move 4 spaces to 2 in JSX files


In order to comply with JavaScript style standards, change 4 spaces to 2

---

diff --git a/hubs/static/client/app/components/Constituent.jsx b/hubs/static/client/app/components/Constituent.jsx
index 17896a1..3691755 100644
--- a/hubs/static/client/app/components/Constituent.jsx
+++ b/hubs/static/client/app/components/Constituent.jsx
@@ -1,52 +1,52 @@
 import React from 'react';
 
 export default class Constituent extends React.Component {
-    render() {
-        const match = this.props.match;
-        const hasConstituent = (match['msg_ids'].length === 1 && Object.keys(match['msg_ids'])[0]['long_form'] !== Object.keys(match['msg_ids'])[0]['subtitle']);
-        if ( hasConstituent ) {
-            const constituentKey = Object.keys(match['msg_ids'])[0];
-            const constituent = match['msg_ids'][constituentKey];
-            const differentIcon = constituent['icon'] != constituent['__icon__'];
-            const longLink = ( constituent['link'] && constituent['long_form'].indexOf(constituent['link']) === -1 );
+  render() {
+    const match = this.props.match;
+    const hasConstituent = (match['msg_ids'].length === 1 && Object.keys(match['msg_ids'])[0]['long_form'] !== Object.keys(match['msg_ids'])[0]['subtitle']);
+    if ( hasConstituent ) {
+      const constituentKey = Object.keys(match['msg_ids'])[0];
+      const constituent = match['msg_ids'][constituentKey];
+      const differentIcon = constituent['icon'] != constituent['__icon__'];
+      const longLink = ( constituent['link'] && constituent['long_form'].indexOf(constituent['link']) === -1 );
 
-            let constituentIcon;
-            if (differentIcon)
-                constituentIcon = (
-                    <div className="media-left media-top">
-                        <a href={constituent['link']}>
-                            <img className="media-object" src={constituent['icon']} alt={constituent['subtitle']}/>
-                        </a>
-                    </div>
+      let constituentIcon;
+      if (differentIcon)
+        constituentIcon = (
+          <div className="media-left media-top">
+            <a href={constituent['link']}>
+              <img className="media-object" src={constituent['icon']} alt={constituent['subtitle']}/>
+            </a>
+          </div>
 
-                )
+        )
 
-            let readMore;
-            if(longLink)
-                readMore = (
-                    <div className="media-body">
-                        {constituent['long_form']}
-                        <a href={constituent['link']} target="_blank">
-                            Read more <span class="glyphicon glyphicon-new-window"></span>
-                        </a>
-                    </div>
-                )
+      let readMore;
+      if(longLink)
+        readMore = (
+          <div className="media-body">
+            {constituent['long_form']}
+            <a href={constituent['link']} target="_blank">
+              Read more <span class="glyphicon glyphicon-new-window"></span>
+            </a>
+          </div>
+        )
 
-            return (
-                <div id="content-{{match['dom_id']}}" className="media">
-                    <ExpandCollapse match={this.props.match} />
-                    {constituentIcon}
-                    {readMore}
-                </div>
-            )
-        } else if (match['msg_ids'].length > 1) {
-            <div id="content-{{match['dom_id']}}" className="media">
-                <ExpandCollapse match={this.props.match} />
-                <MessageList msgs={this.match['msg_ids']} />
-            </div>
-        }
-        else {
-            return null
-        }
+      return (
+        <div id="content-{{match['dom_id']}}" className="media">
+          <ExpandCollapse match={this.props.match} />
+          {constituentIcon}
+          {readMore}
+        </div>
+      )
+    } else if (match['msg_ids'].length > 1) {
+      <div id="content-{{match['dom_id']}}" className="media">
+        <ExpandCollapse match={this.props.match} />
+        <MessageList msgs={this.match['msg_ids']} />
+      </div>
     }
+    else {
+      return null
+    }
+  }
 }
diff --git a/hubs/static/client/app/components/ExpandCollapse.jsx b/hubs/static/client/app/components/ExpandCollapse.jsx
index 80ab303..29b1e6f 100644
--- a/hubs/static/client/app/components/ExpandCollapse.jsx
+++ b/hubs/static/client/app/components/ExpandCollapse.jsx
@@ -1,18 +1,18 @@
 import React from 'react';
 
 export default class ExpandCollapse extends React.Component {
-    render() {
-        return (
-            <div className="pull-right">
-                <a id="expand-{this.props.match['dom_id']}" href="javascript:expand_feed_entries({this.props.match['dom_id']});" className="hidden">
-                    <span className="glyphicon glyphicon-chevron-down"></span>
-                    expand
-                </a>
-                <a id="collapse-{this.props.match['dom_id']}" href="javascript:collapse_feed_entries('{this.props.match['dom_id']}');">
-                    <span className="glyphicon glyphicon-chevron-up"></span>
-                    collapse
-                </a>
-            </div>
-        )
-    }
+  render() {
+    return (
+      <div className="pull-right">
+        <a id="expand-{this.props.match['dom_id']}" href="javascript:expand_feed_entries({this.props.match['dom_id']});" className="hidden">
+          <span className="glyphicon glyphicon-chevron-down"></span>
+          expand
+        </a>
+        <a id="collapse-{this.props.match['dom_id']}" href="javascript:collapse_feed_entries('{this.props.match['dom_id']}');">
+          <span className="glyphicon glyphicon-chevron-up"></span>
+          collapse
+        </a>
+      </div>
+    )
+  }
 }
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index 9e6cccb..187a1d1 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -10,55 +10,55 @@ import {Message, MessageList} from './Messages.jsx';
 
 
 class Panel extends React.Component {
-    render() {
-        return (
-            <div className="panel panel-default">
-                <div className="panel-body">
-                    <Icon match={this.props.match} />
-                    <Markup match={this.props.match} />
-                    <Constituent match={this.props.match} />
-                </div>
-            </div>
-        );
-    }
+  render() {
+    return (
+      <div className="panel panel-default">
+        <div className="panel-body">
+          <Icon match={this.props.match} />
+          <Markup match={this.props.match} />
+          <Constituent match={this.props.match} />
+        </div>
+      </div>
+    );
+  }
 }
 
 export default class Feed extends React.Component {
-    constructor (props) {
-        super(props);
-        this.state = {
-            matches: this.props.matches,
-            sse: true,
-        }
-        this.source = (!!window.EventSource) ? new EventSource('http://localhost:9090') : {};
-        this.source.addEventListener('error', () => {
-            this.state.sse = false;
-        }, false);
-        window.onbeforeunload = () => {
-            this.source.close();
-        }
-        this.source.addEventListener('message', resp => {
-            $.get('/api/fedmsg/markup', {
-                message: resp.data,
-                plugin: 'feed',
-            }).done(data => {
-                if(!$.isEmptyObject(data)) {
-                    this.state.matches.push.apply(this.state.matches, data);
-                    this.setState({matches: this.state.matches});
-                }
-            });
-        }, false);
+  constructor (props) {
+    super(props);
+    this.state = {
+      matches: this.props.matches,
+      sse: true,
     }
-    render() {
-        const feedNodes = this.state.matches.map(match => {
-            return <Panel match={match}/>
-        });
-        return (
-            <div>
-                {feedNodes}
-            </div>
-        )
+    this.source = (!!window.EventSource) ? new EventSource('http://localhost:9090') : {};
+    this.source.addEventListener('error', () => {
+      this.state.sse = false;
+    }, false);
+    window.onbeforeunload = () => {
+      this.source.close();
     }
+    this.source.addEventListener('message', resp => {
+      $.get('/api/fedmsg/markup', {
+        message: resp.data,
+        plugin: 'feed',
+      }).done(data => {
+        if(!$.isEmptyObject(data)) {
+          this.state.matches.push.apply(this.state.matches, data);
+          this.setState({matches: this.state.matches});
+        }
+      });
+    }, false);
+  }
+  render() {
+    const feedNodes = this.state.matches.map(match => {
+      return <Panel match={match}/>
+    });
+    return (
+      <div>
+        {feedNodes}
+      </div>
+    )
+  }
 }
 
 
diff --git a/hubs/static/client/app/components/Icon.jsx b/hubs/static/client/app/components/Icon.jsx
index 577050e..70c2d8c 100644
--- a/hubs/static/client/app/components/Icon.jsx
+++ b/hubs/static/client/app/components/Icon.jsx
@@ -1,15 +1,15 @@
 import React from 'react';
 
 export default class Icon extends React.Component {
-    render() {
-        return (
-            <div>
-                <div className="media-left">
-                    <a href={this.props.match['link'] ? this.props.match['link'] : '#'} target="_blank">
-                        <img className="media-object square-32 img-circle" src={this.props.match['secondary_icon']} />
-                    </a>
-                </div>
-            </div>
-        )
-    }
+  render() {
+    return (
+      <div>
+        <div className="media-left">
+          <a href={this.props.match['link'] ? this.props.match['link'] : '#'} target="_blank">
+            <img className="media-object square-32 img-circle" src={this.props.match['secondary_icon']} />
+          </a>
+        </div>
+      </div>
+    )
+  }
 }
diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
index 45ccbe3..952fe06 100644
--- a/hubs/static/client/app/components/Markup.jsx
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -1,17 +1,17 @@
 import React from 'react';
 
 export default class Markup extends React.Component {
-    createMarkup() {
-        return {__html: this.props.match['markup']};
-    }
-    render() {
-        return (
-            <div className="media-body">
-                <h4 className="media-heading"
-                    dangerouslySetInnerHTML={this.createMarkup()}
-                ></h4>
-                {this.props.match['human_time']}
-            </div>
-        )
-    }
+  createMarkup() {
+    return {__html: this.props.match['markup']};
+  }
+  render() {
+    return (
+      <div className="media-body">
+        <h4 className="media-heading"
+            dangerouslySetInnerHTML={this.createMarkup()}
+        ></h4>
+        {this.props.match['human_time']}
+      </div>
+    )
+  }
 }
diff --git a/hubs/static/client/app/components/Messages.jsx b/hubs/static/client/app/components/Messages.jsx
index f034a87..a773b52 100644
--- a/hubs/static/client/app/components/Messages.jsx
+++ b/hubs/static/client/app/components/Messages.jsx
@@ -1,36 +1,36 @@
 import React from 'react';
 
 class Message extends React.Component {
-    render() {
-        if(this.props.constituent['link']) {
-            return (
-                <li>
-                    {this.props.constituent['markup']}
-                    <a href={this.props.constituent['link']} target="_blank">
-                        <span className="glyphicon glyphicon-new-window"></span>
-                    </a>
-                </li>
-            )
-        } else {
-            return (<li>{ this.props.constituent['markup'] }</li>)
-        }
+  render() {
+    if(this.props.constituent['link']) {
+      return (
+        <li>
+          {this.props.constituent['markup']}
+          <a href={this.props.constituent['link']} target="_blank">
+            <span className="glyphicon glyphicon-new-window"></span>
+          </a>
+        </li>
+      )
+    } else {
+      return (<li>{ this.props.constituent['markup'] }</li>)
     }
+  }
 }
 
 class MessageList extends React.Component {
-    render() {
-        const messageNodes =  this.props.items.map(function(item) {
-            return <Message constituent={item}/>;
-        });
-        return (
-            <ul id="content-{this.props.match['dom_id']}" className="hidden list-unstyled">
-                {messageNodes}
-            </ul>
-        )
-    }
+  render() {
+    const messageNodes =  this.props.items.map(function(item) {
+      return <Message constituent={item}/>;
+    });
+    return (
+      <ul id="content-{this.props.match['dom_id']}" className="hidden list-unstyled">
+        {messageNodes}
+      </ul>
+    )
+  }
 }
 
 module.exports = {
-    Message: Message,
-    MessageList: MessageList
+  Message: Message,
+  MessageList: MessageList
 }
diff --git a/hubs/static/client/app/index.jsx b/hubs/static/client/app/index.jsx
index 29f5129..a753c36 100644
--- a/hubs/static/client/app/index.jsx
+++ b/hubs/static/client/app/index.jsx
@@ -2,4 +2,3 @@ import React from 'react';
 import { render } from 'react-dom';
 
 import Feed from './components/Feed.jsx'
-
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index 00fc7e2..3b01664 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -5,11 +5,10 @@
         src ="{{url_for('static', filename='js/hubs.js')}}"></script>
 <script>
  (function() {
-     const FeedElement = React.createElement(Feed, {
-         matches: {{ matches }}
-     });
+   const FeedElement = React.createElement(Feed, {
+     matches: {{ matches }}
+   });
 
-     reactRender(FeedElement, document.getElementById('feed'));
+   reactRender(FeedElement, document.getElementById('feed'));
  })();
-
 </script>

From 3bd168a4232553a43ad09dbd8d47c384825496bd Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 14 2016 14:40:39 +0000
Subject: [PATCH 536/1001] Move Feed to external SSE


---

diff --git a/ev-server/hubs-stream-server.py b/ev-server/hubs-stream-server.py
deleted file mode 100644
index 56d5b50..0000000
--- a/ev-server/hubs-stream-server.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# encoding=utf8
-'''
-This file is for development purposes only.
-
-The end goal is for the streaming server to be implemented on the FMN side
-'''
-import json
-import logging
-import sys
-import trollius
-import trollius_redis
-import urllib2
-from concurrent.futures import TimeoutError
-from trollius import From
-
-reload(sys)
-sys.setdefaultencoding('utf8')
-
-log = logging.getLogger(__name__)
-SERVER = None
-REDIS_HOST = '0.0.0.0'
-REDIS_PORT = 6379
-REDIS_DB = 0
-EVENTSOURCE_PORT = 9090
-'''
-you need to
-
-pip install trollius trollius_redis
-
-dnf install redis httpie
-systemctl start redis
-
-
-usage: http get 0.0.0.0:9090/
-
-'''
-
-
-def get_recent_posts():
-    delta = "delta=86400"  # one day worth of data
-    rows_per_page = "rows_per_page=50"
-    url = "https://apps.fedoraproject.org/datagrepper/raw" + "?" + delta + "&" + rows_per_page
-    request = urllib2.Request(url)
-    contents = urllib2.urlopen(request).read()
-    json_response = json.loads(contents)
-    return json_response['raw_messages']
-
-
-@trollius.coroutine
-def handle_client(client_reader, client_writer):
-    origin = '*'
-    if origin.endswith('/'):
-        origin = origin[:-1]
-
-    client_writer.write(("HTTP/1.0 200 OK\n"
-                         "Content-Type: text/event-stream\n"
-                         "Cache: nocache\n"
-                         "Connection: keep-alive\n"
-                         "Access-Control-Allow-Origin: %s\n\n" % origin
-                         ).encode())
-
-    connection = yield trollius.From(trollius_redis.Connection.create(
-        host=REDIS_HOST, port=REDIS_PORT,
-        db=REDIS_DB))
-
-    try:
-        posts = get_recent_posts()
-
-        # send 50 latest posts
-        num_post_sent = 0
-        while num_post_sent < 50:
-            reply = posts[num_post_sent]
-            reply = json.dumps(reply)
-            log.info(reply)
-            log.info("Sending post %s %s", str(num_post_sent), reply)
-            client_writer.write(('data: %s\n\n' % reply).encode())
-            yield trollius.From(client_writer.drain())
-            num_post_sent += 1
-            yield From(trollius.sleep(2))
-
-    except trollius.ConnectionResetError:
-        log.exception("ERROR: ConnectionResetError in handle_client")
-    except Exception:
-        log.exception("ERROR: Exception in handle_client")
-    finally:
-        # Wathever happens, close the connection.
-        connection.close()
-        client_writer.close()
-
-
-def main():
-    global SERVER
-
-    try:
-        loop = trollius.get_event_loop()
-        coro = trollius.start_server(handle_client,
-                                     host=None,
-                                     port=EVENTSOURCE_PORT,
-                                     loop=loop)
-        SERVER = loop.run_until_complete(coro)
-        log.info('Serving server at {}'.format(SERVER.sockets[0].getsockname(
-        )))
-        loop.run_forever()
-    except KeyboardInterrupt:
-        pass
-    except trollius.ConnectionResetError as err:
-        log.exception("ERROR: ConnectionResetError in main")
-    except Exception as err:
-        log.exception("ERROR: Exception in main")
-    finally:
-        # Close the server
-        SERVER.close()
-        log.info("End Connection")
-        loop.run_until_complete(SERVER.wait_closed())
-        loop.close()
-        log.info("End")
-
-
-if __name__ == '__main__':
-    log = logging.getLogger("")
-    formatter = logging.Formatter(
-        "%(asctime)s %(levelname)s [%(module)s:%(lineno)d] %(message)s")
-
-    # setup console logging
-    log.setLevel(logging.DEBUG)
-    ch = logging.StreamHandler()
-    ch.setLevel(logging.DEBUG)
-
-    aslog = logging.getLogger("asyncio")
-    aslog.setLevel(logging.DEBUG)
-
-    ch.setFormatter(formatter)
-    log.addHandler(ch)
-    main()
diff --git a/hubs/app.py b/hubs/app.py
index c975952..7e24193 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -639,76 +639,3 @@ def hub_leave(hub):
         return flask.abort(400)
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-PATHS = fmn.lib.load_rules(root='fmn.rules')
-
-
-@app.route('/api/fedmsg/markup', methods=['GET'])
-def markup_fedmsg():
-    '''
-    This is a temporary endpoint to create a human-readable form of a message.
-    For now it serves as a development tool
-
-    This route will be removed once its functionality is integrated into FMN
-    '''
-    from hubs.widgets.feed import (
-        apply_markup, rehydrate_preference,
-        get_remote_preference
-    )
-    try:
-        data = flask.request.args['message']
-        plugin = flask.request.args['plugin']
-    except KeyError:
-        return flask.abort(400)
-
-    widget = hubs.models.Widget.by_plugin(session, plugin)
-
-    if not widget:
-        return flask.abort(400)
-
-    context = widget.config.get('fmn_context')
-
-    messages = []
-    message = json.loads(data)
-
-    if 'topic' not in message:
-        return flask.abort(400)
-
-    try:
-        nickname = flask.g.auth.nickname
-    except AttributeError:      # Not logged in
-        return flask.abort(403)
-
-    preference = get_remote_preference(nickname, context)
-
-    if preference:
-        try:
-            preference = rehydrate_preference(preference)
-        except ImportError:
-            pass
-    recipients = fmn.lib.recipients(
-        [preference], message, PATHS, fedmsg_config)
-    if recipients:
-        messages.append(message)
-    matches = fedmsg.meta.conglomerate(messages, lexers=True, **fedmsg_config)
-
-    for match in matches:
-        match['markup'] = apply_markup(match)
-        for _, constituent in match['msg_ids'].items():
-            constituent['markup'] = apply_markup(constituent)
-            if constituent['long_form'] != constituent['subtitle']:
-                if constituent.get('lexer'):
-                    constituent['long_form'] = pygments.highlight(
-                        constituent['long_form'],
-                        constituent['lexer'],
-                        pygments.formatters.HtmlFormatter(style='monokai'),
-                    )
-                else:
-                    markup = u"<h5>{long_form}</h5>".format(**constituent)
-                    constituent['long_form'] = markup
-
-        # And tack on a unique identifier for each top level entry.
-        match['dom_id'] = six.text_type(uuid.uuid4())
-
-    return flask.jsonify(matches)
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index 187a1d1..da00b25 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -12,11 +12,10 @@ import {Message, MessageList} from './Messages.jsx';
 class Panel extends React.Component {
   render() {
     return (
-      <div className="panel panel-default">
+      <div className="panel panel-default panel-visible">
         <div className="panel-body">
           <Icon match={this.props.match} />
           <Markup match={this.props.match} />
-          <Constituent match={this.props.match} />
         </div>
       </div>
     );
@@ -30,28 +29,22 @@ export default class Feed extends React.Component {
       matches: this.props.matches,
       sse: true,
     }
-    this.source = (!!window.EventSource) ? new EventSource('http://localhost:9090') : {};
+    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : {};
     this.source.addEventListener('error', () => {
       this.state.sse = false;
     }, false);
     window.onbeforeunload = () => {
       this.source.close();
     }
-    this.source.addEventListener('message', resp => {
-      $.get('/api/fedmsg/markup', {
-        message: resp.data,
-        plugin: 'feed',
-      }).done(data => {
-        if(!$.isEmptyObject(data)) {
-          this.state.matches.push.apply(this.state.matches, data);
-          this.setState({matches: this.state.matches});
-        }
-      });
-    }, false);
+    this.source.onmessage = resp => {
+      const data = JSON.parse(resp.data);
+      this.state.matches.push(data);
+      this.setState({matches: this.state.matches});
+    };
   }
   render() {
     const feedNodes = this.state.matches.map(match => {
-      return <Panel match={match}/>
+      return <Panel match={match} />
     });
     return (
       <div>
@@ -61,7 +54,6 @@ export default class Feed extends React.Component {
   }
 }
 
-
 window.Feed = Feed;
 window.React = React;
 window.reactRender = render;
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index 3b01664..4874fb0 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -6,9 +6,9 @@
 <script>
  (function() {
    const FeedElement = React.createElement(Feed, {
-     matches: {{ matches }}
+     matches: {{ matches }},
+     url: ':8080/user/skrzepto'
    });
-
    reactRender(FeedElement, document.getElementById('feed'));
  })();
 </script>

From e3bfeac5cc07fe9ff3199547b46053e383c38eed Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 14 2016 14:40:39 +0000
Subject: [PATCH 537/1001] Add class properties req and new data to top


---

diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index da00b25..7498425 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -38,7 +38,7 @@ export default class Feed extends React.Component {
     }
     this.source.onmessage = resp => {
       const data = JSON.parse(resp.data);
-      this.state.matches.push(data);
+      this.state.matches.unshift(data);
       this.setState({matches: this.state.matches});
     };
   }
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index abb023a..26274f1 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -9,6 +9,7 @@
   "dependencies": {
     "babel-core": "~6.9.1",
     "babel-loader": "~6.2.4",
+    "babel-plugin-transform-class-properties": "^6.10.2",
     "babel-preset-es2015": "~6.9.0",
     "babel-preset-react": "~6.5.0",
     "react": "~15.1.0",

From 8e39a4b4856f06271baee4068b4eddff14d85ce5 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 14 2016 14:40:39 +0000
Subject: [PATCH 538/1001] Change feed widget to card format


* Per discussion on #fedora-hubs, implement message limiting
* Per same discussion format the feed to look like other widgets in card
  format
* Update README to be explicit about what to do after building JS
asseets h/t skrzepto

---

diff --git a/README.rst b/README.rst
index 499e7e3..095bc30 100644
--- a/README.rst
+++ b/README.rst
@@ -210,7 +210,11 @@ Build JavaScript assets. Add ``--w`` for live reloading::
     $ cd hubs/static/client && node_modules/.bin/webpack
 
 **Lastly**, (fingers crossed) start up the fedora-hubs webapp and load your
-profile page.  Once there are some messages that get into your local database
+profile page. Change back to the project root and run::
+
+  $ python runserver.py
+
+Once there are some messages that get into your local database
 that *should* show up on your feed.. they should appear there.  (At very least,
 you shouldn't get an error message about that widget being unable to be
 displayed).
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index 7498425..55ddfdb 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -8,6 +8,7 @@ import Icon from './Icon.jsx';
 import Markup from './Markup.jsx';
 import {Message, MessageList} from './Messages.jsx';
 
+const FEED_MESSAGE_LIMIT = 10;
 
 class Panel extends React.Component {
   render() {
@@ -38,6 +39,9 @@ export default class Feed extends React.Component {
     }
     this.source.onmessage = resp => {
       const data = JSON.parse(resp.data);
+      if(this.state.matches.length >= FEED_MESSAGE_LIMIT) {
+        this.state.matches.pop()
+      }
       this.state.matches.unshift(data);
       this.setState({matches: this.state.matches});
     };
@@ -47,9 +51,14 @@ export default class Feed extends React.Component {
       return <Panel match={match} />
     });
     return (
-      <div>
+      <div className="card">
+        <div className="card-header">
+          Live Feed
+        </div>
+      <div className="card-block">
         {feedNodes}
       </div>
+      </div>
     )
   }
 }

From 2b5d0c2dbacbec195f4058059fdb3faa09bfd873 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 14 2016 14:40:39 +0000
Subject: [PATCH 539/1001] JSX style rules from Airbnb style guide


---

diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index 55ddfdb..1f208aa 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -1,65 +1,48 @@
 import React from 'react';
-import {render} from 'react-dom';
+import { render } from 'react-dom';
 
+import Panel from './Panel.jsx';
 
-import Constituent from './Constituent.jsx';
-import ExpandCollapse from './ExpandCollapse.jsx';
-import Icon from './Icon.jsx';
-import Markup from './Markup.jsx';
-import {Message, MessageList} from './Messages.jsx';
-
-const FEED_MESSAGE_LIMIT = 10;
-
-class Panel extends React.Component {
-  render() {
-    return (
-      <div className="panel panel-default panel-visible">
-        <div className="panel-body">
-          <Icon match={this.props.match} />
-          <Markup match={this.props.match} />
-        </div>
-      </div>
-    );
-  }
-}
+const FEED_MESSAGE_LIMIT = 20;
 
 export default class Feed extends React.Component {
-  constructor (props) {
+  constructor(props) {
     super(props);
     this.state = {
       matches: this.props.matches,
+      messageLimit: FEED_MESSAGE_LIMIT,
       sse: true,
-    }
+    };
     this.source = (!!window.EventSource) ? new EventSource(this.props.url) : {};
     this.source.addEventListener('error', () => {
       this.state.sse = false;
     }, false);
     window.onbeforeunload = () => {
       this.source.close();
-    }
+    };
     this.source.onmessage = resp => {
       const data = JSON.parse(resp.data);
-      if(this.state.matches.length >= FEED_MESSAGE_LIMIT) {
-        this.state.matches.pop()
+      if (this.state.matches.length >= this.state.messageLimit) {
+        this.state.matches.pop();
       }
       this.state.matches.unshift(data);
-      this.setState({matches: this.state.matches});
+      this.setState({ matches: this.state.matches });
     };
   }
   render() {
     const feedNodes = this.state.matches.map(match => {
-      return <Panel match={match} />
+      return <Panel match={match} />;
     });
     return (
       <div className="card">
         <div className="card-header">
           Live Feed
         </div>
-      <div className="card-block">
-        {feedNodes}
-      </div>
+        <div className="card-block">
+          {feedNodes}
+        </div>
       </div>
-    )
+    );
   }
 }
 
diff --git a/hubs/static/client/app/components/Icon.jsx b/hubs/static/client/app/components/Icon.jsx
index 70c2d8c..08c8d60 100644
--- a/hubs/static/client/app/components/Icon.jsx
+++ b/hubs/static/client/app/components/Icon.jsx
@@ -1,15 +1,19 @@
 import React from 'react';
 
-export default class Icon extends React.Component {
-  render() {
-    return (
-      <div>
-        <div className="media-left">
-          <a href={this.props.match['link'] ? this.props.match['link'] : '#'} target="_blank">
-            <img className="media-object square-32 img-circle" src={this.props.match['secondary_icon']} />
-          </a>
-        </div>
+const Icon = function (props) {
+  return (
+    <div>
+      <div className="media-left">
+        <a href={props.match.link ? props.match.link : '#'} target="_blank">
+          <img
+            alt="User avatar"
+            className="media-object square-32 img-circle"
+            src={props.match.secondary_icon}
+          />
+        </a>
       </div>
-    )
-  }
-}
+    </div>
+  );
+};
+
+export default Icon;
diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
index 952fe06..768a81b 100644
--- a/hubs/static/client/app/components/Markup.jsx
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -2,16 +2,19 @@ import React from 'react';
 
 export default class Markup extends React.Component {
   createMarkup() {
-    return {__html: this.props.match['markup']};
+    return { __html: this.props.match.markup };
   }
   render() {
+    debugger;
     return (
       <div className="media-body">
-        <h4 className="media-heading"
-            dangerouslySetInnerHTML={this.createMarkup()}
-        ></h4>
-        {this.props.match['human_time']}
+        <h4
+          className="media-heading"
+          dangerouslySetInnerHTML={this.createMarkup()}
+        >
+        </h4>
+        {this.props.match.human_time}
       </div>
-    )
+    );
   }
 }
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
new file mode 100644
index 0000000..61e8242
--- /dev/null
+++ b/hubs/static/client/app/components/Panel.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+
+import Icon from './Icon.jsx';
+import Markup from './Markup.jsx';
+
+const Panel = function (props) {
+  return (
+    <div className="panel panel-default panel-visible">
+      <div className="panel-body">
+        <Icon match={props.match} />
+        <Markup match={props.match} />
+      </div>
+    </div>
+  );
+};
+
+export default Panel;
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 26274f1..045880c 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -12,17 +12,18 @@
     "babel-plugin-transform-class-properties": "^6.10.2",
     "babel-preset-es2015": "~6.9.0",
     "babel-preset-react": "~6.5.0",
+    "moment": "^2.14.1",
     "react": "~15.1.0",
     "react-dom": "~15.1.0",
     "reactify": "~1.1.1",
     "webpack": "~1.13.1"
   },
   "devDependencies": {
-    "eslint-config-airbnb": "~9.0.1",
-    "eslint-plugin-react": "~5.2.1",
-    "eslint-plugin-jsx-a11y": "~1.5.3",
-    "eslint-plugin-import": "~1.8.1",
-    "eslint": "~2.12.0"
+    "eslint": "^2.13.1",
+    "eslint-config-airbnb": "^9.0.1",
+    "eslint-plugin-import": "^1.10.2",
+    "eslint-plugin-jsx-a11y": "^1.5.5",
+    "eslint-plugin-react": "^5.2.2"
   },
   "scripts": {
     "dev": "webpack --watch",

From 3beee9df2c297fffb3a03cd1da6e2c380ef6d4c7 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 14 2016 14:40:39 +0000
Subject: [PATCH 540/1001] Make feed limit configurable


---

diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index 1f208aa..7d9c618 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -3,14 +3,12 @@ import { render } from 'react-dom';
 
 import Panel from './Panel.jsx';
 
-const FEED_MESSAGE_LIMIT = 20;
-
 export default class Feed extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       matches: this.props.matches,
-      messageLimit: FEED_MESSAGE_LIMIT,
+      messageLimit: this.props.messageLimit,
       sse: true,
     };
     this.source = (!!window.EventSource) ? new EventSource(this.props.url) : {};
@@ -30,17 +28,12 @@ export default class Feed extends React.Component {
     };
   }
   render() {
-    const feedNodes = this.state.matches.map(match => {
-      return <Panel match={match} />;
+    const feedNodes = this.state.matches.map((match, idx) => {
+      return <Panel match={match} key={idx} />;
     });
     return (
-      <div className="card">
-        <div className="card-header">
-          Live Feed
-        </div>
-        <div className="card-block">
-          {feedNodes}
-        </div>
+      <div>
+      {feedNodes}
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
index 768a81b..5023498 100644
--- a/hubs/static/client/app/components/Markup.jsx
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -5,7 +5,6 @@ export default class Markup extends React.Component {
     return { __html: this.props.match.markup };
   }
   render() {
-    debugger;
     return (
       <div className="media-body">
         <h4
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index c6e3797..f6cf651 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -34,9 +34,8 @@ fmn_url = config['fmn.url']
 bazillion = 1000
 paths = fmn.lib.load_rules(root='fmn.rules')
 
-# No chrome around the feed.
-# from hubs.widgets.chrome import panel
-# chrome = panel()
+from hubs.widgets.chrome import panel
+chrome = panel('Live Feed')
 template = templating.environment.get_template('templates/feed.html')
 position = 'left'
 
@@ -86,7 +85,11 @@ class PythonObjectEncoder(json.JSONEncoder):
           default="irc",  # TODO - Make this 'hubs', or...
           validator=validators.fmn_context,
           help="A FMN context.")
-def data(session, widget, username, fmn_context):
+@argument(name="message_limit",
+          default=20,
+          validator=validators.integer,
+          help="Max number of feed messages to display")
+def data(session, widget, username, fmn_context, message_limit):
     messages = []
     matches = []
     preference = get_remote_preference(username, fmn_context)
@@ -151,7 +154,7 @@ def data(session, widget, username, fmn_context):
         # And tack on a unique identifier for each top level entry.
         match['dom_id'] = six.text_type(uuid.uuid4())
     matches = json.dumps(matches, cls=PythonObjectEncoder)
-    return dict(matches=matches)
+    return dict(matches=matches, message_limit=message_limit)
 
 
 @hint(ubiquitous=True)

From 721c1e990e93acb1827cf638ca413a191847d75c Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 14 2016 14:40:39 +0000
Subject: [PATCH 541/1001] Fix human readable time, clean up JS/JSX


---

diff --git a/.gitignore b/.gitignore
index 7787cd3..74ff6cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ build/
 scratch/
 
 npm-debug.log
+client_secrets.json
\ No newline at end of file
diff --git a/hubs/static/client/.eslintrc.json b/hubs/static/client/.eslintrc.json
new file mode 100644
index 0000000..079ce96
--- /dev/null
+++ b/hubs/static/client/.eslintrc.json
@@ -0,0 +1,8 @@
+{
+  "extends": "airbnb",
+  "rules": {
+    "react/prop-types": "off",
+    "arrow-body-style": "off",
+    "func-names": "off"
+  }
+}
diff --git a/hubs/static/client/app/components/Constituent.jsx b/hubs/static/client/app/components/Constituent.jsx
deleted file mode 100644
index 3691755..0000000
--- a/hubs/static/client/app/components/Constituent.jsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import React from 'react';
-
-export default class Constituent extends React.Component {
-  render() {
-    const match = this.props.match;
-    const hasConstituent = (match['msg_ids'].length === 1 && Object.keys(match['msg_ids'])[0]['long_form'] !== Object.keys(match['msg_ids'])[0]['subtitle']);
-    if ( hasConstituent ) {
-      const constituentKey = Object.keys(match['msg_ids'])[0];
-      const constituent = match['msg_ids'][constituentKey];
-      const differentIcon = constituent['icon'] != constituent['__icon__'];
-      const longLink = ( constituent['link'] && constituent['long_form'].indexOf(constituent['link']) === -1 );
-
-      let constituentIcon;
-      if (differentIcon)
-        constituentIcon = (
-          <div className="media-left media-top">
-            <a href={constituent['link']}>
-              <img className="media-object" src={constituent['icon']} alt={constituent['subtitle']}/>
-            </a>
-          </div>
-
-        )
-
-      let readMore;
-      if(longLink)
-        readMore = (
-          <div className="media-body">
-            {constituent['long_form']}
-            <a href={constituent['link']} target="_blank">
-              Read more <span class="glyphicon glyphicon-new-window"></span>
-            </a>
-          </div>
-        )
-
-      return (
-        <div id="content-{{match['dom_id']}}" className="media">
-          <ExpandCollapse match={this.props.match} />
-          {constituentIcon}
-          {readMore}
-        </div>
-      )
-    } else if (match['msg_ids'].length > 1) {
-      <div id="content-{{match['dom_id']}}" className="media">
-        <ExpandCollapse match={this.props.match} />
-        <MessageList msgs={this.match['msg_ids']} />
-      </div>
-    }
-    else {
-      return null
-    }
-  }
-}
diff --git a/hubs/static/client/app/components/ExpandCollapse.jsx b/hubs/static/client/app/components/ExpandCollapse.jsx
deleted file mode 100644
index 29b1e6f..0000000
--- a/hubs/static/client/app/components/ExpandCollapse.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-
-export default class ExpandCollapse extends React.Component {
-  render() {
-    return (
-      <div className="pull-right">
-        <a id="expand-{this.props.match['dom_id']}" href="javascript:expand_feed_entries({this.props.match['dom_id']});" className="hidden">
-          <span className="glyphicon glyphicon-chevron-down"></span>
-          expand
-        </a>
-        <a id="collapse-{this.props.match['dom_id']}" href="javascript:collapse_feed_entries('{this.props.match['dom_id']}');">
-          <span className="glyphicon glyphicon-chevron-up"></span>
-          collapse
-        </a>
-      </div>
-    )
-  }
-}
diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
index 5023498..66f4da4 100644
--- a/hubs/static/client/app/components/Markup.jsx
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -1,4 +1,5 @@
 import React from 'react';
+import TimeAgo from 'react-timeago';
 
 export default class Markup extends React.Component {
   createMarkup() {
@@ -12,7 +13,7 @@ export default class Markup extends React.Component {
           dangerouslySetInnerHTML={this.createMarkup()}
         >
         </h4>
-        {this.props.match.human_time}
+        <TimeAgo date={this.props.match.date_time} />
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/Messages.jsx b/hubs/static/client/app/components/Messages.jsx
deleted file mode 100644
index a773b52..0000000
--- a/hubs/static/client/app/components/Messages.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-
-class Message extends React.Component {
-  render() {
-    if(this.props.constituent['link']) {
-      return (
-        <li>
-          {this.props.constituent['markup']}
-          <a href={this.props.constituent['link']} target="_blank">
-            <span className="glyphicon glyphicon-new-window"></span>
-          </a>
-        </li>
-      )
-    } else {
-      return (<li>{ this.props.constituent['markup'] }</li>)
-    }
-  }
-}
-
-class MessageList extends React.Component {
-  render() {
-    const messageNodes =  this.props.items.map(function(item) {
-      return <Message constituent={item}/>;
-    });
-    return (
-      <ul id="content-{this.props.match['dom_id']}" className="hidden list-unstyled">
-        {messageNodes}
-      </ul>
-    )
-  }
-}
-
-module.exports = {
-  Message: Message,
-  MessageList: MessageList
-}
diff --git a/hubs/static/client/app/index.jsx b/hubs/static/client/app/index.jsx
index a753c36..b12429e 100644
--- a/hubs/static/client/app/index.jsx
+++ b/hubs/static/client/app/index.jsx
@@ -1,4 +1,4 @@
 import React from 'react';
 import { render } from 'react-dom';
 
-import Feed from './components/Feed.jsx'
+import Feed from './components/Feed.jsx';
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 045880c..f717e0d 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -7,29 +7,24 @@
     "doc": "docs"
   },
   "dependencies": {
-    "babel-core": "~6.9.1",
     "babel-loader": "~6.2.4",
     "babel-plugin-transform-class-properties": "^6.10.2",
     "babel-preset-es2015": "~6.9.0",
     "babel-preset-react": "~6.5.0",
-    "moment": "^2.14.1",
     "react": "~15.1.0",
     "react-dom": "~15.1.0",
-    "reactify": "~1.1.1",
+    "react-timeago": "^3.1.1",
     "webpack": "~1.13.1"
   },
   "devDependencies": {
     "eslint": "^2.13.1",
-    "eslint-config-airbnb": "^9.0.1",
-    "eslint-plugin-import": "^1.10.2",
-    "eslint-plugin-jsx-a11y": "^1.5.5",
-    "eslint-plugin-react": "^5.2.2"
+    "depcheck": "~0.6.3"
   },
   "scripts": {
     "dev": "webpack --watch",
     "build": "webpack -p",
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "test": "eslint app/* && depcheck ."
   },
   "author": "",
-  "license": "BSD"
+  "license": "AGPL-3.0"
 }
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index 4874fb0..9973c29 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -7,7 +7,8 @@
  (function() {
    const FeedElement = React.createElement(Feed, {
      matches: {{ matches }},
-     url: ':8080/user/skrzepto'
+     url: 'localhost:8080/user/skrzepto',
+     messageLimit: {{ message_limit }}
    });
    reactRender(FeedElement, document.getElementById('feed'));
  })();

From 791b715958004f08f03dbabc82629b370eda9f4a Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 14 2016 14:40:39 +0000
Subject: [PATCH 542/1001] Use application config to set the SSE url


* Use app.config to set SSE url
* Pin min version for flask-oidc
* Readme instructions for SSE url

---

diff --git a/.gitignore b/.gitignore
index 74ff6cc..096613a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,4 +7,5 @@ build/
 scratch/
 
 npm-debug.log
-client_secrets.json
\ No newline at end of file
+client_secrets.json
+hubs.js
diff --git a/README.rst b/README.rst
index 095bc30..531a78a 100644
--- a/README.rst
+++ b/README.rst
@@ -205,14 +205,15 @@ will just grow and grow over time::
     [2015-07-01 14:33:21][    fedmsg    INFO] copr has 6 entries
     [2015-07-01 14:33:21][    fedmsg    INFO] askbot has 2 entries
 
-Build JavaScript assets. Add ``--w`` for live reloading::
+Change the ``SSE_URL`` location in ``default_config.py`` to point to the
+streaming server then build JavaScript assets. Add ``--w`` for live reloading::
 
     $ cd hubs/static/client && node_modules/.bin/webpack
 
 **Lastly**, (fingers crossed) start up the fedora-hubs webapp and load your
 profile page. Change back to the project root and run::
 
-  $ python runserver.py
+  $ python runserver.py -c config
 
 Once there are some messages that get into your local database
 that *should* show up on your feed.. they should appear there.  (At very least,
diff --git a/hubs/default_config.py b/hubs/default_config.py
index 0ce12f8..4125923 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -9,6 +9,7 @@ PROMOTED_GROUPS = [
 
 HUB_OF_THE_MONTH = 'commops'
 
+SSE_URL = 'http://localhost:8080/user/'
 
 OIDC_CLIENT_SECRETS = os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..', 'client_secrets.json')
diff --git a/hubs/defaults.py b/hubs/defaults.py
index 4b2049d..ddd04db 100755
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -11,7 +11,8 @@ def add_user_widgets(session, hub, username, fullname):
         plugin='feed', index=0, left=True,
         _config=json.dumps({
             'username': username,
-            'fmn_context': 'irc',  # TODO -- make this 'hubs'
+            'fmn_context': 'irc',  # TODO -- make this 'hubs',
+            'message_limit': 20
         }))
     hub.widgets.append(widget)
 
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index f6cf651..42b3cb5 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -92,6 +92,9 @@ class PythonObjectEncoder(json.JSONEncoder):
 def data(session, widget, username, fmn_context, message_limit):
     messages = []
     matches = []
+    # Avoid circular import
+    from hubs.app import app
+    feed_url = app.config['SSE_URL'] + username
     preference = get_remote_preference(username, fmn_context)
     if preference:
         try:
@@ -114,7 +117,7 @@ def data(session, widget, username, fmn_context, message_limit):
             total, pages, rows = datanommer.models.Message.grep(
                 start=end - delta,
                 end=end,
-                rows_per_page=bazillion,
+                rows_per_page=message_limit,
                 page=page,
                 order='desc',
                 **fmn_hinting
@@ -154,7 +157,11 @@ def data(session, widget, username, fmn_context, message_limit):
         # And tack on a unique identifier for each top level entry.
         match['dom_id'] = six.text_type(uuid.uuid4())
     matches = json.dumps(matches, cls=PythonObjectEncoder)
-    return dict(matches=matches, message_limit=message_limit)
+    return dict(
+        matches=matches,
+        message_limit=message_limit,
+        feed_url=feed_url
+    )
 
 
 @hint(ubiquitous=True)
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index 9973c29..755bec9 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -7,7 +7,7 @@
  (function() {
    const FeedElement = React.createElement(Feed, {
      matches: {{ matches }},
-     url: 'localhost:8080/user/skrzepto',
+     url: '{{ feed_url }}',
      messageLimit: {{ message_limit }}
    });
    reactRender(FeedElement, document.getElementById('feed'));
diff --git a/requirements.txt b/requirements.txt
index 883cb24..01e9cc9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,7 +4,7 @@ dogpile.cache
 fedmsg
 fedmsg_meta_fedora_infrastructure
 flask
-flask-oidc
+flask-oidc>=1.0.3
 fmn.lib
 fmn.rules
 gunicorn

From d89312eb0e4eb5999a58f722dd640da4efe5f061 Mon Sep 17 00:00:00 2001
From: Eric Barbour <emb4gu@virginia.edu>
Date: Jul 14 2016 14:40:39 +0000
Subject: [PATCH 543/1001] Remove 'irc' feed context, add package.json author


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index ddd04db..706bb03 100755
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -11,7 +11,6 @@ def add_user_widgets(session, hub, username, fullname):
         plugin='feed', index=0, left=True,
         _config=json.dumps({
             'username': username,
-            'fmn_context': 'irc',  # TODO -- make this 'hubs',
             'message_limit': 20
         }))
     hub.widgets.append(widget)
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index f717e0d..235be28 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -25,6 +25,6 @@
     "build": "webpack -p",
     "test": "eslint app/* && depcheck ."
   },
-  "author": "",
+  "author": "Eric Barbour <ebarbour@redhat.com>",
   "license": "AGPL-3.0"
 }
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 42b3cb5..d3870c3 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -81,21 +81,17 @@ class PythonObjectEncoder(json.JSONEncoder):
           default=None,
           validator=validators.username,
           help="A FAS username.")
-@argument(name="fmn_context",
-          default="irc",  # TODO - Make this 'hubs', or...
-          validator=validators.fmn_context,
-          help="A FMN context.")
 @argument(name="message_limit",
           default=20,
           validator=validators.integer,
           help="Max number of feed messages to display")
-def data(session, widget, username, fmn_context, message_limit):
+def data(session, widget, username, message_limit):
     messages = []
     matches = []
     # Avoid circular import
     from hubs.app import app
     feed_url = app.config['SSE_URL'] + username
-    preference = get_remote_preference(username, fmn_context)
+    preference = get_remote_preference(username, 'sse')
     if preference:
         try:
             preference = rehydrate_preference(preference)
@@ -167,7 +163,7 @@ def data(session, widget, username, fmn_context, message_limit):
 @hint(ubiquitous=True)
 def should_invalidate(message, session, widget):
     username = widget.config['username']
-    fmn_context = widget.config['fmn_context']
+    fmn_context = 'sse'
     preference = get_remote_preference(username, fmn_context)
     if not preference:
         return False

From 7866df8ec4033b9919e201a7a73303925b5ffc38 Mon Sep 17 00:00:00 2001
From: Eric Barbour <emb4gu@virginia.edu>
Date: Jul 14 2016 17:09:01 +0000
Subject: [PATCH 544/1001] Fix tests fmn_context change + fedmsg api removal


---

diff --git a/hubs/tests/test_api/test_fedmsg.py b/hubs/tests/test_api/test_fedmsg.py
deleted file mode 100644
index 332d4d1..0000000
--- a/hubs/tests/test_api/test_fedmsg.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import json
-import os
-
-import hubs.tests
-import hubs.models
-from hubs.app import app
-from hubs.tests import json_path
-
-
-class TestFeed(hubs.tests.APPTest):
-
-    with open(json_path + 'message_involved.json', 'r') as fp:
-        message_involved = json.loads(fp.read())
-
-    with open(json_path + 'message_not_involved.json', 'r') as fp:
-        message_not_involved = json.loads(fp.read())
-
-    # TODO this test relies on a specific filter for the atelic user
-    # It would be better to fake preferences on FAS
-    user = hubs.tests.FakeAuthorization('atelic')
-
-    plugin = 'feed'
-
-    def test_returns_400_when_no_message(self):
-        payload = {'plugin': 'feed'}
-        response = self.app.get('/api/fedmsg/markup', query_string=payload)
-        self.assertEqual(response.status_code, 400)
-
-    def test_returns_400_when_no_plugin(self):
-        payload = {'message': json.dumps(self.message_involved)}
-        response = self.app.get('/api/fedmsg/markup', query_string=payload)
-        self.assertEqual(response.status_code, 400)
-
-    def test_returns_400_when_bad_plugin_name(self):
-        payload = {
-            'message': json.dumps(self.message_involved),
-            'plugin': 'notarealplugin'
-        }
-        response = self.app.get('/api/fedmsg/markup', query_string=payload)
-        self.assertEqual(response.status_code, 400)
-
-    def test_returns_403_when_not_logged_in(self):
-        payload = {
-            'message': json.dumps(self.message_involved),
-            'plugin': 'feed'
-        }
-
-        response = self.app.get('/api/fedmsg/markup', query_string=payload)
-        self.assertEqual(response.status_code, 403)
-
-    def test_returns_match_if_involved(self):
-        payload = {
-            'message': json.dumps(self.message_involved),
-            'plugin': 'feed'
-        }
-        with self.app.session_transaction() as sess:
-            sess['nickname'] = 'atelic'
-
-        with hubs.tests.auth_set(app, self.user):
-            response = self.app.get('/api/fedmsg/markup', query_string=payload)
-
-            self.assertEqual(response.status_code, 200)
-            data = json.loads(response.data)
-            self.assertTrue(data)
-            self.assertTrue(isinstance(data[0], dict))
-
-    def test_returns_no_match_if_not_involved(self):
-        payload = {
-            'message': json.dumps(self.message_not_involved),
-            'plugin': 'feed'
-        }
-        with self.app.session_transaction() as sess:
-            sess['nickname'] = 'atelic'
-
-        with hubs.tests.auth_set(app, self.user):
-            response = self.app.get('/api/fedmsg/markup', query_string=payload)
-
-            self.assertEqual(response.status_code, 200)
-            data = json.loads(response.data)
-            self.assertFalse(data)
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 254b40e..7b7dbff 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -268,7 +268,7 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             result = self.app.get('/ralph/31/edit', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            expected_str = '<input id="fmn_context" class="form-control" type="text"'
+            expected_str = '<input id="message_limit" class="form-control" type="text"'
             self.assertTrue(expected_str in result.data)
 
     @unittest.skip("Authorization layer not present yet")

From 290a3b7b04fbc04f2ca654e1dc87d0f5e71b1dab Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 14 2016 20:02:43 +0000
Subject: [PATCH 545/1001] Explain seemingly unused import in index.jsx


---

diff --git a/hubs/static/client/app/index.jsx b/hubs/static/client/app/index.jsx
index b12429e..7641684 100644
--- a/hubs/static/client/app/index.jsx
+++ b/hubs/static/client/app/index.jsx
@@ -1,4 +1,5 @@
-import React from 'react';
-import { render } from 'react-dom';
-
-import Feed from './components/Feed.jsx';
+/* This import is needed even though it's not used
+ * since the feed component places itself on window.
+ * The feed will not work without it.
+ */
+import Feed from './components/Feed.jsx'; // eslint-disable-line

From b45fe2b18e9a7c5c4f3af2fcaa5e3c1d37c4eb5c Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 18 2016 16:17:49 +0000
Subject: [PATCH 546/1001] Basic ellipsizing of group owners


* Sort top owners by oldest
* Modal shows all owners alphabetically

---

diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index edf141a..443f07c 100755
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -7,6 +7,7 @@ from hubs.widgets import templating
 from hubs.utils import username2avatar
 from hubs import validators
 
+ELLIPSIS_LIMIT = 5
 chrome = panel()
 template = templating.environment.get_template('templates/rules.html')
 position = 'both'
@@ -26,10 +27,17 @@ position = 'both'
           help="Link to meeting minutes from past meetings..")
 def data(session, widget, link, schedule_text, schedule_link, minutes_link):
     owners = widget.hub.owners
+    oldest_owners = sorted(owners, key=lambda o: o.created_on)[:ELLIPSIS_LIMIT]
+    oldest_owners = [{
+        'username': o.username,
+        'avatar': username2avatar(o.username)
+    } for o in oldest_owners]
+
     owners = ordereddict([
         (o.username, username2avatar(o.username)) for o in owners
     ])
-    return dict(owners=owners, link=link,
+    return dict(oldest_owners=oldest_owners,
+                owners=owners, link=link,
                 schedule_text=schedule_text,
                 schedule_link=schedule_link,
                 minutes_link=minutes_link)
diff --git a/hubs/widgets/templates/rules.html b/hubs/widgets/templates/rules.html
index 2d986d1..20f86a6 100644
--- a/hubs/widgets/templates/rules.html
+++ b/hubs/widgets/templates/rules.html
@@ -5,12 +5,23 @@
   {% endif %}
   <h6>group owners</h6>
   <div class="row">
-    {% for owner in owners %}
+    {% if owners|length > 5%}
+      {% for owner in oldest_owners %}
         <div class="col-sm-6">
-            <img class="img-circle" src="{{owners[owner]}}"/>
-            <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
+          <img class="img-circle owner-avatar-sm" src="{{owner['avatar']}}"/>
+          <a href="{{ url_for('hub', name=owner['username']) }}">{{owner['username']}}</a>
         </div>
-    {% endfor %}
+        {% endfor %}
+        <br/>
+        <a href="#" class="btn btn-default" data-toggle="modal" data-target="#ownersModal">View All</a>
+    {% else %}
+      {% for owner in owners %}
+        <div class="col-sm-6">
+          <img class="img-circle owner-avatar-sm" src="{{owners[owner]}}"/>
+          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
+        </div>
+      {% endfor %}
+    {% endif %}
   </div>
   {% if schedule_text or schedule_link or minutes_link %}
   <h6>meetings</h6>
@@ -30,6 +41,30 @@
   </p>
   {% endif %}
 </div>
+
+
+<!-- View all modal -->
+<div class="modal fade" id="ownersModal" tabindex="-1" role="dialog" aria-labelledby="ownersModal" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h4 class="modal-title" id="myModalLabel">All group owners</h4>
+      </div>
+      <div class="modal-body">
+        {% for owner in owners %}
+        <div class="col-sm-6">
+          <img class="img-circle owner-avatar-lg" src="{{owners[owner]}}"/>
+          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
+        </div>
+        {% endfor %}
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+      </div>
+    </div>
+  </div>
+</div>
+
 <style>
   .rules-table {
     width: 180px
@@ -40,4 +75,12 @@
   .rules-table td {
     font-size: 32pt;
   }
+ .owner-avatar-sm {
+   height: 2em;
+   width: 2em;
+ }
+ .owner-avatar-lg {
+   height: 6em;
+   width: 6em;
+ }
 </style>

From 337b739939bca835d810b3ffffbd46587f695bfe Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 19 2016 16:10:43 +0000
Subject: [PATCH 547/1001] Global rule for avatar size


* Global rule for avatar size
* Additional rule for large avatars

---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index c39f680..2e0f42d 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -368,3 +368,8 @@ font-size: 32pt;
 .edit_widget {
   cursor: pointer;
 }
+
+.img-circle {
+  height: 2em;
+  width: 2em;
+}
diff --git a/hubs/widgets/templates/rules.html b/hubs/widgets/templates/rules.html
index 20f86a6..9ab51e8 100644
--- a/hubs/widgets/templates/rules.html
+++ b/hubs/widgets/templates/rules.html
@@ -3,12 +3,12 @@
   <h6>community rules</h6>
   <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
   {% endif %}
-  <h6>group owners</h6>
+  <h6>group owners ({{ owners|length }})</h6>
   <div class="row">
     {% if owners|length > 5%}
       {% for owner in oldest_owners %}
         <div class="col-sm-6">
-          <img class="img-circle owner-avatar-sm" src="{{owner['avatar']}}"/>
+          <img class="img-circle" src="{{owner['avatar']}}"/>
           <a href="{{ url_for('hub', name=owner['username']) }}">{{owner['username']}}</a>
         </div>
         {% endfor %}
@@ -17,7 +17,7 @@
     {% else %}
       {% for owner in owners %}
         <div class="col-sm-6">
-          <img class="img-circle owner-avatar-sm" src="{{owners[owner]}}"/>
+          <img class="img-circle" src="{{owners[owner]}}"/>
           <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
         </div>
       {% endfor %}
@@ -50,10 +50,10 @@
       <div class="modal-header">
         <h4 class="modal-title" id="myModalLabel">All group owners</h4>
       </div>
-      <div class="modal-body">
+      <div id="owners">
         {% for owner in owners %}
         <div class="col-sm-6">
-          <img class="img-circle owner-avatar-lg" src="{{owners[owner]}}"/>
+          <img class="img-circle img-circle-lg" src="{{owners[owner]}}"/>
           <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
         </div>
         {% endfor %}
@@ -75,12 +75,13 @@
   .rules-table td {
     font-size: 32pt;
   }
- .owner-avatar-sm {
-   height: 2em;
-   width: 2em;
+
+ .img-circle-lg {
+   height: 4em;
+   width: 4em;
+   padding: 10px;
  }
- .owner-avatar-lg {
-   height: 6em;
-   width: 6em;
+ .modal-header {
+   border-bottom: 0;
  }
 </style>

From 314897b8bacf883384b53fe447fd302c5c137339 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jul 20 2016 15:40:23 +0000
Subject: [PATCH 548/1001] Visit Counter


Commit History:

added base model for visitcounter and added it to populate.py

updating so that when you delete hub the visit_counter is also deleted but when you delete the visit_counter the hub/user is still there

adding basic hubs incrementing, having problems with ipsilon to test

typo in name, naive implementation works, but its increments 4 times on one load of a page

moving increment counter in another location

updating to js ajax call, at the moment the route call isnt working

debugging stuff

changed url str

finally working

updating route to visit and wrote some unittests

removing unecessary lines

added login requrired to increment visit counter and make sure the user requesting the increment is the same user

removing redundant variable username and just using visited_hub

removing the check if user is logged in because @login_required is there, also surrounded get_or_create in try statement even though it should never except

adding tests and fixing where try/except goes

convering does hub/user exist to one liners

cleaning up file

---

diff --git a/hubs/app.py b/hubs/app.py
index 7e24193..5a1404d 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -554,6 +554,34 @@ def get_hub(session, name):
     return hub
 
 
+@app.route('/visit/<visited_hub>/', methods=['GET', 'POST'])
+@app.route('/visit/<visited_hub>', methods=['GET', 'POST'])
+@login_required
+def increment_counter(visited_hub):
+    nickname = flask.g.auth.nickname
+
+    if str(visited_hub) != str(nickname):
+        try:
+            vc = hubs.models.VisitCounter.get_or_create(session=session,
+                                                        username=nickname,
+                                                        visited_hub=visited_hub)
+        except ValueError:  # this should never trip
+            # flask will 405 if visited_hub is blank
+            # @login_required forces flask.g.auth to be sets
+            flask.abort(404)
+        if flask.request.method == 'POST':
+            vc.increment_visits(session=session,
+                                username=nickname,
+                                visited_hub=visited_hub)
+
+            return flask.jsonify({'count': vc.count})
+
+        elif flask.request.method == 'GET':
+            return flask.jsonify({'count': vc.count})
+    else:
+        return flask.abort(403)
+
+
 def get_widget(session, hub, idx):
     """ Utility shorthand to get a widget and 404 if not found. """
     try:
diff --git a/hubs/models.py b/hubs/models.py
index ad3bc16..ede60dc 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -419,3 +419,62 @@ class User(BASE):
 
             session.commit()
         return self
+
+
+class VisitCounter(BASE):
+    __tablename__ = 'visit_counter'
+    count = sa.Column(sa.Integer, default=0, nullable=False)
+
+    visited_hub = sa.Column(sa.String(50),
+                       sa.ForeignKey('hubs.name'),
+                       primary_key=True)
+
+    username = sa.Column(sa.Text,
+                        sa.ForeignKey('users.username'),
+                        primary_key=True)
+
+    user = relation("User", backref=backref('visit_counters', cascade="all, delete, delete-orphan"))
+    hub = relation("Hub", backref=backref('visit_counters', cascade="all, delete, delete-orphan"))
+
+    @classmethod
+    def by_username(cls, session, username):
+        return session.query(cls).filter_by(username=username).all()
+
+    @classmethod
+    def get_visits_by_username_hub(cls, session, username, visited_hub):
+        return session.query(cls).filter_by(username=username, visited_hub=visited_hub).first()
+
+    @classmethod
+    def increment_visits(cls, session, username, visited_hub):
+        row = cls.get_or_create(session, username=username,
+                                visited_hub=visited_hub)
+        row.count += 1
+        session.commit()
+
+    @classmethod
+    def _does_hub_exist(cls, session, hub=''):
+        return session.query(Hub).filter_by(name=hub).first() is not None
+
+    @classmethod
+    def _does_user_exist(cls, session, user=''):
+        return session.query(User).filter_by(username=user).first() is not None
+
+    @classmethod
+    def get_or_create(cls, session, username, visited_hub):
+        if not username:
+            raise ValueError("Must provide an username, not %r" % username)
+
+        if not visited_hub:
+            raise ValueError("Must provide an hub, not %r" % visited_hub)
+
+        if not cls._does_hub_exist(session, hub=visited_hub) \
+                or not cls._does_user_exist(session, user=username):
+            raise ValueError("Must provide a hub/user that exists")
+
+        self = cls.get_visits_by_username_hub(session, username=username,
+                                              visited_hub=visited_hub)
+        if not self:
+            self = cls(username=username, visited_hub=visited_hub)
+            session.add(self)
+            session.commit()
+        return self
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 618c45a..c4e6b92 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -274,6 +274,30 @@ function setup_edit_btns() {
   });
 }
 
+function visit_counter() {
+  if (window.performance.navigation.type == 0) {
+    var username = '{{ g.auth.nickname }}'
+    var visited_hub = '{{ hub.name }}'
+    if(username != null && username != '' && username != visited_hub) {
+      url_str = '/visit/' + visited_hub;
+
+      $.ajax({
+        method: "POST",
+        url: url_str,
+        dataType: 'html',
+        success: function(html) {
+          console.log('Success: incrementing counter')
+        },
+        error: function() {
+          console.log('Error: incrementing counter');
+        },
+      });
+    }
+  }
+}
+
+visit_counter()
+
 function setup_widgets(widgets) {
   var all_widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
   if (widgets == undefined) {
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 7b7dbff..d099987 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -285,5 +285,46 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 302)
             self.assertEqual(urlparse(result.location).path, '/ralph/')
 
+    def test_hub_visit_counter_logged_in(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/visit/decause'
+            result = self.app.get(url)
+            self.assertEqual(json.loads(result.data), {"count": 0})
+
+            result = self.app.post(url)
+            self.assertEqual(json.loads(result.data), {"count": 1})
+
+            # accessing my hub shouldn't increment the count
+            url = 'visit/ralph'
+            result = self.app.post(url)
+            self.assertEqual(result.status_code, 403)
+
+            # visiting no hub while logged should throw a 405
+            url = 'visit/'
+            result = self.app.post(url)
+            self.assertEqual(result.status_code, 405)
+
+            # visiting a hub that doesn't exist should 404
+            url = 'visit/hub-does-not-exist'
+            result = self.app.post(url)
+            self.assertEqual(result.status_code, 404)
+
+    @unittest.skip("Ajax calls don't seem to work in unittests ")
+    def test_hub_vist_counter_logged_in_2(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/visit/decause'
+            result = self.app.get(url)
+            self.assertEqual(result.data, '0')
+
+            url = '/decause'
+            result = self.app.get(url, follow_redirects=True)
+
+            url = '/visit/decause'
+            result = self.app.get(url)
+            self.assertEqual(result.data, '1')
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index e787c68..c3d540d 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -88,3 +88,73 @@ class ModelTest(hubs.tests.APPTest):
 
         hub = hubs.models.Hub.get(self.session, username)
         self.assertIsNone(hub)
+
+    def test_visit_counter(self):
+        username = 'ralph'
+        hub = 'decause'
+        # Make sure the table is empty of data
+        vc = hubs.models.VisitCounter.get_visits_by_username_hub(
+            session=self.session, username=username, visited_hub=hub)
+        self.assertIsNone(vc)
+
+        # Insert a new counter row
+        vc = hubs.models.VisitCounter.get_or_create(
+            session=self.session, username=username, visited_hub=hub)
+        # Make sure its init to 0
+        self.assertEqual(vc.count, 0)
+
+        # Increment counter and make sure its 1
+        hubs.models.VisitCounter.increment_visits(
+            session=self.session, username=username, visited_hub=hub)
+        self.assertEqual(vc.count, 1)
+
+        # Delete the counter make sure the hub/user is still arround
+        vc = hubs.models.VisitCounter.get_or_create(
+            session=self.session, username=username, visited_hub=hub)
+        self.session.delete(vc)
+        hub_obj = hubs.models.Hub.get(self.session, username)
+        self.assertIsNotNone(hub_obj)
+        user_obj = hubs.models.User.get(session=self.session,
+                                        username=username)
+        self.assertIsNotNone(user_obj)
+
+        # Delete hub and make sure the visit counter is 0
+        vc = hubs.models.VisitCounter.get_visits_by_username_hub(
+            session=self.session, username=username, visited_hub=hub)
+        self.session.delete(hub_obj)
+        self.assertIsNone(vc)
+        user_obj = hubs.models.User.get(session=self.session,
+                                        username=username)
+        self.assertIsNotNone(user_obj)
+
+    def test_visit_counter_does_not_exist(self):
+        username = 'ralph'
+        hub = 'does-not-exist'
+        self.assertRaises(ValueError,
+                          hubs.models.VisitCounter.get_or_create,
+                          session=self.session,
+                          username=username,
+                          visited_hub=hub)
+
+        username = 'does-not-exist'
+        hub = 'ralph'
+        # Make sure the table is empty of data
+        self.assertRaises(ValueError,
+                          hubs.models.VisitCounter.get_or_create,
+                          session=self.session,
+                          username=username,
+                          visited_hub=hub)
+
+        username = 'does-not-exist'
+        hub = 'does-not-exist'
+        # Make sure the table is empty of data
+        self.assertRaises(ValueError,
+                          hubs.models.VisitCounter.get_or_create,
+                          session=self.session,
+                          username=username,
+                          visited_hub=hub)
+
+
+
+
+
diff --git a/populate.py b/populate.py
index a9cbe39..986d5b5 100755
--- a/populate.py
+++ b/populate.py
@@ -237,7 +237,8 @@ hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=3, left=True)
 hub.widgets.append(widget)
 
-
+vc = hubs.models.VisitCounter().get_or_create(session, 'ralph', 'mrichard')
+hubs.models.VisitCounter().increment_visits(session, 'ralph', 'mrichard')
 hub.subscribe(session, hubs.models.User.by_username(session, 'ralph'), 'owner')
 hub.subscribe(session, hubs.models.User.by_username(session, 'abompard'), 'owner')
 hub.subscribe(session, hubs.models.User.by_username(session, 'lmacken'), 'owner')

From 8c52e919fbf728bf2ec44a14d6a35e0f01d413b7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 20:49:03 +0000
Subject: [PATCH 549/1001] Allow configuring the number of meeting shown in the meetings widget


---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 04e0868..faf38f6 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -64,7 +64,12 @@ position = 'both'
           default=None,
           validator=validators.required,
           help="A fedocal calendar.")
-def data(session, widget, calendar):
+@argument(name="n_meetings",
+          default=4,
+          validator=validators.integer,
+          help="The number of meetings to display.")
+def data(session, widget, calendar, n_meetings=4):
+    n_meetings = int(n_meetings)
     base = 'https://apps.fedoraproject.org/calendar/api/meetings/?calendar=%s'
     url = base % calendar
     response = requests.get(url).json()
@@ -82,6 +87,8 @@ def data(session, widget, calendar):
         if not selected:
             continue
         meetings[title] = selected
+        if len(meetings) >= n_meetings:
+            break
 
     return dict(meetings=meetings)
 

From 60708464a2e04cba18622a0441cf3aad732443c1 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 20:49:03 +0000
Subject: [PATCH 550/1001] Let the validator return the validated value and use it when editing a widget


---

diff --git a/hubs/app.py b/hubs/app.py
index 5a1404d..c152053 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -411,7 +411,7 @@ def widget_edit_post(hub, idx):
             error = True
             break
         try:
-            arg.validator(session, val)
+            val = arg.validator(session, val)
             config[arg.name] = val
         except Exception as err:
             flask.flash('Invalid data provided, error: %s' % err, 'error')
diff --git a/hubs/validators.py b/hubs/validators.py
index bdc3c96..791f3fe 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -4,7 +4,8 @@ import hubs.models
 
 
 def required(session, value):
-    return bool(value)
+    if bool(value):
+        return value
 
 
 def text(session, value):

From 889b35b32a02d11473d8581ed56a3754f283ecfb Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 20:49:03 +0000
Subject: [PATCH 551/1001] Always display the meetings widget, even if there are no coming meetings


This allows configuring the widget, for example if you made a mistake
when entering the calendar's name

---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index faf38f6..071496a 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -54,7 +54,7 @@ def next_meeting(meetings):
 
 
 footer_template = templating.environment.get_template('templates/meeting_footer.html')
-chrome = panel(title = 'Meetings', key='meetings', footer_template=footer_template)
+chrome = panel(title='Meetings', footer_template=footer_template)
 templating.environment.filters['humanize'] = lambda d: arrow.get(d).humanize()
 template = templating.environment.get_template('templates/meetings.html')
 position = 'both'
@@ -69,7 +69,6 @@ position = 'both'
           validator=validators.integer,
           help="The number of meetings to display.")
 def data(session, widget, calendar, n_meetings=4):
-    n_meetings = int(n_meetings)
     base = 'https://apps.fedoraproject.org/calendar/api/meetings/?calendar=%s'
     url = base % calendar
     response = requests.get(url).json()
@@ -90,7 +89,10 @@ def data(session, widget, calendar, n_meetings=4):
         if len(meetings) >= n_meetings:
             break
 
-    return dict(meetings=meetings)
+    return dict(
+        calendar=calendar,
+        meetings=meetings,
+    )
 
 
 @hint(ubiquitous=True)
diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index 7725729..b101c5f 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -1,4 +1,3 @@
-{% if meetings %}
 {% for title, next in meetings.items() %}
 <div class="meeting">
   <div class="row">
@@ -40,5 +39,10 @@
   {% endif  %}
 </div>
 {% if meetings | length > 1 %} <hr> {% endif %}
+{% else %}
+<div class="meeting">
+  <div class="row">
+    No coming meetings in {{ calendar }}.
+  </div>
+</div>
 {% endfor %}
-{% endif %}

From e44bec93d562130b284b910ca87f1c1569574ed3 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 20:53:16 +0000
Subject: [PATCH 552/1001] Fix indentation in the HTML


---

diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 6fce42f..9885a78 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -82,7 +82,7 @@
 {% block jscripts %}
 <script type="text/javascript" src="{{
   url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
-  <script type="text/javascript" src="{{
+<script type="text/javascript" src="{{
   url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
 {% endblock %}
 

From 1dd784a208358d567eefa323865d647aac7f2c17 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 20:53:16 +0000
Subject: [PATCH 553/1001] Add autocompletion when adding/editing a calendar in a widget


---

diff --git a/hubs/static/js/bootstrap3-typeahead.min.js b/hubs/static/js/bootstrap3-typeahead.min.js
new file mode 100644
index 0000000..1126208
--- /dev/null
+++ b/hubs/static/js/bootstrap3-typeahead.min.js
@@ -0,0 +1 @@
+!function(a,b){"use strict";"undefined"!=typeof module&&module.exports?module.exports=b(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):b(a.jQuery)}(this,function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.select=this.options.select||this.select,this.autoSelect="boolean"==typeof this.options.autoSelect?this.options.autoSelect:!0,this.highlighter=this.options.highlighter||this.highlighter,this.render=this.options.render||this.render,this.updater=this.options.updater||this.updater,this.displayText=this.options.displayText||this.displayText,this.source=this.options.source,this.delay=this.options.delay,this.$menu=a(this.options.menu),this.$appendTo=this.options.appendTo?a(this.options.appendTo):null,this.shown=!1,this.listen(),this.showHintOnFocus="boolean"==typeof this.options.showHintOnFocus?this.options.showHintOnFocus:!1,this.afterSelect=this.options.afterSelect,this.addItem=!1};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").data("value");if(this.$element.data("active",a),this.autoSelect||a){var b=this.updater(a);b||(b=""),this.$element.val(this.displayText(b)||b).text(this.displayText(b)||b).change(),this.afterSelect(b)}return this.hide()},updater:function(a){return a},setSource:function(a){this.source=a},show:function(){var b,c=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight}),d="function"==typeof this.options.scrollHeight?this.options.scrollHeight.call():this.options.scrollHeight;b=this.shown?this.$menu:this.$appendTo?this.$menu.appendTo(this.$appendTo):this.$menu.insertAfter(this.$element);var e=a(b).parent().hasClass("dropup"),f=e?"auto":c.top+c.height+d,g=a(b).hasClass("dropdown-menu-right"),h=g?"auto":c.left;return b.css({top:f,left:h}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){if("undefined"!=typeof b&&null!==b?this.query=b:this.query=this.$element.val()||this.$element.text()||"",this.query.length<this.options.minLength&&!this.options.showHintOnFocus)return this.shown?this.hide():this;var c=a.proxy(function(){a.isFunction(this.source)?this.source(this.query,a.proxy(this.process,this)):this.source&&this.process(this.source)},this);clearTimeout(this.lookupWorker),this.lookupWorker=setTimeout(c,this.delay)},process:function(b){var c=this;return b=a.grep(b,function(a){return c.matcher(a)}),b=this.sorter(b),b.length||this.options.addItem?(b.length>0?this.$element.data("active",b[0]):this.$element.data("active",null),this.options.addItem&&b.push(this.options.addItem),"all"==this.options.items?this.render(b).show():this.render(b.slice(0,this.options.items)).show()):this.shown?this.hide():this},matcher:function(a){var b=this.displayText(a);return~b.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){for(var b,c=[],d=[],e=[];b=a.shift();){var f=this.displayText(b);f.toLowerCase().indexOf(this.query.toLowerCase())?~f.indexOf(this.query)?d.push(b):e.push(b):c.push(b)}return c.concat(d,e)},highlighter:function(b){var c,d,e,f,g=a("<div></div>"),h=this.query,i=b.toLowerCase().indexOf(h.toLowerCase()),j=h.length;if(0===j)return g.text(b).html();for(;i>-1;)c=b.substr(0,i),d=b.substr(i,j),e=b.substr(i+j),f=a("<strong></strong>").text(d),g.append(document.createTextNode(c)).append(f),b=e,i=b.toLowerCase().indexOf(h.toLowerCase());return g.append(document.createTextNode(b)).html()},render:function(b){var c=this,d=this,e=!1,f=[],g=c.options.separator;return a.each(b,function(a,c){a>0&&c[g]!==b[a-1][g]&&f.push({__type:"divider"}),!c[g]||0!==a&&c[g]===b[a-1][g]||f.push({__type:"category",name:c[g]}),f.push(c)}),b=a(f).map(function(b,f){if("category"==(f.__type||!1))return a(c.options.headerHtml).text(f.name)[0];if("divider"==(f.__type||!1))return a(c.options.headerDivider)[0];var g=d.displayText(f);return b=a(c.options.item).data("value",f),b.find("a").html(c.highlighter(g,f)),g==d.$element.val()&&(b.addClass("active"),d.$element.data("active",f),e=!0),b[0]}),this.autoSelect&&!e&&(b.filter(":not(.dropdown-header)").first().addClass("active"),this.$element.data("active",b.first().data("value"))),this.$menu.html(b),this},displayText:function(a){return"undefined"!=typeof a&&"undefined"!=typeof a.name&&a.name||a},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("input",a.proxy(this.input,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this)).on("mousedown",a.proxy(this.mousedown,this))},mousedown:function(a){this.mouseddown=!0,a.stopPropagation(),a.preventDefault()},destroy:function(){this.$element.data("typeahead",null),this.$element.data("active",null),this.$element.off("focus").off("blur").off("keypress").off("input").off("keyup"),this.eventSupported("keydown")&&this.$element.off("keydown"),this.$menu.remove();this.destroyed=true;},eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b="function"==typeof this.$element[a]),b},move:function(a){if(this.shown)switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.shiftKey)return;a.preventDefault(),this.prev();break;case 40:if(a.shiftKey)return;a.preventDefault(),this.next()}},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.shown||40!=b.keyCode?this.move(b):this.lookup()},keypress:function(a){this.suppressKeyPressRepeat||this.move(a)},input:function(a){this.lookup(),a.preventDefault()},keyup:function(a){if(this.destroyed){return};switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide()}a.preventDefault()},focus:function(a){this.focused||(this.focused=!0,this.options.showHintOnFocus&&this.lookup())},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&(this.mouseddown&&a.originalEvent?this.mouseddown=!1:this.hide())},click:function(a){a.preventDefault(),this.select(),this.$element.focus(),this.hide()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1}};var c=a.fn.typeahead;a.fn.typeahead=function(c){var d=arguments;return"string"==typeof c&&"getActive"==c?this.data("active"):this.each(function(){var e=a(this),f=e.data("typeahead"),g="object"==typeof c&&c;f||e.data("typeahead",f=new b(this,g)),"string"==typeof c&&f[c]&&(d.length>1?f[c].apply(f,Array.prototype.slice.call(d,1)):f[c]())})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu" role="listbox"></ul>',item:'<li><a class="dropdown-item" href="#" role="option"></a></li>',minLength:1,scrollHeight:0,autoSelect:!0,afterSelect:a.noop,addItem:!1,delay:0,separator:"category",headerHtml:'<li class="dropdown-header"></li>',headerDivider:'<li class="divider" role="separator"></li>'},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);c.data("typeahead")||c.typeahead(c.data())})});
\ No newline at end of file
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index e31087a..9f536a6 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -43,6 +43,29 @@
         <button type="submit" class="btn btn-danger" id="delete_widget">
           Remove this widget
         </button>
-    <form>
+    </form>
   </div>
 </div>
+
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/bootstrap3-typeahead.min.js') }}"></script>
+<script type="text/javascript">
+$(function(){
+  if ($('#calendar') != null){
+    $.get(
+      'https://apps.fedoraproject.org/calendar/api/calendars/',
+      function(data){
+        data = JSON.parse(data);
+        var d = [];
+        for (i=0; i<data.calendars.length; i++ ){
+          d.push(data.calendars[i].calendar_name)
+        }
+        $('#calendar').typeahead({ source: d });
+      },
+      'jsonp'
+    );
+  }
+});
+</script>

From c3423a02c9dd415ad82788b76d45b724b11dd15e Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 20:53:16 +0000
Subject: [PATCH 554/1001] Include the header in bootstrap3-typeahead.min.js


---

diff --git a/hubs/static/js/bootstrap3-typeahead.min.js b/hubs/static/js/bootstrap3-typeahead.min.js
index 1126208..b8ffd9d 100644
--- a/hubs/static/js/bootstrap3-typeahead.min.js
+++ b/hubs/static/js/bootstrap3-typeahead.min.js
@@ -1 +1,21 @@
-!function(a,b){"use strict";"undefined"!=typeof module&&module.exports?module.exports=b(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):b(a.jQuery)}(this,function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.select=this.options.select||this.select,this.autoSelect="boolean"==typeof this.options.autoSelect?this.options.autoSelect:!0,this.highlighter=this.options.highlighter||this.highlighter,this.render=this.options.render||this.render,this.updater=this.options.updater||this.updater,this.displayText=this.options.displayText||this.displayText,this.source=this.options.source,this.delay=this.options.delay,this.$menu=a(this.options.menu),this.$appendTo=this.options.appendTo?a(this.options.appendTo):null,this.shown=!1,this.listen(),this.showHintOnFocus="boolean"==typeof this.options.showHintOnFocus?this.options.showHintOnFocus:!1,this.afterSelect=this.options.afterSelect,this.addItem=!1};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").data("value");if(this.$element.data("active",a),this.autoSelect||a){var b=this.updater(a);b||(b=""),this.$element.val(this.displayText(b)||b).text(this.displayText(b)||b).change(),this.afterSelect(b)}return this.hide()},updater:function(a){return a},setSource:function(a){this.source=a},show:function(){var b,c=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight}),d="function"==typeof this.options.scrollHeight?this.options.scrollHeight.call():this.options.scrollHeight;b=this.shown?this.$menu:this.$appendTo?this.$menu.appendTo(this.$appendTo):this.$menu.insertAfter(this.$element);var e=a(b).parent().hasClass("dropup"),f=e?"auto":c.top+c.height+d,g=a(b).hasClass("dropdown-menu-right"),h=g?"auto":c.left;return b.css({top:f,left:h}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){if("undefined"!=typeof b&&null!==b?this.query=b:this.query=this.$element.val()||this.$element.text()||"",this.query.length<this.options.minLength&&!this.options.showHintOnFocus)return this.shown?this.hide():this;var c=a.proxy(function(){a.isFunction(this.source)?this.source(this.query,a.proxy(this.process,this)):this.source&&this.process(this.source)},this);clearTimeout(this.lookupWorker),this.lookupWorker=setTimeout(c,this.delay)},process:function(b){var c=this;return b=a.grep(b,function(a){return c.matcher(a)}),b=this.sorter(b),b.length||this.options.addItem?(b.length>0?this.$element.data("active",b[0]):this.$element.data("active",null),this.options.addItem&&b.push(this.options.addItem),"all"==this.options.items?this.render(b).show():this.render(b.slice(0,this.options.items)).show()):this.shown?this.hide():this},matcher:function(a){var b=this.displayText(a);return~b.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){for(var b,c=[],d=[],e=[];b=a.shift();){var f=this.displayText(b);f.toLowerCase().indexOf(this.query.toLowerCase())?~f.indexOf(this.query)?d.push(b):e.push(b):c.push(b)}return c.concat(d,e)},highlighter:function(b){var c,d,e,f,g=a("<div></div>"),h=this.query,i=b.toLowerCase().indexOf(h.toLowerCase()),j=h.length;if(0===j)return g.text(b).html();for(;i>-1;)c=b.substr(0,i),d=b.substr(i,j),e=b.substr(i+j),f=a("<strong></strong>").text(d),g.append(document.createTextNode(c)).append(f),b=e,i=b.toLowerCase().indexOf(h.toLowerCase());return g.append(document.createTextNode(b)).html()},render:function(b){var c=this,d=this,e=!1,f=[],g=c.options.separator;return a.each(b,function(a,c){a>0&&c[g]!==b[a-1][g]&&f.push({__type:"divider"}),!c[g]||0!==a&&c[g]===b[a-1][g]||f.push({__type:"category",name:c[g]}),f.push(c)}),b=a(f).map(function(b,f){if("category"==(f.__type||!1))return a(c.options.headerHtml).text(f.name)[0];if("divider"==(f.__type||!1))return a(c.options.headerDivider)[0];var g=d.displayText(f);return b=a(c.options.item).data("value",f),b.find("a").html(c.highlighter(g,f)),g==d.$element.val()&&(b.addClass("active"),d.$element.data("active",f),e=!0),b[0]}),this.autoSelect&&!e&&(b.filter(":not(.dropdown-header)").first().addClass("active"),this.$element.data("active",b.first().data("value"))),this.$menu.html(b),this},displayText:function(a){return"undefined"!=typeof a&&"undefined"!=typeof a.name&&a.name||a},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("input",a.proxy(this.input,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this)).on("mousedown",a.proxy(this.mousedown,this))},mousedown:function(a){this.mouseddown=!0,a.stopPropagation(),a.preventDefault()},destroy:function(){this.$element.data("typeahead",null),this.$element.data("active",null),this.$element.off("focus").off("blur").off("keypress").off("input").off("keyup"),this.eventSupported("keydown")&&this.$element.off("keydown"),this.$menu.remove();this.destroyed=true;},eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b="function"==typeof this.$element[a]),b},move:function(a){if(this.shown)switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.shiftKey)return;a.preventDefault(),this.prev();break;case 40:if(a.shiftKey)return;a.preventDefault(),this.next()}},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.shown||40!=b.keyCode?this.move(b):this.lookup()},keypress:function(a){this.suppressKeyPressRepeat||this.move(a)},input:function(a){this.lookup(),a.preventDefault()},keyup:function(a){if(this.destroyed){return};switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide()}a.preventDefault()},focus:function(a){this.focused||(this.focused=!0,this.options.showHintOnFocus&&this.lookup())},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&(this.mouseddown&&a.originalEvent?this.mouseddown=!1:this.hide())},click:function(a){a.preventDefault(),this.select(),this.$element.focus(),this.hide()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1}};var c=a.fn.typeahead;a.fn.typeahead=function(c){var d=arguments;return"string"==typeof c&&"getActive"==c?this.data("active"):this.each(function(){var e=a(this),f=e.data("typeahead"),g="object"==typeof c&&c;f||e.data("typeahead",f=new b(this,g)),"string"==typeof c&&f[c]&&(d.length>1?f[c].apply(f,Array.prototype.slice.call(d,1)):f[c]())})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu" role="listbox"></ul>',item:'<li><a class="dropdown-item" href="#" role="option"></a></li>',minLength:1,scrollHeight:0,autoSelect:!0,afterSelect:a.noop,addItem:!1,delay:0,separator:"category",headerHtml:'<li class="dropdown-header"></li>',headerDivider:'<li class="divider" role="separator"></li>'},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);c.data("typeahead")||c.typeahead(c.data())})});
\ No newline at end of file
+/* =============================================================
+ * bootstrap3-typeahead.js v3.1.0
+ * https://github.com/bassjobsen/Bootstrap-3-Typeahead
+ * =============================================================
+ * Original written by @mdo and @fat
+ * =============================================================
+ * Copyright 2014 Bass Jobsen @bassjobsen
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+!function(a,b){"use strict";"undefined"!=typeof module&&module.exports?module.exports=b(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):b(a.jQuery)}(this,function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.select=this.options.select||this.select,this.autoSelect="boolean"==typeof this.options.autoSelect?this.options.autoSelect:!0,this.highlighter=this.options.highlighter||this.highlighter,this.render=this.options.render||this.render,this.updater=this.options.updater||this.updater,this.displayText=this.options.displayText||this.displayText,this.source=this.options.source,this.delay=this.options.delay,this.$menu=a(this.options.menu),this.$appendTo=this.options.appendTo?a(this.options.appendTo):null,this.shown=!1,this.listen(),this.showHintOnFocus="boolean"==typeof this.options.showHintOnFocus?this.options.showHintOnFocus:!1,this.afterSelect=this.options.afterSelect,this.addItem=!1};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").data("value");if(this.$element.data("active",a),this.autoSelect||a){var b=this.updater(a);b||(b=""),this.$element.val(this.displayText(b)||b).text(this.displayText(b)||b).change(),this.afterSelect(b)}return this.hide()},updater:function(a){return a},setSource:function(a){this.source=a},show:function(){var b,c=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight}),d="function"==typeof this.options.scrollHeight?this.options.scrollHeight.call():this.options.scrollHeight;b=this.shown?this.$menu:this.$appendTo?this.$menu.appendTo(this.$appendTo):this.$menu.insertAfter(this.$element);var e=a(b).parent().hasClass("dropup"),f=e?"auto":c.top+c.height+d,g=a(b).hasClass("dropdown-menu-right"),h=g?"auto":c.left;return b.css({top:f,left:h}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){if("undefined"!=typeof b&&null!==b?this.query=b:this.query=this.$element.val()||this.$element.text()||"",this.query.length<this.options.minLength&&!this.options.showHintOnFocus)return this.shown?this.hide():this;var c=a.proxy(function(){a.isFunction(this.source)?this.source(this.query,a.proxy(this.process,this)):this.source&&this.process(this.source)},this);clearTimeout(this.lookupWorker),this.lookupWorker=setTimeout(c,this.delay)},process:function(b){var c=this;return b=a.grep(b,function(a){return c.matcher(a)}),b=this.sorter(b),b.length||this.options.addItem?(b.length>0?this.$element.data("active",b[0]):this.$element.data("active",null),this.options.addItem&&b.push(this.options.addItem),"all"==this.options.items?this.render(b).show():this.render(b.slice(0,this.options.items)).show()):this.shown?this.hide():this},matcher:function(a){var b=this.displayText(a);return~b.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){for(var b,c=[],d=[],e=[];b=a.shift();){var f=this.displayText(b);f.toLowerCase().indexOf(this.query.toLowerCase())?~f.indexOf(this.query)?d.push(b):e.push(b):c.push(b)}return c.concat(d,e)},highlighter:function(b){var c,d,e,f,g=a("<div></div>"),h=this.query,i=b.toLowerCase().indexOf(h.toLowerCase()),j=h.length;if(0===j)return g.text(b).html();for(;i>-1;)c=b.substr(0,i),d=b.substr(i,j),e=b.substr(i+j),f=a("<strong></strong>").text(d),g.append(document.createTextNode(c)).append(f),b=e,i=b.toLowerCase().indexOf(h.toLowerCase());return g.append(document.createTextNode(b)).html()},render:function(b){var c=this,d=this,e=!1,f=[],g=c.options.separator;return a.each(b,function(a,c){a>0&&c[g]!==b[a-1][g]&&f.push({__type:"divider"}),!c[g]||0!==a&&c[g]===b[a-1][g]||f.push({__type:"category",name:c[g]}),f.push(c)}),b=a(f).map(function(b,f){if("category"==(f.__type||!1))return a(c.options.headerHtml).text(f.name)[0];if("divider"==(f.__type||!1))return a(c.options.headerDivider)[0];var g=d.displayText(f);return b=a(c.options.item).data("value",f),b.find("a").html(c.highlighter(g,f)),g==d.$element.val()&&(b.addClass("active"),d.$element.data("active",f),e=!0),b[0]}),this.autoSelect&&!e&&(b.filter(":not(.dropdown-header)").first().addClass("active"),this.$element.data("active",b.first().data("value"))),this.$menu.html(b),this},displayText:function(a){return"undefined"!=typeof a&&"undefined"!=typeof a.name&&a.name||a},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("input",a.proxy(this.input,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this)).on("mousedown",a.proxy(this.mousedown,this))},mousedown:function(a){this.mouseddown=!0,a.stopPropagation(),a.preventDefault()},destroy:function(){this.$element.data("typeahead",null),this.$element.data("active",null),this.$element.off("focus").off("blur").off("keypress").off("input").off("keyup"),this.eventSupported("keydown")&&this.$element.off("keydown"),this.$menu.remove();this.destroyed=true;},eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b="function"==typeof this.$element[a]),b},move:function(a){if(this.shown)switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.shiftKey)return;a.preventDefault(),this.prev();break;case 40:if(a.shiftKey)return;a.preventDefault(),this.next()}},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.shown||40!=b.keyCode?this.move(b):this.lookup()},keypress:function(a){this.suppressKeyPressRepeat||this.move(a)},input:function(a){this.lookup(),a.preventDefault()},keyup:function(a){if(this.destroyed){return};switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide()}a.preventDefault()},focus:function(a){this.focused||(this.focused=!0,this.options.showHintOnFocus&&this.lookup())},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&(this.mouseddown&&a.originalEvent?this.mouseddown=!1:this.hide())},click:function(a){a.preventDefault(),this.select(),this.$element.focus(),this.hide()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1}};var c=a.fn.typeahead;a.fn.typeahead=function(c){var d=arguments;return"string"==typeof c&&"getActive"==c?this.data("active"):this.each(function(){var e=a(this),f=e.data("typeahead"),g="object"==typeof c&&c;f||e.data("typeahead",f=new b(this,g)),"string"==typeof c&&f[c]&&(d.length>1?f[c].apply(f,Array.prototype.slice.call(d,1)):f[c]())})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu" role="listbox"></ul>',item:'<li><a class="dropdown-item" href="#" role="option"></a></li>',minLength:1,scrollHeight:0,autoSelect:!0,afterSelect:a.noop,addItem:!1,delay:0,separator:"category",headerHtml:'<li class="dropdown-header"></li>',headerDivider:'<li class="divider" role="separator"></li>'},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);c.data("typeahead")||c.typeahead(c.data())})});

From a7951e86f77b04463a1ceaa0193f9c941f420edd Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 21:04:23 +0000
Subject: [PATCH 555/1001] Move the logic to a separate file and re-import fedora-bootstrap


---

diff --git a/hubs/static/js/hubs_input.js b/hubs/static/js/hubs_input.js
new file mode 100644
index 0000000..79b0fb0
--- /dev/null
+++ b/hubs/static/js/hubs_input.js
@@ -0,0 +1,13 @@
+$(function(){
+  if ($('#calendar') != null){
+    $.get(
+      'https://apps.fedoraproject.org/calendar/api/calendars/',
+      function(data){
+        data = JSON.parse(data);
+        var d = data.calendars.map(function(cal) { return cal.calendar_name; });
+        $('#calendar').typeahead({ source: d });
+      },
+      'jsonp'
+    );
+  }
+});
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index 9f536a6..a04145a 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -50,22 +50,8 @@
 <script type="text/javascript" src="{{
   url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script type="text/javascript" src="{{
+  url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
+<script type="text/javascript" src="{{
   url_for('static', filename='js/bootstrap3-typeahead.min.js') }}"></script>
-<script type="text/javascript">
-$(function(){
-  if ($('#calendar') != null){
-    $.get(
-      'https://apps.fedoraproject.org/calendar/api/calendars/',
-      function(data){
-        data = JSON.parse(data);
-        var d = [];
-        for (i=0; i<data.calendars.length; i++ ){
-          d.push(data.calendars[i].calendar_name)
-        }
-        $('#calendar').typeahead({ source: d });
-      },
-      'jsonp'
-    );
-  }
-});
-</script>
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/hubs_input.js') }}"></script>

From a0a7df7fe24d2dfb5a8838393fb47a801437ad54 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 21:08:08 +0000
Subject: [PATCH 556/1001] Impot the hubs_input.js file when adding the widget as well


This way we can also benefit from all the goodies we have when editing

---

diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index 6aa0dfa..422cb84 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -81,4 +81,13 @@ $("#submit_btn").click(function() {
 
 });
 </script>
+{% else %}
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+<script type="text/javascript" src="{{
+  url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/bootstrap3-typeahead.min.js') }}"></script>
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/hubs_input.js') }}"></script>
 {% endif %}

From 7f30e18d0134c5c0c766b39e6ffe8bd87192da60 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 21:16:48 +0000
Subject: [PATCH 557/1001] Redirect the user to the page they are viewing after logging in


---

diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 9885a78..5378ea4 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -37,7 +37,8 @@
         </div>
         <img id="chaticon" class="pull-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
       {% else %}
-        Not logged in.  Click to <a href="{{url_for('login')}}">login</a>.
+        Not logged in.  Click to <a href="{{ url_for(
+            'login', next=request.url) }}">login</a>.
       {% endif %}
     </div>
     <div class="col-sm-4 col-sm-pull-4 col-xs-12">

From 1236c4d7f040fed1c2a60063715ab76d9ab2de2d Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 21:20:45 +0000
Subject: [PATCH 558/1001] Add a clean_input module in hubs.widget


This allows to clean the input provided by the users to ensure there is
nothing malicious in it.

---

diff --git a/hubs/widgets/clean_input.py b/hubs/widgets/clean_input.py
new file mode 100644
index 0000000..46bccbc
--- /dev/null
+++ b/hubs/widgets/clean_input.py
@@ -0,0 +1,40 @@
+import urlparse
+
+import bleach
+
+
+def filter_img_src(name, value):
+    ''' Filter in img html tags images coming from a different domain. '''
+    import hubs.app
+    if name in ('alt', 'height', 'width', 'class'):
+        return True
+    if name == 'src':
+        p = urlparse.urlparse(value)
+        return (not p.netloc) or p.netloc == urlparse.urlparse(
+            hubs.app.app.config['APP_URL']).netloc
+    return False
+
+
+def clean(text, ignore=None):
+    """ For a given html text, escape everything we do not want to support
+    to avoid potential security breach.
+    """
+    if ignore and not isinstance(ignore, (tuple, set, list)):
+        ignore = [ignore]
+
+    attrs = bleach.ALLOWED_ATTRIBUTES
+    if not ignore or not 'img' in ignore:
+        attrs['img'] = filter_img_src
+
+    tags = bleach.ALLOWED_TAGS + [
+        'p', 'br', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+        'table', 'td', 'tr', 'th',
+        'col', 'tbody', 'pre', 'img', 'hr', 'dl', 'dt', 'dd', 'span',
+        'kbd', 'var',
+    ]
+    if ignore:
+        for tag in ignore:
+            if tag in tags:
+                tags.remove(tag)
+
+    return bleach.clean(text, tags=tags, attributes=attrs)
diff --git a/requirements.txt b/requirements.txt
index 01e9cc9..c2dadcf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,5 @@
 arrow
+bleach
 datanommer.models
 dogpile.cache
 fedmsg

From 6ca3800b1048e98c15f0b753d58265616b7df59a Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 21:20:45 +0000
Subject: [PATCH 559/1001] Add a library widget where someone can provide a list of links of interest


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 2e72e00..a365c3d 100755
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -4,6 +4,7 @@ from hubs.widgets import rules
 from hubs.widgets import sticky
 from hubs.widgets import about
 from hubs.widgets import badges
+from hubs.widgets import library
 from hubs.widgets import linechart
 from hubs.widgets import fedmsgstats
 from hubs.widgets import feed
@@ -27,6 +28,7 @@ registry = {
     'sticky': sticky,
     'about': about,
     'badges': badges,
+    'library': library,
     'linechart': linechart,
     'fedmsgstats': fedmsgstats,
     'feed': feed,
diff --git a/hubs/widgets/library.py b/hubs/widgets/library.py
new file mode 100644
index 0000000..8f0dc4b
--- /dev/null
+++ b/hubs/widgets/library.py
@@ -0,0 +1,32 @@
+from hubs.hinting import hint, prefixed as _
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import argument
+from hubs.widgets import clean_input
+from hubs.widgets import templating
+
+import hubs.validators as validators
+
+chrome = panel("Library")
+template = templating.environment.get_template('templates/library.html')
+position = 'both'
+
+
+@argument(name="urls", default=None,
+          validator=validators.text,
+          help="A comma separated list of URLs to add to the library.")
+def data(session, widget, urls):
+    urls = [
+        clean_input.clean('<a href="{0}">{0}</a>'.format(u.strip()))
+        for u in widget.config.get('urls', '').split(',')
+        if u.strip()
+    ]
+    return dict(urls=urls)
+
+
+@hint(topics=[_('hubs.widget.update')])
+def should_invalidate(message, session, widget):
+    if not message['topic'].endswith('hubs.widget.update'):
+        return False
+    if message['msg']['widget']['id'] != widget.id:
+        return False
+    return True
diff --git a/hubs/widgets/templates/library.html b/hubs/widgets/templates/library.html
new file mode 100644
index 0000000..4cbff48
--- /dev/null
+++ b/hubs/widgets/templates/library.html
@@ -0,0 +1,11 @@
+<div class="rules-container">
+  <div class="row">
+    <ul>
+    {% for url in urls %}
+    <li>
+      {{ url }}
+    </li>
+    {% endfor %}
+    </ul>
+  </div>
+</div>

From a0a5d1403f27e619137e61a251399b4e620a69e7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 21:25:44 +0000
Subject: [PATCH 560/1001] Improve the help message on the library widget


---

diff --git a/hubs/widgets/library.py b/hubs/widgets/library.py
index 8f0dc4b..2169f2f 100644
--- a/hubs/widgets/library.py
+++ b/hubs/widgets/library.py
@@ -13,7 +13,8 @@ position = 'both'
 
 @argument(name="urls", default=None,
           validator=validators.text,
-          help="A comma separated list of URLs to add to the library.")
+          help="A comma separated list of URLs to add to the library. "
+          "External links must include the whole link (starting with http...")
 def data(session, widget, urls):
     urls = [
         clean_input.clean('<a href="{0}">{0}</a>'.format(u.strip()))

From 99d00a7fc66be88db371691517494098199d4426 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 21:25:57 +0000
Subject: [PATCH 561/1001] Ensure the URLs are bytes not unicode before being .strip()


---

diff --git a/hubs/widgets/library.py b/hubs/widgets/library.py
index 2169f2f..5dd4f5a 100644
--- a/hubs/widgets/library.py
+++ b/hubs/widgets/library.py
@@ -17,9 +17,9 @@ position = 'both'
           "External links must include the whole link (starting with http...")
 def data(session, widget, urls):
     urls = [
-        clean_input.clean('<a href="{0}">{0}</a>'.format(u.strip()))
+        clean_input.clean('<a href="{0}">{0}</a>'.format(u.encode('utf-8').strip()))
         for u in widget.config.get('urls', '').split(',')
-        if u.strip()
+        if u.encode('utf-8').strip()
     ]
     return dict(urls=urls)
 

From a6ae66c22f4eee668d4abac590b037c4ea42e762 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 20 2016 21:26:37 +0000
Subject: [PATCH 562/1001] Typo in the doc


---

diff --git a/hubs/widgets/library.py b/hubs/widgets/library.py
index 5dd4f5a..c476ced 100644
--- a/hubs/widgets/library.py
+++ b/hubs/widgets/library.py
@@ -14,7 +14,7 @@ position = 'both'
 @argument(name="urls", default=None,
           validator=validators.text,
           help="A comma separated list of URLs to add to the library. "
-          "External links must include the whole link (starting with http...")
+          "External links must include the whole link (starting with http...)")
 def data(session, widget, urls):
     urls = [
         clean_input.clean('<a href="{0}">{0}</a>'.format(u.encode('utf-8').strip()))

From 42adc82a80eee1892b1078fc7e5aaa9260e70bb0 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 21 2016 14:49:14 +0000
Subject: [PATCH 563/1001] changing logo to match mockups


---

diff --git a/hubs/static/img/logo-hubs.png b/hubs/static/img/logo-hubs.png
index 5319490..574c327 100644
Binary files a/hubs/static/img/logo-hubs.png and b/hubs/static/img/logo-hubs.png differ
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 5378ea4..4fd92e5 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -18,7 +18,7 @@
 <div class="masthead">
   <div class="row p-a-0">
     <div class="col-xs-4" id="logo">
-      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs" height="40px" class="p-l-1">
+      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs" class="p-l-1">
     </div>
     <div class="col-sm-4 col-sm-push-4 col-xs-8">
       {% if g.auth.logged_in %}

From dfd20971d66cb56bee6a79ed1ddbf4c9d0f53457 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 21 2016 17:29:54 +0000
Subject: [PATCH 564/1001] nuking the horizontal scroll, has been driving me crazy


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 2e0f42d..1ffc8bb 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -114,6 +114,7 @@
     }
     .row {
       padding: 5px;
+      margin: auto 0px;
     }
     .padded {
       padding: 5px;

From 27f456a05884aa2754d1ef7bbc1d974816ab6a8b Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jul 21 2016 20:20:26 +0000
Subject: [PATCH 565/1001] Updating requirements file and readme


adding missing packages, also html5lib newest version is causing the test suite to crash, rolling back to last known working version

Making a note about html5lib breakage

removing html5lib fixed version

---

diff --git a/README.rst b/README.rst
index 531a78a..6c1b4f4 100644
--- a/README.rst
+++ b/README.rst
@@ -92,6 +92,18 @@ You can run it with::
     $ pip install -r test-requirements.txt
     $ ./runtest.sh
 
+
+
+If the unit tests are all failing and returning errors like this::
+
+    ImportError: cannot import name dummy
+
+
+It most likely is a result of html5lib breaking api stability. Please downgrade to the version below::
+
+    pip install html5lib==0.9999999
+
+
 See the options available with::
 
     $ ./runtest.sh --help
diff --git a/requirements.txt b/requirements.txt
index c2dadcf..a63b658 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,8 @@
 arrow
 bleach
+blinker
 datanommer.models
+decorator
 dogpile.cache
 fedmsg
 fedmsg_meta_fedora_infrastructure

From be8735f62aebfd1bca21d2255a0e7aad4dc599ac Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jul 21 2016 21:03:21 +0000
Subject: [PATCH 566/1001] fixed logout test and added adding widget test


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index d099987..49ab3d7 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -34,17 +34,12 @@ class HubsAPITest(hubs.tests.APPTest):
                              '/login">login</a>' in result.data)
 
     def test_hub_logged_out(self):
-        with app.test_request_context('/ralph'):
-            import flask
-            flask.g.oidc_id_token = None
-            # need to manually call the @app.before_request
-            # since unittest don't call it
-            hubs.app.check_auth()
+        with tests.auth_set(app, None):  # check_auth doesn't load in unittest
             result = self.app.get('/ralph', follow_redirects=True)
-            # assert the status code of the response
             self.assertEqual(result.status_code, 200)
-            str_expected = 'Not logged in.  Click to ' \
-                           '<a href="/login">login</a>'
+            str_expected = '<h5>Ralph</h5>'
+            self.assertTrue(str_expected in result.data)
+            str_expected = 'Not logged in.'
             self.assertTrue(str_expected in result.data)
 
     def test_groups_logged_out(self):
@@ -325,6 +320,19 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get(url)
             self.assertEqual(result.data, '1')
 
+    def test_hub_add_widget_valid_side(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/ralph/add/about?position=right'
+            result = self.app.get(url)
+            self.assertTrue('Adding widget "about"to hub: ralph' in result.data)
+
+    def test_hub_add_widget_invalid_side(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/ralph/add/about?position=invalid'
+            result = self.app.get(url)
+            self.assertEqual(result.status_code, 400)
 
 if __name__ == '__main__':
     unittest.main()

From f89ab2268d3657e3fb049359cccfad14f7c404fa Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jul 21 2016 21:03:21 +0000
Subject: [PATCH 567/1001] added hub deletion and source tests


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 49ab3d7..2eafd21 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -334,5 +334,22 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get(url)
             self.assertEqual(result.status_code, 400)
 
+    def test_hub_delete(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/ralph/31/delete'  # 31 is widget feed for ralph
+            result = self.app.post(url)
+            self.assertEqual(result.status_code, 302)
+            self.assertTrue('/ralph/edit' in result.data)
+
+    def test_source_name(self):
+        with tests.auth_set(app, None):
+            url = '/source/about'
+            result = self.app.get(url)
+            self.assertEqual(result.status_code, 302)
+            expected_str = 'https://pagure.io/fedora-hubs/' \
+                           'blob/develop/f/hubs/widgets/about.py'
+            self.assertTrue(expected_str in result.data)
+
 if __name__ == '__main__':
     unittest.main()

From 24d457f0d03f537a4f49a07c769e760ddd04c203 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jul 21 2016 21:03:21 +0000
Subject: [PATCH 568/1001] adding tests for source url, modified to catch files that dont exist


---

diff --git a/hubs/app.py b/hubs/app.py
index c152053..0007f66 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -453,7 +453,13 @@ def widget_edit_delete(hub, idx):
 def widget_source(name):
     from hubs.widgets import registry
     base = '/hubs/'
-    fname = base + registry[name].__file__.split(base, 1)[1]
+    fname = ''
+    
+    try:
+        fname = base + registry[name].__file__.split(base, 1)[1]
+    except KeyError:
+        flask.abort(404)
+
     fname = fname.replace('.pyc', '.py')
     return flask.redirect(SOURCE_URL + fname)
 
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 2eafd21..5ef5732 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -351,5 +351,12 @@ class HubsAPITest(hubs.tests.APPTest):
                            'blob/develop/f/hubs/widgets/about.py'
             self.assertTrue(expected_str in result.data)
 
+    def test_source_name_not_existent(self):
+        with tests.auth_set(app, None):
+            url = '/source/notexistent'
+            result = self.app.get(url)
+            self.assertEqual(result.status_code, 404)
+
+
 if __name__ == '__main__':
     unittest.main()

From 082d298d8cccab0c1d370b898e5dd57baee7549b Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jul 21 2016 21:03:21 +0000
Subject: [PATCH 569/1001] adding tests for library widget


---

diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index b0b7d64..9b9ac69 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -48,6 +48,14 @@ class WidgetTest(unittest.TestCase):
             index=500,
             _config=json.dumps({"text": "Testing."}),
         )
+
+        hub.widgets.append(widget)
+
+        widget = hubs.models.Widget(
+            plugin='library',
+            index=51,
+            _config=json.dumps({"urls": "ralph/"})  # we must add a url or itll crash
+        )
         hub.widgets.append(widget)
 
         for team in ['i18n', 'infra', 'old']:
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
new file mode 100644
index 0000000..ba558b1
--- /dev/null
+++ b/hubs/tests/test_widgets/test_library.py
@@ -0,0 +1,35 @@
+import json
+
+import hubs.tests.test_widgets
+import hubs.models
+
+class TestLibrary(hubs.tests.test_widgets.WidgetTest):
+    plugin = 'library'  # The name in hubs.widgets.registry
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        response = self.app.get('/ralph/%i/json/' % widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.data)
+        # del data['data']['widget_url']
+        expected_dict = {
+            "config": {
+                "urls": "ralph/"
+            },
+            "data": {
+                "edit_url": "/ralph/52/edit",
+                "source_url": "/source/library",
+                "urls": [
+                    "<a href=\"ralph/\">ralph/</a>"
+                ],
+                "widget_url": "/ralph/52"
+            },
+            "description": None,
+            "hub": "ralph",
+            "id": 52,
+            "index": 51,
+            "left": False,
+            "plugin": "library"
+        }
+
+        self.assertDictEqual(data['data'], expected_dict['data'])

From 879343ff798feabe3a3f04f73e1a809f67bd38ea Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jul 21 2016 21:03:21 +0000
Subject: [PATCH 570/1001] on some machines getting data for calendars doesnt always work and crashes test


---

diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 0a48a83..7184796 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -12,12 +12,13 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/%s/%i/json/' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
         data = json.loads(response.data)
-        meeting = data['data']['meetings']["%s meeting" % team]
-        self.assertIn(team, meeting['meeting_name'])
+        calendar_name = data['data']['calendar']
+        self.assertIn(team, calendar_name)
 
     def test_render_simple(self):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
-        self.assertIn('The i18n meeting is ', response.data)
+        self.assertIn('i18n', response.data)
+        self.assertIn('<strong>Request A New Meeting</strong>', response.data)
\ No newline at end of file

From 80ca59a64ede57439fc52670b73640b4bb874ab8 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Jul 21 2016 21:03:21 +0000
Subject: [PATCH 571/1001] removing unecessary comment


---

diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index ba558b1..27a32cf 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -11,7 +11,6 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.data)
-        # del data['data']['widget_url']
         expected_dict = {
             "config": {
                 "urls": "ralph/"

From c6aaba574fedb9884b1390d183ec734c6254bc6d Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 26 2016 12:59:49 +0000
Subject: [PATCH 572/1001] Add a widget to list tickets on a fedorahosted.org trac instance


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index a365c3d..323aa70 100755
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -15,6 +15,7 @@ from hubs.widgets import github_pr
 from hubs.widgets import pagureissues
 from hubs.widgets import githubissues
 from hubs.widgets import bugzilla
+from hubs.widgets import fhosted
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -39,6 +40,7 @@ registry = {
     'pagureissues': pagureissues,
     'githubissues': githubissues,
     'bugzilla': bugzilla,
+    'fedorahosted': fhosted,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/fhosted.py b/hubs/widgets/fhosted.py
new file mode 100644
index 0000000..4f99f71
--- /dev/null
+++ b/hubs/widgets/fhosted.py
@@ -0,0 +1,56 @@
+from hubs.widgets.chrome import panel
+from hubs.hinting import hint, prefixed as _
+from hubs.widgets.base import argument
+from hubs.widgets import templating
+import hubs.validators as validators
+import requests
+
+chrome = panel("Fedorahosted: Open Tickets")
+template = templating.environment.get_template('templates/fedorahosted.html')
+position = 'right'
+
+from xmlrpclib import ServerProxy
+
+
+@argument(name="project",
+          default=None,
+          validator=validators.github_organization,
+          help="Name of the trac instance on fedorahosted.org")
+@argument(name="n_tickets",
+          default=4,
+          validator=validators.integer,
+          help="The number of tickets to display.")
+def data(session, widget, project, n_tickets=4):
+    n_tickets = int(n_tickets)
+    url = 'https://fedorahosted.org/%s/rpc' % project
+    filters = 'status=accepted&status=assigned&status=new&status=reopened'\
+        '&col=id&col=summary&col=status&col=owner&col=type&col=priority'\
+        '&col=milestone&col=changetime&order=changetime'
+    server = ServerProxy(url)
+    tickets = server.ticket.query(filters)
+    output = []
+    total_tickets = len(tickets)
+    for idx, ticket in enumerate(tickets):
+        ticket = server.ticket.get(ticket)
+        data = ticket[3]
+        data['id'] = ticket[0]
+        data['short_summary'] = data['summary'][:45]
+        output.append(data)
+        if idx + 1 >= n_tickets:
+            break
+
+    return dict(
+        project=project,
+        tickets=output,
+        total_tickets=total_tickets,
+    )
+
+
+@hint(topics=[_('trac.ticket.update'), _('trac.ticket.new')])
+def should_invalidate(message, session, widget):
+    project = widget.config.get('project', '')
+    url = 'https://fedorahosted.org/%s/' % project
+    if '.trac.ticket' in message['topic']:
+        if message['msg']['instance']['base_url'] == url:
+            return True
+    return False
diff --git a/hubs/widgets/templates/fedorahosted.html b/hubs/widgets/templates/fedorahosted.html
new file mode 100644
index 0000000..4908362
--- /dev/null
+++ b/hubs/widgets/templates/fedorahosted.html
@@ -0,0 +1,41 @@
+<a class="btn btn-success" target="_blank"
+    href="https://fedorahosted.org/{{ project }}/report/1">
+  All Issues
+</a>
+<hr/>
+
+<ul class="media-list">
+  {% for issue in tickets %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://fedorahosted.org/{{ project }}/ticket/{{ issue['id'] }}"
+            target="_blank">
+          {{ project }}
+        <span class="label label-default">#{{ issue['id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <span title="{{ issue['summary'] }}">
+            {{ issue['short_summary'] }} {% if
+              issue['summary'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+            {{ issue['reporter'] }}
+        --
+        {% if issue['owner'] %}
+          Assigned to:
+            {{issue['owner'] }}
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if total_tickets > tickets | length %}
+  <li>
+    And {{ total_tickets - tickets | length }} more ...
+  </li>
+  {% endif %}
+</ul>

From 5e1c8fb716d79119f63946707807d4ed398d8512 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 26 2016 13:00:14 +0000
Subject: [PATCH 573/1001] Small fix to ensure the number of meetings provided is a integer


---

diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 071496a..8c05744 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -69,6 +69,7 @@ position = 'both'
           validator=validators.integer,
           help="The number of meetings to display.")
 def data(session, widget, calendar, n_meetings=4):
+    n_meetings = int(n_meetings)
     base = 'https://apps.fedoraproject.org/calendar/api/meetings/?calendar=%s'
     url = base % calendar
     response = requests.get(url).json()

From 14e16f00448e90e243da64df7a81a5a9229ad4d7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 26 2016 13:14:49 +0000
Subject: [PATCH 574/1001] Drop the project name from the link


---

diff --git a/hubs/widgets/templates/fedorahosted.html b/hubs/widgets/templates/fedorahosted.html
index 4908362..7c855b9 100644
--- a/hubs/widgets/templates/fedorahosted.html
+++ b/hubs/widgets/templates/fedorahosted.html
@@ -10,7 +10,6 @@
       <div class="media-left">
         <a  href="https://fedorahosted.org/{{ project }}/ticket/{{ issue['id'] }}"
             target="_blank">
-          {{ project }}
         <span class="label label-default">#{{ issue['id'] }}</span>
         </a>
       </div>

From d18864c268d481d7089ddb8bb9bdd9ed9c3c0e8f Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 26 2016 13:14:59 +0000
Subject: [PATCH 575/1001] Small fix to properly show the assignee of a PR in pagure


---

diff --git a/hubs/widgets/templates/pagure_pr.html b/hubs/widgets/templates/pagure_pr.html
index 5508cb7..94b2f23 100644
--- a/hubs/widgets/templates/pagure_pr.html
+++ b/hubs/widgets/templates/pagure_pr.html
@@ -25,7 +25,7 @@
           Assigned to:
           <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
               target="_blank">
-            {{ pr['pr_assignee'] }}
+            {{ pr['pr_assignee']['name'] }}
           </a>
         {% else %}
           <span class="text-muted">Unassigned</span>

From b3049f8dfb1565e9e07276dd2a798d8374538cbd Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 26 2016 14:00:10 +0000
Subject: [PATCH 576/1001] Show an error message upon error :)


---

diff --git a/hubs/widgets/fhosted.py b/hubs/widgets/fhosted.py
index 4f99f71..0c08928 100644
--- a/hubs/widgets/fhosted.py
+++ b/hubs/widgets/fhosted.py
@@ -26,8 +26,14 @@ def data(session, widget, project, n_tickets=4):
     filters = 'status=accepted&status=assigned&status=new&status=reopened'\
         '&col=id&col=summary&col=status&col=owner&col=type&col=priority'\
         '&col=milestone&col=changetime&order=changetime'
-    server = ServerProxy(url)
-    tickets = server.ticket.query(filters)
+    try:
+        server = ServerProxy(url)
+        tickets = server.ticket.query(filters)
+    except:
+        return dict(
+            error='Invalid or wrongly configured project'
+        )
+
     output = []
     total_tickets = len(tickets)
     for idx, ticket in enumerate(tickets):
diff --git a/hubs/widgets/templates/fedorahosted.html b/hubs/widgets/templates/fedorahosted.html
index 7c855b9..ad22b57 100644
--- a/hubs/widgets/templates/fedorahosted.html
+++ b/hubs/widgets/templates/fedorahosted.html
@@ -1,3 +1,6 @@
+{% if error %}
+<p>{{ error }}</p>
+{% else %}
 <a class="btn btn-success" target="_blank"
     href="https://fedorahosted.org/{{ project }}/report/1">
   All Issues
@@ -38,3 +41,4 @@
   </li>
   {% endif %}
 </ul>
+{% endif %}

From 770b3ad9da7edd0c62e348989ac09c514c0591ca Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 26 2016 14:09:46 +0000
Subject: [PATCH 577/1001] Fix the validator used in the fedorahosted widget


---

diff --git a/hubs/validators.py b/hubs/validators.py
index 791f3fe..c0385d3 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -27,7 +27,7 @@ def username(session, value):
 
 def github_organization(session, value):
     # TODO -- implement this.
-    return True
+    return value
 
 
 def fmn_context(session, value):
@@ -39,3 +39,7 @@ def fmn_context(session, value):
 
 def pagure_repo(session, value):
     return value
+
+def fedorahosted_project(session, value):
+    # TODO -- implement this.
+    return value
diff --git a/hubs/widgets/fhosted.py b/hubs/widgets/fhosted.py
index 0c08928..6a54827 100644
--- a/hubs/widgets/fhosted.py
+++ b/hubs/widgets/fhosted.py
@@ -14,7 +14,7 @@ from xmlrpclib import ServerProxy
 
 @argument(name="project",
           default=None,
-          validator=validators.github_organization,
+          validator=validators.fedorahosted_project,
           help="Name of the trac instance on fedorahosted.org")
 @argument(name="n_tickets",
           default=4,

From dc7707ff3033bcb2ec321d164b51716a9513a269 Mon Sep 17 00:00:00 2001
From: Eric Barbour <emb4gu@virginia.edu>
Date: Jul 26 2016 15:13:59 +0000
Subject: [PATCH 578/1001] Naive implementation of User Members widget


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 323aa70..6423e3e 100755
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -16,6 +16,7 @@ from hubs.widgets import pagureissues
 from hubs.widgets import githubissues
 from hubs.widgets import bugzilla
 from hubs.widgets import fhosted
+from hubs.widgets import memberships
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -41,6 +42,7 @@ registry = {
     'githubissues': githubissues,
     'bugzilla': bugzilla,
     'fedorahosted': fhosted,
+    'memberships': memberships,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/memberships.py b/hubs/widgets/memberships.py
new file mode 100644
index 0000000..8389657
--- /dev/null
+++ b/hubs/widgets/memberships.py
@@ -0,0 +1,29 @@
+import hubs.models
+from hubs.hinting import hint, prefixed as _
+import hubs.validators as validators
+from hubs.widgets.base import argument
+from hubs.widgets.chrome import panel
+from hubs.widgets import templating
+
+chrome = panel('Hubs')
+template = templating.environment.get_template('templates/memberships.html')
+position = 'both'
+
+
+@argument(name="username",
+          default=None,
+          validator=validators.username,
+          help="A FAS username.")
+def data(session, widget, username, **kwargs):
+    user = hubs.models.User.by_username(session, username)
+    memberships = [m.__json__(session) for m in user.memberships
+                   if m.name != user.username and not m.user_hub]
+    return dict(memberships=memberships)
+
+
+@hint(topics=[_('hubs.hub.update')])
+def should_invalidate(message, session, widget):
+    if message['topic'].endswith('hubs.hub.update'):
+        if message['msg']['hub']['name'] == widget.hub.name:
+            return True
+    return False
diff --git a/hubs/widgets/templates/memberships.html b/hubs/widgets/templates/memberships.html
new file mode 100644
index 0000000..482d616
--- /dev/null
+++ b/hubs/widgets/templates/memberships.html
@@ -0,0 +1,18 @@
+{% for member in memberships %}
+<div class="card-block">
+  <img class="col-md-3 img-responsive membership-avatar" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+  <a href="/{{member.name}}">{{ member.name }}</a>
+  {% if g.auth.username in member.owners %}
+    <p class="text-muted">Owner</p>
+  {% else %}
+    <p>Member</p>
+  {% endif %}
+</div>
+{% endfor %}
+
+<style>
+ .membership-avatar {
+   height: 4em;
+   width: 6em;
+ }
+</style>

From 4737208e61400c0b0eb48a23ab19fc2d1c74f6c6 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 26 2016 15:13:59 +0000
Subject: [PATCH 579/1001] Configure user membership for user and groups


* Add ellipsize of member/membership list

---

diff --git a/hubs/widgets/memberships.py b/hubs/widgets/memberships.py
index 8389657..48d8fea 100644
--- a/hubs/widgets/memberships.py
+++ b/hubs/widgets/memberships.py
@@ -5,20 +5,30 @@ from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
 
+ELLIPSIS_LIMIT = 3
 chrome = panel('Hubs')
 template = templating.environment.get_template('templates/memberships.html')
 position = 'both'
 
 
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-def data(session, widget, username, **kwargs):
-    user = hubs.models.User.by_username(session, username)
-    memberships = [m.__json__(session) for m in user.memberships
-                   if m.name != user.username and not m.user_hub]
-    return dict(memberships=memberships)
+def data(session, widget, **kwargs):
+    hub = widget.hub
+    members = []
+    if hub.user_hub:
+        user = hubs.models.User.by_username(session, hub.name)
+        members = [m.__json__(session) for m in user.memberships
+                   if m.name != user.username]
+    else:
+        members_name = []
+        for member in widget.hub.members:
+            if member.username in members_name:
+                continue
+            members_name.append(member.username)
+            members.append(member.__json__(session))
+
+    oldest_members = sorted(members,
+                            key=lambda m: m.get('created_on'))[:ELLIPSIS_LIMIT]
+    return dict(memberships=list(members), oldest_members=list(oldest_members))
 
 
 @hint(topics=[_('hubs.hub.update')])
diff --git a/hubs/widgets/templates/memberships.html b/hubs/widgets/templates/memberships.html
index 482d616..b489188 100644
--- a/hubs/widgets/templates/memberships.html
+++ b/hubs/widgets/templates/memberships.html
@@ -1,18 +1,69 @@
-{% for member in memberships %}
 <div class="card-block">
-  <img class="col-md-3 img-responsive membership-avatar" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
-  <a href="/{{member.name}}">{{ member.name }}</a>
-  {% if g.auth.username in member.owners %}
-    <p class="text-muted">Owner</p>
+  {% if memberships|length > oldest_members|length %}
+  {% for member in oldest_members %}
+  <div class="card-block">
+    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+    <a href="/{{member.name}}">{{ member.name }}</a>
+    {% if g.auth.username in member.owners %}
+      <p class="text-muted">Owner</p>
+    {% else %}
+      <p>Member</p>
+    {% endif %}
+  </div>
+  {% endfor %}
+  <a href="#" class="btn btn-default" data-toggle="modal" data-target="#membersModal">View All</a>
   {% else %}
-    <p>Member</p>
-  {% endif %}
+  {% for member in memberships %}
+  <div class="card-block">
+    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+    <a href="/{{member.name}}">{{ member.name }}</a>
+    {% if g.auth.username in member.owners %}
+      <p class="text-muted">Owner</p>
+    {% else %}
+      <p>Member</p>
+    {% endif %}
+  </div>
+  {% endfor %}
+  {%endif%}
+</div>
+
+<!-- View all modal -->
+<div class="modal fade" id="membersModal" tabindex="-1" role="dialog" aria-labelledby="membersModal" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h4 class="modal-title" id="myModalLabel">All Memberships</h4>
+      </div>
+      <div id="owners" class="modal-body">
+        {% for member in memberships %}
+        <div class="card-block">
+          <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+          <a href="/{{member.name}}">{{ member.name }}</a>
+          {% if g.auth.username in member.owners %}
+          <p class="text-muted">Owner</p>
+          {% else %}
+          <p>Member</p>
+          {% endif %}
+        </div>
+        {% endfor %}
+      </div>
+      <div class="modal-footer clearfix">
+        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+      </div>
+    </div>
+  </div>
 </div>
-{% endfor %}
 
 <style>
  .membership-avatar {
    height: 4em;
    width: 6em;
  }
+ .modal-header {
+   border-bottom: 0;
+ }
+
+ #owners {
+   padding: 10px;
+ }
 </style>

From 260fd583d6ef6102e439b12a5b7dda4a026808b6 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 26 2016 15:13:59 +0000
Subject: [PATCH 580/1001] Display memberships in modal as two columns


---

diff --git a/hubs/widgets/templates/memberships.html b/hubs/widgets/templates/memberships.html
index b489188..534aa95 100644
--- a/hubs/widgets/templates/memberships.html
+++ b/hubs/widgets/templates/memberships.html
@@ -35,24 +35,31 @@
         <h4 class="modal-title" id="myModalLabel">All Memberships</h4>
       </div>
       <div id="owners" class="modal-body">
-        {% for member in memberships %}
         <div class="card-block">
-          <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
-          <a href="/{{member.name}}">{{ member.name }}</a>
-          {% if g.auth.username in member.owners %}
-          <p class="text-muted">Owner</p>
-          {% else %}
-          <p>Member</p>
-          {% endif %}
+          <div class="row">
+            {% for member in memberships %}
+            <div class="col-sm-6">
+              <img class="img-responsive membership-avatar col-sm-3"
+                src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+              <a href="/{{member.name}}">{{ member.name }}</a>
+              {% if g.auth.username in member.owners %}
+              <p class="text-muted">Owner</p>
+              {% else %}
+              <p>Member</p>
+              {% endif %}
+            </div>
+            {% if (loop.index % 2) == 0 %}
+              </div>
+              <div class="row">
+            {% endif %}
+          {% endfor %}
+        </div>
+        <div class="modal-footer clearfix">
+          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
         </div>
-        {% endfor %}
-      </div>
-      <div class="modal-footer clearfix">
-        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
       </div>
     </div>
   </div>
-</div>
 
 <style>
  .membership-avatar {

From 8bd8e68e11368cccb35fb2942b866e4750f2b13b Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 26 2016 20:50:06 +0000
Subject: [PATCH 581/1001] removing img-wrap from team hubs header (will be plain grey to match fedora bootstrap)


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 1ffc8bb..1160e28 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -57,16 +57,18 @@
       .header .dropdown.edit {
         top: 140px !important;
       }
-      .header h3.team {
+      .header h2.team {
         top: 170px !important;
       }
     }
 
     .header {
-      color: #ffffff;
-      background-color: #3c6eb4;
+      color: #373a3c;
+      background: #f3f3f3 none repeat scroll 0 0;
       width: 100%;
       font-family: 'Open Sans', sans-serif;
+      min-height: 100px;
+      border-bottom: 1px solid #ddd;
     }
 
     /*.header .dropdown.edit {
@@ -76,23 +78,6 @@
       z-index: 2;
     }*/
 
-    .header .img-wrap {
-      max-height: 100px;
-      overflow: hidden;
-      position: relative;
-    }
-
-    .header .img-wrap img {
-      width: 100%;
-      text-align: center;
-    }
-
-    .header h3.team {
-      position: absolute;
-      top: 120px;
-      left: 45%;
-    }
-
     .header img.avatar {
         width: 70px;
         float: left;
@@ -101,7 +86,7 @@
         border: 5px solid #fff;
     }
 
-    .header h3 {
+    .header h2 {
         font-weight: 700;
     }
 
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index c4e6b92..d9592ef 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -6,15 +6,12 @@
   {% if hub.user_hub %}
     <div class="padded center-block medium-wide">
       <img src="{{ hub.avatar }}" class="avatar" />
-      <h3>{{ hub.name }}</h3>
+      <h2>{{ hub.name }}</h2>
       <h5>{{ hub.summary }}</h5>
       <div class="clearfix"></div>
     </div>
     {% else %}
-    <div class="img-wrap">
-      <img src="{{ hub.header_img }}" />
-    </div>
-    <h3 class="team">{{ hub.name }}</h3>
+    <h2 class="team">{{ hub.name }}</h2>
   {% endif %}
 </div>
 

From 1f97beda194fe0b19d55d3dcf5cad0d3604f9f81 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 26 2016 20:50:07 +0000
Subject: [PATCH 582/1001] wrangling header for user/team hubs to better match Fedora bootstrap


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 1160e28..f0f0b6a 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -62,7 +62,7 @@
       }
     }
 
-    .header {
+    header {
       color: #373a3c;
       background: #f3f3f3 none repeat scroll 0 0;
       width: 100%;
@@ -78,7 +78,7 @@
       z-index: 2;
     }*/
 
-    .header img.avatar {
+    header img.avatar {
         width: 70px;
         float: left;
         margin: 0 15px;
@@ -86,15 +86,15 @@
         border: 5px solid #fff;
     }
 
-    .header h2 {
-        font-weight: 700;
+    header h2 {
+        font-weight: 500;
     }
 
-    .header a, .header a:hover, .header a:focus {
+    header a, header a:hover, .header a:focus {
       color: #ffffff;
     }
 
-    .header span.edit {
+    header span.edit {
       margin: 5px 5px 0 0;
     }
     .row {
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index d9592ef..c7106fc 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -2,18 +2,21 @@
 
 {% block title %}{{ hub.name }}{% endblock %}
 {% block content %}
-<div class="header">
-  {% if hub.user_hub %}
-    <div class="padded center-block medium-wide">
-      <img src="{{ hub.avatar }}" class="avatar" />
-      <h2>{{ hub.name }}</h2>
-      <h5>{{ hub.summary }}</h5>
-      <div class="clearfix"></div>
-    </div>
-    {% else %}
-    <h2 class="team">{{ hub.name }}</h2>
-  {% endif %}
-</div>
+
+  <header class="p-t-2">
+    <div class="container">
+      {% if hub.user_hub %}
+	    <img src="{{ hub.avatar }}" class="avatar" />
+		<h2 class="user m-b-0">{{ hub.name }}</h2>
+		<h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
+	    <div class="clearfix"></div>
+      {% else %}
+      <h2 class="team">{{ hub.name }}</h2>
+      <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
+	  {% endif %}
+  	</div>
+  </header>
+
 
 {%- with messages = get_flashed_messages(with_categories=true) -%}
   {%- if category, messages -%}

From 0347c76a2a3b9c6b6e6fe169efdcb8764a362726 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 26 2016 20:50:07 +0000
Subject: [PATCH 583/1001] first cut at vertical nav bar


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index f0f0b6a..09d6be9 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -265,6 +265,28 @@ font-size: 32pt;
 .navbar-nav > li.idle-2years  > a { color: #BBB; }
 .navbar-nav > li.idle-5years  > a { color: #CCC; }
 
+.nav {
+  background-color: #fcfcfc;
+  padding: 1.5rem;
+  position: absolute;
+  z-index: 3;
+  min-height: 200px; 
+  float: left;
+}
+
+/* navbar fedora-bootstrap overrides to make it vertical */
+
+.navbar-nav .nav-item {
+    float: none;
+}
+
+.navbar-nav .nav-item + .nav-item, .navbar-nav .nav-link + .nav-link {
+    box-shadow: none;
+    margin-left: 0px !important;
+}
+
+/* end fedora-bootstrap nav overrides */
+
 .media-object {
     max-width: 92px;
     max-height: 92px;
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index c7106fc..f384e37 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -78,8 +78,8 @@
       </div>
   {% endif %}
 
-
   <div class="row">
+	  
     <div class="col-md-{{ hub.left_width }}">
       <!--
         First, before the proper widgets.. a cobweb built-in widget.
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 4fd92e5..22eb10b 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -54,16 +54,18 @@
 </div>
 <div class="bodycontent">
 
-  <nav class="navbar navbar-light navbar-underline p-t-0 p-b-0">
+  
+<div class="col-md-2">
+	  <nav class="navbar navbar-light p-t-2 p-b-0">
         <button type="button" class="navbar-toggler hidden-sm-up"
             data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
           <span class="sr-only">Toggle navigation</span>
           <span class="oi" data-glyph="menu"></span>
         </button>
 
-      <!-- Collect the nav links, forms, and other content for toggling -->
-      <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
-        <ul class="nav navbar-nav nav-underline">
+<!-- Collect the nav links, forms, and other content for toggling -->
+  <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav">
           {% if g.auth.logged_in %}
           <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
             <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
@@ -72,11 +74,15 @@
           <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
           {% endfor %}
           <!-- At the end of the list, tack on a link to all groups -->
-          <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
+
+ <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
           {% endif %}
         </ul>
-      </div><!-- /.navbar-collapse -->
+  </div><!-- /.navbar-collapse -->
   </nav>
+  
+</div>  
+  
 {% block content %}{% endblock %}
 
 </div> <!--end bodycontent-->

From 42b376a1ffc3738641ac3022917c2f62817a8de4 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 26 2016 20:50:07 +0000
Subject: [PATCH 584/1001] some padding / alignment adjustments so things line up with vertical nav


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 09d6be9..f8636d6 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -77,17 +77,23 @@
       right: 0;
       z-index: 2;
     }*/
+    
+    /* line up header with cards below */
+    header .container {
+	padding-left: 1.75rem !important;
+	}
 
     header img.avatar {
         width: 70px;
         float: left;
-        margin: 0 15px;
+        margin-right: 15px;
         display: inline;
         border: 5px solid #fff;
     }
 
     header h2 {
         font-weight: 500;
+        padding-top: .5rem;
     }
 
     header a, header a:hover, .header a:focus {
@@ -98,7 +104,7 @@
       margin: 5px 5px 0 0;
     }
     .row {
-      padding: 5px;
+      padding-top: 5px;
       margin: auto 0px;
     }
     .padded {
@@ -133,6 +139,7 @@
       padding: 5px;
       /* TODO -- lots more nice styling here... */
     }
+
     .panel {
       visibility: hidden;
       max-height: 0px;
@@ -381,3 +388,19 @@ font-size: 32pt;
   height: 2em;
   width: 2em;
 }
+
+
+/** fedora bootstrap overrides **/
+
+/** tightening up card headers - they are too fat imho **/
+.card-header {
+  padding: 0.3rem 0.5rem;
+}
+
+
+/** too much padding over the user's subheader, was attached to .m-b-1 with 
+ * !important so difficult to override **/
+
+header h5.m-b-1 {
+  margin-top: 0.5rem!important;
+}
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f384e37..99418cb 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -5,16 +5,55 @@
 
   <header class="p-t-2">
     <div class="container">
-      {% if hub.user_hub %}
-	    <img src="{{ hub.avatar }}" class="avatar" />
-		<h2 class="user m-b-0">{{ hub.name }}</h2>
-		<h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
-	    <div class="clearfix"></div>
-      {% else %}
-      <h2 class="team">{{ hub.name }}</h2>
-      <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
-	  {% endif %}
+		
+	  <!-- Left side of header -->
+	  <div class="col-md-8">
+        {% if hub.user_hub %}
+	      <img src="{{ hub.avatar }}" class="avatar" />
+		  <h2 class="user m-b-0">{{ hub.name }}</h2>
+		  <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
+	      <div class="clearfix"></div>
+        {% else %}
+        <h2 class="team">{{ hub.name }}</h2>
+        <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
+	    {% endif %}
+	  </div>
+
+      <!-- right side of header -->
+      <div class="col-md-4 header-right">
+{% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
+        {% if not edit %}
+          <div class="dropdown edit pull-xs-right showpointer">
+            <span class="dropdown-toggle edit-this-page" type="button"
+                  id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
+                  aria-expanded="true">
+              <span class="oi" data-glyph="pencil"></span> edit this page
+            </span>
+            <div class="dropdown-menu" aria-labelledby="dropdownMenu2">
+              <a class="dropdown-item" href="#">Customize Header</a>
+              <div class="dropdown-divider"></div>
+              <a class="dropdown-item"
+                  href="{{ url_for('hub_edit', name=hub.name) }}">
+                Configure Hub
+              </a>
+              {% if not hub.user_hub %}
+              <div class="dropdown-divider"></div>
+              <a class="dropdown-item" href="#">Manage Members</a>
+              <div class="dropdown-divider"></div>
+              <a class="dropdown-item" href="#">Archive Hub</a>
+              {% endif %}
+            </div>
+          </div>
+        {% else %}
+          <div id="save_edits_btn" class="pull-xs-right">
+            <span class="oi" data-glyph="data-transfer-download"></span>
+            Save changes
+          </div>
+        {% endif %}
+  {% endif %}
+  </div>
   	</div>
+
   </header>
 
 
@@ -45,39 +84,7 @@
 {%- endwith -%}
 
 <div class="container">
-  {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
-      <div class="row">
-        {% if not edit %}
-          <div class="dropdown edit pull-xs-right showpointer">
-            <span class="dropdown-toggle edit-this-page" type="button"
-                  id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
-                  aria-expanded="true">
-              <span class="oi" data-glyph="pencil"></span> edit this page
-            </span>
-            <div class="dropdown-menu" aria-labelledby="dropdownMenu2">
-              <a class="dropdown-item" href="#">Customize Header</a>
-              <div class="dropdown-divider"></div>
-              <a class="dropdown-item"
-                  href="{{ url_for('hub_edit', name=hub.name) }}">
-                Configure Hub
-              </a>
-              {% if not hub.user_hub %}
-              <div class="dropdown-divider"></div>
-              <a class="dropdown-item" href="#">Manage Members</a>
-              <div class="dropdown-divider"></div>
-              <a class="dropdown-item" href="#">Archive Hub</a>
-              {% endif %}
-            </div>
-          </div>
-        {% else %}
-          <div id="save_edits_btn" class="pull-xs-right">
-            <span class="oi" data-glyph="data-transfer-download"></span>
-            Save changes
-          </div>
-        {% endif %}
-      </div>
-  {% endif %}
-
+  
   <div class="row">
 	  
     <div class="col-md-{{ hub.left_width }}">

From cce099478f812c08375f6d0a3f96a4b5c776702e Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 26 2016 20:50:07 +0000
Subject: [PATCH 585/1001] fixing up groups.html to not be broken-looking + to be compatible with vert bookmarks bar


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index f8636d6..a588609 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -400,7 +400,6 @@ font-size: 32pt;
 
 /** too much padding over the user's subheader, was attached to .m-b-1 with 
  * !important so difficult to override **/
-
 header h5.m-b-1 {
   margin-top: 0.5rem!important;
 }
diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
index 0d3bc20..f13070c 100644
--- a/hubs/templates/groups.html
+++ b/hubs/templates/groups.html
@@ -3,12 +3,16 @@
 {% block title %}Groups{% endblock %}
 {% block content %}
 
-<div class="header">
-  <div class="img-wrap">
-    <img src="#" />
-  </div>
-  <h3 class="team">Groups</h3>
-</div>
+<header class="p-t-2">
+	<div class="container">
+    <div class="col-md-8">
+      <h2 class="team m-b-0">Groups</h2>
+  		<h5 class="m-t-1 m-b-1">Summary of available team hubs</h5>
+    </div>
+    <div class="col-md-4 header-right">
+		</div>
+</header>
+
 <div class="container">
   <div class="row">
   </div>

From 33188da39f06bf5ff7f8825f64d88a1b7e7fb0b5 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 26 2016 20:51:03 +0000
Subject: [PATCH 586/1001] making body background white


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index a588609..30e246b 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -1,7 +1,7 @@
 @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic);
 
    body {
-      background-color: #d1d3d4;
+      background-color: #fff;
     }
 
     /*.super-header {

From bac5cbd6789d1e218752e302695ea6137b27b126 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Jul 26 2016 20:51:08 +0000
Subject: [PATCH 587/1001] minor indentation fix


---

diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
index f13070c..4040938 100644
--- a/hubs/templates/groups.html
+++ b/hubs/templates/groups.html
@@ -7,10 +7,10 @@
 	<div class="container">
     <div class="col-md-8">
       <h2 class="team m-b-0">Groups</h2>
-  		<h5 class="m-t-1 m-b-1">Summary of available team hubs</h5>
+      <h5 class="m-t-1 m-b-1">Summary of available team hubs</h5>
     </div>
     <div class="col-md-4 header-right">
-		</div>
+    </div>
 </header>
 
 <div class="container">
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 99418cb..f52d617 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -5,23 +5,23 @@
 
   <header class="p-t-2">
     <div class="container">
-		
-	  <!-- Left side of header -->
-	  <div class="col-md-8">
+
+    <!-- Left side of header -->
+    <div class="col-md-8">
         {% if hub.user_hub %}
-	      <img src="{{ hub.avatar }}" class="avatar" />
-		  <h2 class="user m-b-0">{{ hub.name }}</h2>
-		  <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
-	      <div class="clearfix"></div>
+        <img src="{{ hub.avatar }}" class="avatar" />
+      <h2 class="user m-b-0">{{ hub.name }}</h2>
+      <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
+        <div class="clearfix"></div>
         {% else %}
         <h2 class="team">{{ hub.name }}</h2>
         <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
-	    {% endif %}
-	  </div>
+      {% endif %}
+    </div>
 
       <!-- right side of header -->
       <div class="col-md-4 header-right">
-{% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
+      {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
         {% if not edit %}
           <div class="dropdown edit pull-xs-right showpointer">
             <span class="dropdown-toggle edit-this-page" type="button"
@@ -50,9 +50,9 @@
             Save changes
           </div>
         {% endif %}
-  {% endif %}
-  </div>
-  	</div>
+      {% endif %}
+      </div>
+    </div>
 
   </header>
 
@@ -86,7 +86,7 @@
 <div class="container">
   
   <div class="row">
-	  
+ 
     <div class="col-md-{{ hub.left_width }}">
       <!--
         First, before the proper widgets.. a cobweb built-in widget.
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 22eb10b..f093304 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -56,7 +56,7 @@
 
   
 <div class="col-md-2">
-	  <nav class="navbar navbar-light p-t-2 p-b-0">
+    <nav class="navbar navbar-light p-t-2 p-b-0">
         <button type="button" class="navbar-toggler hidden-sm-up"
             data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
           <span class="sr-only">Toggle navigation</span>

From f9afac5239d1238ba794b0e2cd3c8af95d0f518c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Jul 28 2016 12:18:13 +0000
Subject: [PATCH 588/1001] Adjust the validators so they return the value validated


---

diff --git a/hubs/validators.py b/hubs/validators.py
index c0385d3..fd4066c 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -1,6 +1,7 @@
 import kitchen.text.converters
 
 import hubs.models
+import httplib
 
 
 def required(session, value):
@@ -22,7 +23,9 @@ def link(session, value):
 
 
 def username(session, value):
-    return hubs.models.User.by_username(session, value) is not None
+    if hubs.models.User.by_username(session, value) is not None:
+        return value
+    raise ValueError('Invalid username')
 
 
 def github_organization(session, value):
@@ -32,14 +35,25 @@ def github_organization(session, value):
 
 def fmn_context(session, value):
     # TODO get this from the fedmsg config.
-    return value in [
-        'irc', 'email', 'android', 'desktop', 'hubs',
-    ]
+    if value in [
+        'irc', 'email', 'android', 'desktop', 'hubs',]:
+        return value
+    raise ValueError('Invalid FMN context')
 
 
 def pagure_repo(session, value):
-    return value
+    conn = httplib.HTTPSConnection("pagure.io")
+    conn.request("GET", "/%s" % value)
+    response = conn.getresponse()
+    if response.status == 200:
+        return value
+    raise ValueError('Invalid pagure repo')
+
 
 def fedorahosted_project(session, value):
-    # TODO -- implement this.
-    return value
+    conn = httplib.HTTPSConnection("fedorahosted.org")
+    conn.request("GET", "/%s" % value)
+    response = conn.getresponse()
+    if response.status == 200:
+        return value
+    raise ValueError('Invalid fedorahosted project')

From c1bbe004f00d5381c37c12855606bb22b4dd005b Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Jul 28 2016 15:55:49 +0000
Subject: [PATCH 589/1001] Avoid empty nav bar if visiting hub logged out


Move check for g.auth.logged_in to surround all of the nav bar

---

diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index f093304..83f7608 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -53,36 +53,33 @@
   </div>
 </div>
 <div class="bodycontent">
-
-  
-<div class="col-md-2">
+  <div class="col-md-2">
     <nav class="navbar navbar-light p-t-2 p-b-0">
-        <button type="button" class="navbar-toggler hidden-sm-up"
-            data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
-          <span class="sr-only">Toggle navigation</span>
-          <span class="oi" data-glyph="menu"></span>
-        </button>
+      <button type="button" class="navbar-toggler hidden-sm-up"
+        data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+        <span class="sr-only">Toggle navigation</span>
+        <span class="oi" data-glyph="menu"></span>
+      </button>
 
-<!-- Collect the nav links, forms, and other content for toggling -->
-  <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      {% if g.auth.logged_in %}
+      <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
         <ul class="nav navbar-nav">
-          {% if g.auth.logged_in %}
           <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
             <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
           {% for hub in g.auth.user.bookmarks %}
           <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
-          <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
+            <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
           {% endfor %}
           <!-- At the end of the list, tack on a link to all groups -->
 
- <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
-          {% endif %}
+            <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
         </ul>
-  </div><!-- /.navbar-collapse -->
-  </nav>
-  
-</div>  
-  
+      </div><!-- /.navbar-collapse -->
+      {% endif %}
+    </nav>
+  </div>
+
 {% block content %}{% endblock %}
 
 </div> <!--end bodycontent-->

From 66619f12faf07a1e5fe9848e3b29d34b9a01e9f5 Mon Sep 17 00:00:00 2001
From: rkolathu <you@example.com>
Date: Aug 01 2016 15:01:33 +0000
Subject: [PATCH 590/1001] Added the font awesome icons


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f52d617..cb29255 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -27,7 +27,7 @@
             <span class="dropdown-toggle edit-this-page" type="button"
                   id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
                   aria-expanded="true">
-              <span class="oi" data-glyph="pencil"></span> edit this page
+              <span><i class="fa fa-pencil" aria-hidden="true"></i></span> edit this page
             </span>
             <div class="dropdown-menu" aria-labelledby="dropdownMenu2">
               <a class="dropdown-item" href="#">Customize Header</a>
@@ -46,7 +46,7 @@
           </div>
         {% else %}
           <div id="save_edits_btn" class="pull-xs-right">
-            <span class="oi" data-glyph="data-transfer-download"></span>
+            <span><i class="fa fa-download" aria-hidden="true"></i></span>
             Save changes
           </div>
         {% endif %}
@@ -84,9 +84,9 @@
 {%- endwith -%}
 
 <div class="container">
-  
+
   <div class="row">
- 
+
     <div class="col-md-{{ hub.left_width }}">
       <!--
         First, before the proper widgets.. a cobweb built-in widget.
@@ -122,7 +122,7 @@
           <div class="card-block">
             <h4>
               <a href="#" class="add_widget" data-position="left">
-                <span class="oi" data-glyph="plus"></span> Add a widget
+                <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
               </a>
             </h4>
           </div>
@@ -144,7 +144,7 @@
           <div class="card-block">
             <h4>
               <a href="#" class="add_widget" data-position="right">
-                <span class="oi" data-glyph="plus"></span> Add a widget
+                <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
               </a>
             </h4>
           </div>
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 83f7608..8b20df0 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -7,7 +7,7 @@
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
   <script type="text/javascript"  src="{{ url_for('static', filename='notificon.js') }}"></script>
-  <link href="{{ url_for('static', filename='open_iconic_1.1.0/css/open-iconic.min.css') }}"
+  <link href="{{ url_for('static', filename='font-awesome-4.6.3/css/font-awesome.min.css') }}"
         type="text/css" rel="stylesheet" />
   <link href="{{ url_for('static', filename='badges/b.css') }}"
         type="text/css" rel="stylesheet" />
@@ -46,7 +46,7 @@
       <div class="input-group">
         <input type="search" class="form-control" placeholder="Search across all hubs ..." aria-describedby="searchform-addon"></input>
         <span class="input-group-addon" id="searchform-addon">
-          <span class="oi" data-glyph="magnifying-glass"></span>
+          <span><i class="fa fa-search" aria-hidden="true"></i></span>
         </span>
     </div>
     </div>
@@ -58,7 +58,7 @@
       <button type="button" class="navbar-toggler hidden-sm-up"
         data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
         <span class="sr-only">Toggle navigation</span>
-        <span class="oi" data-glyph="menu"></span>
+        <span><i class="fa fa-bars" aria-hidden="true"></i></span>
       </button>
 
       <!-- Collect the nav links, forms, and other content for toggling -->
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index 71cb1f6..02ead38 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -1,11 +1,11 @@
 <div class="card {{ klass }}">
   <div class="pull-right widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
-    <a href="{{ source_url }}"><span class="oi" data-glyph="eye"></span></a>
-    <a href="{{ widget_url }}"><span class="oi" data-glyph="external-link"></span></a>
+    <a href="{{ source_url }}"><span><i class="fa fa-eye" aria-hidden="true"></i></span></a>
+    <a href="{{ widget_url }}"><span><i class="fa fa-external-link" aria-hidden="true"></i></span></a>
     <a data-target="#edit_modal" data-toggle="modal" type="button"
         class="edit_widget" data-idx="{{ widget.idx }}">
-      <span class="oi" data-glyph="pencil"></span>
+      <span><i class="fa fa-pencil" aria-hidden="true"></i></span>
     </a>
   </div>
   {{ heading }}

From af126260fc8945c5a6076ec331fc43731be2a15c Mon Sep 17 00:00:00 2001
From: rkolathu <you@example.com>
Date: Aug 01 2016 15:02:45 +0000
Subject: [PATCH 591/1001] Added the font awesome folder


---

diff --git a/hubs/static/font-awesome-4.6.3/HELP-US-OUT.txt b/hubs/static/font-awesome-4.6.3/HELP-US-OUT.txt
new file mode 100644
index 0000000..83d083d
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/HELP-US-OUT.txt
@@ -0,0 +1,7 @@
+I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project,
+Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome,
+comprehensive icon sets or copy and paste your own.
+
+Please. Check it out.
+
+-Dave Gandy
diff --git a/hubs/static/font-awesome-4.6.3/css/font-awesome.css b/hubs/static/font-awesome-4.6.3/css/font-awesome.css
new file mode 100644
index 0000000..74e77d0
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/css/font-awesome.css
@@ -0,0 +1,2199 @@
+/*!
+ *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */
+/* FONT PATH
+ * -------------------------- */
+@font-face {
+  font-family: 'FontAwesome';
+  src: url('../fonts/fontawesome-webfont.eot?v=4.6.3');
+  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.6.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.6.3') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.6.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.6.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.6.3#fontawesomeregular') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+.fa {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+/* makes the font 33% larger relative to the icon container */
+.fa-lg {
+  font-size: 1.33333333em;
+  line-height: 0.75em;
+  vertical-align: -15%;
+}
+.fa-2x {
+  font-size: 2em;
+}
+.fa-3x {
+  font-size: 3em;
+}
+.fa-4x {
+  font-size: 4em;
+}
+.fa-5x {
+  font-size: 5em;
+}
+.fa-fw {
+  width: 1.28571429em;
+  text-align: center;
+}
+.fa-ul {
+  padding-left: 0;
+  margin-left: 2.14285714em;
+  list-style-type: none;
+}
+.fa-ul > li {
+  position: relative;
+}
+.fa-li {
+  position: absolute;
+  left: -2.14285714em;
+  width: 2.14285714em;
+  top: 0.14285714em;
+  text-align: center;
+}
+.fa-li.fa-lg {
+  left: -1.85714286em;
+}
+.fa-border {
+  padding: .2em .25em .15em;
+  border: solid 0.08em #eee;
+  border-radius: .1em;
+}
+.fa-pull-left {
+  float: left;
+}
+.fa-pull-right {
+  float: right;
+}
+.fa.fa-pull-left {
+  margin-right: .3em;
+}
+.fa.fa-pull-right {
+  margin-left: .3em;
+}
+/* Deprecated as of 4.4.0 */
+.pull-right {
+  float: right;
+}
+.pull-left {
+  float: left;
+}
+.fa.pull-left {
+  margin-right: .3em;
+}
+.fa.pull-right {
+  margin-left: .3em;
+}
+.fa-spin {
+  -webkit-animation: fa-spin 2s infinite linear;
+  animation: fa-spin 2s infinite linear;
+}
+.fa-pulse {
+  -webkit-animation: fa-spin 1s infinite steps(8);
+  animation: fa-spin 1s infinite steps(8);
+}
+@-webkit-keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+.fa-rotate-90 {
+  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
+  -webkit-transform: rotate(90deg);
+  -ms-transform: rotate(90deg);
+  transform: rotate(90deg);
+}
+.fa-rotate-180 {
+  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
+  -webkit-transform: rotate(180deg);
+  -ms-transform: rotate(180deg);
+  transform: rotate(180deg);
+}
+.fa-rotate-270 {
+  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
+  -webkit-transform: rotate(270deg);
+  -ms-transform: rotate(270deg);
+  transform: rotate(270deg);
+}
+.fa-flip-horizontal {
+  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
+  -webkit-transform: scale(-1, 1);
+  -ms-transform: scale(-1, 1);
+  transform: scale(-1, 1);
+}
+.fa-flip-vertical {
+  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
+  -webkit-transform: scale(1, -1);
+  -ms-transform: scale(1, -1);
+  transform: scale(1, -1);
+}
+:root .fa-rotate-90,
+:root .fa-rotate-180,
+:root .fa-rotate-270,
+:root .fa-flip-horizontal,
+:root .fa-flip-vertical {
+  filter: none;
+}
+.fa-stack {
+  position: relative;
+  display: inline-block;
+  width: 2em;
+  height: 2em;
+  line-height: 2em;
+  vertical-align: middle;
+}
+.fa-stack-1x,
+.fa-stack-2x {
+  position: absolute;
+  left: 0;
+  width: 100%;
+  text-align: center;
+}
+.fa-stack-1x {
+  line-height: inherit;
+}
+.fa-stack-2x {
+  font-size: 2em;
+}
+.fa-inverse {
+  color: #fff;
+}
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+   readers do not read off random characters that represent icons */
+.fa-glass:before {
+  content: "\f000";
+}
+.fa-music:before {
+  content: "\f001";
+}
+.fa-search:before {
+  content: "\f002";
+}
+.fa-envelope-o:before {
+  content: "\f003";
+}
+.fa-heart:before {
+  content: "\f004";
+}
+.fa-star:before {
+  content: "\f005";
+}
+.fa-star-o:before {
+  content: "\f006";
+}
+.fa-user:before {
+  content: "\f007";
+}
+.fa-film:before {
+  content: "\f008";
+}
+.fa-th-large:before {
+  content: "\f009";
+}
+.fa-th:before {
+  content: "\f00a";
+}
+.fa-th-list:before {
+  content: "\f00b";
+}
+.fa-check:before {
+  content: "\f00c";
+}
+.fa-remove:before,
+.fa-close:before,
+.fa-times:before {
+  content: "\f00d";
+}
+.fa-search-plus:before {
+  content: "\f00e";
+}
+.fa-search-minus:before {
+  content: "\f010";
+}
+.fa-power-off:before {
+  content: "\f011";
+}
+.fa-signal:before {
+  content: "\f012";
+}
+.fa-gear:before,
+.fa-cog:before {
+  content: "\f013";
+}
+.fa-trash-o:before {
+  content: "\f014";
+}
+.fa-home:before {
+  content: "\f015";
+}
+.fa-file-o:before {
+  content: "\f016";
+}
+.fa-clock-o:before {
+  content: "\f017";
+}
+.fa-road:before {
+  content: "\f018";
+}
+.fa-download:before {
+  content: "\f019";
+}
+.fa-arrow-circle-o-down:before {
+  content: "\f01a";
+}
+.fa-arrow-circle-o-up:before {
+  content: "\f01b";
+}
+.fa-inbox:before {
+  content: "\f01c";
+}
+.fa-play-circle-o:before {
+  content: "\f01d";
+}
+.fa-rotate-right:before,
+.fa-repeat:before {
+  content: "\f01e";
+}
+.fa-refresh:before {
+  content: "\f021";
+}
+.fa-list-alt:before {
+  content: "\f022";
+}
+.fa-lock:before {
+  content: "\f023";
+}
+.fa-flag:before {
+  content: "\f024";
+}
+.fa-headphones:before {
+  content: "\f025";
+}
+.fa-volume-off:before {
+  content: "\f026";
+}
+.fa-volume-down:before {
+  content: "\f027";
+}
+.fa-volume-up:before {
+  content: "\f028";
+}
+.fa-qrcode:before {
+  content: "\f029";
+}
+.fa-barcode:before {
+  content: "\f02a";
+}
+.fa-tag:before {
+  content: "\f02b";
+}
+.fa-tags:before {
+  content: "\f02c";
+}
+.fa-book:before {
+  content: "\f02d";
+}
+.fa-bookmark:before {
+  content: "\f02e";
+}
+.fa-print:before {
+  content: "\f02f";
+}
+.fa-camera:before {
+  content: "\f030";
+}
+.fa-font:before {
+  content: "\f031";
+}
+.fa-bold:before {
+  content: "\f032";
+}
+.fa-italic:before {
+  content: "\f033";
+}
+.fa-text-height:before {
+  content: "\f034";
+}
+.fa-text-width:before {
+  content: "\f035";
+}
+.fa-align-left:before {
+  content: "\f036";
+}
+.fa-align-center:before {
+  content: "\f037";
+}
+.fa-align-right:before {
+  content: "\f038";
+}
+.fa-align-justify:before {
+  content: "\f039";
+}
+.fa-list:before {
+  content: "\f03a";
+}
+.fa-dedent:before,
+.fa-outdent:before {
+  content: "\f03b";
+}
+.fa-indent:before {
+  content: "\f03c";
+}
+.fa-video-camera:before {
+  content: "\f03d";
+}
+.fa-photo:before,
+.fa-image:before,
+.fa-picture-o:before {
+  content: "\f03e";
+}
+.fa-pencil:before {
+  content: "\f040";
+}
+.fa-map-marker:before {
+  content: "\f041";
+}
+.fa-adjust:before {
+  content: "\f042";
+}
+.fa-tint:before {
+  content: "\f043";
+}
+.fa-edit:before,
+.fa-pencil-square-o:before {
+  content: "\f044";
+}
+.fa-share-square-o:before {
+  content: "\f045";
+}
+.fa-check-square-o:before {
+  content: "\f046";
+}
+.fa-arrows:before {
+  content: "\f047";
+}
+.fa-step-backward:before {
+  content: "\f048";
+}
+.fa-fast-backward:before {
+  content: "\f049";
+}
+.fa-backward:before {
+  content: "\f04a";
+}
+.fa-play:before {
+  content: "\f04b";
+}
+.fa-pause:before {
+  content: "\f04c";
+}
+.fa-stop:before {
+  content: "\f04d";
+}
+.fa-forward:before {
+  content: "\f04e";
+}
+.fa-fast-forward:before {
+  content: "\f050";
+}
+.fa-step-forward:before {
+  content: "\f051";
+}
+.fa-eject:before {
+  content: "\f052";
+}
+.fa-chevron-left:before {
+  content: "\f053";
+}
+.fa-chevron-right:before {
+  content: "\f054";
+}
+.fa-plus-circle:before {
+  content: "\f055";
+}
+.fa-minus-circle:before {
+  content: "\f056";
+}
+.fa-times-circle:before {
+  content: "\f057";
+}
+.fa-check-circle:before {
+  content: "\f058";
+}
+.fa-question-circle:before {
+  content: "\f059";
+}
+.fa-info-circle:before {
+  content: "\f05a";
+}
+.fa-crosshairs:before {
+  content: "\f05b";
+}
+.fa-times-circle-o:before {
+  content: "\f05c";
+}
+.fa-check-circle-o:before {
+  content: "\f05d";
+}
+.fa-ban:before {
+  content: "\f05e";
+}
+.fa-arrow-left:before {
+  content: "\f060";
+}
+.fa-arrow-right:before {
+  content: "\f061";
+}
+.fa-arrow-up:before {
+  content: "\f062";
+}
+.fa-arrow-down:before {
+  content: "\f063";
+}
+.fa-mail-forward:before,
+.fa-share:before {
+  content: "\f064";
+}
+.fa-expand:before {
+  content: "\f065";
+}
+.fa-compress:before {
+  content: "\f066";
+}
+.fa-plus:before {
+  content: "\f067";
+}
+.fa-minus:before {
+  content: "\f068";
+}
+.fa-asterisk:before {
+  content: "\f069";
+}
+.fa-exclamation-circle:before {
+  content: "\f06a";
+}
+.fa-gift:before {
+  content: "\f06b";
+}
+.fa-leaf:before {
+  content: "\f06c";
+}
+.fa-fire:before {
+  content: "\f06d";
+}
+.fa-eye:before {
+  content: "\f06e";
+}
+.fa-eye-slash:before {
+  content: "\f070";
+}
+.fa-warning:before,
+.fa-exclamation-triangle:before {
+  content: "\f071";
+}
+.fa-plane:before {
+  content: "\f072";
+}
+.fa-calendar:before {
+  content: "\f073";
+}
+.fa-random:before {
+  content: "\f074";
+}
+.fa-comment:before {
+  content: "\f075";
+}
+.fa-magnet:before {
+  content: "\f076";
+}
+.fa-chevron-up:before {
+  content: "\f077";
+}
+.fa-chevron-down:before {
+  content: "\f078";
+}
+.fa-retweet:before {
+  content: "\f079";
+}
+.fa-shopping-cart:before {
+  content: "\f07a";
+}
+.fa-folder:before {
+  content: "\f07b";
+}
+.fa-folder-open:before {
+  content: "\f07c";
+}
+.fa-arrows-v:before {
+  content: "\f07d";
+}
+.fa-arrows-h:before {
+  content: "\f07e";
+}
+.fa-bar-chart-o:before,
+.fa-bar-chart:before {
+  content: "\f080";
+}
+.fa-twitter-square:before {
+  content: "\f081";
+}
+.fa-facebook-square:before {
+  content: "\f082";
+}
+.fa-camera-retro:before {
+  content: "\f083";
+}
+.fa-key:before {
+  content: "\f084";
+}
+.fa-gears:before,
+.fa-cogs:before {
+  content: "\f085";
+}
+.fa-comments:before {
+  content: "\f086";
+}
+.fa-thumbs-o-up:before {
+  content: "\f087";
+}
+.fa-thumbs-o-down:before {
+  content: "\f088";
+}
+.fa-star-half:before {
+  content: "\f089";
+}
+.fa-heart-o:before {
+  content: "\f08a";
+}
+.fa-sign-out:before {
+  content: "\f08b";
+}
+.fa-linkedin-square:before {
+  content: "\f08c";
+}
+.fa-thumb-tack:before {
+  content: "\f08d";
+}
+.fa-external-link:before {
+  content: "\f08e";
+}
+.fa-sign-in:before {
+  content: "\f090";
+}
+.fa-trophy:before {
+  content: "\f091";
+}
+.fa-github-square:before {
+  content: "\f092";
+}
+.fa-upload:before {
+  content: "\f093";
+}
+.fa-lemon-o:before {
+  content: "\f094";
+}
+.fa-phone:before {
+  content: "\f095";
+}
+.fa-square-o:before {
+  content: "\f096";
+}
+.fa-bookmark-o:before {
+  content: "\f097";
+}
+.fa-phone-square:before {
+  content: "\f098";
+}
+.fa-twitter:before {
+  content: "\f099";
+}
+.fa-facebook-f:before,
+.fa-facebook:before {
+  content: "\f09a";
+}
+.fa-github:before {
+  content: "\f09b";
+}
+.fa-unlock:before {
+  content: "\f09c";
+}
+.fa-credit-card:before {
+  content: "\f09d";
+}
+.fa-feed:before,
+.fa-rss:before {
+  content: "\f09e";
+}
+.fa-hdd-o:before {
+  content: "\f0a0";
+}
+.fa-bullhorn:before {
+  content: "\f0a1";
+}
+.fa-bell:before {
+  content: "\f0f3";
+}
+.fa-certificate:before {
+  content: "\f0a3";
+}
+.fa-hand-o-right:before {
+  content: "\f0a4";
+}
+.fa-hand-o-left:before {
+  content: "\f0a5";
+}
+.fa-hand-o-up:before {
+  content: "\f0a6";
+}
+.fa-hand-o-down:before {
+  content: "\f0a7";
+}
+.fa-arrow-circle-left:before {
+  content: "\f0a8";
+}
+.fa-arrow-circle-right:before {
+  content: "\f0a9";
+}
+.fa-arrow-circle-up:before {
+  content: "\f0aa";
+}
+.fa-arrow-circle-down:before {
+  content: "\f0ab";
+}
+.fa-globe:before {
+  content: "\f0ac";
+}
+.fa-wrench:before {
+  content: "\f0ad";
+}
+.fa-tasks:before {
+  content: "\f0ae";
+}
+.fa-filter:before {
+  content: "\f0b0";
+}
+.fa-briefcase:before {
+  content: "\f0b1";
+}
+.fa-arrows-alt:before {
+  content: "\f0b2";
+}
+.fa-group:before,
+.fa-users:before {
+  content: "\f0c0";
+}
+.fa-chain:before,
+.fa-link:before {
+  content: "\f0c1";
+}
+.fa-cloud:before {
+  content: "\f0c2";
+}
+.fa-flask:before {
+  content: "\f0c3";
+}
+.fa-cut:before,
+.fa-scissors:before {
+  content: "\f0c4";
+}
+.fa-copy:before,
+.fa-files-o:before {
+  content: "\f0c5";
+}
+.fa-paperclip:before {
+  content: "\f0c6";
+}
+.fa-save:before,
+.fa-floppy-o:before {
+  content: "\f0c7";
+}
+.fa-square:before {
+  content: "\f0c8";
+}
+.fa-navicon:before,
+.fa-reorder:before,
+.fa-bars:before {
+  content: "\f0c9";
+}
+.fa-list-ul:before {
+  content: "\f0ca";
+}
+.fa-list-ol:before {
+  content: "\f0cb";
+}
+.fa-strikethrough:before {
+  content: "\f0cc";
+}
+.fa-underline:before {
+  content: "\f0cd";
+}
+.fa-table:before {
+  content: "\f0ce";
+}
+.fa-magic:before {
+  content: "\f0d0";
+}
+.fa-truck:before {
+  content: "\f0d1";
+}
+.fa-pinterest:before {
+  content: "\f0d2";
+}
+.fa-pinterest-square:before {
+  content: "\f0d3";
+}
+.fa-google-plus-square:before {
+  content: "\f0d4";
+}
+.fa-google-plus:before {
+  content: "\f0d5";
+}
+.fa-money:before {
+  content: "\f0d6";
+}
+.fa-caret-down:before {
+  content: "\f0d7";
+}
+.fa-caret-up:before {
+  content: "\f0d8";
+}
+.fa-caret-left:before {
+  content: "\f0d9";
+}
+.fa-caret-right:before {
+  content: "\f0da";
+}
+.fa-columns:before {
+  content: "\f0db";
+}
+.fa-unsorted:before,
+.fa-sort:before {
+  content: "\f0dc";
+}
+.fa-sort-down:before,
+.fa-sort-desc:before {
+  content: "\f0dd";
+}
+.fa-sort-up:before,
+.fa-sort-asc:before {
+  content: "\f0de";
+}
+.fa-envelope:before {
+  content: "\f0e0";
+}
+.fa-linkedin:before {
+  content: "\f0e1";
+}
+.fa-rotate-left:before,
+.fa-undo:before {
+  content: "\f0e2";
+}
+.fa-legal:before,
+.fa-gavel:before {
+  content: "\f0e3";
+}
+.fa-dashboard:before,
+.fa-tachometer:before {
+  content: "\f0e4";
+}
+.fa-comment-o:before {
+  content: "\f0e5";
+}
+.fa-comments-o:before {
+  content: "\f0e6";
+}
+.fa-flash:before,
+.fa-bolt:before {
+  content: "\f0e7";
+}
+.fa-sitemap:before {
+  content: "\f0e8";
+}
+.fa-umbrella:before {
+  content: "\f0e9";
+}
+.fa-paste:before,
+.fa-clipboard:before {
+  content: "\f0ea";
+}
+.fa-lightbulb-o:before {
+  content: "\f0eb";
+}
+.fa-exchange:before {
+  content: "\f0ec";
+}
+.fa-cloud-download:before {
+  content: "\f0ed";
+}
+.fa-cloud-upload:before {
+  content: "\f0ee";
+}
+.fa-user-md:before {
+  content: "\f0f0";
+}
+.fa-stethoscope:before {
+  content: "\f0f1";
+}
+.fa-suitcase:before {
+  content: "\f0f2";
+}
+.fa-bell-o:before {
+  content: "\f0a2";
+}
+.fa-coffee:before {
+  content: "\f0f4";
+}
+.fa-cutlery:before {
+  content: "\f0f5";
+}
+.fa-file-text-o:before {
+  content: "\f0f6";
+}
+.fa-building-o:before {
+  content: "\f0f7";
+}
+.fa-hospital-o:before {
+  content: "\f0f8";
+}
+.fa-ambulance:before {
+  content: "\f0f9";
+}
+.fa-medkit:before {
+  content: "\f0fa";
+}
+.fa-fighter-jet:before {
+  content: "\f0fb";
+}
+.fa-beer:before {
+  content: "\f0fc";
+}
+.fa-h-square:before {
+  content: "\f0fd";
+}
+.fa-plus-square:before {
+  content: "\f0fe";
+}
+.fa-angle-double-left:before {
+  content: "\f100";
+}
+.fa-angle-double-right:before {
+  content: "\f101";
+}
+.fa-angle-double-up:before {
+  content: "\f102";
+}
+.fa-angle-double-down:before {
+  content: "\f103";
+}
+.fa-angle-left:before {
+  content: "\f104";
+}
+.fa-angle-right:before {
+  content: "\f105";
+}
+.fa-angle-up:before {
+  content: "\f106";
+}
+.fa-angle-down:before {
+  content: "\f107";
+}
+.fa-desktop:before {
+  content: "\f108";
+}
+.fa-laptop:before {
+  content: "\f109";
+}
+.fa-tablet:before {
+  content: "\f10a";
+}
+.fa-mobile-phone:before,
+.fa-mobile:before {
+  content: "\f10b";
+}
+.fa-circle-o:before {
+  content: "\f10c";
+}
+.fa-quote-left:before {
+  content: "\f10d";
+}
+.fa-quote-right:before {
+  content: "\f10e";
+}
+.fa-spinner:before {
+  content: "\f110";
+}
+.fa-circle:before {
+  content: "\f111";
+}
+.fa-mail-reply:before,
+.fa-reply:before {
+  content: "\f112";
+}
+.fa-github-alt:before {
+  content: "\f113";
+}
+.fa-folder-o:before {
+  content: "\f114";
+}
+.fa-folder-open-o:before {
+  content: "\f115";
+}
+.fa-smile-o:before {
+  content: "\f118";
+}
+.fa-frown-o:before {
+  content: "\f119";
+}
+.fa-meh-o:before {
+  content: "\f11a";
+}
+.fa-gamepad:before {
+  content: "\f11b";
+}
+.fa-keyboard-o:before {
+  content: "\f11c";
+}
+.fa-flag-o:before {
+  content: "\f11d";
+}
+.fa-flag-checkered:before {
+  content: "\f11e";
+}
+.fa-terminal:before {
+  content: "\f120";
+}
+.fa-code:before {
+  content: "\f121";
+}
+.fa-mail-reply-all:before,
+.fa-reply-all:before {
+  content: "\f122";
+}
+.fa-star-half-empty:before,
+.fa-star-half-full:before,
+.fa-star-half-o:before {
+  content: "\f123";
+}
+.fa-location-arrow:before {
+  content: "\f124";
+}
+.fa-crop:before {
+  content: "\f125";
+}
+.fa-code-fork:before {
+  content: "\f126";
+}
+.fa-unlink:before,
+.fa-chain-broken:before {
+  content: "\f127";
+}
+.fa-question:before {
+  content: "\f128";
+}
+.fa-info:before {
+  content: "\f129";
+}
+.fa-exclamation:before {
+  content: "\f12a";
+}
+.fa-superscript:before {
+  content: "\f12b";
+}
+.fa-subscript:before {
+  content: "\f12c";
+}
+.fa-eraser:before {
+  content: "\f12d";
+}
+.fa-puzzle-piece:before {
+  content: "\f12e";
+}
+.fa-microphone:before {
+  content: "\f130";
+}
+.fa-microphone-slash:before {
+  content: "\f131";
+}
+.fa-shield:before {
+  content: "\f132";
+}
+.fa-calendar-o:before {
+  content: "\f133";
+}
+.fa-fire-extinguisher:before {
+  content: "\f134";
+}
+.fa-rocket:before {
+  content: "\f135";
+}
+.fa-maxcdn:before {
+  content: "\f136";
+}
+.fa-chevron-circle-left:before {
+  content: "\f137";
+}
+.fa-chevron-circle-right:before {
+  content: "\f138";
+}
+.fa-chevron-circle-up:before {
+  content: "\f139";
+}
+.fa-chevron-circle-down:before {
+  content: "\f13a";
+}
+.fa-html5:before {
+  content: "\f13b";
+}
+.fa-css3:before {
+  content: "\f13c";
+}
+.fa-anchor:before {
+  content: "\f13d";
+}
+.fa-unlock-alt:before {
+  content: "\f13e";
+}
+.fa-bullseye:before {
+  content: "\f140";
+}
+.fa-ellipsis-h:before {
+  content: "\f141";
+}
+.fa-ellipsis-v:before {
+  content: "\f142";
+}
+.fa-rss-square:before {
+  content: "\f143";
+}
+.fa-play-circle:before {
+  content: "\f144";
+}
+.fa-ticket:before {
+  content: "\f145";
+}
+.fa-minus-square:before {
+  content: "\f146";
+}
+.fa-minus-square-o:before {
+  content: "\f147";
+}
+.fa-level-up:before {
+  content: "\f148";
+}
+.fa-level-down:before {
+  content: "\f149";
+}
+.fa-check-square:before {
+  content: "\f14a";
+}
+.fa-pencil-square:before {
+  content: "\f14b";
+}
+.fa-external-link-square:before {
+  content: "\f14c";
+}
+.fa-share-square:before {
+  content: "\f14d";
+}
+.fa-compass:before {
+  content: "\f14e";
+}
+.fa-toggle-down:before,
+.fa-caret-square-o-down:before {
+  content: "\f150";
+}
+.fa-toggle-up:before,
+.fa-caret-square-o-up:before {
+  content: "\f151";
+}
+.fa-toggle-right:before,
+.fa-caret-square-o-right:before {
+  content: "\f152";
+}
+.fa-euro:before,
+.fa-eur:before {
+  content: "\f153";
+}
+.fa-gbp:before {
+  content: "\f154";
+}
+.fa-dollar:before,
+.fa-usd:before {
+  content: "\f155";
+}
+.fa-rupee:before,
+.fa-inr:before {
+  content: "\f156";
+}
+.fa-cny:before,
+.fa-rmb:before,
+.fa-yen:before,
+.fa-jpy:before {
+  content: "\f157";
+}
+.fa-ruble:before,
+.fa-rouble:before,
+.fa-rub:before {
+  content: "\f158";
+}
+.fa-won:before,
+.fa-krw:before {
+  content: "\f159";
+}
+.fa-bitcoin:before,
+.fa-btc:before {
+  content: "\f15a";
+}
+.fa-file:before {
+  content: "\f15b";
+}
+.fa-file-text:before {
+  content: "\f15c";
+}
+.fa-sort-alpha-asc:before {
+  content: "\f15d";
+}
+.fa-sort-alpha-desc:before {
+  content: "\f15e";
+}
+.fa-sort-amount-asc:before {
+  content: "\f160";
+}
+.fa-sort-amount-desc:before {
+  content: "\f161";
+}
+.fa-sort-numeric-asc:before {
+  content: "\f162";
+}
+.fa-sort-numeric-desc:before {
+  content: "\f163";
+}
+.fa-thumbs-up:before {
+  content: "\f164";
+}
+.fa-thumbs-down:before {
+  content: "\f165";
+}
+.fa-youtube-square:before {
+  content: "\f166";
+}
+.fa-youtube:before {
+  content: "\f167";
+}
+.fa-xing:before {
+  content: "\f168";
+}
+.fa-xing-square:before {
+  content: "\f169";
+}
+.fa-youtube-play:before {
+  content: "\f16a";
+}
+.fa-dropbox:before {
+  content: "\f16b";
+}
+.fa-stack-overflow:before {
+  content: "\f16c";
+}
+.fa-instagram:before {
+  content: "\f16d";
+}
+.fa-flickr:before {
+  content: "\f16e";
+}
+.fa-adn:before {
+  content: "\f170";
+}
+.fa-bitbucket:before {
+  content: "\f171";
+}
+.fa-bitbucket-square:before {
+  content: "\f172";
+}
+.fa-tumblr:before {
+  content: "\f173";
+}
+.fa-tumblr-square:before {
+  content: "\f174";
+}
+.fa-long-arrow-down:before {
+  content: "\f175";
+}
+.fa-long-arrow-up:before {
+  content: "\f176";
+}
+.fa-long-arrow-left:before {
+  content: "\f177";
+}
+.fa-long-arrow-right:before {
+  content: "\f178";
+}
+.fa-apple:before {
+  content: "\f179";
+}
+.fa-windows:before {
+  content: "\f17a";
+}
+.fa-android:before {
+  content: "\f17b";
+}
+.fa-linux:before {
+  content: "\f17c";
+}
+.fa-dribbble:before {
+  content: "\f17d";
+}
+.fa-skype:before {
+  content: "\f17e";
+}
+.fa-foursquare:before {
+  content: "\f180";
+}
+.fa-trello:before {
+  content: "\f181";
+}
+.fa-female:before {
+  content: "\f182";
+}
+.fa-male:before {
+  content: "\f183";
+}
+.fa-gittip:before,
+.fa-gratipay:before {
+  content: "\f184";
+}
+.fa-sun-o:before {
+  content: "\f185";
+}
+.fa-moon-o:before {
+  content: "\f186";
+}
+.fa-archive:before {
+  content: "\f187";
+}
+.fa-bug:before {
+  content: "\f188";
+}
+.fa-vk:before {
+  content: "\f189";
+}
+.fa-weibo:before {
+  content: "\f18a";
+}
+.fa-renren:before {
+  content: "\f18b";
+}
+.fa-pagelines:before {
+  content: "\f18c";
+}
+.fa-stack-exchange:before {
+  content: "\f18d";
+}
+.fa-arrow-circle-o-right:before {
+  content: "\f18e";
+}
+.fa-arrow-circle-o-left:before {
+  content: "\f190";
+}
+.fa-toggle-left:before,
+.fa-caret-square-o-left:before {
+  content: "\f191";
+}
+.fa-dot-circle-o:before {
+  content: "\f192";
+}
+.fa-wheelchair:before {
+  content: "\f193";
+}
+.fa-vimeo-square:before {
+  content: "\f194";
+}
+.fa-turkish-lira:before,
+.fa-try:before {
+  content: "\f195";
+}
+.fa-plus-square-o:before {
+  content: "\f196";
+}
+.fa-space-shuttle:before {
+  content: "\f197";
+}
+.fa-slack:before {
+  content: "\f198";
+}
+.fa-envelope-square:before {
+  content: "\f199";
+}
+.fa-wordpress:before {
+  content: "\f19a";
+}
+.fa-openid:before {
+  content: "\f19b";
+}
+.fa-institution:before,
+.fa-bank:before,
+.fa-university:before {
+  content: "\f19c";
+}
+.fa-mortar-board:before,
+.fa-graduation-cap:before {
+  content: "\f19d";
+}
+.fa-yahoo:before {
+  content: "\f19e";
+}
+.fa-google:before {
+  content: "\f1a0";
+}
+.fa-reddit:before {
+  content: "\f1a1";
+}
+.fa-reddit-square:before {
+  content: "\f1a2";
+}
+.fa-stumbleupon-circle:before {
+  content: "\f1a3";
+}
+.fa-stumbleupon:before {
+  content: "\f1a4";
+}
+.fa-delicious:before {
+  content: "\f1a5";
+}
+.fa-digg:before {
+  content: "\f1a6";
+}
+.fa-pied-piper-pp:before {
+  content: "\f1a7";
+}
+.fa-pied-piper-alt:before {
+  content: "\f1a8";
+}
+.fa-drupal:before {
+  content: "\f1a9";
+}
+.fa-joomla:before {
+  content: "\f1aa";
+}
+.fa-language:before {
+  content: "\f1ab";
+}
+.fa-fax:before {
+  content: "\f1ac";
+}
+.fa-building:before {
+  content: "\f1ad";
+}
+.fa-child:before {
+  content: "\f1ae";
+}
+.fa-paw:before {
+  content: "\f1b0";
+}
+.fa-spoon:before {
+  content: "\f1b1";
+}
+.fa-cube:before {
+  content: "\f1b2";
+}
+.fa-cubes:before {
+  content: "\f1b3";
+}
+.fa-behance:before {
+  content: "\f1b4";
+}
+.fa-behance-square:before {
+  content: "\f1b5";
+}
+.fa-steam:before {
+  content: "\f1b6";
+}
+.fa-steam-square:before {
+  content: "\f1b7";
+}
+.fa-recycle:before {
+  content: "\f1b8";
+}
+.fa-automobile:before,
+.fa-car:before {
+  content: "\f1b9";
+}
+.fa-cab:before,
+.fa-taxi:before {
+  content: "\f1ba";
+}
+.fa-tree:before {
+  content: "\f1bb";
+}
+.fa-spotify:before {
+  content: "\f1bc";
+}
+.fa-deviantart:before {
+  content: "\f1bd";
+}
+.fa-soundcloud:before {
+  content: "\f1be";
+}
+.fa-database:before {
+  content: "\f1c0";
+}
+.fa-file-pdf-o:before {
+  content: "\f1c1";
+}
+.fa-file-word-o:before {
+  content: "\f1c2";
+}
+.fa-file-excel-o:before {
+  content: "\f1c3";
+}
+.fa-file-powerpoint-o:before {
+  content: "\f1c4";
+}
+.fa-file-photo-o:before,
+.fa-file-picture-o:before,
+.fa-file-image-o:before {
+  content: "\f1c5";
+}
+.fa-file-zip-o:before,
+.fa-file-archive-o:before {
+  content: "\f1c6";
+}
+.fa-file-sound-o:before,
+.fa-file-audio-o:before {
+  content: "\f1c7";
+}
+.fa-file-movie-o:before,
+.fa-file-video-o:before {
+  content: "\f1c8";
+}
+.fa-file-code-o:before {
+  content: "\f1c9";
+}
+.fa-vine:before {
+  content: "\f1ca";
+}
+.fa-codepen:before {
+  content: "\f1cb";
+}
+.fa-jsfiddle:before {
+  content: "\f1cc";
+}
+.fa-life-bouy:before,
+.fa-life-buoy:before,
+.fa-life-saver:before,
+.fa-support:before,
+.fa-life-ring:before {
+  content: "\f1cd";
+}
+.fa-circle-o-notch:before {
+  content: "\f1ce";
+}
+.fa-ra:before,
+.fa-resistance:before,
+.fa-rebel:before {
+  content: "\f1d0";
+}
+.fa-ge:before,
+.fa-empire:before {
+  content: "\f1d1";
+}
+.fa-git-square:before {
+  content: "\f1d2";
+}
+.fa-git:before {
+  content: "\f1d3";
+}
+.fa-y-combinator-square:before,
+.fa-yc-square:before,
+.fa-hacker-news:before {
+  content: "\f1d4";
+}
+.fa-tencent-weibo:before {
+  content: "\f1d5";
+}
+.fa-qq:before {
+  content: "\f1d6";
+}
+.fa-wechat:before,
+.fa-weixin:before {
+  content: "\f1d7";
+}
+.fa-send:before,
+.fa-paper-plane:before {
+  content: "\f1d8";
+}
+.fa-send-o:before,
+.fa-paper-plane-o:before {
+  content: "\f1d9";
+}
+.fa-history:before {
+  content: "\f1da";
+}
+.fa-circle-thin:before {
+  content: "\f1db";
+}
+.fa-header:before {
+  content: "\f1dc";
+}
+.fa-paragraph:before {
+  content: "\f1dd";
+}
+.fa-sliders:before {
+  content: "\f1de";
+}
+.fa-share-alt:before {
+  content: "\f1e0";
+}
+.fa-share-alt-square:before {
+  content: "\f1e1";
+}
+.fa-bomb:before {
+  content: "\f1e2";
+}
+.fa-soccer-ball-o:before,
+.fa-futbol-o:before {
+  content: "\f1e3";
+}
+.fa-tty:before {
+  content: "\f1e4";
+}
+.fa-binoculars:before {
+  content: "\f1e5";
+}
+.fa-plug:before {
+  content: "\f1e6";
+}
+.fa-slideshare:before {
+  content: "\f1e7";
+}
+.fa-twitch:before {
+  content: "\f1e8";
+}
+.fa-yelp:before {
+  content: "\f1e9";
+}
+.fa-newspaper-o:before {
+  content: "\f1ea";
+}
+.fa-wifi:before {
+  content: "\f1eb";
+}
+.fa-calculator:before {
+  content: "\f1ec";
+}
+.fa-paypal:before {
+  content: "\f1ed";
+}
+.fa-google-wallet:before {
+  content: "\f1ee";
+}
+.fa-cc-visa:before {
+  content: "\f1f0";
+}
+.fa-cc-mastercard:before {
+  content: "\f1f1";
+}
+.fa-cc-discover:before {
+  content: "\f1f2";
+}
+.fa-cc-amex:before {
+  content: "\f1f3";
+}
+.fa-cc-paypal:before {
+  content: "\f1f4";
+}
+.fa-cc-stripe:before {
+  content: "\f1f5";
+}
+.fa-bell-slash:before {
+  content: "\f1f6";
+}
+.fa-bell-slash-o:before {
+  content: "\f1f7";
+}
+.fa-trash:before {
+  content: "\f1f8";
+}
+.fa-copyright:before {
+  content: "\f1f9";
+}
+.fa-at:before {
+  content: "\f1fa";
+}
+.fa-eyedropper:before {
+  content: "\f1fb";
+}
+.fa-paint-brush:before {
+  content: "\f1fc";
+}
+.fa-birthday-cake:before {
+  content: "\f1fd";
+}
+.fa-area-chart:before {
+  content: "\f1fe";
+}
+.fa-pie-chart:before {
+  content: "\f200";
+}
+.fa-line-chart:before {
+  content: "\f201";
+}
+.fa-lastfm:before {
+  content: "\f202";
+}
+.fa-lastfm-square:before {
+  content: "\f203";
+}
+.fa-toggle-off:before {
+  content: "\f204";
+}
+.fa-toggle-on:before {
+  content: "\f205";
+}
+.fa-bicycle:before {
+  content: "\f206";
+}
+.fa-bus:before {
+  content: "\f207";
+}
+.fa-ioxhost:before {
+  content: "\f208";
+}
+.fa-angellist:before {
+  content: "\f209";
+}
+.fa-cc:before {
+  content: "\f20a";
+}
+.fa-shekel:before,
+.fa-sheqel:before,
+.fa-ils:before {
+  content: "\f20b";
+}
+.fa-meanpath:before {
+  content: "\f20c";
+}
+.fa-buysellads:before {
+  content: "\f20d";
+}
+.fa-connectdevelop:before {
+  content: "\f20e";
+}
+.fa-dashcube:before {
+  content: "\f210";
+}
+.fa-forumbee:before {
+  content: "\f211";
+}
+.fa-leanpub:before {
+  content: "\f212";
+}
+.fa-sellsy:before {
+  content: "\f213";
+}
+.fa-shirtsinbulk:before {
+  content: "\f214";
+}
+.fa-simplybuilt:before {
+  content: "\f215";
+}
+.fa-skyatlas:before {
+  content: "\f216";
+}
+.fa-cart-plus:before {
+  content: "\f217";
+}
+.fa-cart-arrow-down:before {
+  content: "\f218";
+}
+.fa-diamond:before {
+  content: "\f219";
+}
+.fa-ship:before {
+  content: "\f21a";
+}
+.fa-user-secret:before {
+  content: "\f21b";
+}
+.fa-motorcycle:before {
+  content: "\f21c";
+}
+.fa-street-view:before {
+  content: "\f21d";
+}
+.fa-heartbeat:before {
+  content: "\f21e";
+}
+.fa-venus:before {
+  content: "\f221";
+}
+.fa-mars:before {
+  content: "\f222";
+}
+.fa-mercury:before {
+  content: "\f223";
+}
+.fa-intersex:before,
+.fa-transgender:before {
+  content: "\f224";
+}
+.fa-transgender-alt:before {
+  content: "\f225";
+}
+.fa-venus-double:before {
+  content: "\f226";
+}
+.fa-mars-double:before {
+  content: "\f227";
+}
+.fa-venus-mars:before {
+  content: "\f228";
+}
+.fa-mars-stroke:before {
+  content: "\f229";
+}
+.fa-mars-stroke-v:before {
+  content: "\f22a";
+}
+.fa-mars-stroke-h:before {
+  content: "\f22b";
+}
+.fa-neuter:before {
+  content: "\f22c";
+}
+.fa-genderless:before {
+  content: "\f22d";
+}
+.fa-facebook-official:before {
+  content: "\f230";
+}
+.fa-pinterest-p:before {
+  content: "\f231";
+}
+.fa-whatsapp:before {
+  content: "\f232";
+}
+.fa-server:before {
+  content: "\f233";
+}
+.fa-user-plus:before {
+  content: "\f234";
+}
+.fa-user-times:before {
+  content: "\f235";
+}
+.fa-hotel:before,
+.fa-bed:before {
+  content: "\f236";
+}
+.fa-viacoin:before {
+  content: "\f237";
+}
+.fa-train:before {
+  content: "\f238";
+}
+.fa-subway:before {
+  content: "\f239";
+}
+.fa-medium:before {
+  content: "\f23a";
+}
+.fa-yc:before,
+.fa-y-combinator:before {
+  content: "\f23b";
+}
+.fa-optin-monster:before {
+  content: "\f23c";
+}
+.fa-opencart:before {
+  content: "\f23d";
+}
+.fa-expeditedssl:before {
+  content: "\f23e";
+}
+.fa-battery-4:before,
+.fa-battery-full:before {
+  content: "\f240";
+}
+.fa-battery-3:before,
+.fa-battery-three-quarters:before {
+  content: "\f241";
+}
+.fa-battery-2:before,
+.fa-battery-half:before {
+  content: "\f242";
+}
+.fa-battery-1:before,
+.fa-battery-quarter:before {
+  content: "\f243";
+}
+.fa-battery-0:before,
+.fa-battery-empty:before {
+  content: "\f244";
+}
+.fa-mouse-pointer:before {
+  content: "\f245";
+}
+.fa-i-cursor:before {
+  content: "\f246";
+}
+.fa-object-group:before {
+  content: "\f247";
+}
+.fa-object-ungroup:before {
+  content: "\f248";
+}
+.fa-sticky-note:before {
+  content: "\f249";
+}
+.fa-sticky-note-o:before {
+  content: "\f24a";
+}
+.fa-cc-jcb:before {
+  content: "\f24b";
+}
+.fa-cc-diners-club:before {
+  content: "\f24c";
+}
+.fa-clone:before {
+  content: "\f24d";
+}
+.fa-balance-scale:before {
+  content: "\f24e";
+}
+.fa-hourglass-o:before {
+  content: "\f250";
+}
+.fa-hourglass-1:before,
+.fa-hourglass-start:before {
+  content: "\f251";
+}
+.fa-hourglass-2:before,
+.fa-hourglass-half:before {
+  content: "\f252";
+}
+.fa-hourglass-3:before,
+.fa-hourglass-end:before {
+  content: "\f253";
+}
+.fa-hourglass:before {
+  content: "\f254";
+}
+.fa-hand-grab-o:before,
+.fa-hand-rock-o:before {
+  content: "\f255";
+}
+.fa-hand-stop-o:before,
+.fa-hand-paper-o:before {
+  content: "\f256";
+}
+.fa-hand-scissors-o:before {
+  content: "\f257";
+}
+.fa-hand-lizard-o:before {
+  content: "\f258";
+}
+.fa-hand-spock-o:before {
+  content: "\f259";
+}
+.fa-hand-pointer-o:before {
+  content: "\f25a";
+}
+.fa-hand-peace-o:before {
+  content: "\f25b";
+}
+.fa-trademark:before {
+  content: "\f25c";
+}
+.fa-registered:before {
+  content: "\f25d";
+}
+.fa-creative-commons:before {
+  content: "\f25e";
+}
+.fa-gg:before {
+  content: "\f260";
+}
+.fa-gg-circle:before {
+  content: "\f261";
+}
+.fa-tripadvisor:before {
+  content: "\f262";
+}
+.fa-odnoklassniki:before {
+  content: "\f263";
+}
+.fa-odnoklassniki-square:before {
+  content: "\f264";
+}
+.fa-get-pocket:before {
+  content: "\f265";
+}
+.fa-wikipedia-w:before {
+  content: "\f266";
+}
+.fa-safari:before {
+  content: "\f267";
+}
+.fa-chrome:before {
+  content: "\f268";
+}
+.fa-firefox:before {
+  content: "\f269";
+}
+.fa-opera:before {
+  content: "\f26a";
+}
+.fa-internet-explorer:before {
+  content: "\f26b";
+}
+.fa-tv:before,
+.fa-television:before {
+  content: "\f26c";
+}
+.fa-contao:before {
+  content: "\f26d";
+}
+.fa-500px:before {
+  content: "\f26e";
+}
+.fa-amazon:before {
+  content: "\f270";
+}
+.fa-calendar-plus-o:before {
+  content: "\f271";
+}
+.fa-calendar-minus-o:before {
+  content: "\f272";
+}
+.fa-calendar-times-o:before {
+  content: "\f273";
+}
+.fa-calendar-check-o:before {
+  content: "\f274";
+}
+.fa-industry:before {
+  content: "\f275";
+}
+.fa-map-pin:before {
+  content: "\f276";
+}
+.fa-map-signs:before {
+  content: "\f277";
+}
+.fa-map-o:before {
+  content: "\f278";
+}
+.fa-map:before {
+  content: "\f279";
+}
+.fa-commenting:before {
+  content: "\f27a";
+}
+.fa-commenting-o:before {
+  content: "\f27b";
+}
+.fa-houzz:before {
+  content: "\f27c";
+}
+.fa-vimeo:before {
+  content: "\f27d";
+}
+.fa-black-tie:before {
+  content: "\f27e";
+}
+.fa-fonticons:before {
+  content: "\f280";
+}
+.fa-reddit-alien:before {
+  content: "\f281";
+}
+.fa-edge:before {
+  content: "\f282";
+}
+.fa-credit-card-alt:before {
+  content: "\f283";
+}
+.fa-codiepie:before {
+  content: "\f284";
+}
+.fa-modx:before {
+  content: "\f285";
+}
+.fa-fort-awesome:before {
+  content: "\f286";
+}
+.fa-usb:before {
+  content: "\f287";
+}
+.fa-product-hunt:before {
+  content: "\f288";
+}
+.fa-mixcloud:before {
+  content: "\f289";
+}
+.fa-scribd:before {
+  content: "\f28a";
+}
+.fa-pause-circle:before {
+  content: "\f28b";
+}
+.fa-pause-circle-o:before {
+  content: "\f28c";
+}
+.fa-stop-circle:before {
+  content: "\f28d";
+}
+.fa-stop-circle-o:before {
+  content: "\f28e";
+}
+.fa-shopping-bag:before {
+  content: "\f290";
+}
+.fa-shopping-basket:before {
+  content: "\f291";
+}
+.fa-hashtag:before {
+  content: "\f292";
+}
+.fa-bluetooth:before {
+  content: "\f293";
+}
+.fa-bluetooth-b:before {
+  content: "\f294";
+}
+.fa-percent:before {
+  content: "\f295";
+}
+.fa-gitlab:before {
+  content: "\f296";
+}
+.fa-wpbeginner:before {
+  content: "\f297";
+}
+.fa-wpforms:before {
+  content: "\f298";
+}
+.fa-envira:before {
+  content: "\f299";
+}
+.fa-universal-access:before {
+  content: "\f29a";
+}
+.fa-wheelchair-alt:before {
+  content: "\f29b";
+}
+.fa-question-circle-o:before {
+  content: "\f29c";
+}
+.fa-blind:before {
+  content: "\f29d";
+}
+.fa-audio-description:before {
+  content: "\f29e";
+}
+.fa-volume-control-phone:before {
+  content: "\f2a0";
+}
+.fa-braille:before {
+  content: "\f2a1";
+}
+.fa-assistive-listening-systems:before {
+  content: "\f2a2";
+}
+.fa-asl-interpreting:before,
+.fa-american-sign-language-interpreting:before {
+  content: "\f2a3";
+}
+.fa-deafness:before,
+.fa-hard-of-hearing:before,
+.fa-deaf:before {
+  content: "\f2a4";
+}
+.fa-glide:before {
+  content: "\f2a5";
+}
+.fa-glide-g:before {
+  content: "\f2a6";
+}
+.fa-signing:before,
+.fa-sign-language:before {
+  content: "\f2a7";
+}
+.fa-low-vision:before {
+  content: "\f2a8";
+}
+.fa-viadeo:before {
+  content: "\f2a9";
+}
+.fa-viadeo-square:before {
+  content: "\f2aa";
+}
+.fa-snapchat:before {
+  content: "\f2ab";
+}
+.fa-snapchat-ghost:before {
+  content: "\f2ac";
+}
+.fa-snapchat-square:before {
+  content: "\f2ad";
+}
+.fa-pied-piper:before {
+  content: "\f2ae";
+}
+.fa-first-order:before {
+  content: "\f2b0";
+}
+.fa-yoast:before {
+  content: "\f2b1";
+}
+.fa-themeisle:before {
+  content: "\f2b2";
+}
+.fa-google-plus-circle:before,
+.fa-google-plus-official:before {
+  content: "\f2b3";
+}
+.fa-fa:before,
+.fa-font-awesome:before {
+  content: "\f2b4";
+}
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  padding: 0;
+  margin: -1px;
+  overflow: hidden;
+  clip: rect(0, 0, 0, 0);
+  border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+  position: static;
+  width: auto;
+  height: auto;
+  margin: 0;
+  overflow: visible;
+  clip: auto;
+}
diff --git a/hubs/static/font-awesome-4.6.3/css/font-awesome.min.css b/hubs/static/font-awesome-4.6.3/css/font-awesome.min.css
new file mode 100644
index 0000000..4ec9223
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/css/font-awesome.min.css
@@ -0,0 +1,4 @@
+/*!
+ *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.6.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.6.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.6.3') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.6.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.6.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.6.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}
\ No newline at end of file
diff --git a/hubs/static/font-awesome-4.6.3/fonts/FontAwesome.otf b/hubs/static/font-awesome-4.6.3/fonts/FontAwesome.otf
new file mode 100644
index 0000000..d4de13e
Binary files /dev/null and b/hubs/static/font-awesome-4.6.3/fonts/FontAwesome.otf differ
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.eot b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.eot
new file mode 100644
index 0000000..c7b00d2
Binary files /dev/null and b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.eot differ
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.svg b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.svg
new file mode 100644
index 0000000..8b66187
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.svg
@@ -0,0 +1,685 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="fontawesomeregular" horiz-adv-x="1536" >
+<font-face units-per-em="1792" ascent="1536" descent="-256" />
+<missing-glyph horiz-adv-x="448" />
+<glyph unicode=" "  horiz-adv-x="448" />
+<glyph unicode="&#x09;" horiz-adv-x="448" />
+<glyph unicode="&#xa0;" horiz-adv-x="448" />
+<glyph unicode="&#xa8;" horiz-adv-x="1792" />
+<glyph unicode="&#xa9;" horiz-adv-x="1792" />
+<glyph unicode="&#xae;" horiz-adv-x="1792" />
+<glyph unicode="&#xb4;" horiz-adv-x="1792" />
+<glyph unicode="&#xc6;" horiz-adv-x="1792" />
+<glyph unicode="&#xd8;" horiz-adv-x="1792" />
+<glyph unicode="&#x2000;" horiz-adv-x="768" />
+<glyph unicode="&#x2001;" horiz-adv-x="1537" />
+<glyph unicode="&#x2002;" horiz-adv-x="768" />
+<glyph unicode="&#x2003;" horiz-adv-x="1537" />
+<glyph unicode="&#x2004;" horiz-adv-x="512" />
+<glyph unicode="&#x2005;" horiz-adv-x="384" />
+<glyph unicode="&#x2006;" horiz-adv-x="256" />
+<glyph unicode="&#x2007;" horiz-adv-x="256" />
+<glyph unicode="&#x2008;" horiz-adv-x="192" />
+<glyph unicode="&#x2009;" horiz-adv-x="307" />
+<glyph unicode="&#x200a;" horiz-adv-x="85" />
+<glyph unicode="&#x202f;" horiz-adv-x="307" />
+<glyph unicode="&#x205f;" horiz-adv-x="384" />
+<glyph unicode="&#x2122;" horiz-adv-x="1792" />
+<glyph unicode="&#x221e;" horiz-adv-x="1792" />
+<glyph unicode="&#x2260;" horiz-adv-x="1792" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
+<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
+<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
+<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
+<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
+<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
+<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
+<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
+<glyph unicode="&#xf016;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z " />
+<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
+<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
+<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
+<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
+<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
+<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
+<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
+<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
+<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
+<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
+<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
+<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
+<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -4 -0.5 -13t-0.5 -13q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" />
+<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68.5 -0.5t67.5 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" />
+<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q6 2 81.5 21.5t111.5 37.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" />
+<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" />
+<glyph unicode="&#xf035;" d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" />
+<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
+<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
+<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
+<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
+<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
+<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
+<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
+<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
+<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
+<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
+<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
+<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
+<glyph unicode="&#xf053;" horiz-adv-x="1280" d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf054;" horiz-adv-x="1280" d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
+<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
+<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
+<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
+<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
+<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
+<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
+<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
+<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
+<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
+<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
+<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
+<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
+<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
+<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
+<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
+<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf077;" horiz-adv-x="1792" d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf078;" horiz-adv-x="1792" d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
+<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1536 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1664 1088v-512q0 -24 -16.5 -42.5t-40.5 -21.5l-1044 -122q13 -60 13 -70q0 -16 -24 -64h920q26 0 45 -19t19 -45 t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 11 8 31.5t16 36t21.5 40t15.5 29.5l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t19.5 -15.5t13 -24.5t8 -26t5.5 -29.5t4.5 -26h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf080;" horiz-adv-x="2048" d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" />
+<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf082;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-188v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-532q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960z" />
+<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
+<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
+<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
+<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
+<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
+<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
+<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
+<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
+<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf092;" d="M519 336q4 6 -3 13q-9 7 -14 2q-4 -6 3 -13q9 -7 14 -2zM491 377q-5 7 -12 4q-6 -4 0 -12q7 -8 12 -5q6 4 0 13zM450 417q2 4 -5 8q-7 2 -8 -2q-3 -5 4 -8q8 -2 9 2zM471 394q2 1 1.5 4.5t-3.5 5.5q-6 7 -10 3t1 -11q6 -6 11 -2zM557 319q2 7 -9 11q-9 3 -13 -4 q-2 -7 9 -11q9 -3 13 4zM599 316q0 8 -12 8q-10 0 -10 -8t11 -8t11 8zM638 323q-2 7 -13 5t-9 -9q2 -8 12 -6t10 10zM1280 640q0 212 -150 362t-362 150t-362 -150t-150 -362q0 -167 98 -300.5t252 -185.5q18 -3 26.5 5t8.5 20q0 52 -1 95q-6 -1 -15.5 -2.5t-35.5 -2t-48 4 t-43.5 20t-29.5 41.5q-23 59 -57 74q-2 1 -4.5 3.5l-8 8t-7 9.5t4 7.5t19.5 3.5q6 0 15 -2t30 -15.5t33 -35.5q16 -28 37.5 -42t43.5 -14t38 3.5t30 9.5q7 47 33 69q-49 6 -86 18.5t-73 39t-55.5 76t-19.5 119.5q0 79 53 137q-24 62 5 136q19 6 54.5 -7.5t60.5 -29.5l26 -16 q58 17 128 17t128 -17q11 7 28.5 18t55.5 26t57 9q29 -74 5 -136q53 -58 53 -137q0 -57 -14 -100.5t-35.5 -70t-53.5 -44.5t-62.5 -26t-68.5 -12q35 -31 35 -95q0 -40 -0.5 -89t-0.5 -51q0 -12 8.5 -20t26.5 -5q154 52 252 185.5t98 300.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
+<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
+<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
+<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
+<glyph unicode="&#xf09a;" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
+<glyph unicode="&#xf09b;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -40 7t-13 30q0 3 0.5 76.5t0.5 134.5q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 119 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24 q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-85 13.5q-45 -113 -8 -204q-79 -87 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-39 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5 t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -88.5t0.5 -54.5q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103zM291 305q3 7 -7 12 q-10 3 -13 -2q-3 -7 7 -12q9 -6 13 2zM322 271q7 5 -2 16q-10 9 -16 3q-7 -5 2 -16q10 -10 16 -3zM352 226q9 7 0 19q-8 13 -17 6q-9 -5 0 -18t17 -7zM394 184q8 8 -4 19q-12 12 -20 3q-9 -8 4 -19q12 -12 20 -3zM451 159q3 11 -13 16q-15 4 -19 -7t13 -15q15 -6 19 6z M514 154q0 13 -17 11q-16 0 -16 -11q0 -13 17 -11q16 0 16 11zM572 164q-2 11 -18 9q-16 -3 -14 -15t18 -8t14 14z" />
+<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
+<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
+<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
+<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
+<glyph unicode="&#xf0a2;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
+<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
+<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
+<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
+<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
+<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
+<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
+<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
+<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
+<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
+<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
+<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
+<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
+<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
+<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
+<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
+<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
+<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
+<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
+<glyph unicode="&#xf0d4;" d="M917 631q0 26 -6 64h-362v-132h217q-3 -24 -16.5 -50t-37.5 -53t-66.5 -44.5t-96.5 -17.5q-99 0 -169 71t-70 171t70 171t169 71q92 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585 h109v110h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0d5;" horiz-adv-x="2304" d="M1437 623q0 -208 -87 -370.5t-248 -254t-369 -91.5q-149 0 -285 58t-234 156t-156 234t-58 285t58 285t156 234t234 156t285 58q286 0 491 -192l-199 -191q-117 113 -292 113q-123 0 -227.5 -62t-165.5 -168.5t-61 -232.5t61 -232.5t165.5 -168.5t227.5 -62 q83 0 152.5 23t114.5 57.5t78.5 78.5t49 83t21.5 74h-416v252h692q12 -63 12 -122zM2304 745v-210h-209v-209h-210v209h-209v210h209v209h210v-209h209z" />
+<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
+<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
+<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
+<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
+<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
+<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
+<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
+<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
+<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
+<glyph unicode="&#xf0f3;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f6;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" />
+<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
+<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
+<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
+<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
+<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf110;" horiz-adv-x="1792" d="M526 142q0 -53 -37.5 -90.5t-90.5 -37.5q-52 0 -90 38t-38 90q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 -64q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -53 -37.5 -90.5t-90.5 -37.5 t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1522 142q0 -52 -38 -90t-90 -38q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM558 1138q0 -66 -47 -113t-113 -47t-113 47t-47 113t47 113t113 47t113 -47t47 -113z M1728 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1088 1344q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1618 1138q0 -93 -66 -158.5t-158 -65.5q-93 0 -158.5 65.5t-65.5 158.5 q0 92 65.5 158t158.5 66q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
+<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
+<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
+<glyph unicode="&#xf116;" horiz-adv-x="1792" />
+<glyph unicode="&#xf117;" horiz-adv-x="1792" />
+<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
+<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
+<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
+<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
+<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
+<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
+<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
+<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
+<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
+<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
+<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
+<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
+<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
+<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
+<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
+<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
+<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
+<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
+<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
+<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
+<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
+<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
+<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
+<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
+<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
+<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
+<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
+<glyph unicode="&#xf158;" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
+<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
+<glyph unicode="&#xf15b;" d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" />
+<glyph unicode="&#xf15c;" d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" />
+<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
+<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
+<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
+<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
+<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
+<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
+<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
+<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
+<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
+<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
+<glyph unicode="&#xf16c;" d="M1289 -96h-1118v480h-160v-640h1438v640h-160v-480zM347 428l33 157l783 -165l-33 -156zM450 802l67 146l725 -339l-67 -145zM651 1158l102 123l614 -513l-102 -123zM1048 1536l477 -641l-128 -96l-477 641zM330 65v159h800v-159h-800z" />
+<glyph unicode="&#xf16d;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1162 640q0 -164 -115 -279t-279 -115t-279 115t-115 279t115 279t279 115t279 -115t115 -279zM1270 1050q0 -38 -27 -65t-65 -27t-65 27t-27 65t27 65t65 27t65 -27t27 -65zM768 1270 q-7 0 -76.5 0.5t-105.5 0t-96.5 -3t-103 -10t-71.5 -18.5q-50 -20 -88 -58t-58 -88q-11 -29 -18.5 -71.5t-10 -103t-3 -96.5t0 -105.5t0.5 -76.5t-0.5 -76.5t0 -105.5t3 -96.5t10 -103t18.5 -71.5q20 -50 58 -88t88 -58q29 -11 71.5 -18.5t103 -10t96.5 -3t105.5 0t76.5 0.5 t76.5 -0.5t105.5 0t96.5 3t103 10t71.5 18.5q50 20 88 58t58 88q11 29 18.5 71.5t10 103t3 96.5t0 105.5t-0.5 76.5t0.5 76.5t0 105.5t-3 96.5t-10 103t-18.5 71.5q-20 50 -58 88t-88 58q-29 11 -71.5 18.5t-103 10t-96.5 3t-105.5 0t-76.5 -0.5zM1536 640q0 -229 -5 -317 q-10 -208 -124 -322t-322 -124q-88 -5 -317 -5t-317 5q-208 10 -322 124t-124 322q-5 88 -5 317t5 317q10 208 124 322t322 124q88 5 317 5t317 -5q208 -10 322 -124t124 -322q5 -88 5 -317z" />
+<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
+<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
+<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 q78 2 134 29z" />
+<glyph unicode="&#xf174;" d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
+<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
+<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
+<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
+<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
+<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
+<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
+<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
+<glyph unicode="&#xf180;" horiz-adv-x="1280" d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" />
+<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
+<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
+<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
+<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
+<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
+<glyph unicode="&#xf18b;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
+<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
+<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
+<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
+<glyph unicode="&#xf194;" d="M1292 898q10 216 -161 222q-231 8 -312 -261q44 19 82 19q85 0 74 -96q-4 -57 -74 -167t-105 -110q-43 0 -82 169q-13 54 -45 255q-30 189 -160 177q-59 -7 -164 -100l-81 -72l-81 -72l52 -67q76 52 87 52q57 0 107 -179q15 -55 45 -164.5t45 -164.5q68 -179 164 -179 q157 0 383 294q220 283 226 444zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf197;" horiz-adv-x="2176" d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" />
+<glyph unicode="&#xf198;" horiz-adv-x="1664" d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" />
+<glyph unicode="&#xf199;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 q-46 32 -141.5 92.5t-142.5 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" />
+<glyph unicode="&#xf19a;" horiz-adv-x="1792" d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 t273 -182.5t331.5 -68z" />
+<glyph unicode="&#xf19b;" horiz-adv-x="1792" d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" />
+<glyph unicode="&#xf19c;" horiz-adv-x="2048" d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" />
+<glyph unicode="&#xf19d;" horiz-adv-x="2304" d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" />
+<glyph unicode="&#xf19e;" d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q43 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" />
+<glyph unicode="&#xf1a0;" d="M768 750h725q12 -67 12 -128q0 -217 -91 -387.5t-259.5 -266.5t-386.5 -96q-157 0 -299 60.5t-245 163.5t-163.5 245t-60.5 299t60.5 299t163.5 245t245 163.5t299 60.5q300 0 515 -201l-209 -201q-123 119 -306 119q-129 0 -238.5 -65t-173.5 -176.5t-64 -243.5 t64 -243.5t173.5 -176.5t238.5 -65q87 0 160 24t120 60t82 82t51.5 87t22.5 78h-436v264z" />
+<glyph unicode="&#xf1a1;" horiz-adv-x="1792" d="M1095 369q16 -16 0 -31q-62 -62 -199 -62t-199 62q-16 15 0 31q6 6 15 6t15 -6q48 -49 169 -49q120 0 169 49q6 6 15 6t15 -6zM788 550q0 -37 -26 -63t-63 -26t-63.5 26t-26.5 63q0 38 26.5 64t63.5 26t63 -26.5t26 -63.5zM1183 550q0 -37 -26.5 -63t-63.5 -26t-63 26 t-26 63t26 63.5t63 26.5t63.5 -26t26.5 -64zM1434 670q0 49 -35 84t-85 35t-86 -36q-130 90 -311 96l63 283l200 -45q0 -37 26 -63t63 -26t63.5 26.5t26.5 63.5t-26.5 63.5t-63.5 26.5q-54 0 -80 -50l-221 49q-19 5 -25 -16l-69 -312q-180 -7 -309 -97q-35 37 -87 37 q-50 0 -85 -35t-35 -84q0 -35 18.5 -64t49.5 -44q-6 -27 -6 -56q0 -142 140 -243t337 -101q198 0 338 101t140 243q0 32 -7 57q30 15 48 43.5t18 63.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191 t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf1a2;" d="M939 407q13 -13 0 -26q-53 -53 -171 -53t-171 53q-13 13 0 26q5 6 13 6t13 -6q42 -42 145 -42t145 42q5 6 13 6t13 -6zM676 563q0 -31 -23 -54t-54 -23t-54 23t-23 54q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1014 563q0 -31 -23 -54t-54 -23t-54 23t-23 54 q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1229 666q0 42 -30 72t-73 30q-42 0 -73 -31q-113 78 -267 82l54 243l171 -39q1 -32 23.5 -54t53.5 -22q32 0 54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5q-48 0 -69 -43l-189 42q-17 5 -21 -13l-60 -268q-154 -6 -265 -83 q-30 32 -74 32q-43 0 -73 -30t-30 -72q0 -30 16 -55t42 -38q-5 -25 -5 -48q0 -122 120 -208.5t289 -86.5q170 0 290 86.5t120 208.5q0 25 -6 49q25 13 40.5 37.5t15.5 54.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1a3;" d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103 t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1a4;" horiz-adv-x="1920" d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" />
+<glyph unicode="&#xf1a5;" d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf1a6;" horiz-adv-x="2048" d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 v-369h123z" />
+<glyph unicode="&#xf1a7;" d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1a8;" horiz-adv-x="2038" d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" />
+<glyph unicode="&#xf1a9;" d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" />
+<glyph unicode="&#xf1aa;" d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 t135.5 51q85 0 145 -60.5t60 -145.5z" />
+<glyph unicode="&#xf1ab;" d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q106 35 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 q20 0 20 -21v-418z" />
+<glyph unicode="&#xf1ac;" horiz-adv-x="1792" d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" />
+<glyph unicode="&#xf1ad;" d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" />
+<glyph unicode="&#xf1ae;" horiz-adv-x="1280" d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68t68 28t68 -28l228 -228h368l228 228q28 28 68 28t68 -28t28 -68t-28 -68zM864 1152q0 -93 -65.5 -158.5 t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1b0;" horiz-adv-x="1664" d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 t100.5 134t141.5 55.5z" />
+<glyph unicode="&#xf1b1;" horiz-adv-x="768" d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" />
+<glyph unicode="&#xf1b2;" horiz-adv-x="1792" d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z " />
+<glyph unicode="&#xf1b3;" horiz-adv-x="2304" d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-5 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 v-400l434 -186q36 -16 57 -48t21 -70z" />
+<glyph unicode="&#xf1b4;" horiz-adv-x="2048" d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" />
+<glyph unicode="&#xf1b5;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" />
+<glyph unicode="&#xf1b6;" horiz-adv-x="1792" d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" />
+<glyph unicode="&#xf1b7;" d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z " />
+<glyph unicode="&#xf1b8;" horiz-adv-x="1792" d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" />
+<glyph unicode="&#xf1b9;" horiz-adv-x="2048" d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1ba;" horiz-adv-x="2048" d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" />
+<glyph unicode="&#xf1bb;" d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" />
+<glyph unicode="&#xf1bc;" d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1bd;" horiz-adv-x="1024" d="M1024 1233l-303 -582l24 -31h279v-415h-507l-44 -30l-142 -273l-30 -30h-301v303l303 583l-24 30h-279v415h507l44 30l142 273l30 30h301v-303z" />
+<glyph unicode="&#xf1be;" horiz-adv-x="2304" d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236q0 -11 -8 -19 t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786q-13 2 -22 11t-9 22v899 q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" />
+<glyph unicode="&#xf1c0;" d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 t-103 128v128q0 69 103 128t280 93.5t385 34.5z" />
+<glyph unicode="&#xf1c1;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 q-1 1 -1 2t-0.5 1.5t-0.5 1.5q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" />
+<glyph unicode="&#xf1c2;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4l-3 21q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5t-3.5 -21.5l-4 -21h-4l-2 21 q-2 26 -7 46l-99 438h90v107h-300z" />
+<glyph unicode="&#xf1c3;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 h-290v-107h68l189 -272l-194 -283h-68z" />
+<glyph unicode="&#xf1c4;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" />
+<glyph unicode="&#xf1c5;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" />
+<glyph unicode="&#xf1c6;" d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" />
+<glyph unicode="&#xf1c7;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" />
+<glyph unicode="&#xf1c8;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" />
+<glyph unicode="&#xf1c9;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" />
+<glyph unicode="&#xf1ca;" d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" />
+<glyph unicode="&#xf1cb;" horiz-adv-x="1792" d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" />
+<glyph unicode="&#xf1cc;" horiz-adv-x="2048" d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97q14 -16 29.5 -34t34.5 -40t29 -34q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5 t-85 -189.5z" />
+<glyph unicode="&#xf1cd;" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" />
+<glyph unicode="&#xf1ce;" horiz-adv-x="1792" d="M1760 640q0 -176 -68.5 -336t-184 -275.5t-275.5 -184t-336 -68.5t-336 68.5t-275.5 184t-184 275.5t-68.5 336q0 213 97 398.5t265 305.5t374 151v-228q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5 t136.5 204t51 248.5q0 230 -145.5 406t-366.5 221v228q206 -31 374 -151t265 -305.5t97 -398.5z" />
+<glyph unicode="&#xf1d0;" horiz-adv-x="1792" d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" />
+<glyph unicode="&#xf1d1;" horiz-adv-x="1792" d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf1d2;" d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d3;" horiz-adv-x="1792" d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" />
+<glyph unicode="&#xf1d4;" d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d5;" horiz-adv-x="1280" d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" />
+<glyph unicode="&#xf1d6;" horiz-adv-x="1792" d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" />
+<glyph unicode="&#xf1d7;" horiz-adv-x="2048" d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" />
+<glyph unicode="&#xf1d8;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" />
+<glyph unicode="&#xf1d9;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 l863 639l-478 -797z" />
+<glyph unicode="&#xf1da;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23 t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1db;" d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1dc;" horiz-adv-x="1792" d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 q0 -26 -12 -48t-36 -22z" />
+<glyph unicode="&#xf1dd;" horiz-adv-x="1280" d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" />
+<glyph unicode="&#xf1de;" d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" />
+<glyph unicode="&#xf1e0;" d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" />
+<glyph unicode="&#xf1e1;" d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1e2;" horiz-adv-x="1792" d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf1e3;" horiz-adv-x="1792" d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" />
+<glyph unicode="&#xf1e4;" horiz-adv-x="1792" d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" />
+<glyph unicode="&#xf1e5;" horiz-adv-x="1792" d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1e6;" horiz-adv-x="1792" d="M1755 1083q37 -37 37 -90t-37 -91l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234l401 400 q38 37 91 37t90 -37z" />
+<glyph unicode="&#xf1e7;" horiz-adv-x="1792" d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q3 -2 11 -7 t11 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" />
+<glyph unicode="&#xf1e8;" horiz-adv-x="1792" d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" />
+<glyph unicode="&#xf1e9;" d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q70 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" />
+<glyph unicode="&#xf1ea;" horiz-adv-x="2048" d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" />
+<glyph unicode="&#xf1eb;" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
+<glyph unicode="&#xf1ec;" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1ed;" d="M1519 890q18 -84 -4 -204q-87 -444 -565 -444h-44q-25 0 -44 -16.5t-24 -42.5l-4 -19l-55 -346l-2 -15q-5 -26 -24.5 -42.5t-44.5 -16.5h-251q-21 0 -33 15t-9 36q9 56 26.5 168t26.5 168t27 167.5t27 167.5q5 37 43 37h131q133 -2 236 21q175 39 287 144q102 95 155 246 q24 70 35 133q1 6 2.5 7.5t3.5 1t6 -3.5q79 -59 98 -162zM1347 1172q0 -107 -46 -236q-80 -233 -302 -315q-113 -40 -252 -42q0 -1 -90 -1l-90 1q-100 0 -118 -96q-2 -8 -85 -530q-1 -10 -12 -10h-295q-22 0 -36.5 16.5t-11.5 38.5l232 1471q5 29 27.5 48t51.5 19h598 q34 0 97.5 -13t111.5 -32q107 -41 163.5 -123t56.5 -196z" />
+<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M441 864q32 0 52 -26q266 -364 362 -774h-446q-127 441 -367 749q-12 16 -3 33.5t29 17.5h373zM1000 507q-49 -199 -125 -393q-79 310 -256 594q40 221 44 449q211 -340 337 -650zM1099 1216q235 -324 384.5 -698.5t184.5 -773.5h-451q-41 665 -553 1472h435zM1792 640 q0 -424 -101 -812q-67 560 -359 1083q-25 301 -106 584q-4 16 5.5 28.5t25.5 12.5h359q21 0 38.5 -13t22.5 -33q115 -409 115 -850z" />
+<glyph unicode="&#xf1f0;" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f1;" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39 26 60.5t73 21.5q14 0 23 -1q0 3 0.5 5.5t1 4.5t0.5 3 q0 20 -36 20q-29 0 -59 -10q0 4 7 48q38 11 67 11q74 0 74 -62zM889 721l-8 -49q-22 3 -41 3q-27 0 -27 -17q0 -8 4.5 -12t21.5 -11q40 -19 40 -60q0 -72 -87 -71q-34 0 -58 6q0 2 7 49q29 -8 51 -8q32 0 32 19q0 7 -4.5 11.5t-21.5 12.5q-43 20 -43 59q0 72 84 72 q30 0 50 -4zM977 721h28l-7 -52h-29q-2 -17 -6.5 -40.5t-7 -38.5t-2.5 -18q0 -16 19 -16q8 0 16 2l-8 -47q-21 -7 -40 -7q-43 0 -45 47q0 12 8 56q3 20 25 146h55zM1180 648q0 -23 -7 -52h-111q-3 -22 10 -33t38 -11q30 0 58 14l-9 -54q-30 -8 -57 -8q-95 0 -95 95 q0 55 27.5 90.5t69.5 35.5q35 0 55.5 -21t20.5 -56zM1319 722q-13 -23 -22 -62q-22 2 -31 -24t-25 -128h-56l3 14q22 130 29 199h51l-3 -33q14 21 25.5 29.5t28.5 4.5zM1506 763l-9 -57q-28 14 -50 14q-31 0 -51 -27.5t-20 -70.5q0 -30 13.5 -47t38.5 -17q21 0 48 13 l-10 -59q-28 -8 -50 -8q-45 0 -71.5 30.5t-26.5 82.5q0 70 35.5 114.5t91.5 44.5q26 0 61 -13zM1668 663q0 -18 -4 -42q-13 -79 -17 -113h-46l1 22q-20 -26 -59 -26q-23 0 -37 16t-14 42q0 39 25.5 60.5t72.5 21.5q15 0 23 -1q2 7 2 13q0 20 -36 20q-29 0 -59 -10q0 4 8 48 q38 11 67 11q73 0 73 -62zM1809 722q-14 -24 -21 -62q-23 2 -31.5 -23t-25.5 -129h-56l3 14q19 104 29 199h52q0 -11 -4 -33q15 21 26.5 29.5t27.5 4.5zM1950 770h56l-43 -262h-53l3 19q-23 -23 -52 -23q-31 0 -49.5 24t-18.5 64q0 53 27.5 92t64.5 39q31 0 53 -29z M2061 640q0 148 -72.5 273t-198 198t-273.5 73q-181 0 -328 -110q127 -116 171 -284h-50q-44 150 -158 253q-114 -103 -158 -253h-50q44 168 171 284q-147 110 -328 110q-148 0 -273.5 -73t-198 -198t-72.5 -273t72.5 -273t198 -198t273.5 -73q181 0 328 110 q-120 111 -165 264h50q46 -138 152 -233q106 95 152 233h50q-45 -153 -165 -264q147 -110 328 -110q148 0 273.5 73t198 198t72.5 273zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f2;" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
+<glyph unicode="&#xf1f3;" horiz-adv-x="2304" d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" />
+<glyph unicode="&#xf1f4;" horiz-adv-x="2304" d="M745 630q0 -37 -25.5 -61.5t-62.5 -24.5q-29 0 -46.5 16t-17.5 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM1530 779q0 -42 -22 -57t-66 -15l-32 -1l17 107q2 11 13 11h18q22 0 35 -2t25 -12.5t12 -30.5zM1881 630q0 -36 -25.5 -61t-61.5 -25q-29 0 -47 16 t-18 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM513 801q0 59 -38.5 85.5t-100.5 26.5h-160q-19 0 -21 -19l-65 -408q-1 -6 3 -11t10 -5h76q20 0 22 19l18 110q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM822 489l41 261q1 6 -3 11t-10 5h-76 q-14 0 -17 -33q-27 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q28 0 58 12t48 32q-4 -12 -4 -21q0 -16 13 -16h69q19 0 22 19zM1269 752q0 5 -4 9.5t-9 4.5h-77q-11 0 -18 -10l-106 -156l-44 150q-5 16 -22 16h-75q-5 0 -9 -4.5t-4 -9.5q0 -2 19.5 -59 t42 -123t23.5 -70q-82 -112 -82 -120q0 -13 13 -13h77q11 0 18 10l255 368q2 2 2 7zM1649 801q0 59 -38.5 85.5t-100.5 26.5h-159q-20 0 -22 -19l-65 -408q-1 -6 3 -11t10 -5h82q12 0 16 13l18 116q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM1958 489 l41 261q1 6 -3 11t-10 5h-76q-14 0 -17 -33q-26 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q29 0 59 12t47 32q0 -1 -2 -9t-2 -12q0 -16 13 -16h69q19 0 22 19zM2176 898v1q0 14 -13 14h-74q-11 0 -13 -11l-65 -416l-1 -2q0 -5 4 -9.5t10 -4.5h66 q19 0 21 19zM392 764q-5 -35 -26 -46t-60 -11l-33 -1l17 107q2 11 13 11h19q40 0 58 -11.5t12 -48.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f5;" horiz-adv-x="2304" d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f6;" horiz-adv-x="2048" d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f7;" horiz-adv-x="2048" d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f8;" horiz-adv-x="1408" d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1f9;" d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1fa;" d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" />
+<glyph unicode="&#xf1fb;" horiz-adv-x="1792" d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" />
+<glyph unicode="&#xf1fc;" horiz-adv-x="1792" d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" />
+<glyph unicode="&#xf1fd;" horiz-adv-x="1792" d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11t55.5 -11t52.5 -38q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5t47 37.5 q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-35 0 -55.5 11t-52.5 38q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38t-58 27 t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448h256v448 h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51 t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" />
+<glyph unicode="&#xf1fe;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" />
+<glyph unicode="&#xf200;" horiz-adv-x="1792" d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf201;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf202;" horiz-adv-x="1792" d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" />
+<glyph unicode="&#xf203;" d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf204;" horiz-adv-x="2048" d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" />
+<glyph unicode="&#xf205;" horiz-adv-x="2048" d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" />
+<glyph unicode="&#xf206;" horiz-adv-x="2304" d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf207;" d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" />
+<glyph unicode="&#xf208;" horiz-adv-x="2048" d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" />
+<glyph unicode="&#xf209;" horiz-adv-x="1280" d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q18 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" />
+<glyph unicode="&#xf20a;" horiz-adv-x="2048" d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" />
+<glyph unicode="&#xf20b;" d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf20c;" d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" />
+<glyph unicode="&#xf20d;" d="M915 450h-294l147 551zM1001 128h311l-324 1024h-440l-324 -1024h311l383 314zM1536 1120v-960q0 -118 -85 -203t-203 -85h-960q-118 0 -203 85t-85 203v960q0 118 85 203t203 85h960q118 0 203 -85t85 -203z" />
+<glyph unicode="&#xf20e;" horiz-adv-x="2048" d="M2048 641q0 -21 -13 -36.5t-33 -19.5l-205 -356q3 -9 3 -18q0 -20 -12.5 -35.5t-32.5 -19.5l-193 -337q3 -8 3 -16q0 -23 -16.5 -40t-40.5 -17q-25 0 -41 18h-400q-17 -20 -43 -20t-43 20h-399q-17 -20 -43 -20q-23 0 -40 16.5t-17 40.5q0 8 4 20l-193 335 q-20 4 -32.5 19.5t-12.5 35.5q0 9 3 18l-206 356q-20 5 -32.5 20.5t-12.5 35.5q0 21 13.5 36.5t33.5 19.5l199 344q0 1 -0.5 3t-0.5 3q0 36 34 51l209 363q-4 10 -4 18q0 24 17 40.5t40 16.5q26 0 44 -21h396q16 21 43 21t43 -21h398q18 21 44 21q23 0 40 -16.5t17 -40.5 q0 -6 -4 -18l207 -358q23 -1 39 -17.5t16 -38.5q0 -13 -7 -27l187 -324q19 -4 31.5 -19.5t12.5 -35.5zM1063 -158h389l-342 354h-143l-342 -354h360q18 16 39 16t39 -16zM112 654q1 -4 1 -13q0 -10 -2 -15l208 -360q2 0 4.5 -1t5.5 -2.5l5 -2.5l188 199v347l-187 194 q-13 -8 -29 -10zM986 1438h-388l190 -200l554 200h-280q-16 -16 -38 -16t-38 16zM1689 226q1 6 5 11l-64 68l-17 -79h76zM1583 226l22 105l-252 266l-296 -307l63 -64h463zM1495 -142l16 28l65 310h-427l333 -343q8 4 13 5zM578 -158h5l342 354h-373v-335l4 -6q14 -5 22 -13 zM552 226h402l64 66l-309 321l-157 -166v-221zM359 226h163v189l-168 -177q4 -8 5 -12zM358 1051q0 -1 0.5 -2t0.5 -2q0 -16 -8 -29l171 -177v269zM552 1121v-311l153 -157l297 314l-223 236zM556 1425l-4 -8v-264l205 74l-191 201q-6 -2 -10 -3zM1447 1438h-16l-621 -224 l213 -225zM1023 946l-297 -315l311 -319l296 307zM688 634l-136 141v-284zM1038 270l-42 -44h85zM1374 618l238 -251l132 624l-3 5l-1 1zM1718 1018q-8 13 -8 29v2l-216 376q-5 1 -13 5l-437 -463l310 -327zM522 1142v223l-163 -282zM522 196h-163l163 -283v283zM1607 196 l-48 -227l130 227h-82zM1729 266l207 361q-2 10 -2 14q0 1 3 16l-171 296l-129 -612l77 -82q5 3 15 7z" />
+<glyph unicode="&#xf210;" d="M0 856q0 131 91.5 226.5t222.5 95.5h742l352 358v-1470q0 -132 -91.5 -227t-222.5 -95h-780q-131 0 -222.5 95t-91.5 227v790zM1232 102l-176 180v425q0 46 -32 79t-78 33h-484q-46 0 -78 -33t-32 -79v-492q0 -46 32.5 -79.5t77.5 -33.5h770z" />
+<glyph unicode="&#xf211;" d="M934 1386q-317 -121 -556 -362.5t-358 -560.5q-20 89 -20 176q0 208 102.5 384.5t278.5 279t384 102.5q82 0 169 -19zM1203 1267q93 -65 164 -155q-389 -113 -674.5 -400.5t-396.5 -676.5q-93 72 -155 162q112 386 395 671t667 399zM470 -67q115 356 379.5 622t619.5 384 q40 -92 54 -195q-292 -120 -516 -345t-343 -518q-103 14 -194 52zM1536 -125q-193 50 -367 115q-135 -84 -290 -107q109 205 274 370.5t369 275.5q-21 -152 -101 -284q65 -175 115 -370z" />
+<glyph unicode="&#xf212;" horiz-adv-x="2048" d="M1893 1144l155 -1272q-131 0 -257 57q-200 91 -393 91q-226 0 -374 -148q-148 148 -374 148q-193 0 -393 -91q-128 -57 -252 -57h-5l155 1272q224 127 482 127q233 0 387 -106q154 106 387 106q258 0 482 -127zM1398 157q129 0 232 -28.5t260 -93.5l-124 1021 q-171 78 -368 78q-224 0 -374 -141q-150 141 -374 141q-197 0 -368 -78l-124 -1021q105 43 165.5 65t148.5 39.5t178 17.5q202 0 374 -108q172 108 374 108zM1438 191l-55 907q-211 -4 -359 -155q-152 155 -374 155q-176 0 -336 -66l-114 -941q124 51 228.5 76t221.5 25 q209 0 374 -102q172 107 374 102z" />
+<glyph unicode="&#xf213;" horiz-adv-x="2048" d="M1500 165v733q0 21 -15 36t-35 15h-93q-20 0 -35 -15t-15 -36v-733q0 -20 15 -35t35 -15h93q20 0 35 15t15 35zM1216 165v531q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-531q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM924 165v429q0 20 -15 35t-35 15h-101 q-20 0 -35 -15t-15 -35v-429q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM632 165v362q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-362q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM2048 311q0 -166 -118 -284t-284 -118h-1244q-166 0 -284 118t-118 284 q0 116 63 214.5t168 148.5q-10 34 -10 73q0 113 80.5 193.5t193.5 80.5q102 0 180 -67q45 183 194 300t338 117q149 0 275 -73.5t199.5 -199.5t73.5 -275q0 -66 -14 -122q135 -33 221 -142.5t86 -247.5z" />
+<glyph unicode="&#xf214;" d="M0 1536h1536v-1392l-776 -338l-760 338v1392zM1436 209v926h-1336v-926l661 -294zM1436 1235v201h-1336v-201h1336zM181 937v-115h-37v115h37zM181 789v-115h-37v115h37zM181 641v-115h-37v115h37zM181 493v-115h-37v115h37zM181 345v-115h-37v115h37zM207 202l15 34 l105 -47l-15 -33zM343 142l15 34l105 -46l-15 -34zM478 82l15 34l105 -46l-15 -34zM614 23l15 33l104 -46l-15 -34zM797 10l105 46l15 -33l-105 -47zM932 70l105 46l15 -34l-105 -46zM1068 130l105 46l15 -34l-105 -46zM1203 189l105 47l15 -34l-105 -46zM259 1389v-36h-114 v36h114zM421 1389v-36h-115v36h115zM583 1389v-36h-115v36h115zM744 1389v-36h-114v36h114zM906 1389v-36h-114v36h114zM1068 1389v-36h-115v36h115zM1230 1389v-36h-115v36h115zM1391 1389v-36h-114v36h114zM181 1049v-79h-37v115h115v-36h-78zM421 1085v-36h-115v36h115z M583 1085v-36h-115v36h115zM744 1085v-36h-114v36h114zM906 1085v-36h-114v36h114zM1068 1085v-36h-115v36h115zM1230 1085v-36h-115v36h115zM1355 970v79h-78v36h115v-115h-37zM1355 822v115h37v-115h-37zM1355 674v115h37v-115h-37zM1355 526v115h37v-115h-37zM1355 378 v115h37v-115h-37zM1355 230v115h37v-115h-37zM760 265q-129 0 -221 91.5t-92 221.5q0 129 92 221t221 92q130 0 221.5 -92t91.5 -221q0 -130 -91.5 -221.5t-221.5 -91.5zM595 646q0 -36 19.5 -56.5t49.5 -25t64 -7t64 -2t49.5 -9t19.5 -30.5q0 -49 -112 -49q-97 0 -123 51 h-3l-31 -63q67 -42 162 -42q29 0 56.5 5t55.5 16t45.5 33t17.5 53q0 46 -27.5 69.5t-67.5 27t-79.5 3t-67 5t-27.5 25.5q0 21 20.5 33t40.5 15t41 3q34 0 70.5 -11t51.5 -34h3l30 58q-3 1 -21 8.5t-22.5 9t-19.5 7t-22 7t-20 4.5t-24 4t-23 1q-29 0 -56.5 -5t-54 -16.5 t-43 -34t-16.5 -53.5z" />
+<glyph unicode="&#xf215;" horiz-adv-x="2048" d="M863 504q0 112 -79.5 191.5t-191.5 79.5t-191 -79.5t-79 -191.5t79 -191t191 -79t191.5 79t79.5 191zM1726 505q0 112 -79 191t-191 79t-191.5 -79t-79.5 -191q0 -113 79.5 -192t191.5 -79t191 79.5t79 191.5zM2048 1314v-1348q0 -44 -31.5 -75.5t-76.5 -31.5h-1832 q-45 0 -76.5 31.5t-31.5 75.5v1348q0 44 31.5 75.5t76.5 31.5h431q44 0 76 -31.5t32 -75.5v-161h754v161q0 44 32 75.5t76 31.5h431q45 0 76.5 -31.5t31.5 -75.5z" />
+<glyph unicode="&#xf216;" horiz-adv-x="2048" d="M1430 953zM1690 749q148 0 253 -98.5t105 -244.5q0 -157 -109 -261.5t-267 -104.5q-85 0 -162 27.5t-138 73.5t-118 106t-109 126.5t-103.5 132.5t-108.5 126t-117 106t-136 73.5t-159 27.5q-154 0 -251.5 -91.5t-97.5 -244.5q0 -157 104 -250t263 -93q100 0 208 37.5 t193 98.5q5 4 21 18.5t30 24t22 9.5q14 0 24.5 -10.5t10.5 -24.5q0 -24 -60 -77q-101 -88 -234.5 -142t-260.5 -54q-133 0 -245.5 58t-180 165t-67.5 241q0 205 141.5 341t347.5 136q120 0 226.5 -43.5t185.5 -113t151.5 -153t139 -167.5t133.5 -153.5t149.5 -113 t172.5 -43.5q102 0 168.5 61.5t66.5 162.5q0 95 -64.5 159t-159.5 64q-30 0 -81.5 -18.5t-68.5 -18.5q-20 0 -35.5 15t-15.5 35q0 18 8.5 57t8.5 59q0 159 -107.5 263t-266.5 104q-58 0 -111.5 -18.5t-84 -40.5t-55.5 -40.5t-33 -18.5q-15 0 -25.5 10.5t-10.5 25.5 q0 19 25 46q59 67 147 103.5t182 36.5q191 0 318 -125.5t127 -315.5q0 -37 -4 -66q57 15 115 15z" />
+<glyph unicode="&#xf217;" horiz-adv-x="1664" d="M1216 832q0 26 -19 45t-45 19h-128v128q0 26 -19 45t-45 19t-45 -19t-19 -45v-128h-128q-26 0 -45 -19t-19 -45t19 -45t45 -19h128v-128q0 -26 19 -45t45 -19t45 19t19 45v128h128q26 0 45 19t19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf218;" horiz-adv-x="1664" d="M1280 832q0 26 -19 45t-45 19t-45 -19l-147 -146v293q0 26 -19 45t-45 19t-45 -19t-19 -45v-293l-147 146q-19 19 -45 19t-45 -19t-19 -45t19 -45l256 -256q19 -19 45 -19t45 19l256 256q19 19 19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf219;" horiz-adv-x="2048" d="M212 768l623 -665l-300 665h-323zM1024 -4l349 772h-698zM538 896l204 384h-262l-288 -384h346zM1213 103l623 665h-323zM683 896h682l-204 384h-274zM1510 896h346l-288 384h-262zM1651 1382l384 -512q14 -18 13 -41.5t-17 -40.5l-960 -1024q-18 -20 -47 -20t-47 20 l-960 1024q-16 17 -17 40.5t13 41.5l384 512q18 26 51 26h1152q33 0 51 -26z" />
+<glyph unicode="&#xf21a;" horiz-adv-x="2048" d="M1811 -19q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83 q19 19 45 19t45 -19l83 -83zM237 19q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -82l83 82q19 19 45 19t45 -19l83 -82l64 64v293l-210 314q-17 26 -7 56.5t40 40.5l177 58v299h128v128h256v128h256v-128h256v-128h128v-299l177 -58q30 -10 40 -40.5t-7 -56.5l-210 -314 v-293l19 18q19 19 45 19t45 -19l83 -82l83 82q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83zM640 1152v-128l384 128l384 -128v128h-128v128h-512v-128h-128z" />
+<glyph unicode="&#xf21b;" d="M576 0l96 448l-96 128l-128 64zM832 0l128 640l-128 -64l-96 -128zM992 1010q-2 4 -4 6q-10 8 -96 8q-70 0 -167 -19q-7 -2 -21 -2t-21 2q-97 19 -167 19q-86 0 -96 -8q-2 -2 -4 -6q2 -18 4 -27q2 -3 7.5 -6.5t7.5 -10.5q2 -4 7.5 -20.5t7 -20.5t7.5 -17t8.5 -17t9 -14 t12 -13.5t14 -9.5t17.5 -8t20.5 -4t24.5 -2q36 0 59 12.5t32.5 30t14.5 34.5t11.5 29.5t17.5 12.5h12q11 0 17.5 -12.5t11.5 -29.5t14.5 -34.5t32.5 -30t59 -12.5q13 0 24.5 2t20.5 4t17.5 8t14 9.5t12 13.5t9 14t8.5 17t7.5 17t7 20.5t7.5 20.5q2 7 7.5 10.5t7.5 6.5 q2 9 4 27zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 61 4.5 118t19 125.5t37.5 123.5t63.5 103.5t93.5 74.5l-90 220h214q-22 64 -22 128q0 12 2 32q-194 40 -194 96q0 57 210 99q17 62 51.5 134t70.5 114q32 37 76 37q30 0 84 -31t84 -31t84 31 t84 31q44 0 76 -37q36 -42 70.5 -114t51.5 -134q210 -42 210 -99q0 -56 -194 -96q7 -81 -20 -160h214l-82 -225q63 -33 107.5 -96.5t65.5 -143.5t29 -151.5t8 -148.5z" />
+<glyph unicode="&#xf21c;" horiz-adv-x="2304" d="M2301 500q12 -103 -22 -198.5t-99 -163.5t-158.5 -106t-196.5 -31q-161 11 -279.5 125t-134.5 274q-12 111 27.5 210.5t118.5 170.5l-71 107q-96 -80 -151 -194t-55 -244q0 -27 -18.5 -46.5t-45.5 -19.5h-256h-69q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5 t-131.5 316.5t131.5 316.5t316.5 131.5q76 0 152 -27l24 45q-123 110 -304 110h-64q-26 0 -45 19t-19 45t19 45t45 19h128q78 0 145 -13.5t116.5 -38.5t71.5 -39.5t51 -36.5h512h115l-85 128h-222q-30 0 -49 22.5t-14 52.5q4 23 23 38t43 15h253q33 0 53 -28l70 -105 l114 114q19 19 46 19h101q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-179l115 -172q131 63 275 36q143 -26 244 -134.5t118 -253.5zM448 128q115 0 203 72.5t111 183.5h-314q-35 0 -55 31q-18 32 -1 63l147 277q-47 13 -91 13q-132 0 -226 -94t-94 -226t94 -226 t226 -94zM1856 128q132 0 226 94t94 226t-94 226t-226 94q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94z" />
+<glyph unicode="&#xf21d;" d="M1408 0q0 -63 -61.5 -113.5t-164 -81t-225 -46t-253.5 -15.5t-253.5 15.5t-225 46t-164 81t-61.5 113.5q0 49 33 88.5t91 66.5t118 44.5t131 29.5q26 5 48 -10.5t26 -41.5q5 -26 -10.5 -48t-41.5 -26q-58 -10 -106 -23.5t-76.5 -25.5t-48.5 -23.5t-27.5 -19.5t-8.5 -12 q3 -11 27 -26.5t73 -33t114 -32.5t160.5 -25t201.5 -10t201.5 10t160.5 25t114 33t73 33.5t27 27.5q-1 4 -8.5 11t-27.5 19t-48.5 23.5t-76.5 25t-106 23.5q-26 4 -41.5 26t-10.5 48q4 26 26 41.5t48 10.5q71 -12 131 -29.5t118 -44.5t91 -66.5t33 -88.5zM1024 896v-384 q0 -26 -19 -45t-45 -19h-64v-384q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v384h-64q-26 0 -45 19t-19 45v384q0 53 37.5 90.5t90.5 37.5h384q53 0 90.5 -37.5t37.5 -90.5zM928 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5 t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf21e;" horiz-adv-x="1792" d="M1280 512h305q-5 -6 -10 -10.5t-9 -7.5l-3 -4l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-5 2 -21 20h369q22 0 39.5 13.5t22.5 34.5l70 281l190 -667q6 -20 23 -33t39 -13q21 0 38 13t23 33l146 485l56 -112q18 -35 57 -35zM1792 940q0 -145 -103 -300h-369l-111 221 q-8 17 -25.5 27t-36.5 8q-45 -5 -56 -46l-129 -430l-196 686q-6 20 -23.5 33t-39.5 13t-39 -13.5t-22 -34.5l-116 -464h-423q-103 155 -103 300q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124 t127 -344z" />
+<glyph unicode="&#xf221;" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292 q11 134 80.5 249t182 188t245.5 88q170 19 319 -54t236 -212t87 -306zM128 960q0 -185 131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5z" />
+<glyph unicode="&#xf222;" d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-382 -383q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5 q203 0 359 -126l382 382h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf223;" horiz-adv-x="1280" d="M830 1220q145 -72 233.5 -210.5t88.5 -305.5q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5 t-147.5 384.5q0 167 88.5 305.5t233.5 210.5q-165 96 -228 273q-6 16 3.5 29.5t26.5 13.5h69q21 0 29 -20q44 -106 140 -171t214 -65t214 65t140 171q8 20 37 20h61q17 0 26.5 -13.5t3.5 -29.5q-63 -177 -228 -273zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf224;" d="M1024 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-149 16 -270.5 103t-186.5 223.5t-53 291.5q16 204 160 353.5t347 172.5q118 14 228 -19t198 -103l255 254h-134q-14 0 -23 9t-9 23v64zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf225;" horiz-adv-x="1792" d="M1280 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5t-147.5 384.5q0 201 126 359l-52 53l-101 -111q-9 -10 -22 -10.5t-23 7.5l-48 44q-10 8 -10.5 21.5t8.5 23.5l105 115l-111 112v-134q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9 t-9 23v288q0 26 19 45t45 19h288q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-133l106 -107l86 94q9 10 22 10.5t23 -7.5l48 -44q10 -8 10.5 -21.5t-8.5 -23.5l-90 -99l57 -56q158 126 359 126t359 -126l255 254h-134q-14 0 -23 9t-9 23v64zM832 256q185 0 316.5 131.5 t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf226;" horiz-adv-x="1792" d="M1790 1007q12 -155 -52.5 -292t-186 -224t-271.5 -103v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-512v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23 t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292q17 206 164.5 356.5t352.5 169.5q206 21 377 -94q171 115 377 94q205 -19 352.5 -169.5t164.5 -356.5zM896 647q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM576 512q115 0 218 57q-154 165 -154 391 q0 224 154 391q-103 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5zM1152 128v260q-137 15 -256 94q-119 -79 -256 -94v-260h512zM1216 512q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5q-115 0 -218 -57q154 -167 154 -391 q0 -226 -154 -391q103 -57 218 -57z" />
+<glyph unicode="&#xf227;" horiz-adv-x="1920" d="M1536 1120q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-31 -182 -166 -312t-318 -156q-210 -29 -384.5 80t-241.5 300q-117 6 -221 57.5t-177.5 133t-113.5 192.5t-32 230 q9 135 78 252t182 191.5t248 89.5q118 14 227.5 -19t198.5 -103l255 254h-134q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q59 -74 93 -169q182 -9 328 -124l255 254h-134q-14 0 -23 9 t-9 23v64zM1024 704q0 20 -4 58q-162 -25 -271 -150t-109 -292q0 -20 4 -58q162 25 271 150t109 292zM128 704q0 -168 111 -294t276 -149q-3 29 -3 59q0 210 135 369.5t338 196.5q-53 120 -163.5 193t-245.5 73q-185 0 -316.5 -131.5t-131.5 -316.5zM1088 -128 q185 0 316.5 131.5t131.5 316.5q0 168 -111 294t-276 149q3 -29 3 -59q0 -210 -135 -369.5t-338 -196.5q53 -120 163.5 -193t245.5 -73z" />
+<glyph unicode="&#xf228;" horiz-adv-x="2048" d="M1664 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-32 -180 -164.5 -310t-313.5 -157q-223 -34 -409 90q-117 -78 -256 -93v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23 t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-155 17 -279.5 109.5t-187 237.5t-39.5 307q25 187 159.5 322.5t320.5 164.5q224 34 410 -90q146 97 320 97q201 0 359 -126l255 254h-134q-14 0 -23 9 t-9 23v64zM896 391q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM128 704q0 -185 131.5 -316.5t316.5 -131.5q117 0 218 57q-154 167 -154 391t154 391q-101 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5zM1216 256q185 0 316.5 131.5t131.5 316.5 t-131.5 316.5t-316.5 131.5q-117 0 -218 -57q154 -167 154 -391t-154 -391q101 -57 218 -57z" />
+<glyph unicode="&#xf229;" d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-213 -214l140 -140q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-140 141l-78 -79q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5 t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5q203 0 359 -126l78 78l-172 172q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l172 -172l213 213h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf22a;" horiz-adv-x="1280" d="M640 892q217 -24 364.5 -187.5t147.5 -384.5q0 -167 -87 -306t-236 -212t-319 -54q-133 15 -245.5 88t-182 188t-80.5 249q-12 155 52.5 292t186 224t271.5 103v132h-160q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h160v165l-92 -92q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22 t9 23l202 201q19 19 45 19t45 -19l202 -201q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-92 92v-165h160q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-160v-132zM576 -128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5 t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf22b;" horiz-adv-x="2048" d="M1901 621q19 -19 19 -45t-19 -45l-294 -294q-9 -10 -22.5 -10t-22.5 10l-45 45q-10 9 -10 22.5t10 22.5l185 185h-294v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-132q-24 -217 -187.5 -364.5t-384.5 -147.5q-167 0 -306 87t-212 236t-54 319q15 133 88 245.5 t188 182t249 80.5q155 12 292 -52.5t224 -186t103 -271.5h132v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h294l-185 185q-10 9 -10 22.5t10 22.5l45 45q9 10 22.5 10t22.5 -10zM576 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5 t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf22c;" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-612q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v612q-217 24 -364.5 187.5t-147.5 384.5q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM576 512q185 0 316.5 131.5 t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf22d;" horiz-adv-x="1280" d="M1024 576q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1152 576q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123 t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5z" />
+<glyph unicode="&#xf22e;" horiz-adv-x="1792" />
+<glyph unicode="&#xf22f;" horiz-adv-x="1792" />
+<glyph unicode="&#xf230;" d="M1451 1408q35 0 60 -25t25 -60v-1366q0 -35 -25 -60t-60 -25h-391v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-735q-35 0 -60 25t-25 60v1366q0 35 25 60t60 25h1366z" />
+<glyph unicode="&#xf231;" horiz-adv-x="1280" d="M0 939q0 108 37.5 203.5t103.5 166.5t152 123t185 78t202 26q158 0 294 -66.5t221 -193.5t85 -287q0 -96 -19 -188t-60 -177t-100 -149.5t-145 -103t-189 -38.5q-68 0 -135 32t-96 88q-10 -39 -28 -112.5t-23.5 -95t-20.5 -71t-26 -71t-32 -62.5t-46 -77.5t-62 -86.5 l-14 -5l-9 10q-15 157 -15 188q0 92 21.5 206.5t66.5 287.5t52 203q-32 65 -32 169q0 83 52 156t132 73q61 0 95 -40.5t34 -102.5q0 -66 -44 -191t-44 -187q0 -63 45 -104.5t109 -41.5q55 0 102 25t78.5 68t56 95t38 110.5t20 111t6.5 99.5q0 173 -109.5 269.5t-285.5 96.5 q-200 0 -334 -129.5t-134 -328.5q0 -44 12.5 -85t27 -65t27 -45.5t12.5 -30.5q0 -28 -15 -73t-37 -45q-2 0 -17 3q-51 15 -90.5 56t-61 94.5t-32.5 108t-11 106.5z" />
+<glyph unicode="&#xf232;" d="M985 562q13 0 97.5 -44t89.5 -53q2 -5 2 -15q0 -33 -17 -76q-16 -39 -71 -65.5t-102 -26.5q-57 0 -190 62q-98 45 -170 118t-148 185q-72 107 -71 194v8q3 91 74 158q24 22 52 22q6 0 18 -1.5t19 -1.5q19 0 26.5 -6.5t15.5 -27.5q8 -20 33 -88t25 -75q0 -21 -34.5 -57.5 t-34.5 -46.5q0 -7 5 -15q34 -73 102 -137q56 -53 151 -101q12 -7 22 -7q15 0 54 48.5t52 48.5zM782 32q127 0 243.5 50t200.5 134t134 200.5t50 243.5t-50 243.5t-134 200.5t-200.5 134t-243.5 50t-243.5 -50t-200.5 -134t-134 -200.5t-50 -243.5q0 -203 120 -368l-79 -233 l242 77q158 -104 345 -104zM782 1414q153 0 292.5 -60t240.5 -161t161 -240.5t60 -292.5t-60 -292.5t-161 -240.5t-240.5 -161t-292.5 -60q-195 0 -365 94l-417 -134l136 405q-108 178 -108 389q0 153 60 292.5t161 240.5t240.5 161t292.5 60z" />
+<glyph unicode="&#xf233;" horiz-adv-x="1792" d="M128 128h1024v128h-1024v-128zM128 640h1024v128h-1024v-128zM1696 192q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM128 1152h1024v128h-1024v-128zM1696 704q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1696 1216 q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1792 384v-384h-1792v384h1792zM1792 896v-384h-1792v384h1792zM1792 1408v-384h-1792v384h1792z" />
+<glyph unicode="&#xf234;" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1664 512h352q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-352q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5 t-9.5 22.5v352h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v352q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5v-352zM928 288q0 -52 38 -90t90 -38h256v-238q-68 -50 -171 -50h-874q-121 0 -194 69t-73 190q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q79 -61 154.5 -91.5t164.5 -30.5t164.5 30.5t154.5 91.5q20 17 39 17q132 0 217 -96h-223q-52 0 -90 -38t-38 -90v-192z" />
+<glyph unicode="&#xf235;" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1781 320l249 -249q9 -9 9 -23q0 -13 -9 -22l-136 -136q-9 -9 -22 -9q-14 0 -23 9l-249 249l-249 -249q-9 -9 -23 -9q-13 0 -22 9l-136 136 q-9 9 -9 22q0 14 9 23l249 249l-249 249q-9 9 -9 23q0 13 9 22l136 136q9 9 22 9q14 0 23 -9l249 -249l249 249q9 9 23 9q13 0 22 -9l136 -136q9 -9 9 -22q0 -14 -9 -23zM1283 320l-181 -181q-37 -37 -37 -91q0 -53 37 -90l83 -83q-21 -3 -44 -3h-874q-121 0 -194 69 t-73 190q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q154 -122 319 -122t319 122q20 17 39 17q28 0 57 -6q-28 -27 -41 -50t-13 -56q0 -54 37 -91z" />
+<glyph unicode="&#xf236;" horiz-adv-x="2048" d="M256 512h1728q26 0 45 -19t19 -45v-448h-256v256h-1536v-256h-256v1216q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-704zM832 832q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM2048 576v64q0 159 -112.5 271.5t-271.5 112.5h-704 q-26 0 -45 -19t-19 -45v-384h1152z" />
+<glyph unicode="&#xf237;" d="M1536 1536l-192 -448h192v-192h-274l-55 -128h329v-192h-411l-357 -832l-357 832h-411v192h329l-55 128h-274v192h192l-192 448h256l323 -768h378l323 768h256zM768 320l108 256h-216z" />
+<glyph unicode="&#xf238;" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM768 192q80 0 136 56t56 136t-56 136t-136 56 t-136 -56t-56 -136t56 -136t136 -56zM1344 768v512h-1152v-512h1152z" />
+<glyph unicode="&#xf239;" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM288 224q66 0 113 47t47 113t-47 113t-113 47 t-113 -47t-47 -113t47 -113t113 -47zM704 768v512h-544v-512h544zM1248 224q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM1408 768v512h-576v-512h576z" />
+<glyph unicode="&#xf23a;" horiz-adv-x="1792" d="M597 1115v-1173q0 -25 -12.5 -42.5t-36.5 -17.5q-17 0 -33 8l-465 233q-21 10 -35.5 33.5t-14.5 46.5v1140q0 20 10 34t29 14q14 0 44 -15l511 -256q3 -3 3 -5zM661 1014l534 -866l-534 266v600zM1792 996v-1054q0 -25 -14 -40.5t-38 -15.5t-47 13l-441 220zM1789 1116 q0 -3 -256.5 -419.5t-300.5 -487.5l-390 634l324 527q17 28 52 28q14 0 26 -6l541 -270q4 -2 4 -6z" />
+<glyph unicode="&#xf23b;" d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1408v-1536h-1536v1536h1536z" />
+<glyph unicode="&#xf23c;" horiz-adv-x="2296" d="M478 -139q-8 -16 -27 -34.5t-37 -25.5q-25 -9 -51.5 3.5t-28.5 31.5q-1 22 40 55t68 38q23 4 34 -21.5t2 -46.5zM1819 -139q7 -16 26 -34.5t38 -25.5q25 -9 51.5 3.5t27.5 31.5q2 22 -39.5 55t-68.5 38q-22 4 -33 -21.5t-2 -46.5zM1867 -30q13 -27 56.5 -59.5t77.5 -41.5 q45 -13 82 4.5t37 50.5q0 46 -67.5 100.5t-115.5 59.5q-40 5 -63.5 -37.5t-6.5 -76.5zM428 -30q-13 -27 -56 -59.5t-77 -41.5q-45 -13 -82 4.5t-37 50.5q0 46 67.5 100.5t115.5 59.5q40 5 63 -37.5t6 -76.5zM1158 1094h1q-41 0 -76 -15q27 -8 44 -30.5t17 -49.5 q0 -35 -27 -60t-65 -25q-52 0 -80 43q-5 -23 -5 -42q0 -74 56 -126.5t135 -52.5q80 0 136 52.5t56 126.5t-56 126.5t-136 52.5zM1462 1312q-99 109 -220.5 131.5t-245.5 -44.5q27 60 82.5 96.5t118 39.5t121.5 -17t99.5 -74.5t44.5 -131.5zM2212 73q8 -11 -11 -42 q7 -23 7 -40q1 -56 -44.5 -112.5t-109.5 -91.5t-118 -37q-48 -2 -92 21.5t-66 65.5q-687 -25 -1259 0q-23 -41 -66.5 -65t-92.5 -22q-86 3 -179.5 80.5t-92.5 160.5q2 22 7 40q-19 31 -11 42q6 10 31 1q14 22 41 51q-7 29 2 38q11 10 39 -4q29 20 59 34q0 29 13 37 q23 12 51 -16q35 5 61 -2q18 -4 38 -19v73q-11 0 -18 2q-53 10 -97 44.5t-55 87.5q-9 38 0 81q15 62 93 95q2 17 19 35.5t36 23.5t33 -7.5t19 -30.5h13q46 -5 60 -23q3 -3 5 -7q10 1 30.5 3.5t30.5 3.5q-15 11 -30 17q-23 40 -91 43q0 6 1 10q-62 2 -118.5 18.5t-84.5 47.5 q-32 36 -42.5 92t-2.5 112q16 126 90 179q23 16 52 4.5t32 -40.5q0 -1 1.5 -14t2.5 -21t3 -20t5.5 -19t8.5 -10q27 -14 76 -12q48 46 98 74q-40 4 -162 -14l47 46q61 58 163 111q145 73 282 86q-20 8 -41 15.5t-47 14t-42.5 10.5t-47.5 11t-43 10q595 126 904 -139 q98 -84 158 -222q85 -10 121 9h1q5 3 8.5 10t5.5 19t3 19.5t3 21.5l1 14q3 28 32 40t52 -5q73 -52 91 -178q7 -57 -3.5 -113t-42.5 -91q-28 -32 -83.5 -48.5t-115.5 -18.5v-10q-71 -2 -95 -43q-14 -5 -31 -17q11 -1 32 -3.5t30 -3.5q1 4 5 8q16 18 60 23h13q5 18 19 30t33 8 t36 -23t19 -36q79 -32 93 -95q9 -40 1 -81q-12 -53 -56 -88t-97 -44q-10 -2 -17 -2q0 -49 -1 -73q20 15 38 19q26 7 61 2q28 28 51 16q14 -9 14 -37q33 -16 59 -34q27 13 38 4q10 -10 2 -38q28 -30 41 -51q23 8 31 -1zM1937 1025q0 -29 -9 -54q82 -32 112 -132 q4 37 -9.5 98.5t-41.5 90.5q-20 19 -36 17t-16 -20zM1859 925q35 -42 47.5 -108.5t-0.5 -124.5q67 13 97 45q13 14 18 28q-3 64 -31 114.5t-79 66.5q-15 -15 -52 -21zM1822 921q-30 0 -44 1q42 -115 53 -239q21 0 43 3q16 68 1 135t-53 100zM258 839q30 100 112 132 q-9 25 -9 54q0 18 -16.5 20t-35.5 -17q-28 -29 -41.5 -90.5t-9.5 -98.5zM294 737q29 -31 97 -45q-13 58 -0.5 124.5t47.5 108.5v0q-37 6 -52 21q-51 -16 -78.5 -66t-31.5 -115q9 -17 18 -28zM471 683q14 124 73 235q-19 -4 -55 -18l-45 -19v1q-46 -89 -20 -196q25 -3 47 -3z M1434 644q8 -38 16.5 -108.5t11.5 -89.5q3 -18 9.5 -21.5t23.5 4.5q40 20 62 85.5t23 125.5q-24 2 -146 4zM1152 1285q-116 0 -199 -82.5t-83 -198.5q0 -117 83 -199.5t199 -82.5t199 82.5t83 199.5q0 116 -83 198.5t-199 82.5zM1380 646q-106 2 -211 0v1q-1 -27 2.5 -86 t13.5 -66q29 -14 93.5 -14.5t95.5 10.5q9 3 11 39t-0.5 69.5t-4.5 46.5zM1112 447q8 4 9.5 48t-0.5 88t-4 63v1q-212 -3 -214 -3q-4 -20 -7 -62t0 -83t14 -46q34 -15 101 -16t101 10zM718 636q-16 -59 4.5 -118.5t77.5 -84.5q15 -8 24 -5t12 21q3 16 8 90t10 103 q-69 -2 -136 -6zM591 510q3 -23 -34 -36q132 -141 271.5 -240t305.5 -154q172 49 310.5 146t293.5 250q-33 13 -30 34l3 9v1v-1q-17 2 -50 5.5t-48 4.5q-26 -90 -82 -132q-51 -38 -82 1q-5 6 -9 14q-7 13 -17 62q-2 -5 -5 -9t-7.5 -7t-8 -5.5t-9.5 -4l-10 -2.5t-12 -2 l-12 -1.5t-13.5 -1t-13.5 -0.5q-106 -9 -163 11q-4 -17 -10 -26.5t-21 -15t-23 -7t-36 -3.5q-2 0 -3 -0.5t-3 -0.5h-3q-179 -17 -203 40q-2 -63 -56 -54q-47 8 -91 54q-12 13 -20 26q-17 29 -26 65q-58 -6 -87 -10q1 -2 4 -10zM507 -118q3 14 3 30q-17 71 -51 130t-73 70 q-41 12 -101.5 -14.5t-104.5 -80t-39 -107.5q35 -53 100 -93t119 -42q51 -2 94 28t53 79zM510 53q23 -63 27 -119q195 113 392 174q-98 52 -180.5 120t-179.5 165q-6 -4 -29 -13q0 -2 -1 -5t-1 -4q31 -18 22 -37q-12 -23 -56 -34q-10 -13 -29 -24h-1q-2 -83 1 -150 q19 -34 35 -73zM579 -113q532 -21 1145 0q-254 147 -428 196q-76 -35 -156 -57q-8 -3 -16 0q-65 21 -129 49q-208 -60 -416 -188h-1v-1q1 0 1 1zM1763 -67q4 54 28 120q14 38 33 71l-1 -1q3 77 3 153q-15 8 -30 25q-42 9 -56 33q-9 20 22 38q-2 4 -2 9q-16 4 -28 12 q-204 -190 -383 -284q198 -59 414 -176zM2155 -90q5 54 -39 107.5t-104 80t-102 14.5q-38 -11 -72.5 -70.5t-51.5 -129.5q0 -16 3 -30q10 -49 53 -79t94 -28q54 2 119 42t100 93z" />
+<glyph unicode="&#xf23d;" horiz-adv-x="2304" d="M1524 -25q0 -68 -48 -116t-116 -48t-116.5 48t-48.5 116t48.5 116.5t116.5 48.5t116 -48.5t48 -116.5zM775 -25q0 -68 -48.5 -116t-116.5 -48t-116 48t-48 116t48 116.5t116 48.5t116.5 -48.5t48.5 -116.5zM0 1469q57 -60 110.5 -104.5t121 -82t136 -63t166 -45.5 t200 -31.5t250 -18.5t304 -9.5t372.5 -2.5q139 0 244.5 -5t181 -16.5t124 -27.5t71 -39.5t24 -51.5t-19.5 -64t-56.5 -76.5t-89.5 -91t-116 -104.5t-139 -119q-185 -157 -286 -247q29 51 76.5 109t94 105.5t94.5 98.5t83 91.5t54 80.5t13 70t-45.5 55.5t-116.5 41t-204 23.5 t-304 5q-168 -2 -314 6t-256 23t-204.5 41t-159.5 51.5t-122.5 62.5t-91.5 66.5t-68 71.5t-50.5 69.5t-40 68t-36.5 59.5z" />
+<glyph unicode="&#xf23e;" horiz-adv-x="1792" d="M896 1472q-169 0 -323 -66t-265.5 -177.5t-177.5 -265.5t-66 -323t66 -323t177.5 -265.5t265.5 -177.5t323 -66t323 66t265.5 177.5t177.5 265.5t66 323t-66 323t-177.5 265.5t-265.5 177.5t-323 66zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348 t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM496 704q16 0 16 -16v-480q0 -16 -16 -16h-32q-16 0 -16 16v480q0 16 16 16h32zM896 640q53 0 90.5 -37.5t37.5 -90.5q0 -35 -17.5 -64t-46.5 -46v-114q0 -14 -9 -23 t-23 -9h-64q-14 0 -23 9t-9 23v114q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5zM896 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM544 928v-96 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 93 65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5v-96q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 146 -103 249t-249 103t-249 -103t-103 -249zM1408 192v512q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-512 q0 -26 19 -45t45 -19h896q26 0 45 19t19 45z" />
+<glyph unicode="&#xf240;" horiz-adv-x="2304" d="M1920 1024v-768h-1664v768h1664zM2048 448h128v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288zM2304 832v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113 v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf241;" horiz-adv-x="2304" d="M256 256v768h1280v-768h-1280zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
+<glyph unicode="&#xf242;" horiz-adv-x="2304" d="M256 256v768h896v-768h-896zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
+<glyph unicode="&#xf243;" horiz-adv-x="2304" d="M256 256v768h512v-768h-512zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
+<glyph unicode="&#xf244;" horiz-adv-x="2304" d="M2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23 v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
+<glyph unicode="&#xf245;" horiz-adv-x="1280" d="M1133 493q31 -30 14 -69q-17 -40 -59 -40h-382l201 -476q10 -25 0 -49t-34 -35l-177 -75q-25 -10 -49 0t-35 34l-191 452l-312 -312q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v1504q0 42 40 59q12 5 24 5q27 0 45 -19z" />
+<glyph unicode="&#xf246;" horiz-adv-x="1024" d="M832 1408q-320 0 -320 -224v-416h128v-128h-128v-544q0 -224 320 -224h64v-128h-64q-272 0 -384 146q-112 -146 -384 -146h-64v128h64q320 0 320 224v544h-128v128h128v416q0 224 -320 224h-64v128h64q272 0 384 -146q112 146 384 146h64v-128h-64z" />
+<glyph unicode="&#xf247;" horiz-adv-x="2048" d="M2048 1152h-128v-1024h128v-384h-384v128h-1280v-128h-384v384h128v1024h-128v384h384v-128h1280v128h384v-384zM1792 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 -128v128h-128v-128h128zM1664 0v128h128v1024h-128v128h-1280v-128h-128v-1024h128v-128 h1280zM1920 -128v128h-128v-128h128zM1280 896h384v-768h-896v256h-384v768h896v-256zM512 512h640v512h-640v-512zM1536 256v512h-256v-384h-384v-128h640z" />
+<glyph unicode="&#xf248;" horiz-adv-x="2304" d="M2304 768h-128v-640h128v-384h-384v128h-896v-128h-384v384h128v128h-384v-128h-384v384h128v640h-128v384h384v-128h896v128h384v-384h-128v-128h384v128h384v-384zM2048 1024v-128h128v128h-128zM1408 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 256 v128h-128v-128h128zM1536 384h-128v-128h128v128zM384 384h896v128h128v640h-128v128h-896v-128h-128v-640h128v-128zM896 -128v128h-128v-128h128zM2176 -128v128h-128v-128h128zM2048 128v640h-128v128h-384v-384h128v-384h-384v128h-384v-128h128v-128h896v128h128z" />
+<glyph unicode="&#xf249;" d="M1024 288v-416h-928q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68v-928h-416q-40 0 -68 -28t-28 -68zM1152 256h381q-15 -82 -65 -132l-184 -184q-50 -50 -132 -65v381z" />
+<glyph unicode="&#xf24a;" d="M1400 256h-248v-248q29 10 41 22l185 185q12 12 22 41zM1120 384h288v896h-1280v-1280h896v288q0 40 28 68t68 28zM1536 1312v-1024q0 -40 -20 -88t-48 -76l-184 -184q-28 -28 -76 -48t-88 -20h-1024q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68 z" />
+<glyph unicode="&#xf24b;" horiz-adv-x="2304" d="M1951 538q0 -26 -15.5 -44.5t-38.5 -23.5q-8 -2 -18 -2h-153v140h153q10 0 18 -2q23 -5 38.5 -23.5t15.5 -44.5zM1933 751q0 -25 -15 -42t-38 -21q-3 -1 -15 -1h-139v129h139q3 0 8.5 -0.5t6.5 -0.5q23 -4 38 -21.5t15 -42.5zM728 587v308h-228v-308q0 -58 -38 -94.5 t-105 -36.5q-108 0 -229 59v-112q53 -15 121 -23t109 -9l42 -1q328 0 328 217zM1442 403v113q-99 -52 -200 -59q-108 -8 -169 41t-61 142t61 142t169 41q101 -7 200 -58v112q-48 12 -100 19.5t-80 9.5l-28 2q-127 6 -218.5 -14t-140.5 -60t-71 -88t-22 -106t22 -106t71 -88 t140.5 -60t218.5 -14q101 4 208 31zM2176 518q0 54 -43 88.5t-109 39.5v3q57 8 89 41.5t32 79.5q0 55 -41 88t-107 36q-3 0 -12 0.5t-14 0.5h-455v-510h491q74 0 121.5 36.5t47.5 96.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90 t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf24c;" horiz-adv-x="2304" d="M858 295v693q-106 -41 -172 -135.5t-66 -211.5t66 -211.5t172 -134.5zM1362 641q0 117 -66 211.5t-172 135.5v-694q106 41 172 135.5t66 211.5zM1577 641q0 -159 -78.5 -294t-213.5 -213.5t-294 -78.5q-119 0 -227.5 46.5t-187 125t-125 187t-46.5 227.5q0 159 78.5 294 t213.5 213.5t294 78.5t294 -78.5t213.5 -213.5t78.5 -294zM1960 634q0 139 -55.5 261.5t-147.5 205.5t-213.5 131t-252.5 48h-301q-176 0 -323.5 -81t-235 -230t-87.5 -335q0 -171 87 -317.5t236 -231.5t323 -85h301q129 0 251.5 50.5t214.5 135t147.5 202.5t55.5 246z M2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf24d;" horiz-adv-x="1792" d="M1664 -96v1088q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5zM1792 992v-1088q0 -66 -47 -113t-113 -47h-1088q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113 zM1408 1376v-160h-128v160q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h160v-128h-160q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf24e;" horiz-adv-x="2304" d="M1728 1088l-384 -704h768zM448 1088l-384 -704h768zM1269 1280q-14 -40 -45.5 -71.5t-71.5 -45.5v-1291h608q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1344q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h608v1291q-40 14 -71.5 45.5t-45.5 71.5h-491q-14 0 -23 9t-9 23v64 q0 14 9 23t23 9h491q21 57 70 92.5t111 35.5t111 -35.5t70 -92.5h491q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-491zM1088 1264q33 0 56.5 23.5t23.5 56.5t-23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5zM2176 384q0 -73 -46.5 -131t-117.5 -91 t-144.5 -49.5t-139.5 -16.5t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81zM896 384q0 -73 -46.5 -131t-117.5 -91t-144.5 -49.5t-139.5 -16.5 t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81z" />
+<glyph unicode="&#xf250;" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-77 -29 -149 -92.5 t-129.5 -152.5t-92.5 -210t-35 -253h1024q0 132 -35 253t-92.5 210t-129.5 152.5t-149 92.5q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" />
+<glyph unicode="&#xf251;" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -66 9 -128h1006q9 61 9 128zM1280 -128q0 130 -34 249.5t-90.5 208t-126.5 152t-146 94.5h-230q-76 -31 -146 -94.5t-126.5 -152t-90.5 -208t-34 -249.5h1024z" />
+<glyph unicode="&#xf252;" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -206 85 -384h854q85 178 85 384zM1223 192q-54 141 -145.5 241.5t-194.5 142.5h-230q-103 -42 -194.5 -142.5t-145.5 -241.5h910z" />
+<glyph unicode="&#xf253;" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-137 -51 -244 -196 h700q-107 145 -244 196q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" />
+<glyph unicode="&#xf254;" d="M1504 -64q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472zM130 0q3 55 16 107t30 95t46 87t53.5 76t64.5 69.5t66 60t70.5 55t66.5 47.5t65 43q-43 28 -65 43t-66.5 47.5t-70.5 55t-66 60t-64.5 69.5t-53.5 76t-46 87 t-30 95t-16 107h1276q-3 -55 -16 -107t-30 -95t-46 -87t-53.5 -76t-64.5 -69.5t-66 -60t-70.5 -55t-66.5 -47.5t-65 -43q43 -28 65 -43t66.5 -47.5t70.5 -55t66 -60t64.5 -69.5t53.5 -76t46 -87t30 -95t16 -107h-1276zM1504 1536q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9 h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472z" />
+<glyph unicode="&#xf255;" d="M768 1152q-53 0 -90.5 -37.5t-37.5 -90.5v-128h-32v93q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-429l-32 30v172q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-224q0 -47 35 -82l310 -296q39 -39 39 -102q0 -26 19 -45t45 -19h640q26 0 45 19t19 45v25 q0 41 10 77l108 436q10 36 10 77v246q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-32h-32v125q0 40 -25 72.5t-64 40.5q-14 2 -23 2q-46 0 -79 -33t-33 -79v-128h-32v122q0 51 -32.5 89.5t-82.5 43.5q-5 1 -13 1zM768 1280q84 0 149 -50q57 34 123 34q59 0 111 -27 t86 -76q27 7 59 7q100 0 170 -71.5t70 -171.5v-246q0 -51 -13 -108l-109 -436q-6 -24 -6 -71q0 -80 -56 -136t-136 -56h-640q-84 0 -138 58.5t-54 142.5l-308 296q-76 73 -76 175v224q0 99 70.5 169.5t169.5 70.5q11 0 16 -1q6 95 75.5 160t164.5 65q52 0 98 -21 q72 69 174 69z" />
+<glyph unicode="&#xf256;" horiz-adv-x="1792" d="M880 1408q-46 0 -79 -33t-33 -79v-656h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528v-256l-154 205q-38 51 -102 51q-53 0 -90.5 -37.5t-37.5 -90.5q0 -43 26 -77l384 -512q38 -51 102 -51h688q34 0 61 22t34 56l76 405q5 32 5 59v498q0 46 -33 79t-79 33t-79 -33 t-33 -79v-272h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528h-32v656q0 46 -33 79t-79 33zM880 1536q68 0 125.5 -35.5t88.5 -96.5q19 4 42 4q99 0 169.5 -70.5t70.5 -169.5v-17q105 6 180.5 -64t75.5 -175v-498q0 -40 -8 -83l-76 -404q-14 -79 -76.5 -131t-143.5 -52 h-688q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 106 75 181t181 75q78 0 128 -34v434q0 99 70.5 169.5t169.5 70.5q23 0 42 -4q31 61 88.5 96.5t125.5 35.5z" />
+<glyph unicode="&#xf257;" horiz-adv-x="1792" d="M1073 -128h-177q-163 0 -226 141q-23 49 -23 102v5q-62 30 -98.5 88.5t-36.5 127.5q0 38 5 48h-261q-106 0 -181 75t-75 181t75 181t181 75h113l-44 17q-74 28 -119.5 93.5t-45.5 145.5q0 106 75 181t181 75q46 0 91 -17l628 -239h401q106 0 181 -75t75 -181v-668 q0 -88 -54 -157.5t-140 -90.5l-339 -85q-92 -23 -186 -23zM1024 583l-155 -71l-163 -74q-30 -14 -48 -41.5t-18 -60.5q0 -46 33 -79t79 -33q26 0 46 10l338 154q-49 10 -80.5 50t-31.5 90v55zM1344 272q0 46 -33 79t-79 33q-26 0 -46 -10l-290 -132q-28 -13 -37 -17 t-30.5 -17t-29.5 -23.5t-16 -29t-8 -40.5q0 -50 31.5 -82t81.5 -32q20 0 38 9l352 160q30 14 48 41.5t18 60.5zM1112 1024l-650 248q-24 8 -46 8q-53 0 -90.5 -37.5t-37.5 -90.5q0 -40 22.5 -73t59.5 -47l526 -200v-64h-640q-53 0 -90.5 -37.5t-37.5 -90.5t37.5 -90.5 t90.5 -37.5h535l233 106v198q0 63 46 106l111 102h-69zM1073 0q82 0 155 19l339 85q43 11 70 45.5t27 78.5v668q0 53 -37.5 90.5t-90.5 37.5h-308l-136 -126q-36 -33 -36 -82v-296q0 -46 33 -77t79 -31t79 35t33 81v208h32v-208q0 -70 -57 -114q52 -8 86.5 -48.5t34.5 -93.5 q0 -42 -23 -78t-61 -53l-310 -141h91z" />
+<glyph unicode="&#xf258;" horiz-adv-x="2048" d="M1151 1536q61 0 116 -28t91 -77l572 -781q118 -159 118 -359v-355q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v177l-286 143h-546q-80 0 -136 56t-56 136v32q0 119 84.5 203.5t203.5 84.5h420l42 128h-686q-100 0 -173.5 67.5t-81.5 166.5q-65 79 -65 182v32 q0 80 56 136t136 56h959zM1920 -64v355q0 157 -93 284l-573 781q-39 52 -103 52h-959q-26 0 -45 -19t-19 -45q0 -32 1.5 -49.5t9.5 -40.5t25 -43q10 31 35.5 50t56.5 19h832v-32h-832q-26 0 -45 -19t-19 -45q0 -44 3 -58q8 -44 44 -73t81 -29h640h91q40 0 68 -28t28 -68 q0 -15 -5 -30l-64 -192q-10 -29 -35 -47.5t-56 -18.5h-443q-66 0 -113 -47t-47 -113v-32q0 -26 19 -45t45 -19h561q16 0 29 -7l317 -158q24 -13 38.5 -36t14.5 -50v-197q0 -26 19 -45t45 -19h384q26 0 45 19t19 45z" />
+<glyph unicode="&#xf259;" horiz-adv-x="2048" d="M816 1408q-48 0 -79.5 -34t-31.5 -82q0 -14 3 -28l150 -624h-26l-116 482q-9 38 -39.5 62t-69.5 24q-47 0 -79 -34t-32 -81q0 -11 4 -29q3 -13 39 -161t68 -282t32 -138v-227l-307 230q-34 26 -77 26q-52 0 -89.5 -36.5t-37.5 -88.5q0 -67 56 -110l507 -379 q34 -26 76 -26h694q33 0 59 20.5t34 52.5l100 401q8 30 10 88t9 86l116 478q3 12 3 26q0 46 -33 79t-80 33q-38 0 -69 -25.5t-40 -62.5l-99 -408h-26l132 547q3 14 3 28q0 47 -32 80t-80 33q-38 0 -68.5 -24t-39.5 -62l-145 -602h-127l-164 682q-9 38 -39.5 62t-68.5 24z M1461 -256h-694q-85 0 -153 51l-507 380q-50 38 -78.5 94t-28.5 118q0 105 75 179t180 74q25 0 49.5 -5.5t41.5 -11t41 -20.5t35 -23t38.5 -29.5t37.5 -28.5l-123 512q-7 35 -7 59q0 93 60 162t152 79q14 87 80.5 144.5t155.5 57.5q83 0 148 -51.5t85 -132.5l103 -428 l83 348q20 81 85 132.5t148 51.5q87 0 152.5 -54t82.5 -139q93 -10 155 -78t62 -161q0 -30 -7 -57l-116 -477q-5 -22 -5 -67q0 -51 -13 -108l-101 -401q-19 -75 -79.5 -122.5t-137.5 -47.5z" />
+<glyph unicode="&#xf25a;" horiz-adv-x="1792" d="M640 1408q-53 0 -90.5 -37.5t-37.5 -90.5v-512v-384l-151 202q-41 54 -107 54q-52 0 -89 -38t-37 -90q0 -43 26 -77l384 -512q38 -51 102 -51h718q22 0 39.5 13.5t22.5 34.5l92 368q24 96 24 194v217q0 41 -28 71t-68 30t-68 -28t-28 -68h-32v61q0 48 -32 81.5t-80 33.5 q-46 0 -79 -33t-33 -79v-64h-32v90q0 55 -37 94.5t-91 39.5q-53 0 -90.5 -37.5t-37.5 -90.5v-96h-32v570q0 55 -37 94.5t-91 39.5zM640 1536q107 0 181.5 -77.5t74.5 -184.5v-220q22 2 32 2q99 0 173 -69q47 21 99 21q113 0 184 -87q27 7 56 7q94 0 159 -67.5t65 -161.5 v-217q0 -116 -28 -225l-92 -368q-16 -64 -68 -104.5t-118 -40.5h-718q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 105 74.5 180.5t179.5 75.5q71 0 130 -35v547q0 106 75 181t181 75zM768 128v384h-32v-384h32zM1024 128v384h-32v-384h32zM1280 128v384h-32 v-384h32z" />
+<glyph unicode="&#xf25b;" d="M1288 889q60 0 107 -23q141 -63 141 -226v-177q0 -94 -23 -186l-85 -339q-21 -86 -90.5 -140t-157.5 -54h-668q-106 0 -181 75t-75 181v401l-239 628q-17 45 -17 91q0 106 75 181t181 75q80 0 145.5 -45.5t93.5 -119.5l17 -44v113q0 106 75 181t181 75t181 -75t75 -181 v-261q27 5 48 5q69 0 127.5 -36.5t88.5 -98.5zM1072 896q-33 0 -60.5 -18t-41.5 -48l-74 -163l-71 -155h55q50 0 90 -31.5t50 -80.5l154 338q10 20 10 46q0 46 -33 79t-79 33zM1293 761q-22 0 -40.5 -8t-29 -16t-23.5 -29.5t-17 -30.5t-17 -37l-132 -290q-10 -20 -10 -46 q0 -46 33 -79t79 -33q33 0 60.5 18t41.5 48l160 352q9 18 9 38q0 50 -32 81.5t-82 31.5zM128 1120q0 -22 8 -46l248 -650v-69l102 111q43 46 106 46h198l106 233v535q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5v-640h-64l-200 526q-14 37 -47 59.5t-73 22.5 q-53 0 -90.5 -37.5t-37.5 -90.5zM1180 -128q44 0 78.5 27t45.5 70l85 339q19 73 19 155v91l-141 -310q-17 -38 -53 -61t-78 -23q-53 0 -93.5 34.5t-48.5 86.5q-44 -57 -114 -57h-208v32h208q46 0 81 33t35 79t-31 79t-77 33h-296q-49 0 -82 -36l-126 -136v-308 q0 -53 37.5 -90.5t90.5 -37.5h668z" />
+<glyph unicode="&#xf25c;" horiz-adv-x="1973" d="M857 992v-117q0 -13 -9.5 -22t-22.5 -9h-298v-812q0 -13 -9 -22.5t-22 -9.5h-135q-13 0 -22.5 9t-9.5 23v812h-297q-13 0 -22.5 9t-9.5 22v117q0 14 9 23t23 9h793q13 0 22.5 -9.5t9.5 -22.5zM1895 995l77 -961q1 -13 -8 -24q-10 -10 -23 -10h-134q-12 0 -21 8.5 t-10 20.5l-46 588l-189 -425q-8 -19 -29 -19h-120q-20 0 -29 19l-188 427l-45 -590q-1 -12 -10 -20.5t-21 -8.5h-135q-13 0 -23 10q-9 10 -9 24l78 961q1 12 10 20.5t21 8.5h142q20 0 29 -19l220 -520q10 -24 20 -51q3 7 9.5 24.5t10.5 26.5l221 520q9 19 29 19h141 q13 0 22 -8.5t10 -20.5z" />
+<glyph unicode="&#xf25d;" horiz-adv-x="1792" d="M1042 833q0 88 -60 121q-33 18 -117 18h-123v-281h162q66 0 102 37t36 105zM1094 548l205 -373q8 -17 -1 -31q-8 -16 -27 -16h-152q-20 0 -28 17l-194 365h-155v-350q0 -14 -9 -23t-23 -9h-134q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h294q128 0 190 -24q85 -31 134 -109 t49 -180q0 -92 -42.5 -165.5t-115.5 -109.5q6 -10 9 -16zM896 1376q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM1792 640 q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf25e;" horiz-adv-x="1792" d="M605 303q153 0 257 104q14 18 3 36l-45 82q-6 13 -24 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13t-23.5 -14.5t-28.5 -13.5t-33.5 -9.5t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78 q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-148 0 -246 -96.5t-98 -240.5q0 -146 97 -241.5t247 -95.5zM1235 303q153 0 257 104q14 18 4 36l-45 82q-8 14 -25 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13t-23.5 -14.5t-28.5 -13.5t-33.5 -9.5 t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-147 0 -245.5 -96.5t-98.5 -240.5q0 -146 97 -241.5t247 -95.5zM896 1376 q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191 t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71z" />
+<glyph unicode="&#xf260;" horiz-adv-x="2048" d="M736 736l384 -384l-384 -384l-672 672l672 672l168 -168l-96 -96l-72 72l-480 -480l480 -480l193 193l-289 287zM1312 1312l672 -672l-672 -672l-168 168l96 96l72 -72l480 480l-480 480l-193 -193l289 -287l-96 -96l-384 384z" />
+<glyph unicode="&#xf261;" horiz-adv-x="1792" d="M717 182l271 271l-279 279l-88 -88l192 -191l-96 -96l-279 279l279 279l40 -40l87 87l-127 128l-454 -454zM1075 190l454 454l-454 454l-271 -271l279 -279l88 88l-192 191l96 96l279 -279l-279 -279l-40 40l-87 -88zM1792 640q0 -182 -71 -348t-191 -286t-286 -191 t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf262;" horiz-adv-x="2304" d="M651 539q0 -39 -27.5 -66.5t-65.5 -27.5q-39 0 -66.5 27.5t-27.5 66.5q0 38 27.5 65.5t66.5 27.5q38 0 65.5 -27.5t27.5 -65.5zM1805 540q0 -39 -27.5 -66.5t-66.5 -27.5t-66.5 27.5t-27.5 66.5t27.5 66t66.5 27t66.5 -27t27.5 -66zM765 539q0 79 -56.5 136t-136.5 57 t-136.5 -56.5t-56.5 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM1918 540q0 80 -56.5 136.5t-136.5 56.5q-79 0 -136 -56.5t-57 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM850 539q0 -116 -81.5 -197.5t-196.5 -81.5q-116 0 -197.5 82t-81.5 197 t82 196.5t197 81.5t196.5 -81.5t81.5 -196.5zM2004 540q0 -115 -81.5 -196.5t-197.5 -81.5q-115 0 -196.5 81.5t-81.5 196.5t81.5 196.5t196.5 81.5q116 0 197.5 -81.5t81.5 -196.5zM1040 537q0 191 -135.5 326.5t-326.5 135.5q-125 0 -231 -62t-168 -168.5t-62 -231.5 t62 -231.5t168 -168.5t231 -62q191 0 326.5 135.5t135.5 326.5zM1708 1110q-254 111 -556 111q-319 0 -573 -110q117 0 223 -45.5t182.5 -122.5t122 -183t45.5 -223q0 115 43.5 219.5t118 180.5t177.5 123t217 50zM2187 537q0 191 -135 326.5t-326 135.5t-326.5 -135.5 t-135.5 -326.5t135.5 -326.5t326.5 -135.5t326 135.5t135 326.5zM1921 1103h383q-44 -51 -75 -114.5t-40 -114.5q110 -151 110 -337q0 -156 -77 -288t-209 -208.5t-287 -76.5q-133 0 -249 56t-196 155q-47 -56 -129 -179q-11 22 -53.5 82.5t-74.5 97.5 q-80 -99 -196.5 -155.5t-249.5 -56.5q-155 0 -287 76.5t-209 208.5t-77 288q0 186 110 337q-9 51 -40 114.5t-75 114.5h365q149 100 355 156.5t432 56.5q224 0 421 -56t348 -157z" />
+<glyph unicode="&#xf263;" horiz-adv-x="1280" d="M640 629q-188 0 -321 133t-133 320q0 188 133 321t321 133t321 -133t133 -321q0 -187 -133 -320t-321 -133zM640 1306q-92 0 -157.5 -65.5t-65.5 -158.5q0 -92 65.5 -157.5t157.5 -65.5t157.5 65.5t65.5 157.5q0 93 -65.5 158.5t-157.5 65.5zM1163 574q13 -27 15 -49.5 t-4.5 -40.5t-26.5 -38.5t-42.5 -37t-61.5 -41.5q-115 -73 -315 -94l73 -72l267 -267q30 -31 30 -74t-30 -73l-12 -13q-31 -30 -74 -30t-74 30q-67 68 -267 268l-267 -268q-31 -30 -74 -30t-73 30l-12 13q-31 30 -31 73t31 74l267 267l72 72q-203 21 -317 94 q-39 25 -61.5 41.5t-42.5 37t-26.5 38.5t-4.5 40.5t15 49.5q10 20 28 35t42 22t56 -2t65 -35q5 -4 15 -11t43 -24.5t69 -30.5t92 -24t113 -11q91 0 174 25.5t120 50.5l38 25q33 26 65 35t56 2t42 -22t28 -35z" />
+<glyph unicode="&#xf264;" d="M927 956q0 -66 -46.5 -112.5t-112.5 -46.5t-112.5 46.5t-46.5 112.5t46.5 112.5t112.5 46.5t112.5 -46.5t46.5 -112.5zM1141 593q-10 20 -28 32t-47.5 9.5t-60.5 -27.5q-10 -8 -29 -20t-81 -32t-127 -20t-124 18t-86 36l-27 18q-31 25 -60.5 27.5t-47.5 -9.5t-28 -32 q-22 -45 -2 -74.5t87 -73.5q83 -53 226 -67l-51 -52q-142 -142 -191 -190q-22 -22 -22 -52.5t22 -52.5l9 -9q22 -22 52.5 -22t52.5 22l191 191q114 -115 191 -191q22 -22 52.5 -22t52.5 22l9 9q22 22 22 52.5t-22 52.5l-191 190l-52 52q141 14 225 67q67 44 87 73.5t-2 74.5 zM1092 956q0 134 -95 229t-229 95t-229 -95t-95 -229t95 -229t229 -95t229 95t95 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf265;" horiz-adv-x="1720" d="M1565 1408q65 0 110 -45.5t45 -110.5v-519q0 -176 -68 -336t-182.5 -275t-274 -182.5t-334.5 -67.5q-176 0 -335.5 67.5t-274.5 182.5t-183 275t-68 336v519q0 64 46 110t110 46h1409zM861 344q47 0 82 33l404 388q37 35 37 85q0 49 -34.5 83.5t-83.5 34.5q-47 0 -82 -33 l-323 -310l-323 310q-35 33 -81 33q-49 0 -83.5 -34.5t-34.5 -83.5q0 -51 36 -85l405 -388q33 -33 81 -33z" />
+<glyph unicode="&#xf266;" horiz-adv-x="2304" d="M1494 -103l-295 695q-25 -49 -158.5 -305.5t-198.5 -389.5q-1 -1 -27.5 -0.5t-26.5 1.5q-82 193 -255.5 587t-259.5 596q-21 50 -66.5 107.5t-103.5 100.5t-102 43q0 5 -0.5 24t-0.5 27h583v-50q-39 -2 -79.5 -16t-66.5 -43t-10 -64q26 -59 216.5 -499t235.5 -540 q31 61 140 266.5t131 247.5q-19 39 -126 281t-136 295q-38 69 -201 71v50l513 -1v-47q-60 -2 -93.5 -25t-12.5 -69q33 -70 87 -189.5t86 -187.5q110 214 173 363q24 55 -10 79.5t-129 26.5q1 7 1 25v24q64 0 170.5 0.5t180 1t92.5 0.5v-49q-62 -2 -119 -33t-90 -81 l-213 -442q13 -33 127.5 -290t121.5 -274l441 1017q-14 38 -49.5 62.5t-65 31.5t-55.5 8v50l460 -4l1 -2l-1 -44q-139 -4 -201 -145q-526 -1216 -559 -1291h-49z" />
+<glyph unicode="&#xf267;" horiz-adv-x="1792" d="M949 643q0 -26 -16.5 -45t-41.5 -19q-26 0 -45 16.5t-19 41.5q0 26 17 45t42 19t44 -16.5t19 -41.5zM964 585l350 581q-9 -8 -67.5 -62.5t-125.5 -116.5t-136.5 -127t-117 -110.5t-50.5 -51.5l-349 -580q7 7 67 62t126 116.5t136 127t117 111t50 50.5zM1611 640 q0 -201 -104 -371q-3 2 -17 11t-26.5 16.5t-16.5 7.5q-13 0 -13 -13q0 -10 59 -44q-74 -112 -184.5 -190.5t-241.5 -110.5l-16 67q-1 10 -15 10q-5 0 -8 -5.5t-2 -9.5l16 -68q-72 -15 -146 -15q-199 0 -372 105q1 2 13 20.5t21.5 33.5t9.5 19q0 13 -13 13q-6 0 -17 -14.5 t-22.5 -34.5t-13.5 -23q-113 75 -192 187.5t-110 244.5l69 15q10 3 10 15q0 5 -5.5 8t-10.5 2l-68 -15q-14 72 -14 139q0 206 109 379q2 -1 18.5 -12t30 -19t17.5 -8q13 0 13 12q0 6 -12.5 15.5t-32.5 21.5l-20 12q77 112 189 189t244 107l15 -67q2 -10 15 -10q5 0 8 5.5 t2 10.5l-15 66q71 13 134 13q204 0 379 -109q-39 -56 -39 -65q0 -13 12 -13q11 0 48 64q111 -75 187.5 -186t107.5 -241l-56 -12q-10 -2 -10 -16q0 -5 5.5 -8t9.5 -2l57 13q14 -72 14 -140zM1696 640q0 163 -63.5 311t-170.5 255t-255 170.5t-311 63.5t-311 -63.5 t-255 -170.5t-170.5 -255t-63.5 -311t63.5 -311t170.5 -255t255 -170.5t311 -63.5t311 63.5t255 170.5t170.5 255t63.5 311zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191 t191 -286t71 -348z" />
+<glyph unicode="&#xf268;" horiz-adv-x="1792" d="M893 1536q240 2 451 -120q232 -134 352 -372l-742 39q-160 9 -294 -74.5t-185 -229.5l-276 424q128 159 311 245.5t383 87.5zM146 1131l337 -663q72 -143 211 -217t293 -45l-230 -451q-212 33 -385 157.5t-272.5 316t-99.5 411.5q0 267 146 491zM1732 962 q58 -150 59.5 -310.5t-48.5 -306t-153 -272t-246 -209.5q-230 -133 -498 -119l405 623q88 131 82.5 290.5t-106.5 277.5zM896 942q125 0 213.5 -88.5t88.5 -213.5t-88.5 -213.5t-213.5 -88.5t-213.5 88.5t-88.5 213.5t88.5 213.5t213.5 88.5z" />
+<glyph unicode="&#xf269;" horiz-adv-x="1792" d="M903 -256q-283 0 -504.5 150.5t-329.5 398.5q-58 131 -67 301t26 332.5t111 312t179 242.5l-11 -281q11 14 68 15.5t70 -15.5q42 81 160.5 138t234.5 59q-54 -45 -119.5 -148.5t-58.5 -163.5q25 -8 62.5 -13.5t63 -7.5t68 -4t50.5 -3q15 -5 9.5 -45.5t-30.5 -75.5 q-5 -7 -16.5 -18.5t-56.5 -35.5t-101 -34l15 -189l-139 67q-18 -43 -7.5 -81.5t36 -66.5t65.5 -41.5t81 -6.5q51 9 98 34.5t83.5 45t73.5 17.5q61 -4 89.5 -33t19.5 -65q-1 -2 -2.5 -5.5t-8.5 -12.5t-18 -15.5t-31.5 -10.5t-46.5 -1q-60 -95 -144.5 -135.5t-209.5 -29.5 q74 -61 162.5 -82.5t168.5 -6t154.5 52t128 87.5t80.5 104q43 91 39 192.5t-37.5 188.5t-78.5 125q87 -38 137 -79.5t77 -112.5q15 170 -57.5 343t-209.5 284q265 -77 412 -279.5t151 -517.5q2 -127 -40.5 -255t-123.5 -238t-189 -196t-247.5 -135.5t-288.5 -49.5z" />
+<glyph unicode="&#xf26a;" horiz-adv-x="1792" d="M1493 1308q-165 110 -359 110q-155 0 -293 -73t-240 -200q-75 -93 -119.5 -218t-48.5 -266v-42q4 -141 48.5 -266t119.5 -218q102 -127 240 -200t293 -73q194 0 359 110q-121 -108 -274.5 -168t-322.5 -60q-29 0 -43 1q-175 8 -333 82t-272 193t-181 281t-67 339 q0 182 71 348t191 286t286 191t348 71h3q168 -1 320.5 -60.5t273.5 -167.5zM1792 640q0 -192 -77 -362.5t-213 -296.5q-104 -63 -222 -63q-137 0 -255 84q154 56 253.5 233t99.5 405q0 227 -99 404t-253 234q119 83 254 83q119 0 226 -65q135 -125 210.5 -295t75.5 -361z " />
+<glyph unicode="&#xf26b;" horiz-adv-x="1792" d="M1792 599q0 -56 -7 -104h-1151q0 -146 109.5 -244.5t257.5 -98.5q99 0 185.5 46.5t136.5 130.5h423q-56 -159 -170.5 -281t-267.5 -188.5t-321 -66.5q-187 0 -356 83q-228 -116 -394 -116q-237 0 -237 263q0 115 45 275q17 60 109 229q199 360 475 606 q-184 -79 -427 -354q63 274 283.5 449.5t501.5 175.5q30 0 45 -1q255 117 433 117q64 0 116 -13t94.5 -40.5t66.5 -76.5t24 -115q0 -116 -75 -286q101 -182 101 -390zM1722 1239q0 83 -53 132t-137 49q-108 0 -254 -70q121 -47 222.5 -131.5t170.5 -195.5q51 135 51 216z M128 2q0 -86 48.5 -132.5t134.5 -46.5q115 0 266 83q-122 72 -213.5 183t-137.5 245q-98 -205 -98 -332zM632 715h728q-5 142 -113 237t-251 95q-144 0 -251.5 -95t-112.5 -237z" />
+<glyph unicode="&#xf26c;" horiz-adv-x="2048" d="M1792 288v960q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1248v-960q0 -66 -47 -113t-113 -47h-736v-128h352q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23 v64q0 14 9 23t23 9h352v128h-736q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf26d;" horiz-adv-x="1792" d="M138 1408h197q-70 -64 -126 -149q-36 -56 -59 -115t-30 -125.5t-8.5 -120t10.5 -132t21 -126t28 -136.5q4 -19 6 -28q51 -238 81 -329q57 -171 152 -275h-272q-48 0 -82 34t-34 82v1304q0 48 34 82t82 34zM1346 1408h308q48 0 82 -34t34 -82v-1304q0 -48 -34 -82t-82 -34 h-178q212 210 196 565l-469 -101q-2 -45 -12 -82t-31 -72t-59.5 -59.5t-93.5 -36.5q-123 -26 -199 40q-32 27 -53 61t-51.5 129t-64.5 258q-35 163 -45.5 263t-5.5 139t23 77q20 41 62.5 73t102.5 45q45 12 83.5 6.5t67 -17t54 -35t43 -48t34.5 -56.5l468 100 q-68 175 -180 287z" />
+<glyph unicode="&#xf26e;" d="M1401 -11l-6 -6q-113 -114 -259 -175q-154 -64 -317 -64q-165 0 -317 64q-148 63 -259 175q-113 112 -175 258q-42 103 -54 189q-4 28 48 36q51 8 56 -20q1 -1 1 -4q18 -90 46 -159q50 -124 152 -226q98 -98 226 -152q132 -56 276 -56q143 0 276 56q128 55 225 152l6 6 q10 10 25 6q12 -3 33 -22q36 -37 17 -58zM929 604l-66 -66l63 -63q21 -21 -7 -49q-17 -17 -32 -17q-10 0 -19 10l-62 61l-66 -66q-5 -5 -15 -5q-15 0 -31 16l-2 2q-18 15 -18 29q0 7 8 17l66 65l-66 66q-16 16 14 45q18 18 31 18q6 0 13 -5l65 -66l65 65q18 17 48 -13 q27 -27 11 -44zM1400 547q0 -118 -46 -228q-45 -105 -126 -186q-80 -80 -187 -126t-228 -46t-228 46t-187 126q-82 82 -125 186q-15 32 -15 40h-1q-9 27 43 44q50 16 60 -12q37 -99 97 -167h1v339v2q3 136 102 232q105 103 253 103q147 0 251 -103t104 -249 q0 -147 -104.5 -251t-250.5 -104q-58 0 -112 16q-28 11 -13 61q16 51 44 43l14 -3q14 -3 32.5 -6t30.5 -3q104 0 176 71.5t72 174.5q0 101 -72 171q-71 71 -175 71q-107 0 -178 -80q-64 -72 -64 -160v-413q110 -67 242 -67q96 0 185 36.5t156 103.5t103.5 155t36.5 183 q0 198 -141 339q-140 140 -339 140q-200 0 -340 -140q-53 -53 -77 -87l-2 -2q-8 -11 -13 -15.5t-21.5 -9.5t-38.5 3q-21 5 -36.5 16.5t-15.5 26.5v680q0 15 10.5 26.5t27.5 11.5h877q30 0 30 -55t-30 -55h-811v-483h1q40 42 102 84t108 61q109 46 231 46q121 0 228 -46 t187 -126q81 -81 126 -186q46 -112 46 -229zM1369 1128q9 -8 9 -18t-5.5 -18t-16.5 -21q-26 -26 -39 -26q-9 0 -16 7q-106 91 -207 133q-128 56 -276 56q-133 0 -262 -49q-27 -10 -45 37q-9 25 -8 38q3 16 16 20q130 57 299 57q164 0 316 -64q137 -58 235 -152z" />
+<glyph unicode="&#xf270;" horiz-adv-x="1792" d="M1551 60q15 6 26 3t11 -17.5t-15 -33.5q-13 -16 -44 -43.5t-95.5 -68t-141 -74t-188 -58t-229.5 -24.5q-119 0 -238 31t-209 76.5t-172.5 104t-132.5 105t-84 87.5q-8 9 -10 16.5t1 12t8 7t11.5 2t11.5 -4.5q192 -117 300 -166q389 -176 799 -90q190 40 391 135z M1758 175q11 -16 2.5 -69.5t-28.5 -102.5q-34 -83 -85 -124q-17 -14 -26 -9t0 24q21 45 44.5 121.5t6.5 98.5q-5 7 -15.5 11.5t-27 6t-29.5 2.5t-35 0t-31.5 -2t-31 -3t-22.5 -2q-6 -1 -13 -1.5t-11 -1t-8.5 -1t-7 -0.5h-5.5h-4.5t-3 0.5t-2 1.5l-1.5 3q-6 16 47 40t103 30 q46 7 108 1t76 -24zM1364 618q0 -31 13.5 -64t32 -58t37.5 -46t33 -32l13 -11l-227 -224q-40 37 -79 75.5t-58 58.5l-19 20q-11 11 -25 33q-38 -59 -97.5 -102.5t-127.5 -63.5t-140 -23t-137.5 21t-117.5 65.5t-83 113t-31 162.5q0 84 28 154t72 116.5t106.5 83t122.5 57 t130 34.5t119.5 18.5t99.5 6.5v127q0 65 -21 97q-34 53 -121 53q-6 0 -16.5 -1t-40.5 -12t-56 -29.5t-56 -59.5t-48 -96l-294 27q0 60 22 119t67 113t108 95t151.5 65.5t190.5 24.5q100 0 181 -25t129.5 -61.5t81 -83t45 -86t12.5 -73.5v-589zM692 597q0 -86 70 -133 q66 -44 139 -22q84 25 114 123q14 45 14 101v162q-59 -2 -111 -12t-106.5 -33.5t-87 -71t-32.5 -114.5z" />
+<glyph unicode="&#xf271;" horiz-adv-x="1792" d="M1536 1280q52 0 90 -38t38 -90v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128zM1152 1376v-288q0 -14 9 -23t23 -9 h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 1376v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM1536 -128v1024h-1408v-1024h1408zM896 448h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224 v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224z" />
+<glyph unicode="&#xf272;" horiz-adv-x="1792" d="M1152 416v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23 t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47 t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf273;" horiz-adv-x="1792" d="M1111 151l-46 -46q-9 -9 -22 -9t-23 9l-188 189l-188 -189q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22t9 23l189 188l-189 188q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l188 -188l188 188q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23l-188 -188l188 -188q9 -10 9 -23t-9 -22z M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf274;" horiz-adv-x="1792" d="M1303 572l-512 -512q-10 -9 -23 -9t-23 9l-288 288q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l220 -220l444 444q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23 t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47 t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf275;" horiz-adv-x="1792" d="M448 1536q26 0 45 -19t19 -45v-891l536 429q17 14 40 14q26 0 45 -19t19 -45v-379l536 429q17 14 40 14q26 0 45 -19t19 -45v-1152q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h384z" />
+<glyph unicode="&#xf276;" horiz-adv-x="1024" d="M512 448q66 0 128 15v-655q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v655q61 -15 128 -15zM512 1536q212 0 362 -150t150 -362t-150 -362t-362 -150t-362 150t-150 362t150 362t362 150zM512 1312q14 0 23 9t9 23t-9 23t-23 9q-146 0 -249 -103t-103 -249 q0 -14 9 -23t23 -9t23 9t9 23q0 119 84.5 203.5t203.5 84.5z" />
+<glyph unicode="&#xf277;" horiz-adv-x="1792" d="M1745 1239q10 -10 10 -23t-10 -23l-141 -141q-28 -28 -68 -28h-1344q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h576v64q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-64h512q40 0 68 -28zM768 320h256v-512q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v512zM1600 768 q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-1344q-40 0 -68 28l-141 141q-10 10 -10 23t10 23l141 141q28 28 68 28h512v192h256v-192h576z" />
+<glyph unicode="&#xf278;" horiz-adv-x="2048" d="M2020 1525q28 -20 28 -53v-1408q0 -20 -11 -36t-29 -23l-640 -256q-24 -11 -48 0l-616 246l-616 -246q-10 -5 -24 -5q-19 0 -36 11q-28 20 -28 53v1408q0 20 11 36t29 23l640 256q24 11 48 0l616 -246l616 246q32 13 60 -6zM736 1390v-1270l576 -230v1270zM128 1173 v-1270l544 217v1270zM1920 107v1270l-544 -217v-1270z" />
+<glyph unicode="&#xf279;" horiz-adv-x="1792" d="M512 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472q0 20 17 28l480 256q7 4 15 4zM1760 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472 q0 20 17 28l480 256q7 4 15 4zM640 1536q8 0 14 -3l512 -256q18 -10 18 -29v-1472q0 -13 -9.5 -22.5t-22.5 -9.5q-8 0 -14 3l-512 256q-18 10 -18 29v1472q0 13 9.5 22.5t22.5 9.5z" />
+<glyph unicode="&#xf27a;" horiz-adv-x="1792" d="M640 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 640q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-110 0 -211 18q-173 -173 -435 -229q-52 -10 -86 -13q-12 -1 -22 6t-13 18q-4 15 20 37q5 5 23.5 21.5t25.5 23.5t23.5 25.5t24 31.5t20.5 37 t20 48t14.5 57.5t12.5 72.5q-146 90 -229.5 216.5t-83.5 269.5q0 174 120 321.5t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf27b;" horiz-adv-x="1792" d="M640 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 -53 -37.5 -90.5t-90.5 -37.5 t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5 t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51 t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 130 71 248.5t191 204.5t286 136.5t348 50.5t348 -50.5t286 -136.5t191 -204.5t71 -248.5z" />
+<glyph unicode="&#xf27c;" horiz-adv-x="1024" d="M512 345l512 295v-591l-512 -296v592zM0 640v-591l512 296zM512 1527v-591l-512 -296v591zM512 936l512 295v-591z" />
+<glyph unicode="&#xf27d;" horiz-adv-x="1792" d="M1709 1018q-10 -236 -332 -651q-333 -431 -562 -431q-142 0 -240 263q-44 160 -132 482q-72 262 -157 262q-18 0 -127 -76l-77 98q24 21 108 96.5t130 115.5q156 138 241 146q95 9 153 -55.5t81 -203.5q44 -287 66 -373q55 -249 120 -249q51 0 154 161q101 161 109 246 q13 139 -109 139q-57 0 -121 -26q120 393 459 382q251 -8 236 -326z" />
+<glyph unicode="&#xf27e;" d="M0 1408h1536v-1536h-1536v1536zM1085 293l-221 631l221 297h-634l221 -297l-221 -631l317 -304z" />
+<glyph unicode="&#xf280;" d="M0 1408h1536v-1536h-1536v1536zM908 1088l-12 -33l75 -83l-31 -114l25 -25l107 57l107 -57l25 25l-31 114l75 83l-12 33h-95l-53 96h-32l-53 -96h-95zM641 925q32 0 44.5 -16t11.5 -63l174 21q0 55 -17.5 92.5t-50.5 56t-69 25.5t-85 7q-133 0 -199 -57.5t-66 -182.5v-72 h-96v-128h76q20 0 20 -8v-382q0 -14 -5 -20t-18 -7l-73 -7v-88h448v86l-149 14q-6 1 -8.5 1.5t-3.5 2.5t-0.5 4t1 7t0.5 10v387h191l38 128h-231q-6 0 -2 6t4 9v80q0 27 1.5 40.5t7.5 28t19.5 20t36.5 5.5zM1248 96v86l-54 9q-7 1 -9.5 2.5t-2.5 3t1 7.5t1 12v520h-275 l-23 -101l83 -22q23 -7 23 -27v-370q0 -14 -6 -18.5t-20 -6.5l-70 -9v-86h352z" />
+<glyph unicode="&#xf281;" horiz-adv-x="1792" d="M1792 690q0 -58 -29.5 -105.5t-79.5 -72.5q12 -46 12 -96q0 -155 -106.5 -287t-290.5 -208.5t-400 -76.5t-399.5 76.5t-290 208.5t-106.5 287q0 47 11 94q-51 25 -82 73.5t-31 106.5q0 82 58 140.5t141 58.5q85 0 145 -63q218 152 515 162l116 521q3 13 15 21t26 5 l369 -81q18 37 54 59.5t79 22.5q62 0 106 -43.5t44 -105.5t-44 -106t-106 -44t-105.5 43.5t-43.5 105.5l-334 74l-104 -472q300 -9 519 -160q58 61 143 61q83 0 141 -58.5t58 -140.5zM418 491q0 -62 43.5 -106t105.5 -44t106 44t44 106t-44 105.5t-106 43.5q-61 0 -105 -44 t-44 -105zM1228 136q11 11 11 26t-11 26q-10 10 -25 10t-26 -10q-41 -42 -121 -62t-160 -20t-160 20t-121 62q-11 10 -26 10t-25 -10q-11 -10 -11 -25.5t11 -26.5q43 -43 118.5 -68t122.5 -29.5t91 -4.5t91 4.5t122.5 29.5t118.5 68zM1225 341q62 0 105.5 44t43.5 106 q0 61 -44 105t-105 44q-62 0 -106 -43.5t-44 -105.5t44 -106t106 -44z" />
+<glyph unicode="&#xf282;" horiz-adv-x="1792" d="M69 741h1q16 126 58.5 241.5t115 217t167.5 176t223.5 117.5t276.5 43q231 0 414 -105.5t294 -303.5q104 -187 104 -442v-188h-1125q1 -111 53.5 -192.5t136.5 -122.5t189.5 -57t213 -3t208 46.5t173.5 84.5v-377q-92 -55 -229.5 -92t-312.5 -38t-316 53 q-189 73 -311.5 249t-124.5 372q-3 242 111 412t325 268q-48 -60 -78 -125.5t-46 -159.5h635q8 77 -8 140t-47 101.5t-70.5 66.5t-80.5 41t-75 20.5t-56 8.5l-22 1q-135 -5 -259.5 -44.5t-223.5 -104.5t-176 -140.5t-138 -163.5z" />
+<glyph unicode="&#xf283;" horiz-adv-x="2304" d="M0 32v608h2304v-608q0 -66 -47 -113t-113 -47h-1984q-66 0 -113 47t-47 113zM640 256v-128h384v128h-384zM256 256v-128h256v128h-256zM2144 1408q66 0 113 -47t47 -113v-224h-2304v224q0 66 47 113t113 47h1984z" />
+<glyph unicode="&#xf284;" horiz-adv-x="1792" d="M1549 857q55 0 85.5 -28.5t30.5 -83.5t-34 -82t-91 -27h-136v-177h-25v398h170zM1710 267l-4 -11l-5 -10q-113 -230 -330.5 -366t-474.5 -136q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71q244 0 454.5 -124t329.5 -338l2 -4l8 -16 q-30 -15 -136.5 -68.5t-163.5 -84.5q-6 -3 -479 -268q384 -183 799 -366zM896 -234q250 0 462.5 132.5t322.5 357.5l-287 129q-72 -140 -206 -222t-292 -82q-151 0 -280 75t-204 204t-75 280t75 280t204 204t280 75t280 -73.5t204 -204.5l280 143q-116 208 -321 329 t-443 121q-119 0 -232.5 -31.5t-209 -87.5t-176.5 -137t-137 -176.5t-87.5 -209t-31.5 -232.5t31.5 -232.5t87.5 -209t137 -176.5t176.5 -137t209 -87.5t232.5 -31.5z" />
+<glyph unicode="&#xf285;" horiz-adv-x="1792" d="M1427 827l-614 386l92 151h855zM405 562l-184 116v858l1183 -743zM1424 697l147 -95v-858l-532 335zM1387 718l-500 -802h-855l356 571z" />
+<glyph unicode="&#xf286;" horiz-adv-x="1792" d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96 q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 6 2.5 9.5t8.5 5t9.5 2t11.5 0t9 -0.5v391q-32 15 -32 50q0 23 16.5 39t38.5 16t38.5 -16t16.5 -39q0 -35 -32 -50v-17q45 10 83 10q21 0 59.5 -7.5t54.5 -7.5 q17 0 47 7.5t37 7.5q16 0 16 -16v-210q0 -15 -35 -21.5t-62 -6.5q-18 0 -54.5 7.5t-55.5 7.5q-40 0 -90 -12v-133q1 0 9 0.5t11.5 0t9.5 -2t8.5 -5t2.5 -9.5v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96 q16 0 16 -16z" />
+<glyph unicode="&#xf287;" horiz-adv-x="2304" d="M2288 731q16 -8 16 -27t-16 -27l-320 -192q-8 -5 -16 -5q-9 0 -16 4q-16 10 -16 28v128h-858q37 -58 83 -165q16 -37 24.5 -55t24 -49t27 -47t27 -34t31.5 -26t33 -8h96v96q0 14 9 23t23 9h320q14 0 23 -9t9 -23v-320q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v96h-96 q-32 0 -61 10t-51 23.5t-45 40.5t-37 46t-33.5 57t-28.5 57.5t-28 60.5q-23 53 -37 81.5t-36 65t-44.5 53.5t-46.5 17h-360q-22 -84 -91 -138t-157 -54q-106 0 -181 75t-75 181t75 181t181 75q88 0 157 -54t91 -138h104q24 0 46.5 17t44.5 53.5t36 65t37 81.5q19 41 28 60.5 t28.5 57.5t33.5 57t37 46t45 40.5t51 23.5t61 10h107q21 57 70 92.5t111 35.5q80 0 136 -56t56 -136t-56 -136t-136 -56q-62 0 -111 35.5t-70 92.5h-107q-17 0 -33 -8t-31.5 -26t-27 -34t-27 -47t-24 -49t-24.5 -55q-46 -107 -83 -165h1114v128q0 18 16 28t32 -1z" />
+<glyph unicode="&#xf288;" horiz-adv-x="1792" d="M1150 774q0 -56 -39.5 -95t-95.5 -39h-253v269h253q56 0 95.5 -39.5t39.5 -95.5zM1329 774q0 130 -91.5 222t-222.5 92h-433v-896h180v269h253q130 0 222 91.5t92 221.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348 t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf289;" horiz-adv-x="2304" d="M1645 438q0 59 -34 106.5t-87 68.5q-7 -45 -23 -92q-7 -24 -27.5 -38t-44.5 -14q-12 0 -24 3q-31 10 -45 38.5t-4 58.5q23 71 23 143q0 123 -61 227.5t-166 165.5t-228 61q-134 0 -247 -73t-167 -194q108 -28 188 -106q22 -23 22 -55t-22 -54t-54 -22t-55 22 q-75 75 -180 75q-106 0 -181 -74.5t-75 -180.5t75 -180.5t181 -74.5h1046q79 0 134.5 55.5t55.5 133.5zM1798 438q0 -142 -100.5 -242t-242.5 -100h-1046q-169 0 -289 119.5t-120 288.5q0 153 100 267t249 136q62 184 221 298t354 114q235 0 408.5 -158.5t196.5 -389.5 q116 -25 192.5 -118.5t76.5 -214.5zM2048 438q0 -175 -97 -319q-23 -33 -64 -33q-24 0 -43 13q-26 17 -32 48.5t12 57.5q71 104 71 233t-71 233q-18 26 -12 57t32 49t57.5 11.5t49.5 -32.5q97 -142 97 -318zM2304 438q0 -244 -134 -443q-23 -34 -64 -34q-23 0 -42 13 q-26 18 -32.5 49t11.5 57q108 164 108 358q0 195 -108 357q-18 26 -11.5 57.5t32.5 48.5q26 18 57 12t49 -33q134 -198 134 -442z" />
+<glyph unicode="&#xf28a;" d="M1500 -13q0 -89 -63 -152.5t-153 -63.5t-153.5 63.5t-63.5 152.5q0 90 63.5 153.5t153.5 63.5t153 -63.5t63 -153.5zM1267 268q-115 -15 -192.5 -102.5t-77.5 -205.5q0 -74 33 -138q-146 -78 -379 -78q-109 0 -201 21t-153.5 54.5t-110.5 76.5t-76 85t-44.5 83 t-23.5 66.5t-6 39.5q0 19 4.5 42.5t18.5 56t36.5 58t64 43.5t94.5 18t94 -17.5t63 -41t35.5 -53t17.5 -49t4 -33.5q0 -34 -23 -81q28 -27 82 -42t93 -17l40 -1q115 0 190 51t75 133q0 26 -9 48.5t-31.5 44.5t-49.5 41t-74 44t-93.5 47.5t-119.5 56.5q-28 13 -43 20 q-116 55 -187 100t-122.5 102t-72 125.5t-20.5 162.5q0 78 20.5 150t66 137.5t112.5 114t166.5 77t221.5 28.5q120 0 220 -26t164.5 -67t109.5 -94t64 -105.5t19 -103.5q0 -46 -15 -82.5t-36.5 -58t-48.5 -36t-49 -19.5t-39 -5h-8h-32t-39 5t-44 14t-41 28t-37 46t-24 70.5 t-10 97.5q-15 16 -59 25.5t-81 10.5l-37 1q-68 0 -117.5 -31t-70.5 -70t-21 -76q0 -24 5 -43t24 -46t53 -51t97 -53.5t150 -58.5q76 -25 138.5 -53.5t109 -55.5t83 -59t60.5 -59.5t41 -62.5t26.5 -62t14.5 -63.5t6 -62t1 -62.5z" />
+<glyph unicode="&#xf28b;" d="M704 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1152 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103 t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf28c;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 t73 -273t198 -198t273 -73zM864 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192z" />
+<glyph unicode="&#xf28d;" d="M1088 352v576q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
+<glyph unicode="&#xf28e;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 t73 -273t198 -198t273 -73zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h576q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-576z" />
+<glyph unicode="&#xf290;" horiz-adv-x="1792" d="M1757 128l35 -313q3 -28 -16 -50q-19 -21 -48 -21h-1664q-29 0 -48 21q-19 22 -16 50l35 313h1722zM1664 967l86 -775h-1708l86 775q3 24 21 40.5t43 16.5h256v-128q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5v128h384v-128q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5v128h256q25 0 43 -16.5t21 -40.5zM1280 1152v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 159 112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf291;" horiz-adv-x="2048" d="M1920 768q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5h-15l-115 -662q-8 -46 -44 -76t-82 -30h-1280q-46 0 -82 30t-44 76l-115 662h-15q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5h1792zM485 -32q26 2 43.5 22.5t15.5 46.5l-32 416q-2 26 -22.5 43.5 t-46.5 15.5t-43.5 -22.5t-15.5 -46.5l32 -416q2 -25 20.5 -42t43.5 -17h5zM896 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1280 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1632 27l32 416 q2 26 -15.5 46.5t-43.5 22.5t-46.5 -15.5t-22.5 -43.5l-32 -416q-2 -26 15.5 -46.5t43.5 -22.5h5q25 0 43.5 17t20.5 42zM476 1244l-93 -412h-132l101 441q19 88 89 143.5t160 55.5h167q0 26 19 45t45 19h384q26 0 45 -19t19 -45h167q90 0 160 -55.5t89 -143.5l101 -441 h-132l-93 412q-11 44 -45.5 72t-79.5 28h-167q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45h-167q-45 0 -79.5 -28t-45.5 -72z" />
+<glyph unicode="&#xf292;" horiz-adv-x="1792" d="M991 512l64 256h-254l-64 -256h254zM1759 1016l-56 -224q-7 -24 -31 -24h-327l-64 -256h311q15 0 25 -12q10 -14 6 -28l-56 -224q-5 -24 -31 -24h-327l-81 -328q-7 -24 -31 -24h-224q-16 0 -26 12q-9 12 -6 28l78 312h-254l-81 -328q-7 -24 -31 -24h-225q-15 0 -25 12 q-9 12 -6 28l78 312h-311q-15 0 -25 12q-9 12 -6 28l56 224q7 24 31 24h327l64 256h-311q-15 0 -25 12q-10 14 -6 28l56 224q5 24 31 24h327l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h254l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h311 q15 0 25 -12q9 -12 6 -28z" />
+<glyph unicode="&#xf293;" d="M841 483l148 -148l-149 -149zM840 1094l149 -149l-148 -148zM710 -130l464 464l-306 306l306 306l-464 464v-611l-255 255l-93 -93l320 -321l-320 -321l93 -93l255 255v-611zM1429 640q0 -209 -32 -365.5t-87.5 -257t-140.5 -162.5t-181.5 -86.5t-219.5 -24.5 t-219.5 24.5t-181.5 86.5t-140.5 162.5t-87.5 257t-32 365.5t32 365.5t87.5 257t140.5 162.5t181.5 86.5t219.5 24.5t219.5 -24.5t181.5 -86.5t140.5 -162.5t87.5 -257t32 -365.5z" />
+<glyph unicode="&#xf294;" horiz-adv-x="1024" d="M596 113l173 172l-173 172v-344zM596 823l173 172l-173 172v-344zM628 640l356 -356l-539 -540v711l-297 -296l-108 108l372 373l-372 373l108 108l297 -296v711l539 -540z" />
+<glyph unicode="&#xf295;" d="M1280 256q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM512 1024q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5 t112.5 -271.5zM1440 1344q0 -20 -13 -38l-1056 -1408q-19 -26 -51 -26h-160q-26 0 -45 19t-19 45q0 20 13 38l1056 1408q19 26 51 26h160q26 0 45 -19t19 -45zM768 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf296;" horiz-adv-x="1792" d="M104 830l792 -1015l-868 630q-18 13 -25 34.5t0 42.5l101 308v0zM566 830h660l-330 -1015v0zM368 1442l198 -612h-462l198 612q8 23 33 23t33 -23zM1688 830l101 -308q7 -21 0 -42.5t-25 -34.5l-868 -630l792 1015v0zM1688 830h-462l198 612q8 23 33 23t33 -23z" />
+<glyph unicode="&#xf297;" horiz-adv-x="1792" d="M384 704h160v224h-160v-224zM1221 372v92q-104 -36 -243 -38q-135 -1 -259.5 46.5t-220.5 122.5l1 -96q88 -80 212 -128.5t272 -47.5q129 0 238 49zM640 704h640v224h-640v-224zM1792 736q0 -187 -99 -352q89 -102 89 -229q0 -157 -129.5 -268t-313.5 -111 q-122 0 -225 52.5t-161 140.5q-19 -1 -57 -1t-57 1q-58 -88 -161 -140.5t-225 -52.5q-184 0 -313.5 111t-129.5 268q0 127 89 229q-99 165 -99 352q0 209 120 385.5t326.5 279.5t449.5 103t449.5 -103t326.5 -279.5t120 -385.5z" />
+<glyph unicode="&#xf298;" d="M515 625v-128h-252v128h252zM515 880v-127h-252v127h252zM1273 369v-128h-341v128h341zM1273 625v-128h-672v128h672zM1273 880v-127h-672v127h672zM1408 20v1240q0 8 -6 14t-14 6h-32l-378 -256l-210 171l-210 -171l-378 256h-32q-8 0 -14 -6t-6 -14v-1240q0 -8 6 -14 t14 -6h1240q8 0 14 6t6 14zM553 1130l185 150h-406zM983 1130l221 150h-406zM1536 1260v-1240q0 -62 -43 -105t-105 -43h-1240q-62 0 -105 43t-43 105v1240q0 62 43 105t105 43h1240q62 0 105 -43t43 -105z" />
+<glyph unicode="&#xf299;" horiz-adv-x="1792" d="M896 720q-104 196 -160 278q-139 202 -347 318q-34 19 -70 36q-89 40 -94 32t34 -38l39 -31q62 -43 112.5 -93.5t94.5 -116.5t70.5 -113t70.5 -131q9 -17 13 -25q44 -84 84 -153t98 -154t115.5 -150t131 -123.5t148.5 -90.5q153 -66 154 -60q1 3 -49 37q-53 36 -81 57 q-77 58 -179 211t-185 310zM549 177q-76 60 -132.5 125t-98 143.5t-71 154.5t-58.5 186t-52 209t-60.5 252t-76.5 289q273 0 497.5 -36t379 -92t271 -144.5t185.5 -172.5t110 -198.5t56 -199.5t12.5 -198.5t-9.5 -173t-20 -143.5t-13 -107l323 -327h-104l-281 285 q-22 -2 -91.5 -14t-121.5 -19t-138 -6t-160.5 17t-167.5 59t-179 111z" />
+<glyph unicode="&#xf29a;" horiz-adv-x="1792" d="M1374 879q-6 26 -28.5 39.5t-48.5 7.5q-261 -62 -401 -62t-401 62q-26 6 -48.5 -7.5t-28.5 -39.5t7.5 -48.5t39.5 -28.5q194 -46 303 -58q-2 -158 -15.5 -269t-26.5 -155.5t-41 -115.5l-9 -21q-10 -25 1 -49t36 -34q9 -4 23 -4q44 0 60 41l8 20q54 139 71 259h42 q17 -120 71 -259l8 -20q16 -41 60 -41q14 0 23 4q25 10 36 34t1 49l-9 21q-28 71 -41 115.5t-26.5 155.5t-15.5 269q109 12 303 58q26 6 39.5 28.5t7.5 48.5zM1024 1024q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1600 640q0 -143 -55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5zM896 1408q-156 0 -298 -61t-245 -164t-164 -245t-61 -298t61 -298 t164 -245t245 -164t298 -61t298 61t245 164t164 245t61 298t-61 298t-164 245t-245 164t-298 61zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf29b;" d="M1438 723q34 -35 29 -82l-44 -551q-4 -42 -34.5 -70t-71.5 -28q-6 0 -9 1q-44 3 -72.5 36.5t-25.5 77.5l35 429l-143 -8q55 -113 55 -240q0 -216 -148 -372l-137 137q91 101 91 235q0 145 -102.5 248t-247.5 103q-134 0 -236 -92l-137 138q120 114 284 141l264 300 l-149 87l-181 -161q-33 -30 -77 -27.5t-73 35.5t-26.5 77t34.5 73l239 213q26 23 60 26.5t64 -14.5l488 -283q36 -21 48 -68q17 -67 -26 -117l-205 -232l371 20q49 3 83 -32zM1240 1180q-74 0 -126 52t-52 126t52 126t126 52t126.5 -52t52.5 -126t-52.5 -126t-126.5 -52z M613 -62q106 0 196 61l139 -139q-146 -116 -335 -116q-148 0 -273.5 73t-198.5 198t-73 273q0 188 116 336l139 -139q-60 -88 -60 -197q0 -145 102.5 -247.5t247.5 -102.5z" />
+<glyph unicode="&#xf29c;" d="M880 336v-160q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h160q14 0 23 -9t9 -23zM1136 832q0 -50 -15 -90t-45.5 -69t-52 -44t-59.5 -36q-32 -18 -46.5 -28t-26 -24t-11.5 -29v-32q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v68q0 35 10.5 64.5 t24 47.5t39 35.5t41 25.5t44.5 21q53 25 75 43t22 49q0 42 -43.5 71.5t-95.5 29.5q-56 0 -95 -27q-29 -20 -80 -83q-9 -12 -25 -12q-11 0 -19 6l-108 82q-10 7 -12 20t5 23q122 192 349 192q129 0 238.5 -89.5t109.5 -214.5zM768 1280q-130 0 -248.5 -51t-204 -136.5 t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5 t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf29d;" horiz-adv-x="1408" d="M366 1225q-64 0 -110 45.5t-46 110.5q0 64 46 109.5t110 45.5t109.5 -45.5t45.5 -109.5q0 -65 -45.5 -110.5t-109.5 -45.5zM917 583q0 -50 -30 -67.5t-63.5 -6.5t-47.5 34l-367 438q-7 12 -14 15.5t-11 1.5l-3 -3q-7 -8 4 -21l122 -139l1 -354l-161 -457 q-67 -192 -92 -234q-16 -26 -28 -32q-50 -26 -103 -1q-29 13 -41.5 43t-9.5 57q2 17 197 618l5 416l-85 -164l35 -222q4 -24 -1 -42t-14 -27.5t-19 -16t-17 -7.5l-7 -2q-19 -3 -34.5 3t-24 16t-14 22t-7.5 19.5t-2 9.5l-46 299l211 381q23 34 113 34q75 0 107 -40l424 -521 q7 -5 14 -17l3 -3l-1 -1q7 -13 7 -29zM514 433q43 -113 88.5 -225t69.5 -168l24 -55q36 -93 42 -125q11 -70 -36 -97q-35 -22 -66 -16t-51 22t-29 35h-1q-6 16 -8 25l-124 351zM1338 -159q31 -49 31 -57q0 -5 -3 -7q-9 -5 -14.5 0.5t-15.5 26t-16 30.5q-114 172 -423 661 q3 -1 7 1t7 4l3 2q11 9 11 17z" />
+<glyph unicode="&#xf29e;" horiz-adv-x="2304" d="M504 542h171l-1 265zM1530 641q0 87 -50.5 140t-146.5 53h-54v-388h52q91 0 145 57t54 138zM956 1018l1 -756q0 -14 -9.5 -24t-23.5 -10h-216q-14 0 -23.5 10t-9.5 24v62h-291l-55 -81q-10 -15 -28 -15h-267q-21 0 -30.5 18t3.5 35l556 757q9 14 27 14h332q14 0 24 -10 t10 -24zM1783 641q0 -193 -125.5 -303t-324.5 -110h-270q-14 0 -24 10t-10 24v756q0 14 10 24t24 10h268q200 0 326 -109t126 -302zM1939 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5 t-7.5 60t-20 91.5t-41 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2123 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-45 -108t-74 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5 h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2304 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66 104.5t41 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96 t9.5 -70.5z" />
+<glyph unicode="&#xf2a0;" horiz-adv-x="1408" d="M617 -153q0 11 -13 58t-31 107t-20 69q-1 4 -5 26.5t-8.5 36t-13.5 21.5q-15 14 -51 14q-23 0 -70 -5.5t-71 -5.5q-34 0 -47 11q-6 5 -11 15.5t-7.5 20t-6.5 24t-5 18.5q-37 128 -37 255t37 255q1 4 5 18.5t6.5 24t7.5 20t11 15.5q13 11 47 11q24 0 71 -5.5t70 -5.5 q36 0 51 14q9 8 13.5 21.5t8.5 36t5 26.5q2 9 20 69t31 107t13 58q0 22 -43.5 52.5t-75.5 42.5q-20 8 -45 8q-34 0 -98 -18q-57 -17 -96.5 -40.5t-71 -66t-46 -70t-45.5 -94.5q-6 -12 -9 -19q-49 -107 -68 -216t-19 -244t19 -244t68 -216q56 -122 83 -161q63 -91 179 -127 l6 -2q64 -18 98 -18q25 0 45 8q32 12 75.5 42.5t43.5 52.5zM776 760q-26 0 -45 19t-19 45.5t19 45.5q37 37 37 90q0 52 -37 91q-19 19 -19 45t19 45t45 19t45 -19q75 -75 75 -181t-75 -181q-21 -19 -45 -19zM957 579q-27 0 -45 19q-19 19 -19 45t19 45q112 114 112 272 t-112 272q-19 19 -19 45t19 45t45 19t45 -19q150 -150 150 -362t-150 -362q-18 -19 -45 -19zM1138 398q-27 0 -45 19q-19 19 -19 45t19 45q90 91 138.5 208t48.5 245t-48.5 245t-138.5 208q-19 19 -19 45t19 45t45 19t45 -19q109 -109 167 -249t58 -294t-58 -294t-167 -249 q-18 -19 -45 -19z" />
+<glyph unicode="&#xf2a1;" horiz-adv-x="2176" d="M192 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 352 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 864 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 1376q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 192q0 -80 -56 -136 t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 1216q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 192q0 -80 -56 -136t-136 -56t-136 56 t-56 136t56 136t136 56t136 -56t56 -136zM1664 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136 t56 136t136 56t136 -56t56 -136zM2176 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf2a2;" horiz-adv-x="1792" d="M128 -192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM320 0q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM365 365l256 -256l-90 -90l-256 256zM704 384q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45z M1411 704q0 -59 -11.5 -108.5t-37.5 -93.5t-44 -67.5t-53 -64.5q-31 -35 -45.5 -54t-33.5 -50t-26.5 -64t-7.5 -74q0 -159 -112.5 -271.5t-271.5 -112.5q-26 0 -45 19t-19 45t19 45t45 19q106 0 181 75t75 181q0 57 11.5 105.5t37 91t43.5 66.5t52 63q40 46 59.5 72 t37.5 74.5t18 103.5q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM896 576q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45 t45 19t45 -19t19 -45zM1184 704q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 93 -65.5 158.5t-158.5 65.5q-92 0 -158 -65.5t-66 -158.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 146 103 249t249 103t249 -103t103 -249zM1578 993q10 -25 -1 -49t-36 -34q-9 -4 -23 -4 q-19 0 -35.5 11t-23.5 30q-68 178 -224 295q-21 16 -25 42t12 47q17 21 43 25t47 -12q183 -137 266 -351zM1788 1074q9 -25 -1.5 -49t-35.5 -34q-11 -4 -23 -4q-44 0 -60 41q-92 238 -297 393q-22 16 -25.5 42t12.5 47q16 22 42 25.5t47 -12.5q235 -175 341 -449z" />
+<glyph unicode="&#xf2a3;" horiz-adv-x="2304" d="M1032 576q-59 2 -84 55q-17 34 -48 53.5t-68 19.5q-53 0 -90.5 -37.5t-37.5 -90.5q0 -56 36 -89l10 -8q34 -31 82 -31q37 0 68 19.5t48 53.5q25 53 84 55zM1600 704q0 56 -36 89l-10 8q-34 31 -82 31q-37 0 -68 -19.5t-48 -53.5q-25 -53 -84 -55q59 -2 84 -55 q17 -34 48 -53.5t68 -19.5q53 0 90.5 37.5t37.5 90.5zM1174 925q-17 -35 -55 -48t-73 4q-62 31 -134 31q-51 0 -99 -17q3 0 9.5 0.5t9.5 0.5q92 0 170.5 -50t118.5 -133q17 -36 3.5 -73.5t-49.5 -54.5q-18 -9 -39 -9q21 0 39 -9q36 -17 49.5 -54.5t-3.5 -73.5 q-40 -83 -118.5 -133t-170.5 -50h-6q-16 2 -44 4l-290 27l-239 -120q-14 -7 -29 -7q-40 0 -57 35l-160 320q-11 23 -4 47.5t29 37.5l209 119l148 267q17 155 91.5 291.5t195.5 236.5q31 25 70.5 21.5t64.5 -34.5t21.5 -70t-34.5 -65q-70 -59 -117 -128q123 84 267 101 q40 5 71.5 -19t35.5 -64q5 -40 -19 -71.5t-64 -35.5q-84 -10 -159 -55q46 10 99 10q115 0 218 -50q36 -18 49 -55.5t-5 -73.5zM2137 1085l160 -320q11 -23 4 -47.5t-29 -37.5l-209 -119l-148 -267q-17 -155 -91.5 -291.5t-195.5 -236.5q-26 -22 -61 -22q-45 0 -74 35 q-25 31 -21.5 70t34.5 65q70 59 117 128q-123 -84 -267 -101q-4 -1 -12 -1q-36 0 -63.5 24t-31.5 60q-5 40 19 71.5t64 35.5q84 10 159 55q-46 -10 -99 -10q-115 0 -218 50q-36 18 -49 55.5t5 73.5q17 35 55 48t73 -4q62 -31 134 -31q51 0 99 17q-3 0 -9.5 -0.5t-9.5 -0.5 q-92 0 -170.5 50t-118.5 133q-17 36 -3.5 73.5t49.5 54.5q18 9 39 9q-21 0 -39 9q-36 17 -49.5 54.5t3.5 73.5q40 83 118.5 133t170.5 50h6h1q14 -2 42 -4l291 -27l239 120q14 7 29 7q40 0 57 -35z" />
+<glyph unicode="&#xf2a4;" horiz-adv-x="1792" d="M1056 704q0 -26 19 -45t45 -19t45 19t19 45q0 146 -103 249t-249 103t-249 -103t-103 -249q0 -26 19 -45t45 -19t45 19t19 45q0 93 66 158.5t158 65.5t158 -65.5t66 -158.5zM835 1280q-117 0 -223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5q0 -26 19 -45t45 -19t45 19 t19 45q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -55 -18 -103.5t-37.5 -74.5t-59.5 -72q-34 -39 -52 -63t-43.5 -66.5t-37 -91t-11.5 -105.5q0 -106 -75 -181t-181 -75q-26 0 -45 -19t-19 -45t19 -45t45 -19q159 0 271.5 112.5t112.5 271.5q0 41 7.5 74 t26.5 64t33.5 50t45.5 54q35 41 53 64.5t44 67.5t37.5 93.5t11.5 108.5q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5zM591 561l226 -226l-579 -579q-12 -12 -29 -12t-29 12l-168 168q-12 12 -12 29t12 29zM1612 1524l168 -168q12 -12 12 -29t-12 -30l-233 -233 l-26 -25l-71 -71q-66 153 -195 258l91 91l207 207q13 12 30 12t29 -12z" />
+<glyph unicode="&#xf2a5;" d="M866 1021q0 -27 -13 -94q-11 -50 -31.5 -150t-30.5 -150q-2 -11 -4.5 -12.5t-13.5 -2.5q-20 -2 -31 -2q-58 0 -84 49.5t-26 113.5q0 88 35 174t103 124q28 14 51 14q28 0 36.5 -16.5t8.5 -47.5zM1352 597q0 14 -39 75.5t-52 66.5q-21 8 -34 8q-91 0 -226 -77l-2 2 q3 22 27.5 135t24.5 178q0 233 -242 233q-24 0 -68 -6q-94 -17 -168.5 -89.5t-111.5 -166.5t-37 -189q0 -146 80.5 -225t227.5 -79q25 0 25 -3t-1 -5q-4 -34 -26 -117q-14 -52 -51.5 -101t-82.5 -49q-42 0 -42 47q0 24 10.5 47.5t25 39.5t29.5 28.5t26 20t11 8.5q0 3 -7 10 q-24 22 -58.5 36.5t-65.5 14.5q-35 0 -63.5 -34t-41 -75t-12.5 -75q0 -88 51.5 -142t138.5 -54q82 0 155 53t117.5 126t65.5 153q6 22 15.5 66.5t14.5 66.5q3 12 14 18q118 60 227 60q48 0 127 -18q1 -1 4 -1q5 0 9.5 4.5t4.5 8.5zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf2a6;" horiz-adv-x="1535" d="M744 1231q0 24 -2 38.5t-8.5 30t-21 23t-37.5 7.5q-39 0 -78 -23q-105 -58 -159 -190.5t-54 -269.5q0 -44 8.5 -85.5t26.5 -80.5t52.5 -62.5t81.5 -23.5q4 0 18 -0.5t20 0t16 3t15 8.5t7 16q16 77 48 231.5t48 231.5q19 91 19 146zM1498 575q0 -7 -7.5 -13.5t-15.5 -6.5 l-6 1q-22 3 -62 11t-72 12.5t-63 4.5q-167 0 -351 -93q-15 -8 -21 -27q-10 -36 -24.5 -105.5t-22.5 -100.5q-23 -91 -70 -179.5t-112.5 -164.5t-154.5 -123t-185 -47q-135 0 -214.5 83.5t-79.5 219.5q0 53 19.5 117t63 116.5t97.5 52.5q38 0 120 -33.5t83 -61.5 q0 -1 -16.5 -12.5t-39.5 -31t-46 -44.5t-39 -61t-16 -74q0 -33 16.5 -53t48.5 -20q45 0 85 31.5t66.5 78t48 105.5t32.5 107t16 90v9q0 2 -3.5 3.5t-8.5 1.5h-10t-10 -0.5t-6 -0.5q-227 0 -352 122.5t-125 348.5q0 108 34.5 221t96 210t156 167.5t204.5 89.5q52 9 106 9 q374 0 374 -360q0 -98 -38 -273t-43 -211l3 -3q101 57 182.5 88t167.5 31q22 0 53 -13q19 -7 80 -102.5t61 -116.5z" />
+<glyph unicode="&#xf2a7;" horiz-adv-x="1664" d="M831 863q32 0 59 -18l222 -148q61 -40 110 -97l146 -170q40 -46 29 -106l-72 -413q-6 -32 -29.5 -53.5t-55.5 -25.5l-527 -56l-352 -32h-9q-39 0 -67.5 28t-28.5 68q0 37 27 64t65 32l260 32h-448q-41 0 -69.5 30t-26.5 71q2 39 32 65t69 26l442 1l-521 64q-41 5 -66 37 t-19 73q6 35 34.5 57.5t65.5 22.5h10l481 -60l-351 94q-38 10 -62 41.5t-18 68.5q6 36 33 58.5t62 22.5q6 0 20 -2l448 -96l217 -37q1 0 3 -0.5t3 -0.5q23 0 30.5 23t-12.5 36l-186 125q-35 23 -42 63.5t18 73.5q27 38 76 38zM761 661l186 -125l-218 37l-5 2l-36 38 l-238 262q-1 1 -2.5 3.5t-2.5 3.5q-24 31 -18.5 70t37.5 64q31 23 68 17.5t64 -33.5l142 -147l-4 -4t-5 -4q-32 -45 -23 -99t55 -85zM1648 1115l15 -266q4 -73 -11 -147l-48 -219q-12 -59 -67 -87l-106 -54q2 62 -39 109l-146 170q-53 61 -117 103l-222 148q-34 23 -76 23 q-51 0 -88 -37l-235 312q-25 33 -18 73.5t41 63.5q33 22 71.5 14t62.5 -40l266 -352l-262 455q-21 35 -10.5 75t47.5 59q35 18 72.5 6t57.5 -46l241 -420l-136 337q-15 35 -4.5 74t44.5 56q37 19 76 6t56 -51l193 -415l101 -196q8 -15 23 -17.5t27 7.5t11 26l-12 224 q-2 41 26 71t69 31q39 0 67 -28.5t30 -67.5z" />
+<glyph unicode="&#xf2a8;" horiz-adv-x="1792" d="M335 180q-2 0 -6 2q-86 57 -168.5 145t-139.5 180q-21 30 -21 69q0 9 2 19t4 18t7 18t8.5 16t10.5 17t10 15t12 15.5t11 14.5q184 251 452 365q-110 198 -110 211q0 19 17 29q116 64 128 64q18 0 28 -16l124 -229q92 19 192 19q266 0 497.5 -137.5t378.5 -369.5 q20 -31 20 -69t-20 -69q-91 -142 -218.5 -253.5t-278.5 -175.5q110 -198 110 -211q0 -20 -17 -29q-116 -64 -127 -64q-19 0 -29 16l-124 229l-64 119l-444 820l7 7q-58 -24 -99 -47q3 -5 127 -234t243 -449t119 -223q0 -7 -9 -9q-13 -3 -72 -3q-57 0 -60 7l-456 841 q-39 -28 -82 -68q24 -43 214 -393.5t190 -354.5q0 -10 -11 -10q-14 0 -82.5 22t-72.5 28l-106 197l-224 413q-44 -53 -78 -106q2 -3 18 -25t23 -34l176 -327q0 -10 -10 -10zM1165 282l49 -91q273 111 450 385q-180 277 -459 389q67 -64 103 -148.5t36 -176.5 q0 -106 -47 -200.5t-132 -157.5zM848 896q0 -20 14 -34t34 -14q86 0 147 -61t61 -147q0 -20 14 -34t34 -14t34 14t14 34q0 126 -89 215t-215 89q-20 0 -34 -14t-14 -34zM1214 961l-9 4l7 -7z" />
+<glyph unicode="&#xf2a9;" horiz-adv-x="1280" d="M1050 430q0 -215 -147 -374q-148 -161 -378 -161q-232 0 -378 161q-147 159 -147 374q0 147 68 270.5t189 196.5t268 73q96 0 182 -31q-32 -62 -39 -126q-66 28 -143 28q-167 0 -280.5 -123t-113.5 -291q0 -170 112.5 -288.5t281.5 -118.5t281 118.5t112 288.5 q0 89 -32 166q66 13 123 49q41 -98 41 -212zM846 619q0 -192 -79.5 -345t-238.5 -253l-14 -1q-29 0 -62 5q83 32 146.5 102.5t99.5 154.5t58.5 189t30 192.5t7.5 178.5q0 69 -3 103q55 -160 55 -326zM791 947v-2q-73 214 -206 440q88 -59 142.5 -186.5t63.5 -251.5z M1035 744q-83 0 -160 75q218 120 290 247q19 37 21 56q-42 -94 -139.5 -166.5t-204.5 -97.5q-35 54 -35 113q0 37 17 79t43 68q46 44 157 74q59 16 106 58.5t74 100.5q74 -105 74 -253q0 -109 -24 -170q-32 -77 -88.5 -130.5t-130.5 -53.5z" />
+<glyph unicode="&#xf2aa;" d="M1050 495q0 78 -28 147q-41 -25 -85 -34q22 -50 22 -114q0 -117 -77 -198.5t-193 -81.5t-193.5 81.5t-77.5 198.5q0 115 78 199.5t193 84.5q53 0 98 -19q4 43 27 87q-60 21 -125 21q-154 0 -257.5 -108.5t-103.5 -263.5t103.5 -261t257.5 -106t257.5 106.5t103.5 260.5z M872 850q2 -24 2 -71q0 -63 -5 -123t-20.5 -132.5t-40.5 -130t-68.5 -106t-100.5 -70.5q21 -3 42 -3h10q219 139 219 411q0 116 -38 225zM872 850q-4 80 -44 171.5t-98 130.5q92 -156 142 -302zM1207 955q0 102 -51 174q-41 -86 -124 -109q-69 -19 -109 -53.5t-40 -99.5 q0 -40 24 -77q74 17 140.5 67t95.5 115q-4 -52 -74.5 -111.5t-138.5 -97.5q52 -52 110 -52q51 0 90 37t60 90q17 43 17 117zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf2ab;" d="M1279 388q0 22 -22 27q-67 15 -118 59t-80 108q-7 19 -7 25q0 15 19.5 26t43 17t43 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-12 0 -32 -8t-31 -8q-4 0 -12 2q5 95 5 114q0 79 -17 114q-36 78 -103 121.5t-152 43.5q-199 0 -275 -165q-17 -35 -17 -114q0 -19 5 -114 q-4 -2 -14 -2q-12 0 -32 7.5t-30 7.5q-21 0 -38.5 -12t-17.5 -32q0 -21 19.5 -35.5t43 -20.5t43 -17t19.5 -26q0 -6 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -46 137 -68q2 -5 6 -26t11.5 -30.5t23.5 -9.5q12 0 37.5 4.5t39.5 4.5q35 0 67 -15t54 -32.5t57.5 -32.5 t76.5 -15q43 0 79 15t57.5 32.5t53.5 32.5t67 15q14 0 39.5 -4t38.5 -4q16 0 23 10t11 30t6 25q137 22 137 68zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
+<glyph unicode="&#xf2ac;" horiz-adv-x="1664" d="M848 1408q134 1 240.5 -68.5t163.5 -192.5q27 -58 27 -179q0 -47 -9 -191q14 -7 28 -7q18 0 51 13.5t51 13.5q29 0 56 -18t27 -46q0 -32 -31.5 -54t-69 -31.5t-69 -29t-31.5 -47.5q0 -15 12 -43q37 -82 102.5 -150t144.5 -101q28 -12 80 -23q28 -6 28 -35 q0 -70 -219 -103q-7 -11 -11 -39t-14 -46.5t-33 -18.5q-20 0 -62 6.5t-64 6.5q-37 0 -62 -5q-32 -5 -63 -22.5t-58 -38t-58 -40.5t-76 -33.5t-99 -13.5q-52 0 -96.5 13.5t-75 33.5t-57.5 40.5t-58 38t-62 22.5q-26 5 -63 5q-24 0 -65.5 -7.5t-58.5 -7.5q-25 0 -35 18.5 t-14 47.5t-11 40q-219 33 -219 103q0 29 28 35q52 11 80 23q78 32 144.5 101t102.5 150q12 28 12 43q0 28 -31.5 47.5t-69.5 29.5t-69.5 31.5t-31.5 52.5q0 27 26 45.5t55 18.5q15 0 48 -13t53 -13q18 0 32 7q-9 142 -9 190q0 122 27 180q64 137 172 198t264 63z" />
+<glyph unicode="&#xf2ad;" d="M1280 388q0 22 -22 27q-67 14 -118 58t-80 109q-7 14 -7 25q0 15 19.5 26t42.5 17t42.5 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-11 0 -31 -8t-32 -8q-4 0 -12 2q5 63 5 115q0 78 -17 114q-36 78 -102.5 121.5t-152.5 43.5q-198 0 -275 -165q-18 -38 -18 -115 q0 -38 6 -114q-10 -2 -15 -2q-11 0 -31.5 8t-30.5 8q-20 0 -37.5 -12.5t-17.5 -32.5q0 -21 19.5 -35.5t42.5 -20.5t42.5 -17t19.5 -26q0 -11 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -47 138 -69q2 -5 6 -26t11 -30.5t23 -9.5q13 0 38.5 5t38.5 5q35 0 67.5 -15 t54.5 -32.5t57.5 -32.5t76.5 -15q43 0 79 15t57.5 32.5t54 32.5t67.5 15q13 0 39 -4.5t39 -4.5q15 0 22.5 9.5t11.5 31t5 24.5q138 22 138 69zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf2ae;" horiz-adv-x="2304" d="M2304 1536q-69 -46 -125 -92t-89 -81t-59.5 -71.5t-37.5 -57.5t-22 -44.5t-14 -29.5q-10 -18 -35.5 -136.5t-48.5 -164.5q-15 -29 -50 -60.5t-67.5 -50.5t-72.5 -41t-48 -28q-47 -31 -151 -231q-341 14 -630 -158q-92 -53 -303 -179q47 16 86 31t55 22l15 7 q71 27 163 64.5t133.5 53.5t108 34.5t142.5 31.5q186 31 465 -7q1 0 10 -3q11 -6 14 -17t-3 -22l-194 -345q-15 -29 -47 -22q-128 24 -354 24q-146 0 -402 -44.5t-392 -46.5q-82 -1 -149 13t-107 37t-61 40t-33 34l-1 1v2q0 6 6 6q138 0 371 55q192 366 374.5 524t383.5 158 q5 0 14.5 -0.5t38 -5t55 -12t61.5 -24.5t63 -39.5t54 -59t40 -82.5l102 177q2 4 21 42.5t44.5 86.5t61 109.5t84 133.5t100.5 137q66 82 128 141.5t121.5 96.5t92.5 53.5t88 39.5z" />
+<glyph unicode="&#xf2b0;" d="M1322 640q0 -45 -5 -76l-236 14l224 -78q-19 -73 -58 -141l-214 103l177 -158q-44 -61 -107 -108l-157 178l103 -215q-61 -37 -140 -59l-79 228l14 -240q-38 -6 -76 -6t-76 6l14 238l-78 -226q-74 19 -140 59l103 215l-157 -178q-59 43 -108 108l178 158l-214 -104 q-39 69 -58 141l224 79l-237 -14q-5 42 -5 76q0 35 5 77l238 -14l-225 79q19 73 58 140l214 -104l-177 159q46 61 107 108l158 -178l-103 215q67 39 140 58l77 -224l-13 236q36 6 75 6q38 0 76 -6l-14 -237l78 225q74 -19 140 -59l-103 -214l158 178q61 -47 107 -108 l-177 -159l213 104q37 -62 58 -141l-224 -78l237 14q5 -31 5 -77zM1352 640q0 160 -78.5 295.5t-213 214t-292.5 78.5q-119 0 -227 -46.5t-186.5 -125t-124.5 -187.5t-46 -229q0 -119 46 -228t124.5 -187.5t186.5 -125t227 -46.5q158 0 292.5 78.5t213 214t78.5 294.5z M1425 1023v-766l-657 -383l-657 383v766l657 383zM768 -183l708 412v823l-708 411l-708 -411v-823zM1536 1088v-896l-768 -448l-768 448v896l768 448z" />
+<glyph unicode="&#xf2b1;" horiz-adv-x="1664" d="M339 1318h691l-26 -72h-665q-110 0 -188.5 -79t-78.5 -189v-771q0 -95 60.5 -169.5t153.5 -93.5q23 -5 98 -5v-72h-45q-140 0 -239.5 100t-99.5 240v771q0 140 99.5 240t239.5 100zM1190 1536h247l-482 -1294q-23 -61 -40.5 -103.5t-45 -98t-54 -93.5t-64.5 -78.5 t-79.5 -65t-95.5 -41t-116 -18.5v195q163 26 220 182q20 52 20 105q0 54 -20 106l-285 733h228l187 -585zM1664 978v-1111h-795q37 55 45 73h678v1038q0 85 -49.5 155t-129.5 99l25 67q101 -34 163.5 -123.5t62.5 -197.5z" />
+<glyph unicode="&#xf2b2;" horiz-adv-x="1792" d="M852 1227q0 -29 -17 -52.5t-45 -23.5t-45 23.5t-17 52.5t17 52.5t45 23.5t45 -23.5t17 -52.5zM688 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50 -21.5t-20 -51.5v-114q0 -30 20.5 -52t49.5 -22q30 0 50.5 22t20.5 52zM860 -149v114q0 30 -20 51.5t-50 21.5t-50.5 -21.5 t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22q29 0 49.5 22t20.5 52zM1034 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1208 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114 q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1476 535q-84 -160 -232 -259.5t-323 -99.5q-123 0 -229.5 51.5t-178.5 137t-113 197.5t-41 232q0 88 21 174q-104 -175 -104 -390q0 -162 65 -312t185 -251q30 57 91 57q56 0 86 -50q32 50 87 50q56 0 86 -50q32 50 87 50t87 -50 q30 50 86 50q28 0 52.5 -15.5t37.5 -40.5q112 94 177 231.5t73 287.5zM1326 564q0 75 -72 75q-17 0 -47 -6q-95 -19 -149 -19q-226 0 -226 243q0 86 30 204q-83 -127 -83 -275q0 -150 89 -260.5t235 -110.5q111 0 210 70q13 48 13 79zM884 1223q0 50 -32 89.5t-81 39.5 t-81 -39.5t-32 -89.5q0 -51 31.5 -90.5t81.5 -39.5t81.5 39.5t31.5 90.5zM1513 884q0 96 -37.5 179t-113 137t-173.5 54q-77 0 -149 -35t-127 -94q-48 -159 -48 -268q0 -104 45.5 -157t147.5 -53q53 0 142 19q36 6 53 6q51 0 77.5 -28t26.5 -80q0 -26 -4 -46 q75 68 117.5 165.5t42.5 200.5zM1792 667q0 -111 -33.5 -249.5t-93.5 -204.5q-58 -64 -195 -142.5t-228 -104.5l-4 -1v-114q0 -43 -29.5 -75t-72.5 -32q-56 0 -86 50q-32 -50 -87 -50t-87 50q-30 -50 -86 -50q-55 0 -87 50q-30 -50 -86 -50q-47 0 -75 33.5t-28 81.5 q-90 -68 -198 -68q-118 0 -211 80q54 1 106 20q-113 31 -182 127q32 -7 71 -7q89 0 164 46q-192 192 -240 306q-24 56 -24 160q0 57 9 125.5t31.5 146.5t55 141t86.5 105t120 42q59 0 81 -52q19 29 42 54q2 3 12 13t13 16q10 15 23 38t25 42t28 39q87 111 211.5 177 t260.5 66q35 0 62 -4q59 64 146 64q83 0 140 -57q5 -5 5 -12q0 -5 -6 -13.5t-12.5 -16t-16 -17l-10.5 -10.5q17 -6 36 -18t19 -24q0 -6 -16 -25q157 -138 197 -378q25 30 60 30q45 0 100 -49q90 -80 90 -279z" />
+<glyph unicode="&#xf2b3;" d="M917 631q0 33 -6 64h-362v-132h217q-12 -76 -74.5 -120.5t-142.5 -44.5q-99 0 -169 71.5t-70 170.5t70 170.5t169 71.5q93 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585h109v110 h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf2b4;" d="M1536 1024v-839q0 -48 -49 -62q-174 -52 -338 -52q-73 0 -215.5 29.5t-227.5 29.5q-164 0 -370 -48v-338h-160v1368q-63 25 -101 81t-38 124q0 91 64 155t155 64t155 -64t64 -155q0 -68 -38 -124t-101 -81v-68q190 44 343 44q99 0 198 -15q14 -2 111.5 -22.5t149.5 -20.5 q77 0 165 18q11 2 80 21t89 19q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf2b5;" horiz-adv-x="1792" />
+<glyph unicode="&#xf2b6;" horiz-adv-x="1792" />
+<glyph unicode="&#xf2b7;" horiz-adv-x="1792" />
+<glyph unicode="&#xf2b8;" horiz-adv-x="1792" />
+<glyph unicode="&#xf2b9;" horiz-adv-x="1792" />
+<glyph unicode="&#xf2ba;" horiz-adv-x="1792" />
+<glyph unicode="&#xf2bb;" horiz-adv-x="1792" />
+<glyph unicode="&#xf2bc;" horiz-adv-x="1792" />
+<glyph unicode="&#xf2bd;" horiz-adv-x="1792" />
+<glyph unicode="&#xf2be;" horiz-adv-x="1792" />
+<glyph unicode="&#xf500;" horiz-adv-x="1792" />
+</font>
+</defs></svg> 
\ No newline at end of file
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.ttf b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000..f221e50
Binary files /dev/null and b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.ttf differ
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff
new file mode 100644
index 0000000..6e7483c
Binary files /dev/null and b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff differ
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff2 b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff2
new file mode 100644
index 0000000..7eb74fd
Binary files /dev/null and b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff2 differ
diff --git a/hubs/static/font-awesome-4.6.3/less/animated.less b/hubs/static/font-awesome-4.6.3/less/animated.less
new file mode 100644
index 0000000..66ad52a
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/animated.less
@@ -0,0 +1,34 @@
+// Animated Icons
+// --------------------------
+
+.@{fa-css-prefix}-spin {
+  -webkit-animation: fa-spin 2s infinite linear;
+          animation: fa-spin 2s infinite linear;
+}
+
+.@{fa-css-prefix}-pulse {
+  -webkit-animation: fa-spin 1s infinite steps(8);
+          animation: fa-spin 1s infinite steps(8);
+}
+
+@-webkit-keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+            transform: rotate(359deg);
+  }
+}
+
+@keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+            transform: rotate(359deg);
+  }
+}
diff --git a/hubs/static/font-awesome-4.6.3/less/bordered-pulled.less b/hubs/static/font-awesome-4.6.3/less/bordered-pulled.less
new file mode 100644
index 0000000..f1c8ad7
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/bordered-pulled.less
@@ -0,0 +1,25 @@
+// Bordered & Pulled
+// -------------------------
+
+.@{fa-css-prefix}-border {
+  padding: .2em .25em .15em;
+  border: solid .08em @fa-border-color;
+  border-radius: .1em;
+}
+
+.@{fa-css-prefix}-pull-left { float: left; }
+.@{fa-css-prefix}-pull-right { float: right; }
+
+.@{fa-css-prefix} {
+  &.@{fa-css-prefix}-pull-left { margin-right: .3em; }
+  &.@{fa-css-prefix}-pull-right { margin-left: .3em; }
+}
+
+/* Deprecated as of 4.4.0 */
+.pull-right { float: right; }
+.pull-left { float: left; }
+
+.@{fa-css-prefix} {
+  &.pull-left { margin-right: .3em; }
+  &.pull-right { margin-left: .3em; }
+}
diff --git a/hubs/static/font-awesome-4.6.3/less/core.less b/hubs/static/font-awesome-4.6.3/less/core.less
new file mode 100644
index 0000000..c577ac8
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/core.less
@@ -0,0 +1,12 @@
+// Base Class Definition
+// -------------------------
+
+.@{fa-css-prefix} {
+  display: inline-block;
+  font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
+  font-size: inherit; // can't have font-size inherit on line above, so need to override
+  text-rendering: auto; // optimizelegibility throws things off #1094
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+
+}
diff --git a/hubs/static/font-awesome-4.6.3/less/fixed-width.less b/hubs/static/font-awesome-4.6.3/less/fixed-width.less
new file mode 100644
index 0000000..110289f
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/fixed-width.less
@@ -0,0 +1,6 @@
+// Fixed Width Icons
+// -------------------------
+.@{fa-css-prefix}-fw {
+  width: (18em / 14);
+  text-align: center;
+}
diff --git a/hubs/static/font-awesome-4.6.3/less/font-awesome.less b/hubs/static/font-awesome-4.6.3/less/font-awesome.less
new file mode 100644
index 0000000..c44e5f4
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/font-awesome.less
@@ -0,0 +1,18 @@
+/*!
+ *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */
+
+@import "variables.less";
+@import "mixins.less";
+@import "path.less";
+@import "core.less";
+@import "larger.less";
+@import "fixed-width.less";
+@import "list.less";
+@import "bordered-pulled.less";
+@import "animated.less";
+@import "rotated-flipped.less";
+@import "stacked.less";
+@import "icons.less";
+@import "screen-reader.less";
diff --git a/hubs/static/font-awesome-4.6.3/less/icons.less b/hubs/static/font-awesome-4.6.3/less/icons.less
new file mode 100644
index 0000000..ba21b22
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/icons.less
@@ -0,0 +1,733 @@
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+   readers do not read off random characters that represent icons */
+
+.@{fa-css-prefix}-glass:before { content: @fa-var-glass; }
+.@{fa-css-prefix}-music:before { content: @fa-var-music; }
+.@{fa-css-prefix}-search:before { content: @fa-var-search; }
+.@{fa-css-prefix}-envelope-o:before { content: @fa-var-envelope-o; }
+.@{fa-css-prefix}-heart:before { content: @fa-var-heart; }
+.@{fa-css-prefix}-star:before { content: @fa-var-star; }
+.@{fa-css-prefix}-star-o:before { content: @fa-var-star-o; }
+.@{fa-css-prefix}-user:before { content: @fa-var-user; }
+.@{fa-css-prefix}-film:before { content: @fa-var-film; }
+.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; }
+.@{fa-css-prefix}-th:before { content: @fa-var-th; }
+.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; }
+.@{fa-css-prefix}-check:before { content: @fa-var-check; }
+.@{fa-css-prefix}-remove:before,
+.@{fa-css-prefix}-close:before,
+.@{fa-css-prefix}-times:before { content: @fa-var-times; }
+.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; }
+.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; }
+.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; }
+.@{fa-css-prefix}-signal:before { content: @fa-var-signal; }
+.@{fa-css-prefix}-gear:before,
+.@{fa-css-prefix}-cog:before { content: @fa-var-cog; }
+.@{fa-css-prefix}-trash-o:before { content: @fa-var-trash-o; }
+.@{fa-css-prefix}-home:before { content: @fa-var-home; }
+.@{fa-css-prefix}-file-o:before { content: @fa-var-file-o; }
+.@{fa-css-prefix}-clock-o:before { content: @fa-var-clock-o; }
+.@{fa-css-prefix}-road:before { content: @fa-var-road; }
+.@{fa-css-prefix}-download:before { content: @fa-var-download; }
+.@{fa-css-prefix}-arrow-circle-o-down:before { content: @fa-var-arrow-circle-o-down; }
+.@{fa-css-prefix}-arrow-circle-o-up:before { content: @fa-var-arrow-circle-o-up; }
+.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; }
+.@{fa-css-prefix}-play-circle-o:before { content: @fa-var-play-circle-o; }
+.@{fa-css-prefix}-rotate-right:before,
+.@{fa-css-prefix}-repeat:before { content: @fa-var-repeat; }
+.@{fa-css-prefix}-refresh:before { content: @fa-var-refresh; }
+.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; }
+.@{fa-css-prefix}-lock:before { content: @fa-var-lock; }
+.@{fa-css-prefix}-flag:before { content: @fa-var-flag; }
+.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; }
+.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; }
+.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; }
+.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; }
+.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; }
+.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; }
+.@{fa-css-prefix}-tag:before { content: @fa-var-tag; }
+.@{fa-css-prefix}-tags:before { content: @fa-var-tags; }
+.@{fa-css-prefix}-book:before { content: @fa-var-book; }
+.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; }
+.@{fa-css-prefix}-print:before { content: @fa-var-print; }
+.@{fa-css-prefix}-camera:before { content: @fa-var-camera; }
+.@{fa-css-prefix}-font:before { content: @fa-var-font; }
+.@{fa-css-prefix}-bold:before { content: @fa-var-bold; }
+.@{fa-css-prefix}-italic:before { content: @fa-var-italic; }
+.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; }
+.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; }
+.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; }
+.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; }
+.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; }
+.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; }
+.@{fa-css-prefix}-list:before { content: @fa-var-list; }
+.@{fa-css-prefix}-dedent:before,
+.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; }
+.@{fa-css-prefix}-indent:before { content: @fa-var-indent; }
+.@{fa-css-prefix}-video-camera:before { content: @fa-var-video-camera; }
+.@{fa-css-prefix}-photo:before,
+.@{fa-css-prefix}-image:before,
+.@{fa-css-prefix}-picture-o:before { content: @fa-var-picture-o; }
+.@{fa-css-prefix}-pencil:before { content: @fa-var-pencil; }
+.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; }
+.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; }
+.@{fa-css-prefix}-tint:before { content: @fa-var-tint; }
+.@{fa-css-prefix}-edit:before,
+.@{fa-css-prefix}-pencil-square-o:before { content: @fa-var-pencil-square-o; }
+.@{fa-css-prefix}-share-square-o:before { content: @fa-var-share-square-o; }
+.@{fa-css-prefix}-check-square-o:before { content: @fa-var-check-square-o; }
+.@{fa-css-prefix}-arrows:before { content: @fa-var-arrows; }
+.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; }
+.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; }
+.@{fa-css-prefix}-backward:before { content: @fa-var-backward; }
+.@{fa-css-prefix}-play:before { content: @fa-var-play; }
+.@{fa-css-prefix}-pause:before { content: @fa-var-pause; }
+.@{fa-css-prefix}-stop:before { content: @fa-var-stop; }
+.@{fa-css-prefix}-forward:before { content: @fa-var-forward; }
+.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; }
+.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; }
+.@{fa-css-prefix}-eject:before { content: @fa-var-eject; }
+.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; }
+.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; }
+.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; }
+.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; }
+.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; }
+.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; }
+.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; }
+.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; }
+.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; }
+.@{fa-css-prefix}-times-circle-o:before { content: @fa-var-times-circle-o; }
+.@{fa-css-prefix}-check-circle-o:before { content: @fa-var-check-circle-o; }
+.@{fa-css-prefix}-ban:before { content: @fa-var-ban; }
+.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; }
+.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; }
+.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; }
+.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; }
+.@{fa-css-prefix}-mail-forward:before,
+.@{fa-css-prefix}-share:before { content: @fa-var-share; }
+.@{fa-css-prefix}-expand:before { content: @fa-var-expand; }
+.@{fa-css-prefix}-compress:before { content: @fa-var-compress; }
+.@{fa-css-prefix}-plus:before { content: @fa-var-plus; }
+.@{fa-css-prefix}-minus:before { content: @fa-var-minus; }
+.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; }
+.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; }
+.@{fa-css-prefix}-gift:before { content: @fa-var-gift; }
+.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; }
+.@{fa-css-prefix}-fire:before { content: @fa-var-fire; }
+.@{fa-css-prefix}-eye:before { content: @fa-var-eye; }
+.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; }
+.@{fa-css-prefix}-warning:before,
+.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; }
+.@{fa-css-prefix}-plane:before { content: @fa-var-plane; }
+.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; }
+.@{fa-css-prefix}-random:before { content: @fa-var-random; }
+.@{fa-css-prefix}-comment:before { content: @fa-var-comment; }
+.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; }
+.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; }
+.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; }
+.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; }
+.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; }
+.@{fa-css-prefix}-folder:before { content: @fa-var-folder; }
+.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; }
+.@{fa-css-prefix}-arrows-v:before { content: @fa-var-arrows-v; }
+.@{fa-css-prefix}-arrows-h:before { content: @fa-var-arrows-h; }
+.@{fa-css-prefix}-bar-chart-o:before,
+.@{fa-css-prefix}-bar-chart:before { content: @fa-var-bar-chart; }
+.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; }
+.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; }
+.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; }
+.@{fa-css-prefix}-key:before { content: @fa-var-key; }
+.@{fa-css-prefix}-gears:before,
+.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; }
+.@{fa-css-prefix}-comments:before { content: @fa-var-comments; }
+.@{fa-css-prefix}-thumbs-o-up:before { content: @fa-var-thumbs-o-up; }
+.@{fa-css-prefix}-thumbs-o-down:before { content: @fa-var-thumbs-o-down; }
+.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; }
+.@{fa-css-prefix}-heart-o:before { content: @fa-var-heart-o; }
+.@{fa-css-prefix}-sign-out:before { content: @fa-var-sign-out; }
+.@{fa-css-prefix}-linkedin-square:before { content: @fa-var-linkedin-square; }
+.@{fa-css-prefix}-thumb-tack:before { content: @fa-var-thumb-tack; }
+.@{fa-css-prefix}-external-link:before { content: @fa-var-external-link; }
+.@{fa-css-prefix}-sign-in:before { content: @fa-var-sign-in; }
+.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; }
+.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; }
+.@{fa-css-prefix}-upload:before { content: @fa-var-upload; }
+.@{fa-css-prefix}-lemon-o:before { content: @fa-var-lemon-o; }
+.@{fa-css-prefix}-phone:before { content: @fa-var-phone; }
+.@{fa-css-prefix}-square-o:before { content: @fa-var-square-o; }
+.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; }
+.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; }
+.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; }
+.@{fa-css-prefix}-facebook-f:before,
+.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; }
+.@{fa-css-prefix}-github:before { content: @fa-var-github; }
+.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; }
+.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; }
+.@{fa-css-prefix}-feed:before,
+.@{fa-css-prefix}-rss:before { content: @fa-var-rss; }
+.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; }
+.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; }
+.@{fa-css-prefix}-bell:before { content: @fa-var-bell; }
+.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; }
+.@{fa-css-prefix}-hand-o-right:before { content: @fa-var-hand-o-right; }
+.@{fa-css-prefix}-hand-o-left:before { content: @fa-var-hand-o-left; }
+.@{fa-css-prefix}-hand-o-up:before { content: @fa-var-hand-o-up; }
+.@{fa-css-prefix}-hand-o-down:before { content: @fa-var-hand-o-down; }
+.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; }
+.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; }
+.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; }
+.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; }
+.@{fa-css-prefix}-globe:before { content: @fa-var-globe; }
+.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; }
+.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; }
+.@{fa-css-prefix}-filter:before { content: @fa-var-filter; }
+.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; }
+.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; }
+.@{fa-css-prefix}-group:before,
+.@{fa-css-prefix}-users:before { content: @fa-var-users; }
+.@{fa-css-prefix}-chain:before,
+.@{fa-css-prefix}-link:before { content: @fa-var-link; }
+.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; }
+.@{fa-css-prefix}-flask:before { content: @fa-var-flask; }
+.@{fa-css-prefix}-cut:before,
+.@{fa-css-prefix}-scissors:before { content: @fa-var-scissors; }
+.@{fa-css-prefix}-copy:before,
+.@{fa-css-prefix}-files-o:before { content: @fa-var-files-o; }
+.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; }
+.@{fa-css-prefix}-save:before,
+.@{fa-css-prefix}-floppy-o:before { content: @fa-var-floppy-o; }
+.@{fa-css-prefix}-square:before { content: @fa-var-square; }
+.@{fa-css-prefix}-navicon:before,
+.@{fa-css-prefix}-reorder:before,
+.@{fa-css-prefix}-bars:before { content: @fa-var-bars; }
+.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; }
+.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; }
+.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; }
+.@{fa-css-prefix}-underline:before { content: @fa-var-underline; }
+.@{fa-css-prefix}-table:before { content: @fa-var-table; }
+.@{fa-css-prefix}-magic:before { content: @fa-var-magic; }
+.@{fa-css-prefix}-truck:before { content: @fa-var-truck; }
+.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; }
+.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; }
+.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; }
+.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; }
+.@{fa-css-prefix}-money:before { content: @fa-var-money; }
+.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; }
+.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; }
+.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; }
+.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; }
+.@{fa-css-prefix}-columns:before { content: @fa-var-columns; }
+.@{fa-css-prefix}-unsorted:before,
+.@{fa-css-prefix}-sort:before { content: @fa-var-sort; }
+.@{fa-css-prefix}-sort-down:before,
+.@{fa-css-prefix}-sort-desc:before { content: @fa-var-sort-desc; }
+.@{fa-css-prefix}-sort-up:before,
+.@{fa-css-prefix}-sort-asc:before { content: @fa-var-sort-asc; }
+.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; }
+.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; }
+.@{fa-css-prefix}-rotate-left:before,
+.@{fa-css-prefix}-undo:before { content: @fa-var-undo; }
+.@{fa-css-prefix}-legal:before,
+.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; }
+.@{fa-css-prefix}-dashboard:before,
+.@{fa-css-prefix}-tachometer:before { content: @fa-var-tachometer; }
+.@{fa-css-prefix}-comment-o:before { content: @fa-var-comment-o; }
+.@{fa-css-prefix}-comments-o:before { content: @fa-var-comments-o; }
+.@{fa-css-prefix}-flash:before,
+.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; }
+.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; }
+.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; }
+.@{fa-css-prefix}-paste:before,
+.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; }
+.@{fa-css-prefix}-lightbulb-o:before { content: @fa-var-lightbulb-o; }
+.@{fa-css-prefix}-exchange:before { content: @fa-var-exchange; }
+.@{fa-css-prefix}-cloud-download:before { content: @fa-var-cloud-download; }
+.@{fa-css-prefix}-cloud-upload:before { content: @fa-var-cloud-upload; }
+.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; }
+.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; }
+.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; }
+.@{fa-css-prefix}-bell-o:before { content: @fa-var-bell-o; }
+.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; }
+.@{fa-css-prefix}-cutlery:before { content: @fa-var-cutlery; }
+.@{fa-css-prefix}-file-text-o:before { content: @fa-var-file-text-o; }
+.@{fa-css-prefix}-building-o:before { content: @fa-var-building-o; }
+.@{fa-css-prefix}-hospital-o:before { content: @fa-var-hospital-o; }
+.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; }
+.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; }
+.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; }
+.@{fa-css-prefix}-beer:before { content: @fa-var-beer; }
+.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; }
+.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; }
+.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; }
+.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; }
+.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; }
+.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; }
+.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; }
+.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; }
+.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; }
+.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; }
+.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; }
+.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; }
+.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; }
+.@{fa-css-prefix}-mobile-phone:before,
+.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; }
+.@{fa-css-prefix}-circle-o:before { content: @fa-var-circle-o; }
+.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; }
+.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; }
+.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; }
+.@{fa-css-prefix}-circle:before { content: @fa-var-circle; }
+.@{fa-css-prefix}-mail-reply:before,
+.@{fa-css-prefix}-reply:before { content: @fa-var-reply; }
+.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; }
+.@{fa-css-prefix}-folder-o:before { content: @fa-var-folder-o; }
+.@{fa-css-prefix}-folder-open-o:before { content: @fa-var-folder-open-o; }
+.@{fa-css-prefix}-smile-o:before { content: @fa-var-smile-o; }
+.@{fa-css-prefix}-frown-o:before { content: @fa-var-frown-o; }
+.@{fa-css-prefix}-meh-o:before { content: @fa-var-meh-o; }
+.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; }
+.@{fa-css-prefix}-keyboard-o:before { content: @fa-var-keyboard-o; }
+.@{fa-css-prefix}-flag-o:before { content: @fa-var-flag-o; }
+.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; }
+.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; }
+.@{fa-css-prefix}-code:before { content: @fa-var-code; }
+.@{fa-css-prefix}-mail-reply-all:before,
+.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; }
+.@{fa-css-prefix}-star-half-empty:before,
+.@{fa-css-prefix}-star-half-full:before,
+.@{fa-css-prefix}-star-half-o:before { content: @fa-var-star-half-o; }
+.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; }
+.@{fa-css-prefix}-crop:before { content: @fa-var-crop; }
+.@{fa-css-prefix}-code-fork:before { content: @fa-var-code-fork; }
+.@{fa-css-prefix}-unlink:before,
+.@{fa-css-prefix}-chain-broken:before { content: @fa-var-chain-broken; }
+.@{fa-css-prefix}-question:before { content: @fa-var-question; }
+.@{fa-css-prefix}-info:before { content: @fa-var-info; }
+.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; }
+.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; }
+.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; }
+.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; }
+.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; }
+.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; }
+.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; }
+.@{fa-css-prefix}-shield:before { content: @fa-var-shield; }
+.@{fa-css-prefix}-calendar-o:before { content: @fa-var-calendar-o; }
+.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; }
+.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; }
+.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; }
+.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; }
+.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; }
+.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; }
+.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; }
+.@{fa-css-prefix}-html5:before { content: @fa-var-html5; }
+.@{fa-css-prefix}-css3:before { content: @fa-var-css3; }
+.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; }
+.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; }
+.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; }
+.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; }
+.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; }
+.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; }
+.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; }
+.@{fa-css-prefix}-ticket:before { content: @fa-var-ticket; }
+.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; }
+.@{fa-css-prefix}-minus-square-o:before { content: @fa-var-minus-square-o; }
+.@{fa-css-prefix}-level-up:before { content: @fa-var-level-up; }
+.@{fa-css-prefix}-level-down:before { content: @fa-var-level-down; }
+.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; }
+.@{fa-css-prefix}-pencil-square:before { content: @fa-var-pencil-square; }
+.@{fa-css-prefix}-external-link-square:before { content: @fa-var-external-link-square; }
+.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; }
+.@{fa-css-prefix}-compass:before { content: @fa-var-compass; }
+.@{fa-css-prefix}-toggle-down:before,
+.@{fa-css-prefix}-caret-square-o-down:before { content: @fa-var-caret-square-o-down; }
+.@{fa-css-prefix}-toggle-up:before,
+.@{fa-css-prefix}-caret-square-o-up:before { content: @fa-var-caret-square-o-up; }
+.@{fa-css-prefix}-toggle-right:before,
+.@{fa-css-prefix}-caret-square-o-right:before { content: @fa-var-caret-square-o-right; }
+.@{fa-css-prefix}-euro:before,
+.@{fa-css-prefix}-eur:before { content: @fa-var-eur; }
+.@{fa-css-prefix}-gbp:before { content: @fa-var-gbp; }
+.@{fa-css-prefix}-dollar:before,
+.@{fa-css-prefix}-usd:before { content: @fa-var-usd; }
+.@{fa-css-prefix}-rupee:before,
+.@{fa-css-prefix}-inr:before { content: @fa-var-inr; }
+.@{fa-css-prefix}-cny:before,
+.@{fa-css-prefix}-rmb:before,
+.@{fa-css-prefix}-yen:before,
+.@{fa-css-prefix}-jpy:before { content: @fa-var-jpy; }
+.@{fa-css-prefix}-ruble:before,
+.@{fa-css-prefix}-rouble:before,
+.@{fa-css-prefix}-rub:before { content: @fa-var-rub; }
+.@{fa-css-prefix}-won:before,
+.@{fa-css-prefix}-krw:before { content: @fa-var-krw; }
+.@{fa-css-prefix}-bitcoin:before,
+.@{fa-css-prefix}-btc:before { content: @fa-var-btc; }
+.@{fa-css-prefix}-file:before { content: @fa-var-file; }
+.@{fa-css-prefix}-file-text:before { content: @fa-var-file-text; }
+.@{fa-css-prefix}-sort-alpha-asc:before { content: @fa-var-sort-alpha-asc; }
+.@{fa-css-prefix}-sort-alpha-desc:before { content: @fa-var-sort-alpha-desc; }
+.@{fa-css-prefix}-sort-amount-asc:before { content: @fa-var-sort-amount-asc; }
+.@{fa-css-prefix}-sort-amount-desc:before { content: @fa-var-sort-amount-desc; }
+.@{fa-css-prefix}-sort-numeric-asc:before { content: @fa-var-sort-numeric-asc; }
+.@{fa-css-prefix}-sort-numeric-desc:before { content: @fa-var-sort-numeric-desc; }
+.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; }
+.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; }
+.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; }
+.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; }
+.@{fa-css-prefix}-xing:before { content: @fa-var-xing; }
+.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; }
+.@{fa-css-prefix}-youtube-play:before { content: @fa-var-youtube-play; }
+.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; }
+.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; }
+.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; }
+.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; }
+.@{fa-css-prefix}-adn:before { content: @fa-var-adn; }
+.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; }
+.@{fa-css-prefix}-bitbucket-square:before { content: @fa-var-bitbucket-square; }
+.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; }
+.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; }
+.@{fa-css-prefix}-long-arrow-down:before { content: @fa-var-long-arrow-down; }
+.@{fa-css-prefix}-long-arrow-up:before { content: @fa-var-long-arrow-up; }
+.@{fa-css-prefix}-long-arrow-left:before { content: @fa-var-long-arrow-left; }
+.@{fa-css-prefix}-long-arrow-right:before { content: @fa-var-long-arrow-right; }
+.@{fa-css-prefix}-apple:before { content: @fa-var-apple; }
+.@{fa-css-prefix}-windows:before { content: @fa-var-windows; }
+.@{fa-css-prefix}-android:before { content: @fa-var-android; }
+.@{fa-css-prefix}-linux:before { content: @fa-var-linux; }
+.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; }
+.@{fa-css-prefix}-skype:before { content: @fa-var-skype; }
+.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; }
+.@{fa-css-prefix}-trello:before { content: @fa-var-trello; }
+.@{fa-css-prefix}-female:before { content: @fa-var-female; }
+.@{fa-css-prefix}-male:before { content: @fa-var-male; }
+.@{fa-css-prefix}-gittip:before,
+.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; }
+.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; }
+.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; }
+.@{fa-css-prefix}-archive:before { content: @fa-var-archive; }
+.@{fa-css-prefix}-bug:before { content: @fa-var-bug; }
+.@{fa-css-prefix}-vk:before { content: @fa-var-vk; }
+.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; }
+.@{fa-css-prefix}-renren:before { content: @fa-var-renren; }
+.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; }
+.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; }
+.@{fa-css-prefix}-arrow-circle-o-right:before { content: @fa-var-arrow-circle-o-right; }
+.@{fa-css-prefix}-arrow-circle-o-left:before { content: @fa-var-arrow-circle-o-left; }
+.@{fa-css-prefix}-toggle-left:before,
+.@{fa-css-prefix}-caret-square-o-left:before { content: @fa-var-caret-square-o-left; }
+.@{fa-css-prefix}-dot-circle-o:before { content: @fa-var-dot-circle-o; }
+.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; }
+.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; }
+.@{fa-css-prefix}-turkish-lira:before,
+.@{fa-css-prefix}-try:before { content: @fa-var-try; }
+.@{fa-css-prefix}-plus-square-o:before { content: @fa-var-plus-square-o; }
+.@{fa-css-prefix}-space-shuttle:before { content: @fa-var-space-shuttle; }
+.@{fa-css-prefix}-slack:before { content: @fa-var-slack; }
+.@{fa-css-prefix}-envelope-square:before { content: @fa-var-envelope-square; }
+.@{fa-css-prefix}-wordpress:before { content: @fa-var-wordpress; }
+.@{fa-css-prefix}-openid:before { content: @fa-var-openid; }
+.@{fa-css-prefix}-institution:before,
+.@{fa-css-prefix}-bank:before,
+.@{fa-css-prefix}-university:before { content: @fa-var-university; }
+.@{fa-css-prefix}-mortar-board:before,
+.@{fa-css-prefix}-graduation-cap:before { content: @fa-var-graduation-cap; }
+.@{fa-css-prefix}-yahoo:before { content: @fa-var-yahoo; }
+.@{fa-css-prefix}-google:before { content: @fa-var-google; }
+.@{fa-css-prefix}-reddit:before { content: @fa-var-reddit; }
+.@{fa-css-prefix}-reddit-square:before { content: @fa-var-reddit-square; }
+.@{fa-css-prefix}-stumbleupon-circle:before { content: @fa-var-stumbleupon-circle; }
+.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; }
+.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; }
+.@{fa-css-prefix}-digg:before { content: @fa-var-digg; }
+.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; }
+.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; }
+.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; }
+.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; }
+.@{fa-css-prefix}-language:before { content: @fa-var-language; }
+.@{fa-css-prefix}-fax:before { content: @fa-var-fax; }
+.@{fa-css-prefix}-building:before { content: @fa-var-building; }
+.@{fa-css-prefix}-child:before { content: @fa-var-child; }
+.@{fa-css-prefix}-paw:before { content: @fa-var-paw; }
+.@{fa-css-prefix}-spoon:before { content: @fa-var-spoon; }
+.@{fa-css-prefix}-cube:before { content: @fa-var-cube; }
+.@{fa-css-prefix}-cubes:before { content: @fa-var-cubes; }
+.@{fa-css-prefix}-behance:before { content: @fa-var-behance; }
+.@{fa-css-prefix}-behance-square:before { content: @fa-var-behance-square; }
+.@{fa-css-prefix}-steam:before { content: @fa-var-steam; }
+.@{fa-css-prefix}-steam-square:before { content: @fa-var-steam-square; }
+.@{fa-css-prefix}-recycle:before { content: @fa-var-recycle; }
+.@{fa-css-prefix}-automobile:before,
+.@{fa-css-prefix}-car:before { content: @fa-var-car; }
+.@{fa-css-prefix}-cab:before,
+.@{fa-css-prefix}-taxi:before { content: @fa-var-taxi; }
+.@{fa-css-prefix}-tree:before { content: @fa-var-tree; }
+.@{fa-css-prefix}-spotify:before { content: @fa-var-spotify; }
+.@{fa-css-prefix}-deviantart:before { content: @fa-var-deviantart; }
+.@{fa-css-prefix}-soundcloud:before { content: @fa-var-soundcloud; }
+.@{fa-css-prefix}-database:before { content: @fa-var-database; }
+.@{fa-css-prefix}-file-pdf-o:before { content: @fa-var-file-pdf-o; }
+.@{fa-css-prefix}-file-word-o:before { content: @fa-var-file-word-o; }
+.@{fa-css-prefix}-file-excel-o:before { content: @fa-var-file-excel-o; }
+.@{fa-css-prefix}-file-powerpoint-o:before { content: @fa-var-file-powerpoint-o; }
+.@{fa-css-prefix}-file-photo-o:before,
+.@{fa-css-prefix}-file-picture-o:before,
+.@{fa-css-prefix}-file-image-o:before { content: @fa-var-file-image-o; }
+.@{fa-css-prefix}-file-zip-o:before,
+.@{fa-css-prefix}-file-archive-o:before { content: @fa-var-file-archive-o; }
+.@{fa-css-prefix}-file-sound-o:before,
+.@{fa-css-prefix}-file-audio-o:before { content: @fa-var-file-audio-o; }
+.@{fa-css-prefix}-file-movie-o:before,
+.@{fa-css-prefix}-file-video-o:before { content: @fa-var-file-video-o; }
+.@{fa-css-prefix}-file-code-o:before { content: @fa-var-file-code-o; }
+.@{fa-css-prefix}-vine:before { content: @fa-var-vine; }
+.@{fa-css-prefix}-codepen:before { content: @fa-var-codepen; }
+.@{fa-css-prefix}-jsfiddle:before { content: @fa-var-jsfiddle; }
+.@{fa-css-prefix}-life-bouy:before,
+.@{fa-css-prefix}-life-buoy:before,
+.@{fa-css-prefix}-life-saver:before,
+.@{fa-css-prefix}-support:before,
+.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; }
+.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; }
+.@{fa-css-prefix}-ra:before,
+.@{fa-css-prefix}-resistance:before,
+.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; }
+.@{fa-css-prefix}-ge:before,
+.@{fa-css-prefix}-empire:before { content: @fa-var-empire; }
+.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; }
+.@{fa-css-prefix}-git:before { content: @fa-var-git; }
+.@{fa-css-prefix}-y-combinator-square:before,
+.@{fa-css-prefix}-yc-square:before,
+.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; }
+.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; }
+.@{fa-css-prefix}-qq:before { content: @fa-var-qq; }
+.@{fa-css-prefix}-wechat:before,
+.@{fa-css-prefix}-weixin:before { content: @fa-var-weixin; }
+.@{fa-css-prefix}-send:before,
+.@{fa-css-prefix}-paper-plane:before { content: @fa-var-paper-plane; }
+.@{fa-css-prefix}-send-o:before,
+.@{fa-css-prefix}-paper-plane-o:before { content: @fa-var-paper-plane-o; }
+.@{fa-css-prefix}-history:before { content: @fa-var-history; }
+.@{fa-css-prefix}-circle-thin:before { content: @fa-var-circle-thin; }
+.@{fa-css-prefix}-header:before { content: @fa-var-header; }
+.@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; }
+.@{fa-css-prefix}-sliders:before { content: @fa-var-sliders; }
+.@{fa-css-prefix}-share-alt:before { content: @fa-var-share-alt; }
+.@{fa-css-prefix}-share-alt-square:before { content: @fa-var-share-alt-square; }
+.@{fa-css-prefix}-bomb:before { content: @fa-var-bomb; }
+.@{fa-css-prefix}-soccer-ball-o:before,
+.@{fa-css-prefix}-futbol-o:before { content: @fa-var-futbol-o; }
+.@{fa-css-prefix}-tty:before { content: @fa-var-tty; }
+.@{fa-css-prefix}-binoculars:before { content: @fa-var-binoculars; }
+.@{fa-css-prefix}-plug:before { content: @fa-var-plug; }
+.@{fa-css-prefix}-slideshare:before { content: @fa-var-slideshare; }
+.@{fa-css-prefix}-twitch:before { content: @fa-var-twitch; }
+.@{fa-css-prefix}-yelp:before { content: @fa-var-yelp; }
+.@{fa-css-prefix}-newspaper-o:before { content: @fa-var-newspaper-o; }
+.@{fa-css-prefix}-wifi:before { content: @fa-var-wifi; }
+.@{fa-css-prefix}-calculator:before { content: @fa-var-calculator; }
+.@{fa-css-prefix}-paypal:before { content: @fa-var-paypal; }
+.@{fa-css-prefix}-google-wallet:before { content: @fa-var-google-wallet; }
+.@{fa-css-prefix}-cc-visa:before { content: @fa-var-cc-visa; }
+.@{fa-css-prefix}-cc-mastercard:before { content: @fa-var-cc-mastercard; }
+.@{fa-css-prefix}-cc-discover:before { content: @fa-var-cc-discover; }
+.@{fa-css-prefix}-cc-amex:before { content: @fa-var-cc-amex; }
+.@{fa-css-prefix}-cc-paypal:before { content: @fa-var-cc-paypal; }
+.@{fa-css-prefix}-cc-stripe:before { content: @fa-var-cc-stripe; }
+.@{fa-css-prefix}-bell-slash:before { content: @fa-var-bell-slash; }
+.@{fa-css-prefix}-bell-slash-o:before { content: @fa-var-bell-slash-o; }
+.@{fa-css-prefix}-trash:before { content: @fa-var-trash; }
+.@{fa-css-prefix}-copyright:before { content: @fa-var-copyright; }
+.@{fa-css-prefix}-at:before { content: @fa-var-at; }
+.@{fa-css-prefix}-eyedropper:before { content: @fa-var-eyedropper; }
+.@{fa-css-prefix}-paint-brush:before { content: @fa-var-paint-brush; }
+.@{fa-css-prefix}-birthday-cake:before { content: @fa-var-birthday-cake; }
+.@{fa-css-prefix}-area-chart:before { content: @fa-var-area-chart; }
+.@{fa-css-prefix}-pie-chart:before { content: @fa-var-pie-chart; }
+.@{fa-css-prefix}-line-chart:before { content: @fa-var-line-chart; }
+.@{fa-css-prefix}-lastfm:before { content: @fa-var-lastfm; }
+.@{fa-css-prefix}-lastfm-square:before { content: @fa-var-lastfm-square; }
+.@{fa-css-prefix}-toggle-off:before { content: @fa-var-toggle-off; }
+.@{fa-css-prefix}-toggle-on:before { content: @fa-var-toggle-on; }
+.@{fa-css-prefix}-bicycle:before { content: @fa-var-bicycle; }
+.@{fa-css-prefix}-bus:before { content: @fa-var-bus; }
+.@{fa-css-prefix}-ioxhost:before { content: @fa-var-ioxhost; }
+.@{fa-css-prefix}-angellist:before { content: @fa-var-angellist; }
+.@{fa-css-prefix}-cc:before { content: @fa-var-cc; }
+.@{fa-css-prefix}-shekel:before,
+.@{fa-css-prefix}-sheqel:before,
+.@{fa-css-prefix}-ils:before { content: @fa-var-ils; }
+.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; }
+.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; }
+.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; }
+.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; }
+.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; }
+.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; }
+.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; }
+.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; }
+.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; }
+.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; }
+.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; }
+.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; }
+.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; }
+.@{fa-css-prefix}-ship:before { content: @fa-var-ship; }
+.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; }
+.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; }
+.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; }
+.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; }
+.@{fa-css-prefix}-venus:before { content: @fa-var-venus; }
+.@{fa-css-prefix}-mars:before { content: @fa-var-mars; }
+.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; }
+.@{fa-css-prefix}-intersex:before,
+.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; }
+.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; }
+.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; }
+.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; }
+.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; }
+.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; }
+.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; }
+.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; }
+.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; }
+.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; }
+.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; }
+.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; }
+.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; }
+.@{fa-css-prefix}-server:before { content: @fa-var-server; }
+.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; }
+.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; }
+.@{fa-css-prefix}-hotel:before,
+.@{fa-css-prefix}-bed:before { content: @fa-var-bed; }
+.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; }
+.@{fa-css-prefix}-train:before { content: @fa-var-train; }
+.@{fa-css-prefix}-subway:before { content: @fa-var-subway; }
+.@{fa-css-prefix}-medium:before { content: @fa-var-medium; }
+.@{fa-css-prefix}-yc:before,
+.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; }
+.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; }
+.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; }
+.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; }
+.@{fa-css-prefix}-battery-4:before,
+.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; }
+.@{fa-css-prefix}-battery-3:before,
+.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; }
+.@{fa-css-prefix}-battery-2:before,
+.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; }
+.@{fa-css-prefix}-battery-1:before,
+.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; }
+.@{fa-css-prefix}-battery-0:before,
+.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; }
+.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; }
+.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; }
+.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; }
+.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; }
+.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; }
+.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; }
+.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; }
+.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; }
+.@{fa-css-prefix}-clone:before { content: @fa-var-clone; }
+.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; }
+.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; }
+.@{fa-css-prefix}-hourglass-1:before,
+.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; }
+.@{fa-css-prefix}-hourglass-2:before,
+.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; }
+.@{fa-css-prefix}-hourglass-3:before,
+.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; }
+.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; }
+.@{fa-css-prefix}-hand-grab-o:before,
+.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; }
+.@{fa-css-prefix}-hand-stop-o:before,
+.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; }
+.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; }
+.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; }
+.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; }
+.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; }
+.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; }
+.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; }
+.@{fa-css-prefix}-registered:before { content: @fa-var-registered; }
+.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; }
+.@{fa-css-prefix}-gg:before { content: @fa-var-gg; }
+.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; }
+.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; }
+.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; }
+.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; }
+.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; }
+.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; }
+.@{fa-css-prefix}-safari:before { content: @fa-var-safari; }
+.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; }
+.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; }
+.@{fa-css-prefix}-opera:before { content: @fa-var-opera; }
+.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; }
+.@{fa-css-prefix}-tv:before,
+.@{fa-css-prefix}-television:before { content: @fa-var-television; }
+.@{fa-css-prefix}-contao:before { content: @fa-var-contao; }
+.@{fa-css-prefix}-500px:before { content: @fa-var-500px; }
+.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; }
+.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; }
+.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; }
+.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; }
+.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; }
+.@{fa-css-prefix}-industry:before { content: @fa-var-industry; }
+.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; }
+.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; }
+.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; }
+.@{fa-css-prefix}-map:before { content: @fa-var-map; }
+.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; }
+.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; }
+.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; }
+.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; }
+.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; }
+.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; }
+.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; }
+.@{fa-css-prefix}-edge:before { content: @fa-var-edge; }
+.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; }
+.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; }
+.@{fa-css-prefix}-modx:before { content: @fa-var-modx; }
+.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; }
+.@{fa-css-prefix}-usb:before { content: @fa-var-usb; }
+.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; }
+.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; }
+.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; }
+.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; }
+.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; }
+.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; }
+.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; }
+.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; }
+.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; }
+.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; }
+.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; }
+.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; }
+.@{fa-css-prefix}-percent:before { content: @fa-var-percent; }
+.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; }
+.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; }
+.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; }
+.@{fa-css-prefix}-envira:before { content: @fa-var-envira; }
+.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; }
+.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; }
+.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; }
+.@{fa-css-prefix}-blind:before { content: @fa-var-blind; }
+.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; }
+.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; }
+.@{fa-css-prefix}-braille:before { content: @fa-var-braille; }
+.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; }
+.@{fa-css-prefix}-asl-interpreting:before,
+.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; }
+.@{fa-css-prefix}-deafness:before,
+.@{fa-css-prefix}-hard-of-hearing:before,
+.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; }
+.@{fa-css-prefix}-glide:before { content: @fa-var-glide; }
+.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; }
+.@{fa-css-prefix}-signing:before,
+.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; }
+.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; }
+.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; }
+.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; }
+.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; }
+.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; }
+.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; }
+.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
+.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; }
+.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; }
+.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; }
+.@{fa-css-prefix}-google-plus-circle:before,
+.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; }
+.@{fa-css-prefix}-fa:before,
+.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; }
diff --git a/hubs/static/font-awesome-4.6.3/less/larger.less b/hubs/static/font-awesome-4.6.3/less/larger.less
new file mode 100644
index 0000000..c9d6467
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/larger.less
@@ -0,0 +1,13 @@
+// Icon Sizes
+// -------------------------
+
+/* makes the font 33% larger relative to the icon container */
+.@{fa-css-prefix}-lg {
+  font-size: (4em / 3);
+  line-height: (3em / 4);
+  vertical-align: -15%;
+}
+.@{fa-css-prefix}-2x { font-size: 2em; }
+.@{fa-css-prefix}-3x { font-size: 3em; }
+.@{fa-css-prefix}-4x { font-size: 4em; }
+.@{fa-css-prefix}-5x { font-size: 5em; }
diff --git a/hubs/static/font-awesome-4.6.3/less/list.less b/hubs/static/font-awesome-4.6.3/less/list.less
new file mode 100644
index 0000000..0b44038
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/list.less
@@ -0,0 +1,19 @@
+// List Icons
+// -------------------------
+
+.@{fa-css-prefix}-ul {
+  padding-left: 0;
+  margin-left: @fa-li-width;
+  list-style-type: none;
+  > li { position: relative; }
+}
+.@{fa-css-prefix}-li {
+  position: absolute;
+  left: -@fa-li-width;
+  width: @fa-li-width;
+  top: (2em / 14);
+  text-align: center;
+  &.@{fa-css-prefix}-lg {
+    left: (-@fa-li-width + (4em / 14));
+  }
+}
diff --git a/hubs/static/font-awesome-4.6.3/less/mixins.less b/hubs/static/font-awesome-4.6.3/less/mixins.less
new file mode 100644
index 0000000..beef231
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/mixins.less
@@ -0,0 +1,60 @@
+// Mixins
+// --------------------------
+
+.fa-icon() {
+  display: inline-block;
+  font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
+  font-size: inherit; // can't have font-size inherit on line above, so need to override
+  text-rendering: auto; // optimizelegibility throws things off #1094
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+
+}
+
+.fa-icon-rotate(@degrees, @rotation) {
+  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
+  -webkit-transform: rotate(@degrees);
+      -ms-transform: rotate(@degrees);
+          transform: rotate(@degrees);
+}
+
+.fa-icon-flip(@horiz, @vert, @rotation) {
+  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
+  -webkit-transform: scale(@horiz, @vert);
+      -ms-transform: scale(@horiz, @vert);
+          transform: scale(@horiz, @vert);
+}
+
+
+// Only display content to screen readers. A la Bootstrap 4.
+//
+// See: http://a11yproject.com/posts/how-to-hide-content/
+
+.sr-only() {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  padding: 0;
+  margin: -1px;
+  overflow: hidden;
+  clip: rect(0,0,0,0);
+  border: 0;
+}
+
+// Use in conjunction with .sr-only to only display content when it's focused.
+//
+// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
+//
+// Credit: HTML5 Boilerplate
+
+.sr-only-focusable() {
+  &:active,
+  &:focus {
+    position: static;
+    width: auto;
+    height: auto;
+    margin: 0;
+    overflow: visible;
+    clip: auto;
+  }
+}
diff --git a/hubs/static/font-awesome-4.6.3/less/path.less b/hubs/static/font-awesome-4.6.3/less/path.less
new file mode 100644
index 0000000..835be41
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/path.less
@@ -0,0 +1,15 @@
+/* FONT PATH
+ * -------------------------- */
+
+@font-face {
+  font-family: 'FontAwesome';
+  src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
+  src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
+    url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
+    url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
+    url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
+    url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
+  // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
+  font-weight: normal;
+  font-style: normal;
+}
diff --git a/hubs/static/font-awesome-4.6.3/less/rotated-flipped.less b/hubs/static/font-awesome-4.6.3/less/rotated-flipped.less
new file mode 100644
index 0000000..f6ba814
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/rotated-flipped.less
@@ -0,0 +1,20 @@
+// Rotated & Flipped Icons
+// -------------------------
+
+.@{fa-css-prefix}-rotate-90  { .fa-icon-rotate(90deg, 1);  }
+.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
+.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
+
+.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
+.@{fa-css-prefix}-flip-vertical   { .fa-icon-flip(1, -1, 2); }
+
+// Hook for IE8-9
+// -------------------------
+
+:root .@{fa-css-prefix}-rotate-90,
+:root .@{fa-css-prefix}-rotate-180,
+:root .@{fa-css-prefix}-rotate-270,
+:root .@{fa-css-prefix}-flip-horizontal,
+:root .@{fa-css-prefix}-flip-vertical {
+  filter: none;
+}
diff --git a/hubs/static/font-awesome-4.6.3/less/screen-reader.less b/hubs/static/font-awesome-4.6.3/less/screen-reader.less
new file mode 100644
index 0000000..11c1881
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/screen-reader.less
@@ -0,0 +1,5 @@
+// Screen Readers
+// -------------------------
+
+.sr-only { .sr-only(); }
+.sr-only-focusable { .sr-only-focusable(); }
diff --git a/hubs/static/font-awesome-4.6.3/less/stacked.less b/hubs/static/font-awesome-4.6.3/less/stacked.less
new file mode 100644
index 0000000..fc53fb0
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/stacked.less
@@ -0,0 +1,20 @@
+// Stacked Icons
+// -------------------------
+
+.@{fa-css-prefix}-stack {
+  position: relative;
+  display: inline-block;
+  width: 2em;
+  height: 2em;
+  line-height: 2em;
+  vertical-align: middle;
+}
+.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
+  position: absolute;
+  left: 0;
+  width: 100%;
+  text-align: center;
+}
+.@{fa-css-prefix}-stack-1x { line-height: inherit; }
+.@{fa-css-prefix}-stack-2x { font-size: 2em; }
+.@{fa-css-prefix}-inverse { color: @fa-inverse; }
diff --git a/hubs/static/font-awesome-4.6.3/less/variables.less b/hubs/static/font-awesome-4.6.3/less/variables.less
new file mode 100644
index 0000000..2b33819
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/less/variables.less
@@ -0,0 +1,744 @@
+// Variables
+// --------------------------
+
+@fa-font-path:        "../fonts";
+@fa-font-size-base:   14px;
+@fa-line-height-base: 1;
+//@fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.6.3/fonts"; // for referencing Bootstrap CDN font files directly
+@fa-css-prefix:       fa;
+@fa-version:          "4.6.3";
+@fa-border-color:     #eee;
+@fa-inverse:          #fff;
+@fa-li-width:         (30em / 14);
+
+@fa-var-500px: "\f26e";
+@fa-var-adjust: "\f042";
+@fa-var-adn: "\f170";
+@fa-var-align-center: "\f037";
+@fa-var-align-justify: "\f039";
+@fa-var-align-left: "\f036";
+@fa-var-align-right: "\f038";
+@fa-var-amazon: "\f270";
+@fa-var-ambulance: "\f0f9";
+@fa-var-american-sign-language-interpreting: "\f2a3";
+@fa-var-anchor: "\f13d";
+@fa-var-android: "\f17b";
+@fa-var-angellist: "\f209";
+@fa-var-angle-double-down: "\f103";
+@fa-var-angle-double-left: "\f100";
+@fa-var-angle-double-right: "\f101";
+@fa-var-angle-double-up: "\f102";
+@fa-var-angle-down: "\f107";
+@fa-var-angle-left: "\f104";
+@fa-var-angle-right: "\f105";
+@fa-var-angle-up: "\f106";
+@fa-var-apple: "\f179";
+@fa-var-archive: "\f187";
+@fa-var-area-chart: "\f1fe";
+@fa-var-arrow-circle-down: "\f0ab";
+@fa-var-arrow-circle-left: "\f0a8";
+@fa-var-arrow-circle-o-down: "\f01a";
+@fa-var-arrow-circle-o-left: "\f190";
+@fa-var-arrow-circle-o-right: "\f18e";
+@fa-var-arrow-circle-o-up: "\f01b";
+@fa-var-arrow-circle-right: "\f0a9";
+@fa-var-arrow-circle-up: "\f0aa";
+@fa-var-arrow-down: "\f063";
+@fa-var-arrow-left: "\f060";
+@fa-var-arrow-right: "\f061";
+@fa-var-arrow-up: "\f062";
+@fa-var-arrows: "\f047";
+@fa-var-arrows-alt: "\f0b2";
+@fa-var-arrows-h: "\f07e";
+@fa-var-arrows-v: "\f07d";
+@fa-var-asl-interpreting: "\f2a3";
+@fa-var-assistive-listening-systems: "\f2a2";
+@fa-var-asterisk: "\f069";
+@fa-var-at: "\f1fa";
+@fa-var-audio-description: "\f29e";
+@fa-var-automobile: "\f1b9";
+@fa-var-backward: "\f04a";
+@fa-var-balance-scale: "\f24e";
+@fa-var-ban: "\f05e";
+@fa-var-bank: "\f19c";
+@fa-var-bar-chart: "\f080";
+@fa-var-bar-chart-o: "\f080";
+@fa-var-barcode: "\f02a";
+@fa-var-bars: "\f0c9";
+@fa-var-battery-0: "\f244";
+@fa-var-battery-1: "\f243";
+@fa-var-battery-2: "\f242";
+@fa-var-battery-3: "\f241";
+@fa-var-battery-4: "\f240";
+@fa-var-battery-empty: "\f244";
+@fa-var-battery-full: "\f240";
+@fa-var-battery-half: "\f242";
+@fa-var-battery-quarter: "\f243";
+@fa-var-battery-three-quarters: "\f241";
+@fa-var-bed: "\f236";
+@fa-var-beer: "\f0fc";
+@fa-var-behance: "\f1b4";
+@fa-var-behance-square: "\f1b5";
+@fa-var-bell: "\f0f3";
+@fa-var-bell-o: "\f0a2";
+@fa-var-bell-slash: "\f1f6";
+@fa-var-bell-slash-o: "\f1f7";
+@fa-var-bicycle: "\f206";
+@fa-var-binoculars: "\f1e5";
+@fa-var-birthday-cake: "\f1fd";
+@fa-var-bitbucket: "\f171";
+@fa-var-bitbucket-square: "\f172";
+@fa-var-bitcoin: "\f15a";
+@fa-var-black-tie: "\f27e";
+@fa-var-blind: "\f29d";
+@fa-var-bluetooth: "\f293";
+@fa-var-bluetooth-b: "\f294";
+@fa-var-bold: "\f032";
+@fa-var-bolt: "\f0e7";
+@fa-var-bomb: "\f1e2";
+@fa-var-book: "\f02d";
+@fa-var-bookmark: "\f02e";
+@fa-var-bookmark-o: "\f097";
+@fa-var-braille: "\f2a1";
+@fa-var-briefcase: "\f0b1";
+@fa-var-btc: "\f15a";
+@fa-var-bug: "\f188";
+@fa-var-building: "\f1ad";
+@fa-var-building-o: "\f0f7";
+@fa-var-bullhorn: "\f0a1";
+@fa-var-bullseye: "\f140";
+@fa-var-bus: "\f207";
+@fa-var-buysellads: "\f20d";
+@fa-var-cab: "\f1ba";
+@fa-var-calculator: "\f1ec";
+@fa-var-calendar: "\f073";
+@fa-var-calendar-check-o: "\f274";
+@fa-var-calendar-minus-o: "\f272";
+@fa-var-calendar-o: "\f133";
+@fa-var-calendar-plus-o: "\f271";
+@fa-var-calendar-times-o: "\f273";
+@fa-var-camera: "\f030";
+@fa-var-camera-retro: "\f083";
+@fa-var-car: "\f1b9";
+@fa-var-caret-down: "\f0d7";
+@fa-var-caret-left: "\f0d9";
+@fa-var-caret-right: "\f0da";
+@fa-var-caret-square-o-down: "\f150";
+@fa-var-caret-square-o-left: "\f191";
+@fa-var-caret-square-o-right: "\f152";
+@fa-var-caret-square-o-up: "\f151";
+@fa-var-caret-up: "\f0d8";
+@fa-var-cart-arrow-down: "\f218";
+@fa-var-cart-plus: "\f217";
+@fa-var-cc: "\f20a";
+@fa-var-cc-amex: "\f1f3";
+@fa-var-cc-diners-club: "\f24c";
+@fa-var-cc-discover: "\f1f2";
+@fa-var-cc-jcb: "\f24b";
+@fa-var-cc-mastercard: "\f1f1";
+@fa-var-cc-paypal: "\f1f4";
+@fa-var-cc-stripe: "\f1f5";
+@fa-var-cc-visa: "\f1f0";
+@fa-var-certificate: "\f0a3";
+@fa-var-chain: "\f0c1";
+@fa-var-chain-broken: "\f127";
+@fa-var-check: "\f00c";
+@fa-var-check-circle: "\f058";
+@fa-var-check-circle-o: "\f05d";
+@fa-var-check-square: "\f14a";
+@fa-var-check-square-o: "\f046";
+@fa-var-chevron-circle-down: "\f13a";
+@fa-var-chevron-circle-left: "\f137";
+@fa-var-chevron-circle-right: "\f138";
+@fa-var-chevron-circle-up: "\f139";
+@fa-var-chevron-down: "\f078";
+@fa-var-chevron-left: "\f053";
+@fa-var-chevron-right: "\f054";
+@fa-var-chevron-up: "\f077";
+@fa-var-child: "\f1ae";
+@fa-var-chrome: "\f268";
+@fa-var-circle: "\f111";
+@fa-var-circle-o: "\f10c";
+@fa-var-circle-o-notch: "\f1ce";
+@fa-var-circle-thin: "\f1db";
+@fa-var-clipboard: "\f0ea";
+@fa-var-clock-o: "\f017";
+@fa-var-clone: "\f24d";
+@fa-var-close: "\f00d";
+@fa-var-cloud: "\f0c2";
+@fa-var-cloud-download: "\f0ed";
+@fa-var-cloud-upload: "\f0ee";
+@fa-var-cny: "\f157";
+@fa-var-code: "\f121";
+@fa-var-code-fork: "\f126";
+@fa-var-codepen: "\f1cb";
+@fa-var-codiepie: "\f284";
+@fa-var-coffee: "\f0f4";
+@fa-var-cog: "\f013";
+@fa-var-cogs: "\f085";
+@fa-var-columns: "\f0db";
+@fa-var-comment: "\f075";
+@fa-var-comment-o: "\f0e5";
+@fa-var-commenting: "\f27a";
+@fa-var-commenting-o: "\f27b";
+@fa-var-comments: "\f086";
+@fa-var-comments-o: "\f0e6";
+@fa-var-compass: "\f14e";
+@fa-var-compress: "\f066";
+@fa-var-connectdevelop: "\f20e";
+@fa-var-contao: "\f26d";
+@fa-var-copy: "\f0c5";
+@fa-var-copyright: "\f1f9";
+@fa-var-creative-commons: "\f25e";
+@fa-var-credit-card: "\f09d";
+@fa-var-credit-card-alt: "\f283";
+@fa-var-crop: "\f125";
+@fa-var-crosshairs: "\f05b";
+@fa-var-css3: "\f13c";
+@fa-var-cube: "\f1b2";
+@fa-var-cubes: "\f1b3";
+@fa-var-cut: "\f0c4";
+@fa-var-cutlery: "\f0f5";
+@fa-var-dashboard: "\f0e4";
+@fa-var-dashcube: "\f210";
+@fa-var-database: "\f1c0";
+@fa-var-deaf: "\f2a4";
+@fa-var-deafness: "\f2a4";
+@fa-var-dedent: "\f03b";
+@fa-var-delicious: "\f1a5";
+@fa-var-desktop: "\f108";
+@fa-var-deviantart: "\f1bd";
+@fa-var-diamond: "\f219";
+@fa-var-digg: "\f1a6";
+@fa-var-dollar: "\f155";
+@fa-var-dot-circle-o: "\f192";
+@fa-var-download: "\f019";
+@fa-var-dribbble: "\f17d";
+@fa-var-dropbox: "\f16b";
+@fa-var-drupal: "\f1a9";
+@fa-var-edge: "\f282";
+@fa-var-edit: "\f044";
+@fa-var-eject: "\f052";
+@fa-var-ellipsis-h: "\f141";
+@fa-var-ellipsis-v: "\f142";
+@fa-var-empire: "\f1d1";
+@fa-var-envelope: "\f0e0";
+@fa-var-envelope-o: "\f003";
+@fa-var-envelope-square: "\f199";
+@fa-var-envira: "\f299";
+@fa-var-eraser: "\f12d";
+@fa-var-eur: "\f153";
+@fa-var-euro: "\f153";
+@fa-var-exchange: "\f0ec";
+@fa-var-exclamation: "\f12a";
+@fa-var-exclamation-circle: "\f06a";
+@fa-var-exclamation-triangle: "\f071";
+@fa-var-expand: "\f065";
+@fa-var-expeditedssl: "\f23e";
+@fa-var-external-link: "\f08e";
+@fa-var-external-link-square: "\f14c";
+@fa-var-eye: "\f06e";
+@fa-var-eye-slash: "\f070";
+@fa-var-eyedropper: "\f1fb";
+@fa-var-fa: "\f2b4";
+@fa-var-facebook: "\f09a";
+@fa-var-facebook-f: "\f09a";
+@fa-var-facebook-official: "\f230";
+@fa-var-facebook-square: "\f082";
+@fa-var-fast-backward: "\f049";
+@fa-var-fast-forward: "\f050";
+@fa-var-fax: "\f1ac";
+@fa-var-feed: "\f09e";
+@fa-var-female: "\f182";
+@fa-var-fighter-jet: "\f0fb";
+@fa-var-file: "\f15b";
+@fa-var-file-archive-o: "\f1c6";
+@fa-var-file-audio-o: "\f1c7";
+@fa-var-file-code-o: "\f1c9";
+@fa-var-file-excel-o: "\f1c3";
+@fa-var-file-image-o: "\f1c5";
+@fa-var-file-movie-o: "\f1c8";
+@fa-var-file-o: "\f016";
+@fa-var-file-pdf-o: "\f1c1";
+@fa-var-file-photo-o: "\f1c5";
+@fa-var-file-picture-o: "\f1c5";
+@fa-var-file-powerpoint-o: "\f1c4";
+@fa-var-file-sound-o: "\f1c7";
+@fa-var-file-text: "\f15c";
+@fa-var-file-text-o: "\f0f6";
+@fa-var-file-video-o: "\f1c8";
+@fa-var-file-word-o: "\f1c2";
+@fa-var-file-zip-o: "\f1c6";
+@fa-var-files-o: "\f0c5";
+@fa-var-film: "\f008";
+@fa-var-filter: "\f0b0";
+@fa-var-fire: "\f06d";
+@fa-var-fire-extinguisher: "\f134";
+@fa-var-firefox: "\f269";
+@fa-var-first-order: "\f2b0";
+@fa-var-flag: "\f024";
+@fa-var-flag-checkered: "\f11e";
+@fa-var-flag-o: "\f11d";
+@fa-var-flash: "\f0e7";
+@fa-var-flask: "\f0c3";
+@fa-var-flickr: "\f16e";
+@fa-var-floppy-o: "\f0c7";
+@fa-var-folder: "\f07b";
+@fa-var-folder-o: "\f114";
+@fa-var-folder-open: "\f07c";
+@fa-var-folder-open-o: "\f115";
+@fa-var-font: "\f031";
+@fa-var-font-awesome: "\f2b4";
+@fa-var-fonticons: "\f280";
+@fa-var-fort-awesome: "\f286";
+@fa-var-forumbee: "\f211";
+@fa-var-forward: "\f04e";
+@fa-var-foursquare: "\f180";
+@fa-var-frown-o: "\f119";
+@fa-var-futbol-o: "\f1e3";
+@fa-var-gamepad: "\f11b";
+@fa-var-gavel: "\f0e3";
+@fa-var-gbp: "\f154";
+@fa-var-ge: "\f1d1";
+@fa-var-gear: "\f013";
+@fa-var-gears: "\f085";
+@fa-var-genderless: "\f22d";
+@fa-var-get-pocket: "\f265";
+@fa-var-gg: "\f260";
+@fa-var-gg-circle: "\f261";
+@fa-var-gift: "\f06b";
+@fa-var-git: "\f1d3";
+@fa-var-git-square: "\f1d2";
+@fa-var-github: "\f09b";
+@fa-var-github-alt: "\f113";
+@fa-var-github-square: "\f092";
+@fa-var-gitlab: "\f296";
+@fa-var-gittip: "\f184";
+@fa-var-glass: "\f000";
+@fa-var-glide: "\f2a5";
+@fa-var-glide-g: "\f2a6";
+@fa-var-globe: "\f0ac";
+@fa-var-google: "\f1a0";
+@fa-var-google-plus: "\f0d5";
+@fa-var-google-plus-circle: "\f2b3";
+@fa-var-google-plus-official: "\f2b3";
+@fa-var-google-plus-square: "\f0d4";
+@fa-var-google-wallet: "\f1ee";
+@fa-var-graduation-cap: "\f19d";
+@fa-var-gratipay: "\f184";
+@fa-var-group: "\f0c0";
+@fa-var-h-square: "\f0fd";
+@fa-var-hacker-news: "\f1d4";
+@fa-var-hand-grab-o: "\f255";
+@fa-var-hand-lizard-o: "\f258";
+@fa-var-hand-o-down: "\f0a7";
+@fa-var-hand-o-left: "\f0a5";
+@fa-var-hand-o-right: "\f0a4";
+@fa-var-hand-o-up: "\f0a6";
+@fa-var-hand-paper-o: "\f256";
+@fa-var-hand-peace-o: "\f25b";
+@fa-var-hand-pointer-o: "\f25a";
+@fa-var-hand-rock-o: "\f255";
+@fa-var-hand-scissors-o: "\f257";
+@fa-var-hand-spock-o: "\f259";
+@fa-var-hand-stop-o: "\f256";
+@fa-var-hard-of-hearing: "\f2a4";
+@fa-var-hashtag: "\f292";
+@fa-var-hdd-o: "\f0a0";
+@fa-var-header: "\f1dc";
+@fa-var-headphones: "\f025";
+@fa-var-heart: "\f004";
+@fa-var-heart-o: "\f08a";
+@fa-var-heartbeat: "\f21e";
+@fa-var-history: "\f1da";
+@fa-var-home: "\f015";
+@fa-var-hospital-o: "\f0f8";
+@fa-var-hotel: "\f236";
+@fa-var-hourglass: "\f254";
+@fa-var-hourglass-1: "\f251";
+@fa-var-hourglass-2: "\f252";
+@fa-var-hourglass-3: "\f253";
+@fa-var-hourglass-end: "\f253";
+@fa-var-hourglass-half: "\f252";
+@fa-var-hourglass-o: "\f250";
+@fa-var-hourglass-start: "\f251";
+@fa-var-houzz: "\f27c";
+@fa-var-html5: "\f13b";
+@fa-var-i-cursor: "\f246";
+@fa-var-ils: "\f20b";
+@fa-var-image: "\f03e";
+@fa-var-inbox: "\f01c";
+@fa-var-indent: "\f03c";
+@fa-var-industry: "\f275";
+@fa-var-info: "\f129";
+@fa-var-info-circle: "\f05a";
+@fa-var-inr: "\f156";
+@fa-var-instagram: "\f16d";
+@fa-var-institution: "\f19c";
+@fa-var-internet-explorer: "\f26b";
+@fa-var-intersex: "\f224";
+@fa-var-ioxhost: "\f208";
+@fa-var-italic: "\f033";
+@fa-var-joomla: "\f1aa";
+@fa-var-jpy: "\f157";
+@fa-var-jsfiddle: "\f1cc";
+@fa-var-key: "\f084";
+@fa-var-keyboard-o: "\f11c";
+@fa-var-krw: "\f159";
+@fa-var-language: "\f1ab";
+@fa-var-laptop: "\f109";
+@fa-var-lastfm: "\f202";
+@fa-var-lastfm-square: "\f203";
+@fa-var-leaf: "\f06c";
+@fa-var-leanpub: "\f212";
+@fa-var-legal: "\f0e3";
+@fa-var-lemon-o: "\f094";
+@fa-var-level-down: "\f149";
+@fa-var-level-up: "\f148";
+@fa-var-life-bouy: "\f1cd";
+@fa-var-life-buoy: "\f1cd";
+@fa-var-life-ring: "\f1cd";
+@fa-var-life-saver: "\f1cd";
+@fa-var-lightbulb-o: "\f0eb";
+@fa-var-line-chart: "\f201";
+@fa-var-link: "\f0c1";
+@fa-var-linkedin: "\f0e1";
+@fa-var-linkedin-square: "\f08c";
+@fa-var-linux: "\f17c";
+@fa-var-list: "\f03a";
+@fa-var-list-alt: "\f022";
+@fa-var-list-ol: "\f0cb";
+@fa-var-list-ul: "\f0ca";
+@fa-var-location-arrow: "\f124";
+@fa-var-lock: "\f023";
+@fa-var-long-arrow-down: "\f175";
+@fa-var-long-arrow-left: "\f177";
+@fa-var-long-arrow-right: "\f178";
+@fa-var-long-arrow-up: "\f176";
+@fa-var-low-vision: "\f2a8";
+@fa-var-magic: "\f0d0";
+@fa-var-magnet: "\f076";
+@fa-var-mail-forward: "\f064";
+@fa-var-mail-reply: "\f112";
+@fa-var-mail-reply-all: "\f122";
+@fa-var-male: "\f183";
+@fa-var-map: "\f279";
+@fa-var-map-marker: "\f041";
+@fa-var-map-o: "\f278";
+@fa-var-map-pin: "\f276";
+@fa-var-map-signs: "\f277";
+@fa-var-mars: "\f222";
+@fa-var-mars-double: "\f227";
+@fa-var-mars-stroke: "\f229";
+@fa-var-mars-stroke-h: "\f22b";
+@fa-var-mars-stroke-v: "\f22a";
+@fa-var-maxcdn: "\f136";
+@fa-var-meanpath: "\f20c";
+@fa-var-medium: "\f23a";
+@fa-var-medkit: "\f0fa";
+@fa-var-meh-o: "\f11a";
+@fa-var-mercury: "\f223";
+@fa-var-microphone: "\f130";
+@fa-var-microphone-slash: "\f131";
+@fa-var-minus: "\f068";
+@fa-var-minus-circle: "\f056";
+@fa-var-minus-square: "\f146";
+@fa-var-minus-square-o: "\f147";
+@fa-var-mixcloud: "\f289";
+@fa-var-mobile: "\f10b";
+@fa-var-mobile-phone: "\f10b";
+@fa-var-modx: "\f285";
+@fa-var-money: "\f0d6";
+@fa-var-moon-o: "\f186";
+@fa-var-mortar-board: "\f19d";
+@fa-var-motorcycle: "\f21c";
+@fa-var-mouse-pointer: "\f245";
+@fa-var-music: "\f001";
+@fa-var-navicon: "\f0c9";
+@fa-var-neuter: "\f22c";
+@fa-var-newspaper-o: "\f1ea";
+@fa-var-object-group: "\f247";
+@fa-var-object-ungroup: "\f248";
+@fa-var-odnoklassniki: "\f263";
+@fa-var-odnoklassniki-square: "\f264";
+@fa-var-opencart: "\f23d";
+@fa-var-openid: "\f19b";
+@fa-var-opera: "\f26a";
+@fa-var-optin-monster: "\f23c";
+@fa-var-outdent: "\f03b";
+@fa-var-pagelines: "\f18c";
+@fa-var-paint-brush: "\f1fc";
+@fa-var-paper-plane: "\f1d8";
+@fa-var-paper-plane-o: "\f1d9";
+@fa-var-paperclip: "\f0c6";
+@fa-var-paragraph: "\f1dd";
+@fa-var-paste: "\f0ea";
+@fa-var-pause: "\f04c";
+@fa-var-pause-circle: "\f28b";
+@fa-var-pause-circle-o: "\f28c";
+@fa-var-paw: "\f1b0";
+@fa-var-paypal: "\f1ed";
+@fa-var-pencil: "\f040";
+@fa-var-pencil-square: "\f14b";
+@fa-var-pencil-square-o: "\f044";
+@fa-var-percent: "\f295";
+@fa-var-phone: "\f095";
+@fa-var-phone-square: "\f098";
+@fa-var-photo: "\f03e";
+@fa-var-picture-o: "\f03e";
+@fa-var-pie-chart: "\f200";
+@fa-var-pied-piper: "\f2ae";
+@fa-var-pied-piper-alt: "\f1a8";
+@fa-var-pied-piper-pp: "\f1a7";
+@fa-var-pinterest: "\f0d2";
+@fa-var-pinterest-p: "\f231";
+@fa-var-pinterest-square: "\f0d3";
+@fa-var-plane: "\f072";
+@fa-var-play: "\f04b";
+@fa-var-play-circle: "\f144";
+@fa-var-play-circle-o: "\f01d";
+@fa-var-plug: "\f1e6";
+@fa-var-plus: "\f067";
+@fa-var-plus-circle: "\f055";
+@fa-var-plus-square: "\f0fe";
+@fa-var-plus-square-o: "\f196";
+@fa-var-power-off: "\f011";
+@fa-var-print: "\f02f";
+@fa-var-product-hunt: "\f288";
+@fa-var-puzzle-piece: "\f12e";
+@fa-var-qq: "\f1d6";
+@fa-var-qrcode: "\f029";
+@fa-var-question: "\f128";
+@fa-var-question-circle: "\f059";
+@fa-var-question-circle-o: "\f29c";
+@fa-var-quote-left: "\f10d";
+@fa-var-quote-right: "\f10e";
+@fa-var-ra: "\f1d0";
+@fa-var-random: "\f074";
+@fa-var-rebel: "\f1d0";
+@fa-var-recycle: "\f1b8";
+@fa-var-reddit: "\f1a1";
+@fa-var-reddit-alien: "\f281";
+@fa-var-reddit-square: "\f1a2";
+@fa-var-refresh: "\f021";
+@fa-var-registered: "\f25d";
+@fa-var-remove: "\f00d";
+@fa-var-renren: "\f18b";
+@fa-var-reorder: "\f0c9";
+@fa-var-repeat: "\f01e";
+@fa-var-reply: "\f112";
+@fa-var-reply-all: "\f122";
+@fa-var-resistance: "\f1d0";
+@fa-var-retweet: "\f079";
+@fa-var-rmb: "\f157";
+@fa-var-road: "\f018";
+@fa-var-rocket: "\f135";
+@fa-var-rotate-left: "\f0e2";
+@fa-var-rotate-right: "\f01e";
+@fa-var-rouble: "\f158";
+@fa-var-rss: "\f09e";
+@fa-var-rss-square: "\f143";
+@fa-var-rub: "\f158";
+@fa-var-ruble: "\f158";
+@fa-var-rupee: "\f156";
+@fa-var-safari: "\f267";
+@fa-var-save: "\f0c7";
+@fa-var-scissors: "\f0c4";
+@fa-var-scribd: "\f28a";
+@fa-var-search: "\f002";
+@fa-var-search-minus: "\f010";
+@fa-var-search-plus: "\f00e";
+@fa-var-sellsy: "\f213";
+@fa-var-send: "\f1d8";
+@fa-var-send-o: "\f1d9";
+@fa-var-server: "\f233";
+@fa-var-share: "\f064";
+@fa-var-share-alt: "\f1e0";
+@fa-var-share-alt-square: "\f1e1";
+@fa-var-share-square: "\f14d";
+@fa-var-share-square-o: "\f045";
+@fa-var-shekel: "\f20b";
+@fa-var-sheqel: "\f20b";
+@fa-var-shield: "\f132";
+@fa-var-ship: "\f21a";
+@fa-var-shirtsinbulk: "\f214";
+@fa-var-shopping-bag: "\f290";
+@fa-var-shopping-basket: "\f291";
+@fa-var-shopping-cart: "\f07a";
+@fa-var-sign-in: "\f090";
+@fa-var-sign-language: "\f2a7";
+@fa-var-sign-out: "\f08b";
+@fa-var-signal: "\f012";
+@fa-var-signing: "\f2a7";
+@fa-var-simplybuilt: "\f215";
+@fa-var-sitemap: "\f0e8";
+@fa-var-skyatlas: "\f216";
+@fa-var-skype: "\f17e";
+@fa-var-slack: "\f198";
+@fa-var-sliders: "\f1de";
+@fa-var-slideshare: "\f1e7";
+@fa-var-smile-o: "\f118";
+@fa-var-snapchat: "\f2ab";
+@fa-var-snapchat-ghost: "\f2ac";
+@fa-var-snapchat-square: "\f2ad";
+@fa-var-soccer-ball-o: "\f1e3";
+@fa-var-sort: "\f0dc";
+@fa-var-sort-alpha-asc: "\f15d";
+@fa-var-sort-alpha-desc: "\f15e";
+@fa-var-sort-amount-asc: "\f160";
+@fa-var-sort-amount-desc: "\f161";
+@fa-var-sort-asc: "\f0de";
+@fa-var-sort-desc: "\f0dd";
+@fa-var-sort-down: "\f0dd";
+@fa-var-sort-numeric-asc: "\f162";
+@fa-var-sort-numeric-desc: "\f163";
+@fa-var-sort-up: "\f0de";
+@fa-var-soundcloud: "\f1be";
+@fa-var-space-shuttle: "\f197";
+@fa-var-spinner: "\f110";
+@fa-var-spoon: "\f1b1";
+@fa-var-spotify: "\f1bc";
+@fa-var-square: "\f0c8";
+@fa-var-square-o: "\f096";
+@fa-var-stack-exchange: "\f18d";
+@fa-var-stack-overflow: "\f16c";
+@fa-var-star: "\f005";
+@fa-var-star-half: "\f089";
+@fa-var-star-half-empty: "\f123";
+@fa-var-star-half-full: "\f123";
+@fa-var-star-half-o: "\f123";
+@fa-var-star-o: "\f006";
+@fa-var-steam: "\f1b6";
+@fa-var-steam-square: "\f1b7";
+@fa-var-step-backward: "\f048";
+@fa-var-step-forward: "\f051";
+@fa-var-stethoscope: "\f0f1";
+@fa-var-sticky-note: "\f249";
+@fa-var-sticky-note-o: "\f24a";
+@fa-var-stop: "\f04d";
+@fa-var-stop-circle: "\f28d";
+@fa-var-stop-circle-o: "\f28e";
+@fa-var-street-view: "\f21d";
+@fa-var-strikethrough: "\f0cc";
+@fa-var-stumbleupon: "\f1a4";
+@fa-var-stumbleupon-circle: "\f1a3";
+@fa-var-subscript: "\f12c";
+@fa-var-subway: "\f239";
+@fa-var-suitcase: "\f0f2";
+@fa-var-sun-o: "\f185";
+@fa-var-superscript: "\f12b";
+@fa-var-support: "\f1cd";
+@fa-var-table: "\f0ce";
+@fa-var-tablet: "\f10a";
+@fa-var-tachometer: "\f0e4";
+@fa-var-tag: "\f02b";
+@fa-var-tags: "\f02c";
+@fa-var-tasks: "\f0ae";
+@fa-var-taxi: "\f1ba";
+@fa-var-television: "\f26c";
+@fa-var-tencent-weibo: "\f1d5";
+@fa-var-terminal: "\f120";
+@fa-var-text-height: "\f034";
+@fa-var-text-width: "\f035";
+@fa-var-th: "\f00a";
+@fa-var-th-large: "\f009";
+@fa-var-th-list: "\f00b";
+@fa-var-themeisle: "\f2b2";
+@fa-var-thumb-tack: "\f08d";
+@fa-var-thumbs-down: "\f165";
+@fa-var-thumbs-o-down: "\f088";
+@fa-var-thumbs-o-up: "\f087";
+@fa-var-thumbs-up: "\f164";
+@fa-var-ticket: "\f145";
+@fa-var-times: "\f00d";
+@fa-var-times-circle: "\f057";
+@fa-var-times-circle-o: "\f05c";
+@fa-var-tint: "\f043";
+@fa-var-toggle-down: "\f150";
+@fa-var-toggle-left: "\f191";
+@fa-var-toggle-off: "\f204";
+@fa-var-toggle-on: "\f205";
+@fa-var-toggle-right: "\f152";
+@fa-var-toggle-up: "\f151";
+@fa-var-trademark: "\f25c";
+@fa-var-train: "\f238";
+@fa-var-transgender: "\f224";
+@fa-var-transgender-alt: "\f225";
+@fa-var-trash: "\f1f8";
+@fa-var-trash-o: "\f014";
+@fa-var-tree: "\f1bb";
+@fa-var-trello: "\f181";
+@fa-var-tripadvisor: "\f262";
+@fa-var-trophy: "\f091";
+@fa-var-truck: "\f0d1";
+@fa-var-try: "\f195";
+@fa-var-tty: "\f1e4";
+@fa-var-tumblr: "\f173";
+@fa-var-tumblr-square: "\f174";
+@fa-var-turkish-lira: "\f195";
+@fa-var-tv: "\f26c";
+@fa-var-twitch: "\f1e8";
+@fa-var-twitter: "\f099";
+@fa-var-twitter-square: "\f081";
+@fa-var-umbrella: "\f0e9";
+@fa-var-underline: "\f0cd";
+@fa-var-undo: "\f0e2";
+@fa-var-universal-access: "\f29a";
+@fa-var-university: "\f19c";
+@fa-var-unlink: "\f127";
+@fa-var-unlock: "\f09c";
+@fa-var-unlock-alt: "\f13e";
+@fa-var-unsorted: "\f0dc";
+@fa-var-upload: "\f093";
+@fa-var-usb: "\f287";
+@fa-var-usd: "\f155";
+@fa-var-user: "\f007";
+@fa-var-user-md: "\f0f0";
+@fa-var-user-plus: "\f234";
+@fa-var-user-secret: "\f21b";
+@fa-var-user-times: "\f235";
+@fa-var-users: "\f0c0";
+@fa-var-venus: "\f221";
+@fa-var-venus-double: "\f226";
+@fa-var-venus-mars: "\f228";
+@fa-var-viacoin: "\f237";
+@fa-var-viadeo: "\f2a9";
+@fa-var-viadeo-square: "\f2aa";
+@fa-var-video-camera: "\f03d";
+@fa-var-vimeo: "\f27d";
+@fa-var-vimeo-square: "\f194";
+@fa-var-vine: "\f1ca";
+@fa-var-vk: "\f189";
+@fa-var-volume-control-phone: "\f2a0";
+@fa-var-volume-down: "\f027";
+@fa-var-volume-off: "\f026";
+@fa-var-volume-up: "\f028";
+@fa-var-warning: "\f071";
+@fa-var-wechat: "\f1d7";
+@fa-var-weibo: "\f18a";
+@fa-var-weixin: "\f1d7";
+@fa-var-whatsapp: "\f232";
+@fa-var-wheelchair: "\f193";
+@fa-var-wheelchair-alt: "\f29b";
+@fa-var-wifi: "\f1eb";
+@fa-var-wikipedia-w: "\f266";
+@fa-var-windows: "\f17a";
+@fa-var-won: "\f159";
+@fa-var-wordpress: "\f19a";
+@fa-var-wpbeginner: "\f297";
+@fa-var-wpforms: "\f298";
+@fa-var-wrench: "\f0ad";
+@fa-var-xing: "\f168";
+@fa-var-xing-square: "\f169";
+@fa-var-y-combinator: "\f23b";
+@fa-var-y-combinator-square: "\f1d4";
+@fa-var-yahoo: "\f19e";
+@fa-var-yc: "\f23b";
+@fa-var-yc-square: "\f1d4";
+@fa-var-yelp: "\f1e9";
+@fa-var-yen: "\f157";
+@fa-var-yoast: "\f2b1";
+@fa-var-youtube: "\f167";
+@fa-var-youtube-play: "\f16a";
+@fa-var-youtube-square: "\f166";
+
diff --git a/hubs/static/font-awesome-4.6.3/scss/_animated.scss b/hubs/static/font-awesome-4.6.3/scss/_animated.scss
new file mode 100644
index 0000000..8a020db
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_animated.scss
@@ -0,0 +1,34 @@
+// Spinning Icons
+// --------------------------
+
+.#{$fa-css-prefix}-spin {
+  -webkit-animation: fa-spin 2s infinite linear;
+          animation: fa-spin 2s infinite linear;
+}
+
+.#{$fa-css-prefix}-pulse {
+  -webkit-animation: fa-spin 1s infinite steps(8);
+          animation: fa-spin 1s infinite steps(8);
+}
+
+@-webkit-keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+            transform: rotate(359deg);
+  }
+}
+
+@keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+            transform: rotate(359deg);
+  }
+}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_bordered-pulled.scss b/hubs/static/font-awesome-4.6.3/scss/_bordered-pulled.scss
new file mode 100644
index 0000000..d4b85a0
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_bordered-pulled.scss
@@ -0,0 +1,25 @@
+// Bordered & Pulled
+// -------------------------
+
+.#{$fa-css-prefix}-border {
+  padding: .2em .25em .15em;
+  border: solid .08em $fa-border-color;
+  border-radius: .1em;
+}
+
+.#{$fa-css-prefix}-pull-left { float: left; }
+.#{$fa-css-prefix}-pull-right { float: right; }
+
+.#{$fa-css-prefix} {
+  &.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
+  &.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
+}
+
+/* Deprecated as of 4.4.0 */
+.pull-right { float: right; }
+.pull-left { float: left; }
+
+.#{$fa-css-prefix} {
+  &.pull-left { margin-right: .3em; }
+  &.pull-right { margin-left: .3em; }
+}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_core.scss b/hubs/static/font-awesome-4.6.3/scss/_core.scss
new file mode 100644
index 0000000..7425ef8
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_core.scss
@@ -0,0 +1,12 @@
+// Base Class Definition
+// -------------------------
+
+.#{$fa-css-prefix} {
+  display: inline-block;
+  font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
+  font-size: inherit; // can't have font-size inherit on line above, so need to override
+  text-rendering: auto; // optimizelegibility throws things off #1094
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+
+}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_fixed-width.scss b/hubs/static/font-awesome-4.6.3/scss/_fixed-width.scss
new file mode 100644
index 0000000..b221c98
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_fixed-width.scss
@@ -0,0 +1,6 @@
+// Fixed Width Icons
+// -------------------------
+.#{$fa-css-prefix}-fw {
+  width: (18em / 14);
+  text-align: center;
+}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_icons.scss b/hubs/static/font-awesome-4.6.3/scss/_icons.scss
new file mode 100644
index 0000000..2944344
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_icons.scss
@@ -0,0 +1,733 @@
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+   readers do not read off random characters that represent icons */
+
+.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; }
+.#{$fa-css-prefix}-music:before { content: $fa-var-music; }
+.#{$fa-css-prefix}-search:before { content: $fa-var-search; }
+.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; }
+.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; }
+.#{$fa-css-prefix}-star:before { content: $fa-var-star; }
+.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; }
+.#{$fa-css-prefix}-user:before { content: $fa-var-user; }
+.#{$fa-css-prefix}-film:before { content: $fa-var-film; }
+.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; }
+.#{$fa-css-prefix}-th:before { content: $fa-var-th; }
+.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; }
+.#{$fa-css-prefix}-check:before { content: $fa-var-check; }
+.#{$fa-css-prefix}-remove:before,
+.#{$fa-css-prefix}-close:before,
+.#{$fa-css-prefix}-times:before { content: $fa-var-times; }
+.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; }
+.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; }
+.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; }
+.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; }
+.#{$fa-css-prefix}-gear:before,
+.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; }
+.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; }
+.#{$fa-css-prefix}-home:before { content: $fa-var-home; }
+.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; }
+.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; }
+.#{$fa-css-prefix}-road:before { content: $fa-var-road; }
+.#{$fa-css-prefix}-download:before { content: $fa-var-download; }
+.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; }
+.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; }
+.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; }
+.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; }
+.#{$fa-css-prefix}-rotate-right:before,
+.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; }
+.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; }
+.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; }
+.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; }
+.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; }
+.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; }
+.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; }
+.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; }
+.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; }
+.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; }
+.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; }
+.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; }
+.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; }
+.#{$fa-css-prefix}-book:before { content: $fa-var-book; }
+.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; }
+.#{$fa-css-prefix}-print:before { content: $fa-var-print; }
+.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; }
+.#{$fa-css-prefix}-font:before { content: $fa-var-font; }
+.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; }
+.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; }
+.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; }
+.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; }
+.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; }
+.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; }
+.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; }
+.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; }
+.#{$fa-css-prefix}-list:before { content: $fa-var-list; }
+.#{$fa-css-prefix}-dedent:before,
+.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; }
+.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; }
+.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; }
+.#{$fa-css-prefix}-photo:before,
+.#{$fa-css-prefix}-image:before,
+.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; }
+.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; }
+.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; }
+.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; }
+.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; }
+.#{$fa-css-prefix}-edit:before,
+.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; }
+.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; }
+.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; }
+.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; }
+.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; }
+.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; }
+.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; }
+.#{$fa-css-prefix}-play:before { content: $fa-var-play; }
+.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; }
+.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; }
+.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; }
+.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; }
+.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; }
+.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; }
+.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; }
+.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; }
+.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; }
+.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; }
+.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; }
+.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; }
+.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; }
+.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; }
+.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; }
+.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; }
+.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; }
+.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; }
+.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; }
+.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; }
+.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; }
+.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; }
+.#{$fa-css-prefix}-mail-forward:before,
+.#{$fa-css-prefix}-share:before { content: $fa-var-share; }
+.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; }
+.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; }
+.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; }
+.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; }
+.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; }
+.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; }
+.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; }
+.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; }
+.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; }
+.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; }
+.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; }
+.#{$fa-css-prefix}-warning:before,
+.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; }
+.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; }
+.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; }
+.#{$fa-css-prefix}-random:before { content: $fa-var-random; }
+.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; }
+.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; }
+.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; }
+.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; }
+.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; }
+.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; }
+.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; }
+.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; }
+.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; }
+.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; }
+.#{$fa-css-prefix}-bar-chart-o:before,
+.#{$fa-css-prefix}-bar-chart:before { content: $fa-var-bar-chart; }
+.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; }
+.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; }
+.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; }
+.#{$fa-css-prefix}-key:before { content: $fa-var-key; }
+.#{$fa-css-prefix}-gears:before,
+.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; }
+.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; }
+.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; }
+.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; }
+.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; }
+.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; }
+.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; }
+.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; }
+.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; }
+.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; }
+.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; }
+.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; }
+.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; }
+.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; }
+.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; }
+.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; }
+.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; }
+.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; }
+.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; }
+.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; }
+.#{$fa-css-prefix}-facebook-f:before,
+.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; }
+.#{$fa-css-prefix}-github:before { content: $fa-var-github; }
+.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; }
+.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; }
+.#{$fa-css-prefix}-feed:before,
+.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; }
+.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; }
+.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; }
+.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; }
+.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; }
+.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; }
+.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; }
+.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; }
+.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; }
+.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; }
+.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; }
+.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; }
+.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; }
+.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; }
+.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; }
+.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; }
+.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; }
+.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; }
+.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; }
+.#{$fa-css-prefix}-group:before,
+.#{$fa-css-prefix}-users:before { content: $fa-var-users; }
+.#{$fa-css-prefix}-chain:before,
+.#{$fa-css-prefix}-link:before { content: $fa-var-link; }
+.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; }
+.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; }
+.#{$fa-css-prefix}-cut:before,
+.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; }
+.#{$fa-css-prefix}-copy:before,
+.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; }
+.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; }
+.#{$fa-css-prefix}-save:before,
+.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; }
+.#{$fa-css-prefix}-square:before { content: $fa-var-square; }
+.#{$fa-css-prefix}-navicon:before,
+.#{$fa-css-prefix}-reorder:before,
+.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; }
+.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; }
+.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; }
+.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; }
+.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; }
+.#{$fa-css-prefix}-table:before { content: $fa-var-table; }
+.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; }
+.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; }
+.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; }
+.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; }
+.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; }
+.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; }
+.#{$fa-css-prefix}-money:before { content: $fa-var-money; }
+.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; }
+.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; }
+.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; }
+.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; }
+.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; }
+.#{$fa-css-prefix}-unsorted:before,
+.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; }
+.#{$fa-css-prefix}-sort-down:before,
+.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; }
+.#{$fa-css-prefix}-sort-up:before,
+.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; }
+.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; }
+.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; }
+.#{$fa-css-prefix}-rotate-left:before,
+.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; }
+.#{$fa-css-prefix}-legal:before,
+.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; }
+.#{$fa-css-prefix}-dashboard:before,
+.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; }
+.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; }
+.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; }
+.#{$fa-css-prefix}-flash:before,
+.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; }
+.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; }
+.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; }
+.#{$fa-css-prefix}-paste:before,
+.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; }
+.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; }
+.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; }
+.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; }
+.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; }
+.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; }
+.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; }
+.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; }
+.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; }
+.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; }
+.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; }
+.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; }
+.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; }
+.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; }
+.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; }
+.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; }
+.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; }
+.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; }
+.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; }
+.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; }
+.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; }
+.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; }
+.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; }
+.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; }
+.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; }
+.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; }
+.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; }
+.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; }
+.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; }
+.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; }
+.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; }
+.#{$fa-css-prefix}-mobile-phone:before,
+.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; }
+.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; }
+.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; }
+.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; }
+.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; }
+.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; }
+.#{$fa-css-prefix}-mail-reply:before,
+.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; }
+.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; }
+.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; }
+.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; }
+.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; }
+.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; }
+.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; }
+.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; }
+.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; }
+.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; }
+.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; }
+.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; }
+.#{$fa-css-prefix}-code:before { content: $fa-var-code; }
+.#{$fa-css-prefix}-mail-reply-all:before,
+.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; }
+.#{$fa-css-prefix}-star-half-empty:before,
+.#{$fa-css-prefix}-star-half-full:before,
+.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; }
+.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; }
+.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; }
+.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; }
+.#{$fa-css-prefix}-unlink:before,
+.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; }
+.#{$fa-css-prefix}-question:before { content: $fa-var-question; }
+.#{$fa-css-prefix}-info:before { content: $fa-var-info; }
+.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; }
+.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; }
+.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; }
+.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; }
+.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; }
+.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; }
+.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; }
+.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; }
+.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; }
+.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; }
+.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; }
+.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; }
+.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; }
+.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; }
+.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; }
+.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; }
+.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; }
+.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; }
+.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; }
+.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; }
+.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; }
+.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; }
+.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; }
+.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; }
+.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; }
+.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; }
+.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; }
+.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; }
+.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; }
+.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; }
+.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; }
+.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; }
+.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; }
+.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; }
+.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; }
+.#{$fa-css-prefix}-toggle-down:before,
+.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; }
+.#{$fa-css-prefix}-toggle-up:before,
+.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; }
+.#{$fa-css-prefix}-toggle-right:before,
+.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; }
+.#{$fa-css-prefix}-euro:before,
+.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; }
+.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; }
+.#{$fa-css-prefix}-dollar:before,
+.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; }
+.#{$fa-css-prefix}-rupee:before,
+.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; }
+.#{$fa-css-prefix}-cny:before,
+.#{$fa-css-prefix}-rmb:before,
+.#{$fa-css-prefix}-yen:before,
+.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; }
+.#{$fa-css-prefix}-ruble:before,
+.#{$fa-css-prefix}-rouble:before,
+.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; }
+.#{$fa-css-prefix}-won:before,
+.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; }
+.#{$fa-css-prefix}-bitcoin:before,
+.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; }
+.#{$fa-css-prefix}-file:before { content: $fa-var-file; }
+.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; }
+.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; }
+.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; }
+.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; }
+.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; }
+.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; }
+.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; }
+.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; }
+.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; }
+.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; }
+.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; }
+.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; }
+.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; }
+.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; }
+.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; }
+.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; }
+.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; }
+.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; }
+.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; }
+.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; }
+.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; }
+.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; }
+.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; }
+.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; }
+.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; }
+.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; }
+.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; }
+.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; }
+.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; }
+.#{$fa-css-prefix}-android:before { content: $fa-var-android; }
+.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; }
+.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; }
+.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; }
+.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; }
+.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; }
+.#{$fa-css-prefix}-female:before { content: $fa-var-female; }
+.#{$fa-css-prefix}-male:before { content: $fa-var-male; }
+.#{$fa-css-prefix}-gittip:before,
+.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; }
+.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; }
+.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; }
+.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; }
+.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; }
+.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; }
+.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; }
+.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; }
+.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; }
+.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; }
+.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; }
+.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; }
+.#{$fa-css-prefix}-toggle-left:before,
+.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; }
+.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; }
+.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; }
+.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; }
+.#{$fa-css-prefix}-turkish-lira:before,
+.#{$fa-css-prefix}-try:before { content: $fa-var-try; }
+.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; }
+.#{$fa-css-prefix}-space-shuttle:before { content: $fa-var-space-shuttle; }
+.#{$fa-css-prefix}-slack:before { content: $fa-var-slack; }
+.#{$fa-css-prefix}-envelope-square:before { content: $fa-var-envelope-square; }
+.#{$fa-css-prefix}-wordpress:before { content: $fa-var-wordpress; }
+.#{$fa-css-prefix}-openid:before { content: $fa-var-openid; }
+.#{$fa-css-prefix}-institution:before,
+.#{$fa-css-prefix}-bank:before,
+.#{$fa-css-prefix}-university:before { content: $fa-var-university; }
+.#{$fa-css-prefix}-mortar-board:before,
+.#{$fa-css-prefix}-graduation-cap:before { content: $fa-var-graduation-cap; }
+.#{$fa-css-prefix}-yahoo:before { content: $fa-var-yahoo; }
+.#{$fa-css-prefix}-google:before { content: $fa-var-google; }
+.#{$fa-css-prefix}-reddit:before { content: $fa-var-reddit; }
+.#{$fa-css-prefix}-reddit-square:before { content: $fa-var-reddit-square; }
+.#{$fa-css-prefix}-stumbleupon-circle:before { content: $fa-var-stumbleupon-circle; }
+.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; }
+.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; }
+.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; }
+.#{$fa-css-prefix}-pied-piper-pp:before { content: $fa-var-pied-piper-pp; }
+.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; }
+.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; }
+.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; }
+.#{$fa-css-prefix}-language:before { content: $fa-var-language; }
+.#{$fa-css-prefix}-fax:before { content: $fa-var-fax; }
+.#{$fa-css-prefix}-building:before { content: $fa-var-building; }
+.#{$fa-css-prefix}-child:before { content: $fa-var-child; }
+.#{$fa-css-prefix}-paw:before { content: $fa-var-paw; }
+.#{$fa-css-prefix}-spoon:before { content: $fa-var-spoon; }
+.#{$fa-css-prefix}-cube:before { content: $fa-var-cube; }
+.#{$fa-css-prefix}-cubes:before { content: $fa-var-cubes; }
+.#{$fa-css-prefix}-behance:before { content: $fa-var-behance; }
+.#{$fa-css-prefix}-behance-square:before { content: $fa-var-behance-square; }
+.#{$fa-css-prefix}-steam:before { content: $fa-var-steam; }
+.#{$fa-css-prefix}-steam-square:before { content: $fa-var-steam-square; }
+.#{$fa-css-prefix}-recycle:before { content: $fa-var-recycle; }
+.#{$fa-css-prefix}-automobile:before,
+.#{$fa-css-prefix}-car:before { content: $fa-var-car; }
+.#{$fa-css-prefix}-cab:before,
+.#{$fa-css-prefix}-taxi:before { content: $fa-var-taxi; }
+.#{$fa-css-prefix}-tree:before { content: $fa-var-tree; }
+.#{$fa-css-prefix}-spotify:before { content: $fa-var-spotify; }
+.#{$fa-css-prefix}-deviantart:before { content: $fa-var-deviantart; }
+.#{$fa-css-prefix}-soundcloud:before { content: $fa-var-soundcloud; }
+.#{$fa-css-prefix}-database:before { content: $fa-var-database; }
+.#{$fa-css-prefix}-file-pdf-o:before { content: $fa-var-file-pdf-o; }
+.#{$fa-css-prefix}-file-word-o:before { content: $fa-var-file-word-o; }
+.#{$fa-css-prefix}-file-excel-o:before { content: $fa-var-file-excel-o; }
+.#{$fa-css-prefix}-file-powerpoint-o:before { content: $fa-var-file-powerpoint-o; }
+.#{$fa-css-prefix}-file-photo-o:before,
+.#{$fa-css-prefix}-file-picture-o:before,
+.#{$fa-css-prefix}-file-image-o:before { content: $fa-var-file-image-o; }
+.#{$fa-css-prefix}-file-zip-o:before,
+.#{$fa-css-prefix}-file-archive-o:before { content: $fa-var-file-archive-o; }
+.#{$fa-css-prefix}-file-sound-o:before,
+.#{$fa-css-prefix}-file-audio-o:before { content: $fa-var-file-audio-o; }
+.#{$fa-css-prefix}-file-movie-o:before,
+.#{$fa-css-prefix}-file-video-o:before { content: $fa-var-file-video-o; }
+.#{$fa-css-prefix}-file-code-o:before { content: $fa-var-file-code-o; }
+.#{$fa-css-prefix}-vine:before { content: $fa-var-vine; }
+.#{$fa-css-prefix}-codepen:before { content: $fa-var-codepen; }
+.#{$fa-css-prefix}-jsfiddle:before { content: $fa-var-jsfiddle; }
+.#{$fa-css-prefix}-life-bouy:before,
+.#{$fa-css-prefix}-life-buoy:before,
+.#{$fa-css-prefix}-life-saver:before,
+.#{$fa-css-prefix}-support:before,
+.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; }
+.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; }
+.#{$fa-css-prefix}-ra:before,
+.#{$fa-css-prefix}-resistance:before,
+.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; }
+.#{$fa-css-prefix}-ge:before,
+.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; }
+.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; }
+.#{$fa-css-prefix}-git:before { content: $fa-var-git; }
+.#{$fa-css-prefix}-y-combinator-square:before,
+.#{$fa-css-prefix}-yc-square:before,
+.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; }
+.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; }
+.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; }
+.#{$fa-css-prefix}-wechat:before,
+.#{$fa-css-prefix}-weixin:before { content: $fa-var-weixin; }
+.#{$fa-css-prefix}-send:before,
+.#{$fa-css-prefix}-paper-plane:before { content: $fa-var-paper-plane; }
+.#{$fa-css-prefix}-send-o:before,
+.#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; }
+.#{$fa-css-prefix}-history:before { content: $fa-var-history; }
+.#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; }
+.#{$fa-css-prefix}-header:before { content: $fa-var-header; }
+.#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; }
+.#{$fa-css-prefix}-sliders:before { content: $fa-var-sliders; }
+.#{$fa-css-prefix}-share-alt:before { content: $fa-var-share-alt; }
+.#{$fa-css-prefix}-share-alt-square:before { content: $fa-var-share-alt-square; }
+.#{$fa-css-prefix}-bomb:before { content: $fa-var-bomb; }
+.#{$fa-css-prefix}-soccer-ball-o:before,
+.#{$fa-css-prefix}-futbol-o:before { content: $fa-var-futbol-o; }
+.#{$fa-css-prefix}-tty:before { content: $fa-var-tty; }
+.#{$fa-css-prefix}-binoculars:before { content: $fa-var-binoculars; }
+.#{$fa-css-prefix}-plug:before { content: $fa-var-plug; }
+.#{$fa-css-prefix}-slideshare:before { content: $fa-var-slideshare; }
+.#{$fa-css-prefix}-twitch:before { content: $fa-var-twitch; }
+.#{$fa-css-prefix}-yelp:before { content: $fa-var-yelp; }
+.#{$fa-css-prefix}-newspaper-o:before { content: $fa-var-newspaper-o; }
+.#{$fa-css-prefix}-wifi:before { content: $fa-var-wifi; }
+.#{$fa-css-prefix}-calculator:before { content: $fa-var-calculator; }
+.#{$fa-css-prefix}-paypal:before { content: $fa-var-paypal; }
+.#{$fa-css-prefix}-google-wallet:before { content: $fa-var-google-wallet; }
+.#{$fa-css-prefix}-cc-visa:before { content: $fa-var-cc-visa; }
+.#{$fa-css-prefix}-cc-mastercard:before { content: $fa-var-cc-mastercard; }
+.#{$fa-css-prefix}-cc-discover:before { content: $fa-var-cc-discover; }
+.#{$fa-css-prefix}-cc-amex:before { content: $fa-var-cc-amex; }
+.#{$fa-css-prefix}-cc-paypal:before { content: $fa-var-cc-paypal; }
+.#{$fa-css-prefix}-cc-stripe:before { content: $fa-var-cc-stripe; }
+.#{$fa-css-prefix}-bell-slash:before { content: $fa-var-bell-slash; }
+.#{$fa-css-prefix}-bell-slash-o:before { content: $fa-var-bell-slash-o; }
+.#{$fa-css-prefix}-trash:before { content: $fa-var-trash; }
+.#{$fa-css-prefix}-copyright:before { content: $fa-var-copyright; }
+.#{$fa-css-prefix}-at:before { content: $fa-var-at; }
+.#{$fa-css-prefix}-eyedropper:before { content: $fa-var-eyedropper; }
+.#{$fa-css-prefix}-paint-brush:before { content: $fa-var-paint-brush; }
+.#{$fa-css-prefix}-birthday-cake:before { content: $fa-var-birthday-cake; }
+.#{$fa-css-prefix}-area-chart:before { content: $fa-var-area-chart; }
+.#{$fa-css-prefix}-pie-chart:before { content: $fa-var-pie-chart; }
+.#{$fa-css-prefix}-line-chart:before { content: $fa-var-line-chart; }
+.#{$fa-css-prefix}-lastfm:before { content: $fa-var-lastfm; }
+.#{$fa-css-prefix}-lastfm-square:before { content: $fa-var-lastfm-square; }
+.#{$fa-css-prefix}-toggle-off:before { content: $fa-var-toggle-off; }
+.#{$fa-css-prefix}-toggle-on:before { content: $fa-var-toggle-on; }
+.#{$fa-css-prefix}-bicycle:before { content: $fa-var-bicycle; }
+.#{$fa-css-prefix}-bus:before { content: $fa-var-bus; }
+.#{$fa-css-prefix}-ioxhost:before { content: $fa-var-ioxhost; }
+.#{$fa-css-prefix}-angellist:before { content: $fa-var-angellist; }
+.#{$fa-css-prefix}-cc:before { content: $fa-var-cc; }
+.#{$fa-css-prefix}-shekel:before,
+.#{$fa-css-prefix}-sheqel:before,
+.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; }
+.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; }
+.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; }
+.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; }
+.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; }
+.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; }
+.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; }
+.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; }
+.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; }
+.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; }
+.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; }
+.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; }
+.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; }
+.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; }
+.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; }
+.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; }
+.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; }
+.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; }
+.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; }
+.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; }
+.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; }
+.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; }
+.#{$fa-css-prefix}-intersex:before,
+.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; }
+.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; }
+.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; }
+.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; }
+.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; }
+.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; }
+.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; }
+.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; }
+.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; }
+.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; }
+.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; }
+.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; }
+.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; }
+.#{$fa-css-prefix}-server:before { content: $fa-var-server; }
+.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; }
+.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; }
+.#{$fa-css-prefix}-hotel:before,
+.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; }
+.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; }
+.#{$fa-css-prefix}-train:before { content: $fa-var-train; }
+.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; }
+.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; }
+.#{$fa-css-prefix}-yc:before,
+.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; }
+.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; }
+.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; }
+.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; }
+.#{$fa-css-prefix}-battery-4:before,
+.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; }
+.#{$fa-css-prefix}-battery-3:before,
+.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; }
+.#{$fa-css-prefix}-battery-2:before,
+.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; }
+.#{$fa-css-prefix}-battery-1:before,
+.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; }
+.#{$fa-css-prefix}-battery-0:before,
+.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; }
+.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; }
+.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; }
+.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; }
+.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; }
+.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; }
+.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; }
+.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; }
+.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; }
+.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; }
+.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; }
+.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; }
+.#{$fa-css-prefix}-hourglass-1:before,
+.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; }
+.#{$fa-css-prefix}-hourglass-2:before,
+.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; }
+.#{$fa-css-prefix}-hourglass-3:before,
+.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; }
+.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; }
+.#{$fa-css-prefix}-hand-grab-o:before,
+.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; }
+.#{$fa-css-prefix}-hand-stop-o:before,
+.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; }
+.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; }
+.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; }
+.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; }
+.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; }
+.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; }
+.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; }
+.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; }
+.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; }
+.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; }
+.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; }
+.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; }
+.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; }
+.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; }
+.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; }
+.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; }
+.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; }
+.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; }
+.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; }
+.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; }
+.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; }
+.#{$fa-css-prefix}-tv:before,
+.#{$fa-css-prefix}-television:before { content: $fa-var-television; }
+.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; }
+.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; }
+.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; }
+.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; }
+.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; }
+.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; }
+.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; }
+.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; }
+.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; }
+.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; }
+.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; }
+.#{$fa-css-prefix}-map:before { content: $fa-var-map; }
+.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; }
+.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; }
+.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; }
+.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; }
+.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; }
+.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; }
+.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; }
+.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; }
+.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; }
+.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; }
+.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; }
+.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; }
+.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; }
+.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; }
+.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; }
+.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; }
+.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; }
+.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; }
+.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; }
+.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; }
+.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; }
+.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; }
+.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; }
+.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; }
+.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; }
+.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; }
+.#{$fa-css-prefix}-gitlab:before { content: $fa-var-gitlab; }
+.#{$fa-css-prefix}-wpbeginner:before { content: $fa-var-wpbeginner; }
+.#{$fa-css-prefix}-wpforms:before { content: $fa-var-wpforms; }
+.#{$fa-css-prefix}-envira:before { content: $fa-var-envira; }
+.#{$fa-css-prefix}-universal-access:before { content: $fa-var-universal-access; }
+.#{$fa-css-prefix}-wheelchair-alt:before { content: $fa-var-wheelchair-alt; }
+.#{$fa-css-prefix}-question-circle-o:before { content: $fa-var-question-circle-o; }
+.#{$fa-css-prefix}-blind:before { content: $fa-var-blind; }
+.#{$fa-css-prefix}-audio-description:before { content: $fa-var-audio-description; }
+.#{$fa-css-prefix}-volume-control-phone:before { content: $fa-var-volume-control-phone; }
+.#{$fa-css-prefix}-braille:before { content: $fa-var-braille; }
+.#{$fa-css-prefix}-assistive-listening-systems:before { content: $fa-var-assistive-listening-systems; }
+.#{$fa-css-prefix}-asl-interpreting:before,
+.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: $fa-var-american-sign-language-interpreting; }
+.#{$fa-css-prefix}-deafness:before,
+.#{$fa-css-prefix}-hard-of-hearing:before,
+.#{$fa-css-prefix}-deaf:before { content: $fa-var-deaf; }
+.#{$fa-css-prefix}-glide:before { content: $fa-var-glide; }
+.#{$fa-css-prefix}-glide-g:before { content: $fa-var-glide-g; }
+.#{$fa-css-prefix}-signing:before,
+.#{$fa-css-prefix}-sign-language:before { content: $fa-var-sign-language; }
+.#{$fa-css-prefix}-low-vision:before { content: $fa-var-low-vision; }
+.#{$fa-css-prefix}-viadeo:before { content: $fa-var-viadeo; }
+.#{$fa-css-prefix}-viadeo-square:before { content: $fa-var-viadeo-square; }
+.#{$fa-css-prefix}-snapchat:before { content: $fa-var-snapchat; }
+.#{$fa-css-prefix}-snapchat-ghost:before { content: $fa-var-snapchat-ghost; }
+.#{$fa-css-prefix}-snapchat-square:before { content: $fa-var-snapchat-square; }
+.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; }
+.#{$fa-css-prefix}-first-order:before { content: $fa-var-first-order; }
+.#{$fa-css-prefix}-yoast:before { content: $fa-var-yoast; }
+.#{$fa-css-prefix}-themeisle:before { content: $fa-var-themeisle; }
+.#{$fa-css-prefix}-google-plus-circle:before,
+.#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; }
+.#{$fa-css-prefix}-fa:before,
+.#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; }
diff --git a/hubs/static/font-awesome-4.6.3/scss/_larger.scss b/hubs/static/font-awesome-4.6.3/scss/_larger.scss
new file mode 100644
index 0000000..41e9a81
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_larger.scss
@@ -0,0 +1,13 @@
+// Icon Sizes
+// -------------------------
+
+/* makes the font 33% larger relative to the icon container */
+.#{$fa-css-prefix}-lg {
+  font-size: (4em / 3);
+  line-height: (3em / 4);
+  vertical-align: -15%;
+}
+.#{$fa-css-prefix}-2x { font-size: 2em; }
+.#{$fa-css-prefix}-3x { font-size: 3em; }
+.#{$fa-css-prefix}-4x { font-size: 4em; }
+.#{$fa-css-prefix}-5x { font-size: 5em; }
diff --git a/hubs/static/font-awesome-4.6.3/scss/_list.scss b/hubs/static/font-awesome-4.6.3/scss/_list.scss
new file mode 100644
index 0000000..7d1e4d5
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_list.scss
@@ -0,0 +1,19 @@
+// List Icons
+// -------------------------
+
+.#{$fa-css-prefix}-ul {
+  padding-left: 0;
+  margin-left: $fa-li-width;
+  list-style-type: none;
+  > li { position: relative; }
+}
+.#{$fa-css-prefix}-li {
+  position: absolute;
+  left: -$fa-li-width;
+  width: $fa-li-width;
+  top: (2em / 14);
+  text-align: center;
+  &.#{$fa-css-prefix}-lg {
+    left: -$fa-li-width + (4em / 14);
+  }
+}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_mixins.scss b/hubs/static/font-awesome-4.6.3/scss/_mixins.scss
new file mode 100644
index 0000000..c3bbd57
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_mixins.scss
@@ -0,0 +1,60 @@
+// Mixins
+// --------------------------
+
+@mixin fa-icon() {
+  display: inline-block;
+  font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
+  font-size: inherit; // can't have font-size inherit on line above, so need to override
+  text-rendering: auto; // optimizelegibility throws things off #1094
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+
+}
+
+@mixin fa-icon-rotate($degrees, $rotation) {
+  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
+  -webkit-transform: rotate($degrees);
+      -ms-transform: rotate($degrees);
+          transform: rotate($degrees);
+}
+
+@mixin fa-icon-flip($horiz, $vert, $rotation) {
+  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
+  -webkit-transform: scale($horiz, $vert);
+      -ms-transform: scale($horiz, $vert);
+          transform: scale($horiz, $vert);
+}
+
+
+// Only display content to screen readers. A la Bootstrap 4.
+//
+// See: http://a11yproject.com/posts/how-to-hide-content/
+
+@mixin sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  padding: 0;
+  margin: -1px;
+  overflow: hidden;
+  clip: rect(0,0,0,0);
+  border: 0;
+}
+
+// Use in conjunction with .sr-only to only display content when it's focused.
+//
+// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
+//
+// Credit: HTML5 Boilerplate
+
+@mixin sr-only-focusable {
+  &:active,
+  &:focus {
+    position: static;
+    width: auto;
+    height: auto;
+    margin: 0;
+    overflow: visible;
+    clip: auto;
+  }
+}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_path.scss b/hubs/static/font-awesome-4.6.3/scss/_path.scss
new file mode 100644
index 0000000..bb457c2
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_path.scss
@@ -0,0 +1,15 @@
+/* FONT PATH
+ * -------------------------- */
+
+@font-face {
+  font-family: 'FontAwesome';
+  src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
+  src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
+    url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
+    url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
+    url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
+    url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
+//  src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
+  font-weight: normal;
+  font-style: normal;
+}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_rotated-flipped.scss b/hubs/static/font-awesome-4.6.3/scss/_rotated-flipped.scss
new file mode 100644
index 0000000..a3558fd
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_rotated-flipped.scss
@@ -0,0 +1,20 @@
+// Rotated & Flipped Icons
+// -------------------------
+
+.#{$fa-css-prefix}-rotate-90  { @include fa-icon-rotate(90deg, 1);  }
+.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
+.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
+
+.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
+.#{$fa-css-prefix}-flip-vertical   { @include fa-icon-flip(1, -1, 2); }
+
+// Hook for IE8-9
+// -------------------------
+
+:root .#{$fa-css-prefix}-rotate-90,
+:root .#{$fa-css-prefix}-rotate-180,
+:root .#{$fa-css-prefix}-rotate-270,
+:root .#{$fa-css-prefix}-flip-horizontal,
+:root .#{$fa-css-prefix}-flip-vertical {
+  filter: none;
+}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_screen-reader.scss b/hubs/static/font-awesome-4.6.3/scss/_screen-reader.scss
new file mode 100644
index 0000000..637426f
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_screen-reader.scss
@@ -0,0 +1,5 @@
+// Screen Readers
+// -------------------------
+
+.sr-only { @include sr-only(); }
+.sr-only-focusable { @include sr-only-focusable(); }
diff --git a/hubs/static/font-awesome-4.6.3/scss/_stacked.scss b/hubs/static/font-awesome-4.6.3/scss/_stacked.scss
new file mode 100644
index 0000000..aef7403
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_stacked.scss
@@ -0,0 +1,20 @@
+// Stacked Icons
+// -------------------------
+
+.#{$fa-css-prefix}-stack {
+  position: relative;
+  display: inline-block;
+  width: 2em;
+  height: 2em;
+  line-height: 2em;
+  vertical-align: middle;
+}
+.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x {
+  position: absolute;
+  left: 0;
+  width: 100%;
+  text-align: center;
+}
+.#{$fa-css-prefix}-stack-1x { line-height: inherit; }
+.#{$fa-css-prefix}-stack-2x { font-size: 2em; }
+.#{$fa-css-prefix}-inverse { color: $fa-inverse; }
diff --git a/hubs/static/font-awesome-4.6.3/scss/_variables.scss b/hubs/static/font-awesome-4.6.3/scss/_variables.scss
new file mode 100644
index 0000000..a5a89ef
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/_variables.scss
@@ -0,0 +1,744 @@
+// Variables
+// --------------------------
+
+$fa-font-path:        "../fonts" !default;
+$fa-font-size-base:   14px !default;
+$fa-line-height-base: 1 !default;
+//$fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.6.3/fonts" !default; // for referencing Bootstrap CDN font files directly
+$fa-css-prefix:       fa !default;
+$fa-version:          "4.6.3" !default;
+$fa-border-color:     #eee !default;
+$fa-inverse:          #fff !default;
+$fa-li-width:         (30em / 14) !default;
+
+$fa-var-500px: "\f26e";
+$fa-var-adjust: "\f042";
+$fa-var-adn: "\f170";
+$fa-var-align-center: "\f037";
+$fa-var-align-justify: "\f039";
+$fa-var-align-left: "\f036";
+$fa-var-align-right: "\f038";
+$fa-var-amazon: "\f270";
+$fa-var-ambulance: "\f0f9";
+$fa-var-american-sign-language-interpreting: "\f2a3";
+$fa-var-anchor: "\f13d";
+$fa-var-android: "\f17b";
+$fa-var-angellist: "\f209";
+$fa-var-angle-double-down: "\f103";
+$fa-var-angle-double-left: "\f100";
+$fa-var-angle-double-right: "\f101";
+$fa-var-angle-double-up: "\f102";
+$fa-var-angle-down: "\f107";
+$fa-var-angle-left: "\f104";
+$fa-var-angle-right: "\f105";
+$fa-var-angle-up: "\f106";
+$fa-var-apple: "\f179";
+$fa-var-archive: "\f187";
+$fa-var-area-chart: "\f1fe";
+$fa-var-arrow-circle-down: "\f0ab";
+$fa-var-arrow-circle-left: "\f0a8";
+$fa-var-arrow-circle-o-down: "\f01a";
+$fa-var-arrow-circle-o-left: "\f190";
+$fa-var-arrow-circle-o-right: "\f18e";
+$fa-var-arrow-circle-o-up: "\f01b";
+$fa-var-arrow-circle-right: "\f0a9";
+$fa-var-arrow-circle-up: "\f0aa";
+$fa-var-arrow-down: "\f063";
+$fa-var-arrow-left: "\f060";
+$fa-var-arrow-right: "\f061";
+$fa-var-arrow-up: "\f062";
+$fa-var-arrows: "\f047";
+$fa-var-arrows-alt: "\f0b2";
+$fa-var-arrows-h: "\f07e";
+$fa-var-arrows-v: "\f07d";
+$fa-var-asl-interpreting: "\f2a3";
+$fa-var-assistive-listening-systems: "\f2a2";
+$fa-var-asterisk: "\f069";
+$fa-var-at: "\f1fa";
+$fa-var-audio-description: "\f29e";
+$fa-var-automobile: "\f1b9";
+$fa-var-backward: "\f04a";
+$fa-var-balance-scale: "\f24e";
+$fa-var-ban: "\f05e";
+$fa-var-bank: "\f19c";
+$fa-var-bar-chart: "\f080";
+$fa-var-bar-chart-o: "\f080";
+$fa-var-barcode: "\f02a";
+$fa-var-bars: "\f0c9";
+$fa-var-battery-0: "\f244";
+$fa-var-battery-1: "\f243";
+$fa-var-battery-2: "\f242";
+$fa-var-battery-3: "\f241";
+$fa-var-battery-4: "\f240";
+$fa-var-battery-empty: "\f244";
+$fa-var-battery-full: "\f240";
+$fa-var-battery-half: "\f242";
+$fa-var-battery-quarter: "\f243";
+$fa-var-battery-three-quarters: "\f241";
+$fa-var-bed: "\f236";
+$fa-var-beer: "\f0fc";
+$fa-var-behance: "\f1b4";
+$fa-var-behance-square: "\f1b5";
+$fa-var-bell: "\f0f3";
+$fa-var-bell-o: "\f0a2";
+$fa-var-bell-slash: "\f1f6";
+$fa-var-bell-slash-o: "\f1f7";
+$fa-var-bicycle: "\f206";
+$fa-var-binoculars: "\f1e5";
+$fa-var-birthday-cake: "\f1fd";
+$fa-var-bitbucket: "\f171";
+$fa-var-bitbucket-square: "\f172";
+$fa-var-bitcoin: "\f15a";
+$fa-var-black-tie: "\f27e";
+$fa-var-blind: "\f29d";
+$fa-var-bluetooth: "\f293";
+$fa-var-bluetooth-b: "\f294";
+$fa-var-bold: "\f032";
+$fa-var-bolt: "\f0e7";
+$fa-var-bomb: "\f1e2";
+$fa-var-book: "\f02d";
+$fa-var-bookmark: "\f02e";
+$fa-var-bookmark-o: "\f097";
+$fa-var-braille: "\f2a1";
+$fa-var-briefcase: "\f0b1";
+$fa-var-btc: "\f15a";
+$fa-var-bug: "\f188";
+$fa-var-building: "\f1ad";
+$fa-var-building-o: "\f0f7";
+$fa-var-bullhorn: "\f0a1";
+$fa-var-bullseye: "\f140";
+$fa-var-bus: "\f207";
+$fa-var-buysellads: "\f20d";
+$fa-var-cab: "\f1ba";
+$fa-var-calculator: "\f1ec";
+$fa-var-calendar: "\f073";
+$fa-var-calendar-check-o: "\f274";
+$fa-var-calendar-minus-o: "\f272";
+$fa-var-calendar-o: "\f133";
+$fa-var-calendar-plus-o: "\f271";
+$fa-var-calendar-times-o: "\f273";
+$fa-var-camera: "\f030";
+$fa-var-camera-retro: "\f083";
+$fa-var-car: "\f1b9";
+$fa-var-caret-down: "\f0d7";
+$fa-var-caret-left: "\f0d9";
+$fa-var-caret-right: "\f0da";
+$fa-var-caret-square-o-down: "\f150";
+$fa-var-caret-square-o-left: "\f191";
+$fa-var-caret-square-o-right: "\f152";
+$fa-var-caret-square-o-up: "\f151";
+$fa-var-caret-up: "\f0d8";
+$fa-var-cart-arrow-down: "\f218";
+$fa-var-cart-plus: "\f217";
+$fa-var-cc: "\f20a";
+$fa-var-cc-amex: "\f1f3";
+$fa-var-cc-diners-club: "\f24c";
+$fa-var-cc-discover: "\f1f2";
+$fa-var-cc-jcb: "\f24b";
+$fa-var-cc-mastercard: "\f1f1";
+$fa-var-cc-paypal: "\f1f4";
+$fa-var-cc-stripe: "\f1f5";
+$fa-var-cc-visa: "\f1f0";
+$fa-var-certificate: "\f0a3";
+$fa-var-chain: "\f0c1";
+$fa-var-chain-broken: "\f127";
+$fa-var-check: "\f00c";
+$fa-var-check-circle: "\f058";
+$fa-var-check-circle-o: "\f05d";
+$fa-var-check-square: "\f14a";
+$fa-var-check-square-o: "\f046";
+$fa-var-chevron-circle-down: "\f13a";
+$fa-var-chevron-circle-left: "\f137";
+$fa-var-chevron-circle-right: "\f138";
+$fa-var-chevron-circle-up: "\f139";
+$fa-var-chevron-down: "\f078";
+$fa-var-chevron-left: "\f053";
+$fa-var-chevron-right: "\f054";
+$fa-var-chevron-up: "\f077";
+$fa-var-child: "\f1ae";
+$fa-var-chrome: "\f268";
+$fa-var-circle: "\f111";
+$fa-var-circle-o: "\f10c";
+$fa-var-circle-o-notch: "\f1ce";
+$fa-var-circle-thin: "\f1db";
+$fa-var-clipboard: "\f0ea";
+$fa-var-clock-o: "\f017";
+$fa-var-clone: "\f24d";
+$fa-var-close: "\f00d";
+$fa-var-cloud: "\f0c2";
+$fa-var-cloud-download: "\f0ed";
+$fa-var-cloud-upload: "\f0ee";
+$fa-var-cny: "\f157";
+$fa-var-code: "\f121";
+$fa-var-code-fork: "\f126";
+$fa-var-codepen: "\f1cb";
+$fa-var-codiepie: "\f284";
+$fa-var-coffee: "\f0f4";
+$fa-var-cog: "\f013";
+$fa-var-cogs: "\f085";
+$fa-var-columns: "\f0db";
+$fa-var-comment: "\f075";
+$fa-var-comment-o: "\f0e5";
+$fa-var-commenting: "\f27a";
+$fa-var-commenting-o: "\f27b";
+$fa-var-comments: "\f086";
+$fa-var-comments-o: "\f0e6";
+$fa-var-compass: "\f14e";
+$fa-var-compress: "\f066";
+$fa-var-connectdevelop: "\f20e";
+$fa-var-contao: "\f26d";
+$fa-var-copy: "\f0c5";
+$fa-var-copyright: "\f1f9";
+$fa-var-creative-commons: "\f25e";
+$fa-var-credit-card: "\f09d";
+$fa-var-credit-card-alt: "\f283";
+$fa-var-crop: "\f125";
+$fa-var-crosshairs: "\f05b";
+$fa-var-css3: "\f13c";
+$fa-var-cube: "\f1b2";
+$fa-var-cubes: "\f1b3";
+$fa-var-cut: "\f0c4";
+$fa-var-cutlery: "\f0f5";
+$fa-var-dashboard: "\f0e4";
+$fa-var-dashcube: "\f210";
+$fa-var-database: "\f1c0";
+$fa-var-deaf: "\f2a4";
+$fa-var-deafness: "\f2a4";
+$fa-var-dedent: "\f03b";
+$fa-var-delicious: "\f1a5";
+$fa-var-desktop: "\f108";
+$fa-var-deviantart: "\f1bd";
+$fa-var-diamond: "\f219";
+$fa-var-digg: "\f1a6";
+$fa-var-dollar: "\f155";
+$fa-var-dot-circle-o: "\f192";
+$fa-var-download: "\f019";
+$fa-var-dribbble: "\f17d";
+$fa-var-dropbox: "\f16b";
+$fa-var-drupal: "\f1a9";
+$fa-var-edge: "\f282";
+$fa-var-edit: "\f044";
+$fa-var-eject: "\f052";
+$fa-var-ellipsis-h: "\f141";
+$fa-var-ellipsis-v: "\f142";
+$fa-var-empire: "\f1d1";
+$fa-var-envelope: "\f0e0";
+$fa-var-envelope-o: "\f003";
+$fa-var-envelope-square: "\f199";
+$fa-var-envira: "\f299";
+$fa-var-eraser: "\f12d";
+$fa-var-eur: "\f153";
+$fa-var-euro: "\f153";
+$fa-var-exchange: "\f0ec";
+$fa-var-exclamation: "\f12a";
+$fa-var-exclamation-circle: "\f06a";
+$fa-var-exclamation-triangle: "\f071";
+$fa-var-expand: "\f065";
+$fa-var-expeditedssl: "\f23e";
+$fa-var-external-link: "\f08e";
+$fa-var-external-link-square: "\f14c";
+$fa-var-eye: "\f06e";
+$fa-var-eye-slash: "\f070";
+$fa-var-eyedropper: "\f1fb";
+$fa-var-fa: "\f2b4";
+$fa-var-facebook: "\f09a";
+$fa-var-facebook-f: "\f09a";
+$fa-var-facebook-official: "\f230";
+$fa-var-facebook-square: "\f082";
+$fa-var-fast-backward: "\f049";
+$fa-var-fast-forward: "\f050";
+$fa-var-fax: "\f1ac";
+$fa-var-feed: "\f09e";
+$fa-var-female: "\f182";
+$fa-var-fighter-jet: "\f0fb";
+$fa-var-file: "\f15b";
+$fa-var-file-archive-o: "\f1c6";
+$fa-var-file-audio-o: "\f1c7";
+$fa-var-file-code-o: "\f1c9";
+$fa-var-file-excel-o: "\f1c3";
+$fa-var-file-image-o: "\f1c5";
+$fa-var-file-movie-o: "\f1c8";
+$fa-var-file-o: "\f016";
+$fa-var-file-pdf-o: "\f1c1";
+$fa-var-file-photo-o: "\f1c5";
+$fa-var-file-picture-o: "\f1c5";
+$fa-var-file-powerpoint-o: "\f1c4";
+$fa-var-file-sound-o: "\f1c7";
+$fa-var-file-text: "\f15c";
+$fa-var-file-text-o: "\f0f6";
+$fa-var-file-video-o: "\f1c8";
+$fa-var-file-word-o: "\f1c2";
+$fa-var-file-zip-o: "\f1c6";
+$fa-var-files-o: "\f0c5";
+$fa-var-film: "\f008";
+$fa-var-filter: "\f0b0";
+$fa-var-fire: "\f06d";
+$fa-var-fire-extinguisher: "\f134";
+$fa-var-firefox: "\f269";
+$fa-var-first-order: "\f2b0";
+$fa-var-flag: "\f024";
+$fa-var-flag-checkered: "\f11e";
+$fa-var-flag-o: "\f11d";
+$fa-var-flash: "\f0e7";
+$fa-var-flask: "\f0c3";
+$fa-var-flickr: "\f16e";
+$fa-var-floppy-o: "\f0c7";
+$fa-var-folder: "\f07b";
+$fa-var-folder-o: "\f114";
+$fa-var-folder-open: "\f07c";
+$fa-var-folder-open-o: "\f115";
+$fa-var-font: "\f031";
+$fa-var-font-awesome: "\f2b4";
+$fa-var-fonticons: "\f280";
+$fa-var-fort-awesome: "\f286";
+$fa-var-forumbee: "\f211";
+$fa-var-forward: "\f04e";
+$fa-var-foursquare: "\f180";
+$fa-var-frown-o: "\f119";
+$fa-var-futbol-o: "\f1e3";
+$fa-var-gamepad: "\f11b";
+$fa-var-gavel: "\f0e3";
+$fa-var-gbp: "\f154";
+$fa-var-ge: "\f1d1";
+$fa-var-gear: "\f013";
+$fa-var-gears: "\f085";
+$fa-var-genderless: "\f22d";
+$fa-var-get-pocket: "\f265";
+$fa-var-gg: "\f260";
+$fa-var-gg-circle: "\f261";
+$fa-var-gift: "\f06b";
+$fa-var-git: "\f1d3";
+$fa-var-git-square: "\f1d2";
+$fa-var-github: "\f09b";
+$fa-var-github-alt: "\f113";
+$fa-var-github-square: "\f092";
+$fa-var-gitlab: "\f296";
+$fa-var-gittip: "\f184";
+$fa-var-glass: "\f000";
+$fa-var-glide: "\f2a5";
+$fa-var-glide-g: "\f2a6";
+$fa-var-globe: "\f0ac";
+$fa-var-google: "\f1a0";
+$fa-var-google-plus: "\f0d5";
+$fa-var-google-plus-circle: "\f2b3";
+$fa-var-google-plus-official: "\f2b3";
+$fa-var-google-plus-square: "\f0d4";
+$fa-var-google-wallet: "\f1ee";
+$fa-var-graduation-cap: "\f19d";
+$fa-var-gratipay: "\f184";
+$fa-var-group: "\f0c0";
+$fa-var-h-square: "\f0fd";
+$fa-var-hacker-news: "\f1d4";
+$fa-var-hand-grab-o: "\f255";
+$fa-var-hand-lizard-o: "\f258";
+$fa-var-hand-o-down: "\f0a7";
+$fa-var-hand-o-left: "\f0a5";
+$fa-var-hand-o-right: "\f0a4";
+$fa-var-hand-o-up: "\f0a6";
+$fa-var-hand-paper-o: "\f256";
+$fa-var-hand-peace-o: "\f25b";
+$fa-var-hand-pointer-o: "\f25a";
+$fa-var-hand-rock-o: "\f255";
+$fa-var-hand-scissors-o: "\f257";
+$fa-var-hand-spock-o: "\f259";
+$fa-var-hand-stop-o: "\f256";
+$fa-var-hard-of-hearing: "\f2a4";
+$fa-var-hashtag: "\f292";
+$fa-var-hdd-o: "\f0a0";
+$fa-var-header: "\f1dc";
+$fa-var-headphones: "\f025";
+$fa-var-heart: "\f004";
+$fa-var-heart-o: "\f08a";
+$fa-var-heartbeat: "\f21e";
+$fa-var-history: "\f1da";
+$fa-var-home: "\f015";
+$fa-var-hospital-o: "\f0f8";
+$fa-var-hotel: "\f236";
+$fa-var-hourglass: "\f254";
+$fa-var-hourglass-1: "\f251";
+$fa-var-hourglass-2: "\f252";
+$fa-var-hourglass-3: "\f253";
+$fa-var-hourglass-end: "\f253";
+$fa-var-hourglass-half: "\f252";
+$fa-var-hourglass-o: "\f250";
+$fa-var-hourglass-start: "\f251";
+$fa-var-houzz: "\f27c";
+$fa-var-html5: "\f13b";
+$fa-var-i-cursor: "\f246";
+$fa-var-ils: "\f20b";
+$fa-var-image: "\f03e";
+$fa-var-inbox: "\f01c";
+$fa-var-indent: "\f03c";
+$fa-var-industry: "\f275";
+$fa-var-info: "\f129";
+$fa-var-info-circle: "\f05a";
+$fa-var-inr: "\f156";
+$fa-var-instagram: "\f16d";
+$fa-var-institution: "\f19c";
+$fa-var-internet-explorer: "\f26b";
+$fa-var-intersex: "\f224";
+$fa-var-ioxhost: "\f208";
+$fa-var-italic: "\f033";
+$fa-var-joomla: "\f1aa";
+$fa-var-jpy: "\f157";
+$fa-var-jsfiddle: "\f1cc";
+$fa-var-key: "\f084";
+$fa-var-keyboard-o: "\f11c";
+$fa-var-krw: "\f159";
+$fa-var-language: "\f1ab";
+$fa-var-laptop: "\f109";
+$fa-var-lastfm: "\f202";
+$fa-var-lastfm-square: "\f203";
+$fa-var-leaf: "\f06c";
+$fa-var-leanpub: "\f212";
+$fa-var-legal: "\f0e3";
+$fa-var-lemon-o: "\f094";
+$fa-var-level-down: "\f149";
+$fa-var-level-up: "\f148";
+$fa-var-life-bouy: "\f1cd";
+$fa-var-life-buoy: "\f1cd";
+$fa-var-life-ring: "\f1cd";
+$fa-var-life-saver: "\f1cd";
+$fa-var-lightbulb-o: "\f0eb";
+$fa-var-line-chart: "\f201";
+$fa-var-link: "\f0c1";
+$fa-var-linkedin: "\f0e1";
+$fa-var-linkedin-square: "\f08c";
+$fa-var-linux: "\f17c";
+$fa-var-list: "\f03a";
+$fa-var-list-alt: "\f022";
+$fa-var-list-ol: "\f0cb";
+$fa-var-list-ul: "\f0ca";
+$fa-var-location-arrow: "\f124";
+$fa-var-lock: "\f023";
+$fa-var-long-arrow-down: "\f175";
+$fa-var-long-arrow-left: "\f177";
+$fa-var-long-arrow-right: "\f178";
+$fa-var-long-arrow-up: "\f176";
+$fa-var-low-vision: "\f2a8";
+$fa-var-magic: "\f0d0";
+$fa-var-magnet: "\f076";
+$fa-var-mail-forward: "\f064";
+$fa-var-mail-reply: "\f112";
+$fa-var-mail-reply-all: "\f122";
+$fa-var-male: "\f183";
+$fa-var-map: "\f279";
+$fa-var-map-marker: "\f041";
+$fa-var-map-o: "\f278";
+$fa-var-map-pin: "\f276";
+$fa-var-map-signs: "\f277";
+$fa-var-mars: "\f222";
+$fa-var-mars-double: "\f227";
+$fa-var-mars-stroke: "\f229";
+$fa-var-mars-stroke-h: "\f22b";
+$fa-var-mars-stroke-v: "\f22a";
+$fa-var-maxcdn: "\f136";
+$fa-var-meanpath: "\f20c";
+$fa-var-medium: "\f23a";
+$fa-var-medkit: "\f0fa";
+$fa-var-meh-o: "\f11a";
+$fa-var-mercury: "\f223";
+$fa-var-microphone: "\f130";
+$fa-var-microphone-slash: "\f131";
+$fa-var-minus: "\f068";
+$fa-var-minus-circle: "\f056";
+$fa-var-minus-square: "\f146";
+$fa-var-minus-square-o: "\f147";
+$fa-var-mixcloud: "\f289";
+$fa-var-mobile: "\f10b";
+$fa-var-mobile-phone: "\f10b";
+$fa-var-modx: "\f285";
+$fa-var-money: "\f0d6";
+$fa-var-moon-o: "\f186";
+$fa-var-mortar-board: "\f19d";
+$fa-var-motorcycle: "\f21c";
+$fa-var-mouse-pointer: "\f245";
+$fa-var-music: "\f001";
+$fa-var-navicon: "\f0c9";
+$fa-var-neuter: "\f22c";
+$fa-var-newspaper-o: "\f1ea";
+$fa-var-object-group: "\f247";
+$fa-var-object-ungroup: "\f248";
+$fa-var-odnoklassniki: "\f263";
+$fa-var-odnoklassniki-square: "\f264";
+$fa-var-opencart: "\f23d";
+$fa-var-openid: "\f19b";
+$fa-var-opera: "\f26a";
+$fa-var-optin-monster: "\f23c";
+$fa-var-outdent: "\f03b";
+$fa-var-pagelines: "\f18c";
+$fa-var-paint-brush: "\f1fc";
+$fa-var-paper-plane: "\f1d8";
+$fa-var-paper-plane-o: "\f1d9";
+$fa-var-paperclip: "\f0c6";
+$fa-var-paragraph: "\f1dd";
+$fa-var-paste: "\f0ea";
+$fa-var-pause: "\f04c";
+$fa-var-pause-circle: "\f28b";
+$fa-var-pause-circle-o: "\f28c";
+$fa-var-paw: "\f1b0";
+$fa-var-paypal: "\f1ed";
+$fa-var-pencil: "\f040";
+$fa-var-pencil-square: "\f14b";
+$fa-var-pencil-square-o: "\f044";
+$fa-var-percent: "\f295";
+$fa-var-phone: "\f095";
+$fa-var-phone-square: "\f098";
+$fa-var-photo: "\f03e";
+$fa-var-picture-o: "\f03e";
+$fa-var-pie-chart: "\f200";
+$fa-var-pied-piper: "\f2ae";
+$fa-var-pied-piper-alt: "\f1a8";
+$fa-var-pied-piper-pp: "\f1a7";
+$fa-var-pinterest: "\f0d2";
+$fa-var-pinterest-p: "\f231";
+$fa-var-pinterest-square: "\f0d3";
+$fa-var-plane: "\f072";
+$fa-var-play: "\f04b";
+$fa-var-play-circle: "\f144";
+$fa-var-play-circle-o: "\f01d";
+$fa-var-plug: "\f1e6";
+$fa-var-plus: "\f067";
+$fa-var-plus-circle: "\f055";
+$fa-var-plus-square: "\f0fe";
+$fa-var-plus-square-o: "\f196";
+$fa-var-power-off: "\f011";
+$fa-var-print: "\f02f";
+$fa-var-product-hunt: "\f288";
+$fa-var-puzzle-piece: "\f12e";
+$fa-var-qq: "\f1d6";
+$fa-var-qrcode: "\f029";
+$fa-var-question: "\f128";
+$fa-var-question-circle: "\f059";
+$fa-var-question-circle-o: "\f29c";
+$fa-var-quote-left: "\f10d";
+$fa-var-quote-right: "\f10e";
+$fa-var-ra: "\f1d0";
+$fa-var-random: "\f074";
+$fa-var-rebel: "\f1d0";
+$fa-var-recycle: "\f1b8";
+$fa-var-reddit: "\f1a1";
+$fa-var-reddit-alien: "\f281";
+$fa-var-reddit-square: "\f1a2";
+$fa-var-refresh: "\f021";
+$fa-var-registered: "\f25d";
+$fa-var-remove: "\f00d";
+$fa-var-renren: "\f18b";
+$fa-var-reorder: "\f0c9";
+$fa-var-repeat: "\f01e";
+$fa-var-reply: "\f112";
+$fa-var-reply-all: "\f122";
+$fa-var-resistance: "\f1d0";
+$fa-var-retweet: "\f079";
+$fa-var-rmb: "\f157";
+$fa-var-road: "\f018";
+$fa-var-rocket: "\f135";
+$fa-var-rotate-left: "\f0e2";
+$fa-var-rotate-right: "\f01e";
+$fa-var-rouble: "\f158";
+$fa-var-rss: "\f09e";
+$fa-var-rss-square: "\f143";
+$fa-var-rub: "\f158";
+$fa-var-ruble: "\f158";
+$fa-var-rupee: "\f156";
+$fa-var-safari: "\f267";
+$fa-var-save: "\f0c7";
+$fa-var-scissors: "\f0c4";
+$fa-var-scribd: "\f28a";
+$fa-var-search: "\f002";
+$fa-var-search-minus: "\f010";
+$fa-var-search-plus: "\f00e";
+$fa-var-sellsy: "\f213";
+$fa-var-send: "\f1d8";
+$fa-var-send-o: "\f1d9";
+$fa-var-server: "\f233";
+$fa-var-share: "\f064";
+$fa-var-share-alt: "\f1e0";
+$fa-var-share-alt-square: "\f1e1";
+$fa-var-share-square: "\f14d";
+$fa-var-share-square-o: "\f045";
+$fa-var-shekel: "\f20b";
+$fa-var-sheqel: "\f20b";
+$fa-var-shield: "\f132";
+$fa-var-ship: "\f21a";
+$fa-var-shirtsinbulk: "\f214";
+$fa-var-shopping-bag: "\f290";
+$fa-var-shopping-basket: "\f291";
+$fa-var-shopping-cart: "\f07a";
+$fa-var-sign-in: "\f090";
+$fa-var-sign-language: "\f2a7";
+$fa-var-sign-out: "\f08b";
+$fa-var-signal: "\f012";
+$fa-var-signing: "\f2a7";
+$fa-var-simplybuilt: "\f215";
+$fa-var-sitemap: "\f0e8";
+$fa-var-skyatlas: "\f216";
+$fa-var-skype: "\f17e";
+$fa-var-slack: "\f198";
+$fa-var-sliders: "\f1de";
+$fa-var-slideshare: "\f1e7";
+$fa-var-smile-o: "\f118";
+$fa-var-snapchat: "\f2ab";
+$fa-var-snapchat-ghost: "\f2ac";
+$fa-var-snapchat-square: "\f2ad";
+$fa-var-soccer-ball-o: "\f1e3";
+$fa-var-sort: "\f0dc";
+$fa-var-sort-alpha-asc: "\f15d";
+$fa-var-sort-alpha-desc: "\f15e";
+$fa-var-sort-amount-asc: "\f160";
+$fa-var-sort-amount-desc: "\f161";
+$fa-var-sort-asc: "\f0de";
+$fa-var-sort-desc: "\f0dd";
+$fa-var-sort-down: "\f0dd";
+$fa-var-sort-numeric-asc: "\f162";
+$fa-var-sort-numeric-desc: "\f163";
+$fa-var-sort-up: "\f0de";
+$fa-var-soundcloud: "\f1be";
+$fa-var-space-shuttle: "\f197";
+$fa-var-spinner: "\f110";
+$fa-var-spoon: "\f1b1";
+$fa-var-spotify: "\f1bc";
+$fa-var-square: "\f0c8";
+$fa-var-square-o: "\f096";
+$fa-var-stack-exchange: "\f18d";
+$fa-var-stack-overflow: "\f16c";
+$fa-var-star: "\f005";
+$fa-var-star-half: "\f089";
+$fa-var-star-half-empty: "\f123";
+$fa-var-star-half-full: "\f123";
+$fa-var-star-half-o: "\f123";
+$fa-var-star-o: "\f006";
+$fa-var-steam: "\f1b6";
+$fa-var-steam-square: "\f1b7";
+$fa-var-step-backward: "\f048";
+$fa-var-step-forward: "\f051";
+$fa-var-stethoscope: "\f0f1";
+$fa-var-sticky-note: "\f249";
+$fa-var-sticky-note-o: "\f24a";
+$fa-var-stop: "\f04d";
+$fa-var-stop-circle: "\f28d";
+$fa-var-stop-circle-o: "\f28e";
+$fa-var-street-view: "\f21d";
+$fa-var-strikethrough: "\f0cc";
+$fa-var-stumbleupon: "\f1a4";
+$fa-var-stumbleupon-circle: "\f1a3";
+$fa-var-subscript: "\f12c";
+$fa-var-subway: "\f239";
+$fa-var-suitcase: "\f0f2";
+$fa-var-sun-o: "\f185";
+$fa-var-superscript: "\f12b";
+$fa-var-support: "\f1cd";
+$fa-var-table: "\f0ce";
+$fa-var-tablet: "\f10a";
+$fa-var-tachometer: "\f0e4";
+$fa-var-tag: "\f02b";
+$fa-var-tags: "\f02c";
+$fa-var-tasks: "\f0ae";
+$fa-var-taxi: "\f1ba";
+$fa-var-television: "\f26c";
+$fa-var-tencent-weibo: "\f1d5";
+$fa-var-terminal: "\f120";
+$fa-var-text-height: "\f034";
+$fa-var-text-width: "\f035";
+$fa-var-th: "\f00a";
+$fa-var-th-large: "\f009";
+$fa-var-th-list: "\f00b";
+$fa-var-themeisle: "\f2b2";
+$fa-var-thumb-tack: "\f08d";
+$fa-var-thumbs-down: "\f165";
+$fa-var-thumbs-o-down: "\f088";
+$fa-var-thumbs-o-up: "\f087";
+$fa-var-thumbs-up: "\f164";
+$fa-var-ticket: "\f145";
+$fa-var-times: "\f00d";
+$fa-var-times-circle: "\f057";
+$fa-var-times-circle-o: "\f05c";
+$fa-var-tint: "\f043";
+$fa-var-toggle-down: "\f150";
+$fa-var-toggle-left: "\f191";
+$fa-var-toggle-off: "\f204";
+$fa-var-toggle-on: "\f205";
+$fa-var-toggle-right: "\f152";
+$fa-var-toggle-up: "\f151";
+$fa-var-trademark: "\f25c";
+$fa-var-train: "\f238";
+$fa-var-transgender: "\f224";
+$fa-var-transgender-alt: "\f225";
+$fa-var-trash: "\f1f8";
+$fa-var-trash-o: "\f014";
+$fa-var-tree: "\f1bb";
+$fa-var-trello: "\f181";
+$fa-var-tripadvisor: "\f262";
+$fa-var-trophy: "\f091";
+$fa-var-truck: "\f0d1";
+$fa-var-try: "\f195";
+$fa-var-tty: "\f1e4";
+$fa-var-tumblr: "\f173";
+$fa-var-tumblr-square: "\f174";
+$fa-var-turkish-lira: "\f195";
+$fa-var-tv: "\f26c";
+$fa-var-twitch: "\f1e8";
+$fa-var-twitter: "\f099";
+$fa-var-twitter-square: "\f081";
+$fa-var-umbrella: "\f0e9";
+$fa-var-underline: "\f0cd";
+$fa-var-undo: "\f0e2";
+$fa-var-universal-access: "\f29a";
+$fa-var-university: "\f19c";
+$fa-var-unlink: "\f127";
+$fa-var-unlock: "\f09c";
+$fa-var-unlock-alt: "\f13e";
+$fa-var-unsorted: "\f0dc";
+$fa-var-upload: "\f093";
+$fa-var-usb: "\f287";
+$fa-var-usd: "\f155";
+$fa-var-user: "\f007";
+$fa-var-user-md: "\f0f0";
+$fa-var-user-plus: "\f234";
+$fa-var-user-secret: "\f21b";
+$fa-var-user-times: "\f235";
+$fa-var-users: "\f0c0";
+$fa-var-venus: "\f221";
+$fa-var-venus-double: "\f226";
+$fa-var-venus-mars: "\f228";
+$fa-var-viacoin: "\f237";
+$fa-var-viadeo: "\f2a9";
+$fa-var-viadeo-square: "\f2aa";
+$fa-var-video-camera: "\f03d";
+$fa-var-vimeo: "\f27d";
+$fa-var-vimeo-square: "\f194";
+$fa-var-vine: "\f1ca";
+$fa-var-vk: "\f189";
+$fa-var-volume-control-phone: "\f2a0";
+$fa-var-volume-down: "\f027";
+$fa-var-volume-off: "\f026";
+$fa-var-volume-up: "\f028";
+$fa-var-warning: "\f071";
+$fa-var-wechat: "\f1d7";
+$fa-var-weibo: "\f18a";
+$fa-var-weixin: "\f1d7";
+$fa-var-whatsapp: "\f232";
+$fa-var-wheelchair: "\f193";
+$fa-var-wheelchair-alt: "\f29b";
+$fa-var-wifi: "\f1eb";
+$fa-var-wikipedia-w: "\f266";
+$fa-var-windows: "\f17a";
+$fa-var-won: "\f159";
+$fa-var-wordpress: "\f19a";
+$fa-var-wpbeginner: "\f297";
+$fa-var-wpforms: "\f298";
+$fa-var-wrench: "\f0ad";
+$fa-var-xing: "\f168";
+$fa-var-xing-square: "\f169";
+$fa-var-y-combinator: "\f23b";
+$fa-var-y-combinator-square: "\f1d4";
+$fa-var-yahoo: "\f19e";
+$fa-var-yc: "\f23b";
+$fa-var-yc-square: "\f1d4";
+$fa-var-yelp: "\f1e9";
+$fa-var-yen: "\f157";
+$fa-var-yoast: "\f2b1";
+$fa-var-youtube: "\f167";
+$fa-var-youtube-play: "\f16a";
+$fa-var-youtube-square: "\f166";
+
diff --git a/hubs/static/font-awesome-4.6.3/scss/font-awesome.scss b/hubs/static/font-awesome-4.6.3/scss/font-awesome.scss
new file mode 100644
index 0000000..2308b14
--- /dev/null
+++ b/hubs/static/font-awesome-4.6.3/scss/font-awesome.scss
@@ -0,0 +1,18 @@
+/*!
+ *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */
+
+@import "variables";
+@import "mixins";
+@import "path";
+@import "core";
+@import "larger";
+@import "fixed-width";
+@import "list";
+@import "bordered-pulled";
+@import "animated";
+@import "rotated-flipped";
+@import "stacked";
+@import "icons";
+@import "screen-reader";

From 5d12306df2ae17649449e809fd565bb6c2b23cd6 Mon Sep 17 00:00:00 2001
From: rkolathu <you@example.com>
Date: Aug 01 2016 16:44:57 +0000
Subject: [PATCH 592/1001] Removed font-awesome folder and added CDN


---

diff --git a/hubs/static/font-awesome-4.6.3/HELP-US-OUT.txt b/hubs/static/font-awesome-4.6.3/HELP-US-OUT.txt
deleted file mode 100644
index 83d083d..0000000
--- a/hubs/static/font-awesome-4.6.3/HELP-US-OUT.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project,
-Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome,
-comprehensive icon sets or copy and paste your own.
-
-Please. Check it out.
-
--Dave Gandy
diff --git a/hubs/static/font-awesome-4.6.3/css/font-awesome.css b/hubs/static/font-awesome-4.6.3/css/font-awesome.css
deleted file mode 100644
index 74e77d0..0000000
--- a/hubs/static/font-awesome-4.6.3/css/font-awesome.css
+++ /dev/null
@@ -1,2199 +0,0 @@
-/*!
- *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
- *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */
-/* FONT PATH
- * -------------------------- */
-@font-face {
-  font-family: 'FontAwesome';
-  src: url('../fonts/fontawesome-webfont.eot?v=4.6.3');
-  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.6.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.6.3') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.6.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.6.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.6.3#fontawesomeregular') format('svg');
-  font-weight: normal;
-  font-style: normal;
-}
-.fa {
-  display: inline-block;
-  font: normal normal normal 14px/1 FontAwesome;
-  font-size: inherit;
-  text-rendering: auto;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-/* makes the font 33% larger relative to the icon container */
-.fa-lg {
-  font-size: 1.33333333em;
-  line-height: 0.75em;
-  vertical-align: -15%;
-}
-.fa-2x {
-  font-size: 2em;
-}
-.fa-3x {
-  font-size: 3em;
-}
-.fa-4x {
-  font-size: 4em;
-}
-.fa-5x {
-  font-size: 5em;
-}
-.fa-fw {
-  width: 1.28571429em;
-  text-align: center;
-}
-.fa-ul {
-  padding-left: 0;
-  margin-left: 2.14285714em;
-  list-style-type: none;
-}
-.fa-ul > li {
-  position: relative;
-}
-.fa-li {
-  position: absolute;
-  left: -2.14285714em;
-  width: 2.14285714em;
-  top: 0.14285714em;
-  text-align: center;
-}
-.fa-li.fa-lg {
-  left: -1.85714286em;
-}
-.fa-border {
-  padding: .2em .25em .15em;
-  border: solid 0.08em #eee;
-  border-radius: .1em;
-}
-.fa-pull-left {
-  float: left;
-}
-.fa-pull-right {
-  float: right;
-}
-.fa.fa-pull-left {
-  margin-right: .3em;
-}
-.fa.fa-pull-right {
-  margin-left: .3em;
-}
-/* Deprecated as of 4.4.0 */
-.pull-right {
-  float: right;
-}
-.pull-left {
-  float: left;
-}
-.fa.pull-left {
-  margin-right: .3em;
-}
-.fa.pull-right {
-  margin-left: .3em;
-}
-.fa-spin {
-  -webkit-animation: fa-spin 2s infinite linear;
-  animation: fa-spin 2s infinite linear;
-}
-.fa-pulse {
-  -webkit-animation: fa-spin 1s infinite steps(8);
-  animation: fa-spin 1s infinite steps(8);
-}
-@-webkit-keyframes fa-spin {
-  0% {
-    -webkit-transform: rotate(0deg);
-    transform: rotate(0deg);
-  }
-  100% {
-    -webkit-transform: rotate(359deg);
-    transform: rotate(359deg);
-  }
-}
-@keyframes fa-spin {
-  0% {
-    -webkit-transform: rotate(0deg);
-    transform: rotate(0deg);
-  }
-  100% {
-    -webkit-transform: rotate(359deg);
-    transform: rotate(359deg);
-  }
-}
-.fa-rotate-90 {
-  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
-  -webkit-transform: rotate(90deg);
-  -ms-transform: rotate(90deg);
-  transform: rotate(90deg);
-}
-.fa-rotate-180 {
-  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
-  -webkit-transform: rotate(180deg);
-  -ms-transform: rotate(180deg);
-  transform: rotate(180deg);
-}
-.fa-rotate-270 {
-  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
-  -webkit-transform: rotate(270deg);
-  -ms-transform: rotate(270deg);
-  transform: rotate(270deg);
-}
-.fa-flip-horizontal {
-  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
-  -webkit-transform: scale(-1, 1);
-  -ms-transform: scale(-1, 1);
-  transform: scale(-1, 1);
-}
-.fa-flip-vertical {
-  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
-  -webkit-transform: scale(1, -1);
-  -ms-transform: scale(1, -1);
-  transform: scale(1, -1);
-}
-:root .fa-rotate-90,
-:root .fa-rotate-180,
-:root .fa-rotate-270,
-:root .fa-flip-horizontal,
-:root .fa-flip-vertical {
-  filter: none;
-}
-.fa-stack {
-  position: relative;
-  display: inline-block;
-  width: 2em;
-  height: 2em;
-  line-height: 2em;
-  vertical-align: middle;
-}
-.fa-stack-1x,
-.fa-stack-2x {
-  position: absolute;
-  left: 0;
-  width: 100%;
-  text-align: center;
-}
-.fa-stack-1x {
-  line-height: inherit;
-}
-.fa-stack-2x {
-  font-size: 2em;
-}
-.fa-inverse {
-  color: #fff;
-}
-/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
-   readers do not read off random characters that represent icons */
-.fa-glass:before {
-  content: "\f000";
-}
-.fa-music:before {
-  content: "\f001";
-}
-.fa-search:before {
-  content: "\f002";
-}
-.fa-envelope-o:before {
-  content: "\f003";
-}
-.fa-heart:before {
-  content: "\f004";
-}
-.fa-star:before {
-  content: "\f005";
-}
-.fa-star-o:before {
-  content: "\f006";
-}
-.fa-user:before {
-  content: "\f007";
-}
-.fa-film:before {
-  content: "\f008";
-}
-.fa-th-large:before {
-  content: "\f009";
-}
-.fa-th:before {
-  content: "\f00a";
-}
-.fa-th-list:before {
-  content: "\f00b";
-}
-.fa-check:before {
-  content: "\f00c";
-}
-.fa-remove:before,
-.fa-close:before,
-.fa-times:before {
-  content: "\f00d";
-}
-.fa-search-plus:before {
-  content: "\f00e";
-}
-.fa-search-minus:before {
-  content: "\f010";
-}
-.fa-power-off:before {
-  content: "\f011";
-}
-.fa-signal:before {
-  content: "\f012";
-}
-.fa-gear:before,
-.fa-cog:before {
-  content: "\f013";
-}
-.fa-trash-o:before {
-  content: "\f014";
-}
-.fa-home:before {
-  content: "\f015";
-}
-.fa-file-o:before {
-  content: "\f016";
-}
-.fa-clock-o:before {
-  content: "\f017";
-}
-.fa-road:before {
-  content: "\f018";
-}
-.fa-download:before {
-  content: "\f019";
-}
-.fa-arrow-circle-o-down:before {
-  content: "\f01a";
-}
-.fa-arrow-circle-o-up:before {
-  content: "\f01b";
-}
-.fa-inbox:before {
-  content: "\f01c";
-}
-.fa-play-circle-o:before {
-  content: "\f01d";
-}
-.fa-rotate-right:before,
-.fa-repeat:before {
-  content: "\f01e";
-}
-.fa-refresh:before {
-  content: "\f021";
-}
-.fa-list-alt:before {
-  content: "\f022";
-}
-.fa-lock:before {
-  content: "\f023";
-}
-.fa-flag:before {
-  content: "\f024";
-}
-.fa-headphones:before {
-  content: "\f025";
-}
-.fa-volume-off:before {
-  content: "\f026";
-}
-.fa-volume-down:before {
-  content: "\f027";
-}
-.fa-volume-up:before {
-  content: "\f028";
-}
-.fa-qrcode:before {
-  content: "\f029";
-}
-.fa-barcode:before {
-  content: "\f02a";
-}
-.fa-tag:before {
-  content: "\f02b";
-}
-.fa-tags:before {
-  content: "\f02c";
-}
-.fa-book:before {
-  content: "\f02d";
-}
-.fa-bookmark:before {
-  content: "\f02e";
-}
-.fa-print:before {
-  content: "\f02f";
-}
-.fa-camera:before {
-  content: "\f030";
-}
-.fa-font:before {
-  content: "\f031";
-}
-.fa-bold:before {
-  content: "\f032";
-}
-.fa-italic:before {
-  content: "\f033";
-}
-.fa-text-height:before {
-  content: "\f034";
-}
-.fa-text-width:before {
-  content: "\f035";
-}
-.fa-align-left:before {
-  content: "\f036";
-}
-.fa-align-center:before {
-  content: "\f037";
-}
-.fa-align-right:before {
-  content: "\f038";
-}
-.fa-align-justify:before {
-  content: "\f039";
-}
-.fa-list:before {
-  content: "\f03a";
-}
-.fa-dedent:before,
-.fa-outdent:before {
-  content: "\f03b";
-}
-.fa-indent:before {
-  content: "\f03c";
-}
-.fa-video-camera:before {
-  content: "\f03d";
-}
-.fa-photo:before,
-.fa-image:before,
-.fa-picture-o:before {
-  content: "\f03e";
-}
-.fa-pencil:before {
-  content: "\f040";
-}
-.fa-map-marker:before {
-  content: "\f041";
-}
-.fa-adjust:before {
-  content: "\f042";
-}
-.fa-tint:before {
-  content: "\f043";
-}
-.fa-edit:before,
-.fa-pencil-square-o:before {
-  content: "\f044";
-}
-.fa-share-square-o:before {
-  content: "\f045";
-}
-.fa-check-square-o:before {
-  content: "\f046";
-}
-.fa-arrows:before {
-  content: "\f047";
-}
-.fa-step-backward:before {
-  content: "\f048";
-}
-.fa-fast-backward:before {
-  content: "\f049";
-}
-.fa-backward:before {
-  content: "\f04a";
-}
-.fa-play:before {
-  content: "\f04b";
-}
-.fa-pause:before {
-  content: "\f04c";
-}
-.fa-stop:before {
-  content: "\f04d";
-}
-.fa-forward:before {
-  content: "\f04e";
-}
-.fa-fast-forward:before {
-  content: "\f050";
-}
-.fa-step-forward:before {
-  content: "\f051";
-}
-.fa-eject:before {
-  content: "\f052";
-}
-.fa-chevron-left:before {
-  content: "\f053";
-}
-.fa-chevron-right:before {
-  content: "\f054";
-}
-.fa-plus-circle:before {
-  content: "\f055";
-}
-.fa-minus-circle:before {
-  content: "\f056";
-}
-.fa-times-circle:before {
-  content: "\f057";
-}
-.fa-check-circle:before {
-  content: "\f058";
-}
-.fa-question-circle:before {
-  content: "\f059";
-}
-.fa-info-circle:before {
-  content: "\f05a";
-}
-.fa-crosshairs:before {
-  content: "\f05b";
-}
-.fa-times-circle-o:before {
-  content: "\f05c";
-}
-.fa-check-circle-o:before {
-  content: "\f05d";
-}
-.fa-ban:before {
-  content: "\f05e";
-}
-.fa-arrow-left:before {
-  content: "\f060";
-}
-.fa-arrow-right:before {
-  content: "\f061";
-}
-.fa-arrow-up:before {
-  content: "\f062";
-}
-.fa-arrow-down:before {
-  content: "\f063";
-}
-.fa-mail-forward:before,
-.fa-share:before {
-  content: "\f064";
-}
-.fa-expand:before {
-  content: "\f065";
-}
-.fa-compress:before {
-  content: "\f066";
-}
-.fa-plus:before {
-  content: "\f067";
-}
-.fa-minus:before {
-  content: "\f068";
-}
-.fa-asterisk:before {
-  content: "\f069";
-}
-.fa-exclamation-circle:before {
-  content: "\f06a";
-}
-.fa-gift:before {
-  content: "\f06b";
-}
-.fa-leaf:before {
-  content: "\f06c";
-}
-.fa-fire:before {
-  content: "\f06d";
-}
-.fa-eye:before {
-  content: "\f06e";
-}
-.fa-eye-slash:before {
-  content: "\f070";
-}
-.fa-warning:before,
-.fa-exclamation-triangle:before {
-  content: "\f071";
-}
-.fa-plane:before {
-  content: "\f072";
-}
-.fa-calendar:before {
-  content: "\f073";
-}
-.fa-random:before {
-  content: "\f074";
-}
-.fa-comment:before {
-  content: "\f075";
-}
-.fa-magnet:before {
-  content: "\f076";
-}
-.fa-chevron-up:before {
-  content: "\f077";
-}
-.fa-chevron-down:before {
-  content: "\f078";
-}
-.fa-retweet:before {
-  content: "\f079";
-}
-.fa-shopping-cart:before {
-  content: "\f07a";
-}
-.fa-folder:before {
-  content: "\f07b";
-}
-.fa-folder-open:before {
-  content: "\f07c";
-}
-.fa-arrows-v:before {
-  content: "\f07d";
-}
-.fa-arrows-h:before {
-  content: "\f07e";
-}
-.fa-bar-chart-o:before,
-.fa-bar-chart:before {
-  content: "\f080";
-}
-.fa-twitter-square:before {
-  content: "\f081";
-}
-.fa-facebook-square:before {
-  content: "\f082";
-}
-.fa-camera-retro:before {
-  content: "\f083";
-}
-.fa-key:before {
-  content: "\f084";
-}
-.fa-gears:before,
-.fa-cogs:before {
-  content: "\f085";
-}
-.fa-comments:before {
-  content: "\f086";
-}
-.fa-thumbs-o-up:before {
-  content: "\f087";
-}
-.fa-thumbs-o-down:before {
-  content: "\f088";
-}
-.fa-star-half:before {
-  content: "\f089";
-}
-.fa-heart-o:before {
-  content: "\f08a";
-}
-.fa-sign-out:before {
-  content: "\f08b";
-}
-.fa-linkedin-square:before {
-  content: "\f08c";
-}
-.fa-thumb-tack:before {
-  content: "\f08d";
-}
-.fa-external-link:before {
-  content: "\f08e";
-}
-.fa-sign-in:before {
-  content: "\f090";
-}
-.fa-trophy:before {
-  content: "\f091";
-}
-.fa-github-square:before {
-  content: "\f092";
-}
-.fa-upload:before {
-  content: "\f093";
-}
-.fa-lemon-o:before {
-  content: "\f094";
-}
-.fa-phone:before {
-  content: "\f095";
-}
-.fa-square-o:before {
-  content: "\f096";
-}
-.fa-bookmark-o:before {
-  content: "\f097";
-}
-.fa-phone-square:before {
-  content: "\f098";
-}
-.fa-twitter:before {
-  content: "\f099";
-}
-.fa-facebook-f:before,
-.fa-facebook:before {
-  content: "\f09a";
-}
-.fa-github:before {
-  content: "\f09b";
-}
-.fa-unlock:before {
-  content: "\f09c";
-}
-.fa-credit-card:before {
-  content: "\f09d";
-}
-.fa-feed:before,
-.fa-rss:before {
-  content: "\f09e";
-}
-.fa-hdd-o:before {
-  content: "\f0a0";
-}
-.fa-bullhorn:before {
-  content: "\f0a1";
-}
-.fa-bell:before {
-  content: "\f0f3";
-}
-.fa-certificate:before {
-  content: "\f0a3";
-}
-.fa-hand-o-right:before {
-  content: "\f0a4";
-}
-.fa-hand-o-left:before {
-  content: "\f0a5";
-}
-.fa-hand-o-up:before {
-  content: "\f0a6";
-}
-.fa-hand-o-down:before {
-  content: "\f0a7";
-}
-.fa-arrow-circle-left:before {
-  content: "\f0a8";
-}
-.fa-arrow-circle-right:before {
-  content: "\f0a9";
-}
-.fa-arrow-circle-up:before {
-  content: "\f0aa";
-}
-.fa-arrow-circle-down:before {
-  content: "\f0ab";
-}
-.fa-globe:before {
-  content: "\f0ac";
-}
-.fa-wrench:before {
-  content: "\f0ad";
-}
-.fa-tasks:before {
-  content: "\f0ae";
-}
-.fa-filter:before {
-  content: "\f0b0";
-}
-.fa-briefcase:before {
-  content: "\f0b1";
-}
-.fa-arrows-alt:before {
-  content: "\f0b2";
-}
-.fa-group:before,
-.fa-users:before {
-  content: "\f0c0";
-}
-.fa-chain:before,
-.fa-link:before {
-  content: "\f0c1";
-}
-.fa-cloud:before {
-  content: "\f0c2";
-}
-.fa-flask:before {
-  content: "\f0c3";
-}
-.fa-cut:before,
-.fa-scissors:before {
-  content: "\f0c4";
-}
-.fa-copy:before,
-.fa-files-o:before {
-  content: "\f0c5";
-}
-.fa-paperclip:before {
-  content: "\f0c6";
-}
-.fa-save:before,
-.fa-floppy-o:before {
-  content: "\f0c7";
-}
-.fa-square:before {
-  content: "\f0c8";
-}
-.fa-navicon:before,
-.fa-reorder:before,
-.fa-bars:before {
-  content: "\f0c9";
-}
-.fa-list-ul:before {
-  content: "\f0ca";
-}
-.fa-list-ol:before {
-  content: "\f0cb";
-}
-.fa-strikethrough:before {
-  content: "\f0cc";
-}
-.fa-underline:before {
-  content: "\f0cd";
-}
-.fa-table:before {
-  content: "\f0ce";
-}
-.fa-magic:before {
-  content: "\f0d0";
-}
-.fa-truck:before {
-  content: "\f0d1";
-}
-.fa-pinterest:before {
-  content: "\f0d2";
-}
-.fa-pinterest-square:before {
-  content: "\f0d3";
-}
-.fa-google-plus-square:before {
-  content: "\f0d4";
-}
-.fa-google-plus:before {
-  content: "\f0d5";
-}
-.fa-money:before {
-  content: "\f0d6";
-}
-.fa-caret-down:before {
-  content: "\f0d7";
-}
-.fa-caret-up:before {
-  content: "\f0d8";
-}
-.fa-caret-left:before {
-  content: "\f0d9";
-}
-.fa-caret-right:before {
-  content: "\f0da";
-}
-.fa-columns:before {
-  content: "\f0db";
-}
-.fa-unsorted:before,
-.fa-sort:before {
-  content: "\f0dc";
-}
-.fa-sort-down:before,
-.fa-sort-desc:before {
-  content: "\f0dd";
-}
-.fa-sort-up:before,
-.fa-sort-asc:before {
-  content: "\f0de";
-}
-.fa-envelope:before {
-  content: "\f0e0";
-}
-.fa-linkedin:before {
-  content: "\f0e1";
-}
-.fa-rotate-left:before,
-.fa-undo:before {
-  content: "\f0e2";
-}
-.fa-legal:before,
-.fa-gavel:before {
-  content: "\f0e3";
-}
-.fa-dashboard:before,
-.fa-tachometer:before {
-  content: "\f0e4";
-}
-.fa-comment-o:before {
-  content: "\f0e5";
-}
-.fa-comments-o:before {
-  content: "\f0e6";
-}
-.fa-flash:before,
-.fa-bolt:before {
-  content: "\f0e7";
-}
-.fa-sitemap:before {
-  content: "\f0e8";
-}
-.fa-umbrella:before {
-  content: "\f0e9";
-}
-.fa-paste:before,
-.fa-clipboard:before {
-  content: "\f0ea";
-}
-.fa-lightbulb-o:before {
-  content: "\f0eb";
-}
-.fa-exchange:before {
-  content: "\f0ec";
-}
-.fa-cloud-download:before {
-  content: "\f0ed";
-}
-.fa-cloud-upload:before {
-  content: "\f0ee";
-}
-.fa-user-md:before {
-  content: "\f0f0";
-}
-.fa-stethoscope:before {
-  content: "\f0f1";
-}
-.fa-suitcase:before {
-  content: "\f0f2";
-}
-.fa-bell-o:before {
-  content: "\f0a2";
-}
-.fa-coffee:before {
-  content: "\f0f4";
-}
-.fa-cutlery:before {
-  content: "\f0f5";
-}
-.fa-file-text-o:before {
-  content: "\f0f6";
-}
-.fa-building-o:before {
-  content: "\f0f7";
-}
-.fa-hospital-o:before {
-  content: "\f0f8";
-}
-.fa-ambulance:before {
-  content: "\f0f9";
-}
-.fa-medkit:before {
-  content: "\f0fa";
-}
-.fa-fighter-jet:before {
-  content: "\f0fb";
-}
-.fa-beer:before {
-  content: "\f0fc";
-}
-.fa-h-square:before {
-  content: "\f0fd";
-}
-.fa-plus-square:before {
-  content: "\f0fe";
-}
-.fa-angle-double-left:before {
-  content: "\f100";
-}
-.fa-angle-double-right:before {
-  content: "\f101";
-}
-.fa-angle-double-up:before {
-  content: "\f102";
-}
-.fa-angle-double-down:before {
-  content: "\f103";
-}
-.fa-angle-left:before {
-  content: "\f104";
-}
-.fa-angle-right:before {
-  content: "\f105";
-}
-.fa-angle-up:before {
-  content: "\f106";
-}
-.fa-angle-down:before {
-  content: "\f107";
-}
-.fa-desktop:before {
-  content: "\f108";
-}
-.fa-laptop:before {
-  content: "\f109";
-}
-.fa-tablet:before {
-  content: "\f10a";
-}
-.fa-mobile-phone:before,
-.fa-mobile:before {
-  content: "\f10b";
-}
-.fa-circle-o:before {
-  content: "\f10c";
-}
-.fa-quote-left:before {
-  content: "\f10d";
-}
-.fa-quote-right:before {
-  content: "\f10e";
-}
-.fa-spinner:before {
-  content: "\f110";
-}
-.fa-circle:before {
-  content: "\f111";
-}
-.fa-mail-reply:before,
-.fa-reply:before {
-  content: "\f112";
-}
-.fa-github-alt:before {
-  content: "\f113";
-}
-.fa-folder-o:before {
-  content: "\f114";
-}
-.fa-folder-open-o:before {
-  content: "\f115";
-}
-.fa-smile-o:before {
-  content: "\f118";
-}
-.fa-frown-o:before {
-  content: "\f119";
-}
-.fa-meh-o:before {
-  content: "\f11a";
-}
-.fa-gamepad:before {
-  content: "\f11b";
-}
-.fa-keyboard-o:before {
-  content: "\f11c";
-}
-.fa-flag-o:before {
-  content: "\f11d";
-}
-.fa-flag-checkered:before {
-  content: "\f11e";
-}
-.fa-terminal:before {
-  content: "\f120";
-}
-.fa-code:before {
-  content: "\f121";
-}
-.fa-mail-reply-all:before,
-.fa-reply-all:before {
-  content: "\f122";
-}
-.fa-star-half-empty:before,
-.fa-star-half-full:before,
-.fa-star-half-o:before {
-  content: "\f123";
-}
-.fa-location-arrow:before {
-  content: "\f124";
-}
-.fa-crop:before {
-  content: "\f125";
-}
-.fa-code-fork:before {
-  content: "\f126";
-}
-.fa-unlink:before,
-.fa-chain-broken:before {
-  content: "\f127";
-}
-.fa-question:before {
-  content: "\f128";
-}
-.fa-info:before {
-  content: "\f129";
-}
-.fa-exclamation:before {
-  content: "\f12a";
-}
-.fa-superscript:before {
-  content: "\f12b";
-}
-.fa-subscript:before {
-  content: "\f12c";
-}
-.fa-eraser:before {
-  content: "\f12d";
-}
-.fa-puzzle-piece:before {
-  content: "\f12e";
-}
-.fa-microphone:before {
-  content: "\f130";
-}
-.fa-microphone-slash:before {
-  content: "\f131";
-}
-.fa-shield:before {
-  content: "\f132";
-}
-.fa-calendar-o:before {
-  content: "\f133";
-}
-.fa-fire-extinguisher:before {
-  content: "\f134";
-}
-.fa-rocket:before {
-  content: "\f135";
-}
-.fa-maxcdn:before {
-  content: "\f136";
-}
-.fa-chevron-circle-left:before {
-  content: "\f137";
-}
-.fa-chevron-circle-right:before {
-  content: "\f138";
-}
-.fa-chevron-circle-up:before {
-  content: "\f139";
-}
-.fa-chevron-circle-down:before {
-  content: "\f13a";
-}
-.fa-html5:before {
-  content: "\f13b";
-}
-.fa-css3:before {
-  content: "\f13c";
-}
-.fa-anchor:before {
-  content: "\f13d";
-}
-.fa-unlock-alt:before {
-  content: "\f13e";
-}
-.fa-bullseye:before {
-  content: "\f140";
-}
-.fa-ellipsis-h:before {
-  content: "\f141";
-}
-.fa-ellipsis-v:before {
-  content: "\f142";
-}
-.fa-rss-square:before {
-  content: "\f143";
-}
-.fa-play-circle:before {
-  content: "\f144";
-}
-.fa-ticket:before {
-  content: "\f145";
-}
-.fa-minus-square:before {
-  content: "\f146";
-}
-.fa-minus-square-o:before {
-  content: "\f147";
-}
-.fa-level-up:before {
-  content: "\f148";
-}
-.fa-level-down:before {
-  content: "\f149";
-}
-.fa-check-square:before {
-  content: "\f14a";
-}
-.fa-pencil-square:before {
-  content: "\f14b";
-}
-.fa-external-link-square:before {
-  content: "\f14c";
-}
-.fa-share-square:before {
-  content: "\f14d";
-}
-.fa-compass:before {
-  content: "\f14e";
-}
-.fa-toggle-down:before,
-.fa-caret-square-o-down:before {
-  content: "\f150";
-}
-.fa-toggle-up:before,
-.fa-caret-square-o-up:before {
-  content: "\f151";
-}
-.fa-toggle-right:before,
-.fa-caret-square-o-right:before {
-  content: "\f152";
-}
-.fa-euro:before,
-.fa-eur:before {
-  content: "\f153";
-}
-.fa-gbp:before {
-  content: "\f154";
-}
-.fa-dollar:before,
-.fa-usd:before {
-  content: "\f155";
-}
-.fa-rupee:before,
-.fa-inr:before {
-  content: "\f156";
-}
-.fa-cny:before,
-.fa-rmb:before,
-.fa-yen:before,
-.fa-jpy:before {
-  content: "\f157";
-}
-.fa-ruble:before,
-.fa-rouble:before,
-.fa-rub:before {
-  content: "\f158";
-}
-.fa-won:before,
-.fa-krw:before {
-  content: "\f159";
-}
-.fa-bitcoin:before,
-.fa-btc:before {
-  content: "\f15a";
-}
-.fa-file:before {
-  content: "\f15b";
-}
-.fa-file-text:before {
-  content: "\f15c";
-}
-.fa-sort-alpha-asc:before {
-  content: "\f15d";
-}
-.fa-sort-alpha-desc:before {
-  content: "\f15e";
-}
-.fa-sort-amount-asc:before {
-  content: "\f160";
-}
-.fa-sort-amount-desc:before {
-  content: "\f161";
-}
-.fa-sort-numeric-asc:before {
-  content: "\f162";
-}
-.fa-sort-numeric-desc:before {
-  content: "\f163";
-}
-.fa-thumbs-up:before {
-  content: "\f164";
-}
-.fa-thumbs-down:before {
-  content: "\f165";
-}
-.fa-youtube-square:before {
-  content: "\f166";
-}
-.fa-youtube:before {
-  content: "\f167";
-}
-.fa-xing:before {
-  content: "\f168";
-}
-.fa-xing-square:before {
-  content: "\f169";
-}
-.fa-youtube-play:before {
-  content: "\f16a";
-}
-.fa-dropbox:before {
-  content: "\f16b";
-}
-.fa-stack-overflow:before {
-  content: "\f16c";
-}
-.fa-instagram:before {
-  content: "\f16d";
-}
-.fa-flickr:before {
-  content: "\f16e";
-}
-.fa-adn:before {
-  content: "\f170";
-}
-.fa-bitbucket:before {
-  content: "\f171";
-}
-.fa-bitbucket-square:before {
-  content: "\f172";
-}
-.fa-tumblr:before {
-  content: "\f173";
-}
-.fa-tumblr-square:before {
-  content: "\f174";
-}
-.fa-long-arrow-down:before {
-  content: "\f175";
-}
-.fa-long-arrow-up:before {
-  content: "\f176";
-}
-.fa-long-arrow-left:before {
-  content: "\f177";
-}
-.fa-long-arrow-right:before {
-  content: "\f178";
-}
-.fa-apple:before {
-  content: "\f179";
-}
-.fa-windows:before {
-  content: "\f17a";
-}
-.fa-android:before {
-  content: "\f17b";
-}
-.fa-linux:before {
-  content: "\f17c";
-}
-.fa-dribbble:before {
-  content: "\f17d";
-}
-.fa-skype:before {
-  content: "\f17e";
-}
-.fa-foursquare:before {
-  content: "\f180";
-}
-.fa-trello:before {
-  content: "\f181";
-}
-.fa-female:before {
-  content: "\f182";
-}
-.fa-male:before {
-  content: "\f183";
-}
-.fa-gittip:before,
-.fa-gratipay:before {
-  content: "\f184";
-}
-.fa-sun-o:before {
-  content: "\f185";
-}
-.fa-moon-o:before {
-  content: "\f186";
-}
-.fa-archive:before {
-  content: "\f187";
-}
-.fa-bug:before {
-  content: "\f188";
-}
-.fa-vk:before {
-  content: "\f189";
-}
-.fa-weibo:before {
-  content: "\f18a";
-}
-.fa-renren:before {
-  content: "\f18b";
-}
-.fa-pagelines:before {
-  content: "\f18c";
-}
-.fa-stack-exchange:before {
-  content: "\f18d";
-}
-.fa-arrow-circle-o-right:before {
-  content: "\f18e";
-}
-.fa-arrow-circle-o-left:before {
-  content: "\f190";
-}
-.fa-toggle-left:before,
-.fa-caret-square-o-left:before {
-  content: "\f191";
-}
-.fa-dot-circle-o:before {
-  content: "\f192";
-}
-.fa-wheelchair:before {
-  content: "\f193";
-}
-.fa-vimeo-square:before {
-  content: "\f194";
-}
-.fa-turkish-lira:before,
-.fa-try:before {
-  content: "\f195";
-}
-.fa-plus-square-o:before {
-  content: "\f196";
-}
-.fa-space-shuttle:before {
-  content: "\f197";
-}
-.fa-slack:before {
-  content: "\f198";
-}
-.fa-envelope-square:before {
-  content: "\f199";
-}
-.fa-wordpress:before {
-  content: "\f19a";
-}
-.fa-openid:before {
-  content: "\f19b";
-}
-.fa-institution:before,
-.fa-bank:before,
-.fa-university:before {
-  content: "\f19c";
-}
-.fa-mortar-board:before,
-.fa-graduation-cap:before {
-  content: "\f19d";
-}
-.fa-yahoo:before {
-  content: "\f19e";
-}
-.fa-google:before {
-  content: "\f1a0";
-}
-.fa-reddit:before {
-  content: "\f1a1";
-}
-.fa-reddit-square:before {
-  content: "\f1a2";
-}
-.fa-stumbleupon-circle:before {
-  content: "\f1a3";
-}
-.fa-stumbleupon:before {
-  content: "\f1a4";
-}
-.fa-delicious:before {
-  content: "\f1a5";
-}
-.fa-digg:before {
-  content: "\f1a6";
-}
-.fa-pied-piper-pp:before {
-  content: "\f1a7";
-}
-.fa-pied-piper-alt:before {
-  content: "\f1a8";
-}
-.fa-drupal:before {
-  content: "\f1a9";
-}
-.fa-joomla:before {
-  content: "\f1aa";
-}
-.fa-language:before {
-  content: "\f1ab";
-}
-.fa-fax:before {
-  content: "\f1ac";
-}
-.fa-building:before {
-  content: "\f1ad";
-}
-.fa-child:before {
-  content: "\f1ae";
-}
-.fa-paw:before {
-  content: "\f1b0";
-}
-.fa-spoon:before {
-  content: "\f1b1";
-}
-.fa-cube:before {
-  content: "\f1b2";
-}
-.fa-cubes:before {
-  content: "\f1b3";
-}
-.fa-behance:before {
-  content: "\f1b4";
-}
-.fa-behance-square:before {
-  content: "\f1b5";
-}
-.fa-steam:before {
-  content: "\f1b6";
-}
-.fa-steam-square:before {
-  content: "\f1b7";
-}
-.fa-recycle:before {
-  content: "\f1b8";
-}
-.fa-automobile:before,
-.fa-car:before {
-  content: "\f1b9";
-}
-.fa-cab:before,
-.fa-taxi:before {
-  content: "\f1ba";
-}
-.fa-tree:before {
-  content: "\f1bb";
-}
-.fa-spotify:before {
-  content: "\f1bc";
-}
-.fa-deviantart:before {
-  content: "\f1bd";
-}
-.fa-soundcloud:before {
-  content: "\f1be";
-}
-.fa-database:before {
-  content: "\f1c0";
-}
-.fa-file-pdf-o:before {
-  content: "\f1c1";
-}
-.fa-file-word-o:before {
-  content: "\f1c2";
-}
-.fa-file-excel-o:before {
-  content: "\f1c3";
-}
-.fa-file-powerpoint-o:before {
-  content: "\f1c4";
-}
-.fa-file-photo-o:before,
-.fa-file-picture-o:before,
-.fa-file-image-o:before {
-  content: "\f1c5";
-}
-.fa-file-zip-o:before,
-.fa-file-archive-o:before {
-  content: "\f1c6";
-}
-.fa-file-sound-o:before,
-.fa-file-audio-o:before {
-  content: "\f1c7";
-}
-.fa-file-movie-o:before,
-.fa-file-video-o:before {
-  content: "\f1c8";
-}
-.fa-file-code-o:before {
-  content: "\f1c9";
-}
-.fa-vine:before {
-  content: "\f1ca";
-}
-.fa-codepen:before {
-  content: "\f1cb";
-}
-.fa-jsfiddle:before {
-  content: "\f1cc";
-}
-.fa-life-bouy:before,
-.fa-life-buoy:before,
-.fa-life-saver:before,
-.fa-support:before,
-.fa-life-ring:before {
-  content: "\f1cd";
-}
-.fa-circle-o-notch:before {
-  content: "\f1ce";
-}
-.fa-ra:before,
-.fa-resistance:before,
-.fa-rebel:before {
-  content: "\f1d0";
-}
-.fa-ge:before,
-.fa-empire:before {
-  content: "\f1d1";
-}
-.fa-git-square:before {
-  content: "\f1d2";
-}
-.fa-git:before {
-  content: "\f1d3";
-}
-.fa-y-combinator-square:before,
-.fa-yc-square:before,
-.fa-hacker-news:before {
-  content: "\f1d4";
-}
-.fa-tencent-weibo:before {
-  content: "\f1d5";
-}
-.fa-qq:before {
-  content: "\f1d6";
-}
-.fa-wechat:before,
-.fa-weixin:before {
-  content: "\f1d7";
-}
-.fa-send:before,
-.fa-paper-plane:before {
-  content: "\f1d8";
-}
-.fa-send-o:before,
-.fa-paper-plane-o:before {
-  content: "\f1d9";
-}
-.fa-history:before {
-  content: "\f1da";
-}
-.fa-circle-thin:before {
-  content: "\f1db";
-}
-.fa-header:before {
-  content: "\f1dc";
-}
-.fa-paragraph:before {
-  content: "\f1dd";
-}
-.fa-sliders:before {
-  content: "\f1de";
-}
-.fa-share-alt:before {
-  content: "\f1e0";
-}
-.fa-share-alt-square:before {
-  content: "\f1e1";
-}
-.fa-bomb:before {
-  content: "\f1e2";
-}
-.fa-soccer-ball-o:before,
-.fa-futbol-o:before {
-  content: "\f1e3";
-}
-.fa-tty:before {
-  content: "\f1e4";
-}
-.fa-binoculars:before {
-  content: "\f1e5";
-}
-.fa-plug:before {
-  content: "\f1e6";
-}
-.fa-slideshare:before {
-  content: "\f1e7";
-}
-.fa-twitch:before {
-  content: "\f1e8";
-}
-.fa-yelp:before {
-  content: "\f1e9";
-}
-.fa-newspaper-o:before {
-  content: "\f1ea";
-}
-.fa-wifi:before {
-  content: "\f1eb";
-}
-.fa-calculator:before {
-  content: "\f1ec";
-}
-.fa-paypal:before {
-  content: "\f1ed";
-}
-.fa-google-wallet:before {
-  content: "\f1ee";
-}
-.fa-cc-visa:before {
-  content: "\f1f0";
-}
-.fa-cc-mastercard:before {
-  content: "\f1f1";
-}
-.fa-cc-discover:before {
-  content: "\f1f2";
-}
-.fa-cc-amex:before {
-  content: "\f1f3";
-}
-.fa-cc-paypal:before {
-  content: "\f1f4";
-}
-.fa-cc-stripe:before {
-  content: "\f1f5";
-}
-.fa-bell-slash:before {
-  content: "\f1f6";
-}
-.fa-bell-slash-o:before {
-  content: "\f1f7";
-}
-.fa-trash:before {
-  content: "\f1f8";
-}
-.fa-copyright:before {
-  content: "\f1f9";
-}
-.fa-at:before {
-  content: "\f1fa";
-}
-.fa-eyedropper:before {
-  content: "\f1fb";
-}
-.fa-paint-brush:before {
-  content: "\f1fc";
-}
-.fa-birthday-cake:before {
-  content: "\f1fd";
-}
-.fa-area-chart:before {
-  content: "\f1fe";
-}
-.fa-pie-chart:before {
-  content: "\f200";
-}
-.fa-line-chart:before {
-  content: "\f201";
-}
-.fa-lastfm:before {
-  content: "\f202";
-}
-.fa-lastfm-square:before {
-  content: "\f203";
-}
-.fa-toggle-off:before {
-  content: "\f204";
-}
-.fa-toggle-on:before {
-  content: "\f205";
-}
-.fa-bicycle:before {
-  content: "\f206";
-}
-.fa-bus:before {
-  content: "\f207";
-}
-.fa-ioxhost:before {
-  content: "\f208";
-}
-.fa-angellist:before {
-  content: "\f209";
-}
-.fa-cc:before {
-  content: "\f20a";
-}
-.fa-shekel:before,
-.fa-sheqel:before,
-.fa-ils:before {
-  content: "\f20b";
-}
-.fa-meanpath:before {
-  content: "\f20c";
-}
-.fa-buysellads:before {
-  content: "\f20d";
-}
-.fa-connectdevelop:before {
-  content: "\f20e";
-}
-.fa-dashcube:before {
-  content: "\f210";
-}
-.fa-forumbee:before {
-  content: "\f211";
-}
-.fa-leanpub:before {
-  content: "\f212";
-}
-.fa-sellsy:before {
-  content: "\f213";
-}
-.fa-shirtsinbulk:before {
-  content: "\f214";
-}
-.fa-simplybuilt:before {
-  content: "\f215";
-}
-.fa-skyatlas:before {
-  content: "\f216";
-}
-.fa-cart-plus:before {
-  content: "\f217";
-}
-.fa-cart-arrow-down:before {
-  content: "\f218";
-}
-.fa-diamond:before {
-  content: "\f219";
-}
-.fa-ship:before {
-  content: "\f21a";
-}
-.fa-user-secret:before {
-  content: "\f21b";
-}
-.fa-motorcycle:before {
-  content: "\f21c";
-}
-.fa-street-view:before {
-  content: "\f21d";
-}
-.fa-heartbeat:before {
-  content: "\f21e";
-}
-.fa-venus:before {
-  content: "\f221";
-}
-.fa-mars:before {
-  content: "\f222";
-}
-.fa-mercury:before {
-  content: "\f223";
-}
-.fa-intersex:before,
-.fa-transgender:before {
-  content: "\f224";
-}
-.fa-transgender-alt:before {
-  content: "\f225";
-}
-.fa-venus-double:before {
-  content: "\f226";
-}
-.fa-mars-double:before {
-  content: "\f227";
-}
-.fa-venus-mars:before {
-  content: "\f228";
-}
-.fa-mars-stroke:before {
-  content: "\f229";
-}
-.fa-mars-stroke-v:before {
-  content: "\f22a";
-}
-.fa-mars-stroke-h:before {
-  content: "\f22b";
-}
-.fa-neuter:before {
-  content: "\f22c";
-}
-.fa-genderless:before {
-  content: "\f22d";
-}
-.fa-facebook-official:before {
-  content: "\f230";
-}
-.fa-pinterest-p:before {
-  content: "\f231";
-}
-.fa-whatsapp:before {
-  content: "\f232";
-}
-.fa-server:before {
-  content: "\f233";
-}
-.fa-user-plus:before {
-  content: "\f234";
-}
-.fa-user-times:before {
-  content: "\f235";
-}
-.fa-hotel:before,
-.fa-bed:before {
-  content: "\f236";
-}
-.fa-viacoin:before {
-  content: "\f237";
-}
-.fa-train:before {
-  content: "\f238";
-}
-.fa-subway:before {
-  content: "\f239";
-}
-.fa-medium:before {
-  content: "\f23a";
-}
-.fa-yc:before,
-.fa-y-combinator:before {
-  content: "\f23b";
-}
-.fa-optin-monster:before {
-  content: "\f23c";
-}
-.fa-opencart:before {
-  content: "\f23d";
-}
-.fa-expeditedssl:before {
-  content: "\f23e";
-}
-.fa-battery-4:before,
-.fa-battery-full:before {
-  content: "\f240";
-}
-.fa-battery-3:before,
-.fa-battery-three-quarters:before {
-  content: "\f241";
-}
-.fa-battery-2:before,
-.fa-battery-half:before {
-  content: "\f242";
-}
-.fa-battery-1:before,
-.fa-battery-quarter:before {
-  content: "\f243";
-}
-.fa-battery-0:before,
-.fa-battery-empty:before {
-  content: "\f244";
-}
-.fa-mouse-pointer:before {
-  content: "\f245";
-}
-.fa-i-cursor:before {
-  content: "\f246";
-}
-.fa-object-group:before {
-  content: "\f247";
-}
-.fa-object-ungroup:before {
-  content: "\f248";
-}
-.fa-sticky-note:before {
-  content: "\f249";
-}
-.fa-sticky-note-o:before {
-  content: "\f24a";
-}
-.fa-cc-jcb:before {
-  content: "\f24b";
-}
-.fa-cc-diners-club:before {
-  content: "\f24c";
-}
-.fa-clone:before {
-  content: "\f24d";
-}
-.fa-balance-scale:before {
-  content: "\f24e";
-}
-.fa-hourglass-o:before {
-  content: "\f250";
-}
-.fa-hourglass-1:before,
-.fa-hourglass-start:before {
-  content: "\f251";
-}
-.fa-hourglass-2:before,
-.fa-hourglass-half:before {
-  content: "\f252";
-}
-.fa-hourglass-3:before,
-.fa-hourglass-end:before {
-  content: "\f253";
-}
-.fa-hourglass:before {
-  content: "\f254";
-}
-.fa-hand-grab-o:before,
-.fa-hand-rock-o:before {
-  content: "\f255";
-}
-.fa-hand-stop-o:before,
-.fa-hand-paper-o:before {
-  content: "\f256";
-}
-.fa-hand-scissors-o:before {
-  content: "\f257";
-}
-.fa-hand-lizard-o:before {
-  content: "\f258";
-}
-.fa-hand-spock-o:before {
-  content: "\f259";
-}
-.fa-hand-pointer-o:before {
-  content: "\f25a";
-}
-.fa-hand-peace-o:before {
-  content: "\f25b";
-}
-.fa-trademark:before {
-  content: "\f25c";
-}
-.fa-registered:before {
-  content: "\f25d";
-}
-.fa-creative-commons:before {
-  content: "\f25e";
-}
-.fa-gg:before {
-  content: "\f260";
-}
-.fa-gg-circle:before {
-  content: "\f261";
-}
-.fa-tripadvisor:before {
-  content: "\f262";
-}
-.fa-odnoklassniki:before {
-  content: "\f263";
-}
-.fa-odnoklassniki-square:before {
-  content: "\f264";
-}
-.fa-get-pocket:before {
-  content: "\f265";
-}
-.fa-wikipedia-w:before {
-  content: "\f266";
-}
-.fa-safari:before {
-  content: "\f267";
-}
-.fa-chrome:before {
-  content: "\f268";
-}
-.fa-firefox:before {
-  content: "\f269";
-}
-.fa-opera:before {
-  content: "\f26a";
-}
-.fa-internet-explorer:before {
-  content: "\f26b";
-}
-.fa-tv:before,
-.fa-television:before {
-  content: "\f26c";
-}
-.fa-contao:before {
-  content: "\f26d";
-}
-.fa-500px:before {
-  content: "\f26e";
-}
-.fa-amazon:before {
-  content: "\f270";
-}
-.fa-calendar-plus-o:before {
-  content: "\f271";
-}
-.fa-calendar-minus-o:before {
-  content: "\f272";
-}
-.fa-calendar-times-o:before {
-  content: "\f273";
-}
-.fa-calendar-check-o:before {
-  content: "\f274";
-}
-.fa-industry:before {
-  content: "\f275";
-}
-.fa-map-pin:before {
-  content: "\f276";
-}
-.fa-map-signs:before {
-  content: "\f277";
-}
-.fa-map-o:before {
-  content: "\f278";
-}
-.fa-map:before {
-  content: "\f279";
-}
-.fa-commenting:before {
-  content: "\f27a";
-}
-.fa-commenting-o:before {
-  content: "\f27b";
-}
-.fa-houzz:before {
-  content: "\f27c";
-}
-.fa-vimeo:before {
-  content: "\f27d";
-}
-.fa-black-tie:before {
-  content: "\f27e";
-}
-.fa-fonticons:before {
-  content: "\f280";
-}
-.fa-reddit-alien:before {
-  content: "\f281";
-}
-.fa-edge:before {
-  content: "\f282";
-}
-.fa-credit-card-alt:before {
-  content: "\f283";
-}
-.fa-codiepie:before {
-  content: "\f284";
-}
-.fa-modx:before {
-  content: "\f285";
-}
-.fa-fort-awesome:before {
-  content: "\f286";
-}
-.fa-usb:before {
-  content: "\f287";
-}
-.fa-product-hunt:before {
-  content: "\f288";
-}
-.fa-mixcloud:before {
-  content: "\f289";
-}
-.fa-scribd:before {
-  content: "\f28a";
-}
-.fa-pause-circle:before {
-  content: "\f28b";
-}
-.fa-pause-circle-o:before {
-  content: "\f28c";
-}
-.fa-stop-circle:before {
-  content: "\f28d";
-}
-.fa-stop-circle-o:before {
-  content: "\f28e";
-}
-.fa-shopping-bag:before {
-  content: "\f290";
-}
-.fa-shopping-basket:before {
-  content: "\f291";
-}
-.fa-hashtag:before {
-  content: "\f292";
-}
-.fa-bluetooth:before {
-  content: "\f293";
-}
-.fa-bluetooth-b:before {
-  content: "\f294";
-}
-.fa-percent:before {
-  content: "\f295";
-}
-.fa-gitlab:before {
-  content: "\f296";
-}
-.fa-wpbeginner:before {
-  content: "\f297";
-}
-.fa-wpforms:before {
-  content: "\f298";
-}
-.fa-envira:before {
-  content: "\f299";
-}
-.fa-universal-access:before {
-  content: "\f29a";
-}
-.fa-wheelchair-alt:before {
-  content: "\f29b";
-}
-.fa-question-circle-o:before {
-  content: "\f29c";
-}
-.fa-blind:before {
-  content: "\f29d";
-}
-.fa-audio-description:before {
-  content: "\f29e";
-}
-.fa-volume-control-phone:before {
-  content: "\f2a0";
-}
-.fa-braille:before {
-  content: "\f2a1";
-}
-.fa-assistive-listening-systems:before {
-  content: "\f2a2";
-}
-.fa-asl-interpreting:before,
-.fa-american-sign-language-interpreting:before {
-  content: "\f2a3";
-}
-.fa-deafness:before,
-.fa-hard-of-hearing:before,
-.fa-deaf:before {
-  content: "\f2a4";
-}
-.fa-glide:before {
-  content: "\f2a5";
-}
-.fa-glide-g:before {
-  content: "\f2a6";
-}
-.fa-signing:before,
-.fa-sign-language:before {
-  content: "\f2a7";
-}
-.fa-low-vision:before {
-  content: "\f2a8";
-}
-.fa-viadeo:before {
-  content: "\f2a9";
-}
-.fa-viadeo-square:before {
-  content: "\f2aa";
-}
-.fa-snapchat:before {
-  content: "\f2ab";
-}
-.fa-snapchat-ghost:before {
-  content: "\f2ac";
-}
-.fa-snapchat-square:before {
-  content: "\f2ad";
-}
-.fa-pied-piper:before {
-  content: "\f2ae";
-}
-.fa-first-order:before {
-  content: "\f2b0";
-}
-.fa-yoast:before {
-  content: "\f2b1";
-}
-.fa-themeisle:before {
-  content: "\f2b2";
-}
-.fa-google-plus-circle:before,
-.fa-google-plus-official:before {
-  content: "\f2b3";
-}
-.fa-fa:before,
-.fa-font-awesome:before {
-  content: "\f2b4";
-}
-.sr-only {
-  position: absolute;
-  width: 1px;
-  height: 1px;
-  padding: 0;
-  margin: -1px;
-  overflow: hidden;
-  clip: rect(0, 0, 0, 0);
-  border: 0;
-}
-.sr-only-focusable:active,
-.sr-only-focusable:focus {
-  position: static;
-  width: auto;
-  height: auto;
-  margin: 0;
-  overflow: visible;
-  clip: auto;
-}
diff --git a/hubs/static/font-awesome-4.6.3/css/font-awesome.min.css b/hubs/static/font-awesome-4.6.3/css/font-awesome.min.css
deleted file mode 100644
index 4ec9223..0000000
--- a/hubs/static/font-awesome-4.6.3/css/font-awesome.min.css
+++ /dev/null
@@ -1,4 +0,0 @@
-/*!
- *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
- *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.6.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.6.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.6.3') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.6.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.6.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.6.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}
\ No newline at end of file
diff --git a/hubs/static/font-awesome-4.6.3/fonts/FontAwesome.otf b/hubs/static/font-awesome-4.6.3/fonts/FontAwesome.otf
deleted file mode 100644
index d4de13e..0000000
Binary files a/hubs/static/font-awesome-4.6.3/fonts/FontAwesome.otf and /dev/null differ
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.eot b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.eot
deleted file mode 100644
index c7b00d2..0000000
Binary files a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.eot and /dev/null differ
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.svg b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.svg
deleted file mode 100644
index 8b66187..0000000
--- a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.svg
+++ /dev/null
@@ -1,685 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata></metadata>
-<defs>
-<font id="fontawesomeregular" horiz-adv-x="1536" >
-<font-face units-per-em="1792" ascent="1536" descent="-256" />
-<missing-glyph horiz-adv-x="448" />
-<glyph unicode=" "  horiz-adv-x="448" />
-<glyph unicode="&#x09;" horiz-adv-x="448" />
-<glyph unicode="&#xa0;" horiz-adv-x="448" />
-<glyph unicode="&#xa8;" horiz-adv-x="1792" />
-<glyph unicode="&#xa9;" horiz-adv-x="1792" />
-<glyph unicode="&#xae;" horiz-adv-x="1792" />
-<glyph unicode="&#xb4;" horiz-adv-x="1792" />
-<glyph unicode="&#xc6;" horiz-adv-x="1792" />
-<glyph unicode="&#xd8;" horiz-adv-x="1792" />
-<glyph unicode="&#x2000;" horiz-adv-x="768" />
-<glyph unicode="&#x2001;" horiz-adv-x="1537" />
-<glyph unicode="&#x2002;" horiz-adv-x="768" />
-<glyph unicode="&#x2003;" horiz-adv-x="1537" />
-<glyph unicode="&#x2004;" horiz-adv-x="512" />
-<glyph unicode="&#x2005;" horiz-adv-x="384" />
-<glyph unicode="&#x2006;" horiz-adv-x="256" />
-<glyph unicode="&#x2007;" horiz-adv-x="256" />
-<glyph unicode="&#x2008;" horiz-adv-x="192" />
-<glyph unicode="&#x2009;" horiz-adv-x="307" />
-<glyph unicode="&#x200a;" horiz-adv-x="85" />
-<glyph unicode="&#x202f;" horiz-adv-x="307" />
-<glyph unicode="&#x205f;" horiz-adv-x="384" />
-<glyph unicode="&#x2122;" horiz-adv-x="1792" />
-<glyph unicode="&#x221e;" horiz-adv-x="1792" />
-<glyph unicode="&#x2260;" horiz-adv-x="1792" />
-<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
-<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
-<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
-<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
-<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
-<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
-<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
-<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
-<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
-<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
-<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
-<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
-<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
-<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
-<glyph unicode="&#xf016;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z " />
-<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
-<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
-<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
-<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
-<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
-<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
-<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
-<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
-<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
-<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
-<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
-<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
-<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
-<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
-<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
-<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
-<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
-<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -4 -0.5 -13t-0.5 -13q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" />
-<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68.5 -0.5t67.5 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" />
-<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q6 2 81.5 21.5t111.5 37.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" />
-<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" />
-<glyph unicode="&#xf035;" d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" />
-<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
-<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
-<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
-<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
-<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
-<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
-<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
-<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
-<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
-<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
-<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
-<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
-<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
-<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
-<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
-<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
-<glyph unicode="&#xf053;" horiz-adv-x="1280" d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" />
-<glyph unicode="&#xf054;" horiz-adv-x="1280" d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" />
-<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
-<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
-<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
-<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
-<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
-<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
-<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
-<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
-<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
-<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
-<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
-<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
-<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
-<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
-<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
-<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
-<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
-<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
-<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf077;" horiz-adv-x="1792" d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" />
-<glyph unicode="&#xf078;" horiz-adv-x="1792" d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" />
-<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
-<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1536 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1664 1088v-512q0 -24 -16.5 -42.5t-40.5 -21.5l-1044 -122q13 -60 13 -70q0 -16 -24 -64h920q26 0 45 -19t19 -45 t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 11 8 31.5t16 36t21.5 40t15.5 29.5l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t19.5 -15.5t13 -24.5t8 -26t5.5 -29.5t4.5 -26h1201q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
-<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
-<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
-<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
-<glyph unicode="&#xf080;" horiz-adv-x="2048" d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" />
-<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf082;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-188v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-532q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960z" />
-<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
-<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
-<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
-<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
-<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
-<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
-<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
-<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
-<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
-<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
-<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf092;" d="M519 336q4 6 -3 13q-9 7 -14 2q-4 -6 3 -13q9 -7 14 -2zM491 377q-5 7 -12 4q-6 -4 0 -12q7 -8 12 -5q6 4 0 13zM450 417q2 4 -5 8q-7 2 -8 -2q-3 -5 4 -8q8 -2 9 2zM471 394q2 1 1.5 4.5t-3.5 5.5q-6 7 -10 3t1 -11q6 -6 11 -2zM557 319q2 7 -9 11q-9 3 -13 -4 q-2 -7 9 -11q9 -3 13 4zM599 316q0 8 -12 8q-10 0 -10 -8t11 -8t11 8zM638 323q-2 7 -13 5t-9 -9q2 -8 12 -6t10 10zM1280 640q0 212 -150 362t-362 150t-362 -150t-150 -362q0 -167 98 -300.5t252 -185.5q18 -3 26.5 5t8.5 20q0 52 -1 95q-6 -1 -15.5 -2.5t-35.5 -2t-48 4 t-43.5 20t-29.5 41.5q-23 59 -57 74q-2 1 -4.5 3.5l-8 8t-7 9.5t4 7.5t19.5 3.5q6 0 15 -2t30 -15.5t33 -35.5q16 -28 37.5 -42t43.5 -14t38 3.5t30 9.5q7 47 33 69q-49 6 -86 18.5t-73 39t-55.5 76t-19.5 119.5q0 79 53 137q-24 62 5 136q19 6 54.5 -7.5t60.5 -29.5l26 -16 q58 17 128 17t128 -17q11 7 28.5 18t55.5 26t57 9q29 -74 5 -136q53 -58 53 -137q0 -57 -14 -100.5t-35.5 -70t-53.5 -44.5t-62.5 -26t-68.5 -12q35 -31 35 -95q0 -40 -0.5 -89t-0.5 -51q0 -12 8.5 -20t26.5 -5q154 52 252 185.5t98 300.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
-<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
-<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
-<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
-<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
-<glyph unicode="&#xf09a;" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
-<glyph unicode="&#xf09b;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -40 7t-13 30q0 3 0.5 76.5t0.5 134.5q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 119 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24 q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-85 13.5q-45 -113 -8 -204q-79 -87 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-39 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5 t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -88.5t0.5 -54.5q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103zM291 305q3 7 -7 12 q-10 3 -13 -2q-3 -7 7 -12q9 -6 13 2zM322 271q7 5 -2 16q-10 9 -16 3q-7 -5 2 -16q10 -10 16 -3zM352 226q9 7 0 19q-8 13 -17 6q-9 -5 0 -18t17 -7zM394 184q8 8 -4 19q-12 12 -20 3q-9 -8 4 -19q12 -12 20 -3zM451 159q3 11 -13 16q-15 4 -19 -7t13 -15q15 -6 19 6z M514 154q0 13 -17 11q-16 0 -16 -11q0 -13 17 -11q16 0 16 11zM572 164q-2 11 -18 9q-16 -3 -14 -15t18 -8t14 14z" />
-<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
-<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
-<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
-<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
-<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
-<glyph unicode="&#xf0a2;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
-<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
-<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
-<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
-<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
-<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
-<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
-<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
-<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
-<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
-<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
-<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
-<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
-<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
-<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
-<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
-<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
-<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
-<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
-<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
-<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
-<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
-<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
-<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
-<glyph unicode="&#xf0d4;" d="M917 631q0 26 -6 64h-362v-132h217q-3 -24 -16.5 -50t-37.5 -53t-66.5 -44.5t-96.5 -17.5q-99 0 -169 71t-70 171t70 171t169 71q92 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585 h109v110h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf0d5;" horiz-adv-x="2304" d="M1437 623q0 -208 -87 -370.5t-248 -254t-369 -91.5q-149 0 -285 58t-234 156t-156 234t-58 285t58 285t156 234t234 156t285 58q286 0 491 -192l-199 -191q-117 113 -292 113q-123 0 -227.5 -62t-165.5 -168.5t-61 -232.5t61 -232.5t165.5 -168.5t227.5 -62 q83 0 152.5 23t114.5 57.5t78.5 78.5t49 83t21.5 74h-416v252h692q12 -63 12 -122zM2304 745v-210h-209v-209h-210v209h-209v210h209v209h210v-209h209z" />
-<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
-<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
-<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
-<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
-<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
-<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
-<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
-<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
-<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
-<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
-<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
-<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
-<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
-<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
-<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
-<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
-<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
-<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
-<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
-<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
-<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
-<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
-<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
-<glyph unicode="&#xf0f3;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
-<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
-<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0f6;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" />
-<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
-<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
-<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
-<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
-<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
-<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
-<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
-<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
-<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
-<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
-<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
-<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
-<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
-<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
-<glyph unicode="&#xf110;" horiz-adv-x="1792" d="M526 142q0 -53 -37.5 -90.5t-90.5 -37.5q-52 0 -90 38t-38 90q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 -64q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -53 -37.5 -90.5t-90.5 -37.5 t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1522 142q0 -52 -38 -90t-90 -38q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM558 1138q0 -66 -47 -113t-113 -47t-113 47t-47 113t47 113t113 47t113 -47t47 -113z M1728 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1088 1344q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1618 1138q0 -93 -66 -158.5t-158 -65.5q-93 0 -158.5 65.5t-65.5 158.5 q0 92 65.5 158t158.5 66q92 0 158 -66t66 -158z" />
-<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
-<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
-<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
-<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
-<glyph unicode="&#xf116;" horiz-adv-x="1792" />
-<glyph unicode="&#xf117;" horiz-adv-x="1792" />
-<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
-<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
-<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
-<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
-<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
-<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
-<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
-<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
-<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
-<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
-<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
-<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
-<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
-<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
-<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
-<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
-<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
-<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
-<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
-<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
-<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
-<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
-<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
-<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
-<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
-<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
-<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
-<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
-<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
-<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
-<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
-<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
-<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
-<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
-<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
-<glyph unicode="&#xf158;" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
-<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
-<glyph unicode="&#xf15b;" d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" />
-<glyph unicode="&#xf15c;" d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" />
-<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
-<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
-<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
-<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
-<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
-<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
-<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
-<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
-<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
-<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
-<glyph unicode="&#xf16c;" d="M1289 -96h-1118v480h-160v-640h1438v640h-160v-480zM347 428l33 157l783 -165l-33 -156zM450 802l67 146l725 -339l-67 -145zM651 1158l102 123l614 -513l-102 -123zM1048 1536l477 -641l-128 -96l-477 641zM330 65v159h800v-159h-800z" />
-<glyph unicode="&#xf16d;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1162 640q0 -164 -115 -279t-279 -115t-279 115t-115 279t115 279t279 115t279 -115t115 -279zM1270 1050q0 -38 -27 -65t-65 -27t-65 27t-27 65t27 65t65 27t65 -27t27 -65zM768 1270 q-7 0 -76.5 0.5t-105.5 0t-96.5 -3t-103 -10t-71.5 -18.5q-50 -20 -88 -58t-58 -88q-11 -29 -18.5 -71.5t-10 -103t-3 -96.5t0 -105.5t0.5 -76.5t-0.5 -76.5t0 -105.5t3 -96.5t10 -103t18.5 -71.5q20 -50 58 -88t88 -58q29 -11 71.5 -18.5t103 -10t96.5 -3t105.5 0t76.5 0.5 t76.5 -0.5t105.5 0t96.5 3t103 10t71.5 18.5q50 20 88 58t58 88q11 29 18.5 71.5t10 103t3 96.5t0 105.5t-0.5 76.5t0.5 76.5t0 105.5t-3 96.5t-10 103t-18.5 71.5q-20 50 -58 88t-88 58q-29 11 -71.5 18.5t-103 10t-96.5 3t-105.5 0t-76.5 -0.5zM1536 640q0 -229 -5 -317 q-10 -208 -124 -322t-322 -124q-88 -5 -317 -5t-317 5q-208 10 -322 124t-124 322q-5 88 -5 317t5 317q10 208 124 322t322 124q88 5 317 5t317 -5q208 -10 322 -124t124 -322q5 -88 5 -317z" />
-<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
-<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
-<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 q78 2 134 29z" />
-<glyph unicode="&#xf174;" d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
-<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
-<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
-<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
-<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
-<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
-<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
-<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
-<glyph unicode="&#xf180;" horiz-adv-x="1280" d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" />
-<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
-<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
-<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
-<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
-<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
-<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
-<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
-<glyph unicode="&#xf18b;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
-<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
-<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
-<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
-<glyph unicode="&#xf194;" d="M1292 898q10 216 -161 222q-231 8 -312 -261q44 19 82 19q85 0 74 -96q-4 -57 -74 -167t-105 -110q-43 0 -82 169q-13 54 -45 255q-30 189 -160 177q-59 -7 -164 -100l-81 -72l-81 -72l52 -67q76 52 87 52q57 0 107 -179q15 -55 45 -164.5t45 -164.5q68 -179 164 -179 q157 0 383 294q220 283 226 444zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf197;" horiz-adv-x="2176" d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" />
-<glyph unicode="&#xf198;" horiz-adv-x="1664" d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" />
-<glyph unicode="&#xf199;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 q-46 32 -141.5 92.5t-142.5 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" />
-<glyph unicode="&#xf19a;" horiz-adv-x="1792" d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 t273 -182.5t331.5 -68z" />
-<glyph unicode="&#xf19b;" horiz-adv-x="1792" d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" />
-<glyph unicode="&#xf19c;" horiz-adv-x="2048" d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" />
-<glyph unicode="&#xf19d;" horiz-adv-x="2304" d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" />
-<glyph unicode="&#xf19e;" d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q43 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" />
-<glyph unicode="&#xf1a0;" d="M768 750h725q12 -67 12 -128q0 -217 -91 -387.5t-259.5 -266.5t-386.5 -96q-157 0 -299 60.5t-245 163.5t-163.5 245t-60.5 299t60.5 299t163.5 245t245 163.5t299 60.5q300 0 515 -201l-209 -201q-123 119 -306 119q-129 0 -238.5 -65t-173.5 -176.5t-64 -243.5 t64 -243.5t173.5 -176.5t238.5 -65q87 0 160 24t120 60t82 82t51.5 87t22.5 78h-436v264z" />
-<glyph unicode="&#xf1a1;" horiz-adv-x="1792" d="M1095 369q16 -16 0 -31q-62 -62 -199 -62t-199 62q-16 15 0 31q6 6 15 6t15 -6q48 -49 169 -49q120 0 169 49q6 6 15 6t15 -6zM788 550q0 -37 -26 -63t-63 -26t-63.5 26t-26.5 63q0 38 26.5 64t63.5 26t63 -26.5t26 -63.5zM1183 550q0 -37 -26.5 -63t-63.5 -26t-63 26 t-26 63t26 63.5t63 26.5t63.5 -26t26.5 -64zM1434 670q0 49 -35 84t-85 35t-86 -36q-130 90 -311 96l63 283l200 -45q0 -37 26 -63t63 -26t63.5 26.5t26.5 63.5t-26.5 63.5t-63.5 26.5q-54 0 -80 -50l-221 49q-19 5 -25 -16l-69 -312q-180 -7 -309 -97q-35 37 -87 37 q-50 0 -85 -35t-35 -84q0 -35 18.5 -64t49.5 -44q-6 -27 -6 -56q0 -142 140 -243t337 -101q198 0 338 101t140 243q0 32 -7 57q30 15 48 43.5t18 63.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191 t348 71t348 -71t286 -191t191 -286t71 -348z" />
-<glyph unicode="&#xf1a2;" d="M939 407q13 -13 0 -26q-53 -53 -171 -53t-171 53q-13 13 0 26q5 6 13 6t13 -6q42 -42 145 -42t145 42q5 6 13 6t13 -6zM676 563q0 -31 -23 -54t-54 -23t-54 23t-23 54q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1014 563q0 -31 -23 -54t-54 -23t-54 23t-23 54 q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1229 666q0 42 -30 72t-73 30q-42 0 -73 -31q-113 78 -267 82l54 243l171 -39q1 -32 23.5 -54t53.5 -22q32 0 54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5q-48 0 -69 -43l-189 42q-17 5 -21 -13l-60 -268q-154 -6 -265 -83 q-30 32 -74 32q-43 0 -73 -30t-30 -72q0 -30 16 -55t42 -38q-5 -25 -5 -48q0 -122 120 -208.5t289 -86.5q170 0 290 86.5t120 208.5q0 25 -6 49q25 13 40.5 37.5t15.5 54.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf1a3;" d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103 t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf1a4;" horiz-adv-x="1920" d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" />
-<glyph unicode="&#xf1a5;" d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
-<glyph unicode="&#xf1a6;" horiz-adv-x="2048" d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 v-369h123z" />
-<glyph unicode="&#xf1a7;" d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf1a8;" horiz-adv-x="2038" d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" />
-<glyph unicode="&#xf1a9;" d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" />
-<glyph unicode="&#xf1aa;" d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 t135.5 51q85 0 145 -60.5t60 -145.5z" />
-<glyph unicode="&#xf1ab;" d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q106 35 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 q20 0 20 -21v-418z" />
-<glyph unicode="&#xf1ac;" horiz-adv-x="1792" d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" />
-<glyph unicode="&#xf1ad;" d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" />
-<glyph unicode="&#xf1ae;" horiz-adv-x="1280" d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68t68 28t68 -28l228 -228h368l228 228q28 28 68 28t68 -28t28 -68t-28 -68zM864 1152q0 -93 -65.5 -158.5 t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
-<glyph unicode="&#xf1b0;" horiz-adv-x="1664" d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 t100.5 134t141.5 55.5z" />
-<glyph unicode="&#xf1b1;" horiz-adv-x="768" d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" />
-<glyph unicode="&#xf1b2;" horiz-adv-x="1792" d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z " />
-<glyph unicode="&#xf1b3;" horiz-adv-x="2304" d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-5 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 v-400l434 -186q36 -16 57 -48t21 -70z" />
-<glyph unicode="&#xf1b4;" horiz-adv-x="2048" d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" />
-<glyph unicode="&#xf1b5;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" />
-<glyph unicode="&#xf1b6;" horiz-adv-x="1792" d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" />
-<glyph unicode="&#xf1b7;" d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z " />
-<glyph unicode="&#xf1b8;" horiz-adv-x="1792" d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" />
-<glyph unicode="&#xf1b9;" horiz-adv-x="2048" d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" />
-<glyph unicode="&#xf1ba;" horiz-adv-x="2048" d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" />
-<glyph unicode="&#xf1bb;" d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" />
-<glyph unicode="&#xf1bc;" d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf1bd;" horiz-adv-x="1024" d="M1024 1233l-303 -582l24 -31h279v-415h-507l-44 -30l-142 -273l-30 -30h-301v303l303 583l-24 30h-279v415h507l44 30l142 273l30 30h301v-303z" />
-<glyph unicode="&#xf1be;" horiz-adv-x="2304" d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236q0 -11 -8 -19 t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786q-13 2 -22 11t-9 22v899 q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" />
-<glyph unicode="&#xf1c0;" d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 t-103 128v128q0 69 103 128t280 93.5t385 34.5z" />
-<glyph unicode="&#xf1c1;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 q-1 1 -1 2t-0.5 1.5t-0.5 1.5q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" />
-<glyph unicode="&#xf1c2;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4l-3 21q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5t-3.5 -21.5l-4 -21h-4l-2 21 q-2 26 -7 46l-99 438h90v107h-300z" />
-<glyph unicode="&#xf1c3;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 h-290v-107h68l189 -272l-194 -283h-68z" />
-<glyph unicode="&#xf1c4;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" />
-<glyph unicode="&#xf1c5;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" />
-<glyph unicode="&#xf1c6;" d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" />
-<glyph unicode="&#xf1c7;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" />
-<glyph unicode="&#xf1c8;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" />
-<glyph unicode="&#xf1c9;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" />
-<glyph unicode="&#xf1ca;" d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" />
-<glyph unicode="&#xf1cb;" horiz-adv-x="1792" d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" />
-<glyph unicode="&#xf1cc;" horiz-adv-x="2048" d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97q14 -16 29.5 -34t34.5 -40t29 -34q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5 t-85 -189.5z" />
-<glyph unicode="&#xf1cd;" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" />
-<glyph unicode="&#xf1ce;" horiz-adv-x="1792" d="M1760 640q0 -176 -68.5 -336t-184 -275.5t-275.5 -184t-336 -68.5t-336 68.5t-275.5 184t-184 275.5t-68.5 336q0 213 97 398.5t265 305.5t374 151v-228q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5 t136.5 204t51 248.5q0 230 -145.5 406t-366.5 221v228q206 -31 374 -151t265 -305.5t97 -398.5z" />
-<glyph unicode="&#xf1d0;" horiz-adv-x="1792" d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" />
-<glyph unicode="&#xf1d1;" horiz-adv-x="1792" d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
-<glyph unicode="&#xf1d2;" d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf1d3;" horiz-adv-x="1792" d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" />
-<glyph unicode="&#xf1d4;" d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf1d5;" horiz-adv-x="1280" d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" />
-<glyph unicode="&#xf1d6;" horiz-adv-x="1792" d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" />
-<glyph unicode="&#xf1d7;" horiz-adv-x="2048" d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" />
-<glyph unicode="&#xf1d8;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" />
-<glyph unicode="&#xf1d9;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 l863 639l-478 -797z" />
-<glyph unicode="&#xf1da;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23 t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf1db;" d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf1dc;" horiz-adv-x="1792" d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 q0 -26 -12 -48t-36 -22z" />
-<glyph unicode="&#xf1dd;" horiz-adv-x="1280" d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" />
-<glyph unicode="&#xf1de;" d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" />
-<glyph unicode="&#xf1e0;" d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" />
-<glyph unicode="&#xf1e1;" d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf1e2;" horiz-adv-x="1792" d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
-<glyph unicode="&#xf1e3;" horiz-adv-x="1792" d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" />
-<glyph unicode="&#xf1e4;" horiz-adv-x="1792" d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" />
-<glyph unicode="&#xf1e5;" horiz-adv-x="1792" d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf1e6;" horiz-adv-x="1792" d="M1755 1083q37 -37 37 -90t-37 -91l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234l401 400 q38 37 91 37t90 -37z" />
-<glyph unicode="&#xf1e7;" horiz-adv-x="1792" d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q3 -2 11 -7 t11 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" />
-<glyph unicode="&#xf1e8;" horiz-adv-x="1792" d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" />
-<glyph unicode="&#xf1e9;" d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q70 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" />
-<glyph unicode="&#xf1ea;" horiz-adv-x="2048" d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" />
-<glyph unicode="&#xf1eb;" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
-<glyph unicode="&#xf1ec;" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf1ed;" d="M1519 890q18 -84 -4 -204q-87 -444 -565 -444h-44q-25 0 -44 -16.5t-24 -42.5l-4 -19l-55 -346l-2 -15q-5 -26 -24.5 -42.5t-44.5 -16.5h-251q-21 0 -33 15t-9 36q9 56 26.5 168t26.5 168t27 167.5t27 167.5q5 37 43 37h131q133 -2 236 21q175 39 287 144q102 95 155 246 q24 70 35 133q1 6 2.5 7.5t3.5 1t6 -3.5q79 -59 98 -162zM1347 1172q0 -107 -46 -236q-80 -233 -302 -315q-113 -40 -252 -42q0 -1 -90 -1l-90 1q-100 0 -118 -96q-2 -8 -85 -530q-1 -10 -12 -10h-295q-22 0 -36.5 16.5t-11.5 38.5l232 1471q5 29 27.5 48t51.5 19h598 q34 0 97.5 -13t111.5 -32q107 -41 163.5 -123t56.5 -196z" />
-<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M441 864q32 0 52 -26q266 -364 362 -774h-446q-127 441 -367 749q-12 16 -3 33.5t29 17.5h373zM1000 507q-49 -199 -125 -393q-79 310 -256 594q40 221 44 449q211 -340 337 -650zM1099 1216q235 -324 384.5 -698.5t184.5 -773.5h-451q-41 665 -553 1472h435zM1792 640 q0 -424 -101 -812q-67 560 -359 1083q-25 301 -106 584q-4 16 5.5 28.5t25.5 12.5h359q21 0 38.5 -13t22.5 -33q115 -409 115 -850z" />
-<glyph unicode="&#xf1f0;" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf1f1;" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39 26 60.5t73 21.5q14 0 23 -1q0 3 0.5 5.5t1 4.5t0.5 3 q0 20 -36 20q-29 0 -59 -10q0 4 7 48q38 11 67 11q74 0 74 -62zM889 721l-8 -49q-22 3 -41 3q-27 0 -27 -17q0 -8 4.5 -12t21.5 -11q40 -19 40 -60q0 -72 -87 -71q-34 0 -58 6q0 2 7 49q29 -8 51 -8q32 0 32 19q0 7 -4.5 11.5t-21.5 12.5q-43 20 -43 59q0 72 84 72 q30 0 50 -4zM977 721h28l-7 -52h-29q-2 -17 -6.5 -40.5t-7 -38.5t-2.5 -18q0 -16 19 -16q8 0 16 2l-8 -47q-21 -7 -40 -7q-43 0 -45 47q0 12 8 56q3 20 25 146h55zM1180 648q0 -23 -7 -52h-111q-3 -22 10 -33t38 -11q30 0 58 14l-9 -54q-30 -8 -57 -8q-95 0 -95 95 q0 55 27.5 90.5t69.5 35.5q35 0 55.5 -21t20.5 -56zM1319 722q-13 -23 -22 -62q-22 2 -31 -24t-25 -128h-56l3 14q22 130 29 199h51l-3 -33q14 21 25.5 29.5t28.5 4.5zM1506 763l-9 -57q-28 14 -50 14q-31 0 -51 -27.5t-20 -70.5q0 -30 13.5 -47t38.5 -17q21 0 48 13 l-10 -59q-28 -8 -50 -8q-45 0 -71.5 30.5t-26.5 82.5q0 70 35.5 114.5t91.5 44.5q26 0 61 -13zM1668 663q0 -18 -4 -42q-13 -79 -17 -113h-46l1 22q-20 -26 -59 -26q-23 0 -37 16t-14 42q0 39 25.5 60.5t72.5 21.5q15 0 23 -1q2 7 2 13q0 20 -36 20q-29 0 -59 -10q0 4 8 48 q38 11 67 11q73 0 73 -62zM1809 722q-14 -24 -21 -62q-23 2 -31.5 -23t-25.5 -129h-56l3 14q19 104 29 199h52q0 -11 -4 -33q15 21 26.5 29.5t27.5 4.5zM1950 770h56l-43 -262h-53l3 19q-23 -23 -52 -23q-31 0 -49.5 24t-18.5 64q0 53 27.5 92t64.5 39q31 0 53 -29z M2061 640q0 148 -72.5 273t-198 198t-273.5 73q-181 0 -328 -110q127 -116 171 -284h-50q-44 150 -158 253q-114 -103 -158 -253h-50q44 168 171 284q-147 110 -328 110q-148 0 -273.5 -73t-198 -198t-72.5 -273t72.5 -273t198 -198t273.5 -73q181 0 328 110 q-120 111 -165 264h50q46 -138 152 -233q106 95 152 233h50q-45 -153 -165 -264q147 -110 328 -110q148 0 273.5 73t198 198t72.5 273zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf1f2;" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
-<glyph unicode="&#xf1f3;" horiz-adv-x="2304" d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" />
-<glyph unicode="&#xf1f4;" horiz-adv-x="2304" d="M745 630q0 -37 -25.5 -61.5t-62.5 -24.5q-29 0 -46.5 16t-17.5 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM1530 779q0 -42 -22 -57t-66 -15l-32 -1l17 107q2 11 13 11h18q22 0 35 -2t25 -12.5t12 -30.5zM1881 630q0 -36 -25.5 -61t-61.5 -25q-29 0 -47 16 t-18 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM513 801q0 59 -38.5 85.5t-100.5 26.5h-160q-19 0 -21 -19l-65 -408q-1 -6 3 -11t10 -5h76q20 0 22 19l18 110q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM822 489l41 261q1 6 -3 11t-10 5h-76 q-14 0 -17 -33q-27 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q28 0 58 12t48 32q-4 -12 -4 -21q0 -16 13 -16h69q19 0 22 19zM1269 752q0 5 -4 9.5t-9 4.5h-77q-11 0 -18 -10l-106 -156l-44 150q-5 16 -22 16h-75q-5 0 -9 -4.5t-4 -9.5q0 -2 19.5 -59 t42 -123t23.5 -70q-82 -112 -82 -120q0 -13 13 -13h77q11 0 18 10l255 368q2 2 2 7zM1649 801q0 59 -38.5 85.5t-100.5 26.5h-159q-20 0 -22 -19l-65 -408q-1 -6 3 -11t10 -5h82q12 0 16 13l18 116q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM1958 489 l41 261q1 6 -3 11t-10 5h-76q-14 0 -17 -33q-26 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q29 0 59 12t47 32q0 -1 -2 -9t-2 -12q0 -16 13 -16h69q19 0 22 19zM2176 898v1q0 14 -13 14h-74q-11 0 -13 -11l-65 -416l-1 -2q0 -5 4 -9.5t10 -4.5h66 q19 0 21 19zM392 764q-5 -35 -26 -46t-60 -11l-33 -1l17 107q2 11 13 11h19q40 0 58 -11.5t12 -48.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf1f5;" horiz-adv-x="2304" d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf1f6;" horiz-adv-x="2048" d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 l418 363q10 8 23.5 7t21.5 -11z" />
-<glyph unicode="&#xf1f7;" horiz-adv-x="2048" d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" />
-<glyph unicode="&#xf1f8;" horiz-adv-x="1408" d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf1f9;" d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf1fa;" d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" />
-<glyph unicode="&#xf1fb;" horiz-adv-x="1792" d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" />
-<glyph unicode="&#xf1fc;" horiz-adv-x="1792" d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" />
-<glyph unicode="&#xf1fd;" horiz-adv-x="1792" d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11t55.5 -11t52.5 -38q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5t47 37.5 q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-35 0 -55.5 11t-52.5 38q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38t-58 27 t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448h256v448 h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51 t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" />
-<glyph unicode="&#xf1fe;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" />
-<glyph unicode="&#xf200;" horiz-adv-x="1792" d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf201;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 t9 -23z" />
-<glyph unicode="&#xf202;" horiz-adv-x="1792" d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" />
-<glyph unicode="&#xf203;" d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf204;" horiz-adv-x="2048" d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" />
-<glyph unicode="&#xf205;" horiz-adv-x="2048" d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" />
-<glyph unicode="&#xf206;" horiz-adv-x="2304" d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" />
-<glyph unicode="&#xf207;" d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" />
-<glyph unicode="&#xf208;" horiz-adv-x="2048" d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" />
-<glyph unicode="&#xf209;" horiz-adv-x="1280" d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q18 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" />
-<glyph unicode="&#xf20a;" horiz-adv-x="2048" d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" />
-<glyph unicode="&#xf20b;" d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
-<glyph unicode="&#xf20c;" d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" />
-<glyph unicode="&#xf20d;" d="M915 450h-294l147 551zM1001 128h311l-324 1024h-440l-324 -1024h311l383 314zM1536 1120v-960q0 -118 -85 -203t-203 -85h-960q-118 0 -203 85t-85 203v960q0 118 85 203t203 85h960q118 0 203 -85t85 -203z" />
-<glyph unicode="&#xf20e;" horiz-adv-x="2048" d="M2048 641q0 -21 -13 -36.5t-33 -19.5l-205 -356q3 -9 3 -18q0 -20 -12.5 -35.5t-32.5 -19.5l-193 -337q3 -8 3 -16q0 -23 -16.5 -40t-40.5 -17q-25 0 -41 18h-400q-17 -20 -43 -20t-43 20h-399q-17 -20 -43 -20q-23 0 -40 16.5t-17 40.5q0 8 4 20l-193 335 q-20 4 -32.5 19.5t-12.5 35.5q0 9 3 18l-206 356q-20 5 -32.5 20.5t-12.5 35.5q0 21 13.5 36.5t33.5 19.5l199 344q0 1 -0.5 3t-0.5 3q0 36 34 51l209 363q-4 10 -4 18q0 24 17 40.5t40 16.5q26 0 44 -21h396q16 21 43 21t43 -21h398q18 21 44 21q23 0 40 -16.5t17 -40.5 q0 -6 -4 -18l207 -358q23 -1 39 -17.5t16 -38.5q0 -13 -7 -27l187 -324q19 -4 31.5 -19.5t12.5 -35.5zM1063 -158h389l-342 354h-143l-342 -354h360q18 16 39 16t39 -16zM112 654q1 -4 1 -13q0 -10 -2 -15l208 -360q2 0 4.5 -1t5.5 -2.5l5 -2.5l188 199v347l-187 194 q-13 -8 -29 -10zM986 1438h-388l190 -200l554 200h-280q-16 -16 -38 -16t-38 16zM1689 226q1 6 5 11l-64 68l-17 -79h76zM1583 226l22 105l-252 266l-296 -307l63 -64h463zM1495 -142l16 28l65 310h-427l333 -343q8 4 13 5zM578 -158h5l342 354h-373v-335l4 -6q14 -5 22 -13 zM552 226h402l64 66l-309 321l-157 -166v-221zM359 226h163v189l-168 -177q4 -8 5 -12zM358 1051q0 -1 0.5 -2t0.5 -2q0 -16 -8 -29l171 -177v269zM552 1121v-311l153 -157l297 314l-223 236zM556 1425l-4 -8v-264l205 74l-191 201q-6 -2 -10 -3zM1447 1438h-16l-621 -224 l213 -225zM1023 946l-297 -315l311 -319l296 307zM688 634l-136 141v-284zM1038 270l-42 -44h85zM1374 618l238 -251l132 624l-3 5l-1 1zM1718 1018q-8 13 -8 29v2l-216 376q-5 1 -13 5l-437 -463l310 -327zM522 1142v223l-163 -282zM522 196h-163l163 -283v283zM1607 196 l-48 -227l130 227h-82zM1729 266l207 361q-2 10 -2 14q0 1 3 16l-171 296l-129 -612l77 -82q5 3 15 7z" />
-<glyph unicode="&#xf210;" d="M0 856q0 131 91.5 226.5t222.5 95.5h742l352 358v-1470q0 -132 -91.5 -227t-222.5 -95h-780q-131 0 -222.5 95t-91.5 227v790zM1232 102l-176 180v425q0 46 -32 79t-78 33h-484q-46 0 -78 -33t-32 -79v-492q0 -46 32.5 -79.5t77.5 -33.5h770z" />
-<glyph unicode="&#xf211;" d="M934 1386q-317 -121 -556 -362.5t-358 -560.5q-20 89 -20 176q0 208 102.5 384.5t278.5 279t384 102.5q82 0 169 -19zM1203 1267q93 -65 164 -155q-389 -113 -674.5 -400.5t-396.5 -676.5q-93 72 -155 162q112 386 395 671t667 399zM470 -67q115 356 379.5 622t619.5 384 q40 -92 54 -195q-292 -120 -516 -345t-343 -518q-103 14 -194 52zM1536 -125q-193 50 -367 115q-135 -84 -290 -107q109 205 274 370.5t369 275.5q-21 -152 -101 -284q65 -175 115 -370z" />
-<glyph unicode="&#xf212;" horiz-adv-x="2048" d="M1893 1144l155 -1272q-131 0 -257 57q-200 91 -393 91q-226 0 -374 -148q-148 148 -374 148q-193 0 -393 -91q-128 -57 -252 -57h-5l155 1272q224 127 482 127q233 0 387 -106q154 106 387 106q258 0 482 -127zM1398 157q129 0 232 -28.5t260 -93.5l-124 1021 q-171 78 -368 78q-224 0 -374 -141q-150 141 -374 141q-197 0 -368 -78l-124 -1021q105 43 165.5 65t148.5 39.5t178 17.5q202 0 374 -108q172 108 374 108zM1438 191l-55 907q-211 -4 -359 -155q-152 155 -374 155q-176 0 -336 -66l-114 -941q124 51 228.5 76t221.5 25 q209 0 374 -102q172 107 374 102z" />
-<glyph unicode="&#xf213;" horiz-adv-x="2048" d="M1500 165v733q0 21 -15 36t-35 15h-93q-20 0 -35 -15t-15 -36v-733q0 -20 15 -35t35 -15h93q20 0 35 15t15 35zM1216 165v531q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-531q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM924 165v429q0 20 -15 35t-35 15h-101 q-20 0 -35 -15t-15 -35v-429q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM632 165v362q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-362q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM2048 311q0 -166 -118 -284t-284 -118h-1244q-166 0 -284 118t-118 284 q0 116 63 214.5t168 148.5q-10 34 -10 73q0 113 80.5 193.5t193.5 80.5q102 0 180 -67q45 183 194 300t338 117q149 0 275 -73.5t199.5 -199.5t73.5 -275q0 -66 -14 -122q135 -33 221 -142.5t86 -247.5z" />
-<glyph unicode="&#xf214;" d="M0 1536h1536v-1392l-776 -338l-760 338v1392zM1436 209v926h-1336v-926l661 -294zM1436 1235v201h-1336v-201h1336zM181 937v-115h-37v115h37zM181 789v-115h-37v115h37zM181 641v-115h-37v115h37zM181 493v-115h-37v115h37zM181 345v-115h-37v115h37zM207 202l15 34 l105 -47l-15 -33zM343 142l15 34l105 -46l-15 -34zM478 82l15 34l105 -46l-15 -34zM614 23l15 33l104 -46l-15 -34zM797 10l105 46l15 -33l-105 -47zM932 70l105 46l15 -34l-105 -46zM1068 130l105 46l15 -34l-105 -46zM1203 189l105 47l15 -34l-105 -46zM259 1389v-36h-114 v36h114zM421 1389v-36h-115v36h115zM583 1389v-36h-115v36h115zM744 1389v-36h-114v36h114zM906 1389v-36h-114v36h114zM1068 1389v-36h-115v36h115zM1230 1389v-36h-115v36h115zM1391 1389v-36h-114v36h114zM181 1049v-79h-37v115h115v-36h-78zM421 1085v-36h-115v36h115z M583 1085v-36h-115v36h115zM744 1085v-36h-114v36h114zM906 1085v-36h-114v36h114zM1068 1085v-36h-115v36h115zM1230 1085v-36h-115v36h115zM1355 970v79h-78v36h115v-115h-37zM1355 822v115h37v-115h-37zM1355 674v115h37v-115h-37zM1355 526v115h37v-115h-37zM1355 378 v115h37v-115h-37zM1355 230v115h37v-115h-37zM760 265q-129 0 -221 91.5t-92 221.5q0 129 92 221t221 92q130 0 221.5 -92t91.5 -221q0 -130 -91.5 -221.5t-221.5 -91.5zM595 646q0 -36 19.5 -56.5t49.5 -25t64 -7t64 -2t49.5 -9t19.5 -30.5q0 -49 -112 -49q-97 0 -123 51 h-3l-31 -63q67 -42 162 -42q29 0 56.5 5t55.5 16t45.5 33t17.5 53q0 46 -27.5 69.5t-67.5 27t-79.5 3t-67 5t-27.5 25.5q0 21 20.5 33t40.5 15t41 3q34 0 70.5 -11t51.5 -34h3l30 58q-3 1 -21 8.5t-22.5 9t-19.5 7t-22 7t-20 4.5t-24 4t-23 1q-29 0 -56.5 -5t-54 -16.5 t-43 -34t-16.5 -53.5z" />
-<glyph unicode="&#xf215;" horiz-adv-x="2048" d="M863 504q0 112 -79.5 191.5t-191.5 79.5t-191 -79.5t-79 -191.5t79 -191t191 -79t191.5 79t79.5 191zM1726 505q0 112 -79 191t-191 79t-191.5 -79t-79.5 -191q0 -113 79.5 -192t191.5 -79t191 79.5t79 191.5zM2048 1314v-1348q0 -44 -31.5 -75.5t-76.5 -31.5h-1832 q-45 0 -76.5 31.5t-31.5 75.5v1348q0 44 31.5 75.5t76.5 31.5h431q44 0 76 -31.5t32 -75.5v-161h754v161q0 44 32 75.5t76 31.5h431q45 0 76.5 -31.5t31.5 -75.5z" />
-<glyph unicode="&#xf216;" horiz-adv-x="2048" d="M1430 953zM1690 749q148 0 253 -98.5t105 -244.5q0 -157 -109 -261.5t-267 -104.5q-85 0 -162 27.5t-138 73.5t-118 106t-109 126.5t-103.5 132.5t-108.5 126t-117 106t-136 73.5t-159 27.5q-154 0 -251.5 -91.5t-97.5 -244.5q0 -157 104 -250t263 -93q100 0 208 37.5 t193 98.5q5 4 21 18.5t30 24t22 9.5q14 0 24.5 -10.5t10.5 -24.5q0 -24 -60 -77q-101 -88 -234.5 -142t-260.5 -54q-133 0 -245.5 58t-180 165t-67.5 241q0 205 141.5 341t347.5 136q120 0 226.5 -43.5t185.5 -113t151.5 -153t139 -167.5t133.5 -153.5t149.5 -113 t172.5 -43.5q102 0 168.5 61.5t66.5 162.5q0 95 -64.5 159t-159.5 64q-30 0 -81.5 -18.5t-68.5 -18.5q-20 0 -35.5 15t-15.5 35q0 18 8.5 57t8.5 59q0 159 -107.5 263t-266.5 104q-58 0 -111.5 -18.5t-84 -40.5t-55.5 -40.5t-33 -18.5q-15 0 -25.5 10.5t-10.5 25.5 q0 19 25 46q59 67 147 103.5t182 36.5q191 0 318 -125.5t127 -315.5q0 -37 -4 -66q57 15 115 15z" />
-<glyph unicode="&#xf217;" horiz-adv-x="1664" d="M1216 832q0 26 -19 45t-45 19h-128v128q0 26 -19 45t-45 19t-45 -19t-19 -45v-128h-128q-26 0 -45 -19t-19 -45t19 -45t45 -19h128v-128q0 -26 19 -45t45 -19t45 19t19 45v128h128q26 0 45 19t19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf218;" horiz-adv-x="1664" d="M1280 832q0 26 -19 45t-45 19t-45 -19l-147 -146v293q0 26 -19 45t-45 19t-45 -19t-19 -45v-293l-147 146q-19 19 -45 19t-45 -19t-19 -45t19 -45l256 -256q19 -19 45 -19t45 19l256 256q19 19 19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf219;" horiz-adv-x="2048" d="M212 768l623 -665l-300 665h-323zM1024 -4l349 772h-698zM538 896l204 384h-262l-288 -384h346zM1213 103l623 665h-323zM683 896h682l-204 384h-274zM1510 896h346l-288 384h-262zM1651 1382l384 -512q14 -18 13 -41.5t-17 -40.5l-960 -1024q-18 -20 -47 -20t-47 20 l-960 1024q-16 17 -17 40.5t13 41.5l384 512q18 26 51 26h1152q33 0 51 -26z" />
-<glyph unicode="&#xf21a;" horiz-adv-x="2048" d="M1811 -19q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83 q19 19 45 19t45 -19l83 -83zM237 19q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -82l83 82q19 19 45 19t45 -19l83 -82l64 64v293l-210 314q-17 26 -7 56.5t40 40.5l177 58v299h128v128h256v128h256v-128h256v-128h128v-299l177 -58q30 -10 40 -40.5t-7 -56.5l-210 -314 v-293l19 18q19 19 45 19t45 -19l83 -82l83 82q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83zM640 1152v-128l384 128l384 -128v128h-128v128h-512v-128h-128z" />
-<glyph unicode="&#xf21b;" d="M576 0l96 448l-96 128l-128 64zM832 0l128 640l-128 -64l-96 -128zM992 1010q-2 4 -4 6q-10 8 -96 8q-70 0 -167 -19q-7 -2 -21 -2t-21 2q-97 19 -167 19q-86 0 -96 -8q-2 -2 -4 -6q2 -18 4 -27q2 -3 7.5 -6.5t7.5 -10.5q2 -4 7.5 -20.5t7 -20.5t7.5 -17t8.5 -17t9 -14 t12 -13.5t14 -9.5t17.5 -8t20.5 -4t24.5 -2q36 0 59 12.5t32.5 30t14.5 34.5t11.5 29.5t17.5 12.5h12q11 0 17.5 -12.5t11.5 -29.5t14.5 -34.5t32.5 -30t59 -12.5q13 0 24.5 2t20.5 4t17.5 8t14 9.5t12 13.5t9 14t8.5 17t7.5 17t7 20.5t7.5 20.5q2 7 7.5 10.5t7.5 6.5 q2 9 4 27zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 61 4.5 118t19 125.5t37.5 123.5t63.5 103.5t93.5 74.5l-90 220h214q-22 64 -22 128q0 12 2 32q-194 40 -194 96q0 57 210 99q17 62 51.5 134t70.5 114q32 37 76 37q30 0 84 -31t84 -31t84 31 t84 31q44 0 76 -37q36 -42 70.5 -114t51.5 -134q210 -42 210 -99q0 -56 -194 -96q7 -81 -20 -160h214l-82 -225q63 -33 107.5 -96.5t65.5 -143.5t29 -151.5t8 -148.5z" />
-<glyph unicode="&#xf21c;" horiz-adv-x="2304" d="M2301 500q12 -103 -22 -198.5t-99 -163.5t-158.5 -106t-196.5 -31q-161 11 -279.5 125t-134.5 274q-12 111 27.5 210.5t118.5 170.5l-71 107q-96 -80 -151 -194t-55 -244q0 -27 -18.5 -46.5t-45.5 -19.5h-256h-69q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5 t-131.5 316.5t131.5 316.5t316.5 131.5q76 0 152 -27l24 45q-123 110 -304 110h-64q-26 0 -45 19t-19 45t19 45t45 19h128q78 0 145 -13.5t116.5 -38.5t71.5 -39.5t51 -36.5h512h115l-85 128h-222q-30 0 -49 22.5t-14 52.5q4 23 23 38t43 15h253q33 0 53 -28l70 -105 l114 114q19 19 46 19h101q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-179l115 -172q131 63 275 36q143 -26 244 -134.5t118 -253.5zM448 128q115 0 203 72.5t111 183.5h-314q-35 0 -55 31q-18 32 -1 63l147 277q-47 13 -91 13q-132 0 -226 -94t-94 -226t94 -226 t226 -94zM1856 128q132 0 226 94t94 226t-94 226t-226 94q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94z" />
-<glyph unicode="&#xf21d;" d="M1408 0q0 -63 -61.5 -113.5t-164 -81t-225 -46t-253.5 -15.5t-253.5 15.5t-225 46t-164 81t-61.5 113.5q0 49 33 88.5t91 66.5t118 44.5t131 29.5q26 5 48 -10.5t26 -41.5q5 -26 -10.5 -48t-41.5 -26q-58 -10 -106 -23.5t-76.5 -25.5t-48.5 -23.5t-27.5 -19.5t-8.5 -12 q3 -11 27 -26.5t73 -33t114 -32.5t160.5 -25t201.5 -10t201.5 10t160.5 25t114 33t73 33.5t27 27.5q-1 4 -8.5 11t-27.5 19t-48.5 23.5t-76.5 25t-106 23.5q-26 4 -41.5 26t-10.5 48q4 26 26 41.5t48 10.5q71 -12 131 -29.5t118 -44.5t91 -66.5t33 -88.5zM1024 896v-384 q0 -26 -19 -45t-45 -19h-64v-384q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v384h-64q-26 0 -45 19t-19 45v384q0 53 37.5 90.5t90.5 37.5h384q53 0 90.5 -37.5t37.5 -90.5zM928 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5 t158.5 -65.5t65.5 -158.5z" />
-<glyph unicode="&#xf21e;" horiz-adv-x="1792" d="M1280 512h305q-5 -6 -10 -10.5t-9 -7.5l-3 -4l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-5 2 -21 20h369q22 0 39.5 13.5t22.5 34.5l70 281l190 -667q6 -20 23 -33t39 -13q21 0 38 13t23 33l146 485l56 -112q18 -35 57 -35zM1792 940q0 -145 -103 -300h-369l-111 221 q-8 17 -25.5 27t-36.5 8q-45 -5 -56 -46l-129 -430l-196 686q-6 20 -23.5 33t-39.5 13t-39 -13.5t-22 -34.5l-116 -464h-423q-103 155 -103 300q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124 t127 -344z" />
-<glyph unicode="&#xf221;" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292 q11 134 80.5 249t182 188t245.5 88q170 19 319 -54t236 -212t87 -306zM128 960q0 -185 131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5z" />
-<glyph unicode="&#xf222;" d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-382 -383q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5 q203 0 359 -126l382 382h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf223;" horiz-adv-x="1280" d="M830 1220q145 -72 233.5 -210.5t88.5 -305.5q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5 t-147.5 384.5q0 167 88.5 305.5t233.5 210.5q-165 96 -228 273q-6 16 3.5 29.5t26.5 13.5h69q21 0 29 -20q44 -106 140 -171t214 -65t214 65t140 171q8 20 37 20h61q17 0 26.5 -13.5t3.5 -29.5q-63 -177 -228 -273zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf224;" d="M1024 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-149 16 -270.5 103t-186.5 223.5t-53 291.5q16 204 160 353.5t347 172.5q118 14 228 -19t198 -103l255 254h-134q-14 0 -23 9t-9 23v64zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf225;" horiz-adv-x="1792" d="M1280 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5t-147.5 384.5q0 201 126 359l-52 53l-101 -111q-9 -10 -22 -10.5t-23 7.5l-48 44q-10 8 -10.5 21.5t8.5 23.5l105 115l-111 112v-134q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9 t-9 23v288q0 26 19 45t45 19h288q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-133l106 -107l86 94q9 10 22 10.5t23 -7.5l48 -44q10 -8 10.5 -21.5t-8.5 -23.5l-90 -99l57 -56q158 126 359 126t359 -126l255 254h-134q-14 0 -23 9t-9 23v64zM832 256q185 0 316.5 131.5 t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf226;" horiz-adv-x="1792" d="M1790 1007q12 -155 -52.5 -292t-186 -224t-271.5 -103v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-512v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23 t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292q17 206 164.5 356.5t352.5 169.5q206 21 377 -94q171 115 377 94q205 -19 352.5 -169.5t164.5 -356.5zM896 647q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM576 512q115 0 218 57q-154 165 -154 391 q0 224 154 391q-103 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5zM1152 128v260q-137 15 -256 94q-119 -79 -256 -94v-260h512zM1216 512q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5q-115 0 -218 -57q154 -167 154 -391 q0 -226 -154 -391q103 -57 218 -57z" />
-<glyph unicode="&#xf227;" horiz-adv-x="1920" d="M1536 1120q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-31 -182 -166 -312t-318 -156q-210 -29 -384.5 80t-241.5 300q-117 6 -221 57.5t-177.5 133t-113.5 192.5t-32 230 q9 135 78 252t182 191.5t248 89.5q118 14 227.5 -19t198.5 -103l255 254h-134q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q59 -74 93 -169q182 -9 328 -124l255 254h-134q-14 0 -23 9 t-9 23v64zM1024 704q0 20 -4 58q-162 -25 -271 -150t-109 -292q0 -20 4 -58q162 25 271 150t109 292zM128 704q0 -168 111 -294t276 -149q-3 29 -3 59q0 210 135 369.5t338 196.5q-53 120 -163.5 193t-245.5 73q-185 0 -316.5 -131.5t-131.5 -316.5zM1088 -128 q185 0 316.5 131.5t131.5 316.5q0 168 -111 294t-276 149q3 -29 3 -59q0 -210 -135 -369.5t-338 -196.5q53 -120 163.5 -193t245.5 -73z" />
-<glyph unicode="&#xf228;" horiz-adv-x="2048" d="M1664 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-32 -180 -164.5 -310t-313.5 -157q-223 -34 -409 90q-117 -78 -256 -93v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23 t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-155 17 -279.5 109.5t-187 237.5t-39.5 307q25 187 159.5 322.5t320.5 164.5q224 34 410 -90q146 97 320 97q201 0 359 -126l255 254h-134q-14 0 -23 9 t-9 23v64zM896 391q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM128 704q0 -185 131.5 -316.5t316.5 -131.5q117 0 218 57q-154 167 -154 391t154 391q-101 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5zM1216 256q185 0 316.5 131.5t131.5 316.5 t-131.5 316.5t-316.5 131.5q-117 0 -218 -57q154 -167 154 -391t-154 -391q101 -57 218 -57z" />
-<glyph unicode="&#xf229;" d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-213 -214l140 -140q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-140 141l-78 -79q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5 t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5q203 0 359 -126l78 78l-172 172q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l172 -172l213 213h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf22a;" horiz-adv-x="1280" d="M640 892q217 -24 364.5 -187.5t147.5 -384.5q0 -167 -87 -306t-236 -212t-319 -54q-133 15 -245.5 88t-182 188t-80.5 249q-12 155 52.5 292t186 224t271.5 103v132h-160q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h160v165l-92 -92q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22 t9 23l202 201q19 19 45 19t45 -19l202 -201q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-92 92v-165h160q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-160v-132zM576 -128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5 t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf22b;" horiz-adv-x="2048" d="M1901 621q19 -19 19 -45t-19 -45l-294 -294q-9 -10 -22.5 -10t-22.5 10l-45 45q-10 9 -10 22.5t10 22.5l185 185h-294v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-132q-24 -217 -187.5 -364.5t-384.5 -147.5q-167 0 -306 87t-212 236t-54 319q15 133 88 245.5 t188 182t249 80.5q155 12 292 -52.5t224 -186t103 -271.5h132v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h294l-185 185q-10 9 -10 22.5t10 22.5l45 45q9 10 22.5 10t22.5 -10zM576 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5 t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf22c;" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-612q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v612q-217 24 -364.5 187.5t-147.5 384.5q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM576 512q185 0 316.5 131.5 t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
-<glyph unicode="&#xf22d;" horiz-adv-x="1280" d="M1024 576q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1152 576q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123 t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5z" />
-<glyph unicode="&#xf22e;" horiz-adv-x="1792" />
-<glyph unicode="&#xf22f;" horiz-adv-x="1792" />
-<glyph unicode="&#xf230;" d="M1451 1408q35 0 60 -25t25 -60v-1366q0 -35 -25 -60t-60 -25h-391v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-735q-35 0 -60 25t-25 60v1366q0 35 25 60t60 25h1366z" />
-<glyph unicode="&#xf231;" horiz-adv-x="1280" d="M0 939q0 108 37.5 203.5t103.5 166.5t152 123t185 78t202 26q158 0 294 -66.5t221 -193.5t85 -287q0 -96 -19 -188t-60 -177t-100 -149.5t-145 -103t-189 -38.5q-68 0 -135 32t-96 88q-10 -39 -28 -112.5t-23.5 -95t-20.5 -71t-26 -71t-32 -62.5t-46 -77.5t-62 -86.5 l-14 -5l-9 10q-15 157 -15 188q0 92 21.5 206.5t66.5 287.5t52 203q-32 65 -32 169q0 83 52 156t132 73q61 0 95 -40.5t34 -102.5q0 -66 -44 -191t-44 -187q0 -63 45 -104.5t109 -41.5q55 0 102 25t78.5 68t56 95t38 110.5t20 111t6.5 99.5q0 173 -109.5 269.5t-285.5 96.5 q-200 0 -334 -129.5t-134 -328.5q0 -44 12.5 -85t27 -65t27 -45.5t12.5 -30.5q0 -28 -15 -73t-37 -45q-2 0 -17 3q-51 15 -90.5 56t-61 94.5t-32.5 108t-11 106.5z" />
-<glyph unicode="&#xf232;" d="M985 562q13 0 97.5 -44t89.5 -53q2 -5 2 -15q0 -33 -17 -76q-16 -39 -71 -65.5t-102 -26.5q-57 0 -190 62q-98 45 -170 118t-148 185q-72 107 -71 194v8q3 91 74 158q24 22 52 22q6 0 18 -1.5t19 -1.5q19 0 26.5 -6.5t15.5 -27.5q8 -20 33 -88t25 -75q0 -21 -34.5 -57.5 t-34.5 -46.5q0 -7 5 -15q34 -73 102 -137q56 -53 151 -101q12 -7 22 -7q15 0 54 48.5t52 48.5zM782 32q127 0 243.5 50t200.5 134t134 200.5t50 243.5t-50 243.5t-134 200.5t-200.5 134t-243.5 50t-243.5 -50t-200.5 -134t-134 -200.5t-50 -243.5q0 -203 120 -368l-79 -233 l242 77q158 -104 345 -104zM782 1414q153 0 292.5 -60t240.5 -161t161 -240.5t60 -292.5t-60 -292.5t-161 -240.5t-240.5 -161t-292.5 -60q-195 0 -365 94l-417 -134l136 405q-108 178 -108 389q0 153 60 292.5t161 240.5t240.5 161t292.5 60z" />
-<glyph unicode="&#xf233;" horiz-adv-x="1792" d="M128 128h1024v128h-1024v-128zM128 640h1024v128h-1024v-128zM1696 192q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM128 1152h1024v128h-1024v-128zM1696 704q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1696 1216 q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1792 384v-384h-1792v384h1792zM1792 896v-384h-1792v384h1792zM1792 1408v-384h-1792v384h1792z" />
-<glyph unicode="&#xf234;" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1664 512h352q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-352q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5 t-9.5 22.5v352h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v352q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5v-352zM928 288q0 -52 38 -90t90 -38h256v-238q-68 -50 -171 -50h-874q-121 0 -194 69t-73 190q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q79 -61 154.5 -91.5t164.5 -30.5t164.5 30.5t154.5 91.5q20 17 39 17q132 0 217 -96h-223q-52 0 -90 -38t-38 -90v-192z" />
-<glyph unicode="&#xf235;" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1781 320l249 -249q9 -9 9 -23q0 -13 -9 -22l-136 -136q-9 -9 -22 -9q-14 0 -23 9l-249 249l-249 -249q-9 -9 -23 -9q-13 0 -22 9l-136 136 q-9 9 -9 22q0 14 9 23l249 249l-249 249q-9 9 -9 23q0 13 9 22l136 136q9 9 22 9q14 0 23 -9l249 -249l249 249q9 9 23 9q13 0 22 -9l136 -136q9 -9 9 -22q0 -14 -9 -23zM1283 320l-181 -181q-37 -37 -37 -91q0 -53 37 -90l83 -83q-21 -3 -44 -3h-874q-121 0 -194 69 t-73 190q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q154 -122 319 -122t319 122q20 17 39 17q28 0 57 -6q-28 -27 -41 -50t-13 -56q0 -54 37 -91z" />
-<glyph unicode="&#xf236;" horiz-adv-x="2048" d="M256 512h1728q26 0 45 -19t19 -45v-448h-256v256h-1536v-256h-256v1216q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-704zM832 832q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM2048 576v64q0 159 -112.5 271.5t-271.5 112.5h-704 q-26 0 -45 -19t-19 -45v-384h1152z" />
-<glyph unicode="&#xf237;" d="M1536 1536l-192 -448h192v-192h-274l-55 -128h329v-192h-411l-357 -832l-357 832h-411v192h329l-55 128h-274v192h192l-192 448h256l323 -768h378l323 768h256zM768 320l108 256h-216z" />
-<glyph unicode="&#xf238;" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM768 192q80 0 136 56t56 136t-56 136t-136 56 t-136 -56t-56 -136t56 -136t136 -56zM1344 768v512h-1152v-512h1152z" />
-<glyph unicode="&#xf239;" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM288 224q66 0 113 47t47 113t-47 113t-113 47 t-113 -47t-47 -113t47 -113t113 -47zM704 768v512h-544v-512h544zM1248 224q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM1408 768v512h-576v-512h576z" />
-<glyph unicode="&#xf23a;" horiz-adv-x="1792" d="M597 1115v-1173q0 -25 -12.5 -42.5t-36.5 -17.5q-17 0 -33 8l-465 233q-21 10 -35.5 33.5t-14.5 46.5v1140q0 20 10 34t29 14q14 0 44 -15l511 -256q3 -3 3 -5zM661 1014l534 -866l-534 266v600zM1792 996v-1054q0 -25 -14 -40.5t-38 -15.5t-47 13l-441 220zM1789 1116 q0 -3 -256.5 -419.5t-300.5 -487.5l-390 634l324 527q17 28 52 28q14 0 26 -6l541 -270q4 -2 4 -6z" />
-<glyph unicode="&#xf23b;" d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1408v-1536h-1536v1536h1536z" />
-<glyph unicode="&#xf23c;" horiz-adv-x="2296" d="M478 -139q-8 -16 -27 -34.5t-37 -25.5q-25 -9 -51.5 3.5t-28.5 31.5q-1 22 40 55t68 38q23 4 34 -21.5t2 -46.5zM1819 -139q7 -16 26 -34.5t38 -25.5q25 -9 51.5 3.5t27.5 31.5q2 22 -39.5 55t-68.5 38q-22 4 -33 -21.5t-2 -46.5zM1867 -30q13 -27 56.5 -59.5t77.5 -41.5 q45 -13 82 4.5t37 50.5q0 46 -67.5 100.5t-115.5 59.5q-40 5 -63.5 -37.5t-6.5 -76.5zM428 -30q-13 -27 -56 -59.5t-77 -41.5q-45 -13 -82 4.5t-37 50.5q0 46 67.5 100.5t115.5 59.5q40 5 63 -37.5t6 -76.5zM1158 1094h1q-41 0 -76 -15q27 -8 44 -30.5t17 -49.5 q0 -35 -27 -60t-65 -25q-52 0 -80 43q-5 -23 -5 -42q0 -74 56 -126.5t135 -52.5q80 0 136 52.5t56 126.5t-56 126.5t-136 52.5zM1462 1312q-99 109 -220.5 131.5t-245.5 -44.5q27 60 82.5 96.5t118 39.5t121.5 -17t99.5 -74.5t44.5 -131.5zM2212 73q8 -11 -11 -42 q7 -23 7 -40q1 -56 -44.5 -112.5t-109.5 -91.5t-118 -37q-48 -2 -92 21.5t-66 65.5q-687 -25 -1259 0q-23 -41 -66.5 -65t-92.5 -22q-86 3 -179.5 80.5t-92.5 160.5q2 22 7 40q-19 31 -11 42q6 10 31 1q14 22 41 51q-7 29 2 38q11 10 39 -4q29 20 59 34q0 29 13 37 q23 12 51 -16q35 5 61 -2q18 -4 38 -19v73q-11 0 -18 2q-53 10 -97 44.5t-55 87.5q-9 38 0 81q15 62 93 95q2 17 19 35.5t36 23.5t33 -7.5t19 -30.5h13q46 -5 60 -23q3 -3 5 -7q10 1 30.5 3.5t30.5 3.5q-15 11 -30 17q-23 40 -91 43q0 6 1 10q-62 2 -118.5 18.5t-84.5 47.5 q-32 36 -42.5 92t-2.5 112q16 126 90 179q23 16 52 4.5t32 -40.5q0 -1 1.5 -14t2.5 -21t3 -20t5.5 -19t8.5 -10q27 -14 76 -12q48 46 98 74q-40 4 -162 -14l47 46q61 58 163 111q145 73 282 86q-20 8 -41 15.5t-47 14t-42.5 10.5t-47.5 11t-43 10q595 126 904 -139 q98 -84 158 -222q85 -10 121 9h1q5 3 8.5 10t5.5 19t3 19.5t3 21.5l1 14q3 28 32 40t52 -5q73 -52 91 -178q7 -57 -3.5 -113t-42.5 -91q-28 -32 -83.5 -48.5t-115.5 -18.5v-10q-71 -2 -95 -43q-14 -5 -31 -17q11 -1 32 -3.5t30 -3.5q1 4 5 8q16 18 60 23h13q5 18 19 30t33 8 t36 -23t19 -36q79 -32 93 -95q9 -40 1 -81q-12 -53 -56 -88t-97 -44q-10 -2 -17 -2q0 -49 -1 -73q20 15 38 19q26 7 61 2q28 28 51 16q14 -9 14 -37q33 -16 59 -34q27 13 38 4q10 -10 2 -38q28 -30 41 -51q23 8 31 -1zM1937 1025q0 -29 -9 -54q82 -32 112 -132 q4 37 -9.5 98.5t-41.5 90.5q-20 19 -36 17t-16 -20zM1859 925q35 -42 47.5 -108.5t-0.5 -124.5q67 13 97 45q13 14 18 28q-3 64 -31 114.5t-79 66.5q-15 -15 -52 -21zM1822 921q-30 0 -44 1q42 -115 53 -239q21 0 43 3q16 68 1 135t-53 100zM258 839q30 100 112 132 q-9 25 -9 54q0 18 -16.5 20t-35.5 -17q-28 -29 -41.5 -90.5t-9.5 -98.5zM294 737q29 -31 97 -45q-13 58 -0.5 124.5t47.5 108.5v0q-37 6 -52 21q-51 -16 -78.5 -66t-31.5 -115q9 -17 18 -28zM471 683q14 124 73 235q-19 -4 -55 -18l-45 -19v1q-46 -89 -20 -196q25 -3 47 -3z M1434 644q8 -38 16.5 -108.5t11.5 -89.5q3 -18 9.5 -21.5t23.5 4.5q40 20 62 85.5t23 125.5q-24 2 -146 4zM1152 1285q-116 0 -199 -82.5t-83 -198.5q0 -117 83 -199.5t199 -82.5t199 82.5t83 199.5q0 116 -83 198.5t-199 82.5zM1380 646q-106 2 -211 0v1q-1 -27 2.5 -86 t13.5 -66q29 -14 93.5 -14.5t95.5 10.5q9 3 11 39t-0.5 69.5t-4.5 46.5zM1112 447q8 4 9.5 48t-0.5 88t-4 63v1q-212 -3 -214 -3q-4 -20 -7 -62t0 -83t14 -46q34 -15 101 -16t101 10zM718 636q-16 -59 4.5 -118.5t77.5 -84.5q15 -8 24 -5t12 21q3 16 8 90t10 103 q-69 -2 -136 -6zM591 510q3 -23 -34 -36q132 -141 271.5 -240t305.5 -154q172 49 310.5 146t293.5 250q-33 13 -30 34l3 9v1v-1q-17 2 -50 5.5t-48 4.5q-26 -90 -82 -132q-51 -38 -82 1q-5 6 -9 14q-7 13 -17 62q-2 -5 -5 -9t-7.5 -7t-8 -5.5t-9.5 -4l-10 -2.5t-12 -2 l-12 -1.5t-13.5 -1t-13.5 -0.5q-106 -9 -163 11q-4 -17 -10 -26.5t-21 -15t-23 -7t-36 -3.5q-2 0 -3 -0.5t-3 -0.5h-3q-179 -17 -203 40q-2 -63 -56 -54q-47 8 -91 54q-12 13 -20 26q-17 29 -26 65q-58 -6 -87 -10q1 -2 4 -10zM507 -118q3 14 3 30q-17 71 -51 130t-73 70 q-41 12 -101.5 -14.5t-104.5 -80t-39 -107.5q35 -53 100 -93t119 -42q51 -2 94 28t53 79zM510 53q23 -63 27 -119q195 113 392 174q-98 52 -180.5 120t-179.5 165q-6 -4 -29 -13q0 -2 -1 -5t-1 -4q31 -18 22 -37q-12 -23 -56 -34q-10 -13 -29 -24h-1q-2 -83 1 -150 q19 -34 35 -73zM579 -113q532 -21 1145 0q-254 147 -428 196q-76 -35 -156 -57q-8 -3 -16 0q-65 21 -129 49q-208 -60 -416 -188h-1v-1q1 0 1 1zM1763 -67q4 54 28 120q14 38 33 71l-1 -1q3 77 3 153q-15 8 -30 25q-42 9 -56 33q-9 20 22 38q-2 4 -2 9q-16 4 -28 12 q-204 -190 -383 -284q198 -59 414 -176zM2155 -90q5 54 -39 107.5t-104 80t-102 14.5q-38 -11 -72.5 -70.5t-51.5 -129.5q0 -16 3 -30q10 -49 53 -79t94 -28q54 2 119 42t100 93z" />
-<glyph unicode="&#xf23d;" horiz-adv-x="2304" d="M1524 -25q0 -68 -48 -116t-116 -48t-116.5 48t-48.5 116t48.5 116.5t116.5 48.5t116 -48.5t48 -116.5zM775 -25q0 -68 -48.5 -116t-116.5 -48t-116 48t-48 116t48 116.5t116 48.5t116.5 -48.5t48.5 -116.5zM0 1469q57 -60 110.5 -104.5t121 -82t136 -63t166 -45.5 t200 -31.5t250 -18.5t304 -9.5t372.5 -2.5q139 0 244.5 -5t181 -16.5t124 -27.5t71 -39.5t24 -51.5t-19.5 -64t-56.5 -76.5t-89.5 -91t-116 -104.5t-139 -119q-185 -157 -286 -247q29 51 76.5 109t94 105.5t94.5 98.5t83 91.5t54 80.5t13 70t-45.5 55.5t-116.5 41t-204 23.5 t-304 5q-168 -2 -314 6t-256 23t-204.5 41t-159.5 51.5t-122.5 62.5t-91.5 66.5t-68 71.5t-50.5 69.5t-40 68t-36.5 59.5z" />
-<glyph unicode="&#xf23e;" horiz-adv-x="1792" d="M896 1472q-169 0 -323 -66t-265.5 -177.5t-177.5 -265.5t-66 -323t66 -323t177.5 -265.5t265.5 -177.5t323 -66t323 66t265.5 177.5t177.5 265.5t66 323t-66 323t-177.5 265.5t-265.5 177.5t-323 66zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348 t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM496 704q16 0 16 -16v-480q0 -16 -16 -16h-32q-16 0 -16 16v480q0 16 16 16h32zM896 640q53 0 90.5 -37.5t37.5 -90.5q0 -35 -17.5 -64t-46.5 -46v-114q0 -14 -9 -23 t-23 -9h-64q-14 0 -23 9t-9 23v114q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5zM896 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM544 928v-96 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 93 65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5v-96q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 146 -103 249t-249 103t-249 -103t-103 -249zM1408 192v512q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-512 q0 -26 19 -45t45 -19h896q26 0 45 19t19 45z" />
-<glyph unicode="&#xf240;" horiz-adv-x="2304" d="M1920 1024v-768h-1664v768h1664zM2048 448h128v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288zM2304 832v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113 v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160q53 0 90.5 -37.5t37.5 -90.5z" />
-<glyph unicode="&#xf241;" horiz-adv-x="2304" d="M256 256v768h1280v-768h-1280zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
-<glyph unicode="&#xf242;" horiz-adv-x="2304" d="M256 256v768h896v-768h-896zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
-<glyph unicode="&#xf243;" horiz-adv-x="2304" d="M256 256v768h512v-768h-512zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
-<glyph unicode="&#xf244;" horiz-adv-x="2304" d="M2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23 v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
-<glyph unicode="&#xf245;" horiz-adv-x="1280" d="M1133 493q31 -30 14 -69q-17 -40 -59 -40h-382l201 -476q10 -25 0 -49t-34 -35l-177 -75q-25 -10 -49 0t-35 34l-191 452l-312 -312q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v1504q0 42 40 59q12 5 24 5q27 0 45 -19z" />
-<glyph unicode="&#xf246;" horiz-adv-x="1024" d="M832 1408q-320 0 -320 -224v-416h128v-128h-128v-544q0 -224 320 -224h64v-128h-64q-272 0 -384 146q-112 -146 -384 -146h-64v128h64q320 0 320 224v544h-128v128h128v416q0 224 -320 224h-64v128h64q272 0 384 -146q112 146 384 146h64v-128h-64z" />
-<glyph unicode="&#xf247;" horiz-adv-x="2048" d="M2048 1152h-128v-1024h128v-384h-384v128h-1280v-128h-384v384h128v1024h-128v384h384v-128h1280v128h384v-384zM1792 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 -128v128h-128v-128h128zM1664 0v128h128v1024h-128v128h-1280v-128h-128v-1024h128v-128 h1280zM1920 -128v128h-128v-128h128zM1280 896h384v-768h-896v256h-384v768h896v-256zM512 512h640v512h-640v-512zM1536 256v512h-256v-384h-384v-128h640z" />
-<glyph unicode="&#xf248;" horiz-adv-x="2304" d="M2304 768h-128v-640h128v-384h-384v128h-896v-128h-384v384h128v128h-384v-128h-384v384h128v640h-128v384h384v-128h896v128h384v-384h-128v-128h384v128h384v-384zM2048 1024v-128h128v128h-128zM1408 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 256 v128h-128v-128h128zM1536 384h-128v-128h128v128zM384 384h896v128h128v640h-128v128h-896v-128h-128v-640h128v-128zM896 -128v128h-128v-128h128zM2176 -128v128h-128v-128h128zM2048 128v640h-128v128h-384v-384h128v-384h-384v128h-384v-128h128v-128h896v128h128z" />
-<glyph unicode="&#xf249;" d="M1024 288v-416h-928q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68v-928h-416q-40 0 -68 -28t-28 -68zM1152 256h381q-15 -82 -65 -132l-184 -184q-50 -50 -132 -65v381z" />
-<glyph unicode="&#xf24a;" d="M1400 256h-248v-248q29 10 41 22l185 185q12 12 22 41zM1120 384h288v896h-1280v-1280h896v288q0 40 28 68t68 28zM1536 1312v-1024q0 -40 -20 -88t-48 -76l-184 -184q-28 -28 -76 -48t-88 -20h-1024q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68 z" />
-<glyph unicode="&#xf24b;" horiz-adv-x="2304" d="M1951 538q0 -26 -15.5 -44.5t-38.5 -23.5q-8 -2 -18 -2h-153v140h153q10 0 18 -2q23 -5 38.5 -23.5t15.5 -44.5zM1933 751q0 -25 -15 -42t-38 -21q-3 -1 -15 -1h-139v129h139q3 0 8.5 -0.5t6.5 -0.5q23 -4 38 -21.5t15 -42.5zM728 587v308h-228v-308q0 -58 -38 -94.5 t-105 -36.5q-108 0 -229 59v-112q53 -15 121 -23t109 -9l42 -1q328 0 328 217zM1442 403v113q-99 -52 -200 -59q-108 -8 -169 41t-61 142t61 142t169 41q101 -7 200 -58v112q-48 12 -100 19.5t-80 9.5l-28 2q-127 6 -218.5 -14t-140.5 -60t-71 -88t-22 -106t22 -106t71 -88 t140.5 -60t218.5 -14q101 4 208 31zM2176 518q0 54 -43 88.5t-109 39.5v3q57 8 89 41.5t32 79.5q0 55 -41 88t-107 36q-3 0 -12 0.5t-14 0.5h-455v-510h491q74 0 121.5 36.5t47.5 96.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90 t90 38h2048q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf24c;" horiz-adv-x="2304" d="M858 295v693q-106 -41 -172 -135.5t-66 -211.5t66 -211.5t172 -134.5zM1362 641q0 117 -66 211.5t-172 135.5v-694q106 41 172 135.5t66 211.5zM1577 641q0 -159 -78.5 -294t-213.5 -213.5t-294 -78.5q-119 0 -227.5 46.5t-187 125t-125 187t-46.5 227.5q0 159 78.5 294 t213.5 213.5t294 78.5t294 -78.5t213.5 -213.5t78.5 -294zM1960 634q0 139 -55.5 261.5t-147.5 205.5t-213.5 131t-252.5 48h-301q-176 0 -323.5 -81t-235 -230t-87.5 -335q0 -171 87 -317.5t236 -231.5t323 -85h301q129 0 251.5 50.5t214.5 135t147.5 202.5t55.5 246z M2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf24d;" horiz-adv-x="1792" d="M1664 -96v1088q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5zM1792 992v-1088q0 -66 -47 -113t-113 -47h-1088q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113 zM1408 1376v-160h-128v160q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h160v-128h-160q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf24e;" horiz-adv-x="2304" d="M1728 1088l-384 -704h768zM448 1088l-384 -704h768zM1269 1280q-14 -40 -45.5 -71.5t-71.5 -45.5v-1291h608q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1344q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h608v1291q-40 14 -71.5 45.5t-45.5 71.5h-491q-14 0 -23 9t-9 23v64 q0 14 9 23t23 9h491q21 57 70 92.5t111 35.5t111 -35.5t70 -92.5h491q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-491zM1088 1264q33 0 56.5 23.5t23.5 56.5t-23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5zM2176 384q0 -73 -46.5 -131t-117.5 -91 t-144.5 -49.5t-139.5 -16.5t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81zM896 384q0 -73 -46.5 -131t-117.5 -91t-144.5 -49.5t-139.5 -16.5 t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81z" />
-<glyph unicode="&#xf250;" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-77 -29 -149 -92.5 t-129.5 -152.5t-92.5 -210t-35 -253h1024q0 132 -35 253t-92.5 210t-129.5 152.5t-149 92.5q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" />
-<glyph unicode="&#xf251;" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -66 9 -128h1006q9 61 9 128zM1280 -128q0 130 -34 249.5t-90.5 208t-126.5 152t-146 94.5h-230q-76 -31 -146 -94.5t-126.5 -152t-90.5 -208t-34 -249.5h1024z" />
-<glyph unicode="&#xf252;" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -206 85 -384h854q85 178 85 384zM1223 192q-54 141 -145.5 241.5t-194.5 142.5h-230q-103 -42 -194.5 -142.5t-145.5 -241.5h910z" />
-<glyph unicode="&#xf253;" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-137 -51 -244 -196 h700q-107 145 -244 196q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" />
-<glyph unicode="&#xf254;" d="M1504 -64q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472zM130 0q3 55 16 107t30 95t46 87t53.5 76t64.5 69.5t66 60t70.5 55t66.5 47.5t65 43q-43 28 -65 43t-66.5 47.5t-70.5 55t-66 60t-64.5 69.5t-53.5 76t-46 87 t-30 95t-16 107h1276q-3 -55 -16 -107t-30 -95t-46 -87t-53.5 -76t-64.5 -69.5t-66 -60t-70.5 -55t-66.5 -47.5t-65 -43q43 -28 65 -43t66.5 -47.5t70.5 -55t66 -60t64.5 -69.5t53.5 -76t46 -87t30 -95t16 -107h-1276zM1504 1536q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9 h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472z" />
-<glyph unicode="&#xf255;" d="M768 1152q-53 0 -90.5 -37.5t-37.5 -90.5v-128h-32v93q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-429l-32 30v172q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-224q0 -47 35 -82l310 -296q39 -39 39 -102q0 -26 19 -45t45 -19h640q26 0 45 19t19 45v25 q0 41 10 77l108 436q10 36 10 77v246q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-32h-32v125q0 40 -25 72.5t-64 40.5q-14 2 -23 2q-46 0 -79 -33t-33 -79v-128h-32v122q0 51 -32.5 89.5t-82.5 43.5q-5 1 -13 1zM768 1280q84 0 149 -50q57 34 123 34q59 0 111 -27 t86 -76q27 7 59 7q100 0 170 -71.5t70 -171.5v-246q0 -51 -13 -108l-109 -436q-6 -24 -6 -71q0 -80 -56 -136t-136 -56h-640q-84 0 -138 58.5t-54 142.5l-308 296q-76 73 -76 175v224q0 99 70.5 169.5t169.5 70.5q11 0 16 -1q6 95 75.5 160t164.5 65q52 0 98 -21 q72 69 174 69z" />
-<glyph unicode="&#xf256;" horiz-adv-x="1792" d="M880 1408q-46 0 -79 -33t-33 -79v-656h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528v-256l-154 205q-38 51 -102 51q-53 0 -90.5 -37.5t-37.5 -90.5q0 -43 26 -77l384 -512q38 -51 102 -51h688q34 0 61 22t34 56l76 405q5 32 5 59v498q0 46 -33 79t-79 33t-79 -33 t-33 -79v-272h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528h-32v656q0 46 -33 79t-79 33zM880 1536q68 0 125.5 -35.5t88.5 -96.5q19 4 42 4q99 0 169.5 -70.5t70.5 -169.5v-17q105 6 180.5 -64t75.5 -175v-498q0 -40 -8 -83l-76 -404q-14 -79 -76.5 -131t-143.5 -52 h-688q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 106 75 181t181 75q78 0 128 -34v434q0 99 70.5 169.5t169.5 70.5q23 0 42 -4q31 61 88.5 96.5t125.5 35.5z" />
-<glyph unicode="&#xf257;" horiz-adv-x="1792" d="M1073 -128h-177q-163 0 -226 141q-23 49 -23 102v5q-62 30 -98.5 88.5t-36.5 127.5q0 38 5 48h-261q-106 0 -181 75t-75 181t75 181t181 75h113l-44 17q-74 28 -119.5 93.5t-45.5 145.5q0 106 75 181t181 75q46 0 91 -17l628 -239h401q106 0 181 -75t75 -181v-668 q0 -88 -54 -157.5t-140 -90.5l-339 -85q-92 -23 -186 -23zM1024 583l-155 -71l-163 -74q-30 -14 -48 -41.5t-18 -60.5q0 -46 33 -79t79 -33q26 0 46 10l338 154q-49 10 -80.5 50t-31.5 90v55zM1344 272q0 46 -33 79t-79 33q-26 0 -46 -10l-290 -132q-28 -13 -37 -17 t-30.5 -17t-29.5 -23.5t-16 -29t-8 -40.5q0 -50 31.5 -82t81.5 -32q20 0 38 9l352 160q30 14 48 41.5t18 60.5zM1112 1024l-650 248q-24 8 -46 8q-53 0 -90.5 -37.5t-37.5 -90.5q0 -40 22.5 -73t59.5 -47l526 -200v-64h-640q-53 0 -90.5 -37.5t-37.5 -90.5t37.5 -90.5 t90.5 -37.5h535l233 106v198q0 63 46 106l111 102h-69zM1073 0q82 0 155 19l339 85q43 11 70 45.5t27 78.5v668q0 53 -37.5 90.5t-90.5 37.5h-308l-136 -126q-36 -33 -36 -82v-296q0 -46 33 -77t79 -31t79 35t33 81v208h32v-208q0 -70 -57 -114q52 -8 86.5 -48.5t34.5 -93.5 q0 -42 -23 -78t-61 -53l-310 -141h91z" />
-<glyph unicode="&#xf258;" horiz-adv-x="2048" d="M1151 1536q61 0 116 -28t91 -77l572 -781q118 -159 118 -359v-355q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v177l-286 143h-546q-80 0 -136 56t-56 136v32q0 119 84.5 203.5t203.5 84.5h420l42 128h-686q-100 0 -173.5 67.5t-81.5 166.5q-65 79 -65 182v32 q0 80 56 136t136 56h959zM1920 -64v355q0 157 -93 284l-573 781q-39 52 -103 52h-959q-26 0 -45 -19t-19 -45q0 -32 1.5 -49.5t9.5 -40.5t25 -43q10 31 35.5 50t56.5 19h832v-32h-832q-26 0 -45 -19t-19 -45q0 -44 3 -58q8 -44 44 -73t81 -29h640h91q40 0 68 -28t28 -68 q0 -15 -5 -30l-64 -192q-10 -29 -35 -47.5t-56 -18.5h-443q-66 0 -113 -47t-47 -113v-32q0 -26 19 -45t45 -19h561q16 0 29 -7l317 -158q24 -13 38.5 -36t14.5 -50v-197q0 -26 19 -45t45 -19h384q26 0 45 19t19 45z" />
-<glyph unicode="&#xf259;" horiz-adv-x="2048" d="M816 1408q-48 0 -79.5 -34t-31.5 -82q0 -14 3 -28l150 -624h-26l-116 482q-9 38 -39.5 62t-69.5 24q-47 0 -79 -34t-32 -81q0 -11 4 -29q3 -13 39 -161t68 -282t32 -138v-227l-307 230q-34 26 -77 26q-52 0 -89.5 -36.5t-37.5 -88.5q0 -67 56 -110l507 -379 q34 -26 76 -26h694q33 0 59 20.5t34 52.5l100 401q8 30 10 88t9 86l116 478q3 12 3 26q0 46 -33 79t-80 33q-38 0 -69 -25.5t-40 -62.5l-99 -408h-26l132 547q3 14 3 28q0 47 -32 80t-80 33q-38 0 -68.5 -24t-39.5 -62l-145 -602h-127l-164 682q-9 38 -39.5 62t-68.5 24z M1461 -256h-694q-85 0 -153 51l-507 380q-50 38 -78.5 94t-28.5 118q0 105 75 179t180 74q25 0 49.5 -5.5t41.5 -11t41 -20.5t35 -23t38.5 -29.5t37.5 -28.5l-123 512q-7 35 -7 59q0 93 60 162t152 79q14 87 80.5 144.5t155.5 57.5q83 0 148 -51.5t85 -132.5l103 -428 l83 348q20 81 85 132.5t148 51.5q87 0 152.5 -54t82.5 -139q93 -10 155 -78t62 -161q0 -30 -7 -57l-116 -477q-5 -22 -5 -67q0 -51 -13 -108l-101 -401q-19 -75 -79.5 -122.5t-137.5 -47.5z" />
-<glyph unicode="&#xf25a;" horiz-adv-x="1792" d="M640 1408q-53 0 -90.5 -37.5t-37.5 -90.5v-512v-384l-151 202q-41 54 -107 54q-52 0 -89 -38t-37 -90q0 -43 26 -77l384 -512q38 -51 102 -51h718q22 0 39.5 13.5t22.5 34.5l92 368q24 96 24 194v217q0 41 -28 71t-68 30t-68 -28t-28 -68h-32v61q0 48 -32 81.5t-80 33.5 q-46 0 -79 -33t-33 -79v-64h-32v90q0 55 -37 94.5t-91 39.5q-53 0 -90.5 -37.5t-37.5 -90.5v-96h-32v570q0 55 -37 94.5t-91 39.5zM640 1536q107 0 181.5 -77.5t74.5 -184.5v-220q22 2 32 2q99 0 173 -69q47 21 99 21q113 0 184 -87q27 7 56 7q94 0 159 -67.5t65 -161.5 v-217q0 -116 -28 -225l-92 -368q-16 -64 -68 -104.5t-118 -40.5h-718q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 105 74.5 180.5t179.5 75.5q71 0 130 -35v547q0 106 75 181t181 75zM768 128v384h-32v-384h32zM1024 128v384h-32v-384h32zM1280 128v384h-32 v-384h32z" />
-<glyph unicode="&#xf25b;" d="M1288 889q60 0 107 -23q141 -63 141 -226v-177q0 -94 -23 -186l-85 -339q-21 -86 -90.5 -140t-157.5 -54h-668q-106 0 -181 75t-75 181v401l-239 628q-17 45 -17 91q0 106 75 181t181 75q80 0 145.5 -45.5t93.5 -119.5l17 -44v113q0 106 75 181t181 75t181 -75t75 -181 v-261q27 5 48 5q69 0 127.5 -36.5t88.5 -98.5zM1072 896q-33 0 -60.5 -18t-41.5 -48l-74 -163l-71 -155h55q50 0 90 -31.5t50 -80.5l154 338q10 20 10 46q0 46 -33 79t-79 33zM1293 761q-22 0 -40.5 -8t-29 -16t-23.5 -29.5t-17 -30.5t-17 -37l-132 -290q-10 -20 -10 -46 q0 -46 33 -79t79 -33q33 0 60.5 18t41.5 48l160 352q9 18 9 38q0 50 -32 81.5t-82 31.5zM128 1120q0 -22 8 -46l248 -650v-69l102 111q43 46 106 46h198l106 233v535q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5v-640h-64l-200 526q-14 37 -47 59.5t-73 22.5 q-53 0 -90.5 -37.5t-37.5 -90.5zM1180 -128q44 0 78.5 27t45.5 70l85 339q19 73 19 155v91l-141 -310q-17 -38 -53 -61t-78 -23q-53 0 -93.5 34.5t-48.5 86.5q-44 -57 -114 -57h-208v32h208q46 0 81 33t35 79t-31 79t-77 33h-296q-49 0 -82 -36l-126 -136v-308 q0 -53 37.5 -90.5t90.5 -37.5h668z" />
-<glyph unicode="&#xf25c;" horiz-adv-x="1973" d="M857 992v-117q0 -13 -9.5 -22t-22.5 -9h-298v-812q0 -13 -9 -22.5t-22 -9.5h-135q-13 0 -22.5 9t-9.5 23v812h-297q-13 0 -22.5 9t-9.5 22v117q0 14 9 23t23 9h793q13 0 22.5 -9.5t9.5 -22.5zM1895 995l77 -961q1 -13 -8 -24q-10 -10 -23 -10h-134q-12 0 -21 8.5 t-10 20.5l-46 588l-189 -425q-8 -19 -29 -19h-120q-20 0 -29 19l-188 427l-45 -590q-1 -12 -10 -20.5t-21 -8.5h-135q-13 0 -23 10q-9 10 -9 24l78 961q1 12 10 20.5t21 8.5h142q20 0 29 -19l220 -520q10 -24 20 -51q3 7 9.5 24.5t10.5 26.5l221 520q9 19 29 19h141 q13 0 22 -8.5t10 -20.5z" />
-<glyph unicode="&#xf25d;" horiz-adv-x="1792" d="M1042 833q0 88 -60 121q-33 18 -117 18h-123v-281h162q66 0 102 37t36 105zM1094 548l205 -373q8 -17 -1 -31q-8 -16 -27 -16h-152q-20 0 -28 17l-194 365h-155v-350q0 -14 -9 -23t-23 -9h-134q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h294q128 0 190 -24q85 -31 134 -109 t49 -180q0 -92 -42.5 -165.5t-115.5 -109.5q6 -10 9 -16zM896 1376q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM1792 640 q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
-<glyph unicode="&#xf25e;" horiz-adv-x="1792" d="M605 303q153 0 257 104q14 18 3 36l-45 82q-6 13 -24 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13t-23.5 -14.5t-28.5 -13.5t-33.5 -9.5t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78 q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-148 0 -246 -96.5t-98 -240.5q0 -146 97 -241.5t247 -95.5zM1235 303q153 0 257 104q14 18 4 36l-45 82q-8 14 -25 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13t-23.5 -14.5t-28.5 -13.5t-33.5 -9.5 t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-147 0 -245.5 -96.5t-98.5 -240.5q0 -146 97 -241.5t247 -95.5zM896 1376 q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191 t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71z" />
-<glyph unicode="&#xf260;" horiz-adv-x="2048" d="M736 736l384 -384l-384 -384l-672 672l672 672l168 -168l-96 -96l-72 72l-480 -480l480 -480l193 193l-289 287zM1312 1312l672 -672l-672 -672l-168 168l96 96l72 -72l480 480l-480 480l-193 -193l289 -287l-96 -96l-384 384z" />
-<glyph unicode="&#xf261;" horiz-adv-x="1792" d="M717 182l271 271l-279 279l-88 -88l192 -191l-96 -96l-279 279l279 279l40 -40l87 87l-127 128l-454 -454zM1075 190l454 454l-454 454l-271 -271l279 -279l88 88l-192 191l96 96l279 -279l-279 -279l-40 40l-87 -88zM1792 640q0 -182 -71 -348t-191 -286t-286 -191 t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
-<glyph unicode="&#xf262;" horiz-adv-x="2304" d="M651 539q0 -39 -27.5 -66.5t-65.5 -27.5q-39 0 -66.5 27.5t-27.5 66.5q0 38 27.5 65.5t66.5 27.5q38 0 65.5 -27.5t27.5 -65.5zM1805 540q0 -39 -27.5 -66.5t-66.5 -27.5t-66.5 27.5t-27.5 66.5t27.5 66t66.5 27t66.5 -27t27.5 -66zM765 539q0 79 -56.5 136t-136.5 57 t-136.5 -56.5t-56.5 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM1918 540q0 80 -56.5 136.5t-136.5 56.5q-79 0 -136 -56.5t-57 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM850 539q0 -116 -81.5 -197.5t-196.5 -81.5q-116 0 -197.5 82t-81.5 197 t82 196.5t197 81.5t196.5 -81.5t81.5 -196.5zM2004 540q0 -115 -81.5 -196.5t-197.5 -81.5q-115 0 -196.5 81.5t-81.5 196.5t81.5 196.5t196.5 81.5q116 0 197.5 -81.5t81.5 -196.5zM1040 537q0 191 -135.5 326.5t-326.5 135.5q-125 0 -231 -62t-168 -168.5t-62 -231.5 t62 -231.5t168 -168.5t231 -62q191 0 326.5 135.5t135.5 326.5zM1708 1110q-254 111 -556 111q-319 0 -573 -110q117 0 223 -45.5t182.5 -122.5t122 -183t45.5 -223q0 115 43.5 219.5t118 180.5t177.5 123t217 50zM2187 537q0 191 -135 326.5t-326 135.5t-326.5 -135.5 t-135.5 -326.5t135.5 -326.5t326.5 -135.5t326 135.5t135 326.5zM1921 1103h383q-44 -51 -75 -114.5t-40 -114.5q110 -151 110 -337q0 -156 -77 -288t-209 -208.5t-287 -76.5q-133 0 -249 56t-196 155q-47 -56 -129 -179q-11 22 -53.5 82.5t-74.5 97.5 q-80 -99 -196.5 -155.5t-249.5 -56.5q-155 0 -287 76.5t-209 208.5t-77 288q0 186 110 337q-9 51 -40 114.5t-75 114.5h365q149 100 355 156.5t432 56.5q224 0 421 -56t348 -157z" />
-<glyph unicode="&#xf263;" horiz-adv-x="1280" d="M640 629q-188 0 -321 133t-133 320q0 188 133 321t321 133t321 -133t133 -321q0 -187 -133 -320t-321 -133zM640 1306q-92 0 -157.5 -65.5t-65.5 -158.5q0 -92 65.5 -157.5t157.5 -65.5t157.5 65.5t65.5 157.5q0 93 -65.5 158.5t-157.5 65.5zM1163 574q13 -27 15 -49.5 t-4.5 -40.5t-26.5 -38.5t-42.5 -37t-61.5 -41.5q-115 -73 -315 -94l73 -72l267 -267q30 -31 30 -74t-30 -73l-12 -13q-31 -30 -74 -30t-74 30q-67 68 -267 268l-267 -268q-31 -30 -74 -30t-73 30l-12 13q-31 30 -31 73t31 74l267 267l72 72q-203 21 -317 94 q-39 25 -61.5 41.5t-42.5 37t-26.5 38.5t-4.5 40.5t15 49.5q10 20 28 35t42 22t56 -2t65 -35q5 -4 15 -11t43 -24.5t69 -30.5t92 -24t113 -11q91 0 174 25.5t120 50.5l38 25q33 26 65 35t56 2t42 -22t28 -35z" />
-<glyph unicode="&#xf264;" d="M927 956q0 -66 -46.5 -112.5t-112.5 -46.5t-112.5 46.5t-46.5 112.5t46.5 112.5t112.5 46.5t112.5 -46.5t46.5 -112.5zM1141 593q-10 20 -28 32t-47.5 9.5t-60.5 -27.5q-10 -8 -29 -20t-81 -32t-127 -20t-124 18t-86 36l-27 18q-31 25 -60.5 27.5t-47.5 -9.5t-28 -32 q-22 -45 -2 -74.5t87 -73.5q83 -53 226 -67l-51 -52q-142 -142 -191 -190q-22 -22 -22 -52.5t22 -52.5l9 -9q22 -22 52.5 -22t52.5 22l191 191q114 -115 191 -191q22 -22 52.5 -22t52.5 22l9 9q22 22 22 52.5t-22 52.5l-191 190l-52 52q141 14 225 67q67 44 87 73.5t-2 74.5 zM1092 956q0 134 -95 229t-229 95t-229 -95t-95 -229t95 -229t229 -95t229 95t95 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf265;" horiz-adv-x="1720" d="M1565 1408q65 0 110 -45.5t45 -110.5v-519q0 -176 -68 -336t-182.5 -275t-274 -182.5t-334.5 -67.5q-176 0 -335.5 67.5t-274.5 182.5t-183 275t-68 336v519q0 64 46 110t110 46h1409zM861 344q47 0 82 33l404 388q37 35 37 85q0 49 -34.5 83.5t-83.5 34.5q-47 0 -82 -33 l-323 -310l-323 310q-35 33 -81 33q-49 0 -83.5 -34.5t-34.5 -83.5q0 -51 36 -85l405 -388q33 -33 81 -33z" />
-<glyph unicode="&#xf266;" horiz-adv-x="2304" d="M1494 -103l-295 695q-25 -49 -158.5 -305.5t-198.5 -389.5q-1 -1 -27.5 -0.5t-26.5 1.5q-82 193 -255.5 587t-259.5 596q-21 50 -66.5 107.5t-103.5 100.5t-102 43q0 5 -0.5 24t-0.5 27h583v-50q-39 -2 -79.5 -16t-66.5 -43t-10 -64q26 -59 216.5 -499t235.5 -540 q31 61 140 266.5t131 247.5q-19 39 -126 281t-136 295q-38 69 -201 71v50l513 -1v-47q-60 -2 -93.5 -25t-12.5 -69q33 -70 87 -189.5t86 -187.5q110 214 173 363q24 55 -10 79.5t-129 26.5q1 7 1 25v24q64 0 170.5 0.5t180 1t92.5 0.5v-49q-62 -2 -119 -33t-90 -81 l-213 -442q13 -33 127.5 -290t121.5 -274l441 1017q-14 38 -49.5 62.5t-65 31.5t-55.5 8v50l460 -4l1 -2l-1 -44q-139 -4 -201 -145q-526 -1216 -559 -1291h-49z" />
-<glyph unicode="&#xf267;" horiz-adv-x="1792" d="M949 643q0 -26 -16.5 -45t-41.5 -19q-26 0 -45 16.5t-19 41.5q0 26 17 45t42 19t44 -16.5t19 -41.5zM964 585l350 581q-9 -8 -67.5 -62.5t-125.5 -116.5t-136.5 -127t-117 -110.5t-50.5 -51.5l-349 -580q7 7 67 62t126 116.5t136 127t117 111t50 50.5zM1611 640 q0 -201 -104 -371q-3 2 -17 11t-26.5 16.5t-16.5 7.5q-13 0 -13 -13q0 -10 59 -44q-74 -112 -184.5 -190.5t-241.5 -110.5l-16 67q-1 10 -15 10q-5 0 -8 -5.5t-2 -9.5l16 -68q-72 -15 -146 -15q-199 0 -372 105q1 2 13 20.5t21.5 33.5t9.5 19q0 13 -13 13q-6 0 -17 -14.5 t-22.5 -34.5t-13.5 -23q-113 75 -192 187.5t-110 244.5l69 15q10 3 10 15q0 5 -5.5 8t-10.5 2l-68 -15q-14 72 -14 139q0 206 109 379q2 -1 18.5 -12t30 -19t17.5 -8q13 0 13 12q0 6 -12.5 15.5t-32.5 21.5l-20 12q77 112 189 189t244 107l15 -67q2 -10 15 -10q5 0 8 5.5 t2 10.5l-15 66q71 13 134 13q204 0 379 -109q-39 -56 -39 -65q0 -13 12 -13q11 0 48 64q111 -75 187.5 -186t107.5 -241l-56 -12q-10 -2 -10 -16q0 -5 5.5 -8t9.5 -2l57 13q14 -72 14 -140zM1696 640q0 163 -63.5 311t-170.5 255t-255 170.5t-311 63.5t-311 -63.5 t-255 -170.5t-170.5 -255t-63.5 -311t63.5 -311t170.5 -255t255 -170.5t311 -63.5t311 63.5t255 170.5t170.5 255t63.5 311zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191 t191 -286t71 -348z" />
-<glyph unicode="&#xf268;" horiz-adv-x="1792" d="M893 1536q240 2 451 -120q232 -134 352 -372l-742 39q-160 9 -294 -74.5t-185 -229.5l-276 424q128 159 311 245.5t383 87.5zM146 1131l337 -663q72 -143 211 -217t293 -45l-230 -451q-212 33 -385 157.5t-272.5 316t-99.5 411.5q0 267 146 491zM1732 962 q58 -150 59.5 -310.5t-48.5 -306t-153 -272t-246 -209.5q-230 -133 -498 -119l405 623q88 131 82.5 290.5t-106.5 277.5zM896 942q125 0 213.5 -88.5t88.5 -213.5t-88.5 -213.5t-213.5 -88.5t-213.5 88.5t-88.5 213.5t88.5 213.5t213.5 88.5z" />
-<glyph unicode="&#xf269;" horiz-adv-x="1792" d="M903 -256q-283 0 -504.5 150.5t-329.5 398.5q-58 131 -67 301t26 332.5t111 312t179 242.5l-11 -281q11 14 68 15.5t70 -15.5q42 81 160.5 138t234.5 59q-54 -45 -119.5 -148.5t-58.5 -163.5q25 -8 62.5 -13.5t63 -7.5t68 -4t50.5 -3q15 -5 9.5 -45.5t-30.5 -75.5 q-5 -7 -16.5 -18.5t-56.5 -35.5t-101 -34l15 -189l-139 67q-18 -43 -7.5 -81.5t36 -66.5t65.5 -41.5t81 -6.5q51 9 98 34.5t83.5 45t73.5 17.5q61 -4 89.5 -33t19.5 -65q-1 -2 -2.5 -5.5t-8.5 -12.5t-18 -15.5t-31.5 -10.5t-46.5 -1q-60 -95 -144.5 -135.5t-209.5 -29.5 q74 -61 162.5 -82.5t168.5 -6t154.5 52t128 87.5t80.5 104q43 91 39 192.5t-37.5 188.5t-78.5 125q87 -38 137 -79.5t77 -112.5q15 170 -57.5 343t-209.5 284q265 -77 412 -279.5t151 -517.5q2 -127 -40.5 -255t-123.5 -238t-189 -196t-247.5 -135.5t-288.5 -49.5z" />
-<glyph unicode="&#xf26a;" horiz-adv-x="1792" d="M1493 1308q-165 110 -359 110q-155 0 -293 -73t-240 -200q-75 -93 -119.5 -218t-48.5 -266v-42q4 -141 48.5 -266t119.5 -218q102 -127 240 -200t293 -73q194 0 359 110q-121 -108 -274.5 -168t-322.5 -60q-29 0 -43 1q-175 8 -333 82t-272 193t-181 281t-67 339 q0 182 71 348t191 286t286 191t348 71h3q168 -1 320.5 -60.5t273.5 -167.5zM1792 640q0 -192 -77 -362.5t-213 -296.5q-104 -63 -222 -63q-137 0 -255 84q154 56 253.5 233t99.5 405q0 227 -99 404t-253 234q119 83 254 83q119 0 226 -65q135 -125 210.5 -295t75.5 -361z " />
-<glyph unicode="&#xf26b;" horiz-adv-x="1792" d="M1792 599q0 -56 -7 -104h-1151q0 -146 109.5 -244.5t257.5 -98.5q99 0 185.5 46.5t136.5 130.5h423q-56 -159 -170.5 -281t-267.5 -188.5t-321 -66.5q-187 0 -356 83q-228 -116 -394 -116q-237 0 -237 263q0 115 45 275q17 60 109 229q199 360 475 606 q-184 -79 -427 -354q63 274 283.5 449.5t501.5 175.5q30 0 45 -1q255 117 433 117q64 0 116 -13t94.5 -40.5t66.5 -76.5t24 -115q0 -116 -75 -286q101 -182 101 -390zM1722 1239q0 83 -53 132t-137 49q-108 0 -254 -70q121 -47 222.5 -131.5t170.5 -195.5q51 135 51 216z M128 2q0 -86 48.5 -132.5t134.5 -46.5q115 0 266 83q-122 72 -213.5 183t-137.5 245q-98 -205 -98 -332zM632 715h728q-5 142 -113 237t-251 95q-144 0 -251.5 -95t-112.5 -237z" />
-<glyph unicode="&#xf26c;" horiz-adv-x="2048" d="M1792 288v960q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1248v-960q0 -66 -47 -113t-113 -47h-736v-128h352q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23 v64q0 14 9 23t23 9h352v128h-736q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
-<glyph unicode="&#xf26d;" horiz-adv-x="1792" d="M138 1408h197q-70 -64 -126 -149q-36 -56 -59 -115t-30 -125.5t-8.5 -120t10.5 -132t21 -126t28 -136.5q4 -19 6 -28q51 -238 81 -329q57 -171 152 -275h-272q-48 0 -82 34t-34 82v1304q0 48 34 82t82 34zM1346 1408h308q48 0 82 -34t34 -82v-1304q0 -48 -34 -82t-82 -34 h-178q212 210 196 565l-469 -101q-2 -45 -12 -82t-31 -72t-59.5 -59.5t-93.5 -36.5q-123 -26 -199 40q-32 27 -53 61t-51.5 129t-64.5 258q-35 163 -45.5 263t-5.5 139t23 77q20 41 62.5 73t102.5 45q45 12 83.5 6.5t67 -17t54 -35t43 -48t34.5 -56.5l468 100 q-68 175 -180 287z" />
-<glyph unicode="&#xf26e;" d="M1401 -11l-6 -6q-113 -114 -259 -175q-154 -64 -317 -64q-165 0 -317 64q-148 63 -259 175q-113 112 -175 258q-42 103 -54 189q-4 28 48 36q51 8 56 -20q1 -1 1 -4q18 -90 46 -159q50 -124 152 -226q98 -98 226 -152q132 -56 276 -56q143 0 276 56q128 55 225 152l6 6 q10 10 25 6q12 -3 33 -22q36 -37 17 -58zM929 604l-66 -66l63 -63q21 -21 -7 -49q-17 -17 -32 -17q-10 0 -19 10l-62 61l-66 -66q-5 -5 -15 -5q-15 0 -31 16l-2 2q-18 15 -18 29q0 7 8 17l66 65l-66 66q-16 16 14 45q18 18 31 18q6 0 13 -5l65 -66l65 65q18 17 48 -13 q27 -27 11 -44zM1400 547q0 -118 -46 -228q-45 -105 -126 -186q-80 -80 -187 -126t-228 -46t-228 46t-187 126q-82 82 -125 186q-15 32 -15 40h-1q-9 27 43 44q50 16 60 -12q37 -99 97 -167h1v339v2q3 136 102 232q105 103 253 103q147 0 251 -103t104 -249 q0 -147 -104.5 -251t-250.5 -104q-58 0 -112 16q-28 11 -13 61q16 51 44 43l14 -3q14 -3 32.5 -6t30.5 -3q104 0 176 71.5t72 174.5q0 101 -72 171q-71 71 -175 71q-107 0 -178 -80q-64 -72 -64 -160v-413q110 -67 242 -67q96 0 185 36.5t156 103.5t103.5 155t36.5 183 q0 198 -141 339q-140 140 -339 140q-200 0 -340 -140q-53 -53 -77 -87l-2 -2q-8 -11 -13 -15.5t-21.5 -9.5t-38.5 3q-21 5 -36.5 16.5t-15.5 26.5v680q0 15 10.5 26.5t27.5 11.5h877q30 0 30 -55t-30 -55h-811v-483h1q40 42 102 84t108 61q109 46 231 46q121 0 228 -46 t187 -126q81 -81 126 -186q46 -112 46 -229zM1369 1128q9 -8 9 -18t-5.5 -18t-16.5 -21q-26 -26 -39 -26q-9 0 -16 7q-106 91 -207 133q-128 56 -276 56q-133 0 -262 -49q-27 -10 -45 37q-9 25 -8 38q3 16 16 20q130 57 299 57q164 0 316 -64q137 -58 235 -152z" />
-<glyph unicode="&#xf270;" horiz-adv-x="1792" d="M1551 60q15 6 26 3t11 -17.5t-15 -33.5q-13 -16 -44 -43.5t-95.5 -68t-141 -74t-188 -58t-229.5 -24.5q-119 0 -238 31t-209 76.5t-172.5 104t-132.5 105t-84 87.5q-8 9 -10 16.5t1 12t8 7t11.5 2t11.5 -4.5q192 -117 300 -166q389 -176 799 -90q190 40 391 135z M1758 175q11 -16 2.5 -69.5t-28.5 -102.5q-34 -83 -85 -124q-17 -14 -26 -9t0 24q21 45 44.5 121.5t6.5 98.5q-5 7 -15.5 11.5t-27 6t-29.5 2.5t-35 0t-31.5 -2t-31 -3t-22.5 -2q-6 -1 -13 -1.5t-11 -1t-8.5 -1t-7 -0.5h-5.5h-4.5t-3 0.5t-2 1.5l-1.5 3q-6 16 47 40t103 30 q46 7 108 1t76 -24zM1364 618q0 -31 13.5 -64t32 -58t37.5 -46t33 -32l13 -11l-227 -224q-40 37 -79 75.5t-58 58.5l-19 20q-11 11 -25 33q-38 -59 -97.5 -102.5t-127.5 -63.5t-140 -23t-137.5 21t-117.5 65.5t-83 113t-31 162.5q0 84 28 154t72 116.5t106.5 83t122.5 57 t130 34.5t119.5 18.5t99.5 6.5v127q0 65 -21 97q-34 53 -121 53q-6 0 -16.5 -1t-40.5 -12t-56 -29.5t-56 -59.5t-48 -96l-294 27q0 60 22 119t67 113t108 95t151.5 65.5t190.5 24.5q100 0 181 -25t129.5 -61.5t81 -83t45 -86t12.5 -73.5v-589zM692 597q0 -86 70 -133 q66 -44 139 -22q84 25 114 123q14 45 14 101v162q-59 -2 -111 -12t-106.5 -33.5t-87 -71t-32.5 -114.5z" />
-<glyph unicode="&#xf271;" horiz-adv-x="1792" d="M1536 1280q52 0 90 -38t38 -90v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128zM1152 1376v-288q0 -14 9 -23t23 -9 h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 1376v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM1536 -128v1024h-1408v-1024h1408zM896 448h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224 v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224z" />
-<glyph unicode="&#xf272;" horiz-adv-x="1792" d="M1152 416v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23 t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47 t47 -113v-96h128q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf273;" horiz-adv-x="1792" d="M1111 151l-46 -46q-9 -9 -22 -9t-23 9l-188 189l-188 -189q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22t9 23l189 188l-189 188q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l188 -188l188 188q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23l-188 -188l188 -188q9 -10 9 -23t-9 -22z M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf274;" horiz-adv-x="1792" d="M1303 572l-512 -512q-10 -9 -23 -9t-23 9l-288 288q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l220 -220l444 444q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23 t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47 t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
-<glyph unicode="&#xf275;" horiz-adv-x="1792" d="M448 1536q26 0 45 -19t19 -45v-891l536 429q17 14 40 14q26 0 45 -19t19 -45v-379l536 429q17 14 40 14q26 0 45 -19t19 -45v-1152q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h384z" />
-<glyph unicode="&#xf276;" horiz-adv-x="1024" d="M512 448q66 0 128 15v-655q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v655q61 -15 128 -15zM512 1536q212 0 362 -150t150 -362t-150 -362t-362 -150t-362 150t-150 362t150 362t362 150zM512 1312q14 0 23 9t9 23t-9 23t-23 9q-146 0 -249 -103t-103 -249 q0 -14 9 -23t23 -9t23 9t9 23q0 119 84.5 203.5t203.5 84.5z" />
-<glyph unicode="&#xf277;" horiz-adv-x="1792" d="M1745 1239q10 -10 10 -23t-10 -23l-141 -141q-28 -28 -68 -28h-1344q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h576v64q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-64h512q40 0 68 -28zM768 320h256v-512q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v512zM1600 768 q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-1344q-40 0 -68 28l-141 141q-10 10 -10 23t10 23l141 141q28 28 68 28h512v192h256v-192h576z" />
-<glyph unicode="&#xf278;" horiz-adv-x="2048" d="M2020 1525q28 -20 28 -53v-1408q0 -20 -11 -36t-29 -23l-640 -256q-24 -11 -48 0l-616 246l-616 -246q-10 -5 -24 -5q-19 0 -36 11q-28 20 -28 53v1408q0 20 11 36t29 23l640 256q24 11 48 0l616 -246l616 246q32 13 60 -6zM736 1390v-1270l576 -230v1270zM128 1173 v-1270l544 217v1270zM1920 107v1270l-544 -217v-1270z" />
-<glyph unicode="&#xf279;" horiz-adv-x="1792" d="M512 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472q0 20 17 28l480 256q7 4 15 4zM1760 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472 q0 20 17 28l480 256q7 4 15 4zM640 1536q8 0 14 -3l512 -256q18 -10 18 -29v-1472q0 -13 -9.5 -22.5t-22.5 -9.5q-8 0 -14 3l-512 256q-18 10 -18 29v1472q0 13 9.5 22.5t22.5 9.5z" />
-<glyph unicode="&#xf27a;" horiz-adv-x="1792" d="M640 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 640q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-110 0 -211 18q-173 -173 -435 -229q-52 -10 -86 -13q-12 -1 -22 6t-13 18q-4 15 20 37q5 5 23.5 21.5t25.5 23.5t23.5 25.5t24 31.5t20.5 37 t20 48t14.5 57.5t12.5 72.5q-146 90 -229.5 216.5t-83.5 269.5q0 174 120 321.5t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
-<glyph unicode="&#xf27b;" horiz-adv-x="1792" d="M640 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 -53 -37.5 -90.5t-90.5 -37.5 t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5 t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51 t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 130 71 248.5t191 204.5t286 136.5t348 50.5t348 -50.5t286 -136.5t191 -204.5t71 -248.5z" />
-<glyph unicode="&#xf27c;" horiz-adv-x="1024" d="M512 345l512 295v-591l-512 -296v592zM0 640v-591l512 296zM512 1527v-591l-512 -296v591zM512 936l512 295v-591z" />
-<glyph unicode="&#xf27d;" horiz-adv-x="1792" d="M1709 1018q-10 -236 -332 -651q-333 -431 -562 -431q-142 0 -240 263q-44 160 -132 482q-72 262 -157 262q-18 0 -127 -76l-77 98q24 21 108 96.5t130 115.5q156 138 241 146q95 9 153 -55.5t81 -203.5q44 -287 66 -373q55 -249 120 -249q51 0 154 161q101 161 109 246 q13 139 -109 139q-57 0 -121 -26q120 393 459 382q251 -8 236 -326z" />
-<glyph unicode="&#xf27e;" d="M0 1408h1536v-1536h-1536v1536zM1085 293l-221 631l221 297h-634l221 -297l-221 -631l317 -304z" />
-<glyph unicode="&#xf280;" d="M0 1408h1536v-1536h-1536v1536zM908 1088l-12 -33l75 -83l-31 -114l25 -25l107 57l107 -57l25 25l-31 114l75 83l-12 33h-95l-53 96h-32l-53 -96h-95zM641 925q32 0 44.5 -16t11.5 -63l174 21q0 55 -17.5 92.5t-50.5 56t-69 25.5t-85 7q-133 0 -199 -57.5t-66 -182.5v-72 h-96v-128h76q20 0 20 -8v-382q0 -14 -5 -20t-18 -7l-73 -7v-88h448v86l-149 14q-6 1 -8.5 1.5t-3.5 2.5t-0.5 4t1 7t0.5 10v387h191l38 128h-231q-6 0 -2 6t4 9v80q0 27 1.5 40.5t7.5 28t19.5 20t36.5 5.5zM1248 96v86l-54 9q-7 1 -9.5 2.5t-2.5 3t1 7.5t1 12v520h-275 l-23 -101l83 -22q23 -7 23 -27v-370q0 -14 -6 -18.5t-20 -6.5l-70 -9v-86h352z" />
-<glyph unicode="&#xf281;" horiz-adv-x="1792" d="M1792 690q0 -58 -29.5 -105.5t-79.5 -72.5q12 -46 12 -96q0 -155 -106.5 -287t-290.5 -208.5t-400 -76.5t-399.5 76.5t-290 208.5t-106.5 287q0 47 11 94q-51 25 -82 73.5t-31 106.5q0 82 58 140.5t141 58.5q85 0 145 -63q218 152 515 162l116 521q3 13 15 21t26 5 l369 -81q18 37 54 59.5t79 22.5q62 0 106 -43.5t44 -105.5t-44 -106t-106 -44t-105.5 43.5t-43.5 105.5l-334 74l-104 -472q300 -9 519 -160q58 61 143 61q83 0 141 -58.5t58 -140.5zM418 491q0 -62 43.5 -106t105.5 -44t106 44t44 106t-44 105.5t-106 43.5q-61 0 -105 -44 t-44 -105zM1228 136q11 11 11 26t-11 26q-10 10 -25 10t-26 -10q-41 -42 -121 -62t-160 -20t-160 20t-121 62q-11 10 -26 10t-25 -10q-11 -10 -11 -25.5t11 -26.5q43 -43 118.5 -68t122.5 -29.5t91 -4.5t91 4.5t122.5 29.5t118.5 68zM1225 341q62 0 105.5 44t43.5 106 q0 61 -44 105t-105 44q-62 0 -106 -43.5t-44 -105.5t44 -106t106 -44z" />
-<glyph unicode="&#xf282;" horiz-adv-x="1792" d="M69 741h1q16 126 58.5 241.5t115 217t167.5 176t223.5 117.5t276.5 43q231 0 414 -105.5t294 -303.5q104 -187 104 -442v-188h-1125q1 -111 53.5 -192.5t136.5 -122.5t189.5 -57t213 -3t208 46.5t173.5 84.5v-377q-92 -55 -229.5 -92t-312.5 -38t-316 53 q-189 73 -311.5 249t-124.5 372q-3 242 111 412t325 268q-48 -60 -78 -125.5t-46 -159.5h635q8 77 -8 140t-47 101.5t-70.5 66.5t-80.5 41t-75 20.5t-56 8.5l-22 1q-135 -5 -259.5 -44.5t-223.5 -104.5t-176 -140.5t-138 -163.5z" />
-<glyph unicode="&#xf283;" horiz-adv-x="2304" d="M0 32v608h2304v-608q0 -66 -47 -113t-113 -47h-1984q-66 0 -113 47t-47 113zM640 256v-128h384v128h-384zM256 256v-128h256v128h-256zM2144 1408q66 0 113 -47t47 -113v-224h-2304v224q0 66 47 113t113 47h1984z" />
-<glyph unicode="&#xf284;" horiz-adv-x="1792" d="M1549 857q55 0 85.5 -28.5t30.5 -83.5t-34 -82t-91 -27h-136v-177h-25v398h170zM1710 267l-4 -11l-5 -10q-113 -230 -330.5 -366t-474.5 -136q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71q244 0 454.5 -124t329.5 -338l2 -4l8 -16 q-30 -15 -136.5 -68.5t-163.5 -84.5q-6 -3 -479 -268q384 -183 799 -366zM896 -234q250 0 462.5 132.5t322.5 357.5l-287 129q-72 -140 -206 -222t-292 -82q-151 0 -280 75t-204 204t-75 280t75 280t204 204t280 75t280 -73.5t204 -204.5l280 143q-116 208 -321 329 t-443 121q-119 0 -232.5 -31.5t-209 -87.5t-176.5 -137t-137 -176.5t-87.5 -209t-31.5 -232.5t31.5 -232.5t87.5 -209t137 -176.5t176.5 -137t209 -87.5t232.5 -31.5z" />
-<glyph unicode="&#xf285;" horiz-adv-x="1792" d="M1427 827l-614 386l92 151h855zM405 562l-184 116v858l1183 -743zM1424 697l147 -95v-858l-532 335zM1387 718l-500 -802h-855l356 571z" />
-<glyph unicode="&#xf286;" horiz-adv-x="1792" d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96 q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 6 2.5 9.5t8.5 5t9.5 2t11.5 0t9 -0.5v391q-32 15 -32 50q0 23 16.5 39t38.5 16t38.5 -16t16.5 -39q0 -35 -32 -50v-17q45 10 83 10q21 0 59.5 -7.5t54.5 -7.5 q17 0 47 7.5t37 7.5q16 0 16 -16v-210q0 -15 -35 -21.5t-62 -6.5q-18 0 -54.5 7.5t-55.5 7.5q-40 0 -90 -12v-133q1 0 9 0.5t11.5 0t9.5 -2t8.5 -5t2.5 -9.5v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96 q16 0 16 -16z" />
-<glyph unicode="&#xf287;" horiz-adv-x="2304" d="M2288 731q16 -8 16 -27t-16 -27l-320 -192q-8 -5 -16 -5q-9 0 -16 4q-16 10 -16 28v128h-858q37 -58 83 -165q16 -37 24.5 -55t24 -49t27 -47t27 -34t31.5 -26t33 -8h96v96q0 14 9 23t23 9h320q14 0 23 -9t9 -23v-320q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v96h-96 q-32 0 -61 10t-51 23.5t-45 40.5t-37 46t-33.5 57t-28.5 57.5t-28 60.5q-23 53 -37 81.5t-36 65t-44.5 53.5t-46.5 17h-360q-22 -84 -91 -138t-157 -54q-106 0 -181 75t-75 181t75 181t181 75q88 0 157 -54t91 -138h104q24 0 46.5 17t44.5 53.5t36 65t37 81.5q19 41 28 60.5 t28.5 57.5t33.5 57t37 46t45 40.5t51 23.5t61 10h107q21 57 70 92.5t111 35.5q80 0 136 -56t56 -136t-56 -136t-136 -56q-62 0 -111 35.5t-70 92.5h-107q-17 0 -33 -8t-31.5 -26t-27 -34t-27 -47t-24 -49t-24.5 -55q-46 -107 -83 -165h1114v128q0 18 16 28t32 -1z" />
-<glyph unicode="&#xf288;" horiz-adv-x="1792" d="M1150 774q0 -56 -39.5 -95t-95.5 -39h-253v269h253q56 0 95.5 -39.5t39.5 -95.5zM1329 774q0 130 -91.5 222t-222.5 92h-433v-896h180v269h253q130 0 222 91.5t92 221.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348 t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
-<glyph unicode="&#xf289;" horiz-adv-x="2304" d="M1645 438q0 59 -34 106.5t-87 68.5q-7 -45 -23 -92q-7 -24 -27.5 -38t-44.5 -14q-12 0 -24 3q-31 10 -45 38.5t-4 58.5q23 71 23 143q0 123 -61 227.5t-166 165.5t-228 61q-134 0 -247 -73t-167 -194q108 -28 188 -106q22 -23 22 -55t-22 -54t-54 -22t-55 22 q-75 75 -180 75q-106 0 -181 -74.5t-75 -180.5t75 -180.5t181 -74.5h1046q79 0 134.5 55.5t55.5 133.5zM1798 438q0 -142 -100.5 -242t-242.5 -100h-1046q-169 0 -289 119.5t-120 288.5q0 153 100 267t249 136q62 184 221 298t354 114q235 0 408.5 -158.5t196.5 -389.5 q116 -25 192.5 -118.5t76.5 -214.5zM2048 438q0 -175 -97 -319q-23 -33 -64 -33q-24 0 -43 13q-26 17 -32 48.5t12 57.5q71 104 71 233t-71 233q-18 26 -12 57t32 49t57.5 11.5t49.5 -32.5q97 -142 97 -318zM2304 438q0 -244 -134 -443q-23 -34 -64 -34q-23 0 -42 13 q-26 18 -32.5 49t11.5 57q108 164 108 358q0 195 -108 357q-18 26 -11.5 57.5t32.5 48.5q26 18 57 12t49 -33q134 -198 134 -442z" />
-<glyph unicode="&#xf28a;" d="M1500 -13q0 -89 -63 -152.5t-153 -63.5t-153.5 63.5t-63.5 152.5q0 90 63.5 153.5t153.5 63.5t153 -63.5t63 -153.5zM1267 268q-115 -15 -192.5 -102.5t-77.5 -205.5q0 -74 33 -138q-146 -78 -379 -78q-109 0 -201 21t-153.5 54.5t-110.5 76.5t-76 85t-44.5 83 t-23.5 66.5t-6 39.5q0 19 4.5 42.5t18.5 56t36.5 58t64 43.5t94.5 18t94 -17.5t63 -41t35.5 -53t17.5 -49t4 -33.5q0 -34 -23 -81q28 -27 82 -42t93 -17l40 -1q115 0 190 51t75 133q0 26 -9 48.5t-31.5 44.5t-49.5 41t-74 44t-93.5 47.5t-119.5 56.5q-28 13 -43 20 q-116 55 -187 100t-122.5 102t-72 125.5t-20.5 162.5q0 78 20.5 150t66 137.5t112.5 114t166.5 77t221.5 28.5q120 0 220 -26t164.5 -67t109.5 -94t64 -105.5t19 -103.5q0 -46 -15 -82.5t-36.5 -58t-48.5 -36t-49 -19.5t-39 -5h-8h-32t-39 5t-44 14t-41 28t-37 46t-24 70.5 t-10 97.5q-15 16 -59 25.5t-81 10.5l-37 1q-68 0 -117.5 -31t-70.5 -70t-21 -76q0 -24 5 -43t24 -46t53 -51t97 -53.5t150 -58.5q76 -25 138.5 -53.5t109 -55.5t83 -59t60.5 -59.5t41 -62.5t26.5 -62t14.5 -63.5t6 -62t1 -62.5z" />
-<glyph unicode="&#xf28b;" d="M704 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1152 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103 t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf28c;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 t73 -273t198 -198t273 -73zM864 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192z" />
-<glyph unicode="&#xf28d;" d="M1088 352v576q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
-<glyph unicode="&#xf28e;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 t73 -273t198 -198t273 -73zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h576q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-576z" />
-<glyph unicode="&#xf290;" horiz-adv-x="1792" d="M1757 128l35 -313q3 -28 -16 -50q-19 -21 -48 -21h-1664q-29 0 -48 21q-19 22 -16 50l35 313h1722zM1664 967l86 -775h-1708l86 775q3 24 21 40.5t43 16.5h256v-128q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5v128h384v-128q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5v128h256q25 0 43 -16.5t21 -40.5zM1280 1152v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 159 112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
-<glyph unicode="&#xf291;" horiz-adv-x="2048" d="M1920 768q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5h-15l-115 -662q-8 -46 -44 -76t-82 -30h-1280q-46 0 -82 30t-44 76l-115 662h-15q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5h1792zM485 -32q26 2 43.5 22.5t15.5 46.5l-32 416q-2 26 -22.5 43.5 t-46.5 15.5t-43.5 -22.5t-15.5 -46.5l32 -416q2 -25 20.5 -42t43.5 -17h5zM896 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1280 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1632 27l32 416 q2 26 -15.5 46.5t-43.5 22.5t-46.5 -15.5t-22.5 -43.5l-32 -416q-2 -26 15.5 -46.5t43.5 -22.5h5q25 0 43.5 17t20.5 42zM476 1244l-93 -412h-132l101 441q19 88 89 143.5t160 55.5h167q0 26 19 45t45 19h384q26 0 45 -19t19 -45h167q90 0 160 -55.5t89 -143.5l101 -441 h-132l-93 412q-11 44 -45.5 72t-79.5 28h-167q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45h-167q-45 0 -79.5 -28t-45.5 -72z" />
-<glyph unicode="&#xf292;" horiz-adv-x="1792" d="M991 512l64 256h-254l-64 -256h254zM1759 1016l-56 -224q-7 -24 -31 -24h-327l-64 -256h311q15 0 25 -12q10 -14 6 -28l-56 -224q-5 -24 -31 -24h-327l-81 -328q-7 -24 -31 -24h-224q-16 0 -26 12q-9 12 -6 28l78 312h-254l-81 -328q-7 -24 -31 -24h-225q-15 0 -25 12 q-9 12 -6 28l78 312h-311q-15 0 -25 12q-9 12 -6 28l56 224q7 24 31 24h327l64 256h-311q-15 0 -25 12q-10 14 -6 28l56 224q5 24 31 24h327l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h254l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h311 q15 0 25 -12q9 -12 6 -28z" />
-<glyph unicode="&#xf293;" d="M841 483l148 -148l-149 -149zM840 1094l149 -149l-148 -148zM710 -130l464 464l-306 306l306 306l-464 464v-611l-255 255l-93 -93l320 -321l-320 -321l93 -93l255 255v-611zM1429 640q0 -209 -32 -365.5t-87.5 -257t-140.5 -162.5t-181.5 -86.5t-219.5 -24.5 t-219.5 24.5t-181.5 86.5t-140.5 162.5t-87.5 257t-32 365.5t32 365.5t87.5 257t140.5 162.5t181.5 86.5t219.5 24.5t219.5 -24.5t181.5 -86.5t140.5 -162.5t87.5 -257t32 -365.5z" />
-<glyph unicode="&#xf294;" horiz-adv-x="1024" d="M596 113l173 172l-173 172v-344zM596 823l173 172l-173 172v-344zM628 640l356 -356l-539 -540v711l-297 -296l-108 108l372 373l-372 373l108 108l297 -296v711l539 -540z" />
-<glyph unicode="&#xf295;" d="M1280 256q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM512 1024q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5 t112.5 -271.5zM1440 1344q0 -20 -13 -38l-1056 -1408q-19 -26 -51 -26h-160q-26 0 -45 19t-19 45q0 20 13 38l1056 1408q19 26 51 26h160q26 0 45 -19t19 -45zM768 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
-<glyph unicode="&#xf296;" horiz-adv-x="1792" d="M104 830l792 -1015l-868 630q-18 13 -25 34.5t0 42.5l101 308v0zM566 830h660l-330 -1015v0zM368 1442l198 -612h-462l198 612q8 23 33 23t33 -23zM1688 830l101 -308q7 -21 0 -42.5t-25 -34.5l-868 -630l792 1015v0zM1688 830h-462l198 612q8 23 33 23t33 -23z" />
-<glyph unicode="&#xf297;" horiz-adv-x="1792" d="M384 704h160v224h-160v-224zM1221 372v92q-104 -36 -243 -38q-135 -1 -259.5 46.5t-220.5 122.5l1 -96q88 -80 212 -128.5t272 -47.5q129 0 238 49zM640 704h640v224h-640v-224zM1792 736q0 -187 -99 -352q89 -102 89 -229q0 -157 -129.5 -268t-313.5 -111 q-122 0 -225 52.5t-161 140.5q-19 -1 -57 -1t-57 1q-58 -88 -161 -140.5t-225 -52.5q-184 0 -313.5 111t-129.5 268q0 127 89 229q-99 165 -99 352q0 209 120 385.5t326.5 279.5t449.5 103t449.5 -103t326.5 -279.5t120 -385.5z" />
-<glyph unicode="&#xf298;" d="M515 625v-128h-252v128h252zM515 880v-127h-252v127h252zM1273 369v-128h-341v128h341zM1273 625v-128h-672v128h672zM1273 880v-127h-672v127h672zM1408 20v1240q0 8 -6 14t-14 6h-32l-378 -256l-210 171l-210 -171l-378 256h-32q-8 0 -14 -6t-6 -14v-1240q0 -8 6 -14 t14 -6h1240q8 0 14 6t6 14zM553 1130l185 150h-406zM983 1130l221 150h-406zM1536 1260v-1240q0 -62 -43 -105t-105 -43h-1240q-62 0 -105 43t-43 105v1240q0 62 43 105t105 43h1240q62 0 105 -43t43 -105z" />
-<glyph unicode="&#xf299;" horiz-adv-x="1792" d="M896 720q-104 196 -160 278q-139 202 -347 318q-34 19 -70 36q-89 40 -94 32t34 -38l39 -31q62 -43 112.5 -93.5t94.5 -116.5t70.5 -113t70.5 -131q9 -17 13 -25q44 -84 84 -153t98 -154t115.5 -150t131 -123.5t148.5 -90.5q153 -66 154 -60q1 3 -49 37q-53 36 -81 57 q-77 58 -179 211t-185 310zM549 177q-76 60 -132.5 125t-98 143.5t-71 154.5t-58.5 186t-52 209t-60.5 252t-76.5 289q273 0 497.5 -36t379 -92t271 -144.5t185.5 -172.5t110 -198.5t56 -199.5t12.5 -198.5t-9.5 -173t-20 -143.5t-13 -107l323 -327h-104l-281 285 q-22 -2 -91.5 -14t-121.5 -19t-138 -6t-160.5 17t-167.5 59t-179 111z" />
-<glyph unicode="&#xf29a;" horiz-adv-x="1792" d="M1374 879q-6 26 -28.5 39.5t-48.5 7.5q-261 -62 -401 -62t-401 62q-26 6 -48.5 -7.5t-28.5 -39.5t7.5 -48.5t39.5 -28.5q194 -46 303 -58q-2 -158 -15.5 -269t-26.5 -155.5t-41 -115.5l-9 -21q-10 -25 1 -49t36 -34q9 -4 23 -4q44 0 60 41l8 20q54 139 71 259h42 q17 -120 71 -259l8 -20q16 -41 60 -41q14 0 23 4q25 10 36 34t1 49l-9 21q-28 71 -41 115.5t-26.5 155.5t-15.5 269q109 12 303 58q26 6 39.5 28.5t7.5 48.5zM1024 1024q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1600 640q0 -143 -55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5zM896 1408q-156 0 -298 -61t-245 -164t-164 -245t-61 -298t61 -298 t164 -245t245 -164t298 -61t298 61t245 164t164 245t61 298t-61 298t-164 245t-245 164t-298 61zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
-<glyph unicode="&#xf29b;" d="M1438 723q34 -35 29 -82l-44 -551q-4 -42 -34.5 -70t-71.5 -28q-6 0 -9 1q-44 3 -72.5 36.5t-25.5 77.5l35 429l-143 -8q55 -113 55 -240q0 -216 -148 -372l-137 137q91 101 91 235q0 145 -102.5 248t-247.5 103q-134 0 -236 -92l-137 138q120 114 284 141l264 300 l-149 87l-181 -161q-33 -30 -77 -27.5t-73 35.5t-26.5 77t34.5 73l239 213q26 23 60 26.5t64 -14.5l488 -283q36 -21 48 -68q17 -67 -26 -117l-205 -232l371 20q49 3 83 -32zM1240 1180q-74 0 -126 52t-52 126t52 126t126 52t126.5 -52t52.5 -126t-52.5 -126t-126.5 -52z M613 -62q106 0 196 61l139 -139q-146 -116 -335 -116q-148 0 -273.5 73t-198.5 198t-73 273q0 188 116 336l139 -139q-60 -88 -60 -197q0 -145 102.5 -247.5t247.5 -102.5z" />
-<glyph unicode="&#xf29c;" d="M880 336v-160q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h160q14 0 23 -9t9 -23zM1136 832q0 -50 -15 -90t-45.5 -69t-52 -44t-59.5 -36q-32 -18 -46.5 -28t-26 -24t-11.5 -29v-32q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v68q0 35 10.5 64.5 t24 47.5t39 35.5t41 25.5t44.5 21q53 25 75 43t22 49q0 42 -43.5 71.5t-95.5 29.5q-56 0 -95 -27q-29 -20 -80 -83q-9 -12 -25 -12q-11 0 -19 6l-108 82q-10 7 -12 20t5 23q122 192 349 192q129 0 238.5 -89.5t109.5 -214.5zM768 1280q-130 0 -248.5 -51t-204 -136.5 t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5 t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf29d;" horiz-adv-x="1408" d="M366 1225q-64 0 -110 45.5t-46 110.5q0 64 46 109.5t110 45.5t109.5 -45.5t45.5 -109.5q0 -65 -45.5 -110.5t-109.5 -45.5zM917 583q0 -50 -30 -67.5t-63.5 -6.5t-47.5 34l-367 438q-7 12 -14 15.5t-11 1.5l-3 -3q-7 -8 4 -21l122 -139l1 -354l-161 -457 q-67 -192 -92 -234q-16 -26 -28 -32q-50 -26 -103 -1q-29 13 -41.5 43t-9.5 57q2 17 197 618l5 416l-85 -164l35 -222q4 -24 -1 -42t-14 -27.5t-19 -16t-17 -7.5l-7 -2q-19 -3 -34.5 3t-24 16t-14 22t-7.5 19.5t-2 9.5l-46 299l211 381q23 34 113 34q75 0 107 -40l424 -521 q7 -5 14 -17l3 -3l-1 -1q7 -13 7 -29zM514 433q43 -113 88.5 -225t69.5 -168l24 -55q36 -93 42 -125q11 -70 -36 -97q-35 -22 -66 -16t-51 22t-29 35h-1q-6 16 -8 25l-124 351zM1338 -159q31 -49 31 -57q0 -5 -3 -7q-9 -5 -14.5 0.5t-15.5 26t-16 30.5q-114 172 -423 661 q3 -1 7 1t7 4l3 2q11 9 11 17z" />
-<glyph unicode="&#xf29e;" horiz-adv-x="2304" d="M504 542h171l-1 265zM1530 641q0 87 -50.5 140t-146.5 53h-54v-388h52q91 0 145 57t54 138zM956 1018l1 -756q0 -14 -9.5 -24t-23.5 -10h-216q-14 0 -23.5 10t-9.5 24v62h-291l-55 -81q-10 -15 -28 -15h-267q-21 0 -30.5 18t3.5 35l556 757q9 14 27 14h332q14 0 24 -10 t10 -24zM1783 641q0 -193 -125.5 -303t-324.5 -110h-270q-14 0 -24 10t-10 24v756q0 14 10 24t24 10h268q200 0 326 -109t126 -302zM1939 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5 t-7.5 60t-20 91.5t-41 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2123 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-45 -108t-74 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5 h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2304 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66 104.5t41 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96 t9.5 -70.5z" />
-<glyph unicode="&#xf2a0;" horiz-adv-x="1408" d="M617 -153q0 11 -13 58t-31 107t-20 69q-1 4 -5 26.5t-8.5 36t-13.5 21.5q-15 14 -51 14q-23 0 -70 -5.5t-71 -5.5q-34 0 -47 11q-6 5 -11 15.5t-7.5 20t-6.5 24t-5 18.5q-37 128 -37 255t37 255q1 4 5 18.5t6.5 24t7.5 20t11 15.5q13 11 47 11q24 0 71 -5.5t70 -5.5 q36 0 51 14q9 8 13.5 21.5t8.5 36t5 26.5q2 9 20 69t31 107t13 58q0 22 -43.5 52.5t-75.5 42.5q-20 8 -45 8q-34 0 -98 -18q-57 -17 -96.5 -40.5t-71 -66t-46 -70t-45.5 -94.5q-6 -12 -9 -19q-49 -107 -68 -216t-19 -244t19 -244t68 -216q56 -122 83 -161q63 -91 179 -127 l6 -2q64 -18 98 -18q25 0 45 8q32 12 75.5 42.5t43.5 52.5zM776 760q-26 0 -45 19t-19 45.5t19 45.5q37 37 37 90q0 52 -37 91q-19 19 -19 45t19 45t45 19t45 -19q75 -75 75 -181t-75 -181q-21 -19 -45 -19zM957 579q-27 0 -45 19q-19 19 -19 45t19 45q112 114 112 272 t-112 272q-19 19 -19 45t19 45t45 19t45 -19q150 -150 150 -362t-150 -362q-18 -19 -45 -19zM1138 398q-27 0 -45 19q-19 19 -19 45t19 45q90 91 138.5 208t48.5 245t-48.5 245t-138.5 208q-19 19 -19 45t19 45t45 19t45 -19q109 -109 167 -249t58 -294t-58 -294t-167 -249 q-18 -19 -45 -19z" />
-<glyph unicode="&#xf2a1;" horiz-adv-x="2176" d="M192 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 352 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 864 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 1376q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 192q0 -80 -56 -136 t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 1216q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 192q0 -80 -56 -136t-136 -56t-136 56 t-56 136t56 136t136 56t136 -56t56 -136zM1664 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136 t56 136t136 56t136 -56t56 -136zM2176 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z" />
-<glyph unicode="&#xf2a2;" horiz-adv-x="1792" d="M128 -192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM320 0q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM365 365l256 -256l-90 -90l-256 256zM704 384q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45z M1411 704q0 -59 -11.5 -108.5t-37.5 -93.5t-44 -67.5t-53 -64.5q-31 -35 -45.5 -54t-33.5 -50t-26.5 -64t-7.5 -74q0 -159 -112.5 -271.5t-271.5 -112.5q-26 0 -45 19t-19 45t19 45t45 19q106 0 181 75t75 181q0 57 11.5 105.5t37 91t43.5 66.5t52 63q40 46 59.5 72 t37.5 74.5t18 103.5q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM896 576q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45 t45 19t45 -19t19 -45zM1184 704q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 93 -65.5 158.5t-158.5 65.5q-92 0 -158 -65.5t-66 -158.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 146 103 249t249 103t249 -103t103 -249zM1578 993q10 -25 -1 -49t-36 -34q-9 -4 -23 -4 q-19 0 -35.5 11t-23.5 30q-68 178 -224 295q-21 16 -25 42t12 47q17 21 43 25t47 -12q183 -137 266 -351zM1788 1074q9 -25 -1.5 -49t-35.5 -34q-11 -4 -23 -4q-44 0 -60 41q-92 238 -297 393q-22 16 -25.5 42t12.5 47q16 22 42 25.5t47 -12.5q235 -175 341 -449z" />
-<glyph unicode="&#xf2a3;" horiz-adv-x="2304" d="M1032 576q-59 2 -84 55q-17 34 -48 53.5t-68 19.5q-53 0 -90.5 -37.5t-37.5 -90.5q0 -56 36 -89l10 -8q34 -31 82 -31q37 0 68 19.5t48 53.5q25 53 84 55zM1600 704q0 56 -36 89l-10 8q-34 31 -82 31q-37 0 -68 -19.5t-48 -53.5q-25 -53 -84 -55q59 -2 84 -55 q17 -34 48 -53.5t68 -19.5q53 0 90.5 37.5t37.5 90.5zM1174 925q-17 -35 -55 -48t-73 4q-62 31 -134 31q-51 0 -99 -17q3 0 9.5 0.5t9.5 0.5q92 0 170.5 -50t118.5 -133q17 -36 3.5 -73.5t-49.5 -54.5q-18 -9 -39 -9q21 0 39 -9q36 -17 49.5 -54.5t-3.5 -73.5 q-40 -83 -118.5 -133t-170.5 -50h-6q-16 2 -44 4l-290 27l-239 -120q-14 -7 -29 -7q-40 0 -57 35l-160 320q-11 23 -4 47.5t29 37.5l209 119l148 267q17 155 91.5 291.5t195.5 236.5q31 25 70.5 21.5t64.5 -34.5t21.5 -70t-34.5 -65q-70 -59 -117 -128q123 84 267 101 q40 5 71.5 -19t35.5 -64q5 -40 -19 -71.5t-64 -35.5q-84 -10 -159 -55q46 10 99 10q115 0 218 -50q36 -18 49 -55.5t-5 -73.5zM2137 1085l160 -320q11 -23 4 -47.5t-29 -37.5l-209 -119l-148 -267q-17 -155 -91.5 -291.5t-195.5 -236.5q-26 -22 -61 -22q-45 0 -74 35 q-25 31 -21.5 70t34.5 65q70 59 117 128q-123 -84 -267 -101q-4 -1 -12 -1q-36 0 -63.5 24t-31.5 60q-5 40 19 71.5t64 35.5q84 10 159 55q-46 -10 -99 -10q-115 0 -218 50q-36 18 -49 55.5t5 73.5q17 35 55 48t73 -4q62 -31 134 -31q51 0 99 17q-3 0 -9.5 -0.5t-9.5 -0.5 q-92 0 -170.5 50t-118.5 133q-17 36 -3.5 73.5t49.5 54.5q18 9 39 9q-21 0 -39 9q-36 17 -49.5 54.5t3.5 73.5q40 83 118.5 133t170.5 50h6h1q14 -2 42 -4l291 -27l239 120q14 7 29 7q40 0 57 -35z" />
-<glyph unicode="&#xf2a4;" horiz-adv-x="1792" d="M1056 704q0 -26 19 -45t45 -19t45 19t19 45q0 146 -103 249t-249 103t-249 -103t-103 -249q0 -26 19 -45t45 -19t45 19t19 45q0 93 66 158.5t158 65.5t158 -65.5t66 -158.5zM835 1280q-117 0 -223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5q0 -26 19 -45t45 -19t45 19 t19 45q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -55 -18 -103.5t-37.5 -74.5t-59.5 -72q-34 -39 -52 -63t-43.5 -66.5t-37 -91t-11.5 -105.5q0 -106 -75 -181t-181 -75q-26 0 -45 -19t-19 -45t19 -45t45 -19q159 0 271.5 112.5t112.5 271.5q0 41 7.5 74 t26.5 64t33.5 50t45.5 54q35 41 53 64.5t44 67.5t37.5 93.5t11.5 108.5q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5zM591 561l226 -226l-579 -579q-12 -12 -29 -12t-29 12l-168 168q-12 12 -12 29t12 29zM1612 1524l168 -168q12 -12 12 -29t-12 -30l-233 -233 l-26 -25l-71 -71q-66 153 -195 258l91 91l207 207q13 12 30 12t29 -12z" />
-<glyph unicode="&#xf2a5;" d="M866 1021q0 -27 -13 -94q-11 -50 -31.5 -150t-30.5 -150q-2 -11 -4.5 -12.5t-13.5 -2.5q-20 -2 -31 -2q-58 0 -84 49.5t-26 113.5q0 88 35 174t103 124q28 14 51 14q28 0 36.5 -16.5t8.5 -47.5zM1352 597q0 14 -39 75.5t-52 66.5q-21 8 -34 8q-91 0 -226 -77l-2 2 q3 22 27.5 135t24.5 178q0 233 -242 233q-24 0 -68 -6q-94 -17 -168.5 -89.5t-111.5 -166.5t-37 -189q0 -146 80.5 -225t227.5 -79q25 0 25 -3t-1 -5q-4 -34 -26 -117q-14 -52 -51.5 -101t-82.5 -49q-42 0 -42 47q0 24 10.5 47.5t25 39.5t29.5 28.5t26 20t11 8.5q0 3 -7 10 q-24 22 -58.5 36.5t-65.5 14.5q-35 0 -63.5 -34t-41 -75t-12.5 -75q0 -88 51.5 -142t138.5 -54q82 0 155 53t117.5 126t65.5 153q6 22 15.5 66.5t14.5 66.5q3 12 14 18q118 60 227 60q48 0 127 -18q1 -1 4 -1q5 0 9.5 4.5t4.5 8.5zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf2a6;" horiz-adv-x="1535" d="M744 1231q0 24 -2 38.5t-8.5 30t-21 23t-37.5 7.5q-39 0 -78 -23q-105 -58 -159 -190.5t-54 -269.5q0 -44 8.5 -85.5t26.5 -80.5t52.5 -62.5t81.5 -23.5q4 0 18 -0.5t20 0t16 3t15 8.5t7 16q16 77 48 231.5t48 231.5q19 91 19 146zM1498 575q0 -7 -7.5 -13.5t-15.5 -6.5 l-6 1q-22 3 -62 11t-72 12.5t-63 4.5q-167 0 -351 -93q-15 -8 -21 -27q-10 -36 -24.5 -105.5t-22.5 -100.5q-23 -91 -70 -179.5t-112.5 -164.5t-154.5 -123t-185 -47q-135 0 -214.5 83.5t-79.5 219.5q0 53 19.5 117t63 116.5t97.5 52.5q38 0 120 -33.5t83 -61.5 q0 -1 -16.5 -12.5t-39.5 -31t-46 -44.5t-39 -61t-16 -74q0 -33 16.5 -53t48.5 -20q45 0 85 31.5t66.5 78t48 105.5t32.5 107t16 90v9q0 2 -3.5 3.5t-8.5 1.5h-10t-10 -0.5t-6 -0.5q-227 0 -352 122.5t-125 348.5q0 108 34.5 221t96 210t156 167.5t204.5 89.5q52 9 106 9 q374 0 374 -360q0 -98 -38 -273t-43 -211l3 -3q101 57 182.5 88t167.5 31q22 0 53 -13q19 -7 80 -102.5t61 -116.5z" />
-<glyph unicode="&#xf2a7;" horiz-adv-x="1664" d="M831 863q32 0 59 -18l222 -148q61 -40 110 -97l146 -170q40 -46 29 -106l-72 -413q-6 -32 -29.5 -53.5t-55.5 -25.5l-527 -56l-352 -32h-9q-39 0 -67.5 28t-28.5 68q0 37 27 64t65 32l260 32h-448q-41 0 -69.5 30t-26.5 71q2 39 32 65t69 26l442 1l-521 64q-41 5 -66 37 t-19 73q6 35 34.5 57.5t65.5 22.5h10l481 -60l-351 94q-38 10 -62 41.5t-18 68.5q6 36 33 58.5t62 22.5q6 0 20 -2l448 -96l217 -37q1 0 3 -0.5t3 -0.5q23 0 30.5 23t-12.5 36l-186 125q-35 23 -42 63.5t18 73.5q27 38 76 38zM761 661l186 -125l-218 37l-5 2l-36 38 l-238 262q-1 1 -2.5 3.5t-2.5 3.5q-24 31 -18.5 70t37.5 64q31 23 68 17.5t64 -33.5l142 -147l-4 -4t-5 -4q-32 -45 -23 -99t55 -85zM1648 1115l15 -266q4 -73 -11 -147l-48 -219q-12 -59 -67 -87l-106 -54q2 62 -39 109l-146 170q-53 61 -117 103l-222 148q-34 23 -76 23 q-51 0 -88 -37l-235 312q-25 33 -18 73.5t41 63.5q33 22 71.5 14t62.5 -40l266 -352l-262 455q-21 35 -10.5 75t47.5 59q35 18 72.5 6t57.5 -46l241 -420l-136 337q-15 35 -4.5 74t44.5 56q37 19 76 6t56 -51l193 -415l101 -196q8 -15 23 -17.5t27 7.5t11 26l-12 224 q-2 41 26 71t69 31q39 0 67 -28.5t30 -67.5z" />
-<glyph unicode="&#xf2a8;" horiz-adv-x="1792" d="M335 180q-2 0 -6 2q-86 57 -168.5 145t-139.5 180q-21 30 -21 69q0 9 2 19t4 18t7 18t8.5 16t10.5 17t10 15t12 15.5t11 14.5q184 251 452 365q-110 198 -110 211q0 19 17 29q116 64 128 64q18 0 28 -16l124 -229q92 19 192 19q266 0 497.5 -137.5t378.5 -369.5 q20 -31 20 -69t-20 -69q-91 -142 -218.5 -253.5t-278.5 -175.5q110 -198 110 -211q0 -20 -17 -29q-116 -64 -127 -64q-19 0 -29 16l-124 229l-64 119l-444 820l7 7q-58 -24 -99 -47q3 -5 127 -234t243 -449t119 -223q0 -7 -9 -9q-13 -3 -72 -3q-57 0 -60 7l-456 841 q-39 -28 -82 -68q24 -43 214 -393.5t190 -354.5q0 -10 -11 -10q-14 0 -82.5 22t-72.5 28l-106 197l-224 413q-44 -53 -78 -106q2 -3 18 -25t23 -34l176 -327q0 -10 -10 -10zM1165 282l49 -91q273 111 450 385q-180 277 -459 389q67 -64 103 -148.5t36 -176.5 q0 -106 -47 -200.5t-132 -157.5zM848 896q0 -20 14 -34t34 -14q86 0 147 -61t61 -147q0 -20 14 -34t34 -14t34 14t14 34q0 126 -89 215t-215 89q-20 0 -34 -14t-14 -34zM1214 961l-9 4l7 -7z" />
-<glyph unicode="&#xf2a9;" horiz-adv-x="1280" d="M1050 430q0 -215 -147 -374q-148 -161 -378 -161q-232 0 -378 161q-147 159 -147 374q0 147 68 270.5t189 196.5t268 73q96 0 182 -31q-32 -62 -39 -126q-66 28 -143 28q-167 0 -280.5 -123t-113.5 -291q0 -170 112.5 -288.5t281.5 -118.5t281 118.5t112 288.5 q0 89 -32 166q66 13 123 49q41 -98 41 -212zM846 619q0 -192 -79.5 -345t-238.5 -253l-14 -1q-29 0 -62 5q83 32 146.5 102.5t99.5 154.5t58.5 189t30 192.5t7.5 178.5q0 69 -3 103q55 -160 55 -326zM791 947v-2q-73 214 -206 440q88 -59 142.5 -186.5t63.5 -251.5z M1035 744q-83 0 -160 75q218 120 290 247q19 37 21 56q-42 -94 -139.5 -166.5t-204.5 -97.5q-35 54 -35 113q0 37 17 79t43 68q46 44 157 74q59 16 106 58.5t74 100.5q74 -105 74 -253q0 -109 -24 -170q-32 -77 -88.5 -130.5t-130.5 -53.5z" />
-<glyph unicode="&#xf2aa;" d="M1050 495q0 78 -28 147q-41 -25 -85 -34q22 -50 22 -114q0 -117 -77 -198.5t-193 -81.5t-193.5 81.5t-77.5 198.5q0 115 78 199.5t193 84.5q53 0 98 -19q4 43 27 87q-60 21 -125 21q-154 0 -257.5 -108.5t-103.5 -263.5t103.5 -261t257.5 -106t257.5 106.5t103.5 260.5z M872 850q2 -24 2 -71q0 -63 -5 -123t-20.5 -132.5t-40.5 -130t-68.5 -106t-100.5 -70.5q21 -3 42 -3h10q219 139 219 411q0 116 -38 225zM872 850q-4 80 -44 171.5t-98 130.5q92 -156 142 -302zM1207 955q0 102 -51 174q-41 -86 -124 -109q-69 -19 -109 -53.5t-40 -99.5 q0 -40 24 -77q74 17 140.5 67t95.5 115q-4 -52 -74.5 -111.5t-138.5 -97.5q52 -52 110 -52q51 0 90 37t60 90q17 43 17 117zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
-<glyph unicode="&#xf2ab;" d="M1279 388q0 22 -22 27q-67 15 -118 59t-80 108q-7 19 -7 25q0 15 19.5 26t43 17t43 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-12 0 -32 -8t-31 -8q-4 0 -12 2q5 95 5 114q0 79 -17 114q-36 78 -103 121.5t-152 43.5q-199 0 -275 -165q-17 -35 -17 -114q0 -19 5 -114 q-4 -2 -14 -2q-12 0 -32 7.5t-30 7.5q-21 0 -38.5 -12t-17.5 -32q0 -21 19.5 -35.5t43 -20.5t43 -17t19.5 -26q0 -6 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -46 137 -68q2 -5 6 -26t11.5 -30.5t23.5 -9.5q12 0 37.5 4.5t39.5 4.5q35 0 67 -15t54 -32.5t57.5 -32.5 t76.5 -15q43 0 79 15t57.5 32.5t53.5 32.5t67 15q14 0 39.5 -4t38.5 -4q16 0 23 10t11 30t6 25q137 22 137 68zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
-<glyph unicode="&#xf2ac;" horiz-adv-x="1664" d="M848 1408q134 1 240.5 -68.5t163.5 -192.5q27 -58 27 -179q0 -47 -9 -191q14 -7 28 -7q18 0 51 13.5t51 13.5q29 0 56 -18t27 -46q0 -32 -31.5 -54t-69 -31.5t-69 -29t-31.5 -47.5q0 -15 12 -43q37 -82 102.5 -150t144.5 -101q28 -12 80 -23q28 -6 28 -35 q0 -70 -219 -103q-7 -11 -11 -39t-14 -46.5t-33 -18.5q-20 0 -62 6.5t-64 6.5q-37 0 -62 -5q-32 -5 -63 -22.5t-58 -38t-58 -40.5t-76 -33.5t-99 -13.5q-52 0 -96.5 13.5t-75 33.5t-57.5 40.5t-58 38t-62 22.5q-26 5 -63 5q-24 0 -65.5 -7.5t-58.5 -7.5q-25 0 -35 18.5 t-14 47.5t-11 40q-219 33 -219 103q0 29 28 35q52 11 80 23q78 32 144.5 101t102.5 150q12 28 12 43q0 28 -31.5 47.5t-69.5 29.5t-69.5 31.5t-31.5 52.5q0 27 26 45.5t55 18.5q15 0 48 -13t53 -13q18 0 32 7q-9 142 -9 190q0 122 27 180q64 137 172 198t264 63z" />
-<glyph unicode="&#xf2ad;" d="M1280 388q0 22 -22 27q-67 14 -118 58t-80 109q-7 14 -7 25q0 15 19.5 26t42.5 17t42.5 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-11 0 -31 -8t-32 -8q-4 0 -12 2q5 63 5 115q0 78 -17 114q-36 78 -102.5 121.5t-152.5 43.5q-198 0 -275 -165q-18 -38 -18 -115 q0 -38 6 -114q-10 -2 -15 -2q-11 0 -31.5 8t-30.5 8q-20 0 -37.5 -12.5t-17.5 -32.5q0 -21 19.5 -35.5t42.5 -20.5t42.5 -17t19.5 -26q0 -11 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -47 138 -69q2 -5 6 -26t11 -30.5t23 -9.5q13 0 38.5 5t38.5 5q35 0 67.5 -15 t54.5 -32.5t57.5 -32.5t76.5 -15q43 0 79 15t57.5 32.5t54 32.5t67.5 15q13 0 39 -4.5t39 -4.5q15 0 22.5 9.5t11.5 31t5 24.5q138 22 138 69zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" />
-<glyph unicode="&#xf2ae;" horiz-adv-x="2304" d="M2304 1536q-69 -46 -125 -92t-89 -81t-59.5 -71.5t-37.5 -57.5t-22 -44.5t-14 -29.5q-10 -18 -35.5 -136.5t-48.5 -164.5q-15 -29 -50 -60.5t-67.5 -50.5t-72.5 -41t-48 -28q-47 -31 -151 -231q-341 14 -630 -158q-92 -53 -303 -179q47 16 86 31t55 22l15 7 q71 27 163 64.5t133.5 53.5t108 34.5t142.5 31.5q186 31 465 -7q1 0 10 -3q11 -6 14 -17t-3 -22l-194 -345q-15 -29 -47 -22q-128 24 -354 24q-146 0 -402 -44.5t-392 -46.5q-82 -1 -149 13t-107 37t-61 40t-33 34l-1 1v2q0 6 6 6q138 0 371 55q192 366 374.5 524t383.5 158 q5 0 14.5 -0.5t38 -5t55 -12t61.5 -24.5t63 -39.5t54 -59t40 -82.5l102 177q2 4 21 42.5t44.5 86.5t61 109.5t84 133.5t100.5 137q66 82 128 141.5t121.5 96.5t92.5 53.5t88 39.5z" />
-<glyph unicode="&#xf2b0;" d="M1322 640q0 -45 -5 -76l-236 14l224 -78q-19 -73 -58 -141l-214 103l177 -158q-44 -61 -107 -108l-157 178l103 -215q-61 -37 -140 -59l-79 228l14 -240q-38 -6 -76 -6t-76 6l14 238l-78 -226q-74 19 -140 59l103 215l-157 -178q-59 43 -108 108l178 158l-214 -104 q-39 69 -58 141l224 79l-237 -14q-5 42 -5 76q0 35 5 77l238 -14l-225 79q19 73 58 140l214 -104l-177 159q46 61 107 108l158 -178l-103 215q67 39 140 58l77 -224l-13 236q36 6 75 6q38 0 76 -6l-14 -237l78 225q74 -19 140 -59l-103 -214l158 178q61 -47 107 -108 l-177 -159l213 104q37 -62 58 -141l-224 -78l237 14q5 -31 5 -77zM1352 640q0 160 -78.5 295.5t-213 214t-292.5 78.5q-119 0 -227 -46.5t-186.5 -125t-124.5 -187.5t-46 -229q0 -119 46 -228t124.5 -187.5t186.5 -125t227 -46.5q158 0 292.5 78.5t213 214t78.5 294.5z M1425 1023v-766l-657 -383l-657 383v766l657 383zM768 -183l708 412v823l-708 411l-708 -411v-823zM1536 1088v-896l-768 -448l-768 448v896l768 448z" />
-<glyph unicode="&#xf2b1;" horiz-adv-x="1664" d="M339 1318h691l-26 -72h-665q-110 0 -188.5 -79t-78.5 -189v-771q0 -95 60.5 -169.5t153.5 -93.5q23 -5 98 -5v-72h-45q-140 0 -239.5 100t-99.5 240v771q0 140 99.5 240t239.5 100zM1190 1536h247l-482 -1294q-23 -61 -40.5 -103.5t-45 -98t-54 -93.5t-64.5 -78.5 t-79.5 -65t-95.5 -41t-116 -18.5v195q163 26 220 182q20 52 20 105q0 54 -20 106l-285 733h228l187 -585zM1664 978v-1111h-795q37 55 45 73h678v1038q0 85 -49.5 155t-129.5 99l25 67q101 -34 163.5 -123.5t62.5 -197.5z" />
-<glyph unicode="&#xf2b2;" horiz-adv-x="1792" d="M852 1227q0 -29 -17 -52.5t-45 -23.5t-45 23.5t-17 52.5t17 52.5t45 23.5t45 -23.5t17 -52.5zM688 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50 -21.5t-20 -51.5v-114q0 -30 20.5 -52t49.5 -22q30 0 50.5 22t20.5 52zM860 -149v114q0 30 -20 51.5t-50 21.5t-50.5 -21.5 t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22q29 0 49.5 22t20.5 52zM1034 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1208 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114 q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1476 535q-84 -160 -232 -259.5t-323 -99.5q-123 0 -229.5 51.5t-178.5 137t-113 197.5t-41 232q0 88 21 174q-104 -175 -104 -390q0 -162 65 -312t185 -251q30 57 91 57q56 0 86 -50q32 50 87 50q56 0 86 -50q32 50 87 50t87 -50 q30 50 86 50q28 0 52.5 -15.5t37.5 -40.5q112 94 177 231.5t73 287.5zM1326 564q0 75 -72 75q-17 0 -47 -6q-95 -19 -149 -19q-226 0 -226 243q0 86 30 204q-83 -127 -83 -275q0 -150 89 -260.5t235 -110.5q111 0 210 70q13 48 13 79zM884 1223q0 50 -32 89.5t-81 39.5 t-81 -39.5t-32 -89.5q0 -51 31.5 -90.5t81.5 -39.5t81.5 39.5t31.5 90.5zM1513 884q0 96 -37.5 179t-113 137t-173.5 54q-77 0 -149 -35t-127 -94q-48 -159 -48 -268q0 -104 45.5 -157t147.5 -53q53 0 142 19q36 6 53 6q51 0 77.5 -28t26.5 -80q0 -26 -4 -46 q75 68 117.5 165.5t42.5 200.5zM1792 667q0 -111 -33.5 -249.5t-93.5 -204.5q-58 -64 -195 -142.5t-228 -104.5l-4 -1v-114q0 -43 -29.5 -75t-72.5 -32q-56 0 -86 50q-32 -50 -87 -50t-87 50q-30 -50 -86 -50q-55 0 -87 50q-30 -50 -86 -50q-47 0 -75 33.5t-28 81.5 q-90 -68 -198 -68q-118 0 -211 80q54 1 106 20q-113 31 -182 127q32 -7 71 -7q89 0 164 46q-192 192 -240 306q-24 56 -24 160q0 57 9 125.5t31.5 146.5t55 141t86.5 105t120 42q59 0 81 -52q19 29 42 54q2 3 12 13t13 16q10 15 23 38t25 42t28 39q87 111 211.5 177 t260.5 66q35 0 62 -4q59 64 146 64q83 0 140 -57q5 -5 5 -12q0 -5 -6 -13.5t-12.5 -16t-16 -17l-10.5 -10.5q17 -6 36 -18t19 -24q0 -6 -16 -25q157 -138 197 -378q25 30 60 30q45 0 100 -49q90 -80 90 -279z" />
-<glyph unicode="&#xf2b3;" d="M917 631q0 33 -6 64h-362v-132h217q-12 -76 -74.5 -120.5t-142.5 -44.5q-99 0 -169 71.5t-70 170.5t70 170.5t169 71.5q93 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585h109v110 h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
-<glyph unicode="&#xf2b4;" d="M1536 1024v-839q0 -48 -49 -62q-174 -52 -338 -52q-73 0 -215.5 29.5t-227.5 29.5q-164 0 -370 -48v-338h-160v1368q-63 25 -101 81t-38 124q0 91 64 155t155 64t155 -64t64 -155q0 -68 -38 -124t-101 -81v-68q190 44 343 44q99 0 198 -15q14 -2 111.5 -22.5t149.5 -20.5 q77 0 165 18q11 2 80 21t89 19q26 0 45 -19t19 -45z" />
-<glyph unicode="&#xf2b5;" horiz-adv-x="1792" />
-<glyph unicode="&#xf2b6;" horiz-adv-x="1792" />
-<glyph unicode="&#xf2b7;" horiz-adv-x="1792" />
-<glyph unicode="&#xf2b8;" horiz-adv-x="1792" />
-<glyph unicode="&#xf2b9;" horiz-adv-x="1792" />
-<glyph unicode="&#xf2ba;" horiz-adv-x="1792" />
-<glyph unicode="&#xf2bb;" horiz-adv-x="1792" />
-<glyph unicode="&#xf2bc;" horiz-adv-x="1792" />
-<glyph unicode="&#xf2bd;" horiz-adv-x="1792" />
-<glyph unicode="&#xf2be;" horiz-adv-x="1792" />
-<glyph unicode="&#xf500;" horiz-adv-x="1792" />
-</font>
-</defs></svg> 
\ No newline at end of file
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.ttf b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.ttf
deleted file mode 100644
index f221e50..0000000
Binary files a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.ttf and /dev/null differ
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff
deleted file mode 100644
index 6e7483c..0000000
Binary files a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff and /dev/null differ
diff --git a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff2 b/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff2
deleted file mode 100644
index 7eb74fd..0000000
Binary files a/hubs/static/font-awesome-4.6.3/fonts/fontawesome-webfont.woff2 and /dev/null differ
diff --git a/hubs/static/font-awesome-4.6.3/less/animated.less b/hubs/static/font-awesome-4.6.3/less/animated.less
deleted file mode 100644
index 66ad52a..0000000
--- a/hubs/static/font-awesome-4.6.3/less/animated.less
+++ /dev/null
@@ -1,34 +0,0 @@
-// Animated Icons
-// --------------------------
-
-.@{fa-css-prefix}-spin {
-  -webkit-animation: fa-spin 2s infinite linear;
-          animation: fa-spin 2s infinite linear;
-}
-
-.@{fa-css-prefix}-pulse {
-  -webkit-animation: fa-spin 1s infinite steps(8);
-          animation: fa-spin 1s infinite steps(8);
-}
-
-@-webkit-keyframes fa-spin {
-  0% {
-    -webkit-transform: rotate(0deg);
-            transform: rotate(0deg);
-  }
-  100% {
-    -webkit-transform: rotate(359deg);
-            transform: rotate(359deg);
-  }
-}
-
-@keyframes fa-spin {
-  0% {
-    -webkit-transform: rotate(0deg);
-            transform: rotate(0deg);
-  }
-  100% {
-    -webkit-transform: rotate(359deg);
-            transform: rotate(359deg);
-  }
-}
diff --git a/hubs/static/font-awesome-4.6.3/less/bordered-pulled.less b/hubs/static/font-awesome-4.6.3/less/bordered-pulled.less
deleted file mode 100644
index f1c8ad7..0000000
--- a/hubs/static/font-awesome-4.6.3/less/bordered-pulled.less
+++ /dev/null
@@ -1,25 +0,0 @@
-// Bordered & Pulled
-// -------------------------
-
-.@{fa-css-prefix}-border {
-  padding: .2em .25em .15em;
-  border: solid .08em @fa-border-color;
-  border-radius: .1em;
-}
-
-.@{fa-css-prefix}-pull-left { float: left; }
-.@{fa-css-prefix}-pull-right { float: right; }
-
-.@{fa-css-prefix} {
-  &.@{fa-css-prefix}-pull-left { margin-right: .3em; }
-  &.@{fa-css-prefix}-pull-right { margin-left: .3em; }
-}
-
-/* Deprecated as of 4.4.0 */
-.pull-right { float: right; }
-.pull-left { float: left; }
-
-.@{fa-css-prefix} {
-  &.pull-left { margin-right: .3em; }
-  &.pull-right { margin-left: .3em; }
-}
diff --git a/hubs/static/font-awesome-4.6.3/less/core.less b/hubs/static/font-awesome-4.6.3/less/core.less
deleted file mode 100644
index c577ac8..0000000
--- a/hubs/static/font-awesome-4.6.3/less/core.less
+++ /dev/null
@@ -1,12 +0,0 @@
-// Base Class Definition
-// -------------------------
-
-.@{fa-css-prefix} {
-  display: inline-block;
-  font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
-  font-size: inherit; // can't have font-size inherit on line above, so need to override
-  text-rendering: auto; // optimizelegibility throws things off #1094
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-
-}
diff --git a/hubs/static/font-awesome-4.6.3/less/fixed-width.less b/hubs/static/font-awesome-4.6.3/less/fixed-width.less
deleted file mode 100644
index 110289f..0000000
--- a/hubs/static/font-awesome-4.6.3/less/fixed-width.less
+++ /dev/null
@@ -1,6 +0,0 @@
-// Fixed Width Icons
-// -------------------------
-.@{fa-css-prefix}-fw {
-  width: (18em / 14);
-  text-align: center;
-}
diff --git a/hubs/static/font-awesome-4.6.3/less/font-awesome.less b/hubs/static/font-awesome-4.6.3/less/font-awesome.less
deleted file mode 100644
index c44e5f4..0000000
--- a/hubs/static/font-awesome-4.6.3/less/font-awesome.less
+++ /dev/null
@@ -1,18 +0,0 @@
-/*!
- *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
- *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */
-
-@import "variables.less";
-@import "mixins.less";
-@import "path.less";
-@import "core.less";
-@import "larger.less";
-@import "fixed-width.less";
-@import "list.less";
-@import "bordered-pulled.less";
-@import "animated.less";
-@import "rotated-flipped.less";
-@import "stacked.less";
-@import "icons.less";
-@import "screen-reader.less";
diff --git a/hubs/static/font-awesome-4.6.3/less/icons.less b/hubs/static/font-awesome-4.6.3/less/icons.less
deleted file mode 100644
index ba21b22..0000000
--- a/hubs/static/font-awesome-4.6.3/less/icons.less
+++ /dev/null
@@ -1,733 +0,0 @@
-/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
-   readers do not read off random characters that represent icons */
-
-.@{fa-css-prefix}-glass:before { content: @fa-var-glass; }
-.@{fa-css-prefix}-music:before { content: @fa-var-music; }
-.@{fa-css-prefix}-search:before { content: @fa-var-search; }
-.@{fa-css-prefix}-envelope-o:before { content: @fa-var-envelope-o; }
-.@{fa-css-prefix}-heart:before { content: @fa-var-heart; }
-.@{fa-css-prefix}-star:before { content: @fa-var-star; }
-.@{fa-css-prefix}-star-o:before { content: @fa-var-star-o; }
-.@{fa-css-prefix}-user:before { content: @fa-var-user; }
-.@{fa-css-prefix}-film:before { content: @fa-var-film; }
-.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; }
-.@{fa-css-prefix}-th:before { content: @fa-var-th; }
-.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; }
-.@{fa-css-prefix}-check:before { content: @fa-var-check; }
-.@{fa-css-prefix}-remove:before,
-.@{fa-css-prefix}-close:before,
-.@{fa-css-prefix}-times:before { content: @fa-var-times; }
-.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; }
-.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; }
-.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; }
-.@{fa-css-prefix}-signal:before { content: @fa-var-signal; }
-.@{fa-css-prefix}-gear:before,
-.@{fa-css-prefix}-cog:before { content: @fa-var-cog; }
-.@{fa-css-prefix}-trash-o:before { content: @fa-var-trash-o; }
-.@{fa-css-prefix}-home:before { content: @fa-var-home; }
-.@{fa-css-prefix}-file-o:before { content: @fa-var-file-o; }
-.@{fa-css-prefix}-clock-o:before { content: @fa-var-clock-o; }
-.@{fa-css-prefix}-road:before { content: @fa-var-road; }
-.@{fa-css-prefix}-download:before { content: @fa-var-download; }
-.@{fa-css-prefix}-arrow-circle-o-down:before { content: @fa-var-arrow-circle-o-down; }
-.@{fa-css-prefix}-arrow-circle-o-up:before { content: @fa-var-arrow-circle-o-up; }
-.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; }
-.@{fa-css-prefix}-play-circle-o:before { content: @fa-var-play-circle-o; }
-.@{fa-css-prefix}-rotate-right:before,
-.@{fa-css-prefix}-repeat:before { content: @fa-var-repeat; }
-.@{fa-css-prefix}-refresh:before { content: @fa-var-refresh; }
-.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; }
-.@{fa-css-prefix}-lock:before { content: @fa-var-lock; }
-.@{fa-css-prefix}-flag:before { content: @fa-var-flag; }
-.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; }
-.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; }
-.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; }
-.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; }
-.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; }
-.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; }
-.@{fa-css-prefix}-tag:before { content: @fa-var-tag; }
-.@{fa-css-prefix}-tags:before { content: @fa-var-tags; }
-.@{fa-css-prefix}-book:before { content: @fa-var-book; }
-.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; }
-.@{fa-css-prefix}-print:before { content: @fa-var-print; }
-.@{fa-css-prefix}-camera:before { content: @fa-var-camera; }
-.@{fa-css-prefix}-font:before { content: @fa-var-font; }
-.@{fa-css-prefix}-bold:before { content: @fa-var-bold; }
-.@{fa-css-prefix}-italic:before { content: @fa-var-italic; }
-.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; }
-.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; }
-.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; }
-.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; }
-.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; }
-.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; }
-.@{fa-css-prefix}-list:before { content: @fa-var-list; }
-.@{fa-css-prefix}-dedent:before,
-.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; }
-.@{fa-css-prefix}-indent:before { content: @fa-var-indent; }
-.@{fa-css-prefix}-video-camera:before { content: @fa-var-video-camera; }
-.@{fa-css-prefix}-photo:before,
-.@{fa-css-prefix}-image:before,
-.@{fa-css-prefix}-picture-o:before { content: @fa-var-picture-o; }
-.@{fa-css-prefix}-pencil:before { content: @fa-var-pencil; }
-.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; }
-.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; }
-.@{fa-css-prefix}-tint:before { content: @fa-var-tint; }
-.@{fa-css-prefix}-edit:before,
-.@{fa-css-prefix}-pencil-square-o:before { content: @fa-var-pencil-square-o; }
-.@{fa-css-prefix}-share-square-o:before { content: @fa-var-share-square-o; }
-.@{fa-css-prefix}-check-square-o:before { content: @fa-var-check-square-o; }
-.@{fa-css-prefix}-arrows:before { content: @fa-var-arrows; }
-.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; }
-.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; }
-.@{fa-css-prefix}-backward:before { content: @fa-var-backward; }
-.@{fa-css-prefix}-play:before { content: @fa-var-play; }
-.@{fa-css-prefix}-pause:before { content: @fa-var-pause; }
-.@{fa-css-prefix}-stop:before { content: @fa-var-stop; }
-.@{fa-css-prefix}-forward:before { content: @fa-var-forward; }
-.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; }
-.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; }
-.@{fa-css-prefix}-eject:before { content: @fa-var-eject; }
-.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; }
-.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; }
-.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; }
-.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; }
-.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; }
-.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; }
-.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; }
-.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; }
-.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; }
-.@{fa-css-prefix}-times-circle-o:before { content: @fa-var-times-circle-o; }
-.@{fa-css-prefix}-check-circle-o:before { content: @fa-var-check-circle-o; }
-.@{fa-css-prefix}-ban:before { content: @fa-var-ban; }
-.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; }
-.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; }
-.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; }
-.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; }
-.@{fa-css-prefix}-mail-forward:before,
-.@{fa-css-prefix}-share:before { content: @fa-var-share; }
-.@{fa-css-prefix}-expand:before { content: @fa-var-expand; }
-.@{fa-css-prefix}-compress:before { content: @fa-var-compress; }
-.@{fa-css-prefix}-plus:before { content: @fa-var-plus; }
-.@{fa-css-prefix}-minus:before { content: @fa-var-minus; }
-.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; }
-.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; }
-.@{fa-css-prefix}-gift:before { content: @fa-var-gift; }
-.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; }
-.@{fa-css-prefix}-fire:before { content: @fa-var-fire; }
-.@{fa-css-prefix}-eye:before { content: @fa-var-eye; }
-.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; }
-.@{fa-css-prefix}-warning:before,
-.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; }
-.@{fa-css-prefix}-plane:before { content: @fa-var-plane; }
-.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; }
-.@{fa-css-prefix}-random:before { content: @fa-var-random; }
-.@{fa-css-prefix}-comment:before { content: @fa-var-comment; }
-.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; }
-.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; }
-.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; }
-.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; }
-.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; }
-.@{fa-css-prefix}-folder:before { content: @fa-var-folder; }
-.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; }
-.@{fa-css-prefix}-arrows-v:before { content: @fa-var-arrows-v; }
-.@{fa-css-prefix}-arrows-h:before { content: @fa-var-arrows-h; }
-.@{fa-css-prefix}-bar-chart-o:before,
-.@{fa-css-prefix}-bar-chart:before { content: @fa-var-bar-chart; }
-.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; }
-.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; }
-.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; }
-.@{fa-css-prefix}-key:before { content: @fa-var-key; }
-.@{fa-css-prefix}-gears:before,
-.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; }
-.@{fa-css-prefix}-comments:before { content: @fa-var-comments; }
-.@{fa-css-prefix}-thumbs-o-up:before { content: @fa-var-thumbs-o-up; }
-.@{fa-css-prefix}-thumbs-o-down:before { content: @fa-var-thumbs-o-down; }
-.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; }
-.@{fa-css-prefix}-heart-o:before { content: @fa-var-heart-o; }
-.@{fa-css-prefix}-sign-out:before { content: @fa-var-sign-out; }
-.@{fa-css-prefix}-linkedin-square:before { content: @fa-var-linkedin-square; }
-.@{fa-css-prefix}-thumb-tack:before { content: @fa-var-thumb-tack; }
-.@{fa-css-prefix}-external-link:before { content: @fa-var-external-link; }
-.@{fa-css-prefix}-sign-in:before { content: @fa-var-sign-in; }
-.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; }
-.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; }
-.@{fa-css-prefix}-upload:before { content: @fa-var-upload; }
-.@{fa-css-prefix}-lemon-o:before { content: @fa-var-lemon-o; }
-.@{fa-css-prefix}-phone:before { content: @fa-var-phone; }
-.@{fa-css-prefix}-square-o:before { content: @fa-var-square-o; }
-.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; }
-.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; }
-.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; }
-.@{fa-css-prefix}-facebook-f:before,
-.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; }
-.@{fa-css-prefix}-github:before { content: @fa-var-github; }
-.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; }
-.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; }
-.@{fa-css-prefix}-feed:before,
-.@{fa-css-prefix}-rss:before { content: @fa-var-rss; }
-.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; }
-.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; }
-.@{fa-css-prefix}-bell:before { content: @fa-var-bell; }
-.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; }
-.@{fa-css-prefix}-hand-o-right:before { content: @fa-var-hand-o-right; }
-.@{fa-css-prefix}-hand-o-left:before { content: @fa-var-hand-o-left; }
-.@{fa-css-prefix}-hand-o-up:before { content: @fa-var-hand-o-up; }
-.@{fa-css-prefix}-hand-o-down:before { content: @fa-var-hand-o-down; }
-.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; }
-.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; }
-.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; }
-.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; }
-.@{fa-css-prefix}-globe:before { content: @fa-var-globe; }
-.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; }
-.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; }
-.@{fa-css-prefix}-filter:before { content: @fa-var-filter; }
-.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; }
-.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; }
-.@{fa-css-prefix}-group:before,
-.@{fa-css-prefix}-users:before { content: @fa-var-users; }
-.@{fa-css-prefix}-chain:before,
-.@{fa-css-prefix}-link:before { content: @fa-var-link; }
-.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; }
-.@{fa-css-prefix}-flask:before { content: @fa-var-flask; }
-.@{fa-css-prefix}-cut:before,
-.@{fa-css-prefix}-scissors:before { content: @fa-var-scissors; }
-.@{fa-css-prefix}-copy:before,
-.@{fa-css-prefix}-files-o:before { content: @fa-var-files-o; }
-.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; }
-.@{fa-css-prefix}-save:before,
-.@{fa-css-prefix}-floppy-o:before { content: @fa-var-floppy-o; }
-.@{fa-css-prefix}-square:before { content: @fa-var-square; }
-.@{fa-css-prefix}-navicon:before,
-.@{fa-css-prefix}-reorder:before,
-.@{fa-css-prefix}-bars:before { content: @fa-var-bars; }
-.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; }
-.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; }
-.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; }
-.@{fa-css-prefix}-underline:before { content: @fa-var-underline; }
-.@{fa-css-prefix}-table:before { content: @fa-var-table; }
-.@{fa-css-prefix}-magic:before { content: @fa-var-magic; }
-.@{fa-css-prefix}-truck:before { content: @fa-var-truck; }
-.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; }
-.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; }
-.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; }
-.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; }
-.@{fa-css-prefix}-money:before { content: @fa-var-money; }
-.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; }
-.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; }
-.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; }
-.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; }
-.@{fa-css-prefix}-columns:before { content: @fa-var-columns; }
-.@{fa-css-prefix}-unsorted:before,
-.@{fa-css-prefix}-sort:before { content: @fa-var-sort; }
-.@{fa-css-prefix}-sort-down:before,
-.@{fa-css-prefix}-sort-desc:before { content: @fa-var-sort-desc; }
-.@{fa-css-prefix}-sort-up:before,
-.@{fa-css-prefix}-sort-asc:before { content: @fa-var-sort-asc; }
-.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; }
-.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; }
-.@{fa-css-prefix}-rotate-left:before,
-.@{fa-css-prefix}-undo:before { content: @fa-var-undo; }
-.@{fa-css-prefix}-legal:before,
-.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; }
-.@{fa-css-prefix}-dashboard:before,
-.@{fa-css-prefix}-tachometer:before { content: @fa-var-tachometer; }
-.@{fa-css-prefix}-comment-o:before { content: @fa-var-comment-o; }
-.@{fa-css-prefix}-comments-o:before { content: @fa-var-comments-o; }
-.@{fa-css-prefix}-flash:before,
-.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; }
-.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; }
-.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; }
-.@{fa-css-prefix}-paste:before,
-.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; }
-.@{fa-css-prefix}-lightbulb-o:before { content: @fa-var-lightbulb-o; }
-.@{fa-css-prefix}-exchange:before { content: @fa-var-exchange; }
-.@{fa-css-prefix}-cloud-download:before { content: @fa-var-cloud-download; }
-.@{fa-css-prefix}-cloud-upload:before { content: @fa-var-cloud-upload; }
-.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; }
-.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; }
-.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; }
-.@{fa-css-prefix}-bell-o:before { content: @fa-var-bell-o; }
-.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; }
-.@{fa-css-prefix}-cutlery:before { content: @fa-var-cutlery; }
-.@{fa-css-prefix}-file-text-o:before { content: @fa-var-file-text-o; }
-.@{fa-css-prefix}-building-o:before { content: @fa-var-building-o; }
-.@{fa-css-prefix}-hospital-o:before { content: @fa-var-hospital-o; }
-.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; }
-.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; }
-.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; }
-.@{fa-css-prefix}-beer:before { content: @fa-var-beer; }
-.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; }
-.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; }
-.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; }
-.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; }
-.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; }
-.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; }
-.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; }
-.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; }
-.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; }
-.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; }
-.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; }
-.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; }
-.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; }
-.@{fa-css-prefix}-mobile-phone:before,
-.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; }
-.@{fa-css-prefix}-circle-o:before { content: @fa-var-circle-o; }
-.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; }
-.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; }
-.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; }
-.@{fa-css-prefix}-circle:before { content: @fa-var-circle; }
-.@{fa-css-prefix}-mail-reply:before,
-.@{fa-css-prefix}-reply:before { content: @fa-var-reply; }
-.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; }
-.@{fa-css-prefix}-folder-o:before { content: @fa-var-folder-o; }
-.@{fa-css-prefix}-folder-open-o:before { content: @fa-var-folder-open-o; }
-.@{fa-css-prefix}-smile-o:before { content: @fa-var-smile-o; }
-.@{fa-css-prefix}-frown-o:before { content: @fa-var-frown-o; }
-.@{fa-css-prefix}-meh-o:before { content: @fa-var-meh-o; }
-.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; }
-.@{fa-css-prefix}-keyboard-o:before { content: @fa-var-keyboard-o; }
-.@{fa-css-prefix}-flag-o:before { content: @fa-var-flag-o; }
-.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; }
-.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; }
-.@{fa-css-prefix}-code:before { content: @fa-var-code; }
-.@{fa-css-prefix}-mail-reply-all:before,
-.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; }
-.@{fa-css-prefix}-star-half-empty:before,
-.@{fa-css-prefix}-star-half-full:before,
-.@{fa-css-prefix}-star-half-o:before { content: @fa-var-star-half-o; }
-.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; }
-.@{fa-css-prefix}-crop:before { content: @fa-var-crop; }
-.@{fa-css-prefix}-code-fork:before { content: @fa-var-code-fork; }
-.@{fa-css-prefix}-unlink:before,
-.@{fa-css-prefix}-chain-broken:before { content: @fa-var-chain-broken; }
-.@{fa-css-prefix}-question:before { content: @fa-var-question; }
-.@{fa-css-prefix}-info:before { content: @fa-var-info; }
-.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; }
-.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; }
-.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; }
-.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; }
-.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; }
-.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; }
-.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; }
-.@{fa-css-prefix}-shield:before { content: @fa-var-shield; }
-.@{fa-css-prefix}-calendar-o:before { content: @fa-var-calendar-o; }
-.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; }
-.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; }
-.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; }
-.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; }
-.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; }
-.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; }
-.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; }
-.@{fa-css-prefix}-html5:before { content: @fa-var-html5; }
-.@{fa-css-prefix}-css3:before { content: @fa-var-css3; }
-.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; }
-.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; }
-.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; }
-.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; }
-.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; }
-.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; }
-.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; }
-.@{fa-css-prefix}-ticket:before { content: @fa-var-ticket; }
-.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; }
-.@{fa-css-prefix}-minus-square-o:before { content: @fa-var-minus-square-o; }
-.@{fa-css-prefix}-level-up:before { content: @fa-var-level-up; }
-.@{fa-css-prefix}-level-down:before { content: @fa-var-level-down; }
-.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; }
-.@{fa-css-prefix}-pencil-square:before { content: @fa-var-pencil-square; }
-.@{fa-css-prefix}-external-link-square:before { content: @fa-var-external-link-square; }
-.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; }
-.@{fa-css-prefix}-compass:before { content: @fa-var-compass; }
-.@{fa-css-prefix}-toggle-down:before,
-.@{fa-css-prefix}-caret-square-o-down:before { content: @fa-var-caret-square-o-down; }
-.@{fa-css-prefix}-toggle-up:before,
-.@{fa-css-prefix}-caret-square-o-up:before { content: @fa-var-caret-square-o-up; }
-.@{fa-css-prefix}-toggle-right:before,
-.@{fa-css-prefix}-caret-square-o-right:before { content: @fa-var-caret-square-o-right; }
-.@{fa-css-prefix}-euro:before,
-.@{fa-css-prefix}-eur:before { content: @fa-var-eur; }
-.@{fa-css-prefix}-gbp:before { content: @fa-var-gbp; }
-.@{fa-css-prefix}-dollar:before,
-.@{fa-css-prefix}-usd:before { content: @fa-var-usd; }
-.@{fa-css-prefix}-rupee:before,
-.@{fa-css-prefix}-inr:before { content: @fa-var-inr; }
-.@{fa-css-prefix}-cny:before,
-.@{fa-css-prefix}-rmb:before,
-.@{fa-css-prefix}-yen:before,
-.@{fa-css-prefix}-jpy:before { content: @fa-var-jpy; }
-.@{fa-css-prefix}-ruble:before,
-.@{fa-css-prefix}-rouble:before,
-.@{fa-css-prefix}-rub:before { content: @fa-var-rub; }
-.@{fa-css-prefix}-won:before,
-.@{fa-css-prefix}-krw:before { content: @fa-var-krw; }
-.@{fa-css-prefix}-bitcoin:before,
-.@{fa-css-prefix}-btc:before { content: @fa-var-btc; }
-.@{fa-css-prefix}-file:before { content: @fa-var-file; }
-.@{fa-css-prefix}-file-text:before { content: @fa-var-file-text; }
-.@{fa-css-prefix}-sort-alpha-asc:before { content: @fa-var-sort-alpha-asc; }
-.@{fa-css-prefix}-sort-alpha-desc:before { content: @fa-var-sort-alpha-desc; }
-.@{fa-css-prefix}-sort-amount-asc:before { content: @fa-var-sort-amount-asc; }
-.@{fa-css-prefix}-sort-amount-desc:before { content: @fa-var-sort-amount-desc; }
-.@{fa-css-prefix}-sort-numeric-asc:before { content: @fa-var-sort-numeric-asc; }
-.@{fa-css-prefix}-sort-numeric-desc:before { content: @fa-var-sort-numeric-desc; }
-.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; }
-.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; }
-.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; }
-.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; }
-.@{fa-css-prefix}-xing:before { content: @fa-var-xing; }
-.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; }
-.@{fa-css-prefix}-youtube-play:before { content: @fa-var-youtube-play; }
-.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; }
-.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; }
-.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; }
-.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; }
-.@{fa-css-prefix}-adn:before { content: @fa-var-adn; }
-.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; }
-.@{fa-css-prefix}-bitbucket-square:before { content: @fa-var-bitbucket-square; }
-.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; }
-.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; }
-.@{fa-css-prefix}-long-arrow-down:before { content: @fa-var-long-arrow-down; }
-.@{fa-css-prefix}-long-arrow-up:before { content: @fa-var-long-arrow-up; }
-.@{fa-css-prefix}-long-arrow-left:before { content: @fa-var-long-arrow-left; }
-.@{fa-css-prefix}-long-arrow-right:before { content: @fa-var-long-arrow-right; }
-.@{fa-css-prefix}-apple:before { content: @fa-var-apple; }
-.@{fa-css-prefix}-windows:before { content: @fa-var-windows; }
-.@{fa-css-prefix}-android:before { content: @fa-var-android; }
-.@{fa-css-prefix}-linux:before { content: @fa-var-linux; }
-.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; }
-.@{fa-css-prefix}-skype:before { content: @fa-var-skype; }
-.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; }
-.@{fa-css-prefix}-trello:before { content: @fa-var-trello; }
-.@{fa-css-prefix}-female:before { content: @fa-var-female; }
-.@{fa-css-prefix}-male:before { content: @fa-var-male; }
-.@{fa-css-prefix}-gittip:before,
-.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; }
-.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; }
-.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; }
-.@{fa-css-prefix}-archive:before { content: @fa-var-archive; }
-.@{fa-css-prefix}-bug:before { content: @fa-var-bug; }
-.@{fa-css-prefix}-vk:before { content: @fa-var-vk; }
-.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; }
-.@{fa-css-prefix}-renren:before { content: @fa-var-renren; }
-.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; }
-.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; }
-.@{fa-css-prefix}-arrow-circle-o-right:before { content: @fa-var-arrow-circle-o-right; }
-.@{fa-css-prefix}-arrow-circle-o-left:before { content: @fa-var-arrow-circle-o-left; }
-.@{fa-css-prefix}-toggle-left:before,
-.@{fa-css-prefix}-caret-square-o-left:before { content: @fa-var-caret-square-o-left; }
-.@{fa-css-prefix}-dot-circle-o:before { content: @fa-var-dot-circle-o; }
-.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; }
-.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; }
-.@{fa-css-prefix}-turkish-lira:before,
-.@{fa-css-prefix}-try:before { content: @fa-var-try; }
-.@{fa-css-prefix}-plus-square-o:before { content: @fa-var-plus-square-o; }
-.@{fa-css-prefix}-space-shuttle:before { content: @fa-var-space-shuttle; }
-.@{fa-css-prefix}-slack:before { content: @fa-var-slack; }
-.@{fa-css-prefix}-envelope-square:before { content: @fa-var-envelope-square; }
-.@{fa-css-prefix}-wordpress:before { content: @fa-var-wordpress; }
-.@{fa-css-prefix}-openid:before { content: @fa-var-openid; }
-.@{fa-css-prefix}-institution:before,
-.@{fa-css-prefix}-bank:before,
-.@{fa-css-prefix}-university:before { content: @fa-var-university; }
-.@{fa-css-prefix}-mortar-board:before,
-.@{fa-css-prefix}-graduation-cap:before { content: @fa-var-graduation-cap; }
-.@{fa-css-prefix}-yahoo:before { content: @fa-var-yahoo; }
-.@{fa-css-prefix}-google:before { content: @fa-var-google; }
-.@{fa-css-prefix}-reddit:before { content: @fa-var-reddit; }
-.@{fa-css-prefix}-reddit-square:before { content: @fa-var-reddit-square; }
-.@{fa-css-prefix}-stumbleupon-circle:before { content: @fa-var-stumbleupon-circle; }
-.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; }
-.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; }
-.@{fa-css-prefix}-digg:before { content: @fa-var-digg; }
-.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; }
-.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; }
-.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; }
-.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; }
-.@{fa-css-prefix}-language:before { content: @fa-var-language; }
-.@{fa-css-prefix}-fax:before { content: @fa-var-fax; }
-.@{fa-css-prefix}-building:before { content: @fa-var-building; }
-.@{fa-css-prefix}-child:before { content: @fa-var-child; }
-.@{fa-css-prefix}-paw:before { content: @fa-var-paw; }
-.@{fa-css-prefix}-spoon:before { content: @fa-var-spoon; }
-.@{fa-css-prefix}-cube:before { content: @fa-var-cube; }
-.@{fa-css-prefix}-cubes:before { content: @fa-var-cubes; }
-.@{fa-css-prefix}-behance:before { content: @fa-var-behance; }
-.@{fa-css-prefix}-behance-square:before { content: @fa-var-behance-square; }
-.@{fa-css-prefix}-steam:before { content: @fa-var-steam; }
-.@{fa-css-prefix}-steam-square:before { content: @fa-var-steam-square; }
-.@{fa-css-prefix}-recycle:before { content: @fa-var-recycle; }
-.@{fa-css-prefix}-automobile:before,
-.@{fa-css-prefix}-car:before { content: @fa-var-car; }
-.@{fa-css-prefix}-cab:before,
-.@{fa-css-prefix}-taxi:before { content: @fa-var-taxi; }
-.@{fa-css-prefix}-tree:before { content: @fa-var-tree; }
-.@{fa-css-prefix}-spotify:before { content: @fa-var-spotify; }
-.@{fa-css-prefix}-deviantart:before { content: @fa-var-deviantart; }
-.@{fa-css-prefix}-soundcloud:before { content: @fa-var-soundcloud; }
-.@{fa-css-prefix}-database:before { content: @fa-var-database; }
-.@{fa-css-prefix}-file-pdf-o:before { content: @fa-var-file-pdf-o; }
-.@{fa-css-prefix}-file-word-o:before { content: @fa-var-file-word-o; }
-.@{fa-css-prefix}-file-excel-o:before { content: @fa-var-file-excel-o; }
-.@{fa-css-prefix}-file-powerpoint-o:before { content: @fa-var-file-powerpoint-o; }
-.@{fa-css-prefix}-file-photo-o:before,
-.@{fa-css-prefix}-file-picture-o:before,
-.@{fa-css-prefix}-file-image-o:before { content: @fa-var-file-image-o; }
-.@{fa-css-prefix}-file-zip-o:before,
-.@{fa-css-prefix}-file-archive-o:before { content: @fa-var-file-archive-o; }
-.@{fa-css-prefix}-file-sound-o:before,
-.@{fa-css-prefix}-file-audio-o:before { content: @fa-var-file-audio-o; }
-.@{fa-css-prefix}-file-movie-o:before,
-.@{fa-css-prefix}-file-video-o:before { content: @fa-var-file-video-o; }
-.@{fa-css-prefix}-file-code-o:before { content: @fa-var-file-code-o; }
-.@{fa-css-prefix}-vine:before { content: @fa-var-vine; }
-.@{fa-css-prefix}-codepen:before { content: @fa-var-codepen; }
-.@{fa-css-prefix}-jsfiddle:before { content: @fa-var-jsfiddle; }
-.@{fa-css-prefix}-life-bouy:before,
-.@{fa-css-prefix}-life-buoy:before,
-.@{fa-css-prefix}-life-saver:before,
-.@{fa-css-prefix}-support:before,
-.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; }
-.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; }
-.@{fa-css-prefix}-ra:before,
-.@{fa-css-prefix}-resistance:before,
-.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; }
-.@{fa-css-prefix}-ge:before,
-.@{fa-css-prefix}-empire:before { content: @fa-var-empire; }
-.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; }
-.@{fa-css-prefix}-git:before { content: @fa-var-git; }
-.@{fa-css-prefix}-y-combinator-square:before,
-.@{fa-css-prefix}-yc-square:before,
-.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; }
-.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; }
-.@{fa-css-prefix}-qq:before { content: @fa-var-qq; }
-.@{fa-css-prefix}-wechat:before,
-.@{fa-css-prefix}-weixin:before { content: @fa-var-weixin; }
-.@{fa-css-prefix}-send:before,
-.@{fa-css-prefix}-paper-plane:before { content: @fa-var-paper-plane; }
-.@{fa-css-prefix}-send-o:before,
-.@{fa-css-prefix}-paper-plane-o:before { content: @fa-var-paper-plane-o; }
-.@{fa-css-prefix}-history:before { content: @fa-var-history; }
-.@{fa-css-prefix}-circle-thin:before { content: @fa-var-circle-thin; }
-.@{fa-css-prefix}-header:before { content: @fa-var-header; }
-.@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; }
-.@{fa-css-prefix}-sliders:before { content: @fa-var-sliders; }
-.@{fa-css-prefix}-share-alt:before { content: @fa-var-share-alt; }
-.@{fa-css-prefix}-share-alt-square:before { content: @fa-var-share-alt-square; }
-.@{fa-css-prefix}-bomb:before { content: @fa-var-bomb; }
-.@{fa-css-prefix}-soccer-ball-o:before,
-.@{fa-css-prefix}-futbol-o:before { content: @fa-var-futbol-o; }
-.@{fa-css-prefix}-tty:before { content: @fa-var-tty; }
-.@{fa-css-prefix}-binoculars:before { content: @fa-var-binoculars; }
-.@{fa-css-prefix}-plug:before { content: @fa-var-plug; }
-.@{fa-css-prefix}-slideshare:before { content: @fa-var-slideshare; }
-.@{fa-css-prefix}-twitch:before { content: @fa-var-twitch; }
-.@{fa-css-prefix}-yelp:before { content: @fa-var-yelp; }
-.@{fa-css-prefix}-newspaper-o:before { content: @fa-var-newspaper-o; }
-.@{fa-css-prefix}-wifi:before { content: @fa-var-wifi; }
-.@{fa-css-prefix}-calculator:before { content: @fa-var-calculator; }
-.@{fa-css-prefix}-paypal:before { content: @fa-var-paypal; }
-.@{fa-css-prefix}-google-wallet:before { content: @fa-var-google-wallet; }
-.@{fa-css-prefix}-cc-visa:before { content: @fa-var-cc-visa; }
-.@{fa-css-prefix}-cc-mastercard:before { content: @fa-var-cc-mastercard; }
-.@{fa-css-prefix}-cc-discover:before { content: @fa-var-cc-discover; }
-.@{fa-css-prefix}-cc-amex:before { content: @fa-var-cc-amex; }
-.@{fa-css-prefix}-cc-paypal:before { content: @fa-var-cc-paypal; }
-.@{fa-css-prefix}-cc-stripe:before { content: @fa-var-cc-stripe; }
-.@{fa-css-prefix}-bell-slash:before { content: @fa-var-bell-slash; }
-.@{fa-css-prefix}-bell-slash-o:before { content: @fa-var-bell-slash-o; }
-.@{fa-css-prefix}-trash:before { content: @fa-var-trash; }
-.@{fa-css-prefix}-copyright:before { content: @fa-var-copyright; }
-.@{fa-css-prefix}-at:before { content: @fa-var-at; }
-.@{fa-css-prefix}-eyedropper:before { content: @fa-var-eyedropper; }
-.@{fa-css-prefix}-paint-brush:before { content: @fa-var-paint-brush; }
-.@{fa-css-prefix}-birthday-cake:before { content: @fa-var-birthday-cake; }
-.@{fa-css-prefix}-area-chart:before { content: @fa-var-area-chart; }
-.@{fa-css-prefix}-pie-chart:before { content: @fa-var-pie-chart; }
-.@{fa-css-prefix}-line-chart:before { content: @fa-var-line-chart; }
-.@{fa-css-prefix}-lastfm:before { content: @fa-var-lastfm; }
-.@{fa-css-prefix}-lastfm-square:before { content: @fa-var-lastfm-square; }
-.@{fa-css-prefix}-toggle-off:before { content: @fa-var-toggle-off; }
-.@{fa-css-prefix}-toggle-on:before { content: @fa-var-toggle-on; }
-.@{fa-css-prefix}-bicycle:before { content: @fa-var-bicycle; }
-.@{fa-css-prefix}-bus:before { content: @fa-var-bus; }
-.@{fa-css-prefix}-ioxhost:before { content: @fa-var-ioxhost; }
-.@{fa-css-prefix}-angellist:before { content: @fa-var-angellist; }
-.@{fa-css-prefix}-cc:before { content: @fa-var-cc; }
-.@{fa-css-prefix}-shekel:before,
-.@{fa-css-prefix}-sheqel:before,
-.@{fa-css-prefix}-ils:before { content: @fa-var-ils; }
-.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; }
-.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; }
-.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; }
-.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; }
-.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; }
-.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; }
-.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; }
-.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; }
-.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; }
-.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; }
-.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; }
-.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; }
-.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; }
-.@{fa-css-prefix}-ship:before { content: @fa-var-ship; }
-.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; }
-.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; }
-.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; }
-.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; }
-.@{fa-css-prefix}-venus:before { content: @fa-var-venus; }
-.@{fa-css-prefix}-mars:before { content: @fa-var-mars; }
-.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; }
-.@{fa-css-prefix}-intersex:before,
-.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; }
-.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; }
-.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; }
-.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; }
-.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; }
-.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; }
-.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; }
-.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; }
-.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; }
-.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; }
-.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; }
-.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; }
-.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; }
-.@{fa-css-prefix}-server:before { content: @fa-var-server; }
-.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; }
-.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; }
-.@{fa-css-prefix}-hotel:before,
-.@{fa-css-prefix}-bed:before { content: @fa-var-bed; }
-.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; }
-.@{fa-css-prefix}-train:before { content: @fa-var-train; }
-.@{fa-css-prefix}-subway:before { content: @fa-var-subway; }
-.@{fa-css-prefix}-medium:before { content: @fa-var-medium; }
-.@{fa-css-prefix}-yc:before,
-.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; }
-.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; }
-.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; }
-.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; }
-.@{fa-css-prefix}-battery-4:before,
-.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; }
-.@{fa-css-prefix}-battery-3:before,
-.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; }
-.@{fa-css-prefix}-battery-2:before,
-.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; }
-.@{fa-css-prefix}-battery-1:before,
-.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; }
-.@{fa-css-prefix}-battery-0:before,
-.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; }
-.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; }
-.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; }
-.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; }
-.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; }
-.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; }
-.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; }
-.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; }
-.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; }
-.@{fa-css-prefix}-clone:before { content: @fa-var-clone; }
-.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; }
-.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; }
-.@{fa-css-prefix}-hourglass-1:before,
-.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; }
-.@{fa-css-prefix}-hourglass-2:before,
-.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; }
-.@{fa-css-prefix}-hourglass-3:before,
-.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; }
-.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; }
-.@{fa-css-prefix}-hand-grab-o:before,
-.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; }
-.@{fa-css-prefix}-hand-stop-o:before,
-.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; }
-.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; }
-.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; }
-.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; }
-.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; }
-.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; }
-.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; }
-.@{fa-css-prefix}-registered:before { content: @fa-var-registered; }
-.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; }
-.@{fa-css-prefix}-gg:before { content: @fa-var-gg; }
-.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; }
-.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; }
-.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; }
-.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; }
-.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; }
-.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; }
-.@{fa-css-prefix}-safari:before { content: @fa-var-safari; }
-.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; }
-.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; }
-.@{fa-css-prefix}-opera:before { content: @fa-var-opera; }
-.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; }
-.@{fa-css-prefix}-tv:before,
-.@{fa-css-prefix}-television:before { content: @fa-var-television; }
-.@{fa-css-prefix}-contao:before { content: @fa-var-contao; }
-.@{fa-css-prefix}-500px:before { content: @fa-var-500px; }
-.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; }
-.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; }
-.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; }
-.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; }
-.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; }
-.@{fa-css-prefix}-industry:before { content: @fa-var-industry; }
-.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; }
-.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; }
-.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; }
-.@{fa-css-prefix}-map:before { content: @fa-var-map; }
-.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; }
-.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; }
-.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; }
-.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; }
-.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; }
-.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; }
-.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; }
-.@{fa-css-prefix}-edge:before { content: @fa-var-edge; }
-.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; }
-.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; }
-.@{fa-css-prefix}-modx:before { content: @fa-var-modx; }
-.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; }
-.@{fa-css-prefix}-usb:before { content: @fa-var-usb; }
-.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; }
-.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; }
-.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; }
-.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; }
-.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; }
-.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; }
-.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; }
-.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; }
-.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; }
-.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; }
-.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; }
-.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; }
-.@{fa-css-prefix}-percent:before { content: @fa-var-percent; }
-.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; }
-.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; }
-.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; }
-.@{fa-css-prefix}-envira:before { content: @fa-var-envira; }
-.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; }
-.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; }
-.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; }
-.@{fa-css-prefix}-blind:before { content: @fa-var-blind; }
-.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; }
-.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; }
-.@{fa-css-prefix}-braille:before { content: @fa-var-braille; }
-.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; }
-.@{fa-css-prefix}-asl-interpreting:before,
-.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; }
-.@{fa-css-prefix}-deafness:before,
-.@{fa-css-prefix}-hard-of-hearing:before,
-.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; }
-.@{fa-css-prefix}-glide:before { content: @fa-var-glide; }
-.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; }
-.@{fa-css-prefix}-signing:before,
-.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; }
-.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; }
-.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; }
-.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; }
-.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; }
-.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; }
-.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; }
-.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
-.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; }
-.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; }
-.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; }
-.@{fa-css-prefix}-google-plus-circle:before,
-.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; }
-.@{fa-css-prefix}-fa:before,
-.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; }
diff --git a/hubs/static/font-awesome-4.6.3/less/larger.less b/hubs/static/font-awesome-4.6.3/less/larger.less
deleted file mode 100644
index c9d6467..0000000
--- a/hubs/static/font-awesome-4.6.3/less/larger.less
+++ /dev/null
@@ -1,13 +0,0 @@
-// Icon Sizes
-// -------------------------
-
-/* makes the font 33% larger relative to the icon container */
-.@{fa-css-prefix}-lg {
-  font-size: (4em / 3);
-  line-height: (3em / 4);
-  vertical-align: -15%;
-}
-.@{fa-css-prefix}-2x { font-size: 2em; }
-.@{fa-css-prefix}-3x { font-size: 3em; }
-.@{fa-css-prefix}-4x { font-size: 4em; }
-.@{fa-css-prefix}-5x { font-size: 5em; }
diff --git a/hubs/static/font-awesome-4.6.3/less/list.less b/hubs/static/font-awesome-4.6.3/less/list.less
deleted file mode 100644
index 0b44038..0000000
--- a/hubs/static/font-awesome-4.6.3/less/list.less
+++ /dev/null
@@ -1,19 +0,0 @@
-// List Icons
-// -------------------------
-
-.@{fa-css-prefix}-ul {
-  padding-left: 0;
-  margin-left: @fa-li-width;
-  list-style-type: none;
-  > li { position: relative; }
-}
-.@{fa-css-prefix}-li {
-  position: absolute;
-  left: -@fa-li-width;
-  width: @fa-li-width;
-  top: (2em / 14);
-  text-align: center;
-  &.@{fa-css-prefix}-lg {
-    left: (-@fa-li-width + (4em / 14));
-  }
-}
diff --git a/hubs/static/font-awesome-4.6.3/less/mixins.less b/hubs/static/font-awesome-4.6.3/less/mixins.less
deleted file mode 100644
index beef231..0000000
--- a/hubs/static/font-awesome-4.6.3/less/mixins.less
+++ /dev/null
@@ -1,60 +0,0 @@
-// Mixins
-// --------------------------
-
-.fa-icon() {
-  display: inline-block;
-  font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
-  font-size: inherit; // can't have font-size inherit on line above, so need to override
-  text-rendering: auto; // optimizelegibility throws things off #1094
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-
-}
-
-.fa-icon-rotate(@degrees, @rotation) {
-  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
-  -webkit-transform: rotate(@degrees);
-      -ms-transform: rotate(@degrees);
-          transform: rotate(@degrees);
-}
-
-.fa-icon-flip(@horiz, @vert, @rotation) {
-  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
-  -webkit-transform: scale(@horiz, @vert);
-      -ms-transform: scale(@horiz, @vert);
-          transform: scale(@horiz, @vert);
-}
-
-
-// Only display content to screen readers. A la Bootstrap 4.
-//
-// See: http://a11yproject.com/posts/how-to-hide-content/
-
-.sr-only() {
-  position: absolute;
-  width: 1px;
-  height: 1px;
-  padding: 0;
-  margin: -1px;
-  overflow: hidden;
-  clip: rect(0,0,0,0);
-  border: 0;
-}
-
-// Use in conjunction with .sr-only to only display content when it's focused.
-//
-// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
-//
-// Credit: HTML5 Boilerplate
-
-.sr-only-focusable() {
-  &:active,
-  &:focus {
-    position: static;
-    width: auto;
-    height: auto;
-    margin: 0;
-    overflow: visible;
-    clip: auto;
-  }
-}
diff --git a/hubs/static/font-awesome-4.6.3/less/path.less b/hubs/static/font-awesome-4.6.3/less/path.less
deleted file mode 100644
index 835be41..0000000
--- a/hubs/static/font-awesome-4.6.3/less/path.less
+++ /dev/null
@@ -1,15 +0,0 @@
-/* FONT PATH
- * -------------------------- */
-
-@font-face {
-  font-family: 'FontAwesome';
-  src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
-  src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
-    url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
-    url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
-    url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
-    url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
-  // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
-  font-weight: normal;
-  font-style: normal;
-}
diff --git a/hubs/static/font-awesome-4.6.3/less/rotated-flipped.less b/hubs/static/font-awesome-4.6.3/less/rotated-flipped.less
deleted file mode 100644
index f6ba814..0000000
--- a/hubs/static/font-awesome-4.6.3/less/rotated-flipped.less
+++ /dev/null
@@ -1,20 +0,0 @@
-// Rotated & Flipped Icons
-// -------------------------
-
-.@{fa-css-prefix}-rotate-90  { .fa-icon-rotate(90deg, 1);  }
-.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
-.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
-
-.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
-.@{fa-css-prefix}-flip-vertical   { .fa-icon-flip(1, -1, 2); }
-
-// Hook for IE8-9
-// -------------------------
-
-:root .@{fa-css-prefix}-rotate-90,
-:root .@{fa-css-prefix}-rotate-180,
-:root .@{fa-css-prefix}-rotate-270,
-:root .@{fa-css-prefix}-flip-horizontal,
-:root .@{fa-css-prefix}-flip-vertical {
-  filter: none;
-}
diff --git a/hubs/static/font-awesome-4.6.3/less/screen-reader.less b/hubs/static/font-awesome-4.6.3/less/screen-reader.less
deleted file mode 100644
index 11c1881..0000000
--- a/hubs/static/font-awesome-4.6.3/less/screen-reader.less
+++ /dev/null
@@ -1,5 +0,0 @@
-// Screen Readers
-// -------------------------
-
-.sr-only { .sr-only(); }
-.sr-only-focusable { .sr-only-focusable(); }
diff --git a/hubs/static/font-awesome-4.6.3/less/stacked.less b/hubs/static/font-awesome-4.6.3/less/stacked.less
deleted file mode 100644
index fc53fb0..0000000
--- a/hubs/static/font-awesome-4.6.3/less/stacked.less
+++ /dev/null
@@ -1,20 +0,0 @@
-// Stacked Icons
-// -------------------------
-
-.@{fa-css-prefix}-stack {
-  position: relative;
-  display: inline-block;
-  width: 2em;
-  height: 2em;
-  line-height: 2em;
-  vertical-align: middle;
-}
-.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
-  position: absolute;
-  left: 0;
-  width: 100%;
-  text-align: center;
-}
-.@{fa-css-prefix}-stack-1x { line-height: inherit; }
-.@{fa-css-prefix}-stack-2x { font-size: 2em; }
-.@{fa-css-prefix}-inverse { color: @fa-inverse; }
diff --git a/hubs/static/font-awesome-4.6.3/less/variables.less b/hubs/static/font-awesome-4.6.3/less/variables.less
deleted file mode 100644
index 2b33819..0000000
--- a/hubs/static/font-awesome-4.6.3/less/variables.less
+++ /dev/null
@@ -1,744 +0,0 @@
-// Variables
-// --------------------------
-
-@fa-font-path:        "../fonts";
-@fa-font-size-base:   14px;
-@fa-line-height-base: 1;
-//@fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.6.3/fonts"; // for referencing Bootstrap CDN font files directly
-@fa-css-prefix:       fa;
-@fa-version:          "4.6.3";
-@fa-border-color:     #eee;
-@fa-inverse:          #fff;
-@fa-li-width:         (30em / 14);
-
-@fa-var-500px: "\f26e";
-@fa-var-adjust: "\f042";
-@fa-var-adn: "\f170";
-@fa-var-align-center: "\f037";
-@fa-var-align-justify: "\f039";
-@fa-var-align-left: "\f036";
-@fa-var-align-right: "\f038";
-@fa-var-amazon: "\f270";
-@fa-var-ambulance: "\f0f9";
-@fa-var-american-sign-language-interpreting: "\f2a3";
-@fa-var-anchor: "\f13d";
-@fa-var-android: "\f17b";
-@fa-var-angellist: "\f209";
-@fa-var-angle-double-down: "\f103";
-@fa-var-angle-double-left: "\f100";
-@fa-var-angle-double-right: "\f101";
-@fa-var-angle-double-up: "\f102";
-@fa-var-angle-down: "\f107";
-@fa-var-angle-left: "\f104";
-@fa-var-angle-right: "\f105";
-@fa-var-angle-up: "\f106";
-@fa-var-apple: "\f179";
-@fa-var-archive: "\f187";
-@fa-var-area-chart: "\f1fe";
-@fa-var-arrow-circle-down: "\f0ab";
-@fa-var-arrow-circle-left: "\f0a8";
-@fa-var-arrow-circle-o-down: "\f01a";
-@fa-var-arrow-circle-o-left: "\f190";
-@fa-var-arrow-circle-o-right: "\f18e";
-@fa-var-arrow-circle-o-up: "\f01b";
-@fa-var-arrow-circle-right: "\f0a9";
-@fa-var-arrow-circle-up: "\f0aa";
-@fa-var-arrow-down: "\f063";
-@fa-var-arrow-left: "\f060";
-@fa-var-arrow-right: "\f061";
-@fa-var-arrow-up: "\f062";
-@fa-var-arrows: "\f047";
-@fa-var-arrows-alt: "\f0b2";
-@fa-var-arrows-h: "\f07e";
-@fa-var-arrows-v: "\f07d";
-@fa-var-asl-interpreting: "\f2a3";
-@fa-var-assistive-listening-systems: "\f2a2";
-@fa-var-asterisk: "\f069";
-@fa-var-at: "\f1fa";
-@fa-var-audio-description: "\f29e";
-@fa-var-automobile: "\f1b9";
-@fa-var-backward: "\f04a";
-@fa-var-balance-scale: "\f24e";
-@fa-var-ban: "\f05e";
-@fa-var-bank: "\f19c";
-@fa-var-bar-chart: "\f080";
-@fa-var-bar-chart-o: "\f080";
-@fa-var-barcode: "\f02a";
-@fa-var-bars: "\f0c9";
-@fa-var-battery-0: "\f244";
-@fa-var-battery-1: "\f243";
-@fa-var-battery-2: "\f242";
-@fa-var-battery-3: "\f241";
-@fa-var-battery-4: "\f240";
-@fa-var-battery-empty: "\f244";
-@fa-var-battery-full: "\f240";
-@fa-var-battery-half: "\f242";
-@fa-var-battery-quarter: "\f243";
-@fa-var-battery-three-quarters: "\f241";
-@fa-var-bed: "\f236";
-@fa-var-beer: "\f0fc";
-@fa-var-behance: "\f1b4";
-@fa-var-behance-square: "\f1b5";
-@fa-var-bell: "\f0f3";
-@fa-var-bell-o: "\f0a2";
-@fa-var-bell-slash: "\f1f6";
-@fa-var-bell-slash-o: "\f1f7";
-@fa-var-bicycle: "\f206";
-@fa-var-binoculars: "\f1e5";
-@fa-var-birthday-cake: "\f1fd";
-@fa-var-bitbucket: "\f171";
-@fa-var-bitbucket-square: "\f172";
-@fa-var-bitcoin: "\f15a";
-@fa-var-black-tie: "\f27e";
-@fa-var-blind: "\f29d";
-@fa-var-bluetooth: "\f293";
-@fa-var-bluetooth-b: "\f294";
-@fa-var-bold: "\f032";
-@fa-var-bolt: "\f0e7";
-@fa-var-bomb: "\f1e2";
-@fa-var-book: "\f02d";
-@fa-var-bookmark: "\f02e";
-@fa-var-bookmark-o: "\f097";
-@fa-var-braille: "\f2a1";
-@fa-var-briefcase: "\f0b1";
-@fa-var-btc: "\f15a";
-@fa-var-bug: "\f188";
-@fa-var-building: "\f1ad";
-@fa-var-building-o: "\f0f7";
-@fa-var-bullhorn: "\f0a1";
-@fa-var-bullseye: "\f140";
-@fa-var-bus: "\f207";
-@fa-var-buysellads: "\f20d";
-@fa-var-cab: "\f1ba";
-@fa-var-calculator: "\f1ec";
-@fa-var-calendar: "\f073";
-@fa-var-calendar-check-o: "\f274";
-@fa-var-calendar-minus-o: "\f272";
-@fa-var-calendar-o: "\f133";
-@fa-var-calendar-plus-o: "\f271";
-@fa-var-calendar-times-o: "\f273";
-@fa-var-camera: "\f030";
-@fa-var-camera-retro: "\f083";
-@fa-var-car: "\f1b9";
-@fa-var-caret-down: "\f0d7";
-@fa-var-caret-left: "\f0d9";
-@fa-var-caret-right: "\f0da";
-@fa-var-caret-square-o-down: "\f150";
-@fa-var-caret-square-o-left: "\f191";
-@fa-var-caret-square-o-right: "\f152";
-@fa-var-caret-square-o-up: "\f151";
-@fa-var-caret-up: "\f0d8";
-@fa-var-cart-arrow-down: "\f218";
-@fa-var-cart-plus: "\f217";
-@fa-var-cc: "\f20a";
-@fa-var-cc-amex: "\f1f3";
-@fa-var-cc-diners-club: "\f24c";
-@fa-var-cc-discover: "\f1f2";
-@fa-var-cc-jcb: "\f24b";
-@fa-var-cc-mastercard: "\f1f1";
-@fa-var-cc-paypal: "\f1f4";
-@fa-var-cc-stripe: "\f1f5";
-@fa-var-cc-visa: "\f1f0";
-@fa-var-certificate: "\f0a3";
-@fa-var-chain: "\f0c1";
-@fa-var-chain-broken: "\f127";
-@fa-var-check: "\f00c";
-@fa-var-check-circle: "\f058";
-@fa-var-check-circle-o: "\f05d";
-@fa-var-check-square: "\f14a";
-@fa-var-check-square-o: "\f046";
-@fa-var-chevron-circle-down: "\f13a";
-@fa-var-chevron-circle-left: "\f137";
-@fa-var-chevron-circle-right: "\f138";
-@fa-var-chevron-circle-up: "\f139";
-@fa-var-chevron-down: "\f078";
-@fa-var-chevron-left: "\f053";
-@fa-var-chevron-right: "\f054";
-@fa-var-chevron-up: "\f077";
-@fa-var-child: "\f1ae";
-@fa-var-chrome: "\f268";
-@fa-var-circle: "\f111";
-@fa-var-circle-o: "\f10c";
-@fa-var-circle-o-notch: "\f1ce";
-@fa-var-circle-thin: "\f1db";
-@fa-var-clipboard: "\f0ea";
-@fa-var-clock-o: "\f017";
-@fa-var-clone: "\f24d";
-@fa-var-close: "\f00d";
-@fa-var-cloud: "\f0c2";
-@fa-var-cloud-download: "\f0ed";
-@fa-var-cloud-upload: "\f0ee";
-@fa-var-cny: "\f157";
-@fa-var-code: "\f121";
-@fa-var-code-fork: "\f126";
-@fa-var-codepen: "\f1cb";
-@fa-var-codiepie: "\f284";
-@fa-var-coffee: "\f0f4";
-@fa-var-cog: "\f013";
-@fa-var-cogs: "\f085";
-@fa-var-columns: "\f0db";
-@fa-var-comment: "\f075";
-@fa-var-comment-o: "\f0e5";
-@fa-var-commenting: "\f27a";
-@fa-var-commenting-o: "\f27b";
-@fa-var-comments: "\f086";
-@fa-var-comments-o: "\f0e6";
-@fa-var-compass: "\f14e";
-@fa-var-compress: "\f066";
-@fa-var-connectdevelop: "\f20e";
-@fa-var-contao: "\f26d";
-@fa-var-copy: "\f0c5";
-@fa-var-copyright: "\f1f9";
-@fa-var-creative-commons: "\f25e";
-@fa-var-credit-card: "\f09d";
-@fa-var-credit-card-alt: "\f283";
-@fa-var-crop: "\f125";
-@fa-var-crosshairs: "\f05b";
-@fa-var-css3: "\f13c";
-@fa-var-cube: "\f1b2";
-@fa-var-cubes: "\f1b3";
-@fa-var-cut: "\f0c4";
-@fa-var-cutlery: "\f0f5";
-@fa-var-dashboard: "\f0e4";
-@fa-var-dashcube: "\f210";
-@fa-var-database: "\f1c0";
-@fa-var-deaf: "\f2a4";
-@fa-var-deafness: "\f2a4";
-@fa-var-dedent: "\f03b";
-@fa-var-delicious: "\f1a5";
-@fa-var-desktop: "\f108";
-@fa-var-deviantart: "\f1bd";
-@fa-var-diamond: "\f219";
-@fa-var-digg: "\f1a6";
-@fa-var-dollar: "\f155";
-@fa-var-dot-circle-o: "\f192";
-@fa-var-download: "\f019";
-@fa-var-dribbble: "\f17d";
-@fa-var-dropbox: "\f16b";
-@fa-var-drupal: "\f1a9";
-@fa-var-edge: "\f282";
-@fa-var-edit: "\f044";
-@fa-var-eject: "\f052";
-@fa-var-ellipsis-h: "\f141";
-@fa-var-ellipsis-v: "\f142";
-@fa-var-empire: "\f1d1";
-@fa-var-envelope: "\f0e0";
-@fa-var-envelope-o: "\f003";
-@fa-var-envelope-square: "\f199";
-@fa-var-envira: "\f299";
-@fa-var-eraser: "\f12d";
-@fa-var-eur: "\f153";
-@fa-var-euro: "\f153";
-@fa-var-exchange: "\f0ec";
-@fa-var-exclamation: "\f12a";
-@fa-var-exclamation-circle: "\f06a";
-@fa-var-exclamation-triangle: "\f071";
-@fa-var-expand: "\f065";
-@fa-var-expeditedssl: "\f23e";
-@fa-var-external-link: "\f08e";
-@fa-var-external-link-square: "\f14c";
-@fa-var-eye: "\f06e";
-@fa-var-eye-slash: "\f070";
-@fa-var-eyedropper: "\f1fb";
-@fa-var-fa: "\f2b4";
-@fa-var-facebook: "\f09a";
-@fa-var-facebook-f: "\f09a";
-@fa-var-facebook-official: "\f230";
-@fa-var-facebook-square: "\f082";
-@fa-var-fast-backward: "\f049";
-@fa-var-fast-forward: "\f050";
-@fa-var-fax: "\f1ac";
-@fa-var-feed: "\f09e";
-@fa-var-female: "\f182";
-@fa-var-fighter-jet: "\f0fb";
-@fa-var-file: "\f15b";
-@fa-var-file-archive-o: "\f1c6";
-@fa-var-file-audio-o: "\f1c7";
-@fa-var-file-code-o: "\f1c9";
-@fa-var-file-excel-o: "\f1c3";
-@fa-var-file-image-o: "\f1c5";
-@fa-var-file-movie-o: "\f1c8";
-@fa-var-file-o: "\f016";
-@fa-var-file-pdf-o: "\f1c1";
-@fa-var-file-photo-o: "\f1c5";
-@fa-var-file-picture-o: "\f1c5";
-@fa-var-file-powerpoint-o: "\f1c4";
-@fa-var-file-sound-o: "\f1c7";
-@fa-var-file-text: "\f15c";
-@fa-var-file-text-o: "\f0f6";
-@fa-var-file-video-o: "\f1c8";
-@fa-var-file-word-o: "\f1c2";
-@fa-var-file-zip-o: "\f1c6";
-@fa-var-files-o: "\f0c5";
-@fa-var-film: "\f008";
-@fa-var-filter: "\f0b0";
-@fa-var-fire: "\f06d";
-@fa-var-fire-extinguisher: "\f134";
-@fa-var-firefox: "\f269";
-@fa-var-first-order: "\f2b0";
-@fa-var-flag: "\f024";
-@fa-var-flag-checkered: "\f11e";
-@fa-var-flag-o: "\f11d";
-@fa-var-flash: "\f0e7";
-@fa-var-flask: "\f0c3";
-@fa-var-flickr: "\f16e";
-@fa-var-floppy-o: "\f0c7";
-@fa-var-folder: "\f07b";
-@fa-var-folder-o: "\f114";
-@fa-var-folder-open: "\f07c";
-@fa-var-folder-open-o: "\f115";
-@fa-var-font: "\f031";
-@fa-var-font-awesome: "\f2b4";
-@fa-var-fonticons: "\f280";
-@fa-var-fort-awesome: "\f286";
-@fa-var-forumbee: "\f211";
-@fa-var-forward: "\f04e";
-@fa-var-foursquare: "\f180";
-@fa-var-frown-o: "\f119";
-@fa-var-futbol-o: "\f1e3";
-@fa-var-gamepad: "\f11b";
-@fa-var-gavel: "\f0e3";
-@fa-var-gbp: "\f154";
-@fa-var-ge: "\f1d1";
-@fa-var-gear: "\f013";
-@fa-var-gears: "\f085";
-@fa-var-genderless: "\f22d";
-@fa-var-get-pocket: "\f265";
-@fa-var-gg: "\f260";
-@fa-var-gg-circle: "\f261";
-@fa-var-gift: "\f06b";
-@fa-var-git: "\f1d3";
-@fa-var-git-square: "\f1d2";
-@fa-var-github: "\f09b";
-@fa-var-github-alt: "\f113";
-@fa-var-github-square: "\f092";
-@fa-var-gitlab: "\f296";
-@fa-var-gittip: "\f184";
-@fa-var-glass: "\f000";
-@fa-var-glide: "\f2a5";
-@fa-var-glide-g: "\f2a6";
-@fa-var-globe: "\f0ac";
-@fa-var-google: "\f1a0";
-@fa-var-google-plus: "\f0d5";
-@fa-var-google-plus-circle: "\f2b3";
-@fa-var-google-plus-official: "\f2b3";
-@fa-var-google-plus-square: "\f0d4";
-@fa-var-google-wallet: "\f1ee";
-@fa-var-graduation-cap: "\f19d";
-@fa-var-gratipay: "\f184";
-@fa-var-group: "\f0c0";
-@fa-var-h-square: "\f0fd";
-@fa-var-hacker-news: "\f1d4";
-@fa-var-hand-grab-o: "\f255";
-@fa-var-hand-lizard-o: "\f258";
-@fa-var-hand-o-down: "\f0a7";
-@fa-var-hand-o-left: "\f0a5";
-@fa-var-hand-o-right: "\f0a4";
-@fa-var-hand-o-up: "\f0a6";
-@fa-var-hand-paper-o: "\f256";
-@fa-var-hand-peace-o: "\f25b";
-@fa-var-hand-pointer-o: "\f25a";
-@fa-var-hand-rock-o: "\f255";
-@fa-var-hand-scissors-o: "\f257";
-@fa-var-hand-spock-o: "\f259";
-@fa-var-hand-stop-o: "\f256";
-@fa-var-hard-of-hearing: "\f2a4";
-@fa-var-hashtag: "\f292";
-@fa-var-hdd-o: "\f0a0";
-@fa-var-header: "\f1dc";
-@fa-var-headphones: "\f025";
-@fa-var-heart: "\f004";
-@fa-var-heart-o: "\f08a";
-@fa-var-heartbeat: "\f21e";
-@fa-var-history: "\f1da";
-@fa-var-home: "\f015";
-@fa-var-hospital-o: "\f0f8";
-@fa-var-hotel: "\f236";
-@fa-var-hourglass: "\f254";
-@fa-var-hourglass-1: "\f251";
-@fa-var-hourglass-2: "\f252";
-@fa-var-hourglass-3: "\f253";
-@fa-var-hourglass-end: "\f253";
-@fa-var-hourglass-half: "\f252";
-@fa-var-hourglass-o: "\f250";
-@fa-var-hourglass-start: "\f251";
-@fa-var-houzz: "\f27c";
-@fa-var-html5: "\f13b";
-@fa-var-i-cursor: "\f246";
-@fa-var-ils: "\f20b";
-@fa-var-image: "\f03e";
-@fa-var-inbox: "\f01c";
-@fa-var-indent: "\f03c";
-@fa-var-industry: "\f275";
-@fa-var-info: "\f129";
-@fa-var-info-circle: "\f05a";
-@fa-var-inr: "\f156";
-@fa-var-instagram: "\f16d";
-@fa-var-institution: "\f19c";
-@fa-var-internet-explorer: "\f26b";
-@fa-var-intersex: "\f224";
-@fa-var-ioxhost: "\f208";
-@fa-var-italic: "\f033";
-@fa-var-joomla: "\f1aa";
-@fa-var-jpy: "\f157";
-@fa-var-jsfiddle: "\f1cc";
-@fa-var-key: "\f084";
-@fa-var-keyboard-o: "\f11c";
-@fa-var-krw: "\f159";
-@fa-var-language: "\f1ab";
-@fa-var-laptop: "\f109";
-@fa-var-lastfm: "\f202";
-@fa-var-lastfm-square: "\f203";
-@fa-var-leaf: "\f06c";
-@fa-var-leanpub: "\f212";
-@fa-var-legal: "\f0e3";
-@fa-var-lemon-o: "\f094";
-@fa-var-level-down: "\f149";
-@fa-var-level-up: "\f148";
-@fa-var-life-bouy: "\f1cd";
-@fa-var-life-buoy: "\f1cd";
-@fa-var-life-ring: "\f1cd";
-@fa-var-life-saver: "\f1cd";
-@fa-var-lightbulb-o: "\f0eb";
-@fa-var-line-chart: "\f201";
-@fa-var-link: "\f0c1";
-@fa-var-linkedin: "\f0e1";
-@fa-var-linkedin-square: "\f08c";
-@fa-var-linux: "\f17c";
-@fa-var-list: "\f03a";
-@fa-var-list-alt: "\f022";
-@fa-var-list-ol: "\f0cb";
-@fa-var-list-ul: "\f0ca";
-@fa-var-location-arrow: "\f124";
-@fa-var-lock: "\f023";
-@fa-var-long-arrow-down: "\f175";
-@fa-var-long-arrow-left: "\f177";
-@fa-var-long-arrow-right: "\f178";
-@fa-var-long-arrow-up: "\f176";
-@fa-var-low-vision: "\f2a8";
-@fa-var-magic: "\f0d0";
-@fa-var-magnet: "\f076";
-@fa-var-mail-forward: "\f064";
-@fa-var-mail-reply: "\f112";
-@fa-var-mail-reply-all: "\f122";
-@fa-var-male: "\f183";
-@fa-var-map: "\f279";
-@fa-var-map-marker: "\f041";
-@fa-var-map-o: "\f278";
-@fa-var-map-pin: "\f276";
-@fa-var-map-signs: "\f277";
-@fa-var-mars: "\f222";
-@fa-var-mars-double: "\f227";
-@fa-var-mars-stroke: "\f229";
-@fa-var-mars-stroke-h: "\f22b";
-@fa-var-mars-stroke-v: "\f22a";
-@fa-var-maxcdn: "\f136";
-@fa-var-meanpath: "\f20c";
-@fa-var-medium: "\f23a";
-@fa-var-medkit: "\f0fa";
-@fa-var-meh-o: "\f11a";
-@fa-var-mercury: "\f223";
-@fa-var-microphone: "\f130";
-@fa-var-microphone-slash: "\f131";
-@fa-var-minus: "\f068";
-@fa-var-minus-circle: "\f056";
-@fa-var-minus-square: "\f146";
-@fa-var-minus-square-o: "\f147";
-@fa-var-mixcloud: "\f289";
-@fa-var-mobile: "\f10b";
-@fa-var-mobile-phone: "\f10b";
-@fa-var-modx: "\f285";
-@fa-var-money: "\f0d6";
-@fa-var-moon-o: "\f186";
-@fa-var-mortar-board: "\f19d";
-@fa-var-motorcycle: "\f21c";
-@fa-var-mouse-pointer: "\f245";
-@fa-var-music: "\f001";
-@fa-var-navicon: "\f0c9";
-@fa-var-neuter: "\f22c";
-@fa-var-newspaper-o: "\f1ea";
-@fa-var-object-group: "\f247";
-@fa-var-object-ungroup: "\f248";
-@fa-var-odnoklassniki: "\f263";
-@fa-var-odnoklassniki-square: "\f264";
-@fa-var-opencart: "\f23d";
-@fa-var-openid: "\f19b";
-@fa-var-opera: "\f26a";
-@fa-var-optin-monster: "\f23c";
-@fa-var-outdent: "\f03b";
-@fa-var-pagelines: "\f18c";
-@fa-var-paint-brush: "\f1fc";
-@fa-var-paper-plane: "\f1d8";
-@fa-var-paper-plane-o: "\f1d9";
-@fa-var-paperclip: "\f0c6";
-@fa-var-paragraph: "\f1dd";
-@fa-var-paste: "\f0ea";
-@fa-var-pause: "\f04c";
-@fa-var-pause-circle: "\f28b";
-@fa-var-pause-circle-o: "\f28c";
-@fa-var-paw: "\f1b0";
-@fa-var-paypal: "\f1ed";
-@fa-var-pencil: "\f040";
-@fa-var-pencil-square: "\f14b";
-@fa-var-pencil-square-o: "\f044";
-@fa-var-percent: "\f295";
-@fa-var-phone: "\f095";
-@fa-var-phone-square: "\f098";
-@fa-var-photo: "\f03e";
-@fa-var-picture-o: "\f03e";
-@fa-var-pie-chart: "\f200";
-@fa-var-pied-piper: "\f2ae";
-@fa-var-pied-piper-alt: "\f1a8";
-@fa-var-pied-piper-pp: "\f1a7";
-@fa-var-pinterest: "\f0d2";
-@fa-var-pinterest-p: "\f231";
-@fa-var-pinterest-square: "\f0d3";
-@fa-var-plane: "\f072";
-@fa-var-play: "\f04b";
-@fa-var-play-circle: "\f144";
-@fa-var-play-circle-o: "\f01d";
-@fa-var-plug: "\f1e6";
-@fa-var-plus: "\f067";
-@fa-var-plus-circle: "\f055";
-@fa-var-plus-square: "\f0fe";
-@fa-var-plus-square-o: "\f196";
-@fa-var-power-off: "\f011";
-@fa-var-print: "\f02f";
-@fa-var-product-hunt: "\f288";
-@fa-var-puzzle-piece: "\f12e";
-@fa-var-qq: "\f1d6";
-@fa-var-qrcode: "\f029";
-@fa-var-question: "\f128";
-@fa-var-question-circle: "\f059";
-@fa-var-question-circle-o: "\f29c";
-@fa-var-quote-left: "\f10d";
-@fa-var-quote-right: "\f10e";
-@fa-var-ra: "\f1d0";
-@fa-var-random: "\f074";
-@fa-var-rebel: "\f1d0";
-@fa-var-recycle: "\f1b8";
-@fa-var-reddit: "\f1a1";
-@fa-var-reddit-alien: "\f281";
-@fa-var-reddit-square: "\f1a2";
-@fa-var-refresh: "\f021";
-@fa-var-registered: "\f25d";
-@fa-var-remove: "\f00d";
-@fa-var-renren: "\f18b";
-@fa-var-reorder: "\f0c9";
-@fa-var-repeat: "\f01e";
-@fa-var-reply: "\f112";
-@fa-var-reply-all: "\f122";
-@fa-var-resistance: "\f1d0";
-@fa-var-retweet: "\f079";
-@fa-var-rmb: "\f157";
-@fa-var-road: "\f018";
-@fa-var-rocket: "\f135";
-@fa-var-rotate-left: "\f0e2";
-@fa-var-rotate-right: "\f01e";
-@fa-var-rouble: "\f158";
-@fa-var-rss: "\f09e";
-@fa-var-rss-square: "\f143";
-@fa-var-rub: "\f158";
-@fa-var-ruble: "\f158";
-@fa-var-rupee: "\f156";
-@fa-var-safari: "\f267";
-@fa-var-save: "\f0c7";
-@fa-var-scissors: "\f0c4";
-@fa-var-scribd: "\f28a";
-@fa-var-search: "\f002";
-@fa-var-search-minus: "\f010";
-@fa-var-search-plus: "\f00e";
-@fa-var-sellsy: "\f213";
-@fa-var-send: "\f1d8";
-@fa-var-send-o: "\f1d9";
-@fa-var-server: "\f233";
-@fa-var-share: "\f064";
-@fa-var-share-alt: "\f1e0";
-@fa-var-share-alt-square: "\f1e1";
-@fa-var-share-square: "\f14d";
-@fa-var-share-square-o: "\f045";
-@fa-var-shekel: "\f20b";
-@fa-var-sheqel: "\f20b";
-@fa-var-shield: "\f132";
-@fa-var-ship: "\f21a";
-@fa-var-shirtsinbulk: "\f214";
-@fa-var-shopping-bag: "\f290";
-@fa-var-shopping-basket: "\f291";
-@fa-var-shopping-cart: "\f07a";
-@fa-var-sign-in: "\f090";
-@fa-var-sign-language: "\f2a7";
-@fa-var-sign-out: "\f08b";
-@fa-var-signal: "\f012";
-@fa-var-signing: "\f2a7";
-@fa-var-simplybuilt: "\f215";
-@fa-var-sitemap: "\f0e8";
-@fa-var-skyatlas: "\f216";
-@fa-var-skype: "\f17e";
-@fa-var-slack: "\f198";
-@fa-var-sliders: "\f1de";
-@fa-var-slideshare: "\f1e7";
-@fa-var-smile-o: "\f118";
-@fa-var-snapchat: "\f2ab";
-@fa-var-snapchat-ghost: "\f2ac";
-@fa-var-snapchat-square: "\f2ad";
-@fa-var-soccer-ball-o: "\f1e3";
-@fa-var-sort: "\f0dc";
-@fa-var-sort-alpha-asc: "\f15d";
-@fa-var-sort-alpha-desc: "\f15e";
-@fa-var-sort-amount-asc: "\f160";
-@fa-var-sort-amount-desc: "\f161";
-@fa-var-sort-asc: "\f0de";
-@fa-var-sort-desc: "\f0dd";
-@fa-var-sort-down: "\f0dd";
-@fa-var-sort-numeric-asc: "\f162";
-@fa-var-sort-numeric-desc: "\f163";
-@fa-var-sort-up: "\f0de";
-@fa-var-soundcloud: "\f1be";
-@fa-var-space-shuttle: "\f197";
-@fa-var-spinner: "\f110";
-@fa-var-spoon: "\f1b1";
-@fa-var-spotify: "\f1bc";
-@fa-var-square: "\f0c8";
-@fa-var-square-o: "\f096";
-@fa-var-stack-exchange: "\f18d";
-@fa-var-stack-overflow: "\f16c";
-@fa-var-star: "\f005";
-@fa-var-star-half: "\f089";
-@fa-var-star-half-empty: "\f123";
-@fa-var-star-half-full: "\f123";
-@fa-var-star-half-o: "\f123";
-@fa-var-star-o: "\f006";
-@fa-var-steam: "\f1b6";
-@fa-var-steam-square: "\f1b7";
-@fa-var-step-backward: "\f048";
-@fa-var-step-forward: "\f051";
-@fa-var-stethoscope: "\f0f1";
-@fa-var-sticky-note: "\f249";
-@fa-var-sticky-note-o: "\f24a";
-@fa-var-stop: "\f04d";
-@fa-var-stop-circle: "\f28d";
-@fa-var-stop-circle-o: "\f28e";
-@fa-var-street-view: "\f21d";
-@fa-var-strikethrough: "\f0cc";
-@fa-var-stumbleupon: "\f1a4";
-@fa-var-stumbleupon-circle: "\f1a3";
-@fa-var-subscript: "\f12c";
-@fa-var-subway: "\f239";
-@fa-var-suitcase: "\f0f2";
-@fa-var-sun-o: "\f185";
-@fa-var-superscript: "\f12b";
-@fa-var-support: "\f1cd";
-@fa-var-table: "\f0ce";
-@fa-var-tablet: "\f10a";
-@fa-var-tachometer: "\f0e4";
-@fa-var-tag: "\f02b";
-@fa-var-tags: "\f02c";
-@fa-var-tasks: "\f0ae";
-@fa-var-taxi: "\f1ba";
-@fa-var-television: "\f26c";
-@fa-var-tencent-weibo: "\f1d5";
-@fa-var-terminal: "\f120";
-@fa-var-text-height: "\f034";
-@fa-var-text-width: "\f035";
-@fa-var-th: "\f00a";
-@fa-var-th-large: "\f009";
-@fa-var-th-list: "\f00b";
-@fa-var-themeisle: "\f2b2";
-@fa-var-thumb-tack: "\f08d";
-@fa-var-thumbs-down: "\f165";
-@fa-var-thumbs-o-down: "\f088";
-@fa-var-thumbs-o-up: "\f087";
-@fa-var-thumbs-up: "\f164";
-@fa-var-ticket: "\f145";
-@fa-var-times: "\f00d";
-@fa-var-times-circle: "\f057";
-@fa-var-times-circle-o: "\f05c";
-@fa-var-tint: "\f043";
-@fa-var-toggle-down: "\f150";
-@fa-var-toggle-left: "\f191";
-@fa-var-toggle-off: "\f204";
-@fa-var-toggle-on: "\f205";
-@fa-var-toggle-right: "\f152";
-@fa-var-toggle-up: "\f151";
-@fa-var-trademark: "\f25c";
-@fa-var-train: "\f238";
-@fa-var-transgender: "\f224";
-@fa-var-transgender-alt: "\f225";
-@fa-var-trash: "\f1f8";
-@fa-var-trash-o: "\f014";
-@fa-var-tree: "\f1bb";
-@fa-var-trello: "\f181";
-@fa-var-tripadvisor: "\f262";
-@fa-var-trophy: "\f091";
-@fa-var-truck: "\f0d1";
-@fa-var-try: "\f195";
-@fa-var-tty: "\f1e4";
-@fa-var-tumblr: "\f173";
-@fa-var-tumblr-square: "\f174";
-@fa-var-turkish-lira: "\f195";
-@fa-var-tv: "\f26c";
-@fa-var-twitch: "\f1e8";
-@fa-var-twitter: "\f099";
-@fa-var-twitter-square: "\f081";
-@fa-var-umbrella: "\f0e9";
-@fa-var-underline: "\f0cd";
-@fa-var-undo: "\f0e2";
-@fa-var-universal-access: "\f29a";
-@fa-var-university: "\f19c";
-@fa-var-unlink: "\f127";
-@fa-var-unlock: "\f09c";
-@fa-var-unlock-alt: "\f13e";
-@fa-var-unsorted: "\f0dc";
-@fa-var-upload: "\f093";
-@fa-var-usb: "\f287";
-@fa-var-usd: "\f155";
-@fa-var-user: "\f007";
-@fa-var-user-md: "\f0f0";
-@fa-var-user-plus: "\f234";
-@fa-var-user-secret: "\f21b";
-@fa-var-user-times: "\f235";
-@fa-var-users: "\f0c0";
-@fa-var-venus: "\f221";
-@fa-var-venus-double: "\f226";
-@fa-var-venus-mars: "\f228";
-@fa-var-viacoin: "\f237";
-@fa-var-viadeo: "\f2a9";
-@fa-var-viadeo-square: "\f2aa";
-@fa-var-video-camera: "\f03d";
-@fa-var-vimeo: "\f27d";
-@fa-var-vimeo-square: "\f194";
-@fa-var-vine: "\f1ca";
-@fa-var-vk: "\f189";
-@fa-var-volume-control-phone: "\f2a0";
-@fa-var-volume-down: "\f027";
-@fa-var-volume-off: "\f026";
-@fa-var-volume-up: "\f028";
-@fa-var-warning: "\f071";
-@fa-var-wechat: "\f1d7";
-@fa-var-weibo: "\f18a";
-@fa-var-weixin: "\f1d7";
-@fa-var-whatsapp: "\f232";
-@fa-var-wheelchair: "\f193";
-@fa-var-wheelchair-alt: "\f29b";
-@fa-var-wifi: "\f1eb";
-@fa-var-wikipedia-w: "\f266";
-@fa-var-windows: "\f17a";
-@fa-var-won: "\f159";
-@fa-var-wordpress: "\f19a";
-@fa-var-wpbeginner: "\f297";
-@fa-var-wpforms: "\f298";
-@fa-var-wrench: "\f0ad";
-@fa-var-xing: "\f168";
-@fa-var-xing-square: "\f169";
-@fa-var-y-combinator: "\f23b";
-@fa-var-y-combinator-square: "\f1d4";
-@fa-var-yahoo: "\f19e";
-@fa-var-yc: "\f23b";
-@fa-var-yc-square: "\f1d4";
-@fa-var-yelp: "\f1e9";
-@fa-var-yen: "\f157";
-@fa-var-yoast: "\f2b1";
-@fa-var-youtube: "\f167";
-@fa-var-youtube-play: "\f16a";
-@fa-var-youtube-square: "\f166";
-
diff --git a/hubs/static/font-awesome-4.6.3/scss/_animated.scss b/hubs/static/font-awesome-4.6.3/scss/_animated.scss
deleted file mode 100644
index 8a020db..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_animated.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-// Spinning Icons
-// --------------------------
-
-.#{$fa-css-prefix}-spin {
-  -webkit-animation: fa-spin 2s infinite linear;
-          animation: fa-spin 2s infinite linear;
-}
-
-.#{$fa-css-prefix}-pulse {
-  -webkit-animation: fa-spin 1s infinite steps(8);
-          animation: fa-spin 1s infinite steps(8);
-}
-
-@-webkit-keyframes fa-spin {
-  0% {
-    -webkit-transform: rotate(0deg);
-            transform: rotate(0deg);
-  }
-  100% {
-    -webkit-transform: rotate(359deg);
-            transform: rotate(359deg);
-  }
-}
-
-@keyframes fa-spin {
-  0% {
-    -webkit-transform: rotate(0deg);
-            transform: rotate(0deg);
-  }
-  100% {
-    -webkit-transform: rotate(359deg);
-            transform: rotate(359deg);
-  }
-}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_bordered-pulled.scss b/hubs/static/font-awesome-4.6.3/scss/_bordered-pulled.scss
deleted file mode 100644
index d4b85a0..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_bordered-pulled.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-// Bordered & Pulled
-// -------------------------
-
-.#{$fa-css-prefix}-border {
-  padding: .2em .25em .15em;
-  border: solid .08em $fa-border-color;
-  border-radius: .1em;
-}
-
-.#{$fa-css-prefix}-pull-left { float: left; }
-.#{$fa-css-prefix}-pull-right { float: right; }
-
-.#{$fa-css-prefix} {
-  &.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
-  &.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
-}
-
-/* Deprecated as of 4.4.0 */
-.pull-right { float: right; }
-.pull-left { float: left; }
-
-.#{$fa-css-prefix} {
-  &.pull-left { margin-right: .3em; }
-  &.pull-right { margin-left: .3em; }
-}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_core.scss b/hubs/static/font-awesome-4.6.3/scss/_core.scss
deleted file mode 100644
index 7425ef8..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_core.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-// Base Class Definition
-// -------------------------
-
-.#{$fa-css-prefix} {
-  display: inline-block;
-  font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
-  font-size: inherit; // can't have font-size inherit on line above, so need to override
-  text-rendering: auto; // optimizelegibility throws things off #1094
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-
-}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_fixed-width.scss b/hubs/static/font-awesome-4.6.3/scss/_fixed-width.scss
deleted file mode 100644
index b221c98..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_fixed-width.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-// Fixed Width Icons
-// -------------------------
-.#{$fa-css-prefix}-fw {
-  width: (18em / 14);
-  text-align: center;
-}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_icons.scss b/hubs/static/font-awesome-4.6.3/scss/_icons.scss
deleted file mode 100644
index 2944344..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_icons.scss
+++ /dev/null
@@ -1,733 +0,0 @@
-/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
-   readers do not read off random characters that represent icons */
-
-.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; }
-.#{$fa-css-prefix}-music:before { content: $fa-var-music; }
-.#{$fa-css-prefix}-search:before { content: $fa-var-search; }
-.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; }
-.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; }
-.#{$fa-css-prefix}-star:before { content: $fa-var-star; }
-.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; }
-.#{$fa-css-prefix}-user:before { content: $fa-var-user; }
-.#{$fa-css-prefix}-film:before { content: $fa-var-film; }
-.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; }
-.#{$fa-css-prefix}-th:before { content: $fa-var-th; }
-.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; }
-.#{$fa-css-prefix}-check:before { content: $fa-var-check; }
-.#{$fa-css-prefix}-remove:before,
-.#{$fa-css-prefix}-close:before,
-.#{$fa-css-prefix}-times:before { content: $fa-var-times; }
-.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; }
-.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; }
-.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; }
-.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; }
-.#{$fa-css-prefix}-gear:before,
-.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; }
-.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; }
-.#{$fa-css-prefix}-home:before { content: $fa-var-home; }
-.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; }
-.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; }
-.#{$fa-css-prefix}-road:before { content: $fa-var-road; }
-.#{$fa-css-prefix}-download:before { content: $fa-var-download; }
-.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; }
-.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; }
-.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; }
-.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; }
-.#{$fa-css-prefix}-rotate-right:before,
-.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; }
-.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; }
-.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; }
-.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; }
-.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; }
-.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; }
-.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; }
-.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; }
-.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; }
-.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; }
-.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; }
-.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; }
-.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; }
-.#{$fa-css-prefix}-book:before { content: $fa-var-book; }
-.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; }
-.#{$fa-css-prefix}-print:before { content: $fa-var-print; }
-.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; }
-.#{$fa-css-prefix}-font:before { content: $fa-var-font; }
-.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; }
-.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; }
-.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; }
-.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; }
-.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; }
-.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; }
-.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; }
-.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; }
-.#{$fa-css-prefix}-list:before { content: $fa-var-list; }
-.#{$fa-css-prefix}-dedent:before,
-.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; }
-.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; }
-.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; }
-.#{$fa-css-prefix}-photo:before,
-.#{$fa-css-prefix}-image:before,
-.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; }
-.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; }
-.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; }
-.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; }
-.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; }
-.#{$fa-css-prefix}-edit:before,
-.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; }
-.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; }
-.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; }
-.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; }
-.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; }
-.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; }
-.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; }
-.#{$fa-css-prefix}-play:before { content: $fa-var-play; }
-.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; }
-.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; }
-.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; }
-.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; }
-.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; }
-.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; }
-.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; }
-.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; }
-.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; }
-.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; }
-.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; }
-.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; }
-.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; }
-.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; }
-.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; }
-.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; }
-.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; }
-.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; }
-.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; }
-.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; }
-.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; }
-.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; }
-.#{$fa-css-prefix}-mail-forward:before,
-.#{$fa-css-prefix}-share:before { content: $fa-var-share; }
-.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; }
-.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; }
-.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; }
-.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; }
-.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; }
-.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; }
-.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; }
-.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; }
-.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; }
-.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; }
-.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; }
-.#{$fa-css-prefix}-warning:before,
-.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; }
-.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; }
-.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; }
-.#{$fa-css-prefix}-random:before { content: $fa-var-random; }
-.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; }
-.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; }
-.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; }
-.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; }
-.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; }
-.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; }
-.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; }
-.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; }
-.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; }
-.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; }
-.#{$fa-css-prefix}-bar-chart-o:before,
-.#{$fa-css-prefix}-bar-chart:before { content: $fa-var-bar-chart; }
-.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; }
-.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; }
-.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; }
-.#{$fa-css-prefix}-key:before { content: $fa-var-key; }
-.#{$fa-css-prefix}-gears:before,
-.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; }
-.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; }
-.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; }
-.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; }
-.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; }
-.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; }
-.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; }
-.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; }
-.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; }
-.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; }
-.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; }
-.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; }
-.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; }
-.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; }
-.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; }
-.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; }
-.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; }
-.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; }
-.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; }
-.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; }
-.#{$fa-css-prefix}-facebook-f:before,
-.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; }
-.#{$fa-css-prefix}-github:before { content: $fa-var-github; }
-.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; }
-.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; }
-.#{$fa-css-prefix}-feed:before,
-.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; }
-.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; }
-.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; }
-.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; }
-.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; }
-.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; }
-.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; }
-.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; }
-.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; }
-.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; }
-.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; }
-.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; }
-.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; }
-.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; }
-.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; }
-.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; }
-.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; }
-.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; }
-.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; }
-.#{$fa-css-prefix}-group:before,
-.#{$fa-css-prefix}-users:before { content: $fa-var-users; }
-.#{$fa-css-prefix}-chain:before,
-.#{$fa-css-prefix}-link:before { content: $fa-var-link; }
-.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; }
-.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; }
-.#{$fa-css-prefix}-cut:before,
-.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; }
-.#{$fa-css-prefix}-copy:before,
-.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; }
-.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; }
-.#{$fa-css-prefix}-save:before,
-.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; }
-.#{$fa-css-prefix}-square:before { content: $fa-var-square; }
-.#{$fa-css-prefix}-navicon:before,
-.#{$fa-css-prefix}-reorder:before,
-.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; }
-.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; }
-.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; }
-.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; }
-.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; }
-.#{$fa-css-prefix}-table:before { content: $fa-var-table; }
-.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; }
-.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; }
-.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; }
-.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; }
-.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; }
-.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; }
-.#{$fa-css-prefix}-money:before { content: $fa-var-money; }
-.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; }
-.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; }
-.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; }
-.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; }
-.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; }
-.#{$fa-css-prefix}-unsorted:before,
-.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; }
-.#{$fa-css-prefix}-sort-down:before,
-.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; }
-.#{$fa-css-prefix}-sort-up:before,
-.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; }
-.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; }
-.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; }
-.#{$fa-css-prefix}-rotate-left:before,
-.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; }
-.#{$fa-css-prefix}-legal:before,
-.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; }
-.#{$fa-css-prefix}-dashboard:before,
-.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; }
-.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; }
-.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; }
-.#{$fa-css-prefix}-flash:before,
-.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; }
-.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; }
-.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; }
-.#{$fa-css-prefix}-paste:before,
-.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; }
-.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; }
-.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; }
-.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; }
-.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; }
-.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; }
-.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; }
-.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; }
-.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; }
-.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; }
-.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; }
-.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; }
-.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; }
-.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; }
-.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; }
-.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; }
-.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; }
-.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; }
-.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; }
-.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; }
-.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; }
-.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; }
-.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; }
-.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; }
-.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; }
-.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; }
-.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; }
-.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; }
-.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; }
-.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; }
-.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; }
-.#{$fa-css-prefix}-mobile-phone:before,
-.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; }
-.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; }
-.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; }
-.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; }
-.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; }
-.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; }
-.#{$fa-css-prefix}-mail-reply:before,
-.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; }
-.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; }
-.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; }
-.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; }
-.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; }
-.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; }
-.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; }
-.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; }
-.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; }
-.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; }
-.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; }
-.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; }
-.#{$fa-css-prefix}-code:before { content: $fa-var-code; }
-.#{$fa-css-prefix}-mail-reply-all:before,
-.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; }
-.#{$fa-css-prefix}-star-half-empty:before,
-.#{$fa-css-prefix}-star-half-full:before,
-.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; }
-.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; }
-.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; }
-.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; }
-.#{$fa-css-prefix}-unlink:before,
-.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; }
-.#{$fa-css-prefix}-question:before { content: $fa-var-question; }
-.#{$fa-css-prefix}-info:before { content: $fa-var-info; }
-.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; }
-.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; }
-.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; }
-.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; }
-.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; }
-.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; }
-.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; }
-.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; }
-.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; }
-.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; }
-.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; }
-.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; }
-.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; }
-.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; }
-.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; }
-.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; }
-.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; }
-.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; }
-.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; }
-.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; }
-.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; }
-.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; }
-.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; }
-.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; }
-.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; }
-.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; }
-.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; }
-.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; }
-.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; }
-.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; }
-.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; }
-.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; }
-.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; }
-.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; }
-.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; }
-.#{$fa-css-prefix}-toggle-down:before,
-.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; }
-.#{$fa-css-prefix}-toggle-up:before,
-.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; }
-.#{$fa-css-prefix}-toggle-right:before,
-.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; }
-.#{$fa-css-prefix}-euro:before,
-.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; }
-.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; }
-.#{$fa-css-prefix}-dollar:before,
-.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; }
-.#{$fa-css-prefix}-rupee:before,
-.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; }
-.#{$fa-css-prefix}-cny:before,
-.#{$fa-css-prefix}-rmb:before,
-.#{$fa-css-prefix}-yen:before,
-.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; }
-.#{$fa-css-prefix}-ruble:before,
-.#{$fa-css-prefix}-rouble:before,
-.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; }
-.#{$fa-css-prefix}-won:before,
-.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; }
-.#{$fa-css-prefix}-bitcoin:before,
-.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; }
-.#{$fa-css-prefix}-file:before { content: $fa-var-file; }
-.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; }
-.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; }
-.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; }
-.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; }
-.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; }
-.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; }
-.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; }
-.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; }
-.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; }
-.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; }
-.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; }
-.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; }
-.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; }
-.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; }
-.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; }
-.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; }
-.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; }
-.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; }
-.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; }
-.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; }
-.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; }
-.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; }
-.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; }
-.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; }
-.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; }
-.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; }
-.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; }
-.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; }
-.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; }
-.#{$fa-css-prefix}-android:before { content: $fa-var-android; }
-.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; }
-.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; }
-.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; }
-.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; }
-.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; }
-.#{$fa-css-prefix}-female:before { content: $fa-var-female; }
-.#{$fa-css-prefix}-male:before { content: $fa-var-male; }
-.#{$fa-css-prefix}-gittip:before,
-.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; }
-.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; }
-.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; }
-.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; }
-.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; }
-.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; }
-.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; }
-.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; }
-.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; }
-.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; }
-.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; }
-.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; }
-.#{$fa-css-prefix}-toggle-left:before,
-.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; }
-.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; }
-.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; }
-.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; }
-.#{$fa-css-prefix}-turkish-lira:before,
-.#{$fa-css-prefix}-try:before { content: $fa-var-try; }
-.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; }
-.#{$fa-css-prefix}-space-shuttle:before { content: $fa-var-space-shuttle; }
-.#{$fa-css-prefix}-slack:before { content: $fa-var-slack; }
-.#{$fa-css-prefix}-envelope-square:before { content: $fa-var-envelope-square; }
-.#{$fa-css-prefix}-wordpress:before { content: $fa-var-wordpress; }
-.#{$fa-css-prefix}-openid:before { content: $fa-var-openid; }
-.#{$fa-css-prefix}-institution:before,
-.#{$fa-css-prefix}-bank:before,
-.#{$fa-css-prefix}-university:before { content: $fa-var-university; }
-.#{$fa-css-prefix}-mortar-board:before,
-.#{$fa-css-prefix}-graduation-cap:before { content: $fa-var-graduation-cap; }
-.#{$fa-css-prefix}-yahoo:before { content: $fa-var-yahoo; }
-.#{$fa-css-prefix}-google:before { content: $fa-var-google; }
-.#{$fa-css-prefix}-reddit:before { content: $fa-var-reddit; }
-.#{$fa-css-prefix}-reddit-square:before { content: $fa-var-reddit-square; }
-.#{$fa-css-prefix}-stumbleupon-circle:before { content: $fa-var-stumbleupon-circle; }
-.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; }
-.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; }
-.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; }
-.#{$fa-css-prefix}-pied-piper-pp:before { content: $fa-var-pied-piper-pp; }
-.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; }
-.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; }
-.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; }
-.#{$fa-css-prefix}-language:before { content: $fa-var-language; }
-.#{$fa-css-prefix}-fax:before { content: $fa-var-fax; }
-.#{$fa-css-prefix}-building:before { content: $fa-var-building; }
-.#{$fa-css-prefix}-child:before { content: $fa-var-child; }
-.#{$fa-css-prefix}-paw:before { content: $fa-var-paw; }
-.#{$fa-css-prefix}-spoon:before { content: $fa-var-spoon; }
-.#{$fa-css-prefix}-cube:before { content: $fa-var-cube; }
-.#{$fa-css-prefix}-cubes:before { content: $fa-var-cubes; }
-.#{$fa-css-prefix}-behance:before { content: $fa-var-behance; }
-.#{$fa-css-prefix}-behance-square:before { content: $fa-var-behance-square; }
-.#{$fa-css-prefix}-steam:before { content: $fa-var-steam; }
-.#{$fa-css-prefix}-steam-square:before { content: $fa-var-steam-square; }
-.#{$fa-css-prefix}-recycle:before { content: $fa-var-recycle; }
-.#{$fa-css-prefix}-automobile:before,
-.#{$fa-css-prefix}-car:before { content: $fa-var-car; }
-.#{$fa-css-prefix}-cab:before,
-.#{$fa-css-prefix}-taxi:before { content: $fa-var-taxi; }
-.#{$fa-css-prefix}-tree:before { content: $fa-var-tree; }
-.#{$fa-css-prefix}-spotify:before { content: $fa-var-spotify; }
-.#{$fa-css-prefix}-deviantart:before { content: $fa-var-deviantart; }
-.#{$fa-css-prefix}-soundcloud:before { content: $fa-var-soundcloud; }
-.#{$fa-css-prefix}-database:before { content: $fa-var-database; }
-.#{$fa-css-prefix}-file-pdf-o:before { content: $fa-var-file-pdf-o; }
-.#{$fa-css-prefix}-file-word-o:before { content: $fa-var-file-word-o; }
-.#{$fa-css-prefix}-file-excel-o:before { content: $fa-var-file-excel-o; }
-.#{$fa-css-prefix}-file-powerpoint-o:before { content: $fa-var-file-powerpoint-o; }
-.#{$fa-css-prefix}-file-photo-o:before,
-.#{$fa-css-prefix}-file-picture-o:before,
-.#{$fa-css-prefix}-file-image-o:before { content: $fa-var-file-image-o; }
-.#{$fa-css-prefix}-file-zip-o:before,
-.#{$fa-css-prefix}-file-archive-o:before { content: $fa-var-file-archive-o; }
-.#{$fa-css-prefix}-file-sound-o:before,
-.#{$fa-css-prefix}-file-audio-o:before { content: $fa-var-file-audio-o; }
-.#{$fa-css-prefix}-file-movie-o:before,
-.#{$fa-css-prefix}-file-video-o:before { content: $fa-var-file-video-o; }
-.#{$fa-css-prefix}-file-code-o:before { content: $fa-var-file-code-o; }
-.#{$fa-css-prefix}-vine:before { content: $fa-var-vine; }
-.#{$fa-css-prefix}-codepen:before { content: $fa-var-codepen; }
-.#{$fa-css-prefix}-jsfiddle:before { content: $fa-var-jsfiddle; }
-.#{$fa-css-prefix}-life-bouy:before,
-.#{$fa-css-prefix}-life-buoy:before,
-.#{$fa-css-prefix}-life-saver:before,
-.#{$fa-css-prefix}-support:before,
-.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; }
-.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; }
-.#{$fa-css-prefix}-ra:before,
-.#{$fa-css-prefix}-resistance:before,
-.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; }
-.#{$fa-css-prefix}-ge:before,
-.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; }
-.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; }
-.#{$fa-css-prefix}-git:before { content: $fa-var-git; }
-.#{$fa-css-prefix}-y-combinator-square:before,
-.#{$fa-css-prefix}-yc-square:before,
-.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; }
-.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; }
-.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; }
-.#{$fa-css-prefix}-wechat:before,
-.#{$fa-css-prefix}-weixin:before { content: $fa-var-weixin; }
-.#{$fa-css-prefix}-send:before,
-.#{$fa-css-prefix}-paper-plane:before { content: $fa-var-paper-plane; }
-.#{$fa-css-prefix}-send-o:before,
-.#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; }
-.#{$fa-css-prefix}-history:before { content: $fa-var-history; }
-.#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; }
-.#{$fa-css-prefix}-header:before { content: $fa-var-header; }
-.#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; }
-.#{$fa-css-prefix}-sliders:before { content: $fa-var-sliders; }
-.#{$fa-css-prefix}-share-alt:before { content: $fa-var-share-alt; }
-.#{$fa-css-prefix}-share-alt-square:before { content: $fa-var-share-alt-square; }
-.#{$fa-css-prefix}-bomb:before { content: $fa-var-bomb; }
-.#{$fa-css-prefix}-soccer-ball-o:before,
-.#{$fa-css-prefix}-futbol-o:before { content: $fa-var-futbol-o; }
-.#{$fa-css-prefix}-tty:before { content: $fa-var-tty; }
-.#{$fa-css-prefix}-binoculars:before { content: $fa-var-binoculars; }
-.#{$fa-css-prefix}-plug:before { content: $fa-var-plug; }
-.#{$fa-css-prefix}-slideshare:before { content: $fa-var-slideshare; }
-.#{$fa-css-prefix}-twitch:before { content: $fa-var-twitch; }
-.#{$fa-css-prefix}-yelp:before { content: $fa-var-yelp; }
-.#{$fa-css-prefix}-newspaper-o:before { content: $fa-var-newspaper-o; }
-.#{$fa-css-prefix}-wifi:before { content: $fa-var-wifi; }
-.#{$fa-css-prefix}-calculator:before { content: $fa-var-calculator; }
-.#{$fa-css-prefix}-paypal:before { content: $fa-var-paypal; }
-.#{$fa-css-prefix}-google-wallet:before { content: $fa-var-google-wallet; }
-.#{$fa-css-prefix}-cc-visa:before { content: $fa-var-cc-visa; }
-.#{$fa-css-prefix}-cc-mastercard:before { content: $fa-var-cc-mastercard; }
-.#{$fa-css-prefix}-cc-discover:before { content: $fa-var-cc-discover; }
-.#{$fa-css-prefix}-cc-amex:before { content: $fa-var-cc-amex; }
-.#{$fa-css-prefix}-cc-paypal:before { content: $fa-var-cc-paypal; }
-.#{$fa-css-prefix}-cc-stripe:before { content: $fa-var-cc-stripe; }
-.#{$fa-css-prefix}-bell-slash:before { content: $fa-var-bell-slash; }
-.#{$fa-css-prefix}-bell-slash-o:before { content: $fa-var-bell-slash-o; }
-.#{$fa-css-prefix}-trash:before { content: $fa-var-trash; }
-.#{$fa-css-prefix}-copyright:before { content: $fa-var-copyright; }
-.#{$fa-css-prefix}-at:before { content: $fa-var-at; }
-.#{$fa-css-prefix}-eyedropper:before { content: $fa-var-eyedropper; }
-.#{$fa-css-prefix}-paint-brush:before { content: $fa-var-paint-brush; }
-.#{$fa-css-prefix}-birthday-cake:before { content: $fa-var-birthday-cake; }
-.#{$fa-css-prefix}-area-chart:before { content: $fa-var-area-chart; }
-.#{$fa-css-prefix}-pie-chart:before { content: $fa-var-pie-chart; }
-.#{$fa-css-prefix}-line-chart:before { content: $fa-var-line-chart; }
-.#{$fa-css-prefix}-lastfm:before { content: $fa-var-lastfm; }
-.#{$fa-css-prefix}-lastfm-square:before { content: $fa-var-lastfm-square; }
-.#{$fa-css-prefix}-toggle-off:before { content: $fa-var-toggle-off; }
-.#{$fa-css-prefix}-toggle-on:before { content: $fa-var-toggle-on; }
-.#{$fa-css-prefix}-bicycle:before { content: $fa-var-bicycle; }
-.#{$fa-css-prefix}-bus:before { content: $fa-var-bus; }
-.#{$fa-css-prefix}-ioxhost:before { content: $fa-var-ioxhost; }
-.#{$fa-css-prefix}-angellist:before { content: $fa-var-angellist; }
-.#{$fa-css-prefix}-cc:before { content: $fa-var-cc; }
-.#{$fa-css-prefix}-shekel:before,
-.#{$fa-css-prefix}-sheqel:before,
-.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; }
-.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; }
-.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; }
-.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; }
-.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; }
-.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; }
-.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; }
-.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; }
-.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; }
-.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; }
-.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; }
-.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; }
-.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; }
-.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; }
-.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; }
-.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; }
-.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; }
-.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; }
-.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; }
-.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; }
-.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; }
-.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; }
-.#{$fa-css-prefix}-intersex:before,
-.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; }
-.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; }
-.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; }
-.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; }
-.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; }
-.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; }
-.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; }
-.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; }
-.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; }
-.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; }
-.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; }
-.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; }
-.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; }
-.#{$fa-css-prefix}-server:before { content: $fa-var-server; }
-.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; }
-.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; }
-.#{$fa-css-prefix}-hotel:before,
-.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; }
-.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; }
-.#{$fa-css-prefix}-train:before { content: $fa-var-train; }
-.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; }
-.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; }
-.#{$fa-css-prefix}-yc:before,
-.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; }
-.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; }
-.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; }
-.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; }
-.#{$fa-css-prefix}-battery-4:before,
-.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; }
-.#{$fa-css-prefix}-battery-3:before,
-.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; }
-.#{$fa-css-prefix}-battery-2:before,
-.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; }
-.#{$fa-css-prefix}-battery-1:before,
-.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; }
-.#{$fa-css-prefix}-battery-0:before,
-.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; }
-.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; }
-.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; }
-.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; }
-.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; }
-.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; }
-.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; }
-.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; }
-.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; }
-.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; }
-.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; }
-.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; }
-.#{$fa-css-prefix}-hourglass-1:before,
-.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; }
-.#{$fa-css-prefix}-hourglass-2:before,
-.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; }
-.#{$fa-css-prefix}-hourglass-3:before,
-.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; }
-.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; }
-.#{$fa-css-prefix}-hand-grab-o:before,
-.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; }
-.#{$fa-css-prefix}-hand-stop-o:before,
-.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; }
-.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; }
-.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; }
-.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; }
-.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; }
-.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; }
-.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; }
-.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; }
-.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; }
-.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; }
-.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; }
-.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; }
-.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; }
-.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; }
-.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; }
-.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; }
-.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; }
-.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; }
-.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; }
-.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; }
-.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; }
-.#{$fa-css-prefix}-tv:before,
-.#{$fa-css-prefix}-television:before { content: $fa-var-television; }
-.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; }
-.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; }
-.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; }
-.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; }
-.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; }
-.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; }
-.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; }
-.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; }
-.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; }
-.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; }
-.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; }
-.#{$fa-css-prefix}-map:before { content: $fa-var-map; }
-.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; }
-.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; }
-.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; }
-.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; }
-.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; }
-.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; }
-.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; }
-.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; }
-.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; }
-.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; }
-.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; }
-.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; }
-.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; }
-.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; }
-.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; }
-.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; }
-.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; }
-.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; }
-.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; }
-.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; }
-.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; }
-.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; }
-.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; }
-.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; }
-.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; }
-.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; }
-.#{$fa-css-prefix}-gitlab:before { content: $fa-var-gitlab; }
-.#{$fa-css-prefix}-wpbeginner:before { content: $fa-var-wpbeginner; }
-.#{$fa-css-prefix}-wpforms:before { content: $fa-var-wpforms; }
-.#{$fa-css-prefix}-envira:before { content: $fa-var-envira; }
-.#{$fa-css-prefix}-universal-access:before { content: $fa-var-universal-access; }
-.#{$fa-css-prefix}-wheelchair-alt:before { content: $fa-var-wheelchair-alt; }
-.#{$fa-css-prefix}-question-circle-o:before { content: $fa-var-question-circle-o; }
-.#{$fa-css-prefix}-blind:before { content: $fa-var-blind; }
-.#{$fa-css-prefix}-audio-description:before { content: $fa-var-audio-description; }
-.#{$fa-css-prefix}-volume-control-phone:before { content: $fa-var-volume-control-phone; }
-.#{$fa-css-prefix}-braille:before { content: $fa-var-braille; }
-.#{$fa-css-prefix}-assistive-listening-systems:before { content: $fa-var-assistive-listening-systems; }
-.#{$fa-css-prefix}-asl-interpreting:before,
-.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: $fa-var-american-sign-language-interpreting; }
-.#{$fa-css-prefix}-deafness:before,
-.#{$fa-css-prefix}-hard-of-hearing:before,
-.#{$fa-css-prefix}-deaf:before { content: $fa-var-deaf; }
-.#{$fa-css-prefix}-glide:before { content: $fa-var-glide; }
-.#{$fa-css-prefix}-glide-g:before { content: $fa-var-glide-g; }
-.#{$fa-css-prefix}-signing:before,
-.#{$fa-css-prefix}-sign-language:before { content: $fa-var-sign-language; }
-.#{$fa-css-prefix}-low-vision:before { content: $fa-var-low-vision; }
-.#{$fa-css-prefix}-viadeo:before { content: $fa-var-viadeo; }
-.#{$fa-css-prefix}-viadeo-square:before { content: $fa-var-viadeo-square; }
-.#{$fa-css-prefix}-snapchat:before { content: $fa-var-snapchat; }
-.#{$fa-css-prefix}-snapchat-ghost:before { content: $fa-var-snapchat-ghost; }
-.#{$fa-css-prefix}-snapchat-square:before { content: $fa-var-snapchat-square; }
-.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; }
-.#{$fa-css-prefix}-first-order:before { content: $fa-var-first-order; }
-.#{$fa-css-prefix}-yoast:before { content: $fa-var-yoast; }
-.#{$fa-css-prefix}-themeisle:before { content: $fa-var-themeisle; }
-.#{$fa-css-prefix}-google-plus-circle:before,
-.#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; }
-.#{$fa-css-prefix}-fa:before,
-.#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; }
diff --git a/hubs/static/font-awesome-4.6.3/scss/_larger.scss b/hubs/static/font-awesome-4.6.3/scss/_larger.scss
deleted file mode 100644
index 41e9a81..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_larger.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-// Icon Sizes
-// -------------------------
-
-/* makes the font 33% larger relative to the icon container */
-.#{$fa-css-prefix}-lg {
-  font-size: (4em / 3);
-  line-height: (3em / 4);
-  vertical-align: -15%;
-}
-.#{$fa-css-prefix}-2x { font-size: 2em; }
-.#{$fa-css-prefix}-3x { font-size: 3em; }
-.#{$fa-css-prefix}-4x { font-size: 4em; }
-.#{$fa-css-prefix}-5x { font-size: 5em; }
diff --git a/hubs/static/font-awesome-4.6.3/scss/_list.scss b/hubs/static/font-awesome-4.6.3/scss/_list.scss
deleted file mode 100644
index 7d1e4d5..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_list.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-// List Icons
-// -------------------------
-
-.#{$fa-css-prefix}-ul {
-  padding-left: 0;
-  margin-left: $fa-li-width;
-  list-style-type: none;
-  > li { position: relative; }
-}
-.#{$fa-css-prefix}-li {
-  position: absolute;
-  left: -$fa-li-width;
-  width: $fa-li-width;
-  top: (2em / 14);
-  text-align: center;
-  &.#{$fa-css-prefix}-lg {
-    left: -$fa-li-width + (4em / 14);
-  }
-}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_mixins.scss b/hubs/static/font-awesome-4.6.3/scss/_mixins.scss
deleted file mode 100644
index c3bbd57..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_mixins.scss
+++ /dev/null
@@ -1,60 +0,0 @@
-// Mixins
-// --------------------------
-
-@mixin fa-icon() {
-  display: inline-block;
-  font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
-  font-size: inherit; // can't have font-size inherit on line above, so need to override
-  text-rendering: auto; // optimizelegibility throws things off #1094
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-
-}
-
-@mixin fa-icon-rotate($degrees, $rotation) {
-  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
-  -webkit-transform: rotate($degrees);
-      -ms-transform: rotate($degrees);
-          transform: rotate($degrees);
-}
-
-@mixin fa-icon-flip($horiz, $vert, $rotation) {
-  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
-  -webkit-transform: scale($horiz, $vert);
-      -ms-transform: scale($horiz, $vert);
-          transform: scale($horiz, $vert);
-}
-
-
-// Only display content to screen readers. A la Bootstrap 4.
-//
-// See: http://a11yproject.com/posts/how-to-hide-content/
-
-@mixin sr-only {
-  position: absolute;
-  width: 1px;
-  height: 1px;
-  padding: 0;
-  margin: -1px;
-  overflow: hidden;
-  clip: rect(0,0,0,0);
-  border: 0;
-}
-
-// Use in conjunction with .sr-only to only display content when it's focused.
-//
-// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
-//
-// Credit: HTML5 Boilerplate
-
-@mixin sr-only-focusable {
-  &:active,
-  &:focus {
-    position: static;
-    width: auto;
-    height: auto;
-    margin: 0;
-    overflow: visible;
-    clip: auto;
-  }
-}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_path.scss b/hubs/static/font-awesome-4.6.3/scss/_path.scss
deleted file mode 100644
index bb457c2..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_path.scss
+++ /dev/null
@@ -1,15 +0,0 @@
-/* FONT PATH
- * -------------------------- */
-
-@font-face {
-  font-family: 'FontAwesome';
-  src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
-  src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
-    url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
-    url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
-    url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
-    url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
-//  src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
-  font-weight: normal;
-  font-style: normal;
-}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_rotated-flipped.scss b/hubs/static/font-awesome-4.6.3/scss/_rotated-flipped.scss
deleted file mode 100644
index a3558fd..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_rotated-flipped.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-// Rotated & Flipped Icons
-// -------------------------
-
-.#{$fa-css-prefix}-rotate-90  { @include fa-icon-rotate(90deg, 1);  }
-.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
-.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
-
-.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
-.#{$fa-css-prefix}-flip-vertical   { @include fa-icon-flip(1, -1, 2); }
-
-// Hook for IE8-9
-// -------------------------
-
-:root .#{$fa-css-prefix}-rotate-90,
-:root .#{$fa-css-prefix}-rotate-180,
-:root .#{$fa-css-prefix}-rotate-270,
-:root .#{$fa-css-prefix}-flip-horizontal,
-:root .#{$fa-css-prefix}-flip-vertical {
-  filter: none;
-}
diff --git a/hubs/static/font-awesome-4.6.3/scss/_screen-reader.scss b/hubs/static/font-awesome-4.6.3/scss/_screen-reader.scss
deleted file mode 100644
index 637426f..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_screen-reader.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-// Screen Readers
-// -------------------------
-
-.sr-only { @include sr-only(); }
-.sr-only-focusable { @include sr-only-focusable(); }
diff --git a/hubs/static/font-awesome-4.6.3/scss/_stacked.scss b/hubs/static/font-awesome-4.6.3/scss/_stacked.scss
deleted file mode 100644
index aef7403..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_stacked.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-// Stacked Icons
-// -------------------------
-
-.#{$fa-css-prefix}-stack {
-  position: relative;
-  display: inline-block;
-  width: 2em;
-  height: 2em;
-  line-height: 2em;
-  vertical-align: middle;
-}
-.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x {
-  position: absolute;
-  left: 0;
-  width: 100%;
-  text-align: center;
-}
-.#{$fa-css-prefix}-stack-1x { line-height: inherit; }
-.#{$fa-css-prefix}-stack-2x { font-size: 2em; }
-.#{$fa-css-prefix}-inverse { color: $fa-inverse; }
diff --git a/hubs/static/font-awesome-4.6.3/scss/_variables.scss b/hubs/static/font-awesome-4.6.3/scss/_variables.scss
deleted file mode 100644
index a5a89ef..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/_variables.scss
+++ /dev/null
@@ -1,744 +0,0 @@
-// Variables
-// --------------------------
-
-$fa-font-path:        "../fonts" !default;
-$fa-font-size-base:   14px !default;
-$fa-line-height-base: 1 !default;
-//$fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.6.3/fonts" !default; // for referencing Bootstrap CDN font files directly
-$fa-css-prefix:       fa !default;
-$fa-version:          "4.6.3" !default;
-$fa-border-color:     #eee !default;
-$fa-inverse:          #fff !default;
-$fa-li-width:         (30em / 14) !default;
-
-$fa-var-500px: "\f26e";
-$fa-var-adjust: "\f042";
-$fa-var-adn: "\f170";
-$fa-var-align-center: "\f037";
-$fa-var-align-justify: "\f039";
-$fa-var-align-left: "\f036";
-$fa-var-align-right: "\f038";
-$fa-var-amazon: "\f270";
-$fa-var-ambulance: "\f0f9";
-$fa-var-american-sign-language-interpreting: "\f2a3";
-$fa-var-anchor: "\f13d";
-$fa-var-android: "\f17b";
-$fa-var-angellist: "\f209";
-$fa-var-angle-double-down: "\f103";
-$fa-var-angle-double-left: "\f100";
-$fa-var-angle-double-right: "\f101";
-$fa-var-angle-double-up: "\f102";
-$fa-var-angle-down: "\f107";
-$fa-var-angle-left: "\f104";
-$fa-var-angle-right: "\f105";
-$fa-var-angle-up: "\f106";
-$fa-var-apple: "\f179";
-$fa-var-archive: "\f187";
-$fa-var-area-chart: "\f1fe";
-$fa-var-arrow-circle-down: "\f0ab";
-$fa-var-arrow-circle-left: "\f0a8";
-$fa-var-arrow-circle-o-down: "\f01a";
-$fa-var-arrow-circle-o-left: "\f190";
-$fa-var-arrow-circle-o-right: "\f18e";
-$fa-var-arrow-circle-o-up: "\f01b";
-$fa-var-arrow-circle-right: "\f0a9";
-$fa-var-arrow-circle-up: "\f0aa";
-$fa-var-arrow-down: "\f063";
-$fa-var-arrow-left: "\f060";
-$fa-var-arrow-right: "\f061";
-$fa-var-arrow-up: "\f062";
-$fa-var-arrows: "\f047";
-$fa-var-arrows-alt: "\f0b2";
-$fa-var-arrows-h: "\f07e";
-$fa-var-arrows-v: "\f07d";
-$fa-var-asl-interpreting: "\f2a3";
-$fa-var-assistive-listening-systems: "\f2a2";
-$fa-var-asterisk: "\f069";
-$fa-var-at: "\f1fa";
-$fa-var-audio-description: "\f29e";
-$fa-var-automobile: "\f1b9";
-$fa-var-backward: "\f04a";
-$fa-var-balance-scale: "\f24e";
-$fa-var-ban: "\f05e";
-$fa-var-bank: "\f19c";
-$fa-var-bar-chart: "\f080";
-$fa-var-bar-chart-o: "\f080";
-$fa-var-barcode: "\f02a";
-$fa-var-bars: "\f0c9";
-$fa-var-battery-0: "\f244";
-$fa-var-battery-1: "\f243";
-$fa-var-battery-2: "\f242";
-$fa-var-battery-3: "\f241";
-$fa-var-battery-4: "\f240";
-$fa-var-battery-empty: "\f244";
-$fa-var-battery-full: "\f240";
-$fa-var-battery-half: "\f242";
-$fa-var-battery-quarter: "\f243";
-$fa-var-battery-three-quarters: "\f241";
-$fa-var-bed: "\f236";
-$fa-var-beer: "\f0fc";
-$fa-var-behance: "\f1b4";
-$fa-var-behance-square: "\f1b5";
-$fa-var-bell: "\f0f3";
-$fa-var-bell-o: "\f0a2";
-$fa-var-bell-slash: "\f1f6";
-$fa-var-bell-slash-o: "\f1f7";
-$fa-var-bicycle: "\f206";
-$fa-var-binoculars: "\f1e5";
-$fa-var-birthday-cake: "\f1fd";
-$fa-var-bitbucket: "\f171";
-$fa-var-bitbucket-square: "\f172";
-$fa-var-bitcoin: "\f15a";
-$fa-var-black-tie: "\f27e";
-$fa-var-blind: "\f29d";
-$fa-var-bluetooth: "\f293";
-$fa-var-bluetooth-b: "\f294";
-$fa-var-bold: "\f032";
-$fa-var-bolt: "\f0e7";
-$fa-var-bomb: "\f1e2";
-$fa-var-book: "\f02d";
-$fa-var-bookmark: "\f02e";
-$fa-var-bookmark-o: "\f097";
-$fa-var-braille: "\f2a1";
-$fa-var-briefcase: "\f0b1";
-$fa-var-btc: "\f15a";
-$fa-var-bug: "\f188";
-$fa-var-building: "\f1ad";
-$fa-var-building-o: "\f0f7";
-$fa-var-bullhorn: "\f0a1";
-$fa-var-bullseye: "\f140";
-$fa-var-bus: "\f207";
-$fa-var-buysellads: "\f20d";
-$fa-var-cab: "\f1ba";
-$fa-var-calculator: "\f1ec";
-$fa-var-calendar: "\f073";
-$fa-var-calendar-check-o: "\f274";
-$fa-var-calendar-minus-o: "\f272";
-$fa-var-calendar-o: "\f133";
-$fa-var-calendar-plus-o: "\f271";
-$fa-var-calendar-times-o: "\f273";
-$fa-var-camera: "\f030";
-$fa-var-camera-retro: "\f083";
-$fa-var-car: "\f1b9";
-$fa-var-caret-down: "\f0d7";
-$fa-var-caret-left: "\f0d9";
-$fa-var-caret-right: "\f0da";
-$fa-var-caret-square-o-down: "\f150";
-$fa-var-caret-square-o-left: "\f191";
-$fa-var-caret-square-o-right: "\f152";
-$fa-var-caret-square-o-up: "\f151";
-$fa-var-caret-up: "\f0d8";
-$fa-var-cart-arrow-down: "\f218";
-$fa-var-cart-plus: "\f217";
-$fa-var-cc: "\f20a";
-$fa-var-cc-amex: "\f1f3";
-$fa-var-cc-diners-club: "\f24c";
-$fa-var-cc-discover: "\f1f2";
-$fa-var-cc-jcb: "\f24b";
-$fa-var-cc-mastercard: "\f1f1";
-$fa-var-cc-paypal: "\f1f4";
-$fa-var-cc-stripe: "\f1f5";
-$fa-var-cc-visa: "\f1f0";
-$fa-var-certificate: "\f0a3";
-$fa-var-chain: "\f0c1";
-$fa-var-chain-broken: "\f127";
-$fa-var-check: "\f00c";
-$fa-var-check-circle: "\f058";
-$fa-var-check-circle-o: "\f05d";
-$fa-var-check-square: "\f14a";
-$fa-var-check-square-o: "\f046";
-$fa-var-chevron-circle-down: "\f13a";
-$fa-var-chevron-circle-left: "\f137";
-$fa-var-chevron-circle-right: "\f138";
-$fa-var-chevron-circle-up: "\f139";
-$fa-var-chevron-down: "\f078";
-$fa-var-chevron-left: "\f053";
-$fa-var-chevron-right: "\f054";
-$fa-var-chevron-up: "\f077";
-$fa-var-child: "\f1ae";
-$fa-var-chrome: "\f268";
-$fa-var-circle: "\f111";
-$fa-var-circle-o: "\f10c";
-$fa-var-circle-o-notch: "\f1ce";
-$fa-var-circle-thin: "\f1db";
-$fa-var-clipboard: "\f0ea";
-$fa-var-clock-o: "\f017";
-$fa-var-clone: "\f24d";
-$fa-var-close: "\f00d";
-$fa-var-cloud: "\f0c2";
-$fa-var-cloud-download: "\f0ed";
-$fa-var-cloud-upload: "\f0ee";
-$fa-var-cny: "\f157";
-$fa-var-code: "\f121";
-$fa-var-code-fork: "\f126";
-$fa-var-codepen: "\f1cb";
-$fa-var-codiepie: "\f284";
-$fa-var-coffee: "\f0f4";
-$fa-var-cog: "\f013";
-$fa-var-cogs: "\f085";
-$fa-var-columns: "\f0db";
-$fa-var-comment: "\f075";
-$fa-var-comment-o: "\f0e5";
-$fa-var-commenting: "\f27a";
-$fa-var-commenting-o: "\f27b";
-$fa-var-comments: "\f086";
-$fa-var-comments-o: "\f0e6";
-$fa-var-compass: "\f14e";
-$fa-var-compress: "\f066";
-$fa-var-connectdevelop: "\f20e";
-$fa-var-contao: "\f26d";
-$fa-var-copy: "\f0c5";
-$fa-var-copyright: "\f1f9";
-$fa-var-creative-commons: "\f25e";
-$fa-var-credit-card: "\f09d";
-$fa-var-credit-card-alt: "\f283";
-$fa-var-crop: "\f125";
-$fa-var-crosshairs: "\f05b";
-$fa-var-css3: "\f13c";
-$fa-var-cube: "\f1b2";
-$fa-var-cubes: "\f1b3";
-$fa-var-cut: "\f0c4";
-$fa-var-cutlery: "\f0f5";
-$fa-var-dashboard: "\f0e4";
-$fa-var-dashcube: "\f210";
-$fa-var-database: "\f1c0";
-$fa-var-deaf: "\f2a4";
-$fa-var-deafness: "\f2a4";
-$fa-var-dedent: "\f03b";
-$fa-var-delicious: "\f1a5";
-$fa-var-desktop: "\f108";
-$fa-var-deviantart: "\f1bd";
-$fa-var-diamond: "\f219";
-$fa-var-digg: "\f1a6";
-$fa-var-dollar: "\f155";
-$fa-var-dot-circle-o: "\f192";
-$fa-var-download: "\f019";
-$fa-var-dribbble: "\f17d";
-$fa-var-dropbox: "\f16b";
-$fa-var-drupal: "\f1a9";
-$fa-var-edge: "\f282";
-$fa-var-edit: "\f044";
-$fa-var-eject: "\f052";
-$fa-var-ellipsis-h: "\f141";
-$fa-var-ellipsis-v: "\f142";
-$fa-var-empire: "\f1d1";
-$fa-var-envelope: "\f0e0";
-$fa-var-envelope-o: "\f003";
-$fa-var-envelope-square: "\f199";
-$fa-var-envira: "\f299";
-$fa-var-eraser: "\f12d";
-$fa-var-eur: "\f153";
-$fa-var-euro: "\f153";
-$fa-var-exchange: "\f0ec";
-$fa-var-exclamation: "\f12a";
-$fa-var-exclamation-circle: "\f06a";
-$fa-var-exclamation-triangle: "\f071";
-$fa-var-expand: "\f065";
-$fa-var-expeditedssl: "\f23e";
-$fa-var-external-link: "\f08e";
-$fa-var-external-link-square: "\f14c";
-$fa-var-eye: "\f06e";
-$fa-var-eye-slash: "\f070";
-$fa-var-eyedropper: "\f1fb";
-$fa-var-fa: "\f2b4";
-$fa-var-facebook: "\f09a";
-$fa-var-facebook-f: "\f09a";
-$fa-var-facebook-official: "\f230";
-$fa-var-facebook-square: "\f082";
-$fa-var-fast-backward: "\f049";
-$fa-var-fast-forward: "\f050";
-$fa-var-fax: "\f1ac";
-$fa-var-feed: "\f09e";
-$fa-var-female: "\f182";
-$fa-var-fighter-jet: "\f0fb";
-$fa-var-file: "\f15b";
-$fa-var-file-archive-o: "\f1c6";
-$fa-var-file-audio-o: "\f1c7";
-$fa-var-file-code-o: "\f1c9";
-$fa-var-file-excel-o: "\f1c3";
-$fa-var-file-image-o: "\f1c5";
-$fa-var-file-movie-o: "\f1c8";
-$fa-var-file-o: "\f016";
-$fa-var-file-pdf-o: "\f1c1";
-$fa-var-file-photo-o: "\f1c5";
-$fa-var-file-picture-o: "\f1c5";
-$fa-var-file-powerpoint-o: "\f1c4";
-$fa-var-file-sound-o: "\f1c7";
-$fa-var-file-text: "\f15c";
-$fa-var-file-text-o: "\f0f6";
-$fa-var-file-video-o: "\f1c8";
-$fa-var-file-word-o: "\f1c2";
-$fa-var-file-zip-o: "\f1c6";
-$fa-var-files-o: "\f0c5";
-$fa-var-film: "\f008";
-$fa-var-filter: "\f0b0";
-$fa-var-fire: "\f06d";
-$fa-var-fire-extinguisher: "\f134";
-$fa-var-firefox: "\f269";
-$fa-var-first-order: "\f2b0";
-$fa-var-flag: "\f024";
-$fa-var-flag-checkered: "\f11e";
-$fa-var-flag-o: "\f11d";
-$fa-var-flash: "\f0e7";
-$fa-var-flask: "\f0c3";
-$fa-var-flickr: "\f16e";
-$fa-var-floppy-o: "\f0c7";
-$fa-var-folder: "\f07b";
-$fa-var-folder-o: "\f114";
-$fa-var-folder-open: "\f07c";
-$fa-var-folder-open-o: "\f115";
-$fa-var-font: "\f031";
-$fa-var-font-awesome: "\f2b4";
-$fa-var-fonticons: "\f280";
-$fa-var-fort-awesome: "\f286";
-$fa-var-forumbee: "\f211";
-$fa-var-forward: "\f04e";
-$fa-var-foursquare: "\f180";
-$fa-var-frown-o: "\f119";
-$fa-var-futbol-o: "\f1e3";
-$fa-var-gamepad: "\f11b";
-$fa-var-gavel: "\f0e3";
-$fa-var-gbp: "\f154";
-$fa-var-ge: "\f1d1";
-$fa-var-gear: "\f013";
-$fa-var-gears: "\f085";
-$fa-var-genderless: "\f22d";
-$fa-var-get-pocket: "\f265";
-$fa-var-gg: "\f260";
-$fa-var-gg-circle: "\f261";
-$fa-var-gift: "\f06b";
-$fa-var-git: "\f1d3";
-$fa-var-git-square: "\f1d2";
-$fa-var-github: "\f09b";
-$fa-var-github-alt: "\f113";
-$fa-var-github-square: "\f092";
-$fa-var-gitlab: "\f296";
-$fa-var-gittip: "\f184";
-$fa-var-glass: "\f000";
-$fa-var-glide: "\f2a5";
-$fa-var-glide-g: "\f2a6";
-$fa-var-globe: "\f0ac";
-$fa-var-google: "\f1a0";
-$fa-var-google-plus: "\f0d5";
-$fa-var-google-plus-circle: "\f2b3";
-$fa-var-google-plus-official: "\f2b3";
-$fa-var-google-plus-square: "\f0d4";
-$fa-var-google-wallet: "\f1ee";
-$fa-var-graduation-cap: "\f19d";
-$fa-var-gratipay: "\f184";
-$fa-var-group: "\f0c0";
-$fa-var-h-square: "\f0fd";
-$fa-var-hacker-news: "\f1d4";
-$fa-var-hand-grab-o: "\f255";
-$fa-var-hand-lizard-o: "\f258";
-$fa-var-hand-o-down: "\f0a7";
-$fa-var-hand-o-left: "\f0a5";
-$fa-var-hand-o-right: "\f0a4";
-$fa-var-hand-o-up: "\f0a6";
-$fa-var-hand-paper-o: "\f256";
-$fa-var-hand-peace-o: "\f25b";
-$fa-var-hand-pointer-o: "\f25a";
-$fa-var-hand-rock-o: "\f255";
-$fa-var-hand-scissors-o: "\f257";
-$fa-var-hand-spock-o: "\f259";
-$fa-var-hand-stop-o: "\f256";
-$fa-var-hard-of-hearing: "\f2a4";
-$fa-var-hashtag: "\f292";
-$fa-var-hdd-o: "\f0a0";
-$fa-var-header: "\f1dc";
-$fa-var-headphones: "\f025";
-$fa-var-heart: "\f004";
-$fa-var-heart-o: "\f08a";
-$fa-var-heartbeat: "\f21e";
-$fa-var-history: "\f1da";
-$fa-var-home: "\f015";
-$fa-var-hospital-o: "\f0f8";
-$fa-var-hotel: "\f236";
-$fa-var-hourglass: "\f254";
-$fa-var-hourglass-1: "\f251";
-$fa-var-hourglass-2: "\f252";
-$fa-var-hourglass-3: "\f253";
-$fa-var-hourglass-end: "\f253";
-$fa-var-hourglass-half: "\f252";
-$fa-var-hourglass-o: "\f250";
-$fa-var-hourglass-start: "\f251";
-$fa-var-houzz: "\f27c";
-$fa-var-html5: "\f13b";
-$fa-var-i-cursor: "\f246";
-$fa-var-ils: "\f20b";
-$fa-var-image: "\f03e";
-$fa-var-inbox: "\f01c";
-$fa-var-indent: "\f03c";
-$fa-var-industry: "\f275";
-$fa-var-info: "\f129";
-$fa-var-info-circle: "\f05a";
-$fa-var-inr: "\f156";
-$fa-var-instagram: "\f16d";
-$fa-var-institution: "\f19c";
-$fa-var-internet-explorer: "\f26b";
-$fa-var-intersex: "\f224";
-$fa-var-ioxhost: "\f208";
-$fa-var-italic: "\f033";
-$fa-var-joomla: "\f1aa";
-$fa-var-jpy: "\f157";
-$fa-var-jsfiddle: "\f1cc";
-$fa-var-key: "\f084";
-$fa-var-keyboard-o: "\f11c";
-$fa-var-krw: "\f159";
-$fa-var-language: "\f1ab";
-$fa-var-laptop: "\f109";
-$fa-var-lastfm: "\f202";
-$fa-var-lastfm-square: "\f203";
-$fa-var-leaf: "\f06c";
-$fa-var-leanpub: "\f212";
-$fa-var-legal: "\f0e3";
-$fa-var-lemon-o: "\f094";
-$fa-var-level-down: "\f149";
-$fa-var-level-up: "\f148";
-$fa-var-life-bouy: "\f1cd";
-$fa-var-life-buoy: "\f1cd";
-$fa-var-life-ring: "\f1cd";
-$fa-var-life-saver: "\f1cd";
-$fa-var-lightbulb-o: "\f0eb";
-$fa-var-line-chart: "\f201";
-$fa-var-link: "\f0c1";
-$fa-var-linkedin: "\f0e1";
-$fa-var-linkedin-square: "\f08c";
-$fa-var-linux: "\f17c";
-$fa-var-list: "\f03a";
-$fa-var-list-alt: "\f022";
-$fa-var-list-ol: "\f0cb";
-$fa-var-list-ul: "\f0ca";
-$fa-var-location-arrow: "\f124";
-$fa-var-lock: "\f023";
-$fa-var-long-arrow-down: "\f175";
-$fa-var-long-arrow-left: "\f177";
-$fa-var-long-arrow-right: "\f178";
-$fa-var-long-arrow-up: "\f176";
-$fa-var-low-vision: "\f2a8";
-$fa-var-magic: "\f0d0";
-$fa-var-magnet: "\f076";
-$fa-var-mail-forward: "\f064";
-$fa-var-mail-reply: "\f112";
-$fa-var-mail-reply-all: "\f122";
-$fa-var-male: "\f183";
-$fa-var-map: "\f279";
-$fa-var-map-marker: "\f041";
-$fa-var-map-o: "\f278";
-$fa-var-map-pin: "\f276";
-$fa-var-map-signs: "\f277";
-$fa-var-mars: "\f222";
-$fa-var-mars-double: "\f227";
-$fa-var-mars-stroke: "\f229";
-$fa-var-mars-stroke-h: "\f22b";
-$fa-var-mars-stroke-v: "\f22a";
-$fa-var-maxcdn: "\f136";
-$fa-var-meanpath: "\f20c";
-$fa-var-medium: "\f23a";
-$fa-var-medkit: "\f0fa";
-$fa-var-meh-o: "\f11a";
-$fa-var-mercury: "\f223";
-$fa-var-microphone: "\f130";
-$fa-var-microphone-slash: "\f131";
-$fa-var-minus: "\f068";
-$fa-var-minus-circle: "\f056";
-$fa-var-minus-square: "\f146";
-$fa-var-minus-square-o: "\f147";
-$fa-var-mixcloud: "\f289";
-$fa-var-mobile: "\f10b";
-$fa-var-mobile-phone: "\f10b";
-$fa-var-modx: "\f285";
-$fa-var-money: "\f0d6";
-$fa-var-moon-o: "\f186";
-$fa-var-mortar-board: "\f19d";
-$fa-var-motorcycle: "\f21c";
-$fa-var-mouse-pointer: "\f245";
-$fa-var-music: "\f001";
-$fa-var-navicon: "\f0c9";
-$fa-var-neuter: "\f22c";
-$fa-var-newspaper-o: "\f1ea";
-$fa-var-object-group: "\f247";
-$fa-var-object-ungroup: "\f248";
-$fa-var-odnoklassniki: "\f263";
-$fa-var-odnoklassniki-square: "\f264";
-$fa-var-opencart: "\f23d";
-$fa-var-openid: "\f19b";
-$fa-var-opera: "\f26a";
-$fa-var-optin-monster: "\f23c";
-$fa-var-outdent: "\f03b";
-$fa-var-pagelines: "\f18c";
-$fa-var-paint-brush: "\f1fc";
-$fa-var-paper-plane: "\f1d8";
-$fa-var-paper-plane-o: "\f1d9";
-$fa-var-paperclip: "\f0c6";
-$fa-var-paragraph: "\f1dd";
-$fa-var-paste: "\f0ea";
-$fa-var-pause: "\f04c";
-$fa-var-pause-circle: "\f28b";
-$fa-var-pause-circle-o: "\f28c";
-$fa-var-paw: "\f1b0";
-$fa-var-paypal: "\f1ed";
-$fa-var-pencil: "\f040";
-$fa-var-pencil-square: "\f14b";
-$fa-var-pencil-square-o: "\f044";
-$fa-var-percent: "\f295";
-$fa-var-phone: "\f095";
-$fa-var-phone-square: "\f098";
-$fa-var-photo: "\f03e";
-$fa-var-picture-o: "\f03e";
-$fa-var-pie-chart: "\f200";
-$fa-var-pied-piper: "\f2ae";
-$fa-var-pied-piper-alt: "\f1a8";
-$fa-var-pied-piper-pp: "\f1a7";
-$fa-var-pinterest: "\f0d2";
-$fa-var-pinterest-p: "\f231";
-$fa-var-pinterest-square: "\f0d3";
-$fa-var-plane: "\f072";
-$fa-var-play: "\f04b";
-$fa-var-play-circle: "\f144";
-$fa-var-play-circle-o: "\f01d";
-$fa-var-plug: "\f1e6";
-$fa-var-plus: "\f067";
-$fa-var-plus-circle: "\f055";
-$fa-var-plus-square: "\f0fe";
-$fa-var-plus-square-o: "\f196";
-$fa-var-power-off: "\f011";
-$fa-var-print: "\f02f";
-$fa-var-product-hunt: "\f288";
-$fa-var-puzzle-piece: "\f12e";
-$fa-var-qq: "\f1d6";
-$fa-var-qrcode: "\f029";
-$fa-var-question: "\f128";
-$fa-var-question-circle: "\f059";
-$fa-var-question-circle-o: "\f29c";
-$fa-var-quote-left: "\f10d";
-$fa-var-quote-right: "\f10e";
-$fa-var-ra: "\f1d0";
-$fa-var-random: "\f074";
-$fa-var-rebel: "\f1d0";
-$fa-var-recycle: "\f1b8";
-$fa-var-reddit: "\f1a1";
-$fa-var-reddit-alien: "\f281";
-$fa-var-reddit-square: "\f1a2";
-$fa-var-refresh: "\f021";
-$fa-var-registered: "\f25d";
-$fa-var-remove: "\f00d";
-$fa-var-renren: "\f18b";
-$fa-var-reorder: "\f0c9";
-$fa-var-repeat: "\f01e";
-$fa-var-reply: "\f112";
-$fa-var-reply-all: "\f122";
-$fa-var-resistance: "\f1d0";
-$fa-var-retweet: "\f079";
-$fa-var-rmb: "\f157";
-$fa-var-road: "\f018";
-$fa-var-rocket: "\f135";
-$fa-var-rotate-left: "\f0e2";
-$fa-var-rotate-right: "\f01e";
-$fa-var-rouble: "\f158";
-$fa-var-rss: "\f09e";
-$fa-var-rss-square: "\f143";
-$fa-var-rub: "\f158";
-$fa-var-ruble: "\f158";
-$fa-var-rupee: "\f156";
-$fa-var-safari: "\f267";
-$fa-var-save: "\f0c7";
-$fa-var-scissors: "\f0c4";
-$fa-var-scribd: "\f28a";
-$fa-var-search: "\f002";
-$fa-var-search-minus: "\f010";
-$fa-var-search-plus: "\f00e";
-$fa-var-sellsy: "\f213";
-$fa-var-send: "\f1d8";
-$fa-var-send-o: "\f1d9";
-$fa-var-server: "\f233";
-$fa-var-share: "\f064";
-$fa-var-share-alt: "\f1e0";
-$fa-var-share-alt-square: "\f1e1";
-$fa-var-share-square: "\f14d";
-$fa-var-share-square-o: "\f045";
-$fa-var-shekel: "\f20b";
-$fa-var-sheqel: "\f20b";
-$fa-var-shield: "\f132";
-$fa-var-ship: "\f21a";
-$fa-var-shirtsinbulk: "\f214";
-$fa-var-shopping-bag: "\f290";
-$fa-var-shopping-basket: "\f291";
-$fa-var-shopping-cart: "\f07a";
-$fa-var-sign-in: "\f090";
-$fa-var-sign-language: "\f2a7";
-$fa-var-sign-out: "\f08b";
-$fa-var-signal: "\f012";
-$fa-var-signing: "\f2a7";
-$fa-var-simplybuilt: "\f215";
-$fa-var-sitemap: "\f0e8";
-$fa-var-skyatlas: "\f216";
-$fa-var-skype: "\f17e";
-$fa-var-slack: "\f198";
-$fa-var-sliders: "\f1de";
-$fa-var-slideshare: "\f1e7";
-$fa-var-smile-o: "\f118";
-$fa-var-snapchat: "\f2ab";
-$fa-var-snapchat-ghost: "\f2ac";
-$fa-var-snapchat-square: "\f2ad";
-$fa-var-soccer-ball-o: "\f1e3";
-$fa-var-sort: "\f0dc";
-$fa-var-sort-alpha-asc: "\f15d";
-$fa-var-sort-alpha-desc: "\f15e";
-$fa-var-sort-amount-asc: "\f160";
-$fa-var-sort-amount-desc: "\f161";
-$fa-var-sort-asc: "\f0de";
-$fa-var-sort-desc: "\f0dd";
-$fa-var-sort-down: "\f0dd";
-$fa-var-sort-numeric-asc: "\f162";
-$fa-var-sort-numeric-desc: "\f163";
-$fa-var-sort-up: "\f0de";
-$fa-var-soundcloud: "\f1be";
-$fa-var-space-shuttle: "\f197";
-$fa-var-spinner: "\f110";
-$fa-var-spoon: "\f1b1";
-$fa-var-spotify: "\f1bc";
-$fa-var-square: "\f0c8";
-$fa-var-square-o: "\f096";
-$fa-var-stack-exchange: "\f18d";
-$fa-var-stack-overflow: "\f16c";
-$fa-var-star: "\f005";
-$fa-var-star-half: "\f089";
-$fa-var-star-half-empty: "\f123";
-$fa-var-star-half-full: "\f123";
-$fa-var-star-half-o: "\f123";
-$fa-var-star-o: "\f006";
-$fa-var-steam: "\f1b6";
-$fa-var-steam-square: "\f1b7";
-$fa-var-step-backward: "\f048";
-$fa-var-step-forward: "\f051";
-$fa-var-stethoscope: "\f0f1";
-$fa-var-sticky-note: "\f249";
-$fa-var-sticky-note-o: "\f24a";
-$fa-var-stop: "\f04d";
-$fa-var-stop-circle: "\f28d";
-$fa-var-stop-circle-o: "\f28e";
-$fa-var-street-view: "\f21d";
-$fa-var-strikethrough: "\f0cc";
-$fa-var-stumbleupon: "\f1a4";
-$fa-var-stumbleupon-circle: "\f1a3";
-$fa-var-subscript: "\f12c";
-$fa-var-subway: "\f239";
-$fa-var-suitcase: "\f0f2";
-$fa-var-sun-o: "\f185";
-$fa-var-superscript: "\f12b";
-$fa-var-support: "\f1cd";
-$fa-var-table: "\f0ce";
-$fa-var-tablet: "\f10a";
-$fa-var-tachometer: "\f0e4";
-$fa-var-tag: "\f02b";
-$fa-var-tags: "\f02c";
-$fa-var-tasks: "\f0ae";
-$fa-var-taxi: "\f1ba";
-$fa-var-television: "\f26c";
-$fa-var-tencent-weibo: "\f1d5";
-$fa-var-terminal: "\f120";
-$fa-var-text-height: "\f034";
-$fa-var-text-width: "\f035";
-$fa-var-th: "\f00a";
-$fa-var-th-large: "\f009";
-$fa-var-th-list: "\f00b";
-$fa-var-themeisle: "\f2b2";
-$fa-var-thumb-tack: "\f08d";
-$fa-var-thumbs-down: "\f165";
-$fa-var-thumbs-o-down: "\f088";
-$fa-var-thumbs-o-up: "\f087";
-$fa-var-thumbs-up: "\f164";
-$fa-var-ticket: "\f145";
-$fa-var-times: "\f00d";
-$fa-var-times-circle: "\f057";
-$fa-var-times-circle-o: "\f05c";
-$fa-var-tint: "\f043";
-$fa-var-toggle-down: "\f150";
-$fa-var-toggle-left: "\f191";
-$fa-var-toggle-off: "\f204";
-$fa-var-toggle-on: "\f205";
-$fa-var-toggle-right: "\f152";
-$fa-var-toggle-up: "\f151";
-$fa-var-trademark: "\f25c";
-$fa-var-train: "\f238";
-$fa-var-transgender: "\f224";
-$fa-var-transgender-alt: "\f225";
-$fa-var-trash: "\f1f8";
-$fa-var-trash-o: "\f014";
-$fa-var-tree: "\f1bb";
-$fa-var-trello: "\f181";
-$fa-var-tripadvisor: "\f262";
-$fa-var-trophy: "\f091";
-$fa-var-truck: "\f0d1";
-$fa-var-try: "\f195";
-$fa-var-tty: "\f1e4";
-$fa-var-tumblr: "\f173";
-$fa-var-tumblr-square: "\f174";
-$fa-var-turkish-lira: "\f195";
-$fa-var-tv: "\f26c";
-$fa-var-twitch: "\f1e8";
-$fa-var-twitter: "\f099";
-$fa-var-twitter-square: "\f081";
-$fa-var-umbrella: "\f0e9";
-$fa-var-underline: "\f0cd";
-$fa-var-undo: "\f0e2";
-$fa-var-universal-access: "\f29a";
-$fa-var-university: "\f19c";
-$fa-var-unlink: "\f127";
-$fa-var-unlock: "\f09c";
-$fa-var-unlock-alt: "\f13e";
-$fa-var-unsorted: "\f0dc";
-$fa-var-upload: "\f093";
-$fa-var-usb: "\f287";
-$fa-var-usd: "\f155";
-$fa-var-user: "\f007";
-$fa-var-user-md: "\f0f0";
-$fa-var-user-plus: "\f234";
-$fa-var-user-secret: "\f21b";
-$fa-var-user-times: "\f235";
-$fa-var-users: "\f0c0";
-$fa-var-venus: "\f221";
-$fa-var-venus-double: "\f226";
-$fa-var-venus-mars: "\f228";
-$fa-var-viacoin: "\f237";
-$fa-var-viadeo: "\f2a9";
-$fa-var-viadeo-square: "\f2aa";
-$fa-var-video-camera: "\f03d";
-$fa-var-vimeo: "\f27d";
-$fa-var-vimeo-square: "\f194";
-$fa-var-vine: "\f1ca";
-$fa-var-vk: "\f189";
-$fa-var-volume-control-phone: "\f2a0";
-$fa-var-volume-down: "\f027";
-$fa-var-volume-off: "\f026";
-$fa-var-volume-up: "\f028";
-$fa-var-warning: "\f071";
-$fa-var-wechat: "\f1d7";
-$fa-var-weibo: "\f18a";
-$fa-var-weixin: "\f1d7";
-$fa-var-whatsapp: "\f232";
-$fa-var-wheelchair: "\f193";
-$fa-var-wheelchair-alt: "\f29b";
-$fa-var-wifi: "\f1eb";
-$fa-var-wikipedia-w: "\f266";
-$fa-var-windows: "\f17a";
-$fa-var-won: "\f159";
-$fa-var-wordpress: "\f19a";
-$fa-var-wpbeginner: "\f297";
-$fa-var-wpforms: "\f298";
-$fa-var-wrench: "\f0ad";
-$fa-var-xing: "\f168";
-$fa-var-xing-square: "\f169";
-$fa-var-y-combinator: "\f23b";
-$fa-var-y-combinator-square: "\f1d4";
-$fa-var-yahoo: "\f19e";
-$fa-var-yc: "\f23b";
-$fa-var-yc-square: "\f1d4";
-$fa-var-yelp: "\f1e9";
-$fa-var-yen: "\f157";
-$fa-var-yoast: "\f2b1";
-$fa-var-youtube: "\f167";
-$fa-var-youtube-play: "\f16a";
-$fa-var-youtube-square: "\f166";
-
diff --git a/hubs/static/font-awesome-4.6.3/scss/font-awesome.scss b/hubs/static/font-awesome-4.6.3/scss/font-awesome.scss
deleted file mode 100644
index 2308b14..0000000
--- a/hubs/static/font-awesome-4.6.3/scss/font-awesome.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-/*!
- *  Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
- *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */
-
-@import "variables";
-@import "mixins";
-@import "path";
-@import "core";
-@import "larger";
-@import "fixed-width";
-@import "list";
-@import "bordered-pulled";
-@import "animated";
-@import "rotated-flipped";
-@import "stacked";
-@import "icons";
-@import "screen-reader";
diff --git a/hubs/static/open_iconic_1.1.0/css/open-iconic.min.css b/hubs/static/open_iconic_1.1.0/css/open-iconic.min.css
deleted file mode 100644
index 1f6afb8..0000000
--- a/hubs/static/open_iconic_1.1.0/css/open-iconic.min.css
+++ /dev/null
@@ -1 +0,0 @@
-@font-face{font-family:Icons;src:url(../fonts/open-iconic.eot);src:url(../fonts/open-iconic.eot?#iconic-sm) format('embedded-opentype'),url(../fonts/open-iconic.woff) format('woff'),url(../fonts/open-iconic.ttf) format('truetype'),url(../fonts/open-iconic.otf) format('opentype'),url(../fonts/open-iconic.svg#iconic-sm) format('svg');font-weight:400;font-style:normal}.oi[data-glyph].oi-text-replace{font-size:0;line-height:0}.oi[data-glyph].oi-text-replace:before{width:1em;text-align:center}.oi[data-glyph]:before{font-family:Icons;display:inline-block;speak:none;line-height:1;vertical-align:baseline;font-weight:400;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.oi[data-glyph]:empty:before{width:1em;text-align:center;box-sizing:content-box}.oi[data-glyph].oi-align-left:before{text-align:left}.oi[data-glyph].oi-align-right:before{text-align:right}.oi[data-glyph].oi-align-center:before{text-align:center}.oi[data-glyph].oi-flip-horizontal:before{-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.oi[data-glyph].oi-flip-vertical:before{-webkit-transform:scale(1,-1);-ms-transform:scale(-1,1);transform:scale(1,-1)}.oi[data-glyph].oi-flip-horizontal-vertical:before{-webkit-transform:scale(-1,-1);-ms-transform:scale(-1,1);transform:scale(-1,-1)}.oi[data-glyph=account-login]:before{content:'\e000'}.oi[data-glyph=account-logout]:before{content:'\e001'}.oi[data-glyph=action-redo]:before{content:'\e002'}.oi[data-glyph=action-undo]:before{content:'\e003'}.oi[data-glyph=align-center]:before{content:'\e004'}.oi[data-glyph=align-left]:before{content:'\e005'}.oi[data-glyph=align-right]:before{content:'\e006'}.oi[data-glyph=aperture]:before{content:'\e007'}.oi[data-glyph=arrow-bottom]:before{content:'\e008'}.oi[data-glyph=arrow-circle-bottom]:before{content:'\e009'}.oi[data-glyph=arrow-circle-left]:before{content:'\e00a'}.oi[data-glyph=arrow-circle-right]:before{content:'\e00b'}.oi[data-glyph=arrow-circle-top]:before{content:'\e00c'}.oi[data-glyph=arrow-left]:before{content:'\e00d'}.oi[data-glyph=arrow-right]:before{content:'\e00e'}.oi[data-glyph=arrow-thick-bottom]:before{content:'\e00f'}.oi[data-glyph=arrow-thick-left]:before{content:'\e010'}.oi[data-glyph=arrow-thick-right]:before{content:'\e011'}.oi[data-glyph=arrow-thick-top]:before{content:'\e012'}.oi[data-glyph=arrow-top]:before{content:'\e013'}.oi[data-glyph=audio-spectrum]:before{content:'\e014'}.oi[data-glyph=audio]:before{content:'\e015'}.oi[data-glyph=badge]:before{content:'\e016'}.oi[data-glyph=ban]:before{content:'\e017'}.oi[data-glyph=bar-chart]:before{content:'\e018'}.oi[data-glyph=basket]:before{content:'\e019'}.oi[data-glyph=battery-empty]:before{content:'\e01a'}.oi[data-glyph=battery-full]:before{content:'\e01b'}.oi[data-glyph=beaker]:before{content:'\e01c'}.oi[data-glyph=bell]:before{content:'\e01d'}.oi[data-glyph=bluetooth]:before{content:'\e01e'}.oi[data-glyph=bold]:before{content:'\e01f'}.oi[data-glyph=bolt]:before{content:'\e020'}.oi[data-glyph=book]:before{content:'\e021'}.oi[data-glyph=bookmark]:before{content:'\e022'}.oi[data-glyph=box]:before{content:'\e023'}.oi[data-glyph=briefcase]:before{content:'\e024'}.oi[data-glyph=british-pound]:before{content:'\e025'}.oi[data-glyph=browser]:before{content:'\e026'}.oi[data-glyph=brush]:before{content:'\e027'}.oi[data-glyph=bug]:before{content:'\e028'}.oi[data-glyph=bullhorn]:before{content:'\e029'}.oi[data-glyph=calculator]:before{content:'\e02a'}.oi[data-glyph=calendar]:before{content:'\e02b'}.oi[data-glyph=camera-slr]:before{content:'\e02c'}.oi[data-glyph=caret-bottom]:before{content:'\e02d'}.oi[data-glyph=caret-left]:before{content:'\e02e'}.oi[data-glyph=caret-right]:before{content:'\e02f'}.oi[data-glyph=caret-top]:before{content:'\e030'}.oi[data-glyph=cart]:before{content:'\e031'}.oi[data-glyph=chat]:before{content:'\e032'}.oi[data-glyph=check]:before{content:'\e033'}.oi[data-glyph=chevron-bottom]:before{content:'\e034'}.oi[data-glyph=chevron-left]:before{content:'\e035'}.oi[data-glyph=chevron-right]:before{content:'\e036'}.oi[data-glyph=chevron-top]:before{content:'\e037'}.oi[data-glyph=circle-check]:before{content:'\e038'}.oi[data-glyph=circle-x]:before{content:'\e039'}.oi[data-glyph=clipboard]:before{content:'\e03a'}.oi[data-glyph=clock]:before{content:'\e03b'}.oi[data-glyph=cloud-download]:before{content:'\e03c'}.oi[data-glyph=cloud-upload]:before{content:'\e03d'}.oi[data-glyph=cloud]:before{content:'\e03e'}.oi[data-glyph=cloudy]:before{content:'\e03f'}.oi[data-glyph=code]:before{content:'\e040'}.oi[data-glyph=cog]:before{content:'\e041'}.oi[data-glyph=collapse-down]:before{content:'\e042'}.oi[data-glyph=collapse-left]:before{content:'\e043'}.oi[data-glyph=collapse-right]:before{content:'\e044'}.oi[data-glyph=collapse-up]:before{content:'\e045'}.oi[data-glyph=command]:before{content:'\e046'}.oi[data-glyph=comment-square]:before{content:'\e047'}.oi[data-glyph=compass]:before{content:'\e048'}.oi[data-glyph=contrast]:before{content:'\e049'}.oi[data-glyph=copywriting]:before{content:'\e04a'}.oi[data-glyph=credit-card]:before{content:'\e04b'}.oi[data-glyph=crop]:before{content:'\e04c'}.oi[data-glyph=dashboard]:before{content:'\e04d'}.oi[data-glyph=data-transfer-download]:before{content:'\e04e'}.oi[data-glyph=data-transfer-upload]:before{content:'\e04f'}.oi[data-glyph=delete]:before{content:'\e050'}.oi[data-glyph=dial]:before{content:'\e051'}.oi[data-glyph=document]:before{content:'\e052'}.oi[data-glyph=dollar]:before{content:'\e053'}.oi[data-glyph=double-quote-sans-left]:before{content:'\e054'}.oi[data-glyph=double-quote-sans-right]:before{content:'\e055'}.oi[data-glyph=double-quote-serif-left]:before{content:'\e056'}.oi[data-glyph=double-quote-serif-right]:before{content:'\e057'}.oi[data-glyph=droplet]:before{content:'\e058'}.oi[data-glyph=eject]:before{content:'\e059'}.oi[data-glyph=elevator]:before{content:'\e05a'}.oi[data-glyph=ellipses]:before{content:'\e05b'}.oi[data-glyph=envelope-closed]:before{content:'\e05c'}.oi[data-glyph=envelope-open]:before{content:'\e05d'}.oi[data-glyph=euro]:before{content:'\e05e'}.oi[data-glyph=excerpt]:before{content:'\e05f'}.oi[data-glyph=expand-down]:before{content:'\e060'}.oi[data-glyph=expand-left]:before{content:'\e061'}.oi[data-glyph=expand-right]:before{content:'\e062'}.oi[data-glyph=expand-up]:before{content:'\e063'}.oi[data-glyph=external-link]:before{content:'\e064'}.oi[data-glyph=eye]:before{content:'\e065'}.oi[data-glyph=eyedropper]:before{content:'\e066'}.oi[data-glyph=file]:before{content:'\e067'}.oi[data-glyph=fire]:before{content:'\e068'}.oi[data-glyph=flag]:before{content:'\e069'}.oi[data-glyph=flash]:before{content:'\e06a'}.oi[data-glyph=folder]:before{content:'\e06b'}.oi[data-glyph=fork]:before{content:'\e06c'}.oi[data-glyph=fullscreen-enter]:before{content:'\e06d'}.oi[data-glyph=fullscreen-exit]:before{content:'\e06e'}.oi[data-glyph=globe]:before{content:'\e06f'}.oi[data-glyph=graph]:before{content:'\e070'}.oi[data-glyph=grid-four-up]:before{content:'\e071'}.oi[data-glyph=grid-three-up]:before{content:'\e072'}.oi[data-glyph=grid-two-up]:before{content:'\e073'}.oi[data-glyph=hard-drive]:before{content:'\e074'}.oi[data-glyph=header]:before{content:'\e075'}.oi[data-glyph=headphones]:before{content:'\e076'}.oi[data-glyph=heart]:before{content:'\e077'}.oi[data-glyph=home]:before{content:'\e078'}.oi[data-glyph=image]:before{content:'\e079'}.oi[data-glyph=inbox]:before{content:'\e07a'}.oi[data-glyph=infinity]:before{content:'\e07b'}.oi[data-glyph=info]:before{content:'\e07c'}.oi[data-glyph=italic]:before{content:'\e07d'}.oi[data-glyph=justify-center]:before{content:'\e07e'}.oi[data-glyph=justify-left]:before{content:'\e07f'}.oi[data-glyph=justify-right]:before{content:'\e080'}.oi[data-glyph=key]:before{content:'\e081'}.oi[data-glyph=laptop]:before{content:'\e082'}.oi[data-glyph=layers]:before{content:'\e083'}.oi[data-glyph=lightbulb]:before{content:'\e084'}.oi[data-glyph=link-broken]:before{content:'\e085'}.oi[data-glyph=link-intact]:before{content:'\e086'}.oi[data-glyph=list-rich]:before{content:'\e087'}.oi[data-glyph=list]:before{content:'\e088'}.oi[data-glyph=location]:before{content:'\e089'}.oi[data-glyph=lock-locked]:before{content:'\e08a'}.oi[data-glyph=lock-unlocked]:before{content:'\e08b'}.oi[data-glyph=loop-circular]:before{content:'\e08c'}.oi[data-glyph=loop-square]:before{content:'\e08d'}.oi[data-glyph=loop]:before{content:'\e08e'}.oi[data-glyph=magnifying-glass]:before{content:'\e08f'}.oi[data-glyph=map-marker]:before{content:'\e090'}.oi[data-glyph=map]:before{content:'\e091'}.oi[data-glyph=media-pause]:before{content:'\e092'}.oi[data-glyph=media-play]:before{content:'\e093'}.oi[data-glyph=media-record]:before{content:'\e094'}.oi[data-glyph=media-skip-backward]:before{content:'\e095'}.oi[data-glyph=media-skip-forward]:before{content:'\e096'}.oi[data-glyph=media-step-backward]:before{content:'\e097'}.oi[data-glyph=media-step-forward]:before{content:'\e098'}.oi[data-glyph=media-stop]:before{content:'\e099'}.oi[data-glyph=medical-cross]:before{content:'\e09a'}.oi[data-glyph=menu]:before{content:'\e09b'}.oi[data-glyph=microphone]:before{content:'\e09c'}.oi[data-glyph=minus]:before{content:'\e09d'}.oi[data-glyph=monitor]:before{content:'\e09e'}.oi[data-glyph=moon]:before{content:'\e09f'}.oi[data-glyph=move]:before{content:'\e0a0'}.oi[data-glyph=musical-note]:before{content:'\e0a1'}.oi[data-glyph=paperclip]:before{content:'\e0a2'}.oi[data-glyph=pencil]:before{content:'\e0a3'}.oi[data-glyph=people]:before{content:'\e0a4'}.oi[data-glyph=person]:before{content:'\e0a5'}.oi[data-glyph=phone]:before{content:'\e0a6'}.oi[data-glyph=pie-chart]:before{content:'\e0a7'}.oi[data-glyph=pin]:before{content:'\e0a8'}.oi[data-glyph=play-circle]:before{content:'\e0a9'}.oi[data-glyph=plus]:before{content:'\e0aa'}.oi[data-glyph=power-standby]:before{content:'\e0ab'}.oi[data-glyph=print]:before{content:'\e0ac'}.oi[data-glyph=project]:before{content:'\e0ad'}.oi[data-glyph=pulse]:before{content:'\e0ae'}.oi[data-glyph=puzzle-piece]:before{content:'\e0af'}.oi[data-glyph=question-mark]:before{content:'\e0b0'}.oi[data-glyph=rain]:before{content:'\e0b1'}.oi[data-glyph=random]:before{content:'\e0b2'}.oi[data-glyph=reload]:before{content:'\e0b3'}.oi[data-glyph=resize-both]:before{content:'\e0b4'}.oi[data-glyph=resize-height]:before{content:'\e0b5'}.oi[data-glyph=resize-width]:before{content:'\e0b6'}.oi[data-glyph=rss-alt]:before{content:'\e0b7'}.oi[data-glyph=rss]:before{content:'\e0b8'}.oi[data-glyph=script]:before{content:'\e0b9'}.oi[data-glyph=share-boxed]:before{content:'\e0ba'}.oi[data-glyph=share]:before{content:'\e0bb'}.oi[data-glyph=shield]:before{content:'\e0bc'}.oi[data-glyph=signal]:before{content:'\e0bd'}.oi[data-glyph=signpost]:before{content:'\e0be'}.oi[data-glyph=sort-ascending]:before{content:'\e0bf'}.oi[data-glyph=sort-descending]:before{content:'\e0c0'}.oi[data-glyph=spreadsheet]:before{content:'\e0c1'}.oi[data-glyph=star]:before{content:'\e0c2'}.oi[data-glyph=sun]:before{content:'\e0c3'}.oi[data-glyph=tablet]:before{content:'\e0c4'}.oi[data-glyph=tag]:before{content:'\e0c5'}.oi[data-glyph=tags]:before{content:'\e0c6'}.oi[data-glyph=target]:before{content:'\e0c7'}.oi[data-glyph=task]:before{content:'\e0c8'}.oi[data-glyph=terminal]:before{content:'\e0c9'}.oi[data-glyph=text]:before{content:'\e0ca'}.oi[data-glyph=thumb-down]:before{content:'\e0cb'}.oi[data-glyph=thumb-up]:before{content:'\e0cc'}.oi[data-glyph=timer]:before{content:'\e0cd'}.oi[data-glyph=transfer]:before{content:'\e0ce'}.oi[data-glyph=trash]:before{content:'\e0cf'}.oi[data-glyph=underline]:before{content:'\e0d0'}.oi[data-glyph=vertical-align-bottom]:before{content:'\e0d1'}.oi[data-glyph=vertical-align-center]:before{content:'\e0d2'}.oi[data-glyph=vertical-align-top]:before{content:'\e0d3'}.oi[data-glyph=video]:before{content:'\e0d4'}.oi[data-glyph=volume-high]:before{content:'\e0d5'}.oi[data-glyph=volume-low]:before{content:'\e0d6'}.oi[data-glyph=volume-off]:before{content:'\e0d7'}.oi[data-glyph=warning]:before{content:'\e0d8'}.oi[data-glyph=wifi]:before{content:'\e0d9'}.oi[data-glyph=wrench]:before{content:'\e0da'}.oi[data-glyph=x]:before{content:'\e0db'}.oi[data-glyph=yen]:before{content:'\e0dc'}.oi[data-glyph=zoom-in]:before{content:'\e0dd'}.oi[data-glyph=zoom-out]:before{content:'\e0de'}
\ No newline at end of file
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.eot b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.eot
deleted file mode 100644
index f98177d..0000000
Binary files a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.eot and /dev/null differ
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.otf b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.otf
deleted file mode 100644
index f6bd684..0000000
Binary files a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.otf and /dev/null differ
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.svg b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.svg
deleted file mode 100644
index 559edd9..0000000
--- a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.svg
+++ /dev/null
@@ -1,543 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<!--
-2014-7-1: Created.
--->
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata>
-Created by FontForge 20120731 at Tue Jul  1 20:39:22 2014
- By P.J. Onori
-Created by P.J. Onori with FontForge 2.0 (http://fontforge.sf.net)
-</metadata>
-<defs>
-<font id="open-iconic" horiz-adv-x="800" >
-  <font-face
-    font-family="Icons"
-    font-weight="400"
-    font-stretch="normal"
-    units-per-em="800"
-    panose-1="2 0 5 3 0 0 0 0 0 0"
-    ascent="800"
-    descent="0"
-    bbox="-0.5 -101 802 800.126"
-    underline-thickness="50"
-    underline-position="-100"
-    unicode-range="U+E000-E0DE"
-  />
-    <missing-glyph />
-    <glyph glyph-name="" unicode="&#xe000;"
-d="M300 700h500v-700h-500v100h400v500h-400v100zM400 500l200 -150l-200 -150v100h-400v100h400v100z" />
-    <glyph glyph-name="1" unicode="&#xe001;"
-d="M300 700h500v-700h-500v100h400v500h-400v100zM200 500v-100h400v-100h-400v-100l-200 150z" />
-    <glyph glyph-name="2" unicode="&#xe002;"
-d="M350 700c193 0 350 -157 350 -350v-50h100l-200 -200l-200 200h100v50c0 138 -112 250 -250 250s-250 -112 -250 -250c0 193 157 350 350 350z" />
-    <glyph glyph-name="3" unicode="&#xe003;"
-d="M450 700c193 0 350 -157 350 -350c0 138 -112 250 -250 250s-250 -112 -250 -250v-50h100l-200 -200l-200 200h100v50c0 193 157 350 350 350z" />
-    <glyph glyph-name="4" unicode="&#xe004;"
-d="M0 700h800v-100h-800v100zM100 500h600v-100h-600v100zM0 300h800v-100h-800v100zM100 100h600v-100h-600v100z" />
-    <glyph glyph-name="5" unicode="&#xe005;"
-d="M0 700h800v-100h-800v100zM0 500h600v-100h-600v100zM0 300h800v-100h-800v100zM0 100h600v-100h-600v100z" />
-    <glyph glyph-name="6" unicode="&#xe006;"
-d="M0 700h800v-100h-800v100zM200 500h600v-100h-600v100zM0 300h800v-100h-800v100zM200 100h600v-100h-600v100z" />
-    <glyph glyph-name="7" unicode="&#xe007;"
-d="M400 700c75 0 146 -23 206 -59l-75 -225l-322 234c57 31 122 50 191 50zM125 588l191 -138l-310 -222c-4 24 -6 47 -6 72c0 114 49 215 125 288zM688 575c69 -72 112 -168 112 -275c0 -35 -8 -68 -16 -100h-218zM216 253l112 -347c-128 23 -232 109 -287 222zM372 100
-h372c-64 -109 -177 -185 -310 -197z" />
-    <glyph glyph-name="8" unicode="&#xe008;" horiz-adv-x="600"
-d="M200 800h100v-500h200l-247 -300l-253 300h200v500z" />
-    <glyph glyph-name="9" unicode="&#xe009;"
-d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM300 700v-300h-200l300 -300l300 300h-200v300h-200z" />
-    <glyph glyph-name="a" unicode="&#xe00a;"
-d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700l-300 -300l300 -300v200h300v200h-300v200z" />
-    <glyph glyph-name="b" unicode="&#xe00b;"
-d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700v-200h-300v-200h300v-200l300 300z" />
-    <glyph glyph-name="c" unicode="&#xe00c;"
-d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700l-300 -300h200v-300h200v300h200z" />
-    <glyph glyph-name="d" unicode="&#xe00d;"
-d="M300 600v-200h500v-100h-500v-200l-300 247z" />
-    <glyph glyph-name="e" unicode="&#xe00e;"
-d="M500 600l300 -247l-300 -253v200h-500v100h500v200z" />
-    <glyph glyph-name="f" unicode="&#xe00f;" horiz-adv-x="600"
-d="M200 800h200v-500h200l-297 -300l-303 300h200v500z" />
-    <glyph glyph-name="10" unicode="&#xe010;"
-d="M300 700v-200h500v-200h-500v-200l-300 297z" />
-    <glyph glyph-name="11" unicode="&#xe011;"
-d="M500 700l300 -297l-300 -303v200h-500v200h500v200z" />
-    <glyph glyph-name="12" unicode="&#xe012;" horiz-adv-x="600"
-d="M297 800l303 -300h-200v-500h-200v500h-200z" />
-    <glyph glyph-name="13" unicode="&#xe013;" horiz-adv-x="600"
-d="M247 800l253 -300h-200v-500h-100v500h-200z" />
-    <glyph glyph-name="14" unicode="&#xe014;"
-d="M400 800h100v-800h-100v800zM200 700h100v-600h-100v600zM600 600h100v-400h-100v400zM0 500h100v-200h-100v200z" />
-    <glyph glyph-name="15" unicode="&#xe015;"
-d="M116 600l72 -72c-54 -54 -88 -126 -88 -209s34 -159 88 -213l-72 -72c-72 72 -116 175 -116 285s44 209 116 281zM684 600c72 -72 116 -171 116 -281s-44 -213 -116 -285l-72 72c54 54 88 130 88 213s-34 155 -88 209zM259 460l69 -72c-18 -18 -28 -41 -28 -69
-s10 -54 28 -72l-69 -72c-36 36 -59 89 -59 144s23 105 59 141zM541 459c36 -36 59 -85 59 -140s-23 -108 -59 -144l-69 72c18 18 28 44 28 72s-10 51 -28 69z" />
-    <glyph glyph-name="16" unicode="&#xe016;" horiz-adv-x="400"
-d="M200 800c110 0 200 -90 200 -200s-90 -200 -200 -200s-200 90 -200 200s90 200 200 200zM100 319c31 -11 65 -19 100 -19s68 8 100 19v-319l-100 100l-100 -100v319z" />
-    <glyph glyph-name="17" unicode="&#xe017;"
-d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300c0 -66 21 -126 56 -175l419 419c-49 35 -109 56 -175 56zM644 575l-419 -419c49 -35 109 -56 175 -56c166 0 300 134 300 300
-c0 66 -21 126 -56 175z" />
-    <glyph glyph-name="18" unicode="&#xe018;"
-d="M0 700h100v-600h700v-100h-800v700zM500 700h200v-500h-200v500zM200 500h200v-300h-200v300z" />
-    <glyph glyph-name="19" unicode="&#xe019;"
-d="M397 800c13 1 23 -4 34 -13c2 -2 214 -254 241 -287h128v-100h-100v-366c0 -18 -16 -34 -34 -34h-532c-18 0 -34 16 -34 34v366h-100v100h128l234 281c9 11 22 18 35 19zM400 672l-144 -172h288zM250 300c-28 0 -50 -22 -50 -50v-100c0 -28 22 -50 50 -50s50 22 50 50
-v100c0 28 -22 50 -50 50zM550 300c-28 0 -50 -22 -50 -50v-100c0 -28 22 -50 50 -50s50 22 50 50v100c0 28 -22 50 -50 50z" />
-    <glyph glyph-name="1a" unicode="&#xe01a;"
-d="M9 700h682c6 0 9 -4 9 -10v-190h100v-200h-100v-191c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v582c0 6 3 9 9 9zM100 600v-400h500v400h-500z" />
-    <glyph glyph-name="1b" unicode="&#xe01b;"
-d="M9 700h682c6 0 9 -4 9 -10v-190h100v-200h-100v-191c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v582c0 6 3 9 9 9z" />
-    <glyph glyph-name="1c" unicode="&#xe01c;"
-d="M92 650c0 23 19 50 45 50h3h5h5h500c28 0 50 -22 50 -50s-22 -50 -50 -50h-50v-141c9 -17 120 -231 166 -309c16 -26 34 -61 34 -106c0 -39 -15 -77 -41 -103h-3c-26 -25 -62 -41 -100 -41h-512c-39 0 -77 15 -103 41s-41 64 -41 103c0 46 18 80 34 106
-c46 78 157 292 166 309v141h-50c-2 0 -6 -1 -8 -1c-28 0 -50 23 -50 51zM500 600h-200v-162l-6 -10s-63 -123 -119 -228h450c-56 105 -119 228 -119 228l-6 10v162z" />
-    <glyph glyph-name="1d" unicode="&#xe01d;"
-d="M400 800c110 0 200 -90 200 -200c0 -104 52 -198 134 -266c41 -34 66 -82 66 -134h-800c0 52 25 100 66 134c82 68 134 162 134 266c0 110 90 200 200 200zM300 100h200c0 -55 -45 -100 -100 -100s-100 45 -100 100z" />
-    <glyph glyph-name="1e" unicode="&#xe01e;" horiz-adv-x="600"
-d="M150 800h50l350 -250l-225 -147l225 -153l-350 -250h-50v250l-75 -75l-75 75l150 150l-150 150l75 75l75 -75v250zM250 650v-200l150 100zM250 350v-200l150 100z" />
-    <glyph glyph-name="1f" unicode="&#xe01f;"
-d="M0 800h500c110 0 200 -90 200 -200c0 -47 -17 -91 -44 -125c85 -40 144 -125 144 -225c0 -138 -112 -250 -250 -250h-550v100c55 0 100 45 100 100v400c0 55 -45 100 -100 100v100zM300 700v-200h100c55 0 100 45 100 100s-45 100 -100 100h-100zM300 400v-300h150
-c83 0 150 67 150 150s-67 150 -150 150h-150z" />
-    <glyph glyph-name="20" unicode="&#xe020;" horiz-adv-x="600"
-d="M300 800v-300h200l-300 -500v300h-200z" />
-    <glyph glyph-name="21" unicode="&#xe021;"
-d="M100 800h300v-300l100 100l100 -100v300h50c28 0 50 -22 50 -50v-550h-550c-28 0 -50 -22 -50 -50s22 -50 50 -50h550v-100h-550c-83 0 -150 67 -150 150v550l3 19c8 39 39 70 78 78z" />
-    <glyph glyph-name="22" unicode="&#xe022;" horiz-adv-x="400"
-d="M0 800h400v-800l-200 200l-200 -200v800z" />
-    <glyph glyph-name="23" unicode="&#xe023;"
-d="M0 800h800v-100h-800v100zM0 600h300v-103h203v103h297v-591c0 -6 -3 -9 -9 -9h-782c-6 0 -9 3 -9 9v591z" />
-    <glyph glyph-name="24" unicode="&#xe024;"
-d="M300 800h200c55 0 100 -45 100 -100v-100h191c6 0 9 -3 9 -9v-241c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v241c0 6 3 9 9 9h191v100c0 55 45 100 100 100zM300 700v-100h200v100h-200zM0 209c16 -6 32 -9 50 -9h700c18 0 34 3 50 9v-200c0 -6 -3 -9 -9 -9h-782
-c-6 0 -9 3 -9 9v200z" />
-    <glyph glyph-name="25" unicode="&#xe025;" horiz-adv-x="600"
-d="M300 800c58 0 110 -16 147 -53s53 -89 53 -147h-100c0 39 -11 61 -25 75s-36 25 -75 25c-35 0 -55 -10 -72 -31s-28 -55 -28 -94c0 -51 20 -107 28 -175h172v-100h-178c-14 -60 -49 -127 -113 -200h491v-100h-600v122l16 12c69 69 95 121 106 166h-122v100h125
-c-8 50 -25 106 -25 175c0 58 16 114 50 156c34 43 88 69 150 69z" />
-    <glyph glyph-name="26" unicode="&#xe026;"
-d="M34 700h4h3h4h5h700c28 0 50 -22 50 -50v-700c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v700v2c0 20 15 42 34 48zM150 600c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50zM350 600c-28 0 -50 -22 -50 -50s22 -50 50 -50h300c28 0 50 22 50 50
-s-22 50 -50 50h-300zM100 400v-400h600v400h-600z" />
-    <glyph glyph-name="27" unicode="&#xe027;"
-d="M744 797l6 -3l44 -44c4 -4 3 -8 0 -12l-266 -375l-15 -13l-25 -12c-23 72 -78 127 -150 150l12 25l13 15l375 266zM266 400c74 0 134 -60 134 -134c0 -147 -119 -266 -266 -266c-48 0 -95 12 -134 34c80 46 134 133 134 232c0 74 58 134 132 134z" />
-    <glyph glyph-name="28" unicode="&#xe028;"
-d="M9 451c0 23 19 50 46 50c8 0 19 -3 26 -7l131 -66l29 22c-79 81 -1 250 118 250s197 -167 119 -250l28 -22l131 66c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-115 -56c9 -16 19 -33 25 -50h68c28 0 50 -22 50 -50s-22 -50 -50 -50h-50
-c0 -23 -2 -45 -6 -66l78 -40c21 -5 37 -28 37 -49c0 -28 -22 -50 -50 -50c-10 0 -23 5 -31 11l-65 35c-24 -46 -62 -86 -103 -110c-35 19 -60 45 -60 72v135v4v5v6v5v5v87c0 28 -22 50 -50 50c-24 0 -45 -17 -50 -40c1 -3 1 -8 1 -11s0 -8 -1 -11v-82v-4v-5v-144
-c0 -28 -24 -53 -59 -72c-41 25 -79 64 -103 110l-66 -35c-8 -6 -21 -11 -31 -11c-28 0 -50 22 -50 50c0 21 16 44 37 49l78 40c-4 21 -6 43 -6 66h-50h-5c-28 0 -50 22 -50 50c0 26 22 50 50 50h5h69c6 17 16 34 25 50l-116 56c-16 7 -28 27 -28 45z" />
-    <glyph glyph-name="29" unicode="&#xe029;"
-d="M600 700h91c6 0 9 -3 9 -9v-582c0 -6 -3 -9 -9 -9h-91v600zM210 503l290 147v-500l-250 125v-3c-15 0 -25 -8 -28 -22l75 -178c11 -25 0 -58 -25 -69s-58 0 -69 25l-103 272h-91c-6 0 -9 3 -9 9v182c0 6 3 9 9 9h182z" />
-    <glyph glyph-name="2a" unicode="&#xe02a;"
-d="M9 800h682c6 0 9 -3 9 -9v-782c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v782c0 6 3 9 9 9zM100 700v-200h500v200h-500zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400v-300h100v300h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100z" />
-    <glyph glyph-name="2b" unicode="&#xe02b;"
-d="M0 800h700v-200h-700v200zM0 500h700v-491c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v491zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100z" />
-    <glyph glyph-name="2c" unicode="&#xe02c;"
-d="M409 800h182c6 0 10 -4 12 -9l94 -182c2 -5 6 -9 12 -9h82c6 0 9 -3 9 -9v-582c0 -6 -3 -9 -9 -9h-782c-6 0 -9 3 -9 9v441c0 83 67 150 150 150h141c6 0 10 4 12 9l94 182c2 5 6 9 12 9zM150 500c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z
-M500 500c-110 0 -200 -90 -200 -200s90 -200 200 -200s200 90 200 200s-90 200 -200 200zM500 400c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100s45 100 100 100z" />
-    <glyph glyph-name="2d" unicode="&#xe02d;"
-d="M0 600h800l-400 -400z" />
-    <glyph glyph-name="2e" unicode="&#xe02e;" horiz-adv-x="400"
-d="M400 800v-800l-400 400z" />
-    <glyph glyph-name="2f" unicode="&#xe02f;" horiz-adv-x="400"
-d="M0 800l400 -400l-400 -400v800z" />
-    <glyph glyph-name="30" unicode="&#xe030;"
-d="M400 600l400 -400h-800z" />
-    <glyph glyph-name="31" unicode="&#xe031;"
-d="M0 550c0 23 20 50 46 50h3h5h4h200c17 0 37 -13 44 -28l38 -72h444c14 0 19 -12 15 -25l-81 -250c-4 -13 -21 -25 -35 -25h-350c-14 0 -30 12 -34 25c-27 83 -54 167 -81 250l-10 25h-150c-2 0 -5 -1 -7 -1c-28 0 -51 23 -51 51zM358 100c28 0 50 -22 50 -50
-s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM658 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
-    <glyph glyph-name="32" unicode="&#xe032;"
-d="M0 700h500v-100h-300v-300h-100l-100 -100v500zM300 500h500v-500l-100 100h-400v400z" />
-    <glyph glyph-name="33" unicode="&#xe033;"
-d="M641 700l143 -141l-493 -493c-71 76 -146 148 -219 222l-72 71l141 141c50 -51 101 -101 153 -150c116 117 234 231 347 350z" />
-    <glyph glyph-name="34" unicode="&#xe034;"
-d="M150 600l250 -250l250 250l150 -150l-400 -400l-400 400z" />
-    <glyph glyph-name="35" unicode="&#xe035;" horiz-adv-x="600"
-d="M400 800l150 -150l-250 -250l250 -250l-150 -150l-400 400z" />
-    <glyph glyph-name="36" unicode="&#xe036;" horiz-adv-x="600"
-d="M150 800l400 -400l-400 -400l-150 150l250 250l-250 250z" />
-    <glyph glyph-name="37" unicode="&#xe037;"
-d="M400 600l400 -400l-150 -150l-250 250l-250 -250l-150 150z" />
-    <glyph glyph-name="38" unicode="&#xe038;"
-d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM600 622l-250 -250l-100 100l-72 -72l172 -172l322 322z" />
-    <glyph glyph-name="39" unicode="&#xe039;"
-d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM250 622l-72 -72l150 -150l-150 -150l72 -72l150 150l150 -150l72 72l-150 150l150 150l-72 72l-150 -150z" />
-    <glyph glyph-name="3a" unicode="&#xe03a;"
-d="M350 800c28 0 50 -22 50 -50v-50h75c14 0 25 -11 25 -25v-75h-300v75c0 14 11 25 25 25h75v50c0 28 22 50 50 50zM25 700h75v-200h500v200h75c14 0 25 -11 25 -25v-650c0 -14 -11 -25 -25 -25h-650c-14 0 -25 11 -25 25v650c0 14 11 25 25 25z" />
-    <glyph glyph-name="3b" unicode="&#xe03b;"
-d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM350 600h100v-181c23 -24 47 -47 72 -69l-72 -72c-27 30 -55 59 -84 88l-16 12
-v222z" />
-    <glyph glyph-name="3c" unicode="&#xe03c;"
-d="M450 800c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -18 -3 -34 -9 -50h-191v50c0 83 -67 150 -150 150s-150 -67 -150 -150v-50h-272c-17 30 -28 63 -28 100c0 110 90 200 200 200c23 114 129 200 250 200zM434 400h3h4c3 0 6 1 9 1c28 0 50 -22 50 -50v-1
-v-150h150l-200 -200l-200 200h150v150v2c0 20 15 42 34 48z" />
-    <glyph glyph-name="3d" unicode="&#xe03d;"
-d="M450 800c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -18 -3 -34 -9 -50h-141l-200 200l-200 -200h-222c-17 30 -28 63 -28 100c0 110 90 200 200 200c23 114 129 200 250 200zM450 350l250 -250h-200v-50c0 -28 -22 -50 -50 -50s-50 22 -50 50v50h-200z" />
-    <glyph glyph-name="3e" unicode="&#xe03e;"
-d="M450 700c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -83 -67 -150 -150 -150h-450c-110 0 -200 90 -200 200s90 200 200 200c23 114 129 200 250 200z" />
-    <glyph glyph-name="3f" unicode="&#xe03f;"
-d="M250 800c82 0 154 -40 200 -100c-143 0 -270 -85 -325 -209c-36 -10 -70 -25 -100 -47c-16 33 -25 67 -25 106c0 138 112 250 250 250zM450 600c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -83 -67 -150 -150 -150h-450c-110 0 -200 90 -200 200
-s90 200 200 200c23 114 129 200 250 200z" />
-    <glyph glyph-name="40" unicode="&#xe040;"
-d="M500 700h100l-300 -600h-100zM100 600h100l-100 -200l100 -200h-100l-100 200zM600 600h100l100 -200l-100 -200h-100l100 200z" />
-    <glyph glyph-name="41" unicode="&#xe041;"
-d="M350 800h100l50 -119l28 -12l119 50l72 -72l-50 -119l12 -28l119 -50v-100l-119 -50l-12 -28l50 -119l-72 -72l-119 50l-28 -12l-50 -119h-100l-50 119l-28 12l-119 -50l-72 72l50 119l-12 28l-119 50v100l119 50l12 28l-50 119l72 72l119 -50l28 12zM400 550
-c-83 0 -150 -67 -150 -150s67 -150 150 -150s150 67 150 150s-67 150 -150 150z" />
-    <glyph glyph-name="42" unicode="&#xe042;"
-d="M0 800h800v-200h-800v200zM200 500h400l-200 -200zM0 100h800v-100h-800v100z" />
-    <glyph glyph-name="43" unicode="&#xe043;"
-d="M0 800h100v-800h-100v800zM600 800h200v-800h-200v800zM500 600v-400l-200 200z" />
-    <glyph glyph-name="44" unicode="&#xe044;"
-d="M0 800h200v-800h-200v800zM700 800h100v-800h-100v800zM300 600l200 -200l-200 -200v400z" />
-    <glyph glyph-name="45" unicode="&#xe045;"
-d="M0 800h800v-100h-800v100zM400 500l200 -200h-400zM0 200h800v-200h-800v200z" />
-    <glyph glyph-name="46" unicode="&#xe046;"
-d="M150 700c83 0 150 -67 150 -150v-50h100v50c0 83 67 150 150 150s150 -67 150 -150s-67 -150 -150 -150h-50v-100h50c83 0 150 -67 150 -150s-67 -150 -150 -150s-150 67 -150 150v50h-100v-50c0 -83 -67 -150 -150 -150s-150 67 -150 150s67 150 150 150h50v100h-50
-c-83 0 -150 67 -150 150s67 150 150 150zM150 600c-28 0 -50 -22 -50 -50s22 -50 50 -50h50v50c0 28 -22 50 -50 50zM550 600c-28 0 -50 -22 -50 -50v-50h50c28 0 50 22 50 50s-22 50 -50 50zM300 400v-100h100v100h-100zM150 200c-28 0 -50 -22 -50 -50s22 -50 50 -50
-s50 22 50 50v50h-50zM500 200v-50c0 -28 22 -50 50 -50s50 22 50 50s-22 50 -50 50h-50z" />
-    <glyph glyph-name="47" unicode="&#xe047;"
-d="M0 791c0 5 4 9 9 9h782c6 0 9 -4 9 -10v-790l-200 200h-591c-6 0 -9 3 -9 9v582z" />
-    <glyph glyph-name="48" unicode="&#xe048;"
-d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM600 600l-100 -300l-300 -100l100 300zM400 450c-28 0 -50 -22 -50 -50
-s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
-    <glyph glyph-name="49" unicode="&#xe049;"
-d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700v-600c166 0 300 134 300 300s-134 300 -300 300z" />
-    <glyph glyph-name="4a" unicode="&#xe04a;"
-d="M0 800h800v-100h-800v100zM0 600h500v-100h-500v100zM0 300h800v-100h-800v100zM0 100h600v-100h-600v100zM750 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
-    <glyph glyph-name="4b" unicode="&#xe04b;"
-d="M25 700h750c14 0 25 -11 25 -25v-75h-800v75c0 14 11 25 25 25zM0 500h800v-375c0 -14 -11 -25 -25 -25h-750c-14 0 -25 11 -25 25v375zM100 300v-100h100v100h-100zM300 300v-100h100v100h-100z" />
-    <glyph glyph-name="4c" unicode="&#xe04c;"
-d="M100 800h100v-100h450l100 100l50 -50l-100 -100v-450h100v-100h-100v-100h-100v100h-500v500h-100v100h100v100zM200 600v-350l350 350h-350zM600 550l-350 -350h350v350z" />
-    <glyph glyph-name="4d" unicode="&#xe04d;"
-d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM400 600c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z
-M200 452c0 20 15 42 34 48h3h3h8c12 0 28 -7 36 -16l91 -90l25 6c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100l6 25l-90 91c-9 8 -16 24 -16 36zM550 500c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
-    <glyph glyph-name="4e" unicode="&#xe04e;"
-d="M300 800h200v-300h200l-300 -300l-300 300h200v300zM0 100h800v-100h-800v100z" />
-    <glyph glyph-name="4f" unicode="&#xe04f;"
-d="M0 800h800v-100h-800v100zM400 600l300 -300h-200v-300h-200v300h-200z" />
-    <glyph glyph-name="50" unicode="&#xe050;"
-d="M200 700h600v-600h-600l-200 300zM350 622l-72 -72l150 -150l-150 -150l72 -72l150 150l150 -150l72 72l-150 150l150 150l-72 72l-150 -150z" />
-    <glyph glyph-name="51" unicode="&#xe051;"
-d="M400 700c220 0 400 -180 400 -400h-100c0 166 -134 300 -300 300s-300 -134 -300 -300h-100c0 220 180 400 400 400zM341 491l59 -88l59 88c81 -25 141 -101 141 -191c0 -110 -90 -200 -200 -200s-200 90 -200 200c0 90 60 166 141 191z" />
-    <glyph glyph-name="52" unicode="&#xe052;"
-d="M0 800h300v-400h400v-400h-700v800zM400 800l300 -300h-300v300zM100 600v-100h100v100h-100zM100 400v-100h100v100h-100zM100 200v-100h400v100h-400z" />
-    <glyph glyph-name="53" unicode="&#xe053;" horiz-adv-x="600"
-d="M200 700h100v-100h75c30 0 58 -6 81 -22s44 -44 44 -78v-100h-100v94c-4 3 -13 6 -25 6h-250c-14 0 -25 -11 -25 -25v-50c0 -15 20 -40 34 -44l257 -65c66 -16 109 -73 109 -141v-50c0 -68 -57 -125 -125 -125h-75v-100h-100v100h-75c-30 0 -58 6 -81 22s-44 44 -44 78
-v100h100v-94c4 -3 13 -6 25 -6h250c14 0 25 11 25 25v50c0 15 -20 40 -34 44l-257 65c-66 16 -109 73 -109 141v50c0 68 57 125 125 125h75v100z" />
-    <glyph glyph-name="54" unicode="&#xe054;"
-d="M0 700h300v-300l-300 -300v600zM500 700h300v-300l-300 -300v600z" />
-    <glyph glyph-name="55" unicode="&#xe055;"
-d="M300 700v-600h-300v300zM800 700v-600h-300v300z" />
-    <glyph glyph-name="56" unicode="&#xe056;"
-d="M300 700v-100c-111 0 -200 -89 -200 -200h200v-300h-300v300c0 165 135 300 300 300zM800 700v-100c-111 0 -200 -89 -200 -200h200v-300h-300v300c0 165 135 300 300 300z" />
-    <glyph glyph-name="57" unicode="&#xe057;"
-d="M0 700h300v-300c0 -165 -135 -300 -300 -300v100c111 0 200 89 200 200h-200v300zM500 700h300v-300c0 -165 -135 -300 -300 -300v100c111 0 200 89 200 200h-200v300z" />
-    <glyph glyph-name="58" unicode="&#xe058;" horiz-adv-x="600"
-d="M300 800l34 -34c11 -11 266 -270 266 -488c0 -165 -135 -300 -300 -300s-300 135 -300 300c0 218 255 477 266 488zM150 328c-28 0 -50 -22 -50 -50c0 -110 90 -200 200 -200c28 0 50 22 50 50s-22 50 -50 50c-55 0 -100 45 -100 100c0 28 -22 50 -50 50z" />
-    <glyph glyph-name="59" unicode="&#xe059;"
-d="M400 800l400 -500h-800zM0 200h800v-200h-800v200z" />
-    <glyph glyph-name="5a" unicode="&#xe05a;" horiz-adv-x="600"
-d="M300 800l300 -300h-600zM0 300h600l-300 -300z" />
-    <glyph glyph-name="5b" unicode="&#xe05b;"
-d="M0 500h200v-200h-200v200zM300 500h200v-200h-200v200zM600 500h200v-200h-200v200z" />
-    <glyph glyph-name="5c" unicode="&#xe05c;"
-d="M0 700h800v-100l-400 -200l-400 200v100zM0 500l400 -200l400 200v-400h-800v400z" />
-    <glyph glyph-name="5d" unicode="&#xe05d;"
-d="M400 800l400 -200v-600h-800v600zM400 688l-300 -150v-188l300 -150l300 150v188zM200 500h400v-100l-200 -100l-200 100v100z" />
-    <glyph glyph-name="5e" unicode="&#xe05e;"
-d="M600 700c69 0 134 -19 191 -50l-16 -106c-49 35 -109 56 -175 56c-131 0 -240 -84 -281 -200h331l-16 -100h-334c0 -36 8 -68 19 -100h297l-16 -100h-222c55 -61 133 -100 222 -100c78 0 147 30 200 78v-122c-59 -35 -127 -56 -200 -56c-147 0 -274 82 -344 200h-256
-l19 100h197c-8 32 -16 66 -16 100h-200l25 100h191c45 172 198 300 384 300z" />
-    <glyph glyph-name="5f" unicode="&#xe05f;"
-d="M0 700h700v-100h-700v100zM0 500h500v-100h-500v100zM0 300h800v-100h-800v100zM0 100h100v-100h-100v100zM200 100h100v-100h-100v100zM400 100h100v-100h-100v100z" />
-    <glyph glyph-name="60" unicode="&#xe060;"
-d="M0 800h800v-100h-800v100zM200 600h400l-200 -200zM0 200h800v-200h-800v200z" />
-    <glyph glyph-name="61" unicode="&#xe061;"
-d="M0 800h100v-800h-100v800zM600 800h200v-800h-200v800zM200 600l200 -200l-200 -200v400z" />
-    <glyph glyph-name="62" unicode="&#xe062;"
-d="M0 800h200v-800h-200v800zM700 800h100v-800h-100v800zM600 600v-400l-200 200z" />
-    <glyph glyph-name="63" unicode="&#xe063;"
-d="M0 800h800v-200h-800v200zM400 400l200 -200h-400zM0 100h800v-100h-800v100z" />
-    <glyph glyph-name="64" unicode="&#xe064;"
-d="M0 800h200v-100h-100v-600h600v100h100v-200h-800v800zM400 800h400v-400l-150 150l-250 -250l-100 100l250 250z" />
-    <glyph glyph-name="65" unicode="&#xe065;"
-d="M403 700c247 0 397 -300 397 -300s-150 -300 -397 -300c-253 0 -403 300 -403 300s150 300 403 300zM400 600c-110 0 -200 -90 -200 -200s90 -200 200 -200s200 90 200 200s-90 200 -200 200zM400 500c10 0 19 -3 28 -6c-16 -8 -28 -24 -28 -44c0 -28 22 -50 50 -50
-c20 0 36 12 44 28c3 -9 6 -18 6 -28c0 -55 -45 -100 -100 -100s-100 45 -100 100s45 100 100 100z" />
-    <glyph glyph-name="66" unicode="&#xe066;" horiz-adv-x="900"
-d="M331 700h3h3c3 1 7 1 10 1c12 0 29 -8 37 -17l94 -93l66 65c57 57 155 57 212 0c58 -58 58 -154 0 -212l-65 -66l93 -94c10 -8 18 -25 18 -38c0 -28 -22 -50 -50 -50c-13 0 -32 9 -40 20l-62 65l-381 -381h-269v272l375 381l-63 63c-9 8 -16 24 -16 36c0 20 16 42 35 48z
-M447 481l-313 -315l128 -132l316 316z" />
-    <glyph glyph-name="67" unicode="&#xe067;"
-d="M0 800h300v-400h400v-400h-700v800zM400 800l300 -300h-300v300z" />
-    <glyph glyph-name="68" unicode="&#xe068;"
-d="M200 800c0 0 200 -100 200 -300s-298 -302 -200 -500c0 0 -200 100 -200 300s300 300 200 500zM500 500c0 0 200 -100 200 -300c0 -150 -60 -200 -100 -200h-300c0 200 300 300 200 500z" />
-    <glyph glyph-name="69" unicode="&#xe069;"
-d="M0 800h100v-800h-100v800zM200 800h300v-100h300l-200 -203l200 -197h-400v100h-200v400z" />
-    <glyph glyph-name="6a" unicode="&#xe06a;" horiz-adv-x="400"
-d="M150 800h150l-100 -200h200l-150 -300h150l-300 -300l-100 300h134l66 200h-200z" />
-    <glyph glyph-name="6b" unicode="&#xe06b;"
-d="M0 800h300v-100h500v-100h-800v200zM0 500h800v-450c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v450z" />
-    <glyph glyph-name="6c" unicode="&#xe06c;"
-d="M150 800c83 0 150 -67 150 -150c0 -66 -41 -121 -100 -141v-118c15 5 33 9 50 9h200c28 0 50 22 50 50v59c-59 20 -100 75 -100 141c0 83 67 150 150 150s150 -67 150 -150c0 -66 -41 -121 -100 -141v-59c0 -82 -68 -150 -150 -150h-200c-14 0 -25 -7 -34 -16
-c50 -24 84 -74 84 -134c0 -83 -67 -150 -150 -150s-150 67 -150 150c0 66 41 121 100 141v218c-59 20 -100 75 -100 141c0 83 67 150 150 150z" />
-    <glyph glyph-name="6d" unicode="&#xe06d;"
-d="M0 800h400l-150 -150l150 -150l-100 -100l-150 150l-150 -150v400zM500 400l150 -150l150 150v-400h-400l150 150l-150 150z" />
-    <glyph glyph-name="6e" unicode="&#xe06e;"
-d="M100 800l150 -150l150 150v-400h-400l150 150l-150 150zM400 400h400l-150 -150l150 -150l-100 -100l-150 150l-150 -150v400z" />
-    <glyph glyph-name="6f" unicode="&#xe06f;"
-d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700c-56 0 -108 -17 -153 -44l22 -19c33 -18 13 -48 -13 -59c-30 -13 -77 10 -65 -41c13 -55 -27 -3 -47 -15c-42 -26 49 -152 31 -156l-59 34c-8 0 -13 -5 -16 -10
-c1 -30 10 -57 19 -84c28 -11 77 -2 100 -25c47 -28 97 -115 75 -159c34 -13 68 -22 106 -22c101 0 193 48 247 125c3 24 -8 44 -50 44c-69 0 -156 13 -153 97c2 46 101 108 66 143c-30 30 12 39 12 66c0 37 -65 32 -69 50s20 36 41 56c-30 10 -60 19 -94 19zM631 591
-c-38 -11 -94 -35 -87 -53c6 -15 52 -1 65 -13c11 -10 16 -59 44 -31l22 22v3c-11 26 -26 50 -44 72z" />
-    <glyph glyph-name="70" unicode="&#xe070;"
-d="M703 800l97 -100l-400 -400l-100 100l-200 -203l-100 100l300 303l100 -100zM0 100h800v-100h-800v100z" />
-    <glyph glyph-name="71" unicode="&#xe071;"
-d="M0 700h100v-100h-100v100zM200 700h100v-100h-100v100zM400 700h100v-100h-100v100zM600 700h100v-100h-100v100zM0 500h100v-100h-100v100zM200 500h100v-100h-100v100zM400 500h100v-100h-100v100zM600 500h100v-100h-100v100zM0 300h100v-100h-100v100zM200 300h100
-v-100h-100v100zM400 300h100v-100h-100v100zM600 300h100v-100h-100v100zM0 100h100v-100h-100v100zM200 100h100v-100h-100v100zM400 100h100v-100h-100v100zM600 100h100v-100h-100v100z" />
-    <glyph glyph-name="72" unicode="&#xe072;"
-d="M0 800h200v-200h-200v200zM300 800h200v-200h-200v200zM600 800h200v-200h-200v200zM0 500h200v-200h-200v200zM300 500h200v-200h-200v200zM600 500h200v-200h-200v200zM0 200h200v-200h-200v200zM300 200h200v-200h-200v200zM600 200h200v-200h-200v200z" />
-    <glyph glyph-name="73" unicode="&#xe073;"
-d="M0 800h300v-300h-300v300zM500 800h300v-300h-300v300zM0 300h300v-300h-300v300zM500 300h300v-300h-300v300z" />
-    <glyph glyph-name="74" unicode="&#xe074;"
-d="M19 800h662c11 0 19 -8 19 -19v-331c0 -28 -22 -50 -50 -50h-600c-28 0 -50 22 -50 50v331c0 11 8 19 19 19zM0 309c16 -6 32 -9 50 -9h600c18 0 34 3 50 9v-290c0 -11 -8 -19 -19 -19h-662c-11 0 -19 8 -19 19v290zM550 200c-28 0 -50 -22 -50 -50s22 -50 50 -50
-s50 22 50 50s-22 50 -50 50z" />
-    <glyph glyph-name="75" unicode="&#xe075;"
-d="M0 700h300v-100h-50c-28 0 -50 -22 -50 -50v-150h300v150c0 28 -22 50 -50 50h-50v100h300v-100h-50c-28 0 -50 -22 -50 -50v-400c0 -28 22 -50 50 -50h50v-100h-300v100h50c28 0 50 22 50 50v150h-300v-150c0 -28 22 -50 50 -50h50v-100h-300v100h50c28 0 50 22 50 50
-v400c0 28 -22 50 -50 50h-50v100z" />
-    <glyph glyph-name="76" unicode="&#xe076;"
-d="M400 700c165 0 300 -135 300 -300v-100h50c28 0 50 -22 50 -50v-200c0 -28 -22 -50 -50 -50h-100c-28 0 -50 22 -50 50v350c0 111 -89 200 -200 200s-200 -89 -200 -200v-350c0 -28 -22 -50 -50 -50h-100c-28 0 -50 22 -50 50v200c0 28 22 50 50 50h50v100
-c0 165 135 300 300 300z" />
-    <glyph glyph-name="77" unicode="&#xe077;"
-d="M0 500c0 109 91 200 200 200s200 -91 200 -200c0 109 91 200 200 200s200 -91 200 -200c0 -55 -23 -105 -59 -141l-341 -340l-341 340c-36 36 -59 86 -59 141z" />
-    <glyph glyph-name="78" unicode="&#xe078;"
-d="M400 700l400 -300l-100 3v-403h-200v200h-200v-200h-200v400h-100z" />
-    <glyph glyph-name="79" unicode="&#xe079;"
-d="M0 800h800v-800h-800v800zM100 700v-300l100 100l400 -400h100v100l-200 200l100 100l100 -100v300h-600z" />
-    <glyph glyph-name="7a" unicode="&#xe07a;"
-d="M19 800h762c11 0 19 -8 19 -19v-762c0 -11 -8 -19 -19 -19h-762c-11 0 -19 8 -19 19v762c0 11 8 19 19 19zM100 600v-300h100l100 -100h200l100 100h100v300h-600z" />
-    <glyph glyph-name="7b" unicode="&#xe07b;"
-d="M200 600c80 0 142 -56 200 -122c58 66 119 122 200 122c131 0 200 -101 200 -200s-69 -200 -200 -200c-81 0 -142 56 -200 122c-58 -66 -121 -122 -200 -122c-131 0 -200 101 -200 200s69 200 200 200zM200 500c-74 0 -100 -54 -100 -100s26 -100 100 -100
-c42 0 88 47 134 100c-46 53 -92 100 -134 100zM600 500c-43 0 -88 -47 -134 -100c46 -53 91 -100 134 -100c74 0 100 54 100 100s-26 100 -100 100z" />
-    <glyph glyph-name="7c" unicode="&#xe07c;" horiz-adv-x="400"
-d="M300 800c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100s45 100 100 100zM150 550c83 0 150 -69 150 -150c0 -66 -100 -214 -100 -250c0 -28 22 -50 50 -50s50 22 50 50h100c0 -83 -67 -150 -150 -150s-150 64 -150 150s100 222 100 250s-22 50 -50 50
-s-50 -22 -50 -50h-100c0 83 67 150 150 150z" />
-    <glyph glyph-name="7d" unicode="&#xe07d;"
-d="M200 800h500v-100h-122c-77 -197 -156 -392 -234 -588l-6 -12h162v-100h-500v100h122c77 197 156 392 234 588l7 12h-163v100z" />
-    <glyph glyph-name="7e" unicode="&#xe07e;"
-d="M0 700h800v-100h-800v100zM0 500h800v-100h-800v100zM0 300h800v-100h-800v100zM100 100h600v-100h-600v100z" />
-    <glyph glyph-name="7f" unicode="&#xe07f;"
-d="M0 700h800v-100h-800v100zM0 500h800v-100h-800v100zM0 300h800v-100h-800v100zM0 100h600v-100h-600v100z" />
-    <glyph glyph-name="80" unicode="&#xe080;"
-d="M0 700h800v-100h-800v100zM0 500h800v-100h-800v100zM0 300h800v-100h-800v100zM200 100h600v-100h-600v100z" />
-    <glyph glyph-name="81" unicode="&#xe081;"
-d="M550 800c138 0 250 -112 250 -250s-112 -250 -250 -250c-16 0 -32 0 -47 3l-3 -3v-100h-200v-200h-300v200l303 303c-3 15 -3 31 -3 47c0 138 112 250 250 250zM600 700c-55 0 -100 -45 -100 -100s45 -100 100 -100s100 45 100 100s-45 100 -100 100z" />
-    <glyph glyph-name="82" unicode="&#xe082;"
-d="M134 600h3h4h4h5h500c28 0 50 -22 50 -50v-350h100v-150c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v150h100v350v2c0 20 15 42 34 48zM200 500v-300h100v-100h200v100h100v300h-400z" />
-    <glyph glyph-name="83" unicode="&#xe083;"
-d="M0 800h400v-400h-400v400zM500 600h100v-400h-400v100h300v300zM700 400h100v-400h-400v100h300v300z" />
-    <glyph glyph-name="84" unicode="&#xe084;" horiz-adv-x="600"
-d="M337 694c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-300 -150c-8 -6 -21 -11 -31 -11c-28 0 -50 22 -50 50c0 21 16 44 37 49zM437 544c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-400 -200c-8 -6 -21 -11 -31 -11c-28 0 -50 22 -50 50
-c0 21 16 44 37 49zM437 344c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-106 -56c24 -4 43 -26 43 -50c0 -28 -23 -51 -51 -51c-2 0 -6 1 -8 1h-200c-26 1 -48 24 -48 50c0 16 12 36 26 44zM151 -50c0 23 20 50 46 50h3h4h5h100c28 0 50 -22 50 -50
-s-22 -50 -50 -50h-100c-2 0 -6 -1 -8 -1c-28 0 -50 23 -50 51z" />
-    <glyph glyph-name="85" unicode="&#xe085;"
-d="M199 800h100v-200h-200v100h100v100zM586 797h1c18 1 38 1 56 -3c36 -8 69 -26 97 -54c78 -78 78 -203 0 -281l-150 -150c-8 -13 -28 -24 -43 -24c-28 0 -50 22 -50 50c0 15 11 35 24 43l150 150c40 40 39 105 0 144c-41 41 -110 34 -144 0l-44 -44
-c-8 -13 -27 -24 -42 -24c-28 0 -50 22 -50 50c0 15 11 35 24 43l43 44c32 33 72 53 128 56zM208 490c4 5 14 16 22 16h3c2 0 6 1 8 1c28 0 50 -22 50 -50c0 -11 -6 -27 -14 -35l-150 -150c-40 -40 -39 -105 0 -144c41 -41 110 -34 144 0l44 44c8 13 27 24 42 24
-c28 0 50 -22 50 -50c0 -15 -11 -35 -24 -43l-43 -44c-22 -22 -48 -37 -75 -47c-70 -25 -151 -9 -207 47c-78 78 -78 203 0 281zM499 200h200v-100h-100v-100h-100v200z" />
-    <glyph glyph-name="86" unicode="&#xe086;"
-d="M586 797c18 1 39 1 57 -3c36 -8 69 -26 97 -54c78 -78 78 -203 0 -281l-150 -150c-62 -62 -132 -81 -182 -78s-69 17 -84 25s-26 27 -26 44c0 28 22 51 50 51c8 0 19 -3 26 -7c0 0 15 -11 41 -13s62 3 106 47l150 150c40 40 39 105 0 144c-41 41 -110 34 -144 0
-c-8 -13 -28 -24 -43 -24c-28 0 -50 22 -50 50c0 15 11 35 24 43c32 33 72 53 128 56zM386 566c50 -2 64 -17 85 -22s37 -28 37 -49c0 -28 -22 -50 -50 -50c-10 0 -23 5 -31 11c0 0 -19 9 -47 10s-63 -4 -103 -44l-150 -150c-40 -40 -39 -105 0 -144c41 -41 110 -34 144 0
-c8 13 27 24 42 24c28 0 50 -22 50 -50c0 -15 -10 -35 -23 -43c-22 -22 -48 -37 -75 -47c-70 -25 -151 -9 -207 47c-78 78 -78 203 0 281l150 150c60 60 128 78 178 76z" />
-    <glyph glyph-name="87" unicode="&#xe087;"
-d="M0 700h300v-300h-300v300zM400 700h400v-100h-400v100zM400 500h300v-100h-300v100zM0 300h300v-300h-300v300zM400 300h400v-100h-400v100zM400 100h300v-100h-300v100z" />
-    <glyph glyph-name="88" unicode="&#xe088;"
-d="M50 700c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM200 700h600v-100h-600v100zM50 500c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM200 500h600v-100h-600v100zM50 300c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50
-s22 50 50 50zM200 300h600v-100h-600v100zM50 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM200 100h600v-100h-600v100z" />
-    <glyph glyph-name="89" unicode="&#xe089;"
-d="M800 800l-400 -800l-100 300l-300 100z" />
-    <glyph glyph-name="8a" unicode="&#xe08a;" horiz-adv-x="600"
-d="M300 700c110 0 200 -90 200 -200v-100h100v-400h-600v400h100v100c0 110 90 200 200 200zM300 600c-56 0 -100 -44 -100 -100v-100h200v100c0 56 -44 100 -100 100z" />
-    <glyph glyph-name="8b" unicode="&#xe08b;" horiz-adv-x="600"
-d="M300 800c110 0 200 -90 200 -200v-200h100v-400h-600v400h400v200c0 56 -44 100 -100 100s-100 -44 -100 -100h-100c0 110 90 200 200 200z" />
-    <glyph glyph-name="8c" unicode="&#xe08c;"
-d="M400 700v-100c-111 0 -200 -89 -200 -200h100l-150 -200l-150 200h100c0 165 135 300 300 300zM650 600l150 -200h-100c0 -165 -135 -300 -300 -300v100c111 0 200 89 200 200h-100z" />
-    <glyph glyph-name="8d" unicode="&#xe08d;"
-d="M100 800h600v-300h100l-150 -250l-150 250h100v200h-400v-100h-100v200zM150 550l150 -250h-100v-200h400v100h100v-200h-600v300h-100z" />
-    <glyph glyph-name="8e" unicode="&#xe08e;"
-d="M600 700l200 -150l-200 -150v100h-500v-100h-100v100c0 55 45 100 100 100h500v100zM200 300v-100h500v100h100v-100c0 -55 -45 -100 -100 -100h-500v-100l-200 150z" />
-    <glyph glyph-name="8f" unicode="&#xe08f;" horiz-adv-x="900"
-d="M350 800c193 0 350 -157 350 -350c0 -60 -17 -117 -44 -166c5 -3 12 -8 16 -12l100 -100c16 -16 30 -49 30 -72c0 -56 -46 -102 -102 -102c-23 0 -56 14 -72 30l-100 100c-4 3 -9 9 -12 13c-49 -26 -107 -41 -166 -41c-193 0 -350 157 -350 350s157 350 350 350zM350 200
-c142 0 250 108 250 250c0 139 -111 250 -250 250s-250 -111 -250 -250s111 -250 250 -250z" />
-    <glyph glyph-name="90" unicode="&#xe090;" horiz-adv-x="600"
-d="M300 800c166 0 300 -134 300 -300c0 -200 -300 -500 -300 -500s-300 300 -300 500c0 166 134 300 300 300zM300 700c-110 0 -200 -90 -200 -200s90 -200 200 -200s200 90 200 200s-90 200 -200 200z" />
-    <glyph glyph-name="91" unicode="&#xe091;" horiz-adv-x="900"
-d="M0 800h800v-541c1 -3 1 -8 1 -11s0 -7 -1 -10v-238h-800v800zM495 250c0 26 22 50 50 50h5h150v400h-600v-600h600v100h-150h-5c-28 0 -50 22 -50 50zM350 600c83 0 150 -67 150 -150c0 -100 -150 -250 -150 -250s-150 150 -150 250c0 83 67 150 150 150zM350 500
-c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
-    <glyph glyph-name="92" unicode="&#xe092;" horiz-adv-x="600"
-d="M0 700h200v-600h-200v600zM400 700h200v-600h-200v600z" />
-    <glyph glyph-name="93" unicode="&#xe093;" horiz-adv-x="600"
-d="M0 700l600 -300l-600 -300v600z" />
-    <glyph glyph-name="94" unicode="&#xe094;" horiz-adv-x="600"
-d="M300 700c166 0 300 -134 300 -300s-134 -300 -300 -300s-300 134 -300 300s134 300 300 300z" />
-    <glyph glyph-name="95" unicode="&#xe095;"
-d="M400 700v-600l-400 300zM400 400l400 300v-600z" />
-    <glyph glyph-name="96" unicode="&#xe096;"
-d="M0 700l400 -300l-400 -300v600zM400 100v600l400 -300z" />
-    <glyph glyph-name="97" unicode="&#xe097;"
-d="M0 700h200v-600h-200v600zM200 400l500 300v-600z" />
-    <glyph glyph-name="98" unicode="&#xe098;"
-d="M0 700l500 -300l-500 -300v600zM500 100v600h200v-600h-200z" />
-    <glyph glyph-name="99" unicode="&#xe099;" horiz-adv-x="600"
-d="M0 700h600v-600h-600v600z" />
-    <glyph glyph-name="9a" unicode="&#xe09a;"
-d="M200 800h400v-200h200v-400h-200v-200h-400v200h-200v400h200v200z" />
-    <glyph glyph-name="9b" unicode="&#xe09b;"
-d="M0 700h800v-100h-800v100zM0 403h800v-100h-800v100zM0 103h800v-100h-800v100z" />
-    <glyph glyph-name="9c" unicode="&#xe09c;" horiz-adv-x="600"
-d="M278 700c7 2 13 4 22 4c55 0 100 -45 100 -100v-4v-200c0 -55 -45 -100 -100 -100s-100 45 -100 100v200v2c0 44 35 88 78 98zM34 500h4h3c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-50c0 -111 89 -200 200 -200s200 89 200 200v50c0 28 22 50 50 50s50 -22 50 -50v-50
-c0 -148 -109 -270 -250 -294v-106h50c55 0 100 -45 100 -100h-400c0 55 45 100 100 100h50v106c-141 24 -250 146 -250 294v50v2c0 20 15 42 34 48z" />
-    <glyph glyph-name="9d" unicode="&#xe09d;"
-d="M0 500h800v-200h-800v200z" />
-    <glyph glyph-name="9e" unicode="&#xe09e;"
-d="M34 700h4h3h4h5h700c28 0 50 -22 50 -50v-500c0 -28 -22 -50 -50 -50h-250v-100h100c55 0 100 -45 100 -100h-600c0 55 45 100 100 100h100v100h-250c-28 0 -50 22 -50 50v500v2c0 20 15 42 34 48zM100 600v-400h600v400h-600z" />
-    <glyph glyph-name="9f" unicode="&#xe09f;"
-d="M272 700c-14 -40 -22 -83 -22 -128c0 -221 179 -400 400 -400c45 0 88 8 128 22c-53 -158 -202 -272 -378 -272c-221 0 -400 179 -400 400c0 176 114 325 272 378z" />
-    <glyph glyph-name="a0" unicode="&#xe0a0;"
-d="M350 700l150 -150h-100v-150h150v100l150 -150l-150 -150v100h-150v-150h100l-150 -150l-150 150h100v150h-150v-100l-150 150l150 150v-100h150v150h-100z" />
-    <glyph glyph-name="a1" unicode="&#xe0a1;"
-d="M800 800v-550c0 -83 -67 -150 -150 -150s-150 67 -150 150s67 150 150 150c17 0 35 -4 50 -9v206c-201 -6 -327 -27 -400 -50v-397c0 -83 -67 -150 -150 -150s-150 67 -150 150s67 150 150 150c17 0 35 -4 50 -9v409s100 100 600 100z" />
-    <glyph glyph-name="a2" unicode="&#xe0a2;" horiz-adv-x="700"
-d="M499 700c51 0 102 -20 141 -59c78 -78 78 -203 0 -281l-250 -244c-48 -48 -127 -48 -175 0s-48 127 0 175l96 97l69 -69l-90 -94l-7 -3c-10 -10 -10 -28 0 -38s28 -10 38 0l250 247c37 40 39 102 0 141s-104 40 -144 0l-278 -275c-66 -69 -68 -179 0 -247
-c69 -69 181 -69 250 0l9 12l116 113l69 -69l-125 -125c-107 -107 -281 -107 -388 0s-107 281 0 388l278 272c39 39 90 59 141 59z" />
-    <glyph glyph-name="a3" unicode="&#xe0a3;"
-d="M600 800l200 -200l-100 -100l-200 200zM400 600l200 -200l-400 -400h-200v200z" />
-    <glyph glyph-name="a4" unicode="&#xe0a4;"
-d="M550 800c83 0 150 -90 150 -200s-67 -200 -150 -200c-22 0 -40 8 -59 19c6 26 9 52 9 81c0 84 -27 158 -72 212c27 52 71 88 122 88zM250 700c83 0 150 -90 150 -200s-67 -200 -150 -200s-150 90 -150 200s67 200 150 200zM725 384c44 -22 75 -66 75 -118v-166h-200v66
-c0 50 -17 96 -44 134c66 2 126 33 169 84zM75 284c45 -53 106 -84 175 -84s130 31 175 84c44 -22 75 -66 75 -118v-166h-500v166c0 52 31 96 75 118z" />
-    <glyph glyph-name="a5" unicode="&#xe0a5;"
-d="M400 800c110 0 200 -112 200 -250s-90 -250 -200 -250s-200 112 -200 250s90 250 200 250zM191 300c54 -61 128 -100 209 -100s155 39 209 100c106 -5 191 -92 191 -200v-100h-800v100c0 108 85 195 191 200z" />
-    <glyph glyph-name="a6" unicode="&#xe0a6;" horiz-adv-x="600"
-d="M19 800h462c11 0 19 -8 19 -19v-762c0 -11 -8 -19 -19 -19h-462c-11 0 -19 8 -19 19v762c0 11 8 19 19 19zM100 700v-500h300v500h-300zM250 150c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
-    <glyph glyph-name="a7" unicode="&#xe0a7;"
-d="M350 800c17 0 34 -1 50 -3v-397l-297 297c63 64 150 103 247 103zM500 694c169 -25 300 -168 300 -344c0 -193 -157 -350 -350 -350c-85 0 -161 31 -222 81l272 272v341zM91 562l237 -234l-212 -212c-70 55 -116 138 -116 234c0 84 35 158 91 212z" />
-    <glyph glyph-name="a8" unicode="&#xe0a8;"
-d="M92 650c0 23 20 50 46 50h3h4h5h400c28 0 50 -22 50 -50s-22 -50 -50 -50h-50v-200h100c55 0 100 -45 100 -100h-300v-300l-56 -100l-44 100v300h-300c0 55 45 100 100 100h100v200h-50c-2 0 -6 -1 -8 -1c-28 0 -50 23 -50 51z" />
-    <glyph glyph-name="a9" unicode="&#xe0a9;"
-d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM300 600v-400l300 200z" />
-    <glyph glyph-name="aa" unicode="&#xe0aa;"
-d="M300 800h200v-300h300v-200h-300v-300h-200v300h-300v200h300v300z" />
-    <glyph glyph-name="ab" unicode="&#xe0ab;"
-d="M300 800h100v-400h-100v400zM172 656l62 -78l-40 -31c-58 -46 -94 -117 -94 -197c0 -139 111 -250 250 -250s250 111 250 250c0 80 -39 151 -97 197l-37 31l62 78l38 -31c82 -64 134 -164 134 -275c0 -193 -157 -350 -350 -350s-350 157 -350 350c0 111 53 211 134 275z
-" />
-    <glyph glyph-name="ac" unicode="&#xe0ac;"
-d="M200 800h400v-200h-400v200zM9 500h782c6 0 9 -3 9 -9v-282c0 -6 -3 -9 -9 -9h-91v200h-600v-200h-91c-6 0 -9 3 -9 9v282c0 6 3 9 9 9zM200 300h400v-300h-400v300z" />
-    <glyph glyph-name="ad" unicode="&#xe0ad;"
-d="M0 700h100v-700h-100v700zM700 700h100v-700h-100v700zM200 600h200v-100h-200v100zM300 400h200v-100h-200v100zM400 200h200v-100h-200v100z" />
-    <glyph glyph-name="ae" unicode="&#xe0ae;"
-d="M325 700c42 -141 87 -280 131 -419c29 74 59 148 88 222c30 -57 58 -114 87 -172h169v-100h-231l-13 28c-37 -92 -74 -184 -112 -275c-38 129 -79 257 -119 385c-42 -133 -83 -267 -125 -400c-28 88 -56 175 -84 262h-116v100h188l9 -34l3 -6c42 137 83 273 125 409z" />
-    <glyph glyph-name="af" unicode="&#xe0af;"
-d="M200 600c0 57 43 100 100 100s100 -43 100 -100c0 -28 -18 -48 -28 -72c-3 -6 -3 -16 -3 -28h231v-231c12 0 22 0 28 3c24 10 44 28 72 28c57 0 100 -43 100 -100s-43 -100 -100 -100c-28 0 -48 18 -72 28c-6 3 -16 3 -28 3v-231h-231c0 12 0 22 3 28c10 24 28 44 28 72
-c0 57 -43 100 -100 100s-100 -43 -100 -100c0 -28 18 -48 28 -72c3 -6 3 -16 3 -28h-231v600h231c0 12 0 22 -3 28c-10 24 -28 44 -28 72z" />
-    <glyph glyph-name="b0" unicode="&#xe0b0;" horiz-adv-x="500"
-d="M247 700c84 0 148 -20 191 -59s59 -93 59 -141c0 -117 -69 -181 -119 -225s-81 -67 -81 -150v-25h-100v25c0 117 65 181 115 225s85 67 85 150c0 25 -8 48 -28 66s-56 34 -122 34s-97 -18 -116 -37s-27 -43 -31 -69l-100 12c5 38 19 88 59 128s103 66 188 66zM197 0h100
-v-100h-100v100z" />
-    <glyph glyph-name="b1" unicode="&#xe0b1;"
-d="M450 800c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -69 -48 -127 -112 -144c-22 55 -75 94 -138 94c-20 0 -39 -5 -56 -12c-17 64 -75 112 -144 112s-127 -48 -144 -112c-17 7 -36 12 -56 12c-37 0 -71 -12 -97 -34c-33 36 -53 82 -53 134
-c0 110 90 200 200 200c23 114 129 200 250 200zM334 300h4h3c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-200c0 -28 -22 -50 -50 -50s-50 22 -50 50v200v2c0 20 15 42 34 48zM134 200h4h3c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-100c0 -28 -22 -50 -50 -50s-50 22 -50 50v100v2
-c0 20 15 42 34 48zM534 200h3h4c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-100c0 -28 -22 -50 -50 -50s-50 22 -50 50v100v2c0 20 15 42 34 48z" />
-    <glyph glyph-name="b2" unicode="&#xe0b2;"
-d="M600 800l200 -150l-200 -150v100h-50l-153 -191l175 -206l6 -3h22v100l200 -150l-200 -150v100h-25c-35 0 -56 12 -78 38l-166 190l-153 -190c-22 -27 -43 -38 -78 -38h-100v100h100l166 206l-163 191l-3 3h-100v100h100c34 0 56 -12 78 -38l153 -178l141 178
-c22 27 43 38 78 38h50v100z" />
-    <glyph glyph-name="b3" unicode="&#xe0b3;"
-d="M400 800c110 0 209 -47 281 -119l119 119v-300h-300l109 109c-54 55 -126 91 -209 91c-166 0 -300 -134 -300 -300s134 -300 300 -300c83 0 158 34 212 88l72 -72c-72 -72 -174 -116 -284 -116c-220 0 -400 180 -400 400s180 400 400 400z" />
-    <glyph glyph-name="b4" unicode="&#xe0b4;"
-d="M400 800h400v-400l-166 166l-400 -400l166 -166h-400v400l166 -166l400 400z" />
-    <glyph glyph-name="b5" unicode="&#xe0b5;" horiz-adv-x="600"
-d="M250 800l250 -300h-200v-200h200l-250 -300l-250 300h200v200h-200z" />
-    <glyph glyph-name="b6" unicode="&#xe0b6;"
-d="M300 600v-200h200v200l300 -250l-300 -250v200h-200v-200l-300 250z" />
-    <glyph glyph-name="b7" unicode="&#xe0b7;"
-d="M0 800c441 0 800 -359 800 -800h-200c0 333 -267 600 -600 600v200zM0 500c275 0 500 -225 500 -500h-200c0 167 -133 300 -300 300v200zM0 200c110 0 200 -90 200 -200h-200v200z" />
-    <glyph glyph-name="b8" unicode="&#xe0b8;"
-d="M100 800c386 0 700 -314 700 -700h-100c0 332 -268 600 -600 600v100zM100 600c276 0 500 -224 500 -500h-100c0 222 -178 400 -400 400v100zM100 400c165 0 300 -135 300 -300h-100c0 111 -89 200 -200 200v100zM100 200c55 0 100 -45 100 -100s-45 -100 -100 -100
-s-100 45 -100 100s45 100 100 100z" />
-    <glyph glyph-name="b9" unicode="&#xe0b9;"
-d="M300 800h400c55 0 100 -45 100 -100v-200h-400v150c0 28 -22 50 -50 50s-50 -22 -50 -50v-250h400v-300c0 -55 -45 -100 -100 -100h-500c-55 0 -100 45 -100 100v200h100v-150c0 -28 22 -50 50 -50s50 22 50 50v550c0 55 45 100 100 100z" />
-    <glyph glyph-name="ba" unicode="&#xe0ba;"
-d="M75 700h225v-100h-200v-500h400v100h100v-125c0 -41 -34 -75 -75 -75h-450c-41 0 -75 34 -75 75v550c0 41 34 75 75 75zM600 700l200 -200l-200 -200v100h-200c-94 0 -173 -65 -194 -153c23 199 189 353 394 353v100z" />
-    <glyph glyph-name="bb" unicode="&#xe0bb;"
-d="M500 700l300 -284l-300 -316v200h-100c-200 0 -348 -102 -400 -300c0 295 100 500 500 500v200z" />
-    <glyph glyph-name="bc" unicode="&#xe0bc;"
-d="M381 791l19 9l19 -9c127 -53 253 -108 381 -160v-31c0 -166 -67 -313 -147 -419c-40 -53 -83 -97 -125 -128s-82 -53 -128 -53s-86 22 -128 53s-85 75 -125 128c-80 107 -147 253 -147 419v31c128 52 254 107 381 160zM400 100v591l-294 -122c8 -126 58 -243 122 -328
-c35 -46 73 -86 106 -110s62 -31 66 -31z" />
-    <glyph glyph-name="bd" unicode="&#xe0bd;"
-d="M600 800h100v-800h-100v800zM400 700h100v-700h-100v700zM200 500h100v-500h-100v500zM0 300h100v-300h-100v300z" />
-    <glyph glyph-name="be" unicode="&#xe0be;"
-d="M300 800h100v-200h200l100 -100l-100 -100h-200v-400h-100v500h-200l-100 100l100 100h200v100z" />
-    <glyph glyph-name="bf" unicode="&#xe0bf;"
-d="M200 800h100v-600h200l-250 -200l-250 200h200v600zM400 800h200v-100h-200v100zM400 600h300v-100h-300v100zM400 400h400v-100h-400v100z" />
-    <glyph glyph-name="c0" unicode="&#xe0c0;"
-d="M200 800h100v-600h200l-250 -200l-250 200h200v600zM400 800h400v-100h-400v100zM400 600h300v-100h-300v100zM400 400h200v-100h-200v100z" />
-    <glyph glyph-name="c1" unicode="&#xe0c1;"
-d="M75 700h650c41 0 75 -34 75 -75v-550c0 -41 -34 -75 -75 -75h-650c-41 0 -75 34 -75 75v550c0 41 34 75 75 75zM100 600v-100h100v100h-100zM300 600v-100h400v100h-400zM100 400v-100h100v100h-100zM300 400v-100h400v100h-400zM100 200v-100h100v100h-100zM300 200
-v-100h400v100h-400z" />
-    <glyph glyph-name="c2" unicode="&#xe0c2;"
-d="M400 800l100 -300h300l-250 -200l100 -300l-250 200l-250 -200l100 300l-250 200h300z" />
-    <glyph glyph-name="c3" unicode="&#xe0c3;"
-d="M400 800c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM150 700c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM650 700c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM400 600c110 0 200 -90 200 -200
-s-90 -200 -200 -200s-200 90 -200 200s90 200 200 200zM50 450c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM750 450c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM150 200c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50
-s22 50 50 50zM650 200c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM400 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
-    <glyph glyph-name="c4" unicode="&#xe0c4;"
-d="M34 800h632c18 0 34 -16 34 -34v-732c0 -18 -16 -34 -34 -34h-632c-18 0 -34 16 -34 34v732c0 18 16 34 34 34zM100 700v-500h500v500h-500zM350 150c-38 0 -63 -42 -44 -75s69 -33 88 0s-6 75 -44 75z" />
-    <glyph glyph-name="c5" unicode="&#xe0c5;"
-d="M0 800h300l500 -500l-300 -300l-500 500v300zM200 700c-55 0 -100 -45 -100 -100s45 -100 100 -100s100 45 100 100s-45 100 -100 100z" />
-    <glyph glyph-name="c6" unicode="&#xe0c6;"
-d="M0 600h200l300 -300l-200 -200l-300 300v200zM340 600h160l300 -300l-200 -200l-78 78l119 122zM150 500c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
-    <glyph glyph-name="c7" unicode="&#xe0c7;"
-d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM400 600c110 0 200 -90 200 -200s-90 -200 -200 -200s-200 90 -200 200
-s90 200 200 200zM400 500c-56 0 -100 -44 -100 -100s44 -100 100 -100s100 44 100 100s-44 100 -100 100z" />
-    <glyph glyph-name="c8" unicode="&#xe0c8;"
-d="M0 700h559l-100 -100h-359v-500h500v159l100 100v-359h-700v700zM700 700l100 -100l-400 -400l-200 200l100 100l100 -100z" />
-    <glyph glyph-name="c9" unicode="&#xe0c9;"
-d="M9 800h782c6 0 9 -3 9 -9v-782c0 -6 -3 -9 -9 -9h-782c-6 0 -9 3 -9 9v782c0 6 3 9 9 9zM150 722l-72 -72l100 -100l-100 -100l72 -72l172 172zM400 500v-100h300v100h-300z" />
-    <glyph glyph-name="ca" unicode="&#xe0ca;"
-d="M0 800h800v-200h-50c0 55 -45 100 -100 100h-150v-550c0 -28 22 -50 50 -50h50v-100h-400v100h50c28 0 50 22 50 50v550h-150c-55 0 -100 -45 -100 -100h-50v200z" />
-    <glyph glyph-name="cb" unicode="&#xe0cb;"
-d="M0 700h100v-400h-100v400zM200 700h350c21 0 39 -13 47 -31c0 0 103 -291 103 -319s-22 -50 -50 -50h-150c-28 0 -50 -25 -50 -50s39 -158 47 -184s-5 -55 -31 -63s-52 5 -66 31s-109 219 -128 238s-44 28 -72 28v400z" />
-    <glyph glyph-name="cc" unicode="&#xe0cc;"
-d="M400 666c10 19 28 32 47 34l19 -3c26 -8 39 -37 31 -63s-47 -159 -47 -184s22 -50 50 -50h150c28 0 50 -22 50 -50s-103 -319 -103 -319c-8 -18 -26 -31 -47 -31h-350v400c28 0 53 9 72 28s114 212 128 238zM0 400h100v-400h-100v400z" />
-    <glyph glyph-name="cd" unicode="&#xe0cd;"
-d="M200 700h300v-100h-100v-6c25 -4 50 -8 72 -16l-34 -94c-28 11 -58 16 -88 16c-139 0 -250 -111 -250 -250s111 -250 250 -250s250 111 250 250c0 31 -5 60 -16 88l91 37c14 -38 25 -81 25 -125c0 -193 -157 -350 -350 -350s-350 157 -350 350c0 176 130 323 300 347v3
-h-100v100zM700 584c0 0 -296 -348 -316 -368s-48 -20 -68 0s-20 48 0 68s384 300 384 300z" />
-    <glyph glyph-name="ce" unicode="&#xe0ce;"
-d="M600 700l200 -150l-200 -150v100h-600v100h600v100zM200 300v-100h600v-100h-600v-100l-200 150z" />
-    <glyph glyph-name="cf" unicode="&#xe0cf;"
-d="M300 800h100c55 0 100 -45 100 -100h100c55 0 100 -45 100 -100h-700c0 55 45 100 100 100h100c0 55 45 100 100 100zM100 500h100v-350c0 -28 22 -50 50 -50s50 22 50 50v350h100v-350c0 -28 22 -50 50 -50s50 22 50 50v350h100v-481c0 -11 -8 -19 -19 -19h-462
-c-11 0 -19 8 -19 19v481z" />
-    <glyph glyph-name="d0" unicode="&#xe0d0;"
-d="M100 800h200v-400c0 -55 45 -100 100 -100s100 45 100 100v400h100v-400c0 -110 -90 -200 -200 -200h-50c-138 0 -250 90 -250 200v400zM0 100h700v-100h-700v100z" />
-    <glyph glyph-name="d1" unicode="&#xe0d1;"
-d="M9 700h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v482c0 6 3 9 9 9zM609 700h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v482c0 6 3 9 9 9zM309 500h182c6 0 9 -3 9 -9v-282c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v282
-c0 6 3 9 9 9zM0 100h800v-100h-800v100z" />
-    <glyph glyph-name="d2" unicode="&#xe0d2;"
-d="M10 700h181c6 0 9 -3 9 -9v-191h-200v191c0 6 4 9 10 9zM610 700h181c6 0 9 -3 9 -9v-191h-200v191c0 6 5 9 10 9zM310 600h181c6 0 9 -3 9 -9v-91h-200v91c0 6 4 9 10 9zM0 400h800v-100h-800v100zM0 200h200v-191c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v191zM300 200
-h200v-91c0 -6 -3 -9 -9 -9h-181c-6 0 -10 3 -10 9v91zM600 200h200v-191c0 -6 -3 -9 -9 -9h-181c-6 0 -10 3 -10 9v191z" />
-    <glyph glyph-name="d3" unicode="&#xe0d3;"
-d="M0 700h800v-100h-800v100zM9 500h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v482c0 6 3 9 9 9zM309 500h182c6 0 9 -3 9 -9v-282c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v282c0 6 3 9 9 9zM609 500h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182
-c-6 0 -9 3 -9 9v482c0 6 3 9 9 9z" />
-    <glyph glyph-name="d4" unicode="&#xe0d4;"
-d="M50 600h500c28 0 50 -22 50 -50v-150l100 100h100v-300h-100l-100 100v-150c0 -28 -22 -50 -50 -50h-500c-28 0 -50 22 -50 50v400c0 28 22 50 50 50z" />
-    <glyph glyph-name="d5" unicode="&#xe0d5;"
-d="M334 800h66v-800h-66l-134 200h-200v400h200zM500 600v100c26 0 52 -4 75 -10c130 -33 225 -150 225 -290s-95 -258 -225 -291h-3c-23 -6 -47 -9 -72 -9v100c17 0 34 2 50 6c86 22 150 100 150 194s-64 172 -150 194c-16 4 -33 6 -50 6zM500 500l25 -3
-c44 -11 75 -51 75 -97s-32 -86 -75 -97l-25 -3v200z" />
-    <glyph glyph-name="d6" unicode="&#xe0d6;" horiz-adv-x="600"
-d="M334 800h66v-800h-66l-134 200h-200v400h200zM500 500l25 -3c44 -11 75 -51 75 -97s-32 -86 -75 -97l-25 -3v200z" />
-    <glyph glyph-name="d7" unicode="&#xe0d7;" horiz-adv-x="400"
-d="M334 800h66v-800h-66l-134 200h-200v400h200z" />
-    <glyph glyph-name="d8" unicode="&#xe0d8;"
-d="M309 800h82c6 0 10 -4 12 -9l294 -682l3 -19v-81c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v81l3 19l294 682c2 5 6 9 12 9zM300 500v-200h100v200h-100zM300 200v-100h100v100h-100z" />
-    <glyph glyph-name="d9" unicode="&#xe0d9;"
-d="M375 800c138 0 269 -39 378 -109l-53 -82c-93 60 -205 91 -325 91c-119 0 -229 -32 -322 -91l-53 82c109 70 237 109 375 109zM375 500c78 0 154 -23 216 -62l-53 -85c-46 30 -104 47 -163 47c-60 0 -112 -17 -159 -47l-54 85c62 40 134 62 213 62zM375 200
-c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100s45 100 100 100z" />
-    <glyph glyph-name="da" unicode="&#xe0da;" horiz-adv-x="900"
-d="M551 800c16 0 32 0 47 -3l-97 -97v-200h200l97 97c3 -15 3 -31 3 -47c0 -138 -112 -250 -250 -250c-32 0 -62 8 -90 19l-288 -291c-20 -20 -46 -28 -72 -28s-52 8 -72 28c-39 39 -39 105 0 144l291 287c-11 28 -19 59 -19 91c0 138 112 250 250 250zM101 150
-c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
-    <glyph glyph-name="db" unicode="&#xe0db;"
-d="M141 700c84 -84 169 -167 253 -250c82 83 167 165 247 250l143 -141l-253 -253c84 -82 167 -166 253 -247l-143 -143c-81 86 -165 169 -247 253l-253 -253l-141 143c85 80 167 164 250 247c-83 84 -166 169 -250 253z" />
-    <glyph glyph-name="dc" unicode="&#xe0dc;"
-d="M0 800h100l231 -300h38l231 300h100l-225 -300h225v-100h-300v-100h300v-100h-300v-200h-100v200h-300v100h300v100h-300v100h225z" />
-    <glyph glyph-name="dd" unicode="&#xe0dd;" horiz-adv-x="900"
-d="M350 800c193 0 350 -157 350 -350c0 -61 -17 -119 -44 -169c4 -2 10 -6 13 -9l103 -100c16 -16 30 -49 30 -72c0 -56 -46 -102 -102 -102c-23 0 -56 14 -72 30l-100 103c-3 3 -7 9 -9 13c-50 -28 -108 -44 -169 -44c-193 0 -350 157 -350 350s157 350 350 350zM350 700
-c-139 0 -250 -111 -250 -250s111 -250 250 -250c62 0 119 23 163 60c7 11 19 25 31 31l3 3c34 43 53 97 53 156c0 139 -111 250 -250 250zM300 600h100v-100h100v-100h-100v-100h-100v100h-100v100h100v100z" />
-    <glyph glyph-name="de" unicode="&#xe0de;" horiz-adv-x="900"
-d="M350 800c193 0 350 -157 350 -350c0 -61 -17 -119 -44 -169c4 -2 10 -6 13 -9l103 -100c16 -16 30 -49 30 -72c0 -56 -46 -102 -102 -102c-23 0 -56 14 -72 30l-100 103c-3 3 -7 9 -9 13c-50 -28 -108 -44 -169 -44c-193 0 -350 157 -350 350s157 350 350 350zM350 700
-c-139 0 -250 -111 -250 -250s111 -250 250 -250c62 0 119 23 163 60c7 11 19 25 31 31l3 3c34 43 53 97 53 156c0 139 -111 250 -250 250zM200 500h300v-100h-300v100z" />
-  </font>
-</defs></svg>
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.ttf b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.ttf
deleted file mode 100644
index fab6048..0000000
Binary files a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.ttf and /dev/null differ
diff --git a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.woff b/hubs/static/open_iconic_1.1.0/fonts/open-iconic.woff
deleted file mode 100644
index f930998..0000000
Binary files a/hubs/static/open_iconic_1.1.0/fonts/open-iconic.woff and /dev/null differ
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 8b20df0..eae7c6f 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -7,8 +7,7 @@
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
   <script type="text/javascript"  src="{{ url_for('static', filename='notificon.js') }}"></script>
-  <link href="{{ url_for('static', filename='font-awesome-4.6.3/css/font-awesome.min.css') }}"
-        type="text/css" rel="stylesheet" />
+  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css">
   <link href="{{ url_for('static', filename='badges/b.css') }}"
         type="text/css" rel="stylesheet" />
   <link rel="icon" type="image/png"

From 7db2a1e8b8cfb7162b48433d56e53603ba5ecaee Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Aug 01 2016 21:07:55 +0000
Subject: [PATCH 593/1001] removing fmn context from feed


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index d3870c3..3e6b586 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -27,56 +27,11 @@ import uuid
 
 log = logging.getLogger('hubs')
 
-import fedmsg.config
-config = fedmsg.config.load_config()
-fmn_url = config['fmn.url']
-
-bazillion = 1000
-paths = fmn.lib.load_rules(root='fmn.rules')
-
 from hubs.widgets.chrome import panel
 chrome = panel('Live Feed')
 template = templating.environment.get_template('templates/feed.html')
 position = 'left'
 
-
-def apply_markup(match):
-    markup = match['subtitle']
-    for username in match['usernames']:
-        args = (username, '<a href="{url}">@{username}</a>'.format(
-            url=flask.url_for('hub', name=username),
-            username=username,
-        ))
-        markup = markup.replace(*args)
-        # TODO -- have to add these to conglomerate first
-        # match['long_form'] = match['long_form'].replace(*args)
-
-    for package in match['packages']:
-        args = (package, '<a href="{url}">{package}</a>'.format(
-            url='https://apps.fedoraproject.org/packages/' + package,
-            package=package,
-        ))
-        markup = markup.replace(*args)
-        # TODO -- have to add these to conglomerate first
-        # match['long_form'] = match['long_form'].replace(*args)
-
-    return markup
-
-
-class PythonObjectEncoder(json.JSONEncoder):
-    ''' A JSON encoder that handles python data structures in encoding'''
-    def default(self, obj):
-        if isinstance(obj, (list, dict, str, unicode, int, float, bool,
-                            type(None))):
-            return json.JSONEncoder.default(self, obj)
-        if isinstance(obj, set) or isinstance(obj, tuple):
-            return list(obj)
-        if isinstance(obj, object):
-            return obj.__dict__
-        else:
-            raise TypeError
-
-
 @argument(name="username",
           default=None,
           validator=validators.username,
@@ -86,122 +41,18 @@ class PythonObjectEncoder(json.JSONEncoder):
           validator=validators.integer,
           help="Max number of feed messages to display")
 def data(session, widget, username, message_limit):
-    messages = []
-    matches = []
     # Avoid circular import
     from hubs.app import app
     feed_url = app.config['SSE_URL'] + username
-    preference = get_remote_preference(username, 'sse')
-    if preference:
-        try:
-            preference = rehydrate_preference(preference)
-        except ImportError:
-            pass
-
-        # The smaller we make this, the faster it is.
-        delta = datetime.timedelta(days=365)
-        end = datetime.datetime.utcnow()
-
-        # We currently only support getting the first page.
-        # The widget framework as currently written doesn't support
-        # multiple pages yet.
-        page = 1
-
-        for filter in preference['filters']:
-            rules = filter['rules']
-            fmn_hinting = fmn.lib.hinting.gather_hinting(config, rules, paths)
-            total, pages, rows = datanommer.models.Message.grep(
-                start=end - delta,
-                end=end,
-                rows_per_page=message_limit,
-                page=page,
-                order='desc',
-                **fmn_hinting
-            )
-            messages.extend(rows)
-
-        for message in messages:
-            original = message.__json__()
-            recipients = fmn.lib.recipients(
-                [preference], message.__json__(), paths, config)
-            if recipients:
-                matches.append(original)
-    else:
-        log.warn("You don't have any preferences.")
-
-    # TODO - sort messages and remove duplicates
-
-    # Smash multiple messages into single ones
-    matches = fedmsg.meta.conglomerate(matches, lexers=True, **config)
-
-    # Apply some html markup to the subtitles for extra fanciness.
-    for match in matches:
-        match['markup'] = apply_markup(match)
-        for idx, constituent in match['msg_ids'].items():
-            constituent['markup'] = apply_markup(constituent)
-            if constituent['long_form'] != constituent['subtitle']:
-                if constituent.get('lexer'):
-                    constituent['long_form'] = pygments.highlight(
-                        constituent['long_form'],
-                        constituent['lexer'],
-                        pygments.formatters.HtmlFormatter(style='monokai'),
-                    )
-                else:
-                    markup = u"<h5>{long_form}</h5>".format(**constituent)
-                    constituent['long_form'] = markup
-
-        # And tack on a unique identifier for each top level entry.
-        match['dom_id'] = six.text_type(uuid.uuid4())
-    matches = json.dumps(matches, cls=PythonObjectEncoder)
     return dict(
-        matches=matches,
+        matches=[],
         message_limit=message_limit,
         feed_url=feed_url
     )
 
-
 @hint(ubiquitous=True)
 def should_invalidate(message, session, widget):
-    username = widget.config['username']
-    fmn_context = 'sse'
-    preference = get_remote_preference(username, fmn_context)
-    if not preference:
-        return False
-    preference = rehydrate_preference(preference)
-    recipients = fmn.lib.recipients([preference], message, paths, config)
-    return bool(recipients)
-
-
-# TODO -- this cache value needs its own FMN-based invalidator...
-@cache.cache_on_arguments()
-def get_remote_preference(username, fmn_context):
-    openid = '%s.id.fedoraproject.org' % username
-    url = '/'.join([fmn_url, 'api', openid, fmn_context])
-    log.info("Getting FMN preference from %s" % url)
-    response = requests.get(url)
-    if bool(response):
-        return response.json()
-    else:
-        # Some people have no FMN preferences, but when they do get some.. then
-        # we'll receive the fedmsg event about it and bust this cache value.
-        return None
-
-
-def rehydrate_preference(preference):
-    for fltr in preference['filters']:
-        fltr['rules'] = [munch.Munch(r) for r in fltr['rules']]
-        for rule in fltr['rules']:
-            code_path = str(rule.code_path)
-            rule.fn = fedmsg.utils.load_class(code_path)
+    pass
 
-    return preference
 
 
-def make_result(msg, d):
-    return {
-        'icon': fedmsg.meta.msg2icon(d, **config),
-        'icon2': fedmsg.meta.msg2secondary_icon(d, **config),
-        'subtitle': fedmsg.meta.msg2subtitle(d, **config),
-        'link': fedmsg.meta.msg2link(d, **config),
-        'time': arrow.get(msg.timestamp).humanize(),
-    }

From 2305dde1517b7b6b1aa398dcce17f032d5920635 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Aug 02 2016 14:04:16 +0000
Subject: [PATCH 594/1001] feed tests no longer are required


---

diff --git a/hubs/tests/test_widgets/test_feed.py b/hubs/tests/test_widgets/test_feed.py
deleted file mode 100644
index 88e4913..0000000
--- a/hubs/tests/test_widgets/test_feed.py
+++ /dev/null
@@ -1,74 +0,0 @@
-import json
-
-import hubs.tests.test_widgets
-from hubs.widgets.feed import PythonObjectEncoder
-
-
-encode = lambda o: json.dumps(o, cls=PythonObjectEncoder)
-
-class TestPythonObjectEncoder(hubs.tests.test_widgets.WidgetTest):
-    def test_python_object_encoder_encodes_set(self):
-        data = set([1,2,3, 'bar', 'foo'])
-        expected_str = '[1, 2, 3, "bar", "foo"]'
-        expected_list = list(data)
-
-        encoded = encode(data)
-        self.assertEqual(encoded, expected_str)
-
-        decoded = json.loads(encoded)
-        self.assertEqual(expected_list, decoded)
-
-    def test_python_object_encoder_encodes_tuple(self):
-        data = ('foo', 'bar', 'baz', 1)
-        expected_str = '["foo", "bar", "baz", 1]'
-        expected_list = list(data)
-
-        encoded = encode(data)
-        self.assertEqual(encoded, expected_str)
-
-        decoded = json.loads(encoded)
-        self.assertEqual(expected_list, decoded)
-
-
-    def test_python_object_encoder_encodes_object(self):
-        class Test(object):
-            def __init__(self):
-                self.x = 'x'
-
-        data = Test()
-        expected_str = '{"x": "x"}'
-        expected_dict = data.__dict__
-        encoded = encode(data)
-        self.assertEqual(encoded, expected_str)
-
-        decoded = json.loads(encoded)
-        self.assertEqual(expected_dict, decoded)
-
-    def test_python_object_encoder_encodes_deep_dict(self):
-        data = {
-            'some_dict': {
-                'one': 1,
-                'aset': set(['two', 'three']),
-                'four': 4.0,
-                'tupe': (5,6),
-            },
-            'regular': 'string'
-        }
-        expected_str = '{"some_dict": {"four": 4.0, "tupe": [5, 6], "aset": ["two", "three"], "one": 1}, "regular": "string"}'
-
-        expected_dict = {
-            'some_dict': {
-                'one': 1,
-                'aset': ['two', 'three'],
-                'four': 4.0,
-                'tupe': [5,6],
-            },
-            'regular': 'string'
-        }
-
-        encoded = encode(data)
-        self.assertEqual(expected_str, encoded)
-
-        decoded = json.loads(encoded)
-        self.assertEqual(expected_dict, decoded)
-

From 0d63564fb794807de7d947b06668acfe810aa719 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 03 2016 19:55:42 +0000
Subject: [PATCH 595/1001] Stop populate-from-fas.py from crashing on run


---

diff --git a/populate-from-fas.py b/populate-from-fas.py
index cab611e..7639c81 100755
--- a/populate-from-fas.py
+++ b/populate-from-fas.py
@@ -48,7 +48,7 @@ for letter in reversed(sorted(list(set(string.letters.lower())))):
     for user in users:
         username = user['username']
         fullname = user['human_name']
-        print "Creating account for %r" % openid
+        print "Creating account for %r" % username
         hubs_user = hubs.models.User.get_or_create(
             session, username=username, fullname=fullname)
 

From e88a4096f9193e4ca56b577e81f6b47ac9eea523 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Aug 04 2016 18:37:47 +0000
Subject: [PATCH 596/1001] better spacing between icons in upper right of widgets/cards


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 30e246b..3c9cb61 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -136,8 +136,11 @@
       margin-bottom: 0px;
     }
     .widget-buttons {
-      padding: 5px;
-      /* TODO -- lots more nice styling here... */
+      padding: .5rem;
+    }
+    
+    .widget .widget-buttons a {
+      margin-right: .4rem;
     }
 
     .panel {
@@ -403,3 +406,5 @@ font-size: 32pt;
 header h5.m-b-1 {
   margin-top: 0.5rem!important;
 }
+
+/** 

From 3705fd09a964dc055342d71151c602b4ed6e2663 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Aug 04 2016 18:37:47 +0000
Subject: [PATCH 597/1001] fix padding for buttons on the bottom of a widget (Eg request a meeting button in meeting widget)


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 3c9cb61..fe40b05 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -407,4 +407,8 @@ header h5.m-b-1 {
   margin-top: 0.5rem!important;
 }
 
-/** 
+/** not sure if this is coming from fedora bootstrap but it's card related **/
+
+.card .panel-footer {
+  padding-bottom: 2rem; /* fixes request new meeting button padding on the upcoming meeting widget */
+}

From cb8f2c48a03c782778591b77fff60b11abe8e0be Mon Sep 17 00:00:00 2001
From: Lubomír Sedlář <lsedlar@redhat.com>
Date: Aug 05 2016 11:48:51 +0000
Subject: [PATCH 598/1001] Fix test failing due to additional HTML attributes


The HTML contains an attribute which causes the expected string to not
be found. This patch updates the test to use a regular expression, which
should be a tad more reliable.

---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 5ef5732..6808456 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -37,8 +37,8 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, None):  # check_auth doesn't load in unittest
             result = self.app.get('/ralph', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            str_expected = '<h5>Ralph</h5>'
-            self.assertTrue(str_expected in result.data)
+            match_expected = r'<h5[^>]*>Ralph</h5>'
+            self.assertRegexpMatches(result.data, match_expected)
             str_expected = 'Not logged in.'
             self.assertTrue(str_expected in result.data)
 

From 98e9b68b30642323b2341c177796a4feecea5d06 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Aug 05 2016 13:22:49 +0000
Subject: [PATCH 599/1001] creating a automated setup test env script


---

diff --git a/setup_test_env.sh b/setup_test_env.sh
new file mode 100644
index 0000000..d0c83fa
--- /dev/null
+++ b/setup_test_env.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+######
+# Warning this file uses sudo to install dependencies use at your own risk
+#####
+
+# Install dependencies
+sudo yum install gcc gcc-c++ sqlite-devel libffi-devel openssl-devel redhat-rpm-config
+
+# setup python virtualenv
+sudo yum install python-virtualenvwrapper postgresql postgresql-devel
+
+# have bash find mkvirutalenv
+source ~/.bashrc
+
+# Create hubs env
+mkvirtualenv hubs
+
+# activate hubs
+workon hubs
+
+# install python deps
+pip install -r requirements.txt
+pip install -r test-requirements.txt
+
+

From 5bbe2b9314d5a895a4382c7089a65f47fc561d9d Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Aug 05 2016 13:22:49 +0000
Subject: [PATCH 600/1001] minimize user interaction, upgrade python packages if they are already installed, also temp fix for html5lib fiasco


---

diff --git a/setup_test_env.sh b/setup_test_env.sh
index d0c83fa..312c017 100644
--- a/setup_test_env.sh
+++ b/setup_test_env.sh
@@ -5,10 +5,10 @@
 #####
 
 # Install dependencies
-sudo yum install gcc gcc-c++ sqlite-devel libffi-devel openssl-devel redhat-rpm-config
+sudo yum install -y gcc gcc-c++ sqlite-devel libffi-devel openssl-devel redhat-rpm-config
 
 # setup python virtualenv
-sudo yum install python-virtualenvwrapper postgresql postgresql-devel
+sudo yum install -y python-virtualenvwrapper postgresql postgresql-devel
 
 # have bash find mkvirutalenv
 source ~/.bashrc
@@ -20,7 +20,8 @@ mkvirtualenv hubs
 workon hubs
 
 # install python deps
-pip install -r requirements.txt
-pip install -r test-requirements.txt
-
+pip install --upgrade -r requirements.txt
+pip install --upgrade -r test-requirements.txt
 
+# TEMPORARY: html5lib update is causing other apps to crash
+pip install html5lib==0.9999999

From ed036ee85cd48b074ee76ff7d15c694f9254e984 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Aug 05 2016 13:22:49 +0000
Subject: [PATCH 601/1001] removing the hubs env to make sure we have a clean env


---

diff --git a/setup_test_env.sh b/setup_test_env.sh
index 312c017..fed2ad4 100644
--- a/setup_test_env.sh
+++ b/setup_test_env.sh
@@ -13,6 +13,9 @@ sudo yum install -y python-virtualenvwrapper postgresql postgresql-devel
 # have bash find mkvirutalenv
 source ~/.bashrc
 
+# remove the hubs env
+rmvirtualenv hubs
+
 # Create hubs env
 mkvirtualenv hubs
 

From 398316873e796f4a281bbfd8fe8afb9689c0b474 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Aug 05 2016 13:22:49 +0000
Subject: [PATCH 602/1001] seperating fedora and python dependency install


---

diff --git a/setup_python_test_env.sh b/setup_python_test_env.sh
new file mode 100644
index 0000000..4681c75
--- /dev/null
+++ b/setup_python_test_env.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# have bash find mkvirutalenv
+source ~/.bashrc
+
+# remove the hubs env
+rmvirtualenv hubs
+
+# Create hubs env
+mkvirtualenv hubs
+
+# activate hubs
+workon hubs
+
+# install python deps
+pip install --upgrade -r requirements.txt
+pip install --upgrade -r test-requirements.txt
+
+# TEMPORARY: html5lib update is causing other apps to crash
+pip install html5lib==0.9999999
diff --git a/setup_test_env.sh b/setup_test_env.sh
index fed2ad4..bee1732 100644
--- a/setup_test_env.sh
+++ b/setup_test_env.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 ######
 # Warning this file uses sudo to install dependencies use at your own risk
@@ -10,21 +10,4 @@ sudo yum install -y gcc gcc-c++ sqlite-devel libffi-devel openssl-devel redhat-r
 # setup python virtualenv
 sudo yum install -y python-virtualenvwrapper postgresql postgresql-devel
 
-# have bash find mkvirutalenv
-source ~/.bashrc
-
-# remove the hubs env
-rmvirtualenv hubs
-
-# Create hubs env
-mkvirtualenv hubs
-
-# activate hubs
-workon hubs
-
-# install python deps
-pip install --upgrade -r requirements.txt
-pip install --upgrade -r test-requirements.txt
-
-# TEMPORARY: html5lib update is causing other apps to crash
-pip install html5lib==0.9999999
+sh ./setup_python_test_env.sh

From 8cd3b19e3bcb3f0df2675de2079ed2501c7fc02a Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 05 2016 13:22:49 +0000
Subject: [PATCH 603/1001] Make test scripts executable and source hubs


---

diff --git a/runtest.sh b/runtest.sh
index ad0de9c..87fd265 100755
--- a/runtest.sh
+++ b/runtest.sh
@@ -1,3 +1,6 @@
 #!/bin/bash
+
+. ~/.virtualenvs/hubs/bin/activate || /bin/bash ./setup_python_test_env.sh
+
 HUBS_CONFIG=`pwd`/hubs/tests/hubs_test.cfg PYTHONPATH=. ./nosetests \
     --with-coverage --cover-erase --cover-package=hubs $*
diff --git a/setup_python_test_env.sh b/setup_python_test_env.sh
old mode 100644
new mode 100755
diff --git a/setup_test_env.sh b/setup_test_env.sh
old mode 100644
new mode 100755

From 8d6da466a1d89623a8efebfb3dcdbc7b4881d65a Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Aug 05 2016 13:22:49 +0000
Subject: [PATCH 604/1001] Fixing up jenkins scripts


adding centos 7 specific dependency, adding jenkins python venv script

Adding fedora check to install specific packages for centos

adding jenkins runtest

adding jenkins specific venv setup

update setuptools on epel7

manually running test

working on getting jenkins to pass build in centos

adding coverage dep for unittest

removing unused file, forgot to cp the pygments lib

cleaning up and removing hardlink to use relative links

removing the python setup in the fedora dep setup

---

diff --git a/runtest_jenkins.sh b/runtest_jenkins.sh
new file mode 100644
index 0000000..0092438
--- /dev/null
+++ b/runtest_jenkins.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+PATH=$WORKSPACE/venv/bin:/usr/local/bin:$PATH
+
+if [ ! -d "venv" ]; then
+    virtualenv venv
+fi
+. venv/bin/activate
+
+# epel 7 specific python setup
+if ! grep -q "Fedora" /etc/os-release ; then
+    pip install --upgrade setuptools==18.5
+    cp -r /usr/lib/python2.7/site-packages/pygments_markdown_lexer $WORKSPACE/venv/lib/python2.7/site-packages/
+    cp -r /usr/lib/python2.7/site-packages/pygments_markdown_lexer-*-py2.7.egg-info $WORKSPACE/venv/lib/python2.7/site-packages/
+fi
+
+pip install -r requirements.txt
+pip install -r test-requirements.txt
+
+# Temporary: html5lib is breaking stability in some libraries
+pip install html5lib==0.9999999
+
+HUBS_CONFIG=$WORKSPACE/hubs/tests/hubs_test.cfg PYTHONPATH=. ./nosetests \
+    --cover-package=hubs $*
\ No newline at end of file
diff --git a/setup_test_env.sh b/setup_test_env.sh
index bee1732..d1d5305 100755
--- a/setup_test_env.sh
+++ b/setup_test_env.sh
@@ -7,7 +7,12 @@
 # Install dependencies
 sudo yum install -y gcc gcc-c++ sqlite-devel libffi-devel openssl-devel redhat-rpm-config
 
-# setup python virtualenv
-sudo yum install -y python-virtualenvwrapper postgresql postgresql-devel
+if ! grep -q "Fedora" /etc/os-release ; then
+    # Epel 7 specific
+    sudo yum install -y epel-release
+    sudo yum update -y
+    sudo yum install -y python-pip python-pygments-markdown-lexer
+fi
 
-sh ./setup_python_test_env.sh
+# setup python virtualenv
+sudo yum install -y python-virtualenvwrapper postgresql postgresql-devel
\ No newline at end of file
diff --git a/test-requirements.txt b/test-requirements.txt
index c1358b7..cb1dca7 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -2,3 +2,4 @@ nose
 vcrpy
 mock
 yanc
+coverage
\ No newline at end of file

From cd3b626908a4c230ef23b9897505d9c63a670b55 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Aug 05 2016 13:37:10 +0000
Subject: [PATCH 605/1001] updating so that when you copy and paste the script into jenkins build itll still run and added workspace specific route


---

diff --git a/runtest_jenkins.sh b/runtest_jenkins.sh
index 0092438..21ccee0 100644
--- a/runtest_jenkins.sh
+++ b/runtest_jenkins.sh
@@ -20,5 +20,5 @@ pip install -r test-requirements.txt
 # Temporary: html5lib is breaking stability in some libraries
 pip install html5lib==0.9999999
 
-HUBS_CONFIG=$WORKSPACE/hubs/tests/hubs_test.cfg PYTHONPATH=. ./nosetests \
-    --cover-package=hubs $*
\ No newline at end of file
+HUBS_CONFIG=$WORKSPACE/hubs/tests/hubs_test.cfg PYTHONPATH=. ./nosetests --cover-package=$WORKSPACE/hubs $*
+

From bae75459b688a5be70019ad6910c71e672bdb751 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 05 2016 13:52:24 +0000
Subject: [PATCH 606/1001] Make the list un-styled on the fedmsgstats widget


---

diff --git a/hubs/widgets/templates/fedmsgstats.html b/hubs/widgets/templates/fedmsgstats.html
index 37d6c42..bb569e7 100644
--- a/hubs/widgets/templates/fedmsgstats.html
+++ b/hubs/widgets/templates/fedmsgstats.html
@@ -7,6 +7,7 @@
   </div>
   <div class="col-sm-5 col-md-12 col-lg-5">
   {% if session['nickname'] != username %}
+    <ul class="list-unstyled">
     {% if session['nickname'] in subscribers %}
     <li><form action="{{hub_unsubscribe_url}}" method="POST">
         <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
@@ -16,6 +17,7 @@
         <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
     </form></li>
     {% endif %}
+    </ul>
   {% endif %}
   </div>
 </div>

From 2b7bcd9d68ef5fe103bb1114471732c259c7d456 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 18:33:19 +0000
Subject: [PATCH 607/1001] Force idx to be an int in hub routes


* Also except ValueError on idx in get_widget

---

diff --git a/hubs/app.py b/hubs/app.py
index 0007f66..067a3ad 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -363,16 +363,16 @@ def hub_add_widget_post(name):
         'hubs.html', hub=hub, session=session, edit=True)
 
 
-@app.route('/<hub>/<idx>/')
-@app.route('/<hub>/<idx>')
+@app.route('/<hub>/<int:idx>/')
+@app.route('/<hub>/<int:idx>')
 def widget_render(hub, idx):
     widget = get_widget(session, hub, idx)
     return widget.render(session)  # , edit=False)
     # was blocking all widgets from working, sorry!
 
 
-@app.route('/<hub>/<idx>/json')
-@app.route('/<hub>/<idx>/json/')
+@app.route('/<hub>/<int:idx>/json')
+@app.route('/<hub>/<int:idx>/json/')
 def widget_json(hub, idx):
     widget = get_widget(session, hub, idx)
     response = flask.jsonify(widget.__json__(session))
@@ -380,8 +380,8 @@ def widget_json(hub, idx):
     return response
 
 
-@app.route('/<hub>/<idx>/edit/', methods=['GET', 'POST'])
-@app.route('/<hub>/<idx>/edit', methods=['GET', 'POST'])
+@app.route('/<hub>/<int:idx>/edit/', methods=['GET', 'POST'])
+@app.route('/<hub>/<int:idx>/edit', methods=['GET', 'POST'])
 def widget_edit(hub, idx):
     if flask.request.method == 'POST':
         return widget_edit_post(hub, idx)
@@ -432,8 +432,8 @@ def widget_edit_post(hub, idx):
     return flask.redirect(flask.url_for('hub', name=hub))
 
 
-@app.route('/<hub>/<idx>/delete/', methods=['POST'])
-@app.route('/<hub>/<idx>/delete', methods=['POST'])
+@app.route('/<hub>/<int:idx>/delete/', methods=['POST'])
+@app.route('/<hub>/<int:idx>/delete', methods=['POST'])
 def widget_edit_delete(hub, idx):
     ''' Remove a widget from a hub. '''
     widget = get_widget(session, hub, idx)
@@ -592,7 +592,7 @@ def get_widget(session, hub, idx):
     """ Utility shorthand to get a widget and 404 if not found. """
     try:
         idx = int(idx)
-    except TypeError:
+    except (TypeError, ValueError):
         flask.abort(404)
 
     hub = get_hub(session, hub)

From 7c678a851ff699e40393f9cb52086eba7b543c16 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 608/1001] Naive implementaion of stream prototype


---

diff --git a/hubs/app.py b/hubs/app.py
index 067a3ad..4432e91 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -6,6 +6,7 @@ import os
 import urlparse
 import uuid
 
+import bleach
 import flask
 import flask.json
 import fmn.lib
@@ -103,7 +104,7 @@ def index():
     if not authenticated():
         return flask.redirect(flask.url_for('login'))
 
-    return flask.redirect(flask.url_for('hub', name=flask.g.auth.nickname))
+    return flask.redirect(flask.url_for('stream', name=flask.g.auth.nickname))
 
 
 @app.route('/groups')
@@ -519,6 +520,42 @@ def login_required(function):
 
     return decorated_function
 
+@app.route('/<name>/stream')
+@app.route('/<name>/stream/')
+@login_required
+def stream(name):
+    feeds = [
+        {'url': '', 'name': 'streamFeed', 'matches': []},
+        {'url': '', 'name': 'actionsFeed', 'matches': []},
+        {'url': '', 'name': 'mentionsFeed', 'matches': []},
+    ]
+    saved = hubs.models.SavedNotification.by_username(session, name)
+
+    return flask.render_template('stream.html', feeds=json.dumps(feeds), saved=saved)
+
+
+@app.route('/<user>/notifications')
+@app.route('/<user>/notifications/')
+@login_required
+def notifications(user):
+    if flask.request.method == 'GET':
+        notifications = hubs.models.SavedNotification.by_username(session, user)
+        notifications = [n.__json__() for n in notifications]
+        return json.dumps(notifications)
+
+    if flask.request.method == 'POST':
+        markup = bleach.clean(flask.request.data['markup'])
+        link = bleach.clean(flask.request.data['link'])
+        icon = flask.request.data['icon']
+        notification = hubs.models.SavedNotification(
+            username=user,
+            markup=markup,
+            link=link,
+            secondary_icon=icon
+        )
+        session.add(notification)
+        session.commit()
+        return notification.__json__()
 
 @app.before_request
 def check_auth():
diff --git a/hubs/models.py b/hubs/models.py
index ede60dc..c8021e4 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -28,12 +28,13 @@ import operator
 import os
 import random
 
+import bleach
 import sqlalchemy as sa
 from sqlalchemy import create_engine
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.orm import sessionmaker
 from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import relation
+from sqlalchemy.orm import relation, relationship
 from sqlalchemy.orm import backref
 
 import fedmsg
@@ -353,6 +354,8 @@ class User(BASE):
     username = sa.Column(sa.Text, primary_key=True)
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
+    saved_notifications = relationship('SavedNotification', backref='users',
+                                       lazy='dynamic')
 
     def __json__(self, session):
         return {
@@ -478,3 +481,38 @@ class VisitCounter(BASE):
             session.add(self)
             session.commit()
         return self
+
+
+class SavedNotification(BASE):
+    __tablename__ = 'savednotifications'
+    user = sa.Column(sa.Text, sa.ForeignKey('users.username'))
+
+    idx = sa.Column(sa.Integer, primary_key=True)
+    markup = sa.Column(sa.Text)
+    link = sa.Column(sa.Text)
+    secondary_icon = sa.column(sa.Text)
+    created = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
+
+
+    def __init__(self, username=None, markup='', link='', secondary_icon=''):
+        self.user = username
+        self.markup = markup
+        self.link = link
+        self.secondary_icon = secondary_icon
+
+    def __json__(self):
+        return {
+            'idx': self.idx,
+            'markup': bleach.linkify(self.markup),
+            'link': bleach.linkify(self.link),
+            'secondary_icon': self.secondary_icon,
+            'created': self.created
+        }
+
+    @classmethod
+    def by_username(cls, session, username):
+        return session.query(cls).filter_by(user=username)
+
+    @classmethod
+    def all(cls, session):
+        return session.query(cls).all()
diff --git a/hubs/templates/_messages.html b/hubs/templates/_messages.html
new file mode 100644
index 0000000..7f942d3
--- /dev/null
+++ b/hubs/templates/_messages.html
@@ -0,0 +1,294 @@
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
+<div class="panel panel-default panel-visible">
+  <div clas="panel-body">
+    <div class="media-left">
+      <a href="#" target="_blank">
+        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
+      </a>
+    </div>
+    <div className="media-body">
+      <h4 className="media-heading">
+        This is some markup
+      </h4>
+    </div>
+  </div>
+</div>
diff --git a/hubs/templates/includes/_library.html b/hubs/templates/includes/_library.html
new file mode 100644
index 0000000..c4acbea
--- /dev/null
+++ b/hubs/templates/includes/_library.html
@@ -0,0 +1,22 @@
+<div class="col-sm-3">
+  <div class="card-header">
+    My Library
+    <div class="pull-right widget-buttons">
+      <a href="#"><span class="oi" data-glyph="external-link"></span></a>
+      <a data-target="#edit_modal" data-toggle="modal" type="button"
+        class="edit_widget" data-idx="">
+        <span class="oi" data-glyph="pencil"></span>
+      </a>
+    </div>
+  </div>
+  <div class="card">
+    <div class="card-block">
+      <p class="card-text">
+        <li>Lorem</li>
+        <li>Ipsum</li>
+        <li>Sit</li>
+        <li>Amet</li>
+      </p>
+    </div>
+  </div>
+</div>
diff --git a/hubs/templates/includes/_searchstream.html b/hubs/templates/includes/_searchstream.html
new file mode 100644
index 0000000..60b2caf
--- /dev/null
+++ b/hubs/templates/includes/_searchstream.html
@@ -0,0 +1,7 @@
+<!-- NOT HOOKED UP TO ANYTHING XOXO -->
+<div class="input-group">
+  <input type="search" class="form-control" placeholder="Search this activity stream..." aria-describedby="searchform-addon"></input>
+  <span class="input-group-addon" id="searchform-addon">
+    <span class="oi" data-glyph="magnifying-glass"></span>
+  </span>
+</div>
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index eae7c6f..1e19d91 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -66,6 +66,7 @@
         <ul class="nav navbar-nav">
           <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
             <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
+          <li class="p-x-1 nav-item"><a class="nav-link" href="/{{g.auth.user.username}}/stream">My Stream</a></li>
           {% for hub in g.auth.user.bookmarks %}
           <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
             <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
new file mode 100644
index 0000000..fb36b2d
--- /dev/null
+++ b/hubs/templates/stream.html
@@ -0,0 +1,78 @@
+{% extends "master.html" %}
+
+{% block title %}My Stream{% endblock %}
+{% block content %}
+<div class="jumbotron">
+  <h1>My Stream</h1>
+  <p>Notifications, actions, and other things of interest to me</p>
+</div>
+
+<ul class="nav nav-tabs" role="tablist">
+  <li class="nav-item">
+    <a class="nav-link active" href="#stream" role="tab" data-toggle="tab">My stream</a>
+  </li>
+  <li class="nav-item">
+    <a class="nav-link" href="#actions" role="tab" data-toggle="tab">My actions</a>
+  </li>
+  <li class="nav-item">
+    <a class="nav-link" href="#mentions" role="tab" data-toggle="tab">My Mentions</a>
+  </li>
+  <li class="nav-item">
+    <a class="nav-link" href="#saved" role="tab" data-toggle="tab">Saved Notifications</a>
+  </li>
+</ul>
+
+<!-- Tab panes -->
+<div class="tab-content">
+  <div role="tabpanel" class="tab-pane fade in active" id="stream">
+    <div class="container">
+      <div class="row">
+        <div class="col-sm-9 pull-left">
+          {% include "includes/_searchstream.html" %}
+          <div class="alert alert-warning" role="alert">
+            This stream is filtered. <a href="#">View Filters</a>
+          </div>
+          <div id="streamFeed"></div>
+        </div>
+        {% include "includes/_library.html" %}
+      </div>
+    </div>
+  </div>
+
+  <div role="tabpanel" class="tab-pane fade" id="actions">
+    <div id="actionsFeed"></div>
+  </div>
+  <div role="tabpanel" class="tab-pane fade" id="mentions">
+    <div id="mentionsFeed"></div>
+  </div>
+  <div role="tabpanel" class="tab-pane fade" id="saved">
+    <div id="savedFeed"></div>
+  </div>
+</div>
+<script type="text/javascript"
+        src ="{{url_for('static', filename='js/hubs.js')}}"></script>
+<script>
+ (function() {
+   var feeds = {{ feeds|safe }};
+   feeds.forEach(function (feed) {
+     var element = React.createElement(Feed, {
+       matches: feed.matches,
+       url: feed.url,
+       messageLimit: 100
+     });
+     reactRender(element, document.getElementById(feed.name));
+   });
+   var savedFeed = React.createElement(Feed, {
+     matches: {{saved}},
+     url: null,
+     messageLimit: 100
+   });
+   reactRender(savedFeed, document.getElementById('saved'));
+ })();
+</script>
+<style>
+ .jumbotron {
+   margin-bottom: 0;
+ }
+</style>
+{% endblock %}

From c7c827daec9eb5044e8ab8b264921baaf96ca91d Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 609/1001] Front and back ends for SavedNotifications


---

diff --git a/hubs/app.py b/hubs/app.py
index 4432e91..957a809 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -19,6 +19,7 @@ from flask.ext.oidc import OpenIDConnect
 import fmn.lib
 import hubs.models
 import hubs.widgets
+from hubs.widgets import clean_input
 
 import datanommer.models
 
@@ -530,23 +531,29 @@ def stream(name):
         {'url': '', 'name': 'mentionsFeed', 'matches': []},
     ]
     saved = hubs.models.SavedNotification.by_username(session, name)
+    saved = [n.__json__() for n in saved]
 
-    return flask.render_template('stream.html', feeds=json.dumps(feeds), saved=saved)
+    return flask.render_template('stream.html', feeds=json.dumps(feeds), saved=json.dumps(saved))
 
 
-@app.route('/<user>/notifications')
-@app.route('/<user>/notifications/')
+@app.route('/<user>/notifications', methods=['GET', 'POST'])
+@app.route('/<user>/notifications/', methods=['GET', 'POST'])
 @login_required
 def notifications(user):
     if flask.request.method == 'GET':
         notifications = hubs.models.SavedNotification.by_username(session, user)
         notifications = [n.__json__() for n in notifications]
-        return json.dumps(notifications)
+        return flask.jsonify(notifications)
 
     if flask.request.method == 'POST':
-        markup = bleach.clean(flask.request.data['markup'])
-        link = bleach.clean(flask.request.data['link'])
-        icon = flask.request.data['icon']
+        data = flask.request.json
+        try:
+            # TODO clean these with pingou's new method
+            markup = data['markup']
+            link = data['link']
+            icon = data['secondary_icon']
+        except:
+            return str(flask.request.data)
         notification = hubs.models.SavedNotification(
             username=user,
             markup=markup,
@@ -555,7 +562,9 @@ def notifications(user):
         )
         session.add(notification)
         session.commit()
-        return notification.__json__()
+        return flask.jsonify(
+            dict(notification=notification.__json__(),success=True)
+        )
 
 @app.before_request
 def check_auth():
diff --git a/hubs/models.py b/hubs/models.py
index c8021e4..03217c1 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -490,7 +490,7 @@ class SavedNotification(BASE):
     idx = sa.Column(sa.Integer, primary_key=True)
     markup = sa.Column(sa.Text)
     link = sa.Column(sa.Text)
-    secondary_icon = sa.column(sa.Text)
+    secondary_icon = sa.Column(sa.Text)
     created = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
 
@@ -502,16 +502,18 @@ class SavedNotification(BASE):
 
     def __json__(self):
         return {
+            'created': str(self.created),
+            'date_time': str(self.created),
             'idx': self.idx,
-            'markup': bleach.linkify(self.markup),
             'link': bleach.linkify(self.link),
-            'secondary_icon': self.secondary_icon,
-            'created': self.created
+            'markup': bleach.linkify(self.markup),
+            'saved': True,
+            'secondary_icon': self.secondary_icon
         }
 
     @classmethod
     def by_username(cls, session, username):
-        return session.query(cls).filter_by(user=username)
+        return session.query(cls).filter_by(user=username).all()
 
     @classmethod
     def all(cls, session):
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index 7d9c618..4086e00 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -11,6 +11,10 @@ export default class Feed extends React.Component {
       messageLimit: this.props.messageLimit,
       sse: true,
     };
+    // If it wasn't instantiated with a url or an error happened, bail
+    if (!this.props.url || !this.state.sse) {
+      return;
+    }
     this.source = (!!window.EventSource) ? new EventSource(this.props.url) : {};
     this.source.addEventListener('error', () => {
       this.state.sse = false;
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
index 61e8242..a5aa178 100644
--- a/hubs/static/client/app/components/Panel.jsx
+++ b/hubs/static/client/app/components/Panel.jsx
@@ -1,14 +1,39 @@
 import React from 'react';
+import $ from 'jquery';
 
 import Icon from './Icon.jsx';
 import Markup from './Markup.jsx';
 
 const Panel = function (props) {
+  const payload = {
+    link: props.match.link,
+    markup: props.match.markup,
+    secondary_icon: props.match.secondary_icon,
+  };
+
+  function onClick(data) {
+    $.ajax({
+      type: 'POST',
+      url: '/atelic/notifications/',
+      data: JSON.stringify(data),
+      contentType: 'application/json',
+    }).done(resp => {
+      const id = '#save' + resp.notification.idx;
+      const $saveBtn = $(id);
+      $saveBtn.removeClass('btn-default')
+              .addClass('disabled btn-success')
+              .text('Saved');
+      console.log(resp);
+    });
+  }
+  const button = (<button id={'save' + props.match.idx} onClick={onClick.bind(this, payload)} className="btn btn-default">SAVE</button>);
+
   return (
     <div className="panel panel-default panel-visible">
       <div className="panel-body">
         <Icon match={props.match} />
         <Markup match={props.match} />
+        {button}
       </div>
     </div>
   );
diff --git a/hubs/static/client/app/index.jsx b/hubs/static/client/app/index.jsx
index 7641684..3976b89 100644
--- a/hubs/static/client/app/index.jsx
+++ b/hubs/static/client/app/index.jsx
@@ -2,4 +2,8 @@
  * since the feed component places itself on window.
  * The feed will not work without it.
  */
+import $ from 'jquery';
+
 import Feed from './components/Feed.jsx'; // eslint-disable-line
+
+window.$ = $;
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index fb36b2d..f940af9 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -46,7 +46,13 @@
     <div id="mentionsFeed"></div>
   </div>
   <div role="tabpanel" class="tab-pane fade" id="saved">
-    <div id="savedFeed"></div>
+    <div class="container">
+      <div class="row">
+        <div class="col-sm-9 pull-left">
+          <div id="savedFeed"></div>
+        </div>
+      </div>
+    </div>
   </div>
 </div>
 <script type="text/javascript"
@@ -63,11 +69,11 @@
      reactRender(element, document.getElementById(feed.name));
    });
    var savedFeed = React.createElement(Feed, {
-     matches: {{saved}},
-     url: null,
+     matches: {{saved|safe}},
+     url: false,
      messageLimit: 100
    });
-   reactRender(savedFeed, document.getElementById('saved'));
+   reactRender(savedFeed, document.getElementById('savedFeed'));
  })();
 </script>
 <style>

From 1b1493ba9bcd259fe131d511d21da265d92f7d7e Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 610/1001] Data for Mentions, stream, and actions


---

diff --git a/hubs/app.py b/hubs/app.py
index 957a809..67cad13 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -52,6 +52,7 @@ import fedmsg.meta
 
 fedmsg_config = fedmsg.config.load_config()
 fedmsg.meta.make_processors(**fedmsg_config)
+paths = fmn.lib.load_rules(root='fmn.rules')
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 datanommer.models.init(fedmsg_config['datanommer.sqlalchemy.uri'])
@@ -525,15 +526,91 @@ def login_required(function):
 @app.route('/<name>/stream/')
 @login_required
 def stream(name):
-    feeds = [
-        {'url': '', 'name': 'streamFeed', 'matches': []},
-        {'url': '', 'name': 'actionsFeed', 'matches': []},
-        {'url': '', 'name': 'mentionsFeed', 'matches': []},
-    ]
     saved = hubs.models.SavedNotification.by_username(session, name)
     saved = [n.__json__() for n in saved]
 
-    return flask.render_template('stream.html', feeds=json.dumps(feeds), saved=json.dumps(saved))
+    actions_rule = {
+        'filters': [{
+            'created_on': 'Thu, 15 Jan 2015 16:07:43 GMT',
+            'id': 20506,
+            'name': 'Events referring to my username',
+            'oneshot': None,
+            'rules': [
+                {
+                    'arguments': {
+                        'fasnick': name
+                    },
+                    'cache_key': '2f59dcddf85cab5822af8d40d82c7390ce0f80b40119f2db67f3037a0594a2a1',
+                    'code_path': 'fmn.rules:user_filter',
+                    'created_on': 'Thu, 15 Jan 2015 16:07:43 GMT',
+                    'info': {
+                        'args': [
+                            'config',
+                            'message',
+                            'fasnick'
+                        ],
+                        'datanommer-hints': {},
+                        'doc': "<p>Use this rule to include messages that are associated with a\nspecific user.</p>",
+                        'doc-no-links': '<html><head></head><body><p>Use this rule to include messages that are associated with a\nspecific user.</p>\n</body></html>',
+                        'hints-invertible': True,
+                        'submodule': 'generic',
+                        'title': 'A particular user'
+                    },
+                    'negated': False
+                }]
+        }]
+    }
+    actions_rule = hubs.widgets.feed.rehydrate_preference(actions_rule)
+    messages = []
+    matches = []
+
+    delta = datetime.timedelta(days=365)
+    end = datetime.datetime.utcnow()
+
+    fmn_hinting = fmn.lib.hinting.gather_hinting(fedmsg_config, actions_rule['filters'][0]['rules'], paths)
+    total, pages, rows = datanommer.models.Message.grep(
+        start=end - delta,
+        end=end,
+        rows_per_page=100,
+        page=1,
+        order='desc',
+        **fmn_hinting
+    )
+    messages.extend(rows)
+
+    for message in messages:
+        original = message.__json__()
+        if name in fedmsg.meta.msg2usernames(original, **fedmsg_config):
+            matches.append(original)
+
+    # Smash multiple messages into single ones
+    matches = fedmsg.meta.conglomerate(matches, lexers=True, **fedmsg_config)
+
+    # Apply some html markup to the subtitles for extra fanciness.
+    for match in matches:
+        match['markup'] = hubs.widgets.feed.apply_markup(match)
+        for idx, constituent in match['msg_ids'].items():
+            constituent['markup'] = hubs.widgets.feed.apply_markup(constituent)
+            if constituent['long_form'] != constituent['subtitle']:
+                if constituent.get('lexer'):
+                    constituent['long_form'] = pygments.highlight(
+                        constituent['long_form'],
+                        constituent['lexer'],
+                        pygments.formatters.HtmlFormatter(style='monokai'),
+                    )
+                else:
+                    markup = u"<h5>{long_form}</h5>".format(**constituent)
+                    constituent['long_form'] = markup
+
+        # And tack on a unique identifier for each top level entry.
+        match['dom_id'] = six.text_type(uuid.uuid4())
+
+    matches = json.dumps(matches, cls=hubs.widgets.feed.PythonObjectEncoder)
+    return flask.render_template(
+        'stream.html',
+        saved=json.dumps(saved),
+        actions=matches
+    )
 
 
 @app.route('/<user>/notifications', methods=['GET', 'POST'])
@@ -563,7 +640,7 @@ def notifications(user):
         session.add(notification)
         session.commit()
         return flask.jsonify(
-            dict(notification=notification.__json__(),success=True)
+            dict(notification=notification.__json__(), success=True)
         )
 
 @app.before_request
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index 4086e00..bb5aa16 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -37,7 +37,7 @@ export default class Feed extends React.Component {
     });
     return (
       <div>
-      {feedNodes}
+        {feedNodes}
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
index 66f4da4..f2464fe 100644
--- a/hubs/static/client/app/components/Markup.jsx
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -6,6 +6,7 @@ export default class Markup extends React.Component {
     return { __html: this.props.match.markup };
   }
   render() {
+    const timestamp = this.props.date_time ? (<TimeAgo date={this.props.match.date_time} />) : null;
     return (
       <div className="media-body">
         <h4
@@ -13,7 +14,7 @@ export default class Markup extends React.Component {
           dangerouslySetInnerHTML={this.createMarkup()}
         >
         </h4>
-        <TimeAgo date={this.props.match.date_time} />
+        {timestamp}
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
index a5aa178..1651554 100644
--- a/hubs/static/client/app/components/Panel.jsx
+++ b/hubs/static/client/app/components/Panel.jsx
@@ -26,7 +26,10 @@ const Panel = function (props) {
       console.log(resp);
     });
   }
-  const button = (<button id={'save' + props.match.idx} onClick={onClick.bind(this, payload)} className="btn btn-default">SAVE</button>);
+  const button = props.match.saved
+               ? null
+               : (<button id={'save' + props.match.idx} onClick={onClick.bind(this, payload)} className="btn btn-default">SAVE</button>);
+
 
   return (
     <div className="panel panel-default panel-visible">
diff --git a/hubs/templates/includes/_messages.html b/hubs/templates/includes/_messages.html
new file mode 100644
index 0000000..1502b48
--- /dev/null
+++ b/hubs/templates/includes/_messages.html
@@ -0,0 +1,153 @@
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User XYZ mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User ABC mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User ABC mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User XYZ mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User ABC mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User XYZ mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User XYZ mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User ABC mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User XYZ mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User ABC mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-default panel-visible">
+  <div class="panel-body">
+    <div>
+      <div class="media-left">
+        <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
+      </div>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">User XYZ mentioned you in a <a href="#" > comment</a></h4>
+      <time datetime="2016-07-20T23:44:37.121Z" title="2016-07-20 19:44:37.121830">16 hours ago</time>
+    </div>
+  </div>
+</div>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index f940af9..bde7758 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -40,14 +40,36 @@
   </div>
 
   <div role="tabpanel" class="tab-pane fade" id="actions">
-    <div id="actionsFeed"></div>
+    <div class="container">
+      <div class="row">
+        {% include "includes/_searchstream.html" %}
+        <div class="alert alert-warning" role="alert">
+          This stream is filtered. <a href="#">View Filters</a>
+        </div>
+        <div class="col-sm-9 pull-left">
+          <div id="actionsFeed"></div>
+        </div>
+      </div>
+    </div>
   </div>
   <div role="tabpanel" class="tab-pane fade" id="mentions">
-    <div id="mentionsFeed"></div>
+    <div class="container">
+      <div class="row">
+        {% include "includes/_searchstream.html" %}
+        <br/>
+        <div class="col-sm-9 pull-left">
+          <div id="mentionsFeed">
+            {% include "includes/_messages.html" %}
+          </div>
+        </div>
+      </div>
+    </div>
   </div>
   <div role="tabpanel" class="tab-pane fade" id="saved">
     <div class="container">
       <div class="row">
+        <br/>
+        {% include "includes/_searchstream.html" %}
         <div class="col-sm-9 pull-left">
           <div id="savedFeed"></div>
         </div>
@@ -59,15 +81,19 @@
         src ="{{url_for('static', filename='js/hubs.js')}}"></script>
 <script>
  (function() {
-   var feeds = {{ feeds|safe }};
-   feeds.forEach(function (feed) {
-     var element = React.createElement(Feed, {
-       matches: feed.matches,
-       url: feed.url,
-       messageLimit: 100
-     });
-     reactRender(element, document.getElementById(feed.name));
+   var actions = {{actions|safe}};
+
+   var streamFeed = React.createElement(Feed, {
+     matches: actions,
+     url: false,
+     messageLimit: 100
    });
+   /* Right now, stream and actions are the same.
+    * Once, Mentions is implemented, then each will be its own
+    */
+   reactRender(streamFeed, document.getElementById('streamFeed'));
+   reactRender(streamFeed, document.getElementById('actionsFeed'));
+
    var savedFeed = React.createElement(Feed, {
      matches: {{saved|safe}},
      url: false,

From e4df27462cd833c8f7ced2badc75af431c2134eb Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 611/1001] Make stream code more readable, improve save


---

diff --git a/hubs/app.py b/hubs/app.py
index 67cad13..ec76fdb 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -457,7 +457,7 @@ def widget_source(name):
     from hubs.widgets import registry
     base = '/hubs/'
     fname = ''
-    
+
     try:
         fname = base + registry[name].__file__.split(base, 1)[1]
     except KeyError:
@@ -522,6 +522,31 @@ def login_required(function):
 
     return decorated_function
 
+def apply_html(actions):
+    # Smash multiple messages into single ones
+    actions = fedmsg.meta.conglomerate(actions, lexers=True, **fedmsg_config)
+
+    # Apply some html markup to the subtitles for extra fanciness.
+    for match in actions:
+        match['markup'] = hubs.widgets.feed.apply_markup(match)
+        for idx, constituent in match['msg_ids'].items():
+            constituent['markup'] = hubs.widgets.feed.apply_markup(constituent)
+            if constituent['long_form'] != constituent['subtitle']:
+                if constituent.get('lexer'):
+                    constituent['long_form'] = pygments.highlight(
+                        constituent['long_form'],
+                        constituent['lexer'],
+                        pygments.formatters.HtmlFormatter(style='monokai'),
+                    )
+                else:
+                    markup = u"<h5>{long_form}</h5>".format(**constituent)
+                    constituent['long_form'] = markup
+        # And tack on a unique identifier for each top level entry.
+        match['dom_id'] = six.text_type(uuid.uuid4())
+
+    return actions
+
+
 @app.route('/<name>/stream')
 @app.route('/<name>/stream/')
 @login_required
@@ -529,7 +554,7 @@ def stream(name):
     saved = hubs.models.SavedNotification.by_username(session, name)
     saved = [n.__json__() for n in saved]
 
-    actions_rule = {
+    preference = {
         'filters': [{
             'created_on': 'Thu, 15 Jan 2015 16:07:43 GMT',
             'id': 20506,
@@ -560,56 +585,37 @@ def stream(name):
                 }]
         }]
     }
-    actions_rule = hubs.widgets.feed.rehydrate_preference(actions_rule)
+    preference = hubs.widgets.feed.rehydrate_preference(preference)
     messages = []
-    matches = []
+    actions = []
 
     delta = datetime.timedelta(days=365)
     end = datetime.datetime.utcnow()
 
-    fmn_hinting = fmn.lib.hinting.gather_hinting(fedmsg_config, actions_rule['filters'][0]['rules'], paths)
-    total, pages, rows = datanommer.models.Message.grep(
-        start=end - delta,
-        end=end,
-        rows_per_page=100,
-        page=1,
-        order='desc',
-        **fmn_hinting
-    )
-    messages.extend(rows)
+    for fmn_filter in preference['filters']:
+        fmn_hinting = fmn.lib.hinting.gather_hinting(fedmsg_config, fmn_filter['rules'], paths)
+        total, pages, rows = datanommer.models.Message.grep(
+            start=end - delta,
+            end=end,
+            rows_per_page=100,
+            page=1,
+            order='desc',
+            **fmn_hinting
+        )
+        messages.extend(rows)
 
     for message in messages:
         original = message.__json__()
         if name in fedmsg.meta.msg2usernames(original, **fedmsg_config):
-            matches.append(original)
-
-    # Smash multiple messages into single ones
-    matches = fedmsg.meta.conglomerate(matches, lexers=True, **fedmsg_config)
+            actions.append(original)
 
-    # Apply some html markup to the subtitles for extra fanciness.
-    for match in matches:
-        match['markup'] = hubs.widgets.feed.apply_markup(match)
-        for idx, constituent in match['msg_ids'].items():
-            constituent['markup'] = hubs.widgets.feed.apply_markup(constituent)
-            if constituent['long_form'] != constituent['subtitle']:
-                if constituent.get('lexer'):
-                    constituent['long_form'] = pygments.highlight(
-                        constituent['long_form'],
-                        constituent['lexer'],
-                        pygments.formatters.HtmlFormatter(style='monokai'),
-                    )
-                else:
-                    markup = u"<h5>{long_form}</h5>".format(**constituent)
-                    constituent['long_form'] = markup
-
-        # And tack on a unique identifier for each top level entry.
-        match['dom_id'] = six.text_type(uuid.uuid4())
+    actions = apply_html(actions)
 
-    matches = json.dumps(matches, cls=hubs.widgets.feed.PythonObjectEncoder)
+    actions = json.dumps(actions, cls=hubs.widgets.feed.PythonObjectEncoder)
     return flask.render_template(
         'stream.html',
         saved=json.dumps(saved),
-        actions=matches
+        actions=actions
     )
 
 
@@ -629,13 +635,15 @@ def notifications(user):
             markup = data['markup']
             link = data['link']
             icon = data['secondary_icon']
+            dom_id = data['dom_id']
         except:
             return str(flask.request.data)
         notification = hubs.models.SavedNotification(
             username=user,
             markup=markup,
             link=link,
-            secondary_icon=icon
+            secondary_icon=icon,
+            dom_id=dom_id
         )
         session.add(notification)
         session.commit()
diff --git a/hubs/models.py b/hubs/models.py
index 03217c1..48ed913 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -487,23 +487,26 @@ class SavedNotification(BASE):
     __tablename__ = 'savednotifications'
     user = sa.Column(sa.Text, sa.ForeignKey('users.username'))
 
+    created = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
+    dom_id = sa.Column(sa.Text)
     idx = sa.Column(sa.Integer, primary_key=True)
-    markup = sa.Column(sa.Text)
     link = sa.Column(sa.Text)
+    markup = sa.Column(sa.Text)
     secondary_icon = sa.Column(sa.Text)
-    created = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
 
 
-    def __init__(self, username=None, markup='', link='', secondary_icon=''):
+    def __init__(self, username=None, markup='', link='', secondary_icon='', dom_id=''):
         self.user = username
         self.markup = markup
         self.link = link
         self.secondary_icon = secondary_icon
+        self.dom_id = dom_id
 
     def __json__(self):
         return {
             'created': str(self.created),
             'date_time': str(self.created),
+            'dom_id': self.dom_id,
             'idx': self.idx,
             'link': bleach.linkify(self.link),
             'markup': bleach.linkify(self.markup),
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
index 1651554..a30eab1 100644
--- a/hubs/static/client/app/components/Panel.jsx
+++ b/hubs/static/client/app/components/Panel.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
+ import React from 'react';
 import $ from 'jquery';
 
 import Icon from './Icon.jsx';
@@ -9,6 +9,7 @@ const Panel = function (props) {
     link: props.match.link,
     markup: props.match.markup,
     secondary_icon: props.match.secondary_icon,
+    dom_id: props.match.dom_id,
   };
 
   function onClick(data) {
@@ -18,25 +19,22 @@ const Panel = function (props) {
       data: JSON.stringify(data),
       contentType: 'application/json',
     }).done(resp => {
-      const id = '#save' + resp.notification.idx;
+      const id = "#save" + props.match.dom_id;
       const $saveBtn = $(id);
-      $saveBtn.removeClass('btn-default')
-              .addClass('disabled btn-success')
-              .text('Saved');
-      console.log(resp);
+      $saveBtn.removeClass('btn-default').addClass('btn-success').text('SAVED')
     });
   }
-  const button = props.match.saved
-               ? null
-               : (<button id={'save' + props.match.idx} onClick={onClick.bind(this, payload)} className="btn btn-default">SAVE</button>);
-
+  let saveBtn;
+  if (!props.match.saved) {
+    saveBtn = (<button id={'save' + props.match.dom_id} onClick={onClick.bind(this, payload)} className="btn btn-sm btn-default">SAVE</button>);
+  }
 
   return (
     <div className="panel panel-default panel-visible">
       <div className="panel-body">
         <Icon match={props.match} />
         <Markup match={props.match} />
-        {button}
+        {saveBtn}
       </div>
     </div>
   );

From 122f0cd7420461af6f18083bebc6956ef4d0799f Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 612/1001] Hide save button if notif has already been saved..


* Remove unused files
* Remove unused code in python and JSX files

---

diff --git a/hubs/app.py b/hubs/app.py
index ec76fdb..3036b6e 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -6,7 +6,6 @@ import os
 import urlparse
 import uuid
 
-import bleach
 import flask
 import flask.json
 import fmn.lib
@@ -19,7 +18,6 @@ from flask.ext.oidc import OpenIDConnect
 import fmn.lib
 import hubs.models
 import hubs.widgets
-from hubs.widgets import clean_input
 
 import datanommer.models
 
@@ -610,6 +608,9 @@ def stream(name):
             actions.append(original)
 
     actions = apply_html(actions)
+    for action in actions:
+        if any(s['markup'] == action['markup'] for s in saved):
+            action['saved'] = True
 
     actions = json.dumps(actions, cls=hubs.widgets.feed.PythonObjectEncoder)
     return flask.render_template(
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
index a30eab1..3bfd96a 100644
--- a/hubs/static/client/app/components/Panel.jsx
+++ b/hubs/static/client/app/components/Panel.jsx
@@ -1,5 +1,4 @@
- import React from 'react';
-import $ from 'jquery';
+import React from 'react';
 
 import Icon from './Icon.jsx';
 import Markup from './Markup.jsx';
diff --git a/hubs/static/client/app/index.jsx b/hubs/static/client/app/index.jsx
index 3976b89..7641684 100644
--- a/hubs/static/client/app/index.jsx
+++ b/hubs/static/client/app/index.jsx
@@ -2,8 +2,4 @@
  * since the feed component places itself on window.
  * The feed will not work without it.
  */
-import $ from 'jquery';
-
 import Feed from './components/Feed.jsx'; // eslint-disable-line
-
-window.$ = $;
diff --git a/hubs/templates/_messages.html b/hubs/templates/_messages.html
deleted file mode 100644
index 7f942d3..0000000
--- a/hubs/templates/_messages.html
+++ /dev/null
@@ -1,294 +0,0 @@
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
-<div class="panel panel-default panel-visible">
-  <div clas="panel-body">
-    <div class="media-left">
-      <a href="#" target="_blank">
-        <img alt="User avatar" class="media-object square-32 img-circle" src="https://placekitten.com/200/200"/>
-      </a>
-    </div>
-    <div className="media-body">
-      <h4 className="media-heading">
-        This is some markup
-      </h4>
-    </div>
-  </div>
-</div>
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 3e6b586..8ea6536 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -1,29 +1,12 @@
 from __future__ import print_function
 
 from hubs.hinting import hint
-from hubs.widgets.base import argument, cache
+from hubs.widgets.base import argument
 from hubs.widgets import templating
 
-import fmn.lib
-import fmn.lib.hinting
-
-import datanommer.models
-
-import arrow
-import munch
-import requests
-import six
-
-import pygments.formatters
-
-import flask
-
 import hubs.validators as validators
 
-import datetime
-import json
 import logging
-import uuid
 
 log = logging.getLogger('hubs')
 
@@ -32,6 +15,7 @@ chrome = panel('Live Feed')
 template = templating.environment.get_template('templates/feed.html')
 position = 'left'
 
+
 @argument(name="username",
           default=None,
           validator=validators.username,
@@ -44,15 +28,9 @@ def data(session, widget, username, message_limit):
     # Avoid circular import
     from hubs.app import app
     feed_url = app.config['SSE_URL'] + username
-    return dict(
-        matches=[],
-        message_limit=message_limit,
-        feed_url=feed_url
-    )
+    return dict(matches=[], message_limit=message_limit, feed_url=feed_url)
+
 
 @hint(ubiquitous=True)
 def should_invalidate(message, session, widget):
     pass
-
-
-

From deb7a7f4be475755501c487ce0a3c5f53e1cea04 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 613/1001] Add widget ability to my stream page


Clean up a lot of the JS code
Pull save button out to own (pure) component

---

diff --git a/hubs/app.py b/hubs/app.py
index 3036b6e..a9d1893 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -549,6 +549,7 @@ def apply_html(actions):
 @app.route('/<name>/stream/')
 @login_required
 def stream(name):
+    hub = get_hub(session, name)
     saved = hubs.models.SavedNotification.by_username(session, name)
     saved = [n.__json__() for n in saved]
 
@@ -615,6 +616,7 @@ def stream(name):
     actions = json.dumps(actions, cls=hubs.widgets.feed.PythonObjectEncoder)
     return flask.render_template(
         'stream.html',
+        hub=hub,
         saved=json.dumps(saved),
         actions=actions
     )
@@ -632,7 +634,6 @@ def notifications(user):
     if flask.request.method == 'POST':
         data = flask.request.json
         try:
-            # TODO clean these with pingou's new method
             markup = data['markup']
             link = data['link']
             icon = data['secondary_icon']
diff --git a/hubs/models.py b/hubs/models.py
index 48ed913..68197d8 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -34,7 +34,7 @@ from sqlalchemy import create_engine
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.orm import sessionmaker
 from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import relation, relationship
+from sqlalchemy.orm import relation
 from sqlalchemy.orm import backref
 
 import fedmsg
@@ -354,7 +354,7 @@ class User(BASE):
     username = sa.Column(sa.Text, primary_key=True)
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
-    saved_notifications = relationship('SavedNotification', backref='users',
+    saved_notifications = relation('SavedNotification', backref='users',
                                        lazy='dynamic')
 
     def __json__(self, session):
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index bb5aa16..4562dcd 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -33,7 +33,8 @@ export default class Feed extends React.Component {
   }
   render() {
     const feedNodes = this.state.matches.map((match, idx) => {
-      return <Panel match={match} key={idx} />;
+      const saveUrl = this.props.saveUrl || null;
+      return <Panel match={match} saveUrl={saveUrl} key={idx} />;
     });
     return (
       <div>
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
index 3bfd96a..7760893 100644
--- a/hubs/static/client/app/components/Panel.jsx
+++ b/hubs/static/client/app/components/Panel.jsx
@@ -2,30 +2,16 @@ import React from 'react';
 
 import Icon from './Icon.jsx';
 import Markup from './Markup.jsx';
+import SaveNotificationButton from './SaveNotificationButton.jsx';
 
 const Panel = function (props) {
-  const payload = {
-    link: props.match.link,
-    markup: props.match.markup,
-    secondary_icon: props.match.secondary_icon,
-    dom_id: props.match.dom_id,
-  };
-
-  function onClick(data) {
-    $.ajax({
-      type: 'POST',
-      url: '/atelic/notifications/',
-      data: JSON.stringify(data),
-      contentType: 'application/json',
-    }).done(resp => {
-      const id = "#save" + props.match.dom_id;
-      const $saveBtn = $(id);
-      $saveBtn.removeClass('btn-default').addClass('btn-success').text('SAVED')
-    });
-  }
   let saveBtn;
-  if (!props.match.saved) {
-    saveBtn = (<button id={'save' + props.match.dom_id} onClick={onClick.bind(this, payload)} className="btn btn-sm btn-default">SAVE</button>);
+  if (!props.match.saved && props.saveUrl) {
+    saveBtn = (
+      <SaveNotificationButton
+        match={props.match}
+        saveUrl={props.saveUrl}
+      />);
   }
 
   return (
diff --git a/hubs/static/client/app/components/SaveNotificationButton.jsx b/hubs/static/client/app/components/SaveNotificationButton.jsx
new file mode 100644
index 0000000..2b82d78
--- /dev/null
+++ b/hubs/static/client/app/components/SaveNotificationButton.jsx
@@ -0,0 +1,34 @@
+import React from 'react';
+
+const SaveNotificationButton = function (props) {
+  const payload = {
+    link: props.match.link,
+    markup: props.match.markup,
+    secondary_icon: props.match.secondary_icon,
+    dom_id: props.match.dom_id,
+  };
+
+  function onClick(data) {
+    $.ajax({
+      type: 'POST',
+      url: props.saveUrl,
+      data: JSON.stringify(data),
+      contentType: 'application/json',
+    }).done(() => {
+      const id = '#save' + props.match.dom_id;
+      const $saveBtn = $(id);
+      $saveBtn.removeClass('btn-default').addClass('btn-success').text('SAVED');
+    });
+  }
+  return (
+    <button
+      id={'save' + props.match.dom_id}
+      onClick={onClick.bind(this, payload)}
+      className="btn btn-sm btn-default"
+    >
+      SAVE
+    </button>
+  );
+};
+
+export default SaveNotificationButton;
diff --git a/hubs/templates/includes/_library.html b/hubs/templates/includes/_library.html
deleted file mode 100644
index c4acbea..0000000
--- a/hubs/templates/includes/_library.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<div class="col-sm-3">
-  <div class="card-header">
-    My Library
-    <div class="pull-right widget-buttons">
-      <a href="#"><span class="oi" data-glyph="external-link"></span></a>
-      <a data-target="#edit_modal" data-toggle="modal" type="button"
-        class="edit_widget" data-idx="">
-        <span class="oi" data-glyph="pencil"></span>
-      </a>
-    </div>
-  </div>
-  <div class="card">
-    <div class="card-block">
-      <p class="card-text">
-        <li>Lorem</li>
-        <li>Ipsum</li>
-        <li>Sit</li>
-        <li>Amet</li>
-      </p>
-    </div>
-  </div>
-</div>
diff --git a/hubs/templates/includes/_rightpanel.html b/hubs/templates/includes/_rightpanel.html
new file mode 100644
index 0000000..2a9f511
--- /dev/null
+++ b/hubs/templates/includes/_rightpanel.html
@@ -0,0 +1,5 @@
+<div id="right_widgets">
+  {% for widget in hub.right_widgets %}
+  <div id="widget-{{ widget.idx }}" class="widget row"></div>
+  {% endfor %}
+</div>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index bde7758..6da69e4 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -27,14 +27,16 @@
   <div role="tabpanel" class="tab-pane fade in active" id="stream">
     <div class="container">
       <div class="row">
-        <div class="col-sm-9 pull-left">
+        <div class="col-sm-8 pull-left">
           {% include "includes/_searchstream.html" %}
           <div class="alert alert-warning" role="alert">
             This stream is filtered. <a href="#">View Filters</a>
           </div>
           <div id="streamFeed"></div>
         </div>
-        {% include "includes/_library.html" %}
+        <div class="col-sm-4">
+          {% include "includes/_rightpanel.html" %}
+        </div>
       </div>
     </div>
   </div>
@@ -46,9 +48,12 @@
         <div class="alert alert-warning" role="alert">
           This stream is filtered. <a href="#">View Filters</a>
         </div>
-        <div class="col-sm-9 pull-left">
+        <div class="col-sm-8 pull-left">
           <div id="actionsFeed"></div>
         </div>
+        <div class="col-sm-4">
+          {% include "includes/_rightpanel.html" %}
+        </div>
       </div>
     </div>
   </div>
@@ -57,10 +62,13 @@
       <div class="row">
         {% include "includes/_searchstream.html" %}
         <br/>
-        <div class="col-sm-9 pull-left">
+        <div class="col-sm-8 pull-left">
           <div id="mentionsFeed">
             {% include "includes/_messages.html" %}
           </div>
+          <div class="col-sm-4">
+            {% include "includes/_rightpanel.html" %}
+          </div>
         </div>
       </div>
     </div>
@@ -70,22 +78,62 @@
       <div class="row">
         <br/>
         {% include "includes/_searchstream.html" %}
-        <div class="col-sm-9 pull-left">
+        <div class="col-sm-8 pull-left">
           <div id="savedFeed"></div>
         </div>
+        <div class="col-sm-4">
+          {% include "includes/_rightpanel.html" %}
+        </div>
       </div>
     </div>
   </div>
 </div>
+<style>
+ .jumbotron {
+   margin-bottom: 0;
+ }
+</style>
+{% endblock %}
+
+{% block jscripts %}
+{{ super() }}
 <script type="text/javascript"
-        src ="{{url_for('static', filename='js/hubs.js')}}"></script>
+  src ="{{url_for('static', filename='js/hubs.js')}}"></script>
 <script>
- (function() {
+ function setup_widgets(widgets) {
+   var all_widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
+   if (widgets == undefined) {
+     var widgets = all_widgets;
+   }
+   $.each(widgets, function(i, widget) {
+     $.ajax({
+       url: '/{{hub.name}}/' + widget,
+       dataType: 'html',
+       success: function(html) {
+         $('#widget-' + widget).html(html);
+         setTimeout(function() {
+           $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
+         }, 100);
+       },
+       error: function() {
+         $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
+         console.log('error');
+         console.trace();
+       },
+     });
+   });
+ }
+ window.onload = function(){
+   setup_widgets();
+   setup_feeds();
+ }
+
+ function setup_feeds() {
    var actions = {{actions|safe}};
 
    var streamFeed = React.createElement(Feed, {
      matches: actions,
-     url: false,
+     saveUrl: '/{{hub.name}}/notifications/',
      messageLimit: 100
    });
    /* Right now, stream and actions are the same.
@@ -100,11 +148,6 @@
      messageLimit: 100
    });
    reactRender(savedFeed, document.getElementById('savedFeed'));
- })();
-</script>
-<style>
- .jumbotron {
-   margin-bottom: 0;
  }
-</style>
+</script>
 {% endblock %}

From 85f4b1d5323666a0f812d027d39b8bb7d9eb5fdb Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 614/1001] Add SavedNotifications tests


---

diff --git a/hubs/app.py b/hubs/app.py
index a9d1893..925f3a3 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -632,16 +632,19 @@ def notifications(user):
         return flask.jsonify(notifications)
 
     if flask.request.method == 'POST':
-        data = flask.request.json
+        data = json.loads(flask.request.data)
+        user = hubs.models.User.by_username(session, user)
+        if not user:
+            return flask.abort(400)
         try:
             markup = data['markup']
             link = data['link']
             icon = data['secondary_icon']
             dom_id = data['dom_id']
         except:
-            return str(flask.request.data)
+            return flask.abort(400)
         notification = hubs.models.SavedNotification(
-            username=user,
+            username=user.username,
             markup=markup,
             link=link,
             secondary_icon=icon,
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 153374a..e7f4eba 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -45,6 +45,10 @@ class APPTest(unittest.TestCase):
             fullname = user.title()
             hubs.models.User.get_or_create(
                 hubs.app.session, username=user, fullname=fullname)
+            saved_notif = hubs.models.SavedNotification(
+                username=user, markup='foo', link='bar'
+            )
+            hubs.app.session.add(saved_notif)
 
         hubs.app.session.flush()
 
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
new file mode 100644
index 0000000..ea8616f
--- /dev/null
+++ b/hubs/tests/test_api/test_notifications.py
@@ -0,0 +1,84 @@
+import json
+from urlparse import urlparse
+
+import hubs.tests
+import hubs.models
+from hubs.app import app
+
+
+class TestGetNotifications(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('ralph')
+
+    def test_get_notifications_invalid_name(self):
+        name = 'notarealfasuser'
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.get('/{}/notifications/'.format(name))
+        self.assertEqual(resp.status_code, 200)
+        data = json.loads(resp.data)
+        self.assertEqual(data, [])
+
+    def test_get_notifications_valid_name(self):
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.get('/{}/notifications/'.format(
+                self.user.username))
+
+        self.assertEqual(resp.status_code, 200)
+        data = json.loads(resp.data)
+        self.assertEqual(len(data), 1)
+
+        for saved in data:
+            self.assertEqual(saved['markup'], 'foo')
+            self.assertEqual(saved['link'], 'bar')
+
+
+class TestPostNotifications(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('ralph')
+    valid_payload = {
+        'username': user.username,
+        'markup': 'foobar',
+        'link': 'baz',
+        'secondary_icon': 'http://placekitten.com/g/200/300',
+        'dom_id': 'reallyuniqueuid'
+    }
+
+    invalid_payload = {
+        'username': user.username,
+    }
+
+    def test_post_notification_invalid_user(self):
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post(
+                '/{}/notifications/'.format('notarealfasuser'),
+                data=json.dumps(self.valid_payload))
+        self.assertEqual(resp.status_code, 400)
+
+    def test_post_notification_invalid_payload(self):
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post(
+                '/{}/notifications/'.format(self.user.username),
+                data=json.dumps(self.invalid_payload))
+        self.assertEqual(resp.status_code, 400)
+
+    def test_post_notification_valid_payload(self):
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post(
+                '/{}/notifications/'.format(self.user.username),
+                data=json.dumps(self.valid_payload))
+
+        self.assertEqual(resp.status_code, 200)
+        data = json.loads(resp.data)
+        self.assertTrue(isinstance(data, dict))
+
+        notification = data['notification']
+        self.assertEqual(notification['markup'], 'foobar')
+        self.assertEqual(notification['link'], 'baz')
+
+        all_saved = hubs.models.SavedNotification.by_username(
+            hubs.app.session, self.user.username)
+        self.assertEqual(len(all_saved), 2)
+        all_saved = [s.__json__() for s in all_saved]
+        self.assertTrue(any(str(s['markup']) == self.valid_payload['markup']
+                            for s in all_saved))
+        self.assertTrue(any(str(s['link']) == self.valid_payload['link']
+                            for s in all_saved))

From 7f1455b3fcecd0bd803de44f599db89ff295dd58 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 615/1001] Major improvements for Feed UI


* Revert the breaks in the card interface for feed widget from switching
to fedora-bootstrapp.

* Spacing and font size fixes

---

diff --git a/hubs/static/client/app/components/Icon.jsx b/hubs/static/client/app/components/Icon.jsx
index 08c8d60..9adf0e4 100644
--- a/hubs/static/client/app/components/Icon.jsx
+++ b/hubs/static/client/app/components/Icon.jsx
@@ -2,16 +2,14 @@ import React from 'react';
 
 const Icon = function (props) {
   return (
-    <div>
-      <div className="media-left">
-        <a href={props.match.link ? props.match.link : '#'} target="_blank">
-          <img
-            alt="User avatar"
-            className="media-object square-32 img-circle"
-            src={props.match.secondary_icon}
-          />
-        </a>
-      </div>
+    <div className="media-left">
+      <a href={props.match.link ? props.match.link : '#'} target="_blank">
+        <img
+          alt="User avatar"
+          className="media-object square-32"
+          src={props.match.secondary_icon}
+        />
+      </a>
     </div>
   );
 };
diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
index f2464fe..7342f58 100644
--- a/hubs/static/client/app/components/Markup.jsx
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -1,12 +1,25 @@
 import React from 'react';
+import SaveNotificationButton from './SaveNotificationButton.jsx';
+
 import TimeAgo from 'react-timeago';
 
+
 export default class Markup extends React.Component {
   createMarkup() {
     return { __html: this.props.match.markup };
   }
   render() {
     const timestamp = this.props.date_time ? (<TimeAgo date={this.props.match.date_time} />) : null;
+
+
+    let saveBtn;
+    if (!this.props.match.saved && this.props.saveUrl) {
+      saveBtn = (
+        <SaveNotificationButton
+          match={this.props.match}
+          saveUrl={this.props.saveUrl}
+        />);
+    }
     return (
       <div className="media-body">
         <h4
@@ -15,6 +28,7 @@ export default class Markup extends React.Component {
         >
         </h4>
         {timestamp}
+        {saveBtn}
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
index 7760893..0cd9bdf 100644
--- a/hubs/static/client/app/components/Panel.jsx
+++ b/hubs/static/client/app/components/Panel.jsx
@@ -2,24 +2,13 @@ import React from 'react';
 
 import Icon from './Icon.jsx';
 import Markup from './Markup.jsx';
-import SaveNotificationButton from './SaveNotificationButton.jsx';
 
 const Panel = function (props) {
-  let saveBtn;
-  if (!props.match.saved && props.saveUrl) {
-    saveBtn = (
-      <SaveNotificationButton
-        match={props.match}
-        saveUrl={props.saveUrl}
-      />);
-  }
-
   return (
-    <div className="panel panel-default panel-visible">
-      <div className="panel-body">
+    <div className="card">
+      <div className="card-block">
         <Icon match={props.match} />
-        <Markup match={props.match} />
-        {saveBtn}
+        <Markup match={props.match} saveUrl={props.saveUrl} />
       </div>
     </div>
   );
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index cb29255..3ab75a9 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -3,6 +3,32 @@
 {% block title %}{{ hub.name }}{% endblock %}
 {% block content %}
 
+  <div class="col-md-2">
+    <nav class="navbar navbar-light p-t-2 p-b-0">
+      <button type="button" class="navbar-toggler hidden-sm-up"
+        data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+        <span class="sr-only">Toggle navigation</span>
+        <span class="oi" data-glyph="menu"></span>
+      </button>
+
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      {% if g.auth.logged_in %}
+      <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav">
+          <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
+            <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
+          <li class="p-x-1 nav-item"><a class="nav-link" href="/{{g.auth.user.username}}/stream">My Stream</a></li>
+          {% for hub in g.auth.user.bookmarks %}
+          <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
+            <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
+          {% endfor %}
+          <!-- At the end of the list, tack on a link to all groups -->
+          <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
+        </ul>
+      </div><!-- /.navbar-collapse -->
+      {% endif %}
+    </nav>
+  </div>
   <header class="p-t-2">
     <div class="container">
 
diff --git a/hubs/templates/includes/_messages.html b/hubs/templates/includes/_messages.html
index 1502b48..1e89ae8 100644
--- a/hubs/templates/includes/_messages.html
+++ b/hubs/templates/includes/_messages.html
@@ -1,5 +1,5 @@
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -12,8 +12,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -26,8 +26,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -40,8 +40,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -54,8 +54,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -68,8 +68,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -82,8 +82,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -96,8 +96,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -110,8 +110,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -124,8 +124,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
@@ -138,8 +138,8 @@
   </div>
 </div>
 
-<div class="panel panel-default panel-visible">
-  <div class="panel-body">
+<div class="card">
+  <div class="card-block">
     <div>
       <div class="media-left">
         <a href="#" target="_blank"><img alt="User avatar" class="media-object square-32 img-circle" src="https://secure.gravatar.com/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea.jpg?s=64&d=retro"></a>
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 1e19d91..e02081b 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -52,33 +52,6 @@
   </div>
 </div>
 <div class="bodycontent">
-  <div class="col-md-2">
-    <nav class="navbar navbar-light p-t-2 p-b-0">
-      <button type="button" class="navbar-toggler hidden-sm-up"
-        data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
-        <span class="sr-only">Toggle navigation</span>
-        <span><i class="fa fa-bars" aria-hidden="true"></i></span>
-      </button>
-
-      <!-- Collect the nav links, forms, and other content for toggling -->
-      {% if g.auth.logged_in %}
-      <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
-        <ul class="nav navbar-nav">
-          <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
-            <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
-          <li class="p-x-1 nav-item"><a class="nav-link" href="/{{g.auth.user.username}}/stream">My Stream</a></li>
-          {% for hub in g.auth.user.bookmarks %}
-          <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
-            <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
-          {% endfor %}
-          <!-- At the end of the list, tack on a link to all groups -->
-
-            <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
-        </ul>
-      </div><!-- /.navbar-collapse -->
-      {% endif %}
-    </nav>
-  </div>
 
 {% block content %}{% endblock %}
 
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 6da69e4..eff03f8 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -6,13 +6,12 @@
   <h1>My Stream</h1>
   <p>Notifications, actions, and other things of interest to me</p>
 </div>
-
-<ul class="nav nav-tabs" role="tablist">
+<ul class="nav-tabs " role="tablist">
   <li class="nav-item">
-    <a class="nav-link active" href="#stream" role="tab" data-toggle="tab">My stream</a>
+    <a class="nav-link active" href="#stream" role="tab" data-toggle="tab">My Stream</a>
   </li>
   <li class="nav-item">
-    <a class="nav-link" href="#actions" role="tab" data-toggle="tab">My actions</a>
+    <a class="nav-link" href="#actions" role="tab" data-toggle="tab">My Actions</a>
   </li>
   <li class="nav-item">
     <a class="nav-link" href="#mentions" role="tab" data-toggle="tab">My Mentions</a>
@@ -29,8 +28,9 @@
       <div class="row">
         <div class="col-sm-8 pull-left">
           {% include "includes/_searchstream.html" %}
+          <br/>
           <div class="alert alert-warning" role="alert">
-            This stream is filtered. <a href="#">View Filters</a>
+            This stream is filtered. <a href="https://apps.fedoraproject.org/notifications/{{hub.name}}.id.fedoraproject.org/">View Filters</a>
           </div>
           <div id="streamFeed"></div>
         </div>
@@ -45,8 +45,9 @@
     <div class="container">
       <div class="row">
         {% include "includes/_searchstream.html" %}
+        <br/>
         <div class="alert alert-warning" role="alert">
-          This stream is filtered. <a href="#">View Filters</a>
+          This stream is filtered. <a href="https://apps.fedoraproject.org/notifications/{{hub.name}}.id.fedoraproject.org/">View Filters</a>
         </div>
         <div class="col-sm-8 pull-left">
           <div id="actionsFeed"></div>
@@ -92,6 +93,9 @@
  .jumbotron {
    margin-bottom: 0;
  }
+ .nav-tabs {
+   list-style: none;
+ }
 </style>
 {% endblock %}
 

From b18c6c451b9f7491435fa1d3fa9231248bff662e Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 616/1001] Fix failing test, add on dropdown for feed nodes


---

diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
index 7342f58..e9b585e 100644
--- a/hubs/static/client/app/components/Markup.jsx
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -1,6 +1,5 @@
 import React from 'react';
-import SaveNotificationButton from './SaveNotificationButton.jsx';
-
+import Dropdown from './Dropdown.jsx';
 import TimeAgo from 'react-timeago';
 
 
@@ -11,15 +10,6 @@ export default class Markup extends React.Component {
   render() {
     const timestamp = this.props.date_time ? (<TimeAgo date={this.props.match.date_time} />) : null;
 
-
-    let saveBtn;
-    if (!this.props.match.saved && this.props.saveUrl) {
-      saveBtn = (
-        <SaveNotificationButton
-          match={this.props.match}
-          saveUrl={this.props.saveUrl}
-        />);
-    }
     return (
       <div className="media-body">
         <h4
@@ -28,7 +18,10 @@ export default class Markup extends React.Component {
         >
         </h4>
         {timestamp}
-        {saveBtn}
+        <Dropdown
+          match={this.props.match}
+          saveUrl={this.props.saveUrl}
+        />
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/SaveNotificationButton.jsx b/hubs/static/client/app/components/SaveNotificationButton.jsx
deleted file mode 100644
index 2b82d78..0000000
--- a/hubs/static/client/app/components/SaveNotificationButton.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react';
-
-const SaveNotificationButton = function (props) {
-  const payload = {
-    link: props.match.link,
-    markup: props.match.markup,
-    secondary_icon: props.match.secondary_icon,
-    dom_id: props.match.dom_id,
-  };
-
-  function onClick(data) {
-    $.ajax({
-      type: 'POST',
-      url: props.saveUrl,
-      data: JSON.stringify(data),
-      contentType: 'application/json',
-    }).done(() => {
-      const id = '#save' + props.match.dom_id;
-      const $saveBtn = $(id);
-      $saveBtn.removeClass('btn-default').addClass('btn-success').text('SAVED');
-    });
-  }
-  return (
-    <button
-      id={'save' + props.match.dom_id}
-      onClick={onClick.bind(this, payload)}
-      className="btn btn-sm btn-default"
-    >
-      SAVE
-    </button>
-  );
-};
-
-export default SaveNotificationButton;

From e786bc3a52717f84758c6067f54aa596afeb90ca Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 617/1001] Readability, README, and comment improvements


* Update README to clarify that stream needs the feed setup
* Move stream code to its own class
* Add in Dropdown.jsx
* Explain the save tagging loop
* Adjust to removal of feed.py code from #237.

---

diff --git a/README.rst b/README.rst
index 6c1b4f4..8b80f92 100644
--- a/README.rst
+++ b/README.rst
@@ -138,10 +138,10 @@ contents like this::
 Make sure to leave the '' around you username and password - don't delete them! Some widgets will work without the above info being present..
 but it is needed for a subset of them.
 
-Feed Widget - the Extra Mile
-----------------------------
+Feed Widget and My Stream - the Extra Mile
+------------------------------------------
 
-One widget (the big tamale -- the feed widget) requires more legwork to stand
+One widget (the big tamale -- the feed widget) and the My Stream page require more legwork to stand
 up.  If you just want to see how hubs works and you want to hack on other
 peripheral stuff around it, you don't need to bother with these steps.
 
diff --git a/hubs/app.py b/hubs/app.py
index 925f3a3..cc32021 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -4,20 +4,16 @@ import json
 import logging
 import os
 import urlparse
-import uuid
 
 import flask
 import flask.json
-import fmn.lib
 import munch
-import pygments.formatters
-import six
 
 from flask.ext.oidc import OpenIDConnect
 
-import fmn.lib
 import hubs.models
 import hubs.widgets
+import hubs.stream
 
 import datanommer.models
 
@@ -50,7 +46,6 @@ import fedmsg.meta
 
 fedmsg_config = fedmsg.config.load_config()
 fedmsg.meta.make_processors(**fedmsg_config)
-paths = fmn.lib.load_rules(root='fmn.rules')
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 datanommer.models.init(fedmsg_config['datanommer.sqlalchemy.uri'])
@@ -520,31 +515,6 @@ def login_required(function):
 
     return decorated_function
 
-def apply_html(actions):
-    # Smash multiple messages into single ones
-    actions = fedmsg.meta.conglomerate(actions, lexers=True, **fedmsg_config)
-
-    # Apply some html markup to the subtitles for extra fanciness.
-    for match in actions:
-        match['markup'] = hubs.widgets.feed.apply_markup(match)
-        for idx, constituent in match['msg_ids'].items():
-            constituent['markup'] = hubs.widgets.feed.apply_markup(constituent)
-            if constituent['long_form'] != constituent['subtitle']:
-                if constituent.get('lexer'):
-                    constituent['long_form'] = pygments.highlight(
-                        constituent['long_form'],
-                        constituent['lexer'],
-                        pygments.formatters.HtmlFormatter(style='monokai'),
-                    )
-                else:
-                    markup = u"<h5>{long_form}</h5>".format(**constituent)
-                    constituent['long_form'] = markup
-        # And tack on a unique identifier for each top level entry.
-        match['dom_id'] = six.text_type(uuid.uuid4())
-
-    return actions
-
-
 @app.route('/<name>/stream')
 @app.route('/<name>/stream/')
 @login_required
@@ -553,67 +523,17 @@ def stream(name):
     saved = hubs.models.SavedNotification.by_username(session, name)
     saved = [n.__json__() for n in saved]
 
-    preference = {
-        'filters': [{
-            'created_on': 'Thu, 15 Jan 2015 16:07:43 GMT',
-            'id': 20506,
-            'name': 'Events referring to my username',
-            'oneshot': None,
-            'rules': [
-                {
-                    'arguments': {
-                        'fasnick': name
-                    },
-                    'cache_key': '2f59dcddf85cab5822af8d40d82c7390ce0f80b40119f2db67f3037a0594a2a1',
-                    'code_path': 'fmn.rules:user_filter',
-                    'created_on': 'Thu, 15 Jan 2015 16:07:43 GMT',
-                    'info': {
-                        'args': [
-                            'config',
-                            'message',
-                            'fasnick'
-                        ],
-                        'datanommer-hints': {},
-                        'doc': "<p>Use this rule to include messages that are associated with a\nspecific user.</p>",
-                        'doc-no-links': '<html><head></head><body><p>Use this rule to include messages that are associated with a\nspecific user.</p>\n</body></html>',
-                        'hints-invertible': True,
-                        'submodule': 'generic',
-                        'title': 'A particular user'
-                    },
-                    'negated': False
-                }]
-        }]
-    }
-    preference = hubs.widgets.feed.rehydrate_preference(preference)
-    messages = []
-    actions = []
-
-    delta = datetime.timedelta(days=365)
-    end = datetime.datetime.utcnow()
-
-    for fmn_filter in preference['filters']:
-        fmn_hinting = fmn.lib.hinting.gather_hinting(fedmsg_config, fmn_filter['rules'], paths)
-        total, pages, rows = datanommer.models.Message.grep(
-            start=end - delta,
-            end=end,
-            rows_per_page=100,
-            page=1,
-            order='desc',
-            **fmn_hinting
-        )
-        messages.extend(rows)
-
-    for message in messages:
-        original = message.__json__()
-        if name in fedmsg.meta.msg2usernames(original, **fedmsg_config):
-            actions.append(original)
+    stream = hubs.stream.Stream(name)
+    actions = stream.get_actions()
 
-    actions = apply_html(actions)
+    # An action that has already been saved should not have a saved button
+    # this tags all the saved actions so the front end can decide to display or not.
+    # This will get slow pretty quickly so we should reevaluate after flock
     for action in actions:
         if any(s['markup'] == action['markup'] for s in saved):
             action['saved'] = True
 
-    actions = json.dumps(actions, cls=hubs.widgets.feed.PythonObjectEncoder)
+    actions = json.dumps(actions, cls=hubs.stream.PythonObjectEncoder)
     return flask.render_template(
         'stream.html',
         hub=hub,
diff --git a/hubs/static/client/app/components/Dropdown.jsx b/hubs/static/client/app/components/Dropdown.jsx
new file mode 100644
index 0000000..57de016
--- /dev/null
+++ b/hubs/static/client/app/components/Dropdown.jsx
@@ -0,0 +1,54 @@
+import React from 'react';
+
+export default class Dropdown extends React.Component {
+  onClick() {
+    const payload = {
+      link: this.props.match.link,
+      markup: this.props.match.markup,
+      secondary_icon: this.props.match.secondary_icon,
+      dom_id: this.props.match.dom_id,
+    };
+
+    $.ajax({
+      type: 'POST',
+      url: this.props.saveUrl,
+      data: JSON.stringify(payload),
+      contentType: 'application/json',
+    }).done(() => {
+      const id = '#save-' + this.props.match.dom_id;
+      const $saveBtn = $(id);
+      $saveBtn.text('Saved');
+    });
+  }
+
+  render() {
+    let saveBtn;
+    if (!this.props.match.saved && this.props.saveUrl) {
+      saveBtn = (
+        <a
+          className="dropdown-item"
+          onClick={this.onClick.bind(this)}
+          href="#"
+        >
+          Save
+        </a>
+      );
+    }
+
+    return (
+      <div className="dropdown pull-sm-right">
+        <span
+          className="dropdown-toggle" type="button"
+          id={'save-' + this.props.match.dom_id}
+          data-toggle="dropdown" aria-haspopup="true"
+          aria-expanded="true"
+        >
+          More
+        </span>
+        <div className="dropdown-menu" aria-labelledby="dropdownMenu2">
+          {saveBtn}
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/hubs/stream.py b/hubs/stream.py
new file mode 100644
index 0000000..2cbcadf
--- /dev/null
+++ b/hubs/stream.py
@@ -0,0 +1,153 @@
+import datetime
+import json
+import uuid
+
+import datanommer.models
+import flask
+import fmn.lib
+import munch
+import pygments.formatters
+import six
+
+import fedmsg.config
+import fedmsg.meta
+
+
+# TODO Temporary: This is a proof of concept for Flock
+# This needs to be done in fnm.lib
+class Stream(object):
+    paths = fmn.lib.load_rules(root='fmn.rules')
+    fedmsg_config = fedmsg.config.load_config()
+    delta = datetime.timedelta(days=365)
+    end = datetime.datetime.utcnow()
+
+    def __init__(self, name):
+        self.name = name
+        self.preference = {
+            'filters': [{
+                'created_on': 'Thu, 15 Jan 2015 16:07:43 GMT',
+                'id': 20506,
+                'name': 'Events referring to my username',
+                'oneshot': None,
+                'rules': [
+                    {
+                        'arguments': {
+                            'fasnick': name
+                        },
+                        'cache_key':
+                        '2f59dcddf85cab5822af8d40d82c7390ce0f80b40119f2db67f3037a0594a2a1',
+                        'code_path': 'fmn.rules:user_filter',
+                        'created_on': 'Thu, 15 Jan 2015 16:07:43 GMT',
+                        'info': {
+                            'args': [
+                                'config', 'message', 'fasnick'
+                            ],
+                            'datanommer-hints': {},
+                            'doc':
+                            "<p>Use this rule to include messages that are associated with a\nspecific user.</p>",
+                            'doc-no-links':
+                            '<html><head></head><body><p>Use this rule to include messages that are associated with a\nspecific user.</p>\n</body></html>',
+                            'hints-invertible': True,
+                            'submodule': 'generic',
+                            'title': 'A particular user'
+                        },
+                        'negated': False
+                    }
+                ]
+            }]
+        }
+
+    def apply_html(self, matches):
+        # Smash multiple messages into single ones
+        matches = fedmsg.meta.conglomerate(matches,
+                                           lexers=True,
+                                           **self.fedmsg_config)
+
+        # Apply some html markup to the subtitles for extra fanciness.
+        for match in matches:
+            match['markup'] = self.apply_markup(match)
+            for idx, constituent in match['msg_ids'].items():
+                constituent['markup'] = self.apply_markup(constituent)
+                if constituent['long_form'] != constituent['subtitle']:
+                    if constituent.get('lexer'):
+                        constituent['long_form'] = pygments.highlight(
+                            constituent['long_form'],
+                            constituent['lexer'],
+                            pygments.formatters.HtmlFormatter(
+                                style='monokai'), )
+                    else:
+                        markup = u"<h5>{long_form}</h5>".format(**constituent)
+                        constituent['long_form'] = markup
+            # And tack on a unique identifier for each top level entry.
+            match['dom_id'] = six.text_type(uuid.uuid4())
+
+        return matches
+
+    def get_actions(self):
+        preference = self.rehydrate_preference(self.preference)
+        messages = []
+        actions = []
+
+        for fmn_filter in preference['filters']:
+            fmn_hinting = fmn.lib.hinting.gather_hinting(
+                self.fedmsg_config, fmn_filter['rules'], self.paths)
+            total, pages, rows = datanommer.models.Message.grep(
+                start=self.end - self.delta,
+                end=self.end,
+                rows_per_page=100,
+                page=1,
+                order='desc',
+                **fmn_hinting)
+            messages.extend(rows)
+
+        for message in messages:
+            original = message.__json__()
+            if self.name in fedmsg.meta.msg2usernames(original, **
+                                                      self.fedmsg_config):
+                actions.append(original)
+
+        return self.apply_html(actions)
+
+    def rehydrate_preference(self, preference):
+        for fltr in preference['filters']:
+            fltr['rules'] = [munch.Munch(r) for r in fltr['rules']]
+            for rule in fltr['rules']:
+                code_path = str(rule.code_path)
+                rule.fn = fedmsg.utils.load_class(code_path)
+
+        return preference
+
+    def apply_markup(self, match):
+        markup = match['subtitle']
+        for username in match['usernames']:
+            args = (username, '<a href="{url}">@{username}</a>'.format(
+                url=flask.url_for('hub', name=username),
+                username=username, ))
+            markup = markup.replace(*args)
+            # TODO -- have to add these to conglomerate first
+            # match['long_form'] = match['long_form'].replace(*args)
+
+        for package in match['packages']:
+            args = (package, '<a href="{url}">{package}</a>'.format(
+                url='https://apps.fedoraproject.org/packages/' + package,
+                package=package, ))
+            markup = markup.replace(*args)
+            # TODO -- have to add these to conglomerate first
+            # match['long_form'] = match['long_form'].replace(*args)
+
+        return markup
+
+
+class PythonObjectEncoder(json.JSONEncoder):
+    ''' A JSON encoder that handles python data structures in encoding'''
+
+    def default(self, obj):
+        if isinstance(obj, (list, dict, str, unicode, int, float, bool,
+                            type(None))):
+            return json.JSONEncoder.default(self, obj)
+        if isinstance(obj, set) or isinstance(obj, tuple):
+            return list(obj)
+        if isinstance(obj, object):
+            return obj.__dict__
+        else:
+            raise TypeError
diff --git a/hubs/templates/includes/_searchstream.html b/hubs/templates/includes/_searchstream.html
index 60b2caf..bac3d5e 100644
--- a/hubs/templates/includes/_searchstream.html
+++ b/hubs/templates/includes/_searchstream.html
@@ -5,3 +5,7 @@
     <span class="oi" data-glyph="magnifying-glass"></span>
   </span>
 </div>
+<br/>
+<div class="alert alert-warning" role="alert">
+  This stream is filtered. <a href="https://apps.fedoraproject.org/notifications/{{hub.name}}.id.fedoraproject.org/" target="_blank">View Filters</a>
+</div>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index eff03f8..b7a3076 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -28,10 +28,6 @@
       <div class="row">
         <div class="col-sm-8 pull-left">
           {% include "includes/_searchstream.html" %}
-          <br/>
-          <div class="alert alert-warning" role="alert">
-            This stream is filtered. <a href="https://apps.fedoraproject.org/notifications/{{hub.name}}.id.fedoraproject.org/">View Filters</a>
-          </div>
           <div id="streamFeed"></div>
         </div>
         <div class="col-sm-4">
@@ -45,10 +41,6 @@
     <div class="container">
       <div class="row">
         {% include "includes/_searchstream.html" %}
-        <br/>
-        <div class="alert alert-warning" role="alert">
-          This stream is filtered. <a href="https://apps.fedoraproject.org/notifications/{{hub.name}}.id.fedoraproject.org/">View Filters</a>
-        </div>
         <div class="col-sm-8 pull-left">
           <div id="actionsFeed"></div>
         </div>

From 7c0aaeac4f9c2c91211c04a823a926f4c96710b5 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 618/1001] Update README regarding Stream and Feed setup


---

diff --git a/README.rst b/README.rst
index 8b80f92..a7d2910 100644
--- a/README.rst
+++ b/README.rst
@@ -138,14 +138,27 @@ contents like this::
 Make sure to leave the '' around you username and password - don't delete them! Some widgets will work without the above info being present..
 but it is needed for a subset of them.
 
-Feed Widget and My Stream - the Extra Mile
+JavaScript assets
+--------------
+
+Some widgets and pages run on React so to install those dependencies::
+
+    $ cd hubs/static/client && npm install
+
+For the Feed and My Stream, change the ``SSE_URL`` location in the ``config`` you created
+to point to the streaming server then build JavaScript assets. Add ``--w`` for live reloading::
+
+    $ cd hubs/static/client && node_modules/.bin/webpack
+
+
+My Stream - the Extra Mile
 ------------------------------------------
 
-One widget (the big tamale -- the feed widget) and the My Stream page require more legwork to stand
-up.  If you just want to see how hubs works and you want to hack on other
+One portion of Hubs - the My Stream page - requires more legwork to stand up.
+If you just want to see how hubs works and you want to hack on other
 peripheral stuff around it, you don't need to bother with these steps.
 
-The feed widget requires a direct DB connection to the datanommer
+The stream requires a direct DB connection to the datanommer
 database; it can't proxy through datagrepper because it needs more
 flexibility.  To get this working, you're going to set up:
 
@@ -156,10 +169,6 @@ Start with some required packages::
 
     $ sudo dnf install postgresql-server python-datanommer-consumer datanommer-commands fedmsg-hub npm
 
-The Feed Widget runs on React so install those dependencies too::
-
-    $ cd hubs/static/client && npm install
-
 And there are some support libraries you'll also need::
 
     $ sudo dnf install python-psycopg2 python-fedmsg-meta-fedora-infrastructure
@@ -217,19 +226,14 @@ will just grow and grow over time::
     [2015-07-01 14:33:21][    fedmsg    INFO] copr has 6 entries
     [2015-07-01 14:33:21][    fedmsg    INFO] askbot has 2 entries
 
-Change the ``SSE_URL`` location in ``default_config.py`` to point to the
-streaming server then build JavaScript assets. Add ``--w`` for live reloading::
-
-    $ cd hubs/static/client && node_modules/.bin/webpack
-
 **Lastly**, (fingers crossed) start up the fedora-hubs webapp and load your
 profile page. Change back to the project root and run::
 
   $ python runserver.py -c config
 
 Once there are some messages that get into your local database
-that *should* show up on your feed.. they should appear there.  (At very least,
-you shouldn't get an error message about that widget being unable to be
+that *should* show up on your page. they should appear there.  (At very least,
+you shouldn't get an error message about that page being unable to be
 displayed).
 
 Stubbing out a new Widget

From 284a58468a38bafcda227aeb9897c2da98d14c19 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 619/1001] Escape html in fedmsgs and remove More dropdown


* Update saved when changing to that tab

---

diff --git a/hubs/static/client/app/components/Dropdown.jsx b/hubs/static/client/app/components/Dropdown.jsx
index 57de016..47511f7 100644
--- a/hubs/static/client/app/components/Dropdown.jsx
+++ b/hubs/static/client/app/components/Dropdown.jsx
@@ -15,8 +15,9 @@ export default class Dropdown extends React.Component {
       data: JSON.stringify(payload),
       contentType: 'application/json',
     }).done(() => {
-      const id = '#save-' + this.props.match.dom_id;
+      const id = `#save-${this.props.match.dom_id}`;
       const $saveBtn = $(id);
+      $saveBtn.removeClass('btn-primary').addClass('btn-success');
       $saveBtn.text('Saved');
     });
   }
@@ -25,29 +26,20 @@ export default class Dropdown extends React.Component {
     let saveBtn;
     if (!this.props.match.saved && this.props.saveUrl) {
       saveBtn = (
-        <a
-          className="dropdown-item"
+        <button
+          id={`save-${this.props.match.dom_id}`}
+          className="btn btn-sm btn-primary"
           onClick={this.onClick.bind(this)}
           href="#"
         >
           Save
-        </a>
+        </button>
       );
     }
 
     return (
-      <div className="dropdown pull-sm-right">
-        <span
-          className="dropdown-toggle" type="button"
-          id={'save-' + this.props.match.dom_id}
-          data-toggle="dropdown" aria-haspopup="true"
-          aria-expanded="true"
-        >
-          More
-        </span>
-        <div className="dropdown-menu" aria-labelledby="dropdownMenu2">
-          {saveBtn}
-        </div>
+      <div className="pull-right">
+       {saveBtn}
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index 4562dcd..4d6c9d2 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { render } from 'react-dom';
+import ReactDOM from 'react-dom';
 
 import Panel from './Panel.jsx';
 
@@ -46,4 +46,4 @@ export default class Feed extends React.Component {
 
 window.Feed = Feed;
 window.React = React;
-window.reactRender = render;
+window.ReactDOM = ReactDOM;
diff --git a/hubs/stream.py b/hubs/stream.py
index 2cbcadf..8c33bf2 100644
--- a/hubs/stream.py
+++ b/hubs/stream.py
@@ -1,3 +1,4 @@
+import cgi
 import datetime
 import json
 import uuid
@@ -100,6 +101,7 @@ class Stream(object):
                 **fmn_hinting)
             messages.extend(rows)
 
+
         for message in messages:
             original = message.__json__()
             if self.name in fedmsg.meta.msg2usernames(original, **
@@ -117,10 +119,21 @@ class Stream(object):
 
         return preference
 
+    def escape_html(self, match):
+        for key in ['subjective', 'subtitle']:
+            match[key] = cgi.escape(match[key])
+        try:
+            match['long_form'] = cgi.escape(match['long_form'])
+        except:
+            # not all matches have a long form
+            pass
+        return match
+
     def apply_markup(self, match):
+        match = self.escape_html(match)
         markup = match['subtitle']
         for username in match['usernames']:
-            args = (username, '<a href="{url}">@{username}</a>'.format(
+            args = (username, '<a href="{url}" rel="nofollow">@{username}</a>'.format(
                 url=flask.url_for('hub', name=username),
                 username=username, ))
             markup = markup.replace(*args)
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index b7a3076..585d71b 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -135,15 +135,29 @@
    /* Right now, stream and actions are the same.
     * Once, Mentions is implemented, then each will be its own
     */
-   reactRender(streamFeed, document.getElementById('streamFeed'));
-   reactRender(streamFeed, document.getElementById('actionsFeed'));
+   ReactDOM.render(streamFeed, document.getElementById('streamFeed'));
+   ReactDOM.render(streamFeed, document.getElementById('actionsFeed'));
 
    var savedFeed = React.createElement(Feed, {
      matches: {{saved|safe}},
      url: false,
      messageLimit: 100
    });
-   reactRender(savedFeed, document.getElementById('savedFeed'));
+   ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
+   $('a[href="#saved"]').on('shown.bs.tab', function(){
+     $.get('/{{hub.name}}/notifications/').done(function(resp) {
+       var saved = {{saved|safe}};
+       if (resp.length != saved.length) {
+         ReactDOM.unmountComponentAtNode(document.getElementById('savedFeed'));
+         var savedFeed = React.createElement(Feed, {
+           matches: resp,
+           url: false,
+           messageLimit: 100
+         });
+         ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
+       }
+     });
+   });
  }
 </script>
 {% endblock %}
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index 755bec9..bba1c31 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -10,6 +10,6 @@
      url: '{{ feed_url }}',
      messageLimit: {{ message_limit }}
    });
-   reactRender(FeedElement, document.getElementById('feed'));
+   ReactDOM.render(FeedElement, document.getElementById('feed'));
  })();
 </script>

From 3c508ef47051556e1890702d508cfbb0ddc9c37c Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 620/1001] Add DELETE for saved notifications


* Fix open-iconic icon -> font awesome

---

diff --git a/hubs/app.py b/hubs/app.py
index cc32021..ff9cb3a 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -576,6 +576,17 @@ def notifications(user):
             dict(notification=notification.__json__(), success=True)
         )
 
+@app.route('/<user>/notifications/<idx>', methods=['DELETE'])
+@app.route('/<user>/notifications/<idx>/', methods=['DELETE'])
+@login_required
+def delete_notifications(user, idx):
+    notification = session.query(hubs.models.SavedNotification).filter_by(idx=idx).first()
+    if not notification:
+        return flask.abort(400)
+    session.delete(notification)
+    session.commit()
+    return flask.jsonify(dict(status_code=200))
+
 @app.before_request
 def check_auth():
     flask.session.permanent = True
diff --git a/hubs/static/client/app/components/Dropdown.jsx b/hubs/static/client/app/components/Dropdown.jsx
index 47511f7..ae1872c 100644
--- a/hubs/static/client/app/components/Dropdown.jsx
+++ b/hubs/static/client/app/components/Dropdown.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 
 export default class Dropdown extends React.Component {
-  onClick() {
+  save() {
     const payload = {
       link: this.props.match.link,
       markup: this.props.match.markup,
@@ -11,7 +11,7 @@ export default class Dropdown extends React.Component {
 
     $.ajax({
       type: 'POST',
-      url: this.props.saveUrl,
+      url: this.props.options.saveUrl,
       data: JSON.stringify(payload),
       contentType: 'application/json',
     }).done(() => {
@@ -22,24 +22,49 @@ export default class Dropdown extends React.Component {
     });
   }
 
+  delete() {
+    $.ajax({
+      type: 'DELETE',
+      url: `${this.props.options.saveUrl}${this.props.match.idx}/`,
+    }).done((resp) => {
+      if (resp.status_code === 200) {
+        const $notification = $(`#${this.props.match.dom_id}`);
+        $notification.closest('.card-block').remove();
+      }
+    });
+  }
+
   render() {
     let saveBtn;
-    if (!this.props.match.saved && this.props.saveUrl) {
+    if (!this.props.match.saved && this.props.options.saveUrl) {
       saveBtn = (
         <button
           id={`save-${this.props.match.dom_id}`}
           className="btn btn-sm btn-primary"
-          onClick={this.onClick.bind(this)}
+          onClick={this.save.bind(this)}
           href="#"
         >
           Save
         </button>
       );
     }
+    let deleteBtn;
+    if (this.props.options.delete && this.props.options.saveUrl) {
+      deleteBtn = (
+        <button
+          id={`delete-${this.props.match.dom_id}`}
+          className="btn btn-sm btn-danger"
+          onClick={this.delete.bind(this)}
+        >
+          Remove
+        </button>
+      );
+    }
 
     return (
       <div className="pull-right">
        {saveBtn}
+        {deleteBtn}
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index 4d6c9d2..eae102a 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -8,7 +8,7 @@ export default class Feed extends React.Component {
     super(props);
     this.state = {
       matches: this.props.matches,
-      messageLimit: this.props.messageLimit,
+      messageLimit: this.props.options.messageLimit,
       sse: true,
     };
     // If it wasn't instantiated with a url or an error happened, bail
@@ -33,8 +33,7 @@ export default class Feed extends React.Component {
   }
   render() {
     const feedNodes = this.state.matches.map((match, idx) => {
-      const saveUrl = this.props.saveUrl || null;
-      return <Panel match={match} saveUrl={saveUrl} key={idx} />;
+      return <Panel match={match} options={this.props.options || {}} key={idx} />;
     });
     return (
       <div>
diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
index e9b585e..437550e 100644
--- a/hubs/static/client/app/components/Markup.jsx
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -20,7 +20,7 @@ export default class Markup extends React.Component {
         {timestamp}
         <Dropdown
           match={this.props.match}
-          saveUrl={this.props.saveUrl}
+          options={this.props.options}
         />
       </div>
     );
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
index 0cd9bdf..c443155 100644
--- a/hubs/static/client/app/components/Panel.jsx
+++ b/hubs/static/client/app/components/Panel.jsx
@@ -6,9 +6,9 @@ import Markup from './Markup.jsx';
 const Panel = function (props) {
   return (
     <div className="card">
-      <div className="card-block">
+      <div className="card-block" id={props.match.dom_id}>
         <Icon match={props.match} />
-        <Markup match={props.match} saveUrl={props.saveUrl} />
+        <Markup options={props.options} match={props.match} />
       </div>
     </div>
   );
diff --git a/hubs/templates/includes/_searchstream.html b/hubs/templates/includes/_searchstream.html
index bac3d5e..3bfc7c1 100644
--- a/hubs/templates/includes/_searchstream.html
+++ b/hubs/templates/includes/_searchstream.html
@@ -2,7 +2,7 @@
 <div class="input-group">
   <input type="search" class="form-control" placeholder="Search this activity stream..." aria-describedby="searchform-addon"></input>
   <span class="input-group-addon" id="searchform-addon">
-    <span class="oi" data-glyph="magnifying-glass"></span>
+    <span><i class="fa fa-search" aria-hidden="true"></i></span>
   </span>
 </div>
 <br/>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 585d71b..5e6fc57 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -126,11 +126,16 @@
 
  function setup_feeds() {
    var actions = {{actions|safe}};
+   var options = {
+
+   }
 
    var streamFeed = React.createElement(Feed, {
      matches: actions,
-     saveUrl: '/{{hub.name}}/notifications/',
-     messageLimit: 100
+     options: {
+       saveUrl: '/{{hub.name}}/notifications/',
+       messageLimit: 100
+     }
    });
    /* Right now, stream and actions are the same.
     * Once, Mentions is implemented, then each will be its own
@@ -141,7 +146,11 @@
    var savedFeed = React.createElement(Feed, {
      matches: {{saved|safe}},
      url: false,
-     messageLimit: 100
+     options: {
+       messageLimit: 100,
+       delete: true,
+       saveUrl: '/{{hub.name}}/notifications/'
+     }
    });
    ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
    $('a[href="#saved"]').on('shown.bs.tab', function(){
@@ -152,7 +161,11 @@
          var savedFeed = React.createElement(Feed, {
            matches: resp,
            url: false,
-           messageLimit: 100
+           options: {
+             messageLimit: 100,
+             delete: true,
+             saveUrl: '/{{hub.name}}/notifications/'
+           }
          });
          ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
        }
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index ea8616f..6706031 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -82,3 +82,40 @@ class TestPostNotifications(hubs.tests.APPTest):
                             for s in all_saved))
         self.assertTrue(any(str(s['link']) == self.valid_payload['link']
                             for s in all_saved))
+
+
+class TestDeleteNotifications(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('ralph')
+    notification = hubs.models.SavedNotification(
+        username='ralph',
+        markup='foo',
+        link='bar',
+        secondary_icon='baz',
+        dom_id='qux'
+    )
+
+    def test_delete_notification(self):
+        self.session.add(self.notification)
+        self.session.commit()
+        idx = self.notification.idx
+
+        self.assertIsNotNone(self.notification)
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.delete(
+                '/{}/notifications/{}/'.format(self.user.username, idx)
+            )
+
+        self.assertEqual(resp.status_code, 200)
+        notification = self.session.query(
+            hubs.models.SavedNotification).filter_by(idx=idx).first()
+
+        self.assertIsNone(notification)
+
+    def test_400_on_bad_idx(self):
+        idx = 'thisisastringnotanint'
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.delete(
+                '/{}/notifications/{}/'.format(self.user.username, idx)
+            )
+        self.assertEqual(resp.status_code, 400)

From 962805ef2f7577981b50c9fda6f0eac07c6c0ad3 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 621/1001] Fix bugs created by refactoring Feed js


- Make sure to check props.options now.
- Fix typo in checking date_time

---

diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
index 437550e..92c2c50 100644
--- a/hubs/static/client/app/components/Markup.jsx
+++ b/hubs/static/client/app/components/Markup.jsx
@@ -8,7 +8,7 @@ export default class Markup extends React.Component {
     return { __html: this.props.match.markup };
   }
   render() {
-    const timestamp = this.props.date_time ? (<TimeAgo date={this.props.match.date_time} />) : null;
+    const timestamp = this.props.match.date_time ? (<TimeAgo date={this.props.match.date_time} />) : null;
 
     return (
       <div className="media-body">
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index bba1c31..aeed666 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -8,7 +8,9 @@
    const FeedElement = React.createElement(Feed, {
      matches: {{ matches }},
      url: '{{ feed_url }}',
-     messageLimit: {{ message_limit }}
+     options: {
+       messageLimit: {{ message_limit }}
+     }
    });
    ReactDOM.render(FeedElement, document.getElementById('feed'));
  })();

From d1ced5f00c7c3746dd75ef992bd726aed84c5f12 Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:35:20 +0000
Subject: [PATCH 622/1001] Modify stream.py to fake JSON messages


- Since the Flock demo is done, it decreases complexity to pass JSON
objects until stream functionality can be added in fmn.

---

diff --git a/hubs/actions.json b/hubs/actions.json
new file mode 100644
index 0000000..e174333
--- /dev/null
+++ b/hubs/actions.json
@@ -0,0 +1,2446 @@
+[{
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#245: \"Mockup for web IRC chat interface for waartaa\"",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "in 3 hours",
+    "subtitle": "atelic commented on ticket fedora-hubs#245: \"Mockup for web IRC chat interface for waartaa\"",
+    "timestamp": 1470681231,
+    "start_time": 1470681231,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic commented on ticket fedora-hubs#245: \"Mockup for web IRC chat interface for waartaa\"",
+    "dom_id": "dd5e0f8b-d263-42fd-9923-bdbbcba8b2fa",
+    "msg_ids": {
+        "2016-9baa7dab-d34c-4485-84b2-6d1187608c28": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on ticket fedora-hubs#245: \"Mockup for web IRC chat interface for waartaa\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on ticket fedora-hubs#245: \"Mockup for web IRC chat interface for waartaa\"",
+            "long_form": "atelic commented on ticket fedora-hubs#245: \"Mockup for web IRC chat interface for waartaa\"",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/245"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/245#comment-3926",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#245: \"Mockup for web IRC chat interface for waartaa\"",
+            "lexer": null
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/issue/245#comment-3926",
+    "end_time": 1470681231,
+    "packages": [],
+    "topics": [
+        "io.pagure.prod.pagure.issue.comment.added"
+    ],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png"
+}, {
+    "subtitle": "atelic interacted with issue #154 of project \"fedora-hubs\" 3 times",
+    "timestamp": 1470679960,
+    "start_time": 1470679956,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with issue #154 of project \"fedora-hubs\" 3 times",
+    "msg_ids": {
+        "2016-01d790b6-a5f3-452d-8224-29df39704467": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on ticket fedora-hubs#154: \"Small amount of horizontal scroll\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on ticket fedora-hubs#154: \"Small amount of horizontal scroll\"",
+            "long_form": "atelic commented on ticket fedora-hubs#154: \"Small amount of horizontal scroll\"",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/154"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/154#comment-3924",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#154: \"Small amount of horizontal scroll\""
+        },
+        "2016-2f10418b-3cbf-4bd3-b28c-2ca0c759b2d8": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic set the status of ticket fedora-hubs#154 to: Fixed",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic set the status of ticket fedora-hubs#154 to: Fixed",
+            "long_form": "atelic set the status of ticket fedora-hubs#154 to: Fixed",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/154"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/154",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.edit",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> set the status of ticket fedora-hubs#154 to: Fixed"
+        },
+        "2016-4e164500-62ba-43ab-9195-99c58c98f7fa": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on ticket fedora-hubs#154: \"Small amount of horizontal scroll\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on ticket fedora-hubs#154: \"Small amount of horizontal scroll\"",
+            "long_form": "atelic commented on ticket fedora-hubs#154: \"Small amount of horizontal scroll\"",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/154"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/154#comment-3925",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#154: \"Small amount of horizontal scroll\""
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/issue/154",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with issue #154 of project \"fedora-hubs\" 3 times",
+    "dom_id": "91f1d5ec-e373-4de0-b4c1-4c9266df2f2a",
+    "end_time": 1470679962,
+    "human_time": "in 3 hours",
+    "topics": [
+        "io.pagure.prod.pagure.issue.edit",
+        "io.pagure.prod.pagure.issue.comment.added"
+    ]
+}, {
+    "subtitle": "atelic interacted with issue #171 of project \"fedora-hubs\" 4 times",
+    "timestamp": 1470679257.25,
+    "start_time": 1470679253,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with issue #171 of project \"fedora-hubs\" 4 times",
+    "msg_ids": {
+        "2016-30d12db3-bc4a-4fd5-914d-0a567c8574f3": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on ticket fedora-hubs#171: \"Make a decision on JS framework\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on ticket fedora-hubs#171: \"Make a decision on JS framework\"",
+            "long_form": "atelic commented on ticket fedora-hubs#171: \"Make a decision on JS framework\"",
+            "objects": [
+                "issue/171",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/171#comment-3923",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#171: \"Make a decision on JS framework\""
+        },
+        "2016-d4643f66-6944-43f5-8f62-731f18f5470b": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic edited the priority fields of ticket fedora-hubs#171",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic edited the priority fields of ticket fedora-hubs#171",
+            "long_form": "atelic edited the priority fields of ticket fedora-hubs#171",
+            "objects": [
+                "issue/171",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/171",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.edit",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> edited the priority fields of ticket fedora-hubs#171"
+        },
+        "2016-4aefc797-5521-481d-9ee3-90edf036b3a2": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on ticket fedora-hubs#171: \"Make a decision on JS framework\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on ticket fedora-hubs#171: \"Make a decision on JS framework\"",
+            "long_form": "atelic commented on ticket fedora-hubs#171: \"Make a decision on JS framework\"",
+            "objects": [
+                "issue/171",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/171#comment-3922",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#171: \"Make a decision on JS framework\""
+        },
+        "2016-a81dcaa0-77b6-44f3-9ae5-c710c2ee540d": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic set the status of ticket fedora-hubs#171 to: Fixed",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic set the status of ticket fedora-hubs#171 to: Fixed",
+            "long_form": "atelic set the status of ticket fedora-hubs#171 to: Fixed",
+            "objects": [
+                "issue/171",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/171",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.edit",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> set the status of ticket fedora-hubs#171 to: Fixed"
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/issue/171",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with issue #171 of project \"fedora-hubs\" 4 times",
+    "dom_id": "c3484845-2fd0-4019-a6a0-7f2f7a931011",
+    "end_time": 1470679261,
+    "human_time": "in 3 hours",
+    "topics": [
+        "io.pagure.prod.pagure.issue.edit",
+        "io.pagure.prod.pagure.issue.comment.added"
+    ]
+}, {
+    "subtitle": "atelic interacted with issue #234 of project \"fedora-hubs\" 3 times",
+    "timestamp": 1470678655,
+    "start_time": 1470678643,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with issue #234 of project \"fedora-hubs\" 3 times",
+    "msg_ids": {
+        "2016-636f4fb2-9378-4181-8d3b-c0566e3171e1": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on ticket fedora-hubs#234: \"Subscribers widget has floating dot and subscribe button\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on ticket fedora-hubs#234: \"Subscribers widget has floating dot and subscribe button\"",
+            "long_form": "atelic commented on ticket fedora-hubs#234: \"Subscribers widget has floating dot and subscribe button\"",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/234"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/234#comment-3921",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#234: \"Subscribers widget has floating dot and subscribe button\""
+        },
+        "2016-1cb62ec3-9e49-4d07-bb27-ee7255c20115": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic set the status of ticket fedora-hubs#234 to: Fixed",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic set the status of ticket fedora-hubs#234 to: Fixed",
+            "long_form": "atelic set the status of ticket fedora-hubs#234 to: Fixed",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/234"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/234",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.edit",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> set the status of ticket fedora-hubs#234 to: Fixed"
+        },
+        "2016-98893984-1624-4142-a890-2791e52f5aad": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on ticket fedora-hubs#234: \"Subscribers widget has floating dot and subscribe button\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on ticket fedora-hubs#234: \"Subscribers widget has floating dot and subscribe button\"",
+            "long_form": "atelic commented on ticket fedora-hubs#234: \"Subscribers widget has floating dot and subscribe button\"",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/234"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/234#comment-3920",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#234: \"Subscribers widget has floating dot and subscribe button\""
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/issue/234",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with issue #234 of project \"fedora-hubs\" 3 times",
+    "dom_id": "5bfbc86e-3167-4aad-b43e-8714c8669f8d",
+    "end_time": 1470678661,
+    "human_time": "in 3 hours",
+    "topics": [
+        "io.pagure.prod.pagure.issue.edit",
+        "io.pagure.prod.pagure.issue.comment.added"
+    ]
+}, {
+    "subtitle": "atelic interacted with pull-request #239 of project \"fedora-hubs\" 7 times",
+    "timestamp": 1470356286.142857,
+    "start_time": 1470263110,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with pull-request #239 of project \"fedora-hubs\" 7 times",
+    "msg_ids": {
+        "2016-d3a27251-f4a6-4ce9-8b04-15d4f930cf50": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic opened pull-request#239: \"Add tests for React front end\" on project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic opened pull-request#239: \"Add tests for React front end\" on project \"fedora-hubs\"",
+            "long_form": "atelic opened pull-request#239: \"Add tests for React front end\" on project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/239"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/239",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.new",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened pull-request#239: \"Add tests for React front end\" on project \"fedora-hubs\""
+        },
+        "2016-22379cd4-6375-4720-b62d-3b9e05b9b100": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/239"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/239#comment-8241",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#239 of project \"fedora-hubs\""
+        },
+        "2016-857d6d95-0a12-4f45-9ca3-755a9733534c": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/239"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/239#comment-8181",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#239 of project \"fedora-hubs\""
+        },
+        "2016-682cbdb7-e4d2-43da-9cc1-67e439809b02": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/239"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/239#comment-8202",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#239 of project \"fedora-hubs\""
+        },
+        "2016-9361ad7c-f696-4470-8f96-a93d9387c162": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/239"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/239#comment-8253",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#239 of project \"fedora-hubs\""
+        },
+        "2016-0e6ec94c-763c-4864-a150-07e96eeeac32": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/239"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/239#comment-8227",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#239 of project \"fedora-hubs\""
+        },
+        "2016-d9877a21-df96-49a6-a440-9c2d8e5844bb": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#239 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/239"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/239#comment-8251",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#239 of project \"fedora-hubs\""
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/pull-request/239",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with pull-request #239 of project \"fedora-hubs\" 7 times",
+    "dom_id": "e062ee4b-8757-4e8c-ad50-cf2355a5e366",
+    "end_time": 1470431562,
+    "human_time": "3 days ago",
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added",
+        "io.pagure.prod.pagure.pull-request.new"
+    ]
+}, {
+    "subtitle": "atelic interacted with pull-request #231 of project \"fedora-hubs\" 17 times",
+    "timestamp": 1470174598.9411764,
+    "start_time": 1469837470,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with pull-request #231 of project \"fedora-hubs\" 17 times",
+    "msg_ids": {
+        "2016-8b0221db-e924-4c90-aab1-6d0d79534470": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8136",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-f8a4f5ba-26f3-4acf-93bc-63ca9e0dc07d": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8235",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-b4ecafdc-c463-416e-ac8d-db23040a4672": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8130",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-c6023fd0-8424-43f5-be4c-24f582441eea": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8132",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-f42a24d4-db3c-4036-aa53-03df6efd9215": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8252",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-510603d6-8bad-4131-a45a-ad6b475687a0": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8138",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-e63ad5d2-c44f-44d9-80c4-f01910c2385a": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8238",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-a2418776-4589-4041-a3ad-d7f84492d2c6": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8142",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-89d6e37b-9a06-49a3-b1c7-d8bb53c8bbc9": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8139",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-d585ecd3-05e4-479b-bdf2-64fe03270ea0": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8096",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-437f7764-12e2-4c51-bd0b-f6a25c86f782": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8133",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-7ded95aa-b340-4c8b-85d7-8d6bc0d415c9": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8120",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-fa2cb020-eb03-45f7-81b0-a629e2f8dbab": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8121",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-e34c9a7d-89be-488b-8dbe-071199e9196b": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8026",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-87f98c74-dfdb-4261-8536-3a32011f6112": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8140",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-2c743fe3-b0ba-40fc-ac58-9f32a23714b7": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8135",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        },
+        "2016-9fcef2e4-fd16-41c5-b198-824b60dc0dde": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#231 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/231"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/231#comment-8022",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#231 of project \"fedora-hubs\""
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/pull-request/231",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with pull-request #231 of project \"fedora-hubs\" 17 times",
+    "dom_id": "dd953aea-1553-4455-a6af-cc9b2128d357",
+    "end_time": 1470420897,
+    "human_time": "5 days ago",
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added"
+    ]
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#246 of project \"fedora-hubs\"",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "2 days ago",
+    "subtitle": "atelic commented on pull-request#246 of project \"fedora-hubs\"",
+    "timestamp": 1470418821,
+    "start_time": 1470418821,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic commented on pull-request#246 of project \"fedora-hubs\"",
+    "dom_id": "685e8109-f19f-42c6-83df-065ba7378351",
+    "msg_ids": {
+        "2016-92ae6f5c-1f4c-4303-a631-fc5584b51579": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#246 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#246 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#246 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/246"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/246#comment-8244",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#246 of project \"fedora-hubs\"",
+            "lexer": null
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/pull-request/246#comment-8244",
+    "end_time": 1470418821,
+    "packages": [],
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added"
+    ],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#241 of project \"fedora-hubs\"",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "3 days ago",
+    "subtitle": "atelic commented on pull-request#241 of project \"fedora-hubs\"",
+    "timestamp": 1470358933,
+    "start_time": 1470358933,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic commented on pull-request#241 of project \"fedora-hubs\"",
+    "dom_id": "f18a101b-90af-4a20-bca2-bed8ba88e544",
+    "msg_ids": {
+        "2016-6d486c9c-519b-489e-a9dc-27b5b458ceff": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#241 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#241 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#241 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/241"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/241#comment-8219",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#241 of project \"fedora-hubs\"",
+            "lexer": null
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/pull-request/241#comment-8219",
+    "end_time": 1470358933,
+    "packages": [],
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added"
+    ],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png"
+}, {
+    "subtitle": "atelic interacted with pull-request #2 of project \"internexpo\" 5 times",
+    "timestamp": 1470335760.6,
+    "start_time": 1470267969,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with pull-request #2 of project \"internexpo\" 5 times",
+    "msg_ids": {
+        "2016-ac36fb61-3b6a-47f3-97ac-986c17296d26": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#2 of project \"internexpo\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#2 of project \"internexpo\"",
+            "long_form": "atelic commented on pull-request#2 of project \"internexpo\"",
+            "objects": [
+                "pull-request/2",
+                "project/internexpo"
+            ],
+            "link": "https://pagure.io/internexpo/pull-request/2#comment-8210",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#2 of project \"internexpo\""
+        },
+        "2016-3f48dc8b-319c-43be-b37b-a77e2be7b341": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic opened pull-request#2: \"Add code to this repo\" on project \"internexpo\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic opened pull-request#2: \"Add code to this repo\" on project \"internexpo\"",
+            "long_form": "atelic opened pull-request#2: \"Add code to this repo\" on project \"internexpo\"",
+            "objects": [
+                "pull-request/2",
+                "project/internexpo"
+            ],
+            "link": "https://pagure.io/internexpo/pull-request/2",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.new",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened pull-request#2: \"Add code to this repo\" on project \"internexpo\""
+        },
+        "2016-92954af1-b34a-4ca7-9b9a-c2c12143ce19": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#2 of project \"internexpo\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#2 of project \"internexpo\"",
+            "long_form": "atelic commented on pull-request#2 of project \"internexpo\"",
+            "objects": [
+                "pull-request/2",
+                "project/internexpo"
+            ],
+            "link": "https://pagure.io/internexpo/pull-request/2#comment-8214",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#2 of project \"internexpo\""
+        },
+        "2016-c4707879-ac60-4a35-8af0-fa0d9cc94576": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic edited a comment on pull-request#2 of project \"internexpo\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic edited a comment on pull-request#2 of project \"internexpo\"",
+            "long_form": "atelic edited a comment on pull-request#2 of project \"internexpo\"",
+            "objects": [
+                "pull-request/2",
+                "project/internexpo"
+            ],
+            "link": "https://pagure.io/internexpo/pull-request/2#comment-8210",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.edited",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> edited a comment on pull-request#2 of project \"internexpo\""
+        },
+        "2016-1c878b0a-849f-4f97-b501-b4cdf2bbcee0": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#2 of project \"internexpo\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#2 of project \"internexpo\"",
+            "long_form": "atelic commented on pull-request#2 of project \"internexpo\"",
+            "objects": [
+                "pull-request/2",
+                "project/internexpo"
+            ],
+            "link": "https://pagure.io/internexpo/pull-request/2#comment-8211",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#2 of project \"internexpo\""
+        }
+    },
+    "link": "https://pagure.io/internexpo/pull-request/2",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with pull-request #2 of project \"internexpo\" 5 times",
+    "dom_id": "60838fc2-a020-4ef2-803e-6bf35af6170c",
+    "end_time": 1470356477,
+    "human_time": "3 days ago",
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added",
+        "io.pagure.prod.pagure.pull-request.new",
+        "io.pagure.prod.pagure.pull-request.comment.edited"
+    ]
+}, {
+    "subtitle": "atelic interacted with pull-request #240 of project \"fedora-hubs\" 3 times",
+    "timestamp": 1470312049.3333333,
+    "start_time": 1470268764,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with pull-request #240 of project \"fedora-hubs\" 3 times",
+    "msg_ids": {
+        "2016-bc365882-7666-4728-87e0-0413c1d63800": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic opened pull-request#240: \"Stop populate-from-fas.py from crashing on run\" on project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic opened pull-request#240: \"Stop populate-from-fas.py from crashing on run\" on project \"fedora-hubs\"",
+            "long_form": "atelic opened pull-request#240: \"Stop populate-from-fas.py from crashing on run\" on project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/240"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/240",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.new",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened pull-request#240: \"Stop populate-from-fas.py from crashing on run\" on project \"fedora-hubs\""
+        },
+        "2016-783b44a7-80f4-41fe-8676-e577164d7327": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#240 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#240 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#240 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/240"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/240#comment-8185",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#240 of project \"fedora-hubs\""
+        },
+        "2016-8cf4dbea-4fcd-468f-a24a-2dd3ed656e72": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic merged pull-request#240 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic merged pull-request#240 of project \"fedora-hubs\"",
+            "long_form": "atelic merged pull-request#240 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/240"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/240",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.closed",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> merged pull-request#240 of project \"fedora-hubs\""
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/pull-request/240",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with pull-request #240 of project \"fedora-hubs\" 3 times",
+    "dom_id": "d077be97-905b-4b50-bd2e-bb48f5cf4b2b",
+    "end_time": 1470333692,
+    "human_time": "4 days ago",
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.closed",
+        "io.pagure.prod.pagure.pull-request.comment.added",
+        "io.pagure.prod.pagure.pull-request.new"
+    ]
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened a new ticket internexpo#1: \"This repo is empty\"",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "4 days ago",
+    "subtitle": "atelic opened a new ticket internexpo#1: \"This repo is empty\"",
+    "timestamp": 1470267815,
+    "start_time": 1470267815,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic opened a new ticket internexpo#1: \"This repo is empty\"",
+    "dom_id": "32e00222-c13b-4fb7-b06d-64c85aedc937",
+    "msg_ids": {
+        "2016-8b96b2bd-2925-469a-a437-0054d2146c33": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic opened a new ticket internexpo#1: \"This repo is empty\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic opened a new ticket internexpo#1: \"This repo is empty\"",
+            "long_form": "atelic opened a new ticket internexpo#1: \"This repo is empty\"",
+            "objects": [
+                "issue/1",
+                "project/internexpo"
+            ],
+            "link": "https://pagure.io/internexpo/issue/1",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.new",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened a new ticket internexpo#1: \"This repo is empty\"",
+            "lexer": null
+        }
+    },
+    "link": "https://pagure.io/internexpo/issue/1",
+    "end_time": 1470267815,
+    "packages": [],
+    "topics": [
+        "io.pagure.prod.pagure.issue.new"
+    ],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> created a new project \"internexpo\"",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "4 days ago",
+    "subtitle": "atelic created a new project \"internexpo\"",
+    "timestamp": 1470267721,
+    "start_time": 1470267721,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic created a new project \"internexpo\"",
+    "dom_id": "3697fedc-2186-432a-af88-990c9b941ce7",
+    "msg_ids": {
+        "2016-1465dd21-7c2e-4ecb-92f3-de5c70bc8cc1": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic created a new project \"internexpo\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic created a new project \"internexpo\"",
+            "long_form": "atelic created a new project \"internexpo\"",
+            "objects": [
+                "project/internexpo"
+            ],
+            "link": "https://pagure.io/internexpo",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.project.new",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> created a new project \"internexpo\"",
+            "lexer": null
+        }
+    },
+    "link": "https://pagure.io/internexpo",
+    "end_time": 1470267721,
+    "packages": [],
+    "topics": [
+        "io.pagure.prod.pagure.project.new"
+    ],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png"
+}, {
+    "subtitle": "atelic interacted with issue #164 of project \"fedora-hubs\" 3 times",
+    "timestamp": 1470251976,
+    "start_time": 1470251872,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with issue #164 of project \"fedora-hubs\" 3 times",
+    "msg_ids": {
+        "2016-3884c7cb-bf9f-455c-895c-9de153dc9494": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic set the status of ticket fedora-hubs#164 to: Fixed",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic set the status of ticket fedora-hubs#164 to: Fixed",
+            "long_form": "atelic set the status of ticket fedora-hubs#164 to: Fixed",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/164"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/164",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.edit",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> set the status of ticket fedora-hubs#164 to: Fixed"
+        },
+        "2016-a8ef33a1-c1c9-44dd-afaf-ff9fcabb74a2": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on ticket fedora-hubs#164: \"Team Hub Member List Widget\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on ticket fedora-hubs#164: \"Team Hub Member List Widget\"",
+            "long_form": "atelic commented on ticket fedora-hubs#164: \"Team Hub Member List Widget\"",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/164"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/164#comment-3832",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#164: \"Team Hub Member List Widget\""
+        },
+        "2016-da268efb-b7c8-4a75-88a3-369518d9eeee": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on ticket fedora-hubs#164: \"Team Hub Member List Widget\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on ticket fedora-hubs#164: \"Team Hub Member List Widget\"",
+            "long_form": "atelic commented on ticket fedora-hubs#164: \"Team Hub Member List Widget\"",
+            "objects": [
+                "project/fedora-hubs",
+                "issue/164"
+            ],
+            "link": "https://pagure.io/fedora-hubs/issue/164#comment-3834",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on ticket fedora-hubs#164: \"Team Hub Member List Widget\""
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/issue/164",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with issue #164 of project \"fedora-hubs\" 3 times",
+    "dom_id": "7988a9a4-d6a8-4180-9b5b-0f3bc5631fff",
+    "end_time": 1470252028,
+    "human_time": "4 days ago",
+    "topics": [
+        "io.pagure.prod.pagure.issue.edit",
+        "io.pagure.prod.pagure.issue.comment.added"
+    ]
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> gave <a href=\"/abompard/\" rel=\"nofollow\">@abompard</a>(25) a karma cookie in #fedora-hubs.  \"<a href=\"/abompard/\" rel=\"nofollow\">@abompard</a>++\"",
+    "usernames": [
+        "atelic",
+        "abompard"
+    ],
+    "human_time": "4 days ago",
+    "subtitle": "atelic gave abompard(25) a karma cookie in #fedora-hubs.  \"abompard++\"",
+    "timestamp": 1470249514,
+    "start_time": 1470249514,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/f0c54afccefcf4bc888e0d37618a8598602a668e4ffc2e433b551ca19fc164d8?s=64&d=retro",
+    "subjective": "atelic gave abompard(25) a karma cookie in #fedora-hubs.  \"abompard++\"",
+    "dom_id": "d381d76b-d052-4f2b-8a5d-cb46c026ae0e",
+    "msg_ids": {
+        "2016-dea24f20-dd28-45c5-aab4-e96815b41110": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "subtitle": "atelic gave abompard(25) a karma cookie in #fedora-hubs.  \"abompard++\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/f0c54afccefcf4bc888e0d37618a8598602a668e4ffc2e433b551ca19fc164d8?s=64&d=retro",
+            "subjective": "atelic gave abompard(25) a karma cookie in #fedora-hubs.  \"abompard++\"",
+            "long_form": "atelic gave abompard(25) a karma cookie in #fedora-hubs.  \"abompard++\"",
+            "objects": [
+                "karma/abompard"
+            ],
+            "link": "https://badges.fedoraproject.org/user/abompard",
+            "packages": [],
+            "icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "usernames": [
+                "atelic",
+                "abompard"
+            ],
+            "title": "irc.karma",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> gave <a href=\"/abompard/\" rel=\"nofollow\">@abompard</a>(25) a karma cookie in #fedora-hubs.  \"<a href=\"/abompard/\" rel=\"nofollow\">@abompard</a>++\"",
+            "lexer": null
+        }
+    },
+    "link": "https://badges.fedoraproject.org/user/abompard",
+    "end_time": 1470249514,
+    "packages": [],
+    "topics": [
+        "org.fedoraproject.prod.irc.karma"
+    ],
+    "categories": [
+        "irc"
+    ],
+    "icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro"
+}, {
+    "subtitle": "atelic interacted with pull-request #236 of project \"fedora-hubs\" 2 times",
+    "timestamp": 1470162363.5,
+    "start_time": 1470161171,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with pull-request #236 of project \"fedora-hubs\" 2 times",
+    "msg_ids": {
+        "2016-c482de19-046f-4e0a-baf8-db8a1b173b75": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#236 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#236 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#236 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/236"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/236#comment-8114",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#236 of project \"fedora-hubs\""
+        },
+        "2016-bdbb082e-a651-41d6-9be6-7a21a2c9fd23": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#236 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#236 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#236 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/236"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/236#comment-8123",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#236 of project \"fedora-hubs\""
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/pull-request/236",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with pull-request #236 of project \"fedora-hubs\" 2 times",
+    "dom_id": "b4ee44b3-0860-469b-99bf-e2d9ae8be3cf",
+    "end_time": 1470163556,
+    "human_time": "5 days ago",
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added"
+    ]
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened a new ticket <a href=\"/atelic/\" rel=\"nofollow\">@atelic</a>/test#1: \"test &amp; &gt; 1.2 &lt;img src=\"https://pingoured.fr/random\" alt=\"foo\"/&gt; &lt;script&gt; alert('hi')&lt;/script&gt;\"",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "5 days ago",
+    "subtitle": "atelic opened a new ticket atelic/test#1: \"test &amp; &gt; 1.2 &lt;img src=\"https://pingoured.fr/random\" alt=\"foo\"/&gt; &lt;script&gt; alert('hi')&lt;/script&gt;\"",
+    "timestamp": 1470161866,
+    "start_time": 1470161866,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic opened a new ticket atelic/test#1: \"test &amp; &gt; 1.2 &lt;img src=\"https://pingoured.fr/random\" alt=\"foo\"/&gt; &lt;script&gt; alert('hi')&lt;/script&gt;\"",
+    "dom_id": "865a4b73-5b7b-423a-a075-fc41c2faa5cb",
+    "msg_ids": {
+        "2016-95fa6450-e838-40f3-b3fc-8bef1d7637dc": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic opened a new ticket atelic/test#1: \"test &amp; &gt; 1.2 &lt;img src=\"https://pingoured.fr/random\" alt=\"foo\"/&gt; &lt;script&gt; alert('hi')&lt;/script&gt;\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic opened a new ticket atelic/test#1: \"test &amp; &gt; 1.2 &lt;img src=\"https://pingoured.fr/random\" alt=\"foo\"/&gt; &lt;script&gt; alert('hi')&lt;/script&gt;\"",
+            "long_form": "atelic opened a new ticket atelic/test#1: \"test &amp; &gt; 1.2 &lt;img src=\"https://pingoured.fr/random\" alt=\"foo\"/&gt; &lt;script&gt; alert('hi')&lt;/script&gt;\"",
+            "objects": [
+                "issue/1",
+                "project/atelic/test"
+            ],
+            "link": "https://pagure.io/fork/atelic/test/issue/1",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.issue.new",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened a new ticket <a href=\"/atelic/\" rel=\"nofollow\">@atelic</a>/test#1: \"test &amp; &gt; 1.2 &lt;img src=\"https://pingoured.fr/random\" alt=\"foo\"/&gt; &lt;script&gt; alert('hi')&lt;/script&gt;\"",
+            "lexer": null
+        }
+    },
+    "link": "https://pagure.io/fork/atelic/test/issue/1",
+    "end_time": 1470161866,
+    "packages": [],
+    "topics": [
+        "io.pagure.prod.pagure.issue.new"
+    ],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#237 of project \"fedora-hubs\"",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "5 days ago",
+    "subtitle": "atelic commented on pull-request#237 of project \"fedora-hubs\"",
+    "timestamp": 1470160881,
+    "start_time": 1470160881,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic commented on pull-request#237 of project \"fedora-hubs\"",
+    "dom_id": "0d87b48d-4f7d-4ab0-a6b8-1b6112d451c3",
+    "msg_ids": {
+        "2016-fb2099d7-0557-42ae-84e4-bb9ed1b8c320": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#237 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#237 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#237 of project \"fedora-hubs\"",
+            "objects": [
+                "project/fedora-hubs",
+                "pull-request/237"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/237#comment-8110",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#237 of project \"fedora-hubs\"",
+            "lexer": null
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/pull-request/237#comment-8110",
+    "end_time": 1470160881,
+    "packages": [],
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added"
+    ],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> edited the Enforce_signed-off_commits_in_pull-request, Minimum_score_to_merge_pull-request, and 6 others fields of project <a href=\"/atelic/\" rel=\"nofollow\">@atelic</a>/test",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "a month ago",
+    "subtitle": "atelic edited the Enforce_signed-off_commits_in_pull-request, Minimum_score_to_merge_pull-request, and 6 others fields of project atelic/test",
+    "timestamp": 1467917437,
+    "start_time": 1467917437,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic edited the Enforce_signed-off_commits_in_pull-request, Minimum_score_to_merge_pull-request, and 6 others fields of project atelic/test",
+    "dom_id": "2c69bf0c-e6bd-4cb6-afc2-7b5733b8bfdd",
+    "msg_ids": {
+        "2016-c1659952-34fe-463c-ac59-b6dfbbda1359": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic edited the Enforce_signed-off_commits_in_pull-request, Minimum_score_to_merge_pull-request, and 6 others fields of project atelic/test",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic edited the Enforce_signed-off_commits_in_pull-request, Minimum_score_to_merge_pull-request, and 6 others fields of project atelic/test",
+            "long_form": "atelic edited the Enforce_signed-off_commits_in_pull-request, Minimum_score_to_merge_pull-request, and 6 others fields of project atelic/test",
+            "objects": [
+                "project/atelic/test"
+            ],
+            "link": "https://pagure.io/fork/atelic/test",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.project.edit",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> edited the Enforce_signed-off_commits_in_pull-request, Minimum_score_to_merge_pull-request, and 6 others fields of project <a href=\"/atelic/\" rel=\"nofollow\">@atelic</a>/test",
+            "lexer": null
+        }
+    },
+    "link": "https://pagure.io/fork/atelic/test",
+    "end_time": 1467917437,
+    "packages": [],
+    "topics": [
+        "io.pagure.prod.pagure.project.edit"
+    ],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> forked project \"test\" to \"<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a>/test\"",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "a month ago",
+    "subtitle": "atelic forked project \"test\" to \"atelic/test\"",
+    "timestamp": 1467917378,
+    "start_time": 1467917378,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic forked project \"test\" to \"atelic/test\"",
+    "dom_id": "14c16b53-5f1d-4b9c-ad7e-beb5785495b6",
+    "msg_ids": {
+        "2016-4363f65e-705d-4f93-afc4-f675f309af0f": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic forked project \"test\" to \"atelic/test\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic forked project \"test\" to \"atelic/test\"",
+            "long_form": "atelic forked project \"test\" to \"atelic/test\"",
+            "objects": [
+                "project/atelic/test"
+            ],
+            "link": "https://pagure.io/fork/atelic/test",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.project.forked",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> forked project \"test\" to \"<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a>/test\"",
+            "lexer": null
+        }
+    },
+    "link": "https://pagure.io/fork/atelic/test",
+    "end_time": 1467917378,
+    "packages": [],
+    "topics": [
+        "io.pagure.prod.pagure.project.forked"
+    ],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png"
+}, {
+    "subtitle": "atelic interacted with pull-request #1101 of project \"pagure\" 14 times",
+    "timestamp": 1467451273,
+    "start_time": 1467319877,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with pull-request #1101 of project \"pagure\" 14 times",
+    "msg_ids": {
+        "2016-b8a93b19-e3d8-42a6-9aed-f6ebb61fe7e1": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6768",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        },
+        "2016-e913fda8-8488-457f-a6fd-f67a9e930bae": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6762",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        },
+        "2016-fb3f93c0-bcfb-4bfb-97fd-8746ee6b368e": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6863",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        },
+        "2016-bbcd7cf5-21a4-4c4f-8581-33a1b86948ed": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic opened pull-request#1101: \"Add dropdown select for # issue tag\" on project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic opened pull-request#1101: \"Add dropdown select for # issue tag\" on project \"pagure\"",
+            "long_form": "atelic opened pull-request#1101: \"Add dropdown select for # issue tag\" on project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.new",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened pull-request#1101: \"Add dropdown select for # issue tag\" on project \"pagure\""
+        },
+        "2016-4b437ae8-fac6-4f27-97a4-b96bad9a9fea": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6865",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        },
+        "2016-28a959ab-4de4-47b6-87f9-ba785a8d5d89": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic edited a comment on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic edited a comment on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic edited a comment on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6861",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.edited",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> edited a comment on pull-request#1101 of project \"pagure\""
+        },
+        "2016-eb3ccad2-6138-43a6-baf2-950ba7fba070": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6802",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        },
+        "2016-bd253eae-8e04-402a-b977-78097fc58d7b": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6861",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        },
+        "2016-b9769ced-94ad-4e2f-aea3-c0c4b33a8b9c": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6763",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        },
+        "2016-8d7af750-206b-4aa2-9f83-aaae05047564": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6790",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        },
+        "2016-0c38b714-1c1e-4842-a493-eab62a241bcd": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic edited a comment on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic edited a comment on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic edited a comment on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6767",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.edited",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> edited a comment on pull-request#1101 of project \"pagure\""
+        },
+        "2016-d13cf049-13a4-4e6a-ad59-65da3eada965": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6769",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        },
+        "2016-4fbe1729-d38e-480d-b524-a77c0506f546": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic edited a comment on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic edited a comment on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic edited a comment on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6767",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.edited",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> edited a comment on pull-request#1101 of project \"pagure\""
+        },
+        "2016-e9b83f54-31e0-46df-85c0-0d83e6fa0c07": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "long_form": "atelic commented on pull-request#1101 of project \"pagure\"",
+            "objects": [
+                "project/pagure",
+                "pull-request/1101"
+            ],
+            "link": "https://pagure.io/pagure/pull-request/1101#comment-6767",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#1101 of project \"pagure\""
+        }
+    },
+    "link": "https://pagure.io/pagure/pull-request/1101",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with pull-request #1101 of project \"pagure\" 14 times",
+    "dom_id": "ea29ebe1-603b-4dcc-a7ac-8944bb3adc13",
+    "end_time": 1467747435,
+    "human_time": "a month ago",
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added",
+        "io.pagure.prod.pagure.pull-request.new",
+        "io.pagure.prod.pagure.pull-request.comment.edited"
+    ]
+}, {
+    "subtitle": "atelic, devyani7_, and 4 others participated in fedora-hubs in #fedora-hubs",
+    "timestamp": 1467743322.6,
+    "start_time": 1467742586,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/01fe73d687f4db328da1183f2a1b5b22962ca9d9c50f0728aafeac974856311c?s=64&d=retro",
+    "subjective": "atelic, devyani7_, and 4 others participated in fedora-hubs in #fedora-hubs",
+    "msg_ids": {
+        "2016-125dc31b-3c19-40be-beaf-1df93bff1e39": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "subtitle": "pingou's meeting titled \"fedora-hubs\" ended in #fedora-hubs",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/01fe73d687f4db328da1183f2a1b5b22962ca9d9c50f0728aafeac974856311c?s=64&d=retro",
+            "subjective": "pingou's meeting titled \"fedora-hubs\" ended in #fedora-hubs",
+            "long_form": "<h5>=========================\n#fedora-hubs: fedora-hubs\n=========================\n\n\nMeeting started by pingou at 14:12:44 UTC. The full logs are available\nat\nhttps://meetbot.fedoraproject.org/fedora-hubs/2016-07-05/fedora-hubs.2016-07-05-14.12.log.html\n.\n\n\n\nMeeting summary\n---------------\n* rollcall  (pingou, 14:12:54)\n\n* status updates  (pingou, 14:16:26)\n  * LINK: https://pagure.io/fedora-bootstrap looks like only Ryan has\n    commit there  (pingou, 14:18:40)\n  * LINK: https://pagure.io/fedora-hubs/issue/33   (pingou, 14:28:18)\n\n* open-floor  (pingou, 14:38:50)\n\nMeeting ended at 14:41:19 UTC.\n\n\n\n\nAction Items\n------------\n\n\n\n\n\nAction Items, by person\n-----------------------\n* **UNASSIGNED**\n  * (none)\n\n\n\n\nPeople Present (lines said)\n---------------------------\n* pingou (50)\n* atelic (10)\n* radhikak (7)\n* zodbot (7)\n* devyani7_ (6)\n* stickster (4)\n\n\n\n\nGenerated by `MeetBot`_ 0.1.4\n\n.. _`MeetBot`: http://wiki.debian.org/MeetBot\n</h5>",
+            "objects": [
+                "attendees/devyani7_",
+                "titles/fedora-hubs",
+                "attendees/stickster",
+                "topics/open-floor",
+                "channels/#fedora-hubs",
+                "attendees/pingou",
+                "attendees/radhikak",
+                "attendees/atelic"
+            ],
+            "link": "https://meetbot.fedoraproject.org/fedora-hubs/2016-07-05/fedora-hubs.2016-07-05-14.12.html",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "usernames": [
+                "atelic",
+                "radhikak",
+                "stickster",
+                "pingou",
+                "devyani7_"
+            ],
+            "title": "meetbot.meeting.complete",
+            "markup": "<a href=\"/pingou/\" rel=\"nofollow\">@pingou</a>'s meeting titled \"fedora-hubs\" ended in #fedora-hubs"
+        },
+        "2016-a6dab4e9-3ab8-4668-a2cb-c3aec2fd3b9c": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "subtitle": "pingou linked to more information in the \"fedora-hubs\" meeting in #fedora-hubs: \"https://pagure.io/fedora-bootstrap looks like only Ryan has commit there\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/01fe73d687f4db328da1183f2a1b5b22962ca9d9c50f0728aafeac974856311c?s=64&d=retro",
+            "subjective": "pingou linked to more information in the \"fedora-hubs\" meeting in #fedora-hubs: \"https://pagure.io/fedora-bootstrap looks like only Ryan has commit there\"",
+            "long_form": "pingou linked to more information in the \"fedora-hubs\" meeting in #fedora-hubs: \"https://pagure.io/fedora-bootstrap looks like only Ryan has commit there\"",
+            "objects": [
+                "attendees/devyani7_",
+                "titles/fedora-hubs",
+                "attendees/stickster",
+                "channels/#fedora-hubs",
+                "attendees/pingou",
+                "attendees/radhikak",
+                "attendees/atelic",
+                "topics/status updates"
+            ],
+            "link": "https://pagure.io/fedora-bootstrap",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "usernames": [
+                "atelic",
+                "radhikak",
+                "stickster",
+                "pingou",
+                "devyani7_"
+            ],
+            "title": "meetbot.meeting.item.link",
+            "markup": "<a href=\"/pingou/\" rel=\"nofollow\">@pingou</a> linked to more information in the \"fedora-hubs\" meeting in #fedora-hubs: \"https://pagure.io/fedora-bootstrap looks like only Ryan has commit there\""
+        },
+        "2016-5d644757-f50d-4b53-a813-9382afb747fd": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "subtitle": "The topic of pingou's \"fedora-hubs\" meeting changed to \"status updates\" in #fedora-hubs",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/01fe73d687f4db328da1183f2a1b5b22962ca9d9c50f0728aafeac974856311c?s=64&d=retro",
+            "subjective": "The topic of pingou's \"fedora-hubs\" meeting changed to \"status updates\" in #fedora-hubs",
+            "long_form": "The topic of pingou's \"fedora-hubs\" meeting changed to \"status updates\" in #fedora-hubs",
+            "objects": [
+                "attendees/devyani7_",
+                "titles/fedora-hubs",
+                "attendees/stickster",
+                "channels/#fedora-hubs",
+                "attendees/pingou",
+                "attendees/radhikak",
+                "attendees/atelic",
+                "topics/status updates"
+            ],
+            "link": null,
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "usernames": [
+                "atelic",
+                "radhikak",
+                "stickster",
+                "pingou",
+                "devyani7_"
+            ],
+            "title": "meetbot.meeting.topic.update",
+            "markup": "The topic of <a href=\"/pingou/\" rel=\"nofollow\">@pingou</a>'s \"fedora-hubs\" meeting changed to \"status updates\" in #fedora-hubs"
+        },
+        "2016-ff66aff5-bb8a-462b-9bfb-58f7fe79ab6d": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "subtitle": "pingou linked to more information in the \"fedora-hubs\" meeting in #fedora-hubs: \"https://pagure.io/fedora-hubs/issue/33\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/01fe73d687f4db328da1183f2a1b5b22962ca9d9c50f0728aafeac974856311c?s=64&d=retro",
+            "subjective": "pingou linked to more information in the \"fedora-hubs\" meeting in #fedora-hubs: \"https://pagure.io/fedora-hubs/issue/33\"",
+            "long_form": "pingou linked to more information in the \"fedora-hubs\" meeting in #fedora-hubs: \"https://pagure.io/fedora-hubs/issue/33\"",
+            "objects": [
+                "attendees/devyani7_",
+                "titles/fedora-hubs",
+                "attendees/stickster",
+                "channels/#fedora-hubs",
+                "attendees/pingou",
+                "attendees/radhikak",
+                "attendees/atelic",
+                "topics/status updates"
+            ],
+            "link": null,
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "usernames": [
+                "atelic",
+                "radhikak",
+                "stickster",
+                "pingou",
+                "devyani7_"
+            ],
+            "title": "meetbot.meeting.item.link",
+            "markup": "<a href=\"/pingou/\" rel=\"nofollow\">@pingou</a> linked to more information in the \"fedora-hubs\" meeting in #fedora-hubs: \"https://pagure.io/fedora-hubs/issue/33\""
+        },
+        "2016-6e626d88-14e8-42b7-be6d-29ea97e4fa30": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "subtitle": "The topic of pingou's \"fedora-hubs\" meeting changed to \"open-floor\" in #fedora-hubs",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/01fe73d687f4db328da1183f2a1b5b22962ca9d9c50f0728aafeac974856311c?s=64&d=retro",
+            "subjective": "The topic of pingou's \"fedora-hubs\" meeting changed to \"open-floor\" in #fedora-hubs",
+            "long_form": "The topic of pingou's \"fedora-hubs\" meeting changed to \"open-floor\" in #fedora-hubs",
+            "objects": [
+                "attendees/devyani7_",
+                "titles/fedora-hubs",
+                "attendees/stickster",
+                "topics/open-floor",
+                "channels/#fedora-hubs",
+                "attendees/pingou",
+                "attendees/radhikak",
+                "attendees/atelic"
+            ],
+            "link": null,
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+            "usernames": [
+                "atelic",
+                "radhikak",
+                "stickster",
+                "pingou",
+                "devyani7_"
+            ],
+            "title": "meetbot.meeting.topic.update",
+            "markup": "The topic of <a href=\"/pingou/\" rel=\"nofollow\">@pingou</a>'s \"fedora-hubs\" meeting changed to \"open-floor\" in #fedora-hubs"
+        }
+    },
+    "link": "https://meetbot.fedoraproject.org/fedora-hubs/2016-07-05/fedora-hubs.2016-07-05-14.12",
+    "packages": [],
+    "categories": [
+        "meetbot"
+    ],
+    "icon": "https://apps.fedoraproject.org/img/icons/meetbot.png",
+    "usernames": [
+        "atelic",
+        "radhikak",
+        "stickster",
+        "pingou",
+        "devyani7_"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a>, <a href=\"/devyani7_/\" rel=\"nofollow\">@devyani7_</a>, and 4 others participated in fedora-hubs in #fedora-hubs",
+    "dom_id": "0270822e-fd91-4184-b38d-818ea99b8e0a",
+    "end_time": 1467744079,
+    "human_time": "a month ago",
+    "topics": [
+        "org.fedoraproject.prod.meetbot.meeting.complete",
+        "org.fedoraproject.prod.meetbot.meeting.item.link",
+        "org.fedoraproject.prod.meetbot.meeting.topic.update"
+    ]
+}, {
+    "subtitle": "atelic interacted with pull-request #206 of project \"fedora-hubs\" 2 times",
+    "timestamp": 1467268038.5,
+    "start_time": 1467228169,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with pull-request #206 of project \"fedora-hubs\" 2 times",
+    "msg_ids": {
+        "2016-23d3bb2f-431a-43f4-bc5b-a3774791e304": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#206 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#206 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#206 of project \"fedora-hubs\"",
+            "objects": [
+                "pull-request/206",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/206#comment-6746",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#206 of project \"fedora-hubs\""
+        },
+        "2016-75011179-c035-421c-b76e-ac18af8a6dcb": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic opened pull-request#206: \"Fix issue with Feed elements not rendering\" on project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic opened pull-request#206: \"Fix issue with Feed elements not rendering\" on project \"fedora-hubs\"",
+            "long_form": "atelic opened pull-request#206: \"Fix issue with Feed elements not rendering\" on project \"fedora-hubs\"",
+            "objects": [
+                "pull-request/206",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/206",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.new",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened pull-request#206: \"Fix issue with Feed elements not rendering\" on project \"fedora-hubs\""
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/pull-request/206",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with pull-request #206 of project \"fedora-hubs\" 2 times",
+    "dom_id": "c782076a-b8d5-4115-a375-3dcb57990454",
+    "end_time": 1467307908,
+    "human_time": "a month ago",
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added",
+        "io.pagure.prod.pagure.pull-request.new"
+    ]
+}, {
+    "subtitle": "atelic interacted with pull-request #207 of project \"fedora-hubs\" 4 times",
+    "timestamp": 1467233522.75,
+    "start_time": 1467228942,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic interacted with pull-request #207 of project \"fedora-hubs\" 4 times",
+    "msg_ids": {
+        "2016-90a67858-c666-43aa-9a97-1580e479a0c4": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#207 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#207 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#207 of project \"fedora-hubs\"",
+            "objects": [
+                "pull-request/207",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/207#comment-6680",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#207 of project \"fedora-hubs\""
+        },
+        "2016-e805a4ad-26e8-4cf3-86a1-697158736e77": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic opened pull-request#207: \"Move 4 spaces to 2 in JSX files\" on project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic opened pull-request#207: \"Move 4 spaces to 2 in JSX files\" on project \"fedora-hubs\"",
+            "long_form": "atelic opened pull-request#207: \"Move 4 spaces to 2 in JSX files\" on project \"fedora-hubs\"",
+            "objects": [
+                "pull-request/207",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/207",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.new",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> opened pull-request#207: \"Move 4 spaces to 2 in JSX files\" on project \"fedora-hubs\""
+        },
+        "2016-f94132c3-6a07-4e06-9b0b-18ce93e03f19": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#207 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#207 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#207 of project \"fedora-hubs\"",
+            "objects": [
+                "pull-request/207",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/207#comment-6688",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#207 of project \"fedora-hubs\""
+        },
+        "2016-54b4e842-73cb-4b7d-8b53-5a27a433ac22": {
+            "__icon__": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "subtitle": "atelic commented on pull-request#207 of project \"fedora-hubs\"",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic commented on pull-request#207 of project \"fedora-hubs\"",
+            "long_form": "atelic commented on pull-request#207 of project \"fedora-hubs\"",
+            "objects": [
+                "pull-request/207",
+                "project/fedora-hubs"
+            ],
+            "link": "https://pagure.io/fedora-hubs/pull-request/207#comment-6681",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "pagure.pull-request.comment.added",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> commented on pull-request#207 of project \"fedora-hubs\""
+        }
+    },
+    "link": "https://pagure.io/fedora-hubs/pull-request/207",
+    "packages": [],
+    "categories": [
+        "pagure"
+    ],
+    "icon": "https://apps.fedoraproject.org/packages/images/icons/package_128x128.png",
+    "usernames": [
+        "atelic"
+    ],
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> interacted with pull-request #207 of project \"fedora-hubs\" 4 times",
+    "dom_id": "16c799c2-d090-441e-a422-a2b6d7c8d062",
+    "end_time": 1467246314,
+    "human_time": "a month ago",
+    "topics": [
+        "io.pagure.prod.pagure.pull-request.comment.added",
+        "io.pagure.prod.pagure.pull-request.new"
+    ]
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "a month ago",
+    "subtitle": "atelic updated their irc filters",
+    "timestamp": 1467236930,
+    "start_time": 1467236930,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic updated their irc filters",
+    "dom_id": "9b57a8fc-ddde-4cfc-bff8-69759ace8d39",
+    "msg_ids": {
+        "2016-a32a2741-63dc-451f-af31-b67f986844af": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "subtitle": "atelic updated their irc filters",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic updated their irc filters",
+            "long_form": "atelic updated their irc filters",
+            "objects": [
+                "atelic/irc/preference/filters"
+            ],
+            "link": "https://apps.fedoraproject.org/notifications/",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "fmn.preference.update",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+            "lexer": null
+        }
+    },
+    "link": "https://apps.fedoraproject.org/notifications/",
+    "end_time": 1467236930,
+    "packages": [],
+    "topics": [
+        "org.fedoraproject.prod.fmn.preference.update"
+    ],
+    "categories": [
+        "fmn"
+    ],
+    "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "a month ago",
+    "subtitle": "atelic updated their irc filters",
+    "timestamp": 1467236926,
+    "start_time": 1467236926,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic updated their irc filters",
+    "dom_id": "d4a17d44-bebb-439b-8b42-027a6c46ec51",
+    "msg_ids": {
+        "2016-bfb5661b-1f74-4fe9-a6b6-c02494846ba9": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "subtitle": "atelic updated their irc filters",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic updated their irc filters",
+            "long_form": "atelic updated their irc filters",
+            "objects": [
+                "atelic/irc/preference/filters"
+            ],
+            "link": "https://apps.fedoraproject.org/notifications/",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "fmn.preference.update",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+            "lexer": null
+        }
+    },
+    "link": "https://apps.fedoraproject.org/notifications/",
+    "end_time": 1467236926,
+    "packages": [],
+    "topics": [
+        "org.fedoraproject.prod.fmn.preference.update"
+    ],
+    "categories": [
+        "fmn"
+    ],
+    "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "a month ago",
+    "subtitle": "atelic updated their irc filters",
+    "timestamp": 1467236923,
+    "start_time": 1467236923,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic updated their irc filters",
+    "dom_id": "a058f25c-4513-4b0c-a591-5bf8ba397d87",
+    "msg_ids": {
+        "2016-dc33fbb0-a733-46a8-8254-1611d0b20393": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "subtitle": "atelic updated their irc filters",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic updated their irc filters",
+            "long_form": "atelic updated their irc filters",
+            "objects": [
+                "atelic/irc/preference/filters"
+            ],
+            "link": "https://apps.fedoraproject.org/notifications/",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "fmn.preference.update",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+            "lexer": null
+        }
+    },
+    "link": "https://apps.fedoraproject.org/notifications/",
+    "end_time": 1467236923,
+    "packages": [],
+    "topics": [
+        "org.fedoraproject.prod.fmn.preference.update"
+    ],
+    "categories": [
+        "fmn"
+    ],
+    "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated the rules on a fmn irc filter",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "a month ago",
+    "subtitle": "atelic updated the rules on a fmn irc filter",
+    "timestamp": 1467226515,
+    "start_time": 1467226515,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic updated the rules on a fmn irc filter",
+    "dom_id": "e6372a10-148e-4967-99c7-c6780742be67",
+    "msg_ids": {
+        "2016-425ad1ce-4c10-4c12-8f9c-7460ae4fe351": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "subtitle": "atelic updated the rules on a fmn irc filter",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic updated the rules on a fmn irc filter",
+            "long_form": "atelic updated the rules on a fmn irc filter",
+            "objects": [
+                "atelic/irc/filter/rules"
+            ],
+            "link": "https://apps.fedoraproject.org/notifications/",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "fmn.filter.update",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated the rules on a fmn irc filter",
+            "lexer": null
+        }
+    },
+    "link": "https://apps.fedoraproject.org/notifications/",
+    "end_time": 1467226515,
+    "packages": [],
+    "topics": [
+        "org.fedoraproject.prod.fmn.filter.update"
+    ],
+    "categories": [
+        "fmn"
+    ],
+    "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "a month ago",
+    "subtitle": "atelic updated their irc filters",
+    "timestamp": 1467226439,
+    "start_time": 1467226439,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic updated their irc filters",
+    "dom_id": "4153a81c-b44d-44a7-8240-4b0820835768",
+    "msg_ids": {
+        "2016-45d90281-40ee-4f22-9901-4ef849c49810": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "subtitle": "atelic updated their irc filters",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic updated their irc filters",
+            "long_form": "atelic updated their irc filters",
+            "objects": [
+                "atelic/irc/preference/filters"
+            ],
+            "link": "https://apps.fedoraproject.org/notifications/",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "fmn.preference.update",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+            "lexer": null
+        }
+    },
+    "link": "https://apps.fedoraproject.org/notifications/",
+    "end_time": 1467226439,
+    "packages": [],
+    "topics": [
+        "org.fedoraproject.prod.fmn.preference.update"
+    ],
+    "categories": [
+        "fmn"
+    ],
+    "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png"
+}, {
+    "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+    "usernames": [
+        "atelic"
+    ],
+    "human_time": "a month ago",
+    "subtitle": "atelic updated their irc filters",
+    "timestamp": 1467226437,
+    "start_time": 1467226437,
+    "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+    "subjective": "atelic updated their irc filters",
+    "dom_id": "487b1807-b798-4b98-ae35-c5819ffc5db0",
+    "msg_ids": {
+        "2016-06917565-a0ac-4c2a-bb7f-fefe98df903d": {
+            "__icon__": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "subtitle": "atelic updated their irc filters",
+            "secondary_icon": "https://seccdn.libravatar.org/avatar/ba1882fd5522d16213b0535934f77b796f0b89f76edd65460078099fe97c20ea?s=64&d=retro",
+            "subjective": "atelic updated their irc filters",
+            "long_form": "atelic updated their irc filters",
+            "objects": [
+                "atelic/irc/preference/filters"
+            ],
+            "link": "https://apps.fedoraproject.org/notifications/",
+            "packages": [],
+            "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png",
+            "usernames": [
+                "atelic"
+            ],
+            "title": "fmn.preference.update",
+            "markup": "<a href=\"/atelic/\" rel=\"nofollow\">@atelic</a> updated their irc filters",
+            "lexer": null
+        }
+    },
+    "link": "https://apps.fedoraproject.org/notifications/",
+    "end_time": 1467226437,
+    "packages": [],
+    "topics": [
+        "org.fedoraproject.prod.fmn.preference.update"
+    ],
+    "categories": [
+        "fmn"
+    ],
+    "icon": "https://apps.fedoraproject.org/img/icons/fedmsg.png"
+}]
diff --git a/hubs/app.py b/hubs/app.py
index ff9cb3a..43f32a6 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -523,17 +523,9 @@ def stream(name):
     saved = hubs.models.SavedNotification.by_username(session, name)
     saved = [n.__json__() for n in saved]
 
-    stream = hubs.stream.Stream(name)
-    actions = stream.get_actions()
+    stream = hubs.stream.Stream()
+    actions = stream.get_json()
 
-    # An action that has already been saved should not have a saved button
-    # this tags all the saved actions so the front end can decide to display or not.
-    # This will get slow pretty quickly so we should reevaluate after flock
-    for action in actions:
-        if any(s['markup'] == action['markup'] for s in saved):
-            action['saved'] = True
-
-    actions = json.dumps(actions, cls=hubs.stream.PythonObjectEncoder)
     return flask.render_template(
         'stream.html',
         hub=hub,
diff --git a/hubs/stream.py b/hubs/stream.py
index 8c33bf2..fd45923 100644
--- a/hubs/stream.py
+++ b/hubs/stream.py
@@ -1,166 +1,9 @@
-import cgi
-import datetime
 import json
-import uuid
+import os
 
-import datanommer.models
-import flask
-import fmn.lib
-import munch
-import pygments.formatters
-import six
-
-import fedmsg.config
-import fedmsg.meta
-
-
-# TODO Temporary: This is a proof of concept for Flock
-# This needs to be done in fnm.lib
 class Stream(object):
-    paths = fmn.lib.load_rules(root='fmn.rules')
-    fedmsg_config = fedmsg.config.load_config()
-    delta = datetime.timedelta(days=365)
-    end = datetime.datetime.utcnow()
-
-    def __init__(self, name):
-        self.name = name
-        self.preference = {
-            'filters': [{
-                'created_on': 'Thu, 15 Jan 2015 16:07:43 GMT',
-                'id': 20506,
-                'name': 'Events referring to my username',
-                'oneshot': None,
-                'rules': [
-                    {
-                        'arguments': {
-                            'fasnick': name
-                        },
-                        'cache_key':
-                        '2f59dcddf85cab5822af8d40d82c7390ce0f80b40119f2db67f3037a0594a2a1',
-                        'code_path': 'fmn.rules:user_filter',
-                        'created_on': 'Thu, 15 Jan 2015 16:07:43 GMT',
-                        'info': {
-                            'args': [
-                                'config', 'message', 'fasnick'
-                            ],
-                            'datanommer-hints': {},
-                            'doc':
-                            "<p>Use this rule to include messages that are associated with a\nspecific user.</p>",
-                            'doc-no-links':
-                            '<html><head></head><body><p>Use this rule to include messages that are associated with a\nspecific user.</p>\n</body></html>',
-                            'hints-invertible': True,
-                            'submodule': 'generic',
-                            'title': 'A particular user'
-                        },
-                        'negated': False
-                    }
-                ]
-            }]
-        }
-
-    def apply_html(self, matches):
-        # Smash multiple messages into single ones
-        matches = fedmsg.meta.conglomerate(matches,
-                                           lexers=True,
-                                           **self.fedmsg_config)
-
-        # Apply some html markup to the subtitles for extra fanciness.
-        for match in matches:
-            match['markup'] = self.apply_markup(match)
-            for idx, constituent in match['msg_ids'].items():
-                constituent['markup'] = self.apply_markup(constituent)
-                if constituent['long_form'] != constituent['subtitle']:
-                    if constituent.get('lexer'):
-                        constituent['long_form'] = pygments.highlight(
-                            constituent['long_form'],
-                            constituent['lexer'],
-                            pygments.formatters.HtmlFormatter(
-                                style='monokai'), )
-                    else:
-                        markup = u"<h5>{long_form}</h5>".format(**constituent)
-                        constituent['long_form'] = markup
-            # And tack on a unique identifier for each top level entry.
-            match['dom_id'] = six.text_type(uuid.uuid4())
-
-        return matches
-
-    def get_actions(self):
-        preference = self.rehydrate_preference(self.preference)
-        messages = []
-        actions = []
-
-        for fmn_filter in preference['filters']:
-            fmn_hinting = fmn.lib.hinting.gather_hinting(
-                self.fedmsg_config, fmn_filter['rules'], self.paths)
-            total, pages, rows = datanommer.models.Message.grep(
-                start=self.end - self.delta,
-                end=self.end,
-                rows_per_page=100,
-                page=1,
-                order='desc',
-                **fmn_hinting)
-            messages.extend(rows)
-
-
-        for message in messages:
-            original = message.__json__()
-            if self.name in fedmsg.meta.msg2usernames(original, **
-                                                      self.fedmsg_config):
-                actions.append(original)
-
-        return self.apply_html(actions)
-
-    def rehydrate_preference(self, preference):
-        for fltr in preference['filters']:
-            fltr['rules'] = [munch.Munch(r) for r in fltr['rules']]
-            for rule in fltr['rules']:
-                code_path = str(rule.code_path)
-                rule.fn = fedmsg.utils.load_class(code_path)
-
-        return preference
-
-    def escape_html(self, match):
-        for key in ['subjective', 'subtitle']:
-            match[key] = cgi.escape(match[key])
-        try:
-            match['long_form'] = cgi.escape(match['long_form'])
-        except:
-            # not all matches have a long form
-            pass
-        return match
-
-    def apply_markup(self, match):
-        match = self.escape_html(match)
-        markup = match['subtitle']
-        for username in match['usernames']:
-            args = (username, '<a href="{url}" rel="nofollow">@{username}</a>'.format(
-                url=flask.url_for('hub', name=username),
-                username=username, ))
-            markup = markup.replace(*args)
-            # TODO -- have to add these to conglomerate first
-            # match['long_form'] = match['long_form'].replace(*args)
-
-        for package in match['packages']:
-            args = (package, '<a href="{url}">{package}</a>'.format(
-                url='https://apps.fedoraproject.org/packages/' + package,
-                package=package, ))
-            markup = markup.replace(*args)
-            # TODO -- have to add these to conglomerate first
-            # match['long_form'] = match['long_form'].replace(*args)
-
-        return markup
-
-
-class PythonObjectEncoder(json.JSONEncoder):
-    ''' A JSON encoder that handles python data structures in encoding'''
-
-    def default(self, obj):
-        if isinstance(obj, (list, dict, str, unicode, int, float, bool,
-                            type(None))):
-            return json.JSONEncoder.default(self, obj)
-        if isinstance(obj, set) or isinstance(obj, tuple):
-            return list(obj)
-        if isinstance(obj, object):
-            return obj.__dict__
-        else:
-            raise TypeError
+    def get_json(self):
+        here = os.path.dirname(os.path.abspath(__file__))
+        with open(os.path.join(here, 'actions.json')) as fp:
+            actions = fp.read()
+        return actions
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 5e6fc57..49a3dab 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -126,9 +126,6 @@
 
  function setup_feeds() {
    var actions = {{actions|safe}};
-   var options = {
-
-   }
 
    var streamFeed = React.createElement(Feed, {
      matches: actions,

From 4cbd8ced5c6d4e803ad188fb89d2d2c29dd53b7c Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 10 2016 19:37:26 +0000
Subject: [PATCH 623/1001] Force int idx for notification routes.


- To be consistent with other routes, force idx to be an int.
- Update SavedNotification tests to expect this

---

diff --git a/hubs/app.py b/hubs/app.py
index 43f32a6..17b56ad 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -568,8 +568,8 @@ def notifications(user):
             dict(notification=notification.__json__(), success=True)
         )
 
-@app.route('/<user>/notifications/<idx>', methods=['DELETE'])
-@app.route('/<user>/notifications/<idx>/', methods=['DELETE'])
+@app.route('/<user>/notifications/<int:idx>', methods=['DELETE'])
+@app.route('/<user>/notifications/<int:idx>/', methods=['DELETE'])
 @login_required
 def delete_notifications(user, idx):
     notification = session.query(hubs.models.SavedNotification).filter_by(idx=idx).first()
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index 6706031..74acdc1 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -111,11 +111,11 @@ class TestDeleteNotifications(hubs.tests.APPTest):
 
         self.assertIsNone(notification)
 
-    def test_400_on_bad_idx(self):
+    def test_404_on_bad_idx(self):
         idx = 'thisisastringnotanint'
 
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.delete(
                 '/{}/notifications/{}/'.format(self.user.username, idx)
             )
-        self.assertEqual(resp.status_code, 400)
+        self.assertEqual(resp.status_code, 404)

From 17e997de75c65715965b71a27fdbe7af7e9d70cc Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 11 2016 18:22:23 +0000
Subject: [PATCH 624/1001] Add tests for React front end


* Use jest test suite (recommended by React team)

---

diff --git a/README.rst b/README.rst
index a7d2910..c0946ab 100644
--- a/README.rst
+++ b/README.rst
@@ -108,6 +108,9 @@ See the options available with::
 
     $ ./runtest.sh --help
 
+You can run the JavaScript tests from ``hubs/static/client`` with::
+    $ npm test
+
 Some credentials...
 -------------------
 
diff --git a/hubs/static/client/.babelrc b/hubs/static/client/.babelrc
index 9926dbe..aef231b 100644
--- a/hubs/static/client/.babelrc
+++ b/hubs/static/client/.babelrc
@@ -1,5 +1,5 @@
 {
-  "presets" : ["es2015", "react"],
+  "presets" : ["es2015", "react", "stage-1"],
   "plugins": ["transform-class-properties"]
 }
 
diff --git a/hubs/static/client/.eslintrc.json b/hubs/static/client/.eslintrc.json
index 079ce96..62ca52c 100644
--- a/hubs/static/client/.eslintrc.json
+++ b/hubs/static/client/.eslintrc.json
@@ -1,8 +1,9 @@
 {
   "extends": "airbnb",
   "rules": {
-    "react/prop-types": "off",
     "arrow-body-style": "off",
     "func-names": "off"
+    "react/prefer-stateless-function": "off",
+    "react/prop-types": "off",
   }
 }
diff --git a/hubs/static/client/app/__tests__/Feed.test.js b/hubs/static/client/app/__tests__/Feed.test.js
new file mode 100644
index 0000000..ae93f29
--- /dev/null
+++ b/hubs/static/client/app/__tests__/Feed.test.js
@@ -0,0 +1,34 @@
+/* eslint-env jasmine, jest */
+
+jest.unmock('../components/Feed.jsx');
+
+import React from 'react';
+import TestUtils from 'react-addons-test-utils';
+
+import Feed from '../components/Feed.jsx';
+
+describe('Feed', () => {
+  const matches = [{
+    markup: '<a href="https://pagure.io/fedora-hubs">Link</a>',
+    date_time: new Date(),
+    link: 'https://pagure.io/fedora-hubs',
+    secondary_icon: 'https://placekitten.com/g/200/300',
+  }];
+
+  const options = {
+    messageLimit: 100
+  };
+
+  it('should set the correct state', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Feed matches={matches} options={options} />
+    );
+
+    const state = {
+      matches,
+      messageLimit: 100,
+      sse: true,
+    };
+    expect(component.state).toEqual(state);
+  });
+});
diff --git a/hubs/static/client/app/__tests__/Icon.test.js b/hubs/static/client/app/__tests__/Icon.test.js
new file mode 100644
index 0000000..920c853
--- /dev/null
+++ b/hubs/static/client/app/__tests__/Icon.test.js
@@ -0,0 +1,36 @@
+/* eslint-env jasmine, jest */
+
+jest.unmock('../components/Icon.jsx');
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import TestUtils from 'react-addons-test-utils';
+
+import Icon from '../components/Icon.jsx';
+
+describe('Icon', () => {
+  const match = {
+    link: 'https://pagure.io/fedora-hubs',
+    secondary_icon: 'https://placekitten.com/g/200/300',
+  };
+
+  it('has the correct link', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Icon match={match} />
+    );
+    expect(component).toBeTruthy();
+    const node = ReactDOM.findDOMNode(component);
+    const link = node.querySelector('a');
+    expect(link.getAttribute('href')).toEqual(match.link);
+  });
+  it('has the correct image source', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Icon match={match} />
+    );
+    expect(component).toBeTruthy();
+
+    const node = ReactDOM.findDOMNode(component);
+    const image = node.querySelector('img');
+    expect(image.getAttribute('src')).toEqual(match.secondary_icon);
+  });
+});
diff --git a/hubs/static/client/app/__tests__/Markup.test.js b/hubs/static/client/app/__tests__/Markup.test.js
new file mode 100644
index 0000000..d2aea84
--- /dev/null
+++ b/hubs/static/client/app/__tests__/Markup.test.js
@@ -0,0 +1,30 @@
+/* eslint-env jasmine, jest */
+
+jest.unmock('../components/Markup.jsx');
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import TestUtils from 'react-addons-test-utils';
+
+import Markup from '../components/Markup.jsx';
+
+describe('Markup', () => {
+  const match = {
+    markup: '<a href="https://pagure.io/fedora-hubs">Link</a>',
+    date_time: new Date(),
+  };
+
+  it('should set the inner html of the markup', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Markup match={match} />
+    );
+    expect(component).toBeTruthy();
+
+    const node = ReactDOM.findDOMNode(component);
+    const header = node.querySelector('h4');
+
+    expect(header.innerHTML).toEqual(match.markup);
+  });
+
+  // we don't test TimeAgo, the library should have its own tests
+});
diff --git a/hubs/static/client/app/__tests__/Panel.test.js b/hubs/static/client/app/__tests__/Panel.test.js
new file mode 100644
index 0000000..c8632c5
--- /dev/null
+++ b/hubs/static/client/app/__tests__/Panel.test.js
@@ -0,0 +1,30 @@
+/* eslint-env jasmine, jest */
+
+jest.unmock('../components/Panel.jsx');
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import TestUtils from 'react-addons-test-utils';
+
+import Panel from '../components/Panel.jsx';
+
+describe('Panel', () => {
+  const match = {
+    markup: '<a href="https://pagure.io/fedora-hubs">Link</a>',
+    date_time: new Date(),
+    link: 'https://pagure.io/fedora-hubs',
+    secondary_icon: 'https://placekitten.com/g/200/300',
+  };
+
+  it('should render the card block', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Panel match={match} />
+    );
+    expect(component).toBeTruthy();
+
+    const node = ReactDOM.findDOMNode(component);
+    const block = node.querySelector('.card-block');
+
+    expect(block).toBeTruthy();
+  });
+});
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
index eae102a..b196bdb 100644
--- a/hubs/static/client/app/components/Feed.jsx
+++ b/hubs/static/client/app/components/Feed.jsx
@@ -15,7 +15,10 @@ export default class Feed extends React.Component {
     if (!this.props.url || !this.state.sse) {
       return;
     }
-    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : {};
+    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : null;
+    if (!this.source) {
+      return;
+    }
     this.source.addEventListener('error', () => {
       this.state.sse = false;
     }, false);
diff --git a/hubs/static/client/app/components/Icon.jsx b/hubs/static/client/app/components/Icon.jsx
index 9adf0e4..0eec3cc 100644
--- a/hubs/static/client/app/components/Icon.jsx
+++ b/hubs/static/client/app/components/Icon.jsx
@@ -1,17 +1,21 @@
 import React from 'react';
 
-const Icon = function (props) {
-  return (
-    <div className="media-left">
-      <a href={props.match.link ? props.match.link : '#'} target="_blank">
-        <img
-          alt="User avatar"
-          className="media-object square-32"
-          src={props.match.secondary_icon}
-        />
-      </a>
-    </div>
-  );
-};
+class Icon extends React.Component {
+  render() {
+    return (
+      <div>
+        <div className="media-left">
+          <a href={this.props.match.link ? this.props.match.link : '#'} target="_blank">
+            <img
+              alt="User avatar"
+              className="media-object square-32 img-circle"
+              src={this.props.match.secondary_icon}
+            />
+          </a>
+        </div>
+      </div>
+    );
+  }
+}
 
 export default Icon;
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
index c443155..848a5b7 100644
--- a/hubs/static/client/app/components/Panel.jsx
+++ b/hubs/static/client/app/components/Panel.jsx
@@ -3,15 +3,17 @@ import React from 'react';
 import Icon from './Icon.jsx';
 import Markup from './Markup.jsx';
 
-const Panel = function (props) {
-  return (
-    <div className="card">
-      <div className="card-block" id={props.match.dom_id}>
-        <Icon match={props.match} />
-        <Markup options={props.options} match={props.match} />
+class Panel extends React.Component {
+  render() {
+    return (
+      <div className="card">
+        <div className="card-block" id={this.props.match.id}>
+          <Icon match={this.props.match} />
+          <Markup options={this.props.options} match={this.props.match} />
+        </div>
       </div>
-    </div>
-  );
-};
+    );
+  }
+}
 
 export default Panel;
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 235be28..8cc9aa4 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -17,13 +17,28 @@
     "webpack": "~1.13.1"
   },
   "devDependencies": {
+    "babel-jest": "^14.1.0",
+    "babel-preset-es2015": "^6.9.0",
+    "babel-preset-jest": "^14.1.0",
+    "babel-preset-react": "^6.5.0",
+    "babel-preset-stage-1": "^6.5.0",
     "eslint": "^2.13.1",
-    "depcheck": "~0.6.3"
+    "jest": "^14.1.0",
+    "react-addons-test-utils": "^15.3.0",
+    "react-test-renderer": "^15.3.0"
   },
   "scripts": {
     "dev": "webpack --watch",
     "build": "webpack -p",
-    "test": "eslint app/* && depcheck ."
+    "lint": "eslint app/*",
+    "test": "jest"
+  },
+  "jest": {
+    "unmockedModulePathPatterns": [
+      "<rootDir>/node_modules/react/",
+      "<rootDir>/node_modules/react-dom/",
+      "<rootDir>/node_modules/react-addons-test-utils/"
+    ]
   },
   "author": "Eric Barbour <ebarbour@redhat.com>",
   "license": "AGPL-3.0"

From 1fc4ef98f436d6f1a24f6857d5d6f1ac3e5ab91c Mon Sep 17 00:00:00 2001
From: Eric Barbour <ebarbour@redhat.com>
Date: Aug 11 2016 18:22:23 +0000
Subject: [PATCH 625/1001] Add script for running tests from root hubs dir


---

diff --git a/runjstests.sh b/runjstests.sh
new file mode 100755
index 0000000..07e6907
--- /dev/null
+++ b/runjstests.sh
@@ -0,0 +1 @@
+pushd hubs/static/client ; npm install ; npm test ; popd

From 1edbef452c2ddb06e665522586572e6d47a72415 Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Aug 17 2016 20:45:21 +0000
Subject: [PATCH 626/1001] Plus-Plus service backend integration


* initial work on plus-plus

* adding error handling with proper error displayed to client

* Removing debug statements, adding try/except if the plus-plus service is unavailable

* adding plus_plus tests

* adding case where trying to plus_plus a user who doesnt exist

* cleaning up mock request classes

* seperating the status and update routes of plus_plus, adding more tests and made a bool helper function for updating karma

---

diff --git a/hubs/app.py b/hubs/app.py
index 17b56ad..9484bfb 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -10,6 +10,7 @@ import flask.json
 import munch
 
 from flask.ext.oidc import OpenIDConnect
+from requests import request
 
 import hubs.models
 import hubs.widgets
@@ -732,3 +733,69 @@ def hub_leave(hub):
         return flask.abort(400)
     session.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/plus_plus/<user>/status', methods=['GET'])
+def plus_plus_status(user):
+    receiver = hubs.models.User.by_username(session, user)
+
+    if not receiver:
+        return 'User does not exist', 403
+
+    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
+    req = None
+    try:
+        req = request('GET', pp_url)
+    except:
+        flask.abort(500)
+
+    if req.status_code == 200:
+        return flask.jsonify(req.json())
+    else:
+        return req.text, req.status_code
+
+
+def plus_plus_update_bool_helper(val):
+    if isinstance(val, bool):
+        return val
+    elif isinstance(val, (str, unicode)):
+        fmt_str = str(val).replace("'", "").replace('"', '').lower()
+        return fmt_str in ("yes", "true", "t", "1")
+    else:
+        raise ValueError
+
+
+@app.route('/plus_plus/<user>/update', methods=['POST'])
+@login_required
+def plus_plus_update(user):
+    receiver = hubs.models.User.by_username(session, user)
+
+    if not receiver:
+        return 'User does not exist', 403
+
+    if user == flask.g.auth.nickname:
+        return 'You may not modify your own karma.', 403
+
+    if 'decrement' not in flask.request.form \
+            and 'increment' not in flask.request.form:
+        return "You must set 'decrement' or 'increment' " \
+               "with a boolean value in the body", 403
+
+    update = 'increment' if 'increment' in flask.request.form else 'decrement'
+
+    update_bool_val = plus_plus_update_bool_helper(flask.request.form[update])
+    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
+    sender = hubs.models.User.by_username(session, flask.g.auth.nickname)
+    pp_token = app.config['PLUS_PLUS_TOKEN']
+    auth_header = {'Authorization': 'token {}'.format(pp_token)}
+    data = {'sender': sender.username, update: update_bool_val}
+    req = None
+    try:
+        req = request('POST', url=pp_url, headers=auth_header, data=data)
+    except:
+        flask.abort(500)
+
+    if req.status_code == 200:
+        return flask.jsonify(req.json())
+    else:
+        return req.text, req.status_code
diff --git a/hubs/default_config.py b/hubs/default_config.py
index 4125923..bb9ef80 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -10,6 +10,8 @@ PROMOTED_GROUPS = [
 HUB_OF_THE_MONTH = 'commops'
 
 SSE_URL = 'http://localhost:8080/user/'
+PLUS_PLUS_URL = 'http://localhost:5001/user/'
+PLUS_PLUS_TOKEN = 'thisismytoken'
 
 OIDC_CLIENT_SECRETS = os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..', 'client_secrets.json')
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 6808456..d2966ed 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -4,6 +4,7 @@ from urlparse import urlparse
 from flask import json
 from os.path import dirname
 import vcr
+from mock import mock
 from werkzeug.datastructures import ImmutableMultiDict
 
 import hubs
@@ -357,6 +358,117 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get(url)
             self.assertEqual(result.status_code, 404)
 
+    def mocked_requests_get(*args, **kwargs):
+        class MockResponse:
+            def __init__(self, json_data, status_code):
+                self.json_data = json_data
+                self.status_code = status_code
+
+            def json(self):
+                return self.json_data
+
+        if '/plus_plus/decause/status' in args:
+            data = {
+                "current": 0,
+                "decrements": 0,
+                "increments": 0,
+                "release": "f24",
+                "total": 0,
+                "username": "decause"
+            }
+            return MockResponse(json_data=data, status_code=200)
+
+        return MockResponse({}, 404)
+
+    def mocked_requests_post(*args, **kwargs):
+        class MockResponse:
+            def __init__(self, json_data, status_code):
+                self.json_data = json_data
+                self.status_code = status_code
+
+            def json(self):
+                return self.json_data
+
+        if '/plus_plus/decause/update' in args:
+            data = {
+                "current": 1,
+                "decrements": 0,
+                "increments": 1,
+                "release": "f24",
+                "total": 1,
+                "username": "decause"
+            }
+            return MockResponse(json_data=data, status_code=200)
+
+        return MockResponse({}, 404)
+
+    @mock.patch('requests.get', side_effect=mocked_requests_get)
+    def test_plus_plus_get_valid(self, mock_get):
+        url = '/plus_plus/decause/status'
+        result = self.app.get(url)
+        expected = {
+            "current": 0,
+            "decrements": 0,
+            "increments": 0,
+            "release": "f24",
+            "total": 0,
+            "username": "decause"
+        }
+        self.assertEqual(json.loads(result.data), expected)
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_valid(self, mock_post):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/plus_plus/decause/update'
+            result = self.app.post(url, data={'increment': True})
+            expected = {
+                "current": 1,
+                "decrements": 0,
+                "increments": 1,
+                "release": "f24",
+                "total": 1,
+                "username": "decause"
+            }
+            self.assertEqual(json.loads(result.data), expected)
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_myself_error(self, mock_post):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/plus_plus/ralph/update'
+            result = self.app.post(url, data={'increment': True})
+            self.assertEqual(result.status_code, 403)
+            self.assertEqual(result.data, 'You may not modify your own karma.')
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/plus_plus/doesnotexist/update'
+            result = self.app.post(url, data={'increment': True})
+            self.assertEqual(result.status_code, 403)
+            self.assertEqual(result.data, 'User does not exist')
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_no_data_error(self, mock_post):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/plus_plus/decause/update'
+            result = self.app.post(url, data={})
+            self.assertEqual(result.status_code, 403)
+            exp_str = "You must set 'decrement' or 'increment' " \
+                      "with a boolean value in the body"
+            self.assertEqual(result.data, exp_str)
+
+    def test_plus_plus_receiver_does_not_exist(self):
+        url = '/plus_plus/doesnotexist/status'
+        result = self.app.get(url)
+        self.assertEqual(result.status_code, 403)
+        self.assertEqual(result.data, 'User does not exist')
+
+
+
 
 if __name__ == '__main__':
     unittest.main()

From 351b46e03ae1ffdbe15723689d7b88ffb5921429 Mon Sep 17 00:00:00 2001
From: duffy <fedora@linuxgrrl.com>
Date: Aug 23 2016 17:13:06 +0000
Subject: [PATCH 627/1001] Update README.rst


---

diff --git a/README.rst b/README.rst
index c0946ab..cbb8e86 100644
--- a/README.rst
+++ b/README.rst
@@ -11,6 +11,26 @@ Mailing List
 We have a mailing list here:
 https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org
 
+Road Map
+========
+
+We are currently working towards a roadmap of the following features with a mid-October target milestone for them:
+
+# **Zanata support** - Zanata is releasing a new version in November, but we've been in contact with Alex from that team and he said he will provide us with sample data to start developing against while they work on creating the webhooks we need to get that data. So we could do a release in October that has the support (and wait for the November Zanata release to turn it on.) Specifics of what widgets Zanata support would entail for the October release is TBD. 
+# **IRC Integration** - We'd like to have some IRC features available in the October release via the Waartaa project.
+# **Badge support** -  Sayan already has a PR ready for tahrir (I believe) to add paths to badges; once that gets merged he can start working on the widget for hubs.
+# **Hyperkitty support** - Hyperkitty needs some new API methods to provide full post content and metadata about replies / etc. Right now the migration off of Persona is top priority as Mozilla is shutting down Persona in September, but after that Aurelien can work on this. It shouldn't be super complicated. Once completed, Hyperkitty new thread posts will appear in the feed widget and if new replies are received to the thread, it'll bounce the thread to the top of the feed widget again.
+# **Plusplus widget** - Aurelien and szkrepto have backend done; needs to be added to the webui.
+
+Want to get involved? Looking for something to work on?
+=======================================================
+
+* Unfamiliar with what hubs is all about? Read through these blog posts / videos with lots of information about our vision for the project:
+http://blog.linuxgrrl.com/category/fedora/fedora-hubs/
+* Building the development environment locally on your computer is a good beginning step to getting involved. If you have questions / run into issues, feel free to ask on #fedora-hubs in irc.freenode.net.
+* We meet weekly in #fedora-hubs at 1400 UTC (10 AM EDT) on irc.freenode.net. We review our statuses from the preceding week and do ticket triage too. Please join us and get acquainted!
+* **UX Designers** - take a look at our issues tagged 'needsmockup' that have no assignee listed and have a chat with mizmo (Máirín Duffy) for issue assignment / orientation.
+* **Developers** - take a look at our issues with 'normal' or 'low' priority. We're tagging issues with think are particularly good for newbies to take on with the "easy" tag.
 
 Hacking
 =======

From d88f8e4dcbada6f150547d2593024402f7c01d20 Mon Sep 17 00:00:00 2001
From: duffy <fedora@linuxgrrl.com>
Date: Aug 23 2016 17:13:34 +0000
Subject: [PATCH 628/1001] Update README.rst


---

diff --git a/README.rst b/README.rst
index cbb8e86..af7da7d 100644
--- a/README.rst
+++ b/README.rst
@@ -17,9 +17,13 @@ Road Map
 We are currently working towards a roadmap of the following features with a mid-October target milestone for them:
 
 # **Zanata support** - Zanata is releasing a new version in November, but we've been in contact with Alex from that team and he said he will provide us with sample data to start developing against while they work on creating the webhooks we need to get that data. So we could do a release in October that has the support (and wait for the November Zanata release to turn it on.) Specifics of what widgets Zanata support would entail for the October release is TBD. 
+
 # **IRC Integration** - We'd like to have some IRC features available in the October release via the Waartaa project.
+
 # **Badge support** -  Sayan already has a PR ready for tahrir (I believe) to add paths to badges; once that gets merged he can start working on the widget for hubs.
+
 # **Hyperkitty support** - Hyperkitty needs some new API methods to provide full post content and metadata about replies / etc. Right now the migration off of Persona is top priority as Mozilla is shutting down Persona in September, but after that Aurelien can work on this. It shouldn't be super complicated. Once completed, Hyperkitty new thread posts will appear in the feed widget and if new replies are received to the thread, it'll bounce the thread to the top of the feed widget again.
+
 # **Plusplus widget** - Aurelien and szkrepto have backend done; needs to be added to the webui.
 
 Want to get involved? Looking for something to work on?

From d5df8aff23b771d5a920440530370fb13a139fec Mon Sep 17 00:00:00 2001
From: duffy <fedora@linuxgrrl.com>
Date: Aug 23 2016 17:14:15 +0000
Subject: [PATCH 629/1001] Update README.rst


---

diff --git a/README.rst b/README.rst
index af7da7d..a0a016f 100644
--- a/README.rst
+++ b/README.rst
@@ -16,24 +16,28 @@ Road Map
 
 We are currently working towards a roadmap of the following features with a mid-October target milestone for them:
 
-# **Zanata support** - Zanata is releasing a new version in November, but we've been in contact with Alex from that team and he said he will provide us with sample data to start developing against while they work on creating the webhooks we need to get that data. So we could do a release in October that has the support (and wait for the November Zanata release to turn it on.) Specifics of what widgets Zanata support would entail for the October release is TBD. 
+1) **Zanata support** - Zanata is releasing a new version in November, but we've been in contact with Alex from that team and he said he will provide us with sample data to start developing against while they work on creating the webhooks we need to get that data. So we could do a release in October that has the support (and wait for the November Zanata release to turn it on.) Specifics of what widgets Zanata support would entail for the October release is TBD. 
 
-# **IRC Integration** - We'd like to have some IRC features available in the October release via the Waartaa project.
+2) **IRC Integration** - We'd like to have some IRC features available in the October release via the Waartaa project.
 
-# **Badge support** -  Sayan already has a PR ready for tahrir (I believe) to add paths to badges; once that gets merged he can start working on the widget for hubs.
+3) **Badge support** -  Sayan already has a PR ready for tahrir (I believe) to add paths to badges; once that gets merged he can start working on the widget for hubs.
 
-# **Hyperkitty support** - Hyperkitty needs some new API methods to provide full post content and metadata about replies / etc. Right now the migration off of Persona is top priority as Mozilla is shutting down Persona in September, but after that Aurelien can work on this. It shouldn't be super complicated. Once completed, Hyperkitty new thread posts will appear in the feed widget and if new replies are received to the thread, it'll bounce the thread to the top of the feed widget again.
+4) **Hyperkitty support** - Hyperkitty needs some new API methods to provide full post content and metadata about replies / etc. Right now the migration off of Persona is top priority as Mozilla is shutting down Persona in September, but after that Aurelien can work on this. It shouldn't be super complicated. Once completed, Hyperkitty new thread posts will appear in the feed widget and if new replies are received to the thread, it'll bounce the thread to the top of the feed widget again.
 
-# **Plusplus widget** - Aurelien and szkrepto have backend done; needs to be added to the webui.
+5) **Plusplus widget** - Aurelien and szkrepto have backend done; needs to be added to the webui.
 
 Want to get involved? Looking for something to work on?
 =======================================================
 
 * Unfamiliar with what hubs is all about? Read through these blog posts / videos with lots of information about our vision for the project:
 http://blog.linuxgrrl.com/category/fedora/fedora-hubs/
+
 * Building the development environment locally on your computer is a good beginning step to getting involved. If you have questions / run into issues, feel free to ask on #fedora-hubs in irc.freenode.net.
+
 * We meet weekly in #fedora-hubs at 1400 UTC (10 AM EDT) on irc.freenode.net. We review our statuses from the preceding week and do ticket triage too. Please join us and get acquainted!
+
 * **UX Designers** - take a look at our issues tagged 'needsmockup' that have no assignee listed and have a chat with mizmo (Máirín Duffy) for issue assignment / orientation.
+
 * **Developers** - take a look at our issues with 'normal' or 'low' priority. We're tagging issues with think are particularly good for newbies to take on with the "easy" tag.
 
 Hacking

From 09d92f102a4f68f19c7411a19b49aac49fbbc279 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Aug 23 2016 17:15:51 +0000
Subject: [PATCH 630/1001] adding old roadmap as it has useful documentation


---

diff --git a/docs/roadmap-old.txt b/docs/roadmap-old.txt
new file mode 100644
index 0000000..7f1647c
--- /dev/null
+++ b/docs/roadmap-old.txt
@@ -0,0 +1,145 @@
+Roadmap for Fedora Hubs
+
+
+    Goal: Release an awesome Hubs demo experience for 3 hand-picked teams in time for Flock in August, 2016.
+
+    Design
+
+    g11n / translations
+
+    CommOps
+
+    (Badges?)
+
+    (ambassadors?)
+
+    (Council?)
+
+    (Magazine)
+
+    ("the spirit is "places that don't get as much attention/places with lower barrier to entry.")
+
+    When to launch? End of 2016?
+
+    Ticket systems:
+
+      Design uses trac (but we can migrate to pagure maybe - commops can help migrate - we have scripts that need to be replicated)
+      Commops uses Trac (but we could also migrate to pagure)
+      G11n/translations use BZ
+      Badges uses trac
+
+Platform Roadmap
+[X] Add widget to a hub
+[X] Remove widget from a hub
+[  ] Create hub
+[  ] Edit hub
+    [X] Re-order widget
+    [  ] Edit admins
+    [  ] Archive hub
+[x] Join a hub
+[x] Leave a hub
+[  ] List all groups/hubs
+[x] Login (Ipsilon custom theme, file ticket against ) 
+[x] Subscribe to hub (become lurker, no FAS integration)
+[  ] Bookmarks bar (manage bookmarks) <= devyani7
+[  ] Investigate JS frameworks for the UI
+[  ] Write down the SSE server serving fedmsg messages to the hubs
+     -> Integrate this into FMN itself might be an interesting approach
+     -> Stress test that server
+[  ] "View More" system for ellipsed widgets (modal?)
+
+Platform-Supporting Infra Roadmap
+
+
+
+Widget Roadmap
+
+[  ]  IRC  (rtnpro / sayan)
+[  ]  Badges Map/Grid (decause / mizmo design, implement sayan)
+[  ] Hyperkitty (no reply, display and link)
+[  ] Tickets - need various templates for widget https://pagure.io/fedora-hubs/issue/1
+[  ] Tickets - need support for trac (3 of our 4 targeted teams use trac)   
+[  ] Meeting minutes 
+[  ] Meeting reminders
+     Reminder goes in the feed widget => it's a notification card, not statically placed, left-hand side widget
+[x] Meeting display widget (per team, display their regular meeting times and link to their fedocal)
+     -> meeting display widget is a permanent right col widget displayed on team/project hubs
+[  ] User FAS group membership widget (will need filtering) / Team roster widget for team/project hubs
+[  ] Zanata widget for G11n team
+[  ] CommOps #halp widget (DNE) <= is this done? (mizmo)
+[  ] Release Tasks Countdown Widget (DNE) <= is this done? (mizmo)
+
+
+Tickets, Wiki, Meeting Logs, Fedocal, Badges Paths
+
+Infra Hooked Widgets Roadmap
+
+[  ] Hyperkitty inline reply (need API and central-auth)
+[  ] Adding meetings to fedocal from hubs (requires API call for creating, requires auth, requires thoughts :))
+[  ] Lost password (need to modify Ipsilon to have a password reset link) 
+
+    https://fedorahosted.org/fedora-infrastructure/ticket/5263
+
+[  ] Join a hub (needs interaction with FAS3, probably not going to be possible in the time frame)
+[  ] statscache (?) sayan, skamath
+      (https://github.com/fedora-infra/statscache/issues/50)
+[  ] User feed widget config (FMN)
+[  ] Group feed widget config (FMN)
+
+
+Providing Infra Apps List:
+
+    fedocal (pingou)
+
+    FAS3 (SmootherFrOgZ, puiterwijk, pingou) - plan to have stg instance before summer
+
+
+The Flock Demo:
+
+- Log Into Hubs
+- Auto-Generated User Hub (amazing)
+
+    - (has mockup) - needs work - prioritize for demo prioirty teams https://pagure.io/fedora-hubs/issue/raw/files/6beed7d9cf562725001abc14d5b341c8e689c295eaf81e23daa747003f53cfd0-profile-vs-stream_profile-someoneelse.png
+
+    - list widgets needed?
+
+  - Shows FAS Groups you are in
+     needs mockup
+        widget for 'hubs' lower right https://pagure.io/fedora-hubs/issue/raw/files/6beed7d9cf562725001abc14d5b341c8e689c295eaf81e23daa747003f53cfd0-profile-vs-stream_profile-someoneelse.png
+  - Shows badges you have received
+
+     user badges widget, mockup ready to go:  https://pagure.io/fedora-hubs/issue/85
+
+  - Shows Feed of your fedmsg Activity
+      I want to examine fedmsg activity for users in our target teams and analyze it a bit - use this link https://apps.fedoraproject.org/datagrepper/raw?user=duffy (JSON will give raw msg)
+- Go to Design Team Hub via bookmarks bar
+       (need info on bookmarks bar spec here for devyani7)
+  - Shows Team members
+      needsmockup
+  - Shows HK Posts
+  - Shows IRC channel (level 1)
+  - Shows Fedocal for Upcoming meetings done
+  - Shows Wiki-tree for "legacy" info
+  - Shows Meeting Logs for previous meetings
+- Go to g11n Team Hub
+  - Show g11n specific widget1 (Zanata)
+  - Show g11n specific widget2 (Zanata)
+  - Show BZ-configured tickets widget
+     needsmockup
+- Go to CommOps Hub
+  - Show specialized CommOps widgets:
+      - #halp widget (DNE)
+          ticket #:
+      - Release Tasks Countdown Widget (DNE)
+      - others
+- Go to Team Hub you haven't joined yet
+  - Subscribe to Team Hub
+  - Shows Badges Path for joining the team
+       ticket #17
+- Go to Badges Hub
+  - Show "The Grid" of all the badges (!!!)
+  - Show paths for each team (even ones without Hubs yet)
+- Go to Team Hub that doesn't exist yet, Hype++
+- Mobile view (level 2) 
+
+

From 4d3330114b8756e2b25a12ece7931c364c6243c4 Mon Sep 17 00:00:00 2001
From: wispfox <wispfox@gmail.com>
Date: Aug 26 2016 21:36:14 +0000
Subject: [PATCH 631/1001] Update README.rst


Added instructions for how to deal with packages in pip that need upgrading.
---

diff --git a/README.rst b/README.rst
index a0a016f..20bb15a 100644
--- a/README.rst
+++ b/README.rst
@@ -75,6 +75,10 @@ OK -- with that done, now install the dependencies from PyPI::
 
     $ pip install -r requirements.txt
 
+If anything complains about having an old version, you can update it with the following, after replacing [packagename] with the package in question::
+
+	$ pip install --upgrade [packagename]
+
 Configure the project to authenticate against iddev.fedorainfraclouid.org::
 
     oidc-register --debug https://iddev.fedorainfracloud.org/ http://localhost:5000

From 195e6ccd3316188716f290f55e14a7913c25be1f Mon Sep 17 00:00:00 2001
From: wispfox <wispfox@gmail.com>
Date: Aug 26 2016 21:38:19 +0000
Subject: [PATCH 632/1001] Update README.rst


Explanation of why replacing the cert file is relevant.
---

diff --git a/README.rst b/README.rst
index 20bb15a..837eb96 100644
--- a/README.rst
+++ b/README.rst
@@ -83,7 +83,7 @@ Configure the project to authenticate against iddev.fedorainfraclouid.org::
 
     oidc-register --debug https://iddev.fedorainfracloud.org/ http://localhost:5000
 
-Replace httplib2's own ca cert file (to adjust as needed)::
+If the previous command complains about an error verifying the certificate, you will want to replace httplib2's ca cert file::
 
     cp /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
         ~/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt

From b995c42e69aaac8add526486a7a2461a0f561295 Mon Sep 17 00:00:00 2001
From: wispfox <wispfox@gmail.com>
Date: Aug 26 2016 21:44:08 +0000
Subject: [PATCH 633/1001] Update README.rst


Added more detail around running the server and dealing with the kinds of errors I ran into while trying to do so.
---

diff --git a/README.rst b/README.rst
index 837eb96..22eb4ab 100644
--- a/README.rst
+++ b/README.rst
@@ -83,7 +83,7 @@ Configure the project to authenticate against iddev.fedorainfraclouid.org::
 
     oidc-register --debug https://iddev.fedorainfracloud.org/ http://localhost:5000
 
-If the previous command complains about an error verifying the certificate, you will want to replace httplib2's ca cert file::
+If the previous command complains about an error verifying the certificate, you will want to replace httplib2's ca cert file. Afterward, re-run the above command::
 
     cp /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
         ~/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
@@ -92,9 +92,16 @@ Create a local configuration file::
 
     echo "OIDC_ID_TOKEN_COOKIE_SECURE = False" > config
 
-With that, try running the app with::
+With that, try running the app by creating the database::
 
     $ python populate.py  # To create the db
+    
+If this fails with a complaint about no module named sanitizer, or something about HTMLsanitizer, you will need to install bleach::
+
+	$ pip install bleach
+
+Finish running the app by starting the devel server with your local config file. There will be warnings, but you can safely ignore them::
+
     $ python runserver.py -c config  # To run the dev server with our local conf
 
 And then navigate to http://localhost:5000/

From 15a96bf24021a334bde195233e43359c52af51f4 Mon Sep 17 00:00:00 2001
From: Devyani Kota <divs.passion.18@gmail.com>
Date: Aug 29 2016 19:46:33 +0000
Subject: [PATCH 634/1001] Remove typo in the link to hubs hosted url


---

diff --git a/README.rst b/README.rst
index 22eb4ab..3ddaba9 100644
--- a/README.rst
+++ b/README.rst
@@ -79,7 +79,7 @@ If anything complains about having an old version, you can update it with the fo
 
 	$ pip install --upgrade [packagename]
 
-Configure the project to authenticate against iddev.fedorainfraclouid.org::
+Configure the project to authenticate against iddev.fedorainfracloud.org::
 
     oidc-register --debug https://iddev.fedorainfracloud.org/ http://localhost:5000
 
@@ -95,7 +95,7 @@ Create a local configuration file::
 With that, try running the app by creating the database::
 
     $ python populate.py  # To create the db
-    
+
 If this fails with a complaint about no module named sanitizer, or something about HTMLsanitizer, you will need to install bleach::
 
 	$ pip install bleach

From 5c519991942491a16ca507e3dd7a486bb346ec37 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Aug 30 2016 13:46:36 +0000
Subject: [PATCH 635/1001] Remove print statement from hub_add_widget_post function


---

diff --git a/hubs/app.py b/hubs/app.py
index 9484bfb..3d241f5 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -314,7 +314,6 @@ def hub_add_widget_get(name):
 
 
 def hub_add_widget_post(name):
-    print flask.request.form
     widget_name = flask.request.form.get('widget_name')
     position = flask.request.form.get('position', '').lower()
     if not widget_name:

From 2a92863490b46d4660191971b4d1b54a3630e922 Mon Sep 17 00:00:00 2001
From: duffy <fedora@linuxgrrl.com>
Date: Aug 30 2016 15:25:35 +0000
Subject: [PATCH 636/1001] Update README.rst


adding devyani's blog post for hubs newbies
---

diff --git a/README.rst b/README.rst
index 3ddaba9..73ef45f 100644
--- a/README.rst
+++ b/README.rst
@@ -32,7 +32,7 @@ Want to get involved? Looking for something to work on?
 * Unfamiliar with what hubs is all about? Read through these blog posts / videos with lots of information about our vision for the project:
 http://blog.linuxgrrl.com/category/fedora/fedora-hubs/
 
-* Building the development environment locally on your computer is a good beginning step to getting involved. If you have questions / run into issues, feel free to ask on #fedora-hubs in irc.freenode.net.
+* Building the development environment locally on your computer is a good beginning step to getting involved. If you have questions / run into issues, feel free to ask on #fedora-hubs in irc.freenode.net. Devyani put together a great blog post on how to get it working and what to expect here: https://devyani7kota.wordpress.com/2016/08/29/fedora-hubs-getting-started/
 
 * We meet weekly in #fedora-hubs at 1400 UTC (10 AM EDT) on irc.freenode.net. We review our statuses from the preceding week and do ticket triage too. Please join us and get acquainted!
 

From 0347f09003cf39b7505da0dfc45d0bc5705766a4 Mon Sep 17 00:00:00 2001
From: Kanika Murarka <kmurarka@localhost.localdomain>
Date: Sep 14 2016 19:53:01 +0000
Subject: [PATCH 637/1001] Integrated contact widget and Karma


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
index 706bb03..2a27612 100755
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -17,6 +17,13 @@ def add_user_widgets(session, hub, username, fullname):
 
     # Right Side Widgets
     widget = hubs.models.Widget(
+        plugin='contact', index=-2,
+            _config=json.dumps({
+                'username': username,
+            }))
+    hub.widgets.append(widget)
+
+    widget = hubs.models.Widget(
         plugin='meetings', index=-1,
         _config=json.dumps({
             'calendar': 'Fedora release',
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 6423e3e..5f416ed 100755
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -17,6 +17,7 @@ from hubs.widgets import githubissues
 from hubs.widgets import bugzilla
 from hubs.widgets import fhosted
 from hubs.widgets import memberships
+from hubs.widgets import contact
 
 from hubs.widgets.workflow import pendingacls
 from hubs.widgets.workflow import updates2stable
@@ -43,6 +44,7 @@ registry = {
     'bugzilla': bugzilla,
     'fedorahosted': fhosted,
     'memberships': memberships,
+    'contact': contact,
 
     'workflow.pendingacls': pendingacls,
     'workflow.updates2stable': updates2stable,
diff --git a/hubs/widgets/contact.py b/hubs/widgets/contact.py
new file mode 100644
index 0000000..b1f4df8
--- /dev/null
+++ b/hubs/widgets/contact.py
@@ -0,0 +1,58 @@
+from hubs.widgets.chrome import panel
+from hubs.widgets import templating
+
+import hubs.models
+import fedmsg.config
+import fedmsg.meta
+import datetime
+
+config = fedmsg.config.load_config()
+
+chrome = panel()
+template = templating.environment.get_template('templates/contact.html')
+position = 'both'
+
+
+# TODO: update this section when FAS3 is deployed
+def data(session, widget, **kwargs):
+    hub = widget.hub
+    if hub.user_hub:
+        usergroup = True
+        user = hubs.models.User.by_username(session, hub.name)
+        email = user.username + '@fedoraproject.org'
+        fas_info = {
+                    'usergroup': usergroup,
+                    'location': 'United States',
+                    'timezone': 'UTC',
+                    'email': email,
+                    'ircnick': user.username,
+                    'account_age': 'Oct 2010',
+                   }
+    else:
+        usergroup = False
+        # TODO: update this section integrating with FAS3
+        if hub.name == 'infrastructure':
+            ircchannel = 'apps'
+            hubname = 'infrastructure'
+        elif hub.name == 'designteam':
+            ircchannel = 'design'
+            hubname = 'design'
+        elif hub.name == 'commops':
+            ircchannel == 'commops'
+            hubname = 'commops'
+        elif hub.name == 'marketing':
+            ircchannel = 'mktg'
+            hubname = 'marketing'
+        else:
+            ircchannel = hub.name
+            hubname = hub.name
+        mailinglist = 'https://lists.fedoraproject.org/archives/list/{}@lists.fedoraproject.org/'.format(hubname)
+        wikilink = 'https://fedoraproject.org/wiki/' + hubname
+        fas_info = {
+                    'usergroup': usergroup,
+                    'hubname': hubname,
+                    'ircchannel': 'fedora-%s'%ircchannel,
+                    'mailinglist': mailinglist,
+                    'wikilink': wikilink,
+                   }
+    return fas_info
diff --git a/hubs/widgets/templates/contact.html b/hubs/widgets/templates/contact.html
new file mode 100644
index 0000000..b0e2ad2
--- /dev/null
+++ b/hubs/widgets/templates/contact.html
@@ -0,0 +1,78 @@
+<div class="contactinfo-container">
+  {% if usergroup %}
+    <ul style="list-style: none">
+      <li><i class="fa fa-map-marker" aria-hidden="true"></i>
+          <span class="col-md-offset-1">{{location}}</span></li>
+      <li><i class="fa fa-clock-o" aria-hidden="true"></i>
+          <span class="col-md-offset-1">Current-Time :</span>
+          <script type="text/javascript">
+            // TODO: send offset after querying fas3
+            function calcTime(offset) {
+
+              // create Date object for current location
+              d = new Date();
+
+              // convert to msec
+              // add local time zone offset
+              // get UTC time in msec
+              utc = d.getTime() + (d.getTimezoneOffset() * 60000);
+
+              // create new Date object using supplied offset
+              nd = new Date(utc + (3600000 * offset));
+
+              // return time as a string
+              return nd.toLocaleString();
+            }
+
+            setInterval(function() {
+              $("#time").html(calcTime(-4))
+            }, 1000)
+          </script>
+          <span id="time"></span></li>
+      <li><i class="fa fa-envelope" aria-hidden="true"></i>
+          <span class="col-md-offset-1">{{email}}</span></li>
+      <li><i class="fa fa-comment" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span>{{ircnick}}</li>
+    </ul>
+    <div class="col-md-offset-2">
+        <span id="karma_current">XYZ</span>
+    </div>
+    <div class="col-md-offset-2">
+        <i class="fa fa-certificate" aria-hidden="true"></i>
+        <span>Member Since {{account_age}}</span>
+    </div>
+  {% else %}
+    <ul style="list-style: none">
+      <li><i class="fa fa-comment" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span>fedora-{{ircchannel}}</li>
+      <li><i class="fa fa-envelope" aria-hidden="true"></i>
+          <span class="col-md-offset-1"><a href="{{ mailinglist }}">{{ hubname }}@lists.fedoraproject.org</a></span></li>
+      <li><i class="fa fa-info" aria-hidden="true"></i>
+          <span class="col-md-offset-1"><a href="{{ wikilink }}">fedoraproject.org/wiki/{{ hubname }}</a></span></li>
+    </ul>
+  {% endif %}
+</div>
+
+<script type="text/javascript">
+
+function get_karma_stats() {
+    var karma_url = '{{ karma_url }}';
+    console.log("Kanika");
+    console.log(karma_url);
+      $.ajax({
+        method: "GET",
+        url: karma_url,
+        dataType: 'html',
+        success: function(html) {
+          console.log('Success: ' + html);
+          karma_arr = JSON.stringify(html);
+          $('#karma_current').html(karma_arr['current']);
+        },
+        error: function() {
+          console.log('Error: getting karma');
+        },
+      });
+    }
+get_karma_stats()
+
+</script>
diff --git a/populate.py b/populate.py
index 986d5b5..5c34700 100755
--- a/populate.py
+++ b/populate.py
@@ -26,6 +26,8 @@ hub = hubs.models.Hub(
     name='i18n', summary='The Internationalization Team', archived=True)
 session.add(hub)
 
+widget = hubs.models.Widget(plugin='contact', index=-1)
+hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
@@ -69,6 +71,8 @@ session.commit()
 hub = hubs.models.Hub(name='commops', summary='The Fedora Community Operations Team')
 session.add(hub)
 
+widget = hubs.models.Widget(plugin='contact', index=-1)
+hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
@@ -114,6 +118,8 @@ session.commit()
 hub = hubs.models.Hub(name='marketing', summary='The Fedora Marketing Team')
 session.add(hub)
 
+widget = hubs.models.Widget(plugin='contact', index=-1)
+hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
@@ -160,6 +166,8 @@ session.commit()
 hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
 session.add(hub)
 
+widget = hubs.models.Widget(plugin='contact', index=-1)
+hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,
@@ -207,6 +215,8 @@ session.commit()
 hub = hubs.models.Hub(name='infrastructure', summary='The Fedora Infra Team')
 session.add(hub)
 
+widget = hubs.models.Widget(plugin='contact', index=-1)
+hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='rules', index=1,

From c73e0540a8143aeb6e9f7589034e887da276e6fd Mon Sep 17 00:00:00 2001
From: Kanika Murarka <murarkakanika@gmail.com>
Date: Sep 14 2016 19:53:47 +0000
Subject: [PATCH 638/1001] Fixed plus plus widget in contact profile


---

diff --git a/hubs/app.py b/hubs/app.py
index 3d241f5..3862a24 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -10,7 +10,7 @@ import flask.json
 import munch
 
 from flask.ext.oidc import OpenIDConnect
-from requests import request
+import requests
 
 import hubs.models
 import hubs.widgets
@@ -737,17 +737,14 @@ def hub_leave(hub):
 @app.route('/plus_plus/<user>/status', methods=['GET'])
 def plus_plus_status(user):
     receiver = hubs.models.User.by_username(session, user)
-
     if not receiver:
         return 'User does not exist', 403
-
     pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
     req = None
     try:
-        req = request('GET', pp_url)
+        req = requests.get(pp_url)
     except:
         flask.abort(500)
-
     if req.status_code == 200:
         return flask.jsonify(req.json())
     else:
diff --git a/hubs/widgets/contact.py b/hubs/widgets/contact.py
index b1f4df8..8ebce6f 100644
--- a/hubs/widgets/contact.py
+++ b/hubs/widgets/contact.py
@@ -1,6 +1,6 @@
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
-
+import flask
 import hubs.models
 import fedmsg.config
 import fedmsg.meta
@@ -20,12 +20,14 @@ def data(session, widget, **kwargs):
         usergroup = True
         user = hubs.models.User.by_username(session, hub.name)
         email = user.username + '@fedoraproject.org'
+        karma_url = flask.url_for('plus_plus_status', user=user.username)
         fas_info = {
                     'usergroup': usergroup,
                     'location': 'United States',
                     'timezone': 'UTC',
                     'email': email,
                     'ircnick': user.username,
+                    'karma_url': karma_url,
                     'account_age': 'Oct 2010',
                    }
     else:
diff --git a/hubs/widgets/templates/contact.html b/hubs/widgets/templates/contact.html
index b0e2ad2..84f7140 100644
--- a/hubs/widgets/templates/contact.html
+++ b/hubs/widgets/templates/contact.html
@@ -27,6 +27,25 @@
             setInterval(function() {
               $("#time").html(calcTime(-4))
             }, 1000)
+
+            function get_karma_stats() {
+                var karma_url = '{{ karma_url }}';
+                  $.ajax({
+                    method: "GET",
+                    url: karma_url,
+                    dataType: 'html',
+                    success: function(html) {
+                      console.log('Success: ' + html);
+                      karma_arr = JSON.parse(html);
+                      console.log(karma_arr)
+                      $('#karma_current').html("Karma : "+karma_arr['current']+" ("+karma_arr['total']+" all time)");
+                    },
+                    error: function() {
+                      console.log('Error: getting karma');
+                    },
+                  });
+                }
+            get_karma_stats()
           </script>
           <span id="time"></span></li>
       <li><i class="fa fa-envelope" aria-hidden="true"></i>
@@ -35,7 +54,7 @@
           <span class="col-md-offset-1"></span>{{ircnick}}</li>
     </ul>
     <div class="col-md-offset-2">
-        <span id="karma_current">XYZ</span>
+        <span id="karma_current"></span>
     </div>
     <div class="col-md-offset-2">
         <i class="fa fa-certificate" aria-hidden="true"></i>
@@ -52,27 +71,3 @@
     </ul>
   {% endif %}
 </div>
-
-<script type="text/javascript">
-
-function get_karma_stats() {
-    var karma_url = '{{ karma_url }}';
-    console.log("Kanika");
-    console.log(karma_url);
-      $.ajax({
-        method: "GET",
-        url: karma_url,
-        dataType: 'html',
-        success: function(html) {
-          console.log('Success: ' + html);
-          karma_arr = JSON.stringify(html);
-          $('#karma_current').html(karma_arr['current']);
-        },
-        error: function() {
-          console.log('Error: getting karma');
-        },
-      });
-    }
-get_karma_stats()
-
-</script>

From a70f2b29cf45bfa79f200b7803fc8a6da6923dac Mon Sep 17 00:00:00 2001
From: Kanika Murarka <murarkakanika@gmail.com>
Date: Sep 14 2016 19:53:47 +0000
Subject: [PATCH 639/1001] Split readme in multiple line


---

diff --git a/README.rst b/README.rst
index 73ef45f..949db86 100644
--- a/README.rst
+++ b/README.rst
@@ -16,7 +16,7 @@ Road Map
 
 We are currently working towards a roadmap of the following features with a mid-October target milestone for them:
 
-1) **Zanata support** - Zanata is releasing a new version in November, but we've been in contact with Alex from that team and he said he will provide us with sample data to start developing against while they work on creating the webhooks we need to get that data. So we could do a release in October that has the support (and wait for the November Zanata release to turn it on.) Specifics of what widgets Zanata support would entail for the October release is TBD. 
+1) **Zanata support** - Zanata is releasing a new version in November, but we've been in contact with Alex from that team and he said he will provide us with sample data to start developing against while they work on creating the webhooks we need to get that data. So we could do a release in October that has the support (and wait for the November Zanata release to turn it on.) Specifics of what widgets Zanata support would entail for the October release is TBD.
 
 2) **IRC Integration** - We'd like to have some IRC features available in the October release via the Waartaa project.
 
@@ -32,7 +32,8 @@ Want to get involved? Looking for something to work on?
 * Unfamiliar with what hubs is all about? Read through these blog posts / videos with lots of information about our vision for the project:
 http://blog.linuxgrrl.com/category/fedora/fedora-hubs/
 
-* Building the development environment locally on your computer is a good beginning step to getting involved. If you have questions / run into issues, feel free to ask on #fedora-hubs in irc.freenode.net. Devyani put together a great blog post on how to get it working and what to expect here: https://devyani7kota.wordpress.com/2016/08/29/fedora-hubs-getting-started/
+* Building the development environment locally on your computer is a good beginning step to getting involved. If you have questions / run into issues, feel free to ask on #fedora-hubs in irc.freenode.net.
+Devyani put together a great blog post on how to get it working and what to expect here: https://devyani7kota.wordpress.com/2016/08/29/fedora-hubs-getting-started/
 
 * We meet weekly in #fedora-hubs at 1400 UTC (10 AM EDT) on irc.freenode.net. We review our statuses from the preceding week and do ticket triage too. Please join us and get acquainted!
 

From beba51c37cd43a639044e5a980c597675eb2e430 Mon Sep 17 00:00:00 2001
From: Kanika Murarka <murarkakanika@gmail.com>
Date: Sep 14 2016 19:53:47 +0000
Subject: [PATCH 640/1001] Removed blog links from readme


---

diff --git a/README.rst b/README.rst
index 949db86..bed7901 100644
--- a/README.rst
+++ b/README.rst
@@ -29,12 +29,6 @@ We are currently working towards a roadmap of the following features with a mid-
 Want to get involved? Looking for something to work on?
 =======================================================
 
-* Unfamiliar with what hubs is all about? Read through these blog posts / videos with lots of information about our vision for the project:
-http://blog.linuxgrrl.com/category/fedora/fedora-hubs/
-
-* Building the development environment locally on your computer is a good beginning step to getting involved. If you have questions / run into issues, feel free to ask on #fedora-hubs in irc.freenode.net.
-Devyani put together a great blog post on how to get it working and what to expect here: https://devyani7kota.wordpress.com/2016/08/29/fedora-hubs-getting-started/
-
 * We meet weekly in #fedora-hubs at 1400 UTC (10 AM EDT) on irc.freenode.net. We review our statuses from the preceding week and do ticket triage too. Please join us and get acquainted!
 
 * **UX Designers** - take a look at our issues tagged 'needsmockup' that have no assignee listed and have a chat with mizmo (Máirín Duffy) for issue assignment / orientation.

From 01915855fecabfe17abf541ef3e116ccf01eb35d Mon Sep 17 00:00:00 2001
From: Kanika Murarka <murarkakanika@gmail.com>
Date: Sep 16 2016 13:36:00 +0000
Subject: [PATCH 641/1001] Added the suggested changes


---

diff --git a/README.rst b/README.rst
index bed7901..9ce74dc 100644
--- a/README.rst
+++ b/README.rst
@@ -28,6 +28,11 @@ We are currently working towards a roadmap of the following features with a mid-
 
 Want to get involved? Looking for something to work on?
 =======================================================
+* Unfamiliar with what hubs is all about? Read through these blog posts / videos with lots of information about our vision for the project:
+http://blog.linuxgrrl.com/category/fedora/fedora-hubs/
+
+* Building the development environment locally on your computer is a good beginning step to getting involved. If you have questions / run into issues, feel free to ask on
+#fedora-hubs in irc.freenode.net. Devyani put together a great blog post on how to get it working and what to expect here: https://devyani7kota.wordpress.com/2016/08/29/fedora-hubs-getting-started/
 
 * We meet weekly in #fedora-hubs at 1400 UTC (10 AM EDT) on irc.freenode.net. We review our statuses from the preceding week and do ticket triage too. Please join us and get acquainted!
 
diff --git a/hubs/widgets/templates/contact.html b/hubs/widgets/templates/contact.html
index 84f7140..28dd0fc 100644
--- a/hubs/widgets/templates/contact.html
+++ b/hubs/widgets/templates/contact.html
@@ -1,8 +1,8 @@
 <div class="contactinfo-container">
   {% if usergroup %}
     <ul style="list-style: none">
-      <li><i class="fa fa-map-marker" aria-hidden="true"></i>
-          <span class="col-md-offset-1">{{location}}</span></li>
+      <!--<li><i class="fa fa-map-marker" aria-hidden="true"></i>
+          <span class="col-md-offset-1">{{location}}</span></li>-->
       <li><i class="fa fa-clock-o" aria-hidden="true"></i>
           <span class="col-md-offset-1">Current-Time :</span>
           <script type="text/javascript">
@@ -52,11 +52,10 @@
           <span class="col-md-offset-1">{{email}}</span></li>
       <li><i class="fa fa-comment" aria-hidden="true"></i>
           <span class="col-md-offset-1"></span>{{ircnick}}</li>
+      <li><i class="fa fa-user-plus" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span><span id="karma_current"></span></li>
     </ul>
     <div class="col-md-offset-2">
-        <span id="karma_current"></span>
-    </div>
-    <div class="col-md-offset-2">
         <i class="fa fa-certificate" aria-hidden="true"></i>
         <span>Member Since {{account_age}}</span>
     </div>

From fd93b23de5d18f28954a6ed329f0767fbb375625 Mon Sep 17 00:00:00 2001
From: Kanika Murarka <murarkakanika@gmail.com>
Date: Sep 20 2016 14:06:22 +0000
Subject: [PATCH 642/1001] Added the suggested changes


---

diff --git a/hubs/widgets/templates/contact.html b/hubs/widgets/templates/contact.html
index 28dd0fc..7c3cccf 100644
--- a/hubs/widgets/templates/contact.html
+++ b/hubs/widgets/templates/contact.html
@@ -1,6 +1,6 @@
 <div class="contactinfo-container">
   {% if usergroup %}
-    <ul style="list-style: none">
+    <ul style="list-style: none; padding-left: 5px">
       <!--<li><i class="fa fa-map-marker" aria-hidden="true"></i>
           <span class="col-md-offset-1">{{location}}</span></li>-->
       <li><i class="fa fa-clock-o" aria-hidden="true"></i>
@@ -54,11 +54,9 @@
           <span class="col-md-offset-1"></span>{{ircnick}}</li>
       <li><i class="fa fa-user-plus" aria-hidden="true"></i>
           <span class="col-md-offset-1"></span><span id="karma_current"></span></li>
+      <li><i class="fa fa-certificate" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span> Member Since {{account_age}}</li>
     </ul>
-    <div class="col-md-offset-2">
-        <i class="fa fa-certificate" aria-hidden="true"></i>
-        <span>Member Since {{account_age}}</span>
-    </div>
   {% else %}
     <ul style="list-style: none">
       <li><i class="fa fa-comment" aria-hidden="true"></i>

From 039023bd0dbbd1bd5fdce50c11cef77f64b006fd Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Sep 28 2016 19:04:33 +0000
Subject: [PATCH 643/1001] issue #256 - fixing hubs template so vertical nav doesn't obscure header


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index fe40b05..77714a6 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -80,8 +80,8 @@
     
     /* line up header with cards below */
     header .container {
-	padding-left: 1.75rem !important;
-	}
+      padding-left: 1.75rem !important;
+    }
 
     header img.avatar {
         width: 70px;
@@ -277,11 +277,8 @@ font-size: 32pt;
 
 .nav {
   background-color: #fcfcfc;
+  min-height: 180px; 
   padding: 1.5rem;
-  position: absolute;
-  z-index: 3;
-  min-height: 200px; 
-  float: left;
 }
 
 /* navbar fedora-bootstrap overrides to make it vertical */
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 3ab75a9..9de8638 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -3,24 +3,25 @@
 {% block title %}{{ hub.name }}{% endblock %}
 {% block content %}
 
-  <div class="col-md-2">
-    <nav class="navbar navbar-light p-t-2 p-b-0">
-      <button type="button" class="navbar-toggler hidden-sm-up"
-        data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+<div class="row p-t-0">
+  <header class="p-t-1">
+    <nav class="navbar navbar-light col-md-2">
+      <button type="button" class="navbar-toggler hidden-md-up"
+        type="button" data-toggle="collapse" data-target="#vertical-navbar">
         <span class="sr-only">Toggle navigation</span>
-        <span class="oi" data-glyph="menu"></span>
+        <i class="fa fa-bars"></i>
       </button>
 
       <!-- Collect the nav links, forms, and other content for toggling -->
       {% if g.auth.logged_in %}
-      <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">
-        <ul class="nav navbar-nav">
+      <div id="vertical-navbar">
+        <ul class="nav navbar-nav p-r-1">
           <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
             <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
           <li class="p-x-1 nav-item"><a class="nav-link" href="/{{g.auth.user.username}}/stream">My Stream</a></li>
           {% for hub in g.auth.user.bookmarks %}
-          <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
-            <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
+            <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
+              <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
           {% endfor %}
           <!-- At the end of the list, tack on a link to all groups -->
           <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
@@ -28,166 +29,168 @@
       </div><!-- /.navbar-collapse -->
       {% endif %}
     </nav>
-  </div>
-  <header class="p-t-2">
-    <div class="container">
-
-    <!-- Left side of header -->
-    <div class="col-md-8">
-        {% if hub.user_hub %}
-        <img src="{{ hub.avatar }}" class="avatar" />
-      <h2 class="user m-b-0">{{ hub.name }}</h2>
-      <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
-        <div class="clearfix"></div>
-        {% else %}
-        <h2 class="team">{{ hub.name }}</h2>
-        <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
-      {% endif %}
-    </div>
-
-      <!-- right side of header -->
-      <div class="col-md-4 header-right">
-      {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
-        {% if not edit %}
+  
+    <div class="col-md-10">
+      <div class="row">
+        
+        <!-- Left side of header -->
+        <div class="col-md-7">
+          {% if hub.user_hub %}
+          <img src="{{ hub.avatar }}" class="avatar" />
+          <h2 class="user m-b-0">{{ hub.name }}</h2>
+          <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
+          <div class="clearfix"></div>
+          {% else %}
+          <h2 class="team">{{ hub.name }}</h2>
+          <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
+          {% endif %}
+        </div>
+        
+        <!-- right side of header -->
+        <div class="col-md-3 header-right">
+          {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
+          {% if not edit %}
           <div class="dropdown edit pull-xs-right showpointer">
             <span class="dropdown-toggle edit-this-page" type="button"
-                  id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
-                  aria-expanded="true">
+                id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
+                aria-expanded="true">
               <span><i class="fa fa-pencil" aria-hidden="true"></i></span> edit this page
             </span>
             <div class="dropdown-menu" aria-labelledby="dropdownMenu2">
               <a class="dropdown-item" href="#">Customize Header</a>
               <div class="dropdown-divider"></div>
               <a class="dropdown-item"
-                  href="{{ url_for('hub_edit', name=hub.name) }}">
+                href="{{ url_for('hub_edit', name=hub.name) }}">
                 Configure Hub
               </a>
               {% if not hub.user_hub %}
               <div class="dropdown-divider"></div>
-              <a class="dropdown-item" href="#">Manage Members</a>
-              <div class="dropdown-divider"></div>
-              <a class="dropdown-item" href="#">Archive Hub</a>
+                <a class="dropdown-item" href="#">Manage Members</a>
+                <div class="dropdown-divider"></div>
+                <a class="dropdown-item" href="#">Archive Hub</a>
               {% endif %}
             </div>
           </div>
-        {% else %}
+          {% else %}
           <div id="save_edits_btn" class="pull-xs-right">
             <span><i class="fa fa-download" aria-hidden="true"></i></span>
             Save changes
           </div>
-        {% endif %}
-      {% endif %}
+          {% endif %}
+          {% endif %}
+        </div>
+        
       </div>
-    </div>
-
-  </header>
-
-
-{%- with messages = get_flashed_messages(with_categories=true) -%}
-  {%- if category, messages -%}
-  <div class="container">
-    <div class="row">
-      <div class="col-md-6 col-md-offset-3">
-        <ul id="flashes" class="list-group">
-          {%- for category, message in messages -%}
-            <div class="alert {%
-              if category == 'error' %}alert-warning{%
-              else %}alert-info{%
-              endif %} alert-dismissible" role="alert">
-              <button type="button" class="close" data-dismiss="alert"
+      
+      <div class="row p-t-2">
+        {%- with messages = get_flashed_messages(with_categories=true) -%}
+        {%- if category, messages -%}
+          <div class="col-md-6 col-md-offset-3">
+            <ul id="flashes" class="list-group">
+            {%- for category, message in messages -%}
+              <div class="alert {%
+                if category == 'error' %}alert-warning{%
+                else %}alert-info{%
+                endif %} alert-dismissible" role="alert">
+                <button type="button" class="close" data-dismiss="alert"
                   aria-label="Close">
-                <span aria-hidden="true">&times;</span>
-                <span class="sr-only">Close</span>
-              </button>
-              {{ message }}
-            </div>
-          {%- endfor -%}
-        </ul>
-      </div>
-    </div>
-  </div>
-  {%- endif -%}
-{%- endwith -%}
-
-<div class="container">
-
-  <div class="row">
-
-    <div class="col-md-{{ hub.left_width }}">
-      <!--
-        First, before the proper widgets.. a cobweb built-in widget.
-        https://pagure.io/fedora-hubs/issue/133
-      -->
-      {% if hub.archived or hub.last_refreshed | days_since > 31 %}
-      <ul class="media-list">
-        <li class="media">
-          <div class="media-left">
-          {% if hub.archived %}
-            <img class="media-object square-32"
-              src="{{ url_for('static', filename='img/archived.png') }}"/>
-          {% else %}
-            <img class="media-object square-32"
-              src="{{ url_for('static', filename='img/cobweb.png') }}"/>
-          {% endif %}
+                  <span aria-hidden="true">&times;</span>
+                  <span class="sr-only">Close</span>
+                </button>
+                {{ message }}
+              </div>
+            {%- endfor -%}
+            </ul>
           </div>
-          <div class="media-body">
-          {% if hub.archived %}
-            This hub has been archived and locked.
-          {% else %}
-            Cobweb alert!  This hub was last active {{
-                hub.last_refreshed | days_since }} days ago.
+        </div>
+        {%- endif -%}
+        {%- endwith -%}
+        
+
+        <div class="col-md-{{ hub.left_width }}">
+          <!--
+            First, before the proper widgets.. a cobweb built-in widget.
+            https://pagure.io/fedora-hubs/issue/133
+          -->
+          {% if hub.archived or hub.last_refreshed | days_since > 31 %}
+          <ul class="media-list">
+            <li class="media">
+              <div class="media-left">
+              {% if hub.archived %}
+                <img class="media-object square-32"
+                  src="{{ url_for('static', filename='img/archived.png') }}"/>
+              {% else %}
+                <img class="media-object square-32"
+                  src="{{ url_for('static', filename='img/cobweb.png') }}"/>
+              {% endif %}
+              </div>
+              <div class="media-body">
+                {% if hub.archived %}
+                This hub has been archived and locked.
+                {% else %}
+                Cobweb alert!  This hub was last active {{
+                  hub.last_refreshed | days_since }} days ago.
+                {% endif %}
+              </div>
+            </li>
+          </ul>
           {% endif %}
+
+          {% if edit %}
+          <div id='add-widget-left' class='widget row'>
+            <div class="card">
+              <div class="card-block">
+                <h4>
+                <a href="#" class="add_widget" data-position="left">
+                  <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
+                </a>
+                </h4>
+              </div>
+            </div>
           </div>
-        </li>
-      </ul>
-      {% endif %}
+          {% endif %}
 
-      {% if edit %}
-      <div id='add-widget-left' class='widget row'>
-        <div class="card">
-          <div class="card-block">
-            <h4>
-              <a href="#" class="add_widget" data-position="left">
-                <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
-              </a>
-            </h4>
+          <div id="left_widgets">
+          {% for widget in hub.left_widgets %}
+            <div id="widget-{{ widget.idx }}" class="widget row"></div>
+          {% endfor %}
           </div>
         </div>
-      </div>
-      {% endif %}
 
-      <div id="left_widgets">
-        {% for widget in hub.left_widgets %}
-        <div id="widget-{{ widget.idx }}" class="widget row"></div>
-        {% endfor %}
-      </div>
-    </div>
-
-    <div class="col-md-{{ hub.right_width }}">
-      {% if edit %}
-      <div id='add-widget-right' class='widget row'>
-        <div class="card">
-          <div class="card-block">
-            <h4>
-              <a href="#" class="add_widget" data-position="right">
+        <div class="col-md-{{ hub.right_width }}">
+          {% if edit %}
+          <div id='add-widget-right' class='widget row'>
+            <div class="card">
+              <div class="card-block">
+                <h4>
+                <a href="#" class="add_widget" data-position="right">
                 <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
-              </a>
-            </h4>
+                </a>
+                </h4>
+              </div>
+            </div>
+          </div>
+          {% endif %}
+
+          <div id="right_widgets">
+            {% for widget in hub.right_widgets %}
+            <div id="widget-{{ widget.idx }}" class="widget row"></div>
+            {% endfor %}
           </div>
         </div>
-      </div>
-      {% endif %}
 
-      <div id="right_widgets">
-        {% for widget in hub.right_widgets %}
-        <div id="widget-{{ widget.idx }}" class="widget row"></div>
-        {% endfor %}
-      </div>
+      </div>      
+      
+    
     </div>
-
-  </div>
+  </header>
 </div>
 
+      
+
+
+
+
 <div id="edit_modal" class="modal fade" role="dialog">
   <div class="modal-dialog" id="edit_modal_content">
   </div>

From ece01ea7c48861a342ab22f58d16652f44f960d4 Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Sep 29 2016 13:42:27 +0000
Subject: [PATCH 644/1001] Add a Vagrantfile and Ansible role


This is a first pass at a Vagrantfile and Ansible role to automate the
setup of a development environment. This also adds a basic dev guide
document which, at the moment, only includes Vagrant instructions. I
plan to organize the documentation and update the README in a separate
commit.

closes #254

Signed-off-by: Jeremy Cline <jeremy@jcline.org>

---

diff --git a/.gitignore b/.gitignore
index 096613a..357e7b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,10 @@ scratch/
 npm-debug.log
 client_secrets.json
 hubs.js
+
+# Vagrant and Ansible files
+Vagrantfile
+.dnf-cache
+*.retry
+*.pem
+config
diff --git a/Vagrantfile.example b/Vagrantfile.example
new file mode 100644
index 0000000..7fff78d
--- /dev/null
+++ b/Vagrantfile.example
@@ -0,0 +1,63 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+VAGRANTFILE_API_VERSION = "2"
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+ config.vm.box = "fedora/24-cloud-base"
+
+ # Forward traffic on the host to the development server on the guest
+ config.vm.network "forwarded_port", guest: 5000, host: 5000
+
+ # Comment out if you don't want Vagrant to add and remove entries from /etc/hosts for each VM.
+ # requires the vagrant-hostmanager plugin to be installed
+ if Vagrant.has_plugin?("vagrant-hostmanager")
+     config.hostmanager.enabled = true
+     config.hostmanager.manage_host = true
+ end
+
+ # Vagrant can share the source directory using rsync, NFS, or SSHFS (with the vagrant-sshfs
+ # plugin). By default it rsyncs the current working directory to /vagrant. We disable this
+ # in favor of SSHFS.
+ #
+ # If you would prefer to use NFS to share the directory uncomment this and configure NFS
+ #config.vm.synced_folder ".", "/vagrant", type: "nfs", nfs_version: 4, nfs_udp: false
+ config.vm.synced_folder ".", "/vagrant", disabled: true
+ config.vm.synced_folder ".", "/home/vagrant/devel", type: "sshfs", sshfs_opts_append: "-o nonempty"
+
+ # To cache update packages (which is helpful if frequently doing `vagrant destroy && vagrant up`)
+ # you can create a local directory and share it to the guest's DNF cache. The directory needs to
+ # exist, so create it before you uncomment the line below.
+ #config.vm.synced_folder ".dnf-cache", "/var/cache/dnf", type: "sshfs", sshfs_opts_append: "-o nonempty"
+
+ # Comment this line if you would like to disable the automatic update during provisioning
+ config.vm.provision "shell", inline: "sudo dnf upgrade -y"
+
+ # Install packages required for Ansible and configure everything with ansible
+ config.vm.provision "shell", inline: "sudo dnf -y install python2-dnf libselinux-python"
+ config.vm.provision "ansible" do |ansible|
+     ansible.playbook = "ansible/vagrant-playbook.yml"
+ end
+
+
+ # Create the "pagure" box
+ config.vm.define "hubs" do |hubs|
+    hubs.vm.host_name = "hubs-dev.example.com"
+
+    hubs.vm.provider :libvirt do |domain|
+        # Season to taste
+        domain.cpus = 4
+        domain.graphics_type = "spice"
+        domain.memory = 2048
+        domain.video_type = "qxl"
+
+        # Uncomment the following line if you would like to enable libvirt's unsafe cache
+        # mode. It is called unsafe for a reason, as it causes the virtual host to ignore all
+        # fsync() calls from the guest. Only do this if you are comfortable with the possibility of
+        # your development guest becoming corrupted (in which case you should only need to do a
+        # vagrant destroy and vagrant up to get a new one).
+        #
+        #domain.volume_cache = "unsafe"
+    end
+ end
+end
diff --git a/ansible/roles/hubs-dev/files/bashrc b/ansible/roles/hubs-dev/files/bashrc
new file mode 100644
index 0000000..615b5df
--- /dev/null
+++ b/ansible/roles/hubs-dev/files/bashrc
@@ -0,0 +1,39 @@
+# .bashrc
+
+# Source global definitions
+if [ -f /etc/bashrc ]; then
+    . /etc/bashrc
+fi
+
+# Uncomment the following line if you don't like systemctl's auto-paging feature:
+# export SYSTEMD_PAGER=
+
+# User specific aliases and functions
+# If adding new functions to this file, note that you can add help text to the function
+# by defining a variable with name _<function>_help containing the help text
+
+# Set up virtualenvwrapper
+export WORKON_HOME=$HOME/.virtualenvs
+export PIP_VIRTUALENV_BASE=$WORKON_HOME
+export VIRTUALENV_USE_DISTRIBUTE=true
+export PIP_RESPECT_VIRTUALENV=true
+source /usr/bin/virtualenvwrapper.sh
+
+export HUBS_CONFIG=~/devel/config
+
+
+hup() {
+    workon hubs
+    pushd ~/devel/
+    python ./runserver.py --host 0.0.0.0
+}
+
+hreset() {
+    workon hubs
+    rm /var/tmp/hubs.db
+    rm /var/tmp/fedora-hubs-cache.db
+    pushd ~/devel/
+    python populate.py
+    popd
+    deactivate
+}
diff --git a/ansible/roles/hubs-dev/files/datanommer.py b/ansible/roles/hubs-dev/files/datanommer.py
new file mode 100644
index 0000000..30de6fb
--- /dev/null
+++ b/ansible/roles/hubs-dev/files/datanommer.py
@@ -0,0 +1,4 @@
+config = {
+    'datanommer.enabled': True,
+    'datanommer.sqlalchemy.url': 'postgres://datanommer@localhost/datanommer',
+}
diff --git a/ansible/roles/hubs-dev/files/hubs_config b/ansible/roles/hubs-dev/files/hubs_config
new file mode 100644
index 0000000..83417df
--- /dev/null
+++ b/ansible/roles/hubs-dev/files/hubs_config
@@ -0,0 +1,4 @@
+# Enter any hubs configuratio here
+
+# Allow the cookie to be sent of http since we work on localhost
+OIDC_ID_TOKEN_COOKIE_SECURE = False
diff --git a/ansible/roles/hubs-dev/files/motd b/ansible/roles/hubs-dev/files/motd
new file mode 100644
index 0000000..f3d92ab
--- /dev/null
+++ b/ansible/roles/hubs-dev/files/motd
@@ -0,0 +1,18 @@
+
+Welcome to the Fedora Hubs development environment!
+
+Here are some tips:
+
+* The code for Fedora Hubs is located at ~/devel/
+
+* You can type `workon hubs` to enter a configured Python virtualenv
+
+* Run `hup` to start gunicorn
+
+* Run `hreset` to delete the database and repopulate it
+
+Once you run `hup` you can navigate to http://localhost:5000/
+in your browser.
+
+Happy hacking!
+
diff --git a/ansible/roles/hubs-dev/files/pg_hba.conf b/ansible/roles/hubs-dev/files/pg_hba.conf
new file mode 100644
index 0000000..fb47623
--- /dev/null
+++ b/ansible/roles/hubs-dev/files/pg_hba.conf
@@ -0,0 +1,14 @@
+# PostgreSQL Client Authentication Configuration File
+# ===================================================
+#
+# Refer to the "Client Authentication" section in the PostgreSQL
+# documentation for a complete description of this file.
+
+# TYPE  DATABASE        USER            ADDRESS                 METHOD
+
+# "local" is for Unix domain socket connections only
+local   all             all                                     trust
+# IPv4 local connections:
+host    all             all             127.0.0.1/32            trust
+# IPv6 local connections:
+host    all             all             ::1/128                 trust
diff --git a/ansible/roles/hubs-dev/handlers/main.yml b/ansible/roles/hubs-dev/handlers/main.yml
new file mode 100644
index 0000000..5d4ca3e
--- /dev/null
+++ b/ansible/roles/hubs-dev/handlers/main.yml
@@ -0,0 +1,5 @@
+- name: restart postgresql
+  service: name=postgresql state=restarted
+
+- name: restart fedmsg-hub
+  service: name=fedmsg-hub state=restarted
diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
new file mode 100755
index 0000000..c9add18
--- /dev/null
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -0,0 +1,179 @@
+---
+- name: Install helpful development packages
+  dnf: name={{ item }} state=present
+  with_items:
+    - git
+    - vim-enhanced
+
+- name: Install Fedora Hubs development packages
+  dnf: name={{ item }} state=present
+  with_items:
+    - gcc
+    - gcc-c++
+    - libffi-devel
+    - openssl-devel
+    - postgresql
+    - postgresql-devel
+    - python-sphinx
+    - python-virtualenvwrapper
+    - python2-devel
+    - python3-devel
+    - redhat-rpm-config
+    - sqlite-devel
+
+- name: Install the distribution versions of requirements.txt
+  dnf: name={{ item }} state=present
+  with_items:
+    - python-arrow
+    - python-bleach
+    - python-datanommer-models
+    - python-decorator
+    - python-dogpile-cache
+    - python-fedmsg-core
+    - python-fedmsg-meta-fedora-infrastructure
+    - python-flask
+    - python3-flask-oidc
+    - python-fmn-lib
+    - python-fmn-rules
+    - python-gunicorn
+    - python-html5lib
+    - python-munch
+    - python-psycopg2
+    - pytz
+    - python-sqlalchemy
+    - python-markdown
+    - python-pkgwat-api
+    - python-six
+    - python-pygments
+    - python-pygments-markdown-lexer
+    - python-retask
+
+- name: Install packages for datanommer
+  dnf: name={{ item }} state=present
+  with_items:
+    - datanommer-commands
+    - fedmsg-hub
+    - npm
+    - postgresql-server
+    - python-datanommer-consumer
+    - python-fedmsg-meta-fedora-infrastructure
+    - python-psycopg2
+
+
+# Add various helpful configuration files
+- name: Install a custom bashrc
+  copy: src=bashrc dest=/home/{{ ansible_env.SUDO_USER }}/.bashrc
+
+- name: Install the message of the day
+  copy: src=motd dest=/etc/motd
+
+
+# Set up Postgres, create the necessary databases, and start up datanommer
+- name: Set up postgresql database
+  command: postgresql-setup --initdb
+  args:
+      creates: /var/lib/pgsql/data/base
+
+- name: Set up postgresql access rules to allow local access
+  copy:
+      src: pg_hba.conf
+      dest: /var/lib/pgsql/data/pg_hba.conf
+      owner: postgres
+      group: postgres
+      mode: 0600
+  notify: restart postgresql
+
+- name: Start and enable postgresql
+  service: name=postgresql state=started enabled=yes
+
+- name: Set up datanommer DB user
+  postgresql_user:
+      name: datanommer
+      role_attr_flags: SUPERUSER,LOGIN
+
+- name: Create datanommer database
+  postgresql_db:
+      name: datanommer
+      owner: datanommer
+
+- name: Set up datanommer
+  copy: src=datanommer.py dest=/etc/fedmsg.d/datanommer.py
+  notify: restart fedmsg-hub
+
+# TODO unfortunately this always runs as there doesn't appear to be
+# an easy way to check if it needs to run
+- name: Create datanommer database tables
+  command: datanommer-create-db
+
+- name: Start and enable fedmsg-hub
+  service: name=fedmsg-hub state=started enabled=yes
+
+
+# Set up the Python development environment
+- name: Install Fedora Hubs requirements.txt into hubs virtualenv
+  become_user: "{{ ansible_env.SUDO_USER }}"
+  pip:
+    requirements: /home/{{ ansible_env.SUDO_USER }}/devel/requirements.txt
+    virtualenv: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/
+
+- name: Install Fedora Hubs test-requirements.txt into hubs virtualenv
+  become_user: "{{ ansible_env.SUDO_USER }}"
+  pip:
+    requirements: /home/{{ ansible_env.SUDO_USER }}/devel/requirements.txt
+    virtualenv: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/
+
+- name: Install bleach into hubs virtualenv
+  become_user: "{{ ansible_env.SUDO_USER }}"
+  pip:
+    name: bleach
+    virtualenv: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/
+
+- name: Install gunicorn into hubs virtualenv
+  become_user: "{{ ansible_env.SUDO_USER }}"
+  pip:
+    name: gunicorn
+    virtualenv: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/
+
+- name: Update httplib2 trust store
+  copy:
+    src: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
+    dest: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
+    remote_src: True
+
+- name: Add a basic Hubs configuration file
+  copy: src=hubs_config dest=/home/{{ ansible_env.SUDO_USER }}/devel/config
+  become_user: "{{ ansible_env.SUDO_USER }}"
+
+- name: Configure application to authenticate with iddev.fedorainfracloud.org
+  shell: >
+      source ~/.bashrc &&
+      workon hubs &&
+      oidc-register https://iddev.fedorainfracloud.org/ http://localhost:5000
+  become_user: "{{ ansible_env.SUDO_USER }}"
+  args:
+    creates: client_secrets.json
+    chdir: "/home/{{ ansible_env.SUDO_USER }}/devel/"
+
+- name: Populate the Fedora Hubs database
+  shell: >
+      source ~/.bashrc &&
+      workon hubs &&
+      python populate.py
+  become_user: "{{ ansible_env.SUDO_USER }}"
+  args:
+    creates: /var/tmp/hubs.db
+    chdir: "/home/{{ ansible_env.SUDO_USER }}/devel/"
+
+# Set up JavaScript requirements
+- name: Install npm packages
+  command: npm install
+  become_user: "{{ ansible_env.SUDO_USER }}"
+  args:
+    creates: node_modules
+    chdir: /home/{{ ansible_env.SUDO_USER }}/devel/hubs/static/client
+
+- name: Build JavaScript assests
+  command: node_modules/.bin/webpack
+  become_user: "{{ ansible_env.SUDO_USER }}"
+  args:
+    chdir: /home/{{ ansible_env.SUDO_USER }}/devel/hubs/static/client
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
new file mode 100644
index 0000000..14cbf9f
--- /dev/null
+++ b/ansible/vagrant-playbook.yml
@@ -0,0 +1,7 @@
+---
+- hosts: all
+  become: true
+  become_method: sudo
+  vars:
+  roles:
+    - hubs-dev
diff --git a/dev-guide.rst b/dev-guide.rst
new file mode 100644
index 0000000..fda1d46
--- /dev/null
+++ b/dev-guide.rst
@@ -0,0 +1,44 @@
+Developer Setup
+===============
+
+This guide should get you up and running with a development environment.
+The simpliest way to stand up a development environment is to use
+`Vagrant <https://www.vagrantup.com/docs/>`_, but it is also easy to set
+up a development environment without Vagrant.
+
+Vagrant
+^^^^^^^
+
+A ``Vagrantfile`` called ``Vagrantfile.example`` is provided in the root of the
+`Fedora Hub repository <https://pagure.io/fedora-hubs/>`_. To use it, simply
+copy ``Vagrantfile.example`` to ``Vagrantfile`` and modify it as you see fit.
+All settings are documented inline.
+
+If you do not have Vagrant set up, follow these steps:
+
+#. Install Ansible, Vagrant, and several helpful Vagrant plugins::
+
+   $ sudo dnf install ansible vagrant-libvirt vagrant-sshfs vagrant-hostmanager
+
+#. Create and configure the virtual machine::
+
+   $ vagrant up --provider=libvirt
+   $ vagrant reload  # Reboot the machine to use the latest kernel, etc.
+
+#. You can now use ssh to connect to the machine::
+
+   $ vagrant ssh
+
+#. If you ever want to re-run the provisioning scripts, you can::
+
+   $ vagrant provision
+
+#. If you decide you want a fresh development environment, simply destroy your
+   virtual machine and recreate it::
+
+   $ vagrant destroy && vagrant up
+
+You should now be able to point the browser in your host at http://localhost:5000/
+and use Fedora Hubs after you start the development server in the virtual machine.
+
+Happy hacking!

From 9de445398824efe96fcee5efa534f5dbe9357dda Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Oct 01 2016 17:11:51 +0000
Subject: [PATCH 645/1001] Some code beautification in bugzilla widget


---

diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
index 856f975..a33e318 100644
--- a/hubs/widgets/bugzilla.py
+++ b/hubs/widgets/bugzilla.py
@@ -11,11 +11,15 @@ chrome = panel("Bugzilla: Issues")
 template = templating.environment.get_template('templates/bugzilla.html')
 position = 'right'
 
+
 @argument(name="username",
           default=None,
           validator=validators.username,
           help="A FAS username.")
 def data(session, widget, username):
+    ''' Returns data for Bugzilla Widget. Queries pkgdb api for package
+    list of the user and bugzilla for correspoding issues '''
+
     pkgdb_url = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
     url = "/".join([pkgdb_url, username])
     response = requests.get(url)
@@ -23,48 +27,51 @@ def data(session, widget, username):
 
     issues = []
 
+    # get the packages of which the user is
+    # point of contact
     for package in data["point of contact"]:
         if len(issues) == 3:
             break
-        else:
-            pkg_details=pkgwat.api.bugs(package['name'])
-            for row in pkg_details['rows']:
-                if len(issues) == 3:
-                    break
-                else:
-                    issues.append(
-                        dict(
-                          id=row['id'],
-                          title=row['description'],
-                          pkg_name=package['name'],
-                          )
-                        )
+        pkg_details = pkgwat.api.bugs(package['name'])
+        for row in pkg_details['rows']:
+            if len(issues) == 3:
+                break
+            issues.append(
+                dict(
+                    id=row['id'],
+                    title=row['description'],
+                    pkg_name=package['name'],
+                )
+            )
 
+    # get the packages of which the user is
+    # co maintainer
     for package in data["co-maintained"]:
         if len(issues) == 3:
             break
-        else:
-            pkg_details=pkgwat.api.bugs(package['name'])
-            for row in pkg_details['rows']:
-                if len(issues) == 3:
-                    break
-                else:
-                    issues.append(
-                        dict(
-                            id=row['id'],
-                            title=row['description'],
-                            pkg_name=package['name'],
-                            )
-                        )
+        pkg_details = pkgwat.api.bugs(package['name'])
+        for row in pkg_details['rows']:
+            if len(issues) == 3:
+                break
+            issues.append(
+                dict(
+                    id=row['id'],
+                    title=row['description'],
+                    pkg_name=package['name'],
+                )
+            )
 
     return dict(
-      username=username,
-      issues=issues,
+        username=username,
+        issues=issues,
     )
 
 
 @hint(categories=['bugzilla'])
 def should_invalidate(message, session, widget):
+    ''' Validate if the bugzilla widget cache needs an update
+    This is called by a backend daemon listening to fedmsg '''
+
     # TODO -- wrap this pkgdb pull in another invalidatible cache.
     username = widget.config['username']
     pkgdb_url = "https://admin.fedoraproject.org/pkgdb/api/packager/package"

From 166b4fd6387ee4620bbedbb1d7151509a47d4f12 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Oct 05 2016 10:03:26 +0000
Subject: [PATCH 646/1001] some beautification for contact widget


---

diff --git a/hubs/widgets/contact.py b/hubs/widgets/contact.py
index 8ebce6f..b76873c 100644
--- a/hubs/widgets/contact.py
+++ b/hubs/widgets/contact.py
@@ -1,10 +1,10 @@
-from hubs.widgets.chrome import panel
-from hubs.widgets import templating
 import flask
-import hubs.models
+
 import fedmsg.config
 import fedmsg.meta
-import datetime
+import hubs.models
+from hubs.widgets.chrome import panel
+from hubs.widgets import templating
 
 config = fedmsg.config.load_config()
 
@@ -15,6 +15,11 @@ position = 'both'
 
 # TODO: update this section when FAS3 is deployed
 def data(session, widget, **kwargs):
+    ''' Data for Contact widget. Checks if the hub associated
+    with widget is of a user or not. If the hub is of a user, return
+    data related to the user else, hub is of a fedora team
+    - return data related to the team '''
+
     hub = widget.hub
     if hub.user_hub:
         usergroup = True
@@ -22,14 +27,14 @@ def data(session, widget, **kwargs):
         email = user.username + '@fedoraproject.org'
         karma_url = flask.url_for('plus_plus_status', user=user.username)
         fas_info = {
-                    'usergroup': usergroup,
-                    'location': 'United States',
-                    'timezone': 'UTC',
-                    'email': email,
-                    'ircnick': user.username,
-                    'karma_url': karma_url,
-                    'account_age': 'Oct 2010',
-                   }
+            'usergroup': usergroup,
+            'location': 'United States',
+            'timezone': 'UTC',
+            'email': email,
+            'ircnick': user.username,
+            'karma_url': karma_url,
+            'account_age': 'Oct 2010',
+        }
     else:
         usergroup = False
         # TODO: update this section integrating with FAS3
@@ -39,22 +44,20 @@ def data(session, widget, **kwargs):
         elif hub.name == 'designteam':
             ircchannel = 'design'
             hubname = 'design'
-        elif hub.name == 'commops':
-            ircchannel == 'commops'
-            hubname = 'commops'
         elif hub.name == 'marketing':
             ircchannel = 'mktg'
             hubname = 'marketing'
         else:
             ircchannel = hub.name
             hubname = hub.name
-        mailinglist = 'https://lists.fedoraproject.org/archives/list/{}@lists.fedoraproject.org/'.format(hubname)
+        mailinglist = 'https://lists.fedoraproject.org/archives/list/{}'
+        '@lists.fedoraproject.org/'.format(hubname)
         wikilink = 'https://fedoraproject.org/wiki/' + hubname
         fas_info = {
-                    'usergroup': usergroup,
-                    'hubname': hubname,
-                    'ircchannel': 'fedora-%s'%ircchannel,
-                    'mailinglist': mailinglist,
-                    'wikilink': wikilink,
-                   }
+            'usergroup': usergroup,
+            'hubname': hubname,
+            'ircchannel': 'fedora-%s' % ircchannel,
+            'mailinglist': mailinglist,
+            'wikilink': wikilink,
+        }
     return fas_info

From 8be6a4fcbe56d9fc1041c26bf2cf3cf74ebd79b3 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Oct 05 2016 10:03:31 +0000
Subject: [PATCH 647/1001] some beautification for fedorahosted widget


---

diff --git a/hubs/widgets/fhosted.py b/hubs/widgets/fhosted.py
index 6a54827..c2bcd45 100644
--- a/hubs/widgets/fhosted.py
+++ b/hubs/widgets/fhosted.py
@@ -1,16 +1,15 @@
+from xmlrpclib import ServerProxy
+
+import hubs.validators as validators
 from hubs.widgets.chrome import panel
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.widgets import templating
-import hubs.validators as validators
-import requests
 
 chrome = panel("Fedorahosted: Open Tickets")
 template = templating.environment.get_template('templates/fedorahosted.html')
 position = 'right'
 
-from xmlrpclib import ServerProxy
-
 
 @argument(name="project",
           default=None,
@@ -21,11 +20,17 @@ from xmlrpclib import ServerProxy
           validator=validators.integer,
           help="The number of tickets to display.")
 def data(session, widget, project, n_tickets=4):
+    ''' Data for Fedorahosted widget.
+    Queries Fedorahosted via xmlrpc for tickets. '''
+
     n_tickets = int(n_tickets)
     url = 'https://fedorahosted.org/%s/rpc' % project
     filters = 'status=accepted&status=assigned&status=new&status=reopened'\
         '&col=id&col=summary&col=status&col=owner&col=type&col=priority'\
         '&col=milestone&col=changetime&order=changetime'
+
+    # get the tickets based on the filters
+    # returns a list of ticket ids
     try:
         server = ServerProxy(url)
         tickets = server.ticket.query(filters)
@@ -36,14 +41,13 @@ def data(session, widget, project, n_tickets=4):
 
     output = []
     total_tickets = len(tickets)
-    for idx, ticket in enumerate(tickets):
+    for ticket in tickets[:n_tickets]:
+        # get the details of the ticket
         ticket = server.ticket.get(ticket)
         data = ticket[3]
         data['id'] = ticket[0]
         data['short_summary'] = data['summary'][:45]
         output.append(data)
-        if idx + 1 >= n_tickets:
-            break
 
     return dict(
         project=project,
@@ -54,6 +58,9 @@ def data(session, widget, project, n_tickets=4):
 
 @hint(topics=[_('trac.ticket.update'), _('trac.ticket.new')])
 def should_invalidate(message, session, widget):
+    ''' Checks if the Fedorahosted widget needs an update.
+    Called by backend daemon listening to fedmsg '''
+
     project = widget.config.get('project', '')
     url = 'https://fedorahosted.org/%s/' % project
     if '.trac.ticket' in message['topic']:

From 793229ad83b2757b01db79ee6a363b32599cb217 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Oct 05 2016 10:03:31 +0000
Subject: [PATCH 648/1001] some beautification in github issues widget


---

diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
index 295c76b..986ff11 100755
--- a/hubs/widgets/githubissues.py
+++ b/hubs/widgets/githubissues.py
@@ -1,9 +1,10 @@
-from hubs.widgets.chrome import panel
+import requests
+
 from hubs.hinting import hint
-from hubs.widgets.base import argument
 from hubs.widgets import templating
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import argument
 import hubs.validators as validators
-import requests
 
 chrome = panel("Github: Newest Open Tickets")
 template = templating.environment.get_template('templates/githubissues.html')
@@ -15,33 +16,36 @@ position = 'right'
           validator=validators.github_organization,
           help="Github Organization or username")
 def data(session, widget, display_number, org, repo):
+    ''' Data for Github Issues widget. Queries github api for issues '''
+
     url = '/'.join(['https://api.github.com/repos', org, repo, "issues"])
-    issue_response = requests.get(url)
-    data = issue_response.json()
-    all_issues = list()
-    for i in range(0, 10):
-        issue_details = dict()
-        issue_num = data[i]['number']
-        issue_title = data[i]['title']
-        issue_openedby = data[i]['user']['login']
-        if(data[i]['assignee'] is not None):
-            issue_assignee = data[i]['assignee']['login']
-        else:
-            issue_assignee = data[i]['assignee']
-        issue_details['num'] = issue_num
-        issue_details['title'] = issue_title
-        issue_details['openedby'] = issue_openedby
+    issues = requests.get(url).json()
+
+    all_issues = []
+    for issue in issues[:10]:
+        issue_details = {}
+        issue_details['num'] = issue['number']
+        issue_details['title'] = issue['title']
+        issue_details['openedby'] = issue['user']['login']
+
+        issue_assignee = None
+        if issue['assignee'] is not None:
+            issue_assignee = issue['assignee']['login']
+
         issue_details['assignee'] = issue_assignee
         all_issues.append(issue_details)
-    all_issues.reverse()
+
     return dict(
         org=org,
         repo=repo,
-        all_issues=all_issues,
+        all_issues=all_issues.reverse(),
         display_number=display_number,
     )
 
 
 @hint()
 def should_invalidate(message, session, widget):
+    ''' Checks if the Github Issue widget needs an update.
+    Called by a backend daemon listening to fedmsg '''
+
     raise NotImplementedError

From a95fbea7014fbf28f17c4e275179c83d40bf45bf Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Oct 05 2016 10:43:54 +0000
Subject: [PATCH 649/1001] some beautification in about widget


---

diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index 7023139..4be594c 100755
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -14,11 +14,16 @@ position = 'both'
           validator=validators.text,
           help="Text about a user.")
 def data(session, widget, text):
+    ''' Data for the About widget '''
+
     return dict(text=text)
 
 
 @hint(topics=[_('hubs.widget.update')])
 def should_invalidate(message, session, widget):
+    ''' Checks whether the about widget cache needs an update or not
+    Called by backend daemon which listens to fedmsg '''
+
     if not message['topic'].endswith('hubs.widget.update'):
         return False
     if message['msg']['widget']['id'] != widget.idx:

From aa65f58ae8387ebf860219a8b1f9661c74bb059a Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Oct 05 2016 10:43:54 +0000
Subject: [PATCH 650/1001] some beautification in clean_input


---

diff --git a/hubs/widgets/clean_input.py b/hubs/widgets/clean_input.py
index 46bccbc..316c7a4 100644
--- a/hubs/widgets/clean_input.py
+++ b/hubs/widgets/clean_input.py
@@ -5,6 +5,7 @@ import bleach
 
 def filter_img_src(name, value):
     ''' Filter in img html tags images coming from a different domain. '''
+
     import hubs.app
     if name in ('alt', 'height', 'width', 'class'):
         return True
@@ -16,14 +17,15 @@ def filter_img_src(name, value):
 
 
 def clean(text, ignore=None):
-    """ For a given html text, escape everything we do not want to support
+    ''' For a given html text, escape everything we do not want to support
     to avoid potential security breach.
-    """
+    '''
+
     if ignore and not isinstance(ignore, (tuple, set, list)):
         ignore = [ignore]
 
     attrs = bleach.ALLOWED_ATTRIBUTES
-    if not ignore or not 'img' in ignore:
+    if not ignore or 'img' not in ignore:
         attrs['img'] = filter_img_src
 
     tags = bleach.ALLOWED_TAGS + [

From 3d9d80649dce6887056f6e3b4870f0a6af2302f9 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Oct 05 2016 10:43:54 +0000
Subject: [PATCH 651/1001] some beautification in pagureissues widget


---

diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index 118f8d5..c9ecd53 100755
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -1,9 +1,10 @@
+import requests
+
 from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
 from hubs.widgets import templating
 import hubs.validators as validators
-import requests
 
 pagure_url = "https://pagure.io/api/0"
 
@@ -17,6 +18,9 @@ position = 'right'
           validator=validators.pagure_repo,
           help="Pagure repo name")
 def data(session, widget, repo):
+    ''' Data for pagure issues widget
+    Queries Pagure api for issues '''
+
     repo = "pagure"
 
     url = '/'.join([pagure_url, repo, "issues"])
@@ -65,4 +69,7 @@ def data(session, widget, repo):
 
 @hint()
 def should_invalidate(message, session, widget):
+    ''' Checks whether pagureissues widget cache needs an update
+    Run by backend daemon listening to fedmsg '''
+
     raise NotImplementedError

From 2edcbbb3accfe7cb2a81bdff05d3f06b92ea458c Mon Sep 17 00:00:00 2001
From: saptaks <saptak013@gmail.com>
Date: Oct 11 2016 15:47:44 +0000
Subject: [PATCH 652/1001] version number for reactjs changed from 15.1.0 to ^15.3.2


---

diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 8cc9aa4..c9ca168 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -11,7 +11,7 @@
     "babel-plugin-transform-class-properties": "^6.10.2",
     "babel-preset-es2015": "~6.9.0",
     "babel-preset-react": "~6.5.0",
-    "react": "~15.1.0",
+    "react": "^15.3.2",
     "react-dom": "~15.1.0",
     "react-timeago": "^3.1.1",
     "webpack": "~1.13.1"

From 648a6ca2aa2b1e94931cdb45e224e0238997c79b Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Oct 18 2016 14:07:36 +0000
Subject: [PATCH 653/1001] Update the documentation


This commit adds a Sphinx project with the existing README (split into a
few different files) and some additional or updated documentation.

Signed-off-by: Jeremy Cline <jeremy@jcline.org>

---

diff --git a/README.rst b/README.rst
index 9ce74dc..2366db5 100644
--- a/README.rst
+++ b/README.rst
@@ -1,405 +1,24 @@
+Fedora Hubs
+===========
 Fedora Hubs will provide a communication and collaboration center for Fedora
 contributors of all types. The idea is that contributors will be able to visit
 Hubs to check on their involvements across Fedora, discover new places that they
 can contribute, and more.
 
 Hubs is currently under development, and you can see the progress on the
-Development instance here: http://209.132.184.98
+Development instance here: https://hubs-dev.fedorainfracloud.org/
 
-Mailing List
-============
-We have a mailing list here:
-https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org
+Get Involved
+------------
 
-Road Map
-========
+Visit our `mailing list <https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org>`_
+and join us in the ``#fedora-hubs`` IRC channel on irc.freenode.net. Meetings are held
+weekly in ``#fedora-hubs`` at 14:00UTC and the minutes for every meeting are
+`archived <https://meetbot.fedoraproject.org/sresults/?group_id=fedora-hubs&type=team>`_.
+In the meetings we review our statuses from the preceding week and do ticket triage, too.
 
-We are currently working towards a roadmap of the following features with a mid-October target milestone for them:
+For a more detailed overview of what Fedora Hubs is, see the
+`documentation <https://docs.pagure.io/fedora-hubs/overview.html>`_.
 
-1) **Zanata support** - Zanata is releasing a new version in November, but we've been in contact with Alex from that team and he said he will provide us with sample data to start developing against while they work on creating the webhooks we need to get that data. So we could do a release in October that has the support (and wait for the November Zanata release to turn it on.) Specifics of what widgets Zanata support would entail for the October release is TBD.
-
-2) **IRC Integration** - We'd like to have some IRC features available in the October release via the Waartaa project.
-
-3) **Badge support** -  Sayan already has a PR ready for tahrir (I believe) to add paths to badges; once that gets merged he can start working on the widget for hubs.
-
-4) **Hyperkitty support** - Hyperkitty needs some new API methods to provide full post content and metadata about replies / etc. Right now the migration off of Persona is top priority as Mozilla is shutting down Persona in September, but after that Aurelien can work on this. It shouldn't be super complicated. Once completed, Hyperkitty new thread posts will appear in the feed widget and if new replies are received to the thread, it'll bounce the thread to the top of the feed widget again.
-
-5) **Plusplus widget** - Aurelien and szkrepto have backend done; needs to be added to the webui.
-
-Want to get involved? Looking for something to work on?
-=======================================================
-* Unfamiliar with what hubs is all about? Read through these blog posts / videos with lots of information about our vision for the project:
-http://blog.linuxgrrl.com/category/fedora/fedora-hubs/
-
-* Building the development environment locally on your computer is a good beginning step to getting involved. If you have questions / run into issues, feel free to ask on
-#fedora-hubs in irc.freenode.net. Devyani put together a great blog post on how to get it working and what to expect here: https://devyani7kota.wordpress.com/2016/08/29/fedora-hubs-getting-started/
-
-* We meet weekly in #fedora-hubs at 1400 UTC (10 AM EDT) on irc.freenode.net. We review our statuses from the preceding week and do ticket triage too. Please join us and get acquainted!
-
-* **UX Designers** - take a look at our issues tagged 'needsmockup' that have no assignee listed and have a chat with mizmo (Máirín Duffy) for issue assignment / orientation.
-
-* **Developers** - take a look at our issues with 'normal' or 'low' priority. We're tagging issues with think are particularly good for newbies to take on with the "easy" tag.
-
-Hacking
-=======
-Install fedora dependencies::
-
-    $ sudo dnf install gcc gcc-c++ sqlite-devel libffi-devel openssl-devel redhat-rpm-config
-
-Hubs should work on either python2 **or** python3.  These instructions will
-show the way for python2 only, though.
-
-Setup a python virtualenv::
-
-    $ sudo dnf install python-virtualenvwrapper postgresql postgresql-devel
-    $ mkvirtualenv hubs
-
-If the mkvirtualenv command returns "command not found..." you may need to
-refresh your bash profile::
-
-    $ source ~/.bashrc
-
-Note that, you only have to type ``mkvirtualenv`` the *very
-first time* you set up hubs.  When you try go to work on hubs
-a second time (and every time after that..) you only have to
-type ``workon hubs``, which will re-activate the virtual
-environment that you *made* last time.  (The ``mk`` in
-``mkvirtualenv`` stands for "make".)
-
-Now we need to pull the project and change our working directory::
-
-    $ git clone https://pagure.io/fedora-hubs.git
-    $ cd ./fedora-hubs
-
-OK -- with that done, now install the dependencies from PyPI::
-
-    $ pip install -r requirements.txt
-
-If anything complains about having an old version, you can update it with the following, after replacing [packagename] with the package in question::
-
-	$ pip install --upgrade [packagename]
-
-Configure the project to authenticate against iddev.fedorainfracloud.org::
-
-    oidc-register --debug https://iddev.fedorainfracloud.org/ http://localhost:5000
-
-If the previous command complains about an error verifying the certificate, you will want to replace httplib2's ca cert file. Afterward, re-run the above command::
-
-    cp /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
-        ~/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
-
-Create a local configuration file::
-
-    echo "OIDC_ID_TOKEN_COOKIE_SECURE = False" > config
-
-With that, try running the app by creating the database::
-
-    $ python populate.py  # To create the db
-
-If this fails with a complaint about no module named sanitizer, or something about HTMLsanitizer, you will need to install bleach::
-
-	$ pip install bleach
-
-Finish running the app by starting the devel server with your local config file. There will be warnings, but you can safely ignore them::
-
-    $ python runserver.py -c config  # To run the dev server with our local conf
-
-And then navigate to http://localhost:5000/
-
-If you want to test it with 8 worker threads, try ``gunicorn``::
-
-    $ pip install gunicorn
-    $ gunicorn -w 8 -t 60 --log-config logging.ini --reload hubs.app:app -b :5000
-
-Note that then the application is available at http://localhost:8000/
-
-When hacking on widgets, it is useful to have this one-liner handy.  It removes
-the db alltogether, re-populates it, and restarts the app::
-
-    $ rm /var/tmp/hubs.db; rm /var/tmp/fedora-hubs-cache.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 240 --log-config logging.ini hubs.app:app -b :5000
-
-Run the tests!
---------------
-
-We have a test suite.  You should run it *before* you start working on some
-code, to make sure that nothing is broken before you start.  And you should run
-it after you finish your change, before you push, to verify that your change
-didn't inadvertently break something else.
-
-You can run it with::
-
-    $ pip install -r test-requirements.txt
-    $ ./runtest.sh
-
-
-
-If the unit tests are all failing and returning errors like this::
-
-    ImportError: cannot import name dummy
-
-
-It most likely is a result of html5lib breaking api stability. Please downgrade to the version below::
-
-    pip install html5lib==0.9999999
-
-
-See the options available with::
-
-    $ ./runtest.sh --help
-
-You can run the JavaScript tests from ``hubs/static/client`` with::
-    $ npm test
-
-Some credentials...
--------------------
-
-You need to add a new file to the ``fedmsg.d/`` directory.
-Call it ``fedmsg.d/credentials.py``.  It's needed to query FAS
-for information about other users. When we deploy this thing to
-production, we'll use a system account for this but for now, just
-use your personal account. You don't want to accidentally share this
-with anyone else. so be sure to keep it private.  It should have
-contents like this::
-
-    config = {
-        # Put your FAS credentials here...
-        # but leave them commented out.  Note that, if you leave your fas
-        # credentials out, some widgets won't be as accurate as they could be..
-        # but it also makes the app faster than it would otherwise be (which is
-        # nice for development).
-        #'fas_credentials': {
-        #    'username': 'YOUR_FAS_USERNAME',
-        #    'password': 'YOUR_FAS_PASSWORD',
-        #},
-
-        # Go and generate a token for this here:
-        # https://github.com/settings/tokens
-        'github.oauth_token': 'YOUR_GITHUB_TOKEN',
-    }
-
-Make sure to leave the '' around you username and password - don't delete them! Some widgets will work without the above info being present..
-but it is needed for a subset of them.
-
-JavaScript assets
---------------
-
-Some widgets and pages run on React so to install those dependencies::
-
-    $ cd hubs/static/client && npm install
-
-For the Feed and My Stream, change the ``SSE_URL`` location in the ``config`` you created
-to point to the streaming server then build JavaScript assets. Add ``--w`` for live reloading::
-
-    $ cd hubs/static/client && node_modules/.bin/webpack
-
-
-My Stream - the Extra Mile
-------------------------------------------
-
-One portion of Hubs - the My Stream page - requires more legwork to stand up.
-If you just want to see how hubs works and you want to hack on other
-peripheral stuff around it, you don't need to bother with these steps.
-
-The stream requires a direct DB connection to the datanommer
-database; it can't proxy through datagrepper because it needs more
-flexibility.  To get this working, you're going to set up:
-
-- a postgres db
-- the datanommer daemon
-
-Start with some required packages::
-
-    $ sudo dnf install postgresql-server python-datanommer-consumer datanommer-commands fedmsg-hub npm
-
-And there are some support libraries you'll also need::
-
-    $ sudo dnf install python-psycopg2 python-fedmsg-meta-fedora-infrastructure
-
-Now, with packages installed, you need to tell postgres to create its initial filesystem layout::
-
-    $ sudo postgresql-setup initdb
-
-And then, we need to tweak its config to let us connect easily for development::
-
-    $ sudo vim /var/lib/pgsql/data/pg_hba.conf
-
-Change **two lines** from ``ident`` to ``trust``.  These two::
-
-    # IPv4 local connections:
-    host    all             all             127.0.0.1/32            trust
-    # IPv6 local connections:
-    host    all             all             ::1/128                 trust
-
-Start that beast up::
-
-    $ sudo systemctl start postgresql
-
-Now, with the db daemon configured and running, let's configure datanommer.  Edit this file::
-
-    $ sudo vim /etc/fedmsg.d/datanommer.py
-
-And do two things:  1) set enabled to ``True`` and 2) give it a real sqlalchemy url, like this::
-
-    config = {
-        'datanommer.enabled': True,
-        'datanommer.sqlalchemy.url': 'postgres://postgres:whatever@localhost/datanommer',
-    }
-
-Tell postgres that it should create space for a 'datanommer' database with this command::
-
-    $ sudo -u postgres psql -c "CREATE DATABASE datanommer;"
-
-And finally, tell datanommer to create all of its tables in that new db we just created::
-
-    $ datanommer-create-db
-
-Tell the fedmsg-hub daemon to restart itself.  It should pick up datanommer as a plugin and start handing messages to it::
-
-    $ sudo systemctl restart fedmsg-hub
-
-And then, wait a few seconds for a message to get nommed, and then you can
-check that it's working by running ``sudo datanommer-stats``.  It should print
-out some kind of summary about what kinds of messages are in the db now -- it
-will just grow and grow over time::
-
-    $ datanommer-stats
-    [2015-07-01 14:33:21][    fedmsg    INFO] buildsys has 70 entries
-    [2015-07-01 14:33:21][    fedmsg    INFO] faf has 7 entries
-    [2015-07-01 14:33:21][    fedmsg    INFO] copr has 6 entries
-    [2015-07-01 14:33:21][    fedmsg    INFO] askbot has 2 entries
-
-**Lastly**, (fingers crossed) start up the fedora-hubs webapp and load your
-profile page. Change back to the project root and run::
-
-  $ python runserver.py -c config
-
-Once there are some messages that get into your local database
-that *should* show up on your page. they should appear there.  (At very least,
-you shouldn't get an error message about that page being unable to be
-displayed).
-
-Stubbing out a new Widget
-=========================
-
-You write a new widget in the ``hubs/widgets/`` directory and must declare it
-in the registry dict in ``hubs/widgets/__init__.py``.
-
-In order to be valid, a widget must have:
-
-- A ``data(session, widgets, **kwargs)`` function that returns a
-  jsonifiable dict of data.  This will get cached -- more on that later.
-- A ``template`` object that is a jinja2 template for that widget.
-- Optionally, a ``chrome`` decorator.
-- A ``should_invalidate(message, session, widget)`` function that will be used to
-  *potentially* invalidate the widget's cache. That function will get called by
-  a backend daemon listening for fedmsg messages so when you update your group
-  memberships in FAS, a fedmsg message hits the fedora-hubs backend and returns
-  True if the lookup value should be nuked/refreshed in memcached (or some
-  other store).
-
-If you want to try making a new widget:
-
-- Copy an existing one in ``hubs/widgets/``
-- Add it to the registry in ``hubs/widgets/__init__.py``
-- If you want it to show up on a **user** page, add it to ``hubs/defaults.py``
-  in the ``add_user_widgets`` function.
-- If you want it to show up on **group** pages, add it to ``populate.py``.
-
-Destroy your database, rebuild it, and re-run the app.  Your widget should show up.
-
-A proposal, client-side templates
-=================================
-
-- The template per-widget is currently held and rendered *server-side* with
-  jinja2.  This is how all our apps do it, more or less.
-
-  We might want to consider using handlebars.js for our templates instead and
-  rendering all of the widgets asynchronously on the client.  It could be cool,
-  but is new-ground for our team.
-
-  Furthermore, we should likely use something like angular **or** backbone.js
-  to manage the data synchronization with those client-side templates.
-
-Some discussion on how to do pushed updates to web clients:
-
-- We could re-use the existing websocket service we have at
-  ``wss://hub.fedoraproject.org:9939`` but it has some problems:
-- It is very inflexible.  You can subscribe to fedmsg *topics* and then you
-  receive the firehose of those topics. For a widget, we already have to write
-  a 'cache invalidation' function that listens for messages and then somehow
-  knows to invalidate the cache *for a widget* based on some of those messages.
-  If we re-used the firehose on the client, we would have to write that
-  function *twice* for *each widget*, once in python to invalidate the server's
-  memcached cache when a fedmsg message comes in and once in javascript to tell
-  the client to reload and redraw a oprtion of itself when a fedmsg comes in
-  over the websocket firehose.
-- Instead, let's give fedora-hubs its own *widget-specific* `EventSource
-  <https://developer.mozilla.org/en-US/docs/Web/API/EventSource>`_ server that
-  we tie in to the server-side cache-invalidation backend code.  I.e., when a
-  message comes into the backend, it runs all the cache invalidation checkers
-  to see which widgets' caches should be refreshed, and once they are refreshed
-  we can emit events over EventSource to tell only *those* widgets on any
-  connected clients to redraw themselves.
-
-As an aside, it became clear to me when making the diagram in the next section
-that, if we use handlebars.js and get rid of the server-side template
-rendering, then 1) the data returned by AJAX requests at page load and 2) the
-data pushed by the EventSource server can be *the exact same data*.  It will
-simplify and streamline the responsibilities of the pieces if the backend is
-worried *only* about these per-widget JSON responses.
-
-A picture is worth...
----------------------
-
-Here are some more details on how the whole thing should work together.
-
-.. figure:: https://raw.githubusercontent.com/ralphbean/fedora-hubs-prototype/develop/docs/diagram.png
-   :scale: 50 %
-   :alt: A diagram of component interactions
-
-   A diagram of component interactions
-
-Let's talk through how data will flow through the system by asking *what
-happens when a user requsts their main hubs page*:
-
-- The user requests the page and the wsgi app responds with some barebones HTML
-  and enough javascript to get off the ground.
-- The user's browser runs javascript that *subscribes* it to the EventSource server.
-- The user's browser runs that javascript, which requests data for each of the
-  widgets defined on the page.
-- The wsgi app receives those requests and checks to see if the data for any of
-  them is *cached in memcached*.  If it is, then it is returned.  If not, then
-  the wsgi app executes the ``data(...)`` function of that widget to get the
-  response ready.  It is stuffed in memcached for later access and returned.
-- The client renders widgets as the data for each of its requests comes back.
-
-Later, what happens when a *trac ticket* is filed that should show up in some widget on their page?
-
-- The ticket is updated on fedorahosted.org and a fedmsg message is fired.
-- That is received by the hubs backend, which looks up *all* the cached
-  responses that should be invalidated by that event (there is a widget on
-  mizmo's page, threebean's page, and on the design hub that should all get
-  fresh data because of this change).
-- All of those widgets get their cached data nuked.
-- All of those widgets get their cached data rebuilt by calling ``data(...)`` on them.
-- An EventSource event is fired off for any listening clients that *new data is
-  available for widgets X, Y, and Z*.  The data is included in the EventSource
-  payload so the clients can immediately redraw without bothering to re-query
-  the wsgi app.
-
-What happens when the user is viewing the *design team* hub and
-simultaneously, an admin *changes the configuration of a widget on that page*?
-
-- Changing the configuration results in a HTTP POST to the wsgi app.
-- The configuration is changed accordingly in the postgres database.
-- A fedmsg message is fired off indicating that *the configuration for widget X
-  has changed*.
-- The wsgi app responds 200 OK to the admin.
-- Meanwhile, that fedmsg message is received by the backend which:
-- ...looks up the cache key for *widget X with the old configuration* and nukes
-  it the cached data.
-- ...looks up the cache key for *widget X with the new configuration* and
-  builds the cached data by calling ``data(...)`` on the widget.
-- An EventSource event is fired off which gets recieved by everyone looking at
-  the *design team hub*.  The widget on their pages gets redrawn with data from
-  the EventSource event.
+To set up a development environment and start contributing, check out
+the `development guide <https://docs.pagure.io/fedora-hubs/dev-guide.html>`_.
diff --git a/dev-guide.rst b/dev-guide.rst
deleted file mode 100644
index fda1d46..0000000
--- a/dev-guide.rst
+++ /dev/null
@@ -1,44 +0,0 @@
-Developer Setup
-===============
-
-This guide should get you up and running with a development environment.
-The simpliest way to stand up a development environment is to use
-`Vagrant <https://www.vagrantup.com/docs/>`_, but it is also easy to set
-up a development environment without Vagrant.
-
-Vagrant
-^^^^^^^
-
-A ``Vagrantfile`` called ``Vagrantfile.example`` is provided in the root of the
-`Fedora Hub repository <https://pagure.io/fedora-hubs/>`_. To use it, simply
-copy ``Vagrantfile.example`` to ``Vagrantfile`` and modify it as you see fit.
-All settings are documented inline.
-
-If you do not have Vagrant set up, follow these steps:
-
-#. Install Ansible, Vagrant, and several helpful Vagrant plugins::
-
-   $ sudo dnf install ansible vagrant-libvirt vagrant-sshfs vagrant-hostmanager
-
-#. Create and configure the virtual machine::
-
-   $ vagrant up --provider=libvirt
-   $ vagrant reload  # Reboot the machine to use the latest kernel, etc.
-
-#. You can now use ssh to connect to the machine::
-
-   $ vagrant ssh
-
-#. If you ever want to re-run the provisioning scripts, you can::
-
-   $ vagrant provision
-
-#. If you decide you want a fresh development environment, simply destroy your
-   virtual machine and recreate it::
-
-   $ vagrant destroy && vagrant up
-
-You should now be able to point the browser in your host at http://localhost:5000/
-and use Fedora Hubs after you start the development server in the virtual machine.
-
-Happy hacking!
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..7ac26ff
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,225 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  applehelp  to make an Apple Help Book"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  epub3      to make an epub3"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  xml        to make Docutils-native XML files"
+	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+	@echo "  coverage   to run coverage check of the documentation (if enabled)"
+	@echo "  dummy      to check syntax errors of document sources"
+
+.PHONY: clean
+clean:
+	rm -rf $(BUILDDIR)/*
+
+.PHONY: html
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+.PHONY: dirhtml
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+.PHONY: singlehtml
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+.PHONY: pickle
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+.PHONY: json
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+.PHONY: htmlhelp
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+.PHONY: qthelp
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/fedora-hubs.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/fedora-hubs.qhc"
+
+.PHONY: applehelp
+applehelp:
+	$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
+	@echo
+	@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
+	@echo "N.B. You won't be able to view it unless you put it in" \
+	      "~/Library/Documentation/Help or install it in your application" \
+	      "bundle."
+
+.PHONY: devhelp
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/fedora-hubs"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/fedora-hubs"
+	@echo "# devhelp"
+
+.PHONY: epub
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+.PHONY: epub3
+epub3:
+	$(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
+	@echo
+	@echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
+
+.PHONY: latex
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+.PHONY: latexpdf
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: latexpdfja
+latexpdfja:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through platex and dvipdfmx..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: text
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+.PHONY: man
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+.PHONY: texinfo
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+.PHONY: info
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+.PHONY: gettext
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+.PHONY: changes
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+.PHONY: linkcheck
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+.PHONY: doctest
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
+
+.PHONY: coverage
+coverage:
+	$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
+	@echo "Testing of coverage in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/coverage/python.txt."
+
+.PHONY: xml
+xml:
+	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+	@echo
+	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+.PHONY: pseudoxml
+pseudoxml:
+	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+	@echo
+	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
+
+.PHONY: dummy
+dummy:
+	$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
+	@echo
+	@echo "Build finished. Dummy builder generates no files."
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..ca55b4f
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,423 @@
+# -*- coding: utf-8 -*-
+#
+# fedora-hubs documentation build configuration file, created by
+# sphinx-quickstart on Wed Sep 21 16:41:24 2016.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#
+# source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'fedora-hubs'
+copyright = u'2016, Red Hat, Inc. and others.'
+author = u'Red Hat, Inc. and others.'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = u'0.0.1'
+# The full version, including alpha/beta/rc tags.
+release = u'0.0.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#
+# today = ''
+#
+# Else, today_fmt is used as the format for a strftime call.
+#
+# today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#
+# default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#
+# add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#
+# add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#
+# show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+# modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+# keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+# html_theme_path = []
+
+# The name for this set of Sphinx documents.
+# "<project> v<release> documentation" by default.
+#
+# html_title = u'fedora-hubs v0.0.1'
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#
+# html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#
+# html_logo = None
+
+# The name of an image file (relative to this directory) to use as a favicon of
+# the docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#
+# html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#
+# html_extra_path = []
+
+# If not None, a 'Last updated on:' timestamp is inserted at every page
+# bottom, using the given strftime format.
+# The empty string is equivalent to '%b %d, %Y'.
+#
+# html_last_updated_fmt = None
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#
+# html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#
+# html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#
+# html_additional_pages = {}
+
+# If false, no module index is generated.
+#
+# html_domain_indices = True
+
+# If false, no index is generated.
+#
+# html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#
+# html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#
+# html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#
+# html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#
+# html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#
+# html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+# html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+#   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
+#   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
+#
+# html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# 'ja' uses this config value.
+# 'zh' user can custom change `jieba` dictionary path.
+#
+# html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#
+# html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'fedora-hubsdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+     # The paper size ('letterpaper' or 'a4paper').
+     #
+     # 'papersize': 'letterpaper',
+
+     # The font size ('10pt', '11pt' or '12pt').
+     #
+     # 'pointsize': '10pt',
+
+     # Additional stuff for the LaTeX preamble.
+     #
+     # 'preamble': '',
+
+     # Latex figure (float) alignment
+     #
+     # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'fedora-hubs.tex', u'fedora-hubs Documentation',
+     u'AUTHORS', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#
+# latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#
+# latex_use_parts = False
+
+# If true, show page references after internal links.
+#
+# latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#
+# latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#
+# latex_appendices = []
+
+# It false, will not define \strong, \code, 	itleref, \crossref ... but only
+# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added
+# packages.
+#
+# latex_keep_old_macro_names = True
+
+# If false, no module index is generated.
+#
+# latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'fedora-hubs', u'fedora-hubs Documentation',
+     [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#
+# man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'fedora-hubs', u'fedora-hubs Documentation',
+     author, 'fedora-hubs', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#
+# texinfo_appendices = []
+
+# If false, no module index is generated.
+#
+# texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#
+# texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#
+# texinfo_no_detailmenu = False
+
+
+# -- Options for Epub output ----------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = project
+epub_author = author
+epub_publisher = author
+epub_copyright = copyright
+
+# The basename for the epub file. It defaults to the project name.
+# epub_basename = project
+
+# The HTML theme for the epub output. Since the default themes are not
+# optimized for small screen space, using the same theme for HTML and epub
+# output is usually not wise. This defaults to 'epub', a theme designed to save
+# visual space.
+#
+# epub_theme = 'epub'
+
+# The language of the text. It defaults to the language option
+# or 'en' if the language is not set.
+#
+# epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+# epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#
+# epub_identifier = ''
+
+# A unique identification for the text.
+#
+# epub_uid = ''
+
+# A tuple containing the cover image and cover page html template filenames.
+#
+# epub_cover = ()
+
+# A sequence of (type, uri, title) tuples for the guide element of content.opf.
+#
+# epub_guide = ()
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#
+# epub_pre_files = []
+
+# HTML files that should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#
+# epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ['search.html']
+
+# The depth of the table of contents in toc.ncx.
+#
+# epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#
+# epub_tocdup = True
+
+# Choose between 'default' and 'includehidden'.
+#
+# epub_tocscope = 'default'
+
+# Fix unsupported image types using the Pillow.
+#
+# epub_fix_images = False
+
+# Scale large images.
+#
+# epub_max_image_width = 0
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#
+# epub_show_urls = 'inline'
+
+# If false, no index is generated.
+#
+# epub_use_index = True
diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
new file mode 100644
index 0000000..35b1871
--- /dev/null
+++ b/docs/dev-guide.rst
@@ -0,0 +1,479 @@
+
+.. _development-guide:
+
+Development Guide
+=================
+
+Fedora Hubs is a web application written in Python. It uses the
+`Flask <http://flask.pocoo.org/>`_ web framework and `SQLAlchemy
+<http://www.sqlalchemy.org/>`_ to interact with the database.
+
+It also uses the `React <https://facebook.github.io/react/>`_ JavaScript
+framework and `fedora-bootstrap <https://pagure.io/fedora-bootstrap/>`_.
+
+
+Getting Started on a Task
+-------------------------
+
+UX Designers
+^^^^^^^^^^^^
+
+Start by taking a look at our list of `unassigned issues tagged 'needsmockup'
+<https://pagure.io/fedora-hubs/issues?status=Open&assignee=0&tags=needsmockup>`_.
+Have a chat with mizmo (Máirín Duffy) for issue assignment / orientation.
+
+
+Developers
+^^^^^^^^^^
+Take a look at our `issues <https://pagure.io/fedora-hubs/issues/>`_ with
+'normal' or 'low' priority. We're tagging issues that we think are particularly
+good for newbies to take on with the "easy" tag.
+
+
+Development Environment
+-----------------------
+
+There are several options available when setting up a development environment.
+The simpliest way to stand up a development environment is to use
+`Vagrant <https://www.vagrantup.com/docs/>`_, but it is also easy to set
+up a development environment without Vagrant. This documentation assumes you
+are using the latest stable version of Fedora.
+
+
+Vagrant
+^^^^^^^
+
+A ``Vagrantfile`` called ``Vagrantfile.example`` is provided in the root of the
+`Fedora Hub repository <https://pagure.io/fedora-hubs/>`_. To use it, simply
+copy ``Vagrantfile.example`` to ``Vagrantfile`` and modify it as you see fit.
+All settings are documented inline.
+
+If you do not have Vagrant set up, follow these steps:
+
+#. Install Ansible, Vagrant, and several helpful Vagrant plugins::
+
+   $ sudo dnf install ansible vagrant-libvirt vagrant-sshfs
+
+#. In the root of the git repository, copy ``Vagrantfile.example`` to ``Vagrantfile``::
+
+   $ cp Vagrantfile.example Vagrantfile
+
+#. Create and configure the virtual machine::
+
+   $ vagrant up --provider=libvirt
+   $ vagrant reload  # Reboot the machine to use the latest kernel, etc.
+
+#. You can now use ssh to connect to the machine::
+
+   $ vagrant ssh
+
+#. You'll be greeted by a message of the day with instructions on how to start the
+   development server.
+
+#. If you ever want to re-run the provisioning scripts, you can::
+
+   $ vagrant provision
+
+#. If you decide you want a fresh development environment, simply destroy your
+   virtual machine and recreate it::
+
+   $ vagrant destroy && vagrant up
+
+Once you start the development server in the guest, you should be able to access
+Fedora Hubs by navigating to http://localhost:5000/ on the browser in your host.
+
+Happy hacking!
+
+
+Ansible
+^^^^^^^
+
+If you would prefer not to use Vagrant, you can also just use Ansible directly.
+
+.. warning::
+    The Ansible role used to set up a development environment assumes it can do
+    things like overwrite the user's .bashrc. You should not run this on a host
+    you don't feel comfortable re-provisioning.
+
+First, you need to install the packages required to run Ansible::
+
+    $ sudo dnf install ansible python2-dnf libselinux-python
+
+Next, we need to create an Ansible `inventory
+<http://docs.ansible.com/ansible/intro_inventory.html>`_. If you want to run
+Ansible on the local host, you can easily create one with::
+
+    $ echo -e "localhost ansible_connection=local" >> /tmp/ansible_inventory
+
+Finally, run Ansible using the inventory::
+
+    $ ansible-playbook --inventory-file=/tmp/ansible_inventory ansible/vagrant-playbook.yml
+
+Once it finishes, you should have a fully functional development environment!
+
+
+Manual
+^^^^^^
+
+Install fedora dependencies::
+
+    $ sudo dnf install gcc gcc-c++ sqlite-devel libffi-devel openssl-devel redhat-rpm-config
+
+Hubs should work on either python2 **or** python3.  These instructions will
+show the way for python2 only, though.
+
+Setup a python virtualenv::
+
+    $ sudo dnf install python-virtualenvwrapper postgresql postgresql-devel
+    $ mkvirtualenv hubs
+
+If the mkvirtualenv command returns "command not found..." you may need to
+refresh your bash profile::
+
+    $ source ~/.bashrc
+
+Note that, you only have to type ``mkvirtualenv`` the *very
+first time* you set up hubs.  When you try go to work on hubs
+a second time (and every time after that..) you only have to
+type ``workon hubs``, which will re-activate the virtual
+environment that you *made* last time.  (The ``mk`` in
+``mkvirtualenv`` stands for "make".)
+
+Now we need to pull the project and change our working directory::
+
+    $ git clone https://pagure.io/fedora-hubs.git
+    $ cd ./fedora-hubs
+
+OK -- with that done, now install the dependencies from PyPI::
+
+    $ pip install -r requirements.txt
+
+If anything complains about having an old version, you can update it with the following, after replacing [packagename] with the package in question::
+
+	$ pip install --upgrade [packagename]
+
+Configure the project to authenticate against iddev.fedorainfracloud.org::
+
+    oidc-register --debug https://iddev.fedorainfracloud.org/ http://localhost:5000
+
+If the previous command complains about an error verifying the certificate, you will want to replace httplib2's ca cert file. Afterward, re-run the above command::
+
+    cp /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
+        ~/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
+
+Create a local configuration file::
+
+    echo "OIDC_ID_TOKEN_COOKIE_SECURE = False" > config
+
+With that, try running the app by creating the database::
+
+    $ python populate.py  # To create the db
+
+If this fails with a complaint about no module named sanitizer, or something about HTMLsanitizer, you will need to install bleach::
+
+	$ pip install bleach
+
+Finish running the app by starting the devel server with your local config file. There will be warnings, but you can safely ignore them::
+
+    $ python runserver.py -c config  # To run the dev server with our local conf
+
+And then navigate to http://localhost:5000/
+
+If you want to test it with 8 worker threads, try ``gunicorn``::
+
+    $ pip install gunicorn
+    $ gunicorn -w 8 -t 60 --log-config logging.ini --reload hubs.app:app -b :5000
+
+Note that then the application is available at http://localhost:8000/
+
+When hacking on widgets, it is useful to have this one-liner handy.  It removes
+the db alltogether, re-populates it, and restarts the app::
+
+    $ rm /var/tmp/hubs.db; rm /var/tmp/fedora-hubs-cache.db; PYTHONPATH=. python populate.py; gunicorn -w 8 -t 240 --log-config logging.ini hubs.app:app -b :5000
+
+
+Run the tests!
+--------------
+
+We have a test suite.  You should run it *before* you start working on some
+code, to make sure that nothing is broken before you start.  And you should run
+it after you finish your change, before you push, to verify that your change
+didn't inadvertently break something else.
+
+You can run it with::
+
+    $ pip install -r test-requirements.txt
+    $ ./runtest.sh
+
+
+
+If the unit tests are all failing and returning errors like this::
+
+    ImportError: cannot import name dummy
+
+
+It most likely is a result of html5lib breaking api stability. Please downgrade to the version below::
+
+    pip install html5lib==0.9999999
+
+
+See the options available with::
+
+    $ ./runtest.sh --help
+
+You can run the JavaScript tests from ``hubs/static/client`` with::
+    $ npm test
+
+Some credentials...
+-------------------
+
+You need to add a new file to the ``fedmsg.d/`` directory.
+Call it ``fedmsg.d/credentials.py``.  It's needed to query FAS
+for information about other users. When we deploy this thing to
+production, we'll use a system account for this but for now, just
+use your personal account. You don't want to accidentally share this
+with anyone else. so be sure to keep it private.  It should have
+contents like this::
+
+    config = {
+        # Put your FAS credentials here...
+        # but leave them commented out.  Note that, if you leave your fas
+        # credentials out, some widgets won't be as accurate as they could be..
+        # but it also makes the app faster than it would otherwise be (which is
+        # nice for development).
+        #'fas_credentials': {
+        #    'username': 'YOUR_FAS_USERNAME',
+        #    'password': 'YOUR_FAS_PASSWORD',
+        #},
+
+        # Go and generate a token for this here:
+        # https://github.com/settings/tokens
+        'github.oauth_token': 'YOUR_GITHUB_TOKEN',
+    }
+
+Make sure to leave the '' around you username and password - don't delete them! Some widgets will work without the above info being present..
+but it is needed for a subset of them.
+
+JavaScript assets
+-----------------
+
+Some widgets and pages run on React so to install those dependencies::
+
+    $ cd hubs/static/client && npm install
+
+For the Feed and My Stream, change the ``SSE_URL`` location in the ``config`` you created
+to point to the streaming server then build JavaScript assets. Add ``--w`` for live reloading::
+
+    $ cd hubs/static/client && node_modules/.bin/webpack
+
+
+My Stream - the Extra Mile
+--------------------------
+
+One portion of Hubs - the My Stream page - requires more legwork to stand up.
+If you just want to see how hubs works and you want to hack on other
+peripheral stuff around it, you don't need to bother with these steps.
+
+The stream requires a direct DB connection to the datanommer
+database; it can't proxy through datagrepper because it needs more
+flexibility.  To get this working, you're going to set up:
+
+- a postgres db
+- the datanommer daemon
+
+Start with some required packages::
+
+    $ sudo dnf install postgresql-server python-datanommer-consumer datanommer-commands fedmsg-hub npm
+
+And there are some support libraries you'll also need::
+
+    $ sudo dnf install python-psycopg2 python-fedmsg-meta-fedora-infrastructure
+
+Now, with packages installed, you need to tell postgres to create its initial filesystem layout::
+
+    $ sudo postgresql-setup initdb
+
+And then, we need to tweak its config to let us connect easily for development::
+
+    $ sudo vim /var/lib/pgsql/data/pg_hba.conf
+
+Change **two lines** from ``ident`` to ``trust``.  These two::
+
+    # IPv4 local connections:
+    host    all             all             127.0.0.1/32            trust
+    # IPv6 local connections:
+    host    all             all             ::1/128                 trust
+
+Start that beast up::
+
+    $ sudo systemctl start postgresql
+
+Now, with the db daemon configured and running, let's configure datanommer.  Edit this file::
+
+    $ sudo vim /etc/fedmsg.d/datanommer.py
+
+And do two things:  1) set enabled to ``True`` and 2) give it a real sqlalchemy url, like this::
+
+    config = {
+        'datanommer.enabled': True,
+        'datanommer.sqlalchemy.url': 'postgres://postgres:whatever@localhost/datanommer',
+    }
+
+Tell postgres that it should create space for a 'datanommer' database with this command::
+
+    $ sudo -u postgres psql -c "CREATE DATABASE datanommer;"
+
+And finally, tell datanommer to create all of its tables in that new db we just created::
+
+    $ datanommer-create-db
+
+Tell the fedmsg-hub daemon to restart itself.  It should pick up datanommer as a plugin and start handing messages to it::
+
+    $ sudo systemctl restart fedmsg-hub
+
+And then, wait a few seconds for a message to get nommed, and then you can
+check that it's working by running ``sudo datanommer-stats``.  It should print
+out some kind of summary about what kinds of messages are in the db now -- it
+will just grow and grow over time::
+
+    $ datanommer-stats
+    [2015-07-01 14:33:21][    fedmsg    INFO] buildsys has 70 entries
+    [2015-07-01 14:33:21][    fedmsg    INFO] faf has 7 entries
+    [2015-07-01 14:33:21][    fedmsg    INFO] copr has 6 entries
+    [2015-07-01 14:33:21][    fedmsg    INFO] askbot has 2 entries
+
+**Lastly**, (fingers crossed) start up the fedora-hubs webapp and load your
+profile page. Change back to the project root and run::
+
+  $ python runserver.py -c config
+
+Once there are some messages that get into your local database
+that *should* show up on your page. they should appear there.  (At very least,
+you shouldn't get an error message about that page being unable to be
+displayed).
+
+Stubbing out a new Widget
+=========================
+
+You write a new widget in the ``hubs/widgets/`` directory and must declare it
+in the registry dict in ``hubs/widgets/__init__.py``.
+
+In order to be valid, a widget must have:
+
+- A ``data(session, widgets, **kwargs)`` function that returns a
+  jsonifiable dict of data.  This will get cached -- more on that later.
+- A ``template`` object that is a jinja2 template for that widget.
+- Optionally, a ``chrome`` decorator.
+- A ``should_invalidate(message, session, widget)`` function that will be used to
+  *potentially* invalidate the widget's cache. That function will get called by
+  a backend daemon listening for fedmsg messages so when you update your group
+  memberships in FAS, a fedmsg message hits the fedora-hubs backend and returns
+  True if the lookup value should be nuked/refreshed in memcached (or some
+  other store).
+
+If you want to try making a new widget:
+
+- Copy an existing one in ``hubs/widgets/``
+- Add it to the registry in ``hubs/widgets/__init__.py``
+- If you want it to show up on a **user** page, add it to ``hubs/defaults.py``
+  in the ``add_user_widgets`` function.
+- If you want it to show up on **group** pages, add it to ``populate.py``.
+
+Destroy your database, rebuild it, and re-run the app.  Your widget should show up.
+
+A proposal, client-side templates
+=================================
+
+- The template per-widget is currently held and rendered *server-side* with
+  jinja2.  This is how all our apps do it, more or less.
+
+  We might want to consider using handlebars.js for our templates instead and
+  rendering all of the widgets asynchronously on the client.  It could be cool,
+  but is new-ground for our team.
+
+  Furthermore, we should likely use something like angular **or** backbone.js
+  to manage the data synchronization with those client-side templates.
+
+Some discussion on how to do pushed updates to web clients:
+
+- We could re-use the existing websocket service we have at
+  ``wss://hub.fedoraproject.org:9939`` but it has some problems:
+- It is very inflexible.  You can subscribe to fedmsg *topics* and then you
+  receive the firehose of those topics. For a widget, we already have to write
+  a 'cache invalidation' function that listens for messages and then somehow
+  knows to invalidate the cache *for a widget* based on some of those messages.
+  If we re-used the firehose on the client, we would have to write that
+  function *twice* for *each widget*, once in python to invalidate the server's
+  memcached cache when a fedmsg message comes in and once in javascript to tell
+  the client to reload and redraw a oprtion of itself when a fedmsg comes in
+  over the websocket firehose.
+- Instead, let's give fedora-hubs its own *widget-specific* `EventSource
+  <https://developer.mozilla.org/en-US/docs/Web/API/EventSource>`_ server that
+  we tie in to the server-side cache-invalidation backend code.  I.e., when a
+  message comes into the backend, it runs all the cache invalidation checkers
+  to see which widgets' caches should be refreshed, and once they are refreshed
+  we can emit events over EventSource to tell only *those* widgets on any
+  connected clients to redraw themselves.
+
+As an aside, it became clear to me when making the diagram in the next section
+that, if we use handlebars.js and get rid of the server-side template
+rendering, then 1) the data returned by AJAX requests at page load and 2) the
+data pushed by the EventSource server can be *the exact same data*.  It will
+simplify and streamline the responsibilities of the pieces if the backend is
+worried *only* about these per-widget JSON responses.
+
+A picture is worth...
+---------------------
+
+Here are some more details on how the whole thing should work together.
+
+.. figure:: diagram.png
+   :scale: 50 %
+   :alt: A diagram of component interactions
+
+   A diagram of component interactions
+
+Let's talk through how data will flow through the system by asking *what
+happens when a user requsts their main hubs page*:
+
+- The user requests the page and the wsgi app responds with some barebones HTML
+  and enough javascript to get off the ground.
+- The user's browser runs javascript that *subscribes* it to the EventSource server.
+- The user's browser runs that javascript, which requests data for each of the
+  widgets defined on the page.
+- The wsgi app receives those requests and checks to see if the data for any of
+  them is *cached in memcached*.  If it is, then it is returned.  If not, then
+  the wsgi app executes the ``data(...)`` function of that widget to get the
+  response ready.  It is stuffed in memcached for later access and returned.
+- The client renders widgets as the data for each of its requests comes back.
+
+Later, what happens when a *trac ticket* is filed that should show up in some widget on their page?
+
+- The ticket is updated on fedorahosted.org and a fedmsg message is fired.
+- That is received by the hubs backend, which looks up *all* the cached
+  responses that should be invalidated by that event (there is a widget on
+  mizmo's page, threebean's page, and on the design hub that should all get
+  fresh data because of this change).
+- All of those widgets get their cached data nuked.
+- All of those widgets get their cached data rebuilt by calling ``data(...)`` on them.
+- An EventSource event is fired off for any listening clients that *new data is
+  available for widgets X, Y, and Z*.  The data is included in the EventSource
+  payload so the clients can immediately redraw without bothering to re-query
+  the wsgi app.
+
+What happens when the user is viewing the *design team* hub and
+simultaneously, an admin *changes the configuration of a widget on that page*?
+
+- Changing the configuration results in a HTTP POST to the wsgi app.
+- The configuration is changed accordingly in the postgres database.
+- A fedmsg message is fired off indicating that *the configuration for widget X
+  has changed*.
+- The wsgi app responds 200 OK to the admin.
+- Meanwhile, that fedmsg message is received by the backend which:
+- ...looks up the cache key for *widget X with the old configuration* and nukes
+  it the cached data.
+- ...looks up the cache key for *widget X with the new configuration* and
+  builds the cached data by calling ``data(...)`` on the widget.
+- An EventSource event is fired off which gets recieved by everyone looking at
+  the *design team hub*.  The widget on their pages gets redrawn with data from
+  the EventSource event.
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..1f5379f
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,24 @@
+.. fedora-hubs documentation master file, created by
+   sphinx-quickstart on Wed Sep 21 16:41:24 2016.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to Fedora Hubs' documentation!
+======================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   overview
+   dev-guide
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/docs/overview.rst b/docs/overview.rst
new file mode 100644
index 0000000..a72f167
--- /dev/null
+++ b/docs/overview.rst
@@ -0,0 +1,37 @@
+Fedora Hubs Overview
+====================
+
+Fedora Hubs is a web application that will provide a communication and collaboration
+center for Fedora contributors of all types. It aims to integrate with all the various
+tools teams use and provide a consistent experience for contributors across projects
+and teams.
+
+Without Fedora Hubs the Fedora web presence is very static. All of the action is on
+mailing lists and IRC which can be intimidating to new contributors. The vision is
+to have a modern, web-based Fedora activity center which feels like the positive,
+connected energy of Flock or FUDCon, available to all of us at any time.
+
+Integration
+^^^^^^^^^^^
+
+Fedora Hubs integrates with, or plans to integrate with, the following tools and projects:
+
+* IRC integration via the `Waartaa project <https://github.com/waartaa/waartaa>`_.
+
+* `Fedora Badges <https://badges.fedoraproject.org/>`_ integration.
+
+* `Mailing list <https://lists.fedoraproject.org/archives/>`_ integration via
+  `HyperKitty <https://gitlab.com/mailman/hyperkitty>`_.
+
+* `Fedora Planet <http://fedoraplanet.org/>`_ and `Fedora Magazine <https://fedoramagazine.org/>`_
+  integration.
+
+* `Zanata <https://fedora.zanata.org/>`_ integration.
+
+* Plusplus widget to award cookies, just like IRC.
+
+If you would like to know more, `these blog posts / videos
+<http://blog.linuxgrrl.com/category/fedora/fedora-hubs/>`_ are packed with lots of
+information about our vision for the project, or check out the
+`issue tracker <https://pagure.io/fedora-hubs/issues/>`_ to see what features are
+planned.

From 5296ac016ca932b03c388131aa3f60817ccea26d Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Oct 25 2016 15:23:24 +0000
Subject: [PATCH 654/1001] Explicitly install python2-pkgwat-api


For some reason, python2-pkgwat-api conflicts with python-pkgwat-api,
which shipped with F24. This has been reported[0], but this commit works
around the issue by explictly using ``python2``.

[0] https://bugzilla.redhat.com/show_bug.cgi?id=1388544

Signed-off-by: Jeremy Cline <jeremy@jcline.org>

---

diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
index c9add18..9f2ec6b 100755
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -42,7 +42,7 @@
     - pytz
     - python-sqlalchemy
     - python-markdown
-    - python-pkgwat-api
+    - python2-pkgwat-api
     - python-six
     - python-pygments
     - python-pygments-markdown-lexer

From 7da1dcda4a8290d9ff116f967e50108a6c355848 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Nov 01 2016 17:46:36 +0000
Subject: [PATCH 655/1001] some code beautification in library widget


---

diff --git a/hubs/widgets/library.py b/hubs/widgets/library.py
index c476ced..b18354a 100644
--- a/hubs/widgets/library.py
+++ b/hubs/widgets/library.py
@@ -16,8 +16,12 @@ position = 'both'
           help="A comma separated list of URLs to add to the library. "
           "External links must include the whole link (starting with http...)")
 def data(session, widget, urls):
+    ''' Data for the Library widget. Given the widget, it
+    returns the hypertext links of it's configuration urls '''
+
     urls = [
-        clean_input.clean('<a href="{0}">{0}</a>'.format(u.encode('utf-8').strip()))
+        clean_input.clean(
+            '<a href="{0}">{0}</a>'.format(u.encode('utf-8').strip()))
         for u in widget.config.get('urls', '').split(',')
         if u.encode('utf-8').strip()
     ]
@@ -26,6 +30,9 @@ def data(session, widget, urls):
 
 @hint(topics=[_('hubs.widget.update')])
 def should_invalidate(message, session, widget):
+    ''' Check if the Library widget cache needs an update.
+    Called by a backend daemon listening to fedmsg '''
+
     if not message['topic'].endswith('hubs.widget.update'):
         return False
     if message['msg']['widget']['id'] != widget.id:

From b6898dd41b93f325d173c91bf3b81d7157b49f9d Mon Sep 17 00:00:00 2001
From: skrzepto <shims506@gmail.com>
Date: Nov 05 2016 21:38:41 +0000
Subject: [PATCH 656/1001] Fix unittests


fixed test hub json

fixing models unittests

fixing string comparison

ralph widget index changed, fixing to pass tests. TODO: have the index not be hardcoded in unittest

---

diff --git a/hubs/app.py b/hubs/app.py
index 3862a24..5a453a0 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -787,7 +787,7 @@ def plus_plus_update(user):
     data = {'sender': sender.username, update: update_bool_val}
     req = None
     try:
-        req = request('POST', url=pp_url, headers=auth_header, data=data)
+        req = requests.post(url=pp_url, headers=auth_header, data=data)
     except:
         flask.abort(500)
 
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index d2966ed..6dcfcdc 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -1,5 +1,6 @@
 import unittest
 from urlparse import urlparse
+import ast # import for string to dict conversion without unicode
 
 from flask import json
 from os.path import dirname
@@ -80,9 +81,9 @@ class HubsAPITest(hubs.tests.APPTest):
             "owners": ["ralph"],
             "subscribers": [],
             "summary": "Ralph",
-            "widgets": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 51]
+            "widgets": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56]
         }
-        self.assertDictEqual(data, json.loads(result.data))
+        self.assertDictEqual(data, ast.literal_eval(result.data))
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_get_logged_out(self):
@@ -262,9 +263,9 @@ class HubsAPITest(hubs.tests.APPTest):
     def test_hub_edit_widget_get_logged_in(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            result = self.app.get('/ralph/31/edit', follow_redirects=True)
+            result = self.app.get('/ralph/37/edit', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            expected_str = '<input id="message_limit" class="form-control" type="text"'
+            expected_str = '/ralph/37/edit'
             self.assertTrue(expected_str in result.data)
 
     @unittest.skip("Authorization layer not present yet")
@@ -276,7 +277,7 @@ class HubsAPITest(hubs.tests.APPTest):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             data = {}
-            url = '/ralph/31/edit'
+            url = '/ralph/37/edit'
             result = self.app.post(url, data=data, follow_redirects=False)
             self.assertEqual(result.status_code, 302)
             self.assertEqual(urlparse(result.location).path, '/ralph/')
@@ -338,7 +339,7 @@ class HubsAPITest(hubs.tests.APPTest):
     def test_hub_delete(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            url = '/ralph/31/delete'  # 31 is widget feed for ralph
+            url = '/ralph/37/delete'  # 37 is widget fedmsgstats for ralph
             result = self.app.post(url)
             self.assertEqual(result.status_code, 302)
             self.assertTrue('/ralph/edit' in result.data)
@@ -363,11 +364,11 @@ class HubsAPITest(hubs.tests.APPTest):
             def __init__(self, json_data, status_code):
                 self.json_data = json_data
                 self.status_code = status_code
-
+                self.text = str(json_data)
             def json(self):
                 return self.json_data
 
-        if '/plus_plus/decause/status' in args:
+        if '/decause' in args[0]:
             data = {
                 "current": 0,
                 "decrements": 0,
@@ -385,11 +386,11 @@ class HubsAPITest(hubs.tests.APPTest):
             def __init__(self, json_data, status_code):
                 self.json_data = json_data
                 self.status_code = status_code
+                self.text = str(json_data)
 
             def json(self):
                 return self.json_data
-
-        if '/plus_plus/decause/update' in args:
+        if '/decause' in kwargs['url']:
             data = {
                 "current": 1,
                 "decrements": 0,
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index c3d540d..93f4a31 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -30,7 +30,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets still are intact
         widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
-        self.assertEqual(11, len(widgets))
+        self.assertEqual(12, len(widgets))
 
     def test_delete_hubs(self):
         # verify the hub exists
@@ -46,7 +46,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets exist
         widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
-        self.assertEqual(11, len(widgets))
+        self.assertEqual(12, len(widgets))
 
         # delete the hub
         self.session.delete(hub)
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index a0ec275..f67e476 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -15,7 +15,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
-            u'edit_url': u'/ralph/51/edit',
+            u'edit_url': u'/ralph/56/edit',
             u'source_url': u'/source/about',
             u'text': u'Testing.',
         })
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index 8cd43e4..c88b7a4 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -13,7 +13,7 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
-            u'edit_url': u'/ralph/33/edit',
+            u'edit_url': u'/ralph/37/edit',
             u'fedmsgs': 83854,
             u'fedmsgs_text': u'83,854',
             u'source_url': u'/source/fedmsgstats',
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 27a32cf..bd01019 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -16,12 +16,12 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
                 "urls": "ralph/"
             },
             "data": {
-                "edit_url": "/ralph/52/edit",
-                "source_url": "/source/library",
-                "urls": [
-                    "<a href=\"ralph/\">ralph/</a>"
+                u"edit_url": u"/ralph/57/edit",
+                u"source_url": u"/source/library",
+                u"urls": [
+                    u"<a href=\"ralph/\">ralph/</a>"
                 ],
-                "widget_url": "/ralph/52"
+                u"widget_url": u"/ralph/57"
             },
             "description": None,
             "hub": "ralph",

From 4eb7a68202eae2bd6ccebcbca1403d5fecdef353 Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Nov 08 2016 16:04:34 +0000
Subject: [PATCH 657/1001] Update the README links to point to the proper domain


The docs links were pointing to a sub-domain of pagure.io, but the docs
are actually served from docs.pagure.org.

Signed-off-by: Jeremy Cline <jeremy@jcline.org>

---

diff --git a/README.rst b/README.rst
index 2366db5..9ea968c 100644
--- a/README.rst
+++ b/README.rst
@@ -18,7 +18,7 @@ weekly in ``#fedora-hubs`` at 14:00UTC and the minutes for every meeting are
 In the meetings we review our statuses from the preceding week and do ticket triage, too.
 
 For a more detailed overview of what Fedora Hubs is, see the
-`documentation <https://docs.pagure.io/fedora-hubs/overview.html>`_.
+`documentation <https://docs.pagure.org/fedora-hubs/overview.html>`_.
 
 To set up a development environment and start contributing, check out
-the `development guide <https://docs.pagure.io/fedora-hubs/dev-guide.html>`_.
+the `development guide <https://docs.pagure.org/fedora-hubs/dev-guide.html>`_.

From 57aa97cb9e7e21adf0ea033d10af54215a344a2d Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Nov 29 2016 19:55:03 +0000
Subject: [PATCH 658/1001] Update react-dom to ^15.4.1


Fixes #275

Signed-off-by: Jeremy Cline <jeremy@jcline.org>

---

diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index c9ca168..a039acb 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -12,7 +12,7 @@
     "babel-preset-es2015": "~6.9.0",
     "babel-preset-react": "~6.5.0",
     "react": "^15.3.2",
-    "react-dom": "~15.1.0",
+    "react-dom": "^15.4.1",
     "react-timeago": "^3.1.1",
     "webpack": "~1.13.1"
   },

From 1477cd6e71a02ffdfbc4f45c9f392f880626504a Mon Sep 17 00:00:00 2001
From: Sayan Chowdhury <sayan.chowdhury2012@gmail.com>
Date: Nov 29 2016 20:08:04 +0000
Subject: [PATCH 659/1001] Mantain the same version numbers for the react-* sub packages


---

diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index a039acb..746d6c6 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -11,8 +11,8 @@
     "babel-plugin-transform-class-properties": "^6.10.2",
     "babel-preset-es2015": "~6.9.0",
     "babel-preset-react": "~6.5.0",
-    "react": "^15.3.2",
-    "react-dom": "^15.4.1",
+    "react": "^15.4.0",
+    "react-dom": "^15.4.0",
     "react-timeago": "^3.1.1",
     "webpack": "~1.13.1"
   },
@@ -24,8 +24,8 @@
     "babel-preset-stage-1": "^6.5.0",
     "eslint": "^2.13.1",
     "jest": "^14.1.0",
-    "react-addons-test-utils": "^15.3.0",
-    "react-test-renderer": "^15.3.0"
+    "react-addons-test-utils": "^15.4.0",
+    "react-test-renderer": "^15.4.0"
   },
   "scripts": {
     "dev": "webpack --watch",

From 2f9ae803c1ce3bce008d83e4b6528f908e9f83b2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 24 2017 12:42:57 +0000
Subject: [PATCH 660/1001] Don't include the whole page in the <header> tag


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 9de8638..a9a4a71 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -30,7 +30,7 @@
       {% endif %}
     </nav>
   
-    <div class="col-md-10">
+    <div class="col-md-10 col-md-offset-2">
       <div class="row">
         
         <!-- Left side of header -->
@@ -102,11 +102,16 @@
             {%- endfor -%}
             </ul>
           </div>
-        </div>
         {%- endif -%}
         {%- endwith -%}
+      </div>
         
+    </div>
+  </header>
 
+  <div class="row">
+    <div class="col-md-offset-2">
+      <div class="row">
         <div class="col-md-{{ hub.left_width }}">
           <!--
             First, before the proper widgets.. a cobweb built-in widget.
@@ -179,11 +184,11 @@
           </div>
         </div>
 
-      </div>      
+      </div>  <!-- /row -->
+    </div>  <!-- /col-md-offset-2 -->
+  </div>  <!-- /row -->
       
     
-    </div>
-  </header>
 </div>
 
       

From 8206886ee69637705dff21be6bf45fe3da6c8d82 Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Jan 24 2017 17:48:24 +0000
Subject: [PATCH 661/1001] Merge #272 `Fixing unittests`


---

diff --git a/hubs/app.py b/hubs/app.py
index 3862a24..5a453a0 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -787,7 +787,7 @@ def plus_plus_update(user):
     data = {'sender': sender.username, update: update_bool_val}
     req = None
     try:
-        req = request('POST', url=pp_url, headers=auth_header, data=data)
+        req = requests.post(url=pp_url, headers=auth_header, data=data)
     except:
         flask.abort(500)
 
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index d2966ed..6dcfcdc 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -1,5 +1,6 @@
 import unittest
 from urlparse import urlparse
+import ast # import for string to dict conversion without unicode
 
 from flask import json
 from os.path import dirname
@@ -80,9 +81,9 @@ class HubsAPITest(hubs.tests.APPTest):
             "owners": ["ralph"],
             "subscribers": [],
             "summary": "Ralph",
-            "widgets": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 51]
+            "widgets": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56]
         }
-        self.assertDictEqual(data, json.loads(result.data))
+        self.assertDictEqual(data, ast.literal_eval(result.data))
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_get_logged_out(self):
@@ -262,9 +263,9 @@ class HubsAPITest(hubs.tests.APPTest):
     def test_hub_edit_widget_get_logged_in(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            result = self.app.get('/ralph/31/edit', follow_redirects=True)
+            result = self.app.get('/ralph/37/edit', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            expected_str = '<input id="message_limit" class="form-control" type="text"'
+            expected_str = '/ralph/37/edit'
             self.assertTrue(expected_str in result.data)
 
     @unittest.skip("Authorization layer not present yet")
@@ -276,7 +277,7 @@ class HubsAPITest(hubs.tests.APPTest):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             data = {}
-            url = '/ralph/31/edit'
+            url = '/ralph/37/edit'
             result = self.app.post(url, data=data, follow_redirects=False)
             self.assertEqual(result.status_code, 302)
             self.assertEqual(urlparse(result.location).path, '/ralph/')
@@ -338,7 +339,7 @@ class HubsAPITest(hubs.tests.APPTest):
     def test_hub_delete(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            url = '/ralph/31/delete'  # 31 is widget feed for ralph
+            url = '/ralph/37/delete'  # 37 is widget fedmsgstats for ralph
             result = self.app.post(url)
             self.assertEqual(result.status_code, 302)
             self.assertTrue('/ralph/edit' in result.data)
@@ -363,11 +364,11 @@ class HubsAPITest(hubs.tests.APPTest):
             def __init__(self, json_data, status_code):
                 self.json_data = json_data
                 self.status_code = status_code
-
+                self.text = str(json_data)
             def json(self):
                 return self.json_data
 
-        if '/plus_plus/decause/status' in args:
+        if '/decause' in args[0]:
             data = {
                 "current": 0,
                 "decrements": 0,
@@ -385,11 +386,11 @@ class HubsAPITest(hubs.tests.APPTest):
             def __init__(self, json_data, status_code):
                 self.json_data = json_data
                 self.status_code = status_code
+                self.text = str(json_data)
 
             def json(self):
                 return self.json_data
-
-        if '/plus_plus/decause/update' in args:
+        if '/decause' in kwargs['url']:
             data = {
                 "current": 1,
                 "decrements": 0,
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index c3d540d..93f4a31 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -30,7 +30,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets still are intact
         widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
-        self.assertEqual(11, len(widgets))
+        self.assertEqual(12, len(widgets))
 
     def test_delete_hubs(self):
         # verify the hub exists
@@ -46,7 +46,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets exist
         widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
-        self.assertEqual(11, len(widgets))
+        self.assertEqual(12, len(widgets))
 
         # delete the hub
         self.session.delete(hub)
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index a0ec275..f67e476 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -15,7 +15,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
-            u'edit_url': u'/ralph/51/edit',
+            u'edit_url': u'/ralph/56/edit',
             u'source_url': u'/source/about',
             u'text': u'Testing.',
         })
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index 8cd43e4..c88b7a4 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -13,7 +13,7 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
         data = json.loads(response.data)
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
-            u'edit_url': u'/ralph/33/edit',
+            u'edit_url': u'/ralph/37/edit',
             u'fedmsgs': 83854,
             u'fedmsgs_text': u'83,854',
             u'source_url': u'/source/fedmsgstats',
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 27a32cf..bd01019 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -16,12 +16,12 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
                 "urls": "ralph/"
             },
             "data": {
-                "edit_url": "/ralph/52/edit",
-                "source_url": "/source/library",
-                "urls": [
-                    "<a href=\"ralph/\">ralph/</a>"
+                u"edit_url": u"/ralph/57/edit",
+                u"source_url": u"/source/library",
+                u"urls": [
+                    u"<a href=\"ralph/\">ralph/</a>"
                 ],
-                "widget_url": "/ralph/52"
+                u"widget_url": u"/ralph/57"
             },
             "description": None,
             "hub": "ralph",

From 8aae861b573a343b94eb06c206bcd059b4ac5f46 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 25 2017 15:31:55 +0000
Subject: [PATCH 662/1001] Better way to generate JS from Python


---

diff --git a/hubs/models.py b/hubs/models.py
index 68197d8..dd6aaa2 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -266,6 +266,10 @@ class Hub(BASE):
             [w for w in self.widgets if not w.left],
             key=lambda w: w.index)
 
+    @property
+    def widgets_idx(self):
+        return [w.idx for w in self.widgets]
+
     def __json__(self, session):
         return {
             'name': self.name,
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 9de8638..4618c0c 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -335,7 +335,7 @@ function visit_counter() {
 visit_counter()
 
 function setup_widgets(widgets) {
-  var all_widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
+  var all_widgets = {{ hub.widgets_idx|tojson }};
   if (widgets == undefined) {
     var widgets = all_widgets;
   }
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 49a3dab..c2c0c7e 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -97,7 +97,7 @@
   src ="{{url_for('static', filename='js/hubs.js')}}"></script>
 <script>
  function setup_widgets(widgets) {
-   var all_widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
+   var all_widgets = {{ hub.widgets_idx|tojson }};
    if (widgets == undefined) {
      var widgets = all_widgets;
    }

From 69c116e77f2aa7822ce6d38e8e00f59f4b250a3e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 25 2017 15:32:20 +0000
Subject: [PATCH 663/1001] Use event delegation


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 4618c0c..c893767 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -282,9 +282,8 @@ $('#save_edits_btn').click(function() {
 
 <script type="text/javascript">
 function setup_edit_btns() {
-  $(".edit_widget").unbind();
-  $(".edit_widget").click(function() {
-    console.log($(this));
+  $("body").on("click", ".edit_widget", function(e) {
+    e.preventDefault();
     var _idx = $(this).attr('data-idx');
 
     $.ajax({
@@ -348,7 +347,6 @@ function setup_widgets(widgets) {
         setTimeout(function() {
           $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
         }, 100);
-        setup_edit_btns()
       },
       error: function() {
         $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
@@ -356,8 +354,8 @@ function setup_widgets(widgets) {
         console.trace();
       },
     });
-    setup_edit_btns();
   });
+  setup_edit_btns();
 
   {% if edit -%}
   make_widget_sortable();

From 2d911a7528e3aa134520d03059d36bb816094ae8 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 25 2017 15:36:07 +0000
Subject: [PATCH 664/1001] Don't use window.onload when we have jQuery


---

diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index c2c0c7e..478d3da 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -119,10 +119,6 @@
      });
    });
  }
- window.onload = function(){
-   setup_widgets();
-   setup_feeds();
- }
 
  function setup_feeds() {
    var actions = {{actions|safe}};
@@ -169,5 +165,9 @@
      });
    });
  }
+ $(function() {
+   setup_widgets();
+   setup_feeds();
+ });
 </script>
 {% endblock %}

From 2a8ab77b2d78b16c8076e758376ad3e82fef07f2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 25 2017 16:11:06 +0000
Subject: [PATCH 665/1001] Don't assume what the root URL is


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index c893767..7a132b3 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -333,14 +333,14 @@ function visit_counter() {
 
 visit_counter()
 
-function setup_widgets(widgets) {
+function setup_widgets(base_url, widgets) {
   var all_widgets = {{ hub.widgets_idx|tojson }};
   if (widgets == undefined) {
     var widgets = all_widgets;
   }
   $.each(widgets, function(i, widget) {
     $.ajax({
-      url: widget,
+      url: base_url + widget,
       dataType: 'html',
       success: function(html) {
         $('#widget-' + widget).html(html);
@@ -363,7 +363,7 @@ function setup_widgets(widgets) {
   {%- endif %}
 }
 
-setup_widgets();
+setup_widgets({{ url_for("hub", name=hub.name) }});
 
 /* This is how to activate and remove (here after 13 sec) the favicon
 notification */
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 478d3da..3fd4432 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -96,14 +96,14 @@
 <script type="text/javascript"
   src ="{{url_for('static', filename='js/hubs.js')}}"></script>
 <script>
- function setup_widgets(widgets) {
+ function setup_widgets(base_url, widgets) {
    var all_widgets = {{ hub.widgets_idx|tojson }};
    if (widgets == undefined) {
      var widgets = all_widgets;
    }
    $.each(widgets, function(i, widget) {
      $.ajax({
-       url: '/{{hub.name}}/' + widget,
+       url: base_url + widget,
        dataType: 'html',
        success: function(html) {
          $('#widget-' + widget).html(html);
@@ -166,7 +166,7 @@
    });
  }
  $(function() {
-   setup_widgets();
+   setup_widgets({{ url_for("hub", name=hub.name) }});
    setup_feeds();
  });
 </script>

From 0e7559e003d2532f4fec4bbbeb3fa8ae77c59b59 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 25 2017 16:11:06 +0000
Subject: [PATCH 666/1001] Move duplicated JS code to the utils library


---

diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
index 1e97046..01f2382 100644
--- a/hubs/static/js/utils.js
+++ b/hubs/static/js/utils.js
@@ -10,3 +10,25 @@ var collapse_feed_entries = function(idx) {
     $("#collapse-" + idx).addClass('hidden');
     $("#content-" + idx).addClass('hidden');
 }
+
+// Load widgets
+ function setup_widgets(base_url, widgets) {
+   console.log(base_url, widgets);
+   $.each(widgets, function(i, widget) {
+     $.ajax({
+       url: base_url + widget,
+       dataType: 'html',
+       success: function(html) {
+         $('#widget-' + widget).html(html);
+         setTimeout(function() {
+           $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
+         }, 100);
+       },
+       error: function() {
+         $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
+         console.log('error');
+         console.trace();
+       },
+     });
+   });
+ }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 7a132b3..5a1df4c 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -331,49 +331,30 @@ function visit_counter() {
   }
 }
 
-visit_counter()
-
-function setup_widgets(base_url, widgets) {
-  var all_widgets = {{ hub.widgets_idx|tojson }};
-  if (widgets == undefined) {
-    var widgets = all_widgets;
-  }
-  $.each(widgets, function(i, widget) {
-    $.ajax({
-      url: base_url + widget,
-      dataType: 'html',
-      success: function(html) {
-        $('#widget-' + widget).html(html);
-        setTimeout(function() {
-          $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
-        }, 100);
-      },
-      error: function() {
-        $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
-        console.log('error');
-        console.trace();
-      },
-    });
-  });
+$(function() {
+  visit_counter()
+  
+  setup_widgets(
+    {{ url_for("hub", name=hub.name) }},
+    {{ hub.widgets_idx|tojson }}
+    );
   setup_edit_btns();
-
+  
   {% if edit -%}
   make_widget_sortable();
   setup_add_btns();
   {%- endif %}
-}
 
-setup_widgets({{ url_for("hub", name=hub.name) }});
-
-/* This is how to activate and remove (here after 13 sec) the favicon
-notification */
-console.log('Show notification');
-Notificon('#33ff00');
-setTimeout(function(){console.log('Hide notification'); Notificon()}, 13000)
-setTimeout(function(){
-    console.log('Show notification'); Notificon('#eb361e')
-  }, 15000)
-setTimeout(function(){console.log('Hide notification'); Notificon()}, 18000)
+  /* This is how to activate and remove (here after 13 sec) the favicon
+  notification */
+  console.log('Show notification');
+  Notificon('#33ff00');
+  setTimeout(function(){console.log('Hide notification'); Notificon()}, 13000)
+  setTimeout(function(){
+      console.log('Show notification'); Notificon('#eb361e')
+    }, 15000)
+  setTimeout(function(){console.log('Hide notification'); Notificon()}, 18000)
+});
 
 </script>
 {% endblock %}
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 3fd4432..278b076 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -95,30 +95,9 @@
 {{ super() }}
 <script type="text/javascript"
   src ="{{url_for('static', filename='js/hubs.js')}}"></script>
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/utils.js') }}"></script>
 <script>
- function setup_widgets(base_url, widgets) {
-   var all_widgets = {{ hub.widgets_idx|tojson }};
-   if (widgets == undefined) {
-     var widgets = all_widgets;
-   }
-   $.each(widgets, function(i, widget) {
-     $.ajax({
-       url: base_url + widget,
-       dataType: 'html',
-       success: function(html) {
-         $('#widget-' + widget).html(html);
-         setTimeout(function() {
-           $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
-         }, 100);
-       },
-       error: function() {
-         $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
-         console.log('error');
-         console.trace();
-       },
-     });
-   });
- }
 
  function setup_feeds() {
    var actions = {{actions|safe}};
@@ -166,7 +145,10 @@
    });
  }
  $(function() {
-   setup_widgets({{ url_for("hub", name=hub.name) }});
+   setup_widgets(
+    {{ url_for("hub", name=hub.name) }},
+    {{ hub.widgets_idx|tojson }}
+    );
    setup_feeds();
  });
 </script>

From 874a7721e0a72888e83374bc772d547a458b1527 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 26 2017 08:27:42 +0000
Subject: [PATCH 667/1001] Fix Python3 support


---

diff --git a/hubs/app.py b/hubs/app.py
index 5a453a0..a2a48a4 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,9 +1,11 @@
+from __future__ import print_function
+
 import datetime
 import functools
 import json
 import logging
 import os
-import urlparse
+from six.moves.urllib import parse as urlparse
 
 import flask
 import flask.json
@@ -349,7 +351,7 @@ def hub_add_widget_post(name):
             widget.hub.last_edited = datetime.datetime.utcnow()
             session.commit()
         except Exception as err:
-            print err
+            print(err)
             flask.flash(
                 'Could not save the configuration to the database '
                 'if the error persists, please warn an admin',
diff --git a/hubs/tests/test_api/test_hub.py b/hubs/tests/test_api/test_hub.py
index 2fd513f..815411d 100644
--- a/hubs/tests/test_api/test_hub.py
+++ b/hubs/tests/test_api/test_hub.py
@@ -1,6 +1,6 @@
 import flask
 import unittest
-from urlparse import urlparse
+from six.moves.urllib.parse import urlparse
 
 import hubs.tests
 import hubs.models
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index 74acdc1..8440baf 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -1,5 +1,5 @@
 import json
-from urlparse import urlparse
+from six.moves.urllib.parse import urlparse
 
 import hubs.tests
 import hubs.models
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 6dcfcdc..ea4b6b9 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -1,5 +1,5 @@
 import unittest
-from urlparse import urlparse
+from six.moves.urllib.parse import urlparse
 import ast # import for string to dict conversion without unicode
 
 from flask import json
diff --git a/hubs/validators.py b/hubs/validators.py
index fd4066c..0a44d90 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -1,7 +1,7 @@
 import kitchen.text.converters
 
 import hubs.models
-import httplib
+import httplib2
 
 
 def required(session, value):
@@ -42,18 +42,17 @@ def fmn_context(session, value):
 
 
 def pagure_repo(session, value):
-    conn = httplib.HTTPSConnection("pagure.io")
-    conn.request("GET", "/%s" % value)
-    response = conn.getresponse()
+    conn = httplib2.Http()
+    response, _content = conn.request("https://pagure.io/%s" % value, "GET")
     if response.status == 200:
         return value
     raise ValueError('Invalid pagure repo')
 
 
 def fedorahosted_project(session, value):
-    conn = httplib.HTTPSConnection("fedorahosted.org")
-    conn.request("GET", "/%s" % value)
-    response = conn.getresponse()
+    conn = httplib2.Http()
+    response, _content = conn.request(
+        "https://fedorahosted.org/%s" % value, "GET")
     if response.status == 200:
         return value
     raise ValueError('Invalid fedorahosted project')
diff --git a/hubs/widgets/clean_input.py b/hubs/widgets/clean_input.py
index 316c7a4..2ec458a 100644
--- a/hubs/widgets/clean_input.py
+++ b/hubs/widgets/clean_input.py
@@ -1,4 +1,4 @@
-import urlparse
+from six.moves.urllib.parse import urlparse
 
 import bleach
 
@@ -10,8 +10,8 @@ def filter_img_src(name, value):
     if name in ('alt', 'height', 'width', 'class'):
         return True
     if name == 'src':
-        p = urlparse.urlparse(value)
-        return (not p.netloc) or p.netloc == urlparse.urlparse(
+        p = urlparse(value)
+        return (not p.netloc) or p.netloc == urlparse(
             hubs.app.app.config['APP_URL']).netloc
     return False
 
diff --git a/hubs/widgets/fhosted.py b/hubs/widgets/fhosted.py
index c2bcd45..827b228 100644
--- a/hubs/widgets/fhosted.py
+++ b/hubs/widgets/fhosted.py
@@ -1,4 +1,4 @@
-from xmlrpclib import ServerProxy
+from six.moves.xmlrpc_client import ServerProxy
 
 import hubs.validators as validators
 from hubs.widgets.chrome import panel
diff --git a/requirements.txt b/requirements.txt
index a63b658..8cd42fa 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,6 +12,7 @@ fmn.lib
 fmn.rules
 gunicorn
 html5lib
+httplib2
 munch
 psycopg2
 pytz

From cad482dae039b4aa1585cb53521414ff796ea364 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 26 2017 08:27:42 +0000
Subject: [PATCH 668/1001] Use requests instead of httplib2


---

diff --git a/hubs/validators.py b/hubs/validators.py
index 0a44d90..a33fe0f 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -1,7 +1,7 @@
 import kitchen.text.converters
 
 import hubs.models
-import httplib2
+import requests
 
 
 def required(session, value):
@@ -42,17 +42,14 @@ def fmn_context(session, value):
 
 
 def pagure_repo(session, value):
-    conn = httplib2.Http()
-    response, _content = conn.request("https://pagure.io/%s" % value, "GET")
-    if response.status == 200:
+    response = requests.get("https://pagure.io/%s" % value)
+    if response.status_code == 200:
         return value
     raise ValueError('Invalid pagure repo')
 
 
 def fedorahosted_project(session, value):
-    conn = httplib2.Http()
-    response, _content = conn.request(
-        "https://fedorahosted.org/%s" % value, "GET")
-    if response.status == 200:
+    response = requests.get("https://fedorahosted.org/%s" % value)
+    if response.status_code == 200:
         return value
     raise ValueError('Invalid fedorahosted project')
diff --git a/requirements.txt b/requirements.txt
index 8cd42fa..d8d0088 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,10 +12,10 @@ fmn.lib
 fmn.rules
 gunicorn
 html5lib
-httplib2
 munch
 psycopg2
 pytz
+requests
 sqlalchemy
 markdown
 pkgwat.api
diff --git a/setup.py b/setup.py
index 6ddbd37..15f69c2 100644
--- a/setup.py
+++ b/setup.py
@@ -34,6 +34,7 @@ setup(
         'Topic :: Software Development :: Libraries :: Python Modules',
         'Intended Audience :: Developers',
         'Programming Language :: Python',
+        'Programming Language :: Python :: 3',
     ],
     entry_points={
         'moksha.consumer': [

From 1059f3214fd89b66492aba081e0ab9c4372ffc09 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 26 2017 08:27:42 +0000
Subject: [PATCH 669/1001] Add a timeout to the requests-based validators


---

diff --git a/hubs/validators.py b/hubs/validators.py
index a33fe0f..2ae918f 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -42,14 +42,14 @@ def fmn_context(session, value):
 
 
 def pagure_repo(session, value):
-    response = requests.get("https://pagure.io/%s" % value)
+    response = requests.get("https://pagure.io/%s" % value, timeout=5)
     if response.status_code == 200:
         return value
     raise ValueError('Invalid pagure repo')
 
 
 def fedorahosted_project(session, value):
-    response = requests.get("https://fedorahosted.org/%s" % value)
+    response = requests.get("https://fedorahosted.org/%s" % value, timeout=5)
     if response.status_code == 200:
         return value
     raise ValueError('Invalid fedorahosted project')

From 7e3eb51a00e877be10f48dfaacb8b8235d037166 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 26 2017 16:12:33 +0000
Subject: [PATCH 670/1001] Add a docblock


---

diff --git a/hubs/models.py b/hubs/models.py
index dd6aaa2..add289e 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -268,6 +268,7 @@ class Hub(BASE):
 
     @property
     def widgets_idx(self):
+        """Returns the list of indices for this hub's widgets."""
         return [w.idx for w in self.widgets]
 
     def __json__(self, session):

From 261778bdf79fa41bc82d6b1282fe6fbaf85fb62d Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Jan 26 2017 16:30:50 +0000
Subject: [PATCH 671/1001] Merge #303 `Small improvements in the Javascript code`


---

diff --git a/hubs/models.py b/hubs/models.py
index 68197d8..add289e 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -266,6 +266,11 @@ class Hub(BASE):
             [w for w in self.widgets if not w.left],
             key=lambda w: w.index)
 
+    @property
+    def widgets_idx(self):
+        """Returns the list of indices for this hub's widgets."""
+        return [w.idx for w in self.widgets]
+
     def __json__(self, session):
         return {
             'name': self.name,
diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
index 1e97046..01f2382 100644
--- a/hubs/static/js/utils.js
+++ b/hubs/static/js/utils.js
@@ -10,3 +10,25 @@ var collapse_feed_entries = function(idx) {
     $("#collapse-" + idx).addClass('hidden');
     $("#content-" + idx).addClass('hidden');
 }
+
+// Load widgets
+ function setup_widgets(base_url, widgets) {
+   console.log(base_url, widgets);
+   $.each(widgets, function(i, widget) {
+     $.ajax({
+       url: base_url + widget,
+       dataType: 'html',
+       success: function(html) {
+         $('#widget-' + widget).html(html);
+         setTimeout(function() {
+           $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
+         }, 100);
+       },
+       error: function() {
+         $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
+         console.log('error');
+         console.trace();
+       },
+     });
+   });
+ }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index a9a4a71..fed9ae6 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -287,9 +287,8 @@ $('#save_edits_btn').click(function() {
 
 <script type="text/javascript">
 function setup_edit_btns() {
-  $(".edit_widget").unbind();
-  $(".edit_widget").click(function() {
-    console.log($(this));
+  $("body").on("click", ".edit_widget", function(e) {
+    e.preventDefault();
     var _idx = $(this).attr('data-idx');
 
     $.ajax({
@@ -337,50 +336,30 @@ function visit_counter() {
   }
 }
 
-visit_counter()
-
-function setup_widgets(widgets) {
-  var all_widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
-  if (widgets == undefined) {
-    var widgets = all_widgets;
-  }
-  $.each(widgets, function(i, widget) {
-    $.ajax({
-      url: widget,
-      dataType: 'html',
-      success: function(html) {
-        $('#widget-' + widget).html(html);
-        setTimeout(function() {
-          $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
-        }, 100);
-        setup_edit_btns()
-      },
-      error: function() {
-        $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
-        console.log('error');
-        console.trace();
-      },
-    });
-    setup_edit_btns();
-  });
-
+$(function() {
+  visit_counter()
+  
+  setup_widgets(
+    {{ url_for("hub", name=hub.name) }},
+    {{ hub.widgets_idx|tojson }}
+    );
+  setup_edit_btns();
+  
   {% if edit -%}
   make_widget_sortable();
   setup_add_btns();
   {%- endif %}
-}
 
-setup_widgets();
-
-/* This is how to activate and remove (here after 13 sec) the favicon
-notification */
-console.log('Show notification');
-Notificon('#33ff00');
-setTimeout(function(){console.log('Hide notification'); Notificon()}, 13000)
-setTimeout(function(){
-    console.log('Show notification'); Notificon('#eb361e')
-  }, 15000)
-setTimeout(function(){console.log('Hide notification'); Notificon()}, 18000)
+  /* This is how to activate and remove (here after 13 sec) the favicon
+  notification */
+  console.log('Show notification');
+  Notificon('#33ff00');
+  setTimeout(function(){console.log('Hide notification'); Notificon()}, 13000)
+  setTimeout(function(){
+      console.log('Show notification'); Notificon('#eb361e')
+    }, 15000)
+  setTimeout(function(){console.log('Hide notification'); Notificon()}, 18000)
+});
 
 </script>
 {% endblock %}
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 49a3dab..278b076 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -95,34 +95,9 @@
 {{ super() }}
 <script type="text/javascript"
   src ="{{url_for('static', filename='js/hubs.js')}}"></script>
+<script type="text/javascript" src="{{
+  url_for('static', filename='js/utils.js') }}"></script>
 <script>
- function setup_widgets(widgets) {
-   var all_widgets = [{% for widget in hub.widgets %}'{{ widget.idx }}',{% endfor %}];
-   if (widgets == undefined) {
-     var widgets = all_widgets;
-   }
-   $.each(widgets, function(i, widget) {
-     $.ajax({
-       url: '/{{hub.name}}/' + widget,
-       dataType: 'html',
-       success: function(html) {
-         $('#widget-' + widget).html(html);
-         setTimeout(function() {
-           $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
-         }, 100);
-       },
-       error: function() {
-         $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
-         console.log('error');
-         console.trace();
-       },
-     });
-   });
- }
- window.onload = function(){
-   setup_widgets();
-   setup_feeds();
- }
 
  function setup_feeds() {
    var actions = {{actions|safe}};
@@ -169,5 +144,12 @@
      });
    });
  }
+ $(function() {
+   setup_widgets(
+    {{ url_for("hub", name=hub.name) }},
+    {{ hub.widgets_idx|tojson }}
+    );
+   setup_feeds();
+ });
 </script>
 {% endblock %}

From 4e853e2515aa9eccbb0981a408cebd95118b3f2f Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Jan 26 2017 19:38:26 +0000
Subject: [PATCH 672/1001] Add a license to the git repository


There was not a copy of the AGPLv3 included in the repository, so I
added one.

Signed-off-by: Jeremy Cline <jeremy@jcline.org>

---

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..dba13ed
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU Affero General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.

From 32f372b0a59f5fdab8838e139b08f17514c4bee7 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 27 2017 15:30:02 +0000
Subject: [PATCH 673/1001] Add a way for plugins to register their own routes


---

diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
index 35b1871..a69004b 100644
--- a/docs/dev-guide.rst
+++ b/docs/dev-guide.rst
@@ -381,6 +381,42 @@ If you want to try making a new widget:
 
 Destroy your database, rebuild it, and re-run the app.  Your widget should show up.
 
+A widget may also register additional routes by declaring a ``ROUTES`` list in
+the widget module. This list will contain dictionnaries that represent the
+arguments passed to Flask's `add_url_rule
+<http://flask.pocoo.org/docs/latest/api/#flask.Flask.add_url_rule>`_ function.
+There are some changes from the basic ``add_url_rule`` function:
+
+- The view function will be passed the ``session`` and ``widget`` instances as
+  first arguments, and then the URL kwargs.
+- The endpoint will be prefixed with ``<widget_name>_``, for example
+  ``meetings_``. Remember that when you want to reverse the URL with
+  ``url_for``.
+- When reversing the URL, you need to pass the ``hub`` and ``idx`` kwargs.
+
+Example: consider this additional method that needs to be exported as a view
+in the ``meetings`` plugin::
+
+    def search(session, widget, requester):
+        # Do something, probably using the "requester" variable.
+        return flask.jsonify({"hope_sources": ["Obi-Wan Kenobi"]})
+
+It will be registered as a view using the following module variable::
+
+    ROUTES = [
+        {
+            "rule": "search/<requester>/",
+            "endpoint": "search",
+            "view_func": search,
+            "methods": ["GET", "POST"],  # if needed
+        },
+    ]
+
+And a valid call to ``url_for`` to reverse this URL would look like::
+
+    url_for("meetings_search", hub=widget.hub.name, idx=widget.idx, requester="Leia")
+
+
 A proposal, client-side templates
 =================================
 
diff --git a/hubs/app.py b/hubs/app.py
index a2a48a4..1990f58 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -797,3 +797,25 @@ def plus_plus_update(user):
         return flask.jsonify(req.json())
     else:
         return req.text, req.status_code
+
+
+#
+# Add widget-specific routes
+#
+
+def widget_view_decorator(func):
+    @functools.wraps(func)
+    def inner(*args, **kwargs):
+        hubname = kwargs.pop("hub")
+        widgetidx = kwargs.pop("idx")
+        widget = get_widget(session, hubname, widgetidx)
+        return func(session, widget, *args, **kwargs)
+    return inner
+
+for widget in session.query(hubs.models.Widget):
+    for params in getattr(widget.module, 'ROUTES', []):
+        params["rule"] = "/<hub>/<int:idx>/widget/" \
+                         + params["rule"].lstrip("/")
+        params["endpoint"] = "%s_%s" % (widget.plugin, params["endpoint"])
+        params["view_func"] = widget_view_decorator(params["view_func"])
+        app.add_url_rule(**params)

From 2b95bdb2ca6bde903df160a38f20d8ffc20028da Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 27 2017 15:30:02 +0000
Subject: [PATCH 674/1001] Fix typo


---

diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
index a69004b..25680ac 100644
--- a/docs/dev-guide.rst
+++ b/docs/dev-guide.rst
@@ -382,7 +382,7 @@ If you want to try making a new widget:
 Destroy your database, rebuild it, and re-run the app.  Your widget should show up.
 
 A widget may also register additional routes by declaring a ``ROUTES`` list in
-the widget module. This list will contain dictionnaries that represent the
+the widget module. This list will contain dictionaries that represent the
 arguments passed to Flask's `add_url_rule
 <http://flask.pocoo.org/docs/latest/api/#flask.Flask.add_url_rule>`_ function.
 There are some changes from the basic ``add_url_rule`` function:

From 921f4950e1c389de651b6d7d66a2cccea40deb1b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 27 2017 15:30:02 +0000
Subject: [PATCH 675/1001] Switch to a decorator system for the widget routes


It makes them much easier to declare.

---

diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
index 25680ac..1d742f5 100644
--- a/docs/dev-guide.rst
+++ b/docs/dev-guide.rst
@@ -381,11 +381,11 @@ If you want to try making a new widget:
 
 Destroy your database, rebuild it, and re-run the app.  Your widget should show up.
 
-A widget may also register additional routes by declaring a ``ROUTES`` list in
-the widget module. This list will contain dictionaries that represent the
-arguments passed to Flask's `add_url_rule
-<http://flask.pocoo.org/docs/latest/api/#flask.Flask.add_url_rule>`_ function.
-There are some changes from the basic ``add_url_rule`` function:
+Widget-specific views
+---------------------
+A widget may also register additional routes by using the
+``hubs.widgets.base.widget_route`` decorator. There are some differences from
+the usual ``route`` decorator or the ``add_url_rule`` function:
 
 - The view function will be passed the ``session`` and ``widget`` instances as
   first arguments, and then the URL kwargs.
@@ -397,24 +397,25 @@ There are some changes from the basic ``add_url_rule`` function:
 Example: consider this additional method that needs to be exported as a view
 in the ``meetings`` plugin::
 
+    from hubs.widgets.base import widget_route
+    @widget_route(rule="search/<requester>/", methods=["GET", "POST"])
     def search(session, widget, requester):
         # Do something, probably using the "requester" variable.
         return flask.jsonify({"hope_sources": ["Obi-Wan Kenobi"]})
 
-It will be registered as a view using the following module variable::
+Then, a valid call to ``url_for`` to reverse this URL would look like::
 
-    ROUTES = [
-        {
-            "rule": "search/<requester>/",
-            "endpoint": "search",
-            "view_func": search,
-            "methods": ["GET", "POST"],  # if needed
-        },
-    ]
+    url_for("meetings_search", hub=widget.hub.name, idx=widget.idx, requester="Leia")
 
-And a valid call to ``url_for`` to reverse this URL would look like::
+Behind the scenes, the ``widget_route`` decorator adds a ``ROUTES`` global
+variable in the widget module, that contains dictionaries representing the
+arguments passed to Flask's `add_url_rule
+<http://flask.pocoo.org/docs/latest/api/#flask.Flask.add_url_rule>`_ function.
 
-    url_for("meetings_search", hub=widget.hub.name, idx=widget.idx, requester="Leia")
+If you want more control, you can edit this ``ROUTES`` list directly, but there
+are a difference from the basic ``add_url_rule`` function: the view function
+name must be given with the dict key ``view_func_name``, and not ``view_func``
+as in the ``add_url_rule`` function.
 
 
 A proposal, client-side templates
diff --git a/hubs/app.py b/hubs/app.py
index 1990f58..07ef281 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -816,6 +816,9 @@ for widget in session.query(hubs.models.Widget):
     for params in getattr(widget.module, 'ROUTES', []):
         params["rule"] = "/<hub>/<int:idx>/widget/" \
                          + params["rule"].lstrip("/")
+        if not params.get("endpoint"):
+            params["endpoint"] = params["view_func_name"]
         params["endpoint"] = "%s_%s" % (widget.plugin, params["endpoint"])
-        params["view_func"] = widget_view_decorator(params["view_func"])
+        params["view_func"] = widget_view_decorator(
+            getattr(widget.module, params.pop("view_func_name")))
         app.add_url_rule(**params)
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 91d3931..bde7bb1 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -3,6 +3,7 @@ import datetime
 import functools
 import hashlib
 import json
+import sys
 
 import dogpile.cache
 import flask
@@ -96,3 +97,13 @@ def wraps(original):
         subsequent.widget_arguments = getattr(original, 'widget_arguments', [])
         return subsequent
     return decorator
+
+
+def widget_route(**options):
+    def decorator(func):
+        options["view_func_name"] = func.__name__
+        mdict = sys.modules[func.__module__].__dict__
+        mroutes = mdict.setdefault('ROUTES', [])
+        mroutes.append(options)
+        return func
+    return decorator

From f24845b5644fe59de24eb51f5908355b726a37e9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 27 2017 15:30:02 +0000
Subject: [PATCH 676/1001] Add docstrings


---

diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
index 1d742f5..715315b 100644
--- a/docs/dev-guide.rst
+++ b/docs/dev-guide.rst
@@ -387,8 +387,8 @@ A widget may also register additional routes by using the
 ``hubs.widgets.base.widget_route`` decorator. There are some differences from
 the usual ``route`` decorator or the ``add_url_rule`` function:
 
-- The view function will be passed the ``session`` and ``widget`` instances as
-  first arguments, and then the URL kwargs.
+- The view function will be passed the database ``session`` and ``widget``
+  instances as first arguments, and then the URL kwargs.
 - The endpoint will be prefixed with ``<widget_name>_``, for example
   ``meetings_``. Remember that when you want to reverse the URL with
   ``url_for``.
diff --git a/hubs/app.py b/hubs/app.py
index 07ef281..f352afd 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -803,7 +803,14 @@ def plus_plus_update(user):
 # Add widget-specific routes
 #
 
-def widget_view_decorator(func):
+def _widget_view_decorator(func):
+    """
+    This internal decorator will edit the view function arguments.
+
+    It will:
+    - remove the hub name and the widget primary key
+    - add the database session and the widget instance
+    """
     @functools.wraps(func)
     def inner(*args, **kwargs):
         hubname = kwargs.pop("hub")
@@ -819,6 +826,6 @@ for widget in session.query(hubs.models.Widget):
         if not params.get("endpoint"):
             params["endpoint"] = params["view_func_name"]
         params["endpoint"] = "%s_%s" % (widget.plugin, params["endpoint"])
-        params["view_func"] = widget_view_decorator(
+        params["view_func"] = _widget_view_decorator(
             getattr(widget.module, params.pop("view_func_name")))
         app.add_url_rule(**params)
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index bde7bb1..f3cf198 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -100,6 +100,12 @@ def wraps(original):
 
 
 def widget_route(**options):
+    """Register a view for the current widget.
+
+    This decorator can be used to expose a specific function below a widget's
+    URL endpoint. Refer to the "Widget-specific views" section in the
+    documentation to learn how to construct the corresponding URL.
+    """
     def decorator(func):
         options["view_func_name"] = func.__name__
         mdict = sys.modules[func.__module__].__dict__

From 7fa1ee007d96d161cea414be47fab015bf2a678e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 27 2017 17:11:01 +0000
Subject: [PATCH 677/1001] More Python3 compatibility


---

diff --git a/hubs/app.py b/hubs/app.py
index f352afd..f75b404 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -5,6 +5,7 @@ import functools
 import json
 import logging
 import os
+import six
 from six.moves.urllib import parse as urlparse
 
 import flask
@@ -20,7 +21,7 @@ import hubs.stream
 
 import datanommer.models
 
-from hubs.utils import username2avatar
+from hubs.utils import username2avatar, to_str
 
 app = flask.Flask(__name__)
 
@@ -546,7 +547,7 @@ def notifications(user):
         return flask.jsonify(notifications)
 
     if flask.request.method == 'POST':
-        data = json.loads(flask.request.data)
+        data = json.loads(to_str(flask.request.data))
         user = hubs.models.User.by_username(session, user)
         if not user:
             return flask.abort(400)
@@ -756,7 +757,7 @@ def plus_plus_status(user):
 def plus_plus_update_bool_helper(val):
     if isinstance(val, bool):
         return val
-    elif isinstance(val, (str, unicode)):
+    elif isinstance(val, six.string_types):
         fmt_str = str(val).replace("'", "").replace('"', '').lower()
         return fmt_str in ("yes", "true", "t", "1")
     else:
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index 8440baf..66f8d99 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -4,6 +4,7 @@ from six.moves.urllib.parse import urlparse
 import hubs.tests
 import hubs.models
 from hubs.app import app
+from hubs.utils import to_str
 
 
 class TestGetNotifications(hubs.tests.APPTest):
@@ -15,7 +16,7 @@ class TestGetNotifications(hubs.tests.APPTest):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.get('/{}/notifications/'.format(name))
         self.assertEqual(resp.status_code, 200)
-        data = json.loads(resp.data)
+        data = json.loads(to_str(resp.data))
         self.assertEqual(data, [])
 
     def test_get_notifications_valid_name(self):
@@ -24,7 +25,7 @@ class TestGetNotifications(hubs.tests.APPTest):
                 self.user.username))
 
         self.assertEqual(resp.status_code, 200)
-        data = json.loads(resp.data)
+        data = json.loads(to_str(resp.data))
         self.assertEqual(len(data), 1)
 
         for saved in data:
@@ -67,7 +68,7 @@ class TestPostNotifications(hubs.tests.APPTest):
                 data=json.dumps(self.valid_payload))
 
         self.assertEqual(resp.status_code, 200)
-        data = json.loads(resp.data)
+        data = json.loads(to_str(resp.data))
         self.assertTrue(isinstance(data, dict))
 
         notification = data['notification']
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index ea4b6b9..d94ef4a 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -11,6 +11,7 @@ from werkzeug.datastructures import ImmutableMultiDict
 import hubs
 from hubs import tests
 from hubs.app import app
+from hubs.utils import to_str
 
 import hubs.models
 
@@ -287,10 +288,10 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             url = '/visit/decause'
             result = self.app.get(url)
-            self.assertEqual(json.loads(result.data), {"count": 0})
+            self.assertEqual(json.loads(to_str(result.data)), {"count": 0})
 
             result = self.app.post(url)
-            self.assertEqual(json.loads(result.data), {"count": 1})
+            self.assertEqual(json.loads(to_str(result.data)), {"count": 1})
 
             # accessing my hub shouldn't increment the count
             url = 'visit/ralph'
@@ -415,7 +416,7 @@ class HubsAPITest(hubs.tests.APPTest):
             "total": 0,
             "username": "decause"
         }
-        self.assertEqual(json.loads(result.data), expected)
+        self.assertEqual(load_json(result.data), expected)
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_valid(self, mock_post):
@@ -431,7 +432,7 @@ class HubsAPITest(hubs.tests.APPTest):
                 "total": 1,
                 "username": "decause"
             }
-            self.assertEqual(json.loads(result.data), expected)
+            self.assertEqual(load_json(result.data), expected)
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_myself_error(self, mock_post):
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index f67e476..2e358d0 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -3,6 +3,7 @@ import json
 from nose.tools import assert_dict_equal
 
 import hubs.tests.test_widgets
+from hubs.utils import to_str
 
 
 class TestBadges(hubs.tests.test_widgets.WidgetTest):
@@ -12,7 +13,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
+        data = json.loads(to_str(response.data))
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
             u'edit_url': u'/ralph/56/edit',
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index b3b5197..b7831c0 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -2,6 +2,7 @@ import json
 
 from mock import patch, MagicMock
 import hubs.tests.test_widgets
+from hubs.utils import to_str
 
 
 class TestBadges(hubs.tests.test_widgets.WidgetTest):
@@ -11,7 +12,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
+        data = json.loads(to_str(response.data))
         self.assertEquals(data['plugin'], 'badges')
         self.assertIn('assertions', data['data'].keys())
 
@@ -45,4 +46,4 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx + 1}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
-        self.assertTrue(result)
\ No newline at end of file
+        self.assertTrue(result)
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index c88b7a4..5f16417 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -1,6 +1,7 @@
 import json
 
 import hubs.tests.test_widgets
+from hubs.utils import to_str
 
 
 class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
@@ -10,7 +11,7 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
+        data = json.loads(to_str(response.data))
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
             u'edit_url': u'/ralph/37/edit',
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index bd01019..58376c4 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -2,6 +2,7 @@ import json
 
 import hubs.tests.test_widgets
 import hubs.models
+from hubs.utils import to_str
 
 class TestLibrary(hubs.tests.test_widgets.WidgetTest):
     plugin = 'library'  # The name in hubs.widgets.registry
@@ -10,7 +11,7 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         self.assertEqual(response.status_code, 200)
-        data = json.loads(response.data)
+        data = json.loads(to_str(response.data))
         expected_dict = {
             "config": {
                 "urls": "ralph/"
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 7184796..5df4bd5 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -1,6 +1,7 @@
 import json
 
 import hubs.tests.test_widgets
+from hubs.utils import to_str
 
 
 class TestMeetings(hubs.tests.test_widgets.WidgetTest):
@@ -11,7 +12,7 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/json/' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
-        data = json.loads(response.data)
+        data = json.loads(to_str(response.data))
         calendar_name = data['data']['calendar']
         self.assertIn(team, calendar_name)
 
@@ -21,4 +22,4 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/%s/%i/' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
         self.assertIn('i18n', response.data)
-        self.assertIn('<strong>Request A New Meeting</strong>', response.data)
\ No newline at end of file
+        self.assertIn('<strong>Request A New Meeting</strong>', response.data)
diff --git a/hubs/utils.py b/hubs/utils.py
index ed00d80..f5166bd 100755
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -1,9 +1,11 @@
+import json
 import logging
 from hashlib import sha256
 
 import arrow
 import markdown
 import requests
+import six
 
 from six.moves.urllib_parse import urlencode
 
@@ -80,3 +82,14 @@ def _github_results(url, auth):
                     part.split('; ')[0][1:-1],
                 ) for part in field.split(', ')
             ])
+
+
+def to_str(data):
+    """
+    A Python3-compatible way to return a string from a string or a UTF8-encoded
+    bytestring. Werkzeug responses are bytestrings on Python 3.
+    """
+    if isinstance(data, six.binary_type):
+        return data.decode('utf-8')
+    else:
+        return data

From cfa2cef4ee61ceb4dc080c51db313de26c6fef05 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 28 2017 09:04:21 +0000
Subject: [PATCH 678/1001] Fix string/unicode compat issues with Python 3


---

diff --git a/check-cache-coverage.py b/check-cache-coverage.py
index 0f6c6f7..a753f56 100755
--- a/check-cache-coverage.py
+++ b/check-cache-coverage.py
@@ -13,6 +13,8 @@ forcibly re-warms the cache.
 Authors:    Ralph Bean <rbean@redhat.com>
 """
 
+from __future__ import unicode_literals
+
 import sys
 import dogpile.cache
 
diff --git a/check-queue-length.py b/check-queue-length.py
index 4fc7098..5b14d0f 100755
--- a/check-queue-length.py
+++ b/check-queue-length.py
@@ -13,6 +13,8 @@ We could also graph this in collectd, for fun and profit.
 Authors:    Ralph Bean <rbean@redhat.com>
 """
 
+from __future__ import unicode_literals
+
 import fedmsg.config
 config = fedmsg.config.load_config()
 
diff --git a/delete-user.py b/delete-user.py
index acc2563..42a17c1 100755
--- a/delete-user.py
+++ b/delete-user.py
@@ -4,6 +4,8 @@
 Useful for testing what happens when you recreate them.
 """
 
+from __future__ import unicode_literals
+
 import sys
 
 import fedmsg.config
diff --git a/hubs/app.py b/hubs/app.py
index f75b404..ca3bd26 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,4 +1,4 @@
-from __future__ import print_function
+from __future__ import print_function, unicode_literals
 
 import datetime
 import functools
@@ -455,7 +455,7 @@ def widget_source(name):
     fname = ''
 
     try:
-        fname = base + registry[name].__file__.split(base, 1)[1]
+        fname = base + registry[name].__file__.split(base)[-1]
     except KeyError:
         flask.abort(404)
 
diff --git a/hubs/backend/consumer.py b/hubs/backend/consumer.py
index 9d73ef1..7ea5083 100755
--- a/hubs/backend/consumer.py
+++ b/hubs/backend/consumer.py
@@ -1,5 +1,7 @@
 # The fedora hubs backend daemon
 
+from __future__ import unicode_literals
+
 import fedmsg.consumers
 import fedmsg.meta
 
diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index ad86221..c1bf1da 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -19,6 +19,8 @@ though.  If they see that invalidation is required, they put a new task on an
 handle.
 """
 
+from __future__ import unicode_literals
+
 import hubs.app
 import hubs.models
 
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index 11c3342..abc1b32 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -24,6 +24,8 @@ another redis queue so that an EventSource server can update any connected web
 clients with the new content produced here.
 """
 
+from __future__ import unicode_literals
+
 import hubs.app
 import hubs.models
 
diff --git a/hubs/default_config.py b/hubs/default_config.py
index bb9ef80..769f8ad 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import os
 
 SECRET_KEY = 'changemeforreal'
diff --git a/hubs/defaults.py b/hubs/defaults.py
index 2a27612..d91d452 100755
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 import hubs.models
diff --git a/hubs/hinting.py b/hubs/hinting.py
index 14ed445..b1a8c2f 100755
--- a/hubs/hinting.py
+++ b/hubs/hinting.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import decorator
 
 import fedmsg.config
diff --git a/hubs/models.py b/hubs/models.py
index add289e..cdc02de 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -20,6 +20,7 @@
 # of Red Hat, Inc.
 #
 
+from __future__ import unicode_literals
 
 import datetime
 import json
diff --git a/hubs/stream.py b/hubs/stream.py
index fd45923..ced01b9 100644
--- a/hubs/stream.py
+++ b/hubs/stream.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 import os
 
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index e7f4eba..3730d4e 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from contextlib import contextmanager
 import json
 from datetime import datetime, timedelta
diff --git a/hubs/tests/test_api/test_hub.py b/hubs/tests/test_api/test_hub.py
index 815411d..821746c 100644
--- a/hubs/tests/test_api/test_hub.py
+++ b/hubs/tests/test_api/test_hub.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import flask
 import unittest
 from six.moves.urllib.parse import urlparse
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index 66f8d99..360fa4c 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 from six.moves.urllib.parse import urlparse
 
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index d94ef4a..edfc6a6 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import unittest
 from six.moves.urllib.parse import urlparse
 import ast # import for string to dict conversion without unicode
@@ -34,16 +36,16 @@ class HubsAPITest(hubs.tests.APPTest):
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
             self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login">login</a>' in result.data)
+                             '/login">login</a>' in to_str(result.data))
 
     def test_hub_logged_out(self):
         with tests.auth_set(app, None):  # check_auth doesn't load in unittest
             result = self.app.get('/ralph', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             match_expected = r'<h5[^>]*>Ralph</h5>'
-            self.assertRegexpMatches(result.data, match_expected)
+            self.assertRegexpMatches(to_str(result.data), match_expected)
             str_expected = 'Not logged in.'
-            self.assertTrue(str_expected in result.data)
+            self.assertTrue(str_expected in to_str(result.data))
 
     def test_groups_logged_out(self):
         result = self.app.get('/groups', follow_redirects=False)
@@ -58,7 +60,8 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get('/groups', follow_redirects=True)
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
-            self.assertTrue("ZOMG -  is the Hub Of The Month!" in result.data)
+            self.assertTrue("ZOMG -  is the Hub Of The Month!"
+                            in to_str(result.data))
 
     def test_hub_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -66,7 +69,7 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get('/ralph', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login">login</a>' in result.data)
+                             '/login">login</a>' in to_str(result.data))
 
     def test_hub_json(self):
         result = self.app.get('/ralph/json', follow_redirects=True)
@@ -84,7 +87,7 @@ class HubsAPITest(hubs.tests.APPTest):
             "summary": "Ralph",
             "widgets": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56]
         }
-        self.assertDictEqual(data, ast.literal_eval(result.data))
+        self.assertDictEqual(data, json.loads(to_str(result.data)))
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_get_logged_out(self):
@@ -134,9 +137,9 @@ class HubsAPITest(hubs.tests.APPTest):
                                    follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login">login</a>' in result.data)
+                             '/login">login</a>' in to_str(result.data))
             self.assertTrue('<a href="#" class="dropdown-item">Full Name: '
-                            'fullname: ralph</a>' in result.data)
+                            'fullname: ralph</a>' in to_str(result.data))
 
     def test_hub_edit_post_logged_in_owner_valid_data(self):
         user = tests.FakeAuthorization('ralph')
@@ -157,7 +160,7 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.post('/ralph/edit', data=data,
                                    follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            self.assertEqual(result.data, 'ok')
+            self.assertEqual(to_str(result.data), 'ok')
 
     def test_hub_edit_post_logged_in_owner_invalid_data_1(self):
         user = tests.FakeAuthorization('ralph')
@@ -212,30 +215,30 @@ class HubsAPITest(hubs.tests.APPTest):
         result = self.app.get('/ralph/add', follow_redirects=False)
         self.assertEqual(result.status_code, 400)
         expected_str = 'Invalid position provided'
-        self.assertTrue(expected_str in result.data)
+        self.assertTrue(expected_str in to_str(result.data))
 
     def test_hub_add_widget_get_with_args(self):
         result = self.app.get('/ralph/add?position=right',
                               follow_redirects=True)
         self.assertEqual(result.status_code, 200)
         expected_str = 'Adding widget to hub: ralph'
-        self.assertTrue(expected_str in result.data)
+        self.assertTrue(expected_str in to_str(result.data))
         expected_str = "url: 'add/' + $('#widget').val() + '?position=right',"
-        self.assertTrue(expected_str in result.data)
+        self.assertTrue(expected_str in to_str(result.data))
 
     def test_hub_add_widget_post_no_widget_name(self):
         data = {}
         result = self.app.post('/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 400)
         expected_str = 'Invalid request sent'
-        self.assertTrue(expected_str in result.data)
+        self.assertTrue(expected_str in to_str(result.data))
 
     def test_hub_add_widget_post_invalid_widget_name(self):
         data = {'widget_name': 'invalid_widget_name'}
         result = self.app.post('/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 404)
         expected_str = 'Unknown widget called'
-        self.assertTrue(expected_str in result.data)
+        self.assertTrue(expected_str in to_str(result.data))
 
     def test_hub_add_widget_post_valid_widget_name_no_args(self):
         user = tests.FakeAuthorization('ralph')
@@ -245,9 +248,9 @@ class HubsAPITest(hubs.tests.APPTest):
                                    follow_redirects=False)
             self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
-            self.assertTrue(expected_str in result.data)
+            self.assertTrue(expected_str in to_str(result.data))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
-            self.assertTrue(expected_str in result.data)
+            self.assertTrue(expected_str in to_str(result.data))
 
     def test_hub_add_widget_post_valid_widget_name_with_args(self):
         user = tests.FakeAuthorization('ralph')
@@ -257,9 +260,9 @@ class HubsAPITest(hubs.tests.APPTest):
                                    follow_redirects=False)
             self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
-            self.assertTrue(expected_str in result.data)
+            self.assertTrue(expected_str in to_str(result.data))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
-            self.assertTrue(expected_str in result.data)
+            self.assertTrue(expected_str in to_str(result.data))
 
     def test_hub_edit_widget_get_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -267,7 +270,7 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get('/ralph/37/edit', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             expected_str = '/ralph/37/edit'
-            self.assertTrue(expected_str in result.data)
+            self.assertTrue(expected_str in to_str(result.data))
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_widget_get_logged_out(self):
@@ -314,21 +317,22 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             url = '/visit/decause'
             result = self.app.get(url)
-            self.assertEqual(result.data, '0')
+            self.assertEqual(to_str(result.data), '0')
 
             url = '/decause'
             result = self.app.get(url, follow_redirects=True)
 
             url = '/visit/decause'
             result = self.app.get(url)
-            self.assertEqual(result.data, '1')
+            self.assertEqual(to_str(result.data), '1')
 
     def test_hub_add_widget_valid_side(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             url = '/ralph/add/about?position=right'
             result = self.app.get(url)
-            self.assertTrue('Adding widget "about"to hub: ralph' in result.data)
+            self.assertTrue('Adding widget "about"to hub: ralph'
+                            in to_str(result.data))
 
     def test_hub_add_widget_invalid_side(self):
         user = tests.FakeAuthorization('ralph')
@@ -343,7 +347,7 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/ralph/37/delete'  # 37 is widget fedmsgstats for ralph
             result = self.app.post(url)
             self.assertEqual(result.status_code, 302)
-            self.assertTrue('/ralph/edit' in result.data)
+            self.assertTrue('/ralph/edit' in to_str(result.data))
 
     def test_source_name(self):
         with tests.auth_set(app, None):
@@ -352,7 +356,7 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 302)
             expected_str = 'https://pagure.io/fedora-hubs/' \
                            'blob/develop/f/hubs/widgets/about.py'
-            self.assertTrue(expected_str in result.data)
+            self.assertIn(expected_str, to_str(result.data))
 
     def test_source_name_not_existent(self):
         with tests.auth_set(app, None):
@@ -416,7 +420,7 @@ class HubsAPITest(hubs.tests.APPTest):
             "total": 0,
             "username": "decause"
         }
-        self.assertEqual(load_json(result.data), expected)
+        self.assertEqual(json.loads(to_str(result.data)), expected)
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_valid(self, mock_post):
@@ -432,7 +436,7 @@ class HubsAPITest(hubs.tests.APPTest):
                 "total": 1,
                 "username": "decause"
             }
-            self.assertEqual(load_json(result.data), expected)
+            self.assertEqual(json.loads(to_str(result.data)), expected)
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_myself_error(self, mock_post):
@@ -441,7 +445,7 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/plus_plus/ralph/update'
             result = self.app.post(url, data={'increment': True})
             self.assertEqual(result.status_code, 403)
-            self.assertEqual(result.data, 'You may not modify your own karma.')
+            self.assertEqual(to_str(result.data), 'You may not modify your own karma.')
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
@@ -450,7 +454,7 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/plus_plus/doesnotexist/update'
             result = self.app.post(url, data={'increment': True})
             self.assertEqual(result.status_code, 403)
-            self.assertEqual(result.data, 'User does not exist')
+            self.assertEqual(to_str(result.data), 'User does not exist')
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_no_data_error(self, mock_post):
@@ -461,13 +465,13 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 403)
             exp_str = "You must set 'decrement' or 'increment' " \
                       "with a boolean value in the body"
-            self.assertEqual(result.data, exp_str)
+            self.assertEqual(to_str(result.data), exp_str)
 
     def test_plus_plus_receiver_does_not_exist(self):
         url = '/plus_plus/doesnotexist/status'
         result = self.app.get(url)
         self.assertEqual(result.status_code, 403)
-        self.assertEqual(result.data, 'User does not exist')
+        self.assertEqual(to_str(result.data), 'User does not exist')
 
 
 
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index 93f4a31..3065cfb 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import hubs
 import hubs.models
 import hubs.tests
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 9b9ac69..47a2f4f 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 from datetime import datetime, timedelta
 from os.path import dirname
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index 2e358d0..f894e4b 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 from nose.tools import assert_dict_equal
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index b7831c0..2dd6458 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 from mock import patch, MagicMock
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index 5f16417..bec2363 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 import hubs.tests.test_widgets
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 58376c4..68f2598 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 import hubs.tests.test_widgets
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 5df4bd5..d3b3f09 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 import hubs.tests.test_widgets
@@ -21,5 +23,6 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
-        self.assertIn('i18n', response.data)
-        self.assertIn('<strong>Request A New Meeting</strong>', response.data)
+        self.assertIn('i18n', to_str(response.data))
+        self.assertIn('<strong>Request A New Meeting</strong>',
+                      to_str(response.data))
diff --git a/hubs/utils.py b/hubs/utils.py
index f5166bd..c858271 100755
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 import logging
 from hashlib import sha256
@@ -20,10 +22,7 @@ def markup(text):
 
 
 def username2avatar(username, s=312):
-    query = urlencode({
-        'd': 'retro',
-        's': s,
-    })
+    query = urlencode([('s', s), ('d', 'retro')])
     openid = 'http://%s.id.fedoraproject.org/' % username
     hash = sha256(openid.encode('utf-8')).hexdigest()
     avatar = "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)
diff --git a/hubs/validators.py b/hubs/validators.py
index 2ae918f..302b0e7 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import kitchen.text.converters
 
 import hubs.models
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 5f416ed..95253e7 100755
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.widgets import dummy
 from hubs.widgets import stats
 from hubs.widgets import rules
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index 4be594c..7f0d994 100755
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index abf4b15..86bc929 100755
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import operator
 
 import requests
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index f3cf198..581532e 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import collections
 import datetime
 import functools
diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
index a33e318..c2d94ae 100644
--- a/hubs/widgets/bugzilla.py
+++ b/hubs/widgets/bugzilla.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 import pkgwat.api
 
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 717e047..b869094 100755
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.widgets.base import wraps
 from hubs.widgets import templating
 
diff --git a/hubs/widgets/clean_input.py b/hubs/widgets/clean_input.py
index 2ec458a..9d25104 100644
--- a/hubs/widgets/clean_input.py
+++ b/hubs/widgets/clean_input.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from six.moves.urllib.parse import urlparse
 
 import bleach
diff --git a/hubs/widgets/contact.py b/hubs/widgets/contact.py
index b76873c..b14e126 100644
--- a/hubs/widgets/contact.py
+++ b/hubs/widgets/contact.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import flask
 
 import fedmsg.config
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index 2e73bca..bd198d3 100755
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 533c563..0cf5ba2 100755
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 8ea6536..5d744d9 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -1,4 +1,4 @@
-from __future__ import print_function
+from __future__ import print_function, unicode_literals
 
 from hubs.hinting import hint
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/fhosted.py b/hubs/widgets/fhosted.py
index 827b228..bc97d8b 100644
--- a/hubs/widgets/fhosted.py
+++ b/hubs/widgets/fhosted.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from six.moves.xmlrpc_client import ServerProxy
 
 import hubs.validators as validators
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index b2d1788..c2a0be9 100755
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import logging
 
 from hubs.widgets.chrome import panel
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
index 986ff11..7130183 100755
--- a/hubs/widgets/githubissues.py
+++ b/hubs/widgets/githubissues.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 
 from hubs.hinting import hint
diff --git a/hubs/widgets/library.py b/hubs/widgets/library.py
index b18354a..08ad334 100644
--- a/hubs/widgets/library.py
+++ b/hubs/widgets/library.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
@@ -21,9 +23,9 @@ def data(session, widget, urls):
 
     urls = [
         clean_input.clean(
-            '<a href="{0}">{0}</a>'.format(u.encode('utf-8').strip()))
+            '<a href="{0}">{0}</a>'.format(u.strip()))
         for u in widget.config.get('urls', '').split(',')
-        if u.encode('utf-8').strip()
+        if u.strip()
     ]
     return dict(urls=urls)
 
diff --git a/hubs/widgets/linechart.py b/hubs/widgets/linechart.py
index f12ef8f..3d41057 100755
--- a/hubs/widgets/linechart.py
+++ b/hubs/widgets/linechart.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint
 from hubs.widgets.base import argument
 from hubs.widgets import templating
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 8c05744..713177b 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
diff --git a/hubs/widgets/memberships.py b/hubs/widgets/memberships.py
index 48d8fea..2763db0 100644
--- a/hubs/widgets/memberships.py
+++ b/hubs/widgets/memberships.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import hubs.models
 from hubs.hinting import hint, prefixed as _
 import hubs.validators as validators
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index cdb8365..081dcb4 100755
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index c9ecd53..9a4dca8 100755
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 
 from hubs.hinting import hint
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 443f07c..d7554b9 100755
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from collections import OrderedDict as ordereddict
 
 from hubs.hinting import hint, prefixed as _
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 55c90db..ebd6cc8 100755
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 55cc6a1..ca74f59 100755
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 82fce66..8035d3d 100755
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
diff --git a/hubs/widgets/templating.py b/hubs/widgets/templating.py
index 98b29cd..41e0c5b 100644
--- a/hubs/widgets/templating.py
+++ b/hubs/widgets/templating.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import os
 
 import jinja2
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 581bd70..5bc6594 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 
 from hubs.hinting import hint, prefixed as _
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 675d793..c7df1c3 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 
 from hubs.hinting import hint, prefixed as _
diff --git a/populate-from-fas.py b/populate-from-fas.py
index 7639c81..b74e8a6 100755
--- a/populate-from-fas.py
+++ b/populate-from-fas.py
@@ -1,6 +1,8 @@
 #!/usr/bin/env python
 """ Populate the hubs db with lots of data from FAS. """
 
+from __future__ import unicode_literals
+
 import getpass
 import socket
 import string
diff --git a/populate.py b/populate.py
index 5c34700..4286940 100755
--- a/populate.py
+++ b/populate.py
@@ -1,6 +1,8 @@
 #!/usr/bin/env python
 """ Populate the hubs db with some dev data. """
 
+from __future__ import unicode_literals
+
 import json
 
 import hubs.models
diff --git a/runserver.py b/runserver.py
index 5e5a4f2..9552b0a 100755
--- a/runserver.py
+++ b/runserver.py
@@ -1,5 +1,7 @@
 #!/usr/bin/env python2
 
+from __future__ import unicode_literals
+
 import argparse
 import sys
 import os
diff --git a/setup.py b/setup.py
index 15f69c2..aa9b63e 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,7 @@
 """ Setup file for fedora hubs """
 
+from __future__ import unicode_literals
+
 from setuptools import setup, find_packages
 
 
diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index 77021fc..25c2540 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -8,7 +8,7 @@ This is really useful for development purposes as it allow seeing changes
 made to a widget without dropping the entire cache database.
 """
 
-from __future__ import print_function
+from __future__ import print_function, unicode_literals
 
 import argparse
 import os

From f5b1ffb9bd17065eafaba879c9c2463d16d6d2d7 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 28 2017 09:57:21 +0000
Subject: [PATCH 679/1001] Don't use the cache when running tests


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index e7f4eba..2fd805c 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -34,6 +34,9 @@ class APPTest(unittest.TestCase):
         self.app = hubs.app.app.test_client()
         self.app.testing = True
         self.session = hubs.app.session
+        from hubs.widgets.base import cache
+        cache.configure(backend='dogpile.cache.null',
+                        replace_existing_backend=True)
         self.populate()
 
     def tearDown(self):

From 56cff3a43d52bf58a4dbb7fa376949e95fc1df5a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 31 2017 17:14:37 +0000
Subject: [PATCH 680/1001] Use request.get_json() and .get_data() where approriate


---

diff --git a/hubs/app.py b/hubs/app.py
index ca3bd26..89b5271 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -21,7 +21,7 @@ import hubs.stream
 
 import datanommer.models
 
-from hubs.utils import username2avatar, to_str
+from hubs.utils import username2avatar
 
 app = flask.Flask(__name__)
 
@@ -547,7 +547,7 @@ def notifications(user):
         return flask.jsonify(notifications)
 
     if flask.request.method == 'POST':
-        data = json.loads(to_str(flask.request.data))
+        data = flask.request.get_json()
         user = hubs.models.User.by_username(session, user)
         if not user:
             return flask.abort(400)
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index 360fa4c..5b8ad9e 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -6,7 +6,6 @@ from six.moves.urllib.parse import urlparse
 import hubs.tests
 import hubs.models
 from hubs.app import app
-from hubs.utils import to_str
 
 
 class TestGetNotifications(hubs.tests.APPTest):
@@ -18,7 +17,7 @@ class TestGetNotifications(hubs.tests.APPTest):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.get('/{}/notifications/'.format(name))
         self.assertEqual(resp.status_code, 200)
-        data = json.loads(to_str(resp.data))
+        data = json.loads(resp.get_data(as_text=True))
         self.assertEqual(data, [])
 
     def test_get_notifications_valid_name(self):
@@ -27,7 +26,7 @@ class TestGetNotifications(hubs.tests.APPTest):
                 self.user.username))
 
         self.assertEqual(resp.status_code, 200)
-        data = json.loads(to_str(resp.data))
+        data = json.loads(resp.get_data(as_text=True))
         self.assertEqual(len(data), 1)
 
         for saved in data:
@@ -53,24 +52,27 @@ class TestPostNotifications(hubs.tests.APPTest):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post(
                 '/{}/notifications/'.format('notarealfasuser'),
-                data=json.dumps(self.valid_payload))
+                data=json.dumps(self.valid_payload),
+                content_type='application/json')
         self.assertEqual(resp.status_code, 400)
 
     def test_post_notification_invalid_payload(self):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post(
                 '/{}/notifications/'.format(self.user.username),
-                data=json.dumps(self.invalid_payload))
+                data=json.dumps(self.invalid_payload),
+                content_type='application/json')
         self.assertEqual(resp.status_code, 400)
 
     def test_post_notification_valid_payload(self):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post(
                 '/{}/notifications/'.format(self.user.username),
-                data=json.dumps(self.valid_payload))
+                data=json.dumps(self.valid_payload),
+                content_type='application/json')
 
         self.assertEqual(resp.status_code, 200)
-        data = json.loads(to_str(resp.data))
+        data = json.loads(resp.get_data(as_text=True))
         self.assertTrue(isinstance(data, dict))
 
         notification = data['notification']
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index edfc6a6..3c24905 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -13,7 +13,6 @@ from werkzeug.datastructures import ImmutableMultiDict
 import hubs
 from hubs import tests
 from hubs.app import app
-from hubs.utils import to_str
 
 import hubs.models
 
@@ -35,17 +34,19 @@ class HubsAPITest(hubs.tests.APPTest):
             # its trying to redirect to login id.fedoraproject.org/openid
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
-            self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login">login</a>' in to_str(result.data))
+            self.assertNotIn(
+                'Not logged in.  Click to <a href="/login">login</a>',
+                result.get_data(as_text=True))
 
     def test_hub_logged_out(self):
         with tests.auth_set(app, None):  # check_auth doesn't load in unittest
             result = self.app.get('/ralph', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             match_expected = r'<h5[^>]*>Ralph</h5>'
-            self.assertRegexpMatches(to_str(result.data), match_expected)
+            self.assertRegexpMatches(
+                result.get_data(as_text=True), match_expected)
             str_expected = 'Not logged in.'
-            self.assertTrue(str_expected in to_str(result.data))
+            self.assertIn(str_expected, result.get_data(as_text=True))
 
     def test_groups_logged_out(self):
         result = self.app.get('/groups', follow_redirects=False)
@@ -60,16 +61,17 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get('/groups', follow_redirects=True)
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
-            self.assertTrue("ZOMG -  is the Hub Of The Month!"
-                            in to_str(result.data))
+            self.assertIn("ZOMG -  is the Hub Of The Month!",
+                          result.get_data(as_text=True))
 
     def test_hub_logged_in(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             result = self.app.get('/ralph', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login">login</a>' in to_str(result.data))
+            self.assertNotIn(
+                'Not logged in.  Click to <a href="/login">login</a>',
+                result.get_data(as_text=True))
 
     def test_hub_json(self):
         result = self.app.get('/ralph/json', follow_redirects=True)
@@ -87,7 +89,7 @@ class HubsAPITest(hubs.tests.APPTest):
             "summary": "Ralph",
             "widgets": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56]
         }
-        self.assertDictEqual(data, json.loads(to_str(result.data)))
+        self.assertDictEqual(data, json.loads(result.get_data(as_text=True)))
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_get_logged_out(self):
@@ -136,10 +138,12 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.post('/ralph/edit', data={},
                                    follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login">login</a>' in to_str(result.data))
-            self.assertTrue('<a href="#" class="dropdown-item">Full Name: '
-                            'fullname: ralph</a>' in to_str(result.data))
+            self.assertNotIn(
+                'Not logged in.  Click to <a href="/login">login</a>',
+                result.get_data(as_text=True))
+            self.assertIn(
+                '<a href="#" class="dropdown-item">Full Name: '
+                'fullname: ralph</a>', result.get_data(as_text=True))
 
     def test_hub_edit_post_logged_in_owner_valid_data(self):
         user = tests.FakeAuthorization('ralph')
@@ -160,7 +164,7 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.post('/ralph/edit', data=data,
                                    follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            self.assertEqual(to_str(result.data), 'ok')
+            self.assertEqual(result.get_data(as_text=True), 'ok')
 
     def test_hub_edit_post_logged_in_owner_invalid_data_1(self):
         user = tests.FakeAuthorization('ralph')
@@ -215,30 +219,30 @@ class HubsAPITest(hubs.tests.APPTest):
         result = self.app.get('/ralph/add', follow_redirects=False)
         self.assertEqual(result.status_code, 400)
         expected_str = 'Invalid position provided'
-        self.assertTrue(expected_str in to_str(result.data))
+        self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_get_with_args(self):
         result = self.app.get('/ralph/add?position=right',
                               follow_redirects=True)
         self.assertEqual(result.status_code, 200)
         expected_str = 'Adding widget to hub: ralph'
-        self.assertTrue(expected_str in to_str(result.data))
+        self.assertIn(expected_str, result.get_data(as_text=True))
         expected_str = "url: 'add/' + $('#widget').val() + '?position=right',"
-        self.assertTrue(expected_str in to_str(result.data))
+        self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_no_widget_name(self):
         data = {}
         result = self.app.post('/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 400)
         expected_str = 'Invalid request sent'
-        self.assertTrue(expected_str in to_str(result.data))
+        self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_invalid_widget_name(self):
         data = {'widget_name': 'invalid_widget_name'}
         result = self.app.post('/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 404)
         expected_str = 'Unknown widget called'
-        self.assertTrue(expected_str in to_str(result.data))
+        self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_valid_widget_name_no_args(self):
         user = tests.FakeAuthorization('ralph')
@@ -248,9 +252,9 @@ class HubsAPITest(hubs.tests.APPTest):
                                    follow_redirects=False)
             self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
-            self.assertTrue(expected_str in to_str(result.data))
+            self.assertIn(expected_str, result.get_data(as_text=True))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
-            self.assertTrue(expected_str in to_str(result.data))
+            self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_valid_widget_name_with_args(self):
         user = tests.FakeAuthorization('ralph')
@@ -260,9 +264,9 @@ class HubsAPITest(hubs.tests.APPTest):
                                    follow_redirects=False)
             self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
-            self.assertTrue(expected_str in to_str(result.data))
+            self.assertIn(expected_str, result.get_data(as_text=True))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
-            self.assertTrue(expected_str in to_str(result.data))
+            self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_edit_widget_get_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -270,7 +274,7 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get('/ralph/37/edit', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             expected_str = '/ralph/37/edit'
-            self.assertTrue(expected_str in to_str(result.data))
+            self.assertIn(expected_str, result.get_data(as_text=True))
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_widget_get_logged_out(self):
@@ -291,10 +295,14 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             url = '/visit/decause'
             result = self.app.get(url)
-            self.assertEqual(json.loads(to_str(result.data)), {"count": 0})
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"count": 0})
 
             result = self.app.post(url)
-            self.assertEqual(json.loads(to_str(result.data)), {"count": 1})
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"count": 1})
 
             # accessing my hub shouldn't increment the count
             url = 'visit/ralph'
@@ -317,22 +325,22 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             url = '/visit/decause'
             result = self.app.get(url)
-            self.assertEqual(to_str(result.data), '0')
+            self.assertEqual(result.get_data(as_text=True), '0')
 
             url = '/decause'
             result = self.app.get(url, follow_redirects=True)
 
             url = '/visit/decause'
             result = self.app.get(url)
-            self.assertEqual(to_str(result.data), '1')
+            self.assertEqual(result.get_data(as_text=True), '1')
 
     def test_hub_add_widget_valid_side(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             url = '/ralph/add/about?position=right'
             result = self.app.get(url)
-            self.assertTrue('Adding widget "about"to hub: ralph'
-                            in to_str(result.data))
+            self.assertIn('Adding widget "about"to hub: ralph',
+                          result.get_data(as_text=True))
 
     def test_hub_add_widget_invalid_side(self):
         user = tests.FakeAuthorization('ralph')
@@ -347,7 +355,7 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/ralph/37/delete'  # 37 is widget fedmsgstats for ralph
             result = self.app.post(url)
             self.assertEqual(result.status_code, 302)
-            self.assertTrue('/ralph/edit' in to_str(result.data))
+            self.assertIn('/ralph/edit', result.get_data(as_text=True))
 
     def test_source_name(self):
         with tests.auth_set(app, None):
@@ -356,7 +364,7 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 302)
             expected_str = 'https://pagure.io/fedora-hubs/' \
                            'blob/develop/f/hubs/widgets/about.py'
-            self.assertIn(expected_str, to_str(result.data))
+            self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_source_name_not_existent(self):
         with tests.auth_set(app, None):
@@ -420,7 +428,9 @@ class HubsAPITest(hubs.tests.APPTest):
             "total": 0,
             "username": "decause"
         }
-        self.assertEqual(json.loads(to_str(result.data)), expected)
+        self.assertEqual(
+            json.loads(result.get_data(as_text=True)),
+            expected)
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_valid(self, mock_post):
@@ -436,7 +446,9 @@ class HubsAPITest(hubs.tests.APPTest):
                 "total": 1,
                 "username": "decause"
             }
-            self.assertEqual(json.loads(to_str(result.data)), expected)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                expected)
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_myself_error(self, mock_post):
@@ -445,7 +457,9 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/plus_plus/ralph/update'
             result = self.app.post(url, data={'increment': True})
             self.assertEqual(result.status_code, 403)
-            self.assertEqual(to_str(result.data), 'You may not modify your own karma.')
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'You may not modify your own karma.')
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
@@ -454,7 +468,9 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/plus_plus/doesnotexist/update'
             result = self.app.post(url, data={'increment': True})
             self.assertEqual(result.status_code, 403)
-            self.assertEqual(to_str(result.data), 'User does not exist')
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'User does not exist')
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_no_data_error(self, mock_post):
@@ -465,13 +481,13 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 403)
             exp_str = "You must set 'decrement' or 'increment' " \
                       "with a boolean value in the body"
-            self.assertEqual(to_str(result.data), exp_str)
+            self.assertEqual(result.get_data(as_text=True), exp_str)
 
     def test_plus_plus_receiver_does_not_exist(self):
         url = '/plus_plus/doesnotexist/status'
         result = self.app.get(url)
         self.assertEqual(result.status_code, 403)
-        self.assertEqual(to_str(result.data), 'User does not exist')
+        self.assertEqual(result.get_data(as_text=True), 'User does not exist')
 
 
 
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index f894e4b..74e0c56 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -5,7 +5,6 @@ import json
 from nose.tools import assert_dict_equal
 
 import hubs.tests.test_widgets
-from hubs.utils import to_str
 
 
 class TestBadges(hubs.tests.test_widgets.WidgetTest):
@@ -15,7 +14,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
-        data = json.loads(to_str(response.data))
+        data = json.loads(response.get_data(as_text=True))
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
             u'edit_url': u'/ralph/56/edit',
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index 2dd6458..8a88807 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -4,7 +4,6 @@ import json
 
 from mock import patch, MagicMock
 import hubs.tests.test_widgets
-from hubs.utils import to_str
 
 
 class TestBadges(hubs.tests.test_widgets.WidgetTest):
@@ -14,7 +13,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
-        data = json.loads(to_str(response.data))
+        data = json.loads(response.get_data(as_text=True))
         self.assertEquals(data['plugin'], 'badges')
         self.assertIn('assertions', data['data'].keys())
 
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index bec2363..0d7e79d 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
 import json
 
 import hubs.tests.test_widgets
-from hubs.utils import to_str
 
 
 class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
@@ -13,7 +12,7 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
-        data = json.loads(to_str(response.data))
+        data = json.loads(response.get_data(as_text=True))
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
             u'edit_url': u'/ralph/37/edit',
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 68f2598..9182b56 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -4,7 +4,6 @@ import json
 
 import hubs.tests.test_widgets
 import hubs.models
-from hubs.utils import to_str
 
 class TestLibrary(hubs.tests.test_widgets.WidgetTest):
     plugin = 'library'  # The name in hubs.widgets.registry
@@ -13,7 +12,7 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         self.assertEqual(response.status_code, 200)
-        data = json.loads(to_str(response.data))
+        data = json.loads(response.get_data(as_text=True))
         expected_dict = {
             "config": {
                 "urls": "ralph/"
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index d3b3f09..08ea046 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
 import json
 
 import hubs.tests.test_widgets
-from hubs.utils import to_str
 
 
 class TestMeetings(hubs.tests.test_widgets.WidgetTest):
@@ -14,7 +13,7 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/json/' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
-        data = json.loads(to_str(response.data))
+        data = json.loads(response.get_data(as_text=True))
         calendar_name = data['data']['calendar']
         self.assertIn(team, calendar_name)
 
@@ -23,6 +22,6 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
-        self.assertIn('i18n', to_str(response.data))
+        self.assertIn('i18n', response.get_data(as_text=True))
         self.assertIn('<strong>Request A New Meeting</strong>',
-                      to_str(response.data))
+                      response.get_data(as_text=True))
diff --git a/hubs/utils.py b/hubs/utils.py
index c858271..f1ecd92 100755
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -81,14 +81,3 @@ def _github_results(url, auth):
                     part.split('; ')[0][1:-1],
                 ) for part in field.split(', ')
             ])
-
-
-def to_str(data):
-    """
-    A Python3-compatible way to return a string from a string or a UTF8-encoded
-    bytestring. Werkzeug responses are bytestrings on Python 3.
-    """
-    if isinstance(data, six.binary_type):
-        return data.decode('utf-8')
-    else:
-        return data

From e577121892886b2ec262e857164beb61d2a43798 Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Jan 31 2017 18:15:38 +0000
Subject: [PATCH 681/1001] Merge #306 `Python 3 compatibility for strings`


---

diff --git a/check-cache-coverage.py b/check-cache-coverage.py
index 0f6c6f7..a753f56 100755
--- a/check-cache-coverage.py
+++ b/check-cache-coverage.py
@@ -13,6 +13,8 @@ forcibly re-warms the cache.
 Authors:    Ralph Bean <rbean@redhat.com>
 """
 
+from __future__ import unicode_literals
+
 import sys
 import dogpile.cache
 
diff --git a/check-queue-length.py b/check-queue-length.py
index 4fc7098..5b14d0f 100755
--- a/check-queue-length.py
+++ b/check-queue-length.py
@@ -13,6 +13,8 @@ We could also graph this in collectd, for fun and profit.
 Authors:    Ralph Bean <rbean@redhat.com>
 """
 
+from __future__ import unicode_literals
+
 import fedmsg.config
 config = fedmsg.config.load_config()
 
diff --git a/delete-user.py b/delete-user.py
index acc2563..42a17c1 100755
--- a/delete-user.py
+++ b/delete-user.py
@@ -4,6 +4,8 @@
 Useful for testing what happens when you recreate them.
 """
 
+from __future__ import unicode_literals
+
 import sys
 
 import fedmsg.config
diff --git a/hubs/app.py b/hubs/app.py
index f352afd..89b5271 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,10 +1,11 @@
-from __future__ import print_function
+from __future__ import print_function, unicode_literals
 
 import datetime
 import functools
 import json
 import logging
 import os
+import six
 from six.moves.urllib import parse as urlparse
 
 import flask
@@ -454,7 +455,7 @@ def widget_source(name):
     fname = ''
 
     try:
-        fname = base + registry[name].__file__.split(base, 1)[1]
+        fname = base + registry[name].__file__.split(base)[-1]
     except KeyError:
         flask.abort(404)
 
@@ -546,7 +547,7 @@ def notifications(user):
         return flask.jsonify(notifications)
 
     if flask.request.method == 'POST':
-        data = json.loads(flask.request.data)
+        data = flask.request.get_json()
         user = hubs.models.User.by_username(session, user)
         if not user:
             return flask.abort(400)
@@ -756,7 +757,7 @@ def plus_plus_status(user):
 def plus_plus_update_bool_helper(val):
     if isinstance(val, bool):
         return val
-    elif isinstance(val, (str, unicode)):
+    elif isinstance(val, six.string_types):
         fmt_str = str(val).replace("'", "").replace('"', '').lower()
         return fmt_str in ("yes", "true", "t", "1")
     else:
diff --git a/hubs/backend/consumer.py b/hubs/backend/consumer.py
index 9d73ef1..7ea5083 100755
--- a/hubs/backend/consumer.py
+++ b/hubs/backend/consumer.py
@@ -1,5 +1,7 @@
 # The fedora hubs backend daemon
 
+from __future__ import unicode_literals
+
 import fedmsg.consumers
 import fedmsg.meta
 
diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index ad86221..c1bf1da 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -19,6 +19,8 @@ though.  If they see that invalidation is required, they put a new task on an
 handle.
 """
 
+from __future__ import unicode_literals
+
 import hubs.app
 import hubs.models
 
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index 11c3342..abc1b32 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -24,6 +24,8 @@ another redis queue so that an EventSource server can update any connected web
 clients with the new content produced here.
 """
 
+from __future__ import unicode_literals
+
 import hubs.app
 import hubs.models
 
diff --git a/hubs/default_config.py b/hubs/default_config.py
index bb9ef80..769f8ad 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import os
 
 SECRET_KEY = 'changemeforreal'
diff --git a/hubs/defaults.py b/hubs/defaults.py
index 2a27612..d91d452 100755
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 import hubs.models
diff --git a/hubs/hinting.py b/hubs/hinting.py
index 14ed445..b1a8c2f 100755
--- a/hubs/hinting.py
+++ b/hubs/hinting.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import decorator
 
 import fedmsg.config
diff --git a/hubs/models.py b/hubs/models.py
index add289e..cdc02de 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -20,6 +20,7 @@
 # of Red Hat, Inc.
 #
 
+from __future__ import unicode_literals
 
 import datetime
 import json
diff --git a/hubs/stream.py b/hubs/stream.py
index fd45923..ced01b9 100644
--- a/hubs/stream.py
+++ b/hubs/stream.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 import os
 
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 2fd805c..7f8aa8c 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from contextlib import contextmanager
 import json
 from datetime import datetime, timedelta
diff --git a/hubs/tests/test_api/test_hub.py b/hubs/tests/test_api/test_hub.py
index 815411d..821746c 100644
--- a/hubs/tests/test_api/test_hub.py
+++ b/hubs/tests/test_api/test_hub.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import flask
 import unittest
 from six.moves.urllib.parse import urlparse
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index 8440baf..5b8ad9e 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 from six.moves.urllib.parse import urlparse
 
@@ -15,7 +17,7 @@ class TestGetNotifications(hubs.tests.APPTest):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.get('/{}/notifications/'.format(name))
         self.assertEqual(resp.status_code, 200)
-        data = json.loads(resp.data)
+        data = json.loads(resp.get_data(as_text=True))
         self.assertEqual(data, [])
 
     def test_get_notifications_valid_name(self):
@@ -24,7 +26,7 @@ class TestGetNotifications(hubs.tests.APPTest):
                 self.user.username))
 
         self.assertEqual(resp.status_code, 200)
-        data = json.loads(resp.data)
+        data = json.loads(resp.get_data(as_text=True))
         self.assertEqual(len(data), 1)
 
         for saved in data:
@@ -50,24 +52,27 @@ class TestPostNotifications(hubs.tests.APPTest):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post(
                 '/{}/notifications/'.format('notarealfasuser'),
-                data=json.dumps(self.valid_payload))
+                data=json.dumps(self.valid_payload),
+                content_type='application/json')
         self.assertEqual(resp.status_code, 400)
 
     def test_post_notification_invalid_payload(self):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post(
                 '/{}/notifications/'.format(self.user.username),
-                data=json.dumps(self.invalid_payload))
+                data=json.dumps(self.invalid_payload),
+                content_type='application/json')
         self.assertEqual(resp.status_code, 400)
 
     def test_post_notification_valid_payload(self):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post(
                 '/{}/notifications/'.format(self.user.username),
-                data=json.dumps(self.valid_payload))
+                data=json.dumps(self.valid_payload),
+                content_type='application/json')
 
         self.assertEqual(resp.status_code, 200)
-        data = json.loads(resp.data)
+        data = json.loads(resp.get_data(as_text=True))
         self.assertTrue(isinstance(data, dict))
 
         notification = data['notification']
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index ea4b6b9..3c24905 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import unittest
 from six.moves.urllib.parse import urlparse
 import ast # import for string to dict conversion without unicode
@@ -32,17 +34,19 @@ class HubsAPITest(hubs.tests.APPTest):
             # its trying to redirect to login id.fedoraproject.org/openid
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
-            self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login">login</a>' in result.data)
+            self.assertNotIn(
+                'Not logged in.  Click to <a href="/login">login</a>',
+                result.get_data(as_text=True))
 
     def test_hub_logged_out(self):
         with tests.auth_set(app, None):  # check_auth doesn't load in unittest
             result = self.app.get('/ralph', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             match_expected = r'<h5[^>]*>Ralph</h5>'
-            self.assertRegexpMatches(result.data, match_expected)
+            self.assertRegexpMatches(
+                result.get_data(as_text=True), match_expected)
             str_expected = 'Not logged in.'
-            self.assertTrue(str_expected in result.data)
+            self.assertIn(str_expected, result.get_data(as_text=True))
 
     def test_groups_logged_out(self):
         result = self.app.get('/groups', follow_redirects=False)
@@ -57,15 +61,17 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get('/groups', follow_redirects=True)
             # assert the status code of the response
             self.assertEqual(result.status_code, 200)
-            self.assertTrue("ZOMG -  is the Hub Of The Month!" in result.data)
+            self.assertIn("ZOMG -  is the Hub Of The Month!",
+                          result.get_data(as_text=True))
 
     def test_hub_logged_in(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             result = self.app.get('/ralph', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login">login</a>' in result.data)
+            self.assertNotIn(
+                'Not logged in.  Click to <a href="/login">login</a>',
+                result.get_data(as_text=True))
 
     def test_hub_json(self):
         result = self.app.get('/ralph/json', follow_redirects=True)
@@ -83,7 +89,7 @@ class HubsAPITest(hubs.tests.APPTest):
             "summary": "Ralph",
             "widgets": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56]
         }
-        self.assertDictEqual(data, ast.literal_eval(result.data))
+        self.assertDictEqual(data, json.loads(result.get_data(as_text=True)))
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_get_logged_out(self):
@@ -132,10 +138,12 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.post('/ralph/edit', data={},
                                    follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            self.assertFalse('Not logged in.  Click to <a href="'
-                             '/login">login</a>' in result.data)
-            self.assertTrue('<a href="#" class="dropdown-item">Full Name: '
-                            'fullname: ralph</a>' in result.data)
+            self.assertNotIn(
+                'Not logged in.  Click to <a href="/login">login</a>',
+                result.get_data(as_text=True))
+            self.assertIn(
+                '<a href="#" class="dropdown-item">Full Name: '
+                'fullname: ralph</a>', result.get_data(as_text=True))
 
     def test_hub_edit_post_logged_in_owner_valid_data(self):
         user = tests.FakeAuthorization('ralph')
@@ -156,7 +164,7 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.post('/ralph/edit', data=data,
                                    follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            self.assertEqual(result.data, 'ok')
+            self.assertEqual(result.get_data(as_text=True), 'ok')
 
     def test_hub_edit_post_logged_in_owner_invalid_data_1(self):
         user = tests.FakeAuthorization('ralph')
@@ -211,30 +219,30 @@ class HubsAPITest(hubs.tests.APPTest):
         result = self.app.get('/ralph/add', follow_redirects=False)
         self.assertEqual(result.status_code, 400)
         expected_str = 'Invalid position provided'
-        self.assertTrue(expected_str in result.data)
+        self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_get_with_args(self):
         result = self.app.get('/ralph/add?position=right',
                               follow_redirects=True)
         self.assertEqual(result.status_code, 200)
         expected_str = 'Adding widget to hub: ralph'
-        self.assertTrue(expected_str in result.data)
+        self.assertIn(expected_str, result.get_data(as_text=True))
         expected_str = "url: 'add/' + $('#widget').val() + '?position=right',"
-        self.assertTrue(expected_str in result.data)
+        self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_no_widget_name(self):
         data = {}
         result = self.app.post('/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 400)
         expected_str = 'Invalid request sent'
-        self.assertTrue(expected_str in result.data)
+        self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_invalid_widget_name(self):
         data = {'widget_name': 'invalid_widget_name'}
         result = self.app.post('/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 404)
         expected_str = 'Unknown widget called'
-        self.assertTrue(expected_str in result.data)
+        self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_valid_widget_name_no_args(self):
         user = tests.FakeAuthorization('ralph')
@@ -244,9 +252,9 @@ class HubsAPITest(hubs.tests.APPTest):
                                    follow_redirects=False)
             self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
-            self.assertTrue(expected_str in result.data)
+            self.assertIn(expected_str, result.get_data(as_text=True))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
-            self.assertTrue(expected_str in result.data)
+            self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_valid_widget_name_with_args(self):
         user = tests.FakeAuthorization('ralph')
@@ -256,9 +264,9 @@ class HubsAPITest(hubs.tests.APPTest):
                                    follow_redirects=False)
             self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
-            self.assertTrue(expected_str in result.data)
+            self.assertIn(expected_str, result.get_data(as_text=True))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
-            self.assertTrue(expected_str in result.data)
+            self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_edit_widget_get_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -266,7 +274,7 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get('/ralph/37/edit', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
             expected_str = '/ralph/37/edit'
-            self.assertTrue(expected_str in result.data)
+            self.assertIn(expected_str, result.get_data(as_text=True))
 
     @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_widget_get_logged_out(self):
@@ -287,10 +295,14 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             url = '/visit/decause'
             result = self.app.get(url)
-            self.assertEqual(json.loads(result.data), {"count": 0})
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"count": 0})
 
             result = self.app.post(url)
-            self.assertEqual(json.loads(result.data), {"count": 1})
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"count": 1})
 
             # accessing my hub shouldn't increment the count
             url = 'visit/ralph'
@@ -313,21 +325,22 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             url = '/visit/decause'
             result = self.app.get(url)
-            self.assertEqual(result.data, '0')
+            self.assertEqual(result.get_data(as_text=True), '0')
 
             url = '/decause'
             result = self.app.get(url, follow_redirects=True)
 
             url = '/visit/decause'
             result = self.app.get(url)
-            self.assertEqual(result.data, '1')
+            self.assertEqual(result.get_data(as_text=True), '1')
 
     def test_hub_add_widget_valid_side(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             url = '/ralph/add/about?position=right'
             result = self.app.get(url)
-            self.assertTrue('Adding widget "about"to hub: ralph' in result.data)
+            self.assertIn('Adding widget "about"to hub: ralph',
+                          result.get_data(as_text=True))
 
     def test_hub_add_widget_invalid_side(self):
         user = tests.FakeAuthorization('ralph')
@@ -342,7 +355,7 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/ralph/37/delete'  # 37 is widget fedmsgstats for ralph
             result = self.app.post(url)
             self.assertEqual(result.status_code, 302)
-            self.assertTrue('/ralph/edit' in result.data)
+            self.assertIn('/ralph/edit', result.get_data(as_text=True))
 
     def test_source_name(self):
         with tests.auth_set(app, None):
@@ -351,7 +364,7 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 302)
             expected_str = 'https://pagure.io/fedora-hubs/' \
                            'blob/develop/f/hubs/widgets/about.py'
-            self.assertTrue(expected_str in result.data)
+            self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_source_name_not_existent(self):
         with tests.auth_set(app, None):
@@ -415,7 +428,9 @@ class HubsAPITest(hubs.tests.APPTest):
             "total": 0,
             "username": "decause"
         }
-        self.assertEqual(json.loads(result.data), expected)
+        self.assertEqual(
+            json.loads(result.get_data(as_text=True)),
+            expected)
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_valid(self, mock_post):
@@ -431,7 +446,9 @@ class HubsAPITest(hubs.tests.APPTest):
                 "total": 1,
                 "username": "decause"
             }
-            self.assertEqual(json.loads(result.data), expected)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                expected)
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_myself_error(self, mock_post):
@@ -440,7 +457,9 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/plus_plus/ralph/update'
             result = self.app.post(url, data={'increment': True})
             self.assertEqual(result.status_code, 403)
-            self.assertEqual(result.data, 'You may not modify your own karma.')
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'You may not modify your own karma.')
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
@@ -449,7 +468,9 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/plus_plus/doesnotexist/update'
             result = self.app.post(url, data={'increment': True})
             self.assertEqual(result.status_code, 403)
-            self.assertEqual(result.data, 'User does not exist')
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'User does not exist')
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_no_data_error(self, mock_post):
@@ -460,13 +481,13 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 403)
             exp_str = "You must set 'decrement' or 'increment' " \
                       "with a boolean value in the body"
-            self.assertEqual(result.data, exp_str)
+            self.assertEqual(result.get_data(as_text=True), exp_str)
 
     def test_plus_plus_receiver_does_not_exist(self):
         url = '/plus_plus/doesnotexist/status'
         result = self.app.get(url)
         self.assertEqual(result.status_code, 403)
-        self.assertEqual(result.data, 'User does not exist')
+        self.assertEqual(result.get_data(as_text=True), 'User does not exist')
 
 
 
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index 93f4a31..3065cfb 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import hubs
 import hubs.models
 import hubs.tests
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 9b9ac69..47a2f4f 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 from datetime import datetime, timedelta
 from os.path import dirname
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index f67e476..74e0c56 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 from nose.tools import assert_dict_equal
@@ -12,7 +14,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
+        data = json.loads(response.get_data(as_text=True))
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
             u'edit_url': u'/ralph/56/edit',
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index b3b5197..8a88807 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 from mock import patch, MagicMock
@@ -11,7 +13,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
+        data = json.loads(response.get_data(as_text=True))
         self.assertEquals(data['plugin'], 'badges')
         self.assertIn('assertions', data['data'].keys())
 
@@ -45,4 +47,4 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx + 1}}}
         module = hubs.widgets.registry[widget.plugin]
         result = module.should_invalidate(msg, self.session, widget)
-        self.assertTrue(result)
\ No newline at end of file
+        self.assertTrue(result)
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index c88b7a4..0d7e79d 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 import hubs.tests.test_widgets
@@ -10,7 +12,7 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
-        data = json.loads(response.data)
+        data = json.loads(response.get_data(as_text=True))
         del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
             u'edit_url': u'/ralph/37/edit',
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index bd01019..9182b56 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 import hubs.tests.test_widgets
@@ -10,7 +12,7 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance('ralph', self.plugin)
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         self.assertEqual(response.status_code, 200)
-        data = json.loads(response.data)
+        data = json.loads(response.get_data(as_text=True))
         expected_dict = {
             "config": {
                 "urls": "ralph/"
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 7184796..08ea046 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import json
 
 import hubs.tests.test_widgets
@@ -11,7 +13,7 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/json/' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
-        data = json.loads(response.data)
+        data = json.loads(response.get_data(as_text=True))
         calendar_name = data['data']['calendar']
         self.assertIn(team, calendar_name)
 
@@ -20,5 +22,6 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
         widget = self.widget_instance(team, self.plugin)
         response = self.app.get('/%s/%i/' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
-        self.assertIn('i18n', response.data)
-        self.assertIn('<strong>Request A New Meeting</strong>', response.data)
\ No newline at end of file
+        self.assertIn('i18n', response.get_data(as_text=True))
+        self.assertIn('<strong>Request A New Meeting</strong>',
+                      response.get_data(as_text=True))
diff --git a/hubs/utils.py b/hubs/utils.py
index ed00d80..f1ecd92 100755
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -1,9 +1,13 @@
+from __future__ import unicode_literals
+
+import json
 import logging
 from hashlib import sha256
 
 import arrow
 import markdown
 import requests
+import six
 
 from six.moves.urllib_parse import urlencode
 
@@ -18,10 +22,7 @@ def markup(text):
 
 
 def username2avatar(username, s=312):
-    query = urlencode({
-        'd': 'retro',
-        's': s,
-    })
+    query = urlencode([('s', s), ('d', 'retro')])
     openid = 'http://%s.id.fedoraproject.org/' % username
     hash = sha256(openid.encode('utf-8')).hexdigest()
     avatar = "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)
diff --git a/hubs/validators.py b/hubs/validators.py
index 2ae918f..302b0e7 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import kitchen.text.converters
 
 import hubs.models
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 5f416ed..95253e7 100755
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.widgets import dummy
 from hubs.widgets import stats
 from hubs.widgets import rules
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
index 4be594c..7f0d994 100755
--- a/hubs/widgets/about.py
+++ b/hubs/widgets/about.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
index abf4b15..86bc929 100755
--- a/hubs/widgets/badges.py
+++ b/hubs/widgets/badges.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import operator
 
 import requests
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index f3cf198..581532e 100755
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import collections
 import datetime
 import functools
diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
index a33e318..c2d94ae 100644
--- a/hubs/widgets/bugzilla.py
+++ b/hubs/widgets/bugzilla.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 import pkgwat.api
 
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
index 717e047..b869094 100755
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.widgets.base import wraps
 from hubs.widgets import templating
 
diff --git a/hubs/widgets/clean_input.py b/hubs/widgets/clean_input.py
index 2ec458a..9d25104 100644
--- a/hubs/widgets/clean_input.py
+++ b/hubs/widgets/clean_input.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from six.moves.urllib.parse import urlparse
 
 import bleach
diff --git a/hubs/widgets/contact.py b/hubs/widgets/contact.py
index b76873c..b14e126 100644
--- a/hubs/widgets/contact.py
+++ b/hubs/widgets/contact.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import flask
 
 import fedmsg.config
diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
index 2e73bca..bd198d3 100755
--- a/hubs/widgets/dummy.py
+++ b/hubs/widgets/dummy.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
index 533c563..0cf5ba2 100755
--- a/hubs/widgets/fedmsgstats.py
+++ b/hubs/widgets/fedmsgstats.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
index 8ea6536..5d744d9 100755
--- a/hubs/widgets/feed.py
+++ b/hubs/widgets/feed.py
@@ -1,4 +1,4 @@
-from __future__ import print_function
+from __future__ import print_function, unicode_literals
 
 from hubs.hinting import hint
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/fhosted.py b/hubs/widgets/fhosted.py
index 827b228..bc97d8b 100644
--- a/hubs/widgets/fhosted.py
+++ b/hubs/widgets/fhosted.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from six.moves.xmlrpc_client import ServerProxy
 
 import hubs.validators as validators
diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
index b2d1788..c2a0be9 100755
--- a/hubs/widgets/github_pr.py
+++ b/hubs/widgets/github_pr.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import logging
 
 from hubs.widgets.chrome import panel
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
index 986ff11..7130183 100755
--- a/hubs/widgets/githubissues.py
+++ b/hubs/widgets/githubissues.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 
 from hubs.hinting import hint
diff --git a/hubs/widgets/library.py b/hubs/widgets/library.py
index b18354a..08ad334 100644
--- a/hubs/widgets/library.py
+++ b/hubs/widgets/library.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
@@ -21,9 +23,9 @@ def data(session, widget, urls):
 
     urls = [
         clean_input.clean(
-            '<a href="{0}">{0}</a>'.format(u.encode('utf-8').strip()))
+            '<a href="{0}">{0}</a>'.format(u.strip()))
         for u in widget.config.get('urls', '').split(',')
-        if u.encode('utf-8').strip()
+        if u.strip()
     ]
     return dict(urls=urls)
 
diff --git a/hubs/widgets/linechart.py b/hubs/widgets/linechart.py
index f12ef8f..3d41057 100755
--- a/hubs/widgets/linechart.py
+++ b/hubs/widgets/linechart.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint
 from hubs.widgets.base import argument
 from hubs.widgets import templating
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
index 8c05744..713177b 100755
--- a/hubs/widgets/meetings.py
+++ b/hubs/widgets/meetings.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
diff --git a/hubs/widgets/memberships.py b/hubs/widgets/memberships.py
index 48d8fea..2763db0 100644
--- a/hubs/widgets/memberships.py
+++ b/hubs/widgets/memberships.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import hubs.models
 from hubs.hinting import hint, prefixed as _
 import hubs.validators as validators
diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
index cdb8365..081dcb4 100755
--- a/hubs/widgets/pagure_pr.py
+++ b/hubs/widgets/pagure_pr.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
index c9ecd53..9a4dca8 100755
--- a/hubs/widgets/pagureissues.py
+++ b/hubs/widgets/pagureissues.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 
 from hubs.hinting import hint
diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
index 443f07c..d7554b9 100755
--- a/hubs/widgets/rules.py
+++ b/hubs/widgets/rules.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from collections import OrderedDict as ordereddict
 
 from hubs.hinting import hint, prefixed as _
diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
index 55c90db..ebd6cc8 100755
--- a/hubs/widgets/stats.py
+++ b/hubs/widgets/stats.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets import templating
diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
index 55cc6a1..ca74f59 100755
--- a/hubs/widgets/sticky.py
+++ b/hubs/widgets/sticky.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.chrome import panel
 from hubs.widgets.base import argument
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 82fce66..8035d3d 100755
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 from hubs.hinting import hint, prefixed as _
 from hubs.widgets.base import argument
 from hubs.widgets.chrome import panel
diff --git a/hubs/widgets/templating.py b/hubs/widgets/templating.py
index 98b29cd..41e0c5b 100644
--- a/hubs/widgets/templating.py
+++ b/hubs/widgets/templating.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import os
 
 import jinja2
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 581bd70..5bc6594 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 
 from hubs.hinting import hint, prefixed as _
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 675d793..c7df1c3 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
 import requests
 
 from hubs.hinting import hint, prefixed as _
diff --git a/populate-from-fas.py b/populate-from-fas.py
index 7639c81..b74e8a6 100755
--- a/populate-from-fas.py
+++ b/populate-from-fas.py
@@ -1,6 +1,8 @@
 #!/usr/bin/env python
 """ Populate the hubs db with lots of data from FAS. """
 
+from __future__ import unicode_literals
+
 import getpass
 import socket
 import string
diff --git a/populate.py b/populate.py
index 5c34700..4286940 100755
--- a/populate.py
+++ b/populate.py
@@ -1,6 +1,8 @@
 #!/usr/bin/env python
 """ Populate the hubs db with some dev data. """
 
+from __future__ import unicode_literals
+
 import json
 
 import hubs.models
diff --git a/runserver.py b/runserver.py
index 5e5a4f2..9552b0a 100755
--- a/runserver.py
+++ b/runserver.py
@@ -1,5 +1,7 @@
 #!/usr/bin/env python2
 
+from __future__ import unicode_literals
+
 import argparse
 import sys
 import os
diff --git a/setup.py b/setup.py
index 15f69c2..aa9b63e 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,7 @@
 """ Setup file for fedora hubs """
 
+from __future__ import unicode_literals
+
 from setuptools import setup, find_packages
 
 
diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index 77021fc..25c2540 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -8,7 +8,7 @@ This is really useful for development purposes as it allow seeing changes
 made to a widget without dropping the entire cache database.
 """
 
-from __future__ import print_function
+from __future__ import print_function, unicode_literals
 
 import argparse
 import os

From def768a3a816e8bc1fc10eae4f9e83b886d07f12 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 31 2017 18:25:49 +0000
Subject: [PATCH 682/1001] Split off the views in their own module


Fixes #305

---

diff --git a/hubs/app.py b/hubs/app.py
index 89b5271..006edea 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,23 +1,17 @@
-from __future__ import print_function, unicode_literals
+from __future__ import unicode_literals
 
 import datetime
-import functools
 import json
 import logging
 import os
-import six
-from six.moves.urllib import parse as urlparse
 
 import flask
 import flask.json
 import munch
 
 from flask.ext.oidc import OpenIDConnect
-import requests
 
 import hubs.models
-import hubs.widgets
-import hubs.stream
 
 import datanommer.models
 
@@ -36,11 +30,6 @@ app.template_filter('avatar')(username2avatar)
 
 logging.basicConfig()
 
-# TODO - put this in config so we can migrate to pagure
-# TODO - instead of 'develop', use the version from pkg_resources to figure out
-#        the right tag to link people to.  AGPL ftw.
-SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'  # /hubs/widgets/badges.py'
-
 app.config.from_object('hubs.default_config')
 if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
@@ -54,6 +43,10 @@ fedmsg.meta.make_processors(**fedmsg_config)
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 datanommer.models.init(fedmsg_config['datanommer.sqlalchemy.uri'])
 
+@app.before_request
+def store_db():
+    flask.g.db = session
+
 
 class CustomJSONEncoder(flask.json.JSONEncoder):
     def default(self, o):
@@ -69,24 +62,6 @@ class CustomJSONEncoder(flask.json.JSONEncoder):
 app.json_encoder = CustomJSONEncoder
 
 
-def authenticated():
-    """ Utility function checking if the current auth is set or not."""
-    return hasattr(flask.g, 'auth') \
-        and flask.g.auth is not None \
-        and flask.g.auth.logged_in
-
-
-def is_safe_url(target):
-    """ Checks that the target url is safe and sending to the current
-    website not some other malicious one.
-    """
-    ref_url = urlparse.urlparse(flask.request.host_url)
-    test_url = urlparse.urlparse(
-        urlparse.urljoin(flask.request.host_url, target))
-    return test_url.scheme in ('http', 'https') and \
-        ref_url.netloc == test_url.netloc
-
-
 @app.template_filter('commas')
 def commas(numeric):
     return "{:,.2f}".format(numeric)
@@ -98,490 +73,10 @@ def shutdown_session(exception=None):
     session.remove()
 
 
-@app.route('/')
-def index():
-    if not authenticated():
-        return flask.redirect(flask.url_for('login'))
-
-    return flask.redirect(flask.url_for('stream', name=flask.g.auth.nickname))
-
-
-@app.route('/groups')
-def groups():
-    if not authenticated():
-        return flask.redirect(flask.url_for('login'))
-
-    # Get the list of promoted and non-promoted group hubs from the DB
-    promoted_names = app.config.get('PROMOTED_GROUPS')
-    groups = hubs.models.Hub.all_group_hubs(session)
-    promoted = [g for g in groups if g.name in promoted_names]
-    secondary = [g for g in groups if g.name not in promoted_names]
-
-    name_of_the_month = app.config.get('HUB_OF_THE_MONTH')
-    hub_of_the_month = hubs.models.Hub.by_name(session, name_of_the_month)
-
-    return flask.render_template(
-        'groups.html',
-        promoted=promoted,
-        secondary=secondary,
-        hub_of_the_month=hub_of_the_month,
-        session=session,
-    )
-
-
-@app.route('/<name>')
-@app.route('/<name>/')
-def hub(name):
-    hub = get_hub(session, name)
-    return flask.render_template(
-        'hubs.html', hub=hub, session=session, edit=False)
-
-
-@app.route('/<name>/json/')
-@app.route('/<name>/json')
-def hub_json(name):
-    hub = get_hub(session, name)
-    response = flask.jsonify(hub.__json__(session))
-    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
-    return response
-
-
-@app.route('/<name>/edit/', methods=['GET', 'POST'])
-@app.route('/<name>/edit', methods=['GET', 'POST'])
-def hub_edit(name):
-    if flask.request.method == 'POST':
-        return hub_edit_post(name)
-    else:
-        return hub_edit_get(name)
-
-
-def hub_edit_get(name):
-    hub = get_hub(session, name)
-    return flask.render_template(
-        'hubs.html', hub=hub, session=session, edit=True)
-
-
-def hub_edit_post(name):
-    hub = get_hub(session, name)
-    is_js = flask.request.form.get('js', False)
-
-    error = False
-
-    # Check the input submitted
-    # Right side
-    r_widget_ids = [
-        w.strip().replace('widget-', '')
-        for w in flask.request.form.getlist('right_widgets[]')
-        if w.strip()
-        ]
-    try:
-        r_widget_ids = [int(w) for w in r_widget_ids]
-    except:
-        flask.flash('Invalid widget identifiers submitted', 'error')
-        error = True
-
-    r_indexes = [
-        i.strip() for i in flask.request.form.getlist('right_indexes[]')
-        if i.strip()
-        ]
-
-    try:
-        r_indexes = [int(i) for i in r_indexes]
-    except:
-        if not is_js:
-            flask.flash('Invalid indexes submitted', 'error')
-        error = True
-
-    if len(r_widget_ids) != len(r_indexes):
-        if not is_js:
-            flask.flash(
-                'The number of indexes and the number of widgets are not of '
-                'the same length', 'error')
-        error = True
-
-    # Left side
-    l_widget_ids = [
-        w.strip().replace('widget-', '')
-        for w in flask.request.form.getlist('left_widgets[]')
-        if w.strip()
-        ]
-    try:
-        l_widget_ids = [int(w) for w in l_widget_ids]
-    except:
-        flask.flash('Invalid widget identifiers submitted', 'error')
-        error = True
-
-    l_indexes = [
-        i.strip() for i in flask.request.form.getlist('left_indexes[]')
-        if i.strip()
-        ]
-
-    try:
-        l_indexes = [int(i) for i in l_indexes]
-    except:
-        if not is_js:
-            flask.flash('Invalid indexes submitted', 'error')
-        error = True
-
-    if len(l_widget_ids) != len(l_indexes):
-        if not is_js:
-            flask.flash(
-                'The number of indexes and the number of widgets are not of '
-                'the same length', 'error')
-        error = True
-
-    # If all good, update the database
-    if not error:
-        for cnt, wid in enumerate(r_widget_ids):
-            widget = hubs.models.Widget.get(session, wid)
-            if widget.index != r_indexes[cnt]:
-                widget.index = r_indexes[cnt]
-                session.add(widget)
-        for cnt, wid in enumerate(l_widget_ids):
-            widget = hubs.models.Widget.get(session, wid)
-            if widget.index != l_indexes[cnt]:
-                widget.index = l_indexes[cnt]
-                session.add(widget)
-        hub.last_edited = datetime.datetime.utcnow()
-        session.add(hub)
-        try:
-            session.commit()
-        except Exception as err:
-            error = True
-            if not is_js:
-                flask.flash(
-                    'Could not save your changes to the database '
-                    'if the error persists, please warn an admin',
-                    'error')
-    if is_js:
-        if error:
-            flask.abort(400)
-        else:
-            return ('ok', 200)
-    else:
-        return flask.redirect(flask.url_for('hub', name=name))
-
-
-@app.route('/<name>/add/', methods=['GET', 'POST'])
-@app.route('/<name>/add', methods=['GET', 'POST'])
-def hub_add_widgets(name):
-    if flask.request.method == 'POST':
-        return hub_add_widget_post(name)
-    else:
-        return hub_add_widget_get(name)
-
-
-@app.route('/<name>/add/<widget_name>/', methods=['GET'])
-@app.route('/<name>/add/<widget_name>', methods=['GET'])
-def hub_add_widget(name, widget_name):
-    hub = get_hub(session, name)
-    side = str(flask.request.args.get('position')).lower()
-    if side not in ['right', 'left']:
-        flask.abort(400, 'Invalid position provided')
-
-    widget = None
-    w_name = None
-    for widgt in hubs.widgets.registry:
-        if hubs.widgets.registry[widgt].position in ['both', side] \
-                and widgt == widget_name:
-            w_name = widgt
-            widget = hubs.widgets.registry[widgt]
-
-    return flask.render_template(
-        'add_widget.html',
-        hub=hub,
-        widget=widget,
-        widget_name=w_name,
-        side=side,
-        url_to=flask.url_for('hub_add_widgets', name=name),
-    )
-
-
-def hub_add_widget_get(name):
-    hub = get_hub(session, name)
-    side = str(flask.request.args.get('position')).lower()
-    if side not in ['right', 'left']:
-        flask.abort(400, 'Invalid position provided')
-
-    widgets = [
-        widget
-        for widget in hubs.widgets.registry
-        if hubs.widgets.registry[widget].position in ['both', side]
-        ]
-    return flask.render_template(
-        'add_widget.html',
-        hub=hub,
-        widgets=widgets,
-        side=side,
-    )
-
-
-def hub_add_widget_post(name):
-    widget_name = flask.request.form.get('widget_name')
-    position = flask.request.form.get('position', '').lower()
-    if not widget_name:
-        flask.abort(400, 'Invalid request sent')
-    if widget_name not in hubs.widgets.registry:
-        flask.abort(404, 'Unknown widget called')
-
-    hub = get_hub(session, name)
-
-    widget = widget = hubs.models.Widget(
-        plugin=widget_name, index=-1, left=position == 'left')
-    error = False
-    config = {}
-    for arg in widget.module.data.widget_arguments:
-        val = flask.request.form.get(arg.name)
-        if not val:
-            flask.flash(
-                'You must provide a value for: %s' % arg.name, 'error')
-            error = True
-            break
-        try:
-            arg.validator(session, val)
-            config[arg.name] = val
-        except Exception as err:
-            flask.flash('Invalid data provided, error: %s' % err, 'error')
-            error = True
-    if not error:
-        widget.hub = hub
-        widget.config = config
-        try:
-            session.add(widget)
-            session.flush()
-            widget.hub.last_edited = datetime.datetime.utcnow()
-            session.commit()
-        except Exception as err:
-            print(err)
-            flask.flash(
-                'Could not save the configuration to the database '
-                'if the error persists, please warn an admin',
-                'error')
-
-    return flask.render_template(
-        'hubs.html', hub=hub, session=session, edit=True)
-
-
-@app.route('/<hub>/<int:idx>/')
-@app.route('/<hub>/<int:idx>')
-def widget_render(hub, idx):
-    widget = get_widget(session, hub, idx)
-    return widget.render(session)  # , edit=False)
-    # was blocking all widgets from working, sorry!
-
-
-@app.route('/<hub>/<int:idx>/json')
-@app.route('/<hub>/<int:idx>/json/')
-def widget_json(hub, idx):
-    widget = get_widget(session, hub, idx)
-    response = flask.jsonify(widget.__json__(session))
-    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
-    return response
-
-
-@app.route('/<hub>/<int:idx>/edit/', methods=['GET', 'POST'])
-@app.route('/<hub>/<int:idx>/edit', methods=['GET', 'POST'])
-def widget_edit(hub, idx):
-    if flask.request.method == 'POST':
-        return widget_edit_post(hub, idx)
-    else:
-        return widget_edit_get(hub, idx)
-
-
-def widget_edit_get(hub, idx):
-    widget = get_widget(session, hub, idx)
-    return flask.render_template(
-        'edit.html',
-        hub=hub,
-        widget=widget,
-        url_to=flask.url_for('widget_edit', hub=hub, idx=idx)
-    )
-
-
-def widget_edit_post(hub, idx):
-    widget = get_widget(session, hub, idx)
-    error = False
-    config = {}
-    for arg in widget.module.data.widget_arguments:
-        val = flask.request.form.get(arg.name)
-        if not val:
-            flask.flash(
-                'You must provide a value for: %s' % arg.name, 'error')
-            error = True
-            break
-        try:
-            val = arg.validator(session, val)
-            config[arg.name] = val
-        except Exception as err:
-            flask.flash('Invalid data provided, error: %s' % err, 'error')
-            error = True
-    if not error:
-        cur_config = widget.config
-        cur_config.update(config)
-        widget.config = cur_config
-        widget.hub.last_edited = datetime.datetime.utcnow()
-        session.add(widget)
-        try:
-            session.commit()
-        except Exception as err:
-            flask.flash(
-                'Could not save the configuration to the database '
-                'if the error persists, please warn an admin',
-                'error')
-    return flask.redirect(flask.url_for('hub', name=hub))
-
-
-@app.route('/<hub>/<int:idx>/delete/', methods=['POST'])
-@app.route('/<hub>/<int:idx>/delete', methods=['POST'])
-def widget_edit_delete(hub, idx):
-    ''' Remove a widget from a hub. '''
-    widget = get_widget(session, hub, idx)
-    session.delete(widget)
-    try:
-        session.commit()
-    except Exception as err:
-        flask.flash(
-            'Could not delete this widget from this hub in the database '
-            'if the error persists, please warn an admin',
-            'error')
-    return flask.redirect(flask.url_for('hub_edit', name=hub))
-
-
-@app.route('/source/<name>/')
-@app.route('/source/<name>')
-def widget_source(name):
-    from hubs.widgets import registry
-    base = '/hubs/'
-    fname = ''
-
-    try:
-        fname = base + registry[name].__file__.split(base)[-1]
-    except KeyError:
-        flask.abort(404)
-
-    fname = fname.replace('.pyc', '.py')
-    return flask.redirect(SOURCE_URL + fname)
-
-
 # Set up OpenIDConnect
 OIDC = OpenIDConnect(app, credentials_store=flask.session )
 
 
-@app.route('/login/', methods=('GET', 'POST'))
-@app.route('/login', methods=('GET', 'POST'))
-@OIDC.require_login
-def login():
-    default = flask.url_for('index')
-    next_url = flask.request.args.get('next', default)
-    if is_safe_url(next_url):
-        return_point = next_url
-    else:
-        return_point = default
-
-    hubs.models.User.get_or_create(
-        session, username=flask.g.auth.nickname, fullname=flask.g.auth.fullname)
-
-    return flask.redirect(return_point)
-
-
-@app.route('/logout/')
-@app.route('/logout')
-def logout():
-    next_url = flask.url_for('index')
-    if 'next' in flask.request.values:  # pragma: no cover
-        if is_safe_url(flask.request.args['next']):
-            next_url = flask.request.values['next']
-
-    if next_url == flask.url_for('login'):  # pragma: no cover
-        next_url = flask.url_for('index')
-
-    if authenticated():
-        OIDC.logout()
-        flask.session.auth = None
-        flask.flash('You have been logged out')
-
-    return flask.redirect(next_url)
-
-
-def login_required(function):
-    """ Flask decorator to restrict access to logged-in users. """
-
-    @functools.wraps(function)
-    def decorated_function(*args, **kwargs):
-        """ Decorated function, actually does the work. """
-        if not authenticated():
-            flask.flash('Login required', 'errors')
-            return flask.redirect(flask.url_for(
-                'login', next=flask.request.url))
-
-        return function(*args, **kwargs)
-
-    return decorated_function
-
-@app.route('/<name>/stream')
-@app.route('/<name>/stream/')
-@login_required
-def stream(name):
-    hub = get_hub(session, name)
-    saved = hubs.models.SavedNotification.by_username(session, name)
-    saved = [n.__json__() for n in saved]
-
-    stream = hubs.stream.Stream()
-    actions = stream.get_json()
-
-    return flask.render_template(
-        'stream.html',
-        hub=hub,
-        saved=json.dumps(saved),
-        actions=actions
-    )
-
-
-@app.route('/<user>/notifications', methods=['GET', 'POST'])
-@app.route('/<user>/notifications/', methods=['GET', 'POST'])
-@login_required
-def notifications(user):
-    if flask.request.method == 'GET':
-        notifications = hubs.models.SavedNotification.by_username(session, user)
-        notifications = [n.__json__() for n in notifications]
-        return flask.jsonify(notifications)
-
-    if flask.request.method == 'POST':
-        data = flask.request.get_json()
-        user = hubs.models.User.by_username(session, user)
-        if not user:
-            return flask.abort(400)
-        try:
-            markup = data['markup']
-            link = data['link']
-            icon = data['secondary_icon']
-            dom_id = data['dom_id']
-        except:
-            return flask.abort(400)
-        notification = hubs.models.SavedNotification(
-            username=user.username,
-            markup=markup,
-            link=link,
-            secondary_icon=icon,
-            dom_id=dom_id
-        )
-        session.add(notification)
-        session.commit()
-        return flask.jsonify(
-            dict(notification=notification.__json__(), success=True)
-        )
-
-@app.route('/<user>/notifications/<int:idx>', methods=['DELETE'])
-@app.route('/<user>/notifications/<int:idx>/', methods=['DELETE'])
-@login_required
-def delete_notifications(user, idx):
-    notification = session.query(hubs.models.SavedNotification).filter_by(idx=idx).first()
-    if not notification:
-        return flask.abort(400)
-    session.delete(notification)
-    session.commit()
-    return flask.jsonify(dict(status_code=200))
-
 @app.before_request
 def check_auth():
     flask.session.permanent = True
@@ -610,223 +105,4 @@ def check_auth():
         flask.g.auth = munch.Munch(logged_in=False)
 
 
-def get_hub(session, name):
-    """ Utility shorthand to get a hub and 404 if not found. """
-    hub = session.query(hubs.models.Hub) \
-        .filter(hubs.models.Hub.name == name) \
-        .first()
-
-    if not hub:
-        flask.abort(404)
-
-    return hub
-
-
-@app.route('/visit/<visited_hub>/', methods=['GET', 'POST'])
-@app.route('/visit/<visited_hub>', methods=['GET', 'POST'])
-@login_required
-def increment_counter(visited_hub):
-    nickname = flask.g.auth.nickname
-
-    if str(visited_hub) != str(nickname):
-        try:
-            vc = hubs.models.VisitCounter.get_or_create(session=session,
-                                                        username=nickname,
-                                                        visited_hub=visited_hub)
-        except ValueError:  # this should never trip
-            # flask will 405 if visited_hub is blank
-            # @login_required forces flask.g.auth to be sets
-            flask.abort(404)
-        if flask.request.method == 'POST':
-            vc.increment_visits(session=session,
-                                username=nickname,
-                                visited_hub=visited_hub)
-
-            return flask.jsonify({'count': vc.count})
-
-        elif flask.request.method == 'GET':
-            return flask.jsonify({'count': vc.count})
-    else:
-        return flask.abort(403)
-
-
-def get_widget(session, hub, idx):
-    """ Utility shorthand to get a widget and 404 if not found. """
-    try:
-        idx = int(idx)
-    except (TypeError, ValueError):
-        flask.abort(404)
-
-    hub = get_hub(session, hub)
-
-    for widget in hub.widgets:
-        if widget.idx == idx:
-            return widget
-
-    flask.abort(404)
-
-
-# Here are a bunch of API methods that should probably be broken out into
-# their own file
-@app.route('/api/hub/<hub>/subscribe', methods=['POST'])
-@login_required
-def hub_subscribe(hub):
-    hub = get_hub(session, hub)
-    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
-    hub.subscribe(session, user)
-    session.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/unsubscribe', methods=['POST'])
-@login_required
-def hub_unsubscribe(hub):
-    hub = get_hub(session, hub)
-    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
-    try:
-        hub.unsubscribe(session, user)
-    except KeyError:
-        return flask.abort(400)
-    session.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/star', methods=['POST'])
-@login_required
-def hub_star(hub):
-    hub = get_hub(session, hub)
-    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
-    hub.subscribe(session, user, role='stargazer')
-    session.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/unstar', methods=['POST'])
-@login_required
-def hub_unstar(hub):
-    hub = get_hub(session, hub)
-    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
-    try:
-        hub.unsubscribe(session, user, role='stargazer')
-    except KeyError:
-        return flask.abort(400)
-    session.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/join', methods=['POST'])
-@login_required
-def hub_join(hub):
-    hub = get_hub(session, hub)
-    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
-    hub.subscribe(session, user, role='member')
-    session.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/leave', methods=['POST'])
-@login_required
-def hub_leave(hub):
-    hub = get_hub(session, hub)
-    user = hubs.models.User.by_username(session, flask.g.auth.nickname)
-    try:
-        hub.unsubscribe(session, user, role='member')
-    except KeyError:
-        return flask.abort(400)
-    session.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/plus_plus/<user>/status', methods=['GET'])
-def plus_plus_status(user):
-    receiver = hubs.models.User.by_username(session, user)
-    if not receiver:
-        return 'User does not exist', 403
-    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
-    req = None
-    try:
-        req = requests.get(pp_url)
-    except:
-        flask.abort(500)
-    if req.status_code == 200:
-        return flask.jsonify(req.json())
-    else:
-        return req.text, req.status_code
-
-
-def plus_plus_update_bool_helper(val):
-    if isinstance(val, bool):
-        return val
-    elif isinstance(val, six.string_types):
-        fmt_str = str(val).replace("'", "").replace('"', '').lower()
-        return fmt_str in ("yes", "true", "t", "1")
-    else:
-        raise ValueError
-
-
-@app.route('/plus_plus/<user>/update', methods=['POST'])
-@login_required
-def plus_plus_update(user):
-    receiver = hubs.models.User.by_username(session, user)
-
-    if not receiver:
-        return 'User does not exist', 403
-
-    if user == flask.g.auth.nickname:
-        return 'You may not modify your own karma.', 403
-
-    if 'decrement' not in flask.request.form \
-            and 'increment' not in flask.request.form:
-        return "You must set 'decrement' or 'increment' " \
-               "with a boolean value in the body", 403
-
-    update = 'increment' if 'increment' in flask.request.form else 'decrement'
-
-    update_bool_val = plus_plus_update_bool_helper(flask.request.form[update])
-    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
-    sender = hubs.models.User.by_username(session, flask.g.auth.nickname)
-    pp_token = app.config['PLUS_PLUS_TOKEN']
-    auth_header = {'Authorization': 'token {}'.format(pp_token)}
-    data = {'sender': sender.username, update: update_bool_val}
-    req = None
-    try:
-        req = requests.post(url=pp_url, headers=auth_header, data=data)
-    except:
-        flask.abort(500)
-
-    if req.status_code == 200:
-        return flask.jsonify(req.json())
-    else:
-        return req.text, req.status_code
-
-
-#
-# Add widget-specific routes
-#
-
-def _widget_view_decorator(func):
-    """
-    This internal decorator will edit the view function arguments.
-
-    It will:
-    - remove the hub name and the widget primary key
-    - add the database session and the widget instance
-    """
-    @functools.wraps(func)
-    def inner(*args, **kwargs):
-        hubname = kwargs.pop("hub")
-        widgetidx = kwargs.pop("idx")
-        widget = get_widget(session, hubname, widgetidx)
-        return func(session, widget, *args, **kwargs)
-    return inner
-
-for widget in session.query(hubs.models.Widget):
-    for params in getattr(widget.module, 'ROUTES', []):
-        params["rule"] = "/<hub>/<int:idx>/widget/" \
-                         + params["rule"].lstrip("/")
-        if not params.get("endpoint"):
-            params["endpoint"] = params["view_func_name"]
-        params["endpoint"] = "%s_%s" % (widget.plugin, params["endpoint"])
-        params["view_func"] = _widget_view_decorator(
-            getattr(widget.module, params.pop("view_func_name")))
-        app.add_url_rule(**params)
+import hubs.views
diff --git a/hubs/default_config.py b/hubs/default_config.py
index 769f8ad..085ec5f 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -24,3 +24,7 @@ OIDC_ID_TOKEN_COOKIE_SECURE = True
 OIDC_REQUIRE_VERIFIED_EMAIL = False
 OIDC_OPENID_REALM = 'http://localhost:5000/oidc_callback'
 OIDC_SCOPES = ['openid', 'email', 'profile', 'fedora']
+
+# TODO - instead of 'develop', use the version from pkg_resources to figure out
+#        the right tag to link people to.  AGPL ftw.
+SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'  # /hubs/widgets/badges.py'
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 7f8aa8c..b1e182f 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -33,6 +33,7 @@ class APPTest(unittest.TestCase):
             hubs.app.fedmsg_config['hubs.sqlalchemy.uri'],
             create=True,
         )
+        hubs.app.app.config['TESTING'] = True
         self.app = hubs.app.app.test_client()
         self.app.testing = True
         self.session = hubs.app.session
@@ -106,11 +107,13 @@ def auth_set(APP, auth):
     :param auth: A FakeAuthorization instance to set as g.auth.
     """
 
-    # Hack used to remove the before_request function set by
-    # flask.ext.fas_openid.FAS which otherwise kills our effort to set a
-    # flask.g.auth.
+    # Hack used to remove the check_auth function set on `before_request`
+    # which otherwise kills our effort to set a flask.g.auth.
     from flask import appcontext_pushed, g
-    APP.before_request_funcs[None] = []
+    APP.before_request_funcs[None] = [
+        f for f in APP.before_request_funcs[None]
+        if f.__name__ != 'check_auth'
+    ]
 
     def handler(sender, **kwargs):
         g.auth = auth
diff --git a/hubs/tests/test_api/__init__.py b/hubs/tests/test_api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/tests/test_api/__init__.py
diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
new file mode 100644
index 0000000..13fb79c
--- /dev/null
+++ b/hubs/views/__init__.py
@@ -0,0 +1,46 @@
+from __future__ import absolute_import
+
+from .root import *
+from .hub import *
+from .widget import *
+from .user import *
+from .api import *
+from .plus_plus import *
+
+#
+# Add widget-specific routes
+#
+
+import flask
+import functools
+import hubs.models
+from sqlalchemy.orm.exc import NoResultFound
+from hubs.app import app, session
+from .utils import get_widget
+
+def _widget_view_decorator(func):
+    """
+    This internal decorator will edit the view function arguments.
+
+    It will:
+    - remove the hub name and the widget primary key
+    - add the database session and the widget instance
+    """
+    @functools.wraps(func)
+    def inner(*args, **kwargs):
+        hubname = kwargs.pop("hub")
+        widgetidx = kwargs.pop("idx")
+        widget = get_widget(hubname, widgetidx, session=session)
+        return func(session, widget, *args, **kwargs)
+    return inner
+
+for widget in session.query(hubs.models.Widget):
+    for params in getattr(widget.module, 'ROUTES', []):
+        params["rule"] = "/<hub>/<int:idx>/widget/" \
+                         + params["rule"].lstrip("/")
+        if not params.get("endpoint"):
+            params["endpoint"] = params["view_func_name"]
+        params["endpoint"] = "%s_%s" % (widget.plugin, params["endpoint"])
+        params["view_func"] = _widget_view_decorator(
+            getattr(widget.module, params.pop("view_func_name")))
+        app.add_url_rule(**params)
diff --git a/hubs/views/api.py b/hubs/views/api.py
new file mode 100644
index 0000000..18ca0ba
--- /dev/null
+++ b/hubs/views/api.py
@@ -0,0 +1,78 @@
+from __future__ import unicode_literals, absolute_import
+
+
+import flask
+import hubs.models
+
+from hubs.app import app
+from .utils import get_hub, login_required
+
+
+@app.route('/api/hub/<hub>/subscribe', methods=['POST'])
+@login_required
+def hub_subscribe(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    hub.subscribe(flask.g.db, user)
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hub/<hub>/unsubscribe', methods=['POST'])
+@login_required
+def hub_unsubscribe(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    try:
+        hub.unsubscribe(flask.g.db, user)
+    except KeyError:
+        return flask.abort(400)
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hub/<hub>/star', methods=['POST'])
+@login_required
+def hub_star(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    hub.subscribe(flask.g.db, user, role='stargazer')
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hub/<hub>/unstar', methods=['POST'])
+@login_required
+def hub_unstar(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    try:
+        hub.unsubscribe(flask.g.db, user, role='stargazer')
+    except KeyError:
+        return flask.abort(400)
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hub/<hub>/join', methods=['POST'])
+@login_required
+def hub_join(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    hub.subscribe(flask.g.db, user, role='member')
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hub/<hub>/leave', methods=['POST'])
+@login_required
+def hub_leave(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    try:
+        hub.unsubscribe(flask.g.db, user, role='member')
+    except KeyError:
+        return flask.abort(400)
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
new file mode 100644
index 0000000..12b75e9
--- /dev/null
+++ b/hubs/views/hub.py
@@ -0,0 +1,241 @@
+from __future__ import unicode_literals, absolute_import
+
+import datetime
+import flask
+import hubs.models
+
+from hubs.app import app, session
+from .utils import get_hub
+
+
+@app.route('/<name>')
+@app.route('/<name>/')
+def hub(name):
+    hub = get_hub(name)
+    return flask.render_template(
+        'hubs.html', hub=hub, edit=False)
+
+
+@app.route('/<name>/json/')
+@app.route('/<name>/json')
+def hub_json(name):
+    hub = get_hub(name)
+    response = flask.jsonify(hub.__json__(flask.g.db))
+    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
+    return response
+
+
+@app.route('/<name>/edit/', methods=['GET', 'POST'])
+@app.route('/<name>/edit', methods=['GET', 'POST'])
+def hub_edit(name):
+    if flask.request.method == 'POST':
+        return hub_edit_post(name)
+    else:
+        return hub_edit_get(name)
+
+
+def hub_edit_get(name):
+    hub = get_hub(name)
+    return flask.render_template(
+        'hubs.html', hub=hub, edit=True)
+
+
+def hub_edit_post(name):
+    hub = get_hub(name)
+    is_js = flask.request.form.get('js', False)
+
+    error = False
+
+    # Check the input submitted
+    # Right side
+    r_widget_ids = [
+        w.strip().replace('widget-', '')
+        for w in flask.request.form.getlist('right_widgets[]')
+        if w.strip()
+        ]
+    try:
+        r_widget_ids = [int(w) for w in r_widget_ids]
+    except:
+        flask.flash('Invalid widget identifiers submitted', 'error')
+        error = True
+
+    r_indexes = [
+        i.strip() for i in flask.request.form.getlist('right_indexes[]')
+        if i.strip()
+        ]
+
+    try:
+        r_indexes = [int(i) for i in r_indexes]
+    except:
+        if not is_js:
+            flask.flash('Invalid indexes submitted', 'error')
+        error = True
+
+    if len(r_widget_ids) != len(r_indexes):
+        if not is_js:
+            flask.flash(
+                'The number of indexes and the number of widgets are not of '
+                'the same length', 'error')
+        error = True
+
+    # Left side
+    l_widget_ids = [
+        w.strip().replace('widget-', '')
+        for w in flask.request.form.getlist('left_widgets[]')
+        if w.strip()
+        ]
+    try:
+        l_widget_ids = [int(w) for w in l_widget_ids]
+    except:
+        flask.flash('Invalid widget identifiers submitted', 'error')
+        error = True
+
+    l_indexes = [
+        i.strip() for i in flask.request.form.getlist('left_indexes[]')
+        if i.strip()
+        ]
+
+    try:
+        l_indexes = [int(i) for i in l_indexes]
+    except:
+        if not is_js:
+            flask.flash('Invalid indexes submitted', 'error')
+        error = True
+
+    if len(l_widget_ids) != len(l_indexes):
+        if not is_js:
+            flask.flash(
+                'The number of indexes and the number of widgets are not of '
+                'the same length', 'error')
+        error = True
+
+    # If all good, update the database
+    if not error:
+        for cnt, wid in enumerate(r_widget_ids):
+            widget = flask.g.db.query(hubs.models.Widget).get(wid)
+            if widget.index != r_indexes[cnt]:
+                widget.index = r_indexes[cnt]
+                flask.g.db.add(widget)
+        for cnt, wid in enumerate(l_widget_ids):
+            widget = flask.g.db.query(hubs.models.Widget).get(wid)
+            if widget.index != l_indexes[cnt]:
+                widget.index = l_indexes[cnt]
+                flask.g.db.add(widget)
+        hub.last_edited = datetime.datetime.utcnow()
+        flask.g.db.add(hub)
+        try:
+            flask.g.db.commit()
+        except Exception as err:
+            error = True
+            if not is_js:
+                flask.flash(
+                    'Could not save your changes to the database '
+                    'if the error persists, please warn an admin',
+                    'error')
+    if is_js:
+        if error:
+            flask.abort(400)
+        else:
+            return ('ok', 200)
+    else:
+        return flask.redirect(flask.url_for('hub', name=name))
+
+
+@app.route('/<name>/add/', methods=['GET', 'POST'])
+@app.route('/<name>/add', methods=['GET', 'POST'])
+def hub_add_widgets(name):
+    if flask.request.method == 'POST':
+        return hub_add_widget_post(name)
+    else:
+        return hub_add_widget_get(name)
+
+
+@app.route('/<name>/add/<widget_name>/', methods=['GET'])
+@app.route('/<name>/add/<widget_name>', methods=['GET'])
+def hub_add_widget(name, widget_name):
+    hub = get_hub(name)
+    side = str(flask.request.args.get('position')).lower()
+    if side not in ['right', 'left']:
+        flask.abort(400, 'Invalid position provided')
+
+    widget = None
+    w_name = None
+    for widgt in hubs.widgets.registry:
+        if hubs.widgets.registry[widgt].position in ['both', side] \
+                and widgt == widget_name:
+            w_name = widgt
+            widget = hubs.widgets.registry[widgt]
+
+    return flask.render_template(
+        'add_widget.html',
+        hub=hub,
+        widget=widget,
+        widget_name=w_name,
+        side=side,
+        url_to=flask.url_for('hub_add_widgets', name=name),
+    )
+
+
+def hub_add_widget_get(name):
+    hub = get_hub(name)
+    side = str(flask.request.args.get('position')).lower()
+    if side not in ['right', 'left']:
+        flask.abort(400, 'Invalid position provided')
+
+    widgets = [
+        widget
+        for widget in hubs.widgets.registry
+        if hubs.widgets.registry[widget].position in ['both', side]
+        ]
+    return flask.render_template(
+        'add_widget.html',
+        hub=hub,
+        widgets=widgets,
+        side=side,
+    )
+
+
+def hub_add_widget_post(name):
+    widget_name = flask.request.form.get('widget_name')
+    position = flask.request.form.get('position', '').lower()
+    if not widget_name:
+        flask.abort(400, 'Invalid request sent')
+    if widget_name not in hubs.widgets.registry:
+        flask.abort(404, 'Unknown widget called')
+
+    hub = get_hub(name)
+
+    widget = widget = hubs.models.Widget(
+        plugin=widget_name, index=-1, left=position == 'left')
+    error = False
+    config = {}
+    for arg in widget.module.data.widget_arguments:
+        val = flask.request.form.get(arg.name)
+        if not val:
+            flask.flash(
+                'You must provide a value for: %s' % arg.name, 'error')
+            error = True
+            break
+        try:
+            arg.validator(flask.g.db, val)
+            config[arg.name] = val
+        except Exception as err:
+            flask.flash('Invalid data provided, error: %s' % err, 'error')
+            error = True
+    if not error:
+        widget.hub = hub
+        widget.config = config
+        try:
+            flask.g.db.add(widget)
+            flask.g.db.flush()
+            widget.hub.last_edited = datetime.datetime.utcnow()
+            flask.g.db.commit()
+        except Exception as err:
+            print(err)
+            flask.flash(
+                'Could not save the configuration to the database '
+                'if the error persists, please warn an admin',
+                'error')
+
+    return flask.render_template(
+        'hubs.html', hub=hub, edit=True)
diff --git a/hubs/views/plus_plus.py b/hubs/views/plus_plus.py
new file mode 100644
index 0000000..266c2ea
--- /dev/null
+++ b/hubs/views/plus_plus.py
@@ -0,0 +1,77 @@
+from __future__ import unicode_literals, absolute_import
+
+import flask
+import requests
+import six
+import hubs.models
+
+from hubs.app import app, session
+from .utils import login_required
+
+
+# These views should be converted to widget-specific views, now that we can do
+# that.
+
+
+@app.route('/plus_plus/<user>/status', methods=['GET'])
+def plus_plus_status(user):
+    receiver = hubs.models.User.by_username(flask.g.db, user)
+    if not receiver:
+        return 'User does not exist', 403
+    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
+    req = None
+    try:
+        req = requests.get(pp_url)
+    except:
+        flask.abort(500)
+    if req.status_code == 200:
+        return flask.jsonify(req.json())
+    else:
+        return req.text, req.status_code
+
+
+def plus_plus_update_bool_helper(val):
+    if isinstance(val, bool):
+        return val
+    elif isinstance(val, six.string_types):
+        fmt_str = str(val).replace("'", "").replace('"', '').lower()
+        return fmt_str in ("yes", "true", "t", "1")
+    else:
+        raise ValueError
+
+
+@app.route('/plus_plus/<user>/update', methods=['POST'])
+@login_required
+def plus_plus_update(user):
+    receiver = hubs.models.User.by_username(flask.g.db, user)
+
+    if not receiver:
+        return 'User does not exist', 403
+
+    if user == flask.g.auth.nickname:
+        return 'You may not modify your own karma.', 403
+
+    if 'decrement' not in flask.request.form \
+            and 'increment' not in flask.request.form:
+        return "You must set 'decrement' or 'increment' " \
+               "with a boolean value in the body", 403
+
+    update = 'increment' if 'increment' in flask.request.form else 'decrement'
+
+    update_bool_val = plus_plus_update_bool_helper(flask.request.form[update])
+    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
+    sender = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    pp_token = app.config['PLUS_PLUS_TOKEN']
+    auth_header = {'Authorization': 'token {}'.format(pp_token)}
+    data = {'sender': sender.username, update: update_bool_val}
+    req = None
+    try:
+        req = requests.post(url=pp_url, headers=auth_header, data=data)
+    except:
+        flask.abort(500)
+
+    if req.status_code == 200:
+        return flask.jsonify(req.json())
+    else:
+        return req.text, req.status_code
+
diff --git a/hubs/views/root.py b/hubs/views/root.py
new file mode 100644
index 0000000..cc03161
--- /dev/null
+++ b/hubs/views/root.py
@@ -0,0 +1,73 @@
+from __future__ import unicode_literals, absolute_import
+
+import flask
+import hubs.models
+
+from hubs.app import app, session, OIDC
+from .utils import authenticated, is_safe_url
+
+
+@app.route('/')
+def index():
+    if not authenticated():
+        return flask.redirect(flask.url_for('login'))
+
+    return flask.redirect(flask.url_for('stream', name=flask.g.auth.nickname))
+
+
+@app.route('/groups')
+def groups():
+    if not authenticated():
+        return flask.redirect(flask.url_for('login'))
+
+    # Get the list of promoted and non-promoted group hubs from the DB
+    promoted_names = app.config.get('PROMOTED_GROUPS')
+    groups = hubs.models.Hub.all_group_hubs(flask.g.db)
+    promoted = [g for g in groups if g.name in promoted_names]
+    secondary = [g for g in groups if g.name not in promoted_names]
+
+    name_of_the_month = app.config.get('HUB_OF_THE_MONTH')
+    hub_of_the_month = hubs.models.Hub.by_name(flask.g.db, name_of_the_month)
+
+    return flask.render_template(
+        'groups.html',
+        promoted=promoted,
+        secondary=secondary,
+        hub_of_the_month=hub_of_the_month,
+    )
+
+
+@app.route('/login/', methods=('GET', 'POST'))
+@app.route('/login', methods=('GET', 'POST'))
+@OIDC.require_login
+def login():
+    default = flask.url_for('index')
+    next_url = flask.request.args.get('next', default)
+    if is_safe_url(next_url):
+        return_point = next_url
+    else:
+        return_point = default
+
+    hubs.models.User.get_or_create(
+        flask.g.db, username=flask.g.auth.nickname, fullname=flask.g.auth.fullname)
+
+    return flask.redirect(return_point)
+
+
+@app.route('/logout/')
+@app.route('/logout')
+def logout():
+    next_url = flask.url_for('index')
+    if 'next' in flask.request.values:  # pragma: no cover
+        if is_safe_url(flask.request.args['next']):
+            next_url = flask.request.values['next']
+
+    if next_url == flask.url_for('login'):  # pragma: no cover
+        next_url = flask.url_for('index')
+
+    if authenticated():
+        OIDC.logout()
+        flask.session.auth = None
+        flask.flash('You have been logged out')
+
+    return flask.redirect(next_url)
diff --git a/hubs/views/user.py b/hubs/views/user.py
new file mode 100644
index 0000000..cab84ed
--- /dev/null
+++ b/hubs/views/user.py
@@ -0,0 +1,100 @@
+from __future__ import unicode_literals, absolute_import
+
+import flask
+import json
+import hubs.models
+import hubs.stream
+
+from hubs.app import app, session
+from .utils import login_required, get_hub
+
+
+@app.route('/<name>/stream')
+@app.route('/<name>/stream/')
+@login_required
+def stream(name):
+    hub = get_hub(name)
+    saved = hubs.models.SavedNotification.by_username(flask.g.db, name)
+    saved = [n.__json__() for n in saved]
+
+    stream = hubs.stream.Stream()
+    actions = stream.get_json()
+
+    return flask.render_template(
+        'stream.html',
+        hub=hub,
+        saved=json.dumps(saved),
+        actions=actions
+    )
+
+
+@app.route('/<user>/notifications', methods=['GET', 'POST'])
+@app.route('/<user>/notifications/', methods=['GET', 'POST'])
+@login_required
+def notifications(user):
+    if flask.request.method == 'GET':
+        notifications = hubs.models.SavedNotification.by_username(flask.g.db, user)
+        notifications = [n.__json__() for n in notifications]
+        return flask.jsonify(notifications)
+
+    if flask.request.method == 'POST':
+        data = flask.request.get_json()
+        user = hubs.models.User.by_username(flask.g.db, user)
+        if not user:
+            return flask.abort(400)
+        try:
+            markup = data['markup']
+            link = data['link']
+            icon = data['secondary_icon']
+            dom_id = data['dom_id']
+        except:
+            return flask.abort(400)
+        notification = hubs.models.SavedNotification(
+            username=user.username,
+            markup=markup,
+            link=link,
+            secondary_icon=icon,
+            dom_id=dom_id
+        )
+        flask.g.db.add(notification)
+        flask.g.db.commit()
+        return flask.jsonify(
+            dict(notification=notification.__json__(), success=True)
+        )
+
+@app.route('/<user>/notifications/<int:idx>', methods=['DELETE'])
+@app.route('/<user>/notifications/<int:idx>/', methods=['DELETE'])
+@login_required
+def delete_notifications(user, idx):
+    notification = flask.g.db.query(hubs.models.SavedNotification).filter_by(idx=idx).first()
+    if not notification:
+        return flask.abort(400)
+    flask.g.db.delete(notification)
+    flask.g.db.commit()
+    return flask.jsonify(dict(status_code=200))
+@app.route('/visit/<visited_hub>/', methods=['GET', 'POST'])
+@app.route('/visit/<visited_hub>', methods=['GET', 'POST'])
+@login_required
+def increment_counter(visited_hub):
+    nickname = flask.g.auth.nickname
+
+    if str(visited_hub) != str(nickname):
+        try:
+            vc = hubs.models.VisitCounter.get_or_create(session=flask.g.db,
+                                                        username=nickname,
+                                                        visited_hub=visited_hub)
+        except ValueError:  # this should never trip
+            # flask will 405 if visited_hub is blank
+            # @login_required forces flask.g.auth to be sets
+            flask.abort(404)
+        if flask.request.method == 'POST':
+            vc.increment_visits(session=flask.g.db,
+                                username=nickname,
+                                visited_hub=visited_hub)
+
+            return flask.jsonify({'count': vc.count})
+
+        elif flask.request.method == 'GET':
+            return flask.jsonify({'count': vc.count})
+    else:
+        return flask.abort(403)
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
new file mode 100644
index 0000000..e2d4bd2
--- /dev/null
+++ b/hubs/views/utils.py
@@ -0,0 +1,74 @@
+from __future__ import unicode_literals
+
+import flask
+import functools
+import hubs.models
+import hubs.widgets
+
+from six.moves.urllib import parse as urlparse
+from sqlalchemy.orm.exc import NoResultFound
+
+
+def get_hub(name, session=None):
+    """ Utility shorthand to get a hub and 404 if not found. """
+    if session is None:
+        session = flask.g.db
+    try:
+        return session.query(hubs.models.Hub).filter(
+            hubs.models.Hub.name == name).one()
+    except NoResultFound:
+        flask.abort(404)
+
+
+def get_widget(hub, idx, session=None):
+    """ Utility shorthand to get a widget and 404 if not found. """
+    if session is None:
+        session = flask.g.db
+    try:
+        idx = int(idx)
+    except (TypeError, ValueError):
+        flask.abort(400)
+    try:
+        return session.query(
+                hubs.models.Widget
+            ).join(hubs.models.Hub).filter(
+                hubs.models.Hub.name == hub,
+                hubs.models.Widget.idx == idx,
+            ).one()
+    except NoResultFound:
+        flask.abort(404)
+
+
+def authenticated():
+    """ Utility function checking if the current auth is set or not."""
+    return hasattr(flask.g, 'auth') \
+        and flask.g.auth is not None \
+        and flask.g.auth.logged_in
+
+
+def login_required(function):
+    """ Flask decorator to restrict access to logged-in users. """
+
+    @functools.wraps(function)
+    def decorated_function(*args, **kwargs):
+        """ Decorated function, actually does the work. """
+        if not authenticated():
+            flask.flash('Login required', 'errors')
+            return flask.redirect(flask.url_for(
+                'login', next=flask.request.url))
+
+        return function(*args, **kwargs)
+
+    return decorated_function
+
+
+def is_safe_url(target):
+    """ Checks that the target url is safe and sending to the current
+    website not some other malicious one.
+    """
+    ref_url = urlparse.urlparse(flask.request.host_url)
+    test_url = urlparse.urlparse(
+        urlparse.urljoin(flask.request.host_url, target))
+    return test_url.scheme in ('http', 'https') and \
+        ref_url.netloc == test_url.netloc
+
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
new file mode 100644
index 0000000..d40ff3f
--- /dev/null
+++ b/hubs/views/widget.py
@@ -0,0 +1,109 @@
+from __future__ import unicode_literals, absolute_import
+
+import datetime
+import flask
+
+from hubs.app import app, session
+from .utils import get_widget
+
+
+@app.route('/<hub>/<int:idx>/')
+@app.route('/<hub>/<int:idx>')
+def widget_render(hub, idx):
+    widget = get_widget(hub, idx)
+    return widget.render(flask.g.db)  # , edit=False)
+    # was blocking all widgets from working, sorry!
+
+
+@app.route('/<hub>/<int:idx>/json')
+@app.route('/<hub>/<int:idx>/json/')
+def widget_json(hub, idx):
+    widget = get_widget(hub, idx)
+    response = flask.jsonify(widget.__json__(flask.g.db))
+    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
+    return response
+
+
+@app.route('/<hub>/<int:idx>/edit/', methods=['GET', 'POST'])
+@app.route('/<hub>/<int:idx>/edit', methods=['GET', 'POST'])
+def widget_edit(hub, idx):
+    if flask.request.method == 'POST':
+        return widget_edit_post(hub, idx)
+    else:
+        return widget_edit_get(hub, idx)
+
+
+def widget_edit_get(hub, idx):
+    widget = get_widget(hub, idx)
+    return flask.render_template(
+        'edit.html',
+        hub=hub,
+        widget=widget,
+        url_to=flask.url_for('widget_edit', hub=hub, idx=idx)
+    )
+
+
+def widget_edit_post(hub, idx):
+    widget = get_widget(hub, idx)
+    error = False
+    config = {}
+    for arg in widget.module.data.widget_arguments:
+        val = flask.request.form.get(arg.name)
+        if not val:
+            flask.flash(
+                'You must provide a value for: %s' % arg.name, 'error')
+            error = True
+            break
+        try:
+            val = arg.validator(flask.g.db, val)
+            config[arg.name] = val
+        except Exception as err:
+            flask.flash('Invalid data provided, error: %s' % err, 'error')
+            error = True
+    if not error:
+        cur_config = widget.config
+        cur_config.update(config)
+        widget.config = cur_config
+        widget.hub.last_edited = datetime.datetime.utcnow()
+        flask.g.db.add(widget)
+        try:
+            flask.g.db.commit()
+        except Exception as err:
+            flask.flash(
+                'Could not save the configuration to the database '
+                'if the error persists, please warn an admin',
+                'error')
+    return flask.redirect(flask.url_for('hub', name=hub))
+
+
+@app.route('/<hub>/<int:idx>/delete/', methods=['POST'])
+@app.route('/<hub>/<int:idx>/delete', methods=['POST'])
+def widget_edit_delete(hub, idx):
+    ''' Remove a widget from a hub. '''
+    widget = get_widget(hub, idx)
+    flask.g.db.delete(widget)
+    try:
+        flask.g.db.commit()
+    except Exception as err:
+        flask.flash(
+            'Could not delete this widget from this hub in the database '
+            'if the error persists, please warn an admin',
+            'error')
+    return flask.redirect(flask.url_for('hub_edit', name=hub))
+
+
+@app.route('/source/<name>/')
+@app.route('/source/<name>')
+def widget_source(name):
+    from hubs.widgets import registry
+    base = '/hubs/'
+    fname = ''
+
+    try:
+        fname = base + registry[name].__file__.split(base)[-1]
+    except KeyError:
+        flask.abort(404)
+
+    fname = fname.replace('.pyc', '.py')
+    return flask.redirect(app.config.get('SOURCE_URL') + fname)
+

From 8bd1aa1d4d6af5616977bb4b7f9a9f47e942c921 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jan 31 2017 18:25:56 +0000
Subject: [PATCH 683/1001] Protect widget views against uninitialized DB


---

diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
index 13fb79c..f39cc0c 100644
--- a/hubs/views/__init__.py
+++ b/hubs/views/__init__.py
@@ -14,6 +14,7 @@ from .plus_plus import *
 import flask
 import functools
 import hubs.models
+from sqlalchemy.exc import OperationalError
 from sqlalchemy.orm.exc import NoResultFound
 from hubs.app import app, session
 from .utils import get_widget
@@ -34,13 +35,19 @@ def _widget_view_decorator(func):
         return func(session, widget, *args, **kwargs)
     return inner
 
-for widget in session.query(hubs.models.Widget):
-    for params in getattr(widget.module, 'ROUTES', []):
-        params["rule"] = "/<hub>/<int:idx>/widget/" \
-                         + params["rule"].lstrip("/")
-        if not params.get("endpoint"):
-            params["endpoint"] = params["view_func_name"]
-        params["endpoint"] = "%s_%s" % (widget.plugin, params["endpoint"])
-        params["view_func"] = _widget_view_decorator(
-            getattr(widget.module, params.pop("view_func_name")))
-        app.add_url_rule(**params)
+def _load_widget_views():
+    for widget in session.query(hubs.models.Widget):
+        for params in getattr(widget.module, 'ROUTES', []):
+            params["rule"] = "/<hub>/<int:idx>/widget/" \
+                             + params["rule"].lstrip("/")
+            if not params.get("endpoint"):
+                params["endpoint"] = params["view_func_name"]
+            params["endpoint"] = "%s_%s" % (widget.plugin, params["endpoint"])
+            params["view_func"] = _widget_view_decorator(
+                getattr(widget.module, params.pop("view_func_name")))
+            app.add_url_rule(**params)
+
+try:
+    _load_widget_views()
+except OperationalError:
+    pass  # Maybe the DB is not yet initialized (tests).

From 37bd81d6edc500b8904d3463d0044c5b402e5042 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 01 2017 17:30:36 +0000
Subject: [PATCH 684/1001] Use the registry to discover widget routes


---

diff --git a/hubs/tests/test_widget_routes.py b/hubs/tests/test_widget_routes.py
new file mode 100644
index 0000000..be03bd8
--- /dev/null
+++ b/hubs/tests/test_widget_routes.py
@@ -0,0 +1,67 @@
+from __future__ import unicode_literals
+
+import hubs.widgets
+
+from mock import Mock
+from hubs.models import Hub, Widget
+from hubs.tests import APPTest
+
+class WidgetRoutesTest(APPTest):
+
+    def setUp(self):
+        super(WidgetRoutesTest, self).setUp()
+        # Backup the URL map
+        self._old_url_map = (
+            self.app.application.url_map._rules.copy(),
+            self.app.application.url_map._rules_by_endpoint.copy()
+            )
+
+    def tearDown(self):
+        for module in hubs.widgets.registry.values():
+            if hasattr(module, 'ROUTES'):
+                delattr(module, 'ROUTES')
+        # Restore the URL map
+        self.app.application.url_map._rules = self._old_url_map[0]
+        self.app.application.url_map._rules_by_endpoint = self._old_url_map[1]
+        super(WidgetRoutesTest, self).tearDown()
+
+    def test_routes_variable(self):
+        mock_view = Mock(return_value='')
+        hubs.widgets.contact.mock_view = mock_view
+        hubs.widgets.contact.ROUTES = [{
+            'rule': 'dummy-url',
+            'endpoint': 'dummy-endpoint',
+            'view_func_name': 'mock_view',
+        }]
+        hubs.views._load_widget_views()
+        added_rules = list(
+            self.app.application.url_map.iter_rules(
+                endpoint='contact_dummy-endpoint')
+            )
+        self.assertEqual(len(added_rules), 1)
+        self.assertEqual(
+            added_rules[0].rule,
+            '/<hub>/<int:idx>/widget/dummy-url'
+            )
+        widget = self.session.query(Widget).filter_by(
+            plugin="contact").first()
+        self.app.get('/%s/%s/widget/dummy-url'
+                     % (widget.hub.name, widget.idx))
+        self.assertTrue(mock_view.called)
+        call = mock_view.call_args_list[0]
+        # Check arguments: session and widget
+        self.assertEqual(call[0][0].__class__, self.session.__class__)
+        self.assertEqual(call[0][1], widget)
+
+    def test_decorator(self):
+        mock_view = Mock(return_value='')
+        mock_view.__name__ = 'mock_view'
+        mock_view.__module__ = 'hubs.widgets.feed'
+        hubs.widgets.feed.mock_view = hubs.widgets.base.widget_route(
+            rule='dummy-url', endpoint='dummy-endpoint')(mock_view)
+        self.assertEqual(
+            hubs.widgets.feed.ROUTES,
+            [{'view_func_name': 'mock_view',
+              'endpoint': 'dummy-endpoint',
+              'rule': 'dummy-url'}]
+            )
diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
index f39cc0c..f388470 100644
--- a/hubs/views/__init__.py
+++ b/hubs/views/__init__.py
@@ -14,7 +14,7 @@ from .plus_plus import *
 import flask
 import functools
 import hubs.models
-from sqlalchemy.exc import OperationalError
+import hubs.widgets
 from sqlalchemy.orm.exc import NoResultFound
 from hubs.app import app, session
 from .utils import get_widget
@@ -31,23 +31,21 @@ def _widget_view_decorator(func):
     def inner(*args, **kwargs):
         hubname = kwargs.pop("hub")
         widgetidx = kwargs.pop("idx")
-        widget = get_widget(hubname, widgetidx, session=session)
+        widget = get_widget(hubname, widgetidx)
         return func(session, widget, *args, **kwargs)
     return inner
 
 def _load_widget_views():
-    for widget in session.query(hubs.models.Widget):
-        for params in getattr(widget.module, 'ROUTES', []):
+    for name, module in hubs.widgets.registry.items():
+        #print(module, hasattr(module, 'ROUTES'))
+        for params in getattr(module, 'ROUTES', []):
             params["rule"] = "/<hub>/<int:idx>/widget/" \
                              + params["rule"].lstrip("/")
             if not params.get("endpoint"):
                 params["endpoint"] = params["view_func_name"]
-            params["endpoint"] = "%s_%s" % (widget.plugin, params["endpoint"])
+            params["endpoint"] = "%s_%s" % (name, params["endpoint"])
             params["view_func"] = _widget_view_decorator(
-                getattr(widget.module, params.pop("view_func_name")))
+                getattr(module, params.pop("view_func_name")))
             app.add_url_rule(**params)
 
-try:
-    _load_widget_views()
-except OperationalError:
-    pass  # Maybe the DB is not yet initialized (tests).
+_load_widget_views()

From 319c1f4c59b4174084673c47db2dfb7757cb49fc Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 01 2017 17:53:18 +0000
Subject: [PATCH 685/1001] Fixup the last commit (sorry)


---

diff --git a/hubs/tests/test_widget_routes.py b/hubs/tests/test_widget_routes.py
index be03bd8..7eae714 100644
--- a/hubs/tests/test_widget_routes.py
+++ b/hubs/tests/test_widget_routes.py
@@ -12,7 +12,7 @@ class WidgetRoutesTest(APPTest):
         super(WidgetRoutesTest, self).setUp()
         # Backup the URL map
         self._old_url_map = (
-            self.app.application.url_map._rules.copy(),
+            self.app.application.url_map._rules[:],
             self.app.application.url_map._rules_by_endpoint.copy()
             )
 
@@ -26,7 +26,11 @@ class WidgetRoutesTest(APPTest):
         super(WidgetRoutesTest, self).tearDown()
 
     def test_routes_variable(self):
-        mock_view = Mock(return_value='')
+        calls = []
+        def mock_view(*args, **kw):
+            calls.append({'args': args, 'kw': kw})
+            return ''
+        mock_view.__module__ = 'hubs.widgets.contact'
         hubs.widgets.contact.mock_view = mock_view
         hubs.widgets.contact.ROUTES = [{
             'rule': 'dummy-url',
@@ -47,15 +51,14 @@ class WidgetRoutesTest(APPTest):
             plugin="contact").first()
         self.app.get('/%s/%s/widget/dummy-url'
                      % (widget.hub.name, widget.idx))
-        self.assertTrue(mock_view.called)
-        call = mock_view.call_args_list[0]
+        self.assertEqual(len(calls), 1)
         # Check arguments: session and widget
-        self.assertEqual(call[0][0].__class__, self.session.__class__)
-        self.assertEqual(call[0][1], widget)
+        self.assertEqual(calls[0]["args"][0].__class__, self.session.__class__)
+        self.assertEqual(calls[0]["args"][1], widget)
 
     def test_decorator(self):
-        mock_view = Mock(return_value='')
-        mock_view.__name__ = 'mock_view'
+        def mock_view(*args, **kw):
+            return ''
         mock_view.__module__ = 'hubs.widgets.feed'
         hubs.widgets.feed.mock_view = hubs.widgets.base.widget_route(
             rule='dummy-url', endpoint='dummy-endpoint')(mock_view)
diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
index f388470..54f6bd1 100644
--- a/hubs/views/__init__.py
+++ b/hubs/views/__init__.py
@@ -37,7 +37,6 @@ def _widget_view_decorator(func):
 
 def _load_widget_views():
     for name, module in hubs.widgets.registry.items():
-        #print(module, hasattr(module, 'ROUTES'))
         for params in getattr(module, 'ROUTES', []):
             params["rule"] = "/<hub>/<int:idx>/widget/" \
                              + params["rule"].lstrip("/")

From 7751a52b943f3243c85e5933926e1398e00303b9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 01 2017 18:05:50 +0000
Subject: [PATCH 686/1001] Use tox to run the tests


Tests can be run on different versions of Python.

---

diff --git a/.gitignore b/.gitignore
index 357e7b0..b3b67a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,7 @@ Vagrantfile
 *.retry
 *.pem
 config
+
+# tox
+.tox
+.coverage
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000..e35d885
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1 @@
+_build
diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
index 715315b..2617a29 100644
--- a/docs/dev-guide.rst
+++ b/docs/dev-guide.rst
@@ -200,29 +200,18 @@ code, to make sure that nothing is broken before you start.  And you should run
 it after you finish your change, before you push, to verify that your change
 didn't inadvertently break something else.
 
-You can run it with::
+To run the test, you need to install Tox with the command::
 
-    $ pip install -r test-requirements.txt
-    $ ./runtest.sh
+    $ pip install tox
 
+Then you can run the tests with::
 
+    $ tox --skip-missing-interpreters
 
-If the unit tests are all failing and returning errors like this::
+It will run the Python tests with the supported versions you have on your
+system, and it will also run the Javascript tests and try building the
+documentation. It will report the error if any of those steps fail.
 
-    ImportError: cannot import name dummy
-
-
-It most likely is a result of html5lib breaking api stability. Please downgrade to the version below::
-
-    pip install html5lib==0.9999999
-
-
-See the options available with::
-
-    $ ./runtest.sh --help
-
-You can run the JavaScript tests from ``hubs/static/client`` with::
-    $ npm test
 
 Some credentials...
 -------------------
diff --git a/requirements.txt b/requirements.txt
index d8d0088..092bd82 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,7 +11,7 @@ flask-oidc>=1.0.3
 fmn.lib
 fmn.rules
 gunicorn
-html5lib
+html5lib==0.9999999
 munch
 psycopg2
 pytz
diff --git a/runtest.sh b/runtest.sh
index 87fd265..cac5a69 100755
--- a/runtest.sh
+++ b/runtest.sh
@@ -1,6 +1,3 @@
 #!/bin/bash
 
-. ~/.virtualenvs/hubs/bin/activate || /bin/bash ./setup_python_test_env.sh
-
-HUBS_CONFIG=`pwd`/hubs/tests/hubs_test.cfg PYTHONPATH=. ./nosetests \
-    --with-coverage --cover-erase --cover-package=hubs $*
+tox --skip-missing-interpreters
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..37dd0c2
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,51 @@
+[tox]
+envlist = py{27,34,35},js,docs
+skipsdist = True
+
+
+[testenv]
+basepython = python2
+usedevelop = True
+deps =
+    -rrequirements.txt
+    -rtest-requirements.txt
+setenv =
+    HUBS_CONFIG={toxinidir}/hubs/tests/hubs_test.cfg
+    PYTHONPATH={toxinidir}
+whitelist_externals =
+    rm
+commands =
+    rm -f /var/tmp/fedora-hubs-cache.db*
+    nosetests --with-coverage --cover-erase --cover-package=hubs {posargs:hubs}
+
+[testenv:js]
+skip_install = True
+usedevelop = False
+deps =
+whitelist_externals =
+    npm
+changedir = {toxinidir}/hubs/static/client
+commands =
+    npm install
+    npm test
+
+[testenv:docs]
+changedir = docs
+deps = sphinx
+whitelist_externals =
+    mkdir
+commands=
+    mkdir -p _static
+    sphinx-build -W -b html -d {envtmpdir}/doctrees .  _build/html
+
+
+[testenv:lint]
+deps =
+    flake8 > 3.0
+commands =
+    python -m flake8 {posargs}
+
+
+[flake8]
+show-source = True
+exclude = .git,.tox,dist,*egg,doc

From e40c7b1b69b46b0ef9e3cc5f6873185fb004025f Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Feb 01 2017 19:44:46 +0000
Subject: [PATCH 687/1001] Merge #304 `Add a license to the git repository`


---

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..dba13ed
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU Affero General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.

From e7a60fb82d6326cc55db179e2de3af3201c1de21 Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Feb 01 2017 23:55:27 +0000
Subject: [PATCH 688/1001] Merge #309 `Use tox to run the tests`


---

diff --git a/.gitignore b/.gitignore
index 357e7b0..b3b67a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,7 @@ Vagrantfile
 *.retry
 *.pem
 config
+
+# tox
+.tox
+.coverage
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000..e35d885
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1 @@
+_build
diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
index 715315b..2617a29 100644
--- a/docs/dev-guide.rst
+++ b/docs/dev-guide.rst
@@ -200,29 +200,18 @@ code, to make sure that nothing is broken before you start.  And you should run
 it after you finish your change, before you push, to verify that your change
 didn't inadvertently break something else.
 
-You can run it with::
+To run the test, you need to install Tox with the command::
 
-    $ pip install -r test-requirements.txt
-    $ ./runtest.sh
+    $ pip install tox
 
+Then you can run the tests with::
 
+    $ tox --skip-missing-interpreters
 
-If the unit tests are all failing and returning errors like this::
+It will run the Python tests with the supported versions you have on your
+system, and it will also run the Javascript tests and try building the
+documentation. It will report the error if any of those steps fail.
 
-    ImportError: cannot import name dummy
-
-
-It most likely is a result of html5lib breaking api stability. Please downgrade to the version below::
-
-    pip install html5lib==0.9999999
-
-
-See the options available with::
-
-    $ ./runtest.sh --help
-
-You can run the JavaScript tests from ``hubs/static/client`` with::
-    $ npm test
 
 Some credentials...
 -------------------
diff --git a/requirements.txt b/requirements.txt
index d8d0088..092bd82 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,7 +11,7 @@ flask-oidc>=1.0.3
 fmn.lib
 fmn.rules
 gunicorn
-html5lib
+html5lib==0.9999999
 munch
 psycopg2
 pytz
diff --git a/runtest.sh b/runtest.sh
index 87fd265..cac5a69 100755
--- a/runtest.sh
+++ b/runtest.sh
@@ -1,6 +1,3 @@
 #!/bin/bash
 
-. ~/.virtualenvs/hubs/bin/activate || /bin/bash ./setup_python_test_env.sh
-
-HUBS_CONFIG=`pwd`/hubs/tests/hubs_test.cfg PYTHONPATH=. ./nosetests \
-    --with-coverage --cover-erase --cover-package=hubs $*
+tox --skip-missing-interpreters
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..37dd0c2
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,51 @@
+[tox]
+envlist = py{27,34,35},js,docs
+skipsdist = True
+
+
+[testenv]
+basepython = python2
+usedevelop = True
+deps =
+    -rrequirements.txt
+    -rtest-requirements.txt
+setenv =
+    HUBS_CONFIG={toxinidir}/hubs/tests/hubs_test.cfg
+    PYTHONPATH={toxinidir}
+whitelist_externals =
+    rm
+commands =
+    rm -f /var/tmp/fedora-hubs-cache.db*
+    nosetests --with-coverage --cover-erase --cover-package=hubs {posargs:hubs}
+
+[testenv:js]
+skip_install = True
+usedevelop = False
+deps =
+whitelist_externals =
+    npm
+changedir = {toxinidir}/hubs/static/client
+commands =
+    npm install
+    npm test
+
+[testenv:docs]
+changedir = docs
+deps = sphinx
+whitelist_externals =
+    mkdir
+commands=
+    mkdir -p _static
+    sphinx-build -W -b html -d {envtmpdir}/doctrees .  _build/html
+
+
+[testenv:lint]
+deps =
+    flake8 > 3.0
+commands =
+    python -m flake8 {posargs}
+
+
+[flake8]
+show-source = True
+exclude = .git,.tox,dist,*egg,doc

From ff3369dd1b85742a9c3d0508c5e5c31e14f4220d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 05 2017 11:01:11 +0000
Subject: [PATCH 689/1001] Use SQLA's query_attribute, it saves a lot of passing around


---

diff --git a/delete-user.py b/delete-user.py
index 42a17c1..8c54582 100755
--- a/delete-user.py
+++ b/delete-user.py
@@ -18,14 +18,14 @@ session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 username = raw_input('What user do you want to delete: ')
 openid = '%s.id.fedoraproject.org' % username
 print "Looking for account %r" % openid
-user = hubs.models.User.get(session, openid)
+user = hubs.models.User.get(openid)
 if not user:
     print "No such user %r" % openid
 else:
     print "Found %r.  Deleting." % user
     session.delete(user)
 
-hub = hubs.models.Hub.get(session, username)
+hub = hubs.models.Hub.get(username)
 if not hub:
     print "No such hub %r" % username
 else:
diff --git a/hubs/app.py b/hubs/app.py
index 006edea..702175a 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -99,7 +99,7 @@ def check_auth():
             flask.session.auth.avatar=username2avatar(
                 flask.session.auth.nickname)
             flask.session.auth.user = hubs.models.User.by_username(
-                session, flask.session.auth.nickname)
+                flask.session.auth.nickname)
         flask.g.auth = flask.session.auth
     else:
         flask.g.auth = munch.Munch(logged_in=False)
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index abc1b32..b4af706 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -46,7 +46,7 @@ log = logging.getLogger('hubs.backend.worker')
 
 def work(session, widget_idx):
     # Get a real widget, because we update last_refreshed on it.
-    widget = hubs.models.Widget.by_idx(session, widget_idx)
+    widget = hubs.models.Widget.by_idx(widget_idx)
     log.info("! Invalidating cache for %r" % widget)
     # Invalidate the cache...
     hubs.widgets.base.invalidate_cache(widget, **widget.config)
diff --git a/hubs/models.py b/hubs/models.py
index cdc02de..63fbcb1 100755
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -37,6 +37,7 @@ from sqlalchemy.orm import sessionmaker
 from sqlalchemy.orm import scoped_session
 from sqlalchemy.orm import relation
 from sqlalchemy.orm import backref
+from sqlalchemy.orm.session import object_session
 
 import fedmsg
 import fedmsg.utils
@@ -91,8 +92,9 @@ def init(db_url, debug=False, create=False):
 
     if create:
         BASE.metadata.create_all(engine)
-
-    return scoped_session(sessionmaker(bind=engine))
+    session = scoped_session(sessionmaker(bind=engine))
+    BASE.query = session.query_property()
+    return session
 
 
 roles = ['subscriber', 'member', 'owner', 'stargazer']
@@ -113,8 +115,8 @@ class Association(BASE):
     hub = relation("Hub", backref=backref('associations', cascade="all, delete"))
 
     @classmethod
-    def get(cls, session, hub, user, role):
-        return session.query(cls)\
+    def get(cls, hub, user, role):
+        return cls.query\
             .filter_by(hub=hub)\
             .filter_by(user=user)\
             .filter_by(role=role)\
@@ -164,7 +166,7 @@ class Hub(BASE):
 
     @classmethod
     def get_or_create(cls, session, name, summary, **extra):
-        self = cls.by_name(session, name)
+        self = cls.by_name(name)
         if not self:
             self = cls.create_group_hub(session, name, summary, **extra)
             session.add(self)
@@ -191,20 +193,22 @@ class Hub(BASE):
         return [assoc.user for assoc in self.associations
                 if assoc.role == 'stargazer']
 
-    def subscribe(self, session, user, role='subscriber'):
+    def subscribe(self, user, role='subscriber'):
         """ Subscribe a user to this hub. """
         # TODO -- add logic here to manage not adding the user multiple
         # times, doing different roles, etc.. publish a fedmsg message,
         # etc...
+        session = object_session(self)
         session.add(Association(user=user, hub=self, role=role))
         session.commit()
 
-    def unsubscribe(self, session, user, role='subscriber'):
+    def unsubscribe(self, user, role='subscriber'):
         """ Subscribe a user to this hub. """
         # TODO -- add logic here to manage not adding the user multiple
         # times, doing different roles, etc.. publish a fedmsg message,
         # etc...
-        association = Association.get(session, hub=self, user=user, role=role)
+        session = object_session(self)
+        association = Association.get(hub=self, user=user, role=role)
         if not association:
             raise KeyError("%r is not a %r of %r" % (user, role, self))
         session.delete(association)
@@ -214,18 +218,18 @@ class Hub(BASE):
         return user in self.owners
 
     @classmethod
-    def by_name(cls, session, name):
-        return session.query(cls).filter_by(name=name).first()
+    def by_name(cls, name):
+        return cls.query.filter_by(name=name).first()
 
     get = by_name
 
     @classmethod
-    def all_group_hubs(cls, session):
-        return session.query(cls).filter_by(user_hub=False).all()
+    def all_group_hubs(cls):
+        return cls.query.filter_by(user_hub=False).all()
 
     @classmethod
-    def all_user_hubs(cls, session):
-        return session.query(cls).filter_by(user_hub=True).all()
+    def all_user_hubs(cls):
+        return cls.query.filter_by(user_hub=True).all()
 
     @classmethod
     def create_user_hub(cls, session, username, fullname):
@@ -236,8 +240,8 @@ class Hub(BASE):
 
         hubs.defaults.add_user_widgets(session, hub, username, fullname)
 
-        user = User.by_username(session, username)
-        hub.subscribe(session, user, role='owner')
+        user = User.by_username(username)
+        hub.subscribe(user, role='owner')
         return hub
 
     @classmethod
@@ -272,7 +276,7 @@ class Hub(BASE):
         """Returns the list of indices for this hub's widgets."""
         return [w.idx for w in self.widgets]
 
-    def __json__(self, session):
+    def __json__(self):
         return {
             'name': self.name,
             'summary': self.summary,
@@ -306,16 +310,16 @@ class Widget(BASE):
     left = sa.Column(sa.Boolean, nullable=False, default=False)
 
     @classmethod
-    def by_idx(cls, session, idx):
-        return session.query(cls).filter_by(idx=idx).first()
+    def by_idx(cls, idx):
+        return cls.query.filter_by(idx=idx).first()
 
     @classmethod
-    def by_plugin(cls, session, plugin):
-        return session.query(cls).filter_by(plugin=plugin).first()
+    def by_plugin(cls, plugin):
+        return cls.query.filter_by(plugin=plugin).first()
 
     @classmethod
-    def by_hub_id_all(cls, session, hub_id):
-        return session.query(cls).filter_by(hub_id=hub_id).all()
+    def by_hub_id_all(cls, hub_id):
+        return cls.query.filter_by(hub_id=hub_id).all()
 
     get = by_idx
 
@@ -327,7 +331,8 @@ class Widget(BASE):
     def config(self, config):
         self._config = json.dumps(config)
 
-    def __json__(self, session):
+    def __json__(self):
+        session = object_session(self)
         module = hubs.widgets.registry[self.plugin]
         data = module.data(session, self, **self.config)
         data.pop('widget', None)
@@ -350,7 +355,8 @@ class Widget(BASE):
     def module(self):
         return hubs.widgets.registry[self.plugin]
 
-    def render(self, session):
+    def render(self):
+        session = object_session(self)
         render = hubs.widgets.render
         return render(self.module, session, self, **self.config)
 
@@ -363,7 +369,7 @@ class User(BASE):
     saved_notifications = relation('SavedNotification', backref='users',
                                        lazy='dynamic')
 
-    def __json__(self, session):
+    def __json__(self):
         return {
             'username': self.username,
             'avatar': username2avatar(self.username),
@@ -405,25 +411,25 @@ class User(BASE):
         ])), key=operator.attrgetter('name'))
 
     @classmethod
-    def by_username(cls, session, username):
-        return session.query(cls).filter_by(username=username).first()
+    def by_username(cls, username):
+        return cls.query.filter_by(username=username).first()
 
     get = by_username
 
     @classmethod
-    def all(cls, session):
-        return session.query(cls).all()
+    def all(cls):
+        return cls.query.all()
 
     @classmethod
     def get_or_create(cls, session, username, fullname):
         if not username:
             raise ValueError("Must provide an username, not %r" % username)
 
-        self = cls.by_username(session, username)
+        self = cls.by_username(username)
         if not self:
             self = cls(username=username, fullname=fullname)
             session.add(self)
-            if not Hub.by_name(session, self.username):
+            if not Hub.by_name(self.username):
                 Hub.create_user_hub(session, self.username, self.fullname)
 
             session.commit()
@@ -446,12 +452,12 @@ class VisitCounter(BASE):
     hub = relation("Hub", backref=backref('visit_counters', cascade="all, delete, delete-orphan"))
 
     @classmethod
-    def by_username(cls, session, username):
-        return session.query(cls).filter_by(username=username).all()
+    def by_username(cls, username):
+        return cls.query.filter_by(username=username).all()
 
     @classmethod
-    def get_visits_by_username_hub(cls, session, username, visited_hub):
-        return session.query(cls).filter_by(username=username, visited_hub=visited_hub).first()
+    def get_visits_by_username_hub(cls, username, visited_hub):
+        return cls.query.filter_by(username=username, visited_hub=visited_hub).first()
 
     @classmethod
     def increment_visits(cls, session, username, visited_hub):
@@ -480,7 +486,7 @@ class VisitCounter(BASE):
                 or not cls._does_user_exist(session, user=username):
             raise ValueError("Must provide a hub/user that exists")
 
-        self = cls.get_visits_by_username_hub(session, username=username,
+        self = cls.get_visits_by_username_hub(username=username,
                                               visited_hub=visited_hub)
         if not self:
             self = cls(username=username, visited_hub=visited_hub)
@@ -521,9 +527,9 @@ class SavedNotification(BASE):
         }
 
     @classmethod
-    def by_username(cls, session, username):
-        return session.query(cls).filter_by(user=username).all()
+    def by_username(cls, username):
+        return cls.query.filter_by(user=username).all()
 
     @classmethod
-    def all(cls, session):
-        return session.query(cls).all()
+    def all(cls):
+        return cls.query.all()
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index b1e182f..59866ee 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -58,7 +58,7 @@ class APPTest(unittest.TestCase):
 
         hubs.app.session.flush()
 
-        hub = hubs.models.Hub.by_name(hubs.app.session, 'ralph')
+        hub = hubs.models.Hub.by_name('ralph')
         widget = hubs.models.Widget(
             plugin='about',
             index=500,
@@ -82,7 +82,7 @@ class APPTest(unittest.TestCase):
     # TODO - test that it has all the things it needs
 
     def widget_instance(self, hubname, plugin):
-        hub = hubs.models.Hub.by_name(self.session, hubname)
+        hub = hubs.models.Hub.by_name(hubname)
         if not hub:
             raise ValueError("No such hub %r" % hubname)
         for widget in hub.widgets:
diff --git a/hubs/tests/test_api/test_hub.py b/hubs/tests/test_api/test_hub.py
index 821746c..622fd9d 100644
--- a/hubs/tests/test_api/test_hub.py
+++ b/hubs/tests/test_api/test_hub.py
@@ -16,20 +16,20 @@ class TestHubSubscribe(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
     def test_subscribe_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
         self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_subscribe_when_logged_in(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
                                  follow_redirects=True)
             self.assertEqual(resp.status_code, 200)
             # Need to find the Hub again to avoid DetachedInstanceError
-            h = hubs.models.Hub.by_name(self.session, 'infra')
+            h = hubs.models.Hub.by_name('infra')
             self.assertTrue(self.user.username in usernames(h.subscribers))
 
 
@@ -37,17 +37,17 @@ class TestHubUnsubscribe(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
     def test_unsubscribe_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
         self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_unsubscribe_when_logged_in(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         # Need a real user model to subscribe to the hub
-        User = hubs.models.User.by_username(self.session, self.user.username)
-        hub.subscribe(self.session, User)
+        User = hubs.models.User.by_username(self.user.username)
+        hub.subscribe(User)
 
         self.assertTrue(self.user.username in usernames(hub.subscribers))
 
@@ -55,7 +55,7 @@ class TestHubUnsubscribe(hubs.tests.APPTest):
             resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
                                  follow_redirects=True)
             self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name(self.session, 'infra')
+            h = hubs.models.Hub.by_name('infra')
             self.assertTrue(self.user.username not in usernames(h.subscribers))
 
 
@@ -63,20 +63,20 @@ class TestHubStar(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
     def test_star_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         resp = self.app.post('/api/hub/{}/star'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
         self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_star_when_logged_in(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post('/api/hub/{}/star'.format(hub.name),
                                  follow_redirects=True)
 
             self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name(self.session, 'infra')
+            h = hubs.models.Hub.by_name('infra')
             self.assertTrue(self.user.username in usernames(h.stargazers))
 
 
@@ -84,17 +84,17 @@ class TestHubUnstar(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
     def test_unstar_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
         self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_unstar_when_logged_in(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         # Need a real user model to subscribe to the hub
-        User = hubs.models.User.by_username(self.session, self.user.username)
-        hub.subscribe(self.session, User, role='stargazer')
+        User = hubs.models.User.by_username(self.user.username)
+        hub.subscribe(User, role='stargazer')
 
         self.assertTrue(self.user.username in [u.username for
                                                u in hub.stargazers])
@@ -103,7 +103,7 @@ class TestHubUnstar(hubs.tests.APPTest):
             resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
                                  follow_redirects=True)
             self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name(self.session, 'infra')
+            h = hubs.models.Hub.by_name('infra')
             self.assertTrue(self.user.username not in usernames(h.stargazers))
 
 
@@ -111,20 +111,20 @@ class TestHubJoin(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
     def test_join_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         resp = self.app.post('/api/hub/{}/join'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
         self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_join_when_logged_in(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post('/api/hub/{}/join'.format(hub.name),
                                  follow_redirects=True)
 
             self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name(self.session, 'infra')
+            h = hubs.models.Hub.by_name('infra')
             self.assertTrue(self.user.username in usernames(h.members))
 
 
@@ -132,22 +132,22 @@ class TestHubLeave(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('decause')
 
     def test_leave_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
                              follow_redirects=False)
         self.assertEqual(resp.status_code, 302)
         self.assertEqual(urlparse(resp.location).path, '/login')
 
     def test_star_when_logged_in(self):
-        hub = hubs.models.Hub.by_name(self.session, 'infra')
+        hub = hubs.models.Hub.by_name('infra')
         # Need a real user model to subscribe to the hub
-        User = hubs.models.User.by_username(self.session, self.user.username)
-        hub.subscribe(self.session, User, role='member')
+        User = hubs.models.User.by_username(self.user.username)
+        hub.subscribe(User, role='member')
 
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
                                  follow_redirects=True)
 
             self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name(self.session, 'infra')
+            h = hubs.models.Hub.by_name('infra')
             self.assertTrue(self.user.username not in usernames(h.members))
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index 5b8ad9e..c9c7657 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -80,7 +80,7 @@ class TestPostNotifications(hubs.tests.APPTest):
         self.assertEqual(notification['link'], 'baz')
 
         all_saved = hubs.models.SavedNotification.by_username(
-            hubs.app.session, self.user.username)
+            self.user.username)
         self.assertEqual(len(all_saved), 2)
         all_saved = [s.__json__() for s in all_saved]
         self.assertTrue(any(str(s['markup']) == self.valid_payload['markup']
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index 3065cfb..deeb258 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -12,83 +12,83 @@ class ModelTest(hubs.tests.APPTest):
     def test_delete_user(self):
         # verify user exists
         username = 'ralph'
-        user = hubs.models.User.get(self.session, username)
+        user = hubs.models.User.get(username)
         self.assertIsNotNone(user)
 
         # check if association exists
-        hub = hubs.models.Hub.get(self.session, username)
-        assoc = hubs.models.Association.get(self.session, hub, user, 'owner')
+        hub = hubs.models.Hub.get(username)
+        assoc = hubs.models.Association.get(hub, user, 'owner')
         self.assertIsNotNone(assoc)
 
         # delete the user
         self.session.delete(user)
-        user = hubs.models.User.get(self.session, username)
+        user = hubs.models.User.get(username)
         self.assertIsNone(user)
 
         # checking to see if the hub is still intact
-        hub = hubs.models.Hub.get(self.session, username)
+        hub = hubs.models.Hub.get(username)
         self.assertIsNotNone(hub)
         self.assertEqual('ralph', hub.name)
 
         # check if widgets still are intact
-        widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
+        widgets = hubs.models.Widget.by_hub_id_all(hub.name)
         self.assertEqual(12, len(widgets))
 
     def test_delete_hubs(self):
         # verify the hub exists
         hub_name = 'ralph'
-        hub = hubs.models.Hub.get(self.session, hub_name)
+        hub = hubs.models.Hub.get(hub_name)
         self.assertIsNotNone(hub)
 
         # check if association exists
         username = 'ralph'
-        user = hubs.models.User.get(self.session, username)
-        assoc = hubs.models.Association.get(self.session, hub, user, 'owner')
+        user = hubs.models.User.get(username)
+        assoc = hubs.models.Association.get(hub, user, 'owner')
         self.assertIsNotNone(assoc)
 
         # check if widgets exist
-        widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
+        widgets = hubs.models.Widget.by_hub_id_all(hub.name)
         self.assertEqual(12, len(widgets))
 
         # delete the hub
         self.session.delete(hub)
 
         # check if association is removed
-        assoc = hubs.models.Association.get(self.session, hub, user, 'owner')
+        assoc = hubs.models.Association.get(hub, user, 'owner')
         self.assertIsNone(assoc)
 
         # check if widgets are removed
-        widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
+        widgets = hubs.models.Widget.by_hub_id_all(hub.name)
         self.assertEqual([], widgets)
 
         # verify hub is deleted
-        hub = hubs.models.Hub.get(self.session, hub_name)
+        hub = hubs.models.Hub.get(hub_name)
         self.assertIsNone(hub)
 
         # check if user is still intact
-        user = hubs.models.User.get(self.session, username)
+        user = hubs.models.User.get(username)
         self.assertIsNotNone(user)
         self.assertEqual('ralph', user.username)
 
     def test_delete_user_then_hubs(self):
         username = 'ralph'
-        user = hubs.models.User.get(self.session, username)
+        user = hubs.models.User.get(username)
         self.assertIsNotNone(user)
         self.session.delete(user)
-        user = hubs.models.User.get(self.session, username)
+        user = hubs.models.User.get(username)
         self.assertIsNone(user)
 
         # checking to see if the hub is still intact
-        hub = hubs.models.Hub.get(self.session, username)
+        hub = hubs.models.Hub.get(username)
         self.assertIsNotNone(hub)
 
         self.session.delete(hub)
 
         # check if widgets are removed
-        widgets = hubs.models.Widget.by_hub_id_all(self.session, hub.name)
+        widgets = hubs.models.Widget.by_hub_id_all(hub.name)
         self.assertEqual([], widgets)
 
-        hub = hubs.models.Hub.get(self.session, username)
+        hub = hubs.models.Hub.get(username)
         self.assertIsNone(hub)
 
     def test_visit_counter(self):
@@ -96,7 +96,7 @@ class ModelTest(hubs.tests.APPTest):
         hub = 'decause'
         # Make sure the table is empty of data
         vc = hubs.models.VisitCounter.get_visits_by_username_hub(
-            session=self.session, username=username, visited_hub=hub)
+            username=username, visited_hub=hub)
         self.assertIsNone(vc)
 
         # Insert a new counter row
@@ -114,19 +114,17 @@ class ModelTest(hubs.tests.APPTest):
         vc = hubs.models.VisitCounter.get_or_create(
             session=self.session, username=username, visited_hub=hub)
         self.session.delete(vc)
-        hub_obj = hubs.models.Hub.get(self.session, username)
+        hub_obj = hubs.models.Hub.get(username)
         self.assertIsNotNone(hub_obj)
-        user_obj = hubs.models.User.get(session=self.session,
-                                        username=username)
+        user_obj = hubs.models.User.get(username=username)
         self.assertIsNotNone(user_obj)
 
         # Delete hub and make sure the visit counter is 0
         vc = hubs.models.VisitCounter.get_visits_by_username_hub(
-            session=self.session, username=username, visited_hub=hub)
+            username=username, visited_hub=hub)
         self.session.delete(hub_obj)
         self.assertIsNone(vc)
-        user_obj = hubs.models.User.get(session=self.session,
-                                        username=username)
+        user_obj = hubs.models.User.get(username=username)
         self.assertIsNotNone(user_obj)
 
     def test_visit_counter_does_not_exist(self):
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 47a2f4f..229d620 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -44,7 +44,7 @@ class WidgetTest(unittest.TestCase):
 
         hubs.app.session.flush()
 
-        hub = hubs.models.Hub.by_name(hubs.app.session, 'ralph')
+        hub = hubs.models.Hub.by_name('ralph')
         widget = hubs.models.Widget(
             plugin='about',
             index=500,
@@ -75,7 +75,7 @@ class WidgetTest(unittest.TestCase):
     # TODO - test that it has all the things it needs
 
     def widget_instance(self, hubname, plugin):
-        hub = hubs.models.Hub.by_name(self.session, hubname)
+        hub = hubs.models.Hub.by_name(hubname)
         if not hub:
             raise ValueError("No such hub %r" % hubname)
         for widget in hub.widgets:
diff --git a/hubs/validators.py b/hubs/validators.py
index 302b0e7..bd5b3f2 100755
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -25,7 +25,7 @@ def link(session, value):
 
 
 def username(session, value):
-    if hubs.models.User.by_username(session, value) is not None:
+    if hubs.models.User.by_username(value) is not None:
         return value
     raise ValueError('Invalid username')
 
diff --git a/hubs/views/api.py b/hubs/views/api.py
index 18ca0ba..4c96e44 100644
--- a/hubs/views/api.py
+++ b/hubs/views/api.py
@@ -12,8 +12,8 @@ from .utils import get_hub, login_required
 @login_required
 def hub_subscribe(hub):
     hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
-    hub.subscribe(flask.g.db, user)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
+    hub.subscribe(user)
     flask.g.db.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
@@ -22,9 +22,9 @@ def hub_subscribe(hub):
 @login_required
 def hub_unsubscribe(hub):
     hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
     try:
-        hub.unsubscribe(flask.g.db, user)
+        hub.unsubscribe(user)
     except KeyError:
         return flask.abort(400)
     flask.g.db.commit()
@@ -35,8 +35,8 @@ def hub_unsubscribe(hub):
 @login_required
 def hub_star(hub):
     hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
-    hub.subscribe(flask.g.db, user, role='stargazer')
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
+    hub.subscribe(user, role='stargazer')
     flask.g.db.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
@@ -45,9 +45,9 @@ def hub_star(hub):
 @login_required
 def hub_unstar(hub):
     hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
     try:
-        hub.unsubscribe(flask.g.db, user, role='stargazer')
+        hub.unsubscribe(user, role='stargazer')
     except KeyError:
         return flask.abort(400)
     flask.g.db.commit()
@@ -58,8 +58,8 @@ def hub_unstar(hub):
 @login_required
 def hub_join(hub):
     hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
-    hub.subscribe(flask.g.db, user, role='member')
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
+    hub.subscribe(user, role='member')
     flask.g.db.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
 
@@ -68,9 +68,9 @@ def hub_join(hub):
 @login_required
 def hub_leave(hub):
     hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
     try:
-        hub.unsubscribe(flask.g.db, user, role='member')
+        hub.unsubscribe(user, role='member')
     except KeyError:
         return flask.abort(400)
     flask.g.db.commit()
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 12b75e9..f64f261 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -20,7 +20,7 @@ def hub(name):
 @app.route('/<name>/json')
 def hub_json(name):
     hub = get_hub(name)
-    response = flask.jsonify(hub.__json__(flask.g.db))
+    response = flask.jsonify(hub.__json__())
     # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
     return response
 
diff --git a/hubs/views/plus_plus.py b/hubs/views/plus_plus.py
index 266c2ea..4e25746 100644
--- a/hubs/views/plus_plus.py
+++ b/hubs/views/plus_plus.py
@@ -15,7 +15,7 @@ from .utils import login_required
 
 @app.route('/plus_plus/<user>/status', methods=['GET'])
 def plus_plus_status(user):
-    receiver = hubs.models.User.by_username(flask.g.db, user)
+    receiver = hubs.models.User.by_username(user)
     if not receiver:
         return 'User does not exist', 403
     pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
@@ -43,7 +43,7 @@ def plus_plus_update_bool_helper(val):
 @app.route('/plus_plus/<user>/update', methods=['POST'])
 @login_required
 def plus_plus_update(user):
-    receiver = hubs.models.User.by_username(flask.g.db, user)
+    receiver = hubs.models.User.by_username(user)
 
     if not receiver:
         return 'User does not exist', 403
@@ -60,7 +60,7 @@ def plus_plus_update(user):
 
     update_bool_val = plus_plus_update_bool_helper(flask.request.form[update])
     pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
-    sender = hubs.models.User.by_username(flask.g.db, flask.g.auth.nickname)
+    sender = hubs.models.User.by_username(flask.g.auth.nickname)
     pp_token = app.config['PLUS_PLUS_TOKEN']
     auth_header = {'Authorization': 'token {}'.format(pp_token)}
     data = {'sender': sender.username, update: update_bool_val}
diff --git a/hubs/views/root.py b/hubs/views/root.py
index cc03161..6b9102f 100644
--- a/hubs/views/root.py
+++ b/hubs/views/root.py
@@ -22,12 +22,12 @@ def groups():
 
     # Get the list of promoted and non-promoted group hubs from the DB
     promoted_names = app.config.get('PROMOTED_GROUPS')
-    groups = hubs.models.Hub.all_group_hubs(flask.g.db)
+    groups = hubs.models.Hub.all_group_hubs()
     promoted = [g for g in groups if g.name in promoted_names]
     secondary = [g for g in groups if g.name not in promoted_names]
 
     name_of_the_month = app.config.get('HUB_OF_THE_MONTH')
-    hub_of_the_month = hubs.models.Hub.by_name(flask.g.db, name_of_the_month)
+    hub_of_the_month = hubs.models.Hub.by_name(name_of_the_month)
 
     return flask.render_template(
         'groups.html',
diff --git a/hubs/views/user.py b/hubs/views/user.py
index cab84ed..692daf3 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -14,7 +14,7 @@ from .utils import login_required, get_hub
 @login_required
 def stream(name):
     hub = get_hub(name)
-    saved = hubs.models.SavedNotification.by_username(flask.g.db, name)
+    saved = hubs.models.SavedNotification.by_username(name)
     saved = [n.__json__() for n in saved]
 
     stream = hubs.stream.Stream()
@@ -33,13 +33,13 @@ def stream(name):
 @login_required
 def notifications(user):
     if flask.request.method == 'GET':
-        notifications = hubs.models.SavedNotification.by_username(flask.g.db, user)
+        notifications = hubs.models.SavedNotification.by_username(user)
         notifications = [n.__json__() for n in notifications]
         return flask.jsonify(notifications)
 
     if flask.request.method == 'POST':
         data = flask.request.get_json()
-        user = hubs.models.User.by_username(flask.g.db, user)
+        user = hubs.models.User.by_username(user)
         if not user:
             return flask.abort(400)
         try:
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index d40ff3f..f413985 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -11,7 +11,7 @@ from .utils import get_widget
 @app.route('/<hub>/<int:idx>')
 def widget_render(hub, idx):
     widget = get_widget(hub, idx)
-    return widget.render(flask.g.db)  # , edit=False)
+    return widget.render()  # , edit=False)
     # was blocking all widgets from working, sorry!
 
 
@@ -19,7 +19,7 @@ def widget_render(hub, idx):
 @app.route('/<hub>/<int:idx>/json/')
 def widget_json(hub, idx):
     widget = get_widget(hub, idx)
-    response = flask.jsonify(widget.__json__(flask.g.db))
+    response = flask.jsonify(widget.__json__())
     # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
     return response
 
diff --git a/hubs/widgets/memberships.py b/hubs/widgets/memberships.py
index 2763db0..95beb74 100644
--- a/hubs/widgets/memberships.py
+++ b/hubs/widgets/memberships.py
@@ -17,8 +17,8 @@ def data(session, widget, **kwargs):
     hub = widget.hub
     members = []
     if hub.user_hub:
-        user = hubs.models.User.by_username(session, hub.name)
-        members = [m.__json__(session) for m in user.memberships
+        user = hubs.models.User.by_username(hub.name)
+        members = [m.__json__() for m in user.memberships
                    if m.name != user.username]
     else:
         members_name = []
@@ -26,7 +26,7 @@ def data(session, widget, **kwargs):
             if member.username in members_name:
                 continue
             members_name.append(member.username)
-            members.append(member.__json__(session))
+            members.append(member.__json__())
 
     oldest_members = sorted(members,
                             key=lambda m: m.get('created_on'))[:ELLIPSIS_LIMIT]
diff --git a/populate-from-fas.py b/populate-from-fas.py
index b74e8a6..959c5e4 100755
--- a/populate-from-fas.py
+++ b/populate-from-fas.py
@@ -60,7 +60,7 @@ for letter in reversed(sorted(list(set(string.letters.lower())))):
     session = hubs.models.init(
         fedmsg_config['hubs.sqlalchemy.uri'], True, True)
     for user in users:
-        hubs_user = hubs.models.User.by_username(session, user['username'])
+        hubs_user = hubs.models.User.by_username(user['username'])
 
         # Build a lookup by group id
         roles = dict([(r.group_id, r) for r in user['roles']])
@@ -91,11 +91,11 @@ for letter in reversed(sorted(list(set(string.letters.lower())))):
             )
 
             if hubs_user not in hub.subscribers:
-                hub.subscribe(session, hubs_user, role='subscriber')
+                hub.subscribe(hubs_user, role='subscriber')
             if hubs_user not in hub.members:
-                hub.subscribe(session, hubs_user, role='member')
+                hub.subscribe(hubs_user, role='member')
             if hubs_user not in hub.owners:
                 if role['role_type'] in [u'administrator', u'sponsor']:
-                    hub.subscribe(session, hubs_user, role='owner')
+                    hub.subscribe(hubs_user, role='owner')
 
     session.commit()
diff --git a/populate.py b/populate.py
index 4286940..d4b262d 100755
--- a/populate.py
+++ b/populate.py
@@ -62,9 +62,9 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_username(session, 'pravins'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'ralph'), 'subscriber')
+hub.subscribe(hubs.models.User.by_username('pravins'), 'owner')
+hub.subscribe(hubs.models.User.by_username('decause'), 'member')
+hub.subscribe(hubs.models.User.by_username('ralph'), 'subscriber')
 
 
 session.commit()
@@ -107,11 +107,11 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'jflory7'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'bee2502'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'keekri'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'linuxmodder'), 'member')
+hub.subscribe(hubs.models.User.by_username('decause'), 'owner')
+hub.subscribe(hubs.models.User.by_username('jflory7'), 'member')
+hub.subscribe(hubs.models.User.by_username('bee2502'), 'member')
+hub.subscribe(hubs.models.User.by_username('keekri'), 'member')
+hub.subscribe(hubs.models.User.by_username('linuxmodder'), 'member')
 
 
 session.commit()
@@ -154,12 +154,12 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_username(session, 'croberts'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'ryanlerch'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'mrichard'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'mattdm'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'ralph'), 'subscriber')
+hub.subscribe(hubs.models.User.by_username('croberts'), 'owner')
+hub.subscribe(hubs.models.User.by_username('ryanlerch'), 'owner')
+hub.subscribe(hubs.models.User.by_username('mrichard'), 'member')
+hub.subscribe(hubs.models.User.by_username('mattdm'), 'member')
+hub.subscribe(hubs.models.User.by_username('decause'), 'member')
+hub.subscribe(hubs.models.User.by_username('ralph'), 'subscriber')
 
 
 session.commit()
@@ -202,13 +202,13 @@ hub.widgets.append(widget)
 
 
 # Set up some memberships
-hub.subscribe(session, hubs.models.User.by_username(session, 'duffy'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'ryanlerch'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'gnokii'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'mrichard'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'nask0'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'ralph'), 'subscriber')
+hub.subscribe(hubs.models.User.by_username('duffy'), 'owner')
+hub.subscribe(hubs.models.User.by_username('ryanlerch'), 'owner')
+hub.subscribe(hubs.models.User.by_username('gnokii'), 'owner')
+hub.subscribe(hubs.models.User.by_username('mrichard'), 'owner')
+hub.subscribe(hubs.models.User.by_username('nask0'), 'member')
+hub.subscribe(hubs.models.User.by_username('decause'), 'member')
+hub.subscribe(hubs.models.User.by_username('ralph'), 'subscriber')
 
 session.commit()
 
@@ -251,10 +251,10 @@ hub.widgets.append(widget)
 
 vc = hubs.models.VisitCounter().get_or_create(session, 'ralph', 'mrichard')
 hubs.models.VisitCounter().increment_visits(session, 'ralph', 'mrichard')
-hub.subscribe(session, hubs.models.User.by_username(session, 'ralph'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'abompard'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'lmacken'), 'owner')
-hub.subscribe(session, hubs.models.User.by_username(session, 'nask0'), 'member')
-hub.subscribe(session, hubs.models.User.by_username(session, 'decause'), 'subscriber')
+hub.subscribe(hubs.models.User.by_username('ralph'), 'owner')
+hub.subscribe(hubs.models.User.by_username('abompard'), 'owner')
+hub.subscribe(hubs.models.User.by_username('lmacken'), 'owner')
+hub.subscribe(hubs.models.User.by_username('nask0'), 'member')
+hub.subscribe(hubs.models.User.by_username('decause'), 'subscriber')
 
 session.commit()

From 96c39ff13859926f68bec587912201472a940bda Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Feb 06 2017 22:07:21 +0000
Subject: [PATCH 690/1001] Remove session from ``User.by_username`` calls


These two calls got missed by the cleanup in PR#311

Signed-off-by: Jeremy Cline <jeremy@jcline.org>

---

diff --git a/hubs/widgets/contact.py b/hubs/widgets/contact.py
index b14e126..4bd5597 100644
--- a/hubs/widgets/contact.py
+++ b/hubs/widgets/contact.py
@@ -25,7 +25,7 @@ def data(session, widget, **kwargs):
     hub = widget.hub
     if hub.user_hub:
         usergroup = True
-        user = hubs.models.User.by_username(session, hub.name)
+        user = hubs.models.User.by_username(hub.name)
         email = user.username + '@fedoraproject.org'
         karma_url = flask.url_for('plus_plus_status', user=user.username)
         fas_info = {
diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
index 8035d3d..4446c25 100755
--- a/hubs/widgets/subscriptions.py
+++ b/hubs/widgets/subscriptions.py
@@ -26,7 +26,7 @@ position = 'right'
           validator=validators.username,
           help="A FAS username.")
 def data(session, widget, username):
-    user = hubs.models.User.by_username(session, username)
+    user = hubs.models.User.by_username(username)
     ownerships = [u.name for u in user.ownerships]
     memberships = [u.name for u in user.memberships]
     subscriptions = [u.name for u in user.subscriptions]

From 5fa601828904bfad7af3499b5c251989f589ae47 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 06 2017 23:29:15 +0000
Subject: [PATCH 691/1001] Improve the widget-loading system


Avoid passing Python variables to Javascript, this is error-prone.

---

diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
index 01f2382..3474786 100644
--- a/hubs/static/js/utils.js
+++ b/hubs/static/js/utils.js
@@ -12,23 +12,23 @@ var collapse_feed_entries = function(idx) {
 }
 
 // Load widgets
- function setup_widgets(base_url, widgets) {
-   console.log(base_url, widgets);
-   $.each(widgets, function(i, widget) {
-     $.ajax({
-       url: base_url + widget,
-       dataType: 'html',
-       success: function(html) {
-         $('#widget-' + widget).html(html);
-         setTimeout(function() {
-           $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
-         }, 100);
-       },
-       error: function() {
-         $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
-         console.log('error');
-         console.trace();
-       },
-     });
-   });
- }
+function setup_widgets() {
+    $("div.widget[data-url]").each(function() {
+        var element=$(this);
+        $.ajax({
+            url: element.attr("data-url"),
+            dataType: 'html',
+            success: function(html) {
+                element.html(html);
+                setTimeout(function() {
+                  element.find('.panel').toggleClass('panel-visible');
+                }, 100);
+            },
+            error: function() {
+                element.html('Got an error retrieving this widget.  Sorry :(');
+                console.log('error');
+                console.trace();
+            },
+        });
+    });
+}
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index fed9ae6..390949d 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -155,11 +155,7 @@
           </div>
           {% endif %}
 
-          <div id="left_widgets">
-          {% for widget in hub.left_widgets %}
-            <div id="widget-{{ widget.idx }}" class="widget row"></div>
-          {% endfor %}
-          </div>
+          {% include "includes/left_widgets.html" %}
         </div>
 
         <div class="col-md-{{ hub.right_width }}">
@@ -177,11 +173,7 @@
           </div>
           {% endif %}
 
-          <div id="right_widgets">
-            {% for widget in hub.right_widgets %}
-            <div id="widget-{{ widget.idx }}" class="widget row"></div>
-            {% endfor %}
-          </div>
+          {% include "includes/right_widgets.html" %}
         </div>
 
       </div>  <!-- /row -->
@@ -339,10 +331,7 @@ function visit_counter() {
 $(function() {
   visit_counter()
   
-  setup_widgets(
-    {{ url_for("hub", name=hub.name) }},
-    {{ hub.widgets_idx|tojson }}
-    );
+  setup_widgets();
   setup_edit_btns();
   
   {% if edit -%}
diff --git a/hubs/templates/includes/_rightpanel.html b/hubs/templates/includes/_rightpanel.html
deleted file mode 100644
index 2a9f511..0000000
--- a/hubs/templates/includes/_rightpanel.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="right_widgets">
-  {% for widget in hub.right_widgets %}
-  <div id="widget-{{ widget.idx }}" class="widget row"></div>
-  {% endfor %}
-</div>
diff --git a/hubs/templates/includes/left_widgets.html b/hubs/templates/includes/left_widgets.html
new file mode 100644
index 0000000..b0326e9
--- /dev/null
+++ b/hubs/templates/includes/left_widgets.html
@@ -0,0 +1,7 @@
+<div id="left_widgets">
+{% for widget in hub.left_widgets %}
+  <div id="widget-{{ widget.idx }}" class="widget row"
+       data-url="{{ url_for('widget_render', hub=hub.name, idx=widget.idx) }}"
+       ></div>
+{% endfor %}
+</div>
diff --git a/hubs/templates/includes/right_widgets.html b/hubs/templates/includes/right_widgets.html
new file mode 100644
index 0000000..d9b487a
--- /dev/null
+++ b/hubs/templates/includes/right_widgets.html
@@ -0,0 +1,7 @@
+<div id="right_widgets">
+  {% for widget in hub.right_widgets %}
+  <div id="widget-{{ widget.idx }}" class="widget row"
+       data-url="{{ url_for('widget_render', hub=hub.name, idx=widget.idx) }}"
+       ></div>
+  {% endfor %}
+</div>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 278b076..128ff25 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -31,7 +31,7 @@
           <div id="streamFeed"></div>
         </div>
         <div class="col-sm-4">
-          {% include "includes/_rightpanel.html" %}
+          {% include "includes/right_widgets.html" %}
         </div>
       </div>
     </div>
@@ -45,7 +45,7 @@
           <div id="actionsFeed"></div>
         </div>
         <div class="col-sm-4">
-          {% include "includes/_rightpanel.html" %}
+          {% include "includes/right_widgets.html" %}
         </div>
       </div>
     </div>
@@ -60,7 +60,7 @@
             {% include "includes/_messages.html" %}
           </div>
           <div class="col-sm-4">
-            {% include "includes/_rightpanel.html" %}
+            {% include "includes/right_widgets.html" %}
           </div>
         </div>
       </div>
@@ -75,7 +75,7 @@
           <div id="savedFeed"></div>
         </div>
         <div class="col-sm-4">
-          {% include "includes/_rightpanel.html" %}
+          {% include "includes/right_widgets.html" %}
         </div>
       </div>
     </div>
@@ -145,10 +145,7 @@
    });
  }
  $(function() {
-   setup_widgets(
-    {{ url_for("hub", name=hub.name) }},
-    {{ hub.widgets_idx|tojson }}
-    );
+   setup_widgets();
    setup_feeds();
  });
 </script>

From 37a6eec05064b1e7575b5044af7438f2fedc6d5d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 06 2017 23:29:15 +0000
Subject: [PATCH 692/1001] Fix the stream page to not load the widgets 4 times


---

diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 128ff25..8586d2a 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -6,81 +6,54 @@
   <h1>My Stream</h1>
   <p>Notifications, actions, and other things of interest to me</p>
 </div>
-<ul class="nav-tabs " role="tablist">
-  <li class="nav-item">
-    <a class="nav-link active" href="#stream" role="tab" data-toggle="tab">My Stream</a>
-  </li>
-  <li class="nav-item">
-    <a class="nav-link" href="#actions" role="tab" data-toggle="tab">My Actions</a>
-  </li>
-  <li class="nav-item">
-    <a class="nav-link" href="#mentions" role="tab" data-toggle="tab">My Mentions</a>
-  </li>
-  <li class="nav-item">
-    <a class="nav-link" href="#saved" role="tab" data-toggle="tab">Saved Notifications</a>
-  </li>
-</ul>
 
-<!-- Tab panes -->
-<div class="tab-content">
-  <div role="tabpanel" class="tab-pane fade in active" id="stream">
-    <div class="container">
-      <div class="row">
-        <div class="col-sm-8 pull-left">
-          {% include "includes/_searchstream.html" %}
-          <div id="streamFeed"></div>
-        </div>
-        <div class="col-sm-4">
-          {% include "includes/right_widgets.html" %}
-        </div>
-      </div>
-    </div>
-  </div>
+<div class="row">
+  <div class="col-sm-8">
 
-  <div role="tabpanel" class="tab-pane fade" id="actions">
-    <div class="container">
-      <div class="row">
+    <ul class="nav-tabs " role="tablist">
+      <li class="nav-item">
+        <a class="nav-link active" href="#stream" role="tab" data-toggle="tab">My Stream</a>
+      </li>
+      <li class="nav-item">
+        <a class="nav-link" href="#actions" role="tab" data-toggle="tab">My Actions</a>
+      </li>
+      <li class="nav-item">
+        <a class="nav-link" href="#mentions" role="tab" data-toggle="tab">My Mentions</a>
+      </li>
+      <li class="nav-item">
+        <a class="nav-link" href="#saved" role="tab" data-toggle="tab">Saved Notifications</a>
+      </li>
+    </ul>
+
+    <!-- Tab panes -->
+    <div class="tab-content">
+      <div role="tabpanel" class="tab-pane fade in active" id="stream">
         {% include "includes/_searchstream.html" %}
-        <div class="col-sm-8 pull-left">
-          <div id="actionsFeed"></div>
-        </div>
-        <div class="col-sm-4">
-          {% include "includes/right_widgets.html" %}
-        </div>
+        <div id="streamFeed"></div>
       </div>
-    </div>
-  </div>
-  <div role="tabpanel" class="tab-pane fade" id="mentions">
-    <div class="container">
-      <div class="row">
+      <div role="tabpanel" class="tab-pane fade" id="actions">
+        {% include "includes/_searchstream.html" %}
+        <div id="actionsFeed"></div>
+      </div>
+      <div role="tabpanel" class="tab-pane fade" id="mentions">
         {% include "includes/_searchstream.html" %}
         <br/>
-        <div class="col-sm-8 pull-left">
-          <div id="mentionsFeed">
-            {% include "includes/_messages.html" %}
-          </div>
-          <div class="col-sm-4">
-            {% include "includes/right_widgets.html" %}
-          </div>
+        <div id="mentionsFeed">
+          {% include "includes/_messages.html" %}
         </div>
       </div>
-    </div>
-  </div>
-  <div role="tabpanel" class="tab-pane fade" id="saved">
-    <div class="container">
-      <div class="row">
-        <br/>
+      <div role="tabpanel" class="tab-pane fade" id="saved">
         {% include "includes/_searchstream.html" %}
-        <div class="col-sm-8 pull-left">
-          <div id="savedFeed"></div>
-        </div>
-        <div class="col-sm-4">
-          {% include "includes/right_widgets.html" %}
-        </div>
+        <div id="savedFeed"></div>
       </div>
     </div>
   </div>
+
+  <div class="col-sm-4">
+    {% include "includes/right_widgets.html" %}
+  </div>
 </div>
+
 <style>
  .jumbotron {
    margin-bottom: 0;

From 2f5b162d8572ddd0ecc2292b51164711103f6804 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 06 2017 23:29:15 +0000
Subject: [PATCH 693/1001] Fix a CSS glitch on the hubs page


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 390949d..f5628f0 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -30,7 +30,7 @@
       {% endif %}
     </nav>
   
-    <div class="col-md-10 col-md-offset-2">
+    <div class="col-md-10">
       <div class="row">
         
         <!-- Left side of header -->

From e3ba6e82412fcd56ebacc18f243b92cc43407a4d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 06 2017 23:30:15 +0000
Subject: [PATCH 694/1001] Remove duplicated code


---

diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 229d620..7579b19 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -9,84 +9,18 @@ import requests
 import vcr
 
 import hubs.models
+from hubs.tests import APPTest
 
-cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
 
-
-class WidgetTest(unittest.TestCase):
-    def setUp(self):
-        filename = cassette_dir + self.id()
-        self.vcr = vcr.use_cassette(filename, record_mode='new_episodes')
-        self.vcr.__enter__()
-
-        import hubs.app
-        hubs.app.fedmsg_config = {
-            'hubs.sqlalchemy.uri': 'sqlite://',  # in memory
-        }
-        hubs.app.session = hubs.models.init(
-            hubs.app.fedmsg_config['hubs.sqlalchemy.uri'],
-            create=True,
-        )
-        self.app = hubs.app.app.test_client()
-        self.app.testing = True
-        self.session = hubs.app.session
-        self.populate()
-
-    def tearDown(self):
-        self.vcr.__exit__()
-        self.session.remove()
+class WidgetTest(APPTest):
 
     def populate(self):
-        for user in ['devyani7', 'dhrish', 'shalini', 'ralph', 'decause']:
-            fullname = user.title()
-            hubs.models.User.get_or_create(
-                hubs.app.session, username=user, fullname=fullname)
-
-        hubs.app.session.flush()
-
+        super(WidgetTest, self).populate()
         hub = hubs.models.Hub.by_name('ralph')
         widget = hubs.models.Widget(
-            plugin='about',
-            index=500,
-            _config=json.dumps({"text": "Testing."}),
-        )
-
-        hub.widgets.append(widget)
-
-        widget = hubs.models.Widget(
             plugin='library',
             index=51,
             _config=json.dumps({"urls": "ralph/"})  # we must add a url or itll crash
         )
         hub.widgets.append(widget)
-
-        for team in ['i18n', 'infra', 'old']:
-            hub = hubs.models.Hub(name=team, summary="the %s team" % team)
-            if hub.name == 'old':
-                hub.last_refreshed = datetime.utcnow() - timedelta(days=100)
-                hub.last_updated = datetime.utcnow() - timedelta(days=200)
-
-            hubs.app.session.add(hub)
-            widget = hubs.models.Widget(plugin='meetings', index=11,
-                                        _config=json.dumps({'calendar': team}))
-            hub.widgets.append(widget)
-
-    # TODO - test that it is in the registry
-    # TODO - test that it has all the things it needs
-
-    def widget_instance(self, hubname, plugin):
-        hub = hubs.models.Hub.by_name(hubname)
-        if not hub:
-            raise ValueError("No such hub %r" % hubname)
-        for widget in hub.widgets:
-            if widget.plugin == plugin:
-                return widget
-        raise KeyError("No such widget found for %s/%s" % (hubname, plugin))
-
-    @staticmethod
-    def get_fedmsg(idx):
-        url = 'https://apps.fedoraproject.org/datagrepper/id'
-        response = requests.get(url, params=dict(id=idx))
-        if not bool(response):
-            raise IOError("Failed to talk to %r %r" % (response.url, response))
-        return response.json()
+        hubs.app.session.commit()

From 6bd7bfba450865f89f9ab8fe1c0a74674db73aef Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 06 2017 23:30:15 +0000
Subject: [PATCH 695/1001] Remove unused code


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 59866ee..2394c1e 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -14,14 +14,12 @@ import vcr
 
 import hubs.models
 
-cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
-json_path = os.path.join(
-    os.path.join(os.path.dirname(os.path.abspath(__file__))), 'data/')
+cassette_dir = os.path.join(dirname(__file__), 'vcr-request-data')
 
 
 class APPTest(unittest.TestCase):
     def setUp(self):
-        filename = cassette_dir + self.id()
+        filename = os.path.join(cassette_dir, self.id())
         self.vcr = vcr.use_cassette(filename, record_mode='new_episodes')
         self.vcr.__enter__()
 
@@ -155,6 +153,3 @@ class FakeAuthorization(object):
         self.avatar = 'avatar_src_url'
         self.nickname = username
         self.username = username
-
-    def __getitem__(self, key):
-        return self.dic[key]
diff --git a/hubs/tests/data/message_involved.json b/hubs/tests/data/message_involved.json
deleted file mode 100644
index fdfd0db..0000000
--- a/hubs/tests/data/message_involved.json
+++ /dev/null
@@ -1,137 +0,0 @@
-{
-    "timestamp": 1465567413.0,
-    "topic": "io.pagure.prod.pagure.issue.new",
-    "msg_id": "2016-0490127f-473f-4d01-ASDF-a864a56dc302",
-    "msg": {
-        "action": "created",
-        "comment": {
-            "body":
-            "hm, there is something odd the stackage page is inconsistent",
-            "created_at": "2016-06-10T14:03:31Z",
-            "html_url":
-            "https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438",
-            "id": 225190438,
-            "updated_at": "2016-06-10T14:03:31Z",
-            "url":
-            "https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438",
-            "user": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/pypingou",
-                "id": 1240038,
-                "login": "pypingou",
-                "site_admin": false,
-                "type": "User",
-                "url": "https://api.github.com/users/pypingou"
-            }
-        },
-        "fas_usernames": {
-            "fedora-infra": "github_org_fedora-infra",
-            "pypingou": "pingou"
-        },
-        "issue": {
-            "assignee": null,
-            "body":
-            "@juhp it seems that the stackage backend is broken:",
-            "closed_at": "2016-04-29T14:53:10Z",
-            "comments": 8,
-            "created_at": "2016-04-15T16:15:57Z",
-            "html_url":
-            "https://github.com/fedora-infra/anitya/issues/283",
-            "id": 148703615,
-            "labels": [],
-            "locked": false,
-            "milestone": null,
-            "number": 283,
-            "state": "closed",
-            "title": "stackage backend broken",
-            "updated_at": "2016-06-10T14:03:31Z",
-            "url":
-            "https://api.github.com/repos/fedora-infra/anitya/issues/283",
-            "user": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/pypingou",
-                "id": 1240038,
-                "login": "pypingou",
-                "site_admin": false,
-                "type": "User",
-                "url": "https://api.github.com/users/pypingou"
-            }
-        },
-        "organization": {
-            "description": "Fedora Infrastructure Team",
-            "id": 3316637,
-            "login": "fedora-infra",
-            "url": "https://api.github.com/orgs/fedora-infra"
-        },
-        "repository": {
-            "created_at": "2013-11-29T10:17:26Z",
-            "default_branch": "master",
-            "description": "A cross-distribution upstream release project",
-            "fork": false,
-            "forks": 33,
-            "forks_count": 33,
-            "full_name": "fedora-infra/anitya",
-            "has_downloads": true,
-            "has_issues": true,
-            "has_pages": false,
-            "has_wiki": false,
-            "homepage": "https://release-monitoring.org",
-            "html_url": "https://github.com/fedora-infra/anitya",
-            "id": 14798348,
-            "language": "Python",
-            "name": "anitya",
-            "open_issues": 25,
-            "open_issues_count": 25,
-            "owner": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/fedora-infra",
-                "id": 3316637,
-                "login": "fedora-infra",
-                "site_admin": false,
-                "type": "Organization",
-                "url": "https://api.github.com/users/fedora-infra"
-            },
-            "private": false,
-            "pushed_at": "2016-06-05T18:16:15Z",
-            "size": 4364,
-            "stargazers_count": 56,
-            "updated_at": "2016-06-10T09:43:58Z",
-            "url": "https://api.github.com/repos/fedora-infra/anitya",
-            "watchers": 56,
-            "watchers_count": 56
-        },
-        "sender": {
-            "gravatar_id": "",
-            "html_url": "https://github.com/pypingou",
-            "id": 1240038,
-            "login": "pypingou",
-            "site_admin": false,
-            "type": "User",
-            "url": "https://api.github.com/users/pypingou"
-        }
-    },
-    "arguments": {
-        "categories": [
-            "pagure"
-        ],
-        "contains": [],
-        "delta": 172800.0,
-        "end": 1465839365.0,
-        "grouped": false,
-        "meta": [],
-        "not_categories": [],
-        "not_packages": [],
-        "not_topics": [],
-        "not_users": [],
-        "order": "desc",
-        "packages": [],
-        "page": 1,
-        "rows_per_page": 1,
-        "start": 1465666565.0,
-        "topics": [],
-        "users": []
-    },
-    "count": 1,
-    "pages": 225,
-    "total": 225
-}
diff --git a/hubs/tests/data/message_not_involved.json b/hubs/tests/data/message_not_involved.json
deleted file mode 100644
index e72439a..0000000
--- a/hubs/tests/data/message_not_involved.json
+++ /dev/null
@@ -1,120 +0,0 @@
-{
-    "topic": "org.fedoraproject.prod.github.issue.comment",
-    "i": 1,
-    "msg": {
-        "action": "created",
-        "comment": {
-            "body":
-            "hm, there is something odd the stackage page is inconsistent",
-            "created_at": "2016-06-10T14:03:31Z",
-            "html_url":
-            "https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438",
-            "id": 225190438,
-            "updated_at": "2016-06-10T14:03:31Z",
-            "url":
-            "https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438",
-            "user": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/pypingou",
-                "id": 1240038,
-                "login": "pypingou",
-                "site_admin": false,
-                "type": "User",
-                "url": "https://api.github.com/users/pypingou"
-            }
-        },
-        "fas_usernames": {
-            "fedora-infra": "github_org_fedora-infra",
-            "pypingou": "pingou"
-        },
-        "issue": {
-            "assignee": null,
-            "body":
-            "@juhp it seems that the stackage backend is broken",
-            "closed_at": "2016-04-29T14:53:10Z",
-            "comments": 8,
-            "created_at": "2016-04-15T16:15:57Z",
-            "html_url":
-            "https://github.com/fedora-infra/anitya/issues/283",
-            "id": 148703615,
-            "labels": [],
-            "locked": false,
-            "milestone": null,
-            "number": 283,
-            "state": "closed",
-            "title": "stackage backend broken",
-            "updated_at": "2016-06-10T14:03:31Z",
-            "url":
-            "https://api.github.com/repos/fedora-infra/anitya/issues/283",
-            "user": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/pypingou",
-                "id": 1240038,
-                "login": "pypingou",
-                "site_admin": false,
-                "type": "User",
-                "url": "https://api.github.com/users/pypingou"
-            }
-        },
-        "organization": {
-            "description": "Fedora Infrastructure Team",
-            "id": 3316637,
-            "login": "fedora-infra",
-            "url": "https://api.github.com/orgs/fedora-infra"
-        },
-        "repository": {
-            "created_at": "2013-11-29T10:17:26Z",
-            "default_branch": "master",
-            "description":
-            "A cross-distribution upstream release monitoring project",
-            "fork": false,
-            "forks": 33,
-            "forks_count": 33,
-            "full_name": "fedora-infra/anitya",
-            "has_downloads": true,
-            "has_issues": true,
-            "has_pages": false,
-            "has_wiki": false,
-            "homepage": "https://release-monitoring.org",
-            "html_url": "https://github.com/fedora-infra/anitya",
-            "id": 14798348,
-            "language": "Python",
-            "name": "anitya",
-            "open_issues": 25,
-            "open_issues_count": 25,
-            "owner": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/fedora-infra",
-                "id": 3316637,
-                "login": "fedora-infra",
-                "site_admin": false,
-                "type": "Organization",
-                "url": "https://api.github.com/users/fedora-infra"
-            },
-            "private": false,
-            "pushed_at": "2016-06-05T18:16:15Z",
-            "size": 4364,
-            "stargazers_count": 56,
-            "updated_at": "2016-06-10T09:43:58Z",
-            "url": "https://api.github.com/repos/fedora-infra/anitya",
-            "watchers": 56,
-            "watchers_count": 56
-        },
-        "sender": {
-            "gravatar_id": "",
-            "html_url": "https://github.com/pypingou",
-            "id": 1240038,
-            "login": "pypingou",
-            "site_admin": false,
-            "type": "User",
-            "url": "https://api.github.com/users/pypingou"
-        }
-    },
-    "msg_id": "2016-0490127f-473f-4d01-8e3a-a864a56dc302",
-    "signature":
-    "MNpAVdrPW78dcSe94FOS+/6QFBYo/LkrV5ee9tQedkhurHY1BGpaFHlU5l8cNVEpB7rr",
-    "source_name": "datanommer",
-    "source_version": "0.6.5",
-    "timestamp": 1465567413.0,
-    "topic": "org.fedoraproject.prod.github.issue.comment"
-}
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 3c24905..1ca2a8d 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -18,8 +18,6 @@ import hubs.models
 
 import fedmsg.config
 
-cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
-
 
 class HubsAPITest(hubs.tests.APPTest):
     def test_index_logged_out(self):

From daf8051be3969e8b3d3ed31bbbcd11069760085e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 06 2017 23:30:15 +0000
Subject: [PATCH 696/1001] Don't hardcode the basepython in Tox


---

diff --git a/tox.ini b/tox.ini
index 37dd0c2..24d3f29 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,7 +4,6 @@ skipsdist = True
 
 
 [testenv]
-basepython = python2
 usedevelop = True
 deps =
     -rrequirements.txt

From 56f152f7032a7c9ed5946adbe59683751a637f91 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 06 2017 23:30:15 +0000
Subject: [PATCH 697/1001] Fix a index change


---

diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 9182b56..ac7ddfc 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -18,12 +18,12 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
                 "urls": "ralph/"
             },
             "data": {
-                u"edit_url": u"/ralph/57/edit",
+                u"edit_url": u"/ralph/%d/edit" % widget.idx,
                 u"source_url": u"/source/library",
                 u"urls": [
                     u"<a href=\"ralph/\">ralph/</a>"
                 ],
-                u"widget_url": u"/ralph/57"
+                u"widget_url": u"/ralph/%d" % widget.idx,
             },
             "description": None,
             "hub": "ralph",

From 16881cd85fd22e9ba70f7785b21e3aa9baea4dd9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 08 2017 14:04:47 +0000
Subject: [PATCH 698/1001] Replace the deprecated 'fedora' OIDC scope


Fixes #316

---

diff --git a/hubs/default_config.py b/hubs/default_config.py
index 085ec5f..e540ad9 100755
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -23,7 +23,11 @@ OIDC_CLIENT_SECRETS = os.path.join(os.path.dirname(
 OIDC_ID_TOKEN_COOKIE_SECURE = True
 OIDC_REQUIRE_VERIFIED_EMAIL = False
 OIDC_OPENID_REALM = 'http://localhost:5000/oidc_callback'
-OIDC_SCOPES = ['openid', 'email', 'profile', 'fedora']
+OIDC_SCOPES = [
+    'openid', 'email', 'profile',
+    'https://id.fedoraproject.org/scope/groups',
+    'https://id.fedoraproject.org/scope/cla',
+    ]
 
 # TODO - instead of 'develop', use the version from pkg_resources to figure out
 #        the right tag to link people to.  AGPL ftw.

From a819997238b2de250035fc19e03c606ffc20dc32 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 08 2017 14:04:52 +0000
Subject: [PATCH 699/1001] Remove deprecation warning on import


---

diff --git a/hubs/app.py b/hubs/app.py
index 702175a..60981cf 100755
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -9,7 +9,7 @@ import flask
 import flask.json
 import munch
 
-from flask.ext.oidc import OpenIDConnect
+from flask_oidc import OpenIDConnect
 
 import hubs.models
 

From 60e88bb3f7e619186d746032daf5a27ee75d5f26 Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Feb 08 2017 23:29:32 +0000
Subject: [PATCH 700/1001] Merge #314 `Cleanup the testing environment`


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 59866ee..2394c1e 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -14,14 +14,12 @@ import vcr
 
 import hubs.models
 
-cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
-json_path = os.path.join(
-    os.path.join(os.path.dirname(os.path.abspath(__file__))), 'data/')
+cassette_dir = os.path.join(dirname(__file__), 'vcr-request-data')
 
 
 class APPTest(unittest.TestCase):
     def setUp(self):
-        filename = cassette_dir + self.id()
+        filename = os.path.join(cassette_dir, self.id())
         self.vcr = vcr.use_cassette(filename, record_mode='new_episodes')
         self.vcr.__enter__()
 
@@ -155,6 +153,3 @@ class FakeAuthorization(object):
         self.avatar = 'avatar_src_url'
         self.nickname = username
         self.username = username
-
-    def __getitem__(self, key):
-        return self.dic[key]
diff --git a/hubs/tests/data/message_involved.json b/hubs/tests/data/message_involved.json
deleted file mode 100644
index fdfd0db..0000000
--- a/hubs/tests/data/message_involved.json
+++ /dev/null
@@ -1,137 +0,0 @@
-{
-    "timestamp": 1465567413.0,
-    "topic": "io.pagure.prod.pagure.issue.new",
-    "msg_id": "2016-0490127f-473f-4d01-ASDF-a864a56dc302",
-    "msg": {
-        "action": "created",
-        "comment": {
-            "body":
-            "hm, there is something odd the stackage page is inconsistent",
-            "created_at": "2016-06-10T14:03:31Z",
-            "html_url":
-            "https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438",
-            "id": 225190438,
-            "updated_at": "2016-06-10T14:03:31Z",
-            "url":
-            "https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438",
-            "user": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/pypingou",
-                "id": 1240038,
-                "login": "pypingou",
-                "site_admin": false,
-                "type": "User",
-                "url": "https://api.github.com/users/pypingou"
-            }
-        },
-        "fas_usernames": {
-            "fedora-infra": "github_org_fedora-infra",
-            "pypingou": "pingou"
-        },
-        "issue": {
-            "assignee": null,
-            "body":
-            "@juhp it seems that the stackage backend is broken:",
-            "closed_at": "2016-04-29T14:53:10Z",
-            "comments": 8,
-            "created_at": "2016-04-15T16:15:57Z",
-            "html_url":
-            "https://github.com/fedora-infra/anitya/issues/283",
-            "id": 148703615,
-            "labels": [],
-            "locked": false,
-            "milestone": null,
-            "number": 283,
-            "state": "closed",
-            "title": "stackage backend broken",
-            "updated_at": "2016-06-10T14:03:31Z",
-            "url":
-            "https://api.github.com/repos/fedora-infra/anitya/issues/283",
-            "user": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/pypingou",
-                "id": 1240038,
-                "login": "pypingou",
-                "site_admin": false,
-                "type": "User",
-                "url": "https://api.github.com/users/pypingou"
-            }
-        },
-        "organization": {
-            "description": "Fedora Infrastructure Team",
-            "id": 3316637,
-            "login": "fedora-infra",
-            "url": "https://api.github.com/orgs/fedora-infra"
-        },
-        "repository": {
-            "created_at": "2013-11-29T10:17:26Z",
-            "default_branch": "master",
-            "description": "A cross-distribution upstream release project",
-            "fork": false,
-            "forks": 33,
-            "forks_count": 33,
-            "full_name": "fedora-infra/anitya",
-            "has_downloads": true,
-            "has_issues": true,
-            "has_pages": false,
-            "has_wiki": false,
-            "homepage": "https://release-monitoring.org",
-            "html_url": "https://github.com/fedora-infra/anitya",
-            "id": 14798348,
-            "language": "Python",
-            "name": "anitya",
-            "open_issues": 25,
-            "open_issues_count": 25,
-            "owner": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/fedora-infra",
-                "id": 3316637,
-                "login": "fedora-infra",
-                "site_admin": false,
-                "type": "Organization",
-                "url": "https://api.github.com/users/fedora-infra"
-            },
-            "private": false,
-            "pushed_at": "2016-06-05T18:16:15Z",
-            "size": 4364,
-            "stargazers_count": 56,
-            "updated_at": "2016-06-10T09:43:58Z",
-            "url": "https://api.github.com/repos/fedora-infra/anitya",
-            "watchers": 56,
-            "watchers_count": 56
-        },
-        "sender": {
-            "gravatar_id": "",
-            "html_url": "https://github.com/pypingou",
-            "id": 1240038,
-            "login": "pypingou",
-            "site_admin": false,
-            "type": "User",
-            "url": "https://api.github.com/users/pypingou"
-        }
-    },
-    "arguments": {
-        "categories": [
-            "pagure"
-        ],
-        "contains": [],
-        "delta": 172800.0,
-        "end": 1465839365.0,
-        "grouped": false,
-        "meta": [],
-        "not_categories": [],
-        "not_packages": [],
-        "not_topics": [],
-        "not_users": [],
-        "order": "desc",
-        "packages": [],
-        "page": 1,
-        "rows_per_page": 1,
-        "start": 1465666565.0,
-        "topics": [],
-        "users": []
-    },
-    "count": 1,
-    "pages": 225,
-    "total": 225
-}
diff --git a/hubs/tests/data/message_not_involved.json b/hubs/tests/data/message_not_involved.json
deleted file mode 100644
index e72439a..0000000
--- a/hubs/tests/data/message_not_involved.json
+++ /dev/null
@@ -1,120 +0,0 @@
-{
-    "topic": "org.fedoraproject.prod.github.issue.comment",
-    "i": 1,
-    "msg": {
-        "action": "created",
-        "comment": {
-            "body":
-            "hm, there is something odd the stackage page is inconsistent",
-            "created_at": "2016-06-10T14:03:31Z",
-            "html_url":
-            "https://github.com/fedora-infra/anitya/issues/283#issuecomment-225190438",
-            "id": 225190438,
-            "updated_at": "2016-06-10T14:03:31Z",
-            "url":
-            "https://api.github.com/repos/fedora-infra/anitya/issues/comments/225190438",
-            "user": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/pypingou",
-                "id": 1240038,
-                "login": "pypingou",
-                "site_admin": false,
-                "type": "User",
-                "url": "https://api.github.com/users/pypingou"
-            }
-        },
-        "fas_usernames": {
-            "fedora-infra": "github_org_fedora-infra",
-            "pypingou": "pingou"
-        },
-        "issue": {
-            "assignee": null,
-            "body":
-            "@juhp it seems that the stackage backend is broken",
-            "closed_at": "2016-04-29T14:53:10Z",
-            "comments": 8,
-            "created_at": "2016-04-15T16:15:57Z",
-            "html_url":
-            "https://github.com/fedora-infra/anitya/issues/283",
-            "id": 148703615,
-            "labels": [],
-            "locked": false,
-            "milestone": null,
-            "number": 283,
-            "state": "closed",
-            "title": "stackage backend broken",
-            "updated_at": "2016-06-10T14:03:31Z",
-            "url":
-            "https://api.github.com/repos/fedora-infra/anitya/issues/283",
-            "user": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/pypingou",
-                "id": 1240038,
-                "login": "pypingou",
-                "site_admin": false,
-                "type": "User",
-                "url": "https://api.github.com/users/pypingou"
-            }
-        },
-        "organization": {
-            "description": "Fedora Infrastructure Team",
-            "id": 3316637,
-            "login": "fedora-infra",
-            "url": "https://api.github.com/orgs/fedora-infra"
-        },
-        "repository": {
-            "created_at": "2013-11-29T10:17:26Z",
-            "default_branch": "master",
-            "description":
-            "A cross-distribution upstream release monitoring project",
-            "fork": false,
-            "forks": 33,
-            "forks_count": 33,
-            "full_name": "fedora-infra/anitya",
-            "has_downloads": true,
-            "has_issues": true,
-            "has_pages": false,
-            "has_wiki": false,
-            "homepage": "https://release-monitoring.org",
-            "html_url": "https://github.com/fedora-infra/anitya",
-            "id": 14798348,
-            "language": "Python",
-            "name": "anitya",
-            "open_issues": 25,
-            "open_issues_count": 25,
-            "owner": {
-                "gravatar_id": "",
-                "html_url": "https://github.com/fedora-infra",
-                "id": 3316637,
-                "login": "fedora-infra",
-                "site_admin": false,
-                "type": "Organization",
-                "url": "https://api.github.com/users/fedora-infra"
-            },
-            "private": false,
-            "pushed_at": "2016-06-05T18:16:15Z",
-            "size": 4364,
-            "stargazers_count": 56,
-            "updated_at": "2016-06-10T09:43:58Z",
-            "url": "https://api.github.com/repos/fedora-infra/anitya",
-            "watchers": 56,
-            "watchers_count": 56
-        },
-        "sender": {
-            "gravatar_id": "",
-            "html_url": "https://github.com/pypingou",
-            "id": 1240038,
-            "login": "pypingou",
-            "site_admin": false,
-            "type": "User",
-            "url": "https://api.github.com/users/pypingou"
-        }
-    },
-    "msg_id": "2016-0490127f-473f-4d01-8e3a-a864a56dc302",
-    "signature":
-    "MNpAVdrPW78dcSe94FOS+/6QFBYo/LkrV5ee9tQedkhurHY1BGpaFHlU5l8cNVEpB7rr",
-    "source_name": "datanommer",
-    "source_version": "0.6.5",
-    "timestamp": 1465567413.0,
-    "topic": "org.fedoraproject.prod.github.issue.comment"
-}
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 3c24905..1ca2a8d 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -18,8 +18,6 @@ import hubs.models
 
 import fedmsg.config
 
-cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
-
 
 class HubsAPITest(hubs.tests.APPTest):
     def test_index_logged_out(self):
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 229d620..7579b19 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -9,84 +9,18 @@ import requests
 import vcr
 
 import hubs.models
+from hubs.tests import APPTest
 
-cassette_dir = dirname(dirname(__file__)) + '/vcr-request-data/'
 
-
-class WidgetTest(unittest.TestCase):
-    def setUp(self):
-        filename = cassette_dir + self.id()
-        self.vcr = vcr.use_cassette(filename, record_mode='new_episodes')
-        self.vcr.__enter__()
-
-        import hubs.app
-        hubs.app.fedmsg_config = {
-            'hubs.sqlalchemy.uri': 'sqlite://',  # in memory
-        }
-        hubs.app.session = hubs.models.init(
-            hubs.app.fedmsg_config['hubs.sqlalchemy.uri'],
-            create=True,
-        )
-        self.app = hubs.app.app.test_client()
-        self.app.testing = True
-        self.session = hubs.app.session
-        self.populate()
-
-    def tearDown(self):
-        self.vcr.__exit__()
-        self.session.remove()
+class WidgetTest(APPTest):
 
     def populate(self):
-        for user in ['devyani7', 'dhrish', 'shalini', 'ralph', 'decause']:
-            fullname = user.title()
-            hubs.models.User.get_or_create(
-                hubs.app.session, username=user, fullname=fullname)
-
-        hubs.app.session.flush()
-
+        super(WidgetTest, self).populate()
         hub = hubs.models.Hub.by_name('ralph')
         widget = hubs.models.Widget(
-            plugin='about',
-            index=500,
-            _config=json.dumps({"text": "Testing."}),
-        )
-
-        hub.widgets.append(widget)
-
-        widget = hubs.models.Widget(
             plugin='library',
             index=51,
             _config=json.dumps({"urls": "ralph/"})  # we must add a url or itll crash
         )
         hub.widgets.append(widget)
-
-        for team in ['i18n', 'infra', 'old']:
-            hub = hubs.models.Hub(name=team, summary="the %s team" % team)
-            if hub.name == 'old':
-                hub.last_refreshed = datetime.utcnow() - timedelta(days=100)
-                hub.last_updated = datetime.utcnow() - timedelta(days=200)
-
-            hubs.app.session.add(hub)
-            widget = hubs.models.Widget(plugin='meetings', index=11,
-                                        _config=json.dumps({'calendar': team}))
-            hub.widgets.append(widget)
-
-    # TODO - test that it is in the registry
-    # TODO - test that it has all the things it needs
-
-    def widget_instance(self, hubname, plugin):
-        hub = hubs.models.Hub.by_name(hubname)
-        if not hub:
-            raise ValueError("No such hub %r" % hubname)
-        for widget in hub.widgets:
-            if widget.plugin == plugin:
-                return widget
-        raise KeyError("No such widget found for %s/%s" % (hubname, plugin))
-
-    @staticmethod
-    def get_fedmsg(idx):
-        url = 'https://apps.fedoraproject.org/datagrepper/id'
-        response = requests.get(url, params=dict(id=idx))
-        if not bool(response):
-            raise IOError("Failed to talk to %r %r" % (response.url, response))
-        return response.json()
+        hubs.app.session.commit()
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 9182b56..ac7ddfc 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -18,12 +18,12 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
                 "urls": "ralph/"
             },
             "data": {
-                u"edit_url": u"/ralph/57/edit",
+                u"edit_url": u"/ralph/%d/edit" % widget.idx,
                 u"source_url": u"/source/library",
                 u"urls": [
                     u"<a href=\"ralph/\">ralph/</a>"
                 ],
-                u"widget_url": u"/ralph/57"
+                u"widget_url": u"/ralph/%d" % widget.idx,
             },
             "description": None,
             "hub": "ralph",
diff --git a/tox.ini b/tox.ini
index 37dd0c2..24d3f29 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,7 +4,6 @@ skipsdist = True
 
 
 [testenv]
-basepython = python2
 usedevelop = True
 deps =
     -rrequirements.txt

From 338e5d03e4ec10ab9ecea3d6e7ef68ddb4c146c3 Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:23:13 +0000
Subject: [PATCH 701/1001] Merge #312 `Improve the widget-loading system and fix some HTML/CSS problems`


---

diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
index 01f2382..3474786 100644
--- a/hubs/static/js/utils.js
+++ b/hubs/static/js/utils.js
@@ -12,23 +12,23 @@ var collapse_feed_entries = function(idx) {
 }
 
 // Load widgets
- function setup_widgets(base_url, widgets) {
-   console.log(base_url, widgets);
-   $.each(widgets, function(i, widget) {
-     $.ajax({
-       url: base_url + widget,
-       dataType: 'html',
-       success: function(html) {
-         $('#widget-' + widget).html(html);
-         setTimeout(function() {
-           $('#widget-' + widget + ' .panel').toggleClass('panel-visible');
-         }, 100);
-       },
-       error: function() {
-         $('#widget-' + widget).html('Got an error retrieving this widget.  Sorry :(');
-         console.log('error');
-         console.trace();
-       },
-     });
-   });
- }
+function setup_widgets() {
+    $("div.widget[data-url]").each(function() {
+        var element=$(this);
+        $.ajax({
+            url: element.attr("data-url"),
+            dataType: 'html',
+            success: function(html) {
+                element.html(html);
+                setTimeout(function() {
+                  element.find('.panel').toggleClass('panel-visible');
+                }, 100);
+            },
+            error: function() {
+                element.html('Got an error retrieving this widget.  Sorry :(');
+                console.log('error');
+                console.trace();
+            },
+        });
+    });
+}
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index fed9ae6..f5628f0 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -30,7 +30,7 @@
       {% endif %}
     </nav>
   
-    <div class="col-md-10 col-md-offset-2">
+    <div class="col-md-10">
       <div class="row">
         
         <!-- Left side of header -->
@@ -155,11 +155,7 @@
           </div>
           {% endif %}
 
-          <div id="left_widgets">
-          {% for widget in hub.left_widgets %}
-            <div id="widget-{{ widget.idx }}" class="widget row"></div>
-          {% endfor %}
-          </div>
+          {% include "includes/left_widgets.html" %}
         </div>
 
         <div class="col-md-{{ hub.right_width }}">
@@ -177,11 +173,7 @@
           </div>
           {% endif %}
 
-          <div id="right_widgets">
-            {% for widget in hub.right_widgets %}
-            <div id="widget-{{ widget.idx }}" class="widget row"></div>
-            {% endfor %}
-          </div>
+          {% include "includes/right_widgets.html" %}
         </div>
 
       </div>  <!-- /row -->
@@ -339,10 +331,7 @@ function visit_counter() {
 $(function() {
   visit_counter()
   
-  setup_widgets(
-    {{ url_for("hub", name=hub.name) }},
-    {{ hub.widgets_idx|tojson }}
-    );
+  setup_widgets();
   setup_edit_btns();
   
   {% if edit -%}
diff --git a/hubs/templates/includes/_rightpanel.html b/hubs/templates/includes/_rightpanel.html
deleted file mode 100644
index 2a9f511..0000000
--- a/hubs/templates/includes/_rightpanel.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="right_widgets">
-  {% for widget in hub.right_widgets %}
-  <div id="widget-{{ widget.idx }}" class="widget row"></div>
-  {% endfor %}
-</div>
diff --git a/hubs/templates/includes/left_widgets.html b/hubs/templates/includes/left_widgets.html
new file mode 100644
index 0000000..b0326e9
--- /dev/null
+++ b/hubs/templates/includes/left_widgets.html
@@ -0,0 +1,7 @@
+<div id="left_widgets">
+{% for widget in hub.left_widgets %}
+  <div id="widget-{{ widget.idx }}" class="widget row"
+       data-url="{{ url_for('widget_render', hub=hub.name, idx=widget.idx) }}"
+       ></div>
+{% endfor %}
+</div>
diff --git a/hubs/templates/includes/right_widgets.html b/hubs/templates/includes/right_widgets.html
new file mode 100644
index 0000000..d9b487a
--- /dev/null
+++ b/hubs/templates/includes/right_widgets.html
@@ -0,0 +1,7 @@
+<div id="right_widgets">
+  {% for widget in hub.right_widgets %}
+  <div id="widget-{{ widget.idx }}" class="widget row"
+       data-url="{{ url_for('widget_render', hub=hub.name, idx=widget.idx) }}"
+       ></div>
+  {% endfor %}
+</div>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 278b076..8586d2a 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -6,81 +6,54 @@
   <h1>My Stream</h1>
   <p>Notifications, actions, and other things of interest to me</p>
 </div>
-<ul class="nav-tabs " role="tablist">
-  <li class="nav-item">
-    <a class="nav-link active" href="#stream" role="tab" data-toggle="tab">My Stream</a>
-  </li>
-  <li class="nav-item">
-    <a class="nav-link" href="#actions" role="tab" data-toggle="tab">My Actions</a>
-  </li>
-  <li class="nav-item">
-    <a class="nav-link" href="#mentions" role="tab" data-toggle="tab">My Mentions</a>
-  </li>
-  <li class="nav-item">
-    <a class="nav-link" href="#saved" role="tab" data-toggle="tab">Saved Notifications</a>
-  </li>
-</ul>
 
-<!-- Tab panes -->
-<div class="tab-content">
-  <div role="tabpanel" class="tab-pane fade in active" id="stream">
-    <div class="container">
-      <div class="row">
-        <div class="col-sm-8 pull-left">
-          {% include "includes/_searchstream.html" %}
-          <div id="streamFeed"></div>
-        </div>
-        <div class="col-sm-4">
-          {% include "includes/_rightpanel.html" %}
-        </div>
-      </div>
-    </div>
-  </div>
+<div class="row">
+  <div class="col-sm-8">
 
-  <div role="tabpanel" class="tab-pane fade" id="actions">
-    <div class="container">
-      <div class="row">
+    <ul class="nav-tabs " role="tablist">
+      <li class="nav-item">
+        <a class="nav-link active" href="#stream" role="tab" data-toggle="tab">My Stream</a>
+      </li>
+      <li class="nav-item">
+        <a class="nav-link" href="#actions" role="tab" data-toggle="tab">My Actions</a>
+      </li>
+      <li class="nav-item">
+        <a class="nav-link" href="#mentions" role="tab" data-toggle="tab">My Mentions</a>
+      </li>
+      <li class="nav-item">
+        <a class="nav-link" href="#saved" role="tab" data-toggle="tab">Saved Notifications</a>
+      </li>
+    </ul>
+
+    <!-- Tab panes -->
+    <div class="tab-content">
+      <div role="tabpanel" class="tab-pane fade in active" id="stream">
         {% include "includes/_searchstream.html" %}
-        <div class="col-sm-8 pull-left">
-          <div id="actionsFeed"></div>
-        </div>
-        <div class="col-sm-4">
-          {% include "includes/_rightpanel.html" %}
-        </div>
+        <div id="streamFeed"></div>
       </div>
-    </div>
-  </div>
-  <div role="tabpanel" class="tab-pane fade" id="mentions">
-    <div class="container">
-      <div class="row">
+      <div role="tabpanel" class="tab-pane fade" id="actions">
+        {% include "includes/_searchstream.html" %}
+        <div id="actionsFeed"></div>
+      </div>
+      <div role="tabpanel" class="tab-pane fade" id="mentions">
         {% include "includes/_searchstream.html" %}
         <br/>
-        <div class="col-sm-8 pull-left">
-          <div id="mentionsFeed">
-            {% include "includes/_messages.html" %}
-          </div>
-          <div class="col-sm-4">
-            {% include "includes/_rightpanel.html" %}
-          </div>
+        <div id="mentionsFeed">
+          {% include "includes/_messages.html" %}
         </div>
       </div>
-    </div>
-  </div>
-  <div role="tabpanel" class="tab-pane fade" id="saved">
-    <div class="container">
-      <div class="row">
-        <br/>
+      <div role="tabpanel" class="tab-pane fade" id="saved">
         {% include "includes/_searchstream.html" %}
-        <div class="col-sm-8 pull-left">
-          <div id="savedFeed"></div>
-        </div>
-        <div class="col-sm-4">
-          {% include "includes/_rightpanel.html" %}
-        </div>
+        <div id="savedFeed"></div>
       </div>
     </div>
   </div>
+
+  <div class="col-sm-4">
+    {% include "includes/right_widgets.html" %}
+  </div>
 </div>
+
 <style>
  .jumbotron {
    margin-bottom: 0;
@@ -145,10 +118,7 @@
    });
  }
  $(function() {
-   setup_widgets(
-    {{ url_for("hub", name=hub.name) }},
-    {{ hub.widgets_idx|tojson }}
-    );
+   setup_widgets();
    setup_feeds();
  });
 </script>

From a322a9060aaec543c73165291e91afe04c200a0f Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:54:10 +0000
Subject: [PATCH 702/1001] Add a CachedFunction class


This class is a wrapper for a function that will cache its results until a
relevant message is emitted on the bus.

---

diff --git a/hubs/hinting.py b/hubs/hinting.py
deleted file mode 100755
index b1a8c2f..0000000
--- a/hubs/hinting.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from __future__ import unicode_literals
-
-import decorator
-
-import fedmsg.config
-
-import logging
-log = logging.getLogger('hubs.hinting')
-
-
-def hint(topics=None, categories=None, usernames=None, ubiquitous=False):
-    topics = topics or []
-    categories = categories or []
-    default_usernames = lambda x: []
-    usernames = usernames or default_usernames
-    ubiquitous = ubiquitous
-
-    @decorator.decorator
-    def wrapper(fn, *args, **kwargs):
-        return fn(*args, **kwargs)
-
-    def wrapper_wrapper(fn):
-        wrapped = wrapper(fn)
-        wrapped.hints = dict(
-            topics=topics,
-            categories=categories,
-            usernames_function=usernames,
-            ubiquitous=ubiquitous,
-        )
-        return wrapped
-
-    return wrapper_wrapper
-
-
-def prefixed(topic, prefix='org.fedoraproject'):
-    config = fedmsg.config.load_config()  # This is memoized for us.
-    return '.'.join([prefix, config['environment'], topic])
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 2394c1e..d761381 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -35,7 +35,7 @@ class APPTest(unittest.TestCase):
         self.app = hubs.app.app.test_client()
         self.app.testing = True
         self.session = hubs.app.session
-        from hubs.widgets.base import cache
+        from hubs.widgets.caching import cache
         cache.configure(backend='dogpile.cache.null',
                         replace_existing_backend=True)
         self.populate()
diff --git a/hubs/tests/test_widget_caching.py b/hubs/tests/test_widget_caching.py
new file mode 100644
index 0000000..967db0e
--- /dev/null
+++ b/hubs/tests/test_widget_caching.py
@@ -0,0 +1,73 @@
+from __future__ import unicode_literals
+
+from hubs.widgets.caching import cache, CachedFunction
+
+from mock import Mock
+from hubs.tests import APPTest
+from hubs.models import Hub, Widget
+
+
+class DummyFunction(CachedFunction):
+
+    def __init__(self, *args, **kwargs):
+        super(DummyFunction, self).__init__(*args, **kwargs)
+        self.execute_mock = Mock()
+
+    def execute(self, *args, **kwargs):
+        return self.execute_mock(*args, **kwargs)
+
+
+class CachedFunctionTest(APPTest):
+
+    def setUp(self):
+        super(CachedFunctionTest, self).setUp()
+        # Use a memory backend, not the default null backend, or we can't test
+        # anything.
+        cache.configure(backend='dogpile.cache.memory',
+                        replace_existing_backend=True)
+        self.w_instance = Widget.query.filter(
+            Hub.name == "ralph",
+            Widget.plugin == "about",
+            ).one()
+        self.fn = DummyFunction(self.w_instance)
+        cache.delete(self.fn.get_cache_key())
+
+    def tearDown(self):
+        cache.delete(self.fn.get_cache_key())
+        super(CachedFunctionTest, self).tearDown()
+
+    def test_get_cache_key(self):
+        self.assertEqual(
+            self.fn.get_cache_key(),
+            b"%d|DummyFunction" % self.w_instance.idx
+            )
+
+    def test_result_cached(self):
+        self.fn.execute_mock.return_value = "testing"
+        result = self.fn()
+        self.fn.execute_mock.assert_called_once_with()
+        self.assertEqual(result, "testing")
+        result = self.fn()
+        self.assertEqual(result, "testing")
+        # Check it hasn't been called a second time.
+        self.fn.execute_mock.assert_called_once()
+
+    def test_is_cached(self):
+        key = self.fn.get_cache_key()
+        self.assertFalse(self.fn.is_cached())
+        cache.set(key, "testing is_cached")
+        self.assertTrue(self.fn.is_cached())
+
+    def test_invalidate(self):
+        key = self.fn.get_cache_key()
+        cache.set(key, "testing invalidate")
+        self.fn.invalidate()
+        self.assertFalse(self.fn.is_cached())
+
+    def test_rebuild(self):
+        key = self.fn.get_cache_key()
+        cache.set(key, "testing rebuild")
+        self.fn.execute_mock.return_value = "testing"
+        self.fn.rebuild()
+        self.fn.execute_mock.assert_called_once()
+        self.assertEqual(cache.get(key), "testing")
diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
new file mode 100644
index 0000000..2eded91
--- /dev/null
+++ b/hubs/widgets/caching.py
@@ -0,0 +1,147 @@
+"""
+Attributes:
+    cache (dogpile.cache.region.CacheRegion): The cache where function results
+        will be stored. It is configured with the `fedora-hubs.cache` key in
+        fedmsg configuration.
+"""
+from __future__ import unicode_literals
+
+import datetime
+import dogpile
+import dogpile.cache
+import fedmsg.config
+import logging
+
+log = logging.getLogger(__name__)
+
+
+def _get_cache():
+    config = fedmsg.config.load_config()
+    cache_defaults = {
+        "backend": "dogpile.cache.dbm",
+        "expiration_time": 1,  # Expire every 1 second, for development
+        "arguments": {
+            "filename": "/var/tmp/fedora-hubs-cache.db",
+        },
+    }
+    cache = dogpile.cache.make_region()
+    cache.configure(**config.get('fedora-hubs.cache', cache_defaults))
+    return cache
+
+cache = _get_cache()
+
+
+class CachedFunction(object):
+    """
+    A function that has automatic caching and invalidation features.
+
+    This class is a wrapper for a function that will cache its results until a
+    relevant message is emitted on the bus.
+
+    To use this class, you must subclass it and implement a couple methods.
+    It is instantiated by passing a widget instance (database record) as only
+    argument, which lets it access the `.config` property and act accordingly.
+
+    You must implement the `execute()` method, which must return a
+    JSON-serializable value.
+
+    You must also implement the `should_invalidate()` method, which takes the
+    bus message as only argument, and returns `True` if the cache should be
+    rebuild, `False` otherwise.
+
+    To call the function, instanciate the class and execute it. You may also
+    call the `.get_data()` method.
+
+    Args:
+        instance (hubs.models.Widget): The widget instance.
+    """
+
+    # invalidate_filter = {}
+
+    def __init__(self, instance):
+        self.instance = instance
+
+    def execute(self):
+        """
+        The function to cache.
+
+        This is the main method, it must be implemented.
+
+        Returns:
+            dict or list: A JSON-serializable value that will be cached.
+        """
+        raise NotImplementedError
+
+    def get_cache_key(self):
+        return "|".join([
+            str(self.instance.idx),
+            self.__class__.__name__,
+        ]).encode('utf-8')
+
+    def get_data(self):
+        key = self.get_cache_key()
+        # log.debug("Accessing cache key %s", key)
+        return cache.get_or_create(
+            key, lambda: self.execute())
+
+    __call__ = get_data
+
+    # def _get_topic(self, message):
+    #     return message['topic']
+
+    # def _get_category(self, message):
+    #     return message['topic'].split('.')[3]
+
+    # def pass_filter(self, message):
+    #     topic_filter = self.invalidate_filter.get("topic")
+    #     if topic_filter and self._get_topic(message) not in topic_filter:
+    #         return False
+    #     category_filter = self.invalidate_filter.get("category")
+    #     if category_filter and \
+    #             self._get_category(message) not in category_filter:
+    #         return False
+    #     return True
+
+    def should_invalidate(self, message):
+        """
+        Tell the cache invalidator if the received message should invalidate
+        this function's cache.
+
+        Args:
+            message (dict): The recieved bus message.
+
+        Returns:
+            bool: If `True`, the cache will be rebuilt.
+        """
+        # if not self._pass_filter(message):
+        #     return False
+        return True
+
+    def is_cached(self):
+        """
+        Return a boolean indicating if the function's result is currently in the cache.
+
+        Returns:
+            bool: Whether the cache currently contains the function result.
+        """
+        result = cache.get(self.get_cache_key(), ignore_expiration=True)
+        return not isinstance(result, dogpile.cache.api.NoValue)
+
+    def invalidate(self):
+        """
+        Invalidate this function's cache.
+        """
+        key = self.get_cache_key()
+        if not self.is_cached():
+            log.debug("Not deleting cache key %s.  It is absent.", key)
+            return
+        log.debug("Deleting cache key %s.", key)
+        cache.delete(key)
+
+    def rebuild(self):
+        """
+        Rebuild this function's cache.
+        """
+        self.invalidate()
+        self.instance.hub.last_refreshed = datetime.datetime.utcnow()
+        self.get_data()

From 81125b1f916295de027e835048eeb6534a00e764 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:54:10 +0000
Subject: [PATCH 703/1001] Add a class for widget-specific views


---

diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
old mode 100755
new mode 100644
index b869094..cc9b4ca
--- a/hubs/widgets/chrome.py
+++ b/hubs/widgets/chrome.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs.widgets.base import wraps
+from functools import wraps
 from hubs.widgets import templating
 
 _panel_template = templating.environment.get_template(
@@ -9,8 +9,9 @@ _panel_heading_template = templating.environment.get_template(
     'templates/panel_heading.html')
 
 
+# FIXME: replace with template block extension
 def panel(title=None, klass="panel-default", key=None, footer_template=None):
-    def decorator(func):
+    def decorator(view, func):
         @wraps(func)
         def inner(*args, **kwargs):
             heading = ''
@@ -18,7 +19,8 @@ def panel(title=None, klass="panel-default", key=None, footer_template=None):
             if title:
                 heading = _panel_heading_template.render(title=title)
             if footer_template:
-                footer = footer_template.render(**kwargs)
+                footer = templating.environment.get_template(
+                    footer_template).render(**kwargs)
             content = func(*args, **kwargs)
             if key and not kwargs.get(key):
                 return content
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
new file mode 100644
index 0000000..f6f486a
--- /dev/null
+++ b/hubs/widgets/view.py
@@ -0,0 +1,111 @@
+from __future__ import unicode_literals, absolute_import
+
+import flask
+from flask.views import View
+
+
+class WidgetView(View):
+    """
+    This class is the skeleton of a widget-specific view.
+
+    You must subclass this class to use it in your view:
+
+    - the `name` attribute must be defined
+    - the `template_name` attribute must be defined, or the `get_template()`
+      method must be implemented
+    - the `get_context()` method must be implemented
+
+    Every widget must have a view with the name "`root`" registered to `['/']`,
+    which will be the main entry point for the widget.
+
+    The resulting endpoint will be composed using the widget name and the view
+    name as `<widget_name>_<view_name>`, for example `meetings_root`.
+    Remember that when you want to reverse the URL with `url_for`.
+
+    When reversing the URL, you need to pass the ``hub`` and ``idx`` kwargs,
+    which are respectively the hub name (`Hub.name`) and the widget instance
+    (the database record) primary key (`Widget.idx`).
+
+    Attributes:
+        name (str): The view name. It will be used to compose the URL endpoint,
+            following the "`<widget.name>_<view.name>`" convention.
+        url_rules (list): A list of URL rules that this view must be registered
+            for (like the `rule` parameter of Flask's `add_url_rule()`).
+        template_name (str): The template name to use for this view. It will be
+            looked for in the widget's template environment.
+        chrome (function): An optional chrome template wrapper.
+
+    This class is Flask-specific. If another framework were to be switched to,
+    it would have to be re-implemented.
+    """
+
+    name = None
+    url_rules = []
+    template_name = None
+    chrome = None
+
+    def __init__(self, widget):
+        """
+        Args:
+            widget (hubs.widgets.base.Widget): the widget that uses this view.
+        """
+        self.widget = widget
+        if self.name is None:
+            raise NotImplementedError
+
+    def get_context(self, instance, *args, **kwargs):
+        """
+        Return the template context for this view.
+
+        Args:
+            instance (hubs.models.Widget): the widget instance.
+        """
+        raise NotImplementedError
+
+    def get_template(self):
+        """
+        Return the template object, looking for `template_name` in the widget's
+        template environment.
+        """
+        if self.template_name is None:
+            return NotImplementedError
+        tpl_env = self.widget.get_template_environment()
+        template = tpl_env.get_template(self.template_name)
+        return template
+
+    def get_extra_context(self, instance, *args, **kwargs):
+        """
+        Add extra data to the template context.
+        """
+        # Put source links in all API results
+        return {
+            'source_url': flask.url_for(
+                'widget_source', name=self.widget.name),
+            'widget_url': flask.url_for(
+                '%s_root' % self.widget.name,
+                hub=instance.hub.name, idx=instance.idx),
+            'edit_url': flask.url_for(
+                'widget_edit', hub=instance.hub.name, idx=instance.idx),
+            'widget': self.widget,
+            'widget_instance': instance,
+        }
+
+    def _get_instance(self, *args, **kwargs):
+        from hubs.views.utils import get_widget_instance
+        hubname = kwargs.pop("hub")
+        widgetidx = kwargs.pop("idx")
+        return get_widget_instance(hubname, widgetidx)
+
+    def dispatch_request(self, *args, **kwargs):
+        """
+        The `dispatch_request` method that subclasses of `flask.views.View`
+        must implement. It binds the other methods together.
+        """
+        instance = self._get_instance(*args, **kwargs)
+        context = self.get_context(instance, *args, **kwargs)
+        context.update(self.get_extra_context(instance, *args, **kwargs))
+        template = self.get_template()
+        if self.chrome is None:
+            return self.get_template().render(**context)
+        else:
+            return self.chrome(template.render)(**context)

From b96f6eee158de1599ab70a74b2422ca7dbb8962f Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:54:10 +0000
Subject: [PATCH 704/1001] Create a base class for widgets


---

diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
new file mode 100644
index 0000000..fd6b3b3
--- /dev/null
+++ b/hubs/tests/test_widget_base.py
@@ -0,0 +1,110 @@
+from __future__ import unicode_literals
+
+from hubs.widgets.base import Widget
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.view import WidgetView
+
+from mock import Mock
+from hubs.tests import APPTest
+#import hubs.models
+
+
+class TestingWidget(Widget):
+    name = "testing"
+
+class TestingView(WidgetView):
+    name = "root"
+
+class TestingFunction(CachedFunction):
+    pass
+
+
+class WidgetTest(APPTest):
+
+    def setUp(self):
+        super(WidgetTest, self).setUp()
+        # Backup the URL map
+        self._old_url_map = (
+            self.app.application.url_map._rules[:],
+            self.app.application.url_map._rules_by_endpoint.copy()
+            )
+
+    def tearDown(self):
+        # Restore the URL map
+        self.app.application.url_map._rules = self._old_url_map[0]
+        self.app.application.url_map._rules_by_endpoint = self._old_url_map[1]
+        super(WidgetTest, self).tearDown()
+
+    def test_validate(self):
+        class LocalTestWidget(Widget):
+            views = {}
+            def get_views(self):
+                return self.views
+        test_widget = LocalTestWidget()
+        self.assertRaisesRegexp(
+            AttributeError, '.* "name" .*', test_widget.validate)
+        test_widget.name = "învalid næme"
+        self.assertRaisesRegexp(
+            AttributeError, '^Invalid widget name: ', test_widget.validate)
+        test_widget.name = "localtest"
+        self.assertRaisesRegexp(
+            AttributeError, '.* "position" .*', test_widget.validate)
+        test_widget.position = "invalid"
+        self.assertRaisesRegexp(
+            AttributeError, '.* "position" .*', test_widget.validate)
+        test_widget.position = "both"
+        self.assertRaisesRegexp(
+            AttributeError, '.* "root" .*', test_widget.validate)
+        test_widget.views["root"] = Mock()
+        test_widget.views["root"].url_rules = ["/invalid"]
+        self.assertRaisesRegexp(
+            AttributeError, '.* "/" .*', test_widget.validate)
+        test_widget.views["root"].url_rules = ["/"]
+        try:
+            test_widget.validate()
+        except AttributeError as e:
+            self.fail(e)
+
+    def test_list_views(self):
+        testing_widget = TestingWidget()
+        self.assertEqual(
+            testing_widget.get_views(),
+            {"root": TestingView}
+            )
+
+    def test_list_functions(self):
+        testing_widget = TestingWidget()
+        self.assertEqual(
+            testing_widget.get_cached_functions(),
+            {"TestingFunction": TestingFunction}
+            )
+
+    def test_list_views(self):
+        class TestView1(WidgetView):
+            name = "root"
+            url_rules = ["/", "/test-1/"]
+        class TestView2(WidgetView):
+            name = "test2"
+            url_rules = ["/test-2"]
+        testing_widget = TestingWidget()
+        testing_widget.get_views = Mock()
+        testing_widget.get_views.return_value = {
+            "root": TestView1(testing_widget),
+            "test2": TestView2(testing_widget),
+        }
+        testing_widget.register_routes(self.app.application)
+        # TestView1
+        self.assertIn("testing_root",
+                      self.app.application.url_map._rules_by_endpoint)
+        self.assertIn("testing_root", self.app.application.view_functions)
+        rules = list(self.app.application.url_map.iter_rules(endpoint="testing_root"))
+        self.assertEqual(len(rules), 2)
+        self.assertEqual(rules[0].rule, "/<hub>/w/testing/<int:idx>/")
+        self.assertEqual(rules[1].rule, "/<hub>/w/testing/<int:idx>/test-1/")
+        # TestView2
+        self.assertIn("testing_test2",
+                      self.app.application.url_map._rules_by_endpoint)
+        self.assertIn("testing_test2", self.app.application.view_functions)
+        rules = list(self.app.application.url_map.iter_rules(endpoint="testing_test2"))
+        self.assertEqual(len(rules), 1)
+        self.assertEqual(rules[0].rule, "/<hub>/w/testing/<int:idx>/test-2")
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
old mode 100755
new mode 100644
index 581532e..ecccf46
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -1,117 +1,129 @@
-from __future__ import unicode_literals
+from __future__ import unicode_literals, absolute_import
 
 import collections
-import datetime
-import functools
-import hashlib
-import json
-import sys
+import logging
+import re
 
-import dogpile.cache
-import flask
-import six.moves.urllib_parse
+from importlib import import_module
+from .caching import CachedFunction
+from .view import WidgetView
 
-import fedmsg.config
 
-import logging
 log = logging.getLogger(__name__)
 
-config = fedmsg.config.load_config()
-cache_defaults = {
-    "backend": "dogpile.cache.dbm",
-    "expiration_time": 1,  # Expire every 1 second, for development
-    "arguments": {
-        "filename": "/var/tmp/fedora-hubs-cache.db",
-    },
-}
-cache = dogpile.cache.make_region()
-cache.configure(**config.get('fedora-hubs.cache', cache_defaults))
-
-
 Argument = collections.namedtuple(
-    'Argument', ('name', 'default', 'validator', 'help'))
-
-
-def argument(name, default, validator, help):
-    def decorator(func):
-        @wraps(func)
-        def inner(*args, **kwargs):
-            return func(*args, **kwargs)
-
-        inner.widget_arguments.append(Argument(name, default, validator, help))
-        return inner
-    return decorator
-
-
-def AGPLv3(name):
-    def decorator(func):
-        @wraps(func)
-        def inner(session, widget, *args, **kwargs):
-            result = func(session, widget, *args, **kwargs)
-            result['source_url'] = flask.url_for('widget_source', name=name)
-            result['widget_url'] = flask.url_for(
-                'widget_render', hub=widget.hub.name, idx=widget.idx)
-            result['edit_url'] = flask.url_for(
-                'widget_edit', hub=widget.hub.name, idx=widget.idx)
-            result['widget'] = widget
-            return result
-
-        return inner
-    return decorator
-
-
-def smartcache(func):
-    @wraps(func)
-    def inner(session, widget, *args, **kwargs):
-        key = cache_key_generator(widget, *args, **kwargs)
-        creator = lambda: func(session, widget, *args, **kwargs)
-        #log.debug("Accessing cache key %s", key)
-        return cache.get_or_create(key, creator)
+    'Argument', ('name', 'label', 'default', 'validator', 'help'))
 
-    return inner
 
-
-def invalidate_cache(widget, *args, **kwargs):
-    key = cache_key_generator(widget, *args, **kwargs)
-
-    value = cache.get(key, ignore_expiration=True)
-    if isinstance(value, dogpile.cache.api.NoValue):
-        log.debug("Not deleting cache key %s.  It is absent.", key)
-        return
-
-    widget.hub.last_refreshed = datetime.datetime.utcnow()
-    log.debug("Deleting cache key %s.", key)
-    cache.delete(key)
-
-
-def cache_key_generator(widget, *args, **kwargs):
-    return "|".join([
-        str(widget.idx),
-        json.dumps(args),
-        json.dumps(kwargs),
-    ]).encode('utf-8')
-
-
-def wraps(original):
-    @functools.wraps(original)
-    def decorator(subsequent):
-        subsequent = functools.wraps(original)(subsequent)
-        subsequent.widget_arguments = getattr(original, 'widget_arguments', [])
-        return subsequent
-    return decorator
-
-
-def widget_route(**options):
-    """Register a view for the current widget.
-
-    This decorator can be used to expose a specific function below a widget's
-    URL endpoint. Refer to the "Widget-specific views" section in the
-    documentation to learn how to construct the corresponding URL.
+class Widget(object):
+    """
+    The main widget class, you must subclass it to create a widget.
+
+    Args:
+        name (str): The widget name. It will not be displayed in the UI, but
+            will appear in some URLs, so be careful to only use simple,
+            URL-compatible characters.
+        position (str): The position of the widget in the rendered page. It
+            should be one of the following values: 'left', 'right', or 'both'.
+        arguments (list): A list of dictionaries that describe a widget's
+            configuration. See `hubs.widgets.base.Argument`.
     """
-    def decorator(func):
-        options["view_func_name"] = func.__name__
-        mdict = sys.modules[func.__module__].__dict__
-        mroutes = mdict.setdefault('ROUTES', [])
-        mroutes.append(options)
-        return func
-    return decorator
+
+    name = None
+    position = None
+    arguments = []
+
+    def validate(self):
+        """Ensure that the widget has the bits it needs."""
+        if self.name is None:
+            raise AttributeError('Widgets must have a "name" attribute')
+        if not re.match('^[\w_.-]+$', self.name):
+            raise AttributeError(
+                'Invalid widget name: %r. ' % self.name +
+                'Please use URL-compatible characters.')
+        if self.position not in ['left', 'right', 'both']:
+            raise AttributeError(
+                '%r\'s "position" is not: `left`, `right` or `both`'
+                % self.name)
+        root_view = self.get_views().get("root")
+        if root_view is None:
+            raise AttributeError(
+                'Widgets must have a "root" view, please refer to the '
+                'documentation.')
+        if "/" not in root_view.url_rules:
+            raise AttributeError(
+                'The root view must be registered for the "/" URL rule.')
+
+    def get_arguments(self):
+        return [Argument(**arg) for arg in self.arguments]
+
+    def get_template_environment(self):
+        """
+        Get the template environment that widget-specific views will use.
+        """
+        # We may have widget-specific template environment one day
+        # (when widget templates are stored in the widget's directory
+        # instead of a common widget template directory).
+        # When that happens, it should be cached in a Widget attribute.
+        from hubs.widgets.templating import environment
+        return environment
+
+    def _get_local_subclasses(self, parent_class):
+        """
+        Returns the subclasses of the `parent_class` defined in this widget's
+        Python module.
+        """
+        result = []
+        widget_module = import_module(self.__module__)
+        for objname in dir(widget_module):
+            obj = getattr(widget_module, objname)
+            if type(obj) != type(object):
+                continue  # we only look for classes
+            if not issubclass(obj, parent_class):
+                continue  # we only want subclasses of the parent_class
+            if obj.__module__ != self.__module__:
+                # we don't want locally imported classes (like the
+                # parent_class itself)
+                continue
+            result.append(obj)
+        return result
+
+    def get_views(self):
+        """
+        Returns:
+            dict: A dictionary of the widget-specific views, indexed by their
+                `name` attribute.
+        """
+        return dict([
+            (view.name, view) for view in
+            self._get_local_subclasses(WidgetView)
+            ])
+
+    def register_routes(self, app):
+        """
+        Register the widget-specific views in the web framework.
+
+        Args:
+            app (flask.Flask): The Flask application to register the views
+                with.
+
+        This function is Flask-specific.
+        """
+        for view_name, view_class in self.get_views().items():
+            endpoint = "%s_%s" % (self.name, view_name)
+            view_func = view_class.as_view(endpoint, self)
+            for url_rule in view_class.url_rules:
+                rule = "/<hub>/w/%s/<int:idx>/%s" % (
+                    self.name, url_rule.lstrip("/"))
+                app.add_url_rule(rule, view_func=view_func)
+
+    def get_cached_functions(self):
+        """
+        Returns:
+            dict: A dictionary of the widget's cached functions, indexed by
+                their class name.
+        """
+        result = {}
+        for fn_class in self._get_local_subclasses(CachedFunction):
+            result[fn_class.__name__] = fn_class
+        return result

From c178b3e690b989153cbc0572c0c78b30eba211dd Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:54:10 +0000
Subject: [PATCH 705/1001] Create a widget registry class


---

diff --git a/hubs/app.py b/hubs/app.py
old mode 100755
new mode 100644
index 60981cf..0e81a8d
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -104,5 +104,12 @@ def check_auth():
     else:
         flask.g.auth = munch.Munch(logged_in=False)
 
+# Register widgets
+import hubs.widgets
+hubs.widgets.registry.register_list(app.config["WIDGETS"])
 
+# Register routes
 import hubs.views
+
+# Add widget-specific routes
+hubs.widgets.registry.register_routes(app)
diff --git a/hubs/default_config.py b/hubs/default_config.py
old mode 100755
new mode 100644
index e540ad9..be038ad
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -32,3 +32,29 @@ OIDC_SCOPES = [
 # TODO - instead of 'develop', use the version from pkg_resources to figure out
 #        the right tag to link people to.  AGPL ftw.
 SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'  # /hubs/widgets/badges.py'
+
+
+WIDGETS = [
+    'hubs.widgets.dummy.Dummy',
+    'hubs.widgets.stats.Stats',
+    'hubs.widgets.rules.Rules',
+    'hubs.widgets.sticky.Sticky',
+    'hubs.widgets.about.About',
+    'hubs.widgets.badges.Badges',
+    'hubs.widgets.library.Library',
+    'hubs.widgets.linechart.Linechart',
+    'hubs.widgets.fedmsgstats.FedmsgStats',
+    'hubs.widgets.feed.Feed',
+    'hubs.widgets.subscriptions.Subscriptions',
+    'hubs.widgets.meetings.Meetings',
+    'hubs.widgets.pagure_pr.PagurePRs',
+    'hubs.widgets.github_pr.GitHubPRs',
+    'hubs.widgets.pagureissues.PagureIssues',
+    'hubs.widgets.githubissues.GitHubIssues',
+    'hubs.widgets.bugzilla.Bugzilla',
+    'hubs.widgets.fhosted.FedoraHosted',
+    'hubs.widgets.memberships.Memberships',
+    'hubs.widgets.contact.Contact',
+    'hubs.widgets.workflow.pendingacls.PendingACLs',
+    'hubs.widgets.workflow.updates2stable.Updates2Stable',
+    ]
diff --git a/hubs/tests/test_widget_routes.py b/hubs/tests/test_widget_routes.py
deleted file mode 100644
index 7eae714..0000000
--- a/hubs/tests/test_widget_routes.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from __future__ import unicode_literals
-
-import hubs.widgets
-
-from mock import Mock
-from hubs.models import Hub, Widget
-from hubs.tests import APPTest
-
-class WidgetRoutesTest(APPTest):
-
-    def setUp(self):
-        super(WidgetRoutesTest, self).setUp()
-        # Backup the URL map
-        self._old_url_map = (
-            self.app.application.url_map._rules[:],
-            self.app.application.url_map._rules_by_endpoint.copy()
-            )
-
-    def tearDown(self):
-        for module in hubs.widgets.registry.values():
-            if hasattr(module, 'ROUTES'):
-                delattr(module, 'ROUTES')
-        # Restore the URL map
-        self.app.application.url_map._rules = self._old_url_map[0]
-        self.app.application.url_map._rules_by_endpoint = self._old_url_map[1]
-        super(WidgetRoutesTest, self).tearDown()
-
-    def test_routes_variable(self):
-        calls = []
-        def mock_view(*args, **kw):
-            calls.append({'args': args, 'kw': kw})
-            return ''
-        mock_view.__module__ = 'hubs.widgets.contact'
-        hubs.widgets.contact.mock_view = mock_view
-        hubs.widgets.contact.ROUTES = [{
-            'rule': 'dummy-url',
-            'endpoint': 'dummy-endpoint',
-            'view_func_name': 'mock_view',
-        }]
-        hubs.views._load_widget_views()
-        added_rules = list(
-            self.app.application.url_map.iter_rules(
-                endpoint='contact_dummy-endpoint')
-            )
-        self.assertEqual(len(added_rules), 1)
-        self.assertEqual(
-            added_rules[0].rule,
-            '/<hub>/<int:idx>/widget/dummy-url'
-            )
-        widget = self.session.query(Widget).filter_by(
-            plugin="contact").first()
-        self.app.get('/%s/%s/widget/dummy-url'
-                     % (widget.hub.name, widget.idx))
-        self.assertEqual(len(calls), 1)
-        # Check arguments: session and widget
-        self.assertEqual(calls[0]["args"][0].__class__, self.session.__class__)
-        self.assertEqual(calls[0]["args"][1], widget)
-
-    def test_decorator(self):
-        def mock_view(*args, **kw):
-            return ''
-        mock_view.__module__ = 'hubs.widgets.feed'
-        hubs.widgets.feed.mock_view = hubs.widgets.base.widget_route(
-            rule='dummy-url', endpoint='dummy-endpoint')(mock_view)
-        self.assertEqual(
-            hubs.widgets.feed.ROUTES,
-            [{'view_func_name': 'mock_view',
-              'endpoint': 'dummy-endpoint',
-              'rule': 'dummy-url'}]
-            )
diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
index 54f6bd1..1c97db4 100644
--- a/hubs/views/__init__.py
+++ b/hubs/views/__init__.py
@@ -6,45 +6,3 @@ from .widget import *
 from .user import *
 from .api import *
 from .plus_plus import *
-
-#
-# Add widget-specific routes
-#
-
-import flask
-import functools
-import hubs.models
-import hubs.widgets
-from sqlalchemy.orm.exc import NoResultFound
-from hubs.app import app, session
-from .utils import get_widget
-
-def _widget_view_decorator(func):
-    """
-    This internal decorator will edit the view function arguments.
-
-    It will:
-    - remove the hub name and the widget primary key
-    - add the database session and the widget instance
-    """
-    @functools.wraps(func)
-    def inner(*args, **kwargs):
-        hubname = kwargs.pop("hub")
-        widgetidx = kwargs.pop("idx")
-        widget = get_widget(hubname, widgetidx)
-        return func(session, widget, *args, **kwargs)
-    return inner
-
-def _load_widget_views():
-    for name, module in hubs.widgets.registry.items():
-        for params in getattr(module, 'ROUTES', []):
-            params["rule"] = "/<hub>/<int:idx>/widget/" \
-                             + params["rule"].lstrip("/")
-            if not params.get("endpoint"):
-                params["endpoint"] = params["view_func_name"]
-            params["endpoint"] = "%s_%s" % (name, params["endpoint"])
-            params["view_func"] = _widget_view_decorator(
-                getattr(module, params.pop("view_func_name")))
-            app.add_url_rule(**params)
-
-_load_widget_views()
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
old mode 100755
new mode 100644
index 95253e7..6d5f257
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -1,132 +1,10 @@
+"""
+Attributes:
+    registry (dict): This dictionary is a registry of available widgets in
+        Fedora Hubs.
+"""
 from __future__ import unicode_literals
 
-from hubs.widgets import dummy
-from hubs.widgets import stats
-from hubs.widgets import rules
-from hubs.widgets import sticky
-from hubs.widgets import about
-from hubs.widgets import badges
-from hubs.widgets import library
-from hubs.widgets import linechart
-from hubs.widgets import fedmsgstats
-from hubs.widgets import feed
-from hubs.widgets import subscriptions
-from hubs.widgets import meetings
-from hubs.widgets import pagure_pr
-from hubs.widgets import github_pr
-from hubs.widgets import pagureissues
-from hubs.widgets import githubissues
-from hubs.widgets import bugzilla
-from hubs.widgets import fhosted
-from hubs.widgets import memberships
-from hubs.widgets import contact
+from .registry import WidgetRegistry
 
-from hubs.widgets.workflow import pendingacls
-from hubs.widgets.workflow import updates2stable
-
-from hubs.widgets.base import AGPLv3, smartcache
-
-registry = {
-    'dummy': dummy,
-    'stats': stats,
-    'rules': rules,
-    'sticky': sticky,
-    'about': about,
-    'badges': badges,
-    'library': library,
-    'linechart': linechart,
-    'fedmsgstats': fedmsgstats,
-    'feed': feed,
-    'subscriptions': subscriptions,
-    'meetings': meetings,
-    'pagure_pr': pagure_pr,
-    'github_pr': github_pr,
-    'pagureissues': pagureissues,
-    'githubissues': githubissues,
-    'bugzilla': bugzilla,
-    'fedorahosted': fhosted,
-    'memberships': memberships,
-    'contact': contact,
-
-    'workflow.pendingacls': pendingacls,
-    'workflow.updates2stable': updates2stable,
-}
-
-
-def validate_registry(registry):
-    """ Ensure that the widgets in the registry have the bits they need.
-
-    - Check that a template is available and has a render callable.
-    - Look for a data function, etc..
-    """
-    for name, module in registry.items():
-        if not hasattr(module, 'template'):
-            raise AttributeError('%r has no "template"' % module)
-        if not hasattr(module.template, 'render'):
-            raise AttributeError('%r\'s template has no "render"' % module)
-        if not callable(module.template.render):
-            raise TypeError('%r\'s template.render not callable' % module)
-
-        if not hasattr(module, 'position'):
-            raise AttributeError('%r has not "position" function' % module)
-        if module.position not in ['left', 'right', 'both']:
-            raise TypeError(
-                '%r\'s "position" is not: `left`, `right` or `both`'
-                % module)
-
-        if not hasattr(module, 'data'):
-            raise AttributeError('%r has not "data" function' % module)
-        if not callable(module.data):
-            raise TypeError('%r\'s "data" is not callable' % module)
-
-        if hasattr(module, 'chrome'):
-            if not callable(module.chrome):
-                raise TypeError('%r\'s "chrome" is not callable' % module)
-
-
-def prepare_registry(registry):
-    """ Do things ahead of time that we can to the registry.
-
-    - Wrap a cache layer around the data functions.
-    - Wrap any chrome around the render functions.
-    """
-    for name, module in registry.items():
-        # Wrap chrome around the render function
-        module.render = module.template.render
-        if hasattr(module, 'chrome'):
-            module.render = module.chrome(module.render)
-
-        # Put source links in all API results
-        module.data = AGPLv3(name)(module.data)
-
-        # Wrap the data functions in a cache layer to be invalidated by fedmsg
-        # TODO -- we could just do this with a decorator to be explicit..
-        module.data = smartcache(module.data)
-
-
-validate_registry(registry)
-prepare_registry(registry)
-
-
-def get_site_vars():
-    import flask
-    return dict(
-        session=flask.app.session,
-        g=flask.g,
-        url_for=flask.url_for,
-    )
-
-
-def render(module, session, widget, *args, **kwargs):
-    """ Main API entry point.
-
-    Call this to render a widget into HTML
-    """
-    # The API returns exactly this data.  Shared cache
-    data = module.data(session, widget, *args, **kwargs)
-
-    # Also expose some site-level info to the widget here at render-time
-    data.update(get_site_vars())
-
-    # Use the API data to fill out a template, and potentially decorate it.
-    return module.render(**data)
+registry = WidgetRegistry()
diff --git a/hubs/widgets/registry.py b/hubs/widgets/registry.py
new file mode 100644
index 0000000..006eced
--- /dev/null
+++ b/hubs/widgets/registry.py
@@ -0,0 +1,68 @@
+from __future__ import unicode_literals
+
+from importlib import import_module
+from six.moves import UserDict
+from hubs.widgets.base import Widget
+
+
+class WidgetRegistry(UserDict):
+    """
+    The widget registry.
+
+    It behaves like a dictionary where widget names are keys and widget class
+    instances are values.  There are additional methods to register widgets and
+    widget-specific routes.
+    """
+
+    def register_list(self, widget_list):
+        """
+        Register a list of widget class paths.
+
+        Args:
+            widget_list (list): List of Python paths to widget classes that
+                must be registered.
+        """
+        for widget_path in widget_list:
+            self.register(widget_path)
+
+    def register(self, widget_path):
+        """
+        Register a widget.
+
+        Args:
+            widget_path (str): Python path to the subclass of
+                `hubs.widgets.base.Widget`.
+        """
+        mod_path, _, cls_name = widget_path.rpartition('.')
+        mod = import_module(mod_path)
+        try:
+            widget_class = getattr(mod, cls_name)
+        except AttributeError:
+            raise ValueError("Can't find widget %s" % widget_path)
+        if not issubclass(widget_class, Widget):
+            raise ValueError(
+                "Widget %s must be a subclass of %s.Widget"
+                % (widget_path, Widget.__module__))
+        widget = widget_class()
+        if not widget.name:
+            prefix = 'hubs.widgets.'
+            if widget_path.startswith(prefix):
+                widget.name = widget_path[len(prefix):]
+            else:
+                widget.name = widget_path
+        widget.validate()
+        self.data[widget.name] = widget
+
+    def register_routes(self, app):
+        """
+        Register widget-specific routes with the provided app.
+
+        This is not done automatically to allow widgets to be registered
+        without instantiating the Flask application.
+
+        Args:
+            app (flask.Flask): The Flask application to register the views
+                with.
+        """
+        for widget in self.values():
+            widget.register_routes(app)
diff --git a/populate.py b/populate.py
index d4b262d..503b0e9 100755
--- a/populate.py
+++ b/populate.py
@@ -6,12 +6,24 @@ from __future__ import unicode_literals
 import json
 
 import hubs.models
+import hubs.widgets
 
 import fedmsg.config
 fedmsg_config = fedmsg.config.load_config()
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
+# Register widgets we will use
+hubs.widgets.registry.register_list([
+    "hubs.widgets.contact.Contact",
+    "hubs.widgets.stats.Stats",
+    "hubs.widgets.rules.Rules",
+    "hubs.widgets.meetings.Meetings",
+    "hubs.widgets.about.About",
+    "hubs.widgets.sticky.Sticky",
+    "hubs.widgets.dummy.Dummy",
+    ])
+
 users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',
          'abompard', 'decause', 'ralph', 'lmacken', 'croberts', 'mattdm',
          'pravins', 'keekri', 'linuxmodder', 'bee2502', 'jflory7']

From eb85faa6512dcc5a63cbdd22909b9da85ccf503a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:54:10 +0000
Subject: [PATCH 706/1001] Adapt the models to the new widget class


---

diff --git a/hubs/models.py b/hubs/models.py
old mode 100755
new mode 100644
index 63fbcb1..d322437
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -30,6 +30,7 @@ import os
 import random
 
 import bleach
+import dogpile
 import sqlalchemy as sa
 from sqlalchemy import create_engine
 from sqlalchemy.ext.declarative import declarative_base
@@ -292,10 +293,11 @@ class Hub(BASE):
 
 
 def _config_default(context):
-    plugin_name = context.current_parameters['plugin']
-    plugin = hubs.widgets.registry[plugin_name]
-    arguments = getattr(plugin.data, 'widget_arguments', [])
-    return json.dumps(dict([(arg.name, arg.default) for arg in arguments]))
+    widget_name = context.current_parameters['plugin']
+    widget = hubs.widgets.registry[widget_name]
+    return json.dumps(dict([
+        (arg.name, arg.default) for arg in widget.get_arguments()
+        ]))
 
 
 class Widget(BASE):
@@ -334,8 +336,11 @@ class Widget(BASE):
     def __json__(self):
         session = object_session(self)
         module = hubs.widgets.registry[self.plugin]
-        data = module.data(session, self, **self.config)
+        root_view = module.get_views()["root"](module)
+        data = root_view.get_context(self)
+        data.update(root_view.get_extra_context(self))
         data.pop('widget', None)
+        data.pop('widget_instance', None)
         return {
             'id': self.idx,
             # TODO -- use flask.url_for to get the url for this widget
@@ -355,11 +360,6 @@ class Widget(BASE):
     def module(self):
         return hubs.widgets.registry[self.plugin]
 
-    def render(self):
-        session = object_session(self)
-        render = hubs.widgets.render
-        return render(self.module, session, self, **self.config)
-
 
 class User(BASE):
     __tablename__ = 'users'

From 57569e8d718edf8733eba6b4f4c242f7cbce111d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:54:10 +0000
Subject: [PATCH 707/1001] Rename get_widget to get_widget_instance


To make the distinction clearer betweed widgets (subclasses of
hubs.widgets.base.Widget) and widget instances (database records,
instances of hubs.models.Widget).

---

diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index e2d4bd2..df05992 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -20,7 +20,7 @@ def get_hub(name, session=None):
         flask.abort(404)
 
 
-def get_widget(hub, idx, session=None):
+def get_widget_instance(hub, idx, session=None):
     """ Utility shorthand to get a widget and 404 if not found. """
     if session is None:
         session = flask.g.db
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index f413985..613e47d 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -3,14 +3,14 @@ from __future__ import unicode_literals, absolute_import
 import datetime
 import flask
 
-from hubs.app import app, session
-from .utils import get_widget
+from hubs.app import app
+from .utils import get_widget_instance
 
 
 @app.route('/<hub>/<int:idx>/')
 @app.route('/<hub>/<int:idx>')
 def widget_render(hub, idx):
-    widget = get_widget(hub, idx)
+    widget = get_widget_instance(hub, idx)
     return widget.render()  # , edit=False)
     # was blocking all widgets from working, sorry!
 
@@ -18,7 +18,7 @@ def widget_render(hub, idx):
 @app.route('/<hub>/<int:idx>/json')
 @app.route('/<hub>/<int:idx>/json/')
 def widget_json(hub, idx):
-    widget = get_widget(hub, idx)
+    widget = get_widget_instance(hub, idx)
     response = flask.jsonify(widget.__json__())
     # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
     return response
@@ -34,7 +34,7 @@ def widget_edit(hub, idx):
 
 
 def widget_edit_get(hub, idx):
-    widget = get_widget(hub, idx)
+    widget = get_widget_instance(hub, idx)
     return flask.render_template(
         'edit.html',
         hub=hub,
@@ -44,7 +44,7 @@ def widget_edit_get(hub, idx):
 
 
 def widget_edit_post(hub, idx):
-    widget = get_widget(hub, idx)
+    widget = get_widget_instance(hub, idx)
     error = False
     config = {}
     for arg in widget.module.data.widget_arguments:
@@ -80,7 +80,7 @@ def widget_edit_post(hub, idx):
 @app.route('/<hub>/<int:idx>/delete', methods=['POST'])
 def widget_edit_delete(hub, idx):
     ''' Remove a widget from a hub. '''
-    widget = get_widget(hub, idx)
+    widget = get_widget_instance(hub, idx)
     flask.g.db.delete(widget)
     try:
         flask.g.db.commit()

From d505f7b6be1f007151764f84c075cde45d61447a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 708/1001] Adapt views and templates to the new widget class


---

diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index 422cb84..76fc4ac 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -8,7 +8,7 @@
       <div class="modal-header">
         <button type="button" class="close" data-dismiss="modal">&times;</button>
         <h4 class="modal-title">
-          Adding widget {% if widget %}"{{ widget_name }}"{% endif -%} to hub: {{ hub.name }}
+          Adding {% if widget %}widget "{{ widget.name }}"{% else %}a widget{% endif %} to hub: {{ hub.name }}
         </h4>
       </div>
       <div class="modal-body">
@@ -19,12 +19,11 @@
             {% endfor %}
         </select>
         {% elif widget %}
-        <input name="widget_name" type="hidden" value="{{ widget_name }}">
+        <input name="widget_name" type="hidden" value="{{ widget.name }}">
         <input name="position" type="hidden" value="{{ side }}">
-        {% if widget.data.widget_arguments %}
-          {% for arg in widget.data.widget_arguments %}
+          {% for arg in widget.get_arguments() %}
             <fieldset class="form-group ">
-              <strong>{{ arg.name | capitalize }}</strong>
+              <strong>{{ arg.label | capitalize }}</strong>
               <input id="{{ arg.name }}" class="form-control" type="text"
                 value="{{ arg.default if arg.default else '' }}"
                 name="{{ arg.name }}" />
@@ -34,10 +33,9 @@
                 <small class="text-muted">{{ arg.help }}</small>
               </div>
             {% endif %}
+          {% else %}
+            <p>Nothing to configure</p>
           {% endfor %}
-        {% else %}
-          <p>Nothing to configure</p>
-        {% endif %}
         {% endif %}
       </div>
       <div class="modal-footer">
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index a04145a..44a7391 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -8,29 +8,27 @@
         <h4 class="modal-title">Configure {{ name }}</h4>
       </div>
       <div class="modal-body">
-      {% if widget.module.data.widget_arguments %}
-        {% for arg in widget.module.data.widget_arguments %}
-          <fieldset class="form-group ">
-            <strong>{{ arg.name | capitalize }}</strong>
-            <input id="{{ arg.name }}" class="form-control" type="text"
+      {% for arg in widget.module.get_arguments() %}
+        <fieldset class="form-group ">
+          <strong>{{ arg.label | capitalize }}</strong>
+          <input id="{{ arg.name }}" class="form-control" type="text"
               value="{{ widget.config.get(arg.name, arg.default if arg.default else '') }}"
               name="{{ arg.name }}" />
-          </fieldset>
-          {% if arg.help %}
-            <div>
-              <small class="text-muted">{{ arg.help }}</small>
-            </div>
-          {% endif %}
-        {% endfor %}
+        </fieldset>
+        {% if arg.help %}
+          <div>
+            <small class="text-muted">{{ arg.help }}</small>
+          </div>
+        {% endif %}
       {% else %}
         <p>Nothing to configure</p>
-      {% endif %}
+      {% endfor %}
       </div>
       <div class="modal-footer">
         <button type="button" class="btn btn-default" data-dismiss="modal">
           Close
         </button>
-        {% if widget.module.data.widget_arguments %}
+        {% if widget.module.get_arguments() %}
         <button type="submit" class="btn btn-default">
           Save
         </button>
diff --git a/hubs/templates/includes/left_widgets.html b/hubs/templates/includes/left_widgets.html
index b0326e9..032a026 100644
--- a/hubs/templates/includes/left_widgets.html
+++ b/hubs/templates/includes/left_widgets.html
@@ -1,7 +1,7 @@
 <div id="left_widgets">
 {% for widget in hub.left_widgets %}
   <div id="widget-{{ widget.idx }}" class="widget row"
-       data-url="{{ url_for('widget_render', hub=hub.name, idx=widget.idx) }}"
+       data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
        ></div>
 {% endfor %}
 </div>
diff --git a/hubs/templates/includes/right_widgets.html b/hubs/templates/includes/right_widgets.html
index d9b487a..a0b2a3b 100644
--- a/hubs/templates/includes/right_widgets.html
+++ b/hubs/templates/includes/right_widgets.html
@@ -1,7 +1,7 @@
 <div id="right_widgets">
   {% for widget in hub.right_widgets %}
   <div id="widget-{{ widget.idx }}" class="widget row"
-       data-url="{{ url_for('widget_render', hub=hub.name, idx=widget.idx) }}"
+       data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
        ></div>
   {% endfor %}
 </div>
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 1ca2a8d..9f6383a 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -223,7 +223,7 @@ class HubsAPITest(hubs.tests.APPTest):
         result = self.app.get('/ralph/add?position=right',
                               follow_redirects=True)
         self.assertEqual(result.status_code, 200)
-        expected_str = 'Adding widget to hub: ralph'
+        expected_str = 'Adding a widget to hub: ralph'
         self.assertIn(expected_str, result.get_data(as_text=True))
         expected_str = "url: 'add/' + $('#widget').val() + '?position=right',"
         self.assertIn(expected_str, result.get_data(as_text=True))
@@ -337,7 +337,7 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             url = '/ralph/add/about?position=right'
             result = self.app.get(url)
-            self.assertIn('Adding widget "about"to hub: ralph',
+            self.assertIn('Adding widget "about" to hub: ralph',
                           result.get_data(as_text=True))
 
     def test_hub_add_widget_invalid_side(self):
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index f64f261..27e9235 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -158,19 +158,14 @@ def hub_add_widget(name, widget_name):
     if side not in ['right', 'left']:
         flask.abort(400, 'Invalid position provided')
 
-    widget = None
-    w_name = None
-    for widgt in hubs.widgets.registry:
-        if hubs.widgets.registry[widgt].position in ['both', side] \
-                and widgt == widget_name:
-            w_name = widgt
-            widget = hubs.widgets.registry[widgt]
+    widget = hubs.widgets.registry[widget_name]
+    if widget.position not in ['both', side]:
+        flask.abort(400, "This widget can't be placed here")
 
     return flask.render_template(
         'add_widget.html',
         hub=hub,
         widget=widget,
-        widget_name=w_name,
         side=side,
         url_to=flask.url_for('hub_add_widgets', name=name),
     )
@@ -209,7 +204,7 @@ def hub_add_widget_post(name):
         plugin=widget_name, index=-1, left=position == 'left')
     error = False
     config = {}
-    for arg in widget.module.data.widget_arguments:
+    for arg in widget.module.get_arguments():
         val = flask.request.form.get(arg.name)
         if not val:
             flask.flash(
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index df05992..94113e3 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
 import flask
 import functools
 import hubs.models
-import hubs.widgets
 
 from six.moves.urllib import parse as urlparse
 from sqlalchemy.orm.exc import NoResultFound
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 613e47d..cbc002c 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -4,17 +4,10 @@ import datetime
 import flask
 
 from hubs.app import app
+from pkg_resources import resource_isdir
 from .utils import get_widget_instance
 
 
-@app.route('/<hub>/<int:idx>/')
-@app.route('/<hub>/<int:idx>')
-def widget_render(hub, idx):
-    widget = get_widget_instance(hub, idx)
-    return widget.render()  # , edit=False)
-    # was blocking all widgets from working, sorry!
-
-
 @app.route('/<hub>/<int:idx>/json')
 @app.route('/<hub>/<int:idx>/json/')
 def widget_json(hub, idx):
@@ -47,7 +40,7 @@ def widget_edit_post(hub, idx):
     widget = get_widget_instance(hub, idx)
     error = False
     config = {}
-    for arg in widget.module.data.widget_arguments:
+    for arg in widget.module.get_arguments():
         val = flask.request.form.get(arg.name)
         if not val:
             flask.flash(
@@ -96,14 +89,17 @@ def widget_edit_delete(hub, idx):
 @app.route('/source/<name>')
 def widget_source(name):
     from hubs.widgets import registry
-    base = '/hubs/'
-    fname = ''
 
     try:
-        fname = base + registry[name].__file__.split(base)[-1]
+        widget_path = registry[name].__module__
     except KeyError:
         flask.abort(404)
-
-    fname = fname.replace('.pyc', '.py')
-    return flask.redirect(app.config.get('SOURCE_URL') + fname)
+    widget_url = widget_path.replace(".", "/")
+    parent, _ignore, module = widget_path.rpartition(".")
+    if resource_isdir(parent, module):
+        widget_url += "/__init__.py"
+    else:
+        widget_url += ".py"
+    url = "/".join([app.config.get('SOURCE_URL'), widget_url])
+    return flask.redirect(url)
 
diff --git a/requirements.txt b/requirements.txt
index 092bd82..56ea13b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -16,6 +16,7 @@ munch
 psycopg2
 pytz
 requests
+setuptools
 sqlalchemy
 markdown
 pkgwat.api

From 5d1ca31daef0934665a89f6d35b34469e73a62f4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 709/1001] Add the Flask variables and filters to widget template env


---

diff --git a/hubs/widgets/templating.py b/hubs/widgets/templating.py
index 41e0c5b..ac5b3e4 100644
--- a/hubs/widgets/templating.py
+++ b/hubs/widgets/templating.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
 
 import os
 
+import flask
 import jinja2
 
 here = os.path.dirname(os.path.abspath(__file__))
@@ -10,3 +11,9 @@ environment = jinja2.Environment(
     loader=jinja2.FileSystemLoader(here),
     trim_blocks=True,
 )
+environment.filters['tojson'] = flask.json.tojson_filter
+environment.globals.update({
+    'session': flask.app.session,
+    'g': flask.g,
+    'url_for': flask.url_for,
+    })

From 372918c54c9191828de3314b20fda73251bbcc0f Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 710/1001] Adapt the backend workers to the new CachedFunction


---

diff --git a/hubs/backend/consumer.py b/hubs/backend/consumer.py
old mode 100755
new mode 100644
diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index c1bf1da..7320460 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -58,25 +58,21 @@ def triage(session, outbound, msg):
     log.debug("Randomizing list of all widgets.")
     random.shuffle(widgets)
 
+    def is_widget_update(msg, widget):
+        """Always rebuild the cache when the widget config is updated."""
+        return msg['topic'].endswith('hubs.widget.update') \
+            and msg['msg']['widget']['id'] == widget.idx
+
     log.debug("Checking should_invalidate for all widgets.")
     for widget in widgets:
-
-        check = widget.module.should_invalidate
-
-        # Do some pre-flight checks before calling should_invalidate
-        if hasattr(check, 'hints'):
-            if check.hints['topics']:
-                if topic not in check.hints['topics']:
-                    continue
-            if check.hints['categories']:
-                if category not in check.hints['categories']:
-                    continue
-
-        if check(msg, session, widget):
-            yield retask.task.Task(json.dumps({
-                'idx': widget.idx,
-                'msg_id': msg['msg_id'],
-            }))
+        for fn_name, fn_class in widget.module.get_cached_functions().items():
+            if is_widget_update(msg, widget) or \
+                    fn_class(widget).should_invalidate(msg):
+                yield retask.task.Task(json.dumps({
+                    'idx': widget.idx,
+                    'fn_name': fn_name,
+                    'msg_id': msg['msg_id'],
+                }))
 
 
 def main(args):
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index b4af706..e8e63e3 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -44,24 +44,22 @@ import logging.config
 log = logging.getLogger('hubs.backend.worker')
 
 
-def work(session, widget_idx):
+def work(widget_idx, fn_name):
     # Get a real widget, because we update last_refreshed on it.
     widget = hubs.models.Widget.by_idx(widget_idx)
-    log.info("! Invalidating cache for %r" % widget)
+    fn_class = widget.module.get_cached_functions()[fn_name]
+    log.info("! Rebuilding cache for %r:%r" % (widget, cached_fn))
     # Invalidate the cache...
-    hubs.widgets.base.invalidate_cache(widget, **widget.config)
-    # Rebuild it.
-    log.info("! Rebuilding cache for %r" % widget)
-    widget.module.data(session, widget, **widget.config)
+    fn_class(widget).rebuild()
     # TODO -- fire off an EventSource notice that we updated stuff
 
 
-def handle(idx):
+def handle(idx, fn_name):
     session = hubs.models.init(config['hubs.sqlalchemy.uri'])
 
     try:
         with hubs.app.app.app_context():  # so url_for works
-            work(session, idx)
+            work(idx, fn_name)
         session.commit()  # transaction is committed here
     except:
         session.rollback()  # rolls back the transaction
@@ -91,7 +89,7 @@ def main(args):
             log.info("Working on %r.  (backlog is %r)" % (task, queue.length))
             item = json.loads(task.data)
             idx = item['idx']  # A widget ID
-            handle(idx)
+            handle(item['idx'], item['fn_name'])
             log.debug("  Done.")
     except KeyboardInterrupt:
         pass

From 12c0cf674830757960c40d945e87aa087cea5468 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 711/1001] Adapt the cache scripts to the new CachedFunction


---

diff --git a/check-cache-coverage.py b/check-cache-coverage.py
index a753f56..d092dfd 100755
--- a/check-cache-coverage.py
+++ b/check-cache-coverage.py
@@ -13,12 +13,14 @@ forcibly re-warms the cache.
 Authors:    Ralph Bean <rbean@redhat.com>
 """
 
-from __future__ import unicode_literals
+from __future__ import unicode_literals, print_function
 
 import sys
 import dogpile.cache
 
-import hubs.widgets.base
+import hubs.app
+import hubs.widgets
+import hubs.widgets.caching
 import hubs.models
 
 import fedmsg.config
@@ -27,18 +29,21 @@ config = fedmsg.config.load_config()
 
 empty, full = 0, 0
 session = hubs.models.init(config['hubs.sqlalchemy.uri'])
-for widget in session.query(hubs.models.Widget).all():
-    key = hubs.widgets.base.cache_key_generator(widget, **widget.config)
-    result = hubs.widgets.base.cache.get(key, ignore_expiration=True)
-    if isinstance(result, dogpile.cache.api.NoValue):
-        empty += 1
-    else:
-        full += 1
-    sys.stdout.write('.')
-    sys.stdout.flush()
+
+# Register widgets
+hubs.widgets.registry.register_list(hubs.app.app.config["WIDGETS"])
+
+for w_instance in session.query(hubs.models.Widget).all():
+    for fn_name, fn_class in w_instance.module.get_cached_functions().items():
+        if fn_class(w_instance).is_cached():
+            full += 1
+        else:
+            empty += 1
+        sys.stdout.write('.')
+        sys.stdout.flush()
 sys.stdout.write('\n')
 sys.stdout.flush()
 
 total = empty + full
-print full, "cache values found. ", empty, "are missing."
-print full / float(total) * 100, "percent cache coverage."
+print(full, "cache values found. ", empty, "are missing.")
+print(full / float(total) * 100, "percent cache coverage.")
diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index 25c2540..ebf0de6 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -18,8 +18,10 @@ import fedmsg.config
 import fedmsg.meta
 
 
+import hubs.app
 import hubs.models
 import hubs.widgets.base
+import hubs.widgets.caching
 
 # get the DB session
 fedmsg_config = fedmsg.config.load_config()
@@ -27,21 +29,24 @@ fedmsg.meta.make_processors(**fedmsg_config)
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 
+# Register widgets
+hubs.widgets.registry.register_list(hubs.app.app.config["WIDGETS"])
+
 
 def do_list(args):
     ''' List the different widget for which there is data cached. '''
-    for widget in session.query(hubs.models.Widget).all():
-        key = hubs.widgets.base.cache_key_generator(widget, **widget.config)
-        result = hubs.widgets.base.cache.get(key, ignore_expiration=True)
-        if not isinstance(result, dogpile.cache.api.NoValue):
-            print('- Widget cached {0} (#{1}) in {2}'.format(
-                      widget.hub_id, widget.idx, widget.plugin))
+    for w_instance in session.query(hubs.models.Widget).all():
+        widget = w_instance.module
+        for fn_name, fn_class in widget.get_cached_functions().items():
+            if fn_class(w_instance).is_cached():
+                print('- Widget cached {0} (#{1}) in {2}'.format(
+                          w_instance.hub_id, w_instance.idx, w_instance.plugin))
 
 
 def do_clean(args):
     ''' Clean the widget for which there is data cached. '''
     for widget in args.widgets:
-        wid_obj = hubs.models.Widget.get(session, widget)
+        wid_obj = hubs.models.Widget.get(widget)
 
         if not wid_obj:
             wid_obj = session.query(hubs.models.Widget).filter_by(
@@ -52,7 +57,8 @@ def do_clean(args):
 
         print('- Removing cached {0} (#{1}) in {2}'.format(
               wid_obj.hub_id, wid_obj.idx, wid_obj.plugin))
-        result = hubs.widgets.base.invalidate_cache(wid_obj, **wid_obj.config)
+        for fn_class in wid_obj.module.get_cached_functions().values():
+            fn_class(wid_obj).invalidate()
 
 
 def setup_parser():

From 0b302fea975c6d1575b4b466c5be111183c81629 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 712/1001] Convert the about widget


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 9f6383a..9415590 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -361,7 +361,7 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get(url)
             self.assertEqual(result.status_code, 302)
             expected_str = 'https://pagure.io/fedora-hubs/' \
-                           'blob/develop/f/hubs/widgets/about.py'
+                           'blob/develop/f/hubs/widgets/about/__init__.py'
             self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_source_name_not_existent(self):
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index 74e0c56..d068a1b 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -21,24 +21,3 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
             u'source_url': u'/source/about',
             u'text': u'Testing.',
         })
-
-    def test_should_invalidate_wrong_topic(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        msg = {'topic': 'hubs.widget.update.WRONG.TOPIC', 'msg': {'widget': {'id': widget.idx}}}
-        module = hubs.widgets.registry[widget.plugin]
-        result = module.should_invalidate(msg, self.session, widget)
-        self.assertFalse(result)
-
-    def test_should_invalidate_wrong_widget_id(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx+1}}}
-        module = hubs.widgets.registry[widget.plugin]
-        result = module.should_invalidate(msg, self.session, widget)
-        self.assertFalse(result)
-
-    def test_should_invalidate_good_match(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx}}}
-        module = hubs.widgets.registry[widget.plugin]
-        result = module.should_invalidate(msg, self.session, widget)
-        self.assertTrue(result)
diff --git a/hubs/widgets/about.py b/hubs/widgets/about.py
deleted file mode 100755
index 7f0d994..0000000
--- a/hubs/widgets/about.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.chrome import panel
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-
-import hubs.validators as validators
-
-chrome = panel("<span class='glyphicon glyphicon-info-sign' aria-hidden='true'></span> About")
-template = templating.environment.get_template('templates/about.html')
-position = 'both'
-
-
-@argument(name="text", default="I am a Fedora user, and this is my about",
-          validator=validators.text,
-          help="Text about a user.")
-def data(session, widget, text):
-    ''' Data for the About widget '''
-
-    return dict(text=text)
-
-
-@hint(topics=[_('hubs.widget.update')])
-def should_invalidate(message, session, widget):
-    ''' Checks whether the about widget cache needs an update or not
-    Called by backend daemon which listens to fedmsg '''
-
-    if not message['topic'].endswith('hubs.widget.update'):
-        return False
-    if message['msg']['widget']['id'] != widget.idx:
-        return False
-    return True
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
new file mode 100644
index 0000000..aff28b0
--- /dev/null
+++ b/hubs/widgets/about/__init__.py
@@ -0,0 +1,30 @@
+from __future__ import unicode_literals
+
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import Widget, WidgetView
+
+from hubs import validators
+
+
+class About(Widget):
+
+    name = "about"
+    position = "both"
+    arguments = [dict(
+        name="text",
+        label="Text",
+        default="I am a Fedora user, and this is my about",
+        validator=validators.text,
+        help="Text about a user.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/about.html"
+    chrome = panel("<span class='glyphicon glyphicon-info-sign' aria-hidden='true'></span> About")
+
+    def get_context(self, instance, *args, **kwargs):
+        return dict(text=instance.config["text"])

From 05b480c3f5eb8e4762c57091ac8a2bb7532bd2e3 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 713/1001] Convert the badges widget


---

diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index 8a88807..f8ae5b6 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -22,7 +22,8 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         # msg = self.get_fedmsg('2016-ebb84660-59e9-4e68-af8f-4e6f49348b88')
         msg = {'topic': 'hubs.widget.update.WRONG.TOPIC'}
         module = hubs.widgets.registry[widget.plugin]
-        result = module.should_invalidate(msg, self.session, widget)
+        func = module.get_cached_functions()['GetBadges']
+        result = func(widget).should_invalidate(msg)
         self.assertFalse(result)
 
     def test_should_invalidate_wrong_user(self):
@@ -30,7 +31,8 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         # msg = self.get_fedmsg('2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f')
         msg = {'topic': 'fedbadges.badge.award', 'msg': {'user': {'username': 'not_ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
-        result = module.should_invalidate(msg, self.session, widget)
+        func = module.get_cached_functions()['GetBadges']
+        result = func(widget).should_invalidate(msg)
         self.assertFalse(result)
 
     def test_should_invalidate_good_match_fedbadges(self):
@@ -38,7 +40,8 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
         msg = {'topic': 'fedbadges.badge.award', 'msg': {'user': {'username': 'ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
-        result = module.should_invalidate(msg, self.session, widget)
+        func = module.get_cached_functions()['GetBadges']
+        result = func(widget).should_invalidate(msg)
         self.assertTrue(result)
 
     def test_should_invalidate_good_match_hubswidget(self):
@@ -46,5 +49,6 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
         msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx + 1}}}
         module = hubs.widgets.registry[widget.plugin]
-        result = module.should_invalidate(msg, self.session, widget)
+        func = module.get_cached_functions()['GetBadges']
+        result = func(widget).should_invalidate(msg)
         self.assertTrue(result)
diff --git a/hubs/widgets/badges.py b/hubs/widgets/badges.py
deleted file mode 100755
index 86bc929..0000000
--- a/hubs/widgets/badges.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from __future__ import unicode_literals
-
-import operator
-
-import requests
-
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-
-import hubs.validators as validators
-
-from hubs.widgets.chrome import panel
-chrome = panel("Badges")
-template = templating.environment.get_template('templates/badges.html')
-position = 'right'
-
-
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-def data(session, widget, username):
-    url = "https://badges.fedoraproject.org/user/{username}/json"
-    url = url.format(username=username)
-    response = requests.get(url)
-    assertions = response.json()['assertions']
-    key = operator.itemgetter('issued')
-    return dict(assertions=sorted(assertions, key=key, reverse=True))
-
-
-@hint(topics=[_('hubs.widget.update'), _('fedbadges.badge.award')])
-def should_invalidate(message, session, widget):
-    if message['topic'].endswith('hubs.widget.update'):
-        if message['msg']['widget']['id'] != widget.idx:
-            return True
-
-    if message['topic'].endswith('fedbadges.badge.award'):
-        username = widget.config['username']
-        if message['msg']['user']['username'] == username:
-            return True
-
-    return False
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
new file mode 100644
index 0000000..a6d838f
--- /dev/null
+++ b/hubs/widgets/badges/__init__.py
@@ -0,0 +1,56 @@
+from __future__ import unicode_literals
+
+import operator
+import requests
+
+from hubs import validators
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+
+class Badges(Widget):
+
+    name = "badges"
+    position = "right"
+    arguments = [dict(
+        name="username",
+        label="Username",
+        default=None,
+        validator=validators.username,
+        help="A FAS username.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/badges.html"
+    chrome = panel("Badges")
+
+    def get_context(self, instance, *args, **kwargs):
+        get_badges = GetBadges(instance)
+        return get_badges()
+
+
+class GetBadges(CachedFunction):
+
+    def execute(self):
+        username = self.instance.config["username"]
+        url = "https://badges.fedoraproject.org/user/{username}/json"
+        url = url.format(username=username)
+        response = requests.get(url)
+        assertions = response.json()['assertions']
+        key = operator.itemgetter('issued')
+        return dict(assertions=sorted(assertions, key=key, reverse=True))
+
+    def should_invalidate(self, message):
+        if message['topic'].endswith('hubs.widget.update'):
+            if message['msg']['widget']['id'] != self.instance.idx:
+                return True
+        if message['topic'].endswith('fedbadges.badge.award'):
+            username = self.instance.config['username']
+            if message['msg']['user']['username'] == username:
+                return True
+        return False

From 4d711ebf4307b0821392ee62699ab1a4288566e1 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 714/1001] Convert the bugzilla widget


---

diff --git a/hubs/widgets/bugzilla.py b/hubs/widgets/bugzilla.py
deleted file mode 100644
index c2d94ae..0000000
--- a/hubs/widgets/bugzilla.py
+++ /dev/null
@@ -1,89 +0,0 @@
-from __future__ import unicode_literals
-
-import requests
-import pkgwat.api
-
-import hubs.validators as validators
-from hubs.widgets.base import argument
-from hubs.widgets.chrome import panel
-from hubs.widgets import templating
-from hubs.hinting import hint
-
-chrome = panel("Bugzilla: Issues")
-template = templating.environment.get_template('templates/bugzilla.html')
-position = 'right'
-
-
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-def data(session, widget, username):
-    ''' Returns data for Bugzilla Widget. Queries pkgdb api for package
-    list of the user and bugzilla for correspoding issues '''
-
-    pkgdb_url = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
-    url = "/".join([pkgdb_url, username])
-    response = requests.get(url)
-    data = response.json()
-
-    issues = []
-
-    # get the packages of which the user is
-    # point of contact
-    for package in data["point of contact"]:
-        if len(issues) == 3:
-            break
-        pkg_details = pkgwat.api.bugs(package['name'])
-        for row in pkg_details['rows']:
-            if len(issues) == 3:
-                break
-            issues.append(
-                dict(
-                    id=row['id'],
-                    title=row['description'],
-                    pkg_name=package['name'],
-                )
-            )
-
-    # get the packages of which the user is
-    # co maintainer
-    for package in data["co-maintained"]:
-        if len(issues) == 3:
-            break
-        pkg_details = pkgwat.api.bugs(package['name'])
-        for row in pkg_details['rows']:
-            if len(issues) == 3:
-                break
-            issues.append(
-                dict(
-                    id=row['id'],
-                    title=row['description'],
-                    pkg_name=package['name'],
-                )
-            )
-
-    return dict(
-        username=username,
-        issues=issues,
-    )
-
-
-@hint(categories=['bugzilla'])
-def should_invalidate(message, session, widget):
-    ''' Validate if the bugzilla widget cache needs an update
-    This is called by a backend daemon listening to fedmsg '''
-
-    # TODO -- wrap this pkgdb pull in another invalidatible cache.
-    username = widget.config['username']
-    pkgdb_url = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
-    url = "/".join([pkgdb_url, username])
-    response = requests.get(url)
-    data = response.json()
-
-    owned = data['point of contact'] + data['co-maintained']
-    owned = [p['name'] for p in owned]
-    if message['msg']['bug']['component'] in owned:
-        return True
-
-    return False
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
new file mode 100644
index 0000000..ca42357
--- /dev/null
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -0,0 +1,103 @@
+from __future__ import unicode_literals
+
+import requests
+import pkgwat.api
+
+from hubs import validators
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+
+PKGDB_URL = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
+
+
+class Bugzilla(Widget):
+
+    name = "bugzilla"
+    position = "right"
+    arguments = [dict(
+        name="username",
+        label="Username",
+        default=None,
+        validator=validators.username,
+        help="A FAS username.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/bugzilla.html"
+    chrome = panel("Bugzilla: Issues")
+
+    def get_context(self, instance, *args, **kwargs):
+        get_issues = GetIssues(instance)
+        return dict(
+            username=instance.config["username"],
+            issues=get_issues()
+            )
+
+
+class GetIssues(CachedFunction):
+
+    ''' Returns data for Bugzilla Widget. Queries pkgdb api for package
+    list of the user and bugzilla for correspoding issues '''
+
+    def execute(self):
+        username = self.instance.config["username"]
+        url = "/".join([PKGDB_URL, username])
+        response = requests.get(url)
+        data = response.json()
+
+        issues = []
+
+        # get the packages of which the user is
+        # point of contact
+        for package in data["point of contact"]:
+            if len(issues) == 3:
+                break
+            pkg_details = pkgwat.api.bugs(package['name'])
+            for row in pkg_details['rows']:
+                if len(issues) == 3:
+                    break
+                issues.append(
+                    dict(
+                        id=row['id'],
+                        title=row['description'],
+                        pkg_name=package['name'],
+                    )
+                )
+
+        # get the packages of which the user is
+        # co maintainer
+        for package in data["co-maintained"]:
+            if len(issues) == 3:
+                break
+            pkg_details = pkgwat.api.bugs(package['name'])
+            for row in pkg_details['rows']:
+                if len(issues) == 3:
+                    break
+                issues.append(
+                    dict(
+                        id=row['id'],
+                        title=row['description'],
+                        pkg_name=package['name'],
+                    )
+                )
+
+        return issues
+
+    def should_invalidate(self, message):
+        username = self.instance.config["username"]
+        url = "/".join([PKGDB_URL, username])
+        response = requests.get(url)
+        data = response.json()
+
+        owned = data['point of contact'] + data['co-maintained']
+        owned = [p['name'] for p in owned]
+        if message['msg']['bug']['component'] in owned:
+            return True
+
+        return False

From 346c71d40e4980eefd41ab8d56aaede79718e9e2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 715/1001] Convert the contact widget


---

diff --git a/hubs/widgets/contact.py b/hubs/widgets/contact.py
deleted file mode 100644
index 4bd5597..0000000
--- a/hubs/widgets/contact.py
+++ /dev/null
@@ -1,65 +0,0 @@
-from __future__ import unicode_literals
-
-import flask
-
-import fedmsg.config
-import fedmsg.meta
-import hubs.models
-from hubs.widgets.chrome import panel
-from hubs.widgets import templating
-
-config = fedmsg.config.load_config()
-
-chrome = panel()
-template = templating.environment.get_template('templates/contact.html')
-position = 'both'
-
-
-# TODO: update this section when FAS3 is deployed
-def data(session, widget, **kwargs):
-    ''' Data for Contact widget. Checks if the hub associated
-    with widget is of a user or not. If the hub is of a user, return
-    data related to the user else, hub is of a fedora team
-    - return data related to the team '''
-
-    hub = widget.hub
-    if hub.user_hub:
-        usergroup = True
-        user = hubs.models.User.by_username(hub.name)
-        email = user.username + '@fedoraproject.org'
-        karma_url = flask.url_for('plus_plus_status', user=user.username)
-        fas_info = {
-            'usergroup': usergroup,
-            'location': 'United States',
-            'timezone': 'UTC',
-            'email': email,
-            'ircnick': user.username,
-            'karma_url': karma_url,
-            'account_age': 'Oct 2010',
-        }
-    else:
-        usergroup = False
-        # TODO: update this section integrating with FAS3
-        if hub.name == 'infrastructure':
-            ircchannel = 'apps'
-            hubname = 'infrastructure'
-        elif hub.name == 'designteam':
-            ircchannel = 'design'
-            hubname = 'design'
-        elif hub.name == 'marketing':
-            ircchannel = 'mktg'
-            hubname = 'marketing'
-        else:
-            ircchannel = hub.name
-            hubname = hub.name
-        mailinglist = 'https://lists.fedoraproject.org/archives/list/{}'
-        '@lists.fedoraproject.org/'.format(hubname)
-        wikilink = 'https://fedoraproject.org/wiki/' + hubname
-        fas_info = {
-            'usergroup': usergroup,
-            'hubname': hubname,
-            'ircchannel': 'fedora-%s' % ircchannel,
-            'mailinglist': mailinglist,
-            'wikilink': wikilink,
-        }
-    return fas_info
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
new file mode 100644
index 0000000..88841fe
--- /dev/null
+++ b/hubs/widgets/contact/__init__.py
@@ -0,0 +1,75 @@
+from __future__ import unicode_literals
+
+import flask
+
+import fedmsg.config
+import fedmsg.meta
+import hubs.models
+
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.chrome import panel
+
+config = fedmsg.config.load_config()
+
+
+class Contact(Widget):
+
+    name = "contact"
+    position = "both"
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/contact.html"
+    chrome = panel()
+
+    def get_context(self, instance, *args, **kwargs):
+        ''' Data for Contact widget. Checks if the hub associated
+        with instance is of a user or not. If the hub is of a user, return
+        data related to the user else, hub is of a fedora team
+        - return data related to the team '''
+        # TODO: update this section when FAS3 is deployed
+
+        hub = instance.hub
+        if hub.user_hub:
+            usergroup = True
+            user = hubs.models.User.by_username(hub.name)
+            email = user.username + '@fedoraproject.org'
+            karma_url = flask.url_for('plus_plus_status', user=user.username)
+            fas_info = {
+                'usergroup': usergroup,
+                'location': 'United States',
+                'timezone': 'UTC',
+                'email': email,
+                'ircnick': user.username,
+                'karma_url': karma_url,
+                'account_age': 'Oct 2010',
+            }
+        else:
+            usergroup = False
+            # TODO: update this section integrating with FAS3
+            if hub.name == 'infrastructure':
+                ircchannel = 'apps'
+                hubname = 'infrastructure'
+            elif hub.name == 'designteam':
+                ircchannel = 'design'
+                hubname = 'design'
+            elif hub.name == 'marketing':
+                ircchannel = 'mktg'
+                hubname = 'marketing'
+            else:
+                ircchannel = hub.name
+                hubname = hub.name
+            mailinglist = 'https://lists.fedoraproject.org/archives/list/{}'
+            '@lists.fedoraproject.org/'.format(hubname)
+            wikilink = 'https://fedoraproject.org/wiki/' + hubname
+            fas_info = {
+                'usergroup': usergroup,
+                'hubname': hubname,
+                'ircchannel': 'fedora-%s' % ircchannel,
+                'mailinglist': mailinglist,
+                'wikilink': wikilink,
+            }
+        return fas_info

From a235286e351087c80d628543523db590d11c1f04 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 716/1001] Convert the dummy widget


---

diff --git a/hubs/widgets/dummy.py b/hubs/widgets/dummy.py
deleted file mode 100755
index bd198d3..0000000
--- a/hubs/widgets/dummy.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.chrome import panel
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-
-import hubs.validators as validators
-
-chrome = panel("This is a dummy widget")
-template = templating.environment.get_template('templates/dummy.html')
-position = 'both'
-
-
-@argument(name="text", default="Lorem ipsum dolor...",
-          validator=validators.text,
-          help="Some dummy text to display.")
-def data(session, widget, text):
-    return dict(text=text)
-
-
-@hint(topics=[_('hubs.widget.update')])
-def should_invalidate(message, session, widget):
-    if not message['topic'].endswith('hubs.widget.update'):
-        return False
-    if message['msg']['widget']['id'] != widget.id:
-        return False
-    return True
diff --git a/hubs/widgets/dummy/__init__.py b/hubs/widgets/dummy/__init__.py
new file mode 100644
index 0000000..738711a
--- /dev/null
+++ b/hubs/widgets/dummy/__init__.py
@@ -0,0 +1,29 @@
+from __future__ import unicode_literals
+
+from hubs import validators
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import Widget, WidgetView
+
+
+class Dummy(Widget):
+
+    name = "dummy"
+    position = "both"
+    arguments = [dict(
+        name="text",
+        label="Text",
+        default="Lorem ipsum dolor...",
+        validator=validators.text,
+        help="Some dummy text to display.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/dummy.html"
+    chrome = panel("This is a dummy widget")
+
+    def get_context(self, instance, *args, **kwargs):
+        return dict(text=instance.config["text"])

From 2a6bddf2b9bcb55c41767aa0ed15c84c2a8f603c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 717/1001] Convert the fedmsgstats widget


---

diff --git a/hubs/widgets/fedmsgstats.py b/hubs/widgets/fedmsgstats.py
deleted file mode 100755
index 0cf5ba2..0000000
--- a/hubs/widgets/fedmsgstats.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint
-from hubs.widgets.chrome import panel
-from hubs.widgets import templating
-
-from hubs.utils import commas
-
-import flask
-import requests
-
-import fedmsg.config
-import fedmsg.meta
-
-config = fedmsg.config.load_config()
-
-chrome = panel()
-template = templating.environment.get_template('templates/fedmsgstats.html')
-position = 'both'
-
-
-def data(session, widget, username):
-    url = "https://apps.fedoraproject.org/datagrepper/raw?user={username}"
-    url = url.format(username=username)
-    response = requests.get(url)
-    fedmsgs = response.json()['total']
-    sub_list = []
-    for assoc in widget.hub.associations:
-        if assoc.user:
-            sub_list = [u.name for u in assoc.user.subscriptions]
-    subscribers = [u.username for u in widget.hub.subscribers]
-    return dict(
-        username=username,
-        fedmsgs=fedmsgs,
-        subscribers=subscribers,
-        subscribed_to=sub_list,
-        fedmsgs_text=commas(fedmsgs),
-        subscribers_text=commas(len(subscribers)),
-        subscribed_text=commas(len(sub_list)),
-        hub_subscribe_url=flask.url_for(
-            'hub_subscribe', hub=widget.hub.name),
-        hub_unsubscribe_url=flask.url_for(
-            'hub_unsubscribe', hub=widget.hub.name),
-    )
-
-
-@hint(usernames=lambda widget: [widget.config['username']])
-def should_invalidate(message, session, widget):
-    usernames = fedmsg.meta.msg2usernames(message, **config)
-    username = widget.config['username']
-    return username in usernames
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
new file mode 100644
index 0000000..b31ae11
--- /dev/null
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -0,0 +1,76 @@
+from __future__ import unicode_literals
+
+import flask
+import fedmsg.config
+import fedmsg.meta
+import requests
+
+from hubs import validators
+from hubs.utils import commas
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+fedmsg_config = fedmsg.config.load_config()
+
+
+class FedmsgStats(Widget):
+
+    name = "fedmsgstats"
+    position = "both"
+    arguments = [dict(
+        name="username",
+        label="Username",
+        default=None,
+        validator=validators.username,
+        help="A FAS username.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/fedmsgstats.html"
+    chrome = panel()
+
+    def get_context(self, instance, *args, **kwargs):
+        username = instance.config["username"]
+        context = dict(
+            username=username,
+            hub_subscribe_url=flask.url_for(
+                'hub_subscribe', hub=instance.hub.name),
+            hub_unsubscribe_url=flask.url_for(
+                'hub_unsubscribe', hub=instance.hub.name),
+        )
+        get_stats = GetStats(instance)
+        context.update(get_stats())
+        return context
+
+
+class GetStats(CachedFunction):
+
+    def execute(self):
+        username = self.instance.config["username"]
+        url = "https://apps.fedoraproject.org/datagrepper/raw?user={username}"
+        url = url.format(username=username)
+        response = requests.get(url)
+        fedmsgs = response.json()['total']
+        sub_list = []
+        for assoc in self.instance.hub.associations:
+            if assoc.user:
+                sub_list = [u.name for u in assoc.user.subscriptions]
+        subscribers = [u.username for u in self.instance.hub.subscribers]
+        return dict(
+            fedmsgs=fedmsgs,
+            fedmsgs_text=commas(fedmsgs),
+            subscribers=subscribers,
+            subscribed_to=sub_list,
+            subscribers_text=commas(len(subscribers)),
+            subscribed_text=commas(len(sub_list)),
+            )
+
+    def should_invalidate(self, message):
+        usernames = fedmsg.meta.msg2usernames(message, **fedmsg_config)
+        username = self.instance.config['username']
+        return username in usernames

From 9349db72c70a18a90940fe1b6ba2b5b6fd6a67fb Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 718/1001] Convert the feed widget


---

diff --git a/hubs/widgets/feed.py b/hubs/widgets/feed.py
deleted file mode 100755
index 5d744d9..0000000
--- a/hubs/widgets/feed.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from __future__ import print_function, unicode_literals
-
-from hubs.hinting import hint
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-
-import hubs.validators as validators
-
-import logging
-
-log = logging.getLogger('hubs')
-
-from hubs.widgets.chrome import panel
-chrome = panel('Live Feed')
-template = templating.environment.get_template('templates/feed.html')
-position = 'left'
-
-
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-@argument(name="message_limit",
-          default=20,
-          validator=validators.integer,
-          help="Max number of feed messages to display")
-def data(session, widget, username, message_limit):
-    # Avoid circular import
-    from hubs.app import app
-    feed_url = app.config['SSE_URL'] + username
-    return dict(matches=[], message_limit=message_limit, feed_url=feed_url)
-
-
-@hint(ubiquitous=True)
-def should_invalidate(message, session, widget):
-    pass
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
new file mode 100644
index 0000000..678152d
--- /dev/null
+++ b/hubs/widgets/feed/__init__.py
@@ -0,0 +1,48 @@
+from __future__ import unicode_literals
+
+
+from hubs import validators
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import Widget, WidgetView
+
+import logging
+log = logging.getLogger('hubs')
+
+
+class Feed(Widget):
+
+    name = "feed"
+    position = "left"
+    arguments = [
+        {
+            "name": "username",
+            "label": "Username",
+            "default": None,
+            "validator": validators.username,
+            "help": "A FAS username.",
+        }, {
+            "name": "message_limit",
+            "label": "Message limit",
+            "default": 20,
+            "validator": validators.integer,
+            "help": "Max number of feed messages to display.",
+        }]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/feed.html"
+    chrome = panel("Live Feed")
+
+    def get_context(self, instance, *args, **kwargs):
+        # Avoid circular import
+        from hubs.app import app
+        username = instance.config["username"]
+        feed_url = app.config['SSE_URL'] + username
+        return dict(
+            matches=[],
+            message_limit=instance.config["message_limit"],
+            feed_url=feed_url,
+            )

From a21c7f496cf567afdd6d8b0ec70e1aa27c1b449e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 719/1001] Convert the fhosted widget


---

diff --git a/hubs/widgets/fhosted.py b/hubs/widgets/fhosted.py
deleted file mode 100644
index bc97d8b..0000000
--- a/hubs/widgets/fhosted.py
+++ /dev/null
@@ -1,71 +0,0 @@
-from __future__ import unicode_literals
-
-from six.moves.xmlrpc_client import ServerProxy
-
-import hubs.validators as validators
-from hubs.widgets.chrome import panel
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-
-chrome = panel("Fedorahosted: Open Tickets")
-template = templating.environment.get_template('templates/fedorahosted.html')
-position = 'right'
-
-
-@argument(name="project",
-          default=None,
-          validator=validators.fedorahosted_project,
-          help="Name of the trac instance on fedorahosted.org")
-@argument(name="n_tickets",
-          default=4,
-          validator=validators.integer,
-          help="The number of tickets to display.")
-def data(session, widget, project, n_tickets=4):
-    ''' Data for Fedorahosted widget.
-    Queries Fedorahosted via xmlrpc for tickets. '''
-
-    n_tickets = int(n_tickets)
-    url = 'https://fedorahosted.org/%s/rpc' % project
-    filters = 'status=accepted&status=assigned&status=new&status=reopened'\
-        '&col=id&col=summary&col=status&col=owner&col=type&col=priority'\
-        '&col=milestone&col=changetime&order=changetime'
-
-    # get the tickets based on the filters
-    # returns a list of ticket ids
-    try:
-        server = ServerProxy(url)
-        tickets = server.ticket.query(filters)
-    except:
-        return dict(
-            error='Invalid or wrongly configured project'
-        )
-
-    output = []
-    total_tickets = len(tickets)
-    for ticket in tickets[:n_tickets]:
-        # get the details of the ticket
-        ticket = server.ticket.get(ticket)
-        data = ticket[3]
-        data['id'] = ticket[0]
-        data['short_summary'] = data['summary'][:45]
-        output.append(data)
-
-    return dict(
-        project=project,
-        tickets=output,
-        total_tickets=total_tickets,
-    )
-
-
-@hint(topics=[_('trac.ticket.update'), _('trac.ticket.new')])
-def should_invalidate(message, session, widget):
-    ''' Checks if the Fedorahosted widget needs an update.
-    Called by backend daemon listening to fedmsg '''
-
-    project = widget.config.get('project', '')
-    url = 'https://fedorahosted.org/%s/' % project
-    if '.trac.ticket' in message['topic']:
-        if message['msg']['instance']['base_url'] == url:
-            return True
-    return False
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
new file mode 100644
index 0000000..ec1dc93
--- /dev/null
+++ b/hubs/widgets/fhosted/__init__.py
@@ -0,0 +1,90 @@
+from __future__ import unicode_literals
+
+from six.moves.xmlrpc_client import ServerProxy
+
+from hubs import validators
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+
+class FedoraHosted(Widget):
+
+    name = "fhosted"
+    position = "right"
+    arguments = [
+        dict(
+            name="project",
+            label="Project",
+            default=None,
+            validator=validators.fedorahosted_project,
+            help="Name of the trac instance on fedorahosted.org.",
+        ), dict(
+            name="n_tickets",
+            label="Number of tickets",
+            default=4,
+            validator=validators.integer,
+            help="The number of tickets to display.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/fedorahosted.html"
+    chrome = panel("Fedorahosted: Open Tickets")
+
+    def get_context(self, instance, *args, **kwargs):
+        get_tickets = GetTickets(instance)
+        context = dict(project=instance.config["project"])
+        context.update(get_tickets())
+        return context
+
+
+class GetTickets(CachedFunction):
+    ''' Data for Fedorahosted widget.
+    Queries Fedorahosted via xmlrpc for tickets. '''
+
+    def execute(self):
+        n_tickets = int(self.instance.config["n_tickets"])
+        url = 'https://fedorahosted.org/%s/rpc' \
+            % self.instance.config["project"]
+        filters = 'status=accepted&status=assigned&status=new&status=reopened'\
+            '&col=id&col=summary&col=status&col=owner&col=type&col=priority'\
+            '&col=milestone&col=changetime&order=changetime'
+
+        # get the tickets based on the filters
+        # returns a list of ticket ids
+        try:
+            server = ServerProxy(url)
+            tickets = server.ticket.query(filters)
+        except:
+            return dict(
+                error='Invalid or wrongly configured project'
+            )
+
+        output = []
+        total_tickets = len(tickets)
+        for ticket in tickets[:n_tickets]:
+            # get the details of the ticket
+            ticket = server.ticket.get(ticket)
+            data = ticket[3]
+            data['id'] = ticket[0]
+            data['short_summary'] = data['summary'][:45]
+            output.append(data)
+
+        return dict(
+            tickets=output,
+            total_tickets=total_tickets,
+        )
+
+    def should_invalidate(self, message):
+        ''' Checks if the Fedorahosted widget needs an update.
+        Called by backend daemon listening to fedmsg '''
+        if '.trac.ticket' in message['topic']:
+            project = self.instance.config.get("project", "")
+            url = 'https://fedorahosted.org/%s/' % project
+            if message['msg']['instance']['base_url'] == url:
+                return True
+        return False

From 2ea035e6db7580d12ff7aa9e8d4a67c2de5eb1ec Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 720/1001] Convert the githubissues widget


---

diff --git a/hubs/validators.py b/hubs/validators.py
old mode 100755
new mode 100644
index bd5b3f2..e065629
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -34,6 +34,10 @@ def github_organization(session, value):
     # TODO -- implement this.
     return value
 
+def github_repo(session, value):
+    # TODO -- implement this.
+    return value
+
 
 def fmn_context(session, value):
     # TODO get this from the fedmsg config.
diff --git a/hubs/widgets/githubissues.py b/hubs/widgets/githubissues.py
deleted file mode 100755
index 7130183..0000000
--- a/hubs/widgets/githubissues.py
+++ /dev/null
@@ -1,53 +0,0 @@
-from __future__ import unicode_literals
-
-import requests
-
-from hubs.hinting import hint
-from hubs.widgets import templating
-from hubs.widgets.chrome import panel
-from hubs.widgets.base import argument
-import hubs.validators as validators
-
-chrome = panel("Github: Newest Open Tickets")
-template = templating.environment.get_template('templates/githubissues.html')
-position = 'right'
-
-
-@argument(name="repo",
-          default=None,
-          validator=validators.github_organization,
-          help="Github Organization or username")
-def data(session, widget, display_number, org, repo):
-    ''' Data for Github Issues widget. Queries github api for issues '''
-
-    url = '/'.join(['https://api.github.com/repos', org, repo, "issues"])
-    issues = requests.get(url).json()
-
-    all_issues = []
-    for issue in issues[:10]:
-        issue_details = {}
-        issue_details['num'] = issue['number']
-        issue_details['title'] = issue['title']
-        issue_details['openedby'] = issue['user']['login']
-
-        issue_assignee = None
-        if issue['assignee'] is not None:
-            issue_assignee = issue['assignee']['login']
-
-        issue_details['assignee'] = issue_assignee
-        all_issues.append(issue_details)
-
-    return dict(
-        org=org,
-        repo=repo,
-        all_issues=all_issues.reverse(),
-        display_number=display_number,
-    )
-
-
-@hint()
-def should_invalidate(message, session, widget):
-    ''' Checks if the Github Issue widget needs an update.
-    Called by a backend daemon listening to fedmsg '''
-
-    raise NotImplementedError
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
new file mode 100644
index 0000000..efee564
--- /dev/null
+++ b/hubs/widgets/githubissues/__init__.py
@@ -0,0 +1,82 @@
+from __future__ import unicode_literals
+
+import requests
+
+from hubs import validators
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+
+class GitHubIssues(Widget):
+
+    name = "githubissues"
+    position = "right"
+    arguments = [
+        dict(
+            name="org",
+            label="Username",
+            default=None,
+            validator=validators.github_organization,
+            help="Github Organization or username",
+        ), dict(
+            name="repo",
+            label="Repository",
+            default=None,
+            validator=validators.github_repo,
+            help="Github repository",
+        ), dict(
+            name="display_number",
+            label="Number of tickets",
+            default=10,
+            validator=validators.integer,
+            help="The number of tickets to display.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/githubissues.html"
+    chrome = panel("Github: Newest Open Tickets")
+
+    def get_context(self, instance, *args, **kwargs):
+        get_issues = GetIssues(instance)
+        return dict(
+            org=instance.config["org"],
+            repo=instance.config["repo"],
+            display_number=int(instance.config["display_number"]),
+            all_issues=get_issues(),
+        )
+
+
+class GetIssues(CachedFunction):
+    ''' Data for Github Issues widget. Queries github api for issues '''
+
+    def execute(self):
+        org = self.instance.config["org"]
+        repo = self.instance.config["repo"]
+        display_number = int(self.instance.config["display_number"])
+        url = '/'.join(['https://api.github.com/repos', org, repo, "issues"])
+        issues = requests.get(url).json()
+
+        all_issues = []
+        for issue in issues[:display_number]:
+            issue_details = {}
+            issue_details['num'] = issue['number']
+            issue_details['title'] = issue['title']
+            issue_details['openedby'] = issue['user']['login']
+
+            issue_assignee = None
+            if issue['assignee'] is not None:
+                issue_assignee = issue['assignee']['login']
+
+            issue_details['assignee'] = issue_assignee
+            all_issues.append(issue_details)
+
+        all_issues.reverse()
+        return all_issues
+
+    def should_invalidate(self, message):
+        raise NotImplementedError

From daaf67140214e7f69d145c2f6ba68dbf562e0630 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 721/1001] Convert the github_pr widget


---

diff --git a/hubs/widgets/github_pr.py b/hubs/widgets/github_pr.py
deleted file mode 100755
index c2a0be9..0000000
--- a/hubs/widgets/github_pr.py
+++ /dev/null
@@ -1,69 +0,0 @@
-from __future__ import unicode_literals
-
-import logging
-
-from hubs.widgets.chrome import panel
-from hubs.hinting import hint
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-
-import hubs.validators as validators
-import hubs.utils
-
-import fedmsg.config
-config = fedmsg.config.load_config()
-
-log = logging.getLogger(__name__)
-
-chrome = panel("Github: Pull Requests")
-template = templating.environment.get_template('templates/github_pr.html')
-position = 'right'
-
-
-@argument(name="display_number",
-          default=6,
-          validator=validators.integer,
-          help="How many pull requests to display at max.")
-@argument(name="organization",
-          default=None,
-          validator=validators.github_organization,
-          help="Github Organization or username")
-def data(session, widget, display_number, organization):
-    log.info("Getting GH prs for %r, (%r)" % (organization, display_number))
-    token = config.get('github.oauth_token')
-    org = organization
-    pulls = []
-    display_number = 0
-    more = 0
-    if token:
-        repos = hubs.utils.github_repos(token, org)
-        pulls = sum([
-            list(hubs.utils.github_pulls(token, org, repo))
-            for repo in repos
-        ], [])
-        # Reverse-sort by time (newest-first)
-        pulls.sort(lambda a, b: cmp(b['timestamp'], a['timestamp']))
-
-        # Some hints for display
-        len_pulls = len(pulls)
-        display_number = min(display_number, len_pulls)
-        more = max(len_pulls - display_number, 0)
-
-    return dict(
-        organization=org,
-        display_number=display_number,
-        more=more,
-        pulls=pulls,
-    )
-
-
-@hint(categories=['github'])
-def should_invalidate(message, session, widget):
-    owner = message['msg']['repository']['owner']
-
-    if 'login' in owner:
-        owner = owner['login']
-    else:
-        owner = owner['name']
-
-    return owner == widget.config['organization']
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
new file mode 100644
index 0000000..5478f1c
--- /dev/null
+++ b/hubs/widgets/github_pr/__init__.py
@@ -0,0 +1,94 @@
+from __future__ import unicode_literals
+
+import logging
+import hubs.utils
+
+from hubs import validators
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+import fedmsg.config
+fedmsg_config = fedmsg.config.load_config()
+
+log = logging.getLogger(__name__)
+
+
+class GitHubPRs(Widget):
+
+    name = "github_pr"
+    position = "right"
+    arguments = [
+        dict(
+            name="organization",
+            label="Organization",
+            default=None,
+            validator=validators.github_organization,
+            help="Github Organization or username",
+        ), dict(
+            name="display_number",
+            label="Number of tickets",
+            default=6,
+            validator=validators.integer,
+            help="How many pull requests to display at max.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/github_pr.html"
+    chrome = panel("Github: Pull Requests")
+
+    def get_context(self, instance, *args, **kwargs):
+        get_prs = GetPRs(instance)
+        org = instance.config["organization"]
+        display_number = int(instance.config["display_number"])
+        context = dict(
+            organization=org,
+            display_number=display_number,
+        )
+        context.update(get_prs())
+        return context
+
+
+class GetPRs(CachedFunction):
+
+    def execute(self):
+        org = self.instance.config["organization"]
+        display_number = int(self.instance.config["display_number"])
+        log.info("Getting GH prs for %r, (%r)" % (org, display_number))
+        token = fedmsg_config.get('github.oauth_token')
+        pulls = []
+        displayed_number = 0
+        more = 0
+        if token:
+            repos = hubs.utils.github_repos(token, org)
+            pulls = sum([
+                list(hubs.utils.github_pulls(token, org, repo))
+                for repo in repos
+            ], [])
+            # Reverse-sort by time (newest-first)
+            pulls.sort(lambda a, b: cmp(b['timestamp'], a['timestamp']))
+
+            # Some hints for display
+            len_pulls = len(pulls)
+            displayed_number = min(display_number, len_pulls)
+            more = max(len_pulls - displayed_number, 0)
+
+        return dict(
+            more=more,
+            pulls=pulls,
+        )
+
+    def should_invalidate(self, message):
+        category = message["topic"].split('.')[3]
+        if category != "github":
+            return False
+        owner = message['msg']['repository']['owner']
+        if 'login' in owner:
+            owner = owner['login']
+        else:
+            owner = owner['name']
+        return owner == self.instance.config['organization']

From 6532d55260b88862772f3bef1b86fd1539412d3a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 722/1001] Convert the library widget


---

diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index ac7ddfc..92b4bde 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -18,12 +18,12 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
                 "urls": "ralph/"
             },
             "data": {
-                u"edit_url": u"/ralph/%d/edit" % widget.idx,
-                u"source_url": u"/source/library",
-                u"urls": [
-                    u"<a href=\"ralph/\">ralph/</a>"
+                "edit_url": "/ralph/%d/edit" % widget.idx,
+                "source_url": "/source/library",
+                "urls": [
+                    "<a href=\"ralph/\">ralph/</a>"
                 ],
-                u"widget_url": u"/ralph/%d" % widget.idx,
+                "widget_url": "/ralph/w/library/%d/" % widget.idx
             },
             "description": None,
             "hub": "ralph",
@@ -32,5 +32,4 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
             "left": False,
             "plugin": "library"
         }
-
         self.assertDictEqual(data['data'], expected_dict['data'])
diff --git a/hubs/widgets/library.py b/hubs/widgets/library.py
deleted file mode 100644
index 08ad334..0000000
--- a/hubs/widgets/library.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.chrome import panel
-from hubs.widgets.base import argument
-from hubs.widgets import clean_input
-from hubs.widgets import templating
-
-import hubs.validators as validators
-
-chrome = panel("Library")
-template = templating.environment.get_template('templates/library.html')
-position = 'both'
-
-
-@argument(name="urls", default=None,
-          validator=validators.text,
-          help="A comma separated list of URLs to add to the library. "
-          "External links must include the whole link (starting with http...)")
-def data(session, widget, urls):
-    ''' Data for the Library widget. Given the widget, it
-    returns the hypertext links of it's configuration urls '''
-
-    urls = [
-        clean_input.clean(
-            '<a href="{0}">{0}</a>'.format(u.strip()))
-        for u in widget.config.get('urls', '').split(',')
-        if u.strip()
-    ]
-    return dict(urls=urls)
-
-
-@hint(topics=[_('hubs.widget.update')])
-def should_invalidate(message, session, widget):
-    ''' Check if the Library widget cache needs an update.
-    Called by a backend daemon listening to fedmsg '''
-
-    if not message['topic'].endswith('hubs.widget.update'):
-        return False
-    if message['msg']['widget']['id'] != widget.id:
-        return False
-    return True
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
new file mode 100644
index 0000000..09ec390
--- /dev/null
+++ b/hubs/widgets/library/__init__.py
@@ -0,0 +1,38 @@
+from __future__ import unicode_literals
+
+from hubs import validators
+from hubs.widgets import clean_input
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import Widget, WidgetView
+
+
+class Library(Widget):
+
+    name = "library"
+    position = "both"
+    arguments = [dict(
+        name="urls",
+        label="URLs",
+        default=None,
+        validator=validators.text,
+        help="A comma separated list of URLs to add to the library. "
+             "External links must include the whole link "
+             "(starting with http...)."
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/library.html"
+    chrome = panel("Library")
+
+    def get_context(self, instance, *args, **kwargs):
+        urls = [
+            clean_input.clean(
+                '<a href="{0}">{0}</a>'.format(u.strip()))
+            for u in instance.config.get('urls', '').split(',')
+            if u.strip()
+        ]
+        return dict(urls=urls)

From 4fa1f96e09f1d7fdcaf3d1a7bb959a7ddd43bf61 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 723/1001] Convert the linechart widget


---

diff --git a/hubs/widgets/linechart.py b/hubs/widgets/linechart.py
deleted file mode 100755
index 3d41057..0000000
--- a/hubs/widgets/linechart.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-
-import hubs.validators as validators
-
-import fedmsg.config
-config = fedmsg.config.load_config()
-
-from hubs.widgets.chrome import panel
-chrome = panel("Weekly Activity")
-template = templating.environment.get_template('templates/linechart.html')
-position = 'left'
-
-
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-def data(session, widget, username):
-    categories = ['git', 'Wiki', 'Copr', 'anitya', 'mirrormanager', 'ansible',
-                  'fedoratagger', 'Pkgdb', 'summershum', 'nuancier', 'Mailman',
-                  'fedbadges', 'FMN', 'koschei', 'compose', 'fedimg',
-                  'Jenkins', 'irc', 'FAS', 'buildsys', 'Askbot', 'pagure',
-                  'Bodhi', 'faf', 'kerneltest', 'github', 'Trac', 'meetbot',
-                  'planet', 'fedocal', 'hotness']
-    categories = [c.lower() for c in categories]
-    categories = "&".join(['category=%s' % c for c in categories])
-    url = "https://apps.fedoraproject.org/datagrepper/charts/stackedline" \
-          "?delta=604800&N=12&style=clean&height=300&fill=true"\
-          "&user={username}&split_on=categories"
-    url = url + "&" + categories
-    url = url.format(username=username)
-    return dict(url=url)
-
-
-@hint(usernames=lambda widget: [widget.config['username']])
-def should_invalidate(message, session, widget):
-    usernames = fedmsg.meta.msg2usernames(message, **config)
-    username = widget.config['username']
-    return username in usernames
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
new file mode 100644
index 0000000..c7ac68e
--- /dev/null
+++ b/hubs/widgets/linechart/__init__.py
@@ -0,0 +1,45 @@
+from __future__ import unicode_literals
+
+from hubs import validators
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import Widget, WidgetView
+
+
+class Linechart(Widget):
+
+    name = "linechart"
+    position = "left"
+    arguments = [dict(
+        name="username",
+        label="Username",
+        default=None,
+        validator=validators.username,
+        help="A FAS username.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/linechart.html"
+    chrome = panel("Weekly Activity")
+
+    def get_context(self, instance, *args, **kwargs):
+        username = instance.config["username"]
+        categories = [
+            'git', 'Wiki', 'Copr', 'anitya', 'mirrormanager', 'ansible',
+            'fedoratagger', 'Pkgdb', 'summershum', 'nuancier', 'Mailman',
+            'fedbadges', 'FMN', 'koschei', 'compose', 'fedimg',
+            'Jenkins', 'irc', 'FAS', 'buildsys', 'Askbot', 'pagure',
+            'Bodhi', 'faf', 'kerneltest', 'github', 'Trac', 'meetbot',
+            'planet', 'fedocal', 'hotness',
+            ]
+        categories = [c.lower() for c in categories]
+        categories = "&".join(['category=%s' % c for c in categories])
+        url = ("https://apps.fedoraproject.org/datagrepper/charts/stackedline"
+               "?delta=604800&N=12&style=clean&height=300&fill=true"
+               "&user={username}&split_on=categories")
+        url = url + "&" + categories
+        url = url.format(username=username)
+        return dict(url=url)

From 459c740e994f8ef187f0f456779efb5631e49607 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 724/1001] Convert the meetings widget


---

diff --git a/hubs/defaults.py b/hubs/defaults.py
old mode 100755
new mode 100644
index d91d452..7b5129a
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -29,6 +29,7 @@ def add_user_widgets(session, hub, username, fullname):
         plugin='meetings', index=-1,
         _config=json.dumps({
             'calendar': 'Fedora release',
+            'n_meetings': 4,
         }))
     hub.widgets.append(widget)
 
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 08ea046..859bfb9 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -20,7 +20,8 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
     def test_render_simple(self):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
-        response = self.app.get('/%s/%i/' % (team, widget.idx))
+        response = self.app.get('/%s/w/%s/%i/'
+                                % (team, self.plugin, widget.idx))
         self.assertEqual(200, response.status_code)
         self.assertIn('i18n', response.get_data(as_text=True))
         self.assertIn('<strong>Request A New Meeting</strong>',
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_render_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_render_simple
new file mode 100644
index 0000000..32812c9
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_render_simple
@@ -0,0 +1,43 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=i18n
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA+3Zz2/bIBQH8H/lyadNCrZx82s5Teuph/bUSanWKWL2S8pqQ4RJqy3K/z7I0ogw
+        7TBp8rsgxYcA5svDH3Gw91mHaKXa9NkCvuzf/q2s7HDVW2Gsa8/K6aIs3S8bwXmEbFzPhE+qsE2t
+        temElVr52z5J9or43P6A0wBw3SD5XIHBVlhsoJF9vet7d0OfP5pH5a9bbRCCqUC8CNmKby2CsAt4
+        snbbL4pijY02Ymv0d6xtrs2meJXPsrjh87vi9lRUUZV8zJZL9vAAAO+WS2DQaWWfRuBaGDRuEfl7
+        X1YtWlSNMCslOvSL98sM6z3tiN4eN2T254b4uVZuDt/vYmes5KwchyNaXZ/35vfq2anrozR1vjaI
+        SjeYK7ThbZ1QYoPGP6Bsa8SLVH32NQr+e2hYz9tziOv6qdVxzOf76+wwgsTgPzPgcwIGl6GJATWD
+        yj2UwRnEoYkBPQM+IWBwGZoYUDO4ojgN4tDEgJ4BwWkQhyYG9AyqDwQMLkMTA2oGY8arwRnEoYkB
+        PYNqSsDgMjQxoGYwYbwcnEEcmhjQM6iGf4sYhyYG1AymrJwNziAOTQzoGVTDvzeIQxMDagb+iB6c
+        QRyaGNAz4MO/N4hD/5mBn1qYza5DZf135312dnD+hlmFWxbuVlT/1fFgCupWu7Y9HH4Bm4DFHNge
+        AAA=
+    headers:
+      Accept-Ranges: [bytes]
+      Age: ['0']
+      AppServer: [proxy04.fedoraproject.org]
+      AppTime: [D=176951]
+      Connection: [Keep-Alive]
+      Content-Encoding: [gzip]
+      Content-Length: ['515']
+      Content-Type: [application/json]
+      Date: ['Wed, 01 Feb 2017 08:36:43 GMT']
+      Keep-Alive: ['timeout=15, max=500']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      Set-Cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C3Mvmw.rzQ95C3LVBlZJKMEJVpzih4SIT4;
+          Expires=Wed, 01-Feb-2017 09:36:43 GMT; Secure; HttpOnly; Path=/calendar']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+      Vary: [Accept-Encoding]
+      Via: [1.1 varnish-v4]
+      X-Varnish: ['1754049']
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/widgets/meetings.py b/hubs/widgets/meetings.py
deleted file mode 100755
index 713177b..0000000
--- a/hubs/widgets/meetings.py
+++ /dev/null
@@ -1,117 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint
-from hubs.widgets.base import argument
-from hubs.widgets.chrome import panel
-from hubs.widgets import templating
-
-from hubs import validators
-from hubs import utils
-
-import hubs.models
-
-import arrow
-import collections
-import datetime
-import requests
-
-
-def next_meeting(meetings):
-    now = datetime.datetime.utcnow()
-    for meeting in meetings:
-        start_string = "%s %s" % (
-            meeting['meeting_date'], meeting['meeting_time_start'])
-        start_dt = datetime.datetime.strptime(
-            start_string, "%Y-%m-%d %H:%M:%S")
-
-        stop_string = "%s %s" % (
-            meeting['meeting_date_end'], meeting['meeting_time_stop'])
-        stop_dt = datetime.datetime.strptime(
-            stop_string, "%Y-%m-%d %H:%M:%S")
-
-        # Loop over them until we find a good one.
-        # Meetings before now are no good.  We want the first one after now.
-        if start_dt < now:
-            continue
-
-        meeting['start_dt'] = start_dt
-        meeting['start_date'] = start_dt.strftime('%b %d')
-        meeting['stop_date'] = stop_dt.strftime('%b %d')
-        meeting['display_time'] = True
-        meeting['display_duration'] = False
-        # Just UTC for now until we do this on the client and can access
-        # their local with moment.js.
-        meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
-        meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
-        meeting['location'] = meeting['meeting_location'] or ''
-        if '@' in meeting['location']:
-            meeting['location'] = '#' + meeting['location'].split('@')[0]
-        if stop_dt - start_dt >= datetime.timedelta(hours=24) :
-            meeting['display_time'] = False
-            if stop_dt - start_dt > datetime.timedelta(hours=24) :
-                meeting['display_duration'] = True
-        return meeting
-
-    return None
-
-
-footer_template = templating.environment.get_template('templates/meeting_footer.html')
-chrome = panel(title='Meetings', footer_template=footer_template)
-templating.environment.filters['humanize'] = lambda d: arrow.get(d).humanize()
-template = templating.environment.get_template('templates/meetings.html')
-position = 'both'
-
-
-@argument(name="calendar",
-          default=None,
-          validator=validators.required,
-          help="A fedocal calendar.")
-@argument(name="n_meetings",
-          default=4,
-          validator=validators.integer,
-          help="The number of meetings to display.")
-def data(session, widget, calendar, n_meetings=4):
-    n_meetings = int(n_meetings)
-    base = 'https://apps.fedoraproject.org/calendar/api/meetings/?calendar=%s'
-    url = base % calendar
-    response = requests.get(url).json()
-
-    tmp = collections.defaultdict(list)
-    for meeting in response['meetings']:
-        if meeting.get('meeting_information_html'):
-            meeting['meeting_information_html'] = utils.markup(
-                meeting['meeting_information'])
-        tmp[meeting['meeting_name']].append(meeting)
-
-    meetings = {}
-    for title, items in tmp.items():
-        selected = next_meeting(items)
-        if not selected:
-            continue
-        meetings[title] = selected
-        if len(meetings) >= n_meetings:
-            break
-
-    return dict(
-        calendar=calendar,
-        meetings=meetings,
-    )
-
-
-@hint(ubiquitous=True)
-def should_invalidate(message, session, widget):
-
-    # TODO -- first, if this is a fedocal widget, we need to just invalidate
-    # ourselves right away.
-
-    # second, check our old cache value and see if any of our meetings have
-    # passed by in time.
-    old_data = data(session, widget, **widget.config)
-    meetings = old_data['meetings']
-    now = datetime.datetime.utcnow()
-    for title, meeting in meetings.items():
-        assert type(meeting['start_dt']) == type(now)
-        if meeting['start_dt'] < now:
-            return True
-
-    return False
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
new file mode 100644
index 0000000..9209de2
--- /dev/null
+++ b/hubs/widgets/meetings/__init__.py
@@ -0,0 +1,135 @@
+from __future__ import unicode_literals
+
+import arrow
+import collections
+import datetime
+import requests
+
+from hubs import validators
+from hubs import utils
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+
+
+class Meetings(Widget):
+
+    name = "meetings"
+    position = "both"
+    arguments = [
+        dict(
+            name="calendar",
+            label="Calendar",
+            default=None,
+            validator=validators.required,
+            help="A fedocal calendar.",
+        ), dict(
+            name="n_meetings",
+            label="Number of meetings",
+            default=4,
+            validator=validators.integer,
+            help="The number of meetings to display.",
+        )]
+
+    def get_template_environment(self):
+        env = super(Meetings, self).get_template_environment()
+        # Add a filter
+        env.filters['humanize'] = lambda d: arrow.get(d).humanize()
+        return env
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/meetings.html"
+    chrome = panel(title='Meetings', footer_template='templates/meeting_footer.html')
+
+    def get_context(self, instance, *args, **kwargs):
+        get_meetings = GetMeetings(instance)
+        return dict(
+            calendar=instance.config["calendar"],
+            meetings=get_meetings(),
+            )
+
+
+class GetMeetings(CachedFunction):
+
+    def execute(self):
+        calendar = self.instance.config["calendar"]
+        n_meetings = int(self.instance.config.get("n_meetings", 4))
+        base = ('https://apps.fedoraproject.org/calendar/api/meetings/'
+                '?calendar=%s')
+        url = base % calendar
+        response = requests.get(url).json()
+
+        tmp = collections.defaultdict(list)
+        for meeting in response['meetings']:
+            if meeting.get('meeting_information_html'):
+                meeting['meeting_information_html'] = utils.markup(
+                    meeting['meeting_information'])
+            tmp[meeting['meeting_name']].append(meeting)
+
+        meetings = {}
+        for title, items in tmp.items():
+            selected = next_meeting(items)
+            if not selected:
+                continue
+            meetings[title] = selected
+            if len(meetings) >= n_meetings:
+                break
+
+        return meetings
+
+    def should_invalidate(self, message):
+        # TODO -- first, if this is a fedocal widget, we need to just
+        # invalidate ourselves right away.
+
+        # second, check our old cache value and see if any of our meetings have
+        # passed by in time.
+        old_meetings = self.execute()
+        now = datetime.datetime.utcnow()
+        for title, meeting in old_meetings.items():
+            assert type(meeting['start_dt']) == type(now)
+            if meeting['start_dt'] < now:
+                return True
+        return False
+
+
+def next_meeting(meetings):
+    now = datetime.datetime.utcnow()
+    for meeting in meetings:
+        start_string = "%s %s" % (
+            meeting['meeting_date'], meeting['meeting_time_start'])
+        start_dt = datetime.datetime.strptime(
+            start_string, "%Y-%m-%d %H:%M:%S")
+
+        stop_string = "%s %s" % (
+            meeting['meeting_date_end'], meeting['meeting_time_stop'])
+        stop_dt = datetime.datetime.strptime(
+            stop_string, "%Y-%m-%d %H:%M:%S")
+
+        # Loop over them until we find a good one.
+        # Meetings before now are no good.  We want the first one after now.
+        if start_dt < now:
+            continue
+
+        meeting['start_dt'] = start_dt
+        meeting['start_date'] = start_dt.strftime('%b %d')
+        meeting['stop_date'] = stop_dt.strftime('%b %d')
+        meeting['display_time'] = True
+        meeting['display_duration'] = False
+        # Just UTC for now until we do this on the client and can access
+        # their local with moment.js.
+        meeting['start_time'] = meeting['meeting_time_start'][:-3] + " UTC"
+        meeting['stop_time'] = meeting['meeting_time_stop'][:-3] + " UTC"
+        meeting['location'] = meeting['meeting_location'] or ''
+        if '@' in meeting['location']:
+            meeting['location'] = '#' + meeting['location'].split('@')[0]
+        if stop_dt - start_dt >= datetime.timedelta(hours=24):
+            meeting['display_time'] = False
+            if stop_dt - start_dt > datetime.timedelta(hours=24):
+                meeting['display_duration'] = True
+        return meeting
+
+    return None
diff --git a/populate.py b/populate.py
index 503b0e9..3eab11d 100755
--- a/populate.py
+++ b/populate.py
@@ -99,7 +99,7 @@ widget = hubs.models.Widget(plugin='rules', index=1,
 hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='meetings', index=2,
-                            _config=json.dumps({'calendar': 'commops'}))
+                            _config=json.dumps({'calendar': 'commops', 'n_meetings': 4}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -146,7 +146,7 @@ widget = hubs.models.Widget(plugin='rules', index=1,
 hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='meetings', index=2,
-                            _config=json.dumps({'calendar': 'marketing'}))
+                            _config=json.dumps({'calendar': 'marketing', 'n_meetings': 4}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -194,7 +194,7 @@ widget = hubs.models.Widget(plugin='rules', index=1,
 hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='meetings', index=2,
-                            _config=json.dumps({'calendar': 'design'}))
+                            _config=json.dumps({'calendar': 'design', 'n_meetings': 4}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -243,7 +243,7 @@ widget = hubs.models.Widget(plugin='rules', index=1,
 hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='meetings', index=2,
-                            _config=json.dumps({'calendar': 'infrastructure'}))
+                            _config=json.dumps({'calendar': 'infrastructure', 'n_meetings': 4}))
 hub.widgets.append(widget)
 
 # Added a hubs about widget

From dc975affd9ef56da03580da432687e6fc7eed2af Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 725/1001] Convert the memberships widget


---

diff --git a/hubs/widgets/memberships.py b/hubs/widgets/memberships.py
deleted file mode 100644
index 95beb74..0000000
--- a/hubs/widgets/memberships.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from __future__ import unicode_literals
-
-import hubs.models
-from hubs.hinting import hint, prefixed as _
-import hubs.validators as validators
-from hubs.widgets.base import argument
-from hubs.widgets.chrome import panel
-from hubs.widgets import templating
-
-ELLIPSIS_LIMIT = 3
-chrome = panel('Hubs')
-template = templating.environment.get_template('templates/memberships.html')
-position = 'both'
-
-
-def data(session, widget, **kwargs):
-    hub = widget.hub
-    members = []
-    if hub.user_hub:
-        user = hubs.models.User.by_username(hub.name)
-        members = [m.__json__() for m in user.memberships
-                   if m.name != user.username]
-    else:
-        members_name = []
-        for member in widget.hub.members:
-            if member.username in members_name:
-                continue
-            members_name.append(member.username)
-            members.append(member.__json__())
-
-    oldest_members = sorted(members,
-                            key=lambda m: m.get('created_on'))[:ELLIPSIS_LIMIT]
-    return dict(memberships=list(members), oldest_members=list(oldest_members))
-
-
-@hint(topics=[_('hubs.hub.update')])
-def should_invalidate(message, session, widget):
-    if message['topic'].endswith('hubs.hub.update'):
-        if message['msg']['hub']['name'] == widget.hub.name:
-            return True
-    return False
diff --git a/hubs/widgets/memberships/__init__.py b/hubs/widgets/memberships/__init__.py
new file mode 100644
index 0000000..cc8f602
--- /dev/null
+++ b/hubs/widgets/memberships/__init__.py
@@ -0,0 +1,45 @@
+from __future__ import unicode_literals
+
+import hubs.models
+
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import Widget, WidgetView
+
+
+ELLIPSIS_LIMIT = 3
+
+
+class Memberships(Widget):
+
+    name = "memberships"
+    position = "both"
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/memberships.html"
+    chrome = panel('Hubs')
+
+    def get_context(self, instance, *args, **kwargs):
+        hub = instance.hub
+        members = []
+        if hub.user_hub:
+            user = hubs.models.User.by_username(hub.name)
+            members = [m.__json__() for m in user.memberships
+                       if m.name != user.username]
+        else:
+            members_name = []
+            for member in hub.members:
+                if member.username in members_name:
+                    continue
+                members_name.append(member.username)
+                members.append(member.__json__())
+
+        oldest_members = sorted(
+            members, key=lambda m: m.get('created_on'))[:ELLIPSIS_LIMIT]
+        return dict(
+            memberships=list(members),
+            oldest_members=list(oldest_members),
+            )

From 46477d9d20f2fb7b0281746191e2628ff9665548 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 726/1001] Convert the pagureissues widget


---

diff --git a/hubs/widgets/pagureissues.py b/hubs/widgets/pagureissues.py
deleted file mode 100755
index 9a4dca8..0000000
--- a/hubs/widgets/pagureissues.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from __future__ import unicode_literals
-
-import requests
-
-from hubs.hinting import hint
-from hubs.widgets.chrome import panel
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-import hubs.validators as validators
-
-pagure_url = "https://pagure.io/api/0"
-
-chrome = panel("Newest Open Tickets on Pagure")
-template = templating.environment.get_template('templates/pagureissues.html')
-position = 'right'
-
-
-@argument(name="repo",
-          default=None,
-          validator=validators.pagure_repo,
-          help="Pagure repo name")
-def data(session, widget, repo):
-    ''' Data for pagure issues widget
-    Queries Pagure api for issues '''
-
-    repo = "pagure"
-
-    url = '/'.join([pagure_url, repo, "issues"])
-    issue_response = requests.get(url)
-    data = issue_response.json()
-    total = data['total_issues']
-
-    all_issues = list()
-    for issue in data['issues']:
-
-        issue_assignee = None
-        if issue['assignee']:
-            issue_assignee = issue['assignee']['name']
-
-        issue_project_user = None
-        if 'project' in issue:
-            issue_project_name = issue['project']['name']
-            if issue['project']['parent']:
-                issue_project_user = issue['project']['user']['username']
-            else:
-                if '/' in repo:
-                    issue_project_name, issue_project_user = repo.split('/', 1)
-                else:
-                    issue_project_name = repo
-
-        all_issues.append(
-            dict(
-                issue_project_name=issue_project_name,
-                issue_project_user=issue_project_user,
-                issue_id=issue['id'],
-                issue_title=issue['title'][:45],
-                issue_title_full=issue['title'],
-                issue_openedby=issue['user']['name'],
-                issue_assignee=issue_assignee,
-            )
-        )
-
-    all_issues.reverse()
-
-    return dict(
-        repo=repo,
-        total=total,
-        all_issues=all_issues,
-    )
-
-
-@hint()
-def should_invalidate(message, session, widget):
-    ''' Checks whether pagureissues widget cache needs an update
-    Run by backend daemon listening to fedmsg '''
-
-    raise NotImplementedError
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
new file mode 100644
index 0000000..2be36a8
--- /dev/null
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -0,0 +1,91 @@
+from __future__ import unicode_literals
+
+import requests
+
+from hubs import validators
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+pagure_url = "https://pagure.io/api/0"
+
+
+class PagureIssues(Widget):
+
+    name = "pagureissues"
+    position = "right"
+    arguments = [
+        dict(
+            name="repo",
+            label="Repository",
+            default=None,
+            validator=validators.pagure_repo,
+            help="Pagure repo name",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/pagureissues.html"
+    chrome = panel("Newest Open Tickets on Pagure")
+
+    def get_context(self, instance, *args, **kwargs):
+        get_issues = GetIssues(instance)
+        context = dict(repo=instance.config["repo"])
+        context.update(get_issues())
+        return context
+
+
+class GetIssues(CachedFunction):
+    ''' Data for pagure issues widget
+    Queries Pagure api for issues '''
+
+    def execute(self):
+        repo = self.instance.config["repo"]
+
+        url = '/'.join([pagure_url, repo, "issues"])
+        issue_response = requests.get(url)
+        data = issue_response.json()
+        total = data['total_issues']
+
+        all_issues = list()
+        for issue in data['issues']:
+
+            issue_assignee = None
+            if issue['assignee']:
+                issue_assignee = issue['assignee']['name']
+
+            issue_project_user = None
+            if 'project' in issue:
+                issue_project_name = issue['project']['name']
+                if issue['project']['parent']:
+                    issue_project_user = issue['project']['user']['username']
+                else:
+                    if '/' in repo:
+                        issue_project_name, issue_project_user = \
+                            repo.split('/', 1)
+                    else:
+                        issue_project_name = repo
+
+            all_issues.append(
+                dict(
+                    issue_project_name=issue_project_name,
+                    issue_project_user=issue_project_user,
+                    issue_id=issue['id'],
+                    issue_title=issue['title'][:45],
+                    issue_title_full=issue['title'],
+                    issue_openedby=issue['user']['name'],
+                    issue_assignee=issue_assignee,
+                )
+            )
+
+        all_issues.reverse()
+        return dict(
+            total=total,
+            all_issues=all_issues,
+        )
+
+    def should_invalidate(self, message):
+        raise NotImplementedError

From 7a94d6ea57ae6e85dbdca197133f9be9306b77dc Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 727/1001] Convert the pagure_pr widget


---

diff --git a/hubs/widgets/pagure_pr.py b/hubs/widgets/pagure_pr.py
deleted file mode 100755
index 081dcb4..0000000
--- a/hubs/widgets/pagure_pr.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint
-from hubs.widgets.chrome import panel
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-
-import hubs.validators as validators
-
-import requests
-
-pagure_url = "https://pagure.io/api/0"
-
-chrome = panel("Newest Open Pull Requests on Pagure")
-template = templating.environment.get_template('templates/pagure_pr.html')
-position = 'right'
-
-
-@argument(name="repo",
-          default=None,
-          validator=validators.pagure_repo,
-          help="Pagure repo name")
-def data(session, widget, repo):
-    url = '/'.join([pagure_url, repo, "pull-requests"])
-    response = requests.get(url)
-    data = response.json()
-    total_req = data['total_requests']
-    all_pr = list()
-
-    for request in data['requests']:
-        pr_project_user = None
-        if request['project']['parent']:
-            pr_project_user = request['project']['user']['username']
-
-        all_pr.append(
-            dict(
-                pr_project_name=request['project']['name'],
-                pr_project_user=pr_project_user,
-                pr_id=request['id'],
-                pr_title=request['title'][:45],
-                pr_title_full=request['title'],
-                pr_openedby=request['user']['name'],
-                pr_assignee=request['assignee'],
-            )
-        )
-
-    return dict(
-        all_pr=all_pr,
-        total_req=total_req,
-        repo=repo,
-    )
-
-
-# TODO -- this hint could be honed in more to just PRs
-@hint(categories=['pagure'])
-def should_invalidate(message, session, widget):
-    return message['msg']['project']['name'] == widget.config['repo']
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
new file mode 100644
index 0000000..6e3cf5a
--- /dev/null
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -0,0 +1,79 @@
+from __future__ import unicode_literals
+
+from hubs import validators
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+import requests
+
+pagure_url = "https://pagure.io/api/0"
+
+
+class PagurePRs(Widget):
+
+    name = "pagure_pr"
+    position = "right"
+    arguments = [
+        dict(
+            name="repo",
+            label="Repository",
+            default=None,
+            validator=validators.pagure_repo,
+            help="Pagure repo name.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/pagure_pr.html"
+    chrome = panel("Newest Open Pull Requests on Pagure")
+
+    def get_context(self, instance, *args, **kwargs):
+        get_prs = GetPRs(instance)
+        context = dict(repo=instance.config["repo"])
+        context.update(get_prs())
+        return context
+
+
+class GetPRs(CachedFunction):
+
+    def execute(self):
+        repo = self.instance.config["repo"]
+        url = '/'.join([pagure_url, repo, "pull-requests"])
+        response = requests.get(url)
+        data = response.json()
+        total_req = data['total_requests']
+        all_pr = list()
+
+        for request in data['requests']:
+            pr_project_user = None
+            if request['project']['parent']:
+                pr_project_user = request['project']['user']['username']
+
+            all_pr.append(
+                dict(
+                    pr_project_name=request['project']['name'],
+                    pr_project_user=pr_project_user,
+                    pr_id=request['id'],
+                    pr_title=request['title'][:45],
+                    pr_title_full=request['title'],
+                    pr_openedby=request['user']['name'],
+                    pr_assignee=request['assignee'],
+                )
+            )
+
+        return dict(
+            all_pr=all_pr,
+            total_req=total_req,
+        )
+
+    def should_invalidate(self, message):
+        category = message["topic"].split('.')[3]
+        if category != "pagure":
+            # TODO -- this could be honed in more to just PRs
+            return False
+        return (message['msg']['project']['name'] ==
+                self.instance.config['repo'])

From 050777aa069d8a37646bc09ff9f05c28c68dfce2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 728/1001] Convert the rules widget


---

diff --git a/hubs/widgets/rules.py b/hubs/widgets/rules.py
deleted file mode 100755
index d7554b9..0000000
--- a/hubs/widgets/rules.py
+++ /dev/null
@@ -1,58 +0,0 @@
-from __future__ import unicode_literals
-
-from collections import OrderedDict as ordereddict
-
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.chrome import panel
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-from hubs.utils import username2avatar
-from hubs import validators
-
-ELLIPSIS_LIMIT = 5
-chrome = panel()
-template = templating.environment.get_template('templates/rules.html')
-position = 'both'
-
-
-@argument(name='link', default=None,
-          validator=validators.link,
-          help="Link to the community rules and guidelines")
-@argument(name='schedule_text', default=None,
-          validator=validators.text,
-          help="Some text about when meetings are")
-@argument(name='schedule_link', default=None,
-          validator=validators.link,
-          help="Link to a schedule for IRC meetings, etc..")
-@argument(name='minutes_link', default=None,
-          validator=validators.link,
-          help="Link to meeting minutes from past meetings..")
-def data(session, widget, link, schedule_text, schedule_link, minutes_link):
-    owners = widget.hub.owners
-    oldest_owners = sorted(owners, key=lambda o: o.created_on)[:ELLIPSIS_LIMIT]
-    oldest_owners = [{
-        'username': o.username,
-        'avatar': username2avatar(o.username)
-    } for o in oldest_owners]
-
-    owners = ordereddict([
-        (o.username, username2avatar(o.username)) for o in owners
-    ])
-    return dict(oldest_owners=oldest_owners,
-                owners=owners, link=link,
-                schedule_text=schedule_text,
-                schedule_link=schedule_link,
-                minutes_link=minutes_link)
-
-
-@hint(topics=[_('hubs.widget.update'), _('hubs.hub.update')])
-def should_invalidate(message, session, widget):
-    if message['topic'].endswith('hubs.widget.update'):
-        if message['msg']['widget']['id'] == widget.id:
-            return True
-
-    if message['topic'].endswith('hubs.hub.update'):
-        if message['msg']['hub']['name'] == widget.hub.name:
-            return True
-
-    return False
diff --git a/hubs/widgets/rules/__init__.py b/hubs/widgets/rules/__init__.py
new file mode 100644
index 0000000..742ff22
--- /dev/null
+++ b/hubs/widgets/rules/__init__.py
@@ -0,0 +1,72 @@
+from __future__ import unicode_literals
+
+from collections import OrderedDict as ordereddict
+
+from hubs import validators
+from hubs.utils import username2avatar
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import Widget, WidgetView
+
+
+ELLIPSIS_LIMIT = 5
+
+
+class Rules(Widget):
+
+    name = "rules"
+    position = "both"
+    arguments = [
+        dict(
+            name="link",
+            label="Link",
+            default=None,
+            validator=validators.link,
+            help="Link to the community rules and guidelines.",
+        ), dict(
+            name="schedule_text",
+            label="Schedule text",
+            default=None,
+            validator=validators.text,
+            help="Some text about when meetings are.",
+        ), dict(
+            name="schedule_link",
+            label="Schedule link",
+            default=None,
+            validator=validators.link,
+            help="Link to a schedule for IRC meetings, etc.",
+        ), dict(
+            name="minutes_link",
+            label="Minutes link",
+            default=None,
+            validator=validators.link,
+            help="Link to meeting menutes from past meetings.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/rules.html"
+    chrome = panel()
+
+    def get_context(self, instance, *args, **kwargs):
+        owners = instance.hub.owners
+        oldest_owners = sorted(
+            owners, key=lambda o: o.created_on)[:ELLIPSIS_LIMIT]
+        oldest_owners = [{
+            'username': o.username,
+            'avatar': username2avatar(o.username)
+        } for o in oldest_owners]
+
+        owners = ordereddict([
+            (o.username, username2avatar(o.username)) for o in owners
+        ])
+        return dict(
+            oldest_owners=oldest_owners,
+            owners=owners,
+            link=instance.config["link"],
+            schedule_text=instance.config["schedule_text"],
+            schedule_link=instance.config["schedule_link"],
+            minutes_link=instance.config["minutes_link"],
+            )

From e115da1bb17c3b049c05aa4711b29c4a69b27d45 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 729/1001] Convert the stats widget


---

diff --git a/hubs/widgets/stats.py b/hubs/widgets/stats.py
deleted file mode 100755
index ebd6cc8..0000000
--- a/hubs/widgets/stats.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.chrome import panel
-from hubs.widgets import templating
-
-from hubs.utils import commas
-
-import flask
-
-chrome = panel()
-template = templating.environment.get_template('templates/stats.html')
-position = 'right'
-
-
-def data(session, widget):
-    owners = [u.username for u in widget.hub.owners]
-    members = [u.username for u in widget.hub.members]
-    subscribers = [u.username for u in widget.hub.subscribers]
-    stargazers = [u.username for u in widget.hub.stargazers]
-
-    return dict(
-        owners=owners,
-        members=members,
-        subscribers=subscribers,
-        stargazers=stargazers,
-
-        owners_text=commas(len(owners)),
-        members_text=commas(len(members)),
-        subscribers_text=commas(len(subscribers)),
-        stargazers_text=commas(len(stargazers)),
-
-        hub_leave_url=flask.url_for('hub_leave', hub=widget.hub.name),
-        hub_join_url=flask.url_for('hub_join', hub=widget.hub.name),
-        hub_unstar_url=flask.url_for('hub_unstar', hub=widget.hub.name),
-        hub_star_url=flask.url_for('hub_star', hub=widget.hub.name),
-        hub_subscribe_url=flask.url_for('hub_subscribe', hub=widget.hub.name),
-        hub_unsubscribe_url=flask.url_for(
-            'hub_unsubscribe', hub=widget.hub.name),
-    )
-
-
-@hint(topics=[_('hubs.hub.update')])
-def should_invalidate(message, session, widget):
-    if message['topic'].endswith('hubs.hub.update'):
-        if message['msg']['hub']['name'] == widget.hub.name:
-            return True
-
-    # TODO -- also check for FAS group changes??  are we doing that?
-
-    return False
diff --git a/hubs/widgets/stats/__init__.py b/hubs/widgets/stats/__init__.py
new file mode 100644
index 0000000..1ffe664
--- /dev/null
+++ b/hubs/widgets/stats/__init__.py
@@ -0,0 +1,66 @@
+from __future__ import unicode_literals
+
+import flask
+
+from hubs.utils import commas
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+
+class Stats(Widget):
+
+    name = "stats"
+    position = "right"
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/stats.html"
+    chrome = panel()
+
+    def get_context(self, instance, *args, **kwargs):
+        get_stats = GetStats(instance)
+        return get_stats()
+
+
+class GetStats(CachedFunction):
+
+    def execute(self):
+        hub = self.instance.hub
+        owners = [u.username for u in hub.owners]
+        members = [u.username for u in hub.members]
+        subscribers = [u.username for u in hub.subscribers]
+        stargazers = [u.username for u in hub.stargazers]
+
+        return dict(
+            owners=owners,
+            members=members,
+            subscribers=subscribers,
+            stargazers=stargazers,
+
+            owners_text=commas(len(owners)),
+            members_text=commas(len(members)),
+            subscribers_text=commas(len(subscribers)),
+            stargazers_text=commas(len(stargazers)),
+
+            hub_leave_url=flask.url_for('hub_leave', hub=hub.name),
+            hub_join_url=flask.url_for('hub_join', hub=hub.name),
+            hub_unstar_url=flask.url_for('hub_unstar', hub=hub.name),
+            hub_star_url=flask.url_for('hub_star', hub=hub.name),
+            hub_subscribe_url=flask.url_for('hub_subscribe', hub=hub.name),
+            hub_unsubscribe_url=flask.url_for(
+                'hub_unsubscribe', hub=hub.name),
+        )
+
+    def should_invalidate(self, message):
+        if not message['topic'].endswith('hubs.hub.update'):
+            return False
+        if message['msg']['hub']['name'] == self.instance.hub.name:
+            return True
+
+        # TODO -- also check for FAS group changes??  are we doing that?
+
+        return False

From bacb3b6664e04846b3e613e13c86f2845af4e9d8 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 730/1001] Convert the sticky widget


---

diff --git a/hubs/widgets/sticky.py b/hubs/widgets/sticky.py
deleted file mode 100755
index ca74f59..0000000
--- a/hubs/widgets/sticky.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.chrome import panel
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-
-import hubs.validators as validators
-
-chrome = panel(title='Sticky Note', klass="card-info")
-template = templating.environment.get_template('templates/sticky.html')
-position = 'both'
-
-
-@argument(name="text", default="Lorem ipsum dolor...",
-          validator=validators.text,
-          help="Some dummy text to display.")
-def data(session, widget, text):
-    # TODO -- render with markdown
-    return dict(text=text)
-
-
-@hint(topics=[_('hubs.widget.update')])
-def should_invalidate(message, session, widget):
-    if message['topic'].endswith('hubs.widget.update'):
-        if message['msg']['widget']['id'] == widget.id:
-            return True
-
-    return False
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
new file mode 100644
index 0000000..409b382
--- /dev/null
+++ b/hubs/widgets/sticky/__init__.py
@@ -0,0 +1,31 @@
+from __future__ import unicode_literals
+
+from hubs import validators
+from hubs.widgets.chrome import panel
+from hubs.widgets.base import Widget, WidgetView
+
+
+class Sticky(Widget):
+
+    name = "sticky"
+    position = "both"
+    arguments = [
+        dict(
+            name="text",
+            label="Text",
+            default="Lorem ipsum dolor...",
+            validator=validators.text,
+            help="Some dummy text to display.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/sticky.html"
+    chrome = panel(title='Sticky Note', klass="card-info")
+
+    def get_context(self, instance, *args, **kwargs):
+        # TODO -- render with markdown
+        return dict(text=instance.config["text"])

From 4f72c0d06f137eba1dd7f39d5b49eb0301e113ae Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 731/1001] Convert the subscriptions widget


---

diff --git a/hubs/widgets/subscriptions.py b/hubs/widgets/subscriptions.py
deleted file mode 100755
index 4446c25..0000000
--- a/hubs/widgets/subscriptions.py
+++ /dev/null
@@ -1,60 +0,0 @@
-from __future__ import unicode_literals
-
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.base import argument
-from hubs.widgets.chrome import panel
-from hubs.widgets import templating
-
-from hubs import validators
-
-import hubs.models
-
-from fedmsg.meta.base import BaseConglomerator as BC
-
-import fedmsg.config
-fm_config = fedmsg.config.load_config()
-
-import flask
-
-chrome = panel('Hubs', key='associations')
-template = templating.environment.get_template('templates/subscriptions.html')
-position = 'right'
-
-
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-def data(session, widget, username):
-    user = hubs.models.User.by_username(username)
-    ownerships = [u.name for u in user.ownerships]
-    memberships = [u.name for u in user.memberships]
-    subscriptions = [u.name for u in user.subscriptions]
-    subscriptions_list = manage_subscriptions(subscriptions)
-    memberships_list = manage_subscriptions(memberships)
-    return dict(
-        associations=memberships + ownerships,
-        ownerships=ownerships,
-        memberships=memberships,
-        subscriptions=subscriptions,
-        ownerships_text=BC.list_to_series(ownerships),
-        memberships_text=BC.list_to_series(memberships_list),
-        subscriptions_text=BC.list_to_series(subscriptions_list),
-    )
-
-
-# function hyperlinks the hubs in the subscription widget
-def manage_subscriptions(items):
-    return [
-        '<a href="{link}">{item}</a>'.format(
-            link=flask.url_for('hub', name=item),
-            item=item,
-        ) for index, item in enumerate(items[0:3])
-    ]
-
-
-@hint(topics=[_('hubs.associate')])
-def should_invalidate(message, session, widget):
-    username = widget.config['username']
-    users = fedmsg.meta.msg2usernames(message, **fm_config)
-    return username in users
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
new file mode 100644
index 0000000..352945d
--- /dev/null
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -0,0 +1,78 @@
+from __future__ import unicode_literals
+
+import flask
+import hubs.models
+
+from hubs import validators
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
+
+from fedmsg.meta.base import BaseConglomerator as BC
+
+import fedmsg.config
+fm_config = fedmsg.config.load_config()
+
+
+class Subscriptions(Widget):
+
+    name = "subscriptions"
+    position = "right"
+    arguments = [
+        dict(
+            name="username",
+            label="Username",
+            default=None,
+            validator=validators.username,
+            help="A FAS username.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "templates/subscriptions.html"
+    chrome = panel('Hubs', key='associations')
+
+    def get_context(self, instance, *args, **kwargs):
+        get_subs = GetSubs(instance)
+        return get_subs()
+
+
+# function hyperlinks the hubs in the subscription widget
+def manage_subscriptions(items):
+    return [
+        '<a href="{link}">{item}</a>'.format(
+            link=flask.url_for('hub', name=item),
+            item=item,
+        ) for index, item in enumerate(items[0:3])
+    ]
+
+
+class GetSubs(CachedFunction):
+
+    def execute(self):
+        username = self.instance.config["username"]
+        user = hubs.models.User.by_username(username)
+        ownerships = [u.name for u in user.ownerships]
+        memberships = [u.name for u in user.memberships]
+        subscriptions = [u.name for u in user.subscriptions]
+        subscriptions_list = manage_subscriptions(subscriptions)
+        memberships_list = manage_subscriptions(memberships)
+        return dict(
+            associations=memberships + ownerships,
+            ownerships=ownerships,
+            memberships=memberships,
+            subscriptions=subscriptions,
+            ownerships_text=BC.list_to_series(ownerships),
+            memberships_text=BC.list_to_series(memberships_list),
+            subscriptions_text=BC.list_to_series(subscriptions_list),
+        )
+
+    def should_invalidate(self, message):
+        if not message['topic'].endswith('hubs.associate'):
+            return False
+        username = self.instance.config['username']
+        users = fedmsg.meta.msg2usernames(message, **fm_config)
+        return username in users

From f306fe3a5fffbb5fd0b216d280a86bec6a20fc46 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 732/1001] Convert the workflow widgets


---

diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 5bc6594..4676844 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -2,52 +2,67 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.base import argument
-from hubs.widgets import templating
+from hubs import validators
 from hubs.utils import username2avatar
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
 
-import hubs.validators as validators
 
-from hubs.widgets.chrome import panel
-# If 'pending_acls' is empty, then don't render any chrome.
-chrome = panel('Pending ACL Requests', key='pending_acls')
-# TODO -- add approve/deny buttons or just link through to pkgdb
-template = templating.environment.get_template(
-    'templates/workflow/pendingacls.html')
-position = 'right'
-
-
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-def data(session, widget, username):
-
-    # TODO -- rewrite this to
-    # 1) use the datagrepper API instead of the direct pkgdb API
-    # 2) so that we can use the fedmsg.meta.conglomerate API to
-    # 3) group messages nicely in the UI instead of having repeats
-    # It will be slower, but that's fine because of our smart cache.
-
-    baseurl = "https://admin.fedoraproject.org/pkgdb/api/pendingacls"
-    query = "?username={username}&format=json".format(username=username)
-    url = baseurl + query
-    response = requests.get(url)
-    data = response.json()
-    for acl in data['pending_acls']:
-        acl['avatar'] = username2avatar(acl['user'], s=32)
-    data['username'] = username
-    return data
-
-
-@hint(topics=[_('pkgdb.acl.update')])
-def should_invalidate(message, session, widget):
-    # Search the message to see if I am in the ACLs list of the request.
-    username = widget.config['username']
-
-    for acl in message['msg']['package_listing']['acls']:
-        if acl['fas_name'] == username and acl['status'] == 'Approved':
-            return True
-
-    return False
+class PendingACLs(Widget):
+
+    name = "workflow.pendingacls"
+    position = "right"
+    arguments = [
+        dict(
+            name="username",
+            label="Username",
+            default=None,
+            validator=validators.username,
+            help="A FAS username.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    # TODO -- add approve/deny buttons or just link through to pkgdb
+    template_name = "templates/workflow/pendingacls.html"
+    # If 'pending_acls' is empty, then don't render any chrome.
+    chrome = panel('Pending ACL Requests', key='pending_acls')
+
+    def get_context(self, instance, *args, **kwargs):
+        get_pending = GetPending(instance)
+        context = dict(username=instance.config["username"])
+        context.update(get_pending())
+        return context
+
+
+class GetPending(CachedFunction):
+
+    def execute(self):
+        # TODO -- rewrite this to
+        # 1) use the datagrepper API instead of the direct pkgdb API
+        # 2) so that we can use the fedmsg.meta.conglomerate API to
+        # 3) group messages nicely in the UI instead of having repeats
+        # It will be slower, but that's fine because of our cache.
+        username = self.instance.config["username"]
+        baseurl = "https://admin.fedoraproject.org/pkgdb/api/pendingacls"
+        query = "?username={username}&format=json".format(username=username)
+        url = baseurl + query
+        response = requests.get(url)
+        data = response.json()
+        for acl in data['pending_acls']:
+            acl['avatar'] = username2avatar(acl['user'], s=32)
+        return data
+
+    def should_invalidate(self, message):
+        if not message['topic'].endswith('pkgdb.acl.update'):
+            return False
+        # Search the message to see if I am in the ACLs list of the request.
+        username = self.instance.config["username"]
+        for acl in message['msg']['package_listing']['acls']:
+            if acl['fas_name'] == username and acl['status'] == 'Approved':
+                return True
+        return False
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index c7df1c3..7bca860 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -2,60 +2,45 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs.hinting import hint, prefixed as _
-from hubs.widgets.base import argument
-from hubs.widgets import templating
-import hubs.validators as validators
+from hubs import validators
+from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.chrome import panel
 
 
-from hubs.widgets.chrome import panel
-# If 'updates' is empty, then don't render any chrome.
-chrome = panel('Updates Ready for Stable', key='updates')
-# TODO -- add approve/deny buttons or just link through to pkgdb
-template = templating.environment.get_template(
-    'templates/workflow/updates2stable.html')
-position = 'right'
-
-# TODO - the bodhi api exposes a new flag we can use instead of scraping comments...
+# TODO - the bodhi api exposes a new flag we can use instead of scraping
+# comments...
 giveaway = 'can be pushed to stable now'
 
 
-@argument(name="username",
-          default=None,
-          validator=validators.username,
-          help="A FAS username.")
-def data(session, widget, username):
-
-    # First, get all of my updates currently in testing.
-    bodhiurl = 'https://bodhi.fedoraproject.org/updates/'
-    query = '?user={username}&status=testing'.format(username=username)
-    url = bodhiurl + query
-    headers = {'Accept': 'application/json'}
-    response = requests.get(url, headers=headers)
-    if response.status_code == 200:
-        data = response.json()
-
-        # Limit this to only the updates that haven't already requested stable
-        # but which can actually be pushed to stable now.
-        data['updates'] = [
-            update for update in data['updates']
-            if update['request'] is None and
-            any([giveaway in comment['text'] for comment in update['comments']])
-        ]
-
-        # Stuff some useful information in there.
-        baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
-        for update in data['updates']:
-            build = update['builds'][0]
-            nvr = build['nvr']
-            package = parse_nvr(nvr)
-            update['icon'] = baseurl + package[0] + '.png'
-            update['link'] = bodhiurl + update['title']
-
-        return data
-    else:
-        data = {}
-        return data
+class Updates2Stable(Widget):
+
+    name = "workflow.updates2stable"
+    position = "right"
+    arguments = [
+        dict(
+            name="username",
+            label="Username",
+            default=None,
+            validator=validators.username,
+            help="A FAS username.",
+        )]
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    # TODO -- add approve/deny buttons or just link through to pkgdb
+    template_name = "templates/workflow/updates2stable.html"
+    # If 'updates' is empty, then don't render any chrome.
+    chrome = panel('Updates Ready for Stable', key='updates')
+
+    def get_context(self, instance, *args, **kwargs):
+        get_pending = GetPending(instance)
+        context = dict(username=instance.config["username"])
+        context.update(get_pending())
+        return context
 
 
 def parse_nvr(nvr):
@@ -64,11 +49,47 @@ def parse_nvr(nvr):
     return ['-'.join(x[:-2]), x[-2], x[-1]]
 
 
-@hint(topics=[_('bodhi.update.comment')])
-def should_invalidate(message, session, widget):
-    if giveaway in message['msg']['comment']['text']:
-        username = widget.config['username']
-        if username == message['msg']['comment']['update_submitter']:
-            return True
-
-    return False
+class GetPending(CachedFunction):
+
+    def execute(self):
+        username = self.instance.config["username"]
+        # First, get all of my updates currently in testing.
+        bodhiurl = 'https://bodhi.fedoraproject.org/updates/'
+        query = '?user={username}&status=testing'.format(username=username)
+        url = bodhiurl + query
+        headers = {'Accept': 'application/json'}
+        response = requests.get(url, headers=headers)
+        if response.status_code == 200:
+            data = response.json()
+
+            # Limit this to only the updates that haven't already requested
+            # stable but which can actually be pushed to stable now.
+            data['updates'] = [
+                update for update in data['updates']
+                if update['request'] is None and
+                any([giveaway in comment['text']
+                     for comment in update['comments']])
+            ]
+
+            # Stuff some useful information in there.
+            baseurl = 'https://apps.fedoraproject.org/packages/images/icons/'
+            for update in data['updates']:
+                build = update['builds'][0]
+                nvr = build['nvr']
+                package = parse_nvr(nvr)
+                update['icon'] = baseurl + package[0] + '.png'
+                update['link'] = bodhiurl + update['title']
+
+            return data
+        else:
+            data = {}
+            return data
+
+    def should_invalidate(self, message):
+        if not message['topic'].endswith('bodhi.update.comment'):
+            return False
+        if giveaway in message['msg']['comment']['text']:
+            username = self.instance.config['username']
+            if username == message['msg']['comment']['update_submitter']:
+                return True
+        return False

From df2130ce09ccb8d53e46f7b4dfd49b67089c66f5 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 733/1001] Replace the chrome wrapper with template inheritance


---

diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index d068a1b..6fa31e9 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -19,5 +19,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         self.assertDictEqual(data['data'], {
             u'edit_url': u'/ralph/56/edit',
             u'source_url': u'/source/about',
-            u'text': u'Testing.',
+            'text': 'Testing.',
+            'title': "<span class='glyphicon glyphicon-info-sign' "
+                     "aria-hidden='true'></span> About",
         })
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 92b4bde..6e4ba36 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -18,6 +18,7 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
                 "urls": "ralph/"
             },
             "data": {
+                'title': 'Library',
                 "edit_url": "/ralph/%d/edit" % widget.idx,
                 "source_url": "/source/library",
                 "urls": [
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index aff28b0..aa8ff61 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -1,6 +1,5 @@
 from __future__ import unicode_literals
 
-from hubs.widgets.chrome import panel
 from hubs.widgets.base import Widget, WidgetView
 
 from hubs import validators
@@ -24,7 +23,10 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/about.html"
-    chrome = panel("<span class='glyphicon glyphicon-info-sign' aria-hidden='true'></span> About")
 
     def get_context(self, instance, *args, **kwargs):
-        return dict(text=instance.config["text"])
+        return dict(
+            text=instance.config["text"],
+            title="<span class='glyphicon glyphicon-info-sign' "
+                  "aria-hidden='true'></span> About",
+            )
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index a6d838f..3664ae5 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -6,7 +6,6 @@ import requests
 from hubs import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 
 class Badges(Widget):
@@ -27,11 +26,12 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/badges.html"
-    chrome = panel("Badges")
 
     def get_context(self, instance, *args, **kwargs):
+        context = {"title": "Badges"}
         get_badges = GetBadges(instance)
-        return get_badges()
+        context.update(get_badges())
+        return context
 
 
 class GetBadges(CachedFunction):
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index ca42357..6a27bec 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -6,7 +6,6 @@ import pkgwat.api
 from hubs import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 
 PKGDB_URL = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
@@ -30,11 +29,11 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/bugzilla.html"
-    chrome = panel("Bugzilla: Issues")
 
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
         return dict(
+            title="Bugzilla: Issues",
             username=instance.config["username"],
             issues=get_issues()
             )
diff --git a/hubs/widgets/chrome.py b/hubs/widgets/chrome.py
deleted file mode 100644
index cc9b4ca..0000000
--- a/hubs/widgets/chrome.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from __future__ import unicode_literals
-
-from functools import wraps
-from hubs.widgets import templating
-
-_panel_template = templating.environment.get_template(
-    'templates/panel.html')
-_panel_heading_template = templating.environment.get_template(
-    'templates/panel_heading.html')
-
-
-# FIXME: replace with template block extension
-def panel(title=None, klass="panel-default", key=None, footer_template=None):
-    def decorator(view, func):
-        @wraps(func)
-        def inner(*args, **kwargs):
-            heading = ''
-            footer = ''
-            if title:
-                heading = _panel_heading_template.render(title=title)
-            if footer_template:
-                footer = templating.environment.get_template(
-                    footer_template).render(**kwargs)
-            content = func(*args, **kwargs)
-            if key and not kwargs.get(key):
-                return content
-            return _panel_template.render(
-                content=content,
-                heading=heading,
-                footer=footer,
-                klass=klass(kwargs) if callable(klass) else klass,
-                **kwargs)
-        return inner
-    return decorator
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index 88841fe..c491eb3 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -7,7 +7,6 @@ import fedmsg.meta
 import hubs.models
 
 from hubs.widgets.base import Widget, WidgetView
-from hubs.widgets.chrome import panel
 
 config = fedmsg.config.load_config()
 
@@ -23,7 +22,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/contact.html"
-    chrome = panel()
 
     def get_context(self, instance, *args, **kwargs):
         ''' Data for Contact widget. Checks if the hub associated
diff --git a/hubs/widgets/dummy/__init__.py b/hubs/widgets/dummy/__init__.py
index 738711a..1a96ee5 100644
--- a/hubs/widgets/dummy/__init__.py
+++ b/hubs/widgets/dummy/__init__.py
@@ -1,7 +1,6 @@
 from __future__ import unicode_literals
 
 from hubs import validators
-from hubs.widgets.chrome import panel
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -23,7 +22,9 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/dummy.html"
-    chrome = panel("This is a dummy widget")
 
     def get_context(self, instance, *args, **kwargs):
-        return dict(text=instance.config["text"])
+        return dict(
+            title="This is a dummy widget",
+            text=instance.config["text"],
+            )
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index b31ae11..82f68c1 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -9,7 +9,6 @@ from hubs import validators
 from hubs.utils import commas
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 fedmsg_config = fedmsg.config.load_config()
 
@@ -32,7 +31,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/fedmsgstats.html"
-    chrome = panel()
 
     def get_context(self, instance, *args, **kwargs):
         username = instance.config["username"]
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index 678152d..d2601f1 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -2,7 +2,6 @@ from __future__ import unicode_literals
 
 
 from hubs import validators
-from hubs.widgets.chrome import panel
 from hubs.widgets.base import Widget, WidgetView
 
 import logging
@@ -34,7 +33,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/feed.html"
-    chrome = panel("Live Feed")
 
     def get_context(self, instance, *args, **kwargs):
         # Avoid circular import
@@ -42,6 +40,7 @@ class BaseView(WidgetView):
         username = instance.config["username"]
         feed_url = app.config['SSE_URL'] + username
         return dict(
+            title="Live Feed",
             matches=[],
             message_limit=instance.config["message_limit"],
             feed_url=feed_url,
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
index ec1dc93..3c55f9c 100644
--- a/hubs/widgets/fhosted/__init__.py
+++ b/hubs/widgets/fhosted/__init__.py
@@ -5,7 +5,6 @@ from six.moves.xmlrpc_client import ServerProxy
 from hubs import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 
 class FedoraHosted(Widget):
@@ -33,11 +32,13 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/fedorahosted.html"
-    chrome = panel("Fedorahosted: Open Tickets")
 
     def get_context(self, instance, *args, **kwargs):
         get_tickets = GetTickets(instance)
-        context = dict(project=instance.config["project"])
+        context = dict(
+            title="Fedorahosted: Open Tickets",
+            project=instance.config["project"],
+            )
         context.update(get_tickets())
         return context
 
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 5478f1c..9a03bc5 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -6,7 +6,6 @@ import hubs.utils
 from hubs import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 import fedmsg.config
 fedmsg_config = fedmsg.config.load_config()
@@ -39,7 +38,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/github_pr.html"
-    chrome = panel("Github: Pull Requests")
 
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
@@ -48,6 +46,7 @@ class BaseView(WidgetView):
         context = dict(
             organization=org,
             display_number=display_number,
+            title="Github: Pull Requests",
         )
         context.update(get_prs())
         return context
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index efee564..e70dabf 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -5,7 +5,6 @@ import requests
 from hubs import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 
 class GitHubIssues(Widget):
@@ -39,7 +38,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/githubissues.html"
-    chrome = panel("Github: Newest Open Tickets")
 
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
@@ -47,6 +45,7 @@ class BaseView(WidgetView):
             org=instance.config["org"],
             repo=instance.config["repo"],
             display_number=int(instance.config["display_number"]),
+            title="Github: Newest Open Tickets",
             all_issues=get_issues(),
         )
 
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index 09ec390..af990ac 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -2,7 +2,6 @@ from __future__ import unicode_literals
 
 from hubs import validators
 from hubs.widgets import clean_input
-from hubs.widgets.chrome import panel
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -26,7 +25,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/library.html"
-    chrome = panel("Library")
 
     def get_context(self, instance, *args, **kwargs):
         urls = [
@@ -35,4 +33,7 @@ class BaseView(WidgetView):
             for u in instance.config.get('urls', '').split(',')
             if u.strip()
         ]
-        return dict(urls=urls)
+        return dict(
+            title="Library",
+            urls=urls,
+            )
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index c7ac68e..adc9590 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -1,7 +1,6 @@
 from __future__ import unicode_literals
 
 from hubs import validators
-from hubs.widgets.chrome import panel
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -23,7 +22,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/linechart.html"
-    chrome = panel("Weekly Activity")
 
     def get_context(self, instance, *args, **kwargs):
         username = instance.config["username"]
@@ -42,4 +40,7 @@ class BaseView(WidgetView):
                "&user={username}&split_on=categories")
         url = url + "&" + categories
         url = url.format(username=username)
-        return dict(url=url)
+        return dict(
+            title="Weekly Activity",
+            url=url,
+            )
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index 9209de2..8a5c7ef 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -7,7 +7,6 @@ import requests
 
 from hubs import validators
 from hubs import utils
-from hubs.widgets.chrome import panel
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -43,11 +42,11 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/meetings.html"
-    chrome = panel(title='Meetings', footer_template='templates/meeting_footer.html')
 
     def get_context(self, instance, *args, **kwargs):
         get_meetings = GetMeetings(instance)
         return dict(
+            title="Meetings",
             calendar=instance.config["calendar"],
             meetings=get_meetings(),
             )
diff --git a/hubs/widgets/memberships/__init__.py b/hubs/widgets/memberships/__init__.py
index cc8f602..cd36983 100644
--- a/hubs/widgets/memberships/__init__.py
+++ b/hubs/widgets/memberships/__init__.py
@@ -2,7 +2,6 @@ from __future__ import unicode_literals
 
 import hubs.models
 
-from hubs.widgets.chrome import panel
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -20,7 +19,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/memberships.html"
-    chrome = panel('Hubs')
 
     def get_context(self, instance, *args, **kwargs):
         hub = instance.hub
@@ -40,6 +38,7 @@ class BaseView(WidgetView):
         oldest_members = sorted(
             members, key=lambda m: m.get('created_on'))[:ELLIPSIS_LIMIT]
         return dict(
+            title="Hubs",
             memberships=list(members),
             oldest_members=list(oldest_members),
             )
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 6e3cf5a..ad047a7 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
 from hubs import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 import requests
 
@@ -29,11 +28,13 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/pagure_pr.html"
-    chrome = panel("Newest Open Pull Requests on Pagure")
 
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
-        context = dict(repo=instance.config["repo"])
+        context = dict(
+            title="Newest Open Pull Requests on Pagure",
+            repo=instance.config["repo"],
+            )
         context.update(get_prs())
         return context
 
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index 2be36a8..690dd86 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -5,7 +5,6 @@ import requests
 from hubs import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 pagure_url = "https://pagure.io/api/0"
 
@@ -29,11 +28,13 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/pagureissues.html"
-    chrome = panel("Newest Open Tickets on Pagure")
 
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
-        context = dict(repo=instance.config["repo"])
+        context = dict(
+            title="Newest Open Tickets on Pagure",
+            repo=instance.config["repo"],
+            )
         context.update(get_issues())
         return context
 
diff --git a/hubs/widgets/rules/__init__.py b/hubs/widgets/rules/__init__.py
index 742ff22..84b2016 100644
--- a/hubs/widgets/rules/__init__.py
+++ b/hubs/widgets/rules/__init__.py
@@ -4,7 +4,6 @@ from collections import OrderedDict as ordereddict
 
 from hubs import validators
 from hubs.utils import username2avatar
-from hubs.widgets.chrome import panel
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -48,7 +47,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/rules.html"
-    chrome = panel()
 
     def get_context(self, instance, *args, **kwargs):
         owners = instance.hub.owners
diff --git a/hubs/widgets/stats/__init__.py b/hubs/widgets/stats/__init__.py
index 1ffe664..87d4415 100644
--- a/hubs/widgets/stats/__init__.py
+++ b/hubs/widgets/stats/__init__.py
@@ -5,7 +5,6 @@ import flask
 from hubs.utils import commas
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 
 class Stats(Widget):
@@ -19,7 +18,6 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/stats.html"
-    chrome = panel()
 
     def get_context(self, instance, *args, **kwargs):
         get_stats = GetStats(instance)
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index 409b382..28c8fed 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -1,7 +1,6 @@
 from __future__ import unicode_literals
 
 from hubs import validators
-from hubs.widgets.chrome import panel
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -24,8 +23,11 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/sticky.html"
-    chrome = panel(title='Sticky Note', klass="card-info")
 
     def get_context(self, instance, *args, **kwargs):
         # TODO -- render with markdown
-        return dict(text=instance.config["text"])
+        return dict(
+            text=instance.config["text"],
+            title="Sticky Note",
+            panel_css_class="card-info",
+            )
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
index 352945d..466beb9 100644
--- a/hubs/widgets/subscriptions/__init__.py
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -6,7 +6,6 @@ import hubs.models
 from hubs import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 from fedmsg.meta.base import BaseConglomerator as BC
 
@@ -33,11 +32,12 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     template_name = "templates/subscriptions.html"
-    chrome = panel('Hubs', key='associations')
 
     def get_context(self, instance, *args, **kwargs):
+        context = dict(title="Hubs")
         get_subs = GetSubs(instance)
-        return get_subs()
+        context.update(get_subs())
+        return context
 
 
 # function hyperlinks the hubs in the subscription widget
diff --git a/hubs/widgets/templates/about.html b/hubs/widgets/templates/about.html
index f73bbab..3b25a3a 100644
--- a/hubs/widgets/templates/about.html
+++ b/hubs/widgets/templates/about.html
@@ -1 +1,5 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <p>{{text}}</p>
+{% endblock %}
diff --git a/hubs/widgets/templates/badges.html b/hubs/widgets/templates/badges.html
index 926c8d0..22a0562 100644
--- a/hubs/widgets/templates/badges.html
+++ b/hubs/widgets/templates/badges.html
@@ -1,7 +1,11 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <div class="flex-container">
 {% for badge in assertions %}
   <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
     <span class="f-b-{{badge['id']}}"></span>
   </a>
-{%endfor%}
+{% endfor %}
 </div>
+{% endblock %}
diff --git a/hubs/widgets/templates/bugzilla.html b/hubs/widgets/templates/bugzilla.html
index 86891ec..9809c31 100644
--- a/hubs/widgets/templates/bugzilla.html
+++ b/hubs/widgets/templates/bugzilla.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <ul class="media-list">
   {% for item in issues %}
     <li class="media">
@@ -15,3 +18,4 @@
     </li>
   {% endfor %}
 </ul>
+{% endblock %}
diff --git a/hubs/widgets/templates/contact.html b/hubs/widgets/templates/contact.html
index 7c3cccf..9898a18 100644
--- a/hubs/widgets/templates/contact.html
+++ b/hubs/widgets/templates/contact.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <div class="contactinfo-container">
   {% if usergroup %}
     <ul style="list-style: none; padding-left: 5px">
@@ -68,3 +71,4 @@
     </ul>
   {% endif %}
 </div>
+{% endblock %}
diff --git a/hubs/widgets/templates/dummy.html b/hubs/widgets/templates/dummy.html
index 8d15644..6e318ec 100644
--- a/hubs/widgets/templates/dummy.html
+++ b/hubs/widgets/templates/dummy.html
@@ -1 +1,5 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 {{text}}
+{% endblock %}
diff --git a/hubs/widgets/templates/fedmsgstats.html b/hubs/widgets/templates/fedmsgstats.html
index bb569e7..fe369e2 100644
--- a/hubs/widgets/templates/fedmsgstats.html
+++ b/hubs/widgets/templates/fedmsgstats.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <div class="stats-container row">
   <div class="col-sm-7 col-md-12 col-lg-7">
   <table class="stats-table">
@@ -21,3 +24,4 @@
   {% endif %}
   </div>
 </div>
+{% endblock %}
diff --git a/hubs/widgets/templates/fedorahosted.html b/hubs/widgets/templates/fedorahosted.html
index ad22b57..5dcc574 100644
--- a/hubs/widgets/templates/fedorahosted.html
+++ b/hubs/widgets/templates/fedorahosted.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 {% if error %}
 <p>{{ error }}</p>
 {% else %}
@@ -42,3 +45,4 @@
   {% endif %}
 </ul>
 {% endif %}
+{% endblock %}
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
index aeed666..84256cc 100644
--- a/hubs/widgets/templates/feed.html
+++ b/hubs/widgets/templates/feed.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <div id="feed">
 </div>
 
@@ -15,3 +18,4 @@
    ReactDOM.render(FeedElement, document.getElementById('feed'));
  })();
 </script>
+{% endblock %}
diff --git a/hubs/widgets/templates/github_pr.html b/hubs/widgets/templates/github_pr.html
index 8b4a105..743c9aa 100644
--- a/hubs/widgets/templates/github_pr.html
+++ b/hubs/widgets/templates/github_pr.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <a class="btn btn-success" target="_blank"
     href="https://github.com/{{ organization }}" >
   Organization Github Page
@@ -44,3 +47,4 @@
   </li>
 {% endif %}
 </ul>
+{% endblock %}
diff --git a/hubs/widgets/templates/githubissues.html b/hubs/widgets/templates/githubissues.html
index cd5de9d..1a57dab 100644
--- a/hubs/widgets/templates/githubissues.html
+++ b/hubs/widgets/templates/githubissues.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 {% for i in range(display_number) %}
 <div>
   <table class="table-responsive table-condensed">
@@ -36,3 +39,4 @@
 <div class="row">
   <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
 </div>
+{% endblock %}
diff --git a/hubs/widgets/templates/library.html b/hubs/widgets/templates/library.html
index 4cbff48..a9155b5 100644
--- a/hubs/widgets/templates/library.html
+++ b/hubs/widgets/templates/library.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <div class="rules-container">
   <div class="row">
     <ul>
@@ -9,3 +12,4 @@
     </ul>
   </div>
 </div>
+{% endblock %}
diff --git a/hubs/widgets/templates/linechart.html b/hubs/widgets/templates/linechart.html
index 5b4e756..3cc86ef 100644
--- a/hubs/widgets/templates/linechart.html
+++ b/hubs/widgets/templates/linechart.html
@@ -1,3 +1,7 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <div class="flex-container">
     <img src="{{url}}" />
 </div>
+{% endblock %}
diff --git a/hubs/widgets/templates/meeting_footer.html b/hubs/widgets/templates/meeting_footer.html
deleted file mode 100644
index 50b49ef..0000000
--- a/hubs/widgets/templates/meeting_footer.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<div class="panel-footer">
-  <div class="row" align="center">
-    <button class="btn btn-default">
-      <strong>Request A New Meeting</strong>
-    </button>
-  </div>
-</div>
diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
index b101c5f..600c82c 100644
--- a/hubs/widgets/templates/meetings.html
+++ b/hubs/widgets/templates/meetings.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 {% for title, next in meetings.items() %}
 <div class="meeting">
   <div class="row">
@@ -46,3 +49,15 @@
   </div>
 </div>
 {% endfor %}
+{% endblock %}
+
+
+{% block footer %}
+<div class="panel-footer">
+  <div class="row" align="center">
+    <button class="btn btn-default">
+      <strong>Request A New Meeting</strong>
+    </button>
+  </div>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/templates/memberships.html b/hubs/widgets/templates/memberships.html
index 534aa95..57c6d70 100644
--- a/hubs/widgets/templates/memberships.html
+++ b/hubs/widgets/templates/memberships.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <div class="card-block">
   {% if memberships|length > oldest_members|length %}
   {% for member in oldest_members %}
@@ -74,3 +77,4 @@
    padding: 10px;
  }
 </style>
+{% endblock %}
diff --git a/hubs/widgets/templates/pagure_pr.html b/hubs/widgets/templates/pagure_pr.html
index 94b2f23..735ac7b 100644
--- a/hubs/widgets/templates/pagure_pr.html
+++ b/hubs/widgets/templates/pagure_pr.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <ul class="media-list">
   {% for pr in all_pr[:10] %}
     <li class="media">
@@ -46,3 +49,4 @@
     href="https://pagure.io/{{ repo }}/pull-requests">
   All Pull-Requests
 </a>
+{% endblock %}
diff --git a/hubs/widgets/templates/pagureissues.html b/hubs/widgets/templates/pagureissues.html
index 258d37e..55c6a74 100644
--- a/hubs/widgets/templates/pagureissues.html
+++ b/hubs/widgets/templates/pagureissues.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <a class="btn btn-success" target="_blank"
     href="https://pagure.io/{{ repo }}/issues">
   All Issues
@@ -45,3 +48,4 @@
   </li>
   {% endif %}
 </ul>
+{% endblock %}
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index 02ead38..d07fd13 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -1,18 +1,20 @@
-<div class="card {{ klass }}">
+<div class="card {{ panel_css_class|default('panel-default') }} widget-{{ widget.name }}">
   <div class="pull-right widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
     <a href="{{ source_url }}"><span><i class="fa fa-eye" aria-hidden="true"></i></span></a>
     <a href="{{ widget_url }}"><span><i class="fa fa-external-link" aria-hidden="true"></i></span></a>
     <a data-target="#edit_modal" data-toggle="modal" type="button"
-        class="edit_widget" data-idx="{{ widget.idx }}">
+        class="edit_widget" data-idx="{{ widget_instance.idx }}">
       <span><i class="fa fa-pencil" aria-hidden="true"></i></span>
     </a>
   </div>
-  {{ heading }}
+  {% if title %}
+  <div class="card-header">
+    {{title}}
+  </div> <!-- end card-header -->
+  {% endif %}
   <div class="card-block">
-    {{ content }}
+    {% block content %}{% endblock %}
   </div> <!-- end card-block -->
-  {% if footer %}
-    {{footer}}
-  {% endif %}
+  {% block footer %}{% endblock %}
 </div> <!-- end card -->
diff --git a/hubs/widgets/templates/panel_heading.html b/hubs/widgets/templates/panel_heading.html
deleted file mode 100644
index eab2086..0000000
--- a/hubs/widgets/templates/panel_heading.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<div class="card-header">
-    {{title}}
-</div> <!-- end card-header -->
diff --git a/hubs/widgets/templates/rules.html b/hubs/widgets/templates/rules.html
index 9ab51e8..d233741 100644
--- a/hubs/widgets/templates/rules.html
+++ b/hubs/widgets/templates/rules.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <div class="rules-container">
   {% if link %}
   <h6>community rules</h6>
@@ -85,3 +88,4 @@
    border-bottom: 0;
  }
 </style>
+{% endblock %}
diff --git a/hubs/widgets/templates/stats.html b/hubs/widgets/templates/stats.html
index 63bf1e5..f2cba1f 100644
--- a/hubs/widgets/templates/stats.html
+++ b/hubs/widgets/templates/stats.html
@@ -1,3 +1,6 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 <div class="stats-container row">
 <div class="col-md-7">
   <table class="stats-table">
@@ -72,3 +75,4 @@
   </ul>
 </div>
 </div>
+{% endblock %}
diff --git a/hubs/widgets/templates/sticky.html b/hubs/widgets/templates/sticky.html
index 8d15644..6e318ec 100644
--- a/hubs/widgets/templates/sticky.html
+++ b/hubs/widgets/templates/sticky.html
@@ -1 +1,5 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
 {{text}}
+{% endblock %}
diff --git a/hubs/widgets/templates/subscriptions.html b/hubs/widgets/templates/subscriptions.html
index 74e46f2..99fa9a2 100644
--- a/hubs/widgets/templates/subscriptions.html
+++ b/hubs/widgets/templates/subscriptions.html
@@ -1,4 +1,7 @@
 {% if associations %}
+{% extends "templates/panel.html" %}
+
+{% block content %}
     {% if memberships %}
         <p><strong>Belongs to: </strong> {{memberships_text}}</p>
     {% endif %}
@@ -10,4 +13,5 @@
         {{subscription}}</a>
         {% endfor %}</p>
     {% endif %}
+{% endblock %}
 {% endif %}
diff --git a/hubs/widgets/templates/workflow/pendingacls.html b/hubs/widgets/templates/workflow/pendingacls.html
index c419d61..2775fb2 100644
--- a/hubs/widgets/templates/workflow/pendingacls.html
+++ b/hubs/widgets/templates/workflow/pendingacls.html
@@ -1,4 +1,8 @@
 {% if pending_acls %}
+
+{% extends "templates/panel.html" %}
+
+{% block content %}
 {% if session['nickname'] == username %}
 <a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/pkgdb/acl/pending/">Manage requests</a>
 <hr/>
@@ -17,4 +21,6 @@
     </li>
 {% endfor %}
 </ul>
+{% endblock %}
+
 {% endif %}
diff --git a/hubs/widgets/templates/workflow/updates2stable.html b/hubs/widgets/templates/workflow/updates2stable.html
index 35e2d25..3982895 100644
--- a/hubs/widgets/templates/workflow/updates2stable.html
+++ b/hubs/widgets/templates/workflow/updates2stable.html
@@ -1,4 +1,7 @@
 {% if updates %}
+{% extends "templates/panel.html" %}
+
+{% block content %}
 {% if session['nickname'] == username %}
 <a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
 <hr/>
@@ -18,4 +21,5 @@
     </li>
 {% endfor %}
 </ul>
+{% endblock %}
 {% endif %}
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index f6f486a..3c2ccb7 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -1,6 +1,5 @@
 from __future__ import unicode_literals, absolute_import
 
-import flask
 from flask.views import View
 
 
@@ -33,7 +32,6 @@ class WidgetView(View):
             for (like the `rule` parameter of Flask's `add_url_rule()`).
         template_name (str): The template name to use for this view. It will be
             looked for in the widget's template environment.
-        chrome (function): An optional chrome template wrapper.
 
     This class is Flask-specific. If another framework were to be switched to,
     it would have to be re-implemented.
@@ -42,7 +40,6 @@ class WidgetView(View):
     name = None
     url_rules = []
     template_name = None
-    chrome = None
 
     def __init__(self, widget):
         """
@@ -104,8 +101,4 @@ class WidgetView(View):
         instance = self._get_instance(*args, **kwargs)
         context = self.get_context(instance, *args, **kwargs)
         context.update(self.get_extra_context(instance, *args, **kwargs))
-        template = self.get_template()
-        if self.chrome is None:
-            return self.get_template().render(**context)
-        else:
-            return self.chrome(template.render)(**context)
+        return self.get_template().render(**context)
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 4676844..cc4cb3a 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -6,7 +6,6 @@ from hubs import validators
 from hubs.utils import username2avatar
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 
 class PendingACLs(Widget):
@@ -29,12 +28,13 @@ class BaseView(WidgetView):
     url_rules = ["/"]
     # TODO -- add approve/deny buttons or just link through to pkgdb
     template_name = "templates/workflow/pendingacls.html"
-    # If 'pending_acls' is empty, then don't render any chrome.
-    chrome = panel('Pending ACL Requests', key='pending_acls')
 
     def get_context(self, instance, *args, **kwargs):
         get_pending = GetPending(instance)
-        context = dict(username=instance.config["username"])
+        context = dict(
+            title='Pending ACL Requests',
+            username=instance.config["username"],
+            )
         context.update(get_pending())
         return context
 
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 7bca860..00df8fc 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -5,7 +5,6 @@ import requests
 from hubs import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
-from hubs.widgets.chrome import panel
 
 
 # TODO - the bodhi api exposes a new flag we can use instead of scraping
@@ -33,12 +32,13 @@ class BaseView(WidgetView):
     url_rules = ["/"]
     # TODO -- add approve/deny buttons or just link through to pkgdb
     template_name = "templates/workflow/updates2stable.html"
-    # If 'updates' is empty, then don't render any chrome.
-    chrome = panel('Updates Ready for Stable', key='updates')
 
     def get_context(self, instance, *args, **kwargs):
         get_pending = GetPending(instance)
-        context = dict(username=instance.config["username"])
+        context = dict(
+            title='Updates Ready for Stable',
+            username=instance.config["username"],
+            )
         context.update(get_pending())
         return context
 

From 7a05ed469e552b2d27bba49de4669d01dc06bc20 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 734/1001] Replace the AGPLv3 template variables with template tags


---

diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index 6fa31e9..35ff9fa 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -15,10 +15,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
         data = json.loads(response.get_data(as_text=True))
-        del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
-            u'edit_url': u'/ralph/56/edit',
-            u'source_url': u'/source/about',
             'text': 'Testing.',
             'title': "<span class='glyphicon glyphicon-info-sign' "
                      "aria-hidden='true'></span> About",
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index 0d7e79d..6bb9cca 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -13,12 +13,9 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
         response = self.app.get('/ralph/%i/json/' % widget.idx)
         assert response.status_code == 200, response.status_code
         data = json.loads(response.get_data(as_text=True))
-        del data['data']['widget_url']
         self.assertDictEqual(data['data'], {
-            u'edit_url': u'/ralph/37/edit',
             u'fedmsgs': 83854,
             u'fedmsgs_text': u'83,854',
-            u'source_url': u'/source/fedmsgstats',
             u'subscribers': [],
             u'subscribed_to': [],
             u'subscribers_text': u'0',
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 6e4ba36..88db8b0 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -19,12 +19,9 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
             },
             "data": {
                 'title': 'Library',
-                "edit_url": "/ralph/%d/edit" % widget.idx,
-                "source_url": "/source/library",
                 "urls": [
                     "<a href=\"ralph/\">ralph/</a>"
                 ],
-                "widget_url": "/ralph/w/library/%d/" % widget.idx
             },
             "description": None,
             "hub": "ralph",
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index d07fd13..1f86223 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -1,8 +1,10 @@
 <div class="card {{ panel_css_class|default('panel-default') }} widget-{{ widget.name }}">
   <div class="pull-right widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
-    <a href="{{ source_url }}"><span><i class="fa fa-eye" aria-hidden="true"></i></span></a>
-    <a href="{{ widget_url }}"><span><i class="fa fa-external-link" aria-hidden="true"></i></span></a>
+    <a href="{{ url_for('widget_source', name=widget.name) }}"><span><i class="fa fa-eye" aria-hidden="true"></i></span></a>
+    <a href="{{ url_for('%s_root' % widget.name, hub=widget_instance.hub.name, idx=widget_instance.idx) }}">
+        <span><i class="fa fa-external-link" aria-hidden="true"></i></span>
+    </a>
     <a data-target="#edit_modal" data-toggle="modal" type="button"
         class="edit_widget" data-idx="{{ widget_instance.idx }}">
       <span><i class="fa fa-pencil" aria-hidden="true"></i></span>
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index 3c2ccb7..572b670 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -76,13 +76,6 @@ class WidgetView(View):
         """
         # Put source links in all API results
         return {
-            'source_url': flask.url_for(
-                'widget_source', name=self.widget.name),
-            'widget_url': flask.url_for(
-                '%s_root' % self.widget.name,
-                hub=instance.hub.name, idx=instance.idx),
-            'edit_url': flask.url_for(
-                'widget_edit', hub=instance.hub.name, idx=instance.idx),
             'widget': self.widget,
             'widget_instance': instance,
         }

From faddb5d41ec83bc8633f60e36ed9c8e03744ffd5 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 735/1001] Move widget templates inside the widget directory


---

diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index aa8ff61..1a8cc50 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -22,7 +22,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/about.html"
+    template_name = "about.html"
 
     def get_context(self, instance, *args, **kwargs):
         return dict(
diff --git a/hubs/widgets/about/templates/about.html b/hubs/widgets/about/templates/about.html
new file mode 100644
index 0000000..eafc55a
--- /dev/null
+++ b/hubs/widgets/about/templates/about.html
@@ -0,0 +1,5 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<p>{{text}}</p>
+{% endblock %}
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index 3664ae5..6c76716 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -25,7 +25,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/badges.html"
+    template_name = "badges.html"
 
     def get_context(self, instance, *args, **kwargs):
         context = {"title": "Badges"}
diff --git a/hubs/widgets/badges/templates/badges.html b/hubs/widgets/badges/templates/badges.html
new file mode 100644
index 0000000..c7201d2
--- /dev/null
+++ b/hubs/widgets/badges/templates/badges.html
@@ -0,0 +1,11 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="flex-container">
+{% for badge in assertions %}
+  <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
+    <span class="f-b-{{badge['id']}}"></span>
+  </a>
+{% endfor %}
+</div>
+{% endblock %}
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index ecccf46..9123a4d 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -3,6 +3,8 @@ from __future__ import unicode_literals, absolute_import
 import collections
 import logging
 import re
+import flask
+import jinja2
 
 from importlib import import_module
 from .caching import CachedFunction
@@ -33,6 +35,9 @@ class Widget(object):
     position = None
     arguments = []
 
+    def __init__(self):
+        self._template_environment = None
+
     def validate(self):
         """Ensure that the widget has the bits it needs."""
         if self.name is None:
@@ -60,13 +65,26 @@ class Widget(object):
     def get_template_environment(self):
         """
         Get the template environment that widget-specific views will use.
+
+        If additional filters or variables are needed in the templates, they
+        can be added by overriding this method in the widget subclass.
         """
-        # We may have widget-specific template environment one day
-        # (when widget templates are stored in the widget's directory
-        # instead of a common widget template directory).
-        # When that happens, it should be cached in a Widget attribute.
-        from hubs.widgets.templating import environment
-        return environment
+        if self._template_environment is None:
+            env = jinja2.Environment(
+                loader=jinja2.ChoiceLoader([
+                    jinja2.PackageLoader(self.__module__, "templates"),
+                    jinja2.PackageLoader("hubs.widgets", "templates"),
+                    ]),
+                trim_blocks=True,
+            )
+            env.filters['tojson'] = flask.json.tojson_filter
+            env.globals.update({
+                'session': flask.app.session,
+                'g': flask.g,
+                'url_for': flask.url_for,
+                })
+            self._template_environment = env
+        return self._template_environment
 
     def _get_local_subclasses(self, parent_class):
         """
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 6a27bec..5965be1 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -28,7 +28,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/bugzilla.html"
+    template_name = "bugzilla.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
diff --git a/hubs/widgets/bugzilla/templates/bugzilla.html b/hubs/widgets/bugzilla/templates/bugzilla.html
new file mode 100644
index 0000000..5fc68b5
--- /dev/null
+++ b/hubs/widgets/bugzilla/templates/bugzilla.html
@@ -0,0 +1,21 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<ul class="media-list">
+  {% for item in issues %}
+    <li class="media">
+      <div class="media-left">
+        <a href="https://bugzilla.redhat.com/show_bug.cgi?id={{ item['id'] }}" target="_blank">
+        <span class="label label-default">#{{ item['id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <a href="https://apps.fedoraproject.org/packages/{{ item['pkg_name'] }}" target="_blank">{{ item['pkg_name'] }}</a>:
+          {{ item['title'] }}
+        </h4>
+      </div>
+    </li>
+  {% endfor %}
+</ul>
+{% endblock %}
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index c491eb3..f5e5722 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -21,7 +21,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/contact.html"
+    template_name = "contact.html"
 
     def get_context(self, instance, *args, **kwargs):
         ''' Data for Contact widget. Checks if the hub associated
diff --git a/hubs/widgets/contact/templates/contact.html b/hubs/widgets/contact/templates/contact.html
new file mode 100644
index 0000000..d4844e9
--- /dev/null
+++ b/hubs/widgets/contact/templates/contact.html
@@ -0,0 +1,74 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="contactinfo-container">
+  {% if usergroup %}
+    <ul style="list-style: none; padding-left: 5px">
+      <!--<li><i class="fa fa-map-marker" aria-hidden="true"></i>
+          <span class="col-md-offset-1">{{location}}</span></li>-->
+      <li><i class="fa fa-clock-o" aria-hidden="true"></i>
+          <span class="col-md-offset-1">Current-Time :</span>
+          <script type="text/javascript">
+            // TODO: send offset after querying fas3
+            function calcTime(offset) {
+
+              // create Date object for current location
+              d = new Date();
+
+              // convert to msec
+              // add local time zone offset
+              // get UTC time in msec
+              utc = d.getTime() + (d.getTimezoneOffset() * 60000);
+
+              // create new Date object using supplied offset
+              nd = new Date(utc + (3600000 * offset));
+
+              // return time as a string
+              return nd.toLocaleString();
+            }
+
+            setInterval(function() {
+              $("#time").html(calcTime(-4))
+            }, 1000)
+
+            function get_karma_stats() {
+                var karma_url = '{{ karma_url }}';
+                  $.ajax({
+                    method: "GET",
+                    url: karma_url,
+                    dataType: 'html',
+                    success: function(html) {
+                      console.log('Success: ' + html);
+                      karma_arr = JSON.parse(html);
+                      console.log(karma_arr)
+                      $('#karma_current').html("Karma : "+karma_arr['current']+" ("+karma_arr['total']+" all time)");
+                    },
+                    error: function() {
+                      console.log('Error: getting karma');
+                    },
+                  });
+                }
+            get_karma_stats()
+          </script>
+          <span id="time"></span></li>
+      <li><i class="fa fa-envelope" aria-hidden="true"></i>
+          <span class="col-md-offset-1">{{email}}</span></li>
+      <li><i class="fa fa-comment" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span>{{ircnick}}</li>
+      <li><i class="fa fa-user-plus" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span><span id="karma_current"></span></li>
+      <li><i class="fa fa-certificate" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span> Member Since {{account_age}}</li>
+    </ul>
+  {% else %}
+    <ul style="list-style: none">
+      <li><i class="fa fa-comment" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span>fedora-{{ircchannel}}</li>
+      <li><i class="fa fa-envelope" aria-hidden="true"></i>
+          <span class="col-md-offset-1"><a href="{{ mailinglist }}">{{ hubname }}@lists.fedoraproject.org</a></span></li>
+      <li><i class="fa fa-info" aria-hidden="true"></i>
+          <span class="col-md-offset-1"><a href="{{ wikilink }}">fedoraproject.org/wiki/{{ hubname }}</a></span></li>
+    </ul>
+  {% endif %}
+</div>
+{% endblock %}
diff --git a/hubs/widgets/dummy/__init__.py b/hubs/widgets/dummy/__init__.py
index 1a96ee5..19d43c4 100644
--- a/hubs/widgets/dummy/__init__.py
+++ b/hubs/widgets/dummy/__init__.py
@@ -21,7 +21,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/dummy.html"
+    template_name = "dummy.html"
 
     def get_context(self, instance, *args, **kwargs):
         return dict(
diff --git a/hubs/widgets/dummy/templates/dummy.html b/hubs/widgets/dummy/templates/dummy.html
new file mode 100644
index 0000000..f2b2486
--- /dev/null
+++ b/hubs/widgets/dummy/templates/dummy.html
@@ -0,0 +1,5 @@
+{% extends "panel.html" %}
+
+{% block content %}
+{{text}}
+{% endblock %}
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 82f68c1..a557148 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -30,7 +30,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/fedmsgstats.html"
+    template_name = "fedmsgstats.html"
 
     def get_context(self, instance, *args, **kwargs):
         username = instance.config["username"]
diff --git a/hubs/widgets/fedmsgstats/templates/fedmsgstats.html b/hubs/widgets/fedmsgstats/templates/fedmsgstats.html
new file mode 100644
index 0000000..d30234e
--- /dev/null
+++ b/hubs/widgets/fedmsgstats/templates/fedmsgstats.html
@@ -0,0 +1,27 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="stats-container row">
+  <div class="col-sm-7 col-md-12 col-lg-7">
+  <table class="stats-table">
+    <tr><th>subscribers</th><th>subscribed to</th></tr>
+    <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
+  </table>
+  </div>
+  <div class="col-sm-5 col-md-12 col-lg-5">
+  {% if session['nickname'] != username %}
+    <ul class="list-unstyled">
+    {% if session['nickname'] in subscribers %}
+    <li><form action="{{hub_unsubscribe_url}}" method="POST">
+        <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
+    </form></li>
+    {% else %}
+    <li><form action="{{hub_subscribe_url}}" method="POST">
+        <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
+    </form></li>
+    {% endif %}
+    </ul>
+  {% endif %}
+  </div>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index d2601f1..bd35b61 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -32,7 +32,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/feed.html"
+    template_name = "feed.html"
 
     def get_context(self, instance, *args, **kwargs):
         # Avoid circular import
diff --git a/hubs/widgets/feed/templates/feed.html b/hubs/widgets/feed/templates/feed.html
new file mode 100644
index 0000000..3f3bc87
--- /dev/null
+++ b/hubs/widgets/feed/templates/feed.html
@@ -0,0 +1,21 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div id="feed">
+</div>
+
+<script type="text/javascript"
+        src ="{{url_for('static', filename='js/hubs.js')}}"></script>
+<script>
+ (function() {
+   const FeedElement = React.createElement(Feed, {
+     matches: {{ matches }},
+     url: '{{ feed_url }}',
+     options: {
+       messageLimit: {{ message_limit }}
+     }
+   });
+   ReactDOM.render(FeedElement, document.getElementById('feed'));
+ })();
+</script>
+{% endblock %}
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
index 3c55f9c..2c9d26c 100644
--- a/hubs/widgets/fhosted/__init__.py
+++ b/hubs/widgets/fhosted/__init__.py
@@ -31,7 +31,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/fedorahosted.html"
+    template_name = "fhosted.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_tickets = GetTickets(instance)
diff --git a/hubs/widgets/fhosted/templates/fhosted.html b/hubs/widgets/fhosted/templates/fhosted.html
new file mode 100644
index 0000000..5dcc574
--- /dev/null
+++ b/hubs/widgets/fhosted/templates/fhosted.html
@@ -0,0 +1,48 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
+{% if error %}
+<p>{{ error }}</p>
+{% else %}
+<a class="btn btn-success" target="_blank"
+    href="https://fedorahosted.org/{{ project }}/report/1">
+  All Issues
+</a>
+<hr/>
+
+<ul class="media-list">
+  {% for issue in tickets %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://fedorahosted.org/{{ project }}/ticket/{{ issue['id'] }}"
+            target="_blank">
+        <span class="label label-default">#{{ issue['id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <span title="{{ issue['summary'] }}">
+            {{ issue['short_summary'] }} {% if
+              issue['summary'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+            {{ issue['reporter'] }}
+        --
+        {% if issue['owner'] %}
+          Assigned to:
+            {{issue['owner'] }}
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if total_tickets > tickets | length %}
+  <li>
+    And {{ total_tickets - tickets | length }} more ...
+  </li>
+  {% endif %}
+</ul>
+{% endif %}
+{% endblock %}
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 9a03bc5..8b9aab3 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -37,7 +37,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/github_pr.html"
+    template_name = "github_pr.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
diff --git a/hubs/widgets/github_pr/templates/github_pr.html b/hubs/widgets/github_pr/templates/github_pr.html
new file mode 100644
index 0000000..379771a
--- /dev/null
+++ b/hubs/widgets/github_pr/templates/github_pr.html
@@ -0,0 +1,50 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<a class="btn btn-success" target="_blank"
+    href="https://github.com/{{ organization }}" >
+  Organization Github Page
+</a>
+<hr/>
+<ul class="media-list">
+{% for pr in pulls[:display_number] %}
+  <li class="media">
+    <div class="media-left">
+      <a  href="{{ pr['url'] }}" 
+          target="_blank">
+      <span class="label label-default">#{{ pr['number'] }}</span>
+      </a>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">
+        {{ organization }} -
+        <span title="{{ pr['title'] }}">
+          {{ pr['title'] }} {% if
+            pr['title'] | length > 45 %} ... {% endif %}
+        </span>
+      </h4>
+      Opened by:
+        <a href="https://github.com/{{ pr['user'] }}" 
+            target="_blank">
+          {{ pr['user'] }}
+        </a>
+      --
+      {% if pr['assignee'] %}
+        Assigned to:
+        <a href="https://github.com/{{ pr['assignee'] }}"
+            target="_blank">
+          {{ pr['assignee'] }}
+        </a>
+      {% else %}
+        <span class="text-muted">Unassigned</span>
+      {% endif %}
+    </div>
+  </li>
+{% endfor %}
+{% if all_pr | length > display_number %}
+  <li>
+    And {{ all_pr | length - display_number }} more ...
+  </li>
+{% endif %}
+</ul>
+{% endblock %}
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index e70dabf..6af020d 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -37,7 +37,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/githubissues.html"
+    template_name = "githubissues.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
diff --git a/hubs/widgets/githubissues/templates/githubissues.html b/hubs/widgets/githubissues/templates/githubissues.html
new file mode 100644
index 0000000..534e148
--- /dev/null
+++ b/hubs/widgets/githubissues/templates/githubissues.html
@@ -0,0 +1,42 @@
+{% extends "panel.html" %}
+
+{% block content %}
+{% for i in range(display_number) %}
+<div>
+  <table class="table-responsive table-condensed">
+    <tr>
+      <td valign="top" class="panel-heading">
+        <b>#{{ all_issues[i]['num'] }}</b>
+      </td>
+      <td width="300px">
+        <b>{{ all_issues[i]['title'] }}</b>
+      </td>
+    </tr>
+  </table>
+  <table class="table-responsive table-condensed">
+    <tr>
+      <td width="300px">
+        <font size="2">
+          <i>Opened by <a href="https://github.com/{{ all_issues[i]['openedby'] }}" target="_blank">{{ all_issues[i]['openedby'] }}</a></i>
+          {% if all_issues[i]['assignee']|string() == "None" %}
+            <br /><i>Unclaimed</i>
+          {% else %}
+             <br /><i>Assigned by <a href="https://github.com/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
+          {% endif %}
+        </font>
+      </td>
+      <td>
+         <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
+           <button type="button" class="btn btn-default" aria-label="Left Align">
+             <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+           </button>
+         </a>
+      </td>
+    </tr>
+  </table>
+</div>
+{% endfor %}
+<div class="row">
+  <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index af990ac..d15fa1d 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -24,7 +24,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/library.html"
+    template_name = "library.html"
 
     def get_context(self, instance, *args, **kwargs):
         urls = [
diff --git a/hubs/widgets/library/templates/library.html b/hubs/widgets/library/templates/library.html
new file mode 100644
index 0000000..b32cfcb
--- /dev/null
+++ b/hubs/widgets/library/templates/library.html
@@ -0,0 +1,15 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="rules-container">
+  <div class="row">
+    <ul>
+    {% for url in urls %}
+    <li>
+      {{ url }}
+    </li>
+    {% endfor %}
+    </ul>
+  </div>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index adc9590..f745e28 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -21,7 +21,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/linechart.html"
+    template_name = "linechart.html"
 
     def get_context(self, instance, *args, **kwargs):
         username = instance.config["username"]
diff --git a/hubs/widgets/linechart/templates/linechart.html b/hubs/widgets/linechart/templates/linechart.html
new file mode 100644
index 0000000..573d452
--- /dev/null
+++ b/hubs/widgets/linechart/templates/linechart.html
@@ -0,0 +1,7 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="flex-container">
+    <img src="{{url}}" />
+</div>
+{% endblock %}
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index 8a5c7ef..c87df27 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -41,7 +41,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/meetings.html"
+    template_name = "meetings.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_meetings = GetMeetings(instance)
diff --git a/hubs/widgets/meetings/templates/meetings.html b/hubs/widgets/meetings/templates/meetings.html
new file mode 100644
index 0000000..42c5c7b
--- /dev/null
+++ b/hubs/widgets/meetings/templates/meetings.html
@@ -0,0 +1,63 @@
+{% extends "panel.html" %}
+
+{% block content %}
+{% for title, next in meetings.items() %}
+<div class="meeting">
+  <div class="row">
+      <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.start_dt | humanize }}</h5>
+  </div>
+  <div class="row">
+    <div class="col-md-4 meeting-date">
+      {% if next.display_duration %}
+      <strong>{{ next.start_date }} - {{ next.stop_date }}</strong>
+      {% else %}
+      <strong>{{next.start_date}}</strong>
+      {% endif %}
+    </div>
+    <div class="col-md-4 meeting-time">
+      {% if next.display_time %}
+      @{{ next.start_time }}{% endif %}<br>
+
+      <a href="#">{{ next.location }}</a>
+    </div>
+    <div class="col-md-4">
+      <a href="https://apps.fedoraproject.org/calendar/ical/calendar/meeting/{{ next.meeting_id }}/">
+        <button class="btn btn-default btn-sm add-calendar">
+          <strong>Add to calendar</strong>
+        </button>
+      </a>
+    </div>
+  </div>
+  {% if next.get('meeting_information_html')  %}
+  <div class="row">
+      <div class="col-md-12 meeting-info">
+        {{ next.meeting_information_html[:150] }}
+        {%- if next.meeting_information_html | length > 150 %}...
+        <p>
+          <a href="https://apps.fedoraproject.org/calendar/meeting/{{ next.meeting_id }}/">Full description</a>
+        </p>
+        {% endif %}
+      </div>
+  </div>
+  {% endif  %}
+</div>
+{% if meetings | length > 1 %} <hr> {% endif %}
+{% else %}
+<div class="meeting">
+  <div class="row">
+    No coming meetings in {{ calendar }}.
+  </div>
+</div>
+{% endfor %}
+{% endblock %}
+
+
+{% block footer %}
+<div class="panel-footer">
+  <div class="row" align="center">
+    <button class="btn btn-default">
+      <strong>Request A New Meeting</strong>
+    </button>
+  </div>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/memberships/__init__.py b/hubs/widgets/memberships/__init__.py
index cd36983..213f024 100644
--- a/hubs/widgets/memberships/__init__.py
+++ b/hubs/widgets/memberships/__init__.py
@@ -18,7 +18,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/memberships.html"
+    template_name = "memberships.html"
 
     def get_context(self, instance, *args, **kwargs):
         hub = instance.hub
diff --git a/hubs/widgets/memberships/templates/memberships.html b/hubs/widgets/memberships/templates/memberships.html
new file mode 100644
index 0000000..2961e84
--- /dev/null
+++ b/hubs/widgets/memberships/templates/memberships.html
@@ -0,0 +1,80 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="card-block">
+  {% if memberships|length > oldest_members|length %}
+  {% for member in oldest_members %}
+  <div class="card-block">
+    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+    <a href="/{{member.name}}">{{ member.name }}</a>
+    {% if g.auth.username in member.owners %}
+      <p class="text-muted">Owner</p>
+    {% else %}
+      <p>Member</p>
+    {% endif %}
+  </div>
+  {% endfor %}
+  <a href="#" class="btn btn-default" data-toggle="modal" data-target="#membersModal">View All</a>
+  {% else %}
+  {% for member in memberships %}
+  <div class="card-block">
+    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+    <a href="/{{member.name}}">{{ member.name }}</a>
+    {% if g.auth.username in member.owners %}
+      <p class="text-muted">Owner</p>
+    {% else %}
+      <p>Member</p>
+    {% endif %}
+  </div>
+  {% endfor %}
+  {%endif%}
+</div>
+
+<!-- View all modal -->
+<div class="modal fade" id="membersModal" tabindex="-1" role="dialog" aria-labelledby="membersModal" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h4 class="modal-title" id="myModalLabel">All Memberships</h4>
+      </div>
+      <div id="owners" class="modal-body">
+        <div class="card-block">
+          <div class="row">
+            {% for member in memberships %}
+            <div class="col-sm-6">
+              <img class="img-responsive membership-avatar col-sm-3"
+                src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+              <a href="/{{member.name}}">{{ member.name }}</a>
+              {% if g.auth.username in member.owners %}
+              <p class="text-muted">Owner</p>
+              {% else %}
+              <p>Member</p>
+              {% endif %}
+            </div>
+            {% if (loop.index % 2) == 0 %}
+              </div>
+              <div class="row">
+            {% endif %}
+          {% endfor %}
+        </div>
+        <div class="modal-footer clearfix">
+          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+        </div>
+      </div>
+    </div>
+  </div>
+
+<style>
+ .membership-avatar {
+   height: 4em;
+   width: 6em;
+ }
+ .modal-header {
+   border-bottom: 0;
+ }
+
+ #owners {
+   padding: 10px;
+ }
+</style>
+{% endblock %}
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index ad047a7..580fece 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -27,7 +27,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/pagure_pr.html"
+    template_name = "pagure_pr.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
diff --git a/hubs/widgets/pagure_pr/templates/pagure_pr.html b/hubs/widgets/pagure_pr/templates/pagure_pr.html
new file mode 100644
index 0000000..9a7f3f2
--- /dev/null
+++ b/hubs/widgets/pagure_pr/templates/pagure_pr.html
@@ -0,0 +1,52 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<ul class="media-list">
+  {% for pr in all_pr[:10] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
+            target="_blank">
+        <span class="label label-default">#{{ pr['pr_id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          {{ pr['pr_project_name'] }} -
+          <span title="{{ pr['pr_title_full'] }}">
+            {{ pr['pr_title'] }} {% if
+              pr['pr_title_full'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
+              target="_blank">
+            {{ pr['pr_openedby'] }}
+          </a>
+        --
+        {% if pr['pr_assignee'] %}
+          Assigned to:
+          <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
+              target="_blank">
+            {{ pr['pr_assignee']['name'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_pr | length > 10 %}
+  <li>
+    And {{ all_pr | length - 10 }} more ...
+  </li>
+  {% endif %}
+</ul>
+
+<hr/>
+
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/pull-requests">
+  All Pull-Requests
+</a>
+{% endblock %}
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index 690dd86..f3490c9 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -27,7 +27,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/pagureissues.html"
+    template_name = "pagureissues.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
diff --git a/hubs/widgets/pagureissues/templates/pagureissues.html b/hubs/widgets/pagureissues/templates/pagureissues.html
new file mode 100644
index 0000000..989ccd4
--- /dev/null
+++ b/hubs/widgets/pagureissues/templates/pagureissues.html
@@ -0,0 +1,51 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/issues">
+  All Issues
+</a>
+<hr/>
+
+<ul class="media-list">
+  {% for issue in all_issues[:10] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://pagure.io/{{ repo }}/issue/{{ issue['issue_id'] }}"
+            target="_blank">
+          {{ issue['issue_project_name'] }}
+        <span class="label label-default">#{{ issue['issue_id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <span title="{{ issue['issue_title_full'] }}">
+            {{ issue['issue_title'] }} {% if
+              issue['issue_title_full'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
+              target="_blank">
+            {{ issue['issue_openedby'] }}
+          </a>
+        --
+        {% if issue['issue_assignee'] %}
+          Assigned to:
+          <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
+              target="_blank">
+            {{issue['issue_assignee'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_issues | length > 10 %}
+  <li>
+    And {{ all_issues | length - 10 }} more ...
+  </li>
+  {% endif %}
+</ul>
+{% endblock %}
diff --git a/hubs/widgets/rules/__init__.py b/hubs/widgets/rules/__init__.py
index 84b2016..e4e874c 100644
--- a/hubs/widgets/rules/__init__.py
+++ b/hubs/widgets/rules/__init__.py
@@ -46,7 +46,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/rules.html"
+    template_name = "rules.html"
 
     def get_context(self, instance, *args, **kwargs):
         owners = instance.hub.owners
diff --git a/hubs/widgets/rules/templates/rules.html b/hubs/widgets/rules/templates/rules.html
new file mode 100644
index 0000000..c5b83f0
--- /dev/null
+++ b/hubs/widgets/rules/templates/rules.html
@@ -0,0 +1,91 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="rules-container">
+  {% if link %}
+  <h6>community rules</h6>
+  <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
+  {% endif %}
+  <h6>group owners ({{ owners|length }})</h6>
+  <div class="row">
+    {% if owners|length > 5%}
+      {% for owner in oldest_owners %}
+        <div class="col-sm-6">
+          <img class="img-circle" src="{{owner['avatar']}}"/>
+          <a href="{{ url_for('hub', name=owner['username']) }}">{{owner['username']}}</a>
+        </div>
+        {% endfor %}
+        <br/>
+        <a href="#" class="btn btn-default" data-toggle="modal" data-target="#ownersModal">View All</a>
+    {% else %}
+      {% for owner in owners %}
+        <div class="col-sm-6">
+          <img class="img-circle" src="{{owners[owner]}}"/>
+          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
+        </div>
+      {% endfor %}
+    {% endif %}
+  </div>
+  {% if schedule_text or schedule_link or minutes_link %}
+  <h6>meetings</h6>
+  {% if schedule_text %}
+  <p>{{schedule_text}}</p>
+  {% endif %}
+  <p>
+  {% if schedule_link %}
+  <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
+  {% endif %}
+  {% if schedule_link and minutes_link %}
+  &#8214;
+  {% endif %}
+  {% if minutes_link %}
+  <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
+  {% endif %}
+  </p>
+  {% endif %}
+</div>
+
+
+<!-- View all modal -->
+<div class="modal fade" id="ownersModal" tabindex="-1" role="dialog" aria-labelledby="ownersModal" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h4 class="modal-title" id="myModalLabel">All group owners</h4>
+      </div>
+      <div id="owners">
+        {% for owner in owners %}
+        <div class="col-sm-6">
+          <img class="img-circle img-circle-lg" src="{{owners[owner]}}"/>
+          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
+        </div>
+        {% endfor %}
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+      </div>
+    </div>
+  </div>
+</div>
+
+<style>
+  .rules-table {
+    width: 180px
+    padding: 0px;
+    margin: 0px;
+    display: inline-block;
+  }
+  .rules-table td {
+    font-size: 32pt;
+  }
+
+ .img-circle-lg {
+   height: 4em;
+   width: 4em;
+   padding: 10px;
+ }
+ .modal-header {
+   border-bottom: 0;
+ }
+</style>
+{% endblock %}
diff --git a/hubs/widgets/stats/__init__.py b/hubs/widgets/stats/__init__.py
index 87d4415..67740df 100644
--- a/hubs/widgets/stats/__init__.py
+++ b/hubs/widgets/stats/__init__.py
@@ -17,7 +17,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/stats.html"
+    template_name = "stats.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_stats = GetStats(instance)
diff --git a/hubs/widgets/stats/templates/stats.html b/hubs/widgets/stats/templates/stats.html
new file mode 100644
index 0000000..9e959fc
--- /dev/null
+++ b/hubs/widgets/stats/templates/stats.html
@@ -0,0 +1,78 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="stats-container row">
+<div class="col-md-7">
+  <table class="stats-table">
+    <tr><th>Members</th><th>Subscribers</th></tr>
+    <tr class="text-info">
+      <td>{{members_text}}</td>
+      <td class="text-right">{{subscribers_text}}</td>
+    </tr>
+  </table>
+</div>
+<div class="col-md-5">
+  <ul class="list-unstyled">
+  {% if g.auth.nickname in subscribers %}
+  <li>
+    <form action="{{hub_unsubscribe_url}}" method="POST">
+      <button class="btn btn-info">
+        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
+        Unsubscribe
+      </button>
+    </form>
+  </li>
+  {% else %}
+  <li>
+    <form action="{{hub_subscribe_url}}" method="POST">
+      <button class="btn btn-default">
+        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
+        Subscribe
+      </button>
+    </form>
+  </li>
+  {% endif %}
+
+  {% if g.auth.nickname in stargazers %}
+  <li>
+    <form action="{{hub_unstar_url}}" method="POST">
+      <button class="btn btn-info">
+        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
+        Unstar Hub
+      </button>
+    </form>
+  </li>
+  {% else %}
+  <li>
+    <form action="{{hub_star_url}}" method="POST">
+      <button class="btn btn-default">
+        <span class="glyphicon glyphicon-star" aria-hidden="true"></span>
+        Star Hub
+      </button>
+    </form>
+  </li>
+  {% endif %}
+
+  {% if g.auth.nickname in members %}
+  <li>
+    <form action="{{hub_leave_url}}" method="POST">
+      <button class="btn btn-info">
+        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
+        Leave Hub
+      </button>
+    </form>
+  </li>
+  {% else %}
+  <li>
+    <form action="{{hub_join_url}}" method="POST">
+      <button class="btn btn-default">
+        <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
+        Join Hub
+      </button>
+    </form>
+  </li>
+  {% endif %}
+  </ul>
+</div>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index 28c8fed..02e7fdf 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -22,7 +22,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/sticky.html"
+    template_name = "sticky.html"
 
     def get_context(self, instance, *args, **kwargs):
         # TODO -- render with markdown
diff --git a/hubs/widgets/sticky/templates/sticky.html b/hubs/widgets/sticky/templates/sticky.html
new file mode 100644
index 0000000..f2b2486
--- /dev/null
+++ b/hubs/widgets/sticky/templates/sticky.html
@@ -0,0 +1,5 @@
+{% extends "panel.html" %}
+
+{% block content %}
+{{text}}
+{% endblock %}
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
index 466beb9..14538f0 100644
--- a/hubs/widgets/subscriptions/__init__.py
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -31,7 +31,7 @@ class BaseView(WidgetView):
 
     name = "root"
     url_rules = ["/"]
-    template_name = "templates/subscriptions.html"
+    template_name = "subscriptions.html"
 
     def get_context(self, instance, *args, **kwargs):
         context = dict(title="Hubs")
diff --git a/hubs/widgets/subscriptions/templates/subscriptions.html b/hubs/widgets/subscriptions/templates/subscriptions.html
new file mode 100644
index 0000000..1114d8c
--- /dev/null
+++ b/hubs/widgets/subscriptions/templates/subscriptions.html
@@ -0,0 +1,17 @@
+{% if associations %}
+{% extends "panel.html" %}
+
+{% block content %}
+    {% if memberships %}
+        <p><strong>Belongs to: </strong> {{memberships_text}}</p>
+    {% endif %}
+    <hr/>
+    {% if subscriptions %}
+        <p><strong>Subscribes to:</strong>
+        {% for subscription in subscriptions %}
+        <a href="{{ url_for('hub', name=subscription)}}">
+        {{subscription}}</a>
+        {% endfor %}</p>
+    {% endif %}
+{% endblock %}
+{% endif %}
diff --git a/hubs/widgets/templates/about.html b/hubs/widgets/templates/about.html
deleted file mode 100644
index 3b25a3a..0000000
--- a/hubs/widgets/templates/about.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<p>{{text}}</p>
-{% endblock %}
diff --git a/hubs/widgets/templates/badges.html b/hubs/widgets/templates/badges.html
deleted file mode 100644
index 22a0562..0000000
--- a/hubs/widgets/templates/badges.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<div class="flex-container">
-{% for badge in assertions %}
-  <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
-    <span class="f-b-{{badge['id']}}"></span>
-  </a>
-{% endfor %}
-</div>
-{% endblock %}
diff --git a/hubs/widgets/templates/bugzilla.html b/hubs/widgets/templates/bugzilla.html
deleted file mode 100644
index 9809c31..0000000
--- a/hubs/widgets/templates/bugzilla.html
+++ /dev/null
@@ -1,21 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<ul class="media-list">
-  {% for item in issues %}
-    <li class="media">
-      <div class="media-left">
-        <a href="https://bugzilla.redhat.com/show_bug.cgi?id={{ item['id'] }}" target="_blank">
-        <span class="label label-default">#{{ item['id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <a href="https://apps.fedoraproject.org/packages/{{ item['pkg_name'] }}" target="_blank">{{ item['pkg_name'] }}</a>:
-          {{ item['title'] }}
-        </h4>
-      </div>
-    </li>
-  {% endfor %}
-</ul>
-{% endblock %}
diff --git a/hubs/widgets/templates/contact.html b/hubs/widgets/templates/contact.html
deleted file mode 100644
index 9898a18..0000000
--- a/hubs/widgets/templates/contact.html
+++ /dev/null
@@ -1,74 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<div class="contactinfo-container">
-  {% if usergroup %}
-    <ul style="list-style: none; padding-left: 5px">
-      <!--<li><i class="fa fa-map-marker" aria-hidden="true"></i>
-          <span class="col-md-offset-1">{{location}}</span></li>-->
-      <li><i class="fa fa-clock-o" aria-hidden="true"></i>
-          <span class="col-md-offset-1">Current-Time :</span>
-          <script type="text/javascript">
-            // TODO: send offset after querying fas3
-            function calcTime(offset) {
-
-              // create Date object for current location
-              d = new Date();
-
-              // convert to msec
-              // add local time zone offset
-              // get UTC time in msec
-              utc = d.getTime() + (d.getTimezoneOffset() * 60000);
-
-              // create new Date object using supplied offset
-              nd = new Date(utc + (3600000 * offset));
-
-              // return time as a string
-              return nd.toLocaleString();
-            }
-
-            setInterval(function() {
-              $("#time").html(calcTime(-4))
-            }, 1000)
-
-            function get_karma_stats() {
-                var karma_url = '{{ karma_url }}';
-                  $.ajax({
-                    method: "GET",
-                    url: karma_url,
-                    dataType: 'html',
-                    success: function(html) {
-                      console.log('Success: ' + html);
-                      karma_arr = JSON.parse(html);
-                      console.log(karma_arr)
-                      $('#karma_current').html("Karma : "+karma_arr['current']+" ("+karma_arr['total']+" all time)");
-                    },
-                    error: function() {
-                      console.log('Error: getting karma');
-                    },
-                  });
-                }
-            get_karma_stats()
-          </script>
-          <span id="time"></span></li>
-      <li><i class="fa fa-envelope" aria-hidden="true"></i>
-          <span class="col-md-offset-1">{{email}}</span></li>
-      <li><i class="fa fa-comment" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span>{{ircnick}}</li>
-      <li><i class="fa fa-user-plus" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span><span id="karma_current"></span></li>
-      <li><i class="fa fa-certificate" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span> Member Since {{account_age}}</li>
-    </ul>
-  {% else %}
-    <ul style="list-style: none">
-      <li><i class="fa fa-comment" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span>fedora-{{ircchannel}}</li>
-      <li><i class="fa fa-envelope" aria-hidden="true"></i>
-          <span class="col-md-offset-1"><a href="{{ mailinglist }}">{{ hubname }}@lists.fedoraproject.org</a></span></li>
-      <li><i class="fa fa-info" aria-hidden="true"></i>
-          <span class="col-md-offset-1"><a href="{{ wikilink }}">fedoraproject.org/wiki/{{ hubname }}</a></span></li>
-    </ul>
-  {% endif %}
-</div>
-{% endblock %}
diff --git a/hubs/widgets/templates/dummy.html b/hubs/widgets/templates/dummy.html
deleted file mode 100644
index 6e318ec..0000000
--- a/hubs/widgets/templates/dummy.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-{{text}}
-{% endblock %}
diff --git a/hubs/widgets/templates/fedmsgstats.html b/hubs/widgets/templates/fedmsgstats.html
deleted file mode 100644
index fe369e2..0000000
--- a/hubs/widgets/templates/fedmsgstats.html
+++ /dev/null
@@ -1,27 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<div class="stats-container row">
-  <div class="col-sm-7 col-md-12 col-lg-7">
-  <table class="stats-table">
-    <tr><th>subscribers</th><th>subscribed to</th></tr>
-    <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
-  </table>
-  </div>
-  <div class="col-sm-5 col-md-12 col-lg-5">
-  {% if session['nickname'] != username %}
-    <ul class="list-unstyled">
-    {% if session['nickname'] in subscribers %}
-    <li><form action="{{hub_unsubscribe_url}}" method="POST">
-        <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
-    </form></li>
-    {% else %}
-    <li><form action="{{hub_subscribe_url}}" method="POST">
-        <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
-    </form></li>
-    {% endif %}
-    </ul>
-  {% endif %}
-  </div>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/templates/fedorahosted.html b/hubs/widgets/templates/fedorahosted.html
deleted file mode 100644
index 5dcc574..0000000
--- a/hubs/widgets/templates/fedorahosted.html
+++ /dev/null
@@ -1,48 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-{% if error %}
-<p>{{ error }}</p>
-{% else %}
-<a class="btn btn-success" target="_blank"
-    href="https://fedorahosted.org/{{ project }}/report/1">
-  All Issues
-</a>
-<hr/>
-
-<ul class="media-list">
-  {% for issue in tickets %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="https://fedorahosted.org/{{ project }}/ticket/{{ issue['id'] }}"
-            target="_blank">
-        <span class="label label-default">#{{ issue['id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <span title="{{ issue['summary'] }}">
-            {{ issue['short_summary'] }} {% if
-              issue['summary'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-            {{ issue['reporter'] }}
-        --
-        {% if issue['owner'] %}
-          Assigned to:
-            {{issue['owner'] }}
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if total_tickets > tickets | length %}
-  <li>
-    And {{ total_tickets - tickets | length }} more ...
-  </li>
-  {% endif %}
-</ul>
-{% endif %}
-{% endblock %}
diff --git a/hubs/widgets/templates/feed.html b/hubs/widgets/templates/feed.html
deleted file mode 100644
index 84256cc..0000000
--- a/hubs/widgets/templates/feed.html
+++ /dev/null
@@ -1,21 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<div id="feed">
-</div>
-
-<script type="text/javascript"
-        src ="{{url_for('static', filename='js/hubs.js')}}"></script>
-<script>
- (function() {
-   const FeedElement = React.createElement(Feed, {
-     matches: {{ matches }},
-     url: '{{ feed_url }}',
-     options: {
-       messageLimit: {{ message_limit }}
-     }
-   });
-   ReactDOM.render(FeedElement, document.getElementById('feed'));
- })();
-</script>
-{% endblock %}
diff --git a/hubs/widgets/templates/github_pr.html b/hubs/widgets/templates/github_pr.html
deleted file mode 100644
index 743c9aa..0000000
--- a/hubs/widgets/templates/github_pr.html
+++ /dev/null
@@ -1,50 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<a class="btn btn-success" target="_blank"
-    href="https://github.com/{{ organization }}" >
-  Organization Github Page
-</a>
-<hr/>
-<ul class="media-list">
-{% for pr in pulls[:display_number] %}
-  <li class="media">
-    <div class="media-left">
-      <a  href="{{ pr['url'] }}" 
-          target="_blank">
-      <span class="label label-default">#{{ pr['number'] }}</span>
-      </a>
-    </div>
-    <div class="media-body">
-      <h4 class="media-heading">
-        {{ organization }} -
-        <span title="{{ pr['title'] }}">
-          {{ pr['title'] }} {% if
-            pr['title'] | length > 45 %} ... {% endif %}
-        </span>
-      </h4>
-      Opened by:
-        <a href="https://github.com/{{ pr['user'] }}" 
-            target="_blank">
-          {{ pr['user'] }}
-        </a>
-      --
-      {% if pr['assignee'] %}
-        Assigned to:
-        <a href="https://github.com/{{ pr['assignee'] }}"
-            target="_blank">
-          {{ pr['assignee'] }}
-        </a>
-      {% else %}
-        <span class="text-muted">Unassigned</span>
-      {% endif %}
-    </div>
-  </li>
-{% endfor %}
-{% if all_pr | length > display_number %}
-  <li>
-    And {{ all_pr | length - display_number }} more ...
-  </li>
-{% endif %}
-</ul>
-{% endblock %}
diff --git a/hubs/widgets/templates/githubissues.html b/hubs/widgets/templates/githubissues.html
deleted file mode 100644
index 1a57dab..0000000
--- a/hubs/widgets/templates/githubissues.html
+++ /dev/null
@@ -1,42 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-{% for i in range(display_number) %}
-<div>
-  <table class="table-responsive table-condensed">
-    <tr>
-      <td valign="top" class="panel-heading">
-        <b>#{{ all_issues[i]['num'] }}</b>
-      </td>
-      <td width="300px">
-        <b>{{ all_issues[i]['title'] }}</b>
-      </td>
-    </tr>
-  </table>
-  <table class="table-responsive table-condensed">
-    <tr>
-      <td width="300px">
-        <font size="2">
-          <i>Opened by <a href="https://github.com/{{ all_issues[i]['openedby'] }}" target="_blank">{{ all_issues[i]['openedby'] }}</a></i>
-          {% if all_issues[i]['assignee']|string() == "None" %}
-            <br /><i>Unclaimed</i>
-          {% else %}
-             <br /><i>Assigned by <a href="https://github.com/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
-          {% endif %}
-        </font>
-      </td>
-      <td>
-         <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
-           <button type="button" class="btn btn-default" aria-label="Left Align">
-             <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-           </button>
-         </a>
-      </td>
-    </tr>
-  </table>
-</div>
-{% endfor %}
-<div class="row">
-  <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/templates/library.html b/hubs/widgets/templates/library.html
deleted file mode 100644
index a9155b5..0000000
--- a/hubs/widgets/templates/library.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<div class="rules-container">
-  <div class="row">
-    <ul>
-    {% for url in urls %}
-    <li>
-      {{ url }}
-    </li>
-    {% endfor %}
-    </ul>
-  </div>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/templates/linechart.html b/hubs/widgets/templates/linechart.html
deleted file mode 100644
index 3cc86ef..0000000
--- a/hubs/widgets/templates/linechart.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<div class="flex-container">
-    <img src="{{url}}" />
-</div>
-{% endblock %}
diff --git a/hubs/widgets/templates/meetings.html b/hubs/widgets/templates/meetings.html
deleted file mode 100644
index 600c82c..0000000
--- a/hubs/widgets/templates/meetings.html
+++ /dev/null
@@ -1,63 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-{% for title, next in meetings.items() %}
-<div class="meeting">
-  <div class="row">
-      <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.start_dt | humanize }}</h5>
-  </div>
-  <div class="row">
-    <div class="col-md-4 meeting-date">
-      {% if next.display_duration %}
-      <strong>{{ next.start_date }} - {{ next.stop_date }}</strong>
-      {% else %}
-      <strong>{{next.start_date}}</strong>
-      {% endif %}
-    </div>
-    <div class="col-md-4 meeting-time">
-      {% if next.display_time %}
-      @{{ next.start_time }}{% endif %}<br>
-
-      <a href="#">{{ next.location }}</a>
-    </div>
-    <div class="col-md-4">
-      <a href="https://apps.fedoraproject.org/calendar/ical/calendar/meeting/{{ next.meeting_id }}/">
-        <button class="btn btn-default btn-sm add-calendar">
-          <strong>Add to calendar</strong>
-        </button>
-      </a>
-    </div>
-  </div>
-  {% if next.get('meeting_information_html')  %}
-  <div class="row">
-      <div class="col-md-12 meeting-info">
-        {{ next.meeting_information_html[:150] }}
-        {%- if next.meeting_information_html | length > 150 %}...
-        <p>
-          <a href="https://apps.fedoraproject.org/calendar/meeting/{{ next.meeting_id }}/">Full description</a>
-        </p>
-        {% endif %}
-      </div>
-  </div>
-  {% endif  %}
-</div>
-{% if meetings | length > 1 %} <hr> {% endif %}
-{% else %}
-<div class="meeting">
-  <div class="row">
-    No coming meetings in {{ calendar }}.
-  </div>
-</div>
-{% endfor %}
-{% endblock %}
-
-
-{% block footer %}
-<div class="panel-footer">
-  <div class="row" align="center">
-    <button class="btn btn-default">
-      <strong>Request A New Meeting</strong>
-    </button>
-  </div>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/templates/memberships.html b/hubs/widgets/templates/memberships.html
deleted file mode 100644
index 57c6d70..0000000
--- a/hubs/widgets/templates/memberships.html
+++ /dev/null
@@ -1,80 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<div class="card-block">
-  {% if memberships|length > oldest_members|length %}
-  {% for member in oldest_members %}
-  <div class="card-block">
-    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
-    <a href="/{{member.name}}">{{ member.name }}</a>
-    {% if g.auth.username in member.owners %}
-      <p class="text-muted">Owner</p>
-    {% else %}
-      <p>Member</p>
-    {% endif %}
-  </div>
-  {% endfor %}
-  <a href="#" class="btn btn-default" data-toggle="modal" data-target="#membersModal">View All</a>
-  {% else %}
-  {% for member in memberships %}
-  <div class="card-block">
-    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
-    <a href="/{{member.name}}">{{ member.name }}</a>
-    {% if g.auth.username in member.owners %}
-      <p class="text-muted">Owner</p>
-    {% else %}
-      <p>Member</p>
-    {% endif %}
-  </div>
-  {% endfor %}
-  {%endif%}
-</div>
-
-<!-- View all modal -->
-<div class="modal fade" id="membersModal" tabindex="-1" role="dialog" aria-labelledby="membersModal" aria-hidden="true">
-  <div class="modal-dialog">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h4 class="modal-title" id="myModalLabel">All Memberships</h4>
-      </div>
-      <div id="owners" class="modal-body">
-        <div class="card-block">
-          <div class="row">
-            {% for member in memberships %}
-            <div class="col-sm-6">
-              <img class="img-responsive membership-avatar col-sm-3"
-                src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
-              <a href="/{{member.name}}">{{ member.name }}</a>
-              {% if g.auth.username in member.owners %}
-              <p class="text-muted">Owner</p>
-              {% else %}
-              <p>Member</p>
-              {% endif %}
-            </div>
-            {% if (loop.index % 2) == 0 %}
-              </div>
-              <div class="row">
-            {% endif %}
-          {% endfor %}
-        </div>
-        <div class="modal-footer clearfix">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-<style>
- .membership-avatar {
-   height: 4em;
-   width: 6em;
- }
- .modal-header {
-   border-bottom: 0;
- }
-
- #owners {
-   padding: 10px;
- }
-</style>
-{% endblock %}
diff --git a/hubs/widgets/templates/pagure_pr.html b/hubs/widgets/templates/pagure_pr.html
deleted file mode 100644
index 735ac7b..0000000
--- a/hubs/widgets/templates/pagure_pr.html
+++ /dev/null
@@ -1,52 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<ul class="media-list">
-  {% for pr in all_pr[:10] %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
-            target="_blank">
-        <span class="label label-default">#{{ pr['pr_id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          {{ pr['pr_project_name'] }} -
-          <span title="{{ pr['pr_title_full'] }}">
-            {{ pr['pr_title'] }} {% if
-              pr['pr_title_full'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-          <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
-              target="_blank">
-            {{ pr['pr_openedby'] }}
-          </a>
-        --
-        {% if pr['pr_assignee'] %}
-          Assigned to:
-          <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
-              target="_blank">
-            {{ pr['pr_assignee']['name'] }}
-          </a>
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if all_pr | length > 10 %}
-  <li>
-    And {{ all_pr | length - 10 }} more ...
-  </li>
-  {% endif %}
-</ul>
-
-<hr/>
-
-<a class="btn btn-success" target="_blank"
-    href="https://pagure.io/{{ repo }}/pull-requests">
-  All Pull-Requests
-</a>
-{% endblock %}
diff --git a/hubs/widgets/templates/pagureissues.html b/hubs/widgets/templates/pagureissues.html
deleted file mode 100644
index 55c6a74..0000000
--- a/hubs/widgets/templates/pagureissues.html
+++ /dev/null
@@ -1,51 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<a class="btn btn-success" target="_blank"
-    href="https://pagure.io/{{ repo }}/issues">
-  All Issues
-</a>
-<hr/>
-
-<ul class="media-list">
-  {% for issue in all_issues[:10] %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="https://pagure.io/{{ repo }}/issue/{{ issue['issue_id'] }}"
-            target="_blank">
-          {{ issue['issue_project_name'] }}
-        <span class="label label-default">#{{ issue['issue_id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <span title="{{ issue['issue_title_full'] }}">
-            {{ issue['issue_title'] }} {% if
-              issue['issue_title_full'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-          <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
-              target="_blank">
-            {{ issue['issue_openedby'] }}
-          </a>
-        --
-        {% if issue['issue_assignee'] %}
-          Assigned to:
-          <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
-              target="_blank">
-            {{issue['issue_assignee'] }}
-          </a>
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if all_issues | length > 10 %}
-  <li>
-    And {{ all_issues | length - 10 }} more ...
-  </li>
-  {% endif %}
-</ul>
-{% endblock %}
diff --git a/hubs/widgets/templates/rules.html b/hubs/widgets/templates/rules.html
deleted file mode 100644
index d233741..0000000
--- a/hubs/widgets/templates/rules.html
+++ /dev/null
@@ -1,91 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<div class="rules-container">
-  {% if link %}
-  <h6>community rules</h6>
-  <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
-  {% endif %}
-  <h6>group owners ({{ owners|length }})</h6>
-  <div class="row">
-    {% if owners|length > 5%}
-      {% for owner in oldest_owners %}
-        <div class="col-sm-6">
-          <img class="img-circle" src="{{owner['avatar']}}"/>
-          <a href="{{ url_for('hub', name=owner['username']) }}">{{owner['username']}}</a>
-        </div>
-        {% endfor %}
-        <br/>
-        <a href="#" class="btn btn-default" data-toggle="modal" data-target="#ownersModal">View All</a>
-    {% else %}
-      {% for owner in owners %}
-        <div class="col-sm-6">
-          <img class="img-circle" src="{{owners[owner]}}"/>
-          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
-        </div>
-      {% endfor %}
-    {% endif %}
-  </div>
-  {% if schedule_text or schedule_link or minutes_link %}
-  <h6>meetings</h6>
-  {% if schedule_text %}
-  <p>{{schedule_text}}</p>
-  {% endif %}
-  <p>
-  {% if schedule_link %}
-  <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
-  {% endif %}
-  {% if schedule_link and minutes_link %}
-  &#8214;
-  {% endif %}
-  {% if minutes_link %}
-  <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
-  {% endif %}
-  </p>
-  {% endif %}
-</div>
-
-
-<!-- View all modal -->
-<div class="modal fade" id="ownersModal" tabindex="-1" role="dialog" aria-labelledby="ownersModal" aria-hidden="true">
-  <div class="modal-dialog">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h4 class="modal-title" id="myModalLabel">All group owners</h4>
-      </div>
-      <div id="owners">
-        {% for owner in owners %}
-        <div class="col-sm-6">
-          <img class="img-circle img-circle-lg" src="{{owners[owner]}}"/>
-          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
-        </div>
-        {% endfor %}
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
-      </div>
-    </div>
-  </div>
-</div>
-
-<style>
-  .rules-table {
-    width: 180px
-    padding: 0px;
-    margin: 0px;
-    display: inline-block;
-  }
-  .rules-table td {
-    font-size: 32pt;
-  }
-
- .img-circle-lg {
-   height: 4em;
-   width: 4em;
-   padding: 10px;
- }
- .modal-header {
-   border-bottom: 0;
- }
-</style>
-{% endblock %}
diff --git a/hubs/widgets/templates/stats.html b/hubs/widgets/templates/stats.html
deleted file mode 100644
index f2cba1f..0000000
--- a/hubs/widgets/templates/stats.html
+++ /dev/null
@@ -1,78 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-<div class="stats-container row">
-<div class="col-md-7">
-  <table class="stats-table">
-    <tr><th>Members</th><th>Subscribers</th></tr>
-    <tr class="text-info">
-      <td>{{members_text}}</td>
-      <td class="text-right">{{subscribers_text}}</td>
-    </tr>
-  </table>
-</div>
-<div class="col-md-5">
-  <ul class="list-unstyled">
-  {% if g.auth.nickname in subscribers %}
-  <li>
-    <form action="{{hub_unsubscribe_url}}" method="POST">
-      <button class="btn btn-info">
-        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
-        Unsubscribe
-      </button>
-    </form>
-  </li>
-  {% else %}
-  <li>
-    <form action="{{hub_subscribe_url}}" method="POST">
-      <button class="btn btn-default">
-        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
-        Subscribe
-      </button>
-    </form>
-  </li>
-  {% endif %}
-
-  {% if g.auth.nickname in stargazers %}
-  <li>
-    <form action="{{hub_unstar_url}}" method="POST">
-      <button class="btn btn-info">
-        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
-        Unstar Hub
-      </button>
-    </form>
-  </li>
-  {% else %}
-  <li>
-    <form action="{{hub_star_url}}" method="POST">
-      <button class="btn btn-default">
-        <span class="glyphicon glyphicon-star" aria-hidden="true"></span>
-        Star Hub
-      </button>
-    </form>
-  </li>
-  {% endif %}
-
-  {% if g.auth.nickname in members %}
-  <li>
-    <form action="{{hub_leave_url}}" method="POST">
-      <button class="btn btn-info">
-        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
-        Leave Hub
-      </button>
-    </form>
-  </li>
-  {% else %}
-  <li>
-    <form action="{{hub_join_url}}" method="POST">
-      <button class="btn btn-default">
-        <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
-        Join Hub
-      </button>
-    </form>
-  </li>
-  {% endif %}
-  </ul>
-</div>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/templates/sticky.html b/hubs/widgets/templates/sticky.html
deleted file mode 100644
index 6e318ec..0000000
--- a/hubs/widgets/templates/sticky.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-{{text}}
-{% endblock %}
diff --git a/hubs/widgets/templates/subscriptions.html b/hubs/widgets/templates/subscriptions.html
deleted file mode 100644
index 99fa9a2..0000000
--- a/hubs/widgets/templates/subscriptions.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% if associations %}
-{% extends "templates/panel.html" %}
-
-{% block content %}
-    {% if memberships %}
-        <p><strong>Belongs to: </strong> {{memberships_text}}</p>
-    {% endif %}
-    <hr/>
-    {% if subscriptions %}
-        <p><strong>Subscribes to:</strong>
-        {% for subscription in subscriptions %}
-        <a href="{{ url_for('hub', name=subscription)}}">
-        {{subscription}}</a>
-        {% endfor %}</p>
-    {% endif %}
-{% endblock %}
-{% endif %}
diff --git a/hubs/widgets/templates/workflow/pendingacls.html b/hubs/widgets/templates/workflow/pendingacls.html
deleted file mode 100644
index 2775fb2..0000000
--- a/hubs/widgets/templates/workflow/pendingacls.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{% if pending_acls %}
-
-{% extends "templates/panel.html" %}
-
-{% block content %}
-{% if session['nickname'] == username %}
-<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/pkgdb/acl/pending/">Manage requests</a>
-<hr/>
-{% endif %}
-<ul class="media-list">
-{% for acl in pending_acls %}
-    <li class="media">
-        <div class="media-left">
-            <img class="media-object img-circle" src="{{acl['avatar']}}"/>
-        </div>
-        <div class="media-body">
-            <h4 class="media-heading">{{acl['user']}} is {{acl['status']}}</h4>
-            for {{acl['acl']}} on
-            {{acl['package']}}({{acl['collection']}})
-        </div>
-    </li>
-{% endfor %}
-</ul>
-{% endblock %}
-
-{% endif %}
diff --git a/hubs/widgets/templates/workflow/updates2stable.html b/hubs/widgets/templates/workflow/updates2stable.html
deleted file mode 100644
index 3982895..0000000
--- a/hubs/widgets/templates/workflow/updates2stable.html
+++ /dev/null
@@ -1,25 +0,0 @@
-{% if updates %}
-{% extends "templates/panel.html" %}
-
-{% block content %}
-{% if session['nickname'] == username %}
-<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
-<hr/>
-{% endif %}
-<ul class="media-list">
-{% for update in updates %}
-    <li class="media">
-        <div class="media-left">
-            <a href="{{update['link']}}" target="_blank">
-                <img class="media-object square-32" src="{{update['icon']}}"/>
-            </a>
-        </div>
-        <div class="media-body">
-            <h4 class="media-heading">{{update['title']}} (karma {{update['karma']}})</h4>
-            can be pushed to stable
-        </div>
-    </li>
-{% endfor %}
-</ul>
-{% endblock %}
-{% endif %}
diff --git a/hubs/widgets/templating.py b/hubs/widgets/templating.py
deleted file mode 100644
index ac5b3e4..0000000
--- a/hubs/widgets/templating.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from __future__ import unicode_literals
-
-import os
-
-import flask
-import jinja2
-
-here = os.path.dirname(os.path.abspath(__file__))
-
-environment = jinja2.Environment(
-    loader=jinja2.FileSystemLoader(here),
-    trim_blocks=True,
-)
-environment.filters['tojson'] = flask.json.tojson_filter
-environment.globals.update({
-    'session': flask.app.session,
-    'g': flask.g,
-    'url_for': flask.url_for,
-    })
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index 572b670..05a633a 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -31,7 +31,8 @@ class WidgetView(View):
         url_rules (list): A list of URL rules that this view must be registered
             for (like the `rule` parameter of Flask's `add_url_rule()`).
         template_name (str): The template name to use for this view. It will be
-            looked for in the widget's template environment.
+            looked for in the widget's `templates` subdirectory first, and
+            then in the global `hubs/widgets/templates/` directory.
 
     This class is Flask-specific. If another framework were to be switched to,
     it would have to be re-implemented.
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index cc4cb3a..5d891e0 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -27,7 +27,7 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     # TODO -- add approve/deny buttons or just link through to pkgdb
-    template_name = "templates/workflow/pendingacls.html"
+    template_name = "pendingacls.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_pending = GetPending(instance)
diff --git a/hubs/widgets/workflow/templates/pendingacls.html b/hubs/widgets/workflow/templates/pendingacls.html
new file mode 100644
index 0000000..446e723
--- /dev/null
+++ b/hubs/widgets/workflow/templates/pendingacls.html
@@ -0,0 +1,26 @@
+{% if pending_acls %}
+
+{% extends "panel.html" %}
+
+{% block content %}
+{% if session['nickname'] == username %}
+<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/pkgdb/acl/pending/">Manage requests</a>
+<hr/>
+{% endif %}
+<ul class="media-list">
+{% for acl in pending_acls %}
+    <li class="media">
+        <div class="media-left">
+            <img class="media-object img-circle" src="{{acl['avatar']}}"/>
+        </div>
+        <div class="media-body">
+            <h4 class="media-heading">{{acl['user']}} is {{acl['status']}}</h4>
+            for {{acl['acl']}} on
+            {{acl['package']}}({{acl['collection']}})
+        </div>
+    </li>
+{% endfor %}
+</ul>
+{% endblock %}
+
+{% endif %}
diff --git a/hubs/widgets/workflow/templates/updates2stable.html b/hubs/widgets/workflow/templates/updates2stable.html
new file mode 100644
index 0000000..7e72e01
--- /dev/null
+++ b/hubs/widgets/workflow/templates/updates2stable.html
@@ -0,0 +1,25 @@
+{% if updates %}
+{% extends "panel.html" %}
+
+{% block content %}
+{% if session['nickname'] == username %}
+<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
+<hr/>
+{% endif %}
+<ul class="media-list">
+{% for update in updates %}
+    <li class="media">
+        <div class="media-left">
+            <a href="{{update['link']}}" target="_blank">
+                <img class="media-object square-32" src="{{update['icon']}}"/>
+            </a>
+        </div>
+        <div class="media-body">
+            <h4 class="media-heading">{{update['title']}} (karma {{update['karma']}})</h4>
+            can be pushed to stable
+        </div>
+    </li>
+{% endfor %}
+</ul>
+{% endblock %}
+{% endif %}
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 00df8fc..d2490a3 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -31,7 +31,7 @@ class BaseView(WidgetView):
     name = "root"
     url_rules = ["/"]
     # TODO -- add approve/deny buttons or just link through to pkgdb
-    template_name = "templates/workflow/updates2stable.html"
+    template_name = "updates2stable.html"
 
     def get_context(self, instance, *args, **kwargs):
         get_pending = GetPending(instance)

From d601bc58325aebbd7c798f081392e8d3b74e4452 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 736/1001] Fix compatibility with Python 2


---

diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index fd6b3b3..bc8a166 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -43,7 +43,7 @@ class WidgetTest(APPTest):
         test_widget = LocalTestWidget()
         self.assertRaisesRegexp(
             AttributeError, '.* "name" .*', test_widget.validate)
-        test_widget.name = "învalid næme"
+        test_widget.name = "invalid name \xe2\x98\xba"
         self.assertRaisesRegexp(
             AttributeError, '^Invalid widget name: ', test_widget.validate)
         test_widget.name = "localtest"
diff --git a/hubs/tests/test_widget_caching.py b/hubs/tests/test_widget_caching.py
index 967db0e..c04ba76 100644
--- a/hubs/tests/test_widget_caching.py
+++ b/hubs/tests/test_widget_caching.py
@@ -37,9 +37,10 @@ class CachedFunctionTest(APPTest):
         super(CachedFunctionTest, self).tearDown()
 
     def test_get_cache_key(self):
+        value = "%d|DummyFunction" % self.w_instance.idx
         self.assertEqual(
             self.fn.get_cache_key(),
-            b"%d|DummyFunction" % self.w_instance.idx
+            value.encode("ascii"),
             )
 
     def test_result_cached(self):
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 9123a4d..824e34d 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -5,6 +5,7 @@ import logging
 import re
 import flask
 import jinja2
+import six
 
 from importlib import import_module
 from .caching import CachedFunction
@@ -129,6 +130,10 @@ class Widget(object):
         """
         for view_name, view_class in self.get_views().items():
             endpoint = "%s_%s" % (self.name, view_name)
+            if six.PY2:
+                # Flask will set the __name__ property, which must be a
+                # bytestring on PY2
+                endpoint = endpoint.encode("ascii", "replace")
             view_func = view_class.as_view(endpoint, self)
             for url_rule in view_class.url_rules:
                 rule = "/<hub>/w/%s/<int:idx>/%s" % (
diff --git a/hubs/widgets/registry.py b/hubs/widgets/registry.py
index 006eced..db463b3 100644
--- a/hubs/widgets/registry.py
+++ b/hubs/widgets/registry.py
@@ -1,5 +1,7 @@
 from __future__ import unicode_literals
 
+import six
+
 from importlib import import_module
 from six.moves import UserDict
 from hubs.widgets.base import Widget
@@ -66,3 +68,8 @@ class WidgetRegistry(UserDict):
         """
         for widget in self.values():
             widget.register_routes(app)
+
+    # IterableUserDict is in Python2 but not exported by six.
+    if six.PY2:
+        def __iter__(self):
+            return iter(self.data)

From 81acbdc0cc4279f56cd07bcba04896b4b026988d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:10 +0000
Subject: [PATCH 737/1001] Adapt dev-guide documentation


---

diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
index 2617a29..5c185b4 100644
--- a/docs/dev-guide.rst
+++ b/docs/dev-guide.rst
@@ -344,67 +344,73 @@ displayed).
 Stubbing out a new Widget
 =========================
 
-You write a new widget in the ``hubs/widgets/`` directory and must declare it
-in the registry dict in ``hubs/widgets/__init__.py``.
+First, some definitions:
 
-In order to be valid, a widget must have:
+- A *widget* is a Python class inheriting from ``hubs.widgets.base.Widget``.
+  It will be registered with the application in the ``hubs.widgets.registry``
+  dictionary.
+- A *widget instance* is a database record (``hubs.models.Widget``), it means
+  that a particular *widget* has been set up for a particular *hub*, with a
+  specific configuration.  A *widget* can be set up more that one time for the
+  same *hub*, with different configurations (for example, the ``sticky``
+  widget).  In this case, there will one *widget* but multiple *widget
+  instances*.
 
-- A ``data(session, widgets, **kwargs)`` function that returns a
-  jsonifiable dict of data.  This will get cached -- more on that later.
-- A ``template`` object that is a jinja2 template for that widget.
-- Optionally, a ``chrome`` decorator.
-- A ``should_invalidate(message, session, widget)`` function that will be used to
-  *potentially* invalidate the widget's cache. That function will get called by
-  a backend daemon listening for fedmsg messages so when you update your group
-  memberships in FAS, a fedmsg message hits the fedora-hubs backend and returns
-  True if the lookup value should be nuked/refreshed in memcached (or some
-  other store).
+As explained above, widgets are Python classes.  They are best isolated in
+their own module and directory.  To create a new widget, you can follow these
+steps:
 
-If you want to try making a new widget:
+- create a new directory in ``hubs/widgets/``
+- write your widget subclass in the ``__init__.py`` file
+- reference the class in your configuration file, or in the general
+  ``hubs/default_config.py`` configuration file.
 
-- Copy an existing one in ``hubs/widgets/``
-- Add it to the registry in ``hubs/widgets/__init__.py``
-- If you want it to show up on a **user** page, add it to ``hubs/defaults.py``
-  in the ``add_user_widgets`` function.
-- If you want it to show up on **group** pages, add it to ``populate.py``.
+In order to be valid, a widget must:
 
-Destroy your database, rebuild it, and re-run the app.  Your widget should show up.
+- inherit from the ``hubs.widgets.base.Widget`` class,
+- have a valid ``name`` attribute,
+- have a valid ``position`` attribute,
+- contain at least one view named "``root``", registered for the "``/``" URL.
+  See the description of widget views below for details.
+
+A widget view is a class which inherits from the
+``hubs.widgets.view.WidgetView`` class.  A widget can have one or more of them.
+
+Widget views can make use of templates following the Jinja2 engine syntax.  The
+templates are looked for in the widget's ``templates`` subdirectrory first, and
+then in the generic ``hubs/widgets/templates/`` directory.  They can make use
+of any Jinja2 feature, including inheritance, macros, etc.
+
+If you want to add filters to youre widget's Jinja2 environment, you can do so
+by overriding the widget's ``get_template_environment()`` method.
+
+Hubs provides the ``panel.html`` master template for widgets that want their
+output to be wrapped in the common panel chrome, just use the ``extends`` tag
+to take advantage of it.  You can also set a ``title`` variable in your root
+view context, and it will be used for the panel title.
+
+Refer to the API documentation to learn more on how to write a widget view.
+
+A widget can also have any number of cached functions.  A cached function is a
+subclass of ``hubs.widgets.caching.CachedFunction``.
+
+The result is cached until a bus message is recieved that marks the former
+result as invalid.  To filter which messages are relevant, a cached function
+has a ``should_invalidate(message)`` method that returns ``True`` if the cached
+result is obsolete, ``False`` otherwise.  A backend daemon will call this
+method on each incoming bus message.
+
+Refer to the API documentation to learn more on how to write a cached function.
+
+If you want it to show up on a new **user** page, add it to
+``hubs/defaults.py`` in the ``add_user_widgets`` function.  If you want it to
+show up on new **group** pages, add it to the ``add_group_widgets`` function in
+the same module.  If you want your widget to be part of the example hubs
+created by default, add it to ``populate.py``.  Then destroy your database,
+rebuild it, and re-run the app.  Your widget should show up.
+
+Feel free to look at existing widgets for inspiration.
 
-Widget-specific views
----------------------
-A widget may also register additional routes by using the
-``hubs.widgets.base.widget_route`` decorator. There are some differences from
-the usual ``route`` decorator or the ``add_url_rule`` function:
-
-- The view function will be passed the database ``session`` and ``widget``
-  instances as first arguments, and then the URL kwargs.
-- The endpoint will be prefixed with ``<widget_name>_``, for example
-  ``meetings_``. Remember that when you want to reverse the URL with
-  ``url_for``.
-- When reversing the URL, you need to pass the ``hub`` and ``idx`` kwargs.
-
-Example: consider this additional method that needs to be exported as a view
-in the ``meetings`` plugin::
-
-    from hubs.widgets.base import widget_route
-    @widget_route(rule="search/<requester>/", methods=["GET", "POST"])
-    def search(session, widget, requester):
-        # Do something, probably using the "requester" variable.
-        return flask.jsonify({"hope_sources": ["Obi-Wan Kenobi"]})
-
-Then, a valid call to ``url_for`` to reverse this URL would look like::
-
-    url_for("meetings_search", hub=widget.hub.name, idx=widget.idx, requester="Leia")
-
-Behind the scenes, the ``widget_route`` decorator adds a ``ROUTES`` global
-variable in the widget module, that contains dictionaries representing the
-arguments passed to Flask's `add_url_rule
-<http://flask.pocoo.org/docs/latest/api/#flask.Flask.add_url_rule>`_ function.
-
-If you want more control, you can edit this ``ROUTES`` list directly, but there
-are a difference from the basic ``add_url_rule`` function: the view function
-name must be given with the dict key ``view_func_name``, and not ``view_func``
-as in the ``add_url_rule`` function.
 
 
 A proposal, client-side templates

From 520184236cc4983627615022bf0d45630f261b08 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:11 +0000
Subject: [PATCH 738/1001] Build the API documentation with Sphinx


---

diff --git a/docs/api.rst b/docs/api.rst
new file mode 100644
index 0000000..8cecb30
--- /dev/null
+++ b/docs/api.rst
@@ -0,0 +1,42 @@
+Developer Interfaces
+====================
+
+This documents ways developers can interface with Fedora Hubs.
+
+.. _widgets-api:
+
+
+Widgets
+-------
+
+.. automodule:: hubs.widgets
+   :members:
+   :show-inheritance:
+
+Widgets registry
+^^^^^^^^^^^^^^^^
+
+.. automodule:: hubs.widgets.registry
+   :members:
+   :show-inheritance:
+
+Widget class
+^^^^^^^^^^^^
+
+.. automodule:: hubs.widgets.base
+   :members:
+   :show-inheritance:
+
+Widget view
+^^^^^^^^^^^
+
+.. automodule:: hubs.widgets.view
+   :members:
+   :show-inheritance:
+
+Caching
+^^^^^^^
+
+.. automodule:: hubs.widgets.caching
+   :members:
+   :show-inheritance:
diff --git a/docs/conf.py b/docs/conf.py
index ca55b4f..27b4be2 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -16,20 +16,25 @@
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
 #
-# import os
-# import sys
-# sys.path.insert(0, os.path.abspath('.'))
+import os
+import sys
+sys.path.insert(0, os.path.abspath('..'))
 
 # -- General configuration ------------------------------------------------
 
 # If your documentation needs a minimal Sphinx version, state it here.
 #
-# needs_sphinx = '1.0'
+needs_sphinx = '1.3'
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = []
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.doctest',
+    'sphinx.ext.napoleon',
+    'sphinx.ext.viewcode',
+]
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
index 5c185b4..874a7b1 100644
--- a/docs/dev-guide.rst
+++ b/docs/dev-guide.rst
@@ -344,72 +344,9 @@ displayed).
 Stubbing out a new Widget
 =========================
 
-First, some definitions:
-
-- A *widget* is a Python class inheriting from ``hubs.widgets.base.Widget``.
-  It will be registered with the application in the ``hubs.widgets.registry``
-  dictionary.
-- A *widget instance* is a database record (``hubs.models.Widget``), it means
-  that a particular *widget* has been set up for a particular *hub*, with a
-  specific configuration.  A *widget* can be set up more that one time for the
-  same *hub*, with different configurations (for example, the ``sticky``
-  widget).  In this case, there will one *widget* but multiple *widget
-  instances*.
-
-As explained above, widgets are Python classes.  They are best isolated in
-their own module and directory.  To create a new widget, you can follow these
-steps:
-
-- create a new directory in ``hubs/widgets/``
-- write your widget subclass in the ``__init__.py`` file
-- reference the class in your configuration file, or in the general
-  ``hubs/default_config.py`` configuration file.
-
-In order to be valid, a widget must:
-
-- inherit from the ``hubs.widgets.base.Widget`` class,
-- have a valid ``name`` attribute,
-- have a valid ``position`` attribute,
-- contain at least one view named "``root``", registered for the "``/``" URL.
-  See the description of widget views below for details.
-
-A widget view is a class which inherits from the
-``hubs.widgets.view.WidgetView`` class.  A widget can have one or more of them.
-
-Widget views can make use of templates following the Jinja2 engine syntax.  The
-templates are looked for in the widget's ``templates`` subdirectrory first, and
-then in the generic ``hubs/widgets/templates/`` directory.  They can make use
-of any Jinja2 feature, including inheritance, macros, etc.
-
-If you want to add filters to youre widget's Jinja2 environment, you can do so
-by overriding the widget's ``get_template_environment()`` method.
-
-Hubs provides the ``panel.html`` master template for widgets that want their
-output to be wrapped in the common panel chrome, just use the ``extends`` tag
-to take advantage of it.  You can also set a ``title`` variable in your root
-view context, and it will be used for the panel title.
-
-Refer to the API documentation to learn more on how to write a widget view.
-
-A widget can also have any number of cached functions.  A cached function is a
-subclass of ``hubs.widgets.caching.CachedFunction``.
-
-The result is cached until a bus message is recieved that marks the former
-result as invalid.  To filter which messages are relevant, a cached function
-has a ``should_invalidate(message)`` method that returns ``True`` if the cached
-result is obsolete, ``False`` otherwise.  A backend daemon will call this
-method on each incoming bus message.
-
-Refer to the API documentation to learn more on how to write a cached function.
-
-If you want it to show up on a new **user** page, add it to
-``hubs/defaults.py`` in the ``add_user_widgets`` function.  If you want it to
-show up on new **group** pages, add it to the ``add_group_widgets`` function in
-the same module.  If you want your widget to be part of the example hubs
-created by default, add it to ``populate.py``.  Then destroy your database,
-rebuild it, and re-run the app.  Your widget should show up.
-
-Feel free to look at existing widgets for inspiration.
+Widgets can be added and removed from a Hub to provide a customized experience
+for each user. To learn how to implement a new widget, consult the
+:ref:`widgets-api` documentation.
 
 
 
diff --git a/docs/index.rst b/docs/index.rst
index 1f5379f..72ec92e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -13,6 +13,7 @@ Contents:
 
    overview
    dev-guide
+   api
 
 
 Indices and tables
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 6d5f257..a4cafba 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -1,4 +1,79 @@
 """
+First, some definitions:
+
+- A *widget* is a Python class inheriting from
+  :py:class:`hubs.widgets.base.Widget`.
+  It will be registered with the application in the
+  :py:data:`hubs.widgets.registry` dictionary.
+- A *widget instance* is a database record (:py:class:`hubs.models.Widget`), it
+  means that a particular *widget* has been set up for a particular *hub*, with
+  a specific configuration.  A *widget* can be set up more that one time for
+  the same *hub*, with different configurations (for example, the ``sticky``
+  widget).  In this case, there will one *widget* but multiple *widget
+  instances*.
+
+As explained above, widgets are Python classes.  They are best isolated in
+their own module and directory.  To create a new widget, you can follow these
+steps:
+
+- create a new directory in ``hubs/widgets/``
+- write your widget subclass in the ``__init__.py`` file
+- reference the class in your configuration file, or in the general
+  ``hubs/default_config.py`` configuration file.
+
+In order to be valid, a widget must:
+
+- inherit from the :py:class:`hubs.widgets.base.Widget` class,
+- have a valid :py:attr:`~hubs.widgets.base.Widget.name` attribute,
+- have a valid :py:attr:`~hubs.widgets.base.Widget.position` attribute,
+- contain at least one view named "``root``", registered for the "``/``" URL.
+  See the description of widget views below for details.
+
+A widget view is a class which inherits from the
+:py:class:`hubs.widgets.view.WidgetView` class.  A widget can have one or more
+of them.
+
+Widget views can make use of templates following the Jinja2 engine syntax.  The
+templates are looked for in the widget's ``templates`` subdirectrory first, and
+then in the generic ``hubs/widgets/templates/`` directory.  They can make use
+of any Jinja2 feature, including inheritance, macros, etc.
+
+If you want to add filters to youre widget's Jinja2 environment, you can do so
+by overriding the widget's
+:py:meth:`~hubs.widgets.base.Widget.get_template_environment` method.
+
+Hubs provides the ``panel.html`` master template for widgets that want their
+output to be wrapped in the common panel chrome, just use the ``extends`` tag
+to take advantage of it.  You can also set a ``title`` variable in your root
+view context, and it will be used for the panel title.
+
+Refer to the API documentation to learn more on how to write a widget view.
+
+A widget can also have any number of cached functions.  A cached function is a
+subclass of :py:class:`hubs.widgets.caching.CachedFunction`.
+
+The result is cached until a bus message is recieved that marks the former
+result as invalid.  To filter which messages are relevant, a cached function
+has a
+:py:meth:`~hubs.widgets.caching.CachedFunction.should_invalidate(message)`
+method that returns ``True`` if the cached result is obsolete, ``False``
+otherwise.  A backend daemon will call this method on each incoming bus
+message.
+
+Refer to the API documentation to learn more on how to write a cached function.
+
+If you want it to show up on a new **user** page, add it to
+:py:mod:`hubs.defaults` in the :py:func:`add_user_widgets` function.  If you
+want it to show up on new **group** pages, add it to the
+:py:func:`add_group_widgets` function in the same module.  If you want your
+widget to be part of the example hubs created by default, add it to
+``populate.py``.  Then destroy your database, rebuild it, and re-run the app.
+Your widget should show up.
+
+Feel free to look at existing widgets for inspiration.
+
+The widget registry is instanciated in this module, as :py:data:`registry`.
+
 Attributes:
     registry (dict): This dictionary is a registry of available widgets in
         Fedora Hubs.
diff --git a/tox.ini b/tox.ini
index 24d3f29..03e75ca 100644
--- a/tox.ini
+++ b/tox.ini
@@ -30,7 +30,9 @@ commands =
 
 [testenv:docs]
 changedir = docs
-deps = sphinx
+deps =
+    -rrequirements.txt
+    sphinx
 whitelist_externals =
     mkdir
 commands=

From 546067eee44faf602796d3e34410ba8561a26a8d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:11 +0000
Subject: [PATCH 739/1001] Improve API doc crossreferences


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index a4cafba..1ec88bc 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -26,8 +26,8 @@ In order to be valid, a widget must:
 - inherit from the :py:class:`hubs.widgets.base.Widget` class,
 - have a valid :py:attr:`~hubs.widgets.base.Widget.name` attribute,
 - have a valid :py:attr:`~hubs.widgets.base.Widget.position` attribute,
-- contain at least one view named "``root``", registered for the "``/``" URL.
-  See the description of widget views below for details.
+- contain at least one widget view named "``root``", registered for the "``/``"
+  URL.
 
 A widget view is a class which inherits from the
 :py:class:`hubs.widgets.view.WidgetView` class.  A widget can have one or more
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 824e34d..70dbc9c 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -27,9 +27,10 @@ class Widget(object):
             will appear in some URLs, so be careful to only use simple,
             URL-compatible characters.
         position (str): The position of the widget in the rendered page. It
-            should be one of the following values: 'left', 'right', or 'both'.
+            should be one of the following values: ``left``, ``right``, or
+            ``both``.
         arguments (list): A list of dictionaries that describe a widget's
-            configuration. See `hubs.widgets.base.Argument`.
+            configuration. See :py:class:`hubs.widgets.base.Argument`.
     """
 
     name = None
@@ -40,7 +41,11 @@ class Widget(object):
         self._template_environment = None
 
     def validate(self):
-        """Ensure that the widget has the bits it needs."""
+        """
+        Ensure that the widget has the bits it needs.
+
+        Raises: AttributeError
+        """
         if self.name is None:
             raise AttributeError('Widgets must have a "name" attribute')
         if not re.match('^[\w_.-]+$', self.name):
@@ -89,7 +94,7 @@ class Widget(object):
 
     def _get_local_subclasses(self, parent_class):
         """
-        Returns the subclasses of the `parent_class` defined in this widget's
+        Returns the subclasses of the ``parent_class`` defined in this widget's
         Python module.
         """
         result = []
@@ -111,7 +116,7 @@ class Widget(object):
         """
         Returns:
             dict: A dictionary of the widget-specific views, indexed by their
-                `name` attribute.
+                :py:attr:`~hubs.widgets.view.WidgetView.name` attribute.
         """
         return dict([
             (view.name, view) for view in
diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index 2eded91..c8a56e8 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -1,7 +1,7 @@
 """
 Attributes:
     cache (dogpile.cache.region.CacheRegion): The cache where function results
-        will be stored. It is configured with the `fedora-hubs.cache` key in
+        will be stored. It is configured with the ``fedora-hubs.cache`` key in
         fedmsg configuration.
 """
 from __future__ import unicode_literals
@@ -40,17 +40,18 @@ class CachedFunction(object):
 
     To use this class, you must subclass it and implement a couple methods.
     It is instantiated by passing a widget instance (database record) as only
-    argument, which lets it access the `.config` property and act accordingly.
+    argument, which lets it access the :py:attr:`~hubs.models.Widget.config`
+    property and act accordingly.
 
-    You must implement the `execute()` method, which must return a
+    You must implement the :py:meth:`.execute` method, which must return a
     JSON-serializable value.
 
-    You must also implement the `should_invalidate()` method, which takes the
-    bus message as only argument, and returns `True` if the cache should be
-    rebuild, `False` otherwise.
+    You must also implement the :py:meth:`.should_invalidate` method, which
+    takes the bus message as only argument, and returns ``True`` if the cache
+    should be rebuild, ``False`` otherwise.
 
     To call the function, instanciate the class and execute it. You may also
-    call the `.get_data()` method.
+    call the :py:meth:`.get_data` method.
 
     Args:
         instance (hubs.models.Widget): The widget instance.
@@ -111,7 +112,7 @@ class CachedFunction(object):
             message (dict): The recieved bus message.
 
         Returns:
-            bool: If `True`, the cache will be rebuilt.
+            bool: If ``True``, the cache will be rebuilt.
         """
         # if not self._pass_filter(message):
         #     return False
@@ -119,7 +120,8 @@ class CachedFunction(object):
 
     def is_cached(self):
         """
-        Return a boolean indicating if the function's result is currently in the cache.
+        Return a boolean indicating if the function's result is currently in
+        the cache.
 
         Returns:
             bool: Whether the cache currently contains the function result.
diff --git a/hubs/widgets/registry.py b/hubs/widgets/registry.py
index db463b3..109e69a 100644
--- a/hubs/widgets/registry.py
+++ b/hubs/widgets/registry.py
@@ -33,7 +33,7 @@ class WidgetRegistry(UserDict):
 
         Args:
             widget_path (str): Python path to the subclass of
-                `hubs.widgets.base.Widget`.
+                :py:class:`hubs.widgets.base.Widget`.
         """
         mod_path, _, cls_name = widget_path.rpartition('.')
         mod = import_module(mod_path)
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index 05a633a..19ff77c 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -9,30 +9,32 @@ class WidgetView(View):
 
     You must subclass this class to use it in your view:
 
-    - the `name` attribute must be defined
-    - the `template_name` attribute must be defined, or the `get_template()`
-      method must be implemented
-    - the `get_context()` method must be implemented
+    - the :py:attr:`.name` attribute must be defined
+    - the :py:attr:`.template_name` attribute must be defined, or the
+      :py:meth:`.get_template` method must be implemented
+    - the :py:meth:`.get_context` method must be implemented
 
-    Every widget must have a view with the name "`root`" registered to `['/']`,
-    which will be the main entry point for the widget.
+    Every widget must have a view with the name "``root``" registered to
+    ``['/']``, which will be the main entry point for the widget.
 
     The resulting endpoint will be composed using the widget name and the view
-    name as `<widget_name>_<view_name>`, for example `meetings_root`.
-    Remember that when you want to reverse the URL with `url_for`.
+    name as ``<widget_name>_<view_name>``, for example ``meetings_root``.
+    Remember that when you want to reverse the URL with :py:meth:`url_for`.
 
     When reversing the URL, you need to pass the ``hub`` and ``idx`` kwargs,
-    which are respectively the hub name (`Hub.name`) and the widget instance
-    (the database record) primary key (`Widget.idx`).
+    which are respectively the hub name (:py:attr:`hubs.models.Hub.name`) and
+    the widget instance (the database record) primary key
+    (:py:attr:`hubs.models.Widget.idx`).
 
     Attributes:
         name (str): The view name. It will be used to compose the URL endpoint,
-            following the "`<widget.name>_<view.name>`" convention.
+            following the "``<widget.name>_<view.name>``" convention.
         url_rules (list): A list of URL rules that this view must be registered
-            for (like the `rule` parameter of Flask's `add_url_rule()`).
+            for (like the ``rule`` parameter of Flask's
+            :py:meth:`add_url_rule`).
         template_name (str): The template name to use for this view. It will be
-            looked for in the widget's `templates` subdirectory first, and
-            then in the global `hubs/widgets/templates/` directory.
+            looked for in the widget's ``templates`` subdirectory first, and
+            then in the global ``hubs/widgets/templates/`` directory.
 
     This class is Flask-specific. If another framework were to be switched to,
     it would have to be re-implemented.
@@ -62,8 +64,8 @@ class WidgetView(View):
 
     def get_template(self):
         """
-        Return the template object, looking for `template_name` in the widget's
-        template environment.
+        Return the template object, looking for :py:attr:`template_name` in the
+        widget's template environment.
         """
         if self.template_name is None:
             return NotImplementedError
@@ -89,8 +91,8 @@ class WidgetView(View):
 
     def dispatch_request(self, *args, **kwargs):
         """
-        The `dispatch_request` method that subclasses of `flask.views.View`
-        must implement. It binds the other methods together.
+        The method that subclasses of :py:class:`flask.views.View` must
+        implement. It binds the other methods together.
         """
         instance = self._get_instance(*args, **kwargs)
         context = self.get_context(instance, *args, **kwargs)

From 6489dd348f7f292bb99f7f71dae39b14f2858c41 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:11 +0000
Subject: [PATCH 740/1001] Make a real class for WidgetParameter


---

diff --git a/hubs/models.py b/hubs/models.py
index d322437..2c155b9 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -296,7 +296,7 @@ def _config_default(context):
     widget_name = context.current_parameters['plugin']
     widget = hubs.widgets.registry[widget_name]
     return json.dumps(dict([
-        (arg.name, arg.default) for arg in widget.get_arguments()
+        (param.name, param.default) for param in widget.get_parameters()
         ]))
 
 
diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index 76fc4ac..80d4a8d 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -21,16 +21,16 @@
         {% elif widget %}
         <input name="widget_name" type="hidden" value="{{ widget.name }}">
         <input name="position" type="hidden" value="{{ side }}">
-          {% for arg in widget.get_arguments() %}
+          {% for param in widget.get_parameters() %}
             <fieldset class="form-group ">
-              <strong>{{ arg.label | capitalize }}</strong>
-              <input id="{{ arg.name }}" class="form-control" type="text"
-                value="{{ arg.default if arg.default else '' }}"
-                name="{{ arg.name }}" />
+              <strong>{{ param.label | capitalize }}</strong>
+              <input id="{{ param.name }}" class="form-control" type="text"
+                value="{{ param.default if param.default else '' }}"
+                name="{{ param.name }}" />
             </fieldset>
-            {% if arg.help %}
+            {% if param.help %}
               <div>
-                <small class="text-muted">{{ arg.help }}</small>
+                <small class="text-muted">{{ param.help }}</small>
               </div>
             {% endif %}
           {% else %}
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index 44a7391..5b6241c 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -8,16 +8,16 @@
         <h4 class="modal-title">Configure {{ name }}</h4>
       </div>
       <div class="modal-body">
-      {% for arg in widget.module.get_arguments() %}
+      {% for param in widget.module.get_parameters() %}
         <fieldset class="form-group ">
-          <strong>{{ arg.label | capitalize }}</strong>
-          <input id="{{ arg.name }}" class="form-control" type="text"
-              value="{{ widget.config.get(arg.name, arg.default if arg.default else '') }}"
-              name="{{ arg.name }}" />
+          <strong>{{ param.label | capitalize }}</strong>
+          <input id="{{ param.name }}" class="form-control" type="text"
+              value="{{ widget.config.get(param.name, param.default if param.default else '') }}"
+              name="{{ param.name }}" />
         </fieldset>
-        {% if arg.help %}
+        {% if param.help %}
           <div>
-            <small class="text-muted">{{ arg.help }}</small>
+            <small class="text-muted">{{ param.help }}</small>
           </div>
         {% endif %}
       {% else %}
@@ -28,7 +28,7 @@
         <button type="button" class="btn btn-default" data-dismiss="modal">
           Close
         </button>
-        {% if widget.module.get_arguments() %}
+        {% if widget.module.get_parameters() %}
         <button type="submit" class="btn btn-default">
           Save
         </button>
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 27e9235..6641711 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -204,16 +204,16 @@ def hub_add_widget_post(name):
         plugin=widget_name, index=-1, left=position == 'left')
     error = False
     config = {}
-    for arg in widget.module.get_arguments():
-        val = flask.request.form.get(arg.name)
+    for param in widget.module.get_parameters():
+        val = flask.request.form.get(param.name)
         if not val:
             flask.flash(
-                'You must provide a value for: %s' % arg.name, 'error')
+                'You must provide a value for: %s' % param.name, 'error')
             error = True
             break
         try:
-            arg.validator(flask.g.db, val)
-            config[arg.name] = val
+            param.validator(flask.g.db, val)
+            config[param.name] = val
         except Exception as err:
             flask.flash('Invalid data provided, error: %s' % err, 'error')
             error = True
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index cbc002c..192c44d 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -40,16 +40,16 @@ def widget_edit_post(hub, idx):
     widget = get_widget_instance(hub, idx)
     error = False
     config = {}
-    for arg in widget.module.get_arguments():
-        val = flask.request.form.get(arg.name)
+    for param in widget.module.get_parameters():
+        val = flask.request.form.get(param.name)
         if not val:
             flask.flash(
-                'You must provide a value for: %s' % arg.name, 'error')
+                'You must provide a value for: %s' % param.name, 'error')
             error = True
             break
         try:
-            val = arg.validator(flask.g.db, val)
-            config[arg.name] = val
+            val = param.validator(flask.g.db, val)
+            config[param.name] = val
         except Exception as err:
             flask.flash('Invalid data provided, error: %s' % err, 'error')
             error = True
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index 1a8cc50..bdb7e7b 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -9,7 +9,7 @@ class About(Widget):
 
     name = "about"
     position = "both"
-    arguments = [dict(
+    parameters = [dict(
         name="text",
         label="Text",
         default="I am a Fedora user, and this is my about",
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index 6c76716..79315e1 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -12,7 +12,7 @@ class Badges(Widget):
 
     name = "badges"
     position = "right"
-    arguments = [dict(
+    parameters = [dict(
         name="username",
         label="Username",
         default=None,
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 70dbc9c..50b726e 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -1,6 +1,5 @@
 from __future__ import unicode_literals, absolute_import
 
-import collections
 import logging
 import re
 import flask
@@ -14,8 +13,33 @@ from .view import WidgetView
 
 log = logging.getLogger(__name__)
 
-Argument = collections.namedtuple(
-    'Argument', ('name', 'label', 'default', 'validator', 'help'))
+
+class WidgetParameter(object):
+    """
+    Configuration option for a widget.
+
+    A widget can be configured differently for each instance of this widget in
+    a hub.  The list of configuration options is described by the list of
+    :py:class:`WidgetParameter` objects returned by the widget's
+    :py:meth:`~Widget.get_parameters` method.
+
+    Attributes:
+        name (str): The name of the parameter.
+        label (str): A humanized name of the parameter, which will be shown in
+            the UI.
+        default: The default value if this parameter is not set.
+        validator (function): A validation function that will be called when
+            a user sets the parameter value.
+        help (str): A help text that will be shown in the UI.
+    """
+
+    _attrs = ('name', 'label', 'default', 'validator', 'help')
+
+    def __init__(self, **kwargs):
+        for name in self._attrs:
+            setattr(self, name, kwargs.pop(name, None))
+        for name in kwargs:
+            raise TypeError("Invalid attribute: %s" % name)
 
 
 class Widget(object):
@@ -29,13 +53,13 @@ class Widget(object):
         position (str): The position of the widget in the rendered page. It
             should be one of the following values: ``left``, ``right``, or
             ``both``.
-        arguments (list): A list of dictionaries that describe a widget's
-            configuration. See :py:class:`hubs.widgets.base.Argument`.
+        parameters (list): A list of dictionaries that describe a widget's
+            configuration. See :py:class:`hubs.widgets.base.WidgetParameter`.
     """
 
     name = None
     position = None
-    arguments = []
+    parameters = []
 
     def __init__(self):
         self._template_environment = None
@@ -65,8 +89,12 @@ class Widget(object):
             raise AttributeError(
                 'The root view must be registered for the "/" URL rule.')
 
-    def get_arguments(self):
-        return [Argument(**arg) for arg in self.arguments]
+    def get_parameters(self):
+        """
+        Return the :py:class:`WidgetParameter` instances that describe this
+        widget's configuration options.
+        """
+        return [WidgetParameter(**param) for param in self.parameters]
 
     def get_template_environment(self):
         """
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 5965be1..c63fa3c 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -15,7 +15,7 @@ class Bugzilla(Widget):
 
     name = "bugzilla"
     position = "right"
-    arguments = [dict(
+    parameters = [dict(
         name="username",
         label="Username",
         default=None,
diff --git a/hubs/widgets/dummy/__init__.py b/hubs/widgets/dummy/__init__.py
index 19d43c4..ca4bac8 100644
--- a/hubs/widgets/dummy/__init__.py
+++ b/hubs/widgets/dummy/__init__.py
@@ -8,7 +8,7 @@ class Dummy(Widget):
 
     name = "dummy"
     position = "both"
-    arguments = [dict(
+    parameters = [dict(
         name="text",
         label="Text",
         default="Lorem ipsum dolor...",
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index a557148..142548f 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -17,7 +17,7 @@ class FedmsgStats(Widget):
 
     name = "fedmsgstats"
     position = "both"
-    arguments = [dict(
+    parameters = [dict(
         name="username",
         label="Username",
         default=None,
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index bd35b61..b1f8299 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -12,7 +12,7 @@ class Feed(Widget):
 
     name = "feed"
     position = "left"
-    arguments = [
+    parameters = [
         {
             "name": "username",
             "label": "Username",
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
index 2c9d26c..8f60efa 100644
--- a/hubs/widgets/fhosted/__init__.py
+++ b/hubs/widgets/fhosted/__init__.py
@@ -11,7 +11,7 @@ class FedoraHosted(Widget):
 
     name = "fhosted"
     position = "right"
-    arguments = [
+    parameters = [
         dict(
             name="project",
             label="Project",
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 8b9aab3..6961d4a 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -17,7 +17,7 @@ class GitHubPRs(Widget):
 
     name = "github_pr"
     position = "right"
-    arguments = [
+    parameters = [
         dict(
             name="organization",
             label="Organization",
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index 6af020d..e29faa7 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -11,7 +11,7 @@ class GitHubIssues(Widget):
 
     name = "githubissues"
     position = "right"
-    arguments = [
+    parameters = [
         dict(
             name="org",
             label="Username",
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index d15fa1d..351ec4f 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -9,7 +9,7 @@ class Library(Widget):
 
     name = "library"
     position = "both"
-    arguments = [dict(
+    parameters = [dict(
         name="urls",
         label="URLs",
         default=None,
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index f745e28..dfae632 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -8,7 +8,7 @@ class Linechart(Widget):
 
     name = "linechart"
     position = "left"
-    arguments = [dict(
+    parameters = [dict(
         name="username",
         label="Username",
         default=None,
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index c87df27..01908ce 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -15,7 +15,7 @@ class Meetings(Widget):
 
     name = "meetings"
     position = "both"
-    arguments = [
+    parameters = [
         dict(
             name="calendar",
             label="Calendar",
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 580fece..518d12d 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -13,7 +13,7 @@ class PagurePRs(Widget):
 
     name = "pagure_pr"
     position = "right"
-    arguments = [
+    parameters = [
         dict(
             name="repo",
             label="Repository",
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index f3490c9..356d59f 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -13,7 +13,7 @@ class PagureIssues(Widget):
 
     name = "pagureissues"
     position = "right"
-    arguments = [
+    parameters = [
         dict(
             name="repo",
             label="Repository",
diff --git a/hubs/widgets/rules/__init__.py b/hubs/widgets/rules/__init__.py
index e4e874c..498e3a8 100644
--- a/hubs/widgets/rules/__init__.py
+++ b/hubs/widgets/rules/__init__.py
@@ -14,7 +14,7 @@ class Rules(Widget):
 
     name = "rules"
     position = "both"
-    arguments = [
+    parameters = [
         dict(
             name="link",
             label="Link",
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index 02e7fdf..3f038ba 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -8,7 +8,7 @@ class Sticky(Widget):
 
     name = "sticky"
     position = "both"
-    arguments = [
+    parameters = [
         dict(
             name="text",
             label="Text",
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
index 14538f0..1641191 100644
--- a/hubs/widgets/subscriptions/__init__.py
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -17,7 +17,7 @@ class Subscriptions(Widget):
 
     name = "subscriptions"
     position = "right"
-    arguments = [
+    parameters = [
         dict(
             name="username",
             label="Username",
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 5d891e0..07fd52b 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -12,7 +12,7 @@ class PendingACLs(Widget):
 
     name = "workflow.pendingacls"
     position = "right"
-    arguments = [
+    parameters = [
         dict(
             name="username",
             label="Username",
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index d2490a3..79fac1f 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -16,7 +16,7 @@ class Updates2Stable(Widget):
 
     name = "workflow.updates2stable"
     position = "right"
-    arguments = [
+    parameters = [
         dict(
             name="username",
             label="Username",

From 316a22855c6977a2676e377c7f572e0d1bd1e0fb Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:11 +0000
Subject: [PATCH 741/1001] More explicit widget validation errors


---

diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index bc8a166..0abe27c 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -45,13 +45,13 @@ class WidgetTest(APPTest):
             AttributeError, '.* "name" .*', test_widget.validate)
         test_widget.name = "invalid name \xe2\x98\xba"
         self.assertRaisesRegexp(
-            AttributeError, '^Invalid widget name: ', test_widget.validate)
+            AttributeError, '^invalid widget name: ', test_widget.validate)
         test_widget.name = "localtest"
         self.assertRaisesRegexp(
-            AttributeError, '.* "position" .*', test_widget.validate)
+            AttributeError, '"position" .*', test_widget.validate)
         test_widget.position = "invalid"
         self.assertRaisesRegexp(
-            AttributeError, '.* "position" .*', test_widget.validate)
+            AttributeError, '"position" .*', test_widget.validate)
         test_widget.position = "both"
         self.assertRaisesRegexp(
             AttributeError, '.* "root" .*', test_widget.validate)
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 50b726e..c6b87af 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -71,23 +71,23 @@ class Widget(object):
         Raises: AttributeError
         """
         if self.name is None:
-            raise AttributeError('Widgets must have a "name" attribute')
+            raise AttributeError('widgets must have a "name" attribute')
         if not re.match('^[\w_.-]+$', self.name):
             raise AttributeError(
-                'Invalid widget name: %r. ' % self.name +
+                'invalid widget name: %r. ' % self.name +
                 'Please use URL-compatible characters.')
         if self.position not in ['left', 'right', 'both']:
             raise AttributeError(
-                '%r\'s "position" is not: `left`, `right` or `both`'
-                % self.name)
+                '"position" attribute is not: `left`, `right` or `both`'
+                )
         root_view = self.get_views().get("root")
         if root_view is None:
             raise AttributeError(
-                'Widgets must have a "root" view, please refer to the '
+                'widgets must have a "root" view, please refer to the '
                 'documentation.')
         if "/" not in root_view.url_rules:
             raise AttributeError(
-                'The root view must be registered for the "/" URL rule.')
+                'the root view must be registered for the "/" URL rule.')
 
     def get_parameters(self):
         """
diff --git a/hubs/widgets/registry.py b/hubs/widgets/registry.py
index 109e69a..ad4d494 100644
--- a/hubs/widgets/registry.py
+++ b/hubs/widgets/registry.py
@@ -52,7 +52,11 @@ class WidgetRegistry(UserDict):
                 widget.name = widget_path[len(prefix):]
             else:
                 widget.name = widget_path
-        widget.validate()
+        try:
+            widget.validate()
+        except AttributeError as e:
+            raise AttributeError(
+                "Error registering %s: %s" % (widget_path, e))
         self.data[widget.name] = widget
 
     def register_routes(self, app):

From cf2ad4387f4c57d09d8617ba6b4abb95d4d4791d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 09 2017 15:58:11 +0000
Subject: [PATCH 742/1001] Allow the widget to declare where the views and cached functions are


---

diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index 0abe27c..9b53e57 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -1,5 +1,7 @@
 from __future__ import unicode_literals
 
+import six
+
 from hubs.widgets.base import Widget
 from hubs.widgets.caching import CachedFunction
 from hubs.widgets.view import WidgetView
@@ -72,6 +74,20 @@ class WidgetTest(APPTest):
             {"root": TestingView}
             )
 
+    def test_list_views_relative(self):
+        testing_widget = TestingWidget()
+        testing_widget.views_module = ".nowhere"
+        self.assertRaises(AttributeError, testing_widget.get_views)
+        if six.PY2:
+            # On Python2, setting the import module to "." raises a KeyError,
+            # so we can't test.
+            return
+        testing_widget.views_module = "."
+        self.assertEqual(
+            testing_widget.get_views(),
+            {"root": TestingView}
+            )
+
     def test_list_functions(self):
         testing_widget = TestingWidget()
         self.assertEqual(
@@ -79,6 +95,20 @@ class WidgetTest(APPTest):
             {"TestingFunction": TestingFunction}
             )
 
+    def test_list_functions_relative(self):
+        testing_widget = TestingWidget()
+        testing_widget.cached_functions_module = ".nowhere"
+        self.assertRaises(AttributeError, testing_widget.get_cached_functions)
+        if six.PY2:
+            # On Python2, setting the import module to "." raises a KeyError,
+            # so we can't test.
+            return
+        testing_widget.cached_functions_module = "."
+        self.assertEqual(
+            testing_widget.get_cached_functions(),
+            {"TestingFunction": TestingFunction}
+            )
+
     def test_list_views(self):
         class TestView1(WidgetView):
             name = "root"
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index c6b87af..3d27813 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -55,11 +55,19 @@ class Widget(object):
             ``both``.
         parameters (list): A list of dictionaries that describe a widget's
             configuration. See :py:class:`hubs.widgets.base.WidgetParameter`.
+        views_module (list): The Python path to the module where the widget
+            views must be looked for.  By default, they are looked for in the
+            same module.
+        cached_functions_module (list): The Python path to the module where the
+            cached functions must be looked for.  By default, they are looked
+            for in the same module.
     """
 
     name = None
     position = None
     parameters = []
+    views_module = None
+    cached_functions_module = None
 
     def __init__(self):
         self._template_environment = None
@@ -120,20 +128,27 @@ class Widget(object):
             self._template_environment = env
         return self._template_environment
 
-    def _get_local_subclasses(self, parent_class):
+    def _get_local_subclasses(self, parent_class, module=None):
         """
         Returns the subclasses of the ``parent_class`` defined in this widget's
         Python module.
         """
+        if module is None:
+            module = self.__module__
         result = []
-        widget_module = import_module(self.__module__)
+        try:
+            widget_module = import_module(module, package=self.__module__)
+        except ImportError as e:
+            raise AttributeError(
+                "Could not find subclasses of %s in %s: %s"
+                % (parent_class, module, e))
         for objname in dir(widget_module):
             obj = getattr(widget_module, objname)
             if type(obj) != type(object):
                 continue  # we only look for classes
             if not issubclass(obj, parent_class):
                 continue  # we only want subclasses of the parent_class
-            if obj.__module__ != self.__module__:
+            if obj.__module__ != widget_module.__name__:
                 # we don't want locally imported classes (like the
                 # parent_class itself)
                 continue
@@ -148,7 +163,7 @@ class Widget(object):
         """
         return dict([
             (view.name, view) for view in
-            self._get_local_subclasses(WidgetView)
+            self._get_local_subclasses(WidgetView, self.views_module)
             ])
 
     def register_routes(self, app):
@@ -180,6 +195,7 @@ class Widget(object):
                 their class name.
         """
         result = {}
-        for fn_class in self._get_local_subclasses(CachedFunction):
+        for fn_class in self._get_local_subclasses(
+                CachedFunction, self.cached_functions_module):
             result[fn_class.__name__] = fn_class
         return result

From 4baacce8411c88d3fba3b4237770c907e177b02b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 10 2017 09:06:54 +0000
Subject: [PATCH 743/1001] Implement fixes from jcline's review


---

diff --git a/hubs/default_config.py b/hubs/default_config.py
index be038ad..b600b29 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -35,26 +35,26 @@ SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'  # /hubs/widgets/bad
 
 
 WIDGETS = [
-    'hubs.widgets.dummy.Dummy',
-    'hubs.widgets.stats.Stats',
-    'hubs.widgets.rules.Rules',
-    'hubs.widgets.sticky.Sticky',
-    'hubs.widgets.about.About',
-    'hubs.widgets.badges.Badges',
-    'hubs.widgets.library.Library',
-    'hubs.widgets.linechart.Linechart',
-    'hubs.widgets.fedmsgstats.FedmsgStats',
-    'hubs.widgets.feed.Feed',
-    'hubs.widgets.subscriptions.Subscriptions',
-    'hubs.widgets.meetings.Meetings',
-    'hubs.widgets.pagure_pr.PagurePRs',
-    'hubs.widgets.github_pr.GitHubPRs',
-    'hubs.widgets.pagureissues.PagureIssues',
-    'hubs.widgets.githubissues.GitHubIssues',
-    'hubs.widgets.bugzilla.Bugzilla',
-    'hubs.widgets.fhosted.FedoraHosted',
-    'hubs.widgets.memberships.Memberships',
-    'hubs.widgets.contact.Contact',
-    'hubs.widgets.workflow.pendingacls.PendingACLs',
-    'hubs.widgets.workflow.updates2stable.Updates2Stable',
+    'hubs.widgets.dummy:Dummy',
+    'hubs.widgets.stats:Stats',
+    'hubs.widgets.rules:Rules',
+    'hubs.widgets.sticky:Sticky',
+    'hubs.widgets.about:About',
+    'hubs.widgets.badges:Badges',
+    'hubs.widgets.library:Library',
+    'hubs.widgets.linechart:Linechart',
+    'hubs.widgets.fedmsgstats:FedmsgStats',
+    'hubs.widgets.feed:Feed',
+    'hubs.widgets.subscriptions:Subscriptions',
+    'hubs.widgets.meetings:Meetings',
+    'hubs.widgets.pagure_pr:PagurePRs',
+    'hubs.widgets.github_pr:GitHubPRs',
+    'hubs.widgets.pagureissues:PagureIssues',
+    'hubs.widgets.githubissues:GitHubIssues',
+    'hubs.widgets.bugzilla:Bugzilla',
+    'hubs.widgets.fhosted:FedoraHosted',
+    'hubs.widgets.memberships:Memberships',
+    'hubs.widgets.contact:Contact',
+    'hubs.widgets.workflow.pendingacls:PendingACLs',
+    'hubs.widgets.workflow.updates2stable:Updates2Stable',
     ]
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 1ec88bc..76f17b0 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -33,10 +33,12 @@ A widget view is a class which inherits from the
 :py:class:`hubs.widgets.view.WidgetView` class.  A widget can have one or more
 of them.
 
-Widget views can make use of templates following the Jinja2 engine syntax.  The
-templates are looked for in the widget's ``templates`` subdirectrory first, and
-then in the generic ``hubs/widgets/templates/`` directory.  They can make use
-of any Jinja2 feature, including inheritance, macros, etc.
+Widget views can make use of templates following the `Jinja2`_ engine syntax.
+The templates are looked for in the widget's ``templates`` subdirectrory first,
+and then in the generic ``hubs/widgets/templates/`` directory.  They can make
+use of any Jinja2 feature, including inheritance, macros, etc.
+
+.. _Jinja2: http://jinja.pocoo.org/docs/
 
 If you want to add filters to youre widget's Jinja2 environment, you can do so
 by overriding the widget's
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 3d27813..ac50fd3 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -46,7 +46,7 @@ class Widget(object):
     """
     The main widget class, you must subclass it to create a widget.
 
-    Args:
+    Arguments:
         name (str): The widget name. It will not be displayed in the UI, but
             will appear in some URLs, so be careful to only use simple,
             URL-compatible characters.
diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index c8a56e8..9067410 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -50,15 +50,13 @@ class CachedFunction(object):
     takes the bus message as only argument, and returns ``True`` if the cache
     should be rebuild, ``False`` otherwise.
 
-    To call the function, instanciate the class and execute it. You may also
+    To call the function, instantiate the class and execute it. You may also
     call the :py:meth:`.get_data` method.
 
     Args:
         instance (hubs.models.Widget): The widget instance.
     """
 
-    # invalidate_filter = {}
-
     def __init__(self, instance):
         self.instance = instance
 
@@ -81,28 +79,12 @@ class CachedFunction(object):
 
     def get_data(self):
         key = self.get_cache_key()
-        # log.debug("Accessing cache key %s", key)
+        log.debug("Accessing cache key %s", key)
         return cache.get_or_create(
-            key, lambda: self.execute())
+            key, self.execute)
 
     __call__ = get_data
 
-    # def _get_topic(self, message):
-    #     return message['topic']
-
-    # def _get_category(self, message):
-    #     return message['topic'].split('.')[3]
-
-    # def pass_filter(self, message):
-    #     topic_filter = self.invalidate_filter.get("topic")
-    #     if topic_filter and self._get_topic(message) not in topic_filter:
-    #         return False
-    #     category_filter = self.invalidate_filter.get("category")
-    #     if category_filter and \
-    #             self._get_category(message) not in category_filter:
-    #         return False
-    #     return True
-
     def should_invalidate(self, message):
         """
         Tell the cache invalidator if the received message should invalidate
@@ -114,8 +96,6 @@ class CachedFunction(object):
         Returns:
             bool: If ``True``, the cache will be rebuilt.
         """
-        # if not self._pass_filter(message):
-        #     return False
         return True
 
     def is_cached(self):
diff --git a/hubs/widgets/registry.py b/hubs/widgets/registry.py
index ad4d494..fe32607 100644
--- a/hubs/widgets/registry.py
+++ b/hubs/widgets/registry.py
@@ -14,6 +14,9 @@ class WidgetRegistry(UserDict):
     It behaves like a dictionary where widget names are keys and widget class
     instances are values.  There are additional methods to register widgets and
     widget-specific routes.
+
+    Widgets are registered using their class path in the following format:
+    `python.path.to.module:TheWidgetClass`.
     """
 
     def register_list(self, widget_list):
@@ -33,9 +36,10 @@ class WidgetRegistry(UserDict):
 
         Args:
             widget_path (str): Python path to the subclass of
-                :py:class:`hubs.widgets.base.Widget`.
+                :py:class:`hubs.widgets.base.Widget`. The format is
+                `python.path.to.module:TheWidgetClass`.
         """
-        mod_path, _, cls_name = widget_path.rpartition('.')
+        mod_path, cls_name = widget_path.split(':', 1)
         mod = import_module(mod_path)
         try:
             widget_class = getattr(mod, cls_name)

From 5e3de90c7d948bb82e4651e9d5b73a63472fa9e9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 10 2017 10:27:24 +0000
Subject: [PATCH 744/1001] Make CachedFunction.should_invalidate() abstract


---

diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index 9067410..990dce6 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -88,7 +88,8 @@ class CachedFunction(object):
     def should_invalidate(self, message):
         """
         Tell the cache invalidator if the received message should invalidate
-        this function's cache.
+        this function's cache.  This function must be implemented by
+        subclasses.
 
         Args:
             message (dict): The recieved bus message.
@@ -96,7 +97,7 @@ class CachedFunction(object):
         Returns:
             bool: If ``True``, the cache will be rebuilt.
         """
-        return True
+        raise NotImplementedError
 
     def is_cached(self):
         """

From d6eb8815e9c4e7d6e60a924113b13095c5ccbe7e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 10 2017 13:56:13 +0000
Subject: [PATCH 745/1001] Fix the help text in the widgets config template


---

diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index 80d4a8d..cb3f04d 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -27,12 +27,10 @@
               <input id="{{ param.name }}" class="form-control" type="text"
                 value="{{ param.default if param.default else '' }}"
                 name="{{ param.name }}" />
-            </fieldset>
-            {% if param.help %}
-              <div>
+              {% if param.help %}
                 <small class="text-muted">{{ param.help }}</small>
-              </div>
-            {% endif %}
+              {% endif %}
+            </fieldset>
           {% else %}
             <p>Nothing to configure</p>
           {% endfor %}
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index 5b6241c..928ea91 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -14,12 +14,10 @@
           <input id="{{ param.name }}" class="form-control" type="text"
               value="{{ widget.config.get(param.name, param.default if param.default else '') }}"
               name="{{ param.name }}" />
+          {% if param.help %}
+          <small class="text-muted">{{ param.help }}</small>
+          {% endif %}
         </fieldset>
-        {% if param.help %}
-          <div>
-            <small class="text-muted">{{ param.help }}</small>
-          </div>
-        {% endif %}
       {% else %}
         <p>Nothing to configure</p>
       {% endfor %}

From 71893f00e2afa9a2b8c3c2e2b417effabfa8a97e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 10 2017 15:10:50 +0000
Subject: [PATCH 746/1001] Sort the widget registry by name


The order in the configuration will be the order in which widgets will
be proposed for addition in a hub.

---

diff --git a/hubs/default_config.py b/hubs/default_config.py
index b600b29..1c50405 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -35,26 +35,26 @@ SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'  # /hubs/widgets/bad
 
 
 WIDGETS = [
-    'hubs.widgets.dummy:Dummy',
-    'hubs.widgets.stats:Stats',
-    'hubs.widgets.rules:Rules',
-    'hubs.widgets.sticky:Sticky',
     'hubs.widgets.about:About',
     'hubs.widgets.badges:Badges',
+    'hubs.widgets.bugzilla:Bugzilla',
+    'hubs.widgets.contact:Contact',
+    'hubs.widgets.dummy:Dummy',
     'hubs.widgets.library:Library',
     'hubs.widgets.linechart:Linechart',
     'hubs.widgets.fedmsgstats:FedmsgStats',
     'hubs.widgets.feed:Feed',
-    'hubs.widgets.subscriptions:Subscriptions',
-    'hubs.widgets.meetings:Meetings',
-    'hubs.widgets.pagure_pr:PagurePRs',
+    'hubs.widgets.fhosted:FedoraHosted',
     'hubs.widgets.github_pr:GitHubPRs',
-    'hubs.widgets.pagureissues:PagureIssues',
     'hubs.widgets.githubissues:GitHubIssues',
-    'hubs.widgets.bugzilla:Bugzilla',
-    'hubs.widgets.fhosted:FedoraHosted',
+    'hubs.widgets.meetings:Meetings',
     'hubs.widgets.memberships:Memberships',
-    'hubs.widgets.contact:Contact',
+    'hubs.widgets.pagure_pr:PagurePRs',
+    'hubs.widgets.pagureissues:PagureIssues',
+    'hubs.widgets.rules:Rules',
+    'hubs.widgets.stats:Stats',
+    'hubs.widgets.sticky:Sticky',
+    'hubs.widgets.subscriptions:Subscriptions',
     'hubs.widgets.workflow.pendingacls:PendingACLs',
     'hubs.widgets.workflow.updates2stable:Updates2Stable',
     ]
diff --git a/hubs/widgets/registry.py b/hubs/widgets/registry.py
index fe32607..f6e772b 100644
--- a/hubs/widgets/registry.py
+++ b/hubs/widgets/registry.py
@@ -1,19 +1,17 @@
 from __future__ import unicode_literals
 
-import six
-
+from collections import OrderedDict
 from importlib import import_module
-from six.moves import UserDict
 from hubs.widgets.base import Widget
 
 
-class WidgetRegistry(UserDict):
+class WidgetRegistry(OrderedDict):
     """
     The widget registry.
 
-    It behaves like a dictionary where widget names are keys and widget class
-    instances are values.  There are additional methods to register widgets and
-    widget-specific routes.
+    It behaves like an ordered dictionary where widget names are keys and
+    widget class instances are values.  There are additional methods to
+    register widgets and widget-specific routes.
 
     Widgets are registered using their class path in the following format:
     `python.path.to.module:TheWidgetClass`.
@@ -61,7 +59,7 @@ class WidgetRegistry(UserDict):
         except AttributeError as e:
             raise AttributeError(
                 "Error registering %s: %s" % (widget_path, e))
-        self.data[widget.name] = widget
+        self[widget.name] = widget
 
     def register_routes(self, app):
         """
@@ -76,8 +74,3 @@ class WidgetRegistry(UserDict):
         """
         for widget in self.values():
             widget.register_routes(app)
-
-    # IterableUserDict is in Python2 but not exported by six.
-    if six.PY2:
-        def __iter__(self):
-            return iter(self.data)

From 4a9f6c215fb3fefc360ac0fc5d196e2064a4a3c4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 13 2017 11:23:17 +0000
Subject: [PATCH 747/1001] Use the validators's return value for the widget conf


The validators were returning a converted value (for example, to
integer) but that value was ignored and the widgets had to do the
conversion again themselves when they wanted to use that value.

This changeset make use of the validators to convert to and from the
string that was passed to the config form.

---

diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index cb3f04d..38f0467 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -25,7 +25,7 @@
             <fieldset class="form-group ">
               <strong>{{ param.label | capitalize }}</strong>
               <input id="{{ param.name }}" class="form-control" type="text"
-                value="{{ param.default if param.default else '' }}"
+                value="{{ param.validator.to_string(param.default) }}"
                 name="{{ param.name }}" />
               {% if param.help %}
                 <small class="text-muted">{{ param.help }}</small>
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index 928ea91..10c18d8 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -12,7 +12,7 @@
         <fieldset class="form-group ">
           <strong>{{ param.label | capitalize }}</strong>
           <input id="{{ param.name }}" class="form-control" type="text"
-              value="{{ widget.config.get(param.name, param.default if param.default else '') }}"
+              value="{{ param.validator.to_string(widget.config.get(param.name, param.default)) }}"
               name="{{ param.name }}" />
           {% if param.help %}
           <small class="text-muted">{{ param.help }}</small>
diff --git a/hubs/validators.py b/hubs/validators.py
index e065629..b59ca25 100644
--- a/hubs/validators.py
+++ b/hubs/validators.py
@@ -6,56 +6,101 @@ import hubs.models
 import requests
 
 
-def required(session, value):
-    if bool(value):
+class Validator(object):
+
+    @classmethod
+    def from_string(cls, value):
+        if value is None:
+            return ""
         return value
 
+    @classmethod
+    def to_string(cls, value):
+        return value
 
-def text(session, value):
-    return kitchen.text.converters.to_unicode(value)
 
+class Required(Validator):
 
-def integer(session, value):
-    return int(value)
+    @classmethod
+    def from_string(cls, value):
+        if not bool(value):
+            raise ValueError("the parameter is required")
+        return value
 
 
-def link(session, value):
-    # TODO -- verify that this is actually a link
-    return value
+class Text(Validator):
 
+    @classmethod
+    def from_string(cls, value):
+        return kitchen.text.converters.to_unicode(value)
 
-def username(session, value):
-    if hubs.models.User.by_username(value) is not None:
-        return value
-    raise ValueError('Invalid username')
 
+class Integer(Validator):
 
-def github_organization(session, value):
-    # TODO -- implement this.
-    return value
+    @classmethod
+    def from_string(cls, value):
+        return int(value)
 
-def github_repo(session, value):
-    # TODO -- implement this.
-    return value
 
+class Link(Validator):
 
-def fmn_context(session, value):
-    # TODO get this from the fedmsg config.
-    if value in [
-        'irc', 'email', 'android', 'desktop', 'hubs',]:
+    @classmethod
+    def from_string(cls, value):
+        # TODO -- verify that this is actually a link
         return value
-    raise ValueError('Invalid FMN context')
 
 
-def pagure_repo(session, value):
-    response = requests.get("https://pagure.io/%s" % value, timeout=5)
-    if response.status_code == 200:
+class Username(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        if hubs.models.User.by_username(value) is not None:
+            return value
+        raise ValueError('Invalid username')
+
+
+class GithubOrganization(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO -- implement this.
         return value
-    raise ValueError('Invalid pagure repo')
 
 
-def fedorahosted_project(session, value):
-    response = requests.get("https://fedorahosted.org/%s" % value, timeout=5)
-    if response.status_code == 200:
+class GithubRepo(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO -- implement this.
         return value
-    raise ValueError('Invalid fedorahosted project')
+
+
+class FMNContext(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO get this from the fedmsg config.
+        if value in [
+            'irc', 'email', 'android', 'desktop', 'hubs',]:
+            return value
+        raise ValueError('Invalid FMN context')
+
+
+class PagureRepo(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        response = requests.get("https://pagure.io/%s" % value, timeout=5)
+        if response.status_code == 200:
+            return value
+        raise ValueError('Invalid pagure repo')
+
+
+class FedorahostedProject(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        response = requests.get("https://fedorahosted.org/%s" % value, timeout=5)
+        if response.status_code == 200:
+            return value
+        raise ValueError('Invalid fedorahosted project')
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 6641711..7b03d57 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -212,7 +212,7 @@ def hub_add_widget_post(name):
             error = True
             break
         try:
-            param.validator(flask.g.db, val)
+            val = param.validator.from_string(val)
             config[param.name] = val
         except Exception as err:
             flask.flash('Invalid data provided, error: %s' % err, 'error')
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 192c44d..adc857a 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -48,7 +48,7 @@ def widget_edit_post(hub, idx):
             error = True
             break
         try:
-            val = param.validator(flask.g.db, val)
+            val = param.validator.from_string(val)
             config[param.name] = val
         except Exception as err:
             flask.flash('Invalid data provided, error: %s' % err, 'error')
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index bdb7e7b..5fe313c 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -13,7 +13,7 @@ class About(Widget):
         name="text",
         label="Text",
         default="I am a Fedora user, and this is my about",
-        validator=validators.text,
+        validator=validators.Text,
         help="Text about a user.",
         )]
 
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index 79315e1..1c102cb 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -16,7 +16,7 @@ class Badges(Widget):
         name="username",
         label="Username",
         default=None,
-        validator=validators.username,
+        validator=validators.Username,
         help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index c63fa3c..5717e24 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -19,7 +19,7 @@ class Bugzilla(Widget):
         name="username",
         label="Username",
         default=None,
-        validator=validators.username,
+        validator=validators.Username,
         help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/dummy/__init__.py b/hubs/widgets/dummy/__init__.py
index ca4bac8..daa0600 100644
--- a/hubs/widgets/dummy/__init__.py
+++ b/hubs/widgets/dummy/__init__.py
@@ -12,7 +12,7 @@ class Dummy(Widget):
         name="text",
         label="Text",
         default="Lorem ipsum dolor...",
-        validator=validators.text,
+        validator=validators.Text,
         help="Some dummy text to display.",
         )]
 
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 142548f..4887af8 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -21,7 +21,7 @@ class FedmsgStats(Widget):
         name="username",
         label="Username",
         default=None,
-        validator=validators.username,
+        validator=validators.Username,
         help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index b1f8299..9180637 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -17,13 +17,13 @@ class Feed(Widget):
             "name": "username",
             "label": "Username",
             "default": None,
-            "validator": validators.username,
+            "validator": validators.Username,
             "help": "A FAS username.",
         }, {
             "name": "message_limit",
             "label": "Message limit",
             "default": 20,
-            "validator": validators.integer,
+            "validator": validators.Integer,
             "help": "Max number of feed messages to display.",
         }]
 
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
index 8f60efa..49a7955 100644
--- a/hubs/widgets/fhosted/__init__.py
+++ b/hubs/widgets/fhosted/__init__.py
@@ -16,13 +16,13 @@ class FedoraHosted(Widget):
             name="project",
             label="Project",
             default=None,
-            validator=validators.fedorahosted_project,
+            validator=validators.FedorahostedProject,
             help="Name of the trac instance on fedorahosted.org.",
         ), dict(
             name="n_tickets",
             label="Number of tickets",
             default=4,
-            validator=validators.integer,
+            validator=validators.Integer,
             help="The number of tickets to display.",
         )]
 
@@ -48,7 +48,7 @@ class GetTickets(CachedFunction):
     Queries Fedorahosted via xmlrpc for tickets. '''
 
     def execute(self):
-        n_tickets = int(self.instance.config["n_tickets"])
+        n_tickets = self.instance.config["n_tickets"]
         url = 'https://fedorahosted.org/%s/rpc' \
             % self.instance.config["project"]
         filters = 'status=accepted&status=assigned&status=new&status=reopened'\
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 6961d4a..d794c24 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -22,13 +22,13 @@ class GitHubPRs(Widget):
             name="organization",
             label="Organization",
             default=None,
-            validator=validators.github_organization,
+            validator=validators.GithubOrganization,
             help="Github Organization or username",
         ), dict(
             name="display_number",
             label="Number of tickets",
             default=6,
-            validator=validators.integer,
+            validator=validators.Integer,
             help="How many pull requests to display at max.",
         )]
 
@@ -42,10 +42,9 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
         org = instance.config["organization"]
-        display_number = int(instance.config["display_number"])
         context = dict(
             organization=org,
-            display_number=display_number,
+            display_number=instance.config["display_number"],
             title="Github: Pull Requests",
         )
         context.update(get_prs())
@@ -56,7 +55,7 @@ class GetPRs(CachedFunction):
 
     def execute(self):
         org = self.instance.config["organization"]
-        display_number = int(self.instance.config["display_number"])
+        display_number = self.instance.config["display_number"]
         log.info("Getting GH prs for %r, (%r)" % (org, display_number))
         token = fedmsg_config.get('github.oauth_token')
         pulls = []
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index e29faa7..7172dbb 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -16,19 +16,19 @@ class GitHubIssues(Widget):
             name="org",
             label="Username",
             default=None,
-            validator=validators.github_organization,
+            validator=validators.GithubOrganization,
             help="Github Organization or username",
         ), dict(
             name="repo",
             label="Repository",
             default=None,
-            validator=validators.github_repo,
+            validator=validators.GithubRepo,
             help="Github repository",
         ), dict(
             name="display_number",
             label="Number of tickets",
             default=10,
-            validator=validators.integer,
+            validator=validators.Integer,
             help="The number of tickets to display.",
         )]
 
@@ -44,7 +44,7 @@ class BaseView(WidgetView):
         return dict(
             org=instance.config["org"],
             repo=instance.config["repo"],
-            display_number=int(instance.config["display_number"]),
+            display_number=instance.config["display_number"],
             title="Github: Newest Open Tickets",
             all_issues=get_issues(),
         )
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index 351ec4f..bab0ab4 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -13,7 +13,7 @@ class Library(Widget):
         name="urls",
         label="URLs",
         default=None,
-        validator=validators.text,
+        validator=validators.Text,
         help="A comma separated list of URLs to add to the library. "
              "External links must include the whole link "
              "(starting with http...)."
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index dfae632..0da1cb7 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -12,7 +12,7 @@ class Linechart(Widget):
         name="username",
         label="Username",
         default=None,
-        validator=validators.username,
+        validator=validators.Username,
         help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index 01908ce..fbe712a 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -20,13 +20,13 @@ class Meetings(Widget):
             name="calendar",
             label="Calendar",
             default=None,
-            validator=validators.required,
+            validator=validators.Required,
             help="A fedocal calendar.",
         ), dict(
             name="n_meetings",
             label="Number of meetings",
             default=4,
-            validator=validators.integer,
+            validator=validators.Integer,
             help="The number of meetings to display.",
         )]
 
@@ -56,7 +56,7 @@ class GetMeetings(CachedFunction):
 
     def execute(self):
         calendar = self.instance.config["calendar"]
-        n_meetings = int(self.instance.config.get("n_meetings", 4))
+        n_meetings = self.instance.config.get("n_meetings", 4)
         base = ('https://apps.fedoraproject.org/calendar/api/meetings/'
                 '?calendar=%s')
         url = base % calendar
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 518d12d..1ace710 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -18,7 +18,7 @@ class PagurePRs(Widget):
             name="repo",
             label="Repository",
             default=None,
-            validator=validators.pagure_repo,
+            validator=validators.PagureRepo,
             help="Pagure repo name.",
         )]
 
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index 356d59f..f8df811 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -18,7 +18,7 @@ class PagureIssues(Widget):
             name="repo",
             label="Repository",
             default=None,
-            validator=validators.pagure_repo,
+            validator=validators.PagureRepo,
             help="Pagure repo name",
         )]
 
diff --git a/hubs/widgets/rules/__init__.py b/hubs/widgets/rules/__init__.py
index 498e3a8..5c207a3 100644
--- a/hubs/widgets/rules/__init__.py
+++ b/hubs/widgets/rules/__init__.py
@@ -19,25 +19,25 @@ class Rules(Widget):
             name="link",
             label="Link",
             default=None,
-            validator=validators.link,
+            validator=validators.Link,
             help="Link to the community rules and guidelines.",
         ), dict(
             name="schedule_text",
             label="Schedule text",
             default=None,
-            validator=validators.text,
+            validator=validators.Text,
             help="Some text about when meetings are.",
         ), dict(
             name="schedule_link",
             label="Schedule link",
             default=None,
-            validator=validators.link,
+            validator=validators.Link,
             help="Link to a schedule for IRC meetings, etc.",
         ), dict(
             name="minutes_link",
             label="Minutes link",
             default=None,
-            validator=validators.link,
+            validator=validators.Link,
             help="Link to meeting menutes from past meetings.",
         )]
 
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index 3f038ba..3fcccfc 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -13,7 +13,7 @@ class Sticky(Widget):
             name="text",
             label="Text",
             default="Lorem ipsum dolor...",
-            validator=validators.text,
+            validator=validators.Text,
             help="Some dummy text to display.",
         )]
 
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
index 1641191..b427ad5 100644
--- a/hubs/widgets/subscriptions/__init__.py
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -22,7 +22,7 @@ class Subscriptions(Widget):
             name="username",
             label="Username",
             default=None,
-            validator=validators.username,
+            validator=validators.Username,
             help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 07fd52b..1c926d5 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -17,7 +17,7 @@ class PendingACLs(Widget):
             name="username",
             label="Username",
             default=None,
-            validator=validators.username,
+            validator=validators.Username,
             help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 79fac1f..92a56dd 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -21,7 +21,7 @@ class Updates2Stable(Widget):
             name="username",
             label="Username",
             default=None,
-            validator=validators.username,
+            validator=validators.Username,
             help="A FAS username.",
         )]
 

From 2b79f4b88ee5fb8c018c8baa3fea0db9bf893ed3 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 13 2017 11:29:37 +0000
Subject: [PATCH 748/1001] Move validators to the widgets module


Validators are actually only used by widgets, it makes more sense to
have them with the other widget-related modules.

---

diff --git a/hubs/validators.py b/hubs/validators.py
deleted file mode 100644
index b59ca25..0000000
--- a/hubs/validators.py
+++ /dev/null
@@ -1,106 +0,0 @@
-from __future__ import unicode_literals
-
-import kitchen.text.converters
-
-import hubs.models
-import requests
-
-
-class Validator(object):
-
-    @classmethod
-    def from_string(cls, value):
-        if value is None:
-            return ""
-        return value
-
-    @classmethod
-    def to_string(cls, value):
-        return value
-
-
-class Required(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        if not bool(value):
-            raise ValueError("the parameter is required")
-        return value
-
-
-class Text(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        return kitchen.text.converters.to_unicode(value)
-
-
-class Integer(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        return int(value)
-
-
-class Link(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        # TODO -- verify that this is actually a link
-        return value
-
-
-class Username(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        if hubs.models.User.by_username(value) is not None:
-            return value
-        raise ValueError('Invalid username')
-
-
-class GithubOrganization(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        # TODO -- implement this.
-        return value
-
-
-class GithubRepo(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        # TODO -- implement this.
-        return value
-
-
-class FMNContext(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        # TODO get this from the fedmsg config.
-        if value in [
-            'irc', 'email', 'android', 'desktop', 'hubs',]:
-            return value
-        raise ValueError('Invalid FMN context')
-
-
-class PagureRepo(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        response = requests.get("https://pagure.io/%s" % value, timeout=5)
-        if response.status_code == 200:
-            return value
-        raise ValueError('Invalid pagure repo')
-
-
-class FedorahostedProject(Validator):
-
-    @classmethod
-    def from_string(cls, value):
-        response = requests.get("https://fedorahosted.org/%s" % value, timeout=5)
-        if response.status_code == 200:
-            return value
-        raise ValueError('Invalid fedorahosted project')
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index 5fe313c..1de5e0c 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -1,9 +1,8 @@
 from __future__ import unicode_literals
 
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
-from hubs import validators
-
 
 class About(Widget):
 
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index 1c102cb..c609776 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import operator
 import requests
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 5717e24..99d02f1 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import requests
 import pkgwat.api
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/dummy/__init__.py b/hubs/widgets/dummy/__init__.py
index daa0600..463e359 100644
--- a/hubs/widgets/dummy/__init__.py
+++ b/hubs/widgets/dummy/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 4887af8..0b68bcb 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -5,8 +5,8 @@ import fedmsg.config
 import fedmsg.meta
 import requests
 
-from hubs import validators
 from hubs.utils import commas
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index 9180637..30b39eb 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -1,7 +1,7 @@
 from __future__ import unicode_literals
 
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 import logging
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
index 49a7955..7b83881 100644
--- a/hubs/widgets/fhosted/__init__.py
+++ b/hubs/widgets/fhosted/__init__.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 from six.moves.xmlrpc_client import ServerProxy
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index d794c24..1d41502 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import logging
 import hubs.utils
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index 7172dbb..39d5aa0 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index bab0ab4..e1d4511 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -1,7 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
-from hubs.widgets import clean_input
+from hubs.widgets import clean_input, validators
 from hubs.widgets.base import Widget, WidgetView
 
 
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index 0da1cb7..e9765ca 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index fbe712a..568a04b 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -5,8 +5,8 @@ import collections
 import datetime
 import requests
 
-from hubs import validators
 from hubs import utils
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 1ace710..48c57a0 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index f8df811..7aa36c7 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/rules/__init__.py b/hubs/widgets/rules/__init__.py
index 5c207a3..1ec9c09 100644
--- a/hubs/widgets/rules/__init__.py
+++ b/hubs/widgets/rules/__init__.py
@@ -2,8 +2,8 @@ from __future__ import unicode_literals
 
 from collections import OrderedDict as ordereddict
 
-from hubs import validators
 from hubs.utils import username2avatar
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index 3fcccfc..baec759 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
index b427ad5..d6dd928 100644
--- a/hubs/widgets/subscriptions/__init__.py
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import flask
 import hubs.models
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
new file mode 100644
index 0000000..b59ca25
--- /dev/null
+++ b/hubs/widgets/validators.py
@@ -0,0 +1,106 @@
+from __future__ import unicode_literals
+
+import kitchen.text.converters
+
+import hubs.models
+import requests
+
+
+class Validator(object):
+
+    @classmethod
+    def from_string(cls, value):
+        if value is None:
+            return ""
+        return value
+
+    @classmethod
+    def to_string(cls, value):
+        return value
+
+
+class Required(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        if not bool(value):
+            raise ValueError("the parameter is required")
+        return value
+
+
+class Text(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        return kitchen.text.converters.to_unicode(value)
+
+
+class Integer(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        return int(value)
+
+
+class Link(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO -- verify that this is actually a link
+        return value
+
+
+class Username(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        if hubs.models.User.by_username(value) is not None:
+            return value
+        raise ValueError('Invalid username')
+
+
+class GithubOrganization(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO -- implement this.
+        return value
+
+
+class GithubRepo(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO -- implement this.
+        return value
+
+
+class FMNContext(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO get this from the fedmsg config.
+        if value in [
+            'irc', 'email', 'android', 'desktop', 'hubs',]:
+            return value
+        raise ValueError('Invalid FMN context')
+
+
+class PagureRepo(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        response = requests.get("https://pagure.io/%s" % value, timeout=5)
+        if response.status_code == 200:
+            return value
+        raise ValueError('Invalid pagure repo')
+
+
+class FedorahostedProject(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        response = requests.get("https://fedorahosted.org/%s" % value, timeout=5)
+        if response.status_code == 200:
+            return value
+        raise ValueError('Invalid fedorahosted project')
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 1c926d5..40c19ec 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -2,8 +2,8 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs import validators
 from hubs.utils import username2avatar
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 92a56dd..4f6f462 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 

From c0f410dff0895b4880782e06efd60109699b2697 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 13 2017 11:59:22 +0000
Subject: [PATCH 749/1001] Redirect when adding a widget succeeds


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 9415590..61c909e 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -246,9 +246,10 @@ class HubsAPITest(hubs.tests.APPTest):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             data = {'widget_name': 'about'}
-            result = self.app.post('/ralph/add', data=data,
-                                   follow_redirects=False)
-            self.assertEqual(result.status_code, 200)
+            result = self.app.post('/ralph/add', data=data)
+            self.assertEqual(result.status_code, 302)
+            self.assertEqual(urlparse(result.location).path, "/ralph/edit")
+            result = self.app.get('/ralph/edit')
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
             self.assertIn(expected_str, result.get_data(as_text=True))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
@@ -260,7 +261,9 @@ class HubsAPITest(hubs.tests.APPTest):
             data = {'widget_name': 'about', 'text': 'text of widget'}
             result = self.app.post('/ralph/add', data=data,
                                    follow_redirects=False)
-            self.assertEqual(result.status_code, 200)
+            self.assertEqual(result.status_code, 302)
+            self.assertEqual(urlparse(result.location).path, "/ralph/edit")
+            result = self.app.get('/ralph/edit')
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
             self.assertIn(expected_str, result.get_data(as_text=True))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 7b03d57..3da39d3 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -231,6 +231,4 @@ def hub_add_widget_post(name):
                 'Could not save the configuration to the database '
                 'if the error persists, please warn an admin',
                 'error')
-
-    return flask.render_template(
-        'hubs.html', hub=hub, edit=True)
+    return flask.redirect(flask.url_for('hub_edit', name=hub.name))

From 6f743e24fe96e9f47fb008f1fccb4edf5ad2b7dd Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 13 2017 11:59:22 +0000
Subject: [PATCH 750/1001] Make the add and save buttons more visible


---

diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index 38f0467..cf9d686 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -40,7 +40,7 @@
         <button type="button" class="btn btn-default" data-dismiss="modal">
           Close
         </button>
-        <button type="submit" class="btn btn-default" id="submit_btn">
+        <button type="submit" class="btn btn-primary" id="submit_btn">
           Add
         </button>
       </div>
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index 10c18d8..de4613f 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -27,7 +27,7 @@
           Close
         </button>
         {% if widget.module.get_parameters() %}
-        <button type="submit" class="btn btn-default">
+        <button type="submit" class="btn btn-primary">
           Save
         </button>
         {% endif %}

From ace2200a6c1cd1b7c08ad16569a2333f8462bc1c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 14 2017 10:42:52 +0000
Subject: [PATCH 751/1001] Add and fix documentation


---

diff --git a/docs/api.rst b/docs/api.rst
index 8cecb30..449b292 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -27,6 +27,13 @@ Widget class
    :members:
    :show-inheritance:
 
+Widget parameter validators
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. automodule:: hubs.widgets.validators
+   :members:
+   :show-inheritance:
+
 Widget view
 ^^^^^^^^^^^
 
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index ac50fd3..38da840 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -23,13 +23,19 @@ class WidgetParameter(object):
     :py:class:`WidgetParameter` objects returned by the widget's
     :py:meth:`~Widget.get_parameters` method.
 
+    The value of the parameter is stored in the database as the value returned
+    by the validator's :py:meth:`from_string` method.  It can thus be a string,
+    an integer, a list, a dict, or any JSON-serializable value.
+
     Attributes:
         name (str): The name of the parameter.
         label (str): A humanized name of the parameter, which will be shown in
             the UI.
         default: The default value if this parameter is not set.
-        validator (function): A validation function that will be called when
-            a user sets the parameter value.
+        validator (hubs.widgets.validators.Validator): A validator subclass
+            that will be used to convert the parameter value to and from
+            string, raising an exception if it is invalid. This attribute
+            points to the validator subclass, not an instance of the class.
         help (str): A help text that will be shown in the UI.
     """
 
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index b59ca25..18b86fd 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -7,19 +7,42 @@ import requests
 
 
 class Validator(object):
+    """Convert widget parameters to and from string, and validate their value.
+
+    Validators are used to convert
+    :py:class:`~hubs.widgets.base.WidgetParameter` values to and from string.
+    They will raise an exception if the value is invalid.
+
+    A validator is a subclass of the :py:class:`Validator` class and implements
+    two class methods: :py:meth:`from_string` and :py:meth:`to_string`.
+    """
 
     @classmethod
     def from_string(cls, value):
+        """Convert the value from a string to a JSON-serializable value.
+
+        The result of this function will be stored in the database for widget
+        parameters.
+        
+        Raises:
+            ValueError: The value is invalid. 
+        """
         if value is None:
             return ""
         return value
 
     @classmethod
     def to_string(cls, value):
+        """Convert the value to a string.
+
+        The result of this function will be used in the widget configuration
+        form fields.
+        """
         return value
 
 
 class Required(Validator):
+    """Raises an error if the value is ``False``-like."""
 
     @classmethod
     def from_string(cls, value):
@@ -29,6 +52,7 @@ class Required(Validator):
 
 
 class Text(Validator):
+    """Raises an error if the value can't be converted to unicode."""
 
     @classmethod
     def from_string(cls, value):
@@ -36,6 +60,7 @@ class Text(Validator):
 
 
 class Integer(Validator):
+    """Raises an error if the value can't be converted to an integer."""
 
     @classmethod
     def from_string(cls, value):
@@ -43,6 +68,7 @@ class Integer(Validator):
 
 
 class Link(Validator):
+    """Raises an error if the value doesn't look like a link."""
 
     @classmethod
     def from_string(cls, value):
@@ -51,6 +77,13 @@ class Link(Validator):
 
 
 class Username(Validator):
+    """Raises an error if the value isn't an existing username.
+
+    There must be a corresponding :py:class:`~hubs.models.User` record.
+
+    This validator does not return the User instance because it is not
+    JSON-serializable, it returns the username unchanged.
+    """
 
     @classmethod
     def from_string(cls, value):
@@ -60,6 +93,7 @@ class Username(Validator):
 
 
 class GithubOrganization(Validator):
+    """Fails if the Github organization name does not exist."""
 
     @classmethod
     def from_string(cls, value):
@@ -68,6 +102,7 @@ class GithubOrganization(Validator):
 
 
 class GithubRepo(Validator):
+    """Fails if the Github repository name does not exist."""
 
     @classmethod
     def from_string(cls, value):
@@ -76,6 +111,7 @@ class GithubRepo(Validator):
 
 
 class FMNContext(Validator):
+    """Fails if the value is not a valid FMN context name."""
 
     @classmethod
     def from_string(cls, value):
@@ -87,6 +123,7 @@ class FMNContext(Validator):
 
 
 class PagureRepo(Validator):
+    """Fails if the Pagure repository name does not exist."""
 
     @classmethod
     def from_string(cls, value):
@@ -97,6 +134,7 @@ class PagureRepo(Validator):
 
 
 class FedorahostedProject(Validator):
+    """Fails if the FedoraHosted project name does not exist."""
 
     @classmethod
     def from_string(cls, value):

From a906b5984bcecdbc3725bf0d801545d3eba6f14a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 14 2017 10:42:52 +0000
Subject: [PATCH 752/1001] Add two more assertions in the tests


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 61c909e..2a53ba5 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -250,6 +250,7 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 302)
             self.assertEqual(urlparse(result.location).path, "/ralph/edit")
             result = self.app.get('/ralph/edit')
+            self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
             self.assertIn(expected_str, result.get_data(as_text=True))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
@@ -264,6 +265,7 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 302)
             self.assertEqual(urlparse(result.location).path, "/ralph/edit")
             result = self.app.get('/ralph/edit')
+            self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
             self.assertIn(expected_str, result.get_data(as_text=True))
             expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'

From 6e4ad75b5699756d886f0a1dd93dd4c47d2da2cc Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 14 2017 11:01:53 +0000
Subject: [PATCH 753/1001] Add unittests for validators


---

diff --git a/hubs/tests/test_widget_validators.py b/hubs/tests/test_widget_validators.py
new file mode 100644
index 0000000..567c60f
--- /dev/null
+++ b/hubs/tests/test_widget_validators.py
@@ -0,0 +1,69 @@
+from __future__ import unicode_literals
+
+import six
+import unittest
+
+from hubs.widgets import validators
+
+#from mock import Mock
+from hubs.tests import APPTest
+from hubs.models import User
+
+
+class ValidatorsTest(APPTest):
+
+    def test_required(self):
+        self.assertRaises(ValueError, validators.Required.from_string, "")
+
+    def test_text(self):
+        self.assertEqual(validators.Text.from_string("\xe9"), "\xe9")
+
+    def test_integer(self):
+        self.assertEqual(validators.Integer.from_string("1"), 1)
+        self.assertRaises(ValueError, validators.Integer.from_string, "text")
+
+    @unittest.skip("Not implemented yet")
+    def test_link(self):
+        value = '<a href="somewhere">dummy</a>'
+        self.assertEqual(validators.Link.from_string(value), value)
+        self.assertRaises(ValueError, validators.Link.from_string, "text")
+
+    def test_username(self):
+        self.assertEqual(validators.Username.from_string("ralph"), "ralph")
+        self.assertRaises(ValueError, validators.Username.from_string, "nobody")
+
+    @unittest.skip("Not implemented yet")
+    def test_github_organization(self):
+        self.assertEqual(
+            validators.GithubOrganization.from_string("fedora-infra"),
+            "fedora-infra")
+        self.assertRaises(
+            ValueError,
+            validators.GithubOrganization.from_string,
+            "something-that-does-not-exist")
+
+    @unittest.skip("Not implemented yet")
+    def test_github_repo(self):
+        self.assertEqual(
+            validators.GithubRepo.from_string("fedmsg"), "fedmsg")
+        self.assertRaises(ValueError, validators.GithubRepo.from_string,
+                          "something-that-does-not-exist")
+
+    def test_fmncontext(self):
+        self.assertEqual(validators.FMNContext.from_string("email"), "email")
+        self.assertRaises(
+            ValueError, validators.FMNContext.from_string, "dummy")
+
+    def test_pagure_repo(self):
+        self.assertEqual(
+            validators.PagureRepo.from_string("fedora-hubs"), "fedora-hubs")
+        self.assertRaises(ValueError, validators.PagureRepo.from_string,
+                          "something-that-does-not-exist")
+
+    def test_fedorahosted_project(self):
+        self.assertEqual(
+            validators.FedorahostedProject.from_string("about-fedora"),
+            "about-fedora")
+        self.assertRaises(
+            ValueError, validators.FedorahostedProject.from_string,
+            "something-that-does-not-exist")
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_fedorahosted_project b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_fedorahosted_project
new file mode 100644
index 0000000..3d8315c
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_fedorahosted_project
@@ -0,0 +1,186 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://fedorahosted.org/about-fedora/
+  response:
+    body: {string: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"\
+        http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\"\
+        >\n  \n  \n\n  \n\n\n  <head>\n    <title>\n      about-fedora\n    </title>\n\
+        \    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"\
+        \ />\n    <!--[if IE]><script type=\"text/javascript\">\n      if (/^#__msie303:/.test(window.location.hash))\n\
+        \        window.location.replace(window.location.hash.replace(/^#__msie303:/,\
+        \ '#'));\n    </script><![endif]-->\n        <link rel=\"search\" href=\"\
+        /about-fedora/search\" />\n        <link rel=\"help\" href=\"/about-fedora/wiki/TracGuide\"\
+        \ />\n        <link rel=\"alternate\" href=\"/about-fedora/wiki/WikiStart?format=txt\"\
+        \ type=\"text/x-trac-wiki\" title=\"Plain Text\" />\n        <link rel=\"\
+        start\" href=\"/about-fedora/wiki\" />\n        <link rel=\"stylesheet\" href=\"\
+        /about-fedora/chrome/common/css/trac.css\" type=\"text/css\" /><link rel=\"\
+        stylesheet\" href=\"/about-fedora/chrome/common/css/wiki.css\" type=\"text/css\"\
+        \ /><link rel=\"stylesheet\" href=\"/about-fedora/chrome/tracvatar/tracvatar.css\"\
+        \ type=\"text/css\" />\n        <link rel=\"shortcut icon\" href=\"/about-fedora/chrome/common/trac.ico\"\
+        \ type=\"image/x-icon\" />\n        <link rel=\"icon\" href=\"/about-fedora/chrome/common/trac.ico\"\
+        \ type=\"image/x-icon\" />\n      <link type=\"application/opensearchdescription+xml\"\
+        \ rel=\"search\" href=\"/about-fedora/search/opensearch\" title=\"Search about-fedora\"\
+        \ />\n    <script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/jquery.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/babel.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/messages/en_US.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/trac.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/search.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/folding.js\"\
+        ></script>\n    <!--[if lt IE 7]>\n    <script type=\"text/javascript\" src=\"\
+        /about-fedora/chrome/common/js/ie_pre7_hacks.js\"></script>\n    <![endif]-->\n\
+        \    <script type=\"text/javascript\">\n      jQuery(document).ready(function($)\
+        \ {\n        $(\"#content\").find(\"h1,h2,h3,h4,h5,h6\").addAnchor(_(\"Link\
+        \ to this section\"));\n        $(\"#content\").find(\".wikianchor\").each(function()\
+        \ {\n          $(this).addAnchor(babel.format(_(\"Link to #%(id)s\"), {id:\
+        \ $(this).attr('id')}));\n        });\n        $(\".foldable\").enableFolding(true,\
+        \ true);\n      });\n    </script>\n  </head>\n  <body>\n    <div id=\"banner\"\
+        >\n      <div id=\"header\">\n        <a id=\"logo\" href=\"https://fedorahosted.org/\"\
+        ><img src=\"https://fedorahosted.org/web/static/images/fedora-hosted-banner.png\"\
+        \ alt=\"Fedora Hosted\" /></a>\n      </div>\n      <form id=\"search\" action=\"\
+        /about-fedora/search\" method=\"get\">\n        <div>\n          <label for=\"\
+        proj-search\">Search:</label>\n          <input type=\"text\" id=\"proj-search\"\
+        \ name=\"q\" size=\"18\" value=\"\" />\n          <input type=\"submit\" value=\"\
+        Search\" />\n        </div>\n      </form>\n      <div id=\"metanav\" class=\"\
+        nav\">\n    <ul>\n      <li class=\"first\"><a href=\"/about-fedora/openidlogin\"\
+        >OpenID Login</a></li><li><a href=\"https://admin.fedoraproject.org/accounts/user/new\"\
+        >Fedora Account Sign Up</a></li><li><a href=\"/about-fedora/prefs\">Preferences</a></li><li><a\
+        \ href=\"/about-fedora/wiki/TracGuide\">Help/Guide</a></li><li><a href=\"\
+        /about-fedora/about\">About Trac</a></li><li class=\"last\"><a href=\"http://git.fedorahosted.org/cgit/about-fedora.git\"\
+        >CGit</a></li>\n    </ul>\n  </div>\n    </div>\n    <div id=\"mainnav\" class=\"\
+        nav\">\n    <ul>\n      <li class=\"first active\"><a href=\"/about-fedora/wiki\"\
+        >Wiki</a></li><li><a href=\"/about-fedora/timeline\">Timeline</a></li><li><a\
+        \ href=\"/about-fedora/roadmap\">Roadmap</a></li><li><a href=\"/about-fedora/browser\"\
+        >Browse Source</a></li><li><a href=\"/about-fedora/report\">View Tickets</a></li><li\
+        \ class=\"last\"><a href=\"/about-fedora/search\">Search</a></li>\n    </ul>\n\
+        \  </div>\n    <div id=\"main\">\n      <div id=\"pagepath\" class=\"noprint\"\
+        >\n  <a class=\"pathentry first\" title=\"View WikiStart\" href=\"/about-fedora/wiki\"\
+        >wiki:</a><a class=\"pathentry\" href=\"/about-fedora/wiki/WikiStart\" title=\"\
+        View WikiStart\">WikiStart</a>\n</div>\n      <div id=\"ctxtnav\" class=\"\
+        nav\">\n        <h2>Context Navigation</h2>\n          <ul>\n            \
+        \  <li class=\"first\"><a href=\"/about-fedora/wiki/WikiStart\">Start Page</a></li><li><a\
+        \ href=\"/about-fedora/wiki/TitleIndex\">Index</a></li><li class=\"last\"\
+        ><a href=\"/about-fedora/wiki/WikiStart?action=history\">History</a></li>\n\
+        \          </ul>\n        <hr />\n      </div>\n    <div id=\"content\" class=\"\
+        wiki\">\n      <div class=\"wikipage searchable\">\n        \n          \n\
+        \          <div class=\"trac-modifiedby\">\n            <span><a href=\"/about-fedora/wiki/WikiStart?action=diff&amp;version=5\"\
+        \ title=\"Version 5 by quaid: adding step to self-intro\">Last modified</a>\
+        \ <a class=\"timeline\" href=\"/about-fedora/timeline?from=2009-02-09T03%3A57%3A48Z&amp;precision=second\"\
+        \ title=\"2009-02-09T03:57:48Z in Timeline\">8 years</a> ago</span>\n    \
+        \        <span class=\"trac-print\">Last modified on 02/09/09 03:57:48</span>\n\
+        \          </div>\n          <div id=\"wikipage\"><h1 id=\"Whatisthissite\"\
+        >What is this site?</h1>\n<p>\nThis is the source project for About Fedora.\
+        \  It includes a <tt>git</tt> repo and a database for tracking how we develop\
+        \ the source toolchain.  \n</p>\n<p>\nIt's all part of the <a class=\"ext-link\"\
+        \ href=\"https://fedoraproject.org/wiki/Overview\"><span class=\"icon\">\u200B\
+        </span>Fedora Project</a>.  This site, in particular, is run by the <a class=\"\
+        ext-link\" href=\"https://fedoraproject.org/wiki/DocsProject\"><span class=\"\
+        icon\">\u200B</span>Fedora Documentation team</a>.\n</p>\n<p>\nIf you want\
+        \ to look at what we've created, use the \"Browse Source\" link above and\
+        \ to the right.\n</p>\n<h1 id=\"AboutFedorahassomethingmissingorwrong.\">About\
+        \ Fedora has something missing or wrong.</h1>\n<p>\nIf you need to tell us\
+        \ that something is wrong in About Fedora, visit <a class=\"ext-link\" href=\"\
+        https://bugzilla.redhat.com/bugzilla\"><span class=\"icon\">\u200B</span>Bugzilla</a>.\
+        \  File a bug against the product \"Fedora Documentation,\" component \"about-fedora\"\
+        .\n</p>\n<h1 id=\"Iwanttohelpwiththecontent.\">I want to help with the content.</h1>\n\
+        <p>\nIf you want to help update the content of About Fedora, first <a class=\"\
+        ext-link\" href=\"http://fedoraproject.org/wiki/DocsProject/Join#Things_you_need_to_do\"\
+        ><span class=\"icon\">\u200B</span>introduce yourself to the Docs Project</a>.\
+        \  When you've done that, <a class=\"ext-link\" href=\"https://admin.fedoraproject.org/accounts/group/view/gitabout-fedora\"\
+        ><span class=\"icon\">\u200B</span>join our project group</a>.  Then visit\
+        \ <a class=\"ext-link\" href=\"https://fedoraproject.org/wiki/Docs_Project_work_using_git\"\
+        ><span class=\"icon\">\u200B</span>this page on the Fedora Project wiki</a>\
+        \ to find out how to get started using <tt>git</tt>.  These instructions should\
+        \ work for most people with access to this repository:\n</p>\n<pre class=\"\
+        wiki\">cd ~/projects/\ngit clone ssh://&lt;username&gt;@git.fedorahosted.org/git/docs/about-fedora.git\n\
+        git clone git://git.fedorahosted.org/git/fedora-doc-utils docs-common\n</pre><p>\n\
+        If you don't have access to this repo, use <tt>git://</tt> instead of <tt>ssh://</tt>\
+        \ above.\n</p>\n<h1 id=\"Iwanttotranslatethecontenttomylanguage.\">I want\
+        \ to translate the content to my language.</h1>\n<p>\nCheck the <a class=\"\
+        ext-link\" href=\"http://translate.fedoraproject.org/module/docs-about-fedora\"\
+        ><span class=\"icon\">\u200B</span>statistics page</a> to get details about\
+        \ your language and join the <a class=\"ext-link\" href=\"https://fedoraproject.org/wiki/L10N\"\
+        ><span class=\"icon\">\u200B</span>Fedora Translation team</a> if your language\
+        \ is not available.\n</p>\n<h1 id=\"Imconfused.Whatisthissitefor\">I'm confused.\
+        \ What is this site for?</h1>\n<p>\nIf you have questions, come visit the\
+        \ Docs Project on IRC.  IRC is a way to communicate in real time with other\
+        \ Fedora Project members.  You can find more information <a class=\"ext-link\"\
+        \ href=\"https://fedoraproject.org/wiki/Communicate/IRC\"><span class=\"icon\"\
+        >\u200B</span>here</a>.\n</p>\n</div>\n        \n        \n      </div>\n\
+        \      \n\n    </div>\n    <div id=\"altlinks\">\n      <h3>Download in other\
+        \ formats:</h3>\n      <ul>\n        <li class=\"last first\">\n         \
+        \ <a rel=\"nofollow\" href=\"/about-fedora/wiki/WikiStart?format=txt\">Plain\
+        \ Text</a>\n        </li>\n      </ul>\n    </div>\n    </div>\n    <div id=\"\
+        footer\" lang=\"en\" xml:lang=\"en\"><hr />\n      <a id=\"tracpowered\" href=\"\
+        http://trac.edgewall.org/\"><img src=\"/about-fedora/chrome/common/trac_logo_mini.png\"\
+        \ height=\"30\" width=\"107\" alt=\"Trac Powered\" /></a>\n      <p class=\"\
+        left\">Powered by <a href=\"/about-fedora/about\"><strong>Trac 0.12.5</strong></a><br\
+        \ />\n        By <a href=\"http://www.edgewall.org/\">Edgewall Software</a>.<p\
+        \ class=\"left\">Libravatar support by <a href=\"https://bitbucket.org/zzzeek/tracvatar\"\
+        >Tracvatar 1.9</a></p></p>\n      <p class=\"right\">Visit the Trac open source\
+        \ project at<br /><a href=\"http://trac.edgewall.org/\">http://trac.edgewall.org/</a></p>\n\
+        \    </div>\n    <!-- Tack on our fedmenu stuff for this trac. -->\n    <script\
+        \ src=\"https://apps.fedoraproject.org/fedmenu/js/jquery-1.11.2.min.js\"></script>\n\
+        \    <script src=\"https://apps.fedoraproject.org/fedmenu/js/fedmenu.js\"\
+        ></script>\n    <script>\n      fedmenu({\n        'url': 'https://apps.fedoraproject.org/js/data.js',\n\
+        \        'mimeType': 'application/javascript',\n        'position': 'bottom-right',\n\
+        \      });\n    </script>\n  </body>\n</html>"}
+    headers:
+      cache-control: [must-revalidate]
+      connection: [Keep-Alive]
+      content-length: ['9437']
+      content-type: [text/html;charset=utf-8]
+      date: ['Tue, 14 Feb 2017 10:57:38 GMT']
+      expires: ['Fri, 01 Jan 1999 00:00:00 GMT']
+      keep-alive: ['timeout=5, max=500']
+      server: [Apache/2.2.15 (Red Hat)]
+      set-cookie: [trac_form_token=8344c426dbc2cc320d5e431d; Path=/about-fedora, 'trac_session=808a3fc5547b36ddaca5f057;
+          expires=Mon, 15-May-2017 10:57:39 GMT; Path=/about-fedora']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: Ok}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://fedorahosted.org/something-that-does-not-exist/
+  response:
+    body: {string: !!python/unicode '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+
+        <html><head>
+
+        <title>302 Found</title>
+
+        </head><body>
+
+        <h1>Found</h1>
+
+        <p>The document has moved <a href="https://fedorahosted.org/web/410">here</a>.</p>
+
+        <hr>
+
+        <address>Apache/2.2.15 (Red Hat) Server at fedorahosted.org Port 443</address>
+
+        </body></html>
+
+        '}
+    headers:
+      connection: [Keep-Alive]
+      content-length: ['300']
+      content-type: [text/html; charset=iso-8859-1]
+      date: ['Tue, 14 Feb 2017 10:57:40 GMT']
+      keep-alive: ['timeout=5, max=500']
+      location: ['https://fedorahosted.org/web/410']
+      server: [Apache/2.2.15 (Red Hat)]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 302, message: Found}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_pagure_repo b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_pagure_repo
new file mode 100644
index 0000000..03a168e
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_pagure_repo
@@ -0,0 +1,351 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://pagure.io/fedora-hubs
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - fedora-hubs - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"\
+        image/vnd.microsoft.icon\"\n        href=\"/static/favicon.ico\"/>\n    <link\
+        \ href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/fedora-hubs git https://pagure.io/fedora-hubs.git\"\
+        >\n  </head>\n  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"\
+        masthead\">\n      <div class=\"container\">\n        <div class=\"row\">\n\
+        \          <div class=\"col-sm-3\">\n            <a href=\"/\">\n        \
+        \      <img height=40px src=\"/static/pagure-logo.png\"\n                alt=\"\
+        pagure Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n  \
+        \        <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav\
+        \ class=\"navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\"\
+        >\n        <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n   \
+        \           <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link\
+        \ btn btn-primary\" href=\"/login/?next=https://pagure.io/fedora-hubs\">Log\
+        \ In</a>\n              </li>\n        </ul>\n      </div>\n    </nav>\n\n\
+        \            </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n        <a href=\"/fedora-hubs\">\nfedora-hubs</a>\n\
+        \        </h2>\n        <div class=\"projectinfo m-t-1 m-b-1\">\nFedora Hubs\
+        \ &nbsp;| &nbsp;<a class=\"inline\" href=\"https://hubs-dev.fedorainfracloud.org/\"\
+        >https://hubs-dev.fedorainfracloud.org/</a>        </div>\n\n    </header>\n\
+        \    <ul class=\"nav nav-tabs nav-small\">\n      <li class=\"nav-item\">\n\
+        \        <a class=\"nav-link active\" href=\"/fedora-hubs\">\n           \
+        \ <span class=\"oi hidden-md-up\" data-glyph=\"home\"></span>\n          \
+        \  <span class=\"hidden-sm-down\">Overview</span>\n        </a>\n      </li>\n\
+        \        <li class=\"nav-item\" >\n          <a  class=\"nav-link\" href=\"\
+        /docs/fedora-hubs/\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        book\"></span>\n              <span class=\"hidden-sm-down\">Docs</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \    <a class=\"nav-link\" href=\"/fedora-hubs/commits/develop\">\n      \
+        \        <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n   \
+        \           </span><span class=\"hidden-sm-down\">Commits</span>\n       \
+        \     </a>\n        </li>\n\n        <li class=\"nav-item\">\n          <a\
+        \ class=\"nav-link\" href=\"/fedora-hubs/tree/develop\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /fedora-hubs/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/fedora-hubs/issues\">\n             \
+        \   <span class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n     \
+        \           <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n         \
+        \       <span class=\"label label-default label-pill hidden-sm-down\">\n \
+        \                 111\n                </span>\n            </a>\n       \
+        \ </li>\n\n        <li class=\"nav-item\">\n          <a class=\"nav-link\"\
+        \ href=\"/fedora-hubs/pull-requests\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"task\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Pull Requests&nbsp;</span>\n              <span class=\"label label-default\
+        \ label-pill hidden-sm-down\">\n                3\n              </span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \    <a class=\"nav-link\" href=\"/fedora-hubs/forks\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"fork\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Forks&nbsp;</span>\n              <span class=\"\
+        hidden-sm-down label label-default label-pill\">\n                50\n   \
+        \           </span>\n            </a>\n        </li>\n\n\n    </ul>\n  </div>\n\
+        </div>\n\n<div class=\"container p-t-3\">\n  <div class=\"row\">\n       \
+        \ <div class=\"col-md-8\">\n            <section class=\"readme\">\n     \
+        \           <div class=\"document\">\n<h1>Fedora Hubs</h1>\n<p>Fedora Hubs\
+        \ will provide a communication and collaboration center for Fedora\ncontributors\
+        \ of all types. The idea is that contributors will be able to visit\nHubs\
+        \ to check on their involvements across Fedora, discover new places that they\n\
+        can contribute, and more.</p>\n<p>Hubs is currently under development, and\
+        \ you can see the progress on the\nDevelopment instance here: <a href=\"https://hubs-dev.fedorainfracloud.org/\"\
+        >https://hubs-dev.fedorainfracloud.org/</a></p>\n<div class=\"section\">\n\
+        <h1>Get Involved</h1>\n<p>Visit our <a href=\"https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org\"\
+        >mailing list</a>\nand join us in the <code><span class=\"pre\">#fedora-hubs</span></code>\
+        \ IRC channel on irc.freenode.net. Meetings are held\nweekly in <code><span\
+        \ class=\"pre\">#fedora-hubs</span></code> at 14:00UTC and the minutes for\
+        \ every meeting are\n<a href=\"https://meetbot.fedoraproject.org/sresults/?group_id=fedora-hubs&amp;type=team\"\
+        >archived</a>.\nIn the meetings we review our statuses from the preceding\
+        \ week and do ticket triage, too.</p>\n<p>For a more detailed overview of\
+        \ what Fedora Hubs is, see the\n<a href=\"https://docs.pagure.org/fedora-hubs/overview.html\"\
+        >documentation</a>.</p>\n<p>To set up a development environment and start\
+        \ contributing, check out\nthe <a href=\"https://docs.pagure.org/fedora-hubs/dev-guide.html\"\
+        >development guide</a>.</p>\n</div>\n</div>\n\n            </section>\n  \
+        \      </div>\n      <div class=\"col-md-4\">\n        <div class=\"card\"\
+        >\n          <div class=\"card-block\">\n            <h5><strong>Owners</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/decause\">\n                  <img class=\"avatar circle\"\
+        \ src=\"https://seccdn.libravatar.org/avatar/2107fccec2d30c09bcc3f4141388b10aabf16b2a9664f16cdf7227295f28e89b?s=20&d=retro\"\
+        />\n                  Remy DeCausemaker (decause)  -  creator\n          \
+        \      </a>\n              </div>\n              <div>\n                <a\
+        \ href=\"/user/mrichard\">\n                  <img class=\"avatar circle\"\
+        \ src=\"https://seccdn.libravatar.org/avatar/d64b6dc2a878d19f600cb711e02d8547fc94589f8633452f84da1cb961d2b892?s=20&d=retro\"\
+        />\n                  Meghan Richardson (mrichard)\n                </a>\n\
+        \              </div>\n              <div>\n                <a href=\"/user/duffy\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/e4e83ac110d58771f0c0125651a1ab585e9f72715dc76bd4af54e0102e96f171?s=20&d=retro\"\
+        />\n                  M\xE1ir\xEDn Duffy (duffy)\n                </a>\n \
+        \             </div>\n              <div>\n                <a href=\"/user/lmacken\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/d433d26a9f50eb87d94b0473472202aa7cf7952700ae82fc5f9750adc0aad37e?s=20&d=retro\"\
+        />\n                  Luke Macken (lmacken)\n                </a>\n      \
+        \        </div>\n              <div>\n                <a href=\"/user/nyazdani\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/40c9ac361c6cf560171f6bfb99eef9c6849bf8156e2faa15b067e4c4d092246b?s=20&d=retro\"\
+        />\n                  Nathaniel Yazdani (nyazdani)\n                </a>\n\
+        \              </div>\n              <div>\n                <a href=\"/user/bee2502\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/0b4ce1166336c24dae92f4ece34d4b6a2c7218dd85088967e2f12c6e7b09d5ce?s=20&d=retro\"\
+        />\n                  Bhagyashree Padalkar (bee2502)\n                </a>\n\
+        \              </div>\n              <div>\n                <a href=\"/user/devyani7\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/cbfbb8a5d78cfc3a595d65dd26074e5b5799bb2b585311dcc0dd18230e2f5649?s=20&d=retro\"\
+        />\n                  Devyani Kota (devyani7)\n                </a>\n    \
+        \          </div>\n              <div>\n                <a href=\"/user/dhrish20\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/156c08ff565412423d5bdb7a1d46e9ea0a3f0cf8f9b51b4f6cd0c6da56a72da9?s=20&d=retro\"\
+        />\n                  Dhriti Shikhar (dhrish20)\n                </a>\n  \
+        \            </div>\n              <div>\n                <a href=\"/user/jflory7\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/bc8fd31501030af99c3f31ca8a1f4ee205a1d0035b487d09a497a194b8777c70?s=20&d=retro\"\
+        />\n                  Justin W. Flory (jflory7)\n                </a>\n  \
+        \            </div>\n              <div>\n                <a href=\"/user/pingou\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \             </div>\n              <div>\n                <a href=\"/user/ryanlerch\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                  Ryan Lerch (ryanlerch)\n                </a>\n     \
+        \         </div>\n              <div>\n                <a href=\"/user/skrzepto\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/55ffbcbe7ef5ef02b58c2082b79aa1dc23794da806e19333d4dbb994c4093b3d?s=20&d=retro\"\
+        />\n                  Szymon Mucha (skrzepto)\n                </a>\n    \
+        \          </div>\n              <div>\n                <a href=\"/user/sayanchowdhury\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/4771836b6b430740e853f097f7121782109560ec6099e72ffc923ed17f9f88bd?s=20&d=retro\"\
+        />\n                  Sayan Chowdhury (sayanchowdhury)\n                </a>\n\
+        \              </div>\n              <div>\n                <a href=\"/user/bkorren\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/632177fa944babf9d34ebdc5fb82a4b2ea3ca7c1da7ef9657ebd6f3f48e3c094?s=20&d=retro\"\
+        />\n                  bkorren (bkorren)\n                </a>\n          \
+        \    </div>\n              <div>\n                <a href=\"/user/atelic\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/72118562545c3cad698b51ca813fd0149dd19f63d7dceec161d447b834b03a45?s=20&d=retro\"\
+        />\n                  Eric Barbour (atelic)\n                </a>\n      \
+        \        </div>\n              <div>\n                <a href=\"/user/wispfox\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b5f1b3792dc945fba3b616b489aa688b91577f186283427b4f08dd9dcbe53db7?s=20&d=retro\"\
+        />\n                  Suzanne Hillman (wispfox)\n                </a>\n  \
+        \            </div>\n              <div>\n                <a href=\"/user/jcline\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                  Jeremy Cline (jcline)\n                </a>\n      \
+        \        </div>\n              <div>\n                <a href=\"/user/abompard\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/224e9ad3084cb9f442f423b7910701377be7a018408a4f8b22a09d94c89af46f?s=20&d=retro\"\
+        />\n                  Aurelien Bompard (abompard)\n                </a>\n\
+        \              </div>\n            </div>\n            <h5><strong>Branches</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div id=\"branch-develop\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-10\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"\n                    title=\"Default branch\"></span>\n         \
+        \         <strong title=\"Currently viewing branch develop\" data-toggle=\"\
+        tooltip\">develop</strong>\n                </div>\n                <div class=\"\
+        branch_del col-md-2\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        star\"\n                    title=\"Default branch\"></span>\n           \
+        \     </div>\n              </div>\n\n              <div id=\"branch-feature__bugzilla-links\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/fedora-hubs/branch/feature/bugzilla-links\"\
+        \n                    title=\"feature/bugzilla-links\" data-toggle=\"tooltip\"\
+        >feature/bugzilla-links\n                  </a>\n\n                </div>\n\
+        \                <div class=\"branch_del col-md-4\">\n                </div>\n\
+        \              </div>\n              <div id=\"branch-fix_fedmsgstats\" class=\"\
+        repoinfo-branchlistitem row\">\n                <div class=\"branch_name col-md-8\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n\
+        \                  <a class=\"\" href=\"/fedora-hubs/branch/fix_fedmsgstats\"\
+        \n                    title=\"fix_fedmsgstats\" data-toggle=\"tooltip\">fix_fedmsgstats\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-jenkins\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/fedora-hubs/branch/jenkins\"\n           \
+        \         title=\"jenkins\" data-toggle=\"tooltip\">jenkins\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-master\" class=\"repoinfo-branchlistitem row\">\n    \
+        \            <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/fedora-hubs/branch/master\"\n                   \
+        \ title=\"master\" data-toggle=\"tooltip\">master\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-unittest\" class=\"repoinfo-branchlistitem row\">\n               \
+        \ <div class=\"branch_name col-md-8\">\n                  <span class=\"oi\
+        \ text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/fedora-hubs/branch/unittest\"\n                    title=\"unittest\"\
+        \ data-toggle=\"tooltip\">unittest\n                  </a>\n\n           \
+        \     </div>\n                <div class=\"branch_del col-md-4\">\n      \
+        \          </div>\n              </div>\n            </div>\n            <h5><strong>Source\
+        \ GIT URLs</strong>                  <span class=\"pull-xs-right\"><a data-toggle=\"\
+        collapse\" href=\"#moregiturls\"\n                  aria-expanded=\"false\"\
+        \ aria-controls=\"moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n\
+        \            <div>\n              <div class=\"form-group\">\n           \
+        \     <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">SSH</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"ssh://git@pagure.io/fedora-hubs.git\" readonly>\n\
+        \                </div>\n              </div>\n              <div class=\"\
+        form-group\">\n                <div class=\"input-group input-group-sm\">\n\
+        \                  <div class=\"input-group-addon\">GIT</div>\n          \
+        \        <input class=\"form-control\" type=\"text\" value=\"https://pagure.io/fedora-hubs.git\"\
+        \ readonly>\n                </div>\n              </div>\n              <div\
+        \ class=\"collapse\" id=\"moregiturls\">\n                  <h5><strong>Docs\
+        \ GIT URLs</strong></h5>\n                  <div class=\"form-group\">\n \
+        \                   <div class=\"input-group input-group-sm\">\n         \
+        \             <div class=\"input-group-addon\">GIT</div>\n               \
+        \       <input class=\"form-control\" type=\"text\" value=\"https://pagure.io/docs/fedora-hubs.git\"\
+        \ readonly>\n                    </div>\n                  </div>\n      \
+        \        </div>\n            </div>\n          </div>\n          <div class=\"\
+        repo_date\" title=\"2015-06-04 17:27:48.074785\">\n              created 2\
+        \ years ago\n          </div>\n        </div>\n\n          <div class=\"card\"\
+        >\n            <div class=\"card-header\">\n              <strong>Recent Commits\
+        \ in\n                <span class=\"pr-toplabel\">\n                  <span\
+        \ class=\"oi\" data-glyph=\"random\"></span>\n                  develop\n\
+        \                </span>\n              </strong>\n            </div>\n  \
+        \          <div class=\"card-block p-a-0\">\n              <div class=\"list-group\
+        \ list-group-flush\">\n                  <a href=\"/fedora-hubs/c/71893f00e2afa9a2b8c3c2e2b417effabfa8a97e\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Feb 10 2017 15:10:50\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/224e9ad3084cb9f442f423b7910701377be7a018408a4f8b22a09d94c89af46f?s=20&d=retro\"\
+        />\n                          Aur\xE9lien Bompard\n                      \
+        \  </strong>\n                        commited 3 days ago\n              \
+        \        </small>\n                    </div>\n                    <div><small>\n\
+        \                      Sort the widget registry by name\n                \
+        \    </small></div>\n                  </a>\n                  <a href=\"\
+        /fedora-hubs/c/d6eb8815e9c4e7d6e60a924113b13095c5ccbe7e\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Feb 10 2017 13:56:13\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/224e9ad3084cb9f442f423b7910701377be7a018408a4f8b22a09d94c89af46f?s=20&d=retro\"\
+        />\n                          Aur\xE9lien Bompard\n                      \
+        \  </strong>\n                        commited 3 days ago\n              \
+        \        </small>\n                    </div>\n                    <div><small>\n\
+        \                      Fix the help text in the widgets config template\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/fedora-hubs/c/5e3de90c7d948bb82e4651e9d5b73a63472fa9e9\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Feb 10 2017 10:27:24\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/224e9ad3084cb9f442f423b7910701377be7a018408a4f8b22a09d94c89af46f?s=20&d=retro\"\
+        />\n                          Aur\xE9lien Bompard\n                      \
+        \  </strong>\n                        commited 4 days ago\n              \
+        \        </small>\n                    </div>\n                    <div><small>\n\
+        \                      Make CachedFunction.should_invalidate() abstract\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          2.12.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/jquery.min.js\">\n    </script>\n    <script type=\"text/javascript\"\
+        \n        src=\"/static/jquery-ui.min.js\">\n    </script>\n    <script type=\"\
+        text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n  $(\".watch-menu a\"\
+        ).click(function(){\n    var selectedValue = $(this).attr('id');\n    var\
+        \ action = $(\"#watch_project\").attr('action');\n      if (selectedValue\
+        \ != \"unwatch_button\") {\n        action = action.replace('/settings/0',\
+        \ '/settings/1');\n        $('#watch_project').attr('action', action);\n \
+        \     }\n      $('#watch_project').submit();\n\n  });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      connection: [Keep-Alive]
+      content-length: ['21185']
+      content-type: [text/html; charset=utf-8]
+      date: ['Tue, 14 Feb 2017 10:48:02 GMT']
+      keep-alive: ['timeout=5, max=100']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      set-cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiTTJSallqTmlaak16T1ROaE4yWTNOekZpWkdNeFptRTVZek13Wm1FM01ETTBaV1E0WlRFMU1BPT0ifX0.C4Rx4g.oLbGmDy2SdBOneLnLMwKWvCQ5WY;
+          Expires=Fri, 17-Mar-2017 10:48:02 GMT; Secure; HttpOnly; Path=/']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://pagure.io/something-that-does-not-exist
+  response:
+    body: {string: !!python/unicode "<!DOCTYPE html>\n<html lang='en'>\n<head>\n \
+        \   <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"\
+        />\n    <title>Page not found :'( - Pagure</title>\n    <link rel=\"shortcut\
+        \ icon\" type=\"image/vnd.microsoft.icon\"\n        href=\"/static/favicon.ico\"\
+        />\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n  </head>\n  <body id=\"\
+        error\">\n  <!-- start masthead -->\n    <div class=\"masthead\">\n      <div\
+        \ class=\"container\">\n        <div class=\"row\">\n          <div class=\"\
+        col-sm-3\">\n            <a href=\"/\">\n              <img height=40px src=\"\
+        /static/pagure-logo.png\"\n                alt=\"pagure Logo\" id=\"pagureLogo\"\
+        />\n            </a>\n          </div>\n          <div class=\"col-sm-9\"\
+        >\n            <div class=\"row\">\n\n  <nav class=\"navbar navbar-light p-t-0\
+        \ p-b-0\">\n      <div class=\"container\">\n        <ul class=\"nav navbar-nav\
+        \ nav-underline pull-xs-right\">\n              <li class=\"nav-item p-l-1\"\
+        >\n                <a class=\"nav-link btn btn-primary\" href=\"/login/?next=https://pagure.io/something-that-does-not-exist\"\
+        >Log In</a>\n              </li>\n        </ul>\n      </div>\n    </nav>\n\
+        \n            </div>\n          </div>\n        </div>\n      </div>\n   \
+        \ </div><!-- close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\
+        \n<div class=\"container p-t-3\">\n  <div class=\"row\">\n    <div class=\"\
+        col-md-8\">\n      <h2>Page not found (404)</h2>\n      <p>With the message:</p>\n\
+        \      <div class=\"card-block\">\n      <p>Project not found</p>\n      </div>\n\
+        \      <p>You have either entered a bad URL or the page has moved, removed,\
+        \ or otherwise rendered unavailable.<br/>\n      Please use the main navigation\
+        \ menu to get (re)started.</p>\n    </div>\n  </div>\n</div>\n    </div>\n\
+        \n    <div class=\"footer p-t-1 p-b-1\">\n        <div class=\"container\"\
+        >\n            <p class=\"text-muted credit\">\n         Copyright &copy;\
+        \ 2014-2017 Red Hat\n          <a href=\"https://pagure.io/pagure\">pagure</a>\
+        \ &mdash;\n          2.12.1 &mdash; <a href=\"https://docs.pagure.org/pagure/usage.html\"\
+        >Documentation</a>\n            </p>\n            <p><a href=\"/ssh_info\"\
+        >SSH Hostkey/Fingerprint</a></p>\n        </div>\n    </div>\n\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/jquery.min.js\">\n    </script>\n\
+        \    <script type=\"text/javascript\"\n        src=\"/static/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n\n</body>\n\
+        </html>"}
+    headers:
+      connection: [Keep-Alive]
+      content-length: ['3009']
+      content-type: [text/html; charset=utf-8]
+      date: ['Tue, 14 Feb 2017 10:48:03 GMT']
+      keep-alive: ['timeout=5, max=100']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      set-cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlfQ.C4Rx4w.okkFK2vKErtBTg2N2mPN4XPMTVc;
+          Expires=Fri, 17-Mar-2017 10:48:03 GMT; Secure; HttpOnly; Path=/']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 404, message: NOT FOUND}
+version: 1
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index 18b86fd..349fdb9 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -138,7 +138,8 @@ class FedorahostedProject(Validator):
 
     @classmethod
     def from_string(cls, value):
-        response = requests.get("https://fedorahosted.org/%s" % value, timeout=5)
+        response = requests.get("https://fedorahosted.org/%s/" % value,
+                                timeout=5, allow_redirects=False)
         if response.status_code == 200:
             return value
         raise ValueError('Invalid fedorahosted project')

From ad710b9fbc38751ba7cda10f1c6b93bc99d492e5 Mon Sep 17 00:00:00 2001
From: duffy <fedora@linuxgrrl.com>
Date: Feb 14 2017 19:48:52 +0000
Subject: [PATCH 754/1001] Update README.rst


de-emphasizing dev instance since it's not running right now. we had a fedora contributor ask about it in our channel.
---

diff --git a/README.rst b/README.rst
index 9ea968c..3e063f1 100644
--- a/README.rst
+++ b/README.rst
@@ -5,8 +5,8 @@ contributors of all types. The idea is that contributors will be able to visit
 Hubs to check on their involvements across Fedora, discover new places that they
 can contribute, and more.
 
-Hubs is currently under development, and you can see the progress on the
-Development instance here: https://hubs-dev.fedorainfracloud.org/
+Hubs is currently under development. (We had a development instance at 
+https://hubs-dev.fedorainfracloud.org/ but that isn't currently maintained.)
 
 Get Involved
 ------------

From 7a1d24830fa3dfbf2327553cf6b128798a6a752e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 16 2017 14:08:54 +0000
Subject: [PATCH 755/1001] Cleanup blank spaces


---

diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index 349fdb9..99290b3 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -23,9 +23,9 @@ class Validator(object):
 
         The result of this function will be stored in the database for widget
         parameters.
-        
+
         Raises:
-            ValueError: The value is invalid. 
+            ValueError: The value is invalid.
         """
         if value is None:
             return ""

From 7e5de7c42ac5aa506fa0a8eebda42e52af39c739 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 16 2017 14:08:54 +0000
Subject: [PATCH 756/1001] Provide a sensible default for the Username validator


---

diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index 99290b3..9c96320 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -1,8 +1,8 @@
 from __future__ import unicode_literals
 
-import kitchen.text.converters
-
+import flask
 import hubs.models
+import kitchen.text.converters
 import requests
 
 
@@ -91,6 +91,12 @@ class Username(Validator):
             return value
         raise ValueError('Invalid username')
 
+    @classmethod
+    def to_string(cls, value):
+        if value is None and flask.g.auth.logged_in:
+            return flask.g.auth.user.username
+        return value
+
 
 class GithubOrganization(Validator):
     """Fails if the Github organization name does not exist."""

From 0722d9442b5efb69820a2389b90d65a7eada1e54 Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Feb 21 2017 15:12:08 +0000
Subject: [PATCH 757/1001] Merge #324 `Improve the widget configuration validators`


---

diff --git a/docs/api.rst b/docs/api.rst
index 8cecb30..449b292 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -27,6 +27,13 @@ Widget class
    :members:
    :show-inheritance:
 
+Widget parameter validators
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. automodule:: hubs.widgets.validators
+   :members:
+   :show-inheritance:
+
 Widget view
 ^^^^^^^^^^^
 
diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index cb3f04d..cf9d686 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -25,7 +25,7 @@
             <fieldset class="form-group ">
               <strong>{{ param.label | capitalize }}</strong>
               <input id="{{ param.name }}" class="form-control" type="text"
-                value="{{ param.default if param.default else '' }}"
+                value="{{ param.validator.to_string(param.default) }}"
                 name="{{ param.name }}" />
               {% if param.help %}
                 <small class="text-muted">{{ param.help }}</small>
@@ -40,7 +40,7 @@
         <button type="button" class="btn btn-default" data-dismiss="modal">
           Close
         </button>
-        <button type="submit" class="btn btn-default" id="submit_btn">
+        <button type="submit" class="btn btn-primary" id="submit_btn">
           Add
         </button>
       </div>
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
index 928ea91..de4613f 100644
--- a/hubs/templates/edit.html
+++ b/hubs/templates/edit.html
@@ -12,7 +12,7 @@
         <fieldset class="form-group ">
           <strong>{{ param.label | capitalize }}</strong>
           <input id="{{ param.name }}" class="form-control" type="text"
-              value="{{ widget.config.get(param.name, param.default if param.default else '') }}"
+              value="{{ param.validator.to_string(widget.config.get(param.name, param.default)) }}"
               name="{{ param.name }}" />
           {% if param.help %}
           <small class="text-muted">{{ param.help }}</small>
@@ -27,7 +27,7 @@
           Close
         </button>
         {% if widget.module.get_parameters() %}
-        <button type="submit" class="btn btn-default">
+        <button type="submit" class="btn btn-primary">
           Save
         </button>
         {% endif %}
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 9415590..2a53ba5 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -246,8 +246,10 @@ class HubsAPITest(hubs.tests.APPTest):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             data = {'widget_name': 'about'}
-            result = self.app.post('/ralph/add', data=data,
-                                   follow_redirects=False)
+            result = self.app.post('/ralph/add', data=data)
+            self.assertEqual(result.status_code, 302)
+            self.assertEqual(urlparse(result.location).path, "/ralph/edit")
+            result = self.app.get('/ralph/edit')
             self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
             self.assertIn(expected_str, result.get_data(as_text=True))
@@ -260,6 +262,9 @@ class HubsAPITest(hubs.tests.APPTest):
             data = {'widget_name': 'about', 'text': 'text of widget'}
             result = self.app.post('/ralph/add', data=data,
                                    follow_redirects=False)
+            self.assertEqual(result.status_code, 302)
+            self.assertEqual(urlparse(result.location).path, "/ralph/edit")
+            result = self.app.get('/ralph/edit')
             self.assertEqual(result.status_code, 200)
             expected_str = '<h6 class="dropdown-header">Account Information</h6>'
             self.assertIn(expected_str, result.get_data(as_text=True))
diff --git a/hubs/tests/test_widget_validators.py b/hubs/tests/test_widget_validators.py
new file mode 100644
index 0000000..567c60f
--- /dev/null
+++ b/hubs/tests/test_widget_validators.py
@@ -0,0 +1,69 @@
+from __future__ import unicode_literals
+
+import six
+import unittest
+
+from hubs.widgets import validators
+
+#from mock import Mock
+from hubs.tests import APPTest
+from hubs.models import User
+
+
+class ValidatorsTest(APPTest):
+
+    def test_required(self):
+        self.assertRaises(ValueError, validators.Required.from_string, "")
+
+    def test_text(self):
+        self.assertEqual(validators.Text.from_string("\xe9"), "\xe9")
+
+    def test_integer(self):
+        self.assertEqual(validators.Integer.from_string("1"), 1)
+        self.assertRaises(ValueError, validators.Integer.from_string, "text")
+
+    @unittest.skip("Not implemented yet")
+    def test_link(self):
+        value = '<a href="somewhere">dummy</a>'
+        self.assertEqual(validators.Link.from_string(value), value)
+        self.assertRaises(ValueError, validators.Link.from_string, "text")
+
+    def test_username(self):
+        self.assertEqual(validators.Username.from_string("ralph"), "ralph")
+        self.assertRaises(ValueError, validators.Username.from_string, "nobody")
+
+    @unittest.skip("Not implemented yet")
+    def test_github_organization(self):
+        self.assertEqual(
+            validators.GithubOrganization.from_string("fedora-infra"),
+            "fedora-infra")
+        self.assertRaises(
+            ValueError,
+            validators.GithubOrganization.from_string,
+            "something-that-does-not-exist")
+
+    @unittest.skip("Not implemented yet")
+    def test_github_repo(self):
+        self.assertEqual(
+            validators.GithubRepo.from_string("fedmsg"), "fedmsg")
+        self.assertRaises(ValueError, validators.GithubRepo.from_string,
+                          "something-that-does-not-exist")
+
+    def test_fmncontext(self):
+        self.assertEqual(validators.FMNContext.from_string("email"), "email")
+        self.assertRaises(
+            ValueError, validators.FMNContext.from_string, "dummy")
+
+    def test_pagure_repo(self):
+        self.assertEqual(
+            validators.PagureRepo.from_string("fedora-hubs"), "fedora-hubs")
+        self.assertRaises(ValueError, validators.PagureRepo.from_string,
+                          "something-that-does-not-exist")
+
+    def test_fedorahosted_project(self):
+        self.assertEqual(
+            validators.FedorahostedProject.from_string("about-fedora"),
+            "about-fedora")
+        self.assertRaises(
+            ValueError, validators.FedorahostedProject.from_string,
+            "something-that-does-not-exist")
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_fedorahosted_project b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_fedorahosted_project
new file mode 100644
index 0000000..3d8315c
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_fedorahosted_project
@@ -0,0 +1,186 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://fedorahosted.org/about-fedora/
+  response:
+    body: {string: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"\
+        http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\"\
+        >\n  \n  \n\n  \n\n\n  <head>\n    <title>\n      about-fedora\n    </title>\n\
+        \    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"\
+        \ />\n    <!--[if IE]><script type=\"text/javascript\">\n      if (/^#__msie303:/.test(window.location.hash))\n\
+        \        window.location.replace(window.location.hash.replace(/^#__msie303:/,\
+        \ '#'));\n    </script><![endif]-->\n        <link rel=\"search\" href=\"\
+        /about-fedora/search\" />\n        <link rel=\"help\" href=\"/about-fedora/wiki/TracGuide\"\
+        \ />\n        <link rel=\"alternate\" href=\"/about-fedora/wiki/WikiStart?format=txt\"\
+        \ type=\"text/x-trac-wiki\" title=\"Plain Text\" />\n        <link rel=\"\
+        start\" href=\"/about-fedora/wiki\" />\n        <link rel=\"stylesheet\" href=\"\
+        /about-fedora/chrome/common/css/trac.css\" type=\"text/css\" /><link rel=\"\
+        stylesheet\" href=\"/about-fedora/chrome/common/css/wiki.css\" type=\"text/css\"\
+        \ /><link rel=\"stylesheet\" href=\"/about-fedora/chrome/tracvatar/tracvatar.css\"\
+        \ type=\"text/css\" />\n        <link rel=\"shortcut icon\" href=\"/about-fedora/chrome/common/trac.ico\"\
+        \ type=\"image/x-icon\" />\n        <link rel=\"icon\" href=\"/about-fedora/chrome/common/trac.ico\"\
+        \ type=\"image/x-icon\" />\n      <link type=\"application/opensearchdescription+xml\"\
+        \ rel=\"search\" href=\"/about-fedora/search/opensearch\" title=\"Search about-fedora\"\
+        \ />\n    <script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/jquery.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/babel.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/messages/en_US.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/trac.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/search.js\"\
+        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/folding.js\"\
+        ></script>\n    <!--[if lt IE 7]>\n    <script type=\"text/javascript\" src=\"\
+        /about-fedora/chrome/common/js/ie_pre7_hacks.js\"></script>\n    <![endif]-->\n\
+        \    <script type=\"text/javascript\">\n      jQuery(document).ready(function($)\
+        \ {\n        $(\"#content\").find(\"h1,h2,h3,h4,h5,h6\").addAnchor(_(\"Link\
+        \ to this section\"));\n        $(\"#content\").find(\".wikianchor\").each(function()\
+        \ {\n          $(this).addAnchor(babel.format(_(\"Link to #%(id)s\"), {id:\
+        \ $(this).attr('id')}));\n        });\n        $(\".foldable\").enableFolding(true,\
+        \ true);\n      });\n    </script>\n  </head>\n  <body>\n    <div id=\"banner\"\
+        >\n      <div id=\"header\">\n        <a id=\"logo\" href=\"https://fedorahosted.org/\"\
+        ><img src=\"https://fedorahosted.org/web/static/images/fedora-hosted-banner.png\"\
+        \ alt=\"Fedora Hosted\" /></a>\n      </div>\n      <form id=\"search\" action=\"\
+        /about-fedora/search\" method=\"get\">\n        <div>\n          <label for=\"\
+        proj-search\">Search:</label>\n          <input type=\"text\" id=\"proj-search\"\
+        \ name=\"q\" size=\"18\" value=\"\" />\n          <input type=\"submit\" value=\"\
+        Search\" />\n        </div>\n      </form>\n      <div id=\"metanav\" class=\"\
+        nav\">\n    <ul>\n      <li class=\"first\"><a href=\"/about-fedora/openidlogin\"\
+        >OpenID Login</a></li><li><a href=\"https://admin.fedoraproject.org/accounts/user/new\"\
+        >Fedora Account Sign Up</a></li><li><a href=\"/about-fedora/prefs\">Preferences</a></li><li><a\
+        \ href=\"/about-fedora/wiki/TracGuide\">Help/Guide</a></li><li><a href=\"\
+        /about-fedora/about\">About Trac</a></li><li class=\"last\"><a href=\"http://git.fedorahosted.org/cgit/about-fedora.git\"\
+        >CGit</a></li>\n    </ul>\n  </div>\n    </div>\n    <div id=\"mainnav\" class=\"\
+        nav\">\n    <ul>\n      <li class=\"first active\"><a href=\"/about-fedora/wiki\"\
+        >Wiki</a></li><li><a href=\"/about-fedora/timeline\">Timeline</a></li><li><a\
+        \ href=\"/about-fedora/roadmap\">Roadmap</a></li><li><a href=\"/about-fedora/browser\"\
+        >Browse Source</a></li><li><a href=\"/about-fedora/report\">View Tickets</a></li><li\
+        \ class=\"last\"><a href=\"/about-fedora/search\">Search</a></li>\n    </ul>\n\
+        \  </div>\n    <div id=\"main\">\n      <div id=\"pagepath\" class=\"noprint\"\
+        >\n  <a class=\"pathentry first\" title=\"View WikiStart\" href=\"/about-fedora/wiki\"\
+        >wiki:</a><a class=\"pathentry\" href=\"/about-fedora/wiki/WikiStart\" title=\"\
+        View WikiStart\">WikiStart</a>\n</div>\n      <div id=\"ctxtnav\" class=\"\
+        nav\">\n        <h2>Context Navigation</h2>\n          <ul>\n            \
+        \  <li class=\"first\"><a href=\"/about-fedora/wiki/WikiStart\">Start Page</a></li><li><a\
+        \ href=\"/about-fedora/wiki/TitleIndex\">Index</a></li><li class=\"last\"\
+        ><a href=\"/about-fedora/wiki/WikiStart?action=history\">History</a></li>\n\
+        \          </ul>\n        <hr />\n      </div>\n    <div id=\"content\" class=\"\
+        wiki\">\n      <div class=\"wikipage searchable\">\n        \n          \n\
+        \          <div class=\"trac-modifiedby\">\n            <span><a href=\"/about-fedora/wiki/WikiStart?action=diff&amp;version=5\"\
+        \ title=\"Version 5 by quaid: adding step to self-intro\">Last modified</a>\
+        \ <a class=\"timeline\" href=\"/about-fedora/timeline?from=2009-02-09T03%3A57%3A48Z&amp;precision=second\"\
+        \ title=\"2009-02-09T03:57:48Z in Timeline\">8 years</a> ago</span>\n    \
+        \        <span class=\"trac-print\">Last modified on 02/09/09 03:57:48</span>\n\
+        \          </div>\n          <div id=\"wikipage\"><h1 id=\"Whatisthissite\"\
+        >What is this site?</h1>\n<p>\nThis is the source project for About Fedora.\
+        \  It includes a <tt>git</tt> repo and a database for tracking how we develop\
+        \ the source toolchain.  \n</p>\n<p>\nIt's all part of the <a class=\"ext-link\"\
+        \ href=\"https://fedoraproject.org/wiki/Overview\"><span class=\"icon\">\u200B\
+        </span>Fedora Project</a>.  This site, in particular, is run by the <a class=\"\
+        ext-link\" href=\"https://fedoraproject.org/wiki/DocsProject\"><span class=\"\
+        icon\">\u200B</span>Fedora Documentation team</a>.\n</p>\n<p>\nIf you want\
+        \ to look at what we've created, use the \"Browse Source\" link above and\
+        \ to the right.\n</p>\n<h1 id=\"AboutFedorahassomethingmissingorwrong.\">About\
+        \ Fedora has something missing or wrong.</h1>\n<p>\nIf you need to tell us\
+        \ that something is wrong in About Fedora, visit <a class=\"ext-link\" href=\"\
+        https://bugzilla.redhat.com/bugzilla\"><span class=\"icon\">\u200B</span>Bugzilla</a>.\
+        \  File a bug against the product \"Fedora Documentation,\" component \"about-fedora\"\
+        .\n</p>\n<h1 id=\"Iwanttohelpwiththecontent.\">I want to help with the content.</h1>\n\
+        <p>\nIf you want to help update the content of About Fedora, first <a class=\"\
+        ext-link\" href=\"http://fedoraproject.org/wiki/DocsProject/Join#Things_you_need_to_do\"\
+        ><span class=\"icon\">\u200B</span>introduce yourself to the Docs Project</a>.\
+        \  When you've done that, <a class=\"ext-link\" href=\"https://admin.fedoraproject.org/accounts/group/view/gitabout-fedora\"\
+        ><span class=\"icon\">\u200B</span>join our project group</a>.  Then visit\
+        \ <a class=\"ext-link\" href=\"https://fedoraproject.org/wiki/Docs_Project_work_using_git\"\
+        ><span class=\"icon\">\u200B</span>this page on the Fedora Project wiki</a>\
+        \ to find out how to get started using <tt>git</tt>.  These instructions should\
+        \ work for most people with access to this repository:\n</p>\n<pre class=\"\
+        wiki\">cd ~/projects/\ngit clone ssh://&lt;username&gt;@git.fedorahosted.org/git/docs/about-fedora.git\n\
+        git clone git://git.fedorahosted.org/git/fedora-doc-utils docs-common\n</pre><p>\n\
+        If you don't have access to this repo, use <tt>git://</tt> instead of <tt>ssh://</tt>\
+        \ above.\n</p>\n<h1 id=\"Iwanttotranslatethecontenttomylanguage.\">I want\
+        \ to translate the content to my language.</h1>\n<p>\nCheck the <a class=\"\
+        ext-link\" href=\"http://translate.fedoraproject.org/module/docs-about-fedora\"\
+        ><span class=\"icon\">\u200B</span>statistics page</a> to get details about\
+        \ your language and join the <a class=\"ext-link\" href=\"https://fedoraproject.org/wiki/L10N\"\
+        ><span class=\"icon\">\u200B</span>Fedora Translation team</a> if your language\
+        \ is not available.\n</p>\n<h1 id=\"Imconfused.Whatisthissitefor\">I'm confused.\
+        \ What is this site for?</h1>\n<p>\nIf you have questions, come visit the\
+        \ Docs Project on IRC.  IRC is a way to communicate in real time with other\
+        \ Fedora Project members.  You can find more information <a class=\"ext-link\"\
+        \ href=\"https://fedoraproject.org/wiki/Communicate/IRC\"><span class=\"icon\"\
+        >\u200B</span>here</a>.\n</p>\n</div>\n        \n        \n      </div>\n\
+        \      \n\n    </div>\n    <div id=\"altlinks\">\n      <h3>Download in other\
+        \ formats:</h3>\n      <ul>\n        <li class=\"last first\">\n         \
+        \ <a rel=\"nofollow\" href=\"/about-fedora/wiki/WikiStart?format=txt\">Plain\
+        \ Text</a>\n        </li>\n      </ul>\n    </div>\n    </div>\n    <div id=\"\
+        footer\" lang=\"en\" xml:lang=\"en\"><hr />\n      <a id=\"tracpowered\" href=\"\
+        http://trac.edgewall.org/\"><img src=\"/about-fedora/chrome/common/trac_logo_mini.png\"\
+        \ height=\"30\" width=\"107\" alt=\"Trac Powered\" /></a>\n      <p class=\"\
+        left\">Powered by <a href=\"/about-fedora/about\"><strong>Trac 0.12.5</strong></a><br\
+        \ />\n        By <a href=\"http://www.edgewall.org/\">Edgewall Software</a>.<p\
+        \ class=\"left\">Libravatar support by <a href=\"https://bitbucket.org/zzzeek/tracvatar\"\
+        >Tracvatar 1.9</a></p></p>\n      <p class=\"right\">Visit the Trac open source\
+        \ project at<br /><a href=\"http://trac.edgewall.org/\">http://trac.edgewall.org/</a></p>\n\
+        \    </div>\n    <!-- Tack on our fedmenu stuff for this trac. -->\n    <script\
+        \ src=\"https://apps.fedoraproject.org/fedmenu/js/jquery-1.11.2.min.js\"></script>\n\
+        \    <script src=\"https://apps.fedoraproject.org/fedmenu/js/fedmenu.js\"\
+        ></script>\n    <script>\n      fedmenu({\n        'url': 'https://apps.fedoraproject.org/js/data.js',\n\
+        \        'mimeType': 'application/javascript',\n        'position': 'bottom-right',\n\
+        \      });\n    </script>\n  </body>\n</html>"}
+    headers:
+      cache-control: [must-revalidate]
+      connection: [Keep-Alive]
+      content-length: ['9437']
+      content-type: [text/html;charset=utf-8]
+      date: ['Tue, 14 Feb 2017 10:57:38 GMT']
+      expires: ['Fri, 01 Jan 1999 00:00:00 GMT']
+      keep-alive: ['timeout=5, max=500']
+      server: [Apache/2.2.15 (Red Hat)]
+      set-cookie: [trac_form_token=8344c426dbc2cc320d5e431d; Path=/about-fedora, 'trac_session=808a3fc5547b36ddaca5f057;
+          expires=Mon, 15-May-2017 10:57:39 GMT; Path=/about-fedora']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: Ok}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://fedorahosted.org/something-that-does-not-exist/
+  response:
+    body: {string: !!python/unicode '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+
+        <html><head>
+
+        <title>302 Found</title>
+
+        </head><body>
+
+        <h1>Found</h1>
+
+        <p>The document has moved <a href="https://fedorahosted.org/web/410">here</a>.</p>
+
+        <hr>
+
+        <address>Apache/2.2.15 (Red Hat) Server at fedorahosted.org Port 443</address>
+
+        </body></html>
+
+        '}
+    headers:
+      connection: [Keep-Alive]
+      content-length: ['300']
+      content-type: [text/html; charset=iso-8859-1]
+      date: ['Tue, 14 Feb 2017 10:57:40 GMT']
+      keep-alive: ['timeout=5, max=500']
+      location: ['https://fedorahosted.org/web/410']
+      server: [Apache/2.2.15 (Red Hat)]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 302, message: Found}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_pagure_repo b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_pagure_repo
new file mode 100644
index 0000000..03a168e
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_pagure_repo
@@ -0,0 +1,351 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://pagure.io/fedora-hubs
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - fedora-hubs - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"\
+        image/vnd.microsoft.icon\"\n        href=\"/static/favicon.ico\"/>\n    <link\
+        \ href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/fedora-hubs git https://pagure.io/fedora-hubs.git\"\
+        >\n  </head>\n  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"\
+        masthead\">\n      <div class=\"container\">\n        <div class=\"row\">\n\
+        \          <div class=\"col-sm-3\">\n            <a href=\"/\">\n        \
+        \      <img height=40px src=\"/static/pagure-logo.png\"\n                alt=\"\
+        pagure Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n  \
+        \        <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav\
+        \ class=\"navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\"\
+        >\n        <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n   \
+        \           <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link\
+        \ btn btn-primary\" href=\"/login/?next=https://pagure.io/fedora-hubs\">Log\
+        \ In</a>\n              </li>\n        </ul>\n      </div>\n    </nav>\n\n\
+        \            </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n        <a href=\"/fedora-hubs\">\nfedora-hubs</a>\n\
+        \        </h2>\n        <div class=\"projectinfo m-t-1 m-b-1\">\nFedora Hubs\
+        \ &nbsp;| &nbsp;<a class=\"inline\" href=\"https://hubs-dev.fedorainfracloud.org/\"\
+        >https://hubs-dev.fedorainfracloud.org/</a>        </div>\n\n    </header>\n\
+        \    <ul class=\"nav nav-tabs nav-small\">\n      <li class=\"nav-item\">\n\
+        \        <a class=\"nav-link active\" href=\"/fedora-hubs\">\n           \
+        \ <span class=\"oi hidden-md-up\" data-glyph=\"home\"></span>\n          \
+        \  <span class=\"hidden-sm-down\">Overview</span>\n        </a>\n      </li>\n\
+        \        <li class=\"nav-item\" >\n          <a  class=\"nav-link\" href=\"\
+        /docs/fedora-hubs/\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        book\"></span>\n              <span class=\"hidden-sm-down\">Docs</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \    <a class=\"nav-link\" href=\"/fedora-hubs/commits/develop\">\n      \
+        \        <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n   \
+        \           </span><span class=\"hidden-sm-down\">Commits</span>\n       \
+        \     </a>\n        </li>\n\n        <li class=\"nav-item\">\n          <a\
+        \ class=\"nav-link\" href=\"/fedora-hubs/tree/develop\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /fedora-hubs/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/fedora-hubs/issues\">\n             \
+        \   <span class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n     \
+        \           <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n         \
+        \       <span class=\"label label-default label-pill hidden-sm-down\">\n \
+        \                 111\n                </span>\n            </a>\n       \
+        \ </li>\n\n        <li class=\"nav-item\">\n          <a class=\"nav-link\"\
+        \ href=\"/fedora-hubs/pull-requests\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"task\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Pull Requests&nbsp;</span>\n              <span class=\"label label-default\
+        \ label-pill hidden-sm-down\">\n                3\n              </span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \    <a class=\"nav-link\" href=\"/fedora-hubs/forks\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"fork\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Forks&nbsp;</span>\n              <span class=\"\
+        hidden-sm-down label label-default label-pill\">\n                50\n   \
+        \           </span>\n            </a>\n        </li>\n\n\n    </ul>\n  </div>\n\
+        </div>\n\n<div class=\"container p-t-3\">\n  <div class=\"row\">\n       \
+        \ <div class=\"col-md-8\">\n            <section class=\"readme\">\n     \
+        \           <div class=\"document\">\n<h1>Fedora Hubs</h1>\n<p>Fedora Hubs\
+        \ will provide a communication and collaboration center for Fedora\ncontributors\
+        \ of all types. The idea is that contributors will be able to visit\nHubs\
+        \ to check on their involvements across Fedora, discover new places that they\n\
+        can contribute, and more.</p>\n<p>Hubs is currently under development, and\
+        \ you can see the progress on the\nDevelopment instance here: <a href=\"https://hubs-dev.fedorainfracloud.org/\"\
+        >https://hubs-dev.fedorainfracloud.org/</a></p>\n<div class=\"section\">\n\
+        <h1>Get Involved</h1>\n<p>Visit our <a href=\"https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org\"\
+        >mailing list</a>\nand join us in the <code><span class=\"pre\">#fedora-hubs</span></code>\
+        \ IRC channel on irc.freenode.net. Meetings are held\nweekly in <code><span\
+        \ class=\"pre\">#fedora-hubs</span></code> at 14:00UTC and the minutes for\
+        \ every meeting are\n<a href=\"https://meetbot.fedoraproject.org/sresults/?group_id=fedora-hubs&amp;type=team\"\
+        >archived</a>.\nIn the meetings we review our statuses from the preceding\
+        \ week and do ticket triage, too.</p>\n<p>For a more detailed overview of\
+        \ what Fedora Hubs is, see the\n<a href=\"https://docs.pagure.org/fedora-hubs/overview.html\"\
+        >documentation</a>.</p>\n<p>To set up a development environment and start\
+        \ contributing, check out\nthe <a href=\"https://docs.pagure.org/fedora-hubs/dev-guide.html\"\
+        >development guide</a>.</p>\n</div>\n</div>\n\n            </section>\n  \
+        \      </div>\n      <div class=\"col-md-4\">\n        <div class=\"card\"\
+        >\n          <div class=\"card-block\">\n            <h5><strong>Owners</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/decause\">\n                  <img class=\"avatar circle\"\
+        \ src=\"https://seccdn.libravatar.org/avatar/2107fccec2d30c09bcc3f4141388b10aabf16b2a9664f16cdf7227295f28e89b?s=20&d=retro\"\
+        />\n                  Remy DeCausemaker (decause)  -  creator\n          \
+        \      </a>\n              </div>\n              <div>\n                <a\
+        \ href=\"/user/mrichard\">\n                  <img class=\"avatar circle\"\
+        \ src=\"https://seccdn.libravatar.org/avatar/d64b6dc2a878d19f600cb711e02d8547fc94589f8633452f84da1cb961d2b892?s=20&d=retro\"\
+        />\n                  Meghan Richardson (mrichard)\n                </a>\n\
+        \              </div>\n              <div>\n                <a href=\"/user/duffy\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/e4e83ac110d58771f0c0125651a1ab585e9f72715dc76bd4af54e0102e96f171?s=20&d=retro\"\
+        />\n                  M\xE1ir\xEDn Duffy (duffy)\n                </a>\n \
+        \             </div>\n              <div>\n                <a href=\"/user/lmacken\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/d433d26a9f50eb87d94b0473472202aa7cf7952700ae82fc5f9750adc0aad37e?s=20&d=retro\"\
+        />\n                  Luke Macken (lmacken)\n                </a>\n      \
+        \        </div>\n              <div>\n                <a href=\"/user/nyazdani\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/40c9ac361c6cf560171f6bfb99eef9c6849bf8156e2faa15b067e4c4d092246b?s=20&d=retro\"\
+        />\n                  Nathaniel Yazdani (nyazdani)\n                </a>\n\
+        \              </div>\n              <div>\n                <a href=\"/user/bee2502\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/0b4ce1166336c24dae92f4ece34d4b6a2c7218dd85088967e2f12c6e7b09d5ce?s=20&d=retro\"\
+        />\n                  Bhagyashree Padalkar (bee2502)\n                </a>\n\
+        \              </div>\n              <div>\n                <a href=\"/user/devyani7\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/cbfbb8a5d78cfc3a595d65dd26074e5b5799bb2b585311dcc0dd18230e2f5649?s=20&d=retro\"\
+        />\n                  Devyani Kota (devyani7)\n                </a>\n    \
+        \          </div>\n              <div>\n                <a href=\"/user/dhrish20\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/156c08ff565412423d5bdb7a1d46e9ea0a3f0cf8f9b51b4f6cd0c6da56a72da9?s=20&d=retro\"\
+        />\n                  Dhriti Shikhar (dhrish20)\n                </a>\n  \
+        \            </div>\n              <div>\n                <a href=\"/user/jflory7\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/bc8fd31501030af99c3f31ca8a1f4ee205a1d0035b487d09a497a194b8777c70?s=20&d=retro\"\
+        />\n                  Justin W. Flory (jflory7)\n                </a>\n  \
+        \            </div>\n              <div>\n                <a href=\"/user/pingou\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \             </div>\n              <div>\n                <a href=\"/user/ryanlerch\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                  Ryan Lerch (ryanlerch)\n                </a>\n     \
+        \         </div>\n              <div>\n                <a href=\"/user/skrzepto\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/55ffbcbe7ef5ef02b58c2082b79aa1dc23794da806e19333d4dbb994c4093b3d?s=20&d=retro\"\
+        />\n                  Szymon Mucha (skrzepto)\n                </a>\n    \
+        \          </div>\n              <div>\n                <a href=\"/user/sayanchowdhury\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/4771836b6b430740e853f097f7121782109560ec6099e72ffc923ed17f9f88bd?s=20&d=retro\"\
+        />\n                  Sayan Chowdhury (sayanchowdhury)\n                </a>\n\
+        \              </div>\n              <div>\n                <a href=\"/user/bkorren\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/632177fa944babf9d34ebdc5fb82a4b2ea3ca7c1da7ef9657ebd6f3f48e3c094?s=20&d=retro\"\
+        />\n                  bkorren (bkorren)\n                </a>\n          \
+        \    </div>\n              <div>\n                <a href=\"/user/atelic\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/72118562545c3cad698b51ca813fd0149dd19f63d7dceec161d447b834b03a45?s=20&d=retro\"\
+        />\n                  Eric Barbour (atelic)\n                </a>\n      \
+        \        </div>\n              <div>\n                <a href=\"/user/wispfox\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b5f1b3792dc945fba3b616b489aa688b91577f186283427b4f08dd9dcbe53db7?s=20&d=retro\"\
+        />\n                  Suzanne Hillman (wispfox)\n                </a>\n  \
+        \            </div>\n              <div>\n                <a href=\"/user/jcline\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                  Jeremy Cline (jcline)\n                </a>\n      \
+        \        </div>\n              <div>\n                <a href=\"/user/abompard\"\
+        >\n                  <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/224e9ad3084cb9f442f423b7910701377be7a018408a4f8b22a09d94c89af46f?s=20&d=retro\"\
+        />\n                  Aurelien Bompard (abompard)\n                </a>\n\
+        \              </div>\n            </div>\n            <h5><strong>Branches</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div id=\"branch-develop\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-10\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"\n                    title=\"Default branch\"></span>\n         \
+        \         <strong title=\"Currently viewing branch develop\" data-toggle=\"\
+        tooltip\">develop</strong>\n                </div>\n                <div class=\"\
+        branch_del col-md-2\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        star\"\n                    title=\"Default branch\"></span>\n           \
+        \     </div>\n              </div>\n\n              <div id=\"branch-feature__bugzilla-links\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/fedora-hubs/branch/feature/bugzilla-links\"\
+        \n                    title=\"feature/bugzilla-links\" data-toggle=\"tooltip\"\
+        >feature/bugzilla-links\n                  </a>\n\n                </div>\n\
+        \                <div class=\"branch_del col-md-4\">\n                </div>\n\
+        \              </div>\n              <div id=\"branch-fix_fedmsgstats\" class=\"\
+        repoinfo-branchlistitem row\">\n                <div class=\"branch_name col-md-8\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n\
+        \                  <a class=\"\" href=\"/fedora-hubs/branch/fix_fedmsgstats\"\
+        \n                    title=\"fix_fedmsgstats\" data-toggle=\"tooltip\">fix_fedmsgstats\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-jenkins\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/fedora-hubs/branch/jenkins\"\n           \
+        \         title=\"jenkins\" data-toggle=\"tooltip\">jenkins\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-master\" class=\"repoinfo-branchlistitem row\">\n    \
+        \            <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/fedora-hubs/branch/master\"\n                   \
+        \ title=\"master\" data-toggle=\"tooltip\">master\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-unittest\" class=\"repoinfo-branchlistitem row\">\n               \
+        \ <div class=\"branch_name col-md-8\">\n                  <span class=\"oi\
+        \ text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/fedora-hubs/branch/unittest\"\n                    title=\"unittest\"\
+        \ data-toggle=\"tooltip\">unittest\n                  </a>\n\n           \
+        \     </div>\n                <div class=\"branch_del col-md-4\">\n      \
+        \          </div>\n              </div>\n            </div>\n            <h5><strong>Source\
+        \ GIT URLs</strong>                  <span class=\"pull-xs-right\"><a data-toggle=\"\
+        collapse\" href=\"#moregiturls\"\n                  aria-expanded=\"false\"\
+        \ aria-controls=\"moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n\
+        \            <div>\n              <div class=\"form-group\">\n           \
+        \     <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">SSH</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"ssh://git@pagure.io/fedora-hubs.git\" readonly>\n\
+        \                </div>\n              </div>\n              <div class=\"\
+        form-group\">\n                <div class=\"input-group input-group-sm\">\n\
+        \                  <div class=\"input-group-addon\">GIT</div>\n          \
+        \        <input class=\"form-control\" type=\"text\" value=\"https://pagure.io/fedora-hubs.git\"\
+        \ readonly>\n                </div>\n              </div>\n              <div\
+        \ class=\"collapse\" id=\"moregiturls\">\n                  <h5><strong>Docs\
+        \ GIT URLs</strong></h5>\n                  <div class=\"form-group\">\n \
+        \                   <div class=\"input-group input-group-sm\">\n         \
+        \             <div class=\"input-group-addon\">GIT</div>\n               \
+        \       <input class=\"form-control\" type=\"text\" value=\"https://pagure.io/docs/fedora-hubs.git\"\
+        \ readonly>\n                    </div>\n                  </div>\n      \
+        \        </div>\n            </div>\n          </div>\n          <div class=\"\
+        repo_date\" title=\"2015-06-04 17:27:48.074785\">\n              created 2\
+        \ years ago\n          </div>\n        </div>\n\n          <div class=\"card\"\
+        >\n            <div class=\"card-header\">\n              <strong>Recent Commits\
+        \ in\n                <span class=\"pr-toplabel\">\n                  <span\
+        \ class=\"oi\" data-glyph=\"random\"></span>\n                  develop\n\
+        \                </span>\n              </strong>\n            </div>\n  \
+        \          <div class=\"card-block p-a-0\">\n              <div class=\"list-group\
+        \ list-group-flush\">\n                  <a href=\"/fedora-hubs/c/71893f00e2afa9a2b8c3c2e2b417effabfa8a97e\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Feb 10 2017 15:10:50\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/224e9ad3084cb9f442f423b7910701377be7a018408a4f8b22a09d94c89af46f?s=20&d=retro\"\
+        />\n                          Aur\xE9lien Bompard\n                      \
+        \  </strong>\n                        commited 3 days ago\n              \
+        \        </small>\n                    </div>\n                    <div><small>\n\
+        \                      Sort the widget registry by name\n                \
+        \    </small></div>\n                  </a>\n                  <a href=\"\
+        /fedora-hubs/c/d6eb8815e9c4e7d6e60a924113b13095c5ccbe7e\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Feb 10 2017 13:56:13\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/224e9ad3084cb9f442f423b7910701377be7a018408a4f8b22a09d94c89af46f?s=20&d=retro\"\
+        />\n                          Aur\xE9lien Bompard\n                      \
+        \  </strong>\n                        commited 3 days ago\n              \
+        \        </small>\n                    </div>\n                    <div><small>\n\
+        \                      Fix the help text in the widgets config template\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/fedora-hubs/c/5e3de90c7d948bb82e4651e9d5b73a63472fa9e9\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Feb 10 2017 10:27:24\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/224e9ad3084cb9f442f423b7910701377be7a018408a4f8b22a09d94c89af46f?s=20&d=retro\"\
+        />\n                          Aur\xE9lien Bompard\n                      \
+        \  </strong>\n                        commited 4 days ago\n              \
+        \        </small>\n                    </div>\n                    <div><small>\n\
+        \                      Make CachedFunction.should_invalidate() abstract\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          2.12.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/jquery.min.js\">\n    </script>\n    <script type=\"text/javascript\"\
+        \n        src=\"/static/jquery-ui.min.js\">\n    </script>\n    <script type=\"\
+        text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n  $(\".watch-menu a\"\
+        ).click(function(){\n    var selectedValue = $(this).attr('id');\n    var\
+        \ action = $(\"#watch_project\").attr('action');\n      if (selectedValue\
+        \ != \"unwatch_button\") {\n        action = action.replace('/settings/0',\
+        \ '/settings/1');\n        $('#watch_project').attr('action', action);\n \
+        \     }\n      $('#watch_project').submit();\n\n  });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      connection: [Keep-Alive]
+      content-length: ['21185']
+      content-type: [text/html; charset=utf-8]
+      date: ['Tue, 14 Feb 2017 10:48:02 GMT']
+      keep-alive: ['timeout=5, max=100']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      set-cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiTTJSallqTmlaak16T1ROaE4yWTNOekZpWkdNeFptRTVZek13Wm1FM01ETTBaV1E0WlRFMU1BPT0ifX0.C4Rx4g.oLbGmDy2SdBOneLnLMwKWvCQ5WY;
+          Expires=Fri, 17-Mar-2017 10:48:02 GMT; Secure; HttpOnly; Path=/']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://pagure.io/something-that-does-not-exist
+  response:
+    body: {string: !!python/unicode "<!DOCTYPE html>\n<html lang='en'>\n<head>\n \
+        \   <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"\
+        />\n    <title>Page not found :'( - Pagure</title>\n    <link rel=\"shortcut\
+        \ icon\" type=\"image/vnd.microsoft.icon\"\n        href=\"/static/favicon.ico\"\
+        />\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n  </head>\n  <body id=\"\
+        error\">\n  <!-- start masthead -->\n    <div class=\"masthead\">\n      <div\
+        \ class=\"container\">\n        <div class=\"row\">\n          <div class=\"\
+        col-sm-3\">\n            <a href=\"/\">\n              <img height=40px src=\"\
+        /static/pagure-logo.png\"\n                alt=\"pagure Logo\" id=\"pagureLogo\"\
+        />\n            </a>\n          </div>\n          <div class=\"col-sm-9\"\
+        >\n            <div class=\"row\">\n\n  <nav class=\"navbar navbar-light p-t-0\
+        \ p-b-0\">\n      <div class=\"container\">\n        <ul class=\"nav navbar-nav\
+        \ nav-underline pull-xs-right\">\n              <li class=\"nav-item p-l-1\"\
+        >\n                <a class=\"nav-link btn btn-primary\" href=\"/login/?next=https://pagure.io/something-that-does-not-exist\"\
+        >Log In</a>\n              </li>\n        </ul>\n      </div>\n    </nav>\n\
+        \n            </div>\n          </div>\n        </div>\n      </div>\n   \
+        \ </div><!-- close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\
+        \n<div class=\"container p-t-3\">\n  <div class=\"row\">\n    <div class=\"\
+        col-md-8\">\n      <h2>Page not found (404)</h2>\n      <p>With the message:</p>\n\
+        \      <div class=\"card-block\">\n      <p>Project not found</p>\n      </div>\n\
+        \      <p>You have either entered a bad URL or the page has moved, removed,\
+        \ or otherwise rendered unavailable.<br/>\n      Please use the main navigation\
+        \ menu to get (re)started.</p>\n    </div>\n  </div>\n</div>\n    </div>\n\
+        \n    <div class=\"footer p-t-1 p-b-1\">\n        <div class=\"container\"\
+        >\n            <p class=\"text-muted credit\">\n         Copyright &copy;\
+        \ 2014-2017 Red Hat\n          <a href=\"https://pagure.io/pagure\">pagure</a>\
+        \ &mdash;\n          2.12.1 &mdash; <a href=\"https://docs.pagure.org/pagure/usage.html\"\
+        >Documentation</a>\n            </p>\n            <p><a href=\"/ssh_info\"\
+        >SSH Hostkey/Fingerprint</a></p>\n        </div>\n    </div>\n\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/jquery.min.js\">\n    </script>\n\
+        \    <script type=\"text/javascript\"\n        src=\"/static/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n\n</body>\n\
+        </html>"}
+    headers:
+      connection: [Keep-Alive]
+      content-length: ['3009']
+      content-type: [text/html; charset=utf-8]
+      date: ['Tue, 14 Feb 2017 10:48:03 GMT']
+      keep-alive: ['timeout=5, max=100']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      set-cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlfQ.C4Rx4w.okkFK2vKErtBTg2N2mPN4XPMTVc;
+          Expires=Fri, 17-Mar-2017 10:48:03 GMT; Secure; HttpOnly; Path=/']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 404, message: NOT FOUND}
+version: 1
diff --git a/hubs/validators.py b/hubs/validators.py
deleted file mode 100644
index e065629..0000000
--- a/hubs/validators.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from __future__ import unicode_literals
-
-import kitchen.text.converters
-
-import hubs.models
-import requests
-
-
-def required(session, value):
-    if bool(value):
-        return value
-
-
-def text(session, value):
-    return kitchen.text.converters.to_unicode(value)
-
-
-def integer(session, value):
-    return int(value)
-
-
-def link(session, value):
-    # TODO -- verify that this is actually a link
-    return value
-
-
-def username(session, value):
-    if hubs.models.User.by_username(value) is not None:
-        return value
-    raise ValueError('Invalid username')
-
-
-def github_organization(session, value):
-    # TODO -- implement this.
-    return value
-
-def github_repo(session, value):
-    # TODO -- implement this.
-    return value
-
-
-def fmn_context(session, value):
-    # TODO get this from the fedmsg config.
-    if value in [
-        'irc', 'email', 'android', 'desktop', 'hubs',]:
-        return value
-    raise ValueError('Invalid FMN context')
-
-
-def pagure_repo(session, value):
-    response = requests.get("https://pagure.io/%s" % value, timeout=5)
-    if response.status_code == 200:
-        return value
-    raise ValueError('Invalid pagure repo')
-
-
-def fedorahosted_project(session, value):
-    response = requests.get("https://fedorahosted.org/%s" % value, timeout=5)
-    if response.status_code == 200:
-        return value
-    raise ValueError('Invalid fedorahosted project')
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 6641711..3da39d3 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -212,7 +212,7 @@ def hub_add_widget_post(name):
             error = True
             break
         try:
-            param.validator(flask.g.db, val)
+            val = param.validator.from_string(val)
             config[param.name] = val
         except Exception as err:
             flask.flash('Invalid data provided, error: %s' % err, 'error')
@@ -231,6 +231,4 @@ def hub_add_widget_post(name):
                 'Could not save the configuration to the database '
                 'if the error persists, please warn an admin',
                 'error')
-
-    return flask.render_template(
-        'hubs.html', hub=hub, edit=True)
+    return flask.redirect(flask.url_for('hub_edit', name=hub.name))
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 192c44d..adc857a 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -48,7 +48,7 @@ def widget_edit_post(hub, idx):
             error = True
             break
         try:
-            val = param.validator(flask.g.db, val)
+            val = param.validator.from_string(val)
             config[param.name] = val
         except Exception as err:
             flask.flash('Invalid data provided, error: %s' % err, 'error')
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index bdb7e7b..1de5e0c 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -1,9 +1,8 @@
 from __future__ import unicode_literals
 
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
-from hubs import validators
-
 
 class About(Widget):
 
@@ -13,7 +12,7 @@ class About(Widget):
         name="text",
         label="Text",
         default="I am a Fedora user, and this is my about",
-        validator=validators.text,
+        validator=validators.Text,
         help="Text about a user.",
         )]
 
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index 79315e1..c609776 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import operator
 import requests
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -16,7 +16,7 @@ class Badges(Widget):
         name="username",
         label="Username",
         default=None,
-        validator=validators.username,
+        validator=validators.Username,
         help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index ac50fd3..38da840 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -23,13 +23,19 @@ class WidgetParameter(object):
     :py:class:`WidgetParameter` objects returned by the widget's
     :py:meth:`~Widget.get_parameters` method.
 
+    The value of the parameter is stored in the database as the value returned
+    by the validator's :py:meth:`from_string` method.  It can thus be a string,
+    an integer, a list, a dict, or any JSON-serializable value.
+
     Attributes:
         name (str): The name of the parameter.
         label (str): A humanized name of the parameter, which will be shown in
             the UI.
         default: The default value if this parameter is not set.
-        validator (function): A validation function that will be called when
-            a user sets the parameter value.
+        validator (hubs.widgets.validators.Validator): A validator subclass
+            that will be used to convert the parameter value to and from
+            string, raising an exception if it is invalid. This attribute
+            points to the validator subclass, not an instance of the class.
         help (str): A help text that will be shown in the UI.
     """
 
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index c63fa3c..99d02f1 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import requests
 import pkgwat.api
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -19,7 +19,7 @@ class Bugzilla(Widget):
         name="username",
         label="Username",
         default=None,
-        validator=validators.username,
+        validator=validators.Username,
         help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/dummy/__init__.py b/hubs/widgets/dummy/__init__.py
index ca4bac8..463e359 100644
--- a/hubs/widgets/dummy/__init__.py
+++ b/hubs/widgets/dummy/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -12,7 +12,7 @@ class Dummy(Widget):
         name="text",
         label="Text",
         default="Lorem ipsum dolor...",
-        validator=validators.text,
+        validator=validators.Text,
         help="Some dummy text to display.",
         )]
 
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 142548f..0b68bcb 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -5,8 +5,8 @@ import fedmsg.config
 import fedmsg.meta
 import requests
 
-from hubs import validators
 from hubs.utils import commas
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -21,7 +21,7 @@ class FedmsgStats(Widget):
         name="username",
         label="Username",
         default=None,
-        validator=validators.username,
+        validator=validators.Username,
         help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index b1f8299..30b39eb 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -1,7 +1,7 @@
 from __future__ import unicode_literals
 
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 import logging
@@ -17,13 +17,13 @@ class Feed(Widget):
             "name": "username",
             "label": "Username",
             "default": None,
-            "validator": validators.username,
+            "validator": validators.Username,
             "help": "A FAS username.",
         }, {
             "name": "message_limit",
             "label": "Message limit",
             "default": 20,
-            "validator": validators.integer,
+            "validator": validators.Integer,
             "help": "Max number of feed messages to display.",
         }]
 
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
index 8f60efa..7b83881 100644
--- a/hubs/widgets/fhosted/__init__.py
+++ b/hubs/widgets/fhosted/__init__.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 from six.moves.xmlrpc_client import ServerProxy
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -16,13 +16,13 @@ class FedoraHosted(Widget):
             name="project",
             label="Project",
             default=None,
-            validator=validators.fedorahosted_project,
+            validator=validators.FedorahostedProject,
             help="Name of the trac instance on fedorahosted.org.",
         ), dict(
             name="n_tickets",
             label="Number of tickets",
             default=4,
-            validator=validators.integer,
+            validator=validators.Integer,
             help="The number of tickets to display.",
         )]
 
@@ -48,7 +48,7 @@ class GetTickets(CachedFunction):
     Queries Fedorahosted via xmlrpc for tickets. '''
 
     def execute(self):
-        n_tickets = int(self.instance.config["n_tickets"])
+        n_tickets = self.instance.config["n_tickets"]
         url = 'https://fedorahosted.org/%s/rpc' \
             % self.instance.config["project"]
         filters = 'status=accepted&status=assigned&status=new&status=reopened'\
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 6961d4a..1d41502 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import logging
 import hubs.utils
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -22,13 +22,13 @@ class GitHubPRs(Widget):
             name="organization",
             label="Organization",
             default=None,
-            validator=validators.github_organization,
+            validator=validators.GithubOrganization,
             help="Github Organization or username",
         ), dict(
             name="display_number",
             label="Number of tickets",
             default=6,
-            validator=validators.integer,
+            validator=validators.Integer,
             help="How many pull requests to display at max.",
         )]
 
@@ -42,10 +42,9 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
         org = instance.config["organization"]
-        display_number = int(instance.config["display_number"])
         context = dict(
             organization=org,
-            display_number=display_number,
+            display_number=instance.config["display_number"],
             title="Github: Pull Requests",
         )
         context.update(get_prs())
@@ -56,7 +55,7 @@ class GetPRs(CachedFunction):
 
     def execute(self):
         org = self.instance.config["organization"]
-        display_number = int(self.instance.config["display_number"])
+        display_number = self.instance.config["display_number"]
         log.info("Getting GH prs for %r, (%r)" % (org, display_number))
         token = fedmsg_config.get('github.oauth_token')
         pulls = []
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index e29faa7..39d5aa0 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -16,19 +16,19 @@ class GitHubIssues(Widget):
             name="org",
             label="Username",
             default=None,
-            validator=validators.github_organization,
+            validator=validators.GithubOrganization,
             help="Github Organization or username",
         ), dict(
             name="repo",
             label="Repository",
             default=None,
-            validator=validators.github_repo,
+            validator=validators.GithubRepo,
             help="Github repository",
         ), dict(
             name="display_number",
             label="Number of tickets",
             default=10,
-            validator=validators.integer,
+            validator=validators.Integer,
             help="The number of tickets to display.",
         )]
 
@@ -44,7 +44,7 @@ class BaseView(WidgetView):
         return dict(
             org=instance.config["org"],
             repo=instance.config["repo"],
-            display_number=int(instance.config["display_number"]),
+            display_number=instance.config["display_number"],
             title="Github: Newest Open Tickets",
             all_issues=get_issues(),
         )
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index 351ec4f..e1d4511 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -1,7 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
-from hubs.widgets import clean_input
+from hubs.widgets import clean_input, validators
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -13,7 +12,7 @@ class Library(Widget):
         name="urls",
         label="URLs",
         default=None,
-        validator=validators.text,
+        validator=validators.Text,
         help="A comma separated list of URLs to add to the library. "
              "External links must include the whole link "
              "(starting with http...)."
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index dfae632..e9765ca 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -12,7 +12,7 @@ class Linechart(Widget):
         name="username",
         label="Username",
         default=None,
-        validator=validators.username,
+        validator=validators.Username,
         help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index 01908ce..568a04b 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -5,8 +5,8 @@ import collections
 import datetime
 import requests
 
-from hubs import validators
 from hubs import utils
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -20,13 +20,13 @@ class Meetings(Widget):
             name="calendar",
             label="Calendar",
             default=None,
-            validator=validators.required,
+            validator=validators.Required,
             help="A fedocal calendar.",
         ), dict(
             name="n_meetings",
             label="Number of meetings",
             default=4,
-            validator=validators.integer,
+            validator=validators.Integer,
             help="The number of meetings to display.",
         )]
 
@@ -56,7 +56,7 @@ class GetMeetings(CachedFunction):
 
     def execute(self):
         calendar = self.instance.config["calendar"]
-        n_meetings = int(self.instance.config.get("n_meetings", 4))
+        n_meetings = self.instance.config.get("n_meetings", 4)
         base = ('https://apps.fedoraproject.org/calendar/api/meetings/'
                 '?calendar=%s')
         url = base % calendar
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 518d12d..48c57a0 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -18,7 +18,7 @@ class PagurePRs(Widget):
             name="repo",
             label="Repository",
             default=None,
-            validator=validators.pagure_repo,
+            validator=validators.PagureRepo,
             help="Pagure repo name.",
         )]
 
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index 356d59f..7aa36c7 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -18,7 +18,7 @@ class PagureIssues(Widget):
             name="repo",
             label="Repository",
             default=None,
-            validator=validators.pagure_repo,
+            validator=validators.PagureRepo,
             help="Pagure repo name",
         )]
 
diff --git a/hubs/widgets/rules/__init__.py b/hubs/widgets/rules/__init__.py
index 498e3a8..1ec9c09 100644
--- a/hubs/widgets/rules/__init__.py
+++ b/hubs/widgets/rules/__init__.py
@@ -2,8 +2,8 @@ from __future__ import unicode_literals
 
 from collections import OrderedDict as ordereddict
 
-from hubs import validators
 from hubs.utils import username2avatar
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -19,25 +19,25 @@ class Rules(Widget):
             name="link",
             label="Link",
             default=None,
-            validator=validators.link,
+            validator=validators.Link,
             help="Link to the community rules and guidelines.",
         ), dict(
             name="schedule_text",
             label="Schedule text",
             default=None,
-            validator=validators.text,
+            validator=validators.Text,
             help="Some text about when meetings are.",
         ), dict(
             name="schedule_link",
             label="Schedule link",
             default=None,
-            validator=validators.link,
+            validator=validators.Link,
             help="Link to a schedule for IRC meetings, etc.",
         ), dict(
             name="minutes_link",
             label="Minutes link",
             default=None,
-            validator=validators.link,
+            validator=validators.Link,
             help="Link to meeting menutes from past meetings.",
         )]
 
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index 3f038ba..baec759 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
 
@@ -13,7 +13,7 @@ class Sticky(Widget):
             name="text",
             label="Text",
             default="Lorem ipsum dolor...",
-            validator=validators.text,
+            validator=validators.Text,
             help="Some dummy text to display.",
         )]
 
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
index 1641191..d6dd928 100644
--- a/hubs/widgets/subscriptions/__init__.py
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import flask
 import hubs.models
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -22,7 +22,7 @@ class Subscriptions(Widget):
             name="username",
             label="Username",
             default=None,
-            validator=validators.username,
+            validator=validators.Username,
             help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
new file mode 100644
index 0000000..9c96320
--- /dev/null
+++ b/hubs/widgets/validators.py
@@ -0,0 +1,151 @@
+from __future__ import unicode_literals
+
+import flask
+import hubs.models
+import kitchen.text.converters
+import requests
+
+
+class Validator(object):
+    """Convert widget parameters to and from string, and validate their value.
+
+    Validators are used to convert
+    :py:class:`~hubs.widgets.base.WidgetParameter` values to and from string.
+    They will raise an exception if the value is invalid.
+
+    A validator is a subclass of the :py:class:`Validator` class and implements
+    two class methods: :py:meth:`from_string` and :py:meth:`to_string`.
+    """
+
+    @classmethod
+    def from_string(cls, value):
+        """Convert the value from a string to a JSON-serializable value.
+
+        The result of this function will be stored in the database for widget
+        parameters.
+
+        Raises:
+            ValueError: The value is invalid.
+        """
+        if value is None:
+            return ""
+        return value
+
+    @classmethod
+    def to_string(cls, value):
+        """Convert the value to a string.
+
+        The result of this function will be used in the widget configuration
+        form fields.
+        """
+        return value
+
+
+class Required(Validator):
+    """Raises an error if the value is ``False``-like."""
+
+    @classmethod
+    def from_string(cls, value):
+        if not bool(value):
+            raise ValueError("the parameter is required")
+        return value
+
+
+class Text(Validator):
+    """Raises an error if the value can't be converted to unicode."""
+
+    @classmethod
+    def from_string(cls, value):
+        return kitchen.text.converters.to_unicode(value)
+
+
+class Integer(Validator):
+    """Raises an error if the value can't be converted to an integer."""
+
+    @classmethod
+    def from_string(cls, value):
+        return int(value)
+
+
+class Link(Validator):
+    """Raises an error if the value doesn't look like a link."""
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO -- verify that this is actually a link
+        return value
+
+
+class Username(Validator):
+    """Raises an error if the value isn't an existing username.
+
+    There must be a corresponding :py:class:`~hubs.models.User` record.
+
+    This validator does not return the User instance because it is not
+    JSON-serializable, it returns the username unchanged.
+    """
+
+    @classmethod
+    def from_string(cls, value):
+        if hubs.models.User.by_username(value) is not None:
+            return value
+        raise ValueError('Invalid username')
+
+    @classmethod
+    def to_string(cls, value):
+        if value is None and flask.g.auth.logged_in:
+            return flask.g.auth.user.username
+        return value
+
+
+class GithubOrganization(Validator):
+    """Fails if the Github organization name does not exist."""
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO -- implement this.
+        return value
+
+
+class GithubRepo(Validator):
+    """Fails if the Github repository name does not exist."""
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO -- implement this.
+        return value
+
+
+class FMNContext(Validator):
+    """Fails if the value is not a valid FMN context name."""
+
+    @classmethod
+    def from_string(cls, value):
+        # TODO get this from the fedmsg config.
+        if value in [
+            'irc', 'email', 'android', 'desktop', 'hubs',]:
+            return value
+        raise ValueError('Invalid FMN context')
+
+
+class PagureRepo(Validator):
+    """Fails if the Pagure repository name does not exist."""
+
+    @classmethod
+    def from_string(cls, value):
+        response = requests.get("https://pagure.io/%s" % value, timeout=5)
+        if response.status_code == 200:
+            return value
+        raise ValueError('Invalid pagure repo')
+
+
+class FedorahostedProject(Validator):
+    """Fails if the FedoraHosted project name does not exist."""
+
+    @classmethod
+    def from_string(cls, value):
+        response = requests.get("https://fedorahosted.org/%s/" % value,
+                                timeout=5, allow_redirects=False)
+        if response.status_code == 200:
+            return value
+        raise ValueError('Invalid fedorahosted project')
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 07fd52b..40c19ec 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -2,8 +2,8 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs import validators
 from hubs.utils import username2avatar
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -17,7 +17,7 @@ class PendingACLs(Widget):
             name="username",
             label="Username",
             default=None,
-            validator=validators.username,
+            validator=validators.Username,
             help="A FAS username.",
         )]
 
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 79fac1f..4f6f462 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import requests
 
-from hubs import validators
+from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
@@ -21,7 +21,7 @@ class Updates2Stable(Widget):
             name="username",
             label="Username",
             default=None,
-            validator=validators.username,
+            validator=validators.Username,
             help="A FAS username.",
         )]
 

From 572a3fb3260c8e8535844ebe5861d9d50ac42952 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 22 2017 17:21:45 +0000
Subject: [PATCH 758/1001] Protect the edit views to logged-in users only


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 2a53ba5..a682d85 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -214,14 +214,18 @@ class HubsAPITest(hubs.tests.APPTest):
                 "/openidc/Authorization")
 
     def test_hub_add_widget_get_no_args(self):
-        result = self.app.get('/ralph/add', follow_redirects=False)
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/ralph/add', follow_redirects=False)
         self.assertEqual(result.status_code, 400)
         expected_str = 'Invalid position provided'
         self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_get_with_args(self):
-        result = self.app.get('/ralph/add?position=right',
-                              follow_redirects=True)
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/ralph/add?position=right',
+                                  follow_redirects=True)
         self.assertEqual(result.status_code, 200)
         expected_str = 'Adding a widget to hub: ralph'
         self.assertIn(expected_str, result.get_data(as_text=True))
@@ -230,14 +234,18 @@ class HubsAPITest(hubs.tests.APPTest):
 
     def test_hub_add_widget_post_no_widget_name(self):
         data = {}
-        result = self.app.post('/ralph/add', data=data, follow_redirects=False)
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.post('/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 400)
         expected_str = 'Invalid request sent'
         self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_invalid_widget_name(self):
         data = {'widget_name': 'invalid_widget_name'}
-        result = self.app.post('/ralph/add', data=data, follow_redirects=False)
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.post('/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 404)
         expected_str = 'Unknown widget called'
         self.assertIn(expected_str, result.get_data(as_text=True))
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 3da39d3..a0247f4 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -5,7 +5,7 @@ import flask
 import hubs.models
 
 from hubs.app import app, session
-from .utils import get_hub
+from .utils import get_hub, login_required
 
 
 @app.route('/<name>')
@@ -25,8 +25,8 @@ def hub_json(name):
     return response
 
 
-@app.route('/<name>/edit/', methods=['GET', 'POST'])
 @app.route('/<name>/edit', methods=['GET', 'POST'])
+@login_required
 def hub_edit(name):
     if flask.request.method == 'POST':
         return hub_edit_post(name)
diff --git a/hubs/views/root.py b/hubs/views/root.py
index 6b9102f..386f233 100644
--- a/hubs/views/root.py
+++ b/hubs/views/root.py
@@ -50,6 +50,7 @@ def login():
 
     hubs.models.User.get_or_create(
         flask.g.db, username=flask.g.auth.nickname, fullname=flask.g.auth.fullname)
+    flask.flash('Login successful', 'success')
 
     return flask.redirect(return_point)
 
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index 94113e3..32b544b 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -52,7 +52,6 @@ def login_required(function):
     def decorated_function(*args, **kwargs):
         """ Decorated function, actually does the work. """
         if not authenticated():
-            flask.flash('Login required', 'errors')
             return flask.redirect(flask.url_for(
                 'login', next=flask.request.url))
 
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index adc857a..773e357 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -5,7 +5,7 @@ import flask
 
 from hubs.app import app
 from pkg_resources import resource_isdir
-from .utils import get_widget_instance
+from .utils import get_widget_instance, login_required
 
 
 @app.route('/<hub>/<int:idx>/json')
@@ -19,6 +19,7 @@ def widget_json(hub, idx):
 
 @app.route('/<hub>/<int:idx>/edit/', methods=['GET', 'POST'])
 @app.route('/<hub>/<int:idx>/edit', methods=['GET', 'POST'])
+@login_required
 def widget_edit(hub, idx):
     if flask.request.method == 'POST':
         return widget_edit_post(hub, idx)
@@ -71,6 +72,7 @@ def widget_edit_post(hub, idx):
 
 @app.route('/<hub>/<int:idx>/delete/', methods=['POST'])
 @app.route('/<hub>/<int:idx>/delete', methods=['POST'])
+@login_required
 def widget_edit_delete(hub, idx):
     ''' Remove a widget from a hub. '''
     widget = get_widget_instance(hub, idx)

From 69c3e12d1c701db768355ef93445774e069e7a37 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 22 2017 17:21:45 +0000
Subject: [PATCH 759/1001] Let widgets declare their add and edit config urls


This way, widgets can have a more complex configuration panel.

---

diff --git a/hubs/models.py b/hubs/models.py
index 2c155b9..3464f5b 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -360,6 +360,10 @@ class Widget(BASE):
     def module(self):
         return hubs.widgets.registry[self.plugin]
 
+    @property
+    def edit_url(self):
+        return self.module.get_edit_url(self.hub, self)
+
 
 class User(BASE):
     __tablename__ = 'users'
diff --git a/hubs/templates/edit.html b/hubs/templates/edit.html
deleted file mode 100644
index de4613f..0000000
--- a/hubs/templates/edit.html
+++ /dev/null
@@ -1,53 +0,0 @@
-
-<div class="modal-dialog" id="edit_form">
-  <div class="modal-content">
-    <form method="post" action="{{ url_to }}">
-    <!-- Modal content-->
-      <div class="modal-header">
-        <button type="button" class="close" data-dismiss="modal">&times;</button>
-        <h4 class="modal-title">Configure {{ name }}</h4>
-      </div>
-      <div class="modal-body">
-      {% for param in widget.module.get_parameters() %}
-        <fieldset class="form-group ">
-          <strong>{{ param.label | capitalize }}</strong>
-          <input id="{{ param.name }}" class="form-control" type="text"
-              value="{{ param.validator.to_string(widget.config.get(param.name, param.default)) }}"
-              name="{{ param.name }}" />
-          {% if param.help %}
-          <small class="text-muted">{{ param.help }}</small>
-          {% endif %}
-        </fieldset>
-      {% else %}
-        <p>Nothing to configure</p>
-      {% endfor %}
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">
-          Close
-        </button>
-        {% if widget.module.get_parameters() %}
-        <button type="submit" class="btn btn-primary">
-          Save
-        </button>
-        {% endif %}
-      </div>
-    </form>
-    <form method="POST" action="{{ url_for(
-        'widget_edit_delete', hub=widget.hub.name, idx=widget.idx) }}"
-        class="modal-footer p-abs" >
-        <button type="submit" class="btn btn-danger" id="delete_widget">
-          Remove this widget
-        </button>
-    </form>
-  </div>
-</div>
-
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
-<script type="text/javascript" src="{{
-  url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/bootstrap3-typeahead.min.js') }}"></script>
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/hubs_input.js') }}"></script>
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f5628f0..f096d30 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -281,10 +281,10 @@ $('#save_edits_btn').click(function() {
 function setup_edit_btns() {
   $("body").on("click", ".edit_widget", function(e) {
     e.preventDefault();
-    var _idx = $(this).attr('data-idx');
+    var url = $(this).attr('data-url');
 
     $.ajax({
-      url: _idx + '/edit',
+      url: url,
       dataType: 'html',
       success: function(html) {
         $('#edit_modal_content').html(html);
diff --git a/hubs/templates/widget_add.html b/hubs/templates/widget_add.html
new file mode 100644
index 0000000..7eae842
--- /dev/null
+++ b/hubs/templates/widget_add.html
@@ -0,0 +1,36 @@
+<div class="modal-dialog widget-add">
+  <div class="modal-content">
+    <form method="post" action="{{ url_for('widget_add', hub=hub.name, widget=widget.name) }}">
+    <!-- Modal content-->
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        <h4 class="modal-title">
+            Adding widget "{{ widget.name }}" to hub {{ hub.name }}
+        </h4>
+      </div> <!-- /modal-header -->
+      <div class="modal-body">
+      {% for param in widget.get_parameters() %}
+        <fieldset class="form-group ">
+          <strong>{{ param.label | capitalize }}</strong>
+          <input id="{{ param.name }}" class="form-control" type="text"
+              value="{{ param.validator.to_string(param.default) }}"
+              name="{{ param.name }}" />
+          {% if param.help %}
+          <small class="text-muted">{{ param.help }}</small>
+          {% endif %}
+        </fieldset>
+      {% else %}
+        <p>Nothing to configure</p>
+      {% endfor %}
+      </div> <!-- /modal-body -->
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">
+          Cancel
+        </button>
+        <button type="submit" class="btn btn-primary">
+            Add
+        </button>
+      </div> <!-- /modal-footer -->
+    </form>
+  </div>
+</div>
diff --git a/hubs/templates/widget_edit.html b/hubs/templates/widget_edit.html
new file mode 100644
index 0000000..3139d5d
--- /dev/null
+++ b/hubs/templates/widget_edit.html
@@ -0,0 +1,43 @@
+<div class="modal-dialog widget-edit">
+  <div class="modal-content">
+    <form method="post" action="{{ url_for('widget_edit', hub=hub.name, idx=widget_instance.idx) }}">
+    <!-- Modal content-->
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        <h4 class="modal-title">
+            Configure {{ widget_instance.plugin }}
+        </h4>
+      </div> <!-- /modal-header -->
+      <div class="modal-body">
+      {% for param in widget_instance.module.get_parameters() %}
+        <fieldset class="form-group ">
+          <strong>{{ param.label | capitalize }}</strong>
+          <input id="{{ param.name }}" class="form-control" type="text"
+              value="{{ param.validator.to_string(widget_instance.config.get(param.name, param.default)) }}"
+              name="{{ param.name }}" />
+          {% if param.help %}
+          <small class="text-muted">{{ param.help }}</small>
+          {% endif %}
+        </fieldset>
+      {% else %}
+        <p>Nothing to configure</p>
+      {% endfor %}
+      </div> <!-- /modal-body -->
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">
+          Close
+        </button>
+        <button type="submit" class="btn btn-primary">
+          Save
+        </button>
+      </div> <!-- /modal-footer -->
+    </form>
+    <form method="POST" action="{{ url_for(
+        'widget_edit_delete', hub=hub.name, idx=widget_instance.idx) }}"
+        class="modal-footer p-abs" >
+        <button type="submit" class="btn btn-danger" id="delete_widget">
+          Remove this widget
+        </button>
+    </form>
+  </div>
+</div>
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 773e357..60b1326 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -4,8 +4,10 @@ import datetime
 import flask
 
 from hubs.app import app
+from hubs.models import Widget
+from hubs.widgets import registry
 from pkg_resources import resource_isdir
-from .utils import get_widget_instance, login_required
+from .utils import get_hub, get_widget_instance, login_required
 
 
 @app.route('/<hub>/<int:idx>/json')
@@ -17,7 +19,59 @@ def widget_json(hub, idx):
     return response
 
 
-@app.route('/<hub>/<int:idx>/edit/', methods=['GET', 'POST'])
+@app.route('/<hub>/add/<widget>', methods=['GET', 'POST'])
+def widget_add(hub, widget):
+    hub = get_hub(hub)
+    position = flask.request.values.get('position', '')
+    if position not in ['right', 'left']:
+        flask.abort(400, 'Invalid position provided')
+    try:
+        widget = registry[widget]
+    except KeyError:
+        flask.abort(404, 'Unknown widget: %s' % widget)
+    if flask.request.method == 'POST':
+        create_widget_instance(hub, widget, position)
+        return flask.redirect(flask.url_for('hub_edit', name=hub.name))
+    return flask.render_template(
+        'widget_add.html',
+        hub=hub,
+        widget=widget,
+        position=position,
+    )
+
+def create_widget_instance(hub, widget, position):
+    """View helper to instanciate a widget on a hub."""
+    widget_instance = Widget(
+        hub=hub, plugin=widget.name, index=-1,
+        left=(position == 'left'))
+    config = {}
+    for param in widget.get_parameters():
+        val = flask.request.form.get(param.name)
+        if not val:
+            flask.flash(
+                'You must provide a value for: %s' % param.name, 'error')
+            return
+        try:
+            config[param.name] = param.validator.from_string(val)
+        except Exception as err:
+            flask.flash('Invalid data provided, error: %s' % err, 'error')
+            return
+    widget_instance.config = config
+    try:
+        flask.g.db.add(widget_instance)
+        flask.g.db.flush()
+        # TODO: use a SQLAlchemy signal here
+        hub.last_edited = datetime.datetime.utcnow()
+        flask.g.db.commit()
+    except Exception as err:
+        flask.flash(
+            'Could not save the configuration to the database '
+            'if the error persists, please warn an admin',
+            'error')
+    else:
+        flask.flash("The widget has been added.")
+
+
 @app.route('/<hub>/<int:idx>/edit', methods=['GET', 'POST'])
 @login_required
 def widget_edit(hub, idx):
@@ -28,20 +82,19 @@ def widget_edit(hub, idx):
 
 
 def widget_edit_get(hub, idx):
-    widget = get_widget_instance(hub, idx)
+    widget_instance = get_widget_instance(hub, idx)
     return flask.render_template(
-        'edit.html',
-        hub=hub,
-        widget=widget,
-        url_to=flask.url_for('widget_edit', hub=hub, idx=idx)
+        'widget_edit.html',
+        hub=widget_instance.hub,
+        widget_instance=widget_instance,
     )
 
 
 def widget_edit_post(hub, idx):
-    widget = get_widget_instance(hub, idx)
+    widget_instance = get_widget_instance(hub, idx)
     error = False
     config = {}
-    for param in widget.module.get_parameters():
+    for param in widget_instance.module.get_parameters():
         val = flask.request.form.get(param.name)
         if not val:
             flask.flash(
@@ -49,17 +102,17 @@ def widget_edit_post(hub, idx):
             error = True
             break
         try:
-            val = param.validator.from_string(val)
-            config[param.name] = val
+            config[param.name] = param.validator.from_string(val)
         except Exception as err:
             flask.flash('Invalid data provided, error: %s' % err, 'error')
             error = True
     if not error:
-        cur_config = widget.config
+        # Updating in-place is not supported, it's a class property.
+        cur_config = widget_instance.config.copy()
         cur_config.update(config)
-        widget.config = cur_config
-        widget.hub.last_edited = datetime.datetime.utcnow()
-        flask.g.db.add(widget)
+        widget_instance.config = cur_config
+        widget_instance.hub.last_edited = datetime.datetime.utcnow()
+        flask.g.db.add(widget_instance)
         try:
             flask.g.db.commit()
         except Exception as err:
@@ -67,7 +120,7 @@ def widget_edit_post(hub, idx):
                 'Could not save the configuration to the database '
                 'if the error persists, please warn an admin',
                 'error')
-    return flask.redirect(flask.url_for('hub', name=hub))
+    return flask.redirect(flask.url_for('hub_edit', name=hub))
 
 
 @app.route('/<hub>/<int:idx>/delete/', methods=['POST'])
@@ -90,8 +143,6 @@ def widget_edit_delete(hub, idx):
 @app.route('/source/<name>/')
 @app.route('/source/<name>')
 def widget_source(name):
-    from hubs.widgets import registry
-
     try:
         widget_path = registry[name].__module__
     except KeyError:
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 38da840..8ae225a 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -52,7 +52,7 @@ class Widget(object):
     """
     The main widget class, you must subclass it to create a widget.
 
-    Arguments:
+    Attributes:
         name (str): The widget name. It will not be displayed in the UI, but
             will appear in some URLs, so be careful to only use simple,
             URL-compatible characters.
@@ -194,6 +194,39 @@ class Widget(object):
                     self.name, url_rule.lstrip("/"))
                 app.add_url_rule(rule, view_func=view_func)
 
+    def get_add_url(self, hub, position):
+        """Returns the URL to the configuration panel to add this widget.
+
+        By default, it returns the URL to the common widget configuration panel
+        that will simply display the widget's parameters in a form.  Widgets
+        override this method to implement a more complex configuration view.
+
+        If a more complex configuration view is implemented, the resulting HTML
+        code will be wrapped in a ``<div class="modal-dialog">`` tag.
+
+        Args:
+            hub (hubs.models.Hub): The hub instance in the database.
+            position (str): the position where the widget should be added. It
+                must be either ``left`` or ``right``, and must be in the
+                supported positions for this widget (see :py:attr:`position`).
+        """
+        return "%s?position=%s" % (
+            flask.url_for('widget_add', hub=hub.name, widget=self.name),
+            position)
+
+    def get_edit_url(self, hub, widget_instance):
+        """Returns the URL to the configuration panel to edit this widget.
+
+        This method works like :py:meth:`get_add_url`.
+
+        Args:
+            hub (hubs.models.Hub): The hub instance in the database.
+            widget_instance (hubs.models.Widget): The widget instance in the
+                database that must be configured.
+        """
+        return flask.url_for(
+            'widget_edit', hub=hub.name, idx=widget_instance.idx)
+
     def get_cached_functions(self):
         """
         Returns:
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index 1f86223..71f8458 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -6,7 +6,7 @@
         <span><i class="fa fa-external-link" aria-hidden="true"></i></span>
     </a>
     <a data-target="#edit_modal" data-toggle="modal" type="button"
-        class="edit_widget" data-idx="{{ widget_instance.idx }}">
+        class="edit_widget" data-url="{{ widget_instance.edit_url }}">
       <span><i class="fa fa-pencil" aria-hidden="true"></i></span>
     </a>
   </div>

From 175f521bc2d5cc370b16f12efd8c72578212220b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 22 2017 17:21:45 +0000
Subject: [PATCH 760/1001] The add_widget panel is only used to choose the widget name


Then it delegates the configuration to the widget's add_url.

---

diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index cf9d686..ce20d36 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -1,40 +1,21 @@
 
 <div class="modal-dialog" id="adding_form">
   <div class="modal-content">
-    {% if widget %}
-    <form method="post" action="{{ url_to }}">
-    {% endif %}
+    <form method="post" action="{{ url_for('hub_add_widget', name=hub.name) }}">
+    <input type="hidden" name="position" value="{{ position }}" />
     <!-- Modal content-->
       <div class="modal-header">
         <button type="button" class="close" data-dismiss="modal">&times;</button>
         <h4 class="modal-title">
-          Adding {% if widget %}widget "{{ widget.name }}"{% else %}a widget{% endif %} to hub: {{ hub.name }}
+          Adding a widget to hub: {{ hub.name }}
         </h4>
       </div>
       <div class="modal-body">
-        {% if widgets %}
         <select id="widget" class="c-select" name="widget">
             {% for w in widgets %}
             <option value="{{ w }}">{{ w }}</option>
             {% endfor %}
         </select>
-        {% elif widget %}
-        <input name="widget_name" type="hidden" value="{{ widget.name }}">
-        <input name="position" type="hidden" value="{{ side }}">
-          {% for param in widget.get_parameters() %}
-            <fieldset class="form-group ">
-              <strong>{{ param.label | capitalize }}</strong>
-              <input id="{{ param.name }}" class="form-control" type="text"
-                value="{{ param.validator.to_string(param.default) }}"
-                name="{{ param.name }}" />
-              {% if param.help %}
-                <small class="text-muted">{{ param.help }}</small>
-              {% endif %}
-            </fieldset>
-          {% else %}
-            <p>Nothing to configure</p>
-          {% endfor %}
-        {% endif %}
       </div>
       <div class="modal-footer">
         <button type="button" class="btn btn-default" data-dismiss="modal">
@@ -44,46 +25,6 @@
           Add
         </button>
       </div>
-    {% if widget %}
     </form>
-    {% endif %}
   </div>
 </div>
-
-{% if widgets %}
-<script type="text/javascript">
-$("#submit_btn").unbind();
-$("#submit_btn").click(function() {
-  console.log($('#widget').val());
-
-  $.ajax({
-    url: 'add/' + $('#widget').val() + '?position={{ side }}',
-    dataType: 'html',
-    success: function(html) {
-      $('#adding_form').html(html);
-    },
-    error: function() {
-      $('#adding_form').html(
-        '<div class="modal-dialog"><div class="modal-content"> \
-        <div class="modal-body"> \
-        An error occured when trying to add a new widget\
-        </div></div></div>'
-      );
-      console.log('error');
-      console.trace();
-    },
-  });
-  return false;
-
-});
-</script>
-{% else %}
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
-<script type="text/javascript" src="{{
-  url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/bootstrap3-typeahead.min.js') }}"></script>
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/hubs_input.js') }}"></script>
-{% endif %}
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f096d30..fda7f95 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -249,6 +249,39 @@ function setup_add_btns() {
     });
     return false;
   });
+  // Setup events for the "add widget" form using delegated events because it's
+  // not in the DOM yet.
+  $("body").on("submit", "#adding_form form", function(e) {
+      var form = $(this);
+      e.preventDefault();
+      $.ajax({
+          type: "POST",
+          url: form.attr("action"),
+          dataType: "json",
+          data: form.serialize(),
+          success: function(data) {
+              if (data.status === "CONFIGURE") {
+                  $("#adding_form").load(data.url);
+              } else if (data.status === "ADDED") {
+                  // no config necessary, reload the page
+                  window.location = window.location;
+              } else {
+                $('#adding_form .modal-body').html(
+                  "An error occured when trying to add a new widget."
+                );
+                console.log('error');
+                console.trace();
+              }
+          },
+          error: function() {
+            $('#adding_form .modal-body').html(
+              "An error occured when trying to add a new widget."
+            );
+            console.log('error');
+            console.trace();
+          }
+        });
+  });
 }
 
 $('#save_edits_btn').click(function() {
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index a682d85..dc3da86 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -350,7 +350,7 @@ class HubsAPITest(hubs.tests.APPTest):
         with tests.auth_set(app, user):
             url = '/ralph/add/about?position=right'
             result = self.app.get(url)
-            self.assertIn('Adding widget "about" to hub: ralph',
+            self.assertIn('Adding widget "about" to hub ralph',
                           result.get_data(as_text=True))
 
     def test_hub_add_widget_invalid_side(self):
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index a0247f4..a4a8b19 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -139,96 +139,3 @@ def hub_edit_post(name):
             return ('ok', 200)
     else:
         return flask.redirect(flask.url_for('hub', name=name))
-
-
-@app.route('/<name>/add/', methods=['GET', 'POST'])
-@app.route('/<name>/add', methods=['GET', 'POST'])
-def hub_add_widgets(name):
-    if flask.request.method == 'POST':
-        return hub_add_widget_post(name)
-    else:
-        return hub_add_widget_get(name)
-
-
-@app.route('/<name>/add/<widget_name>/', methods=['GET'])
-@app.route('/<name>/add/<widget_name>', methods=['GET'])
-def hub_add_widget(name, widget_name):
-    hub = get_hub(name)
-    side = str(flask.request.args.get('position')).lower()
-    if side not in ['right', 'left']:
-        flask.abort(400, 'Invalid position provided')
-
-    widget = hubs.widgets.registry[widget_name]
-    if widget.position not in ['both', side]:
-        flask.abort(400, "This widget can't be placed here")
-
-    return flask.render_template(
-        'add_widget.html',
-        hub=hub,
-        widget=widget,
-        side=side,
-        url_to=flask.url_for('hub_add_widgets', name=name),
-    )
-
-
-def hub_add_widget_get(name):
-    hub = get_hub(name)
-    side = str(flask.request.args.get('position')).lower()
-    if side not in ['right', 'left']:
-        flask.abort(400, 'Invalid position provided')
-
-    widgets = [
-        widget
-        for widget in hubs.widgets.registry
-        if hubs.widgets.registry[widget].position in ['both', side]
-        ]
-    return flask.render_template(
-        'add_widget.html',
-        hub=hub,
-        widgets=widgets,
-        side=side,
-    )
-
-
-def hub_add_widget_post(name):
-    widget_name = flask.request.form.get('widget_name')
-    position = flask.request.form.get('position', '').lower()
-    if not widget_name:
-        flask.abort(400, 'Invalid request sent')
-    if widget_name not in hubs.widgets.registry:
-        flask.abort(404, 'Unknown widget called')
-
-    hub = get_hub(name)
-
-    widget = widget = hubs.models.Widget(
-        plugin=widget_name, index=-1, left=position == 'left')
-    error = False
-    config = {}
-    for param in widget.module.get_parameters():
-        val = flask.request.form.get(param.name)
-        if not val:
-            flask.flash(
-                'You must provide a value for: %s' % param.name, 'error')
-            error = True
-            break
-        try:
-            val = param.validator.from_string(val)
-            config[param.name] = val
-        except Exception as err:
-            flask.flash('Invalid data provided, error: %s' % err, 'error')
-            error = True
-    if not error:
-        widget.hub = hub
-        widget.config = config
-        try:
-            flask.g.db.add(widget)
-            flask.g.db.flush()
-            widget.hub.last_edited = datetime.datetime.utcnow()
-            flask.g.db.commit()
-        except Exception as err:
-            print(err)
-            flask.flash(
-                'Could not save the configuration to the database '
-                'if the error persists, please warn an admin',
-                'error')
-    return flask.redirect(flask.url_for('hub_edit', name=hub.name))
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 60b1326..02c06c8 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -19,6 +19,40 @@ def widget_json(hub, idx):
     return response
 
 
+@app.route('/<name>/add', methods=['GET', 'POST'])
+def hub_add_widget(name):
+    hub = get_hub(name)
+    position = flask.request.values.get('position', '')
+    if position not in ['right', 'left']:
+        flask.abort(400, 'Invalid position provided')
+    widgets = [
+        widget
+        for widget in registry
+        if registry[widget].position in ['both', position]
+        ]
+
+    if flask.request.method == 'POST':
+        widget_name = flask.request.form.get('widget')
+        if not widget_name:
+            flask.abort(400, 'Invalid request sent')
+        if widget_name not in widgets:
+            flask.abort(404, 'Unknown widget called')
+        widget = registry[widget_name]
+        if widget.get_parameters():
+            return flask.jsonify({
+                "status": "CONFIGURE",
+                "url": widget.get_add_url(hub, position),
+                })
+        create_widget_instance(hub, widget, position)
+        return flask.jsonify({"status": "ADDED"})
+    return flask.render_template(
+        'add_widget.html',
+        hub=hub,
+        widgets=widgets,
+        position=position,
+    )
+
+
 @app.route('/<hub>/add/<widget>', methods=['GET', 'POST'])
 def widget_add(hub, widget):
     hub = get_hub(hub)

From 4198845c1b7cd5e0ab11ae73f6fc1562be5ff5e4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 22 2017 17:21:45 +0000
Subject: [PATCH 761/1001] Fix unit tests


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index dc3da86..97c4911 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -227,13 +227,14 @@ class HubsAPITest(hubs.tests.APPTest):
             result = self.app.get('/ralph/add?position=right',
                                   follow_redirects=True)
         self.assertEqual(result.status_code, 200)
-        expected_str = 'Adding a widget to hub: ralph'
-        self.assertIn(expected_str, result.get_data(as_text=True))
-        expected_str = "url: 'add/' + $('#widget').val() + '?position=right',"
-        self.assertIn(expected_str, result.get_data(as_text=True))
+        page_html = result.get_data(as_text=True)
+        self.assertIn('Adding a widget to hub: ralph', page_html)
+        self.assertIn('<form method="post" action="/ralph/add">', page_html)
+        self.assertIn('<input type="hidden" name="position" value="right" />',
+                      page_html)
 
     def test_hub_add_widget_post_no_widget_name(self):
-        data = {}
+        data = {"position": "left"}
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             result = self.app.post('/ralph/add', data=data, follow_redirects=False)
@@ -242,7 +243,8 @@ class HubsAPITest(hubs.tests.APPTest):
         self.assertIn(expected_str, result.get_data(as_text=True))
 
     def test_hub_add_widget_post_invalid_widget_name(self):
-        data = {'widget_name': 'invalid_widget_name'}
+        data = {'widget': 'invalid_widget_name',
+                'position': 'right'}
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             result = self.app.post('/ralph/add', data=data, follow_redirects=False)
@@ -253,31 +255,36 @@ class HubsAPITest(hubs.tests.APPTest):
     def test_hub_add_widget_post_valid_widget_name_no_args(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            data = {'widget_name': 'about'}
+            data = {
+                'widget': 'memberships',
+                'position': 'right',
+                }
             result = self.app.post('/ralph/add', data=data)
-            self.assertEqual(result.status_code, 302)
-            self.assertEqual(urlparse(result.location).path, "/ralph/edit")
+            self.assertEqual(result.status_code, 200)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"status": "ADDED"})
+            #self.assertEqual(urlparse(result.location).path, "/ralph/edit")
             result = self.app.get('/ralph/edit')
             self.assertEqual(result.status_code, 200)
-            expected_str = '<h6 class="dropdown-header">Account Information</h6>'
-            self.assertIn(expected_str, result.get_data(as_text=True))
-            expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
-            self.assertIn(expected_str, result.get_data(as_text=True))
+            page_html = result.get_data(as_text=True)
+            self.assertIn('data-url="/ralph/w/memberships/', page_html)
 
     def test_hub_add_widget_post_valid_widget_name_with_args(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            data = {'widget_name': 'about', 'text': 'text of widget'}
-            result = self.app.post('/ralph/add', data=data,
+            data = {
+                'text': 'text of widget',
+                'position': 'right',
+                }
+            result = self.app.post('/ralph/add/about', data=data,
                                    follow_redirects=False)
             self.assertEqual(result.status_code, 302)
             self.assertEqual(urlparse(result.location).path, "/ralph/edit")
             result = self.app.get('/ralph/edit')
             self.assertEqual(result.status_code, 200)
-            expected_str = '<h6 class="dropdown-header">Account Information</h6>'
-            self.assertIn(expected_str, result.get_data(as_text=True))
-            expected_str = '<a href="#" class="dropdown-item">Full Name: fullname: ralph</a>'
-            self.assertIn(expected_str, result.get_data(as_text=True))
+            page_html = result.get_data(as_text=True)
+            self.assertIn('data-url="/ralph/w/about/', page_html)
 
     def test_hub_edit_widget_get_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -299,7 +306,7 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/ralph/37/edit'
             result = self.app.post(url, data=data, follow_redirects=False)
             self.assertEqual(result.status_code, 302)
-            self.assertEqual(urlparse(result.location).path, '/ralph/')
+            self.assertEqual(urlparse(result.location).path, '/ralph/edit')
 
     def test_hub_visit_counter_logged_in(self):
         user = tests.FakeAuthorization('ralph')

From addb6b553444e9ea79f633d49cd9d23b64f961bd Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 22 2017 17:21:45 +0000
Subject: [PATCH 762/1001] Don't hardcode URLs in Javascript code


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index fda7f95..2e4ccb3 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -146,7 +146,7 @@
             <div class="card">
               <div class="card-block">
                 <h4>
-                <a href="#" class="add_widget" data-position="left">
+                <a href="{{ url_for("hub_add_widget", name=hub.name) }}?position=left" class="add_widget">
                   <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
                 </a>
                 </h4>
@@ -164,7 +164,7 @@
             <div class="card">
               <div class="card-block">
                 <h4>
-                <a href="#" class="add_widget" data-position="right">
+                <a href="{{ url_for("hub_add_widget", name=hub.name) }}?position=right" class="add_widget">
                 <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
                 </a>
                 </h4>
@@ -223,17 +223,14 @@ function make_widget_sortable() {
 };
 
 function setup_add_btns() {
-  $(".add_widget").unbind();
-  $(".add_widget").click(function() {
-    console.log($(this));
-    var _pos = $(this).attr('data-position');
-
+  // Setup events for the "add widget" button.
+  $(".add_widget").click(function(e) {
+    e.preventDefault();
     $.ajax({
-      url: 'add?position=' + _pos,
+      url: $(this).attr('href'),
       dataType: 'html',
       success: function(html) {
         $('#edit_modal_content').html(html);
-        $('#edit_modal').modal();
       },
       error: function() {
         $('#edit_modal_content').html(
@@ -244,8 +241,10 @@ function setup_add_btns() {
         );
         console.log('error');
         console.trace();
-        $('#edit_modal').modal();
       },
+      complete: function() {
+        $('#edit_modal').modal();
+      }
     });
     return false;
   });

From e8bb053df384c1ddc18fa87f1b96aea895e0c07d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 22 2017 17:24:04 +0000
Subject: [PATCH 763/1001] Move a function in the view utils module


And other minor cleanups

---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 2e4ccb3..b1b013d 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -232,7 +232,7 @@ function setup_add_btns() {
       success: function(html) {
         $('#edit_modal_content').html(html);
       },
-      error: function() {
+      error: function(html) {
         $('#edit_modal_content').html(
           '<div class="modal-dialog"><div class="modal-content"> \
           <div class="modal-body"> \
@@ -241,6 +241,7 @@ function setup_add_btns() {
         );
         console.log('error');
         console.trace();
+        console.log(html);
       },
       complete: function() {
         $('#edit_modal').modal();
@@ -270,14 +271,16 @@ function setup_add_btns() {
                 );
                 console.log('error');
                 console.trace();
+                console.log(data);
               }
           },
-          error: function() {
+          error: function(html) {
             $('#adding_form .modal-body').html(
               "An error occured when trying to add a new widget."
             );
             console.log('error');
             console.trace();
+            console.log(html);
           }
         });
   });
diff --git a/hubs/templates/widget_add.html b/hubs/templates/widget_add.html
index 7eae842..f410ac8 100644
--- a/hubs/templates/widget_add.html
+++ b/hubs/templates/widget_add.html
@@ -1,7 +1,8 @@
 <div class="modal-dialog widget-add">
   <div class="modal-content">
     <form method="post" action="{{ url_for('widget_add', hub=hub.name, widget=widget.name) }}">
-    <!-- Modal content-->
+      <input type="hidden" name="position" value="{{ position }}" />
+      <!-- Modal content-->
       <div class="modal-header">
         <button type="button" class="close" data-dismiss="modal">&times;</button>
         <h4 class="modal-title">
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 97c4911..812159a 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -271,6 +271,11 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertIn('data-url="/ralph/w/memberships/', page_html)
 
     def test_hub_add_widget_post_valid_widget_name_with_args(self):
+        self.assertEqual(
+            hubs.models.Widget.query.filter(
+                hubs.models.Hub.name == "ralph",
+                hubs.models.Widget.plugin == "about",
+            ).count(), 1)
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             data = {
@@ -279,12 +284,15 @@ class HubsAPITest(hubs.tests.APPTest):
                 }
             result = self.app.post('/ralph/add/about', data=data,
                                    follow_redirects=False)
-            self.assertEqual(result.status_code, 302)
-            self.assertEqual(urlparse(result.location).path, "/ralph/edit")
-            result = self.app.get('/ralph/edit')
             self.assertEqual(result.status_code, 200)
-            page_html = result.get_data(as_text=True)
-            self.assertIn('data-url="/ralph/w/about/', page_html)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"status": "ADDED"})
+            self.assertEqual(
+                hubs.models.Widget.query.filter(
+                    hubs.models.Hub.name == "ralph",
+                    hubs.models.Widget.plugin == "about",
+                ).count(), 2)
 
     def test_hub_edit_widget_get_logged_in(self):
         user = tests.FakeAuthorization('ralph')
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index 35ff9fa..7865a34 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -12,7 +12,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
 
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json/' % widget.idx)
+        response = self.app.get('/ralph/%i/json' % widget.idx)
         assert response.status_code == 200, response.status_code
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index f8ae5b6..45e1ce8 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -11,7 +11,7 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
 
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json/' % widget.idx)
+        response = self.app.get('/ralph/%i/json' % widget.idx)
         assert response.status_code == 200, response.status_code
         data = json.loads(response.get_data(as_text=True))
         self.assertEquals(data['plugin'], 'badges')
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index 6bb9cca..cb3d5d3 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -10,7 +10,7 @@ class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
 
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json/' % widget.idx)
+        response = self.app.get('/ralph/%i/json' % widget.idx)
         assert response.status_code == 200, response.status_code
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 88db8b0..a41e60e 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -10,7 +10,7 @@ class TestLibrary(hubs.tests.test_widgets.WidgetTest):
 
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json/' % widget.idx)
+        response = self.app.get('/ralph/%i/json' % widget.idx)
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         expected_dict = {
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 859bfb9..78c41b9 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -11,7 +11,7 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
     def test_data_simple(self):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
-        response = self.app.get('/%s/%i/json/' % (team, widget.idx))
+        response = self.app.get('/%s/%i/json' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
         data = json.loads(response.get_data(as_text=True))
         calendar_name = data['data']['calendar']
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index 32b544b..2aecbb8 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -1,5 +1,6 @@
 from __future__ import unicode_literals
 
+import datetime
 import flask
 import functools
 import hubs.models
@@ -38,6 +39,51 @@ def get_widget_instance(hub, idx, session=None):
         flask.abort(404)
 
 
+class WidgetConfigError(Exception):
+    pass
+
+
+def create_widget_instance(hub, widget, position):
+    """View helper to instanciate a widget on a hub."""
+    widget_instance = hubs.models.Widget(
+        hub=hub, plugin=widget.name, index=-1,
+        left=(position == 'left'))
+    flask.g.db.add(widget_instance)
+    flask.g.db.flush()  # will populate Widget.config
+    try:
+        configure_widget_instance(widget_instance)
+    except WidgetConfigError as e:
+        flask.flash(e.args[0], "error")
+    else:
+        flask.flash("The widget has been added.")
+
+
+def configure_widget_instance(widget_instance):
+    config = {}
+    for param in widget_instance.module.get_parameters():
+        val = flask.request.form.get(param.name)
+        if not val:
+            raise WidgetConfigError(
+                'You must provide a value for: %s' % param.name)
+        try:
+            config[param.name] = param.validator.from_string(val)
+        except Exception as err:
+            raise WidgetConfigError('Invalid data provided, error: %s' % err)
+    # Updating in-place is not supported, it's a class property.
+    cur_config = widget_instance.config or {}
+    cur_config = cur_config.copy()
+    cur_config.update(config)
+    widget_instance.config = cur_config
+    # TODO: use a SQLAlchemy signal here
+    widget_instance.hub.last_edited = datetime.datetime.utcnow()
+    try:
+        flask.g.db.commit()
+    except Exception as err:
+        raise WidgetConfigError(
+            'Could not save the configuration to the database '
+            'if the error persists, please warn an admin')
+
+
 def authenticated():
     """ Utility function checking if the current auth is set or not."""
     return hasattr(flask.g, 'auth') \
@@ -69,4 +115,3 @@ def is_safe_url(target):
         urlparse.urljoin(flask.request.host_url, target))
     return test_url.scheme in ('http', 'https') and \
         ref_url.netloc == test_url.netloc
-
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 02c06c8..637ec25 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -4,19 +4,12 @@ import datetime
 import flask
 
 from hubs.app import app
-from hubs.models import Widget
 from hubs.widgets import registry
 from pkg_resources import resource_isdir
-from .utils import get_hub, get_widget_instance, login_required
-
-
-@app.route('/<hub>/<int:idx>/json')
-@app.route('/<hub>/<int:idx>/json/')
-def widget_json(hub, idx):
-    widget = get_widget_instance(hub, idx)
-    response = flask.jsonify(widget.__json__())
-    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
-    return response
+from .utils import (
+    create_widget_instance, configure_widget_instance, get_hub,
+    get_widget_instance, login_required, WidgetConfigError,
+    )
 
 
 @app.route('/<name>/add', methods=['GET', 'POST'])
@@ -56,6 +49,8 @@ def hub_add_widget(name):
 @app.route('/<hub>/add/<widget>', methods=['GET', 'POST'])
 def widget_add(hub, widget):
     hub = get_hub(hub)
+    # Use request.values instead of request.form to allow the position to be
+    # passed in the query string.
     position = flask.request.values.get('position', '')
     if position not in ['right', 'left']:
         flask.abort(400, 'Invalid position provided')
@@ -65,7 +60,7 @@ def widget_add(hub, widget):
         flask.abort(404, 'Unknown widget: %s' % widget)
     if flask.request.method == 'POST':
         create_widget_instance(hub, widget, position)
-        return flask.redirect(flask.url_for('hub_edit', name=hub.name))
+        return flask.jsonify({"status": "ADDED"})
     return flask.render_template(
         'widget_add.html',
         hub=hub,
@@ -73,100 +68,36 @@ def widget_add(hub, widget):
         position=position,
     )
 
-def create_widget_instance(hub, widget, position):
-    """View helper to instanciate a widget on a hub."""
-    widget_instance = Widget(
-        hub=hub, plugin=widget.name, index=-1,
-        left=(position == 'left'))
-    config = {}
-    for param in widget.get_parameters():
-        val = flask.request.form.get(param.name)
-        if not val:
-            flask.flash(
-                'You must provide a value for: %s' % param.name, 'error')
-            return
-        try:
-            config[param.name] = param.validator.from_string(val)
-        except Exception as err:
-            flask.flash('Invalid data provided, error: %s' % err, 'error')
-            return
-    widget_instance.config = config
-    try:
-        flask.g.db.add(widget_instance)
-        flask.g.db.flush()
-        # TODO: use a SQLAlchemy signal here
-        hub.last_edited = datetime.datetime.utcnow()
-        flask.g.db.commit()
-    except Exception as err:
-        flask.flash(
-            'Could not save the configuration to the database '
-            'if the error persists, please warn an admin',
-            'error')
-    else:
-        flask.flash("The widget has been added.")
-
 
 @app.route('/<hub>/<int:idx>/edit', methods=['GET', 'POST'])
 @login_required
 def widget_edit(hub, idx):
-    if flask.request.method == 'POST':
-        return widget_edit_post(hub, idx)
-    else:
-        return widget_edit_get(hub, idx)
-
-
-def widget_edit_get(hub, idx):
-    widget_instance = get_widget_instance(hub, idx)
-    return flask.render_template(
-        'widget_edit.html',
-        hub=widget_instance.hub,
-        widget_instance=widget_instance,
-    )
-
-
-def widget_edit_post(hub, idx):
     widget_instance = get_widget_instance(hub, idx)
-    error = False
-    config = {}
-    for param in widget_instance.module.get_parameters():
-        val = flask.request.form.get(param.name)
-        if not val:
-            flask.flash(
-                'You must provide a value for: %s' % param.name, 'error')
-            error = True
-            break
-        try:
-            config[param.name] = param.validator.from_string(val)
-        except Exception as err:
-            flask.flash('Invalid data provided, error: %s' % err, 'error')
-            error = True
-    if not error:
-        # Updating in-place is not supported, it's a class property.
-        cur_config = widget_instance.config.copy()
-        cur_config.update(config)
-        widget_instance.config = cur_config
-        widget_instance.hub.last_edited = datetime.datetime.utcnow()
-        flask.g.db.add(widget_instance)
+    if flask.request.method == 'POST':
         try:
-            flask.g.db.commit()
-        except Exception as err:
-            flask.flash(
-                'Could not save the configuration to the database '
-                'if the error persists, please warn an admin',
-                'error')
-    return flask.redirect(flask.url_for('hub_edit', name=hub))
+            configure_widget_instance(widget_instance)
+        except WidgetConfigError as e:
+            flask.flash(e.args[0], "error")
+        else:
+            flask.flash("The widget has been updated.")
+        return flask.redirect(flask.url_for('hub_edit', name=hub))
+    else:
+        return flask.render_template(
+            'widget_edit.html',
+            hub=widget_instance.hub,
+            widget_instance=widget_instance,
+        )
 
 
-@app.route('/<hub>/<int:idx>/delete/', methods=['POST'])
 @app.route('/<hub>/<int:idx>/delete', methods=['POST'])
 @login_required
 def widget_edit_delete(hub, idx):
     ''' Remove a widget from a hub. '''
-    widget = get_widget_instance(hub, idx)
-    flask.g.db.delete(widget)
+    widget_instance = get_widget_instance(hub, idx)
+    flask.g.db.delete(widget_instance)
     try:
         flask.g.db.commit()
-    except Exception as err:
+    except Exception:
         flask.flash(
             'Could not delete this widget from this hub in the database '
             'if the error persists, please warn an admin',
@@ -174,7 +105,14 @@ def widget_edit_delete(hub, idx):
     return flask.redirect(flask.url_for('hub_edit', name=hub))
 
 
-@app.route('/source/<name>/')
+@app.route('/<hub>/<int:idx>/json')
+def widget_json(hub, idx):
+    widget = get_widget_instance(hub, idx)
+    response = flask.jsonify(widget.__json__())
+    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
+    return response
+
+
 @app.route('/source/<name>')
 def widget_source(name):
     try:
@@ -189,4 +127,3 @@ def widget_source(name):
         widget_url += ".py"
     url = "/".join([app.config.get('SOURCE_URL'), widget_url])
     return flask.redirect(url)
-

From 27332a76bc20a330bb94e4236c630df89f720811 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 22 2017 17:24:04 +0000
Subject: [PATCH 764/1001] Update the populate widget list to the new format


---

diff --git a/populate.py b/populate.py
index 3eab11d..54c119f 100755
--- a/populate.py
+++ b/populate.py
@@ -15,13 +15,13 @@ session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 # Register widgets we will use
 hubs.widgets.registry.register_list([
-    "hubs.widgets.contact.Contact",
-    "hubs.widgets.stats.Stats",
-    "hubs.widgets.rules.Rules",
-    "hubs.widgets.meetings.Meetings",
-    "hubs.widgets.about.About",
-    "hubs.widgets.sticky.Sticky",
-    "hubs.widgets.dummy.Dummy",
+    "hubs.widgets.contact:Contact",
+    "hubs.widgets.stats:Stats",
+    "hubs.widgets.rules:Rules",
+    "hubs.widgets.meetings:Meetings",
+    "hubs.widgets.about:About",
+    "hubs.widgets.sticky:Sticky",
+    "hubs.widgets.dummy:Dummy",
     ])
 
 users = ['mrichard', 'duffy', 'ryanlerch', 'gnokii', 'nask0',

From 670f177c4043c8ba33e77c4d7420357ae35484d8 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 22 2017 17:24:04 +0000
Subject: [PATCH 765/1001] Aesthetics


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 77714a6..69171b6 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -366,6 +366,7 @@ font-size: 32pt;
 .p-abs {
   position: absolute;
   bottom: 0;
+  padding-left: 0;
 }
 
 #save_edits_btn {
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index b1b013d..de71ed6 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -269,6 +269,7 @@ function setup_add_btns() {
                 $('#adding_form .modal-body').html(
                   "An error occured when trying to add a new widget."
                 );
+                $('#adding_form .modal-footer button[type="submit"]').remove();
                 console.log('error');
                 console.trace();
                 console.log(data);
@@ -278,6 +279,7 @@ function setup_add_btns() {
             $('#adding_form .modal-body').html(
               "An error occured when trying to add a new widget."
             );
+            $('#adding_form .modal-footer button[type="submit"]').remove();
             console.log('error');
             console.trace();
             console.log(html);

From c8100804cddbb379b860339b7db82cdd67813470 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 23 2017 08:21:21 +0000
Subject: [PATCH 766/1001] Implement review suggestions


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 812159a..b704c1d 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -264,7 +264,6 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(
                 json.loads(result.get_data(as_text=True)),
                 {"status": "ADDED"})
-            #self.assertEqual(urlparse(result.location).path, "/ralph/edit")
             result = self.app.get('/ralph/edit')
             self.assertEqual(result.status_code, 200)
             page_html = result.get_data(as_text=True)
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index 2aecbb8..31a78d8 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -4,11 +4,15 @@ import datetime
 import flask
 import functools
 import hubs.models
+import logging
 
 from six.moves.urllib import parse as urlparse
 from sqlalchemy.orm.exc import NoResultFound
 
 
+log = logging.getLogger(__name__)
+
+
 def get_hub(name, session=None):
     """ Utility shorthand to get a hub and 404 if not found. """
     if session is None:
@@ -44,7 +48,13 @@ class WidgetConfigError(Exception):
 
 
 def create_widget_instance(hub, widget, position):
-    """View helper to instanciate a widget on a hub."""
+    """View helper to instanciate a widget on a hub.
+
+    Arguments:
+        hub (hubs.models.Hub): Instance of the hub to create the widget in.
+        widget (hubs.widgets.base.Widget): Widget to instanciate.
+        position (str): either ``left`` or ``right``.
+    """
     widget_instance = hubs.models.Widget(
         hub=hub, plugin=widget.name, index=-1,
         left=(position == 'left'))
@@ -59,6 +69,12 @@ def create_widget_instance(hub, widget, position):
 
 
 def configure_widget_instance(widget_instance):
+    """Configure a widget instance using the request form data.
+
+    Arguments:
+        widget_instance (hubs.models.Widget): Instance of the widget that is to
+            be configured.
+    """
     config = {}
     for param in widget_instance.module.get_parameters():
         val = flask.request.form.get(param.name)
@@ -67,7 +83,7 @@ def configure_widget_instance(widget_instance):
                 'You must provide a value for: %s' % param.name)
         try:
             config[param.name] = param.validator.from_string(val)
-        except Exception as err:
+        except ValueError as err:
             raise WidgetConfigError('Invalid data provided, error: %s' % err)
     # Updating in-place is not supported, it's a class property.
     cur_config = widget_instance.config or {}
@@ -79,6 +95,10 @@ def configure_widget_instance(widget_instance):
     try:
         flask.g.db.commit()
     except Exception as err:
+        log.warn(
+            "Could not save the configuration of widget "
+            "%s to the database: %s.",
+            widget_instance.idx, err)
         raise WidgetConfigError(
             'Could not save the configuration to the database '
             'if the error persists, please warn an admin')
@@ -115,3 +135,12 @@ def is_safe_url(target):
         urlparse.urljoin(flask.request.host_url, target))
     return test_url.scheme in ('http', 'https') and \
         ref_url.netloc == test_url.netloc
+
+
+def get_position():
+    # Use request.values instead of request.form to allow the position to be
+    # passed in the query string.
+    position = flask.request.values.get('position', '')
+    if position not in ['right', 'left']:
+        flask.abort(400, 'Invalid position provided')
+    return position
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 637ec25..1d21e17 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -1,6 +1,5 @@
 from __future__ import unicode_literals, absolute_import
 
-import datetime
 import flask
 
 from hubs.app import app
@@ -9,15 +8,14 @@ from pkg_resources import resource_isdir
 from .utils import (
     create_widget_instance, configure_widget_instance, get_hub,
     get_widget_instance, login_required, WidgetConfigError,
+    get_position,
     )
 
 
 @app.route('/<name>/add', methods=['GET', 'POST'])
 def hub_add_widget(name):
     hub = get_hub(name)
-    position = flask.request.values.get('position', '')
-    if position not in ['right', 'left']:
-        flask.abort(400, 'Invalid position provided')
+    position = get_position()
     widgets = [
         widget
         for widget in registry
@@ -49,11 +47,7 @@ def hub_add_widget(name):
 @app.route('/<hub>/add/<widget>', methods=['GET', 'POST'])
 def widget_add(hub, widget):
     hub = get_hub(hub)
-    # Use request.values instead of request.form to allow the position to be
-    # passed in the query string.
-    position = flask.request.values.get('position', '')
-    if position not in ['right', 'left']:
-        flask.abort(400, 'Invalid position provided')
+    position = get_position()
     try:
         widget = registry[widget]
     except KeyError:
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 8ae225a..c2a8dca 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -209,6 +209,9 @@ class Widget(object):
             position (str): the position where the widget should be added. It
                 must be either ``left`` or ``right``, and must be in the
                 supported positions for this widget (see :py:attr:`position`).
+
+        Returns:
+            The URL to add this widget, as a string.
         """
         return "%s?position=%s" % (
             flask.url_for('widget_add', hub=hub.name, widget=self.name),
@@ -223,6 +226,9 @@ class Widget(object):
             hub (hubs.models.Hub): The hub instance in the database.
             widget_instance (hubs.models.Widget): The widget instance in the
                 database that must be configured.
+
+        Returns:
+            The URL to edit this widget, as a string.
         """
         return flask.url_for(
             'widget_edit', hub=hub.name, idx=widget_instance.idx)

From b17671cfd6a5092804fef78bb379451270f6cbd2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 23 2017 08:23:28 +0000
Subject: [PATCH 767/1001] Fix Flake8 errors


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index b704c1d..9e66de1 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -2,11 +2,8 @@ from __future__ import unicode_literals
 
 import unittest
 from six.moves.urllib.parse import urlparse
-import ast # import for string to dict conversion without unicode
 
 from flask import json
-from os.path import dirname
-import vcr
 from mock import mock
 from werkzeug.datastructures import ImmutableMultiDict
 
@@ -16,8 +13,6 @@ from hubs.app import app
 
 import hubs.models
 
-import fedmsg.config
-
 
 class HubsAPITest(hubs.tests.APPTest):
     def test_index_logged_out(self):
@@ -237,7 +232,8 @@ class HubsAPITest(hubs.tests.APPTest):
         data = {"position": "left"}
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            result = self.app.post('/ralph/add', data=data, follow_redirects=False)
+            result = self.app.post(
+                '/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 400)
         expected_str = 'Invalid request sent'
         self.assertIn(expected_str, result.get_data(as_text=True))
@@ -247,7 +243,8 @@ class HubsAPITest(hubs.tests.APPTest):
                 'position': 'right'}
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            result = self.app.post('/ralph/add', data=data, follow_redirects=False)
+            result = self.app.post(
+                '/ralph/add', data=data, follow_redirects=False)
         self.assertEqual(result.status_code, 404)
         expected_str = 'Unknown widget called'
         self.assertIn(expected_str, result.get_data(as_text=True))
@@ -398,7 +395,7 @@ class HubsAPITest(hubs.tests.APPTest):
             self.assertEqual(result.status_code, 404)
 
     def mocked_requests_get(*args, **kwargs):
-        class MockResponse:
+        class MockResponse:  # flake8: noqa
             def __init__(self, json_data, status_code):
                 self.json_data = json_data
                 self.status_code = status_code
@@ -513,9 +510,3 @@ class HubsAPITest(hubs.tests.APPTest):
         result = self.app.get(url)
         self.assertEqual(result.status_code, 403)
         self.assertEqual(result.get_data(as_text=True), 'User does not exist')
-
-
-
-
-if __name__ == '__main__':
-    unittest.main()

From 3e4daa2355826f6aa4596d01a82ad2d1a4edf415 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 23 2017 09:15:05 +0000
Subject: [PATCH 768/1001] Add a human-readable label to widgets, and use it in the UI


---

diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index ce20d36..a194aa3 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -12,8 +12,8 @@
       </div>
       <div class="modal-body">
         <select id="widget" class="c-select" name="widget">
-            {% for w in widgets %}
-            <option value="{{ w }}">{{ w }}</option>
+            {% for widget in widgets %}
+            <option value="{{ widget.name }}">{{ widget.label }}</option>
             {% endfor %}
         </select>
       </div>
diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index 9b53e57..9d0e64d 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -42,10 +42,10 @@ class WidgetTest(APPTest):
             views = {}
             def get_views(self):
                 return self.views
-        test_widget = LocalTestWidget()
         self.assertRaisesRegexp(
-            AttributeError, '.* "name" .*', test_widget.validate)
-        test_widget.name = "invalid name \xe2\x98\xba"
+            AttributeError, '.* "name" .*', LocalTestWidget)
+        LocalTestWidget.name = "invalid name \xe2\x98\xba"
+        test_widget = LocalTestWidget()
         self.assertRaisesRegexp(
             AttributeError, '^invalid widget name: ', test_widget.validate)
         test_widget.name = "localtest"
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 1d21e17..39bb8f7 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -18,15 +18,15 @@ def hub_add_widget(name):
     position = get_position()
     widgets = [
         widget
-        for widget in registry
-        if registry[widget].position in ['both', position]
+        for widget in registry.values()
+        if widget.position in ['both', position]
         ]
 
     if flask.request.method == 'POST':
         widget_name = flask.request.form.get('widget')
         if not widget_name:
             flask.abort(400, 'Invalid request sent')
-        if widget_name not in widgets:
+        if widget_name not in [w.name for w in widgets]:
             flask.abort(404, 'Unknown widget called')
         widget = registry[widget_name]
         if widget.get_parameters():
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index c609776..00eae24 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -28,7 +28,7 @@ class BaseView(WidgetView):
     template_name = "badges.html"
 
     def get_context(self, instance, *args, **kwargs):
-        context = {"title": "Badges"}
+        context = {"title": self.widget.label}
         get_badges = GetBadges(instance)
         context.update(get_badges())
         return context
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index c2a8dca..aa8c5b8 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -56,6 +56,8 @@ class Widget(object):
         name (str): The widget name. It will not be displayed in the UI, but
             will appear in some URLs, so be careful to only use simple,
             URL-compatible characters.
+        label (str): A humanized name for the widget, which will be shown in
+            the UI.
         position (str): The position of the widget in the rendered page. It
             should be one of the following values: ``left``, ``right``, or
             ``both``.
@@ -70,12 +72,18 @@ class Widget(object):
     """
 
     name = None
+    label = None
     position = None
     parameters = []
     views_module = None
     cached_functions_module = None
 
     def __init__(self):
+        if self.name is None:
+            raise AttributeError('widgets must have a "name" attribute')
+        if self.label is None:
+            # Try to be smart-ish with the default label.
+            self.label = self.name.replace("_", " ").replace(".", ": ").title()
         self._template_environment = None
 
     def validate(self):
@@ -84,8 +92,6 @@ class Widget(object):
 
         Raises: AttributeError
         """
-        if self.name is None:
-            raise AttributeError('widgets must have a "name" attribute')
         if not re.match('^[\w_.-]+$', self.name):
             raise AttributeError(
                 'invalid widget name: %r. ' % self.name +
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 99d02f1..a9e0c4f 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -14,6 +14,7 @@ PKGDB_URL = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
 class Bugzilla(Widget):
 
     name = "bugzilla"
+    label = "Bugzilla issues"
     position = "right"
     parameters = [dict(
         name="username",
@@ -33,7 +34,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
         return dict(
-            title="Bugzilla: Issues",
+            title=self.widget.label,
             username=instance.config["username"],
             issues=get_issues()
             )
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 0b68bcb..ac1ba24 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -16,6 +16,7 @@ fedmsg_config = fedmsg.config.load_config()
 class FedmsgStats(Widget):
 
     name = "fedmsgstats"
+    label = "Fedmsg stats"
     position = "both"
     parameters = [dict(
         name="username",
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index 30b39eb..ebea21b 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -11,6 +11,7 @@ log = logging.getLogger('hubs')
 class Feed(Widget):
 
     name = "feed"
+    label = "Live feed"
     position = "left"
     parameters = [
         {
@@ -40,7 +41,7 @@ class BaseView(WidgetView):
         username = instance.config["username"]
         feed_url = app.config['SSE_URL'] + username
         return dict(
-            title="Live Feed",
+            title=self.widget.label,
             matches=[],
             message_limit=instance.config["message_limit"],
             feed_url=feed_url,
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
index 7b83881..38e69e6 100644
--- a/hubs/widgets/fhosted/__init__.py
+++ b/hubs/widgets/fhosted/__init__.py
@@ -10,6 +10,7 @@ from hubs.widgets.caching import CachedFunction
 class FedoraHosted(Widget):
 
     name = "fhosted"
+    label = "Fedorahosted: Open Tickets"
     position = "right"
     parameters = [
         dict(
@@ -36,7 +37,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_tickets = GetTickets(instance)
         context = dict(
-            title="Fedorahosted: Open Tickets",
+            title=self.widget.label,
             project=instance.config["project"],
             )
         context.update(get_tickets())
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 1d41502..07374fb 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -16,6 +16,7 @@ log = logging.getLogger(__name__)
 class GitHubPRs(Widget):
 
     name = "github_pr"
+    label = "Github: Pull Requests"
     position = "right"
     parameters = [
         dict(
@@ -45,7 +46,7 @@ class BaseView(WidgetView):
         context = dict(
             organization=org,
             display_number=instance.config["display_number"],
-            title="Github: Pull Requests",
+            title=self.widget.label,
         )
         context.update(get_prs())
         return context
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index 39d5aa0..4da6f9f 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -10,6 +10,7 @@ from hubs.widgets.caching import CachedFunction
 class GitHubIssues(Widget):
 
     name = "githubissues"
+    label = "Github: Newest Open Tickets"
     position = "right"
     parameters = [
         dict(
@@ -45,7 +46,7 @@ class BaseView(WidgetView):
             org=instance.config["org"],
             repo=instance.config["repo"],
             display_number=instance.config["display_number"],
-            title="Github: Newest Open Tickets",
+            title=self.widget.label,
             all_issues=get_issues(),
         )
 
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index e1d4511..803b56a 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -33,6 +33,6 @@ class BaseView(WidgetView):
             if u.strip()
         ]
         return dict(
-            title="Library",
+            title=self.widget.label,
             urls=urls,
             )
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index e9765ca..49388a2 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -7,6 +7,7 @@ from hubs.widgets.base import Widget, WidgetView
 class Linechart(Widget):
 
     name = "linechart"
+    label = "Weekly Activity"
     position = "left"
     parameters = [dict(
         name="username",
@@ -41,6 +42,6 @@ class BaseView(WidgetView):
         url = url + "&" + categories
         url = url.format(username=username)
         return dict(
-            title="Weekly Activity",
+            title=self.widget.label,
             url=url,
             )
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index 568a04b..b737f0a 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -46,7 +46,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_meetings = GetMeetings(instance)
         return dict(
-            title="Meetings",
+            title=self.widget.label,
             calendar=instance.config["calendar"],
             meetings=get_meetings(),
             )
diff --git a/hubs/widgets/memberships/__init__.py b/hubs/widgets/memberships/__init__.py
index 213f024..20f14c0 100644
--- a/hubs/widgets/memberships/__init__.py
+++ b/hubs/widgets/memberships/__init__.py
@@ -11,6 +11,7 @@ ELLIPSIS_LIMIT = 3
 class Memberships(Widget):
 
     name = "memberships"
+    label = "Hubs"
     position = "both"
 
 
@@ -38,7 +39,7 @@ class BaseView(WidgetView):
         oldest_members = sorted(
             members, key=lambda m: m.get('created_on'))[:ELLIPSIS_LIMIT]
         return dict(
-            title="Hubs",
+            title=self.widget.label,
             memberships=list(members),
             oldest_members=list(oldest_members),
             )
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 48c57a0..cce7322 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -12,6 +12,7 @@ pagure_url = "https://pagure.io/api/0"
 class PagurePRs(Widget):
 
     name = "pagure_pr"
+    label = "Pagure: Newest Open Pull Requests"
     position = "right"
     parameters = [
         dict(
@@ -32,7 +33,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
         context = dict(
-            title="Newest Open Pull Requests on Pagure",
+            title=self.widget.label,
             repo=instance.config["repo"],
             )
         context.update(get_prs())
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index 7aa36c7..85f7110 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -12,6 +12,7 @@ pagure_url = "https://pagure.io/api/0"
 class PagureIssues(Widget):
 
     name = "pagureissues"
+    label = "Pagure: Newest Open Tickets"
     position = "right"
     parameters = [
         dict(
@@ -32,7 +33,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
         context = dict(
-            title="Newest Open Tickets on Pagure",
+            title=self.widget.label,
             repo=instance.config["repo"],
             )
         context.update(get_issues())
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index baec759..ee22bc6 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -7,6 +7,7 @@ from hubs.widgets.base import Widget, WidgetView
 class Sticky(Widget):
 
     name = "sticky"
+    label = "Sticky Note"
     position = "both"
     parameters = [
         dict(
@@ -28,6 +29,6 @@ class BaseView(WidgetView):
         # TODO -- render with markdown
         return dict(
             text=instance.config["text"],
-            title="Sticky Note",
+            title=self.widget.label,
             panel_css_class="card-info",
             )
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 40c19ec..b30a208 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -11,6 +11,7 @@ from hubs.widgets.caching import CachedFunction
 class PendingACLs(Widget):
 
     name = "workflow.pendingacls"
+    label = 'Pending ACL Requests'
     position = "right"
     parameters = [
         dict(
@@ -32,7 +33,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_pending = GetPending(instance)
         context = dict(
-            title='Pending ACL Requests',
+            title=self.widget.label,
             username=instance.config["username"],
             )
         context.update(get_pending())
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 4f6f462..6f36260 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -15,6 +15,7 @@ giveaway = 'can be pushed to stable now'
 class Updates2Stable(Widget):
 
     name = "workflow.updates2stable"
+    label = 'Updates Ready for Stable'
     position = "right"
     parameters = [
         dict(
@@ -36,7 +37,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_pending = GetPending(instance)
         context = dict(
-            title='Updates Ready for Stable',
+            title=self.widget.label,
             username=instance.config["username"],
             )
         context.update(get_pending())

From b19d21c7b5cdb6e77878d32aa1109f5b0a9f33a2 Mon Sep 17 00:00:00 2001
From: Jeremy Cline <jeremy@jcline.org>
Date: Feb 23 2017 09:44:05 +0000
Subject: [PATCH 769/1001] Add a basic alembic configuration and README


Signed-off-by: Jeremy Cline <jeremy@jcline.org>

---

diff --git a/alembic.ini b/alembic.ini
new file mode 100644
index 0000000..305672c
--- /dev/null
+++ b/alembic.ini
@@ -0,0 +1,68 @@
+# A generic, single database configuration.
+
+[alembic]
+# path to migration scripts
+script_location = alembic
+
+# template used to generate migration files
+# file_template = %%(rev)s_%%(slug)s
+
+# max length of characters to apply to the
+# "slug" field
+#truncate_slug_length = 40
+
+# set to 'true' to run the environment during
+# the 'revision' command, regardless of autogenerate
+# revision_environment = false
+
+# set to 'true' to allow .pyc and .pyo files without
+# a source .py file to be detected as revisions in the
+# versions/ directory
+# sourceless = false
+
+# version location specification; this defaults
+# to alembic/versions.  When using multiple version
+# directories, initial revisions must be specified with --version-path
+# version_locations = %(here)s/bar %(here)s/bat alembic/versions
+
+# the output encoding used when revision files
+# are written from script.py.mako
+output_encoding = utf-8
+
+sqlalchemy.url = driver://user:pass@localhost/dbname
+
+
+# Logging configuration
+[loggers]
+keys = root,sqlalchemy,alembic
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARN
+handlers = console
+qualname =
+
+[logger_sqlalchemy]
+level = WARN
+handlers =
+qualname = sqlalchemy.engine
+
+[logger_alembic]
+level = INFO
+handlers =
+qualname = alembic
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
diff --git a/alembic/README.rst b/alembic/README.rst
new file mode 100644
index 0000000..5b7a3d1
--- /dev/null
+++ b/alembic/README.rst
@@ -0,0 +1,7 @@
+Generic single-database configuration of Alembic.
+
+Consult `the documentation <http://alembic.zzzcomputing.com/en/latest/>`_ for
+details on how to write new database migrations. In particular, you should be
+aware of the Alembic `autogenerate
+<http://alembic.zzzcomputing.com/en/latest/autogenerate.html>`_ feature which
+you can use with ``alembic revision --autogenerate -m "<migration description>"``
diff --git a/alembic/env.py b/alembic/env.py
new file mode 100644
index 0000000..058378b
--- /dev/null
+++ b/alembic/env.py
@@ -0,0 +1,70 @@
+from __future__ import with_statement
+from alembic import context
+from sqlalchemy import engine_from_config, pool
+from logging.config import fileConfig
+
+# this is the Alembic Config object, which provides
+# access to the values within the .ini file in use.
+config = context.config
+
+# Interpret the config file for Python logging.
+# This line sets up loggers basically.
+fileConfig(config.config_file_name)
+
+# add your model's MetaData object here
+# for 'autogenerate' support
+# from myapp import mymodel
+# target_metadata = mymodel.Base.metadata
+target_metadata = None
+
+# other values from the config, defined by the needs of env.py,
+# can be acquired:
+# my_important_option = config.get_main_option("my_important_option")
+# ... etc.
+
+
+def run_migrations_offline():
+    """Run migrations in 'offline' mode.
+
+    This configures the context with just a URL
+    and not an Engine, though an Engine is acceptable
+    here as well.  By skipping the Engine creation
+    we don't even need a DBAPI to be available.
+
+    Calls to context.execute() here emit the given string to the
+    script output.
+
+    """
+    url = config.get_main_option("sqlalchemy.url")
+    context.configure(
+        url=url, target_metadata=target_metadata, literal_binds=True)
+
+    with context.begin_transaction():
+        context.run_migrations()
+
+
+def run_migrations_online():
+    """Run migrations in 'online' mode.
+
+    In this scenario we need to create an Engine
+    and associate a connection with the context.
+
+    """
+    connectable = engine_from_config(
+        config.get_section(config.config_ini_section),
+        prefix='sqlalchemy.',
+        poolclass=pool.NullPool)
+
+    with connectable.connect() as connection:
+        context.configure(
+            connection=connection,
+            target_metadata=target_metadata
+        )
+
+        with context.begin_transaction():
+            context.run_migrations()
+
+if context.is_offline_mode():
+    run_migrations_offline()
+else:
+    run_migrations_online()
diff --git a/alembic/script.py.mako b/alembic/script.py.mako
new file mode 100644
index 0000000..7df1d1e
--- /dev/null
+++ b/alembic/script.py.mako
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# This Alembic database migration is part of the Fedora Hubs project.
+# Copyright (C) <year>  <name of author>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+${message}
+
+Revision ID: ${up_revision}
+Revises: ${down_revision | comma,n}
+Create Date: ${create_date}
+"""
+from alembic import op
+import sqlalchemy as sa
+${imports if imports else ""}
+
+# revision identifiers, used by Alembic.
+revision = ${repr(up_revision)}
+down_revision = ${repr(down_revision)}
+branch_labels = ${repr(branch_labels)}
+depends_on = ${repr(depends_on)}
+
+
+def upgrade():
+    ${upgrades if upgrades else "pass"}
+
+
+def downgrade():
+    ${downgrades if downgrades else "pass"}

From c3e446cca7097f90d6c877758418aa1e49ec64ab Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Feb 23 2017 13:31:41 +0000
Subject: [PATCH 770/1001] Don't try to display widgets that have been deactivated or removed


---

diff --git a/hubs/models.py b/hubs/models.py
index 3464f5b..2b7b6d5 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -263,13 +263,15 @@ class Hub(BASE):
     @property
     def left_widgets(self):
         return sorted(
-            [w for w in self.widgets if w.left],
+            [w for w in self.widgets
+             if w.plugin in hubs.widgets.registry and w.left],
             key=lambda w: w.index)
 
     @property
     def right_widgets(self):
         return sorted(
-            [w for w in self.widgets if not w.left],
+            [w for w in self.widgets
+             if w.plugin in hubs.widgets.registry and not w.left],
             key=lambda w: w.index)
 
     @property
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index deeb258..66c1488 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -154,7 +154,14 @@ class ModelTest(hubs.tests.APPTest):
                           username=username,
                           visited_hub=hub)
 
-
-
-
-
+    def test_removed_widget(self):
+        hub = hubs.models.Hub.get("ralph")
+        widget = hubs.models.Widget(
+            hub=hub, plugin="does-not-exist",
+            left=True, index=-1, _config="{}")
+        self.session.add(widget)
+        self.assertNotIn(
+            "does-not-exist", [w.plugin for w in hub.left_widgets])
+        widget.left = False
+        self.assertNotIn(
+            "does-not-exist", [w.plugin for w in hub.right_widgets])

From 1c3e4a8763ebe4f3a007efc3dfda6a0a34ef874d Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Mar 02 2017 08:46:35 +0000
Subject: [PATCH 771/1001] Merge #329 `Add a human-readable label to widgets, and use it in the UI`


---

diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index ce20d36..a194aa3 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -12,8 +12,8 @@
       </div>
       <div class="modal-body">
         <select id="widget" class="c-select" name="widget">
-            {% for w in widgets %}
-            <option value="{{ w }}">{{ w }}</option>
+            {% for widget in widgets %}
+            <option value="{{ widget.name }}">{{ widget.label }}</option>
             {% endfor %}
         </select>
       </div>
diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index 9b53e57..9d0e64d 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -42,10 +42,10 @@ class WidgetTest(APPTest):
             views = {}
             def get_views(self):
                 return self.views
-        test_widget = LocalTestWidget()
         self.assertRaisesRegexp(
-            AttributeError, '.* "name" .*', test_widget.validate)
-        test_widget.name = "invalid name \xe2\x98\xba"
+            AttributeError, '.* "name" .*', LocalTestWidget)
+        LocalTestWidget.name = "invalid name \xe2\x98\xba"
+        test_widget = LocalTestWidget()
         self.assertRaisesRegexp(
             AttributeError, '^invalid widget name: ', test_widget.validate)
         test_widget.name = "localtest"
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 1d21e17..39bb8f7 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -18,15 +18,15 @@ def hub_add_widget(name):
     position = get_position()
     widgets = [
         widget
-        for widget in registry
-        if registry[widget].position in ['both', position]
+        for widget in registry.values()
+        if widget.position in ['both', position]
         ]
 
     if flask.request.method == 'POST':
         widget_name = flask.request.form.get('widget')
         if not widget_name:
             flask.abort(400, 'Invalid request sent')
-        if widget_name not in widgets:
+        if widget_name not in [w.name for w in widgets]:
             flask.abort(404, 'Unknown widget called')
         widget = registry[widget_name]
         if widget.get_parameters():
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index c609776..00eae24 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -28,7 +28,7 @@ class BaseView(WidgetView):
     template_name = "badges.html"
 
     def get_context(self, instance, *args, **kwargs):
-        context = {"title": "Badges"}
+        context = {"title": self.widget.label}
         get_badges = GetBadges(instance)
         context.update(get_badges())
         return context
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index c2a8dca..aa8c5b8 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -56,6 +56,8 @@ class Widget(object):
         name (str): The widget name. It will not be displayed in the UI, but
             will appear in some URLs, so be careful to only use simple,
             URL-compatible characters.
+        label (str): A humanized name for the widget, which will be shown in
+            the UI.
         position (str): The position of the widget in the rendered page. It
             should be one of the following values: ``left``, ``right``, or
             ``both``.
@@ -70,12 +72,18 @@ class Widget(object):
     """
 
     name = None
+    label = None
     position = None
     parameters = []
     views_module = None
     cached_functions_module = None
 
     def __init__(self):
+        if self.name is None:
+            raise AttributeError('widgets must have a "name" attribute')
+        if self.label is None:
+            # Try to be smart-ish with the default label.
+            self.label = self.name.replace("_", " ").replace(".", ": ").title()
         self._template_environment = None
 
     def validate(self):
@@ -84,8 +92,6 @@ class Widget(object):
 
         Raises: AttributeError
         """
-        if self.name is None:
-            raise AttributeError('widgets must have a "name" attribute')
         if not re.match('^[\w_.-]+$', self.name):
             raise AttributeError(
                 'invalid widget name: %r. ' % self.name +
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 99d02f1..a9e0c4f 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -14,6 +14,7 @@ PKGDB_URL = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
 class Bugzilla(Widget):
 
     name = "bugzilla"
+    label = "Bugzilla issues"
     position = "right"
     parameters = [dict(
         name="username",
@@ -33,7 +34,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
         return dict(
-            title="Bugzilla: Issues",
+            title=self.widget.label,
             username=instance.config["username"],
             issues=get_issues()
             )
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 0b68bcb..ac1ba24 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -16,6 +16,7 @@ fedmsg_config = fedmsg.config.load_config()
 class FedmsgStats(Widget):
 
     name = "fedmsgstats"
+    label = "Fedmsg stats"
     position = "both"
     parameters = [dict(
         name="username",
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index 30b39eb..ebea21b 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -11,6 +11,7 @@ log = logging.getLogger('hubs')
 class Feed(Widget):
 
     name = "feed"
+    label = "Live feed"
     position = "left"
     parameters = [
         {
@@ -40,7 +41,7 @@ class BaseView(WidgetView):
         username = instance.config["username"]
         feed_url = app.config['SSE_URL'] + username
         return dict(
-            title="Live Feed",
+            title=self.widget.label,
             matches=[],
             message_limit=instance.config["message_limit"],
             feed_url=feed_url,
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
index 7b83881..38e69e6 100644
--- a/hubs/widgets/fhosted/__init__.py
+++ b/hubs/widgets/fhosted/__init__.py
@@ -10,6 +10,7 @@ from hubs.widgets.caching import CachedFunction
 class FedoraHosted(Widget):
 
     name = "fhosted"
+    label = "Fedorahosted: Open Tickets"
     position = "right"
     parameters = [
         dict(
@@ -36,7 +37,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_tickets = GetTickets(instance)
         context = dict(
-            title="Fedorahosted: Open Tickets",
+            title=self.widget.label,
             project=instance.config["project"],
             )
         context.update(get_tickets())
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 1d41502..07374fb 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -16,6 +16,7 @@ log = logging.getLogger(__name__)
 class GitHubPRs(Widget):
 
     name = "github_pr"
+    label = "Github: Pull Requests"
     position = "right"
     parameters = [
         dict(
@@ -45,7 +46,7 @@ class BaseView(WidgetView):
         context = dict(
             organization=org,
             display_number=instance.config["display_number"],
-            title="Github: Pull Requests",
+            title=self.widget.label,
         )
         context.update(get_prs())
         return context
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index 39d5aa0..4da6f9f 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -10,6 +10,7 @@ from hubs.widgets.caching import CachedFunction
 class GitHubIssues(Widget):
 
     name = "githubissues"
+    label = "Github: Newest Open Tickets"
     position = "right"
     parameters = [
         dict(
@@ -45,7 +46,7 @@ class BaseView(WidgetView):
             org=instance.config["org"],
             repo=instance.config["repo"],
             display_number=instance.config["display_number"],
-            title="Github: Newest Open Tickets",
+            title=self.widget.label,
             all_issues=get_issues(),
         )
 
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index e1d4511..803b56a 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -33,6 +33,6 @@ class BaseView(WidgetView):
             if u.strip()
         ]
         return dict(
-            title="Library",
+            title=self.widget.label,
             urls=urls,
             )
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index e9765ca..49388a2 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -7,6 +7,7 @@ from hubs.widgets.base import Widget, WidgetView
 class Linechart(Widget):
 
     name = "linechart"
+    label = "Weekly Activity"
     position = "left"
     parameters = [dict(
         name="username",
@@ -41,6 +42,6 @@ class BaseView(WidgetView):
         url = url + "&" + categories
         url = url.format(username=username)
         return dict(
-            title="Weekly Activity",
+            title=self.widget.label,
             url=url,
             )
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index 568a04b..b737f0a 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -46,7 +46,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_meetings = GetMeetings(instance)
         return dict(
-            title="Meetings",
+            title=self.widget.label,
             calendar=instance.config["calendar"],
             meetings=get_meetings(),
             )
diff --git a/hubs/widgets/memberships/__init__.py b/hubs/widgets/memberships/__init__.py
index 213f024..20f14c0 100644
--- a/hubs/widgets/memberships/__init__.py
+++ b/hubs/widgets/memberships/__init__.py
@@ -11,6 +11,7 @@ ELLIPSIS_LIMIT = 3
 class Memberships(Widget):
 
     name = "memberships"
+    label = "Hubs"
     position = "both"
 
 
@@ -38,7 +39,7 @@ class BaseView(WidgetView):
         oldest_members = sorted(
             members, key=lambda m: m.get('created_on'))[:ELLIPSIS_LIMIT]
         return dict(
-            title="Hubs",
+            title=self.widget.label,
             memberships=list(members),
             oldest_members=list(oldest_members),
             )
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 48c57a0..cce7322 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -12,6 +12,7 @@ pagure_url = "https://pagure.io/api/0"
 class PagurePRs(Widget):
 
     name = "pagure_pr"
+    label = "Pagure: Newest Open Pull Requests"
     position = "right"
     parameters = [
         dict(
@@ -32,7 +33,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
         context = dict(
-            title="Newest Open Pull Requests on Pagure",
+            title=self.widget.label,
             repo=instance.config["repo"],
             )
         context.update(get_prs())
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index 7aa36c7..85f7110 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -12,6 +12,7 @@ pagure_url = "https://pagure.io/api/0"
 class PagureIssues(Widget):
 
     name = "pagureissues"
+    label = "Pagure: Newest Open Tickets"
     position = "right"
     parameters = [
         dict(
@@ -32,7 +33,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
         context = dict(
-            title="Newest Open Tickets on Pagure",
+            title=self.widget.label,
             repo=instance.config["repo"],
             )
         context.update(get_issues())
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index baec759..ee22bc6 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -7,6 +7,7 @@ from hubs.widgets.base import Widget, WidgetView
 class Sticky(Widget):
 
     name = "sticky"
+    label = "Sticky Note"
     position = "both"
     parameters = [
         dict(
@@ -28,6 +29,6 @@ class BaseView(WidgetView):
         # TODO -- render with markdown
         return dict(
             text=instance.config["text"],
-            title="Sticky Note",
+            title=self.widget.label,
             panel_css_class="card-info",
             )
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 40c19ec..b30a208 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -11,6 +11,7 @@ from hubs.widgets.caching import CachedFunction
 class PendingACLs(Widget):
 
     name = "workflow.pendingacls"
+    label = 'Pending ACL Requests'
     position = "right"
     parameters = [
         dict(
@@ -32,7 +33,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_pending = GetPending(instance)
         context = dict(
-            title='Pending ACL Requests',
+            title=self.widget.label,
             username=instance.config["username"],
             )
         context.update(get_pending())
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 4f6f462..6f36260 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -15,6 +15,7 @@ giveaway = 'can be pushed to stable now'
 class Updates2Stable(Widget):
 
     name = "workflow.updates2stable"
+    label = 'Updates Ready for Stable'
     position = "right"
     parameters = [
         dict(
@@ -36,7 +37,7 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_pending = GetPending(instance)
         context = dict(
-            title='Updates Ready for Stable',
+            title=self.widget.label,
             username=instance.config["username"],
             )
         context.update(get_pending())

From e36996423f2cecca7c1fa3660fe727aa3a8a6d28 Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Mar 02 2017 08:47:49 +0000
Subject: [PATCH 772/1001] Merge #330 `Don't try to display widgets that have been deactivated or removed`


---

diff --git a/hubs/models.py b/hubs/models.py
index 3464f5b..2b7b6d5 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -263,13 +263,15 @@ class Hub(BASE):
     @property
     def left_widgets(self):
         return sorted(
-            [w for w in self.widgets if w.left],
+            [w for w in self.widgets
+             if w.plugin in hubs.widgets.registry and w.left],
             key=lambda w: w.index)
 
     @property
     def right_widgets(self):
         return sorted(
-            [w for w in self.widgets if not w.left],
+            [w for w in self.widgets
+             if w.plugin in hubs.widgets.registry and not w.left],
             key=lambda w: w.index)
 
     @property
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index deeb258..66c1488 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -154,7 +154,14 @@ class ModelTest(hubs.tests.APPTest):
                           username=username,
                           visited_hub=hub)
 
-
-
-
-
+    def test_removed_widget(self):
+        hub = hubs.models.Hub.get("ralph")
+        widget = hubs.models.Widget(
+            hub=hub, plugin="does-not-exist",
+            left=True, index=-1, _config="{}")
+        self.session.add(widget)
+        self.assertNotIn(
+            "does-not-exist", [w.plugin for w in hub.left_widgets])
+        widget.left = False
+        self.assertNotIn(
+            "does-not-exist", [w.plugin for w in hub.right_widgets])

From eea7b8a7c74b372e169af007e1b27e46027ff634 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 03 2017 17:29:14 +0000
Subject: [PATCH 773/1001] Split out the Feed widget to make it more independant


This allows more React-based widgets to coexist without bundling the
React libraries twice.

---

diff --git a/hubs/static/client/app/__tests__/Feed.test.js b/hubs/static/client/app/__tests__/Feed.test.js
index ae93f29..76daf32 100644
--- a/hubs/static/client/app/__tests__/Feed.test.js
+++ b/hubs/static/client/app/__tests__/Feed.test.js
@@ -1,11 +1,11 @@
 /* eslint-env jasmine, jest */
 
-jest.unmock('../components/Feed.jsx');
+jest.unmock('../widgets/feed/Feed.jsx');
 
 import React from 'react';
 import TestUtils from 'react-addons-test-utils';
 
-import Feed from '../components/Feed.jsx';
+import Feed from '../widgets/feed/Feed.jsx';
 
 describe('Feed', () => {
   const matches = [{
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
deleted file mode 100644
index b196bdb..0000000
--- a/hubs/static/client/app/components/Feed.jsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-
-import Panel from './Panel.jsx';
-
-export default class Feed extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {
-      matches: this.props.matches,
-      messageLimit: this.props.options.messageLimit,
-      sse: true,
-    };
-    // If it wasn't instantiated with a url or an error happened, bail
-    if (!this.props.url || !this.state.sse) {
-      return;
-    }
-    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : null;
-    if (!this.source) {
-      return;
-    }
-    this.source.addEventListener('error', () => {
-      this.state.sse = false;
-    }, false);
-    window.onbeforeunload = () => {
-      this.source.close();
-    };
-    this.source.onmessage = resp => {
-      const data = JSON.parse(resp.data);
-      if (this.state.matches.length >= this.state.messageLimit) {
-        this.state.matches.pop();
-      }
-      this.state.matches.unshift(data);
-      this.setState({ matches: this.state.matches });
-    };
-  }
-  render() {
-    const feedNodes = this.state.matches.map((match, idx) => {
-      return <Panel match={match} options={this.props.options || {}} key={idx} />;
-    });
-    return (
-      <div>
-        {feedNodes}
-      </div>
-    );
-  }
-}
-
-window.Feed = Feed;
-window.React = React;
-window.ReactDOM = ReactDOM;
diff --git a/hubs/static/client/app/index.jsx b/hubs/static/client/app/index.jsx
deleted file mode 100644
index 7641684..0000000
--- a/hubs/static/client/app/index.jsx
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This import is needed even though it's not used
- * since the feed component places itself on window.
- * The feed will not work without it.
- */
-import Feed from './components/Feed.jsx'; // eslint-disable-line
diff --git a/hubs/static/client/app/widgets/feed/Feed.jsx b/hubs/static/client/app/widgets/feed/Feed.jsx
new file mode 100644
index 0000000..beec5f7
--- /dev/null
+++ b/hubs/static/client/app/widgets/feed/Feed.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import Panel from '../../components/Panel.jsx';
+
+
+class Feed extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      matches: this.props.matches,
+      messageLimit: this.props.options.messageLimit,
+      sse: true,
+    };
+    // If it wasn't instantiated with a url or an error happened, bail
+    if (!this.props.url || !this.state.sse) {
+      return;
+    }
+    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : null;
+    if (!this.source) {
+      return;
+    }
+    this.source.addEventListener('error', () => {
+      this.state.sse = false;
+    }, false);
+    window.onbeforeunload = () => {
+      this.source.close();
+    };
+    this.source.onmessage = resp => {
+      const data = JSON.parse(resp.data);
+      if (this.state.matches.length >= this.state.messageLimit) {
+        this.state.matches.pop();
+      }
+      this.state.matches.unshift(data);
+      this.setState({ matches: this.state.matches });
+    };
+  }
+
+  render() {
+    const feedNodes = this.state.matches.map((match, idx) => {
+      return <Panel match={match} options={this.props.options || {}} key={idx} />;
+    });
+    return (
+      <div>
+        {feedNodes}
+      </div>
+    );
+  }
+
+}
+
+// Don't use the ES6 "export default" construct:
+// http://stackoverflow.com/questions/40294870/module-exports-vs-export-default-in-node-js-and-es6
+module.exports = Feed
diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
index 065ce2f..f97606a 100644
--- a/hubs/static/client/webpack.config.js
+++ b/hubs/static/client/webpack.config.js
@@ -3,16 +3,22 @@ const path = require('path');
 
 const PATHS = {
     app: path.join(__dirname, 'app'),
-    build: path.join(__dirname, '../js')
+    build: path.join(__dirname, '..', 'js', 'build')
 };
 
 const config = {
     entry: {
-        app: path.join(PATHS.app, 'index.jsx')
+        Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.jsx'),
     },
     output: {
         path: PATHS.build,
-        filename: 'hubs.js'
+        filename: '[name].js',
+        library: '[name]',
+    },
+    externals: {
+        'jquery': 'jQuery',
+        'react': 'React',
+        'react-dom': 'ReactDOM',
     },
     module : {
         loaders : [{
@@ -21,7 +27,8 @@ const config = {
             exclude: /(node_modules|bowercomponents)/,
             include : PATHS.app
         }]
-    }
+    },
+    plugins: [ new webpack.optimize.CommonsChunkPlugin("common.js") ]
 };
 
 module.exports = config;
diff --git a/hubs/static/js/build/.gitignore b/hubs/static/js/build/.gitignore
new file mode 100644
index 0000000..a6c7c28
--- /dev/null
+++ b/hubs/static/js/build/.gitignore
@@ -0,0 +1 @@
+*.js
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index de71ed6..8f73175 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -199,6 +199,8 @@
 {{ super() }}
 <script type="text/javascript" src="{{
   url_for('static', filename='js/utils.js') }}"></script>
+<script type="text/javascript"
+  src ="{{url_for('static', filename='js/build/common.js')}}"></script>
 
 {% if edit %}
 <script type="text/javascript" src="{{
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index e02081b..a44178a 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -61,6 +61,8 @@
   url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script type="text/javascript" src="{{
   url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
+<script src="https://unpkg.com/react@15/dist/react.min.js"></script>
+<script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script>
 {% endblock %}
 
 </body>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 8586d2a..f9e00c5 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -66,10 +66,12 @@
 
 {% block jscripts %}
 {{ super() }}
-<script type="text/javascript"
-  src ="{{url_for('static', filename='js/hubs.js')}}"></script>
 <script type="text/javascript" src="{{
   url_for('static', filename='js/utils.js') }}"></script>
+<script type="text/javascript"
+  src ="{{url_for('static', filename='js/build/common.js')}}"></script>
+<script type="text/javascript"
+  src ="{{url_for('static', filename='js/build/Feed.js')}}"></script>
 <script>
 
  function setup_feeds() {
diff --git a/hubs/widgets/feed/templates/feed.html b/hubs/widgets/feed/templates/feed.html
index 3f3bc87..151ed47 100644
--- a/hubs/widgets/feed/templates/feed.html
+++ b/hubs/widgets/feed/templates/feed.html
@@ -5,17 +5,17 @@
 </div>
 
 <script type="text/javascript"
-        src ="{{url_for('static', filename='js/hubs.js')}}"></script>
+  src ="{{url_for('static', filename='js/build/Feed.js')}}"></script>
 <script>
- (function() {
-   const FeedElement = React.createElement(Feed, {
-     matches: {{ matches }},
-     url: '{{ feed_url }}',
-     options: {
-       messageLimit: {{ message_limit }}
-     }
-   });
-   ReactDOM.render(FeedElement, document.getElementById('feed'));
- })();
+(function() {
+    const FeedElement = React.createElement(Feed, {
+        matches: {{ matches }},
+        url: '{{ feed_url }}',
+        options: {
+            messageLimit: {{ message_limit }}
+        }
+    });
+    ReactDOM.render(FeedElement, document.getElementById('feed'));
+})();
 </script>
 {% endblock %}

From 5178274b913855137854ca17b9d684cdfb84c317 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 03 2017 17:29:14 +0000
Subject: [PATCH 774/1001] Fix the syntax of the eslintrc file


---

diff --git a/hubs/static/client/.eslintrc.json b/hubs/static/client/.eslintrc.json
index 62ca52c..434bab5 100644
--- a/hubs/static/client/.eslintrc.json
+++ b/hubs/static/client/.eslintrc.json
@@ -1,9 +1,8 @@
 {
-  "extends": "airbnb",
   "rules": {
     "arrow-body-style": "off",
-    "func-names": "off"
+    "func-names": "off",
     "react/prefer-stateless-function": "off",
-    "react/prop-types": "off",
+    "react/prop-types": "off"
   }
 }

From 2a9d397089abdfc3c8cb3e43092b243c1813afb9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 03 2017 17:29:14 +0000
Subject: [PATCH 775/1001] Make the JS setup_feed function independant from template tags


This will allow moving it to an external JS file.

---

diff --git a/hubs/models.py b/hubs/models.py
index 2b7b6d5..f476bb6 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -274,11 +274,6 @@ class Hub(BASE):
              if w.plugin in hubs.widgets.registry and not w.left],
             key=lambda w: w.index)
 
-    @property
-    def widgets_idx(self):
-        """Returns the list of indices for this hub's widgets."""
-        return [w.idx for w in self.widgets]
-
     def __json__(self):
         return {
             'name': self.name,
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index f9e00c5..e33c301 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -73,55 +73,56 @@
 <script type="text/javascript"
   src ="{{url_for('static', filename='js/build/Feed.js')}}"></script>
 <script>
+  function setup_feeds(actions, saved, saveUrl) {
+    var streamFeed = React.createElement(Feed, {
+      matches: actions,
+      options: {
+        saveUrl: saveUrl,
+        messageLimit: 100
+      }
+    });
+    /* Right now, stream and actions are the same.
+     * Once, Mentions is implemented, then each will be its own
+     */
+    ReactDOM.render(streamFeed, document.getElementById('streamFeed'));
+    ReactDOM.render(streamFeed, document.getElementById('actionsFeed'));
+  
+    var savedFeed = React.createElement(Feed, {
+      matches: saved,
+      url: false,
+      options: {
+        messageLimit: 100,
+        delete: true,
+        saveUrl: saveUrl
+      }
+    });
+    ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
+    $('a[href="#saved"]').on('shown.bs.tab', function(){
+      $.get(saveUrl).done(function(resp) {
+        if (resp.length != saved.length) {
+          ReactDOM.unmountComponentAtNode(document.getElementById('savedFeed'));
+          var savedFeed = React.createElement(Feed, {
+            matches: resp,
+            url: false,
+            options: {
+              messageLimit: 100,
+              delete: true,
+              saveUrl: saveUrl
+            }
+          });
+          ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
+        }
+      });
+    });
+  }
 
- function setup_feeds() {
-   var actions = {{actions|safe}};
-
-   var streamFeed = React.createElement(Feed, {
-     matches: actions,
-     options: {
-       saveUrl: '/{{hub.name}}/notifications/',
-       messageLimit: 100
-     }
-   });
-   /* Right now, stream and actions are the same.
-    * Once, Mentions is implemented, then each will be its own
-    */
-   ReactDOM.render(streamFeed, document.getElementById('streamFeed'));
-   ReactDOM.render(streamFeed, document.getElementById('actionsFeed'));
-
-   var savedFeed = React.createElement(Feed, {
-     matches: {{saved|safe}},
-     url: false,
-     options: {
-       messageLimit: 100,
-       delete: true,
-       saveUrl: '/{{hub.name}}/notifications/'
-     }
-   });
-   ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
-   $('a[href="#saved"]').on('shown.bs.tab', function(){
-     $.get('/{{hub.name}}/notifications/').done(function(resp) {
-       var saved = {{saved|safe}};
-       if (resp.length != saved.length) {
-         ReactDOM.unmountComponentAtNode(document.getElementById('savedFeed'));
-         var savedFeed = React.createElement(Feed, {
-           matches: resp,
-           url: false,
-           options: {
-             messageLimit: 100,
-             delete: true,
-             saveUrl: '/{{hub.name}}/notifications/'
-           }
-         });
-         ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
-       }
-     });
-   });
- }
  $(function() {
    setup_widgets();
-   setup_feeds();
+   setup_feeds(
+       {{ actions|safe }},
+       {{ saved|safe }},
+       {{ url_for("notifications", user=hub.name)|tojson }}
+   );
  });
 </script>
 {% endblock %}

From 7eadb97cf01f6d794af233f65c04241163770391 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 04 2017 08:40:35 +0000
Subject: [PATCH 776/1001] Move the plus-plus views to the contact widget


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 9e66de1..ea33575 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -4,7 +4,6 @@ import unittest
 from six.moves.urllib.parse import urlparse
 
 from flask import json
-from mock import mock
 from werkzeug.datastructures import ImmutableMultiDict
 
 import hubs
@@ -393,120 +392,3 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/source/notexistent'
             result = self.app.get(url)
             self.assertEqual(result.status_code, 404)
-
-    def mocked_requests_get(*args, **kwargs):
-        class MockResponse:  # flake8: noqa
-            def __init__(self, json_data, status_code):
-                self.json_data = json_data
-                self.status_code = status_code
-                self.text = str(json_data)
-            def json(self):
-                return self.json_data
-
-        if '/decause' in args[0]:
-            data = {
-                "current": 0,
-                "decrements": 0,
-                "increments": 0,
-                "release": "f24",
-                "total": 0,
-                "username": "decause"
-            }
-            return MockResponse(json_data=data, status_code=200)
-
-        return MockResponse({}, 404)
-
-    def mocked_requests_post(*args, **kwargs):
-        class MockResponse:
-            def __init__(self, json_data, status_code):
-                self.json_data = json_data
-                self.status_code = status_code
-                self.text = str(json_data)
-
-            def json(self):
-                return self.json_data
-        if '/decause' in kwargs['url']:
-            data = {
-                "current": 1,
-                "decrements": 0,
-                "increments": 1,
-                "release": "f24",
-                "total": 1,
-                "username": "decause"
-            }
-            return MockResponse(json_data=data, status_code=200)
-
-        return MockResponse({}, 404)
-
-    @mock.patch('requests.get', side_effect=mocked_requests_get)
-    def test_plus_plus_get_valid(self, mock_get):
-        url = '/plus_plus/decause/status'
-        result = self.app.get(url)
-        expected = {
-            "current": 0,
-            "decrements": 0,
-            "increments": 0,
-            "release": "f24",
-            "total": 0,
-            "username": "decause"
-        }
-        self.assertEqual(
-            json.loads(result.get_data(as_text=True)),
-            expected)
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_valid(self, mock_post):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/plus_plus/decause/update'
-            result = self.app.post(url, data={'increment': True})
-            expected = {
-                "current": 1,
-                "decrements": 0,
-                "increments": 1,
-                "release": "f24",
-                "total": 1,
-                "username": "decause"
-            }
-            self.assertEqual(
-                json.loads(result.get_data(as_text=True)),
-                expected)
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_myself_error(self, mock_post):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/plus_plus/ralph/update'
-            result = self.app.post(url, data={'increment': True})
-            self.assertEqual(result.status_code, 403)
-            self.assertEqual(
-                result.get_data(as_text=True),
-                'You may not modify your own karma.')
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/plus_plus/doesnotexist/update'
-            result = self.app.post(url, data={'increment': True})
-            self.assertEqual(result.status_code, 403)
-            self.assertEqual(
-                result.get_data(as_text=True),
-                'User does not exist')
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_no_data_error(self, mock_post):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/plus_plus/decause/update'
-            result = self.app.post(url, data={})
-            self.assertEqual(result.status_code, 403)
-            exp_str = "You must set 'decrement' or 'increment' " \
-                      "with a boolean value in the body"
-            self.assertEqual(result.get_data(as_text=True), exp_str)
-
-    def test_plus_plus_receiver_does_not_exist(self):
-        url = '/plus_plus/doesnotexist/status'
-        result = self.app.get(url)
-        self.assertEqual(result.status_code, 403)
-        self.assertEqual(result.get_data(as_text=True), 'User does not exist')
diff --git a/hubs/tests/test_widgets/test_contact.py b/hubs/tests/test_widgets/test_contact.py
new file mode 100644
index 0000000..d338e18
--- /dev/null
+++ b/hubs/tests/test_widgets/test_contact.py
@@ -0,0 +1,158 @@
+from __future__ import unicode_literals
+
+import flask
+import hubs
+import json
+
+from hubs.models import Hub, Widget
+from hubs.tests import APPTest, FakeAuthorization, auth_set
+from hubs.tests.test_widgets import WidgetTest
+from mock import mock
+
+
+def mocked_requests_get(*args, **kwargs):
+    class MockResponse:  # flake8: noqa
+        def __init__(self, json_data, status_code):
+            self.json_data = json_data
+            self.status_code = status_code
+            self.text = str(json_data)
+        def json(self):
+            return self.json_data
+
+    if '/decause' in args[0]:
+        data = {
+            "current": 0,
+            "decrements": 0,
+            "increments": 0,
+            "release": "f24",
+            "total": 0,
+            "username": "decause"
+        }
+        return MockResponse(json_data=data, status_code=200)
+
+    return MockResponse({}, 404)
+
+def mocked_requests_post(*args, **kwargs):
+    class MockResponse:
+        def __init__(self, json_data, status_code):
+            self.json_data = json_data
+            self.status_code = status_code
+            self.text = str(json_data)
+
+        def json(self):
+            return self.json_data
+    if '/decause' in kwargs['url']:
+        data = {
+            "current": 1,
+            "decrements": 0,
+            "increments": 1,
+            "release": "f24",
+            "total": 1,
+            "username": "decause"
+        }
+        return MockResponse(json_data=data, status_code=200)
+
+    return MockResponse({}, 404)
+
+
+class ContactsTest(APPTest):
+
+    plugin = "contact"
+
+    def setUp(self):
+        super(ContactsTest, self).setUp()
+        hub = Hub.by_name('ralph')
+        widget = Widget(
+            plugin='contact',
+            index=1,
+        )
+        hub.widgets.append(widget)
+        self.session.commit()
+        self.widget_idx = widget.idx
+
+    @mock.patch('requests.get', side_effect=mocked_requests_get)
+    def test_plus_plus_get_valid(self, mock_get):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
+            self.widget_idx, "decause")
+        result = self.app.get(url)
+        expected = {
+            "current": 0,
+            "decrements": 0,
+            "increments": 0,
+            "release": "f24",
+            "total": 0,
+            "username": "decause"
+        }
+        self.assertEqual(result.status_code, 200)
+        self.assertEqual(
+            json.loads(result.get_data(as_text=True)),
+            expected)
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_valid(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "decause")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={'increment': True})
+            expected = {
+                "current": 1,
+                "decrements": 0,
+                "increments": 1,
+                "release": "f24",
+                "total": 1,
+                "username": "decause"
+            }
+            self.assertEqual(result.status_code, 200)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                expected)
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_myself_error(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "ralph")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={'increment': True})
+            self.assertEqual(result.status_code, 403)
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'You may not modify your own karma.')
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "doesnotexist")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={'increment': True})
+            self.assertEqual(result.status_code, 403)
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'User does not exist')
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_no_data_error(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "decause")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={})
+            self.assertEqual(result.status_code, 403)
+            exp_str = "You must set 'decrement' or 'increment' " \
+                      "with a boolean value in the body"
+            self.assertEqual(result.get_data(as_text=True), exp_str)
+
+    def test_plus_plus_receiver_does_not_exist(self):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
+            self.widget_idx, "doesnotexist")
+        result = self.app.get(url)
+        self.assertEqual(result.status_code, 403)
+        self.assertEqual(result.get_data(as_text=True), 'User does not exist')
diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
index 1c97db4..f3d8a0c 100644
--- a/hubs/views/__init__.py
+++ b/hubs/views/__init__.py
@@ -5,4 +5,3 @@ from .hub import *
 from .widget import *
 from .user import *
 from .api import *
-from .plus_plus import *
diff --git a/hubs/views/plus_plus.py b/hubs/views/plus_plus.py
deleted file mode 100644
index 4e25746..0000000
--- a/hubs/views/plus_plus.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from __future__ import unicode_literals, absolute_import
-
-import flask
-import requests
-import six
-import hubs.models
-
-from hubs.app import app, session
-from .utils import login_required
-
-
-# These views should be converted to widget-specific views, now that we can do
-# that.
-
-
-@app.route('/plus_plus/<user>/status', methods=['GET'])
-def plus_plus_status(user):
-    receiver = hubs.models.User.by_username(user)
-    if not receiver:
-        return 'User does not exist', 403
-    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
-    req = None
-    try:
-        req = requests.get(pp_url)
-    except:
-        flask.abort(500)
-    if req.status_code == 200:
-        return flask.jsonify(req.json())
-    else:
-        return req.text, req.status_code
-
-
-def plus_plus_update_bool_helper(val):
-    if isinstance(val, bool):
-        return val
-    elif isinstance(val, six.string_types):
-        fmt_str = str(val).replace("'", "").replace('"', '').lower()
-        return fmt_str in ("yes", "true", "t", "1")
-    else:
-        raise ValueError
-
-
-@app.route('/plus_plus/<user>/update', methods=['POST'])
-@login_required
-def plus_plus_update(user):
-    receiver = hubs.models.User.by_username(user)
-
-    if not receiver:
-        return 'User does not exist', 403
-
-    if user == flask.g.auth.nickname:
-        return 'You may not modify your own karma.', 403
-
-    if 'decrement' not in flask.request.form \
-            and 'increment' not in flask.request.form:
-        return "You must set 'decrement' or 'increment' " \
-               "with a boolean value in the body", 403
-
-    update = 'increment' if 'increment' in flask.request.form else 'decrement'
-
-    update_bool_val = plus_plus_update_bool_helper(flask.request.form[update])
-    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
-    sender = hubs.models.User.by_username(flask.g.auth.nickname)
-    pp_token = app.config['PLUS_PLUS_TOKEN']
-    auth_header = {'Authorization': 'token {}'.format(pp_token)}
-    data = {'sender': sender.username, update: update_bool_val}
-    req = None
-    try:
-        req = requests.post(url=pp_url, headers=auth_header, data=data)
-    except:
-        flask.abort(500)
-
-    if req.status_code == 200:
-        return flask.jsonify(req.json())
-    else:
-        return req.text, req.status_code
-
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index f5e5722..43df3b4 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -1,12 +1,14 @@
 from __future__ import unicode_literals
 
-import flask
-
 import fedmsg.config
 import fedmsg.meta
+import flask
 import hubs.models
+import requests
+import six
 
 from hubs.widgets.base import Widget, WidgetView
+from hubs.views.utils import login_required
 
 config = fedmsg.config.load_config()
 
@@ -35,7 +37,9 @@ class BaseView(WidgetView):
             usergroup = True
             user = hubs.models.User.by_username(hub.name)
             email = user.username + '@fedoraproject.org'
-            karma_url = flask.url_for('plus_plus_status', user=user.username)
+            karma_url = flask.url_for(
+                'contact_plus_plus_status',
+                hub=hub.name, idx=instance.idx, user=user.username)
             fas_info = {
                 'usergroup': usergroup,
                 'location': 'United States',
@@ -71,3 +75,86 @@ class BaseView(WidgetView):
                 'wikilink': wikilink,
             }
         return fas_info
+
+
+def _get_pp_url(username):
+    pp_url = flask.current_app.config['PLUS_PLUS_URL']
+    if not pp_url.endswith("/"):
+        pp_url += "/"
+    pp_url += username
+    return pp_url
+
+
+class PlusPlusStatus(WidgetView):
+
+    name = "plus_plus_status"
+    url_rules = ["/plus-plus/<user>/status"]
+
+    def dispatch_request(self, *args, **kwargs):
+        username = kwargs["user"]
+        receiver = hubs.models.User.by_username(username)
+        if not receiver:
+            return 'User does not exist', 403
+        pp_url = _get_pp_url(username)
+        req = None
+        try:
+            req = requests.get(pp_url)
+        except:
+            flask.abort(500)
+        if req.status_code == 200:
+            return flask.jsonify(req.json())
+        else:
+            return req.text, req.status_code
+
+
+def _pp_update_bool_helper(val):
+    if isinstance(val, bool):
+        return val
+    elif isinstance(val, six.string_types):
+        fmt_str = str(val).replace("'", "").replace('"', '').lower()
+        return fmt_str in ("yes", "true", "t", "1")
+    else:
+        raise ValueError
+
+
+class PlusPlusUpdate(WidgetView):
+
+    name = "plus_plus_update"
+    url_rules = ["/plus-plus/<user>/update"]
+    methods = ['POST']
+    decorators = [login_required]
+
+    def dispatch_request(self, *args, **kwargs):
+        username = kwargs["user"]
+        receiver = hubs.models.User.by_username(username)
+        if not receiver:
+            return 'User does not exist', 403
+
+        if username == flask.g.auth.nickname:
+            return 'You may not modify your own karma.', 403
+
+        if 'decrement' not in flask.request.form \
+                and 'increment' not in flask.request.form:
+            return "You must set 'decrement' or 'increment' " \
+                   "with a boolean value in the body", 403
+
+        update = ('increment' if 'increment' in flask.request.form
+                  else 'decrement')
+
+        update_bool_val = _pp_update_bool_helper(
+            flask.request.form[update])
+        pp_url = _get_pp_url(username)
+        sender = hubs.models.User.by_username(flask.g.auth.nickname)
+        pp_token = flask.current_app.config['PLUS_PLUS_TOKEN']
+        auth_header = {'Authorization': 'token {}'.format(pp_token)}
+        data = {'sender': sender.username, update: update_bool_val}
+        req = None
+        try:
+            req = requests.post(url=pp_url, headers=auth_header, data=data)
+        except:
+            flask.abort(500)
+
+        if req.status_code == 200:
+            return flask.jsonify(req.json())
+        else:
+            return req.text, req.status_code

From 6b50a07bd5326b37cc9ded125b5b669fb1353903 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 04 2017 08:45:28 +0000
Subject: [PATCH 777/1001] Add a simple test for the contact widget base view


---

diff --git a/hubs/tests/test_widgets/test_contact.py b/hubs/tests/test_widgets/test_contact.py
index d338e18..ae92f87 100644
--- a/hubs/tests/test_widgets/test_contact.py
+++ b/hubs/tests/test_widgets/test_contact.py
@@ -70,6 +70,22 @@ class ContactsTest(APPTest):
         self.session.commit()
         self.widget_idx = widget.idx
 
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        response = self.app.get('/ralph/%i/json' % widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data['data'], {
+            'account_age': 'Oct 2010',
+            'email': 'ralph@fedoraproject.org',
+            'ircnick': 'ralph',
+            'karma_url': '/ralph/w/contact/%i/plus-plus/ralph/status'
+                         % widget.idx,
+            'location': 'United States',
+            'timezone': 'UTC',
+            'usergroup': True,
+        })
+
     @mock.patch('requests.get', side_effect=mocked_requests_get)
     def test_plus_plus_get_valid(self, mock_get):
         widget = self.widget_instance("ralph", self.plugin)

From d0a3e63c8ec74c9313f407c25c5944d57600dd90 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 04 2017 08:46:52 +0000
Subject: [PATCH 778/1001] Move the alembic conf and migrations inside the package


They must be distributed with the package to allow admins to upgrade
their databases.

---

diff --git a/MANIFEST.in b/MANIFEST.in
index 44ebdab..caa39a2 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,2 +1,5 @@
 include requirements.txt
 include test-requirements.txt
+include hubs/alembic.ini
+recursive-include hubs/migrations *.py *.mako *.rst
+include hubs/migrations/versions/.keep
diff --git a/alembic.ini b/alembic.ini
deleted file mode 100644
index 305672c..0000000
--- a/alembic.ini
+++ /dev/null
@@ -1,68 +0,0 @@
-# A generic, single database configuration.
-
-[alembic]
-# path to migration scripts
-script_location = alembic
-
-# template used to generate migration files
-# file_template = %%(rev)s_%%(slug)s
-
-# max length of characters to apply to the
-# "slug" field
-#truncate_slug_length = 40
-
-# set to 'true' to run the environment during
-# the 'revision' command, regardless of autogenerate
-# revision_environment = false
-
-# set to 'true' to allow .pyc and .pyo files without
-# a source .py file to be detected as revisions in the
-# versions/ directory
-# sourceless = false
-
-# version location specification; this defaults
-# to alembic/versions.  When using multiple version
-# directories, initial revisions must be specified with --version-path
-# version_locations = %(here)s/bar %(here)s/bat alembic/versions
-
-# the output encoding used when revision files
-# are written from script.py.mako
-output_encoding = utf-8
-
-sqlalchemy.url = driver://user:pass@localhost/dbname
-
-
-# Logging configuration
-[loggers]
-keys = root,sqlalchemy,alembic
-
-[handlers]
-keys = console
-
-[formatters]
-keys = generic
-
-[logger_root]
-level = WARN
-handlers = console
-qualname =
-
-[logger_sqlalchemy]
-level = WARN
-handlers =
-qualname = sqlalchemy.engine
-
-[logger_alembic]
-level = INFO
-handlers =
-qualname = alembic
-
-[handler_console]
-class = StreamHandler
-args = (sys.stderr,)
-level = NOTSET
-formatter = generic
-
-[formatter_generic]
-format = %(levelname)-5.5s [%(name)s] %(message)s
-datefmt = %H:%M:%S
diff --git a/alembic/README.rst b/alembic/README.rst
deleted file mode 100644
index 5b7a3d1..0000000
--- a/alembic/README.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-Generic single-database configuration of Alembic.
-
-Consult `the documentation <http://alembic.zzzcomputing.com/en/latest/>`_ for
-details on how to write new database migrations. In particular, you should be
-aware of the Alembic `autogenerate
-<http://alembic.zzzcomputing.com/en/latest/autogenerate.html>`_ feature which
-you can use with ``alembic revision --autogenerate -m "<migration description>"``
diff --git a/alembic/env.py b/alembic/env.py
deleted file mode 100644
index 058378b..0000000
--- a/alembic/env.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from __future__ import with_statement
-from alembic import context
-from sqlalchemy import engine_from_config, pool
-from logging.config import fileConfig
-
-# this is the Alembic Config object, which provides
-# access to the values within the .ini file in use.
-config = context.config
-
-# Interpret the config file for Python logging.
-# This line sets up loggers basically.
-fileConfig(config.config_file_name)
-
-# add your model's MetaData object here
-# for 'autogenerate' support
-# from myapp import mymodel
-# target_metadata = mymodel.Base.metadata
-target_metadata = None
-
-# other values from the config, defined by the needs of env.py,
-# can be acquired:
-# my_important_option = config.get_main_option("my_important_option")
-# ... etc.
-
-
-def run_migrations_offline():
-    """Run migrations in 'offline' mode.
-
-    This configures the context with just a URL
-    and not an Engine, though an Engine is acceptable
-    here as well.  By skipping the Engine creation
-    we don't even need a DBAPI to be available.
-
-    Calls to context.execute() here emit the given string to the
-    script output.
-
-    """
-    url = config.get_main_option("sqlalchemy.url")
-    context.configure(
-        url=url, target_metadata=target_metadata, literal_binds=True)
-
-    with context.begin_transaction():
-        context.run_migrations()
-
-
-def run_migrations_online():
-    """Run migrations in 'online' mode.
-
-    In this scenario we need to create an Engine
-    and associate a connection with the context.
-
-    """
-    connectable = engine_from_config(
-        config.get_section(config.config_ini_section),
-        prefix='sqlalchemy.',
-        poolclass=pool.NullPool)
-
-    with connectable.connect() as connection:
-        context.configure(
-            connection=connection,
-            target_metadata=target_metadata
-        )
-
-        with context.begin_transaction():
-            context.run_migrations()
-
-if context.is_offline_mode():
-    run_migrations_offline()
-else:
-    run_migrations_online()
diff --git a/alembic/script.py.mako b/alembic/script.py.mako
deleted file mode 100644
index 7df1d1e..0000000
--- a/alembic/script.py.mako
+++ /dev/null
@@ -1,40 +0,0 @@
-# -*- coding: utf-8 -*-
-# This Alembic database migration is part of the Fedora Hubs project.
-# Copyright (C) <year>  <name of author>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-"""
-${message}
-
-Revision ID: ${up_revision}
-Revises: ${down_revision | comma,n}
-Create Date: ${create_date}
-"""
-from alembic import op
-import sqlalchemy as sa
-${imports if imports else ""}
-
-# revision identifiers, used by Alembic.
-revision = ${repr(up_revision)}
-down_revision = ${repr(down_revision)}
-branch_labels = ${repr(branch_labels)}
-depends_on = ${repr(depends_on)}
-
-
-def upgrade():
-    ${upgrades if upgrades else "pass"}
-
-
-def downgrade():
-    ${downgrades if downgrades else "pass"}
diff --git a/hubs/alembic.ini b/hubs/alembic.ini
new file mode 100644
index 0000000..8b365d8
--- /dev/null
+++ b/hubs/alembic.ini
@@ -0,0 +1,68 @@
+# A generic, single database configuration.
+
+[alembic]
+# path to migration scripts
+script_location = %(here)s/migrations
+
+# template used to generate migration files
+# file_template = %%(rev)s_%%(slug)s
+
+# max length of characters to apply to the
+# "slug" field
+#truncate_slug_length = 40
+
+# set to 'true' to run the environment during
+# the 'revision' command, regardless of autogenerate
+# revision_environment = false
+
+# set to 'true' to allow .pyc and .pyo files without
+# a source .py file to be detected as revisions in the
+# versions/ directory
+# sourceless = false
+
+# version location specification; this defaults
+# to alembic/versions.  When using multiple version
+# directories, initial revisions must be specified with --version-path
+# version_locations = %(here)s/bar %(here)s/bat alembic/versions
+
+# the output encoding used when revision files
+# are written from script.py.mako
+output_encoding = utf-8
+
+#sqlalchemy.url = driver://user:pass@localhost/dbname
+
+
+# Logging configuration
+[loggers]
+keys = root,sqlalchemy,alembic
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARN
+handlers = console
+qualname =
+
+[logger_sqlalchemy]
+level = WARN
+handlers =
+qualname = sqlalchemy.engine
+
+[logger_alembic]
+level = INFO
+handlers =
+qualname = alembic
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
diff --git a/hubs/migrations/README.rst b/hubs/migrations/README.rst
new file mode 100644
index 0000000..06c25e5
--- /dev/null
+++ b/hubs/migrations/README.rst
@@ -0,0 +1,9 @@
+Generic single-database configuration of Alembic.
+
+Consult `the documentation <http://alembic.zzzcomputing.com/en/latest/>`_ for
+details on how to write new database migrations. In particular, you should be
+aware of the Alembic `autogenerate
+<http://alembic.zzzcomputing.com/en/latest/autogenerate.html>`_ feature which
+you can use with::
+
+    alembic -c hubs/alembic.ini revision --autogenerate -m "<migration description>"
diff --git a/hubs/migrations/env.py b/hubs/migrations/env.py
new file mode 100644
index 0000000..058378b
--- /dev/null
+++ b/hubs/migrations/env.py
@@ -0,0 +1,70 @@
+from __future__ import with_statement
+from alembic import context
+from sqlalchemy import engine_from_config, pool
+from logging.config import fileConfig
+
+# this is the Alembic Config object, which provides
+# access to the values within the .ini file in use.
+config = context.config
+
+# Interpret the config file for Python logging.
+# This line sets up loggers basically.
+fileConfig(config.config_file_name)
+
+# add your model's MetaData object here
+# for 'autogenerate' support
+# from myapp import mymodel
+# target_metadata = mymodel.Base.metadata
+target_metadata = None
+
+# other values from the config, defined by the needs of env.py,
+# can be acquired:
+# my_important_option = config.get_main_option("my_important_option")
+# ... etc.
+
+
+def run_migrations_offline():
+    """Run migrations in 'offline' mode.
+
+    This configures the context with just a URL
+    and not an Engine, though an Engine is acceptable
+    here as well.  By skipping the Engine creation
+    we don't even need a DBAPI to be available.
+
+    Calls to context.execute() here emit the given string to the
+    script output.
+
+    """
+    url = config.get_main_option("sqlalchemy.url")
+    context.configure(
+        url=url, target_metadata=target_metadata, literal_binds=True)
+
+    with context.begin_transaction():
+        context.run_migrations()
+
+
+def run_migrations_online():
+    """Run migrations in 'online' mode.
+
+    In this scenario we need to create an Engine
+    and associate a connection with the context.
+
+    """
+    connectable = engine_from_config(
+        config.get_section(config.config_ini_section),
+        prefix='sqlalchemy.',
+        poolclass=pool.NullPool)
+
+    with connectable.connect() as connection:
+        context.configure(
+            connection=connection,
+            target_metadata=target_metadata
+        )
+
+        with context.begin_transaction():
+            context.run_migrations()
+
+if context.is_offline_mode():
+    run_migrations_offline()
+else:
+    run_migrations_online()
diff --git a/hubs/migrations/script.py.mako b/hubs/migrations/script.py.mako
new file mode 100644
index 0000000..46b3b54
--- /dev/null
+++ b/hubs/migrations/script.py.mako
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# This Alembic database migration is part of the Fedora Hubs project.
+# Copyright (C) <year>  <name of author>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+${message}
+
+Revision ID: ${up_revision}
+Revises: ${down_revision | comma,n}
+Create Date: ${create_date}
+"""
+
+from __future__ import absolute_import, unicode_literals
+
+from alembic import op
+import sqlalchemy as sa
+${imports if imports else ""}
+
+# revision identifiers, used by Alembic.
+revision = ${repr(up_revision)}
+down_revision = ${repr(down_revision)}
+branch_labels = ${repr(branch_labels)}
+depends_on = ${repr(depends_on)}
+
+
+def upgrade():
+    ${upgrades if upgrades else "pass"}
+
+
+def downgrade():
+    ${downgrades if downgrades else "pass"}
diff --git a/hubs/migrations/versions/.keep b/hubs/migrations/versions/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/migrations/versions/.keep

From c90f8593a505a39840642a67a84cce0b20d00789 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 04 2017 08:46:52 +0000
Subject: [PATCH 779/1001] Read the database config and metadata from hubs itself


---

diff --git a/hubs/migrations/env.py b/hubs/migrations/env.py
index 058378b..7605ce5 100644
--- a/hubs/migrations/env.py
+++ b/hubs/migrations/env.py
@@ -1,8 +1,25 @@
-from __future__ import with_statement
+from __future__ import absolute_import, unicode_literals
+
 from alembic import context
-from sqlalchemy import engine_from_config, pool
+from sqlalchemy import create_engine, pool
 from logging.config import fileConfig
 
+
+import fedmsg.config
+
+fedmsg_config = fedmsg.config.load_config()
+
+
+try:
+    import hubs
+except ImportError:
+    import os, sys
+    if "hubs" not in os.listdir("."):
+        raise
+    sys.path.append(os.getcwd())
+
+from hubs.models import BASE
+
 # this is the Alembic Config object, which provides
 # access to the values within the .ini file in use.
 config = context.config
@@ -11,11 +28,8 @@ config = context.config
 # This line sets up loggers basically.
 fileConfig(config.config_file_name)
 
-# add your model's MetaData object here
-# for 'autogenerate' support
-# from myapp import mymodel
-# target_metadata = mymodel.Base.metadata
-target_metadata = None
+url = fedmsg_config['hubs.sqlalchemy.uri']
+target_metadata = BASE.metadata
 
 # other values from the config, defined by the needs of env.py,
 # can be acquired:
@@ -35,7 +49,6 @@ def run_migrations_offline():
     script output.
 
     """
-    url = config.get_main_option("sqlalchemy.url")
     context.configure(
         url=url, target_metadata=target_metadata, literal_binds=True)
 
@@ -50,11 +63,7 @@ def run_migrations_online():
     and associate a connection with the context.
 
     """
-    connectable = engine_from_config(
-        config.get_section(config.config_ini_section),
-        prefix='sqlalchemy.',
-        poolclass=pool.NullPool)
-
+    connectable = create_engine(url, poolclass=pool.NullPool)
     with connectable.connect() as connection:
         context.configure(
             connection=connection,

From 3596487a50ea7a92106ae56b072b03922b3e9ee1 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 04 2017 08:46:53 +0000
Subject: [PATCH 780/1001] Adjust the MANIFEST.in file so that sdist is valid


---

diff --git a/.gitignore b/.gitignore
index b3b67a9..ce06a7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ fedmsg.d/fas_credentials.py
 fedmsg.d/credentials.py
 node*
 build/
+dist/
 scratch/
 
 npm-debug.log
diff --git a/MANIFEST.in b/MANIFEST.in
index caa39a2..c533ed4 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,12 @@
-include requirements.txt
-include test-requirements.txt
+include *.txt LICENSE *.py *.sh *.ini
 include hubs/alembic.ini
+graft hubs/static
+prune hubs/static/client/node_modules
+recursive-include hubs/templates *.html
 recursive-include hubs/migrations *.py *.mako *.rst
 include hubs/migrations/versions/.keep
+include hubs/actions.json
+graft ansible
+graft docs
+prune docs/_build
+recursive-include fedmsg.d *.py

From b4052c2617f7f202300ebbf6e4db23341ba15d63 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 04 2017 08:54:36 +0000
Subject: [PATCH 781/1001] Stamp the DB with the Alembic revision on creation


---

diff --git a/hubs/migrations/env.py b/hubs/migrations/env.py
index 7605ce5..e00d82b 100644
--- a/hubs/migrations/env.py
+++ b/hubs/migrations/env.py
@@ -20,13 +20,13 @@ except ImportError:
 
 from hubs.models import BASE
 
-# this is the Alembic Config object, which provides
+# This is the Alembic Config object, which provides
 # access to the values within the .ini file in use.
-config = context.config
-
-# Interpret the config file for Python logging.
-# This line sets up loggers basically.
-fileConfig(config.config_file_name)
+# The config_file_name property may be None when used programatically.
+if context.config.config_file_name is not None:
+    # Interpret the config file for Python logging.
+    # This line sets up loggers basically.
+    fileConfig(context.config.config_file_name)
 
 url = fedmsg_config['hubs.sqlalchemy.uri']
 target_metadata = BASE.metadata
diff --git a/hubs/migrations/versions/.keep b/hubs/migrations/versions/.keep
deleted file mode 100644
index e69de29..0000000
--- a/hubs/migrations/versions/.keep
+++ /dev/null
diff --git a/hubs/migrations/versions/26cc11577009_initial_empty_revision.py b/hubs/migrations/versions/26cc11577009_initial_empty_revision.py
new file mode 100644
index 0000000..d142330
--- /dev/null
+++ b/hubs/migrations/versions/26cc11577009_initial_empty_revision.py
@@ -0,0 +1,39 @@
+# This Alembic database migration is part of the Fedora Hubs project.
+# Copyright (C) 2017  Fedora project
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Initial empty revision.  It does nothing, to the database except allowing
+Alembic to record a revision.
+
+Revision ID: 26cc11577009
+Revises: None
+Create Date: 2017-03-04 09:20:55.915068
+"""
+
+from __future__ import absolute_import, unicode_literals
+
+
+revision = '26cc11577009'
+down_revision = None
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    pass
+
+
+def downgrade():
+    pass
diff --git a/hubs/models.py b/hubs/models.py
index 2b7b6d5..23d4f14 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -32,6 +32,9 @@ import random
 import bleach
 import dogpile
 import sqlalchemy as sa
+
+from alembic import command as alembic_command
+from alembic.config import Config as AlembicConfig
 from sqlalchemy import create_engine
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.orm import sessionmaker
@@ -93,6 +96,11 @@ def init(db_url, debug=False, create=False):
 
     if create:
         BASE.metadata.create_all(engine)
+        # Stamp the database with the lastest Alembic revision:
+        # http://alembic.zzzcomputing.com/en/latest/cookbook.html#building-an-up-to-date-database-from-scratch
+        alembic_cfg = AlembicConfig()
+        alembic_cfg.set_main_option("script_location", "hubs:migrations")
+        alembic_command.stamp(alembic_cfg, "head")
     session = scoped_session(sessionmaker(bind=engine))
     BASE.query = session.query_property()
     return session

From 336f277e14456a403cb52202a25da891dbcd70de Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 04 2017 08:54:36 +0000
Subject: [PATCH 782/1001] Enable foreign keys constraints on SQLite


---

diff --git a/hubs/models.py b/hubs/models.py
index 23d4f14..d9f7a00 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -93,6 +93,8 @@ def init(db_url, debug=False, create=False):
 
     """
     engine = create_engine(db_url, echo=debug)
+    if engine.name == "sqlite":
+        engine.execute("PRAGMA foreign_keys=ON")
 
     if create:
         BASE.metadata.create_all(engine)

From 3fa6eddfd8839d3df8751d1e139cc8b12971ff79 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 07 2017 17:27:01 +0000
Subject: [PATCH 783/1001] Implement review suggestions by @jcline


---

diff --git a/hubs/tests/test_widgets/test_contact.py b/hubs/tests/test_widgets/test_contact.py
index ae92f87..a934c38 100644
--- a/hubs/tests/test_widgets/test_contact.py
+++ b/hubs/tests/test_widgets/test_contact.py
@@ -1,13 +1,14 @@
 from __future__ import unicode_literals
 
-import flask
-import hubs
 import json
 
+import flask
+import mock
+
+import hubs
 from hubs.models import Hub, Widget
 from hubs.tests import APPTest, FakeAuthorization, auth_set
 from hubs.tests.test_widgets import WidgetTest
-from mock import mock
 
 
 def mocked_requests_get(*args, **kwargs):
@@ -147,7 +148,7 @@ class ContactsTest(APPTest):
         user = FakeAuthorization('ralph')
         with auth_set(hubs.app.app, user):
             result = self.app.post(url, data={'increment': True})
-            self.assertEqual(result.status_code, 403)
+            self.assertEqual(result.status_code, 404)
             self.assertEqual(
                 result.get_data(as_text=True),
                 'User does not exist')
@@ -160,7 +161,7 @@ class ContactsTest(APPTest):
         user = FakeAuthorization('ralph')
         with auth_set(hubs.app.app, user):
             result = self.app.post(url, data={})
-            self.assertEqual(result.status_code, 403)
+            self.assertEqual(result.status_code, 400)
             exp_str = "You must set 'decrement' or 'increment' " \
                       "with a boolean value in the body"
             self.assertEqual(result.get_data(as_text=True), exp_str)
@@ -170,5 +171,5 @@ class ContactsTest(APPTest):
         url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
             self.widget_idx, "doesnotexist")
         result = self.app.get(url)
-        self.assertEqual(result.status_code, 403)
+        self.assertEqual(result.status_code, 404)
         self.assertEqual(result.get_data(as_text=True), 'User does not exist')
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index 43df3b4..90a9e0c 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -94,13 +94,9 @@ class PlusPlusStatus(WidgetView):
         username = kwargs["user"]
         receiver = hubs.models.User.by_username(username)
         if not receiver:
-            return 'User does not exist', 403
+            return 'User does not exist', 404
         pp_url = _get_pp_url(username)
-        req = None
-        try:
-            req = requests.get(pp_url)
-        except:
-            flask.abort(500)
+        req = requests.get(pp_url, timeout=5)
         if req.status_code == 200:
             return flask.jsonify(req.json())
         else:
@@ -128,7 +124,7 @@ class PlusPlusUpdate(WidgetView):
         username = kwargs["user"]
         receiver = hubs.models.User.by_username(username)
         if not receiver:
-            return 'User does not exist', 403
+            return 'User does not exist', 404
 
         if username == flask.g.auth.nickname:
             return 'You may not modify your own karma.', 403
@@ -136,7 +132,7 @@ class PlusPlusUpdate(WidgetView):
         if 'decrement' not in flask.request.form \
                 and 'increment' not in flask.request.form:
             return "You must set 'decrement' or 'increment' " \
-                   "with a boolean value in the body", 403
+                   "with a boolean value in the body", 400
 
         update = ('increment' if 'increment' in flask.request.form
                   else 'decrement')
@@ -148,12 +144,8 @@ class PlusPlusUpdate(WidgetView):
         pp_token = flask.current_app.config['PLUS_PLUS_TOKEN']
         auth_header = {'Authorization': 'token {}'.format(pp_token)}
         data = {'sender': sender.username, update: update_bool_val}
-        req = None
-        try:
-            req = requests.post(url=pp_url, headers=auth_header, data=data)
-        except:
-            flask.abort(500)
-
+        req = requests.post(
+            url=pp_url, headers=auth_header, data=data, timeout=5)
         if req.status_code == 200:
             return flask.jsonify(req.json())
         else:

From 3f5d038a96c29bf523241059cf5970143098892e Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Mar 07 2017 17:29:34 +0000
Subject: [PATCH 784/1001] Merge #332 `Move some code around in the Javascript components`


---

diff --git a/hubs/models.py b/hubs/models.py
index d9f7a00..70a3043 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -284,11 +284,6 @@ class Hub(BASE):
              if w.plugin in hubs.widgets.registry and not w.left],
             key=lambda w: w.index)
 
-    @property
-    def widgets_idx(self):
-        """Returns the list of indices for this hub's widgets."""
-        return [w.idx for w in self.widgets]
-
     def __json__(self):
         return {
             'name': self.name,
diff --git a/hubs/static/client/.eslintrc.json b/hubs/static/client/.eslintrc.json
index 62ca52c..434bab5 100644
--- a/hubs/static/client/.eslintrc.json
+++ b/hubs/static/client/.eslintrc.json
@@ -1,9 +1,8 @@
 {
-  "extends": "airbnb",
   "rules": {
     "arrow-body-style": "off",
-    "func-names": "off"
+    "func-names": "off",
     "react/prefer-stateless-function": "off",
-    "react/prop-types": "off",
+    "react/prop-types": "off"
   }
 }
diff --git a/hubs/static/client/app/__tests__/Feed.test.js b/hubs/static/client/app/__tests__/Feed.test.js
index ae93f29..76daf32 100644
--- a/hubs/static/client/app/__tests__/Feed.test.js
+++ b/hubs/static/client/app/__tests__/Feed.test.js
@@ -1,11 +1,11 @@
 /* eslint-env jasmine, jest */
 
-jest.unmock('../components/Feed.jsx');
+jest.unmock('../widgets/feed/Feed.jsx');
 
 import React from 'react';
 import TestUtils from 'react-addons-test-utils';
 
-import Feed from '../components/Feed.jsx';
+import Feed from '../widgets/feed/Feed.jsx';
 
 describe('Feed', () => {
   const matches = [{
diff --git a/hubs/static/client/app/components/Feed.jsx b/hubs/static/client/app/components/Feed.jsx
deleted file mode 100644
index b196bdb..0000000
--- a/hubs/static/client/app/components/Feed.jsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-
-import Panel from './Panel.jsx';
-
-export default class Feed extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {
-      matches: this.props.matches,
-      messageLimit: this.props.options.messageLimit,
-      sse: true,
-    };
-    // If it wasn't instantiated with a url or an error happened, bail
-    if (!this.props.url || !this.state.sse) {
-      return;
-    }
-    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : null;
-    if (!this.source) {
-      return;
-    }
-    this.source.addEventListener('error', () => {
-      this.state.sse = false;
-    }, false);
-    window.onbeforeunload = () => {
-      this.source.close();
-    };
-    this.source.onmessage = resp => {
-      const data = JSON.parse(resp.data);
-      if (this.state.matches.length >= this.state.messageLimit) {
-        this.state.matches.pop();
-      }
-      this.state.matches.unshift(data);
-      this.setState({ matches: this.state.matches });
-    };
-  }
-  render() {
-    const feedNodes = this.state.matches.map((match, idx) => {
-      return <Panel match={match} options={this.props.options || {}} key={idx} />;
-    });
-    return (
-      <div>
-        {feedNodes}
-      </div>
-    );
-  }
-}
-
-window.Feed = Feed;
-window.React = React;
-window.ReactDOM = ReactDOM;
diff --git a/hubs/static/client/app/index.jsx b/hubs/static/client/app/index.jsx
deleted file mode 100644
index 7641684..0000000
--- a/hubs/static/client/app/index.jsx
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This import is needed even though it's not used
- * since the feed component places itself on window.
- * The feed will not work without it.
- */
-import Feed from './components/Feed.jsx'; // eslint-disable-line
diff --git a/hubs/static/client/app/widgets/feed/Feed.jsx b/hubs/static/client/app/widgets/feed/Feed.jsx
new file mode 100644
index 0000000..beec5f7
--- /dev/null
+++ b/hubs/static/client/app/widgets/feed/Feed.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import Panel from '../../components/Panel.jsx';
+
+
+class Feed extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      matches: this.props.matches,
+      messageLimit: this.props.options.messageLimit,
+      sse: true,
+    };
+    // If it wasn't instantiated with a url or an error happened, bail
+    if (!this.props.url || !this.state.sse) {
+      return;
+    }
+    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : null;
+    if (!this.source) {
+      return;
+    }
+    this.source.addEventListener('error', () => {
+      this.state.sse = false;
+    }, false);
+    window.onbeforeunload = () => {
+      this.source.close();
+    };
+    this.source.onmessage = resp => {
+      const data = JSON.parse(resp.data);
+      if (this.state.matches.length >= this.state.messageLimit) {
+        this.state.matches.pop();
+      }
+      this.state.matches.unshift(data);
+      this.setState({ matches: this.state.matches });
+    };
+  }
+
+  render() {
+    const feedNodes = this.state.matches.map((match, idx) => {
+      return <Panel match={match} options={this.props.options || {}} key={idx} />;
+    });
+    return (
+      <div>
+        {feedNodes}
+      </div>
+    );
+  }
+
+}
+
+// Don't use the ES6 "export default" construct:
+// http://stackoverflow.com/questions/40294870/module-exports-vs-export-default-in-node-js-and-es6
+module.exports = Feed
diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
index 065ce2f..f97606a 100644
--- a/hubs/static/client/webpack.config.js
+++ b/hubs/static/client/webpack.config.js
@@ -3,16 +3,22 @@ const path = require('path');
 
 const PATHS = {
     app: path.join(__dirname, 'app'),
-    build: path.join(__dirname, '../js')
+    build: path.join(__dirname, '..', 'js', 'build')
 };
 
 const config = {
     entry: {
-        app: path.join(PATHS.app, 'index.jsx')
+        Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.jsx'),
     },
     output: {
         path: PATHS.build,
-        filename: 'hubs.js'
+        filename: '[name].js',
+        library: '[name]',
+    },
+    externals: {
+        'jquery': 'jQuery',
+        'react': 'React',
+        'react-dom': 'ReactDOM',
     },
     module : {
         loaders : [{
@@ -21,7 +27,8 @@ const config = {
             exclude: /(node_modules|bowercomponents)/,
             include : PATHS.app
         }]
-    }
+    },
+    plugins: [ new webpack.optimize.CommonsChunkPlugin("common.js") ]
 };
 
 module.exports = config;
diff --git a/hubs/static/js/build/.gitignore b/hubs/static/js/build/.gitignore
new file mode 100644
index 0000000..a6c7c28
--- /dev/null
+++ b/hubs/static/js/build/.gitignore
@@ -0,0 +1 @@
+*.js
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index de71ed6..8f73175 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -199,6 +199,8 @@
 {{ super() }}
 <script type="text/javascript" src="{{
   url_for('static', filename='js/utils.js') }}"></script>
+<script type="text/javascript"
+  src ="{{url_for('static', filename='js/build/common.js')}}"></script>
 
 {% if edit %}
 <script type="text/javascript" src="{{
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index e02081b..a44178a 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -61,6 +61,8 @@
   url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script type="text/javascript" src="{{
   url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
+<script src="https://unpkg.com/react@15/dist/react.min.js"></script>
+<script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script>
 {% endblock %}
 
 </body>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 8586d2a..e33c301 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -66,60 +66,63 @@
 
 {% block jscripts %}
 {{ super() }}
-<script type="text/javascript"
-  src ="{{url_for('static', filename='js/hubs.js')}}"></script>
 <script type="text/javascript" src="{{
   url_for('static', filename='js/utils.js') }}"></script>
+<script type="text/javascript"
+  src ="{{url_for('static', filename='js/build/common.js')}}"></script>
+<script type="text/javascript"
+  src ="{{url_for('static', filename='js/build/Feed.js')}}"></script>
 <script>
+  function setup_feeds(actions, saved, saveUrl) {
+    var streamFeed = React.createElement(Feed, {
+      matches: actions,
+      options: {
+        saveUrl: saveUrl,
+        messageLimit: 100
+      }
+    });
+    /* Right now, stream and actions are the same.
+     * Once, Mentions is implemented, then each will be its own
+     */
+    ReactDOM.render(streamFeed, document.getElementById('streamFeed'));
+    ReactDOM.render(streamFeed, document.getElementById('actionsFeed'));
+  
+    var savedFeed = React.createElement(Feed, {
+      matches: saved,
+      url: false,
+      options: {
+        messageLimit: 100,
+        delete: true,
+        saveUrl: saveUrl
+      }
+    });
+    ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
+    $('a[href="#saved"]').on('shown.bs.tab', function(){
+      $.get(saveUrl).done(function(resp) {
+        if (resp.length != saved.length) {
+          ReactDOM.unmountComponentAtNode(document.getElementById('savedFeed'));
+          var savedFeed = React.createElement(Feed, {
+            matches: resp,
+            url: false,
+            options: {
+              messageLimit: 100,
+              delete: true,
+              saveUrl: saveUrl
+            }
+          });
+          ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
+        }
+      });
+    });
+  }
 
- function setup_feeds() {
-   var actions = {{actions|safe}};
-
-   var streamFeed = React.createElement(Feed, {
-     matches: actions,
-     options: {
-       saveUrl: '/{{hub.name}}/notifications/',
-       messageLimit: 100
-     }
-   });
-   /* Right now, stream and actions are the same.
-    * Once, Mentions is implemented, then each will be its own
-    */
-   ReactDOM.render(streamFeed, document.getElementById('streamFeed'));
-   ReactDOM.render(streamFeed, document.getElementById('actionsFeed'));
-
-   var savedFeed = React.createElement(Feed, {
-     matches: {{saved|safe}},
-     url: false,
-     options: {
-       messageLimit: 100,
-       delete: true,
-       saveUrl: '/{{hub.name}}/notifications/'
-     }
-   });
-   ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
-   $('a[href="#saved"]').on('shown.bs.tab', function(){
-     $.get('/{{hub.name}}/notifications/').done(function(resp) {
-       var saved = {{saved|safe}};
-       if (resp.length != saved.length) {
-         ReactDOM.unmountComponentAtNode(document.getElementById('savedFeed'));
-         var savedFeed = React.createElement(Feed, {
-           matches: resp,
-           url: false,
-           options: {
-             messageLimit: 100,
-             delete: true,
-             saveUrl: '/{{hub.name}}/notifications/'
-           }
-         });
-         ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
-       }
-     });
-   });
- }
  $(function() {
    setup_widgets();
-   setup_feeds();
+   setup_feeds(
+       {{ actions|safe }},
+       {{ saved|safe }},
+       {{ url_for("notifications", user=hub.name)|tojson }}
+   );
  });
 </script>
 {% endblock %}
diff --git a/hubs/widgets/feed/templates/feed.html b/hubs/widgets/feed/templates/feed.html
index 3f3bc87..151ed47 100644
--- a/hubs/widgets/feed/templates/feed.html
+++ b/hubs/widgets/feed/templates/feed.html
@@ -5,17 +5,17 @@
 </div>
 
 <script type="text/javascript"
-        src ="{{url_for('static', filename='js/hubs.js')}}"></script>
+  src ="{{url_for('static', filename='js/build/Feed.js')}}"></script>
 <script>
- (function() {
-   const FeedElement = React.createElement(Feed, {
-     matches: {{ matches }},
-     url: '{{ feed_url }}',
-     options: {
-       messageLimit: {{ message_limit }}
-     }
-   });
-   ReactDOM.render(FeedElement, document.getElementById('feed'));
- })();
+(function() {
+    const FeedElement = React.createElement(Feed, {
+        matches: {{ matches }},
+        url: '{{ feed_url }}',
+        options: {
+            messageLimit: {{ message_limit }}
+        }
+    });
+    ReactDOM.render(FeedElement, document.getElementById('feed'));
+})();
 </script>
 {% endblock %}

From 8471f0efaa5fc14a8cea2a04771723c58884ae52 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 08 2017 13:44:24 +0000
Subject: [PATCH 785/1001] Contact: return a specific error on timeouts


---

diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index 90a9e0c..37b4b1c 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -96,7 +96,10 @@ class PlusPlusStatus(WidgetView):
         if not receiver:
             return 'User does not exist', 404
         pp_url = _get_pp_url(username)
-        req = requests.get(pp_url, timeout=5)
+        try:
+            req = requests.get(pp_url, timeout=5)
+        except requests.Timeout:
+            return 'The request to {url} timed out'.format(url=pp_url), 504
         if req.status_code == 200:
             return flask.jsonify(req.json())
         else:
@@ -144,8 +147,11 @@ class PlusPlusUpdate(WidgetView):
         pp_token = flask.current_app.config['PLUS_PLUS_TOKEN']
         auth_header = {'Authorization': 'token {}'.format(pp_token)}
         data = {'sender': sender.username, update: update_bool_val}
-        req = requests.post(
-            url=pp_url, headers=auth_header, data=data, timeout=5)
+        try:
+            req = requests.post(
+                url=pp_url, headers=auth_header, data=data, timeout=5)
+        except requests.Timeout:
+            return 'The request to {url} timed out'.format(url=pp_url), 504
         if req.status_code == 200:
             return flask.jsonify(req.json())
         else:

From 125034ac0b4e873dd0de2f60b38b3f61d24bec61 Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Mar 09 2017 18:06:00 +0000
Subject: [PATCH 786/1001] Merge #333 `Move the plus-plus views to the contact widget`


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 9e66de1..ea33575 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -4,7 +4,6 @@ import unittest
 from six.moves.urllib.parse import urlparse
 
 from flask import json
-from mock import mock
 from werkzeug.datastructures import ImmutableMultiDict
 
 import hubs
@@ -393,120 +392,3 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/source/notexistent'
             result = self.app.get(url)
             self.assertEqual(result.status_code, 404)
-
-    def mocked_requests_get(*args, **kwargs):
-        class MockResponse:  # flake8: noqa
-            def __init__(self, json_data, status_code):
-                self.json_data = json_data
-                self.status_code = status_code
-                self.text = str(json_data)
-            def json(self):
-                return self.json_data
-
-        if '/decause' in args[0]:
-            data = {
-                "current": 0,
-                "decrements": 0,
-                "increments": 0,
-                "release": "f24",
-                "total": 0,
-                "username": "decause"
-            }
-            return MockResponse(json_data=data, status_code=200)
-
-        return MockResponse({}, 404)
-
-    def mocked_requests_post(*args, **kwargs):
-        class MockResponse:
-            def __init__(self, json_data, status_code):
-                self.json_data = json_data
-                self.status_code = status_code
-                self.text = str(json_data)
-
-            def json(self):
-                return self.json_data
-        if '/decause' in kwargs['url']:
-            data = {
-                "current": 1,
-                "decrements": 0,
-                "increments": 1,
-                "release": "f24",
-                "total": 1,
-                "username": "decause"
-            }
-            return MockResponse(json_data=data, status_code=200)
-
-        return MockResponse({}, 404)
-
-    @mock.patch('requests.get', side_effect=mocked_requests_get)
-    def test_plus_plus_get_valid(self, mock_get):
-        url = '/plus_plus/decause/status'
-        result = self.app.get(url)
-        expected = {
-            "current": 0,
-            "decrements": 0,
-            "increments": 0,
-            "release": "f24",
-            "total": 0,
-            "username": "decause"
-        }
-        self.assertEqual(
-            json.loads(result.get_data(as_text=True)),
-            expected)
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_valid(self, mock_post):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/plus_plus/decause/update'
-            result = self.app.post(url, data={'increment': True})
-            expected = {
-                "current": 1,
-                "decrements": 0,
-                "increments": 1,
-                "release": "f24",
-                "total": 1,
-                "username": "decause"
-            }
-            self.assertEqual(
-                json.loads(result.get_data(as_text=True)),
-                expected)
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_myself_error(self, mock_post):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/plus_plus/ralph/update'
-            result = self.app.post(url, data={'increment': True})
-            self.assertEqual(result.status_code, 403)
-            self.assertEqual(
-                result.get_data(as_text=True),
-                'You may not modify your own karma.')
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/plus_plus/doesnotexist/update'
-            result = self.app.post(url, data={'increment': True})
-            self.assertEqual(result.status_code, 403)
-            self.assertEqual(
-                result.get_data(as_text=True),
-                'User does not exist')
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_no_data_error(self, mock_post):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/plus_plus/decause/update'
-            result = self.app.post(url, data={})
-            self.assertEqual(result.status_code, 403)
-            exp_str = "You must set 'decrement' or 'increment' " \
-                      "with a boolean value in the body"
-            self.assertEqual(result.get_data(as_text=True), exp_str)
-
-    def test_plus_plus_receiver_does_not_exist(self):
-        url = '/plus_plus/doesnotexist/status'
-        result = self.app.get(url)
-        self.assertEqual(result.status_code, 403)
-        self.assertEqual(result.get_data(as_text=True), 'User does not exist')
diff --git a/hubs/tests/test_widgets/test_contact.py b/hubs/tests/test_widgets/test_contact.py
new file mode 100644
index 0000000..a934c38
--- /dev/null
+++ b/hubs/tests/test_widgets/test_contact.py
@@ -0,0 +1,175 @@
+from __future__ import unicode_literals
+
+import json
+
+import flask
+import mock
+
+import hubs
+from hubs.models import Hub, Widget
+from hubs.tests import APPTest, FakeAuthorization, auth_set
+from hubs.tests.test_widgets import WidgetTest
+
+
+def mocked_requests_get(*args, **kwargs):
+    class MockResponse:  # flake8: noqa
+        def __init__(self, json_data, status_code):
+            self.json_data = json_data
+            self.status_code = status_code
+            self.text = str(json_data)
+        def json(self):
+            return self.json_data
+
+    if '/decause' in args[0]:
+        data = {
+            "current": 0,
+            "decrements": 0,
+            "increments": 0,
+            "release": "f24",
+            "total": 0,
+            "username": "decause"
+        }
+        return MockResponse(json_data=data, status_code=200)
+
+    return MockResponse({}, 404)
+
+def mocked_requests_post(*args, **kwargs):
+    class MockResponse:
+        def __init__(self, json_data, status_code):
+            self.json_data = json_data
+            self.status_code = status_code
+            self.text = str(json_data)
+
+        def json(self):
+            return self.json_data
+    if '/decause' in kwargs['url']:
+        data = {
+            "current": 1,
+            "decrements": 0,
+            "increments": 1,
+            "release": "f24",
+            "total": 1,
+            "username": "decause"
+        }
+        return MockResponse(json_data=data, status_code=200)
+
+    return MockResponse({}, 404)
+
+
+class ContactsTest(APPTest):
+
+    plugin = "contact"
+
+    def setUp(self):
+        super(ContactsTest, self).setUp()
+        hub = Hub.by_name('ralph')
+        widget = Widget(
+            plugin='contact',
+            index=1,
+        )
+        hub.widgets.append(widget)
+        self.session.commit()
+        self.widget_idx = widget.idx
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        response = self.app.get('/ralph/%i/json' % widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data['data'], {
+            'account_age': 'Oct 2010',
+            'email': 'ralph@fedoraproject.org',
+            'ircnick': 'ralph',
+            'karma_url': '/ralph/w/contact/%i/plus-plus/ralph/status'
+                         % widget.idx,
+            'location': 'United States',
+            'timezone': 'UTC',
+            'usergroup': True,
+        })
+
+    @mock.patch('requests.get', side_effect=mocked_requests_get)
+    def test_plus_plus_get_valid(self, mock_get):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
+            self.widget_idx, "decause")
+        result = self.app.get(url)
+        expected = {
+            "current": 0,
+            "decrements": 0,
+            "increments": 0,
+            "release": "f24",
+            "total": 0,
+            "username": "decause"
+        }
+        self.assertEqual(result.status_code, 200)
+        self.assertEqual(
+            json.loads(result.get_data(as_text=True)),
+            expected)
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_valid(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "decause")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={'increment': True})
+            expected = {
+                "current": 1,
+                "decrements": 0,
+                "increments": 1,
+                "release": "f24",
+                "total": 1,
+                "username": "decause"
+            }
+            self.assertEqual(result.status_code, 200)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                expected)
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_myself_error(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "ralph")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={'increment': True})
+            self.assertEqual(result.status_code, 403)
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'You may not modify your own karma.')
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "doesnotexist")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={'increment': True})
+            self.assertEqual(result.status_code, 404)
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'User does not exist')
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_no_data_error(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "decause")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={})
+            self.assertEqual(result.status_code, 400)
+            exp_str = "You must set 'decrement' or 'increment' " \
+                      "with a boolean value in the body"
+            self.assertEqual(result.get_data(as_text=True), exp_str)
+
+    def test_plus_plus_receiver_does_not_exist(self):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
+            self.widget_idx, "doesnotexist")
+        result = self.app.get(url)
+        self.assertEqual(result.status_code, 404)
+        self.assertEqual(result.get_data(as_text=True), 'User does not exist')
diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
index 1c97db4..f3d8a0c 100644
--- a/hubs/views/__init__.py
+++ b/hubs/views/__init__.py
@@ -5,4 +5,3 @@ from .hub import *
 from .widget import *
 from .user import *
 from .api import *
-from .plus_plus import *
diff --git a/hubs/views/plus_plus.py b/hubs/views/plus_plus.py
deleted file mode 100644
index 4e25746..0000000
--- a/hubs/views/plus_plus.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from __future__ import unicode_literals, absolute_import
-
-import flask
-import requests
-import six
-import hubs.models
-
-from hubs.app import app, session
-from .utils import login_required
-
-
-# These views should be converted to widget-specific views, now that we can do
-# that.
-
-
-@app.route('/plus_plus/<user>/status', methods=['GET'])
-def plus_plus_status(user):
-    receiver = hubs.models.User.by_username(user)
-    if not receiver:
-        return 'User does not exist', 403
-    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
-    req = None
-    try:
-        req = requests.get(pp_url)
-    except:
-        flask.abort(500)
-    if req.status_code == 200:
-        return flask.jsonify(req.json())
-    else:
-        return req.text, req.status_code
-
-
-def plus_plus_update_bool_helper(val):
-    if isinstance(val, bool):
-        return val
-    elif isinstance(val, six.string_types):
-        fmt_str = str(val).replace("'", "").replace('"', '').lower()
-        return fmt_str in ("yes", "true", "t", "1")
-    else:
-        raise ValueError
-
-
-@app.route('/plus_plus/<user>/update', methods=['POST'])
-@login_required
-def plus_plus_update(user):
-    receiver = hubs.models.User.by_username(user)
-
-    if not receiver:
-        return 'User does not exist', 403
-
-    if user == flask.g.auth.nickname:
-        return 'You may not modify your own karma.', 403
-
-    if 'decrement' not in flask.request.form \
-            and 'increment' not in flask.request.form:
-        return "You must set 'decrement' or 'increment' " \
-               "with a boolean value in the body", 403
-
-    update = 'increment' if 'increment' in flask.request.form else 'decrement'
-
-    update_bool_val = plus_plus_update_bool_helper(flask.request.form[update])
-    pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
-    sender = hubs.models.User.by_username(flask.g.auth.nickname)
-    pp_token = app.config['PLUS_PLUS_TOKEN']
-    auth_header = {'Authorization': 'token {}'.format(pp_token)}
-    data = {'sender': sender.username, update: update_bool_val}
-    req = None
-    try:
-        req = requests.post(url=pp_url, headers=auth_header, data=data)
-    except:
-        flask.abort(500)
-
-    if req.status_code == 200:
-        return flask.jsonify(req.json())
-    else:
-        return req.text, req.status_code
-
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index f5e5722..37b4b1c 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -1,12 +1,14 @@
 from __future__ import unicode_literals
 
-import flask
-
 import fedmsg.config
 import fedmsg.meta
+import flask
 import hubs.models
+import requests
+import six
 
 from hubs.widgets.base import Widget, WidgetView
+from hubs.views.utils import login_required
 
 config = fedmsg.config.load_config()
 
@@ -35,7 +37,9 @@ class BaseView(WidgetView):
             usergroup = True
             user = hubs.models.User.by_username(hub.name)
             email = user.username + '@fedoraproject.org'
-            karma_url = flask.url_for('plus_plus_status', user=user.username)
+            karma_url = flask.url_for(
+                'contact_plus_plus_status',
+                hub=hub.name, idx=instance.idx, user=user.username)
             fas_info = {
                 'usergroup': usergroup,
                 'location': 'United States',
@@ -71,3 +75,84 @@ class BaseView(WidgetView):
                 'wikilink': wikilink,
             }
         return fas_info
+
+
+def _get_pp_url(username):
+    pp_url = flask.current_app.config['PLUS_PLUS_URL']
+    if not pp_url.endswith("/"):
+        pp_url += "/"
+    pp_url += username
+    return pp_url
+
+
+class PlusPlusStatus(WidgetView):
+
+    name = "plus_plus_status"
+    url_rules = ["/plus-plus/<user>/status"]
+
+    def dispatch_request(self, *args, **kwargs):
+        username = kwargs["user"]
+        receiver = hubs.models.User.by_username(username)
+        if not receiver:
+            return 'User does not exist', 404
+        pp_url = _get_pp_url(username)
+        try:
+            req = requests.get(pp_url, timeout=5)
+        except requests.Timeout:
+            return 'The request to {url} timed out'.format(url=pp_url), 504
+        if req.status_code == 200:
+            return flask.jsonify(req.json())
+        else:
+            return req.text, req.status_code
+
+
+def _pp_update_bool_helper(val):
+    if isinstance(val, bool):
+        return val
+    elif isinstance(val, six.string_types):
+        fmt_str = str(val).replace("'", "").replace('"', '').lower()
+        return fmt_str in ("yes", "true", "t", "1")
+    else:
+        raise ValueError
+
+
+class PlusPlusUpdate(WidgetView):
+
+    name = "plus_plus_update"
+    url_rules = ["/plus-plus/<user>/update"]
+    methods = ['POST']
+    decorators = [login_required]
+
+    def dispatch_request(self, *args, **kwargs):
+        username = kwargs["user"]
+        receiver = hubs.models.User.by_username(username)
+        if not receiver:
+            return 'User does not exist', 404
+
+        if username == flask.g.auth.nickname:
+            return 'You may not modify your own karma.', 403
+
+        if 'decrement' not in flask.request.form \
+                and 'increment' not in flask.request.form:
+            return "You must set 'decrement' or 'increment' " \
+                   "with a boolean value in the body", 400
+
+        update = ('increment' if 'increment' in flask.request.form
+                  else 'decrement')
+
+        update_bool_val = _pp_update_bool_helper(
+            flask.request.form[update])
+        pp_url = _get_pp_url(username)
+        sender = hubs.models.User.by_username(flask.g.auth.nickname)
+        pp_token = flask.current_app.config['PLUS_PLUS_TOKEN']
+        auth_header = {'Authorization': 'token {}'.format(pp_token)}
+        data = {'sender': sender.username, update: update_bool_val}
+        try:
+            req = requests.post(
+                url=pp_url, headers=auth_header, data=data, timeout=5)
+        except requests.Timeout:
+            return 'The request to {url} timed out'.format(url=pp_url), 504
+        if req.status_code == 200:
+            return flask.jsonify(req.json())
+        else:
+            return req.text, req.status_code

From 2e7190d27d95860869019df434affe9bf3015647 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 09 2017 18:08:13 +0000
Subject: [PATCH 787/1001] Create a table for hub configuration


---

diff --git a/hubs/migrations/versions/1d660b32b83a_hub_config.py b/hubs/migrations/versions/1d660b32b83a_hub_config.py
new file mode 100644
index 0000000..7f2aefb
--- /dev/null
+++ b/hubs/migrations/versions/1d660b32b83a_hub_config.py
@@ -0,0 +1,85 @@
+# This Alembic database migration is part of the Fedora Hubs project.
+# Copyright (C) 2017  The Fedora Project
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Hub config
+
+Revision ID: 1d660b32b83a
+Revises: 26cc11577009
+Create Date: 2017-03-06 18:31:54.574205
+"""
+
+from __future__ import absolute_import, unicode_literals
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '1d660b32b83a'
+down_revision = '26cc11577009'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    op.create_table('hubs_config',
+        sa.Column('id', sa.Integer(), nullable=False),
+        sa.Column('hub_id', sa.String(length=50), nullable=False),
+        sa.Column('summary', sa.String(length=128), nullable=True),
+        sa.Column('left_width', sa.Integer(), nullable=False, server_default="8"),
+        sa.Column('avatar', sa.String(length=256), nullable=True),
+        sa.Column('header_img', sa.String(length=256), nullable=True),
+        sa.ForeignKeyConstraint(['hub_id'], ['hubs.name'], ),
+        sa.PrimaryKeyConstraint('id')
+    )
+    op.execute("""
+        INSERT INTO hubs_config
+            (hub_id, summary, left_width, avatar, header_img)
+        SELECT name, summary, left_width, avatar, header_img FROM hubs
+        """)
+    # http://alembic.zzzcomputing.com/en/latest/batch.html
+    with op.batch_alter_table("hubs") as batch_op:
+        batch_op.drop_column('left_width')
+        batch_op.drop_column('header_img')
+        batch_op.drop_column('summary')
+        batch_op.drop_column('avatar')
+
+
+def downgrade():
+    op.add_column('hubs', sa.Column('avatar', sa.VARCHAR(length=256), nullable=True))
+    op.add_column('hubs', sa.Column('summary', sa.VARCHAR(length=128), nullable=True))
+    op.add_column('hubs', sa.Column('header_img', sa.VARCHAR(length=256), nullable=True))
+    op.add_column('hubs', sa.Column('left_width', sa.INTEGER(), server_default="8", nullable=False))
+    connection = op.get_bind()
+    query = "SELECT hub_id, summary, left_width, avatar, header_img FROM hubs_config"
+    hubs_table = sa.sql.table('hubs',
+        sa.sql.column('name', sa.String),
+        sa.sql.column('summary', sa.String),
+        sa.sql.column('left_width', sa.Integer),
+        sa.sql.column('avatar', sa.String),
+        sa.sql.column('header_img', sa.String),
+    )
+    for row in connection.execute(query):
+        op.execute(hubs_table.update().where(
+            hubs_table.c.name==op.inline_literal(row["hub_id"])
+            ).values({
+                "summary": op.inline_literal(row["summary"]),
+                "left_width": op.inline_literal(row["left_width"]),
+                "avatar": op.inline_literal(row["avatar"]),
+                "header_img": op.inline_literal(row["header_img"]),
+            })
+        )
+    op.drop_table('hubs_config')
diff --git a/hubs/models.py b/hubs/models.py
index 70a3043..ed67911 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -137,17 +137,11 @@ class Association(BASE):
 class Hub(BASE):
     __tablename__ = 'hubs'
     name = sa.Column(sa.String(50), primary_key=True)
-    summary = sa.Column(sa.String(128))
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     widgets = relation('Widget', cascade='all,delete', backref='hub')
-    left_width = sa.Column(sa.Integer, nullable=False, default=8)
+    config = relation('HubConfig', uselist=False, cascade='all,delete', backref='hub')
     archived = sa.Column(sa.Boolean, default=False)
     user_hub = sa.Column(sa.Boolean, default=False)
-
-    # A URL to the "avatar" for this hub.
-    avatar = sa.Column(sa.String(256), default=placekitten)
-    header_img = sa.Column(sa.String(256), default=randomheader)
-
     # Timestamps about various kinds of "freshness"
     last_refreshed = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     last_edited = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
@@ -244,10 +238,11 @@ class Hub(BASE):
 
     @classmethod
     def create_user_hub(cls, session, username, fullname):
-        hub = cls(name=username, summary=fullname,
-                  avatar=username2avatar(username),
-                  user_hub=True)
+        hub = cls(name=username, user_hub=True)
         session.add(hub)
+        hub_config = HubConfig(
+            hub=hub, summary=fullname, avatar=username2avatar(username))
+        session.add(hub_config)
 
         hubs.defaults.add_user_widgets(session, hub, username, fullname)
 
@@ -257,18 +252,19 @@ class Hub(BASE):
 
     @classmethod
     def create_group_hub(cls, session, name, summary, **extra):
-        hub = cls(name=name, summary=summary,
-                  # TODO -- do something else, smarter for group avatars
-                  avatar=username2avatar(name),
-                  user_hub=False)
+        hub = cls(name=name, user_hub=False)
         session.add(hub)
+        # TODO -- do something else, smarter for group avatars
+        hub_config = HubConfig(
+            hub=hub, summary=summary, avatar=username2avatar(name))
+        session.add(hub_config)
 
         hubs.defaults.add_group_widgets(session, hub, name, summary, **extra)
         return hub
 
     @property
     def right_width(self):
-        return 12 - self.left_width
+        return 12 - self.config.left_width
 
     @property
     def left_widgets(self):
@@ -287,11 +283,10 @@ class Hub(BASE):
     def __json__(self):
         return {
             'name': self.name,
-            'summary': self.summary,
-            'avatar': self.avatar,
+            'config': self.config.__json__(),
 
             'widgets': [widget.idx for widget in self.widgets],
-            'left_width': self.left_width,
+            'left_width': self.config.left_width,
 
             'owners': [u.username for u in self.owners],
             'members': [u.username for u in self.members],
@@ -299,7 +294,26 @@ class Hub(BASE):
         }
 
 
-def _config_default(context):
+class HubConfig(BASE):
+    __tablename__ = 'hubs_config'
+    id = sa.Column(sa.Integer, primary_key=True)
+    hub_id = sa.Column(sa.String(50), sa.ForeignKey('hubs.name'),
+                       nullable=False)
+    summary = sa.Column(sa.String(128))
+    left_width = sa.Column(sa.Integer, nullable=False, default=8)
+    # A URL to the "avatar" for this hub.
+    avatar = sa.Column(sa.String(256), default=placekitten)
+    header_img = sa.Column(sa.String(256), default=randomheader)
+
+    def __json__(self):
+        return {
+            'summary': self.summary,
+            'left_width': self.left_width,
+            'avatar': self.avatar,
+        }
+
+
+def _widget_config_default(context):
     widget_name = context.current_parameters['plugin']
     widget = hubs.widgets.registry[widget_name]
     return json.dumps(dict([
@@ -313,7 +327,7 @@ class Widget(BASE):
     plugin = sa.Column(sa.String(50), nullable=False)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     hub_id = sa.Column(sa.String(50), sa.ForeignKey('hubs.name'))
-    _config = sa.Column(sa.String(256), default=_config_default)
+    _config = sa.Column(sa.String(256), default=_widget_config_default)
 
     index = sa.Column(sa.Integer, nullable=False)
     left = sa.Column(sa.Boolean, nullable=False, default=False)
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 8f73175..4dbbf8f 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -36,13 +36,13 @@
         <!-- Left side of header -->
         <div class="col-md-7">
           {% if hub.user_hub %}
-          <img src="{{ hub.avatar }}" class="avatar" />
+          <img src="{{ hub.config.avatar }}" class="avatar" />
           <h2 class="user m-b-0">{{ hub.name }}</h2>
-          <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
+          <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
           <div class="clearfix"></div>
           {% else %}
           <h2 class="team">{{ hub.name }}</h2>
-          <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>
+          <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
           {% endif %}
         </div>
         
@@ -112,7 +112,7 @@
   <div class="row">
     <div class="col-md-offset-2">
       <div class="row">
-        <div class="col-md-{{ hub.left_width }}">
+        <div class="col-md-{{ hub.config.left_width }}">
           <!--
             First, before the proper widgets.. a cobweb built-in widget.
             https://pagure.io/fedora-hubs/issue/133
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index d761381..a3cc5f7 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -65,12 +65,14 @@ class APPTest(unittest.TestCase):
         hub.widgets.append(widget)
 
         for team in ['i18n', 'infra', 'old']:
-            hub = hubs.models.Hub(name=team, summary="the %s team" % team)
+            hub = hubs.models.Hub(name=team)
             if hub.name == 'old':
                 hub.last_refreshed = datetime.utcnow() - timedelta(days=100)
                 hub.last_updated = datetime.utcnow() - timedelta(days=200)
 
             hubs.app.session.add(hub)
+            hubs.app.session.add(
+                hubs.models.HubConfig(hub=hub, summary="the %s team" % team))
             widget = hubs.models.Widget(plugin='meetings', index=11,
                                         _config=json.dumps({'calendar': team}))
             hub.widgets.append(widget)
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index ea33575..340f685 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -70,15 +70,17 @@ class HubsAPITest(hubs.tests.APPTest):
         # assert the status code of the response
         self.assertEqual(result.status_code, 200)
         data = {
-            "avatar": "https://seccdn.libravatar.org/avatar/"
-                      "9c9f7784935381befc302fe3c814f9136e7a339"
-                      "53d0318761669b8643f4df55c?s=312&d=retro",
-            "left_width": 8,
+            "config": {
+                "avatar": "https://seccdn.libravatar.org/avatar/"
+                          "9c9f7784935381befc302fe3c814f9136e7a339"
+                          "53d0318761669b8643f4df55c?s=312&d=retro",
+                "left_width": 8,
+                "summary": "Ralph",
+            },
             "members": ["ralph"],
             "name": "ralph",
             "owners": ["ralph"],
             "subscribers": [],
-            "summary": "Ralph",
             "widgets": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56]
         }
         self.assertDictEqual(data, json.loads(result.get_data(as_text=True)))
diff --git a/populate.py b/populate.py
index 54c119f..5a5d5a2 100755
--- a/populate.py
+++ b/populate.py
@@ -36,9 +36,10 @@ for username in users:
 session.commit()
 
 ############## Internationalizationteam
-hub = hubs.models.Hub(
-    name='i18n', summary='The Internationalization Team', archived=True)
+hub = hubs.models.Hub(name='i18n', archived=True)
 session.add(hub)
+session.add(hubs.models.HubConfig(
+    hub=hub, summary='The Internationalization Team'))
 
 widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)
@@ -82,8 +83,10 @@ hub.subscribe(hubs.models.User.by_username('ralph'), 'subscriber')
 session.commit()
 
 ############## CommOps
-hub = hubs.models.Hub(name='commops', summary='The Fedora Community Operations Team')
+hub = hubs.models.Hub(name='commops')
 session.add(hub)
+session.add(hubs.models.HubConfig(
+    hub=hub, summary='The Fedora Community Operations Team'))
 
 widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)
@@ -129,8 +132,10 @@ hub.subscribe(hubs.models.User.by_username('linuxmodder'), 'member')
 session.commit()
 
 ############## Marketing team
-hub = hubs.models.Hub(name='marketing', summary='The Fedora Marketing Team')
+hub = hubs.models.Hub(name='marketing')
 session.add(hub)
+session.add(hubs.models.HubConfig(
+    hub=hub, summary='The Fedora Marketing Team'))
 
 widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)
@@ -177,8 +182,10 @@ hub.subscribe(hubs.models.User.by_username('ralph'), 'subscriber')
 session.commit()
 
 ############## Design team
-hub = hubs.models.Hub(name='designteam', summary='The Fedora Design Team')
+hub = hubs.models.Hub(name='designteam')
 session.add(hub)
+session.add(hubs.models.HubConfig(
+    hub=hub, summary='The Fedora Design Team'))
 
 widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)
@@ -226,8 +233,10 @@ session.commit()
 
 
 ############## Infra team
-hub = hubs.models.Hub(name='infrastructure', summary='The Fedora Infra Team')
+hub = hubs.models.Hub(name='infrastructure')
 session.add(hub)
+session.add(hubs.models.HubConfig(
+    hub=hub, summary='The Fedora Infra Team'))
 
 widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)

From 5d4e3ae028c5b913b1d9d93074cbde8c82db0ca7 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 09 2017 18:08:13 +0000
Subject: [PATCH 788/1001] Use eager loading for the hub config


---

diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index a4a8b19..65f2449 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -11,7 +11,7 @@ from .utils import get_hub, login_required
 @app.route('/<name>')
 @app.route('/<name>/')
 def hub(name):
-    hub = get_hub(name)
+    hub = get_hub(name, load_config=True)
     return flask.render_template(
         'hubs.html', hub=hub, edit=False)
 
@@ -35,7 +35,7 @@ def hub_edit(name):
 
 
 def hub_edit_get(name):
-    hub = get_hub(name)
+    hub = get_hub(name, load_config=True)
     return flask.render_template(
         'hubs.html', hub=hub, edit=True)
 
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index 31a78d8..733a32a 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -3,23 +3,26 @@ from __future__ import unicode_literals
 import datetime
 import flask
 import functools
-import hubs.models
 import logging
 
+from hubs.models import Hub, Widget
 from six.moves.urllib import parse as urlparse
+from sqlalchemy.orm import joinedload
 from sqlalchemy.orm.exc import NoResultFound
 
 
 log = logging.getLogger(__name__)
 
 
-def get_hub(name, session=None):
+def get_hub(name, load_config=False, session=None):
     """ Utility shorthand to get a hub and 404 if not found. """
     if session is None:
         session = flask.g.db
+    query = session.query(Hub).filter(Hub.name == name)
+    if load_config:
+        query = query.options(joinedload(Hub.config))
     try:
-        return session.query(hubs.models.Hub).filter(
-            hubs.models.Hub.name == name).one()
+        return query.one()
     except NoResultFound:
         flask.abort(404)
 
@@ -33,11 +36,9 @@ def get_widget_instance(hub, idx, session=None):
     except (TypeError, ValueError):
         flask.abort(400)
     try:
-        return session.query(
-                hubs.models.Widget
-            ).join(hubs.models.Hub).filter(
-                hubs.models.Hub.name == hub,
-                hubs.models.Widget.idx == idx,
+        return session.query(Widget).join(Hub).filter(
+                Hub.name == hub,
+                Widget.idx == idx,
             ).one()
     except NoResultFound:
         flask.abort(404)
@@ -55,7 +56,7 @@ def create_widget_instance(hub, widget, position):
         widget (hubs.widgets.base.Widget): Widget to instanciate.
         position (str): either ``left`` or ``right``.
     """
-    widget_instance = hubs.models.Widget(
+    widget_instance = Widget(
         hub=hub, plugin=widget.name, index=-1,
         left=(position == 'left'))
     flask.g.db.add(widget_instance)

From 17b22bacc9451ed32405029c2711128a6af938f4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 09 2017 18:08:13 +0000
Subject: [PATCH 789/1001] Prepare a React component for the hub config panel


---

diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
new file mode 100644
index 0000000..0471611
--- /dev/null
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import Panel from '../components/Panel.jsx';
+
+
+
+export default class HubConfig extends React.Component {
+
+  //constructor(props) {
+  //  super(props);
+  //}
+
+  render() {
+    return (
+      <Panel/>
+    );
+  }
+
+}
+
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/Hubs.js b/hubs/static/client/app/core/Hubs.js
new file mode 100644
index 0000000..87768e9
--- /dev/null
+++ b/hubs/static/client/app/core/Hubs.js
@@ -0,0 +1,3 @@
+import HubConfig from './HubConfig.jsx';
+
+module.exports = {HubConfig}
diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
index f97606a..ba91ad0 100644
--- a/hubs/static/client/webpack.config.js
+++ b/hubs/static/client/webpack.config.js
@@ -8,6 +8,7 @@ const PATHS = {
 
 const config = {
     entry: {
+        Hubs: path.join(PATHS.app, 'core', 'Hubs.js'),
         Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.jsx'),
     },
     output: {

From f3e66ffec3a8fd871ee0b7a3778ac59f38eec04c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 790/1001] Implement the config panel UI


---

diff --git a/hubs/static/client/app/components/Tab.jsx b/hubs/static/client/app/components/Tab.jsx
new file mode 100644
index 0000000..976e04b
--- /dev/null
+++ b/hubs/static/client/app/components/Tab.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+
+
+export default class Tab extends React.Component {
+  render() {
+    return (
+      <li role="presentation">
+        <a href="#" role="tab"
+           className={"nav-link" + (this.props.active ? " active" : "")}
+           onClick={this.props.linkClicked}
+           >
+          {this.props.children}
+        </a>
+      </li>
+    );
+  }
+}
+
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/TabPanel.jsx b/hubs/static/client/app/components/TabPanel.jsx
new file mode 100644
index 0000000..7d3a4ee
--- /dev/null
+++ b/hubs/static/client/app/components/TabPanel.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+
+
+export default class TabPanel extends React.Component {
+  render() {
+    return (
+      <div role="tabpanel"
+           className={"tab-pane" + (this.props.active ? " active" : "")}>
+        {this.props.children}
+      </div>
+    );
+  }
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/TabSet.jsx b/hubs/static/client/app/components/TabSet.jsx
new file mode 100644
index 0000000..df63568
--- /dev/null
+++ b/hubs/static/client/app/components/TabSet.jsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import Tab from './Tab.jsx';
+import TabPanel from './TabPanel.jsx';
+
+
+export default class TabSet extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      activeTab: 0
+    }
+  }
+
+  linkClicked(e, index) {
+    e.preventDefault();
+    this.setState({activeTab: index});
+  }
+
+  render() {
+    var tabLinks = this.props.children.map(function(panel, index) {
+      return (
+        <Tab active={this.state.activeTab === index}
+             linkClicked={(e) => this.linkClicked(e, index)}
+             key={index.toString()}>
+          {panel.props.tabTitle}
+        </Tab>
+        );
+    }.bind(this));
+
+    var tabPanels = this.props.children.map(function(panel, index) {
+      return (
+        <TabPanel
+          active={this.state.activeTab === index}
+          key={index.toString()}>
+          {panel}
+        </TabPanel>
+        );
+    }.bind(this));
+
+    return (
+      <div>
+        <ul role="tablist"
+            className={"nav nav-tabs " + this.props.tabListClass || ""}
+            >
+          {tabLinks}
+        </ul>
+        <div
+          className={"tab-content " + this.props.tabContentClass || ""}
+          >
+          {tabPanels}
+        </div>
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
index 0471611..dcc54d5 100644
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -1,17 +1,216 @@
 import React from 'react';
-import Panel from '../components/Panel.jsx';
+import {
+  IntlProvider,
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import {ChatPanel, NotImplementedPanel} from './HubConfigPanel.jsx';
+import TabSet from '../components/TabSet.jsx';
+
+
+const messages = defineMessages({
+  title: {
+    id: "hubs.core.config.title",
+    defaultMessage: "Hub settings",
+  },
+  general: {
+    id: "hubs.core.config.general",
+    defaultMessage: "General",
+  },
+  owners: {
+    id: "hubs.core.config.owners",
+    defaultMessage: "Owners",
+  },
+  members: {
+    id: "hubs.core.config.members",
+    defaultMessage: "Members",
+  },
+  chat: {
+    id: "hubs.core.config.chat",
+    defaultMessage: "Chat",
+  },
+  other: {
+    id: "hubs.core.config.other",
+    defaultMessage: "Other",
+  },
+  close: {
+    id: "hubs.core.config.close",
+    defaultMessage: "Close",
+  },
+  save_changes: {
+    id: "hubs.core.config.save_changes",
+    defaultMessage: "Save changes",
+  },
+});
 
 
 
 export default class HubConfig extends React.Component {
 
-  //constructor(props) {
-  //  super(props);
-  //}
+  constructor(props) {
+    super(props);
+    this.state = {
+      hubConfig: {},
+      generalConfig: {},
+      error: null,
+      loading: false
+    }
+    this.serverRequest = null;
+    this.handleSubmit = this.handleSubmit.bind(this);
+    this.handleChange = this.handleChange.bind(this);
+    this.loadState = this.loadState.bind(this);
+    this.pushState = this.pushState.bind(this);
+    //this.componentWillUpdate = this.componentWillUpdate.bind(this);
+  }
+
+	loadState() {
+    this.setState({loading: true});
+    this.serverRequest = $.ajax({
+      url: this.props.url,
+      method: 'GET',
+      dataType: 'json',
+      cache: false,
+      success: function(data) {
+        this.setState({
+          hubConfig: data.result.hub,
+          generalConfig: data.result.general,
+          error: null,
+          loading: false
+				});
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.url, status, err.toString());
+        this.setState({
+          error: err.toString(),
+          loading: false
+        });
+      }.bind(this)
+    });
+  }
+
+  pushState() {
+    this.setState({loading: true});
+    this.serverRequest = $.ajax({
+      url: this.props.url,
+      method: 'POST',
+      data: this.state.hubConfig,
+      dataType: 'json',
+      cache: false,
+      success: function(data) {
+        this.setState({
+          hubConfig: data.result.hub,
+          generalConfig: data.result.general,
+          error: null,
+          loading: false
+        });
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.url, status, err.toString());
+        this.setState({
+          error: err.toString(),
+          loading: false
+        });
+      }.bind(this)
+    });
+  }
+
+  handleChange(e) {
+    var config = this.state.hubConfig;
+    config[e.target.name] = e.target.value;
+    this.setState({hubConfig: config});
+  }
+
+  handleSubmit(e) {
+    e.preventDefault();
+    this.pushState();
+  }
+
+	componentDidMount() {
+		this.loadState();
+  }
+
+	componentWillUnmount() {
+		if (this.serverRequest) { this.serverRequest.abort(); }
+  }
 
   render() {
     return (
-      <Panel/>
+      <IntlProvider locale={navigator.language}>
+        <div className="modal-dialog modal-lg" role="document">
+          <div className="modal-content">
+            <form
+              method="post" action={this.props.url}
+              onSubmit={this.handleSubmit}
+              ref={(ref) => this.formDom = ref}
+              >
+              <div className="modal-header">
+                <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 className="modal-title">
+                  <FormattedMessage {...messages.title} />
+                </h4>
+              </div>
+              <div className="modal-body">
+                <div className="row">
+                  <TabSet
+                    tabListClass="col-md-3"
+                    tabContentClass="col-md-9"
+                    >
+                    <NotImplementedPanel
+                      tabTitle={<FormattedMessage {...messages.general} />}
+                      />
+                    <NotImplementedPanel
+                      tabTitle={<FormattedMessage {...messages.owners} />}
+                      />
+                    <NotImplementedPanel
+                      tabTitle={<FormattedMessage {...messages.members} />}
+                      />
+                    <ChatPanel
+                      hubConfig={this.state.hubConfig}
+                      generalConfig={this.state.generalConfig}
+                      tabTitle={<FormattedMessage {...messages.chat} />}
+                      handleChange={this.handleChange}
+                      />
+                    <NotImplementedPanel
+                      tabTitle={<FormattedMessage {...messages.other} />}
+                      />
+                  </TabSet>
+                </div>
+              </div>
+              <div className="modal-footer">
+                <span
+                  className="loading"
+                  style={this.state.loading ? {display: "inline-block"} : {display: "none"}}
+                  ></span>
+                <button
+                  type="button"
+                  className="btn btn-default"
+                  data-dismiss="modal"
+                  disabled={this.state.loading}
+                  >
+                  <FormattedMessage {...messages.close} />
+                </button>
+                <button type="button" className="btn btn-primary"
+                        onClick={this.handleSubmit}>
+                  <FormattedMessage {...messages.save_changes} />
+                </button>
+                { this.state.error &&
+                  <div
+                    className="alert alert-danger" role="alert"
+                    style={{
+                      margin: "0em 1em",
+                      //textAlign: "center",
+                      display: "inline-block",
+                      padding: "0.375rem",
+                      }}
+                    >
+                    { this.state.error }
+                  </div>
+                }
+              </div>
+            </form>
+          </div>
+        </div>
+      </IntlProvider>
     );
   }
 
diff --git a/hubs/static/client/app/core/HubConfigPanel.jsx b/hubs/static/client/app/core/HubConfigPanel.jsx
new file mode 100644
index 0000000..920b184
--- /dev/null
+++ b/hubs/static/client/app/core/HubConfigPanel.jsx
@@ -0,0 +1,115 @@
+import React from 'react';
+import {
+  IntlProvider,
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import TabPanel from '../components/TabPanel.jsx';
+
+
+const messages = defineMessages({
+  chat_title: {
+    id: "hubs.core.config.chat.title",
+    defaultMessage: "Chat Settings",
+  },
+  chat_intro_1: {
+    id: "hubs.core.config.chat.intro1",
+    defaultMessage: "If your team or project has an IRC channel associated with it, you can connect this hub to it via the Hubs chat widget.",
+  },
+  chat_intro_2: {
+    id: "hubs.core.config.chat.intro2",
+    defaultMessage: "Please indicate your team's IRC channel below:",
+  },
+  chat_channel_name: {
+    id: "hubs.core.config.chat.channel_name",
+    defaultMessage: "Channel name",
+  },
+  chat_example: {
+    id: "hubs.core.config.chat.example",
+    defaultMessage: "Example:",
+  },
+  chat_network: {
+    id: "hubs.core.config.chat.network",
+    defaultMessage: "IRC network",
+  },
+});
+
+
+export class NotImplementedPanel extends React.Component {
+
+  render() {
+    return (
+      <div>
+        Not implemented yet.
+      </div>
+    );
+  }
+
+}
+
+export class ChatPanel extends React.Component {
+
+  render() {
+    var networks = [],
+        channel = "#",
+        //stillLoading = (typeof this.props.hubConfig.chat_channel === "undefined");
+        stillLoading = (
+          typeof this.props.generalConfig.chat_networks === "undefined"
+          );
+    if (this.props.hubConfig.chat_channel) {
+      channel = "#" + this.props.hubConfig.chat_channel.replace(/^#*/, "");
+    }
+    if (this.props.generalConfig.chat_networks) {
+      networks = this.props.generalConfig.chat_networks.map(
+        function(network, index) {
+          return (
+            <option value={network.domain} key={network.domain}>
+              {network.name} - {network.domain}
+            </option>
+          );
+        }.bind(this)
+      );
+    }
+    return (
+      <div>
+        <FormattedMessage {...messages.chat_title} tagName="h3" />
+        <FormattedMessage {...messages.chat_intro_1} tagName="p" />
+        <FormattedMessage {...messages.chat_intro_2} tagName="p" />
+        <div className="form-group">
+          <label htmlFor="hub-settings-chat-channel">
+            <FormattedMessage {...messages.chat_channel_name} />
+          </label>
+          <input
+            type="text" className="form-control" name="chat_channel"
+            id="hub-settings-chat-channel"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={channel}
+            />
+          <p className="form-text text-muted">
+            <FormattedMessage {...messages.chat_example} tagName="strong" />
+            <span style={{marginLeft: "0.5em"}}>#fedora-devel</span>
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-chat-domain">
+            <FormattedMessage {...messages.chat_network} />
+          </label>
+          <select
+            name="chat_domain" className="form-control"
+            id="hub-settings-chat-domain"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.chat_domain || ""}
+            >
+            {networks}
+          </select>
+        </div>
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 69171b6..dad75fc 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -96,10 +96,6 @@
         padding-top: .5rem;
     }
 
-    header a, header a:hover, .header a:focus {
-      color: #ffffff;
-    }
-
     header span.edit {
       margin: 5px 5px 0 0;
     }
@@ -135,6 +131,69 @@
       margin-top: 0px;
       margin-bottom: 0px;
     }
+
+
+  .loading {
+      width: 50px;
+      height: 10px;
+      background: url("../img/spinner.gif") no-repeat center center;
+      vertical-align: bottom;
+      display: none;  /* hidden by default */
+  }
+
+/*
+ * Settings
+ */
+
+#settings-modal .modal-title {
+  line-height: 1;
+}
+#settings-modal .modal-body {
+  padding: 0;
+}
+#settings-modal .modal-body > .row {
+  padding-top: 0;
+}
+#settings-modal .nav {
+  border: 0;
+  background-color: #eee;
+  padding: 1.5em 0 2.5em 2em;
+  min-height: 0;
+}
+#settings-modal .nav .nav-link {
+  border: 0;
+  border-radius: 7px 0 0 7px;
+  padding: .4em 1em;
+  outline: 0;
+}
+#settings-modal .modal-body h3 {
+  margin-bottom: 1em;
+}
+#settings-modal .modal-body label {
+  font-size: 115%;
+}
+#settings-modal .modal-body .tab-content {
+  padding: 1em;
+  padding-bottom: 2em;
+}
+
+/* Fixed vertical size to give the appearance of panels. Hackish. Find a CSS expert to do this properly. */
+#settings-modal .nav {
+  min-height: 400px;
+  max-height: 400px;
+}
+#settings-modal .tab-content {
+  min-height: 400px;
+  max-height: 400px;
+  overflow-y: auto;
+}
+
+
+
+/*
+ * Widgets
+ */
+
     .widget-buttons {
       padding: .5rem;
     }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 4dbbf8f..f40282f 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -34,7 +34,7 @@
       <div class="row">
         
         <!-- Left side of header -->
-        <div class="col-md-7">
+        <div class="col-md-{{ hub.config.left_width }}">
           {% if hub.user_hub %}
           <img src="{{ hub.config.avatar }}" class="avatar" />
           <h2 class="user m-b-0">{{ hub.name }}</h2>
@@ -47,9 +47,17 @@
         </div>
         
         <!-- right side of header -->
-        <div class="col-md-3 header-right">
+        <div class="col-md-{{ hub.config.right_width }} header-right">
           {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
+          <button class="btn btn-link" data-toggle="modal" data-target="#settings-modal">
+            <i class="fa fa-cog" aria-hidden="true"></i>
+            hub settings
+          </button>
           {% if not edit %}
+          <a href="{{ url_for('hub_edit', name=hub.name) }}">
+            <i class="fa fa-pencil" aria-hidden="true"></i>
+            edit page layout
+          </a>
           <div class="dropdown edit pull-xs-right showpointer">
             <span class="dropdown-toggle edit-this-page" type="button"
                 id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
@@ -182,10 +190,10 @@
       
     
 </div>
-
       
 
-
+<div id="settings-modal" class="modal fade" tabindex="-1" role="dialog">
+</div>
 
 
 <div id="edit_modal" class="modal fade" role="dialog">
@@ -201,6 +209,8 @@
   url_for('static', filename='js/utils.js') }}"></script>
 <script type="text/javascript"
   src ="{{url_for('static', filename='js/build/common.js')}}"></script>
+<script type="text/javascript"
+  src ="{{url_for('static', filename='js/build/Hubs.js')}}"></script>
 
 {% if edit %}
 <script type="text/javascript" src="{{
@@ -367,11 +377,27 @@ function visit_counter() {
   }
 }
 
+function setup_settings(url) {
+  var modal = $('#settings-modal');
+  var settingsPanel = React.createElement(Hubs.HubConfig, {
+    url: url
+  });
+  modal.on('show.bs.modal', function () {
+    ReactDOM.render(settingsPanel, modal.get(0));
+  })
+  modal.on('hidden.bs.modal', function () {
+    ReactDOM.unmountComponentAtNode(modal.get(0));
+  })
+}
+
 $(function() {
   visit_counter()
   
   setup_widgets();
   setup_edit_btns();
+  setup_settings(
+    {{ url_for("hub_config", name=hub.name)|tojson }}
+    );
   
   {% if edit -%}
   make_widget_sortable();
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 65f2449..128d50a 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -139,3 +139,25 @@ def hub_edit_post(name):
             return ('ok', 200)
     else:
         return flask.redirect(flask.url_for('hub', name=name))
+
+
+@app.route('/<name>/config', methods=['GET', 'POST'])
+@login_required
+def hub_config(name):
+    hub = get_hub(name)
+    config = {
+        "status": "OK",
+        "result": {
+            "hub": hub.name,
+            },
+        }
+    if flask.request.method == 'POST':
+        for key, value in flask.request.form.items():
+            hub.config[key] = value
+        try:
+            flask.g.db.commit()
+        except Exception as err:
+            config = {"status": "ERROR", "message": str(err)}
+            return flask.jsonify(config), 400
+    config["result"].update(hub.config.__json__())
+    return flask.jsonify(config)

From 7c6bcab2990bc15c0a0a0c2da899ed334983ec74 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 791/1001] Implement the config panel backend


---

diff --git a/hubs/default_config.py b/hubs/default_config.py
index 1c50405..688e51c 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -33,6 +33,16 @@ OIDC_SCOPES = [
 #        the right tag to link people to.  AGPL ftw.
 SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'  # /hubs/widgets/badges.py'
 
+CHAT_NETWORKS = [
+    {
+        "name": "Freenode",
+        "domain": "irc.freenode.net",
+    }, {
+        "name": "Matrix",
+        "domain": "matrix.org",
+    }
+]
+
 
 WIDGETS = [
     'hubs.widgets.about:About',
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 128d50a..30d4fb9 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -148,16 +148,22 @@ def hub_config(name):
     config = {
         "status": "OK",
         "result": {
-            "hub": hub.name,
+            "hub": {},
+            "general": {
+                "chat_networks": app.config["CHAT_NETWORKS"],
             },
-        }
+        },
+    }
     if flask.request.method == 'POST':
         for key, value in flask.request.form.items():
-            hub.config[key] = value
+            setattr(hub.config, key, value)
+        if (not flask.request.form["chat_domain"]
+            and len(app.config["CHAT_NETWORKS"]) > 0):
+            hub.config.chat_domain = app.config["CHAT_NETWORKS"][0]["domain"]
         try:
             flask.g.db.commit()
         except Exception as err:
             config = {"status": "ERROR", "message": str(err)}
             return flask.jsonify(config), 400
-    config["result"].update(hub.config.__json__())
+    config["result"]["hub"].update(hub.config.__json__())
     return flask.jsonify(config)

From 15017c9dedc4913de3778ea085fc84bb47c5894b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 792/1001] Add the chat configuration parameters


---

diff --git a/hubs/migrations/versions/6d4862ec4f93_hub_config_chat.py b/hubs/migrations/versions/6d4862ec4f93_hub_config_chat.py
new file mode 100644
index 0000000..c11bbb5
--- /dev/null
+++ b/hubs/migrations/versions/6d4862ec4f93_hub_config_chat.py
@@ -0,0 +1,48 @@
+# This Alembic database migration is part of the Fedora Hubs project.
+# Copyright (C) 2017  The Fedora Project
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Hub configuration for the chat channel.
+
+Revision ID: 6d4862ec4f93
+Revises: 1d660b32b83a
+Create Date: 2017-03-09 16:42:10.556935
+"""
+
+from __future__ import absolute_import, unicode_literals
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '6d4862ec4f93'
+down_revision = '1d660b32b83a'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    op.add_column('hubs_config', sa.Column(
+        'chat_channel', sa.String(length=256), nullable=True))
+    op.add_column('hubs_config', sa.Column(
+        'chat_domain', sa.String(length=256), nullable=True))
+
+
+def downgrade():
+    # http://alembic.zzzcomputing.com/en/latest/batch.html
+    with op.batch_alter_table("hubs_config") as batch_op:
+        batch_op.drop_column('chat_domain')
+        batch_op.drop_column('chat_channel')
diff --git a/hubs/models.py b/hubs/models.py
index ed67911..d833ab0 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -304,12 +304,16 @@ class HubConfig(BASE):
     # A URL to the "avatar" for this hub.
     avatar = sa.Column(sa.String(256), default=placekitten)
     header_img = sa.Column(sa.String(256), default=randomheader)
+    chat_channel = sa.Column(sa.String(256), nullable=True)
+    chat_domain = sa.Column(sa.String(256), nullable=True)
 
     def __json__(self):
         return {
             'summary': self.summary,
             'left_width': self.left_width,
             'avatar': self.avatar,
+            'chat_channel': self.chat_channel,
+            'chat_domain': self.chat_domain,
         }
 
 
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 340f685..2daa6e9 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -74,6 +74,8 @@ class HubsAPITest(hubs.tests.APPTest):
                 "avatar": "https://seccdn.libravatar.org/avatar/"
                           "9c9f7784935381befc302fe3c814f9136e7a339"
                           "53d0318761669b8643f4df55c?s=312&d=retro",
+                'chat_channel': None,
+                'chat_domain': None,
                 "left_width": 8,
                 "summary": "Ralph",
             },

From 0605ba49843f353e7bab6022ef3b7094f0967164 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 793/1001] Implement the General Settings panel


---

diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
index dcc54d5..9040e46 100644
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -4,7 +4,11 @@ import {
   defineMessages,
   FormattedMessage,
   } from 'react-intl';
-import {ChatPanel, NotImplementedPanel} from './HubConfigPanel.jsx';
+import {
+  GeneralPanel,
+  ChatPanel,
+  NotImplementedPanel,
+  } from './HubConfigPanel.jsx';
 import TabSet from '../components/TabSet.jsx';
 
 
@@ -155,8 +159,11 @@ export default class HubConfig extends React.Component {
                     tabListClass="col-md-3"
                     tabContentClass="col-md-9"
                     >
-                    <NotImplementedPanel
+                    <GeneralPanel
+                      hubConfig={this.state.hubConfig}
+                      generalConfig={this.state.generalConfig}
                       tabTitle={<FormattedMessage {...messages.general} />}
+                      handleChange={this.handleChange}
                       />
                     <NotImplementedPanel
                       tabTitle={<FormattedMessage {...messages.owners} />}
diff --git a/hubs/static/client/app/core/HubConfigPanel.jsx b/hubs/static/client/app/core/HubConfigPanel.jsx
index 920b184..4990dd3 100644
--- a/hubs/static/client/app/core/HubConfigPanel.jsx
+++ b/hubs/static/client/app/core/HubConfigPanel.jsx
@@ -8,6 +8,26 @@ import TabPanel from '../components/TabPanel.jsx';
 
 
 const messages = defineMessages({
+  general_title: {
+    id: "hubs.core.config.general.title",
+    defaultMessage: "General Settings",
+  },
+  general_intro: {
+    id: "hubs.core.config.general.intro",
+    defaultMessage: "Change your global hub parameters here.",
+  },
+  general_summary: {
+    id: "hubs.core.config.general.summary",
+    defaultMessage: "Summary",
+  },
+  general_left_width: {
+    id: "hubs.core.config.general.left_width",
+    defaultMessage: "Left width",
+  },
+  general_avatar: {
+    id: "hubs.core.config.general.avatar",
+    defaultMessage: "Avatar",
+  },
   chat_title: {
     id: "hubs.core.config.chat.title",
     defaultMessage: "Chat Settings",
@@ -47,18 +67,72 @@ export class NotImplementedPanel extends React.Component {
 
 }
 
+
+export class GeneralPanel extends React.Component {
+
+  render() {
+    var stillLoading = (typeof this.props.hubConfig.summary === "undefined");
+    return (
+      <div>
+        <FormattedMessage {...messages.general_title} tagName="h3" />
+        <FormattedMessage {...messages.general_intro} tagName="p" />
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-summary">
+            <FormattedMessage {...messages.general_summary} />
+          </label>
+          <input
+            type="text" className="form-control" name="summary"
+            id="hub-settings-general-summary"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.summary}
+            />
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-leftwidth">
+            <FormattedMessage {...messages.general_left_width} />
+          </label>
+          <input
+            type="number" className="form-control" name="left_width"
+            id="hub-settings-general-leftwidth"
+            disabled={stillLoading}
+            min="1" max="11"
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.left_width}
+            />
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-avatar">
+            <FormattedMessage {...messages.general_avatar} />
+          </label>
+          <input
+            type="text" className="form-control" name="avatar"
+            id="hub-settings-general-avatar"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.avatar}
+            />
+        </div>
+      </div>
+    );
+  }
+
+}
+
+
 export class ChatPanel extends React.Component {
 
   render() {
     var networks = [],
         channel = "#",
-        //stillLoading = (typeof this.props.hubConfig.chat_channel === "undefined");
         stillLoading = (
-          typeof this.props.generalConfig.chat_networks === "undefined"
-          );
+          typeof this.props.hubConfig.chat_channel === "undefined"
+        );
+
     if (this.props.hubConfig.chat_channel) {
       channel = "#" + this.props.hubConfig.chat_channel.replace(/^#*/, "");
     }
+
     if (this.props.generalConfig.chat_networks) {
       networks = this.props.generalConfig.chat_networks.map(
         function(network, index) {
@@ -70,6 +144,7 @@ export class ChatPanel extends React.Component {
         }.bind(this)
       );
     }
+
     return (
       <div>
         <FormattedMessage {...messages.chat_title} tagName="h3" />
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index dad75fc..ab51d60 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -164,6 +164,7 @@
   border: 0;
   border-radius: 7px 0 0 7px;
   padding: .4em 1em;
+  margin: 0.5em 0;
   outline: 0;
 }
 #settings-modal .modal-body h3 {

From 107d8fe556c8a308fecb1d03e2e62619be1da46b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 794/1001] Auto-save the settings


---

diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
index 9040e46..346392e 100644
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -56,31 +56,29 @@ export default class HubConfig extends React.Component {
     this.state = {
       hubConfig: {},
       generalConfig: {},
+      dirty: false,
       error: null,
       loading: false
     }
     this.serverRequest = null;
-    this.handleSubmit = this.handleSubmit.bind(this);
     this.handleChange = this.handleChange.bind(this);
     this.loadState = this.loadState.bind(this);
     this.pushState = this.pushState.bind(this);
-    //this.componentWillUpdate = this.componentWillUpdate.bind(this);
   }
 
-	loadState() {
-    this.setState({loading: true});
-    this.serverRequest = $.ajax({
+  getRequestParams() {
+    return {
       url: this.props.url,
-      method: 'GET',
       dataType: 'json',
       cache: false,
       success: function(data) {
         this.setState({
           hubConfig: data.result.hub,
           generalConfig: data.result.general,
+          dirty: false,
           error: null,
           loading: false
-				});
+        });
       }.bind(this),
       error: function(xhr, status, err) {
         console.error(this.props.url, status, err.toString());
@@ -89,52 +87,42 @@ export default class HubConfig extends React.Component {
           loading: false
         });
       }.bind(this)
-    });
+    }
+  }
+
+  loadState() {
+    var params = this.getRequestParams();
+    params.method = "GET";
+    this.setState({loading: true});
+    this.serverRequest = $.ajax(params);
   }
 
   pushState() {
+    var params = this.getRequestParams();
+    params.method = "POST";
+    params.data = this.state.hubConfig;
     this.setState({loading: true});
-    this.serverRequest = $.ajax({
-      url: this.props.url,
-      method: 'POST',
-      data: this.state.hubConfig,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({
-          hubConfig: data.result.hub,
-          generalConfig: data.result.general,
-          error: null,
-          loading: false
-        });
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-        this.setState({
-          error: err.toString(),
-          loading: false
-        });
-      }.bind(this)
-    });
+    this.serverRequest = $.ajax(params);
   }
 
   handleChange(e) {
     var config = this.state.hubConfig;
     config[e.target.name] = e.target.value;
-    this.setState({hubConfig: config});
-  }
-
-  handleSubmit(e) {
-    e.preventDefault();
-    this.pushState();
+    this.setState({
+      hubConfig: config,
+      dirty: true,
+    }, function() {
+      window.clearTimeout(this.pushTimer);
+      this.pushTimer = window.setTimeout(this.pushState, 1000);
+    });
   }
 
-	componentDidMount() {
-		this.loadState();
+  componentDidMount() {
+    this.loadState();
   }
 
-	componentWillUnmount() {
-		if (this.serverRequest) { this.serverRequest.abort(); }
+  componentWillUnmount() {
+    if (this.serverRequest) { this.serverRequest.abort(); }
   }
 
   render() {
@@ -142,13 +130,17 @@ export default class HubConfig extends React.Component {
       <IntlProvider locale={navigator.language}>
         <div className="modal-dialog modal-lg" role="document">
           <div className="modal-content">
-            <form
-              method="post" action={this.props.url}
-              onSubmit={this.handleSubmit}
-              ref={(ref) => this.formDom = ref}
-              >
+            <form method="post" action={this.props.url}>
               <div className="modal-header">
-                <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <button
+                  type="button"
+                  className="close"
+                  data-dismiss="modal"
+                  aria-label="Close"
+                  disabled={this.state.dirty}
+                  >
+                  <span aria-hidden="true">&times;</span>
+                </button>
                 <h4 className="modal-title">
                   <FormattedMessage {...messages.title} />
                 </h4>
@@ -192,14 +184,10 @@ export default class HubConfig extends React.Component {
                   type="button"
                   className="btn btn-default"
                   data-dismiss="modal"
-                  disabled={this.state.loading}
+                  disabled={this.state.dirty}
                   >
                   <FormattedMessage {...messages.close} />
                 </button>
-                <button type="button" className="btn btn-primary"
-                        onClick={this.handleSubmit}>
-                  <FormattedMessage {...messages.save_changes} />
-                </button>
                 { this.state.error &&
                   <div
                     className="alert alert-danger" role="alert"
diff --git a/hubs/static/client/app/core/HubConfigPanel.jsx b/hubs/static/client/app/core/HubConfigPanel.jsx
index 4990dd3..517042f 100644
--- a/hubs/static/client/app/core/HubConfigPanel.jsx
+++ b/hubs/static/client/app/core/HubConfigPanel.jsx
@@ -85,7 +85,7 @@ export class GeneralPanel extends React.Component {
             id="hub-settings-general-summary"
             disabled={stillLoading}
             onChange={this.props.handleChange}
-            value={this.props.hubConfig.summary}
+            value={this.props.hubConfig.summary || ""}
             />
         </div>
         <div className="form-group">
@@ -98,7 +98,7 @@ export class GeneralPanel extends React.Component {
             disabled={stillLoading}
             min="1" max="11"
             onChange={this.props.handleChange}
-            value={this.props.hubConfig.left_width}
+            value={this.props.hubConfig.left_width || ""}
             />
         </div>
         <div className="form-group">
@@ -110,7 +110,7 @@ export class GeneralPanel extends React.Component {
             id="hub-settings-general-avatar"
             disabled={stillLoading}
             onChange={this.props.handleChange}
-            value={this.props.hubConfig.avatar}
+            value={this.props.hubConfig.avatar || ""}
             />
         </div>
       </div>

From 48d74a3d92ee6b9d772809c54de2032be8fc5f4b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 795/1001] Be more careful about what's stored in the DB


---

diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 30d4fb9..253c132 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -155,8 +155,9 @@ def hub_config(name):
         },
     }
     if flask.request.method == 'POST':
-        for key, value in flask.request.form.items():
-            setattr(hub.config, key, value)
+        for key in hub.config.__json__():
+            # Security: don't save every key in the POST.
+            setattr(hub.config, key, flask.request.form[key])
         if (not flask.request.form["chat_domain"]
             and len(app.config["CHAT_NETWORKS"]) > 0):
             hub.config.chat_domain = app.config["CHAT_NETWORKS"][0]["domain"]

From e717a1e50ea5499ed50e1084b30c68d84d955bdb Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 796/1001] Pass the props when instantiating the panel


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f40282f..c33c5fe 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -377,11 +377,9 @@ function visit_counter() {
   }
 }
 
-function setup_settings(url) {
+function setup_settings(props) {
   var modal = $('#settings-modal');
-  var settingsPanel = React.createElement(Hubs.HubConfig, {
-    url: url
-  });
+  var settingsPanel = React.createElement(Hubs.HubConfig, props);
   modal.on('show.bs.modal', function () {
     ReactDOM.render(settingsPanel, modal.get(0));
   })
@@ -392,13 +390,13 @@ function setup_settings(url) {
 
 $(function() {
   visit_counter()
-  
+
   setup_widgets();
   setup_edit_btns();
-  setup_settings(
-    {{ url_for("hub_config", name=hub.name)|tojson }}
-    );
-  
+  setup_settings({
+    url: {{ url_for("hub_config", name=hub.name)|tojson }},
+  });
+
   {% if edit -%}
   make_widget_sortable();
   setup_add_btns();

From ac409e439a807f4ee4890c40334cad183489703a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 797/1001] Move the right_width property along with the config


---

diff --git a/hubs/models.py b/hubs/models.py
index d833ab0..4102eeb 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -263,10 +263,6 @@ class Hub(BASE):
         return hub
 
     @property
-    def right_width(self):
-        return 12 - self.config.left_width
-
-    @property
     def left_widgets(self):
         return sorted(
             [w for w in self.widgets
@@ -286,7 +282,6 @@ class Hub(BASE):
             'config': self.config.__json__(),
 
             'widgets': [widget.idx for widget in self.widgets],
-            'left_width': self.config.left_width,
 
             'owners': [u.username for u in self.owners],
             'members': [u.username for u in self.members],
@@ -316,6 +311,10 @@ class HubConfig(BASE):
             'chat_domain': self.chat_domain,
         }
 
+    @property
+    def right_width(self):
+        return 12 - self.left_width
+
 
 def _widget_config_default(context):
     widget_name = context.current_parameters['plugin']
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index c33c5fe..9f055f1 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -166,7 +166,7 @@
           {% include "includes/left_widgets.html" %}
         </div>
 
-        <div class="col-md-{{ hub.right_width }}">
+        <div class="col-md-{{ hub.config.right_width }}">
           {% if edit %}
           <div id='add-widget-right' class='widget row'>
             <div class="card">

From b100fdde9ecd6ba4e30eb149f89f83b091866977 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 798/1001] Reload the page when the config changed


---

diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
index 346392e..73cbc7a 100644
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -57,6 +57,7 @@ export default class HubConfig extends React.Component {
       hubConfig: {},
       generalConfig: {},
       dirty: false,
+      mustReload: false,  // the settings were changed at least once
       error: null,
       loading: false
     }
@@ -111,6 +112,7 @@ export default class HubConfig extends React.Component {
     this.setState({
       hubConfig: config,
       dirty: true,
+      mustReload: true,
     }, function() {
       window.clearTimeout(this.pushTimer);
       this.pushTimer = window.setTimeout(this.pushState, 1000);
@@ -123,6 +125,12 @@ export default class HubConfig extends React.Component {
 
   componentWillUnmount() {
     if (this.serverRequest) { this.serverRequest.abort(); }
+    if (this.state.mustReload) {
+      // The configuration was changed but the current display may not
+      // reflect it (for example, the displayed summary may be the old one).
+      // The only way to make the changes visible is to reload the page.
+      window.location = window.location;
+    }
   }
 
   render() {

From 2ceaa1d57de480472fc77fae3cf56eab5492cac1 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 799/1001] Improve the display of the edit links


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 9f055f1..231b364 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -49,42 +49,23 @@
         <!-- right side of header -->
         <div class="col-md-{{ hub.config.right_width }} header-right">
           {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
-          <button class="btn btn-link" data-toggle="modal" data-target="#settings-modal">
-            <i class="fa fa-cog" aria-hidden="true"></i>
-            hub settings
-          </button>
-          {% if not edit %}
-          <a href="{{ url_for('hub_edit', name=hub.name) }}">
-            <i class="fa fa-pencil" aria-hidden="true"></i>
-            edit page layout
-          </a>
-          <div class="dropdown edit pull-xs-right showpointer">
-            <span class="dropdown-toggle edit-this-page" type="button"
-                id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
-                aria-expanded="true">
-              <span><i class="fa fa-pencil" aria-hidden="true"></i></span> edit this page
-            </span>
-            <div class="dropdown-menu" aria-labelledby="dropdownMenu2">
-              <a class="dropdown-item" href="#">Customize Header</a>
-              <div class="dropdown-divider"></div>
-              <a class="dropdown-item"
-                href="{{ url_for('hub_edit', name=hub.name) }}">
-                Configure Hub
-              </a>
-              {% if not hub.user_hub %}
-              <div class="dropdown-divider"></div>
-                <a class="dropdown-item" href="#">Manage Members</a>
-                <div class="dropdown-divider"></div>
-                <a class="dropdown-item" href="#">Archive Hub</a>
-              {% endif %}
-            </div>
+          <div style="text-align:center">
+            <button class="btn btn-secondary" data-toggle="modal" data-target="#settings-modal">
+              <i class="fa fa-cog" aria-hidden="true"></i>
+              hub settings
+            </button>
+            {% if not edit %}
+            <a href="{{ url_for('hub_edit', name=hub.name) }}" class="btn btn-secondary">
+              <i class="fa fa-pencil" aria-hidden="true"></i>
+              edit page layout
+            </a>
+            {% else %}
+            <button class="btn btn-primary" href="#" id="save_edits_btn">
+              <i class="fa fa-download" aria-hidden="true"></i>
+              Save changes
+            </button>
+            {% endif %}
           </div>
-          {% else %}
-          <div id="save_edits_btn" class="pull-xs-right">
-            <span><i class="fa fa-download" aria-hidden="true"></i></span>
-            Save changes
-          </div>
-          {% endif %}
           {% endif %}
         </div>
         
@@ -300,7 +281,8 @@ function setup_add_btns() {
   });
 }
 
-$('#save_edits_btn').click(function() {
+$('#save_edits_btn').click(function(e) {
+  e.preventDefault();
   var _r_indexes = [];
   var _r_widgets = [];
   $.each($('#right_widgets .widget'), function(i, el) {

From 4dba2f0e367c0d3adf1dc1027d9e6dd213eccd9b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 10 2017 18:12:49 +0000
Subject: [PATCH 800/1001] Don't use the minified version in DEBUG mode


---

diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index a44178a..57dc7a5 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -61,8 +61,8 @@
   url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script type="text/javascript" src="{{
   url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
-<script src="https://unpkg.com/react@15/dist/react.min.js"></script>
-<script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script>
+<script src="https://unpkg.com/react@15/dist/react{% if not config.DEBUG %}.min{% endif %}.js"></script>
+<script src="https://unpkg.com/react-dom@15/dist/react-dom{% if not config.DEBUG %}.min{% endif %}.js"></script>
 {% endblock %}
 
 </body>

From 2824cfc6f1bd6e207e1be8ede4307063a3b6d6af Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 15 2017 11:12:40 +0000
Subject: [PATCH 801/1001] Test the config view


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 2daa6e9..442a4e9 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -396,3 +396,46 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/source/notexistent'
             result = self.app.get(url)
             self.assertEqual(result.status_code, 404)
+
+    def test_hub_config_get(self):
+        expected = {
+            "hub": {
+                "summary": "Ralph",
+                "left_width": 8,
+                "avatar": (
+                    "https://seccdn.libravatar.org/avatar/9c9f7784935381befc30"
+                    "2fe3c814f9136e7a33953d0318761669b8643f4df55c?s=312&d=retro"
+                    ),
+                "chat_channel": None,
+                "chat_domain": None,
+            },
+            "general": {
+                "chat_networks": app.config["CHAT_NETWORKS"],
+            },
+        }
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/ralph/config'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertDictEqual(result_data["result"], expected)
+
+    def test_hub_config_post(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/ralph/config'
+            result = self.app.post(url, data={
+                "summary": "changed value",
+                "chat_domain": "",
+            })
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertEqual(
+            result_data["result"]["hub"]["summary"],
+            "changed value")
+        self.assertEqual(
+            result_data["result"]["hub"]["chat_domain"],
+            app.config["CHAT_NETWORKS"][0]["domain"])
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 253c132..2477056 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -157,6 +157,8 @@ def hub_config(name):
     if flask.request.method == 'POST':
         for key in hub.config.__json__():
             # Security: don't save every key in the POST.
+            if key not in flask.request.form:
+                continue
             setattr(hub.config, key, flask.request.form[key])
         if (not flask.request.form["chat_domain"]
             and len(app.config["CHAT_NETWORKS"]) > 0):

From c3de81049b9b6f438fbc5a40a26498c4c3192aea Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 15 2017 16:49:23 +0000
Subject: [PATCH 802/1001] Create a validator class for POST data


---

diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 442a4e9..006f99e 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -439,3 +439,42 @@ class HubsAPITest(hubs.tests.APPTest):
         self.assertEqual(
             result_data["result"]["hub"]["chat_domain"],
             app.config["CHAT_NETWORKS"][0]["domain"])
+
+    def test_hub_config_post_unknown_post_data(self):
+        # Unknown POST data is silently ignored
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/ralph/config'
+            result = self.app.post(url, data={"non_existant": "dummy"})
+        self.assertEqual(result.status_code, 400)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "ERROR")
+        self.assertEqual(result_data["message"], "Invalid value(s)")
+        self.assertIn("non_existant", result_data["fields"])
+        self.assertEqual(
+            result_data["fields"]["non_existant"],
+            "Unexpected parameter."
+            )
+
+    def test_hub_config_post_invalid_chat_domain(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/ralph/config'
+            result = self.app.post(url, data={"chat_domain": "dummy"})
+        self.assertEqual(result.status_code, 400)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "ERROR")
+        self.assertEqual(result_data["message"], "Invalid value(s)")
+        self.assertIn("chat_domain", result_data["fields"])
+        self.assertEqual(
+            result_data["fields"]["chat_domain"],
+            "Unsupported chat domain."
+            )
+
+    @unittest.skip("Authorization layer not present yet")
+    def test_hub_config_unauthorized(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/decause/config'
+            result = self.app.post(url, data={"summary": "Defaced!"})
+        self.assertEqual(result.status_code, 403)
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 2477056..3534c70 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -5,7 +5,7 @@ import flask
 import hubs.models
 
 from hubs.app import app, session
-from .utils import get_hub, login_required
+from .utils import get_hub, login_required, RequestValidator
 
 
 @app.route('/<name>')
@@ -155,14 +155,30 @@ def hub_config(name):
         },
     }
     if flask.request.method == 'POST':
-        for key in hub.config.__json__():
-            # Security: don't save every key in the POST.
-            if key not in flask.request.form:
-                continue
-            setattr(hub.config, key, flask.request.form[key])
-        if (not flask.request.form["chat_domain"]
-            and len(app.config["CHAT_NETWORKS"]) > 0):
-            hub.config.chat_domain = app.config["CHAT_NETWORKS"][0]["domain"]
+        # Validate values
+        def _validate_chat_domain(value):
+            valid_chat_domains = [
+                network["domain"] for network in app.config["CHAT_NETWORKS"]
+                ]
+            if not value and len(valid_chat_domains) > 0:
+                value = valid_chat_domains[0]
+            if value not in valid_chat_domains:
+                raise ValueError("Unsupported chat domain.")
+            return value
+        validator = RequestValidator(dict(
+            # Only allow the parameters listed in __json__().
+            (key, None) for key in hub.config.__json__().keys()
+        ))
+        validator.converters["chat_domain"] = _validate_chat_domain
+        try:
+            values = validator(flask.request.form)
+        except ValueError as e:
+            config = {"status": "ERROR", "message": "Invalid value(s)"}
+            config["fields"] = e.args[0]
+            return flask.jsonify(config), 400
+        # Now set the configuration values
+        for key, value in values.items():
+            setattr(hub.config, key, value)
         try:
             flask.g.db.commit()
         except Exception as err:
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index 733a32a..a90e468 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -145,3 +145,81 @@ def get_position():
     if position not in ['right', 'left']:
         flask.abort(400, 'Invalid position provided')
     return position
+
+
+class RequestValidator(object):
+    """Validate a request's POST data.
+
+    Instantiate this class with a dictionnary mapping POST data keys (found in
+    ``flask.request.form``) to a function that will validate and convert them.
+
+    POST data can be validated by calling the instance and passing the data as
+    an argument.  The instance will return a mapping of keys to converted
+    values if all validations are successful.
+
+    A validation function can raise a :py:exc:`ValueError` if the value is not
+    valid. In this case, the :py:class:`RequestValidator` instance will collect
+    the error messages in a dictionary mapping failed request keys to messages,
+    and raise a :py:exc:`ValueError` with this dictionary.
+
+    If the function is None, the value is returned unchanged. If a posted value
+    is not present in the conversion mapping the class was instantiated with,
+    an error will be raised.
+
+    A typical usage of this class is::
+
+        validator = RequestValidator({"number": int})
+        try:
+            values = validator(flask.request.form)
+        except ValueError as e:
+            failed_fields = e.args[0]
+            return flask.jsonify(failed_fields), 400
+        # Do something with the validated values.
+        for key, value in values.items():
+            setattr(model_instance, key, value)
+
+    In this example:
+
+    - if the posted data was ``number=1``, the resulting ``values`` variable
+      would be ``{"number": 1}``.
+    - if the posted data was ``number=foobar``, a :py:exc:`ValueError` would be
+      raised, ``failed_fields`` would be ``{"number": "error message"}``.
+    - if the posted data was ``foo=bar``, a :py:exc:`ValueError` would be
+      raised, ``failed_fields`` would be
+      ``{"foo": "message about unexpected key"}``.
+
+    Args:
+        converters (dict): a mapping from POST data keys to
+            conversion functions.
+    """
+
+    def __init__(self, converters):
+        self.converters = converters.copy()
+
+    def __call__(self, request_data):
+        """Convert the values in the given mapping.
+
+        Args:
+            request_data (dict): the values to validate and convert,
+                usually ``flask.request.form``.
+
+        Raises:
+            ValueError: At least one value is invalid.
+        """
+        values = {}
+        errors = {}
+        for key, value in request_data.items():
+            if key not in self.converters:
+                errors[key] = "Unexpected parameter."
+                continue
+            if self.converters[key] is None:
+                # Identity
+                values[key] = value
+                continue
+            try:
+                values[key] = self.converters[key](value)
+            except (TypeError, ValueError) as e:
+                errors[key] = e.args[0]
+        if errors:
+            raise ValueError(errors)
+        return values

From 48dfdf4a9ee943c2d1f4525bfae2f916144b3f76 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 16 2017 10:20:53 +0000
Subject: [PATCH 803/1001] Fix all flake8 errors


---

diff --git a/check-cache-coverage.py b/check-cache-coverage.py
index d092dfd..efe45ab 100755
--- a/check-cache-coverage.py
+++ b/check-cache-coverage.py
@@ -16,7 +16,6 @@ Authors:    Ralph Bean <rbean@redhat.com>
 from __future__ import unicode_literals, print_function
 
 import sys
-import dogpile.cache
 
 import hubs.app
 import hubs.widgets
diff --git a/check-queue-length.py b/check-queue-length.py
index 5b14d0f..1a07f79 100755
--- a/check-queue-length.py
+++ b/check-queue-length.py
@@ -13,14 +13,14 @@ We could also graph this in collectd, for fun and profit.
 Authors:    Ralph Bean <rbean@redhat.com>
 """
 
-from __future__ import unicode_literals
+from __future__ import unicode_literals, print_function
+
+import retask
 
 import fedmsg.config
 config = fedmsg.config.load_config()
 
-import retask
-
 for item in ['triage', 'work']:
     queue = retask.queue.Queue(config['hubs.redis.%s-queue-name' % item])
     queue.connect()
-    print ' (%s) queue length is %i' % (item, queue.length)
+    print(' (%s) queue length is %i' % (item, queue.length))
diff --git a/delete-user.py b/delete-user.py
index 8c54582..9c79fc9 100755
--- a/delete-user.py
+++ b/delete-user.py
@@ -4,32 +4,31 @@
 Useful for testing what happens when you recreate them.
 """
 
-from __future__ import unicode_literals
-
-import sys
+from __future__ import unicode_literals, print_function
 
 import fedmsg.config
-fedmsg_config = fedmsg.config.load_config()
 
 import hubs.models
 
+fedmsg_config = fedmsg.config.load_config()
+
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 
-username = raw_input('What user do you want to delete: ')
+username = input('What user do you want to delete: ')
 openid = '%s.id.fedoraproject.org' % username
-print "Looking for account %r" % openid
+print("Looking for account %r" % openid)
 user = hubs.models.User.get(openid)
 if not user:
-    print "No such user %r" % openid
+    print("No such user %r" % openid)
 else:
-    print "Found %r.  Deleting." % user
+    print("Found %r.  Deleting." % user)
     session.delete(user)
 
 hub = hubs.models.Hub.get(username)
 if not hub:
-    print "No such hub %r" % username
+    print("No such hub %r" % username)
 else:
-    print "Found %r.  Deleting." % hub
+    print("Found %r.  Deleting." % hub)
     session.delete(hub)
 
 session.commit()
diff --git a/docs/conf.py b/docs/conf.py
index 27b4be2..9264743 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -150,8 +150,8 @@ html_theme = 'alabaster'
 # html_logo = None
 
 # The name of an image file (relative to this directory) to use as a favicon of
-# the docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
+# the docs.  This file should be a Windows icon file (.ico) being 16x16 or
+# 32x32 pixels large.
 #
 # html_favicon = None
 
diff --git a/fedmsg.d/base.py b/fedmsg.d/base.py
index ddc1a81..57b487a 100644
--- a/fedmsg.d/base.py
+++ b/fedmsg.d/base.py
@@ -17,8 +17,6 @@
 #
 # Authors:  Ralph Bean <rbean@redhat.com>
 
-import os
-
 config = dict(
     # Set this to dev if you're hacking on fedmsg or an app.
     # Set to stg or prod if running in the Fedora Infrastructure
@@ -28,14 +26,14 @@ config = dict(
     high_water_mark=0,
     io_threads=1,
 
-    ## For the fedmsg-hub and fedmsg-relay. ##
+    # # For the fedmsg-hub and fedmsg-relay. # #
 
     # This is a status dir to keep a record of the last processed message
-    #status_directory=os.getcwd() + "/status",
-    #status_directory='/var/run/fedmsg/status',
+    # status_directory=os.getcwd() + "/status",
+    # status_directory='/var/run/fedmsg/status',
 
     # This is the URL of a datagrepper instance that we can query for backlog.
-    #datagrepper_url="https://apps.fedoraproject.org/datagrepper/raw",
+    # datagrepper_url="https://apps.fedoraproject.org/datagrepper/raw",
 
     # We almost always want the fedmsg-hub to be sending messages with zmq as
     # opposed to amqp or stomp.
diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
index 1f45487..8f4f105 100644
--- a/fedmsg.d/testconfig.py
+++ b/fedmsg.d/testconfig.py
@@ -21,7 +21,8 @@ config = {
         ]
     },
 
-    'datanommer.sqlalchemy.uri': 'postgres://postgres:laksjdf@127.0.0.1/datanommer',
+    'datanommer.sqlalchemy.uri':
+        'postgres://postgres:laksjdf@127.0.0.1/datanommer',
 
     'fmn.url': 'https://apps.fedoraproject.org/notifications',
 
@@ -47,7 +48,8 @@ config = {
 
     # Run datanommer locally, just for development.
     'datanommer.enabled': True,
-    'datanommer.sqlalchemy.url': 'postgres://postgres:laksjdf@127.0.0.1/datanommer',
+    'datanommer.sqlalchemy.url':
+        'postgres://postgres:laksjdf@127.0.0.1/datanommer',
 
     # Only do one of these so we can try to not run out of memory.
     'moksha.workers_per_consumer': 1,
diff --git a/hubs/app.py b/hubs/app.py
index 0e81a8d..a32788b 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -1,20 +1,18 @@
 from __future__ import unicode_literals
 
 import datetime
-import json
 import logging
 import os
 
+import datanommer.models
+import fedmsg.config
+import fedmsg.meta
 import flask
 import flask.json
 import munch
-
 from flask_oidc import OpenIDConnect
 
 import hubs.models
-
-import datanommer.models
-
 from hubs.utils import username2avatar
 
 app = flask.Flask(__name__)
@@ -34,15 +32,13 @@ app.config.from_object('hubs.default_config')
 if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
 
-import fedmsg.config
-import fedmsg.meta
-
 fedmsg_config = fedmsg.config.load_config()
 fedmsg.meta.make_processors(**fedmsg_config)
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 datanommer.models.init(fedmsg_config['datanommer.sqlalchemy.uri'])
 
+
 @app.before_request
 def store_db():
     flask.g.db = session
@@ -74,7 +70,7 @@ def shutdown_session(exception=None):
 
 
 # Set up OpenIDConnect
-OIDC = OpenIDConnect(app, credentials_store=flask.session )
+OIDC = OpenIDConnect(app, credentials_store=flask.session)
 
 
 @app.before_request
@@ -86,17 +82,16 @@ def check_auth():
         if not hasattr(flask.session, 'auth') or not flask.session.auth:
             flask.session.auth = munch.Munch(
                 fullname=OIDC.user_getfield('name'),
-                nickname=OIDC.user_getfield('nickname') \
-                    or OIDC.user_getfield('sub'),
+                nickname=(OIDC.user_getfield('nickname') or
+                          OIDC.user_getfield('sub')),
                 email=OIDC.user_getfield('email'),
                 timezone=OIDC.user_getfield('zoneinfo'),
-                cla_done=\
-                    'http://admin.fedoraproject.org/accounts/cla/done' \
-                    in OIDC.user_getfield('cla'),
+                cla_done=('http://admin.fedoraproject.org/accounts/cla/done'
+                          in OIDC.user_getfield('cla')),
                 groups=OIDC.user_getfield('groups'),
                 logged_in=True,
             )
-            flask.session.auth.avatar=username2avatar(
+            flask.session.auth.avatar = username2avatar(
                 flask.session.auth.nickname)
             flask.session.auth.user = hubs.models.User.by_username(
                 flask.session.auth.nickname)
@@ -105,11 +100,11 @@ def check_auth():
         flask.g.auth = munch.Munch(logged_in=False)
 
 # Register widgets
-import hubs.widgets
+import hubs.widgets  # noqa
 hubs.widgets.registry.register_list(app.config["WIDGETS"])
 
 # Register routes
-import hubs.views
+import hubs.views  # noqa
 
 # Add widget-specific routes
 hubs.widgets.registry.register_routes(app)
diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index 7320460..7ea3645 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -21,28 +21,27 @@ handle.
 
 from __future__ import unicode_literals
 
-import hubs.app
-import hubs.models
-
-import hubs.widgets.base
+import json
+import logging
+import logging.config
+import random
+import sys
 
 import fedmsg.config
 import fedmsg.meta
-config = fedmsg.config.load_config()
-
 import retask.queue
 
-import json
-import random
-import sys
-import logging
-import logging.config
+import hubs.app
+import hubs.models
+import hubs.widgets.base
+
+
 log = logging.getLogger('hubs.backend.triage')
+config = fedmsg.config.load_config()
 
 
 def triage(session, outbound, msg):
     topic = msg['topic']
-    category = topic.split('.')[3]
 
     for suffix in config['hubs.junk_suffixes']:
         if topic.endswith(suffix):
@@ -115,5 +114,6 @@ def main(args):
 
     return 0
 
+
 if __name__ == '__main__':
     sys.exit(main(sys.argv))
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index e8e63e3..552d781 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -26,29 +26,29 @@ clients with the new content produced here.
 
 from __future__ import unicode_literals
 
-import hubs.app
-import hubs.models
-
-import hubs.widgets.base
+import json
+import logging
+import logging.config
+import sys
 
 import fedmsg.config
 import fedmsg.meta
-config = fedmsg.config.load_config()
-
 import retask.queue
 
-import json
-import sys
-import logging
-import logging.config
+import hubs.app
+import hubs.models
+import hubs.widgets.base
+
+
 log = logging.getLogger('hubs.backend.worker')
+config = fedmsg.config.load_config()
 
 
 def work(widget_idx, fn_name):
     # Get a real widget, because we update last_refreshed on it.
     widget = hubs.models.Widget.by_idx(widget_idx)
     fn_class = widget.module.get_cached_functions()[fn_name]
-    log.info("! Rebuilding cache for %r:%r" % (widget, cached_fn))
+    log.info("! Rebuilding cache for %r:%r" % (widget, fn_name))
     # Invalidate the cache...
     fn_class(widget).rebuild()
     # TODO -- fire off an EventSource notice that we updated stuff
@@ -88,7 +88,6 @@ def main(args):
             task = queue.wait()  # Wait forever...  timeout is optional.
             log.info("Working on %r.  (backlog is %r)" % (task, queue.length))
             item = json.loads(task.data)
-            idx = item['idx']  # A widget ID
             handle(item['idx'], item['fn_name'])
             log.debug("  Done.")
     except KeyboardInterrupt:
@@ -96,5 +95,6 @@ def main(args):
 
     return 0
 
+
 if __name__ == '__main__':
     sys.exit(main(sys.argv))
diff --git a/hubs/default_config.py b/hubs/default_config.py
index 688e51c..5837486 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -31,7 +31,8 @@ OIDC_SCOPES = [
 
 # TODO - instead of 'develop', use the version from pkg_resources to figure out
 #        the right tag to link people to.  AGPL ftw.
-SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'  # /hubs/widgets/badges.py'
+SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f'
+# Example of what will be appended: '/hubs/widgets/badges.py'
 
 CHAT_NETWORKS = [
     {
diff --git a/hubs/defaults.py b/hubs/defaults.py
index 7b5129a..2d27239 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -20,9 +20,9 @@ def add_user_widgets(session, hub, username, fullname):
     # Right Side Widgets
     widget = hubs.models.Widget(
         plugin='contact', index=-2,
-            _config=json.dumps({
-                'username': username,
-            }))
+        _config=json.dumps({
+            'username': username,
+        }))
     hub.widgets.append(widget)
 
     widget = hubs.models.Widget(
diff --git a/hubs/migrations/env.py b/hubs/migrations/env.py
index e00d82b..db92033 100644
--- a/hubs/migrations/env.py
+++ b/hubs/migrations/env.py
@@ -1,25 +1,24 @@
 from __future__ import absolute_import, unicode_literals
 
-from alembic import context
-from sqlalchemy import create_engine, pool
 from logging.config import fileConfig
 
-
 import fedmsg.config
-
-fedmsg_config = fedmsg.config.load_config()
+from alembic import context
+from sqlalchemy import create_engine, pool
 
 
 try:
-    import hubs
+    import hubs  # noqa
 except ImportError:
-    import os, sys
+    import os
+    import sys
     if "hubs" not in os.listdir("."):
         raise
     sys.path.append(os.getcwd())
 
 from hubs.models import BASE
 
+
 # This is the Alembic Config object, which provides
 # access to the values within the .ini file in use.
 # The config_file_name property may be None when used programatically.
@@ -28,6 +27,7 @@ if context.config.config_file_name is not None:
     # This line sets up loggers basically.
     fileConfig(context.config.config_file_name)
 
+fedmsg_config = fedmsg.config.load_config()
 url = fedmsg_config['hubs.sqlalchemy.uri']
 target_metadata = BASE.metadata
 
@@ -73,6 +73,7 @@ def run_migrations_online():
         with context.begin_transaction():
             context.run_migrations()
 
+
 if context.is_offline_mode():
     run_migrations_offline()
 else:
diff --git a/hubs/migrations/versions/1d660b32b83a_hub_config.py b/hubs/migrations/versions/1d660b32b83a_hub_config.py
index 7f2aefb..348aad5 100644
--- a/hubs/migrations/versions/1d660b32b83a_hub_config.py
+++ b/hubs/migrations/versions/1d660b32b83a_hub_config.py
@@ -35,11 +35,13 @@ depends_on = None
 
 
 def upgrade():
-    op.create_table('hubs_config',
+    op.create_table(
+        'hubs_config',
         sa.Column('id', sa.Integer(), nullable=False),
         sa.Column('hub_id', sa.String(length=50), nullable=False),
         sa.Column('summary', sa.String(length=128), nullable=True),
-        sa.Column('left_width', sa.Integer(), nullable=False, server_default="8"),
+        sa.Column('left_width', sa.Integer(), nullable=False,
+                  server_default="8"),
         sa.Column('avatar', sa.String(length=256), nullable=True),
         sa.Column('header_img', sa.String(length=256), nullable=True),
         sa.ForeignKeyConstraint(['hub_id'], ['hubs.name'], ),
@@ -59,13 +61,20 @@ def upgrade():
 
 
 def downgrade():
-    op.add_column('hubs', sa.Column('avatar', sa.VARCHAR(length=256), nullable=True))
-    op.add_column('hubs', sa.Column('summary', sa.VARCHAR(length=128), nullable=True))
-    op.add_column('hubs', sa.Column('header_img', sa.VARCHAR(length=256), nullable=True))
-    op.add_column('hubs', sa.Column('left_width', sa.INTEGER(), server_default="8", nullable=False))
+    op.add_column(
+        'hubs', sa.Column('avatar', sa.VARCHAR(length=256), nullable=True))
+    op.add_column(
+        'hubs', sa.Column('summary', sa.VARCHAR(length=128), nullable=True))
+    op.add_column(
+        'hubs', sa.Column('header_img', sa.VARCHAR(length=256), nullable=True))
+    op.add_column(
+        'hubs', sa.Column('left_width', sa.INTEGER(), server_default="8",
+                          nullable=False))
     connection = op.get_bind()
-    query = "SELECT hub_id, summary, left_width, avatar, header_img FROM hubs_config"
-    hubs_table = sa.sql.table('hubs',
+    query = ("SELECT hub_id, summary, left_width, avatar, header_img "
+             "FROM hubs_config")
+    hubs_table = sa.sql.table(
+        'hubs',
         sa.sql.column('name', sa.String),
         sa.sql.column('summary', sa.String),
         sa.sql.column('left_width', sa.Integer),
@@ -74,7 +83,7 @@ def downgrade():
     )
     for row in connection.execute(query):
         op.execute(hubs_table.update().where(
-            hubs_table.c.name==op.inline_literal(row["hub_id"])
+            hubs_table.c.name == op.inline_literal(row["hub_id"])
             ).values({
                 "summary": op.inline_literal(row["summary"]),
                 "left_width": op.inline_literal(row["left_width"]),
diff --git a/hubs/models.py b/hubs/models.py
index 4102eeb..48ed695 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -30,7 +30,6 @@ import os
 import random
 
 import bleach
-import dogpile
 import sqlalchemy as sa
 
 from alembic import command as alembic_command
@@ -69,7 +68,7 @@ BASE = declarative_base(cls=HubsBase)
 log = logging.getLogger(__name__)
 
 
-placekitten = lambda: "https://placekitten.com/g/320/320"
+placekitten = "https://placekitten.com/g/320/320"
 
 
 def randomheader():
@@ -122,8 +121,10 @@ class Association(BASE):
                         primary_key=True)
     role = sa.Column(sa.Enum(*roles), primary_key=True)
 
-    user = relation("User", backref=backref('associations', cascade="all, delete"))
-    hub = relation("Hub", backref=backref('associations', cascade="all, delete"))
+    user = relation("User", backref=backref(
+        'associations', cascade="all, delete"))
+    hub = relation("Hub", backref=backref(
+        'associations', cascade="all, delete"))
 
     @classmethod
     def get(cls, hub, user, role):
@@ -139,7 +140,8 @@ class Hub(BASE):
     name = sa.Column(sa.String(50), primary_key=True)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     widgets = relation('Widget', cascade='all,delete', backref='hub')
-    config = relation('HubConfig', uselist=False, cascade='all,delete', backref='hub')
+    config = relation('HubConfig', uselist=False, cascade='all,delete',
+                      backref='hub')
     archived = sa.Column(sa.Boolean, default=False)
     user_hub = sa.Column(sa.Boolean, default=False)
     # Timestamps about various kinds of "freshness"
@@ -358,7 +360,6 @@ class Widget(BASE):
         self._config = json.dumps(config)
 
     def __json__(self):
-        session = object_session(self)
         module = hubs.widgets.registry[self.plugin]
         root_view = module.get_views()["root"](module)
         data = root_view.get_context(self)
@@ -395,7 +396,7 @@ class User(BASE):
     fullname = sa.Column(sa.Text)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     saved_notifications = relation('SavedNotification', backref='users',
-                                       lazy='dynamic')
+                                   lazy='dynamic')
 
     def __json__(self):
         return {
@@ -432,10 +433,10 @@ class User(BASE):
         # TODO -- someday make this editable/configurable.
         return sorted(list(set([
             assoc.hub for assoc in self.associations
-            if assoc.role == 'member'
-            or assoc.role == 'subscriber'
-            or assoc.role == 'owner'
-            and assoc.hub.name != self.username
+            if assoc.role == 'member' or
+            assoc.role == 'subscriber' or
+            assoc.role == 'owner' and
+            assoc.hub.name != self.username
         ])), key=operator.attrgetter('name'))
 
     @classmethod
@@ -468,16 +469,16 @@ class VisitCounter(BASE):
     __tablename__ = 'visit_counter'
     count = sa.Column(sa.Integer, default=0, nullable=False)
 
-    visited_hub = sa.Column(sa.String(50),
-                       sa.ForeignKey('hubs.name'),
-                       primary_key=True)
+    visited_hub = sa.Column(sa.String(50), sa.ForeignKey('hubs.name'),
+                            primary_key=True)
 
-    username = sa.Column(sa.Text,
-                        sa.ForeignKey('users.username'),
-                        primary_key=True)
+    username = sa.Column(sa.Text, sa.ForeignKey('users.username'),
+                         primary_key=True)
 
-    user = relation("User", backref=backref('visit_counters', cascade="all, delete, delete-orphan"))
-    hub = relation("Hub", backref=backref('visit_counters', cascade="all, delete, delete-orphan"))
+    user = relation("User", backref=backref(
+                    'visit_counters', cascade="all, delete, delete-orphan"))
+    hub = relation("Hub", backref=backref(
+                   'visit_counters', cascade="all, delete, delete-orphan"))
 
     @classmethod
     def by_username(cls, username):
@@ -485,7 +486,8 @@ class VisitCounter(BASE):
 
     @classmethod
     def get_visits_by_username_hub(cls, username, visited_hub):
-        return cls.query.filter_by(username=username, visited_hub=visited_hub).first()
+        return cls.query.filter_by(
+            username=username, visited_hub=visited_hub).first()
 
     @classmethod
     def increment_visits(cls, session, username, visited_hub):
@@ -534,8 +536,8 @@ class SavedNotification(BASE):
     markup = sa.Column(sa.Text)
     secondary_icon = sa.Column(sa.Text)
 
-
-    def __init__(self, username=None, markup='', link='', secondary_icon='', dom_id=''):
+    def __init__(self, username=None, markup='', link='', secondary_icon='',
+                 dom_id=''):
         self.user = username
         self.markup = markup
         self.link = link
diff --git a/hubs/stream.py b/hubs/stream.py
index ced01b9..f939ab3 100644
--- a/hubs/stream.py
+++ b/hubs/stream.py
@@ -1,8 +1,8 @@
 from __future__ import unicode_literals
 
-import json
 import os
 
+
 class Stream(object):
     def get_json(self):
         here = os.path.dirname(os.path.abspath(__file__))
diff --git a/hubs/tests/test_api/test_hub.py b/hubs/tests/test_api/test_hub.py
index 622fd9d..abf1e3d 100644
--- a/hubs/tests/test_api/test_hub.py
+++ b/hubs/tests/test_api/test_hub.py
@@ -1,7 +1,5 @@
 from __future__ import unicode_literals
 
-import flask
-import unittest
 from six.moves.urllib.parse import urlparse
 
 import hubs.tests
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index c9c7657..c224a77 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -1,7 +1,6 @@
 from __future__ import unicode_literals
 
 import json
-from six.moves.urllib.parse import urlparse
 
 import hubs.tests
 import hubs.models
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 006f99e..c9e8c39 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -404,7 +404,8 @@ class HubsAPITest(hubs.tests.APPTest):
                 "left_width": 8,
                 "avatar": (
                     "https://seccdn.libravatar.org/avatar/9c9f7784935381befc30"
-                    "2fe3c814f9136e7a33953d0318761669b8643f4df55c?s=312&d=retro"
+                    "2fe3c814f9136e7a33953d0318761669b8643f4df55c"
+                    "?s=312&d=retro"
                     ),
                 "chat_channel": None,
                 "chat_domain": None,
diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index 9d0e64d..53d1bf8 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -8,15 +8,16 @@ from hubs.widgets.view import WidgetView
 
 from mock import Mock
 from hubs.tests import APPTest
-#import hubs.models
 
 
 class TestingWidget(Widget):
     name = "testing"
 
+
 class TestingView(WidgetView):
     name = "root"
 
+
 class TestingFunction(CachedFunction):
     pass
 
@@ -40,8 +41,10 @@ class WidgetTest(APPTest):
     def test_validate(self):
         class LocalTestWidget(Widget):
             views = {}
+
             def get_views(self):
                 return self.views
+
         self.assertRaisesRegexp(
             AttributeError, '.* "name" .*', LocalTestWidget)
         LocalTestWidget.name = "invalid name \xe2\x98\xba"
@@ -109,10 +112,11 @@ class WidgetTest(APPTest):
             {"TestingFunction": TestingFunction}
             )
 
-    def test_list_views(self):
+    def test_list_additional_views(self):
         class TestView1(WidgetView):
             name = "root"
             url_rules = ["/", "/test-1/"]
+
         class TestView2(WidgetView):
             name = "test2"
             url_rules = ["/test-2"]
@@ -127,7 +131,9 @@ class WidgetTest(APPTest):
         self.assertIn("testing_root",
                       self.app.application.url_map._rules_by_endpoint)
         self.assertIn("testing_root", self.app.application.view_functions)
-        rules = list(self.app.application.url_map.iter_rules(endpoint="testing_root"))
+        rules = list(
+            self.app.application.url_map.iter_rules(endpoint="testing_root")
+            )
         self.assertEqual(len(rules), 2)
         self.assertEqual(rules[0].rule, "/<hub>/w/testing/<int:idx>/")
         self.assertEqual(rules[1].rule, "/<hub>/w/testing/<int:idx>/test-1/")
@@ -135,6 +141,8 @@ class WidgetTest(APPTest):
         self.assertIn("testing_test2",
                       self.app.application.url_map._rules_by_endpoint)
         self.assertIn("testing_test2", self.app.application.view_functions)
-        rules = list(self.app.application.url_map.iter_rules(endpoint="testing_test2"))
+        rules = list(
+            self.app.application.url_map.iter_rules(endpoint="testing_test2")
+            )
         self.assertEqual(len(rules), 1)
         self.assertEqual(rules[0].rule, "/<hub>/w/testing/<int:idx>/test-2")
diff --git a/hubs/tests/test_widget_validators.py b/hubs/tests/test_widget_validators.py
index 567c60f..2cadf7f 100644
--- a/hubs/tests/test_widget_validators.py
+++ b/hubs/tests/test_widget_validators.py
@@ -1,13 +1,10 @@
 from __future__ import unicode_literals
 
-import six
 import unittest
 
 from hubs.widgets import validators
 
-#from mock import Mock
 from hubs.tests import APPTest
-from hubs.models import User
 
 
 class ValidatorsTest(APPTest):
@@ -30,7 +27,8 @@ class ValidatorsTest(APPTest):
 
     def test_username(self):
         self.assertEqual(validators.Username.from_string("ralph"), "ralph")
-        self.assertRaises(ValueError, validators.Username.from_string, "nobody")
+        self.assertRaises(
+            ValueError, validators.Username.from_string, "nobody")
 
     @unittest.skip("Not implemented yet")
     def test_github_organization(self):
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 7579b19..3297022 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -1,12 +1,6 @@
 from __future__ import unicode_literals
 
 import json
-from datetime import datetime, timedelta
-from os.path import dirname
-import unittest
-
-import requests
-import vcr
 
 import hubs.models
 from hubs.tests import APPTest
@@ -20,7 +14,8 @@ class WidgetTest(APPTest):
         widget = hubs.models.Widget(
             plugin='library',
             index=51,
-            _config=json.dumps({"urls": "ralph/"})  # we must add a url or itll crash
+            # We must add a url in the config or it'll crash.
+            _config=json.dumps({"urls": "ralph/"})
         )
         hub.widgets.append(widget)
         hubs.app.session.commit()
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index 7865a34..d86435f 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -2,8 +2,6 @@ from __future__ import unicode_literals
 
 import json
 
-from nose.tools import assert_dict_equal
-
 import hubs.tests.test_widgets
 
 
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index 45e1ce8..3521ec2 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -2,7 +2,6 @@ from __future__ import unicode_literals
 
 import json
 
-from mock import patch, MagicMock
 import hubs.tests.test_widgets
 
 
@@ -29,7 +28,8 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
     def test_should_invalidate_wrong_user(self):
         widget = self.widget_instance('ralph', self.plugin)
         # msg = self.get_fedmsg('2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f')
-        msg = {'topic': 'fedbadges.badge.award', 'msg': {'user': {'username': 'not_ralph'}}}
+        msg = {'topic': 'fedbadges.badge.award',
+               'msg': {'user': {'username': 'not_ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
         func = module.get_cached_functions()['GetBadges']
         result = func(widget).should_invalidate(msg)
@@ -38,7 +38,8 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
     def test_should_invalidate_good_match_fedbadges(self):
         widget = self.widget_instance('ralph', self.plugin)
         # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
-        msg = {'topic': 'fedbadges.badge.award', 'msg': {'user': {'username': 'ralph'}}}
+        msg = {'topic': 'fedbadges.badge.award',
+               'msg': {'user': {'username': 'ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
         func = module.get_cached_functions()['GetBadges']
         result = func(widget).should_invalidate(msg)
@@ -47,7 +48,8 @@ class TestBadges(hubs.tests.test_widgets.WidgetTest):
     def test_should_invalidate_good_match_hubswidget(self):
         widget = self.widget_instance('ralph', self.plugin)
         # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
-        msg = {'topic': 'hubs.widget.update', 'msg': {'widget': {'id': widget.idx + 1}}}
+        msg = {'topic': 'hubs.widget.update',
+               'msg': {'widget': {'id': widget.idx + 1}}}
         module = hubs.widgets.registry[widget.plugin]
         func = module.get_cached_functions()['GetBadges']
         result = func(widget).should_invalidate(msg)
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index a41e60e..0e09a7d 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -5,6 +5,7 @@ import json
 import hubs.tests.test_widgets
 import hubs.models
 
+
 class TestLibrary(hubs.tests.test_widgets.WidgetTest):
     plugin = 'library'  # The name in hubs.widgets.registry
 
diff --git a/hubs/utils.py b/hubs/utils.py
index f1ecd92..830d5ae 100755
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -1,13 +1,11 @@
 from __future__ import unicode_literals
 
-import json
 import logging
 from hashlib import sha256
 
 import arrow
 import markdown
 import requests
-import six
 
 from six.moves.urllib_parse import urlencode
 
diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
index f3d8a0c..87da5d9 100644
--- a/hubs/views/__init__.py
+++ b/hubs/views/__init__.py
@@ -1,5 +1,7 @@
 from __future__ import absolute_import
 
+# flake8:noqa
+
 from .root import *
 from .hub import *
 from .widget import *
diff --git a/hubs/views/api.py b/hubs/views/api.py
index 4c96e44..777bcda 100644
--- a/hubs/views/api.py
+++ b/hubs/views/api.py
@@ -75,4 +75,3 @@ def hub_leave(hub):
         return flask.abort(400)
     flask.g.db.commit()
     return flask.redirect(flask.url_for('hub', name=hub.name))
-
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 3534c70..4227357 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -4,7 +4,7 @@ import datetime
 import flask
 import hubs.models
 
-from hubs.app import app, session
+from hubs.app import app
 from .utils import get_hub, login_required, RequestValidator
 
 
diff --git a/hubs/views/root.py b/hubs/views/root.py
index 386f233..1250490 100644
--- a/hubs/views/root.py
+++ b/hubs/views/root.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals, absolute_import
 import flask
 import hubs.models
 
-from hubs.app import app, session, OIDC
+from hubs.app import app, OIDC
 from .utils import authenticated, is_safe_url
 
 
@@ -49,7 +49,8 @@ def login():
         return_point = default
 
     hubs.models.User.get_or_create(
-        flask.g.db, username=flask.g.auth.nickname, fullname=flask.g.auth.fullname)
+        flask.g.db, username=flask.g.auth.nickname,
+        fullname=flask.g.auth.fullname)
     flask.flash('Login successful', 'success')
 
     return flask.redirect(return_point)
diff --git a/hubs/views/user.py b/hubs/views/user.py
index 692daf3..62866ae 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -5,7 +5,7 @@ import json
 import hubs.models
 import hubs.stream
 
-from hubs.app import app, session
+from hubs.app import app
 from .utils import login_required, get_hub
 
 
@@ -62,16 +62,20 @@ def notifications(user):
             dict(notification=notification.__json__(), success=True)
         )
 
+
 @app.route('/<user>/notifications/<int:idx>', methods=['DELETE'])
 @app.route('/<user>/notifications/<int:idx>/', methods=['DELETE'])
 @login_required
 def delete_notifications(user, idx):
-    notification = flask.g.db.query(hubs.models.SavedNotification).filter_by(idx=idx).first()
+    notification = flask.g.db.query(
+        hubs.models.SavedNotification).filter_by(idx=idx).first()
     if not notification:
         return flask.abort(400)
     flask.g.db.delete(notification)
     flask.g.db.commit()
     return flask.jsonify(dict(status_code=200))
+
+
 @app.route('/visit/<visited_hub>/', methods=['GET', 'POST'])
 @app.route('/visit/<visited_hub>', methods=['GET', 'POST'])
 @login_required
@@ -80,9 +84,8 @@ def increment_counter(visited_hub):
 
     if str(visited_hub) != str(nickname):
         try:
-            vc = hubs.models.VisitCounter.get_or_create(session=flask.g.db,
-                                                        username=nickname,
-                                                        visited_hub=visited_hub)
+            vc = hubs.models.VisitCounter.get_or_create(
+                session=flask.g.db, username=nickname, visited_hub=visited_hub)
         except ValueError:  # this should never trip
             # flask will 405 if visited_hub is blank
             # @login_required forces flask.g.auth to be sets
diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index 990dce6..c94dddb 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -28,6 +28,7 @@ def _get_cache():
     cache.configure(**config.get('fedora-hubs.cache', cache_defaults))
     return cache
 
+
 cache = _get_cache()
 
 
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 07374fb..c5970f9 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -69,7 +69,7 @@ class GetPRs(CachedFunction):
                 for repo in repos
             ], [])
             # Reverse-sort by time (newest-first)
-            pulls.sort(lambda a, b: cmp(b['timestamp'], a['timestamp']))
+            pulls.sort(key=lambda x: x['timestamp'], reverse=True)
 
             # Some hints for display
             len_pulls = len(pulls)
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index 9c96320..a037a94 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -122,8 +122,7 @@ class FMNContext(Validator):
     @classmethod
     def from_string(cls, value):
         # TODO get this from the fedmsg config.
-        if value in [
-            'irc', 'email', 'android', 'desktop', 'hubs',]:
+        if value in ['irc', 'email', 'android', 'desktop', 'hubs']:
             return value
         raise ValueError('Invalid FMN context')
 
diff --git a/populate-from-fas.py b/populate-from-fas.py
index 959c5e4..b5ed9ce 100755
--- a/populate-from-fas.py
+++ b/populate-from-fas.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 """ Populate the hubs db with lots of data from FAS. """
 
-from __future__ import unicode_literals
+from __future__ import unicode_literals, print_function
 
 import getpass
 import socket
@@ -14,7 +14,7 @@ import fedmsg.config
 fedmsg_config = fedmsg.config.load_config()
 
 fasclient = fedora.client.fas2.AccountSystem(
-    username=raw_input('Your FAS username: '),
+    username=input('Your FAS username: '),
     password=getpass.getpass(),
 )
 timeout = socket.getdefaulttimeout()
@@ -39,7 +39,7 @@ suffix_blacklist = [
 for letter in reversed(sorted(list(set(string.letters.lower())))):
     session = hubs.models.init(
         fedmsg_config['hubs.sqlalchemy.uri'], True, True)
-    print "Querying FAS for the %r users.. hang on." % letter
+    print("Querying FAS for the %r users.. hang on." % letter)
     request = fasclient.send_request(
         '/user/list',
         req_params={'search': '%s*' % letter, 'status': 'active'},
@@ -50,7 +50,7 @@ for letter in reversed(sorted(list(set(string.letters.lower())))):
     for user in users:
         username = user['username']
         fullname = user['human_name']
-        print "Creating account for %r" % username
+        print("Creating account for %r" % username)
         hubs_user = hubs.models.User.get_or_create(
             session, username=username, fullname=fullname)
 
diff --git a/populate.py b/populate.py
index 5a5d5a2..08feaa3 100755
--- a/populate.py
+++ b/populate.py
@@ -35,7 +35,7 @@ for username in users:
 
 session.commit()
 
-############## Internationalizationteam
+# ############# Internationalizationteam
 hub = hubs.models.Hub(name='i18n', archived=True)
 session.add(hub)
 session.add(hubs.models.HubConfig(
@@ -45,13 +45,14 @@ widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='rules', index=1,
-                            _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/I18N',
-                                'schedule_text': None,
-                                'schedule_link': None,
-                                'minutes_link': 'https://meetbot.fedoraproject.org/sresults/?group_id=i18n&type=team',
-                            }))
+widget = hubs.models.Widget(
+    plugin='rules', index=1, _config=json.dumps({
+        'link': 'https://fedoraproject.org/wiki/I18N',
+        'schedule_text': None,
+        'schedule_link': None,
+        'minutes_link': 'https://meetbot.fedoraproject.org/sresults/'
+                        '?group_id=i18n&type=team',
+    }))
 hub.widgets.append(widget)
 
 widget = hubs.models.Widget(plugin='meetings', index=2,
@@ -59,16 +60,25 @@ widget = hubs.models.Widget(plugin='meetings', index=2,
 hub.widgets.append(widget)
 
 # Added a hubs about widget
-widget = hubs.models.Widget(plugin='about', index=3,
-                            _config=json.dumps({
-                                "text": "I'm a Fedora user, and this is my about widget text!",
-                            }))
-hub.widgets.append(widget)
-
-widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
-                            _config=json.dumps({
-                                'text': "<p>The Fedora I18N project works on internationalization (i18n) to support the localization (l10n) of Fedora in many languages. Translation of Fedora software and documentation are handled by the Fedora L10N project.</p> <p>The goals of the Project are to:</p> <ul><li>Develop, package, and maintain applications like input methods for different languages</li> <li>Improve applications and utilities to support and process different languages</li> <li>Quality-assure that existing applications meet i18n standards</li> <li>Support the infrastructure of the Fedora Localization Project</li></ul>",
-                            }))
+widget = hubs.models.Widget(
+    plugin='about', index=3, _config=json.dumps({
+        "text": "I'm a Fedora user, and this is my about widget text!",
+    }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(
+    plugin='sticky', index=1, left=True, _config=json.dumps({
+        'text': """
+<p>The Fedora I18N project works on internationalization (i18n) to support the
+localization (l10n) of Fedora in many languages. Translation of Fedora software
+and documentation are handled by the Fedora L10N project.</p> <p>The goals of
+the Project are to:</p> <ul><li>Develop, package, and maintain applications
+like input methods for different languages</li> <li>Improve applications and
+utilities to support and process different languages</li> <li>Quality-assure
+that existing applications meet i18n standards</li> <li>Support the
+infrastructure of the Fedora Localization Project</li></ul>
+""",
+    }))
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=2, left=True)
 hub.widgets.append(widget)
@@ -82,7 +92,7 @@ hub.subscribe(hubs.models.User.by_username('ralph'), 'subscriber')
 
 session.commit()
 
-############## CommOps
+# ############# CommOps
 hub = hubs.models.Hub(name='commops')
 session.add(hub)
 session.add(hubs.models.HubConfig(
@@ -92,17 +102,20 @@ widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='rules', index=1,
-                            _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/CommOps',
-                                'schedule_text': None,
-                                'schedule_link': None,
-                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=commops&type=team',
-                            }))
+widget = hubs.models.Widget(
+    plugin='rules', index=1, _config=json.dumps({
+        'link': 'https://fedoraproject.org/wiki/CommOps',
+        'schedule_text': None,
+        'schedule_link': None,
+        'minutes_link': 'http://meetbot.fedoraproject.org/sresults/'
+                        '?group_id=commops&type=team',
+    }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='meetings', index=2,
-                            _config=json.dumps({'calendar': 'commops', 'n_meetings': 4}))
+widget = hubs.models.Widget(
+    plugin='meetings', index=2, _config=json.dumps({
+        'calendar': 'commops', 'n_meetings': 4
+    }))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
@@ -112,10 +125,12 @@ widget = hubs.models.Widget(plugin='about', index=3,
                             }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
-                            _config=json.dumps({
-                                'text': "Bringing more heat and light to Fedora, so you don't have to choose between 'building things' and 'building communities that build things.'",
-                            }))
+widget = hubs.models.Widget(
+    plugin='sticky', index=1, left=True, _config=json.dumps({
+        'text': "Bringing more heat and light to Fedora, so you don't have "
+                "to choose between 'building things' and 'building "
+                "communities that build things.'",
+    }))
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=2, left=True)
 hub.widgets.append(widget)
@@ -131,7 +146,7 @@ hub.subscribe(hubs.models.User.by_username('linuxmodder'), 'member')
 
 session.commit()
 
-############## Marketing team
+# ############# Marketing team
 hub = hubs.models.Hub(name='marketing')
 session.add(hub)
 session.add(hubs.models.HubConfig(
@@ -141,30 +156,41 @@ widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='rules', index=1,
-                            _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/Marketing',
-                                'schedule_text': None,
-                                'schedule_link': None,
-                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=fedora-mktg&type=channel',
-                            }))
+widget = hubs.models.Widget(
+    plugin='rules', index=1, _config=json.dumps({
+        'link': 'https://fedoraproject.org/wiki/Marketing',
+        'schedule_text': None,
+        'schedule_link': None,
+        'minutes_link': 'http://meetbot.fedoraproject.org/sresults/'
+                        '?group_id=fedora-mktg&type=channel',
+    }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='meetings', index=2,
-                            _config=json.dumps({'calendar': 'marketing', 'n_meetings': 4}))
+widget = hubs.models.Widget(
+    plugin='meetings', index=2, _config=json.dumps({
+        'calendar': 'marketing', 'n_meetings': 4
+    }))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
-widget = hubs.models.Widget(plugin='about', index=3,
-                            _config=json.dumps({
-                                "text": "I'm a Fedora user, and this is my about widget text!",
-                            }))
-hub.widgets.append(widget)
-
-widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
-                            _config=json.dumps({
-                                'text': "The Fedora Marketing Team develops and executes marketing strategies to promote the usage and support of Fedora worldwide. Through the development of processes and content, this project aims to support the efforts of other Fedora projects to spread Fedora and to provide a central repository of ideas and information that can be used to deliver Fedora to new audiences. We work closely with the Fedora Ambassadors who spread the word about Fedora at events and allow the Fedora Project to interact directly with its existing and prospective users. ",
-                            }))
+widget = hubs.models.Widget(
+    plugin='about', index=3, _config=json.dumps({
+        "text": "I'm a Fedora user, and this is my about widget text!",
+    }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(
+    plugin='sticky', index=1, left=True, _config=json.dumps({
+        'text': """
+The Fedora Marketing Team develops and executes marketing strategies to promote
+the usage and support of Fedora worldwide. Through the development of processes
+and content, this project aims to support the efforts of other Fedora projects
+to spread Fedora and to provide a central repository of ideas and information
+that can be used to deliver Fedora to new audiences. We work closely with the
+Fedora Ambassadors who spread the word about Fedora at events and allow the
+Fedora Project to interact directly with its existing and prospective users.
+""",
+    }))
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=2, left=True)
 hub.widgets.append(widget)
@@ -181,7 +207,7 @@ hub.subscribe(hubs.models.User.by_username('ralph'), 'subscriber')
 
 session.commit()
 
-############## Design team
+# ############# Design team
 hub = hubs.models.Hub(name='designteam')
 session.add(hub)
 session.add(hubs.models.HubConfig(
@@ -191,30 +217,37 @@ widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='rules', index=1,
-                            _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/Design',
-                                'schedule_text': 'Meetings are every other Tuesday at 16:00 UTC',
-                                'schedule_link': 'https://apps.fedoraproject.org/calendar/design/',
-                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=fedora-design&type=channel',
-                            }))
+widget = hubs.models.Widget(
+    plugin='rules', index=1, _config=json.dumps({
+        'link': 'https://fedoraproject.org/wiki/Design',
+        'schedule_text': 'Meetings are every other Tuesday at 16:00 UTC',
+        'schedule_link': 'https://apps.fedoraproject.org/calendar/design/',
+        'minutes_link': 'http://meetbot.fedoraproject.org/sresults/'
+                        '?group_id=fedora-design&type=channel',
+    }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='meetings', index=2,
-                            _config=json.dumps({'calendar': 'design', 'n_meetings': 4}))
+widget = hubs.models.Widget(
+    plugin='meetings', index=2, _config=json.dumps({
+        'calendar': 'design', 'n_meetings': 4
+    }))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
-widget = hubs.models.Widget(plugin='about', index=3,
-                            _config=json.dumps({
-                                "text": "I'm a Fedora user, and this is my about widget text!",
-                            }))
+widget = hubs.models.Widget(
+    plugin='about', index=3, _config=json.dumps({
+        "text": "I'm a Fedora user, and this is my about widget text!",
+    }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='sticky', index=1, left=True,
-                            _config=json.dumps({
-                                'text': "The Design Team is the design group of the Fedora project. Our interests are not only in creating graphics for use by the Fedora community, but also in advocating the use of the creative tools that are a part of Fedora.",
-                            }))
+widget = hubs.models.Widget(
+    plugin='sticky', index=1, left=True, _config=json.dumps({
+        'text': """
+The Design Team is the design group of the Fedora project. Our interests are
+not only in creating graphics for use by the Fedora community, but also in
+advocating the use of the creative tools that are a part of Fedora.
+""",
+    }))
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=2, left=True)
 hub.widgets.append(widget)
@@ -232,7 +265,7 @@ hub.subscribe(hubs.models.User.by_username('ralph'), 'subscriber')
 session.commit()
 
 
-############## Infra team
+# ############# Infra team
 hub = hubs.models.Hub(name='infrastructure')
 session.add(hub)
 session.add(hubs.models.HubConfig(
@@ -242,30 +275,39 @@ widget = hubs.models.Widget(plugin='contact', index=-1)
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='stats', index=0)
 hub.widgets.append(widget)
-widget = hubs.models.Widget(plugin='rules', index=1,
-                            _config=json.dumps({
-                                'link': 'https://fedoraproject.org/wiki/Infrastructure',
-                                'schedule_text': 'We meet weekly in #fedora-meeting at 18:00 UTC',
-                                'schedule_link': 'https://apps.fedoraproject.org/calendar/infrastructure/',
-                                'minutes_link': 'http://meetbot.fedoraproject.org/sresults/?group_id=infrastructure&type=team',
-                            }))
+widget = hubs.models.Widget(
+    plugin='rules', index=1, _config=json.dumps({
+        'link': 'https://fedoraproject.org/wiki/Infrastructure',
+        'schedule_text': 'We meet weekly in #fedora-meeting at 18:00 UTC',
+        'schedule_link':
+            'https://apps.fedoraproject.org/calendar/infrastructure/',
+        'minutes_link': 'http://meetbot.fedoraproject.org/sresults/'
+                        '?group_id=infrastructure&type=team',
+    }))
 hub.widgets.append(widget)
 
-widget = hubs.models.Widget(plugin='meetings', index=2,
-                            _config=json.dumps({'calendar': 'infrastructure', 'n_meetings': 4}))
+widget = hubs.models.Widget(
+    plugin='meetings', index=2, _config=json.dumps({
+        'calendar': 'infrastructure', 'n_meetings': 4
+    }))
 hub.widgets.append(widget)
 
 # Added a hubs about widget
-widget = hubs.models.Widget(plugin='about', index=3,
-                            _config=json.dumps({
-                                "text": "I'm a Fedora user, and this is my about widget text!",
-                            }))
-hub.widgets.append(widget)
-
-widget = hubs.models.Widget(plugin='sticky', index=2, left=True,
-                            _config=json.dumps({
-                                'text': "The Infrastructure Team consists of dedicated volunteers and professionals managing the servers, building the tools and utilities, and creating new applications to make Fedora development a smoother process. We're located all over the globe and communicate primarily by IRC and e-mail. ",
-                            }))
+widget = hubs.models.Widget(
+    plugin='about', index=3, _config=json.dumps({
+        "text": "I'm a Fedora user, and this is my about widget text!",
+    }))
+hub.widgets.append(widget)
+
+widget = hubs.models.Widget(
+    plugin='sticky', index=2, left=True, _config=json.dumps({
+        'text': """
+The Infrastructure Team consists of dedicated volunteers and professionals
+managing the servers, building the tools and utilities, and creating new
+applications to make Fedora development a smoother process. We're located all
+over the globe and communicate primarily by IRC and e-mail.
+""",
+    }))
 hub.widgets.append(widget)
 widget = hubs.models.Widget(plugin='dummy', index=3, left=True)
 hub.widgets.append(widget)
diff --git a/runserver.py b/runserver.py
index 9552b0a..f41b3cd 100755
--- a/runserver.py
+++ b/runserver.py
@@ -3,7 +3,6 @@
 from __future__ import unicode_literals
 
 import argparse
-import sys
 import os
 
 parser = argparse.ArgumentParser(
@@ -32,7 +31,7 @@ if args.config:
     os.environ['HUBS_CONFIG'] = config
 
 
-from hubs.app import app
+from hubs.app import app  # noqa
 
 app.debug = True
 app.run(debug=True, host=args.host, port=int(args.port))
diff --git a/setup.py b/setup.py
index aa9b63e..cb267d0 100644
--- a/setup.py
+++ b/setup.py
@@ -26,8 +26,8 @@ setup(
     download_url="https://pypi.python.org/pypi/fedora-hubs/",
     license='AGPLv3+',
     install_requires=get_requirements(),
-    #tests_require=tests_require,
-    #test_suite='nose.collector',
+    # tests_require=tests_require,
+    # test_suite='nose.collector',
     packages=find_packages(),
     include_package_data=True,
     zip_safe=False,
@@ -40,7 +40,7 @@ setup(
     ],
     entry_points={
         'moksha.consumer': [
-            "cache_invalidator = hubs.backend.consumer:CacheInvalidatorExtraordinaire",
+            "cache_invalidator = hubs.backend.consumer:CacheInvalidatorExtraordinaire",  # noqa
         ],
     },
 )
diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index ebf0de6..5150b0c 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -11,9 +11,7 @@ made to a widget without dropping the entire cache database.
 from __future__ import print_function, unicode_literals
 
 import argparse
-import os
 
-import dogpile.cache
 import fedmsg.config
 import fedmsg.meta
 
@@ -39,8 +37,8 @@ def do_list(args):
         widget = w_instance.module
         for fn_name, fn_class in widget.get_cached_functions().items():
             if fn_class(w_instance).is_cached():
-                print('- Widget cached {0} (#{1}) in {2}'.format(
-                          w_instance.hub_id, w_instance.idx, w_instance.plugin))
+                print(('- Widget cached {inst.hub_id} (#{inst.idx}) '
+                       'in {inst.plugin}').format(inst=w_instance))
 
 
 def do_clean(args):
diff --git a/tox.ini b/tox.ini
index 03e75ca..a77ac69 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py{27,34,35},js,docs
+envlist = py{27,34,35},js,docs,lint
 skipsdist = True
 
 

From 484d2839a1e04305a77cff64d143dd978d731094 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 17 2017 09:59:16 +0000
Subject: [PATCH 804/1001] Provide defaults to allow importing the app when building the docs


---

diff --git a/docs/api.rst b/docs/api.rst
index 449b292..a5c0786 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -3,6 +3,14 @@ Developer Interfaces
 
 This documents ways developers can interface with Fedora Hubs.
 
+
+View utils
+----------
+
+.. automodule:: hubs.views.utils
+   :members:
+
+
 .. _widgets-api:
 
 
diff --git a/hubs/app.py b/hubs/app.py
index a32788b..c8b5aca 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -35,8 +35,10 @@ if 'HUBS_CONFIG' in os.environ:
 fedmsg_config = fedmsg.config.load_config()
 fedmsg.meta.make_processors(**fedmsg_config)
 
-session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
-datanommer.models.init(fedmsg_config['datanommer.sqlalchemy.uri'])
+session = hubs.models.init(
+    fedmsg_config.get('hubs.sqlalchemy.uri', 'sqlite:///'))
+datanommer.models.init(
+    fedmsg_config.get('datanommer.sqlalchemy.uri', 'sqlite:///'))
 
 
 @app.before_request

From 68f92a71f78750f2393c3bff2e2cdedb9c06da45 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 21 2017 09:44:19 +0000
Subject: [PATCH 805/1001] Add Halp widget


---

diff --git a/hubs/default_config.py b/hubs/default_config.py
index 5837486..72cda31 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -44,6 +44,7 @@ CHAT_NETWORKS = [
     }
 ]
 
+DATAGREPPER_URI = 'https://apps.fedoraproject.org/datagrepper'
 
 WIDGETS = [
     'hubs.widgets.about:About',
@@ -58,6 +59,7 @@ WIDGETS = [
     'hubs.widgets.fhosted:FedoraHosted',
     'hubs.widgets.github_pr:GitHubPRs',
     'hubs.widgets.githubissues:GitHubIssues',
+    'hubs.widgets.halp:Halp',
     'hubs.widgets.meetings:Meetings',
     'hubs.widgets.memberships:Memberships',
     'hubs.widgets.pagure_pr:PagurePRs',
diff --git a/hubs/defaults.py b/hubs/defaults.py
index 2d27239..7bda776 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -82,6 +82,12 @@ def add_user_widgets(session, hub, username, fullname):
             'username': username,
         }))
     hub.widgets.append(widget)
+    hub.widgets.append(
+        hubs.models.Widget(
+            plugin='halp', index=9,
+            _config=json.dumps({
+            }))
+        )
     return hub
 
 
diff --git a/hubs/static/client/app/components/CompletionInput.jsx b/hubs/static/client/app/components/CompletionInput.jsx
new file mode 100644
index 0000000..9b8b581
--- /dev/null
+++ b/hubs/static/client/app/components/CompletionInput.jsx
@@ -0,0 +1,150 @@
+import React from 'react';
+import Autosuggest from 'react-autosuggest';
+
+
+export default class CompletionInput extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      value: "",
+      suggestions: [],
+      loading: false
+    }
+    this.resultsDomNodeStyle = {
+      position: "absolute",
+      width: "auto"
+    }
+    this.queryTimeout = null;
+    this.onResultClick = this.onResultClick.bind(this);
+    this.onChange = this.onChange.bind(this);
+    this.onSuggestionsFetchRequested = this.onSuggestionsFetchRequested.bind(this);
+    this.onSuggestionsClearRequested = this.onSuggestionsClearRequested.bind(this);
+    this.onSuggestionSelected = this.onSuggestionSelected.bind(this);
+    this.loadFromServer = this.loadFromServer.bind(this);
+  }
+
+  componentWillUnmount() {
+    if (this.serverRequest) { this.serverRequest.abort(); }
+  }
+
+  onResultClick(result) {
+    this.setState({
+      results: [],
+      value: result
+    });
+  }
+
+  onChange(e, {newValue}) {
+    this.setState({
+      value: newValue
+    });
+  }
+
+  onSuggestionSelected(e, {suggestionValue}) {
+    // Transmit a "fake" changed event to the parent, if asked to.
+    if (!this.props.onChange) { return; }
+    const mockedEvent = {
+      type: 'change',
+      target: {
+        type: 'input',
+        name: this.props.name,
+        value: suggestionValue,
+      },
+    }
+    this.props.onChange(mockedEvent);
+  }
+
+  // Autosuggest will call this function every time you need to update
+  // suggestions.
+  onSuggestionsFetchRequested({value}) {
+    var inputValue = value.trim().toLowerCase();
+    if (this.queryTimeout !== null) {
+      window.clearTimeout(this.queryTimeout);
+    }
+    if (this.serverRequest) { this.serverRequest.abort(); }
+    if (inputValue.length === 0) {
+      this.setState({
+        suggestions: [],
+        loading: false
+      });
+    } else {
+      this.queryTimeout = window.setTimeout(
+        this.loadFromServer, this.props.queryDelay, inputValue);
+    }
+  }
+
+  loadFromServer(value) {
+    this.setState({loading: true});
+    this.serverRequest = $.ajax({
+      url: this.props.url,
+      method: 'GET',
+      data: {q: value},
+      dataType: 'json',
+      cache: false,
+      success: function(data) {
+        this.setState({
+          suggestions: data.results,
+          loading: false
+        });
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.url, status, err.toString());
+        this.setState({loading: false});
+      }.bind(this)
+    });
+  }
+
+  // Autosuggest will call this function every time you need to clear
+  // suggestions.
+  onSuggestionsClearRequested() {
+    this.setState({
+      suggestions: []
+    });
+  }
+
+  render() {
+    // When a suggestion is clicked, this method will return the value to
+    // populate the input with.
+    const getSuggestionValue = suggestion => suggestion;
+    // Render suggestions.
+    const renderSuggestion = suggestion => suggestion;
+    // Autosuggest will pass through all these props to the input element.
+    const inputProps = {
+      //placeholder: 'Type a programming language',
+      name: this.props.name,
+      className: "form-control",
+      value: this.state.value,
+      placeholder: this.props.placeholder,
+      onChange: this.onChange,
+    };
+
+    // Render the widget.
+    return (
+      <div className="completion-input">
+        <Autosuggest
+          suggestions={this.state.suggestions}
+          onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
+          onSuggestionsClearRequested={this.onSuggestionsClearRequested}
+          onSuggestionSelected={this.onSuggestionSelected}
+          getSuggestionValue={getSuggestionValue}
+          renderSuggestion={renderSuggestion}
+          inputProps={inputProps}
+        />
+        { this.state.loading ?
+          <span className="form-control-feedback">
+            <img src={this.props.spinner} />
+          </span>
+        : null }
+      </div>
+    );
+  }
+
+}
+CompletionInput.defaultProps = {
+    placeholder: "",
+    queryDelay: 800,
+};
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/Modal.jsx b/hubs/static/client/app/components/Modal.jsx
new file mode 100644
index 0000000..1ba31b1
--- /dev/null
+++ b/hubs/static/client/app/components/Modal.jsx
@@ -0,0 +1,109 @@
+import React from 'react';
+
+
+export default class Modal extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.onShow = this.onShow.bind(this);
+    this.onShown = this.onShown.bind(this);
+    this.onHide = this.onHide.bind(this);
+    this.onHidden = this.onHidden.bind(this);
+    this.hide = this.hide.bind(this);
+    this.show = this.show.bind(this);
+    this.getModalBody = this.getModalBody.bind(this);
+    this.getModalFooter = this.getModalFooter.bind(this);
+  }
+
+  componentDidMount() {
+    if (this.domNode) {
+      $(this.domNode).on("show.bs.modal", this.onShow);
+      $(this.domNode).on("shown.bs.modal", this.onShown);
+      $(this.domNode).on("hide.bs.modal", this.onHide);
+      $(this.domNode).on("hidden.bs.modal", this.onHidden);
+    }
+  }
+
+  componentWillUnmount() {
+    if (this.domNode) {
+      $(this.domNode).off("show.bs.modal", this.onShow);
+      $(this.domNode).off("shown.bs.modal", this.onShown);
+      $(this.domNode).off("hide.bs.modal", this.onHide);
+      $(this.domNode).off("hidden.bs.modal", this.onHidden);
+    }
+  }
+
+  onShow(e) {
+    if (this.props.onShow) { this.props.onShow(); }
+  }
+  onShown(e) {
+    if (this.props.onShown) { this.props.onShown(); }
+  }
+  onHide(e) {
+    if (this.props.onHide) { this.props.onHide(); }
+  }
+  onHidden(e) {
+    if (this.props.onHidden) { this.props.onHidden(); }
+  }
+
+  hide(callback) {
+    if (!this.domNode) { return; }
+    var domNode = $(this.domNode);
+    if (callback) { domNode.one("hidden.bs.modal", callback); }
+    domNode.modal("hide");
+  }
+
+  show(callback) {
+    if (!this.domNode) { return; }
+    var domNode = $(this.domNode);
+    if (callback) { domNode.one("shown.bs.modal", callback); }
+    $(this.domNode).modal("show");
+  }
+
+  componentWillUpdate(nextProps, nextState) {
+    if (!nextProps.open) { this.hide(); }
+  }
+
+  componentDidUpdate() {
+    if (this.props.open) { this.show(); }
+  }
+
+  getModalBody() {
+    if (!this.props.data) { return ""; }
+  }
+
+  getModalFooter() {
+    return null;
+  }
+
+  render() {
+    var footer = this.getModalFooter();
+    return (
+      <div className="modal fade" role="dialog" ref={(ref) => this.domNode = ref}>
+        <div className="modal-dialog" role="document">
+          <div className="modal-content">
+            <div className="modal-header">
+              <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+              <h4 className="modal-title">{this.props.title}</h4>
+            </div>
+            <div className="modal-body">
+              {this.getModalBody()}
+            </div>
+            {footer ?
+            <div className="modal-footer">
+              {footer}
+            </div>
+             : null}
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
+Modal.propTypes = {
+    open: React.PropTypes.bool,
+    data: React.PropTypes.object
+};
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/Halp.jsx b/hubs/static/client/app/widgets/halp/Halp.jsx
new file mode 100644
index 0000000..f1db852
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Halp.jsx
@@ -0,0 +1,182 @@
+import React from 'react';
+import {
+  IntlProvider,
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import HubsList from './HubsList.jsx';
+import ModalRequest from './ModalRequest.jsx';
+import ModalAllRequests from './ModalAllRequests.jsx';
+import Request from './Request.jsx';
+
+
+const messages = defineMessages({
+  no_request: {
+    id: "hubs.widgets.halp.no_request",
+    defaultMessage: "No request for now."
+  },
+  view_more: {
+    id: "hubs.widgets.halp.view_more",
+    defaultMessage: "View more"
+  },
+  zoom_title: {
+    id: "hubs.widgets.halp.zoom.title",
+    defaultMessage: "Help request"
+  },
+  search_title: {
+    id: "hubs.widgets.halp.search.title",
+    defaultMessage: "All Help Requests"
+  },
+});
+
+
+export default class HalpWidget extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      requests: [],
+      inactiveHubs: [],
+      zoomedRequest: null,
+      allRequestsOpen: false,
+      loading: false
+    };
+    this.zoomOnRequest = this.zoomOnRequest.bind(this);
+    this.onZoomClose = this.onZoomClose.bind(this);
+    this.openAllRequests = this.openAllRequests.bind(this);
+    this.onAllRequestsClose = this.onAllRequestsClose.bind(this);
+    this.onHubClick = this.onHubClick.bind(this);
+  }
+
+  loadFromServer() {
+    this.setState({loading: true});
+    var data = { hubs: [] };
+    this.props.hubs.forEach(function(hub) {
+      if (this.state.inactiveHubs.indexOf(hub) === -1) {
+        data.hubs.push(hub);
+      }
+    }.bind(this));
+    this.serverRequest = $.ajax({
+      url: this.props.urls.data,
+      method: 'GET',
+      data: $.param(data, true),
+      dataType: 'json',
+      cache: false,
+      success: function(data) {
+        this.setState({
+          requests: data.requests,
+          loading: false
+        });
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.urls.data, status, err.toString());
+        this.setState({loading: false});
+      }.bind(this)
+    });
+  }
+
+  componentDidMount() {
+    this.loadFromServer();
+  }
+
+  componentWillUnmount() {
+    this.serverRequest.abort();
+  }
+
+  zoomOnRequest(request) {
+    this.setState({zoomedRequest: request});
+  }
+  onZoomClose() {
+    this.setState({zoomedRequest: null});
+  }
+
+  openAllRequests(e) {
+    e.preventDefault();
+    this.setState({allRequestsOpen: true});
+  }
+  onAllRequestsClose() {
+    this.setState({allRequestsOpen: false});
+  }
+
+  onHubClick(hubName) {
+    var newInactiveHubs = this.state.inactiveHubs.slice(),
+        inactiveIndex = this.state.inactiveHubs.indexOf(hubName);
+    if (inactiveIndex === -1) {
+      newInactiveHubs.push(hubName);
+    } else {
+      newInactiveHubs.splice(inactiveIndex, 1);
+    }
+    this.setState(
+      { inactiveHubs: newInactiveHubs },
+      this.loadFromServer);
+  }
+
+  render() {
+    var requestNodes;
+    if (this.state.requests.length === 0) {
+      requestNodes = (
+        <p className="no-request">
+          <FormattedMessage {...messages.no_request} />
+        </p>
+        );
+    } else {
+      var previousDate = null;
+      requestNodes = this.state.requests.map(function(request, idx) {
+        var showDate = (request.date !== previousDate);
+        previousDate = request.date;
+        return (
+          <Request
+            request={request}
+            showdate={showDate}
+            onZoomRequest={this.zoomOnRequest}
+            key={idx} />
+        );
+      }.bind(this));
+    }
+    var hubs = this.props.hubs.map(function(hub) {
+      return {
+        name: hub,
+        active: (this.state.inactiveHubs.indexOf(hub) === -1)
+      }
+    }.bind(this));
+    return (
+      <IntlProvider locale={navigator.language}>
+        <div className="widget-halp">
+          <HubsList
+            hubs={hubs}
+            onHubClick={this.onHubClick}
+            />
+          { this.state.loading ?
+              <img className="center-block" src={this.props.urls.spinner} />
+            :
+              <div className="requests">
+                {requestNodes}
+              </div>
+          }
+          <div className="view-more text-muted">
+            <button className="btn btn-secondary" onClick={this.openAllRequests}>
+              <FormattedMessage {...messages.view_more} />
+              &nbsp; <span className="fa fa-chevron-right" aria-hidden="true"></span>
+            </button>
+          </div>
+          <ModalRequest
+            open={this.state.zoomedRequest !== null}
+            data={this.state.zoomedRequest}
+            title={<FormattedMessage {...messages.zoom_title} />}
+            onHidden={this.onZoomClose} />
+          <ModalAllRequests
+            open={this.state.allRequestsOpen}
+            onHidden={this.onAllRequestsClose.bind(this)}
+            onZoomRequest={this.zoomOnRequest}
+            title={<FormattedMessage {...messages.search_title} />}
+            urls={this.props.urls}
+            hubs={hubs}
+            />
+        </div>
+      </IntlProvider>
+    );
+  }
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/Hub.jsx b/hubs/static/client/app/widgets/halp/Hub.jsx
new file mode 100644
index 0000000..044e6d9
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Hub.jsx
@@ -0,0 +1,23 @@
+import React from 'react';
+
+
+export default class Hub extends React.Component {
+
+  onClick(e) {
+    e.preventDefault();
+    this.props.onClick(this.props.name);
+  }
+
+  render() {
+    var activeClass = this.props.active ? "active" : "inactive";
+    return (
+      <span
+        className={"hub " + activeClass}
+        onClick={this.onClick.bind(this)}
+        >{"@" + this.props.name}</span>
+    );
+  }
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/HubsList.jsx b/hubs/static/client/app/widgets/halp/HubsList.jsx
new file mode 100644
index 0000000..3915dd4
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/HubsList.jsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { defineMessages, FormattedMessage } from 'react-intl';
+import Hub from './Hub.jsx';
+
+
+const messages = defineMessages({
+  watching_all_hubs: {
+    id: "hubs.widgets.halp.watching_all_hubs",
+    defaultMessage: "Watching all hubs"
+  },
+});
+
+
+export default class HubsList extends React.Component {
+  render() {
+    var hubNodes = this.props.hubs.map(function(hub, idx) {
+      return (
+        <Hub
+          name={hub.name}
+          active={hub.active}
+          onClick={this.props.onHubClick}
+          key={idx}
+          />
+      );
+    }.bind(this));
+    return (
+      <div className="hubs row">
+        <span className="fa fa-tags" aria-hidden="true"></span>
+        { (hubNodes.length !== 0) ?
+            hubNodes
+          :
+            <FormattedMessage
+              tagName="em"
+              {...messages.watching_all_hubs}
+              />
+        }
+      </div>
+    );
+  }
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx b/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
new file mode 100644
index 0000000..c3d13cd
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
@@ -0,0 +1,234 @@
+import { defineMessages, FormattedMessage } from 'react-intl';
+import CompletionInput from '../../components/CompletionInput.jsx';
+import Modal from '../../components/Modal.jsx';
+import Request from './Request.jsx';
+
+
+const messages = defineMessages({
+  no_request_found: {
+    id: "hubs.widgets.halp.no_request_found",
+    defaultMessage: "No request found."
+  },
+  search_meeting_name: {
+    id: "hubs.widgets.halp.search.meeting_name",
+    defaultMessage: "Meeting name"
+  },
+  search_between_dates: {
+    id: "hubs.widgets.halp.search.between_dates",
+    defaultMessage: "Between dates"
+  },
+  search_people: {
+    id: "hubs.widgets.halp.search.people",
+    defaultMessage: "People"
+  },
+  search_button: {
+    id: "hubs.widgets.halp.search.button",
+    defaultMessage: "Search"
+  },
+  pager_newer: {
+    id: "hubs.widgets.halp.pager.newer",
+    defaultMessage: "Newer"
+  },
+  pager_older: {
+    id: "hubs.widgets.halp.pager.older",
+    defaultMessage: "Older"
+  },
+  pager_status: {
+    id: "hubs.widgets.halp.pager.status",
+    defaultMessage: "Page {page} / {total}"
+  },
+});
+
+
+export default class ModalAllRequests extends Modal {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      requests: [],
+      page: {nr: 1, has_prev: false, has_next: false},
+      formData: {
+        hubs: this.props.hubs.filter(
+            function(hub) { return hub.active; }
+          ).map(
+            function(hub) { return hub.name; }
+          ),
+        },
+      loading: false,
+    };
+    this.onSubmit = this.onSubmit.bind(this);
+    this.loadFromServer = this.loadFromServer.bind(this);
+    this.onZoomRequest = this.onZoomRequest.bind(this);
+    this.changePage = this.changePage.bind(this);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  componentWillUnmount() {
+    super.componentWillUnmount();
+    this.serverRequest.abort();
+  }
+
+  onShown(e) {
+    super.onShown(e);
+    if (this.state.requests.length === 0) { this.loadFromServer(); }
+  }
+
+  onHidden(e) {
+    super.onHidden(e);
+    if (this.serverRequest) { this.serverRequest.abort(); }
+  }
+
+  onZoomRequest(request) {
+    // Close this modal and open the request modal
+    this.hide(function() {
+      this.props.onZoomRequest(request);
+    }.bind(this));
+  }
+
+  onSubmit(e) {
+    e.preventDefault();
+    this.loadFromServer();
+  }
+
+  changePage(inc) {
+    var requestedPage = this.state.page.nr + inc;
+    this.loadFromServer(requestedPage);
+  }
+
+  loadFromServer(requestedPage) {
+    const formData = this.state.formData;
+    formData.page = requestedPage || 1;
+    this.setState({loading: true});
+    this.serverRequest = $.ajax({
+      url: this.props.urls.search,
+      method: 'GET',
+      data: formData,
+      dataType: 'json',
+      cache: false,
+      success: function(data) {
+        this.setState({
+          requests: data.requests,
+          page: data.page,
+          loading: false
+        });
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.urls.search, status, err.toString());
+        this.setState({loading: false});
+      }.bind(this)
+    });
+  }
+
+  handleChange(e) {
+    const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+    const name = e.target.name;
+    var data = this.state.formData;
+    data[name] = value;
+    this.setState({formData: data});
+  }
+
+  getModalBody() {
+    var requestNodes;
+    if (this.state.requests.length === 0) {
+      requestNodes = (<p className="no-request">
+        <FormattedMessage {...messages.no_request_found} />
+      </p>);
+    } else {
+      requestNodes = this.state.requests.map(function(request, idx) {
+        return (
+          <Request
+            request={request}
+            showdate={false}
+            onZoomRequest={this.onZoomRequest}
+            key={idx} />
+        );
+      }.bind(this));
+    }
+    return (
+      <div>
+        <form className="row form-horizontal" method="post"
+              action={this.props.urls.search} onSubmit={this.onSubmit}>
+          <div className="form-group">
+            <label htmlFor="meetingname" className="col-sm-4 control-label">
+              <FormattedMessage {...messages.search_meeting_name} />
+            </label>
+            <div className="col-sm-8">
+              <input type="text" className="form-control" name="meetingname"
+                     onChange={this.handleChange} />
+            </div>
+          </div>
+          <div className="form-group">
+            <label htmlFor="startdate" className="col-sm-4 control-label">
+              <FormattedMessage {...messages.search_between_dates} />
+            </label>
+            <div className="col-sm-4">
+              <input type="date" className="form-control" name="startdate"
+                     onChange={this.handleChange} />
+            </div>
+            <div className="col-sm-4">
+              <input type="date" className="form-control" name="enddate"
+                     onChange={this.handleChange} />
+            </div>
+          </div>
+          <div className="form-group">
+            <label htmlFor="people" className="col-sm-4 control-label">
+              <FormattedMessage {...messages.search_people} />
+            </label>
+            <div className="col-sm-8">
+              <CompletionInput
+                name="people"
+                url={this.props.urls.requesters}
+                spinner={this.props.urls.spinnerCircle}
+                onChange={this.handleChange} />
+            </div>
+          </div>
+          <div className="form-group">
+            <div className="col-sm-offset-4 col-sm-8">
+              <button type="submit" className="btn btn-primary">
+                <FormattedMessage {...messages.search_button} />
+              </button>
+              { this.state.loading && <img style={{marginLeft: "2em"}} src={this.props.urls.spinner} /> }
+            </div>
+          </div>
+        </form>
+        <hr />
+        <div className="requests">
+          {requestNodes}
+        </div>
+      </div>
+    );
+  }
+
+  getModalFooter() {
+    if (this.state.requests.length === 0
+        || (!this.state.page.has_prev && !this.state.page.has_next)) {
+      // No results or only one page: don't show the pager.
+      return null;
+    }
+    return (
+      <nav aria-label="...">
+        <ul className="pager">
+          <li className={"pager-prev" + (this.state.page.has_prev ? "" : " disabled")}>
+            <a href="#" onClick={this.changePage.bind(this, -1)}>
+              <span aria-hidden="true">&larr;</span>
+              <FormattedMessage {...messages.pager_newer} />
+              </a>
+          </li>
+          <FormattedMessage
+            tagName="li"
+            {...messages.pager_status}
+            values={{page: this.state.page.nr, total: this.state.page.total_pages}}
+            />
+          <li className={"pager-next" + (this.state.page.has_next ? "" : " disabled")}>
+            <a href="#" onClick={this.changePage.bind(this, 1)}>
+              <FormattedMessage {...messages.pager_older} />
+              <span aria-hidden="true">&rarr;</span></a>
+          </li>
+        </ul>
+      </nav>
+    );
+  }
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/ModalRequest.jsx b/hubs/static/client/app/widgets/halp/ModalRequest.jsx
new file mode 100644
index 0000000..b6d0860
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/ModalRequest.jsx
@@ -0,0 +1,99 @@
+import { defineMessages, FormattedMessage } from 'react-intl';
+import Modal from '../../components/Modal.jsx';
+import getRequestView from './getRequestView.jsx';
+
+
+const messages = defineMessages({
+  zoom_part2_title: {
+    id: "hubs.widgets.halp.zoom.part2_title",
+    defaultMessage: "Want to help with this request?"
+  },
+  zoom_part2_subtitle: {
+    id: "hubs.widgets.halp.zoom.part2_subtitle",
+    defaultMessage: "Awesome! Here's some tips on getting started:"
+  },
+  zoom_tip1: {
+    id: "hubs.widgets.halp.zoom.tip1",
+    defaultMessage: "Take a look at the link provided in the request. It should have more information about the problem and may have instructions on how to get starter helping out:"
+  },
+  zoom_tip2: {
+    id: "hubs.widgets.halp.zoom.tip2",
+    defaultMessage: "Contact the person who requested help to get more information. By clicking on their name, you'll be taken to their profile where you can contact them:"
+  },
+  zoom_tip3: {
+    id: "hubs.widgets.halp.zoom.tip3",
+    defaultMessage: "Read through the chat log where the request occured. There may be additional context in the log that can help you figure out how to get started:"
+  },
+});
+
+
+export default class ModalRequest extends Modal {
+
+  getModalBody() {
+    if (!this.props.data) { return ""; }
+    return (
+      <div className="zoomed-request">
+        {getRequestView(this.props.data)}
+        <hr />
+        <FormattedMessage
+          tagName="h4"
+          {...messages.zoom_part2_title}
+          />
+        <FormattedMessage
+          tag="p"
+          {...messages.zoom_part2_subtitle}
+          />
+        <ol>
+          { this.props.data.urls ?
+          <li>
+            <FormattedMessage
+              {...messages.zoom_tip1}
+              />
+            <ul>
+              { this.props.data.urls.map(function(url, index) {
+                return (
+                  <li key={index}><a href={url}>
+                    {url.replace(/^https?:\/\//, '')}
+                  </a></li>);
+                }) }
+            </ul>
+          </li>
+          : null }
+          <li>
+            <FormattedMessage
+              {...messages.zoom_tip2}
+              />
+            <ul style={{listStyleType: "none"}}>
+              <li className="media">
+                <div className="media-left media-middle">
+                  <a href={this.props.data.author.url} target="_blank">
+                    <img className="square-32 img-circle"
+                         src={this.props.data.author.avatar} />
+                  </a>
+                </div>
+                <div className="media-body">
+                  <a href={this.props.data.author.url} target="_blank">
+                    {this.props.data.author.name}
+                  </a>
+                </div>
+              </li>
+            </ul>
+          </li>
+          <li>
+            <FormattedMessage
+              {...messages.zoom_tip3}
+              />
+            <ul style={{listStyleType: "none"}}>
+              <a href={this.props.data.context_url}>
+                {this.props.data.context_url.replace(/^https?:\/\//, '')}
+              </a>
+            </ul>
+          </li>
+        </ol>
+      </div>
+    );
+  }
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/Request.jsx b/hubs/static/client/app/widgets/halp/Request.jsx
new file mode 100644
index 0000000..bc80c6c
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Request.jsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import {FormattedRelative} from 'react-intl';
+import getRequestView from './getRequestView.jsx';
+
+
+export default class Request extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.onClick = this.onClick.bind(this);
+  }
+
+  onClick(e) {
+    e.preventDefault;
+    this.props.onZoomRequest(this.props.request);
+  }
+
+  render() {
+    var requestView = getRequestView(
+      this.props.request,
+      this.props.onZoomRequest ? this.onClick : null);
+    return (
+      <div>
+        { this.props.showdate ?
+            <div className="date text-uppercase">
+              <FormattedRelative value={new Date(this.props.request.date * 1000)} />
+            </div>
+          : ""
+        }
+        {requestView}
+      </div>
+    );
+  }
+}
+Request.defaultProps = {
+    onZoomRequest: null,
+};
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/getRequestView.jsx b/hubs/static/client/app/widgets/halp/getRequestView.jsx
new file mode 100644
index 0000000..3e0296f
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/getRequestView.jsx
@@ -0,0 +1,65 @@
+import { FormattedMessage, defineMessages } from 'react-intl';
+import Linkify from 'react-linkify';
+
+
+const messages = defineMessages({
+  req_no_text: {
+    id: "hubs.widgets.halp.req_no_text",
+    defaultMessage: "(no message)"
+  },
+});
+
+
+export default function getRequestView(request, openCallback) {
+    var openButton = "";
+    if (openCallback) {
+      openButton = (
+        <div className="media-right media-middle">
+          <button className="btn btn-secondary btn-sm" onClick={openCallback}>
+            <span className="fa fa-chevron-right" aria-hidden="true"></span>
+          </button>
+        </div>
+      );
+    }
+    return (
+      <div className="request row">
+        <div className="hub col-sm-6">
+          <span>@{request.hub}</span>
+        </div>
+        <div className="channel col-sm-6">
+          {request.channel}
+        </div>
+        <div className="text col-sm-12">
+          { request.text ?
+            <Linkify>"{request.text}"</Linkify>
+          :
+            <em><FormattedMessage {...messages.req_no_text } /></em>
+          }
+        </div>
+        { request.url ?
+        <div className="url col-sm-12">
+          <a href={request.url}>
+            {request.url.replace(/^https?:\/\//, '')}
+          </a>
+        </div>
+        : null }
+        <div className="author media col-sm-12">
+          <div className="media-left media-middle">
+            <a href={request.author.url} target="_blank">
+              <img className="media-object square-32 img-circle"
+                   src={request.author.avatar} />
+            </a>
+          </div>
+          <div className="media-body">
+            <a href={request.author.url}>
+              {request.author.name}
+            </a>
+          </div>
+          {openButton}
+        </div>
+      </div>
+    );
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 746d6c6..f237da9 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -14,6 +14,9 @@
     "react": "^15.4.0",
     "react-dom": "^15.4.0",
     "react-timeago": "^3.1.1",
+    "react-autosuggest": "~6.1.0",
+    "react-linkify": "^0.1.3",
+    "react-intl": "~2.1.5",
     "webpack": "~1.13.1"
   },
   "devDependencies": {
diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
index ba91ad0..4bd3fd9 100644
--- a/hubs/static/client/webpack.config.js
+++ b/hubs/static/client/webpack.config.js
@@ -10,6 +10,7 @@ const config = {
     entry: {
         Hubs: path.join(PATHS.app, 'core', 'Hubs.js'),
         Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.jsx'),
+        Halp: path.join(PATHS.app, 'widgets', 'halp', 'Halp.jsx')
     },
     output: {
         path: PATHS.build,
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index ab51d60..7516bea 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -451,6 +451,137 @@ font-size: 32pt;
 }
 
 
+/*
+ * Autosuggest
+ */
+.react-autosuggest__suggestions-container {
+    position: absolute;
+    z-index: 10;
+    width: 100%;
+    padding-right: 2em;
+}
+.react-autosuggest__suggestions-container ul {
+    list-style: none;
+    padding: 0.3em 0.8em;
+    background-color: #eee;
+    border-bottom-left-radius: 4px;
+    border-bottom-right-radius: 4px;
+}
+
+.form-control-feedback {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+  display: block;
+  width: 34px;
+  height: 34px;
+  line-height: 34px;
+  text-align: center;
+  pointer-events: none;
+}
+.input-lg + .form-control-feedback {
+  width: 46px;
+  height: 46px;
+  line-height: 46px;
+}
+.input-sm + .form-control-feedback {
+  width: 30px;
+  height: 30px;
+  line-height: 30px;
+}
+.form-horizontal .form-control-feedback {
+  right: 15px;
+}
+.form-inline .form-control-feedback {
+  top: 0;
+}
+
+
+
+/*
+ * Widget halp
+ */
+.widget-halp {
+}
+.widget-halp .hubs {
+    color: gray;
+}
+.widget-halp .hubs .fa {
+    margin-right: 4px;
+}
+.widget-halp .hubs span.hub {
+    border: 1px solid gray;
+    border-radius: 2px;
+    background-color: #eee;
+    display: inline-block;
+    margin: 2px 3px 2px 0;
+    padding: 1px 2px;
+    font-size: 90%;
+    cursor: pointer;
+}
+.widget-halp .hubs span.hub.inactive {
+    background-color: white;
+}
+.widget-halp .requests {
+}
+.widget-halp .requests .no-request {
+    margin-top: 10px;
+}
+.widget-halp .requests .date {
+    text-transform: uppercase;
+    font-size: 110%;
+    margin-top: 10px;
+}
+.widget-halp .request {
+    background-color: #f5f5f5;
+    padding: 1em 0;
+    margin-top: 5px;
+}
+.widget-halp .request .hub span {
+    float: left;
+    font-weight: bold;
+    color: white;
+    background-color: #5bc0de;
+    border-radius: 10px;
+    padding: 2px 4px;
+}
+.widget-halp .request .channel {
+    color: gray;
+    text-align: right;
+}
+.widget-halp .request .text {
+    margin-top: 10px;
+}
+.widget-halp .request .url {
+    margin-top: 5px;
+    margin-bottom: 15px;
+}
+.widget-halp .request .author {
+}
+.widget-halp .request .open {
+    text-align: right;
+}
+.widget-halp .request .open button {
+    background-color: white;
+    border-color: gray;
+}
+.widget-halp .request .open button:hover {
+    background-color: #ccc;
+}
+.widget-halp .zoomed-request ol>li {
+    margin-top: 1em;
+}
+.widget-halp .view-more {
+    margin-top: 2em;
+    text-align: center;
+}
+.widget-halp .view-more a {
+    color: gray;
+}
+
+
+
 /** fedora bootstrap overrides **/
 
 /** tightening up card headers - they are too fat imho **/
@@ -470,3 +601,7 @@ header h5.m-b-1 {
 .card .panel-footer {
   padding-bottom: 2rem; /* fixes request new meeting button padding on the upcoming meeting widget */
 }
+
+
+
+/* vim: set ts=2 sw=2 et: */
diff --git a/hubs/static/img/spinner-circle.gif b/hubs/static/img/spinner-circle.gif
new file mode 100644
index 0000000..d0bce15
Binary files /dev/null and b/hubs/static/img/spinner-circle.gif differ
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index c9e8c39..2c8f1ff 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -83,7 +83,7 @@ class HubsAPITest(hubs.tests.APPTest):
             "name": "ralph",
             "owners": ["ralph"],
             "subscribers": [],
-            "widgets": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56]
+            "widgets": [37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 61],
         }
         self.assertDictEqual(data, json.loads(result.get_data(as_text=True)))
 
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index 66c1488..8669160 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -32,7 +32,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets still are intact
         widgets = hubs.models.Widget.by_hub_id_all(hub.name)
-        self.assertEqual(12, len(widgets))
+        self.assertEqual(13, len(widgets))
 
     def test_delete_hubs(self):
         # verify the hub exists
@@ -48,7 +48,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets exist
         widgets = hubs.models.Widget.by_hub_id_all(hub.name)
-        self.assertEqual(12, len(widgets))
+        self.assertEqual(13, len(widgets))
 
         # delete the hub
         self.session.delete(hub)
diff --git a/hubs/widgets/halp/__init__.py b/hubs/widgets/halp/__init__.py
new file mode 100644
index 0000000..92df5a4
--- /dev/null
+++ b/hubs/widgets/halp/__init__.py
@@ -0,0 +1,35 @@
+from __future__ import unicode_literals
+
+
+import arrow
+
+from hubs.widgets.base import Widget
+from hubs.widgets import validators
+
+
+class Halp(Widget):
+
+    name = "halp"
+    label = "Help Requests"
+    position = "both"
+    parameters = [
+        dict(
+            name="hubs",
+            label="Hubs",
+            default=[],
+            validator=validators.CommaSeparatedList,
+            help="A comma-separated list of hubs to monitor.",
+        ), dict(
+            name="per_page",
+            label="Requests per page",
+            default=4,
+            validator=validators.Integer,
+            help="The number of requests per page to display.",
+        )]
+    views_module = ".views"
+    cached_functions_module = ".functions"
+
+    def get_template_environment(self):
+        env = super(Halp, self).get_template_environment()
+        env.filters['humanize'] = lambda d: arrow.get(d).humanize()
+        return env
diff --git a/hubs/widgets/halp/functions.py b/hubs/widgets/halp/functions.py
new file mode 100644
index 0000000..b7f2b88
--- /dev/null
+++ b/hubs/widgets/halp/functions.py
@@ -0,0 +1,149 @@
+from __future__ import unicode_literals
+
+
+import datetime
+import flask
+import fedmsg.meta
+import re
+import logging
+import requests
+import time
+
+from jinja2.utils import urlize
+
+from hubs.widgets.caching import CachedFunction
+
+
+log = logging.getLogger('hubs.widgets')
+
+
+class GetRequests(CachedFunction):
+
+    TOPIC = "org.fedoraproject.prod.meetbot.meeting.item.help"
+
+    def execute(self):
+        # return [_format_message(msg) for msg in EXAMPLE_DATA]
+        from hubs.app import app
+        url = "%s/raw" % app.config["DATAGREPPER_URI"]
+        args = {
+            "topic": self.TOPIC,
+            "delta": str(86400 * 10),  # 10 days
+            # "rows_per_page": per_page,
+        }
+        log.info("Getting request data from Datagrepper")
+        response = requests.get(url, args)
+        if response.status_code != 200:
+            log.warning("Could not get requests from Datagrepper: %s",
+                        response.text)
+            return []
+        raw_messages = response.json()["raw_messages"]
+        return [_format_message(msg) for msg in raw_messages]
+
+    def should_invalidate(self, message):
+        if message["topic"] != self.TOPIC:
+            return False
+        hubs = channel_to_hubs(message['msg']['channel'])
+        return bool(set(hubs) & set(self.instance.config["hubs"]))
+
+
+def channel_to_hubs(channel):
+    # TODO: Link the channel to the hubs that use it.
+    return [channel.lstrip("#")]
+
+
+def _format_message(raw_message):
+    msg = {
+        "date": raw_message["msg"]["details"]["time_"],
+        "channel": raw_message["msg"]["channel"],
+        "hubs": channel_to_hubs(raw_message["msg"]["channel"]),
+        "meeting_topic": raw_message["msg"]["meeting_topic"],
+        "text": raw_message["msg"]["details"]["line"],
+        "context_url": "%s.log.html#l-%s" % (
+            raw_message["msg"]["url"],
+            raw_message["msg"]["details"]["linenum"]),
+        "author": {
+            "name": raw_message["msg"]["details"]["nick"],
+            "avatar": fedmsg.meta.msg2secondary_icon(raw_message["msg"]),
+            "url": flask.url_for(
+                "hub", name=raw_message["msg"]["details"]["nick"]),
+        }
+    }
+    # Extract an URL in the line. Use jinja2's urlize function because the
+    # regexp are better and well-tested.
+    urlized = urlize(raw_message["msg"]["details"]["line"])
+    msg["urls"] = re.findall('<a href="([^"]+)"[^>]*>', urlized)
+    return msg
+
+
+EXAMPLE_DATA = [
+    {
+        "msg": {
+            "details": {
+                "time_": time.mktime((
+                    datetime.datetime.now() - datetime.timedelta(seconds=23)
+                    ).timetuple()),
+                "line": ("The #fedora-apps team needs people to help review "
+                         "code: https://pagure.io/fedora-hubs/issue/21."),
+                "linenum": 42,
+                "nick": "threebean",
+            },
+            "channel": "#fedora-devel",
+            "meeting_topic": "Hubs meeting",
+            "topic": "Hubs meeting",
+            "url": "https://meetbot.fedoraproject.org/fedora-devel/",
+        },
+    },
+    {
+        "msg": {
+            "details": {
+                "time_": time.mktime((
+                    datetime.datetime.now() - datetime.timedelta(hours=2)
+                    ).timetuple()),
+                "line": ("I need help creating signs for Flock: "
+                         "<https://fedorahosted.org/design-team/issue/423> and"
+                         " <https://fedorahosted.org/design-team/issue/424>."),
+                "linenum": 84,
+                "nick": "mizmo",
+            },
+            "channel": "#fedora-design",
+            "meeting_topic": "FLOCK meeting",
+            "topic": "FLOCK meeting",
+            "url": "https://meetbot.fedoraproject.org/fedora-design/",
+        }
+    },
+    {
+        "msg": {
+            "details": {
+                "time_": time.mktime((
+                    datetime.datetime.now() -
+                    datetime.timedelta(days=1, hours=2)
+                    ).timetuple()),
+                "line": ("I need help with the log out bug: "
+                         "https://pagure.io/fedora-hubs/issue/99"),
+                "linenum": 63,
+                "nick": "decause",
+            },
+            "channel": "#fedora-hubs",
+            "meeting_topic": "Hubs meeting",
+            "topic": "Hubs meeting",
+            "url": "https://meetbot.fedoraproject.org/fedora-hubs",
+        }
+    },
+    {
+        "msg": {
+            "details": {
+                "time_": time.mktime((
+                    datetime.datetime.now() -
+                    datetime.timedelta(days=3, hours=20)
+                    ).timetuple()),
+                "line": "Fedora-Hubs should be translated",
+                "linenum": 18,
+                "nick": "mizmo",
+            },
+            "channel": "#fedora-i18n",
+            "meeting_topic": "I18n meeting",
+            "topic": "I18n meeting",
+            "url": "https://meetbot.fedoraproject.org/fedora-hubs",
+        }
+    },
+]
diff --git a/hubs/widgets/halp/templates/halp.html b/hubs/widgets/halp/templates/halp.html
new file mode 100644
index 0000000..908d916
--- /dev/null
+++ b/hubs/widgets/halp/templates/halp.html
@@ -0,0 +1,22 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div id="widget-halp">
+</div>
+<script src="{{url_for('static', filename='js/build/Halp.js')}}"></script>
+<script>
+(function() {
+    const Widget = React.createElement(Halp, {
+        hubs: {{ hubs|tojson }},
+        urls: {
+            data: '{{ url_for("halp_data", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
+            search: '{{ url_for("halp_search", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
+            requesters: '{{ url_for("halp_requesters", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
+            spinner: '{{ url_for("static", filename="img/spinner.gif") }}',
+            spinnerCircle: '{{ url_for("static", filename="img/spinner-circle.gif") }}'
+        }
+    });
+    ReactDOM.render(Widget, document.getElementById('widget-halp'));
+})();
+</script>
+{% endblock %}
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
new file mode 100644
index 0000000..1aaf1ad
--- /dev/null
+++ b/hubs/widgets/halp/views.py
@@ -0,0 +1,160 @@
+from __future__ import unicode_literals, absolute_import
+
+import datetime
+import flask
+import time
+
+from hubs.widgets.base import WidgetView
+from .functions import GetRequests
+
+
+def paginate(values, per_page):
+    try:
+        total = values.count()
+    except TypeError:
+        total = len(values)
+    try:
+        page = flask.request.values.get("page", 1, int)
+    except ValueError:
+        page = 1
+    last_page = int(total / per_page)
+    if total > last_page * per_page:
+        last_page += 1
+    if last_page < 1:
+        last_page = 1
+    if page < 1:
+        page = 1
+    if page > last_page:
+        page = last_page
+    start = (page - 1) * per_page
+    end = start + per_page
+    page_data = {
+        "nr": page,
+        "has_prev": page > 1,
+        "has_next": page < last_page,
+        "total_entries": total,
+        "total_pages": last_page,
+    }
+    return values[start:end], page_data
+
+
+class BaseView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "halp.html"
+
+    def get_context(self, instance, *args, **kwargs):
+        return dict(
+            hubs=instance.config["hubs"],
+            title=self.widget.label,
+            )
+
+
+class DataView(WidgetView):
+
+    name = "data"
+    url_rules = ["data"]
+
+    def dispatch_request(self, *args, **kwargs):
+        """
+        The method that subclasses of :py:class:`flask.views.View` must
+        implement. It binds the other methods together.
+        """
+        instance = self._get_instance(*args, **kwargs)
+        get_requests = GetRequests(instance)
+        data = {"requests": []}
+        hubs_filter = flask.request.args.getlist("hubs")
+        for req in get_requests():
+            req["hub"] = req["hubs"][0]  # Arbitrarily assign the first hub.
+            if "hubs" in flask.request.args:
+                # Find which hubs are targeted by this message.
+                hubs = set(req["hubs"]) & set(hubs_filter)
+                if not hubs:
+                    continue
+                # Arbitrarily assign the first common hub.
+                req["hub"] = list(hubs)[0]
+            data["requests"].append(req)
+            if len(data["requests"]) == 3:
+                # Only 3 requests on the main widget.
+                break
+        return flask.jsonify(data)
+
+
+class SearchView(WidgetView):
+
+    name = "search"
+    url_rules = ["search"]
+    methods = ['GET', 'POST']
+
+    def dispatch_request(self, *args, **kwargs):
+        """
+        The method that subclasses of :py:class:`flask.views.View` must
+        implement. It binds the other methods together.
+        """
+        instance = self._get_instance(*args, **kwargs)
+        get_requests = GetRequests(instance)
+        # prepare filters
+        if "hubs" in flask.request.values:
+            # Find which hubs are targeted by this message.
+            filter_hubs = set(flask.request.values.getlist("hubs"))
+        else:
+            filter_hubs = None
+        filter_people = flask.request.values.get("people")
+        filter_meetingname = flask.request.values.get("meetingname")
+        if flask.request.values.get("startdate"):
+            filter_startdate = datetime.datetime.strptime(
+                flask.request.values.get("startdate"), "%Y-%m-%d")
+            filter_startdate = time.mktime(filter_startdate.timetuple())
+        else:
+            filter_startdate = None
+        if flask.request.values.get("enddate"):
+            filter_enddate = datetime.datetime.strptime(
+                flask.request.values.get("enddate"), "%Y-%m-%d")
+            filter_enddate = time.mktime(filter_enddate.timetuple())
+        else:
+            filter_enddate = None
+
+        # filter the data
+        data = {"requests": []}
+        for req in get_requests():
+            req["hub"] = req["hubs"][0]  # Arbitrarily assign the first hub.
+            if filter_hubs is not None and not set(req["hubs"]) & filter_hubs:
+                continue
+            if filter_people and filter_people not in req["author"]["name"]:
+                continue
+            if (filter_meetingname and
+                    filter_meetingname not in req["meeting_topic"]):
+                continue
+            if filter_startdate is not None and req["date"] < filter_startdate:
+                continue
+            if filter_enddate is not None and req["date"] > filter_enddate:
+                continue
+            data["requests"].append(req)
+        requests, page_data = paginate(
+            data["requests"], instance.config["per_page"])
+        data["requests"] = requests
+        data["page"] = page_data
+        return flask.jsonify(data)
+
+
+class RequestersView(WidgetView):
+
+    name = "requesters"
+    url_rules = ["requesters"]
+    MAX_SUGGESTS = 5
+
+    def dispatch_request(self, *args, **kwargs):
+        """
+        The method that subclasses of :py:class:`flask.views.View` must
+        implement. It binds the other methods together.
+        """
+        instance = self._get_instance(*args, **kwargs)
+        get_requests = GetRequests(instance)
+        results = set([
+            req["author"]["name"] for req in get_requests()
+            if req["author"]["name"].startswith(
+                flask.request.args.get("q"))
+            ])
+        results = sorted(list(results))[:self.MAX_SUGGESTS]
+        return flask.jsonify({"results": results})
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index a037a94..f1dcea7 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -148,3 +148,18 @@ class FedorahostedProject(Validator):
         if response.status_code == 200:
             return value
         raise ValueError('Invalid fedorahosted project')
+
+
+class CommaSeparatedList(Validator):
+
+    @classmethod
+    def from_string(cls, value):
+        return [
+            elem.strip() for elem in value.split(",") if elem.strip()
+            ]
+
+    @classmethod
+    def to_string(cls, value):
+        if not value:
+            return ""
+        return ", ".join(value)

From ed8fa02507a900e7bb802aa7be4565cd2fcc7e3d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 21 2017 09:44:19 +0000
Subject: [PATCH 806/1001] Add the Halp configuration panel


---

diff --git a/hubs/static/client/app/widgets/halp/Config.jsx b/hubs/static/client/app/widgets/halp/Config.jsx
new file mode 100644
index 0000000..9e81477
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Config.jsx
@@ -0,0 +1,226 @@
+import React from 'react';
+import {
+  IntlProvider,
+  defineMessages,
+  injectIntl,
+  FormattedMessage,
+  } from 'react-intl';
+import CompletionInput from '../../components/CompletionInput.jsx';
+
+
+const messages = defineMessages({
+  title_add: {
+    id: "hubs.widgets.halp.config.title.add",
+    defaultMessage: "Adding \"halp\" widget",
+  },
+  title_edit: {
+    id: "hubs.widgets.halp.config.title.edit",
+    defaultMessage: "Configuring \"halp\" widget",
+  },
+  followed_hubs: {
+    id: "hubs.widgets.halp.config.followed_hubs",
+    defaultMessage: "Followed hubs:",
+  },
+  no_hubs: {
+    id: "hubs.widgets.halp.config.no_hubs",
+    defaultMessage: "No hubs. Use the form to the right to add some.",
+  },
+  main_title: {
+    id: "hubs.widgets.halp.config.main_title",
+    defaultMessage: "Track help requests in hubs",
+  },
+  main_subtitle: {
+    id: "hubs.widgets.halp.config.main_subtitle",
+    defaultMessage: "Enter a team name below to add it to the list of hubs this widget will follow.",
+  },
+  placeholder: {
+    id: "hubs.widgets.halp.config.placeholder",
+    defaultMessage: "Enter team name here...",
+  },
+  add: {
+    id: "hubs.widgets.halp.config.add",
+    defaultMessage: "Add",
+  },
+  per_page: {
+    id: "hubs.widgets.halp.config.per_page",
+    defaultMessage: "Requests per page:",
+  },
+  per_page_help: {
+    id: "hubs.widgets.halp.config.per_page_help",
+    defaultMessage: "The number of requests per page to display.",
+  },
+  close: {
+    id: "hubs.widgets.halp.config.close",
+    defaultMessage: "Close",
+  },
+  cancel: {
+    id: "hubs.widgets.halp.config.cancel",
+    defaultMessage: "Cancel",
+  },
+  save: {
+    id: "hubs.widgets.halp.config.save",
+    defaultMessage: "Save",
+  },
+  remove_widget: {
+    id: "hubs.widgets.halp.config.remove_widget",
+    defaultMessage: "Remove this widget",
+  },
+});
+
+
+export default class Config extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = this.props.initialState;
+    this.addHub = this.addHub.bind(this);
+    this.removeHub = this.removeHub.bind(this);
+    this.onAddClick = this.onAddClick.bind(this);
+  }
+
+  addHub(name) {
+    // React may batch state updates:
+    // https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
+    this.setState(function(prevState, props) {
+      if (prevState.hubs.indexOf(name) === -1) {
+        prevState.hubs.push(name);
+      }
+      return {hubs: prevState.hubs};
+    });
+  }
+
+  removeHub(name) {
+    // React may batch state updates:
+    // https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
+    this.setState(function(prevState, props) {
+      prevState.hubs.splice(prevState.hubs.indexOf(name), 1);
+      return {hubs: prevState.hubs};
+    });
+  }
+
+  onAddClick(e) {
+    e.preventDefault();
+    var hubName = $(this.formDom).find("input[name='hub-add']").val();
+    this.addHub(hubName);
+  }
+
+  render() {
+    var titleMsg, followedHubs;
+    if (this.props.mode == "add") {
+      titleMsg = messages.title_add;
+    } else {
+      titleMsg = messages.title_edit;
+    }
+
+    followedHubs = this.state.hubs.map(function(hub, idx) {
+      return (
+        <li key={hub}>
+          <span className="hub">{hub}</span>
+          <span className="fa fa-times remove-hub"
+                onClick={(e) => this.removeHub(hub)}
+            />
+        </li>
+        );
+    }.bind(this));
+
+    const IntlCompletionInput = injectIntl((props) => (
+        <CompletionInput
+          name="hub-add"
+          url={props.urls.hubs}
+          spinner={props.urls.spinnerCircle}
+          placeholder={props.intl.formatMessage(messages.placeholder)}
+          />
+    ));
+
+    return (
+      <IntlProvider locale={navigator.language}>
+        <div className={"modal-dialog widget-halp-config widget-" + this.props.mode}>
+          <div className="modal-content">
+            <form method="post" action={this.props.urls.post}
+                  ref={(ref) => this.formDom = ref}>
+              <div className="modal-header">
+                <button type="button" className="close" data-dismiss="modal">&times;</button>
+                <h4 className="modal-title">
+                  <FormattedMessage {...titleMsg} />
+                </h4>
+              </div>
+              <div className="modal-body row">
+                <div className="col-sm-4 hubs-list">
+                  <FormattedMessage {...messages.followed_hubs} tagName="h5" />
+                  {this.state.hubs.length === 0 ?
+                    <FormattedMessage {...messages.no_hubs} tagName="p" />
+                  :
+                    <ul className="list-unstyled">
+                      {followedHubs}
+                    </ul>
+                  }
+                </div>
+                <div className="col-sm-8 form-side">
+                  <FormattedMessage {...messages.main_title} tagName="h4" />
+                  <FormattedMessage {...messages.main_subtitle} tagName="p" />
+                  <input type="hidden" name="hubs" value={this.state.hubs.join(",")} />
+                  <fieldset className="row">
+                    <div className="col-sm-9">
+                      <IntlCompletionInput {...this.props} />
+                    </div>
+                    <div className="col-sm-3">
+                      <button className="btn btn-info" onClick={this.onAddClick}>
+                        <FormattedMessage {...messages.add} />
+                      </button>
+                    </div>
+                  </fieldset>
+                  <fieldset className="row">
+                    <label className="col-sm-6 control-label">
+                      <FormattedMessage {...messages.per_page} />
+                    </label>
+                    <div className="col-sm-6">
+                      <input
+                        name="per_page"
+                        type="number"
+                        value={this.state.per_page}
+                        onChange={(e) => this.setState({per_page: e.target.value})}
+                        className="form-control input-sm"
+                        />
+                    </div>
+                    <div className="col-sm-12 text-muted">
+                      <FormattedMessage {...messages.per_page_help} tagName="small" />
+                    </div>
+                  </fieldset>
+                </div>
+              </div>
+              <div className="modal-footer">
+                <button type="button" className="btn btn-default" data-dismiss="modal">
+                  {this.props.mode === "add" ?
+                    <FormattedMessage {...messages.cancel} />
+                  :
+                    <FormattedMessage {...messages.close} />
+                  }
+                </button>
+                <button type="submit" className="btn btn-primary"
+                        disabled={this.state.hubs.length === 0 ? true : null}>
+                {this.props.mode === "add" ?
+                    <FormattedMessage {...messages.add} />
+                :
+                    <FormattedMessage {...messages.save} />
+                }
+                </button>
+              </div>
+            </form>
+            {this.props.mode !== "add" &&
+              <form method="POST" action={this.props.urls.remove} className="modal-footer p-abs" >
+                  <button type="submit" className="btn btn-danger" id="delete_widget">
+                    <FormattedMessage {...messages.remove_widget} />
+                  </button>
+              </form>
+            }
+          </div>
+        </div>
+      </IntlProvider>
+    );
+  }
+
+}
+
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/Halp.js b/hubs/static/client/app/widgets/halp/Halp.js
new file mode 100644
index 0000000..5b821f5
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Halp.js
@@ -0,0 +1,4 @@
+import Widget from './Widget.jsx';
+import Config from './Config.jsx';
+
+module.exports = {Widget, Config};
diff --git a/hubs/static/client/app/widgets/halp/Halp.jsx b/hubs/static/client/app/widgets/halp/Halp.jsx
deleted file mode 100644
index f1db852..0000000
--- a/hubs/static/client/app/widgets/halp/Halp.jsx
+++ /dev/null
@@ -1,182 +0,0 @@
-import React from 'react';
-import {
-  IntlProvider,
-  defineMessages,
-  FormattedMessage,
-  } from 'react-intl';
-import HubsList from './HubsList.jsx';
-import ModalRequest from './ModalRequest.jsx';
-import ModalAllRequests from './ModalAllRequests.jsx';
-import Request from './Request.jsx';
-
-
-const messages = defineMessages({
-  no_request: {
-    id: "hubs.widgets.halp.no_request",
-    defaultMessage: "No request for now."
-  },
-  view_more: {
-    id: "hubs.widgets.halp.view_more",
-    defaultMessage: "View more"
-  },
-  zoom_title: {
-    id: "hubs.widgets.halp.zoom.title",
-    defaultMessage: "Help request"
-  },
-  search_title: {
-    id: "hubs.widgets.halp.search.title",
-    defaultMessage: "All Help Requests"
-  },
-});
-
-
-export default class HalpWidget extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      requests: [],
-      inactiveHubs: [],
-      zoomedRequest: null,
-      allRequestsOpen: false,
-      loading: false
-    };
-    this.zoomOnRequest = this.zoomOnRequest.bind(this);
-    this.onZoomClose = this.onZoomClose.bind(this);
-    this.openAllRequests = this.openAllRequests.bind(this);
-    this.onAllRequestsClose = this.onAllRequestsClose.bind(this);
-    this.onHubClick = this.onHubClick.bind(this);
-  }
-
-  loadFromServer() {
-    this.setState({loading: true});
-    var data = { hubs: [] };
-    this.props.hubs.forEach(function(hub) {
-      if (this.state.inactiveHubs.indexOf(hub) === -1) {
-        data.hubs.push(hub);
-      }
-    }.bind(this));
-    this.serverRequest = $.ajax({
-      url: this.props.urls.data,
-      method: 'GET',
-      data: $.param(data, true),
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({
-          requests: data.requests,
-          loading: false
-        });
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.urls.data, status, err.toString());
-        this.setState({loading: false});
-      }.bind(this)
-    });
-  }
-
-  componentDidMount() {
-    this.loadFromServer();
-  }
-
-  componentWillUnmount() {
-    this.serverRequest.abort();
-  }
-
-  zoomOnRequest(request) {
-    this.setState({zoomedRequest: request});
-  }
-  onZoomClose() {
-    this.setState({zoomedRequest: null});
-  }
-
-  openAllRequests(e) {
-    e.preventDefault();
-    this.setState({allRequestsOpen: true});
-  }
-  onAllRequestsClose() {
-    this.setState({allRequestsOpen: false});
-  }
-
-  onHubClick(hubName) {
-    var newInactiveHubs = this.state.inactiveHubs.slice(),
-        inactiveIndex = this.state.inactiveHubs.indexOf(hubName);
-    if (inactiveIndex === -1) {
-      newInactiveHubs.push(hubName);
-    } else {
-      newInactiveHubs.splice(inactiveIndex, 1);
-    }
-    this.setState(
-      { inactiveHubs: newInactiveHubs },
-      this.loadFromServer);
-  }
-
-  render() {
-    var requestNodes;
-    if (this.state.requests.length === 0) {
-      requestNodes = (
-        <p className="no-request">
-          <FormattedMessage {...messages.no_request} />
-        </p>
-        );
-    } else {
-      var previousDate = null;
-      requestNodes = this.state.requests.map(function(request, idx) {
-        var showDate = (request.date !== previousDate);
-        previousDate = request.date;
-        return (
-          <Request
-            request={request}
-            showdate={showDate}
-            onZoomRequest={this.zoomOnRequest}
-            key={idx} />
-        );
-      }.bind(this));
-    }
-    var hubs = this.props.hubs.map(function(hub) {
-      return {
-        name: hub,
-        active: (this.state.inactiveHubs.indexOf(hub) === -1)
-      }
-    }.bind(this));
-    return (
-      <IntlProvider locale={navigator.language}>
-        <div className="widget-halp">
-          <HubsList
-            hubs={hubs}
-            onHubClick={this.onHubClick}
-            />
-          { this.state.loading ?
-              <img className="center-block" src={this.props.urls.spinner} />
-            :
-              <div className="requests">
-                {requestNodes}
-              </div>
-          }
-          <div className="view-more text-muted">
-            <button className="btn btn-secondary" onClick={this.openAllRequests}>
-              <FormattedMessage {...messages.view_more} />
-              &nbsp; <span className="fa fa-chevron-right" aria-hidden="true"></span>
-            </button>
-          </div>
-          <ModalRequest
-            open={this.state.zoomedRequest !== null}
-            data={this.state.zoomedRequest}
-            title={<FormattedMessage {...messages.zoom_title} />}
-            onHidden={this.onZoomClose} />
-          <ModalAllRequests
-            open={this.state.allRequestsOpen}
-            onHidden={this.onAllRequestsClose.bind(this)}
-            onZoomRequest={this.zoomOnRequest}
-            title={<FormattedMessage {...messages.search_title} />}
-            urls={this.props.urls}
-            hubs={hubs}
-            />
-        </div>
-      </IntlProvider>
-    );
-  }
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/Widget.jsx b/hubs/static/client/app/widgets/halp/Widget.jsx
new file mode 100644
index 0000000..71234a4
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Widget.jsx
@@ -0,0 +1,182 @@
+import React from 'react';
+import {
+  IntlProvider,
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import HubsList from './HubsList.jsx';
+import ModalRequest from './ModalRequest.jsx';
+import ModalAllRequests from './ModalAllRequests.jsx';
+import Request from './Request.jsx';
+
+
+const messages = defineMessages({
+  no_request: {
+    id: "hubs.widgets.halp.no_request",
+    defaultMessage: "No request for now."
+  },
+  view_more: {
+    id: "hubs.widgets.halp.view_more",
+    defaultMessage: "View more"
+  },
+  zoom_title: {
+    id: "hubs.widgets.halp.zoom.title",
+    defaultMessage: "Help request"
+  },
+  search_title: {
+    id: "hubs.widgets.halp.search.title",
+    defaultMessage: "All Help Requests"
+  },
+});
+
+
+export default class Widget extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      requests: [],
+      inactiveHubs: [],
+      zoomedRequest: null,
+      allRequestsOpen: false,
+      loading: false
+    };
+    this.zoomOnRequest = this.zoomOnRequest.bind(this);
+    this.onZoomClose = this.onZoomClose.bind(this);
+    this.openAllRequests = this.openAllRequests.bind(this);
+    this.onAllRequestsClose = this.onAllRequestsClose.bind(this);
+    this.onHubClick = this.onHubClick.bind(this);
+  }
+
+  loadFromServer() {
+    this.setState({loading: true});
+    var data = { hubs: [] };
+    this.props.hubs.forEach(function(hub) {
+      if (this.state.inactiveHubs.indexOf(hub) === -1) {
+        data.hubs.push(hub);
+      }
+    }.bind(this));
+    this.serverRequest = $.ajax({
+      url: this.props.urls.data,
+      method: 'GET',
+      data: $.param(data, true),
+      dataType: 'json',
+      cache: false,
+      success: function(data) {
+        this.setState({
+          requests: data.requests,
+          loading: false
+        });
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.urls.data, status, err.toString());
+        this.setState({loading: false});
+      }.bind(this)
+    });
+  }
+
+  componentDidMount() {
+    this.loadFromServer();
+  }
+
+  componentWillUnmount() {
+    this.serverRequest.abort();
+  }
+
+  zoomOnRequest(request) {
+    this.setState({zoomedRequest: request});
+  }
+  onZoomClose() {
+    this.setState({zoomedRequest: null});
+  }
+
+  openAllRequests(e) {
+    e.preventDefault();
+    this.setState({allRequestsOpen: true});
+  }
+  onAllRequestsClose() {
+    this.setState({allRequestsOpen: false});
+  }
+
+  onHubClick(hubName) {
+    var newInactiveHubs = this.state.inactiveHubs.slice(),
+        inactiveIndex = this.state.inactiveHubs.indexOf(hubName);
+    if (inactiveIndex === -1) {
+      newInactiveHubs.push(hubName);
+    } else {
+      newInactiveHubs.splice(inactiveIndex, 1);
+    }
+    this.setState(
+      { inactiveHubs: newInactiveHubs },
+      this.loadFromServer);
+  }
+
+  render() {
+    var requestNodes;
+    if (this.state.requests.length === 0) {
+      requestNodes = (
+        <p className="no-request">
+          <FormattedMessage {...messages.no_request} />
+        </p>
+        );
+    } else {
+      var previousDate = null;
+      requestNodes = this.state.requests.map(function(request, idx) {
+        var showDate = (request.date !== previousDate);
+        previousDate = request.date;
+        return (
+          <Request
+            request={request}
+            showdate={showDate}
+            onZoomRequest={this.zoomOnRequest}
+            key={idx} />
+        );
+      }.bind(this));
+    }
+    var hubs = this.props.hubs.map(function(hub) {
+      return {
+        name: hub,
+        active: (this.state.inactiveHubs.indexOf(hub) === -1)
+      }
+    }.bind(this));
+    return (
+      <IntlProvider locale={navigator.language}>
+        <div className="widget-halp">
+          <HubsList
+            hubs={hubs}
+            onHubClick={this.onHubClick}
+            />
+          { this.state.loading ?
+              <img className="center-block" src={this.props.urls.spinner} />
+            :
+              <div className="requests">
+                {requestNodes}
+              </div>
+          }
+          <div className="view-more text-muted">
+            <button className="btn btn-secondary" onClick={this.openAllRequests}>
+              <FormattedMessage {...messages.view_more} />
+              &nbsp; <span className="fa fa-chevron-right" aria-hidden="true"></span>
+            </button>
+          </div>
+          <ModalRequest
+            open={this.state.zoomedRequest !== null}
+            data={this.state.zoomedRequest}
+            title={<FormattedMessage {...messages.zoom_title} />}
+            onHidden={this.onZoomClose} />
+          <ModalAllRequests
+            open={this.state.allRequestsOpen}
+            onHidden={this.onAllRequestsClose.bind(this)}
+            onZoomRequest={this.zoomOnRequest}
+            title={<FormattedMessage {...messages.search_title} />}
+            urls={this.props.urls}
+            hubs={hubs}
+            />
+        </div>
+      </IntlProvider>
+    );
+  }
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
index 4bd3fd9..f197a0e 100644
--- a/hubs/static/client/webpack.config.js
+++ b/hubs/static/client/webpack.config.js
@@ -10,7 +10,7 @@ const config = {
     entry: {
         Hubs: path.join(PATHS.app, 'core', 'Hubs.js'),
         Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.jsx'),
-        Halp: path.join(PATHS.app, 'widgets', 'halp', 'Halp.jsx')
+        Halp: path.join(PATHS.app, 'widgets', 'halp', 'Halp.js')
     },
     output: {
         path: PATHS.build,
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 7516bea..7ff066f 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -580,6 +580,39 @@ font-size: 32pt;
     color: gray;
 }
 
+/* Config panel */
+.widget-halp-config .modal-body {
+  padding-top: 1em;
+}
+.widget-halp-config .hubs-list h5 {
+  font-weight: bold;
+}
+.widget-halp-config .hubs-list ul {
+  color: gray;
+}
+.widget-halp-config .hubs-list .hub {
+  border: 1px solid #aaa;
+  border-radius: 4px;
+  display: inline-block;
+  margin: 0.7em 0.5em 0 0;
+  padding: 1px 4px;
+  color: #aaa;
+}
+.widget-halp-config .hubs-list .remove-hub {
+  cursor: pointer;
+  font-weight: bold;
+}
+.widget-halp-config .modal-body .form-side {
+  border-left: 1px solid #aaa;
+}
+.widget-halp-config .modal-body h4 {
+  font-weight: bold;
+  margin-bottom: 1em;
+}
+.widget-halp-config fieldset {
+  margin-top: 1.5em;
+}
+
 
 
 /** fedora bootstrap overrides **/
diff --git a/hubs/widgets/halp/__init__.py b/hubs/widgets/halp/__init__.py
index 92df5a4..474fc83 100644
--- a/hubs/widgets/halp/__init__.py
+++ b/hubs/widgets/halp/__init__.py
@@ -2,9 +2,11 @@ from __future__ import unicode_literals
 
 
 import arrow
+import flask
 
 from hubs.widgets.base import Widget
 from hubs.widgets import validators
+from .views import add_view, hubs_suggest_view
 
 
 class Halp(Widget):
@@ -33,3 +35,22 @@ class Halp(Widget):
         env = super(Halp, self).get_template_environment()
         env.filters['humanize'] = lambda d: arrow.get(d).humanize()
         return env
+
+    def get_add_url(self, hub, position):
+        return "%s?position=%s" % (
+            flask.url_for('halp_config_add', hub=hub.name), position)
+
+    def get_edit_url(self, hub, widget_instance):
+        return flask.url_for(
+            'halp_config', hub=hub.name, idx=widget_instance.idx)
+
+    def register_routes(self, app):
+        super(Halp, self).register_routes(app)
+        # Add the widget add view
+        rule = "/<hub>/w/%s/add" % self.name
+        endpoint = "%s_config_add" % self.name
+        app.add_url_rule(rule, endpoint=endpoint, view_func=add_view)
+        # Add the hubs suggestion view
+        rule = "/w/%s/hubs" % self.name
+        endpoint = "%s_config_hubs" % self.name
+        app.add_url_rule(rule, endpoint=endpoint, view_func=hubs_suggest_view)
diff --git a/hubs/widgets/halp/templates/halp.html b/hubs/widgets/halp/templates/halp.html
index 908d916..8709b0e 100644
--- a/hubs/widgets/halp/templates/halp.html
+++ b/hubs/widgets/halp/templates/halp.html
@@ -6,7 +6,7 @@
 <script src="{{url_for('static', filename='js/build/Halp.js')}}"></script>
 <script>
 (function() {
-    const Widget = React.createElement(Halp, {
+    const Widget = React.createElement(Halp.Widget, {
         hubs: {{ hubs|tojson }},
         urls: {
             data: '{{ url_for("halp_data", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
diff --git a/hubs/widgets/halp/templates/halp_config.html b/hubs/widgets/halp/templates/halp_config.html
new file mode 100644
index 0000000..e64a526
--- /dev/null
+++ b/hubs/widgets/halp/templates/halp_config.html
@@ -0,0 +1,29 @@
+<div id="widget-halp-config">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-body">
+        <img src="{{ url_for("static", filename="img/spinner.gif") }}"
+             class="center-block" alt="loading..." />
+      </div>
+    </div>
+  </div>
+</div>
+
+<script src="{{url_for('static', filename='js/build/Halp.js')}}"></script>
+<script>
+(function() {
+    const ConfigPanel = React.createElement(Halp.Config, {
+        mode: {{ mode|tojson }},
+        initialState: {{ initial|tojson }},
+        urls: {
+            post: {{ url|tojson }},
+            hubs: '{{ url_for("halp_config_hubs") }}',
+            {% if mode != "add" %}
+            remove: '{{ url_for("widget_edit_delete", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
+            {% endif %}
+            spinnerCircle: '{{ url_for("static", filename="img/spinner-circle.gif") }}'
+        }
+    });
+    ReactDOM.render(ConfigPanel, document.getElementById('widget-halp-config'));
+})();
+</script>
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index 1aaf1ad..46d530e 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -4,6 +4,9 @@ import datetime
 import flask
 import time
 
+from hubs.models import Hub
+from hubs.views.utils import get_hub
+from hubs.widgets import registry
 from hubs.widgets.base import WidgetView
 from .functions import GetRequests
 
@@ -139,6 +142,9 @@ class SearchView(WidgetView):
 
 
 class RequestersView(WidgetView):
+    """
+    Returns suggestions for the "requesters" filter.
+    """
 
     name = "requesters"
     url_rules = ["requesters"]
@@ -158,3 +164,62 @@ class RequestersView(WidgetView):
             ])
         results = sorted(list(results))[:self.MAX_SUGGESTS]
         return flask.jsonify({"results": results})
+
+
+class ConfigView(WidgetView):
+    """
+    The custom configuration panel.
+    """
+
+    name = "config"
+    url_rules = ["config"]
+    template_name = "halp_config.html"
+
+    def get_context(self, instance, *args, **kwargs):
+        post_url = flask.url_for(
+            'widget_edit', hub=instance.hub.name, idx=instance.idx)
+        initial = instance.config.copy()
+        return dict(
+            mode="edit",
+            url=post_url,
+            initial=initial,
+            )
+
+
+def hubs_suggest_view():
+    """
+    Returns suggestions for the "hubs" list in the configuration.
+    """
+    MAX_SUGGESTS = 5
+    results = Hub.query
+    if flask.request.args.get("q"):
+        results = results.filter(Hub.name.ilike(
+            "%s%%" % flask.request.args.get("q")))
+    results = results.order_by(Hub.name)[:MAX_SUGGESTS]
+    return flask.jsonify({"results": [h.name for h in results]})
+
+
+def add_view(hub):
+    """The custom configuration panel when adding the widget.
+
+    This is not a subclass of WidgetView because it is not specific
+    to a widget instance, therefore it does not have the same URL
+    parameters.
+    """
+    hub = get_hub(hub)
+    widget = registry["halp"]
+    tpl_env = widget.get_template_environment()
+    template = tpl_env.get_template("halp_config.html")
+    post_url = "%s?position=%s" % (
+        flask.url_for('widget_add', hub=hub.name, widget="halp"),
+        flask.request.args.get("position"))
+    initial = dict(
+        (param.name, param.default)
+        for param in widget.get_parameters()
+        )
+    initial["hubs"] = [hub.name]
+    return template.render(
+        mode="add",
+        url=post_url,
+        initial=initial,
+    )

From 6dc1f63a5693c33c8123b17a09a81ebaaf446e44 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 21 2017 09:44:19 +0000
Subject: [PATCH 807/1001] Make widget views emit the template signals


And add a way to inspect rendered templates in unit tests.

---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index a3cc5f7..c430043 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -6,6 +6,7 @@ from datetime import datetime, timedelta
 import os
 
 import munch
+from flask import template_rendered
 from os.path import dirname
 import unittest
 
@@ -155,3 +156,18 @@ class FakeAuthorization(object):
         self.avatar = 'avatar_src_url'
         self.nickname = username
         self.username = username
+
+
+# http://flask.pocoo.org/docs/0.11/signals/#subscribing-to-signals
+
+@contextmanager
+def captured_templates(app):
+    recorded = []
+
+    def record(sender, template, context, **extra):
+        recorded.append((template, context))
+    template_rendered.connect(record, app)
+    try:
+        yield recorded
+    finally:
+        template_rendered.disconnect(record, app)
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index 46d530e..b4ce683 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals, absolute_import
 import datetime
 import flask
 import time
+from flask.signals import template_rendered, before_render_template
 
 from hubs.models import Hub
 from hubs.views.utils import get_hub
@@ -218,8 +219,8 @@ def add_view(hub):
         for param in widget.get_parameters()
         )
     initial["hubs"] = [hub.name]
-    return template.render(
-        mode="add",
-        url=post_url,
-        initial=initial,
-    )
+    context = dict(mode="add", url=post_url, initial=initial)
+    before_render_template.send(widget, template=template, context=context)
+    output = template.render(**context)
+    template_rendered.send(widget, template=template, context=context)
+    return output
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index 19ff77c..943302d 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -1,5 +1,6 @@
 from __future__ import unicode_literals, absolute_import
 
+from flask.signals import template_rendered, before_render_template
 from flask.views import View
 
 
@@ -97,4 +98,10 @@ class WidgetView(View):
         instance = self._get_instance(*args, **kwargs)
         context = self.get_context(instance, *args, **kwargs)
         context.update(self.get_extra_context(instance, *args, **kwargs))
-        return self.get_template().render(**context)
+        template = self.get_template()
+        before_render_template.send(
+            self.widget, template=template, context=context)
+        output = template.render(**context)
+        template_rendered.send(
+            self.widget, template=template, context=context)
+        return output

From d28b4a91a0028f4d96069779d9f46d00c3c53121 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 21 2017 09:44:19 +0000
Subject: [PATCH 808/1001] Map channels in messages to configured channels


---

diff --git a/hubs/widgets/halp/functions.py b/hubs/widgets/halp/functions.py
index b7f2b88..0c30728 100644
--- a/hubs/widgets/halp/functions.py
+++ b/hubs/widgets/halp/functions.py
@@ -1,4 +1,4 @@
-from __future__ import unicode_literals
+from __future__ import unicode_literals, absolute_import
 
 
 import datetime
@@ -12,6 +12,7 @@ import time
 from jinja2.utils import urlize
 
 from hubs.widgets.caching import CachedFunction
+from .utils import find_hubs_for_msg
 
 
 log = logging.getLogger('hubs.widgets')
@@ -42,20 +43,14 @@ class GetRequests(CachedFunction):
     def should_invalidate(self, message):
         if message["topic"] != self.TOPIC:
             return False
-        hubs = channel_to_hubs(message['msg']['channel'])
-        return bool(set(hubs) & set(self.instance.config["hubs"]))
-
-
-def channel_to_hubs(channel):
-    # TODO: Link the channel to the hubs that use it.
-    return [channel.lstrip("#")]
+        hubs = find_hubs_for_msg(message['msg'])
+        return bool(set(hubs) & set(self.instance.config.get("hubs", [])))
 
 
 def _format_message(raw_message):
     msg = {
         "date": raw_message["msg"]["details"]["time_"],
         "channel": raw_message["msg"]["channel"],
-        "hubs": channel_to_hubs(raw_message["msg"]["channel"]),
         "meeting_topic": raw_message["msg"]["meeting_topic"],
         "text": raw_message["msg"]["details"]["line"],
         "context_url": "%s.log.html#l-%s" % (
diff --git a/hubs/widgets/halp/utils.py b/hubs/widgets/halp/utils.py
new file mode 100644
index 0000000..86a5f00
--- /dev/null
+++ b/hubs/widgets/halp/utils.py
@@ -0,0 +1,17 @@
+from __future__ import unicode_literals
+
+from hubs.models import Hub, HubConfig
+
+
+def find_hubs_for_msg(msg):
+    """
+    Returns the hubs working in the given channel.
+
+    TODO: link meeting channels to the hub using them at that time.
+    """
+    return [
+        h[0] for h in
+        Hub.query.join(HubConfig).filter(
+            HubConfig.chat_channel == msg["channel"]
+        ).values(Hub.name)
+        ]
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index b4ce683..3c992f4 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -10,6 +10,7 @@ from hubs.views.utils import get_hub
 from hubs.widgets import registry
 from hubs.widgets.base import WidgetView
 from .functions import GetRequests
+from .utils import find_hubs_for_msg
 
 
 def paginate(values, per_page):
@@ -50,7 +51,7 @@ class BaseView(WidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         return dict(
-            hubs=instance.config["hubs"],
+            hubs=instance.config.get("hubs", []),
             title=self.widget.label,
             )
 
@@ -70,6 +71,9 @@ class DataView(WidgetView):
         data = {"requests": []}
         hubs_filter = flask.request.args.getlist("hubs")
         for req in get_requests():
+            req["hubs"] = find_hubs_for_msg(req)
+            if not req["hubs"]:
+                continue
             req["hub"] = req["hubs"][0]  # Arbitrarily assign the first hub.
             if "hubs" in flask.request.args:
                 # Find which hubs are targeted by this message.
@@ -122,6 +126,9 @@ class SearchView(WidgetView):
         # filter the data
         data = {"requests": []}
         for req in get_requests():
+            req["hubs"] = find_hubs_for_msg(req)
+            if not req["hubs"]:
+                continue
             req["hub"] = req["hubs"][0]  # Arbitrarily assign the first hub.
             if filter_hubs is not None and not set(req["hubs"]) & filter_hubs:
                 continue

From 5b80a602143b5263fa48c9a338afe909a62dc53c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 21 2017 09:44:19 +0000
Subject: [PATCH 809/1001] Add tests for the halp widget


---

diff --git a/hubs/tests/test_widgets/test_halp.py b/hubs/tests/test_widgets/test_halp.py
new file mode 100644
index 0000000..8950429
--- /dev/null
+++ b/hubs/tests/test_widgets/test_halp.py
@@ -0,0 +1,107 @@
+from __future__ import unicode_literals, absolute_import
+
+import json
+
+from hubs.models import Hub
+from hubs.tests import captured_templates
+from hubs.tests.test_widgets import WidgetTest
+from hubs.widgets import registry
+
+
+class HalpViewsTestCase(WidgetTest):
+    plugin = 'halp'  # The name in hubs.widgets.registry
+
+    def setUp(self):
+        super(HalpViewsTestCase, self).setUp()
+        self.widget = self.widget_instance('ralph', self.plugin)
+        config = self.widget.config
+        config["hubs"] = ["fedora-devel"]
+
+    def test_root(self):
+        with captured_templates(self.widget.module) as templates:
+            response = self.app.get('/ralph/w/halp/%i/' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(len(templates), 1)
+        _template, context = templates[0]
+        self.assertEqual(context["hubs"], [])
+
+    def test_json(self):
+        response = self.app.get('/ralph/%i/json' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEquals(data['plugin'], 'halp')
+        self.assertIn('hubs', data['data'].keys())
+
+    def test_config_add(self):
+        with captured_templates(self.widget.module) as templates:
+            response = self.app.get('/ralph/w/halp/add?position=right')
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(len(templates), 1)
+        _template, context = templates[0]
+        self.assertEqual(context["mode"], "add")
+        self.assertEqual(context["initial"], {
+            "hubs": ["ralph"], "per_page": 4,
+            })
+        self.assertEqual(context["url"], "/ralph/add/halp?position=right")
+
+    def test_config_edit(self):
+        with captured_templates(self.widget.module) as templates:
+            response = self.app.get('/ralph/w/halp/%i/config'
+                                    % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(len(templates), 1)
+        _template, context = templates[0]
+        self.assertEqual(context["mode"], "edit")
+        self.assertEqual(context["initial"], {})
+        self.assertEqual(context["url"], "/ralph/%i/edit" % self.widget.idx)
+
+    def test_config_hubs_suggest(self):
+        response = self.app.get('/w/halp/hubs')
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data, {
+            'results': ['decause', 'devyani7', 'dhrish', 'i18n', 'infra']
+        })
+
+
+class HalpFunctionsTestCase(WidgetTest):
+    plugin = 'halp'  # The name in hubs.widgets.registry
+
+    def setUp(self):
+        super(HalpFunctionsTestCase, self).setUp()
+        module = registry[self.plugin]
+        func_class = module.get_cached_functions()['GetRequests']
+        self.widget = self.widget_instance('ralph', self.plugin)
+        self.func = func_class(self.widget)
+        # The tested widget watches the infra hub.
+        config = self.widget.config
+        config["hubs"] = ["infra"]
+        self.widget.config = config
+        # The infra hub works in the fedora-infra channel.
+        infra_hub = Hub.query.filter_by(name="infra").one()
+        infra_hub.config.chat_channel = "#fedora-infra"
+        self.session.commit()
+
+    def test_should_invalidate_wrong_topic(self):
+        msg = {'topic': 'hubs.WRONG.TOPIC'}
+        result = self.func.should_invalidate(msg)
+        self.assertFalse(result)
+
+    def test_should_invalidate_wrong_hub(self):
+        # The decause hub works in the fedora-commops channel.
+        decause_hub = Hub.query.filter_by(name="decause").one()
+        decause_hub.config.chat_channel = "#fedora-commops"
+        self.session.commit()
+        msg = {'topic': 'org.fedoraproject.prod.meetbot.meeting.item.help',
+               'msg': {'channel': '#fedora-commops'},
+               }
+        # The decause hub cache would be invalidated, but not ours.
+        result = self.func.should_invalidate(msg)
+        self.assertFalse(result)
+
+    def test_should_invalidate_good_match(self):
+        msg = {'topic': 'org.fedoraproject.prod.meetbot.meeting.item.help',
+               'msg': {'channel': '#fedora-infra'},
+               }
+        result = self.func.should_invalidate(msg)
+        self.assertTrue(result)

From eef96dc161bfe0f05cf315c03bdda1d8cd2f4492 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Mar 22 2017 22:58:16 +0000
Subject: [PATCH 810/1001] Implement most of the review comments and add tests


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index c430043..67d82fa 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -158,10 +158,21 @@ class FakeAuthorization(object):
         self.username = username
 
 
-# http://flask.pocoo.org/docs/0.11/signals/#subscribing-to-signals
-
 @contextmanager
 def captured_templates(app):
+    """Context manager to inspect rendered templates.
+
+    See http://flask.pocoo.org/docs/0.11/signals/#subscribing-to-signals for
+    usage.
+
+    The argument is the signal emitter.  When calling a core Hubs view, this is
+    the Hubs app (``hubs.app.app`` or ``self.app.application`` if you're in an
+    :py:class:`APPTest` subclass).  If you're calling a widget view, the signal
+    emitter is the widget class, as found in the widgets registry.
+
+    Args:
+        app: The signal emitter.
+    """
     recorded = []
 
     def record(sender, template, context, **extra):
diff --git a/hubs/tests/test_widgets/test_halp.py b/hubs/tests/test_widgets/test_halp.py
index 8950429..81c1831 100644
--- a/hubs/tests/test_widgets/test_halp.py
+++ b/hubs/tests/test_widgets/test_halp.py
@@ -8,14 +8,105 @@ from hubs.tests.test_widgets import WidgetTest
 from hubs.widgets import registry
 
 
+SAMPLE_DATA = [
+    {
+        'author': {
+            'url': '/mattdm/', 'name': 'mattdm', 'avatar': None,
+            },
+        'channel': u'#fedora-meeting',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/fedora-meeting/'
+            '2017-03-17/fesco.2017-03-17-16.00.log.html#l-466'
+            ),
+        'date': 1489773443.0,
+        'meeting_topic': 'FESCO (2017-03-17)',
+        'text': ('"How to enable trim on your SSD drive" would '
+                 'be a good Fedora Magazine article'),
+        'urls': [],
+    }, {
+        'author': {
+            'url': '/jkurik/', 'name': 'jkurik', 'avatar': None,
+            },
+        'channel': '#fedora-meeting-2',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/fedora-meeting-2/2017-03-16/'
+            'f26-alpha-readiness-meeting.2017-03-16-19.00.log.html#l-103'),
+        'date': 1489692368.0,
+        'meeting_topic': 'F26 Alpha Readiness Meeting',
+        'text': ('The Marketing team wants to ask for help from '
+                 'Spins, Labs SIGs and DEs SIGs to populate the '
+                 'talking points that help us to marketing people'),
+        'urls': [],
+    }, {
+        'author': {
+            'url': '/stoney/', 'name': 'stoney', 'avatar': None,
+            },
+        'channel': '#foss2serve',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/foss2serve/2017-03-14/'
+            'posse_irc_meeting_1.2.2017-03-14-17.00.log.html#l-187'),
+        'date': 1489512523.0,
+        'meeting_topic': 'POSSE IRC Meeting 1.2',
+        'text': '',
+        'urls': [],
+    }, {
+        'author': {
+            'url': '/nitzmahone/', 'name': 'nitzmahone', 'avatar': None,
+            },
+        'channel': '#ansible-meeting',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/ansible-meeting/2017-03-14/'
+            'windows_working_group.2017-03-14-00.00.log.html#l-130'),
+        'date': 1489451407.0,
+        'meeting_topic': 'Windows Working Group',
+        'text': '',
+        'urls': [],
+    }, {
+        'author': {
+            'url': '/jborean93/', 'name': 'jborean93', 'avatar': None
+            },
+        'channel': '#ansible-meeting',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/ansible-meeting/2017-03-14/'
+            'windows_working_group.2017-03-14-00.00.log.html#l-59'),
+        'date': 1489450330.0,
+        'meeting_topic': 'Windows Working Group',
+        'text': 'with installers win_msi vs win_product',
+        'urls': [],
+    },
+]
+
+
 class HalpViewsTestCase(WidgetTest):
     plugin = 'halp'  # The name in hubs.widgets.registry
+    maxDiff = None
 
     def setUp(self):
         super(HalpViewsTestCase, self).setUp()
         self.widget = self.widget_instance('ralph', self.plugin)
         config = self.widget.config
         config["hubs"] = ["fedora-devel"]
+        config["per_page"] = 3
+        self.widget.config = config
+        infra_hub = Hub.query.get("infra")
+        infra_hub.config.chat_channel = "#fedora-meeting"
+        devyani7 = Hub.query.get("devyani7")
+        devyani7.config.chat_channel = "#fedora-meeting-2"
+        decause = Hub.query.get("decause")
+        decause.config.chat_channel = "#ansible-meeting"
+        dhrish = Hub.query.get("dhrish")
+        dhrish.config.chat_channel = "#foss2serve"
+        self.session.commit()
+
+    def _get_sample_data_with_hub_keys(self):
+        hub_names = ["infra", "devyani7", "dhrish", "decause", "decause"]
+        data = [req.copy() for req in SAMPLE_DATA]
+        for index, hub_name in enumerate(hub_names):
+            data[index].update({
+                'hub': hub_name,
+                'hubs': [hub_name],
+                })
+        return data
 
     def test_root(self):
         with captured_templates(self.widget.module) as templates:
@@ -23,7 +114,7 @@ class HalpViewsTestCase(WidgetTest):
         self.assertEqual(response.status_code, 200)
         self.assertEqual(len(templates), 1)
         _template, context = templates[0]
-        self.assertEqual(context["hubs"], [])
+        self.assertEqual(context["hubs"], ['fedora-devel'])
 
     def test_json(self):
         response = self.app.get('/ralph/%i/json' % self.widget.idx)
@@ -52,7 +143,10 @@ class HalpViewsTestCase(WidgetTest):
         self.assertEqual(len(templates), 1)
         _template, context = templates[0]
         self.assertEqual(context["mode"], "edit")
-        self.assertEqual(context["initial"], {})
+        self.assertEqual(context["initial"], {
+            'hubs': ['fedora-devel'],
+            'per_page': 3,
+            })
         self.assertEqual(context["url"], "/ralph/%i/edit" % self.widget.idx)
 
     def test_config_hubs_suggest(self):
@@ -62,6 +156,152 @@ class HalpViewsTestCase(WidgetTest):
         self.assertDictEqual(data, {
             'results': ['decause', 'devyani7', 'dhrish', 'i18n', 'infra']
         })
+        response = self.app.get('/w/halp/hubs?q=de')
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data, {
+            'results': ['decause', 'devyani7']
+        })
+
+    def test_data(self):
+        expected = self._get_sample_data_with_hub_keys()
+        # Test with no hub selected
+        response = self.app.get('/ralph/w/halp/%i/data' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {"requests": expected[:3]})
+        # Test with the right hub selected
+        response = self.app.get('/ralph/w/halp/%i/data?hubs=decause'
+                                % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {"requests": expected[3:5]})
+
+    def test_data_wrong_hub(self):
+        # Test with the wrong hub selected
+        response = self.app.get('/ralph/w/halp/%i/data?hubs=ralph'
+                                % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {"requests": []})
+
+    def test_search_requesters(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/requesters' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data, {
+            'results': ['jborean93', 'jkurik', 'mattdm', 'nitzmahone',
+                        'stoney']
+        })
+        response = self.app.get(
+            '/ralph/w/halp/%i/requesters?q=j' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data, {
+            'results': ['jborean93', 'jkurik']
+        })
+
+    def test_search_all(self):
+        expected = self._get_sample_data_with_hub_keys()
+        response = self.app.get(
+            '/ralph/w/halp/%i/search' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {
+            "requests": expected[:3],
+            'page': {
+                'has_next': True,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 5,
+                'total_pages': 2,
+                },
+            })
+        # Page 2
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?page=2' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {
+            "requests": expected[3:],
+            'page': {
+                'has_next': False,
+                'has_prev': True,
+                'nr': 2,
+                'total_entries': 5,
+                'total_pages': 2,
+                },
+            })
+
+    def test_search_hub(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?hubs=infra' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        expected = self._get_sample_data_with_hub_keys()
+        self.assertEqual(data, {
+            "requests": expected[0:1],
+            'page': {
+                'has_next': False,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 1,
+                'total_pages': 1
+                },
+            })
+
+    def test_search_people(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?people=nitzmahone' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        expected = self._get_sample_data_with_hub_keys()
+        self.assertEqual(data, {
+            "requests": expected[3:4],
+            'page': {
+                'has_next': False,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 1,
+                'total_pages': 1
+                },
+            })
+
+    def test_search_meetingname(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?meetingname=Readiness' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        expected = self._get_sample_data_with_hub_keys()
+        self.assertEqual(data, {
+            "requests": expected[1:2],
+            'page': {
+                'has_next': False,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 1,
+                'total_pages': 1
+                },
+            })
+
+    def test_search_date(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?startdate=2017-03-16&enddate=2017-03-17'
+            % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        expected = self._get_sample_data_with_hub_keys()
+        self.assertEqual(data, {
+            "requests": expected[1:2],
+            'page': {
+                'has_next': False,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 1,
+                'total_pages': 1
+                },
+            })
 
 
 class HalpFunctionsTestCase(WidgetTest):
@@ -82,6 +322,11 @@ class HalpFunctionsTestCase(WidgetTest):
         infra_hub.config.chat_channel = "#fedora-infra"
         self.session.commit()
 
+    def test_execute(self):
+        with self.app.application.test_request_context('/'):
+            result = self.func.execute()
+        self.assertEqual(result, SAMPLE_DATA)
+
     def test_should_invalidate_wrong_topic(self):
         msg = {'topic': 'hubs.WRONG.TOPIC'}
         result = self.func.should_invalidate(msg)
@@ -105,3 +350,98 @@ class HalpFunctionsTestCase(WidgetTest):
                }
         result = self.func.should_invalidate(msg)
         self.assertTrue(result)
+
+
+class PaginateTestCase(WidgetTest):
+
+    def setUp(self):
+        super(PaginateTestCase, self).setUp()
+        from hubs.widgets.halp.utils import paginate  # circular
+        self.paginate = paginate
+        self.values = ["A", "B", "C", "D"]
+
+    def test_base(self):
+        with self.app.application.test_request_context('/'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[:3])
+        self.assertDictEqual(result[1], {
+            'has_next': True,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_page_2(self):
+        with self.app.application.test_request_context('/?page=2'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[3:])
+        self.assertDictEqual(result[1], {
+            'has_next': False,
+            'has_prev': True,
+            'nr': 2,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_page_0(self):
+        with self.app.application.test_request_context('/?page=0'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[:3])
+        self.assertDictEqual(result[1], {
+            'has_next': True,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_invalid_page(self):
+        with self.app.application.test_request_context('/?page=blah'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[:3])
+        self.assertDictEqual(result[1], {
+            'has_next': True,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_page_too_high(self):
+        with self.app.application.test_request_context('/?page=3'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[3:])
+        self.assertDictEqual(result[1], {
+            'has_next': False,
+            'has_prev': True,
+            'nr': 2,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_single_page(self):
+        values = self.values[:3]
+        with self.app.application.test_request_context('/'):
+            result = self.paginate(values, 3)
+        self.assertListEqual(result[0], values)
+        self.assertDictEqual(result[1], {
+            'has_next': False,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': len(values),
+            'total_pages': 1,
+            })
+
+    def test_no_value(self):
+        values = []
+        with self.app.application.test_request_context('/'):
+            result = self.paginate(values, 3)
+        self.assertListEqual(result[0], [])
+        self.assertDictEqual(result[1], {
+            'has_next': False,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': 0,
+            'total_pages': 1,
+            })
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpFunctionsTestCase.test_execute b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpFunctionsTestCase.test_execute
new file mode 100644
index 0000000..1e03fdc
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpFunctionsTestCase.test_execute
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=630853]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 18:26:01 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data
new file mode 100644
index 0000000..4d48985
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data
@@ -0,0 +1,194 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=634315]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4028']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 18:58:53 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=583692]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4027']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:24:03 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub
new file mode 100644
index 0000000..6b0a36a
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy02.fedoraproject.org]
+      apptime: [D=886956]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:28:42 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_all b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_all
new file mode 100644
index 0000000..dfd7580
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_all
@@ -0,0 +1,194 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy11.fedoraproject.org]
+      apptime: [D=574648]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:53:38 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=684600]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4028']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 21:58:21 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_date b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_date
new file mode 100644
index 0000000..49d31ac
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_date
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA+2b+4+qypbH/xXj/HJv9rbl6WMn94dGQUXF5lUo0zedgkJBngK2j5v9v88CtR/7
+        9jmTM3MmOZmYdNJUQa1aa7Gq/HwF/9XE+WYfe0lZNH/8q+ni0tukeeBB6z//+b3ppkmJg+TaIl5U
+        4uaPXoejKOqB+t70EtL8QXN9iqEZpsNXXZs83WcedK9xVHjfm7FXDalGJ2n58qv9qi/Dbog3H3vK
+        NAvcD+194eXXZpoTL2/+AFcKt/m9+XlsBofgz/dmnh6Kl8zLXy49DP+9WZQ4Lytne32W612dfZsI
+        7G4e1h5Jc5zl6dZzywf4Tx5izyudtKz/B8nmISi9+MH3oqwJ07259bNK1D4B8/zFieLiBT68xF5R
+        XB2E7Hp5GayDKgkQwkynyplODzSTyEYgDDUkm7ppyyolmVp9jioHIS3rJkI4VIaqQWibkljdlAWb
+        ioYqSjlCaZplZrPnxKEzGY/trRFKmmbaA9OUWJuRBE9UOqqZDWyKt9RQspEoFShSpwaSzoRSYDT8
+        IUnWlmRq0FJHQ5LynKiGNlYNCWmmzBmmjxzTPlsRKZxYEjXkK2qErueV1DD7uoPsfLVVpvgxk7VQ
+        5ldb+eBI4dlc+uJz4oXSQo3JAoWy4NLawEFZYYXuEfII8wmKaghXaxLMRnBtLfIXTkhrizERTRSJ
+        g8jWzKUgPSeEzkrwRSej+WnF+lMcSjlYz13Lz7Hp8uQsDFRakhC1OmlxGSDmSJuVVSkbL5aRbYnv
+        /j0n5tKcVp7DXANF8kUkmgfD1GxC9U19GSnayD0YyH61RM3UDUHRpIg14kz2TFq0z4KC4j7kGdV5
+        hrx9zPRjJjiSbf5epn8vz8/Jb2V6EE/Oeuz/W6Z/L89gbWkr6vlDpi16O6dt1kZkSmJtODcmUwsR
+        bo4yU136cyeUX21TkwnKSgR5nFNZuqJ8uFYqnxMUZ6F6RsyKobeeeOyoS+0auZIjMdsbW2mrj44Z
+        5FYjj1lYRWZLBBGKNpQl8fUR4Y0RXd+V5+TX+2IuUTXf3kAK3IlMqGr8Y4VjSh7hkZYOomw8XwoB
+        tC81ESvgm5aQrWNER+hZzMVjCdaxFyoDJ8kEI5QTzEopZiKoBvegXtaLoJr9AY4kgTDExtR8atOR
+        BFkonhPX4nWHFSLI0dwe9FUvlCc6rc0WSJFgLe6wdfRdSlq4YTSaU8oAxzJD4lJaLAXORf4efMJm
+        TM9UM3p6TuaP2ZwYQqAPSTCjiYljP7RF9TSjkKSZ5dEeIRmF0VSPJROLR81B2lhPBNYaRaotzo8L
+        w37C44zVJP8Iq17KEDbt0Bwqu0FIMm0o8TZanVVWecVDzVJCX7aSiEMU3bEpLZ0jNJobtj9lxJNq
+        iLQ+UvbTMxFWbAQrC3YeFipDWJl92F3sLeQi0aq9wpRyjRKPyNIkQktDaAuEOlY7j62jTFZRFCiS
+        lGgmPwAbS31UWs8JHs3PmNWQI/ID2MNCZySXKIH7LMlQlcpAe8ywJaaHFSLYlcKTthUw7E7hpYJ9
+        TRHRyKYl5KBHGqwNStsRj7IiZfL07Itzi+b0kWRZon2E6FnwNUQmESDCcBBGrEnJHSQqA8/qC8gS
+        D2os5mYYyRjZe8hbRCJkrnjTjEKVKegZBRXA+MnKknLYNRWw5sPdH8KKmt5WlIXUqWodLSTSmsuS
+        YbUroUjSnhOIjtXDvuaFSDNMkapzZaKBJ9ITZNEjl86Wzoj3NRGtDFNG1/NDLNJPUBkWPmT16oLd
+        fwC7pTU5uaOjPaclThtfKtaI7IG6VEw1vqyY+TKDikYqzHa4WoMdiB5blTVGXhkxr5iGzz4ng1C7
+        7TwH2Hlgb82WZqJt57HC6XEmwMr5ZT0omoZgbw2rPZgUBElg9Yi1c8Q/JxbyBxf/DlPLgJVtVTsR
+        n9hMKShDSbDR5LCQ/AmmEQuz2Zpk6/PREXwnrAorSzdL1jLlAXykTaDelkSGnZGt/dsKar0WYdes
+        9tNLZIrhmsTQYRZNkiQ1lDUEtaeIZKCaIW8nIuzVsoytaAE7kujnRqy9zsVMNJb2q4GijqqXoj2E
+        CMeCAFUxnNJ+vDorUIdSbpzJkojFWQ0jDvI2M7Z+irfKwg61HHyL5C2spqF6fuRW4ZzWKXuhUURf
+        xZqB6Kg0DG2yWkoqltypzgoZ3soDN1KWsIoFdyshBUmxc45sT5RM+JShQ8qhNNtcbk7zkXgyh+ZJ
+        F49QGcLZkaLBjEUr86zstZEk4yTaQ1UbaJOtXFZ40q0SeY9pzQMzE0Gk2uA3aGHzj388J4BFQfNH
+        t9cF+Co2FdXhsgRS87wa8TRc+jhJgIoAUfR0X/penryMgAAjL665xU1JmnhRBJdwAH2bIIrTHIil
+        C+dI5PkxTiqQ+t5cH7wgrnAMsGe7TnOnmoHpQaOIg9KHi4CxtgcHOuEgxJH3Coffm1GQ7I9xSmqU
+        g3YMDhKYu8NVx0ccB1EUpDAJjIrDNKonZIEFgzwIYbYK5zY4ivCmmoOFq84pAUyDRqdiMR8H+edY
+        y3zvfQzl0n7z+dq8en1tVX5fDq+eXxqfHLx0Xf26NN49q9oXdxJIJxDff1wIs3WlyWZF1IDXUe0r
+        JKWiwufmOD00yrThJdiJvEaZB3EjTRqndJ83dH3YIHnw6j03G4d0H5GG4zVwY5OmpCHVthtzvMFn
+        MNUA3A3cyGvW6faSPeSX63QqZ13w9ZZzYGC4hS8XMO52WY5jH6ifFbbXLl5QHC6XRH2waPyNoehu
+        i2JbdPfvMDQ9JDWMv4V8JeoqVLrT6zUmiZvGWeSVXuNvCQRReoDhENXfGwNICmBxI103JKYDA/d5
+        lSG/LLPiR7t94+7PSA6Q3v6cwva7Q3CmcNOH944W3XmgqObPehm8BCBJmvXJNdfxOkyfb5G+x7S4
+        Pt9v9YjTb7Eus4YU4D6DK4eKYJPgcl9VS5PQE0ksZ5Fif6PMTB4U5qQrrIan4d7TS9tPnd0x7gdr
+        hzqu095+GnS6+6cJP6SMbrEcctPe6szuXXbKaKsQtr2eRzaL8rGnyUtKOvRjc7v2x4/a/mRact7m
+        N334zMo0EqfrDraWSfvszWfGhJ+cxyG/2AGTYv3J1HNZGYnL58Q3Z/vs8ajqfs4dXHVo2OZlEyig
+        YlzvJcFxHQIucZLG1XJ9O/UK+qUu4yb10Hngr8UAtyjOPhfE+339wzrp5/e77rnrnrvuueueu+65
+        65677rnrnv9j3cP2vtY9mOD4UEsKp6RqOQH/SVomQbLFdf+7PICT23B/ERvcVQrQFfoH0QbXp2+S
+        pVIoDiiZ/eUwOMcp+PAmCWim+kI4Bya/qJksx6/11+lU9fVwQtK4+hL50kydE9lXbF43Cj+o53yX
+        E53qS2yA96K8jjiyMPWpPnHTP91P8uca8kWXfIr2N/TQNeab0LlEe2tdAr62rjFfW5ewvxBDb7Ff
+        m7fwL82PGbj2vCXh1q7z8JWy+pSNS8ctIf+d8GoxX0ovw/dAPuVhfQ1oFRw3Djgpi0qN4SJsgFps
+        VEzbWOdp3NAziOR7Y4adoqFPRkUDgmkMxWsDhmRpto8AeRugsBsljsLKapYGtUUflxdb+/ra+G3a
+        zEuzz6qNptg31Xa9Q59UW6fPsJ3e16qN6TQeo8zHDc3DBAwWRWP+Jj5v8u3d6HXYWxL+x7qsxbwr
+        s057zXRauHKjld/cuF34rtc6Lbr/pV5zGYencJdqsSxZtzjWpVoOx9Otfp90KabH9gjX/0Wvvebt
+        k8OzvY44HSzQ2bGD46icPfmHMjTm/O4crmxN1gt1OenMtK6UtbX9mVb1jDzNfeMx2b4uvqUrk2zi
+        Wdt4TkSf4ba56Y3Vjr45KYEUjjq55u+P+pr1WJ0r88fNmDtryyf3cZ2/fhMWrxH7KHP9drB6FMfO
+        q7x5QqH4tPE66nMy2eWUtdzbYqFMrHy22zGPf5peu5XCXa/d9dpdr9312l2v3fXaXa/d9dpfWK+x
+        Hf5rvSbgY432oG4GEa6wDrTUQp/McVFUDAQiC4D9dhUgsnvc1df4XkCC6j0guMJPDzgn6/r89fil
+        boT7oojxPqo1FqB2udt7XvKyCRJQPNxF7ry8vNTT7/a4olHQlbmfngDOq+ddeRaEl5eNijJNvNOV
+        0y+Nl/qSEoM8SdPaqbK4yLlTGNb2b4KN+yTYbq5fHzu9+XjTO5eJvpA3aVEwIKNevS+FzSc10eu+
+        qYmrwU9qgqcZnvn6GdDTQtfFxkQb3DREg35gPj4GejN3HXClzD+iIt4CedcPXDuDXu8lyN2Xm0sw
+        8bty4Fp090vlQK9dmup2uq1ut9dtcbyHQTSAkHBdzLiu58Aexf76pMczhdftbrW10iLtURtjPR5B
+        URbmypWKUXgSqCwZG742XKHXJD0oy7gtjoJxuOUV+5zoAqwlIWaUjaORWYUL2mTdNzNfXnj7g0Kv
+        VoijBqFeGh1HN/rUhDY9MXekWMLuTIePIW6jiUFvnRS8OncfPT/femO+u3S0LiyneArn8GjNqhRP
+        YrTlnD/vSc/ttt+Vw1053JXDXTnclcNdOdyVw105/IWVA/Nbb7gRDH1s9U6ak+YeTvpsDe9bHx9C
+        rzikef1qWvWMp6wIOr80kqA8x9hPK2Ku3jC7EfrnN8pq29enJe/Wrx2fJrj23aa4PRx5n+TfMR4n
+        ReBE3u++H/aJ5atX364s/8HyJ57neJqjul/yvBUkJD0UDSvN62cTo+qnGx94/rPJ6yDmgW0AN5b7
+        4g9g/S+BfWT7w8WJl8PFiZf69yMf2b76pckXbM9gj2Y4impxmADb4w7b6nmYbfUdtk/zXYbqU94v
+        bK+lbblcBPYsgo/N3VIWnOV5dZ7mibVzKLoc9vvSaZn5u1mnPy+mvsHSO+ZcRnOW9uU4dGZu6eRL
+        e29qigIAGZfDKU6YwQrZpxl/0D1Fd1LuGz14pSyyOFLHUDjKJz/ivce2/+3gKru0HJ5fy6TfM0/q
+        QXBW64CT1Rk2fEAXUjpOONfgI9p5enTs9slT/zS2v5XAne3vbH9n+zvb39n+zvZ3tr+z/V+a7enf
+        YfveJ/ju/kre/Afs5j8zd/XjlL8o2B+C0m8ECXBbFAHRNQCMX+IiaLxeDitA27vlR/zn++/vBb25
+        /Av8UyxL/f+Df6dLvJ7nMS2P5egWxzq9Vp/vMS3So/vemqF5hia/wP/G2jHRXl0gYTUdbcUndPTm
+        /Vmne0bbdluhe0/lbNfrL+Oz+SqPJ/1AOR8VM15MnGI4eCpzSc4mtNxec2a/mD8nxVJ6GqPlWvkW
+        mABEE13MhqtVZ+Yrw91Ul2ws2x2XI5vDyXpqD0+Z2VG4NpvIdKS0d0e2bLe3JHF7u1NwhPU176X7
+        vhPE8n6UhSZj9YTiT4T/Swn8b+D/n9VgqEsouZ//BYvMG5AxQAAA
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=560197]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:51:05 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_hub b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_hub
new file mode 100644
index 0000000..c2ca0a7
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_hub
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=461727]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:51:07 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_meetingname b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_meetingname
new file mode 100644
index 0000000..07ed82f
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_meetingname
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=621781]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:36:08 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_people b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_people
new file mode 100644
index 0000000..d3b8371
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_people
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=474498]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:28:44 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_requesters b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_requesters
new file mode 100644
index 0000000..cd075ec
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_requesters
@@ -0,0 +1,194 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=642014]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 22:29:51 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA+2b+4+qypbH/xXj/HJv9rbl6WMn94dGQUXF5lUo0zedgkJBngK2j5v9v88CtR/7
+        9jmTM3MmOZmYdNJUQa1aa7Gq/HwF/9XE+WYfe0lZNH/8q+ni0tukeeBB6z//+b3ppkmJg+TaIl5U
+        4uaPXoejKOqB+t70EtL8QXN9imEYimerrk2e7jMPutc4KrzvzdirhlSjk7R8+dV+1ZdhN8Sbjz1l
+        mgXuh/a+8PJrM82Jlzd/gCuF2/ze/Dw2g0Pw53szTw/FS+blL5cehv/eLEqcl5WzvT7L967Ovk0E
+        djcPa4+kOc7ydOu55QP8Jw+x55VOWtb/g2TzEJRe/OB7UdaE6d7c+lklap+Aef7iRHHxAh9eYq8o
+        rg5Cdr28DNZBlQQIYaZT5UynB5pJZCMQhhqSTd20ZZWSTK0+R5WDkJZ1EyEcKkPVILRNSaxuyoJN
+        RUMVpRyhNM0ys9lz4tCZjMf21gglTTPtgWlKrM1IgicqHdXMBjbFW2oo2UiUChSpUwNJZ0IpMBr+
+        kCRrSzI1aKmjIUl5TlRDG6uGhDRT5gzTR45pn62IFE4siRryFTVC1/NKaph93UF2vtoqU/yYyVoo
+        86utfHCk8GwuffE58UJpocZkgUJZcGlt4KCssEL3CHmE+QRFNYSrNQlmI7i2FvkLJ6S1xZiIJorE
+        QWRr5lKQnhNCZyX4opPR/LRi/SkOpRys567l59h0eXIWBiotSYhanbS4DBBzpM3KqpSNF8vItsR3
+        /54Tc2lOK89hroEi+SISzYNhajah+qa+jBRt5B4MZL9aombqhqBoUsQacSZ7Ji3aZ0FBcR/yjOo8
+        Q94+ZvoxExzJNn8v07+X5+fktzI9iCdnPfb/LdO/l2ewtrQV9fwh0xa9ndM2ayMyJbE2nBuTqYUI
+        N0eZqS79uRPKr7apyQRlJYI8zqksXVE+XCuVzwmKs1A9I2bF0FtPPHbUpXaNXMmRmO2NrbTVR8cM
+        cquRxyysIrMlgghFG8qS+PqI8MaIru/Kc/LrfTGXqJpvbyAF7kQmVDX+scIxJY/wSEsHUTaeL4UA
+        2peaiBXwTUvI1jGiI/Qs5uKxBOvYC5WBk2SCEcoJZqUUMxFUg3tQL+tFUM3+AEeSQBhiY2o+telI
+        giwUz4lr8brDChHkaG4P+qoXyhOd1mYLpEiwFnfYOvouJS3cMBrNKWWAY5khcSktlgLnIn8PPmEz
+        pmeqGT09J/PHbE4MIdCHJJjRxMSxH9qieppRSNLM8miPkIzCaKrHkonFo+YgbawnAmuNItUW58eF
+        YT/hccZqkn+EVS9lCJt2aA6V3SAkmTaUeButziqrvOKhZimhL1tJxCGK7tiUls4RGs0N258y4kk1
+        RFofKfvpmQgrNoKVBTsPC5UhrMw+7C72FnKRaNVeYUq5RolHZGkSoaUhtAVCHaudx9ZRJqsoChRJ
+        SjSTH4CNpT4qrecEj+ZnzGrIEfkB7GGhM5JLlMB9lmSoSmWgPWbYEtPDChHsSuFJ2woYdqfwUsG+
+        pohoZNMSctAjDdYGpe2IR1mRMnl69sW5RXP6SLIs0T5C9Cz4GiKTCBBhOAgj1qTkDhKVgWf1BWSJ
+        BzUWczOMZIzsPeQtIhEyV7xpRqHKFPSMggpg/GRlSTnsmgpY8+HuD2FFTW8rykLqVLWOFhJpzWXJ
+        sNqVUCRpzwlEx+phX/NCpBmmSNW5MtHAE+kJsuiRS2dLZ8T7mohWhimj6/khFuknqAwLH7J6dcHu
+        P4Dd0pqc3NHRntMSp40vFWtE9kBdKqYaX1bMfJlBRSMVZjtcrcEORI+tyhojr4yYV0zDZ5+TQajd
+        dp4D7Dywt2ZLM9G281jh9DgTYOX8sh4UTUOwt4bVHkwKgiSwesTaOeKfEwv5g4t/h6llwMq2qp2I
+        T2ymFJShJNhoclhI/gTTiIXZbE2y9fnoCL4TVoWVpZsla5nyAD7SJlBvSyLDzsjW/m0FtV6LsGtW
+        ++klMsVwTWLoMIsmSZIayhqC2lNEMlDNkLcTEfZqWcZWtIAdSfRzI9Ze52ImGkv71UBRR9VL0R5C
+        hGNBgKoYTmk/Xp0VqEMpN85kScTirIYRB3mbGVs/xVtlYYdaDr5F8hZW01A9P3KrcE7rlL3QKKKv
+        Ys1AdFQahjZZLSUVS+5UZ4UMb+WBGylLWMWCu5WQgqTYOUe2J0omfMrQIeVQmm0uN6f5SDyZQ/Ok
+        i0eoDOHsSNFgxqKVeVb22kiScRLtoaoNtMlWLis86VaJvMe05oGZiSBSbfAbtLD5xz+eE8CioPmj
+        2+sCfBWbiupwWQKpeV6NeBoufZwkQEWAKHq6L30vT15GQICRF9fc4qYkTbwogks4gL5NEMVpDsTS
+        hXMk8vwYJxVIfW+uD14QVzgG2LNdp7lTzcD0oFHEQenDRcBY24MDnXAQ4sh7hcPvzShI9sc4JTXK
+        QTsGBwnM3eGq4yOOgygKUpgERsVhGtUTssCCQR6EMFuFcxscRXhTzcHCVeeUAKZBo1OxmI+D/HOs
+        Zb73PoZyab/5fG1evb62Kr8vh1fPL41PDl66rn5dGu+eVe2LOwmkE4jvPy6E2brSZLMiasDrqPYV
+        klJR4XNznB4aZdrwEuxEXqPMg7iRJo1Tus8buj5skDx49Z6bjUO6j0jD8Rq4sUlT0pBq24053uAz
+        mGoA7gZu5DXrdHvJHvLLdTqVsy74ess5MDDcwpcLGHe7LMcBGP+ssL128YLicLkk6oNF428MRXdb
+        FNuiu3+HoekhqWH8LeQrUVeh0p1erzFJ3DTOIq/0Gn9LIIjSAwyHqP7eGEBSAIsb6bohMR0YuM+r
+        DPllmRU/2u0bd39GcoD09ucUtt8dgjOFmz68d7TozgNFNX/Wy+AlAEnSrE+uuY7XYfp8i/Q9psX1
+        +X6rR5x+i3WZNaQA9xlcOVQEmwSX+6pamoSeSGI5ixT7G2Vm8qAwJ11hNTwN955e2n7q7I5xP1g7
+        1HGd9vbToNPdP034IWV0i+WQm/ZWZ3bvslNGW4Ww7fU8slmUjz1NXlLSoR+b27U/ftT2J9OS8za/
+        6cNnVqaROF13sLVM2mdvPjMm/OQ8DvnFDpgU60+mnsvKSFw+J74522ePR1X3c+7gqkPDNi+bQAEV
+        43ovCY7rEHCJkzSuluvbqVfQL3UZN6mHzgN/LQa4RXH2uSDe7+sf1kk/v991z1333HXPXffcdc9d
+        99x1z133/B/rHrb3te7BBMeHWlI4JVXLCfhP0jIJki2u+9/lAZzchvuL2OCuUoCu0D+INrg+fZMs
+        lUJxQMnsL4fBOU7BhzdJQDPVF8I5MPlFzWQ5fq2/Tqeqr4cTksbVl8iXZuqcyL5i87pR+EE957uc
+        6FRfYgO8F+V1xJGFqU/1iZv+6X6SP9eQL7rkU7S/oYeuMd+EziXaW+sS8LV1jfnauoT9hRh6i/3a
+        vIV/aX7MwLXnLQm3dp2Hr5TVp2xcOm4J+e+EV4v5UnoZvgfyKQ/ra0Cr4LhxwElZVGoMF2ED1GKj
+        YtrGOk/jhp5BJN8bM+wUDX0yKhoQTGMoXhswJEuzfQTI2wCF3ShxFFZWszSoLfq4vNja19fGb9Nm
+        Xpp9Vm00xb6ptusd+qTaOn2G7fS+Vm1Mp/EYZT5uaB4mYLAoGvM38XmTb+9Gr8PekvA/1mUt5l2Z
+        ddprptPClRut/ObG7cJ3vdZp0f0v9ZrLODyFu1SLZcm6xbEu1XI4nm71+6RLMT22R7j+L3rtNW+f
+        HJ7tdcTpYIHOjh0cR+XsyT+UoTHnd+dwZWuyXqjLSWemdaWsre3PtKpn5GnuG4/J9nXxLV2ZZBPP
+        2sZzIvoMt81Nb6x29M1JCaRw1Mk1f3/U16zH6lyZP27G3FlbPrmP6/z1m7B4jdhHmeu3g9WjOHZe
+        5c0TCsWnjddRn5PJLqes5d4WC2Vi5bPdjnn80/TarRTueu2u1+567a7X7nrtrtfueu2u1/7Ceo3t
+        8F/rNQEfa7QHdTOIcIV1oKUW+mSOi6JiIBBZAOy3qwCR3eOuvsb3AhJU7wHBFX56wDlZ1+evxy91
+        I9wXRYz3Ua2xALXL3d7zkpdNkIDi4S5y5+XlpZ5+t8cVjYKuzP30BHBePe/KsyC8vGxUlGnina6c
+        fmm81JeUGORJmtZOlcVFzp3CsLZ/E2zcJ8F2c/362OnNx5veuUz0hbxJi4IBGfXqfSlsPqmJXvdN
+        TVwNflITPM3wzNfPgJ4Wui42JtrgpiEa9APz8THQm7nrgCtl/hEV8RbIu37g2hn0ei9B7r7cXIKJ
+        35UD16K7XyoHeu3SVLfTbXW7vW6L4z0MogGEhOtixnU9B/Yo9tcnPZ4pvG53q62VFmmP2hjr8QiK
+        sjBXrlSMwpNAZcnY8LXhCr0m6UFZxm1xFIzDLa/Y50QXYC0JMaNsHI3MKlzQJuu+mfnywtsfFHq1
+        Qhw1CPXS6Di60acmtOmJuSPFEnZnOnwMcRtNDHrrpODVufvo+fnWG/PdpaN1YTnFUziHR2tWpXgS
+        oy3n/HlPem63/a4c7srhrhzuyuGuHO7K4a4c7srhL6wcmN96w41g6GOrd9KcNPdw0mdreN/6+BB6
+        xSHN61fTqmc8ZUXQ+aWRBOU5xn5aEXP1htmN0D+/UVbbvj4tebd+7fg0wbXvNsXt4cj7JP+O8Tgp
+        Aifyfvf9sE8sX736dmX5D5Y/8TzH0xzV/ZLnrSAh6aFoWGleP5sYVT/d+MDzn01eBzEPbAO4sdwX
+        fwDrfwnsI9sfLk68HC5OvNS/H/nI9tUvTb5gewZ7NMNRVIvDBNged9hWz8Nsq++wfZrvMlSf8n5h
+        ey1ty+UisGcRfGzulrLgLM+r8zRPrJ1D0eWw35dOy8zfzTr9eTH1DZbeMecymrO0L8ehM3NLJ1/a
+        e1NTFADIuBxOccIMVsg+zfiD7im6k3Lf6MErZZHFkTqGwlE++RHvPbb9bwdX2aXl8PxaJv2eeVIP
+        grNaB5yszrDhA7qQ0nHCuQYf0c7To2O3T576p7H9rQTubH9n+zvb39n+zvZ3tr+z/Z3t/9JsT/8O
+        2/c+wXf3V/LmP2A3/5m5qx+n/EXB/hCUfiNIgNuiCIiuAWD8EhdB4/VyWAHa3i0/4j/ff38v6M3l
+        X+CfYlnq/x/8O13i9TyPaXksR7c41um1+nyPaZEe3ffWDM0zNPkF/jfWjon26gIJq+loKz6hozfv
+        zzrdM9q22wrdeypnu15/GZ/NV3k86QfK+aiY8WLiFMPBU5lLcjah5faaM/vF/DkpltLTGC3XyrfA
+        BCCa6GI2XK06M18Z7qa6ZGPZ7rgc2RxO1lN7eMrMjsK12USmI6W9O7Jlu70lidvbnYIjrK95L933
+        nSCW96MsNBmrJxR/IvxfSuB/A///rAZDXULJ/fwvxci8aTFAAAA=
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=442751]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4028']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 22:34:13 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/widgets/halp/__init__.py b/hubs/widgets/halp/__init__.py
index 474fc83..47b47fb 100644
--- a/hubs/widgets/halp/__init__.py
+++ b/hubs/widgets/halp/__init__.py
@@ -10,6 +10,13 @@ from .views import add_view, hubs_suggest_view
 
 
 class Halp(Widget):
+    """Widget to list and query help requests.
+
+    In IRC channels, people can request help using the #halp keyword.
+    This widget will list those requests and allow searching through them.
+
+    See https://pagure.io/fedora-hubs/issue/98
+    """
 
     name = "halp"
     label = "Help Requests"
diff --git a/hubs/widgets/halp/functions.py b/hubs/widgets/halp/functions.py
index 0c30728..89cf0df 100644
--- a/hubs/widgets/halp/functions.py
+++ b/hubs/widgets/halp/functions.py
@@ -2,13 +2,13 @@ from __future__ import unicode_literals, absolute_import
 
 
 import datetime
-import flask
-import fedmsg.meta
-import re
 import logging
-import requests
+import re
 import time
 
+import flask
+import fedmsg.meta
+import requests
 from jinja2.utils import urlize
 
 from hubs.widgets.caching import CachedFunction
@@ -19,6 +19,11 @@ log = logging.getLogger('hubs.widgets')
 
 
 class GetRequests(CachedFunction):
+    """Get the help requests from Datagrepper.
+
+    This function will request recent help requests from datagrepper and cache
+    them.
+    """
 
     TOPIC = "org.fedoraproject.prod.meetbot.meeting.item.help"
 
@@ -29,7 +34,6 @@ class GetRequests(CachedFunction):
         args = {
             "topic": self.TOPIC,
             "delta": str(86400 * 10),  # 10 days
-            # "rows_per_page": per_page,
         }
         log.info("Getting request data from Datagrepper")
         response = requests.get(url, args)
@@ -48,6 +52,10 @@ class GetRequests(CachedFunction):
 
 
 def _format_message(raw_message):
+    """
+    Format a raw Fedmsg message dict into a dict that the Halp widget will be
+    able to use more directly.
+    """
     msg = {
         "date": raw_message["msg"]["details"]["time_"],
         "channel": raw_message["msg"]["channel"],
diff --git a/hubs/widgets/halp/utils.py b/hubs/widgets/halp/utils.py
index 86a5f00..4d4c210 100644
--- a/hubs/widgets/halp/utils.py
+++ b/hubs/widgets/halp/utils.py
@@ -1,5 +1,7 @@
 from __future__ import unicode_literals
 
+import flask
+
 from hubs.models import Hub, HubConfig
 
 
@@ -8,6 +10,10 @@ def find_hubs_for_msg(msg):
     Returns the hubs working in the given channel.
 
     TODO: link meeting channels to the hub using them at that time.
+
+    Args:
+        msg (dict): the ``msg`` value in the raw message dict sent through
+            Fedmsg.
     """
     return [
         h[0] for h in
@@ -15,3 +21,60 @@ def find_hubs_for_msg(msg):
             HubConfig.chat_channel == msg["channel"]
         ).values(Hub.name)
         ]
+
+
+def paginate(values, per_page):
+    """Paginate the values.
+
+    The requested page will be extracted from the ``page`` query string
+    element.
+
+    The returned value will be a tuple with two elements:
+
+    - the paginated values
+    - the page information
+
+    The page information is a dictionary with the following keys:
+
+    - ``nr``: the page number
+    - ``has_prev``: ``True`` if there is a previous page, ``False`` otherwise
+    - ``has_next``: ``True`` if there is a following page, ``False`` otherwise
+    - ``total_entries``: the total number of entries in the ``values`` argument
+    - ``total_pages``: the total number of pages
+
+    Args:
+        values (list or query): The list or SQLAlchemy query object to
+            paginate.
+        per_page (int): the number of elements per page.
+
+    Returns:
+        tuple: a tuple containing the paginated values and the page
+            information.
+    """
+    try:
+        total = values.count()
+    except TypeError:
+        total = len(values)
+    try:
+        page = flask.request.values.get("page", 1, int)
+    except ValueError:
+        page = 1
+    last_page = int(total / per_page)
+    if total > last_page * per_page:
+        last_page += 1
+    if last_page < 1:
+        last_page = 1
+    if page < 1:
+        page = 1
+    if page > last_page:
+        page = last_page
+    start = (page - 1) * per_page
+    end = start + per_page
+    page_data = {
+        "nr": page,
+        "has_prev": page > 1,
+        "has_next": page < last_page,
+        "total_entries": total,
+        "total_pages": last_page,
+    }
+    return values[start:end], page_data
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index 3c992f4..264da3d 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -1,8 +1,9 @@
 from __future__ import unicode_literals, absolute_import
 
 import datetime
-import flask
 import time
+
+import flask
 from flask.signals import template_rendered, before_render_template
 
 from hubs.models import Hub
@@ -10,40 +11,11 @@ from hubs.views.utils import get_hub
 from hubs.widgets import registry
 from hubs.widgets.base import WidgetView
 from .functions import GetRequests
-from .utils import find_hubs_for_msg
-
-
-def paginate(values, per_page):
-    try:
-        total = values.count()
-    except TypeError:
-        total = len(values)
-    try:
-        page = flask.request.values.get("page", 1, int)
-    except ValueError:
-        page = 1
-    last_page = int(total / per_page)
-    if total > last_page * per_page:
-        last_page += 1
-    if last_page < 1:
-        last_page = 1
-    if page < 1:
-        page = 1
-    if page > last_page:
-        page = last_page
-    start = (page - 1) * per_page
-    end = start + per_page
-    page_data = {
-        "nr": page,
-        "has_prev": page > 1,
-        "has_next": page < last_page,
-        "total_entries": total,
-        "total_pages": last_page,
-    }
-    return values[start:end], page_data
+from .utils import find_hubs_for_msg, paginate
 
 
 class BaseView(WidgetView):
+    """The base view to instantiate the widget."""
 
     name = "root"
     url_rules = ["/"]
@@ -57,15 +29,12 @@ class BaseView(WidgetView):
 
 
 class DataView(WidgetView):
+    """Get the requests in JSON format."""
 
     name = "data"
     url_rules = ["data"]
 
     def dispatch_request(self, *args, **kwargs):
-        """
-        The method that subclasses of :py:class:`flask.views.View` must
-        implement. It binds the other methods together.
-        """
         instance = self._get_instance(*args, **kwargs)
         get_requests = GetRequests(instance)
         data = {"requests": []}
@@ -90,16 +59,13 @@ class DataView(WidgetView):
 
 
 class SearchView(WidgetView):
+    """Search the requests and return the result as JSON."""
 
     name = "search"
     url_rules = ["search"]
     methods = ['GET', 'POST']
 
     def dispatch_request(self, *args, **kwargs):
-        """
-        The method that subclasses of :py:class:`flask.views.View` must
-        implement. It binds the other methods together.
-        """
         instance = self._get_instance(*args, **kwargs)
         get_requests = GetRequests(instance)
         # prepare filters
@@ -150,26 +116,21 @@ class SearchView(WidgetView):
 
 
 class RequestersView(WidgetView):
-    """
-    Returns suggestions for the "requesters" filter.
-    """
+    """Returns suggestions for the "requesters" filter."""
 
     name = "requesters"
     url_rules = ["requesters"]
     MAX_SUGGESTS = 5
 
     def dispatch_request(self, *args, **kwargs):
-        """
-        The method that subclasses of :py:class:`flask.views.View` must
-        implement. It binds the other methods together.
-        """
         instance = self._get_instance(*args, **kwargs)
         get_requests = GetRequests(instance)
         results = set([
             req["author"]["name"] for req in get_requests()
-            if req["author"]["name"].startswith(
-                flask.request.args.get("q"))
             ])
+        query = flask.request.args.get("q")
+        if query:
+            results = [name for name in results if name.startswith(query)]
         results = sorted(list(results))[:self.MAX_SUGGESTS]
         return flask.jsonify({"results": results})
 
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index f1dcea7..780a3d4 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -151,6 +151,13 @@ class FedorahostedProject(Validator):
 
 
 class CommaSeparatedList(Validator):
+    """Fails if the value isn't a comma-separated list.
+
+    The value will be converted to a Python list. If there is no comma in the
+    original value, it will produce a list with a single element. Whitespaces
+    will be stripped from the elements, so spaces are allowed around the
+    commas.
+    """
 
     @classmethod
     def from_string(cls, value):

From ad1a3d2ba98016ec745fbb764ee1cea32dff5441 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 05 2017 12:44:22 +0000
Subject: [PATCH 811/1001] Use url_for in templates


---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 231b364..30b7078 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -17,14 +17,14 @@
       <div id="vertical-navbar">
         <ul class="nav navbar-nav p-r-1">
           <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
-            <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>
-          <li class="p-x-1 nav-item"><a class="nav-link" href="/{{g.auth.user.username}}/stream">My Stream</a></li>
+            <a class="nav-link" href="{{ url_for("hub", name=g.auth.user.username) }}">me</a></li>
+          <li class="p-x-1 nav-item"><a class="nav-link" href="{{ url_for("stream", name=g.auth.user.username) }}">My Stream</a></li>
           {% for hub in g.auth.user.bookmarks %}
             <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
-              <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>
+              <a class="nav-link" href="{{ url_for("hub", name=hub.name) }}">{{hub.name}}</a></li>
           {% endfor %}
           <!-- At the end of the list, tack on a link to all groups -->
-          <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>
+          <li class="p-x-1 nav-item"><a class="nav-link" href="{{ url_for("groups") }}">all</a></li>
         </ul>
       </div><!-- /.navbar-collapse -->
       {% endif %}

From b439153a22f78395c117fd222111af7d4d14097a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 06 2017 23:29:35 +0000
Subject: [PATCH 812/1001] Add an authorization framework


---

diff --git a/hubs/app.py b/hubs/app.py
index c8b5aca..7b28c4c 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -95,11 +95,14 @@ def check_auth():
             )
             flask.session.auth.avatar = username2avatar(
                 flask.session.auth.nickname)
-            flask.session.auth.user = hubs.models.User.by_username(
-                flask.session.auth.nickname)
+
+            user = hubs.models.User.get_or_create(
+                flask.g.db, username=flask.session.auth.nickname,
+                fullname=flask.session.auth.fullname)
+            flask.session.auth.user = user
         flask.g.auth = flask.session.auth
     else:
-        flask.g.auth = munch.Munch(logged_in=False)
+        flask.g.auth = munch.Munch(logged_in=False, user=None)
 
 # Register widgets
 import hubs.widgets  # noqa
diff --git a/hubs/authz.py b/hubs/authz.py
new file mode 100644
index 0000000..ebd85ca
--- /dev/null
+++ b/hubs/authz.py
@@ -0,0 +1,88 @@
+from __future__ import absolute_import, unicode_literals
+
+from enum import IntEnum
+from flask import current_app
+
+
+#class Authorization(object):
+#
+#    def __init__(self, app=None, db=None):
+#        self.db = db
+#        if app is not None:
+#            self.init_app(app)
+#
+#    def init_app(self):
+#        app.config.setdefault("AUTHZ_ADAPTER", None)
+
+
+class AccessLevel(IntEnum):
+    anonymous = 0
+    logged_in = 1
+    member = 2
+    sponsor = 3
+    owner = 4
+
+
+PERMISSIONS = {
+    "hub.public.view": AccessLevel.anonymous,
+    "hub.preview.view": AccessLevel.anonymous,
+    "hub.private.view": AccessLevel.member,
+    "hub.users.manage": AccessLevel.sponsor,
+    "hub.config": AccessLevel.owner,
+    "widget.public.view": AccessLevel.anonymous,
+    "widget.restricted.view": AccessLevel.logged_in,
+}
+
+
+class ObjectAuthzMixin(object):
+
+    def allows(self, user, action):
+        site_admins = current_app.config.get("SITE_ADMINS", [])
+        if user is not None and user.username in site_admins:
+            return True
+        user_level = self._get_auth_access_level(user)
+        permission = self._get_auth_permission_name(action)
+        min_level = PERMISSIONS[permission]
+        if user_level >= min_level:
+            return True
+        return False
+
+    def _get_auth_access_level(self, user):
+        if user is None:
+            return AccessLevel.anonymous
+        levels = [
+            self._get_auth_user_access_level(user),
+            self._get_auth_group_access_level(user),
+        ]
+        return max(l for l in levels if l is not None)
+
+    def _get_auth_user_access_level(self, user):
+        return AccessLevel.logged_in
+
+    def _get_auth_group_access_level(self, user):
+        group = self._get_auth_group()
+        user_roles = self._get_auth_user_roles(user)
+        try:
+            user_level = user_roles[group]
+        except KeyError:
+            # No role for this group
+            return None
+        try:
+            return AccessLevel[user_level]
+        except KeyError:
+            # Unsupported role
+            return None
+
+    def _get_auth_group(self):
+        raise NotImplementedError
+
+    def _get_auth_user_roles(self, user):
+        return get_user_roles(user)
+
+    def _get_auth_permission_name(self, action):
+        return action
+
+
+def get_user_roles(user):
+    # TODO: use the new API
+    return {g: "member" for g in user.groups}
diff --git a/hubs/migrations/versions/bed8bbc0f78e_authz.py b/hubs/migrations/versions/bed8bbc0f78e_authz.py
new file mode 100644
index 0000000..525c2ad
--- /dev/null
+++ b/hubs/migrations/versions/bed8bbc0f78e_authz.py
@@ -0,0 +1,63 @@
+# This Alembic database migration is part of the Fedora Hubs project.
+# Copyright (C) <year>  <name of author>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Authorization
+
+Revision ID: bed8bbc0f78e
+Revises: 6d4862ec4f93
+Create Date: 2017-03-30 21:38:03.629462
+"""
+
+from __future__ import absolute_import, unicode_literals
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'bed8bbc0f78e'
+down_revision = '6d4862ec4f93'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    op.add_column(
+        'hubs_config',
+        sa.Column('auth_group', sa.String(length=256), nullable=True))
+    op.add_column(
+        'hubs_config',
+        sa.Column('visibility', sa.Enum('public', 'preview', 'private'),
+                  nullable=True))
+    op.add_column(
+        'widgets',
+        sa.Column('visibility', sa.Enum('public', 'restricted'),
+                  nullable=True))
+    op.execute("UPDATE hubs_config SET visibility = 'public'")
+    op.execute("UPDATE widgets SET visibility = 'public'")
+    with op.batch_alter_table("hubs_config") as batch_op:
+        batch_op.alter_column("visibility", nullable=False)
+    with op.batch_alter_table("widgets") as batch_op:
+        batch_op.alter_column("visibility", nullable=False)
+
+
+def downgrade():
+    # http://alembic.zzzcomputing.com/en/latest/batch.html
+    with op.batch_alter_table("hubs_config") as batch_op:
+        batch_op.drop_column('visibility')
+        batch_op.drop_column('auth_group')
+    with op.batch_alter_table("widgets") as batch_op:
+        batch_op.drop_column('visibility')
diff --git a/hubs/models.py b/hubs/models.py
index 48ed695..758a64f 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -47,6 +47,7 @@ import fedmsg.utils
 
 import hubs.defaults
 import hubs.widgets
+from hubs.authz import ObjectAuthzMixin, AccessLevel
 from hubs.utils import username2avatar
 
 
@@ -135,7 +136,7 @@ class Association(BASE):
             .first()
 
 
-class Hub(BASE):
+class Hub(ObjectAuthzMixin, BASE):
     __tablename__ = 'hubs'
     name = sa.Column(sa.String(50), primary_key=True)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
@@ -221,9 +222,6 @@ class Hub(BASE):
         session.delete(association)
         session.commit()
 
-    def is_admin(self, user):
-        return user in self.owners
-
     @classmethod
     def by_name(cls, name):
         return cls.query.filter_by(name=name).first()
@@ -264,19 +262,39 @@ class Hub(BASE):
         hubs.defaults.add_group_widgets(session, hub, name, summary, **extra)
         return hub
 
-    @property
-    def left_widgets(self):
-        return sorted(
-            [w for w in self.widgets
-             if w.plugin in hubs.widgets.registry and w.left],
-            key=lambda w: w.index)
+    def _get_auth_user_access_level(self, user):
+        # overridden to handle user hubs.
+        if self.user_hub and user.username == self.name:
+            return AccessLevel.owner
+        return super(Hub, self)._get_auth_user_access_level(user)
+
+    def _get_auth_group(self):
+        # While we're local-only, just use the hub name:
+        return self.name
+        # When the CAIAPI is in place we will be able to use the auth_group
+        # setting:
+        # group = self.config.auth_group
+        # if group is None:
+        #     group = self.name
+        # return group
+
+    def _get_auth_user_roles(self, user):
+        """Override until we can get groups from FAS.
+
+        This will not return all roles, only the one for the current hub, but
+        that fine since it's the only one we're interested in when this method
+        is called.
+        """
+        return {
+            assoc.hub.name: assoc.role
+            for assoc in self.associations
+            if assoc.user.username == user.username
+            }
 
-    @property
-    def right_widgets(self):
-        return sorted(
-            [w for w in self.widgets
-             if w.plugin in hubs.widgets.registry and not w.left],
-            key=lambda w: w.index)
+    def _get_auth_permission_name(self, action):
+        if action == "view":
+            action = "{}.view".format(self.config.visibility)
+        return "hub.{}".format(action)
 
     def __json__(self):
         return {
@@ -292,7 +310,11 @@ class Hub(BASE):
 
 
 class HubConfig(BASE):
+
     __tablename__ = 'hubs_config'
+
+    VISIBILITY = ["public", "preview", "private"]
+
     id = sa.Column(sa.Integer, primary_key=True)
     hub_id = sa.Column(sa.String(50), sa.ForeignKey('hubs.name'),
                        nullable=False)
@@ -303,6 +325,9 @@ class HubConfig(BASE):
     header_img = sa.Column(sa.String(256), default=randomheader)
     chat_channel = sa.Column(sa.String(256), nullable=True)
     chat_domain = sa.Column(sa.String(256), nullable=True)
+    auth_group = sa.Column(sa.String(256), nullable=True)
+    visibility = sa.Column(
+        sa.Enum(*VISIBILITY), default="public", nullable=False)
 
     def __json__(self):
         return {
@@ -311,6 +336,7 @@ class HubConfig(BASE):
             'avatar': self.avatar,
             'chat_channel': self.chat_channel,
             'chat_domain': self.chat_domain,
+            'visibility': self.visibility,
         }
 
     @property
@@ -326,8 +352,12 @@ def _widget_config_default(context):
         ]))
 
 
-class Widget(BASE):
+class Widget(ObjectAuthzMixin, BASE):
+
     __tablename__ = 'widgets'
+
+    VISIBILITY = ["public", "restricted"]
+
     idx = sa.Column(sa.Integer, primary_key=True)
     plugin = sa.Column(sa.String(50), nullable=False)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
@@ -336,6 +366,8 @@ class Widget(BASE):
 
     index = sa.Column(sa.Integer, nullable=False)
     left = sa.Column(sa.Boolean, nullable=False, default=False)
+    visibility = sa.Column(
+        sa.Enum(*VISIBILITY), default="public", nullable=False)
 
     @classmethod
     def by_idx(cls, idx):
@@ -359,6 +391,21 @@ class Widget(BASE):
     def config(self, config):
         self._config = json.dumps(config)
 
+    def _get_auth_access_level(self, user):
+        return self.hub._get_auth_access_level(user)
+
+    def _get_auth_user_roles(self, user):
+        """Override until we can get groups from FAS"""
+        return self.hub._get_auth_user_roles(user)
+
+    def _get_auth_permission_name(self, action):
+        if action != "view":
+            return self.hub._get_auth_permission_name(action)
+        hub_visibility = self.hub.config.visibility
+        if hub_visibility != "preview":
+            return "hub.{}.view".format(hub_visibility)
+        return "widget.{}.view".format(self.visibility)
+
     def __json__(self):
         module = hubs.widgets.registry[self.plugin]
         root_view = module.get_views()["root"](module)
diff --git a/hubs/static/client/app/core/HubConfigPanel.jsx b/hubs/static/client/app/core/HubConfigPanel.jsx
index 517042f..ddc22d3 100644
--- a/hubs/static/client/app/core/HubConfigPanel.jsx
+++ b/hubs/static/client/app/core/HubConfigPanel.jsx
@@ -3,6 +3,7 @@ import {
   IntlProvider,
   defineMessages,
   FormattedMessage,
+  FormattedHTMLMessage,
   } from 'react-intl';
 import TabPanel from '../components/TabPanel.jsx';
 
@@ -20,21 +21,51 @@ const messages = defineMessages({
     id: "hubs.core.config.general.summary",
     defaultMessage: "Summary",
   },
+  general_summary_help: {
+    id: "hubs.core.config.general.summary_help",
+    defaultMessage: "This text will be displayed at the top of the hub.",
+  },
   general_left_width: {
     id: "hubs.core.config.general.left_width",
     defaultMessage: "Left width",
   },
+  general_left_width_help: {
+    id: "hubs.core.config.general.left_width_help",
+    defaultMessage: (
+      "Change the proportions of you hub's columns by setting the width of "
+     +"the left column (the right column's width will be {right_width})."
+      ),
+  },
+  general_visibility: {
+    id: "hubs.core.config.general.visibility",
+    defaultMessage: "Visibility",
+  },
+  general_visibility_help: {
+    id: "hubs.core.config.general.visibility_help",
+    defaultMessage: (
+      "Public: the hub is visible to anyone.<br />"
+     +"Private: the hub is only visible to members.<br />"
+     +"Preview: some widgets can be made visible to logged-in users only."
+      ),
+  },
   general_avatar: {
     id: "hubs.core.config.general.avatar",
     defaultMessage: "Avatar",
   },
+  general_avatar_help: {
+    id: "hubs.core.config.general.avatar_help",
+    defaultMessage: "An URL to you hub's main image or logo."
+  },
   chat_title: {
     id: "hubs.core.config.chat.title",
     defaultMessage: "Chat Settings",
   },
   chat_intro_1: {
     id: "hubs.core.config.chat.intro1",
-    defaultMessage: "If your team or project has an IRC channel associated with it, you can connect this hub to it via the Hubs chat widget.",
+    defaultMessage: (
+      "If your team or project has an IRC channel associated with it, you "
+     +"can connect this hub to it via the Hubs chat widget."
+     ),
   },
   chat_intro_2: {
     id: "hubs.core.config.chat.intro2",
@@ -72,6 +103,7 @@ export class GeneralPanel extends React.Component {
 
   render() {
     var stillLoading = (typeof this.props.hubConfig.summary === "undefined");
+    var visibilities = this.props.generalConfig.hub_visibility || [];
     return (
       <div>
         <FormattedMessage {...messages.general_title} tagName="h3" />
@@ -87,6 +119,9 @@ export class GeneralPanel extends React.Component {
             onChange={this.props.handleChange}
             value={this.props.hubConfig.summary || ""}
             />
+          <p className="form-text text-muted">
+            <FormattedMessage {...messages.general_summary_help} />
+          </p>
         </div>
         <div className="form-group">
           <label htmlFor="hub-settings-general-leftwidth">
@@ -100,6 +135,32 @@ export class GeneralPanel extends React.Component {
             onChange={this.props.handleChange}
             value={this.props.hubConfig.left_width || ""}
             />
+          <p className="form-text text-muted">
+            <FormattedMessage
+              {...messages.general_left_width_help}
+              values={{right_width: 12 - (this.props.hubConfig.left_width || 8)}}
+              />
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-visibility">
+            <FormattedMessage {...messages.general_visibility} />
+          </label>
+          <select
+            className="form-control" name="visibility"
+            value={this.props.hubConfig.visibility || ""}
+            onChange={this.props.handleChange}
+            disabled={stillLoading}
+            >
+            {visibilities.map(function(value) {
+              return (
+                <option value={value} key={value}>{value}</option>
+                );
+            })}
+          </select>
+          <p className="form-text text-muted">
+            <FormattedHTMLMessage {...messages.general_visibility_help} />
+          </p>
         </div>
         <div className="form-group">
           <label htmlFor="hub-settings-general-avatar">
@@ -112,6 +173,9 @@ export class GeneralPanel extends React.Component {
             onChange={this.props.handleChange}
             value={this.props.hubConfig.avatar || ""}
             />
+          <p className="form-text text-muted">
+            <FormattedMessage {...messages.general_avatar_help} />
+          </p>
         </div>
       </div>
     );
diff --git a/hubs/templates/errors/hub.html b/hubs/templates/errors/hub.html
new file mode 100644
index 0000000..36506e1
--- /dev/null
+++ b/hubs/templates/errors/hub.html
@@ -0,0 +1,8 @@
+{% extends "hubs.html" %}
+
+{% block hub_content %}
+
+<p class="text-center">{{ msg }}</p>
+
+{% endblock %}
+
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 30b7078..35ab48a 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -48,7 +48,7 @@
         
         <!-- right side of header -->
         <div class="col-md-{{ hub.config.right_width }} header-right">
-          {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}
+          {% if hub.allows(g.auth.user, "config") %}
           <div style="text-align:center">
             <button class="btn btn-secondary" data-toggle="modal" data-target="#settings-modal">
               <i class="fa fa-cog" aria-hidden="true"></i>
@@ -100,6 +100,7 @@
 
   <div class="row">
     <div class="col-md-offset-2">
+      {% block hub_content %}
       <div class="row">
         <div class="col-md-{{ hub.config.left_width }}">
           <!--
@@ -144,7 +145,13 @@
           </div>
           {% endif %}
 
-          {% include "includes/left_widgets.html" %}
+          <div id="left_widgets">
+            {% for widget in widgets["left"] %}
+            <div id="widget-{{ widget.idx }}" class="widget row"
+                 data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
+                 ></div>
+            {% endfor %}
+          </div>
         </div>
 
         <div class="col-md-{{ hub.config.right_width }}">
@@ -162,16 +169,23 @@
           </div>
           {% endif %}
 
-          {% include "includes/right_widgets.html" %}
+          <div id="right_widgets">
+            {% for widget in widgets["right"] %}
+            <div id="widget-{{ widget.idx }}" class="widget row"
+                 data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
+                 ></div>
+            {% endfor %}
+          </div>
         </div>
 
       </div>  <!-- /row -->
+      {% endblock hub_content %}
     </div>  <!-- /col-md-offset-2 -->
   </div>  <!-- /row -->
-      
-    
+
+
 </div>
-      
+
 
 <div id="settings-modal" class="modal fade" tabindex="-1" role="dialog">
 </div>
diff --git a/hubs/templates/includes/left_widgets.html b/hubs/templates/includes/left_widgets.html
deleted file mode 100644
index 032a026..0000000
--- a/hubs/templates/includes/left_widgets.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<div id="left_widgets">
-{% for widget in hub.left_widgets %}
-  <div id="widget-{{ widget.idx }}" class="widget row"
-       data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
-       ></div>
-{% endfor %}
-</div>
diff --git a/hubs/templates/includes/right_widgets.html b/hubs/templates/includes/right_widgets.html
deleted file mode 100644
index a0b2a3b..0000000
--- a/hubs/templates/includes/right_widgets.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<div id="right_widgets">
-  {% for widget in hub.right_widgets %}
-  <div id="widget-{{ widget.idx }}" class="widget row"
-       data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
-       ></div>
-  {% endfor %}
-</div>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index e33c301..b7ca796 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -50,7 +50,13 @@
   </div>
 
   <div class="col-sm-4">
-    {% include "includes/right_widgets.html" %}
+    <div id="right_widgets">
+      {% for widget in widgets["right"] %}
+      <div id="widget-{{ widget.idx }}" class="widget row"
+           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
+           ></div>
+      {% endfor %}
+    </div>
   </div>
 </div>
 
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 67d82fa..edd2ba5 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -120,7 +120,7 @@ def auth_set(APP, auth):
         g.auth = auth
         g.oidc_id_token = None
         if not auth:
-            g.auth = munch.Munch(logged_in=False)
+            g.auth = munch.Munch(logged_in=False, user=None)
 
     with appcontext_pushed.connected_to(handler, APP):
         yield
@@ -136,9 +136,7 @@ class FakeUser(object):
         """
         self.username = username
         self.booksmarks = []
-
-    def __getitem__(self, key):
-        return self.dic[key]
+        self.groups = []
 
 
 class FakeAuthorization(object):
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 2c8f1ff..778ea54 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -66,7 +66,9 @@ class HubsAPITest(hubs.tests.APPTest):
                 result.get_data(as_text=True))
 
     def test_hub_json(self):
-        result = self.app.get('/ralph/json', follow_redirects=True)
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/ralph/json', follow_redirects=True)
         # assert the status code of the response
         self.assertEqual(result.status_code, 200)
         data = {
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index 8669160..c3279cd 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -153,15 +153,3 @@ class ModelTest(hubs.tests.APPTest):
                           session=self.session,
                           username=username,
                           visited_hub=hub)
-
-    def test_removed_widget(self):
-        hub = hubs.models.Hub.get("ralph")
-        widget = hubs.models.Widget(
-            hub=hub, plugin="does-not-exist",
-            left=True, index=-1, _config="{}")
-        self.session.add(widget)
-        self.assertNotIn(
-            "does-not-exist", [w.plugin for w in hub.left_widgets])
-        widget.left = False
-        self.assertNotIn(
-            "does-not-exist", [w.plugin for w in hub.right_widgets])
diff --git a/hubs/tests/test_view_utils.py b/hubs/tests/test_view_utils.py
new file mode 100644
index 0000000..d5e8218
--- /dev/null
+++ b/hubs/tests/test_view_utils.py
@@ -0,0 +1,24 @@
+from __future__ import unicode_literals
+
+import hubs.models
+import hubs.tests
+from hubs.views.utils import get_visible_widgets
+
+
+class ModelTest(hubs.tests.APPTest):
+
+    def test_removed_widget(self):
+        hub = hubs.models.Hub.get("ralph")
+        widget = hubs.models.Widget(
+            hub=hub, plugin="does-not-exist",
+            left=True, index=-1, _config="{}")
+        self.session.add(widget)
+        user = hubs.tests.FakeAuthorization('ralph')
+        with hubs.tests.auth_set(self.app.application, user):
+            with self.app.application.app_context():
+                widgets = get_visible_widgets(hub)
+        self.assertNotIn(
+            "does-not-exist", [w.plugin for w in widgets["left"]])
+        widget.left = False
+        self.assertNotIn(
+            "does-not-exist", [w.plugin for w in widgets["right"]])
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index d86435f..edab332 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -2,16 +2,19 @@ from __future__ import unicode_literals
 
 import json
 
-import hubs.tests.test_widgets
+from hubs.tests import FakeAuthorization, auth_set
+from hubs.tests.test_widgets import WidgetTest
 
 
-class TestBadges(hubs.tests.test_widgets.WidgetTest):
+class TestAbout(WidgetTest):
     plugin = 'about'  # The name in hubs.widgets.registry
 
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json' % widget.idx)
-        assert response.status_code == 200, response.status_code
+        user = FakeAuthorization('ralph')
+        with auth_set(self.app.application, user):
+            response = self.app.get('/ralph/%i/json' % widget.idx)
+        self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
             'text': 'Testing.',
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index 3521ec2..30284fd 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -2,16 +2,20 @@ from __future__ import unicode_literals
 
 import json
 
-import hubs.tests.test_widgets
+import hubs.widgets
+from hubs.tests import FakeAuthorization, auth_set
+from hubs.tests.test_widgets import WidgetTest
 
 
-class TestBadges(hubs.tests.test_widgets.WidgetTest):
+class TestBadges(WidgetTest):
     plugin = 'badges'  # The name in hubs.widgets.registry
 
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json' % widget.idx)
-        assert response.status_code == 200, response.status_code
+        user = FakeAuthorization('ralph')
+        with auth_set(self.app.application, user):
+            response = self.app.get('/ralph/%i/json' % widget.idx)
+        self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertEquals(data['plugin'], 'badges')
         self.assertIn('assertions', data['data'].keys())
diff --git a/hubs/tests/test_widgets/test_contact.py b/hubs/tests/test_widgets/test_contact.py
index a934c38..3e63953 100644
--- a/hubs/tests/test_widgets/test_contact.py
+++ b/hubs/tests/test_widgets/test_contact.py
@@ -73,7 +73,9 @@ class ContactsTest(APPTest):
 
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json' % widget.idx)
+        user = FakeAuthorization('ralph')
+        with auth_set(self.app.application, user):
+            response = self.app.get('/ralph/%i/json' % widget.idx)
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index cb3d5d3..4861b49 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -2,16 +2,19 @@ from __future__ import unicode_literals
 
 import json
 
-import hubs.tests.test_widgets
+from hubs.tests import FakeAuthorization, auth_set
+from hubs.tests.test_widgets import WidgetTest
 
 
-class TestFedmsgStats(hubs.tests.test_widgets.WidgetTest):
+class TestFedmsgStats(WidgetTest):
     plugin = 'fedmsgstats'  # The name in hubs.widgets.registry
 
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json' % widget.idx)
-        assert response.status_code == 200, response.status_code
+        user = FakeAuthorization('ralph')
+        with auth_set(self.app.application, user):
+            response = self.app.get('/ralph/%i/json' % widget.idx)
+        self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
             u'fedmsgs': 83854,
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index 0e09a7d..eaac331 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -2,16 +2,18 @@ from __future__ import unicode_literals
 
 import json
 
-import hubs.tests.test_widgets
-import hubs.models
+from hubs.tests import FakeAuthorization, auth_set
+from hubs.tests.test_widgets import WidgetTest
 
 
-class TestLibrary(hubs.tests.test_widgets.WidgetTest):
+class TestLibrary(WidgetTest):
     plugin = 'library'  # The name in hubs.widgets.registry
 
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
-        response = self.app.get('/ralph/%i/json' % widget.idx)
+        user = FakeAuthorization('ralph')
+        with auth_set(self.app.application, user):
+            response = self.app.get('/ralph/%i/json' % widget.idx)
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         expected_dict = {
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 78c41b9..8c2784b 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -2,16 +2,19 @@ from __future__ import unicode_literals
 
 import json
 
-import hubs.tests.test_widgets
+from hubs.tests import FakeAuthorization, auth_set
+from hubs.tests.test_widgets import WidgetTest
 
 
-class TestMeetings(hubs.tests.test_widgets.WidgetTest):
+class TestMeetings(WidgetTest):
     plugin = 'meetings'
 
     def test_data_simple(self):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
-        response = self.app.get('/%s/%i/json' % (team, widget.idx))
+        user = FakeAuthorization('ralph')
+        with auth_set(self.app.application, user):
+            response = self.app.get('/%s/%i/json' % (team, widget.idx))
         self.assertEqual(200, response.status_code)
         data = json.loads(response.get_data(as_text=True))
         calendar_name = data['data']['calendar']
@@ -20,8 +23,10 @@ class TestMeetings(hubs.tests.test_widgets.WidgetTest):
     def test_render_simple(self):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
-        response = self.app.get('/%s/w/%s/%i/'
-                                % (team, self.plugin, widget.idx))
+        user = FakeAuthorization('ralph')
+        with auth_set(self.app.application, user):
+            response = self.app.get('/%s/w/%s/%i/'
+                                    % (team, self.plugin, widget.idx))
         self.assertEqual(200, response.status_code)
         self.assertIn('i18n', response.get_data(as_text=True))
         self.assertIn('<strong>Request A New Meeting</strong>',
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 4227357..75b5764 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -5,19 +5,25 @@ import flask
 import hubs.models
 
 from hubs.app import app
-from .utils import get_hub, login_required, RequestValidator
+from .utils import (
+    get_hub, get_visible_widgets, login_required, RequestValidator,
+    require_hub_access,
+    )
 
 
 @app.route('/<name>')
 @app.route('/<name>/')
+@require_hub_access("view")
 def hub(name):
     hub = get_hub(name, load_config=True)
+    widgets = get_visible_widgets(hub)
     return flask.render_template(
-        'hubs.html', hub=hub, edit=False)
+        'hubs.html', hub=hub, widgets=widgets, edit=False)
 
 
 @app.route('/<name>/json/')
 @app.route('/<name>/json')
+@require_hub_access("view", json=True)
 def hub_json(name):
     hub = get_hub(name)
     response = flask.jsonify(hub.__json__())
@@ -27,21 +33,22 @@ def hub_json(name):
 
 @app.route('/<name>/edit', methods=['GET', 'POST'])
 @login_required
+@require_hub_access("config")
 def hub_edit(name):
+    hub = get_hub(name, load_config=True)
     if flask.request.method == 'POST':
-        return hub_edit_post(name)
+        return hub_edit_post(hub)
     else:
-        return hub_edit_get(name)
+        return hub_edit_get(hub)
 
 
-def hub_edit_get(name):
-    hub = get_hub(name, load_config=True)
+def hub_edit_get(hub):
+    widgets = get_visible_widgets(hub)
     return flask.render_template(
-        'hubs.html', hub=hub, edit=True)
+        'hubs.html', hub=hub, widgets=widgets, edit=True)
 
 
-def hub_edit_post(name):
-    hub = get_hub(name)
+def hub_edit_post(hub):
     is_js = flask.request.form.get('js', False)
 
     error = False
@@ -138,11 +145,12 @@ def hub_edit_post(name):
         else:
             return ('ok', 200)
     else:
-        return flask.redirect(flask.url_for('hub', name=name))
+        return flask.redirect(flask.url_for('hub', name=hub.name))
 
 
 @app.route('/<name>/config', methods=['GET', 'POST'])
 @login_required
+@require_hub_access("config", json=True)
 def hub_config(name):
     hub = get_hub(name)
     config = {
@@ -151,6 +159,7 @@ def hub_config(name):
             "hub": {},
             "general": {
                 "chat_networks": app.config["CHAT_NETWORKS"],
+                "hub_visibility": hubs.models.HubConfig.VISIBILITY,
             },
         },
     }
diff --git a/hubs/views/root.py b/hubs/views/root.py
index 1250490..74215da 100644
--- a/hubs/views/root.py
+++ b/hubs/views/root.py
@@ -48,9 +48,6 @@ def login():
     else:
         return_point = default
 
-    hubs.models.User.get_or_create(
-        flask.g.db, username=flask.g.auth.nickname,
-        fullname=flask.g.auth.fullname)
     flask.flash('Login successful', 'success')
 
     return flask.redirect(return_point)
diff --git a/hubs/views/user.py b/hubs/views/user.py
index 62866ae..5012aea 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -6,14 +6,18 @@ import hubs.models
 import hubs.stream
 
 from hubs.app import app
-from .utils import login_required, get_hub
+from .utils import (
+    login_required, get_hub, get_visible_widgets, require_hub_access,
+    )
 
 
 @app.route('/<name>/stream')
 @app.route('/<name>/stream/')
 @login_required
+@require_hub_access("view")
 def stream(name):
     hub = get_hub(name)
+    widgets = get_visible_widgets(hub)
     saved = hubs.models.SavedNotification.by_username(name)
     saved = [n.__json__() for n in saved]
 
@@ -23,6 +27,7 @@ def stream(name):
     return flask.render_template(
         'stream.html',
         hub=hub,
+        widgets=widgets,
         saved=json.dumps(saved),
         actions=actions
     )
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index a90e468..0a89595 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -1,15 +1,16 @@
 from __future__ import unicode_literals
 
 import datetime
-import flask
 import functools
 import logging
 
-from hubs.models import Hub, Widget
+import flask
 from six.moves.urllib import parse as urlparse
 from sqlalchemy.orm import joinedload
 from sqlalchemy.orm.exc import NoResultFound
 
+from hubs.models import Hub, Widget
+
 
 log = logging.getLogger(__name__)
 
@@ -44,6 +45,27 @@ def get_widget_instance(hub, idx, session=None):
         flask.abort(404)
 
 
+def get_visible_widgets(hub):
+    from hubs.widgets import registry
+    widgets = {"left": [], "right": []}
+    for widget in hub.widgets:
+        if widget.plugin not in registry:
+            continue  # disabled widget
+        try:
+            user = flask.g.auth.user
+        except AttributeError:
+            user = None
+        if not widget.allows(user, "view"):
+            continue
+        if widget.left:
+            widgets["left"].append(widget)
+        else:
+            widgets["right"].append(widget)
+    widgets["left"].sort(key=lambda w: w.index)
+    widgets["right"].sort(key=lambda w: w.index)
+    return widgets
+
+
 class WidgetConfigError(Exception):
     pass
 
@@ -127,6 +149,38 @@ def login_required(function):
     return decorated_function
 
 
+def require_hub_access(action, url_param="name", json=False):
+    """Check access to the hub for the specified action."""
+    def decorator(function):
+        @functools.wraps(function)
+        def wrapper(*args, **kwargs):
+            hub_name = kwargs[url_param]
+            hub = get_hub(hub_name, load_config=True)
+            try:
+                user = flask.g.auth.user
+            except AttributeError:
+                user = None
+            if not hub.allows(user, action):
+                if action == "view":
+                    msg = "This hub is for members only."
+                elif action == "config":
+                    msg = "You are not allowed to configure this hub."
+                else:
+                    msg = "Access forbidden."
+                if json:
+                    result = flask.jsonify({
+                        "status": "ERROR", "message": msg, "hub": hub.name,
+                        })
+                else:
+                    result = flask.render_template(
+                        'errors/hub.html', hub=hub, msg=msg,
+                        )
+                return result, 403
+            return function(*args, **kwargs)
+        return wrapper
+    return decorator
+
+
 def is_safe_url(target):
     """ Checks that the target url is safe and sending to the current
     website not some other malicious one.
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 39bb8f7..35fb12a 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -8,11 +8,13 @@ from pkg_resources import resource_isdir
 from .utils import (
     create_widget_instance, configure_widget_instance, get_hub,
     get_widget_instance, login_required, WidgetConfigError,
-    get_position,
+    get_position, require_hub_access,
     )
 
 
 @app.route('/<name>/add', methods=['GET', 'POST'])
+@login_required
+@require_hub_access("config")
 def hub_add_widget(name):
     hub = get_hub(name)
     position = get_position()
@@ -45,6 +47,8 @@ def hub_add_widget(name):
 
 
 @app.route('/<hub>/add/<widget>', methods=['GET', 'POST'])
+@login_required
+@require_hub_access("config", url_param="hub")
 def widget_add(hub, widget):
     hub = get_hub(hub)
     position = get_position()
@@ -65,6 +69,7 @@ def widget_add(hub, widget):
 
 @app.route('/<hub>/<int:idx>/edit', methods=['GET', 'POST'])
 @login_required
+@require_hub_access("config", url_param="hub")
 def widget_edit(hub, idx):
     widget_instance = get_widget_instance(hub, idx)
     if flask.request.method == 'POST':
@@ -85,6 +90,7 @@ def widget_edit(hub, idx):
 
 @app.route('/<hub>/<int:idx>/delete', methods=['POST'])
 @login_required
+@require_hub_access("config", url_param="hub")
 def widget_edit_delete(hub, idx):
     ''' Remove a widget from a hub. '''
     widget_instance = get_widget_instance(hub, idx)
@@ -100,6 +106,7 @@ def widget_edit_delete(hub, idx):
 
 
 @app.route('/<hub>/<int:idx>/json')
+@require_hub_access("view", url_param="hub")
 def widget_json(hub, idx):
     widget = get_widget_instance(hub, idx)
     response = flask.jsonify(widget.__json__())
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index 264da3d..f1aae71 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -7,7 +7,7 @@ import flask
 from flask.signals import template_rendered, before_render_template
 
 from hubs.models import Hub
-from hubs.views.utils import get_hub
+from hubs.views.utils import get_hub, require_hub_access
 from hubs.widgets import registry
 from hubs.widgets.base import WidgetView
 from .functions import GetRequests
@@ -33,9 +33,9 @@ class DataView(WidgetView):
 
     name = "data"
     url_rules = ["data"]
+    json = True
 
-    def dispatch_request(self, *args, **kwargs):
-        instance = self._get_instance(*args, **kwargs)
+    def get_context(self, instance, *args, **kwargs):
         get_requests = GetRequests(instance)
         data = {"requests": []}
         hubs_filter = flask.request.args.getlist("hubs")
@@ -55,7 +55,7 @@ class DataView(WidgetView):
             if len(data["requests"]) == 3:
                 # Only 3 requests on the main widget.
                 break
-        return flask.jsonify(data)
+        return data
 
 
 class SearchView(WidgetView):
@@ -64,9 +64,9 @@ class SearchView(WidgetView):
     name = "search"
     url_rules = ["search"]
     methods = ['GET', 'POST']
+    json = True
 
-    def dispatch_request(self, *args, **kwargs):
-        instance = self._get_instance(*args, **kwargs)
+    def get_context(self, instance, *args, **kwargs):
         get_requests = GetRequests(instance)
         # prepare filters
         if "hubs" in flask.request.values:
@@ -112,7 +112,7 @@ class SearchView(WidgetView):
             data["requests"], instance.config["per_page"])
         data["requests"] = requests
         data["page"] = page_data
-        return flask.jsonify(data)
+        return data
 
 
 class RequestersView(WidgetView):
@@ -121,9 +121,9 @@ class RequestersView(WidgetView):
     name = "requesters"
     url_rules = ["requesters"]
     MAX_SUGGESTS = 5
+    json = True
 
-    def dispatch_request(self, *args, **kwargs):
-        instance = self._get_instance(*args, **kwargs)
+    def get_context(self, instance, *args, **kwargs):
         get_requests = GetRequests(instance)
         results = set([
             req["author"]["name"] for req in get_requests()
@@ -132,7 +132,7 @@ class RequestersView(WidgetView):
         if query:
             results = [name for name in results if name.startswith(query)]
         results = sorted(list(results))[:self.MAX_SUGGESTS]
-        return flask.jsonify({"results": results})
+        return {"results": results}
 
 
 class ConfigView(WidgetView):
@@ -143,6 +143,7 @@ class ConfigView(WidgetView):
     name = "config"
     url_rules = ["config"]
     template_name = "halp_config.html"
+    permission = "config"
 
     def get_context(self, instance, *args, **kwargs):
         post_url = flask.url_for(
@@ -168,6 +169,7 @@ def hubs_suggest_view():
     return flask.jsonify({"results": [h.name for h in results]})
 
 
+@require_hub_access("config", url_param="hub")
 def add_view(hub):
     """The custom configuration panel when adding the widget.
 
@@ -188,7 +190,9 @@ def add_view(hub):
         )
     initial["hubs"] = [hub.name]
     context = dict(mode="add", url=post_url, initial=initial)
-    before_render_template.send(widget, template=template, context=context)
+    before_render_template.send(
+        flask.current_app, template=template, context=context)
     output = template.render(**context)
-    template_rendered.send(widget, template=template, context=context)
+    template_rendered.send(
+        flask.current_app, template=template, context=context)
     return output
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index 943302d..f02e777 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -1,5 +1,6 @@
 from __future__ import unicode_literals, absolute_import
 
+import flask
 from flask.signals import template_rendered, before_render_template
 from flask.views import View
 
@@ -44,6 +45,8 @@ class WidgetView(View):
     name = None
     url_rules = []
     template_name = None
+    json = False
+    permission = "view"
 
     def __init__(self, widget):
         """
@@ -96,12 +99,30 @@ class WidgetView(View):
         implement. It binds the other methods together.
         """
         instance = self._get_instance(*args, **kwargs)
+        try:
+            user = flask.g.auth.user
+        except AttributeError:
+            user = None
+        if not instance.allows(user, self.permission):
+            msg = "You are not allowed to access this widget."
+            if self.json:
+                result = flask.jsonify({
+                    "status": "ERROR", "message": msg,
+                    })
+            else:
+                result = flask.render_template(
+                    'errors/hub.html', hub=instance.hub, msg=msg,
+                    )
+            return result, 403
         context = self.get_context(instance, *args, **kwargs)
-        context.update(self.get_extra_context(instance, *args, **kwargs))
-        template = self.get_template()
-        before_render_template.send(
-            self.widget, template=template, context=context)
-        output = template.render(**context)
-        template_rendered.send(
-            self.widget, template=template, context=context)
-        return output
+        if self.json:
+            return flask.jsonify(context)
+        else:
+            context.update(self.get_extra_context(instance, *args, **kwargs))
+            template = self.get_template()
+            before_render_template.send(
+                flask.current_app, template=template, context=context)
+            output = template.render(**context)
+            template_rendered.send(
+                flask.current_app, template=template, context=context)
+            return output
diff --git a/requirements.txt b/requirements.txt
index 56ea13b..74264a8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,6 +4,7 @@ blinker
 datanommer.models
 decorator
 dogpile.cache
+enum34
 fedmsg
 fedmsg_meta_fedora_infrastructure
 flask

From f6797c682f4785bef0f28fce9eea360853d23524 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 06 2017 23:29:35 +0000
Subject: [PATCH 813/1001] Add a config panel to view, add and delete members


---

diff --git a/hubs/models.py b/hubs/models.py
index 758a64f..d54dccd 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -123,9 +123,9 @@ class Association(BASE):
     role = sa.Column(sa.Enum(*roles), primary_key=True)
 
     user = relation("User", backref=backref(
-        'associations', cascade="all, delete"))
+        'associations', cascade="all, delete, delete-orphan"))
     hub = relation("Hub", backref=backref(
-        'associations', cascade="all, delete"))
+        'associations', cascade="all, delete, delete-orphan"))
 
     @classmethod
     def get(cls, hub, user, role):
diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
index 73cbc7a..f4b75af 100644
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -7,6 +7,7 @@ import {
 import {
   GeneralPanel,
   ChatPanel,
+  UserPanel,
   NotImplementedPanel,
   } from './HubConfigPanel.jsx';
 import TabSet from '../components/TabSet.jsx';
@@ -56,13 +57,15 @@ export default class HubConfig extends React.Component {
     this.state = {
       hubConfig: {},
       generalConfig: {},
+      users: {owner: [], member: []},
       dirty: false,
       mustReload: false,  // the settings were changed at least once
       error: null,
       loading: false
-    }
+    };
     this.serverRequest = null;
     this.handleChange = this.handleChange.bind(this);
+    this.handleUserChange = this.handleUserChange.bind(this);
     this.loadState = this.loadState.bind(this);
     this.pushState = this.pushState.bind(this);
   }
@@ -73,21 +76,31 @@ export default class HubConfig extends React.Component {
       dataType: 'json',
       cache: false,
       success: function(data) {
-        this.setState({
-          hubConfig: data.result.hub,
-          generalConfig: data.result.general,
-          dirty: false,
-          error: null,
-          loading: false
-        });
+        if (data.status === "OK") {
+          this.setState({
+            hubConfig: data.result.hubconfig,
+            generalConfig: data.result.general,
+            users: data.result.users,
+            dirty: false,
+            error: null,
+          });
+        } else if (data.status === "ERROR") {
+          this.setState({error: data.message});
+        } else {
+          this.setState({
+            error: "Unknown status: " + data.status
+          });
+        }
       }.bind(this),
       error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-        this.setState({
-          error: err.toString(),
-          loading: false
-        });
-      }.bind(this)
+        var msg = err.toString();
+        if (!msg) { msg = "Error communicating with the server"; }
+        console.error(this.props.url, status, msg);
+        this.setState({error: msg});
+      }.bind(this),
+      complete: function(xhr, status) {
+        this.setState({loading: false});
+      }.bind(this),
     }
   }
 
@@ -98,10 +111,11 @@ export default class HubConfig extends React.Component {
     this.serverRequest = $.ajax(params);
   }
 
-  pushState() {
+  pushState(data, category) {
     var params = this.getRequestParams();
     params.method = "POST";
-    params.data = this.state.hubConfig;
+    params.data = data;
+    params.url += "?category=" + category;
     this.setState({loading: true});
     this.serverRequest = $.ajax(params);
   }
@@ -115,10 +129,17 @@ export default class HubConfig extends React.Component {
       mustReload: true,
     }, function() {
       window.clearTimeout(this.pushTimer);
-      this.pushTimer = window.setTimeout(this.pushState, 1000);
+      this.pushTimer = window.setTimeout(
+        this.pushState, 1000, this.state.hubConfig, "config");
     });
   }
 
+  handleUserChange(username, role) {
+    console.log("new role", username, role);
+    var data = {username: username, role: role};
+    this.pushState(data, "role_change");
+  }
+
   componentDidMount() {
     this.loadState();
   }
@@ -129,7 +150,7 @@ export default class HubConfig extends React.Component {
       // The configuration was changed but the current display may not
       // reflect it (for example, the displayed summary may be the old one).
       // The only way to make the changes visible is to reload the page.
-      window.location = window.location;
+      window.location.reload(true);
     }
   }
 
@@ -138,7 +159,6 @@ export default class HubConfig extends React.Component {
       <IntlProvider locale={navigator.language}>
         <div className="modal-dialog modal-lg" role="document">
           <div className="modal-content">
-            <form method="post" action={this.props.url}>
               <div className="modal-header">
                 <button
                   type="button"
@@ -164,21 +184,34 @@ export default class HubConfig extends React.Component {
                       generalConfig={this.state.generalConfig}
                       tabTitle={<FormattedMessage {...messages.general} />}
                       handleChange={this.handleChange}
+                      loading={this.state.loading}
                       />
-                    <NotImplementedPanel
+                    <UserPanel
+                      users={this.state.users.owner}
+                      generalConfig={this.state.generalConfig}
+                      role="owner"
+                      handleChange={this.handleUserChange}
                       tabTitle={<FormattedMessage {...messages.owners} />}
+                      loading={this.state.loading}
                       />
-                    <NotImplementedPanel
+                    <UserPanel
+                      users={this.state.users.member}
+                      generalConfig={this.state.generalConfig}
+                      role="member"
+                      handleChange={this.handleUserChange}
                       tabTitle={<FormattedMessage {...messages.members} />}
+                      loading={this.state.loading}
                       />
                     <ChatPanel
                       hubConfig={this.state.hubConfig}
                       generalConfig={this.state.generalConfig}
                       tabTitle={<FormattedMessage {...messages.chat} />}
                       handleChange={this.handleChange}
+                      loading={this.state.loading}
                       />
                     <NotImplementedPanel
                       tabTitle={<FormattedMessage {...messages.other} />}
+                      loading={this.state.loading}
                       />
                   </TabSet>
                 </div>
@@ -190,7 +223,7 @@ export default class HubConfig extends React.Component {
                   ></span>
                 <button
                   type="button"
-                  className="btn btn-default"
+                  className="btn btn-secondary"
                   data-dismiss="modal"
                   disabled={this.state.dirty}
                   >
@@ -210,7 +243,6 @@ export default class HubConfig extends React.Component {
                   </div>
                 }
               </div>
-            </form>
           </div>
         </div>
       </IntlProvider>
diff --git a/hubs/static/client/app/core/HubConfigPanel.jsx b/hubs/static/client/app/core/HubConfigPanel.jsx
index ddc22d3..865e340 100644
--- a/hubs/static/client/app/core/HubConfigPanel.jsx
+++ b/hubs/static/client/app/core/HubConfigPanel.jsx
@@ -83,6 +83,34 @@ const messages = defineMessages({
     id: "hubs.core.config.chat.network",
     defaultMessage: "IRC network",
   },
+  users_fullname: {
+    id: "hubs.core.config.users.fullname",
+    defaultMessage: "Full name",
+  },
+  users_username: {
+    id: "hubs.core.config.users.username",
+    defaultMessage: "Username",
+  },
+  users_change_role: {
+    id: "hubs.core.config.users.change_role",
+    defaultMessage: "Change role",
+  },
+  users_na: {
+    id: "hubs.core.config.users.na",
+    defaultMessage: "(N/A)",
+  },
+  users_remove_user: {
+    id: "hubs.core.config.users.remove_user",
+    defaultMessage: "(remove user)",
+  },
+  users_add_user: {
+    id: "hubs.core.config.users.add_user",
+    defaultMessage: "Add user...",
+  },
+  users_add: {
+    id: "hubs.core.config.users.add",
+    defaultMessage: "Add",
+  },
 });
 
 
@@ -105,7 +133,7 @@ export class GeneralPanel extends React.Component {
     var stillLoading = (typeof this.props.hubConfig.summary === "undefined");
     var visibilities = this.props.generalConfig.hub_visibility || [];
     return (
-      <div>
+      <form onSubmit={(e) => {e.preventDefault();}}>
         <FormattedMessage {...messages.general_title} tagName="h3" />
         <FormattedMessage {...messages.general_intro} tagName="p" />
         <div className="form-group">
@@ -177,6 +205,112 @@ export class GeneralPanel extends React.Component {
             <FormattedMessage {...messages.general_avatar_help} />
           </p>
         </div>
+      </form>
+    );
+  }
+
+}
+
+
+export class UserPanel extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      addUsername: "",
+    };
+    this.handleAdd = this.handleAdd.bind(this);
+    this.handleAddInputChange = this.handleAddInputChange.bind(this);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  handleAdd(e) {
+    e.preventDefault();
+    this.props.handleChange(this.state.addUsername, this.props.role);
+    this.setState({addUsername: ""});
+  }
+
+  handleAddInputChange(e) {
+    this.setState({
+      addUsername: e.target.value,
+    });
+  }
+
+  handleChange(e) {
+    e.preventDefault();
+    this.props.handleChange(e.target.name, e.target.value);
+  }
+
+  render() {
+    var users = this.props.users.map(function(user) {
+      return (
+        <tr key={user.username}>
+          <td>{user.fullname}</td>
+          <td>{user.username}</td>
+          <td>
+            {user.locked ?
+              <FormattedMessage {...messages.users_na} />
+            :
+              <select
+                name={user.username}
+                value={user.role}
+                className="form-control"
+                onChange={this.handleChange}
+                disabled={this.props.loading}
+                >
+                {this.props.generalConfig.roles.map(function(role) {
+                  return (
+                    <option value={role} key={role}>{role}</option>
+                    );
+                })}
+                <FormattedMessage {...messages.users_remove_user}>
+                  {(value) => ( <option value="">{value}</option> )}
+                </FormattedMessage>
+              </select>
+            }
+          </td>
+        </tr>
+        );
+    }.bind(this));
+
+    return (
+      <div>
+        <h3>{this.props.tabTitle}</h3>
+        <p className="text-muted">[Membership requests will be shown here]</p>
+        <hr />
+        <form className="form-inline" onSubmit={this.handleAdd}
+              style={{marginBottom: "1em"}}>
+          <div className="form-group">
+            <FormattedMessage {...messages.users_add_user}>
+              {(value) => (
+                <input
+                  type="text" className="form-control"
+                  name="username" placeholder={value}
+                  onChange={this.handleAddInputChange}
+                  value={this.state.addUsername}
+                  style={{marginRight: "1em"}}
+                  />
+                )}
+            </FormattedMessage>
+          </div>
+          <button className="btn btn-primary" disabled={this.props.loading}>
+            <FormattedMessage {...messages.users_add} />
+          </button>
+        </form>
+        {users.length !== 0 &&
+        <table className="table table-hover table-sm">
+          <thead>
+            <tr>
+              <FormattedMessage {...messages.users_fullname} tagName="th" />
+              <FormattedMessage {...messages.users_username} tagName="th" />
+              <FormattedMessage {...messages.users_change_role} tagName="th" />
+            </tr>
+          </thead>
+          <tbody>
+            {users}
+          </tbody>
+        </table>
+        }
       </div>
     );
   }
@@ -210,7 +344,7 @@ export class ChatPanel extends React.Component {
     }
 
     return (
-      <div>
+      <form onSubmit={(e) => {e.preventDefault();}}>
         <FormattedMessage {...messages.chat_title} tagName="h3" />
         <FormattedMessage {...messages.chat_intro_1} tagName="p" />
         <FormattedMessage {...messages.chat_intro_2} tagName="p" />
@@ -244,7 +378,7 @@ export class ChatPanel extends React.Component {
             {networks}
           </select>
         </div>
-      </div>
+      </form>
     );
   }
 
diff --git a/hubs/templates/widget_add.html b/hubs/templates/widget_add.html
index f410ac8..3e0d4d6 100644
--- a/hubs/templates/widget_add.html
+++ b/hubs/templates/widget_add.html
@@ -23,6 +23,18 @@
       {% else %}
         <p>Nothing to configure</p>
       {% endfor %}
+      {% if hub.config.visibility == "preview" %}
+        <fieldset class="form-group ">
+          <strong>Visibility</strong>
+          <select name="visibility" class="form-control">
+            <option value="public">Public</option>
+            <option value="restricted">Restricted</option>
+          </select>
+          <small class="text-muted">
+            Restricted widgets will only be visible by logged-in users.
+          </small>
+        </fieldset>
+      {% endif %}
       </div> <!-- /modal-body -->
       <div class="modal-footer">
         <button type="button" class="btn btn-default" data-dismiss="modal">
diff --git a/hubs/templates/widget_edit.html b/hubs/templates/widget_edit.html
index 3139d5d..6118e57 100644
--- a/hubs/templates/widget_edit.html
+++ b/hubs/templates/widget_edit.html
@@ -22,6 +22,22 @@
       {% else %}
         <p>Nothing to configure</p>
       {% endfor %}
+      {% if hub.config.visibility == "preview" %}
+        <fieldset class="form-group ">
+          <strong>Visibility</strong>
+          <select name="visibility" class="form-control">
+            <option value="public"
+                {% if widget_instance.visibility == "public" %}selected{% endif %}
+                >Public</option>
+            <option value="restricted"
+                {% if widget_instance.visibility == "restricted" %}selected{% endif %}
+                >Restricted</option>
+          </select>
+          <small class="text-muted">
+            Restricted widgets will only be visible by logged-in users.
+          </small>
+        </fieldset>
+      {% endif %}
       </div> <!-- /modal-body -->
       <div class="modal-footer">
         <button type="button" class="btn btn-default" data-dismiss="modal">
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 778ea54..29b91fc 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -401,7 +401,7 @@ class HubsAPITest(hubs.tests.APPTest):
 
     def test_hub_config_get(self):
         expected = {
-            "hub": {
+            "hubconfig": {
                 "summary": "Ralph",
                 "left_width": 8,
                 "avatar": (
@@ -414,6 +414,16 @@ class HubsAPITest(hubs.tests.APPTest):
             },
             "general": {
                 "chat_networks": app.config["CHAT_NETWORKS"],
+                "roles": ["owner", "member"],
+            },
+            "users": {
+                "member": [],
+                "owner": [{
+                    "fullname": "Ralph",
+                    "locked": True,
+                    "role": "owner",
+                    "username": "ralph",
+                }],
             },
         }
         user = tests.FakeAuthorization('ralph')
@@ -428,7 +438,7 @@ class HubsAPITest(hubs.tests.APPTest):
     def test_hub_config_post(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            url = '/ralph/config'
+            url = '/ralph/config?category=config'
             result = self.app.post(url, data={
                 "summary": "changed value",
                 "chat_domain": "",
@@ -437,19 +447,19 @@ class HubsAPITest(hubs.tests.APPTest):
         result_data = json.loads(result.get_data(as_text=True))
         self.assertEqual(result_data["status"], "OK")
         self.assertEqual(
-            result_data["result"]["hub"]["summary"],
+            result_data["result"]["hubconfig"]["summary"],
             "changed value")
         self.assertEqual(
-            result_data["result"]["hub"]["chat_domain"],
+            result_data["result"]["hubconfig"]["chat_domain"],
             app.config["CHAT_NETWORKS"][0]["domain"])
 
     def test_hub_config_post_unknown_post_data(self):
         # Unknown POST data is silently ignored
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            url = '/ralph/config'
+            url = '/ralph/config?category=config'
             result = self.app.post(url, data={"non_existant": "dummy"})
-        self.assertEqual(result.status_code, 400)
+        self.assertEqual(result.status_code, 200)
         result_data = json.loads(result.get_data(as_text=True))
         self.assertEqual(result_data["status"], "ERROR")
         self.assertEqual(result_data["message"], "Invalid value(s)")
@@ -462,9 +472,9 @@ class HubsAPITest(hubs.tests.APPTest):
     def test_hub_config_post_invalid_chat_domain(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            url = '/ralph/config'
+            url = '/ralph/config?category=config'
             result = self.app.post(url, data={"chat_domain": "dummy"})
-        self.assertEqual(result.status_code, 400)
+        self.assertEqual(result.status_code, 200)
         result_data = json.loads(result.get_data(as_text=True))
         self.assertEqual(result_data["status"], "ERROR")
         self.assertEqual(result_data["message"], "Invalid value(s)")
@@ -478,6 +488,6 @@ class HubsAPITest(hubs.tests.APPTest):
     def test_hub_config_unauthorized(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
-            url = '/decause/config'
+            url = '/decause/config?category=config'
             result = self.app.post(url, data={"summary": "Defaced!"})
         self.assertEqual(result.status_code, 403)
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 75b5764..c3ea5f4 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -153,45 +153,96 @@ def hub_edit_post(hub):
 @require_hub_access("config", json=True)
 def hub_config(name):
     hub = get_hub(name)
-    config = {
+    if flask.request.method == 'POST':
+        category = flask.request.args["category"]
+        if category == "config":
+            result = hub_config_post_config(hub)
+        if category == "role_change":
+            result = hub_config_post_role_change(hub)
+        if result is not None:
+            return result
+    result = hub_config_get(hub)
+    return flask.jsonify(result)
+
+
+def hub_config_get(hub):
+    roles = ["owner", "member"]
+    result = {
         "status": "OK",
         "result": {
-            "hub": {},
+            "hubconfig": hub.config.__json__(),
             "general": {
                 "chat_networks": app.config["CHAT_NETWORKS"],
                 "hub_visibility": hubs.models.HubConfig.VISIBILITY,
+                "roles": roles,
             },
+            "users": {role: [] for role in roles},
         },
     }
-    if flask.request.method == 'POST':
-        # Validate values
-        def _validate_chat_domain(value):
-            valid_chat_domains = [
-                network["domain"] for network in app.config["CHAT_NETWORKS"]
-                ]
-            if not value and len(valid_chat_domains) > 0:
-                value = valid_chat_domains[0]
-            if value not in valid_chat_domains:
-                raise ValueError("Unsupported chat domain.")
-            return value
-        validator = RequestValidator(dict(
-            # Only allow the parameters listed in __json__().
-            (key, None) for key in hub.config.__json__().keys()
-        ))
-        validator.converters["chat_domain"] = _validate_chat_domain
-        try:
-            values = validator(flask.request.form)
-        except ValueError as e:
-            config = {"status": "ERROR", "message": "Invalid value(s)"}
-            config["fields"] = e.args[0]
-            return flask.jsonify(config), 400
-        # Now set the configuration values
-        for key, value in values.items():
-            setattr(hub.config, key, value)
-        try:
-            flask.g.db.commit()
-        except Exception as err:
-            config = {"status": "ERROR", "message": str(err)}
-            return flask.jsonify(config), 400
-    config["result"]["hub"].update(hub.config.__json__())
-    return flask.jsonify(config)
+    for assoc in sorted(hub.associations, key=lambda a: a.user.username):
+        if assoc.role not in roles:
+            continue
+        user = {
+            "username": assoc.user.username,
+            "fullname": assoc.user.fullname,
+            "role": assoc.role,
+        }
+        if (assoc.role == "owner" and
+                assoc.user.username == flask.g.auth.user.username):
+            user["locked"] = True
+        result["result"]["users"][assoc.role].append(user)
+    return result
+
+
+def hub_config_post_config(hub):
+    # Validate values
+    def _validate_chat_domain(value):
+        valid_chat_domains = [
+            network["domain"] for network in app.config["CHAT_NETWORKS"]
+            ]
+        if not value and len(valid_chat_domains) > 0:
+            value = valid_chat_domains[0]
+        if value not in valid_chat_domains:
+            raise ValueError("Unsupported chat domain.")
+        return value
+
+    validator = RequestValidator(dict(
+        # Only allow the parameters listed in __json__().
+        (key, None) for key in hub.config.__json__().keys()
+    ))
+    validator.converters["chat_domain"] = _validate_chat_domain
+    try:
+        values = validator(flask.request.form)
+    except ValueError as e:
+        result = {"status": "ERROR", "message": "Invalid value(s)"}
+        result["fields"] = e.args[0]
+        return flask.jsonify(result)
+
+    # Now set the configuration values
+    for key, value in values.items():
+        setattr(hub.config, key, value)
+    try:
+        flask.g.db.commit()
+    except Exception as err:
+        result = {"status": "ERROR", "message": str(err)}
+        return flask.jsonify(result)
+
+
+def hub_config_post_role_change(hub):
+    username = flask.request.form["username"]
+    user = hubs.models.User.get(username=username)
+    if user is None:
+        result = {
+            "status": "ERROR",
+            "fields": {"username": "Unknown user"},
+            "message": "Unknown user",
+            }
+        return flask.jsonify(result)
+    role = flask.request.form.get("role")
+    for assoc in hub.associations:
+        if assoc.hub == hub and assoc.user == user:
+            hub.associations.remove(assoc)
+    if role:
+        hub.associations.append(hubs.models.Association(
+            hub=hub, user=user, role=role))
+    flask.g.db.commit()
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index 0a89595..15ee71a 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -113,7 +113,12 @@ def configure_widget_instance(widget_instance):
     cur_config = cur_config.copy()
     cur_config.update(config)
     widget_instance.config = cur_config
-    # TODO: use a SQLAlchemy signal here
+    # Set the visibility parameter.
+    try:
+        widget_instance.visibility = flask.request.form["visibility"]
+    except KeyError:
+        pass  # the value is optional.
+    # Update the hub's mtime.  TODO: use a SQLAlchemy signal here.
     widget_instance.hub.last_edited = datetime.datetime.utcnow()
     try:
         flask.g.db.commit()

From 9d703800365277bc63f53a8570880d15ee8512ea Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 06 2017 23:29:35 +0000
Subject: [PATCH 814/1001] Documentation


---

diff --git a/docs/api.rst b/docs/api.rst
deleted file mode 100644
index a5c0786..0000000
--- a/docs/api.rst
+++ /dev/null
@@ -1,57 +0,0 @@
-Developer Interfaces
-====================
-
-This documents ways developers can interface with Fedora Hubs.
-
-
-View utils
-----------
-
-.. automodule:: hubs.views.utils
-   :members:
-
-
-.. _widgets-api:
-
-
-Widgets
--------
-
-.. automodule:: hubs.widgets
-   :members:
-   :show-inheritance:
-
-Widgets registry
-^^^^^^^^^^^^^^^^
-
-.. automodule:: hubs.widgets.registry
-   :members:
-   :show-inheritance:
-
-Widget class
-^^^^^^^^^^^^
-
-.. automodule:: hubs.widgets.base
-   :members:
-   :show-inheritance:
-
-Widget parameter validators
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. automodule:: hubs.widgets.validators
-   :members:
-   :show-inheritance:
-
-Widget view
-^^^^^^^^^^^
-
-.. automodule:: hubs.widgets.view
-   :members:
-   :show-inheritance:
-
-Caching
-^^^^^^^
-
-.. automodule:: hubs.widgets.caching
-   :members:
-   :show-inheritance:
diff --git a/docs/api/auth.rst b/docs/api/auth.rst
new file mode 100644
index 0000000..36b5cf3
--- /dev/null
+++ b/docs/api/auth.rst
@@ -0,0 +1,28 @@
+Authentication and authorization
+================================
+
+Authentication is the fact of checking that the user is who they say they are.
+
+Authorization is the fact of allowing or refusing access to resources for this
+user.
+
+In Hubs, authentication is delegated to Fedora's OpenID server, and the
+authorization system is in the :py:mod:`hubs.authz` module.
+
+Authorization
+-------------
+
+A hub's visibility is controlled by the ``HubConfig.visibility`` parameter. It
+can have 3 values:
+
+- ``public``: the hub is visible to everyone
+- ``private``: the hub is only visible to members
+- ``preview``: the hub is visible to everyone, but some widgets can be
+  restricted to logged-in users only
+
+To restrict a widget to logged-in users only on a ``preview`` hub, set its
+:py:attr:`~hubs.models.Widget.visibility` property to ``restricted``.
+
+.. automodule:: hubs.authz
+   :members:
+   :private-members:
diff --git a/docs/api/index.rst b/docs/api/index.rst
new file mode 100644
index 0000000..90ec30e
--- /dev/null
+++ b/docs/api/index.rst
@@ -0,0 +1,11 @@
+Developer Interfaces
+====================
+
+This documents ways developers can interface with Fedora Hubs.
+
+.. toctree::
+   :maxdepth: 2
+
+   views
+   widgets
+   auth
diff --git a/docs/api/views.rst b/docs/api/views.rst
new file mode 100644
index 0000000..08a2a90
--- /dev/null
+++ b/docs/api/views.rst
@@ -0,0 +1,9 @@
+Views
+=====
+
+View utils
+----------
+
+.. automodule:: hubs.views.utils
+   :members:
+
diff --git a/docs/api/widgets.rst b/docs/api/widgets.rst
new file mode 100644
index 0000000..021bf49
--- /dev/null
+++ b/docs/api/widgets.rst
@@ -0,0 +1,44 @@
+.. _widgets-api:
+
+
+Widgets
+=======
+
+.. automodule:: hubs.widgets
+   :members:
+   :show-inheritance:
+
+Widgets registry
+----------------
+
+.. automodule:: hubs.widgets.registry
+   :members:
+   :show-inheritance:
+
+Widget class
+------------
+
+.. automodule:: hubs.widgets.base
+   :members:
+   :show-inheritance:
+
+Widget parameter validators
+---------------------------
+
+.. automodule:: hubs.widgets.validators
+   :members:
+   :show-inheritance:
+
+Widget view
+-----------
+
+.. automodule:: hubs.widgets.view
+   :members:
+   :show-inheritance:
+
+Caching
+-------
+
+.. automodule:: hubs.widgets.caching
+   :members:
+   :show-inheritance:
diff --git a/docs/conf.py b/docs/conf.py
index 9264743..30c5281 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -34,6 +34,7 @@ extensions = [
     'sphinx.ext.doctest',
     'sphinx.ext.napoleon',
     'sphinx.ext.viewcode',
+    'sphinx.ext.todo',
 ]
 
 # Add any paths that contain templates here, relative to this directory.
@@ -116,7 +117,7 @@ pygments_style = 'sphinx'
 # keep_warnings = False
 
 # If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = False
+todo_include_todos = True
 
 
 # -- Options for HTML output ----------------------------------------------
diff --git a/docs/index.rst b/docs/index.rst
index 72ec92e..ed17c81 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -13,7 +13,7 @@ Contents:
 
    overview
    dev-guide
-   api
+   api/index
 
 
 Indices and tables
diff --git a/docs/overview.rst b/docs/overview.rst
index a72f167..5b661c4 100644
--- a/docs/overview.rst
+++ b/docs/overview.rst
@@ -11,8 +11,9 @@ mailing lists and IRC which can be intimidating to new contributors. The vision 
 to have a modern, web-based Fedora activity center which feels like the positive,
 connected energy of Flock or FUDCon, available to all of us at any time.
 
+
 Integration
-^^^^^^^^^^^
+-----------
 
 Fedora Hubs integrates with, or plans to integrate with, the following tools and projects:
 
@@ -35,3 +36,21 @@ If you would like to know more, `these blog posts / videos
 information about our vision for the project, or check out the
 `issue tracker <https://pagure.io/fedora-hubs/issues/>`_ to see what features are
 planned.
+
+
+Authentication
+--------------
+
+Users are authenticated through the `Fedora Account System
+<https://admin.fedoraproject.org/accounts>`_ (FAS). Every user in FAS will have
+a personal hub created for them when they first login on Fedora Hubs.
+
+Hubs can have 3 different visibility settings:
+
+- ``public``: the hub is visible to everyone
+- ``private``: the hub is only visible to members
+- ``preview``: the hub is visible to everyone, but some widgets can be
+  restricted to logged-in users only
+
+In case of ``preview`` hubs, each widget's visibility can be set in the
+widget's configuration panel.
diff --git a/hubs/authz.py b/hubs/authz.py
index ebd85ca..b38a150 100644
--- a/hubs/authz.py
+++ b/hubs/authz.py
@@ -1,21 +1,44 @@
+"""
+The authorization model is based on an access level hierarchy: each level
+grants more permissions than the previous level. The levels are represented by
+the :py:class:`AccessLevel` enum. For example they can be ``anonymous``,
+``logged_in``, ``member``, ``admin``... anything really, as long as there is a
+hierarchy.
+
+Permissions are named, for example ``view`` or ``edit``. Those permissions are
+linked to the corresponding access level using the :py:data:`PERMISSIONS`
+dictionary.  For example the ``view`` permission can be granted to
+``anonymous`` users, or to ``members`` only.
+
+Object instances where authorization applies can use the
+:py:class:`ObjectAuthzMixin` mixin which provides a method to check for
+permissions.  Those objects must implement a method in the mixin, see the class
+documentation for details.
+
+Todo:
+    Make a Flask extension that can be reused in other applications.
+    The :py:class:`AccessLevel` enum and the :py:data:`PERMISSIONS` mapping
+    will be configurable to suit the app's specifics.  There will be
+    separate backends for getting the user roles that can be chosen by
+    configuration.  The CAIAPI backend will be included.
+
+Attributes:
+    PERMISSIONS (dict): Mapping of permission names (string) to permission
+        level (:py:class:`AccessLevel` member).
+"""
+
 from __future__ import absolute_import, unicode_literals
 
 from enum import IntEnum
 from flask import current_app
 
 
-#class Authorization(object):
-#
-#    def __init__(self, app=None, db=None):
-#        self.db = db
-#        if app is not None:
-#            self.init_app(app)
-#
-#    def init_app(self):
-#        app.config.setdefault("AUTHZ_ADAPTER", None)
-
-
 class AccessLevel(IntEnum):
+    """Possible levels of access for a resource.
+
+    We use an ``IntEnum`` because there is a hierarchy in access level.
+    The ``IntEnum`` class make it easy because it is a subclass of integer.
+    """
     anonymous = 0
     logged_in = 1
     member = 2
@@ -35,8 +58,19 @@ PERMISSIONS = {
 
 
 class ObjectAuthzMixin(object):
+    """Make a model class authorization-aware.
+
+    This mixin introduces the :py:meth:`allows` method, which can be used to
+    check if a user has a permission.
+    """
 
     def allows(self, user, action):
+        """Check whether a user has the right to do the given action.
+
+        Args:
+            user (hubs.models.User): a User instance.
+            action (str): an action, which will be translated to a permission.
+        """
         site_admins = current_app.config.get("SITE_ADMINS", [])
         if user is not None and user.username in site_admins:
             return True
@@ -48,6 +82,19 @@ class ObjectAuthzMixin(object):
         return False
 
     def _get_auth_access_level(self, user):
+        """Get a user's access level.
+
+        A user's access level can come from its own properties (being logged-in
+        for example, or its username) and from its group roles. The global
+        access level is the highest access of the two.
+
+        Args:
+            user (hubs.models.User): a User instance.
+
+        Returns:
+            int: the member of :py:class:`AccessLevel` representing this user's
+                access level.
+        """
         if user is None:
             return AccessLevel.anonymous
         levels = [
@@ -57,9 +104,28 @@ class ObjectAuthzMixin(object):
         return max(l for l in levels if l is not None)
 
     def _get_auth_user_access_level(self, user):
+        """Get a user's access level based on its own properties.
+
+        Args:
+            user (hubs.models.User): a User instance.
+
+        Returns:
+            int: the member of :py:class:`AccessLevel` representing this user's
+                access level.
+        """
         return AccessLevel.logged_in
 
     def _get_auth_group_access_level(self, user):
+        """Get a user's access level based on its group roles.
+
+        Args:
+            user (hubs.models.User): a User instance.
+
+        Returns:
+            int: the member of :py:class:`AccessLevel` representing this user's
+                access level or ``None`` if no access level can be derived from
+                group roles.
+        """
         group = self._get_auth_group()
         user_roles = self._get_auth_user_roles(user)
         try:
@@ -74,15 +140,36 @@ class ObjectAuthzMixin(object):
             return None
 
     def _get_auth_group(self):
+        """Get the corresponding authentication backend's group.
+
+        For each object using this mixin, there can be a group in the
+        authentication backend that will control access to this resource.
+        Roles in this group can be mapped to AccessLevels in this app.
+        """
         raise NotImplementedError
 
     def _get_auth_user_roles(self, user):
-        return get_user_roles(user)
+        """Get all the roles for a user.
+
+        Args:
+            user (hubs.models.User): a User instance.
+
+        Returns:
+            dict: the mapping of group names (str) to roles (str) in the
+                authentication backend for this user.
+
+        Todo:
+            Use the new CAIAPI when it is ready.
+        """
+        return {g: "member" for g in user.groups}
 
     def _get_auth_permission_name(self, action):
-        return action
+        """Return the permission name for the given action.
 
+        Args:
+            action (str): an action name
 
-def get_user_roles(user):
-    # TODO: use the new API
-    return {g: "member" for g in user.groups}
+        Returns:
+            str: a key in the :py:data:`PERMISSIONS` dictionary.
+        """
+        return action
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index 15ee71a..1821026 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -1,3 +1,8 @@
+"""
+The :py:mod:`hubs.views.utils` module contains helper functions and classes
+for the views.
+"""
+
 from __future__ import unicode_literals
 
 import datetime

From 06f0aabc228a36ead8b1ab1cfdad66b3b609daf9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 11 2017 12:51:54 +0000
Subject: [PATCH 815/1001] Add tests


...and un-skip the existing unit tests.

---

diff --git a/hubs/app.py b/hubs/app.py
index 7b28c4c..d50c365 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -65,12 +65,6 @@ def commas(numeric):
     return "{:,.2f}".format(numeric)
 
 
-@app.teardown_request
-def shutdown_session(exception=None):
-    """ Remove the DB session at the end of each request. """
-    session.remove()
-
-
 # Set up OpenIDConnect
 OIDC = OpenIDConnect(app, credentials_store=flask.session)
 
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index edd2ba5..ad600c0 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -1,17 +1,17 @@
 from __future__ import unicode_literals
 
-from contextlib import contextmanager
 import json
-from datetime import datetime, timedelta
 import os
-
-import munch
-from flask import template_rendered
-from os.path import dirname
 import unittest
+from contextlib import contextmanager
+from datetime import datetime, timedelta
+from os.path import dirname
 
+import flask
+import munch
 import requests
 import vcr
+from flask.signals import template_rendered
 
 import hubs.models
 
@@ -99,6 +99,21 @@ class APPTest(unittest.TestCase):
             raise IOError("Failed to talk to %r %r" % (response.url, response))
         return response.json()
 
+    def check_url(self, url, user=None, code=200):
+        with auth_set(hubs.app.app, user):
+            with hubs.app.app.app_context():
+                with captured_templates(flask.current_app) as templates:
+                    response = self.app.get(url)
+        self.assertEqual(response.status_code, code)
+        if templates:
+            self.assertEqual(len(templates), 1)
+            template, context = templates[0]
+        else:
+            template = context = None
+        response.context = context
+        response.template = template
+        return response
+
 
 @contextmanager
 def auth_set(APP, auth):
diff --git a/hubs/tests/hubs_test.cfg b/hubs/tests/hubs_test.cfg
index 66ccd47..a910e72 100644
--- a/hubs/tests/hubs_test.cfg
+++ b/hubs/tests/hubs_test.cfg
@@ -9,3 +9,5 @@ DB_URL = 'sqlite:///%s/test.db' % (os.path.dirname(os.path.abspath(__file__)))
 import os
 OIDC_CLIENT_SECRETS = os.path.join(os.path.dirname(
     os.path.abspath(__file__)), 'client_secrets.json')
+
+SITE_ADMINS = ["admin"]
diff --git a/hubs/tests/test_authz.py b/hubs/tests/test_authz.py
new file mode 100644
index 0000000..ec607de
--- /dev/null
+++ b/hubs/tests/test_authz.py
@@ -0,0 +1,113 @@
+from __future__ import absolute_import, unicode_literals
+
+from hubs.authz import ObjectAuthzMixin, AccessLevel, PERMISSIONS
+from hubs.tests import APPTest, FakeAuthorization
+
+
+class TestObj(ObjectAuthzMixin):
+
+    def __init__(self, roles=None):
+        self.roles = roles or {}
+
+    def _get_auth_group(self):
+        return "auth-group"
+
+    def _get_auth_user_roles(self, user):
+        return self.roles
+
+
+class AuthzTestCase(APPTest):
+
+    def run(self, *args, **kwargs):
+        import hubs.app
+        with hubs.app.app.app_context():
+            super(AuthzTestCase, self).run(*args, **kwargs)
+
+    def test_mixin_access_level_anonymous(self):
+        obj = TestObj()
+        self.assertEqual(
+            obj._get_auth_access_level(None), AccessLevel.anonymous)
+
+    def test_mixin_access_level_logged_in(self):
+        obj = TestObj()
+        user = FakeAuthorization('ralph')
+        self.assertEqual(
+            obj._get_auth_access_level(user), AccessLevel.logged_in)
+
+    def test_mixin_group_access_level(self):
+        obj = TestObj(roles={"auth-group": "member"})
+        user = FakeAuthorization('ralph')
+        self.assertEqual(
+            obj._get_auth_access_level(user), AccessLevel.member)
+
+    def test_mixin_group_access_level_no_role(self):
+        obj = TestObj(roles={"unrelated-group": "member"})
+        user = FakeAuthorization('ralph')
+        self.assertEqual(
+            obj._get_auth_access_level(user), AccessLevel.logged_in)
+
+    def test_mixin_group_access_level_unsupported(self):
+        obj = TestObj(roles={"auth-group": "dark_lord"})
+        user = FakeAuthorization('ralph')
+        self.assertEqual(
+            obj._get_auth_access_level(user), AccessLevel.logged_in)
+
+    def test_allows_anonymous(self):
+        obj = TestObj()
+        self.assertTrue(obj.allows(None, 'hub.public.view'))
+        self.assertTrue(obj.allows(None, 'hub.preview.view'))
+        self.assertFalse(obj.allows(None, 'hub.private.view'))
+        self.assertFalse(obj.allows(None, 'hub.users.manage'))
+        self.assertFalse(obj.allows(None, 'hub.config'))
+        self.assertTrue(obj.allows(None, 'widget.public.view'))
+        self.assertFalse(obj.allows(None, 'widget.restricted.view'))
+
+    def test_allows_logged_in(self):
+        user = FakeAuthorization('ralph')
+        obj = TestObj()
+        self.assertTrue(obj.allows(user, 'hub.public.view'))
+        self.assertTrue(obj.allows(user, 'hub.preview.view'))
+        self.assertFalse(obj.allows(user, 'hub.private.view'))
+        self.assertFalse(obj.allows(user, 'hub.users.manage'))
+        self.assertFalse(obj.allows(user, 'hub.config'))
+        self.assertTrue(obj.allows(user, 'widget.public.view'))
+        self.assertTrue(obj.allows(user, 'widget.restricted.view'))
+
+    def test_allows_member(self):
+        user = FakeAuthorization('ralph')
+        obj = TestObj(roles={"auth-group": "member"})
+        self.assertTrue(obj.allows(user, 'hub.public.view'))
+        self.assertTrue(obj.allows(user, 'hub.preview.view'))
+        self.assertTrue(obj.allows(user, 'hub.private.view'))
+        self.assertFalse(obj.allows(user, 'hub.users.manage'))
+        self.assertFalse(obj.allows(user, 'hub.config'))
+        self.assertTrue(obj.allows(user, 'widget.public.view'))
+        self.assertTrue(obj.allows(user, 'widget.restricted.view'))
+
+    def test_allows_sponsor(self):
+        user = FakeAuthorization('ralph')
+        obj = TestObj(roles={"auth-group": "sponsor"})
+        self.assertTrue(obj.allows(user, 'hub.public.view'))
+        self.assertTrue(obj.allows(user, 'hub.preview.view'))
+        self.assertTrue(obj.allows(user, 'hub.private.view'))
+        self.assertTrue(obj.allows(user, 'hub.users.manage'))
+        self.assertFalse(obj.allows(user, 'hub.config'))
+        self.assertTrue(obj.allows(user, 'widget.public.view'))
+        self.assertTrue(obj.allows(user, 'widget.restricted.view'))
+
+    def test_allows_owner(self):
+        user = FakeAuthorization('ralph')
+        obj = TestObj(roles={"auth-group": "owner"})
+        self.assertTrue(obj.allows(user, 'hub.public.view'))
+        self.assertTrue(obj.allows(user, 'hub.preview.view'))
+        self.assertTrue(obj.allows(user, 'hub.private.view'))
+        self.assertTrue(obj.allows(user, 'hub.users.manage'))
+        self.assertTrue(obj.allows(user, 'hub.config'))
+        self.assertTrue(obj.allows(user, 'widget.public.view'))
+        self.assertTrue(obj.allows(user, 'widget.restricted.view'))
+
+    def test_allows_site_admin(self):
+        user = FakeAuthorization('admin')
+        obj = TestObj()
+        for perm in PERMISSIONS.keys():
+            self.assertTrue(obj.allows(user, perm))
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index 29b91fc..a0a0d62 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -14,6 +14,7 @@ import hubs.models
 
 
 class HubsAPITest(hubs.tests.APPTest):
+
     def test_index_logged_out(self):
         result = self.app.get('/', follow_redirects=False)
         self.assertEqual(result.status_code, 302)
@@ -65,6 +66,29 @@ class HubsAPITest(hubs.tests.APPTest):
                 'Not logged in.  Click to <a href="/login">login</a>',
                 result.get_data(as_text=True))
 
+    def test_hub_preview(self):
+        hub = hubs.models.Hub.by_name('ralph')
+        hub.config.visibility = "preview"
+        # Preview hubs are accessible to anonymous users (but some
+        # widgets may be restricted).
+        with tests.auth_set(app, None):
+            result = self.app.get('/ralph', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+
+    def test_hub_private(self):
+        hub = hubs.models.Hub.by_name('ralph')
+        hub.config.visibility = "private"
+        self.session.commit()
+        # Private hubs are not accessible to anonymous users.
+        with tests.auth_set(app, None):
+            result = self.app.get('/ralph', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)
+        # But they are accessible to members.
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/ralph', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+
     def test_hub_json(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
@@ -80,6 +104,7 @@ class HubsAPITest(hubs.tests.APPTest):
                 'chat_domain': None,
                 "left_width": 8,
                 "summary": "Ralph",
+                "visibility": "public",
             },
             "members": ["ralph"],
             "name": "ralph",
@@ -89,46 +114,49 @@ class HubsAPITest(hubs.tests.APPTest):
         }
         self.assertDictEqual(data, json.loads(result.get_data(as_text=True)))
 
-    @unittest.skip("Authorization layer not present yet")
+    def test_hub_private_json(self):
+        hub = hubs.models.Hub.by_name('ralph')
+        hub.config.visibility = "private"
+        self.session.commit()
+        # Private hubs are not accessible to anonymous users.
+        with tests.auth_set(app, None):
+            result = self.app.get('/ralph/json', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)
+        # But they are accessible to members.
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            result = self.app.get('/ralph/json', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+
     def test_hub_edit_get_logged_out(self):
-        # FAILING: Authorization layer not present yet
         with tests.auth_set(app, None):
-            result = self.app.get('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)  # failing right
-            # We do not have the authorization layer in place yet
+            result = self.app.get('/ralph/edit', follow_redirects=False)
+        self.assertEqual(result.status_code, 302)
+        self.assertEqual(urlparse(result.location).path, "/login")
 
-    @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_get_logged_in_not_owner(self):
-        # FAILING: Authorization layer not present yet
         user = tests.FakeAuthorization('not_ralph')
         with tests.auth_set(app, user):
             result = self.app.get('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)  # failing right
-            # We do not have the authorization layer in place yet
+            self.assertEqual(result.status_code, 403)
 
     def test_hub_edit_get_logged_in_owner(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             result = self.app.get('/ralph/edit', follow_redirects=True)
             self.assertEqual(result.status_code, 200)
-            # We do not have the authorization layer so everyone can edit
 
-    @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_post_logged_out(self):
-        # FAILING: Authorization layer not present yet
         with tests.auth_set(app, None):
-            result = self.app.post('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)  # failing right
-            # We do not have the authorization layer in place yet
+            result = self.app.post('/ralph/edit', follow_redirects=False)
+        self.assertEqual(result.status_code, 302)
+        self.assertEqual(urlparse(result.location).path, "/login")
 
-    @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_post_logged_in_not_owner(self):
-        # FAILING: Authorization layer not present yet
         user = tests.FakeAuthorization('not_ralph')
         with tests.auth_set(app, user):
             result = self.app.post('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)  # failing right
-            # We do not have the authorization layer in place yet
+            self.assertEqual(result.status_code, 403)
 
     def test_hub_edit_post_logged_in_owner_empty_data(self):
         user = tests.FakeAuthorization('ralph')
@@ -303,10 +331,10 @@ class HubsAPITest(hubs.tests.APPTest):
             expected_str = '/ralph/37/edit'
             self.assertIn(expected_str, result.get_data(as_text=True))
 
-    @unittest.skip("Authorization layer not present yet")
     def test_hub_edit_widget_get_logged_out(self):
-        result = self.app.get('/ralph/31/edit', follow_redirects=True)
-        self.assertEqual(result.status_code, 403)
+        result = self.app.get('/ralph/31/edit', follow_redirects=False)
+        self.assertEqual(result.status_code, 302)
+        self.assertEqual(urlparse(result.location).path, "/login")
 
     def test_hub_edit_widget_post_empty_data_logged_in(self):
         user = tests.FakeAuthorization('ralph')
@@ -411,10 +439,12 @@ class HubsAPITest(hubs.tests.APPTest):
                     ),
                 "chat_channel": None,
                 "chat_domain": None,
+                "visibility": "public",
             },
             "general": {
                 "chat_networks": app.config["CHAT_NETWORKS"],
                 "roles": ["owner", "member"],
+                "hub_visibility": hubs.models.HubConfig.VISIBILITY,
             },
             "users": {
                 "member": [],
@@ -484,8 +514,14 @@ class HubsAPITest(hubs.tests.APPTest):
             "Unsupported chat domain."
             )
 
-    @unittest.skip("Authorization layer not present yet")
-    def test_hub_config_unauthorized(self):
+    def test_hub_config_get_unauthorized(self):
+        user = tests.FakeAuthorization('ralph')
+        with tests.auth_set(app, user):
+            url = '/decause/config'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 403)
+
+    def test_hub_config_post_unauthorized(self):
         user = tests.FakeAuthorization('ralph')
         with tests.auth_set(app, user):
             url = '/decause/config?category=config'
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index c3279cd..d6cc11c 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -1,9 +1,11 @@
 from __future__ import unicode_literals
 
+import fedmsg.config
+
 import hubs
 import hubs.models
 import hubs.tests
-import fedmsg.config
+from hubs.authz import AccessLevel
 
 fedmsg_config = fedmsg.config.load_config()
 
@@ -153,3 +155,81 @@ class ModelTest(hubs.tests.APPTest):
                           session=self.session,
                           username=username,
                           visited_hub=hub)
+
+    def test_auth_hub_widget_access_level(self):
+        username = 'ralph'
+        ralph = hubs.models.User.get(username)
+        hub_ralph = hubs.models.Hub.get(username)
+        widget_ralph = hubs.models.Widget.query.filter_by(
+            hub=hub_ralph, plugin="contact").one()
+        hub_decause = hubs.models.Hub.get("decause")
+        widget_decause = hubs.models.Widget.query.filter_by(
+            hub=hub_decause, plugin="contact").one()
+        self.assertEqual(
+            hub_decause._get_auth_access_level(ralph),
+            AccessLevel.logged_in)
+        self.assertEqual(
+            widget_decause._get_auth_access_level(ralph),
+            AccessLevel.logged_in)
+        self.assertEqual(
+            hub_ralph._get_auth_access_level(ralph),
+            AccessLevel.owner)
+        self.assertEqual(
+            widget_ralph._get_auth_access_level(ralph),
+            AccessLevel.owner)
+
+    def test_auth_hub_auth_group(self):
+        username = "ralph"
+        hub = hubs.models.Hub.get(username)
+        self.assertEqual(hub._get_auth_group(), username)
+        # Uncomment this when CAIAPI is active.
+        # hub.config.auth_group = "testing"
+        # self.assertEqual(hub._get_auth_group(), "testing")
+
+    def test_auth_hub_permission_name(self):
+        hub = hubs.models.Hub.get("ralph")
+        self.assertEqual(
+            hub._get_auth_permission_name("view"), "hub.public.view")
+        self.assertEqual(
+            hub._get_auth_permission_name("users.manage"), "hub.users.manage")
+        self.assertEqual(
+            hub._get_auth_permission_name("config"), "hub.config")
+        hub.config.visibility = "preview"
+        self.assertEqual(
+            hub._get_auth_permission_name("view"), "hub.preview.view")
+        hub.config.visibility = "private"
+        self.assertEqual(
+            hub._get_auth_permission_name("view"), "hub.private.view")
+
+    def test_auth_hub_widget_user_roles(self):
+        username = "ralph"
+        ralph = hubs.models.User.get(username)
+        hub = hubs.models.Hub.get(username)
+        widget = hubs.models.Widget.query.filter_by(
+            hub=hub, plugin="contact").one()
+        assert len(hub.associations) == 1
+        assert hub.associations[0].user.username == "ralph"
+        for role in ["owner", "sponsor", "member"]:
+            hub.associations[0].role = role
+            self.assertEqual(
+                hub._get_auth_user_roles(ralph), {"ralph": role})
+            self.assertEqual(
+                widget._get_auth_user_roles(ralph), {"ralph": role})
+
+    def test_auth_widget_permission_name(self):
+        hub = hubs.models.Hub.get("ralph")
+        widget = hubs.models.Widget.query.filter_by(
+            hub=hub, plugin="contact").one()
+        self.assertEqual(
+            widget._get_auth_permission_name("view"), "hub.public.view")
+        hub.config.visibility = "private"
+        self.session.commit()
+        self.assertEqual(
+            widget._get_auth_permission_name("view"), "hub.private.view")
+        hub.config.visibility = "preview"
+        assert widget.visibility == "public"
+        self.assertEqual(
+            widget._get_auth_permission_name("view"), "widget.public.view")
+        widget.visibility = "restricted"
+        self.assertEqual(
+            widget._get_auth_permission_name("view"), "widget.restricted.view")
diff --git a/hubs/tests/test_view_utils.py b/hubs/tests/test_view_utils.py
index d5e8218..0101299 100644
--- a/hubs/tests/test_view_utils.py
+++ b/hubs/tests/test_view_utils.py
@@ -1,11 +1,11 @@
 from __future__ import unicode_literals
 
 import hubs.models
-import hubs.tests
+from hubs.tests import APPTest, FakeAuthorization, auth_set
 from hubs.views.utils import get_visible_widgets
 
 
-class ModelTest(hubs.tests.APPTest):
+class ViewUtilsTest(APPTest):
 
     def test_removed_widget(self):
         hub = hubs.models.Hub.get("ralph")
@@ -13,8 +13,7 @@ class ModelTest(hubs.tests.APPTest):
             hub=hub, plugin="does-not-exist",
             left=True, index=-1, _config="{}")
         self.session.add(widget)
-        user = hubs.tests.FakeAuthorization('ralph')
-        with hubs.tests.auth_set(self.app.application, user):
+        with auth_set(self.app.application, FakeAuthorization('ralph')):
             with self.app.application.app_context():
                 widgets = get_visible_widgets(hub)
         self.assertNotIn(
@@ -22,3 +21,62 @@ class ModelTest(hubs.tests.APPTest):
         widget.left = False
         self.assertNotIn(
             "does-not-exist", [w.plugin for w in widgets["right"]])
+
+    def test_get_visible_widgets(self):
+        hub = hubs.models.Hub.get('ralph')
+        with auth_set(self.app.application, None):
+            with self.app.application.app_context():
+                widgets = get_visible_widgets(hub)
+        self.assertListEqual(
+            [w.plugin for w in widgets["left"]],
+            ["feed"])
+        self.assertListEqual(
+            [w.plugin for w in widgets["right"]],
+            ['contact', 'meetings', 'fedmsgstats', 'workflow.updates2stable',
+             'workflow.pendingacls', 'subscriptions', 'badges', 'pagure_pr',
+             'github_pr', 'bugzilla', 'halp', 'about']
+            )
+
+    def test_get_visible_widgets_preview(self):
+        hub = hubs.models.Hub.by_name('ralph')
+        hub.config.visibility = "preview"
+        meetings = hubs.models.Widget.query.filter_by(
+            hub=hub, plugin="meetings").first()
+        # make sure the test is valid
+        assert meetings.left is False
+        # set the widget to "restricted"
+        meetings.visibility = "restricted"
+        # Restricted widgets in preview hubs aren't displayed to
+        # anonymous users.
+        with auth_set(self.app.application, None):
+            with self.app.application.app_context():
+                widgets = get_visible_widgets(hub)
+        self.assertNotIn(
+            "meetings", [w.plugin for w in widgets["right"]])
+        # But they are displayed to members.
+        with auth_set(self.app.application, FakeAuthorization('ralph')):
+            with self.app.application.app_context():
+                widgets = get_visible_widgets(hub)
+        self.assertIn(
+            "meetings", [w.plugin for w in widgets["right"]])
+
+    def test_get_visible_widgets_private(self):
+        hub = hubs.models.Hub.by_name('ralph')
+        hub.config.visibility = "private"
+        meetings = hubs.models.Widget.query.filter_by(
+            hub=hub, plugin="meetings").first()
+        # make sure the test is valid
+        assert meetings.left is False
+        # Widgets in private hubs aren't displayed to
+        # anonymous users.
+        with auth_set(self.app.application, None):
+            with self.app.application.app_context():
+                widgets = get_visible_widgets(hub)
+        self.assertEqual(widgets["left"], [])
+        self.assertEqual(widgets["right"], [])
+        # But they are displayed to members.
+        with auth_set(self.app.application, FakeAuthorization('ralph')):
+            with self.app.application.app_context():
+                widgets = get_visible_widgets(hub)
+        self.assertNotEqual(len(widgets["left"]), 0)
+        self.assertNotEqual(len(widgets["right"]), 0)
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
index 3297022..7d171e4 100644
--- a/hubs/tests/test_widgets/__init__.py
+++ b/hubs/tests/test_widgets/__init__.py
@@ -1,13 +1,16 @@
 from __future__ import unicode_literals
 
 import json
+import unittest
 
 import hubs.models
-from hubs.tests import APPTest
+from hubs.tests import APPTest, FakeAuthorization
 
 
 class WidgetTest(APPTest):
 
+    plugin = None  # The name in hubs.widgets.registry
+
     def populate(self):
         super(WidgetTest, self).populate()
         hub = hubs.models.Hub.by_name('ralph')
@@ -18,4 +21,27 @@ class WidgetTest(APPTest):
             _config=json.dumps({"urls": "ralph/"})
         )
         hub.widgets.append(widget)
-        hubs.app.session.commit()
+        self.session.commit()
+
+    def _test_view_authz(self):
+        # Test authorizations on the root view.
+        if not self.plugin:
+            raise unittest.SkipTest
+        hub = hubs.models.Hub.query.get("ralph")
+        widget = self.widget_instance(hub.name, self.plugin)
+        url = '/%s/w/%s/%i/' % (hub.name, self.plugin, widget.idx)
+        # Public
+        self.check_url(url, None, 200)
+        # Preview
+        hub.config.visibility = "preview"
+        widget.visibility = "restricted"
+        self.session.commit()
+        self.check_url(url, None, 403)  # anonymous
+        self.check_url(url, FakeAuthorization('decause'), 200)  # logged-in
+        # Private
+        widget.hub.config.visibility = "private"
+        self.session.commit()
+        self.check_url(url, None, 403)  # anonymous
+        self.check_url(url, FakeAuthorization('decause'), 403)  # logged-in
+        hub.subscribe(hubs.models.User.query.get("decause"), "member")
+        self.check_url(url, FakeAuthorization('decause'), 200)  # member
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
index edab332..dd00e20 100644
--- a/hubs/tests/test_widgets/test_about.py
+++ b/hubs/tests/test_widgets/test_about.py
@@ -2,8 +2,8 @@ from __future__ import unicode_literals
 
 import json
 
-from hubs.tests import FakeAuthorization, auth_set
-from hubs.tests.test_widgets import WidgetTest
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
 
 
 class TestAbout(WidgetTest):
@@ -12,12 +12,13 @@ class TestAbout(WidgetTest):
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
-        with auth_set(self.app.application, user):
-            response = self.app.get('/ralph/%i/json' % widget.idx)
-        self.assertEqual(response.status_code, 200)
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
             'text': 'Testing.',
             'title': "<span class='glyphicon glyphicon-info-sign' "
                      "aria-hidden='true'></span> About",
         })
+
+    def test_view_authz(self):
+        self._test_view_authz()
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
index 30284fd..3cd2ee2 100644
--- a/hubs/tests/test_widgets/test_badges.py
+++ b/hubs/tests/test_widgets/test_badges.py
@@ -3,8 +3,8 @@ from __future__ import unicode_literals
 import json
 
 import hubs.widgets
-from hubs.tests import FakeAuthorization, auth_set
-from hubs.tests.test_widgets import WidgetTest
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
 
 
 class TestBadges(WidgetTest):
@@ -13,9 +13,7 @@ class TestBadges(WidgetTest):
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
-        with auth_set(self.app.application, user):
-            response = self.app.get('/ralph/%i/json' % widget.idx)
-        self.assertEqual(response.status_code, 200)
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
         self.assertEquals(data['plugin'], 'badges')
         self.assertIn('assertions', data['data'].keys())
@@ -58,3 +56,6 @@ class TestBadges(WidgetTest):
         func = module.get_cached_functions()['GetBadges']
         result = func(widget).should_invalidate(msg)
         self.assertTrue(result)
+
+    def test_view_authz(self):
+        self._test_view_authz()
diff --git a/hubs/tests/test_widgets/test_contact.py b/hubs/tests/test_widgets/test_contact.py
index 3e63953..3d885d1 100644
--- a/hubs/tests/test_widgets/test_contact.py
+++ b/hubs/tests/test_widgets/test_contact.py
@@ -7,8 +7,8 @@ import mock
 
 import hubs
 from hubs.models import Hub, Widget
-from hubs.tests import APPTest, FakeAuthorization, auth_set
-from hubs.tests.test_widgets import WidgetTest
+from hubs.tests import FakeAuthorization, auth_set
+from . import WidgetTest
 
 
 def mocked_requests_get(*args, **kwargs):
@@ -56,7 +56,7 @@ def mocked_requests_post(*args, **kwargs):
     return MockResponse({}, 404)
 
 
-class ContactsTest(APPTest):
+class ContactsTest(WidgetTest):
 
     plugin = "contact"
 
@@ -74,9 +74,7 @@ class ContactsTest(APPTest):
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
-        with auth_set(self.app.application, user):
-            response = self.app.get('/ralph/%i/json' % widget.idx)
-        self.assertEqual(response.status_code, 200)
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
             'account_age': 'Oct 2010',
@@ -89,6 +87,9 @@ class ContactsTest(APPTest):
             'usergroup': True,
         })
 
+    def test_view_authz(self):
+        self._test_view_authz()
+
     @mock.patch('requests.get', side_effect=mocked_requests_get)
     def test_plus_plus_get_valid(self, mock_get):
         widget = self.widget_instance("ralph", self.plugin)
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
index 4861b49..87b5ae0 100644
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ b/hubs/tests/test_widgets/test_fedmsgstats.py
@@ -2,8 +2,8 @@ from __future__ import unicode_literals
 
 import json
 
-from hubs.tests import FakeAuthorization, auth_set
-from hubs.tests.test_widgets import WidgetTest
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
 
 
 class TestFedmsgStats(WidgetTest):
@@ -12,9 +12,7 @@ class TestFedmsgStats(WidgetTest):
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
-        with auth_set(self.app.application, user):
-            response = self.app.get('/ralph/%i/json' % widget.idx)
-        self.assertEqual(response.status_code, 200)
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
             u'fedmsgs': 83854,
@@ -27,3 +25,6 @@ class TestFedmsgStats(WidgetTest):
             u'hub_subscribe_url': u'/api/hub/ralph/subscribe',
             u'hub_unsubscribe_url': u'/api/hub/ralph/unsubscribe',
         })
+
+    def test_view_authz(self):
+        self._test_view_authz()
diff --git a/hubs/tests/test_widgets/test_halp.py b/hubs/tests/test_widgets/test_halp.py
index 81c1831..ed60356 100644
--- a/hubs/tests/test_widgets/test_halp.py
+++ b/hubs/tests/test_widgets/test_halp.py
@@ -2,10 +2,10 @@ from __future__ import unicode_literals, absolute_import
 
 import json
 
-from hubs.models import Hub
-from hubs.tests import captured_templates
-from hubs.tests.test_widgets import WidgetTest
+from hubs.models import Hub, User
+from hubs.tests import FakeAuthorization
 from hubs.widgets import registry
+from . import WidgetTest
 
 
 SAMPLE_DATA = [
@@ -97,6 +97,7 @@ class HalpViewsTestCase(WidgetTest):
         dhrish = Hub.query.get("dhrish")
         dhrish.config.chat_channel = "#foss2serve"
         self.session.commit()
+        self.session.refresh(self.widget)
 
     def _get_sample_data_with_hub_keys(self):
         hub_names = ["infra", "devyani7", "dhrish", "decause", "decause"]
@@ -109,12 +110,11 @@ class HalpViewsTestCase(WidgetTest):
         return data
 
     def test_root(self):
-        with captured_templates(self.widget.module) as templates:
-            response = self.app.get('/ralph/w/halp/%i/' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(len(templates), 1)
-        _template, context = templates[0]
-        self.assertEqual(context["hubs"], ['fedora-devel'])
+        response = self.check_url('/ralph/w/halp/%i/' % self.widget.idx)
+        self.assertEqual(response.context["hubs"], ['fedora-devel'])
+
+    def test_view_authz(self):
+        self._test_view_authz()
 
     def test_json(self):
         response = self.app.get('/ralph/%i/json' % self.widget.idx)
@@ -124,30 +124,48 @@ class HalpViewsTestCase(WidgetTest):
         self.assertIn('hubs', data['data'].keys())
 
     def test_config_add(self):
-        with captured_templates(self.widget.module) as templates:
-            response = self.app.get('/ralph/w/halp/add?position=right')
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(len(templates), 1)
-        _template, context = templates[0]
-        self.assertEqual(context["mode"], "add")
-        self.assertEqual(context["initial"], {
+        user = FakeAuthorization('ralph')
+        response = self.check_url('/ralph/w/halp/add?position=right', user)
+        self.assertEqual(response.context["mode"], "add")
+        self.assertEqual(response.context["initial"], {
             "hubs": ["ralph"], "per_page": 4,
             })
-        self.assertEqual(context["url"], "/ralph/add/halp?position=right")
+        self.assertEqual(
+            response.context["url"], "/ralph/add/halp?position=right")
 
     def test_config_edit(self):
-        with captured_templates(self.widget.module) as templates:
-            response = self.app.get('/ralph/w/halp/%i/config'
-                                    % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(len(templates), 1)
-        _template, context = templates[0]
-        self.assertEqual(context["mode"], "edit")
-        self.assertEqual(context["initial"], {
+        user = FakeAuthorization('ralph')
+        url = '/ralph/w/halp/%i/config' % self.widget.idx
+        response = self.check_url(url, user)
+        self.assertEqual(response.context["mode"], "edit")
+        self.assertEqual(response.context["initial"], {
             'hubs': ['fedora-devel'],
             'per_page': 3,
             })
-        self.assertEqual(context["url"], "/ralph/%i/edit" % self.widget.idx)
+        self.assertEqual(
+            response.context["url"], "/ralph/%i/edit" % self.widget.idx)
+
+    def test_config_authz(self):
+        urls = [
+            '/ralph/w/halp/add',
+            '/ralph/w/halp/%i/config' % self.widget.idx,
+            ]
+        # Anonymous
+        for url in urls:
+            self.check_url(url, None, 403)
+        # Logged-in
+        user = FakeAuthorization('decause')
+        for url in urls:
+            self.check_url(url, user, 403)
+        # Member
+        hub = Hub.query.get("ralph")
+        hub.subscribe(User.query.get("decause"), "member")
+        for url in urls:
+            self.check_url(url, user, 403)
+        # Owner
+        user = FakeAuthorization('ralph')
+        for url in urls:
+            self.check_url(url, user, 200)
 
     def test_config_hubs_suggest(self):
         response = self.app.get('/w/halp/hubs')
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
index eaac331..6d85ad2 100644
--- a/hubs/tests/test_widgets/test_library.py
+++ b/hubs/tests/test_widgets/test_library.py
@@ -2,8 +2,8 @@ from __future__ import unicode_literals
 
 import json
 
-from hubs.tests import FakeAuthorization, auth_set
-from hubs.tests.test_widgets import WidgetTest
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
 
 
 class TestLibrary(WidgetTest):
@@ -12,9 +12,7 @@ class TestLibrary(WidgetTest):
     def test_data_simple(self):
         widget = self.widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
-        with auth_set(self.app.application, user):
-            response = self.app.get('/ralph/%i/json' % widget.idx)
-        self.assertEqual(response.status_code, 200)
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
         expected_dict = {
             "config": {
@@ -34,3 +32,6 @@ class TestLibrary(WidgetTest):
             "plugin": "library"
         }
         self.assertDictEqual(data['data'], expected_dict['data'])
+
+    def test_view_authz(self):
+        self._test_view_authz()
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
index 8c2784b..49f088b 100644
--- a/hubs/tests/test_widgets/test_meetings.py
+++ b/hubs/tests/test_widgets/test_meetings.py
@@ -2,8 +2,8 @@ from __future__ import unicode_literals
 
 import json
 
-from hubs.tests import FakeAuthorization, auth_set
-from hubs.tests.test_widgets import WidgetTest
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
 
 
 class TestMeetings(WidgetTest):
@@ -13,9 +13,7 @@ class TestMeetings(WidgetTest):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
         user = FakeAuthorization('ralph')
-        with auth_set(self.app.application, user):
-            response = self.app.get('/%s/%i/json' % (team, widget.idx))
-        self.assertEqual(200, response.status_code)
+        response = self.check_url('/%s/%i/json' % (team, widget.idx), user)
         data = json.loads(response.get_data(as_text=True))
         calendar_name = data['data']['calendar']
         self.assertIn(team, calendar_name)
@@ -24,10 +22,11 @@ class TestMeetings(WidgetTest):
         team = 'i18n'
         widget = self.widget_instance(team, self.plugin)
         user = FakeAuthorization('ralph')
-        with auth_set(self.app.application, user):
-            response = self.app.get('/%s/w/%s/%i/'
-                                    % (team, self.plugin, widget.idx))
-        self.assertEqual(200, response.status_code)
+        url = '/%s/w/%s/%i/' % (team, self.plugin, widget.idx)
+        response = self.check_url(url, user)
         self.assertIn('i18n', response.get_data(as_text=True))
         self.assertIn('<strong>Request A New Meeting</strong>',
                       response.get_data(as_text=True))
+
+    def test_view_authz(self):
+        self._test_view_authz()
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_view_authz b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_view_authz
new file mode 100644
index 0000000..cf740f8
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_view_authz
@@ -0,0 +1,2705 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"user_count": 44887, "rank": 5, "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png",
+        "percentile": "0.01", "assertions": [{"description": "You attended Flock 2013,
+        the Fedora Contributor Conference", "tags": "flock,event,", "issued": 1375373082.0,
+        "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "rbergero", "last_awarded": 1473972160.0, "percent_earned": 0.18034465868103486,
+        "id": "flock-2013-attendee", "times_awarded": 81, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198996.0, "percent_earned": 0.663490225764795,
+        "id": "tagger-tagger-ii", "times_awarded": 298, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002037.0, "percent_earned": 1.0508972703388697,
+        "id": "junior-tagger-tagger-i", "times_awarded": 472, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ylarguex", "last_awarded": 1491516838.0, "percent_earned": 53.357527719641986,
+        "id": "involvement", "times_awarded": 23965, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "icole",
+        "last_awarded": 1491505117.0, "percent_earned": 3.9564501046444316, "id":
+        "speak-up!", "times_awarded": 1777, "name": "Speak Up!"}, {"description":
+        "Edited at least 10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0,
+        "image": "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "kdudka",
+        "last_awarded": 1491484751.0, "percent_earned": 3.3129981742886407, "id":
+        "junior-editor", "times_awarded": 1488, "name": "Junior Editor"}, {"description":
+        "Edited at least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0,
+        "image": "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "ankit1997",
+        "last_awarded": 1491242577.0, "percent_earned": 2.108473972480741, "id": "associate-editor",
+        "times_awarded": 947, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "yzhang",
+        "last_awarded": 1491431124.0, "percent_earned": 1.5451752237609653, "id":
+        "secretary-general", "times_awarded": 694, "name": "Secretary General"}, {"description":
+        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
+        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198974.0, "percent_earned": 0.3139332947410607,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 141, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491425650.0, "percent_earned": 0.5454869305784388,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 245, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "nickboldt",
+        "last_awarded": 1490915696.0, "percent_earned": 2.858796811684553, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1284, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "sjenning", "last_awarded": 1491017600.0, "percent_earned": 2.3288952219797836,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 1046, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "tartare",
+        "last_awarded": 1491481451.0, "percent_earned": 1.4138130649686065, "id":
+        "if-you-build-it...-koji-success-iii", "times_awarded": 635, "name": "If you
+        build it... (Koji Success III)"}, {"description": "Ten or more questions and
+        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
+        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedo25", "last_awarded": 1491440137.0, "percent_earned": 1.4182660195039407,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 637, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "andre", "last_awarded": 1491511008.0, "percent_earned": 9.738611568775884,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 4374, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491482061.0, "percent_earned": 1.903638063855368,
+        "id": "riddle-me-this", "times_awarded": 855, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mhonek", "last_awarded": 1490899614.0, "percent_earned": 2.0127354499710557,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 904, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "nickboldt", "last_awarded": 1491244448.0, "percent_earned": 1.94816760920871,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 875, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "jscotka",
+        "last_awarded": 1491289110.0, "percent_earned": 2.6695462439328494, "id":
+        "you-can-call-me-patches-scm-i", "times_awarded": 1199, "name": "You can call
+        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
+        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "berrange",
+        "last_awarded": 1491242273.0, "percent_earned": 0.5588457941844414, "id":
+        "you-can-call-me-patches-scm-iv", "times_awarded": 251, "name": "You can call
+        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
+        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "cydrobolt",
+        "last_awarded": 1490744785.0, "percent_earned": 1.3603776105445964, "id":
+        "you-can-call-me-patches-scm-iii", "times_awarded": 611, "name": "You can
+        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441515.0, "percent_earned": 0.6523578394264594,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 293, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "tkrizek", "last_awarded": 1490376511.0, "percent_earned": 1.329206928797257,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 597, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441872.0, "percent_earned": 0.5299015897047691,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 238, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "toshio", "last_awarded": 1491516269.0, "percent_earned": 2.70739635748319,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 1216, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "apollo7", "last_awarded": 1491362331.0, "percent_earned": 7.547757937391459,
+        "id": "junior-badger-badger-i", "times_awarded": 3390, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "scox", "last_awarded": 1491419635.0, "percent_earned": 2.562675335084829,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 1151, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "alciregi", "last_awarded": 1491294835.0, "percent_earned": 1.6631785189473214,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 747, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "mystro256",
+        "last_awarded": 1491340270.0, "percent_earned": 0.39408647637707617, "id":
+        "like-a-rock-updates-stable-iii", "times_awarded": 177, "name": "Like a Rock
+        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
+        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "landgraf", "last_awarded": 1491498009.0, "percent_earned": 6.412254530881239,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2880, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "cqi",
+        "last_awarded": 1491420777.0, "percent_earned": 1.2379213608229058, "id":
+        "like-a-rock-updates-stable-ii", "times_awarded": 556, "name": "Like a Rock
+        (Updates-Stable II)"}, {"description": "Partied with Flock 2013 (at the South
+        Carolina Aquarium)", "tags": "party,flock,event,", "issued": 1376252202.0,
+        "image": "https://badges.fedoraproject.org/pngs/tanked.png", "first_awarded":
+        1376252202.0, "first_awarded_person": "ralph", "last_awarded_person": "gnokii",
+        "last_awarded": 1411656869.0, "percent_earned": 0.14026806786302712, "id":
+        "tanked!", "times_awarded": 63, "name": "Tanked!"}, {"description": "You proposed
+        a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,", "issued":
+        1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "frantisekz", "last_awarded": 1484316413.0, "percent_earned": 0.3161597720087278,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 142, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491477255.0, "percent_earned": 5.508304760208398,
+        "id": "bona-fide", "times_awarded": 2474, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.05788840895934453,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "mailga", "last_awarded": 1491037049.0, "percent_earned": 0.823796589036826,
+        "id": "senior-badger-badger-ii", "times_awarded": 370, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "olem",
+        "last_awarded": 1491070078.0, "percent_earned": 2.658413857594514, "id": "is-this-thing-on-updates-testing-i",
+        "times_awarded": 1194, "name": "Is this thing on? (Updates-Testing I)"}, {"description":
+        "Pushed 20 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1376077757.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491432891.0, "percent_earned": 1.467248519392617,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 659, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "dustymabe",
+        "last_awarded": 1491406327.0, "percent_earned": 1.714387496103665, "id": "partners-in-crime",
+        "times_awarded": 770, "name": "Partners in Crime"}, {"description": "*(a great
+        struggle, repeated escapes, discipline required)*\nTested and added karma
+        to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "mcepl", "last_awarded": 1491490795.0, "percent_earned": 0.961838179632186,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 432, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "bt0dotninja",
+        "last_awarded": 1489638271.0, "percent_earned": 0.16253284053969808, "id":
+        "master-tagger-tagger-iv", "times_awarded": 73, "name": "Master Tagger (Tagger
+        IV)"}, {"description": "A member of the sysadmin-badges group.  Nothing to
+        see here..  move along.", "tags": "infrastructure,badges,community,", "issued":
+        1378319150.0, "image": "https://badges.fedoraproject.org/pngs/fas-inside-job.png",
+        "first_awarded": 1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "jflory7", "last_awarded": 1472154166.0, "percent_earned": 0.02226477267667097,
+        "id": "inside-job", "times_awarded": 10, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "salvadorhm", "last_awarded": 1491509400.0, "percent_earned": 8.144453845126241,
+        "id": "white-rabbit", "times_awarded": 3658, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jcholast", "last_awarded": 1491423845.0, "percent_earned": 3.061406243042258,
+        "id": "mugshot", "times_awarded": 1375, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.03785011355034065,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jkaluza", "last_awarded": 1490254934.0, "percent_earned": 0.10241795431268647,
+        "id": "maestro", "times_awarded": 46, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "cra", "last_awarded": 1491437628.0, "percent_earned": 4.250345103976488,
+        "id": "let-me-introduce-myself", "times_awarded": 1909, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "ngompa", "last_awarded": 1490659963.0, "percent_earned": 0.7614552255421472,
+        "id": "binary-star", "times_awarded": 342, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "xavierb", "last_awarded": 1484573828.0, "percent_earned": 0.32506568107939615,
+        "id": "packager-sponsor", "times_awarded": 146, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468491.0, "percent_earned": 1.3470187469385937,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 605, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468509.0, "percent_earned": 1.1399563610455536,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 512, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468543.0, "percent_earned": 1.6231019281293138,
+        "id": "bloggin-it!-planet-i", "times_awarded": 729, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "dtimms", "last_awarded": 1491484910.0, "percent_earned": 0.939573406955515,
+        "id": "white-hat", "times_awarded": 422, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.17589170414570066,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "andrespol", "last_awarded": 1491360716.0, "percent_earned": 20.256490181235247,
+        "id": "embryo", "times_awarded": 9098, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "piotrdrag", "last_awarded": 1491478479.0, "percent_earned": 0.549939885113773,
+        "id": "taming-the-bull-tester-v", "times_awarded": 247, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ferdnyc", "last_awarded": 1484744055.0, "percent_earned": 0.1469474996660284,
+        "id": "common-bugs-contributor", "times_awarded": 66, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "metonymy", "last_awarded": 1491502807.0, "percent_earned": 6.249721690341541,
+        "id": "baby-badger", "times_awarded": 2807, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "martinkg", "last_awarded": 1489655875.0, "percent_earned": 0.09351204524201807,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 42, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pwalter", "last_awarded": 1491445231.0, "percent_earned": 0.6167342031437859,
+        "id": "old-yeller", "times_awarded": 277, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.1580798860043639,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "stefw", "last_awarded": 1491468562.0, "percent_earned": 0.7547757937391459,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 339, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "augenauf", "last_awarded": 1491316933.0, "percent_earned": 1.013047156788529,
+        "id": "senior-editor", "times_awarded": 455, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "avichi", "last_awarded": 1491361425.0, "percent_earned": 14.18933962684241,
+        "id": "tadpole", "times_awarded": 6373, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "amogh23k", "last_awarded": 1491362307.0, "percent_earned": 28.41430288996749,
+        "id": "egg", "times_awarded": 12762, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "akopacsi", "last_awarded": 1490757692.0, "percent_earned": 7.30952486975108,
+        "id": "tadpole-with-legs", "times_awarded": 3283, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "lsedlar", "last_awarded": 1476326553.0, "percent_earned": 0.05120897715634323,
+        "id": "badge-off!", "times_awarded": 23, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "sassam", "last_awarded": 1491148875.0, "percent_earned": 0.3072538629380594,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 138, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "metonymy", "last_awarded": 1491476646.0, "percent_earned": 0.4208042035890813,
+        "id": "no-longer-a-ronin", "times_awarded": 189, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bt0dotninja", "last_awarded": 1489643141.0, "percent_earned": 0.13358863606002583,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 60, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002111.0, "percent_earned": 0.8750055661931692,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 393, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "ignacio", "last_awarded": 1485888954.0, "percent_earned": 0.28944204479672264,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 130, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "imabug", "last_awarded": 1490199130.0, "percent_earned": 0.5120897715634324,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 230, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "devconf,speaker,event,", "issued": 1390422108.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.10241795431268647, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "terjeros", "last_awarded": 1491331717.0, "percent_earned": 0.26717727212005166,
+        "id": "patches-scm-v", "times_awarded": 120, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "decathorpe", "last_awarded": 1491331634.0, "percent_earned": 0.7480963619361446,
+        "id": "override,-you-say", "times_awarded": 336, "name": "Override, you say?"},
+        {"description": "You attended the 2014 iteration of devconf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event,devconf,", "issued":
+        1391763090.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png",
+        "first_awarded": 1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.13804159059536003,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf 2014 Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "swilson", "last_awarded": 1458943142.0, "percent_earned":
+        0.03562363628267355, "id": "videographer", "times_awarded": 16, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "zbyszek", "last_awarded": 1490388487.0, "percent_earned": 0.15585340873669679,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 70,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491441908.0, "percent_earned": 3.958676581912099,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1778, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491503467.0, "percent_earned": 2.046132608986062,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 919, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "caiqian",
+        "last_awarded": 1481903131.0, "percent_earned": 1.6765373825533243, "id":
+        "it-still-works!", "times_awarded": 753, "name": "It still works!"}, {"description":
+        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
+        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491442200.0, "percent_earned": 2.1641359041724186,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 972, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "stefw", "last_awarded": 1491468526.0, "percent_earned": 0.35623636282673554,
+        "id": "bob-loblaw-planet-v", "times_awarded": 160, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "dfateyev", "last_awarded": 1490465620.0, "percent_earned": 0.06902079529768002,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 31, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "ignatenkobrain", "last_awarded": 1485808919.0, "percent_earned": 0.14472102239836132,
+        "id": "lets-do-lunch!", "times_awarded": 65, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "mythcat", "last_awarded":
+        1484694397.0, "percent_earned": 0.4208042035890813, "id": "vacation", "times_awarded":
+        189, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "python,event,pycon,", "issued": 1397168025.0, "image":
+        "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png", "first_awarded":
+        1397168025.0, "first_awarded_person": "ralph", "last_awarded_person": "abompard",
+        "last_awarded": 1397573900.0, "percent_earned": 0.02226477267667097, "id":
+        "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 0.6345460212851227,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "nickboldt", "last_awarded": 1490915668.0, "percent_earned": 0.984102952308857,
+        "id": "helping-hand", "times_awarded": 442, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.20483590862537293,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "wtaymans",
+        "last_awarded": 1490906731.0, "percent_earned": 0.20038295409003873, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 90, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "payasr", "last_awarded": 1491512765.0, "percent_earned": 61.86712383666563,
+        "id": "paranoid-panda", "times_awarded": 27787, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.16253284053969808, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jvymazal", "last_awarded": 1491284602.0, "percent_earned": 1.099879770227546,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 494, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "athoscr",
+        "last_awarded": 1490991464.0, "percent_earned": 0.5900164759317807, "id":
+        "master-editor", "times_awarded": 265, "name": "Master Editor"}, {"description":
+        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "terjeros", "last_awarded": 1491384354.0, "percent_earned": 0.389633521841742,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 175, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405296000.0, "first_awarded_person": "marinaz", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.27163022665538583,
+        "id": "flock-2014-attendee", "times_awarded": 122, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "pperron", "last_awarded": 1490999828.0, "percent_earned": 0.49873090795742975,
+        "id": "science-kernel-tester-i", "times_awarded": 224, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.19815647682237164, "id":
+        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
+        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
+        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1485788654.0, "percent_earned": 0.03339715901500646,
+        "id": "corporate-overlord", "times_awarded": 15, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "kdudka", "last_awarded": 1491214689.0, "percent_earned": 0.18925056775170326,
+        "id": "corporate-shill", "times_awarded": 85, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "dsommers", "last_awarded": 1490298016.0, "percent_earned": 1.3024892015852518,
+        "id": "corporate-drone", "times_awarded": 585, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vondruch", "last_awarded": 1491296529.0, "percent_earned": 0.14026806786302712,
+        "id": "master-badger-badger-iii", "times_awarded": 63, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "fale", "last_awarded":
+        1490321832.0, "percent_earned": 0.2248742040343768, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 101, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "rbergero", "last_awarded": 1455959914.0, "percent_earned": 0.0712472725653471,
+        "id": "dancing-with-toshio", "times_awarded": 32, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.2449124994433807, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "keitellf",
+        "last_awarded": 1465418173.0, "percent_earned": 0.8972703388698402, "id":
+        "consolation-prize", "times_awarded": 403, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "usuha", "last_awarded": 1491448085.0, "percent_earned": 6.430066349022577,
+        "id": "crypto-panda", "times_awarded": 2888, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491505320.0, "percent_earned": 2.3711982900654585,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 1065, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1490811747.0, "percent_earned": 0.03562363628267355,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 16, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "sailer", "last_awarded": 1490344262.0, "percent_earned": 0.7525493164714788,
+        "id": "the-cat-came-back...", "times_awarded": 338, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "michalrud", "last_awarded": 1470317213.0, "percent_earned": 0.04675602262100904,
+        "id": "apprentice-badge-artist-i", "times_awarded": 21, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "kkeithle", "last_awarded": 1491364811.0, "percent_earned": 0.20706238589304005,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 93, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.04007659081800775,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.13804159059536003,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "orion", "last_awarded": 1490756246.0, "percent_earned": 0.024491249944338066,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 11, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "pcreech17", "last_awarded": 1491432940.0, "percent_earned": 2.3756512446007925,
+        "id": "associate-badger-badger-1.5", "times_awarded": 1067, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "kellin", "last_awarded": 1461547496.0, "percent_earned": 0.18479761321636906,
+        "id": "flock-2015-attendee", "times_awarded": 83, "name": "Flock 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "gtierney", "last_awarded": 1491405719.0, "percent_earned": 1.852429086699025,
+        "id": "macaron-cookie-i", "times_awarded": 832, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "mizdebsk",
+        "last_awarded": 1491500198.0, "percent_earned": 0.3606893173620697, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 162, "name": "Chocolate Chip
+        (Cookie II)"}, {"description": "Voted in the supplemental wallpapers election
+        for the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.18257113594870197,
+        "id": "nuancier-f22", "times_awarded": 82, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "schwankek", "last_awarded": 1491486520.0, "percent_earned": 17.635926437191078,
+        "id": "origin", "times_awarded": 7921, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "nmilosev", "last_awarded": 1491213323.0, "percent_earned": 0.919535111546511,
+        "id": "delivery", "times_awarded": 413, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dustymabe", "last_awarded": 1475240820.0, "percent_earned": 0.5655252259874427,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 254,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dmsimard", "last_awarded": 1491321510.0, "percent_earned": 0.14472102239836132,
+        "id": "black-and-white-cookie-iii", "times_awarded": 65, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "smani", "last_awarded": 1485976444.0, "percent_earned": 0.08460613617134968,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 38, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509860.0, "percent_earned": 0.006679431803001291,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 3, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "pravins", "last_awarded": 1472553692.0, "percent_earned": 0.03562363628267355,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 16, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "frantisekz", "last_awarded": 1485462295.0, "percent_earned": 0.10019147704501936,
+        "id": "badge-muse-badges-released-i", "times_awarded": 45, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509873.0, "percent_earned": 0.013358863606002582,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 6, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.002226477267667097,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "kellin", "last_awarded": 1461547520.0, "percent_earned": 0.16921227234269937,
+        "id": "nom-nom-nom", "times_awarded": 76, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "rluzynski", "last_awarded": 1491442095.0, "percent_earned": 1.5763459055083047,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 708, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491326903.0, "percent_earned": 0.12468272698935744,
+        "id": "rock-the-web!", "times_awarded": 56, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and and you''ve ported at least one package to Python
+        3", "tags": "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "crobinso", "last_awarded": 1491217608.0, "percent_earned": 0.33842454468539873,
+        "id": "parselmouth", "times_awarded": 152, "name": "Parselmouth I"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "jonatoni",
+        "last_awarded": 1490211890.0, "percent_earned": 0.22710068130204392, "id":
+        "chief-editor", "times_awarded": 102, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "apahim", "last_awarded": 1491360865.0, "percent_earned": 4.628846239479895,
+        "id": "froglet", "times_awarded": 2079, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ryanlerch", "last_awarded": 1490719235.0, "percent_earned": 0.03117068174733936,
+        "id": "pizzelle-cookie-iv", "times_awarded": 14, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "churchyard", "last_awarded": 1475564266.0, "percent_earned": 0.011132386338335486,
+        "id": "silver", "times_awarded": 5, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1489622707.0, "percent_earned": 0.03117068174733936,
+        "id": "top-10", "times_awarded": 14, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "tflink", "last_awarded": 1480461776.0, "percent_earned": 0.25159193124638196,
+        "id": "top-100", "times_awarded": 113, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mrunge", "last_awarded": 1490730635.0, "percent_earned": 0.06679431803001291,
+        "id": "top-25", "times_awarded": 30, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "zsun", "last_awarded": 1490677027.0, "percent_earned": 1.2000712472725654,
+        "id": "top-500", "times_awarded": 539, "name": "Top 500"}, {"description":
+        "You visited the Fedora table at BrickHack 2016!", "tags": "brickhack,event,hackathon,events,",
+        "issued": 1457234130.0, "image": "http://infrastructure.fedoraproject.org/infra/badges/pngs/events-brickhack-2016.png",
+        "first_awarded": 1455845197.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "brandondgr8", "last_awarded": 1461299769.0, "percent_earned": 0.05566193169167742,
+        "id": "brickhack-2016-attendee", "times_awarded": 25, "name": "BrickHack 2016
+        Attendee"}, {"description": "You gave a presentation at DevConf.cz, 2016",
+        "tags": "devconf,speaker,event,", "issued": 1455008224.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2016.png",
+        "first_awarded": 1454667336.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "thozza", "last_awarded": 1459500320.0, "percent_earned": 0.2137418176960413,
+        "id": "devconf-2016-speaker", "times_awarded": 96, "name": "DevConf 2016 Speaker"},
+        {"description": "You attended the 2016 iteration of DevConf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event, devconf,", "issued":
+        1455120228.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee-2016.png",
+        "first_awarded": 1454600601.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "dkaspar", "last_awarded": 1461940547.0, "percent_earned": 0.18925056775170326,
+        "id": "devconf-2016-attendee", "times_awarded": 85, "name": "DevConf 2016
+        Attendee"}, {"description": "You got a \"Change\" accepted into the Fedora
+        24 Change list", "tags": "development,FESCo,process,", "issued": 1458652673.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f24.png", "first_awarded":
+        1458651465.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "pnemade", "last_awarded": 1459240914.0, "percent_earned": 0.10019147704501936,
+        "id": "fedora-24-change-accepted", "times_awarded": 45, "name": "Fedora 24
+        Change Accepted"}, {"description": "You held third place on the Fedora Badges
+        leaderboard", "tags": "meta,community,", "issued": 1462904993.0, "image":
+        "https://badges.fedoraproject.org/pngs/3_badge_340.png", "first_awarded":
+        1452875229.0, "first_awarded_person": "pnemade", "last_awarded_person": "kevin",
+        "last_awarded": 1489692901.0, "percent_earned": 0.011132386338335486, "id":
+        "bronze", "times_awarded": 5, "name": "Bronze"}, {"description": "You burned
+        a yubikey and linked it with your Fedora Account", "tags": "account,community,",
+        "issued": 1462904755.0, "image": "https://badges.fedoraproject.org/pngs/yubi-badge.png",
+        "first_awarded": 1422906928.0, "first_awarded_person": "plautrba", "last_awarded_person":
+        "findarato", "last_awarded": 1491408410.0, "percent_earned": 0.4052188627154117,
+        "id": "horcrux", "times_awarded": 182, "name": "Horcrux"}, {"description":
+        "You hacked with the Fedora crew at PyCon US 2016", "tags": "event, python,pycon,",
+        "issued": 1464988862.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2016_attendee.png",
+        "first_awarded": 1464988862.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "maxamillion", "last_awarded": 1464991242.0, "percent_earned": 0.028944204479672265,
+        "id": "pycon-2016-attendee", "times_awarded": 13, "name": "PyCon 2016 Attendee"},
+        {"description": "You got 150 Fedora Badges!  Wow!", "tags": "badges,community,",
+        "issued": 1468058613.0, "image": "https://badges.fedoraproject.org/pngs/badger-04.png",
+        "first_awarded": 1457979017.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1490919191.0, "percent_earned": 0.020038295409003874,
+        "id": "badge-junkie-badger-iv", "times_awarded": 9, "name": "Badge Junkie
+        (Badger IV)"}, {"description": "You can speak Python and and you''ve ported
+        at least five packages to Python 3", "tags": "python,miscellaneous,", "issued":
+        1468058067.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-II.png",
+        "first_awarded": 1467988651.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1488193805.0, "percent_earned": 0.028944204479672265,
+        "id": "parselmouth-ii", "times_awarded": 13, "name": "Parselmouth II"}, {"description":
+        "You can speak Python and and you''ve ported at least ten packages to Python
+        3", "tags": "python,miscellaneous,", "issued": 1468058072.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-III.png",
+        "first_awarded": 1467997850.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1489753361.0, "percent_earned": 0.02226477267667097,
+        "id": "parselmouth-iii", "times_awarded": 10, "name": "Parselmouth III"},
+        {"description": "You attended Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,event,events,", "issued": 1470404480.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-attendee.png",
+        "first_awarded": 1468984748.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "adrian", "last_awarded": 1486483875.0, "percent_earned": 0.2360065903727123,
+        "id": "flock-2016-attendee", "times_awarded": 106, "name": "Flock 2016 Attendee"},
+        {"description": "You attended the party at Flock 2016 in Krakow!", "tags":
+        "flock,krakow,event,events,", "issued": 1470404592.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/krakow-brews.png",
+        "first_awarded": 1468963417.0, "first_awarded_person": "duffy", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217490.0, "percent_earned": 0.18257113594870197,
+        "id": "krakow-brews!", "times_awarded": 82, "name": "Krakow Brews!"}, {"description":
+        "You gave a presentation at Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,speaker,event,", "issued": 1471354751.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-speaker.png",
+        "first_awarded": 1470941077.0, "first_awarded_person": "mattdm", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217546.0, "percent_earned": 0.19592999955470453,
+        "id": "flock-2016-speaker", "times_awarded": 88, "name": "Flock 2016 Speaker"},
+        {"description": "You''re a member of the Modularity Working Group!", "tags":
+        "modularity,community,", "issued": 1475082397.0, "image": "https://badges.fedoraproject.org/pngs/fas-modularity-wg.png",
+        "first_awarded": 1475082098.0, "first_awarded_person": "asamalik", "last_awarded_person":
+        "jscotka", "last_awarded": 1491213584.0, "percent_earned": 0.0801531816360155,
+        "id": "modularity-wg-member", "times_awarded": 36, "name": "Modularity WG
+        Member"}, {"description": "You got a \"Change\" accepted into the Fedora 26
+        Change list", "tags": "development, FESCo, process,", "issued": 1479749896.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f26.png", "first_awarded":
+        1473331018.0, "first_awarded_person": "cstratak", "last_awarded_person": "ncoghlan",
+        "last_awarded": 1489656918.0, "percent_earned": 0.11577681791868906, "id":
+        "fedora-26-change-accepted", "times_awarded": 52, "name": "Fedora 26 Change
+        Accepted"}, {"description": "You gave a presentation at DevConf.cz, 2017",
+        "tags": "speaker,devconf,event,", "issued": 1486037155.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2017.png",
+        "first_awarded": 1486033923.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "siddharths", "last_awarded": 1486077040.0, "percent_earned": 0.24713897671104776,
+        "id": "devconf-2017-speaker", "times_awarded": 111, "name": "DevConf 2017
+        Speaker"}, {"description": "You have helped so many Fedorans you''ve got over
+        100 cookies. Don''t eat them all at once!", "tags": "cookie,community,", "issued":
+        1486153659.0, "image": "https://badges.fedoraproject.org/pngs/rainbowcookie.png",
+        "first_awarded": 1468278719.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ralph", "last_awarded": 1486153659.0, "percent_earned": 0.011132386338335486,
+        "id": "rainbow-cookie-v", "times_awarded": 5, "name": "Rainbow (Cookie V)"}],
+        "percent_earned": 41.81818181818181, "user": "ralph"}'}
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=74663696]
+      connection: [Keep-Alive]
+      content-length: ['74203']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 06 Apr 2017 22:31:35 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"user_count": 44887, "rank": 5, "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png",
+        "percentile": "0.01", "assertions": [{"description": "You attended Flock 2013,
+        the Fedora Contributor Conference", "tags": "flock,event,", "issued": 1375373082.0,
+        "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "rbergero", "last_awarded": 1473972160.0, "percent_earned": 0.18034465868103486,
+        "id": "flock-2013-attendee", "times_awarded": 81, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198996.0, "percent_earned": 0.663490225764795,
+        "id": "tagger-tagger-ii", "times_awarded": 298, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002037.0, "percent_earned": 1.0508972703388697,
+        "id": "junior-tagger-tagger-i", "times_awarded": 472, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ylarguex", "last_awarded": 1491516838.0, "percent_earned": 53.357527719641986,
+        "id": "involvement", "times_awarded": 23965, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "icole",
+        "last_awarded": 1491505117.0, "percent_earned": 3.9564501046444316, "id":
+        "speak-up!", "times_awarded": 1777, "name": "Speak Up!"}, {"description":
+        "Edited at least 10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0,
+        "image": "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "kdudka",
+        "last_awarded": 1491484751.0, "percent_earned": 3.3129981742886407, "id":
+        "junior-editor", "times_awarded": 1488, "name": "Junior Editor"}, {"description":
+        "Edited at least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0,
+        "image": "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "ankit1997",
+        "last_awarded": 1491242577.0, "percent_earned": 2.108473972480741, "id": "associate-editor",
+        "times_awarded": 947, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "yzhang",
+        "last_awarded": 1491431124.0, "percent_earned": 1.5451752237609653, "id":
+        "secretary-general", "times_awarded": 694, "name": "Secretary General"}, {"description":
+        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
+        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198974.0, "percent_earned": 0.3139332947410607,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 141, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491425650.0, "percent_earned": 0.5454869305784388,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 245, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "nickboldt",
+        "last_awarded": 1490915696.0, "percent_earned": 2.858796811684553, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1284, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "sjenning", "last_awarded": 1491017600.0, "percent_earned": 2.3288952219797836,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 1046, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "tartare",
+        "last_awarded": 1491481451.0, "percent_earned": 1.4138130649686065, "id":
+        "if-you-build-it...-koji-success-iii", "times_awarded": 635, "name": "If you
+        build it... (Koji Success III)"}, {"description": "Ten or more questions and
+        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
+        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedo25", "last_awarded": 1491440137.0, "percent_earned": 1.4182660195039407,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 637, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "andre", "last_awarded": 1491511008.0, "percent_earned": 9.738611568775884,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 4374, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491482061.0, "percent_earned": 1.903638063855368,
+        "id": "riddle-me-this", "times_awarded": 855, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mhonek", "last_awarded": 1490899614.0, "percent_earned": 2.0127354499710557,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 904, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "nickboldt", "last_awarded": 1491244448.0, "percent_earned": 1.94816760920871,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 875, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "jscotka",
+        "last_awarded": 1491289110.0, "percent_earned": 2.6695462439328494, "id":
+        "you-can-call-me-patches-scm-i", "times_awarded": 1199, "name": "You can call
+        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
+        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "berrange",
+        "last_awarded": 1491242273.0, "percent_earned": 0.5588457941844414, "id":
+        "you-can-call-me-patches-scm-iv", "times_awarded": 251, "name": "You can call
+        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
+        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "cydrobolt",
+        "last_awarded": 1490744785.0, "percent_earned": 1.3603776105445964, "id":
+        "you-can-call-me-patches-scm-iii", "times_awarded": 611, "name": "You can
+        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441515.0, "percent_earned": 0.6523578394264594,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 293, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "tkrizek", "last_awarded": 1490376511.0, "percent_earned": 1.329206928797257,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 597, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441872.0, "percent_earned": 0.5299015897047691,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 238, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "toshio", "last_awarded": 1491516269.0, "percent_earned": 2.70739635748319,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 1216, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "apollo7", "last_awarded": 1491362331.0, "percent_earned": 7.547757937391459,
+        "id": "junior-badger-badger-i", "times_awarded": 3390, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "scox", "last_awarded": 1491419635.0, "percent_earned": 2.562675335084829,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 1151, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "alciregi", "last_awarded": 1491294835.0, "percent_earned": 1.6631785189473214,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 747, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "mystro256",
+        "last_awarded": 1491340270.0, "percent_earned": 0.39408647637707617, "id":
+        "like-a-rock-updates-stable-iii", "times_awarded": 177, "name": "Like a Rock
+        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
+        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "landgraf", "last_awarded": 1491498009.0, "percent_earned": 6.412254530881239,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2880, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "cqi",
+        "last_awarded": 1491420777.0, "percent_earned": 1.2379213608229058, "id":
+        "like-a-rock-updates-stable-ii", "times_awarded": 556, "name": "Like a Rock
+        (Updates-Stable II)"}, {"description": "Partied with Flock 2013 (at the South
+        Carolina Aquarium)", "tags": "party,flock,event,", "issued": 1376252202.0,
+        "image": "https://badges.fedoraproject.org/pngs/tanked.png", "first_awarded":
+        1376252202.0, "first_awarded_person": "ralph", "last_awarded_person": "gnokii",
+        "last_awarded": 1411656869.0, "percent_earned": 0.14026806786302712, "id":
+        "tanked!", "times_awarded": 63, "name": "Tanked!"}, {"description": "You proposed
+        a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,", "issued":
+        1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "frantisekz", "last_awarded": 1484316413.0, "percent_earned": 0.3161597720087278,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 142, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491477255.0, "percent_earned": 5.508304760208398,
+        "id": "bona-fide", "times_awarded": 2474, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.05788840895934453,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "mailga", "last_awarded": 1491037049.0, "percent_earned": 0.823796589036826,
+        "id": "senior-badger-badger-ii", "times_awarded": 370, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "olem",
+        "last_awarded": 1491070078.0, "percent_earned": 2.658413857594514, "id": "is-this-thing-on-updates-testing-i",
+        "times_awarded": 1194, "name": "Is this thing on? (Updates-Testing I)"}, {"description":
+        "Pushed 20 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1376077757.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491432891.0, "percent_earned": 1.467248519392617,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 659, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "dustymabe",
+        "last_awarded": 1491406327.0, "percent_earned": 1.714387496103665, "id": "partners-in-crime",
+        "times_awarded": 770, "name": "Partners in Crime"}, {"description": "*(a great
+        struggle, repeated escapes, discipline required)*\nTested and added karma
+        to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "mcepl", "last_awarded": 1491490795.0, "percent_earned": 0.961838179632186,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 432, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "bt0dotninja",
+        "last_awarded": 1489638271.0, "percent_earned": 0.16253284053969808, "id":
+        "master-tagger-tagger-iv", "times_awarded": 73, "name": "Master Tagger (Tagger
+        IV)"}, {"description": "A member of the sysadmin-badges group.  Nothing to
+        see here..  move along.", "tags": "infrastructure,badges,community,", "issued":
+        1378319150.0, "image": "https://badges.fedoraproject.org/pngs/fas-inside-job.png",
+        "first_awarded": 1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "jflory7", "last_awarded": 1472154166.0, "percent_earned": 0.02226477267667097,
+        "id": "inside-job", "times_awarded": 10, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "salvadorhm", "last_awarded": 1491509400.0, "percent_earned": 8.144453845126241,
+        "id": "white-rabbit", "times_awarded": 3658, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jcholast", "last_awarded": 1491423845.0, "percent_earned": 3.061406243042258,
+        "id": "mugshot", "times_awarded": 1375, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.03785011355034065,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jkaluza", "last_awarded": 1490254934.0, "percent_earned": 0.10241795431268647,
+        "id": "maestro", "times_awarded": 46, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "cra", "last_awarded": 1491437628.0, "percent_earned": 4.250345103976488,
+        "id": "let-me-introduce-myself", "times_awarded": 1909, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "ngompa", "last_awarded": 1490659963.0, "percent_earned": 0.7614552255421472,
+        "id": "binary-star", "times_awarded": 342, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "xavierb", "last_awarded": 1484573828.0, "percent_earned": 0.32506568107939615,
+        "id": "packager-sponsor", "times_awarded": 146, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468491.0, "percent_earned": 1.3470187469385937,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 605, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468509.0, "percent_earned": 1.1399563610455536,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 512, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468543.0, "percent_earned": 1.6231019281293138,
+        "id": "bloggin-it!-planet-i", "times_awarded": 729, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "dtimms", "last_awarded": 1491484910.0, "percent_earned": 0.939573406955515,
+        "id": "white-hat", "times_awarded": 422, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.17589170414570066,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "andrespol", "last_awarded": 1491360716.0, "percent_earned": 20.256490181235247,
+        "id": "embryo", "times_awarded": 9098, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "piotrdrag", "last_awarded": 1491478479.0, "percent_earned": 0.549939885113773,
+        "id": "taming-the-bull-tester-v", "times_awarded": 247, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ferdnyc", "last_awarded": 1484744055.0, "percent_earned": 0.1469474996660284,
+        "id": "common-bugs-contributor", "times_awarded": 66, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "metonymy", "last_awarded": 1491502807.0, "percent_earned": 6.249721690341541,
+        "id": "baby-badger", "times_awarded": 2807, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "martinkg", "last_awarded": 1489655875.0, "percent_earned": 0.09351204524201807,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 42, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pwalter", "last_awarded": 1491445231.0, "percent_earned": 0.6167342031437859,
+        "id": "old-yeller", "times_awarded": 277, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.1580798860043639,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "stefw", "last_awarded": 1491468562.0, "percent_earned": 0.7547757937391459,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 339, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "augenauf", "last_awarded": 1491316933.0, "percent_earned": 1.013047156788529,
+        "id": "senior-editor", "times_awarded": 455, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "avichi", "last_awarded": 1491361425.0, "percent_earned": 14.18933962684241,
+        "id": "tadpole", "times_awarded": 6373, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "amogh23k", "last_awarded": 1491362307.0, "percent_earned": 28.41430288996749,
+        "id": "egg", "times_awarded": 12762, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "akopacsi", "last_awarded": 1490757692.0, "percent_earned": 7.30952486975108,
+        "id": "tadpole-with-legs", "times_awarded": 3283, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "lsedlar", "last_awarded": 1476326553.0, "percent_earned": 0.05120897715634323,
+        "id": "badge-off!", "times_awarded": 23, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "sassam", "last_awarded": 1491148875.0, "percent_earned": 0.3072538629380594,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 138, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "metonymy", "last_awarded": 1491476646.0, "percent_earned": 0.4208042035890813,
+        "id": "no-longer-a-ronin", "times_awarded": 189, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bt0dotninja", "last_awarded": 1489643141.0, "percent_earned": 0.13358863606002583,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 60, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002111.0, "percent_earned": 0.8750055661931692,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 393, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "ignacio", "last_awarded": 1485888954.0, "percent_earned": 0.28944204479672264,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 130, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "imabug", "last_awarded": 1490199130.0, "percent_earned": 0.5120897715634324,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 230, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "devconf,speaker,event,", "issued": 1390422108.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.10241795431268647, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "terjeros", "last_awarded": 1491331717.0, "percent_earned": 0.26717727212005166,
+        "id": "patches-scm-v", "times_awarded": 120, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "decathorpe", "last_awarded": 1491331634.0, "percent_earned": 0.7480963619361446,
+        "id": "override,-you-say", "times_awarded": 336, "name": "Override, you say?"},
+        {"description": "You attended the 2014 iteration of devconf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event,devconf,", "issued":
+        1391763090.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png",
+        "first_awarded": 1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.13804159059536003,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf 2014 Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "swilson", "last_awarded": 1458943142.0, "percent_earned":
+        0.03562363628267355, "id": "videographer", "times_awarded": 16, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "zbyszek", "last_awarded": 1490388487.0, "percent_earned": 0.15585340873669679,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 70,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491441908.0, "percent_earned": 3.958676581912099,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1778, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491503467.0, "percent_earned": 2.046132608986062,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 919, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "caiqian",
+        "last_awarded": 1481903131.0, "percent_earned": 1.6765373825533243, "id":
+        "it-still-works!", "times_awarded": 753, "name": "It still works!"}, {"description":
+        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
+        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491442200.0, "percent_earned": 2.1641359041724186,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 972, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "stefw", "last_awarded": 1491468526.0, "percent_earned": 0.35623636282673554,
+        "id": "bob-loblaw-planet-v", "times_awarded": 160, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "dfateyev", "last_awarded": 1490465620.0, "percent_earned": 0.06902079529768002,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 31, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "ignatenkobrain", "last_awarded": 1485808919.0, "percent_earned": 0.14472102239836132,
+        "id": "lets-do-lunch!", "times_awarded": 65, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "mythcat", "last_awarded":
+        1484694397.0, "percent_earned": 0.4208042035890813, "id": "vacation", "times_awarded":
+        189, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "python,event,pycon,", "issued": 1397168025.0, "image":
+        "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png", "first_awarded":
+        1397168025.0, "first_awarded_person": "ralph", "last_awarded_person": "abompard",
+        "last_awarded": 1397573900.0, "percent_earned": 0.02226477267667097, "id":
+        "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 0.6345460212851227,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "nickboldt", "last_awarded": 1490915668.0, "percent_earned": 0.984102952308857,
+        "id": "helping-hand", "times_awarded": 442, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.20483590862537293,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "wtaymans",
+        "last_awarded": 1490906731.0, "percent_earned": 0.20038295409003873, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 90, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "payasr", "last_awarded": 1491512765.0, "percent_earned": 61.86712383666563,
+        "id": "paranoid-panda", "times_awarded": 27787, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.16253284053969808, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jvymazal", "last_awarded": 1491284602.0, "percent_earned": 1.099879770227546,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 494, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "athoscr",
+        "last_awarded": 1490991464.0, "percent_earned": 0.5900164759317807, "id":
+        "master-editor", "times_awarded": 265, "name": "Master Editor"}, {"description":
+        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "terjeros", "last_awarded": 1491384354.0, "percent_earned": 0.389633521841742,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 175, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405296000.0, "first_awarded_person": "marinaz", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.27163022665538583,
+        "id": "flock-2014-attendee", "times_awarded": 122, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "pperron", "last_awarded": 1490999828.0, "percent_earned": 0.49873090795742975,
+        "id": "science-kernel-tester-i", "times_awarded": 224, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.19815647682237164, "id":
+        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
+        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
+        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1485788654.0, "percent_earned": 0.03339715901500646,
+        "id": "corporate-overlord", "times_awarded": 15, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "kdudka", "last_awarded": 1491214689.0, "percent_earned": 0.18925056775170326,
+        "id": "corporate-shill", "times_awarded": 85, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "dsommers", "last_awarded": 1490298016.0, "percent_earned": 1.3024892015852518,
+        "id": "corporate-drone", "times_awarded": 585, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vondruch", "last_awarded": 1491296529.0, "percent_earned": 0.14026806786302712,
+        "id": "master-badger-badger-iii", "times_awarded": 63, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "fale", "last_awarded":
+        1490321832.0, "percent_earned": 0.2248742040343768, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 101, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "rbergero", "last_awarded": 1455959914.0, "percent_earned": 0.0712472725653471,
+        "id": "dancing-with-toshio", "times_awarded": 32, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.2449124994433807, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "keitellf",
+        "last_awarded": 1465418173.0, "percent_earned": 0.8972703388698402, "id":
+        "consolation-prize", "times_awarded": 403, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "usuha", "last_awarded": 1491448085.0, "percent_earned": 6.430066349022577,
+        "id": "crypto-panda", "times_awarded": 2888, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491505320.0, "percent_earned": 2.3711982900654585,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 1065, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1490811747.0, "percent_earned": 0.03562363628267355,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 16, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "sailer", "last_awarded": 1490344262.0, "percent_earned": 0.7525493164714788,
+        "id": "the-cat-came-back...", "times_awarded": 338, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "michalrud", "last_awarded": 1470317213.0, "percent_earned": 0.04675602262100904,
+        "id": "apprentice-badge-artist-i", "times_awarded": 21, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "kkeithle", "last_awarded": 1491364811.0, "percent_earned": 0.20706238589304005,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 93, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.04007659081800775,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.13804159059536003,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "orion", "last_awarded": 1490756246.0, "percent_earned": 0.024491249944338066,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 11, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "pcreech17", "last_awarded": 1491432940.0, "percent_earned": 2.3756512446007925,
+        "id": "associate-badger-badger-1.5", "times_awarded": 1067, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "kellin", "last_awarded": 1461547496.0, "percent_earned": 0.18479761321636906,
+        "id": "flock-2015-attendee", "times_awarded": 83, "name": "Flock 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "gtierney", "last_awarded": 1491405719.0, "percent_earned": 1.852429086699025,
+        "id": "macaron-cookie-i", "times_awarded": 832, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "mizdebsk",
+        "last_awarded": 1491500198.0, "percent_earned": 0.3606893173620697, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 162, "name": "Chocolate Chip
+        (Cookie II)"}, {"description": "Voted in the supplemental wallpapers election
+        for the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.18257113594870197,
+        "id": "nuancier-f22", "times_awarded": 82, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "schwankek", "last_awarded": 1491486520.0, "percent_earned": 17.635926437191078,
+        "id": "origin", "times_awarded": 7921, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "nmilosev", "last_awarded": 1491213323.0, "percent_earned": 0.919535111546511,
+        "id": "delivery", "times_awarded": 413, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dustymabe", "last_awarded": 1475240820.0, "percent_earned": 0.5655252259874427,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 254,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dmsimard", "last_awarded": 1491321510.0, "percent_earned": 0.14472102239836132,
+        "id": "black-and-white-cookie-iii", "times_awarded": 65, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "smani", "last_awarded": 1485976444.0, "percent_earned": 0.08460613617134968,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 38, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509860.0, "percent_earned": 0.006679431803001291,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 3, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "pravins", "last_awarded": 1472553692.0, "percent_earned": 0.03562363628267355,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 16, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "frantisekz", "last_awarded": 1485462295.0, "percent_earned": 0.10019147704501936,
+        "id": "badge-muse-badges-released-i", "times_awarded": 45, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509873.0, "percent_earned": 0.013358863606002582,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 6, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.002226477267667097,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "kellin", "last_awarded": 1461547520.0, "percent_earned": 0.16921227234269937,
+        "id": "nom-nom-nom", "times_awarded": 76, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "rluzynski", "last_awarded": 1491442095.0, "percent_earned": 1.5763459055083047,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 708, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491326903.0, "percent_earned": 0.12468272698935744,
+        "id": "rock-the-web!", "times_awarded": 56, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and and you''ve ported at least one package to Python
+        3", "tags": "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "crobinso", "last_awarded": 1491217608.0, "percent_earned": 0.33842454468539873,
+        "id": "parselmouth", "times_awarded": 152, "name": "Parselmouth I"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "jonatoni",
+        "last_awarded": 1490211890.0, "percent_earned": 0.22710068130204392, "id":
+        "chief-editor", "times_awarded": 102, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "apahim", "last_awarded": 1491360865.0, "percent_earned": 4.628846239479895,
+        "id": "froglet", "times_awarded": 2079, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ryanlerch", "last_awarded": 1490719235.0, "percent_earned": 0.03117068174733936,
+        "id": "pizzelle-cookie-iv", "times_awarded": 14, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "churchyard", "last_awarded": 1475564266.0, "percent_earned": 0.011132386338335486,
+        "id": "silver", "times_awarded": 5, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1489622707.0, "percent_earned": 0.03117068174733936,
+        "id": "top-10", "times_awarded": 14, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "tflink", "last_awarded": 1480461776.0, "percent_earned": 0.25159193124638196,
+        "id": "top-100", "times_awarded": 113, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mrunge", "last_awarded": 1490730635.0, "percent_earned": 0.06679431803001291,
+        "id": "top-25", "times_awarded": 30, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "zsun", "last_awarded": 1490677027.0, "percent_earned": 1.2000712472725654,
+        "id": "top-500", "times_awarded": 539, "name": "Top 500"}, {"description":
+        "You visited the Fedora table at BrickHack 2016!", "tags": "brickhack,event,hackathon,events,",
+        "issued": 1457234130.0, "image": "http://infrastructure.fedoraproject.org/infra/badges/pngs/events-brickhack-2016.png",
+        "first_awarded": 1455845197.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "brandondgr8", "last_awarded": 1461299769.0, "percent_earned": 0.05566193169167742,
+        "id": "brickhack-2016-attendee", "times_awarded": 25, "name": "BrickHack 2016
+        Attendee"}, {"description": "You gave a presentation at DevConf.cz, 2016",
+        "tags": "devconf,speaker,event,", "issued": 1455008224.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2016.png",
+        "first_awarded": 1454667336.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "thozza", "last_awarded": 1459500320.0, "percent_earned": 0.2137418176960413,
+        "id": "devconf-2016-speaker", "times_awarded": 96, "name": "DevConf 2016 Speaker"},
+        {"description": "You attended the 2016 iteration of DevConf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event, devconf,", "issued":
+        1455120228.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee-2016.png",
+        "first_awarded": 1454600601.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "dkaspar", "last_awarded": 1461940547.0, "percent_earned": 0.18925056775170326,
+        "id": "devconf-2016-attendee", "times_awarded": 85, "name": "DevConf 2016
+        Attendee"}, {"description": "You got a \"Change\" accepted into the Fedora
+        24 Change list", "tags": "development,FESCo,process,", "issued": 1458652673.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f24.png", "first_awarded":
+        1458651465.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "pnemade", "last_awarded": 1459240914.0, "percent_earned": 0.10019147704501936,
+        "id": "fedora-24-change-accepted", "times_awarded": 45, "name": "Fedora 24
+        Change Accepted"}, {"description": "You held third place on the Fedora Badges
+        leaderboard", "tags": "meta,community,", "issued": 1462904993.0, "image":
+        "https://badges.fedoraproject.org/pngs/3_badge_340.png", "first_awarded":
+        1452875229.0, "first_awarded_person": "pnemade", "last_awarded_person": "kevin",
+        "last_awarded": 1489692901.0, "percent_earned": 0.011132386338335486, "id":
+        "bronze", "times_awarded": 5, "name": "Bronze"}, {"description": "You burned
+        a yubikey and linked it with your Fedora Account", "tags": "account,community,",
+        "issued": 1462904755.0, "image": "https://badges.fedoraproject.org/pngs/yubi-badge.png",
+        "first_awarded": 1422906928.0, "first_awarded_person": "plautrba", "last_awarded_person":
+        "findarato", "last_awarded": 1491408410.0, "percent_earned": 0.4052188627154117,
+        "id": "horcrux", "times_awarded": 182, "name": "Horcrux"}, {"description":
+        "You hacked with the Fedora crew at PyCon US 2016", "tags": "event, python,pycon,",
+        "issued": 1464988862.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2016_attendee.png",
+        "first_awarded": 1464988862.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "maxamillion", "last_awarded": 1464991242.0, "percent_earned": 0.028944204479672265,
+        "id": "pycon-2016-attendee", "times_awarded": 13, "name": "PyCon 2016 Attendee"},
+        {"description": "You got 150 Fedora Badges!  Wow!", "tags": "badges,community,",
+        "issued": 1468058613.0, "image": "https://badges.fedoraproject.org/pngs/badger-04.png",
+        "first_awarded": 1457979017.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1490919191.0, "percent_earned": 0.020038295409003874,
+        "id": "badge-junkie-badger-iv", "times_awarded": 9, "name": "Badge Junkie
+        (Badger IV)"}, {"description": "You can speak Python and and you''ve ported
+        at least five packages to Python 3", "tags": "python,miscellaneous,", "issued":
+        1468058067.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-II.png",
+        "first_awarded": 1467988651.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1488193805.0, "percent_earned": 0.028944204479672265,
+        "id": "parselmouth-ii", "times_awarded": 13, "name": "Parselmouth II"}, {"description":
+        "You can speak Python and and you''ve ported at least ten packages to Python
+        3", "tags": "python,miscellaneous,", "issued": 1468058072.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-III.png",
+        "first_awarded": 1467997850.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1489753361.0, "percent_earned": 0.02226477267667097,
+        "id": "parselmouth-iii", "times_awarded": 10, "name": "Parselmouth III"},
+        {"description": "You attended Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,event,events,", "issued": 1470404480.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-attendee.png",
+        "first_awarded": 1468984748.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "adrian", "last_awarded": 1486483875.0, "percent_earned": 0.2360065903727123,
+        "id": "flock-2016-attendee", "times_awarded": 106, "name": "Flock 2016 Attendee"},
+        {"description": "You attended the party at Flock 2016 in Krakow!", "tags":
+        "flock,krakow,event,events,", "issued": 1470404592.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/krakow-brews.png",
+        "first_awarded": 1468963417.0, "first_awarded_person": "duffy", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217490.0, "percent_earned": 0.18257113594870197,
+        "id": "krakow-brews!", "times_awarded": 82, "name": "Krakow Brews!"}, {"description":
+        "You gave a presentation at Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,speaker,event,", "issued": 1471354751.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-speaker.png",
+        "first_awarded": 1470941077.0, "first_awarded_person": "mattdm", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217546.0, "percent_earned": 0.19592999955470453,
+        "id": "flock-2016-speaker", "times_awarded": 88, "name": "Flock 2016 Speaker"},
+        {"description": "You''re a member of the Modularity Working Group!", "tags":
+        "modularity,community,", "issued": 1475082397.0, "image": "https://badges.fedoraproject.org/pngs/fas-modularity-wg.png",
+        "first_awarded": 1475082098.0, "first_awarded_person": "asamalik", "last_awarded_person":
+        "jscotka", "last_awarded": 1491213584.0, "percent_earned": 0.0801531816360155,
+        "id": "modularity-wg-member", "times_awarded": 36, "name": "Modularity WG
+        Member"}, {"description": "You got a \"Change\" accepted into the Fedora 26
+        Change list", "tags": "development, FESCo, process,", "issued": 1479749896.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f26.png", "first_awarded":
+        1473331018.0, "first_awarded_person": "cstratak", "last_awarded_person": "ncoghlan",
+        "last_awarded": 1489656918.0, "percent_earned": 0.11577681791868906, "id":
+        "fedora-26-change-accepted", "times_awarded": 52, "name": "Fedora 26 Change
+        Accepted"}, {"description": "You gave a presentation at DevConf.cz, 2017",
+        "tags": "speaker,devconf,event,", "issued": 1486037155.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2017.png",
+        "first_awarded": 1486033923.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "siddharths", "last_awarded": 1486077040.0, "percent_earned": 0.24713897671104776,
+        "id": "devconf-2017-speaker", "times_awarded": 111, "name": "DevConf 2017
+        Speaker"}, {"description": "You have helped so many Fedorans you''ve got over
+        100 cookies. Don''t eat them all at once!", "tags": "cookie,community,", "issued":
+        1486153659.0, "image": "https://badges.fedoraproject.org/pngs/rainbowcookie.png",
+        "first_awarded": 1468278719.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ralph", "last_awarded": 1486153659.0, "percent_earned": 0.011132386338335486,
+        "id": "rainbow-cookie-v", "times_awarded": 5, "name": "Rainbow (Cookie V)"}],
+        "percent_earned": 41.81818181818181, "user": "ralph"}'}
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=45356299]
+      connection: [Keep-Alive]
+      content-length: ['74203']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 06 Apr 2017 22:32:50 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"user_count": 44887, "rank": 5, "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png",
+        "percentile": "0.01", "assertions": [{"description": "You attended Flock 2013,
+        the Fedora Contributor Conference", "tags": "flock,event,", "issued": 1375373082.0,
+        "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "rbergero", "last_awarded": 1473972160.0, "percent_earned": 0.18034465868103486,
+        "id": "flock-2013-attendee", "times_awarded": 81, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198996.0, "percent_earned": 0.663490225764795,
+        "id": "tagger-tagger-ii", "times_awarded": 298, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002037.0, "percent_earned": 1.0508972703388697,
+        "id": "junior-tagger-tagger-i", "times_awarded": 472, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ylarguex", "last_awarded": 1491516838.0, "percent_earned": 53.357527719641986,
+        "id": "involvement", "times_awarded": 23965, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "icole",
+        "last_awarded": 1491505117.0, "percent_earned": 3.9564501046444316, "id":
+        "speak-up!", "times_awarded": 1777, "name": "Speak Up!"}, {"description":
+        "Edited at least 10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0,
+        "image": "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "kdudka",
+        "last_awarded": 1491484751.0, "percent_earned": 3.3129981742886407, "id":
+        "junior-editor", "times_awarded": 1488, "name": "Junior Editor"}, {"description":
+        "Edited at least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0,
+        "image": "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "ankit1997",
+        "last_awarded": 1491242577.0, "percent_earned": 2.108473972480741, "id": "associate-editor",
+        "times_awarded": 947, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "yzhang",
+        "last_awarded": 1491431124.0, "percent_earned": 1.5451752237609653, "id":
+        "secretary-general", "times_awarded": 694, "name": "Secretary General"}, {"description":
+        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
+        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198974.0, "percent_earned": 0.3139332947410607,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 141, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491425650.0, "percent_earned": 0.5454869305784388,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 245, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "nickboldt",
+        "last_awarded": 1490915696.0, "percent_earned": 2.858796811684553, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1284, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "sjenning", "last_awarded": 1491017600.0, "percent_earned": 2.3288952219797836,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 1046, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "tartare",
+        "last_awarded": 1491481451.0, "percent_earned": 1.4138130649686065, "id":
+        "if-you-build-it...-koji-success-iii", "times_awarded": 635, "name": "If you
+        build it... (Koji Success III)"}, {"description": "Ten or more questions and
+        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
+        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedo25", "last_awarded": 1491440137.0, "percent_earned": 1.4182660195039407,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 637, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "andre", "last_awarded": 1491511008.0, "percent_earned": 9.738611568775884,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 4374, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491482061.0, "percent_earned": 1.903638063855368,
+        "id": "riddle-me-this", "times_awarded": 855, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mhonek", "last_awarded": 1490899614.0, "percent_earned": 2.0127354499710557,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 904, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "nickboldt", "last_awarded": 1491244448.0, "percent_earned": 1.94816760920871,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 875, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "jscotka",
+        "last_awarded": 1491289110.0, "percent_earned": 2.6695462439328494, "id":
+        "you-can-call-me-patches-scm-i", "times_awarded": 1199, "name": "You can call
+        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
+        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "berrange",
+        "last_awarded": 1491242273.0, "percent_earned": 0.5588457941844414, "id":
+        "you-can-call-me-patches-scm-iv", "times_awarded": 251, "name": "You can call
+        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
+        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "cydrobolt",
+        "last_awarded": 1490744785.0, "percent_earned": 1.3603776105445964, "id":
+        "you-can-call-me-patches-scm-iii", "times_awarded": 611, "name": "You can
+        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441515.0, "percent_earned": 0.6523578394264594,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 293, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "tkrizek", "last_awarded": 1490376511.0, "percent_earned": 1.329206928797257,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 597, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441872.0, "percent_earned": 0.5299015897047691,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 238, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "toshio", "last_awarded": 1491516269.0, "percent_earned": 2.70739635748319,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 1216, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "apollo7", "last_awarded": 1491362331.0, "percent_earned": 7.547757937391459,
+        "id": "junior-badger-badger-i", "times_awarded": 3390, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "scox", "last_awarded": 1491419635.0, "percent_earned": 2.562675335084829,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 1151, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "alciregi", "last_awarded": 1491294835.0, "percent_earned": 1.6631785189473214,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 747, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "mystro256",
+        "last_awarded": 1491340270.0, "percent_earned": 0.39408647637707617, "id":
+        "like-a-rock-updates-stable-iii", "times_awarded": 177, "name": "Like a Rock
+        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
+        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "landgraf", "last_awarded": 1491498009.0, "percent_earned": 6.412254530881239,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2880, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "cqi",
+        "last_awarded": 1491420777.0, "percent_earned": 1.2379213608229058, "id":
+        "like-a-rock-updates-stable-ii", "times_awarded": 556, "name": "Like a Rock
+        (Updates-Stable II)"}, {"description": "Partied with Flock 2013 (at the South
+        Carolina Aquarium)", "tags": "party,flock,event,", "issued": 1376252202.0,
+        "image": "https://badges.fedoraproject.org/pngs/tanked.png", "first_awarded":
+        1376252202.0, "first_awarded_person": "ralph", "last_awarded_person": "gnokii",
+        "last_awarded": 1411656869.0, "percent_earned": 0.14026806786302712, "id":
+        "tanked!", "times_awarded": 63, "name": "Tanked!"}, {"description": "You proposed
+        a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,", "issued":
+        1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "frantisekz", "last_awarded": 1484316413.0, "percent_earned": 0.3161597720087278,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 142, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491477255.0, "percent_earned": 5.508304760208398,
+        "id": "bona-fide", "times_awarded": 2474, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.05788840895934453,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "mailga", "last_awarded": 1491037049.0, "percent_earned": 0.823796589036826,
+        "id": "senior-badger-badger-ii", "times_awarded": 370, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "olem",
+        "last_awarded": 1491070078.0, "percent_earned": 2.658413857594514, "id": "is-this-thing-on-updates-testing-i",
+        "times_awarded": 1194, "name": "Is this thing on? (Updates-Testing I)"}, {"description":
+        "Pushed 20 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1376077757.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491432891.0, "percent_earned": 1.467248519392617,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 659, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "dustymabe",
+        "last_awarded": 1491406327.0, "percent_earned": 1.714387496103665, "id": "partners-in-crime",
+        "times_awarded": 770, "name": "Partners in Crime"}, {"description": "*(a great
+        struggle, repeated escapes, discipline required)*\nTested and added karma
+        to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "mcepl", "last_awarded": 1491490795.0, "percent_earned": 0.961838179632186,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 432, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "bt0dotninja",
+        "last_awarded": 1489638271.0, "percent_earned": 0.16253284053969808, "id":
+        "master-tagger-tagger-iv", "times_awarded": 73, "name": "Master Tagger (Tagger
+        IV)"}, {"description": "A member of the sysadmin-badges group.  Nothing to
+        see here..  move along.", "tags": "infrastructure,badges,community,", "issued":
+        1378319150.0, "image": "https://badges.fedoraproject.org/pngs/fas-inside-job.png",
+        "first_awarded": 1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "jflory7", "last_awarded": 1472154166.0, "percent_earned": 0.02226477267667097,
+        "id": "inside-job", "times_awarded": 10, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "salvadorhm", "last_awarded": 1491509400.0, "percent_earned": 8.144453845126241,
+        "id": "white-rabbit", "times_awarded": 3658, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jcholast", "last_awarded": 1491423845.0, "percent_earned": 3.061406243042258,
+        "id": "mugshot", "times_awarded": 1375, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.03785011355034065,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jkaluza", "last_awarded": 1490254934.0, "percent_earned": 0.10241795431268647,
+        "id": "maestro", "times_awarded": 46, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "cra", "last_awarded": 1491437628.0, "percent_earned": 4.250345103976488,
+        "id": "let-me-introduce-myself", "times_awarded": 1909, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "ngompa", "last_awarded": 1490659963.0, "percent_earned": 0.7614552255421472,
+        "id": "binary-star", "times_awarded": 342, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "xavierb", "last_awarded": 1484573828.0, "percent_earned": 0.32506568107939615,
+        "id": "packager-sponsor", "times_awarded": 146, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468491.0, "percent_earned": 1.3470187469385937,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 605, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468509.0, "percent_earned": 1.1399563610455536,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 512, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468543.0, "percent_earned": 1.6231019281293138,
+        "id": "bloggin-it!-planet-i", "times_awarded": 729, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "dtimms", "last_awarded": 1491484910.0, "percent_earned": 0.939573406955515,
+        "id": "white-hat", "times_awarded": 422, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.17589170414570066,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "andrespol", "last_awarded": 1491360716.0, "percent_earned": 20.256490181235247,
+        "id": "embryo", "times_awarded": 9098, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "piotrdrag", "last_awarded": 1491478479.0, "percent_earned": 0.549939885113773,
+        "id": "taming-the-bull-tester-v", "times_awarded": 247, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ferdnyc", "last_awarded": 1484744055.0, "percent_earned": 0.1469474996660284,
+        "id": "common-bugs-contributor", "times_awarded": 66, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "metonymy", "last_awarded": 1491502807.0, "percent_earned": 6.249721690341541,
+        "id": "baby-badger", "times_awarded": 2807, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "martinkg", "last_awarded": 1489655875.0, "percent_earned": 0.09351204524201807,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 42, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pwalter", "last_awarded": 1491445231.0, "percent_earned": 0.6167342031437859,
+        "id": "old-yeller", "times_awarded": 277, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.1580798860043639,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "stefw", "last_awarded": 1491468562.0, "percent_earned": 0.7547757937391459,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 339, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "augenauf", "last_awarded": 1491316933.0, "percent_earned": 1.013047156788529,
+        "id": "senior-editor", "times_awarded": 455, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "avichi", "last_awarded": 1491361425.0, "percent_earned": 14.18933962684241,
+        "id": "tadpole", "times_awarded": 6373, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "amogh23k", "last_awarded": 1491362307.0, "percent_earned": 28.41430288996749,
+        "id": "egg", "times_awarded": 12762, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "akopacsi", "last_awarded": 1490757692.0, "percent_earned": 7.30952486975108,
+        "id": "tadpole-with-legs", "times_awarded": 3283, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "lsedlar", "last_awarded": 1476326553.0, "percent_earned": 0.05120897715634323,
+        "id": "badge-off!", "times_awarded": 23, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "sassam", "last_awarded": 1491148875.0, "percent_earned": 0.3072538629380594,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 138, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "metonymy", "last_awarded": 1491476646.0, "percent_earned": 0.4208042035890813,
+        "id": "no-longer-a-ronin", "times_awarded": 189, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bt0dotninja", "last_awarded": 1489643141.0, "percent_earned": 0.13358863606002583,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 60, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002111.0, "percent_earned": 0.8750055661931692,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 393, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "ignacio", "last_awarded": 1485888954.0, "percent_earned": 0.28944204479672264,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 130, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "imabug", "last_awarded": 1490199130.0, "percent_earned": 0.5120897715634324,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 230, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "devconf,speaker,event,", "issued": 1390422108.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.10241795431268647, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "terjeros", "last_awarded": 1491331717.0, "percent_earned": 0.26717727212005166,
+        "id": "patches-scm-v", "times_awarded": 120, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "decathorpe", "last_awarded": 1491331634.0, "percent_earned": 0.7480963619361446,
+        "id": "override,-you-say", "times_awarded": 336, "name": "Override, you say?"},
+        {"description": "You attended the 2014 iteration of devconf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event,devconf,", "issued":
+        1391763090.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png",
+        "first_awarded": 1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.13804159059536003,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf 2014 Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "swilson", "last_awarded": 1458943142.0, "percent_earned":
+        0.03562363628267355, "id": "videographer", "times_awarded": 16, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "zbyszek", "last_awarded": 1490388487.0, "percent_earned": 0.15585340873669679,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 70,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491441908.0, "percent_earned": 3.958676581912099,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1778, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491503467.0, "percent_earned": 2.046132608986062,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 919, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "caiqian",
+        "last_awarded": 1481903131.0, "percent_earned": 1.6765373825533243, "id":
+        "it-still-works!", "times_awarded": 753, "name": "It still works!"}, {"description":
+        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
+        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491442200.0, "percent_earned": 2.1641359041724186,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 972, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "stefw", "last_awarded": 1491468526.0, "percent_earned": 0.35623636282673554,
+        "id": "bob-loblaw-planet-v", "times_awarded": 160, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "dfateyev", "last_awarded": 1490465620.0, "percent_earned": 0.06902079529768002,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 31, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "ignatenkobrain", "last_awarded": 1485808919.0, "percent_earned": 0.14472102239836132,
+        "id": "lets-do-lunch!", "times_awarded": 65, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "mythcat", "last_awarded":
+        1484694397.0, "percent_earned": 0.4208042035890813, "id": "vacation", "times_awarded":
+        189, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "python,event,pycon,", "issued": 1397168025.0, "image":
+        "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png", "first_awarded":
+        1397168025.0, "first_awarded_person": "ralph", "last_awarded_person": "abompard",
+        "last_awarded": 1397573900.0, "percent_earned": 0.02226477267667097, "id":
+        "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 0.6345460212851227,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "nickboldt", "last_awarded": 1490915668.0, "percent_earned": 0.984102952308857,
+        "id": "helping-hand", "times_awarded": 442, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.20483590862537293,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "wtaymans",
+        "last_awarded": 1490906731.0, "percent_earned": 0.20038295409003873, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 90, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "payasr", "last_awarded": 1491512765.0, "percent_earned": 61.86712383666563,
+        "id": "paranoid-panda", "times_awarded": 27787, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.16253284053969808, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jvymazal", "last_awarded": 1491284602.0, "percent_earned": 1.099879770227546,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 494, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "athoscr",
+        "last_awarded": 1490991464.0, "percent_earned": 0.5900164759317807, "id":
+        "master-editor", "times_awarded": 265, "name": "Master Editor"}, {"description":
+        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "terjeros", "last_awarded": 1491384354.0, "percent_earned": 0.389633521841742,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 175, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405296000.0, "first_awarded_person": "marinaz", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.27163022665538583,
+        "id": "flock-2014-attendee", "times_awarded": 122, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "pperron", "last_awarded": 1490999828.0, "percent_earned": 0.49873090795742975,
+        "id": "science-kernel-tester-i", "times_awarded": 224, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.19815647682237164, "id":
+        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
+        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
+        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1485788654.0, "percent_earned": 0.03339715901500646,
+        "id": "corporate-overlord", "times_awarded": 15, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "kdudka", "last_awarded": 1491214689.0, "percent_earned": 0.18925056775170326,
+        "id": "corporate-shill", "times_awarded": 85, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "dsommers", "last_awarded": 1490298016.0, "percent_earned": 1.3024892015852518,
+        "id": "corporate-drone", "times_awarded": 585, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vondruch", "last_awarded": 1491296529.0, "percent_earned": 0.14026806786302712,
+        "id": "master-badger-badger-iii", "times_awarded": 63, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "fale", "last_awarded":
+        1490321832.0, "percent_earned": 0.2248742040343768, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 101, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "rbergero", "last_awarded": 1455959914.0, "percent_earned": 0.0712472725653471,
+        "id": "dancing-with-toshio", "times_awarded": 32, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.2449124994433807, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "keitellf",
+        "last_awarded": 1465418173.0, "percent_earned": 0.8972703388698402, "id":
+        "consolation-prize", "times_awarded": 403, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "usuha", "last_awarded": 1491448085.0, "percent_earned": 6.430066349022577,
+        "id": "crypto-panda", "times_awarded": 2888, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491505320.0, "percent_earned": 2.3711982900654585,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 1065, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1490811747.0, "percent_earned": 0.03562363628267355,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 16, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "sailer", "last_awarded": 1490344262.0, "percent_earned": 0.7525493164714788,
+        "id": "the-cat-came-back...", "times_awarded": 338, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "michalrud", "last_awarded": 1470317213.0, "percent_earned": 0.04675602262100904,
+        "id": "apprentice-badge-artist-i", "times_awarded": 21, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "kkeithle", "last_awarded": 1491364811.0, "percent_earned": 0.20706238589304005,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 93, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.04007659081800775,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.13804159059536003,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "orion", "last_awarded": 1490756246.0, "percent_earned": 0.024491249944338066,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 11, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "pcreech17", "last_awarded": 1491432940.0, "percent_earned": 2.3756512446007925,
+        "id": "associate-badger-badger-1.5", "times_awarded": 1067, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "kellin", "last_awarded": 1461547496.0, "percent_earned": 0.18479761321636906,
+        "id": "flock-2015-attendee", "times_awarded": 83, "name": "Flock 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "gtierney", "last_awarded": 1491405719.0, "percent_earned": 1.852429086699025,
+        "id": "macaron-cookie-i", "times_awarded": 832, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "mizdebsk",
+        "last_awarded": 1491500198.0, "percent_earned": 0.3606893173620697, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 162, "name": "Chocolate Chip
+        (Cookie II)"}, {"description": "Voted in the supplemental wallpapers election
+        for the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.18257113594870197,
+        "id": "nuancier-f22", "times_awarded": 82, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "schwankek", "last_awarded": 1491486520.0, "percent_earned": 17.635926437191078,
+        "id": "origin", "times_awarded": 7921, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "nmilosev", "last_awarded": 1491213323.0, "percent_earned": 0.919535111546511,
+        "id": "delivery", "times_awarded": 413, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dustymabe", "last_awarded": 1475240820.0, "percent_earned": 0.5655252259874427,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 254,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dmsimard", "last_awarded": 1491321510.0, "percent_earned": 0.14472102239836132,
+        "id": "black-and-white-cookie-iii", "times_awarded": 65, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "smani", "last_awarded": 1485976444.0, "percent_earned": 0.08460613617134968,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 38, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509860.0, "percent_earned": 0.006679431803001291,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 3, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "pravins", "last_awarded": 1472553692.0, "percent_earned": 0.03562363628267355,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 16, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "frantisekz", "last_awarded": 1485462295.0, "percent_earned": 0.10019147704501936,
+        "id": "badge-muse-badges-released-i", "times_awarded": 45, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509873.0, "percent_earned": 0.013358863606002582,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 6, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.002226477267667097,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "kellin", "last_awarded": 1461547520.0, "percent_earned": 0.16921227234269937,
+        "id": "nom-nom-nom", "times_awarded": 76, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "rluzynski", "last_awarded": 1491442095.0, "percent_earned": 1.5763459055083047,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 708, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491326903.0, "percent_earned": 0.12468272698935744,
+        "id": "rock-the-web!", "times_awarded": 56, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and and you''ve ported at least one package to Python
+        3", "tags": "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "crobinso", "last_awarded": 1491217608.0, "percent_earned": 0.33842454468539873,
+        "id": "parselmouth", "times_awarded": 152, "name": "Parselmouth I"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "jonatoni",
+        "last_awarded": 1490211890.0, "percent_earned": 0.22710068130204392, "id":
+        "chief-editor", "times_awarded": 102, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "apahim", "last_awarded": 1491360865.0, "percent_earned": 4.628846239479895,
+        "id": "froglet", "times_awarded": 2079, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ryanlerch", "last_awarded": 1490719235.0, "percent_earned": 0.03117068174733936,
+        "id": "pizzelle-cookie-iv", "times_awarded": 14, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "churchyard", "last_awarded": 1475564266.0, "percent_earned": 0.011132386338335486,
+        "id": "silver", "times_awarded": 5, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1489622707.0, "percent_earned": 0.03117068174733936,
+        "id": "top-10", "times_awarded": 14, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "tflink", "last_awarded": 1480461776.0, "percent_earned": 0.25159193124638196,
+        "id": "top-100", "times_awarded": 113, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mrunge", "last_awarded": 1490730635.0, "percent_earned": 0.06679431803001291,
+        "id": "top-25", "times_awarded": 30, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "zsun", "last_awarded": 1490677027.0, "percent_earned": 1.2000712472725654,
+        "id": "top-500", "times_awarded": 539, "name": "Top 500"}, {"description":
+        "You visited the Fedora table at BrickHack 2016!", "tags": "brickhack,event,hackathon,events,",
+        "issued": 1457234130.0, "image": "http://infrastructure.fedoraproject.org/infra/badges/pngs/events-brickhack-2016.png",
+        "first_awarded": 1455845197.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "brandondgr8", "last_awarded": 1461299769.0, "percent_earned": 0.05566193169167742,
+        "id": "brickhack-2016-attendee", "times_awarded": 25, "name": "BrickHack 2016
+        Attendee"}, {"description": "You gave a presentation at DevConf.cz, 2016",
+        "tags": "devconf,speaker,event,", "issued": 1455008224.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2016.png",
+        "first_awarded": 1454667336.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "thozza", "last_awarded": 1459500320.0, "percent_earned": 0.2137418176960413,
+        "id": "devconf-2016-speaker", "times_awarded": 96, "name": "DevConf 2016 Speaker"},
+        {"description": "You attended the 2016 iteration of DevConf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event, devconf,", "issued":
+        1455120228.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee-2016.png",
+        "first_awarded": 1454600601.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "dkaspar", "last_awarded": 1461940547.0, "percent_earned": 0.18925056775170326,
+        "id": "devconf-2016-attendee", "times_awarded": 85, "name": "DevConf 2016
+        Attendee"}, {"description": "You got a \"Change\" accepted into the Fedora
+        24 Change list", "tags": "development,FESCo,process,", "issued": 1458652673.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f24.png", "first_awarded":
+        1458651465.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "pnemade", "last_awarded": 1459240914.0, "percent_earned": 0.10019147704501936,
+        "id": "fedora-24-change-accepted", "times_awarded": 45, "name": "Fedora 24
+        Change Accepted"}, {"description": "You held third place on the Fedora Badges
+        leaderboard", "tags": "meta,community,", "issued": 1462904993.0, "image":
+        "https://badges.fedoraproject.org/pngs/3_badge_340.png", "first_awarded":
+        1452875229.0, "first_awarded_person": "pnemade", "last_awarded_person": "kevin",
+        "last_awarded": 1489692901.0, "percent_earned": 0.011132386338335486, "id":
+        "bronze", "times_awarded": 5, "name": "Bronze"}, {"description": "You burned
+        a yubikey and linked it with your Fedora Account", "tags": "account,community,",
+        "issued": 1462904755.0, "image": "https://badges.fedoraproject.org/pngs/yubi-badge.png",
+        "first_awarded": 1422906928.0, "first_awarded_person": "plautrba", "last_awarded_person":
+        "findarato", "last_awarded": 1491408410.0, "percent_earned": 0.4052188627154117,
+        "id": "horcrux", "times_awarded": 182, "name": "Horcrux"}, {"description":
+        "You hacked with the Fedora crew at PyCon US 2016", "tags": "event, python,pycon,",
+        "issued": 1464988862.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2016_attendee.png",
+        "first_awarded": 1464988862.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "maxamillion", "last_awarded": 1464991242.0, "percent_earned": 0.028944204479672265,
+        "id": "pycon-2016-attendee", "times_awarded": 13, "name": "PyCon 2016 Attendee"},
+        {"description": "You got 150 Fedora Badges!  Wow!", "tags": "badges,community,",
+        "issued": 1468058613.0, "image": "https://badges.fedoraproject.org/pngs/badger-04.png",
+        "first_awarded": 1457979017.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1490919191.0, "percent_earned": 0.020038295409003874,
+        "id": "badge-junkie-badger-iv", "times_awarded": 9, "name": "Badge Junkie
+        (Badger IV)"}, {"description": "You can speak Python and and you''ve ported
+        at least five packages to Python 3", "tags": "python,miscellaneous,", "issued":
+        1468058067.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-II.png",
+        "first_awarded": 1467988651.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1488193805.0, "percent_earned": 0.028944204479672265,
+        "id": "parselmouth-ii", "times_awarded": 13, "name": "Parselmouth II"}, {"description":
+        "You can speak Python and and you''ve ported at least ten packages to Python
+        3", "tags": "python,miscellaneous,", "issued": 1468058072.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-III.png",
+        "first_awarded": 1467997850.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1489753361.0, "percent_earned": 0.02226477267667097,
+        "id": "parselmouth-iii", "times_awarded": 10, "name": "Parselmouth III"},
+        {"description": "You attended Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,event,events,", "issued": 1470404480.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-attendee.png",
+        "first_awarded": 1468984748.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "adrian", "last_awarded": 1486483875.0, "percent_earned": 0.2360065903727123,
+        "id": "flock-2016-attendee", "times_awarded": 106, "name": "Flock 2016 Attendee"},
+        {"description": "You attended the party at Flock 2016 in Krakow!", "tags":
+        "flock,krakow,event,events,", "issued": 1470404592.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/krakow-brews.png",
+        "first_awarded": 1468963417.0, "first_awarded_person": "duffy", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217490.0, "percent_earned": 0.18257113594870197,
+        "id": "krakow-brews!", "times_awarded": 82, "name": "Krakow Brews!"}, {"description":
+        "You gave a presentation at Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,speaker,event,", "issued": 1471354751.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-speaker.png",
+        "first_awarded": 1470941077.0, "first_awarded_person": "mattdm", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217546.0, "percent_earned": 0.19592999955470453,
+        "id": "flock-2016-speaker", "times_awarded": 88, "name": "Flock 2016 Speaker"},
+        {"description": "You''re a member of the Modularity Working Group!", "tags":
+        "modularity,community,", "issued": 1475082397.0, "image": "https://badges.fedoraproject.org/pngs/fas-modularity-wg.png",
+        "first_awarded": 1475082098.0, "first_awarded_person": "asamalik", "last_awarded_person":
+        "jscotka", "last_awarded": 1491213584.0, "percent_earned": 0.0801531816360155,
+        "id": "modularity-wg-member", "times_awarded": 36, "name": "Modularity WG
+        Member"}, {"description": "You got a \"Change\" accepted into the Fedora 26
+        Change list", "tags": "development, FESCo, process,", "issued": 1479749896.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f26.png", "first_awarded":
+        1473331018.0, "first_awarded_person": "cstratak", "last_awarded_person": "ncoghlan",
+        "last_awarded": 1489656918.0, "percent_earned": 0.11577681791868906, "id":
+        "fedora-26-change-accepted", "times_awarded": 52, "name": "Fedora 26 Change
+        Accepted"}, {"description": "You gave a presentation at DevConf.cz, 2017",
+        "tags": "speaker,devconf,event,", "issued": 1486037155.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2017.png",
+        "first_awarded": 1486033923.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "siddharths", "last_awarded": 1486077040.0, "percent_earned": 0.24713897671104776,
+        "id": "devconf-2017-speaker", "times_awarded": 111, "name": "DevConf 2017
+        Speaker"}, {"description": "You have helped so many Fedorans you''ve got over
+        100 cookies. Don''t eat them all at once!", "tags": "cookie,community,", "issued":
+        1486153659.0, "image": "https://badges.fedoraproject.org/pngs/rainbowcookie.png",
+        "first_awarded": 1468278719.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ralph", "last_awarded": 1486153659.0, "percent_earned": 0.011132386338335486,
+        "id": "rainbow-cookie-v", "times_awarded": 5, "name": "Rainbow (Cookie V)"}],
+        "percent_earned": 41.81818181818181, "user": "ralph"}'}
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=44302106]
+      connection: [Keep-Alive]
+      content-length: ['74203']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 06 Apr 2017 22:33:37 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_view_authz b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_view_authz
new file mode 100644
index 0000000..0681d72
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_view_authz
@@ -0,0 +1,1051 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy11.fedoraproject.org]
+      apptime: [D=260670723]
+      connection: [close]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:43:06 GMT']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=5811152]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:28 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=2388762]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:34 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_view_authz b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_view_authz
new file mode 100644
index 0000000..ec0fd82
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_view_authz
@@ -0,0 +1,304 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=Fedora%20release
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      accept-ranges: [bytes]
+      age: ['0']
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=466769]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:43 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C8hXEA.J-L3Q3D5WaWNhP3xXPbEcZs4hBU;
+          Expires=Thu, 06-Apr-2017 23:47:44 GMT; Secure; HttpOnly; Path=/calendar']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+      via: [1.1 varnish-v4]
+      x-varnish: ['14164337']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=Fedora%20release
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      accept-ranges: [bytes]
+      age: ['0']
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=422626]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['3975']
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:44 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C8hXEQ.l-i-NQ-NFV7tfhfpF_Pjr_6LWaM;
+          Expires=Thu, 06-Apr-2017 23:47:45 GMT; Secure; HttpOnly; Path=/calendar']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+      via: [1.1 varnish-v4]
+      x-varnish: ['14488870']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=Fedora%20release
+  response:
+    body:
+      string: !!binary |
+        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
+        AMTKs+Vs2AAA
+    headers:
+      accept-ranges: [bytes]
+      age: ['0']
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=525518]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:45 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C8hXEg.iAM2PfVJ078Ph-buEOa2ztll9hk;
+          Expires=Thu, 06-Apr-2017 23:47:46 GMT; Secure; HttpOnly; Path=/calendar']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+      via: [1.1 varnish-v4]
+      x-varnish: ['14164340']
+    status: {code: 200, message: OK}
+version: 1

From a4468aec867a7a43af53508994c692a0a41f289f Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 11 2017 12:51:54 +0000
Subject: [PATCH 816/1001] Fix the height column issue in the config panel


---

diff --git a/hubs/static/client/app/components/TabSet.jsx b/hubs/static/client/app/components/TabSet.jsx
index df63568..c53bc31 100644
--- a/hubs/static/client/app/components/TabSet.jsx
+++ b/hubs/static/client/app/components/TabSet.jsx
@@ -39,14 +39,14 @@ export default class TabSet extends React.Component {
     }.bind(this));
 
     return (
-      <div>
+      <div {...this.props.tabWrapperProps}>
         <ul role="tablist"
-            className={"nav nav-tabs " + this.props.tabListClass || ""}
+            className={"nav nav-tabs " + this.props.tabListClass}
             >
           {tabLinks}
         </ul>
         <div
-          className={"tab-content " + this.props.tabContentClass || ""}
+          className={"tab-content " + this.props.tabContentClass}
           >
           {tabPanels}
         </div>
@@ -56,5 +56,16 @@ export default class TabSet extends React.Component {
 
 }
 
+TabSet.propTypes = {
+  tabWrapperProps: React.PropTypes.object,
+  tabListClass: React.PropTypes.string,
+  tabContentClass: React.PropTypes.string,
+};
+TabSet.defaultProps = {
+  tabWrapperProps: {},
+  tabListClass: '',
+  tabContentClass: '',
+};
+
 
 // vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
index f4b75af..3732bd7 100644
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -176,6 +176,10 @@ export default class HubConfig extends React.Component {
               <div className="modal-body">
                 <div className="row">
                   <TabSet
+                    tabWrapperProps={{
+                      className: "d-flex",
+                      style: {display: "flex"},
+                      }}
                     tabListClass="col-md-3"
                     tabContentClass="col-md-9"
                     >
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 7ff066f..86e35f0 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -178,18 +178,6 @@
   padding-bottom: 2em;
 }
 
-/* Fixed vertical size to give the appearance of panels. Hackish. Find a CSS expert to do this properly. */
-#settings-modal .nav {
-  min-height: 400px;
-  max-height: 400px;
-}
-#settings-modal .tab-content {
-  min-height: 400px;
-  max-height: 400px;
-  overflow-y: auto;
-}
-
-
 
 /*
  * Widgets

From c8ff4f530bda14d7fc5bedb40c8afb1ac2d0fd9e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 11 2017 12:51:54 +0000
Subject: [PATCH 817/1001] Split the config panels into separate files


---

diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
index 3732bd7..fca9e33 100644
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -4,12 +4,10 @@ import {
   defineMessages,
   FormattedMessage,
   } from 'react-intl';
-import {
-  GeneralPanel,
-  ChatPanel,
-  UserPanel,
-  NotImplementedPanel,
-  } from './HubConfigPanel.jsx';
+import GeneralPanel from './HubConfigPanelGeneral.jsx';
+import UserPanel from './HubConfigPanelUser.jsx';
+import ChatPanel from './HubConfigPanelChat.jsx';
+import NotImplementedPanel from './HubConfigPanelNotImpl.jsx';
 import TabSet from '../components/TabSet.jsx';
 
 
diff --git a/hubs/static/client/app/core/HubConfigPanel.jsx b/hubs/static/client/app/core/HubConfigPanel.jsx
deleted file mode 100644
index 865e340..0000000
--- a/hubs/static/client/app/core/HubConfigPanel.jsx
+++ /dev/null
@@ -1,388 +0,0 @@
-import React from 'react';
-import {
-  IntlProvider,
-  defineMessages,
-  FormattedMessage,
-  FormattedHTMLMessage,
-  } from 'react-intl';
-import TabPanel from '../components/TabPanel.jsx';
-
-
-const messages = defineMessages({
-  general_title: {
-    id: "hubs.core.config.general.title",
-    defaultMessage: "General Settings",
-  },
-  general_intro: {
-    id: "hubs.core.config.general.intro",
-    defaultMessage: "Change your global hub parameters here.",
-  },
-  general_summary: {
-    id: "hubs.core.config.general.summary",
-    defaultMessage: "Summary",
-  },
-  general_summary_help: {
-    id: "hubs.core.config.general.summary_help",
-    defaultMessage: "This text will be displayed at the top of the hub.",
-  },
-  general_left_width: {
-    id: "hubs.core.config.general.left_width",
-    defaultMessage: "Left width",
-  },
-  general_left_width_help: {
-    id: "hubs.core.config.general.left_width_help",
-    defaultMessage: (
-      "Change the proportions of you hub's columns by setting the width of "
-     +"the left column (the right column's width will be {right_width})."
-      ),
-  },
-  general_visibility: {
-    id: "hubs.core.config.general.visibility",
-    defaultMessage: "Visibility",
-  },
-  general_visibility_help: {
-    id: "hubs.core.config.general.visibility_help",
-    defaultMessage: (
-      "Public: the hub is visible to anyone.<br />"
-     +"Private: the hub is only visible to members.<br />"
-     +"Preview: some widgets can be made visible to logged-in users only."
-      ),
-  },
-  general_avatar: {
-    id: "hubs.core.config.general.avatar",
-    defaultMessage: "Avatar",
-  },
-  general_avatar_help: {
-    id: "hubs.core.config.general.avatar_help",
-    defaultMessage: "An URL to you hub's main image or logo."
-  },
-  chat_title: {
-    id: "hubs.core.config.chat.title",
-    defaultMessage: "Chat Settings",
-  },
-  chat_intro_1: {
-    id: "hubs.core.config.chat.intro1",
-    defaultMessage: (
-      "If your team or project has an IRC channel associated with it, you "
-     +"can connect this hub to it via the Hubs chat widget."
-     ),
-  },
-  chat_intro_2: {
-    id: "hubs.core.config.chat.intro2",
-    defaultMessage: "Please indicate your team's IRC channel below:",
-  },
-  chat_channel_name: {
-    id: "hubs.core.config.chat.channel_name",
-    defaultMessage: "Channel name",
-  },
-  chat_example: {
-    id: "hubs.core.config.chat.example",
-    defaultMessage: "Example:",
-  },
-  chat_network: {
-    id: "hubs.core.config.chat.network",
-    defaultMessage: "IRC network",
-  },
-  users_fullname: {
-    id: "hubs.core.config.users.fullname",
-    defaultMessage: "Full name",
-  },
-  users_username: {
-    id: "hubs.core.config.users.username",
-    defaultMessage: "Username",
-  },
-  users_change_role: {
-    id: "hubs.core.config.users.change_role",
-    defaultMessage: "Change role",
-  },
-  users_na: {
-    id: "hubs.core.config.users.na",
-    defaultMessage: "(N/A)",
-  },
-  users_remove_user: {
-    id: "hubs.core.config.users.remove_user",
-    defaultMessage: "(remove user)",
-  },
-  users_add_user: {
-    id: "hubs.core.config.users.add_user",
-    defaultMessage: "Add user...",
-  },
-  users_add: {
-    id: "hubs.core.config.users.add",
-    defaultMessage: "Add",
-  },
-});
-
-
-export class NotImplementedPanel extends React.Component {
-
-  render() {
-    return (
-      <div>
-        Not implemented yet.
-      </div>
-    );
-  }
-
-}
-
-
-export class GeneralPanel extends React.Component {
-
-  render() {
-    var stillLoading = (typeof this.props.hubConfig.summary === "undefined");
-    var visibilities = this.props.generalConfig.hub_visibility || [];
-    return (
-      <form onSubmit={(e) => {e.preventDefault();}}>
-        <FormattedMessage {...messages.general_title} tagName="h3" />
-        <FormattedMessage {...messages.general_intro} tagName="p" />
-        <div className="form-group">
-          <label htmlFor="hub-settings-general-summary">
-            <FormattedMessage {...messages.general_summary} />
-          </label>
-          <input
-            type="text" className="form-control" name="summary"
-            id="hub-settings-general-summary"
-            disabled={stillLoading}
-            onChange={this.props.handleChange}
-            value={this.props.hubConfig.summary || ""}
-            />
-          <p className="form-text text-muted">
-            <FormattedMessage {...messages.general_summary_help} />
-          </p>
-        </div>
-        <div className="form-group">
-          <label htmlFor="hub-settings-general-leftwidth">
-            <FormattedMessage {...messages.general_left_width} />
-          </label>
-          <input
-            type="number" className="form-control" name="left_width"
-            id="hub-settings-general-leftwidth"
-            disabled={stillLoading}
-            min="1" max="11"
-            onChange={this.props.handleChange}
-            value={this.props.hubConfig.left_width || ""}
-            />
-          <p className="form-text text-muted">
-            <FormattedMessage
-              {...messages.general_left_width_help}
-              values={{right_width: 12 - (this.props.hubConfig.left_width || 8)}}
-              />
-          </p>
-        </div>
-        <div className="form-group">
-          <label htmlFor="hub-settings-general-visibility">
-            <FormattedMessage {...messages.general_visibility} />
-          </label>
-          <select
-            className="form-control" name="visibility"
-            value={this.props.hubConfig.visibility || ""}
-            onChange={this.props.handleChange}
-            disabled={stillLoading}
-            >
-            {visibilities.map(function(value) {
-              return (
-                <option value={value} key={value}>{value}</option>
-                );
-            })}
-          </select>
-          <p className="form-text text-muted">
-            <FormattedHTMLMessage {...messages.general_visibility_help} />
-          </p>
-        </div>
-        <div className="form-group">
-          <label htmlFor="hub-settings-general-avatar">
-            <FormattedMessage {...messages.general_avatar} />
-          </label>
-          <input
-            type="text" className="form-control" name="avatar"
-            id="hub-settings-general-avatar"
-            disabled={stillLoading}
-            onChange={this.props.handleChange}
-            value={this.props.hubConfig.avatar || ""}
-            />
-          <p className="form-text text-muted">
-            <FormattedMessage {...messages.general_avatar_help} />
-          </p>
-        </div>
-      </form>
-    );
-  }
-
-}
-
-
-export class UserPanel extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      addUsername: "",
-    };
-    this.handleAdd = this.handleAdd.bind(this);
-    this.handleAddInputChange = this.handleAddInputChange.bind(this);
-    this.handleChange = this.handleChange.bind(this);
-  }
-
-  handleAdd(e) {
-    e.preventDefault();
-    this.props.handleChange(this.state.addUsername, this.props.role);
-    this.setState({addUsername: ""});
-  }
-
-  handleAddInputChange(e) {
-    this.setState({
-      addUsername: e.target.value,
-    });
-  }
-
-  handleChange(e) {
-    e.preventDefault();
-    this.props.handleChange(e.target.name, e.target.value);
-  }
-
-  render() {
-    var users = this.props.users.map(function(user) {
-      return (
-        <tr key={user.username}>
-          <td>{user.fullname}</td>
-          <td>{user.username}</td>
-          <td>
-            {user.locked ?
-              <FormattedMessage {...messages.users_na} />
-            :
-              <select
-                name={user.username}
-                value={user.role}
-                className="form-control"
-                onChange={this.handleChange}
-                disabled={this.props.loading}
-                >
-                {this.props.generalConfig.roles.map(function(role) {
-                  return (
-                    <option value={role} key={role}>{role}</option>
-                    );
-                })}
-                <FormattedMessage {...messages.users_remove_user}>
-                  {(value) => ( <option value="">{value}</option> )}
-                </FormattedMessage>
-              </select>
-            }
-          </td>
-        </tr>
-        );
-    }.bind(this));
-
-    return (
-      <div>
-        <h3>{this.props.tabTitle}</h3>
-        <p className="text-muted">[Membership requests will be shown here]</p>
-        <hr />
-        <form className="form-inline" onSubmit={this.handleAdd}
-              style={{marginBottom: "1em"}}>
-          <div className="form-group">
-            <FormattedMessage {...messages.users_add_user}>
-              {(value) => (
-                <input
-                  type="text" className="form-control"
-                  name="username" placeholder={value}
-                  onChange={this.handleAddInputChange}
-                  value={this.state.addUsername}
-                  style={{marginRight: "1em"}}
-                  />
-                )}
-            </FormattedMessage>
-          </div>
-          <button className="btn btn-primary" disabled={this.props.loading}>
-            <FormattedMessage {...messages.users_add} />
-          </button>
-        </form>
-        {users.length !== 0 &&
-        <table className="table table-hover table-sm">
-          <thead>
-            <tr>
-              <FormattedMessage {...messages.users_fullname} tagName="th" />
-              <FormattedMessage {...messages.users_username} tagName="th" />
-              <FormattedMessage {...messages.users_change_role} tagName="th" />
-            </tr>
-          </thead>
-          <tbody>
-            {users}
-          </tbody>
-        </table>
-        }
-      </div>
-    );
-  }
-
-}
-
-
-export class ChatPanel extends React.Component {
-
-  render() {
-    var networks = [],
-        channel = "#",
-        stillLoading = (
-          typeof this.props.hubConfig.chat_channel === "undefined"
-        );
-
-    if (this.props.hubConfig.chat_channel) {
-      channel = "#" + this.props.hubConfig.chat_channel.replace(/^#*/, "");
-    }
-
-    if (this.props.generalConfig.chat_networks) {
-      networks = this.props.generalConfig.chat_networks.map(
-        function(network, index) {
-          return (
-            <option value={network.domain} key={network.domain}>
-              {network.name} - {network.domain}
-            </option>
-          );
-        }.bind(this)
-      );
-    }
-
-    return (
-      <form onSubmit={(e) => {e.preventDefault();}}>
-        <FormattedMessage {...messages.chat_title} tagName="h3" />
-        <FormattedMessage {...messages.chat_intro_1} tagName="p" />
-        <FormattedMessage {...messages.chat_intro_2} tagName="p" />
-        <div className="form-group">
-          <label htmlFor="hub-settings-chat-channel">
-            <FormattedMessage {...messages.chat_channel_name} />
-          </label>
-          <input
-            type="text" className="form-control" name="chat_channel"
-            id="hub-settings-chat-channel"
-            disabled={stillLoading}
-            onChange={this.props.handleChange}
-            value={channel}
-            />
-          <p className="form-text text-muted">
-            <FormattedMessage {...messages.chat_example} tagName="strong" />
-            <span style={{marginLeft: "0.5em"}}>#fedora-devel</span>
-          </p>
-        </div>
-        <div className="form-group">
-          <label htmlFor="hub-settings-chat-domain">
-            <FormattedMessage {...messages.chat_network} />
-          </label>
-          <select
-            name="chat_domain" className="form-control"
-            id="hub-settings-chat-domain"
-            disabled={stillLoading}
-            onChange={this.props.handleChange}
-            value={this.props.hubConfig.chat_domain || ""}
-            >
-            {networks}
-          </select>
-        </div>
-      </form>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfigPanelChat.jsx b/hubs/static/client/app/core/HubConfigPanelChat.jsx
new file mode 100644
index 0000000..458fd36
--- /dev/null
+++ b/hubs/static/client/app/core/HubConfigPanelChat.jsx
@@ -0,0 +1,106 @@
+import React from 'react';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+
+
+const messages = defineMessages({
+  title: {
+    id: "hubs.core.config.chat.title",
+    defaultMessage: "Chat Settings",
+  },
+  intro_1: {
+    id: "hubs.core.config.chat.intro1",
+    defaultMessage: (
+      "If your team or project has an IRC channel associated with it, you "
+     +"can connect this hub to it via the Hubs chat widget."
+     ),
+  },
+  intro_2: {
+    id: "hubs.core.config.chat.intro2",
+    defaultMessage: "Please indicate your team's IRC channel below:",
+  },
+  channel_name: {
+    id: "hubs.core.config.chat.channel_name",
+    defaultMessage: "Channel name",
+  },
+  example: {
+    id: "hubs.core.config.chat.example",
+    defaultMessage: "Example:",
+  },
+  network: {
+    id: "hubs.core.config.chat.network",
+    defaultMessage: "IRC network",
+  },
+});
+
+
+export default class ChatPanel extends React.Component {
+
+  render() {
+    var networks = [],
+        channel = "#",
+        stillLoading = (
+          typeof this.props.hubConfig.chat_channel === "undefined"
+        );
+
+    if (this.props.hubConfig.chat_channel) {
+      channel = "#" + this.props.hubConfig.chat_channel.replace(/^#*/, "");
+    }
+
+    if (this.props.generalConfig.chat_networks) {
+      networks = this.props.generalConfig.chat_networks.map(
+        function(network, index) {
+          return (
+            <option value={network.domain} key={network.domain}>
+              {network.name} - {network.domain}
+            </option>
+          );
+        }.bind(this)
+      );
+    }
+
+    return (
+      <form onSubmit={(e) => {e.preventDefault();}}>
+        <FormattedMessage {...messages.title} tagName="h3" />
+        <FormattedMessage {...messages.intro_1} tagName="p" />
+        <FormattedMessage {...messages.intro_2} tagName="p" />
+        <div className="form-group">
+          <label htmlFor="hub-settings-chat-channel">
+            <FormattedMessage {...messages.channel_name} />
+          </label>
+          <input
+            type="text" className="form-control" name="chat_channel"
+            id="hub-settings-chat-channel"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={channel}
+            />
+          <p className="form-text text-muted">
+            <FormattedMessage {...messages.example} tagName="strong" />
+            <span style={{marginLeft: "0.5em"}}>#fedora-devel</span>
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-chat-domain">
+            <FormattedMessage {...messages.network} />
+          </label>
+          <select
+            name="chat_domain" className="form-control"
+            id="hub-settings-chat-domain"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.chat_domain || ""}
+            >
+            {networks}
+          </select>
+        </div>
+      </form>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfigPanelGeneral.jsx b/hubs/static/client/app/core/HubConfigPanelGeneral.jsx
new file mode 100644
index 0000000..15d53ab
--- /dev/null
+++ b/hubs/static/client/app/core/HubConfigPanelGeneral.jsx
@@ -0,0 +1,145 @@
+import React from 'react';
+import {
+  defineMessages,
+  FormattedMessage,
+  FormattedHTMLMessage,
+  } from 'react-intl';
+
+
+const messages = defineMessages({
+  title: {
+    id: "hubs.core.config.general.title",
+    defaultMessage: "General Settings",
+  },
+  intro: {
+    id: "hubs.core.config.general.intro",
+    defaultMessage: "Change your global hub parameters here.",
+  },
+  summary: {
+    id: "hubs.core.config.general.summary",
+    defaultMessage: "Summary",
+  },
+  summary_help: {
+    id: "hubs.core.config.general.summary_help",
+    defaultMessage: "This text will be displayed at the top of the hub.",
+  },
+  left_width: {
+    id: "hubs.core.config.general.left_width",
+    defaultMessage: "Left width",
+  },
+  left_width_help: {
+    id: "hubs.core.config.general.left_width_help",
+    defaultMessage: (
+      "Change the proportions of you hub's columns by setting the width of "
+     +"the left column (the right column's width will be {right_width})."
+      ),
+  },
+  visibility: {
+    id: "hubs.core.config.general.visibility",
+    defaultMessage: "Visibility",
+  },
+  visibility_help: {
+    id: "hubs.core.config.general.visibility_help",
+    defaultMessage: (
+      "Public: the hub is visible to anyone.<br />"
+     +"Private: the hub is only visible to members.<br />"
+     +"Preview: some widgets can be made visible to logged-in users only."
+      ),
+  },
+  avatar: {
+    id: "hubs.core.config.general.avatar",
+    defaultMessage: "Avatar",
+  },
+  avatar_help: {
+    id: "hubs.core.config.general.avatar_help",
+    defaultMessage: "An URL to you hub's main image or logo."
+  },
+});
+
+
+export default class GeneralPanel extends React.Component {
+
+  render() {
+    var stillLoading = (typeof this.props.hubConfig.summary === "undefined");
+    var visibilities = this.props.generalConfig.hub_visibility || [];
+    return (
+      <form onSubmit={(e) => {e.preventDefault();}}>
+        <FormattedMessage {...messages.title} tagName="h3" />
+        <FormattedMessage {...messages.intro} tagName="p" />
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-summary">
+            <FormattedMessage {...messages.summary} />
+          </label>
+          <input
+            type="text" className="form-control" name="summary"
+            id="hub-settings-general-summary"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.summary || ""}
+            />
+          <p className="form-text text-muted">
+            <FormattedMessage {...messages.summary_help} />
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-leftwidth">
+            <FormattedMessage {...messages.left_width} />
+          </label>
+          <input
+            type="number" className="form-control" name="left_width"
+            id="hub-settings-general-leftwidth"
+            disabled={stillLoading}
+            min="1" max="11"
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.left_width || ""}
+            />
+          <p className="form-text text-muted">
+            <FormattedMessage
+              {...messages.left_width_help}
+              values={{right_width: 12 - (this.props.hubConfig.left_width || 8)}}
+              />
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-visibility">
+            <FormattedMessage {...messages.visibility} />
+          </label>
+          <select
+            className="form-control" name="visibility"
+            value={this.props.hubConfig.visibility || ""}
+            onChange={this.props.handleChange}
+            disabled={stillLoading}
+            >
+            {visibilities.map(function(value) {
+              return (
+                <option value={value} key={value}>{value}</option>
+                );
+            })}
+          </select>
+          <p className="form-text text-muted">
+            <FormattedHTMLMessage {...messages.visibility_help} />
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-avatar">
+            <FormattedMessage {...messages.avatar} />
+          </label>
+          <input
+            type="text" className="form-control" name="avatar"
+            id="hub-settings-general-avatar"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.avatar || ""}
+            />
+          <p className="form-text text-muted">
+            <FormattedMessage {...messages.avatar_help} />
+          </p>
+        </div>
+      </form>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfigPanelNotImpl.jsx b/hubs/static/client/app/core/HubConfigPanelNotImpl.jsx
new file mode 100644
index 0000000..31803be
--- /dev/null
+++ b/hubs/static/client/app/core/HubConfigPanelNotImpl.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+
+
+export default class NotImplementedPanel extends React.Component {
+
+  render() {
+    return (
+      <div>
+        Not implemented yet.
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfigPanelUser.jsx b/hubs/static/client/app/core/HubConfigPanelUser.jsx
new file mode 100644
index 0000000..d913c79
--- /dev/null
+++ b/hubs/static/client/app/core/HubConfigPanelUser.jsx
@@ -0,0 +1,147 @@
+import React from 'react';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import CompletionInput from '../components/CompletionInput.jsx';
+
+
+const messages = defineMessages({
+  fullname: {
+    id: "hubs.core.config.users.fullname",
+    defaultMessage: "Full name",
+  },
+  username: {
+    id: "hubs.core.config.users.username",
+    defaultMessage: "Username",
+  },
+  change_role: {
+    id: "hubs.core.config.users.change_role",
+    defaultMessage: "Change role",
+  },
+  na: {
+    id: "hubs.core.config.users.na",
+    defaultMessage: "(N/A)",
+  },
+  remove_user: {
+    id: "hubs.core.config.users.remove_user",
+    defaultMessage: "(remove user)",
+  },
+  add_user: {
+    id: "hubs.core.config.users.add_user",
+    defaultMessage: "Add user...",
+  },
+  add: {
+    id: "hubs.core.config.users.add",
+    defaultMessage: "Add",
+  },
+});
+
+
+export default class UserPanel extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      addUsername: "",
+    };
+    this.handleAdd = this.handleAdd.bind(this);
+    this.handleAddInputChange = this.handleAddInputChange.bind(this);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  handleAdd(e) {
+    e.preventDefault();
+    this.props.handleChange(this.state.addUsername, this.props.role);
+    this.setState({addUsername: ""});
+  }
+
+  handleAddInputChange(e) {
+    this.setState({
+      addUsername: e.target.value,
+    });
+  }
+
+  handleChange(e) {
+    e.preventDefault();
+    this.props.handleChange(e.target.name, e.target.value);
+  }
+
+  render() {
+    var users = this.props.users.map(function(user) {
+      return (
+        <tr key={user.username}>
+          <td>{user.fullname}</td>
+          <td>{user.username}</td>
+          <td>
+            {user.locked ?
+              <FormattedMessage {...messages.na} />
+            :
+              <select
+                name={user.username}
+                value={user.role}
+                className="form-control"
+                onChange={this.handleChange}
+                disabled={this.props.loading}
+                >
+                {this.props.generalConfig.roles.map(function(role) {
+                  return (
+                    <option value={role} key={role}>{role}</option>
+                    );
+                })}
+                <FormattedMessage {...messages.remove_user}>
+                  {(value) => ( <option value="">{value}</option> )}
+                </FormattedMessage>
+              </select>
+            }
+          </td>
+        </tr>
+        );
+    }.bind(this));
+
+    return (
+      <div>
+        <h3>{this.props.tabTitle}</h3>
+        <p className="text-muted">[Membership requests will be shown here]</p>
+        <hr />
+        <form className="form-inline" onSubmit={this.handleAdd}
+              style={{marginBottom: "1em"}}>
+          <div className="form-group">
+            <FormattedMessage {...messages.add_user}>
+              {(value) => (
+                <input
+                  type="text" className="form-control"
+                  name="username" placeholder={value}
+                  onChange={this.handleAddInputChange}
+                  value={this.state.addUsername}
+                  style={{marginRight: "1em"}}
+                  />
+                )}
+            </FormattedMessage>
+          </div>
+          <button className="btn btn-primary" disabled={this.props.loading}>
+            <FormattedMessage {...messages.add} />
+          </button>
+        </form>
+        {users.length !== 0 &&
+        <table className="table table-hover table-sm">
+          <thead>
+            <tr>
+              <FormattedMessage {...messages.fullname} tagName="th" />
+              <FormattedMessage {...messages.username} tagName="th" />
+              <FormattedMessage {...messages.change_role} tagName="th" />
+            </tr>
+          </thead>
+          <tbody>
+            {users}
+          </tbody>
+        </table>
+        }
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:

From 2cb5e8bcd7d8f8bab9e40d36e3ae411989d09b6c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 11 2017 12:51:54 +0000
Subject: [PATCH 818/1001] Suggest users in the config panel


---

diff --git a/hubs/static/client/app/components/CompletionInput.jsx b/hubs/static/client/app/components/CompletionInput.jsx
index 9b8b581..a97fc7f 100644
--- a/hubs/static/client/app/components/CompletionInput.jsx
+++ b/hubs/static/client/app/components/CompletionInput.jsx
@@ -20,7 +20,6 @@ export default class CompletionInput extends React.Component {
     this.onChange = this.onChange.bind(this);
     this.onSuggestionsFetchRequested = this.onSuggestionsFetchRequested.bind(this);
     this.onSuggestionsClearRequested = this.onSuggestionsClearRequested.bind(this);
-    this.onSuggestionSelected = this.onSuggestionSelected.bind(this);
     this.loadFromServer = this.loadFromServer.bind(this);
   }
 
@@ -39,20 +38,18 @@ export default class CompletionInput extends React.Component {
     this.setState({
       value: newValue
     });
-  }
-
-  onSuggestionSelected(e, {suggestionValue}) {
     // Transmit a "fake" changed event to the parent, if asked to.
-    if (!this.props.onChange) { return; }
-    const mockedEvent = {
-      type: 'change',
-      target: {
-        type: 'input',
-        name: this.props.name,
-        value: suggestionValue,
-      },
+    if (this.props.onChange) {
+      const mockedEvent = {
+        type: 'change',
+        target: {
+          type: 'input',
+          name: this.props.name,
+          value: newValue,
+        },
+      }
+      this.props.onChange(mockedEvent);
     }
-    this.props.onChange(mockedEvent);
   }
 
   // Autosuggest will call this function every time you need to update
@@ -83,13 +80,16 @@ export default class CompletionInput extends React.Component {
       dataType: 'json',
       cache: false,
       success: function(data) {
-        this.setState({
-          suggestions: data.results,
-          loading: false
-        });
+        var suggestions = data.results;
+        if (this.props.filterResults) {
+          suggestions = suggestions.filter(this.props.filterResults);
+        }
+        this.setState({suggestions: suggestions});
       }.bind(this),
       error: function(xhr, status, err) {
         console.error(this.props.url, status, err.toString());
+      }.bind(this),
+      complete: function(xhr, status) {
         this.setState({loading: false});
       }.bind(this)
     });
@@ -111,13 +111,11 @@ export default class CompletionInput extends React.Component {
     const renderSuggestion = suggestion => suggestion;
     // Autosuggest will pass through all these props to the input element.
     const inputProps = {
-      //placeholder: 'Type a programming language',
-      name: this.props.name,
       className: "form-control",
       value: this.state.value,
-      placeholder: this.props.placeholder,
       onChange: this.onChange,
     };
+    Object.assign(inputProps, this.props.inputProps);
 
     // Render the widget.
     return (
@@ -126,23 +124,21 @@ export default class CompletionInput extends React.Component {
           suggestions={this.state.suggestions}
           onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
           onSuggestionsClearRequested={this.onSuggestionsClearRequested}
-          onSuggestionSelected={this.onSuggestionSelected}
           getSuggestionValue={getSuggestionValue}
           renderSuggestion={renderSuggestion}
           inputProps={inputProps}
         />
-        { this.state.loading ?
-          <span className="form-control-feedback">
-            <img src={this.props.spinner} />
-          </span>
-        : null }
+        <div
+          className="loading-circle"
+          style={this.state.loading ? {display: "block"} : {}}
+          ></div>
       </div>
     );
   }
 
 }
 CompletionInput.defaultProps = {
-    placeholder: "",
+    inputProps: {},
     queryDelay: 800,
 };
 
diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
index fca9e33..f3993d7 100644
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -70,7 +70,7 @@ export default class HubConfig extends React.Component {
 
   getRequestParams() {
     return {
-      url: this.props.url,
+      url: this.props.urls.config,
       dataType: 'json',
       cache: false,
       success: function(data) {
@@ -93,7 +93,7 @@ export default class HubConfig extends React.Component {
       error: function(xhr, status, err) {
         var msg = err.toString();
         if (!msg) { msg = "Error communicating with the server"; }
-        console.error(this.props.url, status, msg);
+        console.error(this.props.urls.config, status, msg);
         this.setState({error: msg});
       }.bind(this),
       complete: function(xhr, status) {
@@ -133,7 +133,6 @@ export default class HubConfig extends React.Component {
   }
 
   handleUserChange(username, role) {
-    console.log("new role", username, role);
     var data = {username: username, role: role};
     this.pushState(data, "role_change");
   }
@@ -195,6 +194,7 @@ export default class HubConfig extends React.Component {
                       handleChange={this.handleUserChange}
                       tabTitle={<FormattedMessage {...messages.owners} />}
                       loading={this.state.loading}
+                      urls={this.props.urls}
                       />
                     <UserPanel
                       users={this.state.users.member}
@@ -203,6 +203,7 @@ export default class HubConfig extends React.Component {
                       handleChange={this.handleUserChange}
                       tabTitle={<FormattedMessage {...messages.members} />}
                       loading={this.state.loading}
+                      urls={this.props.urls}
                       />
                     <ChatPanel
                       hubConfig={this.state.hubConfig}
diff --git a/hubs/static/client/app/core/HubConfigPanelUser.jsx b/hubs/static/client/app/core/HubConfigPanelUser.jsx
index d913c79..3565760 100644
--- a/hubs/static/client/app/core/HubConfigPanelUser.jsx
+++ b/hubs/static/client/app/core/HubConfigPanelUser.jsx
@@ -1,5 +1,6 @@
 import React from 'react';
 import {
+  injectIntl,
   defineMessages,
   FormattedMessage,
   } from 'react-intl';
@@ -48,6 +49,7 @@ export default class UserPanel extends React.Component {
     this.handleAdd = this.handleAdd.bind(this);
     this.handleAddInputChange = this.handleAddInputChange.bind(this);
     this.handleChange = this.handleChange.bind(this);
+    this.filterSuggestedUsers = this.filterSuggestedUsers.bind(this);
   }
 
   handleAdd(e) {
@@ -67,6 +69,11 @@ export default class UserPanel extends React.Component {
     this.props.handleChange(e.target.name, e.target.value);
   }
 
+  filterSuggestedUsers(user) {
+    // Only suggest non-members.
+    return (this.props.users.indexOf(user) === -1);
+  }
+
   render() {
     var users = this.props.users.map(function(user) {
       return (
@@ -99,27 +106,58 @@ export default class UserPanel extends React.Component {
         );
     }.bind(this));
 
+    const IntlCompletionInput = injectIntl(function(props) {
+        return (
+          <CompletionInput
+            inputProps={{
+              name: "username",
+              placeholder: props.intl.formatMessage(messages.add_user),
+            }}
+            url={(
+              props.urls.suggestUsers
+              + "?exclude-role=" + props.role
+            )}
+            onChange={this.handleAddInputChange}
+            />
+            );
+    }.bind(this));
+
     return (
       <div>
         <h3>{this.props.tabTitle}</h3>
-        <p className="text-muted">[Membership requests will be shown here]</p>
-        <hr />
+        {(this.props.role == "member") &&
+          <div>
+            <p className="text-muted">
+              [Membership requests will be shown here]
+            </p>
+            <hr />
+          </div>
+        }
         <form className="form-inline" onSubmit={this.handleAdd}
               style={{marginBottom: "1em"}}>
           <div className="form-group">
             <FormattedMessage {...messages.add_user}>
-              {(value) => (
-                <input
-                  type="text" className="form-control"
-                  name="username" placeholder={value}
+              {(message) => (
+                <CompletionInput
+                  inputProps={{
+                    name: "username",
+                    placeholder: message,
+                    value: this.state.addUsername,
+                  }}
+                  url={(
+                    this.props.urls.suggestUsers
+                    + "?exclude-role=" + this.props.role
+                  )}
                   onChange={this.handleAddInputChange}
-                  value={this.state.addUsername}
-                  style={{marginRight: "1em"}}
                   />
-                )}
+              )}
             </FormattedMessage>
-          </div>
-          <button className="btn btn-primary" disabled={this.props.loading}>
+            </div>
+          <button
+            className="btn btn-primary"
+            disabled={this.props.loading}
+            style={{marginLeft: "1em"}}
+            >
             <FormattedMessage {...messages.add} />
           </button>
         </form>
diff --git a/hubs/static/client/app/widgets/halp/Config.jsx b/hubs/static/client/app/widgets/halp/Config.jsx
index 9e81477..4a65107 100644
--- a/hubs/static/client/app/widgets/halp/Config.jsx
+++ b/hubs/static/client/app/widgets/halp/Config.jsx
@@ -125,10 +125,11 @@ export default class Config extends React.Component {
 
     const IntlCompletionInput = injectIntl((props) => (
         <CompletionInput
-          name="hub-add"
+          inputProps={{
+            name: "hub-add",
+            placeholder: props.intl.formatMessage(messages.placeholder),
+          }}
           url={props.urls.hubs}
-          spinner={props.urls.spinnerCircle}
-          placeholder={props.intl.formatMessage(messages.placeholder)}
           />
     ));
 
diff --git a/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx b/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
index c3d13cd..cbb24b3 100644
--- a/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
+++ b/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
@@ -176,18 +176,25 @@ export default class ModalAllRequests extends Modal {
             </label>
             <div className="col-sm-8">
               <CompletionInput
-                name="people"
+                inputProps={{name: "people"}}
                 url={this.props.urls.requesters}
-                spinner={this.props.urls.spinnerCircle}
-                onChange={this.handleChange} />
+                onChange={this.handleChange}
+                />
             </div>
           </div>
           <div className="form-group">
             <div className="col-sm-offset-4 col-sm-8">
-              <button type="submit" className="btn btn-primary">
+              <button
+                type="submit"
+                className="btn btn-primary"
+                style={{marginRight: "1em"}}
+                >
                 <FormattedMessage {...messages.search_button} />
               </button>
-              { this.state.loading && <img style={{marginLeft: "2em"}} src={this.props.urls.spinner} /> }
+              <div
+                className="loading-circle"
+                style={this.state.loading ? {display: "inline-block"} : {}}
+                ></div>
             </div>
           </div>
         </form>
diff --git a/hubs/static/client/app/widgets/halp/Widget.jsx b/hubs/static/client/app/widgets/halp/Widget.jsx
index 71234a4..91a2fe8 100644
--- a/hubs/static/client/app/widgets/halp/Widget.jsx
+++ b/hubs/static/client/app/widgets/halp/Widget.jsx
@@ -147,7 +147,10 @@ export default class Widget extends React.Component {
             onHubClick={this.onHubClick}
             />
           { this.state.loading ?
-              <img className="center-block" src={this.props.urls.spinner} />
+              <div
+                className="loading-circle center-block"
+                style={{display: "block"}}
+                ></div>
             :
               <div className="requests">
                 {requestNodes}
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 86e35f0..ec6f499 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -141,6 +141,17 @@
       display: none;  /* hidden by default */
   }
 
+.loading-circle {
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+  background: url("../img/spinner-circle.gif") no-repeat center center;
+  vertical-align: bottom;
+  display: none;  /* hidden by default */
+}
+
+
+
 /*
  * Settings
  */
@@ -442,47 +453,36 @@ font-size: 32pt;
 /*
  * Autosuggest
  */
+.completion-input {
+  position: relative;
+}
 .react-autosuggest__suggestions-container {
-    position: absolute;
-    z-index: 10;
-    width: 100%;
-    padding-right: 2em;
+  position: absolute;
+  width: 100%;
+  z-index: 10;
+}
+.react-autosuggest__suggestions-list {
+  list-style: none;
+  padding: 0.3em 0.8em;
+  background-color: #fafafa;
+  border-bottom-left-radius: .25rem;
+  border-bottom-right-radius: .25rem;
+  border: 1px solid #ccc;
+  border-top: none;
+}
+.react-autosuggest__suggestion {
+  cursor: pointer;
 }
-.react-autosuggest__suggestions-container ul {
-    list-style: none;
-    padding: 0.3em 0.8em;
-    background-color: #eee;
-    border-bottom-left-radius: 4px;
-    border-bottom-right-radius: 4px;
+.react-autosuggest__container--open input {
+  border-bottom-left-radius: 0px;
+  border-bottom-right-radius: 0px;
 }
 
-.form-control-feedback {
+.completion-input .loading-circle {
   position: absolute;
   top: 0;
   right: 0;
   z-index: 2;
-  display: block;
-  width: 34px;
-  height: 34px;
-  line-height: 34px;
-  text-align: center;
-  pointer-events: none;
-}
-.input-lg + .form-control-feedback {
-  width: 46px;
-  height: 46px;
-  line-height: 46px;
-}
-.input-sm + .form-control-feedback {
-  width: 30px;
-  height: 30px;
-  line-height: 30px;
-}
-.form-horizontal .form-control-feedback {
-  right: 15px;
-}
-.form-inline .form-control-feedback {
-  top: 0;
 }
 
 
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 35ab48a..2851568 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -390,7 +390,10 @@ $(function() {
   setup_widgets();
   setup_edit_btns();
   setup_settings({
-    url: {{ url_for("hub_config", name=hub.name)|tojson }},
+    urls: {
+        config: {{ url_for("hub_config", name=hub.name)|tojson }},
+        suggestUsers: {{ url_for("hub_config_suggest_users", name=hub.name)|tojson }},
+    }
   });
 
   {% if edit -%}
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
index a0a0d62..ed58d25 100644
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ b/hubs/tests/test_fedora_hubs_flask_api.py
@@ -527,3 +527,61 @@ class HubsAPITest(hubs.tests.APPTest):
             url = '/decause/config?category=config'
             result = self.app.post(url, data={"summary": "Defaced!"})
         self.assertEqual(result.status_code, 403)
+
+    def test_hub_config_suggest_users_no_filter(self):
+        user = tests.FakeAuthorization('ralph')
+        expected = [
+            u.username for u in
+            hubs.models.User.query.order_by(
+                hubs.models.User.username
+            ).all()]
+        # Check without filter
+        with tests.auth_set(app, user):
+            url = '/ralph/config/suggest-users'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertListEqual(result_data["results"], expected)
+
+    def test_hub_config_suggest_users_filter_owners(self):
+        # Filters on owners
+        user = tests.FakeAuthorization('ralph')
+        expected = [
+            u.username for u in
+            hubs.models.User.query.order_by(
+                hubs.models.User.username
+            ).filter(
+                hubs.models.User.username != "ralph"
+            ).all()]
+        with tests.auth_set(app, user):
+            url = '/ralph/config/suggest-users?exclude-role=owner'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertListEqual(result_data["results"], expected)
+
+    def test_hub_config_suggest_users_filter_members(self):
+        # Filters on members
+        user = tests.FakeAuthorization('ralph')
+        hub = hubs.models.Hub.get('ralph')
+        decause = hubs.models.User.query.get("decause")
+        devyani7 = hubs.models.User.query.get("devyani7")
+        hub.subscribe(decause, "member")
+        hub.subscribe(devyani7, "member")
+        expected = [
+            u.username for u in
+            hubs.models.User.query.order_by(
+                hubs.models.User.username
+            ).filter(
+                hubs.models.User.username != "decause",
+                hubs.models.User.username != "devyani7"
+            ).all()]
+        with tests.auth_set(app, user):
+            url = '/ralph/config/suggest-users?exclude-role=member'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertListEqual(result_data["results"], expected)
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index c3ea5f4..d6d05f7 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -246,3 +246,37 @@ def hub_config_post_role_change(hub):
         hub.associations.append(hubs.models.Association(
             hub=hub, user=user, role=role))
     flask.g.db.commit()
+
+
+@app.route('/<name>/config/suggest-users')
+@login_required
+@require_hub_access("config", json=True)
+def hub_config_suggest_users(name):
+    MAX_SUGGESTS = 10
+    hub = get_hub(name)
+    results = flask.g.db.query(hubs.models.User.username)
+    query = flask.request.args.get("q")
+    if query:
+        results = results.filter(
+            hubs.models.User.username.ilike("%{}%".format(query))
+        )
+    exclude = flask.request.args.get("exclude-role")
+    if exclude:
+        exclude_query = flask.g.db.query(
+                hubs.models.User.username
+            ).join(
+                hubs.models.Association
+            ).join(
+                hubs.models.Hub
+            ).filter(
+                hubs.models.Hub.name == hub.name,
+                hubs.models.Association.role == exclude,
+            )
+        results = results.filter(
+            ~hubs.models.User.username.in_(exclude_query)
+            )
+    results = results.order_by(hubs.models.User.username).limit(MAX_SUGGESTS)
+    return flask.jsonify({
+        "status": "OK",
+        "results": [r[0] for r in results],
+        })

From 122c7bb78d71e55053e00c9a093fe3624c884c1d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 11 2017 12:51:55 +0000
Subject: [PATCH 819/1001] Implement review suggestions


---

diff --git a/docs/api/auth.rst b/docs/api/auth.rst
index 36b5cf3..c5e8382 100644
--- a/docs/api/auth.rst
+++ b/docs/api/auth.rst
@@ -1,4 +1,4 @@
-Authentication and authorization
+Authentication and Authorization
 ================================
 
 Authentication is the fact of checking that the user is who they say they are.

From 7dd5b7e37f89f460771d7d7c5894baebbeb4d4ad Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Apr 26 2017 07:53:23 +0000
Subject: [PATCH 820/1001] Support Flask 0.10


---

diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
index c224a77..086e5eb 100644
--- a/hubs/tests/test_api/test_notifications.py
+++ b/hubs/tests/test_api/test_notifications.py
@@ -17,7 +17,7 @@ class TestGetNotifications(hubs.tests.APPTest):
             resp = self.app.get('/{}/notifications/'.format(name))
         self.assertEqual(resp.status_code, 200)
         data = json.loads(resp.get_data(as_text=True))
-        self.assertEqual(data, [])
+        self.assertEqual(data, {"notifications": []})
 
     def test_get_notifications_valid_name(self):
         with hubs.tests.auth_set(app, self.user):
@@ -26,9 +26,9 @@ class TestGetNotifications(hubs.tests.APPTest):
 
         self.assertEqual(resp.status_code, 200)
         data = json.loads(resp.get_data(as_text=True))
-        self.assertEqual(len(data), 1)
+        self.assertEqual(len(data["notifications"]), 1)
 
-        for saved in data:
+        for saved in data["notifications"]:
             self.assertEqual(saved['markup'], 'foo')
             self.assertEqual(saved['link'], 'bar')
 
diff --git a/hubs/views/user.py b/hubs/views/user.py
index 5012aea..8c640af 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -40,7 +40,7 @@ def notifications(user):
     if flask.request.method == 'GET':
         notifications = hubs.models.SavedNotification.by_username(user)
         notifications = [n.__json__() for n in notifications]
-        return flask.jsonify(notifications)
+        return flask.jsonify(dict(notifications=notifications))
 
     if flask.request.method == 'POST':
         data = flask.request.get_json()
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index f1aae71..11ae36e 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -4,7 +4,7 @@ import datetime
 import time
 
 import flask
-from flask.signals import template_rendered, before_render_template
+from flask.signals import template_rendered
 
 from hubs.models import Hub
 from hubs.views.utils import get_hub, require_hub_access
@@ -13,6 +13,11 @@ from hubs.widgets.base import WidgetView
 from .functions import GetRequests
 from .utils import find_hubs_for_msg, paginate
 
+try:
+    from flask.signals import before_render_template
+except ImportError:
+    before_render_template = None  # Flask < 0.11
+
 
 class BaseView(WidgetView):
     """The base view to instantiate the widget."""
@@ -190,8 +195,9 @@ def add_view(hub):
         )
     initial["hubs"] = [hub.name]
     context = dict(mode="add", url=post_url, initial=initial)
-    before_render_template.send(
-        flask.current_app, template=template, context=context)
+    if before_render_template is not None:
+        before_render_template.send(
+            flask.current_app, template=template, context=context)
     output = template.render(**context)
     template_rendered.send(
         flask.current_app, template=template, context=context)
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index f02e777..4fdb936 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -1,9 +1,14 @@
 from __future__ import unicode_literals, absolute_import
 
 import flask
-from flask.signals import template_rendered, before_render_template
+from flask.signals import template_rendered
 from flask.views import View
 
+try:
+    from flask.signals import before_render_template
+except ImportError:
+    before_render_template = None  # Flask < 0.11
+
 
 class WidgetView(View):
     """
@@ -120,8 +125,9 @@ class WidgetView(View):
         else:
             context.update(self.get_extra_context(instance, *args, **kwargs))
             template = self.get_template()
-            before_render_template.send(
-                flask.current_app, template=template, context=context)
+            if before_render_template is not None:
+                before_render_template.send(
+                    flask.current_app, template=template, context=context)
             output = template.render(**context)
             template_rendered.send(
                 flask.current_app, template=template, context=context)
diff --git a/requirements.txt b/requirements.txt
index 74264a8..4a76840 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
 arrow
-bleach
+bleach<2.0.0
 blinker
 datanommer.models
 decorator
diff --git a/tox.ini b/tox.ini
index a77ac69..291e2b9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,12 +1,14 @@
 [tox]
-envlist = py{27,34,35},js,docs,lint
+envlist = py{27,34,35}-flask01{0,1,2},js,docs,lint
 skipsdist = True
 
 
 [testenv]
 usedevelop = True
 deps =
-    -rrequirements.txt
+    flask010: flask>=0.10,<0.11
+    flask011: flask>=0.11,<0.12
+    flask012: flask>=0.12,<0.13
     -rtest-requirements.txt
 setenv =
     HUBS_CONFIG={toxinidir}/hubs/tests/hubs_test.cfg

From 9da845c34b11ee8aca99e10350269e548b63f422 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 821/1001] Exclude the tests themselves from coverage


---

diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..5db0f74
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,5 @@
+[run]
+source = hubs
+omit =
+    hubs/tests/*
+    hubs/migrations/*
diff --git a/setup.cfg b/setup.cfg
index 963de6b..2f576f8 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -2,3 +2,4 @@
 verbosity=2
 nocapture=1
 with-yanc=1
+cover-package=hubs
diff --git a/tox.ini b/tox.ini
index 291e2b9..4c98c45 100644
--- a/tox.ini
+++ b/tox.ini
@@ -17,7 +17,7 @@ whitelist_externals =
     rm
 commands =
     rm -f /var/tmp/fedora-hubs-cache.db*
-    nosetests --with-coverage --cover-erase --cover-package=hubs {posargs:hubs}
+    nosetests --with-coverage --cover-erase {posargs:hubs}
 
 [testenv:js]
 skip_install = True

From c779c14d7068f6541e8eed9e29d269b32ca48e1c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 822/1001] Generate the coverage HTML report


---

diff --git a/.gitignore b/.gitignore
index ce06a7d..c8921e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,4 @@ config
 # tox
 .tox
 .coverage
+htmlcov/
diff --git a/tox.ini b/tox.ini
index 4c98c45..59d93a5 100644
--- a/tox.ini
+++ b/tox.ini
@@ -18,6 +18,7 @@ whitelist_externals =
 commands =
     rm -f /var/tmp/fedora-hubs-cache.db*
     nosetests --with-coverage --cover-erase {posargs:hubs}
+    coverage html
 
 [testenv:js]
 skip_install = True

From a6b1e5cf1d1b892bd1c245cfc6c0737ac8531895 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 823/1001] Move tests around


And split the huge test file we had and that was harder to maintain than
necessary.

---

diff --git a/hubs/tests/test_api/__init__.py b/hubs/tests/test_api/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/hubs/tests/test_api/__init__.py
+++ /dev/null
diff --git a/hubs/tests/test_api/test_hub.py b/hubs/tests/test_api/test_hub.py
deleted file mode 100644
index abf1e3d..0000000
--- a/hubs/tests/test_api/test_hub.py
+++ /dev/null
@@ -1,151 +0,0 @@
-from __future__ import unicode_literals
-
-from six.moves.urllib.parse import urlparse
-
-import hubs.tests
-import hubs.models
-from hubs.app import app
-
-
-def usernames(collection): return [u.username for u in collection]
-
-
-class TestHubSubscribe(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_subscribe_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_subscribe_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
-                                 follow_redirects=True)
-            self.assertEqual(resp.status_code, 200)
-            # Need to find the Hub again to avoid DetachedInstanceError
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username in usernames(h.subscribers))
-
-
-class TestHubUnsubscribe(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_unsubscribe_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_unsubscribe_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        # Need a real user model to subscribe to the hub
-        User = hubs.models.User.by_username(self.user.username)
-        hub.subscribe(User)
-
-        self.assertTrue(self.user.username in usernames(hub.subscribers))
-
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
-                                 follow_redirects=True)
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username not in usernames(h.subscribers))
-
-
-class TestHubStar(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_star_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/star'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_star_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/star'.format(hub.name),
-                                 follow_redirects=True)
-
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username in usernames(h.stargazers))
-
-
-class TestHubUnstar(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_unstar_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_unstar_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        # Need a real user model to subscribe to the hub
-        User = hubs.models.User.by_username(self.user.username)
-        hub.subscribe(User, role='stargazer')
-
-        self.assertTrue(self.user.username in [u.username for
-                                               u in hub.stargazers])
-
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
-                                 follow_redirects=True)
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username not in usernames(h.stargazers))
-
-
-class TestHubJoin(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_join_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/join'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_join_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/join'.format(hub.name),
-                                 follow_redirects=True)
-
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username in usernames(h.members))
-
-
-class TestHubLeave(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_leave_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_star_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        # Need a real user model to subscribe to the hub
-        User = hubs.models.User.by_username(self.user.username)
-        hub.subscribe(User, role='member')
-
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
-                                 follow_redirects=True)
-
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username not in usernames(h.members))
diff --git a/hubs/tests/test_api/test_notifications.py b/hubs/tests/test_api/test_notifications.py
deleted file mode 100644
index 086e5eb..0000000
--- a/hubs/tests/test_api/test_notifications.py
+++ /dev/null
@@ -1,125 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-
-import hubs.tests
-import hubs.models
-from hubs.app import app
-
-
-class TestGetNotifications(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('ralph')
-
-    def test_get_notifications_invalid_name(self):
-        name = 'notarealfasuser'
-
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.get('/{}/notifications/'.format(name))
-        self.assertEqual(resp.status_code, 200)
-        data = json.loads(resp.get_data(as_text=True))
-        self.assertEqual(data, {"notifications": []})
-
-    def test_get_notifications_valid_name(self):
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.get('/{}/notifications/'.format(
-                self.user.username))
-
-        self.assertEqual(resp.status_code, 200)
-        data = json.loads(resp.get_data(as_text=True))
-        self.assertEqual(len(data["notifications"]), 1)
-
-        for saved in data["notifications"]:
-            self.assertEqual(saved['markup'], 'foo')
-            self.assertEqual(saved['link'], 'bar')
-
-
-class TestPostNotifications(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('ralph')
-    valid_payload = {
-        'username': user.username,
-        'markup': 'foobar',
-        'link': 'baz',
-        'secondary_icon': 'http://placekitten.com/g/200/300',
-        'dom_id': 'reallyuniqueuid'
-    }
-
-    invalid_payload = {
-        'username': user.username,
-    }
-
-    def test_post_notification_invalid_user(self):
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post(
-                '/{}/notifications/'.format('notarealfasuser'),
-                data=json.dumps(self.valid_payload),
-                content_type='application/json')
-        self.assertEqual(resp.status_code, 400)
-
-    def test_post_notification_invalid_payload(self):
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post(
-                '/{}/notifications/'.format(self.user.username),
-                data=json.dumps(self.invalid_payload),
-                content_type='application/json')
-        self.assertEqual(resp.status_code, 400)
-
-    def test_post_notification_valid_payload(self):
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post(
-                '/{}/notifications/'.format(self.user.username),
-                data=json.dumps(self.valid_payload),
-                content_type='application/json')
-
-        self.assertEqual(resp.status_code, 200)
-        data = json.loads(resp.get_data(as_text=True))
-        self.assertTrue(isinstance(data, dict))
-
-        notification = data['notification']
-        self.assertEqual(notification['markup'], 'foobar')
-        self.assertEqual(notification['link'], 'baz')
-
-        all_saved = hubs.models.SavedNotification.by_username(
-            self.user.username)
-        self.assertEqual(len(all_saved), 2)
-        all_saved = [s.__json__() for s in all_saved]
-        self.assertTrue(any(str(s['markup']) == self.valid_payload['markup']
-                            for s in all_saved))
-        self.assertTrue(any(str(s['link']) == self.valid_payload['link']
-                            for s in all_saved))
-
-
-class TestDeleteNotifications(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('ralph')
-    notification = hubs.models.SavedNotification(
-        username='ralph',
-        markup='foo',
-        link='bar',
-        secondary_icon='baz',
-        dom_id='qux'
-    )
-
-    def test_delete_notification(self):
-        self.session.add(self.notification)
-        self.session.commit()
-        idx = self.notification.idx
-
-        self.assertIsNotNone(self.notification)
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.delete(
-                '/{}/notifications/{}/'.format(self.user.username, idx)
-            )
-
-        self.assertEqual(resp.status_code, 200)
-        notification = self.session.query(
-            hubs.models.SavedNotification).filter_by(idx=idx).first()
-
-        self.assertIsNone(notification)
-
-    def test_404_on_bad_idx(self):
-        idx = 'thisisastringnotanint'
-
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.delete(
-                '/{}/notifications/{}/'.format(self.user.username, idx)
-            )
-        self.assertEqual(resp.status_code, 404)
diff --git a/hubs/tests/test_fedora_hubs_flask_api.py b/hubs/tests/test_fedora_hubs_flask_api.py
deleted file mode 100644
index ed58d25..0000000
--- a/hubs/tests/test_fedora_hubs_flask_api.py
+++ /dev/null
@@ -1,587 +0,0 @@
-from __future__ import unicode_literals
-
-import unittest
-from six.moves.urllib.parse import urlparse
-
-from flask import json
-from werkzeug.datastructures import ImmutableMultiDict
-
-import hubs
-from hubs import tests
-from hubs.app import app
-
-import hubs.models
-
-
-class HubsAPITest(hubs.tests.APPTest):
-
-    def test_index_logged_out(self):
-        result = self.app.get('/', follow_redirects=False)
-        self.assertEqual(result.status_code, 302)
-        self.assertEqual(urlparse(result.location).path, "/login")
-
-    def test_index_logged_in(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/', follow_redirects=True)
-            # its trying to redirect to login id.fedoraproject.org/openid
-            # assert the status code of the response
-            self.assertEqual(result.status_code, 200)
-            self.assertNotIn(
-                'Not logged in.  Click to <a href="/login">login</a>',
-                result.get_data(as_text=True))
-
-    def test_hub_logged_out(self):
-        with tests.auth_set(app, None):  # check_auth doesn't load in unittest
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            match_expected = r'<h5[^>]*>Ralph</h5>'
-            self.assertRegexpMatches(
-                result.get_data(as_text=True), match_expected)
-            str_expected = 'Not logged in.'
-            self.assertIn(str_expected, result.get_data(as_text=True))
-
-    def test_groups_logged_out(self):
-        result = self.app.get('/groups', follow_redirects=False)
-        # assert the status code of the response
-        self.assertEqual(result.status_code, 302)
-        # this will redirect to fedora.login
-        self.assertEqual(urlparse(result.location).path, "/login")
-
-    def test_groups_logged_in(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/groups', follow_redirects=True)
-            # assert the status code of the response
-            self.assertEqual(result.status_code, 200)
-            self.assertIn("ZOMG -  is the Hub Of The Month!",
-                          result.get_data(as_text=True))
-
-    def test_hub_logged_in(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            self.assertNotIn(
-                'Not logged in.  Click to <a href="/login">login</a>',
-                result.get_data(as_text=True))
-
-    def test_hub_preview(self):
-        hub = hubs.models.Hub.by_name('ralph')
-        hub.config.visibility = "preview"
-        # Preview hubs are accessible to anonymous users (but some
-        # widgets may be restricted).
-        with tests.auth_set(app, None):
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-
-    def test_hub_private(self):
-        hub = hubs.models.Hub.by_name('ralph')
-        hub.config.visibility = "private"
-        self.session.commit()
-        # Private hubs are not accessible to anonymous users.
-        with tests.auth_set(app, None):
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)
-        # But they are accessible to members.
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-
-    def test_hub_json(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/ralph/json', follow_redirects=True)
-        # assert the status code of the response
-        self.assertEqual(result.status_code, 200)
-        data = {
-            "config": {
-                "avatar": "https://seccdn.libravatar.org/avatar/"
-                          "9c9f7784935381befc302fe3c814f9136e7a339"
-                          "53d0318761669b8643f4df55c?s=312&d=retro",
-                'chat_channel': None,
-                'chat_domain': None,
-                "left_width": 8,
-                "summary": "Ralph",
-                "visibility": "public",
-            },
-            "members": ["ralph"],
-            "name": "ralph",
-            "owners": ["ralph"],
-            "subscribers": [],
-            "widgets": [37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 61],
-        }
-        self.assertDictEqual(data, json.loads(result.get_data(as_text=True)))
-
-    def test_hub_private_json(self):
-        hub = hubs.models.Hub.by_name('ralph')
-        hub.config.visibility = "private"
-        self.session.commit()
-        # Private hubs are not accessible to anonymous users.
-        with tests.auth_set(app, None):
-            result = self.app.get('/ralph/json', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)
-        # But they are accessible to members.
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/ralph/json', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-
-    def test_hub_edit_get_logged_out(self):
-        with tests.auth_set(app, None):
-            result = self.app.get('/ralph/edit', follow_redirects=False)
-        self.assertEqual(result.status_code, 302)
-        self.assertEqual(urlparse(result.location).path, "/login")
-
-    def test_hub_edit_get_logged_in_not_owner(self):
-        user = tests.FakeAuthorization('not_ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)
-
-    def test_hub_edit_get_logged_in_owner(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-
-    def test_hub_edit_post_logged_out(self):
-        with tests.auth_set(app, None):
-            result = self.app.post('/ralph/edit', follow_redirects=False)
-        self.assertEqual(result.status_code, 302)
-        self.assertEqual(urlparse(result.location).path, "/login")
-
-    def test_hub_edit_post_logged_in_not_owner(self):
-        user = tests.FakeAuthorization('not_ralph')
-        with tests.auth_set(app, user):
-            result = self.app.post('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)
-
-    def test_hub_edit_post_logged_in_owner_empty_data(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.post('/ralph/edit', data={},
-                                   follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            self.assertNotIn(
-                'Not logged in.  Click to <a href="/login">login</a>',
-                result.get_data(as_text=True))
-            self.assertIn(
-                '<a href="#" class="dropdown-item">Full Name: '
-                'fullname: ralph</a>', result.get_data(as_text=True))
-
-    def test_hub_edit_post_logged_in_owner_valid_data(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            data = ImmutableMultiDict(
-                [('right_indexes[]', u'0'), ('right_indexes[]', u'1'),
-                 ('right_indexes[]', u'2'), ('right_indexes[]', u'3'),
-                 ('right_indexes[]', u'4'), ('right_indexes[]', u'5'),
-                 ('right_indexes[]', u'6'), ('right_indexes[]', u'7'),
-                 ('right_indexes[]', u'8'), ('right_widgets[]', u'32'),
-                 ('right_widgets[]', u'33'), ('right_widgets[]', u'34'),
-                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
-                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
-                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
-                 ('js', u'true'), ('left_indexes[]', u'0'),
-                 ('left_indexes[]', u'1'), ('left_widgets[]', u'31'),
-                 ('left_widgets[]', u'32')])
-            result = self.app.post('/ralph/edit', data=data,
-                                   follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            self.assertEqual(result.get_data(as_text=True), 'ok')
-
-    def test_hub_edit_post_logged_in_owner_invalid_data_1(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            # some indexes and widgets are not integers
-            data = ImmutableMultiDict(
-                [('right_indexes[]', u'0a'), ('right_indexes[]', u'1'),
-                 ('right_indexes[]', u'2'), ('right_indexes[]', u'3'),
-                 ('right_indexes[]', u'4'), ('right_indexes[]', u'5'),
-                 ('right_indexes[]', u'6'), ('right_indexes[]', u'7'),
-                 ('right_indexes[]', u'8'), ('right_widgets[]', u'32'),
-                 ('right_widgets[]', u'33a'), ('right_widgets[]', u'34'),
-                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
-                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
-                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
-                 ('js', u'true'), ('left_indexes[]', u'0a'),
-                 ('left_indexes[]', u'1'), ('left_widgets[]', u'31a'),
-                 ('left_widgets[]', u'32')])
-            result = self.app.post('/ralph/edit', data=data,
-                                   follow_redirects=True)
-            self.assertEqual(result.status_code, 400)
-
-    def test_hub_edit_post_logged_in_owner_invalid_data_2(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            # indexes len don't match widgets len
-            data = ImmutableMultiDict(
-                [('right_indexes[]', u'1'), ('right_indexes[]', u'2'),
-                 ('right_indexes[]', u'3'), ('right_indexes[]', u'4'),
-                 ('right_indexes[]', u'5'), ('right_indexes[]', u'6'),
-                 ('right_indexes[]', u'7'), ('right_indexes[]', u'8'),
-                 ('right_widgets[]', u'32'), ('right_widgets[]', u'34'),
-                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
-                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
-                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
-                 ('js', u'true'), ('left_indexes[]', u'0'),
-                 ('left_indexes[]', u'1'), ('left_widgets[]', u'32')])
-            result = self.app.post('/ralph/edit', data=data,
-                                   follow_redirects=True)
-            self.assertEqual(result.status_code, 400)
-
-    def test_login_already_loggedin(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/login', follow_redirects=False)
-            self.assertEqual(result.status_code, 302)
-            self.assertEqual(
-                urlparse(result.location).path,
-                "/openidc/Authorization")
-
-    def test_hub_add_widget_get_no_args(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/ralph/add', follow_redirects=False)
-        self.assertEqual(result.status_code, 400)
-        expected_str = 'Invalid position provided'
-        self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_hub_add_widget_get_with_args(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/ralph/add?position=right',
-                                  follow_redirects=True)
-        self.assertEqual(result.status_code, 200)
-        page_html = result.get_data(as_text=True)
-        self.assertIn('Adding a widget to hub: ralph', page_html)
-        self.assertIn('<form method="post" action="/ralph/add">', page_html)
-        self.assertIn('<input type="hidden" name="position" value="right" />',
-                      page_html)
-
-    def test_hub_add_widget_post_no_widget_name(self):
-        data = {"position": "left"}
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.post(
-                '/ralph/add', data=data, follow_redirects=False)
-        self.assertEqual(result.status_code, 400)
-        expected_str = 'Invalid request sent'
-        self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_hub_add_widget_post_invalid_widget_name(self):
-        data = {'widget': 'invalid_widget_name',
-                'position': 'right'}
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.post(
-                '/ralph/add', data=data, follow_redirects=False)
-        self.assertEqual(result.status_code, 404)
-        expected_str = 'Unknown widget called'
-        self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_hub_add_widget_post_valid_widget_name_no_args(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            data = {
-                'widget': 'memberships',
-                'position': 'right',
-                }
-            result = self.app.post('/ralph/add', data=data)
-            self.assertEqual(result.status_code, 200)
-            self.assertEqual(
-                json.loads(result.get_data(as_text=True)),
-                {"status": "ADDED"})
-            result = self.app.get('/ralph/edit')
-            self.assertEqual(result.status_code, 200)
-            page_html = result.get_data(as_text=True)
-            self.assertIn('data-url="/ralph/w/memberships/', page_html)
-
-    def test_hub_add_widget_post_valid_widget_name_with_args(self):
-        self.assertEqual(
-            hubs.models.Widget.query.filter(
-                hubs.models.Hub.name == "ralph",
-                hubs.models.Widget.plugin == "about",
-            ).count(), 1)
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            data = {
-                'text': 'text of widget',
-                'position': 'right',
-                }
-            result = self.app.post('/ralph/add/about', data=data,
-                                   follow_redirects=False)
-            self.assertEqual(result.status_code, 200)
-            self.assertEqual(
-                json.loads(result.get_data(as_text=True)),
-                {"status": "ADDED"})
-            self.assertEqual(
-                hubs.models.Widget.query.filter(
-                    hubs.models.Hub.name == "ralph",
-                    hubs.models.Widget.plugin == "about",
-                ).count(), 2)
-
-    def test_hub_edit_widget_get_logged_in(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            result = self.app.get('/ralph/37/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            expected_str = '/ralph/37/edit'
-            self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_hub_edit_widget_get_logged_out(self):
-        result = self.app.get('/ralph/31/edit', follow_redirects=False)
-        self.assertEqual(result.status_code, 302)
-        self.assertEqual(urlparse(result.location).path, "/login")
-
-    def test_hub_edit_widget_post_empty_data_logged_in(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            data = {}
-            url = '/ralph/37/edit'
-            result = self.app.post(url, data=data, follow_redirects=False)
-            self.assertEqual(result.status_code, 302)
-            self.assertEqual(urlparse(result.location).path, '/ralph/edit')
-
-    def test_hub_visit_counter_logged_in(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/visit/decause'
-            result = self.app.get(url)
-            self.assertEqual(
-                json.loads(result.get_data(as_text=True)),
-                {"count": 0})
-
-            result = self.app.post(url)
-            self.assertEqual(
-                json.loads(result.get_data(as_text=True)),
-                {"count": 1})
-
-            # accessing my hub shouldn't increment the count
-            url = 'visit/ralph'
-            result = self.app.post(url)
-            self.assertEqual(result.status_code, 403)
-
-            # visiting no hub while logged should throw a 405
-            url = 'visit/'
-            result = self.app.post(url)
-            self.assertEqual(result.status_code, 405)
-
-            # visiting a hub that doesn't exist should 404
-            url = 'visit/hub-does-not-exist'
-            result = self.app.post(url)
-            self.assertEqual(result.status_code, 404)
-
-    @unittest.skip("Ajax calls don't seem to work in unittests ")
-    def test_hub_vist_counter_logged_in_2(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/visit/decause'
-            result = self.app.get(url)
-            self.assertEqual(result.get_data(as_text=True), '0')
-
-            url = '/decause'
-            result = self.app.get(url, follow_redirects=True)
-
-            url = '/visit/decause'
-            result = self.app.get(url)
-            self.assertEqual(result.get_data(as_text=True), '1')
-
-    def test_hub_add_widget_valid_side(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/ralph/add/about?position=right'
-            result = self.app.get(url)
-            self.assertIn('Adding widget "about" to hub ralph',
-                          result.get_data(as_text=True))
-
-    def test_hub_add_widget_invalid_side(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/ralph/add/about?position=invalid'
-            result = self.app.get(url)
-            self.assertEqual(result.status_code, 400)
-
-    def test_hub_delete(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/ralph/37/delete'  # 37 is widget fedmsgstats for ralph
-            result = self.app.post(url)
-            self.assertEqual(result.status_code, 302)
-            self.assertIn('/ralph/edit', result.get_data(as_text=True))
-
-    def test_source_name(self):
-        with tests.auth_set(app, None):
-            url = '/source/about'
-            result = self.app.get(url)
-            self.assertEqual(result.status_code, 302)
-            expected_str = 'https://pagure.io/fedora-hubs/' \
-                           'blob/develop/f/hubs/widgets/about/__init__.py'
-            self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_source_name_not_existent(self):
-        with tests.auth_set(app, None):
-            url = '/source/notexistent'
-            result = self.app.get(url)
-            self.assertEqual(result.status_code, 404)
-
-    def test_hub_config_get(self):
-        expected = {
-            "hubconfig": {
-                "summary": "Ralph",
-                "left_width": 8,
-                "avatar": (
-                    "https://seccdn.libravatar.org/avatar/9c9f7784935381befc30"
-                    "2fe3c814f9136e7a33953d0318761669b8643f4df55c"
-                    "?s=312&d=retro"
-                    ),
-                "chat_channel": None,
-                "chat_domain": None,
-                "visibility": "public",
-            },
-            "general": {
-                "chat_networks": app.config["CHAT_NETWORKS"],
-                "roles": ["owner", "member"],
-                "hub_visibility": hubs.models.HubConfig.VISIBILITY,
-            },
-            "users": {
-                "member": [],
-                "owner": [{
-                    "fullname": "Ralph",
-                    "locked": True,
-                    "role": "owner",
-                    "username": "ralph",
-                }],
-            },
-        }
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/ralph/config'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertDictEqual(result_data["result"], expected)
-
-    def test_hub_config_post(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/ralph/config?category=config'
-            result = self.app.post(url, data={
-                "summary": "changed value",
-                "chat_domain": "",
-            })
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertEqual(
-            result_data["result"]["hubconfig"]["summary"],
-            "changed value")
-        self.assertEqual(
-            result_data["result"]["hubconfig"]["chat_domain"],
-            app.config["CHAT_NETWORKS"][0]["domain"])
-
-    def test_hub_config_post_unknown_post_data(self):
-        # Unknown POST data is silently ignored
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/ralph/config?category=config'
-            result = self.app.post(url, data={"non_existant": "dummy"})
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "ERROR")
-        self.assertEqual(result_data["message"], "Invalid value(s)")
-        self.assertIn("non_existant", result_data["fields"])
-        self.assertEqual(
-            result_data["fields"]["non_existant"],
-            "Unexpected parameter."
-            )
-
-    def test_hub_config_post_invalid_chat_domain(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/ralph/config?category=config'
-            result = self.app.post(url, data={"chat_domain": "dummy"})
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "ERROR")
-        self.assertEqual(result_data["message"], "Invalid value(s)")
-        self.assertIn("chat_domain", result_data["fields"])
-        self.assertEqual(
-            result_data["fields"]["chat_domain"],
-            "Unsupported chat domain."
-            )
-
-    def test_hub_config_get_unauthorized(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/decause/config'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 403)
-
-    def test_hub_config_post_unauthorized(self):
-        user = tests.FakeAuthorization('ralph')
-        with tests.auth_set(app, user):
-            url = '/decause/config?category=config'
-            result = self.app.post(url, data={"summary": "Defaced!"})
-        self.assertEqual(result.status_code, 403)
-
-    def test_hub_config_suggest_users_no_filter(self):
-        user = tests.FakeAuthorization('ralph')
-        expected = [
-            u.username for u in
-            hubs.models.User.query.order_by(
-                hubs.models.User.username
-            ).all()]
-        # Check without filter
-        with tests.auth_set(app, user):
-            url = '/ralph/config/suggest-users'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertListEqual(result_data["results"], expected)
-
-    def test_hub_config_suggest_users_filter_owners(self):
-        # Filters on owners
-        user = tests.FakeAuthorization('ralph')
-        expected = [
-            u.username for u in
-            hubs.models.User.query.order_by(
-                hubs.models.User.username
-            ).filter(
-                hubs.models.User.username != "ralph"
-            ).all()]
-        with tests.auth_set(app, user):
-            url = '/ralph/config/suggest-users?exclude-role=owner'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertListEqual(result_data["results"], expected)
-
-    def test_hub_config_suggest_users_filter_members(self):
-        # Filters on members
-        user = tests.FakeAuthorization('ralph')
-        hub = hubs.models.Hub.get('ralph')
-        decause = hubs.models.User.query.get("decause")
-        devyani7 = hubs.models.User.query.get("devyani7")
-        hub.subscribe(decause, "member")
-        hub.subscribe(devyani7, "member")
-        expected = [
-            u.username for u in
-            hubs.models.User.query.order_by(
-                hubs.models.User.username
-            ).filter(
-                hubs.models.User.username != "decause",
-                hubs.models.User.username != "devyani7"
-            ).all()]
-        with tests.auth_set(app, user):
-            url = '/ralph/config/suggest-users?exclude-role=member'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertListEqual(result_data["results"], expected)
diff --git a/hubs/tests/test_widgets/__init__.py b/hubs/tests/test_widgets/__init__.py
deleted file mode 100644
index 7d171e4..0000000
--- a/hubs/tests/test_widgets/__init__.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-import unittest
-
-import hubs.models
-from hubs.tests import APPTest, FakeAuthorization
-
-
-class WidgetTest(APPTest):
-
-    plugin = None  # The name in hubs.widgets.registry
-
-    def populate(self):
-        super(WidgetTest, self).populate()
-        hub = hubs.models.Hub.by_name('ralph')
-        widget = hubs.models.Widget(
-            plugin='library',
-            index=51,
-            # We must add a url in the config or it'll crash.
-            _config=json.dumps({"urls": "ralph/"})
-        )
-        hub.widgets.append(widget)
-        self.session.commit()
-
-    def _test_view_authz(self):
-        # Test authorizations on the root view.
-        if not self.plugin:
-            raise unittest.SkipTest
-        hub = hubs.models.Hub.query.get("ralph")
-        widget = self.widget_instance(hub.name, self.plugin)
-        url = '/%s/w/%s/%i/' % (hub.name, self.plugin, widget.idx)
-        # Public
-        self.check_url(url, None, 200)
-        # Preview
-        hub.config.visibility = "preview"
-        widget.visibility = "restricted"
-        self.session.commit()
-        self.check_url(url, None, 403)  # anonymous
-        self.check_url(url, FakeAuthorization('decause'), 200)  # logged-in
-        # Private
-        widget.hub.config.visibility = "private"
-        self.session.commit()
-        self.check_url(url, None, 403)  # anonymous
-        self.check_url(url, FakeAuthorization('decause'), 403)  # logged-in
-        hub.subscribe(hubs.models.User.query.get("decause"), "member")
-        self.check_url(url, FakeAuthorization('decause'), 200)  # member
diff --git a/hubs/tests/test_widgets/test_about.py b/hubs/tests/test_widgets/test_about.py
deleted file mode 100644
index dd00e20..0000000
--- a/hubs/tests/test_widgets/test_about.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-
-from hubs.tests import FakeAuthorization
-from . import WidgetTest
-
-
-class TestAbout(WidgetTest):
-    plugin = 'about'  # The name in hubs.widgets.registry
-
-    def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data['data'], {
-            'text': 'Testing.',
-            'title': "<span class='glyphicon glyphicon-info-sign' "
-                     "aria-hidden='true'></span> About",
-        })
-
-    def test_view_authz(self):
-        self._test_view_authz()
diff --git a/hubs/tests/test_widgets/test_badges.py b/hubs/tests/test_widgets/test_badges.py
deleted file mode 100644
index 3cd2ee2..0000000
--- a/hubs/tests/test_widgets/test_badges.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-
-import hubs.widgets
-from hubs.tests import FakeAuthorization
-from . import WidgetTest
-
-
-class TestBadges(WidgetTest):
-    plugin = 'badges'  # The name in hubs.widgets.registry
-
-    def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertEquals(data['plugin'], 'badges')
-        self.assertIn('assertions', data['data'].keys())
-
-    def test_should_invalidate_wrong_topic(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        # msg = self.get_fedmsg('2016-ebb84660-59e9-4e68-af8f-4e6f49348b88')
-        msg = {'topic': 'hubs.widget.update.WRONG.TOPIC'}
-        module = hubs.widgets.registry[widget.plugin]
-        func = module.get_cached_functions()['GetBadges']
-        result = func(widget).should_invalidate(msg)
-        self.assertFalse(result)
-
-    def test_should_invalidate_wrong_user(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        # msg = self.get_fedmsg('2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f')
-        msg = {'topic': 'fedbadges.badge.award',
-               'msg': {'user': {'username': 'not_ralph'}}}
-        module = hubs.widgets.registry[widget.plugin]
-        func = module.get_cached_functions()['GetBadges']
-        result = func(widget).should_invalidate(msg)
-        self.assertFalse(result)
-
-    def test_should_invalidate_good_match_fedbadges(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
-        msg = {'topic': 'fedbadges.badge.award',
-               'msg': {'user': {'username': 'ralph'}}}
-        module = hubs.widgets.registry[widget.plugin]
-        func = module.get_cached_functions()['GetBadges']
-        result = func(widget).should_invalidate(msg)
-        self.assertTrue(result)
-
-    def test_should_invalidate_good_match_hubswidget(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
-        msg = {'topic': 'hubs.widget.update',
-               'msg': {'widget': {'id': widget.idx + 1}}}
-        module = hubs.widgets.registry[widget.plugin]
-        func = module.get_cached_functions()['GetBadges']
-        result = func(widget).should_invalidate(msg)
-        self.assertTrue(result)
-
-    def test_view_authz(self):
-        self._test_view_authz()
diff --git a/hubs/tests/test_widgets/test_contact.py b/hubs/tests/test_widgets/test_contact.py
deleted file mode 100644
index 3d885d1..0000000
--- a/hubs/tests/test_widgets/test_contact.py
+++ /dev/null
@@ -1,178 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-
-import flask
-import mock
-
-import hubs
-from hubs.models import Hub, Widget
-from hubs.tests import FakeAuthorization, auth_set
-from . import WidgetTest
-
-
-def mocked_requests_get(*args, **kwargs):
-    class MockResponse:  # flake8: noqa
-        def __init__(self, json_data, status_code):
-            self.json_data = json_data
-            self.status_code = status_code
-            self.text = str(json_data)
-        def json(self):
-            return self.json_data
-
-    if '/decause' in args[0]:
-        data = {
-            "current": 0,
-            "decrements": 0,
-            "increments": 0,
-            "release": "f24",
-            "total": 0,
-            "username": "decause"
-        }
-        return MockResponse(json_data=data, status_code=200)
-
-    return MockResponse({}, 404)
-
-def mocked_requests_post(*args, **kwargs):
-    class MockResponse:
-        def __init__(self, json_data, status_code):
-            self.json_data = json_data
-            self.status_code = status_code
-            self.text = str(json_data)
-
-        def json(self):
-            return self.json_data
-    if '/decause' in kwargs['url']:
-        data = {
-            "current": 1,
-            "decrements": 0,
-            "increments": 1,
-            "release": "f24",
-            "total": 1,
-            "username": "decause"
-        }
-        return MockResponse(json_data=data, status_code=200)
-
-    return MockResponse({}, 404)
-
-
-class ContactsTest(WidgetTest):
-
-    plugin = "contact"
-
-    def setUp(self):
-        super(ContactsTest, self).setUp()
-        hub = Hub.by_name('ralph')
-        widget = Widget(
-            plugin='contact',
-            index=1,
-        )
-        hub.widgets.append(widget)
-        self.session.commit()
-        self.widget_idx = widget.idx
-
-    def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data['data'], {
-            'account_age': 'Oct 2010',
-            'email': 'ralph@fedoraproject.org',
-            'ircnick': 'ralph',
-            'karma_url': '/ralph/w/contact/%i/plus-plus/ralph/status'
-                         % widget.idx,
-            'location': 'United States',
-            'timezone': 'UTC',
-            'usergroup': True,
-        })
-
-    def test_view_authz(self):
-        self._test_view_authz()
-
-    @mock.patch('requests.get', side_effect=mocked_requests_get)
-    def test_plus_plus_get_valid(self, mock_get):
-        widget = self.widget_instance("ralph", self.plugin)
-        url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
-            self.widget_idx, "decause")
-        result = self.app.get(url)
-        expected = {
-            "current": 0,
-            "decrements": 0,
-            "increments": 0,
-            "release": "f24",
-            "total": 0,
-            "username": "decause"
-        }
-        self.assertEqual(result.status_code, 200)
-        self.assertEqual(
-            json.loads(result.get_data(as_text=True)),
-            expected)
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_valid(self, mock_post):
-        widget = self.widget_instance("ralph", self.plugin)
-        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
-            self.widget_idx, "decause")
-        user = FakeAuthorization('ralph')
-        with auth_set(hubs.app.app, user):
-            result = self.app.post(url, data={'increment': True})
-            expected = {
-                "current": 1,
-                "decrements": 0,
-                "increments": 1,
-                "release": "f24",
-                "total": 1,
-                "username": "decause"
-            }
-            self.assertEqual(result.status_code, 200)
-            self.assertEqual(
-                json.loads(result.get_data(as_text=True)),
-                expected)
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_myself_error(self, mock_post):
-        widget = self.widget_instance("ralph", self.plugin)
-        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
-            self.widget_idx, "ralph")
-        user = FakeAuthorization('ralph')
-        with auth_set(hubs.app.app, user):
-            result = self.app.post(url, data={'increment': True})
-            self.assertEqual(result.status_code, 403)
-            self.assertEqual(
-                result.get_data(as_text=True),
-                'You may not modify your own karma.')
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
-        widget = self.widget_instance("ralph", self.plugin)
-        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
-            self.widget_idx, "doesnotexist")
-        user = FakeAuthorization('ralph')
-        with auth_set(hubs.app.app, user):
-            result = self.app.post(url, data={'increment': True})
-            self.assertEqual(result.status_code, 404)
-            self.assertEqual(
-                result.get_data(as_text=True),
-                'User does not exist')
-
-    @mock.patch('requests.post', side_effect=mocked_requests_post)
-    def test_plus_plus_post_increment_no_data_error(self, mock_post):
-        widget = self.widget_instance("ralph", self.plugin)
-        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
-            self.widget_idx, "decause")
-        user = FakeAuthorization('ralph')
-        with auth_set(hubs.app.app, user):
-            result = self.app.post(url, data={})
-            self.assertEqual(result.status_code, 400)
-            exp_str = "You must set 'decrement' or 'increment' " \
-                      "with a boolean value in the body"
-            self.assertEqual(result.get_data(as_text=True), exp_str)
-
-    def test_plus_plus_receiver_does_not_exist(self):
-        widget = self.widget_instance("ralph", self.plugin)
-        url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
-            self.widget_idx, "doesnotexist")
-        result = self.app.get(url)
-        self.assertEqual(result.status_code, 404)
-        self.assertEqual(result.get_data(as_text=True), 'User does not exist')
diff --git a/hubs/tests/test_widgets/test_fedmsgstats.py b/hubs/tests/test_widgets/test_fedmsgstats.py
deleted file mode 100644
index 87b5ae0..0000000
--- a/hubs/tests/test_widgets/test_fedmsgstats.py
+++ /dev/null
@@ -1,30 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-
-from hubs.tests import FakeAuthorization
-from . import WidgetTest
-
-
-class TestFedmsgStats(WidgetTest):
-    plugin = 'fedmsgstats'  # The name in hubs.widgets.registry
-
-    def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data['data'], {
-            u'fedmsgs': 83854,
-            u'fedmsgs_text': u'83,854',
-            u'subscribers': [],
-            u'subscribed_to': [],
-            u'subscribers_text': u'0',
-            u'subscribed_text': u'0',
-            u'username': u'ralph',
-            u'hub_subscribe_url': u'/api/hub/ralph/subscribe',
-            u'hub_unsubscribe_url': u'/api/hub/ralph/unsubscribe',
-        })
-
-    def test_view_authz(self):
-        self._test_view_authz()
diff --git a/hubs/tests/test_widgets/test_halp.py b/hubs/tests/test_widgets/test_halp.py
deleted file mode 100644
index ed60356..0000000
--- a/hubs/tests/test_widgets/test_halp.py
+++ /dev/null
@@ -1,465 +0,0 @@
-from __future__ import unicode_literals, absolute_import
-
-import json
-
-from hubs.models import Hub, User
-from hubs.tests import FakeAuthorization
-from hubs.widgets import registry
-from . import WidgetTest
-
-
-SAMPLE_DATA = [
-    {
-        'author': {
-            'url': '/mattdm/', 'name': 'mattdm', 'avatar': None,
-            },
-        'channel': u'#fedora-meeting',
-        'context_url': (
-            'https://meetbot.fedoraproject.org/fedora-meeting/'
-            '2017-03-17/fesco.2017-03-17-16.00.log.html#l-466'
-            ),
-        'date': 1489773443.0,
-        'meeting_topic': 'FESCO (2017-03-17)',
-        'text': ('"How to enable trim on your SSD drive" would '
-                 'be a good Fedora Magazine article'),
-        'urls': [],
-    }, {
-        'author': {
-            'url': '/jkurik/', 'name': 'jkurik', 'avatar': None,
-            },
-        'channel': '#fedora-meeting-2',
-        'context_url': (
-            'https://meetbot.fedoraproject.org/fedora-meeting-2/2017-03-16/'
-            'f26-alpha-readiness-meeting.2017-03-16-19.00.log.html#l-103'),
-        'date': 1489692368.0,
-        'meeting_topic': 'F26 Alpha Readiness Meeting',
-        'text': ('The Marketing team wants to ask for help from '
-                 'Spins, Labs SIGs and DEs SIGs to populate the '
-                 'talking points that help us to marketing people'),
-        'urls': [],
-    }, {
-        'author': {
-            'url': '/stoney/', 'name': 'stoney', 'avatar': None,
-            },
-        'channel': '#foss2serve',
-        'context_url': (
-            'https://meetbot.fedoraproject.org/foss2serve/2017-03-14/'
-            'posse_irc_meeting_1.2.2017-03-14-17.00.log.html#l-187'),
-        'date': 1489512523.0,
-        'meeting_topic': 'POSSE IRC Meeting 1.2',
-        'text': '',
-        'urls': [],
-    }, {
-        'author': {
-            'url': '/nitzmahone/', 'name': 'nitzmahone', 'avatar': None,
-            },
-        'channel': '#ansible-meeting',
-        'context_url': (
-            'https://meetbot.fedoraproject.org/ansible-meeting/2017-03-14/'
-            'windows_working_group.2017-03-14-00.00.log.html#l-130'),
-        'date': 1489451407.0,
-        'meeting_topic': 'Windows Working Group',
-        'text': '',
-        'urls': [],
-    }, {
-        'author': {
-            'url': '/jborean93/', 'name': 'jborean93', 'avatar': None
-            },
-        'channel': '#ansible-meeting',
-        'context_url': (
-            'https://meetbot.fedoraproject.org/ansible-meeting/2017-03-14/'
-            'windows_working_group.2017-03-14-00.00.log.html#l-59'),
-        'date': 1489450330.0,
-        'meeting_topic': 'Windows Working Group',
-        'text': 'with installers win_msi vs win_product',
-        'urls': [],
-    },
-]
-
-
-class HalpViewsTestCase(WidgetTest):
-    plugin = 'halp'  # The name in hubs.widgets.registry
-    maxDiff = None
-
-    def setUp(self):
-        super(HalpViewsTestCase, self).setUp()
-        self.widget = self.widget_instance('ralph', self.plugin)
-        config = self.widget.config
-        config["hubs"] = ["fedora-devel"]
-        config["per_page"] = 3
-        self.widget.config = config
-        infra_hub = Hub.query.get("infra")
-        infra_hub.config.chat_channel = "#fedora-meeting"
-        devyani7 = Hub.query.get("devyani7")
-        devyani7.config.chat_channel = "#fedora-meeting-2"
-        decause = Hub.query.get("decause")
-        decause.config.chat_channel = "#ansible-meeting"
-        dhrish = Hub.query.get("dhrish")
-        dhrish.config.chat_channel = "#foss2serve"
-        self.session.commit()
-        self.session.refresh(self.widget)
-
-    def _get_sample_data_with_hub_keys(self):
-        hub_names = ["infra", "devyani7", "dhrish", "decause", "decause"]
-        data = [req.copy() for req in SAMPLE_DATA]
-        for index, hub_name in enumerate(hub_names):
-            data[index].update({
-                'hub': hub_name,
-                'hubs': [hub_name],
-                })
-        return data
-
-    def test_root(self):
-        response = self.check_url('/ralph/w/halp/%i/' % self.widget.idx)
-        self.assertEqual(response.context["hubs"], ['fedora-devel'])
-
-    def test_view_authz(self):
-        self._test_view_authz()
-
-    def test_json(self):
-        response = self.app.get('/ralph/%i/json' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertEquals(data['plugin'], 'halp')
-        self.assertIn('hubs', data['data'].keys())
-
-    def test_config_add(self):
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/w/halp/add?position=right', user)
-        self.assertEqual(response.context["mode"], "add")
-        self.assertEqual(response.context["initial"], {
-            "hubs": ["ralph"], "per_page": 4,
-            })
-        self.assertEqual(
-            response.context["url"], "/ralph/add/halp?position=right")
-
-    def test_config_edit(self):
-        user = FakeAuthorization('ralph')
-        url = '/ralph/w/halp/%i/config' % self.widget.idx
-        response = self.check_url(url, user)
-        self.assertEqual(response.context["mode"], "edit")
-        self.assertEqual(response.context["initial"], {
-            'hubs': ['fedora-devel'],
-            'per_page': 3,
-            })
-        self.assertEqual(
-            response.context["url"], "/ralph/%i/edit" % self.widget.idx)
-
-    def test_config_authz(self):
-        urls = [
-            '/ralph/w/halp/add',
-            '/ralph/w/halp/%i/config' % self.widget.idx,
-            ]
-        # Anonymous
-        for url in urls:
-            self.check_url(url, None, 403)
-        # Logged-in
-        user = FakeAuthorization('decause')
-        for url in urls:
-            self.check_url(url, user, 403)
-        # Member
-        hub = Hub.query.get("ralph")
-        hub.subscribe(User.query.get("decause"), "member")
-        for url in urls:
-            self.check_url(url, user, 403)
-        # Owner
-        user = FakeAuthorization('ralph')
-        for url in urls:
-            self.check_url(url, user, 200)
-
-    def test_config_hubs_suggest(self):
-        response = self.app.get('/w/halp/hubs')
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data, {
-            'results': ['decause', 'devyani7', 'dhrish', 'i18n', 'infra']
-        })
-        response = self.app.get('/w/halp/hubs?q=de')
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data, {
-            'results': ['decause', 'devyani7']
-        })
-
-    def test_data(self):
-        expected = self._get_sample_data_with_hub_keys()
-        # Test with no hub selected
-        response = self.app.get('/ralph/w/halp/%i/data' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertEqual(data, {"requests": expected[:3]})
-        # Test with the right hub selected
-        response = self.app.get('/ralph/w/halp/%i/data?hubs=decause'
-                                % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertEqual(data, {"requests": expected[3:5]})
-
-    def test_data_wrong_hub(self):
-        # Test with the wrong hub selected
-        response = self.app.get('/ralph/w/halp/%i/data?hubs=ralph'
-                                % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertEqual(data, {"requests": []})
-
-    def test_search_requesters(self):
-        response = self.app.get(
-            '/ralph/w/halp/%i/requesters' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data, {
-            'results': ['jborean93', 'jkurik', 'mattdm', 'nitzmahone',
-                        'stoney']
-        })
-        response = self.app.get(
-            '/ralph/w/halp/%i/requesters?q=j' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data, {
-            'results': ['jborean93', 'jkurik']
-        })
-
-    def test_search_all(self):
-        expected = self._get_sample_data_with_hub_keys()
-        response = self.app.get(
-            '/ralph/w/halp/%i/search' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertEqual(data, {
-            "requests": expected[:3],
-            'page': {
-                'has_next': True,
-                'has_prev': False,
-                'nr': 1,
-                'total_entries': 5,
-                'total_pages': 2,
-                },
-            })
-        # Page 2
-        response = self.app.get(
-            '/ralph/w/halp/%i/search?page=2' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertEqual(data, {
-            "requests": expected[3:],
-            'page': {
-                'has_next': False,
-                'has_prev': True,
-                'nr': 2,
-                'total_entries': 5,
-                'total_pages': 2,
-                },
-            })
-
-    def test_search_hub(self):
-        response = self.app.get(
-            '/ralph/w/halp/%i/search?hubs=infra' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        expected = self._get_sample_data_with_hub_keys()
-        self.assertEqual(data, {
-            "requests": expected[0:1],
-            'page': {
-                'has_next': False,
-                'has_prev': False,
-                'nr': 1,
-                'total_entries': 1,
-                'total_pages': 1
-                },
-            })
-
-    def test_search_people(self):
-        response = self.app.get(
-            '/ralph/w/halp/%i/search?people=nitzmahone' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        expected = self._get_sample_data_with_hub_keys()
-        self.assertEqual(data, {
-            "requests": expected[3:4],
-            'page': {
-                'has_next': False,
-                'has_prev': False,
-                'nr': 1,
-                'total_entries': 1,
-                'total_pages': 1
-                },
-            })
-
-    def test_search_meetingname(self):
-        response = self.app.get(
-            '/ralph/w/halp/%i/search?meetingname=Readiness' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        expected = self._get_sample_data_with_hub_keys()
-        self.assertEqual(data, {
-            "requests": expected[1:2],
-            'page': {
-                'has_next': False,
-                'has_prev': False,
-                'nr': 1,
-                'total_entries': 1,
-                'total_pages': 1
-                },
-            })
-
-    def test_search_date(self):
-        response = self.app.get(
-            '/ralph/w/halp/%i/search?startdate=2017-03-16&enddate=2017-03-17'
-            % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        expected = self._get_sample_data_with_hub_keys()
-        self.assertEqual(data, {
-            "requests": expected[1:2],
-            'page': {
-                'has_next': False,
-                'has_prev': False,
-                'nr': 1,
-                'total_entries': 1,
-                'total_pages': 1
-                },
-            })
-
-
-class HalpFunctionsTestCase(WidgetTest):
-    plugin = 'halp'  # The name in hubs.widgets.registry
-
-    def setUp(self):
-        super(HalpFunctionsTestCase, self).setUp()
-        module = registry[self.plugin]
-        func_class = module.get_cached_functions()['GetRequests']
-        self.widget = self.widget_instance('ralph', self.plugin)
-        self.func = func_class(self.widget)
-        # The tested widget watches the infra hub.
-        config = self.widget.config
-        config["hubs"] = ["infra"]
-        self.widget.config = config
-        # The infra hub works in the fedora-infra channel.
-        infra_hub = Hub.query.filter_by(name="infra").one()
-        infra_hub.config.chat_channel = "#fedora-infra"
-        self.session.commit()
-
-    def test_execute(self):
-        with self.app.application.test_request_context('/'):
-            result = self.func.execute()
-        self.assertEqual(result, SAMPLE_DATA)
-
-    def test_should_invalidate_wrong_topic(self):
-        msg = {'topic': 'hubs.WRONG.TOPIC'}
-        result = self.func.should_invalidate(msg)
-        self.assertFalse(result)
-
-    def test_should_invalidate_wrong_hub(self):
-        # The decause hub works in the fedora-commops channel.
-        decause_hub = Hub.query.filter_by(name="decause").one()
-        decause_hub.config.chat_channel = "#fedora-commops"
-        self.session.commit()
-        msg = {'topic': 'org.fedoraproject.prod.meetbot.meeting.item.help',
-               'msg': {'channel': '#fedora-commops'},
-               }
-        # The decause hub cache would be invalidated, but not ours.
-        result = self.func.should_invalidate(msg)
-        self.assertFalse(result)
-
-    def test_should_invalidate_good_match(self):
-        msg = {'topic': 'org.fedoraproject.prod.meetbot.meeting.item.help',
-               'msg': {'channel': '#fedora-infra'},
-               }
-        result = self.func.should_invalidate(msg)
-        self.assertTrue(result)
-
-
-class PaginateTestCase(WidgetTest):
-
-    def setUp(self):
-        super(PaginateTestCase, self).setUp()
-        from hubs.widgets.halp.utils import paginate  # circular
-        self.paginate = paginate
-        self.values = ["A", "B", "C", "D"]
-
-    def test_base(self):
-        with self.app.application.test_request_context('/'):
-            result = self.paginate(self.values, 3)
-        self.assertListEqual(result[0], self.values[:3])
-        self.assertDictEqual(result[1], {
-            'has_next': True,
-            'has_prev': False,
-            'nr': 1,
-            'total_entries': len(self.values),
-            'total_pages': 2,
-            })
-
-    def test_page_2(self):
-        with self.app.application.test_request_context('/?page=2'):
-            result = self.paginate(self.values, 3)
-        self.assertListEqual(result[0], self.values[3:])
-        self.assertDictEqual(result[1], {
-            'has_next': False,
-            'has_prev': True,
-            'nr': 2,
-            'total_entries': len(self.values),
-            'total_pages': 2,
-            })
-
-    def test_page_0(self):
-        with self.app.application.test_request_context('/?page=0'):
-            result = self.paginate(self.values, 3)
-        self.assertListEqual(result[0], self.values[:3])
-        self.assertDictEqual(result[1], {
-            'has_next': True,
-            'has_prev': False,
-            'nr': 1,
-            'total_entries': len(self.values),
-            'total_pages': 2,
-            })
-
-    def test_invalid_page(self):
-        with self.app.application.test_request_context('/?page=blah'):
-            result = self.paginate(self.values, 3)
-        self.assertListEqual(result[0], self.values[:3])
-        self.assertDictEqual(result[1], {
-            'has_next': True,
-            'has_prev': False,
-            'nr': 1,
-            'total_entries': len(self.values),
-            'total_pages': 2,
-            })
-
-    def test_page_too_high(self):
-        with self.app.application.test_request_context('/?page=3'):
-            result = self.paginate(self.values, 3)
-        self.assertListEqual(result[0], self.values[3:])
-        self.assertDictEqual(result[1], {
-            'has_next': False,
-            'has_prev': True,
-            'nr': 2,
-            'total_entries': len(self.values),
-            'total_pages': 2,
-            })
-
-    def test_single_page(self):
-        values = self.values[:3]
-        with self.app.application.test_request_context('/'):
-            result = self.paginate(values, 3)
-        self.assertListEqual(result[0], values)
-        self.assertDictEqual(result[1], {
-            'has_next': False,
-            'has_prev': False,
-            'nr': 1,
-            'total_entries': len(values),
-            'total_pages': 1,
-            })
-
-    def test_no_value(self):
-        values = []
-        with self.app.application.test_request_context('/'):
-            result = self.paginate(values, 3)
-        self.assertListEqual(result[0], [])
-        self.assertDictEqual(result[1], {
-            'has_next': False,
-            'has_prev': False,
-            'nr': 1,
-            'total_entries': 0,
-            'total_pages': 1,
-            })
diff --git a/hubs/tests/test_widgets/test_library.py b/hubs/tests/test_widgets/test_library.py
deleted file mode 100644
index 6d85ad2..0000000
--- a/hubs/tests/test_widgets/test_library.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-
-from hubs.tests import FakeAuthorization
-from . import WidgetTest
-
-
-class TestLibrary(WidgetTest):
-    plugin = 'library'  # The name in hubs.widgets.registry
-
-    def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
-        data = json.loads(response.get_data(as_text=True))
-        expected_dict = {
-            "config": {
-                "urls": "ralph/"
-            },
-            "data": {
-                'title': 'Library',
-                "urls": [
-                    "<a href=\"ralph/\">ralph/</a>"
-                ],
-            },
-            "description": None,
-            "hub": "ralph",
-            "id": 52,
-            "index": 51,
-            "left": False,
-            "plugin": "library"
-        }
-        self.assertDictEqual(data['data'], expected_dict['data'])
-
-    def test_view_authz(self):
-        self._test_view_authz()
diff --git a/hubs/tests/test_widgets/test_meetings.py b/hubs/tests/test_widgets/test_meetings.py
deleted file mode 100644
index 49f088b..0000000
--- a/hubs/tests/test_widgets/test_meetings.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-
-from hubs.tests import FakeAuthorization
-from . import WidgetTest
-
-
-class TestMeetings(WidgetTest):
-    plugin = 'meetings'
-
-    def test_data_simple(self):
-        team = 'i18n'
-        widget = self.widget_instance(team, self.plugin)
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/%s/%i/json' % (team, widget.idx), user)
-        data = json.loads(response.get_data(as_text=True))
-        calendar_name = data['data']['calendar']
-        self.assertIn(team, calendar_name)
-
-    def test_render_simple(self):
-        team = 'i18n'
-        widget = self.widget_instance(team, self.plugin)
-        user = FakeAuthorization('ralph')
-        url = '/%s/w/%s/%i/' % (team, self.plugin, widget.idx)
-        response = self.check_url(url, user)
-        self.assertIn('i18n', response.get_data(as_text=True))
-        self.assertIn('<strong>Request A New Meeting</strong>',
-                      response.get_data(as_text=True))
-
-    def test_view_authz(self):
-        self._test_view_authz()
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_data_simple
deleted file mode 100644
index 94b3210..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_data_simple
+++ /dev/null
@@ -1,808 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://badges.fedoraproject.org/user/ralph/json
-  response:
-    body: {string: !!python/unicode '{"percent_earned": 47.05882352941176, "assertions":
-        [{"description": "You attended Flock 2013, the Fedora Contributor Conference",
-        "tags": "flock,event,", "issued": 1375373082.0, "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
-        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "gnokii", "last_awarded": 1386188828.0, "percent_earned": 0.404551201011378,
-        "id": "flock-2013-attendee", "times_awarded": 80, "name": "Flock 2013 Attendee"},
-        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
-        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bitlord", "last_awarded": 1452636478.0, "percent_earned": 1.1276864728192162,
-        "id": "tagger-tagger-ii", "times_awarded": 223, "name": "Tagger (Tagger II)"},
-        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
-        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bitlord", "last_awarded": 1452632614.0, "percent_earned": 1.7496839443742098,
-        "id": "junior-tagger-tagger-i", "times_awarded": 346, "name": "Junior Tagger
-        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
-        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
-        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "kldymcx", "last_awarded": 1453391986.0, "percent_earned": 58.063211125158034,
-        "id": "involvement", "times_awarded": 11482, "name": "Involvement"}, {"description":
-        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
-        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
-        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "leifmadsen",
-        "last_awarded": 1453305829.0, "percent_earned": 7.509481668773704, "id": "speak-up!",
-        "times_awarded": 1485, "name": "Speak Up!"}, {"description": "Edited at least
-        10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0, "image":
-        "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
-        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "cnangel",
-        "last_awarded": 1453350349.0, "percent_earned": 4.783817951959545, "id": "junior-editor",
-        "times_awarded": 946, "name": "Junior Editor"}, {"description": "Edited at
-        least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0, "image":
-        "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
-        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "raven",
-        "last_awarded": 1452869625.0, "percent_earned": 3.27180783817952, "id": "associate-editor",
-        "times_awarded": 647, "name": "Associate Editor"}, {"description": "Chaired
-        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
-        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
-        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "farhaan",
-        "last_awarded": 1453312868.0, "percent_earned": 2.735777496839444, "id": "secretary-general",
-        "times_awarded": 541, "name": "Secretary General"}, {"description": "Voted
-        on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
-        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "mastaiza", "last_awarded": 1451951597.0, "percent_earned": 0.5309734513274336,
-        "id": "senior-tagger-tagger-iii", "times_awarded": 105, "name": "Senior Tagger
-        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
-        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
-        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
-        "fale", "last_awarded": 1453273101.0, "percent_earned": 0.9506953223767384,
-        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 188, "name":
-        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
-        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
-        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "cstratak",
-        "last_awarded": 1453310380.0, "percent_earned": 5.734513274336283, "id": "if-you-build-it...-koji-success-i",
-        "times_awarded": 1134, "name": "If you build it... (Koji Success I)"}, {"description":
-        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
-        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
-        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
-        "eischmann", "last_awarded": 1453239619.0, "percent_earned": 4.621997471554994,
-        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 914, "name":
-        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
-        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
-        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "gnat",
-        "last_awarded": 1452623672.0, "percent_earned": 2.634639696586599, "id": "if-you-build-it...-koji-success-iii",
-        "times_awarded": 521, "name": "If you build it... (Koji Success III)"}, {"description":
-        "Ten or more questions and answers on the Ask Fedora system.", "tags": "ask
-        fedora,community,", "issued": 1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
-        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "fedelibre", "last_awarded": 1453367297.0, "percent_earned": 2.5082174462705433,
-        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 496, "name": "Curious
-        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
-        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
-        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
-        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "panos", "last_awarded": 1453375409.0, "percent_earned": 16.293299620733247,
-        "id": "curious-penguin-ask-fedora-i", "times_awarded": 3222, "name": "Curious
-        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
-        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
-        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "quinnrm", "last_awarded": 1453389677.0, "percent_earned": 3.1554993678887486,
-        "id": "riddle-me-this", "times_awarded": 624, "name": "Riddle Me This"}, {"description":
-        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
-        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
-        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "cockpit", "last_awarded": 1453321371.0, "percent_earned": 3.919089759797725,
-        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 775, "name": "You
-        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
-        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
-        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "eischmann", "last_awarded": 1453239295.0, "percent_earned": 3.8280657395701643,
-        "id": "what-goes-up...-koji-failure-i", "times_awarded": 757, "name": "What
-        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
-        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "suraia",
-        "last_awarded": 1452800930.0, "percent_earned": 5.350189633375474, "id": "you-can-call-me-patches-scm-i",
-        "times_awarded": 1058, "name": "You can call me \"Patches\" (SCM I)"}, {"description":
-        "Pushed 400 commits to a Fedora package repository.", "tags": "development,",
-        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png",
-        "first_awarded": 1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "lvrabec", "last_awarded": 1452698912.0, "percent_earned": 0.8748419721871049,
-        "id": "you-can-call-me-patches-scm-iv", "times_awarded": 173, "name": "You
-        can call me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to
-        a Fedora package repository.", "tags": "development,", "issued": 1376076329.0,
-        "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png",
-        "first_awarded": 1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person":
-        "pschiffe", "last_awarded": 1453290910.0, "percent_earned": 2.47787610619469,
-        "id": "you-can-call-me-patches-scm-iii", "times_awarded": 490, "name": "You
-        can call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more
-        koji builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
-        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "ankursinha", "last_awarded": 1452452682.0, "percent_earned": 1.1833122629582806,
-        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 234, "name": "What
-        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
-        builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
-        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "pkilambi", "last_awarded": 1453335472.0, "percent_earned": 2.5486725663716814,
-        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 504, "name": "What
-        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
-        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
-        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "lvrabec", "last_awarded": 1452777318.0, "percent_earned": 0.9152970922882426,
-        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 181, "name":
-        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
-        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
-        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "dhabben", "last_awarded": 1453392166.0, "percent_earned": 4.723135271807838,
-        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 934, "name":
-        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
-        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
-        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
-        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
-        "lovetide", "last_awarded": 1453389567.0, "percent_earned": 11.97471554993679,
-        "id": "junior-badger-badger-i", "times_awarded": 2368, "name": "Junior Badger
-        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
-        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
-        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
-        "jortel", "last_awarded": 1453223123.0, "percent_earned": 5.006321112515803,
-        "id": "like-a-rock-updates-stable-i", "times_awarded": 990, "name": "Like
-        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
-        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "fmuellner", "last_awarded": 1453226784.0, "percent_earned": 2.831858407079646,
-        "id": "perceiving-the-bull-tester-iii", "times_awarded": 560, "name": "Perceiving
-        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
-        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
-        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
-        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "heffer",
-        "last_awarded": 1453162247.0, "percent_earned": 0.6776232616940581, "id":
-        "like-a-rock-updates-stable-iii", "times_awarded": 134, "name": "Like a Rock
-        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
-        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "nshaikh", "last_awarded": 1453381228.0, "percent_earned": 11.625790139064476,
-        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2299, "name": "In
-        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
-        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
-        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
-        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "gnat",
-        "last_awarded": 1453138519.0, "percent_earned": 2.260429835651075, "id": "like-a-rock-updates-stable-ii",
-        "times_awarded": 447, "name": "Like a Rock (Updates-Stable II)"}, {"description":
-        "Partied with Flock 2013 (at the South Carolina Aquarium)", "tags": "party,flock,event,",
-        "issued": 1376252202.0, "image": "https://badges.fedoraproject.org/pngs/tanked.png",
-        "first_awarded": 1376252202.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "gnokii", "last_awarded": 1411656869.0, "percent_earned": 0.3135271807838179,
-        "id": "tanked!", "times_awarded": 62, "name": "Tanked!"}, {"description":
-        "You proposed a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,",
-        "issued": 1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
-        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jsmith", "last_awarded": 1453126870.0, "percent_earned": 0.5967130214917826,
-        "id": "badge-muse-badge-ideas-i", "times_awarded": 118, "name": "Badge Muse
-        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
-        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
-        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
-        "drsn0w", "last_awarded": 1453260519.0, "percent_earned": 9.982300884955752,
-        "id": "bona-fide", "times_awarded": 1974, "name": "Bona Fide"}, {"description":
-        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
-        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
-        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.13147914032869784,
-        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
-        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
-        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
-        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "jmlich", "last_awarded": 1453380139.0, "percent_earned": 1.2541087231352717,
-        "id": "senior-badger-badger-ii", "times_awarded": 248, "name": "Senior Badger
-        (Badger II)"}, {"description": "You pushed your first bodhi update to the
-        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
-        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
-        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "cstratak",
-        "last_awarded": 1453371252.0, "percent_earned": 5.3198482932996205, "id":
-        "is-this-thing-on-updates-testing-i", "times_awarded": 1052, "name": "Is this
-        thing on? (Updates-Testing I)"}, {"description": "Pushed 20 bodhi updates
-        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
-        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
-        "rcritten", "last_awarded": 1452870021.0, "percent_earned": 2.786346396965866,
-        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 551, "name":
-        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
-        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
-        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
-        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "bmbouter",
-        "last_awarded": 1453326365.0, "percent_earned": 3.1099873577749686, "id":
-        "partners-in-crime", "times_awarded": 615, "name": "Partners in Crime"}, {"description":
-        "*(a great struggle, repeated escapes, discipline required)*\nTested and added
-        karma to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
-        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "rbarlow", "last_awarded": 1452797003.0, "percent_earned": 1.592920353982301,
-        "id": "catching-the-bull-tester-iv", "times_awarded": 315, "name": "Catching
-        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
-        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
-        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
-        "first_awarded_person": "jamielinux", "last_awarded_person": "jibecfed", "last_awarded":
-        1451517381.0, "percent_earned": 0.2427307206068268, "id": "master-tagger-tagger-iv",
-        "times_awarded": 48, "name": "Master Tagger (Tagger IV)"}, {"description":
-        "A member of the sysadmin-badges group.  Nothing to see here..  move along.",
-        "tags": "infrastructure,badges,community,", "issued": 1378319150.0, "image":
-        "https://badges.fedoraproject.org/pngs/fas-inside-job.png", "first_awarded":
-        1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
-        "decause", "last_awarded": 1435781009.0, "percent_earned": 0.025284450063211124,
-        "id": "inside-job", "times_awarded": 5, "name": "Inside Job"}, {"description":
-        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
-        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
-        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "jvasallo", "last_awarded": 1453390587.0, "percent_earned": 12.303413400758533,
-        "id": "white-rabbit", "times_awarded": 2433, "name": "White Rabbit"}, {"description":
-        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
-        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
-        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "redandrei", "last_awarded": 1453393896.0, "percent_earned": 4.632111251580278,
-        "id": "mugshot", "times_awarded": 916, "name": "Mugshot"}, {"description":
-        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
-        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
-        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
-        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.08596713021491784,
-        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
-        me, I know what I am doing"}, {"description": "Has used an ansible playbook
-        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
-        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
-        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "sayanchowdhury", "last_awarded": 1449249202.0, "percent_earned": 0.16687737041719342,
-        "id": "maestro", "times_awarded": 33, "name": "Maestro"}, {"description":
-        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
-        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
-        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "aniketkhisti", "last_awarded": 1453384257.0, "percent_earned": 7.691529709228824,
-        "id": "let-me-introduce-myself", "times_awarded": 1521, "name": "Let Me Introduce
-        Myself"}, {"description": "You submitted a bodhi update including multiple
-        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
-        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
-        "suraia", "last_awarded": 1452876478.0, "percent_earned": 1.3299620733249051,
-        "id": "binary-star", "times_awarded": 263, "name": "Binary Star"}, {"description":
-        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
-        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
-        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "cweyl", "last_awarded": 1451604516.0, "percent_earned": 0.6826801517067004,
-        "id": "packager-sponsor", "times_awarded": 135, "name": "Packager Sponsor"},
-        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
-        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "jmlich", "last_awarded": 1453380114.0, "percent_earned": 2.857142857142857,
-        "id": "bloggin-it!-planet-ii", "times_awarded": 565, "name": "Bloggin'' it!
-        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
-        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "fale", "last_awarded": 1452955260.0, "percent_earned": 2.427307206068268,
-        "id": "bloggin-it!-planet-iii", "times_awarded": 480, "name": "Bloggin'' it!
-        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
-        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "m4rtink", "last_awarded": 1451904147.0, "percent_earned": 3.372945638432364,
-        "id": "bloggin-it!-planet-i", "times_awarded": 667, "name": "Bloggin'' it!
-        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
-        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
-        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "jcajka", "last_awarded": 1452784301.0, "percent_earned": 1.729456384323641,
-        "id": "white-hat", "times_awarded": 342, "name": "White Hat"}, {"description":
-        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
-        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
-        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.3994943109987358,
-        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
-        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
-        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
-        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
-        "coralatlas", "last_awarded": 1453259601.0, "percent_earned": 27.95954487989886,
-        "id": "embryo", "times_awarded": 5529, "name": "Embryo"}, {"description":
-        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
-        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
-        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "mastaiza", "last_awarded": 1453293512.0, "percent_earned": 0.8798988621997471,
-        "id": "taming-the-bull-tester-v", "times_awarded": 174, "name": "Taming the
-        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
-        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
-        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "fale", "last_awarded": 1451379096.0, "percent_earned": 0.27307206068268014,
-        "id": "common-bugs-contributor", "times_awarded": 54, "name": "Common Bugs
-        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
-        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
-        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "tomh", "last_awarded": 1453387927.0, "percent_earned": 8.56637168141593,
-        "id": "baby-badger", "times_awarded": 1694, "name": "Baby Badger"}, {"description":
-        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
-        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
-        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "piotrp", "last_awarded": 1449068505.0, "percent_earned": 0.1213653603034134,
-        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 24, "name":
-        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
-        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
-        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
-        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
-        "pfrields", "last_awarded": 1453230770.0, "percent_earned": 1.0821744627054362,
-        "id": "old-yeller", "times_awarded": 214, "name": "Old Yeller"}, {"description":
-        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
-        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
-        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.35903919089759795,
-        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
-        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
-        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
-        "paulcarroty", "last_awarded": 1451415976.0, "percent_earned": 1.5423514538558787,
-        "id": "bloggin-it!-planet-iv", "times_awarded": 305, "name": "Bloggin'' it!
-        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
-        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
-        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "tomh", "last_awarded": 1453043511.0, "percent_earned": 1.6940581542351456,
-        "id": "senior-editor", "times_awarded": 335, "name": "Senior Editor"}, {"description":
-        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
-        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
-        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "nilix007", "last_awarded": 1449026189.0, "percent_earned": 17.754740834386855,
-        "id": "tadpole", "times_awarded": 3511, "name": "Tadpole"}, {"description":
-        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
-        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
-        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
-        "rajalakshmi", "last_awarded": 1449029694.0, "percent_earned": 37.67888748419722,
-        "id": "egg", "times_awarded": 7451, "name": "Egg"}, {"description": "You''ve
-        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
-        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
-        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
-        "jdulaney", "last_awarded": 1446505520.0, "percent_earned": 9.780025284450062,
-        "id": "tadpole-with-legs", "times_awarded": 1934, "name": "Tadpole with Legs"},
-        {"description": "You''re a developer contributing to the Fedora Badges stack",
-        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
-        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "sayanchowdhury", "last_awarded": 1449715315.0, "percent_earned": 0.1011378002528445,
-        "id": "badge-off!", "times_awarded": 20, "name": "Badge Off!"}, {"description":
-        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
-        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "vinumoses", "last_awarded": 1451694870.0, "percent_earned": 0.4753476611883692,
-        "id": "riding-the-bull-home-tester-vi", "times_awarded": 94, "name": "Riding
-        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
-        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
-        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
-        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
-        "aryasaatvik", "last_awarded": 1452796719.0, "percent_earned": 0.6624525916561315,
-        "id": "no-longer-a-ronin", "times_awarded": 131, "name": "No Longer a Ronin"},
-        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
-        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jibecfed", "last_awarded": 1451496270.0, "percent_earned": 0.2579013906447535,
-        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 51, "name":
-        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
-        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
-        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "bitlord", "last_awarded": 1452632607.0, "percent_earned": 1.4563843236409608,
-        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 288, "name":
-        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
-        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
-        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "duffy", "last_awarded": 1451767725.0, "percent_earned": 0.5208596713021492,
-        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 103, "name":
-        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
-        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
-        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "mastaiza", "last_awarded": 1453367728.0, "percent_earned": 0.9254108723135273,
-        "id": "package-tagger-package-tagger-ii", "times_awarded": 183, "name": "Package
-        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
-        DevConf.cz, 2014", "tags": "event,speaker,", "issued": 1390422108.0, "image":
-        "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
-        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
-        "last_awarded": 1420480194.0, "percent_earned": 0.23261694058154236, "id":
-        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
-        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
-        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
-        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "valtri", "last_awarded": 1452814661.0, "percent_earned": 0.38432364096080907,
-        "id": "patches-scm-v", "times_awarded": 76, "name": "Patches (SCM V)"}, {"description":
-        "Created a buildroot override in the koji build system", "tags": "development,",
-        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
-        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
-        "cstratak", "last_awarded": 1453371384.0, "percent_earned": 1.4007585335018964,
-        "id": "override,-you-say", "times_awarded": 277, "name": "Override, you say?"},
-        {"description": "You attended devconf.cz, a yearly Linux and JBoss conference
-        in the Czech Republic", "tags": "event,devconf,", "issued": 1391763090.0,
-        "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png", "first_awarded":
-        1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.3135271807838179,
-        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf Attendee"},
-        {"description": "You are a member of the videos team", "tags": "video,community,",
-        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
-        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
-        "last_awarded_person": "nb", "last_awarded": 1439569573.0, "percent_earned":
-        0.0606826801517067, "id": "videographer", "times_awarded": 12, "name": "Videographer"},
-        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
-        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
-        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "sagitter", "last_awarded": 1450261520.0, "percent_earned": 0.2376738305941846,
-        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 47,
-        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
-        "Successfully completed a copr build", "tags": "development,copr,", "issued":
-        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
-        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "tkral", "last_awarded": 1453372187.0, "percent_earned": 5.719342604298356,
-        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1131, "name":
-        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
-        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
-        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
-        "plfiorini", "last_awarded": 1453366379.0, "percent_earned": 3.706700379266751,
-        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 733, "name":
-        "What goes around comes around (Karma I)"}, {"description": "Tested an update
-        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
-        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
-        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "catanzaro",
-        "last_awarded": 1453387064.0, "percent_earned": 3.3426042983565107, "id":
-        "it-still-works!", "times_awarded": 661, "name": "It still works!"}, {"description":
-        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
-        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
-        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
-        "cstratak", "last_awarded": 1453371258.0, "percent_earned": 4.1466498103666245,
-        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 820, "name":
-        "Take this and call me in the morning"}, {"description": "You posted 40 or
-        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
-        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
-        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
-        "bochecha", "last_awarded": 1452463312.0, "percent_earned": 0.6624525916561315,
-        "id": "bob-loblaw-planet-v", "times_awarded": 131, "name": "Bob Loblaw (Planet
-        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
-        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
-        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "piotrp", "last_awarded": 1452692980.0, "percent_earned": 0.11125158027812895,
-        "id": "like-a-rock-updates-stable-iv", "times_awarded": 22, "name": "Like
-        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
-        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
-        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
-        "potty", "last_awarded": 1448485603.0, "percent_earned": 0.26801517067003794,
-        "id": "lets-do-lunch!", "times_awarded": 53, "name": "Let''s do lunch!"},
-        {"description": "Sip the lemonade away (You deserve it for remembering your
-        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
-        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
-        "first_awarded_person": "shaiton", "last_awarded_person": "piotrp", "last_awarded":
-        1452501182.0, "percent_earned": 0.7433628318584071, "id": "vacation", "times_awarded":
-        147, "name": "Vacation"}, {"description": "You visited the Fedora booth at
-        Pycon, 2014", "tags": "event,python,", "issued": 1397168025.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png",
-        "first_awarded": 1397168025.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "abompard", "last_awarded": 1397573900.0, "percent_earned": 0.05056890012642225,
-        "id": "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
-        {"description": "You submitted feedback for an update in Bodhi after it was
-        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
-        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
-        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "thozza", "last_awarded": 1439904242.0, "percent_earned": 1.441213653603034,
-        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
-        {"description": "You built a package owned by someone else.  It takes a village...",
-        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
-        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
-        "ilgrad", "last_awarded": 1452896392.0, "percent_earned": 2.0126422250316054,
-        "id": "helping-hand", "times_awarded": 398, "name": "Helping Hand"}, {"description":
-        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
-        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
-        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.46523388116308473,
-        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
-        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
-        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
-        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "mcrha",
-        "last_awarded": 1453136709.0, "percent_earned": 0.34892541087231355, "id":
-        "what-goes-up...-koji-failure-iv", "times_awarded": 69, "name": "What goes
-        up... (Koji Failure IV)"}, {"description": "You updated your password with
-        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
-        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
-        "indexengines", "last_awarded": 1453392311.0, "percent_earned": 69.38558786346397,
-        "id": "paranoid-panda", "times_awarded": 13721, "name": "Paranoid Panda"},
-        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
-        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
-        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
-        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
-        "last_awarded": 1408553413.0, "percent_earned": 0.36915297092288246, "id":
-        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
-        {"description": "You have received 10 or more good karma on your bodhi updates",
-        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
-        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "swilkerson", "last_awarded": 1453199550.0, "percent_earned": 1.7951959544879899,
-        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 355, "name":
-        "What goes around comes around (Karma II)"}, {"description": "Edited at least
-        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
-        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
-        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "siwinski",
-        "last_awarded": 1453319029.0, "percent_earned": 0.9810366624525916, "id":
-        "master-editor", "times_awarded": 194, "name": "Master Editor"}, {"description":
-        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
-        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
-        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "mluscon", "last_awarded": 1450742624.0, "percent_earned": 0.5865992414664981,
-        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 116, "name":
-        "What goes around comes around (Karma III)"}, {"description": "  You attended
-        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
-        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
-        "first_awarded": 1405334492.0, "first_awarded_person": "sgallagh", "last_awarded_person":
-        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.6118836915297092,
-        "id": "flock-2014-attendee", "times_awarded": 121, "name": "Flock 2014 Attendee"},
-        {"description": "You completed a run of the kernel regression test suite",
-        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
-        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "devhen", "last_awarded": 1452673329.0, "percent_earned": 0.6573957016434893,
-        "id": "science-kernel-tester-i", "times_awarded": 130, "name": "Science (Kernel
-        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
-        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
-        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
-        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
-        "last_awarded": 1408665317.0, "percent_earned": 0.450063211125158, "id": "party-pirate",
-        "times_awarded": 89, "name": "Party Pirate"}, {"description": "You submitted
-        200 Bodhi updates for an EPEL branch.", "tags": "development,epel,", "issued":
-        1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
-        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
-        "limb", "last_awarded": 1452540830.0, "percent_earned": 0.05562579013906448,
-        "id": "corporate-overlord", "times_awarded": 11, "name": "Corporate Overlord"},
-        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
-        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
-        "greghellings", "last_awarded": 1453354804.0, "percent_earned": 0.34386852085967134,
-        "id": "corporate-shill", "times_awarded": 68, "name": "Corporate Shill"},
-        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
-        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
-        "cstratak", "last_awarded": 1453390902.0, "percent_earned": 2.4829329962073325,
-        "id": "corporate-drone", "times_awarded": 491, "name": "Corporate Drone"},
-        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
-        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
-        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "fale", "last_awarded": 1452297195.0, "percent_earned": 0.17193426042983567,
-        "id": "master-badger-badger-iii", "times_awarded": 34, "name": "Master Badger
-        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
-        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
-        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
-        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
-        "first_awarded_person": "kevin", "last_awarded_person": "heikoada", "last_awarded":
-        1452772620.0, "percent_earned": 0.37926675094816686, "id": "the-bull-transcended-tester-vii",
-        "times_awarded": 75, "name": "The Bull Transcended (Tester VII)"}, {"description":
-        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
-        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
-        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "chrisroberts", "last_awarded": 1439838603.0, "percent_earned": 0.15676359039190896,
-        "id": "dancing-with-toshio", "times_awarded": 31, "name": "Dancing with Toshio"},
-        {"description": "Voted in a supplemental wallpapers election for the Fedora
-        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
-        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
-        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
-        "last_awarded": 1409902273.0, "percent_earned": 0.5562579013906448, "id":
-        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
-        "We''re sorry, but you had one of your badges revoked.  Something must have
-        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
-        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
-        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "iaguis",
-        "last_awarded": 1452874718.0, "percent_earned": 2.0227560050568902, "id":
-        "consolation-prize", "times_awarded": 400, "name": "Consolation Prize"}, {"description":
-        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
-        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
-        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
-        "lovetide", "last_awarded": 1453389559.0, "percent_earned": 12.323640960809103,
-        "id": "crypto-panda", "times_awarded": 2437, "name": "Crypto Panda"}, {"description":
-        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
-        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
-        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "paulotada", "last_awarded": 1453313558.0, "percent_earned": 3.2616940581542355,
-        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 645, "name":
-        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
-        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
-        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "ppisar", "last_awarded": 1447066663.0, "percent_earned": 0.045512010113780026,
-        "id": "mic-check!-updates-testing-v", "times_awarded": 9, "name": "Mic Check!
-        (Updates-Testing V)"}, {"description": "You took ownership of a previously
-        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
-        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
-        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
-        "ohaessler", "last_awarded": 1452768576.0, "percent_earned": 1.3046776232616941,
-        "id": "the-cat-came-back...", "times_awarded": 258, "name": "The cat came
-        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
-        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
-        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
-        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "spot", "last_awarded": 1446145228.0, "percent_earned": 0.09102402022756005,
-        "id": "apprentice-badge-artist-i", "times_awarded": 18, "name": "Apprentice
-        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
-        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
-        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "sandeen", "last_awarded": 1439922999.0, "percent_earned": 0.2831858407079646,
-        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 56, "name":
-        "What goes around comes around (Karma IV)"}, {"description": "You participated
-        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
-        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
-        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
-        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.09102402022756005,
-        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
-        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
-        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
-        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
-        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.3135271807838179,
-        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
-        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
-        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
-        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
-        "rdieter", "last_awarded": 1449536137.0, "percent_earned": 0.03034134007585335,
-        "id": "tectonic!-updates-stable-v", "times_awarded": 6, "name": "Tectonic!
-        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
-        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
-        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
-        "icon", "last_awarded": 1453222652.0, "percent_earned": 4.101137800252844,
-        "id": "associate-badger-badger-1.5", "times_awarded": 811, "name": "Associate
-        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
-        Contributor Conference", "tags": "conference,rochester,events,flock,flock
-        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
-        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
-        "jenneh", "last_awarded": 1441736246.0, "percent_earned": 0.3994943109987358,
-        "id": "flock-2015-attendee", "times_awarded": 79, "name": "FLOCK 2015 Attendee"},
-        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
-        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
-        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
-        "mluscon", "last_awarded": 1453387739.0, "percent_earned": 2.2553729456384324,
-        "id": "macaron-cookie-i", "times_awarded": 446, "name": "Macaron (Cookie I)"},
-        {"description": "Ten people think you''re great, because they''ve given you
-        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
-        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
-        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "walters",
-        "last_awarded": 1452199929.0, "percent_earned": 0.26801517067003794, "id":
-        "chocolate-chip-cookie-ii", "times_awarded": 53, "name": "Chocolate Chip (Cookie
-        II)"}, {"description": "Voted in the supplemental wallpapers election for
-        the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
-        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
-        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.4096080910240202,
-        "id": "nuancier-f22", "times_awarded": 81, "name": "Nuancier (F22)"}, {"description":
-        "You pinned your country in FAS!", "tags": "account,community,", "issued":
-        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
-        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
-        "jvasallo", "last_awarded": 1453390594.0, "percent_earned": 36.86472819216182,
-        "id": "origin", "times_awarded": 7290, "name": "Origin"}, {"description":
-        "You added a new package to the distribution.", "tags": "development,", "issued":
-        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
-        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
-        "tadej", "last_awarded": 1450046737.0, "percent_earned": 2.0480404551201015,
-        "id": "delivery", "times_awarded": 405, "name": "Delivery"}, {"description":
-        "You mapped an upstream project to a Fedora package on release-monitoring.org",
-        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
-        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "pabelanger", "last_awarded": 1453318849.0, "percent_earned": 0.9405815423514539,
-        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 186,
-        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
-        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
-        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
-        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "hguemar", "last_awarded": 1453303231.0, "percent_earned": 0.05056890012642225,
-        "id": "black-and-white-cookie-iii", "times_awarded": 10, "name": "Black and
-        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
-        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
-        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "piotrp", "last_awarded": 1451395906.0, "percent_earned": 0.12642225031605564,
-        "id": "hindenburg-koji-failure-v", "times_awarded": 25, "name": "Hindenburg
-        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
-        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
-        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
-        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ralph", "last_awarded": 1433267989.0, "percent_earned": 0.0050568900126422255,
-        "id": "badge-muse-badges-released-iv", "times_awarded": 1, "name": "Badge
-        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
-        ideas were approved and released.  Superb!", "tags": "community,badges,",
-        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
-        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "eischmann", "last_awarded": 1452092327.0, "percent_earned": 0.035398230088495575,
-        "id": "badge-muse-badges-released-ii", "times_awarded": 7, "name": "Badge
-        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
-        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
-        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
-        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "viveknrt", "last_awarded": 1452876035.0, "percent_earned": 0.11630847029077118,
-        "id": "badge-muse-badges-released-i", "times_awarded": 23, "name": "Badge
-        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
-        ideas were approved and released.  Impressive!", "tags": "community,badges,",
-        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
-        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "ralph", "last_awarded": 1433267996.0, "percent_earned": 0.010113780025284451,
-        "id": "badge-muse-badges-released-iii", "times_awarded": 2, "name": "Badge
-        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
-        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
-        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
-        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.0050568900126422255,
-        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
-        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
-        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
-        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
-        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "jenneh", "last_awarded": 1441736228.0, "percent_earned": 0.37420986093552466,
-        "id": "nom-nom-nom", "times_awarded": 74, "name": "Nom Nom Nom"}, {"description":
-        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
-        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
-        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "alonid", "last_awarded": 1453299407.0, "percent_earned": 2.1238938053097343,
-        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 420, "name":
-        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
-        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
-        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
-        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "onekopaka", "last_awarded": 1451613302.0, "percent_earned": 0.2528445006321113,
-        "id": "rock-the-web!", "times_awarded": 50, "name": "Rock the Web!"}, {"description":
-        "You can speak Python and helped with porting stuff to Python 3", "tags":
-        "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
-        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
-        "toshio", "last_awarded": 1447943130.0, "percent_earned": 0.21238938053097348,
-        "id": "parselmouth", "times_awarded": 42, "name": "Parselmouth"}, {"description":
-        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
-        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
-        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "fale",
-        "last_awarded": 1453212624.0, "percent_earned": 0.38432364096080907, "id":
-        "chief-editor", "times_awarded": 76, "name": "Chief Editor"}, {"description":
-        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
-        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
-        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "pschultz", "last_awarded": 1449025570.0, "percent_earned": 5.926675094816688,
-        "id": "froglet", "times_awarded": 1172, "name": "Froglet"}, {"description":
-        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
-        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
-        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "puiterwijk", "last_awarded": 1450374896.0, "percent_earned": 0.015170670037926675,
-        "id": "pizzelle-cookie-iv", "times_awarded": 3, "name": "Pizzelle (Cookie
-        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
-        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ralph", "last_awarded": 1452873723.0, "percent_earned": 0.0050568900126422255,
-        "id": "silver", "times_awarded": 1, "name": "Silver"}, {"description": "You
-        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
-        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "churchyard", "last_awarded": 1452875228.0, "percent_earned": 0.05056890012642225,
-        "id": "top-10", "times_awarded": 10, "name": "Top 10"}, {"description": "You
-        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
-        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "siwinski", "last_awarded": 1453319241.0, "percent_earned": 0.15676359039190896,
-        "id": "top-100", "times_awarded": 31, "name": "Top 100"}, {"description":
-        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
-        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "fale", "last_awarded": 1453212640.0, "percent_earned": 0.13147914032869784,
-        "id": "top-25", "times_awarded": 26, "name": "Top 25"}, {"description": "You
-        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
-        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "mluscon", "last_awarded": 1453387764.0, "percent_earned": 0.3034134007585335,
-        "id": "top-500", "times_awarded": 60, "name": "Top 500"}], "user": "ralph",
-        "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png"}'}
-    headers:
-      appserver: [proxy11.fedoraproject.org]
-      apptime: [D=23056117]
-      connection: [Keep-Alive]
-      content-length: ['66178']
-      content-type: [application/json; charset=UTF-8]
-      date: ['Thu, 21 Jan 2016 16:41:06 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_good_match b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_good_match
deleted file mode 100644
index bfce42a..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_good_match
+++ /dev/null
@@ -1,60 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy08.fedoraproject.org]
-      apptime: [D=55142]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['1874']
-      content-type: ['*/*']
-      date: ['Thu, 21 Jan 2016 16:41:30 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_topic b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_topic
deleted file mode 100644
index 25e7a53..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_topic
+++ /dev/null
@@ -1,59 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy06.fedoraproject.org]
-      apptime: [D=98106]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['1823']
-      content-type: ['*/*']
-      date: ['Thu, 21 Jan 2016 16:41:31 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_user b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_user
deleted file mode 100644
index 44ea8bf..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_about.TestBadges.test_should_invalidate_wrong_user
+++ /dev/null
@@ -1,62 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f
-  response:
-    body:
-      string: !!binary |
-        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
-        CwAA
-    headers:
-      appserver: [proxy10.phx2.fedoraproject.org]
-      apptime: [D=12673]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['1941']
-      content-type: ['*/*']
-      date: ['Thu, 21 Jan 2016 16:41:31 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_data_simple
deleted file mode 100644
index e4c8d8d..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_data_simple
+++ /dev/null
@@ -1,810 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://badges.fedoraproject.org/user/ralph/json
-  response:
-    body: {string: !!python/unicode '{"percent_earned": 47.05882352941176, "assertions":
-        [{"description": "You attended Flock 2013, the Fedora Contributor Conference",
-        "tags": "flock,event,", "issued": 1375373082.0, "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
-        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "gnokii", "last_awarded": 1386188828.0, "percent_earned": 0.4045921205684519,
-        "id": "flock-2013-attendee", "times_awarded": 80, "name": "Flock 2013 Attendee"},
-        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
-        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bitlord", "last_awarded": 1452636478.0, "percent_earned": 1.1278005360845598,
-        "id": "tagger-tagger-ii", "times_awarded": 223, "name": "Tagger (Tagger II)"},
-        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
-        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bitlord", "last_awarded": 1452632614.0, "percent_earned": 1.7498609214585545,
-        "id": "junior-tagger-tagger-i", "times_awarded": 346, "name": "Junior Tagger
-        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
-        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
-        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "fishers1967", "last_awarded": 1453390941.0, "percent_earned": 58.06402670307996,
-        "id": "involvement", "times_awarded": 11481, "name": "Involvement"}, {"description":
-        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
-        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
-        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "leifmadsen",
-        "last_awarded": 1453305829.0, "percent_earned": 7.510241238051889, "id": "speak-up!",
-        "times_awarded": 1485, "name": "Speak Up!"}, {"description": "Edited at least
-        10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0, "image":
-        "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
-        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "cnangel",
-        "last_awarded": 1453350349.0, "percent_earned": 4.784301825721944, "id": "junior-editor",
-        "times_awarded": 946, "name": "Junior Editor"}, {"description": "Edited at
-        least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0, "image":
-        "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
-        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "raven",
-        "last_awarded": 1452869625.0, "percent_earned": 3.272138775097355, "id": "associate-editor",
-        "times_awarded": 647, "name": "Associate Editor"}, {"description": "Chaired
-        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
-        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
-        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "farhaan",
-        "last_awarded": 1453312868.0, "percent_earned": 2.7360542153441565, "id":
-        "secretary-general", "times_awarded": 541, "name": "Secretary General"}, {"description":
-        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
-        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
-        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "mastaiza", "last_awarded": 1451951597.0, "percent_earned": 0.5310271582460933,
-        "id": "senior-tagger-tagger-iii", "times_awarded": 105, "name": "Senior Tagger
-        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
-        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
-        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
-        "fale", "last_awarded": 1453273101.0, "percent_earned": 0.950791483335862,
-        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 188, "name":
-        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
-        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
-        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "cstratak",
-        "last_awarded": 1453310380.0, "percent_earned": 5.735093309057806, "id": "if-you-build-it...-koji-success-i",
-        "times_awarded": 1134, "name": "If you build it... (Koji Success I)"}, {"description":
-        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
-        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
-        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
-        "eischmann", "last_awarded": 1453239619.0, "percent_earned": 4.622464977494563,
-        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 914, "name":
-        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
-        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
-        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "gnat",
-        "last_awarded": 1452623672.0, "percent_earned": 2.6349061852020434, "id":
-        "if-you-build-it...-koji-success-iii", "times_awarded": 521, "name": "If you
-        build it... (Koji Success III)"}, {"description": "Ten or more questions and
-        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
-        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
-        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "fedelibre", "last_awarded": 1453367297.0, "percent_earned": 2.508471147524402,
-        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 496, "name": "Curious
-        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
-        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
-        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
-        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "panos", "last_awarded": 1453375409.0, "percent_earned": 16.2949476558944,
-        "id": "curious-penguin-ask-fedora-i", "times_awarded": 3222, "name": "Curious
-        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
-        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
-        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "quinnrm", "last_awarded": 1453389677.0, "percent_earned": 3.155818540433925,
-        "id": "riddle-me-this", "times_awarded": 624, "name": "Riddle Me This"}, {"description":
-        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
-        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
-        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "cockpit", "last_awarded": 1453321371.0, "percent_earned": 3.919486168006878,
-        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 775, "name": "You
-        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
-        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
-        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "eischmann", "last_awarded": 1453239295.0, "percent_earned": 3.8284529408789765,
-        "id": "what-goes-up...-koji-failure-i", "times_awarded": 757, "name": "What
-        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
-        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "suraia",
-        "last_awarded": 1452800930.0, "percent_earned": 5.3507307945177764, "id":
-        "you-can-call-me-patches-scm-i", "times_awarded": 1058, "name": "You can call
-        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
-        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "lvrabec",
-        "last_awarded": 1452698912.0, "percent_earned": 0.8749304607292773, "id":
-        "you-can-call-me-patches-scm-iv", "times_awarded": 173, "name": "You can call
-        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
-        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "pschiffe",
-        "last_awarded": 1453290910.0, "percent_earned": 2.4781267384817682, "id":
-        "you-can-call-me-patches-scm-iii", "times_awarded": 490, "name": "You can
-        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
-        builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
-        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "ankursinha", "last_awarded": 1452452682.0, "percent_earned": 1.183431952662722,
-        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 234, "name": "What
-        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
-        builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
-        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "pkilambi", "last_awarded": 1453335472.0, "percent_earned": 2.548930359581247,
-        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 504, "name": "What
-        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
-        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
-        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "lvrabec", "last_awarded": 1452777318.0, "percent_earned": 0.9153896727861224,
-        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 181, "name":
-        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
-        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
-        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "stevenmerrill", "last_awarded": 1453314068.0, "percent_earned": 4.718555606129571,
-        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 933, "name":
-        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
-        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
-        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
-        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
-        "lovetide", "last_awarded": 1453389567.0, "percent_earned": 11.975926768826177,
-        "id": "junior-badger-badger-i", "times_awarded": 2368, "name": "Junior Badger
-        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
-        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
-        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
-        "jortel", "last_awarded": 1453223123.0, "percent_earned": 5.006827492034593,
-        "id": "like-a-rock-updates-stable-i", "times_awarded": 990, "name": "Like
-        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
-        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "fmuellner", "last_awarded": 1453226784.0, "percent_earned": 2.8321448439791634,
-        "id": "perceiving-the-bull-tester-iii", "times_awarded": 560, "name": "Perceiving
-        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
-        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
-        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
-        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "heffer",
-        "last_awarded": 1453162247.0, "percent_earned": 0.677691801952157, "id": "like-a-rock-updates-stable-iii",
-        "times_awarded": 134, "name": "Like a Rock (Updates-Stable III)"}, {"description":
-        "*(aimless searching, only the sound of cicadas)*\nTested and added karma
-        to 1 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,", "issued":
-        1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "nshaikh", "last_awarded": 1453381228.0, "percent_earned": 11.626966064835887,
-        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2299, "name": "In
-        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
-        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
-        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
-        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "gnat",
-        "last_awarded": 1453138519.0, "percent_earned": 2.260658473676225, "id": "like-a-rock-updates-stable-ii",
-        "times_awarded": 447, "name": "Like a Rock (Updates-Stable II)"}, {"description":
-        "Partied with Flock 2013 (at the South Carolina Aquarium)", "tags": "party,flock,event,",
-        "issued": 1376252202.0, "image": "https://badges.fedoraproject.org/pngs/tanked.png",
-        "first_awarded": 1376252202.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "gnokii", "last_awarded": 1411656869.0, "percent_earned": 0.31355889344055027,
-        "id": "tanked!", "times_awarded": 62, "name": "Tanked!"}, {"description":
-        "You proposed a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,",
-        "issued": 1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
-        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jsmith", "last_awarded": 1453126870.0, "percent_earned": 0.5967733778384666,
-        "id": "badge-muse-badge-ideas-i", "times_awarded": 118, "name": "Badge Muse
-        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
-        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
-        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
-        "drsn0w", "last_awarded": 1453260519.0, "percent_earned": 9.98331057502655,
-        "id": "bona-fide", "times_awarded": 1974, "name": "Bona Fide"}, {"description":
-        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
-        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
-        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.13149243918474687,
-        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
-        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
-        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
-        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "jmlich", "last_awarded": 1453380139.0, "percent_earned": 1.254235573762201,
-        "id": "senior-badger-badger-ii", "times_awarded": 248, "name": "Senior Badger
-        (Badger II)"}, {"description": "You pushed your first bodhi update to the
-        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
-        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
-        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "cstratak",
-        "last_awarded": 1453371252.0, "percent_earned": 5.3203863854751425, "id":
-        "is-this-thing-on-updates-testing-i", "times_awarded": 1052, "name": "Is this
-        thing on? (Updates-Testing I)"}, {"description": "Pushed 20 bodhi updates
-        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
-        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
-        "rcritten", "last_awarded": 1452870021.0, "percent_earned": 2.7866282304152126,
-        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 551, "name":
-        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
-        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
-        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
-        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "bmbouter",
-        "last_awarded": 1453326365.0, "percent_earned": 3.1103019268699743, "id":
-        "partners-in-crime", "times_awarded": 615, "name": "Partners in Crime"}, {"description":
-        "*(a great struggle, repeated escapes, discipline required)*\nTested and added
-        karma to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
-        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "rbarlow", "last_awarded": 1452797003.0, "percent_earned": 1.5930814747382795,
-        "id": "catching-the-bull-tester-iv", "times_awarded": 315, "name": "Catching
-        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
-        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
-        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
-        "first_awarded_person": "jamielinux", "last_awarded_person": "jibecfed", "last_awarded":
-        1451517381.0, "percent_earned": 0.24275527234107114, "id": "master-tagger-tagger-iv",
-        "times_awarded": 48, "name": "Master Tagger (Tagger IV)"}, {"description":
-        "A member of the sysadmin-badges group.  Nothing to see here..  move along.",
-        "tags": "infrastructure,badges,community,", "issued": 1378319150.0, "image":
-        "https://badges.fedoraproject.org/pngs/fas-inside-job.png", "first_awarded":
-        1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
-        "decause", "last_awarded": 1435781009.0, "percent_earned": 0.025287007535528244,
-        "id": "inside-job", "times_awarded": 5, "name": "Inside Job"}, {"description":
-        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
-        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
-        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "jvasallo", "last_awarded": 1453390587.0, "percent_earned": 12.304657866788045,
-        "id": "white-rabbit", "times_awarded": 2433, "name": "White Rabbit"}, {"description":
-        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
-        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
-        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "hahnsaja", "last_awarded": 1453391469.0, "percent_earned": 4.617407575987458,
-        "id": "mugshot", "times_awarded": 913, "name": "Mugshot"}, {"description":
-        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
-        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
-        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
-        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.08597582562079603,
-        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
-        me, I know what I am doing"}, {"description": "Has used an ansible playbook
-        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
-        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
-        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "sayanchowdhury", "last_awarded": 1449249202.0, "percent_earned": 0.1668942497344864,
-        "id": "maestro", "times_awarded": 33, "name": "Maestro"}, {"description":
-        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
-        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
-        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "aniketkhisti", "last_awarded": 1453384257.0, "percent_earned": 7.6923076923076925,
-        "id": "let-me-introduce-myself", "times_awarded": 1521, "name": "Let Me Introduce
-        Myself"}, {"description": "You submitted a bodhi update including multiple
-        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
-        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
-        "suraia", "last_awarded": 1452876478.0, "percent_earned": 1.3300965963687856,
-        "id": "binary-star", "times_awarded": 263, "name": "Binary Star"}, {"description":
-        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
-        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
-        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "cweyl", "last_awarded": 1451604516.0, "percent_earned": 0.6827492034592627,
-        "id": "packager-sponsor", "times_awarded": 135, "name": "Packager Sponsor"},
-        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
-        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "jmlich", "last_awarded": 1453380114.0, "percent_earned": 2.8574318515146917,
-        "id": "bloggin-it!-planet-ii", "times_awarded": 565, "name": "Bloggin'' it!
-        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
-        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "fale", "last_awarded": 1452955260.0, "percent_earned": 2.4275527234107117,
-        "id": "bloggin-it!-planet-iii", "times_awarded": 480, "name": "Bloggin'' it!
-        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
-        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "m4rtink", "last_awarded": 1451904147.0, "percent_earned": 3.373286805239468,
-        "id": "bloggin-it!-planet-i", "times_awarded": 667, "name": "Bloggin'' it!
-        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
-        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
-        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "jcajka", "last_awarded": 1452784301.0, "percent_earned": 1.729631315430132,
-        "id": "white-hat", "times_awarded": 342, "name": "White Hat"}, {"description":
-        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
-        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
-        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.3995347190613463,
-        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
-        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
-        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
-        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
-        "coralatlas", "last_awarded": 1453259601.0, "percent_earned": 27.962372932787133,
-        "id": "embryo", "times_awarded": 5529, "name": "Embryo"}, {"description":
-        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
-        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
-        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "mastaiza", "last_awarded": 1453293512.0, "percent_earned": 0.8799878622363829,
-        "id": "taming-the-bull-tester-v", "times_awarded": 174, "name": "Taming the
-        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
-        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
-        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "fale", "last_awarded": 1451379096.0, "percent_earned": 0.27309968138370505,
-        "id": "common-bugs-contributor", "times_awarded": 54, "name": "Common Bugs
-        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
-        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
-        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "tomh", "last_awarded": 1453387927.0, "percent_earned": 8.56723815303697,
-        "id": "baby-badger", "times_awarded": 1694, "name": "Baby Badger"}, {"description":
-        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
-        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
-        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "piotrp", "last_awarded": 1449068505.0, "percent_earned": 0.12137763617053557,
-        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 24, "name":
-        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
-        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
-        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
-        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
-        "pfrields", "last_awarded": 1453230770.0, "percent_earned": 1.082283922520609,
-        "id": "old-yeller", "times_awarded": 214, "name": "Old Yeller"}, {"description":
-        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
-        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
-        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.3590755070045011,
-        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
-        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
-        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
-        "paulcarroty", "last_awarded": 1451415976.0, "percent_earned": 1.542507459667223,
-        "id": "bloggin-it!-planet-iv", "times_awarded": 305, "name": "Bloggin'' it!
-        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
-        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
-        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "tomh", "last_awarded": 1453043511.0, "percent_earned": 1.6942295048803926,
-        "id": "senior-editor", "times_awarded": 335, "name": "Senior Editor"}, {"description":
-        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
-        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
-        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "nilix007", "last_awarded": 1449026189.0, "percent_earned": 17.756536691447934,
-        "id": "tadpole", "times_awarded": 3511, "name": "Tadpole"}, {"description":
-        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
-        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
-        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
-        "rajalakshmi", "last_awarded": 1449029694.0, "percent_earned": 37.68269862944419,
-        "id": "egg", "times_awarded": 7451, "name": "Egg"}, {"description": "You''ve
-        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
-        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
-        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
-        "jdulaney", "last_awarded": 1446505520.0, "percent_earned": 9.781014514742326,
-        "id": "tadpole-with-legs", "times_awarded": 1934, "name": "Tadpole with Legs"},
-        {"description": "You''re a developer contributing to the Fedora Badges stack",
-        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
-        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "sayanchowdhury", "last_awarded": 1449715315.0, "percent_earned": 0.10114803014211297,
-        "id": "badge-off!", "times_awarded": 20, "name": "Badge Off!"}, {"description":
-        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
-        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "vinumoses", "last_awarded": 1451694870.0, "percent_earned": 0.475395741667931,
-        "id": "riding-the-bull-home-tester-vi", "times_awarded": 94, "name": "Riding
-        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
-        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
-        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
-        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
-        "aryasaatvik", "last_awarded": 1452796719.0, "percent_earned": 0.66251959743084,
-        "id": "no-longer-a-ronin", "times_awarded": 131, "name": "No Longer a Ronin"},
-        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
-        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jibecfed", "last_awarded": 1451496270.0, "percent_earned": 0.2579274768623881,
-        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 51, "name":
-        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
-        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
-        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "bitlord", "last_awarded": 1452632607.0, "percent_earned": 1.456531634046427,
-        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 288, "name":
-        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
-        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
-        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "duffy", "last_awarded": 1451767725.0, "percent_earned": 0.5209123552318818,
-        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 103, "name":
-        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
-        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
-        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "mastaiza", "last_awarded": 1453367728.0, "percent_earned": 0.9255044758003338,
-        "id": "package-tagger-package-tagger-ii", "times_awarded": 183, "name": "Package
-        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
-        DevConf.cz, 2014", "tags": "event,speaker,", "issued": 1390422108.0, "image":
-        "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
-        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
-        "last_awarded": 1420480194.0, "percent_earned": 0.23264046932685986, "id":
-        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
-        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
-        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
-        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "valtri", "last_awarded": 1452814661.0, "percent_earned": 0.38436251454002934,
-        "id": "patches-scm-v", "times_awarded": 76, "name": "Patches (SCM V)"}, {"description":
-        "Created a buildroot override in the koji build system", "tags": "development,",
-        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
-        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
-        "cstratak", "last_awarded": 1453371384.0, "percent_earned": 1.4009002174682648,
-        "id": "override,-you-say", "times_awarded": 277, "name": "Override, you say?"},
-        {"description": "You attended devconf.cz, a yearly Linux and JBoss conference
-        in the Czech Republic", "tags": "event,devconf,", "issued": 1391763090.0,
-        "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png", "first_awarded":
-        1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.31355889344055027,
-        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf Attendee"},
-        {"description": "You are a member of the videos team", "tags": "video,community,",
-        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
-        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
-        "last_awarded_person": "nb", "last_awarded": 1439569573.0, "percent_earned":
-        0.060688818085267784, "id": "videographer", "times_awarded": 12, "name": "Videographer"},
-        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
-        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
-        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "sagitter", "last_awarded": 1450261520.0, "percent_earned": 0.2376978708339655,
-        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 47,
-        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
-        "Successfully completed a copr build", "tags": "development,copr,", "issued":
-        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
-        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "tkral", "last_awarded": 1453372187.0, "percent_earned": 5.719921104536489,
-        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1131, "name":
-        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
-        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
-        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
-        "plfiorini", "last_awarded": 1453366379.0, "percent_earned": 3.7070753047084413,
-        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 733, "name":
-        "What goes around comes around (Karma I)"}, {"description": "Tested an update
-        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
-        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
-        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "catanzaro",
-        "last_awarded": 1453387064.0, "percent_earned": 3.342942396196834, "id": "it-still-works!",
-        "times_awarded": 661, "name": "It still works!"}, {"description": "You submitted
-        an update to bodhi with one or more bugzilla bug numbers attached", "tags":
-        "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
-        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
-        "cstratak", "last_awarded": 1453371258.0, "percent_earned": 4.147069235826632,
-        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 820, "name":
-        "Take this and call me in the morning"}, {"description": "You posted 40 or
-        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
-        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
-        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
-        "bochecha", "last_awarded": 1452463312.0, "percent_earned": 0.66251959743084,
-        "id": "bob-loblaw-planet-v", "times_awarded": 131, "name": "Bob Loblaw (Planet
-        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
-        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
-        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "piotrp", "last_awarded": 1452692980.0, "percent_earned": 0.11126283315632428,
-        "id": "like-a-rock-updates-stable-iv", "times_awarded": 22, "name": "Like
-        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
-        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
-        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
-        "potty", "last_awarded": 1448485603.0, "percent_earned": 0.2680422798765994,
-        "id": "lets-do-lunch!", "times_awarded": 53, "name": "Let''s do lunch!"},
-        {"description": "Sip the lemonade away (You deserve it for remembering your
-        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
-        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
-        "first_awarded_person": "shaiton", "last_awarded_person": "piotrp", "last_awarded":
-        1452501182.0, "percent_earned": 0.7434380215445304, "id": "vacation", "times_awarded":
-        147, "name": "Vacation"}, {"description": "You visited the Fedora booth at
-        Pycon, 2014", "tags": "event,python,", "issued": 1397168025.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png",
-        "first_awarded": 1397168025.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "abompard", "last_awarded": 1397573900.0, "percent_earned": 0.05057401507105649,
-        "id": "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
-        {"description": "You submitted feedback for an update in Bodhi after it was
-        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
-        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
-        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "thozza", "last_awarded": 1439904242.0, "percent_earned": 1.44135942952511,
-        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
-        {"description": "You built a package owned by someone else.  It takes a village...",
-        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
-        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
-        "ilgrad", "last_awarded": 1452896392.0, "percent_earned": 2.0128457998280487,
-        "id": "helping-hand", "times_awarded": 398, "name": "Helping Hand"}, {"description":
-        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
-        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
-        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.4652809386537197,
-        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
-        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
-        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
-        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "mcrha",
-        "last_awarded": 1453136709.0, "percent_earned": 0.3489607039902898, "id":
-        "what-goes-up...-koji-failure-iv", "times_awarded": 69, "name": "What goes
-        up... (Koji Failure IV)"}, {"description": "You updated your password with
-        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
-        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
-        "fishers1967", "last_awarded": 1453390883.0, "percent_earned": 69.3824912759824,
-        "id": "paranoid-panda", "times_awarded": 13719, "name": "Paranoid Panda"},
-        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
-        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
-        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
-        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
-        "last_awarded": 1408553413.0, "percent_earned": 0.3691903100187124, "id":
-        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
-        {"description": "You have received 10 or more good karma on your bodhi updates",
-        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
-        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "swilkerson", "last_awarded": 1453199550.0, "percent_earned": 1.7953775350225056,
-        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 355, "name":
-        "What goes around comes around (Karma II)"}, {"description": "Edited at least
-        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
-        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
-        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "siwinski",
-        "last_awarded": 1453319029.0, "percent_earned": 0.981135892378496, "id": "master-editor",
-        "times_awarded": 194, "name": "Master Editor"}, {"description": "You have
-        received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
-        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
-        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "mluscon", "last_awarded": 1450742624.0, "percent_earned": 0.5866585748242553,
-        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 116, "name":
-        "What goes around comes around (Karma III)"}, {"description": "  You attended
-        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
-        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
-        "first_awarded": 1405334492.0, "first_awarded_person": "sgallagh", "last_awarded_person":
-        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.6119455823597835,
-        "id": "flock-2014-attendee", "times_awarded": 121, "name": "Flock 2014 Attendee"},
-        {"description": "You completed a run of the kernel regression test suite",
-        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
-        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "devhen", "last_awarded": 1452673329.0, "percent_earned": 0.6574621959237344,
-        "id": "science-kernel-tester-i", "times_awarded": 130, "name": "Science (Kernel
-        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
-        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
-        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
-        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
-        "last_awarded": 1408665317.0, "percent_earned": 0.4501087341324028, "id":
-        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
-        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
-        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
-        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
-        "limb", "last_awarded": 1452540830.0, "percent_earned": 0.05563141657816214,
-        "id": "corporate-overlord", "times_awarded": 11, "name": "Corporate Overlord"},
-        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
-        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
-        "greghellings", "last_awarded": 1453354804.0, "percent_earned": 0.3439033024831841,
-        "id": "corporate-shill", "times_awarded": 68, "name": "Corporate Shill"},
-        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
-        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
-        "cstratak", "last_awarded": 1453390902.0, "percent_earned": 2.483184139988874,
-        "id": "corporate-drone", "times_awarded": 491, "name": "Corporate Drone"},
-        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
-        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
-        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "fale", "last_awarded": 1452297195.0, "percent_earned": 0.17195165124159206,
-        "id": "master-badger-badger-iii", "times_awarded": 34, "name": "Master Badger
-        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
-        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
-        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
-        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
-        "first_awarded_person": "kevin", "last_awarded_person": "heikoada", "last_awarded":
-        1452772620.0, "percent_earned": 0.3793051130329237, "id": "the-bull-transcended-tester-vii",
-        "times_awarded": 75, "name": "The Bull Transcended (Tester VII)"}, {"description":
-        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
-        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
-        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "chrisroberts", "last_awarded": 1439838603.0, "percent_earned": 0.15677944672027513,
-        "id": "dancing-with-toshio", "times_awarded": 31, "name": "Dancing with Toshio"},
-        {"description": "Voted in a supplemental wallpapers election for the Fedora
-        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
-        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
-        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
-        "last_awarded": 1409902273.0, "percent_earned": 0.5563141657816214, "id":
-        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
-        "We''re sorry, but you had one of your badges revoked.  Something must have
-        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
-        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
-        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "iaguis",
-        "last_awarded": 1452874718.0, "percent_earned": 2.0229606028422595, "id":
-        "consolation-prize", "times_awarded": 400, "name": "Consolation Prize"}, {"description":
-        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
-        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
-        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
-        "lovetide", "last_awarded": 1453389559.0, "percent_earned": 12.324887472816467,
-        "id": "crypto-panda", "times_awarded": 2437, "name": "Crypto Panda"}, {"description":
-        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
-        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
-        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "paulotada", "last_awarded": 1453313558.0, "percent_earned": 3.262023972083144,
-        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 645, "name":
-        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
-        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
-        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "ppisar", "last_awarded": 1447066663.0, "percent_earned": 0.04551661356395084,
-        "id": "mic-check!-updates-testing-v", "times_awarded": 9, "name": "Mic Check!
-        (Updates-Testing V)"}, {"description": "You took ownership of a previously
-        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
-        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
-        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
-        "ohaessler", "last_awarded": 1452768576.0, "percent_earned": 1.3048095888332576,
-        "id": "the-cat-came-back...", "times_awarded": 258, "name": "The cat came
-        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
-        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
-        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
-        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "spot", "last_awarded": 1446145228.0, "percent_earned": 0.09103322712790168,
-        "id": "apprentice-badge-artist-i", "times_awarded": 18, "name": "Apprentice
-        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
-        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
-        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "sandeen", "last_awarded": 1439922999.0, "percent_earned": 0.28321448439791636,
-        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 56, "name":
-        "What goes around comes around (Karma IV)"}, {"description": "You participated
-        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
-        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
-        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
-        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.09103322712790168,
-        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
-        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
-        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
-        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
-        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.31355889344055027,
-        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
-        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
-        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
-        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
-        "rdieter", "last_awarded": 1449536137.0, "percent_earned": 0.030344409042633892,
-        "id": "tectonic!-updates-stable-v", "times_awarded": 6, "name": "Tectonic!
-        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
-        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
-        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
-        "icon", "last_awarded": 1453222652.0, "percent_earned": 4.101552622262681,
-        "id": "associate-badger-badger-1.5", "times_awarded": 811, "name": "Associate
-        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
-        Contributor Conference", "tags": "conference,rochester,events,flock,flock
-        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
-        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
-        "jenneh", "last_awarded": 1441736246.0, "percent_earned": 0.3995347190613463,
-        "id": "flock-2015-attendee", "times_awarded": 79, "name": "FLOCK 2015 Attendee"},
-        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
-        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
-        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
-        "mluscon", "last_awarded": 1453387739.0, "percent_earned": 2.2556010721691195,
-        "id": "macaron-cookie-i", "times_awarded": 446, "name": "Macaron (Cookie I)"},
-        {"description": "Ten people think you''re great, because they''ve given you
-        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
-        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
-        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "walters",
-        "last_awarded": 1452199929.0, "percent_earned": 0.2680422798765994, "id":
-        "chocolate-chip-cookie-ii", "times_awarded": 53, "name": "Chocolate Chip (Cookie
-        II)"}, {"description": "Voted in the supplemental wallpapers election for
-        the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
-        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
-        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.40964952207555755,
-        "id": "nuancier-f22", "times_awarded": 81, "name": "Nuancier (F22)"}, {"description":
-        "You pinned your country in FAS!", "tags": "account,community,", "issued":
-        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
-        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
-        "jvasallo", "last_awarded": 1453390594.0, "percent_earned": 36.86845698680018,
-        "id": "origin", "times_awarded": 7290, "name": "Origin"}, {"description":
-        "You added a new package to the distribution.", "tags": "development,", "issued":
-        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
-        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
-        "tadej", "last_awarded": 1450046737.0, "percent_earned": 2.048247610377788,
-        "id": "delivery", "times_awarded": 405, "name": "Delivery"}, {"description":
-        "You mapped an upstream project to a Fedora package on release-monitoring.org",
-        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
-        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "pabelanger", "last_awarded": 1453318849.0, "percent_earned": 0.9406766803216507,
-        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 186,
-        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
-        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
-        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
-        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "hguemar", "last_awarded": 1453303231.0, "percent_earned": 0.05057401507105649,
-        "id": "black-and-white-cookie-iii", "times_awarded": 10, "name": "Black and
-        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
-        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
-        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "piotrp", "last_awarded": 1451395906.0, "percent_earned": 0.12643503767764122,
-        "id": "hindenburg-koji-failure-v", "times_awarded": 25, "name": "Hindenburg
-        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
-        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
-        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
-        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ralph", "last_awarded": 1433267989.0, "percent_earned": 0.005057401507105649,
-        "id": "badge-muse-badges-released-iv", "times_awarded": 1, "name": "Badge
-        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
-        ideas were approved and released.  Superb!", "tags": "community,badges,",
-        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
-        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "eischmann", "last_awarded": 1452092327.0, "percent_earned": 0.035401810549739544,
-        "id": "badge-muse-badges-released-ii", "times_awarded": 7, "name": "Badge
-        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
-        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
-        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
-        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "viveknrt", "last_awarded": 1452876035.0, "percent_earned": 0.11632023466342993,
-        "id": "badge-muse-badges-released-i", "times_awarded": 23, "name": "Badge
-        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
-        ideas were approved and released.  Impressive!", "tags": "community,badges,",
-        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
-        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "ralph", "last_awarded": 1433267996.0, "percent_earned": 0.010114803014211297,
-        "id": "badge-muse-badges-released-iii", "times_awarded": 2, "name": "Badge
-        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
-        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
-        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
-        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.005057401507105649,
-        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
-        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
-        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
-        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
-        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "jenneh", "last_awarded": 1441736228.0, "percent_earned": 0.37424771152581804,
-        "id": "nom-nom-nom", "times_awarded": 74, "name": "Nom Nom Nom"}, {"description":
-        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
-        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
-        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "alonid", "last_awarded": 1453299407.0, "percent_earned": 2.124108632984373,
-        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 420, "name":
-        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
-        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
-        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
-        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "onekopaka", "last_awarded": 1451613302.0, "percent_earned": 0.25287007535528244,
-        "id": "rock-the-web!", "times_awarded": 50, "name": "Rock the Web!"}, {"description":
-        "You can speak Python and helped with porting stuff to Python 3", "tags":
-        "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
-        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
-        "toshio", "last_awarded": 1447943130.0, "percent_earned": 0.21241086329843728,
-        "id": "parselmouth", "times_awarded": 42, "name": "Parselmouth"}, {"description":
-        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
-        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
-        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "fale",
-        "last_awarded": 1453212624.0, "percent_earned": 0.38436251454002934, "id":
-        "chief-editor", "times_awarded": 76, "name": "Chief Editor"}, {"description":
-        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
-        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
-        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "pschultz", "last_awarded": 1449025570.0, "percent_earned": 5.927274566327821,
-        "id": "froglet", "times_awarded": 1172, "name": "Froglet"}, {"description":
-        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
-        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
-        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "puiterwijk", "last_awarded": 1450374896.0, "percent_earned": 0.015172204521316946,
-        "id": "pizzelle-cookie-iv", "times_awarded": 3, "name": "Pizzelle (Cookie
-        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
-        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ralph", "last_awarded": 1452873723.0, "percent_earned": 0.005057401507105649,
-        "id": "silver", "times_awarded": 1, "name": "Silver"}, {"description": "You
-        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
-        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "churchyard", "last_awarded": 1452875228.0, "percent_earned": 0.05057401507105649,
-        "id": "top-10", "times_awarded": 10, "name": "Top 10"}, {"description": "You
-        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
-        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "siwinski", "last_awarded": 1453319241.0, "percent_earned": 0.15677944672027513,
-        "id": "top-100", "times_awarded": 31, "name": "Top 100"}, {"description":
-        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
-        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "fale", "last_awarded": 1453212640.0, "percent_earned": 0.13149243918474687,
-        "id": "top-25", "times_awarded": 26, "name": "Top 25"}, {"description": "You
-        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
-        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "mluscon", "last_awarded": 1453387764.0, "percent_earned": 0.30344409042633896,
-        "id": "top-500", "times_awarded": 60, "name": "Top 500"}], "user": "ralph",
-        "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png"}'}
-    headers:
-      appserver: [proxy10.phx2.fedoraproject.org]
-      apptime: [D=14564110]
-      connection: [Keep-Alive]
-      content-length: ['66175']
-      content-type: [application/json; charset=UTF-8]
-      date: ['Thu, 21 Jan 2016 15:58:44 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_good_match b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_good_match
deleted file mode 100644
index 141bebb..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_good_match
+++ /dev/null
@@ -1,117 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy11.fedoraproject.org]
-      apptime: [D=168454]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['1823']
-      content-type: ['*/*']
-      date: ['Thu, 21 Jan 2016 16:06:58 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy03.fedoraproject.org]
-      apptime: [D=99135]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['1874']
-      content-type: ['*/*']
-      date: ['Thu, 21 Jan 2016 16:11:16 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_topic b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_topic
deleted file mode 100644
index 26d99fc..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_topic
+++ /dev/null
@@ -1,59 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy03.fedoraproject.org]
-      apptime: [D=107470]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['1823']
-      content-type: ['*/*']
-      date: ['Thu, 21 Jan 2016 16:06:59 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_user b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_user
deleted file mode 100644
index 7f29a67..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_should_invalidate_wrong_user
+++ /dev/null
@@ -1,119 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy01.phx2.fedoraproject.org]
-      apptime: [D=4994]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['1823']
-      content-type: ['*/*']
-      date: ['Thu, 21 Jan 2016 16:07:00 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f
-  response:
-    body:
-      string: !!binary |
-        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
-        CwAA
-    headers:
-      appserver: [proxy12.fedoraproject.org]
-      apptime: [D=143566]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['1941']
-      content-type: ['*/*']
-      date: ['Thu, 21 Jan 2016 16:11:17 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_view_authz b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_view_authz
deleted file mode 100644
index cf740f8..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_badges.TestBadges.test_view_authz
+++ /dev/null
@@ -1,2705 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://badges.fedoraproject.org/user/ralph/json
-  response:
-    body: {string: !!python/unicode '{"user_count": 44887, "rank": 5, "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png",
-        "percentile": "0.01", "assertions": [{"description": "You attended Flock 2013,
-        the Fedora Contributor Conference", "tags": "flock,event,", "issued": 1375373082.0,
-        "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
-        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "rbergero", "last_awarded": 1473972160.0, "percent_earned": 0.18034465868103486,
-        "id": "flock-2013-attendee", "times_awarded": 81, "name": "Flock 2013 Attendee"},
-        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
-        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "imabug", "last_awarded": 1490198996.0, "percent_earned": 0.663490225764795,
-        "id": "tagger-tagger-ii", "times_awarded": 298, "name": "Tagger (Tagger II)"},
-        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
-        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bbroad", "last_awarded": 1491002037.0, "percent_earned": 1.0508972703388697,
-        "id": "junior-tagger-tagger-i", "times_awarded": 472, "name": "Junior Tagger
-        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
-        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
-        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "ylarguex", "last_awarded": 1491516838.0, "percent_earned": 53.357527719641986,
-        "id": "involvement", "times_awarded": 23965, "name": "Involvement"}, {"description":
-        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
-        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
-        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "icole",
-        "last_awarded": 1491505117.0, "percent_earned": 3.9564501046444316, "id":
-        "speak-up!", "times_awarded": 1777, "name": "Speak Up!"}, {"description":
-        "Edited at least 10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0,
-        "image": "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
-        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "kdudka",
-        "last_awarded": 1491484751.0, "percent_earned": 3.3129981742886407, "id":
-        "junior-editor", "times_awarded": 1488, "name": "Junior Editor"}, {"description":
-        "Edited at least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0,
-        "image": "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
-        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "ankit1997",
-        "last_awarded": 1491242577.0, "percent_earned": 2.108473972480741, "id": "associate-editor",
-        "times_awarded": 947, "name": "Associate Editor"}, {"description": "Chaired
-        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
-        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
-        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "yzhang",
-        "last_awarded": 1491431124.0, "percent_earned": 1.5451752237609653, "id":
-        "secretary-general", "times_awarded": 694, "name": "Secretary General"}, {"description":
-        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
-        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
-        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "imabug", "last_awarded": 1490198974.0, "percent_earned": 0.3139332947410607,
-        "id": "senior-tagger-tagger-iii", "times_awarded": 141, "name": "Senior Tagger
-        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
-        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
-        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
-        "jhogarth", "last_awarded": 1491425650.0, "percent_earned": 0.5454869305784388,
-        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 245, "name":
-        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
-        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
-        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "nickboldt",
-        "last_awarded": 1490915696.0, "percent_earned": 2.858796811684553, "id": "if-you-build-it...-koji-success-i",
-        "times_awarded": 1284, "name": "If you build it... (Koji Success I)"}, {"description":
-        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
-        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
-        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
-        "sjenning", "last_awarded": 1491017600.0, "percent_earned": 2.3288952219797836,
-        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 1046, "name":
-        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
-        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
-        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "tartare",
-        "last_awarded": 1491481451.0, "percent_earned": 1.4138130649686065, "id":
-        "if-you-build-it...-koji-success-iii", "times_awarded": 635, "name": "If you
-        build it... (Koji Success III)"}, {"description": "Ten or more questions and
-        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
-        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
-        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "fedo25", "last_awarded": 1491440137.0, "percent_earned": 1.4182660195039407,
-        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 637, "name": "Curious
-        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
-        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
-        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
-        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "andre", "last_awarded": 1491511008.0, "percent_earned": 9.738611568775884,
-        "id": "curious-penguin-ask-fedora-i", "times_awarded": 4374, "name": "Curious
-        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
-        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
-        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "dtemirgaziyev", "last_awarded": 1491482061.0, "percent_earned": 1.903638063855368,
-        "id": "riddle-me-this", "times_awarded": 855, "name": "Riddle Me This"}, {"description":
-        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
-        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
-        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "mhonek", "last_awarded": 1490899614.0, "percent_earned": 2.0127354499710557,
-        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 904, "name": "You
-        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
-        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
-        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "nickboldt", "last_awarded": 1491244448.0, "percent_earned": 1.94816760920871,
-        "id": "what-goes-up...-koji-failure-i", "times_awarded": 875, "name": "What
-        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
-        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "jscotka",
-        "last_awarded": 1491289110.0, "percent_earned": 2.6695462439328494, "id":
-        "you-can-call-me-patches-scm-i", "times_awarded": 1199, "name": "You can call
-        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
-        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "berrange",
-        "last_awarded": 1491242273.0, "percent_earned": 0.5588457941844414, "id":
-        "you-can-call-me-patches-scm-iv", "times_awarded": 251, "name": "You can call
-        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
-        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "cydrobolt",
-        "last_awarded": 1490744785.0, "percent_earned": 1.3603776105445964, "id":
-        "you-can-call-me-patches-scm-iii", "times_awarded": 611, "name": "You can
-        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
-        builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
-        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "jhogarth", "last_awarded": 1491441515.0, "percent_earned": 0.6523578394264594,
-        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 293, "name": "What
-        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
-        builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
-        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "tkrizek", "last_awarded": 1490376511.0, "percent_earned": 1.329206928797257,
-        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 597, "name": "What
-        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
-        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
-        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "jhogarth", "last_awarded": 1491441872.0, "percent_earned": 0.5299015897047691,
-        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 238, "name":
-        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
-        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
-        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "toshio", "last_awarded": 1491516269.0, "percent_earned": 2.70739635748319,
-        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 1216, "name":
-        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
-        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
-        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
-        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
-        "apollo7", "last_awarded": 1491362331.0, "percent_earned": 7.547757937391459,
-        "id": "junior-badger-badger-i", "times_awarded": 3390, "name": "Junior Badger
-        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
-        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
-        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
-        "scox", "last_awarded": 1491419635.0, "percent_earned": 2.562675335084829,
-        "id": "like-a-rock-updates-stable-i", "times_awarded": 1151, "name": "Like
-        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
-        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "alciregi", "last_awarded": 1491294835.0, "percent_earned": 1.6631785189473214,
-        "id": "perceiving-the-bull-tester-iii", "times_awarded": 747, "name": "Perceiving
-        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
-        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
-        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
-        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "mystro256",
-        "last_awarded": 1491340270.0, "percent_earned": 0.39408647637707617, "id":
-        "like-a-rock-updates-stable-iii", "times_awarded": 177, "name": "Like a Rock
-        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
-        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "landgraf", "last_awarded": 1491498009.0, "percent_earned": 6.412254530881239,
-        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2880, "name": "In
-        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
-        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
-        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
-        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "cqi",
-        "last_awarded": 1491420777.0, "percent_earned": 1.2379213608229058, "id":
-        "like-a-rock-updates-stable-ii", "times_awarded": 556, "name": "Like a Rock
-        (Updates-Stable II)"}, {"description": "Partied with Flock 2013 (at the South
-        Carolina Aquarium)", "tags": "party,flock,event,", "issued": 1376252202.0,
-        "image": "https://badges.fedoraproject.org/pngs/tanked.png", "first_awarded":
-        1376252202.0, "first_awarded_person": "ralph", "last_awarded_person": "gnokii",
-        "last_awarded": 1411656869.0, "percent_earned": 0.14026806786302712, "id":
-        "tanked!", "times_awarded": 63, "name": "Tanked!"}, {"description": "You proposed
-        a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,", "issued":
-        1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
-        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "frantisekz", "last_awarded": 1484316413.0, "percent_earned": 0.3161597720087278,
-        "id": "badge-muse-badge-ideas-i", "times_awarded": 142, "name": "Badge Muse
-        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
-        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
-        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
-        "dtemirgaziyev", "last_awarded": 1491477255.0, "percent_earned": 5.508304760208398,
-        "id": "bona-fide", "times_awarded": 2474, "name": "Bona Fide"}, {"description":
-        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
-        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
-        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.05788840895934453,
-        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
-        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
-        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
-        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "mailga", "last_awarded": 1491037049.0, "percent_earned": 0.823796589036826,
-        "id": "senior-badger-badger-ii", "times_awarded": 370, "name": "Senior Badger
-        (Badger II)"}, {"description": "You pushed your first bodhi update to the
-        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
-        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
-        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "olem",
-        "last_awarded": 1491070078.0, "percent_earned": 2.658413857594514, "id": "is-this-thing-on-updates-testing-i",
-        "times_awarded": 1194, "name": "Is this thing on? (Updates-Testing I)"}, {"description":
-        "Pushed 20 bodhi updates to the testing repositories.", "tags": "development",
-        "issued": 1376077757.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
-        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
-        "dustymabe", "last_awarded": 1491432891.0, "percent_earned": 1.467248519392617,
-        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 659, "name":
-        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
-        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
-        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
-        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "dustymabe",
-        "last_awarded": 1491406327.0, "percent_earned": 1.714387496103665, "id": "partners-in-crime",
-        "times_awarded": 770, "name": "Partners in Crime"}, {"description": "*(a great
-        struggle, repeated escapes, discipline required)*\nTested and added karma
-        to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
-        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "mcepl", "last_awarded": 1491490795.0, "percent_earned": 0.961838179632186,
-        "id": "catching-the-bull-tester-iv", "times_awarded": 432, "name": "Catching
-        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
-        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
-        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
-        "first_awarded_person": "jamielinux", "last_awarded_person": "bt0dotninja",
-        "last_awarded": 1489638271.0, "percent_earned": 0.16253284053969808, "id":
-        "master-tagger-tagger-iv", "times_awarded": 73, "name": "Master Tagger (Tagger
-        IV)"}, {"description": "A member of the sysadmin-badges group.  Nothing to
-        see here..  move along.", "tags": "infrastructure,badges,community,", "issued":
-        1378319150.0, "image": "https://badges.fedoraproject.org/pngs/fas-inside-job.png",
-        "first_awarded": 1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
-        "jflory7", "last_awarded": 1472154166.0, "percent_earned": 0.02226477267667097,
-        "id": "inside-job", "times_awarded": 10, "name": "Inside Job"}, {"description":
-        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
-        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
-        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "salvadorhm", "last_awarded": 1491509400.0, "percent_earned": 8.144453845126241,
-        "id": "white-rabbit", "times_awarded": 3658, "name": "White Rabbit"}, {"description":
-        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
-        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
-        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jcholast", "last_awarded": 1491423845.0, "percent_earned": 3.061406243042258,
-        "id": "mugshot", "times_awarded": 1375, "name": "Mugshot"}, {"description":
-        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
-        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
-        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
-        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.03785011355034065,
-        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
-        me, I know what I am doing"}, {"description": "Has used an ansible playbook
-        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
-        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
-        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jkaluza", "last_awarded": 1490254934.0, "percent_earned": 0.10241795431268647,
-        "id": "maestro", "times_awarded": 46, "name": "Maestro"}, {"description":
-        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
-        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
-        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "cra", "last_awarded": 1491437628.0, "percent_earned": 4.250345103976488,
-        "id": "let-me-introduce-myself", "times_awarded": 1909, "name": "Let Me Introduce
-        Myself"}, {"description": "You submitted a bodhi update including multiple
-        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
-        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
-        "ngompa", "last_awarded": 1490659963.0, "percent_earned": 0.7614552255421472,
-        "id": "binary-star", "times_awarded": 342, "name": "Binary Star"}, {"description":
-        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
-        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
-        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "xavierb", "last_awarded": 1484573828.0, "percent_earned": 0.32506568107939615,
-        "id": "packager-sponsor", "times_awarded": 146, "name": "Packager Sponsor"},
-        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
-        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "stefw", "last_awarded": 1491468491.0, "percent_earned": 1.3470187469385937,
-        "id": "bloggin-it!-planet-ii", "times_awarded": 605, "name": "Bloggin'' it!
-        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
-        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "stefw", "last_awarded": 1491468509.0, "percent_earned": 1.1399563610455536,
-        "id": "bloggin-it!-planet-iii", "times_awarded": 512, "name": "Bloggin'' it!
-        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
-        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "stefw", "last_awarded": 1491468543.0, "percent_earned": 1.6231019281293138,
-        "id": "bloggin-it!-planet-i", "times_awarded": 729, "name": "Bloggin'' it!
-        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
-        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
-        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "dtimms", "last_awarded": 1491484910.0, "percent_earned": 0.939573406955515,
-        "id": "white-hat", "times_awarded": 422, "name": "White Hat"}, {"description":
-        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
-        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
-        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.17589170414570066,
-        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
-        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
-        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
-        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
-        "andrespol", "last_awarded": 1491360716.0, "percent_earned": 20.256490181235247,
-        "id": "embryo", "times_awarded": 9098, "name": "Embryo"}, {"description":
-        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
-        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
-        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "piotrdrag", "last_awarded": 1491478479.0, "percent_earned": 0.549939885113773,
-        "id": "taming-the-bull-tester-v", "times_awarded": 247, "name": "Taming the
-        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
-        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
-        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ferdnyc", "last_awarded": 1484744055.0, "percent_earned": 0.1469474996660284,
-        "id": "common-bugs-contributor", "times_awarded": 66, "name": "Common Bugs
-        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
-        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
-        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "metonymy", "last_awarded": 1491502807.0, "percent_earned": 6.249721690341541,
-        "id": "baby-badger", "times_awarded": 2807, "name": "Baby Badger"}, {"description":
-        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
-        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
-        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "martinkg", "last_awarded": 1489655875.0, "percent_earned": 0.09351204524201807,
-        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 42, "name":
-        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
-        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
-        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
-        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
-        "pwalter", "last_awarded": 1491445231.0, "percent_earned": 0.6167342031437859,
-        "id": "old-yeller", "times_awarded": 277, "name": "Old Yeller"}, {"description":
-        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
-        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
-        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.1580798860043639,
-        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
-        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
-        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
-        "stefw", "last_awarded": 1491468562.0, "percent_earned": 0.7547757937391459,
-        "id": "bloggin-it!-planet-iv", "times_awarded": 339, "name": "Bloggin'' it!
-        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
-        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
-        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "augenauf", "last_awarded": 1491316933.0, "percent_earned": 1.013047156788529,
-        "id": "senior-editor", "times_awarded": 455, "name": "Senior Editor"}, {"description":
-        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
-        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
-        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "avichi", "last_awarded": 1491361425.0, "percent_earned": 14.18933962684241,
-        "id": "tadpole", "times_awarded": 6373, "name": "Tadpole"}, {"description":
-        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
-        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
-        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
-        "amogh23k", "last_awarded": 1491362307.0, "percent_earned": 28.41430288996749,
-        "id": "egg", "times_awarded": 12762, "name": "Egg"}, {"description": "You''ve
-        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
-        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
-        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
-        "akopacsi", "last_awarded": 1490757692.0, "percent_earned": 7.30952486975108,
-        "id": "tadpole-with-legs", "times_awarded": 3283, "name": "Tadpole with Legs"},
-        {"description": "You''re a developer contributing to the Fedora Badges stack",
-        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
-        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "lsedlar", "last_awarded": 1476326553.0, "percent_earned": 0.05120897715634323,
-        "id": "badge-off!", "times_awarded": 23, "name": "Badge Off!"}, {"description":
-        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
-        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "sassam", "last_awarded": 1491148875.0, "percent_earned": 0.3072538629380594,
-        "id": "riding-the-bull-home-tester-vi", "times_awarded": 138, "name": "Riding
-        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
-        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
-        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
-        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
-        "metonymy", "last_awarded": 1491476646.0, "percent_earned": 0.4208042035890813,
-        "id": "no-longer-a-ronin", "times_awarded": 189, "name": "No Longer a Ronin"},
-        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
-        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bt0dotninja", "last_awarded": 1489643141.0, "percent_earned": 0.13358863606002583,
-        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 60, "name":
-        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
-        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
-        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "bbroad", "last_awarded": 1491002111.0, "percent_earned": 0.8750055661931692,
-        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 393, "name":
-        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
-        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
-        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "ignacio", "last_awarded": 1485888954.0, "percent_earned": 0.28944204479672264,
-        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 130, "name":
-        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
-        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
-        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "imabug", "last_awarded": 1490199130.0, "percent_earned": 0.5120897715634324,
-        "id": "package-tagger-package-tagger-ii", "times_awarded": 230, "name": "Package
-        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
-        DevConf.cz, 2014", "tags": "devconf,speaker,event,", "issued": 1390422108.0,
-        "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
-        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
-        "last_awarded": 1420480194.0, "percent_earned": 0.10241795431268647, "id":
-        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
-        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
-        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
-        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "terjeros", "last_awarded": 1491331717.0, "percent_earned": 0.26717727212005166,
-        "id": "patches-scm-v", "times_awarded": 120, "name": "Patches (SCM V)"}, {"description":
-        "Created a buildroot override in the koji build system", "tags": "development,",
-        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
-        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
-        "decathorpe", "last_awarded": 1491331634.0, "percent_earned": 0.7480963619361446,
-        "id": "override,-you-say", "times_awarded": 336, "name": "Override, you say?"},
-        {"description": "You attended the 2014 iteration of devconf.cz, a yearly Linux
-        and JBoss conference in the Czech Republic", "tags": "event,devconf,", "issued":
-        1391763090.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png",
-        "first_awarded": 1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.13804159059536003,
-        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf 2014 Attendee"},
-        {"description": "You are a member of the videos team", "tags": "video,community,",
-        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
-        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
-        "last_awarded_person": "swilson", "last_awarded": 1458943142.0, "percent_earned":
-        0.03562363628267355, "id": "videographer", "times_awarded": 16, "name": "Videographer"},
-        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
-        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
-        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "zbyszek", "last_awarded": 1490388487.0, "percent_earned": 0.15585340873669679,
-        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 70,
-        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
-        "Successfully completed a copr build", "tags": "development,copr,", "issued":
-        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
-        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "shosca", "last_awarded": 1491441908.0, "percent_earned": 3.958676581912099,
-        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1778, "name":
-        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
-        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
-        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
-        "cydrobolt", "last_awarded": 1491503467.0, "percent_earned": 2.046132608986062,
-        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 919, "name":
-        "What goes around comes around (Karma I)"}, {"description": "Tested an update
-        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
-        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
-        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "caiqian",
-        "last_awarded": 1481903131.0, "percent_earned": 1.6765373825533243, "id":
-        "it-still-works!", "times_awarded": 753, "name": "It still works!"}, {"description":
-        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
-        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
-        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
-        "cydrobolt", "last_awarded": 1491442200.0, "percent_earned": 2.1641359041724186,
-        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 972, "name":
-        "Take this and call me in the morning"}, {"description": "You posted 40 or
-        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
-        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
-        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
-        "stefw", "last_awarded": 1491468526.0, "percent_earned": 0.35623636282673554,
-        "id": "bob-loblaw-planet-v", "times_awarded": 160, "name": "Bob Loblaw (Planet
-        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
-        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
-        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "dfateyev", "last_awarded": 1490465620.0, "percent_earned": 0.06902079529768002,
-        "id": "like-a-rock-updates-stable-iv", "times_awarded": 31, "name": "Like
-        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
-        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
-        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
-        "ignatenkobrain", "last_awarded": 1485808919.0, "percent_earned": 0.14472102239836132,
-        "id": "lets-do-lunch!", "times_awarded": 65, "name": "Let''s do lunch!"},
-        {"description": "Sip the lemonade away (You deserve it for remembering your
-        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
-        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
-        "first_awarded_person": "shaiton", "last_awarded_person": "mythcat", "last_awarded":
-        1484694397.0, "percent_earned": 0.4208042035890813, "id": "vacation", "times_awarded":
-        189, "name": "Vacation"}, {"description": "You visited the Fedora booth at
-        Pycon, 2014", "tags": "python,event,pycon,", "issued": 1397168025.0, "image":
-        "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png", "first_awarded":
-        1397168025.0, "first_awarded_person": "ralph", "last_awarded_person": "abompard",
-        "last_awarded": 1397573900.0, "percent_earned": 0.02226477267667097, "id":
-        "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
-        {"description": "You submitted feedback for an update in Bodhi after it was
-        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
-        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
-        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "thozza", "last_awarded": 1439904242.0, "percent_earned": 0.6345460212851227,
-        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
-        {"description": "You built a package owned by someone else.  It takes a village...",
-        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
-        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
-        "nickboldt", "last_awarded": 1490915668.0, "percent_earned": 0.984102952308857,
-        "id": "helping-hand", "times_awarded": 442, "name": "Helping Hand"}, {"description":
-        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
-        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
-        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.20483590862537293,
-        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
-        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
-        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
-        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "wtaymans",
-        "last_awarded": 1490906731.0, "percent_earned": 0.20038295409003873, "id":
-        "what-goes-up...-koji-failure-iv", "times_awarded": 90, "name": "What goes
-        up... (Koji Failure IV)"}, {"description": "You updated your password with
-        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
-        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
-        "payasr", "last_awarded": 1491512765.0, "percent_earned": 61.86712383666563,
-        "id": "paranoid-panda", "times_awarded": 27787, "name": "Paranoid Panda"},
-        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
-        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
-        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
-        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
-        "last_awarded": 1408553413.0, "percent_earned": 0.16253284053969808, "id":
-        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
-        {"description": "You have received 10 or more good karma on your bodhi updates",
-        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
-        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "jvymazal", "last_awarded": 1491284602.0, "percent_earned": 1.099879770227546,
-        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 494, "name":
-        "What goes around comes around (Karma II)"}, {"description": "Edited at least
-        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
-        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
-        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "athoscr",
-        "last_awarded": 1490991464.0, "percent_earned": 0.5900164759317807, "id":
-        "master-editor", "times_awarded": 265, "name": "Master Editor"}, {"description":
-        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
-        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
-        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "terjeros", "last_awarded": 1491384354.0, "percent_earned": 0.389633521841742,
-        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 175, "name":
-        "What goes around comes around (Karma III)"}, {"description": "  You attended
-        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
-        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
-        "first_awarded": 1405296000.0, "first_awarded_person": "marinaz", "last_awarded_person":
-        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.27163022665538583,
-        "id": "flock-2014-attendee", "times_awarded": 122, "name": "Flock 2014 Attendee"},
-        {"description": "You completed a run of the kernel regression test suite",
-        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
-        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "pperron", "last_awarded": 1490999828.0, "percent_earned": 0.49873090795742975,
-        "id": "science-kernel-tester-i", "times_awarded": 224, "name": "Science (Kernel
-        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
-        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
-        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
-        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
-        "last_awarded": 1408665317.0, "percent_earned": 0.19815647682237164, "id":
-        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
-        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
-        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
-        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
-        "pghmcfc", "last_awarded": 1485788654.0, "percent_earned": 0.03339715901500646,
-        "id": "corporate-overlord", "times_awarded": 15, "name": "Corporate Overlord"},
-        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
-        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
-        "kdudka", "last_awarded": 1491214689.0, "percent_earned": 0.18925056775170326,
-        "id": "corporate-shill", "times_awarded": 85, "name": "Corporate Shill"},
-        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
-        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
-        "dsommers", "last_awarded": 1490298016.0, "percent_earned": 1.3024892015852518,
-        "id": "corporate-drone", "times_awarded": 585, "name": "Corporate Drone"},
-        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
-        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
-        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "vondruch", "last_awarded": 1491296529.0, "percent_earned": 0.14026806786302712,
-        "id": "master-badger-badger-iii", "times_awarded": 63, "name": "Master Badger
-        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
-        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
-        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
-        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
-        "first_awarded_person": "kevin", "last_awarded_person": "fale", "last_awarded":
-        1490321832.0, "percent_earned": 0.2248742040343768, "id": "the-bull-transcended-tester-vii",
-        "times_awarded": 101, "name": "The Bull Transcended (Tester VII)"}, {"description":
-        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
-        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
-        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "rbergero", "last_awarded": 1455959914.0, "percent_earned": 0.0712472725653471,
-        "id": "dancing-with-toshio", "times_awarded": 32, "name": "Dancing with Toshio"},
-        {"description": "Voted in a supplemental wallpapers election for the Fedora
-        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
-        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
-        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
-        "last_awarded": 1409902273.0, "percent_earned": 0.2449124994433807, "id":
-        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
-        "We''re sorry, but you had one of your badges revoked.  Something must have
-        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
-        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
-        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "keitellf",
-        "last_awarded": 1465418173.0, "percent_earned": 0.8972703388698402, "id":
-        "consolation-prize", "times_awarded": 403, "name": "Consolation Prize"}, {"description":
-        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
-        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
-        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
-        "usuha", "last_awarded": 1491448085.0, "percent_earned": 6.430066349022577,
-        "id": "crypto-panda", "times_awarded": 2888, "name": "Crypto Panda"}, {"description":
-        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
-        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
-        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "shosca", "last_awarded": 1491505320.0, "percent_earned": 2.3711982900654585,
-        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 1065, "name":
-        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
-        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
-        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "pghmcfc", "last_awarded": 1490811747.0, "percent_earned": 0.03562363628267355,
-        "id": "mic-check!-updates-testing-v", "times_awarded": 16, "name": "Mic Check!
-        (Updates-Testing V)"}, {"description": "You took ownership of a previously
-        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
-        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
-        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
-        "sailer", "last_awarded": 1490344262.0, "percent_earned": 0.7525493164714788,
-        "id": "the-cat-came-back...", "times_awarded": 338, "name": "The cat came
-        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
-        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
-        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
-        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "michalrud", "last_awarded": 1470317213.0, "percent_earned": 0.04675602262100904,
-        "id": "apprentice-badge-artist-i", "times_awarded": 21, "name": "Apprentice
-        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
-        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
-        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "kkeithle", "last_awarded": 1491364811.0, "percent_earned": 0.20706238589304005,
-        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 93, "name":
-        "What goes around comes around (Karma IV)"}, {"description": "You participated
-        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
-        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
-        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
-        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.04007659081800775,
-        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
-        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
-        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
-        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
-        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.13804159059536003,
-        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
-        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
-        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
-        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
-        "orion", "last_awarded": 1490756246.0, "percent_earned": 0.024491249944338066,
-        "id": "tectonic!-updates-stable-v", "times_awarded": 11, "name": "Tectonic!
-        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
-        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
-        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
-        "pcreech17", "last_awarded": 1491432940.0, "percent_earned": 2.3756512446007925,
-        "id": "associate-badger-badger-1.5", "times_awarded": 1067, "name": "Associate
-        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
-        Contributor Conference", "tags": "conference,rochester,events,flock,flock
-        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
-        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
-        "kellin", "last_awarded": 1461547496.0, "percent_earned": 0.18479761321636906,
-        "id": "flock-2015-attendee", "times_awarded": 83, "name": "Flock 2015 Attendee"},
-        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
-        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
-        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
-        "gtierney", "last_awarded": 1491405719.0, "percent_earned": 1.852429086699025,
-        "id": "macaron-cookie-i", "times_awarded": 832, "name": "Macaron (Cookie I)"},
-        {"description": "Ten people think you''re great, because they''ve given you
-        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
-        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
-        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "mizdebsk",
-        "last_awarded": 1491500198.0, "percent_earned": 0.3606893173620697, "id":
-        "chocolate-chip-cookie-ii", "times_awarded": 162, "name": "Chocolate Chip
-        (Cookie II)"}, {"description": "Voted in the supplemental wallpapers election
-        for the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
-        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
-        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.18257113594870197,
-        "id": "nuancier-f22", "times_awarded": 82, "name": "Nuancier (F22)"}, {"description":
-        "You pinned your country in FAS!", "tags": "account,community,", "issued":
-        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
-        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
-        "schwankek", "last_awarded": 1491486520.0, "percent_earned": 17.635926437191078,
-        "id": "origin", "times_awarded": 7921, "name": "Origin"}, {"description":
-        "You added a new package to the distribution.", "tags": "development,", "issued":
-        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
-        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
-        "nmilosev", "last_awarded": 1491213323.0, "percent_earned": 0.919535111546511,
-        "id": "delivery", "times_awarded": 413, "name": "Delivery"}, {"description":
-        "You mapped an upstream project to a Fedora package on release-monitoring.org",
-        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
-        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "dustymabe", "last_awarded": 1475240820.0, "percent_earned": 0.5655252259874427,
-        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 254,
-        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
-        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
-        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
-        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "dmsimard", "last_awarded": 1491321510.0, "percent_earned": 0.14472102239836132,
-        "id": "black-and-white-cookie-iii", "times_awarded": 65, "name": "Black and
-        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
-        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
-        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "smani", "last_awarded": 1485976444.0, "percent_earned": 0.08460613617134968,
-        "id": "hindenburg-koji-failure-v", "times_awarded": 38, "name": "Hindenburg
-        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
-        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
-        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
-        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jflory7", "last_awarded": 1475509860.0, "percent_earned": 0.006679431803001291,
-        "id": "badge-muse-badges-released-iv", "times_awarded": 3, "name": "Badge
-        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
-        ideas were approved and released.  Superb!", "tags": "community,badges,",
-        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
-        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "pravins", "last_awarded": 1472553692.0, "percent_earned": 0.03562363628267355,
-        "id": "badge-muse-badges-released-ii", "times_awarded": 16, "name": "Badge
-        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
-        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
-        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
-        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "frantisekz", "last_awarded": 1485462295.0, "percent_earned": 0.10019147704501936,
-        "id": "badge-muse-badges-released-i", "times_awarded": 45, "name": "Badge
-        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
-        ideas were approved and released.  Impressive!", "tags": "community,badges,",
-        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
-        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "jflory7", "last_awarded": 1475509873.0, "percent_earned": 0.013358863606002582,
-        "id": "badge-muse-badges-released-iii", "times_awarded": 6, "name": "Badge
-        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
-        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
-        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
-        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.002226477267667097,
-        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
-        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
-        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
-        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
-        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "kellin", "last_awarded": 1461547520.0, "percent_earned": 0.16921227234269937,
-        "id": "nom-nom-nom", "times_awarded": 76, "name": "Nom Nom Nom"}, {"description":
-        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
-        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
-        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "rluzynski", "last_awarded": 1491442095.0, "percent_earned": 1.5763459055083047,
-        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 708, "name":
-        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
-        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
-        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
-        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "dustymabe", "last_awarded": 1491326903.0, "percent_earned": 0.12468272698935744,
-        "id": "rock-the-web!", "times_awarded": 56, "name": "Rock the Web!"}, {"description":
-        "You can speak Python and and you''ve ported at least one package to Python
-        3", "tags": "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
-        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
-        "crobinso", "last_awarded": 1491217608.0, "percent_earned": 0.33842454468539873,
-        "id": "parselmouth", "times_awarded": 152, "name": "Parselmouth I"}, {"description":
-        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
-        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
-        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "jonatoni",
-        "last_awarded": 1490211890.0, "percent_earned": 0.22710068130204392, "id":
-        "chief-editor", "times_awarded": 102, "name": "Chief Editor"}, {"description":
-        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
-        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
-        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "apahim", "last_awarded": 1491360865.0, "percent_earned": 4.628846239479895,
-        "id": "froglet", "times_awarded": 2079, "name": "Froglet"}, {"description":
-        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
-        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
-        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ryanlerch", "last_awarded": 1490719235.0, "percent_earned": 0.03117068174733936,
-        "id": "pizzelle-cookie-iv", "times_awarded": 14, "name": "Pizzelle (Cookie
-        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
-        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "churchyard", "last_awarded": 1475564266.0, "percent_earned": 0.011132386338335486,
-        "id": "silver", "times_awarded": 5, "name": "Silver"}, {"description": "You
-        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
-        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "fale", "last_awarded": 1489622707.0, "percent_earned": 0.03117068174733936,
-        "id": "top-10", "times_awarded": 14, "name": "Top 10"}, {"description": "You
-        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
-        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "tflink", "last_awarded": 1480461776.0, "percent_earned": 0.25159193124638196,
-        "id": "top-100", "times_awarded": 113, "name": "Top 100"}, {"description":
-        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
-        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "mrunge", "last_awarded": 1490730635.0, "percent_earned": 0.06679431803001291,
-        "id": "top-25", "times_awarded": 30, "name": "Top 25"}, {"description": "You
-        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
-        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "zsun", "last_awarded": 1490677027.0, "percent_earned": 1.2000712472725654,
-        "id": "top-500", "times_awarded": 539, "name": "Top 500"}, {"description":
-        "You visited the Fedora table at BrickHack 2016!", "tags": "brickhack,event,hackathon,events,",
-        "issued": 1457234130.0, "image": "http://infrastructure.fedoraproject.org/infra/badges/pngs/events-brickhack-2016.png",
-        "first_awarded": 1455845197.0, "first_awarded_person": "jflory7", "last_awarded_person":
-        "brandondgr8", "last_awarded": 1461299769.0, "percent_earned": 0.05566193169167742,
-        "id": "brickhack-2016-attendee", "times_awarded": 25, "name": "BrickHack 2016
-        Attendee"}, {"description": "You gave a presentation at DevConf.cz, 2016",
-        "tags": "devconf,speaker,event,", "issued": 1455008224.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2016.png",
-        "first_awarded": 1454667336.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "thozza", "last_awarded": 1459500320.0, "percent_earned": 0.2137418176960413,
-        "id": "devconf-2016-speaker", "times_awarded": 96, "name": "DevConf 2016 Speaker"},
-        {"description": "You attended the 2016 iteration of DevConf.cz, a yearly Linux
-        and JBoss conference in the Czech Republic", "tags": "event, devconf,", "issued":
-        1455120228.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee-2016.png",
-        "first_awarded": 1454600601.0, "first_awarded_person": "eischmann", "last_awarded_person":
-        "dkaspar", "last_awarded": 1461940547.0, "percent_earned": 0.18925056775170326,
-        "id": "devconf-2016-attendee", "times_awarded": 85, "name": "DevConf 2016
-        Attendee"}, {"description": "You got a \"Change\" accepted into the Fedora
-        24 Change list", "tags": "development,FESCo,process,", "issued": 1458652673.0,
-        "image": "https://badges.fedoraproject.org/pngs/changes-f24.png", "first_awarded":
-        1458651465.0, "first_awarded_person": "eischmann", "last_awarded_person":
-        "pnemade", "last_awarded": 1459240914.0, "percent_earned": 0.10019147704501936,
-        "id": "fedora-24-change-accepted", "times_awarded": 45, "name": "Fedora 24
-        Change Accepted"}, {"description": "You held third place on the Fedora Badges
-        leaderboard", "tags": "meta,community,", "issued": 1462904993.0, "image":
-        "https://badges.fedoraproject.org/pngs/3_badge_340.png", "first_awarded":
-        1452875229.0, "first_awarded_person": "pnemade", "last_awarded_person": "kevin",
-        "last_awarded": 1489692901.0, "percent_earned": 0.011132386338335486, "id":
-        "bronze", "times_awarded": 5, "name": "Bronze"}, {"description": "You burned
-        a yubikey and linked it with your Fedora Account", "tags": "account,community,",
-        "issued": 1462904755.0, "image": "https://badges.fedoraproject.org/pngs/yubi-badge.png",
-        "first_awarded": 1422906928.0, "first_awarded_person": "plautrba", "last_awarded_person":
-        "findarato", "last_awarded": 1491408410.0, "percent_earned": 0.4052188627154117,
-        "id": "horcrux", "times_awarded": 182, "name": "Horcrux"}, {"description":
-        "You hacked with the Fedora crew at PyCon US 2016", "tags": "event, python,pycon,",
-        "issued": 1464988862.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2016_attendee.png",
-        "first_awarded": 1464988862.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "maxamillion", "last_awarded": 1464991242.0, "percent_earned": 0.028944204479672265,
-        "id": "pycon-2016-attendee", "times_awarded": 13, "name": "PyCon 2016 Attendee"},
-        {"description": "You got 150 Fedora Badges!  Wow!", "tags": "badges,community,",
-        "issued": 1468058613.0, "image": "https://badges.fedoraproject.org/pngs/badger-04.png",
-        "first_awarded": 1457979017.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "pbrobinson", "last_awarded": 1490919191.0, "percent_earned": 0.020038295409003874,
-        "id": "badge-junkie-badger-iv", "times_awarded": 9, "name": "Badge Junkie
-        (Badger IV)"}, {"description": "You can speak Python and and you''ve ported
-        at least five packages to Python 3", "tags": "python,miscellaneous,", "issued":
-        1468058067.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-II.png",
-        "first_awarded": 1467988651.0, "first_awarded_person": "cstratak", "last_awarded_person":
-        "ishcherb", "last_awarded": 1488193805.0, "percent_earned": 0.028944204479672265,
-        "id": "parselmouth-ii", "times_awarded": 13, "name": "Parselmouth II"}, {"description":
-        "You can speak Python and and you''ve ported at least ten packages to Python
-        3", "tags": "python,miscellaneous,", "issued": 1468058072.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-III.png",
-        "first_awarded": 1467997850.0, "first_awarded_person": "cstratak", "last_awarded_person":
-        "ishcherb", "last_awarded": 1489753361.0, "percent_earned": 0.02226477267667097,
-        "id": "parselmouth-iii", "times_awarded": 10, "name": "Parselmouth III"},
-        {"description": "You attended Flock 2016, the Fedora Contributor Conference",
-        "tags": "flock,event,events,", "issued": 1470404480.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-attendee.png",
-        "first_awarded": 1468984748.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "adrian", "last_awarded": 1486483875.0, "percent_earned": 0.2360065903727123,
-        "id": "flock-2016-attendee", "times_awarded": 106, "name": "Flock 2016 Attendee"},
-        {"description": "You attended the party at Flock 2016 in Krakow!", "tags":
-        "flock,krakow,event,events,", "issued": 1470404592.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/krakow-brews.png",
-        "first_awarded": 1468963417.0, "first_awarded_person": "duffy", "last_awarded_person":
-        "kittykat", "last_awarded": 1486217490.0, "percent_earned": 0.18257113594870197,
-        "id": "krakow-brews!", "times_awarded": 82, "name": "Krakow Brews!"}, {"description":
-        "You gave a presentation at Flock 2016, the Fedora Contributor Conference",
-        "tags": "flock,speaker,event,", "issued": 1471354751.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-speaker.png",
-        "first_awarded": 1470941077.0, "first_awarded_person": "mattdm", "last_awarded_person":
-        "kittykat", "last_awarded": 1486217546.0, "percent_earned": 0.19592999955470453,
-        "id": "flock-2016-speaker", "times_awarded": 88, "name": "Flock 2016 Speaker"},
-        {"description": "You''re a member of the Modularity Working Group!", "tags":
-        "modularity,community,", "issued": 1475082397.0, "image": "https://badges.fedoraproject.org/pngs/fas-modularity-wg.png",
-        "first_awarded": 1475082098.0, "first_awarded_person": "asamalik", "last_awarded_person":
-        "jscotka", "last_awarded": 1491213584.0, "percent_earned": 0.0801531816360155,
-        "id": "modularity-wg-member", "times_awarded": 36, "name": "Modularity WG
-        Member"}, {"description": "You got a \"Change\" accepted into the Fedora 26
-        Change list", "tags": "development, FESCo, process,", "issued": 1479749896.0,
-        "image": "https://badges.fedoraproject.org/pngs/changes-f26.png", "first_awarded":
-        1473331018.0, "first_awarded_person": "cstratak", "last_awarded_person": "ncoghlan",
-        "last_awarded": 1489656918.0, "percent_earned": 0.11577681791868906, "id":
-        "fedora-26-change-accepted", "times_awarded": 52, "name": "Fedora 26 Change
-        Accepted"}, {"description": "You gave a presentation at DevConf.cz, 2017",
-        "tags": "speaker,devconf,event,", "issued": 1486037155.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2017.png",
-        "first_awarded": 1486033923.0, "first_awarded_person": "jflory7", "last_awarded_person":
-        "siddharths", "last_awarded": 1486077040.0, "percent_earned": 0.24713897671104776,
-        "id": "devconf-2017-speaker", "times_awarded": 111, "name": "DevConf 2017
-        Speaker"}, {"description": "You have helped so many Fedorans you''ve got over
-        100 cookies. Don''t eat them all at once!", "tags": "cookie,community,", "issued":
-        1486153659.0, "image": "https://badges.fedoraproject.org/pngs/rainbowcookie.png",
-        "first_awarded": 1468278719.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "ralph", "last_awarded": 1486153659.0, "percent_earned": 0.011132386338335486,
-        "id": "rainbow-cookie-v", "times_awarded": 5, "name": "Rainbow (Cookie V)"}],
-        "percent_earned": 41.81818181818181, "user": "ralph"}'}
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=74663696]
-      connection: [Keep-Alive]
-      content-length: ['74203']
-      content-type: [application/json; charset=UTF-8]
-      date: ['Thu, 06 Apr 2017 22:31:35 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://badges.fedoraproject.org/user/ralph/json
-  response:
-    body: {string: !!python/unicode '{"user_count": 44887, "rank": 5, "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png",
-        "percentile": "0.01", "assertions": [{"description": "You attended Flock 2013,
-        the Fedora Contributor Conference", "tags": "flock,event,", "issued": 1375373082.0,
-        "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
-        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "rbergero", "last_awarded": 1473972160.0, "percent_earned": 0.18034465868103486,
-        "id": "flock-2013-attendee", "times_awarded": 81, "name": "Flock 2013 Attendee"},
-        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
-        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "imabug", "last_awarded": 1490198996.0, "percent_earned": 0.663490225764795,
-        "id": "tagger-tagger-ii", "times_awarded": 298, "name": "Tagger (Tagger II)"},
-        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
-        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bbroad", "last_awarded": 1491002037.0, "percent_earned": 1.0508972703388697,
-        "id": "junior-tagger-tagger-i", "times_awarded": 472, "name": "Junior Tagger
-        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
-        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
-        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "ylarguex", "last_awarded": 1491516838.0, "percent_earned": 53.357527719641986,
-        "id": "involvement", "times_awarded": 23965, "name": "Involvement"}, {"description":
-        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
-        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
-        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "icole",
-        "last_awarded": 1491505117.0, "percent_earned": 3.9564501046444316, "id":
-        "speak-up!", "times_awarded": 1777, "name": "Speak Up!"}, {"description":
-        "Edited at least 10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0,
-        "image": "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
-        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "kdudka",
-        "last_awarded": 1491484751.0, "percent_earned": 3.3129981742886407, "id":
-        "junior-editor", "times_awarded": 1488, "name": "Junior Editor"}, {"description":
-        "Edited at least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0,
-        "image": "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
-        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "ankit1997",
-        "last_awarded": 1491242577.0, "percent_earned": 2.108473972480741, "id": "associate-editor",
-        "times_awarded": 947, "name": "Associate Editor"}, {"description": "Chaired
-        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
-        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
-        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "yzhang",
-        "last_awarded": 1491431124.0, "percent_earned": 1.5451752237609653, "id":
-        "secretary-general", "times_awarded": 694, "name": "Secretary General"}, {"description":
-        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
-        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
-        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "imabug", "last_awarded": 1490198974.0, "percent_earned": 0.3139332947410607,
-        "id": "senior-tagger-tagger-iii", "times_awarded": 141, "name": "Senior Tagger
-        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
-        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
-        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
-        "jhogarth", "last_awarded": 1491425650.0, "percent_earned": 0.5454869305784388,
-        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 245, "name":
-        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
-        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
-        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "nickboldt",
-        "last_awarded": 1490915696.0, "percent_earned": 2.858796811684553, "id": "if-you-build-it...-koji-success-i",
-        "times_awarded": 1284, "name": "If you build it... (Koji Success I)"}, {"description":
-        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
-        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
-        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
-        "sjenning", "last_awarded": 1491017600.0, "percent_earned": 2.3288952219797836,
-        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 1046, "name":
-        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
-        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
-        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "tartare",
-        "last_awarded": 1491481451.0, "percent_earned": 1.4138130649686065, "id":
-        "if-you-build-it...-koji-success-iii", "times_awarded": 635, "name": "If you
-        build it... (Koji Success III)"}, {"description": "Ten or more questions and
-        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
-        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
-        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "fedo25", "last_awarded": 1491440137.0, "percent_earned": 1.4182660195039407,
-        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 637, "name": "Curious
-        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
-        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
-        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
-        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "andre", "last_awarded": 1491511008.0, "percent_earned": 9.738611568775884,
-        "id": "curious-penguin-ask-fedora-i", "times_awarded": 4374, "name": "Curious
-        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
-        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
-        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "dtemirgaziyev", "last_awarded": 1491482061.0, "percent_earned": 1.903638063855368,
-        "id": "riddle-me-this", "times_awarded": 855, "name": "Riddle Me This"}, {"description":
-        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
-        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
-        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "mhonek", "last_awarded": 1490899614.0, "percent_earned": 2.0127354499710557,
-        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 904, "name": "You
-        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
-        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
-        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "nickboldt", "last_awarded": 1491244448.0, "percent_earned": 1.94816760920871,
-        "id": "what-goes-up...-koji-failure-i", "times_awarded": 875, "name": "What
-        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
-        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "jscotka",
-        "last_awarded": 1491289110.0, "percent_earned": 2.6695462439328494, "id":
-        "you-can-call-me-patches-scm-i", "times_awarded": 1199, "name": "You can call
-        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
-        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "berrange",
-        "last_awarded": 1491242273.0, "percent_earned": 0.5588457941844414, "id":
-        "you-can-call-me-patches-scm-iv", "times_awarded": 251, "name": "You can call
-        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
-        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "cydrobolt",
-        "last_awarded": 1490744785.0, "percent_earned": 1.3603776105445964, "id":
-        "you-can-call-me-patches-scm-iii", "times_awarded": 611, "name": "You can
-        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
-        builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
-        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "jhogarth", "last_awarded": 1491441515.0, "percent_earned": 0.6523578394264594,
-        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 293, "name": "What
-        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
-        builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
-        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "tkrizek", "last_awarded": 1490376511.0, "percent_earned": 1.329206928797257,
-        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 597, "name": "What
-        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
-        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
-        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "jhogarth", "last_awarded": 1491441872.0, "percent_earned": 0.5299015897047691,
-        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 238, "name":
-        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
-        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
-        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "toshio", "last_awarded": 1491516269.0, "percent_earned": 2.70739635748319,
-        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 1216, "name":
-        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
-        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
-        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
-        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
-        "apollo7", "last_awarded": 1491362331.0, "percent_earned": 7.547757937391459,
-        "id": "junior-badger-badger-i", "times_awarded": 3390, "name": "Junior Badger
-        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
-        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
-        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
-        "scox", "last_awarded": 1491419635.0, "percent_earned": 2.562675335084829,
-        "id": "like-a-rock-updates-stable-i", "times_awarded": 1151, "name": "Like
-        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
-        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "alciregi", "last_awarded": 1491294835.0, "percent_earned": 1.6631785189473214,
-        "id": "perceiving-the-bull-tester-iii", "times_awarded": 747, "name": "Perceiving
-        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
-        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
-        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
-        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "mystro256",
-        "last_awarded": 1491340270.0, "percent_earned": 0.39408647637707617, "id":
-        "like-a-rock-updates-stable-iii", "times_awarded": 177, "name": "Like a Rock
-        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
-        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "landgraf", "last_awarded": 1491498009.0, "percent_earned": 6.412254530881239,
-        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2880, "name": "In
-        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
-        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
-        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
-        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "cqi",
-        "last_awarded": 1491420777.0, "percent_earned": 1.2379213608229058, "id":
-        "like-a-rock-updates-stable-ii", "times_awarded": 556, "name": "Like a Rock
-        (Updates-Stable II)"}, {"description": "Partied with Flock 2013 (at the South
-        Carolina Aquarium)", "tags": "party,flock,event,", "issued": 1376252202.0,
-        "image": "https://badges.fedoraproject.org/pngs/tanked.png", "first_awarded":
-        1376252202.0, "first_awarded_person": "ralph", "last_awarded_person": "gnokii",
-        "last_awarded": 1411656869.0, "percent_earned": 0.14026806786302712, "id":
-        "tanked!", "times_awarded": 63, "name": "Tanked!"}, {"description": "You proposed
-        a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,", "issued":
-        1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
-        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "frantisekz", "last_awarded": 1484316413.0, "percent_earned": 0.3161597720087278,
-        "id": "badge-muse-badge-ideas-i", "times_awarded": 142, "name": "Badge Muse
-        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
-        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
-        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
-        "dtemirgaziyev", "last_awarded": 1491477255.0, "percent_earned": 5.508304760208398,
-        "id": "bona-fide", "times_awarded": 2474, "name": "Bona Fide"}, {"description":
-        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
-        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
-        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.05788840895934453,
-        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
-        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
-        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
-        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "mailga", "last_awarded": 1491037049.0, "percent_earned": 0.823796589036826,
-        "id": "senior-badger-badger-ii", "times_awarded": 370, "name": "Senior Badger
-        (Badger II)"}, {"description": "You pushed your first bodhi update to the
-        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
-        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
-        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "olem",
-        "last_awarded": 1491070078.0, "percent_earned": 2.658413857594514, "id": "is-this-thing-on-updates-testing-i",
-        "times_awarded": 1194, "name": "Is this thing on? (Updates-Testing I)"}, {"description":
-        "Pushed 20 bodhi updates to the testing repositories.", "tags": "development",
-        "issued": 1376077757.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
-        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
-        "dustymabe", "last_awarded": 1491432891.0, "percent_earned": 1.467248519392617,
-        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 659, "name":
-        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
-        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
-        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
-        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "dustymabe",
-        "last_awarded": 1491406327.0, "percent_earned": 1.714387496103665, "id": "partners-in-crime",
-        "times_awarded": 770, "name": "Partners in Crime"}, {"description": "*(a great
-        struggle, repeated escapes, discipline required)*\nTested and added karma
-        to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
-        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "mcepl", "last_awarded": 1491490795.0, "percent_earned": 0.961838179632186,
-        "id": "catching-the-bull-tester-iv", "times_awarded": 432, "name": "Catching
-        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
-        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
-        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
-        "first_awarded_person": "jamielinux", "last_awarded_person": "bt0dotninja",
-        "last_awarded": 1489638271.0, "percent_earned": 0.16253284053969808, "id":
-        "master-tagger-tagger-iv", "times_awarded": 73, "name": "Master Tagger (Tagger
-        IV)"}, {"description": "A member of the sysadmin-badges group.  Nothing to
-        see here..  move along.", "tags": "infrastructure,badges,community,", "issued":
-        1378319150.0, "image": "https://badges.fedoraproject.org/pngs/fas-inside-job.png",
-        "first_awarded": 1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
-        "jflory7", "last_awarded": 1472154166.0, "percent_earned": 0.02226477267667097,
-        "id": "inside-job", "times_awarded": 10, "name": "Inside Job"}, {"description":
-        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
-        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
-        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "salvadorhm", "last_awarded": 1491509400.0, "percent_earned": 8.144453845126241,
-        "id": "white-rabbit", "times_awarded": 3658, "name": "White Rabbit"}, {"description":
-        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
-        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
-        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jcholast", "last_awarded": 1491423845.0, "percent_earned": 3.061406243042258,
-        "id": "mugshot", "times_awarded": 1375, "name": "Mugshot"}, {"description":
-        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
-        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
-        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
-        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.03785011355034065,
-        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
-        me, I know what I am doing"}, {"description": "Has used an ansible playbook
-        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
-        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
-        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jkaluza", "last_awarded": 1490254934.0, "percent_earned": 0.10241795431268647,
-        "id": "maestro", "times_awarded": 46, "name": "Maestro"}, {"description":
-        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
-        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
-        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "cra", "last_awarded": 1491437628.0, "percent_earned": 4.250345103976488,
-        "id": "let-me-introduce-myself", "times_awarded": 1909, "name": "Let Me Introduce
-        Myself"}, {"description": "You submitted a bodhi update including multiple
-        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
-        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
-        "ngompa", "last_awarded": 1490659963.0, "percent_earned": 0.7614552255421472,
-        "id": "binary-star", "times_awarded": 342, "name": "Binary Star"}, {"description":
-        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
-        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
-        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "xavierb", "last_awarded": 1484573828.0, "percent_earned": 0.32506568107939615,
-        "id": "packager-sponsor", "times_awarded": 146, "name": "Packager Sponsor"},
-        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
-        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "stefw", "last_awarded": 1491468491.0, "percent_earned": 1.3470187469385937,
-        "id": "bloggin-it!-planet-ii", "times_awarded": 605, "name": "Bloggin'' it!
-        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
-        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "stefw", "last_awarded": 1491468509.0, "percent_earned": 1.1399563610455536,
-        "id": "bloggin-it!-planet-iii", "times_awarded": 512, "name": "Bloggin'' it!
-        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
-        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "stefw", "last_awarded": 1491468543.0, "percent_earned": 1.6231019281293138,
-        "id": "bloggin-it!-planet-i", "times_awarded": 729, "name": "Bloggin'' it!
-        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
-        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
-        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "dtimms", "last_awarded": 1491484910.0, "percent_earned": 0.939573406955515,
-        "id": "white-hat", "times_awarded": 422, "name": "White Hat"}, {"description":
-        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
-        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
-        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.17589170414570066,
-        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
-        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
-        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
-        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
-        "andrespol", "last_awarded": 1491360716.0, "percent_earned": 20.256490181235247,
-        "id": "embryo", "times_awarded": 9098, "name": "Embryo"}, {"description":
-        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
-        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
-        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "piotrdrag", "last_awarded": 1491478479.0, "percent_earned": 0.549939885113773,
-        "id": "taming-the-bull-tester-v", "times_awarded": 247, "name": "Taming the
-        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
-        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
-        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ferdnyc", "last_awarded": 1484744055.0, "percent_earned": 0.1469474996660284,
-        "id": "common-bugs-contributor", "times_awarded": 66, "name": "Common Bugs
-        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
-        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
-        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "metonymy", "last_awarded": 1491502807.0, "percent_earned": 6.249721690341541,
-        "id": "baby-badger", "times_awarded": 2807, "name": "Baby Badger"}, {"description":
-        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
-        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
-        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "martinkg", "last_awarded": 1489655875.0, "percent_earned": 0.09351204524201807,
-        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 42, "name":
-        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
-        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
-        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
-        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
-        "pwalter", "last_awarded": 1491445231.0, "percent_earned": 0.6167342031437859,
-        "id": "old-yeller", "times_awarded": 277, "name": "Old Yeller"}, {"description":
-        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
-        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
-        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.1580798860043639,
-        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
-        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
-        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
-        "stefw", "last_awarded": 1491468562.0, "percent_earned": 0.7547757937391459,
-        "id": "bloggin-it!-planet-iv", "times_awarded": 339, "name": "Bloggin'' it!
-        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
-        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
-        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "augenauf", "last_awarded": 1491316933.0, "percent_earned": 1.013047156788529,
-        "id": "senior-editor", "times_awarded": 455, "name": "Senior Editor"}, {"description":
-        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
-        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
-        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "avichi", "last_awarded": 1491361425.0, "percent_earned": 14.18933962684241,
-        "id": "tadpole", "times_awarded": 6373, "name": "Tadpole"}, {"description":
-        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
-        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
-        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
-        "amogh23k", "last_awarded": 1491362307.0, "percent_earned": 28.41430288996749,
-        "id": "egg", "times_awarded": 12762, "name": "Egg"}, {"description": "You''ve
-        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
-        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
-        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
-        "akopacsi", "last_awarded": 1490757692.0, "percent_earned": 7.30952486975108,
-        "id": "tadpole-with-legs", "times_awarded": 3283, "name": "Tadpole with Legs"},
-        {"description": "You''re a developer contributing to the Fedora Badges stack",
-        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
-        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "lsedlar", "last_awarded": 1476326553.0, "percent_earned": 0.05120897715634323,
-        "id": "badge-off!", "times_awarded": 23, "name": "Badge Off!"}, {"description":
-        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
-        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "sassam", "last_awarded": 1491148875.0, "percent_earned": 0.3072538629380594,
-        "id": "riding-the-bull-home-tester-vi", "times_awarded": 138, "name": "Riding
-        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
-        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
-        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
-        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
-        "metonymy", "last_awarded": 1491476646.0, "percent_earned": 0.4208042035890813,
-        "id": "no-longer-a-ronin", "times_awarded": 189, "name": "No Longer a Ronin"},
-        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
-        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bt0dotninja", "last_awarded": 1489643141.0, "percent_earned": 0.13358863606002583,
-        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 60, "name":
-        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
-        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
-        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "bbroad", "last_awarded": 1491002111.0, "percent_earned": 0.8750055661931692,
-        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 393, "name":
-        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
-        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
-        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "ignacio", "last_awarded": 1485888954.0, "percent_earned": 0.28944204479672264,
-        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 130, "name":
-        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
-        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
-        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "imabug", "last_awarded": 1490199130.0, "percent_earned": 0.5120897715634324,
-        "id": "package-tagger-package-tagger-ii", "times_awarded": 230, "name": "Package
-        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
-        DevConf.cz, 2014", "tags": "devconf,speaker,event,", "issued": 1390422108.0,
-        "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
-        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
-        "last_awarded": 1420480194.0, "percent_earned": 0.10241795431268647, "id":
-        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
-        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
-        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
-        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "terjeros", "last_awarded": 1491331717.0, "percent_earned": 0.26717727212005166,
-        "id": "patches-scm-v", "times_awarded": 120, "name": "Patches (SCM V)"}, {"description":
-        "Created a buildroot override in the koji build system", "tags": "development,",
-        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
-        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
-        "decathorpe", "last_awarded": 1491331634.0, "percent_earned": 0.7480963619361446,
-        "id": "override,-you-say", "times_awarded": 336, "name": "Override, you say?"},
-        {"description": "You attended the 2014 iteration of devconf.cz, a yearly Linux
-        and JBoss conference in the Czech Republic", "tags": "event,devconf,", "issued":
-        1391763090.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png",
-        "first_awarded": 1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.13804159059536003,
-        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf 2014 Attendee"},
-        {"description": "You are a member of the videos team", "tags": "video,community,",
-        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
-        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
-        "last_awarded_person": "swilson", "last_awarded": 1458943142.0, "percent_earned":
-        0.03562363628267355, "id": "videographer", "times_awarded": 16, "name": "Videographer"},
-        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
-        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
-        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "zbyszek", "last_awarded": 1490388487.0, "percent_earned": 0.15585340873669679,
-        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 70,
-        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
-        "Successfully completed a copr build", "tags": "development,copr,", "issued":
-        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
-        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "shosca", "last_awarded": 1491441908.0, "percent_earned": 3.958676581912099,
-        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1778, "name":
-        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
-        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
-        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
-        "cydrobolt", "last_awarded": 1491503467.0, "percent_earned": 2.046132608986062,
-        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 919, "name":
-        "What goes around comes around (Karma I)"}, {"description": "Tested an update
-        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
-        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
-        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "caiqian",
-        "last_awarded": 1481903131.0, "percent_earned": 1.6765373825533243, "id":
-        "it-still-works!", "times_awarded": 753, "name": "It still works!"}, {"description":
-        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
-        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
-        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
-        "cydrobolt", "last_awarded": 1491442200.0, "percent_earned": 2.1641359041724186,
-        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 972, "name":
-        "Take this and call me in the morning"}, {"description": "You posted 40 or
-        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
-        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
-        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
-        "stefw", "last_awarded": 1491468526.0, "percent_earned": 0.35623636282673554,
-        "id": "bob-loblaw-planet-v", "times_awarded": 160, "name": "Bob Loblaw (Planet
-        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
-        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
-        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "dfateyev", "last_awarded": 1490465620.0, "percent_earned": 0.06902079529768002,
-        "id": "like-a-rock-updates-stable-iv", "times_awarded": 31, "name": "Like
-        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
-        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
-        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
-        "ignatenkobrain", "last_awarded": 1485808919.0, "percent_earned": 0.14472102239836132,
-        "id": "lets-do-lunch!", "times_awarded": 65, "name": "Let''s do lunch!"},
-        {"description": "Sip the lemonade away (You deserve it for remembering your
-        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
-        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
-        "first_awarded_person": "shaiton", "last_awarded_person": "mythcat", "last_awarded":
-        1484694397.0, "percent_earned": 0.4208042035890813, "id": "vacation", "times_awarded":
-        189, "name": "Vacation"}, {"description": "You visited the Fedora booth at
-        Pycon, 2014", "tags": "python,event,pycon,", "issued": 1397168025.0, "image":
-        "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png", "first_awarded":
-        1397168025.0, "first_awarded_person": "ralph", "last_awarded_person": "abompard",
-        "last_awarded": 1397573900.0, "percent_earned": 0.02226477267667097, "id":
-        "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
-        {"description": "You submitted feedback for an update in Bodhi after it was
-        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
-        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
-        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "thozza", "last_awarded": 1439904242.0, "percent_earned": 0.6345460212851227,
-        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
-        {"description": "You built a package owned by someone else.  It takes a village...",
-        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
-        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
-        "nickboldt", "last_awarded": 1490915668.0, "percent_earned": 0.984102952308857,
-        "id": "helping-hand", "times_awarded": 442, "name": "Helping Hand"}, {"description":
-        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
-        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
-        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.20483590862537293,
-        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
-        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
-        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
-        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "wtaymans",
-        "last_awarded": 1490906731.0, "percent_earned": 0.20038295409003873, "id":
-        "what-goes-up...-koji-failure-iv", "times_awarded": 90, "name": "What goes
-        up... (Koji Failure IV)"}, {"description": "You updated your password with
-        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
-        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
-        "payasr", "last_awarded": 1491512765.0, "percent_earned": 61.86712383666563,
-        "id": "paranoid-panda", "times_awarded": 27787, "name": "Paranoid Panda"},
-        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
-        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
-        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
-        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
-        "last_awarded": 1408553413.0, "percent_earned": 0.16253284053969808, "id":
-        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
-        {"description": "You have received 10 or more good karma on your bodhi updates",
-        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
-        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "jvymazal", "last_awarded": 1491284602.0, "percent_earned": 1.099879770227546,
-        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 494, "name":
-        "What goes around comes around (Karma II)"}, {"description": "Edited at least
-        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
-        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
-        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "athoscr",
-        "last_awarded": 1490991464.0, "percent_earned": 0.5900164759317807, "id":
-        "master-editor", "times_awarded": 265, "name": "Master Editor"}, {"description":
-        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
-        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
-        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "terjeros", "last_awarded": 1491384354.0, "percent_earned": 0.389633521841742,
-        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 175, "name":
-        "What goes around comes around (Karma III)"}, {"description": "  You attended
-        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
-        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
-        "first_awarded": 1405296000.0, "first_awarded_person": "marinaz", "last_awarded_person":
-        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.27163022665538583,
-        "id": "flock-2014-attendee", "times_awarded": 122, "name": "Flock 2014 Attendee"},
-        {"description": "You completed a run of the kernel regression test suite",
-        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
-        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "pperron", "last_awarded": 1490999828.0, "percent_earned": 0.49873090795742975,
-        "id": "science-kernel-tester-i", "times_awarded": 224, "name": "Science (Kernel
-        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
-        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
-        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
-        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
-        "last_awarded": 1408665317.0, "percent_earned": 0.19815647682237164, "id":
-        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
-        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
-        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
-        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
-        "pghmcfc", "last_awarded": 1485788654.0, "percent_earned": 0.03339715901500646,
-        "id": "corporate-overlord", "times_awarded": 15, "name": "Corporate Overlord"},
-        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
-        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
-        "kdudka", "last_awarded": 1491214689.0, "percent_earned": 0.18925056775170326,
-        "id": "corporate-shill", "times_awarded": 85, "name": "Corporate Shill"},
-        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
-        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
-        "dsommers", "last_awarded": 1490298016.0, "percent_earned": 1.3024892015852518,
-        "id": "corporate-drone", "times_awarded": 585, "name": "Corporate Drone"},
-        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
-        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
-        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "vondruch", "last_awarded": 1491296529.0, "percent_earned": 0.14026806786302712,
-        "id": "master-badger-badger-iii", "times_awarded": 63, "name": "Master Badger
-        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
-        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
-        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
-        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
-        "first_awarded_person": "kevin", "last_awarded_person": "fale", "last_awarded":
-        1490321832.0, "percent_earned": 0.2248742040343768, "id": "the-bull-transcended-tester-vii",
-        "times_awarded": 101, "name": "The Bull Transcended (Tester VII)"}, {"description":
-        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
-        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
-        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "rbergero", "last_awarded": 1455959914.0, "percent_earned": 0.0712472725653471,
-        "id": "dancing-with-toshio", "times_awarded": 32, "name": "Dancing with Toshio"},
-        {"description": "Voted in a supplemental wallpapers election for the Fedora
-        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
-        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
-        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
-        "last_awarded": 1409902273.0, "percent_earned": 0.2449124994433807, "id":
-        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
-        "We''re sorry, but you had one of your badges revoked.  Something must have
-        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
-        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
-        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "keitellf",
-        "last_awarded": 1465418173.0, "percent_earned": 0.8972703388698402, "id":
-        "consolation-prize", "times_awarded": 403, "name": "Consolation Prize"}, {"description":
-        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
-        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
-        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
-        "usuha", "last_awarded": 1491448085.0, "percent_earned": 6.430066349022577,
-        "id": "crypto-panda", "times_awarded": 2888, "name": "Crypto Panda"}, {"description":
-        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
-        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
-        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "shosca", "last_awarded": 1491505320.0, "percent_earned": 2.3711982900654585,
-        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 1065, "name":
-        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
-        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
-        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "pghmcfc", "last_awarded": 1490811747.0, "percent_earned": 0.03562363628267355,
-        "id": "mic-check!-updates-testing-v", "times_awarded": 16, "name": "Mic Check!
-        (Updates-Testing V)"}, {"description": "You took ownership of a previously
-        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
-        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
-        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
-        "sailer", "last_awarded": 1490344262.0, "percent_earned": 0.7525493164714788,
-        "id": "the-cat-came-back...", "times_awarded": 338, "name": "The cat came
-        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
-        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
-        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
-        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "michalrud", "last_awarded": 1470317213.0, "percent_earned": 0.04675602262100904,
-        "id": "apprentice-badge-artist-i", "times_awarded": 21, "name": "Apprentice
-        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
-        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
-        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "kkeithle", "last_awarded": 1491364811.0, "percent_earned": 0.20706238589304005,
-        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 93, "name":
-        "What goes around comes around (Karma IV)"}, {"description": "You participated
-        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
-        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
-        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
-        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.04007659081800775,
-        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
-        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
-        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
-        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
-        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.13804159059536003,
-        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
-        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
-        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
-        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
-        "orion", "last_awarded": 1490756246.0, "percent_earned": 0.024491249944338066,
-        "id": "tectonic!-updates-stable-v", "times_awarded": 11, "name": "Tectonic!
-        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
-        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
-        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
-        "pcreech17", "last_awarded": 1491432940.0, "percent_earned": 2.3756512446007925,
-        "id": "associate-badger-badger-1.5", "times_awarded": 1067, "name": "Associate
-        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
-        Contributor Conference", "tags": "conference,rochester,events,flock,flock
-        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
-        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
-        "kellin", "last_awarded": 1461547496.0, "percent_earned": 0.18479761321636906,
-        "id": "flock-2015-attendee", "times_awarded": 83, "name": "Flock 2015 Attendee"},
-        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
-        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
-        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
-        "gtierney", "last_awarded": 1491405719.0, "percent_earned": 1.852429086699025,
-        "id": "macaron-cookie-i", "times_awarded": 832, "name": "Macaron (Cookie I)"},
-        {"description": "Ten people think you''re great, because they''ve given you
-        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
-        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
-        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "mizdebsk",
-        "last_awarded": 1491500198.0, "percent_earned": 0.3606893173620697, "id":
-        "chocolate-chip-cookie-ii", "times_awarded": 162, "name": "Chocolate Chip
-        (Cookie II)"}, {"description": "Voted in the supplemental wallpapers election
-        for the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
-        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
-        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.18257113594870197,
-        "id": "nuancier-f22", "times_awarded": 82, "name": "Nuancier (F22)"}, {"description":
-        "You pinned your country in FAS!", "tags": "account,community,", "issued":
-        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
-        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
-        "schwankek", "last_awarded": 1491486520.0, "percent_earned": 17.635926437191078,
-        "id": "origin", "times_awarded": 7921, "name": "Origin"}, {"description":
-        "You added a new package to the distribution.", "tags": "development,", "issued":
-        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
-        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
-        "nmilosev", "last_awarded": 1491213323.0, "percent_earned": 0.919535111546511,
-        "id": "delivery", "times_awarded": 413, "name": "Delivery"}, {"description":
-        "You mapped an upstream project to a Fedora package on release-monitoring.org",
-        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
-        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "dustymabe", "last_awarded": 1475240820.0, "percent_earned": 0.5655252259874427,
-        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 254,
-        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
-        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
-        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
-        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "dmsimard", "last_awarded": 1491321510.0, "percent_earned": 0.14472102239836132,
-        "id": "black-and-white-cookie-iii", "times_awarded": 65, "name": "Black and
-        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
-        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
-        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "smani", "last_awarded": 1485976444.0, "percent_earned": 0.08460613617134968,
-        "id": "hindenburg-koji-failure-v", "times_awarded": 38, "name": "Hindenburg
-        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
-        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
-        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
-        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jflory7", "last_awarded": 1475509860.0, "percent_earned": 0.006679431803001291,
-        "id": "badge-muse-badges-released-iv", "times_awarded": 3, "name": "Badge
-        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
-        ideas were approved and released.  Superb!", "tags": "community,badges,",
-        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
-        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "pravins", "last_awarded": 1472553692.0, "percent_earned": 0.03562363628267355,
-        "id": "badge-muse-badges-released-ii", "times_awarded": 16, "name": "Badge
-        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
-        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
-        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
-        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "frantisekz", "last_awarded": 1485462295.0, "percent_earned": 0.10019147704501936,
-        "id": "badge-muse-badges-released-i", "times_awarded": 45, "name": "Badge
-        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
-        ideas were approved and released.  Impressive!", "tags": "community,badges,",
-        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
-        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "jflory7", "last_awarded": 1475509873.0, "percent_earned": 0.013358863606002582,
-        "id": "badge-muse-badges-released-iii", "times_awarded": 6, "name": "Badge
-        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
-        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
-        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
-        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.002226477267667097,
-        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
-        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
-        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
-        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
-        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "kellin", "last_awarded": 1461547520.0, "percent_earned": 0.16921227234269937,
-        "id": "nom-nom-nom", "times_awarded": 76, "name": "Nom Nom Nom"}, {"description":
-        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
-        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
-        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "rluzynski", "last_awarded": 1491442095.0, "percent_earned": 1.5763459055083047,
-        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 708, "name":
-        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
-        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
-        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
-        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "dustymabe", "last_awarded": 1491326903.0, "percent_earned": 0.12468272698935744,
-        "id": "rock-the-web!", "times_awarded": 56, "name": "Rock the Web!"}, {"description":
-        "You can speak Python and and you''ve ported at least one package to Python
-        3", "tags": "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
-        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
-        "crobinso", "last_awarded": 1491217608.0, "percent_earned": 0.33842454468539873,
-        "id": "parselmouth", "times_awarded": 152, "name": "Parselmouth I"}, {"description":
-        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
-        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
-        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "jonatoni",
-        "last_awarded": 1490211890.0, "percent_earned": 0.22710068130204392, "id":
-        "chief-editor", "times_awarded": 102, "name": "Chief Editor"}, {"description":
-        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
-        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
-        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "apahim", "last_awarded": 1491360865.0, "percent_earned": 4.628846239479895,
-        "id": "froglet", "times_awarded": 2079, "name": "Froglet"}, {"description":
-        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
-        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
-        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ryanlerch", "last_awarded": 1490719235.0, "percent_earned": 0.03117068174733936,
-        "id": "pizzelle-cookie-iv", "times_awarded": 14, "name": "Pizzelle (Cookie
-        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
-        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "churchyard", "last_awarded": 1475564266.0, "percent_earned": 0.011132386338335486,
-        "id": "silver", "times_awarded": 5, "name": "Silver"}, {"description": "You
-        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
-        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "fale", "last_awarded": 1489622707.0, "percent_earned": 0.03117068174733936,
-        "id": "top-10", "times_awarded": 14, "name": "Top 10"}, {"description": "You
-        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
-        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "tflink", "last_awarded": 1480461776.0, "percent_earned": 0.25159193124638196,
-        "id": "top-100", "times_awarded": 113, "name": "Top 100"}, {"description":
-        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
-        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "mrunge", "last_awarded": 1490730635.0, "percent_earned": 0.06679431803001291,
-        "id": "top-25", "times_awarded": 30, "name": "Top 25"}, {"description": "You
-        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
-        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "zsun", "last_awarded": 1490677027.0, "percent_earned": 1.2000712472725654,
-        "id": "top-500", "times_awarded": 539, "name": "Top 500"}, {"description":
-        "You visited the Fedora table at BrickHack 2016!", "tags": "brickhack,event,hackathon,events,",
-        "issued": 1457234130.0, "image": "http://infrastructure.fedoraproject.org/infra/badges/pngs/events-brickhack-2016.png",
-        "first_awarded": 1455845197.0, "first_awarded_person": "jflory7", "last_awarded_person":
-        "brandondgr8", "last_awarded": 1461299769.0, "percent_earned": 0.05566193169167742,
-        "id": "brickhack-2016-attendee", "times_awarded": 25, "name": "BrickHack 2016
-        Attendee"}, {"description": "You gave a presentation at DevConf.cz, 2016",
-        "tags": "devconf,speaker,event,", "issued": 1455008224.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2016.png",
-        "first_awarded": 1454667336.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "thozza", "last_awarded": 1459500320.0, "percent_earned": 0.2137418176960413,
-        "id": "devconf-2016-speaker", "times_awarded": 96, "name": "DevConf 2016 Speaker"},
-        {"description": "You attended the 2016 iteration of DevConf.cz, a yearly Linux
-        and JBoss conference in the Czech Republic", "tags": "event, devconf,", "issued":
-        1455120228.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee-2016.png",
-        "first_awarded": 1454600601.0, "first_awarded_person": "eischmann", "last_awarded_person":
-        "dkaspar", "last_awarded": 1461940547.0, "percent_earned": 0.18925056775170326,
-        "id": "devconf-2016-attendee", "times_awarded": 85, "name": "DevConf 2016
-        Attendee"}, {"description": "You got a \"Change\" accepted into the Fedora
-        24 Change list", "tags": "development,FESCo,process,", "issued": 1458652673.0,
-        "image": "https://badges.fedoraproject.org/pngs/changes-f24.png", "first_awarded":
-        1458651465.0, "first_awarded_person": "eischmann", "last_awarded_person":
-        "pnemade", "last_awarded": 1459240914.0, "percent_earned": 0.10019147704501936,
-        "id": "fedora-24-change-accepted", "times_awarded": 45, "name": "Fedora 24
-        Change Accepted"}, {"description": "You held third place on the Fedora Badges
-        leaderboard", "tags": "meta,community,", "issued": 1462904993.0, "image":
-        "https://badges.fedoraproject.org/pngs/3_badge_340.png", "first_awarded":
-        1452875229.0, "first_awarded_person": "pnemade", "last_awarded_person": "kevin",
-        "last_awarded": 1489692901.0, "percent_earned": 0.011132386338335486, "id":
-        "bronze", "times_awarded": 5, "name": "Bronze"}, {"description": "You burned
-        a yubikey and linked it with your Fedora Account", "tags": "account,community,",
-        "issued": 1462904755.0, "image": "https://badges.fedoraproject.org/pngs/yubi-badge.png",
-        "first_awarded": 1422906928.0, "first_awarded_person": "plautrba", "last_awarded_person":
-        "findarato", "last_awarded": 1491408410.0, "percent_earned": 0.4052188627154117,
-        "id": "horcrux", "times_awarded": 182, "name": "Horcrux"}, {"description":
-        "You hacked with the Fedora crew at PyCon US 2016", "tags": "event, python,pycon,",
-        "issued": 1464988862.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2016_attendee.png",
-        "first_awarded": 1464988862.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "maxamillion", "last_awarded": 1464991242.0, "percent_earned": 0.028944204479672265,
-        "id": "pycon-2016-attendee", "times_awarded": 13, "name": "PyCon 2016 Attendee"},
-        {"description": "You got 150 Fedora Badges!  Wow!", "tags": "badges,community,",
-        "issued": 1468058613.0, "image": "https://badges.fedoraproject.org/pngs/badger-04.png",
-        "first_awarded": 1457979017.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "pbrobinson", "last_awarded": 1490919191.0, "percent_earned": 0.020038295409003874,
-        "id": "badge-junkie-badger-iv", "times_awarded": 9, "name": "Badge Junkie
-        (Badger IV)"}, {"description": "You can speak Python and and you''ve ported
-        at least five packages to Python 3", "tags": "python,miscellaneous,", "issued":
-        1468058067.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-II.png",
-        "first_awarded": 1467988651.0, "first_awarded_person": "cstratak", "last_awarded_person":
-        "ishcherb", "last_awarded": 1488193805.0, "percent_earned": 0.028944204479672265,
-        "id": "parselmouth-ii", "times_awarded": 13, "name": "Parselmouth II"}, {"description":
-        "You can speak Python and and you''ve ported at least ten packages to Python
-        3", "tags": "python,miscellaneous,", "issued": 1468058072.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-III.png",
-        "first_awarded": 1467997850.0, "first_awarded_person": "cstratak", "last_awarded_person":
-        "ishcherb", "last_awarded": 1489753361.0, "percent_earned": 0.02226477267667097,
-        "id": "parselmouth-iii", "times_awarded": 10, "name": "Parselmouth III"},
-        {"description": "You attended Flock 2016, the Fedora Contributor Conference",
-        "tags": "flock,event,events,", "issued": 1470404480.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-attendee.png",
-        "first_awarded": 1468984748.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "adrian", "last_awarded": 1486483875.0, "percent_earned": 0.2360065903727123,
-        "id": "flock-2016-attendee", "times_awarded": 106, "name": "Flock 2016 Attendee"},
-        {"description": "You attended the party at Flock 2016 in Krakow!", "tags":
-        "flock,krakow,event,events,", "issued": 1470404592.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/krakow-brews.png",
-        "first_awarded": 1468963417.0, "first_awarded_person": "duffy", "last_awarded_person":
-        "kittykat", "last_awarded": 1486217490.0, "percent_earned": 0.18257113594870197,
-        "id": "krakow-brews!", "times_awarded": 82, "name": "Krakow Brews!"}, {"description":
-        "You gave a presentation at Flock 2016, the Fedora Contributor Conference",
-        "tags": "flock,speaker,event,", "issued": 1471354751.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-speaker.png",
-        "first_awarded": 1470941077.0, "first_awarded_person": "mattdm", "last_awarded_person":
-        "kittykat", "last_awarded": 1486217546.0, "percent_earned": 0.19592999955470453,
-        "id": "flock-2016-speaker", "times_awarded": 88, "name": "Flock 2016 Speaker"},
-        {"description": "You''re a member of the Modularity Working Group!", "tags":
-        "modularity,community,", "issued": 1475082397.0, "image": "https://badges.fedoraproject.org/pngs/fas-modularity-wg.png",
-        "first_awarded": 1475082098.0, "first_awarded_person": "asamalik", "last_awarded_person":
-        "jscotka", "last_awarded": 1491213584.0, "percent_earned": 0.0801531816360155,
-        "id": "modularity-wg-member", "times_awarded": 36, "name": "Modularity WG
-        Member"}, {"description": "You got a \"Change\" accepted into the Fedora 26
-        Change list", "tags": "development, FESCo, process,", "issued": 1479749896.0,
-        "image": "https://badges.fedoraproject.org/pngs/changes-f26.png", "first_awarded":
-        1473331018.0, "first_awarded_person": "cstratak", "last_awarded_person": "ncoghlan",
-        "last_awarded": 1489656918.0, "percent_earned": 0.11577681791868906, "id":
-        "fedora-26-change-accepted", "times_awarded": 52, "name": "Fedora 26 Change
-        Accepted"}, {"description": "You gave a presentation at DevConf.cz, 2017",
-        "tags": "speaker,devconf,event,", "issued": 1486037155.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2017.png",
-        "first_awarded": 1486033923.0, "first_awarded_person": "jflory7", "last_awarded_person":
-        "siddharths", "last_awarded": 1486077040.0, "percent_earned": 0.24713897671104776,
-        "id": "devconf-2017-speaker", "times_awarded": 111, "name": "DevConf 2017
-        Speaker"}, {"description": "You have helped so many Fedorans you''ve got over
-        100 cookies. Don''t eat them all at once!", "tags": "cookie,community,", "issued":
-        1486153659.0, "image": "https://badges.fedoraproject.org/pngs/rainbowcookie.png",
-        "first_awarded": 1468278719.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "ralph", "last_awarded": 1486153659.0, "percent_earned": 0.011132386338335486,
-        "id": "rainbow-cookie-v", "times_awarded": 5, "name": "Rainbow (Cookie V)"}],
-        "percent_earned": 41.81818181818181, "user": "ralph"}'}
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=45356299]
-      connection: [Keep-Alive]
-      content-length: ['74203']
-      content-type: [application/json; charset=UTF-8]
-      date: ['Thu, 06 Apr 2017 22:32:50 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://badges.fedoraproject.org/user/ralph/json
-  response:
-    body: {string: !!python/unicode '{"user_count": 44887, "rank": 5, "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png",
-        "percentile": "0.01", "assertions": [{"description": "You attended Flock 2013,
-        the Fedora Contributor Conference", "tags": "flock,event,", "issued": 1375373082.0,
-        "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
-        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "rbergero", "last_awarded": 1473972160.0, "percent_earned": 0.18034465868103486,
-        "id": "flock-2013-attendee", "times_awarded": 81, "name": "Flock 2013 Attendee"},
-        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
-        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "imabug", "last_awarded": 1490198996.0, "percent_earned": 0.663490225764795,
-        "id": "tagger-tagger-ii", "times_awarded": 298, "name": "Tagger (Tagger II)"},
-        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
-        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bbroad", "last_awarded": 1491002037.0, "percent_earned": 1.0508972703388697,
-        "id": "junior-tagger-tagger-i", "times_awarded": 472, "name": "Junior Tagger
-        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
-        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
-        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "ylarguex", "last_awarded": 1491516838.0, "percent_earned": 53.357527719641986,
-        "id": "involvement", "times_awarded": 23965, "name": "Involvement"}, {"description":
-        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
-        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
-        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "icole",
-        "last_awarded": 1491505117.0, "percent_earned": 3.9564501046444316, "id":
-        "speak-up!", "times_awarded": 1777, "name": "Speak Up!"}, {"description":
-        "Edited at least 10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0,
-        "image": "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
-        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "kdudka",
-        "last_awarded": 1491484751.0, "percent_earned": 3.3129981742886407, "id":
-        "junior-editor", "times_awarded": 1488, "name": "Junior Editor"}, {"description":
-        "Edited at least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0,
-        "image": "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
-        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "ankit1997",
-        "last_awarded": 1491242577.0, "percent_earned": 2.108473972480741, "id": "associate-editor",
-        "times_awarded": 947, "name": "Associate Editor"}, {"description": "Chaired
-        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
-        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
-        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "yzhang",
-        "last_awarded": 1491431124.0, "percent_earned": 1.5451752237609653, "id":
-        "secretary-general", "times_awarded": 694, "name": "Secretary General"}, {"description":
-        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
-        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
-        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "imabug", "last_awarded": 1490198974.0, "percent_earned": 0.3139332947410607,
-        "id": "senior-tagger-tagger-iii", "times_awarded": 141, "name": "Senior Tagger
-        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
-        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
-        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
-        "jhogarth", "last_awarded": 1491425650.0, "percent_earned": 0.5454869305784388,
-        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 245, "name":
-        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
-        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
-        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "nickboldt",
-        "last_awarded": 1490915696.0, "percent_earned": 2.858796811684553, "id": "if-you-build-it...-koji-success-i",
-        "times_awarded": 1284, "name": "If you build it... (Koji Success I)"}, {"description":
-        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
-        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
-        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
-        "sjenning", "last_awarded": 1491017600.0, "percent_earned": 2.3288952219797836,
-        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 1046, "name":
-        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
-        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
-        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "tartare",
-        "last_awarded": 1491481451.0, "percent_earned": 1.4138130649686065, "id":
-        "if-you-build-it...-koji-success-iii", "times_awarded": 635, "name": "If you
-        build it... (Koji Success III)"}, {"description": "Ten or more questions and
-        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
-        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
-        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "fedo25", "last_awarded": 1491440137.0, "percent_earned": 1.4182660195039407,
-        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 637, "name": "Curious
-        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
-        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
-        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
-        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
-        "andre", "last_awarded": 1491511008.0, "percent_earned": 9.738611568775884,
-        "id": "curious-penguin-ask-fedora-i", "times_awarded": 4374, "name": "Curious
-        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
-        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
-        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "dtemirgaziyev", "last_awarded": 1491482061.0, "percent_earned": 1.903638063855368,
-        "id": "riddle-me-this", "times_awarded": 855, "name": "Riddle Me This"}, {"description":
-        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
-        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
-        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "mhonek", "last_awarded": 1490899614.0, "percent_earned": 2.0127354499710557,
-        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 904, "name": "You
-        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
-        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
-        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "nickboldt", "last_awarded": 1491244448.0, "percent_earned": 1.94816760920871,
-        "id": "what-goes-up...-koji-failure-i", "times_awarded": 875, "name": "What
-        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
-        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "jscotka",
-        "last_awarded": 1491289110.0, "percent_earned": 2.6695462439328494, "id":
-        "you-can-call-me-patches-scm-i", "times_awarded": 1199, "name": "You can call
-        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
-        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "berrange",
-        "last_awarded": 1491242273.0, "percent_earned": 0.5588457941844414, "id":
-        "you-can-call-me-patches-scm-iv", "times_awarded": 251, "name": "You can call
-        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
-        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
-        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
-        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "cydrobolt",
-        "last_awarded": 1490744785.0, "percent_earned": 1.3603776105445964, "id":
-        "you-can-call-me-patches-scm-iii", "times_awarded": 611, "name": "You can
-        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
-        builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
-        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "jhogarth", "last_awarded": 1491441515.0, "percent_earned": 0.6523578394264594,
-        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 293, "name": "What
-        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
-        builds that failed to build.", "tags": "development,oops,koji,", "issued":
-        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
-        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
-        "tkrizek", "last_awarded": 1490376511.0, "percent_earned": 1.329206928797257,
-        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 597, "name": "What
-        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
-        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
-        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "jhogarth", "last_awarded": 1491441872.0, "percent_earned": 0.5299015897047691,
-        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 238, "name":
-        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
-        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
-        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "toshio", "last_awarded": 1491516269.0, "percent_earned": 2.70739635748319,
-        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 1216, "name":
-        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
-        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
-        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
-        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
-        "apollo7", "last_awarded": 1491362331.0, "percent_earned": 7.547757937391459,
-        "id": "junior-badger-badger-i", "times_awarded": 3390, "name": "Junior Badger
-        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
-        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
-        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
-        "scox", "last_awarded": 1491419635.0, "percent_earned": 2.562675335084829,
-        "id": "like-a-rock-updates-stable-i", "times_awarded": 1151, "name": "Like
-        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
-        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "alciregi", "last_awarded": 1491294835.0, "percent_earned": 1.6631785189473214,
-        "id": "perceiving-the-bull-tester-iii", "times_awarded": 747, "name": "Perceiving
-        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
-        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
-        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
-        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "mystro256",
-        "last_awarded": 1491340270.0, "percent_earned": 0.39408647637707617, "id":
-        "like-a-rock-updates-stable-iii", "times_awarded": 177, "name": "Like a Rock
-        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
-        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
-        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "landgraf", "last_awarded": 1491498009.0, "percent_earned": 6.412254530881239,
-        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2880, "name": "In
-        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
-        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
-        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
-        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "cqi",
-        "last_awarded": 1491420777.0, "percent_earned": 1.2379213608229058, "id":
-        "like-a-rock-updates-stable-ii", "times_awarded": 556, "name": "Like a Rock
-        (Updates-Stable II)"}, {"description": "Partied with Flock 2013 (at the South
-        Carolina Aquarium)", "tags": "party,flock,event,", "issued": 1376252202.0,
-        "image": "https://badges.fedoraproject.org/pngs/tanked.png", "first_awarded":
-        1376252202.0, "first_awarded_person": "ralph", "last_awarded_person": "gnokii",
-        "last_awarded": 1411656869.0, "percent_earned": 0.14026806786302712, "id":
-        "tanked!", "times_awarded": 63, "name": "Tanked!"}, {"description": "You proposed
-        a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,", "issued":
-        1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
-        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "frantisekz", "last_awarded": 1484316413.0, "percent_earned": 0.3161597720087278,
-        "id": "badge-muse-badge-ideas-i", "times_awarded": 142, "name": "Badge Muse
-        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
-        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
-        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
-        "dtemirgaziyev", "last_awarded": 1491477255.0, "percent_earned": 5.508304760208398,
-        "id": "bona-fide", "times_awarded": 2474, "name": "Bona Fide"}, {"description":
-        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
-        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
-        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.05788840895934453,
-        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
-        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
-        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
-        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "mailga", "last_awarded": 1491037049.0, "percent_earned": 0.823796589036826,
-        "id": "senior-badger-badger-ii", "times_awarded": 370, "name": "Senior Badger
-        (Badger II)"}, {"description": "You pushed your first bodhi update to the
-        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
-        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
-        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "olem",
-        "last_awarded": 1491070078.0, "percent_earned": 2.658413857594514, "id": "is-this-thing-on-updates-testing-i",
-        "times_awarded": 1194, "name": "Is this thing on? (Updates-Testing I)"}, {"description":
-        "Pushed 20 bodhi updates to the testing repositories.", "tags": "development",
-        "issued": 1376077757.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
-        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
-        "dustymabe", "last_awarded": 1491432891.0, "percent_earned": 1.467248519392617,
-        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 659, "name":
-        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
-        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
-        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
-        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "dustymabe",
-        "last_awarded": 1491406327.0, "percent_earned": 1.714387496103665, "id": "partners-in-crime",
-        "times_awarded": 770, "name": "Partners in Crime"}, {"description": "*(a great
-        struggle, repeated escapes, discipline required)*\nTested and added karma
-        to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
-        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "mcepl", "last_awarded": 1491490795.0, "percent_earned": 0.961838179632186,
-        "id": "catching-the-bull-tester-iv", "times_awarded": 432, "name": "Catching
-        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
-        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
-        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
-        "first_awarded_person": "jamielinux", "last_awarded_person": "bt0dotninja",
-        "last_awarded": 1489638271.0, "percent_earned": 0.16253284053969808, "id":
-        "master-tagger-tagger-iv", "times_awarded": 73, "name": "Master Tagger (Tagger
-        IV)"}, {"description": "A member of the sysadmin-badges group.  Nothing to
-        see here..  move along.", "tags": "infrastructure,badges,community,", "issued":
-        1378319150.0, "image": "https://badges.fedoraproject.org/pngs/fas-inside-job.png",
-        "first_awarded": 1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
-        "jflory7", "last_awarded": 1472154166.0, "percent_earned": 0.02226477267667097,
-        "id": "inside-job", "times_awarded": 10, "name": "Inside Job"}, {"description":
-        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
-        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
-        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "salvadorhm", "last_awarded": 1491509400.0, "percent_earned": 8.144453845126241,
-        "id": "white-rabbit", "times_awarded": 3658, "name": "White Rabbit"}, {"description":
-        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
-        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
-        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jcholast", "last_awarded": 1491423845.0, "percent_earned": 3.061406243042258,
-        "id": "mugshot", "times_awarded": 1375, "name": "Mugshot"}, {"description":
-        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
-        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
-        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
-        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.03785011355034065,
-        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
-        me, I know what I am doing"}, {"description": "Has used an ansible playbook
-        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
-        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
-        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jkaluza", "last_awarded": 1490254934.0, "percent_earned": 0.10241795431268647,
-        "id": "maestro", "times_awarded": 46, "name": "Maestro"}, {"description":
-        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
-        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
-        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "cra", "last_awarded": 1491437628.0, "percent_earned": 4.250345103976488,
-        "id": "let-me-introduce-myself", "times_awarded": 1909, "name": "Let Me Introduce
-        Myself"}, {"description": "You submitted a bodhi update including multiple
-        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
-        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
-        "ngompa", "last_awarded": 1490659963.0, "percent_earned": 0.7614552255421472,
-        "id": "binary-star", "times_awarded": 342, "name": "Binary Star"}, {"description":
-        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
-        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
-        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "xavierb", "last_awarded": 1484573828.0, "percent_earned": 0.32506568107939615,
-        "id": "packager-sponsor", "times_awarded": 146, "name": "Packager Sponsor"},
-        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
-        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "stefw", "last_awarded": 1491468491.0, "percent_earned": 1.3470187469385937,
-        "id": "bloggin-it!-planet-ii", "times_awarded": 605, "name": "Bloggin'' it!
-        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
-        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "stefw", "last_awarded": 1491468509.0, "percent_earned": 1.1399563610455536,
-        "id": "bloggin-it!-planet-iii", "times_awarded": 512, "name": "Bloggin'' it!
-        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
-        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
-        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
-        "stefw", "last_awarded": 1491468543.0, "percent_earned": 1.6231019281293138,
-        "id": "bloggin-it!-planet-i", "times_awarded": 729, "name": "Bloggin'' it!
-        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
-        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
-        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "dtimms", "last_awarded": 1491484910.0, "percent_earned": 0.939573406955515,
-        "id": "white-hat", "times_awarded": 422, "name": "White Hat"}, {"description":
-        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
-        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
-        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.17589170414570066,
-        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
-        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
-        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
-        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
-        "andrespol", "last_awarded": 1491360716.0, "percent_earned": 20.256490181235247,
-        "id": "embryo", "times_awarded": 9098, "name": "Embryo"}, {"description":
-        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
-        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
-        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
-        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "piotrdrag", "last_awarded": 1491478479.0, "percent_earned": 0.549939885113773,
-        "id": "taming-the-bull-tester-v", "times_awarded": 247, "name": "Taming the
-        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
-        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
-        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ferdnyc", "last_awarded": 1484744055.0, "percent_earned": 0.1469474996660284,
-        "id": "common-bugs-contributor", "times_awarded": 66, "name": "Common Bugs
-        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
-        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
-        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "metonymy", "last_awarded": 1491502807.0, "percent_earned": 6.249721690341541,
-        "id": "baby-badger", "times_awarded": 2807, "name": "Baby Badger"}, {"description":
-        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
-        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
-        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "martinkg", "last_awarded": 1489655875.0, "percent_earned": 0.09351204524201807,
-        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 42, "name":
-        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
-        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
-        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
-        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
-        "pwalter", "last_awarded": 1491445231.0, "percent_earned": 0.6167342031437859,
-        "id": "old-yeller", "times_awarded": 277, "name": "Old Yeller"}, {"description":
-        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
-        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
-        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.1580798860043639,
-        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
-        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
-        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
-        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
-        "stefw", "last_awarded": 1491468562.0, "percent_earned": 0.7547757937391459,
-        "id": "bloggin-it!-planet-iv", "times_awarded": 339, "name": "Bloggin'' it!
-        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
-        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
-        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "augenauf", "last_awarded": 1491316933.0, "percent_earned": 1.013047156788529,
-        "id": "senior-editor", "times_awarded": 455, "name": "Senior Editor"}, {"description":
-        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
-        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
-        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "avichi", "last_awarded": 1491361425.0, "percent_earned": 14.18933962684241,
-        "id": "tadpole", "times_awarded": 6373, "name": "Tadpole"}, {"description":
-        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
-        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
-        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
-        "amogh23k", "last_awarded": 1491362307.0, "percent_earned": 28.41430288996749,
-        "id": "egg", "times_awarded": 12762, "name": "Egg"}, {"description": "You''ve
-        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
-        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
-        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
-        "akopacsi", "last_awarded": 1490757692.0, "percent_earned": 7.30952486975108,
-        "id": "tadpole-with-legs", "times_awarded": 3283, "name": "Tadpole with Legs"},
-        {"description": "You''re a developer contributing to the Fedora Badges stack",
-        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
-        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "lsedlar", "last_awarded": 1476326553.0, "percent_earned": 0.05120897715634323,
-        "id": "badge-off!", "times_awarded": 23, "name": "Badge Off!"}, {"description":
-        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
-        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
-        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "sassam", "last_awarded": 1491148875.0, "percent_earned": 0.3072538629380594,
-        "id": "riding-the-bull-home-tester-vi", "times_awarded": 138, "name": "Riding
-        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
-        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
-        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
-        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
-        "metonymy", "last_awarded": 1491476646.0, "percent_earned": 0.4208042035890813,
-        "id": "no-longer-a-ronin", "times_awarded": 189, "name": "No Longer a Ronin"},
-        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
-        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
-        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "bt0dotninja", "last_awarded": 1489643141.0, "percent_earned": 0.13358863606002583,
-        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 60, "name":
-        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
-        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
-        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "bbroad", "last_awarded": 1491002111.0, "percent_earned": 0.8750055661931692,
-        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 393, "name":
-        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
-        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
-        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "ignacio", "last_awarded": 1485888954.0, "percent_earned": 0.28944204479672264,
-        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 130, "name":
-        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
-        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
-        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
-        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "imabug", "last_awarded": 1490199130.0, "percent_earned": 0.5120897715634324,
-        "id": "package-tagger-package-tagger-ii", "times_awarded": 230, "name": "Package
-        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
-        DevConf.cz, 2014", "tags": "devconf,speaker,event,", "issued": 1390422108.0,
-        "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
-        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
-        "last_awarded": 1420480194.0, "percent_earned": 0.10241795431268647, "id":
-        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
-        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
-        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
-        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "terjeros", "last_awarded": 1491331717.0, "percent_earned": 0.26717727212005166,
-        "id": "patches-scm-v", "times_awarded": 120, "name": "Patches (SCM V)"}, {"description":
-        "Created a buildroot override in the koji build system", "tags": "development,",
-        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
-        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
-        "decathorpe", "last_awarded": 1491331634.0, "percent_earned": 0.7480963619361446,
-        "id": "override,-you-say", "times_awarded": 336, "name": "Override, you say?"},
-        {"description": "You attended the 2014 iteration of devconf.cz, a yearly Linux
-        and JBoss conference in the Czech Republic", "tags": "event,devconf,", "issued":
-        1391763090.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png",
-        "first_awarded": 1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
-        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.13804159059536003,
-        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf 2014 Attendee"},
-        {"description": "You are a member of the videos team", "tags": "video,community,",
-        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
-        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
-        "last_awarded_person": "swilson", "last_awarded": 1458943142.0, "percent_earned":
-        0.03562363628267355, "id": "videographer", "times_awarded": 16, "name": "Videographer"},
-        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
-        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
-        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
-        "zbyszek", "last_awarded": 1490388487.0, "percent_earned": 0.15585340873669679,
-        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 70,
-        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
-        "Successfully completed a copr build", "tags": "development,copr,", "issued":
-        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
-        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "shosca", "last_awarded": 1491441908.0, "percent_earned": 3.958676581912099,
-        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1778, "name":
-        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
-        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
-        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
-        "cydrobolt", "last_awarded": 1491503467.0, "percent_earned": 2.046132608986062,
-        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 919, "name":
-        "What goes around comes around (Karma I)"}, {"description": "Tested an update
-        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
-        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
-        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "caiqian",
-        "last_awarded": 1481903131.0, "percent_earned": 1.6765373825533243, "id":
-        "it-still-works!", "times_awarded": 753, "name": "It still works!"}, {"description":
-        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
-        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
-        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
-        "cydrobolt", "last_awarded": 1491442200.0, "percent_earned": 2.1641359041724186,
-        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 972, "name":
-        "Take this and call me in the morning"}, {"description": "You posted 40 or
-        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
-        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
-        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
-        "stefw", "last_awarded": 1491468526.0, "percent_earned": 0.35623636282673554,
-        "id": "bob-loblaw-planet-v", "times_awarded": 160, "name": "Bob Loblaw (Planet
-        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
-        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
-        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "dfateyev", "last_awarded": 1490465620.0, "percent_earned": 0.06902079529768002,
-        "id": "like-a-rock-updates-stable-iv", "times_awarded": 31, "name": "Like
-        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
-        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
-        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
-        "ignatenkobrain", "last_awarded": 1485808919.0, "percent_earned": 0.14472102239836132,
-        "id": "lets-do-lunch!", "times_awarded": 65, "name": "Let''s do lunch!"},
-        {"description": "Sip the lemonade away (You deserve it for remembering your
-        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
-        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
-        "first_awarded_person": "shaiton", "last_awarded_person": "mythcat", "last_awarded":
-        1484694397.0, "percent_earned": 0.4208042035890813, "id": "vacation", "times_awarded":
-        189, "name": "Vacation"}, {"description": "You visited the Fedora booth at
-        Pycon, 2014", "tags": "python,event,pycon,", "issued": 1397168025.0, "image":
-        "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png", "first_awarded":
-        1397168025.0, "first_awarded_person": "ralph", "last_awarded_person": "abompard",
-        "last_awarded": 1397573900.0, "percent_earned": 0.02226477267667097, "id":
-        "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
-        {"description": "You submitted feedback for an update in Bodhi after it was
-        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
-        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
-        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "thozza", "last_awarded": 1439904242.0, "percent_earned": 0.6345460212851227,
-        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
-        {"description": "You built a package owned by someone else.  It takes a village...",
-        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
-        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
-        "nickboldt", "last_awarded": 1490915668.0, "percent_earned": 0.984102952308857,
-        "id": "helping-hand", "times_awarded": 442, "name": "Helping Hand"}, {"description":
-        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
-        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
-        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.20483590862537293,
-        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
-        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
-        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
-        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
-        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "wtaymans",
-        "last_awarded": 1490906731.0, "percent_earned": 0.20038295409003873, "id":
-        "what-goes-up...-koji-failure-iv", "times_awarded": 90, "name": "What goes
-        up... (Koji Failure IV)"}, {"description": "You updated your password with
-        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
-        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
-        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
-        "payasr", "last_awarded": 1491512765.0, "percent_earned": 61.86712383666563,
-        "id": "paranoid-panda", "times_awarded": 27787, "name": "Paranoid Panda"},
-        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
-        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
-        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
-        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
-        "last_awarded": 1408553413.0, "percent_earned": 0.16253284053969808, "id":
-        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
-        {"description": "You have received 10 or more good karma on your bodhi updates",
-        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
-        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "jvymazal", "last_awarded": 1491284602.0, "percent_earned": 1.099879770227546,
-        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 494, "name":
-        "What goes around comes around (Karma II)"}, {"description": "Edited at least
-        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
-        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
-        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "athoscr",
-        "last_awarded": 1490991464.0, "percent_earned": 0.5900164759317807, "id":
-        "master-editor", "times_awarded": 265, "name": "Master Editor"}, {"description":
-        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
-        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
-        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "terjeros", "last_awarded": 1491384354.0, "percent_earned": 0.389633521841742,
-        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 175, "name":
-        "What goes around comes around (Karma III)"}, {"description": "  You attended
-        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
-        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
-        "first_awarded": 1405296000.0, "first_awarded_person": "marinaz", "last_awarded_person":
-        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.27163022665538583,
-        "id": "flock-2014-attendee", "times_awarded": 122, "name": "Flock 2014 Attendee"},
-        {"description": "You completed a run of the kernel regression test suite",
-        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
-        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "pperron", "last_awarded": 1490999828.0, "percent_earned": 0.49873090795742975,
-        "id": "science-kernel-tester-i", "times_awarded": 224, "name": "Science (Kernel
-        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
-        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
-        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
-        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
-        "last_awarded": 1408665317.0, "percent_earned": 0.19815647682237164, "id":
-        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
-        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
-        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
-        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
-        "pghmcfc", "last_awarded": 1485788654.0, "percent_earned": 0.03339715901500646,
-        "id": "corporate-overlord", "times_awarded": 15, "name": "Corporate Overlord"},
-        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
-        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
-        "kdudka", "last_awarded": 1491214689.0, "percent_earned": 0.18925056775170326,
-        "id": "corporate-shill", "times_awarded": 85, "name": "Corporate Shill"},
-        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
-        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
-        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
-        "dsommers", "last_awarded": 1490298016.0, "percent_earned": 1.3024892015852518,
-        "id": "corporate-drone", "times_awarded": 585, "name": "Corporate Drone"},
-        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
-        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
-        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "vondruch", "last_awarded": 1491296529.0, "percent_earned": 0.14026806786302712,
-        "id": "master-badger-badger-iii", "times_awarded": 63, "name": "Master Badger
-        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
-        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
-        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
-        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
-        "first_awarded_person": "kevin", "last_awarded_person": "fale", "last_awarded":
-        1490321832.0, "percent_earned": 0.2248742040343768, "id": "the-bull-transcended-tester-vii",
-        "times_awarded": 101, "name": "The Bull Transcended (Tester VII)"}, {"description":
-        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
-        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
-        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
-        "rbergero", "last_awarded": 1455959914.0, "percent_earned": 0.0712472725653471,
-        "id": "dancing-with-toshio", "times_awarded": 32, "name": "Dancing with Toshio"},
-        {"description": "Voted in a supplemental wallpapers election for the Fedora
-        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
-        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
-        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
-        "last_awarded": 1409902273.0, "percent_earned": 0.2449124994433807, "id":
-        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
-        "We''re sorry, but you had one of your badges revoked.  Something must have
-        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
-        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
-        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "keitellf",
-        "last_awarded": 1465418173.0, "percent_earned": 0.8972703388698402, "id":
-        "consolation-prize", "times_awarded": 403, "name": "Consolation Prize"}, {"description":
-        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
-        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
-        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
-        "usuha", "last_awarded": 1491448085.0, "percent_earned": 6.430066349022577,
-        "id": "crypto-panda", "times_awarded": 2888, "name": "Crypto Panda"}, {"description":
-        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
-        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
-        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "shosca", "last_awarded": 1491505320.0, "percent_earned": 2.3711982900654585,
-        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 1065, "name":
-        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
-        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
-        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
-        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
-        "pghmcfc", "last_awarded": 1490811747.0, "percent_earned": 0.03562363628267355,
-        "id": "mic-check!-updates-testing-v", "times_awarded": 16, "name": "Mic Check!
-        (Updates-Testing V)"}, {"description": "You took ownership of a previously
-        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
-        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
-        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
-        "sailer", "last_awarded": 1490344262.0, "percent_earned": 0.7525493164714788,
-        "id": "the-cat-came-back...", "times_awarded": 338, "name": "The cat came
-        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
-        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
-        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
-        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "michalrud", "last_awarded": 1470317213.0, "percent_earned": 0.04675602262100904,
-        "id": "apprentice-badge-artist-i", "times_awarded": 21, "name": "Apprentice
-        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
-        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
-        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
-        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
-        "kkeithle", "last_awarded": 1491364811.0, "percent_earned": 0.20706238589304005,
-        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 93, "name":
-        "What goes around comes around (Karma IV)"}, {"description": "You participated
-        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
-        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
-        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
-        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.04007659081800775,
-        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
-        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
-        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
-        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
-        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.13804159059536003,
-        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
-        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
-        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
-        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
-        "orion", "last_awarded": 1490756246.0, "percent_earned": 0.024491249944338066,
-        "id": "tectonic!-updates-stable-v", "times_awarded": 11, "name": "Tectonic!
-        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
-        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
-        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
-        "pcreech17", "last_awarded": 1491432940.0, "percent_earned": 2.3756512446007925,
-        "id": "associate-badger-badger-1.5", "times_awarded": 1067, "name": "Associate
-        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
-        Contributor Conference", "tags": "conference,rochester,events,flock,flock
-        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
-        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
-        "kellin", "last_awarded": 1461547496.0, "percent_earned": 0.18479761321636906,
-        "id": "flock-2015-attendee", "times_awarded": 83, "name": "Flock 2015 Attendee"},
-        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
-        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
-        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
-        "gtierney", "last_awarded": 1491405719.0, "percent_earned": 1.852429086699025,
-        "id": "macaron-cookie-i", "times_awarded": 832, "name": "Macaron (Cookie I)"},
-        {"description": "Ten people think you''re great, because they''ve given you
-        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
-        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
-        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "mizdebsk",
-        "last_awarded": 1491500198.0, "percent_earned": 0.3606893173620697, "id":
-        "chocolate-chip-cookie-ii", "times_awarded": 162, "name": "Chocolate Chip
-        (Cookie II)"}, {"description": "Voted in the supplemental wallpapers election
-        for the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
-        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
-        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.18257113594870197,
-        "id": "nuancier-f22", "times_awarded": 82, "name": "Nuancier (F22)"}, {"description":
-        "You pinned your country in FAS!", "tags": "account,community,", "issued":
-        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
-        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
-        "schwankek", "last_awarded": 1491486520.0, "percent_earned": 17.635926437191078,
-        "id": "origin", "times_awarded": 7921, "name": "Origin"}, {"description":
-        "You added a new package to the distribution.", "tags": "development,", "issued":
-        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
-        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
-        "nmilosev", "last_awarded": 1491213323.0, "percent_earned": 0.919535111546511,
-        "id": "delivery", "times_awarded": 413, "name": "Delivery"}, {"description":
-        "You mapped an upstream project to a Fedora package on release-monitoring.org",
-        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
-        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "dustymabe", "last_awarded": 1475240820.0, "percent_earned": 0.5655252259874427,
-        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 254,
-        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
-        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
-        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
-        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "dmsimard", "last_awarded": 1491321510.0, "percent_earned": 0.14472102239836132,
-        "id": "black-and-white-cookie-iii", "times_awarded": 65, "name": "Black and
-        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
-        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
-        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
-        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
-        "smani", "last_awarded": 1485976444.0, "percent_earned": 0.08460613617134968,
-        "id": "hindenburg-koji-failure-v", "times_awarded": 38, "name": "Hindenburg
-        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
-        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
-        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
-        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "jflory7", "last_awarded": 1475509860.0, "percent_earned": 0.006679431803001291,
-        "id": "badge-muse-badges-released-iv", "times_awarded": 3, "name": "Badge
-        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
-        ideas were approved and released.  Superb!", "tags": "community,badges,",
-        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
-        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "pravins", "last_awarded": 1472553692.0, "percent_earned": 0.03562363628267355,
-        "id": "badge-muse-badges-released-ii", "times_awarded": 16, "name": "Badge
-        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
-        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
-        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
-        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
-        "frantisekz", "last_awarded": 1485462295.0, "percent_earned": 0.10019147704501936,
-        "id": "badge-muse-badges-released-i", "times_awarded": 45, "name": "Badge
-        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
-        ideas were approved and released.  Impressive!", "tags": "community,badges,",
-        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
-        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
-        "jflory7", "last_awarded": 1475509873.0, "percent_earned": 0.013358863606002582,
-        "id": "badge-muse-badges-released-iii", "times_awarded": 6, "name": "Badge
-        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
-        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
-        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
-        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.002226477267667097,
-        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
-        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
-        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
-        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
-        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "kellin", "last_awarded": 1461547520.0, "percent_earned": 0.16921227234269937,
-        "id": "nom-nom-nom", "times_awarded": 76, "name": "Nom Nom Nom"}, {"description":
-        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
-        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
-        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
-        "rluzynski", "last_awarded": 1491442095.0, "percent_earned": 1.5763459055083047,
-        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 708, "name":
-        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
-        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
-        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
-        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
-        "dustymabe", "last_awarded": 1491326903.0, "percent_earned": 0.12468272698935744,
-        "id": "rock-the-web!", "times_awarded": 56, "name": "Rock the Web!"}, {"description":
-        "You can speak Python and and you''ve ported at least one package to Python
-        3", "tags": "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
-        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
-        "crobinso", "last_awarded": 1491217608.0, "percent_earned": 0.33842454468539873,
-        "id": "parselmouth", "times_awarded": 152, "name": "Parselmouth I"}, {"description":
-        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
-        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
-        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "jonatoni",
-        "last_awarded": 1490211890.0, "percent_earned": 0.22710068130204392, "id":
-        "chief-editor", "times_awarded": 102, "name": "Chief Editor"}, {"description":
-        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
-        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
-        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
-        "apahim", "last_awarded": 1491360865.0, "percent_earned": 4.628846239479895,
-        "id": "froglet", "times_awarded": 2079, "name": "Froglet"}, {"description":
-        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
-        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
-        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "ryanlerch", "last_awarded": 1490719235.0, "percent_earned": 0.03117068174733936,
-        "id": "pizzelle-cookie-iv", "times_awarded": 14, "name": "Pizzelle (Cookie
-        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
-        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "churchyard", "last_awarded": 1475564266.0, "percent_earned": 0.011132386338335486,
-        "id": "silver", "times_awarded": 5, "name": "Silver"}, {"description": "You
-        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
-        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "fale", "last_awarded": 1489622707.0, "percent_earned": 0.03117068174733936,
-        "id": "top-10", "times_awarded": 14, "name": "Top 10"}, {"description": "You
-        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
-        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "tflink", "last_awarded": 1480461776.0, "percent_earned": 0.25159193124638196,
-        "id": "top-100", "times_awarded": 113, "name": "Top 100"}, {"description":
-        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
-        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
-        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "mrunge", "last_awarded": 1490730635.0, "percent_earned": 0.06679431803001291,
-        "id": "top-25", "times_awarded": 30, "name": "Top 25"}, {"description": "You
-        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
-        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
-        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "zsun", "last_awarded": 1490677027.0, "percent_earned": 1.2000712472725654,
-        "id": "top-500", "times_awarded": 539, "name": "Top 500"}, {"description":
-        "You visited the Fedora table at BrickHack 2016!", "tags": "brickhack,event,hackathon,events,",
-        "issued": 1457234130.0, "image": "http://infrastructure.fedoraproject.org/infra/badges/pngs/events-brickhack-2016.png",
-        "first_awarded": 1455845197.0, "first_awarded_person": "jflory7", "last_awarded_person":
-        "brandondgr8", "last_awarded": 1461299769.0, "percent_earned": 0.05566193169167742,
-        "id": "brickhack-2016-attendee", "times_awarded": 25, "name": "BrickHack 2016
-        Attendee"}, {"description": "You gave a presentation at DevConf.cz, 2016",
-        "tags": "devconf,speaker,event,", "issued": 1455008224.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2016.png",
-        "first_awarded": 1454667336.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
-        "thozza", "last_awarded": 1459500320.0, "percent_earned": 0.2137418176960413,
-        "id": "devconf-2016-speaker", "times_awarded": 96, "name": "DevConf 2016 Speaker"},
-        {"description": "You attended the 2016 iteration of DevConf.cz, a yearly Linux
-        and JBoss conference in the Czech Republic", "tags": "event, devconf,", "issued":
-        1455120228.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee-2016.png",
-        "first_awarded": 1454600601.0, "first_awarded_person": "eischmann", "last_awarded_person":
-        "dkaspar", "last_awarded": 1461940547.0, "percent_earned": 0.18925056775170326,
-        "id": "devconf-2016-attendee", "times_awarded": 85, "name": "DevConf 2016
-        Attendee"}, {"description": "You got a \"Change\" accepted into the Fedora
-        24 Change list", "tags": "development,FESCo,process,", "issued": 1458652673.0,
-        "image": "https://badges.fedoraproject.org/pngs/changes-f24.png", "first_awarded":
-        1458651465.0, "first_awarded_person": "eischmann", "last_awarded_person":
-        "pnemade", "last_awarded": 1459240914.0, "percent_earned": 0.10019147704501936,
-        "id": "fedora-24-change-accepted", "times_awarded": 45, "name": "Fedora 24
-        Change Accepted"}, {"description": "You held third place on the Fedora Badges
-        leaderboard", "tags": "meta,community,", "issued": 1462904993.0, "image":
-        "https://badges.fedoraproject.org/pngs/3_badge_340.png", "first_awarded":
-        1452875229.0, "first_awarded_person": "pnemade", "last_awarded_person": "kevin",
-        "last_awarded": 1489692901.0, "percent_earned": 0.011132386338335486, "id":
-        "bronze", "times_awarded": 5, "name": "Bronze"}, {"description": "You burned
-        a yubikey and linked it with your Fedora Account", "tags": "account,community,",
-        "issued": 1462904755.0, "image": "https://badges.fedoraproject.org/pngs/yubi-badge.png",
-        "first_awarded": 1422906928.0, "first_awarded_person": "plautrba", "last_awarded_person":
-        "findarato", "last_awarded": 1491408410.0, "percent_earned": 0.4052188627154117,
-        "id": "horcrux", "times_awarded": 182, "name": "Horcrux"}, {"description":
-        "You hacked with the Fedora crew at PyCon US 2016", "tags": "event, python,pycon,",
-        "issued": 1464988862.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2016_attendee.png",
-        "first_awarded": 1464988862.0, "first_awarded_person": "ralph", "last_awarded_person":
-        "maxamillion", "last_awarded": 1464991242.0, "percent_earned": 0.028944204479672265,
-        "id": "pycon-2016-attendee", "times_awarded": 13, "name": "PyCon 2016 Attendee"},
-        {"description": "You got 150 Fedora Badges!  Wow!", "tags": "badges,community,",
-        "issued": 1468058613.0, "image": "https://badges.fedoraproject.org/pngs/badger-04.png",
-        "first_awarded": 1457979017.0, "first_awarded_person": "kevin", "last_awarded_person":
-        "pbrobinson", "last_awarded": 1490919191.0, "percent_earned": 0.020038295409003874,
-        "id": "badge-junkie-badger-iv", "times_awarded": 9, "name": "Badge Junkie
-        (Badger IV)"}, {"description": "You can speak Python and and you''ve ported
-        at least five packages to Python 3", "tags": "python,miscellaneous,", "issued":
-        1468058067.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-II.png",
-        "first_awarded": 1467988651.0, "first_awarded_person": "cstratak", "last_awarded_person":
-        "ishcherb", "last_awarded": 1488193805.0, "percent_earned": 0.028944204479672265,
-        "id": "parselmouth-ii", "times_awarded": 13, "name": "Parselmouth II"}, {"description":
-        "You can speak Python and and you''ve ported at least ten packages to Python
-        3", "tags": "python,miscellaneous,", "issued": 1468058072.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-III.png",
-        "first_awarded": 1467997850.0, "first_awarded_person": "cstratak", "last_awarded_person":
-        "ishcherb", "last_awarded": 1489753361.0, "percent_earned": 0.02226477267667097,
-        "id": "parselmouth-iii", "times_awarded": 10, "name": "Parselmouth III"},
-        {"description": "You attended Flock 2016, the Fedora Contributor Conference",
-        "tags": "flock,event,events,", "issued": 1470404480.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-attendee.png",
-        "first_awarded": 1468984748.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
-        "adrian", "last_awarded": 1486483875.0, "percent_earned": 0.2360065903727123,
-        "id": "flock-2016-attendee", "times_awarded": 106, "name": "Flock 2016 Attendee"},
-        {"description": "You attended the party at Flock 2016 in Krakow!", "tags":
-        "flock,krakow,event,events,", "issued": 1470404592.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/krakow-brews.png",
-        "first_awarded": 1468963417.0, "first_awarded_person": "duffy", "last_awarded_person":
-        "kittykat", "last_awarded": 1486217490.0, "percent_earned": 0.18257113594870197,
-        "id": "krakow-brews!", "times_awarded": 82, "name": "Krakow Brews!"}, {"description":
-        "You gave a presentation at Flock 2016, the Fedora Contributor Conference",
-        "tags": "flock,speaker,event,", "issued": 1471354751.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-speaker.png",
-        "first_awarded": 1470941077.0, "first_awarded_person": "mattdm", "last_awarded_person":
-        "kittykat", "last_awarded": 1486217546.0, "percent_earned": 0.19592999955470453,
-        "id": "flock-2016-speaker", "times_awarded": 88, "name": "Flock 2016 Speaker"},
-        {"description": "You''re a member of the Modularity Working Group!", "tags":
-        "modularity,community,", "issued": 1475082397.0, "image": "https://badges.fedoraproject.org/pngs/fas-modularity-wg.png",
-        "first_awarded": 1475082098.0, "first_awarded_person": "asamalik", "last_awarded_person":
-        "jscotka", "last_awarded": 1491213584.0, "percent_earned": 0.0801531816360155,
-        "id": "modularity-wg-member", "times_awarded": 36, "name": "Modularity WG
-        Member"}, {"description": "You got a \"Change\" accepted into the Fedora 26
-        Change list", "tags": "development, FESCo, process,", "issued": 1479749896.0,
-        "image": "https://badges.fedoraproject.org/pngs/changes-f26.png", "first_awarded":
-        1473331018.0, "first_awarded_person": "cstratak", "last_awarded_person": "ncoghlan",
-        "last_awarded": 1489656918.0, "percent_earned": 0.11577681791868906, "id":
-        "fedora-26-change-accepted", "times_awarded": 52, "name": "Fedora 26 Change
-        Accepted"}, {"description": "You gave a presentation at DevConf.cz, 2017",
-        "tags": "speaker,devconf,event,", "issued": 1486037155.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2017.png",
-        "first_awarded": 1486033923.0, "first_awarded_person": "jflory7", "last_awarded_person":
-        "siddharths", "last_awarded": 1486077040.0, "percent_earned": 0.24713897671104776,
-        "id": "devconf-2017-speaker", "times_awarded": 111, "name": "DevConf 2017
-        Speaker"}, {"description": "You have helped so many Fedorans you''ve got over
-        100 cookies. Don''t eat them all at once!", "tags": "cookie,community,", "issued":
-        1486153659.0, "image": "https://badges.fedoraproject.org/pngs/rainbowcookie.png",
-        "first_awarded": 1468278719.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
-        "ralph", "last_awarded": 1486153659.0, "percent_earned": 0.011132386338335486,
-        "id": "rainbow-cookie-v", "times_awarded": 5, "name": "Rainbow (Cookie V)"}],
-        "percent_earned": 41.81818181818181, "user": "ralph"}'}
-    headers:
-      appserver: [proxy06.fedoraproject.org]
-      apptime: [D=44302106]
-      connection: [Keep-Alive]
-      content-length: ['74203']
-      content-type: [application/json; charset=UTF-8]
-      date: ['Thu, 06 Apr 2017 22:33:37 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_old b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_old
deleted file mode 100644
index 2c37a30..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_old
+++ /dev/null
@@ -1,247 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
-  response:
-    body:
-      string: !!binary |
-        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
-        ubkEsJUZnCGJf/9/FQ8wekRjAQA=
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=8742172]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-type: [application/json]
-      date: ['Thu, 21 Jan 2016 20:30:43 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_simple
deleted file mode 100644
index 8f957b0..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_data_simple
+++ /dev/null
@@ -1,247 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
-  response:
-    body:
-      string: !!binary |
-        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
-        ubkEsJUZnCGJf/9/FQ8wekRjAQA=
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=1554107]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-type: [application/json]
-      date: ['Thu, 21 Jan 2016 20:32:22 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_view_authz b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_view_authz
deleted file mode 100644
index 0681d72..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_fedmsgstats.TestFedmsgStats.test_view_authz
+++ /dev/null
@@ -1,1051 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy11.fedoraproject.org]
-      apptime: [D=260670723]
-      connection: [close]
-      content-encoding: [gzip]
-      content-type: [application/json]
-      date: ['Thu, 06 Apr 2017 22:43:06 GMT']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=5811152]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-type: [application/json]
-      date: ['Thu, 06 Apr 2017 22:47:28 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=2388762]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-type: [application/json]
-      date: ['Thu, 06 Apr 2017 22:47:34 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpFunctionsTestCase.test_execute b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpFunctionsTestCase.test_execute
deleted file mode 100644
index 1e03fdc..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpFunctionsTestCase.test_execute
+++ /dev/null
@@ -1,98 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=630853]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4029']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 18:26:01 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data
deleted file mode 100644
index 4d48985..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data
+++ /dev/null
@@ -1,194 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy06.fedoraproject.org]
-      apptime: [D=634315]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4028']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 18:58:53 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=583692]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4027']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 19:24:03 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub
deleted file mode 100644
index 6b0a36a..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub
+++ /dev/null
@@ -1,98 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy02.fedoraproject.org]
-      apptime: [D=886956]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4029']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 19:28:42 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_all b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_all
deleted file mode 100644
index dfd7580..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_all
+++ /dev/null
@@ -1,194 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy11.fedoraproject.org]
-      apptime: [D=574648]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4029']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 19:53:38 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy06.fedoraproject.org]
-      apptime: [D=684600]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4028']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 21:58:21 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_date b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_date
deleted file mode 100644
index 49d31ac..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_date
+++ /dev/null
@@ -1,98 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy06.fedoraproject.org]
-      apptime: [D=560197]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4029']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 19:51:05 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_hub b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_hub
deleted file mode 100644
index c2ca0a7..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_hub
+++ /dev/null
@@ -1,98 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy06.fedoraproject.org]
-      apptime: [D=461727]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4029']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 19:51:07 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_meetingname b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_meetingname
deleted file mode 100644
index 07ed82f..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_meetingname
+++ /dev/null
@@ -1,98 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=621781]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4029']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 19:36:08 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_people b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_people
deleted file mode 100644
index d3b8371..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_people
+++ /dev/null
@@ -1,98 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy06.fedoraproject.org]
-      apptime: [D=474498]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4029']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 19:28:44 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_requesters b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_requesters
deleted file mode 100644
index cd075ec..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_halp.HalpViewsTestCase.test_search_requesters
+++ /dev/null
@@ -1,194 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=642014]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4029']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 22:29:51 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      appserver: [proxy06.fedoraproject.org]
-      apptime: [D=442751]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['4028']
-      content-type: [application/json]
-      date: ['Wed, 22 Mar 2017 22:34:13 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_data_simple
deleted file mode 100644
index c896aa4..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_data_simple
+++ /dev/null
@@ -1,43 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
-    method: GET
-    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=i18n
-  response:
-    body:
-      string: !!binary |
-        H4sIAAAAAAAAA+2ZTW/bIBiA/8ornzYp2IZ8NqdpO+3QnTYp1TpFzH6TstoQYdJqi/LfB20aEdYd
-        Jk1wQcIH8/XwvjySkTkUPaIRcjsUS/h6eHlbG9HjejBcG1tf1LNlXdtSjODcQ7S2hV5Nar9ObpTu
-        uRFKumHvBXlEvO9+wqkD2GYQdCFBY8cNttCKodkPgx0wlLf6VrrnWmkEbyrgD1x0/HuHwM0S7ozZ
-        Dcuq2mCrNN9p9QMbUyq9rR7Fvag+0sWn6voUVMVqOiGrFbm5AYA3qxUQ6JU0dyOwNQRau4jyrQur
-        4R3Kluu15D26xbtl+vGeMqJ2TwmZ/5kQN9fazuHaLXZKKCNs7PfoVHPOzfPqyanpndBNudGIUrVY
-        SjT+sJ5LvkXtNqjYaf4g5FB8C8B/h/rxvOxDGNcvJZ/6fPn8oTiOIGvw/zSYkZqSehZXg1egWYP0
-        GrA6gQaX0KxBag0YqSN/FF6BZg3Sa0DnCTS4hGYNUmswtpsSXYMQmjVIrwGNf0QMoVmD9BqM4x8R
-        Q2jWILUGE0LjHxFDaNYgvQYs/hExhGYNUmswJZRG1yCEZg3Sa8CmCTS4hGYNUmtgyyK6BiE0a5Be
-        Axb/v0EIzRqk1mCe4mophP6zBm5qrrf7HqVx986H4uzB+Q6T+SnzsxXET69cpRe33Hfd8fgbBWYL
-        WtgeAAA=
-    headers:
-      accept-ranges: [bytes]
-      age: ['0']
-      appserver: [proxy12.fedoraproject.org]
-      apptime: [D=179808]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['518']
-      content-type: [application/json]
-      date: ['Thu, 21 Jan 2016 20:50:48 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.CYLWKA._XkgyD4SujeEkonmfv7CP91G1mM;
-          Expires=Thu, 21-Jan-2016 21:50:48 GMT; Secure; HttpOnly; Path=/calendar']
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-      via: [1.1 varnish-v4]
-      x-varnish: ['22710494']
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_render_simple b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_render_simple
deleted file mode 100644
index 32812c9..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_render_simple
+++ /dev/null
@@ -1,43 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.12.5]
-    method: GET
-    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=i18n
-  response:
-    body:
-      string: !!binary |
-        H4sIAAAAAAAAA+3Zz2/bIBQH8H/lyadNCrZx82s5Teuph/bUSanWKWL2S8pqQ4RJqy3K/z7I0ogw
-        7TBp8rsgxYcA5svDH3Gw91mHaKXa9NkCvuzf/q2s7HDVW2Gsa8/K6aIs3S8bwXmEbFzPhE+qsE2t
-        temElVr52z5J9or43P6A0wBw3SD5XIHBVlhsoJF9vet7d0OfP5pH5a9bbRCCqUC8CNmKby2CsAt4
-        snbbL4pijY02Ymv0d6xtrs2meJXPsrjh87vi9lRUUZV8zJZL9vAAAO+WS2DQaWWfRuBaGDRuEfl7
-        X1YtWlSNMCslOvSL98sM6z3tiN4eN2T254b4uVZuDt/vYmes5KwchyNaXZ/35vfq2anrozR1vjaI
-        SjeYK7ThbZ1QYoPGP6Bsa8SLVH32NQr+e2hYz9tziOv6qdVxzOf76+wwgsTgPzPgcwIGl6GJATWD
-        yj2UwRnEoYkBPQM+IWBwGZoYUDO4ojgN4tDEgJ4BwWkQhyYG9AyqDwQMLkMTA2oGY8arwRnEoYkB
-        PYNqSsDgMjQxoGYwYbwcnEEcmhjQM6iGf4sYhyYG1AymrJwNziAOTQzoGVTDvzeIQxMDagb+iB6c
-        QRyaGNAz4MO/N4hD/5mBn1qYza5DZf135312dnD+hlmFWxbuVlT/1fFgCupWu7Y9HH4Bm4DFHNge
-        AAA=
-    headers:
-      Accept-Ranges: [bytes]
-      Age: ['0']
-      AppServer: [proxy04.fedoraproject.org]
-      AppTime: [D=176951]
-      Connection: [Keep-Alive]
-      Content-Encoding: [gzip]
-      Content-Length: ['515']
-      Content-Type: [application/json]
-      Date: ['Wed, 01 Feb 2017 08:36:43 GMT']
-      Keep-Alive: ['timeout=15, max=500']
-      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      Set-Cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C3Mvmw.rzQ95C3LVBlZJKMEJVpzih4SIT4;
-          Expires=Wed, 01-Feb-2017 09:36:43 GMT; Secure; HttpOnly; Path=/calendar']
-      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
-      Vary: [Accept-Encoding]
-      Via: [1.1 varnish-v4]
-      X-Varnish: ['1754049']
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_view_authz b/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_view_authz
deleted file mode 100644
index ec0fd82..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widgets.test_meetings.TestMeetings.test_view_authz
+++ /dev/null
@@ -1,304 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=Fedora%20release
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      accept-ranges: [bytes]
-      age: ['0']
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=466769]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-type: [application/json]
-      date: ['Thu, 06 Apr 2017 22:47:43 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C8hXEA.J-L3Q3D5WaWNhP3xXPbEcZs4hBU;
-          Expires=Thu, 06-Apr-2017 23:47:44 GMT; Secure; HttpOnly; Path=/calendar']
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-      via: [1.1 varnish-v4]
-      x-varnish: ['14164337']
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=Fedora%20release
-  response:
-    body:
-      string: !!binary |
-        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
-    headers:
-      accept-ranges: [bytes]
-      age: ['0']
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=422626]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-length: ['3975']
-      content-type: [application/json]
-      date: ['Thu, 06 Apr 2017 22:47:44 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C8hXEQ.l-i-NQ-NFV7tfhfpF_Pjr_6LWaM;
-          Expires=Thu, 06-Apr-2017 23:47:45 GMT; Secure; HttpOnly; Path=/calendar']
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-      via: [1.1 varnish-v4]
-      x-varnish: ['14488870']
-    status: {code: 200, message: OK}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=Fedora%20release
-  response:
-    body:
-      string: !!binary |
-        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
-        AMTKs+Vs2AAA
-    headers:
-      accept-ranges: [bytes]
-      age: ['0']
-      appserver: [proxy04.fedoraproject.org]
-      apptime: [D=525518]
-      connection: [Keep-Alive]
-      content-encoding: [gzip]
-      content-type: [application/json]
-      date: ['Thu, 06 Apr 2017 22:47:45 GMT']
-      keep-alive: ['timeout=15, max=500']
-      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C8hXEg.iAM2PfVJ078Ph-buEOa2ztll9hk;
-          Expires=Thu, 06-Apr-2017 23:47:46 GMT; Secure; HttpOnly; Path=/calendar']
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-      vary: [Accept-Encoding]
-      via: [1.1 varnish-v4]
-      x-varnish: ['14164340']
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_data_simple
new file mode 100644
index 0000000..94b3210
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_data_simple
@@ -0,0 +1,808 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"percent_earned": 47.05882352941176, "assertions":
+        [{"description": "You attended Flock 2013, the Fedora Contributor Conference",
+        "tags": "flock,event,", "issued": 1375373082.0, "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "gnokii", "last_awarded": 1386188828.0, "percent_earned": 0.404551201011378,
+        "id": "flock-2013-attendee", "times_awarded": 80, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bitlord", "last_awarded": 1452636478.0, "percent_earned": 1.1276864728192162,
+        "id": "tagger-tagger-ii", "times_awarded": 223, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bitlord", "last_awarded": 1452632614.0, "percent_earned": 1.7496839443742098,
+        "id": "junior-tagger-tagger-i", "times_awarded": 346, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "kldymcx", "last_awarded": 1453391986.0, "percent_earned": 58.063211125158034,
+        "id": "involvement", "times_awarded": 11482, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "leifmadsen",
+        "last_awarded": 1453305829.0, "percent_earned": 7.509481668773704, "id": "speak-up!",
+        "times_awarded": 1485, "name": "Speak Up!"}, {"description": "Edited at least
+        10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0, "image":
+        "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "cnangel",
+        "last_awarded": 1453350349.0, "percent_earned": 4.783817951959545, "id": "junior-editor",
+        "times_awarded": 946, "name": "Junior Editor"}, {"description": "Edited at
+        least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0, "image":
+        "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "raven",
+        "last_awarded": 1452869625.0, "percent_earned": 3.27180783817952, "id": "associate-editor",
+        "times_awarded": 647, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "farhaan",
+        "last_awarded": 1453312868.0, "percent_earned": 2.735777496839444, "id": "secretary-general",
+        "times_awarded": 541, "name": "Secretary General"}, {"description": "Voted
+        on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "mastaiza", "last_awarded": 1451951597.0, "percent_earned": 0.5309734513274336,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 105, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "fale", "last_awarded": 1453273101.0, "percent_earned": 0.9506953223767384,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 188, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "cstratak",
+        "last_awarded": 1453310380.0, "percent_earned": 5.734513274336283, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1134, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "eischmann", "last_awarded": 1453239619.0, "percent_earned": 4.621997471554994,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 914, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "gnat",
+        "last_awarded": 1452623672.0, "percent_earned": 2.634639696586599, "id": "if-you-build-it...-koji-success-iii",
+        "times_awarded": 521, "name": "If you build it... (Koji Success III)"}, {"description":
+        "Ten or more questions and answers on the Ask Fedora system.", "tags": "ask
+        fedora,community,", "issued": 1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedelibre", "last_awarded": 1453367297.0, "percent_earned": 2.5082174462705433,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 496, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "panos", "last_awarded": 1453375409.0, "percent_earned": 16.293299620733247,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 3222, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "quinnrm", "last_awarded": 1453389677.0, "percent_earned": 3.1554993678887486,
+        "id": "riddle-me-this", "times_awarded": 624, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "cockpit", "last_awarded": 1453321371.0, "percent_earned": 3.919089759797725,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 775, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "eischmann", "last_awarded": 1453239295.0, "percent_earned": 3.8280657395701643,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 757, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "suraia",
+        "last_awarded": 1452800930.0, "percent_earned": 5.350189633375474, "id": "you-can-call-me-patches-scm-i",
+        "times_awarded": 1058, "name": "You can call me \"Patches\" (SCM I)"}, {"description":
+        "Pushed 400 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png",
+        "first_awarded": 1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "lvrabec", "last_awarded": 1452698912.0, "percent_earned": 0.8748419721871049,
+        "id": "you-can-call-me-patches-scm-iv", "times_awarded": 173, "name": "You
+        can call me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to
+        a Fedora package repository.", "tags": "development,", "issued": 1376076329.0,
+        "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png",
+        "first_awarded": 1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person":
+        "pschiffe", "last_awarded": 1453290910.0, "percent_earned": 2.47787610619469,
+        "id": "you-can-call-me-patches-scm-iii", "times_awarded": 490, "name": "You
+        can call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more
+        koji builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "ankursinha", "last_awarded": 1452452682.0, "percent_earned": 1.1833122629582806,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 234, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "pkilambi", "last_awarded": 1453335472.0, "percent_earned": 2.5486725663716814,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 504, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "lvrabec", "last_awarded": 1452777318.0, "percent_earned": 0.9152970922882426,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 181, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "dhabben", "last_awarded": 1453392166.0, "percent_earned": 4.723135271807838,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 934, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "lovetide", "last_awarded": 1453389567.0, "percent_earned": 11.97471554993679,
+        "id": "junior-badger-badger-i", "times_awarded": 2368, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "jortel", "last_awarded": 1453223123.0, "percent_earned": 5.006321112515803,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 990, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "fmuellner", "last_awarded": 1453226784.0, "percent_earned": 2.831858407079646,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 560, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "heffer",
+        "last_awarded": 1453162247.0, "percent_earned": 0.6776232616940581, "id":
+        "like-a-rock-updates-stable-iii", "times_awarded": 134, "name": "Like a Rock
+        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
+        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "nshaikh", "last_awarded": 1453381228.0, "percent_earned": 11.625790139064476,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2299, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "gnat",
+        "last_awarded": 1453138519.0, "percent_earned": 2.260429835651075, "id": "like-a-rock-updates-stable-ii",
+        "times_awarded": 447, "name": "Like a Rock (Updates-Stable II)"}, {"description":
+        "Partied with Flock 2013 (at the South Carolina Aquarium)", "tags": "party,flock,event,",
+        "issued": 1376252202.0, "image": "https://badges.fedoraproject.org/pngs/tanked.png",
+        "first_awarded": 1376252202.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "gnokii", "last_awarded": 1411656869.0, "percent_earned": 0.3135271807838179,
+        "id": "tanked!", "times_awarded": 62, "name": "Tanked!"}, {"description":
+        "You proposed a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,",
+        "issued": 1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jsmith", "last_awarded": 1453126870.0, "percent_earned": 0.5967130214917826,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 118, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "drsn0w", "last_awarded": 1453260519.0, "percent_earned": 9.982300884955752,
+        "id": "bona-fide", "times_awarded": 1974, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.13147914032869784,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "jmlich", "last_awarded": 1453380139.0, "percent_earned": 1.2541087231352717,
+        "id": "senior-badger-badger-ii", "times_awarded": 248, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "cstratak",
+        "last_awarded": 1453371252.0, "percent_earned": 5.3198482932996205, "id":
+        "is-this-thing-on-updates-testing-i", "times_awarded": 1052, "name": "Is this
+        thing on? (Updates-Testing I)"}, {"description": "Pushed 20 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "rcritten", "last_awarded": 1452870021.0, "percent_earned": 2.786346396965866,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 551, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "bmbouter",
+        "last_awarded": 1453326365.0, "percent_earned": 3.1099873577749686, "id":
+        "partners-in-crime", "times_awarded": 615, "name": "Partners in Crime"}, {"description":
+        "*(a great struggle, repeated escapes, discipline required)*\nTested and added
+        karma to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "rbarlow", "last_awarded": 1452797003.0, "percent_earned": 1.592920353982301,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 315, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "jibecfed", "last_awarded":
+        1451517381.0, "percent_earned": 0.2427307206068268, "id": "master-tagger-tagger-iv",
+        "times_awarded": 48, "name": "Master Tagger (Tagger IV)"}, {"description":
+        "A member of the sysadmin-badges group.  Nothing to see here..  move along.",
+        "tags": "infrastructure,badges,community,", "issued": 1378319150.0, "image":
+        "https://badges.fedoraproject.org/pngs/fas-inside-job.png", "first_awarded":
+        1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "decause", "last_awarded": 1435781009.0, "percent_earned": 0.025284450063211124,
+        "id": "inside-job", "times_awarded": 5, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "jvasallo", "last_awarded": 1453390587.0, "percent_earned": 12.303413400758533,
+        "id": "white-rabbit", "times_awarded": 2433, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "redandrei", "last_awarded": 1453393896.0, "percent_earned": 4.632111251580278,
+        "id": "mugshot", "times_awarded": 916, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.08596713021491784,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "sayanchowdhury", "last_awarded": 1449249202.0, "percent_earned": 0.16687737041719342,
+        "id": "maestro", "times_awarded": 33, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "aniketkhisti", "last_awarded": 1453384257.0, "percent_earned": 7.691529709228824,
+        "id": "let-me-introduce-myself", "times_awarded": 1521, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "suraia", "last_awarded": 1452876478.0, "percent_earned": 1.3299620733249051,
+        "id": "binary-star", "times_awarded": 263, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "cweyl", "last_awarded": 1451604516.0, "percent_earned": 0.6826801517067004,
+        "id": "packager-sponsor", "times_awarded": 135, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "jmlich", "last_awarded": 1453380114.0, "percent_earned": 2.857142857142857,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 565, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "fale", "last_awarded": 1452955260.0, "percent_earned": 2.427307206068268,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 480, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "m4rtink", "last_awarded": 1451904147.0, "percent_earned": 3.372945638432364,
+        "id": "bloggin-it!-planet-i", "times_awarded": 667, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jcajka", "last_awarded": 1452784301.0, "percent_earned": 1.729456384323641,
+        "id": "white-hat", "times_awarded": 342, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.3994943109987358,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "coralatlas", "last_awarded": 1453259601.0, "percent_earned": 27.95954487989886,
+        "id": "embryo", "times_awarded": 5529, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mastaiza", "last_awarded": 1453293512.0, "percent_earned": 0.8798988621997471,
+        "id": "taming-the-bull-tester-v", "times_awarded": 174, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "fale", "last_awarded": 1451379096.0, "percent_earned": 0.27307206068268014,
+        "id": "common-bugs-contributor", "times_awarded": 54, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "tomh", "last_awarded": 1453387927.0, "percent_earned": 8.56637168141593,
+        "id": "baby-badger", "times_awarded": 1694, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "piotrp", "last_awarded": 1449068505.0, "percent_earned": 0.1213653603034134,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 24, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pfrields", "last_awarded": 1453230770.0, "percent_earned": 1.0821744627054362,
+        "id": "old-yeller", "times_awarded": 214, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.35903919089759795,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "paulcarroty", "last_awarded": 1451415976.0, "percent_earned": 1.5423514538558787,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 305, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "tomh", "last_awarded": 1453043511.0, "percent_earned": 1.6940581542351456,
+        "id": "senior-editor", "times_awarded": 335, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "nilix007", "last_awarded": 1449026189.0, "percent_earned": 17.754740834386855,
+        "id": "tadpole", "times_awarded": 3511, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "rajalakshmi", "last_awarded": 1449029694.0, "percent_earned": 37.67888748419722,
+        "id": "egg", "times_awarded": 7451, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "jdulaney", "last_awarded": 1446505520.0, "percent_earned": 9.780025284450062,
+        "id": "tadpole-with-legs", "times_awarded": 1934, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "sayanchowdhury", "last_awarded": 1449715315.0, "percent_earned": 0.1011378002528445,
+        "id": "badge-off!", "times_awarded": 20, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vinumoses", "last_awarded": 1451694870.0, "percent_earned": 0.4753476611883692,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 94, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "aryasaatvik", "last_awarded": 1452796719.0, "percent_earned": 0.6624525916561315,
+        "id": "no-longer-a-ronin", "times_awarded": 131, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jibecfed", "last_awarded": 1451496270.0, "percent_earned": 0.2579013906447535,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 51, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bitlord", "last_awarded": 1452632607.0, "percent_earned": 1.4563843236409608,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 288, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "duffy", "last_awarded": 1451767725.0, "percent_earned": 0.5208596713021492,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 103, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mastaiza", "last_awarded": 1453367728.0, "percent_earned": 0.9254108723135273,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 183, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "event,speaker,", "issued": 1390422108.0, "image":
+        "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.23261694058154236, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "valtri", "last_awarded": 1452814661.0, "percent_earned": 0.38432364096080907,
+        "id": "patches-scm-v", "times_awarded": 76, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "cstratak", "last_awarded": 1453371384.0, "percent_earned": 1.4007585335018964,
+        "id": "override,-you-say", "times_awarded": 277, "name": "Override, you say?"},
+        {"description": "You attended devconf.cz, a yearly Linux and JBoss conference
+        in the Czech Republic", "tags": "event,devconf,", "issued": 1391763090.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png", "first_awarded":
+        1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.3135271807838179,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "nb", "last_awarded": 1439569573.0, "percent_earned":
+        0.0606826801517067, "id": "videographer", "times_awarded": 12, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "sagitter", "last_awarded": 1450261520.0, "percent_earned": 0.2376738305941846,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 47,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "tkral", "last_awarded": 1453372187.0, "percent_earned": 5.719342604298356,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1131, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "plfiorini", "last_awarded": 1453366379.0, "percent_earned": 3.706700379266751,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 733, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "catanzaro",
+        "last_awarded": 1453387064.0, "percent_earned": 3.3426042983565107, "id":
+        "it-still-works!", "times_awarded": 661, "name": "It still works!"}, {"description":
+        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
+        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cstratak", "last_awarded": 1453371258.0, "percent_earned": 4.1466498103666245,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 820, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "bochecha", "last_awarded": 1452463312.0, "percent_earned": 0.6624525916561315,
+        "id": "bob-loblaw-planet-v", "times_awarded": 131, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "piotrp", "last_awarded": 1452692980.0, "percent_earned": 0.11125158027812895,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 22, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "potty", "last_awarded": 1448485603.0, "percent_earned": 0.26801517067003794,
+        "id": "lets-do-lunch!", "times_awarded": 53, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "piotrp", "last_awarded":
+        1452501182.0, "percent_earned": 0.7433628318584071, "id": "vacation", "times_awarded":
+        147, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "event,python,", "issued": 1397168025.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png",
+        "first_awarded": 1397168025.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "abompard", "last_awarded": 1397573900.0, "percent_earned": 0.05056890012642225,
+        "id": "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 1.441213653603034,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "ilgrad", "last_awarded": 1452896392.0, "percent_earned": 2.0126422250316054,
+        "id": "helping-hand", "times_awarded": 398, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.46523388116308473,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "mcrha",
+        "last_awarded": 1453136709.0, "percent_earned": 0.34892541087231355, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 69, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "indexengines", "last_awarded": 1453392311.0, "percent_earned": 69.38558786346397,
+        "id": "paranoid-panda", "times_awarded": 13721, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.36915297092288246, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "swilkerson", "last_awarded": 1453199550.0, "percent_earned": 1.7951959544879899,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 355, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "siwinski",
+        "last_awarded": 1453319029.0, "percent_earned": 0.9810366624525916, "id":
+        "master-editor", "times_awarded": 194, "name": "Master Editor"}, {"description":
+        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mluscon", "last_awarded": 1450742624.0, "percent_earned": 0.5865992414664981,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 116, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405334492.0, "first_awarded_person": "sgallagh", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.6118836915297092,
+        "id": "flock-2014-attendee", "times_awarded": 121, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "devhen", "last_awarded": 1452673329.0, "percent_earned": 0.6573957016434893,
+        "id": "science-kernel-tester-i", "times_awarded": 130, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.450063211125158, "id": "party-pirate",
+        "times_awarded": 89, "name": "Party Pirate"}, {"description": "You submitted
+        200 Bodhi updates for an EPEL branch.", "tags": "development,epel,", "issued":
+        1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "limb", "last_awarded": 1452540830.0, "percent_earned": 0.05562579013906448,
+        "id": "corporate-overlord", "times_awarded": 11, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "greghellings", "last_awarded": 1453354804.0, "percent_earned": 0.34386852085967134,
+        "id": "corporate-shill", "times_awarded": 68, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "cstratak", "last_awarded": 1453390902.0, "percent_earned": 2.4829329962073325,
+        "id": "corporate-drone", "times_awarded": 491, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1452297195.0, "percent_earned": 0.17193426042983567,
+        "id": "master-badger-badger-iii", "times_awarded": 34, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "heikoada", "last_awarded":
+        1452772620.0, "percent_earned": 0.37926675094816686, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 75, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "chrisroberts", "last_awarded": 1439838603.0, "percent_earned": 0.15676359039190896,
+        "id": "dancing-with-toshio", "times_awarded": 31, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.5562579013906448, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "iaguis",
+        "last_awarded": 1452874718.0, "percent_earned": 2.0227560050568902, "id":
+        "consolation-prize", "times_awarded": 400, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "lovetide", "last_awarded": 1453389559.0, "percent_earned": 12.323640960809103,
+        "id": "crypto-panda", "times_awarded": 2437, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "paulotada", "last_awarded": 1453313558.0, "percent_earned": 3.2616940581542355,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 645, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "ppisar", "last_awarded": 1447066663.0, "percent_earned": 0.045512010113780026,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 9, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "ohaessler", "last_awarded": 1452768576.0, "percent_earned": 1.3046776232616941,
+        "id": "the-cat-came-back...", "times_awarded": 258, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "spot", "last_awarded": 1446145228.0, "percent_earned": 0.09102402022756005,
+        "id": "apprentice-badge-artist-i", "times_awarded": 18, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "sandeen", "last_awarded": 1439922999.0, "percent_earned": 0.2831858407079646,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 56, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.09102402022756005,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.3135271807838179,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "rdieter", "last_awarded": 1449536137.0, "percent_earned": 0.03034134007585335,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 6, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "icon", "last_awarded": 1453222652.0, "percent_earned": 4.101137800252844,
+        "id": "associate-badger-badger-1.5", "times_awarded": 811, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "jenneh", "last_awarded": 1441736246.0, "percent_earned": 0.3994943109987358,
+        "id": "flock-2015-attendee", "times_awarded": 79, "name": "FLOCK 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "mluscon", "last_awarded": 1453387739.0, "percent_earned": 2.2553729456384324,
+        "id": "macaron-cookie-i", "times_awarded": 446, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "walters",
+        "last_awarded": 1452199929.0, "percent_earned": 0.26801517067003794, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 53, "name": "Chocolate Chip (Cookie
+        II)"}, {"description": "Voted in the supplemental wallpapers election for
+        the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.4096080910240202,
+        "id": "nuancier-f22", "times_awarded": 81, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "jvasallo", "last_awarded": 1453390594.0, "percent_earned": 36.86472819216182,
+        "id": "origin", "times_awarded": 7290, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "tadej", "last_awarded": 1450046737.0, "percent_earned": 2.0480404551201015,
+        "id": "delivery", "times_awarded": 405, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "pabelanger", "last_awarded": 1453318849.0, "percent_earned": 0.9405815423514539,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 186,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "hguemar", "last_awarded": 1453303231.0, "percent_earned": 0.05056890012642225,
+        "id": "black-and-white-cookie-iii", "times_awarded": 10, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "piotrp", "last_awarded": 1451395906.0, "percent_earned": 0.12642225031605564,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 25, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433267989.0, "percent_earned": 0.0050568900126422255,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 1, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "eischmann", "last_awarded": 1452092327.0, "percent_earned": 0.035398230088495575,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 7, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "viveknrt", "last_awarded": 1452876035.0, "percent_earned": 0.11630847029077118,
+        "id": "badge-muse-badges-released-i", "times_awarded": 23, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "ralph", "last_awarded": 1433267996.0, "percent_earned": 0.010113780025284451,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 2, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.0050568900126422255,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "jenneh", "last_awarded": 1441736228.0, "percent_earned": 0.37420986093552466,
+        "id": "nom-nom-nom", "times_awarded": 74, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "alonid", "last_awarded": 1453299407.0, "percent_earned": 2.1238938053097343,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 420, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "onekopaka", "last_awarded": 1451613302.0, "percent_earned": 0.2528445006321113,
+        "id": "rock-the-web!", "times_awarded": 50, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and helped with porting stuff to Python 3", "tags":
+        "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "toshio", "last_awarded": 1447943130.0, "percent_earned": 0.21238938053097348,
+        "id": "parselmouth", "times_awarded": 42, "name": "Parselmouth"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "fale",
+        "last_awarded": 1453212624.0, "percent_earned": 0.38432364096080907, "id":
+        "chief-editor", "times_awarded": 76, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "pschultz", "last_awarded": 1449025570.0, "percent_earned": 5.926675094816688,
+        "id": "froglet", "times_awarded": 1172, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "puiterwijk", "last_awarded": 1450374896.0, "percent_earned": 0.015170670037926675,
+        "id": "pizzelle-cookie-iv", "times_awarded": 3, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1452873723.0, "percent_earned": 0.0050568900126422255,
+        "id": "silver", "times_awarded": 1, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "churchyard", "last_awarded": 1452875228.0, "percent_earned": 0.05056890012642225,
+        "id": "top-10", "times_awarded": 10, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "siwinski", "last_awarded": 1453319241.0, "percent_earned": 0.15676359039190896,
+        "id": "top-100", "times_awarded": 31, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1453212640.0, "percent_earned": 0.13147914032869784,
+        "id": "top-25", "times_awarded": 26, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mluscon", "last_awarded": 1453387764.0, "percent_earned": 0.3034134007585335,
+        "id": "top-500", "times_awarded": 60, "name": "Top 500"}], "user": "ralph",
+        "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png"}'}
+    headers:
+      appserver: [proxy11.fedoraproject.org]
+      apptime: [D=23056117]
+      connection: [Keep-Alive]
+      content-length: ['66178']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 21 Jan 2016 16:41:06 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_should_invalidate_good_match b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_should_invalidate_good_match
new file mode 100644
index 0000000..bfce42a
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_should_invalidate_good_match
@@ -0,0 +1,60 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy08.fedoraproject.org]
+      apptime: [D=55142]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1874']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:41:30 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_should_invalidate_wrong_topic b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_should_invalidate_wrong_topic
new file mode 100644
index 0000000..25e7a53
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_should_invalidate_wrong_topic
@@ -0,0 +1,59 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=98106]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1823']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:41:31 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_should_invalidate_wrong_user b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_should_invalidate_wrong_user
new file mode 100644
index 0000000..44ea8bf
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_about.TestBadges.test_should_invalidate_wrong_user
@@ -0,0 +1,62 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f
+  response:
+    body:
+      string: !!binary |
+        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
+        CwAA
+    headers:
+      appserver: [proxy10.phx2.fedoraproject.org]
+      apptime: [D=12673]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1941']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:41:31 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_data_simple
new file mode 100644
index 0000000..e4c8d8d
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_data_simple
@@ -0,0 +1,810 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"percent_earned": 47.05882352941176, "assertions":
+        [{"description": "You attended Flock 2013, the Fedora Contributor Conference",
+        "tags": "flock,event,", "issued": 1375373082.0, "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "gnokii", "last_awarded": 1386188828.0, "percent_earned": 0.4045921205684519,
+        "id": "flock-2013-attendee", "times_awarded": 80, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bitlord", "last_awarded": 1452636478.0, "percent_earned": 1.1278005360845598,
+        "id": "tagger-tagger-ii", "times_awarded": 223, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bitlord", "last_awarded": 1452632614.0, "percent_earned": 1.7498609214585545,
+        "id": "junior-tagger-tagger-i", "times_awarded": 346, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "fishers1967", "last_awarded": 1453390941.0, "percent_earned": 58.06402670307996,
+        "id": "involvement", "times_awarded": 11481, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "leifmadsen",
+        "last_awarded": 1453305829.0, "percent_earned": 7.510241238051889, "id": "speak-up!",
+        "times_awarded": 1485, "name": "Speak Up!"}, {"description": "Edited at least
+        10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0, "image":
+        "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "cnangel",
+        "last_awarded": 1453350349.0, "percent_earned": 4.784301825721944, "id": "junior-editor",
+        "times_awarded": 946, "name": "Junior Editor"}, {"description": "Edited at
+        least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0, "image":
+        "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "raven",
+        "last_awarded": 1452869625.0, "percent_earned": 3.272138775097355, "id": "associate-editor",
+        "times_awarded": 647, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "farhaan",
+        "last_awarded": 1453312868.0, "percent_earned": 2.7360542153441565, "id":
+        "secretary-general", "times_awarded": 541, "name": "Secretary General"}, {"description":
+        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
+        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "mastaiza", "last_awarded": 1451951597.0, "percent_earned": 0.5310271582460933,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 105, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "fale", "last_awarded": 1453273101.0, "percent_earned": 0.950791483335862,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 188, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "cstratak",
+        "last_awarded": 1453310380.0, "percent_earned": 5.735093309057806, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1134, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "eischmann", "last_awarded": 1453239619.0, "percent_earned": 4.622464977494563,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 914, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "gnat",
+        "last_awarded": 1452623672.0, "percent_earned": 2.6349061852020434, "id":
+        "if-you-build-it...-koji-success-iii", "times_awarded": 521, "name": "If you
+        build it... (Koji Success III)"}, {"description": "Ten or more questions and
+        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
+        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedelibre", "last_awarded": 1453367297.0, "percent_earned": 2.508471147524402,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 496, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "panos", "last_awarded": 1453375409.0, "percent_earned": 16.2949476558944,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 3222, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "quinnrm", "last_awarded": 1453389677.0, "percent_earned": 3.155818540433925,
+        "id": "riddle-me-this", "times_awarded": 624, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "cockpit", "last_awarded": 1453321371.0, "percent_earned": 3.919486168006878,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 775, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "eischmann", "last_awarded": 1453239295.0, "percent_earned": 3.8284529408789765,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 757, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "suraia",
+        "last_awarded": 1452800930.0, "percent_earned": 5.3507307945177764, "id":
+        "you-can-call-me-patches-scm-i", "times_awarded": 1058, "name": "You can call
+        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
+        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "lvrabec",
+        "last_awarded": 1452698912.0, "percent_earned": 0.8749304607292773, "id":
+        "you-can-call-me-patches-scm-iv", "times_awarded": 173, "name": "You can call
+        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
+        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "pschiffe",
+        "last_awarded": 1453290910.0, "percent_earned": 2.4781267384817682, "id":
+        "you-can-call-me-patches-scm-iii", "times_awarded": 490, "name": "You can
+        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "ankursinha", "last_awarded": 1452452682.0, "percent_earned": 1.183431952662722,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 234, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "pkilambi", "last_awarded": 1453335472.0, "percent_earned": 2.548930359581247,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 504, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "lvrabec", "last_awarded": 1452777318.0, "percent_earned": 0.9153896727861224,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 181, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "stevenmerrill", "last_awarded": 1453314068.0, "percent_earned": 4.718555606129571,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 933, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "lovetide", "last_awarded": 1453389567.0, "percent_earned": 11.975926768826177,
+        "id": "junior-badger-badger-i", "times_awarded": 2368, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "jortel", "last_awarded": 1453223123.0, "percent_earned": 5.006827492034593,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 990, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "fmuellner", "last_awarded": 1453226784.0, "percent_earned": 2.8321448439791634,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 560, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "heffer",
+        "last_awarded": 1453162247.0, "percent_earned": 0.677691801952157, "id": "like-a-rock-updates-stable-iii",
+        "times_awarded": 134, "name": "Like a Rock (Updates-Stable III)"}, {"description":
+        "*(aimless searching, only the sound of cicadas)*\nTested and added karma
+        to 1 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,", "issued":
+        1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "nshaikh", "last_awarded": 1453381228.0, "percent_earned": 11.626966064835887,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2299, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "gnat",
+        "last_awarded": 1453138519.0, "percent_earned": 2.260658473676225, "id": "like-a-rock-updates-stable-ii",
+        "times_awarded": 447, "name": "Like a Rock (Updates-Stable II)"}, {"description":
+        "Partied with Flock 2013 (at the South Carolina Aquarium)", "tags": "party,flock,event,",
+        "issued": 1376252202.0, "image": "https://badges.fedoraproject.org/pngs/tanked.png",
+        "first_awarded": 1376252202.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "gnokii", "last_awarded": 1411656869.0, "percent_earned": 0.31355889344055027,
+        "id": "tanked!", "times_awarded": 62, "name": "Tanked!"}, {"description":
+        "You proposed a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,",
+        "issued": 1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jsmith", "last_awarded": 1453126870.0, "percent_earned": 0.5967733778384666,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 118, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "drsn0w", "last_awarded": 1453260519.0, "percent_earned": 9.98331057502655,
+        "id": "bona-fide", "times_awarded": 1974, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.13149243918474687,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "jmlich", "last_awarded": 1453380139.0, "percent_earned": 1.254235573762201,
+        "id": "senior-badger-badger-ii", "times_awarded": 248, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "cstratak",
+        "last_awarded": 1453371252.0, "percent_earned": 5.3203863854751425, "id":
+        "is-this-thing-on-updates-testing-i", "times_awarded": 1052, "name": "Is this
+        thing on? (Updates-Testing I)"}, {"description": "Pushed 20 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "rcritten", "last_awarded": 1452870021.0, "percent_earned": 2.7866282304152126,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 551, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "bmbouter",
+        "last_awarded": 1453326365.0, "percent_earned": 3.1103019268699743, "id":
+        "partners-in-crime", "times_awarded": 615, "name": "Partners in Crime"}, {"description":
+        "*(a great struggle, repeated escapes, discipline required)*\nTested and added
+        karma to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "rbarlow", "last_awarded": 1452797003.0, "percent_earned": 1.5930814747382795,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 315, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "jibecfed", "last_awarded":
+        1451517381.0, "percent_earned": 0.24275527234107114, "id": "master-tagger-tagger-iv",
+        "times_awarded": 48, "name": "Master Tagger (Tagger IV)"}, {"description":
+        "A member of the sysadmin-badges group.  Nothing to see here..  move along.",
+        "tags": "infrastructure,badges,community,", "issued": 1378319150.0, "image":
+        "https://badges.fedoraproject.org/pngs/fas-inside-job.png", "first_awarded":
+        1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "decause", "last_awarded": 1435781009.0, "percent_earned": 0.025287007535528244,
+        "id": "inside-job", "times_awarded": 5, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "jvasallo", "last_awarded": 1453390587.0, "percent_earned": 12.304657866788045,
+        "id": "white-rabbit", "times_awarded": 2433, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "hahnsaja", "last_awarded": 1453391469.0, "percent_earned": 4.617407575987458,
+        "id": "mugshot", "times_awarded": 913, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.08597582562079603,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "sayanchowdhury", "last_awarded": 1449249202.0, "percent_earned": 0.1668942497344864,
+        "id": "maestro", "times_awarded": 33, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "aniketkhisti", "last_awarded": 1453384257.0, "percent_earned": 7.6923076923076925,
+        "id": "let-me-introduce-myself", "times_awarded": 1521, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "suraia", "last_awarded": 1452876478.0, "percent_earned": 1.3300965963687856,
+        "id": "binary-star", "times_awarded": 263, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "cweyl", "last_awarded": 1451604516.0, "percent_earned": 0.6827492034592627,
+        "id": "packager-sponsor", "times_awarded": 135, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "jmlich", "last_awarded": 1453380114.0, "percent_earned": 2.8574318515146917,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 565, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "fale", "last_awarded": 1452955260.0, "percent_earned": 2.4275527234107117,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 480, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "m4rtink", "last_awarded": 1451904147.0, "percent_earned": 3.373286805239468,
+        "id": "bloggin-it!-planet-i", "times_awarded": 667, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jcajka", "last_awarded": 1452784301.0, "percent_earned": 1.729631315430132,
+        "id": "white-hat", "times_awarded": 342, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.3995347190613463,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "coralatlas", "last_awarded": 1453259601.0, "percent_earned": 27.962372932787133,
+        "id": "embryo", "times_awarded": 5529, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mastaiza", "last_awarded": 1453293512.0, "percent_earned": 0.8799878622363829,
+        "id": "taming-the-bull-tester-v", "times_awarded": 174, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "fale", "last_awarded": 1451379096.0, "percent_earned": 0.27309968138370505,
+        "id": "common-bugs-contributor", "times_awarded": 54, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "tomh", "last_awarded": 1453387927.0, "percent_earned": 8.56723815303697,
+        "id": "baby-badger", "times_awarded": 1694, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "piotrp", "last_awarded": 1449068505.0, "percent_earned": 0.12137763617053557,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 24, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pfrields", "last_awarded": 1453230770.0, "percent_earned": 1.082283922520609,
+        "id": "old-yeller", "times_awarded": 214, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.3590755070045011,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "paulcarroty", "last_awarded": 1451415976.0, "percent_earned": 1.542507459667223,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 305, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "tomh", "last_awarded": 1453043511.0, "percent_earned": 1.6942295048803926,
+        "id": "senior-editor", "times_awarded": 335, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "nilix007", "last_awarded": 1449026189.0, "percent_earned": 17.756536691447934,
+        "id": "tadpole", "times_awarded": 3511, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "rajalakshmi", "last_awarded": 1449029694.0, "percent_earned": 37.68269862944419,
+        "id": "egg", "times_awarded": 7451, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "jdulaney", "last_awarded": 1446505520.0, "percent_earned": 9.781014514742326,
+        "id": "tadpole-with-legs", "times_awarded": 1934, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "sayanchowdhury", "last_awarded": 1449715315.0, "percent_earned": 0.10114803014211297,
+        "id": "badge-off!", "times_awarded": 20, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vinumoses", "last_awarded": 1451694870.0, "percent_earned": 0.475395741667931,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 94, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "aryasaatvik", "last_awarded": 1452796719.0, "percent_earned": 0.66251959743084,
+        "id": "no-longer-a-ronin", "times_awarded": 131, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jibecfed", "last_awarded": 1451496270.0, "percent_earned": 0.2579274768623881,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 51, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bitlord", "last_awarded": 1452632607.0, "percent_earned": 1.456531634046427,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 288, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "duffy", "last_awarded": 1451767725.0, "percent_earned": 0.5209123552318818,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 103, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mastaiza", "last_awarded": 1453367728.0, "percent_earned": 0.9255044758003338,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 183, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "event,speaker,", "issued": 1390422108.0, "image":
+        "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.23264046932685986, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "valtri", "last_awarded": 1452814661.0, "percent_earned": 0.38436251454002934,
+        "id": "patches-scm-v", "times_awarded": 76, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "cstratak", "last_awarded": 1453371384.0, "percent_earned": 1.4009002174682648,
+        "id": "override,-you-say", "times_awarded": 277, "name": "Override, you say?"},
+        {"description": "You attended devconf.cz, a yearly Linux and JBoss conference
+        in the Czech Republic", "tags": "event,devconf,", "issued": 1391763090.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png", "first_awarded":
+        1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.31355889344055027,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "nb", "last_awarded": 1439569573.0, "percent_earned":
+        0.060688818085267784, "id": "videographer", "times_awarded": 12, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "sagitter", "last_awarded": 1450261520.0, "percent_earned": 0.2376978708339655,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 47,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "tkral", "last_awarded": 1453372187.0, "percent_earned": 5.719921104536489,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1131, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "plfiorini", "last_awarded": 1453366379.0, "percent_earned": 3.7070753047084413,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 733, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "catanzaro",
+        "last_awarded": 1453387064.0, "percent_earned": 3.342942396196834, "id": "it-still-works!",
+        "times_awarded": 661, "name": "It still works!"}, {"description": "You submitted
+        an update to bodhi with one or more bugzilla bug numbers attached", "tags":
+        "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cstratak", "last_awarded": 1453371258.0, "percent_earned": 4.147069235826632,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 820, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "bochecha", "last_awarded": 1452463312.0, "percent_earned": 0.66251959743084,
+        "id": "bob-loblaw-planet-v", "times_awarded": 131, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "piotrp", "last_awarded": 1452692980.0, "percent_earned": 0.11126283315632428,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 22, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "potty", "last_awarded": 1448485603.0, "percent_earned": 0.2680422798765994,
+        "id": "lets-do-lunch!", "times_awarded": 53, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "piotrp", "last_awarded":
+        1452501182.0, "percent_earned": 0.7434380215445304, "id": "vacation", "times_awarded":
+        147, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "event,python,", "issued": 1397168025.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png",
+        "first_awarded": 1397168025.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "abompard", "last_awarded": 1397573900.0, "percent_earned": 0.05057401507105649,
+        "id": "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 1.44135942952511,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "ilgrad", "last_awarded": 1452896392.0, "percent_earned": 2.0128457998280487,
+        "id": "helping-hand", "times_awarded": 398, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.4652809386537197,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "mcrha",
+        "last_awarded": 1453136709.0, "percent_earned": 0.3489607039902898, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 69, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "fishers1967", "last_awarded": 1453390883.0, "percent_earned": 69.3824912759824,
+        "id": "paranoid-panda", "times_awarded": 13719, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.3691903100187124, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "swilkerson", "last_awarded": 1453199550.0, "percent_earned": 1.7953775350225056,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 355, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "siwinski",
+        "last_awarded": 1453319029.0, "percent_earned": 0.981135892378496, "id": "master-editor",
+        "times_awarded": 194, "name": "Master Editor"}, {"description": "You have
+        received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mluscon", "last_awarded": 1450742624.0, "percent_earned": 0.5866585748242553,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 116, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405334492.0, "first_awarded_person": "sgallagh", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.6119455823597835,
+        "id": "flock-2014-attendee", "times_awarded": 121, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "devhen", "last_awarded": 1452673329.0, "percent_earned": 0.6574621959237344,
+        "id": "science-kernel-tester-i", "times_awarded": 130, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.4501087341324028, "id":
+        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
+        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
+        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "limb", "last_awarded": 1452540830.0, "percent_earned": 0.05563141657816214,
+        "id": "corporate-overlord", "times_awarded": 11, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "greghellings", "last_awarded": 1453354804.0, "percent_earned": 0.3439033024831841,
+        "id": "corporate-shill", "times_awarded": 68, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "cstratak", "last_awarded": 1453390902.0, "percent_earned": 2.483184139988874,
+        "id": "corporate-drone", "times_awarded": 491, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1452297195.0, "percent_earned": 0.17195165124159206,
+        "id": "master-badger-badger-iii", "times_awarded": 34, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "heikoada", "last_awarded":
+        1452772620.0, "percent_earned": 0.3793051130329237, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 75, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "chrisroberts", "last_awarded": 1439838603.0, "percent_earned": 0.15677944672027513,
+        "id": "dancing-with-toshio", "times_awarded": 31, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.5563141657816214, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "iaguis",
+        "last_awarded": 1452874718.0, "percent_earned": 2.0229606028422595, "id":
+        "consolation-prize", "times_awarded": 400, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "lovetide", "last_awarded": 1453389559.0, "percent_earned": 12.324887472816467,
+        "id": "crypto-panda", "times_awarded": 2437, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "paulotada", "last_awarded": 1453313558.0, "percent_earned": 3.262023972083144,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 645, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "ppisar", "last_awarded": 1447066663.0, "percent_earned": 0.04551661356395084,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 9, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "ohaessler", "last_awarded": 1452768576.0, "percent_earned": 1.3048095888332576,
+        "id": "the-cat-came-back...", "times_awarded": 258, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "spot", "last_awarded": 1446145228.0, "percent_earned": 0.09103322712790168,
+        "id": "apprentice-badge-artist-i", "times_awarded": 18, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "sandeen", "last_awarded": 1439922999.0, "percent_earned": 0.28321448439791636,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 56, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.09103322712790168,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.31355889344055027,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "rdieter", "last_awarded": 1449536137.0, "percent_earned": 0.030344409042633892,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 6, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "icon", "last_awarded": 1453222652.0, "percent_earned": 4.101552622262681,
+        "id": "associate-badger-badger-1.5", "times_awarded": 811, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "jenneh", "last_awarded": 1441736246.0, "percent_earned": 0.3995347190613463,
+        "id": "flock-2015-attendee", "times_awarded": 79, "name": "FLOCK 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "mluscon", "last_awarded": 1453387739.0, "percent_earned": 2.2556010721691195,
+        "id": "macaron-cookie-i", "times_awarded": 446, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "walters",
+        "last_awarded": 1452199929.0, "percent_earned": 0.2680422798765994, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 53, "name": "Chocolate Chip (Cookie
+        II)"}, {"description": "Voted in the supplemental wallpapers election for
+        the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.40964952207555755,
+        "id": "nuancier-f22", "times_awarded": 81, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "jvasallo", "last_awarded": 1453390594.0, "percent_earned": 36.86845698680018,
+        "id": "origin", "times_awarded": 7290, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "tadej", "last_awarded": 1450046737.0, "percent_earned": 2.048247610377788,
+        "id": "delivery", "times_awarded": 405, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "pabelanger", "last_awarded": 1453318849.0, "percent_earned": 0.9406766803216507,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 186,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "hguemar", "last_awarded": 1453303231.0, "percent_earned": 0.05057401507105649,
+        "id": "black-and-white-cookie-iii", "times_awarded": 10, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "piotrp", "last_awarded": 1451395906.0, "percent_earned": 0.12643503767764122,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 25, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433267989.0, "percent_earned": 0.005057401507105649,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 1, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "eischmann", "last_awarded": 1452092327.0, "percent_earned": 0.035401810549739544,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 7, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "viveknrt", "last_awarded": 1452876035.0, "percent_earned": 0.11632023466342993,
+        "id": "badge-muse-badges-released-i", "times_awarded": 23, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "ralph", "last_awarded": 1433267996.0, "percent_earned": 0.010114803014211297,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 2, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.005057401507105649,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "jenneh", "last_awarded": 1441736228.0, "percent_earned": 0.37424771152581804,
+        "id": "nom-nom-nom", "times_awarded": 74, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "alonid", "last_awarded": 1453299407.0, "percent_earned": 2.124108632984373,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 420, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "onekopaka", "last_awarded": 1451613302.0, "percent_earned": 0.25287007535528244,
+        "id": "rock-the-web!", "times_awarded": 50, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and helped with porting stuff to Python 3", "tags":
+        "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "toshio", "last_awarded": 1447943130.0, "percent_earned": 0.21241086329843728,
+        "id": "parselmouth", "times_awarded": 42, "name": "Parselmouth"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "fale",
+        "last_awarded": 1453212624.0, "percent_earned": 0.38436251454002934, "id":
+        "chief-editor", "times_awarded": 76, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "pschultz", "last_awarded": 1449025570.0, "percent_earned": 5.927274566327821,
+        "id": "froglet", "times_awarded": 1172, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "puiterwijk", "last_awarded": 1450374896.0, "percent_earned": 0.015172204521316946,
+        "id": "pizzelle-cookie-iv", "times_awarded": 3, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1452873723.0, "percent_earned": 0.005057401507105649,
+        "id": "silver", "times_awarded": 1, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "churchyard", "last_awarded": 1452875228.0, "percent_earned": 0.05057401507105649,
+        "id": "top-10", "times_awarded": 10, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "siwinski", "last_awarded": 1453319241.0, "percent_earned": 0.15677944672027513,
+        "id": "top-100", "times_awarded": 31, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1453212640.0, "percent_earned": 0.13149243918474687,
+        "id": "top-25", "times_awarded": 26, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mluscon", "last_awarded": 1453387764.0, "percent_earned": 0.30344409042633896,
+        "id": "top-500", "times_awarded": 60, "name": "Top 500"}], "user": "ralph",
+        "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png"}'}
+    headers:
+      appserver: [proxy10.phx2.fedoraproject.org]
+      apptime: [D=14564110]
+      connection: [Keep-Alive]
+      content-length: ['66175']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 21 Jan 2016 15:58:44 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_should_invalidate_good_match b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_should_invalidate_good_match
new file mode 100644
index 0000000..141bebb
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_should_invalidate_good_match
@@ -0,0 +1,117 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy11.fedoraproject.org]
+      apptime: [D=168454]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1823']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:06:58 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy03.fedoraproject.org]
+      apptime: [D=99135]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1874']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:11:16 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_should_invalidate_wrong_topic b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_should_invalidate_wrong_topic
new file mode 100644
index 0000000..26d99fc
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_should_invalidate_wrong_topic
@@ -0,0 +1,59 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy03.fedoraproject.org]
+      apptime: [D=107470]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1823']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:06:59 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_should_invalidate_wrong_user b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_should_invalidate_wrong_user
new file mode 100644
index 0000000..7f29a67
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_should_invalidate_wrong_user
@@ -0,0 +1,119 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-ebb84660-59e9-4e68-af8f-4e6f49348b88
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy01.phx2.fedoraproject.org]
+      apptime: [D=4994]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1823']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:07:00 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/id?id=2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f
+  response:
+    body:
+      string: !!binary |
+        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
+        CwAA
+    headers:
+      appserver: [proxy12.fedoraproject.org]
+      apptime: [D=143566]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['1941']
+      content-type: ['*/*']
+      date: ['Thu, 21 Jan 2016 16:11:17 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_view_authz b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_view_authz
new file mode 100644
index 0000000..cf740f8
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_badges.TestBadges.test_view_authz
@@ -0,0 +1,2705 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"user_count": 44887, "rank": 5, "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png",
+        "percentile": "0.01", "assertions": [{"description": "You attended Flock 2013,
+        the Fedora Contributor Conference", "tags": "flock,event,", "issued": 1375373082.0,
+        "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "rbergero", "last_awarded": 1473972160.0, "percent_earned": 0.18034465868103486,
+        "id": "flock-2013-attendee", "times_awarded": 81, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198996.0, "percent_earned": 0.663490225764795,
+        "id": "tagger-tagger-ii", "times_awarded": 298, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002037.0, "percent_earned": 1.0508972703388697,
+        "id": "junior-tagger-tagger-i", "times_awarded": 472, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ylarguex", "last_awarded": 1491516838.0, "percent_earned": 53.357527719641986,
+        "id": "involvement", "times_awarded": 23965, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "icole",
+        "last_awarded": 1491505117.0, "percent_earned": 3.9564501046444316, "id":
+        "speak-up!", "times_awarded": 1777, "name": "Speak Up!"}, {"description":
+        "Edited at least 10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0,
+        "image": "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "kdudka",
+        "last_awarded": 1491484751.0, "percent_earned": 3.3129981742886407, "id":
+        "junior-editor", "times_awarded": 1488, "name": "Junior Editor"}, {"description":
+        "Edited at least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0,
+        "image": "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "ankit1997",
+        "last_awarded": 1491242577.0, "percent_earned": 2.108473972480741, "id": "associate-editor",
+        "times_awarded": 947, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "yzhang",
+        "last_awarded": 1491431124.0, "percent_earned": 1.5451752237609653, "id":
+        "secretary-general", "times_awarded": 694, "name": "Secretary General"}, {"description":
+        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
+        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198974.0, "percent_earned": 0.3139332947410607,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 141, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491425650.0, "percent_earned": 0.5454869305784388,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 245, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "nickboldt",
+        "last_awarded": 1490915696.0, "percent_earned": 2.858796811684553, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1284, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "sjenning", "last_awarded": 1491017600.0, "percent_earned": 2.3288952219797836,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 1046, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "tartare",
+        "last_awarded": 1491481451.0, "percent_earned": 1.4138130649686065, "id":
+        "if-you-build-it...-koji-success-iii", "times_awarded": 635, "name": "If you
+        build it... (Koji Success III)"}, {"description": "Ten or more questions and
+        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
+        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedo25", "last_awarded": 1491440137.0, "percent_earned": 1.4182660195039407,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 637, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "andre", "last_awarded": 1491511008.0, "percent_earned": 9.738611568775884,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 4374, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491482061.0, "percent_earned": 1.903638063855368,
+        "id": "riddle-me-this", "times_awarded": 855, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mhonek", "last_awarded": 1490899614.0, "percent_earned": 2.0127354499710557,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 904, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "nickboldt", "last_awarded": 1491244448.0, "percent_earned": 1.94816760920871,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 875, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "jscotka",
+        "last_awarded": 1491289110.0, "percent_earned": 2.6695462439328494, "id":
+        "you-can-call-me-patches-scm-i", "times_awarded": 1199, "name": "You can call
+        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
+        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "berrange",
+        "last_awarded": 1491242273.0, "percent_earned": 0.5588457941844414, "id":
+        "you-can-call-me-patches-scm-iv", "times_awarded": 251, "name": "You can call
+        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
+        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "cydrobolt",
+        "last_awarded": 1490744785.0, "percent_earned": 1.3603776105445964, "id":
+        "you-can-call-me-patches-scm-iii", "times_awarded": 611, "name": "You can
+        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441515.0, "percent_earned": 0.6523578394264594,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 293, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "tkrizek", "last_awarded": 1490376511.0, "percent_earned": 1.329206928797257,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 597, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441872.0, "percent_earned": 0.5299015897047691,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 238, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "toshio", "last_awarded": 1491516269.0, "percent_earned": 2.70739635748319,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 1216, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "apollo7", "last_awarded": 1491362331.0, "percent_earned": 7.547757937391459,
+        "id": "junior-badger-badger-i", "times_awarded": 3390, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "scox", "last_awarded": 1491419635.0, "percent_earned": 2.562675335084829,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 1151, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "alciregi", "last_awarded": 1491294835.0, "percent_earned": 1.6631785189473214,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 747, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "mystro256",
+        "last_awarded": 1491340270.0, "percent_earned": 0.39408647637707617, "id":
+        "like-a-rock-updates-stable-iii", "times_awarded": 177, "name": "Like a Rock
+        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
+        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "landgraf", "last_awarded": 1491498009.0, "percent_earned": 6.412254530881239,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2880, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "cqi",
+        "last_awarded": 1491420777.0, "percent_earned": 1.2379213608229058, "id":
+        "like-a-rock-updates-stable-ii", "times_awarded": 556, "name": "Like a Rock
+        (Updates-Stable II)"}, {"description": "Partied with Flock 2013 (at the South
+        Carolina Aquarium)", "tags": "party,flock,event,", "issued": 1376252202.0,
+        "image": "https://badges.fedoraproject.org/pngs/tanked.png", "first_awarded":
+        1376252202.0, "first_awarded_person": "ralph", "last_awarded_person": "gnokii",
+        "last_awarded": 1411656869.0, "percent_earned": 0.14026806786302712, "id":
+        "tanked!", "times_awarded": 63, "name": "Tanked!"}, {"description": "You proposed
+        a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,", "issued":
+        1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "frantisekz", "last_awarded": 1484316413.0, "percent_earned": 0.3161597720087278,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 142, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491477255.0, "percent_earned": 5.508304760208398,
+        "id": "bona-fide", "times_awarded": 2474, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.05788840895934453,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "mailga", "last_awarded": 1491037049.0, "percent_earned": 0.823796589036826,
+        "id": "senior-badger-badger-ii", "times_awarded": 370, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "olem",
+        "last_awarded": 1491070078.0, "percent_earned": 2.658413857594514, "id": "is-this-thing-on-updates-testing-i",
+        "times_awarded": 1194, "name": "Is this thing on? (Updates-Testing I)"}, {"description":
+        "Pushed 20 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1376077757.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491432891.0, "percent_earned": 1.467248519392617,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 659, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "dustymabe",
+        "last_awarded": 1491406327.0, "percent_earned": 1.714387496103665, "id": "partners-in-crime",
+        "times_awarded": 770, "name": "Partners in Crime"}, {"description": "*(a great
+        struggle, repeated escapes, discipline required)*\nTested and added karma
+        to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "mcepl", "last_awarded": 1491490795.0, "percent_earned": 0.961838179632186,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 432, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "bt0dotninja",
+        "last_awarded": 1489638271.0, "percent_earned": 0.16253284053969808, "id":
+        "master-tagger-tagger-iv", "times_awarded": 73, "name": "Master Tagger (Tagger
+        IV)"}, {"description": "A member of the sysadmin-badges group.  Nothing to
+        see here..  move along.", "tags": "infrastructure,badges,community,", "issued":
+        1378319150.0, "image": "https://badges.fedoraproject.org/pngs/fas-inside-job.png",
+        "first_awarded": 1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "jflory7", "last_awarded": 1472154166.0, "percent_earned": 0.02226477267667097,
+        "id": "inside-job", "times_awarded": 10, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "salvadorhm", "last_awarded": 1491509400.0, "percent_earned": 8.144453845126241,
+        "id": "white-rabbit", "times_awarded": 3658, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jcholast", "last_awarded": 1491423845.0, "percent_earned": 3.061406243042258,
+        "id": "mugshot", "times_awarded": 1375, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.03785011355034065,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jkaluza", "last_awarded": 1490254934.0, "percent_earned": 0.10241795431268647,
+        "id": "maestro", "times_awarded": 46, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "cra", "last_awarded": 1491437628.0, "percent_earned": 4.250345103976488,
+        "id": "let-me-introduce-myself", "times_awarded": 1909, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "ngompa", "last_awarded": 1490659963.0, "percent_earned": 0.7614552255421472,
+        "id": "binary-star", "times_awarded": 342, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "xavierb", "last_awarded": 1484573828.0, "percent_earned": 0.32506568107939615,
+        "id": "packager-sponsor", "times_awarded": 146, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468491.0, "percent_earned": 1.3470187469385937,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 605, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468509.0, "percent_earned": 1.1399563610455536,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 512, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468543.0, "percent_earned": 1.6231019281293138,
+        "id": "bloggin-it!-planet-i", "times_awarded": 729, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "dtimms", "last_awarded": 1491484910.0, "percent_earned": 0.939573406955515,
+        "id": "white-hat", "times_awarded": 422, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.17589170414570066,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "andrespol", "last_awarded": 1491360716.0, "percent_earned": 20.256490181235247,
+        "id": "embryo", "times_awarded": 9098, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "piotrdrag", "last_awarded": 1491478479.0, "percent_earned": 0.549939885113773,
+        "id": "taming-the-bull-tester-v", "times_awarded": 247, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ferdnyc", "last_awarded": 1484744055.0, "percent_earned": 0.1469474996660284,
+        "id": "common-bugs-contributor", "times_awarded": 66, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "metonymy", "last_awarded": 1491502807.0, "percent_earned": 6.249721690341541,
+        "id": "baby-badger", "times_awarded": 2807, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "martinkg", "last_awarded": 1489655875.0, "percent_earned": 0.09351204524201807,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 42, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pwalter", "last_awarded": 1491445231.0, "percent_earned": 0.6167342031437859,
+        "id": "old-yeller", "times_awarded": 277, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.1580798860043639,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "stefw", "last_awarded": 1491468562.0, "percent_earned": 0.7547757937391459,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 339, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "augenauf", "last_awarded": 1491316933.0, "percent_earned": 1.013047156788529,
+        "id": "senior-editor", "times_awarded": 455, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "avichi", "last_awarded": 1491361425.0, "percent_earned": 14.18933962684241,
+        "id": "tadpole", "times_awarded": 6373, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "amogh23k", "last_awarded": 1491362307.0, "percent_earned": 28.41430288996749,
+        "id": "egg", "times_awarded": 12762, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "akopacsi", "last_awarded": 1490757692.0, "percent_earned": 7.30952486975108,
+        "id": "tadpole-with-legs", "times_awarded": 3283, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "lsedlar", "last_awarded": 1476326553.0, "percent_earned": 0.05120897715634323,
+        "id": "badge-off!", "times_awarded": 23, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "sassam", "last_awarded": 1491148875.0, "percent_earned": 0.3072538629380594,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 138, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "metonymy", "last_awarded": 1491476646.0, "percent_earned": 0.4208042035890813,
+        "id": "no-longer-a-ronin", "times_awarded": 189, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bt0dotninja", "last_awarded": 1489643141.0, "percent_earned": 0.13358863606002583,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 60, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002111.0, "percent_earned": 0.8750055661931692,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 393, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "ignacio", "last_awarded": 1485888954.0, "percent_earned": 0.28944204479672264,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 130, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "imabug", "last_awarded": 1490199130.0, "percent_earned": 0.5120897715634324,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 230, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "devconf,speaker,event,", "issued": 1390422108.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.10241795431268647, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "terjeros", "last_awarded": 1491331717.0, "percent_earned": 0.26717727212005166,
+        "id": "patches-scm-v", "times_awarded": 120, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "decathorpe", "last_awarded": 1491331634.0, "percent_earned": 0.7480963619361446,
+        "id": "override,-you-say", "times_awarded": 336, "name": "Override, you say?"},
+        {"description": "You attended the 2014 iteration of devconf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event,devconf,", "issued":
+        1391763090.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png",
+        "first_awarded": 1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.13804159059536003,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf 2014 Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "swilson", "last_awarded": 1458943142.0, "percent_earned":
+        0.03562363628267355, "id": "videographer", "times_awarded": 16, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "zbyszek", "last_awarded": 1490388487.0, "percent_earned": 0.15585340873669679,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 70,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491441908.0, "percent_earned": 3.958676581912099,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1778, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491503467.0, "percent_earned": 2.046132608986062,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 919, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "caiqian",
+        "last_awarded": 1481903131.0, "percent_earned": 1.6765373825533243, "id":
+        "it-still-works!", "times_awarded": 753, "name": "It still works!"}, {"description":
+        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
+        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491442200.0, "percent_earned": 2.1641359041724186,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 972, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "stefw", "last_awarded": 1491468526.0, "percent_earned": 0.35623636282673554,
+        "id": "bob-loblaw-planet-v", "times_awarded": 160, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "dfateyev", "last_awarded": 1490465620.0, "percent_earned": 0.06902079529768002,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 31, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "ignatenkobrain", "last_awarded": 1485808919.0, "percent_earned": 0.14472102239836132,
+        "id": "lets-do-lunch!", "times_awarded": 65, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "mythcat", "last_awarded":
+        1484694397.0, "percent_earned": 0.4208042035890813, "id": "vacation", "times_awarded":
+        189, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "python,event,pycon,", "issued": 1397168025.0, "image":
+        "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png", "first_awarded":
+        1397168025.0, "first_awarded_person": "ralph", "last_awarded_person": "abompard",
+        "last_awarded": 1397573900.0, "percent_earned": 0.02226477267667097, "id":
+        "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 0.6345460212851227,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "nickboldt", "last_awarded": 1490915668.0, "percent_earned": 0.984102952308857,
+        "id": "helping-hand", "times_awarded": 442, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.20483590862537293,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "wtaymans",
+        "last_awarded": 1490906731.0, "percent_earned": 0.20038295409003873, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 90, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "payasr", "last_awarded": 1491512765.0, "percent_earned": 61.86712383666563,
+        "id": "paranoid-panda", "times_awarded": 27787, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.16253284053969808, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jvymazal", "last_awarded": 1491284602.0, "percent_earned": 1.099879770227546,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 494, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "athoscr",
+        "last_awarded": 1490991464.0, "percent_earned": 0.5900164759317807, "id":
+        "master-editor", "times_awarded": 265, "name": "Master Editor"}, {"description":
+        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "terjeros", "last_awarded": 1491384354.0, "percent_earned": 0.389633521841742,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 175, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405296000.0, "first_awarded_person": "marinaz", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.27163022665538583,
+        "id": "flock-2014-attendee", "times_awarded": 122, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "pperron", "last_awarded": 1490999828.0, "percent_earned": 0.49873090795742975,
+        "id": "science-kernel-tester-i", "times_awarded": 224, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.19815647682237164, "id":
+        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
+        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
+        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1485788654.0, "percent_earned": 0.03339715901500646,
+        "id": "corporate-overlord", "times_awarded": 15, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "kdudka", "last_awarded": 1491214689.0, "percent_earned": 0.18925056775170326,
+        "id": "corporate-shill", "times_awarded": 85, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "dsommers", "last_awarded": 1490298016.0, "percent_earned": 1.3024892015852518,
+        "id": "corporate-drone", "times_awarded": 585, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vondruch", "last_awarded": 1491296529.0, "percent_earned": 0.14026806786302712,
+        "id": "master-badger-badger-iii", "times_awarded": 63, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "fale", "last_awarded":
+        1490321832.0, "percent_earned": 0.2248742040343768, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 101, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "rbergero", "last_awarded": 1455959914.0, "percent_earned": 0.0712472725653471,
+        "id": "dancing-with-toshio", "times_awarded": 32, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.2449124994433807, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "keitellf",
+        "last_awarded": 1465418173.0, "percent_earned": 0.8972703388698402, "id":
+        "consolation-prize", "times_awarded": 403, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "usuha", "last_awarded": 1491448085.0, "percent_earned": 6.430066349022577,
+        "id": "crypto-panda", "times_awarded": 2888, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491505320.0, "percent_earned": 2.3711982900654585,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 1065, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1490811747.0, "percent_earned": 0.03562363628267355,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 16, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "sailer", "last_awarded": 1490344262.0, "percent_earned": 0.7525493164714788,
+        "id": "the-cat-came-back...", "times_awarded": 338, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "michalrud", "last_awarded": 1470317213.0, "percent_earned": 0.04675602262100904,
+        "id": "apprentice-badge-artist-i", "times_awarded": 21, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "kkeithle", "last_awarded": 1491364811.0, "percent_earned": 0.20706238589304005,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 93, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.04007659081800775,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.13804159059536003,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "orion", "last_awarded": 1490756246.0, "percent_earned": 0.024491249944338066,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 11, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "pcreech17", "last_awarded": 1491432940.0, "percent_earned": 2.3756512446007925,
+        "id": "associate-badger-badger-1.5", "times_awarded": 1067, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "kellin", "last_awarded": 1461547496.0, "percent_earned": 0.18479761321636906,
+        "id": "flock-2015-attendee", "times_awarded": 83, "name": "Flock 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "gtierney", "last_awarded": 1491405719.0, "percent_earned": 1.852429086699025,
+        "id": "macaron-cookie-i", "times_awarded": 832, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "mizdebsk",
+        "last_awarded": 1491500198.0, "percent_earned": 0.3606893173620697, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 162, "name": "Chocolate Chip
+        (Cookie II)"}, {"description": "Voted in the supplemental wallpapers election
+        for the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.18257113594870197,
+        "id": "nuancier-f22", "times_awarded": 82, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "schwankek", "last_awarded": 1491486520.0, "percent_earned": 17.635926437191078,
+        "id": "origin", "times_awarded": 7921, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "nmilosev", "last_awarded": 1491213323.0, "percent_earned": 0.919535111546511,
+        "id": "delivery", "times_awarded": 413, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dustymabe", "last_awarded": 1475240820.0, "percent_earned": 0.5655252259874427,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 254,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dmsimard", "last_awarded": 1491321510.0, "percent_earned": 0.14472102239836132,
+        "id": "black-and-white-cookie-iii", "times_awarded": 65, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "smani", "last_awarded": 1485976444.0, "percent_earned": 0.08460613617134968,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 38, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509860.0, "percent_earned": 0.006679431803001291,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 3, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "pravins", "last_awarded": 1472553692.0, "percent_earned": 0.03562363628267355,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 16, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "frantisekz", "last_awarded": 1485462295.0, "percent_earned": 0.10019147704501936,
+        "id": "badge-muse-badges-released-i", "times_awarded": 45, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509873.0, "percent_earned": 0.013358863606002582,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 6, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.002226477267667097,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "kellin", "last_awarded": 1461547520.0, "percent_earned": 0.16921227234269937,
+        "id": "nom-nom-nom", "times_awarded": 76, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "rluzynski", "last_awarded": 1491442095.0, "percent_earned": 1.5763459055083047,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 708, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491326903.0, "percent_earned": 0.12468272698935744,
+        "id": "rock-the-web!", "times_awarded": 56, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and and you''ve ported at least one package to Python
+        3", "tags": "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "crobinso", "last_awarded": 1491217608.0, "percent_earned": 0.33842454468539873,
+        "id": "parselmouth", "times_awarded": 152, "name": "Parselmouth I"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "jonatoni",
+        "last_awarded": 1490211890.0, "percent_earned": 0.22710068130204392, "id":
+        "chief-editor", "times_awarded": 102, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "apahim", "last_awarded": 1491360865.0, "percent_earned": 4.628846239479895,
+        "id": "froglet", "times_awarded": 2079, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ryanlerch", "last_awarded": 1490719235.0, "percent_earned": 0.03117068174733936,
+        "id": "pizzelle-cookie-iv", "times_awarded": 14, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "churchyard", "last_awarded": 1475564266.0, "percent_earned": 0.011132386338335486,
+        "id": "silver", "times_awarded": 5, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1489622707.0, "percent_earned": 0.03117068174733936,
+        "id": "top-10", "times_awarded": 14, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "tflink", "last_awarded": 1480461776.0, "percent_earned": 0.25159193124638196,
+        "id": "top-100", "times_awarded": 113, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mrunge", "last_awarded": 1490730635.0, "percent_earned": 0.06679431803001291,
+        "id": "top-25", "times_awarded": 30, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "zsun", "last_awarded": 1490677027.0, "percent_earned": 1.2000712472725654,
+        "id": "top-500", "times_awarded": 539, "name": "Top 500"}, {"description":
+        "You visited the Fedora table at BrickHack 2016!", "tags": "brickhack,event,hackathon,events,",
+        "issued": 1457234130.0, "image": "http://infrastructure.fedoraproject.org/infra/badges/pngs/events-brickhack-2016.png",
+        "first_awarded": 1455845197.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "brandondgr8", "last_awarded": 1461299769.0, "percent_earned": 0.05566193169167742,
+        "id": "brickhack-2016-attendee", "times_awarded": 25, "name": "BrickHack 2016
+        Attendee"}, {"description": "You gave a presentation at DevConf.cz, 2016",
+        "tags": "devconf,speaker,event,", "issued": 1455008224.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2016.png",
+        "first_awarded": 1454667336.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "thozza", "last_awarded": 1459500320.0, "percent_earned": 0.2137418176960413,
+        "id": "devconf-2016-speaker", "times_awarded": 96, "name": "DevConf 2016 Speaker"},
+        {"description": "You attended the 2016 iteration of DevConf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event, devconf,", "issued":
+        1455120228.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee-2016.png",
+        "first_awarded": 1454600601.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "dkaspar", "last_awarded": 1461940547.0, "percent_earned": 0.18925056775170326,
+        "id": "devconf-2016-attendee", "times_awarded": 85, "name": "DevConf 2016
+        Attendee"}, {"description": "You got a \"Change\" accepted into the Fedora
+        24 Change list", "tags": "development,FESCo,process,", "issued": 1458652673.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f24.png", "first_awarded":
+        1458651465.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "pnemade", "last_awarded": 1459240914.0, "percent_earned": 0.10019147704501936,
+        "id": "fedora-24-change-accepted", "times_awarded": 45, "name": "Fedora 24
+        Change Accepted"}, {"description": "You held third place on the Fedora Badges
+        leaderboard", "tags": "meta,community,", "issued": 1462904993.0, "image":
+        "https://badges.fedoraproject.org/pngs/3_badge_340.png", "first_awarded":
+        1452875229.0, "first_awarded_person": "pnemade", "last_awarded_person": "kevin",
+        "last_awarded": 1489692901.0, "percent_earned": 0.011132386338335486, "id":
+        "bronze", "times_awarded": 5, "name": "Bronze"}, {"description": "You burned
+        a yubikey and linked it with your Fedora Account", "tags": "account,community,",
+        "issued": 1462904755.0, "image": "https://badges.fedoraproject.org/pngs/yubi-badge.png",
+        "first_awarded": 1422906928.0, "first_awarded_person": "plautrba", "last_awarded_person":
+        "findarato", "last_awarded": 1491408410.0, "percent_earned": 0.4052188627154117,
+        "id": "horcrux", "times_awarded": 182, "name": "Horcrux"}, {"description":
+        "You hacked with the Fedora crew at PyCon US 2016", "tags": "event, python,pycon,",
+        "issued": 1464988862.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2016_attendee.png",
+        "first_awarded": 1464988862.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "maxamillion", "last_awarded": 1464991242.0, "percent_earned": 0.028944204479672265,
+        "id": "pycon-2016-attendee", "times_awarded": 13, "name": "PyCon 2016 Attendee"},
+        {"description": "You got 150 Fedora Badges!  Wow!", "tags": "badges,community,",
+        "issued": 1468058613.0, "image": "https://badges.fedoraproject.org/pngs/badger-04.png",
+        "first_awarded": 1457979017.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1490919191.0, "percent_earned": 0.020038295409003874,
+        "id": "badge-junkie-badger-iv", "times_awarded": 9, "name": "Badge Junkie
+        (Badger IV)"}, {"description": "You can speak Python and and you''ve ported
+        at least five packages to Python 3", "tags": "python,miscellaneous,", "issued":
+        1468058067.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-II.png",
+        "first_awarded": 1467988651.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1488193805.0, "percent_earned": 0.028944204479672265,
+        "id": "parselmouth-ii", "times_awarded": 13, "name": "Parselmouth II"}, {"description":
+        "You can speak Python and and you''ve ported at least ten packages to Python
+        3", "tags": "python,miscellaneous,", "issued": 1468058072.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-III.png",
+        "first_awarded": 1467997850.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1489753361.0, "percent_earned": 0.02226477267667097,
+        "id": "parselmouth-iii", "times_awarded": 10, "name": "Parselmouth III"},
+        {"description": "You attended Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,event,events,", "issued": 1470404480.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-attendee.png",
+        "first_awarded": 1468984748.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "adrian", "last_awarded": 1486483875.0, "percent_earned": 0.2360065903727123,
+        "id": "flock-2016-attendee", "times_awarded": 106, "name": "Flock 2016 Attendee"},
+        {"description": "You attended the party at Flock 2016 in Krakow!", "tags":
+        "flock,krakow,event,events,", "issued": 1470404592.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/krakow-brews.png",
+        "first_awarded": 1468963417.0, "first_awarded_person": "duffy", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217490.0, "percent_earned": 0.18257113594870197,
+        "id": "krakow-brews!", "times_awarded": 82, "name": "Krakow Brews!"}, {"description":
+        "You gave a presentation at Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,speaker,event,", "issued": 1471354751.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-speaker.png",
+        "first_awarded": 1470941077.0, "first_awarded_person": "mattdm", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217546.0, "percent_earned": 0.19592999955470453,
+        "id": "flock-2016-speaker", "times_awarded": 88, "name": "Flock 2016 Speaker"},
+        {"description": "You''re a member of the Modularity Working Group!", "tags":
+        "modularity,community,", "issued": 1475082397.0, "image": "https://badges.fedoraproject.org/pngs/fas-modularity-wg.png",
+        "first_awarded": 1475082098.0, "first_awarded_person": "asamalik", "last_awarded_person":
+        "jscotka", "last_awarded": 1491213584.0, "percent_earned": 0.0801531816360155,
+        "id": "modularity-wg-member", "times_awarded": 36, "name": "Modularity WG
+        Member"}, {"description": "You got a \"Change\" accepted into the Fedora 26
+        Change list", "tags": "development, FESCo, process,", "issued": 1479749896.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f26.png", "first_awarded":
+        1473331018.0, "first_awarded_person": "cstratak", "last_awarded_person": "ncoghlan",
+        "last_awarded": 1489656918.0, "percent_earned": 0.11577681791868906, "id":
+        "fedora-26-change-accepted", "times_awarded": 52, "name": "Fedora 26 Change
+        Accepted"}, {"description": "You gave a presentation at DevConf.cz, 2017",
+        "tags": "speaker,devconf,event,", "issued": 1486037155.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2017.png",
+        "first_awarded": 1486033923.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "siddharths", "last_awarded": 1486077040.0, "percent_earned": 0.24713897671104776,
+        "id": "devconf-2017-speaker", "times_awarded": 111, "name": "DevConf 2017
+        Speaker"}, {"description": "You have helped so many Fedorans you''ve got over
+        100 cookies. Don''t eat them all at once!", "tags": "cookie,community,", "issued":
+        1486153659.0, "image": "https://badges.fedoraproject.org/pngs/rainbowcookie.png",
+        "first_awarded": 1468278719.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ralph", "last_awarded": 1486153659.0, "percent_earned": 0.011132386338335486,
+        "id": "rainbow-cookie-v", "times_awarded": 5, "name": "Rainbow (Cookie V)"}],
+        "percent_earned": 41.81818181818181, "user": "ralph"}'}
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=74663696]
+      connection: [Keep-Alive]
+      content-length: ['74203']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 06 Apr 2017 22:31:35 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"user_count": 44887, "rank": 5, "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png",
+        "percentile": "0.01", "assertions": [{"description": "You attended Flock 2013,
+        the Fedora Contributor Conference", "tags": "flock,event,", "issued": 1375373082.0,
+        "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "rbergero", "last_awarded": 1473972160.0, "percent_earned": 0.18034465868103486,
+        "id": "flock-2013-attendee", "times_awarded": 81, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198996.0, "percent_earned": 0.663490225764795,
+        "id": "tagger-tagger-ii", "times_awarded": 298, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002037.0, "percent_earned": 1.0508972703388697,
+        "id": "junior-tagger-tagger-i", "times_awarded": 472, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ylarguex", "last_awarded": 1491516838.0, "percent_earned": 53.357527719641986,
+        "id": "involvement", "times_awarded": 23965, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "icole",
+        "last_awarded": 1491505117.0, "percent_earned": 3.9564501046444316, "id":
+        "speak-up!", "times_awarded": 1777, "name": "Speak Up!"}, {"description":
+        "Edited at least 10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0,
+        "image": "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "kdudka",
+        "last_awarded": 1491484751.0, "percent_earned": 3.3129981742886407, "id":
+        "junior-editor", "times_awarded": 1488, "name": "Junior Editor"}, {"description":
+        "Edited at least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0,
+        "image": "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "ankit1997",
+        "last_awarded": 1491242577.0, "percent_earned": 2.108473972480741, "id": "associate-editor",
+        "times_awarded": 947, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "yzhang",
+        "last_awarded": 1491431124.0, "percent_earned": 1.5451752237609653, "id":
+        "secretary-general", "times_awarded": 694, "name": "Secretary General"}, {"description":
+        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
+        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198974.0, "percent_earned": 0.3139332947410607,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 141, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491425650.0, "percent_earned": 0.5454869305784388,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 245, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "nickboldt",
+        "last_awarded": 1490915696.0, "percent_earned": 2.858796811684553, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1284, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "sjenning", "last_awarded": 1491017600.0, "percent_earned": 2.3288952219797836,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 1046, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "tartare",
+        "last_awarded": 1491481451.0, "percent_earned": 1.4138130649686065, "id":
+        "if-you-build-it...-koji-success-iii", "times_awarded": 635, "name": "If you
+        build it... (Koji Success III)"}, {"description": "Ten or more questions and
+        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
+        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedo25", "last_awarded": 1491440137.0, "percent_earned": 1.4182660195039407,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 637, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "andre", "last_awarded": 1491511008.0, "percent_earned": 9.738611568775884,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 4374, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491482061.0, "percent_earned": 1.903638063855368,
+        "id": "riddle-me-this", "times_awarded": 855, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mhonek", "last_awarded": 1490899614.0, "percent_earned": 2.0127354499710557,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 904, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "nickboldt", "last_awarded": 1491244448.0, "percent_earned": 1.94816760920871,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 875, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "jscotka",
+        "last_awarded": 1491289110.0, "percent_earned": 2.6695462439328494, "id":
+        "you-can-call-me-patches-scm-i", "times_awarded": 1199, "name": "You can call
+        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
+        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "berrange",
+        "last_awarded": 1491242273.0, "percent_earned": 0.5588457941844414, "id":
+        "you-can-call-me-patches-scm-iv", "times_awarded": 251, "name": "You can call
+        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
+        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "cydrobolt",
+        "last_awarded": 1490744785.0, "percent_earned": 1.3603776105445964, "id":
+        "you-can-call-me-patches-scm-iii", "times_awarded": 611, "name": "You can
+        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441515.0, "percent_earned": 0.6523578394264594,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 293, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "tkrizek", "last_awarded": 1490376511.0, "percent_earned": 1.329206928797257,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 597, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441872.0, "percent_earned": 0.5299015897047691,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 238, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "toshio", "last_awarded": 1491516269.0, "percent_earned": 2.70739635748319,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 1216, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "apollo7", "last_awarded": 1491362331.0, "percent_earned": 7.547757937391459,
+        "id": "junior-badger-badger-i", "times_awarded": 3390, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "scox", "last_awarded": 1491419635.0, "percent_earned": 2.562675335084829,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 1151, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "alciregi", "last_awarded": 1491294835.0, "percent_earned": 1.6631785189473214,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 747, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "mystro256",
+        "last_awarded": 1491340270.0, "percent_earned": 0.39408647637707617, "id":
+        "like-a-rock-updates-stable-iii", "times_awarded": 177, "name": "Like a Rock
+        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
+        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "landgraf", "last_awarded": 1491498009.0, "percent_earned": 6.412254530881239,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2880, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "cqi",
+        "last_awarded": 1491420777.0, "percent_earned": 1.2379213608229058, "id":
+        "like-a-rock-updates-stable-ii", "times_awarded": 556, "name": "Like a Rock
+        (Updates-Stable II)"}, {"description": "Partied with Flock 2013 (at the South
+        Carolina Aquarium)", "tags": "party,flock,event,", "issued": 1376252202.0,
+        "image": "https://badges.fedoraproject.org/pngs/tanked.png", "first_awarded":
+        1376252202.0, "first_awarded_person": "ralph", "last_awarded_person": "gnokii",
+        "last_awarded": 1411656869.0, "percent_earned": 0.14026806786302712, "id":
+        "tanked!", "times_awarded": 63, "name": "Tanked!"}, {"description": "You proposed
+        a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,", "issued":
+        1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "frantisekz", "last_awarded": 1484316413.0, "percent_earned": 0.3161597720087278,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 142, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491477255.0, "percent_earned": 5.508304760208398,
+        "id": "bona-fide", "times_awarded": 2474, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.05788840895934453,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "mailga", "last_awarded": 1491037049.0, "percent_earned": 0.823796589036826,
+        "id": "senior-badger-badger-ii", "times_awarded": 370, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "olem",
+        "last_awarded": 1491070078.0, "percent_earned": 2.658413857594514, "id": "is-this-thing-on-updates-testing-i",
+        "times_awarded": 1194, "name": "Is this thing on? (Updates-Testing I)"}, {"description":
+        "Pushed 20 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1376077757.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491432891.0, "percent_earned": 1.467248519392617,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 659, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "dustymabe",
+        "last_awarded": 1491406327.0, "percent_earned": 1.714387496103665, "id": "partners-in-crime",
+        "times_awarded": 770, "name": "Partners in Crime"}, {"description": "*(a great
+        struggle, repeated escapes, discipline required)*\nTested and added karma
+        to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "mcepl", "last_awarded": 1491490795.0, "percent_earned": 0.961838179632186,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 432, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "bt0dotninja",
+        "last_awarded": 1489638271.0, "percent_earned": 0.16253284053969808, "id":
+        "master-tagger-tagger-iv", "times_awarded": 73, "name": "Master Tagger (Tagger
+        IV)"}, {"description": "A member of the sysadmin-badges group.  Nothing to
+        see here..  move along.", "tags": "infrastructure,badges,community,", "issued":
+        1378319150.0, "image": "https://badges.fedoraproject.org/pngs/fas-inside-job.png",
+        "first_awarded": 1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "jflory7", "last_awarded": 1472154166.0, "percent_earned": 0.02226477267667097,
+        "id": "inside-job", "times_awarded": 10, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "salvadorhm", "last_awarded": 1491509400.0, "percent_earned": 8.144453845126241,
+        "id": "white-rabbit", "times_awarded": 3658, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jcholast", "last_awarded": 1491423845.0, "percent_earned": 3.061406243042258,
+        "id": "mugshot", "times_awarded": 1375, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.03785011355034065,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jkaluza", "last_awarded": 1490254934.0, "percent_earned": 0.10241795431268647,
+        "id": "maestro", "times_awarded": 46, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "cra", "last_awarded": 1491437628.0, "percent_earned": 4.250345103976488,
+        "id": "let-me-introduce-myself", "times_awarded": 1909, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "ngompa", "last_awarded": 1490659963.0, "percent_earned": 0.7614552255421472,
+        "id": "binary-star", "times_awarded": 342, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "xavierb", "last_awarded": 1484573828.0, "percent_earned": 0.32506568107939615,
+        "id": "packager-sponsor", "times_awarded": 146, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468491.0, "percent_earned": 1.3470187469385937,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 605, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468509.0, "percent_earned": 1.1399563610455536,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 512, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468543.0, "percent_earned": 1.6231019281293138,
+        "id": "bloggin-it!-planet-i", "times_awarded": 729, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "dtimms", "last_awarded": 1491484910.0, "percent_earned": 0.939573406955515,
+        "id": "white-hat", "times_awarded": 422, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.17589170414570066,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "andrespol", "last_awarded": 1491360716.0, "percent_earned": 20.256490181235247,
+        "id": "embryo", "times_awarded": 9098, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "piotrdrag", "last_awarded": 1491478479.0, "percent_earned": 0.549939885113773,
+        "id": "taming-the-bull-tester-v", "times_awarded": 247, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ferdnyc", "last_awarded": 1484744055.0, "percent_earned": 0.1469474996660284,
+        "id": "common-bugs-contributor", "times_awarded": 66, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "metonymy", "last_awarded": 1491502807.0, "percent_earned": 6.249721690341541,
+        "id": "baby-badger", "times_awarded": 2807, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "martinkg", "last_awarded": 1489655875.0, "percent_earned": 0.09351204524201807,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 42, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pwalter", "last_awarded": 1491445231.0, "percent_earned": 0.6167342031437859,
+        "id": "old-yeller", "times_awarded": 277, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.1580798860043639,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "stefw", "last_awarded": 1491468562.0, "percent_earned": 0.7547757937391459,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 339, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "augenauf", "last_awarded": 1491316933.0, "percent_earned": 1.013047156788529,
+        "id": "senior-editor", "times_awarded": 455, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "avichi", "last_awarded": 1491361425.0, "percent_earned": 14.18933962684241,
+        "id": "tadpole", "times_awarded": 6373, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "amogh23k", "last_awarded": 1491362307.0, "percent_earned": 28.41430288996749,
+        "id": "egg", "times_awarded": 12762, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "akopacsi", "last_awarded": 1490757692.0, "percent_earned": 7.30952486975108,
+        "id": "tadpole-with-legs", "times_awarded": 3283, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "lsedlar", "last_awarded": 1476326553.0, "percent_earned": 0.05120897715634323,
+        "id": "badge-off!", "times_awarded": 23, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "sassam", "last_awarded": 1491148875.0, "percent_earned": 0.3072538629380594,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 138, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "metonymy", "last_awarded": 1491476646.0, "percent_earned": 0.4208042035890813,
+        "id": "no-longer-a-ronin", "times_awarded": 189, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bt0dotninja", "last_awarded": 1489643141.0, "percent_earned": 0.13358863606002583,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 60, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002111.0, "percent_earned": 0.8750055661931692,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 393, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "ignacio", "last_awarded": 1485888954.0, "percent_earned": 0.28944204479672264,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 130, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "imabug", "last_awarded": 1490199130.0, "percent_earned": 0.5120897715634324,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 230, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "devconf,speaker,event,", "issued": 1390422108.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.10241795431268647, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "terjeros", "last_awarded": 1491331717.0, "percent_earned": 0.26717727212005166,
+        "id": "patches-scm-v", "times_awarded": 120, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "decathorpe", "last_awarded": 1491331634.0, "percent_earned": 0.7480963619361446,
+        "id": "override,-you-say", "times_awarded": 336, "name": "Override, you say?"},
+        {"description": "You attended the 2014 iteration of devconf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event,devconf,", "issued":
+        1391763090.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png",
+        "first_awarded": 1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.13804159059536003,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf 2014 Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "swilson", "last_awarded": 1458943142.0, "percent_earned":
+        0.03562363628267355, "id": "videographer", "times_awarded": 16, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "zbyszek", "last_awarded": 1490388487.0, "percent_earned": 0.15585340873669679,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 70,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491441908.0, "percent_earned": 3.958676581912099,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1778, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491503467.0, "percent_earned": 2.046132608986062,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 919, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "caiqian",
+        "last_awarded": 1481903131.0, "percent_earned": 1.6765373825533243, "id":
+        "it-still-works!", "times_awarded": 753, "name": "It still works!"}, {"description":
+        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
+        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491442200.0, "percent_earned": 2.1641359041724186,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 972, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "stefw", "last_awarded": 1491468526.0, "percent_earned": 0.35623636282673554,
+        "id": "bob-loblaw-planet-v", "times_awarded": 160, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "dfateyev", "last_awarded": 1490465620.0, "percent_earned": 0.06902079529768002,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 31, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "ignatenkobrain", "last_awarded": 1485808919.0, "percent_earned": 0.14472102239836132,
+        "id": "lets-do-lunch!", "times_awarded": 65, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "mythcat", "last_awarded":
+        1484694397.0, "percent_earned": 0.4208042035890813, "id": "vacation", "times_awarded":
+        189, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "python,event,pycon,", "issued": 1397168025.0, "image":
+        "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png", "first_awarded":
+        1397168025.0, "first_awarded_person": "ralph", "last_awarded_person": "abompard",
+        "last_awarded": 1397573900.0, "percent_earned": 0.02226477267667097, "id":
+        "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 0.6345460212851227,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "nickboldt", "last_awarded": 1490915668.0, "percent_earned": 0.984102952308857,
+        "id": "helping-hand", "times_awarded": 442, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.20483590862537293,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "wtaymans",
+        "last_awarded": 1490906731.0, "percent_earned": 0.20038295409003873, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 90, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "payasr", "last_awarded": 1491512765.0, "percent_earned": 61.86712383666563,
+        "id": "paranoid-panda", "times_awarded": 27787, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.16253284053969808, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jvymazal", "last_awarded": 1491284602.0, "percent_earned": 1.099879770227546,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 494, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "athoscr",
+        "last_awarded": 1490991464.0, "percent_earned": 0.5900164759317807, "id":
+        "master-editor", "times_awarded": 265, "name": "Master Editor"}, {"description":
+        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "terjeros", "last_awarded": 1491384354.0, "percent_earned": 0.389633521841742,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 175, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405296000.0, "first_awarded_person": "marinaz", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.27163022665538583,
+        "id": "flock-2014-attendee", "times_awarded": 122, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "pperron", "last_awarded": 1490999828.0, "percent_earned": 0.49873090795742975,
+        "id": "science-kernel-tester-i", "times_awarded": 224, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.19815647682237164, "id":
+        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
+        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
+        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1485788654.0, "percent_earned": 0.03339715901500646,
+        "id": "corporate-overlord", "times_awarded": 15, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "kdudka", "last_awarded": 1491214689.0, "percent_earned": 0.18925056775170326,
+        "id": "corporate-shill", "times_awarded": 85, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "dsommers", "last_awarded": 1490298016.0, "percent_earned": 1.3024892015852518,
+        "id": "corporate-drone", "times_awarded": 585, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vondruch", "last_awarded": 1491296529.0, "percent_earned": 0.14026806786302712,
+        "id": "master-badger-badger-iii", "times_awarded": 63, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "fale", "last_awarded":
+        1490321832.0, "percent_earned": 0.2248742040343768, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 101, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "rbergero", "last_awarded": 1455959914.0, "percent_earned": 0.0712472725653471,
+        "id": "dancing-with-toshio", "times_awarded": 32, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.2449124994433807, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "keitellf",
+        "last_awarded": 1465418173.0, "percent_earned": 0.8972703388698402, "id":
+        "consolation-prize", "times_awarded": 403, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "usuha", "last_awarded": 1491448085.0, "percent_earned": 6.430066349022577,
+        "id": "crypto-panda", "times_awarded": 2888, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491505320.0, "percent_earned": 2.3711982900654585,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 1065, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1490811747.0, "percent_earned": 0.03562363628267355,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 16, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "sailer", "last_awarded": 1490344262.0, "percent_earned": 0.7525493164714788,
+        "id": "the-cat-came-back...", "times_awarded": 338, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "michalrud", "last_awarded": 1470317213.0, "percent_earned": 0.04675602262100904,
+        "id": "apprentice-badge-artist-i", "times_awarded": 21, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "kkeithle", "last_awarded": 1491364811.0, "percent_earned": 0.20706238589304005,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 93, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.04007659081800775,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.13804159059536003,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "orion", "last_awarded": 1490756246.0, "percent_earned": 0.024491249944338066,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 11, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "pcreech17", "last_awarded": 1491432940.0, "percent_earned": 2.3756512446007925,
+        "id": "associate-badger-badger-1.5", "times_awarded": 1067, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "kellin", "last_awarded": 1461547496.0, "percent_earned": 0.18479761321636906,
+        "id": "flock-2015-attendee", "times_awarded": 83, "name": "Flock 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "gtierney", "last_awarded": 1491405719.0, "percent_earned": 1.852429086699025,
+        "id": "macaron-cookie-i", "times_awarded": 832, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "mizdebsk",
+        "last_awarded": 1491500198.0, "percent_earned": 0.3606893173620697, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 162, "name": "Chocolate Chip
+        (Cookie II)"}, {"description": "Voted in the supplemental wallpapers election
+        for the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.18257113594870197,
+        "id": "nuancier-f22", "times_awarded": 82, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "schwankek", "last_awarded": 1491486520.0, "percent_earned": 17.635926437191078,
+        "id": "origin", "times_awarded": 7921, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "nmilosev", "last_awarded": 1491213323.0, "percent_earned": 0.919535111546511,
+        "id": "delivery", "times_awarded": 413, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dustymabe", "last_awarded": 1475240820.0, "percent_earned": 0.5655252259874427,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 254,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dmsimard", "last_awarded": 1491321510.0, "percent_earned": 0.14472102239836132,
+        "id": "black-and-white-cookie-iii", "times_awarded": 65, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "smani", "last_awarded": 1485976444.0, "percent_earned": 0.08460613617134968,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 38, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509860.0, "percent_earned": 0.006679431803001291,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 3, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "pravins", "last_awarded": 1472553692.0, "percent_earned": 0.03562363628267355,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 16, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "frantisekz", "last_awarded": 1485462295.0, "percent_earned": 0.10019147704501936,
+        "id": "badge-muse-badges-released-i", "times_awarded": 45, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509873.0, "percent_earned": 0.013358863606002582,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 6, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.002226477267667097,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "kellin", "last_awarded": 1461547520.0, "percent_earned": 0.16921227234269937,
+        "id": "nom-nom-nom", "times_awarded": 76, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "rluzynski", "last_awarded": 1491442095.0, "percent_earned": 1.5763459055083047,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 708, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491326903.0, "percent_earned": 0.12468272698935744,
+        "id": "rock-the-web!", "times_awarded": 56, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and and you''ve ported at least one package to Python
+        3", "tags": "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "crobinso", "last_awarded": 1491217608.0, "percent_earned": 0.33842454468539873,
+        "id": "parselmouth", "times_awarded": 152, "name": "Parselmouth I"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "jonatoni",
+        "last_awarded": 1490211890.0, "percent_earned": 0.22710068130204392, "id":
+        "chief-editor", "times_awarded": 102, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "apahim", "last_awarded": 1491360865.0, "percent_earned": 4.628846239479895,
+        "id": "froglet", "times_awarded": 2079, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ryanlerch", "last_awarded": 1490719235.0, "percent_earned": 0.03117068174733936,
+        "id": "pizzelle-cookie-iv", "times_awarded": 14, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "churchyard", "last_awarded": 1475564266.0, "percent_earned": 0.011132386338335486,
+        "id": "silver", "times_awarded": 5, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1489622707.0, "percent_earned": 0.03117068174733936,
+        "id": "top-10", "times_awarded": 14, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "tflink", "last_awarded": 1480461776.0, "percent_earned": 0.25159193124638196,
+        "id": "top-100", "times_awarded": 113, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mrunge", "last_awarded": 1490730635.0, "percent_earned": 0.06679431803001291,
+        "id": "top-25", "times_awarded": 30, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "zsun", "last_awarded": 1490677027.0, "percent_earned": 1.2000712472725654,
+        "id": "top-500", "times_awarded": 539, "name": "Top 500"}, {"description":
+        "You visited the Fedora table at BrickHack 2016!", "tags": "brickhack,event,hackathon,events,",
+        "issued": 1457234130.0, "image": "http://infrastructure.fedoraproject.org/infra/badges/pngs/events-brickhack-2016.png",
+        "first_awarded": 1455845197.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "brandondgr8", "last_awarded": 1461299769.0, "percent_earned": 0.05566193169167742,
+        "id": "brickhack-2016-attendee", "times_awarded": 25, "name": "BrickHack 2016
+        Attendee"}, {"description": "You gave a presentation at DevConf.cz, 2016",
+        "tags": "devconf,speaker,event,", "issued": 1455008224.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2016.png",
+        "first_awarded": 1454667336.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "thozza", "last_awarded": 1459500320.0, "percent_earned": 0.2137418176960413,
+        "id": "devconf-2016-speaker", "times_awarded": 96, "name": "DevConf 2016 Speaker"},
+        {"description": "You attended the 2016 iteration of DevConf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event, devconf,", "issued":
+        1455120228.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee-2016.png",
+        "first_awarded": 1454600601.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "dkaspar", "last_awarded": 1461940547.0, "percent_earned": 0.18925056775170326,
+        "id": "devconf-2016-attendee", "times_awarded": 85, "name": "DevConf 2016
+        Attendee"}, {"description": "You got a \"Change\" accepted into the Fedora
+        24 Change list", "tags": "development,FESCo,process,", "issued": 1458652673.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f24.png", "first_awarded":
+        1458651465.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "pnemade", "last_awarded": 1459240914.0, "percent_earned": 0.10019147704501936,
+        "id": "fedora-24-change-accepted", "times_awarded": 45, "name": "Fedora 24
+        Change Accepted"}, {"description": "You held third place on the Fedora Badges
+        leaderboard", "tags": "meta,community,", "issued": 1462904993.0, "image":
+        "https://badges.fedoraproject.org/pngs/3_badge_340.png", "first_awarded":
+        1452875229.0, "first_awarded_person": "pnemade", "last_awarded_person": "kevin",
+        "last_awarded": 1489692901.0, "percent_earned": 0.011132386338335486, "id":
+        "bronze", "times_awarded": 5, "name": "Bronze"}, {"description": "You burned
+        a yubikey and linked it with your Fedora Account", "tags": "account,community,",
+        "issued": 1462904755.0, "image": "https://badges.fedoraproject.org/pngs/yubi-badge.png",
+        "first_awarded": 1422906928.0, "first_awarded_person": "plautrba", "last_awarded_person":
+        "findarato", "last_awarded": 1491408410.0, "percent_earned": 0.4052188627154117,
+        "id": "horcrux", "times_awarded": 182, "name": "Horcrux"}, {"description":
+        "You hacked with the Fedora crew at PyCon US 2016", "tags": "event, python,pycon,",
+        "issued": 1464988862.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2016_attendee.png",
+        "first_awarded": 1464988862.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "maxamillion", "last_awarded": 1464991242.0, "percent_earned": 0.028944204479672265,
+        "id": "pycon-2016-attendee", "times_awarded": 13, "name": "PyCon 2016 Attendee"},
+        {"description": "You got 150 Fedora Badges!  Wow!", "tags": "badges,community,",
+        "issued": 1468058613.0, "image": "https://badges.fedoraproject.org/pngs/badger-04.png",
+        "first_awarded": 1457979017.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1490919191.0, "percent_earned": 0.020038295409003874,
+        "id": "badge-junkie-badger-iv", "times_awarded": 9, "name": "Badge Junkie
+        (Badger IV)"}, {"description": "You can speak Python and and you''ve ported
+        at least five packages to Python 3", "tags": "python,miscellaneous,", "issued":
+        1468058067.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-II.png",
+        "first_awarded": 1467988651.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1488193805.0, "percent_earned": 0.028944204479672265,
+        "id": "parselmouth-ii", "times_awarded": 13, "name": "Parselmouth II"}, {"description":
+        "You can speak Python and and you''ve ported at least ten packages to Python
+        3", "tags": "python,miscellaneous,", "issued": 1468058072.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-III.png",
+        "first_awarded": 1467997850.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1489753361.0, "percent_earned": 0.02226477267667097,
+        "id": "parselmouth-iii", "times_awarded": 10, "name": "Parselmouth III"},
+        {"description": "You attended Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,event,events,", "issued": 1470404480.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-attendee.png",
+        "first_awarded": 1468984748.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "adrian", "last_awarded": 1486483875.0, "percent_earned": 0.2360065903727123,
+        "id": "flock-2016-attendee", "times_awarded": 106, "name": "Flock 2016 Attendee"},
+        {"description": "You attended the party at Flock 2016 in Krakow!", "tags":
+        "flock,krakow,event,events,", "issued": 1470404592.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/krakow-brews.png",
+        "first_awarded": 1468963417.0, "first_awarded_person": "duffy", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217490.0, "percent_earned": 0.18257113594870197,
+        "id": "krakow-brews!", "times_awarded": 82, "name": "Krakow Brews!"}, {"description":
+        "You gave a presentation at Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,speaker,event,", "issued": 1471354751.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-speaker.png",
+        "first_awarded": 1470941077.0, "first_awarded_person": "mattdm", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217546.0, "percent_earned": 0.19592999955470453,
+        "id": "flock-2016-speaker", "times_awarded": 88, "name": "Flock 2016 Speaker"},
+        {"description": "You''re a member of the Modularity Working Group!", "tags":
+        "modularity,community,", "issued": 1475082397.0, "image": "https://badges.fedoraproject.org/pngs/fas-modularity-wg.png",
+        "first_awarded": 1475082098.0, "first_awarded_person": "asamalik", "last_awarded_person":
+        "jscotka", "last_awarded": 1491213584.0, "percent_earned": 0.0801531816360155,
+        "id": "modularity-wg-member", "times_awarded": 36, "name": "Modularity WG
+        Member"}, {"description": "You got a \"Change\" accepted into the Fedora 26
+        Change list", "tags": "development, FESCo, process,", "issued": 1479749896.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f26.png", "first_awarded":
+        1473331018.0, "first_awarded_person": "cstratak", "last_awarded_person": "ncoghlan",
+        "last_awarded": 1489656918.0, "percent_earned": 0.11577681791868906, "id":
+        "fedora-26-change-accepted", "times_awarded": 52, "name": "Fedora 26 Change
+        Accepted"}, {"description": "You gave a presentation at DevConf.cz, 2017",
+        "tags": "speaker,devconf,event,", "issued": 1486037155.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2017.png",
+        "first_awarded": 1486033923.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "siddharths", "last_awarded": 1486077040.0, "percent_earned": 0.24713897671104776,
+        "id": "devconf-2017-speaker", "times_awarded": 111, "name": "DevConf 2017
+        Speaker"}, {"description": "You have helped so many Fedorans you''ve got over
+        100 cookies. Don''t eat them all at once!", "tags": "cookie,community,", "issued":
+        1486153659.0, "image": "https://badges.fedoraproject.org/pngs/rainbowcookie.png",
+        "first_awarded": 1468278719.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ralph", "last_awarded": 1486153659.0, "percent_earned": 0.011132386338335486,
+        "id": "rainbow-cookie-v", "times_awarded": 5, "name": "Rainbow (Cookie V)"}],
+        "percent_earned": 41.81818181818181, "user": "ralph"}'}
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=45356299]
+      connection: [Keep-Alive]
+      content-length: ['74203']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 06 Apr 2017 22:32:50 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://badges.fedoraproject.org/user/ralph/json
+  response:
+    body: {string: !!python/unicode '{"user_count": 44887, "rank": 5, "avatar": "https://seccdn.libravatar.org/avatar/9c9f7784935381befc302fe3c814f9136e7a33953d0318761669b8643f4df55c?s=100&d=https%3A%2F%2Fbadges.fedoraproject.org%2Fstatic%2Fimg%2Fbadger_avatar.png",
+        "percentile": "0.01", "assertions": [{"description": "You attended Flock 2013,
+        the Fedora Contributor Conference", "tags": "flock,event,", "issued": 1375373082.0,
+        "image": "https://badges.fedoraproject.org/pngs/flock-2013-attendee.png",
+        "first_awarded": 1375373082.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "rbergero", "last_awarded": 1473972160.0, "percent_earned": 0.18034465868103486,
+        "id": "flock-2013-attendee", "times_awarded": 81, "name": "Flock 2013 Attendee"},
+        {"description": "Voted on 50 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450118.0, "image": "https://badges.fedoraproject.org/pngs/tagger-02.png",
+        "first_awarded": 1375450118.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198996.0, "percent_earned": 0.663490225764795,
+        "id": "tagger-tagger-ii", "times_awarded": 298, "name": "Tagger (Tagger II)"},
+        {"description": "Voted on 10 tags for packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1375450119.0, "image": "https://badges.fedoraproject.org/pngs/tagger-01.png",
+        "first_awarded": 1375450119.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002037.0, "percent_earned": 1.0508972703388697,
+        "id": "junior-tagger-tagger-i", "times_awarded": 472, "name": "Junior Tagger
+        (Tagger I)"}, {"description": "You signed the Fedora Project Contributor Agreement
+        (FPCA)", "tags": "account,community,", "issued": 1375572218.0, "image": "https://badges.fedoraproject.org/pngs/involvement.png",
+        "first_awarded": 1375572176.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ylarguex", "last_awarded": 1491516838.0, "percent_earned": 53.357527719641986,
+        "id": "involvement", "times_awarded": 23965, "name": "Involvement"}, {"description":
+        "Participated in an IRC meeting.", "tags": "irc,community,", "issued": 1375734057.0,
+        "image": "https://badges.fedoraproject.org/pngs/irc-speak-up.png", "first_awarded":
+        1375734057.0, "first_awarded_person": "ralph", "last_awarded_person": "icole",
+        "last_awarded": 1491505117.0, "percent_earned": 3.9564501046444316, "id":
+        "speak-up!", "times_awarded": 1777, "name": "Speak Up!"}, {"description":
+        "Edited at least 10 wiki pages.", "tags": "content,wiki,", "issued": 1375888314.0,
+        "image": "https://badges.fedoraproject.org/pngs/junior-editor.png", "first_awarded":
+        1375888314.0, "first_awarded_person": "ralph", "last_awarded_person": "kdudka",
+        "last_awarded": 1491484751.0, "percent_earned": 3.3129981742886407, "id":
+        "junior-editor", "times_awarded": 1488, "name": "Junior Editor"}, {"description":
+        "Edited at least 20 wiki pages.", "tags": "content,wiki,", "issued": 1375888315.0,
+        "image": "https://badges.fedoraproject.org/pngs/associate-editor.png", "first_awarded":
+        1375888315.0, "first_awarded_person": "ralph", "last_awarded_person": "ankit1997",
+        "last_awarded": 1491242577.0, "percent_earned": 2.108473972480741, "id": "associate-editor",
+        "times_awarded": 947, "name": "Associate Editor"}, {"description": "Chaired
+        an IRC meeting.", "tags": "irc,community,", "issued": 1375889493.0, "image":
+        "https://badges.fedoraproject.org/pngs/irc-secretary-general.png", "first_awarded":
+        1375889493.0, "first_awarded_person": "ralph", "last_awarded_person": "yzhang",
+        "last_awarded": 1491431124.0, "percent_earned": 1.5451752237609653, "id":
+        "secretary-general", "times_awarded": 694, "name": "Secretary General"}, {"description":
+        "Voted on 250 tags for packages in Fedora Tagger.", "tags": "quality,tagger,",
+        "issued": 1375898650.0, "image": "https://badges.fedoraproject.org/pngs/tagger-03.png",
+        "first_awarded": 1375898650.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "imabug", "last_awarded": 1490198974.0, "percent_earned": 0.3139332947410607,
+        "id": "senior-tagger-tagger-iii", "times_awarded": 141, "name": "Senior Tagger
+        (Tagger III)"}, {"description": "Succesfully completed 250 koji builds.",
+        "tags": "development,koji,", "issued": 1377742978.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-04.png",
+        "first_awarded": 1377711940.0, "first_awarded_person": "remi", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491425650.0, "percent_earned": 0.5454869305784388,
+        "id": "if-you-build-it...-koji-success-iv", "times_awarded": 245, "name":
+        "If you build it... (Koji Success IV)"}, {"description": "Succesfully completed
+        a koji build.", "tags": "development,koji,", "issued": 1377742982.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-01.png", "first_awarded":
+        1377708898.0, "first_awarded_person": "mcpierce", "last_awarded_person": "nickboldt",
+        "last_awarded": 1490915696.0, "percent_earned": 2.858796811684553, "id": "if-you-build-it...-koji-success-i",
+        "times_awarded": 1284, "name": "If you build it... (Koji Success I)"}, {"description":
+        "Succesfully completed 10 koji builds.", "tags": "development,koji,", "issued":
+        1377742977.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-02.png",
+        "first_awarded": 1377708893.0, "first_awarded_person": "mcpierce", "last_awarded_person":
+        "sjenning", "last_awarded": 1491017600.0, "percent_earned": 2.3288952219797836,
+        "id": "if-you-build-it...-koji-success-ii", "times_awarded": 1046, "name":
+        "If you build it... (Koji Success II)"}, {"description": "Succesfully completed
+        50 koji builds.", "tags": "development,koji,", "issued": 1377742981.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-03.png", "first_awarded":
+        1377708896.0, "first_awarded_person": "mcpierce", "last_awarded_person": "tartare",
+        "last_awarded": 1491481451.0, "percent_earned": 1.4138130649686065, "id":
+        "if-you-build-it...-koji-success-iii", "times_awarded": 635, "name": "If you
+        build it... (Koji Success III)"}, {"description": "Ten or more questions and
+        answers on the Ask Fedora system.", "tags": "ask fedora,community,", "issued":
+        1377794097.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-02.png",
+        "first_awarded": 1375889645.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "fedo25", "last_awarded": 1491440137.0, "percent_earned": 1.4182660195039407,
+        "id": "curious-penguin-ask-fedora-ii", "times_awarded": 637, "name": "Curious
+        Penguin (Ask Fedora II)"}, {"description": "You had your first interaction
+        with the Ask Fedora forum system.", "tags": "ask fedora,community,", "issued":
+        1377794096.0, "image": "https://badges.fedoraproject.org/pngs/askbot-curious-penguin-01.png",
+        "first_awarded": 1375889644.0, "first_awarded_person": "hmaarrfk", "last_awarded_person":
+        "andre", "last_awarded": 1491511008.0, "percent_earned": 9.738611568775884,
+        "id": "curious-penguin-ask-fedora-i", "times_awarded": 4374, "name": "Curious
+        Penguin (Ask Fedora I)"}, {"description": "You updated your Security Question
+        with the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1375988994.0, "image": "https://badges.fedoraproject.org/pngs/fas-riddle-me-this.png",
+        "first_awarded": 1375988994.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491482061.0, "percent_earned": 1.903638063855368,
+        "id": "riddle-me-this", "times_awarded": 855, "name": "Riddle Me This"}, {"description":
+        "Pushed 30 commits to a Fedora package repository.", "tags": "development,",
+        "issued": 1376076329.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-02.png",
+        "first_awarded": 1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "mhonek", "last_awarded": 1490899614.0, "percent_earned": 2.0127354499710557,
+        "id": "you-can-call-me-patches-scm-ii", "times_awarded": 904, "name": "You
+        can call me \"Patches\" (SCM II)"}, {"description": "Submitted a koji build
+        that failed to build.", "tags": "development,oops,koji,", "issued": 1377887821.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-01.png",
+        "first_awarded": 1377711403.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "nickboldt", "last_awarded": 1491244448.0, "percent_earned": 1.94816760920871,
+        "id": "what-goes-up...-koji-failure-i", "times_awarded": 875, "name": "What
+        goes up... (Koji Failure I)"}, {"description": "Pushed 5 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076328.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-01.png", "first_awarded":
+        1375887918.0, "first_awarded_person": "jforbes", "last_awarded_person": "jscotka",
+        "last_awarded": 1491289110.0, "percent_earned": 2.6695462439328494, "id":
+        "you-can-call-me-patches-scm-i", "times_awarded": 1199, "name": "You can call
+        me \"Patches\" (SCM I)"}, {"description": "Pushed 400 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-04.png", "first_awarded":
+        1375892509.0, "first_awarded_person": "rdieter", "last_awarded_person": "berrange",
+        "last_awarded": 1491242273.0, "percent_earned": 0.5588457941844414, "id":
+        "you-can-call-me-patches-scm-iv", "times_awarded": 251, "name": "You can call
+        me \"Patches\" (SCM IV)"}, {"description": "Pushed 90 commits to a Fedora
+        package repository.", "tags": "development,", "issued": 1376076329.0, "image":
+        "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-03.png", "first_awarded":
+        1375889053.0, "first_awarded_person": "mhlavink", "last_awarded_person": "cydrobolt",
+        "last_awarded": 1490744785.0, "percent_earned": 1.3603776105445964, "id":
+        "you-can-call-me-patches-scm-iii", "times_awarded": 611, "name": "You can
+        call me \"Patches\" (SCM III)"}, {"description": "Submitted 20 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887820.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-03.png",
+        "first_awarded": 1377711401.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441515.0, "percent_earned": 0.6523578394264594,
+        "id": "what-goes-up...-koji-failure-iii", "times_awarded": 293, "name": "What
+        goes up... (Koji Failure III)"}, {"description": "Submitted 5 or more koji
+        builds that failed to build.", "tags": "development,oops,koji,", "issued":
+        1377887822.0, "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-02.png",
+        "first_awarded": 1377711406.0, "first_awarded_person": "bpepple", "last_awarded_person":
+        "tkrizek", "last_awarded": 1490376511.0, "percent_earned": 1.329206928797257,
+        "id": "what-goes-up...-koji-failure-ii", "times_awarded": 597, "name": "What
+        goes up... (Koji Failure II)"}, {"description": "Pushed 100 bodhi updates
+        to the testing repositories.", "tags": "development", "issued": 1376077757.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-03.png",
+        "first_awarded": 1375892382.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "jhogarth", "last_awarded": 1491441872.0, "percent_earned": 0.5299015897047691,
+        "id": "is-this-thing-on-updates-testing-iii", "times_awarded": 238, "name":
+        "Is this thing on? (Updates-Testing III)"}, {"description": "*(a path to follow)*\nTested
+        and added karma to 5 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1376171387.0, "image": "https://badges.fedoraproject.org/pngs/tester-02.png",
+        "first_awarded": 1375889658.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "toshio", "last_awarded": 1491516269.0, "percent_earned": 2.70739635748319,
+        "id": "discovery-of-the-footprints-tester-ii", "times_awarded": 1216, "name":
+        "Discovery of the Footprints (Tester II)"}, {"description": "You got your
+        first 10 Fedora Badges", "tags": "community,badges,", "issued": 1376171392.0,
+        "image": "https://badges.fedoraproject.org/pngs/badger-01.png", "first_awarded":
+        1376118882.0, "first_awarded_person": "ignatenkobrain", "last_awarded_person":
+        "apollo7", "last_awarded": 1491362331.0, "percent_earned": 7.547757937391459,
+        "id": "junior-badger-badger-i", "times_awarded": 3390, "name": "Junior Badger
+        (Badger I)"}, {"description": "You pushed your first bodhi update to the stable
+        repositories.", "tags": "development,", "issued": 1376171906.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-01.png",
+        "first_awarded": 1375891204.0, "first_awarded_person": "blakegardner", "last_awarded_person":
+        "scox", "last_awarded": 1491419635.0, "percent_earned": 2.562675335084829,
+        "id": "like-a-rock-updates-stable-i", "times_awarded": 1151, "name": "Like
+        a Rock (Updates-Stable I)"}, {"description": "*(but only its rear, not its
+        head)*\nTested and added karma to 10 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-03.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "alciregi", "last_awarded": 1491294835.0, "percent_earned": 1.6631785189473214,
+        "id": "perceiving-the-bull-tester-iii", "times_awarded": 747, "name": "Perceiving
+        the Bull (Tester III)"}, {"description": "Pushed 100 bodhi updates to the
+        stable repositories.", "tags": "development,", "issued": 1376171907.0, "image":
+        "https://badges.fedoraproject.org/pngs/like-a-rock-03.png", "first_awarded":
+        1375930621.0, "first_awarded_person": "cicku", "last_awarded_person": "mystro256",
+        "last_awarded": 1491340270.0, "percent_earned": 0.39408647637707617, "id":
+        "like-a-rock-updates-stable-iii", "times_awarded": 177, "name": "Like a Rock
+        (Updates-Stable III)"}, {"description": "*(aimless searching, only the sound
+        of cicadas)*\nTested and added karma to 1 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1376171388.0, "image": "https://badges.fedoraproject.org/pngs/tester-01.png",
+        "first_awarded": 1375889660.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "landgraf", "last_awarded": 1491498009.0, "percent_earned": 6.412254530881239,
+        "id": "in-search-of-the-bull-tester-i", "times_awarded": 2880, "name": "In
+        Search of the Bull (Tester I)"}, {"description": "Pushed 20 bodhi updates
+        to the stable repositories.", "tags": "development,", "issued": 1376171906.0,
+        "image": "https://badges.fedoraproject.org/pngs/like-a-rock-02.png", "first_awarded":
+        1375893154.0, "first_awarded_person": "pingou", "last_awarded_person": "cqi",
+        "last_awarded": 1491420777.0, "percent_earned": 1.2379213608229058, "id":
+        "like-a-rock-updates-stable-ii", "times_awarded": 556, "name": "Like a Rock
+        (Updates-Stable II)"}, {"description": "Partied with Flock 2013 (at the South
+        Carolina Aquarium)", "tags": "party,flock,event,", "issued": 1376252202.0,
+        "image": "https://badges.fedoraproject.org/pngs/tanked.png", "first_awarded":
+        1376252202.0, "first_awarded_person": "ralph", "last_awarded_person": "gnokii",
+        "last_awarded": 1411656869.0, "percent_earned": 0.14026806786302712, "id":
+        "tanked!", "times_awarded": 63, "name": "Tanked!"}, {"description": "You proposed
+        a new idea for a Fedora Badge.  Thanks!", "tags": "community,badges,", "issued":
+        1376261121.0, "image": "https://badges.fedoraproject.org/pngs/badge-muse-01.png",
+        "first_awarded": 1376261121.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "frantisekz", "last_awarded": 1484316413.0, "percent_earned": 0.3161597720087278,
+        "id": "badge-muse-badge-ideas-i", "times_awarded": 142, "name": "Badge Muse
+        (Badge Ideas I)"}, {"description": "You got a new koji certificate!", "tags":
+        "account,community,", "issued": 1376347603.0, "image": "https://badges.fedoraproject.org/pngs/fas-bona-fide.png",
+        "first_awarded": 1375891140.0, "first_awarded_person": "ralphlange", "last_awarded_person":
+        "dtemirgaziyev", "last_awarded": 1491477255.0, "percent_earned": 5.508304760208398,
+        "id": "bona-fide", "times_awarded": 2474, "name": "Bona Fide"}, {"description":
+        " Submitted a Supplemental Wallpaper Idea for Fedora 20.", "tags": "content,design,nuancier,",
+        "issued": 1378218417.0, "image": "https://badges.fedoraproject.org/pngs/design-keepin-fedora-beautiful-f20.png",
+        "first_awarded": 1377269416.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "iwan14", "last_awarded": 1378218427.0, "percent_earned": 0.05788840895934453,
+        "id": "keepin-fedora-beautiful-f20", "times_awarded": 26, "name": "Keepin
+        Fedora Beautiful (F20)"}, {"description": "You got (about) 50 Fedora Badges.  Way
+        to go!", "tags": "community,badges,", "issued": 1378504718.0, "image": "https://badges.fedoraproject.org/pngs/badger-02.png",
+        "first_awarded": 1377470469.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "mailga", "last_awarded": 1491037049.0, "percent_earned": 0.823796589036826,
+        "id": "senior-badger-badger-ii", "times_awarded": 370, "name": "Senior Badger
+        (Badger II)"}, {"description": "You pushed your first bodhi update to the
+        testing repositories.", "tags": "development", "issued": 1376077757.0, "image":
+        "https://badges.fedoraproject.org/pngs/is-this-thing-on-01.png", "first_awarded":
+        1375889661.0, "first_awarded_person": "fantom", "last_awarded_person": "olem",
+        "last_awarded": 1491070078.0, "percent_earned": 2.658413857594514, "id": "is-this-thing-on-updates-testing-i",
+        "times_awarded": 1194, "name": "Is this thing on? (Updates-Testing I)"}, {"description":
+        "Pushed 20 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1376077757.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-02.png",
+        "first_awarded": 1375889878.0, "first_awarded_person": "stefw", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491432891.0, "percent_earned": 1.467248519392617,
+        "id": "is-this-thing-on-updates-testing-ii", "times_awarded": 659, "name":
+        "Is this thing on? (Updates-Testing II)"}, {"description": "You added a co-maintainer
+        to a package. BFF!", "tags": "development,", "issued": 1376531564.0, "image":
+        "https://badges.fedoraproject.org/pngs/pkgdb-partners-in-crime.png", "first_awarded":
+        1376531564.0, "first_awarded_person": "ralph", "last_awarded_person": "dustymabe",
+        "last_awarded": 1491406327.0, "percent_earned": 1.714387496103665, "id": "partners-in-crime",
+        "times_awarded": 770, "name": "Partners in Crime"}, {"description": "*(a great
+        struggle, repeated escapes, discipline required)*\nTested and added karma
+        to 20 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1378251927.0, "image": "https://badges.fedoraproject.org/pngs/tester-04.png",
+        "first_awarded": 1375889657.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "mcepl", "last_awarded": 1491490795.0, "percent_earned": 0.961838179632186,
+        "id": "catching-the-bull-tester-iv", "times_awarded": 432, "name": "Catching
+        the Bull (Tester IV)"}, {"description": "Voted on 1000 tags for packages in
+        Fedora Tagger.", "tags": "quality,tagger,", "issued": 1378613794.0, "image":
+        "https://badges.fedoraproject.org/pngs/tagger-04.png", "first_awarded": 1376814408.0,
+        "first_awarded_person": "jamielinux", "last_awarded_person": "bt0dotninja",
+        "last_awarded": 1489638271.0, "percent_earned": 0.16253284053969808, "id":
+        "master-tagger-tagger-iv", "times_awarded": 73, "name": "Master Tagger (Tagger
+        IV)"}, {"description": "A member of the sysadmin-badges group.  Nothing to
+        see here..  move along.", "tags": "infrastructure,badges,community,", "issued":
+        1378319150.0, "image": "https://badges.fedoraproject.org/pngs/fas-inside-job.png",
+        "first_awarded": 1378319146.0, "first_awarded_person": "oddshocks", "last_awarded_person":
+        "jflory7", "last_awarded": 1472154166.0, "percent_earned": 0.02226477267667097,
+        "id": "inside-job", "times_awarded": 10, "name": "Inside Job"}, {"description":
+        "Indicated your timezone in FAS so everyone can sync with you", "tags": "account,community,",
+        "issued": 1378320160.0, "image": "https://badges.fedoraproject.org/pngs/fas-white-rabbit.png",
+        "first_awarded": 1378313171.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "salvadorhm", "last_awarded": 1491509400.0, "percent_earned": 8.144453845126241,
+        "id": "white-rabbit", "times_awarded": 3658, "name": "White Rabbit"}, {"description":
+        "You have a Libravatar associated with your Fedora OpenID.", "tags": "libravatar,community,",
+        "issued": 1376946138.0, "image": "https://badges.fedoraproject.org/pngs/mugshot.png",
+        "first_awarded": 1376946138.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jcholast", "last_awarded": 1491423845.0, "percent_earned": 3.061406243042258,
+        "id": "mugshot", "times_awarded": 1375, "name": "Mugshot"}, {"description":
+        "A member of sysadmin-main.", "tags": "development,infrastructure,", "issued":
+        1378320106.0, "image": "https://badges.fedoraproject.org/pngs/fas-trust-me-i-know-what-i-am-doing.png",
+        "first_awarded": 1378320079.0, "first_awarded_person": "lmacken", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1430409877.0, "percent_earned": 0.03785011355034065,
+        "id": "trust-me,-i-know-what-i-am-doing", "times_awarded": 17, "name": "Trust
+        me, I know what I am doing"}, {"description": "Has used an ansible playbook
+        to deploy to Fedora Infrastructure", "tags": "development,infrastructure,",
+        "issued": 1378321037.0, "image": "https://badges.fedoraproject.org/pngs/ansible-maestro.png",
+        "first_awarded": 1378321037.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jkaluza", "last_awarded": 1490254934.0, "percent_earned": 0.10241795431268647,
+        "id": "maestro", "times_awarded": 46, "name": "Maestro"}, {"description":
+        "Created your own user profile page on the Fedora Wiki", "tags": "content,",
+        "issued": 1378321704.0, "image": "https://badges.fedoraproject.org/pngs/wiki-let-me-introduce-myself.png",
+        "first_awarded": 1378321704.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "cra", "last_awarded": 1491437628.0, "percent_earned": 4.250345103976488,
+        "id": "let-me-introduce-myself", "times_awarded": 1909, "name": "Let Me Introduce
+        Myself"}, {"description": "You submitted a bodhi update including multiple
+        packages.", "tags": "development,", "issued": 1377206257.0, "image": "https://badges.fedoraproject.org/pngs/bodhi-binary-star.png",
+        "first_awarded": 1376049444.0, "first_awarded_person": "jwrdegoede", "last_awarded_person":
+        "ngompa", "last_awarded": 1490659963.0, "percent_earned": 0.7614552255421472,
+        "id": "binary-star", "times_awarded": 342, "name": "Binary Star"}, {"description":
+        "Became a sponsor of new packagers.", "tags": "development,account,", "issued":
+        1377283223.0, "image": "https://badges.fedoraproject.org/pngs/fas-packager-sponsor.png",
+        "first_awarded": 1377283156.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "xavierb", "last_awarded": 1484573828.0, "percent_earned": 0.32506568107939615,
+        "id": "packager-sponsor", "times_awarded": 146, "name": "Packager Sponsor"},
+        {"description": "You posted 5 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-02.png",
+        "first_awarded": 1375902038.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468491.0, "percent_earned": 1.3470187469385937,
+        "id": "bloggin-it!-planet-ii", "times_awarded": 605, "name": "Bloggin'' it!
+        (Planet II)"}, {"description": "You posted 10 or more things to the Fedora
+        Planet!", "tags": "blog,community,", "issued": 1377697247.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-03.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468509.0, "percent_earned": 1.1399563610455536,
+        "id": "bloggin-it!-planet-iii", "times_awarded": 512, "name": "Bloggin'' it!
+        (Planet III)"}, {"description": "You posted something to the Fedora Planet.",
+        "tags": "blog,community,", "issued": 1377697248.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-01.png",
+        "first_awarded": 1375902037.0, "first_awarded_person": "gomix", "last_awarded_person":
+        "stefw", "last_awarded": 1491468543.0, "percent_earned": 1.6231019281293138,
+        "id": "bloggin-it!-planet-i", "times_awarded": 729, "name": "Bloggin'' it!
+        (Planet I)"}, {"description": "You submitted a bodhi update with type \"security\"",
+        "tags": "development,security,", "issued": 1380316519.0, "image": "https://badges.fedoraproject.org/pngs/white-hat.png",
+        "first_awarded": 1379357860.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "dtimms", "last_awarded": 1491484910.0, "percent_earned": 0.939573406955515,
+        "id": "white-hat", "times_awarded": 422, "name": "White Hat"}, {"description":
+        "Voted in a supplemental wallpapers election for a Fedora release", "tags":
+        "election,community,nuancier,", "issued": 1380637092.0, "image": "https://badges.fedoraproject.org/pngs/nauncier.png",
+        "first_awarded": 1380617342.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "duffy", "last_awarded": 1381233461.0, "percent_earned": 0.17589170414570066,
+        "id": "nuancier", "times_awarded": 79, "name": "Nuancier"}, {"description":
+        "You''ve had a FAS account for over two years", "tags": "lifecycle,community,",
+        "issued": 1389056166.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-embryo.png",
+        "first_awarded": 1389043685.0, "first_awarded_person": "joev", "last_awarded_person":
+        "andrespol", "last_awarded": 1491360716.0, "percent_earned": 20.256490181235247,
+        "id": "embryo", "times_awarded": 9098, "name": "Embryo"}, {"description":
+        "*(less straying/discipline, bull becomes gentle/obedient)*\nTested and added
+        karma to 40 updates-testing updates in Bodhi.\n", "tags": "ten bulls,quality,",
+        "issued": 1381160713.0, "image": "https://badges.fedoraproject.org/pngs/tester-05.png",
+        "first_awarded": 1375896222.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "piotrdrag", "last_awarded": 1491478479.0, "percent_earned": 0.549939885113773,
+        "id": "taming-the-bull-tester-v", "times_awarded": 247, "name": "Taming the
+        Bull (Tester V)"}, {"description": "You contributed to a Common Bugs page.
+        Bugs? What bugs?", "tags": "content,", "issued": 1381324210.0, "image": "https://badges.fedoraproject.org/pngs/wiki-common-bugs.png",
+        "first_awarded": 1381324210.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ferdnyc", "last_awarded": 1484744055.0, "percent_earned": 0.1469474996660284,
+        "id": "common-bugs-contributor", "times_awarded": 66, "name": "Common Bugs
+        Contributor"}, {"description": "You have logged in to the Fedora Badges app",
+        "tags": "community,badges,", "issued": 1382755079.0, "image": "https://badges.fedoraproject.org/pngs/baby-badger.png",
+        "first_awarded": 1382755079.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "metonymy", "last_awarded": 1491502807.0, "percent_earned": 6.249721690341541,
+        "id": "baby-badger", "times_awarded": 2807, "name": "Baby Badger"}, {"description":
+        "Pushed 500 bodhi updates to the testing repositories.", "tags": "development",
+        "issued": 1384804767.0, "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-04.png",
+        "first_awarded": 1376840497.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "martinkg", "last_awarded": 1489655875.0, "percent_earned": 0.09351204524201807,
+        "id": "is-this-thing-on-updates-testing-iv", "times_awarded": 42, "name":
+        "Is this thing on? (Updates-Testing IV)"}, {"description": "You retired a
+        package from the distribution. It hurt, but it had to be done.", "tags": "development,ownership,",
+        "issued": 1389043285.0, "image": "https://badges.fedoraproject.org/pngs/pkgdb-old-yeller.png",
+        "first_awarded": 1382533838.0, "first_awarded_person": "notting", "last_awarded_person":
+        "pwalter", "last_awarded": 1491445231.0, "percent_earned": 0.6167342031437859,
+        "id": "old-yeller", "times_awarded": 277, "name": "Old Yeller"}, {"description":
+        "  You gave a presentation at Flock 2013, the Fedora Contributor Conference",
+        "tags": "event,speaker,", "issued": 1386089550.0, "image": "https://badges.fedoraproject.org/pngs/flockpresenter.png",
+        "first_awarded": 1386089406.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "pjones", "last_awarded": 1407317187.0, "percent_earned": 0.1580798860043639,
+        "id": "flock-2013-speaker", "times_awarded": 71, "name": "Flock 2013 Speaker"},
+        {"description": "You posted 20 or more things to the Fedora Planet!", "tags":
+        "blog,community,", "issued": 1386909731.0, "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-04.png",
+        "first_awarded": 1375904463.0, "first_awarded_person": "paulmellors", "last_awarded_person":
+        "stefw", "last_awarded": 1491468562.0, "percent_earned": 0.7547757937391459,
+        "id": "bloggin-it!-planet-iv", "times_awarded": 339, "name": "Bloggin'' it!
+        (Planet IV)"}, {"description": "Edited at least 50 wiki pages.", "tags": "content,wiki,",
+        "issued": 1389045512.0, "image": "https://badges.fedoraproject.org/pngs/senior-editor.png",
+        "first_awarded": 1375891555.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "augenauf", "last_awarded": 1491316933.0, "percent_earned": 1.013047156788529,
+        "id": "senior-editor", "times_awarded": 455, "name": "Senior Editor"}, {"description":
+        "You''ve had a FAS account for over three years", "tags": "lifecycle,community,",
+        "issued": 1389064377.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole.png",
+        "first_awarded": 1389061835.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "avichi", "last_awarded": 1491361425.0, "percent_earned": 14.18933962684241,
+        "id": "tadpole", "times_awarded": 6373, "name": "Tadpole"}, {"description":
+        "You''ve had a FAS account for over one year", "tags": "lifecycle,community,",
+        "issued": 1389070973.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-egg.png",
+        "first_awarded": 1389068846.0, "first_awarded_person": "darthvader", "last_awarded_person":
+        "amogh23k", "last_awarded": 1491362307.0, "percent_earned": 28.41430288996749,
+        "id": "egg", "times_awarded": 12762, "name": "Egg"}, {"description": "You''ve
+        had a FAS account for over 5 years", "tags": "lifecycle,community,", "issued":
+        1389077372.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-tadpole-with-legs.png",
+        "first_awarded": 1389076692.0, "first_awarded_person": "ftpfree", "last_awarded_person":
+        "akopacsi", "last_awarded": 1490757692.0, "percent_earned": 7.30952486975108,
+        "id": "tadpole-with-legs", "times_awarded": 3283, "name": "Tadpole with Legs"},
+        {"description": "You''re a developer contributing to the Fedora Badges stack",
+        "tags": "development,badges,", "issued": 1389131503.0, "image": "https://badges.fedoraproject.org/pngs/badge-off.png",
+        "first_awarded": 1389131479.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "lsedlar", "last_awarded": 1476326553.0, "percent_earned": 0.05120897715634323,
+        "id": "badge-off!", "times_awarded": 23, "name": "Badge Off!"}, {"description":
+        "*(great joy)*\nTested and added karma to 80 updates-testing updates in Bodhi.\n",
+        "tags": "ten bulls,quality,", "issued": 1389368853.0, "image": "https://badges.fedoraproject.org/pngs/tester-06.png",
+        "first_awarded": 1375896221.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "sassam", "last_awarded": 1491148875.0, "percent_earned": 0.3072538629380594,
+        "id": "riding-the-bull-home-tester-vi", "times_awarded": 138, "name": "Riding
+        the Bull Home (Tester VI)"}, {"description": "You were sponsored into the
+        Fedora Infrastructure Apprentice group", "tags": "development,infrastructure,",
+        "issued": 1389889699.0, "image": "https://badges.fedoraproject.org/pngs/no-ronin.png",
+        "first_awarded": 1389889653.0, "first_awarded_person": "jam3s", "last_awarded_person":
+        "metonymy", "last_awarded": 1491476646.0, "percent_earned": 0.4208042035890813,
+        "id": "no-longer-a-ronin", "times_awarded": 189, "name": "No Longer a Ronin"},
+        {"description": "Added 250 new tags to packages in Fedora Tagger.", "tags":
+        "quality,tagger,", "issued": 1390419184.0, "image": "https://badges.fedoraproject.org/pngs/master-package-tagger.png",
+        "first_awarded": 1390419184.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "bt0dotninja", "last_awarded": 1489643141.0, "percent_earned": 0.13358863606002583,
+        "id": "master-package-tagger-package-tagger-iv", "times_awarded": 60, "name":
+        "Master Package Tagger (Package Tagger IV)"}, {"description": "Added a new
+        tag for a package in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419187.0, "image": "https://badges.fedoraproject.org/pngs/junior-package-tagger.png",
+        "first_awarded": 1390412894.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "bbroad", "last_awarded": 1491002111.0, "percent_earned": 0.8750055661931692,
+        "id": "junior-package-tagger-package-tagger-i", "times_awarded": 393, "name":
+        "Junior Package Tagger (Package Tagger I)"}, {"description": "Added 50 new
+        tags to packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419190.0, "image": "https://badges.fedoraproject.org/pngs/senior-package-tagger.png",
+        "first_awarded": 1390412897.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "ignacio", "last_awarded": 1485888954.0, "percent_earned": 0.28944204479672264,
+        "id": "senior-package-tagger-package-tagger-iii", "times_awarded": 130, "name":
+        "Senior Package Tagger (Package Tagger III)"}, {"description": "Added 10 new
+        tags for packages in Fedora Tagger.", "tags": "quality,tagger,", "issued":
+        1390419193.0, "image": "https://badges.fedoraproject.org/pngs/package-tagger.png",
+        "first_awarded": 1390412900.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "imabug", "last_awarded": 1490199130.0, "percent_earned": 0.5120897715634324,
+        "id": "package-tagger-package-tagger-ii", "times_awarded": 230, "name": "Package
+        Tagger (Package Tagger II)"}, {"description": "You gave a presentation at
+        DevConf.cz, 2014", "tags": "devconf,speaker,event,", "issued": 1390422108.0,
+        "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter.png", "first_awarded":
+        1390422108.0, "first_awarded_person": "ralph", "last_awarded_person": "siddharths",
+        "last_awarded": 1420480194.0, "percent_earned": 0.10241795431268647, "id":
+        "devconf-2014-speaker", "times_awarded": 46, "name": "DevConf 2014 Speaker"},
+        {"description": "Pushed 1000 commits to a Fedora package repository.", "tags":
+        "development,", "issued": 1390944539.0, "image": "https://badges.fedoraproject.org/pngs/you-can-call-me-patches-05.png",
+        "first_awarded": 1375892508.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "terjeros", "last_awarded": 1491331717.0, "percent_earned": 0.26717727212005166,
+        "id": "patches-scm-v", "times_awarded": 120, "name": "Patches (SCM V)"}, {"description":
+        "Created a buildroot override in the koji build system", "tags": "development,",
+        "issued": 1391016371.0, "image": "https://badges.fedoraproject.org/pngs/override-you-say.png",
+        "first_awarded": 1390489685.0, "first_awarded_person": "notting", "last_awarded_person":
+        "decathorpe", "last_awarded": 1491331634.0, "percent_earned": 0.7480963619361446,
+        "id": "override,-you-say", "times_awarded": 336, "name": "Override, you say?"},
+        {"description": "You attended the 2014 iteration of devconf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event,devconf,", "issued":
+        1391763090.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee.png",
+        "first_awarded": 1391760446.0, "first_awarded_person": "churchyard", "last_awarded_person":
+        "siddharths", "last_awarded": 1419207296.0, "percent_earned": 0.13804159059536003,
+        "id": "devconf-attendee", "times_awarded": 62, "name": "DevConf 2014 Attendee"},
+        {"description": "You are a member of the videos team", "tags": "video,community,",
+        "issued": 1392217171.0, "image": "https://badges.fedoraproject.org/pngs/videographer.png",
+        "first_awarded": 1392217167.0, "first_awarded_person": "williamjmorenor",
+        "last_awarded_person": "swilson", "last_awarded": 1458943142.0, "percent_earned":
+        0.03562363628267355, "id": "videographer", "times_awarded": 16, "name": "Videographer"},
+        {"description": "Succesfully completed 1000 koji builds.", "tags": "development,koji,",
+        "issued": 1392827319.0, "image": "https://badges.fedoraproject.org/pngs/koji-if-you-build-it-05.png",
+        "first_awarded": 1377712281.0, "first_awarded_person": "rdieter", "last_awarded_person":
+        "zbyszek", "last_awarded": 1490388487.0, "percent_earned": 0.15585340873669679,
+        "id": "all-your-$arch-are-belong-to-us-koji-success-v", "times_awarded": 70,
+        "name": "All your $arch are belong to us (Koji Success V)"}, {"description":
+        "Successfully completed a copr build", "tags": "development,copr,", "issued":
+        1392676733.0, "image": "https://badges.fedoraproject.org/pngs/copr-build.png",
+        "first_awarded": 1389199510.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491441908.0, "percent_earned": 3.958676581912099,
+        "id": "building-the-outer-ring-copr-build-i", "times_awarded": 1778, "name":
+        "Building the Outer Ring (Copr Build I)"}, {"description": "Someone gave one
+        of your updates good karma", "tags": "development,karma,", "issued": 1392712116.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around.png",
+        "first_awarded": 1392392577.0, "first_awarded_person": "spot", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491503467.0, "percent_earned": 2.046132608986062,
+        "id": "what-goes-around-comes-around-karma-i", "times_awarded": 919, "name":
+        "What goes around comes around (Karma I)"}, {"description": "Tested an update
+        for an older stable release of Fedora", "tags": "quality,", "issued": 1392752446.0,
+        "image": "https://badges.fedoraproject.org/pngs/it-still-works.png", "first_awarded":
+        1386126231.0, "first_awarded_person": "kevin", "last_awarded_person": "caiqian",
+        "last_awarded": 1481903131.0, "percent_earned": 1.6765373825533243, "id":
+        "it-still-works!", "times_awarded": 753, "name": "It still works!"}, {"description":
+        "You submitted an update to bodhi with one or more bugzilla bug numbers attached",
+        "tags": "development,", "issued": 1394463577.0, "image": "https://badges.fedoraproject.org/pngs/take-this.png",
+        "first_awarded": 1393128956.0, "first_awarded_person": "mooninite", "last_awarded_person":
+        "cydrobolt", "last_awarded": 1491442200.0, "percent_earned": 2.1641359041724186,
+        "id": "take-this-and-call-me-in-the-morning", "times_awarded": 972, "name":
+        "Take this and call me in the morning"}, {"description": "You posted 40 or
+        more things to the Fedora Planet!", "tags": "blog,community,", "issued": 1398960087.0,
+        "image": "https://badges.fedoraproject.org/pngs/planet-bloggin-it-05.png",
+        "first_awarded": 1375963234.0, "first_awarded_person": "rjones", "last_awarded_person":
+        "stefw", "last_awarded": 1491468526.0, "percent_earned": 0.35623636282673554,
+        "id": "bob-loblaw-planet-v", "times_awarded": 160, "name": "Bob Loblaw (Planet
+        V)"}, {"description": "Pushed 500 bodhi updates to the stable repositories.",
+        "tags": "development,", "issued": 1396123360.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-04.png",
+        "first_awarded": 1376079014.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "dfateyev", "last_awarded": 1490465620.0, "percent_earned": 0.06902079529768002,
+        "id": "like-a-rock-updates-stable-iv", "times_awarded": 31, "name": "Like
+        a Rock (Updates-Stable IV)"}, {"description": "You set up a meeting in the
+        Fedora Calendar", "tags": "community,", "issued": 1397054728.0, "image": "https://badges.fedoraproject.org/pngs/lets-do-lunch.png",
+        "first_awarded": 1391191973.0, "first_awarded_person": "lbazan", "last_awarded_person":
+        "ignatenkobrain", "last_awarded": 1485808919.0, "percent_earned": 0.14472102239836132,
+        "id": "lets-do-lunch!", "times_awarded": 65, "name": "Let''s do lunch!"},
+        {"description": "Sip the lemonade away (You deserve it for remembering your
+        responsibility)!", "tags": "community,", "issued": 1397059347.0, "image":
+        "https://badges.fedoraproject.org/pngs/beach-bum.png", "first_awarded": 1394486757.0,
+        "first_awarded_person": "shaiton", "last_awarded_person": "mythcat", "last_awarded":
+        1484694397.0, "percent_earned": 0.4208042035890813, "id": "vacation", "times_awarded":
+        189, "name": "Vacation"}, {"description": "You visited the Fedora booth at
+        Pycon, 2014", "tags": "python,event,pycon,", "issued": 1397168025.0, "image":
+        "https://badges.fedoraproject.org/pngs/pycon_2014_attendee.png", "first_awarded":
+        1397168025.0, "first_awarded_person": "ralph", "last_awarded_person": "abompard",
+        "last_awarded": 1397573900.0, "percent_earned": 0.02226477267667097, "id":
+        "pycon-2014-attendee", "times_awarded": 10, "name": "Pycon 2014 Attendee"},
+        {"description": "You submitted feedback for an update in Bodhi after it was
+        pushed to stable", "tags": "quality,oops,", "issued": 1397684618.0, "image":
+        "https://badges.fedoraproject.org/pngs/missed-the-train.png", "first_awarded":
+        1392396477.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "thozza", "last_awarded": 1439904242.0, "percent_earned": 0.6345460212851227,
+        "id": "missed-the-train", "times_awarded": 285, "name": "Missed the Train"},
+        {"description": "You built a package owned by someone else.  It takes a village...",
+        "tags": "development,", "issued": 1400246660.0, "image": "https://badges.fedoraproject.org/pngs/helping_hand.png",
+        "first_awarded": 1394038498.0, "first_awarded_person": "sochotni", "last_awarded_person":
+        "nickboldt", "last_awarded": 1490915668.0, "percent_earned": 0.984102952308857,
+        "id": "helping-hand", "times_awarded": 442, "name": "Helping Hand"}, {"description":
+        "You''ve been granted the blessing of the Fedora Project Leader.", "tags":
+        "fpl,miscellaneous,", "issued": 1401833399.0, "image": "https://badges.fedoraproject.org/pngs/fpl-blessing.png",
+        "first_awarded": 1376269552.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "skottler", "last_awarded": 1401833697.0, "percent_earned": 0.20483590862537293,
+        "id": "the-blessing-of-the-fpl", "times_awarded": 92, "name": "The Blessing
+        of the FPL"}, {"description": "Submitted 100 or more koji builds that failed
+        to build.", "tags": "development,oops,koji,", "issued": 1403195400.0, "image":
+        "https://badges.fedoraproject.org/pngs/koji-what-goes-up-04.png", "first_awarded":
+        1377715853.0, "first_awarded_person": "vicodan", "last_awarded_person": "wtaymans",
+        "last_awarded": 1490906731.0, "percent_earned": 0.20038295409003873, "id":
+        "what-goes-up...-koji-failure-iv", "times_awarded": 90, "name": "What goes
+        up... (Koji Failure IV)"}, {"description": "You updated your password with
+        the Fedora Account System (FAS)", "tags": "account,community,", "issued":
+        1404948910.0, "image": "https://badges.fedoraproject.org/pngs/fas-paranoid-panda.png",
+        "first_awarded": 1376708721.0, "first_awarded_person": "rstrode", "last_awarded_person":
+        "payasr", "last_awarded": 1491512765.0, "percent_earned": 61.86712383666563,
+        "id": "paranoid-panda", "times_awarded": 27787, "name": "Paranoid Panda"},
+        {"description": "      You gave a presentation at Flock 2014, the Fedora Contributor
+        Conference", "tags": "event,flock,speaker,", "issued": 1405362797.0, "image":
+        "https://badges.fedoraproject.org/pngs/flock-2014-speaker.png", "first_awarded":
+        1405362496.0, "first_awarded_person": "abompard", "last_awarded_person": "amita",
+        "last_awarded": 1408553413.0, "percent_earned": 0.16253284053969808, "id":
+        "flock-2014-speaker", "times_awarded": 73, "name": "Flock 2014 Speaker"},
+        {"description": "You have received 10 or more good karma on your bodhi updates",
+        "tags": "development,karma,", "issued": 1406215355.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-10.png",
+        "first_awarded": 1392397378.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "jvymazal", "last_awarded": 1491284602.0, "percent_earned": 1.099879770227546,
+        "id": "what-goes-around-comes-around-karma-ii", "times_awarded": 494, "name":
+        "What goes around comes around (Karma II)"}, {"description": "Edited at least
+        100 wiki pages.", "tags": "content,wiki,", "issued": 1406329746.0, "image":
+        "https://badges.fedoraproject.org/pngs/master-editor.png", "first_awarded":
+        1375891554.0, "first_awarded_person": "ppisar", "last_awarded_person": "athoscr",
+        "last_awarded": 1490991464.0, "percent_earned": 0.5900164759317807, "id":
+        "master-editor", "times_awarded": 265, "name": "Master Editor"}, {"description":
+        "You have received 50 or more good karma on your bodhi updates", "tags": "development,karma,",
+        "issued": 1406630310.0, "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-50.png",
+        "first_awarded": 1393287975.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "terjeros", "last_awarded": 1491384354.0, "percent_earned": 0.389633521841742,
+        "id": "what-goes-around-comes-around-karma-iii", "times_awarded": 175, "name":
+        "What goes around comes around (Karma III)"}, {"description": "  You attended
+        Flock 2014, the Fedora Contributor Conference", "tags": "event,flock,", "issued":
+        1407308400.0, "image": "https://badges.fedoraproject.org/pngs/flock-2014-attendee.png",
+        "first_awarded": 1405296000.0, "first_awarded_person": "marinaz", "last_awarded_person":
+        "rathann", "last_awarded": 1426267409.0, "percent_earned": 0.27163022665538583,
+        "id": "flock-2014-attendee", "times_awarded": 122, "name": "Flock 2014 Attendee"},
+        {"description": "You completed a run of the kernel regression test suite",
+        "tags": "kernel,quality,", "issued": 1407409472.0, "image": "https://badges.fedoraproject.org/pngs/kernel-tester.png",
+        "first_awarded": 1407405561.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "pperron", "last_awarded": 1490999828.0, "percent_earned": 0.49873090795742975,
+        "id": "science-kernel-tester-i", "times_awarded": 224, "name": "Science (Kernel
+        Tester I)"}, {"description": "Ahoy! You attended the boat party at the Flock
+        2014 conference in Prague!", "tags": "event,flock,", "issued": 1407430507.0,
+        "image": "https://badges.fedoraproject.org/pngs/party-pirate.png", "first_awarded":
+        1407430497.0, "first_awarded_person": "lmacken", "last_awarded_person": "amsharma",
+        "last_awarded": 1408665317.0, "percent_earned": 0.19815647682237164, "id":
+        "party-pirate", "times_awarded": 89, "name": "Party Pirate"}, {"description":
+        "You submitted 200 Bodhi updates for an EPEL branch.", "tags": "development,epel,",
+        "issued": 1407498349.0, "image": "https://badges.fedoraproject.org/pngs/corporate-overlord.png",
+        "first_awarded": 1407423571.0, "first_awarded_person": "remi", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1485788654.0, "percent_earned": 0.03339715901500646,
+        "id": "corporate-overlord", "times_awarded": 15, "name": "Corporate Overlord"},
+        {"description": "You submitted 50 Bodhi updates for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498359.0, "image": "https://badges.fedoraproject.org/pngs/corporate-shill.png",
+        "first_awarded": 1407423581.0, "first_awarded_person": "remi", "last_awarded_person":
+        "kdudka", "last_awarded": 1491214689.0, "percent_earned": 0.18925056775170326,
+        "id": "corporate-shill", "times_awarded": 85, "name": "Corporate Shill"},
+        {"description": "You submitted an Bodhi update for an EPEL branch.", "tags":
+        "development,epel,", "issued": 1407498367.0, "image": "https://badges.fedoraproject.org/pngs/corporate-drone.png",
+        "first_awarded": 1407423591.0, "first_awarded_person": "remi", "last_awarded_person":
+        "dsommers", "last_awarded": 1490298016.0, "percent_earned": 1.3024892015852518,
+        "id": "corporate-drone", "times_awarded": 585, "name": "Corporate Drone"},
+        {"description": "You got 100 Fedora Badges!  Wow!", "tags": "community,badges,",
+        "issued": 1407498391.0, "image": "https://badges.fedoraproject.org/pngs/badger-03.png",
+        "first_awarded": 1394558737.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "vondruch", "last_awarded": 1491296529.0, "percent_earned": 0.14026806786302712,
+        "id": "master-badger-badger-iii", "times_awarded": 63, "name": "Master Badger
+        (Badger III)"}, {"description": "*(the bull forgotten, discipline''s whip
+        is idle; stillness)*\nTested and added karma to 125 updates-testing updates
+        in Bodhi.\n", "tags": "ten bulls,quality,", "issued": 1408115651.0, "image":
+        "https://badges.fedoraproject.org/pngs/tester-07.png", "first_awarded": 1375896222.0,
+        "first_awarded_person": "kevin", "last_awarded_person": "fale", "last_awarded":
+        1490321832.0, "percent_earned": 0.2248742040343768, "id": "the-bull-transcended-tester-vii",
+        "times_awarded": 101, "name": "The Bull Transcended (Tester VII)"}, {"description":
+        "You danced with Toshio (abadger1999) at a Fedora event", "tags": "event,freshness,",
+        "issued": 1408122340.0, "image": "https://badges.fedoraproject.org/pngs/dancing_with_toshio.png",
+        "first_awarded": 1408121695.0, "first_awarded_person": "abompard", "last_awarded_person":
+        "rbergero", "last_awarded": 1455959914.0, "percent_earned": 0.0712472725653471,
+        "id": "dancing-with-toshio", "times_awarded": 32, "name": "Dancing with Toshio"},
+        {"description": "Voted in a supplemental wallpapers election for the Fedora
+        21 release", "tags": "election,community,nuancier,", "issued": 1408150877.0,
+        "image": "https://badges.fedoraproject.org/pngs/nuancier-f21-voted.png", "first_awarded":
+        1408147284.0, "first_awarded_person": "gnokii", "last_awarded_person": "pravins",
+        "last_awarded": 1409902273.0, "percent_earned": 0.2449124994433807, "id":
+        "nuancier-21", "times_awarded": 110, "name": "Nuancier 21"}, {"description":
+        "We''re sorry, but you had one of your badges revoked.  Something must have
+        gone wrong.", "tags": "sad trombone,badges,community,", "issued": 1408725704.0,
+        "image": "https://badges.fedoraproject.org/pngs/consolation-prize.png", "first_awarded":
+        1392255607.0, "first_awarded_person": "dmalcolm", "last_awarded_person": "keitellf",
+        "last_awarded": 1465418173.0, "percent_earned": 0.8972703388698402, "id":
+        "consolation-prize", "times_awarded": 403, "name": "Consolation Prize"}, {"description":
+        "You updated your GPG key with the Fedora Account System (FAS)", "tags": "account,community,",
+        "issued": 1408455462.0, "image": "https://badges.fedoraproject.org/pngs/fas-crypto-panda.png",
+        "first_awarded": 1375891835.0, "first_awarded_person": "itorres", "last_awarded_person":
+        "usuha", "last_awarded": 1491448085.0, "percent_earned": 6.430066349022577,
+        "id": "crypto-panda", "times_awarded": 2888, "name": "Crypto Panda"}, {"description":
+        "Successfully completed 20 copr builds", "tags": "development,copr,", "issued":
+        1408587109.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-20.png",
+        "first_awarded": 1389199520.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "shosca", "last_awarded": 1491505320.0, "percent_earned": 2.3711982900654585,
+        "id": "building-the-outer-ring-copr-build-ii", "times_awarded": 1065, "name":
+        "Building the Outer Ring (Copr Build II)"}, {"description": "Pushed 1000 bodhi
+        updates to the testing repositories.", "tags": "development,", "issued": 1409321568.0,
+        "image": "https://badges.fedoraproject.org/pngs/is-this-thing-on-05.png",
+        "first_awarded": 1398006872.0, "first_awarded_person": "jamielinux", "last_awarded_person":
+        "pghmcfc", "last_awarded": 1490811747.0, "percent_earned": 0.03562363628267355,
+        "id": "mic-check!-updates-testing-v", "times_awarded": 16, "name": "Mic Check!
+        (Updates-Testing V)"}, {"description": "You took ownership of a previously
+        orphaned package.", "tags": "development,ownership,", "issued": 1418228616.0,
+        "image": "https://badges.fedoraproject.org/pngs/pkgdb-the-cat-came-back.png",
+        "first_awarded": 1381330499.0, "first_awarded_person": "tmraz", "last_awarded_person":
+        "sailer", "last_awarded": 1490344262.0, "percent_earned": 0.7525493164714788,
+        "id": "the-cat-came-back...", "times_awarded": 338, "name": "The cat came
+        back..."}, {"description": "You designed a Fedora Badge! Welcome to Florence,
+        apprentice badge artist.", "tags": "content,design,badges", "issued": 1420755671.0,
+        "image": "https://badges.fedoraproject.org/pngs/artist-01-apprentice.png",
+        "first_awarded": 1420755606.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "michalrud", "last_awarded": 1470317213.0, "percent_earned": 0.04675602262100904,
+        "id": "apprentice-badge-artist-i", "times_awarded": 21, "name": "Apprentice
+        (Badge Artist I)"}, {"description": "You have received 100 or more good karma
+        on your bodhi updates", "tags": "development,karma,", "issued": 1421316923.0,
+        "image": "https://badges.fedoraproject.org/pngs/what-goes-around-comes-around-100.png",
+        "first_awarded": 1396803342.0, "first_awarded_person": "jforbes", "last_awarded_person":
+        "kkeithle", "last_awarded": 1491364811.0, "percent_earned": 0.20706238589304005,
+        "id": "what-goes-around-comes-around-karma-iv", "times_awarded": 93, "name":
+        "What goes around comes around (Karma IV)"}, {"description": "You participated
+        in the Design Team FAD, 2015", "tags": "event,fad,design,", "issued": 1421420485.0,
+        "image": "https://badges.fedoraproject.org/pngs/fad_design.png", "first_awarded":
+        1421419806.0, "first_awarded_person": "chrisroberts", "last_awarded_person":
+        "rbergero", "last_awarded": 1421432734.0, "percent_earned": 0.04007659081800775,
+        "id": "design-ninja", "times_awarded": 18, "name": "Design Ninja"}, {"description":
+        "You gave a presentation at Flock 2015, the Fedora Contributor Conference",
+        "tags": "event,flock,speaker,", "issued": 1439502241.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-speaker.png",
+        "first_awarded": 1439502092.0, "first_awarded_person": "spot", "last_awarded_person":
+        "jzeleny", "last_awarded": 1439503832.0, "percent_earned": 0.13804159059536003,
+        "id": "flock-2015-speaker", "times_awarded": 62, "name": "Flock 2015 Speaker"},
+        {"description": "Pushed 1000 bodhi updates to the stable repositories.", "tags":
+        "development,", "issued": 1423235515.0, "image": "https://badges.fedoraproject.org/pngs/like-a-rock-05.png",
+        "first_awarded": 1413266082.0, "first_awarded_person": "remi", "last_awarded_person":
+        "orion", "last_awarded": 1490756246.0, "percent_earned": 0.024491249944338066,
+        "id": "tectonic!-updates-stable-v", "times_awarded": 11, "name": "Tectonic!
+        (Updates-Stable V)"}, {"description": "You got 25 or more Fedora Badges",
+        "tags": "community,badges,", "issued": 1423235523.0, "image": "https://badges.fedoraproject.org/pngs/badger-01.5.png",
+        "first_awarded": 1421694162.0, "first_awarded_person": "rhughes", "last_awarded_person":
+        "pcreech17", "last_awarded": 1491432940.0, "percent_earned": 2.3756512446007925,
+        "id": "associate-badger-badger-1.5", "times_awarded": 1067, "name": "Associate
+        Badger (Badger 1.5)"}, {"description": "You attended Flock 2015, the Fedora
+        Contributor Conference", "tags": "conference,rochester,events,flock,flock
+        2015,event,", "issued": 1439318156.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-attendee.png",
+        "first_awarded": 1438119680.0, "first_awarded_person": "decause", "last_awarded_person":
+        "kellin", "last_awarded": 1461547496.0, "percent_earned": 0.18479761321636906,
+        "id": "flock-2015-attendee", "times_awarded": 83, "name": "Flock 2015 Attendee"},
+        {"description": "You''ve been given a cookie for helping someone out.  Thanks!",
+        "tags": "cookie,community,", "issued": 1426702546.0, "image": "https://badges.fedoraproject.org/pngs/macaroncookie.png",
+        "first_awarded": 1426702242.0, "first_awarded_person": "riecatnor", "last_awarded_person":
+        "gtierney", "last_awarded": 1491405719.0, "percent_earned": 1.852429086699025,
+        "id": "macaron-cookie-i", "times_awarded": 832, "name": "Macaron (Cookie I)"},
+        {"description": "Ten people think you''re great, because they''ve given you
+        cookies. Yummy!", "tags": "cookie,community,", "issued": 1426796321.0, "image":
+        "https://badges.fedoraproject.org/pngs/chocolatechipcookie.png", "first_awarded":
+        1426796321.0, "first_awarded_person": "ralph", "last_awarded_person": "mizdebsk",
+        "last_awarded": 1491500198.0, "percent_earned": 0.3606893173620697, "id":
+        "chocolate-chip-cookie-ii", "times_awarded": 162, "name": "Chocolate Chip
+        (Cookie II)"}, {"description": "Voted in the supplemental wallpapers election
+        for the Fedora 22 release", "tags": "election,community,nuancier,", "issued":
+        1426883250.0, "image": "https://badges.fedoraproject.org/pngs/nuancier-f22-voted.png",
+        "first_awarded": 1426835617.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "sarupbanskota", "last_awarded": 1427224635.0, "percent_earned": 0.18257113594870197,
+        "id": "nuancier-f22", "times_awarded": 82, "name": "Nuancier (F22)"}, {"description":
+        "You pinned your country in FAS!", "tags": "account,community,", "issued":
+        1427991763.0, "image": "https://badges.fedoraproject.org/pngs/fas-country.png",
+        "first_awarded": 1427832337.0, "first_awarded_person": "aeperezt", "last_awarded_person":
+        "schwankek", "last_awarded": 1491486520.0, "percent_earned": 17.635926437191078,
+        "id": "origin", "times_awarded": 7921, "name": "Origin"}, {"description":
+        "You added a new package to the distribution.", "tags": "development,", "issued":
+        1377267893.0, "image": "https://badges.fedoraproject.org/pngs/delivery.png",
+        "first_awarded": 1376569056.0, "first_awarded_person": "besser82", "last_awarded_person":
+        "nmilosev", "last_awarded": 1491213323.0, "percent_earned": 0.919535111546511,
+        "id": "delivery", "times_awarded": 413, "name": "Delivery"}, {"description":
+        "You mapped an upstream project to a Fedora package on release-monitoring.org",
+        "tags": "quality,anitya,", "issued": 1430855052.0, "image": "https://badges.fedoraproject.org/pngs/telegraph.png",
+        "first_awarded": 1430855052.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dustymabe", "last_awarded": 1475240820.0, "percent_earned": 0.5655252259874427,
+        "id": "telegraphist-upstream-release-monitoring-i", "times_awarded": 254,
+        "name": "Telegraphist (Upstream Release Monitoring I)"}, {"description": "Mmmmm....
+        cookies. You''ve helped out 25 Fedorans! Go you!", "tags": "cookies,cookie,community,",
+        "issued": 1430923797.0, "image": "https://badges.fedoraproject.org/pngs/blackandwhitecookie.png",
+        "first_awarded": 1430923797.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "dmsimard", "last_awarded": 1491321510.0, "percent_earned": 0.14472102239836132,
+        "id": "black-and-white-cookie-iii", "times_awarded": 65, "name": "Black and
+        White (Cookie III)"}, {"description": "Submitted 250 or more koji builds that
+        failed to build.", "tags": "development,oops,koji,", "issued": 1431713399.0,
+        "image": "https://badges.fedoraproject.org/pngs/koji-what-goes-up-05.png",
+        "first_awarded": 1378300711.0, "first_awarded_person": "ppisar", "last_awarded_person":
+        "smani", "last_awarded": 1485976444.0, "percent_earned": 0.08460613617134968,
+        "id": "hindenburg-koji-failure-v", "times_awarded": 38, "name": "Hindenburg
+        (Koji Failure V)"}, {"description": "Twenty Fedora Badges owe their existence
+        to you.  Prolific!", "tags": "community,badges,", "issued": 1433267989.0,
+        "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_20.png",
+        "first_awarded": 1433267989.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509860.0, "percent_earned": 0.006679431803001291,
+        "id": "badge-muse-badges-released-iv", "times_awarded": 3, "name": "Badge
+        Muse (Badges Released IV)"}, {"description": "Five of your new Fedora Badge
+        ideas were approved and released.  Superb!", "tags": "community,badges,",
+        "issued": 1433268002.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_5.png",
+        "first_awarded": 1423674135.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "pravins", "last_awarded": 1472553692.0, "percent_earned": 0.03562363628267355,
+        "id": "badge-muse-badges-released-ii", "times_awarded": 16, "name": "Badge
+        Muse (Badges Released II)"}, {"description": "Your idea for a new Fedora Badge
+        was approved and released.  Awesome!", "tags": "community,badges,", "issued":
+        1433268014.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved.png",
+        "first_awarded": 1423674153.0, "first_awarded_person": "adamwill", "last_awarded_person":
+        "frantisekz", "last_awarded": 1485462295.0, "percent_earned": 0.10019147704501936,
+        "id": "badge-muse-badges-released-i", "times_awarded": 45, "name": "Badge
+        Muse (Badges Released I)"}, {"description": "Ten of your new Fedora Badge
+        ideas were approved and released.  Impressive!", "tags": "community,badges,",
+        "issued": 1433267996.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_10.png",
+        "first_awarded": 1424466072.0, "first_awarded_person": "gnokii", "last_awarded_person":
+        "jflory7", "last_awarded": 1475509873.0, "percent_earned": 0.013358863606002582,
+        "id": "badge-muse-badges-released-iii", "times_awarded": 6, "name": "Badge
+        Muse (Badges Released III)"}, {"description": "Each unique like a snowflake,
+        fifty of your Fedora Badge ideas were implemented.", "tags": "community,badges,",
+        "issued": 1433268008.0, "image": "https://badges.fedoraproject.org/pngs/badgemuse_approved_50.png",
+        "first_awarded": 1433268008.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ralph", "last_awarded": 1433268008.0, "percent_earned": 0.002226477267667097,
+        "id": "badge-muse-badges-released-v", "times_awarded": 1, "name": "Badge Muse
+        (Badges Released V)"}, {"description": "Beep boop!  You attended the Museum
+        of Play party at the Flock 2015 conference in Rochester!", "tags": "event,flock,",
+        "issued": 1440122051.0, "image": "https://badges.fedoraproject.org/pngs/flock-2015-party.png",
+        "first_awarded": 1439510783.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "kellin", "last_awarded": 1461547520.0, "percent_earned": 0.16921227234269937,
+        "id": "nom-nom-nom", "times_awarded": 76, "name": "Nom Nom Nom"}, {"description":
+        "Successfully completed 60 copr builds", "tags": "development,copr,", "issued":
+        1441220012.0, "image": "https://badges.fedoraproject.org/pngs/copr-build-60.png",
+        "first_awarded": 1389199513.0, "first_awarded_person": "dvratil", "last_awarded_person":
+        "rluzynski", "last_awarded": 1491442095.0, "percent_earned": 1.5763459055083047,
+        "id": "building-the-outer-ring-copr-build-iii", "times_awarded": 708, "name":
+        "Building the Outer Ring (Copr Build III)"}, {"description": "You maintain
+        the Fedora websites.  The Web is yours!", "tags": "web,community,", "issued":
+        1442348476.0, "image": "https://badges.fedoraproject.org/pngs/rock-the-web.png",
+        "first_awarded": 1393598200.0, "first_awarded_person": "sundaram", "last_awarded_person":
+        "dustymabe", "last_awarded": 1491326903.0, "percent_earned": 0.12468272698935744,
+        "id": "rock-the-web!", "times_awarded": 56, "name": "Rock the Web!"}, {"description":
+        "You can speak Python and and you''ve ported at least one package to Python
+        3", "tags": "python,miscellaneous,", "issued": 1447943105.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth.png",
+        "first_awarded": 1438695566.0, "first_awarded_person": "rkuska", "last_awarded_person":
+        "crobinso", "last_awarded": 1491217608.0, "percent_earned": 0.33842454468539873,
+        "id": "parselmouth", "times_awarded": 152, "name": "Parselmouth I"}, {"description":
+        "Edited at least 250 wiki pages.", "tags": "content,wiki,", "issued": 1444762324.0,
+        "image": "https://badges.fedoraproject.org/pngs/wikiedit-250.png", "first_awarded":
+        1409692963.0, "first_awarded_person": "hhorak", "last_awarded_person": "jonatoni",
+        "last_awarded": 1490211890.0, "percent_earned": 0.22710068130204392, "id":
+        "chief-editor", "times_awarded": 102, "name": "Chief Editor"}, {"description":
+        "You''ve had a FAS account for over seven years", "tags": "lifecycle,community,",
+        "issued": 1446001652.0, "image": "https://badges.fedoraproject.org/pngs/fas-account-froglet.png",
+        "first_awarded": 1389060935.0, "first_awarded_person": "jwboyer", "last_awarded_person":
+        "apahim", "last_awarded": 1491360865.0, "percent_earned": 4.628846239479895,
+        "id": "froglet", "times_awarded": 2079, "name": "Froglet"}, {"description":
+        "50 Fedorans have recognized your achievements by giving you cookies.", "tags":
+        "cookie,community,", "issued": 1447693727.0, "image": "https://badges.fedoraproject.org/pngs/pizzellecookie.png",
+        "first_awarded": 1447693727.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "ryanlerch", "last_awarded": 1490719235.0, "percent_earned": 0.03117068174733936,
+        "id": "pizzelle-cookie-iv", "times_awarded": 14, "name": "Pizzelle (Cookie
+        IV)"}, {"description": "You held second place on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452873723.0, "image": "https://badges.fedoraproject.org/pngs/2_badge_340.png",
+        "first_awarded": 1452873723.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "churchyard", "last_awarded": 1475564266.0, "percent_earned": 0.011132386338335486,
+        "id": "silver", "times_awarded": 5, "name": "Silver"}, {"description": "You
+        ranked among the top 10 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875167.0, "image": "https://badges.fedoraproject.org/pngs/10_badge_340.png",
+        "first_awarded": 1452875035.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "fale", "last_awarded": 1489622707.0, "percent_earned": 0.03117068174733936,
+        "id": "top-10", "times_awarded": 14, "name": "Top 10"}, {"description": "You
+        ranked among the top 100 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875191.0, "image": "https://badges.fedoraproject.org/pngs/100_badge_340.png",
+        "first_awarded": 1452875133.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "tflink", "last_awarded": 1480461776.0, "percent_earned": 0.25159193124638196,
+        "id": "top-100", "times_awarded": 113, "name": "Top 100"}, {"description":
+        "You ranked among the top 25 contributors on the Fedora Badges leaderboard",
+        "tags": "meta,community,", "issued": 1452875198.0, "image": "https://badges.fedoraproject.org/pngs/25_badge_340.png",
+        "first_awarded": 1452875140.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "mrunge", "last_awarded": 1490730635.0, "percent_earned": 0.06679431803001291,
+        "id": "top-25", "times_awarded": 30, "name": "Top 25"}, {"description": "You
+        ranked among the top 500 contributors on the Fedora Badges leaderboard", "tags":
+        "meta,community,", "issued": 1452875206.0, "image": "https://badges.fedoraproject.org/pngs/500_badge_340.png",
+        "first_awarded": 1452875147.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "zsun", "last_awarded": 1490677027.0, "percent_earned": 1.2000712472725654,
+        "id": "top-500", "times_awarded": 539, "name": "Top 500"}, {"description":
+        "You visited the Fedora table at BrickHack 2016!", "tags": "brickhack,event,hackathon,events,",
+        "issued": 1457234130.0, "image": "http://infrastructure.fedoraproject.org/infra/badges/pngs/events-brickhack-2016.png",
+        "first_awarded": 1455845197.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "brandondgr8", "last_awarded": 1461299769.0, "percent_earned": 0.05566193169167742,
+        "id": "brickhack-2016-attendee", "times_awarded": 25, "name": "BrickHack 2016
+        Attendee"}, {"description": "You gave a presentation at DevConf.cz, 2016",
+        "tags": "devconf,speaker,event,", "issued": 1455008224.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2016.png",
+        "first_awarded": 1454667336.0, "first_awarded_person": "pbrobinson", "last_awarded_person":
+        "thozza", "last_awarded": 1459500320.0, "percent_earned": 0.2137418176960413,
+        "id": "devconf-2016-speaker", "times_awarded": 96, "name": "DevConf 2016 Speaker"},
+        {"description": "You attended the 2016 iteration of DevConf.cz, a yearly Linux
+        and JBoss conference in the Czech Republic", "tags": "event, devconf,", "issued":
+        1455120228.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-attendee-2016.png",
+        "first_awarded": 1454600601.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "dkaspar", "last_awarded": 1461940547.0, "percent_earned": 0.18925056775170326,
+        "id": "devconf-2016-attendee", "times_awarded": 85, "name": "DevConf 2016
+        Attendee"}, {"description": "You got a \"Change\" accepted into the Fedora
+        24 Change list", "tags": "development,FESCo,process,", "issued": 1458652673.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f24.png", "first_awarded":
+        1458651465.0, "first_awarded_person": "eischmann", "last_awarded_person":
+        "pnemade", "last_awarded": 1459240914.0, "percent_earned": 0.10019147704501936,
+        "id": "fedora-24-change-accepted", "times_awarded": 45, "name": "Fedora 24
+        Change Accepted"}, {"description": "You held third place on the Fedora Badges
+        leaderboard", "tags": "meta,community,", "issued": 1462904993.0, "image":
+        "https://badges.fedoraproject.org/pngs/3_badge_340.png", "first_awarded":
+        1452875229.0, "first_awarded_person": "pnemade", "last_awarded_person": "kevin",
+        "last_awarded": 1489692901.0, "percent_earned": 0.011132386338335486, "id":
+        "bronze", "times_awarded": 5, "name": "Bronze"}, {"description": "You burned
+        a yubikey and linked it with your Fedora Account", "tags": "account,community,",
+        "issued": 1462904755.0, "image": "https://badges.fedoraproject.org/pngs/yubi-badge.png",
+        "first_awarded": 1422906928.0, "first_awarded_person": "plautrba", "last_awarded_person":
+        "findarato", "last_awarded": 1491408410.0, "percent_earned": 0.4052188627154117,
+        "id": "horcrux", "times_awarded": 182, "name": "Horcrux"}, {"description":
+        "You hacked with the Fedora crew at PyCon US 2016", "tags": "event, python,pycon,",
+        "issued": 1464988862.0, "image": "https://badges.fedoraproject.org/pngs/pycon_2016_attendee.png",
+        "first_awarded": 1464988862.0, "first_awarded_person": "ralph", "last_awarded_person":
+        "maxamillion", "last_awarded": 1464991242.0, "percent_earned": 0.028944204479672265,
+        "id": "pycon-2016-attendee", "times_awarded": 13, "name": "PyCon 2016 Attendee"},
+        {"description": "You got 150 Fedora Badges!  Wow!", "tags": "badges,community,",
+        "issued": 1468058613.0, "image": "https://badges.fedoraproject.org/pngs/badger-04.png",
+        "first_awarded": 1457979017.0, "first_awarded_person": "kevin", "last_awarded_person":
+        "pbrobinson", "last_awarded": 1490919191.0, "percent_earned": 0.020038295409003874,
+        "id": "badge-junkie-badger-iv", "times_awarded": 9, "name": "Badge Junkie
+        (Badger IV)"}, {"description": "You can speak Python and and you''ve ported
+        at least five packages to Python 3", "tags": "python,miscellaneous,", "issued":
+        1468058067.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-II.png",
+        "first_awarded": 1467988651.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1488193805.0, "percent_earned": 0.028944204479672265,
+        "id": "parselmouth-ii", "times_awarded": 13, "name": "Parselmouth II"}, {"description":
+        "You can speak Python and and you''ve ported at least ten packages to Python
+        3", "tags": "python,miscellaneous,", "issued": 1468058072.0, "image": "https://badges.fedoraproject.org/pngs/parselmouth-III.png",
+        "first_awarded": 1467997850.0, "first_awarded_person": "cstratak", "last_awarded_person":
+        "ishcherb", "last_awarded": 1489753361.0, "percent_earned": 0.02226477267667097,
+        "id": "parselmouth-iii", "times_awarded": 10, "name": "Parselmouth III"},
+        {"description": "You attended Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,event,events,", "issued": 1470404480.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-attendee.png",
+        "first_awarded": 1468984748.0, "first_awarded_person": "ryanlerch", "last_awarded_person":
+        "adrian", "last_awarded": 1486483875.0, "percent_earned": 0.2360065903727123,
+        "id": "flock-2016-attendee", "times_awarded": 106, "name": "Flock 2016 Attendee"},
+        {"description": "You attended the party at Flock 2016 in Krakow!", "tags":
+        "flock,krakow,event,events,", "issued": 1470404592.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/krakow-brews.png",
+        "first_awarded": 1468963417.0, "first_awarded_person": "duffy", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217490.0, "percent_earned": 0.18257113594870197,
+        "id": "krakow-brews!", "times_awarded": 82, "name": "Krakow Brews!"}, {"description":
+        "You gave a presentation at Flock 2016, the Fedora Contributor Conference",
+        "tags": "flock,speaker,event,", "issued": 1471354751.0, "image": "https://infrastructure.fedoraproject.org/infra/badges/pngs/flock-2016-speaker.png",
+        "first_awarded": 1470941077.0, "first_awarded_person": "mattdm", "last_awarded_person":
+        "kittykat", "last_awarded": 1486217546.0, "percent_earned": 0.19592999955470453,
+        "id": "flock-2016-speaker", "times_awarded": 88, "name": "Flock 2016 Speaker"},
+        {"description": "You''re a member of the Modularity Working Group!", "tags":
+        "modularity,community,", "issued": 1475082397.0, "image": "https://badges.fedoraproject.org/pngs/fas-modularity-wg.png",
+        "first_awarded": 1475082098.0, "first_awarded_person": "asamalik", "last_awarded_person":
+        "jscotka", "last_awarded": 1491213584.0, "percent_earned": 0.0801531816360155,
+        "id": "modularity-wg-member", "times_awarded": 36, "name": "Modularity WG
+        Member"}, {"description": "You got a \"Change\" accepted into the Fedora 26
+        Change list", "tags": "development, FESCo, process,", "issued": 1479749896.0,
+        "image": "https://badges.fedoraproject.org/pngs/changes-f26.png", "first_awarded":
+        1473331018.0, "first_awarded_person": "cstratak", "last_awarded_person": "ncoghlan",
+        "last_awarded": 1489656918.0, "percent_earned": 0.11577681791868906, "id":
+        "fedora-26-change-accepted", "times_awarded": 52, "name": "Fedora 26 Change
+        Accepted"}, {"description": "You gave a presentation at DevConf.cz, 2017",
+        "tags": "speaker,devconf,event,", "issued": 1486037155.0, "image": "https://badges.fedoraproject.org/pngs/dev-conf-presenter-2017.png",
+        "first_awarded": 1486033923.0, "first_awarded_person": "jflory7", "last_awarded_person":
+        "siddharths", "last_awarded": 1486077040.0, "percent_earned": 0.24713897671104776,
+        "id": "devconf-2017-speaker", "times_awarded": 111, "name": "DevConf 2017
+        Speaker"}, {"description": "You have helped so many Fedorans you''ve got over
+        100 cookies. Don''t eat them all at once!", "tags": "cookie,community,", "issued":
+        1486153659.0, "image": "https://badges.fedoraproject.org/pngs/rainbowcookie.png",
+        "first_awarded": 1468278719.0, "first_awarded_person": "puiterwijk", "last_awarded_person":
+        "ralph", "last_awarded": 1486153659.0, "percent_earned": 0.011132386338335486,
+        "id": "rainbow-cookie-v", "times_awarded": 5, "name": "Rainbow (Cookie V)"}],
+        "percent_earned": 41.81818181818181, "user": "ralph"}'}
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=44302106]
+      connection: [Keep-Alive]
+      content-length: ['74203']
+      content-type: [application/json; charset=UTF-8]
+      date: ['Thu, 06 Apr 2017 22:33:37 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_fedmsgstats.TestFedmsgStats.test_data_old b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_fedmsgstats.TestFedmsgStats.test_data_old
new file mode 100644
index 0000000..2c37a30
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_fedmsgstats.TestFedmsgStats.test_data_old
@@ -0,0 +1,247 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        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
+        ubkEsJUZnCGJf/9/FQ8wekRjAQA=
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=8742172]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 21 Jan 2016 20:30:43 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_fedmsgstats.TestFedmsgStats.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_fedmsgstats.TestFedmsgStats.test_data_simple
new file mode 100644
index 0000000..8f957b0
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_fedmsgstats.TestFedmsgStats.test_data_simple
@@ -0,0 +1,247 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        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
+        ubkEsJUZnCGJf/9/FQ8wekRjAQA=
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=1554107]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 21 Jan 2016 20:32:22 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_fedmsgstats.TestFedmsgStats.test_view_authz b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_fedmsgstats.TestFedmsgStats.test_view_authz
new file mode 100644
index 0000000..0681d72
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_fedmsgstats.TestFedmsgStats.test_view_authz
@@ -0,0 +1,1051 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy11.fedoraproject.org]
+      apptime: [D=260670723]
+      connection: [close]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:43:06 GMT']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=5811152]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:28 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?user=ralph
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=2388762]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:34 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpFunctionsTestCase.test_execute b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpFunctionsTestCase.test_execute
new file mode 100644
index 0000000..1e03fdc
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpFunctionsTestCase.test_execute
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=630853]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 18:26:01 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data
new file mode 100644
index 0000000..4d48985
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data
@@ -0,0 +1,194 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=634315]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4028']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 18:58:53 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=583692]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4027']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:24:03 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub
new file mode 100644
index 0000000..6b0a36a
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy02.fedoraproject.org]
+      apptime: [D=886956]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:28:42 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_all b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_all
new file mode 100644
index 0000000..dfd7580
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_all
@@ -0,0 +1,194 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy11.fedoraproject.org]
+      apptime: [D=574648]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:53:38 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=684600]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4028']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 21:58:21 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_date b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_date
new file mode 100644
index 0000000..49d31ac
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_date
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=560197]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:51:05 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_hub b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_hub
new file mode 100644
index 0000000..c2ca0a7
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_hub
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=461727]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:51:07 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_meetingname b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_meetingname
new file mode 100644
index 0000000..07ed82f
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_meetingname
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=621781]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:36:08 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_people b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_people
new file mode 100644
index 0000000..d3b8371
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_people
@@ -0,0 +1,98 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=474498]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 19:28:44 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_requesters b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_requesters
new file mode 100644
index 0000000..cd075ec
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_requesters
@@ -0,0 +1,194 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=642014]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4029']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 22:29:51 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      appserver: [proxy06.fedoraproject.org]
+      apptime: [D=442751]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['4028']
+      content-type: [application/json]
+      date: ['Wed, 22 Mar 2017 22:34:13 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_meetings.TestMeetings.test_data_simple b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_meetings.TestMeetings.test_data_simple
new file mode 100644
index 0000000..c896aa4
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_meetings.TestMeetings.test_data_simple
@@ -0,0 +1,43 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.7.0 CPython/2.7.10 Linux/4.3.3-300.fc23.x86_64]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=i18n
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA+2ZTW/bIBiA/8ornzYp2IZ8NqdpO+3QnTYp1TpFzH6TstoQYdJqi/LfB20aEdYd
+        Jk1wQcIH8/XwvjySkTkUPaIRcjsUS/h6eHlbG9HjejBcG1tf1LNlXdtSjODcQ7S2hV5Nar9ObpTu
+        uRFKumHvBXlEvO9+wqkD2GYQdCFBY8cNttCKodkPgx0wlLf6VrrnWmkEbyrgD1x0/HuHwM0S7ozZ
+        Dcuq2mCrNN9p9QMbUyq9rR7Fvag+0sWn6voUVMVqOiGrFbm5AYA3qxUQ6JU0dyOwNQRau4jyrQur
+        4R3Kluu15D26xbtl+vGeMqJ2TwmZ/5kQN9fazuHaLXZKKCNs7PfoVHPOzfPqyanpndBNudGIUrVY
+        SjT+sJ5LvkXtNqjYaf4g5FB8C8B/h/rxvOxDGNcvJZ/6fPn8oTiOIGvw/zSYkZqSehZXg1egWYP0
+        GrA6gQaX0KxBag0YqSN/FF6BZg3Sa0DnCTS4hGYNUmswtpsSXYMQmjVIrwGNf0QMoVmD9BqM4x8R
+        Q2jWILUGE0LjHxFDaNYgvQYs/hExhGYNUmswJZRG1yCEZg3Sa8CmCTS4hGYNUmtgyyK6BiE0a5Be
+        Axb/v0EIzRqk1mCe4mophP6zBm5qrrf7HqVx986H4uzB+Q6T+SnzsxXET69cpRe33Hfd8fgbBWYL
+        WtgeAAA=
+    headers:
+      accept-ranges: [bytes]
+      age: ['0']
+      appserver: [proxy12.fedoraproject.org]
+      apptime: [D=179808]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['518']
+      content-type: [application/json]
+      date: ['Thu, 21 Jan 2016 20:50:48 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.CYLWKA._XkgyD4SujeEkonmfv7CP91G1mM;
+          Expires=Thu, 21-Jan-2016 21:50:48 GMT; Secure; HttpOnly; Path=/calendar']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+      via: [1.1 varnish-v4]
+      x-varnish: ['22710494']
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_meetings.TestMeetings.test_render_simple b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_meetings.TestMeetings.test_render_simple
new file mode 100644
index 0000000..32812c9
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_meetings.TestMeetings.test_render_simple
@@ -0,0 +1,43 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=i18n
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA+3Zz2/bIBQH8H/lyadNCrZx82s5Teuph/bUSanWKWL2S8pqQ4RJqy3K/z7I0ogw
+        7TBp8rsgxYcA5svDH3Gw91mHaKXa9NkCvuzf/q2s7HDVW2Gsa8/K6aIs3S8bwXmEbFzPhE+qsE2t
+        temElVr52z5J9or43P6A0wBw3SD5XIHBVlhsoJF9vet7d0OfP5pH5a9bbRCCqUC8CNmKby2CsAt4
+        snbbL4pijY02Ymv0d6xtrs2meJXPsrjh87vi9lRUUZV8zJZL9vAAAO+WS2DQaWWfRuBaGDRuEfl7
+        X1YtWlSNMCslOvSL98sM6z3tiN4eN2T254b4uVZuDt/vYmes5KwchyNaXZ/35vfq2anrozR1vjaI
+        SjeYK7ThbZ1QYoPGP6Bsa8SLVH32NQr+e2hYz9tziOv6qdVxzOf76+wwgsTgPzPgcwIGl6GJATWD
+        yj2UwRnEoYkBPQM+IWBwGZoYUDO4ojgN4tDEgJ4BwWkQhyYG9AyqDwQMLkMTA2oGY8arwRnEoYkB
+        PYNqSsDgMjQxoGYwYbwcnEEcmhjQM6iGf4sYhyYG1AymrJwNziAOTQzoGVTDvzeIQxMDagb+iB6c
+        QRyaGNAz4MO/N4hD/5mBn1qYza5DZf135312dnD+hlmFWxbuVlT/1fFgCupWu7Y9HH4Bm4DFHNge
+        AAA=
+    headers:
+      Accept-Ranges: [bytes]
+      Age: ['0']
+      AppServer: [proxy04.fedoraproject.org]
+      AppTime: [D=176951]
+      Connection: [Keep-Alive]
+      Content-Encoding: [gzip]
+      Content-Length: ['515']
+      Content-Type: [application/json]
+      Date: ['Wed, 01 Feb 2017 08:36:43 GMT']
+      Keep-Alive: ['timeout=15, max=500']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      Set-Cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C3Mvmw.rzQ95C3LVBlZJKMEJVpzih4SIT4;
+          Expires=Wed, 01-Feb-2017 09:36:43 GMT; Secure; HttpOnly; Path=/calendar']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+      Vary: [Accept-Encoding]
+      Via: [1.1 varnish-v4]
+      X-Varnish: ['1754049']
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_meetings.TestMeetings.test_view_authz b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_meetings.TestMeetings.test_view_authz
new file mode 100644
index 0000000..ec0fd82
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_meetings.TestMeetings.test_view_authz
@@ -0,0 +1,304 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=Fedora%20release
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      accept-ranges: [bytes]
+      age: ['0']
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=466769]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:43 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C8hXEA.J-L3Q3D5WaWNhP3xXPbEcZs4hBU;
+          Expires=Thu, 06-Apr-2017 23:47:44 GMT; Secure; HttpOnly; Path=/calendar']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+      via: [1.1 varnish-v4]
+      x-varnish: ['14164337']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=Fedora%20release
+  response:
+    body:
+      string: !!binary |
+        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
+    headers:
+      accept-ranges: [bytes]
+      age: ['0']
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=422626]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-length: ['3975']
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:44 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C8hXEQ.l-i-NQ-NFV7tfhfpF_Pjr_6LWaM;
+          Expires=Thu, 06-Apr-2017 23:47:45 GMT; Secure; HttpOnly; Path=/calendar']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+      via: [1.1 varnish-v4]
+      x-varnish: ['14488870']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://apps.fedoraproject.org/calendar/api/meetings/?calendar=Fedora%20release
+  response:
+    body:
+      string: !!binary |
+        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
+        AMTKs+Vs2AAA
+    headers:
+      accept-ranges: [bytes]
+      age: ['0']
+      appserver: [proxy04.fedoraproject.org]
+      apptime: [D=525518]
+      connection: [Keep-Alive]
+      content-encoding: [gzip]
+      content-type: [application/json]
+      date: ['Thu, 06 Apr 2017 22:47:45 GMT']
+      keep-alive: ['timeout=15, max=500']
+      server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      set-cookie: ['fedocal=eyJfcGVybWFuZW50Ijp0cnVlfQ.C8hXEg.iAM2PfVJ078Ph-buEOa2ztll9hk;
+          Expires=Thu, 06-Apr-2017 23:47:46 GMT; Secure; HttpOnly; Path=/calendar']
+      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
+      vary: [Accept-Encoding]
+      via: [1.1 varnish-v4]
+      x-varnish: ['14164340']
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/views/__init__.py b/hubs/tests/views/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/tests/views/__init__.py
diff --git a/hubs/tests/views/test_api.py b/hubs/tests/views/test_api.py
new file mode 100644
index 0000000..abf1e3d
--- /dev/null
+++ b/hubs/tests/views/test_api.py
@@ -0,0 +1,151 @@
+from __future__ import unicode_literals
+
+from six.moves.urllib.parse import urlparse
+
+import hubs.tests
+import hubs.models
+from hubs.app import app
+
+
+def usernames(collection): return [u.username for u in collection]
+
+
+class TestHubSubscribe(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_subscribe_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_subscribe_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
+                                 follow_redirects=True)
+            self.assertEqual(resp.status_code, 200)
+            # Need to find the Hub again to avoid DetachedInstanceError
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.username in usernames(h.subscribers))
+
+
+class TestHubUnsubscribe(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_unsubscribe_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_unsubscribe_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        # Need a real user model to subscribe to the hub
+        User = hubs.models.User.by_username(self.user.username)
+        hub.subscribe(User)
+
+        self.assertTrue(self.user.username in usernames(hub.subscribers))
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
+                                 follow_redirects=True)
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.username not in usernames(h.subscribers))
+
+
+class TestHubStar(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_star_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hub/{}/star'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_star_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/star'.format(hub.name),
+                                 follow_redirects=True)
+
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.username in usernames(h.stargazers))
+
+
+class TestHubUnstar(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_unstar_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_unstar_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        # Need a real user model to subscribe to the hub
+        User = hubs.models.User.by_username(self.user.username)
+        hub.subscribe(User, role='stargazer')
+
+        self.assertTrue(self.user.username in [u.username for
+                                               u in hub.stargazers])
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
+                                 follow_redirects=True)
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.username not in usernames(h.stargazers))
+
+
+class TestHubJoin(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_join_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hub/{}/join'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_join_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/join'.format(hub.name),
+                                 follow_redirects=True)
+
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.username in usernames(h.members))
+
+
+class TestHubLeave(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_leave_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_star_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        # Need a real user model to subscribe to the hub
+        User = hubs.models.User.by_username(self.user.username)
+        hub.subscribe(User, role='member')
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
+                                 follow_redirects=True)
+
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.username not in usernames(h.members))
diff --git a/hubs/tests/views/test_hub_config.py b/hubs/tests/views/test_hub_config.py
new file mode 100644
index 0000000..9b66b03
--- /dev/null
+++ b/hubs/tests/views/test_hub_config.py
@@ -0,0 +1,166 @@
+from __future__ import unicode_literals
+
+from flask import json
+
+from hubs.app import app
+from hubs.models import Hub, HubConfig, User
+from hubs.tests import APPTest, FakeAuthorization, auth_set
+
+
+class HubConfigTestCase(APPTest):
+
+    def test_hub_config_get(self):
+        expected = {
+            "hubconfig": {
+                "summary": "Ralph",
+                "left_width": 8,
+                "avatar": (
+                    "https://seccdn.libravatar.org/avatar/9c9f7784935381befc30"
+                    "2fe3c814f9136e7a33953d0318761669b8643f4df55c"
+                    "?s=312&d=retro"
+                    ),
+                "chat_channel": None,
+                "chat_domain": None,
+                "visibility": "public",
+            },
+            "general": {
+                "chat_networks": app.config["CHAT_NETWORKS"],
+                "roles": ["owner", "member"],
+                "hub_visibility": HubConfig.VISIBILITY,
+            },
+            "users": {
+                "member": [],
+                "owner": [{
+                    "fullname": "Ralph",
+                    "locked": True,
+                    "role": "owner",
+                    "username": "ralph",
+                }],
+            },
+        }
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            url = '/ralph/config'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertDictEqual(result_data["result"], expected)
+
+    def test_hub_config_post(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            url = '/ralph/config?category=config'
+            result = self.app.post(url, data={
+                "summary": "changed value",
+                "chat_domain": "",
+            })
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertEqual(
+            result_data["result"]["hubconfig"]["summary"],
+            "changed value")
+        self.assertEqual(
+            result_data["result"]["hubconfig"]["chat_domain"],
+            app.config["CHAT_NETWORKS"][0]["domain"])
+
+    def test_hub_config_post_unknown_post_data(self):
+        # Unknown POST data is silently ignored
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            url = '/ralph/config?category=config'
+            result = self.app.post(url, data={"non_existant": "dummy"})
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "ERROR")
+        self.assertEqual(result_data["message"], "Invalid value(s)")
+        self.assertIn("non_existant", result_data["fields"])
+        self.assertEqual(
+            result_data["fields"]["non_existant"],
+            "Unexpected parameter."
+            )
+
+    def test_hub_config_post_invalid_chat_domain(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            url = '/ralph/config?category=config'
+            result = self.app.post(url, data={"chat_domain": "dummy"})
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "ERROR")
+        self.assertEqual(result_data["message"], "Invalid value(s)")
+        self.assertIn("chat_domain", result_data["fields"])
+        self.assertEqual(
+            result_data["fields"]["chat_domain"],
+            "Unsupported chat domain."
+            )
+
+    def test_hub_config_get_unauthorized(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            url = '/decause/config'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 403)
+
+    def test_hub_config_post_unauthorized(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            url = '/decause/config?category=config'
+            result = self.app.post(url, data={"summary": "Defaced!"})
+        self.assertEqual(result.status_code, 403)
+
+    def test_hub_config_suggest_users_no_filter(self):
+        user = FakeAuthorization('ralph')
+        expected = [
+            u.username for u in
+            User.query.order_by(User.username).all()
+            ]
+        # Check without filter
+        with auth_set(app, user):
+            url = '/ralph/config/suggest-users'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertListEqual(result_data["results"], expected)
+
+    def test_hub_config_suggest_users_filter_owners(self):
+        # Filters on owners
+        user = FakeAuthorization('ralph')
+        expected = [
+            u.username for u in
+            User.query.order_by(User.username).filter(
+                User.username != "ralph").all()
+            ]
+        with auth_set(app, user):
+            url = '/ralph/config/suggest-users?exclude-role=owner'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertListEqual(result_data["results"], expected)
+
+    def test_hub_config_suggest_users_filter_members(self):
+        # Filters on members
+        user = FakeAuthorization('ralph')
+        hub = Hub.get('ralph')
+        decause = User.query.get("decause")
+        devyani7 = User.query.get("devyani7")
+        hub.subscribe(decause, "member")
+        hub.subscribe(devyani7, "member")
+        expected = [
+            u.username for u in
+            User.query.order_by(
+                User.username
+            ).filter(
+                User.username != "decause",
+                User.username != "devyani7"
+            ).all()]
+        with auth_set(app, user):
+            url = '/ralph/config/suggest-users?exclude-role=member'
+            result = self.app.get(url)
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertListEqual(result_data["results"], expected)
diff --git a/hubs/tests/views/test_hub_edit.py b/hubs/tests/views/test_hub_edit.py
new file mode 100644
index 0000000..2ff727e
--- /dev/null
+++ b/hubs/tests/views/test_hub_edit.py
@@ -0,0 +1,114 @@
+from __future__ import unicode_literals
+
+from six.moves.urllib.parse import urlparse
+from werkzeug.datastructures import ImmutableMultiDict
+
+from hubs.app import app
+from hubs.tests import APPTest, FakeAuthorization, auth_set
+
+
+class HubEditTestCase(APPTest):
+
+    def test_hub_edit_get_logged_out(self):
+        with auth_set(app, None):
+            result = self.app.get('/ralph/edit', follow_redirects=False)
+        self.assertEqual(result.status_code, 302)
+        self.assertEqual(urlparse(result.location).path, "/login")
+
+    def test_hub_edit_get_logged_in_not_owner(self):
+        user = FakeAuthorization('not_ralph')
+        with auth_set(app, user):
+            result = self.app.get('/ralph/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)
+
+    def test_hub_edit_get_logged_in_owner(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/ralph/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+
+    def test_hub_edit_post_logged_out(self):
+        with auth_set(app, None):
+            result = self.app.post('/ralph/edit', follow_redirects=False)
+        self.assertEqual(result.status_code, 302)
+        self.assertEqual(urlparse(result.location).path, "/login")
+
+    def test_hub_edit_post_logged_in_not_owner(self):
+        user = FakeAuthorization('not_ralph')
+        with auth_set(app, user):
+            result = self.app.post('/ralph/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)
+
+    def test_hub_edit_post_logged_in_owner_empty_data(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.post('/ralph/edit', data={},
+                                   follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            self.assertNotIn(
+                'Not logged in.  Click to <a href="/login">login</a>',
+                result.get_data(as_text=True))
+            self.assertIn(
+                '<a href="#" class="dropdown-item">Full Name: '
+                'fullname: ralph</a>', result.get_data(as_text=True))
+
+    def test_hub_edit_post_logged_in_owner_valid_data(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            data = ImmutableMultiDict(
+                [('right_indexes[]', u'0'), ('right_indexes[]', u'1'),
+                 ('right_indexes[]', u'2'), ('right_indexes[]', u'3'),
+                 ('right_indexes[]', u'4'), ('right_indexes[]', u'5'),
+                 ('right_indexes[]', u'6'), ('right_indexes[]', u'7'),
+                 ('right_indexes[]', u'8'), ('right_widgets[]', u'32'),
+                 ('right_widgets[]', u'33'), ('right_widgets[]', u'34'),
+                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
+                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
+                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
+                 ('js', u'true'), ('left_indexes[]', u'0'),
+                 ('left_indexes[]', u'1'), ('left_widgets[]', u'31'),
+                 ('left_widgets[]', u'32')])
+            result = self.app.post('/ralph/edit', data=data,
+                                   follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            self.assertEqual(result.get_data(as_text=True), 'ok')
+
+    def test_hub_edit_post_logged_in_owner_invalid_data_1(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            # some indexes and widgets are not integers
+            data = ImmutableMultiDict(
+                [('right_indexes[]', u'0a'), ('right_indexes[]', u'1'),
+                 ('right_indexes[]', u'2'), ('right_indexes[]', u'3'),
+                 ('right_indexes[]', u'4'), ('right_indexes[]', u'5'),
+                 ('right_indexes[]', u'6'), ('right_indexes[]', u'7'),
+                 ('right_indexes[]', u'8'), ('right_widgets[]', u'32'),
+                 ('right_widgets[]', u'33a'), ('right_widgets[]', u'34'),
+                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
+                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
+                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
+                 ('js', u'true'), ('left_indexes[]', u'0a'),
+                 ('left_indexes[]', u'1'), ('left_widgets[]', u'31a'),
+                 ('left_widgets[]', u'32')])
+            result = self.app.post('/ralph/edit', data=data,
+                                   follow_redirects=True)
+            self.assertEqual(result.status_code, 400)
+
+    def test_hub_edit_post_logged_in_owner_invalid_data_2(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            # indexes len don't match widgets len
+            data = ImmutableMultiDict(
+                [('right_indexes[]', u'1'), ('right_indexes[]', u'2'),
+                 ('right_indexes[]', u'3'), ('right_indexes[]', u'4'),
+                 ('right_indexes[]', u'5'), ('right_indexes[]', u'6'),
+                 ('right_indexes[]', u'7'), ('right_indexes[]', u'8'),
+                 ('right_widgets[]', u'32'), ('right_widgets[]', u'34'),
+                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
+                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
+                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
+                 ('js', u'true'), ('left_indexes[]', u'0'),
+                 ('left_indexes[]', u'1'), ('left_widgets[]', u'32')])
+            result = self.app.post('/ralph/edit', data=data,
+                                   follow_redirects=True)
+            self.assertEqual(result.status_code, 400)
diff --git a/hubs/tests/views/test_hub_view.py b/hubs/tests/views/test_hub_view.py
new file mode 100644
index 0000000..f82127c
--- /dev/null
+++ b/hubs/tests/views/test_hub_view.py
@@ -0,0 +1,91 @@
+from __future__ import unicode_literals
+
+from flask import json
+
+from hubs.app import app
+from hubs.models import Hub
+from hubs.tests import APPTest, FakeAuthorization, auth_set
+
+
+class HubViewTestCase(APPTest):
+
+    def test_hub_logged_out(self):
+        with auth_set(app, None):  # check_auth doesn't load in unittest
+            result = self.app.get('/ralph', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            match_expected = r'<h5[^>]*>Ralph</h5>'
+            self.assertRegexpMatches(
+                result.get_data(as_text=True), match_expected)
+            str_expected = 'Not logged in.'
+            self.assertIn(str_expected, result.get_data(as_text=True))
+
+    def test_hub_logged_in(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/ralph', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            self.assertNotIn(
+                'Not logged in.  Click to <a href="/login">login</a>',
+                result.get_data(as_text=True))
+
+    def test_hub_preview(self):
+        hub = Hub.by_name('ralph')
+        hub.config.visibility = "preview"
+        # Preview hubs are accessible to anonymous users (but some
+        # widgets may be restricted).
+        with auth_set(app, None):
+            result = self.app.get('/ralph', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+
+    def test_hub_private(self):
+        hub = Hub.by_name('ralph')
+        hub.config.visibility = "private"
+        self.session.commit()
+        # Private hubs are not accessible to anonymous users.
+        with auth_set(app, None):
+            result = self.app.get('/ralph', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)
+        # But they are accessible to members.
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/ralph', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+
+    def test_hub_json(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/ralph/json', follow_redirects=True)
+        # assert the status code of the response
+        self.assertEqual(result.status_code, 200)
+        data = {
+            "config": {
+                "avatar": "https://seccdn.libravatar.org/avatar/"
+                          "9c9f7784935381befc302fe3c814f9136e7a339"
+                          "53d0318761669b8643f4df55c?s=312&d=retro",
+                'chat_channel': None,
+                'chat_domain': None,
+                "left_width": 8,
+                "summary": "Ralph",
+                "visibility": "public",
+            },
+            "members": ["ralph"],
+            "name": "ralph",
+            "owners": ["ralph"],
+            "subscribers": [],
+            "widgets": [37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 61],
+        }
+        self.assertDictEqual(data, json.loads(result.get_data(as_text=True)))
+
+    def test_hub_private_json(self):
+        hub = Hub.by_name('ralph')
+        hub.config.visibility = "private"
+        self.session.commit()
+        # Private hubs are not accessible to anonymous users.
+        with auth_set(app, None):
+            result = self.app.get('/ralph/json', follow_redirects=True)
+            self.assertEqual(result.status_code, 403)
+        # But they are accessible to members.
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/ralph/json', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
diff --git a/hubs/tests/views/test_hub_widgets.py b/hubs/tests/views/test_hub_widgets.py
new file mode 100644
index 0000000..bef72bb
--- /dev/null
+++ b/hubs/tests/views/test_hub_widgets.py
@@ -0,0 +1,138 @@
+from __future__ import unicode_literals
+
+from flask import json
+from six.moves.urllib.parse import urlparse
+
+from hubs.app import app
+from hubs.models import Hub, Widget
+from hubs.tests import APPTest, FakeAuthorization, auth_set
+
+
+class HubWidgetsTestCase(APPTest):
+
+    def test_hub_add_widget_get_no_args(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/ralph/add', follow_redirects=False)
+        self.assertEqual(result.status_code, 400)
+        expected_str = 'Invalid position provided'
+        self.assertIn(expected_str, result.get_data(as_text=True))
+
+    def test_hub_add_widget_get_with_args(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/ralph/add?position=right',
+                                  follow_redirects=True)
+        self.assertEqual(result.status_code, 200)
+        page_html = result.get_data(as_text=True)
+        self.assertIn('Adding a widget to hub: ralph', page_html)
+        self.assertIn('<form method="post" action="/ralph/add">', page_html)
+        self.assertIn('<input type="hidden" name="position" value="right" />',
+                      page_html)
+
+    def test_hub_add_widget_post_no_widget_name(self):
+        data = {"position": "left"}
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.post(
+                '/ralph/add', data=data, follow_redirects=False)
+        self.assertEqual(result.status_code, 400)
+        expected_str = 'Invalid request sent'
+        self.assertIn(expected_str, result.get_data(as_text=True))
+
+    def test_hub_add_widget_post_invalid_widget_name(self):
+        data = {'widget': 'invalid_widget_name',
+                'position': 'right'}
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.post(
+                '/ralph/add', data=data, follow_redirects=False)
+        self.assertEqual(result.status_code, 404)
+        expected_str = 'Unknown widget called'
+        self.assertIn(expected_str, result.get_data(as_text=True))
+
+    def test_hub_add_widget_post_valid_widget_name_no_args(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            data = {
+                'widget': 'memberships',
+                'position': 'right',
+                }
+            result = self.app.post('/ralph/add', data=data)
+            self.assertEqual(result.status_code, 200)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"status": "ADDED"})
+            result = self.app.get('/ralph/edit')
+            self.assertEqual(result.status_code, 200)
+            page_html = result.get_data(as_text=True)
+            self.assertIn('data-url="/ralph/w/memberships/', page_html)
+
+    def test_hub_add_widget_post_valid_widget_name_with_args(self):
+        self.assertEqual(
+            Widget.query.filter(
+                Hub.name == "ralph",
+                Widget.plugin == "about",
+            ).count(), 1)
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            data = {
+                'text': 'text of widget',
+                'position': 'right',
+                }
+            result = self.app.post('/ralph/add/about', data=data,
+                                   follow_redirects=False)
+            self.assertEqual(result.status_code, 200)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"status": "ADDED"})
+            self.assertEqual(
+                Widget.query.filter(
+                    Hub.name == "ralph",
+                    Widget.plugin == "about",
+                ).count(), 2)
+
+    def test_hub_edit_widget_get_logged_in(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/ralph/37/edit', follow_redirects=True)
+            self.assertEqual(result.status_code, 200)
+            expected_str = '/ralph/37/edit'
+            self.assertIn(expected_str, result.get_data(as_text=True))
+
+    def test_hub_edit_widget_get_logged_out(self):
+        result = self.app.get('/ralph/31/edit', follow_redirects=False)
+        self.assertEqual(result.status_code, 302)
+        self.assertEqual(urlparse(result.location).path, "/login")
+
+    def test_hub_edit_widget_post_empty_data_logged_in(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            data = {}
+            url = '/ralph/37/edit'
+            result = self.app.post(url, data=data, follow_redirects=False)
+            self.assertEqual(result.status_code, 302)
+            self.assertEqual(urlparse(result.location).path, '/ralph/edit')
+
+    def test_hub_add_widget_valid_side(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            url = '/ralph/add/about?position=right'
+            result = self.app.get(url)
+            self.assertIn('Adding widget "about" to hub ralph',
+                          result.get_data(as_text=True))
+
+    def test_hub_add_widget_invalid_side(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            url = '/ralph/add/about?position=invalid'
+            result = self.app.get(url)
+            self.assertEqual(result.status_code, 400)
+
+    def test_hub_delete(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            url = '/ralph/37/delete'  # 37 is widget fedmsgstats for ralph
+            result = self.app.post(url)
+            self.assertEqual(result.status_code, 302)
+            self.assertIn('/ralph/edit', result.get_data(as_text=True))
diff --git a/hubs/tests/views/test_root.py b/hubs/tests/views/test_root.py
new file mode 100644
index 0000000..b34e9c0
--- /dev/null
+++ b/hubs/tests/views/test_root.py
@@ -0,0 +1,50 @@
+from __future__ import unicode_literals
+
+from six.moves.urllib.parse import urlparse
+
+from hubs.app import app
+from hubs.tests import APPTest, FakeAuthorization, auth_set
+
+
+class RootTestCase(APPTest):
+
+    def test_index_logged_out(self):
+        result = self.app.get('/', follow_redirects=False)
+        self.assertEqual(result.status_code, 302)
+        self.assertEqual(urlparse(result.location).path, "/login")
+
+    def test_index_logged_in(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/', follow_redirects=True)
+            # its trying to redirect to login id.fedoraproject.org/openid
+            # assert the status code of the response
+            self.assertEqual(result.status_code, 200)
+            self.assertNotIn(
+                'Not logged in.  Click to <a href="/login">login</a>',
+                result.get_data(as_text=True))
+
+    def test_login_already_loggedin(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/login', follow_redirects=False)
+            self.assertEqual(result.status_code, 302)
+            self.assertEqual(
+                urlparse(result.location).path,
+                "/openidc/Authorization")
+
+    def test_groups_logged_out(self):
+        result = self.app.get('/groups', follow_redirects=False)
+        # assert the status code of the response
+        self.assertEqual(result.status_code, 302)
+        # this will redirect to fedora.login
+        self.assertEqual(urlparse(result.location).path, "/login")
+
+    def test_groups_logged_in(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.get('/groups', follow_redirects=True)
+            # assert the status code of the response
+            self.assertEqual(result.status_code, 200)
+            self.assertIn("ZOMG -  is the Hub Of The Month!",
+                          result.get_data(as_text=True))
diff --git a/hubs/tests/views/test_user.py b/hubs/tests/views/test_user.py
new file mode 100644
index 0000000..a31a782
--- /dev/null
+++ b/hubs/tests/views/test_user.py
@@ -0,0 +1,173 @@
+from __future__ import unicode_literals
+
+import json
+import unittest
+
+import hubs.tests
+import hubs.models
+from hubs.app import app
+
+
+class TestGetNotifications(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('ralph')
+
+    def test_get_notifications_invalid_name(self):
+        name = 'notarealfasuser'
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.get('/{}/notifications/'.format(name))
+        self.assertEqual(resp.status_code, 200)
+        data = json.loads(resp.get_data(as_text=True))
+        self.assertEqual(data, {"notifications": []})
+
+    def test_get_notifications_valid_name(self):
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.get('/{}/notifications/'.format(
+                self.user.username))
+
+        self.assertEqual(resp.status_code, 200)
+        data = json.loads(resp.get_data(as_text=True))
+        self.assertEqual(len(data["notifications"]), 1)
+
+        for saved in data["notifications"]:
+            self.assertEqual(saved['markup'], 'foo')
+            self.assertEqual(saved['link'], 'bar')
+
+
+class TestPostNotifications(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('ralph')
+    valid_payload = {
+        'username': user.username,
+        'markup': 'foobar',
+        'link': 'baz',
+        'secondary_icon': 'http://placekitten.com/g/200/300',
+        'dom_id': 'reallyuniqueuid'
+    }
+
+    invalid_payload = {
+        'username': user.username,
+    }
+
+    def test_post_notification_invalid_user(self):
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post(
+                '/{}/notifications/'.format('notarealfasuser'),
+                data=json.dumps(self.valid_payload),
+                content_type='application/json')
+        self.assertEqual(resp.status_code, 400)
+
+    def test_post_notification_invalid_payload(self):
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post(
+                '/{}/notifications/'.format(self.user.username),
+                data=json.dumps(self.invalid_payload),
+                content_type='application/json')
+        self.assertEqual(resp.status_code, 400)
+
+    def test_post_notification_valid_payload(self):
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post(
+                '/{}/notifications/'.format(self.user.username),
+                data=json.dumps(self.valid_payload),
+                content_type='application/json')
+
+        self.assertEqual(resp.status_code, 200)
+        data = json.loads(resp.get_data(as_text=True))
+        self.assertTrue(isinstance(data, dict))
+
+        notification = data['notification']
+        self.assertEqual(notification['markup'], 'foobar')
+        self.assertEqual(notification['link'], 'baz')
+
+        all_saved = hubs.models.SavedNotification.by_username(
+            self.user.username)
+        self.assertEqual(len(all_saved), 2)
+        all_saved = [s.__json__() for s in all_saved]
+        self.assertTrue(any(str(s['markup']) == self.valid_payload['markup']
+                            for s in all_saved))
+        self.assertTrue(any(str(s['link']) == self.valid_payload['link']
+                            for s in all_saved))
+
+
+class TestDeleteNotifications(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('ralph')
+    notification = hubs.models.SavedNotification(
+        username='ralph',
+        markup='foo',
+        link='bar',
+        secondary_icon='baz',
+        dom_id='qux'
+    )
+
+    def test_delete_notification(self):
+        self.session.add(self.notification)
+        self.session.commit()
+        idx = self.notification.idx
+
+        self.assertIsNotNone(self.notification)
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.delete(
+                '/{}/notifications/{}/'.format(self.user.username, idx)
+            )
+
+        self.assertEqual(resp.status_code, 200)
+        notification = self.session.query(
+            hubs.models.SavedNotification).filter_by(idx=idx).first()
+
+        self.assertIsNone(notification)
+
+    def test_404_on_bad_idx(self):
+        idx = 'thisisastringnotanint'
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.delete(
+                '/{}/notifications/{}/'.format(self.user.username, idx)
+            )
+        self.assertEqual(resp.status_code, 404)
+
+
+class TestHubVisits(hubs.tests.APPTest):
+
+    def test_hub_visit_counter_logged_in(self):
+        user = hubs.tests.FakeAuthorization('ralph')
+        with hubs.tests.auth_set(app, user):
+            url = '/visit/decause'
+            result = self.app.get(url)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"count": 0})
+
+            result = self.app.post(url)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                {"count": 1})
+
+            # accessing my hub shouldn't increment the count
+            url = 'visit/ralph'
+            result = self.app.post(url)
+            self.assertEqual(result.status_code, 403)
+
+            # visiting no hub while logged should throw a 405
+            url = 'visit/'
+            result = self.app.post(url)
+            self.assertEqual(result.status_code, 405)
+
+            # visiting a hub that doesn't exist should 404
+            url = 'visit/hub-does-not-exist'
+            result = self.app.post(url)
+            self.assertEqual(result.status_code, 404)
+
+    @unittest.skip("Ajax calls don't seem to work in unittests ")
+    def test_hub_vist_counter_logged_in_2(self):
+        user = hubs.tests.FakeAuthorization('ralph')
+        with hubs.tests.auth_set(app, user):
+            url = '/visit/decause'
+            result = self.app.get(url)
+            self.assertEqual(result.get_data(as_text=True), '0')
+
+            url = '/decause'
+            result = self.app.get(url, follow_redirects=True)
+
+            url = '/visit/decause'
+            result = self.app.get(url)
+            self.assertEqual(result.get_data(as_text=True), '1')
diff --git a/hubs/tests/views/test_widget.py b/hubs/tests/views/test_widget.py
new file mode 100644
index 0000000..7a8d2f7
--- /dev/null
+++ b/hubs/tests/views/test_widget.py
@@ -0,0 +1,23 @@
+from __future__ import unicode_literals
+
+
+from hubs.app import app
+from hubs.tests import APPTest, auth_set
+
+
+class WidgetTestCase(APPTest):
+
+    def test_source_name(self):
+        with auth_set(app, None):
+            url = '/source/about'
+            result = self.app.get(url)
+            self.assertEqual(result.status_code, 302)
+            expected_str = 'https://pagure.io/fedora-hubs/' \
+                           'blob/develop/f/hubs/widgets/about/__init__.py'
+            self.assertIn(expected_str, result.get_data(as_text=True))
+
+    def test_source_name_not_existent(self):
+        with auth_set(app, None):
+            url = '/source/notexistent'
+            result = self.app.get(url)
+            self.assertEqual(result.status_code, 404)
diff --git a/hubs/tests/widgets/__init__.py b/hubs/tests/widgets/__init__.py
new file mode 100644
index 0000000..7d171e4
--- /dev/null
+++ b/hubs/tests/widgets/__init__.py
@@ -0,0 +1,47 @@
+from __future__ import unicode_literals
+
+import json
+import unittest
+
+import hubs.models
+from hubs.tests import APPTest, FakeAuthorization
+
+
+class WidgetTest(APPTest):
+
+    plugin = None  # The name in hubs.widgets.registry
+
+    def populate(self):
+        super(WidgetTest, self).populate()
+        hub = hubs.models.Hub.by_name('ralph')
+        widget = hubs.models.Widget(
+            plugin='library',
+            index=51,
+            # We must add a url in the config or it'll crash.
+            _config=json.dumps({"urls": "ralph/"})
+        )
+        hub.widgets.append(widget)
+        self.session.commit()
+
+    def _test_view_authz(self):
+        # Test authorizations on the root view.
+        if not self.plugin:
+            raise unittest.SkipTest
+        hub = hubs.models.Hub.query.get("ralph")
+        widget = self.widget_instance(hub.name, self.plugin)
+        url = '/%s/w/%s/%i/' % (hub.name, self.plugin, widget.idx)
+        # Public
+        self.check_url(url, None, 200)
+        # Preview
+        hub.config.visibility = "preview"
+        widget.visibility = "restricted"
+        self.session.commit()
+        self.check_url(url, None, 403)  # anonymous
+        self.check_url(url, FakeAuthorization('decause'), 200)  # logged-in
+        # Private
+        widget.hub.config.visibility = "private"
+        self.session.commit()
+        self.check_url(url, None, 403)  # anonymous
+        self.check_url(url, FakeAuthorization('decause'), 403)  # logged-in
+        hub.subscribe(hubs.models.User.query.get("decause"), "member")
+        self.check_url(url, FakeAuthorization('decause'), 200)  # member
diff --git a/hubs/tests/widgets/test_about.py b/hubs/tests/widgets/test_about.py
new file mode 100644
index 0000000..dd00e20
--- /dev/null
+++ b/hubs/tests/widgets/test_about.py
@@ -0,0 +1,24 @@
+from __future__ import unicode_literals
+
+import json
+
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
+
+
+class TestAbout(WidgetTest):
+    plugin = 'about'  # The name in hubs.widgets.registry
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        user = FakeAuthorization('ralph')
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data['data'], {
+            'text': 'Testing.',
+            'title': "<span class='glyphicon glyphicon-info-sign' "
+                     "aria-hidden='true'></span> About",
+        })
+
+    def test_view_authz(self):
+        self._test_view_authz()
diff --git a/hubs/tests/widgets/test_badges.py b/hubs/tests/widgets/test_badges.py
new file mode 100644
index 0000000..3cd2ee2
--- /dev/null
+++ b/hubs/tests/widgets/test_badges.py
@@ -0,0 +1,61 @@
+from __future__ import unicode_literals
+
+import json
+
+import hubs.widgets
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
+
+
+class TestBadges(WidgetTest):
+    plugin = 'badges'  # The name in hubs.widgets.registry
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        user = FakeAuthorization('ralph')
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEquals(data['plugin'], 'badges')
+        self.assertIn('assertions', data['data'].keys())
+
+    def test_should_invalidate_wrong_topic(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        # msg = self.get_fedmsg('2016-ebb84660-59e9-4e68-af8f-4e6f49348b88')
+        msg = {'topic': 'hubs.widget.update.WRONG.TOPIC'}
+        module = hubs.widgets.registry[widget.plugin]
+        func = module.get_cached_functions()['GetBadges']
+        result = func(widget).should_invalidate(msg)
+        self.assertFalse(result)
+
+    def test_should_invalidate_wrong_user(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        # msg = self.get_fedmsg('2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f')
+        msg = {'topic': 'fedbadges.badge.award',
+               'msg': {'user': {'username': 'not_ralph'}}}
+        module = hubs.widgets.registry[widget.plugin]
+        func = module.get_cached_functions()['GetBadges']
+        result = func(widget).should_invalidate(msg)
+        self.assertFalse(result)
+
+    def test_should_invalidate_good_match_fedbadges(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
+        msg = {'topic': 'fedbadges.badge.award',
+               'msg': {'user': {'username': 'ralph'}}}
+        module = hubs.widgets.registry[widget.plugin]
+        func = module.get_cached_functions()['GetBadges']
+        result = func(widget).should_invalidate(msg)
+        self.assertTrue(result)
+
+    def test_should_invalidate_good_match_hubswidget(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
+        msg = {'topic': 'hubs.widget.update',
+               'msg': {'widget': {'id': widget.idx + 1}}}
+        module = hubs.widgets.registry[widget.plugin]
+        func = module.get_cached_functions()['GetBadges']
+        result = func(widget).should_invalidate(msg)
+        self.assertTrue(result)
+
+    def test_view_authz(self):
+        self._test_view_authz()
diff --git a/hubs/tests/widgets/test_contact.py b/hubs/tests/widgets/test_contact.py
new file mode 100644
index 0000000..3d885d1
--- /dev/null
+++ b/hubs/tests/widgets/test_contact.py
@@ -0,0 +1,178 @@
+from __future__ import unicode_literals
+
+import json
+
+import flask
+import mock
+
+import hubs
+from hubs.models import Hub, Widget
+from hubs.tests import FakeAuthorization, auth_set
+from . import WidgetTest
+
+
+def mocked_requests_get(*args, **kwargs):
+    class MockResponse:  # flake8: noqa
+        def __init__(self, json_data, status_code):
+            self.json_data = json_data
+            self.status_code = status_code
+            self.text = str(json_data)
+        def json(self):
+            return self.json_data
+
+    if '/decause' in args[0]:
+        data = {
+            "current": 0,
+            "decrements": 0,
+            "increments": 0,
+            "release": "f24",
+            "total": 0,
+            "username": "decause"
+        }
+        return MockResponse(json_data=data, status_code=200)
+
+    return MockResponse({}, 404)
+
+def mocked_requests_post(*args, **kwargs):
+    class MockResponse:
+        def __init__(self, json_data, status_code):
+            self.json_data = json_data
+            self.status_code = status_code
+            self.text = str(json_data)
+
+        def json(self):
+            return self.json_data
+    if '/decause' in kwargs['url']:
+        data = {
+            "current": 1,
+            "decrements": 0,
+            "increments": 1,
+            "release": "f24",
+            "total": 1,
+            "username": "decause"
+        }
+        return MockResponse(json_data=data, status_code=200)
+
+    return MockResponse({}, 404)
+
+
+class ContactsTest(WidgetTest):
+
+    plugin = "contact"
+
+    def setUp(self):
+        super(ContactsTest, self).setUp()
+        hub = Hub.by_name('ralph')
+        widget = Widget(
+            plugin='contact',
+            index=1,
+        )
+        hub.widgets.append(widget)
+        self.session.commit()
+        self.widget_idx = widget.idx
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        user = FakeAuthorization('ralph')
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data['data'], {
+            'account_age': 'Oct 2010',
+            'email': 'ralph@fedoraproject.org',
+            'ircnick': 'ralph',
+            'karma_url': '/ralph/w/contact/%i/plus-plus/ralph/status'
+                         % widget.idx,
+            'location': 'United States',
+            'timezone': 'UTC',
+            'usergroup': True,
+        })
+
+    def test_view_authz(self):
+        self._test_view_authz()
+
+    @mock.patch('requests.get', side_effect=mocked_requests_get)
+    def test_plus_plus_get_valid(self, mock_get):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
+            self.widget_idx, "decause")
+        result = self.app.get(url)
+        expected = {
+            "current": 0,
+            "decrements": 0,
+            "increments": 0,
+            "release": "f24",
+            "total": 0,
+            "username": "decause"
+        }
+        self.assertEqual(result.status_code, 200)
+        self.assertEqual(
+            json.loads(result.get_data(as_text=True)),
+            expected)
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_valid(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "decause")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={'increment': True})
+            expected = {
+                "current": 1,
+                "decrements": 0,
+                "increments": 1,
+                "release": "f24",
+                "total": 1,
+                "username": "decause"
+            }
+            self.assertEqual(result.status_code, 200)
+            self.assertEqual(
+                json.loads(result.get_data(as_text=True)),
+                expected)
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_myself_error(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "ralph")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={'increment': True})
+            self.assertEqual(result.status_code, 403)
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'You may not modify your own karma.')
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "doesnotexist")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={'increment': True})
+            self.assertEqual(result.status_code, 404)
+            self.assertEqual(
+                result.get_data(as_text=True),
+                'User does not exist')
+
+    @mock.patch('requests.post', side_effect=mocked_requests_post)
+    def test_plus_plus_post_increment_no_data_error(self, mock_post):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
+            self.widget_idx, "decause")
+        user = FakeAuthorization('ralph')
+        with auth_set(hubs.app.app, user):
+            result = self.app.post(url, data={})
+            self.assertEqual(result.status_code, 400)
+            exp_str = "You must set 'decrement' or 'increment' " \
+                      "with a boolean value in the body"
+            self.assertEqual(result.get_data(as_text=True), exp_str)
+
+    def test_plus_plus_receiver_does_not_exist(self):
+        widget = self.widget_instance("ralph", self.plugin)
+        url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
+            self.widget_idx, "doesnotexist")
+        result = self.app.get(url)
+        self.assertEqual(result.status_code, 404)
+        self.assertEqual(result.get_data(as_text=True), 'User does not exist')
diff --git a/hubs/tests/widgets/test_fedmsgstats.py b/hubs/tests/widgets/test_fedmsgstats.py
new file mode 100644
index 0000000..87b5ae0
--- /dev/null
+++ b/hubs/tests/widgets/test_fedmsgstats.py
@@ -0,0 +1,30 @@
+from __future__ import unicode_literals
+
+import json
+
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
+
+
+class TestFedmsgStats(WidgetTest):
+    plugin = 'fedmsgstats'  # The name in hubs.widgets.registry
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        user = FakeAuthorization('ralph')
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data['data'], {
+            u'fedmsgs': 83854,
+            u'fedmsgs_text': u'83,854',
+            u'subscribers': [],
+            u'subscribed_to': [],
+            u'subscribers_text': u'0',
+            u'subscribed_text': u'0',
+            u'username': u'ralph',
+            u'hub_subscribe_url': u'/api/hub/ralph/subscribe',
+            u'hub_unsubscribe_url': u'/api/hub/ralph/unsubscribe',
+        })
+
+    def test_view_authz(self):
+        self._test_view_authz()
diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
new file mode 100644
index 0000000..ed60356
--- /dev/null
+++ b/hubs/tests/widgets/test_halp.py
@@ -0,0 +1,465 @@
+from __future__ import unicode_literals, absolute_import
+
+import json
+
+from hubs.models import Hub, User
+from hubs.tests import FakeAuthorization
+from hubs.widgets import registry
+from . import WidgetTest
+
+
+SAMPLE_DATA = [
+    {
+        'author': {
+            'url': '/mattdm/', 'name': 'mattdm', 'avatar': None,
+            },
+        'channel': u'#fedora-meeting',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/fedora-meeting/'
+            '2017-03-17/fesco.2017-03-17-16.00.log.html#l-466'
+            ),
+        'date': 1489773443.0,
+        'meeting_topic': 'FESCO (2017-03-17)',
+        'text': ('"How to enable trim on your SSD drive" would '
+                 'be a good Fedora Magazine article'),
+        'urls': [],
+    }, {
+        'author': {
+            'url': '/jkurik/', 'name': 'jkurik', 'avatar': None,
+            },
+        'channel': '#fedora-meeting-2',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/fedora-meeting-2/2017-03-16/'
+            'f26-alpha-readiness-meeting.2017-03-16-19.00.log.html#l-103'),
+        'date': 1489692368.0,
+        'meeting_topic': 'F26 Alpha Readiness Meeting',
+        'text': ('The Marketing team wants to ask for help from '
+                 'Spins, Labs SIGs and DEs SIGs to populate the '
+                 'talking points that help us to marketing people'),
+        'urls': [],
+    }, {
+        'author': {
+            'url': '/stoney/', 'name': 'stoney', 'avatar': None,
+            },
+        'channel': '#foss2serve',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/foss2serve/2017-03-14/'
+            'posse_irc_meeting_1.2.2017-03-14-17.00.log.html#l-187'),
+        'date': 1489512523.0,
+        'meeting_topic': 'POSSE IRC Meeting 1.2',
+        'text': '',
+        'urls': [],
+    }, {
+        'author': {
+            'url': '/nitzmahone/', 'name': 'nitzmahone', 'avatar': None,
+            },
+        'channel': '#ansible-meeting',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/ansible-meeting/2017-03-14/'
+            'windows_working_group.2017-03-14-00.00.log.html#l-130'),
+        'date': 1489451407.0,
+        'meeting_topic': 'Windows Working Group',
+        'text': '',
+        'urls': [],
+    }, {
+        'author': {
+            'url': '/jborean93/', 'name': 'jborean93', 'avatar': None
+            },
+        'channel': '#ansible-meeting',
+        'context_url': (
+            'https://meetbot.fedoraproject.org/ansible-meeting/2017-03-14/'
+            'windows_working_group.2017-03-14-00.00.log.html#l-59'),
+        'date': 1489450330.0,
+        'meeting_topic': 'Windows Working Group',
+        'text': 'with installers win_msi vs win_product',
+        'urls': [],
+    },
+]
+
+
+class HalpViewsTestCase(WidgetTest):
+    plugin = 'halp'  # The name in hubs.widgets.registry
+    maxDiff = None
+
+    def setUp(self):
+        super(HalpViewsTestCase, self).setUp()
+        self.widget = self.widget_instance('ralph', self.plugin)
+        config = self.widget.config
+        config["hubs"] = ["fedora-devel"]
+        config["per_page"] = 3
+        self.widget.config = config
+        infra_hub = Hub.query.get("infra")
+        infra_hub.config.chat_channel = "#fedora-meeting"
+        devyani7 = Hub.query.get("devyani7")
+        devyani7.config.chat_channel = "#fedora-meeting-2"
+        decause = Hub.query.get("decause")
+        decause.config.chat_channel = "#ansible-meeting"
+        dhrish = Hub.query.get("dhrish")
+        dhrish.config.chat_channel = "#foss2serve"
+        self.session.commit()
+        self.session.refresh(self.widget)
+
+    def _get_sample_data_with_hub_keys(self):
+        hub_names = ["infra", "devyani7", "dhrish", "decause", "decause"]
+        data = [req.copy() for req in SAMPLE_DATA]
+        for index, hub_name in enumerate(hub_names):
+            data[index].update({
+                'hub': hub_name,
+                'hubs': [hub_name],
+                })
+        return data
+
+    def test_root(self):
+        response = self.check_url('/ralph/w/halp/%i/' % self.widget.idx)
+        self.assertEqual(response.context["hubs"], ['fedora-devel'])
+
+    def test_view_authz(self):
+        self._test_view_authz()
+
+    def test_json(self):
+        response = self.app.get('/ralph/%i/json' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEquals(data['plugin'], 'halp')
+        self.assertIn('hubs', data['data'].keys())
+
+    def test_config_add(self):
+        user = FakeAuthorization('ralph')
+        response = self.check_url('/ralph/w/halp/add?position=right', user)
+        self.assertEqual(response.context["mode"], "add")
+        self.assertEqual(response.context["initial"], {
+            "hubs": ["ralph"], "per_page": 4,
+            })
+        self.assertEqual(
+            response.context["url"], "/ralph/add/halp?position=right")
+
+    def test_config_edit(self):
+        user = FakeAuthorization('ralph')
+        url = '/ralph/w/halp/%i/config' % self.widget.idx
+        response = self.check_url(url, user)
+        self.assertEqual(response.context["mode"], "edit")
+        self.assertEqual(response.context["initial"], {
+            'hubs': ['fedora-devel'],
+            'per_page': 3,
+            })
+        self.assertEqual(
+            response.context["url"], "/ralph/%i/edit" % self.widget.idx)
+
+    def test_config_authz(self):
+        urls = [
+            '/ralph/w/halp/add',
+            '/ralph/w/halp/%i/config' % self.widget.idx,
+            ]
+        # Anonymous
+        for url in urls:
+            self.check_url(url, None, 403)
+        # Logged-in
+        user = FakeAuthorization('decause')
+        for url in urls:
+            self.check_url(url, user, 403)
+        # Member
+        hub = Hub.query.get("ralph")
+        hub.subscribe(User.query.get("decause"), "member")
+        for url in urls:
+            self.check_url(url, user, 403)
+        # Owner
+        user = FakeAuthorization('ralph')
+        for url in urls:
+            self.check_url(url, user, 200)
+
+    def test_config_hubs_suggest(self):
+        response = self.app.get('/w/halp/hubs')
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data, {
+            'results': ['decause', 'devyani7', 'dhrish', 'i18n', 'infra']
+        })
+        response = self.app.get('/w/halp/hubs?q=de')
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data, {
+            'results': ['decause', 'devyani7']
+        })
+
+    def test_data(self):
+        expected = self._get_sample_data_with_hub_keys()
+        # Test with no hub selected
+        response = self.app.get('/ralph/w/halp/%i/data' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {"requests": expected[:3]})
+        # Test with the right hub selected
+        response = self.app.get('/ralph/w/halp/%i/data?hubs=decause'
+                                % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {"requests": expected[3:5]})
+
+    def test_data_wrong_hub(self):
+        # Test with the wrong hub selected
+        response = self.app.get('/ralph/w/halp/%i/data?hubs=ralph'
+                                % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {"requests": []})
+
+    def test_search_requesters(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/requesters' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data, {
+            'results': ['jborean93', 'jkurik', 'mattdm', 'nitzmahone',
+                        'stoney']
+        })
+        response = self.app.get(
+            '/ralph/w/halp/%i/requesters?q=j' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(data, {
+            'results': ['jborean93', 'jkurik']
+        })
+
+    def test_search_all(self):
+        expected = self._get_sample_data_with_hub_keys()
+        response = self.app.get(
+            '/ralph/w/halp/%i/search' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {
+            "requests": expected[:3],
+            'page': {
+                'has_next': True,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 5,
+                'total_pages': 2,
+                },
+            })
+        # Page 2
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?page=2' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(data, {
+            "requests": expected[3:],
+            'page': {
+                'has_next': False,
+                'has_prev': True,
+                'nr': 2,
+                'total_entries': 5,
+                'total_pages': 2,
+                },
+            })
+
+    def test_search_hub(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?hubs=infra' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        expected = self._get_sample_data_with_hub_keys()
+        self.assertEqual(data, {
+            "requests": expected[0:1],
+            'page': {
+                'has_next': False,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 1,
+                'total_pages': 1
+                },
+            })
+
+    def test_search_people(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?people=nitzmahone' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        expected = self._get_sample_data_with_hub_keys()
+        self.assertEqual(data, {
+            "requests": expected[3:4],
+            'page': {
+                'has_next': False,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 1,
+                'total_pages': 1
+                },
+            })
+
+    def test_search_meetingname(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?meetingname=Readiness' % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        expected = self._get_sample_data_with_hub_keys()
+        self.assertEqual(data, {
+            "requests": expected[1:2],
+            'page': {
+                'has_next': False,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 1,
+                'total_pages': 1
+                },
+            })
+
+    def test_search_date(self):
+        response = self.app.get(
+            '/ralph/w/halp/%i/search?startdate=2017-03-16&enddate=2017-03-17'
+            % self.widget.idx)
+        self.assertEqual(response.status_code, 200)
+        data = json.loads(response.get_data(as_text=True))
+        expected = self._get_sample_data_with_hub_keys()
+        self.assertEqual(data, {
+            "requests": expected[1:2],
+            'page': {
+                'has_next': False,
+                'has_prev': False,
+                'nr': 1,
+                'total_entries': 1,
+                'total_pages': 1
+                },
+            })
+
+
+class HalpFunctionsTestCase(WidgetTest):
+    plugin = 'halp'  # The name in hubs.widgets.registry
+
+    def setUp(self):
+        super(HalpFunctionsTestCase, self).setUp()
+        module = registry[self.plugin]
+        func_class = module.get_cached_functions()['GetRequests']
+        self.widget = self.widget_instance('ralph', self.plugin)
+        self.func = func_class(self.widget)
+        # The tested widget watches the infra hub.
+        config = self.widget.config
+        config["hubs"] = ["infra"]
+        self.widget.config = config
+        # The infra hub works in the fedora-infra channel.
+        infra_hub = Hub.query.filter_by(name="infra").one()
+        infra_hub.config.chat_channel = "#fedora-infra"
+        self.session.commit()
+
+    def test_execute(self):
+        with self.app.application.test_request_context('/'):
+            result = self.func.execute()
+        self.assertEqual(result, SAMPLE_DATA)
+
+    def test_should_invalidate_wrong_topic(self):
+        msg = {'topic': 'hubs.WRONG.TOPIC'}
+        result = self.func.should_invalidate(msg)
+        self.assertFalse(result)
+
+    def test_should_invalidate_wrong_hub(self):
+        # The decause hub works in the fedora-commops channel.
+        decause_hub = Hub.query.filter_by(name="decause").one()
+        decause_hub.config.chat_channel = "#fedora-commops"
+        self.session.commit()
+        msg = {'topic': 'org.fedoraproject.prod.meetbot.meeting.item.help',
+               'msg': {'channel': '#fedora-commops'},
+               }
+        # The decause hub cache would be invalidated, but not ours.
+        result = self.func.should_invalidate(msg)
+        self.assertFalse(result)
+
+    def test_should_invalidate_good_match(self):
+        msg = {'topic': 'org.fedoraproject.prod.meetbot.meeting.item.help',
+               'msg': {'channel': '#fedora-infra'},
+               }
+        result = self.func.should_invalidate(msg)
+        self.assertTrue(result)
+
+
+class PaginateTestCase(WidgetTest):
+
+    def setUp(self):
+        super(PaginateTestCase, self).setUp()
+        from hubs.widgets.halp.utils import paginate  # circular
+        self.paginate = paginate
+        self.values = ["A", "B", "C", "D"]
+
+    def test_base(self):
+        with self.app.application.test_request_context('/'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[:3])
+        self.assertDictEqual(result[1], {
+            'has_next': True,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_page_2(self):
+        with self.app.application.test_request_context('/?page=2'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[3:])
+        self.assertDictEqual(result[1], {
+            'has_next': False,
+            'has_prev': True,
+            'nr': 2,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_page_0(self):
+        with self.app.application.test_request_context('/?page=0'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[:3])
+        self.assertDictEqual(result[1], {
+            'has_next': True,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_invalid_page(self):
+        with self.app.application.test_request_context('/?page=blah'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[:3])
+        self.assertDictEqual(result[1], {
+            'has_next': True,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_page_too_high(self):
+        with self.app.application.test_request_context('/?page=3'):
+            result = self.paginate(self.values, 3)
+        self.assertListEqual(result[0], self.values[3:])
+        self.assertDictEqual(result[1], {
+            'has_next': False,
+            'has_prev': True,
+            'nr': 2,
+            'total_entries': len(self.values),
+            'total_pages': 2,
+            })
+
+    def test_single_page(self):
+        values = self.values[:3]
+        with self.app.application.test_request_context('/'):
+            result = self.paginate(values, 3)
+        self.assertListEqual(result[0], values)
+        self.assertDictEqual(result[1], {
+            'has_next': False,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': len(values),
+            'total_pages': 1,
+            })
+
+    def test_no_value(self):
+        values = []
+        with self.app.application.test_request_context('/'):
+            result = self.paginate(values, 3)
+        self.assertListEqual(result[0], [])
+        self.assertDictEqual(result[1], {
+            'has_next': False,
+            'has_prev': False,
+            'nr': 1,
+            'total_entries': 0,
+            'total_pages': 1,
+            })
diff --git a/hubs/tests/widgets/test_library.py b/hubs/tests/widgets/test_library.py
new file mode 100644
index 0000000..6d85ad2
--- /dev/null
+++ b/hubs/tests/widgets/test_library.py
@@ -0,0 +1,37 @@
+from __future__ import unicode_literals
+
+import json
+
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
+
+
+class TestLibrary(WidgetTest):
+    plugin = 'library'  # The name in hubs.widgets.registry
+
+    def test_data_simple(self):
+        widget = self.widget_instance('ralph', self.plugin)
+        user = FakeAuthorization('ralph')
+        response = self.check_url('/ralph/%i/json' % widget.idx, user)
+        data = json.loads(response.get_data(as_text=True))
+        expected_dict = {
+            "config": {
+                "urls": "ralph/"
+            },
+            "data": {
+                'title': 'Library',
+                "urls": [
+                    "<a href=\"ralph/\">ralph/</a>"
+                ],
+            },
+            "description": None,
+            "hub": "ralph",
+            "id": 52,
+            "index": 51,
+            "left": False,
+            "plugin": "library"
+        }
+        self.assertDictEqual(data['data'], expected_dict['data'])
+
+    def test_view_authz(self):
+        self._test_view_authz()
diff --git a/hubs/tests/widgets/test_meetings.py b/hubs/tests/widgets/test_meetings.py
new file mode 100644
index 0000000..49f088b
--- /dev/null
+++ b/hubs/tests/widgets/test_meetings.py
@@ -0,0 +1,32 @@
+from __future__ import unicode_literals
+
+import json
+
+from hubs.tests import FakeAuthorization
+from . import WidgetTest
+
+
+class TestMeetings(WidgetTest):
+    plugin = 'meetings'
+
+    def test_data_simple(self):
+        team = 'i18n'
+        widget = self.widget_instance(team, self.plugin)
+        user = FakeAuthorization('ralph')
+        response = self.check_url('/%s/%i/json' % (team, widget.idx), user)
+        data = json.loads(response.get_data(as_text=True))
+        calendar_name = data['data']['calendar']
+        self.assertIn(team, calendar_name)
+
+    def test_render_simple(self):
+        team = 'i18n'
+        widget = self.widget_instance(team, self.plugin)
+        user = FakeAuthorization('ralph')
+        url = '/%s/w/%s/%i/' % (team, self.plugin, widget.idx)
+        response = self.check_url(url, user)
+        self.assertIn('i18n', response.get_data(as_text=True))
+        self.assertIn('<strong>Request A New Meeting</strong>',
+                      response.get_data(as_text=True))
+
+    def test_view_authz(self):
+        self._test_view_authz()

From 3258a03d11cd53ab2260f4abf59d386a20f9e0df Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 824/1001] Make Flake8 exceptions more precise


---

diff --git a/hubs/app.py b/hubs/app.py
index d50c365..62a7485 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -98,12 +98,13 @@ def check_auth():
     else:
         flask.g.auth = munch.Munch(logged_in=False, user=None)
 
+
 # Register widgets
-import hubs.widgets  # noqa
+import hubs.widgets  # noqa: E402
 hubs.widgets.registry.register_list(app.config["WIDGETS"])
 
 # Register routes
-import hubs.views  # noqa
+import hubs.views  # noqa: E402
 
 # Add widget-specific routes
 hubs.widgets.registry.register_routes(app)
diff --git a/hubs/migrations/env.py b/hubs/migrations/env.py
index db92033..a9ea110 100644
--- a/hubs/migrations/env.py
+++ b/hubs/migrations/env.py
@@ -8,7 +8,7 @@ from sqlalchemy import create_engine, pool
 
 
 try:
-    import hubs  # noqa
+    import hubs
 except ImportError:
     import os
     import sys
diff --git a/hubs/tests/widgets/test_contact.py b/hubs/tests/widgets/test_contact.py
index 3d885d1..03f24e7 100644
--- a/hubs/tests/widgets/test_contact.py
+++ b/hubs/tests/widgets/test_contact.py
@@ -2,7 +2,6 @@ from __future__ import unicode_literals
 
 import json
 
-import flask
 import mock
 
 import hubs
@@ -12,11 +11,12 @@ from . import WidgetTest
 
 
 def mocked_requests_get(*args, **kwargs):
-    class MockResponse:  # flake8: noqa
+    class MockResponse:
         def __init__(self, json_data, status_code):
             self.json_data = json_data
             self.status_code = status_code
             self.text = str(json_data)
+
         def json(self):
             return self.json_data
 
@@ -33,6 +33,7 @@ def mocked_requests_get(*args, **kwargs):
 
     return MockResponse({}, 404)
 
+
 def mocked_requests_post(*args, **kwargs):
     class MockResponse:
         def __init__(self, json_data, status_code):
@@ -42,6 +43,7 @@ def mocked_requests_post(*args, **kwargs):
 
         def json(self):
             return self.json_data
+
     if '/decause' in kwargs['url']:
         data = {
             "current": 1,
@@ -72,16 +74,15 @@ class ContactsTest(WidgetTest):
         self.widget_idx = widget.idx
 
     def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
+        response = self.check_url('/ralph/%i/json' % self.widget_idx, user)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
             'account_age': 'Oct 2010',
             'email': 'ralph@fedoraproject.org',
             'ircnick': 'ralph',
             'karma_url': '/ralph/w/contact/%i/plus-plus/ralph/status'
-                         % widget.idx,
+                         % self.widget_idx,
             'location': 'United States',
             'timezone': 'UTC',
             'usergroup': True,
@@ -92,7 +93,6 @@ class ContactsTest(WidgetTest):
 
     @mock.patch('requests.get', side_effect=mocked_requests_get)
     def test_plus_plus_get_valid(self, mock_get):
-        widget = self.widget_instance("ralph", self.plugin)
         url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
             self.widget_idx, "decause")
         result = self.app.get(url)
@@ -111,7 +111,6 @@ class ContactsTest(WidgetTest):
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_valid(self, mock_post):
-        widget = self.widget_instance("ralph", self.plugin)
         url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
             self.widget_idx, "decause")
         user = FakeAuthorization('ralph')
@@ -132,7 +131,6 @@ class ContactsTest(WidgetTest):
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_myself_error(self, mock_post):
-        widget = self.widget_instance("ralph", self.plugin)
         url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
             self.widget_idx, "ralph")
         user = FakeAuthorization('ralph')
@@ -145,7 +143,6 @@ class ContactsTest(WidgetTest):
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_user_does_not_exist(self, mock_post):
-        widget = self.widget_instance("ralph", self.plugin)
         url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
             self.widget_idx, "doesnotexist")
         user = FakeAuthorization('ralph')
@@ -158,7 +155,6 @@ class ContactsTest(WidgetTest):
 
     @mock.patch('requests.post', side_effect=mocked_requests_post)
     def test_plus_plus_post_increment_no_data_error(self, mock_post):
-        widget = self.widget_instance("ralph", self.plugin)
         url = "/ralph/w/contact/%d/plus-plus/%s/update" % (
             self.widget_idx, "decause")
         user = FakeAuthorization('ralph')
@@ -170,7 +166,6 @@ class ContactsTest(WidgetTest):
             self.assertEqual(result.get_data(as_text=True), exp_str)
 
     def test_plus_plus_receiver_does_not_exist(self):
-        widget = self.widget_instance("ralph", self.plugin)
         url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
             self.widget_idx, "doesnotexist")
         result = self.app.get(url)
diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
index 87da5d9..33b68f2 100644
--- a/hubs/views/__init__.py
+++ b/hubs/views/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import absolute_import
 
-# flake8:noqa
+# flake8: noqa
 
 from .root import *
 from .hub import *
diff --git a/runserver.py b/runserver.py
index f41b3cd..42bd503 100755
--- a/runserver.py
+++ b/runserver.py
@@ -31,7 +31,7 @@ if args.config:
     os.environ['HUBS_CONFIG'] = config
 
 
-from hubs.app import app  # noqa
+from hubs.app import app  # noqa: E402
 
 app.debug = True
 app.run(debug=True, host=args.host, port=int(args.port))
diff --git a/setup.py b/setup.py
index cb267d0..824eeb9 100644
--- a/setup.py
+++ b/setup.py
@@ -40,7 +40,7 @@ setup(
     ],
     entry_points={
         'moksha.consumer': [
-            "cache_invalidator = hubs.backend.consumer:CacheInvalidatorExtraordinaire",  # noqa
+            "cache_invalidator = hubs.backend.consumer:CacheInvalidatorExtraordinaire",  # noqa: E501
         ],
     },
 )

From 0cca1db2dde280d20a9159394838c727e2a3a8db Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 825/1001] Include tests config and data in the tarball


---

diff --git a/MANIFEST.in b/MANIFEST.in
index c533ed4..c243f4b 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -6,6 +6,9 @@ recursive-include hubs/templates *.html
 recursive-include hubs/migrations *.py *.mako *.rst
 include hubs/migrations/versions/.keep
 include hubs/actions.json
+include hubs/tests/*.cfg
+include hubs/tests/*.json
+graft hubs/tests/vcr-request-data
 graft ansible
 graft docs
 prune docs/_build

From d383af07491029e476782d30171943c3a8b05cf4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 826/1001] Backend: don't create a new DB session for each task


---

diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index 7ea3645..36fb76f 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -38,9 +38,10 @@ import hubs.widgets.base
 
 log = logging.getLogger('hubs.backend.triage')
 config = fedmsg.config.load_config()
+session = hubs.app.session
 
 
-def triage(session, outbound, msg):
+def triage(outbound, msg):
     topic = msg['topic']
 
     for suffix in config['hubs.junk_suffixes']:
@@ -103,9 +104,8 @@ def main(args):
                 "(triage backlog: %r, work backlog: %r)  Working on %r %r",
                 inbound.length, outbound.length, msg['msg_id'], msg['topic'],
             )
-            session = hubs.models.init(config['hubs.sqlalchemy.uri'])
             with hubs.app.app.app_context():  # so url_for works
-                for task in triage(session, outbound, msg):
+                for task in triage(outbound, msg):
                     log.debug("  Triage sending %r to workers." % task)
                     outbound.enqueue(task)
             log.debug("  Done with triage of %r.", msg['msg_id'])
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index 552d781..a827c3a 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -42,6 +42,7 @@ import hubs.widgets.base
 
 log = logging.getLogger('hubs.backend.worker')
 config = fedmsg.config.load_config()
+session = hubs.app.session
 
 
 def work(widget_idx, fn_name):
@@ -55,7 +56,6 @@ def work(widget_idx, fn_name):
 
 
 def handle(idx, fn_name):
-    session = hubs.models.init(config['hubs.sqlalchemy.uri'])
 
     try:
         with hubs.app.app.app_context():  # so url_for works

From d4409c099dadd2223d03c2e1a4d7f8ea64e73ac8 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 827/1001] Don't create DB sessions needlessly in the scripts


---

diff --git a/check-cache-coverage.py b/check-cache-coverage.py
index efe45ab..409eafe 100755
--- a/check-cache-coverage.py
+++ b/check-cache-coverage.py
@@ -22,12 +22,9 @@ import hubs.widgets
 import hubs.widgets.caching
 import hubs.models
 
-import fedmsg.config
-
-config = fedmsg.config.load_config()
 
 empty, full = 0, 0
-session = hubs.models.init(config['hubs.sqlalchemy.uri'])
+session = hubs.app.session
 
 # Register widgets
 hubs.widgets.registry.register_list(hubs.app.app.config["WIDGETS"])
diff --git a/populate-from-fas.py b/populate-from-fas.py
index b5ed9ce..6e9fb36 100755
--- a/populate-from-fas.py
+++ b/populate-from-fas.py
@@ -12,6 +12,7 @@ import hubs.models
 import fedora.client.fas2
 import fedmsg.config
 fedmsg_config = fedmsg.config.load_config()
+session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 fasclient = fedora.client.fas2.AccountSystem(
     username=input('Your FAS username: '),
@@ -37,8 +38,6 @@ suffix_blacklist = [
 
 
 for letter in reversed(sorted(list(set(string.letters.lower())))):
-    session = hubs.models.init(
-        fedmsg_config['hubs.sqlalchemy.uri'], True, True)
     print("Querying FAS for the %r users.. hang on." % letter)
     request = fasclient.send_request(
         '/user/list',
@@ -57,8 +56,6 @@ for letter in reversed(sorted(list(set(string.letters.lower())))):
     session.commit()
 
     # Go back now and set up the groups...
-    session = hubs.models.init(
-        fedmsg_config['hubs.sqlalchemy.uri'], True, True)
     for user in users:
         hubs_user = hubs.models.User.by_username(user['username'])
 
diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index 5150b0c..4339c04 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -12,20 +12,13 @@ from __future__ import print_function, unicode_literals
 
 import argparse
 
-import fedmsg.config
-import fedmsg.meta
-
-
 import hubs.app
 import hubs.models
 import hubs.widgets.base
 import hubs.widgets.caching
 
 # get the DB session
-fedmsg_config = fedmsg.config.load_config()
-fedmsg.meta.make_processors(**fedmsg_config)
-
-session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
+session = hubs.app.session
 
 # Register widgets
 hubs.widgets.registry.register_list(hubs.app.app.config["WIDGETS"])

From 7333d1fad7fcc319955658f6ab1a4322d1e39526 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 828/1001] Don't load the fedmsg config if not necessary


---

diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index 36fb76f..7f7858c 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -27,8 +27,6 @@ import logging.config
 import random
 import sys
 
-import fedmsg.config
-import fedmsg.meta
 import retask.queue
 
 import hubs.app
@@ -37,14 +35,14 @@ import hubs.widgets.base
 
 
 log = logging.getLogger('hubs.backend.triage')
-config = fedmsg.config.load_config()
+fedmsg_config = hubs.app.fedmsg_config
 session = hubs.app.session
 
 
 def triage(outbound, msg):
     topic = msg['topic']
 
-    for suffix in config['hubs.junk_suffixes']:
+    for suffix in fedmsg_config['hubs.junk_suffixes']:
         if topic.endswith(suffix):
             log.debug("  Dropping junk %r", topic)
             return
@@ -76,16 +74,14 @@ def triage(outbound, msg):
 
 
 def main(args):
-    logging.config.dictConfig(config['logging'])
+    logging.config.dictConfig(fedmsg_config['logging'])
     logging.basicConfig()
 
-    fedmsg.meta.make_processors(**config)
-
     # XXX - for flask.url_for to work
     hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
 
-    inbound_name = config['hubs.redis.triage-queue-name']
-    outbound_name = config['hubs.redis.work-queue-name']
+    inbound_name = fedmsg_config['hubs.redis.triage-queue-name']
+    outbound_name = fedmsg_config['hubs.redis.work-queue-name']
 
     log.info("Triage proc starting. Moving from %r to %r."
              % (inbound_name, outbound_name))
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index a827c3a..8e8d8c6 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -31,8 +31,6 @@ import logging
 import logging.config
 import sys
 
-import fedmsg.config
-import fedmsg.meta
 import retask.queue
 
 import hubs.app
@@ -41,7 +39,7 @@ import hubs.widgets.base
 
 
 log = logging.getLogger('hubs.backend.worker')
-config = fedmsg.config.load_config()
+fedmsg_config = hubs.app.fedmsg_config
 session = hubs.app.session
 
 
@@ -69,15 +67,13 @@ def handle(idx, fn_name):
 
 
 def main(args):
-    logging.config.dictConfig(config['logging'])
+    logging.config.dictConfig(fedmsg_config['logging'])
     logging.basicConfig()
 
-    fedmsg.meta.make_processors(**config)
-
     # XXX - for flask.url_for to work
     hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
 
-    name = config['hubs.redis.work-queue-name']
+    name = fedmsg_config['hubs.redis.work-queue-name']
     log.info("Worker starting, connecting to retask queue %r." % name)
     queue = retask.queue.Queue(name)
     queue.connect()
diff --git a/hubs/migrations/env.py b/hubs/migrations/env.py
index a9ea110..0148bb7 100644
--- a/hubs/migrations/env.py
+++ b/hubs/migrations/env.py
@@ -2,7 +2,6 @@ from __future__ import absolute_import, unicode_literals
 
 from logging.config import fileConfig
 
-import fedmsg.config
 from alembic import context
 from sqlalchemy import create_engine, pool
 
@@ -27,7 +26,7 @@ if context.config.config_file_name is not None:
     # This line sets up loggers basically.
     fileConfig(context.config.config_file_name)
 
-fedmsg_config = fedmsg.config.load_config()
+fedmsg_config = hubs.app.fedmsg_config
 url = fedmsg_config['hubs.sqlalchemy.uri']
 target_metadata = BASE.metadata
 
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index d6cc11c..3b4c6b3 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -1,14 +1,10 @@
 from __future__ import unicode_literals
 
-import fedmsg.config
-
 import hubs
 import hubs.models
 import hubs.tests
 from hubs.authz import AccessLevel
 
-fedmsg_config = fedmsg.config.load_config()
-
 
 class ModelTest(hubs.tests.APPTest):
     def test_delete_user(self):
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index 37b4b1c..1596cea 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -1,7 +1,5 @@
 from __future__ import unicode_literals
 
-import fedmsg.config
-import fedmsg.meta
 import flask
 import hubs.models
 import requests
@@ -10,8 +8,6 @@ import six
 from hubs.widgets.base import Widget, WidgetView
 from hubs.views.utils import login_required
 
-config = fedmsg.config.load_config()
-
 
 class Contact(Widget):
 

From 7ab1e184ace945b94e8c014553eee5512d154156 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 829/1001] Add a way to override the fedmsg config file


---

diff --git a/check-queue-length.py b/check-queue-length.py
index 1a07f79..d6d90e9 100755
--- a/check-queue-length.py
+++ b/check-queue-length.py
@@ -17,8 +17,9 @@ from __future__ import unicode_literals, print_function
 
 import retask
 
-import fedmsg.config
-config = fedmsg.config.load_config()
+from hubs.utils import get_fedmsg_config
+
+config = get_fedmsg_config()
 
 for item in ['triage', 'work']:
     queue = retask.queue.Queue(config['hubs.redis.%s-queue-name' % item])
diff --git a/delete-user.py b/delete-user.py
index 9c79fc9..544f89e 100755
--- a/delete-user.py
+++ b/delete-user.py
@@ -6,11 +6,10 @@ Useful for testing what happens when you recreate them.
 
 from __future__ import unicode_literals, print_function
 
-import fedmsg.config
-
 import hubs.models
+from hubs.utils import get_fedmsg_config
 
-fedmsg_config = fedmsg.config.load_config()
+fedmsg_config = get_fedmsg_config()
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 
diff --git a/hubs/app.py b/hubs/app.py
index 62a7485..fa24829 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -5,15 +5,13 @@ import logging
 import os
 
 import datanommer.models
-import fedmsg.config
-import fedmsg.meta
 import flask
 import flask.json
 import munch
 from flask_oidc import OpenIDConnect
 
 import hubs.models
-from hubs.utils import username2avatar
+from hubs.utils import get_fedmsg_config, username2avatar
 
 app = flask.Flask(__name__)
 
@@ -32,9 +30,7 @@ app.config.from_object('hubs.default_config')
 if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
 
-fedmsg_config = fedmsg.config.load_config()
-fedmsg.meta.make_processors(**fedmsg_config)
-
+fedmsg_config = get_fedmsg_config()
 session = hubs.models.init(
     fedmsg_config.get('hubs.sqlalchemy.uri', 'sqlite:///'))
 datanommer.models.init(
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index ad600c0..90913f1 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -25,9 +25,6 @@ class APPTest(unittest.TestCase):
         self.vcr.__enter__()
 
         import hubs.app
-        hubs.app.fedmsg_config = {
-            'hubs.sqlalchemy.uri': 'sqlite://',  # in memory
-        }
         hubs.app.session = hubs.models.init(
             hubs.app.fedmsg_config['hubs.sqlalchemy.uri'],
             create=True,
@@ -36,9 +33,6 @@ class APPTest(unittest.TestCase):
         self.app = hubs.app.app.test_client()
         self.app.testing = True
         self.session = hubs.app.session
-        from hubs.widgets.caching import cache
-        cache.configure(backend='dogpile.cache.null',
-                        replace_existing_backend=True)
         self.populate()
 
     def tearDown(self):
diff --git a/hubs/tests/fedmsg_test.cfg b/hubs/tests/fedmsg_test.cfg
new file mode 100644
index 0000000..6d64bdf
--- /dev/null
+++ b/hubs/tests/fedmsg_test.cfg
@@ -0,0 +1,53 @@
+# Fedmsg configuration for testing
+
+config = {
+    #'hubs.consumer.enabled': True,
+    'hubs.sqlalchemy.uri': 'sqlite://',  # in memory
+
+    ## For communication between fedmsg-hub and the cache worker farm
+    #'hubs.redis.triage-queue-name': 'fedora-hubs-triage-queue',
+    #'hubs.redis.work-queue-name': 'fedora-hubs-work-queue',
+
+    ## Junk junk junk.. that we don't care about.  Drop it!
+    #'hubs.junk_suffixes': [
+    #    'buildsys.tag',
+    #    'buildsys.untag',
+    #    'buildsys.rpm.sign',
+    #],
+
+    'endpoints': {
+        "fedora-infrastructure": [
+            "tcp://hub.fedoraproject.org:9940",
+        ]
+    },
+
+    #'datanommer.sqlalchemy.uri':
+    #    'postgres://postgres:laksjdf@127.0.0.1/datanommer',
+
+    #'fmn.url': 'https://apps.fedoraproject.org/notifications',
+
+    ## Some configuration for the rule processors
+    #"fmn.rules.utils.use_pkgdb2": False,
+    #"fmn.rules.utils.pkgdb2_api_url": "http://209.132.184.188/api/",
+    #"fmn.rules.cache": {
+    #    "backend": "dogpile.cache.dbm",
+    #    "expiration_time": 300,
+    #    "arguments": {
+    #        "filename": "/var/tmp/fmn-cache.db",
+    #    },
+    #},
+
+    # No cache during testing.
+    "fedora-hubs.cache": {
+        "backend": "dogpile.cache.null",
+    },
+
+    ## Run datanommer locally, just for development.
+    #'datanommer.enabled': True,
+    #'datanommer.sqlalchemy.url':
+    #    'postgres://postgres:laksjdf@127.0.0.1/datanommer',
+
+    ## Only do one of these so we can try to not run out of memory.
+    #'moksha.workers_per_consumer': 1,
+}
+
diff --git a/hubs/utils.py b/hubs/utils.py
index 830d5ae..4fa5f1f 100755
--- a/hubs/utils.py
+++ b/hubs/utils.py
@@ -1,17 +1,29 @@
 from __future__ import unicode_literals
 
-import logging
-from hashlib import sha256
-
 import arrow
+import logging
 import markdown
+import os
 import requests
+from hashlib import sha256
 
+import fedmsg.config
+import fedmsg.meta
 from six.moves.urllib_parse import urlencode
 
 log = logging.getLogger(__name__)
 
 
+def get_fedmsg_config():
+    try:
+        filenames = [os.environ["FEDMSG_CONFIG"]]
+    except KeyError:
+        filenames = None
+    fedmsg_config = fedmsg.config.load_config(filenames=filenames)
+    fedmsg.meta.make_processors(**fedmsg_config)
+    return fedmsg_config
+
+
 def markup(text):
     return markdown.markdown(
         text,
diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index c94dddb..acb18d5 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -9,14 +9,15 @@ from __future__ import unicode_literals
 import datetime
 import dogpile
 import dogpile.cache
-import fedmsg.config
 import logging
 
+from hubs.utils import get_fedmsg_config
+
+
 log = logging.getLogger(__name__)
 
 
 def _get_cache():
-    config = fedmsg.config.load_config()
     cache_defaults = {
         "backend": "dogpile.cache.dbm",
         "expiration_time": 1,  # Expire every 1 second, for development
@@ -25,7 +26,8 @@ def _get_cache():
         },
     }
     cache = dogpile.cache.make_region()
-    cache.configure(**config.get('fedora-hubs.cache', cache_defaults))
+    fedmsg_config = get_fedmsg_config()
+    cache.configure(**fedmsg_config.get('fedora-hubs.cache', cache_defaults))
     return cache
 
 
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index ac1ba24..56f5e40 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -5,12 +5,13 @@ import fedmsg.config
 import fedmsg.meta
 import requests
 
-from hubs.utils import commas
+from hubs.utils import get_fedmsg_config, commas
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
-fedmsg_config = fedmsg.config.load_config()
+
+fedmsg_config = get_fedmsg_config()
 
 
 class FedmsgStats(Widget):
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index c5970f9..283a15d 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -3,14 +3,14 @@ from __future__ import unicode_literals
 import logging
 import hubs.utils
 
+from hubs.utils import get_fedmsg_config
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
-import fedmsg.config
-fedmsg_config = fedmsg.config.load_config()
 
 log = logging.getLogger(__name__)
+fedmsg_config = get_fedmsg_config()
 
 
 class GitHubPRs(Widget):
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
index d6dd928..05d0693 100644
--- a/hubs/widgets/subscriptions/__init__.py
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -1,16 +1,17 @@
 from __future__ import unicode_literals
 
 import flask
-import hubs.models
+from fedmsg.meta import msg2usernames
+from fedmsg.meta.base import BaseConglomerator as BC
 
+import hubs.models
+from hubs.utils import get_fedmsg_config
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
-from fedmsg.meta.base import BaseConglomerator as BC
 
-import fedmsg.config
-fm_config = fedmsg.config.load_config()
+fedmsg_config = get_fedmsg_config()
 
 
 class Subscriptions(Widget):
@@ -74,5 +75,5 @@ class GetSubs(CachedFunction):
         if not message['topic'].endswith('hubs.associate'):
             return False
         username = self.instance.config['username']
-        users = fedmsg.meta.msg2usernames(message, **fm_config)
+        users = msg2usernames(message, **fedmsg_config)
         return username in users
diff --git a/populate-from-fas.py b/populate-from-fas.py
index 6e9fb36..0771d24 100755
--- a/populate-from-fas.py
+++ b/populate-from-fas.py
@@ -7,11 +7,13 @@ import getpass
 import socket
 import string
 
+import fedora.client.fas2
+
 import hubs.models
+from hubs.utils import get_fedmsg_config
 
-import fedora.client.fas2
-import fedmsg.config
-fedmsg_config = fedmsg.config.load_config()
+
+fedmsg_config = get_fedmsg_config()
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
 fasclient = fedora.client.fas2.AccountSystem(
diff --git a/populate.py b/populate.py
index 08feaa3..1aa1c8b 100755
--- a/populate.py
+++ b/populate.py
@@ -7,9 +7,10 @@ import json
 
 import hubs.models
 import hubs.widgets
+from hubs.utils import get_fedmsg_config
 
-import fedmsg.config
-fedmsg_config = fedmsg.config.load_config()
+
+fedmsg_config = get_fedmsg_config()
 
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'], True, True)
 
diff --git a/tox.ini b/tox.ini
index 59d93a5..a6609a0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -12,12 +12,12 @@ deps =
     -rtest-requirements.txt
 setenv =
     HUBS_CONFIG={toxinidir}/hubs/tests/hubs_test.cfg
+    FEDMSG_CONFIG={toxinidir}/hubs/tests/fedmsg_test.cfg
     PYTHONPATH={toxinidir}
 whitelist_externals =
     rm
 commands =
-    rm -f /var/tmp/fedora-hubs-cache.db*
-    nosetests --with-coverage --cover-erase {posargs:hubs}
+    nosetests --with-coverage --cover-erase {posargs:hubs.tests}
     coverage html
 
 [testenv:js]

From 049c82708373ec32f50f5029bc5b0d4c0ee7c15b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 830/1001] Automatically set the env vars for testing


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 90913f1..0fd3ba9 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -13,10 +13,17 @@ import requests
 import vcr
 from flask.signals import template_rendered
 
-import hubs.models
-
+here = dirname(__file__)
 cassette_dir = os.path.join(dirname(__file__), 'vcr-request-data')
 
+if "HUBS_CONFIG" not in os.environ:
+    os.environ["HUBS_CONFIG"] = os.path.join(here, "hubs_test.cfg")
+if "FEDMSG_CONFIG" not in os.environ:
+    os.environ["FEDMSG_CONFIG"] = os.path.join(here, "fedmsg_test.cfg")
+
+import hubs.app     # noqa: E402
+import hubs.models  # noqa: E402
+
 
 class APPTest(unittest.TestCase):
     def setUp(self):
@@ -24,7 +31,6 @@ class APPTest(unittest.TestCase):
         self.vcr = vcr.use_cassette(filename, record_mode='new_episodes')
         self.vcr.__enter__()
 
-        import hubs.app
         hubs.app.session = hubs.models.init(
             hubs.app.fedmsg_config['hubs.sqlalchemy.uri'],
             create=True,

From 31ad3b93d5ebc4ed093be487d41309cf87c2cc90 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 831/1001] Tests: hubs.app.app is now safe to use


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 0fd3ba9..729db65 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -179,9 +179,7 @@ def captured_templates(app):
     usage.
 
     The argument is the signal emitter.  When calling a core Hubs view, this is
-    the Hubs app (``hubs.app.app`` or ``self.app.application`` if you're in an
-    :py:class:`APPTest` subclass).  If you're calling a widget view, the signal
-    emitter is the widget class, as found in the widgets registry.
+    the Hubs app (``hubs.app.app``).
 
     Args:
         app: The signal emitter.
diff --git a/hubs/tests/test_authz.py b/hubs/tests/test_authz.py
index ec607de..7a7c85a 100644
--- a/hubs/tests/test_authz.py
+++ b/hubs/tests/test_authz.py
@@ -1,5 +1,6 @@
 from __future__ import absolute_import, unicode_literals
 
+from hubs.app import app
 from hubs.authz import ObjectAuthzMixin, AccessLevel, PERMISSIONS
 from hubs.tests import APPTest, FakeAuthorization
 
@@ -18,10 +19,14 @@ class TestObj(ObjectAuthzMixin):
 
 class AuthzTestCase(APPTest):
 
-    def run(self, *args, **kwargs):
-        import hubs.app
-        with hubs.app.app.app_context():
-            super(AuthzTestCase, self).run(*args, **kwargs)
+    def setUp(self):
+        super(AuthzTestCase, self).setUp()
+        self.app_context = app.app_context()
+        self.app_context.__enter__()
+
+    def tearDown(self):
+        self.app_context.__exit__(None, None, None)
+        super(AuthzTestCase, self).tearDown()
 
     def test_mixin_access_level_anonymous(self):
         obj = TestObj()
diff --git a/hubs/tests/test_view_utils.py b/hubs/tests/test_view_utils.py
index 0101299..d445c28 100644
--- a/hubs/tests/test_view_utils.py
+++ b/hubs/tests/test_view_utils.py
@@ -1,21 +1,30 @@
 from __future__ import unicode_literals
 
 import hubs.models
+from hubs.app import app
 from hubs.tests import APPTest, FakeAuthorization, auth_set
 from hubs.views.utils import get_visible_widgets
 
 
 class ViewUtilsTest(APPTest):
 
+    def setUp(self):
+        super(ViewUtilsTest, self).setUp()
+        self.app_context = app.app_context()
+        self.app_context.__enter__()
+
+    def tearDown(self):
+        self.app_context.__exit__(None, None, None)
+        super(ViewUtilsTest, self).tearDown()
+
     def test_removed_widget(self):
         hub = hubs.models.Hub.get("ralph")
         widget = hubs.models.Widget(
             hub=hub, plugin="does-not-exist",
             left=True, index=-1, _config="{}")
         self.session.add(widget)
-        with auth_set(self.app.application, FakeAuthorization('ralph')):
-            with self.app.application.app_context():
-                widgets = get_visible_widgets(hub)
+        with auth_set(app, FakeAuthorization('ralph')):
+            widgets = get_visible_widgets(hub)
         self.assertNotIn(
             "does-not-exist", [w.plugin for w in widgets["left"]])
         widget.left = False
@@ -24,9 +33,8 @@ class ViewUtilsTest(APPTest):
 
     def test_get_visible_widgets(self):
         hub = hubs.models.Hub.get('ralph')
-        with auth_set(self.app.application, None):
-            with self.app.application.app_context():
-                widgets = get_visible_widgets(hub)
+        with auth_set(app, None):
+            widgets = get_visible_widgets(hub)
         self.assertListEqual(
             [w.plugin for w in widgets["left"]],
             ["feed"])
@@ -48,15 +56,13 @@ class ViewUtilsTest(APPTest):
         meetings.visibility = "restricted"
         # Restricted widgets in preview hubs aren't displayed to
         # anonymous users.
-        with auth_set(self.app.application, None):
-            with self.app.application.app_context():
-                widgets = get_visible_widgets(hub)
+        with auth_set(app, None):
+            widgets = get_visible_widgets(hub)
         self.assertNotIn(
             "meetings", [w.plugin for w in widgets["right"]])
         # But they are displayed to members.
-        with auth_set(self.app.application, FakeAuthorization('ralph')):
-            with self.app.application.app_context():
-                widgets = get_visible_widgets(hub)
+        with auth_set(app, FakeAuthorization('ralph')):
+            widgets = get_visible_widgets(hub)
         self.assertIn(
             "meetings", [w.plugin for w in widgets["right"]])
 
@@ -69,14 +75,12 @@ class ViewUtilsTest(APPTest):
         assert meetings.left is False
         # Widgets in private hubs aren't displayed to
         # anonymous users.
-        with auth_set(self.app.application, None):
-            with self.app.application.app_context():
-                widgets = get_visible_widgets(hub)
+        with auth_set(app, None):
+            widgets = get_visible_widgets(hub)
         self.assertEqual(widgets["left"], [])
         self.assertEqual(widgets["right"], [])
         # But they are displayed to members.
-        with auth_set(self.app.application, FakeAuthorization('ralph')):
-            with self.app.application.app_context():
-                widgets = get_visible_widgets(hub)
+        with auth_set(app, FakeAuthorization('ralph')):
+            widgets = get_visible_widgets(hub)
         self.assertNotEqual(len(widgets["left"]), 0)
         self.assertNotEqual(len(widgets["right"]), 0)
diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index 53d1bf8..832c2f8 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -1,14 +1,14 @@
 from __future__ import unicode_literals
 
 import six
+from mock import Mock
 
+from hubs.app import app
+from hubs.tests import APPTest
 from hubs.widgets.base import Widget
 from hubs.widgets.caching import CachedFunction
 from hubs.widgets.view import WidgetView
 
-from mock import Mock
-from hubs.tests import APPTest
-
 
 class TestingWidget(Widget):
     name = "testing"
@@ -28,14 +28,14 @@ class WidgetTest(APPTest):
         super(WidgetTest, self).setUp()
         # Backup the URL map
         self._old_url_map = (
-            self.app.application.url_map._rules[:],
-            self.app.application.url_map._rules_by_endpoint.copy()
+            app.url_map._rules[:],
+            app.url_map._rules_by_endpoint.copy()
             )
 
     def tearDown(self):
         # Restore the URL map
-        self.app.application.url_map._rules = self._old_url_map[0]
-        self.app.application.url_map._rules_by_endpoint = self._old_url_map[1]
+        app.url_map._rules = self._old_url_map[0]
+        app.url_map._rules_by_endpoint = self._old_url_map[1]
         super(WidgetTest, self).tearDown()
 
     def test_validate(self):
@@ -126,23 +126,17 @@ class WidgetTest(APPTest):
             "root": TestView1(testing_widget),
             "test2": TestView2(testing_widget),
         }
-        testing_widget.register_routes(self.app.application)
+        testing_widget.register_routes(app)
         # TestView1
-        self.assertIn("testing_root",
-                      self.app.application.url_map._rules_by_endpoint)
-        self.assertIn("testing_root", self.app.application.view_functions)
-        rules = list(
-            self.app.application.url_map.iter_rules(endpoint="testing_root")
-            )
+        self.assertIn("testing_root", app.url_map._rules_by_endpoint)
+        self.assertIn("testing_root", app.view_functions)
+        rules = list(app.url_map.iter_rules(endpoint="testing_root"))
         self.assertEqual(len(rules), 2)
         self.assertEqual(rules[0].rule, "/<hub>/w/testing/<int:idx>/")
         self.assertEqual(rules[1].rule, "/<hub>/w/testing/<int:idx>/test-1/")
         # TestView2
-        self.assertIn("testing_test2",
-                      self.app.application.url_map._rules_by_endpoint)
-        self.assertIn("testing_test2", self.app.application.view_functions)
-        rules = list(
-            self.app.application.url_map.iter_rules(endpoint="testing_test2")
-            )
+        self.assertIn("testing_test2", app.url_map._rules_by_endpoint)
+        self.assertIn("testing_test2", app.view_functions)
+        rules = list(app.url_map.iter_rules(endpoint="testing_test2"))
         self.assertEqual(len(rules), 1)
         self.assertEqual(rules[0].rule, "/<hub>/w/testing/<int:idx>/test-2")
diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index ed60356..a9d296d 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals, absolute_import
 
 import json
 
+from hubs.app import app
 from hubs.models import Hub, User
 from hubs.tests import FakeAuthorization
 from hubs.widgets import registry
@@ -341,7 +342,7 @@ class HalpFunctionsTestCase(WidgetTest):
         self.session.commit()
 
     def test_execute(self):
-        with self.app.application.test_request_context('/'):
+        with app.test_request_context('/'):
             result = self.func.execute()
         self.assertEqual(result, SAMPLE_DATA)
 
@@ -379,7 +380,7 @@ class PaginateTestCase(WidgetTest):
         self.values = ["A", "B", "C", "D"]
 
     def test_base(self):
-        with self.app.application.test_request_context('/'):
+        with app.test_request_context('/'):
             result = self.paginate(self.values, 3)
         self.assertListEqual(result[0], self.values[:3])
         self.assertDictEqual(result[1], {
@@ -391,7 +392,7 @@ class PaginateTestCase(WidgetTest):
             })
 
     def test_page_2(self):
-        with self.app.application.test_request_context('/?page=2'):
+        with app.test_request_context('/?page=2'):
             result = self.paginate(self.values, 3)
         self.assertListEqual(result[0], self.values[3:])
         self.assertDictEqual(result[1], {
@@ -403,7 +404,7 @@ class PaginateTestCase(WidgetTest):
             })
 
     def test_page_0(self):
-        with self.app.application.test_request_context('/?page=0'):
+        with app.test_request_context('/?page=0'):
             result = self.paginate(self.values, 3)
         self.assertListEqual(result[0], self.values[:3])
         self.assertDictEqual(result[1], {
@@ -415,7 +416,7 @@ class PaginateTestCase(WidgetTest):
             })
 
     def test_invalid_page(self):
-        with self.app.application.test_request_context('/?page=blah'):
+        with app.test_request_context('/?page=blah'):
             result = self.paginate(self.values, 3)
         self.assertListEqual(result[0], self.values[:3])
         self.assertDictEqual(result[1], {
@@ -427,7 +428,7 @@ class PaginateTestCase(WidgetTest):
             })
 
     def test_page_too_high(self):
-        with self.app.application.test_request_context('/?page=3'):
+        with app.test_request_context('/?page=3'):
             result = self.paginate(self.values, 3)
         self.assertListEqual(result[0], self.values[3:])
         self.assertDictEqual(result[1], {
@@ -440,7 +441,7 @@ class PaginateTestCase(WidgetTest):
 
     def test_single_page(self):
         values = self.values[:3]
-        with self.app.application.test_request_context('/'):
+        with app.test_request_context('/'):
             result = self.paginate(values, 3)
         self.assertListEqual(result[0], values)
         self.assertDictEqual(result[1], {
@@ -453,7 +454,7 @@ class PaginateTestCase(WidgetTest):
 
     def test_no_value(self):
         values = []
-        with self.app.application.test_request_context('/'):
+        with app.test_request_context('/'):
             result = self.paginate(values, 3)
         self.assertListEqual(result[0], [])
         self.assertDictEqual(result[1], {

From c2ffc620bdc98731f74551f242892b1747127bda Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 832/1001] Tests: fix auth_set when the context is already pushed


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 729db65..afe1f2f 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -137,7 +137,13 @@ def auth_set(APP, auth):
         if not auth:
             g.auth = munch.Munch(logged_in=False, user=None)
 
-    with appcontext_pushed.connected_to(handler, APP):
+    if flask._app_ctx_stack.top is None:
+        # App context isn't pushed yet
+        with appcontext_pushed.connected_to(handler, APP):
+            yield
+    else:
+        # App context already pushed
+        handler(APP)
         yield
 
 

From a788a25214fb523bb71014877fceb627a89b552e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:05:20 +0000
Subject: [PATCH 833/1001] Minor refactoring


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index afe1f2f..2630d8c 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -26,9 +26,10 @@ import hubs.models  # noqa: E402
 
 
 class APPTest(unittest.TestCase):
+
     def setUp(self):
-        filename = os.path.join(cassette_dir, self.id())
-        self.vcr = vcr.use_cassette(filename, record_mode='new_episodes')
+        vcr_filename = os.path.join(cassette_dir, self.id())
+        self.vcr = vcr.use_cassette(vcr_filename, record_mode='new_episodes')
         self.vcr.__enter__()
 
         hubs.app.session = hubs.models.init(
@@ -36,26 +37,28 @@ class APPTest(unittest.TestCase):
             create=True,
         )
         hubs.app.app.config['TESTING'] = True
+
         self.app = hubs.app.app.test_client()
         self.app.testing = True
         self.session = hubs.app.session
+
         self.populate()
 
     def tearDown(self):
-        self.vcr.__exit__()
         self.session.remove()
+        self.vcr.__exit__()
 
     def populate(self):
         for user in ['devyani7', 'dhrish', 'shalini', 'ralph', 'decause']:
             fullname = user.title()
             hubs.models.User.get_or_create(
-                hubs.app.session, username=user, fullname=fullname)
+                self.session, username=user, fullname=fullname)
             saved_notif = hubs.models.SavedNotification(
                 username=user, markup='foo', link='bar'
             )
-            hubs.app.session.add(saved_notif)
+            self.session.add(saved_notif)
 
-        hubs.app.session.flush()
+        self.session.flush()
 
         hub = hubs.models.Hub.by_name('ralph')
         widget = hubs.models.Widget(
@@ -71,13 +74,13 @@ class APPTest(unittest.TestCase):
                 hub.last_refreshed = datetime.utcnow() - timedelta(days=100)
                 hub.last_updated = datetime.utcnow() - timedelta(days=200)
 
-            hubs.app.session.add(hub)
-            hubs.app.session.add(
+            self.session.add(hub)
+            self.session.add(
                 hubs.models.HubConfig(hub=hub, summary="the %s team" % team))
             widget = hubs.models.Widget(plugin='meetings', index=11,
                                         _config=json.dumps({'calendar': team}))
             hub.widgets.append(widget)
-        hubs.app.session.commit()
+        self.session.commit()
 
     # TODO - test that it is in the registry
     # TODO - test that it has all the things it needs
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
index 1821026..94f7ef0 100644
--- a/hubs/views/utils.py
+++ b/hubs/views/utils.py
@@ -53,13 +53,13 @@ def get_widget_instance(hub, idx, session=None):
 def get_visible_widgets(hub):
     from hubs.widgets import registry
     widgets = {"left": [], "right": []}
+    try:
+        user = flask.g.auth.user
+    except AttributeError:
+        user = None
     for widget in hub.widgets:
         if widget.plugin not in registry:
             continue  # disabled widget
-        try:
-            user = flask.g.auth.user
-        except AttributeError:
-            user = None
         if not widget.allows(user, "view"):
             continue
         if widget.left:

From ae34ea4dd2bb8c9e78878516914111c8fc677e92 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:07:32 +0000
Subject: [PATCH 834/1001] Don't confuse the app and the current_app proxy in signals


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 2630d8c..6680c2c 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -104,9 +104,8 @@ class APPTest(unittest.TestCase):
 
     def check_url(self, url, user=None, code=200):
         with auth_set(hubs.app.app, user):
-            with hubs.app.app.app_context():
-                with captured_templates(flask.current_app) as templates:
-                    response = self.app.get(url)
+            with captured_templates(hubs.app.app) as templates:
+                response = self.app.get(url)
         self.assertEqual(response.status_code, code)
         if templates:
             self.assertEqual(len(templates), 1)
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index 11ae36e..2b5b2b4 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -195,10 +195,13 @@ def add_view(hub):
         )
     initial["hubs"] = [hub.name]
     context = dict(mode="add", url=post_url, initial=initial)
+    # Mimic flask.templating._render(). Too bad it's not a public API.
     if before_render_template is not None:
         before_render_template.send(
-            flask.current_app, template=template, context=context)
+            flask._app_ctx_stack.top.app,
+            template=template, context=context)
     output = template.render(**context)
     template_rendered.send(
-        flask.current_app, template=template, context=context)
+        flask._app_ctx_stack.top.app,
+        template=template, context=context)
     return output
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index 4fdb936..65d91c5 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -125,10 +125,13 @@ class WidgetView(View):
         else:
             context.update(self.get_extra_context(instance, *args, **kwargs))
             template = self.get_template()
+            # Mimic flask.templating._render(). Too bad it's not a public API.
             if before_render_template is not None:
                 before_render_template.send(
-                    flask.current_app, template=template, context=context)
+                    flask._app_ctx_stack.top.app,
+                    template=template, context=context)
             output = template.render(**context)
             template_rendered.send(
-                flask.current_app, template=template, context=context)
+                flask._app_ctx_stack.top.app,
+                template=template, context=context)
             return output

From 56848a0bc7aa80d66a5b7fea34c495d6f1c58e09 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 04 2017 22:07:32 +0000
Subject: [PATCH 835/1001] Don't use TestCase methods when it's not necessary


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 6680c2c..c060b42 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -85,23 +85,6 @@ class APPTest(unittest.TestCase):
     # TODO - test that it is in the registry
     # TODO - test that it has all the things it needs
 
-    def widget_instance(self, hubname, plugin):
-        hub = hubs.models.Hub.by_name(hubname)
-        if not hub:
-            raise ValueError("No such hub %r" % hubname)
-        for widget in hub.widgets:
-            if widget.plugin == plugin:
-                return widget
-        raise KeyError("No such widget found for %s/%s" % (hubname, plugin))
-
-    @staticmethod
-    def get_fedmsg(idx):
-        url = 'https://apps.fedoraproject.org/datagrepper/id'
-        response = requests.get(url, params=dict(id=idx))
-        if not bool(response):
-            raise IOError("Failed to talk to %r %r" % (response.url, response))
-        return response.json()
-
     def check_url(self, url, user=None, code=200):
         with auth_set(hubs.app.app, user):
             with captured_templates(hubs.app.app) as templates:
@@ -117,6 +100,24 @@ class APPTest(unittest.TestCase):
         return response
 
 
+def get_fedmsg(idx):
+    url = 'https://apps.fedoraproject.org/datagrepper/id'
+    response = requests.get(url, params=dict(id=idx))
+    if not bool(response):
+        raise IOError("Failed to talk to %r %r" % (response.url, response))
+    return response.json()
+
+
+def widget_instance(hubname, plugin):
+    hub = hubs.models.Hub.by_name(hubname)
+    if not hub:
+        raise ValueError("No such hub %r" % hubname)
+    for widget in hub.widgets:
+        if widget.plugin == plugin:
+            return widget
+    raise KeyError("No such widget found for %s/%s" % (hubname, plugin))
+
+
 @contextmanager
 def auth_set(APP, auth):
     """
diff --git a/hubs/tests/widgets/__init__.py b/hubs/tests/widgets/__init__.py
index 7d171e4..653e9d6 100644
--- a/hubs/tests/widgets/__init__.py
+++ b/hubs/tests/widgets/__init__.py
@@ -4,7 +4,7 @@ import json
 import unittest
 
 import hubs.models
-from hubs.tests import APPTest, FakeAuthorization
+from hubs.tests import APPTest, FakeAuthorization, widget_instance
 
 
 class WidgetTest(APPTest):
@@ -28,7 +28,7 @@ class WidgetTest(APPTest):
         if not self.plugin:
             raise unittest.SkipTest
         hub = hubs.models.Hub.query.get("ralph")
-        widget = self.widget_instance(hub.name, self.plugin)
+        widget = widget_instance(hub.name, self.plugin)
         url = '/%s/w/%s/%i/' % (hub.name, self.plugin, widget.idx)
         # Public
         self.check_url(url, None, 200)
diff --git a/hubs/tests/widgets/test_about.py b/hubs/tests/widgets/test_about.py
index dd00e20..0766de2 100644
--- a/hubs/tests/widgets/test_about.py
+++ b/hubs/tests/widgets/test_about.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import json
 
-from hubs.tests import FakeAuthorization
+from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
 
 
@@ -10,7 +10,7 @@ class TestAbout(WidgetTest):
     plugin = 'about'  # The name in hubs.widgets.registry
 
     def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
+        widget = widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
         response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
diff --git a/hubs/tests/widgets/test_badges.py b/hubs/tests/widgets/test_badges.py
index 3cd2ee2..d460a1f 100644
--- a/hubs/tests/widgets/test_badges.py
+++ b/hubs/tests/widgets/test_badges.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import json
 
 import hubs.widgets
-from hubs.tests import FakeAuthorization
+from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
 
 
@@ -11,7 +11,7 @@ class TestBadges(WidgetTest):
     plugin = 'badges'  # The name in hubs.widgets.registry
 
     def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
+        widget = widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
         response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
@@ -19,8 +19,9 @@ class TestBadges(WidgetTest):
         self.assertIn('assertions', data['data'].keys())
 
     def test_should_invalidate_wrong_topic(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        # msg = self.get_fedmsg('2016-ebb84660-59e9-4e68-af8f-4e6f49348b88')
+        widget = widget_instance('ralph', self.plugin)
+        # from hubs.tests import get_fedmsg
+        # msg = get_fedmsg('2016-ebb84660-59e9-4e68-af8f-4e6f49348b88')
         msg = {'topic': 'hubs.widget.update.WRONG.TOPIC'}
         module = hubs.widgets.registry[widget.plugin]
         func = module.get_cached_functions()['GetBadges']
@@ -28,8 +29,9 @@ class TestBadges(WidgetTest):
         self.assertFalse(result)
 
     def test_should_invalidate_wrong_user(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        # msg = self.get_fedmsg('2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f')
+        widget = widget_instance('ralph', self.plugin)
+        # from hubs.tests import get_fedmsg
+        # msg = get_fedmsg('2016-e371c7f6-bc8e-4632-8e33-b9102dc30b5f')
         msg = {'topic': 'fedbadges.badge.award',
                'msg': {'user': {'username': 'not_ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
@@ -38,8 +40,9 @@ class TestBadges(WidgetTest):
         self.assertFalse(result)
 
     def test_should_invalidate_good_match_fedbadges(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
+        widget = widget_instance('ralph', self.plugin)
+        # from hubs.tests import get_fedmsg
+        # msg = get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
         msg = {'topic': 'fedbadges.badge.award',
                'msg': {'user': {'username': 'ralph'}}}
         module = hubs.widgets.registry[widget.plugin]
@@ -48,8 +51,9 @@ class TestBadges(WidgetTest):
         self.assertTrue(result)
 
     def test_should_invalidate_good_match_hubswidget(self):
-        widget = self.widget_instance('ralph', self.plugin)
-        # msg = self.get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
+        widget = widget_instance('ralph', self.plugin)
+        # from hubs.tests import get_fedmsg
+        # msg = get_fedmsg('2016-1fbb1135-681b-4d3b-9a40-d0f6ebd313f4')
         msg = {'topic': 'hubs.widget.update',
                'msg': {'widget': {'id': widget.idx + 1}}}
         module = hubs.widgets.registry[widget.plugin]
diff --git a/hubs/tests/widgets/test_fedmsgstats.py b/hubs/tests/widgets/test_fedmsgstats.py
index 87b5ae0..c7f7ce2 100644
--- a/hubs/tests/widgets/test_fedmsgstats.py
+++ b/hubs/tests/widgets/test_fedmsgstats.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import json
 
-from hubs.tests import FakeAuthorization
+from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
 
 
@@ -10,7 +10,7 @@ class TestFedmsgStats(WidgetTest):
     plugin = 'fedmsgstats'  # The name in hubs.widgets.registry
 
     def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
+        widget = widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
         response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index a9d296d..2e33ade 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -4,7 +4,7 @@ import json
 
 from hubs.app import app
 from hubs.models import Hub, User
-from hubs.tests import FakeAuthorization
+from hubs.tests import FakeAuthorization, widget_instance
 from hubs.widgets import registry
 from . import WidgetTest
 
@@ -84,7 +84,7 @@ class HalpViewsTestCase(WidgetTest):
 
     def setUp(self):
         super(HalpViewsTestCase, self).setUp()
-        self.widget = self.widget_instance('ralph', self.plugin)
+        self.widget = widget_instance('ralph', self.plugin)
         config = self.widget.config
         config["hubs"] = ["fedora-devel"]
         config["per_page"] = 3
@@ -330,7 +330,7 @@ class HalpFunctionsTestCase(WidgetTest):
         super(HalpFunctionsTestCase, self).setUp()
         module = registry[self.plugin]
         func_class = module.get_cached_functions()['GetRequests']
-        self.widget = self.widget_instance('ralph', self.plugin)
+        self.widget = widget_instance('ralph', self.plugin)
         self.func = func_class(self.widget)
         # The tested widget watches the infra hub.
         config = self.widget.config
diff --git a/hubs/tests/widgets/test_library.py b/hubs/tests/widgets/test_library.py
index 6d85ad2..f8651e4 100644
--- a/hubs/tests/widgets/test_library.py
+++ b/hubs/tests/widgets/test_library.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import json
 
-from hubs.tests import FakeAuthorization
+from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
 
 
@@ -10,7 +10,7 @@ class TestLibrary(WidgetTest):
     plugin = 'library'  # The name in hubs.widgets.registry
 
     def test_data_simple(self):
-        widget = self.widget_instance('ralph', self.plugin)
+        widget = widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
         response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
diff --git a/hubs/tests/widgets/test_meetings.py b/hubs/tests/widgets/test_meetings.py
index 49f088b..0ac32a6 100644
--- a/hubs/tests/widgets/test_meetings.py
+++ b/hubs/tests/widgets/test_meetings.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import json
 
-from hubs.tests import FakeAuthorization
+from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
 
 
@@ -11,7 +11,7 @@ class TestMeetings(WidgetTest):
 
     def test_data_simple(self):
         team = 'i18n'
-        widget = self.widget_instance(team, self.plugin)
+        widget = widget_instance(team, self.plugin)
         user = FakeAuthorization('ralph')
         response = self.check_url('/%s/%i/json' % (team, widget.idx), user)
         data = json.loads(response.get_data(as_text=True))
@@ -20,7 +20,7 @@ class TestMeetings(WidgetTest):
 
     def test_render_simple(self):
         team = 'i18n'
-        widget = self.widget_instance(team, self.plugin)
+        widget = widget_instance(team, self.plugin)
         user = FakeAuthorization('ralph')
         url = '/%s/w/%s/%i/' % (team, self.plugin, widget.idx)
         response = self.check_url(url, user)

From d305efbdbae5f28a7c7e4888f2ed413e6d9739cb Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 10 2017 07:28:34 +0000
Subject: [PATCH 836/1001] Reorganize the utils modules to avoid circular imports


---

diff --git a/docs/api/views.rst b/docs/api/views.rst
index 08a2a90..4c205af 100644
--- a/docs/api/views.rst
+++ b/docs/api/views.rst
@@ -4,6 +4,6 @@ Views
 View utils
 ----------
 
-.. automodule:: hubs.views.utils
+.. automodule:: hubs.utils.views
    :members:
 
diff --git a/hubs/tests/test_view_utils.py b/hubs/tests/test_view_utils.py
index d445c28..64b6aee 100644
--- a/hubs/tests/test_view_utils.py
+++ b/hubs/tests/test_view_utils.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import hubs.models
 from hubs.app import app
 from hubs.tests import APPTest, FakeAuthorization, auth_set
-from hubs.views.utils import get_visible_widgets
+from hubs.utils.views import get_visible_widgets
 
 
 class ViewUtilsTest(APPTest):
diff --git a/hubs/utils.py b/hubs/utils.py
deleted file mode 100755
index 4fa5f1f..0000000
--- a/hubs/utils.py
+++ /dev/null
@@ -1,93 +0,0 @@
-from __future__ import unicode_literals
-
-import arrow
-import logging
-import markdown
-import os
-import requests
-from hashlib import sha256
-
-import fedmsg.config
-import fedmsg.meta
-from six.moves.urllib_parse import urlencode
-
-log = logging.getLogger(__name__)
-
-
-def get_fedmsg_config():
-    try:
-        filenames = [os.environ["FEDMSG_CONFIG"]]
-    except KeyError:
-        filenames = None
-    fedmsg_config = fedmsg.config.load_config(filenames=filenames)
-    fedmsg.meta.make_processors(**fedmsg_config)
-    return fedmsg_config
-
-
-def markup(text):
-    return markdown.markdown(
-        text,
-        safe_mode="replace",
-        html_replacement_text="--RAW HTML NOT ALLOWED--")
-
-
-def username2avatar(username, s=312):
-    query = urlencode([('s', s), ('d', 'retro')])
-    openid = 'http://%s.id.fedoraproject.org/' % username
-    hash = sha256(openid.encode('utf-8')).hexdigest()
-    avatar = "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)
-    return avatar
-
-
-def commas(numeric):
-    return "{:,}".format(numeric)
-
-
-def github_repos(token, username):
-    log.info("Finding github repos for %r" % username)
-    tmpl = "https://api.github.com/users/{username}/repos?per_page=100"
-    url = tmpl.format(username=username)
-    auth = dict(access_token=token)
-    for result in _github_results(url, auth):
-        yield result['name']
-
-
-def github_pulls(token, username, repo):
-    log.info("Finding github pull requests for %r %r" % (username, repo))
-    tmpl = "https://api.github.com/repos/{username}/{repo}/" + \
-        "pulls?per_page=100"
-    url = tmpl.format(username=username, repo=repo)
-    auth = dict(access_token=token)
-    for result in _github_results(url, auth):
-        yield dict(
-            user=result['user']['login'],
-            title=result['title'],
-            url=result['html_url'],
-            number=result['number'],
-            assignee=result['assignee'],
-            timestamp=arrow.get(result['created_at']).timestamp,
-        )
-
-
-def _github_results(url, auth):
-    link = dict(next=url)
-    while 'next' in link:
-        response = requests.get(link['next'], params=auth)
-
-        # And.. if we didn't get good results, just bail.
-        if not bool(response):
-            raise IOError("Failed on %r %r" % (link['next'], response))
-
-        results = response.json()
-        for result in results:
-            yield result
-
-        field = response.headers.get('link', None)
-        link = dict()
-        if field:
-            link = dict([
-                (
-                    part.split('; ')[1][5:-1],
-                    part.split('; ')[0][1:-1],
-                ) for part in field.split(', ')
-            ])
diff --git a/hubs/utils/__init__.py b/hubs/utils/__init__.py
new file mode 100755
index 0000000..8713806
--- /dev/null
+++ b/hubs/utils/__init__.py
@@ -0,0 +1,26 @@
+from __future__ import unicode_literals
+
+import os
+from hashlib import sha256
+
+import fedmsg.config
+import fedmsg.meta
+from six.moves.urllib_parse import urlencode
+
+
+def get_fedmsg_config():
+    try:
+        filenames = [os.environ["FEDMSG_CONFIG"]]
+    except KeyError:
+        filenames = None
+    fedmsg_config = fedmsg.config.load_config(filenames=filenames)
+    fedmsg.meta.make_processors(**fedmsg_config)
+    return fedmsg_config
+
+
+def username2avatar(username, s=312):
+    query = urlencode([('s', s), ('d', 'retro')])
+    openid = 'http://%s.id.fedoraproject.org/' % username
+    hash = sha256(openid.encode('utf-8')).hexdigest()
+    avatar = "https://seccdn.libravatar.org/avatar/%s?%s" % (hash, query)
+    return avatar
diff --git a/hubs/utils/github.py b/hubs/utils/github.py
new file mode 100644
index 0000000..47c1018
--- /dev/null
+++ b/hubs/utils/github.py
@@ -0,0 +1,59 @@
+from __future__ import unicode_literals
+
+import logging
+
+import arrow
+import requests
+
+
+log = logging.getLogger(__name__)
+
+
+def github_repos(token, username):
+    log.info("Finding github repos for %r" % username)
+    tmpl = "https://api.github.com/users/{username}/repos?per_page=100"
+    url = tmpl.format(username=username)
+    auth = dict(access_token=token)
+    for result in _github_results(url, auth):
+        yield result['name']
+
+
+def github_pulls(token, username, repo):
+    log.info("Finding github pull requests for %r %r" % (username, repo))
+    tmpl = "https://api.github.com/repos/{username}/{repo}/" + \
+        "pulls?per_page=100"
+    url = tmpl.format(username=username, repo=repo)
+    auth = dict(access_token=token)
+    for result in _github_results(url, auth):
+        yield dict(
+            user=result['user']['login'],
+            title=result['title'],
+            url=result['html_url'],
+            number=result['number'],
+            assignee=result['assignee'],
+            timestamp=arrow.get(result['created_at']).timestamp,
+        )
+
+
+def _github_results(url, auth):
+    link = dict(next=url)
+    while 'next' in link:
+        response = requests.get(link['next'], params=auth)
+
+        # And.. if we didn't get good results, just bail.
+        if not bool(response):
+            raise IOError("Failed on %r %r" % (link['next'], response))
+
+        results = response.json()
+        for result in results:
+            yield result
+
+        field = response.headers.get('link', None)
+        link = dict()
+        if field:
+            link = dict([
+                (
+                    part.split('; ')[1][5:-1],
+                    part.split('; ')[0][1:-1],
+                ) for part in field.split(', ')
+            ])
diff --git a/hubs/utils/text.py b/hubs/utils/text.py
new file mode 100644
index 0000000..ad8fc55
--- /dev/null
+++ b/hubs/utils/text.py
@@ -0,0 +1,15 @@
+from __future__ import unicode_literals
+
+
+import markdown
+
+
+def markup(text):
+    return markdown.markdown(
+        text,
+        safe_mode="replace",
+        html_replacement_text="--RAW HTML NOT ALLOWED--")
+
+
+def commas(numeric):
+    return "{:,}".format(numeric)
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
new file mode 100644
index 0000000..2ceb399
--- /dev/null
+++ b/hubs/utils/views.py
@@ -0,0 +1,288 @@
+"""
+This module contains helper functions and classes for the views.
+"""
+
+from __future__ import unicode_literals
+
+import datetime
+import functools
+import logging
+
+import flask
+from six.moves.urllib import parse as urlparse
+from sqlalchemy.orm import joinedload
+from sqlalchemy.orm.exc import NoResultFound
+
+from hubs.models import Hub, Widget
+
+
+log = logging.getLogger(__name__)
+
+
+def get_hub(name, load_config=False, session=None):
+    """ Utility shorthand to get a hub and 404 if not found. """
+    if session is None:
+        session = flask.g.db
+    query = session.query(Hub).filter(Hub.name == name)
+    if load_config:
+        query = query.options(joinedload(Hub.config))
+    try:
+        return query.one()
+    except NoResultFound:
+        flask.abort(404)
+
+
+def get_widget_instance(hub, idx, session=None):
+    """ Utility shorthand to get a widget and 404 if not found. """
+    if session is None:
+        session = flask.g.db
+    try:
+        idx = int(idx)
+    except (TypeError, ValueError):
+        flask.abort(400)
+    try:
+        return session.query(Widget).join(Hub).filter(
+                Hub.name == hub,
+                Widget.idx == idx,
+            ).one()
+    except NoResultFound:
+        flask.abort(404)
+
+
+def get_visible_widgets(hub):
+    from hubs.widgets import registry
+    widgets = {"left": [], "right": []}
+    try:
+        user = flask.g.auth.user
+    except AttributeError:
+        user = None
+    for widget in hub.widgets:
+        if widget.plugin not in registry:
+            continue  # disabled widget
+        if not widget.allows(user, "view"):
+            continue
+        if widget.left:
+            widgets["left"].append(widget)
+        else:
+            widgets["right"].append(widget)
+    widgets["left"].sort(key=lambda w: w.index)
+    widgets["right"].sort(key=lambda w: w.index)
+    return widgets
+
+
+class WidgetConfigError(Exception):
+    pass
+
+
+def create_widget_instance(hub, widget, position):
+    """View helper to instanciate a widget on a hub.
+
+    Arguments:
+        hub (hubs.models.Hub): Instance of the hub to create the widget in.
+        widget (hubs.widgets.base.Widget): Widget to instanciate.
+        position (str): either ``left`` or ``right``.
+    """
+    widget_instance = Widget(
+        hub=hub, plugin=widget.name, index=-1,
+        left=(position == 'left'))
+    flask.g.db.add(widget_instance)
+    flask.g.db.flush()  # will populate Widget.config
+    try:
+        configure_widget_instance(widget_instance)
+    except WidgetConfigError as e:
+        flask.flash(e.args[0], "error")
+    else:
+        flask.flash("The widget has been added.")
+
+
+def configure_widget_instance(widget_instance):
+    """Configure a widget instance using the request form data.
+
+    Arguments:
+        widget_instance (hubs.models.Widget): Instance of the widget that is to
+            be configured.
+    """
+    config = {}
+    for param in widget_instance.module.get_parameters():
+        val = flask.request.form.get(param.name)
+        if not val:
+            raise WidgetConfigError(
+                'You must provide a value for: %s' % param.name)
+        try:
+            config[param.name] = param.validator.from_string(val)
+        except ValueError as err:
+            raise WidgetConfigError('Invalid data provided, error: %s' % err)
+    # Updating in-place is not supported, it's a class property.
+    cur_config = widget_instance.config or {}
+    cur_config = cur_config.copy()
+    cur_config.update(config)
+    widget_instance.config = cur_config
+    # Set the visibility parameter.
+    try:
+        widget_instance.visibility = flask.request.form["visibility"]
+    except KeyError:
+        pass  # the value is optional.
+    # Update the hub's mtime.  TODO: use a SQLAlchemy signal here.
+    widget_instance.hub.last_edited = datetime.datetime.utcnow()
+    try:
+        flask.g.db.commit()
+    except Exception as err:
+        log.warn(
+            "Could not save the configuration of widget "
+            "%s to the database: %s.",
+            widget_instance.idx, err)
+        raise WidgetConfigError(
+            'Could not save the configuration to the database '
+            'if the error persists, please warn an admin')
+
+
+def authenticated():
+    """ Utility function checking if the current auth is set or not."""
+    return hasattr(flask.g, 'auth') \
+        and flask.g.auth is not None \
+        and flask.g.auth.logged_in
+
+
+def login_required(function):
+    """ Flask decorator to restrict access to logged-in users. """
+
+    @functools.wraps(function)
+    def decorated_function(*args, **kwargs):
+        """ Decorated function, actually does the work. """
+        if not authenticated():
+            return flask.redirect(flask.url_for(
+                'login', next=flask.request.url))
+
+        return function(*args, **kwargs)
+
+    return decorated_function
+
+
+def require_hub_access(action, url_param="name", json=False):
+    """Check access to the hub for the specified action."""
+    def decorator(function):
+        @functools.wraps(function)
+        def wrapper(*args, **kwargs):
+            hub_name = kwargs[url_param]
+            hub = get_hub(hub_name, load_config=True)
+            try:
+                user = flask.g.auth.user
+            except AttributeError:
+                user = None
+            if not hub.allows(user, action):
+                if action == "view":
+                    msg = "This hub is for members only."
+                elif action == "config":
+                    msg = "You are not allowed to configure this hub."
+                else:
+                    msg = "Access forbidden."
+                if json:
+                    result = flask.jsonify({
+                        "status": "ERROR", "message": msg, "hub": hub.name,
+                        })
+                else:
+                    result = flask.render_template(
+                        'errors/hub.html', hub=hub, msg=msg,
+                        )
+                return result, 403
+            return function(*args, **kwargs)
+        return wrapper
+    return decorator
+
+
+def is_safe_url(target):
+    """ Checks that the target url is safe and sending to the current
+    website not some other malicious one.
+    """
+    ref_url = urlparse.urlparse(flask.request.host_url)
+    test_url = urlparse.urlparse(
+        urlparse.urljoin(flask.request.host_url, target))
+    return test_url.scheme in ('http', 'https') and \
+        ref_url.netloc == test_url.netloc
+
+
+def get_position():
+    # Use request.values instead of request.form to allow the position to be
+    # passed in the query string.
+    position = flask.request.values.get('position', '')
+    if position not in ['right', 'left']:
+        flask.abort(400, 'Invalid position provided')
+    return position
+
+
+class RequestValidator(object):
+    """Validate a request's POST data.
+
+    Instantiate this class with a dictionnary mapping POST data keys (found in
+    ``flask.request.form``) to a function that will validate and convert them.
+
+    POST data can be validated by calling the instance and passing the data as
+    an argument.  The instance will return a mapping of keys to converted
+    values if all validations are successful.
+
+    A validation function can raise a :py:exc:`ValueError` if the value is not
+    valid. In this case, the :py:class:`RequestValidator` instance will collect
+    the error messages in a dictionary mapping failed request keys to messages,
+    and raise a :py:exc:`ValueError` with this dictionary.
+
+    If the function is None, the value is returned unchanged. If a posted value
+    is not present in the conversion mapping the class was instantiated with,
+    an error will be raised.
+
+    A typical usage of this class is::
+
+        validator = RequestValidator({"number": int})
+        try:
+            values = validator(flask.request.form)
+        except ValueError as e:
+            failed_fields = e.args[0]
+            return flask.jsonify(failed_fields), 400
+        # Do something with the validated values.
+        for key, value in values.items():
+            setattr(model_instance, key, value)
+
+    In this example:
+
+    - if the posted data was ``number=1``, the resulting ``values`` variable
+      would be ``{"number": 1}``.
+    - if the posted data was ``number=foobar``, a :py:exc:`ValueError` would be
+      raised, ``failed_fields`` would be ``{"number": "error message"}``.
+    - if the posted data was ``foo=bar``, a :py:exc:`ValueError` would be
+      raised, ``failed_fields`` would be
+      ``{"foo": "message about unexpected key"}``.
+
+    Args:
+        converters (dict): a mapping from POST data keys to
+            conversion functions.
+    """
+
+    def __init__(self, converters):
+        self.converters = converters.copy()
+
+    def __call__(self, request_data):
+        """Convert the values in the given mapping.
+
+        Args:
+            request_data (dict): the values to validate and convert,
+                usually ``flask.request.form``.
+
+        Raises:
+            ValueError: At least one value is invalid.
+        """
+        values = {}
+        errors = {}
+        for key, value in request_data.items():
+            if key not in self.converters:
+                errors[key] = "Unexpected parameter."
+                continue
+            if self.converters[key] is None:
+                # Identity
+                values[key] = value
+                continue
+            try:
+                values[key] = self.converters[key](value)
+            except (TypeError, ValueError) as e:
+                errors[key] = e.args[0]
+        if errors:
+            raise ValueError(errors)
+        return values
diff --git a/hubs/views/api.py b/hubs/views/api.py
index 777bcda..b1232a5 100644
--- a/hubs/views/api.py
+++ b/hubs/views/api.py
@@ -5,7 +5,7 @@ import flask
 import hubs.models
 
 from hubs.app import app
-from .utils import get_hub, login_required
+from hubs.utils.views import get_hub, login_required
 
 
 @app.route('/api/hub/<hub>/subscribe', methods=['POST'])
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index d6d05f7..adcf65e 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -5,7 +5,7 @@ import flask
 import hubs.models
 
 from hubs.app import app
-from .utils import (
+from hubs.utils.views import (
     get_hub, get_visible_widgets, login_required, RequestValidator,
     require_hub_access,
     )
diff --git a/hubs/views/root.py b/hubs/views/root.py
index 74215da..be77ce6 100644
--- a/hubs/views/root.py
+++ b/hubs/views/root.py
@@ -4,7 +4,7 @@ import flask
 import hubs.models
 
 from hubs.app import app, OIDC
-from .utils import authenticated, is_safe_url
+from hubs.utils.views import authenticated, is_safe_url
 
 
 @app.route('/')
diff --git a/hubs/views/user.py b/hubs/views/user.py
index 8c640af..0397b69 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -6,7 +6,7 @@ import hubs.models
 import hubs.stream
 
 from hubs.app import app
-from .utils import (
+from hubs.utils.views import (
     login_required, get_hub, get_visible_widgets, require_hub_access,
     )
 
diff --git a/hubs/views/utils.py b/hubs/views/utils.py
deleted file mode 100644
index 94f7ef0..0000000
--- a/hubs/views/utils.py
+++ /dev/null
@@ -1,289 +0,0 @@
-"""
-The :py:mod:`hubs.views.utils` module contains helper functions and classes
-for the views.
-"""
-
-from __future__ import unicode_literals
-
-import datetime
-import functools
-import logging
-
-import flask
-from six.moves.urllib import parse as urlparse
-from sqlalchemy.orm import joinedload
-from sqlalchemy.orm.exc import NoResultFound
-
-from hubs.models import Hub, Widget
-
-
-log = logging.getLogger(__name__)
-
-
-def get_hub(name, load_config=False, session=None):
-    """ Utility shorthand to get a hub and 404 if not found. """
-    if session is None:
-        session = flask.g.db
-    query = session.query(Hub).filter(Hub.name == name)
-    if load_config:
-        query = query.options(joinedload(Hub.config))
-    try:
-        return query.one()
-    except NoResultFound:
-        flask.abort(404)
-
-
-def get_widget_instance(hub, idx, session=None):
-    """ Utility shorthand to get a widget and 404 if not found. """
-    if session is None:
-        session = flask.g.db
-    try:
-        idx = int(idx)
-    except (TypeError, ValueError):
-        flask.abort(400)
-    try:
-        return session.query(Widget).join(Hub).filter(
-                Hub.name == hub,
-                Widget.idx == idx,
-            ).one()
-    except NoResultFound:
-        flask.abort(404)
-
-
-def get_visible_widgets(hub):
-    from hubs.widgets import registry
-    widgets = {"left": [], "right": []}
-    try:
-        user = flask.g.auth.user
-    except AttributeError:
-        user = None
-    for widget in hub.widgets:
-        if widget.plugin not in registry:
-            continue  # disabled widget
-        if not widget.allows(user, "view"):
-            continue
-        if widget.left:
-            widgets["left"].append(widget)
-        else:
-            widgets["right"].append(widget)
-    widgets["left"].sort(key=lambda w: w.index)
-    widgets["right"].sort(key=lambda w: w.index)
-    return widgets
-
-
-class WidgetConfigError(Exception):
-    pass
-
-
-def create_widget_instance(hub, widget, position):
-    """View helper to instanciate a widget on a hub.
-
-    Arguments:
-        hub (hubs.models.Hub): Instance of the hub to create the widget in.
-        widget (hubs.widgets.base.Widget): Widget to instanciate.
-        position (str): either ``left`` or ``right``.
-    """
-    widget_instance = Widget(
-        hub=hub, plugin=widget.name, index=-1,
-        left=(position == 'left'))
-    flask.g.db.add(widget_instance)
-    flask.g.db.flush()  # will populate Widget.config
-    try:
-        configure_widget_instance(widget_instance)
-    except WidgetConfigError as e:
-        flask.flash(e.args[0], "error")
-    else:
-        flask.flash("The widget has been added.")
-
-
-def configure_widget_instance(widget_instance):
-    """Configure a widget instance using the request form data.
-
-    Arguments:
-        widget_instance (hubs.models.Widget): Instance of the widget that is to
-            be configured.
-    """
-    config = {}
-    for param in widget_instance.module.get_parameters():
-        val = flask.request.form.get(param.name)
-        if not val:
-            raise WidgetConfigError(
-                'You must provide a value for: %s' % param.name)
-        try:
-            config[param.name] = param.validator.from_string(val)
-        except ValueError as err:
-            raise WidgetConfigError('Invalid data provided, error: %s' % err)
-    # Updating in-place is not supported, it's a class property.
-    cur_config = widget_instance.config or {}
-    cur_config = cur_config.copy()
-    cur_config.update(config)
-    widget_instance.config = cur_config
-    # Set the visibility parameter.
-    try:
-        widget_instance.visibility = flask.request.form["visibility"]
-    except KeyError:
-        pass  # the value is optional.
-    # Update the hub's mtime.  TODO: use a SQLAlchemy signal here.
-    widget_instance.hub.last_edited = datetime.datetime.utcnow()
-    try:
-        flask.g.db.commit()
-    except Exception as err:
-        log.warn(
-            "Could not save the configuration of widget "
-            "%s to the database: %s.",
-            widget_instance.idx, err)
-        raise WidgetConfigError(
-            'Could not save the configuration to the database '
-            'if the error persists, please warn an admin')
-
-
-def authenticated():
-    """ Utility function checking if the current auth is set or not."""
-    return hasattr(flask.g, 'auth') \
-        and flask.g.auth is not None \
-        and flask.g.auth.logged_in
-
-
-def login_required(function):
-    """ Flask decorator to restrict access to logged-in users. """
-
-    @functools.wraps(function)
-    def decorated_function(*args, **kwargs):
-        """ Decorated function, actually does the work. """
-        if not authenticated():
-            return flask.redirect(flask.url_for(
-                'login', next=flask.request.url))
-
-        return function(*args, **kwargs)
-
-    return decorated_function
-
-
-def require_hub_access(action, url_param="name", json=False):
-    """Check access to the hub for the specified action."""
-    def decorator(function):
-        @functools.wraps(function)
-        def wrapper(*args, **kwargs):
-            hub_name = kwargs[url_param]
-            hub = get_hub(hub_name, load_config=True)
-            try:
-                user = flask.g.auth.user
-            except AttributeError:
-                user = None
-            if not hub.allows(user, action):
-                if action == "view":
-                    msg = "This hub is for members only."
-                elif action == "config":
-                    msg = "You are not allowed to configure this hub."
-                else:
-                    msg = "Access forbidden."
-                if json:
-                    result = flask.jsonify({
-                        "status": "ERROR", "message": msg, "hub": hub.name,
-                        })
-                else:
-                    result = flask.render_template(
-                        'errors/hub.html', hub=hub, msg=msg,
-                        )
-                return result, 403
-            return function(*args, **kwargs)
-        return wrapper
-    return decorator
-
-
-def is_safe_url(target):
-    """ Checks that the target url is safe and sending to the current
-    website not some other malicious one.
-    """
-    ref_url = urlparse.urlparse(flask.request.host_url)
-    test_url = urlparse.urlparse(
-        urlparse.urljoin(flask.request.host_url, target))
-    return test_url.scheme in ('http', 'https') and \
-        ref_url.netloc == test_url.netloc
-
-
-def get_position():
-    # Use request.values instead of request.form to allow the position to be
-    # passed in the query string.
-    position = flask.request.values.get('position', '')
-    if position not in ['right', 'left']:
-        flask.abort(400, 'Invalid position provided')
-    return position
-
-
-class RequestValidator(object):
-    """Validate a request's POST data.
-
-    Instantiate this class with a dictionnary mapping POST data keys (found in
-    ``flask.request.form``) to a function that will validate and convert them.
-
-    POST data can be validated by calling the instance and passing the data as
-    an argument.  The instance will return a mapping of keys to converted
-    values if all validations are successful.
-
-    A validation function can raise a :py:exc:`ValueError` if the value is not
-    valid. In this case, the :py:class:`RequestValidator` instance will collect
-    the error messages in a dictionary mapping failed request keys to messages,
-    and raise a :py:exc:`ValueError` with this dictionary.
-
-    If the function is None, the value is returned unchanged. If a posted value
-    is not present in the conversion mapping the class was instantiated with,
-    an error will be raised.
-
-    A typical usage of this class is::
-
-        validator = RequestValidator({"number": int})
-        try:
-            values = validator(flask.request.form)
-        except ValueError as e:
-            failed_fields = e.args[0]
-            return flask.jsonify(failed_fields), 400
-        # Do something with the validated values.
-        for key, value in values.items():
-            setattr(model_instance, key, value)
-
-    In this example:
-
-    - if the posted data was ``number=1``, the resulting ``values`` variable
-      would be ``{"number": 1}``.
-    - if the posted data was ``number=foobar``, a :py:exc:`ValueError` would be
-      raised, ``failed_fields`` would be ``{"number": "error message"}``.
-    - if the posted data was ``foo=bar``, a :py:exc:`ValueError` would be
-      raised, ``failed_fields`` would be
-      ``{"foo": "message about unexpected key"}``.
-
-    Args:
-        converters (dict): a mapping from POST data keys to
-            conversion functions.
-    """
-
-    def __init__(self, converters):
-        self.converters = converters.copy()
-
-    def __call__(self, request_data):
-        """Convert the values in the given mapping.
-
-        Args:
-            request_data (dict): the values to validate and convert,
-                usually ``flask.request.form``.
-
-        Raises:
-            ValueError: At least one value is invalid.
-        """
-        values = {}
-        errors = {}
-        for key, value in request_data.items():
-            if key not in self.converters:
-                errors[key] = "Unexpected parameter."
-                continue
-            if self.converters[key] is None:
-                # Identity
-                values[key] = value
-                continue
-            try:
-                values[key] = self.converters[key](value)
-            except (TypeError, ValueError) as e:
-                errors[key] = e.args[0]
-        if errors:
-            raise ValueError(errors)
-        return values
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
index 35fb12a..2cd7f98 100644
--- a/hubs/views/widget.py
+++ b/hubs/views/widget.py
@@ -5,7 +5,7 @@ import flask
 from hubs.app import app
 from hubs.widgets import registry
 from pkg_resources import resource_isdir
-from .utils import (
+from hubs.utils.views import (
     create_widget_instance, configure_widget_instance, get_hub,
     get_widget_instance, login_required, WidgetConfigError,
     get_position, require_hub_access,
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index 1596cea..59b7a1d 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -6,7 +6,7 @@ import requests
 import six
 
 from hubs.widgets.base import Widget, WidgetView
-from hubs.views.utils import login_required
+from hubs.utils.views import login_required
 
 
 class Contact(Widget):
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 56f5e40..afcdf2e 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -5,7 +5,8 @@ import fedmsg.config
 import fedmsg.meta
 import requests
 
-from hubs.utils import get_fedmsg_config, commas
+from hubs.utils import get_fedmsg_config
+from hubs.utils.text import commas
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 283a15d..2de11a3 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -1,9 +1,9 @@
 from __future__ import unicode_literals
 
 import logging
-import hubs.utils
 
 from hubs.utils import get_fedmsg_config
+from hubs.utils.github import github_repos, github_pulls
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
@@ -63,9 +63,9 @@ class GetPRs(CachedFunction):
         displayed_number = 0
         more = 0
         if token:
-            repos = hubs.utils.github_repos(token, org)
+            repos = github_repos(token, org)
             pulls = sum([
-                list(hubs.utils.github_pulls(token, org, repo))
+                list(github_pulls(token, org, repo))
                 for repo in repos
             ], [])
             # Reverse-sort by time (newest-first)
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index 2b5b2b4..eaa46ac 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -7,7 +7,7 @@ import flask
 from flask.signals import template_rendered
 
 from hubs.models import Hub
-from hubs.views.utils import get_hub, require_hub_access
+from hubs.utils.views import get_hub, require_hub_access
 from hubs.widgets import registry
 from hubs.widgets.base import WidgetView
 from .functions import GetRequests
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index b737f0a..68c26b9 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -5,7 +5,7 @@ import collections
 import datetime
 import requests
 
-from hubs import utils
+from hubs.utils.text import markup
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
@@ -65,7 +65,7 @@ class GetMeetings(CachedFunction):
         tmp = collections.defaultdict(list)
         for meeting in response['meetings']:
             if meeting.get('meeting_information_html'):
-                meeting['meeting_information_html'] = utils.markup(
+                meeting['meeting_information_html'] = markup(
                     meeting['meeting_information'])
             tmp[meeting['meeting_name']].append(meeting)
 
diff --git a/hubs/widgets/stats/__init__.py b/hubs/widgets/stats/__init__.py
index 67740df..b139175 100644
--- a/hubs/widgets/stats/__init__.py
+++ b/hubs/widgets/stats/__init__.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 import flask
 
-from hubs.utils import commas
+from hubs.utils.text import commas
 from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction
 
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index 65d91c5..cd2810f 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -93,7 +93,7 @@ class WidgetView(View):
         }
 
     def _get_instance(self, *args, **kwargs):
-        from hubs.views.utils import get_widget_instance
+        from hubs.utils.views import get_widget_instance
         hubname = kwargs.pop("hub")
         widgetidx = kwargs.pop("idx")
         return get_widget_instance(hubname, widgetidx)

From d6064329786158e727836fc9a0084a4fae5b9d93 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 17 2017 09:04:28 +0000
Subject: [PATCH 837/1001] Update fedora-bootstrap to 1.0.3


---

diff --git a/hubs/static/fedora-bootstrap/fedora-bootstrap.css b/hubs/static/fedora-bootstrap/fedora-bootstrap.css
deleted file mode 100644
index becb558..0000000
--- a/hubs/static/fedora-bootstrap/fedora-bootstrap.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/*!
- * Bootstrap v4.0.0-alpha.2 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*,:after,:before{text-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]:after{content:" (" attr(title) ")"}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}@-moz-viewport{width:device-width}@-ms-viewport{width:device-width}@-o-viewport{width:device-width}@-webkit-viewport{width:device-width}@viewport{width:device-width}html{font-size:14px;-webkit-tap-highlight-color:transparent}body{font-family:Open Sans;font-size:1rem;line-height:1.5;color:#373a3c;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #818a91}address{font-style:normal;line-height:inherit}address,dl,ol,ul{margin-bottom:1rem}dl,ol,ul{margin-top:0}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}a{color:#0275d8;text-decoration:none}a:focus,a:hover{color:#014c8c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}pre{margin-top:0;margin-bottom:1rem}figure{margin:0 0 1rem}img{vertical-align:middle}[role=button]{cursor:pointer}[role=button],a,area,button,input,label,select,summary,textarea{touch-action:manipulation}table{background-color:transparent}caption{padding-top:.75rem;padding-bottom:.75rem;color:#818a91;caption-side:bottom}caption,th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,select,textarea{margin:0;line-height:inherit;border-radius:0}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}input[type=search]{box-sizing:inherit;-webkit-appearance:none}output{display:inline-block}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1{font-size:2rem}h2{font-size:1.75rem}h3{font-size:1.5rem}h4{font-size:1.25rem}h5,h6{font-size:1rem}.h1{font-size:2rem}.h2{font-size:1.75rem}.h3{font-size:1.5rem}.h4{font-size:1.25rem}.h5,.h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300}.display-2{font-size:5.5rem;font-weight:300}.display-3{font-size:4.5rem;font-weight:300}.display-4{font-size:3.5rem;font-weight:300}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.dl-horizontal{margin-right:-1.875rem;margin-left:-1.875rem}.dl-horizontal:after{content:"";display:table;clear:both}.initialism{font-size:90%;text-transform:uppercase}.blockquote{padding:.5rem 1rem;margin-bottom:1rem;font-size:1.25rem;border-left:.25rem solid #eceeef}.blockquote-footer{display:block;font-size:80%;line-height:1.5;color:#818a91}.blockquote-footer:before{content:"\2014   \A0"}.blockquote-reverse{padding-right:1rem;padding-left:0;text-align:right;border-right:.25rem solid #eceeef;border-left:0}.blockquote-reverse .blockquote-footer:before{content:""}.blockquote-reverse .blockquote-footer:after{content:"\A0   \2014"}.carousel-inner>.carousel-item>a>img,.carousel-inner>.carousel-item>img,.img-fluid{display:block;max-width:100%;height:auto}.img-rounded{border-radius:.3rem}.img-thumbnail{padding:.25rem;line-height:1.5;background-color:#fff;border:1px solid #ddd;border-radius:.25rem;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#818a91}code,kbd,pre,samp{font-family:Hack,monospace}code{color:#bd4147;background-color:#f7f7f9;border-radius:.25rem}code,kbd{padding:.2rem .4rem;font-size:90%}kbd{color:#fff;background-color:#333;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;margin-top:0;margin-bottom:1rem;font-size:90%;line-height:1.5;color:#586e75}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-left:auto;margin-right:auto;padding-left:.9375rem;padding-right:.9375rem}.container:after{content:"";display:table;clear:both}@media (min-width:544px){.container{max-width:6in}}@media (min-width:768px){.container{max-width:45pc}}@media (min-width:992px){.container{max-width:940px}}@media (min-width:1200px){.container{max-width:855pt}}.container-fluid{margin-left:auto;margin-right:auto;padding-left:.9375rem;padding-right:.9375rem}.container-fluid:after{content:"";display:table;clear:both}.row{margin-left:-.9375rem;margin-right:-.9375rem}.row:after{content:"";display:table;clear:both}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{position:relative;min-height:1px;padding-left:.9375rem;padding-right:.9375rem}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-1{width:8.33333%}.col-xs-2{width:16.66667%}.col-xs-3{width:25%}.col-xs-4{width:33.33333%}.col-xs-5{width:41.66667%}.col-xs-6{width:50%}.col-xs-7{width:58.33333%}.col-xs-8{width:66.66667%}.col-xs-9{width:75%}.col-xs-10{width:83.33333%}.col-xs-11{width:91.66667%}.col-xs-12{width:100%}.col-xs-pull-0{right:auto}.col-xs-pull-1{right:8.33333%}.col-xs-pull-2{right:16.66667%}.col-xs-pull-3{right:25%}.col-xs-pull-4{right:33.33333%}.col-xs-pull-5{right:41.66667%}.col-xs-pull-6{right:50%}.col-xs-pull-7{right:58.33333%}.col-xs-pull-8{right:66.66667%}.col-xs-pull-9{right:75%}.col-xs-pull-10{right:83.33333%}.col-xs-pull-11{right:91.66667%}.col-xs-pull-12{right:100%}.col-xs-push-0{left:auto}.col-xs-push-1{left:8.33333%}.col-xs-push-2{left:16.66667%}.col-xs-push-3{left:25%}.col-xs-push-4{left:33.33333%}.col-xs-push-5{left:41.66667%}.col-xs-push-6{left:50%}.col-xs-push-7{left:58.33333%}.col-xs-push-8{left:66.66667%}.col-xs-push-9{left:75%}.col-xs-push-10{left:83.33333%}.col-xs-push-11{left:91.66667%}.col-xs-push-12{left:100%}.col-xs-offset-0{margin-left:0}.col-xs-offset-1{margin-left:8.33333%}.col-xs-offset-2{margin-left:16.66667%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-4{margin-left:33.33333%}.col-xs-offset-5{margin-left:41.66667%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-7{margin-left:58.33333%}.col-xs-offset-8{margin-left:66.66667%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-10{margin-left:83.33333%}.col-xs-offset-11{margin-left:91.66667%}.col-xs-offset-12{margin-left:100%}@media (min-width:544px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-1{width:8.33333%}.col-sm-2{width:16.66667%}.col-sm-3{width:25%}.col-sm-4{width:33.33333%}.col-sm-5{width:41.66667%}.col-sm-6{width:50%}.col-sm-7{width:58.33333%}.col-sm-8{width:66.66667%}.col-sm-9{width:75%}.col-sm-10{width:83.33333%}.col-sm-11{width:91.66667%}.col-sm-12{width:100%}.col-sm-pull-0{right:auto}.col-sm-pull-1{right:8.33333%}.col-sm-pull-2{right:16.66667%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.33333%}.col-sm-pull-5{right:41.66667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.33333%}.col-sm-pull-8{right:66.66667%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.33333%}.col-sm-pull-11{right:91.66667%}.col-sm-pull-12{right:100%}.col-sm-push-0{left:auto}.col-sm-push-1{left:8.33333%}.col-sm-push-2{left:16.66667%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.33333%}.col-sm-push-5{left:41.66667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.33333%}.col-sm-push-8{left:66.66667%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.33333%}.col-sm-push-11{left:91.66667%}.col-sm-push-12{left:100%}.col-sm-offset-0{margin-left:0}.col-sm-offset-1{margin-left:8.33333%}.col-sm-offset-2{margin-left:16.66667%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.33333%}.col-sm-offset-5{margin-left:41.66667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.33333%}.col-sm-offset-8{margin-left:66.66667%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.33333%}.col-sm-offset-11{margin-left:91.66667%}.col-sm-offset-12{margin-left:100%}}@media (min-width:768px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-1{width:8.33333%}.col-md-2{width:16.66667%}.col-md-3{width:25%}.col-md-4{width:33.33333%}.col-md-5{width:41.66667%}.col-md-6{width:50%}.col-md-7{width:58.33333%}.col-md-8{width:66.66667%}.col-md-9{width:75%}.col-md-10{width:83.33333%}.col-md-11{width:91.66667%}.col-md-12{width:100%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.33333%}.col-md-pull-2{right:16.66667%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.33333%}.col-md-pull-5{right:41.66667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.33333%}.col-md-pull-8{right:66.66667%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.33333%}.col-md-pull-11{right:91.66667%}.col-md-pull-12{right:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.33333%}.col-md-push-2{left:16.66667%}.col-md-push-3{left:25%}.col-md-push-4{left:33.33333%}.col-md-push-5{left:41.66667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.33333%}.col-md-push-8{left:66.66667%}.col-md-push-9{left:75%}.col-md-push-10{left:83.33333%}.col-md-push-11{left:91.66667%}.col-md-push-12{left:100%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.33333%}.col-md-offset-2{margin-left:16.66667%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.33333%}.col-md-offset-5{margin-left:41.66667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.33333%}.col-md-offset-8{margin-left:66.66667%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.33333%}.col-md-offset-11{margin-left:91.66667%}.col-md-offset-12{margin-left:100%}}@media (min-width:992px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-1{width:8.33333%}.col-lg-2{width:16.66667%}.col-lg-3{width:25%}.col-lg-4{width:33.33333%}.col-lg-5{width:41.66667%}.col-lg-6{width:50%}.col-lg-7{width:58.33333%}.col-lg-8{width:66.66667%}.col-lg-9{width:75%}.col-lg-10{width:83.33333%}.col-lg-11{width:91.66667%}.col-lg-12{width:100%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.33333%}.col-lg-pull-2{right:16.66667%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.33333%}.col-lg-pull-5{right:41.66667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.33333%}.col-lg-pull-8{right:66.66667%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.33333%}.col-lg-pull-11{right:91.66667%}.col-lg-pull-12{right:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.33333%}.col-lg-push-2{left:16.66667%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.33333%}.col-lg-push-5{left:41.66667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.33333%}.col-lg-push-8{left:66.66667%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.33333%}.col-lg-push-11{left:91.66667%}.col-lg-push-12{left:100%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.33333%}.col-lg-offset-2{margin-left:16.66667%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.33333%}.col-lg-offset-5{margin-left:41.66667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.33333%}.col-lg-offset-8{margin-left:66.66667%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.33333%}.col-lg-offset-11{margin-left:91.66667%}.col-lg-offset-12{margin-left:100%}}@media (min-width:1200px){.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{float:left}.col-xl-1{width:8.33333%}.col-xl-2{width:16.66667%}.col-xl-3{width:25%}.col-xl-4{width:33.33333%}.col-xl-5{width:41.66667%}.col-xl-6{width:50%}.col-xl-7{width:58.33333%}.col-xl-8{width:66.66667%}.col-xl-9{width:75%}.col-xl-10{width:83.33333%}.col-xl-11{width:91.66667%}.col-xl-12{width:100%}.col-xl-pull-0{right:auto}.col-xl-pull-1{right:8.33333%}.col-xl-pull-2{right:16.66667%}.col-xl-pull-3{right:25%}.col-xl-pull-4{right:33.33333%}.col-xl-pull-5{right:41.66667%}.col-xl-pull-6{right:50%}.col-xl-pull-7{right:58.33333%}.col-xl-pull-8{right:66.66667%}.col-xl-pull-9{right:75%}.col-xl-pull-10{right:83.33333%}.col-xl-pull-11{right:91.66667%}.col-xl-pull-12{right:100%}.col-xl-push-0{left:auto}.col-xl-push-1{left:8.33333%}.col-xl-push-2{left:16.66667%}.col-xl-push-3{left:25%}.col-xl-push-4{left:33.33333%}.col-xl-push-5{left:41.66667%}.col-xl-push-6{left:50%}.col-xl-push-7{left:58.33333%}.col-xl-push-8{left:66.66667%}.col-xl-push-9{left:75%}.col-xl-push-10{left:83.33333%}.col-xl-push-11{left:91.66667%}.col-xl-push-12{left:100%}.col-xl-offset-0{margin-left:0}.col-xl-offset-1{margin-left:8.33333%}.col-xl-offset-2{margin-left:16.66667%}.col-xl-offset-3{margin-left:25%}.col-xl-offset-4{margin-left:33.33333%}.col-xl-offset-5{margin-left:41.66667%}.col-xl-offset-6{margin-left:50%}.col-xl-offset-7{margin-left:58.33333%}.col-xl-offset-8{margin-left:66.66667%}.col-xl-offset-9{margin-left:75%}.col-xl-offset-10{margin-left:83.33333%}.col-xl-offset-11{margin-left:91.66667%}.col-xl-offset-12{margin-left:100%}}.table{width:100%;max-width:100%;margin-bottom:1rem}.table td,.table th{padding:.75rem;line-height:1.5;vertical-align:top;border-top:1px solid #eceeef}.table thead th{vertical-align:bottom;border-bottom:2px solid #eceeef}.table tbody+tbody{border-top:2px solid #eceeef}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #eceeef}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:#f9f9f9}.table-active,.table-active>td,.table-active>th,.table-hover tbody tr:hover{background-color:#f5f5f5}.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:#e8e8e8}.table-success,.table-success>td,.table-success>th{background-color:#dff0d8}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#d0e9c6}.table-info,.table-info>td,.table-info>th{background-color:#d9edf7}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#c4e3f3}.table-warning,.table-warning>td,.table-warning>th{background-color:#fcf8e3}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#faf2cc}.table-danger,.table-danger>td,.table-danger>th{background-color:#f2dede}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#ebcccc}.table-responsive{display:block;width:100%;min-height:.01%;overflow-x:auto}.thead-inverse th{color:#fff;background-color:#373a3c}.thead-default th{color:#55595c;background-color:#eceeef}.table-inverse{color:#eceeef;background-color:#373a3c}.table-inverse.table-bordered{border:0}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#55595c}.table-reflow thead{float:left}.table-reflow tbody{display:block;white-space:nowrap}.table-reflow td,.table-reflow th{border-top:1px solid #eceeef;border-left:1px solid #eceeef}.table-reflow td:last-child,.table-reflow th:last-child{border-right:1px solid #eceeef}.table-reflow tbody:last-child tr:last-child td,.table-reflow tbody:last-child tr:last-child th,.table-reflow tfoot:last-child tr:last-child td,.table-reflow tfoot:last-child tr:last-child th,.table-reflow thead:last-child tr:last-child td,.table-reflow thead:last-child tr:last-child th{border-bottom:1px solid #eceeef}.table-reflow tr{float:left}.table-reflow tr td,.table-reflow tr th{display:block!important;border:1px solid #eceeef}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#55595c;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:.25rem}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{border-color:#66afe9;outline:0}.form-control::placeholder{color:#999;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#eceeef;opacity:1}.form-control:disabled{cursor:not-allowed}.form-control-file,.form-control-range{display:block}.form-control-label{padding:.375rem .75rem;margin-bottom:0}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{line-height:2.25rem}.input-group-sm input[type=date].form-control,.input-group-sm input[type=datetime-local].form-control,.input-group-sm input[type=month].form-control,.input-group-sm input[type=time].form-control,input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:1.8625rem}.input-group-lg input[type=date].form-control,.input-group-lg input[type=datetime-local].form-control,.input-group-lg input[type=month].form-control,.input-group-lg input[type=time].form-control,input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:3.16667rem}}.form-control-static{min-height:2.25rem;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0}.form-control-static.form-control-lg,.form-control-static.form-control-sm,.input-group-lg>.form-control-static.form-control,.input-group-lg>.form-control-static.input-group-addon,.input-group-lg>.input-group-btn>.form-control-static.btn,.input-group-sm>.form-control-static.form-control,.input-group-sm>.form-control-static.input-group-addon,.input-group-sm>.input-group-btn>.form-control-static.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.275rem .75rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.75rem 1.25rem;font-size:1.25rem;line-height:1.33333;border-radius:.3rem}.form-group{margin-bottom:1rem}.checkbox,.radio{position:relative;display:block;margin-bottom:.75rem}.checkbox label,.radio label{padding-left:1.25rem;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox label input:only-child,.radio label input:only-child{position:static}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:.25rem;margin-left:-1.25rem}.checkbox+.checkbox,.radio+.radio{margin-top:-.25rem}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:1.25rem;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:.75rem}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,input[type=checkbox].disabled,input[type=checkbox]:disabled,input[type=radio].disabled,input[type=radio]:disabled{cursor:not-allowed}.form-control-danger,.form-control-success,.form-control-warning{padding-right:2.25rem;background-repeat:no-repeat;background-position:center right .5625rem;background-size:1.4625rem 1.4625rem}.has-success .checkbox,.has-success .checkbox-inline,.has-success .form-control-label,.has-success .radio,.has-success .radio-inline,.has-success .text-help,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#5cb85c}.has-success .form-control{border-color:#5cb85c}.has-success .input-group-addon{color:#5cb85c;border-color:#5cb85c;background-color:#eaf6ea}.has-success .form-control-feedback{color:#5cb85c}.has-success .form-control-success{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjNWNiODVjIiBkPSJNMjMzLjggNjEwYy0xMy4zIDAtMjYtNi0zNC0xNi44TDkwLjUgNDQ4LjhDNzYuMyA0MzAgODAgNDAzLjMgOTguOCAzODljMTguOC0xNC4yIDQ1LjUtMTAuNCA1OS44IDguNGw3MiA5NUw0NTEuMyAyNDJjMTIuNS0yMCAzOC44LTI2LjIgNTguOC0xMy43IDIwIDEyLjQgMjYgMzguNyAxMy43IDU4LjhMMjcwIDU5MGMtNy40IDEyLTIwLjIgMTkuNC0zNC4zIDIwaC0yeiIvPjwvc3ZnPg==")}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .form-control-label,.has-warning .radio,.has-warning .radio-inline,.has-warning .text-help,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#f0ad4e}.has-warning .form-control{border-color:#f0ad4e}.has-warning .input-group-addon{color:#f0ad4e;border-color:#f0ad4e;background-color:#fff}.has-warning .form-control-feedback{color:#f0ad4e}.has-warning .form-control-warning{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZjBhZDRlIiBkPSJNNjAzIDY0MC4ybC0yNzguNS01MDljLTMuOC02LjYtMTAuOC0xMC42LTE4LjUtMTAuNnMtMTQuNyA0LTE4LjUgMTAuNkw5IDY0MC4yYy0zLjcgNi41LTMuNiAxNC40LjIgMjAuOCAzLjggNi41IDEwLjggMTAuNCAxOC4zIDEwLjRoNTU3YzcuNiAwIDE0LjYtNCAxOC40LTEwLjQgMy41LTYuNCAzLjYtMTQuNCAwLTIwLjh6bS0yNjYuNC0zMGgtNjEuMlY1NDloNjEuMnY2MS4yem0wLTEwN2gtNjEuMlYzMDRoNjEuMnYxOTl6Ii8+PC9zdmc+")}.has-danger .checkbox,.has-danger .checkbox-inline,.has-danger .form-control-label,.has-danger .radio,.has-danger .radio-inline,.has-danger .text-help,.has-danger.checkbox label,.has-danger.checkbox-inline label,.has-danger.radio label,.has-danger.radio-inline label{color:#d9534f}.has-danger .form-control{border-color:#d9534f}.has-danger .input-group-addon{color:#d9534f;border-color:#d9534f;background-color:#fdf7f7}.has-danger .form-control-feedback{color:#d9534f}.has-danger .form-control-danger{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZDk1MzRmIiBkPSJNNDQ3IDU0NC40Yy0xNC40IDE0LjQtMzcuNiAxNC40LTUyIDBsLTg5LTkyLjctODkgOTIuN2MtMTQuNSAxNC40LTM3LjcgMTQuNC01MiAwLTE0LjQtMTQuNC0xNC40LTM3LjYgMC01Mmw5Mi40LTk2LjMtOTIuNC05Ni4zYy0xNC40LTE0LjQtMTQuNC0zNy42IDAtNTJzMzcuNi0xNC4zIDUyIDBsODkgOTIuOCA4OS4yLTkyLjdjMTQuNC0xNC40IDM3LjYtMTQuNCA1MiAwIDE0LjMgMTQuNCAxNC4zIDM3LjYgMCA1MkwzNTQuNiAzOTZsOTIuNCA5Ni40YzE0LjQgMTQuNCAxNC40IDM3LjYgMCA1MnoiLz48L3N2Zz4=")}@media (min-width:544px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .form-control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;user-select:none;border:1px solid transparent;padding:.375rem 1rem;font-size:1rem;line-height:1.5;border-radius:.25rem}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0}.btn.disabled,.btn:disabled{cursor:not-allowed;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary.focus,.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#025aa5;border-color:#01549b}.btn-primary.active,.btn-primary:active,.open>.btn-primary.dropdown-toggle{color:#fff;background-color:#025aa5;border-color:#01549b;background-image:none}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.btn-primary.dropdown-toggle.focus,.open>.btn-primary.dropdown-toggle:focus,.open>.btn-primary.dropdown-toggle:hover{color:#fff;background-color:#014682;border-color:#01315a}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary:disabled.focus,.btn-primary:disabled:focus,.btn-primary:disabled:hover{background-color:#0275d8;border-color:#0275d8}.btn-secondary{color:#373a3c;background-color:#fff;border-color:#ccc}.btn-secondary.focus,.btn-secondary:focus,.btn-secondary:hover{color:#373a3c;background-color:#e6e6e6;border-color:#adadad}.btn-secondary.active,.btn-secondary:active,.open>.btn-secondary.dropdown-toggle{color:#373a3c;background-color:#e6e6e6;border-color:#adadad;background-image:none}.btn-secondary.active.focus,.btn-secondary.active:focus,.btn-secondary.active:hover,.btn-secondary:active.focus,.btn-secondary:active:focus,.btn-secondary:active:hover,.open>.btn-secondary.dropdown-toggle.focus,.open>.btn-secondary.dropdown-toggle:focus,.open>.btn-secondary.dropdown-toggle:hover{color:#373a3c;background-color:#d4d4d4;border-color:#8c8c8c}.btn-secondary.disabled.focus,.btn-secondary.disabled:focus,.btn-secondary.disabled:hover,.btn-secondary:disabled.focus,.btn-secondary:disabled:focus,.btn-secondary:disabled:hover{background-color:#fff;border-color:#ccc}.btn-info{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info.focus,.btn-info:focus,.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#2aabd2}.btn-info.active,.btn-info:active,.open>.btn-info.dropdown-toggle{color:#fff;background-color:#31b0d5;border-color:#2aabd2;background-image:none}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.btn-info.dropdown-toggle.focus,.open>.btn-info.dropdown-toggle:focus,.open>.btn-info.dropdown-toggle:hover{color:#fff;background-color:#269abc;border-color:#1f7e9a}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info:disabled.focus,.btn-info:disabled:focus,.btn-info:disabled:hover{background-color:#5bc0de;border-color:#5bc0de}.btn-success{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success.focus,.btn-success:focus,.btn-success:hover{color:#fff;background-color:#449d44;border-color:#419641}.btn-success.active,.btn-success:active,.open>.btn-success.dropdown-toggle{color:#fff;background-color:#449d44;border-color:#419641;background-image:none}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.btn-success.dropdown-toggle.focus,.open>.btn-success.dropdown-toggle:focus,.open>.btn-success.dropdown-toggle:hover{color:#fff;background-color:#398439;border-color:#2d672d}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success:disabled.focus,.btn-success:disabled:focus,.btn-success:disabled:hover{background-color:#5cb85c;border-color:#5cb85c}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning.focus,.btn-warning:focus,.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#eb9316}.btn-warning.active,.btn-warning:active,.open>.btn-warning.dropdown-toggle{color:#fff;background-color:#ec971f;border-color:#eb9316;background-image:none}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.btn-warning.dropdown-toggle.focus,.open>.btn-warning.dropdown-toggle:focus,.open>.btn-warning.dropdown-toggle:hover{color:#fff;background-color:#d58512;border-color:#b06d0f}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning:disabled.focus,.btn-warning:disabled:focus,.btn-warning:disabled:hover{background-color:#f0ad4e;border-color:#f0ad4e}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger.focus,.btn-danger:focus,.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#c12e2a}.btn-danger.active,.btn-danger:active,.open>.btn-danger.dropdown-toggle{color:#fff;background-color:#c9302c;border-color:#c12e2a;background-image:none}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.btn-danger.dropdown-toggle.focus,.open>.btn-danger.dropdown-toggle:focus,.open>.btn-danger.dropdown-toggle:hover{color:#fff;background-color:#ac2925;border-color:#8b211e}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger:disabled.focus,.btn-danger:disabled:focus,.btn-danger:disabled:hover{background-color:#d9534f;border-color:#d9534f}.btn-primary-outline{color:#0275d8;background-image:none;background-color:transparent;border-color:#0275d8}.btn-primary-outline.active,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline:focus,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary-outline.disabled.focus,.btn-primary-outline.disabled:focus,.btn-primary-outline.disabled:hover,.btn-primary-outline:disabled.focus,.btn-primary-outline:disabled:focus,.btn-primary-outline:disabled:hover{border-color:#43a7fd}.btn-secondary-outline{color:#ccc;background-image:none;background-color:transparent;border-color:#ccc}.btn-secondary-outline.active,.btn-secondary-outline.focus,.btn-secondary-outline:active,.btn-secondary-outline:focus,.btn-secondary-outline:hover,.open>.btn-secondary-outline.dropdown-toggle{color:#fff;background-color:#ccc;border-color:#ccc}.btn-secondary-outline.disabled.focus,.btn-secondary-outline.disabled:focus,.btn-secondary-outline.disabled:hover,.btn-secondary-outline:disabled.focus,.btn-secondary-outline:disabled:focus,.btn-secondary-outline:disabled:hover{border-color:#fff}.btn-info-outline{color:#5bc0de;background-image:none;background-color:transparent;border-color:#5bc0de}.btn-info-outline.active,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline:focus,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info-outline.disabled.focus,.btn-info-outline.disabled:focus,.btn-info-outline.disabled:hover,.btn-info-outline:disabled.focus,.btn-info-outline:disabled:focus,.btn-info-outline:disabled:hover{border-color:#b0e1ef}.btn-success-outline{color:#5cb85c;background-image:none;background-color:transparent;border-color:#5cb85c}.btn-success-outline.active,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline:focus,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success-outline.disabled.focus,.btn-success-outline.disabled:focus,.btn-success-outline.disabled:hover,.btn-success-outline:disabled.focus,.btn-success-outline:disabled:focus,.btn-success-outline:disabled:hover{border-color:#a3d7a3}.btn-warning-outline{color:#f0ad4e;background-image:none;background-color:transparent;border-color:#f0ad4e}.btn-warning-outline.active,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline:focus,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning-outline.disabled.focus,.btn-warning-outline.disabled:focus,.btn-warning-outline.disabled:hover,.btn-warning-outline:disabled.focus,.btn-warning-outline:disabled:focus,.btn-warning-outline:disabled:hover{border-color:#f8d9ac}.btn-danger-outline{color:#d9534f;background-image:none;background-color:transparent;border-color:#d9534f}.btn-danger-outline.active,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline:focus,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger-outline.disabled.focus,.btn-danger-outline.disabled:focus,.btn-danger-outline.disabled:hover,.btn-danger-outline:disabled.focus,.btn-danger-outline:disabled:focus,.btn-danger-outline:disabled:hover{border-color:#eba5a3}.btn-link{font-weight:400;color:#0275d8;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#014c8c;text-decoration:underline;background-color:transparent}.btn-link:disabled:focus,.btn-link:disabled:hover{color:#818a91;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.75rem 1.25rem;font-size:1.25rem;line-height:1.33333;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .75rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{height:0;overflow:hidden;transition-timing-function:ease;transition-duration:.35s;transition-property:height}.collapsing,.dropdown,.dropup{position:relative}.dropdown-toggle:after{display:inline-block;width:0;height:0;margin-right:.25rem;margin-left:.25rem;vertical-align:middle;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:focus{outline:0}.dropup .dropdown-toggle:after{border-top:0;border-bottom:.3em solid}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10pc;padding:5px 0;margin:2px 0 0;font-size:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-divider{height:1px;margin:.5rem 0;overflow:hidden;background-color:#e5e5e5}.dropdown-item{display:block;width:100%;padding:3px 20px;clear:both;font-weight:400;line-height:1.5;color:#373a3c;text-align:inherit;white-space:nowrap;background:none;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#2b2d2f;text-decoration:none;background-color:#f5f5f5}.dropdown-item.active,.dropdown-item.active:focus,.dropdown-item.active:hover{color:#fff;text-decoration:none;background-color:#0275d8;outline:0}.dropdown-item.disabled,.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{color:#818a91}.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:"progid:DXImageTransform.Microsoft.gradient(enabled = false)"}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:.875rem;line-height:1.5;color:#818a91;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:.3em solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar:after{content:"";display:table;clear:both}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group-lg.btn-group>.btn+.dropdown-toggle,.btn-group>.btn-lg+.dropdown-toggle{padding-right:9pt;padding-left:9pt}.btn .caret{margin-left:0}.btn-group-lg>.btn .caret,.btn-lg .caret{border-width:.3em .3em 0;border-bottom-width:0}.dropup .btn-group-lg>.btn .caret,.dropup .btn-lg .caret{border-width:0 .3em .3em}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:after{content:"";display:table;clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:.25rem;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:.25rem;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover{z-index:3}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1;color:#55595c;text-align:center;background-color:#eceeef;border:1px solid #ccc;border-radius:.25rem}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.275rem .75rem;font-size:.875rem;border-radius:.2rem}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.75rem 1.25rem;font-size:1.25rem;border-radius:.3rem}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{font-size:0;white-space:nowrap}.input-group-btn,.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.input-group-btn:last-child>.btn-group:active,.input-group-btn:last-child>.btn-group:focus,.input-group-btn:last-child>.btn-group:hover,.input-group-btn:last-child>.btn:active,.input-group-btn:last-child>.btn:focus,.input-group-btn:last-child>.btn:hover{z-index:3}.c-input{position:relative;display:inline;padding-left:1.5rem;color:#555;cursor:pointer}.c-input>input{position:absolute;z-index:-1;opacity:0}.c-input>input:checked~.c-indicator{color:#fff;background-color:#0074d9}.c-input>input:focus~.c-indicator{box-shadow:0 0 0 .075rem #fff,0 0 0 .2rem #0074d9}.c-input>input:active~.c-indicator{color:#fff;background-color:#84c6ff}.c-input+.c-input{margin-left:1rem}.c-indicator{position:absolute;top:0;left:0;display:block;width:1rem;height:1rem;font-size:65%;line-height:1rem;color:#eee;text-align:center;user-select:none;background-color:#eee;background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.c-checkbox .c-indicator{border-radius:.25rem}.c-checkbox input:checked~.c-indicator{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgOCA4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA4IDgiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTYuNCwxTDUuNywxLjdMMi45LDQuNUwyLjEsMy43TDEuNCwzTDAsNC40bDAuNywwLjdsMS41LDEuNWwwLjcsMC43bDAuNy0wLjdsMy41LTMuNWwwLjctMC43TDYuNCwxTDYuNCwxeiINCgkvPg0KPC9zdmc+DQo=)}.c-checkbox input:indeterminate~.c-indicator{background-color:#0074d9;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iOHB4IiBoZWlnaHQ9IjhweCIgdmlld0JveD0iMCAwIDggOCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOCA4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0wLDN2Mmg4VjNIMHoiLz4NCjwvc3ZnPg0K)}.c-radio .c-indicator{border-radius:50%}.c-radio input:checked~.c-indicator{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgOCA4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA4IDgiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTQsMUMyLjMsMSwxLDIuMywxLDRzMS4zLDMsMywzczMtMS4zLDMtM1M1LjcsMSw0LDF6Ii8+DQo8L3N2Zz4NCg==)}.c-inputs-stacked .c-input{display:inline}.c-inputs-stacked .c-input:after{display:block;margin-bottom:.25rem;content:""}.c-inputs-stacked .c-input+.c-input{margin-left:0}.c-select{display:inline-block;max-width:100%;padding:.375rem 1.75rem .375rem .75rem;padding-right:.75rem\9;color:#55595c;vertical-align:middle;background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAUCAMAAACzvE1FAAAADFBMVEUzMzMzMzMzMzMzMzMKAG/3AAAAA3RSTlMAf4C/aSLHAAAAPElEQVR42q3NMQ4AIAgEQTn//2cLdRKppSGzBYwzVXvznNWs8C58CiussPJj8h6NwgorrKRdTvuV9v16Afn0AYFOB7aYAAAAAElFTkSuQmCC) no-repeat right .75rem center;background-image:none\9;background-size:8px 10px;border:1px solid #ccc;-moz-appearance:none;-webkit-appearance:none}.c-select:focus{border-color:#51a7e8;outline:0}.c-select::-ms-expand{opacity:0}.c-select-sm{padding-top:3px;padding-bottom:3px;font-size:9pt}.c-select-sm:not([multiple]){height:26px;min-height:26px}.file{position:relative;display:inline-block;height:2.5rem;cursor:pointer}.file input{min-width:14rem;margin:0;filter:alpha(opacity=0);opacity:0}.file-custom{position:absolute;top:0;right:0;left:0;z-index:5;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#555;user-select:none;background-color:#fff;border:1px solid #ddd;border-radius:.25rem}.file-custom:after{content:"Choose file..."}.file-custom:before{position:absolute;top:-.075rem;right:-.075rem;bottom:-.075rem;z-index:6;display:block;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#555;content:"Browse";background-color:#eee;border:1px solid #ddd;border-radius:0 .25rem .25rem 0}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:inline-block}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#818a91}.nav-link.disabled,.nav-link.disabled:focus,.nav-link.disabled:hover{color:#818a91;cursor:not-allowed;background-color:transparent}.nav-inline .nav-item{display:inline-block}.nav-inline .nav-item+.nav-item,.nav-inline .nav-link+.nav-link{margin-left:1rem}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs:after{content:"";display:table;clear:both}.nav-tabs .nav-item{float:left;margin-bottom:-1px}.nav-tabs .nav-item+.nav-item{margin-left:.2rem}.nav-tabs .nav-link{display:block;padding:.5em 1em;border:1px solid transparent;border-radius:.25rem .25rem 0 0}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#eceeef #eceeef #ddd}.nav-tabs .nav-link.disabled,.nav-tabs .nav-link.disabled:focus,.nav-tabs .nav-link.disabled:hover{color:#818a91;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.open .nav-link,.nav-tabs .nav-item.open .nav-link:focus,.nav-tabs .nav-item.open .nav-link:hover,.nav-tabs .nav-link.active,.nav-tabs .nav-link.active:focus,.nav-tabs .nav-link.active:hover{color:#55595c;background-color:#fff;border-color:#ddd #ddd transparent}.nav-pills:after{content:"";display:table;clear:both}.nav-pills .nav-item{float:left}.nav-pills .nav-item+.nav-item{margin-left:.2rem}.nav-pills .nav-link{display:block;padding:.5em 1em;border-radius:.25rem}.nav-pills .nav-item.open .nav-link,.nav-pills .nav-item.open .nav-link:focus,.nav-pills .nav-item.open .nav-link:hover,.nav-pills .nav-link.active,.nav-pills .nav-link.active:focus,.nav-pills .nav-link.active:hover{color:#fff;cursor:default;background-color:#0275d8}.nav-stacked .nav-item{display:block;float:none}.nav-stacked .nav-item+.nav-item{margin-top:.2rem;margin-left:0}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;padding:.5rem 1rem}.navbar:after{content:"";display:table;clear:both}@media (min-width:544px){.navbar{border-radius:.25rem}}.navbar-full{z-index:1000}@media (min-width:544px){.navbar-full{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:544px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0}.navbar-fixed-bottom{bottom:0}.navbar-sticky-top{position:sticky;top:0;z-index:1030;width:100%}@media (min-width:544px){.navbar-sticky-top{border-radius:0}}.navbar-brand{float:left;padding-top:.25rem;padding-bottom:.25rem;margin-right:1rem;font-size:1.25rem}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}.navbar-divider{float:left;width:1px;padding-top:.425rem;padding-bottom:.425rem;margin-right:1rem;margin-left:1rem;overflow:hidden}.navbar-divider:before{content:"\A0"}.navbar-toggler{padding:.5rem .75rem;font-size:1.25rem;line-height:1;background:none;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}@media (min-width:544px){.navbar-toggleable-xs{display:block!important}}@media (min-width:768px){.navbar-toggleable-sm{display:block!important}}@media (min-width:992px){.navbar-toggleable-md{display:block!important}}.navbar-nav .nav-item{float:left}.navbar-nav .nav-link{display:block;padding-top:.425rem;padding-bottom:.425rem}.navbar-nav .nav-item+.nav-item,.navbar-nav .nav-link+.nav-link{margin-left:1rem}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.8)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.6)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .active>.nav-link:focus,.navbar-light .navbar-nav .active>.nav-link:hover,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.active:focus,.navbar-light .navbar-nav .nav-link.active:hover,.navbar-light .navbar-nav .nav-link.open,.navbar-light .navbar-nav .nav-link.open:focus,.navbar-light .navbar-nav .nav-link.open:hover,.navbar-light .navbar-nav .open>.nav-link,.navbar-light .navbar-nav .open>.nav-link:focus,.navbar-light .navbar-nav .open>.nav-link:hover{color:rgba(0,0,0,.8)}.navbar-light .navbar-divider{background-color:rgba(0,0,0,.075)}.navbar-dark .navbar-brand,.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:hsla(0,0%,100%,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:hsla(0,0%,100%,.75)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .active>.nav-link:focus,.navbar-dark .navbar-nav .active>.nav-link:hover,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.active:focus,.navbar-dark .navbar-nav .nav-link.active:hover,.navbar-dark .navbar-nav .nav-link.open,.navbar-dark .navbar-nav .nav-link.open:focus,.navbar-dark .navbar-nav .nav-link.open:hover,.navbar-dark .navbar-nav .open>.nav-link,.navbar-dark .navbar-nav .open>.nav-link:focus,.navbar-dark .navbar-nav .open>.nav-link:hover{color:#fff}.navbar-dark .navbar-divider{background-color:hsla(0,0%,100%,.075)}.card{position:relative;display:block;margin-bottom:.75rem;background-color:#fff;border:1px solid #e5e5e5;border-radius:.25rem}.card-block{padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem}.card-subtitle,.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card>.list-group:first-child .list-group-item:first-child{border-radius:.25rem .25rem 0 0}.card>.list-group:last-child .list-group-item:last-child{border-radius:0 0 .25rem .25rem}.card-header{padding:.75rem 1.25rem;background-color:#f5f5f5;border-bottom:1px solid #e5e5e5}.card-header:first-child{border-radius:.25rem .25rem 0 0}.card-footer{padding:.75rem 1.25rem;background-color:#f5f5f5;border-top:1px solid #e5e5e5}.card-footer:last-child{border-radius:0 0 .25rem .25rem}.card-primary{background-color:#0275d8;border-color:#0275d8}.card-success{background-color:#5cb85c;border-color:#5cb85c}.card-info{background-color:#5bc0de;border-color:#5bc0de}.card-warning{background-color:#f0ad4e;border-color:#f0ad4e}.card-danger{background-color:#d9534f;border-color:#d9534f}.card-primary-outline{background-color:transparent;border-color:#0275d8}.card-secondary-outline{background-color:transparent;border-color:#ccc}.card-info-outline{background-color:transparent;border-color:#5bc0de}.card-success-outline{background-color:transparent;border-color:#5cb85c}.card-warning-outline{background-color:transparent;border-color:#f0ad4e}.card-danger-outline{background-color:transparent;border-color:#d9534f}.card-inverse .card-footer,.card-inverse .card-header{border-bottom:1px solid hsla(0,0%,100%,.2)}.card-inverse .card-blockquote,.card-inverse .card-footer,.card-inverse .card-header,.card-inverse .card-title{color:#fff}.card-inverse .card-blockquote>footer,.card-inverse .card-link,.card-inverse .card-text{color:hsla(0,0%,100%,.65)}.card-inverse .card-link:focus,.card-inverse .card-link:hover{color:#fff}.card-blockquote{padding:0;margin-bottom:0;border-left:0}.card-img{border-radius:.25rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img-top{border-radius:.25rem .25rem 0 0}.card-img-bottom{border-radius:0 0 .25rem .25rem}@media (min-width:544px){.card-deck{display:table;table-layout:fixed;border-spacing:1.25rem 0}.card-deck .card{display:table-cell;width:1%;vertical-align:top}.card-deck-wrapper{margin-right:-1.25rem;margin-left:-1.25rem}}@media (min-width:544px){.card-group{display:table;width:100%;table-layout:fixed}.card-group .card{display:table-cell;vertical-align:top}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-bottom-right-radius:0;border-top-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-bottom-left-radius:0;border-top-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child),.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}}@media (min-width:544px){.card-columns{column-count:3;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#eceeef;border-radius:.25rem}.breadcrumb:after{content:"";display:table;clear:both}.breadcrumb>li{float:left}.breadcrumb>li+li:before{padding-right:.5rem;padding-left:.5rem;color:#818a91;content:"/"}.breadcrumb>.active{color:#818a91}.pagination{display:inline-block;padding-left:0;margin-top:1rem;margin-bottom:1rem;border-radius:.25rem}.page-item{display:inline}.page-item:first-child .page-link{margin-left:0;border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.page-item:last-child .page-link{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.page-item.active .page-link,.page-item.active .page-link:focus,.page-item.active .page-link:hover{z-index:2;color:#fff;cursor:default;background-color:#0275d8;border-color:#0275d8}.page-item.disabled .page-link,.page-item.disabled .page-link:focus,.page-item.disabled .page-link:hover{color:#818a91;cursor:not-allowed;background-color:#fff;border-color:#ddd}.page-link{position:relative;float:left;padding:.5rem .75rem;margin-left:-1px;line-height:1.5;color:#0275d8;text-decoration:none;background-color:#fff;border:1px solid #ddd}.page-link:focus,.page-link:hover{color:#014c8c;background-color:#eceeef;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.33333}.pagination-lg .page-item:first-child .page-link{border-bottom-left-radius:.3rem;border-top-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-bottom-right-radius:.3rem;border-top-right-radius:.3rem}.pagination-sm .page-link{padding:.275rem .75rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-bottom-left-radius:.2rem;border-top-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-bottom-right-radius:.2rem;border-top-right-radius:.2rem}.pager{padding-left:0;margin-top:1rem;margin-bottom:1rem;text-align:center;list-style:none}.pager:after{content:"";display:table;clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eceeef}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#818a91;cursor:not-allowed;background-color:#fff}.pager-next>a,.pager-next>span{float:right}.pager-prev>a,.pager-prev>span{float:left}.label{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.label:empty{display:none}.btn .label{position:relative;top:-1px}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.label-default{background-color:#818a91}.label-default[href]:focus,.label-default[href]:hover{background-color:#687077}.label-primary{background-color:#0275d8}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#025aa5}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#eceeef;border-radius:.3rem}@media (min-width:544px){.jumbotron{padding:4rem 2rem}}.jumbotron-hr{border-top-color:#d0d5d8}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:15px;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:35px}.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d0e9c6;color:#3c763d}.alert-success hr{border-top-color:#c1e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.alert-info hr{border-top-color:#a6d5ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faf2cc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7ecb5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebcccc;color:#a94442}.alert-danger hr{border-top-color:#e4b9b9}.alert-danger .alert-link{color:#843534}@keyframes progress-bar-stripes{0%{background-position:1rem 0}to{background-position:0 0}}.progress{display:block;width:100%;height:1rem;margin-bottom:1rem}.progress[value]{color:#0074d9;border:0;appearance:none}.progress[value]::-webkit-progress-bar{background-color:#eee;border-radius:.25rem}.progress[value]::-webkit-progress-value:before{content:attr(value)}.progress[value]::-webkit-progress-value{background-color:#0074d9;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.progress[value="100"]::-webkit-progress-value{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}@media screen and (min-width:0\0){.progress{background-color:#eee;border-radius:.25rem}.progress-bar{display:inline-block;height:1rem;text-indent:-999rem;background-color:#0074d9;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.progress[width^="0"]{min-width:2rem;color:#818a91;background-color:transparent;background-image:none}.progress[width="100%"]{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}}.progress-striped[value]::-webkit-progress-value{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 25%,transparent 50%,hsla(0,0%,100%,.15) 50%,hsla(0,0%,100%,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-striped[value]::-moz-progress-bar{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 25%,transparent 50%,hsla(0,0%,100%,.15) 50%,hsla(0,0%,100%,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}@media screen and (min-width:0\0){.progress-bar-striped{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 25%,transparent 50%,hsla(0,0%,100%,.15) 50%,hsla(0,0%,100%,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}}.progress-animated[value]::-webkit-progress-value{animation:progress-bar-stripes 2s linear infinite}.progress-animated[value]::-moz-progress-bar{animation:progress-bar-stripes 2s linear infinite}@media screen and (min-width:0\0){.progress-animated .progress-bar-striped{animation:progress-bar-stripes 2s linear infinite}}.progress-success[value]::-webkit-progress-value{background-color:#5cb85c}.progress-success[value]::-moz-progress-bar{background-color:#5cb85c}@media screen and (min-width:0\0){.progress-success .progress-bar{background-color:#5cb85c}}.progress-info[value]::-webkit-progress-value{background-color:#5bc0de}.progress-info[value]::-moz-progress-bar{background-color:#5bc0de}@media screen and (min-width:0\0){.progress-info .progress-bar{background-color:#5bc0de}}.progress-warning[value]::-webkit-progress-value{background-color:#f0ad4e}.progress-warning[value]::-moz-progress-bar{background-color:#f0ad4e}@media screen and (min-width:0\0){.progress-warning .progress-bar{background-color:#f0ad4e}}.progress-danger[value]::-webkit-progress-value{background-color:#d9534f}.progress-danger[value]::-moz-progress-bar{background-color:#d9534f}@media screen and (min-width:0\0){.progress-danger .progress-bar{background-color:#d9534f}}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:625pc}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right{padding-left:10px}.media-left{padding-right:10px}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:0}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:.25rem;border-top-left-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-flush .list-group-item{border-width:1px 0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}a.list-group-item,button.list-group-item{width:100%;color:#555;text-align:inherit}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#818a91;cursor:not-allowed;background-color:#eceeef}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#818a91}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#0275d8;border-color:#0275d8}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#a8d6fe}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9{padding-bottom:42.85714%}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.embed-responsive-1by1{padding-bottom:100%}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal,.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;outline:0;-webkit-overflow-scrolling:touch}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -25%)}.modal.in .modal-dialog{transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.in{opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header:after{content:"";display:table;clear:both}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.5}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:after{content:"";display:table;clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:544px){.modal-dialog{width:600px;margin:30px auto}.modal-sm{width:300px}}@media (min-width:768px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Open Sans;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:.875rem;opacity:0}.tooltip.in{opacity:.9}.tooltip.bs-tether-element-attached-bottom,.tooltip.tooltip-top{padding:5px 0;margin-top:-3px}.tooltip.bs-tether-element-attached-bottom .tooltip-arrow,.tooltip.tooltip-top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.bs-tether-element-attached-left,.tooltip.tooltip-right{padding:0 5px;margin-left:3px}.tooltip.bs-tether-element-attached-left .tooltip-arrow,.tooltip.tooltip-right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.bs-tether-element-attached-top,.tooltip.tooltip-bottom{padding:5px 0;margin-top:3px}.tooltip.bs-tether-element-attached-top .tooltip-arrow,.tooltip.tooltip-bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bs-tether-element-attached-right,.tooltip.tooltip-left{padding:0 5px;margin-left:-3px}.tooltip.bs-tether-element-attached-right .tooltip-arrow,.tooltip.tooltip-left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;padding:1px;font-family:Open Sans;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:.875rem;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover.bs-tether-element-attached-bottom,.popover.popover-top{margin-top:-10px}.popover.bs-tether-element-attached-bottom .popover-arrow,.popover.popover-top .popover-arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.bs-tether-element-attached-bottom .popover-arrow:after,.popover.popover-top .popover-arrow:after{bottom:1px;margin-left:-10px;content:"";border-top-color:#fff;border-bottom-width:0}.popover.bs-tether-element-attached-left,.popover.popover-right{margin-left:10px}.popover.bs-tether-element-attached-left .popover-arrow,.popover.popover-right .popover-arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.bs-tether-element-attached-left .popover-arrow:after,.popover.popover-right .popover-arrow:after{bottom:-10px;left:1px;content:"";border-right-color:#fff;border-left-width:0}.popover.bs-tether-element-attached-top,.popover.popover-bottom{margin-top:10px}.popover.bs-tether-element-attached-top .popover-arrow,.popover.popover-bottom .popover-arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-top .popover-arrow:after,.popover.popover-bottom .popover-arrow:after{top:1px;margin-left:-10px;content:"";border-top-width:0;border-bottom-color:#fff}.popover.bs-tether-element-attached-right,.popover.popover-left{margin-left:-10px}.popover.bs-tether-element-attached-right .popover-arrow,.popover.popover-left .popover-arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-right .popover-arrow:after,.popover.popover-left .popover-arrow:after{right:1px;bottom:-10px;content:"";border-right-width:0;border-left-color:#fff}.popover-title{padding:8px 14px;margin:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:-.7rem -.7rem 0 0}.popover-content{padding:9px 14px}.popover-arrow,.popover-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover-arrow{border-width:11px}.popover-arrow:after{content:"";border-width:10px}.carousel,.carousel-inner{position:relative}.carousel-inner{width:100%;overflow:hidden}.carousel-inner>.carousel-item{position:relative;display:none;transition:.6s ease-in-out left}.carousel-inner>.carousel-item>a>img,.carousel-inner>.carousel-item>img{line-height:1}@media (-webkit-transform-3d),all and (transform-3d){.carousel-inner>.carousel-item{transition:transform .6s ease-in-out;backface-visibility:hidden;perspective:750pt}.carousel-inner>.carousel-item.active.right,.carousel-inner>.carousel-item.next{left:0;transform:translate3d(100%,0,0)}.carousel-inner>.carousel-item.active.left,.carousel-inner>.carousel-item.prev{left:0;transform:translate3d(-100%,0,0)}.carousel-inner>.carousel-item.active,.carousel-inner>.carousel-item.next.left,.carousel-inner>.carousel-item.prev.right{left:0;transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);opacity:.5}.carousel-control.left{background-image:linear-gradient(to right,rgba(0,0,0,.5) 0%,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0%,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-prev:before{content:"\2039"}.carousel-control .icon-next:before{content:"\203A"}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:transparent;border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:9pt;height:9pt;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media (min-width:544px){.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .icon-prev{margin-left:-15px}.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:after{content:"";display:table;clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-xs-left{float:left!important}.pull-xs-right{float:right!important}.pull-xs-none{float:none!important}@media (min-width:544px){.pull-sm-left{float:left!important}.pull-sm-right{float:right!important}.pull-sm-none{float:none!important}}@media (min-width:768px){.pull-md-left{float:left!important}.pull-md-right{float:right!important}.pull-md-none{float:none!important}}@media (min-width:992px){.pull-lg-left{float:left!important}.pull-lg-right{float:right!important}.pull-lg-none{float:none!important}}@media (min-width:1200px){.pull-xl-left{float:left!important}.pull-xl-right{float:right!important}.pull-xl-none{float:none!important}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.invisible{visibility:hidden!important}.text-hide{font:0\/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-xs-left{text-align:left!important}.text-xs-right{text-align:right!important}.text-xs-center{text-align:center!important}@media (min-width:544px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-muted{color:#818a91}.text-primary{color:#0275d8!important}a.text-primary:focus,a.text-primary:hover{color:#025aa5}.text-success{color:#5cb85c!important}a.text-success:focus,a.text-success:hover{color:#449d44}.text-info{color:#5bc0de!important}a.text-info:focus,a.text-info:hover{color:#31b0d5}.text-warning{color:#f0ad4e!important}a.text-warning:focus,a.text-warning:hover{color:#ec971f}.text-danger{color:#d9534f!important}a.text-danger:focus,a.text-danger:hover{color:#c9302c}.bg-inverse{color:#eceeef;background-color:#373a3c}.bg-faded{background-color:#f7f7f9}.bg-primary{color:#fff!important;background-color:#0275d8!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#025aa5}.bg-success{color:#fff!important;background-color:#5cb85c!important}a.bg-success:focus,a.bg-success:hover{background-color:#449d44}.bg-info{color:#fff!important;background-color:#5bc0de!important}a.bg-info:focus,a.bg-info:hover{background-color:#31b0d5}.bg-warning{color:#fff!important;background-color:#f0ad4e!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#ec971f}.bg-danger{color:#fff!important;background-color:#d9534f!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#c9302c}.m-x-auto{margin-right:auto!important;margin-left:auto!important}.m-a-0{margin:0!important}.m-t-0{margin-top:0!important}.m-r-0{margin-right:0!important}.m-b-0{margin-bottom:0!important}.m-l-0,.m-x-0{margin-left:0!important}.m-x-0{margin-right:0!important}.m-y-0{margin-top:0!important;margin-bottom:0!important}.m-a-1{margin:1rem!important}.m-t-1{margin-top:1rem!important}.m-r-1{margin-right:1rem!important}.m-b-1{margin-bottom:1rem!important}.m-l-1,.m-x-1{margin-left:1rem!important}.m-x-1{margin-right:1rem!important}.m-y-1{margin-top:1rem!important;margin-bottom:1rem!important}.m-a-2{margin:1.5rem!important}.m-t-2{margin-top:1.5rem!important}.m-r-2{margin-right:1.5rem!important}.m-b-2{margin-bottom:1.5rem!important}.m-l-2,.m-x-2{margin-left:1.5rem!important}.m-x-2{margin-right:1.5rem!important}.m-y-2{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-a-3{margin:3rem!important}.m-t-3{margin-top:3rem!important}.m-r-3{margin-right:3rem!important}.m-b-3{margin-bottom:3rem!important}.m-l-3,.m-x-3{margin-left:3rem!important}.m-x-3{margin-right:3rem!important}.m-y-3{margin-top:3rem!important;margin-bottom:3rem!important}.p-a-0{padding:0!important}.p-t-0{padding-top:0!important}.p-r-0{padding-right:0!important}.p-b-0{padding-bottom:0!important}.p-l-0,.p-x-0{padding-left:0!important}.p-x-0{padding-right:0!important}.p-y-0{padding-top:0!important;padding-bottom:0!important}.p-a-1{padding:1rem!important}.p-t-1{padding-top:1rem!important}.p-r-1{padding-right:1rem!important}.p-b-1{padding-bottom:1rem!important}.p-l-1,.p-x-1{padding-left:1rem!important}.p-x-1{padding-right:1rem!important}.p-y-1{padding-top:1rem!important;padding-bottom:1rem!important}.p-a-2{padding:1.5rem!important}.p-t-2{padding-top:1.5rem!important}.p-r-2{padding-right:1.5rem!important}.p-b-2{padding-bottom:1.5rem!important}.p-l-2,.p-x-2{padding-left:1.5rem!important}.p-x-2{padding-right:1.5rem!important}.p-y-2{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-a-3{padding:3rem!important}.p-t-3{padding-top:3rem!important}.p-r-3{padding-right:3rem!important}.p-b-3{padding-bottom:3rem!important}.p-l-3,.p-x-3{padding-left:3rem!important}.p-x-3{padding-right:3rem!important}.p-y-3{padding-top:3rem!important;padding-bottom:3rem!important}.pos-f-t{position:fixed;top:0;right:0;left:0;z-index:1030}.hidden-xs-up{display:none!important}@media (max-width:543px){.hidden-xs-down{display:none!important}}@media (min-width:544px){.hidden-sm-up{display:none!important}}@media (max-width:767px){.hidden-sm-down{display:none!important}}@media (min-width:768px){.hidden-md-up{display:none!important}}@media (max-width:991px){.hidden-md-down{display:none!important}}@media (min-width:992px){.hidden-lg-up{display:none!important}}@media (max-width:1199px){.hidden-lg-down{display:none!important}}@media (min-width:1200px){.hidden-xl-up{display:none!important}}.hidden-xl-down,.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}.container-narrow{margin-left:auto;margin-right:auto;padding-left:.9375rem;padding-right:.9375rem}.container-narrow:after{content:"";display:table;clear:both}@media (min-width:544px){.container-narrow{max-width:34rem}}@media (min-width:768px){.container-narrow{max-width:45rem}}@media (min-width:992px){.container-narrow{max-width:45rem}}@media (min-width:1200px){.container-narrow{max-width:45rem}}.nav-justified{width:100%}.nav-justified>li{display:table-cell;width:1%;float:none!important;text-align:center}.nav-underline .nav-item.active,.nav-underline .nav-item.active:hover{box-shadow:0 -3px 0 0 #0275d8 inset}.nav-underline .nav-item.active .nav-link,.nav-underline .nav-item.active:hover .nav-link{color:#0275d8}.nav-underline li:hover{box-shadow:0 -3px 0 0 #ddd inset}.nav-underline li{padding-top:.2rem;padding-bottom:.2rem}.navbar-underline{background-color:#d5d5d5;border-top:1px solid #c8c8c8}pre{background-color:#fdf6e3;padding:1rem}.table-expand-col{min-width:100%}body{background-color:#373a3c}.card-success{background-color:#dff0d8;border-color:#d0e9c6;color:#3c763d}.card-success hr{border-top-color:#c1e2b3}.card-success .alert-link{color:#2b542c}.card-success .card-header{background-color:#d0e9c6;border-bottom:1px solid #c1e2b3}.card-info{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.card-info hr{border-top-color:#a6d5ec}.card-info .alert-link{color:#245269}.card-info .card-header{background-color:#c4e3f3;border-bottom:1px solid #afd9ee}.card-warning{background-color:#fcf8e3;border-color:#faf2cc;color:#8a6d3b}.card-warning hr{border-top-color:#f7ecb5}.card-warning .alert-link{color:#66512c}.card-warning .card-header{background-color:#faf2cc;border-bottom:1px solid #f7ecb5}.card-danger{background-color:#f2dede;border-color:#ebcccc;color:#a94442}.card-danger hr{border-top-color:#e4b9b9}.card-danger .alert-link{color:#843534}.card-danger .card-header{background-color:#ebcccc;border-bottom:1px solid #e4b9b9}.masthead{background-image:linear-gradient(to bottom,#eee 0%,#ddd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE',endColorstr='#FFDDDDDD',GradientType=0);padding-top:10px;padding-bottom:10px}.footer{background-color:#373a3c}.bodycontent{background:#fff}.document-docutils>.section{padding-bottom:1rem}.document-docutils pre .comment{color:#586e75}.document-docutils pre .error,.document-docutils pre .generic{color:#93a1a1}.document-docutils pre .keyword{color:#859900}.document-docutils pre .literal,.document-docutils pre .name{color:#93a1a1}.document-docutils pre .operator{color:#859900}.document-docutils pre .other{color:#cb4b16}.document-docutils pre .punctuation{color:#93a1a1}.document-docutils pre .comment.multiline{color:#586e75}.document-docutils pre .comment.preproc{color:#859900}.document-docutils pre .comment.single{color:#586e75}.document-docutils pre .comment.special{color:#859900}.document-docutils pre .generic.deleted{color:#2aa198}.document-docutils pre .generic.emph{color:#93a1a1;font-style:italic}.document-docutils pre .generic.error{color:#dc322f}.document-docutils pre .generic.heading{color:#cb4b16}.document-docutils pre .generic.inserted{color:#859900}.document-docutils pre .generic.output,.document-docutils pre .generic.prompt{color:#93a1a1}.document-docutils pre .generic.strong{color:#93a1a1;font-weight:700}.document-docutils pre .generic.subheading{color:#cb4b16}.document-docutils pre .generic.traceback{color:#93a1a1}.document-docutils pre .keyword.constant{color:#cb4b16}.document-docutils pre .keyword.declaration{color:#268bd2}.document-docutils pre .keyword.namespace,.document-docutils pre .keyword.pseudo{color:#859900}.document-docutils pre .keyword.reserved{color:#268bd2}.document-docutils pre .keyword.type{color:#dc322f}.document-docutils pre .literal.date{color:#93a1a1}.document-docutils pre .literal.number,.document-docutils pre .literal.string{color:#2aa198}.document-docutils pre .name.attribute{color:#93a1a1}.document-docutils pre .name.builtin{color:#b58900}.document-docutils pre .name.class{color:#268bd2}.document-docutils pre .name.constant{color:#cb4b16}.document-docutils pre .name.decorator{color:#268bd2}.document-docutils pre .name.entity,.document-docutils pre .name.exception{color:#cb4b16}.document-docutils pre .name.function{color:#268bd2}.document-docutils pre .name.label,.document-docutils pre .name.namespace,.document-docutils pre .name.other,.document-docutils pre .name.property{color:#93a1a1}.document-docutils pre .name.tag,.document-docutils pre .name.variable{color:#268bd2}.document-docutils pre .operator.word{color:#859900}.document-docutils pre .text.whitespace{color:#93a1a1}.document-docutils pre .literal.number.float,.document-docutils pre .literal.number.hex,.document-docutils pre .literal.number.integer,.document-docutils pre .literal.number.oct{color:#2aa198}.document-docutils pre .literal.string.backtick{color:#586e75}.document-docutils pre .literal.string.char{color:#2aa198}.document-docutils pre .literal.string.doc{color:#93a1a1}.document-docutils pre .literal.string.double{color:#2aa198}.document-docutils pre .literal.string.escape{color:#cb4b16}.document-docutils pre .literal.string.heredoc{color:#93a1a1}.document-docutils pre .literal.string.interpol,.document-docutils pre .literal.string.other{color:#2aa198}.document-docutils pre .literal.string.regex{color:#dc322f}.document-docutils pre .literal.string.single,.document-docutils pre .literal.string.symbol{color:#2aa198}.document-docutils pre .name.builtin.pseudo,.document-docutils pre .name.variable.class,.document-docutils pre .name.variable.global,.document-docutils pre .name.variable.instance{color:#268bd2}.document-docutils pre .literal.number.integer.long{color:#2aa198}
\ No newline at end of file
diff --git a/hubs/static/fedora-bootstrap/fedora-bootstrap.js b/hubs/static/fedora-bootstrap/fedora-bootstrap.js
deleted file mode 100644
index 347d583..0000000
--- a/hubs/static/fedora-bootstrap/fedora-bootstrap.js
+++ /dev/null
@@ -1,4 +0,0 @@
-!function(t){function e(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return t[i].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";n(2),n(4),n(14),console.log("Hello World")},function(t,e,n){var i,o,r;!function(n,s){o=[e,t],i=s,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e){"use strict";var n=function(t){function e(t){return{}.toString.call(t).match(/\s([a-zA-Z]+)/)[1].toLowerCase()}function n(t){return(t[0]||t).nodeType}function i(){return{bindType:a.end,delegateType:a.end,handle:function(e){return t(e.target).is(this)?e.handleObj.handler.apply(this,arguments):void 0}}}function o(){if(window.QUnit)return!1;var t=document.createElement("bootstrap");for(var e in l)if(void 0!==t.style[e])return{end:l[e]};return!1}function r(e){var n=this,i=!1;return t(this).one(u.TRANSITION_END,function(){i=!0}),setTimeout(function(){i||u.triggerTransitionEnd(n)},e),this}function s(){a=o(),t.fn.emulateTransitionEnd=r,u.supportsTransitionEnd()&&(t.event.special[u.TRANSITION_END]=i())}var a=!1,l={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},u={TRANSITION_END:"bsTransitionEnd",getUID:function(t){do t+=~~(1e6*Math.random());while(document.getElementById(t));return t},getSelectorFromElement:function(t){var e=t.getAttribute("data-target");return e||(e=t.getAttribute("href")||"",e=/^#[a-z]/i.test(e)?e:null),e},reflow:function(t){new Function("bs","return bs")(t.offsetHeight)},triggerTransitionEnd:function(e){t(e).trigger(a.end)},supportsTransitionEnd:function(){return Boolean(a)},typeCheckConfig:function(t,i,o){for(var r in o)if(o.hasOwnProperty(r)){var s=o[r],a=i[r],l=void 0;if(l=a&&n(a)?"element":e(a),!new RegExp(s).test(l))throw new Error(t.toUpperCase()+": "+('Option "'+r+'" provided type "'+l+'" ')+('but expected type "'+s+'".'))}}};return s(),u}(jQuery);e.exports=n})},function(t,e,n){var i,o;/*! tether 1.2.3 */
-!function(r,s){i=s,o="function"==typeof i?i.call(e,n,e,t):i,!(void 0!==o&&(t.exports=o))}(this,function(t,e,n){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t){var e=getComputedStyle(t)||{},n=e.position,i=[];if("fixed"===n)return[t];for(var o=t;o=o.parentNode;){var r=void 0;try{r=getComputedStyle(o)}catch(s){}if("undefined"==typeof r||null===r)return i.push(o),i;var a=r,l=a.overflow,u=a.overflowX,f=a.overflowY;/(auto|scroll)/.test(l+f+u)&&("absolute"!==n||["relative","absolute","fixed"].indexOf(r.position)>=0)&&i.push(o)}return i.push(document.body),i}function r(t){var e=void 0;t===document?(e=document,t=document.documentElement):e=t.ownerDocument;var n=e.documentElement,i={},o=t.getBoundingClientRect();for(var r in o)i[r]=o[r];var s=I(e);return i.top-=s.top,i.left-=s.left,"undefined"==typeof i.width&&(i.width=document.body.scrollWidth-i.left-i.right),"undefined"==typeof i.height&&(i.height=document.body.scrollHeight-i.top-i.bottom),i.top=i.top-n.clientTop,i.left=i.left-n.clientLeft,i.right=e.body.clientWidth-i.width-i.left,i.bottom=e.body.clientHeight-i.height-i.top,i}function s(t){return t.offsetParent||document.documentElement}function a(){var t=document.createElement("div");t.style.width="100%",t.style.height="200px";var e=document.createElement("div");l(e.style,{position:"absolute",top:0,left:0,pointerEvents:"none",visibility:"hidden",width:"200px",height:"150px",overflow:"hidden"}),e.appendChild(t),document.body.appendChild(e);var n=t.offsetWidth;e.style.overflow="scroll";var i=t.offsetWidth;n===i&&(i=e.clientWidth),document.body.removeChild(e);var o=n-i;return{width:o,height:o}}function l(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],e=[];return Array.prototype.push.apply(e,arguments),e.slice(1).forEach(function(e){if(e)for(var n in e)({}).hasOwnProperty.call(e,n)&&(t[n]=e[n])}),t}function u(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.remove(e)});else{var n=new RegExp("(^| )"+e.split(" ").join("|")+"( |$)","gi"),i=c(t).replace(n," ");d(t,i)}}function f(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.add(e)});else{u(t,e);var n=c(t)+(" "+e);d(t,n)}}function h(t,e){if("undefined"!=typeof t.classList)return t.classList.contains(e);var n=c(t);return new RegExp("(^| )"+e+"( |$)","gi").test(n)}function c(t){return t.className instanceof SVGAnimatedString?t.className.baseVal:t.className}function d(t,e){t.setAttribute("class",e)}function p(t,e,n){n.forEach(function(n){-1===e.indexOf(n)&&h(t,n)&&u(t,n)}),e.forEach(function(e){h(t,e)||f(t,e)})}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function g(t,e){var n=arguments.length<=2||void 0===arguments[2]?1:arguments[2];return t+n>=e&&e>=t-n}function v(){return"undefined"!=typeof performance&&"undefined"!=typeof performance.now?performance.now():+new Date}function m(){for(var t={top:0,left:0},e=arguments.length,n=Array(e),i=0;e>i;i++)n[i]=arguments[i];return n.forEach(function(e){var n=e.top,i=e.left;"string"==typeof n&&(n=parseFloat(n,10)),"string"==typeof i&&(i=parseFloat(i,10)),t.top+=n,t.left+=i}),t}function _(t,e){return"string"==typeof t.left&&-1!==t.left.indexOf("%")&&(t.left=parseFloat(t.left,10)/100*e.width),"string"==typeof t.top&&-1!==t.top.indexOf("%")&&(t.top=parseFloat(t.top,10)/100*e.height),t}function y(t,e){return"scrollParent"===e?e=t.scrollParents[0]:"window"===e&&(e=[pageXOffset,pageYOffset,innerWidth+pageXOffset,innerHeight+pageYOffset]),e===document&&(e=e.documentElement),"undefined"!=typeof e.nodeType&&!function(){var t=r(e),n=t,i=getComputedStyle(e);e=[n.left,n.top,t.width+n.left,t.height+n.top],B.forEach(function(t,n){t=t[0].toUpperCase()+t.substr(1),"Top"===t||"Left"===t?e[n]+=parseFloat(i["border"+t+"Width"]):e[n]-=parseFloat(i["border"+t+"Width"])})}(),e}var E=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),T=void 0;"undefined"==typeof T&&(T={modules:[]});var C=function(){var t=0;return function(){return++t}}(),b={},I=function(t){var e=t._tetherZeroElement;"undefined"==typeof e&&(e=t.createElement("div"),e.setAttribute("data-tether-id",C()),l(e.style,{top:0,left:0,position:"absolute"}),t.body.appendChild(e),t._tetherZeroElement=e);var n=e.getAttribute("data-tether-id");if("undefined"==typeof b[n]){b[n]={};var i=e.getBoundingClientRect();for(var o in i)b[n][o]=i[o];O(function(){delete b[n]})}return b[n]},A=[],O=function(t){A.push(t)},D=function(){for(var t=void 0;t=A.pop();)t()},w=function(){function t(){i(this,t)}return E(t,[{key:"on",value:function(t,e,n){var i=arguments.length<=3||void 0===arguments[3]?!1:arguments[3];"undefined"==typeof this.bindings&&(this.bindings={}),"undefined"==typeof this.bindings[t]&&(this.bindings[t]=[]),this.bindings[t].push({handler:e,ctx:n,once:i})}},{key:"once",value:function(t,e,n){this.on(t,e,n,!0)}},{key:"off",value:function(t,e){if("undefined"==typeof this.bindings||"undefined"==typeof this.bindings[t])if("undefined"==typeof e)delete this.bindings[t];else for(var n=0;n<this.bindings[t].length;)this.bindings[t][n].handler===e?this.bindings[t].splice(n,1):++n}},{key:"trigger",value:function(t){if("undefined"!=typeof this.bindings&&this.bindings[t]){for(var e=0,n=arguments.length,i=Array(n>1?n-1:0),o=1;n>o;o++)i[o-1]=arguments[o];for(;e<this.bindings[t].length;){var r=this.bindings[t][e],s=r.handler,a=r.ctx,l=r.once,u=a;"undefined"==typeof u&&(u=this),s.apply(u,i),l?this.bindings[t].splice(e,1):++e}}}}]),t}();T.Utils={getScrollParents:o,getBounds:r,getOffsetParent:s,extend:l,addClass:f,removeClass:u,hasClass:h,updateClasses:p,defer:O,flush:D,uniqueId:C,Evented:w,getScrollBarSize:a};var S=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(l){o=!0,r=l}finally{try{!i&&a["return"]&&a["return"]()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),E=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}();if("undefined"==typeof T)throw new Error("You must include the utils.js file before tether.js");var N=T.Utils,o=N.getScrollParents,r=N.getBounds,s=N.getOffsetParent,l=N.extend,f=N.addClass,u=N.removeClass,p=N.updateClasses,O=N.defer,D=N.flush,a=N.getScrollBarSize,k=function(){if("undefined"==typeof document)return"";for(var t=document.createElement("div"),e=["transform","webkitTransform","OTransform","MozTransform","msTransform"],n=0;n<e.length;++n){var i=e[n];if(void 0!==t.style[i])return i}}(),L=[],P=function(){L.forEach(function(t){t.position(!1)}),D()};!function(){var t=null,e=null,n=null,i=function o(){return"undefined"!=typeof e&&e>16?(e=Math.min(e-16,250),void(n=setTimeout(o,250))):void("undefined"!=typeof t&&v()-t<10||("undefined"!=typeof n&&(clearTimeout(n),n=null),t=v(),P(),e=v()-t))};"undefined"!=typeof window&&"undefined"!=typeof window.addEventListener&&["resize","scroll","touchmove"].forEach(function(t){window.addEventListener(t,i)})}();var x={center:"center",left:"right",right:"left"},R={middle:"middle",top:"bottom",bottom:"top"},H={top:0,left:0,middle:"50%",center:"50%",bottom:"100%",right:"100%"},W=function(t,e){var n=t.left,i=t.top;return"auto"===n&&(n=x[e.left]),"auto"===i&&(i=R[e.top]),{left:n,top:i}},M=function(t){var e=t.left,n=t.top;return"undefined"!=typeof H[t.left]&&(e=H[t.left]),"undefined"!=typeof H[t.top]&&(n=H[t.top]),{left:e,top:n}},j=function(t){var e=t.split(" "),n=S(e,2),i=n[0],o=n[1];return{top:i,left:o}},V=j,U=function(){function t(e){var n=this;i(this,t),this.position=this.position.bind(this),L.push(this),this.history=[],this.setOptions(e,!1),T.modules.forEach(function(t){"undefined"!=typeof t.initialize&&t.initialize.call(n)}),this.position()}return E(t,[{key:"getClass",value:function(){var t=arguments.length<=0||void 0===arguments[0]?"":arguments[0],e=this.options.classes;return"undefined"!=typeof e&&e[t]?this.options.classes[t]:this.options.classPrefix?this.options.classPrefix+"-"+t:t}},{key:"setOptions",value:function(t){var e=this,n=arguments.length<=1||void 0===arguments[1]?!0:arguments[1],i={offset:"0 0",targetOffset:"0 0",targetAttachment:"auto auto",classPrefix:"tether"};this.options=l(i,t);var r=this.options,s=r.element,a=r.target,u=r.targetModifier;if(this.element=s,this.target=a,this.targetModifier=u,"viewport"===this.target?(this.target=document.body,this.targetModifier="visible"):"scroll-handle"===this.target&&(this.target=document.body,this.targetModifier="scroll-handle"),["element","target"].forEach(function(t){if("undefined"==typeof e[t])throw new Error("Tether Error: Both element and target must be defined");"undefined"!=typeof e[t].jquery?e[t]=e[t][0]:"string"==typeof e[t]&&(e[t]=document.querySelector(e[t]))}),f(this.element,this.getClass("element")),this.options.addTargetClasses!==!1&&f(this.target,this.getClass("target")),!this.options.attachment)throw new Error("Tether Error: You must provide an attachment");this.targetAttachment=V(this.options.targetAttachment),this.attachment=V(this.options.attachment),this.offset=j(this.options.offset),this.targetOffset=j(this.options.targetOffset),"undefined"!=typeof this.scrollParents&&this.disable(),"scroll-handle"===this.targetModifier?this.scrollParents=[this.target]:this.scrollParents=o(this.target),this.options.enabled!==!1&&this.enable(n)}},{key:"getTargetBounds",value:function(){if("undefined"==typeof this.targetModifier)return r(this.target);if("visible"===this.targetModifier){if(this.target===document.body)return{top:pageYOffset,left:pageXOffset,height:innerHeight,width:innerWidth};var t=r(this.target),e={height:t.height,width:t.width,top:t.top,left:t.left};return e.height=Math.min(e.height,t.height-(pageYOffset-t.top)),e.height=Math.min(e.height,t.height-(t.top+t.height-(pageYOffset+innerHeight))),e.height=Math.min(innerHeight,e.height),e.height-=2,e.width=Math.min(e.width,t.width-(pageXOffset-t.left)),e.width=Math.min(e.width,t.width-(t.left+t.width-(pageXOffset+innerWidth))),e.width=Math.min(innerWidth,e.width),e.width-=2,e.top<pageYOffset&&(e.top=pageYOffset),e.left<pageXOffset&&(e.left=pageXOffset),e}if("scroll-handle"===this.targetModifier){var t=void 0,n=this.target;n===document.body?(n=document.documentElement,t={left:pageXOffset,top:pageYOffset,height:innerHeight,width:innerWidth}):t=r(n);var i=getComputedStyle(n),o=n.scrollWidth>n.clientWidth||[i.overflow,i.overflowX].indexOf("scroll")>=0||this.target!==document.body,s=0;o&&(s=15);var a=t.height-parseFloat(i.borderTopWidth)-parseFloat(i.borderBottomWidth)-s,e={width:15,height:.975*a*(a/n.scrollHeight),left:t.left+t.width-parseFloat(i.borderLeftWidth)-15},l=0;408>a&&this.target===document.body&&(l=-11e-5*Math.pow(a,2)-.00727*a+22.58),this.target!==document.body&&(e.height=Math.max(e.height,24));var u=this.target.scrollTop/(n.scrollHeight-a);return e.top=u*(a-e.height-l)+t.top+parseFloat(i.borderTopWidth),this.target===document.body&&(e.height=Math.max(e.height,24)),e}}},{key:"clearCache",value:function(){this._cache={}}},{key:"cache",value:function(t,e){return"undefined"==typeof this._cache&&(this._cache={}),"undefined"==typeof this._cache[t]&&(this._cache[t]=e.call(this)),this._cache[t]}},{key:"enable",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]?!0:arguments[0];this.options.addTargetClasses!==!1&&f(this.target,this.getClass("enabled")),f(this.element,this.getClass("enabled")),this.enabled=!0,this.scrollParents.forEach(function(e){e!==document&&e.addEventListener("scroll",t.position)}),e&&this.position()}},{key:"disable",value:function(){var t=this;u(this.target,this.getClass("enabled")),u(this.element,this.getClass("enabled")),this.enabled=!1,"undefined"!=typeof this.scrollParents&&this.scrollParents.forEach(function(e){e.removeEventListener("scroll",t.position)})}},{key:"destroy",value:function(){var t=this;this.disable(),L.forEach(function(e,n){return e===t?void L.splice(n,1):void 0})}},{key:"updateAttachClasses",value:function(t,e){var n=this;t=t||this.attachment,e=e||this.targetAttachment;var i=["left","top","bottom","right","middle","center"];"undefined"!=typeof this._addAttachClasses&&this._addAttachClasses.length&&this._addAttachClasses.splice(0,this._addAttachClasses.length),"undefined"==typeof this._addAttachClasses&&(this._addAttachClasses=[]);var o=this._addAttachClasses;t.top&&o.push(this.getClass("element-attached")+"-"+t.top),t.left&&o.push(this.getClass("element-attached")+"-"+t.left),e.top&&o.push(this.getClass("target-attached")+"-"+e.top),e.left&&o.push(this.getClass("target-attached")+"-"+e.left);var r=[];i.forEach(function(t){r.push(n.getClass("element-attached")+"-"+t),r.push(n.getClass("target-attached")+"-"+t)}),O(function(){"undefined"!=typeof n._addAttachClasses&&(p(n.element,n._addAttachClasses,r),n.options.addTargetClasses!==!1&&p(n.target,n._addAttachClasses,r),delete n._addAttachClasses)})}},{key:"position",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]?!0:arguments[0];if(this.enabled){this.clearCache();var n=W(this.targetAttachment,this.attachment);this.updateAttachClasses(this.attachment,n);var i=this.cache("element-bounds",function(){return r(t.element)}),o=i.width,l=i.height;if(0===o&&0===l&&"undefined"!=typeof this.lastSize){var u=this.lastSize;o=u.width,l=u.height}else this.lastSize={width:o,height:l};var f=this.cache("target-bounds",function(){return t.getTargetBounds()}),h=f,c=_(M(this.attachment),{width:o,height:l}),d=_(M(n),h),p=_(this.offset,{width:o,height:l}),g=_(this.targetOffset,h);c=m(c,p),d=m(d,g);for(var v=f.left+d.left-c.left,y=f.top+d.top-c.top,E=0;E<T.modules.length;++E){var C=T.modules[E],b=C.position.call(this,{left:v,top:y,targetAttachment:n,targetPos:f,elementPos:i,offset:c,targetOffset:d,manualOffset:p,manualTargetOffset:g,scrollbarSize:A,attachment:this.attachment});if(b===!1)return!1;"undefined"!=typeof b&&"object"==typeof b&&(y=b.top,v=b.left)}var I={page:{top:y,left:v},viewport:{top:y-pageYOffset,bottom:pageYOffset-y-l+innerHeight,left:v-pageXOffset,right:pageXOffset-v-o+innerWidth}},A=void 0;return document.body.scrollWidth>window.innerWidth&&(A=this.cache("scrollbar-size",a),I.viewport.bottom-=A.height),document.body.scrollHeight>window.innerHeight&&(A=this.cache("scrollbar-size",a),I.viewport.right-=A.width),-1!==["","static"].indexOf(document.body.style.position)&&-1!==["","static"].indexOf(document.body.parentElement.style.position)||(I.page.bottom=document.body.scrollHeight-y-l,I.page.right=document.body.scrollWidth-v-o),"undefined"!=typeof this.options.optimizations&&this.options.optimizations.moveElement!==!1&&"undefined"==typeof this.targetModifier&&!function(){var e=t.cache("target-offsetparent",function(){return s(t.target)}),n=t.cache("target-offsetparent-bounds",function(){return r(e)}),i=getComputedStyle(e),o=n,a={};if(["Top","Left","Bottom","Right"].forEach(function(t){a[t.toLowerCase()]=parseFloat(i["border"+t+"Width"])}),n.right=document.body.scrollWidth-n.left-o.width+a.right,n.bottom=document.body.scrollHeight-n.top-o.height+a.bottom,I.page.top>=n.top+a.top&&I.page.bottom>=n.bottom&&I.page.left>=n.left+a.left&&I.page.right>=n.right){var l=e.scrollTop,u=e.scrollLeft;I.offset={top:I.page.top-n.top+l-a.top,left:I.page.left-n.left+u-a.left}}}(),this.move(I),this.history.unshift(I),this.history.length>3&&this.history.pop(),e&&D(),!0}}},{key:"move",value:function(t){var e=this;if("undefined"!=typeof this.element.parentNode){var n={};for(var i in t){n[i]={};for(var o in t[i]){for(var r=!1,a=0;a<this.history.length;++a){var u=this.history[a];if("undefined"!=typeof u[i]&&!g(u[i][o],t[i][o])){r=!0;break}}r||(n[i][o]=!0)}}var f={top:"",left:"",right:"",bottom:""},h=function(t,n){var i="undefined"!=typeof e.options.optimizations,o=i?e.options.optimizations.gpu:null;if(o!==!1){var r=void 0,s=void 0;t.top?(f.top=0,r=n.top):(f.bottom=0,r=-n.bottom),t.left?(f.left=0,s=n.left):(f.right=0,s=-n.right),f[k]="translateX("+Math.round(s)+"px) translateY("+Math.round(r)+"px)","msTransform"!==k&&(f[k]+=" translateZ(0)")}else t.top?f.top=n.top+"px":f.bottom=n.bottom+"px",t.left?f.left=n.left+"px":f.right=n.right+"px"},c=!1;if((n.page.top||n.page.bottom)&&(n.page.left||n.page.right)?(f.position="absolute",h(n.page,t.page)):(n.viewport.top||n.viewport.bottom)&&(n.viewport.left||n.viewport.right)?(f.position="fixed",h(n.viewport,t.viewport)):"undefined"!=typeof n.offset&&n.offset.top&&n.offset.left?!function(){f.position="absolute";var i=e.cache("target-offsetparent",function(){return s(e.target)});s(e.element)!==i&&O(function(){e.element.parentNode.removeChild(e.element),i.appendChild(e.element)}),h(n.offset,t.offset),c=!0}():(f.position="absolute",h({top:!0,left:!0},t.page)),!c){for(var d=!0,p=this.element.parentNode;p&&"BODY"!==p.tagName;){if("static"!==getComputedStyle(p).position){d=!1;break}p=p.parentNode}d||(this.element.parentNode.removeChild(this.element),document.body.appendChild(this.element))}var v={},m=!1;for(var o in f){var _=f[o],y=this.element.style[o];y!==_&&(m=!0,v[o]=_)}m&&O(function(){l(e.element.style,v)})}}}]),t}();U.modules=[],T.position=P;var F=l(U,T),S=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(l){o=!0,r=l}finally{try{!i&&a["return"]&&a["return"]()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),N=T.Utils,r=N.getBounds,l=N.extend,p=N.updateClasses,O=N.defer,B=["left","top","right","bottom"];T.modules.push({position:function(t){var e=this,n=t.top,i=t.left,o=t.targetAttachment;if(!this.options.constraints)return!0;var s=this.cache("element-bounds",function(){return r(e.element)}),a=s.height,u=s.width;if(0===u&&0===a&&"undefined"!=typeof this.lastSize){var f=this.lastSize;u=f.width,a=f.height}var h=this.cache("target-bounds",function(){return e.getTargetBounds()}),c=h.height,d=h.width,g=[this.getClass("pinned"),this.getClass("out-of-bounds")];this.options.constraints.forEach(function(t){var e=t.outOfBoundsClass,n=t.pinnedClass;e&&g.push(e),n&&g.push(n)}),g.forEach(function(t){["left","top","right","bottom"].forEach(function(e){g.push(t+"-"+e)})});var v=[],m=l({},o),_=l({},this.attachment);return this.options.constraints.forEach(function(t){var r=t.to,s=t.attachment,l=t.pin;"undefined"==typeof s&&(s="");var f=void 0,h=void 0;if(s.indexOf(" ")>=0){var p=s.split(" "),g=S(p,2);h=g[0],f=g[1]}else f=h=s;var E=y(e,r);"target"!==h&&"both"!==h||(n<E[1]&&"top"===m.top&&(n+=c,m.top="bottom"),n+a>E[3]&&"bottom"===m.top&&(n-=c,m.top="top")),"together"===h&&("top"===m.top&&("bottom"===_.top&&n<E[1]?(n+=c,m.top="bottom",n+=a,_.top="top"):"top"===_.top&&n+a>E[3]&&n-(a-c)>=E[1]&&(n-=a-c,m.top="bottom",_.top="bottom")),"bottom"===m.top&&("top"===_.top&&n+a>E[3]?(n-=c,m.top="top",n-=a,_.top="bottom"):"bottom"===_.top&&n<E[1]&&n+(2*a-c)<=E[3]&&(n+=a-c,m.top="top",_.top="top")),"middle"===m.top&&(n+a>E[3]&&"top"===_.top?(n-=a,_.top="bottom"):n<E[1]&&"bottom"===_.top&&(n+=a,_.top="top"))),"target"!==f&&"both"!==f||(i<E[0]&&"left"===m.left&&(i+=d,m.left="right"),i+u>E[2]&&"right"===m.left&&(i-=d,m.left="left")),"together"===f&&(i<E[0]&&"left"===m.left?"right"===_.left?(i+=d,m.left="right",i+=u,_.left="left"):"left"===_.left&&(i+=d,m.left="right",i-=u,_.left="right"):i+u>E[2]&&"right"===m.left?"left"===_.left?(i-=d,m.left="left",i-=u,_.left="right"):"right"===_.left&&(i-=d,m.left="left",i+=u,_.left="left"):"center"===m.left&&(i+u>E[2]&&"left"===_.left?(i-=u,_.left="right"):i<E[0]&&"right"===_.left&&(i+=u,_.left="left"))),"element"!==h&&"both"!==h||(n<E[1]&&"bottom"===_.top&&(n+=a,_.top="top"),n+a>E[3]&&"top"===_.top&&(n-=a,_.top="bottom")),"element"!==f&&"both"!==f||(i<E[0]&&("right"===_.left?(i+=u,_.left="left"):"center"===_.left&&(i+=u/2,_.left="left")),i+u>E[2]&&("left"===_.left?(i-=u,_.left="right"):"center"===_.left&&(i-=u/2,_.left="right"))),"string"==typeof l?l=l.split(",").map(function(t){return t.trim()}):l===!0&&(l=["top","left","right","bottom"]),l=l||[];var T=[],C=[];n<E[1]&&(l.indexOf("top")>=0?(n=E[1],T.push("top")):C.push("top")),n+a>E[3]&&(l.indexOf("bottom")>=0?(n=E[3]-a,T.push("bottom")):C.push("bottom")),i<E[0]&&(l.indexOf("left")>=0?(i=E[0],T.push("left")):C.push("left")),i+u>E[2]&&(l.indexOf("right")>=0?(i=E[2]-u,T.push("right")):C.push("right")),T.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.pinnedClass?e.options.pinnedClass:e.getClass("pinned"),v.push(t),T.forEach(function(e){v.push(t+"-"+e)})}(),C.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.outOfBoundsClass?e.options.outOfBoundsClass:e.getClass("out-of-bounds"),v.push(t),C.forEach(function(e){v.push(t+"-"+e)})}(),(T.indexOf("left")>=0||T.indexOf("right")>=0)&&(_.left=m.left=!1),(T.indexOf("top")>=0||T.indexOf("bottom")>=0)&&(_.top=m.top=!1),m.top===o.top&&m.left===o.left&&_.top===e.attachment.top&&_.left===e.attachment.left||e.updateAttachClasses(_,m)}),O(function(){e.options.addTargetClasses!==!1&&p(e.target,v,g),p(e.element,v,g)}),{top:n,left:i}}});var N=T.Utils,r=N.getBounds,p=N.updateClasses,O=N.defer;T.modules.push({position:function(t){var e=this,n=t.top,i=t.left,o=this.cache("element-bounds",function(){return r(e.element)}),s=o.height,a=o.width,l=this.getTargetBounds(),u=n+s,f=i+a,h=[];n<=l.bottom&&u>=l.top&&["left","right"].forEach(function(t){var e=l[t];e!==i&&e!==f||h.push(t)}),i<=l.right&&f>=l.left&&["top","bottom"].forEach(function(t){var e=l[t];e!==n&&e!==u||h.push(t)});var c=[],d=[],g=["left","top","right","bottom"];return c.push(this.getClass("abutted")),g.forEach(function(t){c.push(e.getClass("abutted")+"-"+t)}),h.length&&d.push(this.getClass("abutted")),h.forEach(function(t){d.push(e.getClass("abutted")+"-"+t)}),O(function(){e.options.addTargetClasses!==!1&&p(e.target,d,c),p(e.element,d,c)}),!0}});var S=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(l){o=!0,r=l}finally{try{!i&&a["return"]&&a["return"]()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();return T.modules.push({position:function(t){var e=t.top,n=t.left;if(this.options.shift){var i=this.options.shift;"function"==typeof this.options.shift&&(i=this.options.shift.call(this,{top:e,left:n}));var o=void 0,r=void 0;if("string"==typeof i){i=i.split(" "),i[1]=i[1]||i[0];var s=i,a=S(s,2);o=a[0],r=a[1],o=parseFloat(o,10),r=parseFloat(r,10)}else o=i.top,r=i.left;return e+=o,n+=r,{top:e,left:n}}}}),F})},function(t,e,n){var i,o,r;(function(s,a){!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),l=i(n),u=function(t){if(void 0===s)throw new Error("Bootstrap tooltips require Tether (http://github.hubspot.com/tether/)");var e="tooltip",n="4.0.0-alpha",i="bs.tooltip",u="."+i,f=t.fn[e],h=150,c="bs-tether",d={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:"0 0",constraints:[]},p={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"string",constraints:"array"},g={TOP:"bottom center",RIGHT:"middle left",BOTTOM:"top center",LEFT:"middle right"},v={IN:"in",OUT:"out"},m={HIDE:"hide"+u,HIDDEN:"hidden"+u,SHOW:"show"+u,SHOWN:"shown"+u,INSERTED:"inserted"+u,CLICK:"click"+u,FOCUSIN:"focusin"+u,FOCUSOUT:"focusout"+u,MOUSEENTER:"mouseenter"+u,MOUSELEAVE:"mouseleave"+u},_={FADE:"fade",IN:"in"},y={TOOLTIP:".tooltip",TOOLTIP_INNER:".tooltip-inner"},E={element:!1,enabled:!1},T={HOVER:"hover",FOCUS:"focus",CLICK:"click",MANUAL:"manual"},C=function(){function s(t,e){o(this,s),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._tether=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}return r(s,[{key:"enable",value:function(){this._isEnabled=!0}},{key:"disable",value:function(){this._isEnabled=!1}},{key:"toggleEnabled",value:function(){this._isEnabled=!this._isEnabled}},{key:"toggle",value:function(e){if(e){var n=this.constructor.DATA_KEY,i=t(e.currentTarget).data(n);i||(i=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(n,i)),i._activeTrigger.click=!i._activeTrigger.click,i._isWithActiveTrigger()?i._enter(null,i):i._leave(null,i)}else{if(t(this.getTipElement()).hasClass(_.IN))return void this._leave(null,this);this._enter(null,this)}}},{key:"dispose",value:function(){clearTimeout(this._timeout),this.cleanupTether(),t.removeData(this.element,this.constructor.DATA_KEY),t(this.element).off(this.constructor.EVENT_KEY),this.tip&&t(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._tether=null,this.element=null,this.config=null,this.tip=null}},{key:"show",value:function(){var e=this,n=t.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){t(this.element).trigger(n);var i=t.contains(this.element.ownerDocument.documentElement,this.element);if(n.isDefaultPrevented()||!i)return;var o=this.getTipElement(),r=l["default"].getUID(this.constructor.NAME);o.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&t(o).addClass(_.FADE);var u="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,f=this._getAttachment(u);t(o).data(this.constructor.DATA_KEY,this).appendTo(document.body),t(this.element).trigger(this.constructor.Event.INSERTED),this._tether=new a({attachment:f,element:o,target:this.element,classes:E,classPrefix:c,offset:this.config.offset,constraints:this.config.constraints,addTargetClasses:!1}),l["default"].reflow(o),this._tether.position(),t(o).addClass(_.IN);var h=function(){var n=e._hoverState;e._hoverState=null,t(e.element).trigger(e.constructor.Event.SHOWN),n===v.OUT&&e._leave(null,e)};if(l["default"].supportsTransitionEnd()&&t(this.tip).hasClass(_.FADE))return void t(this.tip).one(l["default"].TRANSITION_END,h).emulateTransitionEnd(s._TRANSITION_DURATION);h()}}},{key:"hide",value:function(e){var n=this,i=this.getTipElement(),o=t.Event(this.constructor.Event.HIDE),r=function(){n._hoverState!==v.IN&&i.parentNode&&i.parentNode.removeChild(i),n.element.removeAttribute("aria-describedby"),t(n.element).trigger(n.constructor.Event.HIDDEN),n.cleanupTether(),e&&e()};t(this.element).trigger(o),o.isDefaultPrevented()||(t(i).removeClass(_.IN),l["default"].supportsTransitionEnd()&&t(this.tip).hasClass(_.FADE)?t(i).one(l["default"].TRANSITION_END,r).emulateTransitionEnd(h):r(),this._hoverState="")}},{key:"isWithContent",value:function(){return Boolean(this.getTitle())}},{key:"getTipElement",value:function(){return this.tip=this.tip||t(this.config.template)[0]}},{key:"setContent",value:function(){var e=t(this.getTipElement());this.setElementContent(e.find(y.TOOLTIP_INNER),this.getTitle()),e.removeClass(_.FADE).removeClass(_.IN),this.cleanupTether()}},{key:"setElementContent",value:function(e,n){var i=this.config.html;"object"==typeof n&&(n.nodeType||n.jquery)?i?t(n).parent().is(e)||e.empty().append(n):e.text(t(n).text()):e[i?"html":"text"](n)}},{key:"getTitle",value:function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t}},{key:"cleanupTether",value:function(){this._tether&&this._tether.destroy()}},{key:"_getAttachment",value:function(t){return g[t.toUpperCase()]}},{key:"_setListeners",value:function(){var e=this,n=this.config.trigger.split(" ");n.forEach(function(n){if("click"===n)t(e.element).on(e.constructor.Event.CLICK,e.config.selector,t.proxy(e.toggle,e));else if(n!==T.MANUAL){var i=n===T.HOVER?e.constructor.Event.MOUSEENTER:e.constructor.Event.FOCUSIN,o=n===T.HOVER?e.constructor.Event.MOUSELEAVE:e.constructor.Event.FOCUSOUT;t(e.element).on(i,e.config.selector,t.proxy(e._enter,e)).on(o,e.config.selector,t.proxy(e._leave,e))}}),this.config.selector?this.config=t.extend({},this.config,{trigger:"manual",selector:""}):this._fixTitle()}},{key:"_fixTitle",value:function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))}},{key:"_enter",value:function(e,n){var i=this.constructor.DATA_KEY;return n=n||t(e.currentTarget).data(i),n||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusin"===e.type?T.FOCUS:T.HOVER]=!0),t(n.getTipElement()).hasClass(_.IN)||n._hoverState===v.IN?void(n._hoverState=v.IN):(clearTimeout(n._timeout),n._hoverState=v.IN,n.config.delay&&n.config.delay.show?void(n._timeout=setTimeout(function(){n._hoverState===v.IN&&n.show()},n.config.delay.show)):void n.show())}},{key:"_leave",value:function(e,n){var i=this.constructor.DATA_KEY;return n=n||t(e.currentTarget).data(i),n||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusout"===e.type?T.FOCUS:T.HOVER]=!1),n._isWithActiveTrigger()?void 0:(clearTimeout(n._timeout),n._hoverState=v.OUT,n.config.delay&&n.config.delay.hide?void(n._timeout=setTimeout(function(){n._hoverState===v.OUT&&n.hide()},n.config.delay.hide)):void n.hide())}},{key:"_isWithActiveTrigger",value:function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}},{key:"_getConfig",value:function(n){return n=t.extend({},this.constructor.Default,t(this.element).data(),n),n.delay&&"number"==typeof n.delay&&(n.delay={show:n.delay,hide:n.delay}),l["default"].typeCheckConfig(e,n,this.constructor.DefaultType),n}},{key:"_getDelegateConfig",value:function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t}}],[{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this).data(i),o="object"==typeof e?e:null;if((n||!/destroy|hide/.test(e))&&(n||(n=new s(this,o),t(this).data(i,n)),"string"==typeof e)){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return d}},{key:"NAME",get:function(){return e}},{key:"DATA_KEY",get:function(){return i}},{key:"Event",get:function(){return m}},{key:"EVENT_KEY",get:function(){return u}},{key:"DefaultType",get:function(){return p}}]),s}();return t.fn[e]=C._jQueryInterface,t.fn[e].Constructor=C,
-t.fn[e].noConflict=function(){return t.fn[e]=f,C._jQueryInterface},C}(jQuery);e.exports=u})}).call(e,n(2),n(2))},function(t,e,n){n(1),n(5),n(6),n(7),n(8),n(9),n(10),n(12),n(13),n(3),n(11)},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="alert",n="4.0.0-alpha",i="bs.alert",a="."+i,l=".data-api",u=t.fn[e],f=150,h={DISMISS:'[data-dismiss="alert"]'},c={CLOSE:"close"+a,CLOSED:"closed"+a,CLICK_DATA_API:"click"+a+l},d={ALERT:"alert",FADE:"fade",IN:"in"},p=function(){function e(t){o(this,e),this._element=t}return r(e,[{key:"close",value:function(t){t=t||this._element;var e=this._getRootElement(t),n=this._triggerCloseEvent(e);n.isDefaultPrevented()||this._removeElement(e)}},{key:"dispose",value:function(){t.removeData(this._element,i),this._element=null}},{key:"_getRootElement",value:function(e){var n=s["default"].getSelectorFromElement(e),i=!1;return n&&(i=t(n)[0]),i||(i=t(e).closest("."+d.ALERT)[0]),i}},{key:"_triggerCloseEvent",value:function(e){var n=t.Event(c.CLOSE);return t(e).trigger(n),n}},{key:"_removeElement",value:function(e){return t(e).removeClass(d.IN),s["default"].supportsTransitionEnd()&&t(e).hasClass(d.FADE)?void t(e).one(s["default"].TRANSITION_END,t.proxy(this._destroyElement,this,e)).emulateTransitionEnd(f):void this._destroyElement(e)}},{key:"_destroyElement",value:function(e){t(e).detach().trigger(c.CLOSED).remove()}}],[{key:"_jQueryInterface",value:function(n){return this.each(function(){var o=t(this),r=o.data(i);r||(r=new e(this),o.data(i,r)),"close"===n&&r[n](this)})}},{key:"_handleDismiss",value:function(t){return function(e){e&&e.preventDefault(),t.close(this)}}},{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(c.CLICK_DATA_API,h.DISMISS,p._handleDismiss(new p)),t.fn[e]=p._jQueryInterface,t.fn[e].Constructor=p,t.fn[e].noConflict=function(){return t.fn[e]=u,p._jQueryInterface},p}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(n,s){o=[e,t],i=s,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),o=function(t){var e="button",o="4.0.0-alpha",r="bs.button",s="."+r,a=".data-api",l=t.fn[e],u={ACTIVE:"active",BUTTON:"btn",FOCUS:"focus"},f={DATA_TOGGLE_CARROT:'[data-toggle^="button"]',DATA_TOGGLE:'[data-toggle="buttons"]',INPUT:"input",ACTIVE:".active",BUTTON:".btn"},h={CLICK_DATA_API:"click"+s+a,FOCUS_BLUR_DATA_API:"focus"+s+a+" "+("blur"+s+a)},c=function(){function e(t){n(this,e),this._element=t}return i(e,[{key:"toggle",value:function(){var e=!0,n=t(this._element).closest(f.DATA_TOGGLE)[0];if(n){var i=t(this._element).find(f.INPUT)[0];if(i){if("radio"===i.type)if(i.checked&&t(this._element).hasClass(u.ACTIVE))e=!1;else{var o=t(n).find(f.ACTIVE)[0];o&&t(o).removeClass(u.ACTIVE)}e&&(i.checked=!t(this._element).hasClass(u.ACTIVE),t(this._element).trigger("change"))}}else this._element.setAttribute("aria-pressed",!t(this._element).hasClass(u.ACTIVE));e&&t(this._element).toggleClass(u.ACTIVE)}},{key:"dispose",value:function(){t.removeData(this._element,r),this._element=null}}],[{key:"_jQueryInterface",value:function(n){return this.each(function(){var i=t(this).data(r);i||(i=new e(this),t(this).data(r,i)),"toggle"===n&&i[n]()})}},{key:"VERSION",get:function(){return o}}]),e}();return t(document).on(h.CLICK_DATA_API,f.DATA_TOGGLE_CARROT,function(e){e.preventDefault();var n=e.target;t(n).hasClass(u.BUTTON)||(n=t(n).closest(f.BUTTON)),c._jQueryInterface.call(t(n),"toggle")}).on(h.FOCUS_BLUR_DATA_API,f.DATA_TOGGLE_CARROT,function(e){var n=t(e.target).closest(f.BUTTON)[0];t(n).toggleClass(u.FOCUS,/^focus(in)?$/.test(e.type))}),t.fn[e]=c._jQueryInterface,t.fn[e].Constructor=c,t.fn[e].noConflict=function(){return t.fn[e]=l,c._jQueryInterface},c}(jQuery);e.exports=o})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="carousel",n="4.0.0-alpha",i="bs.carousel",a="."+i,l=".data-api",u=t.fn[e],f=600,h={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0},c={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean"},d={NEXT:"next",PREVIOUS:"prev"},p={SLIDE:"slide"+a,SLID:"slid"+a,KEYDOWN:"keydown"+a,MOUSEENTER:"mouseenter"+a,MOUSELEAVE:"mouseleave"+a,LOAD_DATA_API:"load"+a+l,CLICK_DATA_API:"click"+a+l},g={CAROUSEL:"carousel",ACTIVE:"active",SLIDE:"slide",RIGHT:"right",LEFT:"left",ITEM:"carousel-item"},v={ACTIVE:".active",ACTIVE_ITEM:".active.carousel-item",ITEM:".carousel-item",NEXT_PREV:".next, .prev",INDICATORS:".carousel-indicators",DATA_SLIDE:"[data-slide], [data-slide-to]",DATA_RIDE:'[data-ride="carousel"]'},m=function(){function l(e,n){o(this,l),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this._config=this._getConfig(n),this._element=t(e)[0],this._indicatorsElement=t(this._element).find(v.INDICATORS)[0],this._addEventListeners()}return r(l,[{key:"next",value:function(){this._isSliding||this._slide(d.NEXT)}},{key:"nextWhenVisible",value:function(){document.hidden||this.next()}},{key:"prev",value:function(){this._isSliding||this._slide(d.PREVIOUS)}},{key:"pause",value:function(e){e||(this._isPaused=!0),t(this._element).find(v.NEXT_PREV)[0]&&s["default"].supportsTransitionEnd()&&(s["default"].triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}},{key:"cycle",value:function(e){e||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval(t.proxy(document.visibilityState?this.nextWhenVisible:this.next,this),this._config.interval))}},{key:"to",value:function(e){var n=this;this._activeElement=t(this._element).find(v.ACTIVE_ITEM)[0];var i=this._getItemIndex(this._activeElement);if(!(e>this._items.length-1||0>e)){if(this._isSliding)return void t(this._element).one(p.SLID,function(){return n.to(e)});if(i===e)return this.pause(),void this.cycle();var o=e>i?d.NEXT:d.PREVIOUS;this._slide(o,this._items[e])}}},{key:"dispose",value:function(){t(this._element).off(a),t.removeData(this._element,i),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null}},{key:"_getConfig",value:function(n){return n=t.extend({},h,n),s["default"].typeCheckConfig(e,n,c),n}},{key:"_addEventListeners",value:function(){this._config.keyboard&&t(this._element).on(p.KEYDOWN,t.proxy(this._keydown,this)),"hover"!==this._config.pause||"ontouchstart"in document.documentElement||t(this._element).on(p.MOUSEENTER,t.proxy(this.pause,this)).on(p.MOUSELEAVE,t.proxy(this.cycle,this))}},{key:"_keydown",value:function(t){if(t.preventDefault(),!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:this.prev();break;case 39:this.next();break;default:return}}},{key:"_getItemIndex",value:function(e){return this._items=t.makeArray(t(e).parent().find(v.ITEM)),this._items.indexOf(e)}},{key:"_getItemByDirection",value:function(t,e){var n=t===d.NEXT,i=t===d.PREVIOUS,o=this._getItemIndex(e),r=this._items.length-1,s=i&&0===o||n&&o===r;if(s&&!this._config.wrap)return e;var a=t===d.PREVIOUS?-1:1,l=(o+a)%this._items.length;return-1===l?this._items[this._items.length-1]:this._items[l]}},{key:"_triggerSlideEvent",value:function(e,n){var i=t.Event(p.SLIDE,{relatedTarget:e,direction:n});return t(this._element).trigger(i),i}},{key:"_setActiveIndicatorElement",value:function(e){if(this._indicatorsElement){t(this._indicatorsElement).find(v.ACTIVE).removeClass(g.ACTIVE);var n=this._indicatorsElement.children[this._getItemIndex(e)];n&&t(n).addClass(g.ACTIVE)}}},{key:"_slide",value:function(e,n){var i=this,o=t(this._element).find(v.ACTIVE_ITEM)[0],r=n||o&&this._getItemByDirection(e,o),a=Boolean(this._interval),l=e===d.NEXT?g.LEFT:g.RIGHT;if(r&&t(r).hasClass(g.ACTIVE))return void(this._isSliding=!1);var u=this._triggerSlideEvent(r,l);if(!u.isDefaultPrevented()&&o&&r){this._isSliding=!0,a&&this.pause(),this._setActiveIndicatorElement(r);var h=t.Event(p.SLID,{relatedTarget:r,direction:l});s["default"].supportsTransitionEnd()&&t(this._element).hasClass(g.SLIDE)?(t(r).addClass(e),s["default"].reflow(r),t(o).addClass(l),t(r).addClass(l),t(o).one(s["default"].TRANSITION_END,function(){t(r).removeClass(l).removeClass(e),t(r).addClass(g.ACTIVE),t(o).removeClass(g.ACTIVE).removeClass(e).removeClass(l),i._isSliding=!1,setTimeout(function(){return t(i._element).trigger(h)},0)}).emulateTransitionEnd(f)):(t(o).removeClass(g.ACTIVE),t(r).addClass(g.ACTIVE),this._isSliding=!1,t(this._element).trigger(h)),a&&this.cycle()}}}],[{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this).data(i),o=t.extend({},h,t(this).data());"object"==typeof e&&t.extend(o,e);var r="string"==typeof e?e:o.slide;if(n||(n=new l(this,o),t(this).data(i,n)),"number"==typeof e)n.to(e);else if("string"==typeof r){if(void 0===n[r])throw new Error('No method named "'+r+'"');n[r]()}else o.interval&&(n.pause(),n.cycle())})}},{key:"_dataApiClickHandler",value:function(e){var n=s["default"].getSelectorFromElement(this);if(n){var o=t(n)[0];if(o&&t(o).hasClass(g.CAROUSEL)){var r=t.extend({},t(o).data(),t(this).data()),a=this.getAttribute("data-slide-to");a&&(r.interval=!1),l._jQueryInterface.call(t(o),r),a&&t(o).data(i).to(a),e.preventDefault()}}}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return h}}]),l}();return t(document).on(p.CLICK_DATA_API,v.DATA_SLIDE,m._dataApiClickHandler),t(window).on(p.LOAD_DATA_API,function(){t(v.DATA_RIDE).each(function(){var e=t(this);m._jQueryInterface.call(e,e.data())})}),t.fn[e]=m._jQueryInterface,t.fn[e].Constructor=m,t.fn[e].noConflict=function(){return t.fn[e]=u,m._jQueryInterface},m}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="collapse",n="4.0.0-alpha",i="bs.collapse",a="."+i,l=".data-api",u=t.fn[e],f=600,h={toggle:!0,parent:""},c={toggle:"boolean",parent:"string"},d={SHOW:"show"+a,SHOWN:"shown"+a,HIDE:"hide"+a,HIDDEN:"hidden"+a,CLICK_DATA_API:"click"+a+l},p={IN:"in",COLLAPSE:"collapse",COLLAPSING:"collapsing",COLLAPSED:"collapsed"},g={WIDTH:"width",HEIGHT:"height"},v={ACTIVES:".panel > .in, .panel > .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},m=function(){function a(e,n){o(this,a),this._isTransitioning=!1,this._element=e,this._config=this._getConfig(n),this._triggerArray=t.makeArray(t('[data-toggle="collapse"][href="#'+e.id+'"],'+('[data-toggle="collapse"][data-target="#'+e.id+'"]'))),this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}return r(a,[{key:"toggle",value:function(){t(this._element).hasClass(p.IN)?this.hide():this.show()}},{key:"show",value:function(){var e=this;if(!this._isTransitioning&&!t(this._element).hasClass(p.IN)){var n=void 0,o=void 0;if(this._parent&&(n=t.makeArray(t(v.ACTIVES)),n.length||(n=null)),!(n&&(o=t(n).data(i),o&&o._isTransitioning))){var r=t.Event(d.SHOW);if(t(this._element).trigger(r),!r.isDefaultPrevented()){n&&(a._jQueryInterface.call(t(n),"hide"),o||t(n).data(i,null));var l=this._getDimension();t(this._element).removeClass(p.COLLAPSE).addClass(p.COLLAPSING),this._element.style[l]=0,this._element.setAttribute("aria-expanded",!0),this._triggerArray.length&&t(this._triggerArray).removeClass(p.COLLAPSED).attr("aria-expanded",!0),this.setTransitioning(!0);var u=function(){t(e._element).removeClass(p.COLLAPSING).addClass(p.COLLAPSE).addClass(p.IN),e._element.style[l]="",e.setTransitioning(!1),t(e._element).trigger(d.SHOWN)};if(!s["default"].supportsTransitionEnd())return void u();var h=l[0].toUpperCase()+l.slice(1),c="scroll"+h;t(this._element).one(s["default"].TRANSITION_END,u).emulateTransitionEnd(f),this._element.style[l]=this._element[c]+"px"}}}}},{key:"hide",value:function(){var e=this;if(!this._isTransitioning&&t(this._element).hasClass(p.IN)){var n=t.Event(d.HIDE);if(t(this._element).trigger(n),!n.isDefaultPrevented()){var i=this._getDimension(),o=i===g.WIDTH?"offsetWidth":"offsetHeight";this._element.style[i]=this._element[o]+"px",s["default"].reflow(this._element),t(this._element).addClass(p.COLLAPSING).removeClass(p.COLLAPSE).removeClass(p.IN),this._element.setAttribute("aria-expanded",!1),this._triggerArray.length&&t(this._triggerArray).addClass(p.COLLAPSED).attr("aria-expanded",!1),this.setTransitioning(!0);var r=function(){e.setTransitioning(!1),t(e._element).removeClass(p.COLLAPSING).addClass(p.COLLAPSE).trigger(d.HIDDEN)};return this._element.style[i]=0,s["default"].supportsTransitionEnd()?void t(this._element).one(s["default"].TRANSITION_END,r).emulateTransitionEnd(f):void r()}}}},{key:"setTransitioning",value:function(t){this._isTransitioning=t}},{key:"dispose",value:function(){t.removeData(this._element,i),this._config=null,this._parent=null,this._element=null,this._triggerArray=null,this._isTransitioning=null}},{key:"_getConfig",value:function(n){return n=t.extend({},h,n),n.toggle=Boolean(n.toggle),s["default"].typeCheckConfig(e,n,c),n}},{key:"_getDimension",value:function(){var e=t(this._element).hasClass(g.WIDTH);return e?g.WIDTH:g.HEIGHT}},{key:"_getParent",value:function(){var e=this,n=t(this._config.parent)[0],i='[data-toggle="collapse"][data-parent="'+this._config.parent+'"]';return t(n).find(i).each(function(t,n){e._addAriaAndCollapsedClass(a._getTargetFromElement(n),[n])}),n}},{key:"_addAriaAndCollapsedClass",value:function(e,n){if(e){var i=t(e).hasClass(p.IN);e.setAttribute("aria-expanded",i),n.length&&t(n).toggleClass(p.COLLAPSED,!i).attr("aria-expanded",i)}}}],[{key:"_getTargetFromElement",value:function(e){var n=s["default"].getSelectorFromElement(e);return n?t(n)[0]:null}},{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this),o=n.data(i),r=t.extend({},h,n.data(),"object"==typeof e&&e);if(!o&&r.toggle&&/show|hide/.test(e)&&(r.toggle=!1),o||(o=new a(this,r),n.data(i,o)),"string"==typeof e){if(void 0===o[e])throw new Error('No method named "'+e+'"');o[e]()}})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return h}}]),a}();return t(document).on(d.CLICK_DATA_API,v.DATA_TOGGLE,function(e){e.preventDefault();var n=m._getTargetFromElement(this),o=t(n).data(i),r=o?"toggle":t(this).data();m._jQueryInterface.call(t(n),r)}),t.fn[e]=m._jQueryInterface,t.fn[e].Constructor=m,t.fn[e].noConflict=function(){return t.fn[e]=u,m._jQueryInterface},m}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="dropdown",n="4.0.0-alpha",i="bs.dropdown",a="."+i,l=".data-api",u=t.fn[e],f={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,CLICK:"click"+a,CLICK_DATA_API:"click"+a+l,KEYDOWN_DATA_API:"keydown"+a+l},h={BACKDROP:"dropdown-backdrop",DISABLED:"disabled",OPEN:"open"},c={BACKDROP:".dropdown-backdrop",DATA_TOGGLE:'[data-toggle="dropdown"]',FORM_CHILD:".dropdown form",ROLE_MENU:'[role="menu"]',ROLE_LISTBOX:'[role="listbox"]',NAVBAR_NAV:".navbar-nav",VISIBLE_ITEMS:'[role="menu"] li:not(.disabled) a, [role="listbox"] li:not(.disabled) a'},d=function(){function e(t){o(this,e),this._element=t,this._addEventListeners()}return r(e,[{key:"toggle",value:function(){if(this.disabled||t(this).hasClass(h.DISABLED))return!1;var n=e._getParentFromElement(this),i=t(n).hasClass(h.OPEN);if(e._clearMenus(),i)return!1;if("ontouchstart"in document.documentElement&&!t(n).closest(c.NAVBAR_NAV).length){var o=document.createElement("div");o.className=h.BACKDROP,t(o).insertBefore(this),t(o).on("click",e._clearMenus)}var r={relatedTarget:this},s=t.Event(f.SHOW,r);return t(n).trigger(s),s.isDefaultPrevented()?!1:(this.focus(),this.setAttribute("aria-expanded","true"),t(n).toggleClass(h.OPEN),t(n).trigger(t.Event(f.SHOWN,r)),!1)}},{key:"dispose",value:function(){t.removeData(this._element,i),t(this._element).off(a),this._element=null}},{key:"_addEventListeners",value:function(){t(this._element).on(f.CLICK,this.toggle)}}],[{key:"_jQueryInterface",value:function(n){return this.each(function(){var o=t(this).data(i);if(o||t(this).data(i,o=new e(this)),"string"==typeof n){if(void 0===o[n])throw new Error('No method named "'+n+'"');o[n].call(this)}})}},{key:"_clearMenus",value:function(n){if(!n||3!==n.which){var i=t(c.BACKDROP)[0];i&&i.parentNode.removeChild(i);for(var o=t.makeArray(t(c.DATA_TOGGLE)),r=0;r<o.length;r++){var s=e._getParentFromElement(o[r]),a={relatedTarget:o[r]};if(t(s).hasClass(h.OPEN)&&!(n&&"click"===n.type&&/input|textarea/i.test(n.target.tagName)&&t.contains(s,n.target))){var l=t.Event(f.HIDE,a);t(s).trigger(l),l.isDefaultPrevented()||(o[r].setAttribute("aria-expanded","false"),t(s).removeClass(h.OPEN).trigger(t.Event(f.HIDDEN,a)))}}}}},{key:"_getParentFromElement",value:function(e){var n=void 0,i=s["default"].getSelectorFromElement(e);return i&&(n=t(i)[0]),n||e.parentNode}},{key:"_dataApiKeydownHandler",value:function(n){if(/(38|40|27|32)/.test(n.which)&&!/input|textarea/i.test(n.target.tagName)&&(n.preventDefault(),n.stopPropagation(),!this.disabled&&!t(this).hasClass(h.DISABLED))){var i=e._getParentFromElement(this),o=t(i).hasClass(h.OPEN);if(!o&&27!==n.which||o&&27===n.which){if(27===n.which){var r=t(i).find(c.DATA_TOGGLE)[0];t(r).trigger("focus")}return void t(this).trigger("click")}var s=t.makeArray(t(c.VISIBLE_ITEMS));if(s=s.filter(function(t){return t.offsetWidth||t.offsetHeight}),s.length){var a=s.indexOf(n.target);38===n.which&&a>0&&a--,40===n.which&&a<s.length-1&&a++,~a||(a=0),s[a].focus()}}}},{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(f.KEYDOWN_DATA_API,c.DATA_TOGGLE,d._dataApiKeydownHandler).on(f.KEYDOWN_DATA_API,c.ROLE_MENU,d._dataApiKeydownHandler).on(f.KEYDOWN_DATA_API,c.ROLE_LISTBOX,d._dataApiKeydownHandler).on(f.CLICK_DATA_API,d._clearMenus).on(f.CLICK_DATA_API,c.DATA_TOGGLE,d.prototype.toggle).on(f.CLICK_DATA_API,c.FORM_CHILD,function(t){t.stopPropagation()}),t.fn[e]=d._jQueryInterface,t.fn[e].Constructor=d,t.fn[e].noConflict=function(){return t.fn[e]=u,d._jQueryInterface},d}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="modal",n="4.0.0-alpha",i="bs.modal",a="."+i,l=".data-api",u=t.fn[e],f=300,h=150,c={backdrop:!0,keyboard:!0,focus:!0,show:!0},d={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean",show:"boolean"},p={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,FOCUSIN:"focusin"+a,RESIZE:"resize"+a,CLICK_DISMISS:"click.dismiss"+a,KEYDOWN_DISMISS:"keydown.dismiss"+a,MOUSEUP_DISMISS:"mouseup.dismiss"+a,MOUSEDOWN_DISMISS:"mousedown.dismiss"+a,CLICK_DATA_API:"click"+a+l},g={SCROLLBAR_MEASURER:"modal-scrollbar-measure",BACKDROP:"modal-backdrop",OPEN:"modal-open",FADE:"fade",IN:"in"},v={DIALOG:".modal-dialog",DATA_TOGGLE:'[data-toggle="modal"]',DATA_DISMISS:'[data-dismiss="modal"]',FIXED_CONTENT:".navbar-fixed-top, .navbar-fixed-bottom, .is-fixed"},m=function(){function l(e,n){o(this,l),this._config=this._getConfig(n),this._element=e,this._dialog=t(e).find(v.DIALOG)[0],this._backdrop=null,this._isShown=!1,this._isBodyOverflowing=!1,this._ignoreBackdropClick=!1,this._originalBodyPadding=0,this._scrollbarWidth=0}return r(l,[{key:"toggle",value:function(t){return this._isShown?this.hide():this.show(t)}},{key:"show",value:function(e){var n=this,i=t.Event(p.SHOW,{relatedTarget:e});t(this._element).trigger(i),this._isShown||i.isDefaultPrevented()||(this._isShown=!0,this._checkScrollbar(),this._setScrollbar(),t(document.body).addClass(g.OPEN),this._setEscapeEvent(),this._setResizeEvent(),t(this._element).on(p.CLICK_DISMISS,v.DATA_DISMISS,t.proxy(this.hide,this)),t(this._dialog).on(p.MOUSEDOWN_DISMISS,function(){t(n._element).one(p.MOUSEUP_DISMISS,function(e){t(e.target).is(n._element)&&(n._ignoreBackdropClick=!0)})}),this._showBackdrop(t.proxy(this._showElement,this,e)))}},{key:"hide",value:function(e){e&&e.preventDefault();var n=t.Event(p.HIDE);t(this._element).trigger(n),this._isShown&&!n.isDefaultPrevented()&&(this._isShown=!1,this._setEscapeEvent(),this._setResizeEvent(),t(document).off(p.FOCUSIN),t(this._element).removeClass(g.IN),t(this._element).off(p.CLICK_DISMISS),t(this._dialog).off(p.MOUSEDOWN_DISMISS),s["default"].supportsTransitionEnd()&&t(this._element).hasClass(g.FADE)?t(this._element).one(s["default"].TRANSITION_END,t.proxy(this._hideModal,this)).emulateTransitionEnd(f):this._hideModal())}},{key:"dispose",value:function(){t.removeData(this._element,i),t(window).off(a),t(document).off(a),t(this._element).off(a),t(this._backdrop).off(a),this._config=null,this._element=null,this._dialog=null,this._backdrop=null,this._isShown=null,this._isBodyOverflowing=null,this._ignoreBackdropClick=null,this._originalBodyPadding=null,this._scrollbarWidth=null}},{key:"_getConfig",value:function(n){return n=t.extend({},c,n),s["default"].typeCheckConfig(e,n,d),n}},{key:"_showElement",value:function(e){var n=this,i=s["default"].supportsTransitionEnd()&&t(this._element).hasClass(g.FADE);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.scrollTop=0,i&&s["default"].reflow(this._element),t(this._element).addClass(g.IN),this._config.focus&&this._enforceFocus();var o=t.Event(p.SHOWN,{relatedTarget:e}),r=function(){n._config.focus&&n._element.focus(),t(n._element).trigger(o)};i?t(this._dialog).one(s["default"].TRANSITION_END,r).emulateTransitionEnd(f):r()}},{key:"_enforceFocus",value:function(){var e=this;t(document).off(p.FOCUSIN).on(p.FOCUSIN,function(n){e._element===n.target||t(e._element).has(n.target).length||e._element.focus()})}},{key:"_setEscapeEvent",value:function(){var e=this;this._isShown&&this._config.keyboard?t(this._element).on(p.KEYDOWN_DISMISS,function(t){27===t.which&&e.hide()}):this._isShown||t(this._element).off(p.KEYDOWN_DISMISS)}},{key:"_setResizeEvent",value:function(){this._isShown?t(window).on(p.RESIZE,t.proxy(this._handleUpdate,this)):t(window).off(p.RESIZE)}},{key:"_hideModal",value:function(){var e=this;this._element.style.display="none",this._showBackdrop(function(){t(document.body).removeClass(g.OPEN),e._resetAdjustments(),e._resetScrollbar(),t(e._element).trigger(p.HIDDEN)})}},{key:"_removeBackdrop",value:function(){this._backdrop&&(t(this._backdrop).remove(),this._backdrop=null)}},{key:"_showBackdrop",value:function(e){var n=this,i=t(this._element).hasClass(g.FADE)?g.FADE:"";if(this._isShown&&this._config.backdrop){var o=s["default"].supportsTransitionEnd()&&i;if(this._backdrop=document.createElement("div"),this._backdrop.className=g.BACKDROP,i&&t(this._backdrop).addClass(i),t(this._backdrop).appendTo(document.body),t(this._element).on(p.CLICK_DISMISS,function(t){return n._ignoreBackdropClick?void(n._ignoreBackdropClick=!1):void(t.target===t.currentTarget&&("static"===n._config.backdrop?n._element.focus():n.hide()))}),o&&s["default"].reflow(this._backdrop),t(this._backdrop).addClass(g.IN),!e)return;if(!o)return void e();t(this._backdrop).one(s["default"].TRANSITION_END,e).emulateTransitionEnd(h)}else if(!this._isShown&&this._backdrop){t(this._backdrop).removeClass(g.IN);var r=function(){n._removeBackdrop(),e&&e()};s["default"].supportsTransitionEnd()&&t(this._element).hasClass(g.FADE)?t(this._backdrop).one(s["default"].TRANSITION_END,r).emulateTransitionEnd(h):r()}else e&&e()}},{key:"_handleUpdate",value:function(){this._adjustDialog()}},{key:"_adjustDialog",value:function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px~")}},{key:"_resetAdjustments",value:function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}},{key:"_checkScrollbar",value:function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this._isBodyOverflowing=document.body.clientWidth<t,this._scrollbarWidth=this._getScrollbarWidth()}},{key:"_setScrollbar",value:function(){var e=parseInt(t(v.FIXED_CONTENT).css("padding-right")||0,10);this._originalBodyPadding=document.body.style.paddingRight||"",this._isBodyOverflowing&&(document.body.style.paddingRight=e+this._scrollbarWidth+"px")}},{key:"_resetScrollbar",value:function(){document.body.style.paddingRight=this._originalBodyPadding}},{key:"_getScrollbarWidth",value:function(){var t=document.createElement("div");t.className=g.SCROLLBAR_MEASURER,document.body.appendChild(t);var e=t.offsetWidth-t.clientWidth;return document.body.removeChild(t),e}}],[{key:"_jQueryInterface",value:function(e,n){return this.each(function(){var o=t(this).data(i),r=t.extend({},l.Default,t(this).data(),"object"==typeof e&&e);if(o||(o=new l(this,r),t(this).data(i,o)),"string"==typeof e){if(void 0===o[e])throw new Error('No method named "'+e+'"');o[e](n)}else r.show&&o.show(n)})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return c}}]),l}();return t(document).on(p.CLICK_DATA_API,v.DATA_TOGGLE,function(e){var n=this,o=void 0,r=s["default"].getSelectorFromElement(this);r&&(o=t(r)[0]);var a=t(o).data(i)?"toggle":t.extend({},t(o).data(),t(this).data());"A"===this.tagName&&e.preventDefault();var l=t(o).one(p.SHOW,function(e){e.isDefaultPrevented()||l.one(p.HIDDEN,function(){t(n).is(":visible")&&n.focus()})});m._jQueryInterface.call(t(o),a,this)}),t.fn[e]=m._jQueryInterface,t.fn[e].Constructor=m,t.fn[e].noConflict=function(){return t.fn[e]=u,m._jQueryInterface},m}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(3)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var s=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),a=function(t,e,n){for(var i=!0;i;){var o=t,r=e,s=n;i=!1,null===o&&(o=Function.prototype);var a=Object.getOwnPropertyDescriptor(o,r);if(void 0!==a){if("value"in a)return a.value;var l=a.get;if(void 0===l)return;return l.call(s)}var u=Object.getPrototypeOf(o);if(null===u)return;t=u,e=r,n=s,i=!0,a=u=void 0}},l=i(n),u=function(t){var e="popover",n="4.0.0-alpha",i="bs.popover",u="."+i,f=t.fn[e],h=t.extend({},l["default"].Default,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c=t.extend({},l["default"].DefaultType,{content:"(string|element|function)"}),d={FADE:"fade",IN:"in"},p={TITLE:".popover-title",CONTENT:".popover-content",ARROW:".popover-arrow"},g={HIDE:"hide"+u,HIDDEN:"hidden"+u,SHOW:"show"+u,SHOWN:"shown"+u,INSERTED:"inserted"+u,CLICK:"click"+u,FOCUSIN:"focusin"+u,FOCUSOUT:"focusout"+u,MOUSEENTER:"mouseenter"+u,MOUSELEAVE:"mouseleave"+u},v=function(l){function f(){o(this,f),a(Object.getPrototypeOf(f.prototype),"constructor",this).apply(this,arguments)}return r(f,l),s(f,[{key:"isWithContent",value:function(){return this.getTitle()||this._getContent()}},{key:"getTipElement",value:function(){return this.tip=this.tip||t(this.config.template)[0]}},{key:"setContent",value:function(){var e=t(this.getTipElement());this.setElementContent(e.find(p.TITLE),this.getTitle()),this.setElementContent(e.find(p.CONTENT),this._getContent()),e.removeClass(d.FADE).removeClass(d.IN),this.cleanupTether()}},{key:"_getContent",value:function(){return this.element.getAttribute("data-content")||("function"==typeof this.config.content?this.config.content.call(this.element):this.config.content)}}],[{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this).data(i),o="object"==typeof e?e:null;if((n||!/destroy|hide/.test(e))&&(n||(n=new f(this,o),t(this).data(i,n)),"string"==typeof e)){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return h}},{key:"NAME",get:function(){return e}},{key:"DATA_KEY",get:function(){return i}},{key:"Event",get:function(){return g}},{key:"EVENT_KEY",get:function(){return u}},{key:"DefaultType",get:function(){return c}}]),f}(l["default"]);return t.fn[e]=v._jQueryInterface,t.fn[e].Constructor=v,t.fn[e].noConflict=function(){return t.fn[e]=f,v._jQueryInterface},v}(jQuery);e.exports=u})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){
-"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="scrollspy",n="4.0.0-alpha",i="bs.scrollspy",a="."+i,l=".data-api",u=t.fn[e],f={offset:10,method:"auto",target:""},h={offset:"number",method:"string",target:"(string|element)"},c={ACTIVATE:"activate"+a,SCROLL:"scroll"+a,LOAD_DATA_API:"load"+a+l},d={DROPDOWN_ITEM:"dropdown-item",DROPDOWN_MENU:"dropdown-menu",NAV_LINK:"nav-link",NAV:"nav",ACTIVE:"active"},p={DATA_SPY:'[data-spy="scroll"]',ACTIVE:".active",LIST_ITEM:".list-item",LI:"li",LI_DROPDOWN:"li.dropdown",NAV_LINKS:".nav-link",DROPDOWN:".dropdown",DROPDOWN_ITEMS:".dropdown-item",DROPDOWN_TOGGLE:".dropdown-toggle"},g={OFFSET:"offset",POSITION:"position"},v=function(){function l(e,n){o(this,l),this._element=e,this._scrollElement="BODY"===e.tagName?window:e,this._config=this._getConfig(n),this._selector=this._config.target+" "+p.NAV_LINKS+","+(this._config.target+" "+p.DROPDOWN_ITEMS),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,t(this._scrollElement).on(c.SCROLL,t.proxy(this._process,this)),this.refresh(),this._process()}return r(l,[{key:"refresh",value:function(){var e=this,n=this._scrollElement!==this._scrollElement.window?g.POSITION:g.OFFSET,i="auto"===this._config.method?n:this._config.method,o=i===g.POSITION?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight();var r=t.makeArray(t(this._selector));r.map(function(e){var n=void 0,r=s["default"].getSelectorFromElement(e);return r&&(n=t(r)[0]),n&&(n.offsetWidth||n.offsetHeight)?[t(n)[i]().top+o,r]:void 0}).filter(function(t){return t}).sort(function(t,e){return t[0]-e[0]}).forEach(function(t){e._offsets.push(t[0]),e._targets.push(t[1])})}},{key:"dispose",value:function(){t.removeData(this._element,i),t(this._scrollElement).off(a),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null}},{key:"_getConfig",value:function(n){if(n=t.extend({},f,n),"string"!=typeof n.target){var i=t(n.target).attr("id");i||(i=s["default"].getUID(e),t(n.target).attr("id",i)),n.target="#"+i}return s["default"].typeCheckConfig(e,n,h),n}},{key:"_getScrollTop",value:function(){return this._scrollElement===window?this._scrollElement.scrollY:this._scrollElement.scrollTop}},{key:"_getScrollHeight",value:function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}},{key:"_process",value:function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._scrollElement.offsetHeight;if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}if(this._activeTarget&&t<this._offsets[0])return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;){var r=this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&(void 0===this._offsets[o+1]||t<this._offsets[o+1]);r&&this._activate(this._targets[o])}}},{key:"_activate",value:function(e){this._activeTarget=e,this._clear();var n=this._selector.split(",");n=n.map(function(t){return t+'[data-target="'+e+'"],'+(t+'[href="'+e+'"]')});var i=t(n.join(","));i.hasClass(d.DROPDOWN_ITEM)?(i.closest(p.DROPDOWN).find(p.DROPDOWN_TOGGLE).addClass(d.ACTIVE),i.addClass(d.ACTIVE)):i.parents(p.LI).find(p.NAV_LINKS).addClass(d.ACTIVE),t(this._scrollElement).trigger(c.ACTIVATE,{relatedTarget:e})}},{key:"_clear",value:function(){t(this._selector).filter(p.ACTIVE).removeClass(d.ACTIVE)}}],[{key:"_jQueryInterface",value:function(e){return this.each(function(){var n=t(this).data(i),o="object"==typeof e&&e||null;if(n||(n=new l(this,o),t(this).data(i,n)),"string"==typeof e){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})}},{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return f}}]),l}();return t(window).on(c.LOAD_DATA_API,function(){for(var e=t.makeArray(t(p.DATA_SPY)),n=e.length;n--;){var i=t(e[n]);v._jQueryInterface.call(i,i.data())}}),t.fn[e]=v._jQueryInterface,t.fn[e].Constructor=v,t.fn[e].noConflict=function(){return t.fn[e]=u,v._jQueryInterface},v}(jQuery);e.exports=a})},function(t,e,n){var i,o,r;!function(s,a){o=[e,t,n(1)],i=a,r="function"==typeof i?i.apply(e,o):i,!(void 0!==r&&(t.exports=r))}(this,function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=i(n),a=function(t){var e="tab",n="4.0.0-alpha",i="bs.tab",a="."+i,l=".data-api",u=t.fn[e],f=150,h={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,CLICK_DATA_API:"click"+a+l},c={DROPDOWN_MENU:"dropdown-menu",ACTIVE:"active",FADE:"fade",IN:"in"},d={A:"a",LI:"li",DROPDOWN:".dropdown",UL:"ul:not(.dropdown-menu)",FADE_CHILD:"> .nav-item .fade, > .fade",ACTIVE:".active",ACTIVE_CHILD:"> .nav-item > .active, > .active",DATA_TOGGLE:'[data-toggle="tab"], [data-toggle="pill"]',DROPDOWN_TOGGLE:".dropdown-toggle",DROPDOWN_ACTIVE_CHILD:"> .dropdown-menu .active"},p=function(){function e(t){o(this,e),this._element=t}return r(e,[{key:"show",value:function(){var e=this;if(!this._element.parentNode||this._element.parentNode.nodeType!==Node.ELEMENT_NODE||!t(this._element).hasClass(c.ACTIVE)){var n=void 0,i=void 0,o=t(this._element).closest(d.UL)[0],r=s["default"].getSelectorFromElement(this._element);o&&(i=t.makeArray(t(o).find(d.ACTIVE)),i=i[i.length-1]);var a=t.Event(h.HIDE,{relatedTarget:this._element}),l=t.Event(h.SHOW,{relatedTarget:i});if(i&&t(i).trigger(a),t(this._element).trigger(l),!l.isDefaultPrevented()&&!a.isDefaultPrevented()){r&&(n=t(r)[0]),this._activate(this._element,o);var u=function(){var n=t.Event(h.HIDDEN,{relatedTarget:e._element}),o=t.Event(h.SHOWN,{relatedTarget:i});t(i).trigger(n),t(e._element).trigger(o)};n?this._activate(n,n.parentNode,u):u()}}}},{key:"dispose",value:function(){t.removeClass(this._element,i),this._element=null}},{key:"_activate",value:function(e,n,i){var o=t(n).find(d.ACTIVE_CHILD)[0],r=i&&s["default"].supportsTransitionEnd()&&(o&&t(o).hasClass(c.FADE)||Boolean(t(n).find(d.FADE_CHILD)[0])),a=t.proxy(this._transitionComplete,this,e,o,r,i);o&&r?t(o).one(s["default"].TRANSITION_END,a).emulateTransitionEnd(f):a(),o&&t(o).removeClass(c.IN)}},{key:"_transitionComplete",value:function(e,n,i,o){if(n){t(n).removeClass(c.ACTIVE);var r=t(n).find(d.DROPDOWN_ACTIVE_CHILD)[0];r&&t(r).removeClass(c.ACTIVE),n.setAttribute("aria-expanded",!1)}if(t(e).addClass(c.ACTIVE),e.setAttribute("aria-expanded",!0),i?(s["default"].reflow(e),t(e).addClass(c.IN)):t(e).removeClass(c.FADE),e.parentNode&&t(e.parentNode).hasClass(c.DROPDOWN_MENU)){var a=t(e).closest(d.DROPDOWN)[0];a&&t(a).find(d.DROPDOWN_TOGGLE).addClass(c.ACTIVE),e.setAttribute("aria-expanded",!0)}o&&o()}}],[{key:"_jQueryInterface",value:function(n){return this.each(function(){var o=t(this),r=o.data(i);if(r||(r=r=new e(this),o.data(i,r)),"string"==typeof n){if(void 0===r[n])throw new Error('No method named "'+n+'"');r[n]()}})}},{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(h.CLICK_DATA_API,d.DATA_TOGGLE,function(e){e.preventDefault(),p._jQueryInterface.call(t(this),"show")}),t.fn[e]=p._jQueryInterface,t.fn[e].Constructor=p,t.fn[e].noConflict=function(){return t.fn[e]=u,p._jQueryInterface},p}(jQuery);e.exports=a})},function(t,e){}]);
\ No newline at end of file
diff --git a/hubs/static/fedora-bootstrap/fedora-bootstrap.min.css b/hubs/static/fedora-bootstrap/fedora-bootstrap.min.css
new file mode 100644
index 0000000..0476390
--- /dev/null
+++ b/hubs/static/fedora-bootstrap/fedora-bootstrap.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Bootstrap v4.0.0-alpha.6 (https://getbootstrap.com)
+ * Copyright 2011-2017 The Bootstrap Authors
+ * Copyright 2011-2017 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}code,kbd,samp{font-family:monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}@media print{*,:after,:before,blockquote:first-letter,blockquote:first-line,div:first-letter,div:first-line,li:first-letter,li:first-line,p:first-letter,p:first-line{text-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]:after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}@-ms-viewport{width:device-width}html{-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}body{font-family:Open Sans;font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{cursor:help}address{font-style:normal;line-height:inherit}address,dl,ol,ul{margin-bottom:1rem}dl,ol,ul{margin-top:0}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}a{color:#0275d8;text-decoration:none}a:focus,a:hover{color:#014c8c;text-decoration:underline}a:not([href]):not([tabindex]),a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle}[role=button]{cursor:pointer}[role=button],a,area,button,input,label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse;background-color:transparent}caption{padding-top:.75rem;padding-bottom:.75rem;color:#d5d5d5;caption-side:bottom}caption,th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,select,textarea{line-height:inherit}input[type=checkbox]:disabled,input[type=radio]:disabled{cursor:not-allowed}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}input[type=search]{-webkit-appearance:none}output{display:inline-block}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1,h1{font-size:2rem}.h2,h2{font-size:1.75rem}.h3,h3{font-size:1.5rem}.h4,h4{font-size:1.25rem}.h5,.h6,h5,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem}.display-1,.display-2{font-weight:300;line-height:1.1}.display-2{font-size:5.5rem}.display-3{font-size:4.5rem}.display-3,.display-4{font-weight:300;line-height:1.1}.display-4{font-size:3.5rem}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.initialism{font-size:90%;text-transform:uppercase}.blockquote{padding:.5rem 1rem;margin-bottom:1rem;font-size:1.25rem;border-left:.25rem solid #eceeef}.blockquote-footer{display:block;font-size:80%;color:#d5d5d5}.blockquote-footer:before{content:"\2014   \A0"}.blockquote-reverse{padding-right:1rem;padding-left:0;text-align:right;border-right:.25rem solid #eceeef;border-left:0}.blockquote-reverse .blockquote-footer:before{content:""}.blockquote-reverse .blockquote-footer:after{content:"\A0   \2014"}.img-fluid,.img-thumbnail{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #ddd;border-radius:.25rem;transition:all .2s ease-in-out}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#d5d5d5}code,kbd,pre,samp{font-family:Hack,monospace}code{padding:.2rem .4rem;font-size:90%;color:#bd4147;background-color:#f3f3f3;border-radius:.25rem}a>code{padding:0;color:inherit;background-color:inherit}kbd{padding:.2rem .4rem;font-size:90%;color:#fff;background-color:#373a3c;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;margin-top:0;margin-bottom:1rem;font-size:90%;color:#586e75}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{position:relative;margin-left:auto;margin-right:auto;padding-right:15px;padding-left:15px}@media (min-width:576px){.container{padding-right:15px;padding-left:15px}}@media (min-width:768px){.container{padding-right:15px;padding-left:15px}}@media (min-width:992px){.container{padding-right:15px;padding-left:15px}}@media (min-width:1200px){.container{padding-right:15px;padding-left:15px}}@media (min-width:576px){.container{width:540px;max-width:100%}}@media (min-width:768px){.container{width:45pc;max-width:100%}}@media (min-width:992px){.container{width:60pc;max-width:100%}}@media (min-width:1200px){.container{width:855pt;max-width:100%}}.container-fluid{position:relative;margin-left:auto;margin-right:auto;padding-right:15px;padding-left:15px}@media (min-width:576px){.container-fluid{padding-right:15px;padding-left:15px}}@media (min-width:768px){.container-fluid{padding-right:15px;padding-left:15px}}@media (min-width:992px){.container-fluid{padding-right:15px;padding-left:15px}}@media (min-width:1200px){.container-fluid{padding-right:15px;padding-left:15px}}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}@media (min-width:576px){.row{margin-right:-15px;margin-left:-15px}}@media (min-width:768px){.row{margin-right:-15px;margin-left:-15px}}@media (min-width:992px){.row{margin-right:-15px;margin-left:-15px}}@media (min-width:1200px){.row{margin-right:-15px;margin-left:-15px}}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}@media (min-width:576px){.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{padding-right:15px;padding-left:15px}}@media (min-width:768px){.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{padding-right:15px;padding-left:15px}}@media (min-width:992px){.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{padding-right:15px;padding-left:15px}}@media (min-width:1200px){.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{padding-right:15px;padding-left:15px}}.col{flex-basis:0;flex-grow:1;max-width:100%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.pull-0{right:auto}.pull-1{right:8.33333%}.pull-2{right:16.66667%}.pull-3{right:25%}.pull-4{right:33.33333%}.pull-5{right:41.66667%}.pull-6{right:50%}.pull-7{right:58.33333%}.pull-8{right:66.66667%}.pull-9{right:75%}.pull-10{right:83.33333%}.pull-11{right:91.66667%}.pull-12{right:100%}.push-0{left:auto}.push-1{left:8.33333%}.push-2{left:16.66667%}.push-3{left:25%}.push-4{left:33.33333%}.push-5{left:41.66667%}.push-6{left:50%}.push-7{left:58.33333%}.push-8{left:66.66667%}.push-9{left:75%}.push-10{left:83.33333%}.push-11{left:91.66667%}.push-12{left:100%}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.pull-sm-0{right:auto}.pull-sm-1{right:8.33333%}.pull-sm-2{right:16.66667%}.pull-sm-3{right:25%}.pull-sm-4{right:33.33333%}.pull-sm-5{right:41.66667%}.pull-sm-6{right:50%}.pull-sm-7{right:58.33333%}.pull-sm-8{right:66.66667%}.pull-sm-9{right:75%}.pull-sm-10{right:83.33333%}.pull-sm-11{right:91.66667%}.pull-sm-12{right:100%}.push-sm-0{left:auto}.push-sm-1{left:8.33333%}.push-sm-2{left:16.66667%}.push-sm-3{left:25%}.push-sm-4{left:33.33333%}.push-sm-5{left:41.66667%}.push-sm-6{left:50%}.push-sm-7{left:58.33333%}.push-sm-8{left:66.66667%}.push-sm-9{left:75%}.push-sm-10{left:83.33333%}.push-sm-11{left:91.66667%}.push-sm-12{left:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.pull-md-0{right:auto}.pull-md-1{right:8.33333%}.pull-md-2{right:16.66667%}.pull-md-3{right:25%}.pull-md-4{right:33.33333%}.pull-md-5{right:41.66667%}.pull-md-6{right:50%}.pull-md-7{right:58.33333%}.pull-md-8{right:66.66667%}.pull-md-9{right:75%}.pull-md-10{right:83.33333%}.pull-md-11{right:91.66667%}.pull-md-12{right:100%}.push-md-0{left:auto}.push-md-1{left:8.33333%}.push-md-2{left:16.66667%}.push-md-3{left:25%}.push-md-4{left:33.33333%}.push-md-5{left:41.66667%}.push-md-6{left:50%}.push-md-7{left:58.33333%}.push-md-8{left:66.66667%}.push-md-9{left:75%}.push-md-10{left:83.33333%}.push-md-11{left:91.66667%}.push-md-12{left:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:992px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.pull-lg-0{right:auto}.pull-lg-1{right:8.33333%}.pull-lg-2{right:16.66667%}.pull-lg-3{right:25%}.pull-lg-4{right:33.33333%}.pull-lg-5{right:41.66667%}.pull-lg-6{right:50%}.pull-lg-7{right:58.33333%}.pull-lg-8{right:66.66667%}.pull-lg-9{right:75%}.pull-lg-10{right:83.33333%}.pull-lg-11{right:91.66667%}.pull-lg-12{right:100%}.push-lg-0{left:auto}.push-lg-1{left:8.33333%}.push-lg-2{left:16.66667%}.push-lg-3{left:25%}.push-lg-4{left:33.33333%}.push-lg-5{left:41.66667%}.push-lg-6{left:50%}.push-lg-7{left:58.33333%}.push-lg-8{left:66.66667%}.push-lg-9{left:75%}.push-lg-10{left:83.33333%}.push-lg-11{left:91.66667%}.push-lg-12{left:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.pull-xl-0{right:auto}.pull-xl-1{right:8.33333%}.pull-xl-2{right:16.66667%}.pull-xl-3{right:25%}.pull-xl-4{right:33.33333%}.pull-xl-5{right:41.66667%}.pull-xl-6{right:50%}.pull-xl-7{right:58.33333%}.pull-xl-8{right:66.66667%}.pull-xl-9{right:75%}.pull-xl-10{right:83.33333%}.pull-xl-11{right:91.66667%}.pull-xl-12{right:100%}.push-xl-0{left:auto}.push-xl-1{left:8.33333%}.push-xl-2{left:16.66667%}.push-xl-3{left:25%}.push-xl-4{left:33.33333%}.push-xl-5{left:41.66667%}.push-xl-6{left:50%}.push-xl-7{left:58.33333%}.push-xl-8{left:66.66667%}.push-xl-9{left:75%}.push-xl-10{left:83.33333%}.push-xl-11{left:91.66667%}.push-xl-12{left:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;max-width:100%;margin-bottom:1rem}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #eceeef}.table thead th{vertical-align:bottom;border-bottom:2px solid #eceeef}.table tbody+tbody{border-top:2px solid #eceeef}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #eceeef}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-active,.table-active>td,.table-active>th,.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th,.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-success,.table-success>td,.table-success>th{background-color:#dff0d8}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#d0e9c6}.table-info,.table-info>td,.table-info>th{background-color:#d9edf7}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#c4e3f3}.table-warning,.table-warning>td,.table-warning>th{background-color:#fcf8e3}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#faf2cc}.table-danger,.table-danger>td,.table-danger>th{background-color:#f2dede}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#ebcccc}.thead-inverse th{color:#fff;background-color:#373a3c}.thead-default th{color:#55595c;background-color:#eceeef}.table-inverse{color:#fff;background-color:#373a3c}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#fff}.table-inverse.table-bordered{border:0}.table-responsive{display:block;width:100%;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive.table-bordered{border:0}.form-control{display:block;width:100%;padding:.5rem .75rem;font-size:1rem;line-height:1.25;color:#55595c;background-color:#fff;background-image:none;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#55595c;background-color:#fff;border-color:#5cb3fd;outline:0}.form-control::placeholder{color:#d5d5d5;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#eceeef;opacity:1}.form-control:disabled{cursor:not-allowed}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#55595c;background-color:#fff}.form-control-file,.form-control-range{display:block}.col-form-label{padding-top:calc(.5rem - 1px * 2);padding-bottom:calc(.5rem - 1px * 2);margin-bottom:0}.col-form-label-lg{padding-top:calc(.75rem - 1px * 2);padding-bottom:calc(.75rem - 1px * 2);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem - 1px * 2);padding-bottom:calc(.25rem - 1px * 2);font-size:.875rem}.col-form-legend{font-size:1rem}.col-form-legend,.form-control-static{padding-top:.5rem;padding-bottom:.5rem;margin-bottom:0}.form-control-static{line-height:1.25;border:solid transparent;border-width:1px 0}.form-control-static.form-control-lg,.form-control-static.form-control-sm,.input-group-lg>.form-control-static.form-control,.input-group-lg>.form-control-static.input-group-addon,.input-group-lg>.input-group-btn>.form-control-static.btn,.input-group-sm>.form-control-static.form-control,.input-group-sm>.form-control-static.input-group-addon,.input-group-sm>.input-group-btn>.form-control-static.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-sm>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),.input-group-sm>select.input-group-addon:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:1.8125rem}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.75rem 1.5rem;font-size:1.25rem;border-radius:.3rem}.input-group-lg>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),.input-group-lg>select.input-group-addon:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:3.16667rem}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-check{position:relative;display:block;margin-bottom:.5rem}.form-check.disabled .form-check-label{color:#d5d5d5;cursor:not-allowed}.form-check-label{padding-left:1.25rem;margin-bottom:0;cursor:pointer}.form-check-input{position:absolute;margin-top:.25rem;margin-left:-1.25rem}.form-check-input:only-child{position:static}.form-check-inline{display:inline-block}.form-check-inline .form-check-label{vertical-align:middle}.form-check-inline+.form-check-inline{margin-left:.75rem}.form-control-feedback{margin-top:.25rem}.form-control-danger,.form-control-success,.form-control-warning{padding-right:2.25rem;background-repeat:no-repeat;background-position:center right .5625rem;background-size:1.125rem 1.125rem}.has-success .col-form-label,.has-success .custom-control,.has-success .form-check-label,.has-success .form-control-feedback,.has-success .form-control-label{color:#5cb85c}.has-success .form-control{border-color:#5cb85c}.has-success .input-group-addon{color:#5cb85c;border-color:#5cb85c;background-color:#eaf6ea}.has-success .form-control-success{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%235cb85c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E")}.has-warning .col-form-label,.has-warning .custom-control,.has-warning .form-check-label,.has-warning .form-control-feedback,.has-warning .form-control-label{color:#f0ad4e}.has-warning .form-control{border-color:#f0ad4e}.has-warning .input-group-addon{color:#f0ad4e;border-color:#f0ad4e;background-color:#fff}.has-warning .form-control-warning{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23f0ad4e' d='M4.4 5.324h-.8v-2.46h.8zm0 1.42h-.8V5.89h.8zM3.76.63L.04 7.075c-.115.2.016.425.26.426h7.397c.242 0 .372-.226.258-.426C6.726 4.924 5.47 2.79 4.253.63c-.113-.174-.39-.174-.494 0z'/%3E%3C/svg%3E")}.has-danger .col-form-label,.has-danger .custom-control,.has-danger .form-check-label,.has-danger .form-control-feedback,.has-danger .form-control-label{color:#d9534f}.has-danger .form-control{border-color:#d9534f}.has-danger .input-group-addon{color:#d9534f;border-color:#d9534f;background-color:#fdf7f7}.has-danger .form-control-danger{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23d9534f' viewBox='-2 -2 7 7'%3E%3Cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3E%3Ccircle r='.5'/%3E%3Ccircle cx='3' r='.5'/%3E%3Ccircle cy='3' r='.5'/%3E%3Ccircle cx='3' cy='3' r='.5'/%3E%3C/svg%3E")}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{justify-content:center}.form-inline .form-group,.form-inline label{display:flex;align-items:center;margin-bottom:0}.form-inline .form-group{flex:0 0 auto;flex-flow:row wrap}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-control-label{margin-bottom:0;vertical-align:middle}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;margin-top:0;margin-bottom:0}.form-inline .form-check-label{padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{display:flex;align-items:center;justify-content:center;padding-left:0}.form-inline .custom-control-indicator{position:static;display:inline-block;margin-right:.25rem;vertical-align:text-bottom}.form-inline .has-feedback .form-control-feedback{top:0}}.btn{display:inline-block;font-weight:400;line-height:1.25;text-align:center;white-space:nowrap;vertical-align:middle;user-select:none;border:1px solid transparent;padding:.5rem 1rem;font-size:1rem;border-radius:.25rem;transition:all .2s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 2px rgba(2,117,216,.25)}.btn.disabled,.btn:disabled{cursor:not-allowed;opacity:.65}.btn.active,.btn:active{background-image:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary:hover{color:#fff;background-color:#025aa5;border-color:#01549b}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 2px rgba(2,117,216,.5)}.btn-primary.disabled,.btn-primary:disabled{background-color:#0275d8;border-color:#0275d8}.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#025aa5;background-image:none;border-color:#01549b}.btn-secondary{color:#373a3c;background-color:#fff;border-color:#ccc}.btn-secondary:hover{color:#373a3c;background-color:#e6e6e6;border-color:#adadad}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 2px hsla(0,0%,80%,.5)}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#fff;border-color:#ccc}.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#373a3c;background-color:#e6e6e6;background-image:none;border-color:#adadad}.btn-info{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#2aabd2}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 2px rgba(91,192,222,.5)}.btn-info.disabled,.btn-info:disabled{background-color:#5bc0de;border-color:#5bc0de}.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#31b0d5;background-image:none;border-color:#2aabd2}.btn-success{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#419641}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 2px rgba(92,184,92,.5)}.btn-success.disabled,.btn-success:disabled{background-color:#5cb85c;border-color:#5cb85c}.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#449d44;background-image:none;border-color:#419641}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#eb9316}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 2px rgba(240,173,78,.5)}.btn-warning.disabled,.btn-warning:disabled{background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#fff;background-color:#ec971f;background-image:none;border-color:#eb9316}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#c12e2a}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 2px rgba(217,83,79,.5)}.btn-danger.disabled,.btn-danger:disabled{background-color:#d9534f;border-color:#d9534f}.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#c9302c;background-image:none;border-color:#c12e2a}.btn-outline-primary{color:#0275d8;background-image:none;background-color:transparent;border-color:#0275d8}.btn-outline-primary:hover{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 2px rgba(2,117,216,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0275d8;background-color:transparent}.btn-outline-primary.active,.btn-outline-primary:active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-outline-secondary{color:#ccc;background-image:none;background-color:transparent;border-color:#ccc}.btn-outline-secondary:hover{color:#fff;background-color:#ccc;border-color:#ccc}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 2px hsla(0,0%,80%,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#ccc;background-color:transparent}.btn-outline-secondary.active,.btn-outline-secondary:active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#ccc;border-color:#ccc}.btn-outline-info{color:#5bc0de;background-image:none;background-color:transparent;border-color:#5bc0de}.btn-outline-info:hover{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 2px rgba(91,192,222,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#5bc0de;background-color:transparent}.btn-outline-info.active,.btn-outline-info:active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-outline-success{color:#5cb85c;background-image:none;background-color:transparent;border-color:#5cb85c}.btn-outline-success:hover{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 2px rgba(92,184,92,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#5cb85c;background-color:transparent}.btn-outline-success.active,.btn-outline-success:active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-outline-warning{color:#f0ad4e;background-image:none;background-color:transparent;border-color:#f0ad4e}.btn-outline-warning:hover{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 2px rgba(240,173,78,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#f0ad4e;background-color:transparent}.btn-outline-warning.active,.btn-outline-warning:active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-outline-danger{color:#d9534f;background-image:none;background-color:transparent;border-color:#d9534f}.btn-outline-danger:hover{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 2px rgba(217,83,79,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#d9534f;background-color:transparent}.btn-outline-danger.active,.btn-outline-danger:active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-link{font-weight:400;color:#0275d8;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#014c8c;text-decoration:underline;background-color:transparent}.btn-link:disabled{color:#d5d5d5}.btn-link:disabled:focus,.btn-link:disabled:hover{text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.75rem 1.5rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{height:0;overflow:hidden;transition:height .35s ease}.collapsing,.dropdown,.dropup{position:relative}.dropdown-toggle:after{display:inline-block;width:0;height:0;margin-left:.3em;vertical-align:middle;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:focus{outline:0}.dropup .dropdown-toggle:after{border-top:0;border-bottom:.3em solid}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-divider{height:1px;margin:.5rem 0;overflow:hidden;background-color:#eceeef}.dropdown-item{display:block;width:100%;padding:3px 1.5rem;clear:both;font-weight:400;color:#373a3c;text-align:inherit;white-space:nowrap;background:none;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#2b2d2f;text-decoration:none;background-color:#f3f3f3}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0275d8}.dropdown-item.disabled,.dropdown-item:disabled{color:#d5d5d5;cursor:not-allowed;background-color:transparent}.show>.dropdown-menu{display:block}.show>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#d5d5d5;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.dropup .dropdown-menu{top:auto;bottom:100%;margin-bottom:.125rem}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:0 1 auto}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:flex;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn+.dropdown-toggle-split:after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:1.125rem;padding-left:1.125rem}.btn-group-vertical{display:inline-flex;flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:flex;width:100%}.input-group .form-control{position:relative;z-index:2;flex:1 1 auto;width:1%;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover{z-index:3}.input-group .form-control,.input-group-addon,.input-group-btn{display:flex;flex-direction:column;justify-content:center}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{white-space:nowrap;vertical-align:middle}.input-group-addon{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.25;color:#55595c;text-align:center;background-color:#eceeef;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.75rem 1.5rem;font-size:1.25rem;border-radius:.3rem}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:not(:last-child),.input-group-addon:not(:last-child),.input-group-btn:not(:first-child)>.btn-group:not(:last-child)>.btn,.input-group-btn:not(:first-child)>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group>.btn,.input-group-btn:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:not(:last-child){border-right:0}.input-group .form-control:not(:first-child),.input-group-addon:not(:first-child),.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group>.btn,.input-group-btn:not(:first-child)>.dropdown-toggle,.input-group-btn:not(:last-child)>.btn-group:not(:first-child)>.btn,.input-group-btn:not(:last-child)>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.form-control+.input-group-addon:not(:first-child){border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative;flex:1}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group{margin-right:-1px}.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group{z-index:2;margin-left:-1px}.input-group-btn:not(:first-child)>.btn-group:active,.input-group-btn:not(:first-child)>.btn-group:focus,.input-group-btn:not(:first-child)>.btn-group:hover,.input-group-btn:not(:first-child)>.btn:active,.input-group-btn:not(:first-child)>.btn:focus,.input-group-btn:not(:first-child)>.btn:hover{z-index:3}.custom-control{position:relative;display:inline-flex;min-height:1.5rem;padding-left:1.5rem;margin-right:1rem;cursor:pointer}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-indicator{color:#fff;background-color:#0275d8}.custom-control-input:focus~.custom-control-indicator{box-shadow:0 0 0 1px #fff,0 0 0 3px #0275d8}.custom-control-input:active~.custom-control-indicator{color:#fff;background-color:#8fcafe}.custom-control-input:disabled~.custom-control-indicator{cursor:not-allowed;background-color:#eceeef}.custom-control-input:disabled~.custom-control-description{color:#d5d5d5;cursor:not-allowed}.custom-control-indicator{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;user-select:none;background-color:#ddd;background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-indicator{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-indicator{background-color:#0275d8;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-radio .custom-control-indicator{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-controls-stacked{display:flex;flex-direction:column}.custom-controls-stacked .custom-control{margin-bottom:.25rem}.custom-controls-stacked .custom-control+.custom-control{margin-left:0}.custom-select{display:inline-block;max-width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.25;color:#55595c;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;-moz-appearance:none;-webkit-appearance:none}.custom-select:focus{border-color:#5cb3fd;outline:0}.custom-select:focus::-ms-value{color:#55595c;background-color:#fff}.custom-select:disabled{color:#d5d5d5;cursor:not-allowed;background-color:#eceeef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-file{position:relative;display:inline-block;max-width:100%;height:2.5rem;margin-bottom:0;cursor:pointer}.custom-file-input{min-width:14rem;max-width:100%;height:2.5rem;margin:0;filter:alpha(opacity=0);opacity:0}.custom-file-control{position:absolute;top:0;right:0;left:0;z-index:5;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#55595c;pointer-events:none;user-select:none;background-color:#fff;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.custom-file-control:lang(en):after{content:"Choose file..."}.custom-file-control:before{position:absolute;top:-1px;right:-1px;bottom:-1px;z-index:6;display:block;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#55595c;background-color:#eceeef;border:1px solid rgba(0,0,0,.15);border-radius:0 .25rem .25rem 0}.custom-file-control:lang(en):before{content:"Browse"}.nav{display:flex;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5em 1em}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#d5d5d5;cursor:not-allowed}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-right-radius:.25rem;border-top-left-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#eceeef #eceeef #ddd}.nav-tabs .nav-link.disabled{color:#d5d5d5;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#55595c;background-color:#fff;border-color:#ddd #ddd #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-item.show .nav-link,.nav-pills .nav-link.active{color:#fff;cursor:default;background-color:#0275d8}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex:1 1 100%;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-direction:column;padding:.5rem 1rem}.navbar-brand{display:inline-block;padding-top:.25rem;padding-bottom:.25rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-text{display:inline-block;padding-top:.425rem;padding-bottom:.425rem}.navbar-toggler{align-self:flex-start;padding:.25rem .75rem;font-size:1.25rem;line-height:1;background:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}.navbar-toggler-left{position:absolute;left:1rem}.navbar-toggler-right{position:absolute;right:1rem}@media (max-width:575px){.navbar-toggleable .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable>.container{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-toggleable{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable .navbar-nav{flex-direction:row}.navbar-toggleable .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable .navbar-toggler{display:none}}@media (max-width:767px){.navbar-toggleable-sm .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable-sm>.container{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-toggleable-sm{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable-sm .navbar-nav{flex-direction:row}.navbar-toggleable-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable-sm>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable-sm .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable-sm .navbar-toggler{display:none}}@media (max-width:991px){.navbar-toggleable-md .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable-md>.container{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-toggleable-md{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable-md .navbar-nav{flex-direction:row}.navbar-toggleable-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable-md>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable-md .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable-md .navbar-toggler{display:none}}@media (max-width:1199px){.navbar-toggleable-lg .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable-lg>.container{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-toggleable-lg{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable-lg .navbar-nav{flex-direction:row}.navbar-toggleable-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable-lg>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable-lg .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable-lg .navbar-toggler{display:none}}.navbar-toggleable-xl{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable-xl .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable-xl>.container{padding-right:0;padding-left:0}.navbar-toggleable-xl .navbar-nav{flex-direction:row}.navbar-toggleable-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable-xl>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable-xl .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable-xl .navbar-toggler{display:none}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover,.navbar-light .navbar-toggler,.navbar-light .navbar-toggler:focus,.navbar-light .navbar-toggler:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.open,.navbar-light .navbar-nav .open>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0,0,0,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-toggler,.navbar-inverse .navbar-toggler:focus,.navbar-inverse .navbar-toggler:hover{color:#fff}.navbar-inverse .navbar-nav .nav-link{color:hsla(0,0%,100%,.5)}.navbar-inverse .navbar-nav .nav-link:focus,.navbar-inverse .navbar-nav .nav-link:hover{color:hsla(0,0%,100%,.75)}.navbar-inverse .navbar-nav .nav-link.disabled{color:hsla(0,0%,100%,.25)}.navbar-inverse .navbar-nav .active>.nav-link,.navbar-inverse .navbar-nav .nav-link.active,.navbar-inverse .navbar-nav .nav-link.open,.navbar-inverse .navbar-nav .open>.nav-link{color:#fff}.navbar-inverse .navbar-toggler{border-color:hsla(0,0%,100%,.1)}.navbar-inverse .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255,255,255,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E")}.navbar-inverse .navbar-text{color:hsla(0,0%,100%,.5)}.card{position:relative;display:flex;flex-direction:column;background-color:#fff;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card-block{flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem}.card-subtitle,.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card>.list-group:first-child .list-group-item:first-child{border-top-right-radius:.25rem;border-top-left-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:#f3f3f3;border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.75rem 1.25rem;background-color:#f3f3f3;border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-bottom:-.75rem;border-bottom:0}.card-header-pills,.card-header-tabs{margin-right:-.625rem;margin-left:-.625rem}.card-primary{background-color:#0275d8;border-color:#0275d8}.card-primary .card-footer,.card-primary .card-header{background-color:transparent}.card-success{background-color:#5cb85c;border-color:#5cb85c}.card-success .card-footer,.card-success .card-header{background-color:transparent}.card-info{background-color:#5bc0de;border-color:#5bc0de}.card-info .card-footer,.card-info .card-header{background-color:transparent}.card-warning{background-color:#f0ad4e;border-color:#f0ad4e}.card-warning .card-footer,.card-warning .card-header{background-color:transparent}.card-danger{background-color:#d9534f;border-color:#d9534f}.card-danger .card-footer,.card-danger .card-header,.card-outline-primary{background-color:transparent}.card-outline-primary{border-color:#0275d8}.card-outline-secondary{background-color:transparent;border-color:#ccc}.card-outline-info{background-color:transparent;border-color:#5bc0de}.card-outline-success{background-color:transparent;border-color:#5cb85c}.card-outline-warning{background-color:transparent;border-color:#f0ad4e}.card-outline-danger{background-color:transparent;border-color:#d9534f}.card-inverse{color:hsla(0,0%,100%,.65)}.card-inverse .card-footer,.card-inverse .card-header{background-color:transparent;border-color:hsla(0,0%,100%,.2)}.card-inverse .card-blockquote,.card-inverse .card-footer,.card-inverse .card-header,.card-inverse .card-title{color:#fff}.card-inverse .card-blockquote .blockquote-footer,.card-inverse .card-link,.card-inverse .card-subtitle,.card-inverse .card-text{color:hsla(0,0%,100%,.65)}.card-inverse .card-link:focus,.card-inverse .card-link:hover{color:#fff}.card-blockquote{padding:0;margin-bottom:0;border-left:0}.card-img{border-radius:calc(.25rem - 1px)}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img-top{border-top-right-radius:calc(.25rem - 1px);border-top-left-radius:calc(.25rem - 1px)}.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}@media (min-width:576px){.card-deck{display:flex;flex-flow:row wrap}.card-deck .card{display:flex;flex:1 0 0;flex-direction:column}.card-deck .card:not(:first-child){margin-left:15px}.card-deck .card:not(:last-child){margin-right:15px}}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group .card{flex:1 0 0}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-bottom-right-radius:0;border-top-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-bottom-left-radius:0;border-top-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child),.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}}@media (min-width:576px){.card-columns{column-count:3;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%;margin-bottom:.75rem}}.breadcrumb{padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#eceeef;border-radius:.25rem}.breadcrumb:after{display:block;content:"";clear:both}.breadcrumb-item{float:left}.breadcrumb-item+.breadcrumb-item:before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#d5d5d5;content:"/"}.breadcrumb-item+.breadcrumb-item:hover:before{text-decoration:underline;text-decoration:none}.breadcrumb-item.active{color:#d5d5d5}.pagination{display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-item:first-child .page-link{margin-left:0;border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.page-item:last-child .page-link{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.page-item.active .page-link{z-index:2;color:#fff;background-color:#0275d8;border-color:#0275d8}.page-item.disabled .page-link{color:#d5d5d5;pointer-events:none;cursor:not-allowed;background-color:#fff;border-color:#ddd}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#0275d8;background-color:#fff;border:1px solid #ddd}.page-link:focus,.page-link:hover{color:#014c8c;text-decoration:none;background-color:#eceeef;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-bottom-left-radius:.3rem;border-top-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-bottom-right-radius:.3rem;border-top-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-bottom-left-radius:.2rem;border-top-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-bottom-right-radius:.2rem;border-top-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-default{background-color:#d5d5d5}.badge-default[href]:focus,.badge-default[href]:hover{background-color:#bcbcbc}.badge-primary{background-color:#0275d8}.badge-primary[href]:focus,.badge-primary[href]:hover{background-color:#025aa5}.badge-success{background-color:#5cb85c}.badge-success[href]:focus,.badge-success[href]:hover{background-color:#449d44}.badge-info{background-color:#5bc0de}.badge-info[href]:focus,.badge-info[href]:hover{background-color:#31b0d5}.badge-warning{background-color:#f0ad4e}.badge-warning[href]:focus,.badge-warning[href]:hover{background-color:#ec971f}.badge-danger{background-color:#d9534f}.badge-danger[href]:focus,.badge-danger[href]:hover{background-color:#c9302c}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#eceeef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-hr{border-top-color:#d0d5d8}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible .close{position:relative;top:-.75rem;right:-1.25rem;padding:.75rem 1.25rem;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d0e9c6;color:#3c763d}.alert-success hr{border-top-color:#c1e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.alert-info hr{border-top-color:#a6d5ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faf2cc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7ecb5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebcccc;color:#a94442}.alert-danger hr{border-top-color:#e4b9b9}.alert-danger .alert-link{color:#843534}@keyframes progress-bar-stripes{0%{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;overflow:hidden;font-size:.75rem;line-height:1rem;text-align:center;background-color:#eceeef;border-radius:.25rem}.progress-bar{height:1rem;color:#fff;background-color:#0275d8}.progress-bar-striped{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 25%,transparent 50%,hsla(0,0%,100%,.15) 50%,hsla(0,0%,100%,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#55595c;text-align:inherit}.list-group-item-action .list-group-item-heading{color:#373a3c}.list-group-item-action:focus,.list-group-item-action:hover{color:#55595c;text-decoration:none;background-color:#f3f3f3}.list-group-item-action:active{color:#373a3c;background-color:#eceeef}.list-group-item{position:relative;display:flex;flex-flow:row wrap;align-items:center;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-right-radius:.25rem;border-top-left-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#d5d5d5;cursor:not-allowed;background-color:#fff}.list-group-item.disabled .list-group-item-heading,.list-group-item:disabled .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item:disabled .list-group-item-text{color:#d5d5d5}.list-group-item.active{z-index:2;color:#fff;background-color:#0275d8;border-color:#0275d8}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text{color:#daeeff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,button.list-group-item-success.active{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,button.list-group-item-info.active{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,button.list-group-item-warning.active{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,button.list-group-item-danger.active{color:#fff;background-color:#a94442;border-color:#a94442}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive:before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9:before{padding-top:42.85714%}.embed-responsive-16by9:before{padding-top:56.25%}.embed-responsive-4by3:before{padding-top:75%}.embed-responsive-1by1:before{padding-top:100%}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.75}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal,.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;outline:0}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -25%)}.modal.show .modal-dialog{transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;display:flex;flex-direction:column;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;align-items:center;justify-content:space-between;padding:15px;border-bottom:1px solid #eceeef}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:15px}.modal-footer{display:flex;align-items:center;justify-content:flex-end;padding:15px;border-top:1px solid #eceeef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:30px auto}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:50pc}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Open Sans;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip.bs-tether-element-attached-bottom,.tooltip.tooltip-top{padding:5px 0;margin-top:-3px}.tooltip.bs-tether-element-attached-bottom .tooltip-inner:before,.tooltip.tooltip-top .tooltip-inner:before{bottom:0;left:50%;margin-left:-5px;content:"";border-width:5px 5px 0;border-top-color:#000}.tooltip.bs-tether-element-attached-left,.tooltip.tooltip-right{padding:0 5px;margin-left:3px}.tooltip.bs-tether-element-attached-left .tooltip-inner:before,.tooltip.tooltip-right .tooltip-inner:before{top:50%;left:0;margin-top:-5px;content:"";border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.bs-tether-element-attached-top,.tooltip.tooltip-bottom{padding:5px 0;margin-top:3px}.tooltip.bs-tether-element-attached-top .tooltip-inner:before,.tooltip.tooltip-bottom .tooltip-inner:before{top:0;left:50%;margin-left:-5px;content:"";border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bs-tether-element-attached-right,.tooltip.tooltip-left{padding:0 5px;margin-left:-3px}.tooltip.bs-tether-element-attached-right .tooltip-inner:before,.tooltip.tooltip-left .tooltip-inner:before{top:50%;right:0;margin-top:-5px;content:"";border-width:5px 0 5px 5px;border-left-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.tooltip-inner:before{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;padding:1px;font-family:Open Sans;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover.bs-tether-element-attached-bottom,.popover.popover-top{margin-top:-10px}.popover.bs-tether-element-attached-bottom:after,.popover.bs-tether-element-attached-bottom:before,.popover.popover-top:after,.popover.popover-top:before{left:50%;border-bottom-width:0}.popover.bs-tether-element-attached-bottom:before,.popover.popover-top:before{bottom:-11px;margin-left:-11px;border-top-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-bottom:after,.popover.popover-top:after{bottom:-10px;margin-left:-10px;border-top-color:#fff}.popover.bs-tether-element-attached-left,.popover.popover-right{margin-left:10px}.popover.bs-tether-element-attached-left:after,.popover.bs-tether-element-attached-left:before,.popover.popover-right:after,.popover.popover-right:before{top:50%;border-left-width:0}.popover.bs-tether-element-attached-left:before,.popover.popover-right:before{left:-11px;margin-top:-11px;border-right-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-left:after,.popover.popover-right:after{left:-10px;margin-top:-10px;border-right-color:#fff}.popover.bs-tether-element-attached-top,.popover.popover-bottom{margin-top:10px}.popover.bs-tether-element-attached-top:after,.popover.bs-tether-element-attached-top:before,.popover.popover-bottom:after,.popover.popover-bottom:before{left:50%;border-top-width:0}.popover.bs-tether-element-attached-top:before,.popover.popover-bottom:before{top:-11px;margin-left:-11px;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-top:after,.popover.popover-bottom:after{top:-10px;margin-left:-10px;border-bottom-color:#f7f7f7}.popover.bs-tether-element-attached-top .popover-title:before,.popover.popover-bottom .popover-title:before{position:absolute;top:0;left:50%;display:block;width:20px;margin-left:-10px;content:"";border-bottom:1px solid #f7f7f7}.popover.bs-tether-element-attached-right,.popover.popover-left{margin-left:-10px}.popover.bs-tether-element-attached-right:after,.popover.bs-tether-element-attached-right:before,.popover.popover-left:after,.popover.popover-left:before{top:50%;border-right-width:0}.popover.bs-tether-element-attached-right:before,.popover.popover-left:before{right:-11px;margin-top:-11px;border-left-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-right:after,.popover.popover-left:after{right:-10px;margin-top:-10px;border-left-color:#fff}.popover-title{padding:8px 14px;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-right-radius:calc(.3rem - 1px);border-top-left-radius:calc(.3rem - 1px)}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover:after,.popover:before{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover:before{content:"";border-width:11px}.popover:after{content:"";border-width:10px}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;width:100%}@media (-webkit-transform-3d){.carousel-item{transition:transform .6s ease-in-out;backface-visibility:hidden;perspective:750pt}}@supports (transform:translate3d(0,0,0)){.carousel-item{transition:transform .6s ease-in-out;backface-visibility:hidden;perspective:750pt}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:flex}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}@media (-webkit-transform-3d){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translate3d(0,0,0)}.active.carousel-item-right,.carousel-item-next{transform:translate3d(100%,0,0)}.active.carousel-item-left,.carousel-item-prev{transform:translate3d(-100%,0,0)}}@supports (transform:translate3d(0,0,0)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translate3d(0,0,0)}.active.carousel-item-right,.carousel-item-next{transform:translate3d(100%,0,0)}.active.carousel-item-left,.carousel-item-prev{transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:flex;align-items:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M4 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;flex:1 0 auto;max-width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:hsla(0,0%,100%,.5)}.carousel-indicators li:before{top:-10px}.carousel-indicators li:after,.carousel-indicators li:before{position:absolute;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li:after{bottom:-10px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-faded{background-color:#f7f7f7}.bg-primary{background-color:#0275d8!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#025aa5!important}.bg-success{background-color:#5cb85c!important}a.bg-success:focus,a.bg-success:hover{background-color:#449d44!important}.bg-info{background-color:#5bc0de!important}a.bg-info:focus,a.bg-info:hover{background-color:#31b0d5!important}.bg-warning{background-color:#f0ad4e!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#ec971f!important}.bg-danger{background-color:#d9534f!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#c9302c!important}.bg-inverse{background-color:#373a3c!important}a.bg-inverse:focus,a.bg-inverse:hover{background-color:#1f2021!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.rounded{border-radius:.25rem}.rounded-top{border-top-left-radius:.25rem}.rounded-right,.rounded-top{border-top-right-radius:.25rem}.rounded-bottom,.rounded-right{border-bottom-right-radius:.25rem}.rounded-bottom,.rounded-left{border-bottom-left-radius:.25rem}.rounded-left{border-top-left-radius:.25rem}.rounded-circle{border-radius:50%}.rounded-0{border-radius:0}.clearfix:after{display:block;content:"";clear:both}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}.flex-first{order:-1}.flex-last{order:1}.flex-unordered{order:0}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:576px){.flex-sm-first{order:-1}.flex-sm-last{order:1}.flex-sm-unordered{order:0}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:768px){.flex-md-first{order:-1}.flex-md-last{order:1}.flex-md-unordered{order:0}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:992px){.flex-lg-first{order:-1}.flex-lg-last{order:1}.flex-lg-unordered{order:0}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1200px){.flex-xl-first{order:-1}.flex-xl-last{order:1}.flex-xl-unordered{order:0}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.fixed-top{top:0}.fixed-bottom,.fixed-top{position:fixed;right:0;left:0;z-index:1030}.fixed-bottom{bottom:0}.sticky-top{position:sticky;top:0;z-index:1030}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.mx-0{margin-right:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.25rem!important}.mt-1{margin-top:.25rem!important}.mr-1{margin-right:.25rem!important}.mb-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.mx-1{margin-right:.25rem!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-2{margin:.5rem!important}.mt-2{margin-top:.5rem!important}.mr-2{margin-right:.5rem!important}.mb-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.mx-2{margin-right:.5rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-3{margin:1rem!important}.mt-3{margin-top:1rem!important}.mr-3{margin-right:1rem!important}.mb-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.mx-3{margin-right:1rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-4{margin:1.5rem!important}.mt-4{margin-top:1.5rem!important}.mr-4{margin-right:1.5rem!important}.mb-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.mx-4{margin-right:1.5rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-5{margin:3rem!important}.mt-5{margin-top:3rem!important}.mr-5{margin-right:3rem!important}.mb-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.mx-5{margin-right:3rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.px-0{padding-right:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.25rem!important}.pt-1{padding-top:.25rem!important}.pr-1{padding-right:.25rem!important}.pb-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.px-1{padding-right:.25rem!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-2{padding:.5rem!important}.pt-2{padding-top:.5rem!important}.pr-2{padding-right:.5rem!important}.pb-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.px-2{padding-right:.5rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-3{padding:1rem!important}.pt-3{padding-top:1rem!important}.pr-3{padding-right:1rem!important}.pb-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.px-3{padding-right:1rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-4{padding:1.5rem!important}.pt-4{padding-top:1.5rem!important}.pr-4{padding-right:1.5rem!important}.pb-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.px-4{padding-right:1.5rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-5{padding:3rem!important}.pt-5{padding-top:3rem!important}.pr-5{padding-right:3rem!important}.pb-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.px-5{padding-right:3rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-auto{margin:auto!important}.mt-auto{margin-top:auto!important}.mr-auto{margin-right:auto!important}.mb-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}.mx-auto{margin-right:auto!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0{margin-top:0!important}.mr-sm-0{margin-right:0!important}.mb-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.mx-sm-0{margin-right:0!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1{margin-top:.25rem!important}.mr-sm-1{margin-right:.25rem!important}.mb-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.mx-sm-1{margin-right:.25rem!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2{margin-top:.5rem!important}.mr-sm-2{margin-right:.5rem!important}.mb-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.mx-sm-2{margin-right:.5rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3{margin-top:1rem!important}.mr-sm-3{margin-right:1rem!important}.mb-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.mx-sm-3{margin-right:1rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4{margin-top:1.5rem!important}.mr-sm-4{margin-right:1.5rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.mx-sm-4{margin-right:1.5rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5{margin-top:3rem!important}.mr-sm-5{margin-right:3rem!important}.mb-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.mx-sm-5{margin-right:3rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0{padding-top:0!important}.pr-sm-0{padding-right:0!important}.pb-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.px-sm-0{padding-right:0!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1{padding-top:.25rem!important}.pr-sm-1{padding-right:.25rem!important}.pb-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.px-sm-1{padding-right:.25rem!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2{padding-top:.5rem!important}.pr-sm-2{padding-right:.5rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.px-sm-2{padding-right:.5rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3{padding-top:1rem!important}.pr-sm-3{padding-right:1rem!important}.pb-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.px-sm-3{padding-right:1rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4{padding-top:1.5rem!important}.pr-sm-4{padding-right:1.5rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.px-sm-4{padding-right:1.5rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5{padding-top:3rem!important}.pr-sm-5{padding-right:3rem!important}.pb-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.px-sm-5{padding-right:3rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto{margin-top:auto!important}.mr-sm-auto{margin-right:auto!important}.mb-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}.mx-sm-auto{margin-right:auto!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0{margin-top:0!important}.mr-md-0{margin-right:0!important}.mb-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.mx-md-0{margin-right:0!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.m-md-1{margin:.25rem!important}.mt-md-1{margin-top:.25rem!important}.mr-md-1{margin-right:.25rem!important}.mb-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.mx-md-1{margin-right:.25rem!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2{margin-top:.5rem!important}.mr-md-2{margin-right:.5rem!important}.mb-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.mx-md-2{margin-right:.5rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3{margin-top:1rem!important}.mr-md-3{margin-right:1rem!important}.mb-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.mx-md-3{margin-right:1rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4{margin-top:1.5rem!important}.mr-md-4{margin-right:1.5rem!important}.mb-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.mx-md-4{margin-right:1.5rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5{margin-top:3rem!important}.mr-md-5{margin-right:3rem!important}.mb-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.mx-md-5{margin-right:3rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-md-0{padding:0!important}.pt-md-0{padding-top:0!important}.pr-md-0{padding-right:0!important}.pb-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.px-md-0{padding-right:0!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.p-md-1{padding:.25rem!important}.pt-md-1{padding-top:.25rem!important}.pr-md-1{padding-right:.25rem!important}.pb-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.px-md-1{padding-right:.25rem!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2{padding-top:.5rem!important}.pr-md-2{padding-right:.5rem!important}.pb-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.px-md-2{padding-right:.5rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3{padding-top:1rem!important}.pr-md-3{padding-right:1rem!important}.pb-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.px-md-3{padding-right:1rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4{padding-top:1.5rem!important}.pr-md-4{padding-right:1.5rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.px-md-4{padding-right:1.5rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5{padding-top:3rem!important}.pr-md-5{padding-right:3rem!important}.pb-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.px-md-5{padding-right:3rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto{margin-top:auto!important}.mr-md-auto{margin-right:auto!important}.mb-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}.mx-md-auto{margin-right:auto!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0{margin-top:0!important}.mr-lg-0{margin-right:0!important}.mb-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.mx-lg-0{margin-right:0!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1{margin-top:.25rem!important}.mr-lg-1{margin-right:.25rem!important}.mb-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.mx-lg-1{margin-right:.25rem!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2{margin-top:.5rem!important}.mr-lg-2{margin-right:.5rem!important}.mb-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.mx-lg-2{margin-right:.5rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3{margin-top:1rem!important}.mr-lg-3{margin-right:1rem!important}.mb-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.mx-lg-3{margin-right:1rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4{margin-top:1.5rem!important}.mr-lg-4{margin-right:1.5rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.mx-lg-4{margin-right:1.5rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5{margin-top:3rem!important}.mr-lg-5{margin-right:3rem!important}.mb-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.mx-lg-5{margin-right:3rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0{padding-top:0!important}.pr-lg-0{padding-right:0!important}.pb-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.px-lg-0{padding-right:0!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1{padding-top:.25rem!important}.pr-lg-1{padding-right:.25rem!important}.pb-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.px-lg-1{padding-right:.25rem!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2{padding-top:.5rem!important}.pr-lg-2{padding-right:.5rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.px-lg-2{padding-right:.5rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3{padding-top:1rem!important}.pr-lg-3{padding-right:1rem!important}.pb-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.px-lg-3{padding-right:1rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4{padding-top:1.5rem!important}.pr-lg-4{padding-right:1.5rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.px-lg-4{padding-right:1.5rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5{padding-top:3rem!important}.pr-lg-5{padding-right:3rem!important}.pb-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.px-lg-5{padding-right:3rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto{margin-top:auto!important}.mr-lg-auto{margin-right:auto!important}.mb-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}.mx-lg-auto{margin-right:auto!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0{margin-top:0!important}.mr-xl-0{margin-right:0!important}.mb-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.mx-xl-0{margin-right:0!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1{margin-top:.25rem!important}.mr-xl-1{margin-right:.25rem!important}.mb-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.mx-xl-1{margin-right:.25rem!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2{margin-top:.5rem!important}.mr-xl-2{margin-right:.5rem!important}.mb-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.mx-xl-2{margin-right:.5rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3{margin-top:1rem!important}.mr-xl-3{margin-right:1rem!important}.mb-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.mx-xl-3{margin-right:1rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4{margin-top:1.5rem!important}.mr-xl-4{margin-right:1.5rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.mx-xl-4{margin-right:1.5rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5{margin-top:3rem!important}.mr-xl-5{margin-right:3rem!important}.mb-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.mx-xl-5{margin-right:3rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0{padding-top:0!important}.pr-xl-0{padding-right:0!important}.pb-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.px-xl-0{padding-right:0!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1{padding-top:.25rem!important}.pr-xl-1{padding-right:.25rem!important}.pb-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.px-xl-1{padding-right:.25rem!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2{padding-top:.5rem!important}.pr-xl-2{padding-right:.5rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.px-xl-2{padding-right:.5rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3{padding-top:1rem!important}.pr-xl-3{padding-right:1rem!important}.pb-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.px-xl-3{padding-right:1rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4{padding-top:1.5rem!important}.pr-xl-4{padding-right:1.5rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.px-xl-4{padding-right:1.5rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5{padding-top:3rem!important}.pr-xl-5{padding-right:3rem!important}.pb-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.px-xl-5{padding-right:3rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto{margin-top:auto!important}.mr-xl-auto{margin-right:auto!important}.mb-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}.mx-xl-auto{margin-right:auto!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-white{color:#fff!important}.text-muted{color:#d5d5d5!important}a.text-muted:focus,a.text-muted:hover{color:#bcbcbc!important}.text-primary{color:#0275d8!important}a.text-primary:focus,a.text-primary:hover{color:#025aa5!important}.text-success{color:#5cb85c!important}a.text-success:focus,a.text-success:hover{color:#449d44!important}.text-info{color:#5bc0de!important}a.text-info:focus,a.text-info:hover{color:#31b0d5!important}.text-warning{color:#f0ad4e!important}a.text-warning:focus,a.text-warning:hover{color:#ec971f!important}.text-danger{color:#d9534f!important}a.text-danger:focus,a.text-danger:hover{color:#c9302c!important}.text-gray-dark{color:#373a3c!important}a.text-gray-dark:focus,a.text-gray-dark:hover{color:#1f2021!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.invisible{visibility:hidden!important}.hidden-xs-up{display:none!important}@media (max-width:575px){.hidden-xs-down{display:none!important}}@media (min-width:576px){.hidden-sm-up{display:none!important}}@media (max-width:767px){.hidden-sm-down{display:none!important}}@media (min-width:768px){.hidden-md-up{display:none!important}}@media (max-width:991px){.hidden-md-down{display:none!important}}@media (min-width:992px){.hidden-lg-up{display:none!important}}@media (max-width:1199px){.hidden-lg-down{display:none!important}}@media (min-width:1200px){.hidden-xl-up{display:none!important}}.hidden-xl-down,.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}.container-narrow{position:relative;margin-left:auto;margin-right:auto;padding-right:15px;padding-left:15px}@media (min-width:576px){.container-narrow{padding-right:15px;padding-left:15px}}@media (min-width:768px){.container-narrow{padding-right:15px;padding-left:15px}}@media (min-width:992px){.container-narrow{padding-right:15px;padding-left:15px}}@media (min-width:1200px){.container-narrow{padding-right:15px;padding-left:15px}}@media (min-width:576px){.container-narrow{max-width:34rem}}@media (min-width:768px){.container-narrow{max-width:45rem}}@media (min-width:992px){.container-narrow{max-width:45rem}}@media (min-width:1200px){.container-narrow{max-width:45rem}}.nav-underline .nav-item.active,.nav-underline .nav-item.active:hover{box-shadow:0 -3px 0 0 #0275d8 inset}.nav-underline .nav-item.active .nav-link,.nav-underline .nav-item.active:hover .nav-link{color:#0275d8}.nav-underline li:hover{box-shadow:0 -3px 0 0 #ddd inset}.nav-underline li{padding-top:.2rem;padding-bottom:.2rem}.navbar-underline{background-color:#d5d5d5;border-top:1px solid #c8c8c8}pre{background-color:#fdf6e3;padding:1rem}.table-expand-col{min-width:100%}body{background-color:#373a3c}.card-success{background-color:#dff0d8;border-color:#d0e9c6;color:#3c763d}.card-success hr{border-top-color:#c1e2b3}.card-success .alert-link{color:#2b542c}.card-success .card-header{background-color:#d0e9c6;border-bottom:1px solid #c1e2b3}.card-info{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.card-info hr{border-top-color:#a6d5ec}.card-info .alert-link{color:#245269}.card-info .card-header{background-color:#c4e3f3;border-bottom:1px solid #afd9ee}.card-primary{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.card-primary hr{border-top-color:#a6d5ec}.card-primary .alert-link{color:#245269}.card-primary .card-header{background-color:#c4e3f3;border-bottom:1px solid #afd9ee}.card-warning{background-color:#fcf8e3;border-color:#faf2cc;color:#8a6d3b}.card-warning hr{border-top-color:#f7ecb5}.card-warning .alert-link{color:#66512c}.card-warning .card-header{background-color:#faf2cc;border-bottom:1px solid #f7ecb5}.card-danger{background-color:#f2dede;border-color:#ebcccc;color:#a94442}.card-danger hr{border-top-color:#e4b9b9}.card-danger .alert-link{color:#843534}.card-danger .card-header{background-color:#ebcccc;border-bottom:1px solid #e4b9b9}.masthead{background-image:linear-gradient(to bottom,#eee 0%,#ddd 100%);background-repeat:repeat-x;padding-top:10px;padding-bottom:10px}.subheader{background:#f3f3f3;border-bottom:1px solid #d5d5d5}.subheader .nav-tabs{margin-bottom:-1px}.footer{background-color:#373a3c}.bodycontent{background:#fff}.document-docutils>.section{padding-bottom:1rem}.document-docutils pre .comment{color:#586e75}.document-docutils pre .error,.document-docutils pre .generic{color:#93a1a1}.document-docutils pre .keyword{color:#859900}.document-docutils pre .literal,.document-docutils pre .name{color:#93a1a1}.document-docutils pre .operator{color:#859900}.document-docutils pre .other{color:#cb4b16}.document-docutils pre .punctuation{color:#93a1a1}.document-docutils pre .comment.multiline{color:#586e75}.document-docutils pre .comment.preproc{color:#859900}.document-docutils pre .comment.single{color:#586e75}.document-docutils pre .comment.special{color:#859900}.document-docutils pre .generic.deleted{color:#2aa198}.document-docutils pre .generic.emph{color:#93a1a1;font-style:italic}.document-docutils pre .generic.error{color:#dc322f}.document-docutils pre .generic.heading{color:#cb4b16}.document-docutils pre .generic.inserted{color:#859900}.document-docutils pre .generic.output,.document-docutils pre .generic.prompt{color:#93a1a1}.document-docutils pre .generic.strong{color:#93a1a1;font-weight:700}.document-docutils pre .generic.subheading{color:#cb4b16}.document-docutils pre .generic.traceback{color:#93a1a1}.document-docutils pre .keyword.constant{color:#cb4b16}.document-docutils pre .keyword.declaration{color:#268bd2}.document-docutils pre .keyword.namespace,.document-docutils pre .keyword.pseudo{color:#859900}.document-docutils pre .keyword.reserved{color:#268bd2}.document-docutils pre .keyword.type{color:#dc322f}.document-docutils pre .literal.date{color:#93a1a1}.document-docutils pre .literal.number,.document-docutils pre .literal.string{color:#2aa198}.document-docutils pre .name.attribute{color:#93a1a1}.document-docutils pre .name.builtin{color:#b58900}.document-docutils pre .name.class{color:#268bd2}.document-docutils pre .name.constant{color:#cb4b16}.document-docutils pre .name.decorator{color:#268bd2}.document-docutils pre .name.entity,.document-docutils pre .name.exception{color:#cb4b16}.document-docutils pre .name.function{color:#268bd2}.document-docutils pre .name.label,.document-docutils pre .name.namespace,.document-docutils pre .name.other,.document-docutils pre .name.property{color:#93a1a1}.document-docutils pre .name.tag,.document-docutils pre .name.variable{color:#268bd2}.document-docutils pre .operator.word{color:#859900}.document-docutils pre .text.whitespace{color:#93a1a1}.document-docutils pre .literal.number.float,.document-docutils pre .literal.number.hex,.document-docutils pre .literal.number.integer,.document-docutils pre .literal.number.oct{color:#2aa198}.document-docutils pre .literal.string.backtick{color:#586e75}.document-docutils pre .literal.string.char{color:#2aa198}.document-docutils pre .literal.string.doc{color:#93a1a1}.document-docutils pre .literal.string.double{color:#2aa198}.document-docutils pre .literal.string.escape{color:#cb4b16}.document-docutils pre .literal.string.heredoc{color:#93a1a1}.document-docutils pre .literal.string.interpol,.document-docutils pre .literal.string.other{color:#2aa198}.document-docutils pre .literal.string.regex{color:#dc322f}.document-docutils pre .literal.string.single,.document-docutils pre .literal.string.symbol{color:#2aa198}.document-docutils pre .name.builtin.pseudo,.document-docutils pre .name.variable.class,.document-docutils pre .name.variable.global,.document-docutils pre .name.variable.instance{color:#268bd2}.document-docutils pre .literal.number.integer.long{color:#2aa198}
\ No newline at end of file
diff --git a/hubs/static/fedora-bootstrap/fedora-bootstrap.min.js b/hubs/static/fedora-bootstrap/fedora-bootstrap.min.js
new file mode 100644
index 0000000..3624839
--- /dev/null
+++ b/hubs/static/fedora-bootstrap/fedora-bootstrap.min.js
@@ -0,0 +1,8 @@
+!function(t){function e(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return t[i].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";n(1),n(2),n(3)},function(t,e,n){var i,o;/*! tether 1.4.0 */
+!function(r,s){i=s,o="function"==typeof i?i.call(e,n,e,t):i,!(void 0!==o&&(t.exports=o))}(this,function(t,e,n){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t){var e=t.getBoundingClientRect(),n={};for(var i in e)n[i]=e[i];if(t.ownerDocument!==document){var r=t.ownerDocument.defaultView.frameElement;if(r){var s=o(r);n.top+=s.top,n.bottom+=s.top,n.left+=s.left,n.right+=s.left}}return n}function r(t){var e=getComputedStyle(t)||{},n=e.position,i=[];if("fixed"===n)return[t];for(var o=t;(o=o.parentNode)&&o&&1===o.nodeType;){var r=void 0;try{r=getComputedStyle(o)}catch(t){}if("undefined"==typeof r||null===r)return i.push(o),i;var s=r,a=s.overflow,l=s.overflowX,h=s.overflowY;/(auto|scroll)/.test(a+h+l)&&("absolute"!==n||["relative","absolute","fixed"].indexOf(r.position)>=0)&&i.push(o)}return i.push(t.ownerDocument.body),t.ownerDocument!==document&&i.push(t.ownerDocument.defaultView),i}function s(){b&&document.body.removeChild(b),b=null}function a(t){var e=void 0;t===document?(e=document,t=document.documentElement):e=t.ownerDocument;var n=e.documentElement,i=o(t),r=D();return i.top-=r.top,i.left-=r.left,"undefined"==typeof i.width&&(i.width=document.body.scrollWidth-i.left-i.right),"undefined"==typeof i.height&&(i.height=document.body.scrollHeight-i.top-i.bottom),i.top=i.top-n.clientTop,i.left=i.left-n.clientLeft,i.right=e.body.clientWidth-i.width-i.left,i.bottom=e.body.clientHeight-i.height-i.top,i}function l(t){return t.offsetParent||document.documentElement}function h(){if(w)return w;var t=document.createElement("div");t.style.width="100%",t.style.height="200px";var e=document.createElement("div");f(e.style,{position:"absolute",top:0,left:0,pointerEvents:"none",visibility:"hidden",width:"200px",height:"150px",overflow:"hidden"}),e.appendChild(t),document.body.appendChild(e);var n=t.offsetWidth;e.style.overflow="scroll";var i=t.offsetWidth;n===i&&(i=e.clientWidth),document.body.removeChild(e);var o=n-i;return w={width:o,height:o}}function f(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],e=[];return Array.prototype.push.apply(e,arguments),e.slice(1).forEach(function(e){if(e)for(var n in e)({}).hasOwnProperty.call(e,n)&&(t[n]=e[n])}),t}function u(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.remove(e)});else{var n=new RegExp("(^| )"+e.split(" ").join("|")+"( |$)","gi"),i=p(t).replace(n," ");g(t,i)}}function c(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.add(e)});else{u(t,e);var n=p(t)+(" "+e);g(t,n)}}function d(t,e){if("undefined"!=typeof t.classList)return t.classList.contains(e);var n=p(t);return new RegExp("(^| )"+e+"( |$)","gi").test(n)}function p(t){return t.className instanceof t.ownerDocument.defaultView.SVGAnimatedString?t.className.baseVal:t.className}function g(t,e){t.setAttribute("class",e)}function m(t,e,n){n.forEach(function(n){e.indexOf(n)===-1&&d(t,n)&&u(t,n)}),e.forEach(function(e){d(t,e)||c(t,e)})}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function _(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function v(t,e){var n=arguments.length<=2||void 0===arguments[2]?1:arguments[2];return t+n>=e&&e>=t-n}function E(){return"undefined"!=typeof performance&&"undefined"!=typeof performance.now?performance.now():+new Date}function y(){for(var t={top:0,left:0},e=arguments.length,n=Array(e),i=0;i<e;i++)n[i]=arguments[i];return n.forEach(function(e){var n=e.top,i=e.left;"string"==typeof n&&(n=parseFloat(n,10)),"string"==typeof i&&(i=parseFloat(i,10)),t.top+=n,t.left+=i}),t}function T(t,e){return"string"==typeof t.left&&t.left.indexOf("%")!==-1&&(t.left=parseFloat(t.left,10)/100*e.width),"string"==typeof t.top&&t.top.indexOf("%")!==-1&&(t.top=parseFloat(t.top,10)/100*e.height),t}function C(t,e){return"scrollParent"===e?e=t.scrollParents[0]:"window"===e&&(e=[pageXOffset,pageYOffset,innerWidth+pageXOffset,innerHeight+pageYOffset]),e===document&&(e=e.documentElement),"undefined"!=typeof e.nodeType&&!function(){var t=e,n=a(e),i=n,o=getComputedStyle(e);if(e=[i.left,i.top,n.width+i.left,n.height+i.top],t.ownerDocument!==document){var r=t.ownerDocument.defaultView;e[0]+=r.pageXOffset,e[1]+=r.pageYOffset,e[2]+=r.pageXOffset,e[3]+=r.pageYOffset}z.forEach(function(t,n){t=t[0].toUpperCase()+t.substr(1),"Top"===t||"Left"===t?e[n]+=parseFloat(o["border"+t+"Width"]):e[n]-=parseFloat(o["border"+t+"Width"])})}(),e}var A=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),O=void 0;"undefined"==typeof O&&(O={modules:[]});var b=null,I=function(){var t=0;return function(){return++t}}(),S={},D=function(){var t=b;t&&document.body.contains(t)||(t=document.createElement("div"),t.setAttribute("data-tether-id",I()),f(t.style,{top:0,left:0,position:"absolute"}),document.body.appendChild(t),b=t);var e=t.getAttribute("data-tether-id");return"undefined"==typeof S[e]&&(S[e]=o(t),L(function(){delete S[e]})),S[e]},w=null,N=[],L=function(t){N.push(t)},P=function(){for(var t=void 0;t=N.pop();)t()},H=function(){function t(){i(this,t)}return A(t,[{key:"on",value:function(t,e,n){var i=!(arguments.length<=3||void 0===arguments[3])&&arguments[3];"undefined"==typeof this.bindings&&(this.bindings={}),"undefined"==typeof this.bindings[t]&&(this.bindings[t]=[]),this.bindings[t].push({handler:e,ctx:n,once:i})}},{key:"once",value:function(t,e,n){this.on(t,e,n,!0)}},{key:"off",value:function(t,e){if("undefined"!=typeof this.bindings&&"undefined"!=typeof this.bindings[t])if("undefined"==typeof e)delete this.bindings[t];else for(var n=0;n<this.bindings[t].length;)this.bindings[t][n].handler===e?this.bindings[t].splice(n,1):++n}},{key:"trigger",value:function(t){if("undefined"!=typeof this.bindings&&this.bindings[t]){for(var e=0,n=arguments.length,i=Array(n>1?n-1:0),o=1;o<n;o++)i[o-1]=arguments[o];for(;e<this.bindings[t].length;){var r=this.bindings[t][e],s=r.handler,a=r.ctx,l=r.once,h=a;"undefined"==typeof h&&(h=this),s.apply(h,i),l?this.bindings[t].splice(e,1):++e}}}}]),t}();O.Utils={getActualBoundingClientRect:o,getScrollParents:r,getBounds:a,getOffsetParent:l,extend:f,addClass:c,removeClass:u,hasClass:d,updateClasses:m,defer:L,flush:P,uniqueId:I,Evented:H,getScrollBarSize:h,removeUtilElements:s};var k=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{!i&&a.return&&a.return()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),A=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),W=function(t,e,n){for(var i=!0;i;){var o=t,r=e,s=n;i=!1,null===o&&(o=Function.prototype);var a=Object.getOwnPropertyDescriptor(o,r);if(void 0!==a){if("value"in a)return a.value;var l=a.get;if(void 0===l)return;return l.call(s)}var h=Object.getPrototypeOf(o);if(null===h)return;t=h,e=r,n=s,i=!0,a=h=void 0}};if("undefined"==typeof O)throw new Error("You must include the utils.js file before tether.js");var R=O.Utils,r=R.getScrollParents,a=R.getBounds,l=R.getOffsetParent,f=R.extend,c=R.addClass,u=R.removeClass,m=R.updateClasses,L=R.defer,P=R.flush,h=R.getScrollBarSize,s=R.removeUtilElements,x=function(){if("undefined"==typeof document)return"";for(var t=document.createElement("div"),e=["transform","WebkitTransform","OTransform","MozTransform","msTransform"],n=0;n<e.length;++n){var i=e[n];if(void 0!==t.style[i])return i}}(),M=[],V=function(){M.forEach(function(t){t.position(!1)}),P()};!function(){var t=null,e=null,n=null,i=function i(){return"undefined"!=typeof e&&e>16?(e=Math.min(e-16,250),void(n=setTimeout(i,250))):void("undefined"!=typeof t&&E()-t<10||(null!=n&&(clearTimeout(n),n=null),t=E(),V(),e=E()-t))};"undefined"!=typeof window&&"undefined"!=typeof window.addEventListener&&["resize","scroll","touchmove"].forEach(function(t){window.addEventListener(t,i)})}();var j={center:"center",left:"right",right:"left"},F={middle:"middle",top:"bottom",bottom:"top"},U={top:0,left:0,middle:"50%",center:"50%",bottom:"100%",right:"100%"},B=function(t,e){var n=t.left,i=t.top;return"auto"===n&&(n=j[e.left]),"auto"===i&&(i=F[e.top]),{left:n,top:i}},K=function(t){var e=t.left,n=t.top;return"undefined"!=typeof U[t.left]&&(e=U[t.left]),"undefined"!=typeof U[t.top]&&(n=U[t.top]),{left:e,top:n}},G=function(t){var e=t.split(" "),n=k(e,2),i=n[0],o=n[1];return{top:i,left:o}},Q=G,Y=function(t){function e(t){var n=this;i(this,e),W(Object.getPrototypeOf(e.prototype),"constructor",this).call(this),this.position=this.position.bind(this),M.push(this),this.history=[],this.setOptions(t,!1),O.modules.forEach(function(t){"undefined"!=typeof t.initialize&&t.initialize.call(n)}),this.position()}return _(e,t),A(e,[{key:"getClass",value:function(){var t=arguments.length<=0||void 0===arguments[0]?"":arguments[0],e=this.options.classes;return"undefined"!=typeof e&&e[t]?this.options.classes[t]:this.options.classPrefix?this.options.classPrefix+"-"+t:t}},{key:"setOptions",value:function(t){var e=this,n=arguments.length<=1||void 0===arguments[1]||arguments[1],i={offset:"0 0",targetOffset:"0 0",targetAttachment:"auto auto",classPrefix:"tether"};this.options=f(i,t);var o=this.options,s=o.element,a=o.target,l=o.targetModifier;if(this.element=s,this.target=a,this.targetModifier=l,"viewport"===this.target?(this.target=document.body,this.targetModifier="visible"):"scroll-handle"===this.target&&(this.target=document.body,this.targetModifier="scroll-handle"),["element","target"].forEach(function(t){if("undefined"==typeof e[t])throw new Error("Tether Error: Both element and target must be defined");"undefined"!=typeof e[t].jquery?e[t]=e[t][0]:"string"==typeof e[t]&&(e[t]=document.querySelector(e[t]))}),c(this.element,this.getClass("element")),this.options.addTargetClasses!==!1&&c(this.target,this.getClass("target")),!this.options.attachment)throw new Error("Tether Error: You must provide an attachment");this.targetAttachment=Q(this.options.targetAttachment),this.attachment=Q(this.options.attachment),this.offset=G(this.options.offset),this.targetOffset=G(this.options.targetOffset),"undefined"!=typeof this.scrollParents&&this.disable(),"scroll-handle"===this.targetModifier?this.scrollParents=[this.target]:this.scrollParents=r(this.target),this.options.enabled!==!1&&this.enable(n)}},{key:"getTargetBounds",value:function(){if("undefined"==typeof this.targetModifier)return a(this.target);if("visible"===this.targetModifier){if(this.target===document.body)return{top:pageYOffset,left:pageXOffset,height:innerHeight,width:innerWidth};var t=a(this.target),e={height:t.height,width:t.width,top:t.top,left:t.left};return e.height=Math.min(e.height,t.height-(pageYOffset-t.top)),e.height=Math.min(e.height,t.height-(t.top+t.height-(pageYOffset+innerHeight))),e.height=Math.min(innerHeight,e.height),e.height-=2,e.width=Math.min(e.width,t.width-(pageXOffset-t.left)),e.width=Math.min(e.width,t.width-(t.left+t.width-(pageXOffset+innerWidth))),e.width=Math.min(innerWidth,e.width),e.width-=2,e.top<pageYOffset&&(e.top=pageYOffset),e.left<pageXOffset&&(e.left=pageXOffset),e}if("scroll-handle"===this.targetModifier){var t=void 0,n=this.target;n===document.body?(n=document.documentElement,t={left:pageXOffset,top:pageYOffset,height:innerHeight,width:innerWidth}):t=a(n);var i=getComputedStyle(n),o=n.scrollWidth>n.clientWidth||[i.overflow,i.overflowX].indexOf("scroll")>=0||this.target!==document.body,r=0;o&&(r=15);var s=t.height-parseFloat(i.borderTopWidth)-parseFloat(i.borderBottomWidth)-r,e={width:15,height:.975*s*(s/n.scrollHeight),left:t.left+t.width-parseFloat(i.borderLeftWidth)-15},l=0;s<408&&this.target===document.body&&(l=-11e-5*Math.pow(s,2)-.00727*s+22.58),this.target!==document.body&&(e.height=Math.max(e.height,24));var h=this.target.scrollTop/(n.scrollHeight-s);return e.top=h*(s-e.height-l)+t.top+parseFloat(i.borderTopWidth),this.target===document.body&&(e.height=Math.max(e.height,24)),e}}},{key:"clearCache",value:function(){this._cache={}}},{key:"cache",value:function(t,e){return"undefined"==typeof this._cache&&(this._cache={}),"undefined"==typeof this._cache[t]&&(this._cache[t]=e.call(this)),this._cache[t]}},{key:"enable",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]||arguments[0];this.options.addTargetClasses!==!1&&c(this.target,this.getClass("enabled")),c(this.element,this.getClass("enabled")),this.enabled=!0,this.scrollParents.forEach(function(e){e!==t.target.ownerDocument&&e.addEventListener("scroll",t.position)}),e&&this.position()}},{key:"disable",value:function(){var t=this;u(this.target,this.getClass("enabled")),u(this.element,this.getClass("enabled")),this.enabled=!1,"undefined"!=typeof this.scrollParents&&this.scrollParents.forEach(function(e){e.removeEventListener("scroll",t.position)})}},{key:"destroy",value:function(){var t=this;this.disable(),M.forEach(function(e,n){e===t&&M.splice(n,1)}),0===M.length&&s()}},{key:"updateAttachClasses",value:function(t,e){var n=this;t=t||this.attachment,e=e||this.targetAttachment;var i=["left","top","bottom","right","middle","center"];"undefined"!=typeof this._addAttachClasses&&this._addAttachClasses.length&&this._addAttachClasses.splice(0,this._addAttachClasses.length),"undefined"==typeof this._addAttachClasses&&(this._addAttachClasses=[]);var o=this._addAttachClasses;t.top&&o.push(this.getClass("element-attached")+"-"+t.top),t.left&&o.push(this.getClass("element-attached")+"-"+t.left),e.top&&o.push(this.getClass("target-attached")+"-"+e.top),e.left&&o.push(this.getClass("target-attached")+"-"+e.left);var r=[];i.forEach(function(t){r.push(n.getClass("element-attached")+"-"+t),r.push(n.getClass("target-attached")+"-"+t)}),L(function(){"undefined"!=typeof n._addAttachClasses&&(m(n.element,n._addAttachClasses,r),n.options.addTargetClasses!==!1&&m(n.target,n._addAttachClasses,r),delete n._addAttachClasses)})}},{key:"position",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]||arguments[0];if(this.enabled){this.clearCache();var n=B(this.targetAttachment,this.attachment);this.updateAttachClasses(this.attachment,n);var i=this.cache("element-bounds",function(){return a(t.element)}),o=i.width,r=i.height;if(0===o&&0===r&&"undefined"!=typeof this.lastSize){var s=this.lastSize;o=s.width,r=s.height}else this.lastSize={width:o,height:r};var f=this.cache("target-bounds",function(){return t.getTargetBounds()}),u=f,c=T(K(this.attachment),{width:o,height:r}),d=T(K(n),u),p=T(this.offset,{width:o,height:r}),g=T(this.targetOffset,u);c=y(c,p),d=y(d,g);for(var m=f.left+d.left-c.left,_=f.top+d.top-c.top,v=0;v<O.modules.length;++v){var E=O.modules[v],C=E.position.call(this,{left:m,top:_,targetAttachment:n,targetPos:f,elementPos:i,offset:c,targetOffset:d,manualOffset:p,manualTargetOffset:g,scrollbarSize:S,attachment:this.attachment});if(C===!1)return!1;"undefined"!=typeof C&&"object"==typeof C&&(_=C.top,m=C.left)}var A={page:{top:_,left:m},viewport:{top:_-pageYOffset,bottom:pageYOffset-_-r+innerHeight,left:m-pageXOffset,right:pageXOffset-m-o+innerWidth}},b=this.target.ownerDocument,I=b.defaultView,S=void 0;return I.innerHeight>b.documentElement.clientHeight&&(S=this.cache("scrollbar-size",h),A.viewport.bottom-=S.height),I.innerWidth>b.documentElement.clientWidth&&(S=this.cache("scrollbar-size",h),A.viewport.right-=S.width),["","static"].indexOf(b.body.style.position)!==-1&&["","static"].indexOf(b.body.parentElement.style.position)!==-1||(A.page.bottom=b.body.scrollHeight-_-r,A.page.right=b.body.scrollWidth-m-o),"undefined"!=typeof this.options.optimizations&&this.options.optimizations.moveElement!==!1&&"undefined"==typeof this.targetModifier&&!function(){var e=t.cache("target-offsetparent",function(){return l(t.target)}),n=t.cache("target-offsetparent-bounds",function(){return a(e)}),i=getComputedStyle(e),o=n,r={};if(["Top","Left","Bottom","Right"].forEach(function(t){r[t.toLowerCase()]=parseFloat(i["border"+t+"Width"])}),n.right=b.body.scrollWidth-n.left-o.width+r.right,n.bottom=b.body.scrollHeight-n.top-o.height+r.bottom,A.page.top>=n.top+r.top&&A.page.bottom>=n.bottom&&A.page.left>=n.left+r.left&&A.page.right>=n.right){var s=e.scrollTop,h=e.scrollLeft;A.offset={top:A.page.top-n.top+s-r.top,left:A.page.left-n.left+h-r.left}}}(),this.move(A),this.history.unshift(A),this.history.length>3&&this.history.pop(),e&&P(),!0}}},{key:"move",value:function(t){var e=this;if("undefined"!=typeof this.element.parentNode){var n={};for(var i in t){n[i]={};for(var o in t[i]){for(var r=!1,s=0;s<this.history.length;++s){var a=this.history[s];if("undefined"!=typeof a[i]&&!v(a[i][o],t[i][o])){r=!0;break}}r||(n[i][o]=!0)}}var h={top:"",left:"",right:"",bottom:""},u=function(t,n){var i="undefined"!=typeof e.options.optimizations,o=i?e.options.optimizations.gpu:null;if(o!==!1){var r=void 0,s=void 0;if(t.top?(h.top=0,r=n.top):(h.bottom=0,r=-n.bottom),t.left?(h.left=0,s=n.left):(h.right=0,s=-n.right),window.matchMedia){var a=window.matchMedia("only screen and (min-resolution: 1.3dppx)").matches||window.matchMedia("only screen and (-webkit-min-device-pixel-ratio: 1.3)").matches;a||(s=Math.round(s),r=Math.round(r))}h[x]="translateX("+s+"px) translateY("+r+"px)","msTransform"!==x&&(h[x]+=" translateZ(0)")}else t.top?h.top=n.top+"px":h.bottom=n.bottom+"px",t.left?h.left=n.left+"px":h.right=n.right+"px"},c=!1;if((n.page.top||n.page.bottom)&&(n.page.left||n.page.right)?(h.position="absolute",u(n.page,t.page)):(n.viewport.top||n.viewport.bottom)&&(n.viewport.left||n.viewport.right)?(h.position="fixed",u(n.viewport,t.viewport)):"undefined"!=typeof n.offset&&n.offset.top&&n.offset.left?!function(){h.position="absolute";var i=e.cache("target-offsetparent",function(){return l(e.target)});l(e.element)!==i&&L(function(){e.element.parentNode.removeChild(e.element),i.appendChild(e.element)}),u(n.offset,t.offset),c=!0}():(h.position="absolute",u({top:!0,left:!0},t.page)),!c)if(this.options.bodyElement)this.options.bodyElement.appendChild(this.element);else{for(var d=!0,p=this.element.parentNode;p&&1===p.nodeType&&"BODY"!==p.tagName;){if("static"!==getComputedStyle(p).position){d=!1;break}p=p.parentNode}d||(this.element.parentNode.removeChild(this.element),this.element.ownerDocument.body.appendChild(this.element))}var g={},m=!1;for(var o in h){var _=h[o],E=this.element.style[o];E!==_&&(m=!0,g[o]=_)}m&&L(function(){f(e.element.style,g),e.trigger("repositioned")})}}}]),e}(H);Y.modules=[],O.position=V;var X=f(Y,O),k=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{!i&&a.return&&a.return()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),R=O.Utils,a=R.getBounds,f=R.extend,m=R.updateClasses,L=R.defer,z=["left","top","right","bottom"];O.modules.push({position:function(t){var e=this,n=t.top,i=t.left,o=t.targetAttachment;if(!this.options.constraints)return!0;var r=this.cache("element-bounds",function(){return a(e.element)}),s=r.height,l=r.width;if(0===l&&0===s&&"undefined"!=typeof this.lastSize){var h=this.lastSize;l=h.width,s=h.height}var u=this.cache("target-bounds",function(){return e.getTargetBounds()}),c=u.height,d=u.width,p=[this.getClass("pinned"),this.getClass("out-of-bounds")];this.options.constraints.forEach(function(t){var e=t.outOfBoundsClass,n=t.pinnedClass;e&&p.push(e),n&&p.push(n)}),p.forEach(function(t){["left","top","right","bottom"].forEach(function(e){p.push(t+"-"+e)})});var g=[],_=f({},o),v=f({},this.attachment);return this.options.constraints.forEach(function(t){var r=t.to,a=t.attachment,h=t.pin;"undefined"==typeof a&&(a="");var f=void 0,u=void 0;if(a.indexOf(" ")>=0){var p=a.split(" "),m=k(p,2);u=m[0],f=m[1]}else f=u=a;var E=C(e,r);"target"!==u&&"both"!==u||(n<E[1]&&"top"===_.top&&(n+=c,_.top="bottom"),n+s>E[3]&&"bottom"===_.top&&(n-=c,_.top="top")),"together"===u&&("top"===_.top&&("bottom"===v.top&&n<E[1]?(n+=c,_.top="bottom",n+=s,v.top="top"):"top"===v.top&&n+s>E[3]&&n-(s-c)>=E[1]&&(n-=s-c,_.top="bottom",v.top="bottom")),"bottom"===_.top&&("top"===v.top&&n+s>E[3]?(n-=c,_.top="top",n-=s,v.top="bottom"):"bottom"===v.top&&n<E[1]&&n+(2*s-c)<=E[3]&&(n+=s-c,_.top="top",v.top="top")),"middle"===_.top&&(n+s>E[3]&&"top"===v.top?(n-=s,v.top="bottom"):n<E[1]&&"bottom"===v.top&&(n+=s,v.top="top"))),"target"!==f&&"both"!==f||(i<E[0]&&"left"===_.left&&(i+=d,_.left="right"),i+l>E[2]&&"right"===_.left&&(i-=d,_.left="left")),"together"===f&&(i<E[0]&&"left"===_.left?"right"===v.left?(i+=d,_.left="right",i+=l,v.left="left"):"left"===v.left&&(i+=d,_.left="right",i-=l,v.left="right"):i+l>E[2]&&"right"===_.left?"left"===v.left?(i-=d,_.left="left",i-=l,v.left="right"):"right"===v.left&&(i-=d,_.left="left",i+=l,v.left="left"):"center"===_.left&&(i+l>E[2]&&"left"===v.left?(i-=l,v.left="right"):i<E[0]&&"right"===v.left&&(i+=l,v.left="left"))),"element"!==u&&"both"!==u||(n<E[1]&&"bottom"===v.top&&(n+=s,v.top="top"),n+s>E[3]&&"top"===v.top&&(n-=s,v.top="bottom")),"element"!==f&&"both"!==f||(i<E[0]&&("right"===v.left?(i+=l,v.left="left"):"center"===v.left&&(i+=l/2,v.left="left")),i+l>E[2]&&("left"===v.left?(i-=l,v.left="right"):"center"===v.left&&(i-=l/2,v.left="right"))),"string"==typeof h?h=h.split(",").map(function(t){return t.trim()}):h===!0&&(h=["top","left","right","bottom"]),h=h||[];var y=[],T=[];n<E[1]&&(h.indexOf("top")>=0?(n=E[1],y.push("top")):T.push("top")),n+s>E[3]&&(h.indexOf("bottom")>=0?(n=E[3]-s,y.push("bottom")):T.push("bottom")),i<E[0]&&(h.indexOf("left")>=0?(i=E[0],y.push("left")):T.push("left")),i+l>E[2]&&(h.indexOf("right")>=0?(i=E[2]-l,y.push("right")):T.push("right")),y.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.pinnedClass?e.options.pinnedClass:e.getClass("pinned"),g.push(t),y.forEach(function(e){g.push(t+"-"+e)})}(),T.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.outOfBoundsClass?e.options.outOfBoundsClass:e.getClass("out-of-bounds"),g.push(t),T.forEach(function(e){g.push(t+"-"+e)})}(),(y.indexOf("left")>=0||y.indexOf("right")>=0)&&(v.left=_.left=!1),(y.indexOf("top")>=0||y.indexOf("bottom")>=0)&&(v.top=_.top=!1),_.top===o.top&&_.left===o.left&&v.top===e.attachment.top&&v.left===e.attachment.left||(e.updateAttachClasses(v,_),e.trigger("update",{attachment:v,targetAttachment:_}))}),L(function(){e.options.addTargetClasses!==!1&&m(e.target,g,p),m(e.element,g,p)}),{top:n,left:i}}});var R=O.Utils,a=R.getBounds,m=R.updateClasses,L=R.defer;O.modules.push({position:function(t){var e=this,n=t.top,i=t.left,o=this.cache("element-bounds",function(){return a(e.element)}),r=o.height,s=o.width,l=this.getTargetBounds(),h=n+r,f=i+s,u=[];n<=l.bottom&&h>=l.top&&["left","right"].forEach(function(t){var e=l[t];e!==i&&e!==f||u.push(t)}),i<=l.right&&f>=l.left&&["top","bottom"].forEach(function(t){var e=l[t];e!==n&&e!==h||u.push(t)});var c=[],d=[],p=["left","top","right","bottom"];return c.push(this.getClass("abutted")),p.forEach(function(t){c.push(e.getClass("abutted")+"-"+t)}),u.length&&d.push(this.getClass("abutted")),u.forEach(function(t){d.push(e.getClass("abutted")+"-"+t)}),L(function(){e.options.addTargetClasses!==!1&&m(e.target,d,c),m(e.element,d,c)}),!0}});var k=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{!i&&a.return&&a.return()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();return O.modules.push({position:function(t){var e=t.top,n=t.left;if(this.options.shift){var i=this.options.shift;"function"==typeof this.options.shift&&(i=this.options.shift.call(this,{top:e,left:n}));var o=void 0,r=void 0;if("string"==typeof i){i=i.split(" "),i[1]=i[1]||i[0];var s=i,a=k(s,2);o=a[0],r=a[1],o=parseFloat(o,10),r=parseFloat(r,10)}else o=i.top,r=i.left;return e+=o,n+=r,{top:e,left:n}}}}),X})},function(t,e,n){(function(t){/*!
+	 * Bootstrap v4.0.0-alpha.6 (https://getbootstrap.com)
+	 * Copyright 2011-2017 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
+	 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+	 */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.");+function(t){var e=t.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||e[0]>=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(jQuery),+function(){function e(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function n(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=function(t){function e(t){return{}.toString.call(t).match(/\s([a-zA-Z]+)/)[1].toLowerCase()}function n(t){return(t[0]||t).nodeType}function i(){return{bindType:a.end,delegateType:a.end,handle:function(e){if(t(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}}}function o(){if(window.QUnit)return!1;var t=document.createElement("bootstrap");for(var e in h)if(void 0!==t.style[e])return{end:h[e]};return!1}function r(e){var n=this,i=!1;return t(this).one(f.TRANSITION_END,function(){i=!0}),setTimeout(function(){i||f.triggerTransitionEnd(n)},e),this}function s(){a=o(),t.fn.emulateTransitionEnd=r,f.supportsTransitionEnd()&&(t.event.special[f.TRANSITION_END]=i())}var a=!1,l=1e6,h={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},f={TRANSITION_END:"bsTransitionEnd",getUID:function(t){do t+=~~(Math.random()*l);while(document.getElementById(t));return t},getSelectorFromElement:function(t){var e=t.getAttribute("data-target");return e||(e=t.getAttribute("href")||"",e=/^#[a-z]/i.test(e)?e:null),e},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(e){t(e).trigger(a.end)},supportsTransitionEnd:function(){return Boolean(a)},typeCheckConfig:function(t,i,o){for(var r in o)if(o.hasOwnProperty(r)){var s=o[r],a=i[r],l=a&&n(a)?"element":e(a);if(!new RegExp(s).test(l))throw new Error(t.toUpperCase()+": "+('Option "'+r+'" provided type "'+l+'" ')+('but expected type "'+s+'".'))}}};return s(),f}(jQuery),a=(function(t){var e="alert",n="4.0.0-alpha.6",o="bs.alert",a="."+o,l=".data-api",h=t.fn[e],f=150,u={DISMISS:'[data-dismiss="alert"]'},c={CLOSE:"close"+a,CLOSED:"closed"+a,CLICK_DATA_API:"click"+a+l},d={ALERT:"alert",FADE:"fade",SHOW:"show"},p=function(){function e(t){i(this,e),this._element=t}return e.prototype.close=function(t){t=t||this._element;var e=this._getRootElement(t),n=this._triggerCloseEvent(e);n.isDefaultPrevented()||this._removeElement(e)},e.prototype.dispose=function(){t.removeData(this._element,o),this._element=null},e.prototype._getRootElement=function(e){var n=s.getSelectorFromElement(e),i=!1;return n&&(i=t(n)[0]),i||(i=t(e).closest("."+d.ALERT)[0]),i},e.prototype._triggerCloseEvent=function(e){var n=t.Event(c.CLOSE);return t(e).trigger(n),n},e.prototype._removeElement=function(e){var n=this;return t(e).removeClass(d.SHOW),s.supportsTransitionEnd()&&t(e).hasClass(d.FADE)?void t(e).one(s.TRANSITION_END,function(t){return n._destroyElement(e,t)}).emulateTransitionEnd(f):void this._destroyElement(e)},e.prototype._destroyElement=function(e){t(e).detach().trigger(c.CLOSED).remove()},e._jQueryInterface=function(n){return this.each(function(){var i=t(this),r=i.data(o);r||(r=new e(this),i.data(o,r)),"close"===n&&r[n](this)})},e._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},r(e,null,[{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(c.CLICK_DATA_API,u.DISMISS,p._handleDismiss(new p)),t.fn[e]=p._jQueryInterface,t.fn[e].Constructor=p,t.fn[e].noConflict=function(){return t.fn[e]=h,p._jQueryInterface},p}(jQuery),function(t){var e="button",n="4.0.0-alpha.6",o="bs.button",s="."+o,a=".data-api",l=t.fn[e],h={ACTIVE:"active",BUTTON:"btn",FOCUS:"focus"},f={DATA_TOGGLE_CARROT:'[data-toggle^="button"]',DATA_TOGGLE:'[data-toggle="buttons"]',INPUT:"input",ACTIVE:".active",BUTTON:".btn"},u={CLICK_DATA_API:"click"+s+a,FOCUS_BLUR_DATA_API:"focus"+s+a+" "+("blur"+s+a)},c=function(){function e(t){i(this,e),this._element=t}return e.prototype.toggle=function(){var e=!0,n=t(this._element).closest(f.DATA_TOGGLE)[0];if(n){var i=t(this._element).find(f.INPUT)[0];if(i){if("radio"===i.type)if(i.checked&&t(this._element).hasClass(h.ACTIVE))e=!1;else{var o=t(n).find(f.ACTIVE)[0];o&&t(o).removeClass(h.ACTIVE)}e&&(i.checked=!t(this._element).hasClass(h.ACTIVE),t(i).trigger("change")),i.focus()}}this._element.setAttribute("aria-pressed",!t(this._element).hasClass(h.ACTIVE)),e&&t(this._element).toggleClass(h.ACTIVE)},e.prototype.dispose=function(){t.removeData(this._element,o),this._element=null},e._jQueryInterface=function(n){return this.each(function(){var i=t(this).data(o);i||(i=new e(this),t(this).data(o,i)),"toggle"===n&&i[n]()})},r(e,null,[{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(u.CLICK_DATA_API,f.DATA_TOGGLE_CARROT,function(e){e.preventDefault();var n=e.target;t(n).hasClass(h.BUTTON)||(n=t(n).closest(f.BUTTON)),c._jQueryInterface.call(t(n),"toggle")}).on(u.FOCUS_BLUR_DATA_API,f.DATA_TOGGLE_CARROT,function(e){var n=t(e.target).closest(f.BUTTON)[0];t(n).toggleClass(h.FOCUS,/^focus(in)?$/.test(e.type))}),t.fn[e]=c._jQueryInterface,t.fn[e].Constructor=c,t.fn[e].noConflict=function(){return t.fn[e]=l,c._jQueryInterface},c}(jQuery),function(t){var e="carousel",n="4.0.0-alpha.6",a="bs.carousel",l="."+a,h=".data-api",f=t.fn[e],u=600,c=37,d=39,p={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0},g={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean"},m={NEXT:"next",PREV:"prev",LEFT:"left",RIGHT:"right"},_={SLIDE:"slide"+l,SLID:"slid"+l,KEYDOWN:"keydown"+l,MOUSEENTER:"mouseenter"+l,MOUSELEAVE:"mouseleave"+l,LOAD_DATA_API:"load"+l+h,CLICK_DATA_API:"click"+l+h},v={CAROUSEL:"carousel",ACTIVE:"active",SLIDE:"slide",RIGHT:"carousel-item-right",LEFT:"carousel-item-left",NEXT:"carousel-item-next",PREV:"carousel-item-prev",ITEM:"carousel-item"},E={ACTIVE:".active",ACTIVE_ITEM:".active.carousel-item",ITEM:".carousel-item",NEXT_PREV:".carousel-item-next, .carousel-item-prev",INDICATORS:".carousel-indicators",DATA_SLIDE:"[data-slide], [data-slide-to]",DATA_RIDE:'[data-ride="carousel"]'},y=function(){function h(e,n){i(this,h),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this._config=this._getConfig(n),this._element=t(e)[0],this._indicatorsElement=t(this._element).find(E.INDICATORS)[0],this._addEventListeners()}return h.prototype.next=function(){if(this._isSliding)throw new Error("Carousel is sliding");this._slide(m.NEXT)},h.prototype.nextWhenVisible=function(){document.hidden||this.next()},h.prototype.prev=function(){if(this._isSliding)throw new Error("Carousel is sliding");this._slide(m.PREVIOUS)},h.prototype.pause=function(e){e||(this._isPaused=!0),t(this._element).find(E.NEXT_PREV)[0]&&s.supportsTransitionEnd()&&(s.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},h.prototype.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},h.prototype.to=function(e){var n=this;this._activeElement=t(this._element).find(E.ACTIVE_ITEM)[0];var i=this._getItemIndex(this._activeElement);if(!(e>this._items.length-1||e<0)){if(this._isSliding)return void t(this._element).one(_.SLID,function(){return n.to(e)});if(i===e)return this.pause(),void this.cycle();var o=e>i?m.NEXT:m.PREVIOUS;this._slide(o,this._items[e])}},h.prototype.dispose=function(){t(this._element).off(l),t.removeData(this._element,a),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},h.prototype._getConfig=function(n){return n=t.extend({},p,n),s.typeCheckConfig(e,n,g),n},h.prototype._addEventListeners=function(){var e=this;this._config.keyboard&&t(this._element).on(_.KEYDOWN,function(t){return e._keydown(t)}),"hover"!==this._config.pause||"ontouchstart"in document.documentElement||t(this._element).on(_.MOUSEENTER,function(t){return e.pause(t)}).on(_.MOUSELEAVE,function(t){return e.cycle(t)})},h.prototype._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case c:t.preventDefault(),this.prev();break;case d:t.preventDefault(),this.next();break;default:return}},h.prototype._getItemIndex=function(e){return this._items=t.makeArray(t(e).parent().find(E.ITEM)),this._items.indexOf(e)},h.prototype._getItemByDirection=function(t,e){var n=t===m.NEXT,i=t===m.PREVIOUS,o=this._getItemIndex(e),r=this._items.length-1,s=i&&0===o||n&&o===r;if(s&&!this._config.wrap)return e;var a=t===m.PREVIOUS?-1:1,l=(o+a)%this._items.length;return l===-1?this._items[this._items.length-1]:this._items[l]},h.prototype._triggerSlideEvent=function(e,n){var i=t.Event(_.SLIDE,{relatedTarget:e,direction:n});return t(this._element).trigger(i),i},h.prototype._setActiveIndicatorElement=function(e){if(this._indicatorsElement){t(this._indicatorsElement).find(E.ACTIVE).removeClass(v.ACTIVE);var n=this._indicatorsElement.children[this._getItemIndex(e)];n&&t(n).addClass(v.ACTIVE)}},h.prototype._slide=function(e,n){var i=this,o=t(this._element).find(E.ACTIVE_ITEM)[0],r=n||o&&this._getItemByDirection(e,o),a=Boolean(this._interval),l=void 0,h=void 0,f=void 0;if(e===m.NEXT?(l=v.LEFT,h=v.NEXT,f=m.LEFT):(l=v.RIGHT,h=v.PREV,f=m.RIGHT),r&&t(r).hasClass(v.ACTIVE))return void(this._isSliding=!1);var c=this._triggerSlideEvent(r,f);if(!c.isDefaultPrevented()&&o&&r){this._isSliding=!0,a&&this.pause(),this._setActiveIndicatorElement(r);var d=t.Event(_.SLID,{relatedTarget:r,direction:f});s.supportsTransitionEnd()&&t(this._element).hasClass(v.SLIDE)?(t(r).addClass(h),s.reflow(r),t(o).addClass(l),t(r).addClass(l),t(o).one(s.TRANSITION_END,function(){t(r).removeClass(l+" "+h).addClass(v.ACTIVE),t(o).removeClass(v.ACTIVE+" "+h+" "+l),i._isSliding=!1,setTimeout(function(){return t(i._element).trigger(d)},0)}).emulateTransitionEnd(u)):(t(o).removeClass(v.ACTIVE),t(r).addClass(v.ACTIVE),this._isSliding=!1,t(this._element).trigger(d)),a&&this.cycle()}},h._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(a),i=t.extend({},p,t(this).data());"object"===("undefined"==typeof e?"undefined":o(e))&&t.extend(i,e);var r="string"==typeof e?e:i.slide;if(n||(n=new h(this,i),t(this).data(a,n)),"number"==typeof e)n.to(e);else if("string"==typeof r){if(void 0===n[r])throw new Error('No method named "'+r+'"');n[r]()}else i.interval&&(n.pause(),n.cycle())})},h._dataApiClickHandler=function(e){var n=s.getSelectorFromElement(this);if(n){var i=t(n)[0];if(i&&t(i).hasClass(v.CAROUSEL)){var o=t.extend({},t(i).data(),t(this).data()),r=this.getAttribute("data-slide-to");r&&(o.interval=!1),h._jQueryInterface.call(t(i),o),r&&t(i).data(a).to(r),e.preventDefault()}}},r(h,null,[{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return p}}]),h}();return t(document).on(_.CLICK_DATA_API,E.DATA_SLIDE,y._dataApiClickHandler),t(window).on(_.LOAD_DATA_API,function(){t(E.DATA_RIDE).each(function(){var e=t(this);y._jQueryInterface.call(e,e.data())})}),t.fn[e]=y._jQueryInterface,t.fn[e].Constructor=y,t.fn[e].noConflict=function(){return t.fn[e]=f,y._jQueryInterface},y}(jQuery),function(t){var e="collapse",n="4.0.0-alpha.6",a="bs.collapse",l="."+a,h=".data-api",f=t.fn[e],u=600,c={toggle:!0,parent:""},d={toggle:"boolean",parent:"string"},p={SHOW:"show"+l,SHOWN:"shown"+l,HIDE:"hide"+l,HIDDEN:"hidden"+l,CLICK_DATA_API:"click"+l+h},g={SHOW:"show",COLLAPSE:"collapse",COLLAPSING:"collapsing",COLLAPSED:"collapsed"},m={WIDTH:"width",HEIGHT:"height"},_={ACTIVES:".card > .show, .card > .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},v=function(){function l(e,n){i(this,l),this._isTransitioning=!1,this._element=e,this._config=this._getConfig(n),this._triggerArray=t.makeArray(t('[data-toggle="collapse"][href="#'+e.id+'"],'+('[data-toggle="collapse"][data-target="#'+e.id+'"]'))),this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}return l.prototype.toggle=function(){t(this._element).hasClass(g.SHOW)?this.hide():this.show()},l.prototype.show=function(){var e=this;if(this._isTransitioning)throw new Error("Collapse is transitioning");if(!t(this._element).hasClass(g.SHOW)){var n=void 0,i=void 0;if(this._parent&&(n=t.makeArray(t(this._parent).find(_.ACTIVES)),n.length||(n=null)),!(n&&(i=t(n).data(a),i&&i._isTransitioning))){var o=t.Event(p.SHOW);if(t(this._element).trigger(o),!o.isDefaultPrevented()){n&&(l._jQueryInterface.call(t(n),"hide"),i||t(n).data(a,null));var r=this._getDimension();t(this._element).removeClass(g.COLLAPSE).addClass(g.COLLAPSING),this._element.style[r]=0,this._element.setAttribute("aria-expanded",!0),this._triggerArray.length&&t(this._triggerArray).removeClass(g.COLLAPSED).attr("aria-expanded",!0),this.setTransitioning(!0);var h=function(){t(e._element).removeClass(g.COLLAPSING).addClass(g.COLLAPSE).addClass(g.SHOW),e._element.style[r]="",e.setTransitioning(!1),t(e._element).trigger(p.SHOWN)};if(!s.supportsTransitionEnd())return void h();var f=r[0].toUpperCase()+r.slice(1),c="scroll"+f;t(this._element).one(s.TRANSITION_END,h).emulateTransitionEnd(u),this._element.style[r]=this._element[c]+"px"}}}},l.prototype.hide=function(){var e=this;if(this._isTransitioning)throw new Error("Collapse is transitioning");if(t(this._element).hasClass(g.SHOW)){var n=t.Event(p.HIDE);if(t(this._element).trigger(n),!n.isDefaultPrevented()){var i=this._getDimension(),o=i===m.WIDTH?"offsetWidth":"offsetHeight";this._element.style[i]=this._element[o]+"px",s.reflow(this._element),t(this._element).addClass(g.COLLAPSING).removeClass(g.COLLAPSE).removeClass(g.SHOW),this._element.setAttribute("aria-expanded",!1),this._triggerArray.length&&t(this._triggerArray).addClass(g.COLLAPSED).attr("aria-expanded",!1),this.setTransitioning(!0);var r=function(){e.setTransitioning(!1),t(e._element).removeClass(g.COLLAPSING).addClass(g.COLLAPSE).trigger(p.HIDDEN)};return this._element.style[i]="",s.supportsTransitionEnd()?void t(this._element).one(s.TRANSITION_END,r).emulateTransitionEnd(u):void r()}}},l.prototype.setTransitioning=function(t){this._isTransitioning=t},l.prototype.dispose=function(){t.removeData(this._element,a),this._config=null,this._parent=null,this._element=null,this._triggerArray=null,this._isTransitioning=null},l.prototype._getConfig=function(n){return n=t.extend({},c,n),n.toggle=Boolean(n.toggle),s.typeCheckConfig(e,n,d),n},l.prototype._getDimension=function(){var e=t(this._element).hasClass(m.WIDTH);return e?m.WIDTH:m.HEIGHT},l.prototype._getParent=function(){var e=this,n=t(this._config.parent)[0],i='[data-toggle="collapse"][data-parent="'+this._config.parent+'"]';return t(n).find(i).each(function(t,n){e._addAriaAndCollapsedClass(l._getTargetFromElement(n),[n])}),n},l.prototype._addAriaAndCollapsedClass=function(e,n){if(e){var i=t(e).hasClass(g.SHOW);e.setAttribute("aria-expanded",i),n.length&&t(n).toggleClass(g.COLLAPSED,!i).attr("aria-expanded",i)}},l._getTargetFromElement=function(e){var n=s.getSelectorFromElement(e);return n?t(n)[0]:null},l._jQueryInterface=function(e){return this.each(function(){var n=t(this),i=n.data(a),r=t.extend({},c,n.data(),"object"===("undefined"==typeof e?"undefined":o(e))&&e);if(!i&&r.toggle&&/show|hide/.test(e)&&(r.toggle=!1),i||(i=new l(this,r),n.data(a,i)),"string"==typeof e){if(void 0===i[e])throw new Error('No method named "'+e+'"');i[e]()}})},r(l,null,[{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return c}}]),l}();return t(document).on(p.CLICK_DATA_API,_.DATA_TOGGLE,function(e){e.preventDefault();var n=v._getTargetFromElement(this),i=t(n).data(a),o=i?"toggle":t(this).data();v._jQueryInterface.call(t(n),o)}),t.fn[e]=v._jQueryInterface,t.fn[e].Constructor=v,t.fn[e].noConflict=function(){return t.fn[e]=f,v._jQueryInterface},v}(jQuery),function(t){var e="dropdown",n="4.0.0-alpha.6",o="bs.dropdown",a="."+o,l=".data-api",h=t.fn[e],f=27,u=38,c=40,d=3,p={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,CLICK:"click"+a,CLICK_DATA_API:"click"+a+l,FOCUSIN_DATA_API:"focusin"+a+l,KEYDOWN_DATA_API:"keydown"+a+l},g={BACKDROP:"dropdown-backdrop",DISABLED:"disabled",SHOW:"show"},m={BACKDROP:".dropdown-backdrop",DATA_TOGGLE:'[data-toggle="dropdown"]',FORM_CHILD:".dropdown form",ROLE_MENU:'[role="menu"]',ROLE_LISTBOX:'[role="listbox"]',NAVBAR_NAV:".navbar-nav",VISIBLE_ITEMS:'[role="menu"] li:not(.disabled) a, [role="listbox"] li:not(.disabled) a'},_=function(){function e(t){i(this,e),this._element=t,this._addEventListeners()}return e.prototype.toggle=function(){if(this.disabled||t(this).hasClass(g.DISABLED))return!1;var n=e._getParentFromElement(this),i=t(n).hasClass(g.SHOW);if(e._clearMenus(),i)return!1;if("ontouchstart"in document.documentElement&&!t(n).closest(m.NAVBAR_NAV).length){var o=document.createElement("div");o.className=g.BACKDROP,t(o).insertBefore(this),t(o).on("click",e._clearMenus)}var r={relatedTarget:this},s=t.Event(p.SHOW,r);return t(n).trigger(s),!s.isDefaultPrevented()&&(this.focus(),this.setAttribute("aria-expanded",!0),t(n).toggleClass(g.SHOW),t(n).trigger(t.Event(p.SHOWN,r)),!1)},e.prototype.dispose=function(){t.removeData(this._element,o),t(this._element).off(a),this._element=null},e.prototype._addEventListeners=function(){t(this._element).on(p.CLICK,this.toggle)},e._jQueryInterface=function(n){return this.each(function(){var i=t(this).data(o);if(i||(i=new e(this),t(this).data(o,i)),"string"==typeof n){if(void 0===i[n])throw new Error('No method named "'+n+'"');i[n].call(this)}})},e._clearMenus=function(n){if(!n||n.which!==d){var i=t(m.BACKDROP)[0];i&&i.parentNode.removeChild(i);for(var o=t.makeArray(t(m.DATA_TOGGLE)),r=0;r<o.length;r++){var s=e._getParentFromElement(o[r]),a={relatedTarget:o[r]};if(t(s).hasClass(g.SHOW)&&!(n&&("click"===n.type&&/input|textarea/i.test(n.target.tagName)||"focusin"===n.type)&&t.contains(s,n.target))){var l=t.Event(p.HIDE,a);t(s).trigger(l),l.isDefaultPrevented()||(o[r].setAttribute("aria-expanded","false"),t(s).removeClass(g.SHOW).trigger(t.Event(p.HIDDEN,a)))}}}},e._getParentFromElement=function(e){var n=void 0,i=s.getSelectorFromElement(e);return i&&(n=t(i)[0]),n||e.parentNode},e._dataApiKeydownHandler=function(n){if(/(38|40|27|32)/.test(n.which)&&!/input|textarea/i.test(n.target.tagName)&&(n.preventDefault(),n.stopPropagation(),!this.disabled&&!t(this).hasClass(g.DISABLED))){var i=e._getParentFromElement(this),o=t(i).hasClass(g.SHOW);if(!o&&n.which!==f||o&&n.which===f){if(n.which===f){var r=t(i).find(m.DATA_TOGGLE)[0];t(r).trigger("focus")}return void t(this).trigger("click")}var s=t(i).find(m.VISIBLE_ITEMS).get();if(s.length){var a=s.indexOf(n.target);n.which===u&&a>0&&a--,n.which===c&&a<s.length-1&&a++,a<0&&(a=0),s[a].focus()}}},r(e,null,[{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(p.KEYDOWN_DATA_API,m.DATA_TOGGLE,_._dataApiKeydownHandler).on(p.KEYDOWN_DATA_API,m.ROLE_MENU,_._dataApiKeydownHandler).on(p.KEYDOWN_DATA_API,m.ROLE_LISTBOX,_._dataApiKeydownHandler).on(p.CLICK_DATA_API+" "+p.FOCUSIN_DATA_API,_._clearMenus).on(p.CLICK_DATA_API,m.DATA_TOGGLE,_.prototype.toggle).on(p.CLICK_DATA_API,m.FORM_CHILD,function(t){t.stopPropagation()}),t.fn[e]=_._jQueryInterface,t.fn[e].Constructor=_,t.fn[e].noConflict=function(){return t.fn[e]=h,_._jQueryInterface},_}(jQuery),function(t){var e="modal",n="4.0.0-alpha.6",a="bs.modal",l="."+a,h=".data-api",f=t.fn[e],u=300,c=150,d=27,p={backdrop:!0,keyboard:!0,focus:!0,show:!0},g={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean",show:"boolean"},m={HIDE:"hide"+l,HIDDEN:"hidden"+l,SHOW:"show"+l,SHOWN:"shown"+l,FOCUSIN:"focusin"+l,RESIZE:"resize"+l,CLICK_DISMISS:"click.dismiss"+l,KEYDOWN_DISMISS:"keydown.dismiss"+l,MOUSEUP_DISMISS:"mouseup.dismiss"+l,MOUSEDOWN_DISMISS:"mousedown.dismiss"+l,CLICK_DATA_API:"click"+l+h},_={SCROLLBAR_MEASURER:"modal-scrollbar-measure",BACKDROP:"modal-backdrop",OPEN:"modal-open",FADE:"fade",SHOW:"show"},v={DIALOG:".modal-dialog",DATA_TOGGLE:'[data-toggle="modal"]',DATA_DISMISS:'[data-dismiss="modal"]',FIXED_CONTENT:".fixed-top, .fixed-bottom, .is-fixed, .sticky-top"},E=function(){function h(e,n){i(this,h),this._config=this._getConfig(n),this._element=e,this._dialog=t(e).find(v.DIALOG)[0],this._backdrop=null,this._isShown=!1,this._isBodyOverflowing=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._originalBodyPadding=0,this._scrollbarWidth=0}return h.prototype.toggle=function(t){return this._isShown?this.hide():this.show(t)},h.prototype.show=function(e){var n=this;if(this._isTransitioning)throw new Error("Modal is transitioning");s.supportsTransitionEnd()&&t(this._element).hasClass(_.FADE)&&(this._isTransitioning=!0);var i=t.Event(m.SHOW,{relatedTarget:e});t(this._element).trigger(i),this._isShown||i.isDefaultPrevented()||(this._isShown=!0,this._checkScrollbar(),this._setScrollbar(),t(document.body).addClass(_.OPEN),this._setEscapeEvent(),this._setResizeEvent(),t(this._element).on(m.CLICK_DISMISS,v.DATA_DISMISS,function(t){return n.hide(t)}),t(this._dialog).on(m.MOUSEDOWN_DISMISS,function(){t(n._element).one(m.MOUSEUP_DISMISS,function(e){t(e.target).is(n._element)&&(n._ignoreBackdropClick=!0)})}),this._showBackdrop(function(){return n._showElement(e)}))},h.prototype.hide=function(e){var n=this;if(e&&e.preventDefault(),this._isTransitioning)throw new Error("Modal is transitioning");var i=s.supportsTransitionEnd()&&t(this._element).hasClass(_.FADE);i&&(this._isTransitioning=!0);var o=t.Event(m.HIDE);t(this._element).trigger(o),this._isShown&&!o.isDefaultPrevented()&&(this._isShown=!1,this._setEscapeEvent(),this._setResizeEvent(),t(document).off(m.FOCUSIN),t(this._element).removeClass(_.SHOW),t(this._element).off(m.CLICK_DISMISS),t(this._dialog).off(m.MOUSEDOWN_DISMISS),i?t(this._element).one(s.TRANSITION_END,function(t){return n._hideModal(t)}).emulateTransitionEnd(u):this._hideModal())},h.prototype.dispose=function(){t.removeData(this._element,a),t(window,document,this._element,this._backdrop).off(l),this._config=null,this._element=null,this._dialog=null,this._backdrop=null,this._isShown=null,this._isBodyOverflowing=null,this._ignoreBackdropClick=null,this._originalBodyPadding=null,this._scrollbarWidth=null},h.prototype._getConfig=function(n){return n=t.extend({},p,n),s.typeCheckConfig(e,n,g),n},h.prototype._showElement=function(e){var n=this,i=s.supportsTransitionEnd()&&t(this._element).hasClass(_.FADE);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.scrollTop=0,i&&s.reflow(this._element),t(this._element).addClass(_.SHOW),this._config.focus&&this._enforceFocus();var o=t.Event(m.SHOWN,{relatedTarget:e}),r=function(){n._config.focus&&n._element.focus(),n._isTransitioning=!1,t(n._element).trigger(o)};i?t(this._dialog).one(s.TRANSITION_END,r).emulateTransitionEnd(u):r()},h.prototype._enforceFocus=function(){var e=this;t(document).off(m.FOCUSIN).on(m.FOCUSIN,function(n){document===n.target||e._element===n.target||t(e._element).has(n.target).length||e._element.focus()})},h.prototype._setEscapeEvent=function(){var e=this;this._isShown&&this._config.keyboard?t(this._element).on(m.KEYDOWN_DISMISS,function(t){t.which===d&&e.hide()}):this._isShown||t(this._element).off(m.KEYDOWN_DISMISS)},h.prototype._setResizeEvent=function(){var e=this;this._isShown?t(window).on(m.RESIZE,function(t){return e._handleUpdate(t)}):t(window).off(m.RESIZE)},h.prototype._hideModal=function(){var e=this;this._element.style.display="none",this._element.setAttribute("aria-hidden","true"),this._isTransitioning=!1,this._showBackdrop(function(){t(document.body).removeClass(_.OPEN),e._resetAdjustments(),e._resetScrollbar(),t(e._element).trigger(m.HIDDEN)})},h.prototype._removeBackdrop=function(){this._backdrop&&(t(this._backdrop).remove(),this._backdrop=null)},h.prototype._showBackdrop=function(e){var n=this,i=t(this._element).hasClass(_.FADE)?_.FADE:"";if(this._isShown&&this._config.backdrop){var o=s.supportsTransitionEnd()&&i;if(this._backdrop=document.createElement("div"),this._backdrop.className=_.BACKDROP,i&&t(this._backdrop).addClass(i),t(this._backdrop).appendTo(document.body),t(this._element).on(m.CLICK_DISMISS,function(t){return n._ignoreBackdropClick?void(n._ignoreBackdropClick=!1):void(t.target===t.currentTarget&&("static"===n._config.backdrop?n._element.focus():n.hide()))}),o&&s.reflow(this._backdrop),t(this._backdrop).addClass(_.SHOW),!e)return;if(!o)return void e();t(this._backdrop).one(s.TRANSITION_END,e).emulateTransitionEnd(c)}else if(!this._isShown&&this._backdrop){t(this._backdrop).removeClass(_.SHOW);var r=function(){n._removeBackdrop(),e&&e()};s.supportsTransitionEnd()&&t(this._element).hasClass(_.FADE)?t(this._backdrop).one(s.TRANSITION_END,r).emulateTransitionEnd(c):r()}else e&&e()},h.prototype._handleUpdate=function(){this._adjustDialog()},h.prototype._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},h.prototype._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},h.prototype._checkScrollbar=function(){this._isBodyOverflowing=document.body.clientWidth<window.innerWidth,this._scrollbarWidth=this._getScrollbarWidth()},h.prototype._setScrollbar=function(){var e=parseInt(t(v.FIXED_CONTENT).css("padding-right")||0,10);this._originalBodyPadding=document.body.style.paddingRight||"",this._isBodyOverflowing&&(document.body.style.paddingRight=e+this._scrollbarWidth+"px")},h.prototype._resetScrollbar=function(){document.body.style.paddingRight=this._originalBodyPadding},h.prototype._getScrollbarWidth=function(){var t=document.createElement("div");t.className=_.SCROLLBAR_MEASURER,document.body.appendChild(t);var e=t.offsetWidth-t.clientWidth;return document.body.removeChild(t),e},h._jQueryInterface=function(e,n){return this.each(function(){var i=t(this).data(a),r=t.extend({},h.Default,t(this).data(),"object"===("undefined"==typeof e?"undefined":o(e))&&e);if(i||(i=new h(this,r),t(this).data(a,i)),"string"==typeof e){if(void 0===i[e])throw new Error('No method named "'+e+'"');i[e](n)}else r.show&&i.show(n)})},r(h,null,[{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return p}}]),h}();return t(document).on(m.CLICK_DATA_API,v.DATA_TOGGLE,function(e){var n=this,i=void 0,o=s.getSelectorFromElement(this);o&&(i=t(o)[0]);var r=t(i).data(a)?"toggle":t.extend({},t(i).data(),t(this).data());"A"!==this.tagName&&"AREA"!==this.tagName||e.preventDefault();var l=t(i).one(m.SHOW,function(e){e.isDefaultPrevented()||l.one(m.HIDDEN,function(){t(n).is(":visible")&&n.focus()})});E._jQueryInterface.call(t(i),r,this)}),t.fn[e]=E._jQueryInterface,t.fn[e].Constructor=E,t.fn[e].noConflict=function(){return t.fn[e]=f,E._jQueryInterface},E}(jQuery),function(t){var e="scrollspy",n="4.0.0-alpha.6",a="bs.scrollspy",l="."+a,h=".data-api",f=t.fn[e],u={offset:10,method:"auto",target:""},c={offset:"number",method:"string",target:"(string|element)"},d={ACTIVATE:"activate"+l,SCROLL:"scroll"+l,LOAD_DATA_API:"load"+l+h},p={DROPDOWN_ITEM:"dropdown-item",DROPDOWN_MENU:"dropdown-menu",NAV_LINK:"nav-link",NAV:"nav",ACTIVE:"active"},g={DATA_SPY:'[data-spy="scroll"]',ACTIVE:".active",LIST_ITEM:".list-item",LI:"li",LI_DROPDOWN:"li.dropdown",NAV_LINKS:".nav-link",DROPDOWN:".dropdown",DROPDOWN_ITEMS:".dropdown-item",DROPDOWN_TOGGLE:".dropdown-toggle"},m={OFFSET:"offset",POSITION:"position"},_=function(){function h(e,n){var o=this;i(this,h),this._element=e,this._scrollElement="BODY"===e.tagName?window:e,this._config=this._getConfig(n),this._selector=this._config.target+" "+g.NAV_LINKS+","+(this._config.target+" "+g.DROPDOWN_ITEMS),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,t(this._scrollElement).on(d.SCROLL,function(t){return o._process(t)}),this.refresh(),this._process()}return h.prototype.refresh=function(){var e=this,n=this._scrollElement!==this._scrollElement.window?m.POSITION:m.OFFSET,i="auto"===this._config.method?n:this._config.method,o=i===m.POSITION?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight();var r=t.makeArray(t(this._selector));r.map(function(e){var n=void 0,r=s.getSelectorFromElement(e);return r&&(n=t(r)[0]),n&&(n.offsetWidth||n.offsetHeight)?[t(n)[i]().top+o,r]:null}).filter(function(t){return t}).sort(function(t,e){return t[0]-e[0]}).forEach(function(t){e._offsets.push(t[0]),e._targets.push(t[1])})},h.prototype.dispose=function(){t.removeData(this._element,a),t(this._scrollElement).off(l),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},h.prototype._getConfig=function(n){if(n=t.extend({},u,n),"string"!=typeof n.target){var i=t(n.target).attr("id");i||(i=s.getUID(e),t(n.target).attr("id",i)),n.target="#"+i}return s.typeCheckConfig(e,n,c),n},h.prototype._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},h.prototype._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},h.prototype._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.offsetHeight},h.prototype._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];return void(this._activeTarget!==i&&this._activate(i))}if(this._activeTarget&&t<this._offsets[0]&&this._offsets[0]>0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;){var r=this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&(void 0===this._offsets[o+1]||t<this._offsets[o+1]);r&&this._activate(this._targets[o])}},h.prototype._activate=function(e){this._activeTarget=e,this._clear();var n=this._selector.split(",");n=n.map(function(t){return t+'[data-target="'+e+'"],'+(t+'[href="'+e+'"]')});var i=t(n.join(","));i.hasClass(p.DROPDOWN_ITEM)?(i.closest(g.DROPDOWN).find(g.DROPDOWN_TOGGLE).addClass(p.ACTIVE),i.addClass(p.ACTIVE)):i.parents(g.LI).find("> "+g.NAV_LINKS).addClass(p.ACTIVE),t(this._scrollElement).trigger(d.ACTIVATE,{relatedTarget:e})},h.prototype._clear=function(){t(this._selector).filter(g.ACTIVE).removeClass(p.ACTIVE)},h._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(a),i="object"===("undefined"==typeof e?"undefined":o(e))&&e;
+if(n||(n=new h(this,i),t(this).data(a,n)),"string"==typeof e){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})},r(h,null,[{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return u}}]),h}();return t(window).on(d.LOAD_DATA_API,function(){for(var e=t.makeArray(t(g.DATA_SPY)),n=e.length;n--;){var i=t(e[n]);_._jQueryInterface.call(i,i.data())}}),t.fn[e]=_._jQueryInterface,t.fn[e].Constructor=_,t.fn[e].noConflict=function(){return t.fn[e]=f,_._jQueryInterface},_}(jQuery),function(t){var e="tab",n="4.0.0-alpha.6",o="bs.tab",a="."+o,l=".data-api",h=t.fn[e],f=150,u={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,CLICK_DATA_API:"click"+a+l},c={DROPDOWN_MENU:"dropdown-menu",ACTIVE:"active",DISABLED:"disabled",FADE:"fade",SHOW:"show"},d={A:"a",LI:"li",DROPDOWN:".dropdown",LIST:"ul:not(.dropdown-menu), ol:not(.dropdown-menu), nav:not(.dropdown-menu)",FADE_CHILD:"> .nav-item .fade, > .fade",ACTIVE:".active",ACTIVE_CHILD:"> .nav-item > .active, > .active",DATA_TOGGLE:'[data-toggle="tab"], [data-toggle="pill"]',DROPDOWN_TOGGLE:".dropdown-toggle",DROPDOWN_ACTIVE_CHILD:"> .dropdown-menu .active"},p=function(){function e(t){i(this,e),this._element=t}return e.prototype.show=function(){var e=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&t(this._element).hasClass(c.ACTIVE)||t(this._element).hasClass(c.DISABLED))){var n=void 0,i=void 0,o=t(this._element).closest(d.LIST)[0],r=s.getSelectorFromElement(this._element);o&&(i=t.makeArray(t(o).find(d.ACTIVE)),i=i[i.length-1]);var a=t.Event(u.HIDE,{relatedTarget:this._element}),l=t.Event(u.SHOW,{relatedTarget:i});if(i&&t(i).trigger(a),t(this._element).trigger(l),!l.isDefaultPrevented()&&!a.isDefaultPrevented()){r&&(n=t(r)[0]),this._activate(this._element,o);var h=function(){var n=t.Event(u.HIDDEN,{relatedTarget:e._element}),o=t.Event(u.SHOWN,{relatedTarget:i});t(i).trigger(n),t(e._element).trigger(o)};n?this._activate(n,n.parentNode,h):h()}}},e.prototype.dispose=function(){t.removeClass(this._element,o),this._element=null},e.prototype._activate=function(e,n,i){var o=this,r=t(n).find(d.ACTIVE_CHILD)[0],a=i&&s.supportsTransitionEnd()&&(r&&t(r).hasClass(c.FADE)||Boolean(t(n).find(d.FADE_CHILD)[0])),l=function(){return o._transitionComplete(e,r,a,i)};r&&a?t(r).one(s.TRANSITION_END,l).emulateTransitionEnd(f):l(),r&&t(r).removeClass(c.SHOW)},e.prototype._transitionComplete=function(e,n,i,o){if(n){t(n).removeClass(c.ACTIVE);var r=t(n.parentNode).find(d.DROPDOWN_ACTIVE_CHILD)[0];r&&t(r).removeClass(c.ACTIVE),n.setAttribute("aria-expanded",!1)}if(t(e).addClass(c.ACTIVE),e.setAttribute("aria-expanded",!0),i?(s.reflow(e),t(e).addClass(c.SHOW)):t(e).removeClass(c.FADE),e.parentNode&&t(e.parentNode).hasClass(c.DROPDOWN_MENU)){var a=t(e).closest(d.DROPDOWN)[0];a&&t(a).find(d.DROPDOWN_TOGGLE).addClass(c.ACTIVE),e.setAttribute("aria-expanded",!0)}o&&o()},e._jQueryInterface=function(n){return this.each(function(){var i=t(this),r=i.data(o);if(r||(r=new e(this),i.data(o,r)),"string"==typeof n){if(void 0===r[n])throw new Error('No method named "'+n+'"');r[n]()}})},r(e,null,[{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(u.CLICK_DATA_API,d.DATA_TOGGLE,function(e){e.preventDefault(),p._jQueryInterface.call(t(this),"show")}),t.fn[e]=p._jQueryInterface,t.fn[e].Constructor=p,t.fn[e].noConflict=function(){return t.fn[e]=h,p._jQueryInterface},p}(jQuery),function(e){if("undefined"==typeof t)throw new Error("Bootstrap tooltips require Tether (http://tether.io/)");var n="tooltip",a="4.0.0-alpha.6",l="bs.tooltip",h="."+l,f=e.fn[n],u=150,c="bs-tether",d={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:"0 0",constraints:[],container:!1},p={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"string",constraints:"array",container:"(string|element|boolean)"},g={TOP:"bottom center",RIGHT:"middle left",BOTTOM:"top center",LEFT:"middle right"},m={SHOW:"show",OUT:"out"},_={HIDE:"hide"+h,HIDDEN:"hidden"+h,SHOW:"show"+h,SHOWN:"shown"+h,INSERTED:"inserted"+h,CLICK:"click"+h,FOCUSIN:"focusin"+h,FOCUSOUT:"focusout"+h,MOUSEENTER:"mouseenter"+h,MOUSELEAVE:"mouseleave"+h},v={FADE:"fade",SHOW:"show"},E={TOOLTIP:".tooltip",TOOLTIP_INNER:".tooltip-inner"},y={element:!1,enabled:!1},T={HOVER:"hover",FOCUS:"focus",CLICK:"click",MANUAL:"manual"},C=function(){function f(t,e){i(this,f),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._isTransitioning=!1,this._tether=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}return f.prototype.enable=function(){this._isEnabled=!0},f.prototype.disable=function(){this._isEnabled=!1},f.prototype.toggleEnabled=function(){this._isEnabled=!this._isEnabled},f.prototype.toggle=function(t){if(t){var n=this.constructor.DATA_KEY,i=e(t.currentTarget).data(n);i||(i=new this.constructor(t.currentTarget,this._getDelegateConfig()),e(t.currentTarget).data(n,i)),i._activeTrigger.click=!i._activeTrigger.click,i._isWithActiveTrigger()?i._enter(null,i):i._leave(null,i)}else{if(e(this.getTipElement()).hasClass(v.SHOW))return void this._leave(null,this);this._enter(null,this)}},f.prototype.dispose=function(){clearTimeout(this._timeout),this.cleanupTether(),e.removeData(this.element,this.constructor.DATA_KEY),e(this.element).off(this.constructor.EVENT_KEY),e(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&e(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._tether=null,this.element=null,this.config=null,this.tip=null},f.prototype.show=function(){var n=this;if("none"===e(this.element).css("display"))throw new Error("Please use show on visible elements");var i=e.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){if(this._isTransitioning)throw new Error("Tooltip is transitioning");e(this.element).trigger(i);var o=e.contains(this.element.ownerDocument.documentElement,this.element);if(i.isDefaultPrevented()||!o)return;var r=this.getTipElement(),a=s.getUID(this.constructor.NAME);r.setAttribute("id",a),this.element.setAttribute("aria-describedby",a),this.setContent(),this.config.animation&&e(r).addClass(v.FADE);var l="function"==typeof this.config.placement?this.config.placement.call(this,r,this.element):this.config.placement,h=this._getAttachment(l),u=this.config.container===!1?document.body:e(this.config.container);e(r).data(this.constructor.DATA_KEY,this).appendTo(u),e(this.element).trigger(this.constructor.Event.INSERTED),this._tether=new t({attachment:h,element:r,target:this.element,classes:y,classPrefix:c,offset:this.config.offset,constraints:this.config.constraints,addTargetClasses:!1}),s.reflow(r),this._tether.position(),e(r).addClass(v.SHOW);var d=function(){var t=n._hoverState;n._hoverState=null,n._isTransitioning=!1,e(n.element).trigger(n.constructor.Event.SHOWN),t===m.OUT&&n._leave(null,n)};if(s.supportsTransitionEnd()&&e(this.tip).hasClass(v.FADE))return this._isTransitioning=!0,void e(this.tip).one(s.TRANSITION_END,d).emulateTransitionEnd(f._TRANSITION_DURATION);d()}},f.prototype.hide=function(t){var n=this,i=this.getTipElement(),o=e.Event(this.constructor.Event.HIDE);if(this._isTransitioning)throw new Error("Tooltip is transitioning");var r=function(){n._hoverState!==m.SHOW&&i.parentNode&&i.parentNode.removeChild(i),n.element.removeAttribute("aria-describedby"),e(n.element).trigger(n.constructor.Event.HIDDEN),n._isTransitioning=!1,n.cleanupTether(),t&&t()};e(this.element).trigger(o),o.isDefaultPrevented()||(e(i).removeClass(v.SHOW),this._activeTrigger[T.CLICK]=!1,this._activeTrigger[T.FOCUS]=!1,this._activeTrigger[T.HOVER]=!1,s.supportsTransitionEnd()&&e(this.tip).hasClass(v.FADE)?(this._isTransitioning=!0,e(i).one(s.TRANSITION_END,r).emulateTransitionEnd(u)):r(),this._hoverState="")},f.prototype.isWithContent=function(){return Boolean(this.getTitle())},f.prototype.getTipElement=function(){return this.tip=this.tip||e(this.config.template)[0]},f.prototype.setContent=function(){var t=e(this.getTipElement());this.setElementContent(t.find(E.TOOLTIP_INNER),this.getTitle()),t.removeClass(v.FADE+" "+v.SHOW),this.cleanupTether()},f.prototype.setElementContent=function(t,n){var i=this.config.html;"object"===("undefined"==typeof n?"undefined":o(n))&&(n.nodeType||n.jquery)?i?e(n).parent().is(t)||t.empty().append(n):t.text(e(n).text()):t[i?"html":"text"](n)},f.prototype.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},f.prototype.cleanupTether=function(){this._tether&&this._tether.destroy()},f.prototype._getAttachment=function(t){return g[t.toUpperCase()]},f.prototype._setListeners=function(){var t=this,n=this.config.trigger.split(" ");n.forEach(function(n){if("click"===n)e(t.element).on(t.constructor.Event.CLICK,t.config.selector,function(e){return t.toggle(e)});else if(n!==T.MANUAL){var i=n===T.HOVER?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,o=n===T.HOVER?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;e(t.element).on(i,t.config.selector,function(e){return t._enter(e)}).on(o,t.config.selector,function(e){return t._leave(e)})}e(t.element).closest(".modal").on("hide.bs.modal",function(){return t.hide()})}),this.config.selector?this.config=e.extend({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},f.prototype._fixTitle=function(){var t=o(this.element.getAttribute("data-original-title"));(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},f.prototype._enter=function(t,n){var i=this.constructor.DATA_KEY;return n=n||e(t.currentTarget).data(i),n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),e(t.currentTarget).data(i,n)),t&&(n._activeTrigger["focusin"===t.type?T.FOCUS:T.HOVER]=!0),e(n.getTipElement()).hasClass(v.SHOW)||n._hoverState===m.SHOW?void(n._hoverState=m.SHOW):(clearTimeout(n._timeout),n._hoverState=m.SHOW,n.config.delay&&n.config.delay.show?void(n._timeout=setTimeout(function(){n._hoverState===m.SHOW&&n.show()},n.config.delay.show)):void n.show())},f.prototype._leave=function(t,n){var i=this.constructor.DATA_KEY;if(n=n||e(t.currentTarget).data(i),n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),e(t.currentTarget).data(i,n)),t&&(n._activeTrigger["focusout"===t.type?T.FOCUS:T.HOVER]=!1),!n._isWithActiveTrigger())return clearTimeout(n._timeout),n._hoverState=m.OUT,n.config.delay&&n.config.delay.hide?void(n._timeout=setTimeout(function(){n._hoverState===m.OUT&&n.hide()},n.config.delay.hide)):void n.hide()},f.prototype._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},f.prototype._getConfig=function(t){return t=e.extend({},this.constructor.Default,e(this.element).data(),t),t.delay&&"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),s.typeCheckConfig(n,t,this.constructor.DefaultType),t},f.prototype._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},f._jQueryInterface=function(t){return this.each(function(){var n=e(this).data(l),i="object"===("undefined"==typeof t?"undefined":o(t))&&t;if((n||!/dispose|hide/.test(t))&&(n||(n=new f(this,i),e(this).data(l,n)),"string"==typeof t)){if(void 0===n[t])throw new Error('No method named "'+t+'"');n[t]()}})},r(f,null,[{key:"VERSION",get:function(){return a}},{key:"Default",get:function(){return d}},{key:"NAME",get:function(){return n}},{key:"DATA_KEY",get:function(){return l}},{key:"Event",get:function(){return _}},{key:"EVENT_KEY",get:function(){return h}},{key:"DefaultType",get:function(){return p}}]),f}();return e.fn[n]=C._jQueryInterface,e.fn[n].Constructor=C,e.fn[n].noConflict=function(){return e.fn[n]=f,C._jQueryInterface},C}(jQuery));(function(t){var s="popover",l="4.0.0-alpha.6",h="bs.popover",f="."+h,u=t.fn[s],c=t.extend({},a.Default,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),d=t.extend({},a.DefaultType,{content:"(string|element|function)"}),p={FADE:"fade",SHOW:"show"},g={TITLE:".popover-title",CONTENT:".popover-content"},m={HIDE:"hide"+f,HIDDEN:"hidden"+f,SHOW:"show"+f,SHOWN:"shown"+f,INSERTED:"inserted"+f,CLICK:"click"+f,FOCUSIN:"focusin"+f,FOCUSOUT:"focusout"+f,MOUSEENTER:"mouseenter"+f,MOUSELEAVE:"mouseleave"+f},_=function(a){function u(){return i(this,u),e(this,a.apply(this,arguments))}return n(u,a),u.prototype.isWithContent=function(){return this.getTitle()||this._getContent()},u.prototype.getTipElement=function(){return this.tip=this.tip||t(this.config.template)[0]},u.prototype.setContent=function(){var e=t(this.getTipElement());this.setElementContent(e.find(g.TITLE),this.getTitle()),this.setElementContent(e.find(g.CONTENT),this._getContent()),e.removeClass(p.FADE+" "+p.SHOW),this.cleanupTether()},u.prototype._getContent=function(){return this.element.getAttribute("data-content")||("function"==typeof this.config.content?this.config.content.call(this.element):this.config.content)},u._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(h),i="object"===("undefined"==typeof e?"undefined":o(e))?e:null;if((n||!/destroy|hide/.test(e))&&(n||(n=new u(this,i),t(this).data(h,n)),"string"==typeof e)){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})},r(u,null,[{key:"VERSION",get:function(){return l}},{key:"Default",get:function(){return c}},{key:"NAME",get:function(){return s}},{key:"DATA_KEY",get:function(){return h}},{key:"Event",get:function(){return m}},{key:"EVENT_KEY",get:function(){return f}},{key:"DefaultType",get:function(){return d}}]),u}(a);return t.fn[s]=_._jQueryInterface,t.fn[s].Constructor=_,t.fn[s].noConflict=function(){return t.fn[s]=u,_._jQueryInterface},_})(jQuery)}()}).call(e,n(1))},function(t,e){}]);
\ No newline at end of file
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 57dc7a5..b16d88e 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -2,7 +2,7 @@
 <html lang='en'>
 <head>
   <title>{% block title %}{% endblock %}</title>
-  <link href="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.min.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
@@ -57,10 +57,8 @@
 
 </div> <!--end bodycontent-->
 {% block jscripts %}
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
-<script type="text/javascript" src="{{
-  url_for('static',filename='fedora-bootstrap/fedora-bootstrap.js')}}"></script>
+<script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
+<script src="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.min.js') }}"></script>
 <script src="https://unpkg.com/react@15/dist/react{% if not config.DEBUG %}.min{% endif %}.js"></script>
 <script src="https://unpkg.com/react-dom@15/dist/react-dom{% if not config.DEBUG %}.min{% endif %}.js"></script>
 {% endblock %}

From 98227938cf4e5a10c0a8d5038698a2baf6bc92dd Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 17 2017 09:04:46 +0000
Subject: [PATCH 838/1001] Refactor the HTML structure in the templates


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index ec6f499..4f2a177 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -69,6 +69,7 @@
       font-family: 'Open Sans', sans-serif;
       min-height: 100px;
       border-bottom: 1px solid #ddd;
+      padding-top: 10px;
     }
 
     /*.header .dropdown.edit {
@@ -334,7 +335,15 @@ font-size: 32pt;
 .navbar-nav > li.idle-2years  > a { color: #BBB; }
 .navbar-nav > li.idle-5years  > a { color: #CCC; }
 
-.nav {
+#vertical-navbar {
+  position: absolute;
+}
+
+#vertical-navbar .navbar {
+  padding: 0;
+}
+
+#vertical-navbar .nav {
   background-color: #fcfcfc;
   min-height: 180px; 
   padding: 1.5rem;
@@ -351,6 +360,7 @@ font-size: 32pt;
     margin-left: 0px !important;
 }
 
+
 /* end fedora-bootstrap nav overrides */
 
 .media-object {
diff --git a/hubs/templates/errors/hub.html b/hubs/templates/errors/hub.html
index 36506e1..ad55d2a 100644
--- a/hubs/templates/errors/hub.html
+++ b/hubs/templates/errors/hub.html
@@ -1,6 +1,6 @@
 {% extends "hubs.html" %}
 
-{% block hub_content %}
+{% block content %}
 
 <p class="text-center">{{ msg }}</p>
 
diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html
index 4040938..50b5710 100644
--- a/hubs/templates/groups.html
+++ b/hubs/templates/groups.html
@@ -1,21 +1,16 @@
 {% extends "master.html" %}
 
 {% block title %}Groups{% endblock %}
-{% block content %}
 
-<header class="p-t-2">
-	<div class="container">
-    <div class="col-md-8">
-      <h2 class="team m-b-0">Groups</h2>
-      <h5 class="m-t-1 m-b-1">Summary of available team hubs</h5>
-    </div>
-    <div class="col-md-4 header-right">
-    </div>
-</header>
 
-<div class="container">
-  <div class="row">
-  </div>
+{% block header %}
+  <h1 class="team">Groups</h2>
+  <p>Summary of available team hubs</p>
+{% endblock header %}
+
+
+{% block content %}
+
   <div class="row">
     <div class="col-md-12">
       {% for group in promoted %}
@@ -61,4 +56,5 @@
     </div>
   </div>
 </div>
-{% endblock %}
+
+{% endblock content %}
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 2851568..f4fb7d2 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -1,191 +1,130 @@
 {% extends "master.html" %}
 
 {% block title %}{{ hub.name }}{% endblock %}
-{% block content %}
 
-<div class="row p-t-0">
-  <header class="p-t-1">
-    <nav class="navbar navbar-light col-md-2">
-      <button type="button" class="navbar-toggler hidden-md-up"
-        type="button" data-toggle="collapse" data-target="#vertical-navbar">
-        <span class="sr-only">Toggle navigation</span>
-        <i class="fa fa-bars"></i>
-      </button>
-
-      <!-- Collect the nav links, forms, and other content for toggling -->
-      {% if g.auth.logged_in %}
-      <div id="vertical-navbar">
-        <ul class="nav navbar-nav p-r-1">
-          <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
-            <a class="nav-link" href="{{ url_for("hub", name=g.auth.user.username) }}">me</a></li>
-          <li class="p-x-1 nav-item"><a class="nav-link" href="{{ url_for("stream", name=g.auth.user.username) }}">My Stream</a></li>
-          {% for hub in g.auth.user.bookmarks %}
-            <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
-              <a class="nav-link" href="{{ url_for("hub", name=hub.name) }}">{{hub.name}}</a></li>
-          {% endfor %}
-          <!-- At the end of the list, tack on a link to all groups -->
-          <li class="p-x-1 nav-item"><a class="nav-link" href="{{ url_for("groups") }}">all</a></li>
-        </ul>
-      </div><!-- /.navbar-collapse -->
-      {% endif %}
-    </nav>
-  
-    <div class="col-md-10">
-      <div class="row">
-        
-        <!-- Left side of header -->
-        <div class="col-md-{{ hub.config.left_width }}">
-          {% if hub.user_hub %}
-          <img src="{{ hub.config.avatar }}" class="avatar" />
-          <h2 class="user m-b-0">{{ hub.name }}</h2>
-          <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
-          <div class="clearfix"></div>
-          {% else %}
-          <h2 class="team">{{ hub.name }}</h2>
-          <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
-          {% endif %}
-        </div>
+
+{% block header %}
         
-        <!-- right side of header -->
-        <div class="col-md-{{ hub.config.right_width }} header-right">
-          {% if hub.allows(g.auth.user, "config") %}
-          <div style="text-align:center">
-            <button class="btn btn-secondary" data-toggle="modal" data-target="#settings-modal">
-              <i class="fa fa-cog" aria-hidden="true"></i>
-              hub settings
-            </button>
-            {% if not edit %}
-            <a href="{{ url_for('hub_edit', name=hub.name) }}" class="btn btn-secondary">
-              <i class="fa fa-pencil" aria-hidden="true"></i>
-              edit page layout
-            </a>
-            {% else %}
-            <button class="btn btn-primary" href="#" id="save_edits_btn">
-              <i class="fa fa-download" aria-hidden="true"></i>
-              Save changes
-            </button>
-            {% endif %}
-          </div>
-          {% endif %}
-        </div>
+<!-- Left side of header -->
+<div class="col-md-{{ hub.config.left_width }}">
+  {% if hub.user_hub %}
+  <img src="{{ hub.config.avatar }}" class="avatar" />
+  <h2 class="user m-b-0">{{ hub.name }}</h2>
+  <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
+  <div class="clearfix"></div>
+  {% else %}
+  <h2 class="team">{{ hub.name }}</h2>
+  <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
+  {% endif %}
+</div>
         
-      </div>
-      
-      <div class="row p-t-2">
-        {%- with messages = get_flashed_messages(with_categories=true) -%}
-        {%- if category, messages -%}
-          <div class="col-md-6 col-md-offset-3">
-            <ul id="flashes" class="list-group">
-            {%- for category, message in messages -%}
-              <div class="alert {%
-                if category == 'error' %}alert-warning{%
-                else %}alert-info{%
-                endif %} alert-dismissible" role="alert">
-                <button type="button" class="close" data-dismiss="alert"
-                  aria-label="Close">
-                  <span aria-hidden="true">&times;</span>
-                  <span class="sr-only">Close</span>
-                </button>
-                {{ message }}
-              </div>
-            {%- endfor -%}
-            </ul>
-          </div>
-        {%- endif -%}
-        {%- endwith -%}
-      </div>
+<!-- right side of header -->
+<div class="col-md-{{ hub.config.right_width }} header-right">
+  {% if hub.allows(g.auth.user, "config") %}
+  <div style="text-align:center">
+    <button class="btn btn-secondary" data-toggle="modal" data-target="#settings-modal">
+      <i class="fa fa-cog" aria-hidden="true"></i>
+      hub settings
+    </button>
+    {% if not edit %}
+    <a href="{{ url_for('hub_edit', name=hub.name) }}" class="btn btn-secondary">
+      <i class="fa fa-pencil" aria-hidden="true"></i>
+      edit page layout
+    </a>
+    {% else %}
+    <button class="btn btn-primary" href="#" id="save_edits_btn">
+      <i class="fa fa-download" aria-hidden="true"></i>
+      Save changes
+    </button>
+    {% endif %}
+  </div>
+  {% endif %}
+</div>
         
-    </div>
-  </header>
-
-  <div class="row">
-    <div class="col-md-offset-2">
-      {% block hub_content %}
-      <div class="row">
-        <div class="col-md-{{ hub.config.left_width }}">
-          <!--
-            First, before the proper widgets.. a cobweb built-in widget.
-            https://pagure.io/fedora-hubs/issue/133
-          -->
-          {% if hub.archived or hub.last_refreshed | days_since > 31 %}
-          <ul class="media-list">
-            <li class="media">
-              <div class="media-left">
-              {% if hub.archived %}
-                <img class="media-object square-32"
-                  src="{{ url_for('static', filename='img/archived.png') }}"/>
-              {% else %}
-                <img class="media-object square-32"
-                  src="{{ url_for('static', filename='img/cobweb.png') }}"/>
-              {% endif %}
-              </div>
-              <div class="media-body">
-                {% if hub.archived %}
-                This hub has been archived and locked.
-                {% else %}
-                Cobweb alert!  This hub was last active {{
-                  hub.last_refreshed | days_since }} days ago.
-                {% endif %}
-              </div>
-            </li>
-          </ul>
-          {% endif %}
+{% endblock header %}
 
-          {% if edit %}
-          <div id='add-widget-left' class='widget row'>
-            <div class="card">
-              <div class="card-block">
-                <h4>
-                <a href="{{ url_for("hub_add_widget", name=hub.name) }}?position=left" class="add_widget">
-                  <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
-                </a>
-                </h4>
-              </div>
-            </div>
-          </div>
-          {% endif %}
 
-          <div id="left_widgets">
-            {% for widget in widgets["left"] %}
-            <div id="widget-{{ widget.idx }}" class="widget row"
-                 data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
-                 ></div>
-            {% endfor %}
-          </div>
-        </div>
 
-        <div class="col-md-{{ hub.config.right_width }}">
-          {% if edit %}
-          <div id='add-widget-right' class='widget row'>
-            <div class="card">
-              <div class="card-block">
-                <h4>
-                <a href="{{ url_for("hub_add_widget", name=hub.name) }}?position=right" class="add_widget">
-                <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
-                </a>
-                </h4>
-              </div>
-            </div>
-          </div>
-          {% endif %}
+{% block content %}
 
-          <div id="right_widgets">
-            {% for widget in widgets["right"] %}
-            <div id="widget-{{ widget.idx }}" class="widget row"
-                 data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
-                 ></div>
-            {% endfor %}
-          </div>
+<div class="row">
+  <div class="col-md-{{ hub.config.left_width }}">
+    <!--
+      First, before the proper widgets.. a cobweb built-in widget.
+      https://pagure.io/fedora-hubs/issue/133
+    -->
+    {% if hub.archived or hub.last_refreshed | days_since > 31 %}
+    <ul class="media-list">
+      <li class="media">
+        <div class="media-left">
+        {% if hub.archived %}
+          <img class="media-object square-32"
+            src="{{ url_for('static', filename='img/archived.png') }}"/>
+        {% else %}
+          <img class="media-object square-32"
+            src="{{ url_for('static', filename='img/cobweb.png') }}"/>
+        {% endif %}
         </div>
+        <div class="media-body">
+          {% if hub.archived %}
+          This hub has been archived and locked.
+          {% else %}
+          Cobweb alert!  This hub was last active {{
+            hub.last_refreshed | days_since }} days ago.
+          {% endif %}
+        </div>
+      </li>
+    </ul>
+    {% endif %}
+
+    {% if edit %}
+    <div id='add-widget-left' class='widget row'>
+      <div class="card">
+        <div class="card-block">
+          <h4>
+          <a href="{{ url_for("hub_add_widget", name=hub.name) }}?position=left" class="add_widget">
+            <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
+          </a>
+          </h4>
+        </div>
+      </div>
+    </div>
+    {% endif %}
+
+    <div id="left_widgets">
+      {% for widget in widgets["left"] %}
+      <div id="widget-{{ widget.idx }}" class="widget row"
+           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
+           ></div>
+      {% endfor %}
+    </div>
+  </div>
 
-      </div>  <!-- /row -->
-      {% endblock hub_content %}
-    </div>  <!-- /col-md-offset-2 -->
-  </div>  <!-- /row -->
-
-
-</div>
+  <div class="col-md-{{ hub.config.right_width }}">
+    {% if edit %}
+    <div id='add-widget-right' class='widget row'>
+      <div class="card">
+        <div class="card-block">
+          <h4>
+          <a href="{{ url_for("hub_add_widget", name=hub.name) }}?position=right" class="add_widget">
+          <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
+          </a>
+          </h4>
+        </div>
+      </div>
+    </div>
+    {% endif %}
+
+    <div id="right_widgets">
+      {% for widget in widgets["right"] %}
+      <div id="widget-{{ widget.idx }}" class="widget row"
+           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
+           ></div>
+      {% endfor %}
+    </div>
+  </div>
 
+</div>  <!-- /row -->
 
 <div id="settings-modal" class="modal fade" tabindex="-1" role="dialog">
 </div>
@@ -196,21 +135,16 @@
   </div>
 </div>
 
-{% endblock %}
+{% endblock content %}
+
+
 
 {% block jscripts %}
 {{ super() }}
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/utils.js') }}"></script>
-<script type="text/javascript"
-  src ="{{url_for('static', filename='js/build/common.js')}}"></script>
-<script type="text/javascript"
-  src ="{{url_for('static', filename='js/build/Hubs.js')}}"></script>
 
 {% if edit %}
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/Sortable.min.js') }}"></script>
-<script type="text/javascript">
+<script src="{{ url_for('static', filename='js/Sortable.min.js') }}"></script>
+<script>
 
 function make_widget_sortable() {
   var byId = function (id) { return document.getElementById(id); }
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index b16d88e..285cd08 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -14,7 +14,8 @@
       href="{{ url_for('static', filename='img/favicon.png') }}">
 </head>
 <body>
-<div class="masthead">
+
+<div class="masthead container-fluid">
   <div class="row p-a-0">
     <div class="col-xs-4" id="logo">
       <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs" class="p-l-1">
@@ -51,16 +52,92 @@
     </div>
   </div>
 </div>
-<div class="bodycontent">
 
-{% block content %}{% endblock %}
+<header class="container-fluid">
+  <div class="row">
+
+  <!-- Left vertical nav menu -->
+  <div class="col-md-2" id="vertical-navbar">
+    <nav class="navbar navbar-light">
+      <button type="button" class="navbar-toggler hidden-md-up"
+        type="button" data-toggle="collapse" data-target="#vertical-navbar-menu">
+        <span class="sr-only">Toggle navigation</span>
+        <i class="fa fa-bars"></i>
+      </button>
+
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      <div id="vertical-navbar-menu" class="collapse in">
+        <ul class="nav navbar-nav p-r-1 rounded">
+          {% if g.auth.logged_in %}
+          <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
+            <a class="nav-link" href="{{ url_for("hub", name=g.auth.user.username) }}">me</a></li>
+          <li class="p-x-1 nav-item"><a class="nav-link" href="{{ url_for("stream", name=g.auth.user.username) }}">My Stream</a></li>
+          {% for hub in g.auth.user.bookmarks %}
+            <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
+              <a class="nav-link" href="{{ url_for("hub", name=hub.name) }}">{{hub.name}}</a></li>
+          {% endfor %}
+          {% endif %}
+          <!-- At the end of the list, tack on a link to all groups -->
+          <li class="p-x-1 nav-item"><a class="nav-link" href="{{ url_for("groups") }}">all</a></li>
+        </ul>
+      </div><!-- /.navbar-collapse -->
+    </nav>
+  </div>
+
+  <div class="col-md-offset-2 col-md-10">
+    <!-- Header -->
+    {% block header %}
+    {% endblock header %}
+  </div>
+
+  </div> <!-- /.row -->
+</header>
+
+<div class="bodycontent container-fluid">
+  <div class="row">
+    <div class="col-md-offset-2">
+
+    <!-- Flash messages -->
+    <div class="row p-t-2">
+      {%- with messages = get_flashed_messages(with_categories=true) -%}
+      {%- if category, messages -%}
+        <div class="col-md-6 col-md-offset-3">
+          <ul id="flashes" class="list-group">
+          {%- for category, message in messages -%}
+            <div class="alert {%
+              if category == 'error' %}alert-warning{%
+              else %}alert-info{%
+              endif %} alert-dismissible" role="alert">
+              <button type="button" class="close" data-dismiss="alert"
+                aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+                <span class="sr-only">Close</span>
+              </button>
+              {{ message }}
+            </div>
+          {%- endfor -%}
+          </ul>
+        </div>
+      {%- endif -%}
+      {%- endwith -%}
+    </div>
+
+    <!-- Main content -->
+    {% block content %}
+    {% endblock content %}
+
+    </div>
+  </div>
+</div> <!--end .bodycontent-->
 
-</div> <!--end bodycontent-->
 {% block jscripts %}
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
 <script src="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.min.js') }}"></script>
 <script src="https://unpkg.com/react@15/dist/react{% if not config.DEBUG %}.min{% endif %}.js"></script>
 <script src="https://unpkg.com/react-dom@15/dist/react-dom{% if not config.DEBUG %}.min{% endif %}.js"></script>
+<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
+<script src="{{ url_for('static', filename='js/build/common.js') }}"></script>
+<script src="{{ url_for('static', filename='js/build/Hubs.js') }}"></script>
 {% endblock %}
 
 </body>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index b7ca796..7cfda81 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -1,11 +1,15 @@
 {% extends "master.html" %}
 
 {% block title %}My Stream{% endblock %}
-{% block content %}
-<div class="jumbotron">
+
+
+{% block header %}
   <h1>My Stream</h1>
   <p>Notifications, actions, and other things of interest to me</p>
-</div>
+{% endblock header %}
+
+
+{% block content %}
 
 <div class="row">
   <div class="col-sm-8">
@@ -50,34 +54,17 @@
   </div>
 
   <div class="col-sm-4">
-    <div id="right_widgets">
-      {% for widget in widgets["right"] %}
-      <div id="widget-{{ widget.idx }}" class="widget row"
-           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
-           ></div>
-      {% endfor %}
-    </div>
+    <!-- put some content here! :) -->
   </div>
 </div>
 
-<style>
- .jumbotron {
-   margin-bottom: 0;
- }
- .nav-tabs {
-   list-style: none;
- }
-</style>
-{% endblock %}
+{% endblock content %}
+
 
 {% block jscripts %}
 {{ super() }}
-<script type="text/javascript" src="{{
-  url_for('static', filename='js/utils.js') }}"></script>
-<script type="text/javascript"
-  src ="{{url_for('static', filename='js/build/common.js')}}"></script>
 <script type="text/javascript"
-  src ="{{url_for('static', filename='js/build/Feed.js')}}"></script>
+  src="{{url_for('static', filename='js/build/Feed.js')}}"></script>
 <script>
   function setup_feeds(actions, saved, saveUrl) {
     var streamFeed = React.createElement(Feed, {

From bfae30d7fae41424ffc3675d69bc1e0961936ab9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 17 2017 09:04:46 +0000
Subject: [PATCH 839/1001] Adapt to the newer fedora-bootstrap


---

diff --git a/hubs/static/client/app/components/Dropdown.jsx b/hubs/static/client/app/components/Dropdown.jsx
index ae1872c..efa6201 100644
--- a/hubs/static/client/app/components/Dropdown.jsx
+++ b/hubs/static/client/app/components/Dropdown.jsx
@@ -62,7 +62,7 @@ export default class Dropdown extends React.Component {
     }
 
     return (
-      <div className="pull-right">
+      <div className="float-right">
        {saveBtn}
         {deleteBtn}
       </div>
diff --git a/hubs/static/client/app/components/Modal.jsx b/hubs/static/client/app/components/Modal.jsx
index 1ba31b1..5aa6749 100644
--- a/hubs/static/client/app/components/Modal.jsx
+++ b/hubs/static/client/app/components/Modal.jsx
@@ -5,6 +5,9 @@ export default class Modal extends React.Component {
 
   constructor(props) {
     super(props);
+    this.state = {
+      open: false,
+    }
     this.onShow = this.onShow.bind(this);
     this.onShown = this.onShown.bind(this);
     this.onHide = this.onHide.bind(this);
@@ -57,15 +60,23 @@ export default class Modal extends React.Component {
     if (!this.domNode) { return; }
     var domNode = $(this.domNode);
     if (callback) { domNode.one("shown.bs.modal", callback); }
-    $(this.domNode).modal("show");
+    domNode.modal("show");
   }
 
   componentWillUpdate(nextProps, nextState) {
-    if (!nextProps.open) { this.hide(); }
+    if (!this.domNode) { return; }
+    const domNode = $(this.domNode);
+    if (domNode.is(":visible") && !nextProps.open) {
+      this.hide();
+    }
   }
 
   componentDidUpdate() {
-    if (this.props.open) { this.show(); }
+    if (!this.domNode) { return; }
+    const domNode = $(this.domNode);
+    if (this.props.open && !domNode.is(":visible")) {
+      this.show();
+    }
   }
 
   getModalBody() {
@@ -83,8 +94,8 @@ export default class Modal extends React.Component {
         <div className="modal-dialog" role="document">
           <div className="modal-content">
             <div className="modal-header">
-              <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
               <h4 className="modal-title">{this.props.title}</h4>
+              <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
             </div>
             <div className="modal-body">
               {this.getModalBody()}
diff --git a/hubs/static/client/app/components/Tab.jsx b/hubs/static/client/app/components/Tab.jsx
index 976e04b..3dd8b5a 100644
--- a/hubs/static/client/app/components/Tab.jsx
+++ b/hubs/static/client/app/components/Tab.jsx
@@ -3,10 +3,12 @@ import React from 'react';
 
 export default class Tab extends React.Component {
   render() {
+    var linkClass = `nav-link ${this.props.tabLinkClass}`;
+    if (this.props.active) { linkClass += " active"; }
     return (
-      <li role="presentation">
+      <li className="nav-item">
         <a href="#" role="tab"
-           className={"nav-link" + (this.props.active ? " active" : "")}
+           className={linkClass}
            onClick={this.props.linkClicked}
            >
           {this.props.children}
@@ -16,6 +18,12 @@ export default class Tab extends React.Component {
   }
 }
 
+Tab.propTypes = {
+  tabLinkClass: React.PropTypes.string,
+};
+Tab.defaultProps = {
+  tabLinkClass: '',
+};
 
 
 // vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/TabSet.jsx b/hubs/static/client/app/components/TabSet.jsx
index c53bc31..e366f37 100644
--- a/hubs/static/client/app/components/TabSet.jsx
+++ b/hubs/static/client/app/components/TabSet.jsx
@@ -41,7 +41,7 @@ export default class TabSet extends React.Component {
     return (
       <div {...this.props.tabWrapperProps}>
         <ul role="tablist"
-            className={"nav nav-tabs " + this.props.tabListClass}
+            className={`nav nav-${this.props.tabType} ${this.props.tabListClass}`}
             >
           {tabLinks}
         </ul>
@@ -58,11 +58,13 @@ export default class TabSet extends React.Component {
 
 TabSet.propTypes = {
   tabWrapperProps: React.PropTypes.object,
+  tabType: React.PropTypes.string,
   tabListClass: React.PropTypes.string,
   tabContentClass: React.PropTypes.string,
 };
 TabSet.defaultProps = {
   tabWrapperProps: {},
+  tabType: 'tabs',
   tabListClass: '',
   tabContentClass: '',
 };
diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
index f3993d7..01c079f 100644
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ b/hubs/static/client/app/core/HubConfig.jsx
@@ -157,6 +157,9 @@ export default class HubConfig extends React.Component {
         <div className="modal-dialog modal-lg" role="document">
           <div className="modal-content">
               <div className="modal-header">
+                <h5 className="modal-title">
+                  <FormattedMessage {...messages.title} />
+                </h5>
                 <button
                   type="button"
                   className="close"
@@ -166,60 +169,61 @@ export default class HubConfig extends React.Component {
                   >
                   <span aria-hidden="true">&times;</span>
                 </button>
-                <h4 className="modal-title">
-                  <FormattedMessage {...messages.title} />
-                </h4>
               </div>
-              <div className="modal-body">
-                <div className="row">
-                  <TabSet
-                    tabWrapperProps={{
-                      className: "d-flex",
-                      style: {display: "flex"},
-                      }}
-                    tabListClass="col-md-3"
-                    tabContentClass="col-md-9"
-                    >
-                    <GeneralPanel
-                      hubConfig={this.state.hubConfig}
-                      generalConfig={this.state.generalConfig}
-                      tabTitle={<FormattedMessage {...messages.general} />}
-                      handleChange={this.handleChange}
-                      loading={this.state.loading}
-                      />
-                    <UserPanel
-                      users={this.state.users.owner}
-                      generalConfig={this.state.generalConfig}
-                      role="owner"
-                      handleChange={this.handleUserChange}
-                      tabTitle={<FormattedMessage {...messages.owners} />}
-                      loading={this.state.loading}
-                      urls={this.props.urls}
-                      />
-                    <UserPanel
-                      users={this.state.users.member}
-                      generalConfig={this.state.generalConfig}
-                      role="member"
-                      handleChange={this.handleUserChange}
-                      tabTitle={<FormattedMessage {...messages.members} />}
-                      loading={this.state.loading}
-                      urls={this.props.urls}
-                      />
-                    <ChatPanel
-                      hubConfig={this.state.hubConfig}
-                      generalConfig={this.state.generalConfig}
-                      tabTitle={<FormattedMessage {...messages.chat} />}
-                      handleChange={this.handleChange}
-                      loading={this.state.loading}
-                      />
-                    <NotImplementedPanel
-                      tabTitle={<FormattedMessage {...messages.other} />}
-                      loading={this.state.loading}
-                      />
-                  </TabSet>
-                </div>
+              <div className="modal-body p-0">
+                <TabSet
+                  tabWrapperProps={{className: "row pt-0"}}
+                  tabListClass="flex-md-column justify-content-center justify-content-md-start col-md-3 pt-2 pt-md-3 pb-md-4 pr-md-0 pl-md-2"
+                  tabLinkClass="my-md-2"
+                  tabContentClass="col-md-9 p-3 pb-4"
+                  >
+                  <GeneralPanel
+                    hubConfig={this.state.hubConfig}
+                    generalConfig={this.state.generalConfig}
+                    tabTitle={<FormattedMessage {...messages.general} />}
+                    handleChange={this.handleChange}
+                    loading={this.state.loading}
+                    />
+                  <UserPanel
+                    users={this.state.users.owner}
+                    generalConfig={this.state.generalConfig}
+                    role="owner"
+                    handleChange={this.handleUserChange}
+                    tabTitle={<FormattedMessage {...messages.owners} />}
+                    loading={this.state.loading}
+                    urls={this.props.urls}
+                    />
+                  <UserPanel
+                    users={this.state.users.member}
+                    generalConfig={this.state.generalConfig}
+                    role="member"
+                    handleChange={this.handleUserChange}
+                    tabTitle={<FormattedMessage {...messages.members} />}
+                    loading={this.state.loading}
+                    urls={this.props.urls}
+                    />
+                  <ChatPanel
+                    hubConfig={this.state.hubConfig}
+                    generalConfig={this.state.generalConfig}
+                    tabTitle={<FormattedMessage {...messages.chat} />}
+                    handleChange={this.handleChange}
+                    loading={this.state.loading}
+                    />
+                  <NotImplementedPanel
+                    tabTitle={<FormattedMessage {...messages.other} />}
+                    loading={this.state.loading}
+                    />
+                </TabSet>
               </div>
               <div className="modal-footer">
+                { this.state.error &&
+                  <div
+                    className="alert alert-danger my-0 mx-3 py-1 px-2"
+                    role="alert"
+                    >
+                    { this.state.error }
+                  </div>
+                }
                 <span
                   className="loading"
                   style={this.state.loading ? {display: "inline-block"} : {display: "none"}}
@@ -232,19 +236,6 @@ export default class HubConfig extends React.Component {
                   >
                   <FormattedMessage {...messages.close} />
                 </button>
-                { this.state.error &&
-                  <div
-                    className="alert alert-danger" role="alert"
-                    style={{
-                      margin: "0em 1em",
-                      //textAlign: "center",
-                      display: "inline-block",
-                      padding: "0.375rem",
-                      }}
-                    >
-                    { this.state.error }
-                  </div>
-                }
               </div>
           </div>
         </div>
diff --git a/hubs/static/client/app/core/HubConfigPanelChat.jsx b/hubs/static/client/app/core/HubConfigPanelChat.jsx
index 458fd36..e15a141 100644
--- a/hubs/static/client/app/core/HubConfigPanelChat.jsx
+++ b/hubs/static/client/app/core/HubConfigPanelChat.jsx
@@ -79,7 +79,7 @@ export default class ChatPanel extends React.Component {
             />
           <p className="form-text text-muted">
             <FormattedMessage {...messages.example} tagName="strong" />
-            <span style={{marginLeft: "0.5em"}}>#fedora-devel</span>
+            <span className="ml-2">#fedora-devel</span>
           </p>
         </div>
         <div className="form-group">
diff --git a/hubs/static/client/app/core/HubConfigPanelUser.jsx b/hubs/static/client/app/core/HubConfigPanelUser.jsx
index 3565760..7ef5175 100644
--- a/hubs/static/client/app/core/HubConfigPanelUser.jsx
+++ b/hubs/static/client/app/core/HubConfigPanelUser.jsx
@@ -133,8 +133,10 @@ export default class UserPanel extends React.Component {
             <hr />
           </div>
         }
-        <form className="form-inline" onSubmit={this.handleAdd}
-              style={{marginBottom: "1em"}}>
+        <form
+          className="form-inline mb-3"
+          onSubmit={this.handleAdd}
+          >
           <div className="form-group">
             <FormattedMessage {...messages.add_user}>
               {(message) => (
@@ -154,9 +156,8 @@ export default class UserPanel extends React.Component {
             </FormattedMessage>
             </div>
           <button
-            className="btn btn-primary"
+            className="btn btn-primary ml-3"
             disabled={this.props.loading}
-            style={{marginLeft: "1em"}}
             >
             <FormattedMessage {...messages.add} />
           </button>
diff --git a/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx b/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
index cbb24b3..e7365a9 100644
--- a/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
+++ b/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
@@ -146,9 +146,9 @@ export default class ModalAllRequests extends Modal {
     }
     return (
       <div>
-        <form className="row form-horizontal" method="post"
+        <form className="" method="post"
               action={this.props.urls.search} onSubmit={this.onSubmit}>
-          <div className="form-group">
+          <div className="form-group row">
             <label htmlFor="meetingname" className="col-sm-4 control-label">
               <FormattedMessage {...messages.search_meeting_name} />
             </label>
@@ -157,7 +157,7 @@ export default class ModalAllRequests extends Modal {
                      onChange={this.handleChange} />
             </div>
           </div>
-          <div className="form-group">
+          <div className="form-group row">
             <label htmlFor="startdate" className="col-sm-4 control-label">
               <FormattedMessage {...messages.search_between_dates} />
             </label>
@@ -170,7 +170,7 @@ export default class ModalAllRequests extends Modal {
                      onChange={this.handleChange} />
             </div>
           </div>
-          <div className="form-group">
+          <div className="form-group row">
             <label htmlFor="people" className="col-sm-4 control-label">
               <FormattedMessage {...messages.search_people} />
             </label>
@@ -182,12 +182,11 @@ export default class ModalAllRequests extends Modal {
                 />
             </div>
           </div>
-          <div className="form-group">
-            <div className="col-sm-offset-4 col-sm-8">
+          <div className="form-group row">
+            <div className="offset-sm-4 col-sm-8">
               <button
                 type="submit"
-                className="btn btn-primary"
-                style={{marginRight: "1em"}}
+                className="btn btn-primary mr-3"
                 >
                 <FormattedMessage {...messages.search_button} />
               </button>
diff --git a/hubs/static/client/app/widgets/halp/ModalRequest.jsx b/hubs/static/client/app/widgets/halp/ModalRequest.jsx
index b6d0860..36ea130 100644
--- a/hubs/static/client/app/widgets/halp/ModalRequest.jsx
+++ b/hubs/static/client/app/widgets/halp/ModalRequest.jsx
@@ -63,7 +63,7 @@ export default class ModalRequest extends Modal {
             <FormattedMessage
               {...messages.zoom_tip2}
               />
-            <ul style={{listStyleType: "none"}}>
+            <ul className="list-unstyled">
               <li className="media">
                 <div className="media-left media-middle">
                   <a href={this.props.data.author.url} target="_blank">
@@ -83,7 +83,7 @@ export default class ModalRequest extends Modal {
             <FormattedMessage
               {...messages.zoom_tip3}
               />
-            <ul style={{listStyleType: "none"}}>
+            <ul className="list-unstyled">
               <a href={this.props.data.context_url}>
                 {this.props.data.context_url.replace(/^https?:\/\//, '')}
               </a>
diff --git a/hubs/static/client/app/widgets/halp/Widget.jsx b/hubs/static/client/app/widgets/halp/Widget.jsx
index 91a2fe8..8d64895 100644
--- a/hubs/static/client/app/widgets/halp/Widget.jsx
+++ b/hubs/static/client/app/widgets/halp/Widget.jsx
@@ -147,10 +147,7 @@ export default class Widget extends React.Component {
             onHubClick={this.onHubClick}
             />
           { this.state.loading ?
-              <div
-                className="loading-circle center-block"
-                style={{display: "block"}}
-                ></div>
+              <div className="loading-circle mx-auto d-block"></div>
             :
               <div className="requests">
                 {requestNodes}
diff --git a/hubs/static/client/app/widgets/halp/getRequestView.jsx b/hubs/static/client/app/widgets/halp/getRequestView.jsx
index 3e0296f..1f7627b 100644
--- a/hubs/static/client/app/widgets/halp/getRequestView.jsx
+++ b/hubs/static/client/app/widgets/halp/getRequestView.jsx
@@ -44,13 +44,14 @@ export default function getRequestView(request, openCallback) {
         </div>
         : null }
         <div className="author media col-sm-12">
-          <div className="media-left media-middle">
-            <a href={request.author.url} target="_blank">
-              <img className="media-object square-32 img-circle"
-                   src={request.author.avatar} />
-            </a>
-          </div>
-          <div className="media-body">
+          <a
+            href={request.author.url} target="_blank"
+            className="d-flex mr-3"
+            >
+            <img className="square-32 img-circle"
+                 src={request.author.avatar} />
+          </a>
+          <div className="media-body align-self-center">
             <a href={request.author.url}>
               {request.author.name}
             </a>
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 4f2a177..2b722b4 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -1,115 +1,96 @@
 @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic);
 
-   body {
-      background-color: #fff;
-    }
+body {
+  background-color: #fff;
+}
 
-    /*.super-header {
-      background: -webkit-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
-      background: -o-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
-      background: -moz-linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
-      background: linear-gradient(rgba(255,255,255,0.4),rgba(255,255,255,0.9),rgba(255,255,255,1));
-      padding: 5px 12px 5px 12px;
-      font-family: 'Open Sans', 'sans-serif';
-      font-size: 12pt;
-    }*/
-
-    .masthead img#chaticon, .masthead img#avatar {
-      height: 30px;
-      width: auto;
-    }
+#navbar-top {
+  background-image: linear-gradient(to bottom,#eee 0%,#ddd 100%);
+  background-repeat: repeat-x;
+}
 
-    .showpointer{cursor:pointer;}
+#navbar-top img.chaticon,
+#navbar-top img.avatar {
+  height: 30px;
+  width: auto;
+}
 
-/*
-    .masthead input {
-      width: 100%;
-      border-radius: 0;
-      font-family: 'Open Sans', sans-serif;
-      padding: 5px;
-      border: 1px solid #d1d3d4;
-    }
+.showpointer {
+  cursor:pointer;
+}
 
-    .masthead .input-group-addon {
-      background-color: #3C6EB4;
-      color: #fff;
-      border: 0;
-      border-radius: 0;
-    }
-*/
-    @media (max-width: 768px) {
-      .masthead .input-group {
-        margin-top: 20px;
-      }
-    }
+@media (max-width: 768px) {
+  .masthead .input-group {
+    margin-top: 20px;
+  }
+}
 
-    #logo { text-align: left; }
+#logo { text-align: left; }
 
 
-    .navbar-default .navbar-toggle {
-      border: none;
-    }
+.navbar-default .navbar-toggle {
+  border: none;
+}
 
-    .navbar-default .navbar-toggle:focus {
-      background-color: none;
-    }
-    @media (max-width:768px) {
-      .header .dropdown.edit {
-        top: 140px !important;
-      }
-      .header h2.team {
-        top: 170px !important;
-      }
-    }
+.navbar-default .navbar-toggle:focus {
+  background-color: none;
+}
+@media (max-width:768px) {
+  .header .dropdown.edit {
+    top: 140px !important;
+  }
+  .header h2.team {
+    top: 170px !important;
+  }
+}
 
-    header {
-      color: #373a3c;
-      background: #f3f3f3 none repeat scroll 0 0;
-      width: 100%;
-      font-family: 'Open Sans', sans-serif;
-      min-height: 100px;
-      border-bottom: 1px solid #ddd;
-      padding-top: 10px;
-    }
+header {
+  color: #373a3c;
+  background: #f3f3f3 none repeat scroll 0 0;
+  width: 100%;
+  font-family: 'Open Sans', sans-serif;
+  border-bottom: 1px solid #ddd;
+  padding-bottom: .5rem;
+}
 
-    /*.header .dropdown.edit {
-      position: absolute;
-      top: 90px;
-      right: 0;
-      z-index: 2;
-    }*/
-    
-    /* line up header with cards below */
-    header .container {
-      padding-left: 1.75rem !important;
-    }
+/*.header .dropdown.edit {
+  position: absolute;
+  top: 90px;
+  right: 0;
+  z-index: 2;
+}*/
 
-    header img.avatar {
-        width: 70px;
-        float: left;
-        margin-right: 15px;
-        display: inline;
-        border: 5px solid #fff;
-    }
+/* line up header with cards below */
+header .container {
+  padding-left: 1.75rem !important;
+}
 
-    header h2 {
-        font-weight: 500;
-        padding-top: .5rem;
-    }
+header img.avatar {
+    width: 70px;
+    float: left;
+    margin-right: 15px;
+    display: inline;
+    border: 5px solid #fff;
+}
 
-    header span.edit {
-      margin: 5px 5px 0 0;
-    }
-    .row {
-      padding-top: 5px;
-      margin: auto 0px;
-    }
-    .padded {
-      padding: 5px;
-    }
-    .medium-wide {
-      width: 300px;
-    }
+header h2 {
+    font-weight: 500;
+    padding-top: .5rem;
+}
+
+header span.edit {
+  margin: 5px 5px 0 0;
+}
+.row {
+  padding-top: 5px;
+  margin: auto 0px;
+}
+.padded {
+  padding: 5px;
+}
+.medium-wide {
+  width: 300px;
+}
 
 @media (max-width: 320px) {
   .medium-wide {
@@ -134,6 +115,13 @@
     }
 
 
+.nav-tabs {
+  list-style: none;
+}
+.nav-tabs a.nav-link {
+  outline: 0;
+}
+
   .loading {
       width: 50px;
       height: 10px;
@@ -160,24 +148,16 @@
 #settings-modal .modal-title {
   line-height: 1;
 }
-#settings-modal .modal-body {
-  padding: 0;
-}
-#settings-modal .modal-body > .row {
-  padding-top: 0;
-}
 #settings-modal .nav {
   border: 0;
   background-color: #eee;
-  padding: 1.5em 0 2.5em 2em;
-  min-height: 0;
 }
-#settings-modal .nav .nav-link {
+#settings-modal .nav-tabs .nav-item {
+  float: none;
+  margin-bottom: 0;
+}
+#settings-modal .nav-tabs .nav-link {
   border: 0;
-  border-radius: 7px 0 0 7px;
-  padding: .4em 1em;
-  margin: 0.5em 0;
-  outline: 0;
 }
 #settings-modal .modal-body h3 {
   margin-bottom: 1em;
@@ -190,79 +170,44 @@
   padding-bottom: 2em;
 }
 
+@media (min-width: 768px) {
+  /* the menu is on the left */
+  #settings-modal .nav .nav-item {
+    margin-bottom: 0;
+  }
+  #settings-modal .nav .nav-link {
+    border-radius: 0.25rem 0 0 0.25rem;
+  }
+}
+
 
 /*
  * Widgets
  */
 
-    .widget-buttons {
-      padding: .5rem;
-    }
-    
-    .widget .widget-buttons a {
-      margin-right: .4rem;
-    }
-
-    .panel {
-      visibility: hidden;
-      max-height: 0px;
-      overflow: hidden;
-      border: 0;
-      border-radius:0px;
-      transition: max-height 0.4s;
-    }
-
-    .panel-visible {
-      visibility: visible;
-      max-height: 100%;
-    }
-
-    .panel-info, .panel-info .panel-heading {
-      background-color: #a07cbc;
-      font-family: 'Open Sans', sans-serif;
-      color: #fff;
-      border: 0;
-    }
-
-    .panel-info .panel-heading h3 {
-      font-weight: 700;
-      font-size: 16px;
-    }
-
-    .panel-info .widget-buttons a, .panel-danger .widget-buttons a {
-      color: #fff;
-    }
-
-    .panel-danger, .panel-danger .panel-heading {
-      background-color: #bd0b0b;
-      font-family: 'Open Sans', sans-serif;
-      color: #fff;
-      border: 0;
-    }
-
-    .panel-danger .panel-heading h3 {
-      font-weight: 700;
-      font-size: 16px;
-    }
-
-    .panel-info .widget-buttons a {
-      color: #fff;
-    }
+.widget {
+  font-family: 'Open Sans', sans-serif;
+  margin-bottom: .5rem;
+}
 
-/* generic widget styling */
-.widget .panel-default > .panel-heading {
-    font-family: 'Open Sans', 'sans-serif';
-    color: #fff;
-    background-color: #a7a9ac;
-    border-radius: 0;
+.widget .card {
+  width: 100%;
 }
 
-.widget .panel-default > .panel-heading h3 {
-    font-weight: 700;
+.widget-buttons {
+  font-size: 10px;
+  position: absolute;
+  top: 0;
+  right: 0;
+  padding: .3rem;
 }
 
-.widget {
-  font-family: 'Open Sans', sans-serif;
+.widget .widget-buttons a {
+  margin-right: .4rem;
+  color: #373a3c;
+}
+.widget .widget-buttons a:hover {
+  text-decoration: none;
 }
 
 /* hub widgets */
@@ -336,29 +281,27 @@ font-size: 32pt;
 .navbar-nav > li.idle-5years  > a { color: #CCC; }
 
 #vertical-navbar {
-  position: absolute;
+  background-color: #fcfcfc;
+  border: 1px solid #dddddd;
 }
-
-#vertical-navbar .navbar {
-  padding: 0;
+@media (min-width: 992px) {
+  #vertical-navbar {
+    position: relative;
+    top: -85px;
+  }
 }
 
-#vertical-navbar .nav {
-  background-color: #fcfcfc;
-  min-height: 180px; 
-  padding: 1.5rem;
+#vertical-navbar a.nav-link {
+  color: #373a3c;
+  font-size: 85%;
 }
 
-/* navbar fedora-bootstrap overrides to make it vertical */
-
-.navbar-nav .nav-item {
-    float: none;
+#vertical-navbar a.nav-link.active {
+  color: white;
+  /*background-color: #373a3c;*/
 }
 
-.navbar-nav .nav-item + .nav-item, .navbar-nav .nav-link + .nav-link {
-    box-shadow: none;
-    margin-left: 0px !important;
-}
+
 
 
 /* end fedora-bootstrap nav overrides */
@@ -442,14 +385,6 @@ font-size: 32pt;
     cursor: pointer;
 }
 
-.pull-right {
-  float: right;
-}
-
-.widget-buttons {
-  font-size: 10px;
-}
-
 .edit_widget {
   cursor: pointer;
 }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index f4fb7d2..c0f1a84 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -5,40 +5,42 @@
 
 {% block header %}
         
-<!-- Left side of header -->
-<div class="col-md-{{ hub.config.left_width }}">
-  {% if hub.user_hub %}
-  <img src="{{ hub.config.avatar }}" class="avatar" />
-  <h2 class="user m-b-0">{{ hub.name }}</h2>
-  <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
-  <div class="clearfix"></div>
-  {% else %}
-  <h2 class="team">{{ hub.name }}</h2>
-  <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
-  {% endif %}
-</div>
-        
-<!-- right side of header -->
-<div class="col-md-{{ hub.config.right_width }} header-right">
-  {% if hub.allows(g.auth.user, "config") %}
-  <div style="text-align:center">
-    <button class="btn btn-secondary" data-toggle="modal" data-target="#settings-modal">
-      <i class="fa fa-cog" aria-hidden="true"></i>
-      hub settings
-    </button>
-    {% if not edit %}
-    <a href="{{ url_for('hub_edit', name=hub.name) }}" class="btn btn-secondary">
-      <i class="fa fa-pencil" aria-hidden="true"></i>
-      edit page layout
-    </a>
+<div class="row">
+
+  <!-- Left side of header -->
+  <div class="col-md-{{ hub.config.left_width }}">
+    {% if hub.user_hub %}
+      <img src="{{ hub.config.avatar }}" class="avatar" />
+      <h2 class="user m-b-0">{{ hub.name }}</h2>
+      <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
+      <div class="clearfix"></div>
     {% else %}
-    <button class="btn btn-primary" href="#" id="save_edits_btn">
-      <i class="fa fa-download" aria-hidden="true"></i>
-      Save changes
-    </button>
+      <h2 class="team">{{ hub.name }}</h2>
+      <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
     {% endif %}
   </div>
-  {% endif %}
+          
+  <!-- right side of header -->
+  <div class="col-md-{{ hub.config.right_width }} text-center align-self-end">
+    {% if hub.allows(g.auth.user, "config") %}
+      <button class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#settings-modal">
+        <i class="fa fa-cog" aria-hidden="true"></i>
+        hub settings
+      </button>
+      {% if not edit %}
+        <a href="{{ url_for('hub_edit', name=hub.name) }}" class="btn btn-sm btn-secondary">
+          <i class="fa fa-pencil" aria-hidden="true"></i>
+          edit page layout
+        </a>
+      {% else %}
+        <button class="btn btn-sm btn-primary" href="#" id="save_edits_btn">
+          <i class="fa fa-download" aria-hidden="true"></i>
+          Save changes
+        </button>
+      {% endif %}
+    {% endif %}
+  </div>
+
 </div>
         
 {% endblock header %}
@@ -307,15 +309,14 @@ function visit_counter() {
   }
 }
 
-function setup_settings(props) {
-  var modal = $('#settings-modal');
-  var settingsPanel = React.createElement(Hubs.HubConfig, props);
-  modal.on('show.bs.modal', function () {
-    ReactDOM.render(settingsPanel, modal.get(0));
-  })
-  modal.on('hidden.bs.modal', function () {
-    ReactDOM.unmountComponentAtNode(modal.get(0));
-  })
+function setup_settings() {
+  var settingsPanel = React.createElement(Hubs.HubConfig, {
+    urls: {
+      config: {{ url_for("hub_config", name=hub.name)|tojson }},
+      suggestUsers: {{ url_for("hub_config_suggest_users", name=hub.name)|tojson }},
+    }
+  });
+  ReactDOM.render(settingsPanel, document.getElementById("settings-modal"));
 }
 
 $(function() {
@@ -323,12 +324,9 @@ $(function() {
 
   setup_widgets();
   setup_edit_btns();
-  setup_settings({
-    urls: {
-        config: {{ url_for("hub_config", name=hub.name)|tojson }},
-        suggestUsers: {{ url_for("hub_config_suggest_users", name=hub.name)|tojson }},
-    }
-  });
+  {% if hub.allows(g.auth.user, "config") %}
+  setup_settings();
+  {% endif %}
 
   {% if edit -%}
   make_widget_sortable();
@@ -348,3 +346,4 @@ $(function() {
 
 </script>
 {% endblock %}
+{# vim: set ts=2 sw=2 et: #}
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 285cd08..cf1af80 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -15,120 +15,143 @@
 </head>
 <body>
 
-<div class="masthead container-fluid">
-  <div class="row p-a-0">
-    <div class="col-xs-4" id="logo">
-      <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Fedora Hubs" class="p-l-1">
-    </div>
-    <div class="col-sm-4 col-sm-push-4 col-xs-8">
-      {% if g.auth.logged_in %}
-        <div class="dropdown pull-xs-right showpointer">
-          <span class="dropdown-toggle m-r-1" type="button" id="dropdownMenu1"
-            data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
-            <img src="{{ g.auth.avatar }}" id="avatar" alt="User Icon"/>
-          </span>
-          <div class="dropdown-menu dropdown-menu-right m-r-1" aria-labelledby="dropdownMenu1">
-            <h6 class="dropdown-header">Account Information</h6>
-            <a href="#" class="dropdown-item">Full Name: {{ g.auth.fullname }}</a>
-            <a href="#" class="dropdown-item">Email: {{ g.auth.email }}</a>
-            <div class="dropdown-divider"></div>
-            <a href="#" class="dropdown-item">Separated link</a>
-          </div>
-        </div>
-        <img id="chaticon" class="pull-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
-      {% else %}
-        Not logged in.  Click to <a href="{{ url_for(
-            'login', next=request.url) }}">login</a>.
-      {% endif %}
-    </div>
-    <div class="col-sm-4 col-sm-pull-4 col-xs-12">
-      <!-- NOT HOOKED UP TO ANYTHING XOXO -->
+<nav class="navbar navbar-toggleable-sm navbar-light" id="navbar-top">
+  <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbar-top-menu" aria-controls="navbar-top" aria-expanded="false" aria-label="Toggle navigation">
+    <span class="navbar-toggler-icon"></span>
+  </button>
+
+  <a class="navbar-brand" href="#">
+    <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Hubs">
+  </a>
+
+  <div class="collapse navbar-collapse" id="navbar-top-menu">
+    <!-- NOT HOOKED UP TO ANYTHING XOXO -->
+    <form class="form-inline mx-auto">
       <div class="input-group">
-        <input type="search" class="form-control" placeholder="Search across all hubs ..." aria-describedby="searchform-addon"></input>
-        <span class="input-group-addon" id="searchform-addon">
-          <span><i class="fa fa-search" aria-hidden="true"></i></span>
+        <input class="form-control" type="text" placeholder="Search across all hubs...">
+        <div class="input-group-btn">
+          <button class="btn btn-secondary" type="submit">
+            <span><i class="fa fa-search" aria-hidden="true"></i></span>
+          </button>
+        </div>
+      </div>
+    </form>
+
+    {% if g.auth.logged_in %}
+    <ul class="navbar-nav ml-auto">
+      <li class="nav-item mr-4">
+        <img class="chaticon pull-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
+      </li>
+      <li class="nav-item dropdown">
+        <span href="#" class="dropdown-toggle showpointer" id="navbar-dropdown-user" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+          <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
         </span>
-    </div>
-    </div>
+        <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbar-dropdown-user">
+          <h6 class="dropdown-header">Account Information</h6>
+          <a href="#" class="dropdown-item">Full Name: {{ g.auth.fullname }}</a>
+          <a href="#" class="dropdown-item">Email: {{ g.auth.email }}</a>
+          <div class="dropdown-divider"></div>
+          <a href="#" class="dropdown-item">Separated link</a>
+        </div>
+      </li>
+    </ul>
+    {% else %}
+    <span class="navbar-text ml-auto">
+      Not logged in.  Click to
+      <a href="{{ url_for('login', next=request.url) }}">login</a>.
+    </span>
+    {% endif %}
+
   </div>
-</div>
 
-<header class="container-fluid">
-  <div class="row">
+</nav>
 
-  <!-- Left vertical nav menu -->
-  <div class="col-md-2" id="vertical-navbar">
-    <nav class="navbar navbar-light">
-      <button type="button" class="navbar-toggler hidden-md-up"
-        type="button" data-toggle="collapse" data-target="#vertical-navbar-menu">
-        <span class="sr-only">Toggle navigation</span>
-        <i class="fa fa-bars"></i>
-      </button>
-
-      <!-- Collect the nav links, forms, and other content for toggling -->
-      <div id="vertical-navbar-menu" class="collapse in">
-        <ul class="nav navbar-nav p-r-1 rounded">
-          {% if g.auth.logged_in %}
-          <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">
-            <a class="nav-link" href="{{ url_for("hub", name=g.auth.user.username) }}">me</a></li>
-          <li class="p-x-1 nav-item"><a class="nav-link" href="{{ url_for("stream", name=g.auth.user.username) }}">My Stream</a></li>
-          {% for hub in g.auth.user.bookmarks %}
-            <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
-              <a class="nav-link" href="{{ url_for("hub", name=hub.name) }}">{{hub.name}}</a></li>
-          {% endfor %}
-          {% endif %}
-          <!-- At the end of the list, tack on a link to all groups -->
-          <li class="p-x-1 nav-item"><a class="nav-link" href="{{ url_for("groups") }}">all</a></li>
-        </ul>
-      </div><!-- /.navbar-collapse -->
-    </nav>
-  </div>
 
-  <div class="col-md-offset-2 col-md-10">
-    <!-- Header -->
-    {% block header %}
-    {% endblock header %}
+<header>
+
+  <!-- Flash messages -->
+  {%- with messages = get_flashed_messages(with_categories=true) -%}
+  {%- if category, messages -%}
+    <div class="row p-t-2">
+      <div class="col-md-6 offset-md-3">
+      {%- for category, message in messages -%}
+        <div class="alert {%
+          if category == 'error' %}alert-warning{%
+          else %}alert-info{%
+          endif %} alert-dismissible" role="alert">
+          <button type="button" class="close" data-dismiss="alert"
+            aria-label="Close">
+            <span aria-hidden="true">&times;</span>
+          </button>
+          {{ message }}
+        </div>
+      {%- endfor -%}
+      </div>
+    </div>
+  {%- endif -%}
+  {%- endwith -%}
+
+  <div class="row">
+    <div class="offset-lg-2 col-lg-10">
+      <!-- Header -->
+      {% block header %}
+      {% endblock header %}
+    </div>
   </div>
 
-  </div> <!-- /.row -->
 </header>
 
-<div class="bodycontent container-fluid">
+
+<!-- main content -->
+<div class="container-fluid">
+
   <div class="row">
-    <div class="col-md-offset-2">
 
-    <!-- Flash messages -->
-    <div class="row p-t-2">
-      {%- with messages = get_flashed_messages(with_categories=true) -%}
-      {%- if category, messages -%}
-        <div class="col-md-6 col-md-offset-3">
-          <ul id="flashes" class="list-group">
-          {%- for category, message in messages -%}
-            <div class="alert {%
-              if category == 'error' %}alert-warning{%
-              else %}alert-info{%
-              endif %} alert-dismissible" role="alert">
-              <button type="button" class="close" data-dismiss="alert"
-                aria-label="Close">
-                <span aria-hidden="true">&times;</span>
-                <span class="sr-only">Close</span>
-              </button>
-              {{ message }}
-            </div>
-          {%- endfor -%}
-          </ul>
-        </div>
-      {%- endif -%}
-      {%- endwith -%}
+    <!-- Left vertical nav menu -->
+    <div class="col-lg-2">
+      <ul class="nav nav-pills flex-lg-column mb-3 rounded" id="vertical-navbar" role="navigation">
+        {% if g.auth.logged_in %}
+        <li class="nav-item">
+          <a class="nav-link {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}"
+             href="{{ url_for("hub", name=g.auth.user.username) }}">
+            <span><i class="fa fa-home" aria-hidden="true"></i></span>
+            My Hub
+          </a>
+        </li>
+        <li class="nav-item">
+          <a class="nav-link" href="{{ url_for("stream", name=g.auth.user.username) }}">
+            <span><i class="fa fa-home" aria-hidden="true"></i></span>
+            My Stream
+          </a>
+        </li>
+        {% for hub in g.auth.user.bookmarks %}
+          <li class='nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
+            <a class="nav-link" href="{{ url_for("hub", name=hub.name) }}">
+              <span><i class="fa fa-bookmark" aria-hidden="true"></i></span>
+              {{hub.name}}
+            </a>
+          </li>
+        {% endfor %}
+        {% endif %}
+        <!-- At the end of the list, tack on a link to all groups -->
+        <li class="nav-item">
+          <a class="nav-link" href="{{ url_for("groups") }}">
+            <span><i class="fa fa-users" aria-hidden="true"></i></span>
+            All groups
+          </a>
+        </li>
+      </ul>
     </div>
 
-    <!-- Main content -->
-    {% block content %}
-    {% endblock content %}
+    <div class="col-lg-10 px-0">
+
+      <!-- Main content -->
+      {% block content %}
+      {% endblock content %}
 
     </div>
   </div>
-</div> <!--end .bodycontent-->
+</div> <!-- /.container-fluid -->
 
 {% block jscripts %}
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
@@ -142,3 +165,4 @@
 
 </body>
 </html>
+{# vim: set ts=2 sw=2 et: #}
diff --git a/hubs/widgets/fedmsgstats/templates/fedmsgstats.html b/hubs/widgets/fedmsgstats/templates/fedmsgstats.html
index d30234e..6c6efe1 100644
--- a/hubs/widgets/fedmsgstats/templates/fedmsgstats.html
+++ b/hubs/widgets/fedmsgstats/templates/fedmsgstats.html
@@ -8,7 +8,7 @@
     <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
   </table>
   </div>
-  <div class="col-sm-5 col-md-12 col-lg-5">
+  <div class="col-sm-5 col-md-12 col-lg-5 align-self-center">
   {% if session['nickname'] != username %}
     <ul class="list-unstyled">
     {% if session['nickname'] in subscribers %}
@@ -17,7 +17,7 @@
     </form></li>
     {% else %}
     <li><form action="{{hub_subscribe_url}}" method="POST">
-        <button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
+        <button class="btn btn-secondary"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
     </form></li>
     {% endif %}
     </ul>
diff --git a/hubs/widgets/githubissues/templates/githubissues.html b/hubs/widgets/githubissues/templates/githubissues.html
index 534e148..31943ae 100644
--- a/hubs/widgets/githubissues/templates/githubissues.html
+++ b/hubs/widgets/githubissues/templates/githubissues.html
@@ -27,7 +27,7 @@
       </td>
       <td>
          <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
-           <button type="button" class="btn btn-default" aria-label="Left Align">
+           <button type="button" class="btn btn-secondary" aria-label="Left Align">
              <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
            </button>
          </a>
diff --git a/hubs/widgets/halp/templates/halp_config.html b/hubs/widgets/halp/templates/halp_config.html
index e64a526..5587c3d 100644
--- a/hubs/widgets/halp/templates/halp_config.html
+++ b/hubs/widgets/halp/templates/halp_config.html
@@ -3,7 +3,7 @@
     <div class="modal-content">
       <div class="modal-body">
         <img src="{{ url_for("static", filename="img/spinner.gif") }}"
-             class="center-block" alt="loading..." />
+             class="mx-auto" alt="loading..." />
       </div>
     </div>
   </div>
diff --git a/hubs/widgets/meetings/templates/meetings.html b/hubs/widgets/meetings/templates/meetings.html
index 42c5c7b..d2ade22 100644
--- a/hubs/widgets/meetings/templates/meetings.html
+++ b/hubs/widgets/meetings/templates/meetings.html
@@ -22,7 +22,7 @@
     </div>
     <div class="col-md-4">
       <a href="https://apps.fedoraproject.org/calendar/ical/calendar/meeting/{{ next.meeting_id }}/">
-        <button class="btn btn-default btn-sm add-calendar">
+        <button class="btn btn-secondary btn-sm add-calendar">
           <strong>Add to calendar</strong>
         </button>
       </a>
@@ -54,8 +54,8 @@
 
 {% block footer %}
 <div class="panel-footer">
-  <div class="row" align="center">
-    <button class="btn btn-default">
+  <div class="text-center">
+    <button class="btn btn-secondary">
       <strong>Request A New Meeting</strong>
     </button>
   </div>
diff --git a/hubs/widgets/memberships/templates/memberships.html b/hubs/widgets/memberships/templates/memberships.html
index 2961e84..621ea9f 100644
--- a/hubs/widgets/memberships/templates/memberships.html
+++ b/hubs/widgets/memberships/templates/memberships.html
@@ -14,7 +14,7 @@
     {% endif %}
   </div>
   {% endfor %}
-  <a href="#" class="btn btn-default" data-toggle="modal" data-target="#membersModal">View All</a>
+  <a href="#" class="btn btn-secondary" data-toggle="modal" data-target="#membersModal">View All</a>
   {% else %}
   {% for member in memberships %}
   <div class="card-block">
@@ -58,7 +58,7 @@
           {% endfor %}
         </div>
         <div class="modal-footer clearfix">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+          <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
         </div>
       </div>
     </div>
diff --git a/hubs/widgets/rules/templates/rules.html b/hubs/widgets/rules/templates/rules.html
index c5b83f0..c52c61c 100644
--- a/hubs/widgets/rules/templates/rules.html
+++ b/hubs/widgets/rules/templates/rules.html
@@ -16,7 +16,7 @@
         </div>
         {% endfor %}
         <br/>
-        <a href="#" class="btn btn-default" data-toggle="modal" data-target="#ownersModal">View All</a>
+        <a href="#" class="btn btn-secondary" data-toggle="modal" data-target="#ownersModal">View All</a>
     {% else %}
       {% for owner in owners %}
         <div class="col-sm-6">
@@ -62,7 +62,7 @@
         {% endfor %}
       </div>
       <div class="modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
       </div>
     </div>
   </div>
diff --git a/hubs/widgets/stats/templates/stats.html b/hubs/widgets/stats/templates/stats.html
index 9e959fc..5dc307e 100644
--- a/hubs/widgets/stats/templates/stats.html
+++ b/hubs/widgets/stats/templates/stats.html
@@ -25,7 +25,7 @@
   {% else %}
   <li>
     <form action="{{hub_subscribe_url}}" method="POST">
-      <button class="btn btn-default">
+      <button class="btn btn-secondary">
         <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
         Subscribe
       </button>
@@ -45,7 +45,7 @@
   {% else %}
   <li>
     <form action="{{hub_star_url}}" method="POST">
-      <button class="btn btn-default">
+      <button class="btn btn-secondary">
         <span class="glyphicon glyphicon-star" aria-hidden="true"></span>
         Star Hub
       </button>
@@ -65,7 +65,7 @@
   {% else %}
   <li>
     <form action="{{hub_join_url}}" method="POST">
-      <button class="btn btn-default">
+      <button class="btn btn-secondary">
         <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
         Join Hub
       </button>
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index 71f8458..a74a757 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -1,5 +1,5 @@
-<div class="card {{ panel_css_class|default('panel-default') }} widget-{{ widget.name }}">
-  <div class="pull-right widget-buttons">
+<div class="card {{ panel_css_class }} widget-{{ widget.name }}">
+  <div class="widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
     <a href="{{ url_for('widget_source', name=widget.name) }}"><span><i class="fa fa-eye" aria-hidden="true"></i></span></a>
     <a href="{{ url_for('%s_root' % widget.name, hub=widget_instance.hub.name, idx=widget_instance.idx) }}">
@@ -7,7 +7,7 @@
     </a>
     <a data-target="#edit_modal" data-toggle="modal" type="button"
         class="edit_widget" data-url="{{ widget_instance.edit_url }}">
-      <span><i class="fa fa-pencil" aria-hidden="true"></i></span>
+      <span><i class="fa fa-cog" aria-hidden="true"></i></span>
     </a>
   </div>
   {% if title %}

From 61f2ab6c784caa47bbaa9ce3f1305419efdaf705 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 17 2017 09:04:46 +0000
Subject: [PATCH 840/1001] Only show the widget configure button if allowed


---

diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index a74a757..de62d35 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -5,10 +5,12 @@
     <a href="{{ url_for('%s_root' % widget.name, hub=widget_instance.hub.name, idx=widget_instance.idx) }}">
         <span><i class="fa fa-external-link" aria-hidden="true"></i></span>
     </a>
+    {% if widget_instance.hub.allows(g.auth.user, "config") %}
     <a data-target="#edit_modal" data-toggle="modal" type="button"
         class="edit_widget" data-url="{{ widget_instance.edit_url }}">
       <span><i class="fa fa-cog" aria-hidden="true"></i></span>
     </a>
+    {% endif %}
   </div>
   {% if title %}
   <div class="card-header">

From 569bfd9c85c83a6e219ca0a7083bbd1d32c6bfa5 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: May 17 2017 09:04:46 +0000
Subject: [PATCH 841/1001] Use react-proptypes, React.PropTypes is deprecated


---

diff --git a/hubs/static/client/app/components/Modal.jsx b/hubs/static/client/app/components/Modal.jsx
index 5aa6749..3b18312 100644
--- a/hubs/static/client/app/components/Modal.jsx
+++ b/hubs/static/client/app/components/Modal.jsx
@@ -1,4 +1,5 @@
 import React from 'react';
+import PropTypes from 'prop-types';
 
 
 export default class Modal extends React.Component {
@@ -112,8 +113,8 @@ export default class Modal extends React.Component {
   }
 }
 Modal.propTypes = {
-    open: React.PropTypes.bool,
-    data: React.PropTypes.object
+    open: PropTypes.bool,
+    data: PropTypes.object
 };
 
 
diff --git a/hubs/static/client/app/components/Tab.jsx b/hubs/static/client/app/components/Tab.jsx
index 3dd8b5a..a26e1b7 100644
--- a/hubs/static/client/app/components/Tab.jsx
+++ b/hubs/static/client/app/components/Tab.jsx
@@ -1,4 +1,5 @@
 import React from 'react';
+import PropTypes from 'prop-types';
 
 
 export default class Tab extends React.Component {
@@ -19,7 +20,7 @@ export default class Tab extends React.Component {
 }
 
 Tab.propTypes = {
-  tabLinkClass: React.PropTypes.string,
+  tabLinkClass: PropTypes.string,
 };
 Tab.defaultProps = {
   tabLinkClass: '',
diff --git a/hubs/static/client/app/components/TabSet.jsx b/hubs/static/client/app/components/TabSet.jsx
index e366f37..c3064c5 100644
--- a/hubs/static/client/app/components/TabSet.jsx
+++ b/hubs/static/client/app/components/TabSet.jsx
@@ -1,4 +1,5 @@
 import React from 'react';
+import PropTypes from 'prop-types';
 import Tab from './Tab.jsx';
 import TabPanel from './TabPanel.jsx';
 
@@ -57,10 +58,10 @@ export default class TabSet extends React.Component {
 }
 
 TabSet.propTypes = {
-  tabWrapperProps: React.PropTypes.object,
-  tabType: React.PropTypes.string,
-  tabListClass: React.PropTypes.string,
-  tabContentClass: React.PropTypes.string,
+  tabWrapperProps: PropTypes.object,
+  tabType: PropTypes.string,
+  tabListClass: PropTypes.string,
+  tabContentClass: PropTypes.string,
 };
 TabSet.defaultProps = {
   tabWrapperProps: {},
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index f237da9..c37dc96 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -11,12 +11,13 @@
     "babel-plugin-transform-class-properties": "^6.10.2",
     "babel-preset-es2015": "~6.9.0",
     "babel-preset-react": "~6.5.0",
+    "prop-types": "^15.5.8",
     "react": "^15.4.0",
-    "react-dom": "^15.4.0",
-    "react-timeago": "^3.1.1",
     "react-autosuggest": "~6.1.0",
-    "react-linkify": "^0.1.3",
+    "react-dom": "^15.4.0",
     "react-intl": "~2.1.5",
+    "react-linkify": "^0.1.3",
+    "react-timeago": "^3.1.1",
     "webpack": "~1.13.1"
   },
   "devDependencies": {

From 1b2a4d01f25e92496287645d579fc797fcfd7391 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 16 2017 10:30:01 +0000
Subject: [PATCH 842/1001] Be more compatible


---

diff --git a/hubs/migrations/env.py b/hubs/migrations/env.py
index 0148bb7..34f4ab0 100644
--- a/hubs/migrations/env.py
+++ b/hubs/migrations/env.py
@@ -15,6 +15,7 @@ except ImportError:
         raise
     sys.path.append(os.getcwd())
 
+import hubs.app
 from hubs.models import BASE
 
 

From 5f12f0e54eb40d54db1d93f0d7435453dd2afd38 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 16 2017 10:30:17 +0000
Subject: [PATCH 843/1001] Ignore local vagrant dir


---

diff --git a/.gitignore b/.gitignore
index c8921e7..f769f52 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ hubs.js
 
 # Vagrant and Ansible files
 Vagrantfile
+.vagrant
 .dnf-cache
 *.retry
 *.pem

From 373984121b0475d6c80a5e63342e8dbcf12c19be Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 16 2017 10:33:25 +0000
Subject: [PATCH 844/1001] Paramertize the local user


---

diff --git a/ansible/roles/hubs-dev/defaults/main.yml b/ansible/roles/hubs-dev/defaults/main.yml
new file mode 100644
index 0000000..746731f
--- /dev/null
+++ b/ansible/roles/hubs-dev/defaults/main.yml
@@ -0,0 +1 @@
+main_user: hubs
diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
index 9f2ec6b..ef3fb7d 100755
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -62,7 +62,7 @@
 
 # Add various helpful configuration files
 - name: Install a custom bashrc
-  copy: src=bashrc dest=/home/{{ ansible_env.SUDO_USER }}/.bashrc
+  copy: src=bashrc dest=/home/{{ main_user }}/.bashrc
 
 - name: Install the message of the day
   copy: src=motd dest=/etc/motd
@@ -111,69 +111,69 @@
 
 # Set up the Python development environment
 - name: Install Fedora Hubs requirements.txt into hubs virtualenv
-  become_user: "{{ ansible_env.SUDO_USER }}"
+  become_user: "{{ main_user }}"
   pip:
-    requirements: /home/{{ ansible_env.SUDO_USER }}/devel/requirements.txt
-    virtualenv: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/
+    requirements: /home/{{ main_user }}/devel/requirements.txt
+    virtualenv: /home/{{ main_user }}/.virtualenvs/hubs/
 
 - name: Install Fedora Hubs test-requirements.txt into hubs virtualenv
-  become_user: "{{ ansible_env.SUDO_USER }}"
+  become_user: "{{ main_user }}"
   pip:
-    requirements: /home/{{ ansible_env.SUDO_USER }}/devel/requirements.txt
-    virtualenv: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/
+    requirements: /home/{{ main_user }}/devel/requirements.txt
+    virtualenv: /home/{{ main_user }}/.virtualenvs/hubs/
 
 - name: Install bleach into hubs virtualenv
-  become_user: "{{ ansible_env.SUDO_USER }}"
+  become_user: "{{ main_user }}"
   pip:
     name: bleach
-    virtualenv: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/
+    virtualenv: /home/{{ main_user }}/.virtualenvs/hubs/
 
 - name: Install gunicorn into hubs virtualenv
-  become_user: "{{ ansible_env.SUDO_USER }}"
+  become_user: "{{ main_user }}"
   pip:
     name: gunicorn
-    virtualenv: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/
+    virtualenv: /home/{{ main_user }}/.virtualenvs/hubs/
 
 - name: Update httplib2 trust store
   copy:
     src: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
-    dest: /home/{{ ansible_env.SUDO_USER }}/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
+    dest: /home/{{ main_user }}/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
     remote_src: True
 
 - name: Add a basic Hubs configuration file
-  copy: src=hubs_config dest=/home/{{ ansible_env.SUDO_USER }}/devel/config
-  become_user: "{{ ansible_env.SUDO_USER }}"
+  copy: src=hubs_config dest=/home/{{ main_user }}/devel/config
+  become_user: "{{ main_user }}"
 
 - name: Configure application to authenticate with iddev.fedorainfracloud.org
   shell: >
       source ~/.bashrc &&
       workon hubs &&
       oidc-register https://iddev.fedorainfracloud.org/ http://localhost:5000
-  become_user: "{{ ansible_env.SUDO_USER }}"
+  become_user: "{{ main_user }}"
   args:
     creates: client_secrets.json
-    chdir: "/home/{{ ansible_env.SUDO_USER }}/devel/"
+    chdir: "/home/{{ main_user }}/devel/"
 
 - name: Populate the Fedora Hubs database
   shell: >
       source ~/.bashrc &&
       workon hubs &&
       python populate.py
-  become_user: "{{ ansible_env.SUDO_USER }}"
+  become_user: "{{ main_user }}"
   args:
     creates: /var/tmp/hubs.db
-    chdir: "/home/{{ ansible_env.SUDO_USER }}/devel/"
+    chdir: "/home/{{ main_user }}/devel/"
 
 # Set up JavaScript requirements
 - name: Install npm packages
   command: npm install
-  become_user: "{{ ansible_env.SUDO_USER }}"
+  become_user: "{{ main_user }}"
   args:
     creates: node_modules
-    chdir: /home/{{ ansible_env.SUDO_USER }}/devel/hubs/static/client
+    chdir: /home/{{ main_user }}/devel/hubs/static/client
 
 - name: Build JavaScript assests
   command: node_modules/.bin/webpack
-  become_user: "{{ ansible_env.SUDO_USER }}"
+  become_user: "{{ main_user }}"
   args:
-    chdir: /home/{{ ansible_env.SUDO_USER }}/devel/hubs/static/client
+    chdir: /home/{{ main_user }}/devel/hubs/static/client
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
index 14cbf9f..b69920c 100644
--- a/ansible/vagrant-playbook.yml
+++ b/ansible/vagrant-playbook.yml
@@ -4,4 +4,5 @@
   become_method: sudo
   vars:
   roles:
-    - hubs-dev
+    - role: hubs-dev
+      main_user: vagrant

From 07ddc938861dd557111f0c99a81b624f4c386515 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 16 2017 10:34:41 +0000
Subject: [PATCH 845/1001] Take the setting of motd out of the role


---

diff --git a/ansible/files/motd b/ansible/files/motd
new file mode 100644
index 0000000..f3d92ab
--- /dev/null
+++ b/ansible/files/motd
@@ -0,0 +1,18 @@
+
+Welcome to the Fedora Hubs development environment!
+
+Here are some tips:
+
+* The code for Fedora Hubs is located at ~/devel/
+
+* You can type `workon hubs` to enter a configured Python virtualenv
+
+* Run `hup` to start gunicorn
+
+* Run `hreset` to delete the database and repopulate it
+
+Once you run `hup` you can navigate to http://localhost:5000/
+in your browser.
+
+Happy hacking!
+
diff --git a/ansible/roles/hubs-dev/files/motd b/ansible/roles/hubs-dev/files/motd
deleted file mode 100644
index f3d92ab..0000000
--- a/ansible/roles/hubs-dev/files/motd
+++ /dev/null
@@ -1,18 +0,0 @@
-
-Welcome to the Fedora Hubs development environment!
-
-Here are some tips:
-
-* The code for Fedora Hubs is located at ~/devel/
-
-* You can type `workon hubs` to enter a configured Python virtualenv
-
-* Run `hup` to start gunicorn
-
-* Run `hreset` to delete the database and repopulate it
-
-Once you run `hup` you can navigate to http://localhost:5000/
-in your browser.
-
-Happy hacking!
-
diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
index ef3fb7d..e5359a0 100755
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -64,9 +64,6 @@
 - name: Install a custom bashrc
   copy: src=bashrc dest=/home/{{ main_user }}/.bashrc
 
-- name: Install the message of the day
-  copy: src=motd dest=/etc/motd
-
 
 # Set up Postgres, create the necessary databases, and start up datanommer
 - name: Set up postgresql database
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
index b69920c..d6a4449 100644
--- a/ansible/vagrant-playbook.yml
+++ b/ansible/vagrant-playbook.yml
@@ -6,3 +6,7 @@
   roles:
     - role: hubs-dev
       main_user: vagrant
+
+  tasks:
+    - name: Install the message of the day
+      copy: src=files/motd dest=/etc/motd

From 5f7827cb014f4be6ce5f6a44534f02d40bc5a8dc Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 16 2017 14:44:27 +0000
Subject: [PATCH 846/1001] PostgreSQL compatibility


---

diff --git a/hubs/models.py b/hubs/models.py
index d54dccd..0a58e40 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -120,7 +120,8 @@ class Association(BASE):
     user_id = sa.Column(sa.Text,
                         sa.ForeignKey('users.username'),
                         primary_key=True)
-    role = sa.Column(sa.Enum(*roles), primary_key=True)
+    role = sa.Column(
+        sa.Enum(*roles, name="roles"), primary_key=True)
 
     user = relation("User", backref=backref(
         'associations', cascade="all, delete, delete-orphan"))
@@ -327,7 +328,8 @@ class HubConfig(BASE):
     chat_domain = sa.Column(sa.String(256), nullable=True)
     auth_group = sa.Column(sa.String(256), nullable=True)
     visibility = sa.Column(
-        sa.Enum(*VISIBILITY), default="public", nullable=False)
+        sa.Enum(*VISIBILITY, name="hub_visibility"),
+        default="public", nullable=False)
 
     def __json__(self):
         return {
@@ -362,12 +364,13 @@ class Widget(ObjectAuthzMixin, BASE):
     plugin = sa.Column(sa.String(50), nullable=False)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     hub_id = sa.Column(sa.String(50), sa.ForeignKey('hubs.name'))
-    _config = sa.Column(sa.String(256), default=_widget_config_default)
+    _config = sa.Column(sa.Text, default=_widget_config_default)
 
     index = sa.Column(sa.Integer, nullable=False)
     left = sa.Column(sa.Boolean, nullable=False, default=False)
     visibility = sa.Column(
-        sa.Enum(*VISIBILITY), default="public", nullable=False)
+        sa.Enum(*VISIBILITY, name="widget_visibility"),
+        default="public", nullable=False)
 
     @classmethod
     def by_idx(cls, idx):

From dfff7b60df14cb6353888b9bb42814946c29f30f Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 16 2017 15:40:25 +0000
Subject: [PATCH 847/1001] Create console scripts


---

diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index 7f7858c..50ba5ef 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -73,7 +73,8 @@ def triage(outbound, msg):
                 }))
 
 
-def main(args):
+def main(args=None):
+    args = args if args is not None else sys.argv
     logging.config.dictConfig(fedmsg_config['logging'])
     logging.basicConfig()
 
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index 8e8d8c6..30c55bc 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -66,7 +66,8 @@ def handle(idx, fn_name):
         session.close()
 
 
-def main(args):
+def main(args=None):
+    args = args if args is not None else sys.argv
     logging.config.dictConfig(fedmsg_config['logging'])
     logging.basicConfig()
 
diff --git a/setup.py b/setup.py
index 824eeb9..7ca61b7 100644
--- a/setup.py
+++ b/setup.py
@@ -42,5 +42,9 @@ setup(
         'moksha.consumer': [
             "cache_invalidator = hubs.backend.consumer:CacheInvalidatorExtraordinaire",  # noqa: E501
         ],
+        'console_scripts': [
+            "fedora-hubs-triage = hubs.backend.triage:main",
+            "fedora-hubs-worker = hubs.backend.worker:main",
+        ],
     },
 )
diff --git a/systemd/hubs-triage@.service b/systemd/hubs-triage@.service
index c88ebde..400ddd7 100644
--- a/systemd/hubs-triage@.service
+++ b/systemd/hubs-triage@.service
@@ -4,8 +4,9 @@ After=network.target
 Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
-ExecStart=/srv/git/fedora-hubs/hubs/backend/triage.py
-WorkingDirectory=/srv/git/fedora-hubs/
+ExecStart=/usr/bin/fedora-hubs-triage
+WorkingDirectory=/srv/hubs/fedora-hubs/
+Environment=HUBS_CONFIG=/srv/hubs/fedora-hubs/config
 Type=simple
 User=root
 Group=root
diff --git a/systemd/hubs-webapp.service b/systemd/hubs-webapp.service
index 5c66951..7bee708 100644
--- a/systemd/hubs-webapp.service
+++ b/systemd/hubs-webapp.service
@@ -5,7 +5,8 @@ Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
 ExecStart=/usr/bin/gunicorn -b 0.0.0.0:80 --threads 12 --log-config logging.ini --reload hubs.app:app
-WorkingDirectory=/srv/git/fedora-hubs/
+WorkingDirectory=/srv/hubs/fedora-hubs/
+Environment=HUBS_CONFIG=/srv/hubs/fedora-hubs/config
 Type=simple
 User=root
 Group=root
diff --git a/systemd/hubs-worker@.service b/systemd/hubs-worker@.service
index bf6f0ef..a84f3de 100644
--- a/systemd/hubs-worker@.service
+++ b/systemd/hubs-worker@.service
@@ -4,8 +4,8 @@ After=network.target
 Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
-ExecStart=/srv/git/fedora-hubs/hubs/backend/worker.py
-WorkingDirectory=/srv/git/fedora-hubs/
+ExecStart=/usr/bin/fedora-hubs-worker
+Environment=HUBS_CONFIG=/srv/git/fedora-hubs/config
 Type=simple
 User=root
 Group=root

From ffb9f27c98ccaf360c841ff4c8174410fc65515e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 19 2017 15:42:53 +0000
Subject: [PATCH 848/1001] Don't use fedmsg.d for default values


Otherwise those defaults can't be overridden by values in /etc/fedmsg.d.

---

diff --git a/fedmsg.d/testconfig.py b/fedmsg.d/testconfig.py
deleted file mode 100644
index 8f4f105..0000000
--- a/fedmsg.d/testconfig.py
+++ /dev/null
@@ -1,56 +0,0 @@
-config = {
-
-    'hubs.consumer.enabled': True,
-    # Production ready.
-    'hubs.sqlalchemy.uri': 'sqlite:////var/tmp/hubs.db',
-
-    # For communication between fedmsg-hub and the cache worker farm
-    'hubs.redis.triage-queue-name': 'fedora-hubs-triage-queue',
-    'hubs.redis.work-queue-name': 'fedora-hubs-work-queue',
-
-    # Junk junk junk.. that we don't care about.  Drop it!
-    'hubs.junk_suffixes': [
-        'buildsys.tag',
-        'buildsys.untag',
-        'buildsys.rpm.sign',
-    ],
-
-    'endpoints': {
-        "fedora-infrastructure": [
-            "tcp://hub.fedoraproject.org:9940",
-        ]
-    },
-
-    'datanommer.sqlalchemy.uri':
-        'postgres://postgres:laksjdf@127.0.0.1/datanommer',
-
-    'fmn.url': 'https://apps.fedoraproject.org/notifications',
-
-    # Some configuration for the rule processors
-    "fmn.rules.utils.use_pkgdb2": False,
-    "fmn.rules.utils.pkgdb2_api_url": "http://209.132.184.188/api/",
-    "fmn.rules.cache": {
-        "backend": "dogpile.cache.dbm",
-        "expiration_time": 300,
-        "arguments": {
-            "filename": "/var/tmp/fmn-cache.db",
-        },
-    },
-
-    # Some configuration for the general hubs cache.
-    "fedora-hubs.cache": {
-        "backend": "dogpile.cache.dbm",
-        "expiration_time": -1,  # Expire every 1 second, for development
-        "arguments": {
-            "filename": "/var/tmp/fedora-hubs-cache.db",
-        },
-    },
-
-    # Run datanommer locally, just for development.
-    'datanommer.enabled': True,
-    'datanommer.sqlalchemy.url':
-        'postgres://postgres:laksjdf@127.0.0.1/datanommer',
-
-    # Only do one of these so we can try to not run out of memory.
-    'moksha.workers_per_consumer': 1,
-}
diff --git a/hubs/app.py b/hubs/app.py
index fa24829..8072e1f 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -31,8 +31,7 @@ if 'HUBS_CONFIG' in os.environ:
     app.config.from_envvar('HUBS_CONFIG')
 
 fedmsg_config = get_fedmsg_config()
-session = hubs.models.init(
-    fedmsg_config.get('hubs.sqlalchemy.uri', 'sqlite:///'))
+session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
 datanommer.models.init(
     fedmsg_config.get('datanommer.sqlalchemy.uri', 'sqlite:///'))
 
diff --git a/hubs/default_fedmsg_config.py b/hubs/default_fedmsg_config.py
new file mode 100644
index 0000000..81198d6
--- /dev/null
+++ b/hubs/default_fedmsg_config.py
@@ -0,0 +1,58 @@
+config = {
+
+    # Fedmsg hub consumer
+    'hubs.consumer.enabled': True,
+
+    # Main database
+    'hubs.sqlalchemy.uri': 'sqlite:////var/tmp/hubs.db',
+
+    # For communication between fedmsg-hub and the cache worker farm
+    'hubs.redis.triage-queue-name': 'fedora-hubs-triage-queue',
+    'hubs.redis.work-queue-name': 'fedora-hubs-work-queue',
+
+    # Junk junk junk.. that we don't care about.  Drop it!
+    'hubs.junk_suffixes': [
+        'buildsys.tag',
+        'buildsys.untag',
+        'buildsys.rpm.sign',
+    ],
+
+    'endpoints': {
+        "fedora-infrastructure": [
+            "tcp://hub.fedoraproject.org:9940",
+        ]
+    },
+
+    'datanommer.sqlalchemy.uri':
+        'postgres://postgres:laksjdf@127.0.0.1/datanommer',
+
+    'fmn.url': 'https://apps.fedoraproject.org/notifications',
+
+    # Some configuration for the rule processors
+    "fmn.rules.utils.use_pkgdb2": False,
+    "fmn.rules.utils.pkgdb2_api_url": "http://209.132.184.188/api/",
+    "fmn.rules.cache": {
+        "backend": "dogpile.cache.dbm",
+        "expiration_time": 300,
+        "arguments": {
+            "filename": "/var/tmp/fmn-cache.db",
+        },
+    },
+
+    # Some configuration for the general hubs cache.
+    "fedora-hubs.cache": {
+        "backend": "dogpile.cache.dbm",
+        "expiration_time": -1,  # Expire every 1 second, for development
+        "arguments": {
+            "filename": "/var/tmp/fedora-hubs-cache.db",
+        },
+    },
+
+    # Run datanommer locally, just for development.
+    'datanommer.enabled': True,
+    'datanommer.sqlalchemy.url':
+        'postgres://postgres:laksjdf@127.0.0.1/datanommer',
+
+    # Only do one of these so we can try to not run out of memory.
+    'moksha.workers_per_consumer': 1,
+}
diff --git a/hubs/utils/__init__.py b/hubs/utils/__init__.py
index 8713806..80d239f 100755
--- a/hubs/utils/__init__.py
+++ b/hubs/utils/__init__.py
@@ -7,6 +7,8 @@ import fedmsg.config
 import fedmsg.meta
 from six.moves.urllib_parse import urlencode
 
+from hubs.default_fedmsg_config import config as default_fedmsg_config
+
 
 def get_fedmsg_config():
     try:
@@ -14,6 +16,11 @@ def get_fedmsg_config():
     except KeyError:
         filenames = None
     fedmsg_config = fedmsg.config.load_config(filenames=filenames)
+    # Only add default values if they don't exist yet.
+    for key, value in default_fedmsg_config.items():
+        if key not in fedmsg_config:
+            fedmsg_config[key] = value
+    # Meta processors
     fedmsg.meta.make_processors(**fedmsg_config)
     return fedmsg_config
 

From d693c057d973a702e6f62c1622d59f202ecb5bbd Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 19 2017 16:05:55 +0000
Subject: [PATCH 849/1001] Use variables in playbooks


---

diff --git a/ansible/roles/hubs-dev/defaults/main.yml b/ansible/roles/hubs-dev/defaults/main.yml
index 746731f..8f50281 100644
--- a/ansible/roles/hubs-dev/defaults/main.yml
+++ b/ansible/roles/hubs-dev/defaults/main.yml
@@ -1 +1,8 @@
 main_user: hubs
+hubs_dev_mode: yes
+hubs_secret_key: changeme
+hubs_code_dir: "/home/{{ main_user }}/devel"
+hubs_venv_dir: "/home/{{ main_user }}/.virtualenvs/hubs"
+hubs_db_type: sqlite
+hubs_db_password: changeme
+hubs_url: http://localhost:5000
diff --git a/ansible/roles/hubs-dev/files/bashrc b/ansible/roles/hubs-dev/files/bashrc
deleted file mode 100644
index 615b5df..0000000
--- a/ansible/roles/hubs-dev/files/bashrc
+++ /dev/null
@@ -1,39 +0,0 @@
-# .bashrc
-
-# Source global definitions
-if [ -f /etc/bashrc ]; then
-    . /etc/bashrc
-fi
-
-# Uncomment the following line if you don't like systemctl's auto-paging feature:
-# export SYSTEMD_PAGER=
-
-# User specific aliases and functions
-# If adding new functions to this file, note that you can add help text to the function
-# by defining a variable with name _<function>_help containing the help text
-
-# Set up virtualenvwrapper
-export WORKON_HOME=$HOME/.virtualenvs
-export PIP_VIRTUALENV_BASE=$WORKON_HOME
-export VIRTUALENV_USE_DISTRIBUTE=true
-export PIP_RESPECT_VIRTUALENV=true
-source /usr/bin/virtualenvwrapper.sh
-
-export HUBS_CONFIG=~/devel/config
-
-
-hup() {
-    workon hubs
-    pushd ~/devel/
-    python ./runserver.py --host 0.0.0.0
-}
-
-hreset() {
-    workon hubs
-    rm /var/tmp/hubs.db
-    rm /var/tmp/fedora-hubs-cache.db
-    pushd ~/devel/
-    python populate.py
-    popd
-    deactivate
-}
diff --git a/ansible/roles/hubs-dev/files/hubs_config b/ansible/roles/hubs-dev/files/hubs_config
deleted file mode 100644
index 83417df..0000000
--- a/ansible/roles/hubs-dev/files/hubs_config
+++ /dev/null
@@ -1,4 +0,0 @@
-# Enter any hubs configuratio here
-
-# Allow the cookie to be sent of http since we work on localhost
-OIDC_ID_TOKEN_COOKIE_SECURE = False
diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
index e5359a0..b1ae3fc 100755
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -62,7 +62,7 @@
 
 # Add various helpful configuration files
 - name: Install a custom bashrc
-  copy: src=bashrc dest=/home/{{ main_user }}/.bashrc
+  template: src=bashrc dest=/home/{{ main_user }}/.bashrc
 
 
 # Set up Postgres, create the necessary databases, and start up datanommer
@@ -110,26 +110,23 @@
 - name: Install Fedora Hubs requirements.txt into hubs virtualenv
   become_user: "{{ main_user }}"
   pip:
-    requirements: /home/{{ main_user }}/devel/requirements.txt
-    virtualenv: /home/{{ main_user }}/.virtualenvs/hubs/
+    requirements: "{{ hubs_code_dir }}/requirements.txt"
+    virtualenv: "{{ hubs_venv_dir}}"
 
 - name: Install Fedora Hubs test-requirements.txt into hubs virtualenv
   become_user: "{{ main_user }}"
   pip:
-    requirements: /home/{{ main_user }}/devel/requirements.txt
-    virtualenv: /home/{{ main_user }}/.virtualenvs/hubs/
+    requirements: "{{ hubs_code_dir }}/test-requirements.txt"
+    virtualenv: "{{ hubs_venv_dir}}"
 
-- name: Install bleach into hubs virtualenv
+- name: Install other packages into hubs virtualenv
   become_user: "{{ main_user }}"
   pip:
-    name: bleach
-    virtualenv: /home/{{ main_user }}/.virtualenvs/hubs/
-
-- name: Install gunicorn into hubs virtualenv
-  become_user: "{{ main_user }}"
-  pip:
-    name: gunicorn
-    virtualenv: /home/{{ main_user }}/.virtualenvs/hubs/
+    name: "{{ item }}"
+    virtualenv: "{{ hubs_venv_dir }}"
+  with_items:
+    - bleach
+    - gunicorn
 
 - name: Update httplib2 trust store
   copy:
@@ -138,18 +135,17 @@
     remote_src: True
 
 - name: Add a basic Hubs configuration file
-  copy: src=hubs_config dest=/home/{{ main_user }}/devel/config
+  template:
+    src: [hubs_config, hubs_config.{{ ansible_group }}, hubs_config.{{ ansible_hostname }}]
+    dest: "{{ hubs_code_dir }}/config"
   become_user: "{{ main_user }}"
 
 - name: Configure application to authenticate with iddev.fedorainfracloud.org
-  shell: >
-      source ~/.bashrc &&
-      workon hubs &&
-      oidc-register https://iddev.fedorainfracloud.org/ http://localhost:5000
+  command: oidc-register https://iddev.fedorainfracloud.org/ {{hubs_url}}
   become_user: "{{ main_user }}"
   args:
     creates: client_secrets.json
-    chdir: "/home/{{ main_user }}/devel/"
+    chdir: "{{ hubs_code_dir }}"
 
 - name: Populate the Fedora Hubs database
   shell: >
@@ -159,7 +155,7 @@
   become_user: "{{ main_user }}"
   args:
     creates: /var/tmp/hubs.db
-    chdir: "/home/{{ main_user }}/devel/"
+    chdir: "{{ hubs_code_dir }}"
 
 # Set up JavaScript requirements
 - name: Install npm packages
@@ -167,10 +163,10 @@
   become_user: "{{ main_user }}"
   args:
     creates: node_modules
-    chdir: /home/{{ main_user }}/devel/hubs/static/client
+    chdir: "{{ hubs_code_dir }}/hubs/static/client"
 
 - name: Build JavaScript assests
   command: node_modules/.bin/webpack
   become_user: "{{ main_user }}"
   args:
-    chdir: /home/{{ main_user }}/devel/hubs/static/client
+    chdir: "{{ hubs_code_dir }}/hubs/static/client"
diff --git a/ansible/roles/hubs-dev/templates/bashrc b/ansible/roles/hubs-dev/templates/bashrc
new file mode 100644
index 0000000..db0746d
--- /dev/null
+++ b/ansible/roles/hubs-dev/templates/bashrc
@@ -0,0 +1,45 @@
+# .bashrc
+
+# Source global definitions
+if [ -f /etc/bashrc ]; then
+    . /etc/bashrc
+fi
+
+# Uncomment the following line if you don't like systemctl's auto-paging feature:
+# export SYSTEMD_PAGER=
+
+# User specific aliases and functions
+# If adding new functions to this file, note that you can add help text to the function
+# by defining a variable with name _<function>_help containing the help text
+
+# Set up virtualenvwrapper
+export WORKON_HOME=$HOME/.virtualenvs
+export PIP_VIRTUALENV_BASE=$WORKON_HOME
+export VIRTUALENV_USE_DISTRIBUTE=true
+export PIP_RESPECT_VIRTUALENV=true
+source /usr/bin/virtualenvwrapper.sh
+
+export HUBS_CONFIG={{ hubs_code_dir }}/config
+export FLASK_APP={{ hubs_code_dir }}/hubs/app.py
+
+
+hup() {
+    workon hubs
+    pushd {{ hubs_code_dir }}
+    FLASK_DEBUG=1 flask run --host 0.0.0.0
+}
+
+hreset() {
+    workon hubs
+    {% if hubs_db_type == "postgresql" %}
+    sudo -u postgres dropdb hubs
+    sudo -u postgres createdb -O hubs hubs
+    {% else %}
+    rm /var/lib/hubs/hubs.db
+    {% endif %}
+    rm /var/lib/hubs/cache.db
+    pushd {{ hubs_code_dir }}
+    python populate.py
+    popd
+    deactivate
+}
diff --git a/ansible/roles/hubs-dev/templates/hubs-fedmsg-hub.service b/ansible/roles/hubs-dev/templates/hubs-fedmsg-hub.service
new file mode 100644
index 0000000..cc2b96e
--- /dev/null
+++ b/ansible/roles/hubs-dev/templates/hubs-fedmsg-hub.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Hubs-specific fedmsg processing hub
+After=network.target
+Documentation=https://fedmsg.readthedocs.org/
+
+[Service]
+ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/fedmsg-hub
+WorkingDirectory={{ hubs_code_dir }}
+Type=simple
+User=fedmsg
+Group=fedmsg
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/hubs-dev/templates/hubs-triage@.service b/ansible/roles/hubs-dev/templates/hubs-triage@.service
new file mode 100644
index 0000000..fc74242
--- /dev/null
+++ b/ansible/roles/hubs-dev/templates/hubs-triage@.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=fedora-hubs triage worker #%i
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart={{ hubs_venv_dir }}/bin/fedora-hubs-triage
+WorkingDirectory={{ hubs_code_dir }}
+Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
+Type=simple
+User={{ main_user }}
+Group={{ main_user }}
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/hubs-dev/templates/hubs-webapp.service b/ansible/roles/hubs-dev/templates/hubs-webapp.service
new file mode 100644
index 0000000..00ba431
--- /dev/null
+++ b/ansible/roles/hubs-dev/templates/hubs-webapp.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=fedora-hubs frontend webapp
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/gunicorn -b 0.0.0.0:80 --threads 12 --log-config logging.ini --reload hubs.app:app
+WorkingDirectory={{ hubs_code_dir }}
+Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
+Type=simple
+User={{ main_user }}
+Group={{ main_user }}
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/hubs-dev/templates/hubs-worker@.service b/ansible/roles/hubs-dev/templates/hubs-worker@.service
new file mode 100644
index 0000000..8073577
--- /dev/null
+++ b/ansible/roles/hubs-dev/templates/hubs-worker@.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=fedora-hubs cache worker #%i
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart={{ hubs_venv_dir }}/bin/fedora-hubs-worker
+WorkingDirectory={{ hubs_code_dir }}
+Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
+Type=simple
+User={{ main_user }}
+Group={{ main_user }}
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/hubs-dev/templates/hubs_config b/ansible/roles/hubs-dev/templates/hubs_config
new file mode 100644
index 0000000..d5a5394
--- /dev/null
+++ b/ansible/roles/hubs-dev/templates/hubs_config
@@ -0,0 +1,8 @@
+# Enter any hubs configuration here
+
+SECRET_KEY = "{{ hubs_secret_key }}"
+
+{% if hubs_dev_mode %}
+# Allow the cookie to be sent of http since we work on localhost
+OIDC_ID_TOKEN_COOKIE_SECURE = False
+{% endif %}
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
index d6a4449..f971611 100644
--- a/ansible/vagrant-playbook.yml
+++ b/ansible/vagrant-playbook.yml
@@ -3,9 +3,13 @@
   become: true
   become_method: sudo
   vars:
+    main_user: vagrant
+
   roles:
     - role: hubs-dev
-      main_user: vagrant
+      hubs_secret_key: vagrantmachinesecretkey
+      hubs_db_type: sqlite
+      hubs_url: http://localhost:5000
 
   tasks:
     - name: Install the message of the day

From e99e1ea318d56d9b9fca0f7b5124deed16add6ac Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 19 2017 16:35:47 +0000
Subject: [PATCH 850/1001] Get rid of datanommer


---

diff --git a/ansible/roles/hubs-dev/files/datanommer.py b/ansible/roles/hubs-dev/files/datanommer.py
deleted file mode 100644
index 30de6fb..0000000
--- a/ansible/roles/hubs-dev/files/datanommer.py
+++ /dev/null
@@ -1,4 +0,0 @@
-config = {
-    'datanommer.enabled': True,
-    'datanommer.sqlalchemy.url': 'postgres://datanommer@localhost/datanommer',
-}
diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
index b1ae3fc..9ec1f23 100755
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -12,8 +12,6 @@
     - gcc-c++
     - libffi-devel
     - openssl-devel
-    - postgresql
-    - postgresql-devel
     - python-sphinx
     - python-virtualenvwrapper
     - python2-devel
@@ -26,7 +24,6 @@
   with_items:
     - python-arrow
     - python-bleach
-    - python-datanommer-models
     - python-decorator
     - python-dogpile-cache
     - python-fedmsg-core
@@ -38,7 +35,6 @@
     - python-gunicorn
     - python-html5lib
     - python-munch
-    - python-psycopg2
     - pytz
     - python-sqlalchemy
     - python-markdown
@@ -48,60 +44,12 @@
     - python-pygments-markdown-lexer
     - python-retask
 
-- name: Install packages for datanommer
-  dnf: name={{ item }} state=present
-  with_items:
-    - datanommer-commands
-    - fedmsg-hub
-    - npm
-    - postgresql-server
-    - python-datanommer-consumer
-    - python-fedmsg-meta-fedora-infrastructure
-    - python-psycopg2
-
 
 # Add various helpful configuration files
 - name: Install a custom bashrc
   template: src=bashrc dest=/home/{{ main_user }}/.bashrc
 
 
-# Set up Postgres, create the necessary databases, and start up datanommer
-- name: Set up postgresql database
-  command: postgresql-setup --initdb
-  args:
-      creates: /var/lib/pgsql/data/base
-
-- name: Set up postgresql access rules to allow local access
-  copy:
-      src: pg_hba.conf
-      dest: /var/lib/pgsql/data/pg_hba.conf
-      owner: postgres
-      group: postgres
-      mode: 0600
-  notify: restart postgresql
-
-- name: Start and enable postgresql
-  service: name=postgresql state=started enabled=yes
-
-- name: Set up datanommer DB user
-  postgresql_user:
-      name: datanommer
-      role_attr_flags: SUPERUSER,LOGIN
-
-- name: Create datanommer database
-  postgresql_db:
-      name: datanommer
-      owner: datanommer
-
-- name: Set up datanommer
-  copy: src=datanommer.py dest=/etc/fedmsg.d/datanommer.py
-  notify: restart fedmsg-hub
-
-# TODO unfortunately this always runs as there doesn't appear to be
-# an easy way to check if it needs to run
-- name: Create datanommer database tables
-  command: datanommer-create-db
-
 - name: Start and enable fedmsg-hub
   service: name=fedmsg-hub state=started enabled=yes
 
diff --git a/hubs/app.py b/hubs/app.py
index 8072e1f..1cc6c68 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -4,7 +4,6 @@ import datetime
 import logging
 import os
 
-import datanommer.models
 import flask
 import flask.json
 import munch
@@ -32,8 +31,6 @@ if 'HUBS_CONFIG' in os.environ:
 
 fedmsg_config = get_fedmsg_config()
 session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
-datanommer.models.init(
-    fedmsg_config.get('datanommer.sqlalchemy.uri', 'sqlite:///'))
 
 
 @app.before_request
diff --git a/hubs/default_fedmsg_config.py b/hubs/default_fedmsg_config.py
index 81198d6..648f504 100644
--- a/hubs/default_fedmsg_config.py
+++ b/hubs/default_fedmsg_config.py
@@ -23,9 +23,6 @@ config = {
         ]
     },
 
-    'datanommer.sqlalchemy.uri':
-        'postgres://postgres:laksjdf@127.0.0.1/datanommer',
-
     'fmn.url': 'https://apps.fedoraproject.org/notifications',
 
     # Some configuration for the rule processors
@@ -48,11 +45,6 @@ config = {
         },
     },
 
-    # Run datanommer locally, just for development.
-    'datanommer.enabled': True,
-    'datanommer.sqlalchemy.url':
-        'postgres://postgres:laksjdf@127.0.0.1/datanommer',
-
     # Only do one of these so we can try to not run out of memory.
     'moksha.workers_per_consumer': 1,
 }
diff --git a/hubs/tests/fedmsg_test.cfg b/hubs/tests/fedmsg_test.cfg
index 6d64bdf..6dc85b7 100644
--- a/hubs/tests/fedmsg_test.cfg
+++ b/hubs/tests/fedmsg_test.cfg
@@ -21,9 +21,6 @@ config = {
         ]
     },
 
-    #'datanommer.sqlalchemy.uri':
-    #    'postgres://postgres:laksjdf@127.0.0.1/datanommer',
-
     #'fmn.url': 'https://apps.fedoraproject.org/notifications',
 
     ## Some configuration for the rule processors
@@ -42,11 +39,6 @@ config = {
         "backend": "dogpile.cache.null",
     },
 
-    ## Run datanommer locally, just for development.
-    #'datanommer.enabled': True,
-    #'datanommer.sqlalchemy.url':
-    #    'postgres://postgres:laksjdf@127.0.0.1/datanommer',
-
     ## Only do one of these so we can try to not run out of memory.
     #'moksha.workers_per_consumer': 1,
 }
diff --git a/requirements.txt b/requirements.txt
index 4a76840..1eb3902 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,6 @@
 arrow
 bleach<2.0.0
 blinker
-datanommer.models
 decorator
 dogpile.cache
 enum34

From 2c6b4b74b42f70ee9725dc903db7fb5e34fbf167 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 19 2017 22:40:54 +0000
Subject: [PATCH 851/1001] Deploy a specific configuration file


---

diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
index 9ec1f23..2912be9 100755
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -88,6 +88,21 @@
     dest: "{{ hubs_code_dir }}/config"
   become_user: "{{ main_user }}"
 
+- name: Add a basic fedmsg configuration file
+  template:
+    src: [fedmsg_config, fedmsg_config.{{ ansible_group }}, fedmsg_config.{{ ansible_hostname }}]
+    dest: "/etc/fedmsg.d/hubs_config.py"
+  become_user: "{{ main_user }}"
+
+- name: Create a directory for variable files
+  file:
+    path: "/var/lib/hubs"
+    state: directory
+    owner: "{{ main_user }}"
+    group: "{{ main_user }}"
+    mode: 755
+    setype: httpd_sys_content_rw_t
+
 - name: Configure application to authenticate with iddev.fedorainfracloud.org
   command: oidc-register https://iddev.fedorainfracloud.org/ {{hubs_url}}
   become_user: "{{ main_user }}"
diff --git a/ansible/roles/hubs-dev/templates/fedmsg_config b/ansible/roles/hubs-dev/templates/fedmsg_config
new file mode 100644
index 0000000..0b33780
--- /dev/null
+++ b/ansible/roles/hubs-dev/templates/fedmsg_config
@@ -0,0 +1,15 @@
+config = {
+    
+    # Database
+    'hubs.sqlalchemy.uri': 'sqlite:////var/lib/hubs/hubs.db',
+
+    # Some configuration for the general hubs cache.
+    "fedora-hubs.cache": {
+        "backend": "dogpile.cache.dbm",
+        #"expiration_time": 0,
+        "arguments": {
+            "filename": "/var/lib/hubs/cache.db",
+        },
+    },
+}
+
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
index f971611..623d093 100644
--- a/ansible/vagrant-playbook.yml
+++ b/ansible/vagrant-playbook.yml
@@ -5,6 +5,12 @@
   vars:
     main_user: vagrant
 
+  pre_tasks:
+    - name: Allow the vagrant user to sudo as anyone
+      copy:
+        content: "vagrant ALL=(ALL) NOPASSWD: ALL"
+        dest: /etc/sudoers.d/vagrant-nopasswd
+
   roles:
     - role: hubs-dev
       hubs_secret_key: vagrantmachinesecretkey

From 3d90f0304ea28913e28817312ad0be188a09e38e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 19 2017 22:43:24 +0000
Subject: [PATCH 852/1001] Options to deploy using sqlite or postgresql


---

diff --git a/ansible/roles/hubs-dev/files/pg_hba.conf b/ansible/roles/hubs-dev/files/pg_hba.conf
index fb47623..c703fd9 100644
--- a/ansible/roles/hubs-dev/files/pg_hba.conf
+++ b/ansible/roles/hubs-dev/files/pg_hba.conf
@@ -7,8 +7,8 @@
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
 
 # "local" is for Unix domain socket connections only
-local   all             all                                     trust
+local   all             all                                     peer
 # IPv4 local connections:
-host    all             all             127.0.0.1/32            trust
+host    all             all             127.0.0.1/32            md5
 # IPv6 local connections:
-host    all             all             ::1/128                 trust
+host    all             all             ::1/128                 md5
diff --git a/ansible/roles/hubs-dev/tasks/db-postgresql.yml b/ansible/roles/hubs-dev/tasks/db-postgresql.yml
new file mode 100644
index 0000000..d228b80
--- /dev/null
+++ b/ansible/roles/hubs-dev/tasks/db-postgresql.yml
@@ -0,0 +1,54 @@
+# Set up Postgres, create the database, and populate it.
+
+- name: Install dependencies
+  dnf: name={{ item }} state=present
+  with_items:
+    - postgresql-server
+    - python-psycopg2
+
+- name: Set up postgresql database
+  command: postgresql-setup --initdb
+  args:
+      creates: /var/lib/pgsql/data/base
+
+- name: Set up postgresql access rules to allow local access
+  copy:
+      src: pg_hba.conf
+      dest: /var/lib/pgsql/data/pg_hba.conf
+      owner: postgres
+      group: postgres
+      mode: 0600
+  notify: restart postgresql
+
+- name: Start and enable postgresql
+  service: name=postgresql state=started enabled=yes
+
+- name: Set up the DB user
+  postgresql_user:
+      name: hubs
+      password: "{{ hubs_db_password }}"
+      role_attr_flags: NOSUPERUSER,NOCREATEROLE,NOCREATEDB
+  become_user: postgres
+
+- name: Create the database
+  postgresql_db:
+      name: hubs
+      owner: hubs
+  register: db_creation
+  become_user: postgres
+
+- name: Ease local access to the database
+  copy:
+    content: "*:*:hubs:hubs:{{ hubs_db_password }}"
+    dest: /home/{{ main_user }}/.pgpass
+    mode: 600
+    owner: "{{ main_user }}"
+    group: "{{ main_user }}"
+
+- name: Populate the Fedora Hubs database
+  command: "{{ hubs_venv_dir }}/bin/python {{ hubs_code_dir }}/populate.py"
+  args:
+    chdir: "{{ hubs_code_dir }}"
+  become_user: "{{ main_user }}"
+  when: db_creation|succeeded
+
diff --git a/ansible/roles/hubs-dev/tasks/db-sqlite.yml b/ansible/roles/hubs-dev/tasks/db-sqlite.yml
new file mode 100644
index 0000000..120e1c7
--- /dev/null
+++ b/ansible/roles/hubs-dev/tasks/db-sqlite.yml
@@ -0,0 +1,6 @@
+- name: Create and populate the Fedora Hubs database
+  command: "{{ hubs_venv_dir }}/bin/python {{ hubs_code_dir }}/populate.py"
+  become_user: "{{ main_user }}"
+  args:
+    creates: /var/lib/hubs/hubs.db
+    chdir: "{{ hubs_code_dir }}"
diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
index 2912be9..5b3a341 100755
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -110,15 +110,10 @@
     creates: client_secrets.json
     chdir: "{{ hubs_code_dir }}"
 
-- name: Populate the Fedora Hubs database
-  shell: >
-      source ~/.bashrc &&
-      workon hubs &&
-      python populate.py
-  become_user: "{{ main_user }}"
-  args:
-    creates: /var/tmp/hubs.db
-    chdir: "{{ hubs_code_dir }}"
+
+# Set up, create, and populate the database.
+- include: db-{{ hubs_database_type }}.yml
+
 
 # Set up JavaScript requirements
 - name: Install npm packages
diff --git a/ansible/roles/hubs-dev/templates/fedmsg_config b/ansible/roles/hubs-dev/templates/fedmsg_config
index 0b33780..c54fdb2 100644
--- a/ansible/roles/hubs-dev/templates/fedmsg_config
+++ b/ansible/roles/hubs-dev/templates/fedmsg_config
@@ -1,7 +1,11 @@
 config = {
     
     # Database
+    {% if hubs_db_type == "postgresql" %}
+    'hubs.sqlalchemy.uri': 'postgresql://hubs:{{ hubs_db_password }}@localhost/hubs',
+    {% else %}
     'hubs.sqlalchemy.uri': 'sqlite:////var/lib/hubs/hubs.db',
+    {% endif %}
 
     # Some configuration for the general hubs cache.
     "fedora-hubs.cache": {

From 66f6dd2a443cdb5704814ddd8804a8679d75afcf Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 19 2017 22:44:58 +0000
Subject: [PATCH 853/1001] Deploy in a virtualenv with access to system packages


---

diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
index 5b3a341..b55a81a 100755
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -60,18 +60,21 @@
   pip:
     requirements: "{{ hubs_code_dir }}/requirements.txt"
     virtualenv: "{{ hubs_venv_dir}}"
+    virtualenv_site_packages: yes
 
 - name: Install Fedora Hubs test-requirements.txt into hubs virtualenv
   become_user: "{{ main_user }}"
   pip:
     requirements: "{{ hubs_code_dir }}/test-requirements.txt"
     virtualenv: "{{ hubs_venv_dir}}"
+    virtualenv_site_packages: yes
 
 - name: Install other packages into hubs virtualenv
   become_user: "{{ main_user }}"
   pip:
     name: "{{ item }}"
     virtualenv: "{{ hubs_venv_dir }}"
+    virtualenv_site_packages: yes
   with_items:
     - bleach
     - gunicorn

From e41282c3e275b7687ef58bd0a3eec00793f93d31 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 19 2017 22:45:43 +0000
Subject: [PATCH 854/1001] Deploy services


---

diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
index b55a81a..75c0736 100755
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ b/ansible/roles/hubs-dev/tasks/main.yml
@@ -5,6 +5,13 @@
     - git
     - vim-enhanced
 
+- name: Install external dependencies
+  dnf: name={{ item }} state=present
+  with_items:
+    - npm
+    - redis
+    - fedmsg-hub
+
 - name: Install Fedora Hubs development packages
   dnf: name={{ item }} state=present
   with_items:
@@ -50,10 +57,6 @@
   template: src=bashrc dest=/home/{{ main_user }}/.bashrc
 
 
-- name: Start and enable fedmsg-hub
-  service: name=fedmsg-hub state=started enabled=yes
-
-
 # Set up the Python development environment
 - name: Install Fedora Hubs requirements.txt into hubs virtualenv
   become_user: "{{ main_user }}"
@@ -131,3 +134,28 @@
   become_user: "{{ main_user }}"
   args:
     chdir: "{{ hubs_code_dir }}/hubs/static/client"
+
+# Services
+- name: Disable the system-wide fedmsg-hub
+  service: name=fedmsg-hub state=stopped enabled=no
+
+- name: Install the service files
+  template:
+    src: "{{ item }}.service"
+    dest: /etc/systemd/system/{{ item }}.service
+  with_items:
+    - hubs-webapp
+    - hubs-triage@
+    - hubs-worker@
+    - hubs-fedmsg-hub
+
+- name: Start and enable the services
+  service: name={{ item }} state=started enabled=yes
+  with_items:
+    - redis
+    - hubs-webapp
+    - hubs-triage@1
+    - hubs-triage@2
+    - hubs-worker@1
+    - hubs-worker@2
+    - hubs-fedmsg-hub

From dc681906692edb90839077a8272836967125a00b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 20 2017 03:42:15 +0000
Subject: [PATCH 855/1001] Rename ansible role to be more generic


---

diff --git a/ansible/roles/hubs-dev/defaults/main.yml b/ansible/roles/hubs-dev/defaults/main.yml
deleted file mode 100644
index 8f50281..0000000
--- a/ansible/roles/hubs-dev/defaults/main.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-main_user: hubs
-hubs_dev_mode: yes
-hubs_secret_key: changeme
-hubs_code_dir: "/home/{{ main_user }}/devel"
-hubs_venv_dir: "/home/{{ main_user }}/.virtualenvs/hubs"
-hubs_db_type: sqlite
-hubs_db_password: changeme
-hubs_url: http://localhost:5000
diff --git a/ansible/roles/hubs-dev/files/pg_hba.conf b/ansible/roles/hubs-dev/files/pg_hba.conf
deleted file mode 100644
index c703fd9..0000000
--- a/ansible/roles/hubs-dev/files/pg_hba.conf
+++ /dev/null
@@ -1,14 +0,0 @@
-# PostgreSQL Client Authentication Configuration File
-# ===================================================
-#
-# Refer to the "Client Authentication" section in the PostgreSQL
-# documentation for a complete description of this file.
-
-# TYPE  DATABASE        USER            ADDRESS                 METHOD
-
-# "local" is for Unix domain socket connections only
-local   all             all                                     peer
-# IPv4 local connections:
-host    all             all             127.0.0.1/32            md5
-# IPv6 local connections:
-host    all             all             ::1/128                 md5
diff --git a/ansible/roles/hubs-dev/handlers/main.yml b/ansible/roles/hubs-dev/handlers/main.yml
deleted file mode 100644
index 5d4ca3e..0000000
--- a/ansible/roles/hubs-dev/handlers/main.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-- name: restart postgresql
-  service: name=postgresql state=restarted
-
-- name: restart fedmsg-hub
-  service: name=fedmsg-hub state=restarted
diff --git a/ansible/roles/hubs-dev/tasks/db-postgresql.yml b/ansible/roles/hubs-dev/tasks/db-postgresql.yml
deleted file mode 100644
index d228b80..0000000
--- a/ansible/roles/hubs-dev/tasks/db-postgresql.yml
+++ /dev/null
@@ -1,54 +0,0 @@
-# Set up Postgres, create the database, and populate it.
-
-- name: Install dependencies
-  dnf: name={{ item }} state=present
-  with_items:
-    - postgresql-server
-    - python-psycopg2
-
-- name: Set up postgresql database
-  command: postgresql-setup --initdb
-  args:
-      creates: /var/lib/pgsql/data/base
-
-- name: Set up postgresql access rules to allow local access
-  copy:
-      src: pg_hba.conf
-      dest: /var/lib/pgsql/data/pg_hba.conf
-      owner: postgres
-      group: postgres
-      mode: 0600
-  notify: restart postgresql
-
-- name: Start and enable postgresql
-  service: name=postgresql state=started enabled=yes
-
-- name: Set up the DB user
-  postgresql_user:
-      name: hubs
-      password: "{{ hubs_db_password }}"
-      role_attr_flags: NOSUPERUSER,NOCREATEROLE,NOCREATEDB
-  become_user: postgres
-
-- name: Create the database
-  postgresql_db:
-      name: hubs
-      owner: hubs
-  register: db_creation
-  become_user: postgres
-
-- name: Ease local access to the database
-  copy:
-    content: "*:*:hubs:hubs:{{ hubs_db_password }}"
-    dest: /home/{{ main_user }}/.pgpass
-    mode: 600
-    owner: "{{ main_user }}"
-    group: "{{ main_user }}"
-
-- name: Populate the Fedora Hubs database
-  command: "{{ hubs_venv_dir }}/bin/python {{ hubs_code_dir }}/populate.py"
-  args:
-    chdir: "{{ hubs_code_dir }}"
-  become_user: "{{ main_user }}"
-  when: db_creation|succeeded
-
diff --git a/ansible/roles/hubs-dev/tasks/db-sqlite.yml b/ansible/roles/hubs-dev/tasks/db-sqlite.yml
deleted file mode 100644
index 120e1c7..0000000
--- a/ansible/roles/hubs-dev/tasks/db-sqlite.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-- name: Create and populate the Fedora Hubs database
-  command: "{{ hubs_venv_dir }}/bin/python {{ hubs_code_dir }}/populate.py"
-  become_user: "{{ main_user }}"
-  args:
-    creates: /var/lib/hubs/hubs.db
-    chdir: "{{ hubs_code_dir }}"
diff --git a/ansible/roles/hubs-dev/tasks/main.yml b/ansible/roles/hubs-dev/tasks/main.yml
deleted file mode 100755
index 75c0736..0000000
--- a/ansible/roles/hubs-dev/tasks/main.yml
+++ /dev/null
@@ -1,161 +0,0 @@
----
-- name: Install helpful development packages
-  dnf: name={{ item }} state=present
-  with_items:
-    - git
-    - vim-enhanced
-
-- name: Install external dependencies
-  dnf: name={{ item }} state=present
-  with_items:
-    - npm
-    - redis
-    - fedmsg-hub
-
-- name: Install Fedora Hubs development packages
-  dnf: name={{ item }} state=present
-  with_items:
-    - gcc
-    - gcc-c++
-    - libffi-devel
-    - openssl-devel
-    - python-sphinx
-    - python-virtualenvwrapper
-    - python2-devel
-    - python3-devel
-    - redhat-rpm-config
-    - sqlite-devel
-
-- name: Install the distribution versions of requirements.txt
-  dnf: name={{ item }} state=present
-  with_items:
-    - python-arrow
-    - python-bleach
-    - python-decorator
-    - python-dogpile-cache
-    - python-fedmsg-core
-    - python-fedmsg-meta-fedora-infrastructure
-    - python-flask
-    - python3-flask-oidc
-    - python-fmn-lib
-    - python-fmn-rules
-    - python-gunicorn
-    - python-html5lib
-    - python-munch
-    - pytz
-    - python-sqlalchemy
-    - python-markdown
-    - python2-pkgwat-api
-    - python-six
-    - python-pygments
-    - python-pygments-markdown-lexer
-    - python-retask
-
-
-# Add various helpful configuration files
-- name: Install a custom bashrc
-  template: src=bashrc dest=/home/{{ main_user }}/.bashrc
-
-
-# Set up the Python development environment
-- name: Install Fedora Hubs requirements.txt into hubs virtualenv
-  become_user: "{{ main_user }}"
-  pip:
-    requirements: "{{ hubs_code_dir }}/requirements.txt"
-    virtualenv: "{{ hubs_venv_dir}}"
-    virtualenv_site_packages: yes
-
-- name: Install Fedora Hubs test-requirements.txt into hubs virtualenv
-  become_user: "{{ main_user }}"
-  pip:
-    requirements: "{{ hubs_code_dir }}/test-requirements.txt"
-    virtualenv: "{{ hubs_venv_dir}}"
-    virtualenv_site_packages: yes
-
-- name: Install other packages into hubs virtualenv
-  become_user: "{{ main_user }}"
-  pip:
-    name: "{{ item }}"
-    virtualenv: "{{ hubs_venv_dir }}"
-    virtualenv_site_packages: yes
-  with_items:
-    - bleach
-    - gunicorn
-
-- name: Update httplib2 trust store
-  copy:
-    src: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
-    dest: /home/{{ main_user }}/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
-    remote_src: True
-
-- name: Add a basic Hubs configuration file
-  template:
-    src: [hubs_config, hubs_config.{{ ansible_group }}, hubs_config.{{ ansible_hostname }}]
-    dest: "{{ hubs_code_dir }}/config"
-  become_user: "{{ main_user }}"
-
-- name: Add a basic fedmsg configuration file
-  template:
-    src: [fedmsg_config, fedmsg_config.{{ ansible_group }}, fedmsg_config.{{ ansible_hostname }}]
-    dest: "/etc/fedmsg.d/hubs_config.py"
-  become_user: "{{ main_user }}"
-
-- name: Create a directory for variable files
-  file:
-    path: "/var/lib/hubs"
-    state: directory
-    owner: "{{ main_user }}"
-    group: "{{ main_user }}"
-    mode: 755
-    setype: httpd_sys_content_rw_t
-
-- name: Configure application to authenticate with iddev.fedorainfracloud.org
-  command: oidc-register https://iddev.fedorainfracloud.org/ {{hubs_url}}
-  become_user: "{{ main_user }}"
-  args:
-    creates: client_secrets.json
-    chdir: "{{ hubs_code_dir }}"
-
-
-# Set up, create, and populate the database.
-- include: db-{{ hubs_database_type }}.yml
-
-
-# Set up JavaScript requirements
-- name: Install npm packages
-  command: npm install
-  become_user: "{{ main_user }}"
-  args:
-    creates: node_modules
-    chdir: "{{ hubs_code_dir }}/hubs/static/client"
-
-- name: Build JavaScript assests
-  command: node_modules/.bin/webpack
-  become_user: "{{ main_user }}"
-  args:
-    chdir: "{{ hubs_code_dir }}/hubs/static/client"
-
-# Services
-- name: Disable the system-wide fedmsg-hub
-  service: name=fedmsg-hub state=stopped enabled=no
-
-- name: Install the service files
-  template:
-    src: "{{ item }}.service"
-    dest: /etc/systemd/system/{{ item }}.service
-  with_items:
-    - hubs-webapp
-    - hubs-triage@
-    - hubs-worker@
-    - hubs-fedmsg-hub
-
-- name: Start and enable the services
-  service: name={{ item }} state=started enabled=yes
-  with_items:
-    - redis
-    - hubs-webapp
-    - hubs-triage@1
-    - hubs-triage@2
-    - hubs-worker@1
-    - hubs-worker@2
-    - hubs-fedmsg-hub
diff --git a/ansible/roles/hubs-dev/templates/bashrc b/ansible/roles/hubs-dev/templates/bashrc
deleted file mode 100644
index db0746d..0000000
--- a/ansible/roles/hubs-dev/templates/bashrc
+++ /dev/null
@@ -1,45 +0,0 @@
-# .bashrc
-
-# Source global definitions
-if [ -f /etc/bashrc ]; then
-    . /etc/bashrc
-fi
-
-# Uncomment the following line if you don't like systemctl's auto-paging feature:
-# export SYSTEMD_PAGER=
-
-# User specific aliases and functions
-# If adding new functions to this file, note that you can add help text to the function
-# by defining a variable with name _<function>_help containing the help text
-
-# Set up virtualenvwrapper
-export WORKON_HOME=$HOME/.virtualenvs
-export PIP_VIRTUALENV_BASE=$WORKON_HOME
-export VIRTUALENV_USE_DISTRIBUTE=true
-export PIP_RESPECT_VIRTUALENV=true
-source /usr/bin/virtualenvwrapper.sh
-
-export HUBS_CONFIG={{ hubs_code_dir }}/config
-export FLASK_APP={{ hubs_code_dir }}/hubs/app.py
-
-
-hup() {
-    workon hubs
-    pushd {{ hubs_code_dir }}
-    FLASK_DEBUG=1 flask run --host 0.0.0.0
-}
-
-hreset() {
-    workon hubs
-    {% if hubs_db_type == "postgresql" %}
-    sudo -u postgres dropdb hubs
-    sudo -u postgres createdb -O hubs hubs
-    {% else %}
-    rm /var/lib/hubs/hubs.db
-    {% endif %}
-    rm /var/lib/hubs/cache.db
-    pushd {{ hubs_code_dir }}
-    python populate.py
-    popd
-    deactivate
-}
diff --git a/ansible/roles/hubs-dev/templates/fedmsg_config b/ansible/roles/hubs-dev/templates/fedmsg_config
deleted file mode 100644
index c54fdb2..0000000
--- a/ansible/roles/hubs-dev/templates/fedmsg_config
+++ /dev/null
@@ -1,19 +0,0 @@
-config = {
-    
-    # Database
-    {% if hubs_db_type == "postgresql" %}
-    'hubs.sqlalchemy.uri': 'postgresql://hubs:{{ hubs_db_password }}@localhost/hubs',
-    {% else %}
-    'hubs.sqlalchemy.uri': 'sqlite:////var/lib/hubs/hubs.db',
-    {% endif %}
-
-    # Some configuration for the general hubs cache.
-    "fedora-hubs.cache": {
-        "backend": "dogpile.cache.dbm",
-        #"expiration_time": 0,
-        "arguments": {
-            "filename": "/var/lib/hubs/cache.db",
-        },
-    },
-}
-
diff --git a/ansible/roles/hubs-dev/templates/hubs-fedmsg-hub.service b/ansible/roles/hubs-dev/templates/hubs-fedmsg-hub.service
deleted file mode 100644
index cc2b96e..0000000
--- a/ansible/roles/hubs-dev/templates/hubs-fedmsg-hub.service
+++ /dev/null
@@ -1,15 +0,0 @@
-[Unit]
-Description=Hubs-specific fedmsg processing hub
-After=network.target
-Documentation=https://fedmsg.readthedocs.org/
-
-[Service]
-ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/fedmsg-hub
-WorkingDirectory={{ hubs_code_dir }}
-Type=simple
-User=fedmsg
-Group=fedmsg
-Restart=on-failure
-
-[Install]
-WantedBy=multi-user.target
diff --git a/ansible/roles/hubs-dev/templates/hubs-triage@.service b/ansible/roles/hubs-dev/templates/hubs-triage@.service
deleted file mode 100644
index fc74242..0000000
--- a/ansible/roles/hubs-dev/templates/hubs-triage@.service
+++ /dev/null
@@ -1,16 +0,0 @@
-[Unit]
-Description=fedora-hubs triage worker #%i
-After=network.target
-Documentation=https://pagure.io/fedora-hubs/
-
-[Service]
-ExecStart={{ hubs_venv_dir }}/bin/fedora-hubs-triage
-WorkingDirectory={{ hubs_code_dir }}
-Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
-Type=simple
-User={{ main_user }}
-Group={{ main_user }}
-Restart=on-failure
-
-[Install]
-WantedBy=multi-user.target
diff --git a/ansible/roles/hubs-dev/templates/hubs-webapp.service b/ansible/roles/hubs-dev/templates/hubs-webapp.service
deleted file mode 100644
index 00ba431..0000000
--- a/ansible/roles/hubs-dev/templates/hubs-webapp.service
+++ /dev/null
@@ -1,16 +0,0 @@
-[Unit]
-Description=fedora-hubs frontend webapp
-After=network.target
-Documentation=https://pagure.io/fedora-hubs/
-
-[Service]
-ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/gunicorn -b 0.0.0.0:80 --threads 12 --log-config logging.ini --reload hubs.app:app
-WorkingDirectory={{ hubs_code_dir }}
-Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
-Type=simple
-User={{ main_user }}
-Group={{ main_user }}
-Restart=on-failure
-
-[Install]
-WantedBy=multi-user.target
diff --git a/ansible/roles/hubs-dev/templates/hubs-worker@.service b/ansible/roles/hubs-dev/templates/hubs-worker@.service
deleted file mode 100644
index 8073577..0000000
--- a/ansible/roles/hubs-dev/templates/hubs-worker@.service
+++ /dev/null
@@ -1,16 +0,0 @@
-[Unit]
-Description=fedora-hubs cache worker #%i
-After=network.target
-Documentation=https://pagure.io/fedora-hubs/
-
-[Service]
-ExecStart={{ hubs_venv_dir }}/bin/fedora-hubs-worker
-WorkingDirectory={{ hubs_code_dir }}
-Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
-Type=simple
-User={{ main_user }}
-Group={{ main_user }}
-Restart=on-failure
-
-[Install]
-WantedBy=multi-user.target
diff --git a/ansible/roles/hubs-dev/templates/hubs_config b/ansible/roles/hubs-dev/templates/hubs_config
deleted file mode 100644
index d5a5394..0000000
--- a/ansible/roles/hubs-dev/templates/hubs_config
+++ /dev/null
@@ -1,8 +0,0 @@
-# Enter any hubs configuration here
-
-SECRET_KEY = "{{ hubs_secret_key }}"
-
-{% if hubs_dev_mode %}
-# Allow the cookie to be sent of http since we work on localhost
-OIDC_ID_TOKEN_COOKIE_SECURE = False
-{% endif %}
diff --git a/ansible/roles/hubs/defaults/main.yml b/ansible/roles/hubs/defaults/main.yml
new file mode 100644
index 0000000..8f50281
--- /dev/null
+++ b/ansible/roles/hubs/defaults/main.yml
@@ -0,0 +1,8 @@
+main_user: hubs
+hubs_dev_mode: yes
+hubs_secret_key: changeme
+hubs_code_dir: "/home/{{ main_user }}/devel"
+hubs_venv_dir: "/home/{{ main_user }}/.virtualenvs/hubs"
+hubs_db_type: sqlite
+hubs_db_password: changeme
+hubs_url: http://localhost:5000
diff --git a/ansible/roles/hubs/files/pg_hba.conf b/ansible/roles/hubs/files/pg_hba.conf
new file mode 100644
index 0000000..c703fd9
--- /dev/null
+++ b/ansible/roles/hubs/files/pg_hba.conf
@@ -0,0 +1,14 @@
+# PostgreSQL Client Authentication Configuration File
+# ===================================================
+#
+# Refer to the "Client Authentication" section in the PostgreSQL
+# documentation for a complete description of this file.
+
+# TYPE  DATABASE        USER            ADDRESS                 METHOD
+
+# "local" is for Unix domain socket connections only
+local   all             all                                     peer
+# IPv4 local connections:
+host    all             all             127.0.0.1/32            md5
+# IPv6 local connections:
+host    all             all             ::1/128                 md5
diff --git a/ansible/roles/hubs/handlers/main.yml b/ansible/roles/hubs/handlers/main.yml
new file mode 100644
index 0000000..5d4ca3e
--- /dev/null
+++ b/ansible/roles/hubs/handlers/main.yml
@@ -0,0 +1,5 @@
+- name: restart postgresql
+  service: name=postgresql state=restarted
+
+- name: restart fedmsg-hub
+  service: name=fedmsg-hub state=restarted
diff --git a/ansible/roles/hubs/tasks/db-postgresql.yml b/ansible/roles/hubs/tasks/db-postgresql.yml
new file mode 100644
index 0000000..d228b80
--- /dev/null
+++ b/ansible/roles/hubs/tasks/db-postgresql.yml
@@ -0,0 +1,54 @@
+# Set up Postgres, create the database, and populate it.
+
+- name: Install dependencies
+  dnf: name={{ item }} state=present
+  with_items:
+    - postgresql-server
+    - python-psycopg2
+
+- name: Set up postgresql database
+  command: postgresql-setup --initdb
+  args:
+      creates: /var/lib/pgsql/data/base
+
+- name: Set up postgresql access rules to allow local access
+  copy:
+      src: pg_hba.conf
+      dest: /var/lib/pgsql/data/pg_hba.conf
+      owner: postgres
+      group: postgres
+      mode: 0600
+  notify: restart postgresql
+
+- name: Start and enable postgresql
+  service: name=postgresql state=started enabled=yes
+
+- name: Set up the DB user
+  postgresql_user:
+      name: hubs
+      password: "{{ hubs_db_password }}"
+      role_attr_flags: NOSUPERUSER,NOCREATEROLE,NOCREATEDB
+  become_user: postgres
+
+- name: Create the database
+  postgresql_db:
+      name: hubs
+      owner: hubs
+  register: db_creation
+  become_user: postgres
+
+- name: Ease local access to the database
+  copy:
+    content: "*:*:hubs:hubs:{{ hubs_db_password }}"
+    dest: /home/{{ main_user }}/.pgpass
+    mode: 600
+    owner: "{{ main_user }}"
+    group: "{{ main_user }}"
+
+- name: Populate the Fedora Hubs database
+  command: "{{ hubs_venv_dir }}/bin/python {{ hubs_code_dir }}/populate.py"
+  args:
+    chdir: "{{ hubs_code_dir }}"
+  become_user: "{{ main_user }}"
+  when: db_creation|succeeded
+
diff --git a/ansible/roles/hubs/tasks/db-sqlite.yml b/ansible/roles/hubs/tasks/db-sqlite.yml
new file mode 100644
index 0000000..120e1c7
--- /dev/null
+++ b/ansible/roles/hubs/tasks/db-sqlite.yml
@@ -0,0 +1,6 @@
+- name: Create and populate the Fedora Hubs database
+  command: "{{ hubs_venv_dir }}/bin/python {{ hubs_code_dir }}/populate.py"
+  become_user: "{{ main_user }}"
+  args:
+    creates: /var/lib/hubs/hubs.db
+    chdir: "{{ hubs_code_dir }}"
diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
new file mode 100644
index 0000000..de8f328
--- /dev/null
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -0,0 +1,168 @@
+---
+- name: Install helpful development packages
+  dnf: name={{ item }} state=present
+  with_items:
+    - git
+    - vim-enhanced
+
+- name: Install external dependencies
+  dnf: name={{ item }} state=present
+  with_items:
+    - npm
+    - redis
+    - fedmsg-hub
+
+- name: Install Fedora Hubs development packages
+  dnf: name={{ item }} state=present
+  with_items:
+    - gcc
+    - gcc-c++
+    - libffi-devel
+    - openssl-devel
+    - python-sphinx
+    - python-virtualenvwrapper
+    - python2-devel
+    - python3-devel
+    - redhat-rpm-config
+    - sqlite-devel
+
+- name: Install the distribution versions of requirements.txt
+  dnf: name={{ item }} state=present
+  with_items:
+    - python-alembic
+    - python-arrow
+    - python-bleach
+    - python-decorator
+    - python-dogpile-cache
+    - python-fedmsg-core
+    - python-fedmsg-meta-fedora-infrastructure
+    - python-flask
+    - python-flask-oidc
+    - python-fmn-lib
+    - python-fmn-rules
+    - python-gunicorn
+    - python-futures
+    - python-html5lib
+    - python-munch
+    - pytz
+    - python-sqlalchemy
+    - python-markdown
+    - python2-pkgwat-api
+    - python-six
+    - python-pygments
+    - python-pygments-markdown-lexer
+    - python-retask
+
+
+# Add various helpful configuration files
+- name: Install a custom bashrc
+  template: src=bashrc dest=/home/{{ main_user }}/.bashrc
+
+
+# Set up the Python development environment
+- name: Install Fedora Hubs requirements.txt into hubs virtualenv
+  become_user: "{{ main_user }}"
+  pip:
+    requirements: "{{ hubs_code_dir }}/requirements.txt"
+    virtualenv: "{{ hubs_venv_dir}}"
+    virtualenv_site_packages: yes
+
+- name: Install Fedora Hubs test-requirements.txt into hubs virtualenv
+  become_user: "{{ main_user }}"
+  pip:
+    requirements: "{{ hubs_code_dir }}/test-requirements.txt"
+    virtualenv: "{{ hubs_venv_dir}}"
+    virtualenv_site_packages: yes
+
+- name: Install other packages into hubs virtualenv
+  become_user: "{{ main_user }}"
+  pip:
+    name: "{{ item }}"
+    virtualenv: "{{ hubs_venv_dir }}"
+    virtualenv_site_packages: yes
+  with_items:
+    - bleach
+    - gunicorn
+
+#- name: Update httplib2 trust store
+#  copy:
+#    src: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
+#    dest: /home/{{ main_user }}/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
+#    remote_src: True
+
+- name: Add a basic Hubs configuration file
+  template:
+    src: "{{ item }}"
+    dest: "{{ hubs_code_dir }}/config"
+  with_first_found:
+    - hubs_config.{{ ansible_hostname }}
+    - hubs_config
+  become_user: "{{ main_user }}"
+
+- name: Add a basic fedmsg configuration file
+  template:
+    src: "{{ item }}"
+    dest: "/etc/fedmsg.d/hubs_config.py"
+  with_first_found:
+    - fedmsg_config.{{ ansible_hostname }}
+    - fedmsg_config
+
+- name: Create a directory for variable files
+  file:
+    path: "/var/lib/hubs"
+    state: directory
+    owner: "{{ main_user }}"
+    group: "{{ main_user }}"
+    mode: 755
+    setype: httpd_sys_content_rw_t
+
+- name: Configure application to authenticate with iddev.fedorainfracloud.org
+  command: oidc-register https://iddev.fedorainfracloud.org/ {{hubs_url}}
+  become_user: "{{ main_user }}"
+  args:
+    creates: client_secrets.json
+    chdir: "{{ hubs_code_dir }}"
+
+
+# Set up, create, and populate the database.
+- include: db-{{ hubs_db_type }}.yml
+
+
+# Set up JavaScript requirements
+- name: Install npm packages
+  command: npm install
+  become_user: "{{ main_user }}"
+  args:
+    creates: node_modules
+    chdir: "{{ hubs_code_dir }}/hubs/static/client"
+
+- name: Build JavaScript assests
+  command: node_modules/.bin/webpack
+  become_user: "{{ main_user }}"
+  args:
+    chdir: "{{ hubs_code_dir }}/hubs/static/client"
+
+# Services
+- name: Disable the system-wide fedmsg-hub
+  service: name=fedmsg-hub state=stopped enabled=no
+
+- name: Install the service files
+  template:
+    src: "{{ item }}.service"
+    dest: /etc/systemd/system/{{ item }}.service
+  with_items:
+    - hubs-webapp
+    - hubs-triage@
+    - hubs-worker@
+    - hubs-fedmsg-hub
+
+- name: Start and enable the services
+  service: name={{ item }} state=started enabled=yes
+  with_items:
+    - redis
+    - hubs-webapp
+    - hubs-triage@1
+    - hubs-triage@2
+    - hubs-worker@1
+    - hubs-worker@2
+    - hubs-fedmsg-hub
diff --git a/ansible/roles/hubs/templates/bashrc b/ansible/roles/hubs/templates/bashrc
new file mode 100644
index 0000000..db0746d
--- /dev/null
+++ b/ansible/roles/hubs/templates/bashrc
@@ -0,0 +1,45 @@
+# .bashrc
+
+# Source global definitions
+if [ -f /etc/bashrc ]; then
+    . /etc/bashrc
+fi
+
+# Uncomment the following line if you don't like systemctl's auto-paging feature:
+# export SYSTEMD_PAGER=
+
+# User specific aliases and functions
+# If adding new functions to this file, note that you can add help text to the function
+# by defining a variable with name _<function>_help containing the help text
+
+# Set up virtualenvwrapper
+export WORKON_HOME=$HOME/.virtualenvs
+export PIP_VIRTUALENV_BASE=$WORKON_HOME
+export VIRTUALENV_USE_DISTRIBUTE=true
+export PIP_RESPECT_VIRTUALENV=true
+source /usr/bin/virtualenvwrapper.sh
+
+export HUBS_CONFIG={{ hubs_code_dir }}/config
+export FLASK_APP={{ hubs_code_dir }}/hubs/app.py
+
+
+hup() {
+    workon hubs
+    pushd {{ hubs_code_dir }}
+    FLASK_DEBUG=1 flask run --host 0.0.0.0
+}
+
+hreset() {
+    workon hubs
+    {% if hubs_db_type == "postgresql" %}
+    sudo -u postgres dropdb hubs
+    sudo -u postgres createdb -O hubs hubs
+    {% else %}
+    rm /var/lib/hubs/hubs.db
+    {% endif %}
+    rm /var/lib/hubs/cache.db
+    pushd {{ hubs_code_dir }}
+    python populate.py
+    popd
+    deactivate
+}
diff --git a/ansible/roles/hubs/templates/fedmsg_config b/ansible/roles/hubs/templates/fedmsg_config
new file mode 100644
index 0000000..c54fdb2
--- /dev/null
+++ b/ansible/roles/hubs/templates/fedmsg_config
@@ -0,0 +1,19 @@
+config = {
+    
+    # Database
+    {% if hubs_db_type == "postgresql" %}
+    'hubs.sqlalchemy.uri': 'postgresql://hubs:{{ hubs_db_password }}@localhost/hubs',
+    {% else %}
+    'hubs.sqlalchemy.uri': 'sqlite:////var/lib/hubs/hubs.db',
+    {% endif %}
+
+    # Some configuration for the general hubs cache.
+    "fedora-hubs.cache": {
+        "backend": "dogpile.cache.dbm",
+        #"expiration_time": 0,
+        "arguments": {
+            "filename": "/var/lib/hubs/cache.db",
+        },
+    },
+}
+
diff --git a/ansible/roles/hubs/templates/hubs-fedmsg-hub.service b/ansible/roles/hubs/templates/hubs-fedmsg-hub.service
new file mode 100644
index 0000000..cc2b96e
--- /dev/null
+++ b/ansible/roles/hubs/templates/hubs-fedmsg-hub.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Hubs-specific fedmsg processing hub
+After=network.target
+Documentation=https://fedmsg.readthedocs.org/
+
+[Service]
+ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/fedmsg-hub
+WorkingDirectory={{ hubs_code_dir }}
+Type=simple
+User=fedmsg
+Group=fedmsg
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/hubs/templates/hubs-triage@.service b/ansible/roles/hubs/templates/hubs-triage@.service
new file mode 100644
index 0000000..fc74242
--- /dev/null
+++ b/ansible/roles/hubs/templates/hubs-triage@.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=fedora-hubs triage worker #%i
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart={{ hubs_venv_dir }}/bin/fedora-hubs-triage
+WorkingDirectory={{ hubs_code_dir }}
+Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
+Type=simple
+User={{ main_user }}
+Group={{ main_user }}
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/hubs/templates/hubs-webapp.service b/ansible/roles/hubs/templates/hubs-webapp.service
new file mode 100644
index 0000000..00ba431
--- /dev/null
+++ b/ansible/roles/hubs/templates/hubs-webapp.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=fedora-hubs frontend webapp
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/gunicorn -b 0.0.0.0:80 --threads 12 --log-config logging.ini --reload hubs.app:app
+WorkingDirectory={{ hubs_code_dir }}
+Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
+Type=simple
+User={{ main_user }}
+Group={{ main_user }}
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/hubs/templates/hubs-worker@.service b/ansible/roles/hubs/templates/hubs-worker@.service
new file mode 100644
index 0000000..8073577
--- /dev/null
+++ b/ansible/roles/hubs/templates/hubs-worker@.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=fedora-hubs cache worker #%i
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart={{ hubs_venv_dir }}/bin/fedora-hubs-worker
+WorkingDirectory={{ hubs_code_dir }}
+Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
+Type=simple
+User={{ main_user }}
+Group={{ main_user }}
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/hubs/templates/hubs_config b/ansible/roles/hubs/templates/hubs_config
new file mode 100644
index 0000000..d5a5394
--- /dev/null
+++ b/ansible/roles/hubs/templates/hubs_config
@@ -0,0 +1,8 @@
+# Enter any hubs configuration here
+
+SECRET_KEY = "{{ hubs_secret_key }}"
+
+{% if hubs_dev_mode %}
+# Allow the cookie to be sent of http since we work on localhost
+OIDC_ID_TOKEN_COOKIE_SECURE = False
+{% endif %}
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
index 623d093..d2a5e98 100644
--- a/ansible/vagrant-playbook.yml
+++ b/ansible/vagrant-playbook.yml
@@ -12,7 +12,7 @@
         dest: /etc/sudoers.d/vagrant-nopasswd
 
   roles:
-    - role: hubs-dev
+    - role: hubs
       hubs_secret_key: vagrantmachinesecretkey
       hubs_db_type: sqlite
       hubs_url: http://localhost:5000

From 77155d0ac5d0792bc73d947e72d3cefc615dae57 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 20 2017 03:42:27 +0000
Subject: [PATCH 856/1001] Missing dependency


---

diff --git a/requirements.txt b/requirements.txt
index 1eb3902..e2a8eb5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
+alembic
 arrow
 bleach<2.0.0
 blinker

From f7eb2655e9de1609057c96aac984e4cf052cb6a5 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 20 2017 04:21:12 +0000
Subject: [PATCH 857/1001] Gunicorn can't listen on a privileged port


---

diff --git a/ansible/roles/hubs/templates/hubs-webapp.service b/ansible/roles/hubs/templates/hubs-webapp.service
index 00ba431..3ed4220 100644
--- a/ansible/roles/hubs/templates/hubs-webapp.service
+++ b/ansible/roles/hubs/templates/hubs-webapp.service
@@ -4,7 +4,7 @@ After=network.target
 Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
-ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/gunicorn -b 0.0.0.0:80 --threads 12 --log-config logging.ini --reload hubs.app:app
+ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/gunicorn -b 0.0.0.0:8000 --threads 12 --log-config logging.ini --reload hubs.app:app
 WorkingDirectory={{ hubs_code_dir }}
 Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
 Type=simple

From 63ca8580b71de56bf73e94daf7005ddf0d18f293 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 10:00:03 +0000
Subject: [PATCH 858/1001] Use a F25 box for Vagrant


---

diff --git a/Vagrantfile.example b/Vagrantfile.example
index 7fff78d..c03dce5 100644
--- a/Vagrantfile.example
+++ b/Vagrantfile.example
@@ -4,7 +4,7 @@
 VAGRANTFILE_API_VERSION = "2"
 
 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
- config.vm.box = "fedora/24-cloud-base"
+ config.vm.box = "fedora/25-cloud-base"
 
  # Forward traffic on the host to the development server on the guest
  config.vm.network "forwarded_port", guest: 5000, host: 5000

From 1436e2c56290107cda10522e37ecd99ad8ac57b3 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 10:10:29 +0000
Subject: [PATCH 859/1001] Put the code, the config and the data in the FHS


---

diff --git a/Vagrantfile.example b/Vagrantfile.example
index c03dce5..5caa591 100644
--- a/Vagrantfile.example
+++ b/Vagrantfile.example
@@ -23,7 +23,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # If you would prefer to use NFS to share the directory uncomment this and configure NFS
  #config.vm.synced_folder ".", "/vagrant", type: "nfs", nfs_version: 4, nfs_udp: false
  config.vm.synced_folder ".", "/vagrant", disabled: true
- config.vm.synced_folder ".", "/home/vagrant/devel", type: "sshfs", sshfs_opts_append: "-o nonempty"
+ config.vm.synced_folder ".", "/srv/hubs/fedora-hubs", type: "sshfs", sshfs_opts_append: "-o nonempty"
 
  # To cache update packages (which is helpful if frequently doing `vagrant destroy && vagrant up`)
  # you can create a local directory and share it to the guest's DNF cache. The directory needs to
diff --git a/ansible/files/motd b/ansible/files/motd
index f3d92ab..6c75466 100644
--- a/ansible/files/motd
+++ b/ansible/files/motd
@@ -3,7 +3,7 @@ Welcome to the Fedora Hubs development environment!
 
 Here are some tips:
 
-* The code for Fedora Hubs is located at ~/devel/
+* The code for Fedora Hubs is located at /srv/hubs/fedora-hubs
 
 * You can type `workon hubs` to enter a configured Python virtualenv
 
diff --git a/ansible/roles/hubs/defaults/main.yml b/ansible/roles/hubs/defaults/main.yml
index 8f50281..ecd3429 100644
--- a/ansible/roles/hubs/defaults/main.yml
+++ b/ansible/roles/hubs/defaults/main.yml
@@ -1,8 +1,11 @@
 main_user: hubs
 hubs_dev_mode: yes
 hubs_secret_key: changeme
-hubs_code_dir: "/home/{{ main_user }}/devel"
-hubs_venv_dir: "/home/{{ main_user }}/.virtualenvs/hubs"
+hubs_base_dir: "/srv/hubs"
+hubs_code_dir: "{{ hubs_base_dir }}/fedora-hubs"
+hubs_conf_dir: "{{ hubs_base_dir }}/config"
+hubs_venv_dir: "{{ hubs_base_dir }}/venv"
+hubs_var_dir: "{{ hubs_base_dir }}/var"
 hubs_db_type: sqlite
 hubs_db_password: changeme
 hubs_url: http://localhost:5000
diff --git a/ansible/roles/hubs/tasks/db-sqlite.yml b/ansible/roles/hubs/tasks/db-sqlite.yml
index 120e1c7..ec27bb8 100644
--- a/ansible/roles/hubs/tasks/db-sqlite.yml
+++ b/ansible/roles/hubs/tasks/db-sqlite.yml
@@ -2,5 +2,5 @@
   command: "{{ hubs_venv_dir }}/bin/python {{ hubs_code_dir }}/populate.py"
   become_user: "{{ main_user }}"
   args:
-    creates: /var/lib/hubs/hubs.db
+    creates: "{{ hubs_var_dir }}/hubs.db"
     chdir: "{{ hubs_code_dir }}"
diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index de8f328..edeac23 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -11,6 +11,8 @@
     - npm
     - redis
     - fedmsg-hub
+    - python-virtualenv
+    - python3-flask-oidc
 
 - name: Install Fedora Hubs development packages
   dnf: name={{ item }} state=present
@@ -20,7 +22,6 @@
     - libffi-devel
     - openssl-devel
     - python-sphinx
-    - python-virtualenvwrapper
     - python2-devel
     - python3-devel
     - redhat-rpm-config
@@ -59,6 +60,22 @@
   template: src=bashrc dest=/home/{{ main_user }}/.bashrc
 
 
+# Create directory structure
+
+- name: Create the directory structure
+  file:
+    path: "{{ item.path }}"
+    state: directory
+    owner: "{{ main_user }}"
+    group: "{{ main_user }}"
+    mode: "{{ item.mode }}"
+    #setype: httpd_sys_content_rw_t
+  with_items:
+    - {path: "{{ hubs_base_dir }}", mode: 755}
+    - {path: "{{ hubs_conf_dir }}", mode: 750}
+    - {path: "{{ hubs_var_dir }}", mode: 755}
+
+
 # Set up the Python development environment
 - name: Install Fedora Hubs requirements.txt into hubs virtualenv
   become_user: "{{ main_user }}"
@@ -84,6 +101,21 @@
     - bleach
     - gunicorn
 
+- name: Install Fedora Hubs into the virtualenv
+  become_user: "{{ main_user }}"
+  pip:
+    name: "{{ hubs_code_dir }}"
+    editable: true
+    virtualenv: "{{ hubs_venv_dir}}"
+    virtualenv_site_packages: yes
+
+- name: Set bin file context in the virtualenv
+  file:
+    path: "{{ hubs_venv_dir }}/bin"
+    state: directory
+    recurse: true
+    setype: bin_t
+
 #- name: Update httplib2 trust store
 #  copy:
 #    src: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
@@ -93,11 +125,12 @@
 - name: Add a basic Hubs configuration file
   template:
     src: "{{ item }}"
-    dest: "{{ hubs_code_dir }}/config"
+    dest: "{{ hubs_conf_dir }}/hubs_config.py"
   with_first_found:
     - hubs_config.{{ ansible_hostname }}
     - hubs_config
   become_user: "{{ main_user }}"
+  notify: "hubs configuration change"
 
 - name: Add a basic fedmsg configuration file
   template:
@@ -106,6 +139,7 @@
   with_first_found:
     - fedmsg_config.{{ ansible_hostname }}
     - fedmsg_config
+  notify: "hubs configuration change"
 
 - name: Create a directory for variable files
   file:
@@ -117,11 +151,13 @@
     setype: httpd_sys_content_rw_t
 
 - name: Configure application to authenticate with iddev.fedorainfracloud.org
-  command: oidc-register https://iddev.fedorainfracloud.org/ {{hubs_url}}
+  command:
+    oidc-register
+    --output-file {{ hubs_conf_dir }}/client_secrets.json
+    https://iddev.fedorainfracloud.org/ {{ hubs_url }}
   become_user: "{{ main_user }}"
   args:
-    creates: client_secrets.json
-    chdir: "{{ hubs_code_dir }}"
+    creates: "{{ hubs_conf_dir }}/client_secrets.json"
 
 
 # Set up, create, and populate the database.
diff --git a/ansible/roles/hubs/templates/bashrc b/ansible/roles/hubs/templates/bashrc
index db0746d..8902729 100644
--- a/ansible/roles/hubs/templates/bashrc
+++ b/ansible/roles/hubs/templates/bashrc
@@ -12,32 +12,32 @@ fi
 # If adding new functions to this file, note that you can add help text to the function
 # by defining a variable with name _<function>_help containing the help text
 
-# Set up virtualenvwrapper
-export WORKON_HOME=$HOME/.virtualenvs
-export PIP_VIRTUALENV_BASE=$WORKON_HOME
-export VIRTUALENV_USE_DISTRIBUTE=true
-export PIP_RESPECT_VIRTUALENV=true
-source /usr/bin/virtualenvwrapper.sh
-
-export HUBS_CONFIG={{ hubs_code_dir }}/config
+
+export HUBS_CONFIG={{ hubs_conf_dir }}/hubs_config.py
 export FLASK_APP={{ hubs_code_dir }}/hubs/app.py
 
 
+workon() {
+    [ "$1" == "hubs" ] || ( echo "No such virtualenv."; exit 1 )
+    source {{ hubs_venv_dir }}/bin/activate
+    cd {{ hubs_code_dir }}
+}
+
 hup() {
-    workon hubs
+    source {{ hubs_venv_dir }}/bin/activate
     pushd {{ hubs_code_dir }}
-    FLASK_DEBUG=1 flask run --host 0.0.0.0
+    FLASK_DEBUG=1 flask run --host 0.0.0.0 --port 5000
 }
 
 hreset() {
-    workon hubs
+    source {{ hubs_venv_dir }}/bin/activate
     {% if hubs_db_type == "postgresql" %}
     sudo -u postgres dropdb hubs
     sudo -u postgres createdb -O hubs hubs
     {% else %}
-    rm /var/lib/hubs/hubs.db
+    rm {{ hubs_var_dir }}/hubs.db
     {% endif %}
-    rm /var/lib/hubs/cache.db
+    rm {{ hubs_var_dir }}/cache.db
     pushd {{ hubs_code_dir }}
     python populate.py
     popd
diff --git a/ansible/roles/hubs/templates/fedmsg_config b/ansible/roles/hubs/templates/fedmsg_config
index c54fdb2..fc15ac4 100644
--- a/ansible/roles/hubs/templates/fedmsg_config
+++ b/ansible/roles/hubs/templates/fedmsg_config
@@ -1,10 +1,10 @@
 config = {
-    
+
     # Database
     {% if hubs_db_type == "postgresql" %}
     'hubs.sqlalchemy.uri': 'postgresql://hubs:{{ hubs_db_password }}@localhost/hubs',
     {% else %}
-    'hubs.sqlalchemy.uri': 'sqlite:////var/lib/hubs/hubs.db',
+    'hubs.sqlalchemy.uri': 'sqlite:///{{ hubs_var_dir }}/hubs.db',
     {% endif %}
 
     # Some configuration for the general hubs cache.
@@ -12,7 +12,7 @@ config = {
         "backend": "dogpile.cache.dbm",
         #"expiration_time": 0,
         "arguments": {
-            "filename": "/var/lib/hubs/cache.db",
+            "filename": "{{ hubs_var_dir }}/cache.db",
         },
     },
 }
diff --git a/ansible/roles/hubs/templates/hubs-fedmsg-hub.service b/ansible/roles/hubs/templates/hubs-fedmsg-hub.service
index cc2b96e..ca56996 100644
--- a/ansible/roles/hubs/templates/hubs-fedmsg-hub.service
+++ b/ansible/roles/hubs/templates/hubs-fedmsg-hub.service
@@ -5,7 +5,6 @@ Documentation=https://fedmsg.readthedocs.org/
 
 [Service]
 ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/fedmsg-hub
-WorkingDirectory={{ hubs_code_dir }}
 Type=simple
 User=fedmsg
 Group=fedmsg
diff --git a/ansible/roles/hubs/templates/hubs-triage@.service b/ansible/roles/hubs/templates/hubs-triage@.service
index fc74242..06ccacc 100644
--- a/ansible/roles/hubs/templates/hubs-triage@.service
+++ b/ansible/roles/hubs/templates/hubs-triage@.service
@@ -5,8 +5,7 @@ Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
 ExecStart={{ hubs_venv_dir }}/bin/fedora-hubs-triage
-WorkingDirectory={{ hubs_code_dir }}
-Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
+Environment=HUBS_CONFIG={{ hubs_conf_dir }}/hubs_config.py
 Type=simple
 User={{ main_user }}
 Group={{ main_user }}
diff --git a/ansible/roles/hubs/templates/hubs-webapp.service b/ansible/roles/hubs/templates/hubs-webapp.service
index 3ed4220..59586d3 100644
--- a/ansible/roles/hubs/templates/hubs-webapp.service
+++ b/ansible/roles/hubs/templates/hubs-webapp.service
@@ -4,9 +4,13 @@ After=network.target
 Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
-ExecStart={{ hubs_venv_dir }}/bin/python /usr/bin/gunicorn -b 0.0.0.0:8000 --threads 12 --log-config logging.ini --reload hubs.app:app
-WorkingDirectory={{ hubs_code_dir }}
-Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
+ExecStart= \
+    {{ hubs_venv_dir }}/bin/python \
+    /usr/bin/gunicorn -b 127.0.0.1:8000 --threads 12 \
+    --log-config {{ hubs_conf_dir }}/logging.ini \
+    {% if hubs_dev_mode %}--reload{% endif %} \
+    hubs.app:app
+Environment=HUBS_CONFIG={{ hubs_conf_dir }}/hubs_config.py
 Type=simple
 User={{ main_user }}
 Group={{ main_user }}
diff --git a/ansible/roles/hubs/templates/hubs-worker@.service b/ansible/roles/hubs/templates/hubs-worker@.service
index 8073577..8f597f1 100644
--- a/ansible/roles/hubs/templates/hubs-worker@.service
+++ b/ansible/roles/hubs/templates/hubs-worker@.service
@@ -5,8 +5,7 @@ Documentation=https://pagure.io/fedora-hubs/
 
 [Service]
 ExecStart={{ hubs_venv_dir }}/bin/fedora-hubs-worker
-WorkingDirectory={{ hubs_code_dir }}
-Environment=HUBS_CONFIG={{ hubs_code_dir }}/config
+Environment=HUBS_CONFIG={{ hubs_conf_dir }}/hubs_config.py
 Type=simple
 User={{ main_user }}
 Group={{ main_user }}
diff --git a/ansible/roles/hubs/templates/hubs_config b/ansible/roles/hubs/templates/hubs_config
index d5a5394..d079537 100644
--- a/ansible/roles/hubs/templates/hubs_config
+++ b/ansible/roles/hubs/templates/hubs_config
@@ -6,3 +6,5 @@ SECRET_KEY = "{{ hubs_secret_key }}"
 # Allow the cookie to be sent of http since we work on localhost
 OIDC_ID_TOKEN_COOKIE_SECURE = False
 {% endif %}
+
+OIDC_CLIENT_SECRETS = "{{ hubs_conf_dir }}/client_secrets.json"
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
index d2a5e98..342ff0d 100644
--- a/ansible/vagrant-playbook.yml
+++ b/ansible/vagrant-playbook.yml
@@ -20,3 +20,9 @@
   tasks:
     - name: Install the message of the day
       copy: src=files/motd dest=/etc/motd
+
+    - name: Make a symlink to the code
+      file:
+        state: link
+        path: /home/{{ main_user }}/devel
+        src: /srv/hubs/fedora-hubs

From 503d4fb35d167b5cac34a49dbda41aef7892a838 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 10:50:26 +0000
Subject: [PATCH 860/1001] Deploy the webserver config in prod mode only


---

diff --git a/ansible/files/motd b/ansible/files/motd
index 6c75466..fdd814a 100644
--- a/ansible/files/motd
+++ b/ansible/files/motd
@@ -7,7 +7,7 @@ Here are some tips:
 
 * You can type `workon hubs` to enter a configured Python virtualenv
 
-* Run `hup` to start gunicorn
+* Run `hup` to start the flask webserver
 
 * Run `hreset` to delete the database and repopulate it
 
diff --git a/ansible/roles/hubs/defaults/main.yml b/ansible/roles/hubs/defaults/main.yml
index ecd3429..3f5cb63 100644
--- a/ansible/roles/hubs/defaults/main.yml
+++ b/ansible/roles/hubs/defaults/main.yml
@@ -1,5 +1,5 @@
 main_user: hubs
-hubs_dev_mode: yes
+hubs_dev_mode: false
 hubs_secret_key: changeme
 hubs_base_dir: "/srv/hubs"
 hubs_code_dir: "{{ hubs_base_dir }}/fedora-hubs"
@@ -8,4 +8,5 @@ hubs_venv_dir: "{{ hubs_base_dir }}/venv"
 hubs_var_dir: "{{ hubs_base_dir }}/var"
 hubs_db_type: sqlite
 hubs_db_password: changeme
-hubs_url: http://localhost:5000
+hubs_url_hostname: localhost
+hubs_url: http{% if not hubs_dev_mode %}s{% endif %}://{{ hubs_url_hostname }}{% if hubs_dev_mode %}:5000{% endif %}
diff --git a/ansible/roles/hubs/files/logging.ini b/ansible/roles/hubs/files/logging.ini
new file mode 100644
index 0000000..3512fa6
--- /dev/null
+++ b/ansible/roles/hubs/files/logging.ini
@@ -0,0 +1,23 @@
+# From https://docs.python.org/2/howto/logging.html
+[loggers]
+keys=root
+
+[handlers]
+keys=console
+
+[formatters]
+keys=simple
+
+[logger_root]
+level=DEBUG
+handlers=console
+
+[handler_console]
+class=StreamHandler
+level=DEBUG
+formatter=simple
+args=(sys.stdout,)
+
+[formatter_simple]
+format=[%(asctime)s][%(process)d][%(levelname)s] (%(name)s) %(message)s
+datefmt=%H:%M:%S
diff --git a/ansible/roles/hubs/handlers/main.yml b/ansible/roles/hubs/handlers/main.yml
index 5d4ca3e..62e0484 100644
--- a/ansible/roles/hubs/handlers/main.yml
+++ b/ansible/roles/hubs/handlers/main.yml
@@ -3,3 +3,6 @@
 
 - name: restart fedmsg-hub
   service: name=fedmsg-hub state=restarted
+
+# Webserver
+- include: webserver.yml
diff --git a/ansible/roles/hubs/handlers/webserver.yml b/ansible/roles/hubs/handlers/webserver.yml
new file mode 100644
index 0000000..e6cb871
--- /dev/null
+++ b/ansible/roles/hubs/handlers/webserver.yml
@@ -0,0 +1,7 @@
+- name: restart hubs webapp
+  service: name=hubs-webapp state=restarted
+  listen: "hubs configuration change"
+  when: not hubs_dev_mode
+
+- name: restart nginx
+  service: name=nginx state=restarted
diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index edeac23..43406e7 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -26,6 +26,7 @@
     - python3-devel
     - redhat-rpm-config
     - sqlite-devel
+  when: hubs_dev_mode
 
 - name: Install the distribution versions of requirements.txt
   dnf: name={{ item }} state=present
@@ -41,7 +42,6 @@
     - python-flask-oidc
     - python-fmn-lib
     - python-fmn-rules
-    - python-gunicorn
     - python-futures
     - python-html5lib
     - python-munch
@@ -58,6 +58,7 @@
 # Add various helpful configuration files
 - name: Install a custom bashrc
   template: src=bashrc dest=/home/{{ main_user }}/.bashrc
+  when: hubs_dev_mode
 
 
 # Create directory structure
@@ -99,7 +100,6 @@
     virtualenv_site_packages: yes
   with_items:
     - bleach
-    - gunicorn
 
 - name: Install Fedora Hubs into the virtualenv
   become_user: "{{ main_user }}"
@@ -178,16 +178,17 @@
   args:
     chdir: "{{ hubs_code_dir }}/hubs/static/client"
 
+
 # Services
 - name: Disable the system-wide fedmsg-hub
   service: name=fedmsg-hub state=stopped enabled=no
 
+
 - name: Install the service files
   template:
     src: "{{ item }}.service"
     dest: /etc/systemd/system/{{ item }}.service
   with_items:
-    - hubs-webapp
     - hubs-triage@
     - hubs-worker@
     - hubs-fedmsg-hub
@@ -196,9 +197,13 @@
   service: name={{ item }} state=started enabled=yes
   with_items:
     - redis
-    - hubs-webapp
     - hubs-triage@1
     - hubs-triage@2
     - hubs-worker@1
     - hubs-worker@2
     - hubs-fedmsg-hub
+
+
+# Webserver
+- include: webserver.yml
+  when: not hubs_dev_mode
diff --git a/ansible/roles/hubs/tasks/webserver.yml b/ansible/roles/hubs/tasks/webserver.yml
new file mode 100644
index 0000000..f070549
--- /dev/null
+++ b/ansible/roles/hubs/tasks/webserver.yml
@@ -0,0 +1,78 @@
+# Webserver config
+
+- name: Install the webserver packages
+  dnf: name={{ item }} state=present
+  with_items:
+    - python-gunicorn
+    - nginx
+    - make
+
+
+- name: Generate SSL certificate and key
+  shell:
+    echo -e "--\nSomeState\nSomeCity\nSomeOrganization\nSomeOrganizationalUnit\nlocalhost.localdomain\nroot@localhost.localdomain"
+    | openssl req -utf8 -newkey rsa:2048
+    -keyout /etc/pki/tls/private/localhost.key
+    -nodes -x509 -days 365
+    -out /etc/pki/tls/certs/localhost.crt
+  args:
+    creates: /etc/pki/tls/certs/localhost.crt
+    #creates: /etc/pki/tls/private/localhost.key
+
+
+#- name: Generate SSL certificate
+#  shell:
+#    echo -e "--\nSomeState\nSomeCity\nSomeOrganization\nSomeOrganizationalUnit\nlocalhost.localdomain\nroot@localhost.localdomain"
+#    | make -C /etc/pki/tls/certs testcert
+#  args:
+#    creates: /etc/pki/tls/certs/localhost.crt
+
+
+- name: Gunicorn logging configuration
+  copy:
+    src: logging.ini
+    dest: "{{ hubs_conf_dir }}/logging.ini"
+    owner: "{{ main_user }}"
+    group: "{{ main_user }}"
+  notify:
+    - restart hubs webapp
+
+
+- name: Nginx configuration
+  template:
+    src: nginx.conf
+    dest: /etc/nginx/conf.d/hubs.conf
+  notify:
+    - restart nginx
+
+
+- name: Nginx SSL configuration
+  template:
+    src: "{{ item }}"
+    dest: /etc/nginx/ssl_params
+  with_first_found:
+    - nginx_ssl_params.{{ ansible_hostname }}
+    - nginx_ssl_params
+  notify:
+    - restart nginx
+
+- name: Allow network connection for Nginx
+  seboolean:
+    name: httpd_can_network_connect
+    state: yes
+    persistent: yes
+
+
+- name: Install the service files
+  template:
+    src: "{{ item }}.service"
+    dest: /etc/systemd/system/{{ item }}.service
+  with_items:
+    - hubs-webapp
+
+
+- name: Start and enable the services
+  service: name={{ item }} state=started enabled=yes
+  with_items:
+    - hubs-webapp
+    - nginx
diff --git a/ansible/roles/hubs/templates/hubs_config b/ansible/roles/hubs/templates/hubs_config
index d079537..fbaf61d 100644
--- a/ansible/roles/hubs/templates/hubs_config
+++ b/ansible/roles/hubs/templates/hubs_config
@@ -8,3 +8,4 @@ OIDC_ID_TOKEN_COOKIE_SECURE = False
 {% endif %}
 
 OIDC_CLIENT_SECRETS = "{{ hubs_conf_dir }}/client_secrets.json"
+OIDC_OPENID_REALM = "{{ hubs_url }}/oidc_callback"
diff --git a/ansible/roles/hubs/templates/nginx.conf b/ansible/roles/hubs/templates/nginx.conf
new file mode 100644
index 0000000..b969aaa
--- /dev/null
+++ b/ansible/roles/hubs/templates/nginx.conf
@@ -0,0 +1,56 @@
+upstream hubs {
+    # fail_timeout=0 means we always retry an upstream even if it failed
+    # to return a good HTTP response
+
+    # for UNIX domain socket setups
+    #server unix:/tmp/gunicorn.sock fail_timeout=0;
+
+    # for a TCP configuration
+    server 127.0.0.1:8000 fail_timeout=0;
+}
+
+# Redirect cleartext traffic to HTTPS
+server {
+    listen 80;
+    listen [::]:80;
+    server_name {{ hubs_url_hostname }};
+    return 301 https://$server_name$request_uri;
+}
+
+# Main server block
+server {
+    listen 443 deferred;
+    listen [::]:443 deferred;
+    client_max_body_size 4G;
+
+    server_name {{ hubs_url_hostname }};
+
+    include ssl_params;
+    keepalive_timeout 5;
+
+    # path for static files
+    root {{ hubs_code_dir }}/hubs/static;
+
+    location / {
+      # checks for static file, if not found proxy to app
+      try_files $uri @proxy_to_app;
+    }
+
+    location @proxy_to_app {
+      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+      # enable this if and only if you use HTTPS
+      proxy_set_header X-Forwarded-Proto https;
+      proxy_set_header Host $http_host;
+      # we don't want nginx trying to do something clever with
+      # redirects, we set the Host: header above already.
+      proxy_redirect off;
+      # Allow long-running queries (SSE):
+      proxy_buffering off;
+      proxy_pass http://hubs;
+    }
+
+    #error_page 500 502 503 504 /500.html;
+    #location = /500.html {
+    #  root /path/to/app/current/public;
+    #}
+  }
diff --git a/ansible/roles/hubs/templates/nginx_ssl_params b/ansible/roles/hubs/templates/nginx_ssl_params
new file mode 100644
index 0000000..c6bc906
--- /dev/null
+++ b/ansible/roles/hubs/templates/nginx_ssl_params
@@ -0,0 +1,9 @@
+ssl                  on;
+ssl_certificate      /etc/pki/tls/certs/localhost.crt;
+ssl_certificate_key  /etc/pki/tls/private/localhost.key;
+
+ssl_session_timeout  5m;
+
+ssl_protocols  SSLv2 SSLv3 TLSv1;
+ssl_ciphers  HIGH:!aNULL:!MD5;
+ssl_prefer_server_ciphers   on;
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
index 342ff0d..6ad295f 100644
--- a/ansible/vagrant-playbook.yml
+++ b/ansible/vagrant-playbook.yml
@@ -15,7 +15,7 @@
     - role: hubs
       hubs_secret_key: vagrantmachinesecretkey
       hubs_db_type: sqlite
-      hubs_url: http://localhost:5000
+      hubs_dev_mode: true
 
   tasks:
     - name: Install the message of the day

From af637b03c13a7d171242125ad03f13b943008da9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 10:50:26 +0000
Subject: [PATCH 861/1001] Restart services on config change


---

diff --git a/ansible/roles/hubs/handlers/main.yml b/ansible/roles/hubs/handlers/main.yml
index 62e0484..30ce20d 100644
--- a/ansible/roles/hubs/handlers/main.yml
+++ b/ansible/roles/hubs/handlers/main.yml
@@ -3,6 +3,15 @@
 
 - name: restart fedmsg-hub
   service: name=fedmsg-hub state=restarted
+  listen: "hubs configuration change"
+
+- name: restart hubs triage
+  service: name=hubs-triage@* state=restarted
+  listen: "hubs configuration change"
+
+- name: restart hubs workers
+  service: name=hubs-worker@* state=restarted
+  listen: "hubs configuration change"
 
 # Webserver
 - include: webserver.yml

From 2de9f4bfb0de8b798a2a180a49e856e19dd1203e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 10:50:26 +0000
Subject: [PATCH 862/1001] The fedmsg consumer can't get the defaults


...because it does not use the Flask function to get the configuration.
So add them to the local config file.

---

diff --git a/ansible/roles/hubs/templates/fedmsg_config b/ansible/roles/hubs/templates/fedmsg_config
index fc15ac4..96a7ce8 100644
--- a/ansible/roles/hubs/templates/fedmsg_config
+++ b/ansible/roles/hubs/templates/fedmsg_config
@@ -15,5 +15,9 @@ config = {
             "filename": "{{ hubs_var_dir }}/cache.db",
         },
     },
+
+    # Fedmsg hub consumer
+    'hubs.consumer.enabled': True,
+    'hubs.redis.triage-queue-name': 'fedora-hubs-triage-queue',
 }
 

From 91f48087f3bc4f026c784ba2f21338beea15caca Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 11:06:58 +0000
Subject: [PATCH 863/1001] fixup! Put the code, the config and the data in the FHS


---

diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index 43406e7..9b2c241 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -74,7 +74,7 @@
   with_items:
     - {path: "{{ hubs_base_dir }}", mode: 755}
     - {path: "{{ hubs_conf_dir }}", mode: 750}
-    - {path: "{{ hubs_var_dir }}", mode: 755}
+    - {path: "{{ hubs_var_dir }}", mode: 750}
 
 
 # Set up the Python development environment
@@ -105,7 +105,7 @@
   become_user: "{{ main_user }}"
   pip:
     name: "{{ hubs_code_dir }}"
-    editable: true
+    extra_args: -e
     virtualenv: "{{ hubs_venv_dir}}"
     virtualenv_site_packages: yes
 
@@ -141,15 +141,6 @@
     - fedmsg_config
   notify: "hubs configuration change"
 
-- name: Create a directory for variable files
-  file:
-    path: "/var/lib/hubs"
-    state: directory
-    owner: "{{ main_user }}"
-    group: "{{ main_user }}"
-    mode: 755
-    setype: httpd_sys_content_rw_t
-
 - name: Configure application to authenticate with iddev.fedorainfracloud.org
   command:
     oidc-register

From 8b24f244d2b6be9a4cb0f9a978c7826f37669c65 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 12:33:41 +0000
Subject: [PATCH 864/1001] Minor improvements to the playbooks


---

diff --git a/ansible/roles/hubs/handlers/main.yml b/ansible/roles/hubs/handlers/main.yml
index 30ce20d..cd2d639 100644
--- a/ansible/roles/hubs/handlers/main.yml
+++ b/ansible/roles/hubs/handlers/main.yml
@@ -1,8 +1,8 @@
 - name: restart postgresql
   service: name=postgresql state=restarted
 
-- name: restart fedmsg-hub
-  service: name=fedmsg-hub state=restarted
+- name: restart the hubs-specific fedmsg-hub
+  service: name=hubs-fedmsg-hub state=restarted
   listen: "hubs configuration change"
 
 - name: restart hubs triage
diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index 9b2c241..02f14fc 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -103,11 +103,9 @@
 
 - name: Install Fedora Hubs into the virtualenv
   become_user: "{{ main_user }}"
-  pip:
-    name: "{{ hubs_code_dir }}"
-    extra_args: -e
-    virtualenv: "{{ hubs_venv_dir}}"
-    virtualenv_site_packages: yes
+  command: "{{ hubs_venv_dir }}/bin/pip install -e {{ hubs_code_dir }}"
+  args:
+    creates: "{{ hubs_venv_dir }}/lib/python2.7/site-packages/fedora-hubs.egg-link"
 
 - name: Set bin file context in the virtualenv
   file:
@@ -116,12 +114,6 @@
     recurse: true
     setype: bin_t
 
-#- name: Update httplib2 trust store
-#  copy:
-#    src: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
-#    dest: /home/{{ main_user }}/.virtualenvs/hubs/lib/python2.7/site-packages/httplib2/cacerts.txt
-#    remote_src: True
-
 - name: Add a basic Hubs configuration file
   template:
     src: "{{ item }}"
@@ -168,6 +160,7 @@
   become_user: "{{ main_user }}"
   args:
     chdir: "{{ hubs_code_dir }}/hubs/static/client"
+    creates: "{{ hubs_code_dir }}/hubs/static/js/build/common.js"
 
 
 # Services

From 3aa165a145f9d3e61352fbc148b2b3b1c99a45ae Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:21:58 +0000
Subject: [PATCH 865/1001] Remove useless SSL params in Nginx


Use the default protocols (don't add SSLv2) and remove commented out
lines in the playbook.

---

diff --git a/ansible/roles/hubs/tasks/webserver.yml b/ansible/roles/hubs/tasks/webserver.yml
index f070549..234089f 100644
--- a/ansible/roles/hubs/tasks/webserver.yml
+++ b/ansible/roles/hubs/tasks/webserver.yml
@@ -17,15 +17,6 @@
     -out /etc/pki/tls/certs/localhost.crt
   args:
     creates: /etc/pki/tls/certs/localhost.crt
-    #creates: /etc/pki/tls/private/localhost.key
-
-
-#- name: Generate SSL certificate
-#  shell:
-#    echo -e "--\nSomeState\nSomeCity\nSomeOrganization\nSomeOrganizationalUnit\nlocalhost.localdomain\nroot@localhost.localdomain"
-#    | make -C /etc/pki/tls/certs testcert
-#  args:
-#    creates: /etc/pki/tls/certs/localhost.crt
 
 
 - name: Gunicorn logging configuration
diff --git a/ansible/roles/hubs/templates/nginx_ssl_params b/ansible/roles/hubs/templates/nginx_ssl_params
index c6bc906..d97125f 100644
--- a/ansible/roles/hubs/templates/nginx_ssl_params
+++ b/ansible/roles/hubs/templates/nginx_ssl_params
@@ -1,9 +1,3 @@
 ssl                  on;
 ssl_certificate      /etc/pki/tls/certs/localhost.crt;
 ssl_certificate_key  /etc/pki/tls/private/localhost.key;
-
-ssl_session_timeout  5m;
-
-ssl_protocols  SSLv2 SSLv3 TLSv1;
-ssl_ciphers  HIGH:!aNULL:!MD5;
-ssl_prefer_server_ciphers   on;

From 5fd3a04790ecc6ea9b8a5c9d0a3bc9765fb83195 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:40:40 +0000
Subject: [PATCH 866/1001] Make the Feed component more reusable


---

diff --git a/hubs/static/client/app/__tests__/Feed.test.js b/hubs/static/client/app/__tests__/Feed.test.js
deleted file mode 100644
index 76daf32..0000000
--- a/hubs/static/client/app/__tests__/Feed.test.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/* eslint-env jasmine, jest */
-
-jest.unmock('../widgets/feed/Feed.jsx');
-
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-
-import Feed from '../widgets/feed/Feed.jsx';
-
-describe('Feed', () => {
-  const matches = [{
-    markup: '<a href="https://pagure.io/fedora-hubs">Link</a>',
-    date_time: new Date(),
-    link: 'https://pagure.io/fedora-hubs',
-    secondary_icon: 'https://placekitten.com/g/200/300',
-  }];
-
-  const options = {
-    messageLimit: 100
-  };
-
-  it('should set the correct state', () => {
-    const component = TestUtils.renderIntoDocument(
-      <Feed matches={matches} options={options} />
-    );
-
-    const state = {
-      matches,
-      messageLimit: 100,
-      sse: true,
-    };
-    expect(component.state).toEqual(state);
-  });
-});
diff --git a/hubs/static/client/app/__tests__/Icon.test.js b/hubs/static/client/app/__tests__/Icon.test.js
deleted file mode 100644
index 920c853..0000000
--- a/hubs/static/client/app/__tests__/Icon.test.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* eslint-env jasmine, jest */
-
-jest.unmock('../components/Icon.jsx');
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
-
-import Icon from '../components/Icon.jsx';
-
-describe('Icon', () => {
-  const match = {
-    link: 'https://pagure.io/fedora-hubs',
-    secondary_icon: 'https://placekitten.com/g/200/300',
-  };
-
-  it('has the correct link', () => {
-    const component = TestUtils.renderIntoDocument(
-      <Icon match={match} />
-    );
-    expect(component).toBeTruthy();
-    const node = ReactDOM.findDOMNode(component);
-    const link = node.querySelector('a');
-    expect(link.getAttribute('href')).toEqual(match.link);
-  });
-  it('has the correct image source', () => {
-    const component = TestUtils.renderIntoDocument(
-      <Icon match={match} />
-    );
-    expect(component).toBeTruthy();
-
-    const node = ReactDOM.findDOMNode(component);
-    const image = node.querySelector('img');
-    expect(image.getAttribute('src')).toEqual(match.secondary_icon);
-  });
-});
diff --git a/hubs/static/client/app/__tests__/Markup.test.js b/hubs/static/client/app/__tests__/Markup.test.js
deleted file mode 100644
index d2aea84..0000000
--- a/hubs/static/client/app/__tests__/Markup.test.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/* eslint-env jasmine, jest */
-
-jest.unmock('../components/Markup.jsx');
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
-
-import Markup from '../components/Markup.jsx';
-
-describe('Markup', () => {
-  const match = {
-    markup: '<a href="https://pagure.io/fedora-hubs">Link</a>',
-    date_time: new Date(),
-  };
-
-  it('should set the inner html of the markup', () => {
-    const component = TestUtils.renderIntoDocument(
-      <Markup match={match} />
-    );
-    expect(component).toBeTruthy();
-
-    const node = ReactDOM.findDOMNode(component);
-    const header = node.querySelector('h4');
-
-    expect(header.innerHTML).toEqual(match.markup);
-  });
-
-  // we don't test TimeAgo, the library should have its own tests
-});
diff --git a/hubs/static/client/app/__tests__/Panel.test.js b/hubs/static/client/app/__tests__/Panel.test.js
deleted file mode 100644
index c8632c5..0000000
--- a/hubs/static/client/app/__tests__/Panel.test.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/* eslint-env jasmine, jest */
-
-jest.unmock('../components/Panel.jsx');
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
-
-import Panel from '../components/Panel.jsx';
-
-describe('Panel', () => {
-  const match = {
-    markup: '<a href="https://pagure.io/fedora-hubs">Link</a>',
-    date_time: new Date(),
-    link: 'https://pagure.io/fedora-hubs',
-    secondary_icon: 'https://placekitten.com/g/200/300',
-  };
-
-  it('should render the card block', () => {
-    const component = TestUtils.renderIntoDocument(
-      <Panel match={match} />
-    );
-    expect(component).toBeTruthy();
-
-    const node = ReactDOM.findDOMNode(component);
-    const block = node.querySelector('.card-block');
-
-    expect(block).toBeTruthy();
-  });
-});
diff --git a/hubs/static/client/app/components/Dropdown.jsx b/hubs/static/client/app/components/Dropdown.jsx
deleted file mode 100644
index efa6201..0000000
--- a/hubs/static/client/app/components/Dropdown.jsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import React from 'react';
-
-export default class Dropdown extends React.Component {
-  save() {
-    const payload = {
-      link: this.props.match.link,
-      markup: this.props.match.markup,
-      secondary_icon: this.props.match.secondary_icon,
-      dom_id: this.props.match.dom_id,
-    };
-
-    $.ajax({
-      type: 'POST',
-      url: this.props.options.saveUrl,
-      data: JSON.stringify(payload),
-      contentType: 'application/json',
-    }).done(() => {
-      const id = `#save-${this.props.match.dom_id}`;
-      const $saveBtn = $(id);
-      $saveBtn.removeClass('btn-primary').addClass('btn-success');
-      $saveBtn.text('Saved');
-    });
-  }
-
-  delete() {
-    $.ajax({
-      type: 'DELETE',
-      url: `${this.props.options.saveUrl}${this.props.match.idx}/`,
-    }).done((resp) => {
-      if (resp.status_code === 200) {
-        const $notification = $(`#${this.props.match.dom_id}`);
-        $notification.closest('.card-block').remove();
-      }
-    });
-  }
-
-  render() {
-    let saveBtn;
-    if (!this.props.match.saved && this.props.options.saveUrl) {
-      saveBtn = (
-        <button
-          id={`save-${this.props.match.dom_id}`}
-          className="btn btn-sm btn-primary"
-          onClick={this.save.bind(this)}
-          href="#"
-        >
-          Save
-        </button>
-      );
-    }
-    let deleteBtn;
-    if (this.props.options.delete && this.props.options.saveUrl) {
-      deleteBtn = (
-        <button
-          id={`delete-${this.props.match.dom_id}`}
-          className="btn btn-sm btn-danger"
-          onClick={this.delete.bind(this)}
-        >
-          Remove
-        </button>
-      );
-    }
-
-    return (
-      <div className="float-right">
-       {saveBtn}
-        {deleteBtn}
-      </div>
-    );
-  }
-}
diff --git a/hubs/static/client/app/components/Icon.jsx b/hubs/static/client/app/components/Icon.jsx
deleted file mode 100644
index 0eec3cc..0000000
--- a/hubs/static/client/app/components/Icon.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-
-class Icon extends React.Component {
-  render() {
-    return (
-      <div>
-        <div className="media-left">
-          <a href={this.props.match.link ? this.props.match.link : '#'} target="_blank">
-            <img
-              alt="User avatar"
-              className="media-object square-32 img-circle"
-              src={this.props.match.secondary_icon}
-            />
-          </a>
-        </div>
-      </div>
-    );
-  }
-}
-
-export default Icon;
diff --git a/hubs/static/client/app/components/Markup.jsx b/hubs/static/client/app/components/Markup.jsx
deleted file mode 100644
index 92c2c50..0000000
--- a/hubs/static/client/app/components/Markup.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-import Dropdown from './Dropdown.jsx';
-import TimeAgo from 'react-timeago';
-
-
-export default class Markup extends React.Component {
-  createMarkup() {
-    return { __html: this.props.match.markup };
-  }
-  render() {
-    const timestamp = this.props.match.date_time ? (<TimeAgo date={this.props.match.date_time} />) : null;
-
-    return (
-      <div className="media-body">
-        <h4
-          className="media-heading"
-          dangerouslySetInnerHTML={this.createMarkup()}
-        >
-        </h4>
-        {timestamp}
-        <Dropdown
-          match={this.props.match}
-          options={this.props.options}
-        />
-      </div>
-    );
-  }
-}
diff --git a/hubs/static/client/app/components/Panel.jsx b/hubs/static/client/app/components/Panel.jsx
deleted file mode 100644
index 848a5b7..0000000
--- a/hubs/static/client/app/components/Panel.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-
-import Icon from './Icon.jsx';
-import Markup from './Markup.jsx';
-
-class Panel extends React.Component {
-  render() {
-    return (
-      <div className="card">
-        <div className="card-block" id={this.props.match.id}>
-          <Icon match={this.props.match} />
-          <Markup options={this.props.options} match={this.props.match} />
-        </div>
-      </div>
-    );
-  }
-}
-
-export default Panel;
diff --git a/hubs/static/client/app/components/feed/Actions.jsx b/hubs/static/client/app/components/feed/Actions.jsx
new file mode 100644
index 0000000..c481377
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Actions.jsx
@@ -0,0 +1,78 @@
+import React from 'react';
+
+
+export default class Actions extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.save = this.save.bind(this);
+    this.delete = this.delete.bind(this);
+  }
+
+  save() {
+    const payload = {
+      link: this.props.item.link,
+      markup: this.props.item.markup,
+      secondary_icon: this.props.item.secondary_icon,
+      dom_id: this.props.item.dom_id,
+    };
+
+    $.ajax({
+      type: 'POST',
+      url: this.props.options.saveUrl,
+      data: JSON.stringify(payload),
+      contentType: 'application/json',
+    }).done(() => {
+      const id = `#save-${this.props.item.dom_id}`;
+      const $saveBtn = $(id);
+      $saveBtn.removeClass('btn-primary').addClass('btn-success');
+      $saveBtn.text('Saved');
+    });
+  }
+
+  delete() {
+    $.ajax({
+      type: 'DELETE',
+      url: `${this.props.options.saveUrl}${this.props.item.idx}/`,
+    }).done((resp) => {
+      if (resp.status_code === 200) {
+        const $notification = $(`#${this.props.item.dom_id}`);
+        $notification.closest('.card-block').remove();
+      }
+    });
+  }
+
+  render() {
+    var buttonProps = {
+      id: `save-${this.props.item.dom_id}`,
+      className: "btn btn-sm ",
+    };
+    var buttonText;
+
+    if (this.props.item.saved) {
+      if (this.props.options.delete) {
+        buttonProps.className += "btn-danger";
+        buttonProps.onClick = this.delete;
+        buttonText = "Remove";
+      } else {
+        buttonText = "Saved";
+      }
+    } else {
+      buttonProps.className += "btn-primary";
+      buttonProps.onClick = this.save;
+      buttonText = "Save";
+    }
+
+    return (
+      <div className="float-right">
+        <button {...buttonProps}>
+          {buttonText}
+        </button>
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/Feed.jsx b/hubs/static/client/app/components/feed/Feed.jsx
new file mode 100644
index 0000000..464e2e1
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Feed.jsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import Panel from './Panel.jsx';
+
+
+export default class Feed extends React.Component {
+
+  render() {
+    var items = this.props.items || [];
+    items = items.map((item, idx) => {
+      return (
+        <Panel item={item} {...this.props} key={idx} />
+        );
+    });
+    return (
+      <div>
+        {items}
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/Icon.jsx b/hubs/static/client/app/components/feed/Icon.jsx
new file mode 100644
index 0000000..a81f41c
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Icon.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+
+class Icon extends React.Component {
+  render() {
+    return (
+      <div>
+        <div className="media-left">
+          <a href={this.props.item.link ? this.props.item.link : '#'} target="_blank">
+            <img
+              alt="User avatar"
+              className="media-object square-32 img-circle"
+              src={this.props.item.secondary_icon}
+            />
+          </a>
+        </div>
+      </div>
+    );
+  }
+}
+
+export default Icon;
diff --git a/hubs/static/client/app/components/feed/Markup.jsx b/hubs/static/client/app/components/feed/Markup.jsx
new file mode 100644
index 0000000..daf2d84
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Markup.jsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import Actions from './Actions.jsx';
+import TimeAgo from 'react-timeago';
+
+
+export default class Markup extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.createMarkup = this.createMarkup.bind(this);
+  }
+
+  createMarkup() {
+    return { __html: this.props.item.markup };
+  }
+
+  render() {
+    const timestamp = this.props.item.date_time ? (<TimeAgo date={this.props.item.date_time} />) : null;
+
+    return (
+      <div className="media-body">
+        <h4
+          className="media-heading"
+          dangerouslySetInnerHTML={this.createMarkup()}
+        >
+        </h4>
+        {timestamp}
+        <Actions {...this.props} />
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/Panel.jsx b/hubs/static/client/app/components/feed/Panel.jsx
new file mode 100644
index 0000000..eb0128b
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Panel.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import Icon from './Icon.jsx';
+import Markup from './Markup.jsx';
+
+
+export default class Panel extends React.Component {
+
+  render() {
+    return (
+      <div className="card">
+        <div className="card-block" id={this.props.item.id}>
+          <Icon item={this.props.item} />
+          <Markup {...this.props} />
+        </div>
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/__tests__/Feed.test.js b/hubs/static/client/app/components/feed/__tests__/Feed.test.js
new file mode 100644
index 0000000..a3e8365
--- /dev/null
+++ b/hubs/static/client/app/components/feed/__tests__/Feed.test.js
@@ -0,0 +1,30 @@
+/* eslint-env jasmine, jest */
+
+jest.unmock('../Feed.jsx');
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import TestUtils from 'react-addons-test-utils';
+
+import Feed from '../Feed.jsx';
+
+describe('Feed', () => {
+  const item = {
+    markup: '<a href="https://pagure.io/fedora-hubs">Link</a>',
+    date_time: new Date(),
+    link: 'https://pagure.io/fedora-hubs',
+    secondary_icon: 'https://placekitten.com/g/200/300',
+  }
+  const items = [item, item, item];
+
+  it('should create the children', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Feed items={items} messageLimit={100} />
+    );
+    const node = ReactDOM.findDOMNode(component);
+    expect(node.children.length).toEqual(3);
+  });
+});
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/__tests__/Icon.test.js b/hubs/static/client/app/components/feed/__tests__/Icon.test.js
new file mode 100644
index 0000000..72dadc5
--- /dev/null
+++ b/hubs/static/client/app/components/feed/__tests__/Icon.test.js
@@ -0,0 +1,39 @@
+/* eslint-env jasmine, jest */
+
+jest.unmock('../Icon.jsx');
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import TestUtils from 'react-addons-test-utils';
+
+import Icon from '../Icon.jsx';
+
+describe('Icon', () => {
+  const item = {
+    link: 'https://pagure.io/fedora-hubs',
+    secondary_icon: 'https://placekitten.com/g/200/300',
+  };
+
+  it('has the correct link', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Icon item={item} />
+    );
+    expect(component).toBeTruthy();
+    const node = ReactDOM.findDOMNode(component);
+    const link = node.querySelector('a');
+    expect(link.getAttribute('href')).toEqual(item.link);
+  });
+  it('has the correct image source', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Icon item={item} />
+    );
+    expect(component).toBeTruthy();
+
+    const node = ReactDOM.findDOMNode(component);
+    const image = node.querySelector('img');
+    expect(image.getAttribute('src')).toEqual(item.secondary_icon);
+  });
+});
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/__tests__/Markup.test.js b/hubs/static/client/app/components/feed/__tests__/Markup.test.js
new file mode 100644
index 0000000..31d336d
--- /dev/null
+++ b/hubs/static/client/app/components/feed/__tests__/Markup.test.js
@@ -0,0 +1,33 @@
+/* eslint-env jasmine, jest */
+
+jest.unmock('../Markup.jsx');
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import TestUtils from 'react-addons-test-utils';
+
+import Markup from '../Markup.jsx';
+
+describe('Markup', () => {
+  const item = {
+    markup: '<a href="https://pagure.io/fedora-hubs">Link</a>',
+    date_time: new Date(),
+  };
+
+  it('should set the inner html of the markup', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Markup item={item} />
+    );
+    expect(component).toBeTruthy();
+
+    const node = ReactDOM.findDOMNode(component);
+    const header = node.querySelector('h4');
+
+    expect(header.innerHTML).toEqual(item.markup);
+  });
+
+  // we don't test TimeAgo, the library should have its own tests
+});
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/__tests__/Panel.test.js b/hubs/static/client/app/components/feed/__tests__/Panel.test.js
new file mode 100644
index 0000000..6e17d1c
--- /dev/null
+++ b/hubs/static/client/app/components/feed/__tests__/Panel.test.js
@@ -0,0 +1,33 @@
+/* eslint-env jasmine, jest */
+
+jest.unmock('../Panel.jsx');
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import TestUtils from 'react-addons-test-utils';
+
+import Panel from '../Panel.jsx';
+
+describe('Panel', () => {
+  const item = {
+    markup: '<a href="https://pagure.io/fedora-hubs">Link</a>',
+    date_time: new Date(),
+    link: 'https://pagure.io/fedora-hubs',
+    secondary_icon: 'https://placekitten.com/g/200/300',
+  };
+
+  it('should render the card block', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Panel item={item} />
+    );
+    expect(component).toBeTruthy();
+
+    const node = ReactDOM.findDOMNode(component);
+    const block = node.querySelector('.card-block');
+
+    expect(block).toBeTruthy();
+  });
+});
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/feed/Feed.js b/hubs/static/client/app/widgets/feed/Feed.js
new file mode 100644
index 0000000..af0b1c6
--- /dev/null
+++ b/hubs/static/client/app/widgets/feed/Feed.js
@@ -0,0 +1,7 @@
+import Widget from './Widget.jsx';
+
+
+// Don't use the ES6 "export default" construct:
+// http://stackoverflow.com/questions/40294870/module-exports-vs-export-default-in-node-js-and-es6
+
+module.exports = {Widget};
diff --git a/hubs/static/client/app/widgets/feed/Feed.jsx b/hubs/static/client/app/widgets/feed/Feed.jsx
deleted file mode 100644
index beec5f7..0000000
--- a/hubs/static/client/app/widgets/feed/Feed.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import Panel from '../../components/Panel.jsx';
-
-
-class Feed extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      matches: this.props.matches,
-      messageLimit: this.props.options.messageLimit,
-      sse: true,
-    };
-    // If it wasn't instantiated with a url or an error happened, bail
-    if (!this.props.url || !this.state.sse) {
-      return;
-    }
-    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : null;
-    if (!this.source) {
-      return;
-    }
-    this.source.addEventListener('error', () => {
-      this.state.sse = false;
-    }, false);
-    window.onbeforeunload = () => {
-      this.source.close();
-    };
-    this.source.onmessage = resp => {
-      const data = JSON.parse(resp.data);
-      if (this.state.matches.length >= this.state.messageLimit) {
-        this.state.matches.pop();
-      }
-      this.state.matches.unshift(data);
-      this.setState({ matches: this.state.matches });
-    };
-  }
-
-  render() {
-    const feedNodes = this.state.matches.map((match, idx) => {
-      return <Panel match={match} options={this.props.options || {}} key={idx} />;
-    });
-    return (
-      <div>
-        {feedNodes}
-      </div>
-    );
-  }
-
-}
-
-// Don't use the ES6 "export default" construct:
-// http://stackoverflow.com/questions/40294870/module-exports-vs-export-default-in-node-js-and-es6
-module.exports = Feed
diff --git a/hubs/static/client/app/widgets/feed/Widget.jsx b/hubs/static/client/app/widgets/feed/Widget.jsx
new file mode 100644
index 0000000..5ee232f
--- /dev/null
+++ b/hubs/static/client/app/widgets/feed/Widget.jsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import Feed from '../../components/feed/Feed.jsx';
+
+
+export default class Widget extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      items: this.props.items,
+      sse: true,
+    };
+    this.componentDidMount = this.componentDidMount.bind(this);
+    this.componentWillUnmount = this.componentWillUnmount.bind(this);
+    this.handleMessage = this.handleMessage.bind(this);
+    this.source = null;
+  }
+
+  componentDidMount() {
+    // If it wasn't instantiated with a url or an error happened, bail
+    if (!this.props.url || !this.state.sse) {
+      return;
+    }
+    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : null;
+    if (!this.source) {
+      return;
+    }
+    this.source.addEventListener('error', () => {
+      this.state.sse = false;
+    }, false);
+    this.source.onmessage = resp => {
+      this.handleMessage(JSON.parse(resp.data));
+    };
+  }
+
+  componentWillUnmount() {
+    if (this.source) { this.source.close(); }
+  }
+
+  handleMessage(msg) {
+    if (this.state.items.length >= this.props.options.messageLimit) {
+      this.state.items.pop();
+    }
+    this.state.items.unshift(msg);
+    this.setState({items: this.state.items});
+  }
+
+  render() {
+    return (
+        <Feed items={this.state.items} {...this.props} />
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
index f197a0e..532e978 100644
--- a/hubs/static/client/webpack.config.js
+++ b/hubs/static/client/webpack.config.js
@@ -9,7 +9,7 @@ const PATHS = {
 const config = {
     entry: {
         Hubs: path.join(PATHS.app, 'core', 'Hubs.js'),
-        Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.jsx'),
+        Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.js'),
         Halp: path.join(PATHS.app, 'widgets', 'halp', 'Halp.js')
     },
     output: {
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 7cfda81..b70b23d 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -67,8 +67,8 @@
   src="{{url_for('static', filename='js/build/Feed.js')}}"></script>
 <script>
   function setup_feeds(actions, saved, saveUrl) {
-    var streamFeed = React.createElement(Feed, {
-      matches: actions,
+    var streamFeed = React.createElement(Feed.Widget, {
+      items: actions,
       options: {
         saveUrl: saveUrl,
         messageLimit: 100
@@ -80,8 +80,8 @@
     ReactDOM.render(streamFeed, document.getElementById('streamFeed'));
     ReactDOM.render(streamFeed, document.getElementById('actionsFeed'));
   
-    var savedFeed = React.createElement(Feed, {
-      matches: saved,
+    var savedFeed = React.createElement(Feed.Widget, {
+      items: saved,
       url: false,
       options: {
         messageLimit: 100,
@@ -94,8 +94,8 @@
       $.get(saveUrl).done(function(resp) {
         if (resp.length != saved.length) {
           ReactDOM.unmountComponentAtNode(document.getElementById('savedFeed'));
-          var savedFeed = React.createElement(Feed, {
-            matches: resp,
+          var savedFeed = React.createElement(Feed.Widget, {
+            items: resp,
             url: false,
             options: {
               messageLimit: 100,
diff --git a/hubs/widgets/feed/templates/feed.html b/hubs/widgets/feed/templates/feed.html
index 151ed47..81cf13d 100644
--- a/hubs/widgets/feed/templates/feed.html
+++ b/hubs/widgets/feed/templates/feed.html
@@ -5,11 +5,11 @@
 </div>
 
 <script type="text/javascript"
-  src ="{{url_for('static', filename='js/build/Feed.js')}}"></script>
+  src ="{{ url_for('static', filename='js/build/Feed.js') }}"></script>
 <script>
 (function() {
-    const FeedElement = React.createElement(Feed, {
-        matches: {{ matches }},
+    const FeedElement = React.createElement(Feed.Widget, {
+        items: {{ matches }},
         url: '{{ feed_url }}',
         options: {
             messageLimit: {{ message_limit }}

From eaa186326e914c0297b4ea38a8a371d2590200ec Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:40:40 +0000
Subject: [PATCH 867/1001] Add a component to load the existing feed data dynamically


---

diff --git a/hubs/static/client/app/components/feed/Actions.jsx b/hubs/static/client/app/components/feed/Actions.jsx
index c481377..69890f1 100644
--- a/hubs/static/client/app/components/feed/Actions.jsx
+++ b/hubs/static/client/app/components/feed/Actions.jsx
@@ -3,45 +3,6 @@ import React from 'react';
 
 export default class Actions extends React.Component {
 
-  constructor(props) {
-    super(props);
-    this.save = this.save.bind(this);
-    this.delete = this.delete.bind(this);
-  }
-
-  save() {
-    const payload = {
-      link: this.props.item.link,
-      markup: this.props.item.markup,
-      secondary_icon: this.props.item.secondary_icon,
-      dom_id: this.props.item.dom_id,
-    };
-
-    $.ajax({
-      type: 'POST',
-      url: this.props.options.saveUrl,
-      data: JSON.stringify(payload),
-      contentType: 'application/json',
-    }).done(() => {
-      const id = `#save-${this.props.item.dom_id}`;
-      const $saveBtn = $(id);
-      $saveBtn.removeClass('btn-primary').addClass('btn-success');
-      $saveBtn.text('Saved');
-    });
-  }
-
-  delete() {
-    $.ajax({
-      type: 'DELETE',
-      url: `${this.props.options.saveUrl}${this.props.item.idx}/`,
-    }).done((resp) => {
-      if (resp.status_code === 200) {
-        const $notification = $(`#${this.props.item.dom_id}`);
-        $notification.closest('.card-block').remove();
-      }
-    });
-  }
-
   render() {
     var buttonProps = {
       id: `save-${this.props.item.dom_id}`,
@@ -50,16 +11,16 @@ export default class Actions extends React.Component {
     var buttonText;
 
     if (this.props.item.saved) {
-      if (this.props.options.delete) {
-        buttonProps.className += "btn-danger";
-        buttonProps.onClick = this.delete;
-        buttonText = "Remove";
-      } else {
-        buttonText = "Saved";
-      }
+      buttonProps.className += "btn-success";
+      buttonProps.onClick = () => {
+        this.props.handleUnsave(this.props.item);
+      };
+      buttonText = "Saved";
     } else {
       buttonProps.className += "btn-primary";
-      buttonProps.onClick = this.save;
+      buttonProps.onClick = () => {
+        this.props.handleSave(this.props.item);
+      };
       buttonText = "Save";
     }
 
diff --git a/hubs/static/client/app/components/feed/ItemsGetter.jsx b/hubs/static/client/app/components/feed/ItemsGetter.jsx
new file mode 100644
index 0000000..1ba1c4f
--- /dev/null
+++ b/hubs/static/client/app/components/feed/ItemsGetter.jsx
@@ -0,0 +1,104 @@
+import React from 'react';
+
+
+export default class ItemsGetter extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      sseError: false,
+      loading: false,
+    };
+    this.source = null;
+    this.setupSource = this.setupSource.bind(this);
+    this.handleEventError = this.handleEventError.bind(this);
+    this.loadExistingFromServer = this.loadExistingFromServer.bind(this);
+  }
+
+  componentDidMount() {
+    this.loadExistingFromServer();
+  }
+
+  componentWillUnmount() {
+    this.serverRequest.abort();
+    if (this.source !== null) {
+      this.source.removeEventListener('error', this.handleEventError);
+      this.source.close();
+    }
+  }
+
+  componentDidUpdate(prevProps, prevState) {
+    if (this.props.sseActive && !this.source) {
+      // Only setup the source after the initial loading, or new elements may
+      // be overwritten by the call to this.props.handleInitialData().
+      this.setupSource();
+    }
+  }
+
+  setupSource() {
+    if (!this.props.urls.sse) {
+      // Auto-update is disabled.
+      return;
+    }
+
+    if (!window.EventSource) {
+      this.setState({
+        sseError: ("Cannot auto-update the feed, you will have to refresh "
+                  +"the page manually to see new elements.")
+      });
+      return;
+    }
+
+    this.source = new EventSource(this.props.urls.sse);
+    this.source.addEventListener('error', this.handleEventError);
+    this.source.onmessage = (resp) => {
+      this.props.handleMessage(JSON.parse(resp.data));
+    };
+  }
+
+  handleEventError() {
+    this.setState({
+      sseError: "There was an error retrieving the new elements."
+    });
+  }
+
+  loadExistingFromServer() {
+    this.setState({loading: true});
+    this.serverRequest = $.ajax({
+      url: this.props.urls.content,
+      method: 'GET',
+      dataType: 'json',
+      cache: false,
+      success: (data, textStatus, jqXHR) => {
+        this.props.handleInitialData(data.data);
+      },
+      error: (xhr, status, err) => {
+        console.error(status, err.toString());
+      },
+      complete: (xhr, status) => {
+        this.setState({loading: false});
+      },
+    });
+  }
+
+  render() {
+    return (
+      <div>
+        {this.props.children}
+        <div
+          className="loading mx-auto"
+          style={{display: this.state.loading ? "block" : "none"}}
+          ></div>
+        { (this.state.sseError !== false) &&
+          <div className="alert alert-warning">
+            {this.state.sseError}
+          </div>
+        }
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/Markup.jsx b/hubs/static/client/app/components/feed/Markup.jsx
index daf2d84..72f88c9 100644
--- a/hubs/static/client/app/components/feed/Markup.jsx
+++ b/hubs/static/client/app/components/feed/Markup.jsx
@@ -25,7 +25,9 @@ export default class Markup extends React.Component {
         >
         </h4>
         {timestamp}
-        <Actions {...this.props} />
+        { (this.props.handleSave) &&
+          <Actions {...this.props} />
+        }
       </div>
     );
   }
diff --git a/hubs/static/client/app/widgets/feed/Widget.jsx b/hubs/static/client/app/widgets/feed/Widget.jsx
index 5ee232f..38a006d 100644
--- a/hubs/static/client/app/widgets/feed/Widget.jsx
+++ b/hubs/static/client/app/widgets/feed/Widget.jsx
@@ -1,4 +1,5 @@
 import React from 'react';
+import ItemsGetter from '../../components/feed/ItemsGetter.jsx';
 import Feed from '../../components/feed/Feed.jsx';
 
 
@@ -7,47 +8,98 @@ export default class Widget extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
-      items: this.props.items,
-      sse: true,
+      items: [],
+      sseActive: false,
     };
-    this.componentDidMount = this.componentDidMount.bind(this);
-    this.componentWillUnmount = this.componentWillUnmount.bind(this);
+    this.handleInitialData = this.handleInitialData.bind(this);
     this.handleMessage = this.handleMessage.bind(this);
-    this.source = null;
+    this.handleSave = this.handleSave.bind(this);
+    this.handleUnsave = this.handleUnsave.bind(this);
   }
 
-  componentDidMount() {
-    // If it wasn't instantiated with a url or an error happened, bail
-    if (!this.props.url || !this.state.sse) {
-      return;
-    }
-    this.source = (!!window.EventSource) ? new EventSource(this.props.url) : null;
-    if (!this.source) {
-      return;
-    }
-    this.source.addEventListener('error', () => {
-      this.state.sse = false;
-    }, false);
-    this.source.onmessage = resp => {
-      this.handleMessage(JSON.parse(resp.data));
-    };
-  }
-
-  componentWillUnmount() {
-    if (this.source) { this.source.close(); }
+  handleInitialData(data) {
+    // Only activate SSE after the initial loading, or new elements may
+    // be overwritten.
+    this.setState({
+      items: data,
+      sseActive: true,
+    });
   }
 
   handleMessage(msg) {
-    if (this.state.items.length >= this.props.options.messageLimit) {
+    if (this.state.items.length >= this.props.messageLimit) {
       this.state.items.pop();
     }
     this.state.items.unshift(msg);
     this.setState({items: this.state.items});
   }
 
+  handleSave(item) {
+    if (!this.props.urls.save) { return; }
+    const payload = {
+      link: item.link,
+      markup: item.markup,
+      secondary_icon: item.secondary_icon,
+      dom_id: item.dom_id,
+    };
+    $.ajax({
+      type: 'POST',
+      url: this.props.urls.save,
+      data: JSON.stringify(payload),
+      contentType: 'application/json',
+      success: () => {
+        this.setState((prevState, props) => {
+          var items = prevState.items.map((currentItem) => {
+            if (currentItem.dom_id === item.dom_id) {
+              currentItem.saved = true;
+            }
+            return currentItem;
+          })
+          return {items};
+        });
+      },
+    });
+  }
+
+  handleUnsave(item) {
+    if (!this.props.urls.save) { return; }
+    var updateItemState = (item) => {
+      this.setState((prevState, props) => {
+        var items = prevState.items.map((currentItem) => {
+          if (currentItem.dom_id === item.dom_id) {
+            currentItem.saved = false;
+          }
+          return currentItem;
+        });
+        return {items};
+      });
+    };
+    if (item.idx) {
+      // Already saved
+      $.ajax({
+        type: 'DELETE',
+        url: `${this.props.urls.save}${item.idx}/`,
+        success: () => { updateItemState(item) },
+      });
+    } else {
+      updateItemState(item);
+    }
+  }
+
   render() {
     return (
-        <Feed items={this.state.items} {...this.props} />
+      <ItemsGetter
+        sseActive={this.state.sseActive}
+        urls={this.props.urls}
+        handleMessage={this.handleMessage}
+        handleInitialData={this.handleInitialData}
+        >
+        <Feed
+          items={this.state.items}
+          handleSave={this.handleSave}
+          handleUnsave={this.handleUnsave}
+          />
+      </ItemsGetter>
     );
   }
 
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index ebea21b..6f7d07a 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -39,10 +39,28 @@ class BaseView(WidgetView):
         # Avoid circular import
         from hubs.app import app
         username = instance.config["username"]
-        feed_url = app.config['SSE_URL'] + username
+        sse_url = app.config['SSE_URL'] + username
         return dict(
             title=self.widget.label,
-            matches=[],
             message_limit=instance.config["message_limit"],
-            feed_url=feed_url,
+            sse_url=sse_url,
             )
+
+
+class ExistingView(WidgetView):
+
+    name = "existing"
+    url_rules = ["/existing"]
+    json = True
+
+    def get_context(self, instance, *args, **kwargs):
+        username = instance.config["username"]
+        # Mock data:
+        import hubs.stream
+        import json
+        stream = hubs.stream.Stream()
+        existing = json.loads(stream.get_json())
+        return {
+            "status": "OK",
+            "data": existing,
+        }
diff --git a/hubs/widgets/feed/templates/feed.html b/hubs/widgets/feed/templates/feed.html
index 81cf13d..6f74ccb 100644
--- a/hubs/widgets/feed/templates/feed.html
+++ b/hubs/widgets/feed/templates/feed.html
@@ -9,11 +9,11 @@
 <script>
 (function() {
     const FeedElement = React.createElement(Feed.Widget, {
-        items: {{ matches }},
-        url: '{{ feed_url }}',
-        options: {
-            messageLimit: {{ message_limit }}
-        }
+        urls: {
+            content: {{ url_for("feed_existing", hub=widget_instance.hub.name, idx=widget_instance.idx) | tojson }},
+            sse: {{ sse_url|tojson }},
+        },
+        messageLimit: {{ message_limit }}
     });
     ReactDOM.render(FeedElement, document.getElementById('feed'));
 })();

From ae9bb03b0f35c76bf71bdf0a4d181d48e81278eb Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:40:40 +0000
Subject: [PATCH 868/1001] Use the Feed component for the Streams page


---

diff --git a/hubs/static/client/app/core/Hubs.js b/hubs/static/client/app/core/Hubs.js
index 87768e9..fa53ab5 100644
--- a/hubs/static/client/app/core/Hubs.js
+++ b/hubs/static/client/app/core/Hubs.js
@@ -1,3 +1,4 @@
 import HubConfig from './HubConfig.jsx';
+import Streams from './Streams.jsx';
 
-module.exports = {HubConfig}
+module.exports = {HubConfig, Streams}
diff --git a/hubs/static/client/app/core/Streams.jsx b/hubs/static/client/app/core/Streams.jsx
new file mode 100644
index 0000000..fa257f9
--- /dev/null
+++ b/hubs/static/client/app/core/Streams.jsx
@@ -0,0 +1,189 @@
+import React from 'react';
+import {
+  IntlProvider,
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import TabSet from '../components/TabSet.jsx';
+import ItemsGetter from '../components/feed/ItemsGetter.jsx';
+import Feed from '../components/feed/Feed.jsx';
+
+
+export default class Streams extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      items: {
+        "notif": [],
+        "action": [],
+      },
+      sseActive: false,
+    };
+    this.handleInitialData = this.handleInitialData.bind(this);
+    this.handleMessage = this.handleMessage.bind(this);
+    this.handleSave = this.handleSave.bind(this);
+    this.handleUnsave = this.handleUnsave.bind(this);
+  }
+
+  handleInitialData(data) {
+    var newItems = {
+        notif: data.notif,
+        action: data.action,
+      };
+    // Only activate SSE after the initial loading, or new elements may
+    // be overwritten.
+    this.setState({
+      items: newItems,
+      sseActive: true,
+    });
+  }
+
+  handleMessage(msg) {
+    var items = this.state.items[msg.type];
+    if (items.length >= this.props.messageLimit) {
+      items.pop();
+    }
+    items.unshift(msg);
+    this.setState((prevState, props) => {
+      prevState.items[msg.type] = items;
+      return {items: prevState.items};
+    });
+  }
+
+  handleSave(item) {
+    if (!this.props.urls.save) { return; }
+    const payload = {
+      link: item.link,
+      markup: item.markup,
+      secondary_icon: item.secondary_icon,
+      dom_id: item.dom_id,
+    };
+    $.ajax({
+      type: 'POST',
+      url: this.props.urls.save,
+      data: JSON.stringify(payload),
+      contentType: 'application/json',
+      success: () => {
+        this.setState((prevState, props) => {
+          var items = prevState.items.notif.map((currentItem) => {
+            if (currentItem.dom_id === item.dom_id) {
+              currentItem.saved = true;
+            }
+            return currentItem;
+          })
+          prevState.items.notif = items;
+          return {items: prevState.items};
+        });
+      },
+    });
+  }
+
+  handleUnsave(item) {
+    if (!this.props.urls.save) { return; }
+    var updateItemState = (item) => {
+      this.setState((prevState, props) => {
+        var items = prevState.items.notif.map((currentItem) => {
+          if (currentItem.dom_id === item.dom_id) {
+            currentItem.saved = false;
+          }
+          return currentItem;
+        });
+        prevState.items.notif = items;
+        return {items: prevState.items};
+      });
+    };
+    if (item.idx) {
+      // Already saved
+      $.ajax({
+        type: 'DELETE',
+        url: `${this.props.urls.save}${item.idx}/`,
+        success: () => { updateItemState(item) },
+      });
+    } else {
+      updateItemState(item);
+    }
+  }
+
+  render() {
+    var saved = [];
+    if (this.state.items.notif) {
+      saved = this.state.items.notif.filter((item) => (item.saved));
+    }
+
+    return (
+      <IntlProvider locale={navigator.language}>
+        <ItemsGetter
+          sseActive={this.state.sseActive}
+          urls={this.props.urls}
+          handleMessage={this.handleMessage}
+          handleInitialData={this.handleInitialData}
+          >
+          <TabSet tabListClass="mb-3">
+            <FeedPanel
+              hub={this.props.hub}
+              tabTitle="My Stream"
+              >
+              <Feed
+                items={this.state.items.notif}
+                handleSave={this.handleSave}
+                handleUnsave={this.handleUnsave}
+                />
+            </FeedPanel>
+            <FeedPanel
+              hub={this.props.hub}
+              tabTitle="My Actions"
+              >
+              <Feed
+                items={this.state.items.action}
+                handleSave={this.handleSave}
+                handleUnsave={this.handleUnsave}
+                />
+            </FeedPanel>
+            <FeedPanel
+              hub={this.props.hub}
+              tabTitle="Saved Notifications"
+              >
+              <Feed
+                items={saved}
+                handleSave={this.handleSave}
+                handleUnsave={this.handleUnsave}
+                />
+            </FeedPanel>
+          </TabSet>
+        </ItemsGetter>
+      </IntlProvider>
+    );
+  }
+}
+
+
+class FeedPanel extends React.Component {
+
+  render() {
+    const filters_url = `https://apps.fedoraproject.org/notifications/${this.props.hub}.id.fedoraproject.org/`;
+
+    return (
+      <div>
+        <div className="input-group">
+          <input
+            type="search" className="form-control"
+            placeholder="Search this activity stream..."
+            aria-describedby="searchform-addon" />
+          <span className="input-group-addon">
+            <span><i className="fa fa-search" aria-hidden="true"></i></span>
+          </span>
+        </div>
+        <br/>
+        <div className="alert alert-warning" role="alert">
+          This stream is filtered. <a href={filters_url} target="_blank">View Filters</a>
+        </div>
+        {this.props.children}
+      </div>
+    );
+  }
+
+}
+
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index b70b23d..0bd9538 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -13,43 +13,7 @@
 
 <div class="row">
   <div class="col-sm-8">
-
-    <ul class="nav-tabs " role="tablist">
-      <li class="nav-item">
-        <a class="nav-link active" href="#stream" role="tab" data-toggle="tab">My Stream</a>
-      </li>
-      <li class="nav-item">
-        <a class="nav-link" href="#actions" role="tab" data-toggle="tab">My Actions</a>
-      </li>
-      <li class="nav-item">
-        <a class="nav-link" href="#mentions" role="tab" data-toggle="tab">My Mentions</a>
-      </li>
-      <li class="nav-item">
-        <a class="nav-link" href="#saved" role="tab" data-toggle="tab">Saved Notifications</a>
-      </li>
-    </ul>
-
-    <!-- Tab panes -->
-    <div class="tab-content">
-      <div role="tabpanel" class="tab-pane fade in active" id="stream">
-        {% include "includes/_searchstream.html" %}
-        <div id="streamFeed"></div>
-      </div>
-      <div role="tabpanel" class="tab-pane fade" id="actions">
-        {% include "includes/_searchstream.html" %}
-        <div id="actionsFeed"></div>
-      </div>
-      <div role="tabpanel" class="tab-pane fade" id="mentions">
-        {% include "includes/_searchstream.html" %}
-        <br/>
-        <div id="mentionsFeed">
-          {% include "includes/_messages.html" %}
-        </div>
-      </div>
-      <div role="tabpanel" class="tab-pane fade" id="saved">
-        {% include "includes/_searchstream.html" %}
-        <div id="savedFeed"></div>
-      </div>
+    <div id="streams">
     </div>
   </div>
 
@@ -63,59 +27,18 @@
 
 {% block jscripts %}
 {{ super() }}
-<script type="text/javascript"
-  src="{{url_for('static', filename='js/build/Feed.js')}}"></script>
 <script>
-  function setup_feeds(actions, saved, saveUrl) {
-    var streamFeed = React.createElement(Feed.Widget, {
-      items: actions,
-      options: {
-        saveUrl: saveUrl,
-        messageLimit: 100
-      }
-    });
-    /* Right now, stream and actions are the same.
-     * Once, Mentions is implemented, then each will be its own
-     */
-    ReactDOM.render(streamFeed, document.getElementById('streamFeed'));
-    ReactDOM.render(streamFeed, document.getElementById('actionsFeed'));
-  
-    var savedFeed = React.createElement(Feed.Widget, {
-      items: saved,
-      url: false,
-      options: {
+ $(function() {
+    setup_widgets();
+    const StreamsElement = React.createElement(Hubs.Streams, {
+        hub: {{ hub.name | tojson }},
+        urls: {
+            save: {{ url_for("notifications", user=hub.name) | tojson }},
+            content: {{ url_for("stream_existing", name=hub.name) | tojson }},
+        },
         messageLimit: 100,
-        delete: true,
-        saveUrl: saveUrl
-      }
     });
-    ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
-    $('a[href="#saved"]').on('shown.bs.tab', function(){
-      $.get(saveUrl).done(function(resp) {
-        if (resp.length != saved.length) {
-          ReactDOM.unmountComponentAtNode(document.getElementById('savedFeed'));
-          var savedFeed = React.createElement(Feed.Widget, {
-            items: resp,
-            url: false,
-            options: {
-              messageLimit: 100,
-              delete: true,
-              saveUrl: saveUrl
-            }
-          });
-          ReactDOM.render(savedFeed, document.getElementById('savedFeed'));
-        }
-      });
-    });
-  }
-
- $(function() {
-   setup_widgets();
-   setup_feeds(
-       {{ actions|safe }},
-       {{ saved|safe }},
-       {{ url_for("notifications", user=hub.name)|tojson }}
-   );
+    ReactDOM.render(StreamsElement, document.getElementById('streams'));
  });
 </script>
 {% endblock %}
diff --git a/hubs/views/user.py b/hubs/views/user.py
index 0397b69..0a15cac 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -33,15 +33,27 @@ def stream(name):
     )
 
 
-@app.route('/<user>/notifications', methods=['GET', 'POST'])
-@app.route('/<user>/notifications/', methods=['GET', 'POST'])
+@app.route('/<name>/stream/existing')
+@require_hub_access("view")
+def stream_existing(name):
+    hub = get_hub(name)
+    stream = hubs.stream.Stream()
+    existing = json.loads(stream.get_json())
+    saved = [s.dom_id for s in
+             hubs.models.SavedNotification.by_username(name)]
+    for e in existing:
+        e["saved"] = (e["dom_id"] in saved)
+    # Right now, stream and actions are the same.
+    # Once mentions is implemented, then each will be its own.
+    return flask.jsonify(dict(
+        status="OK", data=dict(notif=existing, action=existing),
+        ))
+
+
+@app.route('/<user>/notifications', methods=['POST'])
+@app.route('/<user>/notifications/', methods=['POST'])
 @login_required
 def notifications(user):
-    if flask.request.method == 'GET':
-        notifications = hubs.models.SavedNotification.by_username(user)
-        notifications = [n.__json__() for n in notifications]
-        return flask.jsonify(dict(notifications=notifications))
-
     if flask.request.method == 'POST':
         data = flask.request.get_json()
         user = hubs.models.User.by_username(user)
@@ -63,9 +75,9 @@ def notifications(user):
         )
         flask.g.db.add(notification)
         flask.g.db.commit()
-        return flask.jsonify(
-            dict(notification=notification.__json__(), success=True)
-        )
+        return flask.jsonify(dict(
+            status="OK", data=notification.__json__(),
+            ))
 
 
 @app.route('/<user>/notifications/<int:idx>', methods=['DELETE'])
@@ -78,7 +90,7 @@ def delete_notifications(user, idx):
         return flask.abort(400)
     flask.g.db.delete(notification)
     flask.g.db.commit()
-    return flask.jsonify(dict(status_code=200))
+    return flask.jsonify(dict(status="OK"))
 
 
 @app.route('/visit/<visited_hub>/', methods=['GET', 'POST'])

From 7138b0b0a6e5e30c4519772efe5ee798eb95b663 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:40:40 +0000
Subject: [PATCH 869/1001] Improve display of the Feed widget


---

diff --git a/hubs/static/client/app/components/feed/Feed.jsx b/hubs/static/client/app/components/feed/Feed.jsx
index 464e2e1..9292add 100644
--- a/hubs/static/client/app/components/feed/Feed.jsx
+++ b/hubs/static/client/app/components/feed/Feed.jsx
@@ -8,11 +8,11 @@ export default class Feed extends React.Component {
     var items = this.props.items || [];
     items = items.map((item, idx) => {
       return (
-        <Panel item={item} {...this.props} key={idx} />
+        <Panel item={item} {...this.props} key={item.dom_id} />
         );
     });
     return (
-      <div>
+      <div className="component-feed">
         {items}
       </div>
     );
diff --git a/hubs/static/client/app/components/feed/Icon.jsx b/hubs/static/client/app/components/feed/Icon.jsx
index a81f41c..3a15c77 100644
--- a/hubs/static/client/app/components/feed/Icon.jsx
+++ b/hubs/static/client/app/components/feed/Icon.jsx
@@ -1,21 +1,21 @@
 import React from 'react';
 
-class Icon extends React.Component {
+export default class Icon extends React.Component {
   render() {
     return (
-      <div>
-        <div className="media-left">
-          <a href={this.props.item.link ? this.props.item.link : '#'} target="_blank">
-            <img
-              alt="User avatar"
-              className="media-object square-32 img-circle"
-              src={this.props.item.secondary_icon}
-            />
-          </a>
-        </div>
-      </div>
+      <a href={this.props.item.link ? this.props.item.link : '#'}
+         target="_blank"
+         className="d-flex align-self-center mr-3"
+         >
+        <img
+          alt="User avatar"
+          className="square-32 img-circle"
+          src={this.props.item.secondary_icon}
+        />
+      </a>
     );
   }
 }
 
-export default Icon;
+
+// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/ItemsGetter.jsx b/hubs/static/client/app/components/feed/ItemsGetter.jsx
index 1ba1c4f..16d87de 100644
--- a/hubs/static/client/app/components/feed/ItemsGetter.jsx
+++ b/hubs/static/client/app/components/feed/ItemsGetter.jsx
@@ -90,7 +90,7 @@ export default class ItemsGetter extends React.Component {
           style={{display: this.state.loading ? "block" : "none"}}
           ></div>
         { (this.state.sseError !== false) &&
-          <div className="alert alert-warning">
+          <div className="alert alert-warning mt-3">
             {this.state.sseError}
           </div>
         }
diff --git a/hubs/static/client/app/components/feed/Markup.jsx b/hubs/static/client/app/components/feed/Markup.jsx
index 72f88c9..16658eb 100644
--- a/hubs/static/client/app/components/feed/Markup.jsx
+++ b/hubs/static/client/app/components/feed/Markup.jsx
@@ -1,5 +1,4 @@
 import React from 'react';
-import Actions from './Actions.jsx';
 import TimeAgo from 'react-timeago';
 
 
@@ -18,16 +17,9 @@ export default class Markup extends React.Component {
     const timestamp = this.props.item.date_time ? (<TimeAgo date={this.props.item.date_time} />) : null;
 
     return (
-      <div className="media-body">
-        <h4
-          className="media-heading"
-          dangerouslySetInnerHTML={this.createMarkup()}
-        >
-        </h4>
+      <div className="media-body align-self-center">
+        <span dangerouslySetInnerHTML={this.createMarkup()}></span>
         {timestamp}
-        { (this.props.handleSave) &&
-          <Actions {...this.props} />
-        }
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/feed/Panel.jsx b/hubs/static/client/app/components/feed/Panel.jsx
index eb0128b..af5f440 100644
--- a/hubs/static/client/app/components/feed/Panel.jsx
+++ b/hubs/static/client/app/components/feed/Panel.jsx
@@ -1,17 +1,19 @@
 import React from 'react';
 import Icon from './Icon.jsx';
 import Markup from './Markup.jsx';
+import Actions from './Actions.jsx';
 
 
 export default class Panel extends React.Component {
 
   render() {
     return (
-      <div className="card">
-        <div className="card-block" id={this.props.item.id}>
-          <Icon item={this.props.item} />
-          <Markup {...this.props} />
-        </div>
+      <div className="media py-3" id={this.props.item.id}>
+        <Icon item={this.props.item} />
+        <Markup {...this.props} />
+        { (this.props.handleSave) &&
+          <Actions {...this.props} />
+        }
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/feed/__tests__/Feed.test.js b/hubs/static/client/app/components/feed/__tests__/Feed.test.js
index a3e8365..d1cdf24 100644
--- a/hubs/static/client/app/components/feed/__tests__/Feed.test.js
+++ b/hubs/static/client/app/components/feed/__tests__/Feed.test.js
@@ -7,6 +7,7 @@ import ReactDOM from 'react-dom';
 import TestUtils from 'react-addons-test-utils';
 
 import Feed from '../Feed.jsx';
+import Panel from '../Panel.jsx';
 
 describe('Feed', () => {
   const item = {
@@ -15,14 +16,17 @@ describe('Feed', () => {
     link: 'https://pagure.io/fedora-hubs',
     secondary_icon: 'https://placekitten.com/g/200/300',
   }
-  const items = [item, item, item];
+  var items = [item, item, item];
+  items = items.map((obj, idx) => {
+    return Object.assign({dom_id: "item-" + idx}, obj);
+  });
 
   it('should create the children', () => {
     const component = TestUtils.renderIntoDocument(
       <Feed items={items} messageLimit={100} />
     );
     const node = ReactDOM.findDOMNode(component);
-    expect(node.children.length).toEqual(3);
+    expect(Panel.mock.calls.length).toEqual(3);
   });
 });
 
diff --git a/hubs/static/client/app/components/feed/__tests__/Icon.test.js b/hubs/static/client/app/components/feed/__tests__/Icon.test.js
index 72dadc5..3cd5bb8 100644
--- a/hubs/static/client/app/components/feed/__tests__/Icon.test.js
+++ b/hubs/static/client/app/components/feed/__tests__/Icon.test.js
@@ -20,8 +20,7 @@ describe('Icon', () => {
     );
     expect(component).toBeTruthy();
     const node = ReactDOM.findDOMNode(component);
-    const link = node.querySelector('a');
-    expect(link.getAttribute('href')).toEqual(item.link);
+    expect(node.getAttribute('href')).toEqual(item.link);
   });
   it('has the correct image source', () => {
     const component = TestUtils.renderIntoDocument(
diff --git a/hubs/static/client/app/components/feed/__tests__/Markup.test.js b/hubs/static/client/app/components/feed/__tests__/Markup.test.js
index 31d336d..6305d51 100644
--- a/hubs/static/client/app/components/feed/__tests__/Markup.test.js
+++ b/hubs/static/client/app/components/feed/__tests__/Markup.test.js
@@ -21,9 +21,9 @@ describe('Markup', () => {
     expect(component).toBeTruthy();
 
     const node = ReactDOM.findDOMNode(component);
-    const header = node.querySelector('h4');
+    const markup = node.querySelector('span');
 
-    expect(header.innerHTML).toEqual(item.markup);
+    expect(markup.innerHTML).toEqual(item.markup);
   });
 
   // we don't test TimeAgo, the library should have its own tests
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 2b722b4..60880bc 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -547,6 +547,17 @@ font-size: 32pt;
 }
 
 
+/*
+ * Widget Feed
+ */
+
+.component-feed .media {
+  border-bottom: 1px solid rgba(0, 0, 0, .125);
+}
+.component-feed .media:last-child {
+  border: 0
+}
+
 
 /** fedora bootstrap overrides **/
 
diff --git a/hubs/widgets/feed/templates/feed.html b/hubs/widgets/feed/templates/feed.html
index 6f74ccb..87fbafa 100644
--- a/hubs/widgets/feed/templates/feed.html
+++ b/hubs/widgets/feed/templates/feed.html
@@ -1,7 +1,7 @@
 {% extends "panel.html" %}
 
 {% block content %}
-<div id="feed">
+<div id="feed-{{ widget_instance.idx }}">
 </div>
 
 <script type="text/javascript"
@@ -15,7 +15,7 @@
         },
         messageLimit: {{ message_limit }}
     });
-    ReactDOM.render(FeedElement, document.getElementById('feed'));
+    ReactDOM.render(FeedElement, document.getElementById('feed-' + {{ widget_instance.idx | tojson }}));
 })();
 </script>
 {% endblock %}

From 70ff175b1db43c718065726c95dec5978a947d74 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:40:40 +0000
Subject: [PATCH 870/1001] Get the saved notifs from a different source in the feed


---

diff --git a/hubs/static/client/app/components/feed/Panel.jsx b/hubs/static/client/app/components/feed/Panel.jsx
index af5f440..80bed1c 100644
--- a/hubs/static/client/app/components/feed/Panel.jsx
+++ b/hubs/static/client/app/components/feed/Panel.jsx
@@ -11,7 +11,7 @@ export default class Panel extends React.Component {
       <div className="media py-3" id={this.props.item.id}>
         <Icon item={this.props.item} />
         <Markup {...this.props} />
-        { (this.props.handleSave) &&
+        { (this.props.handleSave || this.props.handleUnsave) &&
           <Actions {...this.props} />
         }
       </div>
diff --git a/hubs/static/client/app/core/Streams.jsx b/hubs/static/client/app/core/Streams.jsx
index fa257f9..144fab7 100644
--- a/hubs/static/client/app/core/Streams.jsx
+++ b/hubs/static/client/app/core/Streams.jsx
@@ -14,45 +14,39 @@ export default class Streams extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
-      items: {
-        "notif": [],
-        "action": [],
-      },
+      notifItems: [],
+      savedItems: [],
       sseActive: false,
     };
     this.handleInitialData = this.handleInitialData.bind(this);
+    this.handleInitialSavedData = this.handleInitialSavedData.bind(this);
     this.handleMessage = this.handleMessage.bind(this);
     this.handleSave = this.handleSave.bind(this);
     this.handleUnsave = this.handleUnsave.bind(this);
   }
 
   handleInitialData(data) {
-    var newItems = {
-        notif: data.notif,
-        action: data.action,
-      };
     // Only activate SSE after the initial loading, or new elements may
     // be overwritten.
     this.setState({
-      items: newItems,
+      notifItems: data,
       sseActive: true,
     });
   }
 
+  handleInitialSavedData(data) {
+    this.setState({savedItems: data});
+  }
+
   handleMessage(msg) {
-    var items = this.state.items[msg.type];
-    if (items.length >= this.props.messageLimit) {
-      items.pop();
-    }
+    var items = this.state.notifItems;
     items.unshift(msg);
-    this.setState((prevState, props) => {
-      prevState.items[msg.type] = items;
-      return {items: prevState.items};
-    });
+    items = items.slice(0, this.props.messageLimit);
+    this.setState({notifItems: items});
   }
 
   handleSave(item) {
-    if (!this.props.urls.save) { return; }
+    if (!this.props.urls.saved) { return; }
     const payload = {
       link: item.link,
       markup: item.markup,
@@ -61,97 +55,93 @@ export default class Streams extends React.Component {
     };
     $.ajax({
       type: 'POST',
-      url: this.props.urls.save,
+      url: this.props.urls.saved,
       data: JSON.stringify(payload),
       contentType: 'application/json',
-      success: () => {
+      success: (data) => {
         this.setState((prevState, props) => {
-          var items = prevState.items.notif.map((currentItem) => {
-            if (currentItem.dom_id === item.dom_id) {
-              currentItem.saved = true;
-            }
-            return currentItem;
-          })
-          prevState.items.notif = items;
-          return {items: prevState.items};
+          prevState.savedItems.push(data.data);
+          return {savedItems: prevState.savedItems};
         });
       },
     });
   }
 
   handleUnsave(item) {
-    if (!this.props.urls.save) { return; }
-    var updateItemState = (item) => {
+    if (!this.props.urls.saved) { return; }
+    var updateSavedItems = (item) => {
       this.setState((prevState, props) => {
-        var items = prevState.items.notif.map((currentItem) => {
-          if (currentItem.dom_id === item.dom_id) {
-            currentItem.saved = false;
-          }
-          return currentItem;
-        });
-        prevState.items.notif = items;
-        return {items: prevState.items};
+        var items = prevState.savedItems.filter(
+          (currentItem) => (currentItem.dom_id !== item.dom_id)
+        );
+        return {savedItems: items};
       });
     };
     if (item.idx) {
       // Already saved
       $.ajax({
         type: 'DELETE',
-        url: `${this.props.urls.save}${item.idx}/`,
-        success: () => { updateItemState(item) },
+        url: `${this.props.urls.saved}${item.idx}/`,
+        success: () => { updateSavedItems(item) },
       });
     } else {
-      updateItemState(item);
+      updateSavedItems(item);
     }
   }
 
   render() {
-    var saved = [];
-    if (this.state.items.notif) {
-      saved = this.state.items.notif.filter((item) => (item.saved));
-    }
+    // Add saved state.
+    var savedItemsIds = this.state.savedItems.map((item) => {
+      return item.dom_id;
+    });
+    var notifs = this.state.notifItems.map((item) => {
+      item.saved = (savedItemsIds.indexOf(item.dom_id) !== -1);
+      return item;
+    });
 
     return (
       <IntlProvider locale={navigator.language}>
-        <ItemsGetter
-          sseActive={this.state.sseActive}
-          urls={this.props.urls}
-          handleMessage={this.handleMessage}
-          handleInitialData={this.handleInitialData}
-          >
-          <TabSet tabListClass="mb-3">
-            <FeedPanel
-              hub={this.props.hub}
-              tabTitle="My Stream"
+        <TabSet tabListClass="mb-3">
+          <FeedPanel
+            hub={this.props.hub}
+            tabTitle="My Stream"
+            >
+            <ItemsGetter
+              sseActive={this.state.sseActive}
+              urls={this.props.urls}
+              handleMessage={this.handleMessage}
+              handleInitialData={this.handleInitialData}
               >
               <Feed
-                items={this.state.items.notif}
+                items={notifs}
                 handleSave={this.handleSave}
                 handleUnsave={this.handleUnsave}
                 />
-            </FeedPanel>
-            <FeedPanel
-              hub={this.props.hub}
-              tabTitle="My Actions"
+            </ItemsGetter>
+          </FeedPanel>
+          <FeedPanel
+            hub={this.props.hub}
+            tabTitle="My Actions"
+            >
+            <Feed
+              items={this.state.notifItems}
+              />
+          </FeedPanel>
+          <FeedPanel
+            hub={this.props.hub}
+            tabTitle="Saved Notifications"
+            >
+            <ItemsGetter
+              urls={{content: this.props.urls.saved}}
+              handleInitialData={this.handleInitialSavedData}
               >
               <Feed
-                items={this.state.items.action}
-                handleSave={this.handleSave}
-                handleUnsave={this.handleUnsave}
-                />
-            </FeedPanel>
-            <FeedPanel
-              hub={this.props.hub}
-              tabTitle="Saved Notifications"
-              >
-              <Feed
-                items={saved}
-                handleSave={this.handleSave}
+                items={this.state.savedItems}
                 handleUnsave={this.handleUnsave}
                 />
-            </FeedPanel>
-          </TabSet>
-        </ItemsGetter>
+            </ItemsGetter>
+          </FeedPanel>
+        </TabSet>
       </IntlProvider>
     );
   }
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 0bd9538..58ba9ca 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -33,7 +33,7 @@
     const StreamsElement = React.createElement(Hubs.Streams, {
         hub: {{ hub.name | tojson }},
         urls: {
-            save: {{ url_for("notifications", user=hub.name) | tojson }},
+            saved: {{ url_for("notifications", user=hub.name) | tojson }},
             content: {{ url_for("stream_existing", name=hub.name) | tojson }},
         },
         messageLimit: 100,
diff --git a/hubs/views/user.py b/hubs/views/user.py
index 0a15cac..d40e393 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -18,18 +18,10 @@ from hubs.utils.views import (
 def stream(name):
     hub = get_hub(name)
     widgets = get_visible_widgets(hub)
-    saved = hubs.models.SavedNotification.by_username(name)
-    saved = [n.__json__() for n in saved]
-
-    stream = hubs.stream.Stream()
-    actions = stream.get_json()
-
     return flask.render_template(
         'stream.html',
         hub=hub,
         widgets=widgets,
-        saved=json.dumps(saved),
-        actions=actions
     )
 
 
@@ -39,22 +31,23 @@ def stream_existing(name):
     hub = get_hub(name)
     stream = hubs.stream.Stream()
     existing = json.loads(stream.get_json())
-    saved = [s.dom_id for s in
-             hubs.models.SavedNotification.by_username(name)]
-    for e in existing:
-        e["saved"] = (e["dom_id"] in saved)
     # Right now, stream and actions are the same.
     # Once mentions is implemented, then each will be its own.
     return flask.jsonify(dict(
-        status="OK", data=dict(notif=existing, action=existing),
+        status="OK", data=existing,
         ))
 
 
-@app.route('/<user>/notifications', methods=['POST'])
-@app.route('/<user>/notifications/', methods=['POST'])
+@app.route('/<user>/notifications', methods=['GET', 'POST'])
+@app.route('/<user>/notifications/', methods=['GET', 'POST'])
 @login_required
 def notifications(user):
-    if flask.request.method == 'POST':
+    if flask.request.method == "GET":
+        saved = hubs.models.SavedNotification.by_username(user)
+        return flask.jsonify(dict(
+            status="OK", data=[n.__json__() for n in saved],
+            ))
+    elif flask.request.method == "POST":
         data = flask.request.get_json()
         user = hubs.models.User.by_username(user)
         if not user:

From 508b9eac5f5c0fc8bcf8b299664e68f338c416c4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:40:40 +0000
Subject: [PATCH 871/1001] The stream does not need the username in the URL


---

diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index cf1af80..b8e4b57 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -119,7 +119,8 @@
           </a>
         </li>
         <li class="nav-item">
-          <a class="nav-link" href="{{ url_for("stream", name=g.auth.user.username) }}">
+          <a class="nav-link {% if request.path.endswith(url_for("stream")) %}active{% endif %}"
+             href="{{ url_for("stream") }}">
             <span><i class="fa fa-home" aria-hidden="true"></i></span>
             My Stream
           </a>
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index 58ba9ca..cae069f 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -33,8 +33,8 @@
     const StreamsElement = React.createElement(Hubs.Streams, {
         hub: {{ hub.name | tojson }},
         urls: {
-            saved: {{ url_for("notifications", user=hub.name) | tojson }},
-            content: {{ url_for("stream_existing", name=hub.name) | tojson }},
+            saved: {{ url_for("saved_notifs") | tojson }},
+            content: {{ url_for("stream_existing") | tojson }},
         },
         messageLimit: 100,
     });
diff --git a/hubs/tests/views/test_user.py b/hubs/tests/views/test_user.py
index a31a782..7df2c1d 100644
--- a/hubs/tests/views/test_user.py
+++ b/hubs/tests/views/test_user.py
@@ -15,23 +15,23 @@ class TestGetNotifications(hubs.tests.APPTest):
         name = 'notarealfasuser'
 
         with hubs.tests.auth_set(app, self.user):
-            resp = self.app.get('/{}/notifications/'.format(name))
+            resp = self.app.get('/stream/saved/'.format(name))
         self.assertEqual(resp.status_code, 200)
         data = json.loads(resp.get_data(as_text=True))
-        self.assertEqual(data, {"notifications": []})
+        self.assertEqual(data["status"], "OK")
+        self.assertEqual(data["data"], [])
 
     def test_get_notifications_valid_name(self):
         with hubs.tests.auth_set(app, self.user):
-            resp = self.app.get('/{}/notifications/'.format(
+            resp = self.app.get('/stream/saved/'.format(
                 self.user.username))
 
         self.assertEqual(resp.status_code, 200)
         data = json.loads(resp.get_data(as_text=True))
-        self.assertEqual(len(data["notifications"]), 1)
-
-        for saved in data["notifications"]:
-            self.assertEqual(saved['markup'], 'foo')
-            self.assertEqual(saved['link'], 'bar')
+        self.assertEqual(data["status"], "OK")
+        self.assertEqual(len(data["data"]), 1)
+        self.assertEqual(data["data"][0]['markup'], 'foo')
+        self.assertEqual(data["data"][0]['link'], 'bar')
 
 
 class TestPostNotifications(hubs.tests.APPTest):
@@ -48,18 +48,10 @@ class TestPostNotifications(hubs.tests.APPTest):
         'username': user.username,
     }
 
-    def test_post_notification_invalid_user(self):
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post(
-                '/{}/notifications/'.format('notarealfasuser'),
-                data=json.dumps(self.valid_payload),
-                content_type='application/json')
-        self.assertEqual(resp.status_code, 400)
-
     def test_post_notification_invalid_payload(self):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post(
-                '/{}/notifications/'.format(self.user.username),
+                '/stream/saved/',
                 data=json.dumps(self.invalid_payload),
                 content_type='application/json')
         self.assertEqual(resp.status_code, 400)
@@ -67,15 +59,16 @@ class TestPostNotifications(hubs.tests.APPTest):
     def test_post_notification_valid_payload(self):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.post(
-                '/{}/notifications/'.format(self.user.username),
+                '/stream/saved/',
                 data=json.dumps(self.valid_payload),
                 content_type='application/json')
 
         self.assertEqual(resp.status_code, 200)
         data = json.loads(resp.get_data(as_text=True))
         self.assertTrue(isinstance(data, dict))
+        self.assertEqual(data["status"], "OK")
 
-        notification = data['notification']
+        notification = data['data']
         self.assertEqual(notification['markup'], 'foobar')
         self.assertEqual(notification['link'], 'baz')
 
@@ -107,7 +100,7 @@ class TestDeleteNotifications(hubs.tests.APPTest):
         self.assertIsNotNone(self.notification)
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.delete(
-                '/{}/notifications/{}/'.format(self.user.username, idx)
+                '/stream/saved/{}/'.format(idx)
             )
 
         self.assertEqual(resp.status_code, 200)
@@ -121,7 +114,7 @@ class TestDeleteNotifications(hubs.tests.APPTest):
 
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.delete(
-                '/{}/notifications/{}/'.format(self.user.username, idx)
+                '/stream/saved/{}/'.format(self.user.username, idx)
             )
         self.assertEqual(resp.status_code, 404)
 
diff --git a/hubs/views/user.py b/hubs/views/user.py
index d40e393..64ebb81 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -11,12 +11,12 @@ from hubs.utils.views import (
     )
 
 
-@app.route('/<name>/stream')
-@app.route('/<name>/stream/')
+@app.route('/stream')
+@app.route('/stream/')
 @login_required
-@require_hub_access("view")
-def stream(name):
-    hub = get_hub(name)
+def stream():
+    username = flask.g.auth.user.username
+    hub = get_hub(username)
     widgets = get_visible_widgets(hub)
     return flask.render_template(
         'stream.html',
@@ -25,10 +25,10 @@ def stream(name):
     )
 
 
-@app.route('/<name>/stream/existing')
-@require_hub_access("view")
-def stream_existing(name):
-    hub = get_hub(name)
+@app.route('/stream/existing')
+@login_required
+def stream_existing():
+    username = flask.g.auth.user.username
     stream = hubs.stream.Stream()
     existing = json.loads(stream.get_json())
     # Right now, stream and actions are the same.
@@ -38,20 +38,18 @@ def stream_existing(name):
         ))
 
 
-@app.route('/<user>/notifications', methods=['GET', 'POST'])
-@app.route('/<user>/notifications/', methods=['GET', 'POST'])
+@app.route('/stream/saved', methods=['GET', 'POST'])
+@app.route('/stream/saved/', methods=['GET', 'POST'])
 @login_required
-def notifications(user):
+def saved_notifs():
+    user = flask.g.auth.user
     if flask.request.method == "GET":
-        saved = hubs.models.SavedNotification.by_username(user)
+        saved = hubs.models.SavedNotification.by_username(user.username)
         return flask.jsonify(dict(
             status="OK", data=[n.__json__() for n in saved],
             ))
     elif flask.request.method == "POST":
         data = flask.request.get_json()
-        user = hubs.models.User.by_username(user)
-        if not user:
-            return flask.abort(400)
         try:
             markup = data['markup']
             link = data['link']
@@ -73,10 +71,10 @@ def notifications(user):
             ))
 
 
-@app.route('/<user>/notifications/<int:idx>', methods=['DELETE'])
-@app.route('/<user>/notifications/<int:idx>/', methods=['DELETE'])
+@app.route('/stream/saved/<int:idx>', methods=['DELETE'])
+@app.route('/stream/saved/<int:idx>/', methods=['DELETE'])
 @login_required
-def delete_notifications(user, idx):
+def delete_notifs(idx):
     notification = flask.g.db.query(
         hubs.models.SavedNotification).filter_by(idx=idx).first()
     if not notification:

From 2460db0100248cc00d72157af992be7ba1de6b0b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:40:40 +0000
Subject: [PATCH 872/1001] Add a test for /stream/existing


---

diff --git a/hubs/tests/views/test_user.py b/hubs/tests/views/test_user.py
index 7df2c1d..f15192c 100644
--- a/hubs/tests/views/test_user.py
+++ b/hubs/tests/views/test_user.py
@@ -3,11 +3,34 @@ from __future__ import unicode_literals
 import json
 import unittest
 
+from mock import Mock, patch
+
 import hubs.tests
 import hubs.models
 from hubs.app import app
 
 
+class TestStreamExisting(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('ralph')
+
+    @patch("hubs.feed.Notifications")
+    def test_get(self, Notifications):
+        feed = Mock()
+        Notifications.return_value = feed
+        feed.get.return_value = [{
+            "markup": "foo", "link": "bar",
+        }]
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.get('/stream/existing')
+
+        self.assertEqual(resp.status_code, 200)
+        data = json.loads(resp.get_data(as_text=True))
+        self.assertEqual(data["status"], "OK")
+        self.assertEqual(len(data["data"]), 1)
+        self.assertEqual(data["data"][0]['markup'], 'foo')
+        self.assertEqual(data["data"][0]['link'], 'bar')
+
+
 class TestGetNotifications(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('ralph')
 
@@ -19,7 +42,9 @@ class TestGetNotifications(hubs.tests.APPTest):
         self.assertEqual(resp.status_code, 200)
         data = json.loads(resp.get_data(as_text=True))
         self.assertEqual(data["status"], "OK")
-        self.assertEqual(data["data"], [])
+        self.assertEqual(len(data["data"]), 1)
+        self.assertEqual(data["data"][0]['markup'], 'foo')
+        self.assertEqual(data["data"][0]['link'], 'bar')
 
     def test_get_notifications_valid_name(self):
         with hubs.tests.auth_set(app, self.user):

From d42f2eaf8b1a283efaa87b64d9bb8d3db48d3b5d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:41:17 +0000
Subject: [PATCH 873/1001] Create a backend for the Feed widget and the My Stream page


---

diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index 50ba5ef..16bcbd1 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -30,6 +30,7 @@ import sys
 import retask.queue
 
 import hubs.app
+import hubs.feed
 import hubs.models
 import hubs.widgets.base
 
@@ -39,7 +40,7 @@ fedmsg_config = hubs.app.fedmsg_config
 session = hubs.app.session
 
 
-def triage(outbound, msg):
+def triage(msg):
     topic = msg['topic']
 
     for suffix in fedmsg_config['hubs.junk_suffixes']:
@@ -47,14 +48,22 @@ def triage(outbound, msg):
             log.debug("  Dropping junk %r", topic)
             return
 
-    # Get a list of all our widgets:
-    log.debug("Querying for all widgets.")
-    widgets = session.query(hubs.models.Widget).all()
+    # Handle user notifications.
+    if ".fmn.notification." in topic:  # XXX: use the proper topic pattern when it's chosen
+        yield retask.task.Task(json.dumps({
+            'type': 'notification',
+            'msg': msg,
+        }))
+        return  # Notifications don't appear anywhere else, stop here.
 
-    # Randomize so that all the triage daemons work on widgets in different
-    # orders.  This should hopefully prevent cache thrashing.
-    log.debug("Randomizing list of all widgets.")
-    random.shuffle(widgets)
+    # Store the list of concerned hubs to check later in the
+    # should_invalidate() method of Feed widgets.
+    msg["_hubs"] = hubs.feed.get_hubs_for_msg(msg)
+
+    # Store the message for the Feed widgets.
+    hubs.feed.on_new_message(msg)
+
+    widgets = get_widgets()
 
     def is_widget_update(msg, widget):
         """Always rebuild the cache when the widget config is updated."""
@@ -64,15 +73,29 @@ def triage(outbound, msg):
     log.debug("Checking should_invalidate for all widgets.")
     for widget in widgets:
         for fn_name, fn_class in widget.module.get_cached_functions().items():
-            if is_widget_update(msg, widget) or \
-                    fn_class(widget).should_invalidate(msg):
+            # log.debug("Checking %s:%s", widget.plugin, widget.idx)
+            fn = fn_class(widget)
+            if is_widget_update(msg, widget) or fn.should_invalidate(msg):
                 yield retask.task.Task(json.dumps({
+                    'type': 'widget-cache',
                     'idx': widget.idx,
                     'fn_name': fn_name,
                     'msg_id': msg['msg_id'],
                 }))
 
 
+def get_widgets():
+    # Get a list of all our widgets:
+    log.debug("Querying for all widgets.")
+    widgets = session.query(hubs.models.Widget).all()
+    # Randomize so that all the triage daemons work on widgets in different
+    # orders.  This should hopefully prevent cache thrashing.
+    log.debug("Randomizing list of all widgets.")
+    random.shuffle(widgets)
+    # TODO: cache the widgets list until a widget is added or deleted?
+    return widgets
+
+
 def main(args=None):
     args = args if args is not None else sys.argv
     logging.config.dictConfig(fedmsg_config['logging'])
@@ -102,7 +125,7 @@ def main(args=None):
                 inbound.length, outbound.length, msg['msg_id'], msg['topic'],
             )
             with hubs.app.app.app_context():  # so url_for works
-                for task in triage(outbound, msg):
+                for task in triage(msg):
                     log.debug("  Triage sending %r to workers." % task)
                     outbound.enqueue(task)
             log.debug("  Done with triage of %r.", msg['msg_id'])
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index 30c55bc..5e82bda 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -34,6 +34,7 @@ import sys
 import retask.queue
 
 import hubs.app
+import hubs.feed
 import hubs.models
 import hubs.widgets.base
 
@@ -43,7 +44,7 @@ fedmsg_config = hubs.app.fedmsg_config
 session = hubs.app.session
 
 
-def work(widget_idx, fn_name):
+def widget_cache_work(widget_idx, fn_name):
     # Get a real widget, because we update last_refreshed on it.
     widget = hubs.models.Widget.by_idx(widget_idx)
     fn_class = widget.module.get_cached_functions()[fn_name]
@@ -53,11 +54,10 @@ def work(widget_idx, fn_name):
     # TODO -- fire off an EventSource notice that we updated stuff
 
 
-def handle(idx, fn_name):
-
+def handle_widget_cache(widget_idx, fn_name):
     try:
         with hubs.app.app.app_context():  # so url_for works
-            work(idx, fn_name)
+            widget_cache_work(widget_idx, fn_name)
         session.commit()  # transaction is committed here
     except:
         session.rollback()  # rolls back the transaction
@@ -78,6 +78,10 @@ def main(args=None):
     log.info("Worker starting, connecting to retask queue %r." % name)
     queue = retask.queue.Queue(name)
     queue.connect()
+    sse_name = fedmsg_config['hubs.redis.sse-queue-name']
+    log.info("Worker starting, connecting to retask queue %r." % sse_name)
+    sse_queue = retask.queue.Queue(sse_name)
+    sse_queue.connect()
 
     try:
         log.info("Entering work loop.")
@@ -85,7 +89,23 @@ def main(args=None):
             task = queue.wait()  # Wait forever...  timeout is optional.
             log.info("Working on %r.  (backlog is %r)" % (task, queue.length))
             item = json.loads(task.data)
-            handle(item['idx'], item['fn_name'])
+            sse_task = None
+            item_type = item.get("type", "widget-cache")
+            if item_type == "widget-cache":
+                handle_widget_cache(item['idx'], item['fn_name'])
+                sse_task = {
+                    "event": "hubs:widget-updated",
+                    "data": item["idx"],
+                }
+            elif item_type == "notification":
+                hubs.feed.on_new_notification(item["msg"])
+                username = fedmsg.meta.msg2agent(msg)
+                sse_task = {
+                    "event": "hubs:new-notification",
+                    "data": username,
+                }
+            if sse_task is not None:
+                sse_queue.enqueue(retask.task.Task(json.dumps(sse_task)))
             log.debug("  Done.")
     except KeyboardInterrupt:
         pass
diff --git a/hubs/default_fedmsg_config.py b/hubs/default_fedmsg_config.py
index 648f504..7cf088d 100644
--- a/hubs/default_fedmsg_config.py
+++ b/hubs/default_fedmsg_config.py
@@ -9,6 +9,7 @@ config = {
     # For communication between fedmsg-hub and the cache worker farm
     'hubs.redis.triage-queue-name': 'fedora-hubs-triage-queue',
     'hubs.redis.work-queue-name': 'fedora-hubs-work-queue',
+    'hubs.redis.sse-queue-name': 'fedora-hubs-sse-queue',
 
     # Junk junk junk.. that we don't care about.  Drop it!
     'hubs.junk_suffixes': [
diff --git a/hubs/feed.py b/hubs/feed.py
new file mode 100644
index 0000000..786844b
--- /dev/null
+++ b/hubs/feed.py
@@ -0,0 +1,181 @@
+from __future__ import unicode_literals
+
+import hashlib
+import logging
+import os
+
+import fedmsg.meta
+import redis
+from fedmsg.encoding import loads, dumps
+
+import hubs.app
+from hubs.models import Hub, User, Association
+
+
+log = logging.getLogger(__name__)
+
+
+def get_hubs_for_msg(msg):
+    hubs = []
+    for username in fedmsg.meta.msg2usernames(msg):
+        user = User.query.get(username)
+        # Only act on existing users
+        if user is None:
+            log.debug("Message concerning an unknown user: %s", username)
+            continue
+        hubs.append(username)
+        group_hubs = Hub.query.filter(
+                Hub.user_hub == False,  # noqa:E712
+            ).join(Association).filter(
+                Association.user == user,
+                Association.role.in_(["owner", "member"]),
+            )
+        hubs.extend([result[0] for result in group_hubs.values(Hub.name)])
+    return hubs
+
+
+def on_new_notification(msg):
+    """Only for FMN messages."""
+    username = fedmsg.meta.msg2agent(msg)
+    user = User.query.get(username)
+    # Only act on existing users
+    if user is None:
+        log.debug("Notification for an unknown user: %s", username)
+        return
+    # Users may exists without their hub if they have never logged
+    # in but are just added to the members list.  Don't check that
+    # the user Hub actually exists, it will be created when the user
+    # logs in, and this way the feed will be already populated.
+    log.debug("Received a notification concerning %s", username)
+    feed = Notifications(username)
+    feed.add(msg)
+
+
+def on_new_message(msg):
+    for hub_name in msg["_hubs"]:
+        log.debug("Received a feed item for hub %s", hub_name)
+        feed = Activity(hub_name)
+        feed.add(msg)
+
+
+def format_msg(msg):
+    if "msg_ids" not in msg:
+        msg = fedmsg.meta.conglomerate([msg])[0]
+    # Compute a deterministic dom_id.  Since this is the identifier stored
+    # when the message is saved by the user in the SQL DB, it has to be
+    # invariant through conglomerate() calls.
+    msg["dom_id"] = hashlib.sha1(
+        b":".join(
+            [mid.encode("utf-8") for mid in msg["msg_ids"]]
+        )).hexdigest()
+    # TODO: generate markup
+    msg["markup"] = msg["subtitle"]
+    msg["markup_subjective"] = msg["subjective"]
+    return msg
+
+
+class Feed(object):
+
+    max_items = 100
+    connection_pool = None
+    msgtype = None
+
+    def __init__(self, owner):
+        """
+        Args:
+            owner (str): User name or Hub name.
+        """
+        if self.msgtype is None:
+            raise NotImplementedError(
+                "You must subclass Feed and set self.msgtype.")
+        self.owner = owner
+        self.db = None
+        fedmsg_config = hubs.app.fedmsg_config
+        self.db_config = {
+            'host': fedmsg_config.get('hubs.redis.host', 'localhost'),
+            'port': fedmsg_config.get('hubs.redis.port', 6379),
+            'db': fedmsg_config.get('hubs.redis.db', 0),
+            'password': fedmsg_config.get('hubs.redis.password', None),
+            }
+        self.key = self._get_key()
+
+    def _get_key(self):
+        parts = ["feed", self.msgtype, self.owner]
+        key_prefix = hubs.app.fedmsg_config.get('hubs.redis.feed-prefix')
+        if key_prefix:
+            parts.insert(0, key_prefix)
+        return "|".join(parts)
+
+    def get(self, start=0, end=None):
+        end = end or -1
+        if self.db is None:
+            self.connect()
+        return [
+            loads(item.decode("utf-8")) for item in
+            self.db.lrange(self.key, start, end)
+            ]
+
+    def add(self, msg):
+        if self.db is None:
+            self.connect()
+        log.debug("Adding message %s to %s", msg["msg_id"], self.key)
+        self.db.lpush(self.key, dumps(self._format_msg(msg)))
+        self.db.ltrim(self.key, 0, self.max_items)
+
+    def length(self):
+        if self.db is None:
+            self.connect()
+        return self.db.llen(self.key)
+
+    __len__ = length
+
+    def connect(self):
+        if self.connection_pool is None:
+            self.connection_pool = redis.ConnectionPool(**self.db_config)
+        self.db = redis.Redis(connection_pool=self.connection_pool)
+        try:
+            self.db.info()
+        except redis.exceptions.ConnectionError:
+            log.warning("Could not connect to Redis")
+            self.db = None
+            raise  # XXX: do better?
+
+    def close(self):
+        try:
+            self.db.close()
+        except redis.exceptions.ConnectionError:
+            log.warning("Could not disconnect from Redis")
+            raise  # XXX: do better?
+        self.db = None
+        self.connection_pool = None
+
+
+class Notifications(Feed):
+
+    msgtype = "notif"
+
+    def _format_msg(self, msg):
+        return format_msg(msg)
+
+
+class Activity(Feed):
+
+    msgtype = "activity"
+
+    def _format_msg(self, msg):
+        # No-op, we want raw messages in the DB to conglomerate and format them
+        # later.
+        return msg
+
+
+def _load_json(username):
+    """This loads dummy data in the feeds."""
+    here = os.path.dirname(os.path.abspath(__file__))
+    with open(os.path.join(here, 'actions.json')) as fp:
+        msgs = loads(fp.read())
+    for feed_class in (Notifications, Activity):
+        feed = feed_class(username)
+        if feed.db is None:
+            feed.connect()
+        for msg in msgs:
+            feed.db.rpush(feed.key, dumps(msg))
diff --git a/hubs/stream.py b/hubs/stream.py
deleted file mode 100644
index f939ab3..0000000
--- a/hubs/stream.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from __future__ import unicode_literals
-
-import os
-
-
-class Stream(object):
-    def get_json(self):
-        here = os.path.dirname(os.path.abspath(__file__))
-        with open(os.path.join(here, 'actions.json')) as fp:
-            actions = fp.read()
-        return actions
diff --git a/hubs/tests/test_feed.py b/hubs/tests/test_feed.py
new file mode 100644
index 0000000..29b21ba
--- /dev/null
+++ b/hubs/tests/test_feed.py
@@ -0,0 +1,119 @@
+from __future__ import unicode_literals
+
+import json
+
+from mock import Mock, patch
+
+from hubs.app import app
+from hubs.models import User, Hub, Association
+from hubs.feed import (
+    Notifications, Activity, format_msg, get_hubs_for_msg,
+    on_new_message, on_new_notification)
+from hubs.tests import APPTest
+
+
+class FeedTest(APPTest):
+
+    def setUp(self):
+        super(FeedTest, self).setUp()
+        self.feed_classes = [
+            (Notifications, "notif"),
+            (Activity, "activity"),
+            ]
+
+    def tearDown(self):
+        super(FeedTest, self).tearDown()
+
+    def test_get(self):
+        for feed_class, msgtype in self.feed_classes:
+            feed = feed_class("testuser")
+            feed.db = Mock()
+            feed.db.lrange.return_value = []
+            feed.get()
+            feed.db.lrange.assert_called_once_with(
+                "feed|{}|testuser".format(msgtype), 0, -1)
+
+    def test_add(self):
+        msg = {
+            "msg_id": "testid",
+            "topic": "test.topic.dummy.value",
+            "timestamp": 123456789,
+            "testkey": "testvalue",
+            }
+        for feed_class, msgtype in self.feed_classes:
+            feed = feed_class("testuser")
+            feed.db = Mock()
+            key = "feed|{}|testuser".format(msgtype)
+            feed.add(msg)
+            feed.db.lpush.assert_called_once()
+            lpush_call_args = feed.db.lpush.call_args_list[0][0]
+            self.assertEqual(lpush_call_args[0], key)
+            if feed_class == Notifications:
+                self.assertIn("msg_ids", json.loads(lpush_call_args[1]))
+            elif feed_class == Activity:
+                self.assertEqual(json.loads(lpush_call_args[1]), msg)
+            feed.db.ltrim.assert_called_once_with(key, 0, 100)
+
+    def test_length(self):
+        for feed_class, msgtype in self.feed_classes:
+            feed = feed_class("testuser")
+            feed.db = Mock()
+            feed.db.llen.return_value = 42
+            self.assertEqual(feed.length(), 42)
+            feed.db.llen.assert_called_once_with(
+                "feed|{}|testuser".format(msgtype))
+
+    def test_close(self):
+        for feed_class, msgtype in self.feed_classes:
+            feed = feed_class("testuser")
+            redis_mock = feed.db = Mock()
+            feed.close()
+            redis_mock.close.assert_called_once()
+            self.assertIsNone(feed.db)
+            self.assertIsNone(feed.connection_pool)
+
+    @patch("hubs.feed.Activity")
+    def test_on_new_message(self, mock_activity):
+        msg = {"_hubs": ["testhub1", "testhub2"]}
+        feed = Mock()
+        mock_activity.return_value = feed
+        on_new_message(msg)
+        call_args = [c[0] for c in mock_activity.call_args_list]
+        self.assertEqual(call_args, [("testhub1", ), ("testhub2", )])
+        self.assertEqual(feed.add.call_count, 2)
+        feed.add.assert_called_with(msg)
+
+    @patch("hubs.feed.Notifications")
+    def test_on_new_notification(self, mock_notifications):
+        feed = Mock()
+        mock_notifications.return_value = feed
+        msg = {"msg_id": "testmsg"}
+        with patch("hubs.feed.fedmsg.meta.msg2agent") as msg2agent:
+            msg2agent.return_value = "ralph"
+            on_new_notification(msg)
+        msg2agent.assert_called()
+        mock_notifications.assert_called_with("ralph")
+        feed.add.assert_called_with(msg)
+
+    @patch("hubs.feed.Notifications")
+    def test_on_new_notification_unknown_user(self, mock_notifications):
+        with patch("hubs.feed.fedmsg.meta.msg2agent") as msg2agent:
+            msg2agent.return_value = "unknown_user"
+            on_new_notification({"msg_id": "testmsg"})
+        msg2agent.assert_called()
+        # User does not exist, no feed instance should have been created.
+        mock_notifications.assert_not_called()
+
+    @patch("hubs.feed.fedmsg.meta.msg2usernames")
+    def test_get_hubs_for_msg(self, msg2usernames):
+        ralph = User.query.get("ralph")
+        infra = Hub.query.get("infra")
+        test_hub = Hub(name="testhub")
+        self.session.add(test_hub)
+        self.session.add(Association(hub=test_hub, user=ralph, role="member"))
+        self.session.add(Association(hub=infra, user=ralph, role="owner"))
+        msg2usernames.return_value = ["unknown_user", "ralph"]
+        self.assertListEqual(
+            sorted(get_hubs_for_msg({"msg_id": "testmsg"})),
+            ["infra", "ralph", "testhub"]
+            )
diff --git a/hubs/views/user.py b/hubs/views/user.py
index 64ebb81..0306821 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals, absolute_import
 import flask
 import json
 import hubs.models
-import hubs.stream
+import hubs.feed
 
 from hubs.app import app
 from hubs.utils.views import (
@@ -29,8 +29,8 @@ def stream():
 @login_required
 def stream_existing():
     username = flask.g.auth.user.username
-    stream = hubs.stream.Stream()
-    existing = json.loads(stream.get_json())
+    feed = hubs.feed.Notifications(username)
+    existing = feed.get()  # TODO: paging?
     # Right now, stream and actions are the same.
     # Once mentions is implemented, then each will be its own.
     return flask.jsonify(dict(
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index 6f7d07a..f8ed081 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -1,11 +1,16 @@
-from __future__ import unicode_literals
+from __future__ import unicode_literals, absolute_import
 
 
+import logging
+
+import hubs.feed
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
-import logging
-log = logging.getLogger('hubs')
+from .functions import GetData
+
+
+log = logging.getLogger('hubs.widgets')
 
 
 class Feed(Widget):
@@ -16,10 +21,10 @@ class Feed(Widget):
     parameters = [
         {
             "name": "username",
-            "label": "Username",
+            "label": "User name",
             "default": None,
             "validator": validators.Username,
-            "help": "A FAS username.",
+            "help": "A user name.",
         }, {
             "name": "message_limit",
             "label": "Message limit",
@@ -27,6 +32,7 @@ class Feed(Widget):
             "validator": validators.Integer,
             "help": "Max number of feed messages to display.",
         }]
+    cached_functions_module = ".functions"
 
 
 class BaseView(WidgetView):
@@ -55,11 +61,8 @@ class ExistingView(WidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         username = instance.config["username"]
-        # Mock data:
-        import hubs.stream
-        import json
-        stream = hubs.stream.Stream()
-        existing = json.loads(stream.get_json())
+        get_data = GetData(instance)
+        existing = get_data()
         return {
             "status": "OK",
             "data": existing,
diff --git a/hubs/widgets/feed/functions.py b/hubs/widgets/feed/functions.py
new file mode 100644
index 0000000..afe2836
--- /dev/null
+++ b/hubs/widgets/feed/functions.py
@@ -0,0 +1,27 @@
+from __future__ import unicode_literals, absolute_import
+
+
+import flask
+import fedmsg.meta
+
+from hubs.feed import Activity, format_msg
+from hubs.widgets.caching import CachedFunction
+
+
+class GetData(CachedFunction):
+    """Get the feed data from Redis and aggregate it."""
+
+    def execute(self):
+        username = self.instance.config["username"]
+        feed = Activity(username)
+        raw_msgs = feed.get()  # TODO: paging?
+        msgs = fedmsg.meta.conglomerate(raw_msgs)
+        msgs = [format_msg(msg) for msg in msgs]
+        limit = self.instance.config["message_limit"]
+        return msgs[:limit]
+
+    def should_invalidate(self, message):
+        if "_hubs" not in message:
+            return False
+        username = self.instance.config["username"]
+        return (username in message["_hubs"])
diff --git a/requirements.txt b/requirements.txt
index e2a8eb5..ed9742f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -24,4 +24,5 @@ pkgwat.api
 six
 pygments
 pygments-markdown-lexer
+redis
 retask

From 156d5e9b132dc39c42ebf6d883822be8048152f6 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:41:17 +0000
Subject: [PATCH 874/1001] Be more resilient with incoming messages


---

diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index a9e0c4f..8939130 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -90,6 +90,12 @@ class GetIssues(CachedFunction):
         return issues
 
     def should_invalidate(self, message):
+        if "bug" not in message["msg"]:
+            return False
+        try:
+            component = message['msg']['bug']['component']
+        except KeyError:
+            return False
         username = self.instance.config["username"]
         url = "/".join([PKGDB_URL, username])
         response = requests.get(url)
@@ -97,7 +103,4 @@ class GetIssues(CachedFunction):
 
         owned = data['point of contact'] + data['co-maintained']
         owned = [p['name'] for p in owned]
-        if message['msg']['bug']['component'] in owned:
-            return True
-
-        return False
+        return (component in owned)
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index afcdf2e..70f545e 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -1,5 +1,7 @@
 from __future__ import unicode_literals
 
+import json
+
 import flask
 import fedmsg.config
 import fedmsg.meta
@@ -56,7 +58,10 @@ class GetStats(CachedFunction):
         url = "https://apps.fedoraproject.org/datagrepper/raw?user={username}"
         url = url.format(username=username)
         response = requests.get(url)
-        fedmsgs = response.json()['total']
+        try:
+            fedmsgs = response.json()['total']
+        except json.decoder.JSONDecodeError:
+            fedmsgs = 0
         sub_list = []
         for assoc in self.instance.hub.associations:
             if assoc.user:
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index cce7322..0eec25a 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -77,5 +77,8 @@ class GetPRs(CachedFunction):
         if category != "pagure":
             # TODO -- this could be honed in more to just PRs
             return False
-        return (message['msg']['project']['name'] ==
-                self.instance.config['repo'])
+        try:
+            project = message['msg']['project']['name']
+        except KeyError:
+            return False
+        return (project == self.instance.config['repo'])
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index b30a208..9ceb94b 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -63,7 +63,7 @@ class GetPending(CachedFunction):
             return False
         # Search the message to see if I am in the ACLs list of the request.
         username = self.instance.config["username"]
-        for acl in message['msg']['package_listing']['acls']:
+        for acl in message['msg']['package_listing'].get('acls', []):
             if acl['fas_name'] == username and acl['status'] == 'Approved':
                 return True
         return False

From 05ccb0c2335b17c3d4e4756d79ff39866fea55c2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:41:17 +0000
Subject: [PATCH 875/1001] Unused import


---

diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index acb18d5..51c46b5 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -7,7 +7,6 @@ Attributes:
 from __future__ import unicode_literals
 
 import datetime
-import dogpile
 import dogpile.cache
 import logging
 

From a551f0c52347e35e470e147669cdc8b79768a8f4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:41:17 +0000
Subject: [PATCH 876/1001] Cache the list of packages owned by the user


---

diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 8939130..1c37299 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -5,7 +5,7 @@ import pkgwat.api
 
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
-from hubs.widgets.caching import CachedFunction
+from hubs.widgets.caching import CachedFunction, cache
 
 
 PKGDB_URL = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
@@ -97,10 +97,16 @@ class GetIssues(CachedFunction):
         except KeyError:
             return False
         username = self.instance.config["username"]
-        url = "/".join([PKGDB_URL, username])
-        response = requests.get(url)
-        data = response.json()
 
-        owned = data['point of contact'] + data['co-maintained']
-        owned = [p['name'] for p in owned]
+        # Cache for a while the list of packages owned by the user, the HTTP
+        # request is waaaay too long to be run on each incoming bug message.
+        def get_owned():
+            url = "/".join([PKGDB_URL, username])
+            response = requests.get(url)
+            data = response.json()
+            owned = data['point of contact'] + data['co-maintained']
+            return [p['name'] for p in owned]
+        owned_cache_key = ":".join(["owned_packages", username])
+        # Cache for 5 minutes, it seems reasonable.
+        owned = cache.get_or_create(owned_cache_key, get_owned, 5 * 60)
         return (component in owned)

From bb229287ba2f0d8f2f04d59002479163c2fcdf83 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:41:17 +0000
Subject: [PATCH 877/1001] Don't use the fedmsg as a clock to check meeting time


---

diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index 68c26b9..e8eec08 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -45,15 +45,23 @@ class BaseView(WidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_meetings = GetMeetings(instance)
+        now = datetime.datetime.utcnow()
+        meetings = {
+            title: meeting
+            for title, meeting in get_meetings().items()
+            if meeting['start_dt'] > now
+            }
         return dict(
             title=self.widget.label,
             calendar=instance.config["calendar"],
-            meetings=get_meetings(),
+            meetings=meetings,
             )
 
 
 class GetMeetings(CachedFunction):
 
+    TOPIC = ".fedocal.calendar."
+
     def execute(self):
         calendar = self.instance.config["calendar"]
         n_meetings = self.instance.config.get("n_meetings", 4)
@@ -81,18 +89,13 @@ class GetMeetings(CachedFunction):
         return meetings
 
     def should_invalidate(self, message):
-        # TODO -- first, if this is a fedocal widget, we need to just
-        # invalidate ourselves right away.
-
-        # second, check our old cache value and see if any of our meetings have
-        # passed by in time.
-        old_meetings = self.execute()
-        now = datetime.datetime.utcnow()
-        for title, meeting in old_meetings.items():
-            assert type(meeting['start_dt']) == type(now)
-            if meeting['start_dt'] < now:
-                return True
-        return False
+        if self.TOPIC not in message["topic"]:
+            return False
+        try:
+            calendar = message["msg"]["calendar"]["calendar_name"]
+        except KeyError:
+            return False
+        return (calendar == self.instance.config.get("calendar"))
 
 
 def next_meeting(meetings):

From 6e8a3d205969c9be54675b5e3033c7fddc8a82e6 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:41:17 +0000
Subject: [PATCH 878/1001] A Feed widget is linked to its hub, not to a username


---

diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index f8ed081..730150d 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -20,12 +20,6 @@ class Feed(Widget):
     position = "left"
     parameters = [
         {
-            "name": "username",
-            "label": "User name",
-            "default": None,
-            "validator": validators.Username,
-            "help": "A user name.",
-        }, {
             "name": "message_limit",
             "label": "Message limit",
             "default": 20,
@@ -44,7 +38,6 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         # Avoid circular import
         from hubs.app import app
-        username = instance.config["username"]
         sse_url = app.config['SSE_URL'] + username
         return dict(
             title=self.widget.label,
@@ -60,7 +53,6 @@ class ExistingView(WidgetView):
     json = True
 
     def get_context(self, instance, *args, **kwargs):
-        username = instance.config["username"]
         get_data = GetData(instance)
         existing = get_data()
         return {
diff --git a/hubs/widgets/feed/functions.py b/hubs/widgets/feed/functions.py
index afe2836..da6d8df 100644
--- a/hubs/widgets/feed/functions.py
+++ b/hubs/widgets/feed/functions.py
@@ -1,7 +1,6 @@
 from __future__ import unicode_literals, absolute_import
 
 
-import flask
 import fedmsg.meta
 
 from hubs.feed import Activity, format_msg
@@ -12,8 +11,8 @@ class GetData(CachedFunction):
     """Get the feed data from Redis and aggregate it."""
 
     def execute(self):
-        username = self.instance.config["username"]
-        feed = Activity(username)
+        hub_name = self.instance.hub.name
+        feed = Activity(hub_name)
         raw_msgs = feed.get()  # TODO: paging?
         msgs = fedmsg.meta.conglomerate(raw_msgs)
         msgs = [format_msg(msg) for msg in msgs]
@@ -23,5 +22,5 @@ class GetData(CachedFunction):
     def should_invalidate(self, message):
         if "_hubs" not in message:
             return False
-        username = self.instance.config["username"]
-        return (username in message["_hubs"])
+        hub_name = self.instance.hub.name
+        return (hub_name in message["_hubs"])

From 0f8c1d21e51e0338a10352df69cfdf57bab272d6 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:41:17 +0000
Subject: [PATCH 879/1001] Add a timeout to the request call in some widgets


---

diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 1c37299..ae09257 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -1,5 +1,8 @@
 from __future__ import unicode_literals
 
+import logging
+import json
+
 import requests
 import pkgwat.api
 
@@ -8,6 +11,9 @@ from hubs.widgets.base import Widget, WidgetView
 from hubs.widgets.caching import CachedFunction, cache
 
 
+log = logging.getLogger('hubs.widgets')
+
+
 PKGDB_URL = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
 
 
@@ -102,8 +108,20 @@ class GetIssues(CachedFunction):
         # request is waaaay too long to be run on each incoming bug message.
         def get_owned():
             url = "/".join([PKGDB_URL, username])
-            response = requests.get(url)
-            data = response.json()
+            try:
+                response = requests.get(url, timeout=5)
+            except (requests.exceptions.ConnectionError,
+                    requests.exceptions.Timeout):
+                log.warning("Could not get the list of owned packages for %s",
+                            username)
+                return []
+            try:
+                data = response.json()
+            except json.decoder.JSONDecodeError:
+                log.warning(
+                    "Invalid JSON response getting the list of packages "
+                    "owned by %s: %s", username, response.text)
+                return []
             owned = data['point of contact'] + data['co-maintained']
             return [p['name'] for p in owned]
         owned_cache_key = ":".join(["owned_packages", username])
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 70f545e..3e5ab7c 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -57,11 +57,14 @@ class GetStats(CachedFunction):
         username = self.instance.config["username"]
         url = "https://apps.fedoraproject.org/datagrepper/raw?user={username}"
         url = url.format(username=username)
-        response = requests.get(url)
         try:
+            response = requests.get(url, timeout=5)
             fedmsgs = response.json()['total']
-        except json.decoder.JSONDecodeError:
-            fedmsgs = 0
+        except (requests.exceptions.Timeout, json.decoder.JSONDecodeError):
+            fedmsgs = None
+            fedmsgs_text = "?"
+        else:
+            fedmsgs_text = commas(fedmsgs)
         sub_list = []
         for assoc in self.instance.hub.associations:
             if assoc.user:
@@ -69,7 +72,7 @@ class GetStats(CachedFunction):
         subscribers = [u.username for u in self.instance.hub.subscribers]
         return dict(
             fedmsgs=fedmsgs,
-            fedmsgs_text=commas(fedmsgs),
+            fedmsgs_text=fedmsgs_text,
             subscribers=subscribers,
             subscribed_to=sub_list,
             subscribers_text=commas(len(subscribers)),
@@ -78,5 +81,4 @@ class GetStats(CachedFunction):
 
     def should_invalidate(self, message):
         usernames = fedmsg.meta.msg2usernames(message, **fedmsg_config)
-        username = self.instance.config['username']
-        return username in usernames
+        return (self.instance.config['username'] in usernames)

From b3f662945a0a9519735565a862ba4f75eb820b42 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 21 2017 13:41:17 +0000
Subject: [PATCH 880/1001] Setup SSE as a global element used to reload widgets


---

diff --git a/hubs/default_config.py b/hubs/default_config.py
index 72cda31..917840b 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -11,7 +11,10 @@ PROMOTED_GROUPS = [
 
 HUB_OF_THE_MONTH = 'commops'
 
-SSE_URL = 'http://localhost:8080/user/'
+SSE_URL = {
+    "port": "8080",
+    "path": "/sse",
+}
 PLUS_PLUS_URL = 'http://localhost:5001/user/'
 PLUS_PLUS_TOKEN = 'thisismytoken'
 
diff --git a/hubs/static/client/app/components/feed/ItemsGetter.jsx b/hubs/static/client/app/components/feed/ItemsGetter.jsx
index 16d87de..bfc51a8 100644
--- a/hubs/static/client/app/components/feed/ItemsGetter.jsx
+++ b/hubs/static/client/app/components/feed/ItemsGetter.jsx
@@ -9,68 +9,71 @@ export default class ItemsGetter extends React.Component {
       sseError: false,
       loading: false,
     };
-    this.source = null;
-    this.setupSource = this.setupSource.bind(this);
-    this.handleEventError = this.handleEventError.bind(this);
-    this.loadExistingFromServer = this.loadExistingFromServer.bind(this);
+    this.sseSource = null;
+    this.setupSSESource = this.setupSSESource.bind(this);
+    this.handleSSEEvent = this.handleSSEEvent.bind(this);
+    this.handleSSEEventError = this.handleSSEEventError.bind(this);
+    this.loadFromServer = this.loadFromServer.bind(this);
   }
 
   componentDidMount() {
-    this.loadExistingFromServer();
+    this.setupSSESource();
+    this.loadFromServer();
   }
 
   componentWillUnmount() {
     this.serverRequest.abort();
-    if (this.source !== null) {
-      this.source.removeEventListener('error', this.handleEventError);
-      this.source.close();
+    if (this.sseSource) {
+      this.sseSource.removeEventListener(
+        this.props.sseEventName, this.this.props.handleSSEEvent);
+      this.sseSource.removeEventListener('error', this.handleSSEEventError);
     }
   }
 
-  componentDidUpdate(prevProps, prevState) {
-    if (this.props.sseActive && !this.source) {
-      // Only setup the source after the initial loading, or new elements may
-      // be overwritten by the call to this.props.handleInitialData().
-      this.setupSource();
-    }
-  }
-
-  setupSource() {
-    if (!this.props.urls.sse) {
+  setupSSESource() {
+    //if (!this.props.sseEventName || !this.props.handleSSEEvent) {
+    if (!this.props.sse.eventName || !this.props.sse.shouldReload) {
       // Auto-update is disabled.
       return;
     }
 
-    if (!window.EventSource) {
-      this.setState({
-        sseError: ("Cannot auto-update the feed, you will have to refresh "
-                  +"the page manually to see new elements.")
-      });
+    this.sseSource = document.sseSource;
+    if (!this.sseSource || this.sseSource.readyState === EventSource.CLOSED) {
+      this.handleSSEEventError();
       return;
     }
 
-    this.source = new EventSource(this.props.urls.sse);
-    this.source.addEventListener('error', this.handleEventError);
-    this.source.onmessage = (resp) => {
-      this.props.handleMessage(JSON.parse(resp.data));
-    };
+    this.sseSource.addEventListener('error', this.handleSSEEventError);
+    this.sseSource.addEventListener(
+      this.props.sse.eventName, this.handleSSEEvent);
   }
 
-  handleEventError() {
+  handleSSEEvent(e) {
+    if (this.props.sse.shouldReload(e.data)) {
+      this.loadFromServer();
+    }
+  }
+
+  handleSSEEventError() {
     this.setState({
-      sseError: "There was an error retrieving the new elements."
+      sseError: ("Cannot auto-update the feed, you will have to refresh "
+                +"the page manually to see new elements.")
     });
   }
 
-  loadExistingFromServer() {
+  loadFromServer() {
     this.setState({loading: true});
+    if (this.serverRequest &&
+        this.serverRequest.readyState !== XMLHttpRequest.DONE) {
+      this.serverRequest.abort();
+    }
     this.serverRequest = $.ajax({
-      url: this.props.urls.content,
+      url: this.props.url,
       method: 'GET',
       dataType: 'json',
       cache: false,
       success: (data, textStatus, jqXHR) => {
-        this.props.handleInitialData(data.data);
+        this.props.handleData(data.data);
       },
       error: (xhr, status, err) => {
         console.error(status, err.toString());
diff --git a/hubs/static/client/app/components/feed/__tests__/Feed.test.js b/hubs/static/client/app/components/feed/__tests__/Feed.test.js
index d1cdf24..9f2e9be 100644
--- a/hubs/static/client/app/components/feed/__tests__/Feed.test.js
+++ b/hubs/static/client/app/components/feed/__tests__/Feed.test.js
@@ -23,7 +23,7 @@ describe('Feed', () => {
 
   it('should create the children', () => {
     const component = TestUtils.renderIntoDocument(
-      <Feed items={items} messageLimit={100} />
+      <Feed items={items} />
     );
     const node = ReactDOM.findDOMNode(component);
     expect(Panel.mock.calls.length).toEqual(3);
diff --git a/hubs/static/client/app/core/Streams.jsx b/hubs/static/client/app/core/Streams.jsx
index 144fab7..a681951 100644
--- a/hubs/static/client/app/core/Streams.jsx
+++ b/hubs/static/client/app/core/Streams.jsx
@@ -16,35 +16,21 @@ export default class Streams extends React.Component {
     this.state = {
       notifItems: [],
       savedItems: [],
-      sseActive: false,
     };
-    this.handleInitialData = this.handleInitialData.bind(this);
-    this.handleInitialSavedData = this.handleInitialSavedData.bind(this);
-    this.handleMessage = this.handleMessage.bind(this);
+    this.handleStreamData = this.handleStreamData.bind(this);
+    this.handleSavedData = this.handleSavedData.bind(this);
     this.handleSave = this.handleSave.bind(this);
     this.handleUnsave = this.handleUnsave.bind(this);
   }
 
-  handleInitialData(data) {
-    // Only activate SSE after the initial loading, or new elements may
-    // be overwritten.
-    this.setState({
-      notifItems: data,
-      sseActive: true,
-    });
+  handleStreamData(data) {
+    this.setState({notifItems: data});
   }
 
-  handleInitialSavedData(data) {
+  handleSavedData(data) {
     this.setState({savedItems: data});
   }
 
-  handleMessage(msg) {
-    var items = this.state.notifItems;
-    items.unshift(msg);
-    items = items.slice(0, this.props.messageLimit);
-    this.setState({notifItems: items});
-  }
-
   handleSave(item) {
     if (!this.props.urls.saved) { return; }
     const payload = {
@@ -103,14 +89,16 @@ export default class Streams extends React.Component {
       <IntlProvider locale={navigator.language}>
         <TabSet tabListClass="mb-3">
           <FeedPanel
-            hub={this.props.hub}
+            username={this.props.username}
             tabTitle="My Stream"
             >
             <ItemsGetter
-              sseActive={this.state.sseActive}
-              urls={this.props.urls}
-              handleMessage={this.handleMessage}
-              handleInitialData={this.handleInitialData}
+              url={this.props.urls.content}
+              sse={{
+                eventName: "hubs:new-notification",
+                shouldReload: (username) => (username === this.props.username),
+              }}
+              handleData={this.handleStreamData}
               >
               <Feed
                 items={notifs}
@@ -120,7 +108,7 @@ export default class Streams extends React.Component {
             </ItemsGetter>
           </FeedPanel>
           <FeedPanel
-            hub={this.props.hub}
+            username={this.props.username}
             tabTitle="My Actions"
             >
             <Feed
@@ -128,12 +116,12 @@ export default class Streams extends React.Component {
               />
           </FeedPanel>
           <FeedPanel
-            hub={this.props.hub}
+            username={this.props.username}
             tabTitle="Saved Notifications"
             >
             <ItemsGetter
-              urls={{content: this.props.urls.saved}}
-              handleInitialData={this.handleInitialSavedData}
+              url={this.props.urls.saved}
+              handleData={this.handleSavedData}
               >
               <Feed
                 items={this.state.savedItems}
@@ -151,7 +139,7 @@ export default class Streams extends React.Component {
 class FeedPanel extends React.Component {
 
   render() {
-    const filters_url = `https://apps.fedoraproject.org/notifications/${this.props.hub}.id.fedoraproject.org/`;
+    const filters_url = `https://apps.fedoraproject.org/notifications/${this.props.username}.id.fedoraproject.org/`;
 
     return (
       <div>
diff --git a/hubs/static/client/app/widgets/feed/Widget.jsx b/hubs/static/client/app/widgets/feed/Widget.jsx
index 38a006d..ded612e 100644
--- a/hubs/static/client/app/widgets/feed/Widget.jsx
+++ b/hubs/static/client/app/widgets/feed/Widget.jsx
@@ -9,95 +9,26 @@ export default class Widget extends React.Component {
     super(props);
     this.state = {
       items: [],
-      sseActive: false,
     };
-    this.handleInitialData = this.handleInitialData.bind(this);
-    this.handleMessage = this.handleMessage.bind(this);
-    this.handleSave = this.handleSave.bind(this);
-    this.handleUnsave = this.handleUnsave.bind(this);
+    this.handleServerData = this.handleServerData.bind(this);
   }
 
-  handleInitialData(data) {
-    // Only activate SSE after the initial loading, or new elements may
-    // be overwritten.
-    this.setState({
-      items: data,
-      sseActive: true,
-    });
-  }
-
-  handleMessage(msg) {
-    if (this.state.items.length >= this.props.messageLimit) {
-      this.state.items.pop();
-    }
-    this.state.items.unshift(msg);
-    this.setState({items: this.state.items});
-  }
-
-  handleSave(item) {
-    if (!this.props.urls.save) { return; }
-    const payload = {
-      link: item.link,
-      markup: item.markup,
-      secondary_icon: item.secondary_icon,
-      dom_id: item.dom_id,
-    };
-    $.ajax({
-      type: 'POST',
-      url: this.props.urls.save,
-      data: JSON.stringify(payload),
-      contentType: 'application/json',
-      success: () => {
-        this.setState((prevState, props) => {
-          var items = prevState.items.map((currentItem) => {
-            if (currentItem.dom_id === item.dom_id) {
-              currentItem.saved = true;
-            }
-            return currentItem;
-          })
-          return {items};
-        });
-      },
-    });
-  }
-
-  handleUnsave(item) {
-    if (!this.props.urls.save) { return; }
-    var updateItemState = (item) => {
-      this.setState((prevState, props) => {
-        var items = prevState.items.map((currentItem) => {
-          if (currentItem.dom_id === item.dom_id) {
-            currentItem.saved = false;
-          }
-          return currentItem;
-        });
-        return {items};
-      });
-    };
-    if (item.idx) {
-      // Already saved
-      $.ajax({
-        type: 'DELETE',
-        url: `${this.props.urls.save}${item.idx}/`,
-        success: () => { updateItemState(item) },
-      });
-    } else {
-      updateItemState(item);
-    }
+  handleServerData(data) {
+    this.setState({items: data});
   }
 
   render() {
     return (
       <ItemsGetter
-        sseActive={this.state.sseActive}
-        urls={this.props.urls}
-        handleMessage={this.handleMessage}
-        handleInitialData={this.handleInitialData}
+        url={this.props.url}
+        sse={{
+          eventName: "hubs:widget-updated",
+          shouldReload: (idx) => (idx === this.props.widgetIdx),
+        }}
+        handleData={this.handleServerData}
         >
         <Feed
           items={this.state.items}
-          handleSave={this.handleSave}
-          handleUnsave={this.handleUnsave}
           />
       </ItemsGetter>
     );
diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
index 3474786..1f33870 100644
--- a/hubs/static/js/utils.js
+++ b/hubs/static/js/utils.js
@@ -32,3 +32,30 @@ function setup_widgets() {
         });
     });
 }
+
+function setup_sse(url) {
+    if (!url || !window.EventSource) {
+      // Auto-update is disabled.
+      return;
+    }
+    var sseSource = new EventSource(url);
+    sseSource.addEventListener("hubs:widget-updated", function(e) {
+        var widget = $("#widget-" + e.data);
+        if (widget.find("div.card[data-disable-autoreload]").length !== 0) { return; }
+        $.ajax({
+            url: widget.attr("data-url"),
+            dataType: 'html',
+            success: function(html) {
+                widget.css("opacity", "0.5");
+                widget.html(html);
+                widget.animate({opacity: 1}, 200);
+            },
+            error: function() {
+                console.log('error updating the widget');
+                console.trace();
+            },
+        });
+    });
+    // Make it accessible by other components on the page.
+    document.sseSource = sseSource;
+  }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index c0f1a84..d39d1ca 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -323,6 +323,7 @@ $(function() {
   visit_counter()
 
   setup_widgets();
+  setup_sse({{ sse_url | tojson }});
   setup_edit_btns();
   {% if hub.allows(g.auth.user, "config") %}
   setup_settings();
diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
index cae069f..4292f6d 100644
--- a/hubs/templates/stream.html
+++ b/hubs/templates/stream.html
@@ -29,14 +29,13 @@
 {{ super() }}
 <script>
  $(function() {
-    setup_widgets();
+    setup_sse({{ sse_url | tojson }});
     const StreamsElement = React.createElement(Hubs.Streams, {
-        hub: {{ hub.name | tojson }},
+        username: {{ g.auth.nickname | tojson }},
         urls: {
             saved: {{ url_for("saved_notifs") | tojson }},
             content: {{ url_for("stream_existing") | tojson }},
         },
-        messageLimit: 100,
     });
     ReactDOM.render(StreamsElement, document.getElementById('streams'));
  });
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index c060b42..a57c0c1 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -202,3 +202,19 @@ def captured_templates(app):
         yield recorded
     finally:
         template_rendered.disconnect(record, app)
+
+
+@contextmanager
+def app_config(app, config):
+    """Context manager to change the application's configuration
+
+    Args:
+        app: The application.
+        config: The configuration to set temporarily.
+    """
+    original_config = app.config.__dict__
+    app.config.update(config)
+    try:
+        yield
+    finally:
+        app.config.__dict__ = original_config
diff --git a/hubs/tests/test_view_utils.py b/hubs/tests/test_view_utils.py
index 64b6aee..6a6d116 100644
--- a/hubs/tests/test_view_utils.py
+++ b/hubs/tests/test_view_utils.py
@@ -1,9 +1,11 @@
 from __future__ import unicode_literals
 
+import flask
+
 import hubs.models
 from hubs.app import app
-from hubs.tests import APPTest, FakeAuthorization, auth_set
-from hubs.utils.views import get_visible_widgets
+from hubs.tests import APPTest, FakeAuthorization, auth_set, app_config
+from hubs.utils.views import get_visible_widgets, get_sse_url
 
 
 class ViewUtilsTest(APPTest):
@@ -84,3 +86,31 @@ class ViewUtilsTest(APPTest):
             widgets = get_visible_widgets(hub)
         self.assertNotEqual(len(widgets["left"]), 0)
         self.assertNotEqual(len(widgets["right"]), 0)
+
+    def test_sse_url(self):
+        with app.test_request_context():
+            self.assertEqual(get_sse_url(), "http://localhost:8080/sse")
+
+        with app.test_request_context(base_url='http://hubs.example.com/'):
+            self.assertEqual(get_sse_url(), "http://hubs.example.com:8080/sse")
+
+        with app.test_request_context(base_url='http://example.com/hubs'):
+            self.assertEqual(flask.url_for("index"), "/hubs/")  # test validity
+            self.assertEqual(get_sse_url(), "http://example.com:8080/sse")
+
+        with app.test_request_context(base_url='http://hubs.example.com/'):
+            with app_config(app, {
+                    "SSE_URL": {"host": "hubs-sse.example.com"}
+                    }):
+                self.assertEqual(get_sse_url(), "http://hubs-sse.example.com/")
+
+        with app.test_request_context(base_url='http://hubs.example.com/'):
+            with app_config(app, {
+                    "SSE_URL": {"host": "hubs-sse.example.com",
+                                "port": 8080}
+                    }):
+                self.assertEqual(get_sse_url(), "http://hubs-sse.example.com:8080/")
+
+        with app.test_request_context(base_url='http://localhost/hubs'):
+            with app_config(app, {"SSE_URL": {"host": "example.com"}}):
+                self.assertEqual(get_sse_url(), "http://example.com/")
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
index 2ceb399..4a4c63a 100644
--- a/hubs/utils/views.py
+++ b/hubs/utils/views.py
@@ -286,3 +286,24 @@ class RequestValidator(object):
         if errors:
             raise ValueError(errors)
         return values
+
+
+def get_sse_url():
+    """Build the SSE URL."""
+    # Avoid circular import with widgets.
+    from hubs.app import app
+    # TODO: have a page (hub, user stream, ...) specific SSE URL to only
+    # subscribe to relevant messages.
+    base_url = flask.url_for("index", _external=True)
+    base_url = urlparse.urlsplit(base_url)
+    conf = app.config["SSE_URL"]
+    host = conf.get("host") or base_url.hostname
+    port = conf.get("port") or base_url.port
+    netloc = host
+    if port:
+        netloc = "{}:{}".format(host, port)
+    path = urlparse.urljoin(base_url.path, conf.get("path", "/"))
+    return urlparse.urlunsplit([
+        conf.get("scheme") or base_url.scheme,
+        netloc, path, "", "",
+    ])
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index adcf65e..5496503 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -6,8 +6,8 @@ import hubs.models
 
 from hubs.app import app
 from hubs.utils.views import (
-    get_hub, get_visible_widgets, login_required, RequestValidator,
-    require_hub_access,
+    get_hub, get_sse_url, get_visible_widgets, login_required,
+    RequestValidator, require_hub_access,
     )
 
 
@@ -18,7 +18,12 @@ def hub(name):
     hub = get_hub(name, load_config=True)
     widgets = get_visible_widgets(hub)
     return flask.render_template(
-        'hubs.html', hub=hub, widgets=widgets, edit=False)
+        'hubs.html',
+        hub=hub,
+        widgets=widgets,
+        edit=False,
+        sse_url=get_sse_url(),
+        )
 
 
 @app.route('/<name>/json/')
diff --git a/hubs/views/user.py b/hubs/views/user.py
index 0306821..a5cc00d 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -7,7 +7,8 @@ import hubs.feed
 
 from hubs.app import app
 from hubs.utils.views import (
-    login_required, get_hub, get_visible_widgets, require_hub_access,
+    login_required, get_hub, get_sse_url, get_visible_widgets,
+    require_hub_access,
     )
 
 
@@ -22,6 +23,7 @@ def stream():
         'stream.html',
         hub=hub,
         widgets=widgets,
+        sse_url=get_sse_url(),
     )
 
 
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index 730150d..eb0db3c 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -4,6 +4,7 @@ from __future__ import unicode_literals, absolute_import
 import logging
 
 import hubs.feed
+from hubs.views.utils import get_sse_url
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
@@ -36,13 +37,10 @@ class BaseView(WidgetView):
     template_name = "feed.html"
 
     def get_context(self, instance, *args, **kwargs):
-        # Avoid circular import
-        from hubs.app import app
-        sse_url = app.config['SSE_URL'] + username
         return dict(
             title=self.widget.label,
-            message_limit=instance.config["message_limit"],
-            sse_url=sse_url,
+            sse_url=get_sse_url(),
+            disable_autoreload=True,
             )
 
 
diff --git a/hubs/widgets/feed/templates/feed.html b/hubs/widgets/feed/templates/feed.html
index 87fbafa..f687dd4 100644
--- a/hubs/widgets/feed/templates/feed.html
+++ b/hubs/widgets/feed/templates/feed.html
@@ -9,11 +9,8 @@
 <script>
 (function() {
     const FeedElement = React.createElement(Feed.Widget, {
-        urls: {
-            content: {{ url_for("feed_existing", hub=widget_instance.hub.name, idx=widget_instance.idx) | tojson }},
-            sse: {{ sse_url|tojson }},
-        },
-        messageLimit: {{ message_limit }}
+        url: {{ url_for("feed_existing", hub=widget_instance.hub.name, idx=widget_instance.idx) | tojson }},
+        widgetIdx: {{ widget_instance.idx | tojson }}
     });
     ReactDOM.render(FeedElement, document.getElementById('feed-' + {{ widget_instance.idx | tojson }}));
 })();
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index eaa46ac..ada528b 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -30,6 +30,7 @@ class BaseView(WidgetView):
         return dict(
             hubs=instance.config.get("hubs", []),
             title=self.widget.label,
+            disable_autoreload=True,
             )
 
 
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index de62d35..fa39d4e 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -1,4 +1,6 @@
-<div class="card {{ panel_css_class }} widget-{{ widget.name }}">
+<div class="card {{ panel_css_class }} widget-{{ widget.name }}"
+     {% if disable_autoreload %}data-disable-autoreload="true"{% endif %}
+    >
   <div class="widget-buttons">
     <!-- the AGPLv3 wrapper puts the source url in all responses -->
     <a href="{{ url_for('widget_source', name=widget.name) }}"><span><i class="fa fa-eye" aria-hidden="true"></i></span></a>

From 5f3168c509e091e05c5f9f3145b6de1e78ef5a4c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 22 2017 18:23:01 +0000
Subject: [PATCH 881/1001] Create the SSE server with Twisted


---

diff --git a/Vagrantfile.example b/Vagrantfile.example
index 5caa591..5310d5a 100644
--- a/Vagrantfile.example
+++ b/Vagrantfile.example
@@ -8,6 +8,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
 
  # Forward traffic on the host to the development server on the guest
  config.vm.network "forwarded_port", guest: 5000, host: 5000
+ config.vm.network "forwarded_port", guest: 8080, host: 8080
 
  # Comment out if you don't want Vagrant to add and remove entries from /etc/hosts for each VM.
  # requires the vagrant-hostmanager plugin to be installed
diff --git a/ansible/roles/hubs/files/nginx_proxy_params b/ansible/roles/hubs/files/nginx_proxy_params
new file mode 100644
index 0000000..f4ebcd7
--- /dev/null
+++ b/ansible/roles/hubs/files/nginx_proxy_params
@@ -0,0 +1,6 @@
+proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+proxy_set_header X-Forwarded-Proto $scheme;
+proxy_set_header Host $http_host;
+# we don't want nginx trying to do something clever with
+# redirects, we set the Host: header above already.
+proxy_redirect off;
diff --git a/ansible/roles/hubs/handlers/main.yml b/ansible/roles/hubs/handlers/main.yml
index cd2d639..e87c345 100644
--- a/ansible/roles/hubs/handlers/main.yml
+++ b/ansible/roles/hubs/handlers/main.yml
@@ -13,5 +13,9 @@
   service: name=hubs-worker@* state=restarted
   listen: "hubs configuration change"
 
+- name: restart hubs SSE server
+  service: name=hubs-sse state=restarted
+  listen: "hubs configuration change"
+
 # Webserver
 - include: webserver.yml
diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index 02f14fc..8e11108 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -175,6 +175,7 @@
   with_items:
     - hubs-triage@
     - hubs-worker@
+    - hubs-sse
     - hubs-fedmsg-hub
 
 - name: Start and enable the services
@@ -185,6 +186,7 @@
     - hubs-triage@2
     - hubs-worker@1
     - hubs-worker@2
+    - hubs-sse
     - hubs-fedmsg-hub
 
 
diff --git a/ansible/roles/hubs/tasks/webserver.yml b/ansible/roles/hubs/tasks/webserver.yml
index 234089f..37d70f0 100644
--- a/ansible/roles/hubs/tasks/webserver.yml
+++ b/ansible/roles/hubs/tasks/webserver.yml
@@ -5,7 +5,7 @@
   with_items:
     - python-gunicorn
     - nginx
-    - make
+    - libsemanage-python
 
 
 - name: Generate SSL certificate and key
@@ -29,7 +29,7 @@
     - restart hubs webapp
 
 
-- name: Nginx configuration
+- name: Nginx configuration for hubs
   template:
     src: nginx.conf
     dest: /etc/nginx/conf.d/hubs.conf
@@ -47,6 +47,18 @@
   notify:
     - restart nginx
 
+
+- name: Nginx proxy configuration
+  copy:
+    src: "{{ item }}"
+    dest: /etc/nginx/proxy_params
+  with_first_found:
+    - nginx_proxy_params.{{ ansible_hostname }}
+    - nginx_proxy_params
+  notify:
+    - restart nginx
+
+
 - name: Allow network connection for Nginx
   seboolean:
     name: httpd_can_network_connect
diff --git a/ansible/roles/hubs/templates/hubs-sse.service b/ansible/roles/hubs/templates/hubs-sse.service
new file mode 100644
index 0000000..5ff68a2
--- /dev/null
+++ b/ansible/roles/hubs/templates/hubs-sse.service
@@ -0,0 +1,18 @@
+[Unit]
+Description=fedora-hubs SSE server
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart= \
+    {{ hubs_venv_dir }}/bin/python \
+    /usr/bin/twistd -l - --pidfile= \
+    -ny {{ hubs_code_dir }}/hubs/backend/sse_server.tac
+Environment=HUBS_CONFIG={{ hubs_conf_dir }}/hubs_config.py
+Type=simple
+User={{ main_user }}
+Group={{ main_user }}
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/hubs/templates/hubs_config b/ansible/roles/hubs/templates/hubs_config
index fbaf61d..f901915 100644
--- a/ansible/roles/hubs/templates/hubs_config
+++ b/ansible/roles/hubs/templates/hubs_config
@@ -9,3 +9,12 @@ OIDC_ID_TOKEN_COOKIE_SECURE = False
 
 OIDC_CLIENT_SECRETS = "{{ hubs_conf_dir }}/client_secrets.json"
 OIDC_OPENID_REALM = "{{ hubs_url }}/oidc_callback"
+
+SSE_URL = {
+    # "host": "sse.example.com",
+    {% if hubs_dev_mode %}
+    "port": "8080",
+    {% else %}
+    "path": "/sse",
+    {% endif %}
+}
diff --git a/ansible/roles/hubs/templates/nginx.conf b/ansible/roles/hubs/templates/nginx.conf
index b969aaa..aa34310 100644
--- a/ansible/roles/hubs/templates/nginx.conf
+++ b/ansible/roles/hubs/templates/nginx.conf
@@ -9,6 +9,12 @@ upstream hubs {
     server 127.0.0.1:8000 fail_timeout=0;
 }
 
+upstream hubs-sse {
+    # SSE server (twisted-based)
+    server 127.0.0.1:8080 fail_timeout=0;
+}
+
+
 # Redirect cleartext traffic to HTTPS
 server {
     listen 80;
@@ -36,16 +42,21 @@ server {
       try_files $uri @proxy_to_app;
     }
 
-    location @proxy_to_app {
-      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-      # enable this if and only if you use HTTPS
-      proxy_set_header X-Forwarded-Proto https;
-      proxy_set_header Host $http_host;
-      # we don't want nginx trying to do something clever with
-      # redirects, we set the Host: header above already.
-      proxy_redirect off;
+    location /sse/ {
+      include proxy_params;
+      proxy_pass http://hubs-sse/;
       # Allow long-running queries (SSE):
       proxy_buffering off;
+      proxy_http_version 1.1;
+      proxy_set_header Connection "";
+      proxy_cache off;
+      chunked_transfer_encoding off;
+      keepalive_timeout 0;
+      proxy_read_timeout 30m;
+    }
+
+    location @proxy_to_app {
+      include proxy_params;
       proxy_pass http://hubs;
     }
 
diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst
index 874a7b1..1a81f72 100644
--- a/docs/dev-guide.rst
+++ b/docs/dev-guide.rst
@@ -376,7 +376,7 @@ Some discussion on how to do pushed updates to web clients:
   memcached cache when a fedmsg message comes in and once in javascript to tell
   the client to reload and redraw a oprtion of itself when a fedmsg comes in
   over the websocket firehose.
-- Instead, let's give fedora-hubs its own *widget-specific* `EventSource
+- Instead, let's give fedora-hubs its own *page-specific* `EventSource
   <https://developer.mozilla.org/en-US/docs/Web/API/EventSource>`_ server that
   we tie in to the server-side cache-invalidation backend code.  I.e., when a
   message comes into the backend, it runs all the cache invalidation checkers
@@ -384,12 +384,18 @@ Some discussion on how to do pushed updates to web clients:
   we can emit events over EventSource to tell only *those* widgets on any
   connected clients to redraw themselves.
 
-As an aside, it became clear to me when making the diagram in the next section
-that, if we use handlebars.js and get rid of the server-side template
-rendering, then 1) the data returned by AJAX requests at page load and 2) the
-data pushed by the EventSource server can be *the exact same data*.  It will
-simplify and streamline the responsibilities of the pieces if the backend is
-worried *only* about these per-widget JSON responses.
+Since the number of concurrent connections to a page is limited by the browser,
+we can't have one EventSource connection per widget, but we can have an
+EventSource connection per page, which will dispatch the index of the widget to
+redraw in its ``data`` field.
+
+The EventSource message will only tell the browser to redraw the widget, it
+will not carry the changed data itself.  Otherwise, we would have to check
+authentication and authorizations on the SSE server itself, which means
+connecting to the database, and this must be done using non-blocking APIs so we
+can't reuse our models.  Just sending a change notice makes it much easier, all
+this control code can stay in the webapp itself.
+
 
 A picture is worth...
 ---------------------
@@ -407,8 +413,9 @@ happens when a user requsts their main hubs page*:
 
 - The user requests the page and the wsgi app responds with some barebones HTML
   and enough javascript to get off the ground.
-- The user's browser runs javascript that *subscribes* it to the EventSource server.
-- The user's browser runs that javascript, which requests data for each of the
+- The user's browser runs javascript that *subscribes* it to the EventSource
+  server.
+- The user's browser runs javascript that requests data for each of the
   widgets defined on the page.
 - The wsgi app receives those requests and checks to see if the data for any of
   them is *cached in memcached*.  If it is, then it is returned.  If not, then
@@ -416,7 +423,8 @@ happens when a user requsts their main hubs page*:
   response ready.  It is stuffed in memcached for later access and returned.
 - The client renders widgets as the data for each of its requests comes back.
 
-Later, what happens when a *trac ticket* is filed that should show up in some widget on their page?
+Later, what happens when a *trac ticket* is filed that should show up in some
+widget on their page?
 
 - The ticket is updated on fedorahosted.org and a fedmsg message is fired.
 - That is received by the hubs backend, which looks up *all* the cached
@@ -424,11 +432,11 @@ Later, what happens when a *trac ticket* is filed that should show up in some wi
   mizmo's page, threebean's page, and on the design hub that should all get
   fresh data because of this change).
 - All of those widgets get their cached data nuked.
-- All of those widgets get their cached data rebuilt by calling ``data(...)`` on them.
+- All of those widgets get their cached data rebuilt by calling ``data(...)``
+  on them.
 - An EventSource event is fired off for any listening clients that *new data is
-  available for widgets X, Y, and Z*.  The data is included in the EventSource
-  payload so the clients can immediately redraw without bothering to re-query
-  the wsgi app.
+  available for widgets X, Y, and Z*.
+- The clients re-query the wsgi app for those widgets' content and redraw them.
 
 What happens when the user is viewing the *design team* hub and
 simultaneously, an admin *changes the configuration of a widget on that page*?
@@ -444,5 +452,5 @@ simultaneously, an admin *changes the configuration of a widget on that page*?
 - ...looks up the cache key for *widget X with the new configuration* and
   builds the cached data by calling ``data(...)`` on the widget.
 - An EventSource event is fired off which gets recieved by everyone looking at
-  the *design team hub*.  The widget on their pages gets redrawn with data from
-  the EventSource event.
+  the *design team hub*.  The widget on their pages gets redrawn after
+  requesting the new data from the wsgi app.
diff --git a/docs/diagram.txt b/docs/diagram.txt
index a0d18b4..3c5fed5 100644
--- a/docs/diagram.txt
+++ b/docs/diagram.txt
@@ -9,7 +9,7 @@
                      |  |               |   +--------------+                                                        | js activity graphs
                      |  +---------------+                                                                           |
                      |                                                                                              V
-                     |                                                   push updated JSON                +-------------------------+
+                     |                                                   push redraw notice               +-------------------------+
                      |                                                   to clients asap                  | web client              |
                      |                                          +---------------------------------------->| (built from HTML and JS |
                      |                                          |                                         | served by the wsgi app) |
diff --git a/hubs/backend/sse_server.py b/hubs/backend/sse_server.py
new file mode 100644
index 0000000..781ddb2
--- /dev/null
+++ b/hubs/backend/sse_server.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+from __future__ import unicode_literals, print_function
+
+import json
+
+import txredisapi as redis
+
+from twisted.application import service
+from twisted.web import server, resource
+from twisted.internet import reactor, defer
+from twisted.logger import (
+    Logger, globalLogBeginner, ILogObserver, formatEvent)
+from zope.interface import provider
+
+import hubs.app
+
+
+log = Logger()
+fedmsg_config = hubs.app.fedmsg_config
+
+REDIS_CONF = {
+    'host': fedmsg_config.get('hubs.redis.host', 'localhost'),
+    'port': fedmsg_config.get('hubs.redis.port', 6379),
+    'dbid': fedmsg_config.get('hubs.redis.db', 0),
+    'password': fedmsg_config.get('hubs.redis.password', None),
+}
+
+
+class RetaskQueue(object):
+    """
+    Compatibility class with https://github.com/kushaldas/retask/ using the
+    txredisapi non-blocking API for Redis.
+    """
+
+    def __init__(self, name, connection=None):
+        self.conn = connection or redis.lazyConnection(**REDIS_CONF)
+        self.name = "retaskqueue-{}".format(name)
+
+    def wait(self, wait_time=0):
+        def format_result(msg):
+            task = json.loads(msg[1])
+            return json.loads(task["_data"])
+        d = self.conn.brpop(self.name, wait_time)
+        d.addCallback(format_result)
+        d.addErrback(self._error_handler)
+        return d
+
+    def length(self):
+        d = self.conn.llen(self.name)
+        d.addErrback(self._error_handler)
+        return d
+
+    def _error_handler(self, failure):
+        failure.trap(redis.ConnectionError)
+        log.debug("Lost connection to Redis, will attempt to reconnect "
+                  "in the background.")
+        return None
+
+    def disconnect(self):
+        return self.conn.disconnect()
+
+
+class Subscribe(resource.Resource):
+    """
+    Twisted web resource allowing clients to subscribe to Redis messages.
+
+    The Redis messages will be broadcasted to all clients using the broadcast()
+    method.
+    """
+
+    isLeaf = True
+
+    def __init__(self):
+        resource.Resource.__init__(self)
+        self.subscribers = {}
+        self.allow_origin = fedmsg_config.get('hubs.sse.allow-origin', '*')
+
+    def render_GET(self, request):
+        """
+        Handle GET requests to this endpoint. Requests should be to
+        ``/[user|hub]/<target>/``.
+        """
+        # If the request ended in a trailing / the final path section is ''.
+        # This allows the trailing / on /<type>/<target>/ to be optional.
+        if request.postpath[-1] == '':
+            request.postpath.pop()
+        if len(request.postpath) != 2:
+            response = resource.ErrorPage(
+                status=400, brief="Bad request", detail="Bad request.")
+            return response.render(request)
+        target = "/".join([p.decode("utf-8") for p in request.postpath])
+
+        request.setHeader('Content-Type', 'text/event-stream; charset=utf-8')
+        request.setHeader('Access-Control-Allow-Origin', self.allow_origin)
+        request.setHeader('X-Accel-Buffering', 'no')
+        request.write(b"")
+        request.notifyFinish().addBoth(self.request_closed, request, target)
+
+        if target not in self.subscribers:
+            self.subscribers[target] = []  # first request to this target.
+        log.debug("New subscriber: {req}", req=request)
+        self.subscribers[target].append(request)
+        log.debug("There is now {count} subscribers to {target}.",
+                  target=target, count=len(self.subscribers[target]))
+
+        return server.NOT_DONE_YET
+
+    def broadcast(self, target, event, data):
+        log.debug("Received {event} message to broadcast to {target}: {data}",
+                  target=target, event=event, data=data)
+        target_subscribers = self.subscribers.get(target, [])
+        if not target_subscribers:
+            return
+        log.debug("Broadcasting to {num} requests.",
+                  num=len(target_subscribers))
+        for request in target_subscribers:
+            if event:
+                request.write("event: {}\r\n".format(event).encode("utf-8"))
+            request.write("data: {}\r\n".format(data).encode("utf-8"))
+            # The last CRLF is required to dispatch the event to the client.
+            request.write(b"\r\n")
+
+    def request_closed(self, err, request, target):
+        log.debug("Removing subscriber {subscriber} from {target}.",
+                  subscriber=request, target=target)
+        self.subscribers[target].remove(request)
+        log.debug("There is now {count} subscribers to {target}.",
+                  target=target, count=len(self.subscribers[target]))
+
+
+class RedisClientService(service.Service):
+
+    def __init__(self, broadcaster):
+        self.broadcaster = broadcaster
+        self.queue = None
+        self._stopping = False
+
+    @defer.inlineCallbacks
+    def process(self):
+        """
+        Get the data from the Redis queue and broadcast it.
+        """
+
+        backlog = yield self.queue.length()
+        log.info("Starting Redis task dispatcher with a backlog of {num} "
+                 "messages.", num=backlog)
+        while True:
+            task = yield self.queue.wait()
+            if task is None:
+                if self._stopping:
+                    break
+                log.debug("No task received, or connection lost.")
+                continue
+            try:
+                task = json.loads(task)
+            except ValueError:
+                log.warning("Invalid task received: {task!r}", task=task)
+                continue
+            log.debug("Task received: {task!r}", task=task)
+            if "target" not in task or "data" not in task:
+                log.warning("Invalid task received: {task!r}", task=task)
+                continue
+            self.broadcaster.broadcast(
+                task["target"], task.get("event"), task["data"])
+
+    def startService(self):
+        queue_name = fedmsg_config['hubs.sse.redis-queue-name']
+        self.queue = RetaskQueue(queue_name)
+        return reactor.callLater(0, self.process)
+
+    def stopService(self):
+        self._stopping = True
+        return self.queue.disconnect()
+
+
+def main():
+    @provider(ILogObserver)
+    def printingObserver(event):
+        print(formatEvent(event))
+    globalLogBeginner.beginLoggingTo(
+        [printingObserver], redirectStandardIO=False)
+    sub = Subscribe()
+    site = server.Site(sub)
+    port = int(hubs.app.app.config.get("SSE_URL", {}).get("port", 8080))
+    reactor.listenTCP(port, site)
+    redisclient = RedisClientService(sub)
+    redisclient.startService()
+    reactor.run()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/hubs/backend/sse_server.tac b/hubs/backend/sse_server.tac
new file mode 100644
index 0000000..57dc41f
--- /dev/null
+++ b/hubs/backend/sse_server.tac
@@ -0,0 +1,39 @@
+# You can run this .tac file directly with:
+#    twistd -ny hubs/backend/sse_server.tac
+
+"""
+This is an example .tac file which starts a webserver on port 8080 and
+serves files from the current working directory.
+
+The important part of this, the part that makes it a .tac file, is
+the final root-level section, which sets up the object called 'application'
+which twistd will look for
+"""
+
+from __future__ import unicode_literals
+
+from twisted.application import service, internet
+from twisted.internet import reactor
+from twisted.web import server
+
+import hubs.app
+from hubs.backend.sse_server import Subscribe, RedisClientService
+
+
+sse_config = hubs.app.app.config.get("SSE_URL", {})
+WEB_PORT = int(sse_config.get("port", 8080))
+
+
+# this is the core part of any tac file, the creation of the root-level
+# application object
+application = service.Application("Hubs SSE Server")
+
+# Web server
+broadcaster = Subscribe()
+site = server.Site(broadcaster)
+web_service = internet.TCPServer(WEB_PORT, site)
+web_service.setServiceParent(application)
+
+# Redis client
+redis_service = RedisClientService(broadcaster)
+redis_service.setServiceParent(application)
diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index 16bcbd1..b4a2c82 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -49,7 +49,8 @@ def triage(msg):
             return
 
     # Handle user notifications.
-    if ".fmn.notification." in topic:  # XXX: use the proper topic pattern when it's chosen
+    # XXX: use the proper topic pattern when it's chosen
+    if ".fmn.notification." in topic:
         yield retask.task.Task(json.dumps({
             'type': 'notification',
             'msg': msg,
@@ -79,6 +80,7 @@ def triage(msg):
                 yield retask.task.Task(json.dumps({
                     'type': 'widget-cache',
                     'idx': widget.idx,
+                    'hub': widget.hub.name,
                     'fn_name': fn_name,
                     'msg_id': msg['msg_id'],
                 }))
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index 5e82bda..363025a 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -31,6 +31,7 @@ import logging
 import logging.config
 import sys
 
+import fedmsg.meta
 import retask.queue
 
 import hubs.app
@@ -51,7 +52,6 @@ def widget_cache_work(widget_idx, fn_name):
     log.info("! Rebuilding cache for %r:%r" % (widget, fn_name))
     # Invalidate the cache...
     fn_class(widget).rebuild()
-    # TODO -- fire off an EventSource notice that we updated stuff
 
 
 def handle_widget_cache(widget_idx, fn_name):
@@ -78,7 +78,7 @@ def main(args=None):
     log.info("Worker starting, connecting to retask queue %r." % name)
     queue = retask.queue.Queue(name)
     queue.connect()
-    sse_name = fedmsg_config['hubs.redis.sse-queue-name']
+    sse_name = fedmsg_config['hubs.sse.redis-queue-name']
     log.info("Worker starting, connecting to retask queue %r." % sse_name)
     sse_queue = retask.queue.Queue(sse_name)
     sse_queue.connect()
@@ -96,13 +96,15 @@ def main(args=None):
                 sse_task = {
                     "event": "hubs:widget-updated",
                     "data": item["idx"],
+                    "target": "hub/{}".format(item["hub"]),
                 }
             elif item_type == "notification":
                 hubs.feed.on_new_notification(item["msg"])
-                username = fedmsg.meta.msg2agent(msg)
+                username = fedmsg.meta.msg2agent(item["msg"])
                 sse_task = {
                     "event": "hubs:new-notification",
                     "data": username,
+                    "target": "user/{}".format(username),
                 }
             if sse_task is not None:
                 sse_queue.enqueue(retask.task.Task(json.dumps(sse_task)))
diff --git a/hubs/default_config.py b/hubs/default_config.py
index 917840b..ab47804 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -12,8 +12,9 @@ PROMOTED_GROUPS = [
 HUB_OF_THE_MONTH = 'commops'
 
 SSE_URL = {
+    # "host": "sse.example.com",
     "port": "8080",
-    "path": "/sse",
+    # "path": "/sse",
 }
 PLUS_PLUS_URL = 'http://localhost:5001/user/'
 PLUS_PLUS_TOKEN = 'thisismytoken'
diff --git a/hubs/default_fedmsg_config.py b/hubs/default_fedmsg_config.py
index 7cf088d..a7d1a3c 100644
--- a/hubs/default_fedmsg_config.py
+++ b/hubs/default_fedmsg_config.py
@@ -9,7 +9,7 @@ config = {
     # For communication between fedmsg-hub and the cache worker farm
     'hubs.redis.triage-queue-name': 'fedora-hubs-triage-queue',
     'hubs.redis.work-queue-name': 'fedora-hubs-work-queue',
-    'hubs.redis.sse-queue-name': 'fedora-hubs-sse-queue',
+    'hubs.sse.redis-queue-name': 'fedora-hubs-sse-queue',
 
     # Junk junk junk.. that we don't care about.  Drop it!
     'hubs.junk_suffixes': [
diff --git a/hubs/static/client/app/components/feed/ItemsGetter.jsx b/hubs/static/client/app/components/feed/ItemsGetter.jsx
index bfc51a8..75c50f9 100644
--- a/hubs/static/client/app/components/feed/ItemsGetter.jsx
+++ b/hubs/static/client/app/components/feed/ItemsGetter.jsx
@@ -33,6 +33,7 @@ export default class ItemsGetter extends React.Component {
   setupSSESource() {
     //if (!this.props.sseEventName || !this.props.handleSSEEvent) {
     if (!this.props.sse.eventName || !this.props.sse.shouldReload) {
+      console.log("SSE auto-update is disabled");
       // Auto-update is disabled.
       return;
     }
diff --git a/hubs/static/client/app/components/feed/Markup.jsx b/hubs/static/client/app/components/feed/Markup.jsx
index 16658eb..ad482e0 100644
--- a/hubs/static/client/app/components/feed/Markup.jsx
+++ b/hubs/static/client/app/components/feed/Markup.jsx
@@ -14,12 +14,14 @@ export default class Markup extends React.Component {
   }
 
   render() {
-    const timestamp = this.props.item.date_time ? (<TimeAgo date={this.props.item.date_time} />) : null;
+    const timestamp = this.props.item.end_time || this.props.item.timestamp;
 
     return (
       <div className="media-body align-self-center">
         <span dangerouslySetInnerHTML={this.createMarkup()}></span>
-        {timestamp}
+        <small className="text-muted float-right">
+          <TimeAgo date={timestamp * 1000} />
+        </small>
       </div>
     );
   }
diff --git a/hubs/static/client/app/widgets/feed/Widget.jsx b/hubs/static/client/app/widgets/feed/Widget.jsx
index ded612e..636daa2 100644
--- a/hubs/static/client/app/widgets/feed/Widget.jsx
+++ b/hubs/static/client/app/widgets/feed/Widget.jsx
@@ -23,7 +23,7 @@ export default class Widget extends React.Component {
         url={this.props.url}
         sse={{
           eventName: "hubs:widget-updated",
-          shouldReload: (idx) => (idx === this.props.widgetIdx),
+          shouldReload: (idx) => (parseInt(idx) === this.props.widgetIdx),
         }}
         handleData={this.handleServerData}
         >
diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
index 1f33870..2169c6b 100644
--- a/hubs/static/js/utils.js
+++ b/hubs/static/js/utils.js
@@ -41,6 +41,7 @@ function setup_sse(url) {
     var sseSource = new EventSource(url);
     sseSource.addEventListener("hubs:widget-updated", function(e) {
         var widget = $("#widget-" + e.data);
+        if (widget.length === 0) { return; }
         if (widget.find("div.card[data-disable-autoreload]").length !== 0) { return; }
         $.ajax({
             url: widget.attr("data-url"),
@@ -56,6 +57,16 @@ function setup_sse(url) {
             },
         });
     });
+    // On each message, switch the notification favicon to green for 15s.
+    sseSource.addEventListener("message", function(e) {
+        Notificon('#33ff00');  // green
+        setTimeout(function(){ Notificon(); }, 15000)
+    });
+    // On error, switch the notification favicon to red.
+    sseSource.addEventListener("error", function(e) {
+        Notificon('#eb361e');  // red
+        setTimeout(function(){ Notificon(); }, 15000)
+    });
     // Make it accessible by other components on the page.
     document.sseSource = sseSource;
   }
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index d39d1ca..611fae9 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -333,16 +333,6 @@ $(function() {
   make_widget_sortable();
   setup_add_btns();
   {%- endif %}
-
-  /* This is how to activate and remove (here after 13 sec) the favicon
-  notification */
-  console.log('Show notification');
-  Notificon('#33ff00');
-  setTimeout(function(){console.log('Hide notification'); Notificon()}, 13000)
-  setTimeout(function(){
-      console.log('Show notification'); Notificon('#eb361e')
-    }, 15000)
-  setTimeout(function(){console.log('Hide notification'); Notificon()}, 18000)
 });
 
 </script>
diff --git a/hubs/tests/hubs_test.cfg b/hubs/tests/hubs_test.cfg
index a910e72..bae6178 100644
--- a/hubs/tests/hubs_test.cfg
+++ b/hubs/tests/hubs_test.cfg
@@ -1,7 +1,8 @@
 ### Secret key for the Flask application
-SECRET_KEY='<The web application secret key>'
+SECRET_KEY = '<The web application secret key>'
 
 ### url to the database server:
+
 import os
 DB_URL = 'sqlite:///%s/test.db' % (os.path.dirname(os.path.abspath(__file__)))
 #DB_URL='sqlite:////tmp/fedocal_dev.sqlite'
@@ -11,3 +12,8 @@ OIDC_CLIENT_SECRETS = os.path.join(os.path.dirname(
     os.path.abspath(__file__)), 'client_secrets.json')
 
 SITE_ADMINS = ["admin"]
+
+SSE_URL = {
+    "port": "8080",
+    "path": "/sse",
+}
diff --git a/hubs/tests/test_view_utils.py b/hubs/tests/test_view_utils.py
index 6a6d116..ca49dac 100644
--- a/hubs/tests/test_view_utils.py
+++ b/hubs/tests/test_view_utils.py
@@ -89,28 +89,43 @@ class ViewUtilsTest(APPTest):
 
     def test_sse_url(self):
         with app.test_request_context():
-            self.assertEqual(get_sse_url(), "http://localhost:8080/sse")
+            self.assertEqual(get_sse_url(""), "http://localhost:8080/sse/")
+
+        with app.test_request_context():
+            self.assertEqual(
+                get_sse_url("hub/ralph"),
+                "http://localhost:8080/sse/hub/ralph")
 
         with app.test_request_context(base_url='http://hubs.example.com/'):
-            self.assertEqual(get_sse_url(), "http://hubs.example.com:8080/sse")
+            self.assertEqual(
+                get_sse_url("hub/ralph"),
+                "http://hubs.example.com:8080/sse/hub/ralph")
 
         with app.test_request_context(base_url='http://example.com/hubs'):
             self.assertEqual(flask.url_for("index"), "/hubs/")  # test validity
-            self.assertEqual(get_sse_url(), "http://example.com:8080/sse")
+            self.assertEqual(
+                get_sse_url("hub/ralph"),
+                "http://example.com:8080/sse/hub/ralph")
 
         with app.test_request_context(base_url='http://hubs.example.com/'):
             with app_config(app, {
                     "SSE_URL": {"host": "hubs-sse.example.com"}
                     }):
-                self.assertEqual(get_sse_url(), "http://hubs-sse.example.com/")
+                self.assertEqual(
+                    get_sse_url("hub/ralph"),
+                    "http://hubs-sse.example.com/hub/ralph")
 
         with app.test_request_context(base_url='http://hubs.example.com/'):
             with app_config(app, {
                     "SSE_URL": {"host": "hubs-sse.example.com",
                                 "port": 8080}
                     }):
-                self.assertEqual(get_sse_url(), "http://hubs-sse.example.com:8080/")
+                self.assertEqual(
+                    get_sse_url("hub/ralph"),
+                    "http://hubs-sse.example.com:8080/hub/ralph")
 
         with app.test_request_context(base_url='http://localhost/hubs'):
             with app_config(app, {"SSE_URL": {"host": "example.com"}}):
-                self.assertEqual(get_sse_url(), "http://example.com/")
+                self.assertEqual(
+                    get_sse_url("hub/ralph"),
+                    "http://example.com/hub/ralph")
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
index 4a4c63a..50c5723 100644
--- a/hubs/utils/views.py
+++ b/hubs/utils/views.py
@@ -288,7 +288,7 @@ class RequestValidator(object):
         return values
 
 
-def get_sse_url():
+def get_sse_url(target):
     """Build the SSE URL."""
     # Avoid circular import with widgets.
     from hubs.app import app
@@ -302,7 +302,11 @@ def get_sse_url():
     netloc = host
     if port:
         netloc = "{}:{}".format(host, port)
-    path = urlparse.urljoin(base_url.path, conf.get("path", "/"))
+    path = conf.get("path", "")
+    if not path.endswith("/"):
+        path += "/"
+    path = urlparse.urljoin(base_url.path, path)
+    path = urlparse.urljoin(path, target)
     return urlparse.urlunsplit([
         conf.get("scheme") or base_url.scheme,
         netloc, path, "", "",
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 5496503..0616f05 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -22,7 +22,7 @@ def hub(name):
         hub=hub,
         widgets=widgets,
         edit=False,
-        sse_url=get_sse_url(),
+        sse_url=get_sse_url("hub/{}".format(hub.name)),
         )
 
 
diff --git a/hubs/views/user.py b/hubs/views/user.py
index a5cc00d..13e1313 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -1,15 +1,11 @@
 from __future__ import unicode_literals, absolute_import
 
 import flask
-import json
 import hubs.models
 import hubs.feed
 
 from hubs.app import app
-from hubs.utils.views import (
-    login_required, get_hub, get_sse_url, get_visible_widgets,
-    require_hub_access,
-    )
+from hubs.utils.views import login_required, get_hub, get_sse_url
 
 
 @app.route('/stream')
@@ -18,12 +14,10 @@ from hubs.utils.views import (
 def stream():
     username = flask.g.auth.user.username
     hub = get_hub(username)
-    widgets = get_visible_widgets(hub)
     return flask.render_template(
         'stream.html',
         hub=hub,
-        widgets=widgets,
-        sse_url=get_sse_url(),
+        sse_url=get_sse_url("user/{}".format(username)),
     )
 
 
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index eb0db3c..9010ad1 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -3,8 +3,6 @@ from __future__ import unicode_literals, absolute_import
 
 import logging
 
-import hubs.feed
-from hubs.views.utils import get_sse_url
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
 
@@ -39,7 +37,6 @@ class BaseView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         return dict(
             title=self.widget.label,
-            sse_url=get_sse_url(),
             disable_autoreload=True,
             )
 
diff --git a/requirements.txt b/requirements.txt
index ed9742f..07dab88 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -26,3 +26,4 @@ pygments
 pygments-markdown-lexer
 redis
 retask
+txredisapi
diff --git a/systemd/hubs-sse.service b/systemd/hubs-sse.service
new file mode 100644
index 0000000..1120a4f
--- /dev/null
+++ b/systemd/hubs-sse.service
@@ -0,0 +1,19 @@
+[Unit]
+Description=fedora-hubs SSE server
+After=network.target
+Documentation=https://pagure.io/fedora-hubs/
+
+[Service]
+ExecStart= \
+    twistd -l - --pidfile= \
+    -ny /srv/hubs/fedora-hubs/hubs/backend/sse_server.tac
+WorkingDirectory=/srv/hubs/fedora-hubs/
+PIDFile=/run/hubs-sse.pid
+Type=simple
+User=root
+Group=root
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
+

From 4355b079430255ac1d15cc9d8a548e5bc0607bdc Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 22 2017 18:23:02 +0000
Subject: [PATCH 882/1001] Add switches to the backend commands for debug output


---

diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index b4a2c82..f59769b 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -21,6 +21,7 @@ handle.
 
 from __future__ import unicode_literals
 
+import argparse
 import json
 import logging
 import logging.config
@@ -98,10 +99,20 @@ def get_widgets():
     return widgets
 
 
+def parse_args(args):
+    parser = argparse.ArgumentParser(
+        description='Triage messages from the bus.')
+    parser.add_argument("-d", "--debug", action="store_true",
+                        help="debugging output level.")
+    return parser.parse_args()
+
+
 def main(args=None):
     args = args if args is not None else sys.argv
+    args = parse_args(args)
     logging.config.dictConfig(fedmsg_config['logging'])
-    logging.basicConfig()
+    log_level = logging.DEBUG if args.debug else logging.INFO
+    logging.basicConfig(level=log_level)
 
     # XXX - for flask.url_for to work
     hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'
@@ -122,7 +133,7 @@ def main(args=None):
         while True:
             task = inbound.wait()  # Wait forever...  timeout is optional.
             msg = json.loads(task.data)
-            log.info(
+            log.debug(
                 "(triage backlog: %r, work backlog: %r)  Working on %r %r",
                 inbound.length, outbound.length, msg['msg_id'], msg['topic'],
             )
diff --git a/hubs/backend/worker.py b/hubs/backend/worker.py
index 363025a..c3c2f35 100755
--- a/hubs/backend/worker.py
+++ b/hubs/backend/worker.py
@@ -26,6 +26,7 @@ clients with the new content produced here.
 
 from __future__ import unicode_literals
 
+import argparse
 import json
 import logging
 import logging.config
@@ -66,10 +67,19 @@ def handle_widget_cache(widget_idx, fn_name):
         session.close()
 
 
+def parse_args(args):
+    parser = argparse.ArgumentParser(description='Rebuild widget caches.')
+    parser.add_argument("-d", "--debug", action="store_true",
+                        help="debugging output level.")
+    return parser.parse_args()
+
+
 def main(args=None):
     args = args if args is not None else sys.argv
+    args = parse_args(args)
     logging.config.dictConfig(fedmsg_config['logging'])
-    logging.basicConfig()
+    log_level = logging.DEBUG if args.debug else logging.INFO
+    logging.basicConfig(level=log_level)
 
     # XXX - for flask.url_for to work
     hubs.app.app.config['SERVER_NAME'] = '0.0.0.0:5000'

From 8ac9cae9c98be453a465da713233c77cfe9a89bc Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 22 2017 18:23:02 +0000
Subject: [PATCH 883/1001] Feed: add a toggle to show the events of an aggregate


---

diff --git a/hubs/static/client/app/components/feed/Icon.jsx b/hubs/static/client/app/components/feed/Icon.jsx
index 3a15c77..9e0cfbe 100644
--- a/hubs/static/client/app/components/feed/Icon.jsx
+++ b/hubs/static/client/app/components/feed/Icon.jsx
@@ -5,7 +5,7 @@ export default class Icon extends React.Component {
     return (
       <a href={this.props.item.link ? this.props.item.link : '#'}
          target="_blank"
-         className="d-flex align-self-center mr-3"
+         className="d-flex align-self-start mr-3"
          >
         <img
           alt="User avatar"
diff --git a/hubs/static/client/app/components/feed/Markup.jsx b/hubs/static/client/app/components/feed/Markup.jsx
index ad482e0..1ea749e 100644
--- a/hubs/static/client/app/components/feed/Markup.jsx
+++ b/hubs/static/client/app/components/feed/Markup.jsx
@@ -9,19 +9,40 @@ export default class Markup extends React.Component {
     this.createMarkup = this.createMarkup.bind(this);
   }
 
-  createMarkup() {
-    return { __html: this.props.item.markup };
+  createMarkup(item) {
+    return { __html: item.markup || item.subtitle };
   }
 
   render() {
     const timestamp = this.props.item.end_time || this.props.item.timestamp;
+    const submsgs = this.props.item.msg_ids;
+    var submessages = [];
+    if (submsgs && Object.keys(submsgs).length > 1) {
+      submessages = Object.keys(submsgs).map((msgid) => {
+        return (
+          <li key={msgid}>
+            <small dangerouslySetInnerHTML={this.createMarkup(submsgs[msgid])}></small>
+          </li>
+        );
+      });
+    }
 
     return (
-      <div className="media-body align-self-center">
-        <span dangerouslySetInnerHTML={this.createMarkup()}></span>
-        <small className="text-muted float-right">
-          <TimeAgo date={timestamp * 1000} />
-        </small>
+      <div className="media-body align-self-start">
+        <span dangerouslySetInnerHTML={this.createMarkup(this.props.item)}></span>
+        {timestamp &&
+          <small className="text-muted ml-3">
+            <TimeAgo date={timestamp * 1000} />
+          </small>
+        }
+        {submessages.length !== 0 &&
+          <ul
+            className="submessages"
+            style={{display: this.props.detailsOpened ? "block" : "none" }}
+            >
+            {submessages}
+          </ul>
+        }
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/feed/Panel.jsx b/hubs/static/client/app/components/feed/Panel.jsx
index 80bed1c..5be00e7 100644
--- a/hubs/static/client/app/components/feed/Panel.jsx
+++ b/hubs/static/client/app/components/feed/Panel.jsx
@@ -6,14 +6,42 @@ import Actions from './Actions.jsx';
 
 export default class Panel extends React.Component {
 
+  constructor(props) {
+    super(props);
+    this.state = {
+      detailsOpened: false,
+    }
+    this.toggleDetails = this.toggleDetails.bind(this);
+  }
+
+  toggleDetails(e) {
+    e.preventDefault();
+    this.setState((prevState, props) => (
+      {detailsOpened: !prevState.detailsOpened}
+    ));
+  }
+
   render() {
     return (
       <div className="media py-3" id={this.props.item.id}>
         <Icon item={this.props.item} />
-        <Markup {...this.props} />
-        { (this.props.handleSave || this.props.handleUnsave) &&
-          <Actions {...this.props} />
-        }
+        <Markup
+          {...this.props}
+          detailsOpened={this.state.detailsOpened}
+          />
+        <div className="d-flex flex-column align-self-start ml-3 text-right">
+          { (this.props.handleSave || this.props.handleUnsave) &&
+            <Actions {...this.props} />
+          }
+          { (this.props.item.msg_ids &&
+             Object.keys(this.props.item.msg_ids).length > 1) &&
+            <div className="mt-auto">
+              <small>
+                <a href="#" onClick={this.toggleDetails}>details</a>
+              </small>
+            </div>
+          }
+        </div>
       </div>
     );
   }
diff --git a/hubs/static/client/app/components/feed/__tests__/Panel.test.js b/hubs/static/client/app/components/feed/__tests__/Panel.test.js
index 6e17d1c..ff93dbe 100644
--- a/hubs/static/client/app/components/feed/__tests__/Panel.test.js
+++ b/hubs/static/client/app/components/feed/__tests__/Panel.test.js
@@ -14,19 +14,35 @@ describe('Panel', () => {
     date_time: new Date(),
     link: 'https://pagure.io/fedora-hubs',
     secondary_icon: 'https://placekitten.com/g/200/300',
+    msg_ids: {
+      foobar1: {},
+      foobar2: {},
+    },
   };
 
-  it('should render the card block', () => {
+  it('should render the actions block', () => {
     const component = TestUtils.renderIntoDocument(
       <Panel item={item} />
     );
     expect(component).toBeTruthy();
 
     const node = ReactDOM.findDOMNode(component);
-    const block = node.querySelector('.card-block');
+    const block = node.querySelector('div.ml-3.text-right');
 
     expect(block).toBeTruthy();
   });
+
+  it('should show the details link', () => {
+    const component = TestUtils.renderIntoDocument(
+      <Panel item={item} />
+    );
+    expect(component).toBeTruthy();
+
+    const node = ReactDOM.findDOMNode(component);
+    const details = node.querySelector('.text-right small a');
+
+    expect(details).toBeTruthy();
+  });
 });
 
 

From dcfbfb4ac366ae22036fdc791cd02fa3dc4a48f1 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 22 2017 18:23:02 +0000
Subject: [PATCH 884/1001] Create links for user hubs in Feed messages


---

diff --git a/hubs/feed.py b/hubs/feed.py
index 786844b..5fb9546 100644
--- a/hubs/feed.py
+++ b/hubs/feed.py
@@ -3,8 +3,10 @@ from __future__ import unicode_literals
 import hashlib
 import logging
 import os
+import re
 
 import fedmsg.meta
+import flask
 import redis
 from fedmsg.encoding import loads, dumps
 
@@ -66,14 +68,41 @@ def format_msg(msg):
     # invariant through conglomerate() calls.
     msg["dom_id"] = hashlib.sha1(
         b":".join(
-            [mid.encode("utf-8") for mid in msg["msg_ids"]]
+            [mid.encode("utf-8") for mid in sorted(msg["msg_ids"])]
         )).hexdigest()
     # TODO: generate markup
-    msg["markup"] = msg["subtitle"]
-    msg["markup_subjective"] = msg["subjective"]
+    msg["markup"] = _make_hub_links(msg, "subtitle")
+    msg["markup_subjective"] = _make_hub_links(msg, "subjective")
     return msg
 
 
+_word_split_re = re.compile(r'(\s+)')
+_punctuation_re = re.compile(
+    '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
+        '|'.join(map(re.escape, ('(', '<', '&lt;'))),
+        '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '&gt;', "'s")))
+    )
+)
+
+
+def _make_hub_links(msg, attr):
+    if not msg.get(attr):
+        return ""
+    existing_usernames = [r[0] for r in User.query.values(User.username)]
+    usernames = [u for u in msg["usernames"] if u in existing_usernames]
+    words = _word_split_re.split(msg[attr])
+    for i, word in enumerate(words):
+        match = _punctuation_re.match(word)
+        if match:
+            lead, middle, trail = match.groups()
+            if middle in usernames:
+                middle = '<a href="{}">{}</a>'.format(
+                    flask.url_for("hub", name=middle), middle)
+            if lead + middle + trail != word:
+                words[i] = lead + middle + trail
+    return ''.join(words)
+
+
 class Feed(object):
 
     max_items = 100
diff --git a/hubs/tests/test_feed.py b/hubs/tests/test_feed.py
index 29b21ba..042ff55 100644
--- a/hubs/tests/test_feed.py
+++ b/hubs/tests/test_feed.py
@@ -117,3 +117,29 @@ class FeedTest(APPTest):
             sorted(get_hubs_for_msg({"msg_id": "testmsg"})),
             ["infra", "ralph", "testhub"]
             )
+
+    def test_format_msg(self):
+        msg = {
+            "msg_ids": {
+                "testid1": {"msg_id": "testid1"},
+                "testid2": {"msg_id": "testid2"},
+                "testid3": {"msg_id": "testid3"},
+            },
+            "usernames": ["ralph", "decause"],
+            "subtitle": "ralph's ticket was commented by decause",
+            "subjective": "your ticket was commented by decause",
+        }
+        with app.test_request_context():
+            result = format_msg(msg)
+        self.assertEqual(
+            result["dom_id"],
+            "067306d0b091ec48d9e2dded1ca9b1f8b1b2ac93")
+        self.assertEqual(
+            result["markup"],
+            """<a href="/ralph/">ralph</a>'s ticket was commented by """
+            """<a href="/decause/">decause</a>"""
+            )
+        self.assertEqual(
+            result["markup_subjective"],
+            """your ticket was commented by <a href="/decause/">decause</a>"""
+            )

From 5a753eca4a7c951e379441f3b4b42658f2f3edcc Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 22 2017 18:23:02 +0000
Subject: [PATCH 885/1001] Don't show the SSE error message when leaving the page


---

diff --git a/hubs/static/client/app/components/feed/ItemsGetter.jsx b/hubs/static/client/app/components/feed/ItemsGetter.jsx
index 75c50f9..dcfe7ca 100644
--- a/hubs/static/client/app/components/feed/ItemsGetter.jsx
+++ b/hubs/static/client/app/components/feed/ItemsGetter.jsx
@@ -11,6 +11,7 @@ export default class ItemsGetter extends React.Component {
     };
     this.sseSource = null;
     this.setupSSESource = this.setupSSESource.bind(this);
+    this.tearDownSSESource = this.tearDownSSESource.bind(this);
     this.handleSSEEvent = this.handleSSEEvent.bind(this);
     this.handleSSEEventError = this.handleSSEEventError.bind(this);
     this.loadFromServer = this.loadFromServer.bind(this);
@@ -23,17 +24,14 @@ export default class ItemsGetter extends React.Component {
 
   componentWillUnmount() {
     this.serverRequest.abort();
-    if (this.sseSource) {
-      this.sseSource.removeEventListener(
-        this.props.sseEventName, this.this.props.handleSSEEvent);
-      this.sseSource.removeEventListener('error', this.handleSSEEventError);
-    }
+    this.tearDownSSESource();
+    window.removeEventListener("beforeunload", this.tearDownSSESource);
   }
 
   setupSSESource() {
-    //if (!this.props.sseEventName || !this.props.handleSSEEvent) {
-    if (!this.props.sse.eventName || !this.props.sse.shouldReload) {
-      console.log("SSE auto-update is disabled");
+    if (!this.props.sse ||
+        !this.props.sse.eventName ||
+        !this.props.sse.shouldReload) {
       // Auto-update is disabled.
       return;
     }
@@ -47,6 +45,18 @@ export default class ItemsGetter extends React.Component {
     this.sseSource.addEventListener('error', this.handleSSEEventError);
     this.sseSource.addEventListener(
       this.props.sse.eventName, this.handleSSEEvent);
+    // This is necessary to avoid the error message being displayed right
+    // before the user changes page.
+    // Pretty much like: https://bugzilla.mozilla.org/show_bug.cgi?id=833462
+    window.addEventListener("beforeunload", this.tearDownSSESource);
+  }
+
+  tearDownSSESource() {
+    if (!this.sseSource) { return; }
+    this.sseSource.removeEventListener(
+      this.props.sse.eventName, this.handleSSEEvent);
+    this.sseSource.removeEventListener('error', this.handleSSEEventError);
+    this.sseSource = null;
   }
 
   handleSSEEvent(e) {
@@ -55,7 +65,8 @@ export default class ItemsGetter extends React.Component {
     }
   }
 
-  handleSSEEventError() {
+  handleSSEEventError(e) {
+    console.log(e);
     this.setState({
       sseError: ("Cannot auto-update the feed, you will have to refresh "
                 +"the page manually to see new elements.")

From 7d9541562bd5a9a18d52908c083047ab04a16155 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 22 2017 18:23:02 +0000
Subject: [PATCH 886/1001] Display a message when there is no feed item


---

diff --git a/hubs/static/client/app/components/feed/Feed.jsx b/hubs/static/client/app/components/feed/Feed.jsx
index 9292add..ec6b037 100644
--- a/hubs/static/client/app/components/feed/Feed.jsx
+++ b/hubs/static/client/app/components/feed/Feed.jsx
@@ -1,7 +1,21 @@
 import React from 'react';
+import PropTypes from 'prop-types';
+import {
+  IntlProvider,
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
 import Panel from './Panel.jsx';
 
 
+const messages = defineMessages({
+  no_items: {
+    id: "hubs.components.feed.no_items",
+    defaultMessage: "No items yet.",
+  },
+});
+
+
 export default class Feed extends React.Component {
 
   render() {
@@ -12,13 +26,27 @@ export default class Feed extends React.Component {
         );
     });
     return (
-      <div className="component-feed">
-        {items}
-      </div>
+      <IntlProvider locale={navigator.language}>
+        <div className="component-feed">
+          { (items.length == 0 && this.props.loaded) ?
+            <FormattedMessage {...messages.no_items} tagName="i" />
+            :
+            items
+          }
+        </div>
+      </IntlProvider>
     );
   }
 
 }
 
 
+Feed.propTypes = {
+  loaded: PropTypes.bool,
+};
+Feed.defaultProps = {
+  loaded: true,
+};
+
+
 // vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/feed/Widget.jsx b/hubs/static/client/app/widgets/feed/Widget.jsx
index 636daa2..b266609 100644
--- a/hubs/static/client/app/widgets/feed/Widget.jsx
+++ b/hubs/static/client/app/widgets/feed/Widget.jsx
@@ -9,12 +9,16 @@ export default class Widget extends React.Component {
     super(props);
     this.state = {
       items: [],
+      loaded: false,
     };
     this.handleServerData = this.handleServerData.bind(this);
   }
 
   handleServerData(data) {
-    this.setState({items: data});
+    this.setState({
+      items: data,
+      loaded: true,
+    });
   }
 
   render() {
@@ -29,6 +33,7 @@ export default class Widget extends React.Component {
         >
         <Feed
           items={this.state.items}
+          loaded={this.state.loaded}
           />
       </ItemsGetter>
     );

From 6212bfe0ddad80609021593ed11ccfbcbf0c872a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 22 2017 18:23:02 +0000
Subject: [PATCH 887/1001] Handle error cases better in the SSE server


---

diff --git a/hubs/backend/sse_server.py b/hubs/backend/sse_server.py
index 781ddb2..7bcd7c7 100644
--- a/hubs/backend/sse_server.py
+++ b/hubs/backend/sse_server.py
@@ -9,7 +9,7 @@ import txredisapi as redis
 
 from twisted.application import service
 from twisted.web import server, resource
-from twisted.internet import reactor, defer
+from twisted.internet import reactor, defer, task
 from twisted.logger import (
     Logger, globalLogBeginner, ILogObserver, formatEvent)
 from zope.interface import provider
@@ -102,6 +102,7 @@ class Subscribe(resource.Resource):
             self.subscribers[target] = []  # first request to this target.
         log.debug("New subscriber: {req}", req=request)
         self.subscribers[target].append(request)
+        self._send_event(request, "connected", "null")
         log.debug("There is now {count} subscribers to {target}.",
                   target=target, count=len(self.subscribers[target]))
 
@@ -116,11 +117,25 @@ class Subscribe(resource.Resource):
         log.debug("Broadcasting to {num} requests.",
                   num=len(target_subscribers))
         for request in target_subscribers:
-            if event:
-                request.write("event: {}\r\n".format(event).encode("utf-8"))
-            request.write("data: {}\r\n".format(data).encode("utf-8"))
-            # The last CRLF is required to dispatch the event to the client.
-            request.write(b"\r\n")
+            self._send_event(request, event, data)
+
+    def keepalive(self):
+        all_subscribers = []
+        for subs in self.subscribers.values():
+            all_subscribers.extend(subs)
+        if not all_subscribers:
+            return
+        log.debug("Broadcasting a ping to {num} requests.",
+                  num=len(all_subscribers))
+        for request in all_subscribers:
+            self._send_event(request, "ping", "null")
+
+    def _send_event(self, request, event, data):
+        if event:
+            request.write("event: {}\r\n".format(event).encode("utf-8"))
+        request.write("data: {}\r\n".format(data).encode("utf-8"))
+        # The last CRLF is required to dispatch the event to the client.
+        request.write(b"\r\n")
 
     def request_closed(self, err, request, target):
         log.debug("Removing subscriber {subscriber} from {target}.",
@@ -181,12 +196,18 @@ def main():
         print(formatEvent(event))
     globalLogBeginner.beginLoggingTo(
         [printingObserver], redirectStandardIO=False)
+    # Web service
     sub = Subscribe()
     site = server.Site(sub)
     port = int(hubs.app.app.config.get("SSE_URL", {}).get("port", 8080))
     reactor.listenTCP(port, site)
+    # Redis client
     redisclient = RedisClientService(sub)
     redisclient.startService()
+    # Keepalive ping
+    keepalive = task.LoopingCall(sub.keepalive)
+    keepalive.start(30)
+    # Start the reactor
     reactor.run()
 
 
diff --git a/hubs/backend/sse_server.tac b/hubs/backend/sse_server.tac
index 57dc41f..1ea980f 100644
--- a/hubs/backend/sse_server.tac
+++ b/hubs/backend/sse_server.tac
@@ -13,7 +13,7 @@ which twistd will look for
 from __future__ import unicode_literals
 
 from twisted.application import service, internet
-from twisted.internet import reactor
+from twisted.internet import reactor, task
 from twisted.web import server
 
 import hubs.app
@@ -37,3 +37,7 @@ web_service.setServiceParent(application)
 # Redis client
 redis_service = RedisClientService(broadcaster)
 redis_service.setServiceParent(application)
+
+# Keepalive ping
+keepalive = task.LoopingCall(broadcaster.keepalive)
+keepalive.start(30)
diff --git a/hubs/static/client/app/components/feed/ItemsGetter.jsx b/hubs/static/client/app/components/feed/ItemsGetter.jsx
index dcfe7ca..ca6397d 100644
--- a/hubs/static/client/app/components/feed/ItemsGetter.jsx
+++ b/hubs/static/client/app/components/feed/ItemsGetter.jsx
@@ -14,6 +14,7 @@ export default class ItemsGetter extends React.Component {
     this.tearDownSSESource = this.tearDownSSESource.bind(this);
     this.handleSSEEvent = this.handleSSEEvent.bind(this);
     this.handleSSEEventError = this.handleSSEEventError.bind(this);
+    this.handleSSEEventOpen = this.handleSSEEventOpen.bind(this);
     this.loadFromServer = this.loadFromServer.bind(this);
   }
 
@@ -42,6 +43,7 @@ export default class ItemsGetter extends React.Component {
       return;
     }
 
+    this.sseSource.addEventListener('open', this.handleSSEEventOpen);
     this.sseSource.addEventListener('error', this.handleSSEEventError);
     this.sseSource.addEventListener(
       this.props.sse.eventName, this.handleSSEEvent);
@@ -65,12 +67,24 @@ export default class ItemsGetter extends React.Component {
     }
   }
 
+  handleSSEEventOpen(e) {
+    this.setState({sseError: false});
+  }
+
   handleSSEEventError(e) {
     console.log(e);
-    this.setState({
-      sseError: ("Cannot auto-update the feed, you will have to refresh "
-                +"the page manually to see new elements.")
-    });
+    if (this.sseSource.readyState === 2) {
+      // Connection closed.
+      this.setState({
+        sseError: ("Cannot auto-update the feed, you will have to refresh "
+                  +"the page manually to see new elements.")
+      });
+    } else if (this.sseSource.readyState === 0) {
+      // Reconnecting
+      this.setState({
+        sseError: "Reconnecting to the auto-update source...",
+      });
+    }
   }
 
   loadFromServer() {

From c40253cb4e34b947994a4c766cf58df84552fdb2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 22 2017 18:23:02 +0000
Subject: [PATCH 888/1001] Fix usage of the session


---

diff --git a/hubs/app.py b/hubs/app.py
index 1cc6c68..c24a9e0 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -67,28 +67,34 @@ def check_auth():
     flask.g.fedmsg_config = fedmsg_config
 
     if OIDC.user_loggedin:
-        if not hasattr(flask.session, 'auth') or not flask.session.auth:
-            flask.session.auth = munch.Munch(
-                fullname=OIDC.user_getfield('name'),
-                nickname=(OIDC.user_getfield('nickname') or
-                          OIDC.user_getfield('sub')),
-                email=OIDC.user_getfield('email'),
-                timezone=OIDC.user_getfield('zoneinfo'),
+        if "auth" not in flask.session or not flask.session["auth"]:
+            user_info = OIDC.user_getinfo([
+                "name", "nickname", "sub", "email", "zoneinfo", "cla",
+                "groups",
+                ])
+            flask.session["auth"] = dict(
+                fullname=user_info['name'],
+                nickname=(user_info['nickname'] or user_info['sub']),
+                email=user_info['email'],
+                timezone=user_info['zoneinfo'],
                 cla_done=('http://admin.fedoraproject.org/accounts/cla/done'
-                          in OIDC.user_getfield('cla')),
-                groups=OIDC.user_getfield('groups'),
+                          in user_info['cla']),
+                groups=user_info['groups'],
                 logged_in=True,
             )
-            flask.session.auth.avatar = username2avatar(
-                flask.session.auth.nickname)
-
-            user = hubs.models.User.get_or_create(
-                flask.g.db, username=flask.session.auth.nickname,
-                fullname=flask.session.auth.fullname)
-            flask.session.auth.user = user
-        flask.g.auth = flask.session.auth
+            flask.session["auth"]["avatar"] = username2avatar(
+                flask.session["auth"]["nickname"])
+            # Changes on mutable objects aren't picked up:
+            # http://flask.pocoo.org/docs/0.12/api/#flask.session.modified
+            flask.session.modified = True
+        flask.g.auth = munch.Munch(**flask.session["auth"])
+        user = hubs.models.User.get_or_create(
+            flask.g.db, username=flask.session["auth"]["nickname"],
+            fullname=flask.session["auth"]["fullname"])
+        flask.g.user = user
     else:
-        flask.g.auth = munch.Munch(logged_in=False, user=None)
+        flask.g.auth = munch.Munch(logged_in=False)
+        flask.g.user = None
 
 
 # Register widgets
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 611fae9..63946a3 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -22,7 +22,7 @@
           
   <!-- right side of header -->
   <div class="col-md-{{ hub.config.right_width }} text-center align-self-end">
-    {% if hub.allows(g.auth.user, "config") %}
+    {% if hub.allows(g.user, "config") %}
       <button class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#settings-modal">
         <i class="fa fa-cog" aria-hidden="true"></i>
         hub settings
@@ -325,7 +325,7 @@ $(function() {
   setup_widgets();
   setup_sse({{ sse_url | tojson }});
   setup_edit_btns();
-  {% if hub.allows(g.auth.user, "config") %}
+  {% if hub.allows(g.user, "config") %}
   setup_settings();
   {% endif %}
 
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index b8e4b57..10c831e 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -112,8 +112,8 @@
       <ul class="nav nav-pills flex-lg-column mb-3 rounded" id="vertical-navbar" role="navigation">
         {% if g.auth.logged_in %}
         <li class="nav-item">
-          <a class="nav-link {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}"
-             href="{{ url_for("hub", name=g.auth.user.username) }}">
+          <a class="nav-link {% if request.path.endswith('/' + g.user.username + '/') %}active{% endif %}"
+             href="{{ url_for("hub", name=g.user.username) }}">
             <span><i class="fa fa-home" aria-hidden="true"></i></span>
             My Hub
           </a>
@@ -125,7 +125,7 @@
             My Stream
           </a>
         </li>
-        {% for hub in g.auth.user.bookmarks %}
+        {% for hub in g.user.bookmarks %}
           <li class='nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>
             <a class="nav-link" href="{{ url_for("hub", name=hub.name) }}">
               <span><i class="fa fa-bookmark" aria-hidden="true"></i></span>
diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index a57c0c1..15051a6 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -138,7 +138,10 @@ def auth_set(APP, auth):
         g.auth = auth
         g.oidc_id_token = None
         if not auth:
-            g.auth = munch.Munch(logged_in=False, user=None)
+            g.auth = munch.Munch(logged_in=False)
+            g.user = None
+        else:
+            g.user = auth.user
 
     if flask._app_ctx_stack.top is None:
         # App context isn't pushed yet
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
index 50c5723..cc576c7 100644
--- a/hubs/utils/views.py
+++ b/hubs/utils/views.py
@@ -53,7 +53,7 @@ def get_visible_widgets(hub):
     from hubs.widgets import registry
     widgets = {"left": [], "right": []}
     try:
-        user = flask.g.auth.user
+        user = flask.g.user
     except AttributeError:
         user = None
     for widget in hub.widgets:
@@ -166,7 +166,7 @@ def require_hub_access(action, url_param="name", json=False):
             hub_name = kwargs[url_param]
             hub = get_hub(hub_name, load_config=True)
             try:
-                user = flask.g.auth.user
+                user = flask.g.user
             except AttributeError:
                 user = None
             if not hub.allows(user, action):
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 0616f05..4a7c6e7 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -193,7 +193,7 @@ def hub_config_get(hub):
             "role": assoc.role,
         }
         if (assoc.role == "owner" and
-                assoc.user.username == flask.g.auth.user.username):
+                assoc.user.username == flask.g.user.username):
             user["locked"] = True
         result["result"]["users"][assoc.role].append(user)
     return result
diff --git a/hubs/views/user.py b/hubs/views/user.py
index 13e1313..e33c638 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -12,7 +12,7 @@ from hubs.utils.views import login_required, get_hub, get_sse_url
 @app.route('/stream/')
 @login_required
 def stream():
-    username = flask.g.auth.user.username
+    username = flask.g.user.username
     hub = get_hub(username)
     return flask.render_template(
         'stream.html',
@@ -24,7 +24,7 @@ def stream():
 @app.route('/stream/existing')
 @login_required
 def stream_existing():
-    username = flask.g.auth.user.username
+    username = flask.g.user.username
     feed = hubs.feed.Notifications(username)
     existing = feed.get()  # TODO: paging?
     # Right now, stream and actions are the same.
@@ -38,7 +38,7 @@ def stream_existing():
 @app.route('/stream/saved/', methods=['GET', 'POST'])
 @login_required
 def saved_notifs():
-    user = flask.g.auth.user
+    user = flask.g.user
     if flask.request.method == "GET":
         saved = hubs.models.SavedNotification.by_username(user.username)
         return flask.jsonify(dict(
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index fa39d4e..6120391 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -7,7 +7,7 @@
     <a href="{{ url_for('%s_root' % widget.name, hub=widget_instance.hub.name, idx=widget_instance.idx) }}">
         <span><i class="fa fa-external-link" aria-hidden="true"></i></span>
     </a>
-    {% if widget_instance.hub.allows(g.auth.user, "config") %}
+    {% if widget_instance.hub.allows(g.user, "config") %}
     <a data-target="#edit_modal" data-toggle="modal" type="button"
         class="edit_widget" data-url="{{ widget_instance.edit_url }}">
       <span><i class="fa fa-cog" aria-hidden="true"></i></span>
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index 780a3d4..98fef57 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -94,7 +94,7 @@ class Username(Validator):
     @classmethod
     def to_string(cls, value):
         if value is None and flask.g.auth.logged_in:
-            return flask.g.auth.user.username
+            return flask.g.user.username
         return value
 
 
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index cd2810f..2f956bf 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -105,7 +105,7 @@ class WidgetView(View):
         """
         instance = self._get_instance(*args, **kwargs)
         try:
-            user = flask.g.auth.user
+            user = flask.g.user
         except AttributeError:
             user = None
         if not instance.allows(user, self.permission):

From d54c37467102a9079ba1da06b6fb6145a69b50a5 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 27 2017 16:25:13 +0000
Subject: [PATCH 889/1001] Fix some errors in the ansible role


---

diff --git a/ansible/roles/hubs/tasks/db-postgresql.yml b/ansible/roles/hubs/tasks/db-postgresql.yml
index d228b80..e8a5601 100644
--- a/ansible/roles/hubs/tasks/db-postgresql.yml
+++ b/ansible/roles/hubs/tasks/db-postgresql.yml
@@ -49,6 +49,8 @@
   command: "{{ hubs_venv_dir }}/bin/python {{ hubs_code_dir }}/populate.py"
   args:
     chdir: "{{ hubs_code_dir }}"
+  environment:
+    HUBS_CONFIG: "{{ hubs_conf_dir }}/hubs_config.py"
   become_user: "{{ main_user }}"
   when: db_creation|succeeded
 
diff --git a/ansible/roles/hubs/tasks/db-sqlite.yml b/ansible/roles/hubs/tasks/db-sqlite.yml
index ec27bb8..624c726 100644
--- a/ansible/roles/hubs/tasks/db-sqlite.yml
+++ b/ansible/roles/hubs/tasks/db-sqlite.yml
@@ -1,6 +1,8 @@
 - name: Create and populate the Fedora Hubs database
   command: "{{ hubs_venv_dir }}/bin/python {{ hubs_code_dir }}/populate.py"
-  become_user: "{{ main_user }}"
   args:
     creates: "{{ hubs_var_dir }}/hubs.db"
     chdir: "{{ hubs_code_dir }}"
+  environment:
+    HUBS_CONFIG: "{{ hubs_conf_dir }}/hubs_config.py"
+  become_user: "{{ main_user }}"
diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index 8e11108..a2ee9f5 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -167,7 +167,6 @@
 - name: Disable the system-wide fedmsg-hub
   service: name=fedmsg-hub state=stopped enabled=no
 
-
 - name: Install the service files
   template:
     src: "{{ item }}.service"
@@ -177,6 +176,11 @@
     - hubs-worker@
     - hubs-sse
     - hubs-fedmsg-hub
+  register: service_installed
+
+- name: reload systemd
+  command: systemctl daemon-reload
+  when: service_installed|changed
 
 - name: Start and enable the services
   service: name={{ item }} state=started enabled=yes
diff --git a/ansible/roles/hubs/tasks/webserver.yml b/ansible/roles/hubs/tasks/webserver.yml
index 37d70f0..3359739 100644
--- a/ansible/roles/hubs/tasks/webserver.yml
+++ b/ansible/roles/hubs/tasks/webserver.yml
@@ -72,6 +72,12 @@
     dest: /etc/systemd/system/{{ item }}.service
   with_items:
     - hubs-webapp
+  register: service_installed
+
+
+- name: reload systemd
+  command: systemctl daemon-reload
+  when: service_installed|changed
 
 
 - name: Start and enable the services

From c1b77d5dcb6445d491980b639f488ceb42fcda89 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 27 2017 16:25:38 +0000
Subject: [PATCH 890/1001] Cache the list of owned packages


---

diff --git a/check-cache-coverage.py b/check-cache-coverage.py
index 409eafe..4e623cc 100755
--- a/check-cache-coverage.py
+++ b/check-cache-coverage.py
@@ -19,7 +19,6 @@ import sys
 
 import hubs.app
 import hubs.widgets
-import hubs.widgets.caching
 import hubs.models
 
 
diff --git a/hubs/tests/test_widget_caching.py b/hubs/tests/test_widget_caching.py
index c04ba76..2a2684f 100644
--- a/hubs/tests/test_widget_caching.py
+++ b/hubs/tests/test_widget_caching.py
@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 
-from hubs.widgets.caching import cache, CachedFunction
+from hubs.utils.cache import cache
+from hubs.widgets.caching import CachedFunction
 
 from mock import Mock
 from hubs.tests import APPTest
diff --git a/hubs/utils/cache.py b/hubs/utils/cache.py
new file mode 100644
index 0000000..ab618a2
--- /dev/null
+++ b/hubs/utils/cache.py
@@ -0,0 +1,30 @@
+"""
+Attributes:
+    cache (dogpile.cache.region.CacheRegion): The cache where data
+        will be stored. It is configured with the ``fedora-hubs.cache`` key in
+        fedmsg configuration.
+"""
+
+from __future__ import unicode_literals
+
+import dogpile
+import dogpile.cache
+
+from hubs.utils import get_fedmsg_config
+
+
+def _get_cache():
+    cache_defaults = {
+        "backend": "dogpile.cache.dbm",
+        "expiration_time": 1,  # Expire every 1 second, for development
+        "arguments": {
+            "filename": "/var/tmp/fedora-hubs-cache.db",
+        },
+    }
+    cache = dogpile.cache.make_region()
+    fedmsg_config = get_fedmsg_config()
+    cache.configure(**fedmsg_config.get('fedora-hubs.cache', cache_defaults))
+    return cache
+
+
+cache = _get_cache()
diff --git a/hubs/utils/pkgdb.py b/hubs/utils/pkgdb.py
new file mode 100644
index 0000000..55be246
--- /dev/null
+++ b/hubs/utils/pkgdb.py
@@ -0,0 +1,45 @@
+from __future__ import unicode_literals
+
+import logging
+
+import requests
+
+from .cache import cache
+
+log = logging.getLogger(__name__)
+
+PKGDB_URL = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
+
+
+def get_owned_packages(username, use_cache=True):
+    """Get the list of packages owned by the username.
+
+    Args:
+        username (str): The FAS username.
+        use_cache (bool): Whether to cache the results for a few minutes.
+            Defaults to ``True``.
+    """
+    def get_data():
+        url = "/".join([PKGDB_URL, username])
+        try:
+            response = requests.get(url, timeout=5)
+        except (requests.exceptions.ConnectionError,
+                requests.exceptions.Timeout):
+            log.warning("Could not get the list of owned packages for %s",
+                        username)
+            return []
+        try:
+            data = response.json()
+        except ValueError:
+            log.warning(
+                "Invalid JSON response getting the list of packages "
+                "owned by %s: %s", username, response.text)
+            return []
+        owned = data['point of contact'] + data['co-maintained']
+        return sorted(set(p['name'] for p in owned))
+    if not use_cache:
+        return get_data()
+    else:
+        cache_key = ":".join(["owned_packages", username])
+        # Cache for 5 minutes, it seems reasonable.
+        return cache.get_or_create(cache_key.encode("utf-8"), get_data, 5 * 60)
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index ae09257..7125aaf 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -1,14 +1,13 @@
 from __future__ import unicode_literals
 
 import logging
-import json
 
-import requests
 import pkgwat.api
 
+from hubs.utils.pkgdb import get_owned_packages
 from hubs.widgets import validators
 from hubs.widgets.base import Widget, WidgetView
-from hubs.widgets.caching import CachedFunction, cache
+from hubs.widgets.caching import CachedFunction
 
 
 log = logging.getLogger('hubs.widgets')
@@ -47,24 +46,20 @@ class BaseView(WidgetView):
 
 
 class GetIssues(CachedFunction):
+    """Returns data for Bugzilla widget.
 
-    ''' Returns data for Bugzilla Widget. Queries pkgdb api for package
-    list of the user and bugzilla for correspoding issues '''
+    Queries pkgdb api for package list of the user and bugzilla for
+    corresponding issues.
+    """
 
     def execute(self):
         username = self.instance.config["username"]
-        url = "/".join([PKGDB_URL, username])
-        response = requests.get(url)
-        data = response.json()
-
+        owned = get_owned_packages(username)
         issues = []
-
-        # get the packages of which the user is
-        # point of contact
-        for package in data["point of contact"]:
+        for pkg_name in owned:
             if len(issues) == 3:
                 break
-            pkg_details = pkgwat.api.bugs(package['name'])
+            pkg_details = pkgwat.api.bugs(pkg_name)
             for row in pkg_details['rows']:
                 if len(issues) == 3:
                     break
@@ -72,59 +67,16 @@ class GetIssues(CachedFunction):
                     dict(
                         id=row['id'],
                         title=row['description'],
-                        pkg_name=package['name'],
+                        pkg_name=pkg_name,
                     )
                 )
-
-        # get the packages of which the user is
-        # co maintainer
-        for package in data["co-maintained"]:
-            if len(issues) == 3:
-                break
-            pkg_details = pkgwat.api.bugs(package['name'])
-            for row in pkg_details['rows']:
-                if len(issues) == 3:
-                    break
-                issues.append(
-                    dict(
-                        id=row['id'],
-                        title=row['description'],
-                        pkg_name=package['name'],
-                    )
-                )
-
         return issues
 
     def should_invalidate(self, message):
-        if "bug" not in message["msg"]:
-            return False
         try:
             component = message['msg']['bug']['component']
         except KeyError:
             return False
         username = self.instance.config["username"]
-
-        # Cache for a while the list of packages owned by the user, the HTTP
-        # request is waaaay too long to be run on each incoming bug message.
-        def get_owned():
-            url = "/".join([PKGDB_URL, username])
-            try:
-                response = requests.get(url, timeout=5)
-            except (requests.exceptions.ConnectionError,
-                    requests.exceptions.Timeout):
-                log.warning("Could not get the list of owned packages for %s",
-                            username)
-                return []
-            try:
-                data = response.json()
-            except json.decoder.JSONDecodeError:
-                log.warning(
-                    "Invalid JSON response getting the list of packages "
-                    "owned by %s: %s", username, response.text)
-                return []
-            owned = data['point of contact'] + data['co-maintained']
-            return [p['name'] for p in owned]
-        owned_cache_key = ":".join(["owned_packages", username])
-        # Cache for 5 minutes, it seems reasonable.
-        owned = cache.get_or_create(owned_cache_key, get_owned, 5 * 60)
+        owned = get_owned_packages(username)
         return (component in owned)
diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index 51c46b5..02abde3 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -1,36 +1,14 @@
-"""
-Attributes:
-    cache (dogpile.cache.region.CacheRegion): The cache where function results
-        will be stored. It is configured with the ``fedora-hubs.cache`` key in
-        fedmsg configuration.
-"""
 from __future__ import unicode_literals
 
 import datetime
-import dogpile.cache
 import logging
 
-from hubs.utils import get_fedmsg_config
-
-
-log = logging.getLogger(__name__)
-
+import dogpile.cache
 
-def _get_cache():
-    cache_defaults = {
-        "backend": "dogpile.cache.dbm",
-        "expiration_time": 1,  # Expire every 1 second, for development
-        "arguments": {
-            "filename": "/var/tmp/fedora-hubs-cache.db",
-        },
-    }
-    cache = dogpile.cache.make_region()
-    fedmsg_config = get_fedmsg_config()
-    cache.configure(**fedmsg_config.get('fedora-hubs.cache', cache_defaults))
-    return cache
+from hubs.utils.cache import cache
 
 
-cache = _get_cache()
+log = logging.getLogger(__name__)
 
 
 class CachedFunction(object):
diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index 4339c04..75b4487 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -15,7 +15,7 @@ import argparse
 import hubs.app
 import hubs.models
 import hubs.widgets.base
-import hubs.widgets.caching
+
 
 # get the DB session
 session = hubs.app.session

From 8f273cca362f515430257ef4f39c89d7cb138df3 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 27 2017 16:25:38 +0000
Subject: [PATCH 891/1001] Add a parameter to control the number of issues to display


---

diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 7125aaf..2fc20a9 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -22,11 +22,17 @@ class Bugzilla(Widget):
     label = "Bugzilla issues"
     position = "right"
     parameters = [dict(
-        name="username",
-        label="Username",
-        default=None,
-        validator=validators.Username,
-        help="A FAS username.",
+            name="username",
+            label="Username",
+            default=None,
+            validator=validators.Username,
+            help="A FAS username.",
+        ), dict(
+            name="max",
+            label="Max number of issues",
+            default=3,
+            validator=validators.Integer,
+            help="The maximum number of issues to display.",
         )]
 
 
@@ -54,14 +60,15 @@ class GetIssues(CachedFunction):
 
     def execute(self):
         username = self.instance.config["username"]
+        max_num = int(self.instance.config("max", 3))
         owned = get_owned_packages(username)
         issues = []
         for pkg_name in owned:
-            if len(issues) == 3:
+            if len(issues) == max_num:
                 break
             pkg_details = pkgwat.api.bugs(pkg_name)
             for row in pkg_details['rows']:
-                if len(issues) == 3:
+                if len(issues) == max_num:
                     break
                 issues.append(
                     dict(

From f184ca5e241d005bc9aa47a0075056303ef584c4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 27 2017 16:25:38 +0000
Subject: [PATCH 892/1001] Add unit tests


---

diff --git a/hubs/tests/test_view_utils.py b/hubs/tests/test_view_utils.py
deleted file mode 100644
index ca49dac..0000000
--- a/hubs/tests/test_view_utils.py
+++ /dev/null
@@ -1,131 +0,0 @@
-from __future__ import unicode_literals
-
-import flask
-
-import hubs.models
-from hubs.app import app
-from hubs.tests import APPTest, FakeAuthorization, auth_set, app_config
-from hubs.utils.views import get_visible_widgets, get_sse_url
-
-
-class ViewUtilsTest(APPTest):
-
-    def setUp(self):
-        super(ViewUtilsTest, self).setUp()
-        self.app_context = app.app_context()
-        self.app_context.__enter__()
-
-    def tearDown(self):
-        self.app_context.__exit__(None, None, None)
-        super(ViewUtilsTest, self).tearDown()
-
-    def test_removed_widget(self):
-        hub = hubs.models.Hub.get("ralph")
-        widget = hubs.models.Widget(
-            hub=hub, plugin="does-not-exist",
-            left=True, index=-1, _config="{}")
-        self.session.add(widget)
-        with auth_set(app, FakeAuthorization('ralph')):
-            widgets = get_visible_widgets(hub)
-        self.assertNotIn(
-            "does-not-exist", [w.plugin for w in widgets["left"]])
-        widget.left = False
-        self.assertNotIn(
-            "does-not-exist", [w.plugin for w in widgets["right"]])
-
-    def test_get_visible_widgets(self):
-        hub = hubs.models.Hub.get('ralph')
-        with auth_set(app, None):
-            widgets = get_visible_widgets(hub)
-        self.assertListEqual(
-            [w.plugin for w in widgets["left"]],
-            ["feed"])
-        self.assertListEqual(
-            [w.plugin for w in widgets["right"]],
-            ['contact', 'meetings', 'fedmsgstats', 'workflow.updates2stable',
-             'workflow.pendingacls', 'subscriptions', 'badges', 'pagure_pr',
-             'github_pr', 'bugzilla', 'halp', 'about']
-            )
-
-    def test_get_visible_widgets_preview(self):
-        hub = hubs.models.Hub.by_name('ralph')
-        hub.config.visibility = "preview"
-        meetings = hubs.models.Widget.query.filter_by(
-            hub=hub, plugin="meetings").first()
-        # make sure the test is valid
-        assert meetings.left is False
-        # set the widget to "restricted"
-        meetings.visibility = "restricted"
-        # Restricted widgets in preview hubs aren't displayed to
-        # anonymous users.
-        with auth_set(app, None):
-            widgets = get_visible_widgets(hub)
-        self.assertNotIn(
-            "meetings", [w.plugin for w in widgets["right"]])
-        # But they are displayed to members.
-        with auth_set(app, FakeAuthorization('ralph')):
-            widgets = get_visible_widgets(hub)
-        self.assertIn(
-            "meetings", [w.plugin for w in widgets["right"]])
-
-    def test_get_visible_widgets_private(self):
-        hub = hubs.models.Hub.by_name('ralph')
-        hub.config.visibility = "private"
-        meetings = hubs.models.Widget.query.filter_by(
-            hub=hub, plugin="meetings").first()
-        # make sure the test is valid
-        assert meetings.left is False
-        # Widgets in private hubs aren't displayed to
-        # anonymous users.
-        with auth_set(app, None):
-            widgets = get_visible_widgets(hub)
-        self.assertEqual(widgets["left"], [])
-        self.assertEqual(widgets["right"], [])
-        # But they are displayed to members.
-        with auth_set(app, FakeAuthorization('ralph')):
-            widgets = get_visible_widgets(hub)
-        self.assertNotEqual(len(widgets["left"]), 0)
-        self.assertNotEqual(len(widgets["right"]), 0)
-
-    def test_sse_url(self):
-        with app.test_request_context():
-            self.assertEqual(get_sse_url(""), "http://localhost:8080/sse/")
-
-        with app.test_request_context():
-            self.assertEqual(
-                get_sse_url("hub/ralph"),
-                "http://localhost:8080/sse/hub/ralph")
-
-        with app.test_request_context(base_url='http://hubs.example.com/'):
-            self.assertEqual(
-                get_sse_url("hub/ralph"),
-                "http://hubs.example.com:8080/sse/hub/ralph")
-
-        with app.test_request_context(base_url='http://example.com/hubs'):
-            self.assertEqual(flask.url_for("index"), "/hubs/")  # test validity
-            self.assertEqual(
-                get_sse_url("hub/ralph"),
-                "http://example.com:8080/sse/hub/ralph")
-
-        with app.test_request_context(base_url='http://hubs.example.com/'):
-            with app_config(app, {
-                    "SSE_URL": {"host": "hubs-sse.example.com"}
-                    }):
-                self.assertEqual(
-                    get_sse_url("hub/ralph"),
-                    "http://hubs-sse.example.com/hub/ralph")
-
-        with app.test_request_context(base_url='http://hubs.example.com/'):
-            with app_config(app, {
-                    "SSE_URL": {"host": "hubs-sse.example.com",
-                                "port": 8080}
-                    }):
-                self.assertEqual(
-                    get_sse_url("hub/ralph"),
-                    "http://hubs-sse.example.com:8080/hub/ralph")
-
-        with app.test_request_context(base_url='http://localhost/hubs'):
-            with app_config(app, {"SSE_URL": {"host": "example.com"}}):
-                self.assertEqual(
-                    get_sse_url("hub/ralph"),
-                    "http://example.com/hub/ralph")
diff --git a/hubs/tests/utils/__init__.py b/hubs/tests/utils/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/tests/utils/__init__.py
diff --git a/hubs/tests/utils/test_pkgdb.py b/hubs/tests/utils/test_pkgdb.py
new file mode 100644
index 0000000..36f4905
--- /dev/null
+++ b/hubs/tests/utils/test_pkgdb.py
@@ -0,0 +1,50 @@
+from __future__ import unicode_literals
+
+import dogpile
+import dogpile.cache
+from mock import Mock, patch
+
+from hubs.tests import APPTest
+from hubs.utils.cache import cache
+from hubs.utils.pkgdb import get_owned_packages
+
+
+class PkgdbUtilsTest(APPTest):
+
+    def setUp(self):
+        super(PkgdbUtilsTest, self).setUp()
+        # Use a memory backend, not the default null backend, or we can't test
+        # the caching feature.
+        cache.configure(backend='dogpile.cache.memory',
+                        replace_existing_backend=True)
+        cache.delete("owned_packages:abompard")
+
+    def _is_cached(self):
+        result = cache.get("owned_packages:abompard", ignore_expiration=True)
+        return not isinstance(result, dogpile.cache.api.NoValue)
+
+    def test_get_owned_packages(self):
+        pkgs = get_owned_packages("abompard", use_cache=False)
+        self.assertEqual(len(pkgs), 42)  # not kidding! :-)
+        for pkg in pkgs:
+            self.assertEqual(type(pkg), type(""))
+        self.assertFalse(self._is_cached())
+
+    def test_get_owned_packages_invalid(self):
+        pkgs = get_owned_packages("abompard", use_cache=False)
+        self.assertListEqual(pkgs, [])
+
+    @patch("hubs.utils.pkgdb.requests")
+    def test_get_owned_packages_cache(self, requests):
+        response = Mock()
+        response.json.return_value = {
+            "point of contact": [],
+            "co-maintained": [],
+        }
+        requests.get.return_value = response
+        get_owned_packages("abompard", use_cache=True)
+        self.assertTrue(self._is_cached())
+        self.assertEqual(requests.get.call_count, 1)
+        get_owned_packages("abompard", use_cache=True)
+        self.assertTrue(self._is_cached())
+        self.assertEqual(requests.get.call_count, 1)
diff --git a/hubs/tests/utils/test_views.py b/hubs/tests/utils/test_views.py
new file mode 100644
index 0000000..ca49dac
--- /dev/null
+++ b/hubs/tests/utils/test_views.py
@@ -0,0 +1,131 @@
+from __future__ import unicode_literals
+
+import flask
+
+import hubs.models
+from hubs.app import app
+from hubs.tests import APPTest, FakeAuthorization, auth_set, app_config
+from hubs.utils.views import get_visible_widgets, get_sse_url
+
+
+class ViewUtilsTest(APPTest):
+
+    def setUp(self):
+        super(ViewUtilsTest, self).setUp()
+        self.app_context = app.app_context()
+        self.app_context.__enter__()
+
+    def tearDown(self):
+        self.app_context.__exit__(None, None, None)
+        super(ViewUtilsTest, self).tearDown()
+
+    def test_removed_widget(self):
+        hub = hubs.models.Hub.get("ralph")
+        widget = hubs.models.Widget(
+            hub=hub, plugin="does-not-exist",
+            left=True, index=-1, _config="{}")
+        self.session.add(widget)
+        with auth_set(app, FakeAuthorization('ralph')):
+            widgets = get_visible_widgets(hub)
+        self.assertNotIn(
+            "does-not-exist", [w.plugin for w in widgets["left"]])
+        widget.left = False
+        self.assertNotIn(
+            "does-not-exist", [w.plugin for w in widgets["right"]])
+
+    def test_get_visible_widgets(self):
+        hub = hubs.models.Hub.get('ralph')
+        with auth_set(app, None):
+            widgets = get_visible_widgets(hub)
+        self.assertListEqual(
+            [w.plugin for w in widgets["left"]],
+            ["feed"])
+        self.assertListEqual(
+            [w.plugin for w in widgets["right"]],
+            ['contact', 'meetings', 'fedmsgstats', 'workflow.updates2stable',
+             'workflow.pendingacls', 'subscriptions', 'badges', 'pagure_pr',
+             'github_pr', 'bugzilla', 'halp', 'about']
+            )
+
+    def test_get_visible_widgets_preview(self):
+        hub = hubs.models.Hub.by_name('ralph')
+        hub.config.visibility = "preview"
+        meetings = hubs.models.Widget.query.filter_by(
+            hub=hub, plugin="meetings").first()
+        # make sure the test is valid
+        assert meetings.left is False
+        # set the widget to "restricted"
+        meetings.visibility = "restricted"
+        # Restricted widgets in preview hubs aren't displayed to
+        # anonymous users.
+        with auth_set(app, None):
+            widgets = get_visible_widgets(hub)
+        self.assertNotIn(
+            "meetings", [w.plugin for w in widgets["right"]])
+        # But they are displayed to members.
+        with auth_set(app, FakeAuthorization('ralph')):
+            widgets = get_visible_widgets(hub)
+        self.assertIn(
+            "meetings", [w.plugin for w in widgets["right"]])
+
+    def test_get_visible_widgets_private(self):
+        hub = hubs.models.Hub.by_name('ralph')
+        hub.config.visibility = "private"
+        meetings = hubs.models.Widget.query.filter_by(
+            hub=hub, plugin="meetings").first()
+        # make sure the test is valid
+        assert meetings.left is False
+        # Widgets in private hubs aren't displayed to
+        # anonymous users.
+        with auth_set(app, None):
+            widgets = get_visible_widgets(hub)
+        self.assertEqual(widgets["left"], [])
+        self.assertEqual(widgets["right"], [])
+        # But they are displayed to members.
+        with auth_set(app, FakeAuthorization('ralph')):
+            widgets = get_visible_widgets(hub)
+        self.assertNotEqual(len(widgets["left"]), 0)
+        self.assertNotEqual(len(widgets["right"]), 0)
+
+    def test_sse_url(self):
+        with app.test_request_context():
+            self.assertEqual(get_sse_url(""), "http://localhost:8080/sse/")
+
+        with app.test_request_context():
+            self.assertEqual(
+                get_sse_url("hub/ralph"),
+                "http://localhost:8080/sse/hub/ralph")
+
+        with app.test_request_context(base_url='http://hubs.example.com/'):
+            self.assertEqual(
+                get_sse_url("hub/ralph"),
+                "http://hubs.example.com:8080/sse/hub/ralph")
+
+        with app.test_request_context(base_url='http://example.com/hubs'):
+            self.assertEqual(flask.url_for("index"), "/hubs/")  # test validity
+            self.assertEqual(
+                get_sse_url("hub/ralph"),
+                "http://example.com:8080/sse/hub/ralph")
+
+        with app.test_request_context(base_url='http://hubs.example.com/'):
+            with app_config(app, {
+                    "SSE_URL": {"host": "hubs-sse.example.com"}
+                    }):
+                self.assertEqual(
+                    get_sse_url("hub/ralph"),
+                    "http://hubs-sse.example.com/hub/ralph")
+
+        with app.test_request_context(base_url='http://hubs.example.com/'):
+            with app_config(app, {
+                    "SSE_URL": {"host": "hubs-sse.example.com",
+                                "port": 8080}
+                    }):
+                self.assertEqual(
+                    get_sse_url("hub/ralph"),
+                    "http://hubs-sse.example.com:8080/hub/ralph")
+
+        with app.test_request_context(base_url='http://localhost/hubs'):
+            with app_config(app, {"SSE_URL": {"host": "example.com"}}):
+                self.assertEqual(
+                    get_sse_url("hub/ralph"),
+                    "http://example.com/hub/ralph")
diff --git a/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages b/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages
new file mode 100644
index 0000000..764dd50
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages
@@ -0,0 +1,451 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://admin.fedoraproject.org/pkgdb/api/packager/package/abompard
+  response:
+    body: {string: "{\n  \"co-maintained\": [\n    {\n      \"acls\": [],\n      \"\
+        creation_date\": 1430239258.0,\n      \"description\": \"contextlib2 is a\
+        \ backport of the standard library's contextlib module to\\nearlier Python\
+        \ versions.\\n\\nIt also serves as a real world proving ground for possible\
+        \ future\\nenhancements to the standard library version.\",\n      \"koschei_monitor\"\
+        : false,\n      \"monitor\": true,\n      \"name\": \"python-contextlib2\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1210978\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Backports and enhancements\
+        \ for the contextlib module\",\n      \"upstream_url\": \"https://pypi.io/project/contextlib2\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"This is a lib package for use by pytest-cov, nose-cov\
+        \ and nose2-cov. If\\nyou're developing a coverage plugin for a test framework\
+        \ then you probably\\nwant one of those.\",\n      \"koschei_monitor\": false,\n\
+        \      \"monitor\": false,\n      \"name\": \"python-cov-core\",\n      \"\
+        namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\": \"\
+        Approved\",\n      \"summary\": \"Plugin core for use by pytest-cov, nose-cov\
+        \ and nose2-cov\",\n      \"upstream_url\": \"http://bitbucket.org/memedough/cov-core/overview\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"Coverage.py is a Python module that measures code\
+        \ coverage during Python\\nexecution. It uses the code analysis tools and\
+        \ tracing hooks provided in the\\nPython standard library to determine which\
+        \ lines are executable, and which\\nhave been executed.\",\n      \"koschei_monitor\"\
+        : false,\n      \"monitor\": true,\n      \"name\": \"python-coverage\",\n\
+        \      \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
+        : \"Approved\",\n      \"summary\": \"Code coverage testing module for Python\"\
+        ,\n      \"upstream_url\": \"http://nedbatchelder.com/code/modules/coverage.html\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1437659169.0,\n\
+        \      \"description\": \"DDT (Data-Driven Tests) allows you to multiply one\
+        \ test case by running it with\\ndifferent test data, and make it appear as\
+        \ multiple test cases. It is used in\\ncombination with other testing frameworks\
+        \ like unittest and nose.\",\n      \"koschei_monitor\": true,\n      \"monitor\"\
+        : true,\n      \"name\": \"python-ddt\",\n      \"namespace\": \"rpms\",\n\
+        \      \"review_url\": \"https://bugzilla.redhat.com/1244014\",\n      \"\
+        status\": \"Approved\",\n      \"summary\": \"Python library to multiply test\
+        \ cases\",\n      \"upstream_url\": \"https://github.com/txels/ddt\"\n   \
+        \ },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"Falcon is a high-performance Python framework for\
+        \ building cloud APIs.\\nIt encourages the REST architectural style, and tries\
+        \ to do as little as\\npossible while remaining highly effective.\",\n   \
+        \   \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
+        : \"python-falcon\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
+        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"An unladen\
+        \ web framework for building APIs and app backends\",\n      \"upstream_url\"\
+        : \"https://falconframework.org\"\n    },\n    {\n      \"acls\": [],\n  \
+        \    \"creation_date\": 1400070978.0,\n      \"description\": \"A comprehensive\
+        \ HTTP client library that supports many features left out of\\nother HTTP\
+        \ libraries.\",\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n\
+        \      \"name\": \"python-httplib2\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"review_url\": null,\n      \"status\": \"Approved\",\n      \"summary\"\
+        : \"A comprehensive HTTP client library\",\n      \"upstream_url\": \"https://pypi.python.org/pypi/httplib2\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"This module provides basic functions for parsing\
+        \ mime-type names\\nand matching them against a list of media-ranges.\",\n\
+        \      \"koschei_monitor\": false,\n      \"monitor\": false,\n      \"name\"\
+        : \"python-mimeparse\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
+        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"Python module\
+        \ for parsing mime-type names\",\n      \"upstream_url\": \"https://github.com/dbtsai/python-mimeparse\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"Passlib is a password hashing library for Python\
+        \ 2 & 3, which provides\\ncross-platform implementations of over 20 password\
+        \ hashing algorithms,\\nas well as a framework for managing existing password\
+        \ hashes. It's\\ndesigned to be useful for a wide range of tasks, from verifying\
+        \ a hash\\nfound in /etc/shadow, to providing full-strength password hashing\
+        \ for\\nmulti-user application.\",\n      \"koschei_monitor\": false,\n  \
+        \    \"monitor\": true,\n      \"name\": \"python-passlib\",\n      \"namespace\"\
+        : \"rpms\",\n      \"review_url\": null,\n      \"status\": \"Approved\",\n\
+        \      \"summary\": \"Comprehensive password hashing framework supporting\
+        \ over 20 schemes\",\n      \"upstream_url\": \"https://bitbucket.org/ecollins/passlib\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1462278195.0,\n\
+        \      \"description\": \"A fork of SocksiPy with bug fixes and extra features.\\\
+        n\\nActs as a drop-in replacement to the socket module. Featuring:\\n\\n-\
+        \ SOCKS proxy client for Python 2.6 - 3.x\\n- TCP and UDP both supported\\\
+        n- HTTP proxy client included but not supported or recommended (you should\
+        \ use\\n  urllib2's or requests' own HTTP proxy interface)\\n- urllib2 handler\
+        \ included.\",\n      \"koschei_monitor\": true,\n      \"monitor\": \"nobuild\"\
+        ,\n      \"name\": \"python-pysocks\",\n      \"namespace\": \"rpms\",\n \
+        \     \"review_url\": \"https://bugzilla.redhat.com/1332206\",\n      \"status\"\
+        : \"Approved\",\n      \"summary\": \"A Python SOCKS client module\",\n  \
+        \    \"upstream_url\": \"https://github.com/Anorov/PySocks\"\n    },\n   \
+        \ {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"\
+        description\": \"testtools is a set of extensions to the Python standard library's\
+        \ unit testing\\nframework.\",\n      \"koschei_monitor\": false,\n      \"\
+        monitor\": true,\n      \"name\": \"python-testtools\",\n      \"namespace\"\
+        : \"rpms\",\n      \"review_url\": null,\n      \"status\": \"Approved\",\n\
+        \      \"summary\": \"Extensions to the Python unit testing framework\",\n\
+        \      \"upstream_url\": \"https://launchpad.net/testtools\"\n    },\n   \
+        \ {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"\
+        description\": \"This package represents the core of the Zope Component Architecture.\\\
+        nTogether with the 'zope.interface' package, it provides facilities for\\\
+        ndefining, registering and looking up components.\",\n      \"koschei_monitor\"\
+        : false,\n      \"monitor\": true,\n      \"name\": \"python-zope-component\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
+        : \"Approved\",\n      \"summary\": \"Zope Component Architecture\",\n   \
+        \   \"upstream_url\": \"https://pypi.io/project/zope.component\"\n    },\n\
+        \    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n    \
+        \  \"description\": \"The zope configuration system provides an extensible\
+        \ system for supporting\\nvarious kinds of configurations.\\n\\nIt is based\
+        \ on the idea of configuration directives. Users of the configuration\\nsystem\
+        \ provide configuration directives in some language that express\\nconfiguration\
+        \ choices. The intent is that the language be pluggable. An XML\\nlanguage\
+        \ is provided by default.\",\n      \"koschei_monitor\": true,\n      \"monitor\"\
+        : true,\n      \"name\": \"python-zope-configuration\",\n      \"namespace\"\
+        : \"rpms\",\n      \"review_url\": null,\n      \"status\": \"Approved\",\n\
+        \      \"summary\": \"Zope Configuration Markup Language (ZCML)\",\n     \
+        \ \"upstream_url\": \"https://github.com/zopefoundation/zope.configuration\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"The zope.event package provides a simple event system.\
+        \ It provides\\nan event publishing system and a very simple event-dispatching\
+        \ system\\non which more sophisticated event dispatching systems can be built.\\\
+        n(For example, a type-based event dispatching system that builds on\\nzope.event\
+        \ can be found in zope.component.)\",\n      \"koschei_monitor\": false,\n\
+        \      \"monitor\": true,\n      \"name\": \"python-zope-event\",\n      \"\
+        namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\": \"\
+        Approved\",\n      \"summary\": \"Zope Event Publication\",\n      \"upstream_url\"\
+        : \"http://pypi.python.org/pypi/zope.event/\"\n    },\n    {\n      \"acls\"\
+        : [],\n      \"creation_date\": 1400070978.0,\n      \"description\": \"This\
+        \ package contains exception interfaces and implementations which are so\\\
+        ngeneral purpose that they don't belong in Zope application-specific packages.\"\
+        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
+        : \"python-zope-exceptions\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
+        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope Exceptions\"\
+        ,\n      \"upstream_url\": \"http://pypi.python.org/pypi/zope.exceptions\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"This module provides message identifiers for internationalization.\"\
+        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
+        : \"python-zope-i18nmessageid\",\n      \"namespace\": \"rpms\",\n      \"\
+        review_url\": null,\n      \"status\": \"Approved\",\n      \"summary\": \"\
+        Message Identifiers for internationalization\",\n      \"upstream_url\": \"\
+        http://pypi.python.org/pypi/zope.i18nmessageid\"\n    },\n    {\n      \"\
+        acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
+        : \"This package is a zope.interface extension for defining data schemas.\"\
+        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
+        : \"python-zope-schema\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
+        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope 3 schemas\"\
+        ,\n      \"upstream_url\": \"http://pypi.python.org/pypi/zope.schema\"\n \
+        \   },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"This package provides a number of testing frameworks.\
+        \ It includes a\\nflexible test runner, and supports both doctest and unittest.\"\
+        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
+        : \"python-zope-testing\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
+        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope Testing\
+        \ Framework\",\n      \"upstream_url\": \"https://pypi.io/project/zope.testing\"\
+        \n    }\n  ],\n  \"output\": \"ok\",\n  \"point of contact\": [\n    {\n \
+        \     \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
+        : \"Grisbi is a very functional personal financial management program\\nwith\
+        \ a lot of features: checking, cash and liabilities accounts,\\nseveral accounts\
+        \ with automatic contra entries, several currencies,\\nincluding euro, arbitrary\
+        \ currency for every operation, money\\ninterchange fees, switch to euro account\
+        \ per account, description\\nof the transactions with third parties, categories,\
+        \ sub-categories,\\nfinancial year, notes, breakdown, transfers between accounts,\
+        \ even\\nfor accounts of different currencies, bank reconciliation, scheduled\\\
+        ntransactions, automatic recall of last transaction for every third\\nparty,\
+        \ nice and easy user interface, user manual, QIF import/export.\",\n     \
+        \ \"koschei_monitor\": false,\n      \"monitor\": false,\n      \"name\":\
+        \ \"grisbi\",\n      \"namespace\": \"rpms\",\n      \"review_url\": null,\n\
+        \      \"status\": \"Approved\",\n      \"summary\": \"Personal finances manager\"\
+        ,\n      \"upstream_url\": \"http://www.grisbi.org\"\n    },\n    {\n    \
+        \  \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
+        : \"KeePassX is an application for people with extremly high demands on secure\\\
+        npersonal data management.\\nKeePassX saves many different information e.g.\
+        \ user names, passwords, urls,\\nattachemts and comments in one single database.\
+        \ For a better management\\nuser-defined titles and icons can be specified\
+        \ for each single entry.\\nFurthermore the entries are sorted in groups, which\
+        \ are customizable as well.\\nThe integrated search function allows to search\
+        \ in a single group or the\\ncomplete database.\\nKeePassX offers a little\
+        \ utility for secure password generation. The password\\ngenerator is very\
+        \ customizable, fast and easy to use. Especially someone who\\ngenerates passwords\
+        \ frequently will appreciate this feature.\\nThe complete database is always\
+        \ encrypted either with AES (alias Rijndael) or\\nTwofish encryption algorithm\
+        \ using a 256 bit key. Therefore the saved\\ninformation can be considered\
+        \ as quite safe. KeePassX uses a database format\\nthat is compatible with\
+        \ KeePass Password Safe v2 for MS Windows.\",\n      \"koschei_monitor\":\
+        \ false,\n      \"monitor\": false,\n      \"name\": \"keepassx\",\n     \
+        \ \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
+        : \"Approved\",\n      \"summary\": \"Cross-platform password manager\",\n\
+        \      \"upstream_url\": \"http://www.keepassx.org/\"\n    },\n    {\n   \
+        \   \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
+        : \"A ssh-add helper that uses kwallet and kpassworddialog.\",\n      \"koschei_monitor\"\
+        : false,\n      \"monitor\": true,\n      \"name\": \"ksshaskpass\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
+        : \"Approved\",\n      \"summary\": \"A ssh-add helper that uses kwallet and\
+        \ kpassworddialog\",\n      \"upstream_url\": \"https://cgit.kde.org/ksshaskpass.git\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1474548104.0,\n\
+        \      \"description\": \"Libsass is a C/C++ port of the Sass CSS precompiler.\
+        \ The original version was\\nwritten in Ruby, but this version is meant for\
+        \ efficiency and portability.\\n\\nThis library strives to be light, simple,\
+        \ and easy to build and integrate with\\na variety of platforms and languages.\\\
+        n\\nLibsass is just a library, but if you want to RUN libsass, install the\
+        \ sassc\\npackage.\",\n      \"koschei_monitor\": true,\n      \"monitor\"\
+        : true,\n      \"name\": \"libsass\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"review_url\": \"https://bugzilla.redhat.com/1369534\",\n      \"status\"\
+        : \"Approved\",\n      \"summary\": \"C/C++ port of the Sass CSS precompiler\"\
+        ,\n      \"upstream_url\": \"http://sass-lang.com/libsass\"\n    },\n    {\n\
+        \      \"acls\": [],\n      \"creation_date\": 1496666386.0,\n      \"description\"\
+        : \"This is a server for SMTP and related protocols, similar in utility\\\
+        r\\nto the standard library\\u2019s smtpd.py module, but rewritten to be based\\\
+        r\\non asyncio for Python 3.\",\n      \"koschei_monitor\": true,\n      \"\
+        monitor\": true,\n      \"name\": \"python-aiosmtpd\",\n      \"namespace\"\
+        : \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1404883\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Asyncio-based SMTP\
+        \ server\",\n      \"upstream_url\": \"https://github.com/aio-libs/aiosmtpd\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1496666324.0,\n\
+        \      \"description\": \"This is a very simple decorator and function which\
+        \ populates a \\r\\nmodule's __all__ and optionally the module globals. \\\
+        r\\nThis provides both a pure-Python implementation and a C implementation.\
+        \ \\r\\nIt is proposed that the C implementation be added to built-ins for\
+        \ \\r\\nPython 3.6.\",\n      \"koschei_monitor\": true,\n      \"monitor\"\
+        : true,\n      \"name\": \"python-atpublic\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"review_url\": \"https://bugzilla.redhat.com/1404882\",\n      \"\
+        status\": \"Approved\",\n      \"summary\": \"Decorator for populating a Python\
+        \ module's __all__\",\n      \"upstream_url\": \"http://public.readthedocs.io\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1496666808.0,\n\
+        \      \"description\": \"Blessed is a thin, practical wrapper around terminal\
+        \ styling, screen\\r\\npositioning, and keyboard input.\",\n      \"koschei_monitor\"\
+        : true,\n      \"monitor\": true,\n      \"name\": \"python-blessed\",\n \
+        \     \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1435986\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"A thin, practical\
+        \ wrapper around terminal capabilities in Python\",\n      \"upstream_url\"\
+        : \"https://pypi.python.org/pypi/blessed\"\n    },\n    {\n      \"acls\"\
+        : [],\n      \"creation_date\": 1476188786.0,\n      \"description\": \"The\
+        \ flufl.bounce library provides a set of heuristics and an API for\\ndetecting\
+        \ the original bouncing email addresses from a bounce message.  Many\\nformats\
+        \ found in the wild are supported, as are VERP and RFC 3464 (DSN).\",\n  \
+        \    \"koschei_monitor\": true,\n      \"monitor\": true,\n      \"name\"\
+        : \"python-flufl-bounce\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
+        : \"https://bugzilla.redhat.com/1375999\",\n      \"status\": \"Approved\"\
+        ,\n      \"summary\": \"Email bounce detectors\",\n      \"upstream_url\"\
+        : \"https://gitlab.com/warsaw/flufl.bounce\"\n    },\n    {\n      \"acls\"\
+        : [],\n      \"creation_date\": 1476188935.0,\n      \"description\": \"The\
+        \ ``flufl.i18n`` library provides a convenient API for managing translation\\\
+        ncontexts in Python applications. It provides facilities not only for\\nsingle-context\
+        \ applications like command line scripts, but also more\\nsophisticated management\
+        \ of multiple-context applications such as Internet\\nservers.\",\n      \"\
+        koschei_monitor\": true,\n      \"monitor\": true,\n      \"name\": \"python-flufl-i18n\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1375993\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"A high level API\
+        \ for Python internationalization\",\n      \"upstream_url\": \"https://gitlab.com/warsaw/flufl.i18n\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1476188827.0,\n\
+        \      \"description\": \"The flufl.lock library provides an NFS-safe file-based\
+        \ locking algorithm\\ninfluenced by the GNU/Linux \\\"open(2)\\\" man page,\
+        \ under the description of\\nthe \\\"O_EXCL\\\" option.\",\n      \"koschei_monitor\"\
+        : true,\n      \"monitor\": true,\n      \"name\": \"python-flufl-lock\",\n\
+        \      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1376001\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"NFS-safe file locking\
+        \ with timeouts for POSIX systems\",\n      \"upstream_url\": \"https://gitlab.com/warsaw/flufl.lock\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1481720827.0,\n\
+        \      \"description\": \"This package contains a small collection of test\
+        \ helpers that Barry Warsaw\\nuses in almost all his packages. Specifically,\
+        \ plugins for the following\\ntest tools are provided:\\n- nose2\\n- flake8\\\
+        nPython 3.4 is the minimum supported version.\",\n      \"koschei_monitor\"\
+        : true,\n      \"monitor\": true,\n      \"name\": \"python-flufl-testing\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1401582\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Small collection\
+        \ of test tool plugins\",\n      \"upstream_url\": \"https://gitlab.com/warsaw/flufl.testing\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1481720722.0,\n\
+        \      \"description\": \"The LAZR config system is typically used to manage\
+        \ process configuration.\\nProcess configuration is for saying how things\
+        \ change when we run systems on\\ndifferent machines, or under different circumstances.\\\
+        n\\nThis system uses ini-like file format of section, keys, and values. The\
+        \ config\\nfile supports inheritance to minimize duplication of information\
+        \ across files.\\nThe format supports schema validation.\",\n      \"koschei_monitor\"\
+        : true,\n      \"monitor\": true,\n      \"name\": \"python-lazr-config\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1387518\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Create configuration\
+        \ schemas, and process and validate configurations\",\n      \"upstream_url\"\
+        : \"https://launchpad.net/lazr.config\"\n    },\n    {\n      \"acls\": [],\n\
+        \      \"creation_date\": 1477410675.0,\n      \"description\": \"The lazr.delegates\
+        \ package makes it easy to write objects that delegate\\nbehavior to another\
+        \ object. The new object adds some property or behavior on\\nto the other\
+        \ object, while still providing the underlying interface, and\\ndelegating\
+        \ behavior.\",\n      \"koschei_monitor\": true,\n      \"monitor\": true,\n\
+        \      \"name\": \"python-lazr-delegates\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"review_url\": \"https://bugzilla.redhat.com/1387291\",\n      \"\
+        status\": \"Approved\",\n      \"summary\": \"Easily write objects that delegate\
+        \ behavior\",\n      \"upstream_url\": \"https://launchpad.net/lazr.delegates\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1479219121.0,\n\
+        \      \"description\": \"This is LAZR smtptest, a framework for testing SMTP-based\
+        \ applications and\\nlibraries. It provides a real, live SMTP server that\
+        \ you can send messages\\nto, and from which you can read those test messages.\
+        \ This can be used to\\nensure proper operation of your applications which\
+        \ send email.\",\n      \"koschei_monitor\": true,\n      \"monitor\": true,\n\
+        \      \"name\": \"python-lazr-smtptest\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"review_url\": \"https://bugzilla.redhat.com/1387250\",\n      \"\
+        status\": \"Approved\",\n      \"summary\": \"Test framework for SMTP-based\
+        \ applications\",\n      \"upstream_url\": \"https://launchpad.net/lazr.smtptest\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"Mako is a template library written in Python. It\
+        \ provides a familiar, non-XML\\nsyntax which compiles into Python modules\
+        \ for maximum performance. Mako's\\nsyntax and API borrows from the best ideas\
+        \ of many others, including Django\\ntemplates, Cheetah, Myghty, and Genshi.\
+        \ Conceptually, Mako is an embedded\\nPython (i.e. Python Server Page) language,\
+        \ which refines the familiar ideas of\\ncomponentized layout and inheritance\
+        \ to produce one of the most straightforward\\nand flexible models available,\
+        \ while also maintaining close ties to Python\\ncalling and scoping semantics.\"\
+        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
+        : \"python-mako\",\n      \"namespace\": \"rpms\",\n      \"review_url\":\
+        \ null,\n      \"status\": \"Approved\",\n      \"summary\": \"Mako template\
+        \ library for Python\",\n      \"upstream_url\": \"http://www.makotemplates.org/\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1474373839.0,\n\
+        \      \"description\": \"nose2 is the next generation of nicer testing for\
+        \ Python, based on the plugins\\nbranch of unittest2. nose2 aims to improve\
+        \ on nose by:\\n- providing a better plugin API\\n- being easier for users\
+        \ to configure\\n- simplifying internal interfaces and processes\\n- supporting\
+        \ Python 2 and 3 from the same codebase, without translation\\n- encouraging\
+        \ greater community involvement in its development\\n\\nIn service of some\
+        \ those goals, some features of nose will not be supported in\\nnose2. See\
+        \ the documentation for a thorough rundown.\",\n      \"koschei_monitor\"\
+        : true,\n      \"monitor\": true,\n      \"name\": \"python-nose2\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1375926\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Next generation of\
+        \ nicer testing for Python\",\n      \"upstream_url\": \"https://nose2.readthedocs.org\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"pylibmc is a client in Python for memcached. It\
+        \ is a wrapper\\naround TangentOrg\\u2018s libmemcached library. The interface\
+        \ is\\nintentionally made as close to python-memcached as possible,\\nso that\
+        \ applications can drop-in replace it.\",\n      \"koschei_monitor\": false,\n\
+        \      \"monitor\": false,\n      \"name\": \"python-pylibmc\",\n      \"\
+        namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\": \"\
+        Approved\",\n      \"summary\": \"Memcached client for Python\",\n      \"\
+        upstream_url\": \"http://sendapatch.se/projects/pylibmc/\"\n    },\n    {\n\
+        \      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
+        : \"Most existing Python modules for sending HTTP requests are extremely verbose\
+        \ and\\ncumbersome. Python\\u2019s built-in urllib2 module provides most of\
+        \ the HTTP\\ncapabilities you should need, but the API is thoroughly broken.\
+        \ This library is\\ndesigned to make HTTP requests easy for developers.\"\
+        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
+        : \"python-requests\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
+        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"HTTP library,\
+        \ written in Python, for human beings\",\n      \"upstream_url\": \"https://pypi.io/project/requests\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"Tornado is an open source version of the scalable,\
+        \ non-blocking web\\nserver and tools.\\n\\nThe framework is distinct from\
+        \ most mainstream web server frameworks\\n(and certainly most Python frameworks)\
+        \ because it is non-blocking and\\nreasonably fast. Because it is non-blocking\
+        \ and uses epoll, it can\\nhandle thousands of simultaneous standing connections,\
+        \ which means it is\\nideal for real-time web services.\",\n      \"koschei_monitor\"\
+        : true,\n      \"monitor\": true,\n      \"name\": \"python-tornado\",\n \
+        \     \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
+        : \"Approved\",\n      \"summary\": \"Scalable, non-blocking web server and\
+        \ tools\",\n      \"upstream_url\": \"http://www.tornadoweb.org\"\n    },\n\
+        \    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n    \
+        \  \"description\": \"Python HTTP module with connection pooling and file\
+        \ POST abilities.\",\n      \"koschei_monitor\": false,\n      \"monitor\"\
+        : true,\n      \"name\": \"python-urllib3\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"review_url\": null,\n      \"status\": \"Approved\",\n      \"\
+        summary\": \"Python HTTP library with thread-safe connection pooling and file\
+        \ post\",\n      \"upstream_url\": \"https://github.com/shazow/urllib3\"\n\
+        \    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
+        \      \"description\": \"Werkzeug\\n========\\n\\nWerkzeug started as simple\
+        \ collection of various utilities for WSGI\\napplications and has become one\
+        \ of the most advanced WSGI utility\\nmodules.  It includes a powerful debugger,\
+        \ full featured request and\\nresponse objects, HTTP utilities to handle entity\
+        \ tags, cache control\\nheaders, HTTP dates, cookie handling, file uploads,\
+        \ a powerful URL\\nrouting system and a bunch of community contributed addon\
+        \ modules.\\n\\nWerkzeug is unicode aware and doesn't enforce a specific template\\\
+        nengine, database adapter or anything else.  It doesn't even enforce\\na specific\
+        \ way of handling requests and leaves all that up to the\\ndeveloper. It's\
+        \ most useful for end user applications which should work\\non as many server\
+        \ environments as possible (such as blogs, wikis,\\nbulletin boards, etc.).\"\
+        ,\n      \"koschei_monitor\": true,\n      \"monitor\": true,\n      \"name\"\
+        : \"python-werkzeug\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
+        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"The Swiss Army\
+        \ knife of Python web development\",\n      \"upstream_url\": \"http://werkzeug.pocoo.org/\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1465852253.0,\n\
+        \      \"description\": \"This package provides a flexible test runner with\
+        \ layer support.\",\n      \"koschei_monitor\": true,\n      \"monitor\":\
+        \ true,\n      \"name\": \"python-zope-testrunner\",\n      \"namespace\"\
+        : \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1341815\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope testrunner script\"\
+        ,\n      \"upstream_url\": \"https://pypi.python.org/pypi/zope.testrunner\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1481116746.0,\n\
+        \      \"description\": \"The zope.event package provides a simple event system.\
+        \ It provides\\nan event publishing system and a very simple event-dispatching\
+        \ system\\non which more sophisticated event dispatching systems can be built.\\\
+        n(For example, a type-based event dispatching system that builds on\\nzope.event\
+        \ can be found in zope.component.)\",\n      \"koschei_monitor\": true,\n\
+        \      \"monitor\": true,\n      \"name\": \"python3-zope-event\",\n     \
+        \ \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1395244\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope Event Publication\"\
+        ,\n      \"upstream_url\": \"http://pypi.python.org/pypi/zope.event/\"\n \
+        \   },\n    {\n      \"acls\": [],\n      \"creation_date\": 1481289213.0,\n\
+        \      \"description\": \"Interfaces are a mechanism for labeling objects\
+        \ as conforming to a given API\\nor contract.\\nThis is a separate distribution\
+        \ of the zope.interface package used in Zope 3.\",\n      \"koschei_monitor\"\
+        : true,\n      \"monitor\": true,\n      \"name\": \"python3-zope-interface\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1395255\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope 3 Interface\
+        \ Infrastructure\",\n      \"upstream_url\": \"https://pypi.io/project/zope.interface\"\
+        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1479138409.0,\n\
+        \      \"description\": \"SassC is a wrapper around libsass used to generate\
+        \ a useful command-line\\napplication that can be installed and packaged for\
+        \ several operating systems.\",\n      \"koschei_monitor\": true,\n      \"\
+        monitor\": true,\n      \"name\": \"sassc\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"review_url\": \"https://bugzilla.redhat.com/1369535\",\n      \"\
+        status\": \"Approved\",\n      \"summary\": \"Wrapper around libsass to compile\
+        \ CSS stylesheet\",\n      \"upstream_url\": \"http://github.com/sass/sassc\"\
+        \n    }\n  ],\n  \"watch\": [\n    {\n      \"acls\": [],\n      \"creation_date\"\
+        : 1400070978.0,\n      \"description\": \"Advanced Web Statistics is a powerful\
+        \ and featureful tool that generates\\nadvanced web server graphic statistics.\
+        \ This server log analyzer works\\nfrom command line or as a CGI and shows\
+        \ you all information your log contains,\\nin graphical web pages. It can\
+        \ analyze a lot of web/wap/proxy servers like\\nApache, IIS, Weblogic, Webstar,\
+        \ Squid, ... but also mail or ftp servers.\\n\\nThis program can measure visits,\
+        \ unique vistors, authenticated users, pages,\\ndomains/countries, OS busiest\
+        \ times, robot visits, type of files, search\\nengines/keywords used, visits\
+        \ duration, HTTP errors and more...\\nStatistics can be updated from a browser\
+        \ or your scheduler.\\nThe program also supports virtual servers, plugins\
+        \ and a lot of features.\\n\\nWith the default configuration, the statistics\
+        \ are available:\\nhttp://localhost/awstats/awstats.pl\",\n      \"koschei_monitor\"\
+        : true,\n      \"monitor\": true,\n      \"name\": \"awstats\",\n      \"\
+        namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\": \"\
+        Approved\",\n      \"summary\": \"Advanced Web Statistics\",\n      \"upstream_url\"\
+        : \"http://awstats.sourceforge.net\"\n    },\n    {\n      \"acls\": [],\n\
+        \      \"creation_date\": 1452111332.0,\n      \"description\": \"This API\
+        \ is mainly for Terminal Emulator implementors, or those writing programs\\\
+        nthat expect to interpreted by a terminal emulator and wish to determine the\\\
+        nprintable width of a string on a Terminal.\",\n      \"koschei_monitor\"\
+        : true,\n      \"monitor\": true,\n      \"name\": \"python-wcwidth\",\n \
+        \     \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1295152\"\
+        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Measures number of\
+        \ Terminal column cells of wide-character codes\",\n      \"upstream_url\"\
+        : \"https://github.com/jquast/wcwidth\"\n    }\n  ]\n}"}
+    headers:
+      Accept-Ranges: [bytes]
+      Age: ['0']
+      AppServer: [proxy06.fedoraproject.org]
+      AppTime: [D=293465]
+      Connection: [Keep-Alive]
+      Content-Length: ['30176']
+      Content-Type: [application/json]
+      Date: ['Thu, 15 Jun 2017 15:04:24 GMT']
+      Keep-Alive: ['timeout=15, max=500']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      Set-Cookie: ['pkgdb=eyJfcGVybWFuZW50Ijp0cnVlfQ.DCQzeA.1B01lt3fuPret9GeJCOsCK6JptU;
+          Expires=Thu, 15-Jun-2017 16:04:24 GMT; Secure; HttpOnly; Path=/pkgdb/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+      Via: [1.1 varnish-v4]
+      X-Varnish: ['23219393']
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages_invalid b/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages_invalid
new file mode 100644
index 0000000..fd196e2
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages_invalid
@@ -0,0 +1,30 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.13.0]
+    method: GET
+    uri: https://admin.fedoraproject.org/pkgdb/api/packager/package/abompard
+  response:
+    body: {string: "this is invalid"}
+    headers:
+      Accept-Ranges: [bytes]
+      Age: ['0']
+      AppServer: [proxy06.fedoraproject.org]
+      AppTime: [D=293465]
+      Connection: [Keep-Alive]
+      Content-Length: ['30176']
+      Content-Type: [application/json]
+      Date: ['Thu, 15 Jun 2017 15:04:24 GMT']
+      Keep-Alive: ['timeout=15, max=500']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
+      Set-Cookie: ['pkgdb=eyJfcGVybWFuZW50Ijp0cnVlfQ.DCQzeA.1B01lt3fuPret9GeJCOsCK6JptU;
+          Expires=Thu, 15-Jun-2017 16:04:24 GMT; Secure; HttpOnly; Path=/pkgdb/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+      Via: [1.1 varnish-v4]
+      X-Varnish: ['23219393']
+    status: {code: 200, message: OK}
+version: 1

From e432d0ca16bcf0e6a8ba9dffcbb14afc17eb213a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 27 2017 16:25:38 +0000
Subject: [PATCH 893/1001] Update documentation


---

diff --git a/docs/api/index.rst b/docs/api/index.rst
index 90ec30e..605cf11 100644
--- a/docs/api/index.rst
+++ b/docs/api/index.rst
@@ -6,6 +6,6 @@ This documents ways developers can interface with Fedora Hubs.
 .. toctree::
    :maxdepth: 2
 
-   views
    widgets
+   utils
    auth
diff --git a/docs/api/utils.rst b/docs/api/utils.rst
new file mode 100644
index 0000000..e178be4
--- /dev/null
+++ b/docs/api/utils.rst
@@ -0,0 +1,21 @@
+Utilities
+=========
+
+View utils
+----------
+
+.. automodule:: hubs.utils.views
+   :members:
+
+Caching utils
+-------------
+
+.. automodule:: hubs.utils.cache
+   :members:
+
+Packages database utils
+-----------------------
+
+.. automodule:: hubs.utils.pkgdb
+   :members:
+
diff --git a/docs/api/views.rst b/docs/api/views.rst
deleted file mode 100644
index 4c205af..0000000
--- a/docs/api/views.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Views
-=====
-
-View utils
-----------
-
-.. automodule:: hubs.utils.views
-   :members:
-

From 2476aa90611070545a534c9adae851005c0ef893 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 27 2017 16:25:38 +0000
Subject: [PATCH 894/1001] Compatibility with Python < 3.5


---

diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 3e5ab7c..fe86e40 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -1,7 +1,5 @@
 from __future__ import unicode_literals
 
-import json
-
 import flask
 import fedmsg.config
 import fedmsg.meta
@@ -60,7 +58,7 @@ class GetStats(CachedFunction):
         try:
             response = requests.get(url, timeout=5)
             fedmsgs = response.json()['total']
-        except (requests.exceptions.Timeout, json.decoder.JSONDecodeError):
+        except (requests.exceptions.Timeout, ValueError):
             fedmsgs = None
             fedmsgs_text = "?"
         else:

From eb343263c4188bfbbab3924b975c6a8ff79569a7 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 27 2017 16:55:07 +0000
Subject: [PATCH 895/1001] Ansible role: add a parameter for the SSL cert


---

diff --git a/ansible/roles/hubs/defaults/main.yml b/ansible/roles/hubs/defaults/main.yml
index 3f5cb63..2ee3221 100644
--- a/ansible/roles/hubs/defaults/main.yml
+++ b/ansible/roles/hubs/defaults/main.yml
@@ -10,3 +10,5 @@ hubs_db_type: sqlite
 hubs_db_password: changeme
 hubs_url_hostname: localhost
 hubs_url: http{% if not hubs_dev_mode %}s{% endif %}://{{ hubs_url_hostname }}{% if hubs_dev_mode %}:5000{% endif %}
+hubs_ssl_cert: /etc/pki/tls/certs/localhost.crt
+hubs_ssl_key: /etc/pki/tls/private/localhost.key
diff --git a/ansible/roles/hubs/templates/nginx_ssl_params b/ansible/roles/hubs/templates/nginx_ssl_params
index d97125f..c8ab38d 100644
--- a/ansible/roles/hubs/templates/nginx_ssl_params
+++ b/ansible/roles/hubs/templates/nginx_ssl_params
@@ -1,3 +1,3 @@
 ssl                  on;
-ssl_certificate      /etc/pki/tls/certs/localhost.crt;
-ssl_certificate_key  /etc/pki/tls/private/localhost.key;
+ssl_certificate      {{ hubs_ssl_cert }};
+ssl_certificate_key  {{ hubs_ssl_key }};

From 794e22e5cc4c8c6d5d1bc1de3533cdca9b6d6c9c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 28 2017 05:21:04 +0000
Subject: [PATCH 896/1001] Fix typo


---

diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 2fc20a9..b55f1e8 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -60,7 +60,7 @@ class GetIssues(CachedFunction):
 
     def execute(self):
         username = self.instance.config["username"]
-        max_num = int(self.instance.config("max", 3))
+        max_num = int(self.instance.config.get("max", 3))
         owned = get_owned_packages(username)
         issues = []
         for pkg_name in owned:

From 12876580b3c62361c2adac6e831ddf9b429af3e6 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 28 2017 05:21:30 +0000
Subject: [PATCH 897/1001] One more small fix to the ansible role


---

diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index a2ee9f5..b2de8bd 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -108,6 +108,7 @@
     creates: "{{ hubs_venv_dir }}/lib/python2.7/site-packages/fedora-hubs.egg-link"
 
 - name: Set bin file context in the virtualenv
+  become_user: "{{ main_user }}"
   file:
     path: "{{ hubs_venv_dir }}/bin"
     state: directory

From c41966d896894ce0e506e8f92a81839ff4578000 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jun 28 2017 07:07:20 +0000
Subject: [PATCH 898/1001] Ansible role: better defaults


---

diff --git a/ansible/roles/hubs/defaults/main.yml b/ansible/roles/hubs/defaults/main.yml
index 2ee3221..02c1f40 100644
--- a/ansible/roles/hubs/defaults/main.yml
+++ b/ansible/roles/hubs/defaults/main.yml
@@ -8,7 +8,7 @@ hubs_venv_dir: "{{ hubs_base_dir }}/venv"
 hubs_var_dir: "{{ hubs_base_dir }}/var"
 hubs_db_type: sqlite
 hubs_db_password: changeme
-hubs_url_hostname: localhost
+hubs_url_hostname: "{{ ansible_fqdn }}"
 hubs_url: http{% if not hubs_dev_mode %}s{% endif %}://{{ hubs_url_hostname }}{% if hubs_dev_mode %}:5000{% endif %}
-hubs_ssl_cert: /etc/pki/tls/certs/localhost.crt
-hubs_ssl_key: /etc/pki/tls/private/localhost.key
+hubs_ssl_cert: /etc/pki/tls/certs/{{ hubs_url_hostname }}.crt
+hubs_ssl_key: /etc/pki/tls/private/{{ hubs_url_hostname }}.key
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
index 6ad295f..a691079 100644
--- a/ansible/vagrant-playbook.yml
+++ b/ansible/vagrant-playbook.yml
@@ -13,6 +13,7 @@
 
   roles:
     - role: hubs
+      hubs_url_hostname: localhost
       hubs_secret_key: vagrantmachinesecretkey
       hubs_db_type: sqlite
       hubs_dev_mode: true

From 1c12cc873e67e9423a8e97974103ea774db29bb2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 18 2017 13:41:54 +0000
Subject: [PATCH 899/1001] Ansible role: OIDC needs larger Nginx buffers


---

diff --git a/ansible/roles/hubs/files/nginx_proxy_params b/ansible/roles/hubs/files/nginx_proxy_params
index f4ebcd7..8d22239 100644
--- a/ansible/roles/hubs/files/nginx_proxy_params
+++ b/ansible/roles/hubs/files/nginx_proxy_params
@@ -4,3 +4,6 @@ proxy_set_header Host $http_host;
 # we don't want nginx trying to do something clever with
 # redirects, we set the Host: header above already.
 proxy_redirect off;
+# OpenID Connect uses large headers, we need bigger buffers.
+proxy_buffer_size 128k;
+proxy_buffers 8 256k;

From 9986f1a7f8bf4bb33874d6ba44fe06985e21909b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 18 2017 13:42:17 +0000
Subject: [PATCH 900/1001] Protect the pagure_pr widget against malformed JSON


---

diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 0eec25a..3f51323 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -46,7 +46,10 @@ class GetPRs(CachedFunction):
         repo = self.instance.config["repo"]
         url = '/'.join([pagure_url, repo, "pull-requests"])
         response = requests.get(url)
-        data = response.json()
+        try:
+            data = response.json()
+        except ValueError:
+            return dict(all_pr=[], total_req=0)
         total_req = data['total_requests']
         all_pr = list()
 

From 8be4f3024ade97ea2ecb7366b3fda5d297e34723 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 21 2017 15:46:24 +0000
Subject: [PATCH 901/1001] Automatically reconnect the EventSource


---

diff --git a/hubs/static/client/app/core/Hubs.js b/hubs/static/client/app/core/Hubs.js
index fa53ab5..6f24426 100644
--- a/hubs/static/client/app/core/Hubs.js
+++ b/hubs/static/client/app/core/Hubs.js
@@ -1,4 +1,5 @@
 import HubConfig from './HubConfig.jsx';
 import Streams from './Streams.jsx';
+import ReconnectingEventSource from "reconnecting-eventsource";
 
-module.exports = {HubConfig, Streams}
+module.exports = {HubConfig, Streams, ReconnectingEventSource}
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index c37dc96..d0e6a6c 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -18,6 +18,7 @@
     "react-intl": "~2.1.5",
     "react-linkify": "^0.1.3",
     "react-timeago": "^3.1.1",
+    "reconnecting-eventsource": "^1.0.1",
     "webpack": "~1.13.1"
   },
   "devDependencies": {
diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
index 2169c6b..cefe086 100644
--- a/hubs/static/js/utils.js
+++ b/hubs/static/js/utils.js
@@ -38,7 +38,7 @@ function setup_sse(url) {
       // Auto-update is disabled.
       return;
     }
-    var sseSource = new EventSource(url);
+    var sseSource = new Hubs.ReconnectingEventSource(url);
     sseSource.addEventListener("hubs:widget-updated", function(e) {
         var widget = $("#widget-" + e.data);
         if (widget.length === 0) { return; }

From 924495183297e6936ea29589da60bf98a3d344e1 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 21 2017 15:49:54 +0000
Subject: [PATCH 902/1001] Refactor the notification icon


---

diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
index cefe086..63f3ed0 100644
--- a/hubs/static/js/utils.js
+++ b/hubs/static/js/utils.js
@@ -38,7 +38,8 @@ function setup_sse(url) {
       // Auto-update is disabled.
       return;
     }
-    var sseSource = new Hubs.ReconnectingEventSource(url);
+    var sseSource = new Hubs.ReconnectingEventSource(url),
+        notifTimeout = null;
     sseSource.addEventListener("hubs:widget-updated", function(e) {
         var widget = $("#widget-" + e.data);
         if (widget.length === 0) { return; }
@@ -57,16 +58,20 @@ function setup_sse(url) {
             },
         });
     });
-    // On each message, switch the notification favicon to green for 15s.
-    sseSource.addEventListener("message", function(e) {
-        Notificon('#33ff00');  // green
-        setTimeout(function(){ Notificon(); }, 15000)
-    });
-    // On error, switch the notification favicon to red.
-    sseSource.addEventListener("error", function(e) {
-        Notificon('#eb361e');  // red
-        setTimeout(function(){ Notificon(); }, 15000)
-    });
+    function change_notify_icon(color) {
+        // Set the notify icon for 5s
+        if (color == "green") {
+            color = "#33ff00";
+        } else if (color == "red") {
+            color = "#eb361e";
+        }
+        Notificon(color);
+        if (notifTimeout) { clearTimeout(notifTimeout); }
+        notifTimeout = setTimeout(function(){ Notificon(); }, 5000)
+    }
+    // Icon to red on disconnect, icon to green on reconnect.
+    sseSource.addEventListener("error", function() { change_notify_icon("red"); });
+    sseSource.addEventListener("open", function() { change_notify_icon("green"); });
     // Make it accessible by other components on the page.
     document.sseSource = sseSource;
   }

From f7d8a3cd4bca27036f862d0fd9930d72b2a2d304 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 21 2017 16:42:28 +0000
Subject: [PATCH 903/1001] Remove useless debug output


---

diff --git a/hubs/static/client/app/components/feed/ItemsGetter.jsx b/hubs/static/client/app/components/feed/ItemsGetter.jsx
index ca6397d..678f420 100644
--- a/hubs/static/client/app/components/feed/ItemsGetter.jsx
+++ b/hubs/static/client/app/components/feed/ItemsGetter.jsx
@@ -72,7 +72,6 @@ export default class ItemsGetter extends React.Component {
   }
 
   handleSSEEventError(e) {
-    console.log(e);
     if (this.sseSource.readyState === 2) {
       // Connection closed.
       this.setState({

From 22fd419aeaae458cf92bd2918265e72574984bea Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 25 2017 14:48:11 +0000
Subject: [PATCH 904/1001] Tranfer the hub edit mode to the widgets


Some widgets display no chrome when there is no data. However, in edit
mode, the chrome should be displayed anyway or the widget can't be
configured, removed, or moved on the page.

This change allows widgets to be informed of the display mode and
display the panel chrome accordingly.

---

diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
index 63946a3..ff6ed6d 100644
--- a/hubs/templates/hubs.html
+++ b/hubs/templates/hubs.html
@@ -96,7 +96,7 @@
     <div id="left_widgets">
       {% for widget in widgets["left"] %}
       <div id="widget-{{ widget.idx }}" class="widget row"
-           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
+           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}{% if edit %}?editmode=1{% endif %}"
            ></div>
       {% endfor %}
     </div>
@@ -120,7 +120,7 @@
     <div id="right_widgets">
       {% for widget in widgets["right"] %}
       <div id="widget-{{ widget.idx }}" class="widget row"
-           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}"
+           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}{% if edit %}?editmode=1{% endif %}"
            ></div>
       {% endfor %}
     </div>
diff --git a/hubs/tests/test_widget_view.py b/hubs/tests/test_widget_view.py
new file mode 100644
index 0000000..328d207
--- /dev/null
+++ b/hubs/tests/test_widget_view.py
@@ -0,0 +1,34 @@
+from __future__ import unicode_literals
+
+import six
+from mock import Mock
+
+from hubs.app import app
+from hubs.tests import APPTest
+from hubs.widgets.base import Widget
+from hubs.widgets.caching import CachedFunction
+from hubs.widgets.view import WidgetView, RootWidgetView
+
+
+class TestingWidget(Widget):
+    name = "testing"
+
+
+class WidgetViewTest(APPTest):
+
+    def test_root_view(self):
+        testing_widget = TestingWidget()
+        view = RootWidgetView(testing_widget)
+        self.assertEqual(view.name, "root")
+        self.assertEqual(view.url_rules, ["/"])
+        self.assertEqual(view.template_name, "root.html")
+
+    def test_root_view_edit_mode(self):
+        testing_widget = TestingWidget()
+        view = RootWidgetView(testing_widget)
+        with app.test_request_context('/'):
+            context = view.get_extra_context(None)
+        self.assertFalse(context["edit_mode"])
+        with app.test_request_context('/?editmode=1'):
+            context = view.get_extra_context(None)
+        self.assertTrue(context["edit_mode"])
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index 1de5e0c..196ace3 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -1,7 +1,8 @@
 from __future__ import unicode_literals
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import WidgetView, RootWidgetView
 
 
 class About(Widget):
@@ -17,11 +18,7 @@ class About(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "about.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         return dict(
diff --git a/hubs/widgets/about/templates/about.html b/hubs/widgets/about/templates/about.html
deleted file mode 100644
index eafc55a..0000000
--- a/hubs/widgets/about/templates/about.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<p>{{text}}</p>
-{% endblock %}
diff --git a/hubs/widgets/about/templates/root.html b/hubs/widgets/about/templates/root.html
new file mode 100644
index 0000000..eafc55a
--- /dev/null
+++ b/hubs/widgets/about/templates/root.html
@@ -0,0 +1,5 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<p>{{text}}</p>
+{% endblock %}
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index 00eae24..ee1ff98 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -4,7 +4,8 @@ import operator
 import requests
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import WidgetView, RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -21,11 +22,7 @@ class Badges(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "badges.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         context = {"title": self.widget.label}
diff --git a/hubs/widgets/badges/templates/badges.html b/hubs/widgets/badges/templates/badges.html
deleted file mode 100644
index c7201d2..0000000
--- a/hubs/widgets/badges/templates/badges.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div class="flex-container">
-{% for badge in assertions %}
-  <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
-    <span class="f-b-{{badge['id']}}"></span>
-  </a>
-{% endfor %}
-</div>
-{% endblock %}
diff --git a/hubs/widgets/badges/templates/root.html b/hubs/widgets/badges/templates/root.html
new file mode 100644
index 0000000..c7201d2
--- /dev/null
+++ b/hubs/widgets/badges/templates/root.html
@@ -0,0 +1,11 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="flex-container">
+{% for badge in assertions %}
+  <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
+    <span class="f-b-{{badge['id']}}"></span>
+  </a>
+{% endfor %}
+</div>
+{% endblock %}
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index b55f1e8..a57d72b 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -6,16 +6,14 @@ import pkgwat.api
 
 from hubs.utils.pkgdb import get_owned_packages
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import WidgetView, RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
 log = logging.getLogger('hubs.widgets')
 
 
-PKGDB_URL = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
-
-
 class Bugzilla(Widget):
 
     name = "bugzilla"
@@ -36,11 +34,7 @@ class Bugzilla(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "bugzilla.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
diff --git a/hubs/widgets/bugzilla/templates/bugzilla.html b/hubs/widgets/bugzilla/templates/bugzilla.html
deleted file mode 100644
index 5fc68b5..0000000
--- a/hubs/widgets/bugzilla/templates/bugzilla.html
+++ /dev/null
@@ -1,21 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<ul class="media-list">
-  {% for item in issues %}
-    <li class="media">
-      <div class="media-left">
-        <a href="https://bugzilla.redhat.com/show_bug.cgi?id={{ item['id'] }}" target="_blank">
-        <span class="label label-default">#{{ item['id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <a href="https://apps.fedoraproject.org/packages/{{ item['pkg_name'] }}" target="_blank">{{ item['pkg_name'] }}</a>:
-          {{ item['title'] }}
-        </h4>
-      </div>
-    </li>
-  {% endfor %}
-</ul>
-{% endblock %}
diff --git a/hubs/widgets/bugzilla/templates/root.html b/hubs/widgets/bugzilla/templates/root.html
new file mode 100644
index 0000000..5fc68b5
--- /dev/null
+++ b/hubs/widgets/bugzilla/templates/root.html
@@ -0,0 +1,21 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<ul class="media-list">
+  {% for item in issues %}
+    <li class="media">
+      <div class="media-left">
+        <a href="https://bugzilla.redhat.com/show_bug.cgi?id={{ item['id'] }}" target="_blank">
+        <span class="label label-default">#{{ item['id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <a href="https://apps.fedoraproject.org/packages/{{ item['pkg_name'] }}" target="_blank">{{ item['pkg_name'] }}</a>:
+          {{ item['title'] }}
+        </h4>
+      </div>
+    </li>
+  {% endfor %}
+</ul>
+{% endblock %}
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index 59b7a1d..0d6c6b3 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -5,7 +5,8 @@ import hubs.models
 import requests
 import six
 
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import WidgetView, RootWidgetView
 from hubs.utils.views import login_required
 
 
@@ -15,11 +16,7 @@ class Contact(Widget):
     position = "both"
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "contact.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         ''' Data for Contact widget. Checks if the hub associated
diff --git a/hubs/widgets/contact/templates/contact.html b/hubs/widgets/contact/templates/contact.html
deleted file mode 100644
index d4844e9..0000000
--- a/hubs/widgets/contact/templates/contact.html
+++ /dev/null
@@ -1,74 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div class="contactinfo-container">
-  {% if usergroup %}
-    <ul style="list-style: none; padding-left: 5px">
-      <!--<li><i class="fa fa-map-marker" aria-hidden="true"></i>
-          <span class="col-md-offset-1">{{location}}</span></li>-->
-      <li><i class="fa fa-clock-o" aria-hidden="true"></i>
-          <span class="col-md-offset-1">Current-Time :</span>
-          <script type="text/javascript">
-            // TODO: send offset after querying fas3
-            function calcTime(offset) {
-
-              // create Date object for current location
-              d = new Date();
-
-              // convert to msec
-              // add local time zone offset
-              // get UTC time in msec
-              utc = d.getTime() + (d.getTimezoneOffset() * 60000);
-
-              // create new Date object using supplied offset
-              nd = new Date(utc + (3600000 * offset));
-
-              // return time as a string
-              return nd.toLocaleString();
-            }
-
-            setInterval(function() {
-              $("#time").html(calcTime(-4))
-            }, 1000)
-
-            function get_karma_stats() {
-                var karma_url = '{{ karma_url }}';
-                  $.ajax({
-                    method: "GET",
-                    url: karma_url,
-                    dataType: 'html',
-                    success: function(html) {
-                      console.log('Success: ' + html);
-                      karma_arr = JSON.parse(html);
-                      console.log(karma_arr)
-                      $('#karma_current').html("Karma : "+karma_arr['current']+" ("+karma_arr['total']+" all time)");
-                    },
-                    error: function() {
-                      console.log('Error: getting karma');
-                    },
-                  });
-                }
-            get_karma_stats()
-          </script>
-          <span id="time"></span></li>
-      <li><i class="fa fa-envelope" aria-hidden="true"></i>
-          <span class="col-md-offset-1">{{email}}</span></li>
-      <li><i class="fa fa-comment" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span>{{ircnick}}</li>
-      <li><i class="fa fa-user-plus" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span><span id="karma_current"></span></li>
-      <li><i class="fa fa-certificate" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span> Member Since {{account_age}}</li>
-    </ul>
-  {% else %}
-    <ul style="list-style: none">
-      <li><i class="fa fa-comment" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span>fedora-{{ircchannel}}</li>
-      <li><i class="fa fa-envelope" aria-hidden="true"></i>
-          <span class="col-md-offset-1"><a href="{{ mailinglist }}">{{ hubname }}@lists.fedoraproject.org</a></span></li>
-      <li><i class="fa fa-info" aria-hidden="true"></i>
-          <span class="col-md-offset-1"><a href="{{ wikilink }}">fedoraproject.org/wiki/{{ hubname }}</a></span></li>
-    </ul>
-  {% endif %}
-</div>
-{% endblock %}
diff --git a/hubs/widgets/contact/templates/root.html b/hubs/widgets/contact/templates/root.html
new file mode 100644
index 0000000..d4844e9
--- /dev/null
+++ b/hubs/widgets/contact/templates/root.html
@@ -0,0 +1,74 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="contactinfo-container">
+  {% if usergroup %}
+    <ul style="list-style: none; padding-left: 5px">
+      <!--<li><i class="fa fa-map-marker" aria-hidden="true"></i>
+          <span class="col-md-offset-1">{{location}}</span></li>-->
+      <li><i class="fa fa-clock-o" aria-hidden="true"></i>
+          <span class="col-md-offset-1">Current-Time :</span>
+          <script type="text/javascript">
+            // TODO: send offset after querying fas3
+            function calcTime(offset) {
+
+              // create Date object for current location
+              d = new Date();
+
+              // convert to msec
+              // add local time zone offset
+              // get UTC time in msec
+              utc = d.getTime() + (d.getTimezoneOffset() * 60000);
+
+              // create new Date object using supplied offset
+              nd = new Date(utc + (3600000 * offset));
+
+              // return time as a string
+              return nd.toLocaleString();
+            }
+
+            setInterval(function() {
+              $("#time").html(calcTime(-4))
+            }, 1000)
+
+            function get_karma_stats() {
+                var karma_url = '{{ karma_url }}';
+                  $.ajax({
+                    method: "GET",
+                    url: karma_url,
+                    dataType: 'html',
+                    success: function(html) {
+                      console.log('Success: ' + html);
+                      karma_arr = JSON.parse(html);
+                      console.log(karma_arr)
+                      $('#karma_current').html("Karma : "+karma_arr['current']+" ("+karma_arr['total']+" all time)");
+                    },
+                    error: function() {
+                      console.log('Error: getting karma');
+                    },
+                  });
+                }
+            get_karma_stats()
+          </script>
+          <span id="time"></span></li>
+      <li><i class="fa fa-envelope" aria-hidden="true"></i>
+          <span class="col-md-offset-1">{{email}}</span></li>
+      <li><i class="fa fa-comment" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span>{{ircnick}}</li>
+      <li><i class="fa fa-user-plus" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span><span id="karma_current"></span></li>
+      <li><i class="fa fa-certificate" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span> Member Since {{account_age}}</li>
+    </ul>
+  {% else %}
+    <ul style="list-style: none">
+      <li><i class="fa fa-comment" aria-hidden="true"></i>
+          <span class="col-md-offset-1"></span>fedora-{{ircchannel}}</li>
+      <li><i class="fa fa-envelope" aria-hidden="true"></i>
+          <span class="col-md-offset-1"><a href="{{ mailinglist }}">{{ hubname }}@lists.fedoraproject.org</a></span></li>
+      <li><i class="fa fa-info" aria-hidden="true"></i>
+          <span class="col-md-offset-1"><a href="{{ wikilink }}">fedoraproject.org/wiki/{{ hubname }}</a></span></li>
+    </ul>
+  {% endif %}
+</div>
+{% endblock %}
diff --git a/hubs/widgets/dummy/__init__.py b/hubs/widgets/dummy/__init__.py
index 463e359..d6733b7 100644
--- a/hubs/widgets/dummy/__init__.py
+++ b/hubs/widgets/dummy/__init__.py
@@ -1,7 +1,8 @@
 from __future__ import unicode_literals
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 
 
 class Dummy(Widget):
@@ -17,11 +18,7 @@ class Dummy(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "dummy.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         return dict(
diff --git a/hubs/widgets/dummy/templates/dummy.html b/hubs/widgets/dummy/templates/dummy.html
deleted file mode 100644
index f2b2486..0000000
--- a/hubs/widgets/dummy/templates/dummy.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-{{text}}
-{% endblock %}
diff --git a/hubs/widgets/dummy/templates/root.html b/hubs/widgets/dummy/templates/root.html
new file mode 100644
index 0000000..f2b2486
--- /dev/null
+++ b/hubs/widgets/dummy/templates/root.html
@@ -0,0 +1,5 @@
+{% extends "panel.html" %}
+
+{% block content %}
+{{text}}
+{% endblock %}
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index fe86e40..2cecb75 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -8,7 +8,8 @@ import requests
 from hubs.utils import get_fedmsg_config
 from hubs.utils.text import commas
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -29,11 +30,7 @@ class FedmsgStats(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "fedmsgstats.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         username = instance.config["username"]
diff --git a/hubs/widgets/fedmsgstats/templates/fedmsgstats.html b/hubs/widgets/fedmsgstats/templates/fedmsgstats.html
deleted file mode 100644
index 6c6efe1..0000000
--- a/hubs/widgets/fedmsgstats/templates/fedmsgstats.html
+++ /dev/null
@@ -1,27 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div class="stats-container row">
-  <div class="col-sm-7 col-md-12 col-lg-7">
-  <table class="stats-table">
-    <tr><th>subscribers</th><th>subscribed to</th></tr>
-    <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
-  </table>
-  </div>
-  <div class="col-sm-5 col-md-12 col-lg-5 align-self-center">
-  {% if session['nickname'] != username %}
-    <ul class="list-unstyled">
-    {% if session['nickname'] in subscribers %}
-    <li><form action="{{hub_unsubscribe_url}}" method="POST">
-        <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
-    </form></li>
-    {% else %}
-    <li><form action="{{hub_subscribe_url}}" method="POST">
-        <button class="btn btn-secondary"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
-    </form></li>
-    {% endif %}
-    </ul>
-  {% endif %}
-  </div>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/fedmsgstats/templates/root.html b/hubs/widgets/fedmsgstats/templates/root.html
new file mode 100644
index 0000000..6c6efe1
--- /dev/null
+++ b/hubs/widgets/fedmsgstats/templates/root.html
@@ -0,0 +1,27 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="stats-container row">
+  <div class="col-sm-7 col-md-12 col-lg-7">
+  <table class="stats-table">
+    <tr><th>subscribers</th><th>subscribed to</th></tr>
+    <tr class="text-info"><td>{{subscribers_text}}</td><td class="text-center">{{subscribed_text}}</td></tr>
+  </table>
+  </div>
+  <div class="col-sm-5 col-md-12 col-lg-5 align-self-center">
+  {% if session['nickname'] != username %}
+    <ul class="list-unstyled">
+    {% if session['nickname'] in subscribers %}
+    <li><form action="{{hub_unsubscribe_url}}" method="POST">
+        <button class="btn btn-info"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> Unsubscribe</button>
+    </form></li>
+    {% else %}
+    <li><form action="{{hub_subscribe_url}}" method="POST">
+        <button class="btn btn-secondary"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Subscribe</button>
+    </form></li>
+    {% endif %}
+    </ul>
+  {% endif %}
+  </div>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index 9010ad1..9a58891 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -4,7 +4,8 @@ from __future__ import unicode_literals, absolute_import
 import logging
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import WidgetView, RootWidgetView
 
 from .functions import GetData
 
@@ -28,11 +29,7 @@ class Feed(Widget):
     cached_functions_module = ".functions"
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "feed.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         return dict(
diff --git a/hubs/widgets/feed/templates/feed.html b/hubs/widgets/feed/templates/feed.html
deleted file mode 100644
index f687dd4..0000000
--- a/hubs/widgets/feed/templates/feed.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div id="feed-{{ widget_instance.idx }}">
-</div>
-
-<script type="text/javascript"
-  src ="{{ url_for('static', filename='js/build/Feed.js') }}"></script>
-<script>
-(function() {
-    const FeedElement = React.createElement(Feed.Widget, {
-        url: {{ url_for("feed_existing", hub=widget_instance.hub.name, idx=widget_instance.idx) | tojson }},
-        widgetIdx: {{ widget_instance.idx | tojson }}
-    });
-    ReactDOM.render(FeedElement, document.getElementById('feed-' + {{ widget_instance.idx | tojson }}));
-})();
-</script>
-{% endblock %}
diff --git a/hubs/widgets/feed/templates/root.html b/hubs/widgets/feed/templates/root.html
new file mode 100644
index 0000000..f687dd4
--- /dev/null
+++ b/hubs/widgets/feed/templates/root.html
@@ -0,0 +1,18 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div id="feed-{{ widget_instance.idx }}">
+</div>
+
+<script type="text/javascript"
+  src ="{{ url_for('static', filename='js/build/Feed.js') }}"></script>
+<script>
+(function() {
+    const FeedElement = React.createElement(Feed.Widget, {
+        url: {{ url_for("feed_existing", hub=widget_instance.hub.name, idx=widget_instance.idx) | tojson }},
+        widgetIdx: {{ widget_instance.idx | tojson }}
+    });
+    ReactDOM.render(FeedElement, document.getElementById('feed-' + {{ widget_instance.idx | tojson }}));
+})();
+</script>
+{% endblock %}
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
index 38e69e6..b17eb7a 100644
--- a/hubs/widgets/fhosted/__init__.py
+++ b/hubs/widgets/fhosted/__init__.py
@@ -3,7 +3,8 @@ from __future__ import unicode_literals
 from six.moves.xmlrpc_client import ServerProxy
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -28,11 +29,7 @@ class FedoraHosted(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "fhosted.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_tickets = GetTickets(instance)
diff --git a/hubs/widgets/fhosted/templates/fhosted.html b/hubs/widgets/fhosted/templates/fhosted.html
deleted file mode 100644
index 5dcc574..0000000
--- a/hubs/widgets/fhosted/templates/fhosted.html
+++ /dev/null
@@ -1,48 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-{% if error %}
-<p>{{ error }}</p>
-{% else %}
-<a class="btn btn-success" target="_blank"
-    href="https://fedorahosted.org/{{ project }}/report/1">
-  All Issues
-</a>
-<hr/>
-
-<ul class="media-list">
-  {% for issue in tickets %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="https://fedorahosted.org/{{ project }}/ticket/{{ issue['id'] }}"
-            target="_blank">
-        <span class="label label-default">#{{ issue['id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <span title="{{ issue['summary'] }}">
-            {{ issue['short_summary'] }} {% if
-              issue['summary'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-            {{ issue['reporter'] }}
-        --
-        {% if issue['owner'] %}
-          Assigned to:
-            {{issue['owner'] }}
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if total_tickets > tickets | length %}
-  <li>
-    And {{ total_tickets - tickets | length }} more ...
-  </li>
-  {% endif %}
-</ul>
-{% endif %}
-{% endblock %}
diff --git a/hubs/widgets/fhosted/templates/root.html b/hubs/widgets/fhosted/templates/root.html
new file mode 100644
index 0000000..5dcc574
--- /dev/null
+++ b/hubs/widgets/fhosted/templates/root.html
@@ -0,0 +1,48 @@
+{% extends "templates/panel.html" %}
+
+{% block content %}
+{% if error %}
+<p>{{ error }}</p>
+{% else %}
+<a class="btn btn-success" target="_blank"
+    href="https://fedorahosted.org/{{ project }}/report/1">
+  All Issues
+</a>
+<hr/>
+
+<ul class="media-list">
+  {% for issue in tickets %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://fedorahosted.org/{{ project }}/ticket/{{ issue['id'] }}"
+            target="_blank">
+        <span class="label label-default">#{{ issue['id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <span title="{{ issue['summary'] }}">
+            {{ issue['short_summary'] }} {% if
+              issue['summary'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+            {{ issue['reporter'] }}
+        --
+        {% if issue['owner'] %}
+          Assigned to:
+            {{issue['owner'] }}
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if total_tickets > tickets | length %}
+  <li>
+    And {{ total_tickets - tickets | length }} more ...
+  </li>
+  {% endif %}
+</ul>
+{% endif %}
+{% endblock %}
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index 2de11a3..f52c149 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -5,7 +5,8 @@ import logging
 from hubs.utils import get_fedmsg_config
 from hubs.utils.github import github_repos, github_pulls
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -34,11 +35,7 @@ class GitHubPRs(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "github_pr.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
diff --git a/hubs/widgets/github_pr/templates/github_pr.html b/hubs/widgets/github_pr/templates/github_pr.html
deleted file mode 100644
index 379771a..0000000
--- a/hubs/widgets/github_pr/templates/github_pr.html
+++ /dev/null
@@ -1,50 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<a class="btn btn-success" target="_blank"
-    href="https://github.com/{{ organization }}" >
-  Organization Github Page
-</a>
-<hr/>
-<ul class="media-list">
-{% for pr in pulls[:display_number] %}
-  <li class="media">
-    <div class="media-left">
-      <a  href="{{ pr['url'] }}" 
-          target="_blank">
-      <span class="label label-default">#{{ pr['number'] }}</span>
-      </a>
-    </div>
-    <div class="media-body">
-      <h4 class="media-heading">
-        {{ organization }} -
-        <span title="{{ pr['title'] }}">
-          {{ pr['title'] }} {% if
-            pr['title'] | length > 45 %} ... {% endif %}
-        </span>
-      </h4>
-      Opened by:
-        <a href="https://github.com/{{ pr['user'] }}" 
-            target="_blank">
-          {{ pr['user'] }}
-        </a>
-      --
-      {% if pr['assignee'] %}
-        Assigned to:
-        <a href="https://github.com/{{ pr['assignee'] }}"
-            target="_blank">
-          {{ pr['assignee'] }}
-        </a>
-      {% else %}
-        <span class="text-muted">Unassigned</span>
-      {% endif %}
-    </div>
-  </li>
-{% endfor %}
-{% if all_pr | length > display_number %}
-  <li>
-    And {{ all_pr | length - display_number }} more ...
-  </li>
-{% endif %}
-</ul>
-{% endblock %}
diff --git a/hubs/widgets/github_pr/templates/root.html b/hubs/widgets/github_pr/templates/root.html
new file mode 100644
index 0000000..379771a
--- /dev/null
+++ b/hubs/widgets/github_pr/templates/root.html
@@ -0,0 +1,50 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<a class="btn btn-success" target="_blank"
+    href="https://github.com/{{ organization }}" >
+  Organization Github Page
+</a>
+<hr/>
+<ul class="media-list">
+{% for pr in pulls[:display_number] %}
+  <li class="media">
+    <div class="media-left">
+      <a  href="{{ pr['url'] }}" 
+          target="_blank">
+      <span class="label label-default">#{{ pr['number'] }}</span>
+      </a>
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading">
+        {{ organization }} -
+        <span title="{{ pr['title'] }}">
+          {{ pr['title'] }} {% if
+            pr['title'] | length > 45 %} ... {% endif %}
+        </span>
+      </h4>
+      Opened by:
+        <a href="https://github.com/{{ pr['user'] }}" 
+            target="_blank">
+          {{ pr['user'] }}
+        </a>
+      --
+      {% if pr['assignee'] %}
+        Assigned to:
+        <a href="https://github.com/{{ pr['assignee'] }}"
+            target="_blank">
+          {{ pr['assignee'] }}
+        </a>
+      {% else %}
+        <span class="text-muted">Unassigned</span>
+      {% endif %}
+    </div>
+  </li>
+{% endfor %}
+{% if all_pr | length > display_number %}
+  <li>
+    And {{ all_pr | length - display_number }} more ...
+  </li>
+{% endif %}
+</ul>
+{% endblock %}
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index 4da6f9f..e2a25e2 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -3,7 +3,8 @@ from __future__ import unicode_literals
 import requests
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -34,11 +35,7 @@ class GitHubIssues(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "githubissues.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
diff --git a/hubs/widgets/githubissues/templates/githubissues.html b/hubs/widgets/githubissues/templates/githubissues.html
deleted file mode 100644
index 31943ae..0000000
--- a/hubs/widgets/githubissues/templates/githubissues.html
+++ /dev/null
@@ -1,42 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-{% for i in range(display_number) %}
-<div>
-  <table class="table-responsive table-condensed">
-    <tr>
-      <td valign="top" class="panel-heading">
-        <b>#{{ all_issues[i]['num'] }}</b>
-      </td>
-      <td width="300px">
-        <b>{{ all_issues[i]['title'] }}</b>
-      </td>
-    </tr>
-  </table>
-  <table class="table-responsive table-condensed">
-    <tr>
-      <td width="300px">
-        <font size="2">
-          <i>Opened by <a href="https://github.com/{{ all_issues[i]['openedby'] }}" target="_blank">{{ all_issues[i]['openedby'] }}</a></i>
-          {% if all_issues[i]['assignee']|string() == "None" %}
-            <br /><i>Unclaimed</i>
-          {% else %}
-             <br /><i>Assigned by <a href="https://github.com/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
-          {% endif %}
-        </font>
-      </td>
-      <td>
-         <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
-           <button type="button" class="btn btn-secondary" aria-label="Left Align">
-             <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
-           </button>
-         </a>
-      </td>
-    </tr>
-  </table>
-</div>
-{% endfor %}
-<div class="row">
-  <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/githubissues/templates/root.html b/hubs/widgets/githubissues/templates/root.html
new file mode 100644
index 0000000..31943ae
--- /dev/null
+++ b/hubs/widgets/githubissues/templates/root.html
@@ -0,0 +1,42 @@
+{% extends "panel.html" %}
+
+{% block content %}
+{% for i in range(display_number) %}
+<div>
+  <table class="table-responsive table-condensed">
+    <tr>
+      <td valign="top" class="panel-heading">
+        <b>#{{ all_issues[i]['num'] }}</b>
+      </td>
+      <td width="300px">
+        <b>{{ all_issues[i]['title'] }}</b>
+      </td>
+    </tr>
+  </table>
+  <table class="table-responsive table-condensed">
+    <tr>
+      <td width="300px">
+        <font size="2">
+          <i>Opened by <a href="https://github.com/{{ all_issues[i]['openedby'] }}" target="_blank">{{ all_issues[i]['openedby'] }}</a></i>
+          {% if all_issues[i]['assignee']|string() == "None" %}
+            <br /><i>Unclaimed</i>
+          {% else %}
+             <br /><i>Assigned by <a href="https://github.com/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
+          {% endif %}
+        </font>
+      </td>
+      <td>
+         <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
+           <button type="button" class="btn btn-secondary" aria-label="Left Align">
+             <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+           </button>
+         </a>
+      </td>
+    </tr>
+  </table>
+</div>
+{% endfor %}
+<div class="row">
+  <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/halp/templates/halp.html b/hubs/widgets/halp/templates/halp.html
deleted file mode 100644
index 8709b0e..0000000
--- a/hubs/widgets/halp/templates/halp.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div id="widget-halp">
-</div>
-<script src="{{url_for('static', filename='js/build/Halp.js')}}"></script>
-<script>
-(function() {
-    const Widget = React.createElement(Halp.Widget, {
-        hubs: {{ hubs|tojson }},
-        urls: {
-            data: '{{ url_for("halp_data", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
-            search: '{{ url_for("halp_search", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
-            requesters: '{{ url_for("halp_requesters", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
-            spinner: '{{ url_for("static", filename="img/spinner.gif") }}',
-            spinnerCircle: '{{ url_for("static", filename="img/spinner-circle.gif") }}'
-        }
-    });
-    ReactDOM.render(Widget, document.getElementById('widget-halp'));
-})();
-</script>
-{% endblock %}
diff --git a/hubs/widgets/halp/templates/root.html b/hubs/widgets/halp/templates/root.html
new file mode 100644
index 0000000..8709b0e
--- /dev/null
+++ b/hubs/widgets/halp/templates/root.html
@@ -0,0 +1,22 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div id="widget-halp">
+</div>
+<script src="{{url_for('static', filename='js/build/Halp.js')}}"></script>
+<script>
+(function() {
+    const Widget = React.createElement(Halp.Widget, {
+        hubs: {{ hubs|tojson }},
+        urls: {
+            data: '{{ url_for("halp_data", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
+            search: '{{ url_for("halp_search", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
+            requesters: '{{ url_for("halp_requesters", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
+            spinner: '{{ url_for("static", filename="img/spinner.gif") }}',
+            spinnerCircle: '{{ url_for("static", filename="img/spinner-circle.gif") }}'
+        }
+    });
+    ReactDOM.render(Widget, document.getElementById('widget-halp'));
+})();
+</script>
+{% endblock %}
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index ada528b..584fb53 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -9,7 +9,7 @@ from flask.signals import template_rendered
 from hubs.models import Hub
 from hubs.utils.views import get_hub, require_hub_access
 from hubs.widgets import registry
-from hubs.widgets.base import WidgetView
+from hubs.widgets.view import WidgetView, RootWidgetView
 from .functions import GetRequests
 from .utils import find_hubs_for_msg, paginate
 
@@ -19,13 +19,9 @@ except ImportError:
     before_render_template = None  # Flask < 0.11
 
 
-class BaseView(WidgetView):
+class BaseView(RootWidgetView):
     """The base view to instantiate the widget."""
 
-    name = "root"
-    url_rules = ["/"]
-    template_name = "halp.html"
-
     def get_context(self, instance, *args, **kwargs):
         return dict(
             hubs=instance.config.get("hubs", []),
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index 803b56a..3eddd2d 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -1,7 +1,8 @@
 from __future__ import unicode_literals
 
 from hubs.widgets import clean_input, validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 
 
 class Library(Widget):
@@ -19,11 +20,7 @@ class Library(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "library.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         urls = [
diff --git a/hubs/widgets/library/templates/library.html b/hubs/widgets/library/templates/library.html
deleted file mode 100644
index b32cfcb..0000000
--- a/hubs/widgets/library/templates/library.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div class="rules-container">
-  <div class="row">
-    <ul>
-    {% for url in urls %}
-    <li>
-      {{ url }}
-    </li>
-    {% endfor %}
-    </ul>
-  </div>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/library/templates/root.html b/hubs/widgets/library/templates/root.html
new file mode 100644
index 0000000..b32cfcb
--- /dev/null
+++ b/hubs/widgets/library/templates/root.html
@@ -0,0 +1,15 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="rules-container">
+  <div class="row">
+    <ul>
+    {% for url in urls %}
+    <li>
+      {{ url }}
+    </li>
+    {% endfor %}
+    </ul>
+  </div>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index 49388a2..c1fcf37 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -1,7 +1,8 @@
 from __future__ import unicode_literals
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 
 
 class Linechart(Widget):
@@ -18,11 +19,7 @@ class Linechart(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "linechart.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         username = instance.config["username"]
diff --git a/hubs/widgets/linechart/templates/linechart.html b/hubs/widgets/linechart/templates/linechart.html
deleted file mode 100644
index 573d452..0000000
--- a/hubs/widgets/linechart/templates/linechart.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div class="flex-container">
-    <img src="{{url}}" />
-</div>
-{% endblock %}
diff --git a/hubs/widgets/linechart/templates/root.html b/hubs/widgets/linechart/templates/root.html
new file mode 100644
index 0000000..573d452
--- /dev/null
+++ b/hubs/widgets/linechart/templates/root.html
@@ -0,0 +1,7 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="flex-container">
+    <img src="{{url}}" />
+</div>
+{% endblock %}
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index e8eec08..0633d40 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -7,7 +7,8 @@ import requests
 
 from hubs.utils.text import markup
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -37,11 +38,7 @@ class Meetings(Widget):
         return env
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "meetings.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_meetings = GetMeetings(instance)
diff --git a/hubs/widgets/meetings/templates/meetings.html b/hubs/widgets/meetings/templates/meetings.html
deleted file mode 100644
index d2ade22..0000000
--- a/hubs/widgets/meetings/templates/meetings.html
+++ /dev/null
@@ -1,63 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-{% for title, next in meetings.items() %}
-<div class="meeting">
-  <div class="row">
-      <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.start_dt | humanize }}</h5>
-  </div>
-  <div class="row">
-    <div class="col-md-4 meeting-date">
-      {% if next.display_duration %}
-      <strong>{{ next.start_date }} - {{ next.stop_date }}</strong>
-      {% else %}
-      <strong>{{next.start_date}}</strong>
-      {% endif %}
-    </div>
-    <div class="col-md-4 meeting-time">
-      {% if next.display_time %}
-      @{{ next.start_time }}{% endif %}<br>
-
-      <a href="#">{{ next.location }}</a>
-    </div>
-    <div class="col-md-4">
-      <a href="https://apps.fedoraproject.org/calendar/ical/calendar/meeting/{{ next.meeting_id }}/">
-        <button class="btn btn-secondary btn-sm add-calendar">
-          <strong>Add to calendar</strong>
-        </button>
-      </a>
-    </div>
-  </div>
-  {% if next.get('meeting_information_html')  %}
-  <div class="row">
-      <div class="col-md-12 meeting-info">
-        {{ next.meeting_information_html[:150] }}
-        {%- if next.meeting_information_html | length > 150 %}...
-        <p>
-          <a href="https://apps.fedoraproject.org/calendar/meeting/{{ next.meeting_id }}/">Full description</a>
-        </p>
-        {% endif %}
-      </div>
-  </div>
-  {% endif  %}
-</div>
-{% if meetings | length > 1 %} <hr> {% endif %}
-{% else %}
-<div class="meeting">
-  <div class="row">
-    No coming meetings in {{ calendar }}.
-  </div>
-</div>
-{% endfor %}
-{% endblock %}
-
-
-{% block footer %}
-<div class="panel-footer">
-  <div class="text-center">
-    <button class="btn btn-secondary">
-      <strong>Request A New Meeting</strong>
-    </button>
-  </div>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/meetings/templates/root.html b/hubs/widgets/meetings/templates/root.html
new file mode 100644
index 0000000..d2ade22
--- /dev/null
+++ b/hubs/widgets/meetings/templates/root.html
@@ -0,0 +1,63 @@
+{% extends "panel.html" %}
+
+{% block content %}
+{% for title, next in meetings.items() %}
+<div class="meeting">
+  <div class="row">
+      <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.start_dt | humanize }}</h5>
+  </div>
+  <div class="row">
+    <div class="col-md-4 meeting-date">
+      {% if next.display_duration %}
+      <strong>{{ next.start_date }} - {{ next.stop_date }}</strong>
+      {% else %}
+      <strong>{{next.start_date}}</strong>
+      {% endif %}
+    </div>
+    <div class="col-md-4 meeting-time">
+      {% if next.display_time %}
+      @{{ next.start_time }}{% endif %}<br>
+
+      <a href="#">{{ next.location }}</a>
+    </div>
+    <div class="col-md-4">
+      <a href="https://apps.fedoraproject.org/calendar/ical/calendar/meeting/{{ next.meeting_id }}/">
+        <button class="btn btn-secondary btn-sm add-calendar">
+          <strong>Add to calendar</strong>
+        </button>
+      </a>
+    </div>
+  </div>
+  {% if next.get('meeting_information_html')  %}
+  <div class="row">
+      <div class="col-md-12 meeting-info">
+        {{ next.meeting_information_html[:150] }}
+        {%- if next.meeting_information_html | length > 150 %}...
+        <p>
+          <a href="https://apps.fedoraproject.org/calendar/meeting/{{ next.meeting_id }}/">Full description</a>
+        </p>
+        {% endif %}
+      </div>
+  </div>
+  {% endif  %}
+</div>
+{% if meetings | length > 1 %} <hr> {% endif %}
+{% else %}
+<div class="meeting">
+  <div class="row">
+    No coming meetings in {{ calendar }}.
+  </div>
+</div>
+{% endfor %}
+{% endblock %}
+
+
+{% block footer %}
+<div class="panel-footer">
+  <div class="text-center">
+    <button class="btn btn-secondary">
+      <strong>Request A New Meeting</strong>
+    </button>
+  </div>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/memberships/__init__.py b/hubs/widgets/memberships/__init__.py
index 20f14c0..ff57c74 100644
--- a/hubs/widgets/memberships/__init__.py
+++ b/hubs/widgets/memberships/__init__.py
@@ -2,7 +2,8 @@ from __future__ import unicode_literals
 
 import hubs.models
 
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 
 
 ELLIPSIS_LIMIT = 3
@@ -15,11 +16,7 @@ class Memberships(Widget):
     position = "both"
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "memberships.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         hub = instance.hub
diff --git a/hubs/widgets/memberships/templates/memberships.html b/hubs/widgets/memberships/templates/memberships.html
deleted file mode 100644
index 621ea9f..0000000
--- a/hubs/widgets/memberships/templates/memberships.html
+++ /dev/null
@@ -1,80 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div class="card-block">
-  {% if memberships|length > oldest_members|length %}
-  {% for member in oldest_members %}
-  <div class="card-block">
-    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
-    <a href="/{{member.name}}">{{ member.name }}</a>
-    {% if g.auth.username in member.owners %}
-      <p class="text-muted">Owner</p>
-    {% else %}
-      <p>Member</p>
-    {% endif %}
-  </div>
-  {% endfor %}
-  <a href="#" class="btn btn-secondary" data-toggle="modal" data-target="#membersModal">View All</a>
-  {% else %}
-  {% for member in memberships %}
-  <div class="card-block">
-    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
-    <a href="/{{member.name}}">{{ member.name }}</a>
-    {% if g.auth.username in member.owners %}
-      <p class="text-muted">Owner</p>
-    {% else %}
-      <p>Member</p>
-    {% endif %}
-  </div>
-  {% endfor %}
-  {%endif%}
-</div>
-
-<!-- View all modal -->
-<div class="modal fade" id="membersModal" tabindex="-1" role="dialog" aria-labelledby="membersModal" aria-hidden="true">
-  <div class="modal-dialog">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h4 class="modal-title" id="myModalLabel">All Memberships</h4>
-      </div>
-      <div id="owners" class="modal-body">
-        <div class="card-block">
-          <div class="row">
-            {% for member in memberships %}
-            <div class="col-sm-6">
-              <img class="img-responsive membership-avatar col-sm-3"
-                src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
-              <a href="/{{member.name}}">{{ member.name }}</a>
-              {% if g.auth.username in member.owners %}
-              <p class="text-muted">Owner</p>
-              {% else %}
-              <p>Member</p>
-              {% endif %}
-            </div>
-            {% if (loop.index % 2) == 0 %}
-              </div>
-              <div class="row">
-            {% endif %}
-          {% endfor %}
-        </div>
-        <div class="modal-footer clearfix">
-          <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-<style>
- .membership-avatar {
-   height: 4em;
-   width: 6em;
- }
- .modal-header {
-   border-bottom: 0;
- }
-
- #owners {
-   padding: 10px;
- }
-</style>
-{% endblock %}
diff --git a/hubs/widgets/memberships/templates/root.html b/hubs/widgets/memberships/templates/root.html
new file mode 100644
index 0000000..621ea9f
--- /dev/null
+++ b/hubs/widgets/memberships/templates/root.html
@@ -0,0 +1,80 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="card-block">
+  {% if memberships|length > oldest_members|length %}
+  {% for member in oldest_members %}
+  <div class="card-block">
+    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+    <a href="/{{member.name}}">{{ member.name }}</a>
+    {% if g.auth.username in member.owners %}
+      <p class="text-muted">Owner</p>
+    {% else %}
+      <p>Member</p>
+    {% endif %}
+  </div>
+  {% endfor %}
+  <a href="#" class="btn btn-secondary" data-toggle="modal" data-target="#membersModal">View All</a>
+  {% else %}
+  {% for member in memberships %}
+  <div class="card-block">
+    <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+    <a href="/{{member.name}}">{{ member.name }}</a>
+    {% if g.auth.username in member.owners %}
+      <p class="text-muted">Owner</p>
+    {% else %}
+      <p>Member</p>
+    {% endif %}
+  </div>
+  {% endfor %}
+  {%endif%}
+</div>
+
+<!-- View all modal -->
+<div class="modal fade" id="membersModal" tabindex="-1" role="dialog" aria-labelledby="membersModal" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h4 class="modal-title" id="myModalLabel">All Memberships</h4>
+      </div>
+      <div id="owners" class="modal-body">
+        <div class="card-block">
+          <div class="row">
+            {% for member in memberships %}
+            <div class="col-sm-6">
+              <img class="img-responsive membership-avatar col-sm-3"
+                src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">
+              <a href="/{{member.name}}">{{ member.name }}</a>
+              {% if g.auth.username in member.owners %}
+              <p class="text-muted">Owner</p>
+              {% else %}
+              <p>Member</p>
+              {% endif %}
+            </div>
+            {% if (loop.index % 2) == 0 %}
+              </div>
+              <div class="row">
+            {% endif %}
+          {% endfor %}
+        </div>
+        <div class="modal-footer clearfix">
+          <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+        </div>
+      </div>
+    </div>
+  </div>
+
+<style>
+ .membership-avatar {
+   height: 4em;
+   width: 6em;
+ }
+ .modal-header {
+   border-bottom: 0;
+ }
+
+ #owners {
+   padding: 10px;
+ }
+</style>
+{% endblock %}
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 3f51323..9346e54 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -1,7 +1,8 @@
 from __future__ import unicode_literals
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 import requests
@@ -24,11 +25,7 @@ class PagurePRs(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "pagure_pr.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
diff --git a/hubs/widgets/pagure_pr/templates/pagure_pr.html b/hubs/widgets/pagure_pr/templates/pagure_pr.html
deleted file mode 100644
index 9a7f3f2..0000000
--- a/hubs/widgets/pagure_pr/templates/pagure_pr.html
+++ /dev/null
@@ -1,52 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<ul class="media-list">
-  {% for pr in all_pr[:10] %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
-            target="_blank">
-        <span class="label label-default">#{{ pr['pr_id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          {{ pr['pr_project_name'] }} -
-          <span title="{{ pr['pr_title_full'] }}">
-            {{ pr['pr_title'] }} {% if
-              pr['pr_title_full'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-          <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
-              target="_blank">
-            {{ pr['pr_openedby'] }}
-          </a>
-        --
-        {% if pr['pr_assignee'] %}
-          Assigned to:
-          <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
-              target="_blank">
-            {{ pr['pr_assignee']['name'] }}
-          </a>
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if all_pr | length > 10 %}
-  <li>
-    And {{ all_pr | length - 10 }} more ...
-  </li>
-  {% endif %}
-</ul>
-
-<hr/>
-
-<a class="btn btn-success" target="_blank"
-    href="https://pagure.io/{{ repo }}/pull-requests">
-  All Pull-Requests
-</a>
-{% endblock %}
diff --git a/hubs/widgets/pagure_pr/templates/root.html b/hubs/widgets/pagure_pr/templates/root.html
new file mode 100644
index 0000000..9a7f3f2
--- /dev/null
+++ b/hubs/widgets/pagure_pr/templates/root.html
@@ -0,0 +1,52 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<ul class="media-list">
+  {% for pr in all_pr[:10] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
+            target="_blank">
+        <span class="label label-default">#{{ pr['pr_id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          {{ pr['pr_project_name'] }} -
+          <span title="{{ pr['pr_title_full'] }}">
+            {{ pr['pr_title'] }} {% if
+              pr['pr_title_full'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
+              target="_blank">
+            {{ pr['pr_openedby'] }}
+          </a>
+        --
+        {% if pr['pr_assignee'] %}
+          Assigned to:
+          <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"
+              target="_blank">
+            {{ pr['pr_assignee']['name'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_pr | length > 10 %}
+  <li>
+    And {{ all_pr | length - 10 }} more ...
+  </li>
+  {% endif %}
+</ul>
+
+<hr/>
+
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/pull-requests">
+  All Pull-Requests
+</a>
+{% endblock %}
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index 85f7110..d8db995 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -3,7 +3,8 @@ from __future__ import unicode_literals
 import requests
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 pagure_url = "https://pagure.io/api/0"
@@ -24,11 +25,7 @@ class PagureIssues(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "pagureissues.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
diff --git a/hubs/widgets/pagureissues/templates/pagureissues.html b/hubs/widgets/pagureissues/templates/pagureissues.html
deleted file mode 100644
index 989ccd4..0000000
--- a/hubs/widgets/pagureissues/templates/pagureissues.html
+++ /dev/null
@@ -1,51 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<a class="btn btn-success" target="_blank"
-    href="https://pagure.io/{{ repo }}/issues">
-  All Issues
-</a>
-<hr/>
-
-<ul class="media-list">
-  {% for issue in all_issues[:10] %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="https://pagure.io/{{ repo }}/issue/{{ issue['issue_id'] }}"
-            target="_blank">
-          {{ issue['issue_project_name'] }}
-        <span class="label label-default">#{{ issue['issue_id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <span title="{{ issue['issue_title_full'] }}">
-            {{ issue['issue_title'] }} {% if
-              issue['issue_title_full'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-          <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
-              target="_blank">
-            {{ issue['issue_openedby'] }}
-          </a>
-        --
-        {% if issue['issue_assignee'] %}
-          Assigned to:
-          <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
-              target="_blank">
-            {{issue['issue_assignee'] }}
-          </a>
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if all_issues | length > 10 %}
-  <li>
-    And {{ all_issues | length - 10 }} more ...
-  </li>
-  {% endif %}
-</ul>
-{% endblock %}
diff --git a/hubs/widgets/pagureissues/templates/root.html b/hubs/widgets/pagureissues/templates/root.html
new file mode 100644
index 0000000..989ccd4
--- /dev/null
+++ b/hubs/widgets/pagureissues/templates/root.html
@@ -0,0 +1,51 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<a class="btn btn-success" target="_blank"
+    href="https://pagure.io/{{ repo }}/issues">
+  All Issues
+</a>
+<hr/>
+
+<ul class="media-list">
+  {% for issue in all_issues[:10] %}
+    <li class="media">
+      <div class="media-left">
+        <a  href="https://pagure.io/{{ repo }}/issue/{{ issue['issue_id'] }}"
+            target="_blank">
+          {{ issue['issue_project_name'] }}
+        <span class="label label-default">#{{ issue['issue_id'] }}</span>
+        </a>
+      </div>
+      <div class="media-body">
+        <h4 class="media-heading">
+          <span title="{{ issue['issue_title_full'] }}">
+            {{ issue['issue_title'] }} {% if
+              issue['issue_title_full'] | length > 45 %} ... {% endif %}
+          </span>
+        </h4>
+        Opened by:
+          <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
+              target="_blank">
+            {{ issue['issue_openedby'] }}
+          </a>
+        --
+        {% if issue['issue_assignee'] %}
+          Assigned to:
+          <a href="https://pagure.io/user/{{issue['issue_assignee'] }}"
+              target="_blank">
+            {{issue['issue_assignee'] }}
+          </a>
+        {% else %}
+          <span class="text-muted">Unassigned</span>
+        {% endif %}
+      </div>
+    </li>
+  {% endfor %}
+  {% if all_issues | length > 10 %}
+  <li>
+    And {{ all_issues | length - 10 }} more ...
+  </li>
+  {% endif %}
+</ul>
+{% endblock %}
diff --git a/hubs/widgets/rules/__init__.py b/hubs/widgets/rules/__init__.py
index 1ec9c09..7331acd 100644
--- a/hubs/widgets/rules/__init__.py
+++ b/hubs/widgets/rules/__init__.py
@@ -4,7 +4,8 @@ from collections import OrderedDict as ordereddict
 
 from hubs.utils import username2avatar
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 
 
 ELLIPSIS_LIMIT = 5
@@ -42,11 +43,7 @@ class Rules(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "rules.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         owners = instance.hub.owners
diff --git a/hubs/widgets/rules/templates/root.html b/hubs/widgets/rules/templates/root.html
new file mode 100644
index 0000000..c52c61c
--- /dev/null
+++ b/hubs/widgets/rules/templates/root.html
@@ -0,0 +1,91 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="rules-container">
+  {% if link %}
+  <h6>community rules</h6>
+  <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
+  {% endif %}
+  <h6>group owners ({{ owners|length }})</h6>
+  <div class="row">
+    {% if owners|length > 5%}
+      {% for owner in oldest_owners %}
+        <div class="col-sm-6">
+          <img class="img-circle" src="{{owner['avatar']}}"/>
+          <a href="{{ url_for('hub', name=owner['username']) }}">{{owner['username']}}</a>
+        </div>
+        {% endfor %}
+        <br/>
+        <a href="#" class="btn btn-secondary" data-toggle="modal" data-target="#ownersModal">View All</a>
+    {% else %}
+      {% for owner in owners %}
+        <div class="col-sm-6">
+          <img class="img-circle" src="{{owners[owner]}}"/>
+          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
+        </div>
+      {% endfor %}
+    {% endif %}
+  </div>
+  {% if schedule_text or schedule_link or minutes_link %}
+  <h6>meetings</h6>
+  {% if schedule_text %}
+  <p>{{schedule_text}}</p>
+  {% endif %}
+  <p>
+  {% if schedule_link %}
+  <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
+  {% endif %}
+  {% if schedule_link and minutes_link %}
+  &#8214;
+  {% endif %}
+  {% if minutes_link %}
+  <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
+  {% endif %}
+  </p>
+  {% endif %}
+</div>
+
+
+<!-- View all modal -->
+<div class="modal fade" id="ownersModal" tabindex="-1" role="dialog" aria-labelledby="ownersModal" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h4 class="modal-title" id="myModalLabel">All group owners</h4>
+      </div>
+      <div id="owners">
+        {% for owner in owners %}
+        <div class="col-sm-6">
+          <img class="img-circle img-circle-lg" src="{{owners[owner]}}"/>
+          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
+        </div>
+        {% endfor %}
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+      </div>
+    </div>
+  </div>
+</div>
+
+<style>
+  .rules-table {
+    width: 180px
+    padding: 0px;
+    margin: 0px;
+    display: inline-block;
+  }
+  .rules-table td {
+    font-size: 32pt;
+  }
+
+ .img-circle-lg {
+   height: 4em;
+   width: 4em;
+   padding: 10px;
+ }
+ .modal-header {
+   border-bottom: 0;
+ }
+</style>
+{% endblock %}
diff --git a/hubs/widgets/rules/templates/rules.html b/hubs/widgets/rules/templates/rules.html
deleted file mode 100644
index c52c61c..0000000
--- a/hubs/widgets/rules/templates/rules.html
+++ /dev/null
@@ -1,91 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div class="rules-container">
-  {% if link %}
-  <h6>community rules</h6>
-  <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
-  {% endif %}
-  <h6>group owners ({{ owners|length }})</h6>
-  <div class="row">
-    {% if owners|length > 5%}
-      {% for owner in oldest_owners %}
-        <div class="col-sm-6">
-          <img class="img-circle" src="{{owner['avatar']}}"/>
-          <a href="{{ url_for('hub', name=owner['username']) }}">{{owner['username']}}</a>
-        </div>
-        {% endfor %}
-        <br/>
-        <a href="#" class="btn btn-secondary" data-toggle="modal" data-target="#ownersModal">View All</a>
-    {% else %}
-      {% for owner in owners %}
-        <div class="col-sm-6">
-          <img class="img-circle" src="{{owners[owner]}}"/>
-          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
-        </div>
-      {% endfor %}
-    {% endif %}
-  </div>
-  {% if schedule_text or schedule_link or minutes_link %}
-  <h6>meetings</h6>
-  {% if schedule_text %}
-  <p>{{schedule_text}}</p>
-  {% endif %}
-  <p>
-  {% if schedule_link %}
-  <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
-  {% endif %}
-  {% if schedule_link and minutes_link %}
-  &#8214;
-  {% endif %}
-  {% if minutes_link %}
-  <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
-  {% endif %}
-  </p>
-  {% endif %}
-</div>
-
-
-<!-- View all modal -->
-<div class="modal fade" id="ownersModal" tabindex="-1" role="dialog" aria-labelledby="ownersModal" aria-hidden="true">
-  <div class="modal-dialog">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h4 class="modal-title" id="myModalLabel">All group owners</h4>
-      </div>
-      <div id="owners">
-        {% for owner in owners %}
-        <div class="col-sm-6">
-          <img class="img-circle img-circle-lg" src="{{owners[owner]}}"/>
-          <a href="{{ url_for('hub', name=owner)}}">{{owner}}</a>
-        </div>
-        {% endfor %}
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-      </div>
-    </div>
-  </div>
-</div>
-
-<style>
-  .rules-table {
-    width: 180px
-    padding: 0px;
-    margin: 0px;
-    display: inline-block;
-  }
-  .rules-table td {
-    font-size: 32pt;
-  }
-
- .img-circle-lg {
-   height: 4em;
-   width: 4em;
-   padding: 10px;
- }
- .modal-header {
-   border-bottom: 0;
- }
-</style>
-{% endblock %}
diff --git a/hubs/widgets/stats/__init__.py b/hubs/widgets/stats/__init__.py
index b139175..b893feb 100644
--- a/hubs/widgets/stats/__init__.py
+++ b/hubs/widgets/stats/__init__.py
@@ -3,7 +3,8 @@ from __future__ import unicode_literals
 import flask
 
 from hubs.utils.text import commas
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -13,11 +14,7 @@ class Stats(Widget):
     position = "right"
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "stats.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_stats = GetStats(instance)
diff --git a/hubs/widgets/stats/templates/root.html b/hubs/widgets/stats/templates/root.html
new file mode 100644
index 0000000..5dc307e
--- /dev/null
+++ b/hubs/widgets/stats/templates/root.html
@@ -0,0 +1,78 @@
+{% extends "panel.html" %}
+
+{% block content %}
+<div class="stats-container row">
+<div class="col-md-7">
+  <table class="stats-table">
+    <tr><th>Members</th><th>Subscribers</th></tr>
+    <tr class="text-info">
+      <td>{{members_text}}</td>
+      <td class="text-right">{{subscribers_text}}</td>
+    </tr>
+  </table>
+</div>
+<div class="col-md-5">
+  <ul class="list-unstyled">
+  {% if g.auth.nickname in subscribers %}
+  <li>
+    <form action="{{hub_unsubscribe_url}}" method="POST">
+      <button class="btn btn-info">
+        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
+        Unsubscribe
+      </button>
+    </form>
+  </li>
+  {% else %}
+  <li>
+    <form action="{{hub_subscribe_url}}" method="POST">
+      <button class="btn btn-secondary">
+        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
+        Subscribe
+      </button>
+    </form>
+  </li>
+  {% endif %}
+
+  {% if g.auth.nickname in stargazers %}
+  <li>
+    <form action="{{hub_unstar_url}}" method="POST">
+      <button class="btn btn-info">
+        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
+        Unstar Hub
+      </button>
+    </form>
+  </li>
+  {% else %}
+  <li>
+    <form action="{{hub_star_url}}" method="POST">
+      <button class="btn btn-secondary">
+        <span class="glyphicon glyphicon-star" aria-hidden="true"></span>
+        Star Hub
+      </button>
+    </form>
+  </li>
+  {% endif %}
+
+  {% if g.auth.nickname in members %}
+  <li>
+    <form action="{{hub_leave_url}}" method="POST">
+      <button class="btn btn-info">
+        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
+        Leave Hub
+      </button>
+    </form>
+  </li>
+  {% else %}
+  <li>
+    <form action="{{hub_join_url}}" method="POST">
+      <button class="btn btn-secondary">
+        <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
+        Join Hub
+      </button>
+    </form>
+  </li>
+  {% endif %}
+  </ul>
+</div>
+</div>
+{% endblock %}
diff --git a/hubs/widgets/stats/templates/stats.html b/hubs/widgets/stats/templates/stats.html
deleted file mode 100644
index 5dc307e..0000000
--- a/hubs/widgets/stats/templates/stats.html
+++ /dev/null
@@ -1,78 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div class="stats-container row">
-<div class="col-md-7">
-  <table class="stats-table">
-    <tr><th>Members</th><th>Subscribers</th></tr>
-    <tr class="text-info">
-      <td>{{members_text}}</td>
-      <td class="text-right">{{subscribers_text}}</td>
-    </tr>
-  </table>
-</div>
-<div class="col-md-5">
-  <ul class="list-unstyled">
-  {% if g.auth.nickname in subscribers %}
-  <li>
-    <form action="{{hub_unsubscribe_url}}" method="POST">
-      <button class="btn btn-info">
-        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
-        Unsubscribe
-      </button>
-    </form>
-  </li>
-  {% else %}
-  <li>
-    <form action="{{hub_subscribe_url}}" method="POST">
-      <button class="btn btn-secondary">
-        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
-        Subscribe
-      </button>
-    </form>
-  </li>
-  {% endif %}
-
-  {% if g.auth.nickname in stargazers %}
-  <li>
-    <form action="{{hub_unstar_url}}" method="POST">
-      <button class="btn btn-info">
-        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
-        Unstar Hub
-      </button>
-    </form>
-  </li>
-  {% else %}
-  <li>
-    <form action="{{hub_star_url}}" method="POST">
-      <button class="btn btn-secondary">
-        <span class="glyphicon glyphicon-star" aria-hidden="true"></span>
-        Star Hub
-      </button>
-    </form>
-  </li>
-  {% endif %}
-
-  {% if g.auth.nickname in members %}
-  <li>
-    <form action="{{hub_leave_url}}" method="POST">
-      <button class="btn btn-info">
-        <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
-        Leave Hub
-      </button>
-    </form>
-  </li>
-  {% else %}
-  <li>
-    <form action="{{hub_join_url}}" method="POST">
-      <button class="btn btn-secondary">
-        <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
-        Join Hub
-      </button>
-    </form>
-  </li>
-  {% endif %}
-  </ul>
-</div>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index ee22bc6..f452d24 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -1,7 +1,8 @@
 from __future__ import unicode_literals
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 
 
 class Sticky(Widget):
@@ -19,11 +20,7 @@ class Sticky(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "sticky.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         # TODO -- render with markdown
diff --git a/hubs/widgets/sticky/templates/root.html b/hubs/widgets/sticky/templates/root.html
new file mode 100644
index 0000000..f2b2486
--- /dev/null
+++ b/hubs/widgets/sticky/templates/root.html
@@ -0,0 +1,5 @@
+{% extends "panel.html" %}
+
+{% block content %}
+{{text}}
+{% endblock %}
diff --git a/hubs/widgets/sticky/templates/sticky.html b/hubs/widgets/sticky/templates/sticky.html
deleted file mode 100644
index f2b2486..0000000
--- a/hubs/widgets/sticky/templates/sticky.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-{{text}}
-{% endblock %}
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
index 05d0693..c3b9cb8 100644
--- a/hubs/widgets/subscriptions/__init__.py
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -7,7 +7,8 @@ from fedmsg.meta.base import BaseConglomerator as BC
 import hubs.models
 from hubs.utils import get_fedmsg_config
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -28,11 +29,7 @@ class Subscriptions(Widget):
         )]
 
 
-class BaseView(WidgetView):
-
-    name = "root"
-    url_rules = ["/"]
-    template_name = "subscriptions.html"
+class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         context = dict(title="Hubs")
diff --git a/hubs/widgets/subscriptions/templates/root.html b/hubs/widgets/subscriptions/templates/root.html
new file mode 100644
index 0000000..83033dd
--- /dev/null
+++ b/hubs/widgets/subscriptions/templates/root.html
@@ -0,0 +1,17 @@
+{% if associations or edit_mode %}
+{% extends "panel.html" %}
+
+{% block content %}
+    {% if memberships %}
+        <p><strong>Belongs to: </strong> {{memberships_text}}</p>
+    {% endif %}
+    <hr/>
+    {% if subscriptions %}
+        <p><strong>Subscribes to:</strong>
+        {% for subscription in subscriptions %}
+        <a href="{{ url_for('hub', name=subscription)}}">
+        {{subscription}}</a>
+        {% endfor %}</p>
+    {% endif %}
+{% endblock %}
+{% endif %}
diff --git a/hubs/widgets/subscriptions/templates/subscriptions.html b/hubs/widgets/subscriptions/templates/subscriptions.html
deleted file mode 100644
index 1114d8c..0000000
--- a/hubs/widgets/subscriptions/templates/subscriptions.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% if associations %}
-{% extends "panel.html" %}
-
-{% block content %}
-    {% if memberships %}
-        <p><strong>Belongs to: </strong> {{memberships_text}}</p>
-    {% endif %}
-    <hr/>
-    {% if subscriptions %}
-        <p><strong>Subscribes to:</strong>
-        {% for subscription in subscriptions %}
-        <a href="{{ url_for('hub', name=subscription)}}">
-        {{subscription}}</a>
-        {% endfor %}</p>
-    {% endif %}
-{% endblock %}
-{% endif %}
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index 2f956bf..c5aec95 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -135,3 +135,18 @@ class WidgetView(View):
                 flask._app_ctx_stack.top.app,
                 template=template, context=context)
             return output
+
+
+class RootWidgetView(WidgetView):
+
+    name = "root"
+    url_rules = ["/"]
+    template_name = "root.html"
+
+    def get_extra_context(self, *args, **kwargs):
+        """
+        Export the edit mode status to the template
+        """
+        context = super(RootWidgetView, self).get_extra_context(*args, **kwargs)
+        context["edit_mode"] = flask.request.args.get("editmode", "", type=bool)
+        return context
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 9ceb94b..8db3aeb 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -4,7 +4,8 @@ import requests
 
 from hubs.utils import username2avatar
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import WidgetView, RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -23,10 +24,8 @@ class PendingACLs(Widget):
         )]
 
 
-class BaseView(WidgetView):
+class BaseView(RootWidgetView):
 
-    name = "root"
-    url_rules = ["/"]
     # TODO -- add approve/deny buttons or just link through to pkgdb
     template_name = "pendingacls.html"
 
diff --git a/hubs/widgets/workflow/templates/pendingacls.html b/hubs/widgets/workflow/templates/pendingacls.html
index 446e723..11254a2 100644
--- a/hubs/widgets/workflow/templates/pendingacls.html
+++ b/hubs/widgets/workflow/templates/pendingacls.html
@@ -1,4 +1,4 @@
-{% if pending_acls %}
+{% if pending_acls or edit_mode %}
 
 {% extends "panel.html" %}
 
diff --git a/hubs/widgets/workflow/templates/updates2stable.html b/hubs/widgets/workflow/templates/updates2stable.html
index 7e72e01..f32efca 100644
--- a/hubs/widgets/workflow/templates/updates2stable.html
+++ b/hubs/widgets/workflow/templates/updates2stable.html
@@ -1,4 +1,4 @@
-{% if updates %}
+{% if updates or edit_mode %}
 {% extends "panel.html" %}
 
 {% block content %}
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 6f36260..413631b 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -3,7 +3,8 @@ from __future__ import unicode_literals
 import requests
 
 from hubs.widgets import validators
-from hubs.widgets.base import Widget, WidgetView
+from hubs.widgets.base import Widget
+from hubs.widgets.view import WidgetView, RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
@@ -27,10 +28,8 @@ class Updates2Stable(Widget):
         )]
 
 
-class BaseView(WidgetView):
+class BaseView(RootWidgetView):
 
-    name = "root"
-    url_rules = ["/"]
     # TODO -- add approve/deny buttons or just link through to pkgdb
     template_name = "updates2stable.html"
 

From 7f1424e6fa96098dd063fc53eee2c85331cda047 Mon Sep 17 00:00:00 2001
From: Sayak Sarkar <ssarkar@redhat.com>
Date: Jul 26 2017 13:53:48 +0000
Subject: [PATCH 905/1001] Dropped FedoraHosted widget. Fixes #354.


---

diff --git a/hubs/default_config.py b/hubs/default_config.py
index ab47804..3924a1f 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -60,7 +60,6 @@ WIDGETS = [
     'hubs.widgets.linechart:Linechart',
     'hubs.widgets.fedmsgstats:FedmsgStats',
     'hubs.widgets.feed:Feed',
-    'hubs.widgets.fhosted:FedoraHosted',
     'hubs.widgets.github_pr:GitHubPRs',
     'hubs.widgets.githubissues:GitHubIssues',
     'hubs.widgets.halp:Halp',
diff --git a/hubs/widgets/fhosted/__init__.py b/hubs/widgets/fhosted/__init__.py
deleted file mode 100644
index b17eb7a..0000000
--- a/hubs/widgets/fhosted/__init__.py
+++ /dev/null
@@ -1,89 +0,0 @@
-from __future__ import unicode_literals
-
-from six.moves.xmlrpc_client import ServerProxy
-
-from hubs.widgets import validators
-from hubs.widgets.base import Widget
-from hubs.widgets.view import RootWidgetView
-from hubs.widgets.caching import CachedFunction
-
-
-class FedoraHosted(Widget):
-
-    name = "fhosted"
-    label = "Fedorahosted: Open Tickets"
-    position = "right"
-    parameters = [
-        dict(
-            name="project",
-            label="Project",
-            default=None,
-            validator=validators.FedorahostedProject,
-            help="Name of the trac instance on fedorahosted.org.",
-        ), dict(
-            name="n_tickets",
-            label="Number of tickets",
-            default=4,
-            validator=validators.Integer,
-            help="The number of tickets to display.",
-        )]
-
-
-class BaseView(RootWidgetView):
-
-    def get_context(self, instance, *args, **kwargs):
-        get_tickets = GetTickets(instance)
-        context = dict(
-            title=self.widget.label,
-            project=instance.config["project"],
-            )
-        context.update(get_tickets())
-        return context
-
-
-class GetTickets(CachedFunction):
-    ''' Data for Fedorahosted widget.
-    Queries Fedorahosted via xmlrpc for tickets. '''
-
-    def execute(self):
-        n_tickets = self.instance.config["n_tickets"]
-        url = 'https://fedorahosted.org/%s/rpc' \
-            % self.instance.config["project"]
-        filters = 'status=accepted&status=assigned&status=new&status=reopened'\
-            '&col=id&col=summary&col=status&col=owner&col=type&col=priority'\
-            '&col=milestone&col=changetime&order=changetime'
-
-        # get the tickets based on the filters
-        # returns a list of ticket ids
-        try:
-            server = ServerProxy(url)
-            tickets = server.ticket.query(filters)
-        except:
-            return dict(
-                error='Invalid or wrongly configured project'
-            )
-
-        output = []
-        total_tickets = len(tickets)
-        for ticket in tickets[:n_tickets]:
-            # get the details of the ticket
-            ticket = server.ticket.get(ticket)
-            data = ticket[3]
-            data['id'] = ticket[0]
-            data['short_summary'] = data['summary'][:45]
-            output.append(data)
-
-        return dict(
-            tickets=output,
-            total_tickets=total_tickets,
-        )
-
-    def should_invalidate(self, message):
-        ''' Checks if the Fedorahosted widget needs an update.
-        Called by backend daemon listening to fedmsg '''
-        if '.trac.ticket' in message['topic']:
-            project = self.instance.config.get("project", "")
-            url = 'https://fedorahosted.org/%s/' % project
-            if message['msg']['instance']['base_url'] == url:
-                return True
-        return False
diff --git a/hubs/widgets/fhosted/templates/root.html b/hubs/widgets/fhosted/templates/root.html
deleted file mode 100644
index 5dcc574..0000000
--- a/hubs/widgets/fhosted/templates/root.html
+++ /dev/null
@@ -1,48 +0,0 @@
-{% extends "templates/panel.html" %}
-
-{% block content %}
-{% if error %}
-<p>{{ error }}</p>
-{% else %}
-<a class="btn btn-success" target="_blank"
-    href="https://fedorahosted.org/{{ project }}/report/1">
-  All Issues
-</a>
-<hr/>
-
-<ul class="media-list">
-  {% for issue in tickets %}
-    <li class="media">
-      <div class="media-left">
-        <a  href="https://fedorahosted.org/{{ project }}/ticket/{{ issue['id'] }}"
-            target="_blank">
-        <span class="label label-default">#{{ issue['id'] }}</span>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <span title="{{ issue['summary'] }}">
-            {{ issue['short_summary'] }} {% if
-              issue['summary'] | length > 45 %} ... {% endif %}
-          </span>
-        </h4>
-        Opened by:
-            {{ issue['reporter'] }}
-        --
-        {% if issue['owner'] %}
-          Assigned to:
-            {{issue['owner'] }}
-        {% else %}
-          <span class="text-muted">Unassigned</span>
-        {% endif %}
-      </div>
-    </li>
-  {% endfor %}
-  {% if total_tickets > tickets | length %}
-  <li>
-    And {{ total_tickets - tickets | length }} more ...
-  </li>
-  {% endif %}
-</ul>
-{% endif %}
-{% endblock %}

From 4d85c8ab7660d504bc4f08dd17fcdeff2280b8e6 Mon Sep 17 00:00:00 2001
From: Sayak Sarkar <ssarkar@redhat.com>
Date: Jul 26 2017 14:22:14 +0000
Subject: [PATCH 906/1001] Removed the FedoraHostedProject validator along with its unit tests and VCR files.


---

diff --git a/hubs/tests/test_widget_validators.py b/hubs/tests/test_widget_validators.py
index 2cadf7f..ba0c2b8 100644
--- a/hubs/tests/test_widget_validators.py
+++ b/hubs/tests/test_widget_validators.py
@@ -57,11 +57,3 @@ class ValidatorsTest(APPTest):
             validators.PagureRepo.from_string("fedora-hubs"), "fedora-hubs")
         self.assertRaises(ValueError, validators.PagureRepo.from_string,
                           "something-that-does-not-exist")
-
-    def test_fedorahosted_project(self):
-        self.assertEqual(
-            validators.FedorahostedProject.from_string("about-fedora"),
-            "about-fedora")
-        self.assertRaises(
-            ValueError, validators.FedorahostedProject.from_string,
-            "something-that-does-not-exist")
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_fedorahosted_project b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_fedorahosted_project
deleted file mode 100644
index 3d8315c..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_fedorahosted_project
+++ /dev/null
@@ -1,186 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://fedorahosted.org/about-fedora/
-  response:
-    body: {string: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"\
-        http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\"\
-        >\n  \n  \n\n  \n\n\n  <head>\n    <title>\n      about-fedora\n    </title>\n\
-        \    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"\
-        \ />\n    <!--[if IE]><script type=\"text/javascript\">\n      if (/^#__msie303:/.test(window.location.hash))\n\
-        \        window.location.replace(window.location.hash.replace(/^#__msie303:/,\
-        \ '#'));\n    </script><![endif]-->\n        <link rel=\"search\" href=\"\
-        /about-fedora/search\" />\n        <link rel=\"help\" href=\"/about-fedora/wiki/TracGuide\"\
-        \ />\n        <link rel=\"alternate\" href=\"/about-fedora/wiki/WikiStart?format=txt\"\
-        \ type=\"text/x-trac-wiki\" title=\"Plain Text\" />\n        <link rel=\"\
-        start\" href=\"/about-fedora/wiki\" />\n        <link rel=\"stylesheet\" href=\"\
-        /about-fedora/chrome/common/css/trac.css\" type=\"text/css\" /><link rel=\"\
-        stylesheet\" href=\"/about-fedora/chrome/common/css/wiki.css\" type=\"text/css\"\
-        \ /><link rel=\"stylesheet\" href=\"/about-fedora/chrome/tracvatar/tracvatar.css\"\
-        \ type=\"text/css\" />\n        <link rel=\"shortcut icon\" href=\"/about-fedora/chrome/common/trac.ico\"\
-        \ type=\"image/x-icon\" />\n        <link rel=\"icon\" href=\"/about-fedora/chrome/common/trac.ico\"\
-        \ type=\"image/x-icon\" />\n      <link type=\"application/opensearchdescription+xml\"\
-        \ rel=\"search\" href=\"/about-fedora/search/opensearch\" title=\"Search about-fedora\"\
-        \ />\n    <script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/jquery.js\"\
-        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/babel.js\"\
-        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/messages/en_US.js\"\
-        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/trac.js\"\
-        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/search.js\"\
-        ></script><script type=\"text/javascript\" src=\"/about-fedora/chrome/common/js/folding.js\"\
-        ></script>\n    <!--[if lt IE 7]>\n    <script type=\"text/javascript\" src=\"\
-        /about-fedora/chrome/common/js/ie_pre7_hacks.js\"></script>\n    <![endif]-->\n\
-        \    <script type=\"text/javascript\">\n      jQuery(document).ready(function($)\
-        \ {\n        $(\"#content\").find(\"h1,h2,h3,h4,h5,h6\").addAnchor(_(\"Link\
-        \ to this section\"));\n        $(\"#content\").find(\".wikianchor\").each(function()\
-        \ {\n          $(this).addAnchor(babel.format(_(\"Link to #%(id)s\"), {id:\
-        \ $(this).attr('id')}));\n        });\n        $(\".foldable\").enableFolding(true,\
-        \ true);\n      });\n    </script>\n  </head>\n  <body>\n    <div id=\"banner\"\
-        >\n      <div id=\"header\">\n        <a id=\"logo\" href=\"https://fedorahosted.org/\"\
-        ><img src=\"https://fedorahosted.org/web/static/images/fedora-hosted-banner.png\"\
-        \ alt=\"Fedora Hosted\" /></a>\n      </div>\n      <form id=\"search\" action=\"\
-        /about-fedora/search\" method=\"get\">\n        <div>\n          <label for=\"\
-        proj-search\">Search:</label>\n          <input type=\"text\" id=\"proj-search\"\
-        \ name=\"q\" size=\"18\" value=\"\" />\n          <input type=\"submit\" value=\"\
-        Search\" />\n        </div>\n      </form>\n      <div id=\"metanav\" class=\"\
-        nav\">\n    <ul>\n      <li class=\"first\"><a href=\"/about-fedora/openidlogin\"\
-        >OpenID Login</a></li><li><a href=\"https://admin.fedoraproject.org/accounts/user/new\"\
-        >Fedora Account Sign Up</a></li><li><a href=\"/about-fedora/prefs\">Preferences</a></li><li><a\
-        \ href=\"/about-fedora/wiki/TracGuide\">Help/Guide</a></li><li><a href=\"\
-        /about-fedora/about\">About Trac</a></li><li class=\"last\"><a href=\"http://git.fedorahosted.org/cgit/about-fedora.git\"\
-        >CGit</a></li>\n    </ul>\n  </div>\n    </div>\n    <div id=\"mainnav\" class=\"\
-        nav\">\n    <ul>\n      <li class=\"first active\"><a href=\"/about-fedora/wiki\"\
-        >Wiki</a></li><li><a href=\"/about-fedora/timeline\">Timeline</a></li><li><a\
-        \ href=\"/about-fedora/roadmap\">Roadmap</a></li><li><a href=\"/about-fedora/browser\"\
-        >Browse Source</a></li><li><a href=\"/about-fedora/report\">View Tickets</a></li><li\
-        \ class=\"last\"><a href=\"/about-fedora/search\">Search</a></li>\n    </ul>\n\
-        \  </div>\n    <div id=\"main\">\n      <div id=\"pagepath\" class=\"noprint\"\
-        >\n  <a class=\"pathentry first\" title=\"View WikiStart\" href=\"/about-fedora/wiki\"\
-        >wiki:</a><a class=\"pathentry\" href=\"/about-fedora/wiki/WikiStart\" title=\"\
-        View WikiStart\">WikiStart</a>\n</div>\n      <div id=\"ctxtnav\" class=\"\
-        nav\">\n        <h2>Context Navigation</h2>\n          <ul>\n            \
-        \  <li class=\"first\"><a href=\"/about-fedora/wiki/WikiStart\">Start Page</a></li><li><a\
-        \ href=\"/about-fedora/wiki/TitleIndex\">Index</a></li><li class=\"last\"\
-        ><a href=\"/about-fedora/wiki/WikiStart?action=history\">History</a></li>\n\
-        \          </ul>\n        <hr />\n      </div>\n    <div id=\"content\" class=\"\
-        wiki\">\n      <div class=\"wikipage searchable\">\n        \n          \n\
-        \          <div class=\"trac-modifiedby\">\n            <span><a href=\"/about-fedora/wiki/WikiStart?action=diff&amp;version=5\"\
-        \ title=\"Version 5 by quaid: adding step to self-intro\">Last modified</a>\
-        \ <a class=\"timeline\" href=\"/about-fedora/timeline?from=2009-02-09T03%3A57%3A48Z&amp;precision=second\"\
-        \ title=\"2009-02-09T03:57:48Z in Timeline\">8 years</a> ago</span>\n    \
-        \        <span class=\"trac-print\">Last modified on 02/09/09 03:57:48</span>\n\
-        \          </div>\n          <div id=\"wikipage\"><h1 id=\"Whatisthissite\"\
-        >What is this site?</h1>\n<p>\nThis is the source project for About Fedora.\
-        \  It includes a <tt>git</tt> repo and a database for tracking how we develop\
-        \ the source toolchain.  \n</p>\n<p>\nIt's all part of the <a class=\"ext-link\"\
-        \ href=\"https://fedoraproject.org/wiki/Overview\"><span class=\"icon\">\u200B\
-        </span>Fedora Project</a>.  This site, in particular, is run by the <a class=\"\
-        ext-link\" href=\"https://fedoraproject.org/wiki/DocsProject\"><span class=\"\
-        icon\">\u200B</span>Fedora Documentation team</a>.\n</p>\n<p>\nIf you want\
-        \ to look at what we've created, use the \"Browse Source\" link above and\
-        \ to the right.\n</p>\n<h1 id=\"AboutFedorahassomethingmissingorwrong.\">About\
-        \ Fedora has something missing or wrong.</h1>\n<p>\nIf you need to tell us\
-        \ that something is wrong in About Fedora, visit <a class=\"ext-link\" href=\"\
-        https://bugzilla.redhat.com/bugzilla\"><span class=\"icon\">\u200B</span>Bugzilla</a>.\
-        \  File a bug against the product \"Fedora Documentation,\" component \"about-fedora\"\
-        .\n</p>\n<h1 id=\"Iwanttohelpwiththecontent.\">I want to help with the content.</h1>\n\
-        <p>\nIf you want to help update the content of About Fedora, first <a class=\"\
-        ext-link\" href=\"http://fedoraproject.org/wiki/DocsProject/Join#Things_you_need_to_do\"\
-        ><span class=\"icon\">\u200B</span>introduce yourself to the Docs Project</a>.\
-        \  When you've done that, <a class=\"ext-link\" href=\"https://admin.fedoraproject.org/accounts/group/view/gitabout-fedora\"\
-        ><span class=\"icon\">\u200B</span>join our project group</a>.  Then visit\
-        \ <a class=\"ext-link\" href=\"https://fedoraproject.org/wiki/Docs_Project_work_using_git\"\
-        ><span class=\"icon\">\u200B</span>this page on the Fedora Project wiki</a>\
-        \ to find out how to get started using <tt>git</tt>.  These instructions should\
-        \ work for most people with access to this repository:\n</p>\n<pre class=\"\
-        wiki\">cd ~/projects/\ngit clone ssh://&lt;username&gt;@git.fedorahosted.org/git/docs/about-fedora.git\n\
-        git clone git://git.fedorahosted.org/git/fedora-doc-utils docs-common\n</pre><p>\n\
-        If you don't have access to this repo, use <tt>git://</tt> instead of <tt>ssh://</tt>\
-        \ above.\n</p>\n<h1 id=\"Iwanttotranslatethecontenttomylanguage.\">I want\
-        \ to translate the content to my language.</h1>\n<p>\nCheck the <a class=\"\
-        ext-link\" href=\"http://translate.fedoraproject.org/module/docs-about-fedora\"\
-        ><span class=\"icon\">\u200B</span>statistics page</a> to get details about\
-        \ your language and join the <a class=\"ext-link\" href=\"https://fedoraproject.org/wiki/L10N\"\
-        ><span class=\"icon\">\u200B</span>Fedora Translation team</a> if your language\
-        \ is not available.\n</p>\n<h1 id=\"Imconfused.Whatisthissitefor\">I'm confused.\
-        \ What is this site for?</h1>\n<p>\nIf you have questions, come visit the\
-        \ Docs Project on IRC.  IRC is a way to communicate in real time with other\
-        \ Fedora Project members.  You can find more information <a class=\"ext-link\"\
-        \ href=\"https://fedoraproject.org/wiki/Communicate/IRC\"><span class=\"icon\"\
-        >\u200B</span>here</a>.\n</p>\n</div>\n        \n        \n      </div>\n\
-        \      \n\n    </div>\n    <div id=\"altlinks\">\n      <h3>Download in other\
-        \ formats:</h3>\n      <ul>\n        <li class=\"last first\">\n         \
-        \ <a rel=\"nofollow\" href=\"/about-fedora/wiki/WikiStart?format=txt\">Plain\
-        \ Text</a>\n        </li>\n      </ul>\n    </div>\n    </div>\n    <div id=\"\
-        footer\" lang=\"en\" xml:lang=\"en\"><hr />\n      <a id=\"tracpowered\" href=\"\
-        http://trac.edgewall.org/\"><img src=\"/about-fedora/chrome/common/trac_logo_mini.png\"\
-        \ height=\"30\" width=\"107\" alt=\"Trac Powered\" /></a>\n      <p class=\"\
-        left\">Powered by <a href=\"/about-fedora/about\"><strong>Trac 0.12.5</strong></a><br\
-        \ />\n        By <a href=\"http://www.edgewall.org/\">Edgewall Software</a>.<p\
-        \ class=\"left\">Libravatar support by <a href=\"https://bitbucket.org/zzzeek/tracvatar\"\
-        >Tracvatar 1.9</a></p></p>\n      <p class=\"right\">Visit the Trac open source\
-        \ project at<br /><a href=\"http://trac.edgewall.org/\">http://trac.edgewall.org/</a></p>\n\
-        \    </div>\n    <!-- Tack on our fedmenu stuff for this trac. -->\n    <script\
-        \ src=\"https://apps.fedoraproject.org/fedmenu/js/jquery-1.11.2.min.js\"></script>\n\
-        \    <script src=\"https://apps.fedoraproject.org/fedmenu/js/fedmenu.js\"\
-        ></script>\n    <script>\n      fedmenu({\n        'url': 'https://apps.fedoraproject.org/js/data.js',\n\
-        \        'mimeType': 'application/javascript',\n        'position': 'bottom-right',\n\
-        \      });\n    </script>\n  </body>\n</html>"}
-    headers:
-      cache-control: [must-revalidate]
-      connection: [Keep-Alive]
-      content-length: ['9437']
-      content-type: [text/html;charset=utf-8]
-      date: ['Tue, 14 Feb 2017 10:57:38 GMT']
-      expires: ['Fri, 01 Jan 1999 00:00:00 GMT']
-      keep-alive: ['timeout=5, max=500']
-      server: [Apache/2.2.15 (Red Hat)]
-      set-cookie: [trac_form_token=8344c426dbc2cc320d5e431d; Path=/about-fedora, 'trac_session=808a3fc5547b36ddaca5f057;
-          expires=Mon, 15-May-2017 10:57:39 GMT; Path=/about-fedora']
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-    status: {code: 200, message: Ok}
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://fedorahosted.org/something-that-does-not-exist/
-  response:
-    body: {string: !!python/unicode '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
-
-        <html><head>
-
-        <title>302 Found</title>
-
-        </head><body>
-
-        <h1>Found</h1>
-
-        <p>The document has moved <a href="https://fedorahosted.org/web/410">here</a>.</p>
-
-        <hr>
-
-        <address>Apache/2.2.15 (Red Hat) Server at fedorahosted.org Port 443</address>
-
-        </body></html>
-
-        '}
-    headers:
-      connection: [Keep-Alive]
-      content-length: ['300']
-      content-type: [text/html; charset=iso-8859-1]
-      date: ['Tue, 14 Feb 2017 10:57:40 GMT']
-      keep-alive: ['timeout=5, max=500']
-      location: ['https://fedorahosted.org/web/410']
-      server: [Apache/2.2.15 (Red Hat)]
-      strict-transport-security: [max-age=15768000; includeSubDomains; preload]
-    status: {code: 302, message: Found}
-version: 1
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index 98fef57..bf05a53 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -138,18 +138,6 @@ class PagureRepo(Validator):
         raise ValueError('Invalid pagure repo')
 
 
-class FedorahostedProject(Validator):
-    """Fails if the FedoraHosted project name does not exist."""
-
-    @classmethod
-    def from_string(cls, value):
-        response = requests.get("https://fedorahosted.org/%s/" % value,
-                                timeout=5, allow_redirects=False)
-        if response.status_code == 200:
-            return value
-        raise ValueError('Invalid fedorahosted project')
-
-
 class CommaSeparatedList(Validator):
     """Fails if the value isn't a comma-separated list.
 

From d90f85b8570246a34a21156f7f46af7b8ae377e7 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 26 2017 16:42:52 +0000
Subject: [PATCH 907/1001] Fix unit tests


---

diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index d0e6a6c..420bd05 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -42,7 +42,10 @@
     "unmockedModulePathPatterns": [
       "<rootDir>/node_modules/react/",
       "<rootDir>/node_modules/react-dom/",
-      "<rootDir>/node_modules/react-addons-test-utils/"
+      "<rootDir>/node_modules/prop-types/",
+      "<rootDir>/node_modules/react-addons-test-utils/",
+      "<rootDir>/node_modules/react-intl/",
+      "<rootDir>/node_modules/intl-messageformat/"
     ]
   },
   "author": "Eric Barbour <ebarbour@redhat.com>",
diff --git a/hubs/tests/test_widget_view.py b/hubs/tests/test_widget_view.py
index 328d207..6b17af2 100644
--- a/hubs/tests/test_widget_view.py
+++ b/hubs/tests/test_widget_view.py
@@ -1,13 +1,9 @@
 from __future__ import unicode_literals
 
-import six
-from mock import Mock
-
 from hubs.app import app
 from hubs.tests import APPTest
 from hubs.widgets.base import Widget
-from hubs.widgets.caching import CachedFunction
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 
 
 class TestingWidget(Widget):
diff --git a/hubs/tests/utils/test_pkgdb.py b/hubs/tests/utils/test_pkgdb.py
index 36f4905..c5f193a 100644
--- a/hubs/tests/utils/test_pkgdb.py
+++ b/hubs/tests/utils/test_pkgdb.py
@@ -20,7 +20,7 @@ class PkgdbUtilsTest(APPTest):
         cache.delete("owned_packages:abompard")
 
     def _is_cached(self):
-        result = cache.get("owned_packages:abompard", ignore_expiration=True)
+        result = cache.get(b"owned_packages:abompard", ignore_expiration=True)
         return not isinstance(result, dogpile.cache.api.NoValue)
 
     def test_get_owned_packages(self):
diff --git a/hubs/tests/widgets/test_about.py b/hubs/tests/widgets/test_about.py
index 0766de2..1cb4ab1 100644
--- a/hubs/tests/widgets/test_about.py
+++ b/hubs/tests/widgets/test_about.py
@@ -18,6 +18,7 @@ class TestAbout(WidgetTest):
             'text': 'Testing.',
             'title': "<span class='glyphicon glyphicon-info-sign' "
                      "aria-hidden='true'></span> About",
+            'edit_mode': False,
         })
 
     def test_view_authz(self):
diff --git a/hubs/tests/widgets/test_contact.py b/hubs/tests/widgets/test_contact.py
index 03f24e7..8bea137 100644
--- a/hubs/tests/widgets/test_contact.py
+++ b/hubs/tests/widgets/test_contact.py
@@ -86,6 +86,7 @@ class ContactsTest(WidgetTest):
             'location': 'United States',
             'timezone': 'UTC',
             'usergroup': True,
+            'edit_mode': False,
         })
 
     def test_view_authz(self):
diff --git a/hubs/tests/widgets/test_fedmsgstats.py b/hubs/tests/widgets/test_fedmsgstats.py
index c7f7ce2..2a4508a 100644
--- a/hubs/tests/widgets/test_fedmsgstats.py
+++ b/hubs/tests/widgets/test_fedmsgstats.py
@@ -15,15 +15,16 @@ class TestFedmsgStats(WidgetTest):
         response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
-            u'fedmsgs': 83854,
-            u'fedmsgs_text': u'83,854',
-            u'subscribers': [],
-            u'subscribed_to': [],
-            u'subscribers_text': u'0',
-            u'subscribed_text': u'0',
-            u'username': u'ralph',
-            u'hub_subscribe_url': u'/api/hub/ralph/subscribe',
-            u'hub_unsubscribe_url': u'/api/hub/ralph/unsubscribe',
+            'fedmsgs': 83854,
+            'fedmsgs_text': '83,854',
+            'subscribers': [],
+            'subscribed_to': [],
+            'subscribers_text': '0',
+            'subscribed_text': '0',
+            'username': 'ralph',
+            'hub_subscribe_url': '/api/hub/ralph/subscribe',
+            'hub_unsubscribe_url': '/api/hub/ralph/unsubscribe',
+            'edit_mode': False,
         })
 
     def test_view_authz(self):
diff --git a/hubs/tests/widgets/test_library.py b/hubs/tests/widgets/test_library.py
index f8651e4..11e4c92 100644
--- a/hubs/tests/widgets/test_library.py
+++ b/hubs/tests/widgets/test_library.py
@@ -23,6 +23,7 @@ class TestLibrary(WidgetTest):
                 "urls": [
                     "<a href=\"ralph/\">ralph/</a>"
                 ],
+                'edit_mode': False,
             },
             "description": None,
             "hub": "ralph",
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index 196ace3..0c01124 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 
 
 class About(Widget):
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index ee1ff98..1e5fcea 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -5,7 +5,7 @@ import requests
 
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index a57d72b..8731c8a 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -7,7 +7,7 @@ import pkgwat.api
 from hubs.utils.pkgdb import get_owned_packages
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index c5aec95..3794bb3 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -147,6 +147,8 @@ class RootWidgetView(WidgetView):
         """
         Export the edit mode status to the template
         """
-        context = super(RootWidgetView, self).get_extra_context(*args, **kwargs)
-        context["edit_mode"] = flask.request.args.get("editmode", "", type=bool)
+        context = super(RootWidgetView, self).get_extra_context(
+            *args, **kwargs)
+        context["edit_mode"] = flask.request.args.get(
+            "editmode", False, type=bool)
         return context
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 8db3aeb..f7b0c4b 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -5,7 +5,7 @@ import requests
 from hubs.utils import username2avatar
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 413631b..6b87c03 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -4,7 +4,7 @@ import requests
 
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 

From 36f6714e9f1e5b226313a6f06a8d7836f22afe9a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 26 2017 16:45:36 +0000
Subject: [PATCH 908/1001] Only top-level elements should instantiate IntlProvider, not components


---

diff --git a/hubs/static/client/app/components/feed/Feed.jsx b/hubs/static/client/app/components/feed/Feed.jsx
index ec6b037..a11176e 100644
--- a/hubs/static/client/app/components/feed/Feed.jsx
+++ b/hubs/static/client/app/components/feed/Feed.jsx
@@ -1,7 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import {
-  IntlProvider,
   defineMessages,
   FormattedMessage,
   } from 'react-intl';
@@ -26,15 +25,13 @@ export default class Feed extends React.Component {
         );
     });
     return (
-      <IntlProvider locale={navigator.language}>
-        <div className="component-feed">
-          { (items.length == 0 && this.props.loaded) ?
-            <FormattedMessage {...messages.no_items} tagName="i" />
-            :
-            items
-          }
-        </div>
-      </IntlProvider>
+      <div className="component-feed">
+        { (items.length == 0 && this.props.loaded) ?
+          <FormattedMessage {...messages.no_items} tagName="i" />
+          :
+          items
+        }
+      </div>
     );
   }
 
diff --git a/hubs/static/client/app/widgets/feed/Widget.jsx b/hubs/static/client/app/widgets/feed/Widget.jsx
index b266609..b60a6eb 100644
--- a/hubs/static/client/app/widgets/feed/Widget.jsx
+++ b/hubs/static/client/app/widgets/feed/Widget.jsx
@@ -1,4 +1,5 @@
 import React from 'react';
+import {IntlProvider} from 'react-intl';
 import ItemsGetter from '../../components/feed/ItemsGetter.jsx';
 import Feed from '../../components/feed/Feed.jsx';
 
@@ -23,19 +24,21 @@ export default class Widget extends React.Component {
 
   render() {
     return (
-      <ItemsGetter
-        url={this.props.url}
-        sse={{
-          eventName: "hubs:widget-updated",
-          shouldReload: (idx) => (parseInt(idx) === this.props.widgetIdx),
-        }}
-        handleData={this.handleServerData}
-        >
-        <Feed
-          items={this.state.items}
-          loaded={this.state.loaded}
-          />
-      </ItemsGetter>
+      <IntlProvider locale={navigator.language}>
+        <ItemsGetter
+          url={this.props.url}
+          sse={{
+            eventName: "hubs:widget-updated",
+            shouldReload: (idx) => (parseInt(idx) === this.props.widgetIdx),
+          }}
+          handleData={this.handleServerData}
+          >
+          <Feed
+            items={this.state.items}
+            loaded={this.state.loaded}
+            />
+        </ItemsGetter>
+      </IntlProvider>
     );
   }
 

From ff23468efd47fefd2bb3f1fe190c194cc09ede3f Mon Sep 17 00:00:00 2001
From: Sayak Sarkar <ssarkar@redhat.com>
Date: Jul 27 2017 12:03:48 +0000
Subject: [PATCH 909/1001] Added python3-tox to the list of packages to be instaled by Ansible when dev_mode is True. Fixes #363.


---

diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index b2de8bd..be0c8c9 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -24,6 +24,7 @@
     - python-sphinx
     - python2-devel
     - python3-devel
+    - python3-tox
     - redhat-rpm-config
     - sqlite-devel
   when: hubs_dev_mode

From def5e03f4e58f1515f4a838ff59ccef5a0b40850 Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Jul 29 2017 12:44:54 +0000
Subject: [PATCH 910/1001] Merge #365 `Fix unit tests`


---

diff --git a/hubs/static/client/app/components/feed/Feed.jsx b/hubs/static/client/app/components/feed/Feed.jsx
index ec6b037..a11176e 100644
--- a/hubs/static/client/app/components/feed/Feed.jsx
+++ b/hubs/static/client/app/components/feed/Feed.jsx
@@ -1,7 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import {
-  IntlProvider,
   defineMessages,
   FormattedMessage,
   } from 'react-intl';
@@ -26,15 +25,13 @@ export default class Feed extends React.Component {
         );
     });
     return (
-      <IntlProvider locale={navigator.language}>
-        <div className="component-feed">
-          { (items.length == 0 && this.props.loaded) ?
-            <FormattedMessage {...messages.no_items} tagName="i" />
-            :
-            items
-          }
-        </div>
-      </IntlProvider>
+      <div className="component-feed">
+        { (items.length == 0 && this.props.loaded) ?
+          <FormattedMessage {...messages.no_items} tagName="i" />
+          :
+          items
+        }
+      </div>
     );
   }
 
diff --git a/hubs/static/client/app/widgets/feed/Widget.jsx b/hubs/static/client/app/widgets/feed/Widget.jsx
index b266609..b60a6eb 100644
--- a/hubs/static/client/app/widgets/feed/Widget.jsx
+++ b/hubs/static/client/app/widgets/feed/Widget.jsx
@@ -1,4 +1,5 @@
 import React from 'react';
+import {IntlProvider} from 'react-intl';
 import ItemsGetter from '../../components/feed/ItemsGetter.jsx';
 import Feed from '../../components/feed/Feed.jsx';
 
@@ -23,19 +24,21 @@ export default class Widget extends React.Component {
 
   render() {
     return (
-      <ItemsGetter
-        url={this.props.url}
-        sse={{
-          eventName: "hubs:widget-updated",
-          shouldReload: (idx) => (parseInt(idx) === this.props.widgetIdx),
-        }}
-        handleData={this.handleServerData}
-        >
-        <Feed
-          items={this.state.items}
-          loaded={this.state.loaded}
-          />
-      </ItemsGetter>
+      <IntlProvider locale={navigator.language}>
+        <ItemsGetter
+          url={this.props.url}
+          sse={{
+            eventName: "hubs:widget-updated",
+            shouldReload: (idx) => (parseInt(idx) === this.props.widgetIdx),
+          }}
+          handleData={this.handleServerData}
+          >
+          <Feed
+            items={this.state.items}
+            loaded={this.state.loaded}
+            />
+        </ItemsGetter>
+      </IntlProvider>
     );
   }
 
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index d0e6a6c..420bd05 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -42,7 +42,10 @@
     "unmockedModulePathPatterns": [
       "<rootDir>/node_modules/react/",
       "<rootDir>/node_modules/react-dom/",
-      "<rootDir>/node_modules/react-addons-test-utils/"
+      "<rootDir>/node_modules/prop-types/",
+      "<rootDir>/node_modules/react-addons-test-utils/",
+      "<rootDir>/node_modules/react-intl/",
+      "<rootDir>/node_modules/intl-messageformat/"
     ]
   },
   "author": "Eric Barbour <ebarbour@redhat.com>",
diff --git a/hubs/tests/test_widget_view.py b/hubs/tests/test_widget_view.py
index 328d207..6b17af2 100644
--- a/hubs/tests/test_widget_view.py
+++ b/hubs/tests/test_widget_view.py
@@ -1,13 +1,9 @@
 from __future__ import unicode_literals
 
-import six
-from mock import Mock
-
 from hubs.app import app
 from hubs.tests import APPTest
 from hubs.widgets.base import Widget
-from hubs.widgets.caching import CachedFunction
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 
 
 class TestingWidget(Widget):
diff --git a/hubs/tests/utils/test_pkgdb.py b/hubs/tests/utils/test_pkgdb.py
index 36f4905..c5f193a 100644
--- a/hubs/tests/utils/test_pkgdb.py
+++ b/hubs/tests/utils/test_pkgdb.py
@@ -20,7 +20,7 @@ class PkgdbUtilsTest(APPTest):
         cache.delete("owned_packages:abompard")
 
     def _is_cached(self):
-        result = cache.get("owned_packages:abompard", ignore_expiration=True)
+        result = cache.get(b"owned_packages:abompard", ignore_expiration=True)
         return not isinstance(result, dogpile.cache.api.NoValue)
 
     def test_get_owned_packages(self):
diff --git a/hubs/tests/widgets/test_about.py b/hubs/tests/widgets/test_about.py
index 0766de2..1cb4ab1 100644
--- a/hubs/tests/widgets/test_about.py
+++ b/hubs/tests/widgets/test_about.py
@@ -18,6 +18,7 @@ class TestAbout(WidgetTest):
             'text': 'Testing.',
             'title': "<span class='glyphicon glyphicon-info-sign' "
                      "aria-hidden='true'></span> About",
+            'edit_mode': False,
         })
 
     def test_view_authz(self):
diff --git a/hubs/tests/widgets/test_contact.py b/hubs/tests/widgets/test_contact.py
index 03f24e7..8bea137 100644
--- a/hubs/tests/widgets/test_contact.py
+++ b/hubs/tests/widgets/test_contact.py
@@ -86,6 +86,7 @@ class ContactsTest(WidgetTest):
             'location': 'United States',
             'timezone': 'UTC',
             'usergroup': True,
+            'edit_mode': False,
         })
 
     def test_view_authz(self):
diff --git a/hubs/tests/widgets/test_fedmsgstats.py b/hubs/tests/widgets/test_fedmsgstats.py
index c7f7ce2..2a4508a 100644
--- a/hubs/tests/widgets/test_fedmsgstats.py
+++ b/hubs/tests/widgets/test_fedmsgstats.py
@@ -15,15 +15,16 @@ class TestFedmsgStats(WidgetTest):
         response = self.check_url('/ralph/%i/json' % widget.idx, user)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data['data'], {
-            u'fedmsgs': 83854,
-            u'fedmsgs_text': u'83,854',
-            u'subscribers': [],
-            u'subscribed_to': [],
-            u'subscribers_text': u'0',
-            u'subscribed_text': u'0',
-            u'username': u'ralph',
-            u'hub_subscribe_url': u'/api/hub/ralph/subscribe',
-            u'hub_unsubscribe_url': u'/api/hub/ralph/unsubscribe',
+            'fedmsgs': 83854,
+            'fedmsgs_text': '83,854',
+            'subscribers': [],
+            'subscribed_to': [],
+            'subscribers_text': '0',
+            'subscribed_text': '0',
+            'username': 'ralph',
+            'hub_subscribe_url': '/api/hub/ralph/subscribe',
+            'hub_unsubscribe_url': '/api/hub/ralph/unsubscribe',
+            'edit_mode': False,
         })
 
     def test_view_authz(self):
diff --git a/hubs/tests/widgets/test_library.py b/hubs/tests/widgets/test_library.py
index f8651e4..11e4c92 100644
--- a/hubs/tests/widgets/test_library.py
+++ b/hubs/tests/widgets/test_library.py
@@ -23,6 +23,7 @@ class TestLibrary(WidgetTest):
                 "urls": [
                     "<a href=\"ralph/\">ralph/</a>"
                 ],
+                'edit_mode': False,
             },
             "description": None,
             "hub": "ralph",
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index 196ace3..0c01124 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 
 
 class About(Widget):
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index ee1ff98..1e5fcea 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -5,7 +5,7 @@ import requests
 
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index a57d72b..8731c8a 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -7,7 +7,7 @@ import pkgwat.api
 from hubs.utils.pkgdb import get_owned_packages
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index c5aec95..3794bb3 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -147,6 +147,8 @@ class RootWidgetView(WidgetView):
         """
         Export the edit mode status to the template
         """
-        context = super(RootWidgetView, self).get_extra_context(*args, **kwargs)
-        context["edit_mode"] = flask.request.args.get("editmode", "", type=bool)
+        context = super(RootWidgetView, self).get_extra_context(
+            *args, **kwargs)
+        context["edit_mode"] = flask.request.args.get(
+            "editmode", False, type=bool)
         return context
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
index 8db3aeb..f7b0c4b 100644
--- a/hubs/widgets/workflow/pendingacls.py
+++ b/hubs/widgets/workflow/pendingacls.py
@@ -5,7 +5,7 @@ import requests
 from hubs.utils import username2avatar
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 413631b..6b87c03 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -4,7 +4,7 @@ import requests
 
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import RootWidgetView
 from hubs.widgets.caching import CachedFunction
 
 

From 3359be026581248705f7082012291be0c1fd28dd Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 29 2017 16:24:16 +0000
Subject: [PATCH 911/1001] Use Honcho to start the services in the VM in dev mode


---

diff --git a/ansible/files/motd b/ansible/files/motd
index fdd814a..b5fd69d 100644
--- a/ansible/files/motd
+++ b/ansible/files/motd
@@ -7,11 +7,11 @@ Here are some tips:
 
 * You can type `workon hubs` to enter a configured Python virtualenv
 
-* Run `hup` to start the flask webserver
+* Run `honcho start` to start the webserver and the backend services.
 
 * Run `hreset` to delete the database and repopulate it
 
-Once you run `hup` you can navigate to http://localhost:5000/
+Once you run `honcho start` you can navigate to http://localhost:5000/
 in your browser.
 
 Happy hacking!
diff --git a/ansible/roles/hubs/tasks/dev.yml b/ansible/roles/hubs/tasks/dev.yml
new file mode 100644
index 0000000..9b3133c
--- /dev/null
+++ b/ansible/roles/hubs/tasks/dev.yml
@@ -0,0 +1,23 @@
+- name: Install Fedora Hubs development packages
+  dnf: name={{ item }} state=present
+  with_items:
+    - gcc
+    - gcc-c++
+    - libffi-devel
+    - openssl-devel
+    - python-sphinx
+    - python2-devel
+    - python3-devel
+    - python3-honcho
+    - python3-tox
+    - redhat-rpm-config
+    - sqlite-devel
+
+- name: Install a custom bashrc
+  template: src=bashrc dest=/home/{{ main_user }}/.bashrc
+
+- name: Install Honcho's env file
+  template: src=honcho-env dest={{ hubs_base_dir }}/.env
+
+- name: Install Honcho's procfile
+  template: src=honcho-procfile dest={{ hubs_base_dir }}/Procfile
diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index be0c8c9..2aa310a 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -14,21 +14,6 @@
     - python-virtualenv
     - python3-flask-oidc
 
-- name: Install Fedora Hubs development packages
-  dnf: name={{ item }} state=present
-  with_items:
-    - gcc
-    - gcc-c++
-    - libffi-devel
-    - openssl-devel
-    - python-sphinx
-    - python2-devel
-    - python3-devel
-    - python3-tox
-    - redhat-rpm-config
-    - sqlite-devel
-  when: hubs_dev_mode
-
 - name: Install the distribution versions of requirements.txt
   dnf: name={{ item }} state=present
   with_items:
@@ -56,12 +41,6 @@
     - python-retask
 
 
-# Add various helpful configuration files
-- name: Install a custom bashrc
-  template: src=bashrc dest=/home/{{ main_user }}/.bashrc
-  when: hubs_dev_mode
-
-
 # Create directory structure
 
 - name: Create the directory structure
@@ -169,33 +148,16 @@
 - name: Disable the system-wide fedmsg-hub
   service: name=fedmsg-hub state=stopped enabled=no
 
-- name: Install the service files
-  template:
-    src: "{{ item }}.service"
-    dest: /etc/systemd/system/{{ item }}.service
-  with_items:
-    - hubs-triage@
-    - hubs-worker@
-    - hubs-sse
-    - hubs-fedmsg-hub
-  register: service_installed
-
-- name: reload systemd
-  command: systemctl daemon-reload
-  when: service_installed|changed
-
-- name: Start and enable the services
+- name: Start and enable the common services
   service: name={{ item }} state=started enabled=yes
   with_items:
     - redis
-    - hubs-triage@1
-    - hubs-triage@2
-    - hubs-worker@1
-    - hubs-worker@2
-    - hubs-sse
-    - hubs-fedmsg-hub
 
 
-# Webserver
-- include: webserver.yml
+# Include mode-specific tasks
+
+- include: dev.yml
+  when: hubs_dev_mode
+
+- include: prod.yml
   when: not hubs_dev_mode
diff --git a/ansible/roles/hubs/tasks/prod.yml b/ansible/roles/hubs/tasks/prod.yml
new file mode 100644
index 0000000..0f8bb3d
--- /dev/null
+++ b/ansible/roles/hubs/tasks/prod.yml
@@ -0,0 +1,26 @@
+- name: Install the service files
+  template:
+    src: "{{ item }}.service"
+    dest: /etc/systemd/system/{{ item }}.service
+  with_items:
+    - hubs-triage@
+    - hubs-worker@
+    - hubs-sse
+    - hubs-fedmsg-hub
+  register: service_installed
+
+- name: reload systemd
+  command: systemctl daemon-reload
+  when: service_installed|changed
+
+- name: Start and enable the services in prod mode
+  service: name={{ item }} state=started enabled=yes
+  with_items:
+    - hubs-triage@1
+    - hubs-triage@2
+    - hubs-worker@1
+    - hubs-worker@2
+    - hubs-sse
+    - hubs-fedmsg-hub
+
+- include: webserver.yml
diff --git a/ansible/roles/hubs/templates/bashrc b/ansible/roles/hubs/templates/bashrc
index 8902729..f7004fa 100644
--- a/ansible/roles/hubs/templates/bashrc
+++ b/ansible/roles/hubs/templates/bashrc
@@ -23,14 +23,9 @@ workon() {
     cd {{ hubs_code_dir }}
 }
 
-hup() {
-    source {{ hubs_venv_dir }}/bin/activate
-    pushd {{ hubs_code_dir }}
-    FLASK_DEBUG=1 flask run --host 0.0.0.0 --port 5000
-}
+alias hup="pushd ~ ; honcho start ; popd"
 
 hreset() {
-    source {{ hubs_venv_dir }}/bin/activate
     {% if hubs_db_type == "postgresql" %}
     sudo -u postgres dropdb hubs
     sudo -u postgres createdb -O hubs hubs
@@ -39,7 +34,6 @@ hreset() {
     {% endif %}
     rm {{ hubs_var_dir }}/cache.db
     pushd {{ hubs_code_dir }}
-    python populate.py
+    {{ hubs_venv_dir }}/bin/python populate.py
     popd
-    deactivate
 }
diff --git a/ansible/roles/hubs/templates/honcho-env b/ansible/roles/hubs/templates/honcho-env
new file mode 100644
index 0000000..352c551
--- /dev/null
+++ b/ansible/roles/hubs/templates/honcho-env
@@ -0,0 +1,3 @@
+FLASK_DEBUG=1
+FLASK_APP={{ hubs_code_dir }}/hubs/app.py
+HUBS_CONFIG={{ hubs_conf_dir }}/hubs_config.py
diff --git a/ansible/roles/hubs/templates/honcho-procfile b/ansible/roles/hubs/templates/honcho-procfile
new file mode 100644
index 0000000..ee8a451
--- /dev/null
+++ b/ansible/roles/hubs/templates/honcho-procfile
@@ -0,0 +1,6 @@
+web: {{ hubs_venv_dir }}/bin/python /usr/bin/flask run --host 0.0.0.0 --port 5000
+triage: {{ hubs_venv_dir }}/bin/fedora-hubs-triage
+worker: {{ hubs_venv_dir }}/bin/fedora-hubs-worker
+sse: {{ hubs_venv_dir }}/bin/python /usr/bin/twistd -l - --pidfile= -ny {{ hubs_code_dir }}/hubs/backend/sse_server.tac
+fedmsg_hub: {{ hubs_venv_dir }}/bin/python /usr/bin/fedmsg-hub
+js_build: cd {{ hubs_code_dir }}/hubs/static/client && npm run dev
diff --git a/ansible/vagrant-playbook.yml b/ansible/vagrant-playbook.yml
index a691079..f24cfa8 100644
--- a/ansible/vagrant-playbook.yml
+++ b/ansible/vagrant-playbook.yml
@@ -27,3 +27,12 @@
         state: link
         path: /home/{{ main_user }}/devel
         src: /srv/hubs/fedora-hubs
+
+    - name: Make a symlink to the Honcho files
+      file:
+        state: link
+        path: /home/{{ main_user }}/{{ item }}
+        src: /srv/hubs/{{ item }}
+      with_items:
+      - Procfile
+      - .env

From ac53197aba95e78d76828b185b17c97f4e36d754 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 30 2017 14:14:27 +0000
Subject: [PATCH 912/1001] Get widget parameter defaults more dynamically


---

diff --git a/hubs/models.py b/hubs/models.py
index 0a58e40..f894c22 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -28,6 +28,7 @@ import logging
 import operator
 import os
 import random
+from collections import defaultdict
 
 import bleach
 import sqlalchemy as sa
@@ -346,12 +347,18 @@ class HubConfig(BASE):
         return 12 - self.left_width
 
 
-def _widget_config_default(context):
-    widget_name = context.current_parameters['plugin']
-    widget = hubs.widgets.registry[widget_name]
-    return json.dumps(dict([
-        (param.name, param.default) for param in widget.get_parameters()
-        ]))
+class SpecificDefaultDict(defaultdict):
+    """A more specific version of defaultdict.
+
+    This class behaves like defaultdict, but calls the ``default_factory`` with
+    the key as first argument.
+    """
+
+    def __missing__(self, key):
+        if self.default_factory is None:
+            return super(SpecificDefaultDict, self).__missing__(key)
+        self[key] = self.default_factory(key)
+        return self[key]
 
 
 class Widget(ObjectAuthzMixin, BASE):
@@ -364,7 +371,7 @@ class Widget(ObjectAuthzMixin, BASE):
     plugin = sa.Column(sa.String(50), nullable=False)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
     hub_id = sa.Column(sa.String(50), sa.ForeignKey('hubs.name'))
-    _config = sa.Column(sa.Text, default=_widget_config_default)
+    _config = sa.Column(sa.Text, default="{}")
 
     index = sa.Column(sa.Integer, nullable=False)
     left = sa.Column(sa.Boolean, nullable=False, default=False)
@@ -388,7 +395,17 @@ class Widget(ObjectAuthzMixin, BASE):
 
     @property
     def config(self):
-        return json.loads(self._config)
+        def get_default(key):
+            for param in self.module.get_parameters():
+                if key == param.name:
+                    break
+            else:
+                raise KeyError("No such parameter")
+            return param.default
+
+        value = SpecificDefaultDict(get_default)
+        value.update(json.loads(self._config))
+        return value
 
     @config.setter
     def config(self, config):
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index aa8c5b8..7f35b37 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -9,6 +9,7 @@ import six
 from importlib import import_module
 from .caching import CachedFunction
 from .view import WidgetView
+from .validators import Validator
 
 
 log = logging.getLogger(__name__)
@@ -46,6 +47,9 @@ class WidgetParameter(object):
             setattr(self, name, kwargs.pop(name, None))
         for name in kwargs:
             raise TypeError("Invalid attribute: %s" % name)
+        # Set default validator
+        if self.validator is None:
+            self.validator = Validator
 
 
 class Widget(object):

From 96a5824082b3b0b98c22eb1607e2fd2c07de610b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 30 2017 14:15:19 +0000
Subject: [PATCH 913/1001] Don't force overriding get_context()


---

diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index 3794bb3..fce34b3 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -69,7 +69,7 @@ class WidgetView(View):
         Args:
             instance (hubs.models.Widget): the widget instance.
         """
-        raise NotImplementedError
+        return {}
 
     def get_template(self):
         """

From adefa8a86ddc2a748ade65184262e4e6d94d71f4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Jul 31 2017 11:27:11 +0000
Subject: [PATCH 914/1001] Widget cache must be rebuilt on config change


---

diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index 02abde3..10b7903 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -55,6 +55,7 @@ class CachedFunction(object):
         return "|".join([
             str(self.instance.idx),
             self.__class__.__name__,
+            str(dict(self.instance.config)),
         ]).encode('utf-8')
 
     def get_data(self):

From 73d06206d69719d07ffa63dad059452f05069a96 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 01 2017 12:11:15 +0000
Subject: [PATCH 915/1001] Ansible handlers fixes


---

diff --git a/ansible/roles/hubs/handlers/main.yml b/ansible/roles/hubs/handlers/main.yml
index e87c345..7913d42 100644
--- a/ansible/roles/hubs/handlers/main.yml
+++ b/ansible/roles/hubs/handlers/main.yml
@@ -4,18 +4,22 @@
 - name: restart the hubs-specific fedmsg-hub
   service: name=hubs-fedmsg-hub state=restarted
   listen: "hubs configuration change"
+  when: not hubs_dev_mode
 
 - name: restart hubs triage
   service: name=hubs-triage@* state=restarted
   listen: "hubs configuration change"
+  when: not hubs_dev_mode
 
 - name: restart hubs workers
   service: name=hubs-worker@* state=restarted
   listen: "hubs configuration change"
+  when: not hubs_dev_mode
 
 - name: restart hubs SSE server
   service: name=hubs-sse state=restarted
   listen: "hubs configuration change"
+  when: not hubs_dev_mode
 
 # Webserver
 - include: webserver.yml

From e1ffeb16ee2f1d252d27e3e76b748b7964e4ae7d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 01 2017 13:33:45 +0000
Subject: [PATCH 916/1001] Fix a unit test broken by adefa8a


---

diff --git a/hubs/tests/test_widget_caching.py b/hubs/tests/test_widget_caching.py
index 2a2684f..2b9ec36 100644
--- a/hubs/tests/test_widget_caching.py
+++ b/hubs/tests/test_widget_caching.py
@@ -38,7 +38,7 @@ class CachedFunctionTest(APPTest):
         super(CachedFunctionTest, self).tearDown()
 
     def test_get_cache_key(self):
-        value = "%d|DummyFunction" % self.w_instance.idx
+        value = '%d|DummyFunction|{"text": "Testing."}' % self.w_instance.idx
         self.assertEqual(
             self.fn.get_cache_key(),
             value.encode("ascii"),
diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index 10b7903..c531cc0 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 
 import datetime
+import json
 import logging
 
 import dogpile.cache
@@ -55,7 +56,7 @@ class CachedFunction(object):
         return "|".join([
             str(self.instance.idx),
             self.__class__.__name__,
-            str(dict(self.instance.config)),
+            json.dumps(self.instance.config),
         ]).encode('utf-8')
 
     def get_data(self):

From 811a0c63c33326e522aa96197a2eb88741454913 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 03 2017 10:28:07 +0000
Subject: [PATCH 917/1001] Fix an error with EventSource in edit mode


---

diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 4a7c6e7..ff52725 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -50,7 +50,12 @@ def hub_edit(name):
 def hub_edit_get(hub):
     widgets = get_visible_widgets(hub)
     return flask.render_template(
-        'hubs.html', hub=hub, widgets=widgets, edit=True)
+        'hubs.html',
+        hub=hub,
+        widgets=widgets,
+        edit=True,
+        sse_url=get_sse_url("hub/{}".format(hub.name)),
+        )
 
 
 def hub_edit_post(hub):

From d2fe6340381739cd4bd503c415b0829cf510c6ab Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 09 2017 15:17:24 +0000
Subject: [PATCH 918/1001] Go through the Datagrepper pages


---

diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpFunctionsTestCase.test_execute b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpFunctionsTestCase.test_execute
index 1e03fdc..1dcff5f 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpFunctionsTestCase.test_execute
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpFunctionsTestCase.test_execute
@@ -7,7 +7,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data
index 4d48985..645c292 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data
@@ -7,7 +7,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
@@ -103,7 +103,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub
index 6b0a36a..73f7aba 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_data_wrong_hub
@@ -7,7 +7,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_all b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_all
index dfd7580..87a393c 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_all
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_all
@@ -7,7 +7,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
@@ -103,7 +103,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_date b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_date
index 49d31ac..496366e 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_date
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_date
@@ -7,7 +7,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_hub b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_hub
index c2ca0a7..77ee8a3 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_hub
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_hub
@@ -7,7 +7,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_meetingname b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_meetingname
index 07ed82f..b9c3aa6 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_meetingname
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_meetingname
@@ -7,7 +7,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_people b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_people
index d3b8371..26609f7 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_people
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_people
@@ -7,7 +7,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
diff --git a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_requesters b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_requesters
index cd075ec..00b846c 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_requesters
+++ b/hubs/tests/vcr-request-data/hubs.tests.widgets.test_halp.HalpViewsTestCase.test_search_requesters
@@ -7,7 +7,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
@@ -103,7 +103,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.13.0]
     method: GET
-    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000
+    uri: https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.meetbot.meeting.item.help&delta=864000&page=1
   response:
     body:
       string: !!binary |
diff --git a/hubs/utils/datagrepper.py b/hubs/utils/datagrepper.py
new file mode 100644
index 0000000..42aa8ec
--- /dev/null
+++ b/hubs/utils/datagrepper.py
@@ -0,0 +1,51 @@
+from __future__ import unicode_literals, absolute_import
+
+import logging
+
+import requests
+
+from hubs.app import app
+
+log = logging.getLogger(__name__)
+
+
+def datagrepper_get(args):
+    """Make a query to Datagrepper, and return the ``raw_messages``.
+
+    This function will go through all pages to retrieve all the data.
+
+    Parameters:
+        args (dict): elements of the query string to Datagrepper.
+    """
+    url = "%s/raw" % app.config["DATAGREPPER_URI"]
+    result = []
+    page = 1
+    total_pages = 42  # it doesn't matter for now
+    log.debug("Getting data from Datagrepper: %s", str(args))
+    while page <= total_pages:
+        paged_args = args.copy()
+        paged_args["page"] = page
+        try:
+            # Call Datagrepper, but be careful to set a long timeout, this
+            # query may take some time to complete.
+            response = requests.get(url, paged_args, timeout=60)
+        except requests.exceptions.Timeout:
+            log.warning(
+                "Datagrepper request timed out (args: %s)", paged_args)
+            return None
+        if response.status_code != 200:
+            log.warning(
+                "Datagrepper request failed with args %s: %s",
+                paged_args, response.text)
+            return None
+        try:
+            response = response.json()
+        except ValueError as e:
+            log.warning(
+                "Datagrepper request with args %s could not be converted to "
+                "JSON: %s", paged_args, e)
+            return None
+        result.extend(response["raw_messages"])
+        total_pages = response["pages"]
+        page = page + 1
+    return result
diff --git a/hubs/widgets/halp/functions.py b/hubs/widgets/halp/functions.py
index 89cf0df..662081d 100644
--- a/hubs/widgets/halp/functions.py
+++ b/hubs/widgets/halp/functions.py
@@ -8,10 +8,10 @@ import time
 
 import flask
 import fedmsg.meta
-import requests
 from jinja2.utils import urlize
 
 from hubs.widgets.caching import CachedFunction
+from hubs.utils.datagrepper import datagrepper_get
 from .utils import find_hubs_for_msg
 
 
@@ -29,19 +29,12 @@ class GetRequests(CachedFunction):
 
     def execute(self):
         # return [_format_message(msg) for msg in EXAMPLE_DATA]
-        from hubs.app import app
-        url = "%s/raw" % app.config["DATAGREPPER_URI"]
-        args = {
+        raw_messages = datagrepper_get({
             "topic": self.TOPIC,
             "delta": str(86400 * 10),  # 10 days
-        }
-        log.info("Getting request data from Datagrepper")
-        response = requests.get(url, args)
-        if response.status_code != 200:
-            log.warning("Could not get requests from Datagrepper: %s",
-                        response.text)
-            return []
-        raw_messages = response.json()["raw_messages"]
+        })
+        if raw_messages is None:
+            return None
         return [_format_message(msg) for msg in raw_messages]
 
     def should_invalidate(self, message):
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index 584fb53..a00ad6e 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -40,8 +40,9 @@ class DataView(WidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_requests = GetRequests(instance)
         data = {"requests": []}
+        requests = get_requests() or []
         hubs_filter = flask.request.args.getlist("hubs")
-        for req in get_requests():
+        for req in requests:
             req["hubs"] = find_hubs_for_msg(req)
             if not req["hubs"]:
                 continue
@@ -93,7 +94,8 @@ class SearchView(WidgetView):
 
         # filter the data
         data = {"requests": []}
-        for req in get_requests():
+        requests = get_requests() or []
+        for req in requests:
             req["hubs"] = find_hubs_for_msg(req)
             if not req["hubs"]:
                 continue
@@ -127,8 +129,9 @@ class RequestersView(WidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_requests = GetRequests(instance)
+        requests = get_requests() or []
         results = set([
-            req["author"]["name"] for req in get_requests()
+            req["author"]["name"] for req in requests
             ])
         query = flask.request.args.get("q")
         if query:

From 14abe1437b42ae8ef39ceac188d663e5ec6a07c8 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 09 2017 15:17:24 +0000
Subject: [PATCH 919/1001] Fix documentation


---

diff --git a/docs/api/utils.rst b/docs/api/utils.rst
index e178be4..9154b45 100644
--- a/docs/api/utils.rst
+++ b/docs/api/utils.rst
@@ -19,3 +19,9 @@ Packages database utils
 .. automodule:: hubs.utils.pkgdb
    :members:
 
+Datagrepper utils
+-----------------
+
+.. automodule:: hubs.utils.datagrepper
+   :members:
+
diff --git a/hubs/utils/datagrepper.py b/hubs/utils/datagrepper.py
index 42aa8ec..0a266aa 100644
--- a/hubs/utils/datagrepper.py
+++ b/hubs/utils/datagrepper.py
@@ -4,8 +4,6 @@ import logging
 
 import requests
 
-from hubs.app import app
-
 log = logging.getLogger(__name__)
 
 
@@ -16,7 +14,12 @@ def datagrepper_get(args):
 
     Parameters:
         args (dict): elements of the query string to Datagrepper.
+
+    Returns:
+        list of dictionaries: The accumulated Fedmsg messages in the
+        ``raw_messages`` lists over every page.
     """
+    from hubs.app import app  # Avoid circular import
     url = "%s/raw" % app.config["DATAGREPPER_URI"]
     result = []
     page = 1

From 356aa68191f230e3b2f2a3aaf8da34e9f930437a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 11 2017 13:00:29 +0000
Subject: [PATCH 920/1001] Use Pagure instead of pkgdb in get_user_packages


---

diff --git a/docs/api/utils.rst b/docs/api/utils.rst
index 9154b45..773eb40 100644
--- a/docs/api/utils.rst
+++ b/docs/api/utils.rst
@@ -13,10 +13,10 @@ Caching utils
 .. automodule:: hubs.utils.cache
    :members:
 
-Packages database utils
------------------------
+Package database utils
+----------------------
 
-.. automodule:: hubs.utils.pkgdb
+.. automodule:: hubs.utils.packages
    :members:
 
 Datagrepper utils
diff --git a/hubs/tests/utils/test_packages.py b/hubs/tests/utils/test_packages.py
new file mode 100644
index 0000000..5b258d1
--- /dev/null
+++ b/hubs/tests/utils/test_packages.py
@@ -0,0 +1,65 @@
+from __future__ import unicode_literals
+
+import dogpile
+import dogpile.cache
+from mock import Mock, patch
+
+from hubs.tests import APPTest
+from hubs.utils.cache import cache
+from hubs.utils.packages import get_user_packages
+
+
+class PackageUtilsTest(APPTest):
+
+    def setUp(self):
+        super(PackageUtilsTest, self).setUp()
+        # Use a memory backend, not the default null backend, or we can't test
+        # the caching feature.
+        cache.configure(backend='dogpile.cache.memory',
+                        replace_existing_backend=True)
+        cache.delete("owned_packages:abompard")
+
+    def _is_cached(self):
+        result = cache.get(b"owned_packages:abompard", ignore_expiration=True)
+        return not isinstance(result, dogpile.cache.api.NoValue)
+
+    def test_get_user_packages(self):
+        pkgs = get_user_packages("abompard", use_cache=False)
+        self.assertEqual(len(pkgs), 280)
+        for pkg in pkgs:
+            self.assertEqual(type(pkg), type(""))
+        self.assertFalse(self._is_cached())
+
+    def test_get_user_packages_owned(self):
+        pkgs = get_user_packages("abompard", only_owned=True, use_cache=False)
+        self.assertEqual(len(pkgs), 18)
+        for pkg in pkgs:
+            self.assertEqual(type(pkg), type(""))
+        self.assertFalse(self._is_cached())
+
+    @patch("hubs.utils.packages.requests")
+    def test_get_user_packages_invalid(self, requests):
+        response = Mock()
+        response.json.side_effect = ValueError("invalid value")
+        requests.get.return_value = response
+        pkgs = get_user_packages("abompard", use_cache=False)
+        self.assertListEqual(pkgs, [])
+
+    @patch("hubs.utils.packages.requests")
+    def test_get_user_packages_cache(self, requests):
+        response = Mock()
+        response.json.return_value = {
+            "forks": [],
+            "repos": [],
+            "user": {
+                "name": "abompard",
+                "fullname": "abompard",
+            },
+        }
+        requests.get.return_value = response
+        get_user_packages("abompard", use_cache=True)
+        self.assertTrue(self._is_cached())
+        self.assertEqual(requests.get.call_count, 1)
+        get_user_packages("abompard", use_cache=True)
+        self.assertTrue(self._is_cached())
+        self.assertEqual(requests.get.call_count, 1)
diff --git a/hubs/tests/utils/test_pkgdb.py b/hubs/tests/utils/test_pkgdb.py
deleted file mode 100644
index c5f193a..0000000
--- a/hubs/tests/utils/test_pkgdb.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from __future__ import unicode_literals
-
-import dogpile
-import dogpile.cache
-from mock import Mock, patch
-
-from hubs.tests import APPTest
-from hubs.utils.cache import cache
-from hubs.utils.pkgdb import get_owned_packages
-
-
-class PkgdbUtilsTest(APPTest):
-
-    def setUp(self):
-        super(PkgdbUtilsTest, self).setUp()
-        # Use a memory backend, not the default null backend, or we can't test
-        # the caching feature.
-        cache.configure(backend='dogpile.cache.memory',
-                        replace_existing_backend=True)
-        cache.delete("owned_packages:abompard")
-
-    def _is_cached(self):
-        result = cache.get(b"owned_packages:abompard", ignore_expiration=True)
-        return not isinstance(result, dogpile.cache.api.NoValue)
-
-    def test_get_owned_packages(self):
-        pkgs = get_owned_packages("abompard", use_cache=False)
-        self.assertEqual(len(pkgs), 42)  # not kidding! :-)
-        for pkg in pkgs:
-            self.assertEqual(type(pkg), type(""))
-        self.assertFalse(self._is_cached())
-
-    def test_get_owned_packages_invalid(self):
-        pkgs = get_owned_packages("abompard", use_cache=False)
-        self.assertListEqual(pkgs, [])
-
-    @patch("hubs.utils.pkgdb.requests")
-    def test_get_owned_packages_cache(self, requests):
-        response = Mock()
-        response.json.return_value = {
-            "point of contact": [],
-            "co-maintained": [],
-        }
-        requests.get.return_value = response
-        get_owned_packages("abompard", use_cache=True)
-        self.assertTrue(self._is_cached())
-        self.assertEqual(requests.get.call_count, 1)
-        get_owned_packages("abompard", use_cache=True)
-        self.assertTrue(self._is_cached())
-        self.assertEqual(requests.get.call_count, 1)
diff --git a/hubs/tests/vcr-request-data/hubs.tests.utils.test_packages.PackageUtilsTest.test_get_user_packages b/hubs/tests/vcr-request-data/hubs.tests.utils.test_packages.PackageUtilsTest.test_get_user_packages
new file mode 100644
index 0000000..b39687d
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.utils.test_packages.PackageUtilsTest.test_get_user_packages
@@ -0,0 +1,5160 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.3]
+    method: GET
+    uri: https://src.fedoraproject.org/api/0/user/abompard
+  response:
+    body: {string: "{\n  \"forks\": [],\n  \"repos\": [\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501865563\",\n      \"date_modified\": \"1501865563\",\n      \"description\"\
+        : \"The ampy rpms\",\n      \"fullname\": \"rpms/ampy\",\n      \"id\": 657,\n\
+        \      \"milestones\": {},\n      \"name\": \"ampy\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ianweller\"\n        ],\n        \"owner\": [\n          \"ralph\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501866970\",\n   \
+        \   \"date_modified\": \"1501866970\",\n      \"description\": \"The datagrepper\
+        \ rpms\",\n      \"fullname\": \"rpms/datagrepper\",\n      \"id\": 2300,\n\
+        \      \"milestones\": {},\n      \"name\": \"datagrepper\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501866971\",\n      \"date_modified\": \"1501866971\"\
+        ,\n      \"description\": \"The datanommer rpms\",\n      \"fullname\": \"\
+        rpms/datanommer\",\n      \"id\": 2303,\n      \"milestones\": {},\n     \
+        \ \"name\": \"datanommer\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501866971\",\n   \
+        \   \"date_modified\": \"1501866971\",\n      \"description\": \"The datanommer-commands\
+        \ rpms\",\n      \"fullname\": \"rpms/datanommer-commands\",\n      \"id\"\
+        : 2302,\n      \"milestones\": {},\n      \"name\": \"datanommer-commands\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501867113\",\n   \
+        \   \"date_modified\": \"1501867113\",\n      \"description\": \"The doge\
+        \ rpms\",\n      \"fullname\": \"rpms/doge\",\n      \"id\": 2650,\n     \
+        \ \"milestones\": {},\n      \"name\": \"doge\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"bowlofeggs\"\n        ],\n        \"owner\"\
+        : [\n          \"lmacken\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501867531\",\n      \"date_modified\": \"1501867531\",\n      \"description\"\
+        : \"The fedmsg rpms\",\n      \"fullname\": \"rpms/fedmsg\",\n      \"id\"\
+        : 3634,\n      \"milestones\": {},\n      \"name\": \"fedmsg\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"pingou\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501867531\"\
+        ,\n      \"date_modified\": \"1501867531\",\n      \"description\": \"The\
+        \ fedocal rpms\",\n      \"fullname\": \"rpms/fedocal\",\n      \"id\": 3635,\n\
+        \      \"milestones\": {},\n      \"name\": \"fedocal\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Pierre-YvesChibon\",\n        \"name\": \"pingou\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"orphan\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501867872\",\n   \
+        \   \"date_modified\": \"1501867872\",\n      \"description\": \"The geoip-geolite\
+        \ rpms\",\n      \"fullname\": \"rpms/geoip-geolite\",\n      \"id\": 4300,\n\
+        \      \"milestones\": {},\n      \"name\": \"geoip-geolite\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orphan\",\n        \"name\": \"orphan\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501868076\",\n      \"date_modified\": \"1501868076\"\
+        ,\n      \"description\": \"The gilmsg rpms\",\n      \"fullname\": \"rpms/gilmsg\"\
+        ,\n      \"id\": 4709,\n      \"milestones\": {},\n      \"name\": \"gilmsg\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501868097\",\n   \
+        \   \"date_modified\": \"1501868097\",\n      \"description\": \"The gitflow\
+        \ rpms\",\n      \"fullname\": \"rpms/gitflow\",\n      \"id\": 4763,\n  \
+        \    \"milestones\": {},\n      \"name\": \"gitflow\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501868099\",\n      \"date_modified\": \"1501868099\"\
+        ,\n      \"description\": \"The github2fedmsg rpms\",\n      \"fullname\"\
+        : \"rpms/github2fedmsg\",\n      \"id\": 4765,\n      \"milestones\": {},\n\
+        \      \"name\": \"github2fedmsg\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"abompard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501868897\",\n   \
+        \   \"date_modified\": \"1501868897\",\n      \"description\": \"The grisbi\
+        \ rpms\",\n      \"fullname\": \"rpms/grisbi\",\n      \"id\": 5813,\n   \
+        \   \"milestones\": {},\n      \"name\": \"grisbi\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ignatenkobrain\",\n          \"churchyard\",\n          \"lbalhar\"\
+        ,\n          \"dcantrel\",\n          \"mrunge\",\n          \"cstratak\"\
+        ,\n          \"orion\",\n          \"salimma\"\n        ],\n        \"owner\"\
+        : [\n          \"tomspur\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501869392\",\n      \"date_modified\": \"1501869395\",\n      \"description\"\
+        : \"The ipython rpms\",\n      \"fullname\": \"rpms/ipython\",\n      \"id\"\
+        : 6713,\n      \"milestones\": {},\n      \"name\": \"ipython\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"frafra\",\n          \"slaanesh\"\n        ],\n        \"\
+        owner\": [\n          \"abompard\"\n        ],\n        \"ticket\": []\n \
+        \     },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501869882\",\n      \"date_modified\": \"1501869882\",\n\
+        \      \"description\": \"The keepassx rpms\",\n      \"fullname\": \"rpms/keepassx\"\
+        ,\n      \"id\": 7558,\n      \"milestones\": {},\n      \"name\": \"keepassx\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"kde-sig\"\n       \
+        \ ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"dvratil\"\n        ],\n\
+        \        \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501870090\",\n      \"date_modified\": \"1501870090\"\
+        ,\n      \"description\": \"The ksshaskpass rpms\",\n      \"fullname\": \"\
+        rpms/ksshaskpass\",\n      \"id\": 7907,\n      \"milestones\": {},\n    \
+        \  \"name\": \"ksshaskpass\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501870283\",\n      \"date_modified\": \"1501870283\",\n      \"description\"\
+        : \"The libarcus rpms\",\n      \"fullname\": \"rpms/libarcus\",\n      \"\
+        id\": 8165,\n      \"milestones\": {},\n      \"name\": \"libarcus\",\n  \
+        \    \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n  \
+        \    },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501870571\",\n      \"date_modified\": \"\
+        1501870571\",\n      \"description\": \"The libsass rpms\",\n      \"fullname\"\
+        : \"rpms/libsass\",\n      \"id\": 8837,\n      \"milestones\": {},\n    \
+        \  \"name\": \"libsass\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501870571\",\n      \"date_modified\": \"1501870571\",\n      \"description\"\
+        : \"The libsavitar rpms\",\n      \"fullname\": \"rpms/libsavitar\",\n   \
+        \   \"id\": 8838,\n      \"milestones\": {},\n      \"name\": \"libsavitar\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n   \
+        \       \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501870834\",\n      \"date_modified\": \"1501870834\",\n      \"description\"\
+        : \"The mailman3-fedmsg-plugin rpms\",\n      \"fullname\": \"rpms/mailman3-fedmsg-plugin\"\
+        ,\n      \"id\": 9439,\n      \"milestones\": {},\n      \"name\": \"mailman3-fedmsg-plugin\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"adrian\"\n        ],\n        \"\
+        owner\": [\n          \"puiterwijk\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501871113\",\n      \"date_modified\": \"1501871113\"\
+        ,\n      \"description\": \"The mirrormanager2 rpms\",\n      \"fullname\"\
+        : \"rpms/mirrormanager2\",\n      \"id\": 10234,\n      \"milestones\": {},\n\
+        \      \"name\": \"mirrormanager2\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Patrick \\\"\\u30de\\u30eb\\u30bf\\u30a4\\u30f3\\u30a2\\u30f3\\u30c9\\\
+        u30ec\\u30a2\\u30b9\\\" Uiterwijk\",\n        \"name\": \"puiterwijk\"\n \
+        \     }\n    },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n\
+        \        \"commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [\n          \"ralph\",\n          \"lmacken\"\n        ],\n\
+        \        \"owner\": [\n          \"johnp\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501871141\",\n      \"date_modified\": \"1501871141\"\
+        ,\n      \"description\": \"The moksha rpms\",\n      \"fullname\": \"rpms/moksha\"\
+        ,\n      \"id\": 10362,\n      \"milestones\": {},\n      \"name\": \"moksha\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"johnp\",\n        \"name\": \"\
+        johnp\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"cydrobolt\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501871162\",\n      \"date_modified\": \"1501871162\"\
+        ,\n      \"description\": \"The mote rpms\",\n      \"fullname\": \"rpms/mote\"\
+        ,\n      \"id\": 10432,\n      \"milestones\": {},\n      \"name\": \"mote\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"cydrobolt\",\n        \"name\"\
+        : \"cydrobolt\"\n      }\n    },\n    {\n      \"access_groups\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n       \
+        \ ],\n        \"owner\": [\n          \"tomspur\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873791\",\n      \"date_modified\": \"\
+        1501873791\",\n      \"description\": \"The php-zmq rpms\",\n      \"fullname\"\
+        : \"rpms/php-zmq\",\n      \"id\": 16766,\n      \"milestones\": {},\n   \
+        \   \"name\": \"php-zmq\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"mstuchli\"\n     \
+        \   ],\n        \"owner\": [\n          \"cstratak\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873804\",\n      \"date_modified\": \"\
+        1501873804\",\n      \"description\": \"The pipsi rpms\",\n      \"fullname\"\
+        : \"rpms/pipsi\",\n      \"id\": 16861,\n      \"milestones\": {},\n     \
+        \ \"name\": \"pipsi\",\n      \"namespace\": \"rpms\",\n      \"parent\":\
+        \ null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501873810\",\n      \"date_modified\": \"1501873810\",\n      \"description\"\
+        : \"The pkgwat rpms\",\n      \"fullname\": \"rpms/pkgwat\",\n      \"id\"\
+        : 16877,\n      \"milestones\": {},\n      \"name\": \"pkgwat\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873821\",\n   \
+        \   \"date_modified\": \"1501873821\",\n      \"description\": \"The playitagainsam\
+        \ rpms\",\n      \"fullname\": \"rpms/playitagainsam\",\n      \"id\": 16926,\n\
+        \      \"milestones\": {},\n      \"name\": \"playitagainsam\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"pviktori\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873902\",\n      \"date_modified\": \"1501873902\",\n      \"description\"\
+        : \"The py3c rpms\",\n      \"fullname\": \"rpms/py3c\",\n      \"id\": 17268,\n\
+        \      \"milestones\": {},\n      \"name\": \"py3c\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"pviktori\",\n        \"name\": \"pviktori\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"bochecha\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873911\",\n      \"date_modified\": \"1501873911\"\
+        ,\n      \"description\": \"The pycanberra rpms\",\n      \"fullname\": \"\
+        rpms/pycanberra\",\n      \"id\": 17285,\n      \"milestones\": {},\n    \
+        \  \"name\": \"pycanberra\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bochecha\",\n        \"name\"\
+        : \"bochecha\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"mstuchli\"\n    \
+        \    ],\n        \"owner\": [\n          \"mcyprian\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873931\",\n      \"date_modified\": \"\
+        1501873931\",\n      \"description\": \"The pypy rpms\",\n      \"fullname\"\
+        : \"rpms/pypy\",\n      \"id\": 17377,\n      \"milestones\": {},\n      \"\
+        name\": \"pypy\",\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n\
+        \      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"mcyprian\",\n        \"name\"\
+        : \"mcyprian\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"mstuchli\"\n    \
+        \    ],\n        \"owner\": [\n          \"churchyard\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873931\",\n      \"date_modified\": \"\
+        1501873931\",\n      \"description\": \"The pypy3 rpms\",\n      \"fullname\"\
+        : \"rpms/pypy3\",\n      \"id\": 17378,\n      \"milestones\": {},\n     \
+        \ \"name\": \"pypy3\",\n      \"namespace\": \"rpms\",\n      \"parent\":\
+        \ null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874338\",\n      \"date_modified\": \"1501874338\",\n      \"description\"\
+        : \"The python26 rpms\",\n      \"fullname\": \"rpms/python26\",\n      \"\
+        id\": 19472,\n      \"milestones\": {},\n      \"name\": \"python26\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"lbalhar\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874333\",\n      \"date_modified\": \"1501874333\",\n      \"description\"\
+        : \"The python2-ipython rpms\",\n      \"fullname\": \"rpms/python2-ipython\"\
+        ,\n      \"id\": 19437,\n      \"milestones\": {},\n      \"name\": \"python2-ipython\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lbalhar\",\n        \"name\":\
+        \ \"lbalhar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n     \
+        \     \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874349\",\n      \"date_modified\": \"1501874349\",\n      \"description\"\
+        : \"The python33 rpms\",\n      \"fullname\": \"rpms/python33\",\n      \"\
+        id\": 19536,\n      \"milestones\": {},\n      \"name\": \"python33\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"churchyard\",\n\
+        \          \"torsava\",\n          \"kevin\",\n          \"cstratak\",\n \
+        \         \"mstuchli\",\n          \"ttorling\"\n        ],\n        \"owner\"\
+        : [\n          \"pviktori\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874349\",\n      \"date_modified\": \"1501874349\",\n      \"description\"\
+        : \"The python34 rpms\",\n      \"fullname\": \"rpms/python34\",\n      \"\
+        id\": 19537,\n      \"milestones\": {},\n      \"name\": \"python34\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"pviktori\",\n        \"name\"\
+        : \"pviktori\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"cstratak\"\n    \
+        \    ],\n        \"owner\": [\n          \"churchyard\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874349\",\n      \"date_modified\": \"\
+        1501874349\",\n      \"description\": \"The python35 rpms\",\n      \"fullname\"\
+        : \"rpms/python35\",\n      \"id\": 19538,\n      \"milestones\": {},\n  \
+        \    \"name\": \"python35\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"cstratak\"\n  \
+        \      ],\n        \"owner\": [\n          \"churchyard\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874350\",\n      \"date_modified\": \"\
+        1501874350\",\n      \"description\": \"The python36 rpms\",\n      \"fullname\"\
+        : \"rpms/python36\",\n      \"id\": 19539,\n      \"milestones\": {},\n  \
+        \    \"name\": \"python36\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n      \
+        \  ],\n        \"owner\": [\n          \"johnp\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874339\",\n      \"date_modified\": \"1501874339\"\
+        ,\n      \"description\": \"The python3-cairo rpms\",\n      \"fullname\"\
+        : \"rpms/python3-cairo\",\n      \"id\": 19476,\n      \"milestones\": {},\n\
+        \      \"name\": \"python3-cairo\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"johnp\",\n        \"name\": \"johnp\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"churchyard\"\n        ],\n        \"owner\": [\n          \"torsava\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874340\",\n   \
+        \   \"date_modified\": \"1501874340\",\n      \"description\": \"The python3-cherrypy\
+        \ rpms\",\n      \"fullname\": \"rpms/python3-cherrypy\",\n      \"id\": 19480,\n\
+        \      \"milestones\": {},\n      \"name\": \"python3-cherrypy\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"torsava\",\n        \"name\":\
+        \ \"torsava\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"abompard\",\n          \"ttorling\"\n        ],\n       \
+        \ \"owner\": [\n          \"orion\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874340\",\n      \"date_modified\": \"1501874340\"\
+        ,\n      \"description\": \"The python3-coverage rpms\",\n      \"fullname\"\
+        : \"rpms/python3-coverage\",\n      \"id\": 19482,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python3-coverage\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"bkabrda\",\n          \"mstuchli\",\n          \"rkuska\"\n        ],\n\
+        \        \"owner\": [\n          \"pviktori\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874343\",\n      \"date_modified\": \"1501874343\"\
+        ,\n      \"description\": \"The python3-pkgversion-macros rpms\",\n      \"\
+        fullname\": \"rpms/python3-pkgversion-macros\",\n      \"id\": 19503,\n  \
+        \    \"milestones\": {},\n      \"name\": \"python3-pkgversion-macros\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"pviktori\",\n        \"name\"\
+        : \"pviktori\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"thm\",\n        \
+        \  \"ttorling\"\n        ],\n        \"owner\": [\n          \"orion\"\n \
+        \       ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874344\",\n   \
+        \   \"date_modified\": \"1501874344\",\n      \"description\": \"The python3-py\
+        \ rpms\",\n      \"fullname\": \"rpms/python3-py\",\n      \"id\": 19509,\n\
+        \      \"milestones\": {},\n      \"name\": \"python3-py\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874344\",\n      \"date_modified\": \"1501874344\"\
+        ,\n      \"description\": \"The python3-py3dns rpms\",\n      \"fullname\"\
+        : \"rpms/python3-py3dns\",\n      \"id\": 19510,\n      \"milestones\": {},\n\
+        \      \"name\": \"python3-py3dns\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"pviktori\",\n          \"ttorling\",\n          \"thm\"\n   \
+        \     ],\n        \"owner\": [\n          \"orion\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874345\",\n      \"date_modified\": \"\
+        1501874346\",\n      \"description\": \"The python3-pytest rpms\",\n     \
+        \ \"fullname\": \"rpms/python3-pytest\",\n      \"id\": 19517,\n      \"milestones\"\
+        : {},\n      \"name\": \"python3-pytest\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"pviktori\",\n          \"ttorling\"\n        ],\n        \"owner\":\
+        \ [\n          \"orion\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874346\",\n      \"date_modified\": \"1501874346\",\n      \"description\"\
+        : \"The python3-setuptools rpms\",\n      \"fullname\": \"rpms/python3-setuptools\"\
+        ,\n      \"id\": 19523,\n      \"milestones\": {},\n      \"name\": \"python3-setuptools\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orion\",\n        \"name\": \"\
+        orion\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\":\
+        \ []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874347\",\n      \"date_modified\": \"1501874347\"\
+        ,\n      \"description\": \"The python3-zope-event rpms\",\n      \"fullname\"\
+        : \"rpms/python3-zope-event\",\n      \"id\": 19532,\n      \"milestones\"\
+        : {},\n      \"name\": \"python3-zope-event\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874347\",\n      \"date_modified\": \"1501874347\"\
+        ,\n      \"description\": \"The python3-zope-fixers rpms\",\n      \"fullname\"\
+        : \"rpms/python3-zope-fixers\",\n      \"id\": 19533,\n      \"milestones\"\
+        : {},\n      \"name\": \"python3-zope-fixers\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"abompard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874347\",\n   \
+        \   \"date_modified\": \"1501874347\",\n      \"description\": \"The python3-zope-interface\
+        \ rpms\",\n      \"fullname\": \"rpms/python3-zope-interface\",\n      \"\
+        id\": 19534,\n      \"milestones\": {},\n      \"name\": \"python3-zope-interface\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873954\",\n      \"date_modified\": \"1501873954\",\n      \"description\"\
+        : \"The python-admesh rpms\",\n      \"fullname\": \"rpms/python-admesh\"\
+        ,\n      \"id\": 17501,\n      \"milestones\": {},\n      \"name\": \"python-admesh\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n  \
+        \    },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873956\",\n      \"date_modified\": \"\
+        1501873956\",\n      \"description\": \"The python-aiosmtpd rpms\",\n    \
+        \  \"fullname\": \"rpms/python-aiosmtpd\",\n      \"id\": 17511,\n      \"\
+        milestones\": {},\n      \"name\": \"python-aiosmtpd\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873956\",\n      \"date_modified\": \"1501873956\"\
+        ,\n      \"description\": \"The python-alembic rpms\",\n      \"fullname\"\
+        : \"rpms/python-alembic\",\n      \"id\": 17514,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-alembic\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873960\",\n      \"date_modified\": \"1501873960\"\
+        ,\n      \"description\": \"The python-anykeystore rpms\",\n      \"fullname\"\
+        : \"rpms/python-anykeystore\",\n      \"id\": 17531,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-anykeystore\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873961\",\n      \"date_modified\": \"1501873961\"\
+        ,\n      \"description\": \"The python-appstream rpms\",\n      \"fullname\"\
+        : \"rpms/python-appstream\",\n      \"id\": 17539,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-appstream\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"pingou\"\n        ],\n        \"owner\": [\n          \"ralph\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873963\",\n   \
+        \   \"date_modified\": \"1501873963\",\n      \"description\": \"The python-arrow\
+        \ rpms\",\n      \"fullname\": \"rpms/python-arrow\",\n      \"id\": 17547,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-arrow\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"orphan\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873964\",\n   \
+        \   \"date_modified\": \"1501873964\",\n      \"description\": \"The python-askbot-fedmsg\
+        \ rpms\",\n      \"fullname\": \"rpms/python-askbot-fedmsg\",\n      \"id\"\
+        : 17551,\n      \"milestones\": {},\n      \"name\": \"python-askbot-fedmsg\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orphan\",\n        \"name\": \"\
+        orphan\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\":\
+        \ []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873966\",\n      \"date_modified\": \"1501873966\"\
+        ,\n      \"description\": \"The python-atpublic rpms\",\n      \"fullname\"\
+        : \"rpms/python-atpublic\",\n      \"id\": 17570,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-atpublic\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873970\",\n   \
+        \   \"date_modified\": \"1501873970\",\n      \"description\": \"The python-backlash\
+        \ rpms\",\n      \"fullname\": \"rpms/python-backlash\",\n      \"id\": 17581,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-backlash\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ianweller\"\n     \
+        \   ],\n        \"owner\": [\n          \"ralph\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873971\",\n      \"date_modified\": \"\
+        1501873971\",\n      \"description\": \"The python-backports-lzma rpms\",\n\
+        \      \"fullname\": \"rpms/python-backports-lzma\",\n      \"id\": 17585,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-backports-lzma\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ianweller\"\n        ],\n      \
+        \  \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501873971\",\n      \"date_modified\": \"1501873971\"\
+        ,\n      \"description\": \"The python-backports-ssl_match_hostname rpms\"\
+        ,\n      \"fullname\": \"rpms/python-backports-ssl_match_hostname\",\n   \
+        \   \"id\": 17588,\n      \"milestones\": {},\n      \"name\": \"python-backports-ssl_match_hostname\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873978\",\n      \"date_modified\": \"1501873978\"\
+        ,\n      \"description\": \"The python-blessed rpms\",\n      \"fullname\"\
+        : \"rpms/python-blessed\",\n      \"id\": 17620,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-blessed\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873981\",\n      \"date_modified\": \"1501873981\"\
+        ,\n      \"description\": \"The python-blurb rpms\",\n      \"fullname\":\
+        \ \"rpms/python-blurb\",\n      \"id\": 17630,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-blurb\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"cicku\"\n        ],\n        \"owner\": [\n          \"cstratak\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873981\",\n   \
+        \   \"date_modified\": \"1501873981\",\n      \"description\": \"The python-bna\
+        \ rpms\",\n      \"fullname\": \"rpms/python-bna\",\n      \"id\": 17631,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-bna\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Charalampos Stratakis\",\n        \"name\": \"cstratak\"\n      }\n  \
+        \  },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n       \
+        \ \"commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\":\
+        \ []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873984\",\n      \"date_modified\": \"\
+        1501873984\",\n      \"description\": \"The python-bugzilla2fedmsg rpms\"\
+        ,\n      \"fullname\": \"rpms/python-bugzilla2fedmsg\",\n      \"id\": 17642,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-bugzilla2fedmsg\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"pingou\"\n        ],\n        \"\
+        owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n    \
+        \  },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873992\",\n      \"date_modified\": \"1501873992\",\n      \"description\"\
+        : \"The python-chai rpms\",\n      \"fullname\": \"rpms/python-chai\",\n \
+        \     \"id\": 17678,\n      \"milestones\": {},\n      \"name\": \"python-chai\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\",\n          \"lmacken\"\n\
+        \        ],\n        \"owner\": [\n          \"tdabasin\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873992\",\n      \"date_modified\": \"\
+        1501873993\",\n      \"description\": \"The python-chameleon rpms\",\n   \
+        \   \"fullname\": \"rpms/python-chameleon\",\n      \"id\": 17679,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-chameleon\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"tdabasin\",\n        \"name\": \"tdabasin\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"dcallagh\",\n          \"lmacken\",\n          \"mbacovsk\"\n\
+        \        ],\n        \"owner\": [\n          \"fschwarz\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873994\",\n      \"date_modified\": \"\
+        1501873994\",\n      \"description\": \"The python-cherrypy2 rpms\",\n   \
+        \   \"fullname\": \"rpms/python-cherrypy2\",\n      \"id\": 17684,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-cherrypy2\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"fschwarz\",\n        \"name\": \"fschwarz\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"torsava\"\n        ],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501875664\",\n   \
+        \   \"date_modified\": \"1501875664\",\n      \"description\": \"The python-classroom\
+        \ container\",\n      \"fullname\": \"container/python-classroom\",\n    \
+        \  \"id\": 24026,\n      \"milestones\": {},\n      \"name\": \"python-classroom\"\
+        ,\n      \"namespace\": \"container\",\n      \"parent\": null,\n      \"\
+        priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"mstuchli\",\n \
+        \         \"cstratak\",\n          \"fab\"\n        ],\n        \"owner\"\
+        : [\n          \"rkuska\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873996\",\n      \"date_modified\": \"1501873997\",\n      \"description\"\
+        : \"The python-click rpms\",\n      \"fullname\": \"rpms/python-click\",\n\
+        \      \"id\": 17694,\n      \"milestones\": {},\n      \"name\": \"python-click\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"rkuska\",\n        \"name\": \"\
+        rkuska\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"apevec\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873997\",\n   \
+        \   \"date_modified\": \"1501873997\",\n      \"description\": \"The python-cliff\
+        \ rpms\",\n      \"fullname\": \"rpms/python-cliff\",\n      \"id\": 17697,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-cliff\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"apevec\",\n        \"name\": \"apevec\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873997\",\n      \"date_modified\": \"1501873997\"\
+        ,\n      \"description\": \"The python-cligj rpms\",\n      \"fullname\":\
+        \ \"rpms/python-cligj\",\n      \"id\": 17698,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-cligj\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873997\",\n      \"date_modified\": \"1501873998\"\
+        ,\n      \"description\": \"The python-cloud-sptheme rpms\",\n      \"fullname\"\
+        : \"rpms/python-cloud-sptheme\",\n      \"id\": 17700,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-cloud-sptheme\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"apevec\"\n        ],\n        \"owner\"\
+        : [\n          \"mmagr\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873999\",\n      \"date_modified\": \"1501873999\",\n      \"description\"\
+        : \"The python-cmd2 rpms\",\n      \"fullname\": \"rpms/python-cmd2\",\n \
+        \     \"id\": 17707,\n      \"milestones\": {},\n      \"name\": \"python-cmd2\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"mmagr\",\n        \"name\": \"\
+        mmagr\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\",\n          \"lmacken\"\n\
+        \        ],\n        \"owner\": [\n          \"ignatenkobrain\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873999\",\n      \"date_modified\": \"\
+        1501873999\",\n      \"description\": \"The python-colander rpms\",\n    \
+        \  \"fullname\": \"rpms/python-colander\",\n      \"id\": 17711,\n      \"\
+        milestones\": {},\n      \"name\": \"python-colander\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Igor Gnatenko\",\n        \"name\": \"ignatenkobrain\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"pingou\",\n       \
+        \   \"tjikkun\",\n          \"abompard\"\n        ],\n        \"owner\": [\n\
+        \          \"ralph\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874003\",\n      \"date_modified\": \"1501874003\",\n      \"description\"\
+        : \"The python-contextlib2 rpms\",\n      \"fullname\": \"rpms/python-contextlib2\"\
+        ,\n      \"id\": 17729,\n      \"milestones\": {},\n      \"name\": \"python-contextlib2\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\",\n          \"\
+        python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"access_users\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"bowlofeggs\"\
+        ,\n          \"lmacken\"\n        ],\n        \"owner\": [\n          \"hguemar\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874004\",\n   \
+        \   \"date_modified\": \"1501874005\",\n      \"description\": \"The python-cornice\
+        \ rpms\",\n      \"fullname\": \"rpms/python-cornice\",\n      \"id\": 17733,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-cornice\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"hguemar\",\n        \"name\":\
+        \ \"hguemar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"abompard\"\n        ],\n        \"owner\": [\n          \"\
+        bkabrda\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874006\"\
+        ,\n      \"date_modified\": \"1501874006\",\n      \"description\": \"The\
+        \ python-cov-core rpms\",\n      \"fullname\": \"rpms/python-cov-core\",\n\
+        \      \"id\": 17737,\n      \"milestones\": {},\n      \"name\": \"python-cov-core\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bkabrda\",\n        \"name\":\
+        \ \"bkabrda\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"mrunge\",\n          \"abompard\",\n          \"lmacken\"\
+        \n        ],\n        \"owner\": [\n          \"spot\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874006\",\n      \"date_modified\": \"\
+        1501874006\",\n      \"description\": \"The python-coverage rpms\",\n    \
+        \  \"fullname\": \"rpms/python-coverage\",\n      \"id\": 17739,\n      \"\
+        milestones\": {},\n      \"name\": \"python-coverage\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"spot\",\n        \"name\": \"spot\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874006\",\n      \"date_modified\": \"1501874006\"\
+        ,\n      \"description\": \"The python-coverage_pth rpms\",\n      \"fullname\"\
+        : \"rpms/python-coverage_pth\",\n      \"id\": 17740,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-coverage_pth\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874009\",\n   \
+        \   \"date_modified\": \"1501874009\",\n      \"description\": \"The python-crank\
+        \ rpms\",\n      \"fullname\": \"rpms/python-crank\",\n      \"id\": 17748,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-crank\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"kevin\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874009\",\n      \"date_modified\": \"1501874009\"\
+        ,\n      \"description\": \"The python-crypto2.6 rpms\",\n      \"fullname\"\
+        : \"rpms/python-crypto2.6\",\n      \"id\": 17753,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-crypto2.6\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Kevin Fenzi\",\n        \"name\": \"kevin\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"brouhaha\",\n          \"kevin\",\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"echevemaster\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874011\",\n      \"date_modified\": \"\
+        1501874012\",\n      \"description\": \"The python-cssselect rpms\",\n   \
+        \   \"fullname\": \"rpms/python-cssselect\",\n      \"id\": 17758,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-cssselect\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"echevemaster\",\n        \"name\": \"echevemaster\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"lmacken\",\n          \"tomspur\"\n   \
+        \     ],\n        \"owner\": [\n          \"kushal\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874014\",\n      \"date_modified\": \"\
+        1501874014\",\n      \"description\": \"The python-daemon rpms\",\n      \"\
+        fullname\": \"rpms/python-daemon\",\n      \"id\": 17777,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-daemon\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"kushal\",\n        \"name\": \"kushal\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874014\",\n      \"date_modified\": \"1501874014\"\
+        ,\n      \"description\": \"The python-datanommer-consumer rpms\",\n     \
+        \ \"fullname\": \"rpms/python-datanommer-consumer\",\n      \"id\": 17781,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-datanommer-consumer\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874015\",\n   \
+        \   \"date_modified\": \"1501874015\",\n      \"description\": \"The python-datanommer-models\
+        \ rpms\",\n      \"fullname\": \"rpms/python-datanommer-models\",\n      \"\
+        id\": 17782,\n      \"milestones\": {},\n      \"name\": \"python-datanommer-models\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"limb\",\n          \"tomspur\",\n\
+        \          \"pjp\",\n          \"jspaleta\"\n        ],\n        \"owner\"\
+        : [\n          \"hguemar\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874015\",\n      \"date_modified\": \"1501874015\",\n      \"description\"\
+        : \"The python-dateutil rpms\",\n      \"fullname\": \"rpms/python-dateutil\"\
+        ,\n      \"id\": 17783,\n      \"milestones\": {},\n      \"name\": \"python-dateutil\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"hguemar\",\n        \"name\":\
+        \ \"hguemar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"ignatenkobrain\",\n          \"abompard\"\n        ],\n \
+        \       \"owner\": [\n          \"carlwgeorge\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874016\",\n      \"date_modified\": \"1501874016\"\
+        ,\n      \"description\": \"The python-ddt rpms\",\n      \"fullname\": \"\
+        rpms/python-ddt\",\n      \"id\": 17789,\n      \"milestones\": {},\n    \
+        \  \"name\": \"python-ddt\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Carl George\",\n        \"name\"\
+        : \"carlwgeorge\"\n      }\n    },\n    {\n      \"access_groups\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"fale\"\n      \
+        \  ],\n        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874017\",\n      \"date_modified\": \"1501874017\"\
+        ,\n      \"description\": \"The python-decorator rpms\",\n      \"fullname\"\
+        : \"rpms/python-decorator\",\n      \"id\": 17794,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-decorator\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"bkabrda\"\n        ],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874017\",\n   \
+        \   \"date_modified\": \"1501874018\",\n      \"description\": \"The python-defusedxml\
+        \ rpms\",\n      \"fullname\": \"rpms/python-defusedxml\",\n      \"id\":\
+        \ 17798,\n      \"milestones\": {},\n      \"name\": \"python-defusedxml\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"mstuchli\"\n  \
+        \      ],\n        \"owner\": [\n          \"cstratak\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874023\",\n      \"date_modified\": \"\
+        1501874024\",\n      \"description\": \"The python-distlib rpms\",\n     \
+        \ \"fullname\": \"rpms/python-distlib\",\n      \"id\": 17813,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-distlib\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Charalampos Stratakis\",\n        \"name\": \"cstratak\"\n      }\n  \
+        \  },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n       \
+        \ \"commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\":\
+        \ []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [\n          \"ralph\"\n        ],\n        \"owner\": [\n\
+        \          \"orphan\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874029\",\n      \"date_modified\": \"1501874029\",\n      \"description\"\
+        : \"The python-django-longerusername rpms\",\n      \"fullname\": \"rpms/python-django-longerusername\"\
+        ,\n      \"id\": 17860,\n      \"milestones\": {},\n      \"name\": \"python-django-longerusername\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orphan\",\n        \"name\": \"\
+        orphan\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mrunge\",\n          \"yuwang\"\n\
+        \        ],\n        \"owner\": [\n          \"ralph\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874039\",\n      \"date_modified\": \"\
+        1501874039\",\n      \"description\": \"The python-django-tinymce rpms\",\n\
+        \      \"fullname\": \"rpms/python-django-tinymce\",\n      \"id\": 17910,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-django-tinymce\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"oddshocks\"\n        ],\n      \
+        \  \"owner\": [\n          \"mstuchli\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874045\",\n      \"date_modified\": \"1501874045\"\
+        ,\n      \"description\": \"The python-docutils rpms\",\n      \"fullname\"\
+        : \"rpms/python-docutils\",\n      \"id\": 17930,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-docutils\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"mstuchli\",\n        \"name\": \"mstuchli\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"bowlofeggs\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874046\",\n   \
+        \   \"date_modified\": \"1501874046\",\n      \"description\": \"The python-dogpile-cache\
+        \ rpms\",\n      \"fullname\": \"rpms/python-dogpile-cache\",\n      \"id\"\
+        : 17932,\n      \"milestones\": {},\n      \"name\": \"python-dogpile-cache\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bowlofeggs\",\n        \"name\"\
+        : \"bowlofeggs\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n      \
+        \  ],\n        \"owner\": [\n          \"bowlofeggs\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874046\",\n      \"date_modified\": \"\
+        1501874046\",\n      \"description\": \"The python-dogpile-core rpms\",\n\
+        \      \"fullname\": \"rpms/python-dogpile-core\",\n      \"id\": 17933,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-dogpile-core\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bowlofeggs\",\n        \"name\"\
+        : \"bowlofeggs\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874046\",\n      \"date_modified\": \"1501874047\",\n      \"description\"\
+        : \"The python-dropbox rpms\",\n      \"fullname\": \"rpms/python-dropbox\"\
+        ,\n      \"id\": 17941,\n      \"milestones\": {},\n      \"name\": \"python-dropbox\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"apevec\",\n    \
+        \      \"social\"\n        ],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874047\",\n   \
+        \   \"date_modified\": \"1501874048\",\n      \"description\": \"The python-editor\
+        \ rpms\",\n      \"fullname\": \"rpms/python-editor\",\n      \"id\": 17950,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-editor\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"galt\",\n          \"cstratak\",\n          \"dsommers\"\n  \
+        \      ],\n        \"owner\": [\n          \"acme\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874051\",\n      \"date_modified\": \"\
+        1501874051\",\n      \"description\": \"The python-ethtool rpms\",\n     \
+        \ \"fullname\": \"rpms/python-ethtool\",\n      \"id\": 17971,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-ethtool\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"acme\",\n        \"name\": \"acme\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n    \
+        \    \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"abompard\",\n          \"carlwgeorge\"\
+        \n        ],\n        \"owner\": [\n          \"jamielennox\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874053\",\n      \"date_modified\": \"\
+        1501874053\",\n      \"description\": \"The python-falcon rpms\",\n      \"\
+        fullname\": \"rpms/python-falcon\",\n      \"id\": 17984,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-falcon\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"jamielennox\",\n        \"name\": \"jamielennox\"\n      }\n    },\n \
+        \   {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874055\",\n      \"date_modified\": \"1501874055\"\
+        ,\n      \"description\": \"The python-fedbadges rpms\",\n      \"fullname\"\
+        : \"rpms/python-fedbadges\",\n      \"id\": 17990,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-fedbadges\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"kevin\",\n          \"oddshocks\",\n          \"ralph\"\n   \
+        \     ],\n        \"owner\": [\n          \"sayanchowdhury\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874055\",\n      \"date_modified\": \"\
+        1501874055\",\n      \"description\": \"The python-fedimg rpms\",\n      \"\
+        fullname\": \"rpms/python-fedimg\",\n      \"id\": 17991,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-fedimg\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sayanchowdhury\",\n        \"name\": \"sayanchowdhury\"\n      }\n   \
+        \ },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"\
+        commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"bowlofeggs\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874055\",\n      \"date_modified\": \"\
+        1501874055\",\n      \"description\": \"The python-fedmsg-atomic-composer\
+        \ rpms\",\n      \"fullname\": \"rpms/python-fedmsg-atomic-composer\",\n \
+        \     \"id\": 17992,\n      \"milestones\": {},\n      \"name\": \"python-fedmsg-atomic-composer\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bowlofeggs\",\n        \"name\"\
+        : \"bowlofeggs\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n   \
+        \       \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874055\",\n      \"date_modified\": \"1501874055\",\n      \"description\"\
+        : \"The python-fedmsg-genacls rpms\",\n      \"fullname\": \"rpms/python-fedmsg-genacls\"\
+        ,\n      \"id\": 17993,\n      \"milestones\": {},\n      \"name\": \"python-fedmsg-genacls\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ianweller\"\n        ],\n      \
+        \  \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874055\",\n      \"date_modified\": \"1501874055\"\
+        ,\n      \"description\": \"The python-fedmsg-meta-debian rpms\",\n      \"\
+        fullname\": \"rpms/python-fedmsg-meta-debian\",\n      \"id\": 17994,\n  \
+        \    \"milestones\": {},\n      \"name\": \"python-fedmsg-meta-debian\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"sayanchowdhury\",\n          \"\
+        ianweller\",\n          \"lmacken\"\n        ],\n        \"owner\": [\n  \
+        \        \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874055\",\n      \"date_modified\": \"1501874056\",\n      \"description\"\
+        : \"The python-fedmsg-meta-fedora-infrastructure rpms\",\n      \"fullname\"\
+        : \"rpms/python-fedmsg-meta-fedora-infrastructure\",\n      \"id\": 17995,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-fedmsg-meta-fedora-infrastructure\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"codeblock\",\n          \"ricky\"\
+        ,\n          \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"\
+        lmacken\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874056\"\
+        ,\n      \"date_modified\": \"1501874056\",\n      \"description\": \"The\
+        \ python-fedora rpms\",\n      \"fullname\": \"rpms/python-fedora\",\n   \
+        \   \"id\": 17997,\n      \"milestones\": {},\n      \"name\": \"python-fedora\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"mstuchli\",\n     \
+        \     \"pingou\",\n          \"pviktori\"\n        ],\n        \"owner\":\
+        \ [\n          \"puiterwijk\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874058\",\n      \"date_modified\": \"1501874059\",\n      \"description\"\
+        : \"The python-flask-admin rpms\",\n      \"fullname\": \"rpms/python-flask-admin\"\
+        ,\n      \"id\": 18009,\n      \"milestones\": {},\n      \"name\": \"python-flask-admin\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Patrick \\\"\\u30de\\u30eb\\u30bf\\\
+        u30a4\\u30f3\\u30a2\\u30f3\\u30c9\\u30ec\\u30a2\\u30b9\\\" Uiterwijk\",\n\
+        \        \"name\": \"puiterwijk\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874060\",\n      \"date_modified\": \"1501874060\",\n      \"description\"\
+        : \"The python-flask-mako rpms\",\n      \"fullname\": \"rpms/python-flask-mako\"\
+        ,\n      \"id\": 18021,\n      \"milestones\": {},\n      \"name\": \"python-flask-mako\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874066\",\n      \"date_modified\": \"1501874066\"\
+        ,\n      \"description\": \"The python-flufl-bounce rpms\",\n      \"fullname\"\
+        : \"rpms/python-flufl-bounce\",\n      \"id\": 18048,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-flufl-bounce\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"abompard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874067\",\n   \
+        \   \"date_modified\": \"1501874067\",\n      \"description\": \"The python-flufl-i18n\
+        \ rpms\",\n      \"fullname\": \"rpms/python-flufl-i18n\",\n      \"id\":\
+        \ 18049,\n      \"milestones\": {},\n      \"name\": \"python-flufl-i18n\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n    \
+        \  },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874067\",\n      \"date_modified\": \"\
+        1501874067\",\n      \"description\": \"The python-flufl-lock rpms\",\n  \
+        \    \"fullname\": \"rpms/python-flufl-lock\",\n      \"id\": 18050,\n   \
+        \   \"milestones\": {},\n      \"name\": \"python-flufl-lock\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n    \
+        \  },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874067\",\n      \"date_modified\": \"\
+        1501874067\",\n      \"description\": \"The python-flufl-testing rpms\",\n\
+        \      \"fullname\": \"rpms/python-flufl-testing\",\n      \"id\": 18051,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-flufl-testing\",\n  \
+        \    \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"sayanchowdhury\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874068\",\n      \"date_modified\": \"\
+        1501874068\",\n      \"description\": \"The python-fmn-consumer rpms\",\n\
+        \      \"fullname\": \"rpms/python-fmn-consumer\",\n      \"id\": 18054,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-fmn-consumer\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"sayanchowdhury\",\n        \"\
+        name\": \"sayanchowdhury\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"sayanchowdhury\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874068\",\n      \"date_modified\": \"\
+        1501874068\",\n      \"description\": \"The python-fmn-lib rpms\",\n     \
+        \ \"fullname\": \"rpms/python-fmn-lib\",\n      \"id\": 18055,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-fmn-lib\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sayanchowdhury\",\n        \"name\": \"sayanchowdhury\"\n      }\n   \
+        \ },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"\
+        commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"ralph\"\n        ],\n        \"owner\": [\n          \"sayanchowdhury\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874068\",\n   \
+        \   \"date_modified\": \"1501874068\",\n      \"description\": \"The python-fmn-rules\
+        \ rpms\",\n      \"fullname\": \"rpms/python-fmn-rules\",\n      \"id\": 18056,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-fmn-rules\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"sayanchowdhury\",\n        \"\
+        name\": \"sayanchowdhury\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"sayanchowdhury\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874069\",\n      \"date_modified\": \"\
+        1501874069\",\n      \"description\": \"The python-fmn-web rpms\",\n     \
+        \ \"fullname\": \"rpms/python-fmn-web\",\n      \"id\": 18058,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-fmn-web\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sayanchowdhury\",\n        \"name\": \"sayanchowdhury\"\n      }\n   \
+        \ },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"\
+        commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"ralph\",\n          \"lmacken\"\n        ],\n        \"owner\"\
+        : [\n          \"kylev\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874070\",\n      \"date_modified\": \"1501874070\",\n      \"description\"\
+        : \"The python-formencode rpms\",\n      \"fullname\": \"rpms/python-formencode\"\
+        ,\n      \"id\": 18065,\n      \"milestones\": {},\n      \"name\": \"python-formencode\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"kylev\",\n        \"name\": \"\
+        kylev\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874071\",\n   \
+        \   \"date_modified\": \"1501874071\",\n      \"description\": \"The python-freezegun\
+        \ rpms\",\n      \"fullname\": \"rpms/python-freezegun\",\n      \"id\": 18071,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-freezegun\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874074\",\n      \"date_modified\": \"1501874074\",\n\
+        \      \"description\": \"The python-gearbox rpms\",\n      \"fullname\":\
+        \ \"rpms/python-gearbox\",\n      \"id\": 18096,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-gearbox\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"pingou\"\n        ],\n        \"owner\"\
+        : [\n          \"sergiomb\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873940\",\n      \"date_modified\": \"1501873940\",\n      \"description\"\
+        : \"The python-GeoIP rpms\",\n      \"fullname\": \"rpms/python-GeoIP\",\n\
+        \      \"id\": 17421,\n      \"milestones\": {},\n      \"name\": \"python-GeoIP\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"S\\u00e9rgio Monteiro Basto\"\
+        ,\n        \"name\": \"sergiomb\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"orion\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874077\",\n      \"date_modified\": \"1501874077\",\n      \"description\"\
+        : \"The python-gflags rpms\",\n      \"fullname\": \"rpms/python-gflags\"\
+        ,\n      \"id\": 18115,\n      \"milestones\": {},\n      \"name\": \"python-gflags\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orion\",\n        \"name\": \"\
+        orion\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"jspaleta\",\n          \"dchen\",\n          \"abompard\",\n       \
+        \   \"kevin\"\n        ],\n        \"owner\": [\n          \"awjb\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n \
+        \     \"custom_keys\": [],\n      \"date_created\": \"1501874090\",\n    \
+        \  \"date_modified\": \"1501874090\",\n      \"description\": \"The python-httplib2\
+        \ rpms\",\n      \"fullname\": \"rpms/python-httplib2\",\n      \"id\": 18174,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-httplib2\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"awjb\",\n        \"name\": \"\
+        awjb\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"bkabrda\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874088\",\n      \"date_modified\": \"1501874088\",\n\
+        \      \"description\": \"The python-http-parser rpms\",\n      \"fullname\"\
+        : \"rpms/python-http-parser\",\n      \"id\": 18172,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-http-parser\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"bkabrda\",\n        \"name\": \"bkabrda\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"kevin\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874091\",\n      \"date_modified\": \"1501874091\"\
+        ,\n      \"description\": \"The python-hupper rpms\",\n      \"fullname\"\
+        : \"rpms/python-hupper\",\n      \"id\": 18180,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-hupper\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Kevin Fenzi\",\n        \"name\": \"kevin\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"cstratak\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874094\",\n      \"date_modified\": \"1501874094\"\
+        ,\n      \"description\": \"The python-inifile rpms\",\n      \"fullname\"\
+        : \"rpms/python-inifile\",\n      \"id\": 18201,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-inifile\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Charalampos Stratakis\",\n        \"name\": \"cstratak\"\n      }\n  \
+        \  },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n       \
+        \ \"commit\": [\n          \"python-sig\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [\n          \"lupinix\"\n        ],\n        \"owner\": [\n\
+        \          \"ignatenkobrain\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874094\",\n      \"date_modified\": \"1501874094\",\n      \"description\"\
+        : \"The python-iniparse rpms\",\n      \"fullname\": \"rpms/python-iniparse\"\
+        ,\n      \"id\": 18202,\n      \"milestones\": {},\n      \"name\": \"python-iniparse\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Igor Gnatenko\",\n        \"name\"\
+        : \"ignatenkobrain\"\n      }\n    },\n    {\n      \"access_groups\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"churchyard\"\n\
+        \        ],\n        \"owner\": [\n          \"pcpa\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874097\",\n      \"date_modified\": \"\
+        1501874097\",\n      \"description\": \"The python-ipykernel rpms\",\n   \
+        \   \"fullname\": \"rpms/python-ipykernel\",\n      \"id\": 18216,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-ipykernel\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"pcpa\",\n        \"name\": \"pcpa\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"churchyard\"\n        ],\n        \"owner\": [\n          \"tomspur\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874104\",\n   \
+        \   \"date_modified\": \"1501874104\",\n      \"description\": \"The python-jupyter-client\
+        \ rpms\",\n      \"fullname\": \"rpms/python-jupyter-client\",\n      \"id\"\
+        : 18262,\n      \"milestones\": {},\n      \"name\": \"python-jupyter-client\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"orion\",\n       \
+        \   \"churchyard\"\n        ],\n        \"owner\": [\n          \"tomspur\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874104\",\n   \
+        \   \"date_modified\": \"1501874105\",\n      \"description\": \"The python-jupyter-core\
+        \ rpms\",\n      \"fullname\": \"rpms/python-jupyter-core\",\n      \"id\"\
+        : 18263,\n      \"milestones\": {},\n      \"name\": \"python-jupyter-core\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874105\"\
+        ,\n      \"date_modified\": \"1501874105\",\n      \"description\": \"The\
+        \ python-jwt rpms\",\n      \"fullname\": \"rpms/python-jwt\",\n      \"id\"\
+        : 18268,\n      \"milestones\": {},\n      \"name\": \"python-jwt\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874106\",\n   \
+        \   \"date_modified\": \"1501874106\",\n      \"description\": \"The python-kajiki\
+        \ rpms\",\n      \"fullname\": \"rpms/python-kajiki\",\n      \"id\": 18275,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-kajiki\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"pingou\"\n        ],\n        \"owner\": [\n          \"ralph\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874110\",\n   \
+        \   \"date_modified\": \"1501874111\",\n      \"description\": \"The python-kitchen\
+        \ rpms\",\n      \"fullname\": \"rpms/python-kitchen\",\n      \"id\": 18289,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-kitchen\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874112\",\n      \"date_modified\": \"1501874112\"\
+        ,\n      \"description\": \"The python-lazr-config rpms\",\n      \"fullname\"\
+        : \"rpms/python-lazr-config\",\n      \"id\": 18302,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-lazr-config\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"abompard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874112\",\n   \
+        \   \"date_modified\": \"1501874112\",\n      \"description\": \"The python-lazr-delegates\
+        \ rpms\",\n      \"fullname\": \"rpms/python-lazr-delegates\",\n      \"id\"\
+        : 18303,\n      \"milestones\": {},\n      \"name\": \"python-lazr-delegates\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n    \
+        \  },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874112\",\n      \"date_modified\": \"\
+        1501874112\",\n      \"description\": \"The python-lazr-smtptest rpms\",\n\
+        \      \"fullname\": \"rpms/python-lazr-smtptest\",\n      \"id\": 18304,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-lazr-smtptest\",\n  \
+        \    \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"cstratak\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501873941\",\n      \"date_modified\": \"1501873941\",\n      \"description\"\
+        : \"The python-Lektor rpms\",\n      \"fullname\": \"rpms/python-Lektor\"\
+        ,\n      \"id\": 17427,\n      \"milestones\": {},\n      \"name\": \"python-Lektor\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874123\",\n      \"date_modified\": \"1501874123\",\n      \"description\"\
+        : \"The python-logutils rpms\",\n      \"fullname\": \"rpms/python-logutils\"\
+        ,\n      \"id\": 18354,\n      \"milestones\": {},\n      \"name\": \"python-logutils\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874124\",\n   \
+        \   \"date_modified\": \"1501874124\",\n      \"description\": \"The python-m2ext\
+        \ rpms\",\n      \"fullname\": \"rpms/python-m2ext\",\n      \"id\": 18362,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-m2ext\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mcepl\",\n          \"lmacken\"\
+        ,\n          \"bowlofeggs\",\n          \"abompard\"\n        ],\n       \
+        \ \"owner\": [\n          \"kylev\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874125\",\n      \"date_modified\": \"1501874126\"\
+        ,\n      \"description\": \"The python-mako rpms\",\n      \"fullname\": \"\
+        rpms/python-mako\",\n      \"id\": 18366,\n      \"milestones\": {},\n   \
+        \   \"name\": \"python-mako\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"kylev\",\n        \"name\": \"\
+        kylev\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"lmacken\",\n          \"oddshocks\"\
+        ,\n          \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"\
+        orphan\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874126\"\
+        ,\n      \"date_modified\": \"1501874126\",\n      \"description\": \"The\
+        \ python-mako0.4 rpms\",\n      \"fullname\": \"rpms/python-mako0.4\",\n \
+        \     \"id\": 18367,\n      \"milestones\": {},\n      \"name\": \"python-mako0.4\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orphan\",\n        \"name\": \"\
+        orphan\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"jjames\"\n        ],\n        \"\
+        owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n    \
+        \  },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874127\",\n      \"date_modified\": \"1501874127\",\n      \"description\"\
+        : \"The python-manuel rpms\",\n      \"fullname\": \"rpms/python-manuel\"\
+        ,\n      \"id\": 18371,\n      \"milestones\": {},\n      \"name\": \"python-manuel\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"jspaleta\",\n          \"pcpa\"\
+        ,\n          \"jgu\",\n          \"limb\",\n          \"rathann\",\n     \
+        \     \"cstratak\"\n        ],\n        \"owner\": [\n          \"tomspur\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874129\",\n   \
+        \   \"date_modified\": \"1501874129\",\n      \"description\": \"The python-matplotlib\
+        \ rpms\",\n      \"fullname\": \"rpms/python-matplotlib\",\n      \"id\":\
+        \ 18384,\n      \"milestones\": {},\n      \"name\": \"python-matplotlib\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n     \
+        \     \"tomspur\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874131\",\n      \"date_modified\": \"1501874131\",\n      \"description\"\
+        : \"The python-mglob rpms\",\n      \"fullname\": \"rpms/python-mglob\",\n\
+        \      \"id\": 18399,\n      \"milestones\": {},\n      \"name\": \"python-mglob\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"carlwgeorge\",\n          \"abompard\",\n          \"stevetraylen\"\
+        \n        ],\n        \"owner\": [\n          \"jkaluza\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874132\",\n      \"date_modified\": \"\
+        1501874132\",\n      \"description\": \"The python-mimeparse rpms\",\n   \
+        \   \"fullname\": \"rpms/python-mimeparse\",\n      \"id\": 18403,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-mimeparse\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"jkaluza\",\n        \"name\": \"jkaluza\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"tomspur\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874133\",\n   \
+        \   \"date_modified\": \"1501874133\",\n      \"description\": \"The python-minimock\
+        \ rpms\",\n      \"fullname\": \"rpms/python-minimock\",\n      \"id\": 18408,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-minimock\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"lmacken\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874133\"\
+        ,\n      \"date_modified\": \"1501874133\",\n      \"description\": \"The\
+        \ python-modernize rpms\",\n      \"fullname\": \"rpms/python-modernize\"\
+        ,\n      \"id\": 18417,\n      \"milestones\": {},\n      \"name\": \"python-modernize\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\",\n        \
+        \  \"lmacken\"\n        ],\n        \"owner\": [\n          \"lbalhar\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874134\",\n   \
+        \   \"date_modified\": \"1501874134\",\n      \"description\": \"The python-moksha-common\
+        \ rpms\",\n      \"fullname\": \"rpms/python-moksha-common\",\n      \"id\"\
+        : 18420,\n      \"milestones\": {},\n      \"name\": \"python-moksha-common\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lbalhar\",\n        \"name\":\
+        \ \"lbalhar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\",\n        \
+        \  \"lmacken\"\n        ],\n        \"owner\": [\n          \"lbalhar\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874134\",\n   \
+        \   \"date_modified\": \"1501874134\",\n      \"description\": \"The python-moksha-hub\
+        \ rpms\",\n      \"fullname\": \"rpms/python-moksha-hub\",\n      \"id\":\
+        \ 18421,\n      \"milestones\": {},\n      \"name\": \"python-moksha-hub\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lbalhar\",\n        \"name\":\
+        \ \"lbalhar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874134\",\n      \"date_modified\": \"1501874135\"\
+        ,\n      \"description\": \"The python-moksha-wsgi rpms\",\n      \"fullname\"\
+        : \"rpms/python-moksha-wsgi\",\n      \"id\": 18422,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-moksha-wsgi\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"bkabrda\",\n          \"sergiomb\"\n        ],\n        \"owner\"\
+        : [\n          \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873941\",\n      \"date_modified\": \"1501873941\",\n      \"description\"\
+        : \"The python-MultipartPostHandler2 rpms\",\n      \"fullname\": \"rpms/python-MultipartPostHandler2\"\
+        ,\n      \"id\": 17431,\n      \"milestones\": {},\n      \"name\": \"python-MultipartPostHandler2\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n   \
+        \       \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874138\",\n      \"date_modified\": \"1501874138\",\n      \"description\"\
+        : \"The python-munch rpms\",\n      \"fullname\": \"rpms/python-munch\",\n\
+        \      \"id\": 18443,\n      \"milestones\": {},\n      \"name\": \"python-munch\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"nonamedotc\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874142\",\n   \
+        \   \"date_modified\": \"1501874142\",\n      \"description\": \"The python-nbconvert\
+        \ rpms\",\n      \"fullname\": \"rpms/python-nbconvert\",\n      \"id\": 18465,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-nbconvert\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Mukundan Ragavan\",\n        \"\
+        name\": \"nonamedotc\"\n      }\n    },\n    {\n      \"access_groups\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"tomspur\"\n  \
+        \      ],\n        \"owner\": [\n          \"orion\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874142\",\n      \"date_modified\": \"\
+        1501874142\",\n      \"description\": \"The python-nbformat rpms\",\n    \
+        \  \"fullname\": \"rpms/python-nbformat\",\n      \"id\": 18466,\n      \"\
+        milestones\": {},\n      \"name\": \"python-nbformat\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874143\",\n      \"date_modified\": \"1501874143\"\
+        ,\n      \"description\": \"The python-nbsphinx rpms\",\n      \"fullname\"\
+        : \"rpms/python-nbsphinx\",\n      \"id\": 18467,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-nbsphinx\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"itamarjp\",\n          \"noodles\"\n        ],\n        \"owner\"\
+        : [\n          \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874143\",\n      \"date_modified\": \"1501874143\",\n      \"description\"\
+        : \"The python-ndg_httpsclient rpms\",\n      \"fullname\": \"rpms/python-ndg_httpsclient\"\
+        ,\n      \"id\": 18470,\n      \"milestones\": {},\n      \"name\": \"python-ndg_httpsclient\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"bowlofeggs\"\n \
+        \       ],\n        \"owner\": [\n          \"lmacken\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874149\",\n      \"date_modified\": \"\
+        1501874149\",\n      \"description\": \"The python-nose rpms\",\n      \"\
+        fullname\": \"rpms/python-nose\",\n      \"id\": 18505,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-nose\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"\
+        lmacken\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874149\"\
+        ,\n      \"date_modified\": \"1501874150\",\n      \"description\": \"The\
+        \ python-nose1.1 rpms\",\n      \"fullname\": \"rpms/python-nose1.1\",\n \
+        \     \"id\": 18506,\n      \"milestones\": {},\n      \"name\": \"python-nose1.1\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874150\",\n      \"date_modified\": \"\
+        1501874150\",\n      \"description\": \"The python-nose2 rpms\",\n      \"\
+        fullname\": \"rpms/python-nose2\",\n      \"id\": 18507,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-nose2\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874150\",\n      \"date_modified\": \"1501874150\"\
+        ,\n      \"description\": \"The python-nose_warnings_filters rpms\",\n   \
+        \   \"fullname\": \"rpms/python-nose_warnings_filters\",\n      \"id\": 18509,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-nose_warnings_filters\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874150\",\n      \"date_modified\": \"1501874150\",\n      \"description\"\
+        : \"The python-notebook rpms\",\n      \"fullname\": \"rpms/python-notebook\"\
+        ,\n      \"id\": 18511,\n      \"milestones\": {},\n      \"name\": \"python-notebook\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"tomspur\"\n   \
+        \     ],\n        \"owner\": [\n          \"orion\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874154\",\n      \"date_modified\": \"\
+        1501874154\",\n      \"description\": \"The python-numpydoc rpms\",\n    \
+        \  \"fullname\": \"rpms/python-numpydoc\",\n      \"id\": 18526,\n      \"\
+        milestones\": {},\n      \"name\": \"python-numpydoc\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874154\",\n      \"date_modified\": \"1501874154\"\
+        ,\n      \"description\": \"The python-numpy-stl rpms\",\n      \"fullname\"\
+        : \"rpms/python-numpy-stl\",\n      \"id\": 18525,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-numpy-stl\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"jdennis\",\n          \"jdornak\",\n          \"ralph\"\n   \
+        \     ],\n        \"owner\": [\n          \"puiterwijk\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874155\",\n      \"date_modified\": \"\
+        1501874157\",\n      \"description\": \"The python-oauthlib rpms\",\n    \
+        \  \"fullname\": \"rpms/python-oauthlib\",\n      \"id\": 18532,\n      \"\
+        milestones\": {},\n      \"name\": \"python-oauthlib\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Patrick \\\"\\u30de\\u30eb\\u30bf\\u30a4\\u30f3\\u30a2\\u30f3\\u30c9\\\
+        u30ec\\u30a2\\u30b9\\\" Uiterwijk\",\n        \"name\": \"puiterwijk\"\n \
+        \     }\n    },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n\
+        \        \"commit\": [],\n        \"ticket\": []\n      },\n      \"access_users\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"abompard\"\
+        \n        ],\n        \"owner\": [\n          \"apevec\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874174\",\n      \"date_modified\": \"\
+        1501874174\",\n      \"description\": \"The python-passlib rpms\",\n     \
+        \ \"fullname\": \"rpms/python-passlib\",\n      \"id\": 18607,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-passlib\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"apevec\",\n        \"name\": \"apevec\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"bowlofeggs\",\n          \"lmacken\"\n\
+        \        ],\n        \"owner\": [\n          \"kylev\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874174\",\n      \"date_modified\": \"\
+        1501874175\",\n      \"description\": \"The python-paste-deploy rpms\",\n\
+        \      \"fullname\": \"rpms/python-paste-deploy\",\n      \"id\": 18608,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-paste-deploy\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"kylev\",\n        \"name\": \"\
+        kylev\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"tc01\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874177\",\n   \
+        \   \"date_modified\": \"1501874177\",\n      \"description\": \"The python-pdfminer\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pdfminer\",\n      \"id\": 18623,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-pdfminer\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ben Rosser\",\n        \"name\"\
+        : \"tc01\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mstuchli\",\n          \"vkrizan\"\
+        \n        ],\n        \"owner\": [\n          \"cstratak\"\n        ],\n \
+        \       \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874178\",\n      \"date_modified\": \"\
+        1501874178\",\n      \"description\": \"The python-peewee rpms\",\n      \"\
+        fullname\": \"rpms/python-peewee\",\n      \"id\": 18634,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-peewee\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Charalampos Stratakis\",\n        \"name\": \"cstratak\"\n      }\n  \
+        \  },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n       \
+        \ \"commit\": [\n          \"python-sig\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [\n          \"sundaram\",\n          \"ncoghlan\",\n     \
+        \     \"ttorling\",\n          \"mstuchli\",\n          \"bkabrda\"\n    \
+        \    ],\n        \"owner\": [\n          \"torsava\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874184\",\n      \"date_modified\": \"\
+        1501874185\",\n      \"description\": \"The python-pip rpms\",\n      \"fullname\"\
+        : \"rpms/python-pip\",\n      \"id\": 18659,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-pip\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"torsava\",\n        \"name\":\
+        \ \"torsava\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874186\"\
+        ,\n      \"date_modified\": \"1501874186\",\n      \"description\": \"The\
+        \ python-pkgwat-api rpms\",\n      \"fullname\": \"rpms/python-pkgwat-api\"\
+        ,\n      \"id\": 18663,\n      \"milestones\": {},\n      \"name\": \"python-pkgwat-api\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874191\",\n   \
+        \   \"date_modified\": \"1501874191\",\n      \"description\": \"The python-power\
+        \ rpms\",\n      \"fullname\": \"rpms/python-power\",\n      \"id\": 18684,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-power\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"salimma\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874194\",\n      \"date_modified\": \"1501874194\"\
+        ,\n      \"description\": \"The python-psutil rpms\",\n      \"fullname\"\
+        : \"rpms/python-psutil\",\n      \"id\": 18702,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-psutil\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"salimma\",\n        \"name\": \"salimma\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"orion\",\n          \"tomspur\"\n        ],\n        \"owner\"\
+        : [\n          \"ignatenkobrain\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874195\",\n      \"date_modified\": \"1501874196\",\n\
+        \      \"description\": \"The python-ptyprocess rpms\",\n      \"fullname\"\
+        : \"rpms/python-ptyprocess\",\n      \"id\": 18709,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-ptyprocess\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Igor Gnatenko\",\n        \"name\": \"ignatenkobrain\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"orion\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874198\",\n   \
+        \   \"date_modified\": \"1501874198\",\n      \"description\": \"The python-pycodestyle\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pycodestyle\",\n      \"id\"\
+        : 18729,\n      \"milestones\": {},\n      \"name\": \"python-pycodestyle\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"immanetize\"\n    \
+        \    ],\n        \"owner\": [\n          \"ralph\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874200\",\n      \"date_modified\": \"\
+        1501874200\",\n      \"description\": \"The python-pygal rpms\",\n      \"\
+        fullname\": \"rpms/python-pygal\",\n      \"id\": 18744,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-pygal\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874201\",\n      \"date_modified\": \"1501874201\"\
+        ,\n      \"description\": \"The python-pygeoip rpms\",\n      \"fullname\"\
+        : \"rpms/python-pygeoip\",\n      \"id\": 18746,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-pygeoip\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"cicku\",\n          \"ignatenkobrain\"\n        ],\n        \"\
+        owner\": [\n          \"pwalter\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874201\",\n      \"date_modified\": \"1501874202\",\n\
+        \      \"description\": \"The python-pygit2 rpms\",\n      \"fullname\": \"\
+        rpms/python-pygit2\",\n      \"id\": 18748,\n      \"milestones\": {},\n \
+        \     \"name\": \"python-pygit2\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Pete Walter\",\n        \"name\": \"pwalter\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"orion\"\n        ],\n        \"owner\": [\n          \"pviktori\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874202\",\n   \
+        \   \"date_modified\": \"1501874202\",\n      \"description\": \"The python-pyglet\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pyglet\",\n      \"id\": 18749,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-pyglet\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"pviktori\",\n        \"name\": \"pviktori\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874202\",\n      \"date_modified\": \"1501874202\"\
+        ,\n      \"description\": \"The python-pygments-markdown-lexer rpms\",\n \
+        \     \"fullname\": \"rpms/python-pygments-markdown-lexer\",\n      \"id\"\
+        : 18750,\n      \"milestones\": {},\n      \"name\": \"python-pygments-markdown-lexer\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mstuchli\",\n          \"pviktori\"\
+        ,\n          \"rkuska\"\n        ],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874204\",\n   \
+        \   \"date_modified\": \"1501874204\",\n      \"description\": \"The python-pyldap\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pyldap\",\n      \"id\": 18762,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-pyldap\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"kumarpraveen\",\n \
+        \         \"abompard\",\n          \"pjp\"\n        ],\n        \"owner\"\
+        : [\n          \"sundaram\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874204\",\n      \"date_modified\": \"1501874205\",\n      \"description\"\
+        : \"The python-pylibmc rpms\",\n      \"fullname\": \"rpms/python-pylibmc\"\
+        ,\n      \"id\": 18763,\n      \"milestones\": {},\n      \"name\": \"python-pylibmc\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"sundaram\",\n        \"name\"\
+        : \"sundaram\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n     \
+        \     \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874205\"\
+        ,\n      \"date_modified\": \"1501874205\",\n      \"description\": \"The\
+        \ python-pylibravatar rpms\",\n      \"fullname\": \"rpms/python-pylibravatar\"\
+        ,\n      \"id\": 18764,\n      \"milestones\": {},\n      \"name\": \"python-pylibravatar\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874208\",\n   \
+        \   \"date_modified\": \"1501874208\",\n      \"description\": \"The python-pypng\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pypng\",\n      \"id\": 18783,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-pypng\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874209\",\n      \"date_modified\": \"1501874209\"\
+        ,\n      \"description\": \"The python-pyquery rpms\",\n      \"fullname\"\
+        : \"rpms/python-pyquery\",\n      \"id\": 18788,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-pyquery\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tdabasin\",\n          \"lmacken\",\n          \"bowlofeggs\"\
+        ,\n          \"rossdylan\"\n        ],\n        \"owner\": [\n          \"\
+        ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874210\"\
+        ,\n      \"date_modified\": \"1501874210\",\n      \"description\": \"The\
+        \ python-pyramid rpms\",\n      \"fullname\": \"rpms/python-pyramid\",\n \
+        \     \"id\": 18794,\n      \"milestones\": {},\n      \"name\": \"python-pyramid\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"bowlofeggs\"\n        ],\n     \
+        \   \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874209\",\n      \"date_modified\": \"1501874209\"\
+        ,\n      \"description\": \"The python-pyramid-chameleon rpms\",\n      \"\
+        fullname\": \"rpms/python-pyramid-chameleon\",\n      \"id\": 18790,\n   \
+        \   \"milestones\": {},\n      \"name\": \"python-pyramid-chameleon\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\",\n        \
+        \  \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874209\",\n   \
+        \   \"date_modified\": \"1501874209\",\n      \"description\": \"The python-pyramid-fas-openid\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pyramid-fas-openid\",\n     \
+        \ \"id\": 18791,\n      \"milestones\": {},\n      \"name\": \"python-pyramid-fas-openid\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874210\"\
+        ,\n      \"date_modified\": \"1501874210\",\n      \"description\": \"The\
+        \ python-pyramid-mako rpms\",\n      \"fullname\": \"rpms/python-pyramid-mako\"\
+        ,\n      \"id\": 18792,\n      \"milestones\": {},\n      \"name\": \"python-pyramid-mako\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"rossdylan\"\n        ],\n      \
+        \  \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874210\",\n      \"date_modified\": \"1501874210\"\
+        ,\n      \"description\": \"The python-pyramid-tm rpms\",\n      \"fullname\"\
+        : \"rpms/python-pyramid-tm\",\n      \"id\": 18793,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-pyramid-tm\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"kevin\",\n          \"abompard\",\n          \"ttorling\"\n \
+        \       ],\n        \"owner\": [\n          \"ralph\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874215\",\n      \"date_modified\": \"\
+        1501874215\",\n      \"description\": \"The python-pysocks rpms\",\n     \
+        \ \"fullname\": \"rpms/python-pysocks\",\n      \"id\": 18807,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-pysocks\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"pviktori\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874217\",\n      \"date_modified\": \"1501874217\"\
+        ,\n      \"description\": \"The python-pytest-multihost rpms\",\n      \"\
+        fullname\": \"rpms/python-pytest-multihost\",\n      \"id\": 18821,\n    \
+        \  \"milestones\": {},\n      \"name\": \"python-pytest-multihost\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"pviktori\",\n        \"name\"\
+        : \"pviktori\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874218\",\n      \"date_modified\": \"1501874218\",\n      \"description\"\
+        : \"The python-pytest-testmon rpms\",\n      \"fullname\": \"rpms/python-pytest-testmon\"\
+        ,\n      \"id\": 18826,\n      \"milestones\": {},\n      \"name\": \"python-pytest-testmon\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"bochecha\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874218\",\n      \"date_modified\": \"1501874218\",\n      \"description\"\
+        : \"The python-pythonz-bd rpms\",\n      \"fullname\": \"rpms/python-pythonz-bd\"\
+        ,\n      \"id\": 18831,\n      \"milestones\": {},\n      \"name\": \"python-pythonz-bd\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bochecha\",\n        \"name\"\
+        : \"bochecha\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"bochecha\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874223\",\n      \"date_modified\": \"1501874223\",\n      \"description\"\
+        : \"The python-rangehttpserver rpms\",\n      \"fullname\": \"rpms/python-rangehttpserver\"\
+        ,\n      \"id\": 18862,\n      \"milestones\": {},\n      \"name\": \"python-rangehttpserver\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bochecha\",\n        \"name\"\
+        : \"bochecha\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"kiilerix\"\n     \
+        \   ],\n        \"owner\": [\n          \"ralph\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874224\",\n      \"date_modified\": \"\
+        1501874224\",\n      \"description\": \"The python-re2 rpms\",\n      \"fullname\"\
+        : \"rpms/python-re2\",\n      \"id\": 18869,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-re2\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"cicku\",\n          \"maxamillion\"\
+        \n        ],\n        \"owner\": [\n          \"ralph\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874224\",\n      \"date_modified\": \"\
+        1501874224\",\n      \"description\": \"The python-redis rpms\",\n      \"\
+        fullname\": \"rpms/python-redis\",\n      \"id\": 18872,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-redis\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874226\",\n   \
+        \   \"date_modified\": \"1501874226\",\n      \"description\": \"The python-repoze-lru\
+        \ rpms\",\n      \"fullname\": \"rpms/python-repoze-lru\",\n      \"id\":\
+        \ 18881,\n      \"milestones\": {},\n      \"name\": \"python-repoze-lru\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874226\",\n      \"date_modified\": \"1501874226\"\
+        ,\n      \"description\": \"The python-repoze-what rpms\",\n      \"fullname\"\
+        : \"rpms/python-repoze-what\",\n      \"id\": 18887,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-repoze-what\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"spot\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874226\",\n      \"date_modified\": \"1501874226\"\
+        ,\n      \"description\": \"The python-repoze-who-friendlyform rpms\",\n \
+        \     \"fullname\": \"rpms/python-repoze-who-friendlyform\",\n      \"id\"\
+        : 18888,\n      \"milestones\": {},\n      \"name\": \"python-repoze-who-friendlyform\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"spot\",\n        \"name\": \"\
+        spot\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"jcline\",\n          \"ralph\",\n\
+        \          \"abompard\",\n          \"sagarun\"\n        ],\n        \"owner\"\
+        : [\n          \"cstratak\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874228\",\n      \"date_modified\": \"1501874229\",\n      \"description\"\
+        : \"The python-requests rpms\",\n      \"fullname\": \"rpms/python-requests\"\
+        ,\n      \"id\": 18902,\n      \"milestones\": {},\n      \"name\": \"python-requests\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"jdennis\",\n \
+        \         \"jdornak\"\n        ],\n        \"owner\": [\n          \"puiterwijk\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874228\",\n   \
+        \   \"date_modified\": \"1501874228\",\n      \"description\": \"The python-requests-oauthlib\
+        \ rpms\",\n      \"fullname\": \"rpms/python-requests-oauthlib\",\n      \"\
+        id\": 18900,\n      \"milestones\": {},\n      \"name\": \"python-requests-oauthlib\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Patrick \\\"\\u30de\\u30eb\\u30bf\\\
+        u30a4\\u30f3\\u30a2\\u30f3\\u30c9\\u30ec\\u30a2\\u30b9\\\" Uiterwijk\",\n\
+        \        \"name\": \"puiterwijk\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"bkabrda\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874230\",\n      \"date_modified\": \"\
+        1501874230\",\n      \"description\": \"The python-restkit rpms\",\n     \
+        \ \"fullname\": \"rpms/python-restkit\",\n      \"id\": 18909,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-restkit\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"bkabrda\",\n        \"name\": \"bkabrda\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"bochecha\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874230\",\n      \"date_modified\": \"1501874230\"\
+        ,\n      \"description\": \"The python-resumable-urlretrieve rpms\",\n   \
+        \   \"fullname\": \"rpms/python-resumable-urlretrieve\",\n      \"id\": 18913,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-resumable-urlretrieve\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bochecha\",\n        \"name\"\
+        : \"bochecha\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874232\",\n      \"date_modified\": \"1501874232\",\n      \"description\"\
+        : \"The python-ripozo rpms\",\n      \"fullname\": \"rpms/python-ripozo\"\
+        ,\n      \"id\": 18924,\n      \"milestones\": {},\n      \"name\": \"python-ripozo\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"tibbs\",\n    \
+        \      \"mcyprian\",\n          \"cstratak\",\n          \"torsava\"\n   \
+        \     ],\n        \"owner\": [\n          \"orion\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874236\",\n      \"date_modified\": \"\
+        1501874236\",\n      \"description\": \"The python-rpm-macros rpms\",\n  \
+        \    \"fullname\": \"rpms/python-rpm-macros\",\n      \"id\": 18944,\n   \
+        \   \"milestones\": {},\n      \"name\": \"python-rpm-macros\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orion\",\n        \"name\": \"\
+        orion\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874238\",\n   \
+        \   \"date_modified\": \"1501874238\",\n      \"description\": \"The python-rxjson\
+        \ rpms\",\n      \"fullname\": \"rpms/python-rxjson\",\n      \"id\": 18955,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-rxjson\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874239\",\n      \"date_modified\": \"1501874239\"\
+        ,\n      \"description\": \"The python-sanction rpms\",\n      \"fullname\"\
+        : \"rpms/python-sanction\",\n      \"id\": 18960,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-sanction\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tc01\"\n        ],\n        \"owner\": [\n          \"orion\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874241\",\n   \
+        \   \"date_modified\": \"1501874241\",\n      \"description\": \"The python-scp\
+        \ rpms\",\n      \"fullname\": \"rpms/python-scp\",\n      \"id\": 18971,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-scp\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"mbacovsk\",\n          \"mstuchli\"\n        ],\n        \"owner\":\
+        \ [\n          \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874241\",\n      \"date_modified\": \"1501874241\",\n      \"description\"\
+        : \"The python-scripttest rpms\",\n      \"fullname\": \"rpms/python-scripttest\"\
+        ,\n      \"id\": 18973,\n      \"milestones\": {},\n      \"name\": \"python-scripttest\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"tc01\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874241\",\n      \"date_modified\": \"1501874241\",\n      \"description\"\
+        : \"The python-seesaw rpms\",\n      \"fullname\": \"rpms/python-seesaw\"\
+        ,\n      \"id\": 18977,\n      \"milestones\": {},\n      \"name\": \"python-seesaw\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ben Rosser\",\n        \"name\"\
+        : \"tc01\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"churchyard\",\n          \"mcyprian\"\
+        ,\n          \"cstratak\",\n          \"rkuska\",\n          \"mstuchli\"\
+        ,\n          \"lmacken\"\n        ],\n        \"owner\": [\n          \"bowlofeggs\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874243\",\n   \
+        \   \"date_modified\": \"1501874244\",\n      \"description\": \"The python-setuptools\
+        \ rpms\",\n      \"fullname\": \"rpms/python-setuptools\",\n      \"id\":\
+        \ 18988,\n      \"milestones\": {},\n      \"name\": \"python-setuptools\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bowlofeggs\",\n        \"name\"\
+        : \"bowlofeggs\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"ralph\",\n     \
+        \     \"grover\",\n          \"jpena\"\n        ],\n        \"owner\": [\n\
+        \          \"carlwgeorge\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874245\",\n      \"date_modified\": \"1501874245\",\n      \"description\"\
+        : \"The python-sh rpms\",\n      \"fullname\": \"rpms/python-sh\",\n     \
+        \ \"id\": 18995,\n      \"milestones\": {},\n      \"name\": \"python-sh\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Carl George\",\n        \"name\"\
+        : \"carlwgeorge\"\n      }\n    },\n    {\n      \"access_groups\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874246\",\n      \"date_modified\": \"1501874246\",\n      \"description\"\
+        : \"The python-sieve rpms\",\n      \"fullname\": \"rpms/python-sieve\",\n\
+        \      \"id\": 19002,\n      \"milestones\": {},\n      \"name\": \"python-sieve\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\",\n          \"bowlofeggs\"\
+        ,\n          \"lmacken\"\n        ],\n        \"owner\": [\n          \"potty\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874247\",\n   \
+        \   \"date_modified\": \"1501874247\",\n      \"description\": \"The python-simplemediawiki\
+        \ rpms\",\n      \"fullname\": \"rpms/python-simplemediawiki\",\n      \"\
+        id\": 19010,\n      \"milestones\": {},\n      \"name\": \"python-simplemediawiki\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"potty\",\n        \"name\": \"\
+        potty\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"bkabrda\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874251\",\n      \"date_modified\": \"1501874251\",\n\
+        \      \"description\": \"The python-socketpool rpms\",\n      \"fullname\"\
+        : \"rpms/python-socketpool\",\n      \"id\": 19036,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-socketpool\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"bkabrda\",\n        \"name\": \"bkabrda\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"tc01\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874251\",\n      \"date_modified\": \"1501874251\"\
+        ,\n      \"description\": \"The python-sockjs-tornado rpms\",\n      \"fullname\"\
+        : \"rpms/python-sockjs-tornado\",\n      \"id\": 19037,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-sockjs-tornado\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ben Rosser\",\n        \"name\": \"tc01\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"mbacovsk\",\n          \"ivazquez\",\n          \"lmacken\",\n\
+        \          \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"\
+        nphilipp\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874256\"\
+        ,\n      \"date_modified\": \"1501874256\",\n      \"description\": \"The\
+        \ python-sqlalchemy rpms\",\n      \"fullname\": \"rpms/python-sqlalchemy\"\
+        ,\n      \"id\": 19077,\n      \"milestones\": {},\n      \"name\": \"python-sqlalchemy\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"nphilipp\",\n        \"name\"\
+        : \"nphilipp\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"orphan\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874256\",\n      \"date_modified\": \"1501874256\"\
+        ,\n      \"description\": \"The python-sqlalchemy0.8 rpms\",\n      \"fullname\"\
+        : \"rpms/python-sqlalchemy0.8\",\n      \"id\": 19081,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-sqlalchemy0.8\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orphan\",\n        \"name\": \"orphan\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874259\",\n   \
+        \   \"date_modified\": \"1501874259\",\n      \"description\": \"The python-stomper\
+        \ rpms\",\n      \"fullname\": \"rpms/python-stomper\",\n      \"id\": 19099,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-stomper\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874259\",\n      \"date_modified\": \"1501874259\"\
+        ,\n      \"description\": \"The python-strainer rpms\",\n      \"fullname\"\
+        : \"rpms/python-strainer\",\n      \"id\": 19102,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-strainer\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874259\",\n      \"date_modified\": \"1501874260\"\
+        ,\n      \"description\": \"The python-stuf rpms\",\n      \"fullname\": \"\
+        rpms/python-stuf\",\n      \"id\": 19105,\n      \"milestones\": {},\n   \
+        \   \"name\": \"python-stuf\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"nsoffer\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874260\",\n   \
+        \   \"date_modified\": \"1501874260\",\n      \"description\": \"The python-subprocess32\
+        \ rpms\",\n      \"fullname\": \"rpms/python-subprocess32\",\n      \"id\"\
+        : 19106,\n      \"milestones\": {},\n      \"name\": \"python-subprocess32\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"nsoffer\",\n        \"name\":\
+        \ \"nsoffer\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"pingou\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874261\"\
+        ,\n      \"date_modified\": \"1501874261\",\n      \"description\": \"The\
+        \ python-summershum rpms\",\n      \"fullname\": \"rpms/python-summershum\"\
+        ,\n      \"id\": 19112,\n      \"milestones\": {},\n      \"name\": \"python-summershum\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Pierre-YvesChibon\",\n       \
+        \ \"name\": \"pingou\"\n      }\n    },\n    {\n      \"access_groups\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874261\",\n      \"date_modified\": \"1501874261\",\n      \"description\"\
+        : \"The python-svg-path rpms\",\n      \"fullname\": \"rpms/python-svg-path\"\
+        ,\n      \"id\": 19115,\n      \"milestones\": {},\n      \"name\": \"python-svg-path\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\",\n          \"apevec\"\n\
+        \        ],\n        \"owner\": [\n          \"hguemar\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874262\",\n      \"date_modified\": \"\
+        1501874262\",\n      \"description\": \"The python-tablib rpms\",\n      \"\
+        fullname\": \"rpms/python-tablib\",\n      \"id\": 19124,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-tablib\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"hguemar\",\n        \"name\": \"hguemar\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"rossdylan\"\n        ],\n        \"owner\": [\n          \"sayanchowdhury\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874263\",\n   \
+        \   \"date_modified\": \"1501874263\",\n      \"description\": \"The python-tahrir\
+        \ rpms\",\n      \"fullname\": \"rpms/python-tahrir\",\n      \"id\": 19130,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-tahrir\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sayanchowdhury\",\n        \"name\": \"sayanchowdhury\"\n      }\n   \
+        \ },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"\
+        commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"rossdylan\"\n        ],\n        \"owner\": [\n         \
+        \ \"sayanchowdhury\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874263\",\n      \"date_modified\": \"1501874263\",\n      \"description\"\
+        : \"The python-tahrir-api rpms\",\n      \"fullname\": \"rpms/python-tahrir-api\"\
+        ,\n      \"id\": 19129,\n      \"milestones\": {},\n      \"name\": \"python-tahrir-api\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"sayanchowdhury\",\n        \"\
+        name\": \"sayanchowdhury\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"lmacken\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874263\",\n      \"date_modified\": \"\
+        1501874263\",\n      \"description\": \"The python-tbgrep rpms\",\n      \"\
+        fullname\": \"rpms/python-tbgrep\",\n      \"id\": 19135,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-tbgrep\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874265\",\n      \"date_modified\": \"1501874265\"\
+        ,\n      \"description\": \"The python-testpath rpms\",\n      \"fullname\"\
+        : \"rpms/python-testpath\",\n      \"id\": 19148,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-testpath\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"kumarpraveen\",\n \
+        \         \"abompard\"\n        ],\n        \"owner\": [\n          \"salimma\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874266\",\n   \
+        \   \"date_modified\": \"1501874266\",\n      \"description\": \"The python-testtools\
+        \ rpms\",\n      \"fullname\": \"rpms/python-testtools\",\n      \"id\": 19152,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-testtools\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"salimma\",\n        \"name\":\
+        \ \"salimma\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"lmacken\"\n       \
+        \ ],\n        \"owner\": [\n          \"dcallagh\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874267\",\n      \"date_modified\": \"\
+        1501874267\",\n      \"description\": \"The python-tgmochikit rpms\",\n  \
+        \    \"fullname\": \"rpms/python-tgmochikit\",\n      \"id\": 19164,\n   \
+        \   \"milestones\": {},\n      \"name\": \"python-tgmochikit\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"dcallagh\",\n        \"name\"\
+        : \"dcallagh\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n     \
+        \     \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874267\"\
+        ,\n      \"date_modified\": \"1501874267\",\n      \"description\": \"The\
+        \ python-tgscheduler rpms\",\n      \"fullname\": \"rpms/python-tgscheduler\"\
+        ,\n      \"id\": 19165,\n      \"milestones\": {},\n      \"name\": \"python-tgscheduler\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"orion\",\n          \"abompard\"\
+        ,\n          \"churchyard\"\n        ],\n        \"owner\": [\n          \"\
+        tomspur\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874269\"\
+        ,\n      \"date_modified\": \"1501874269\",\n      \"description\": \"The\
+        \ python-tornado rpms\",\n      \"fullname\": \"rpms/python-tornado\",\n \
+        \     \"id\": 19178,\n      \"milestones\": {},\n      \"name\": \"python-tornado\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"lmacken\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874271\"\
+        ,\n      \"date_modified\": \"1501874271\",\n      \"description\": \"The\
+        \ python-toscawidgets rpms\",\n      \"fullname\": \"rpms/python-toscawidgets\"\
+        ,\n      \"id\": 19182,\n      \"milestones\": {},\n      \"name\": \"python-toscawidgets\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874273\",\n      \"date_modified\": \"1501874273\"\
+        ,\n      \"description\": \"The python-transaction rpms\",\n      \"fullname\"\
+        : \"rpms/python-transaction\",\n      \"id\": 19190,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-transaction\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874278\",\n   \
+        \   \"date_modified\": \"1501874278\",\n      \"description\": \"The python-translationstring\
+        \ rpms\",\n      \"fullname\": \"rpms/python-translationstring\",\n      \"\
+        id\": 19194,\n      \"milestones\": {},\n      \"name\": \"python-translationstring\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"lmacken\"\n       \
+        \ ],\n        \"owner\": [\n          \"orphan\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874280\",\n      \"date_modified\": \"1501874280\"\
+        ,\n      \"description\": \"The python-turbojson13 rpms\",\n      \"fullname\"\
+        : \"rpms/python-turbojson13\",\n      \"id\": 19205,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-turbojson13\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orphan\",\n        \"name\": \"orphan\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874281\",\n      \"date_modified\": \"1501874281\"\
+        ,\n      \"description\": \"The python-tw-forms rpms\",\n      \"fullname\"\
+        : \"rpms/python-tw-forms\",\n      \"id\": 19209,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-tw-forms\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874285\",\n      \"date_modified\": \"1501874285\"\
+        ,\n      \"description\": \"The python-twiggy rpms\",\n      \"fullname\"\
+        : \"rpms/python-twiggy\",\n      \"id\": 19225,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-twiggy\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874293\",\n      \"date_modified\": \"1501874293\"\
+        ,\n      \"description\": \"The python-txrequests rpms\",\n      \"fullname\"\
+        : \"rpms/python-txrequests\",\n      \"id\": 19243,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-txrequests\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874294\",\n      \"date_modified\": \"1501874294\"\
+        ,\n      \"description\": \"The python-txws rpms\",\n      \"fullname\": \"\
+        rpms/python-txws\",\n      \"id\": 19245,\n      \"milestones\": {},\n   \
+        \   \"name\": \"python-txws\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874294\",\n   \
+        \   \"date_modified\": \"1501874294\",\n      \"description\": \"The python-txzmq\
+        \ rpms\",\n      \"fullname\": \"rpms/python-txzmq\",\n      \"id\": 19246,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-txzmq\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874297\",\n      \"date_modified\": \"1501874297\"\
+        ,\n      \"description\": \"The python-uranium rpms\",\n      \"fullname\"\
+        : \"rpms/python-uranium\",\n      \"id\": 19266,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-uranium\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"jcline\",\n          \"abompard\",\n          \"ralph\"\n   \
+        \     ],\n        \"owner\": [\n          \"sagarun\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874298\",\n      \"date_modified\": \"\
+        1501874298\",\n      \"description\": \"The python-urllib3 rpms\",\n     \
+        \ \"fullname\": \"rpms/python-urllib3\",\n      \"id\": 19272,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-urllib3\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sagarun\",\n        \"name\": \"sagarun\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874305\",\n      \"date_modified\": \"1501874305\"\
+        ,\n      \"description\": \"The python-utils rpms\",\n      \"fullname\":\
+        \ \"rpms/python-utils\",\n      \"id\": 19277,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-utils\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874306\",\n      \"date_modified\": \"1501874306\"\
+        ,\n      \"description\": \"The python-vcrpy rpms\",\n      \"fullname\":\
+        \ \"rpms/python-vcrpy\",\n      \"id\": 19282,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-vcrpy\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874307\",\n      \"date_modified\": \"1501874307\"\
+        ,\n      \"description\": \"The python-velruse rpms\",\n      \"fullname\"\
+        : \"rpms/python-velruse\",\n      \"id\": 19284,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-velruse\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"lmacken\",\n          \"rossdylan\"\n \
+        \       ],\n        \"owner\": [\n          \"tdabasin\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874307\",\n      \"date_modified\": \"\
+        1501874308\",\n      \"description\": \"The python-venusian rpms\",\n    \
+        \  \"fullname\": \"rpms/python-venusian\",\n      \"id\": 19285,\n      \"\
+        milestones\": {},\n      \"name\": \"python-venusian\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"tdabasin\",\n        \"name\": \"tdabasin\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874308\",\n      \"date_modified\": \"1501874308\"\
+        ,\n      \"description\": \"The python-virtualenv-clone rpms\",\n      \"\
+        fullname\": \"rpms/python-virtualenv-clone\",\n      \"id\": 19291,\n    \
+        \  \"milestones\": {},\n      \"name\": \"python-virtualenv-clone\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"lgs\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874310\",\n      \"date_modified\": \"1501874311\",\n      \"description\"\
+        : \"The python-waitress rpms\",\n      \"fullname\": \"rpms/python-waitress\"\
+        ,\n      \"id\": 19306,\n      \"milestones\": {},\n      \"name\": \"python-waitress\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lgs\",\n        \"name\": \"lgs\"\
+        \n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n\
+        \        \"commit\": [],\n        \"ticket\": []\n      },\n      \"access_users\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"abompard\"\
+        \n        ],\n        \"owner\": [\n          \"fale\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874312\",\n      \"date_modified\": \"\
+        1501874312\",\n      \"description\": \"The python-wcwidth rpms\",\n     \
+        \ \"fullname\": \"rpms/python-wcwidth\",\n      \"id\": 19312,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-wcwidth\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"fale\",\n        \"name\": \"fale\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"ralph\",\n          \"ricky\"\n        ],\n        \"owner\": [\n  \
+        \        \"lmacken\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874312\",\n      \"date_modified\": \"1501874313\",\n      \"description\"\
+        : \"The python-weberror rpms\",\n      \"fullname\": \"rpms/python-weberror\"\
+        ,\n      \"id\": 19318,\n      \"milestones\": {},\n      \"name\": \"python-weberror\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"hguemar\",\n      \
+        \    \"ralph\",\n          \"ricky\",\n          \"lmacken\"\n        ],\n\
+        \        \"owner\": [\n          \"mrunge\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874313\",\n      \"date_modified\": \"1501874314\"\
+        ,\n      \"description\": \"The python-webob rpms\",\n      \"fullname\":\
+        \ \"rpms/python-webob\",\n      \"id\": 19322,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-webob\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"mrunge\",\n        \"name\": \"mrunge\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"orphan\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874314\",\n   \
+        \   \"date_modified\": \"1501874314\",\n      \"description\": \"The python-webob1.2\
+        \ rpms\",\n      \"fullname\": \"rpms/python-webob1.2\",\n      \"id\": 19325,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-webob1.2\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orphan\",\n        \"name\": \"\
+        orphan\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874314\",\n   \
+        \   \"date_modified\": \"1501874314\",\n      \"description\": \"The python-webob1.4\
+        \ rpms\",\n      \"fullname\": \"rpms/python-webob1.4\",\n      \"id\": 19326,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-webob1.4\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"lmacken\",\n          \"ricky\"\n\
+        \        ],\n        \"owner\": [\n          \"bkabrda\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874315\",\n      \"date_modified\": \"\
+        1501874315\",\n      \"description\": \"The python-webtest rpms\",\n     \
+        \ \"fullname\": \"rpms/python-webtest\",\n      \"id\": 19331,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-webtest\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"bkabrda\",\n        \"name\": \"bkabrda\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874315\",\n      \"date_modified\": \"1501874315\"\
+        ,\n      \"description\": \"The python-webtest1.3 rpms\",\n      \"fullname\"\
+        : \"rpms/python-webtest1.3\",\n      \"id\": 19332,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-webtest1.3\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"hguemar\",\n          \"abompard\"\
+        ,\n          \"ianweller\"\n        ],\n        \"owner\": [\n          \"\
+        codeblock\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874316\"\
+        ,\n      \"date_modified\": \"1501874316\",\n      \"description\": \"The\
+        \ python-werkzeug rpms\",\n      \"fullname\": \"rpms/python-werkzeug\",\n\
+        \      \"id\": 19334,\n      \"milestones\": {},\n      \"name\": \"python-werkzeug\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"codeblock\",\n        \"name\"\
+        : \"codeblock\"\n      }\n    },\n    {\n      \"access_groups\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n   \
+        \       \"orion\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874318\",\n      \"date_modified\": \"1501874318\",\n      \"description\"\
+        : \"The python-workerpool rpms\",\n      \"fullname\": \"rpms/python-workerpool\"\
+        ,\n      \"id\": 19351,\n      \"milestones\": {},\n      \"name\": \"python-workerpool\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orion\",\n        \"name\": \"\
+        orion\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"chandankumar\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874318\",\n      \"date_modified\": \"1501874319\"\
+        ,\n      \"description\": \"The python-wrapt rpms\",\n      \"fullname\":\
+        \ \"rpms/python-wrapt\",\n      \"id\": 19352,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-wrapt\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"chandankumar\",\n        \"name\": \"chandankumar\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"mstuchli\"\n        ],\n        \"owner\": [\n          \"cstratak\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874320\",\n   \
+        \   \"date_modified\": \"1501874320\",\n      \"description\": \"The python-wtf-peewee\
+        \ rpms\",\n      \"fullname\": \"rpms/python-wtf-peewee\",\n      \"id\":\
+        \ 19361,\n      \"milestones\": {},\n      \"name\": \"python-wtf-peewee\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"fab\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874323\",\n      \"date_modified\": \"1501874323\"\
+        ,\n      \"description\": \"The python-xmltodict rpms\",\n      \"fullname\"\
+        : \"rpms/python-xmltodict\",\n      \"id\": 19378,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-xmltodict\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Fabian Affolter\",\n        \"name\": \"fab\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874327\",\n      \"date_modified\": \"1501874327\"\
+        ,\n      \"description\": \"The python-zanata2fedmsg rpms\",\n      \"fullname\"\
+        : \"rpms/python-zanata2fedmsg\",\n      \"id\": 19400,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-zanata2fedmsg\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"pbrobinson\"\n        ],\n        \"owner\": [\n          \"\
+        churchyard\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874327\"\
+        ,\n      \"date_modified\": \"1501874327\",\n      \"description\": \"The\
+        \ python-zeroconf rpms\",\n      \"fullname\": \"rpms/python-zeroconf\",\n\
+        \      \"id\": 19407,\n      \"milestones\": {},\n      \"name\": \"python-zeroconf\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n      \
+        \  ],\n        \"owner\": [\n          \"tomspur\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874328\",\n      \"date_modified\": \"\
+        1501874328\",\n      \"description\": \"The python-zmq rpms\",\n      \"fullname\"\
+        : \"rpms/python-zmq\",\n      \"id\": 19410,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-zmq\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"tdabasin\",\n          \"abompard\"\n        ],\n       \
+        \ \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874328\",\n      \"date_modified\": \"1501874328\"\
+        ,\n      \"description\": \"The python-zope-component rpms\",\n      \"fullname\"\
+        : \"rpms/python-zope-component\",\n      \"id\": 19412,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-zope-component\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"tdabasin\",\n          \"abompard\"\
+        ,\n          \"bowlofeggs\",\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874328\",\n      \"date_modified\": \"1501874328\",\n\
+        \      \"description\": \"The python-zope-configuration rpms\",\n      \"\
+        fullname\": \"rpms/python-zope-configuration\",\n      \"id\": 19413,\n  \
+        \    \"milestones\": {},\n      \"name\": \"python-zope-configuration\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"tdabasin\",\n          \"abompard\"\n        ],\n       \
+        \ \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874329\",\n      \"date_modified\": \"1501874329\"\
+        ,\n      \"description\": \"The python-zope-event rpms\",\n      \"fullname\"\
+        : \"rpms/python-zope-event\",\n      \"id\": 19418,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-zope-event\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"tdabasin\",\n          \"abompard\"\
+        \n        ],\n        \"owner\": [\n          \"ralph\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874329\",\n      \"date_modified\": \"\
+        1501874330\",\n      \"description\": \"The python-zope-exceptions rpms\"\
+        ,\n      \"fullname\": \"rpms/python-zope-exceptions\",\n      \"id\": 19419,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-zope-exceptions\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tdabasin\",\n          \"abompard\"\n        ],\n        \"owner\"\
+        : [\n          \"ralph\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874330\",\n      \"date_modified\": \"1501874330\",\n      \"description\"\
+        : \"The python-zope-i18nmessageid rpms\",\n      \"fullname\": \"rpms/python-zope-i18nmessageid\"\
+        ,\n      \"id\": 19423,\n      \"milestones\": {},\n      \"name\": \"python-zope-i18nmessageid\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tdabasin\",\n          \"abompard\"\n        ],\n        \"owner\"\
+        : [\n          \"ralph\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874331\",\n      \"date_modified\": \"1501874331\",\n      \"description\"\
+        : \"The python-zope-schema rpms\",\n      \"fullname\": \"rpms/python-zope-schema\"\
+        ,\n      \"id\": 19428,\n      \"milestones\": {},\n      \"name\": \"python-zope-schema\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tdabasin\",\n          \"abompard\"\n        ],\n        \"owner\"\
+        : [\n          \"ralph\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874331\",\n      \"date_modified\": \"1501874331\",\n      \"description\"\
+        : \"The python-zope-testing rpms\",\n      \"fullname\": \"rpms/python-zope-testing\"\
+        ,\n      \"id\": 19432,\n      \"milestones\": {},\n      \"name\": \"python-zope-testing\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"abompard\"\n        ],\n        \"owner\": [\n          \"jjames\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874331\",\n   \
+        \   \"date_modified\": \"1501874331\",\n      \"description\": \"The python-zope-testrunner\
+        \ rpms\",\n      \"fullname\": \"rpms/python-zope-testrunner\",\n      \"\
+        id\": 19433,\n      \"milestones\": {},\n      \"name\": \"python-zope-testrunner\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"jjames\",\n        \"name\": \"\
+        jjames\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mstuchli\"\n        ],\n       \
+        \ \"owner\": [\n          \"cstratak\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501865449\",\n      \"date_modified\": \"1501865449\"\
+        ,\n      \"description\": \"The RunSnakeRun rpms\",\n      \"fullname\": \"\
+        rpms/RunSnakeRun\",\n      \"id\": 374,\n      \"milestones\": {},\n     \
+        \ \"name\": \"RunSnakeRun\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [],\n        \"ticket\":\
+        \ []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [],\n        \"owner\": [\n          \"abompard\"\n       \
+        \ ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n    \
+        \  \"custom_keys\": [],\n      \"date_created\": \"1501874684\",\n      \"\
+        date_modified\": \"1501874684\",\n      \"description\": \"The sassc rpms\"\
+        ,\n      \"fullname\": \"rpms/sassc\",\n      \"id\": 20986,\n      \"milestones\"\
+        : {},\n      \"name\": \"sassc\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"jspaleta\",\n   \
+        \       \"orion\",\n          \"cstratak\",\n          \"limb\",\n       \
+        \   \"ttomecek\"\n        ],\n        \"owner\": [\n          \"tomspur\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874702\",\n   \
+        \   \"date_modified\": \"1501874703\",\n      \"description\": \"The scipy\
+        \ rpms\",\n      \"fullname\": \"rpms/scipy\",\n      \"id\": 21075,\n   \
+        \   \"milestones\": {},\n      \"name\": \"scipy\",\n      \"namespace\":\
+        \ \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"tomspur\",\n        \"name\": \"tomspur\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"rkuska\",\n          \"ishcherb\",\n          \"torsava\"\n \
+        \       ],\n        \"owner\": [\n          \"bkabrda\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874838\",\n      \"date_modified\": \"\
+        1501874838\",\n      \"description\": \"The spec2scl rpms\",\n      \"fullname\"\
+        : \"rpms/spec2scl\",\n      \"id\": 21510,\n      \"milestones\": {},\n  \
+        \    \"name\": \"spec2scl\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bkabrda\",\n        \"name\":\
+        \ \"bkabrda\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"rtnpro\"\n        ],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874902\",\n      \"date_modified\": \"1501874903\"\
+        ,\n      \"description\": \"The statscache rpms\",\n      \"fullname\": \"\
+        rpms/statscache\",\n      \"id\": 21659,\n      \"milestones\": {},\n    \
+        \  \"name\": \"statscache\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"rtnpro\"\n        ],\n        \"\
+        owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n    \
+        \  },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874902\",\n      \"date_modified\": \"1501874902\",\n      \"description\"\
+        : \"The statscache-plugins rpms\",\n      \"fullname\": \"rpms/statscache-plugins\"\
+        ,\n      \"id\": 21658,\n      \"milestones\": {},\n      \"name\": \"statscache-plugins\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"kevin\"\n        ],\n        \"\
+        owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n    \
+        \  },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874948\",\n      \"date_modified\": \"1501874948\",\n      \"description\"\
+        : \"The supybot-fedmsg rpms\",\n      \"fullname\": \"rpms/supybot-fedmsg\"\
+        ,\n      \"id\": 21827,\n      \"milestones\": {},\n      \"name\": \"supybot-fedmsg\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"kevin\",\n          \"jstanley\"\
+        ,\n          \"puiterwijk\",\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"ianweller\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874948\",\n      \"date_modified\": \"1501874949\"\
+        ,\n      \"description\": \"The supybot-fedora rpms\",\n      \"fullname\"\
+        : \"rpms/supybot-fedora\",\n      \"id\": 21828,\n      \"milestones\": {},\n\
+        \      \"name\": \"supybot-fedora\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"ianweller\",\n        \"name\": \"ianweller\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501875115\",\n      \"date_modified\": \"1501875115\"\
+        ,\n      \"description\": \"The trac-fedmsg-plugin rpms\",\n      \"fullname\"\
+        : \"rpms/trac-fedmsg-plugin\",\n      \"id\": 22419,\n      \"milestones\"\
+        : {},\n      \"name\": \"trac-fedmsg-plugin\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"mstuchli\"\n        ],\n        \"owner\": [\n          \"cstratak\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501875220\",\n   \
+        \   \"date_modified\": \"1501875221\",\n      \"description\": \"The unp rpms\"\
+        ,\n      \"fullname\": \"rpms/unp\",\n      \"id\": 22729,\n      \"milestones\"\
+        : {},\n      \"name\": \"unp\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    }\n  ],\n  \"user\": {\n    \"\
+        fullname\": \"abompard\",\n    \"name\": \"abompard\"\n  }\n}"}
+    headers:
+      AppServer: [proxy10.phx2.fedoraproject.org]
+      AppTime: [D=10332807]
+      Connection: [Keep-Alive]
+      Content-Length: ['353146']
+      Content-Type: [application/json]
+      Date: ['Mon, 07 Aug 2017 14:54:51 GMT']
+      Keep-Alive: ['timeout=15, max=500']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_auth_gssapi/1.4.0
+          mod_wsgi/3.4 Python/2.7.5]
+      Set-Cookie: ['disgit_pagure=eyJfcGVybWFuZW50Ijp0cnVlfQ.DGoQxQ.35lhBIibCNeGWKEEQBOvRdBeoJA;
+          Expires=Thu, 07-Sep-2017 14:55:01 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.utils.test_packages.PackageUtilsTest.test_get_user_packages_owned b/hubs/tests/vcr-request-data/hubs.tests.utils.test_packages.PackageUtilsTest.test_get_user_packages_owned
new file mode 100644
index 0000000..b39687d
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.utils.test_packages.PackageUtilsTest.test_get_user_packages_owned
@@ -0,0 +1,5160 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.3]
+    method: GET
+    uri: https://src.fedoraproject.org/api/0/user/abompard
+  response:
+    body: {string: "{\n  \"forks\": [],\n  \"repos\": [\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501865563\",\n      \"date_modified\": \"1501865563\",\n      \"description\"\
+        : \"The ampy rpms\",\n      \"fullname\": \"rpms/ampy\",\n      \"id\": 657,\n\
+        \      \"milestones\": {},\n      \"name\": \"ampy\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ianweller\"\n        ],\n        \"owner\": [\n          \"ralph\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501866970\",\n   \
+        \   \"date_modified\": \"1501866970\",\n      \"description\": \"The datagrepper\
+        \ rpms\",\n      \"fullname\": \"rpms/datagrepper\",\n      \"id\": 2300,\n\
+        \      \"milestones\": {},\n      \"name\": \"datagrepper\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501866971\",\n      \"date_modified\": \"1501866971\"\
+        ,\n      \"description\": \"The datanommer rpms\",\n      \"fullname\": \"\
+        rpms/datanommer\",\n      \"id\": 2303,\n      \"milestones\": {},\n     \
+        \ \"name\": \"datanommer\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501866971\",\n   \
+        \   \"date_modified\": \"1501866971\",\n      \"description\": \"The datanommer-commands\
+        \ rpms\",\n      \"fullname\": \"rpms/datanommer-commands\",\n      \"id\"\
+        : 2302,\n      \"milestones\": {},\n      \"name\": \"datanommer-commands\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501867113\",\n   \
+        \   \"date_modified\": \"1501867113\",\n      \"description\": \"The doge\
+        \ rpms\",\n      \"fullname\": \"rpms/doge\",\n      \"id\": 2650,\n     \
+        \ \"milestones\": {},\n      \"name\": \"doge\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"bowlofeggs\"\n        ],\n        \"owner\"\
+        : [\n          \"lmacken\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501867531\",\n      \"date_modified\": \"1501867531\",\n      \"description\"\
+        : \"The fedmsg rpms\",\n      \"fullname\": \"rpms/fedmsg\",\n      \"id\"\
+        : 3634,\n      \"milestones\": {},\n      \"name\": \"fedmsg\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"pingou\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501867531\"\
+        ,\n      \"date_modified\": \"1501867531\",\n      \"description\": \"The\
+        \ fedocal rpms\",\n      \"fullname\": \"rpms/fedocal\",\n      \"id\": 3635,\n\
+        \      \"milestones\": {},\n      \"name\": \"fedocal\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Pierre-YvesChibon\",\n        \"name\": \"pingou\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"orphan\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501867872\",\n   \
+        \   \"date_modified\": \"1501867872\",\n      \"description\": \"The geoip-geolite\
+        \ rpms\",\n      \"fullname\": \"rpms/geoip-geolite\",\n      \"id\": 4300,\n\
+        \      \"milestones\": {},\n      \"name\": \"geoip-geolite\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orphan\",\n        \"name\": \"orphan\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501868076\",\n      \"date_modified\": \"1501868076\"\
+        ,\n      \"description\": \"The gilmsg rpms\",\n      \"fullname\": \"rpms/gilmsg\"\
+        ,\n      \"id\": 4709,\n      \"milestones\": {},\n      \"name\": \"gilmsg\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501868097\",\n   \
+        \   \"date_modified\": \"1501868097\",\n      \"description\": \"The gitflow\
+        \ rpms\",\n      \"fullname\": \"rpms/gitflow\",\n      \"id\": 4763,\n  \
+        \    \"milestones\": {},\n      \"name\": \"gitflow\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501868099\",\n      \"date_modified\": \"1501868099\"\
+        ,\n      \"description\": \"The github2fedmsg rpms\",\n      \"fullname\"\
+        : \"rpms/github2fedmsg\",\n      \"id\": 4765,\n      \"milestones\": {},\n\
+        \      \"name\": \"github2fedmsg\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"abompard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501868897\",\n   \
+        \   \"date_modified\": \"1501868897\",\n      \"description\": \"The grisbi\
+        \ rpms\",\n      \"fullname\": \"rpms/grisbi\",\n      \"id\": 5813,\n   \
+        \   \"milestones\": {},\n      \"name\": \"grisbi\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ignatenkobrain\",\n          \"churchyard\",\n          \"lbalhar\"\
+        ,\n          \"dcantrel\",\n          \"mrunge\",\n          \"cstratak\"\
+        ,\n          \"orion\",\n          \"salimma\"\n        ],\n        \"owner\"\
+        : [\n          \"tomspur\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501869392\",\n      \"date_modified\": \"1501869395\",\n      \"description\"\
+        : \"The ipython rpms\",\n      \"fullname\": \"rpms/ipython\",\n      \"id\"\
+        : 6713,\n      \"milestones\": {},\n      \"name\": \"ipython\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"frafra\",\n          \"slaanesh\"\n        ],\n        \"\
+        owner\": [\n          \"abompard\"\n        ],\n        \"ticket\": []\n \
+        \     },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501869882\",\n      \"date_modified\": \"1501869882\",\n\
+        \      \"description\": \"The keepassx rpms\",\n      \"fullname\": \"rpms/keepassx\"\
+        ,\n      \"id\": 7558,\n      \"milestones\": {},\n      \"name\": \"keepassx\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"kde-sig\"\n       \
+        \ ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"dvratil\"\n        ],\n\
+        \        \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501870090\",\n      \"date_modified\": \"1501870090\"\
+        ,\n      \"description\": \"The ksshaskpass rpms\",\n      \"fullname\": \"\
+        rpms/ksshaskpass\",\n      \"id\": 7907,\n      \"milestones\": {},\n    \
+        \  \"name\": \"ksshaskpass\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501870283\",\n      \"date_modified\": \"1501870283\",\n      \"description\"\
+        : \"The libarcus rpms\",\n      \"fullname\": \"rpms/libarcus\",\n      \"\
+        id\": 8165,\n      \"milestones\": {},\n      \"name\": \"libarcus\",\n  \
+        \    \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n  \
+        \    },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501870571\",\n      \"date_modified\": \"\
+        1501870571\",\n      \"description\": \"The libsass rpms\",\n      \"fullname\"\
+        : \"rpms/libsass\",\n      \"id\": 8837,\n      \"milestones\": {},\n    \
+        \  \"name\": \"libsass\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501870571\",\n      \"date_modified\": \"1501870571\",\n      \"description\"\
+        : \"The libsavitar rpms\",\n      \"fullname\": \"rpms/libsavitar\",\n   \
+        \   \"id\": 8838,\n      \"milestones\": {},\n      \"name\": \"libsavitar\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n   \
+        \       \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501870834\",\n      \"date_modified\": \"1501870834\",\n      \"description\"\
+        : \"The mailman3-fedmsg-plugin rpms\",\n      \"fullname\": \"rpms/mailman3-fedmsg-plugin\"\
+        ,\n      \"id\": 9439,\n      \"milestones\": {},\n      \"name\": \"mailman3-fedmsg-plugin\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"adrian\"\n        ],\n        \"\
+        owner\": [\n          \"puiterwijk\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501871113\",\n      \"date_modified\": \"1501871113\"\
+        ,\n      \"description\": \"The mirrormanager2 rpms\",\n      \"fullname\"\
+        : \"rpms/mirrormanager2\",\n      \"id\": 10234,\n      \"milestones\": {},\n\
+        \      \"name\": \"mirrormanager2\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Patrick \\\"\\u30de\\u30eb\\u30bf\\u30a4\\u30f3\\u30a2\\u30f3\\u30c9\\\
+        u30ec\\u30a2\\u30b9\\\" Uiterwijk\",\n        \"name\": \"puiterwijk\"\n \
+        \     }\n    },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n\
+        \        \"commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [\n          \"ralph\",\n          \"lmacken\"\n        ],\n\
+        \        \"owner\": [\n          \"johnp\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501871141\",\n      \"date_modified\": \"1501871141\"\
+        ,\n      \"description\": \"The moksha rpms\",\n      \"fullname\": \"rpms/moksha\"\
+        ,\n      \"id\": 10362,\n      \"milestones\": {},\n      \"name\": \"moksha\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"johnp\",\n        \"name\": \"\
+        johnp\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"cydrobolt\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501871162\",\n      \"date_modified\": \"1501871162\"\
+        ,\n      \"description\": \"The mote rpms\",\n      \"fullname\": \"rpms/mote\"\
+        ,\n      \"id\": 10432,\n      \"milestones\": {},\n      \"name\": \"mote\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"cydrobolt\",\n        \"name\"\
+        : \"cydrobolt\"\n      }\n    },\n    {\n      \"access_groups\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n       \
+        \ ],\n        \"owner\": [\n          \"tomspur\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873791\",\n      \"date_modified\": \"\
+        1501873791\",\n      \"description\": \"The php-zmq rpms\",\n      \"fullname\"\
+        : \"rpms/php-zmq\",\n      \"id\": 16766,\n      \"milestones\": {},\n   \
+        \   \"name\": \"php-zmq\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"mstuchli\"\n     \
+        \   ],\n        \"owner\": [\n          \"cstratak\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873804\",\n      \"date_modified\": \"\
+        1501873804\",\n      \"description\": \"The pipsi rpms\",\n      \"fullname\"\
+        : \"rpms/pipsi\",\n      \"id\": 16861,\n      \"milestones\": {},\n     \
+        \ \"name\": \"pipsi\",\n      \"namespace\": \"rpms\",\n      \"parent\":\
+        \ null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501873810\",\n      \"date_modified\": \"1501873810\",\n      \"description\"\
+        : \"The pkgwat rpms\",\n      \"fullname\": \"rpms/pkgwat\",\n      \"id\"\
+        : 16877,\n      \"milestones\": {},\n      \"name\": \"pkgwat\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873821\",\n   \
+        \   \"date_modified\": \"1501873821\",\n      \"description\": \"The playitagainsam\
+        \ rpms\",\n      \"fullname\": \"rpms/playitagainsam\",\n      \"id\": 16926,\n\
+        \      \"milestones\": {},\n      \"name\": \"playitagainsam\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"pviktori\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873902\",\n      \"date_modified\": \"1501873902\",\n      \"description\"\
+        : \"The py3c rpms\",\n      \"fullname\": \"rpms/py3c\",\n      \"id\": 17268,\n\
+        \      \"milestones\": {},\n      \"name\": \"py3c\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"pviktori\",\n        \"name\": \"pviktori\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"bochecha\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873911\",\n      \"date_modified\": \"1501873911\"\
+        ,\n      \"description\": \"The pycanberra rpms\",\n      \"fullname\": \"\
+        rpms/pycanberra\",\n      \"id\": 17285,\n      \"milestones\": {},\n    \
+        \  \"name\": \"pycanberra\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bochecha\",\n        \"name\"\
+        : \"bochecha\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"mstuchli\"\n    \
+        \    ],\n        \"owner\": [\n          \"mcyprian\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873931\",\n      \"date_modified\": \"\
+        1501873931\",\n      \"description\": \"The pypy rpms\",\n      \"fullname\"\
+        : \"rpms/pypy\",\n      \"id\": 17377,\n      \"milestones\": {},\n      \"\
+        name\": \"pypy\",\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n\
+        \      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"mcyprian\",\n        \"name\"\
+        : \"mcyprian\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"mstuchli\"\n    \
+        \    ],\n        \"owner\": [\n          \"churchyard\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873931\",\n      \"date_modified\": \"\
+        1501873931\",\n      \"description\": \"The pypy3 rpms\",\n      \"fullname\"\
+        : \"rpms/pypy3\",\n      \"id\": 17378,\n      \"milestones\": {},\n     \
+        \ \"name\": \"pypy3\",\n      \"namespace\": \"rpms\",\n      \"parent\":\
+        \ null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874338\",\n      \"date_modified\": \"1501874338\",\n      \"description\"\
+        : \"The python26 rpms\",\n      \"fullname\": \"rpms/python26\",\n      \"\
+        id\": 19472,\n      \"milestones\": {},\n      \"name\": \"python26\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"lbalhar\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874333\",\n      \"date_modified\": \"1501874333\",\n      \"description\"\
+        : \"The python2-ipython rpms\",\n      \"fullname\": \"rpms/python2-ipython\"\
+        ,\n      \"id\": 19437,\n      \"milestones\": {},\n      \"name\": \"python2-ipython\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lbalhar\",\n        \"name\":\
+        \ \"lbalhar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n     \
+        \     \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874349\",\n      \"date_modified\": \"1501874349\",\n      \"description\"\
+        : \"The python33 rpms\",\n      \"fullname\": \"rpms/python33\",\n      \"\
+        id\": 19536,\n      \"milestones\": {},\n      \"name\": \"python33\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"churchyard\",\n\
+        \          \"torsava\",\n          \"kevin\",\n          \"cstratak\",\n \
+        \         \"mstuchli\",\n          \"ttorling\"\n        ],\n        \"owner\"\
+        : [\n          \"pviktori\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874349\",\n      \"date_modified\": \"1501874349\",\n      \"description\"\
+        : \"The python34 rpms\",\n      \"fullname\": \"rpms/python34\",\n      \"\
+        id\": 19537,\n      \"milestones\": {},\n      \"name\": \"python34\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"pviktori\",\n        \"name\"\
+        : \"pviktori\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"cstratak\"\n    \
+        \    ],\n        \"owner\": [\n          \"churchyard\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874349\",\n      \"date_modified\": \"\
+        1501874349\",\n      \"description\": \"The python35 rpms\",\n      \"fullname\"\
+        : \"rpms/python35\",\n      \"id\": 19538,\n      \"milestones\": {},\n  \
+        \    \"name\": \"python35\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"cstratak\"\n  \
+        \      ],\n        \"owner\": [\n          \"churchyard\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874350\",\n      \"date_modified\": \"\
+        1501874350\",\n      \"description\": \"The python36 rpms\",\n      \"fullname\"\
+        : \"rpms/python36\",\n      \"id\": 19539,\n      \"milestones\": {},\n  \
+        \    \"name\": \"python36\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n      \
+        \  ],\n        \"owner\": [\n          \"johnp\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874339\",\n      \"date_modified\": \"1501874339\"\
+        ,\n      \"description\": \"The python3-cairo rpms\",\n      \"fullname\"\
+        : \"rpms/python3-cairo\",\n      \"id\": 19476,\n      \"milestones\": {},\n\
+        \      \"name\": \"python3-cairo\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"johnp\",\n        \"name\": \"johnp\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"churchyard\"\n        ],\n        \"owner\": [\n          \"torsava\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874340\",\n   \
+        \   \"date_modified\": \"1501874340\",\n      \"description\": \"The python3-cherrypy\
+        \ rpms\",\n      \"fullname\": \"rpms/python3-cherrypy\",\n      \"id\": 19480,\n\
+        \      \"milestones\": {},\n      \"name\": \"python3-cherrypy\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"torsava\",\n        \"name\":\
+        \ \"torsava\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"abompard\",\n          \"ttorling\"\n        ],\n       \
+        \ \"owner\": [\n          \"orion\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874340\",\n      \"date_modified\": \"1501874340\"\
+        ,\n      \"description\": \"The python3-coverage rpms\",\n      \"fullname\"\
+        : \"rpms/python3-coverage\",\n      \"id\": 19482,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python3-coverage\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"bkabrda\",\n          \"mstuchli\",\n          \"rkuska\"\n        ],\n\
+        \        \"owner\": [\n          \"pviktori\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874343\",\n      \"date_modified\": \"1501874343\"\
+        ,\n      \"description\": \"The python3-pkgversion-macros rpms\",\n      \"\
+        fullname\": \"rpms/python3-pkgversion-macros\",\n      \"id\": 19503,\n  \
+        \    \"milestones\": {},\n      \"name\": \"python3-pkgversion-macros\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"pviktori\",\n        \"name\"\
+        : \"pviktori\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"thm\",\n        \
+        \  \"ttorling\"\n        ],\n        \"owner\": [\n          \"orion\"\n \
+        \       ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874344\",\n   \
+        \   \"date_modified\": \"1501874344\",\n      \"description\": \"The python3-py\
+        \ rpms\",\n      \"fullname\": \"rpms/python3-py\",\n      \"id\": 19509,\n\
+        \      \"milestones\": {},\n      \"name\": \"python3-py\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874344\",\n      \"date_modified\": \"1501874344\"\
+        ,\n      \"description\": \"The python3-py3dns rpms\",\n      \"fullname\"\
+        : \"rpms/python3-py3dns\",\n      \"id\": 19510,\n      \"milestones\": {},\n\
+        \      \"name\": \"python3-py3dns\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"pviktori\",\n          \"ttorling\",\n          \"thm\"\n   \
+        \     ],\n        \"owner\": [\n          \"orion\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874345\",\n      \"date_modified\": \"\
+        1501874346\",\n      \"description\": \"The python3-pytest rpms\",\n     \
+        \ \"fullname\": \"rpms/python3-pytest\",\n      \"id\": 19517,\n      \"milestones\"\
+        : {},\n      \"name\": \"python3-pytest\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"pviktori\",\n          \"ttorling\"\n        ],\n        \"owner\":\
+        \ [\n          \"orion\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874346\",\n      \"date_modified\": \"1501874346\",\n      \"description\"\
+        : \"The python3-setuptools rpms\",\n      \"fullname\": \"rpms/python3-setuptools\"\
+        ,\n      \"id\": 19523,\n      \"milestones\": {},\n      \"name\": \"python3-setuptools\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orion\",\n        \"name\": \"\
+        orion\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\":\
+        \ []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874347\",\n      \"date_modified\": \"1501874347\"\
+        ,\n      \"description\": \"The python3-zope-event rpms\",\n      \"fullname\"\
+        : \"rpms/python3-zope-event\",\n      \"id\": 19532,\n      \"milestones\"\
+        : {},\n      \"name\": \"python3-zope-event\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874347\",\n      \"date_modified\": \"1501874347\"\
+        ,\n      \"description\": \"The python3-zope-fixers rpms\",\n      \"fullname\"\
+        : \"rpms/python3-zope-fixers\",\n      \"id\": 19533,\n      \"milestones\"\
+        : {},\n      \"name\": \"python3-zope-fixers\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"abompard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874347\",\n   \
+        \   \"date_modified\": \"1501874347\",\n      \"description\": \"The python3-zope-interface\
+        \ rpms\",\n      \"fullname\": \"rpms/python3-zope-interface\",\n      \"\
+        id\": 19534,\n      \"milestones\": {},\n      \"name\": \"python3-zope-interface\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873954\",\n      \"date_modified\": \"1501873954\",\n      \"description\"\
+        : \"The python-admesh rpms\",\n      \"fullname\": \"rpms/python-admesh\"\
+        ,\n      \"id\": 17501,\n      \"milestones\": {},\n      \"name\": \"python-admesh\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n  \
+        \    },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873956\",\n      \"date_modified\": \"\
+        1501873956\",\n      \"description\": \"The python-aiosmtpd rpms\",\n    \
+        \  \"fullname\": \"rpms/python-aiosmtpd\",\n      \"id\": 17511,\n      \"\
+        milestones\": {},\n      \"name\": \"python-aiosmtpd\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873956\",\n      \"date_modified\": \"1501873956\"\
+        ,\n      \"description\": \"The python-alembic rpms\",\n      \"fullname\"\
+        : \"rpms/python-alembic\",\n      \"id\": 17514,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-alembic\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873960\",\n      \"date_modified\": \"1501873960\"\
+        ,\n      \"description\": \"The python-anykeystore rpms\",\n      \"fullname\"\
+        : \"rpms/python-anykeystore\",\n      \"id\": 17531,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-anykeystore\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873961\",\n      \"date_modified\": \"1501873961\"\
+        ,\n      \"description\": \"The python-appstream rpms\",\n      \"fullname\"\
+        : \"rpms/python-appstream\",\n      \"id\": 17539,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-appstream\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"pingou\"\n        ],\n        \"owner\": [\n          \"ralph\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873963\",\n   \
+        \   \"date_modified\": \"1501873963\",\n      \"description\": \"The python-arrow\
+        \ rpms\",\n      \"fullname\": \"rpms/python-arrow\",\n      \"id\": 17547,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-arrow\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"orphan\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873964\",\n   \
+        \   \"date_modified\": \"1501873964\",\n      \"description\": \"The python-askbot-fedmsg\
+        \ rpms\",\n      \"fullname\": \"rpms/python-askbot-fedmsg\",\n      \"id\"\
+        : 17551,\n      \"milestones\": {},\n      \"name\": \"python-askbot-fedmsg\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orphan\",\n        \"name\": \"\
+        orphan\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\":\
+        \ []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873966\",\n      \"date_modified\": \"1501873966\"\
+        ,\n      \"description\": \"The python-atpublic rpms\",\n      \"fullname\"\
+        : \"rpms/python-atpublic\",\n      \"id\": 17570,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-atpublic\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873970\",\n   \
+        \   \"date_modified\": \"1501873970\",\n      \"description\": \"The python-backlash\
+        \ rpms\",\n      \"fullname\": \"rpms/python-backlash\",\n      \"id\": 17581,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-backlash\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ianweller\"\n     \
+        \   ],\n        \"owner\": [\n          \"ralph\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873971\",\n      \"date_modified\": \"\
+        1501873971\",\n      \"description\": \"The python-backports-lzma rpms\",\n\
+        \      \"fullname\": \"rpms/python-backports-lzma\",\n      \"id\": 17585,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-backports-lzma\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ianweller\"\n        ],\n      \
+        \  \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501873971\",\n      \"date_modified\": \"1501873971\"\
+        ,\n      \"description\": \"The python-backports-ssl_match_hostname rpms\"\
+        ,\n      \"fullname\": \"rpms/python-backports-ssl_match_hostname\",\n   \
+        \   \"id\": 17588,\n      \"milestones\": {},\n      \"name\": \"python-backports-ssl_match_hostname\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873978\",\n      \"date_modified\": \"1501873978\"\
+        ,\n      \"description\": \"The python-blessed rpms\",\n      \"fullname\"\
+        : \"rpms/python-blessed\",\n      \"id\": 17620,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-blessed\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873981\",\n      \"date_modified\": \"1501873981\"\
+        ,\n      \"description\": \"The python-blurb rpms\",\n      \"fullname\":\
+        \ \"rpms/python-blurb\",\n      \"id\": 17630,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-blurb\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"cicku\"\n        ],\n        \"owner\": [\n          \"cstratak\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873981\",\n   \
+        \   \"date_modified\": \"1501873981\",\n      \"description\": \"The python-bna\
+        \ rpms\",\n      \"fullname\": \"rpms/python-bna\",\n      \"id\": 17631,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-bna\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Charalampos Stratakis\",\n        \"name\": \"cstratak\"\n      }\n  \
+        \  },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n       \
+        \ \"commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\":\
+        \ []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873984\",\n      \"date_modified\": \"\
+        1501873984\",\n      \"description\": \"The python-bugzilla2fedmsg rpms\"\
+        ,\n      \"fullname\": \"rpms/python-bugzilla2fedmsg\",\n      \"id\": 17642,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-bugzilla2fedmsg\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"pingou\"\n        ],\n        \"\
+        owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n    \
+        \  },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873992\",\n      \"date_modified\": \"1501873992\",\n      \"description\"\
+        : \"The python-chai rpms\",\n      \"fullname\": \"rpms/python-chai\",\n \
+        \     \"id\": 17678,\n      \"milestones\": {},\n      \"name\": \"python-chai\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\",\n          \"lmacken\"\n\
+        \        ],\n        \"owner\": [\n          \"tdabasin\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873992\",\n      \"date_modified\": \"\
+        1501873993\",\n      \"description\": \"The python-chameleon rpms\",\n   \
+        \   \"fullname\": \"rpms/python-chameleon\",\n      \"id\": 17679,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-chameleon\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"tdabasin\",\n        \"name\": \"tdabasin\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"dcallagh\",\n          \"lmacken\",\n          \"mbacovsk\"\n\
+        \        ],\n        \"owner\": [\n          \"fschwarz\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873994\",\n      \"date_modified\": \"\
+        1501873994\",\n      \"description\": \"The python-cherrypy2 rpms\",\n   \
+        \   \"fullname\": \"rpms/python-cherrypy2\",\n      \"id\": 17684,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-cherrypy2\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"fschwarz\",\n        \"name\": \"fschwarz\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"torsava\"\n        ],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501875664\",\n   \
+        \   \"date_modified\": \"1501875664\",\n      \"description\": \"The python-classroom\
+        \ container\",\n      \"fullname\": \"container/python-classroom\",\n    \
+        \  \"id\": 24026,\n      \"milestones\": {},\n      \"name\": \"python-classroom\"\
+        ,\n      \"namespace\": \"container\",\n      \"parent\": null,\n      \"\
+        priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"mstuchli\",\n \
+        \         \"cstratak\",\n          \"fab\"\n        ],\n        \"owner\"\
+        : [\n          \"rkuska\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873996\",\n      \"date_modified\": \"1501873997\",\n      \"description\"\
+        : \"The python-click rpms\",\n      \"fullname\": \"rpms/python-click\",\n\
+        \      \"id\": 17694,\n      \"milestones\": {},\n      \"name\": \"python-click\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"rkuska\",\n        \"name\": \"\
+        rkuska\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"apevec\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501873997\",\n   \
+        \   \"date_modified\": \"1501873997\",\n      \"description\": \"The python-cliff\
+        \ rpms\",\n      \"fullname\": \"rpms/python-cliff\",\n      \"id\": 17697,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-cliff\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"apevec\",\n        \"name\": \"apevec\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873997\",\n      \"date_modified\": \"1501873997\"\
+        ,\n      \"description\": \"The python-cligj rpms\",\n      \"fullname\":\
+        \ \"rpms/python-cligj\",\n      \"id\": 17698,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-cligj\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501873997\",\n      \"date_modified\": \"1501873998\"\
+        ,\n      \"description\": \"The python-cloud-sptheme rpms\",\n      \"fullname\"\
+        : \"rpms/python-cloud-sptheme\",\n      \"id\": 17700,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-cloud-sptheme\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"apevec\"\n        ],\n        \"owner\"\
+        : [\n          \"mmagr\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873999\",\n      \"date_modified\": \"1501873999\",\n      \"description\"\
+        : \"The python-cmd2 rpms\",\n      \"fullname\": \"rpms/python-cmd2\",\n \
+        \     \"id\": 17707,\n      \"milestones\": {},\n      \"name\": \"python-cmd2\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"mmagr\",\n        \"name\": \"\
+        mmagr\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\",\n          \"lmacken\"\n\
+        \        ],\n        \"owner\": [\n          \"ignatenkobrain\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501873999\",\n      \"date_modified\": \"\
+        1501873999\",\n      \"description\": \"The python-colander rpms\",\n    \
+        \  \"fullname\": \"rpms/python-colander\",\n      \"id\": 17711,\n      \"\
+        milestones\": {},\n      \"name\": \"python-colander\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Igor Gnatenko\",\n        \"name\": \"ignatenkobrain\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"pingou\",\n       \
+        \   \"tjikkun\",\n          \"abompard\"\n        ],\n        \"owner\": [\n\
+        \          \"ralph\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874003\",\n      \"date_modified\": \"1501874003\",\n      \"description\"\
+        : \"The python-contextlib2 rpms\",\n      \"fullname\": \"rpms/python-contextlib2\"\
+        ,\n      \"id\": 17729,\n      \"milestones\": {},\n      \"name\": \"python-contextlib2\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\",\n          \"\
+        python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"access_users\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"bowlofeggs\"\
+        ,\n          \"lmacken\"\n        ],\n        \"owner\": [\n          \"hguemar\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874004\",\n   \
+        \   \"date_modified\": \"1501874005\",\n      \"description\": \"The python-cornice\
+        \ rpms\",\n      \"fullname\": \"rpms/python-cornice\",\n      \"id\": 17733,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-cornice\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"hguemar\",\n        \"name\":\
+        \ \"hguemar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"abompard\"\n        ],\n        \"owner\": [\n          \"\
+        bkabrda\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874006\"\
+        ,\n      \"date_modified\": \"1501874006\",\n      \"description\": \"The\
+        \ python-cov-core rpms\",\n      \"fullname\": \"rpms/python-cov-core\",\n\
+        \      \"id\": 17737,\n      \"milestones\": {},\n      \"name\": \"python-cov-core\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bkabrda\",\n        \"name\":\
+        \ \"bkabrda\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"mrunge\",\n          \"abompard\",\n          \"lmacken\"\
+        \n        ],\n        \"owner\": [\n          \"spot\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874006\",\n      \"date_modified\": \"\
+        1501874006\",\n      \"description\": \"The python-coverage rpms\",\n    \
+        \  \"fullname\": \"rpms/python-coverage\",\n      \"id\": 17739,\n      \"\
+        milestones\": {},\n      \"name\": \"python-coverage\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"spot\",\n        \"name\": \"spot\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874006\",\n      \"date_modified\": \"1501874006\"\
+        ,\n      \"description\": \"The python-coverage_pth rpms\",\n      \"fullname\"\
+        : \"rpms/python-coverage_pth\",\n      \"id\": 17740,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-coverage_pth\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874009\",\n   \
+        \   \"date_modified\": \"1501874009\",\n      \"description\": \"The python-crank\
+        \ rpms\",\n      \"fullname\": \"rpms/python-crank\",\n      \"id\": 17748,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-crank\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"kevin\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874009\",\n      \"date_modified\": \"1501874009\"\
+        ,\n      \"description\": \"The python-crypto2.6 rpms\",\n      \"fullname\"\
+        : \"rpms/python-crypto2.6\",\n      \"id\": 17753,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-crypto2.6\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Kevin Fenzi\",\n        \"name\": \"kevin\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"brouhaha\",\n          \"kevin\",\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"echevemaster\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874011\",\n      \"date_modified\": \"\
+        1501874012\",\n      \"description\": \"The python-cssselect rpms\",\n   \
+        \   \"fullname\": \"rpms/python-cssselect\",\n      \"id\": 17758,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-cssselect\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"echevemaster\",\n        \"name\": \"echevemaster\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"lmacken\",\n          \"tomspur\"\n   \
+        \     ],\n        \"owner\": [\n          \"kushal\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874014\",\n      \"date_modified\": \"\
+        1501874014\",\n      \"description\": \"The python-daemon rpms\",\n      \"\
+        fullname\": \"rpms/python-daemon\",\n      \"id\": 17777,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-daemon\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"kushal\",\n        \"name\": \"kushal\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874014\",\n      \"date_modified\": \"1501874014\"\
+        ,\n      \"description\": \"The python-datanommer-consumer rpms\",\n     \
+        \ \"fullname\": \"rpms/python-datanommer-consumer\",\n      \"id\": 17781,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-datanommer-consumer\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874015\",\n   \
+        \   \"date_modified\": \"1501874015\",\n      \"description\": \"The python-datanommer-models\
+        \ rpms\",\n      \"fullname\": \"rpms/python-datanommer-models\",\n      \"\
+        id\": 17782,\n      \"milestones\": {},\n      \"name\": \"python-datanommer-models\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"limb\",\n          \"tomspur\",\n\
+        \          \"pjp\",\n          \"jspaleta\"\n        ],\n        \"owner\"\
+        : [\n          \"hguemar\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874015\",\n      \"date_modified\": \"1501874015\",\n      \"description\"\
+        : \"The python-dateutil rpms\",\n      \"fullname\": \"rpms/python-dateutil\"\
+        ,\n      \"id\": 17783,\n      \"milestones\": {},\n      \"name\": \"python-dateutil\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"hguemar\",\n        \"name\":\
+        \ \"hguemar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"ignatenkobrain\",\n          \"abompard\"\n        ],\n \
+        \       \"owner\": [\n          \"carlwgeorge\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874016\",\n      \"date_modified\": \"1501874016\"\
+        ,\n      \"description\": \"The python-ddt rpms\",\n      \"fullname\": \"\
+        rpms/python-ddt\",\n      \"id\": 17789,\n      \"milestones\": {},\n    \
+        \  \"name\": \"python-ddt\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Carl George\",\n        \"name\"\
+        : \"carlwgeorge\"\n      }\n    },\n    {\n      \"access_groups\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"fale\"\n      \
+        \  ],\n        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874017\",\n      \"date_modified\": \"1501874017\"\
+        ,\n      \"description\": \"The python-decorator rpms\",\n      \"fullname\"\
+        : \"rpms/python-decorator\",\n      \"id\": 17794,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-decorator\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"bkabrda\"\n        ],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874017\",\n   \
+        \   \"date_modified\": \"1501874018\",\n      \"description\": \"The python-defusedxml\
+        \ rpms\",\n      \"fullname\": \"rpms/python-defusedxml\",\n      \"id\":\
+        \ 17798,\n      \"milestones\": {},\n      \"name\": \"python-defusedxml\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"mstuchli\"\n  \
+        \      ],\n        \"owner\": [\n          \"cstratak\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874023\",\n      \"date_modified\": \"\
+        1501874024\",\n      \"description\": \"The python-distlib rpms\",\n     \
+        \ \"fullname\": \"rpms/python-distlib\",\n      \"id\": 17813,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-distlib\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Charalampos Stratakis\",\n        \"name\": \"cstratak\"\n      }\n  \
+        \  },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n       \
+        \ \"commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\":\
+        \ []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [\n          \"ralph\"\n        ],\n        \"owner\": [\n\
+        \          \"orphan\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874029\",\n      \"date_modified\": \"1501874029\",\n      \"description\"\
+        : \"The python-django-longerusername rpms\",\n      \"fullname\": \"rpms/python-django-longerusername\"\
+        ,\n      \"id\": 17860,\n      \"milestones\": {},\n      \"name\": \"python-django-longerusername\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orphan\",\n        \"name\": \"\
+        orphan\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mrunge\",\n          \"yuwang\"\n\
+        \        ],\n        \"owner\": [\n          \"ralph\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874039\",\n      \"date_modified\": \"\
+        1501874039\",\n      \"description\": \"The python-django-tinymce rpms\",\n\
+        \      \"fullname\": \"rpms/python-django-tinymce\",\n      \"id\": 17910,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-django-tinymce\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"oddshocks\"\n        ],\n      \
+        \  \"owner\": [\n          \"mstuchli\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874045\",\n      \"date_modified\": \"1501874045\"\
+        ,\n      \"description\": \"The python-docutils rpms\",\n      \"fullname\"\
+        : \"rpms/python-docutils\",\n      \"id\": 17930,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-docutils\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"mstuchli\",\n        \"name\": \"mstuchli\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"bowlofeggs\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874046\",\n   \
+        \   \"date_modified\": \"1501874046\",\n      \"description\": \"The python-dogpile-cache\
+        \ rpms\",\n      \"fullname\": \"rpms/python-dogpile-cache\",\n      \"id\"\
+        : 17932,\n      \"milestones\": {},\n      \"name\": \"python-dogpile-cache\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bowlofeggs\",\n        \"name\"\
+        : \"bowlofeggs\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n      \
+        \  ],\n        \"owner\": [\n          \"bowlofeggs\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874046\",\n      \"date_modified\": \"\
+        1501874046\",\n      \"description\": \"The python-dogpile-core rpms\",\n\
+        \      \"fullname\": \"rpms/python-dogpile-core\",\n      \"id\": 17933,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-dogpile-core\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bowlofeggs\",\n        \"name\"\
+        : \"bowlofeggs\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874046\",\n      \"date_modified\": \"1501874047\",\n      \"description\"\
+        : \"The python-dropbox rpms\",\n      \"fullname\": \"rpms/python-dropbox\"\
+        ,\n      \"id\": 17941,\n      \"milestones\": {},\n      \"name\": \"python-dropbox\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"apevec\",\n    \
+        \      \"social\"\n        ],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874047\",\n   \
+        \   \"date_modified\": \"1501874048\",\n      \"description\": \"The python-editor\
+        \ rpms\",\n      \"fullname\": \"rpms/python-editor\",\n      \"id\": 17950,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-editor\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"galt\",\n          \"cstratak\",\n          \"dsommers\"\n  \
+        \      ],\n        \"owner\": [\n          \"acme\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874051\",\n      \"date_modified\": \"\
+        1501874051\",\n      \"description\": \"The python-ethtool rpms\",\n     \
+        \ \"fullname\": \"rpms/python-ethtool\",\n      \"id\": 17971,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-ethtool\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"acme\",\n        \"name\": \"acme\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n    \
+        \    \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"abompard\",\n          \"carlwgeorge\"\
+        \n        ],\n        \"owner\": [\n          \"jamielennox\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874053\",\n      \"date_modified\": \"\
+        1501874053\",\n      \"description\": \"The python-falcon rpms\",\n      \"\
+        fullname\": \"rpms/python-falcon\",\n      \"id\": 17984,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-falcon\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"jamielennox\",\n        \"name\": \"jamielennox\"\n      }\n    },\n \
+        \   {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874055\",\n      \"date_modified\": \"1501874055\"\
+        ,\n      \"description\": \"The python-fedbadges rpms\",\n      \"fullname\"\
+        : \"rpms/python-fedbadges\",\n      \"id\": 17990,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-fedbadges\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"kevin\",\n          \"oddshocks\",\n          \"ralph\"\n   \
+        \     ],\n        \"owner\": [\n          \"sayanchowdhury\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874055\",\n      \"date_modified\": \"\
+        1501874055\",\n      \"description\": \"The python-fedimg rpms\",\n      \"\
+        fullname\": \"rpms/python-fedimg\",\n      \"id\": 17991,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-fedimg\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sayanchowdhury\",\n        \"name\": \"sayanchowdhury\"\n      }\n   \
+        \ },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"\
+        commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"bowlofeggs\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874055\",\n      \"date_modified\": \"\
+        1501874055\",\n      \"description\": \"The python-fedmsg-atomic-composer\
+        \ rpms\",\n      \"fullname\": \"rpms/python-fedmsg-atomic-composer\",\n \
+        \     \"id\": 17992,\n      \"milestones\": {},\n      \"name\": \"python-fedmsg-atomic-composer\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bowlofeggs\",\n        \"name\"\
+        : \"bowlofeggs\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n   \
+        \       \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874055\",\n      \"date_modified\": \"1501874055\",\n      \"description\"\
+        : \"The python-fedmsg-genacls rpms\",\n      \"fullname\": \"rpms/python-fedmsg-genacls\"\
+        ,\n      \"id\": 17993,\n      \"milestones\": {},\n      \"name\": \"python-fedmsg-genacls\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ianweller\"\n        ],\n      \
+        \  \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874055\",\n      \"date_modified\": \"1501874055\"\
+        ,\n      \"description\": \"The python-fedmsg-meta-debian rpms\",\n      \"\
+        fullname\": \"rpms/python-fedmsg-meta-debian\",\n      \"id\": 17994,\n  \
+        \    \"milestones\": {},\n      \"name\": \"python-fedmsg-meta-debian\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"sayanchowdhury\",\n          \"\
+        ianweller\",\n          \"lmacken\"\n        ],\n        \"owner\": [\n  \
+        \        \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874055\",\n      \"date_modified\": \"1501874056\",\n      \"description\"\
+        : \"The python-fedmsg-meta-fedora-infrastructure rpms\",\n      \"fullname\"\
+        : \"rpms/python-fedmsg-meta-fedora-infrastructure\",\n      \"id\": 17995,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-fedmsg-meta-fedora-infrastructure\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"codeblock\",\n          \"ricky\"\
+        ,\n          \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"\
+        lmacken\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874056\"\
+        ,\n      \"date_modified\": \"1501874056\",\n      \"description\": \"The\
+        \ python-fedora rpms\",\n      \"fullname\": \"rpms/python-fedora\",\n   \
+        \   \"id\": 17997,\n      \"milestones\": {},\n      \"name\": \"python-fedora\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"mstuchli\",\n     \
+        \     \"pingou\",\n          \"pviktori\"\n        ],\n        \"owner\":\
+        \ [\n          \"puiterwijk\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874058\",\n      \"date_modified\": \"1501874059\",\n      \"description\"\
+        : \"The python-flask-admin rpms\",\n      \"fullname\": \"rpms/python-flask-admin\"\
+        ,\n      \"id\": 18009,\n      \"milestones\": {},\n      \"name\": \"python-flask-admin\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Patrick \\\"\\u30de\\u30eb\\u30bf\\\
+        u30a4\\u30f3\\u30a2\\u30f3\\u30c9\\u30ec\\u30a2\\u30b9\\\" Uiterwijk\",\n\
+        \        \"name\": \"puiterwijk\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874060\",\n      \"date_modified\": \"1501874060\",\n      \"description\"\
+        : \"The python-flask-mako rpms\",\n      \"fullname\": \"rpms/python-flask-mako\"\
+        ,\n      \"id\": 18021,\n      \"milestones\": {},\n      \"name\": \"python-flask-mako\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874066\",\n      \"date_modified\": \"1501874066\"\
+        ,\n      \"description\": \"The python-flufl-bounce rpms\",\n      \"fullname\"\
+        : \"rpms/python-flufl-bounce\",\n      \"id\": 18048,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-flufl-bounce\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"abompard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874067\",\n   \
+        \   \"date_modified\": \"1501874067\",\n      \"description\": \"The python-flufl-i18n\
+        \ rpms\",\n      \"fullname\": \"rpms/python-flufl-i18n\",\n      \"id\":\
+        \ 18049,\n      \"milestones\": {},\n      \"name\": \"python-flufl-i18n\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n    \
+        \  },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874067\",\n      \"date_modified\": \"\
+        1501874067\",\n      \"description\": \"The python-flufl-lock rpms\",\n  \
+        \    \"fullname\": \"rpms/python-flufl-lock\",\n      \"id\": 18050,\n   \
+        \   \"milestones\": {},\n      \"name\": \"python-flufl-lock\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n    \
+        \  },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874067\",\n      \"date_modified\": \"\
+        1501874067\",\n      \"description\": \"The python-flufl-testing rpms\",\n\
+        \      \"fullname\": \"rpms/python-flufl-testing\",\n      \"id\": 18051,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-flufl-testing\",\n  \
+        \    \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"sayanchowdhury\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874068\",\n      \"date_modified\": \"\
+        1501874068\",\n      \"description\": \"The python-fmn-consumer rpms\",\n\
+        \      \"fullname\": \"rpms/python-fmn-consumer\",\n      \"id\": 18054,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-fmn-consumer\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"sayanchowdhury\",\n        \"\
+        name\": \"sayanchowdhury\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"sayanchowdhury\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874068\",\n      \"date_modified\": \"\
+        1501874068\",\n      \"description\": \"The python-fmn-lib rpms\",\n     \
+        \ \"fullname\": \"rpms/python-fmn-lib\",\n      \"id\": 18055,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-fmn-lib\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sayanchowdhury\",\n        \"name\": \"sayanchowdhury\"\n      }\n   \
+        \ },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"\
+        commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"ralph\"\n        ],\n        \"owner\": [\n          \"sayanchowdhury\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874068\",\n   \
+        \   \"date_modified\": \"1501874068\",\n      \"description\": \"The python-fmn-rules\
+        \ rpms\",\n      \"fullname\": \"rpms/python-fmn-rules\",\n      \"id\": 18056,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-fmn-rules\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"sayanchowdhury\",\n        \"\
+        name\": \"sayanchowdhury\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"sayanchowdhury\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874069\",\n      \"date_modified\": \"\
+        1501874069\",\n      \"description\": \"The python-fmn-web rpms\",\n     \
+        \ \"fullname\": \"rpms/python-fmn-web\",\n      \"id\": 18058,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-fmn-web\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sayanchowdhury\",\n        \"name\": \"sayanchowdhury\"\n      }\n   \
+        \ },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"\
+        commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"ralph\",\n          \"lmacken\"\n        ],\n        \"owner\"\
+        : [\n          \"kylev\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874070\",\n      \"date_modified\": \"1501874070\",\n      \"description\"\
+        : \"The python-formencode rpms\",\n      \"fullname\": \"rpms/python-formencode\"\
+        ,\n      \"id\": 18065,\n      \"milestones\": {},\n      \"name\": \"python-formencode\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"kylev\",\n        \"name\": \"\
+        kylev\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874071\",\n   \
+        \   \"date_modified\": \"1501874071\",\n      \"description\": \"The python-freezegun\
+        \ rpms\",\n      \"fullname\": \"rpms/python-freezegun\",\n      \"id\": 18071,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-freezegun\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874074\",\n      \"date_modified\": \"1501874074\",\n\
+        \      \"description\": \"The python-gearbox rpms\",\n      \"fullname\":\
+        \ \"rpms/python-gearbox\",\n      \"id\": 18096,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-gearbox\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"pingou\"\n        ],\n        \"owner\"\
+        : [\n          \"sergiomb\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873940\",\n      \"date_modified\": \"1501873940\",\n      \"description\"\
+        : \"The python-GeoIP rpms\",\n      \"fullname\": \"rpms/python-GeoIP\",\n\
+        \      \"id\": 17421,\n      \"milestones\": {},\n      \"name\": \"python-GeoIP\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"S\\u00e9rgio Monteiro Basto\"\
+        ,\n        \"name\": \"sergiomb\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"orion\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874077\",\n      \"date_modified\": \"1501874077\",\n      \"description\"\
+        : \"The python-gflags rpms\",\n      \"fullname\": \"rpms/python-gflags\"\
+        ,\n      \"id\": 18115,\n      \"milestones\": {},\n      \"name\": \"python-gflags\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orion\",\n        \"name\": \"\
+        orion\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"jspaleta\",\n          \"dchen\",\n          \"abompard\",\n       \
+        \   \"kevin\"\n        ],\n        \"owner\": [\n          \"awjb\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n \
+        \     \"custom_keys\": [],\n      \"date_created\": \"1501874090\",\n    \
+        \  \"date_modified\": \"1501874090\",\n      \"description\": \"The python-httplib2\
+        \ rpms\",\n      \"fullname\": \"rpms/python-httplib2\",\n      \"id\": 18174,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-httplib2\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"awjb\",\n        \"name\": \"\
+        awjb\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"bkabrda\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874088\",\n      \"date_modified\": \"1501874088\",\n\
+        \      \"description\": \"The python-http-parser rpms\",\n      \"fullname\"\
+        : \"rpms/python-http-parser\",\n      \"id\": 18172,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-http-parser\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"bkabrda\",\n        \"name\": \"bkabrda\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"kevin\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874091\",\n      \"date_modified\": \"1501874091\"\
+        ,\n      \"description\": \"The python-hupper rpms\",\n      \"fullname\"\
+        : \"rpms/python-hupper\",\n      \"id\": 18180,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-hupper\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Kevin Fenzi\",\n        \"name\": \"kevin\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"cstratak\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874094\",\n      \"date_modified\": \"1501874094\"\
+        ,\n      \"description\": \"The python-inifile rpms\",\n      \"fullname\"\
+        : \"rpms/python-inifile\",\n      \"id\": 18201,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-inifile\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Charalampos Stratakis\",\n        \"name\": \"cstratak\"\n      }\n  \
+        \  },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n       \
+        \ \"commit\": [\n          \"python-sig\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [\n          \"lupinix\"\n        ],\n        \"owner\": [\n\
+        \          \"ignatenkobrain\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874094\",\n      \"date_modified\": \"1501874094\",\n      \"description\"\
+        : \"The python-iniparse rpms\",\n      \"fullname\": \"rpms/python-iniparse\"\
+        ,\n      \"id\": 18202,\n      \"milestones\": {},\n      \"name\": \"python-iniparse\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Igor Gnatenko\",\n        \"name\"\
+        : \"ignatenkobrain\"\n      }\n    },\n    {\n      \"access_groups\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"churchyard\"\n\
+        \        ],\n        \"owner\": [\n          \"pcpa\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874097\",\n      \"date_modified\": \"\
+        1501874097\",\n      \"description\": \"The python-ipykernel rpms\",\n   \
+        \   \"fullname\": \"rpms/python-ipykernel\",\n      \"id\": 18216,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-ipykernel\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"pcpa\",\n        \"name\": \"pcpa\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"churchyard\"\n        ],\n        \"owner\": [\n          \"tomspur\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874104\",\n   \
+        \   \"date_modified\": \"1501874104\",\n      \"description\": \"The python-jupyter-client\
+        \ rpms\",\n      \"fullname\": \"rpms/python-jupyter-client\",\n      \"id\"\
+        : 18262,\n      \"milestones\": {},\n      \"name\": \"python-jupyter-client\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"orion\",\n       \
+        \   \"churchyard\"\n        ],\n        \"owner\": [\n          \"tomspur\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874104\",\n   \
+        \   \"date_modified\": \"1501874105\",\n      \"description\": \"The python-jupyter-core\
+        \ rpms\",\n      \"fullname\": \"rpms/python-jupyter-core\",\n      \"id\"\
+        : 18263,\n      \"milestones\": {},\n      \"name\": \"python-jupyter-core\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874105\"\
+        ,\n      \"date_modified\": \"1501874105\",\n      \"description\": \"The\
+        \ python-jwt rpms\",\n      \"fullname\": \"rpms/python-jwt\",\n      \"id\"\
+        : 18268,\n      \"milestones\": {},\n      \"name\": \"python-jwt\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874106\",\n   \
+        \   \"date_modified\": \"1501874106\",\n      \"description\": \"The python-kajiki\
+        \ rpms\",\n      \"fullname\": \"rpms/python-kajiki\",\n      \"id\": 18275,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-kajiki\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"pingou\"\n        ],\n        \"owner\": [\n          \"ralph\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874110\",\n   \
+        \   \"date_modified\": \"1501874111\",\n      \"description\": \"The python-kitchen\
+        \ rpms\",\n      \"fullname\": \"rpms/python-kitchen\",\n      \"id\": 18289,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-kitchen\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"abompard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874112\",\n      \"date_modified\": \"1501874112\"\
+        ,\n      \"description\": \"The python-lazr-config rpms\",\n      \"fullname\"\
+        : \"rpms/python-lazr-config\",\n      \"id\": 18302,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-lazr-config\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"abompard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874112\",\n   \
+        \   \"date_modified\": \"1501874112\",\n      \"description\": \"The python-lazr-delegates\
+        \ rpms\",\n      \"fullname\": \"rpms/python-lazr-delegates\",\n      \"id\"\
+        : 18303,\n      \"milestones\": {},\n      \"name\": \"python-lazr-delegates\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n    \
+        \  },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874112\",\n      \"date_modified\": \"\
+        1501874112\",\n      \"description\": \"The python-lazr-smtptest rpms\",\n\
+        \      \"fullname\": \"rpms/python-lazr-smtptest\",\n      \"id\": 18304,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-lazr-smtptest\",\n  \
+        \    \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"cstratak\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501873941\",\n      \"date_modified\": \"1501873941\",\n      \"description\"\
+        : \"The python-Lektor rpms\",\n      \"fullname\": \"rpms/python-Lektor\"\
+        ,\n      \"id\": 17427,\n      \"milestones\": {},\n      \"name\": \"python-Lektor\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874123\",\n      \"date_modified\": \"1501874123\",\n      \"description\"\
+        : \"The python-logutils rpms\",\n      \"fullname\": \"rpms/python-logutils\"\
+        ,\n      \"id\": 18354,\n      \"milestones\": {},\n      \"name\": \"python-logutils\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874124\",\n   \
+        \   \"date_modified\": \"1501874124\",\n      \"description\": \"The python-m2ext\
+        \ rpms\",\n      \"fullname\": \"rpms/python-m2ext\",\n      \"id\": 18362,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-m2ext\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mcepl\",\n          \"lmacken\"\
+        ,\n          \"bowlofeggs\",\n          \"abompard\"\n        ],\n       \
+        \ \"owner\": [\n          \"kylev\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874125\",\n      \"date_modified\": \"1501874126\"\
+        ,\n      \"description\": \"The python-mako rpms\",\n      \"fullname\": \"\
+        rpms/python-mako\",\n      \"id\": 18366,\n      \"milestones\": {},\n   \
+        \   \"name\": \"python-mako\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"kylev\",\n        \"name\": \"\
+        kylev\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"lmacken\",\n          \"oddshocks\"\
+        ,\n          \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"\
+        orphan\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874126\"\
+        ,\n      \"date_modified\": \"1501874126\",\n      \"description\": \"The\
+        \ python-mako0.4 rpms\",\n      \"fullname\": \"rpms/python-mako0.4\",\n \
+        \     \"id\": 18367,\n      \"milestones\": {},\n      \"name\": \"python-mako0.4\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orphan\",\n        \"name\": \"\
+        orphan\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"jjames\"\n        ],\n        \"\
+        owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n    \
+        \  },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874127\",\n      \"date_modified\": \"1501874127\",\n      \"description\"\
+        : \"The python-manuel rpms\",\n      \"fullname\": \"rpms/python-manuel\"\
+        ,\n      \"id\": 18371,\n      \"milestones\": {},\n      \"name\": \"python-manuel\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"jspaleta\",\n          \"pcpa\"\
+        ,\n          \"jgu\",\n          \"limb\",\n          \"rathann\",\n     \
+        \     \"cstratak\"\n        ],\n        \"owner\": [\n          \"tomspur\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874129\",\n   \
+        \   \"date_modified\": \"1501874129\",\n      \"description\": \"The python-matplotlib\
+        \ rpms\",\n      \"fullname\": \"rpms/python-matplotlib\",\n      \"id\":\
+        \ 18384,\n      \"milestones\": {},\n      \"name\": \"python-matplotlib\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n     \
+        \     \"tomspur\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874131\",\n      \"date_modified\": \"1501874131\",\n      \"description\"\
+        : \"The python-mglob rpms\",\n      \"fullname\": \"rpms/python-mglob\",\n\
+        \      \"id\": 18399,\n      \"milestones\": {},\n      \"name\": \"python-mglob\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"carlwgeorge\",\n          \"abompard\",\n          \"stevetraylen\"\
+        \n        ],\n        \"owner\": [\n          \"jkaluza\"\n        ],\n  \
+        \      \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874132\",\n      \"date_modified\": \"\
+        1501874132\",\n      \"description\": \"The python-mimeparse rpms\",\n   \
+        \   \"fullname\": \"rpms/python-mimeparse\",\n      \"id\": 18403,\n     \
+        \ \"milestones\": {},\n      \"name\": \"python-mimeparse\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"jkaluza\",\n        \"name\": \"jkaluza\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"tomspur\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874133\",\n   \
+        \   \"date_modified\": \"1501874133\",\n      \"description\": \"The python-minimock\
+        \ rpms\",\n      \"fullname\": \"rpms/python-minimock\",\n      \"id\": 18408,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-minimock\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"lmacken\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874133\"\
+        ,\n      \"date_modified\": \"1501874133\",\n      \"description\": \"The\
+        \ python-modernize rpms\",\n      \"fullname\": \"rpms/python-modernize\"\
+        ,\n      \"id\": 18417,\n      \"milestones\": {},\n      \"name\": \"python-modernize\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\",\n        \
+        \  \"lmacken\"\n        ],\n        \"owner\": [\n          \"lbalhar\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874134\",\n   \
+        \   \"date_modified\": \"1501874134\",\n      \"description\": \"The python-moksha-common\
+        \ rpms\",\n      \"fullname\": \"rpms/python-moksha-common\",\n      \"id\"\
+        : 18420,\n      \"milestones\": {},\n      \"name\": \"python-moksha-common\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lbalhar\",\n        \"name\":\
+        \ \"lbalhar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\",\n        \
+        \  \"lmacken\"\n        ],\n        \"owner\": [\n          \"lbalhar\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874134\",\n   \
+        \   \"date_modified\": \"1501874134\",\n      \"description\": \"The python-moksha-hub\
+        \ rpms\",\n      \"fullname\": \"rpms/python-moksha-hub\",\n      \"id\":\
+        \ 18421,\n      \"milestones\": {},\n      \"name\": \"python-moksha-hub\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lbalhar\",\n        \"name\":\
+        \ \"lbalhar\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874134\",\n      \"date_modified\": \"1501874135\"\
+        ,\n      \"description\": \"The python-moksha-wsgi rpms\",\n      \"fullname\"\
+        : \"rpms/python-moksha-wsgi\",\n      \"id\": 18422,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-moksha-wsgi\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"bkabrda\",\n          \"sergiomb\"\n        ],\n        \"owner\"\
+        : [\n          \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501873941\",\n      \"date_modified\": \"1501873941\",\n      \"description\"\
+        : \"The python-MultipartPostHandler2 rpms\",\n      \"fullname\": \"rpms/python-MultipartPostHandler2\"\
+        ,\n      \"id\": 17431,\n      \"milestones\": {},\n      \"name\": \"python-MultipartPostHandler2\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n   \
+        \       \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874138\",\n      \"date_modified\": \"1501874138\",\n      \"description\"\
+        : \"The python-munch rpms\",\n      \"fullname\": \"rpms/python-munch\",\n\
+        \      \"id\": 18443,\n      \"milestones\": {},\n      \"name\": \"python-munch\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"nonamedotc\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874142\",\n   \
+        \   \"date_modified\": \"1501874142\",\n      \"description\": \"The python-nbconvert\
+        \ rpms\",\n      \"fullname\": \"rpms/python-nbconvert\",\n      \"id\": 18465,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-nbconvert\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Mukundan Ragavan\",\n        \"\
+        name\": \"nonamedotc\"\n      }\n    },\n    {\n      \"access_groups\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"tomspur\"\n  \
+        \      ],\n        \"owner\": [\n          \"orion\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874142\",\n      \"date_modified\": \"\
+        1501874142\",\n      \"description\": \"The python-nbformat rpms\",\n    \
+        \  \"fullname\": \"rpms/python-nbformat\",\n      \"id\": 18466,\n      \"\
+        milestones\": {},\n      \"name\": \"python-nbformat\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874143\",\n      \"date_modified\": \"1501874143\"\
+        ,\n      \"description\": \"The python-nbsphinx rpms\",\n      \"fullname\"\
+        : \"rpms/python-nbsphinx\",\n      \"id\": 18467,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-nbsphinx\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"itamarjp\",\n          \"noodles\"\n        ],\n        \"owner\"\
+        : [\n          \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874143\",\n      \"date_modified\": \"1501874143\",\n      \"description\"\
+        : \"The python-ndg_httpsclient rpms\",\n      \"fullname\": \"rpms/python-ndg_httpsclient\"\
+        ,\n      \"id\": 18470,\n      \"milestones\": {},\n      \"name\": \"python-ndg_httpsclient\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"bowlofeggs\"\n \
+        \       ],\n        \"owner\": [\n          \"lmacken\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874149\",\n      \"date_modified\": \"\
+        1501874149\",\n      \"description\": \"The python-nose rpms\",\n      \"\
+        fullname\": \"rpms/python-nose\",\n      \"id\": 18505,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-nose\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"\
+        lmacken\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874149\"\
+        ,\n      \"date_modified\": \"1501874150\",\n      \"description\": \"The\
+        \ python-nose1.1 rpms\",\n      \"fullname\": \"rpms/python-nose1.1\",\n \
+        \     \"id\": 18506,\n      \"milestones\": {},\n      \"name\": \"python-nose1.1\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"owner\": [\n          \"abompard\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874150\",\n      \"date_modified\": \"\
+        1501874150\",\n      \"description\": \"The python-nose2 rpms\",\n      \"\
+        fullname\": \"rpms/python-nose2\",\n      \"id\": 18507,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-nose2\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"abompard\",\n        \"name\": \"abompard\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874150\",\n      \"date_modified\": \"1501874150\"\
+        ,\n      \"description\": \"The python-nose_warnings_filters rpms\",\n   \
+        \   \"fullname\": \"rpms/python-nose_warnings_filters\",\n      \"id\": 18509,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-nose_warnings_filters\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874150\",\n      \"date_modified\": \"1501874150\",\n      \"description\"\
+        : \"The python-notebook rpms\",\n      \"fullname\": \"rpms/python-notebook\"\
+        ,\n      \"id\": 18511,\n      \"milestones\": {},\n      \"name\": \"python-notebook\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"tomspur\"\n   \
+        \     ],\n        \"owner\": [\n          \"orion\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874154\",\n      \"date_modified\": \"\
+        1501874154\",\n      \"description\": \"The python-numpydoc rpms\",\n    \
+        \  \"fullname\": \"rpms/python-numpydoc\",\n      \"id\": 18526,\n      \"\
+        milestones\": {},\n      \"name\": \"python-numpydoc\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n     \
+        \   \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874154\",\n      \"date_modified\": \"1501874154\"\
+        ,\n      \"description\": \"The python-numpy-stl rpms\",\n      \"fullname\"\
+        : \"rpms/python-numpy-stl\",\n      \"id\": 18525,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-numpy-stl\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"jdennis\",\n          \"jdornak\",\n          \"ralph\"\n   \
+        \     ],\n        \"owner\": [\n          \"puiterwijk\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874155\",\n      \"date_modified\": \"\
+        1501874157\",\n      \"description\": \"The python-oauthlib rpms\",\n    \
+        \  \"fullname\": \"rpms/python-oauthlib\",\n      \"id\": 18532,\n      \"\
+        milestones\": {},\n      \"name\": \"python-oauthlib\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Patrick \\\"\\u30de\\u30eb\\u30bf\\u30a4\\u30f3\\u30a2\\u30f3\\u30c9\\\
+        u30ec\\u30a2\\u30b9\\\" Uiterwijk\",\n        \"name\": \"puiterwijk\"\n \
+        \     }\n    },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n\
+        \        \"commit\": [],\n        \"ticket\": []\n      },\n      \"access_users\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"abompard\"\
+        \n        ],\n        \"owner\": [\n          \"apevec\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874174\",\n      \"date_modified\": \"\
+        1501874174\",\n      \"description\": \"The python-passlib rpms\",\n     \
+        \ \"fullname\": \"rpms/python-passlib\",\n      \"id\": 18607,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-passlib\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"apevec\",\n        \"name\": \"apevec\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"bowlofeggs\",\n          \"lmacken\"\n\
+        \        ],\n        \"owner\": [\n          \"kylev\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874174\",\n      \"date_modified\": \"\
+        1501874175\",\n      \"description\": \"The python-paste-deploy rpms\",\n\
+        \      \"fullname\": \"rpms/python-paste-deploy\",\n      \"id\": 18608,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-paste-deploy\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"kylev\",\n        \"name\": \"\
+        kylev\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"tc01\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874177\",\n   \
+        \   \"date_modified\": \"1501874177\",\n      \"description\": \"The python-pdfminer\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pdfminer\",\n      \"id\": 18623,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-pdfminer\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ben Rosser\",\n        \"name\"\
+        : \"tc01\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mstuchli\",\n          \"vkrizan\"\
+        \n        ],\n        \"owner\": [\n          \"cstratak\"\n        ],\n \
+        \       \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874178\",\n      \"date_modified\": \"\
+        1501874178\",\n      \"description\": \"The python-peewee rpms\",\n      \"\
+        fullname\": \"rpms/python-peewee\",\n      \"id\": 18634,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-peewee\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Charalampos Stratakis\",\n        \"name\": \"cstratak\"\n      }\n  \
+        \  },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n       \
+        \ \"commit\": [\n          \"python-sig\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [\n          \"sundaram\",\n          \"ncoghlan\",\n     \
+        \     \"ttorling\",\n          \"mstuchli\",\n          \"bkabrda\"\n    \
+        \    ],\n        \"owner\": [\n          \"torsava\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874184\",\n      \"date_modified\": \"\
+        1501874185\",\n      \"description\": \"The python-pip rpms\",\n      \"fullname\"\
+        : \"rpms/python-pip\",\n      \"id\": 18659,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-pip\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"torsava\",\n        \"name\":\
+        \ \"torsava\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874186\"\
+        ,\n      \"date_modified\": \"1501874186\",\n      \"description\": \"The\
+        \ python-pkgwat-api rpms\",\n      \"fullname\": \"rpms/python-pkgwat-api\"\
+        ,\n      \"id\": 18663,\n      \"milestones\": {},\n      \"name\": \"python-pkgwat-api\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874191\",\n   \
+        \   \"date_modified\": \"1501874191\",\n      \"description\": \"The python-power\
+        \ rpms\",\n      \"fullname\": \"rpms/python-power\",\n      \"id\": 18684,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-power\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"salimma\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874194\",\n      \"date_modified\": \"1501874194\"\
+        ,\n      \"description\": \"The python-psutil rpms\",\n      \"fullname\"\
+        : \"rpms/python-psutil\",\n      \"id\": 18702,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-psutil\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"salimma\",\n        \"name\": \"salimma\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"orion\",\n          \"tomspur\"\n        ],\n        \"owner\"\
+        : [\n          \"ignatenkobrain\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874195\",\n      \"date_modified\": \"1501874196\",\n\
+        \      \"description\": \"The python-ptyprocess rpms\",\n      \"fullname\"\
+        : \"rpms/python-ptyprocess\",\n      \"id\": 18709,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-ptyprocess\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Igor Gnatenko\",\n        \"name\": \"ignatenkobrain\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"orion\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874198\",\n   \
+        \   \"date_modified\": \"1501874198\",\n      \"description\": \"The python-pycodestyle\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pycodestyle\",\n      \"id\"\
+        : 18729,\n      \"milestones\": {},\n      \"name\": \"python-pycodestyle\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"immanetize\"\n    \
+        \    ],\n        \"owner\": [\n          \"ralph\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874200\",\n      \"date_modified\": \"\
+        1501874200\",\n      \"description\": \"The python-pygal rpms\",\n      \"\
+        fullname\": \"rpms/python-pygal\",\n      \"id\": 18744,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-pygal\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874201\",\n      \"date_modified\": \"1501874201\"\
+        ,\n      \"description\": \"The python-pygeoip rpms\",\n      \"fullname\"\
+        : \"rpms/python-pygeoip\",\n      \"id\": 18746,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-pygeoip\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"cicku\",\n          \"ignatenkobrain\"\n        ],\n        \"\
+        owner\": [\n          \"pwalter\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874201\",\n      \"date_modified\": \"1501874202\",\n\
+        \      \"description\": \"The python-pygit2 rpms\",\n      \"fullname\": \"\
+        rpms/python-pygit2\",\n      \"id\": 18748,\n      \"milestones\": {},\n \
+        \     \"name\": \"python-pygit2\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Pete Walter\",\n        \"name\": \"pwalter\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"orion\"\n        ],\n        \"owner\": [\n          \"pviktori\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874202\",\n   \
+        \   \"date_modified\": \"1501874202\",\n      \"description\": \"The python-pyglet\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pyglet\",\n      \"id\": 18749,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-pyglet\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"pviktori\",\n        \"name\": \"pviktori\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874202\",\n      \"date_modified\": \"1501874202\"\
+        ,\n      \"description\": \"The python-pygments-markdown-lexer rpms\",\n \
+        \     \"fullname\": \"rpms/python-pygments-markdown-lexer\",\n      \"id\"\
+        : 18750,\n      \"milestones\": {},\n      \"name\": \"python-pygments-markdown-lexer\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mstuchli\",\n          \"pviktori\"\
+        ,\n          \"rkuska\"\n        ],\n        \"owner\": [\n          \"churchyard\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874204\",\n   \
+        \   \"date_modified\": \"1501874204\",\n      \"description\": \"The python-pyldap\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pyldap\",\n      \"id\": 18762,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-pyldap\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"kumarpraveen\",\n \
+        \         \"abompard\",\n          \"pjp\"\n        ],\n        \"owner\"\
+        : [\n          \"sundaram\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874204\",\n      \"date_modified\": \"1501874205\",\n      \"description\"\
+        : \"The python-pylibmc rpms\",\n      \"fullname\": \"rpms/python-pylibmc\"\
+        ,\n      \"id\": 18763,\n      \"milestones\": {},\n      \"name\": \"python-pylibmc\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"sundaram\",\n        \"name\"\
+        : \"sundaram\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n     \
+        \     \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874205\"\
+        ,\n      \"date_modified\": \"1501874205\",\n      \"description\": \"The\
+        \ python-pylibravatar rpms\",\n      \"fullname\": \"rpms/python-pylibravatar\"\
+        ,\n      \"id\": 18764,\n      \"milestones\": {},\n      \"name\": \"python-pylibravatar\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874208\",\n   \
+        \   \"date_modified\": \"1501874208\",\n      \"description\": \"The python-pypng\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pypng\",\n      \"id\": 18783,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-pypng\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874209\",\n      \"date_modified\": \"1501874209\"\
+        ,\n      \"description\": \"The python-pyquery rpms\",\n      \"fullname\"\
+        : \"rpms/python-pyquery\",\n      \"id\": 18788,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-pyquery\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tdabasin\",\n          \"lmacken\",\n          \"bowlofeggs\"\
+        ,\n          \"rossdylan\"\n        ],\n        \"owner\": [\n          \"\
+        ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874210\"\
+        ,\n      \"date_modified\": \"1501874210\",\n      \"description\": \"The\
+        \ python-pyramid rpms\",\n      \"fullname\": \"rpms/python-pyramid\",\n \
+        \     \"id\": 18794,\n      \"milestones\": {},\n      \"name\": \"python-pyramid\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"bowlofeggs\"\n        ],\n     \
+        \   \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874209\",\n      \"date_modified\": \"1501874209\"\
+        ,\n      \"description\": \"The python-pyramid-chameleon rpms\",\n      \"\
+        fullname\": \"rpms/python-pyramid-chameleon\",\n      \"id\": 18790,\n   \
+        \   \"milestones\": {},\n      \"name\": \"python-pyramid-chameleon\",\n \
+        \     \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\",\n        \
+        \  \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874209\",\n   \
+        \   \"date_modified\": \"1501874209\",\n      \"description\": \"The python-pyramid-fas-openid\
+        \ rpms\",\n      \"fullname\": \"rpms/python-pyramid-fas-openid\",\n     \
+        \ \"id\": 18791,\n      \"milestones\": {},\n      \"name\": \"python-pyramid-fas-openid\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874210\"\
+        ,\n      \"date_modified\": \"1501874210\",\n      \"description\": \"The\
+        \ python-pyramid-mako rpms\",\n      \"fullname\": \"rpms/python-pyramid-mako\"\
+        ,\n      \"id\": 18792,\n      \"milestones\": {},\n      \"name\": \"python-pyramid-mako\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"rossdylan\"\n        ],\n      \
+        \  \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874210\",\n      \"date_modified\": \"1501874210\"\
+        ,\n      \"description\": \"The python-pyramid-tm rpms\",\n      \"fullname\"\
+        : \"rpms/python-pyramid-tm\",\n      \"id\": 18793,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-pyramid-tm\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"kevin\",\n          \"abompard\",\n          \"ttorling\"\n \
+        \       ],\n        \"owner\": [\n          \"ralph\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874215\",\n      \"date_modified\": \"\
+        1501874215\",\n      \"description\": \"The python-pysocks rpms\",\n     \
+        \ \"fullname\": \"rpms/python-pysocks\",\n      \"id\": 18807,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-pysocks\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"pviktori\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874217\",\n      \"date_modified\": \"1501874217\"\
+        ,\n      \"description\": \"The python-pytest-multihost rpms\",\n      \"\
+        fullname\": \"rpms/python-pytest-multihost\",\n      \"id\": 18821,\n    \
+        \  \"milestones\": {},\n      \"name\": \"python-pytest-multihost\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"pviktori\",\n        \"name\"\
+        : \"pviktori\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874218\",\n      \"date_modified\": \"1501874218\",\n      \"description\"\
+        : \"The python-pytest-testmon rpms\",\n      \"fullname\": \"rpms/python-pytest-testmon\"\
+        ,\n      \"id\": 18826,\n      \"milestones\": {},\n      \"name\": \"python-pytest-testmon\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"bochecha\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874218\",\n      \"date_modified\": \"1501874218\",\n      \"description\"\
+        : \"The python-pythonz-bd rpms\",\n      \"fullname\": \"rpms/python-pythonz-bd\"\
+        ,\n      \"id\": 18831,\n      \"milestones\": {},\n      \"name\": \"python-pythonz-bd\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bochecha\",\n        \"name\"\
+        : \"bochecha\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"bochecha\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874223\",\n      \"date_modified\": \"1501874223\",\n      \"description\"\
+        : \"The python-rangehttpserver rpms\",\n      \"fullname\": \"rpms/python-rangehttpserver\"\
+        ,\n      \"id\": 18862,\n      \"milestones\": {},\n      \"name\": \"python-rangehttpserver\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bochecha\",\n        \"name\"\
+        : \"bochecha\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"kiilerix\"\n     \
+        \   ],\n        \"owner\": [\n          \"ralph\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874224\",\n      \"date_modified\": \"\
+        1501874224\",\n      \"description\": \"The python-re2 rpms\",\n      \"fullname\"\
+        : \"rpms/python-re2\",\n      \"id\": 18869,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-re2\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"cicku\",\n          \"maxamillion\"\
+        \n        ],\n        \"owner\": [\n          \"ralph\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874224\",\n      \"date_modified\": \"\
+        1501874224\",\n      \"description\": \"The python-redis rpms\",\n      \"\
+        fullname\": \"rpms/python-redis\",\n      \"id\": 18872,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-redis\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874226\",\n   \
+        \   \"date_modified\": \"1501874226\",\n      \"description\": \"The python-repoze-lru\
+        \ rpms\",\n      \"fullname\": \"rpms/python-repoze-lru\",\n      \"id\":\
+        \ 18881,\n      \"milestones\": {},\n      \"name\": \"python-repoze-lru\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874226\",\n      \"date_modified\": \"1501874226\"\
+        ,\n      \"description\": \"The python-repoze-what rpms\",\n      \"fullname\"\
+        : \"rpms/python-repoze-what\",\n      \"id\": 18887,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-repoze-what\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"spot\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874226\",\n      \"date_modified\": \"1501874226\"\
+        ,\n      \"description\": \"The python-repoze-who-friendlyform rpms\",\n \
+        \     \"fullname\": \"rpms/python-repoze-who-friendlyform\",\n      \"id\"\
+        : 18888,\n      \"milestones\": {},\n      \"name\": \"python-repoze-who-friendlyform\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"spot\",\n        \"name\": \"\
+        spot\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"jcline\",\n          \"ralph\",\n\
+        \          \"abompard\",\n          \"sagarun\"\n        ],\n        \"owner\"\
+        : [\n          \"cstratak\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874228\",\n      \"date_modified\": \"1501874229\",\n      \"description\"\
+        : \"The python-requests rpms\",\n      \"fullname\": \"rpms/python-requests\"\
+        ,\n      \"id\": 18902,\n      \"milestones\": {},\n      \"name\": \"python-requests\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"jdennis\",\n \
+        \         \"jdornak\"\n        ],\n        \"owner\": [\n          \"puiterwijk\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874228\",\n   \
+        \   \"date_modified\": \"1501874228\",\n      \"description\": \"The python-requests-oauthlib\
+        \ rpms\",\n      \"fullname\": \"rpms/python-requests-oauthlib\",\n      \"\
+        id\": 18900,\n      \"milestones\": {},\n      \"name\": \"python-requests-oauthlib\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Patrick \\\"\\u30de\\u30eb\\u30bf\\\
+        u30a4\\u30f3\\u30a2\\u30f3\\u30c9\\u30ec\\u30a2\\u30b9\\\" Uiterwijk\",\n\
+        \        \"name\": \"puiterwijk\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"bkabrda\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874230\",\n      \"date_modified\": \"\
+        1501874230\",\n      \"description\": \"The python-restkit rpms\",\n     \
+        \ \"fullname\": \"rpms/python-restkit\",\n      \"id\": 18909,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-restkit\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"bkabrda\",\n        \"name\": \"bkabrda\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"bochecha\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874230\",\n      \"date_modified\": \"1501874230\"\
+        ,\n      \"description\": \"The python-resumable-urlretrieve rpms\",\n   \
+        \   \"fullname\": \"rpms/python-resumable-urlretrieve\",\n      \"id\": 18913,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-resumable-urlretrieve\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bochecha\",\n        \"name\"\
+        : \"bochecha\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n    \
+        \      \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n    \
+        \  \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874232\",\n      \"date_modified\": \"1501874232\",\n      \"description\"\
+        : \"The python-ripozo rpms\",\n      \"fullname\": \"rpms/python-ripozo\"\
+        ,\n      \"id\": 18924,\n      \"milestones\": {},\n      \"name\": \"python-ripozo\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [\n          \"tibbs\",\n    \
+        \      \"mcyprian\",\n          \"cstratak\",\n          \"torsava\"\n   \
+        \     ],\n        \"owner\": [\n          \"orion\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874236\",\n      \"date_modified\": \"\
+        1501874236\",\n      \"description\": \"The python-rpm-macros rpms\",\n  \
+        \    \"fullname\": \"rpms/python-rpm-macros\",\n      \"id\": 18944,\n   \
+        \   \"milestones\": {},\n      \"name\": \"python-rpm-macros\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orion\",\n        \"name\": \"\
+        orion\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874238\",\n   \
+        \   \"date_modified\": \"1501874238\",\n      \"description\": \"The python-rxjson\
+        \ rpms\",\n      \"fullname\": \"rpms/python-rxjson\",\n      \"id\": 18955,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-rxjson\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874239\",\n      \"date_modified\": \"1501874239\"\
+        ,\n      \"description\": \"The python-sanction rpms\",\n      \"fullname\"\
+        : \"rpms/python-sanction\",\n      \"id\": 18960,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-sanction\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tc01\"\n        ],\n        \"owner\": [\n          \"orion\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874241\",\n   \
+        \   \"date_modified\": \"1501874241\",\n      \"description\": \"The python-scp\
+        \ rpms\",\n      \"fullname\": \"rpms/python-scp\",\n      \"id\": 18971,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-scp\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orion\",\n        \"name\": \"orion\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"mbacovsk\",\n          \"mstuchli\"\n        ],\n        \"owner\":\
+        \ [\n          \"churchyard\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874241\",\n      \"date_modified\": \"1501874241\",\n      \"description\"\
+        : \"The python-scripttest rpms\",\n      \"fullname\": \"rpms/python-scripttest\"\
+        ,\n      \"id\": 18973,\n      \"milestones\": {},\n      \"name\": \"python-scripttest\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"tc01\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874241\",\n      \"date_modified\": \"1501874241\",\n      \"description\"\
+        : \"The python-seesaw rpms\",\n      \"fullname\": \"rpms/python-seesaw\"\
+        ,\n      \"id\": 18977,\n      \"milestones\": {},\n      \"name\": \"python-seesaw\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ben Rosser\",\n        \"name\"\
+        : \"tc01\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"churchyard\",\n          \"mcyprian\"\
+        ,\n          \"cstratak\",\n          \"rkuska\",\n          \"mstuchli\"\
+        ,\n          \"lmacken\"\n        ],\n        \"owner\": [\n          \"bowlofeggs\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874243\",\n   \
+        \   \"date_modified\": \"1501874244\",\n      \"description\": \"The python-setuptools\
+        \ rpms\",\n      \"fullname\": \"rpms/python-setuptools\",\n      \"id\":\
+        \ 18988,\n      \"milestones\": {},\n      \"name\": \"python-setuptools\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bowlofeggs\",\n        \"name\"\
+        : \"bowlofeggs\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"ralph\",\n     \
+        \     \"grover\",\n          \"jpena\"\n        ],\n        \"owner\": [\n\
+        \          \"carlwgeorge\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874245\",\n      \"date_modified\": \"1501874245\",\n      \"description\"\
+        : \"The python-sh rpms\",\n      \"fullname\": \"rpms/python-sh\",\n     \
+        \ \"id\": 18995,\n      \"milestones\": {},\n      \"name\": \"python-sh\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Carl George\",\n        \"name\"\
+        : \"carlwgeorge\"\n      }\n    },\n    {\n      \"access_groups\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n  \
+        \      ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n \
+        \       \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n  \
+        \        \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874246\",\n      \"date_modified\": \"1501874246\",\n      \"description\"\
+        : \"The python-sieve rpms\",\n      \"fullname\": \"rpms/python-sieve\",\n\
+        \      \"id\": 19002,\n      \"milestones\": {},\n      \"name\": \"python-sieve\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\",\n          \"bowlofeggs\"\
+        ,\n          \"lmacken\"\n        ],\n        \"owner\": [\n          \"potty\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874247\",\n   \
+        \   \"date_modified\": \"1501874247\",\n      \"description\": \"The python-simplemediawiki\
+        \ rpms\",\n      \"fullname\": \"rpms/python-simplemediawiki\",\n      \"\
+        id\": 19010,\n      \"milestones\": {},\n      \"name\": \"python-simplemediawiki\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"potty\",\n        \"name\": \"\
+        potty\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"bkabrda\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874251\",\n      \"date_modified\": \"1501874251\",\n\
+        \      \"description\": \"The python-socketpool rpms\",\n      \"fullname\"\
+        : \"rpms/python-socketpool\",\n      \"id\": 19036,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-socketpool\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"bkabrda\",\n        \"name\": \"bkabrda\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"tc01\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874251\",\n      \"date_modified\": \"1501874251\"\
+        ,\n      \"description\": \"The python-sockjs-tornado rpms\",\n      \"fullname\"\
+        : \"rpms/python-sockjs-tornado\",\n      \"id\": 19037,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-sockjs-tornado\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ben Rosser\",\n        \"name\": \"tc01\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"mbacovsk\",\n          \"ivazquez\",\n          \"lmacken\",\n\
+        \          \"bowlofeggs\"\n        ],\n        \"owner\": [\n          \"\
+        nphilipp\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874256\"\
+        ,\n      \"date_modified\": \"1501874256\",\n      \"description\": \"The\
+        \ python-sqlalchemy rpms\",\n      \"fullname\": \"rpms/python-sqlalchemy\"\
+        ,\n      \"id\": 19077,\n      \"milestones\": {},\n      \"name\": \"python-sqlalchemy\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"nphilipp\",\n        \"name\"\
+        : \"nphilipp\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"orphan\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874256\",\n      \"date_modified\": \"1501874256\"\
+        ,\n      \"description\": \"The python-sqlalchemy0.8 rpms\",\n      \"fullname\"\
+        : \"rpms/python-sqlalchemy0.8\",\n      \"id\": 19081,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-sqlalchemy0.8\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orphan\",\n        \"name\": \"orphan\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874259\",\n   \
+        \   \"date_modified\": \"1501874259\",\n      \"description\": \"The python-stomper\
+        \ rpms\",\n      \"fullname\": \"rpms/python-stomper\",\n      \"id\": 19099,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-stomper\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874259\",\n      \"date_modified\": \"1501874259\"\
+        ,\n      \"description\": \"The python-strainer rpms\",\n      \"fullname\"\
+        : \"rpms/python-strainer\",\n      \"id\": 19102,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-strainer\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874259\",\n      \"date_modified\": \"1501874260\"\
+        ,\n      \"description\": \"The python-stuf rpms\",\n      \"fullname\": \"\
+        rpms/python-stuf\",\n      \"id\": 19105,\n      \"milestones\": {},\n   \
+        \   \"name\": \"python-stuf\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"nsoffer\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874260\",\n   \
+        \   \"date_modified\": \"1501874260\",\n      \"description\": \"The python-subprocess32\
+        \ rpms\",\n      \"fullname\": \"rpms/python-subprocess32\",\n      \"id\"\
+        : 19106,\n      \"milestones\": {},\n      \"name\": \"python-subprocess32\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"nsoffer\",\n        \"name\":\
+        \ \"nsoffer\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"pingou\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874261\"\
+        ,\n      \"date_modified\": \"1501874261\",\n      \"description\": \"The\
+        \ python-summershum rpms\",\n      \"fullname\": \"rpms/python-summershum\"\
+        ,\n      \"id\": 19112,\n      \"milestones\": {},\n      \"name\": \"python-summershum\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Pierre-YvesChibon\",\n       \
+        \ \"name\": \"pingou\"\n      }\n    },\n    {\n      \"access_groups\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n \
+        \         \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874261\",\n      \"date_modified\": \"1501874261\",\n      \"description\"\
+        : \"The python-svg-path rpms\",\n      \"fullname\": \"rpms/python-svg-path\"\
+        ,\n      \"id\": 19115,\n      \"milestones\": {},\n      \"name\": \"python-svg-path\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\",\n          \"apevec\"\n\
+        \        ],\n        \"owner\": [\n          \"hguemar\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874262\",\n      \"date_modified\": \"\
+        1501874262\",\n      \"description\": \"The python-tablib rpms\",\n      \"\
+        fullname\": \"rpms/python-tablib\",\n      \"id\": 19124,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-tablib\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"hguemar\",\n        \"name\": \"hguemar\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"rossdylan\"\n        ],\n        \"owner\": [\n          \"sayanchowdhury\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874263\",\n   \
+        \   \"date_modified\": \"1501874263\",\n      \"description\": \"The python-tahrir\
+        \ rpms\",\n      \"fullname\": \"rpms/python-tahrir\",\n      \"id\": 19130,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-tahrir\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sayanchowdhury\",\n        \"name\": \"sayanchowdhury\"\n      }\n   \
+        \ },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"\
+        commit\": [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"rossdylan\"\n        ],\n        \"owner\": [\n         \
+        \ \"sayanchowdhury\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874263\",\n      \"date_modified\": \"1501874263\",\n      \"description\"\
+        : \"The python-tahrir-api rpms\",\n      \"fullname\": \"rpms/python-tahrir-api\"\
+        ,\n      \"id\": 19129,\n      \"milestones\": {},\n      \"name\": \"python-tahrir-api\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"sayanchowdhury\",\n        \"\
+        name\": \"sayanchowdhury\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"lmacken\"\n        ],\n       \
+        \ \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874263\",\n      \"date_modified\": \"\
+        1501874263\",\n      \"description\": \"The python-tbgrep rpms\",\n      \"\
+        fullname\": \"rpms/python-tbgrep\",\n      \"id\": 19135,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-tbgrep\",\n      \"namespace\": \"rpms\",\n\
+        \      \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874265\",\n      \"date_modified\": \"1501874265\"\
+        ,\n      \"description\": \"The python-testpath rpms\",\n      \"fullname\"\
+        : \"rpms/python-testpath\",\n      \"id\": 19148,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-testpath\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"kumarpraveen\",\n \
+        \         \"abompard\"\n        ],\n        \"owner\": [\n          \"salimma\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874266\",\n   \
+        \   \"date_modified\": \"1501874266\",\n      \"description\": \"The python-testtools\
+        \ rpms\",\n      \"fullname\": \"rpms/python-testtools\",\n      \"id\": 19152,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-testtools\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"salimma\",\n        \"name\":\
+        \ \"salimma\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"lmacken\"\n       \
+        \ ],\n        \"owner\": [\n          \"dcallagh\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874267\",\n      \"date_modified\": \"\
+        1501874267\",\n      \"description\": \"The python-tgmochikit rpms\",\n  \
+        \    \"fullname\": \"rpms/python-tgmochikit\",\n      \"id\": 19164,\n   \
+        \   \"milestones\": {},\n      \"name\": \"python-tgmochikit\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"dcallagh\",\n        \"name\"\
+        : \"dcallagh\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n     \
+        \   ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n     \
+        \     \"ralph\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874267\"\
+        ,\n      \"date_modified\": \"1501874267\",\n      \"description\": \"The\
+        \ python-tgscheduler rpms\",\n      \"fullname\": \"rpms/python-tgscheduler\"\
+        ,\n      \"id\": 19165,\n      \"milestones\": {},\n      \"name\": \"python-tgscheduler\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"orion\",\n          \"abompard\"\
+        ,\n          \"churchyard\"\n        ],\n        \"owner\": [\n          \"\
+        tomspur\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874269\"\
+        ,\n      \"date_modified\": \"1501874269\",\n      \"description\": \"The\
+        \ python-tornado rpms\",\n      \"fullname\": \"rpms/python-tornado\",\n \
+        \     \"id\": 19178,\n      \"milestones\": {},\n      \"name\": \"python-tornado\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n      \
+        \    \"lmacken\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874271\"\
+        ,\n      \"date_modified\": \"1501874271\",\n      \"description\": \"The\
+        \ python-toscawidgets rpms\",\n      \"fullname\": \"rpms/python-toscawidgets\"\
+        ,\n      \"id\": 19182,\n      \"milestones\": {},\n      \"name\": \"python-toscawidgets\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n        ],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874273\",\n      \"date_modified\": \"1501874273\"\
+        ,\n      \"description\": \"The python-transaction rpms\",\n      \"fullname\"\
+        : \"rpms/python-transaction\",\n      \"id\": 19190,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-transaction\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"lmacken\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874278\",\n   \
+        \   \"date_modified\": \"1501874278\",\n      \"description\": \"The python-translationstring\
+        \ rpms\",\n      \"fullname\": \"rpms/python-translationstring\",\n      \"\
+        id\": 19194,\n      \"milestones\": {},\n      \"name\": \"python-translationstring\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"lmacken\"\n       \
+        \ ],\n        \"owner\": [\n          \"orphan\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874280\",\n      \"date_modified\": \"1501874280\"\
+        ,\n      \"description\": \"The python-turbojson13 rpms\",\n      \"fullname\"\
+        : \"rpms/python-turbojson13\",\n      \"id\": 19205,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-turbojson13\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"orphan\",\n        \"name\": \"orphan\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874281\",\n      \"date_modified\": \"1501874281\"\
+        ,\n      \"description\": \"The python-tw-forms rpms\",\n      \"fullname\"\
+        : \"rpms/python-tw-forms\",\n      \"id\": 19209,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-tw-forms\",\n      \"namespace\": \"rpms\",\n  \
+        \    \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"lmacken\",\n        \"name\": \"lmacken\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874285\",\n      \"date_modified\": \"1501874285\"\
+        ,\n      \"description\": \"The python-twiggy rpms\",\n      \"fullname\"\
+        : \"rpms/python-twiggy\",\n      \"id\": 19225,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-twiggy\",\n      \"namespace\": \"rpms\",\n    \
+        \  \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n \
+        \       \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874293\",\n      \"date_modified\": \"1501874293\"\
+        ,\n      \"description\": \"The python-txrequests rpms\",\n      \"fullname\"\
+        : \"rpms/python-txrequests\",\n      \"id\": 19243,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-txrequests\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874294\",\n      \"date_modified\": \"1501874294\"\
+        ,\n      \"description\": \"The python-txws rpms\",\n      \"fullname\": \"\
+        rpms/python-txws\",\n      \"id\": 19245,\n      \"milestones\": {},\n   \
+        \   \"name\": \"python-txws\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874294\",\n   \
+        \   \"date_modified\": \"1501874294\",\n      \"description\": \"The python-txzmq\
+        \ rpms\",\n      \"fullname\": \"rpms/python-txzmq\",\n      \"id\": 19246,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-txzmq\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874297\",\n      \"date_modified\": \"1501874297\"\
+        ,\n      \"description\": \"The python-uranium rpms\",\n      \"fullname\"\
+        : \"rpms/python-uranium\",\n      \"id\": 19266,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-uranium\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"jcline\",\n          \"abompard\",\n          \"ralph\"\n   \
+        \     ],\n        \"owner\": [\n          \"sagarun\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874298\",\n      \"date_modified\": \"\
+        1501874298\",\n      \"description\": \"The python-urllib3 rpms\",\n     \
+        \ \"fullname\": \"rpms/python-urllib3\",\n      \"id\": 19272,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-urllib3\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"sagarun\",\n        \"name\": \"sagarun\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"churchyard\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874305\",\n      \"date_modified\": \"1501874305\"\
+        ,\n      \"description\": \"The python-utils rpms\",\n      \"fullname\":\
+        \ \"rpms/python-utils\",\n      \"id\": 19277,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-utils\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"churchyard\",\n        \"name\": \"churchyard\"\n      }\n    },\n   \
+        \ {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874306\",\n      \"date_modified\": \"1501874306\"\
+        ,\n      \"description\": \"The python-vcrpy rpms\",\n      \"fullname\":\
+        \ \"rpms/python-vcrpy\",\n      \"id\": 19282,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-vcrpy\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874307\",\n      \"date_modified\": \"1501874307\"\
+        ,\n      \"description\": \"The python-velruse rpms\",\n      \"fullname\"\
+        : \"rpms/python-velruse\",\n      \"id\": 19284,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-velruse\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\",\n          \"lmacken\",\n          \"rossdylan\"\n \
+        \       ],\n        \"owner\": [\n          \"tdabasin\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874307\",\n      \"date_modified\": \"\
+        1501874308\",\n      \"description\": \"The python-venusian rpms\",\n    \
+        \  \"fullname\": \"rpms/python-venusian\",\n      \"id\": 19285,\n      \"\
+        milestones\": {},\n      \"name\": \"python-venusian\",\n      \"namespace\"\
+        : \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"tdabasin\",\n        \"name\": \"tdabasin\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874308\",\n      \"date_modified\": \"1501874308\"\
+        ,\n      \"description\": \"The python-virtualenv-clone rpms\",\n      \"\
+        fullname\": \"rpms/python-virtualenv-clone\",\n      \"id\": 19291,\n    \
+        \  \"milestones\": {},\n      \"name\": \"python-virtualenv-clone\",\n   \
+        \   \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"lgs\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874310\",\n      \"date_modified\": \"1501874311\",\n      \"description\"\
+        : \"The python-waitress rpms\",\n      \"fullname\": \"rpms/python-waitress\"\
+        ,\n      \"id\": 19306,\n      \"milestones\": {},\n      \"name\": \"python-waitress\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lgs\",\n        \"name\": \"lgs\"\
+        \n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\": [],\n\
+        \        \"commit\": [],\n        \"ticket\": []\n      },\n      \"access_users\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"abompard\"\
+        \n        ],\n        \"owner\": [\n          \"fale\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874312\",\n      \"date_modified\": \"\
+        1501874312\",\n      \"description\": \"The python-wcwidth rpms\",\n     \
+        \ \"fullname\": \"rpms/python-wcwidth\",\n      \"id\": 19312,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-wcwidth\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"fale\",\n        \"name\": \"fale\"\n      }\n    },\n    {\n      \"\
+        access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n      \
+        \    \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        access_users\": {\n        \"admin\": [],\n        \"commit\": [\n       \
+        \   \"ralph\",\n          \"ricky\"\n        ],\n        \"owner\": [\n  \
+        \        \"lmacken\"\n        ],\n        \"ticket\": []\n      },\n     \
+        \ \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874312\",\n      \"date_modified\": \"1501874313\",\n      \"description\"\
+        : \"The python-weberror rpms\",\n      \"fullname\": \"rpms/python-weberror\"\
+        ,\n      \"id\": 19318,\n      \"milestones\": {},\n      \"name\": \"python-weberror\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"hguemar\",\n      \
+        \    \"ralph\",\n          \"ricky\",\n          \"lmacken\"\n        ],\n\
+        \        \"owner\": [\n          \"mrunge\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874313\",\n      \"date_modified\": \"1501874314\"\
+        ,\n      \"description\": \"The python-webob rpms\",\n      \"fullname\":\
+        \ \"rpms/python-webob\",\n      \"id\": 19322,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-webob\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"mrunge\",\n        \"name\": \"mrunge\"\n      }\n    },\n    {\n    \
+        \  \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n \
+        \         \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n  \
+        \    \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"ralph\"\n        ],\n        \"owner\": [\n          \"orphan\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874314\",\n   \
+        \   \"date_modified\": \"1501874314\",\n      \"description\": \"The python-webob1.2\
+        \ rpms\",\n      \"fullname\": \"rpms/python-webob1.2\",\n      \"id\": 19325,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-webob1.2\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orphan\",\n        \"name\": \"\
+        orphan\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [],\n        \"owner\": [\n          \"ralph\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874314\",\n   \
+        \   \"date_modified\": \"1501874314\",\n      \"description\": \"The python-webob1.4\
+        \ rpms\",\n      \"fullname\": \"rpms/python-webob1.4\",\n      \"id\": 19326,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-webob1.4\",\n      \"\
+        namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n\
+        \      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"lmacken\",\n          \"ricky\"\n\
+        \        ],\n        \"owner\": [\n          \"bkabrda\"\n        ],\n   \
+        \     \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874315\",\n      \"date_modified\": \"\
+        1501874315\",\n      \"description\": \"The python-webtest rpms\",\n     \
+        \ \"fullname\": \"rpms/python-webtest\",\n      \"id\": 19331,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-webtest\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"bkabrda\",\n        \"name\": \"bkabrda\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874315\",\n      \"date_modified\": \"1501874315\"\
+        ,\n      \"description\": \"The python-webtest1.3 rpms\",\n      \"fullname\"\
+        : \"rpms/python-webtest1.3\",\n      \"id\": 19332,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-webtest1.3\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"hguemar\",\n          \"abompard\"\
+        ,\n          \"ianweller\"\n        ],\n        \"owner\": [\n          \"\
+        codeblock\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874316\"\
+        ,\n      \"date_modified\": \"1501874316\",\n      \"description\": \"The\
+        \ python-werkzeug rpms\",\n      \"fullname\": \"rpms/python-werkzeug\",\n\
+        \      \"id\": 19334,\n      \"milestones\": {},\n      \"name\": \"python-werkzeug\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"codeblock\",\n        \"name\"\
+        : \"codeblock\"\n      }\n    },\n    {\n      \"access_groups\": {\n    \
+        \    \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [],\n        \"owner\": [\n   \
+        \       \"orion\"\n        ],\n        \"ticket\": []\n      },\n      \"\
+        close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\": \"\
+        1501874318\",\n      \"date_modified\": \"1501874318\",\n      \"description\"\
+        : \"The python-workerpool rpms\",\n      \"fullname\": \"rpms/python-workerpool\"\
+        ,\n      \"id\": 19351,\n      \"milestones\": {},\n      \"name\": \"python-workerpool\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"orion\",\n        \"name\": \"\
+        orion\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n      \
+        \  \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"chandankumar\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874318\",\n      \"date_modified\": \"1501874319\"\
+        ,\n      \"description\": \"The python-wrapt rpms\",\n      \"fullname\":\
+        \ \"rpms/python-wrapt\",\n      \"id\": 19352,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-wrapt\",\n      \"namespace\": \"rpms\",\n     \
+        \ \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n  \
+        \      \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"chandankumar\",\n        \"name\": \"chandankumar\"\n      }\n    },\n\
+        \    {\n      \"access_groups\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"mstuchli\"\n        ],\n        \"owner\": [\n          \"cstratak\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874320\",\n   \
+        \   \"date_modified\": \"1501874320\",\n      \"description\": \"The python-wtf-peewee\
+        \ rpms\",\n      \"fullname\": \"rpms/python-wtf-peewee\",\n      \"id\":\
+        \ 19361,\n      \"milestones\": {},\n      \"name\": \"python-wtf-peewee\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n\
+        \        \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n    \
+        \    ],\n        \"owner\": [\n          \"fab\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874323\",\n      \"date_modified\": \"1501874323\"\
+        ,\n      \"description\": \"The python-xmltodict rpms\",\n      \"fullname\"\
+        : \"rpms/python-xmltodict\",\n      \"id\": 19378,\n      \"milestones\":\
+        \ {},\n      \"name\": \"python-xmltodict\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Fabian Affolter\",\n        \"name\": \"fab\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874327\",\n      \"date_modified\": \"1501874327\"\
+        ,\n      \"description\": \"The python-zanata2fedmsg rpms\",\n      \"fullname\"\
+        : \"rpms/python-zanata2fedmsg\",\n      \"id\": 19400,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-zanata2fedmsg\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"pbrobinson\"\n        ],\n        \"owner\": [\n          \"\
+        churchyard\"\n        ],\n        \"ticket\": []\n      },\n      \"close_status\"\
+        : [],\n      \"custom_keys\": [],\n      \"date_created\": \"1501874327\"\
+        ,\n      \"date_modified\": \"1501874327\",\n      \"description\": \"The\
+        \ python-zeroconf rpms\",\n      \"fullname\": \"rpms/python-zeroconf\",\n\
+        \      \"id\": 19407,\n      \"milestones\": {},\n      \"name\": \"python-zeroconf\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"churchyard\",\n        \"name\"\
+        : \"churchyard\"\n      }\n    },\n    {\n      \"access_groups\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n   \
+        \     ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n  \
+        \      \"admin\": [],\n        \"commit\": [\n          \"ralph\"\n      \
+        \  ],\n        \"owner\": [\n          \"tomspur\"\n        ],\n        \"\
+        ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874328\",\n      \"date_modified\": \"\
+        1501874328\",\n      \"description\": \"The python-zmq rpms\",\n      \"fullname\"\
+        : \"rpms/python-zmq\",\n      \"id\": 19410,\n      \"milestones\": {},\n\
+        \      \"name\": \"python-zmq\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"tomspur\",\n        \"name\":\
+        \ \"tomspur\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"tdabasin\",\n          \"abompard\"\n        ],\n       \
+        \ \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874328\",\n      \"date_modified\": \"1501874328\"\
+        ,\n      \"description\": \"The python-zope-component rpms\",\n      \"fullname\"\
+        : \"rpms/python-zope-component\",\n      \"id\": 19412,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-zope-component\",\n      \"namespace\": \"\
+        rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"tdabasin\",\n          \"abompard\"\
+        ,\n          \"bowlofeggs\",\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"lmacken\"\n        ],\n        \"ticket\": []\n  \
+        \    },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"\
+        date_created\": \"1501874328\",\n      \"date_modified\": \"1501874328\",\n\
+        \      \"description\": \"The python-zope-configuration rpms\",\n      \"\
+        fullname\": \"rpms/python-zope-configuration\",\n      \"id\": 19413,\n  \
+        \    \"milestones\": {},\n      \"name\": \"python-zope-configuration\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"lmacken\",\n        \"name\":\
+        \ \"lmacken\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n     \
+        \ },\n      \"access_users\": {\n        \"admin\": [],\n        \"commit\"\
+        : [\n          \"tdabasin\",\n          \"abompard\"\n        ],\n       \
+        \ \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874329\",\n      \"date_modified\": \"1501874329\"\
+        ,\n      \"description\": \"The python-zope-event rpms\",\n      \"fullname\"\
+        : \"rpms/python-zope-event\",\n      \"id\": 19418,\n      \"milestones\"\
+        : {},\n      \"name\": \"python-zope-event\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"tdabasin\",\n          \"abompard\"\
+        \n        ],\n        \"owner\": [\n          \"ralph\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874329\",\n      \"date_modified\": \"\
+        1501874330\",\n      \"description\": \"The python-zope-exceptions rpms\"\
+        ,\n      \"fullname\": \"rpms/python-zope-exceptions\",\n      \"id\": 19419,\n\
+        \      \"milestones\": {},\n      \"name\": \"python-zope-exceptions\",\n\
+        \      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tdabasin\",\n          \"abompard\"\n        ],\n        \"owner\"\
+        : [\n          \"ralph\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874330\",\n      \"date_modified\": \"1501874330\",\n      \"description\"\
+        : \"The python-zope-i18nmessageid rpms\",\n      \"fullname\": \"rpms/python-zope-i18nmessageid\"\
+        ,\n      \"id\": 19423,\n      \"milestones\": {},\n      \"name\": \"python-zope-i18nmessageid\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tdabasin\",\n          \"abompard\"\n        ],\n        \"owner\"\
+        : [\n          \"ralph\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874331\",\n      \"date_modified\": \"1501874331\",\n      \"description\"\
+        : \"The python-zope-schema rpms\",\n      \"fullname\": \"rpms/python-zope-schema\"\
+        ,\n      \"id\": 19428,\n      \"milestones\": {},\n      \"name\": \"python-zope-schema\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"tdabasin\",\n          \"abompard\"\n        ],\n        \"owner\"\
+        : [\n          \"ralph\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874331\",\n      \"date_modified\": \"1501874331\",\n      \"description\"\
+        : \"The python-zope-testing rpms\",\n      \"fullname\": \"rpms/python-zope-testing\"\
+        ,\n      \"id\": 19432,\n      \"milestones\": {},\n      \"name\": \"python-zope-testing\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"abompard\"\n        ],\n        \"owner\": [\n          \"jjames\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874331\",\n   \
+        \   \"date_modified\": \"1501874331\",\n      \"description\": \"The python-zope-testrunner\
+        \ rpms\",\n      \"fullname\": \"rpms/python-zope-testrunner\",\n      \"\
+        id\": 19433,\n      \"milestones\": {},\n      \"name\": \"python-zope-testrunner\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"jjames\",\n        \"name\": \"\
+        jjames\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"python-sig\"\n        ],\n     \
+        \   \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"mstuchli\"\n        ],\n       \
+        \ \"owner\": [\n          \"cstratak\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501865449\",\n      \"date_modified\": \"1501865449\"\
+        ,\n      \"description\": \"The RunSnakeRun rpms\",\n      \"fullname\": \"\
+        rpms/RunSnakeRun\",\n      \"id\": 374,\n      \"milestones\": {},\n     \
+        \ \"name\": \"RunSnakeRun\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    },\n    {\n      \"access_groups\"\
+        : {\n        \"admin\": [],\n        \"commit\": [],\n        \"ticket\":\
+        \ []\n      },\n      \"access_users\": {\n        \"admin\": [],\n      \
+        \  \"commit\": [],\n        \"owner\": [\n          \"abompard\"\n       \
+        \ ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n    \
+        \  \"custom_keys\": [],\n      \"date_created\": \"1501874684\",\n      \"\
+        date_modified\": \"1501874684\",\n      \"description\": \"The sassc rpms\"\
+        ,\n      \"fullname\": \"rpms/sassc\",\n      \"id\": 20986,\n      \"milestones\"\
+        : {},\n      \"name\": \"sassc\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"abompard\",\n        \"name\"\
+        : \"abompard\"\n      }\n    },\n    {\n      \"access_groups\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"python-sig\"\n    \
+        \    ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n   \
+        \     \"admin\": [],\n        \"commit\": [\n          \"jspaleta\",\n   \
+        \       \"orion\",\n          \"cstratak\",\n          \"limb\",\n       \
+        \   \"ttomecek\"\n        ],\n        \"owner\": [\n          \"tomspur\"\n\
+        \        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501874702\",\n   \
+        \   \"date_modified\": \"1501874703\",\n      \"description\": \"The scipy\
+        \ rpms\",\n      \"fullname\": \"rpms/scipy\",\n      \"id\": 21075,\n   \
+        \   \"milestones\": {},\n      \"name\": \"scipy\",\n      \"namespace\":\
+        \ \"rpms\",\n      \"parent\": null,\n      \"priorities\": {},\n      \"\
+        settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n\
+        \        \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"tomspur\",\n        \"name\": \"tomspur\"\n      }\n    },\n    {\n  \
+        \    \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"rkuska\",\n          \"ishcherb\",\n          \"torsava\"\n \
+        \       ],\n        \"owner\": [\n          \"bkabrda\"\n        ],\n    \
+        \    \"ticket\": []\n      },\n      \"close_status\": [],\n      \"custom_keys\"\
+        : [],\n      \"date_created\": \"1501874838\",\n      \"date_modified\": \"\
+        1501874838\",\n      \"description\": \"The spec2scl rpms\",\n      \"fullname\"\
+        : \"rpms/spec2scl\",\n      \"id\": 21510,\n      \"milestones\": {},\n  \
+        \    \"name\": \"spec2scl\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"bkabrda\",\n        \"name\":\
+        \ \"bkabrda\"\n      }\n    },\n    {\n      \"access_groups\": {\n      \
+        \  \"admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n      \
+        \  ],\n        \"ticket\": []\n      },\n      \"access_users\": {\n     \
+        \   \"admin\": [],\n        \"commit\": [\n          \"rtnpro\"\n        ],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501874902\",\n      \"date_modified\": \"1501874903\"\
+        ,\n      \"description\": \"The statscache rpms\",\n      \"fullname\": \"\
+        rpms/statscache\",\n      \"id\": 21659,\n      \"milestones\": {},\n    \
+        \  \"name\": \"statscache\",\n      \"namespace\": \"rpms\",\n      \"parent\"\
+        : null,\n      \"priorities\": {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"rtnpro\"\n        ],\n        \"\
+        owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n    \
+        \  },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874902\",\n      \"date_modified\": \"1501874902\",\n      \"description\"\
+        : \"The statscache-plugins rpms\",\n      \"fullname\": \"rpms/statscache-plugins\"\
+        ,\n      \"id\": 21658,\n      \"milestones\": {},\n      \"name\": \"statscache-plugins\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"kevin\"\n        ],\n        \"\
+        owner\": [\n          \"ralph\"\n        ],\n        \"ticket\": []\n    \
+        \  },\n      \"close_status\": [],\n      \"custom_keys\": [],\n      \"date_created\"\
+        : \"1501874948\",\n      \"date_modified\": \"1501874948\",\n      \"description\"\
+        : \"The supybot-fedmsg rpms\",\n      \"fullname\": \"rpms/supybot-fedmsg\"\
+        ,\n      \"id\": 21827,\n      \"milestones\": {},\n      \"name\": \"supybot-fedmsg\"\
+        ,\n      \"namespace\": \"rpms\",\n      \"parent\": null,\n      \"priorities\"\
+        : {},\n      \"settings\": {\n        \"Enforce_signed-off_commits_in_pull-request\"\
+        : false,\n        \"Minimum_score_to_merge_pull-request\": -1,\n        \"\
+        Only_assignee_can_merge_pull-request\": false,\n        \"Web-hooks\": null,\n\
+        \        \"always_merge\": false,\n        \"fedmsg_notifications\": true,\n\
+        \        \"issue_tracker\": true,\n        \"issues_default_to_private\":\
+        \ false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Ralph Bean\",\n        \"name\"\
+        : \"ralph\"\n      }\n    },\n    {\n      \"access_groups\": {\n        \"\
+        admin\": [],\n        \"commit\": [\n          \"infra-sig\"\n        ],\n\
+        \        \"ticket\": []\n      },\n      \"access_users\": {\n        \"admin\"\
+        : [],\n        \"commit\": [\n          \"kevin\",\n          \"jstanley\"\
+        ,\n          \"puiterwijk\",\n          \"ralph\"\n        ],\n        \"\
+        owner\": [\n          \"ianweller\"\n        ],\n        \"ticket\": []\n\
+        \      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n     \
+        \ \"date_created\": \"1501874948\",\n      \"date_modified\": \"1501874949\"\
+        ,\n      \"description\": \"The supybot-fedora rpms\",\n      \"fullname\"\
+        : \"rpms/supybot-fedora\",\n      \"id\": 21828,\n      \"milestones\": {},\n\
+        \      \"name\": \"supybot-fedora\",\n      \"namespace\": \"rpms\",\n   \
+        \   \"parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n\
+        \        \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"\
+        Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"ianweller\",\n        \"name\": \"ianweller\"\n      }\n    },\n    {\n\
+        \      \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"infra-sig\"\n        ],\n        \"ticket\": []\n      },\n \
+        \     \"access_users\": {\n        \"admin\": [],\n        \"commit\": [],\n\
+        \        \"owner\": [\n          \"ralph\"\n        ],\n        \"ticket\"\
+        : []\n      },\n      \"close_status\": [],\n      \"custom_keys\": [],\n\
+        \      \"date_created\": \"1501875115\",\n      \"date_modified\": \"1501875115\"\
+        ,\n      \"description\": \"The trac-fedmsg-plugin rpms\",\n      \"fullname\"\
+        : \"rpms/trac-fedmsg-plugin\",\n      \"id\": 22419,\n      \"milestones\"\
+        : {},\n      \"name\": \"trac-fedmsg-plugin\",\n      \"namespace\": \"rpms\"\
+        ,\n      \"parent\": null,\n      \"priorities\": {},\n      \"settings\"\
+        : {\n        \"Enforce_signed-off_commits_in_pull-request\": false,\n    \
+        \    \"Minimum_score_to_merge_pull-request\": -1,\n        \"Only_assignee_can_merge_pull-request\"\
+        : false,\n        \"Web-hooks\": null,\n        \"always_merge\": false,\n\
+        \        \"fedmsg_notifications\": true,\n        \"issue_tracker\": true,\n\
+        \        \"issues_default_to_private\": false,\n        \"project_documentation\"\
+        : false,\n        \"pull_request_access_only\": false,\n        \"pull_requests\"\
+        : true\n      },\n      \"tags\": [],\n      \"user\": {\n        \"fullname\"\
+        : \"Ralph Bean\",\n        \"name\": \"ralph\"\n      }\n    },\n    {\n \
+        \     \"access_groups\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"python-sig\"\n        ],\n        \"ticket\": []\n      },\n\
+        \      \"access_users\": {\n        \"admin\": [],\n        \"commit\": [\n\
+        \          \"mstuchli\"\n        ],\n        \"owner\": [\n          \"cstratak\"\
+        \n        ],\n        \"ticket\": []\n      },\n      \"close_status\": [],\n\
+        \      \"custom_keys\": [],\n      \"date_created\": \"1501875220\",\n   \
+        \   \"date_modified\": \"1501875221\",\n      \"description\": \"The unp rpms\"\
+        ,\n      \"fullname\": \"rpms/unp\",\n      \"id\": 22729,\n      \"milestones\"\
+        : {},\n      \"name\": \"unp\",\n      \"namespace\": \"rpms\",\n      \"\
+        parent\": null,\n      \"priorities\": {},\n      \"settings\": {\n      \
+        \  \"Enforce_signed-off_commits_in_pull-request\": false,\n        \"Minimum_score_to_merge_pull-request\"\
+        : -1,\n        \"Only_assignee_can_merge_pull-request\": false,\n        \"\
+        Web-hooks\": null,\n        \"always_merge\": false,\n        \"fedmsg_notifications\"\
+        : true,\n        \"issue_tracker\": true,\n        \"issues_default_to_private\"\
+        : false,\n        \"project_documentation\": false,\n        \"pull_request_access_only\"\
+        : false,\n        \"pull_requests\": true\n      },\n      \"tags\": [],\n\
+        \      \"user\": {\n        \"fullname\": \"Charalampos Stratakis\",\n   \
+        \     \"name\": \"cstratak\"\n      }\n    }\n  ],\n  \"user\": {\n    \"\
+        fullname\": \"abompard\",\n    \"name\": \"abompard\"\n  }\n}"}
+    headers:
+      AppServer: [proxy10.phx2.fedoraproject.org]
+      AppTime: [D=10332807]
+      Connection: [Keep-Alive]
+      Content-Length: ['353146']
+      Content-Type: [application/json]
+      Date: ['Mon, 07 Aug 2017 14:54:51 GMT']
+      Keep-Alive: ['timeout=15, max=500']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_auth_gssapi/1.4.0
+          mod_wsgi/3.4 Python/2.7.5]
+      Set-Cookie: ['disgit_pagure=eyJfcGVybWFuZW50Ijp0cnVlfQ.DGoQxQ.35lhBIibCNeGWKEEQBOvRdBeoJA;
+          Expires=Thu, 07-Sep-2017 14:55:01 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages b/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages
deleted file mode 100644
index 764dd50..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages
+++ /dev/null
@@ -1,451 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://admin.fedoraproject.org/pkgdb/api/packager/package/abompard
-  response:
-    body: {string: "{\n  \"co-maintained\": [\n    {\n      \"acls\": [],\n      \"\
-        creation_date\": 1430239258.0,\n      \"description\": \"contextlib2 is a\
-        \ backport of the standard library's contextlib module to\\nearlier Python\
-        \ versions.\\n\\nIt also serves as a real world proving ground for possible\
-        \ future\\nenhancements to the standard library version.\",\n      \"koschei_monitor\"\
-        : false,\n      \"monitor\": true,\n      \"name\": \"python-contextlib2\"\
-        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1210978\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Backports and enhancements\
-        \ for the contextlib module\",\n      \"upstream_url\": \"https://pypi.io/project/contextlib2\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"This is a lib package for use by pytest-cov, nose-cov\
-        \ and nose2-cov. If\\nyou're developing a coverage plugin for a test framework\
-        \ then you probably\\nwant one of those.\",\n      \"koschei_monitor\": false,\n\
-        \      \"monitor\": false,\n      \"name\": \"python-cov-core\",\n      \"\
-        namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\": \"\
-        Approved\",\n      \"summary\": \"Plugin core for use by pytest-cov, nose-cov\
-        \ and nose2-cov\",\n      \"upstream_url\": \"http://bitbucket.org/memedough/cov-core/overview\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"Coverage.py is a Python module that measures code\
-        \ coverage during Python\\nexecution. It uses the code analysis tools and\
-        \ tracing hooks provided in the\\nPython standard library to determine which\
-        \ lines are executable, and which\\nhave been executed.\",\n      \"koschei_monitor\"\
-        : false,\n      \"monitor\": true,\n      \"name\": \"python-coverage\",\n\
-        \      \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
-        : \"Approved\",\n      \"summary\": \"Code coverage testing module for Python\"\
-        ,\n      \"upstream_url\": \"http://nedbatchelder.com/code/modules/coverage.html\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1437659169.0,\n\
-        \      \"description\": \"DDT (Data-Driven Tests) allows you to multiply one\
-        \ test case by running it with\\ndifferent test data, and make it appear as\
-        \ multiple test cases. It is used in\\ncombination with other testing frameworks\
-        \ like unittest and nose.\",\n      \"koschei_monitor\": true,\n      \"monitor\"\
-        : true,\n      \"name\": \"python-ddt\",\n      \"namespace\": \"rpms\",\n\
-        \      \"review_url\": \"https://bugzilla.redhat.com/1244014\",\n      \"\
-        status\": \"Approved\",\n      \"summary\": \"Python library to multiply test\
-        \ cases\",\n      \"upstream_url\": \"https://github.com/txels/ddt\"\n   \
-        \ },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"Falcon is a high-performance Python framework for\
-        \ building cloud APIs.\\nIt encourages the REST architectural style, and tries\
-        \ to do as little as\\npossible while remaining highly effective.\",\n   \
-        \   \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
-        : \"python-falcon\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
-        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"An unladen\
-        \ web framework for building APIs and app backends\",\n      \"upstream_url\"\
-        : \"https://falconframework.org\"\n    },\n    {\n      \"acls\": [],\n  \
-        \    \"creation_date\": 1400070978.0,\n      \"description\": \"A comprehensive\
-        \ HTTP client library that supports many features left out of\\nother HTTP\
-        \ libraries.\",\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n\
-        \      \"name\": \"python-httplib2\",\n      \"namespace\": \"rpms\",\n  \
-        \    \"review_url\": null,\n      \"status\": \"Approved\",\n      \"summary\"\
-        : \"A comprehensive HTTP client library\",\n      \"upstream_url\": \"https://pypi.python.org/pypi/httplib2\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"This module provides basic functions for parsing\
-        \ mime-type names\\nand matching them against a list of media-ranges.\",\n\
-        \      \"koschei_monitor\": false,\n      \"monitor\": false,\n      \"name\"\
-        : \"python-mimeparse\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
-        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"Python module\
-        \ for parsing mime-type names\",\n      \"upstream_url\": \"https://github.com/dbtsai/python-mimeparse\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"Passlib is a password hashing library for Python\
-        \ 2 & 3, which provides\\ncross-platform implementations of over 20 password\
-        \ hashing algorithms,\\nas well as a framework for managing existing password\
-        \ hashes. It's\\ndesigned to be useful for a wide range of tasks, from verifying\
-        \ a hash\\nfound in /etc/shadow, to providing full-strength password hashing\
-        \ for\\nmulti-user application.\",\n      \"koschei_monitor\": false,\n  \
-        \    \"monitor\": true,\n      \"name\": \"python-passlib\",\n      \"namespace\"\
-        : \"rpms\",\n      \"review_url\": null,\n      \"status\": \"Approved\",\n\
-        \      \"summary\": \"Comprehensive password hashing framework supporting\
-        \ over 20 schemes\",\n      \"upstream_url\": \"https://bitbucket.org/ecollins/passlib\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1462278195.0,\n\
-        \      \"description\": \"A fork of SocksiPy with bug fixes and extra features.\\\
-        n\\nActs as a drop-in replacement to the socket module. Featuring:\\n\\n-\
-        \ SOCKS proxy client for Python 2.6 - 3.x\\n- TCP and UDP both supported\\\
-        n- HTTP proxy client included but not supported or recommended (you should\
-        \ use\\n  urllib2's or requests' own HTTP proxy interface)\\n- urllib2 handler\
-        \ included.\",\n      \"koschei_monitor\": true,\n      \"monitor\": \"nobuild\"\
-        ,\n      \"name\": \"python-pysocks\",\n      \"namespace\": \"rpms\",\n \
-        \     \"review_url\": \"https://bugzilla.redhat.com/1332206\",\n      \"status\"\
-        : \"Approved\",\n      \"summary\": \"A Python SOCKS client module\",\n  \
-        \    \"upstream_url\": \"https://github.com/Anorov/PySocks\"\n    },\n   \
-        \ {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"\
-        description\": \"testtools is a set of extensions to the Python standard library's\
-        \ unit testing\\nframework.\",\n      \"koschei_monitor\": false,\n      \"\
-        monitor\": true,\n      \"name\": \"python-testtools\",\n      \"namespace\"\
-        : \"rpms\",\n      \"review_url\": null,\n      \"status\": \"Approved\",\n\
-        \      \"summary\": \"Extensions to the Python unit testing framework\",\n\
-        \      \"upstream_url\": \"https://launchpad.net/testtools\"\n    },\n   \
-        \ {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"\
-        description\": \"This package represents the core of the Zope Component Architecture.\\\
-        nTogether with the 'zope.interface' package, it provides facilities for\\\
-        ndefining, registering and looking up components.\",\n      \"koschei_monitor\"\
-        : false,\n      \"monitor\": true,\n      \"name\": \"python-zope-component\"\
-        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
-        : \"Approved\",\n      \"summary\": \"Zope Component Architecture\",\n   \
-        \   \"upstream_url\": \"https://pypi.io/project/zope.component\"\n    },\n\
-        \    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n    \
-        \  \"description\": \"The zope configuration system provides an extensible\
-        \ system for supporting\\nvarious kinds of configurations.\\n\\nIt is based\
-        \ on the idea of configuration directives. Users of the configuration\\nsystem\
-        \ provide configuration directives in some language that express\\nconfiguration\
-        \ choices. The intent is that the language be pluggable. An XML\\nlanguage\
-        \ is provided by default.\",\n      \"koschei_monitor\": true,\n      \"monitor\"\
-        : true,\n      \"name\": \"python-zope-configuration\",\n      \"namespace\"\
-        : \"rpms\",\n      \"review_url\": null,\n      \"status\": \"Approved\",\n\
-        \      \"summary\": \"Zope Configuration Markup Language (ZCML)\",\n     \
-        \ \"upstream_url\": \"https://github.com/zopefoundation/zope.configuration\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"The zope.event package provides a simple event system.\
-        \ It provides\\nan event publishing system and a very simple event-dispatching\
-        \ system\\non which more sophisticated event dispatching systems can be built.\\\
-        n(For example, a type-based event dispatching system that builds on\\nzope.event\
-        \ can be found in zope.component.)\",\n      \"koschei_monitor\": false,\n\
-        \      \"monitor\": true,\n      \"name\": \"python-zope-event\",\n      \"\
-        namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\": \"\
-        Approved\",\n      \"summary\": \"Zope Event Publication\",\n      \"upstream_url\"\
-        : \"http://pypi.python.org/pypi/zope.event/\"\n    },\n    {\n      \"acls\"\
-        : [],\n      \"creation_date\": 1400070978.0,\n      \"description\": \"This\
-        \ package contains exception interfaces and implementations which are so\\\
-        ngeneral purpose that they don't belong in Zope application-specific packages.\"\
-        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
-        : \"python-zope-exceptions\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
-        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope Exceptions\"\
-        ,\n      \"upstream_url\": \"http://pypi.python.org/pypi/zope.exceptions\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"This module provides message identifiers for internationalization.\"\
-        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
-        : \"python-zope-i18nmessageid\",\n      \"namespace\": \"rpms\",\n      \"\
-        review_url\": null,\n      \"status\": \"Approved\",\n      \"summary\": \"\
-        Message Identifiers for internationalization\",\n      \"upstream_url\": \"\
-        http://pypi.python.org/pypi/zope.i18nmessageid\"\n    },\n    {\n      \"\
-        acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
-        : \"This package is a zope.interface extension for defining data schemas.\"\
-        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
-        : \"python-zope-schema\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
-        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope 3 schemas\"\
-        ,\n      \"upstream_url\": \"http://pypi.python.org/pypi/zope.schema\"\n \
-        \   },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"This package provides a number of testing frameworks.\
-        \ It includes a\\nflexible test runner, and supports both doctest and unittest.\"\
-        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
-        : \"python-zope-testing\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
-        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope Testing\
-        \ Framework\",\n      \"upstream_url\": \"https://pypi.io/project/zope.testing\"\
-        \n    }\n  ],\n  \"output\": \"ok\",\n  \"point of contact\": [\n    {\n \
-        \     \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
-        : \"Grisbi is a very functional personal financial management program\\nwith\
-        \ a lot of features: checking, cash and liabilities accounts,\\nseveral accounts\
-        \ with automatic contra entries, several currencies,\\nincluding euro, arbitrary\
-        \ currency for every operation, money\\ninterchange fees, switch to euro account\
-        \ per account, description\\nof the transactions with third parties, categories,\
-        \ sub-categories,\\nfinancial year, notes, breakdown, transfers between accounts,\
-        \ even\\nfor accounts of different currencies, bank reconciliation, scheduled\\\
-        ntransactions, automatic recall of last transaction for every third\\nparty,\
-        \ nice and easy user interface, user manual, QIF import/export.\",\n     \
-        \ \"koschei_monitor\": false,\n      \"monitor\": false,\n      \"name\":\
-        \ \"grisbi\",\n      \"namespace\": \"rpms\",\n      \"review_url\": null,\n\
-        \      \"status\": \"Approved\",\n      \"summary\": \"Personal finances manager\"\
-        ,\n      \"upstream_url\": \"http://www.grisbi.org\"\n    },\n    {\n    \
-        \  \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
-        : \"KeePassX is an application for people with extremly high demands on secure\\\
-        npersonal data management.\\nKeePassX saves many different information e.g.\
-        \ user names, passwords, urls,\\nattachemts and comments in one single database.\
-        \ For a better management\\nuser-defined titles and icons can be specified\
-        \ for each single entry.\\nFurthermore the entries are sorted in groups, which\
-        \ are customizable as well.\\nThe integrated search function allows to search\
-        \ in a single group or the\\ncomplete database.\\nKeePassX offers a little\
-        \ utility for secure password generation. The password\\ngenerator is very\
-        \ customizable, fast and easy to use. Especially someone who\\ngenerates passwords\
-        \ frequently will appreciate this feature.\\nThe complete database is always\
-        \ encrypted either with AES (alias Rijndael) or\\nTwofish encryption algorithm\
-        \ using a 256 bit key. Therefore the saved\\ninformation can be considered\
-        \ as quite safe. KeePassX uses a database format\\nthat is compatible with\
-        \ KeePass Password Safe v2 for MS Windows.\",\n      \"koschei_monitor\":\
-        \ false,\n      \"monitor\": false,\n      \"name\": \"keepassx\",\n     \
-        \ \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
-        : \"Approved\",\n      \"summary\": \"Cross-platform password manager\",\n\
-        \      \"upstream_url\": \"http://www.keepassx.org/\"\n    },\n    {\n   \
-        \   \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
-        : \"A ssh-add helper that uses kwallet and kpassworddialog.\",\n      \"koschei_monitor\"\
-        : false,\n      \"monitor\": true,\n      \"name\": \"ksshaskpass\",\n   \
-        \   \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
-        : \"Approved\",\n      \"summary\": \"A ssh-add helper that uses kwallet and\
-        \ kpassworddialog\",\n      \"upstream_url\": \"https://cgit.kde.org/ksshaskpass.git\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1474548104.0,\n\
-        \      \"description\": \"Libsass is a C/C++ port of the Sass CSS precompiler.\
-        \ The original version was\\nwritten in Ruby, but this version is meant for\
-        \ efficiency and portability.\\n\\nThis library strives to be light, simple,\
-        \ and easy to build and integrate with\\na variety of platforms and languages.\\\
-        n\\nLibsass is just a library, but if you want to RUN libsass, install the\
-        \ sassc\\npackage.\",\n      \"koschei_monitor\": true,\n      \"monitor\"\
-        : true,\n      \"name\": \"libsass\",\n      \"namespace\": \"rpms\",\n  \
-        \    \"review_url\": \"https://bugzilla.redhat.com/1369534\",\n      \"status\"\
-        : \"Approved\",\n      \"summary\": \"C/C++ port of the Sass CSS precompiler\"\
-        ,\n      \"upstream_url\": \"http://sass-lang.com/libsass\"\n    },\n    {\n\
-        \      \"acls\": [],\n      \"creation_date\": 1496666386.0,\n      \"description\"\
-        : \"This is a server for SMTP and related protocols, similar in utility\\\
-        r\\nto the standard library\\u2019s smtpd.py module, but rewritten to be based\\\
-        r\\non asyncio for Python 3.\",\n      \"koschei_monitor\": true,\n      \"\
-        monitor\": true,\n      \"name\": \"python-aiosmtpd\",\n      \"namespace\"\
-        : \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1404883\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Asyncio-based SMTP\
-        \ server\",\n      \"upstream_url\": \"https://github.com/aio-libs/aiosmtpd\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1496666324.0,\n\
-        \      \"description\": \"This is a very simple decorator and function which\
-        \ populates a \\r\\nmodule's __all__ and optionally the module globals. \\\
-        r\\nThis provides both a pure-Python implementation and a C implementation.\
-        \ \\r\\nIt is proposed that the C implementation be added to built-ins for\
-        \ \\r\\nPython 3.6.\",\n      \"koschei_monitor\": true,\n      \"monitor\"\
-        : true,\n      \"name\": \"python-atpublic\",\n      \"namespace\": \"rpms\"\
-        ,\n      \"review_url\": \"https://bugzilla.redhat.com/1404882\",\n      \"\
-        status\": \"Approved\",\n      \"summary\": \"Decorator for populating a Python\
-        \ module's __all__\",\n      \"upstream_url\": \"http://public.readthedocs.io\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1496666808.0,\n\
-        \      \"description\": \"Blessed is a thin, practical wrapper around terminal\
-        \ styling, screen\\r\\npositioning, and keyboard input.\",\n      \"koschei_monitor\"\
-        : true,\n      \"monitor\": true,\n      \"name\": \"python-blessed\",\n \
-        \     \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1435986\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"A thin, practical\
-        \ wrapper around terminal capabilities in Python\",\n      \"upstream_url\"\
-        : \"https://pypi.python.org/pypi/blessed\"\n    },\n    {\n      \"acls\"\
-        : [],\n      \"creation_date\": 1476188786.0,\n      \"description\": \"The\
-        \ flufl.bounce library provides a set of heuristics and an API for\\ndetecting\
-        \ the original bouncing email addresses from a bounce message.  Many\\nformats\
-        \ found in the wild are supported, as are VERP and RFC 3464 (DSN).\",\n  \
-        \    \"koschei_monitor\": true,\n      \"monitor\": true,\n      \"name\"\
-        : \"python-flufl-bounce\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
-        : \"https://bugzilla.redhat.com/1375999\",\n      \"status\": \"Approved\"\
-        ,\n      \"summary\": \"Email bounce detectors\",\n      \"upstream_url\"\
-        : \"https://gitlab.com/warsaw/flufl.bounce\"\n    },\n    {\n      \"acls\"\
-        : [],\n      \"creation_date\": 1476188935.0,\n      \"description\": \"The\
-        \ ``flufl.i18n`` library provides a convenient API for managing translation\\\
-        ncontexts in Python applications. It provides facilities not only for\\nsingle-context\
-        \ applications like command line scripts, but also more\\nsophisticated management\
-        \ of multiple-context applications such as Internet\\nservers.\",\n      \"\
-        koschei_monitor\": true,\n      \"monitor\": true,\n      \"name\": \"python-flufl-i18n\"\
-        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1375993\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"A high level API\
-        \ for Python internationalization\",\n      \"upstream_url\": \"https://gitlab.com/warsaw/flufl.i18n\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1476188827.0,\n\
-        \      \"description\": \"The flufl.lock library provides an NFS-safe file-based\
-        \ locking algorithm\\ninfluenced by the GNU/Linux \\\"open(2)\\\" man page,\
-        \ under the description of\\nthe \\\"O_EXCL\\\" option.\",\n      \"koschei_monitor\"\
-        : true,\n      \"monitor\": true,\n      \"name\": \"python-flufl-lock\",\n\
-        \      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1376001\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"NFS-safe file locking\
-        \ with timeouts for POSIX systems\",\n      \"upstream_url\": \"https://gitlab.com/warsaw/flufl.lock\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1481720827.0,\n\
-        \      \"description\": \"This package contains a small collection of test\
-        \ helpers that Barry Warsaw\\nuses in almost all his packages. Specifically,\
-        \ plugins for the following\\ntest tools are provided:\\n- nose2\\n- flake8\\\
-        nPython 3.4 is the minimum supported version.\",\n      \"koschei_monitor\"\
-        : true,\n      \"monitor\": true,\n      \"name\": \"python-flufl-testing\"\
-        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1401582\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Small collection\
-        \ of test tool plugins\",\n      \"upstream_url\": \"https://gitlab.com/warsaw/flufl.testing\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1481720722.0,\n\
-        \      \"description\": \"The LAZR config system is typically used to manage\
-        \ process configuration.\\nProcess configuration is for saying how things\
-        \ change when we run systems on\\ndifferent machines, or under different circumstances.\\\
-        n\\nThis system uses ini-like file format of section, keys, and values. The\
-        \ config\\nfile supports inheritance to minimize duplication of information\
-        \ across files.\\nThe format supports schema validation.\",\n      \"koschei_monitor\"\
-        : true,\n      \"monitor\": true,\n      \"name\": \"python-lazr-config\"\
-        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1387518\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Create configuration\
-        \ schemas, and process and validate configurations\",\n      \"upstream_url\"\
-        : \"https://launchpad.net/lazr.config\"\n    },\n    {\n      \"acls\": [],\n\
-        \      \"creation_date\": 1477410675.0,\n      \"description\": \"The lazr.delegates\
-        \ package makes it easy to write objects that delegate\\nbehavior to another\
-        \ object. The new object adds some property or behavior on\\nto the other\
-        \ object, while still providing the underlying interface, and\\ndelegating\
-        \ behavior.\",\n      \"koschei_monitor\": true,\n      \"monitor\": true,\n\
-        \      \"name\": \"python-lazr-delegates\",\n      \"namespace\": \"rpms\"\
-        ,\n      \"review_url\": \"https://bugzilla.redhat.com/1387291\",\n      \"\
-        status\": \"Approved\",\n      \"summary\": \"Easily write objects that delegate\
-        \ behavior\",\n      \"upstream_url\": \"https://launchpad.net/lazr.delegates\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1479219121.0,\n\
-        \      \"description\": \"This is LAZR smtptest, a framework for testing SMTP-based\
-        \ applications and\\nlibraries. It provides a real, live SMTP server that\
-        \ you can send messages\\nto, and from which you can read those test messages.\
-        \ This can be used to\\nensure proper operation of your applications which\
-        \ send email.\",\n      \"koschei_monitor\": true,\n      \"monitor\": true,\n\
-        \      \"name\": \"python-lazr-smtptest\",\n      \"namespace\": \"rpms\"\
-        ,\n      \"review_url\": \"https://bugzilla.redhat.com/1387250\",\n      \"\
-        status\": \"Approved\",\n      \"summary\": \"Test framework for SMTP-based\
-        \ applications\",\n      \"upstream_url\": \"https://launchpad.net/lazr.smtptest\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"Mako is a template library written in Python. It\
-        \ provides a familiar, non-XML\\nsyntax which compiles into Python modules\
-        \ for maximum performance. Mako's\\nsyntax and API borrows from the best ideas\
-        \ of many others, including Django\\ntemplates, Cheetah, Myghty, and Genshi.\
-        \ Conceptually, Mako is an embedded\\nPython (i.e. Python Server Page) language,\
-        \ which refines the familiar ideas of\\ncomponentized layout and inheritance\
-        \ to produce one of the most straightforward\\nand flexible models available,\
-        \ while also maintaining close ties to Python\\ncalling and scoping semantics.\"\
-        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
-        : \"python-mako\",\n      \"namespace\": \"rpms\",\n      \"review_url\":\
-        \ null,\n      \"status\": \"Approved\",\n      \"summary\": \"Mako template\
-        \ library for Python\",\n      \"upstream_url\": \"http://www.makotemplates.org/\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1474373839.0,\n\
-        \      \"description\": \"nose2 is the next generation of nicer testing for\
-        \ Python, based on the plugins\\nbranch of unittest2. nose2 aims to improve\
-        \ on nose by:\\n- providing a better plugin API\\n- being easier for users\
-        \ to configure\\n- simplifying internal interfaces and processes\\n- supporting\
-        \ Python 2 and 3 from the same codebase, without translation\\n- encouraging\
-        \ greater community involvement in its development\\n\\nIn service of some\
-        \ those goals, some features of nose will not be supported in\\nnose2. See\
-        \ the documentation for a thorough rundown.\",\n      \"koschei_monitor\"\
-        : true,\n      \"monitor\": true,\n      \"name\": \"python-nose2\",\n   \
-        \   \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1375926\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Next generation of\
-        \ nicer testing for Python\",\n      \"upstream_url\": \"https://nose2.readthedocs.org\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"pylibmc is a client in Python for memcached. It\
-        \ is a wrapper\\naround TangentOrg\\u2018s libmemcached library. The interface\
-        \ is\\nintentionally made as close to python-memcached as possible,\\nso that\
-        \ applications can drop-in replace it.\",\n      \"koschei_monitor\": false,\n\
-        \      \"monitor\": false,\n      \"name\": \"python-pylibmc\",\n      \"\
-        namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\": \"\
-        Approved\",\n      \"summary\": \"Memcached client for Python\",\n      \"\
-        upstream_url\": \"http://sendapatch.se/projects/pylibmc/\"\n    },\n    {\n\
-        \      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n      \"description\"\
-        : \"Most existing Python modules for sending HTTP requests are extremely verbose\
-        \ and\\ncumbersome. Python\\u2019s built-in urllib2 module provides most of\
-        \ the HTTP\\ncapabilities you should need, but the API is thoroughly broken.\
-        \ This library is\\ndesigned to make HTTP requests easy for developers.\"\
-        ,\n      \"koschei_monitor\": false,\n      \"monitor\": true,\n      \"name\"\
-        : \"python-requests\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
-        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"HTTP library,\
-        \ written in Python, for human beings\",\n      \"upstream_url\": \"https://pypi.io/project/requests\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"Tornado is an open source version of the scalable,\
-        \ non-blocking web\\nserver and tools.\\n\\nThe framework is distinct from\
-        \ most mainstream web server frameworks\\n(and certainly most Python frameworks)\
-        \ because it is non-blocking and\\nreasonably fast. Because it is non-blocking\
-        \ and uses epoll, it can\\nhandle thousands of simultaneous standing connections,\
-        \ which means it is\\nideal for real-time web services.\",\n      \"koschei_monitor\"\
-        : true,\n      \"monitor\": true,\n      \"name\": \"python-tornado\",\n \
-        \     \"namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\"\
-        : \"Approved\",\n      \"summary\": \"Scalable, non-blocking web server and\
-        \ tools\",\n      \"upstream_url\": \"http://www.tornadoweb.org\"\n    },\n\
-        \    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n    \
-        \  \"description\": \"Python HTTP module with connection pooling and file\
-        \ POST abilities.\",\n      \"koschei_monitor\": false,\n      \"monitor\"\
-        : true,\n      \"name\": \"python-urllib3\",\n      \"namespace\": \"rpms\"\
-        ,\n      \"review_url\": null,\n      \"status\": \"Approved\",\n      \"\
-        summary\": \"Python HTTP library with thread-safe connection pooling and file\
-        \ post\",\n      \"upstream_url\": \"https://github.com/shazow/urllib3\"\n\
-        \    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1400070978.0,\n\
-        \      \"description\": \"Werkzeug\\n========\\n\\nWerkzeug started as simple\
-        \ collection of various utilities for WSGI\\napplications and has become one\
-        \ of the most advanced WSGI utility\\nmodules.  It includes a powerful debugger,\
-        \ full featured request and\\nresponse objects, HTTP utilities to handle entity\
-        \ tags, cache control\\nheaders, HTTP dates, cookie handling, file uploads,\
-        \ a powerful URL\\nrouting system and a bunch of community contributed addon\
-        \ modules.\\n\\nWerkzeug is unicode aware and doesn't enforce a specific template\\\
-        nengine, database adapter or anything else.  It doesn't even enforce\\na specific\
-        \ way of handling requests and leaves all that up to the\\ndeveloper. It's\
-        \ most useful for end user applications which should work\\non as many server\
-        \ environments as possible (such as blogs, wikis,\\nbulletin boards, etc.).\"\
-        ,\n      \"koschei_monitor\": true,\n      \"monitor\": true,\n      \"name\"\
-        : \"python-werkzeug\",\n      \"namespace\": \"rpms\",\n      \"review_url\"\
-        : null,\n      \"status\": \"Approved\",\n      \"summary\": \"The Swiss Army\
-        \ knife of Python web development\",\n      \"upstream_url\": \"http://werkzeug.pocoo.org/\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1465852253.0,\n\
-        \      \"description\": \"This package provides a flexible test runner with\
-        \ layer support.\",\n      \"koschei_monitor\": true,\n      \"monitor\":\
-        \ true,\n      \"name\": \"python-zope-testrunner\",\n      \"namespace\"\
-        : \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1341815\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope testrunner script\"\
-        ,\n      \"upstream_url\": \"https://pypi.python.org/pypi/zope.testrunner\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1481116746.0,\n\
-        \      \"description\": \"The zope.event package provides a simple event system.\
-        \ It provides\\nan event publishing system and a very simple event-dispatching\
-        \ system\\non which more sophisticated event dispatching systems can be built.\\\
-        n(For example, a type-based event dispatching system that builds on\\nzope.event\
-        \ can be found in zope.component.)\",\n      \"koschei_monitor\": true,\n\
-        \      \"monitor\": true,\n      \"name\": \"python3-zope-event\",\n     \
-        \ \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1395244\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope Event Publication\"\
-        ,\n      \"upstream_url\": \"http://pypi.python.org/pypi/zope.event/\"\n \
-        \   },\n    {\n      \"acls\": [],\n      \"creation_date\": 1481289213.0,\n\
-        \      \"description\": \"Interfaces are a mechanism for labeling objects\
-        \ as conforming to a given API\\nor contract.\\nThis is a separate distribution\
-        \ of the zope.interface package used in Zope 3.\",\n      \"koschei_monitor\"\
-        : true,\n      \"monitor\": true,\n      \"name\": \"python3-zope-interface\"\
-        ,\n      \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1395255\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Zope 3 Interface\
-        \ Infrastructure\",\n      \"upstream_url\": \"https://pypi.io/project/zope.interface\"\
-        \n    },\n    {\n      \"acls\": [],\n      \"creation_date\": 1479138409.0,\n\
-        \      \"description\": \"SassC is a wrapper around libsass used to generate\
-        \ a useful command-line\\napplication that can be installed and packaged for\
-        \ several operating systems.\",\n      \"koschei_monitor\": true,\n      \"\
-        monitor\": true,\n      \"name\": \"sassc\",\n      \"namespace\": \"rpms\"\
-        ,\n      \"review_url\": \"https://bugzilla.redhat.com/1369535\",\n      \"\
-        status\": \"Approved\",\n      \"summary\": \"Wrapper around libsass to compile\
-        \ CSS stylesheet\",\n      \"upstream_url\": \"http://github.com/sass/sassc\"\
-        \n    }\n  ],\n  \"watch\": [\n    {\n      \"acls\": [],\n      \"creation_date\"\
-        : 1400070978.0,\n      \"description\": \"Advanced Web Statistics is a powerful\
-        \ and featureful tool that generates\\nadvanced web server graphic statistics.\
-        \ This server log analyzer works\\nfrom command line or as a CGI and shows\
-        \ you all information your log contains,\\nin graphical web pages. It can\
-        \ analyze a lot of web/wap/proxy servers like\\nApache, IIS, Weblogic, Webstar,\
-        \ Squid, ... but also mail or ftp servers.\\n\\nThis program can measure visits,\
-        \ unique vistors, authenticated users, pages,\\ndomains/countries, OS busiest\
-        \ times, robot visits, type of files, search\\nengines/keywords used, visits\
-        \ duration, HTTP errors and more...\\nStatistics can be updated from a browser\
-        \ or your scheduler.\\nThe program also supports virtual servers, plugins\
-        \ and a lot of features.\\n\\nWith the default configuration, the statistics\
-        \ are available:\\nhttp://localhost/awstats/awstats.pl\",\n      \"koschei_monitor\"\
-        : true,\n      \"monitor\": true,\n      \"name\": \"awstats\",\n      \"\
-        namespace\": \"rpms\",\n      \"review_url\": null,\n      \"status\": \"\
-        Approved\",\n      \"summary\": \"Advanced Web Statistics\",\n      \"upstream_url\"\
-        : \"http://awstats.sourceforge.net\"\n    },\n    {\n      \"acls\": [],\n\
-        \      \"creation_date\": 1452111332.0,\n      \"description\": \"This API\
-        \ is mainly for Terminal Emulator implementors, or those writing programs\\\
-        nthat expect to interpreted by a terminal emulator and wish to determine the\\\
-        nprintable width of a string on a Terminal.\",\n      \"koschei_monitor\"\
-        : true,\n      \"monitor\": true,\n      \"name\": \"python-wcwidth\",\n \
-        \     \"namespace\": \"rpms\",\n      \"review_url\": \"https://bugzilla.redhat.com/1295152\"\
-        ,\n      \"status\": \"Approved\",\n      \"summary\": \"Measures number of\
-        \ Terminal column cells of wide-character codes\",\n      \"upstream_url\"\
-        : \"https://github.com/jquast/wcwidth\"\n    }\n  ]\n}"}
-    headers:
-      Accept-Ranges: [bytes]
-      Age: ['0']
-      AppServer: [proxy06.fedoraproject.org]
-      AppTime: [D=293465]
-      Connection: [Keep-Alive]
-      Content-Length: ['30176']
-      Content-Type: [application/json]
-      Date: ['Thu, 15 Jun 2017 15:04:24 GMT']
-      Keep-Alive: ['timeout=15, max=500']
-      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      Set-Cookie: ['pkgdb=eyJfcGVybWFuZW50Ijp0cnVlfQ.DCQzeA.1B01lt3fuPret9GeJCOsCK6JptU;
-          Expires=Thu, 15-Jun-2017 16:04:24 GMT; Secure; HttpOnly; Path=/pkgdb/']
-      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
-      Via: [1.1 varnish-v4]
-      X-Varnish: ['23219393']
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages_invalid b/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages_invalid
deleted file mode 100644
index fd196e2..0000000
--- a/hubs/tests/vcr-request-data/hubs.tests.utils.test_pkgdb.PkgdbUtilsTest.test_get_owned_packages_invalid
+++ /dev/null
@@ -1,30 +0,0 @@
-interactions:
-- request:
-    body: null
-    headers:
-      Accept: ['*/*']
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      User-Agent: [python-requests/2.13.0]
-    method: GET
-    uri: https://admin.fedoraproject.org/pkgdb/api/packager/package/abompard
-  response:
-    body: {string: "this is invalid"}
-    headers:
-      Accept-Ranges: [bytes]
-      Age: ['0']
-      AppServer: [proxy06.fedoraproject.org]
-      AppTime: [D=293465]
-      Connection: [Keep-Alive]
-      Content-Length: ['30176']
-      Content-Type: [application/json]
-      Date: ['Thu, 15 Jun 2017 15:04:24 GMT']
-      Keep-Alive: ['timeout=15, max=500']
-      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5]
-      Set-Cookie: ['pkgdb=eyJfcGVybWFuZW50Ijp0cnVlfQ.DCQzeA.1B01lt3fuPret9GeJCOsCK6JptU;
-          Expires=Thu, 15-Jun-2017 16:04:24 GMT; Secure; HttpOnly; Path=/pkgdb/']
-      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
-      Via: [1.1 varnish-v4]
-      X-Varnish: ['23219393']
-    status: {code: 200, message: OK}
-version: 1
diff --git a/hubs/utils/packages.py b/hubs/utils/packages.py
new file mode 100644
index 0000000..0335ceb
--- /dev/null
+++ b/hubs/utils/packages.py
@@ -0,0 +1,53 @@
+from __future__ import unicode_literals
+
+import logging
+
+import requests
+
+from .cache import cache
+
+log = logging.getLogger(__name__)
+
+PAGURE_URL = "https://src.fedoraproject.org"
+
+
+def get_user_packages(username, only_owned=False, use_cache=True):
+    """Get the list of packages owned by the username.
+
+    Args:
+        username (str): The FAS username.
+        only_owned (bool): Only return the package names owned by the user, not
+            those they are co-maintainer of.
+        use_cache (bool): Whether to cache the results for a few minutes.
+            Defaults to ``True``.
+
+    Returns:
+        The list of package names sorted alphabetically.
+    """
+    def get_data():
+        url = "/".join([PAGURE_URL, "api", "0", "user", username])
+        try:
+            response = requests.get(url, timeout=20)
+        except (requests.exceptions.ConnectionError,
+                requests.exceptions.Timeout):
+            log.warning("Could not get the list of owned packages for %s",
+                        username)
+            return []
+        try:
+            data = response.json()
+        except ValueError:
+            log.warning(
+                "Invalid JSON response getting the list of packages "
+                "owned by %s: %s", username, response.text)
+            return []
+        return sorted(set(
+            repo['name'] for repo in data["repos"]
+            if not only_owned or repo["user"]["name"] == username
+            ))
+    if not use_cache:
+        return get_data()
+    else:
+        cache_key = ":".join(["owned_packages", username])
+        # Cache for 5 minutes, it seems reasonable.
+        # TODO: invalidate on fedmsg?
+        return cache.get_or_create(cache_key.encode("utf-8"), get_data, 5 * 60)
diff --git a/hubs/utils/pkgdb.py b/hubs/utils/pkgdb.py
deleted file mode 100644
index 55be246..0000000
--- a/hubs/utils/pkgdb.py
+++ /dev/null
@@ -1,45 +0,0 @@
-from __future__ import unicode_literals
-
-import logging
-
-import requests
-
-from .cache import cache
-
-log = logging.getLogger(__name__)
-
-PKGDB_URL = "https://admin.fedoraproject.org/pkgdb/api/packager/package"
-
-
-def get_owned_packages(username, use_cache=True):
-    """Get the list of packages owned by the username.
-
-    Args:
-        username (str): The FAS username.
-        use_cache (bool): Whether to cache the results for a few minutes.
-            Defaults to ``True``.
-    """
-    def get_data():
-        url = "/".join([PKGDB_URL, username])
-        try:
-            response = requests.get(url, timeout=5)
-        except (requests.exceptions.ConnectionError,
-                requests.exceptions.Timeout):
-            log.warning("Could not get the list of owned packages for %s",
-                        username)
-            return []
-        try:
-            data = response.json()
-        except ValueError:
-            log.warning(
-                "Invalid JSON response getting the list of packages "
-                "owned by %s: %s", username, response.text)
-            return []
-        owned = data['point of contact'] + data['co-maintained']
-        return sorted(set(p['name'] for p in owned))
-    if not use_cache:
-        return get_data()
-    else:
-        cache_key = ":".join(["owned_packages", username])
-        # Cache for 5 minutes, it seems reasonable.
-        return cache.get_or_create(cache_key.encode("utf-8"), get_data, 5 * 60)
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 8731c8a..363f7b2 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -4,7 +4,7 @@ import logging
 
 import pkgwat.api
 
-from hubs.utils.pkgdb import get_owned_packages
+from hubs.utils.packages import get_user_packages
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
 from hubs.widgets.view import RootWidgetView
@@ -48,14 +48,13 @@ class BaseView(RootWidgetView):
 class GetIssues(CachedFunction):
     """Returns data for Bugzilla widget.
 
-    Queries pkgdb api for package list of the user and bugzilla for
-    corresponding issues.
+    Queries Bugzilla for issues on the user's packages.
     """
 
     def execute(self):
         username = self.instance.config["username"]
         max_num = int(self.instance.config.get("max", 3))
-        owned = get_owned_packages(username)
+        owned = get_user_packages(username)
         issues = []
         for pkg_name in owned:
             if len(issues) == max_num:
@@ -79,5 +78,5 @@ class GetIssues(CachedFunction):
         except KeyError:
             return False
         username = self.instance.config["username"]
-        owned = get_owned_packages(username)
+        owned = get_user_packages(username)
         return (component in owned)

From feae96eebd9f92df6de9f2569dd3098728401ca0 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 11 2017 13:00:29 +0000
Subject: [PATCH 921/1001] Remove pkgdb from the linechart categories


---

diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index c1fcf37..39b5be8 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -25,7 +25,7 @@ class BaseView(RootWidgetView):
         username = instance.config["username"]
         categories = [
             'git', 'Wiki', 'Copr', 'anitya', 'mirrormanager', 'ansible',
-            'fedoratagger', 'Pkgdb', 'summershum', 'nuancier', 'Mailman',
+            'fedoratagger', 'summershum', 'nuancier', 'Mailman',
             'fedbadges', 'FMN', 'koschei', 'compose', 'fedimg',
             'Jenkins', 'irc', 'FAS', 'buildsys', 'Askbot', 'pagure',
             'Bodhi', 'faf', 'kerneltest', 'github', 'Trac', 'meetbot',

From 812c215867472049ad180e91835cea30417d8897 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 11 2017 13:00:29 +0000
Subject: [PATCH 922/1001] Remove the pendingacls widget: obsolete with Pagure


---

diff --git a/hubs/default_config.py b/hubs/default_config.py
index 3924a1f..fe46f94 100644
--- a/hubs/default_config.py
+++ b/hubs/default_config.py
@@ -71,6 +71,5 @@ WIDGETS = [
     'hubs.widgets.stats:Stats',
     'hubs.widgets.sticky:Sticky',
     'hubs.widgets.subscriptions:Subscriptions',
-    'hubs.widgets.workflow.pendingacls:PendingACLs',
     'hubs.widgets.workflow.updates2stable:Updates2Stable',
     ]
diff --git a/hubs/defaults.py b/hubs/defaults.py
index 7bda776..5cf01f8 100644
--- a/hubs/defaults.py
+++ b/hubs/defaults.py
@@ -46,12 +46,6 @@ def add_user_widgets(session, hub, username, fullname):
         }))
     hub.widgets.append(widget)
     widget = hubs.models.Widget(
-        plugin='workflow.pendingacls', index=2,
-        _config=json.dumps({
-            'username': username,
-        }))
-    hub.widgets.append(widget)
-    widget = hubs.models.Widget(
         plugin='subscriptions', index=3,
         _config=json.dumps({
             'username': username,
diff --git a/hubs/tests/utils/test_views.py b/hubs/tests/utils/test_views.py
index ca49dac..262df3d 100644
--- a/hubs/tests/utils/test_views.py
+++ b/hubs/tests/utils/test_views.py
@@ -43,8 +43,8 @@ class ViewUtilsTest(APPTest):
         self.assertListEqual(
             [w.plugin for w in widgets["right"]],
             ['contact', 'meetings', 'fedmsgstats', 'workflow.updates2stable',
-             'workflow.pendingacls', 'subscriptions', 'badges', 'pagure_pr',
-             'github_pr', 'bugzilla', 'halp', 'about']
+             'subscriptions', 'badges', 'pagure_pr', 'github_pr', 'bugzilla',
+             'halp', 'about']
             )
 
     def test_get_visible_widgets_preview(self):
diff --git a/hubs/widgets/workflow/pendingacls.py b/hubs/widgets/workflow/pendingacls.py
deleted file mode 100644
index f7b0c4b..0000000
--- a/hubs/widgets/workflow/pendingacls.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from __future__ import unicode_literals
-
-import requests
-
-from hubs.utils import username2avatar
-from hubs.widgets import validators
-from hubs.widgets.base import Widget
-from hubs.widgets.view import RootWidgetView
-from hubs.widgets.caching import CachedFunction
-
-
-class PendingACLs(Widget):
-
-    name = "workflow.pendingacls"
-    label = 'Pending ACL Requests'
-    position = "right"
-    parameters = [
-        dict(
-            name="username",
-            label="Username",
-            default=None,
-            validator=validators.Username,
-            help="A FAS username.",
-        )]
-
-
-class BaseView(RootWidgetView):
-
-    # TODO -- add approve/deny buttons or just link through to pkgdb
-    template_name = "pendingacls.html"
-
-    def get_context(self, instance, *args, **kwargs):
-        get_pending = GetPending(instance)
-        context = dict(
-            title=self.widget.label,
-            username=instance.config["username"],
-            )
-        context.update(get_pending())
-        return context
-
-
-class GetPending(CachedFunction):
-
-    def execute(self):
-        # TODO -- rewrite this to
-        # 1) use the datagrepper API instead of the direct pkgdb API
-        # 2) so that we can use the fedmsg.meta.conglomerate API to
-        # 3) group messages nicely in the UI instead of having repeats
-        # It will be slower, but that's fine because of our cache.
-        username = self.instance.config["username"]
-        baseurl = "https://admin.fedoraproject.org/pkgdb/api/pendingacls"
-        query = "?username={username}&format=json".format(username=username)
-        url = baseurl + query
-        response = requests.get(url)
-        data = response.json()
-        for acl in data['pending_acls']:
-            acl['avatar'] = username2avatar(acl['user'], s=32)
-        return data
-
-    def should_invalidate(self, message):
-        if not message['topic'].endswith('pkgdb.acl.update'):
-            return False
-        # Search the message to see if I am in the ACLs list of the request.
-        username = self.instance.config["username"]
-        for acl in message['msg']['package_listing'].get('acls', []):
-            if acl['fas_name'] == username and acl['status'] == 'Approved':
-                return True
-        return False
diff --git a/hubs/widgets/workflow/templates/pendingacls.html b/hubs/widgets/workflow/templates/pendingacls.html
deleted file mode 100644
index 11254a2..0000000
--- a/hubs/widgets/workflow/templates/pendingacls.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{% if pending_acls or edit_mode %}
-
-{% extends "panel.html" %}
-
-{% block content %}
-{% if session['nickname'] == username %}
-<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/pkgdb/acl/pending/">Manage requests</a>
-<hr/>
-{% endif %}
-<ul class="media-list">
-{% for acl in pending_acls %}
-    <li class="media">
-        <div class="media-left">
-            <img class="media-object img-circle" src="{{acl['avatar']}}"/>
-        </div>
-        <div class="media-body">
-            <h4 class="media-heading">{{acl['user']}} is {{acl['status']}}</h4>
-            for {{acl['acl']}} on
-            {{acl['package']}}({{acl['collection']}})
-        </div>
-    </li>
-{% endfor %}
-</ul>
-{% endblock %}
-
-{% endif %}
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 6b87c03..25cc62d 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -30,7 +30,6 @@ class Updates2Stable(Widget):
 
 class BaseView(RootWidgetView):
 
-    # TODO -- add approve/deny buttons or just link through to pkgdb
     template_name = "updates2stable.html"
 
     def get_context(self, instance, *args, **kwargs):

From c270dbbf2b8110faee90d2c2ee311b4a584d02e1 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 14 2017 17:27:23 +0000
Subject: [PATCH 923/1001] Only show the widget config button in edit mode


---

diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
index 6120391..9374f19 100644
--- a/hubs/widgets/templates/panel.html
+++ b/hubs/widgets/templates/panel.html
@@ -7,7 +7,7 @@
     <a href="{{ url_for('%s_root' % widget.name, hub=widget_instance.hub.name, idx=widget_instance.idx) }}">
         <span><i class="fa fa-external-link" aria-hidden="true"></i></span>
     </a>
-    {% if widget_instance.hub.allows(g.user, "config") %}
+    {% if edit_mode and widget_instance.hub.allows(g.user, "config") %}
     <a data-target="#edit_modal" data-toggle="modal" type="button"
         class="edit_widget" data-url="{{ widget_instance.edit_url }}">
       <span><i class="fa fa-cog" aria-hidden="true"></i></span>

From e820f72335a43a851a74fb0ccbe002d741663b2c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 15 2017 14:31:29 +0000
Subject: [PATCH 924/1001] Fix tests after 812c2158


---

diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index 3b4c6b3..175caa1 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -30,7 +30,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets still are intact
         widgets = hubs.models.Widget.by_hub_id_all(hub.name)
-        self.assertEqual(13, len(widgets))
+        self.assertEqual(12, len(widgets))
 
     def test_delete_hubs(self):
         # verify the hub exists
@@ -46,7 +46,7 @@ class ModelTest(hubs.tests.APPTest):
 
         # check if widgets exist
         widgets = hubs.models.Widget.by_hub_id_all(hub.name)
-        self.assertEqual(13, len(widgets))
+        self.assertEqual(12, len(widgets))
 
         # delete the hub
         self.session.delete(hub)
diff --git a/hubs/tests/views/test_hub_view.py b/hubs/tests/views/test_hub_view.py
index f82127c..68b822c 100644
--- a/hubs/tests/views/test_hub_view.py
+++ b/hubs/tests/views/test_hub_view.py
@@ -72,7 +72,7 @@ class HubViewTestCase(APPTest):
             "name": "ralph",
             "owners": ["ralph"],
             "subscribers": [],
-            "widgets": [37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 61],
+            "widgets": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56],
         }
         self.assertDictEqual(data, json.loads(result.get_data(as_text=True)))
 

From 9997f4c9b4f31ea157db6313e054692a3b21f334 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Aug 23 2017 20:48:01 +0000
Subject: [PATCH 925/1001] css hacks to look better for flock demo

- styled contact widget
- styled community rules widget
- styled meetings widget
- adjusted padding for all rhs widgets

---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 60880bc..d512d2c 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -222,9 +222,11 @@ header span.edit {
 }
 .rules-container h6 {
   font-family: 'Open Sans', sans-serif;
-  text-transform: uppercase;
-  font-size: 12px;
-  color: #797a7c;
+  text-transform: capitalize;
+  font-size: normal;
+  font-weight: 700;
+  color: #808080;
+  margin-bottom: 5px;
 }
 
 .rules-container img {
@@ -353,13 +355,18 @@ font-size: 32pt;
        url('/fonts/Comfortaa-700/Comfortaa-700.svg#Comfortaa') format('svg');
 }
 
+.meeting h5 { 
+    font-size: small !important;
+}
 
 .meeting .meeting-date {
     font-size: 18px;
+    text-align: center;
 }
 
 .meeting .meeting-time {
     font-size: 12px;
+    padding-left: 5px;
 }
 
 .meeting .meeting-info {
@@ -370,6 +377,17 @@ font-size: 32pt;
     font-size: 10px;
     color: #a07cbc;
 }
+
+.meeting .row {
+  border-bottom: 1px solid #ddd;
+  padding-top: 0.5rem !important;
+  padding-bottom: 0.5rem !important;
+}
+
+.meeting:last-child .row{
+  border-bottom: none !important;
+}
+
 .modal-footer button {
   float: right;
   margin-left: 1em;
@@ -548,6 +566,21 @@ font-size: 32pt;
 
 
 /*
+ *  Contact Widget
+ */
+ 
+ 
+.widget-contact .card-block ul {
+  padding: 0px; 
+}
+
+.widget-contact i {
+  width: 25px;
+  text-align: center;
+}
+
+
+/*
  * Widget Feed
  */
 
@@ -576,7 +609,46 @@ header h5.m-b-1 {
 /** not sure if this is coming from fedora bootstrap but it's card related **/
 
 .card .panel-footer {
-  padding-bottom: 2rem; /* fixes request new meeting button padding on the upcoming meeting widget */
+  padding-top: 1rem;
+  padding-bottom: 1.25rem; /* fixes request new meeting button padding on the upcoming meeting widget */
+  background-color: #a7a9ac;
+}
+
+
+
+.row.no-gutters {
+  margin-left: 0;
+  margin-right: 0;
+  
+  & > [class^="col-"],
+  & > [class*=" col-"] {
+  padding-right: 0;
+  padding-left: 0;
+  }
+}
+
+#right_widgets .widget .card-block {
+  padding: 0.25rem 0.6rem !important;
+}
+
+#right_widgets .widget-rules .card-block {
+  padding: 1.25rem 0.9rem !important;
+  background: #e7e7e7;
+}
+
+
+#right_widgets .widget-contact .card-block {
+  padding-top: 1rem !important;
+  font-size: 80%;
+}
+
+#right_widgets hr {
+  margin-top: 0.33rem;
+  margin-bottom: 0.33rem;
+}
+
+.small {
+  font-size: small;
 }
 
 
diff --git a/hubs/widgets/meetings/templates/root.html b/hubs/widgets/meetings/templates/root.html
index d2ade22..e3948aa 100644
--- a/hubs/widgets/meetings/templates/root.html
+++ b/hubs/widgets/meetings/templates/root.html
@@ -3,11 +3,11 @@
 {% block content %}
 {% for title, next in meetings.items() %}
 <div class="meeting">
-  <div class="row">
-      <h5>&nbsp;&nbsp;The {{ next.meeting_name }} is {{ next.start_dt | humanize }}</h5>
-  </div>
-  <div class="row">
-    <div class="col-md-4 meeting-date">
+  <div class="row no-gutters">
+    <div class="col-md-12">
+      <h5>The {{ next.meeting_name }} is {{ next.start_dt | humanize }}:</h5>
+    </div>
+    <div class="col-md-3 meeting-date">
       {% if next.display_duration %}
       <strong>{{ next.start_date }} - {{ next.stop_date }}</strong>
       {% else %}
@@ -20,7 +20,7 @@
 
       <a href="#">{{ next.location }}</a>
     </div>
-    <div class="col-md-4">
+    <div class="col-md-5">
       <a href="https://apps.fedoraproject.org/calendar/ical/calendar/meeting/{{ next.meeting_id }}/">
         <button class="btn btn-secondary btn-sm add-calendar">
           <strong>Add to calendar</strong>
@@ -41,7 +41,7 @@
   </div>
   {% endif  %}
 </div>
-{% if meetings | length > 1 %} <hr> {% endif %}
+<!-- {% if meetings | length > 3 %} <hr> {% endif %} -->
 {% else %}
 <div class="meeting">
   <div class="row">
diff --git a/hubs/widgets/rules/templates/root.html b/hubs/widgets/rules/templates/root.html
index c52c61c..0803f95 100644
--- a/hubs/widgets/rules/templates/root.html
+++ b/hubs/widgets/rules/templates/root.html
@@ -7,7 +7,7 @@
   <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
   {% endif %}
   <h6>group owners ({{ owners|length }})</h6>
-  <div class="row">
+  <div class="row no-gutters">
     {% if owners|length > 5%}
       {% for owner in oldest_owners %}
         <div class="col-sm-6">
@@ -33,13 +33,13 @@
   {% endif %}
   <p>
   {% if schedule_link %}
-  <a target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
+  <a class="small" target="_blank" href="{{schedule_link}}">Meeting Schedule</a>
   {% endif %}
   {% if schedule_link and minutes_link %}
-  &#8214;
+  &#124;
   {% endif %}
   {% if minutes_link %}
-  <a target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
+  <a class="small" target="_blank" href="{{minutes_link}}">Past Meeting Minutes</a>
   {% endif %}
   </p>
   {% endif %}

From 51bfc721c83f5f90778271a44546689884a8c819 Mon Sep 17 00:00:00 2001
From: Máirín Duffy <duffy@redhat.com>
Date: Aug 24 2017 16:47:41 +0000
Subject: [PATCH 926/1001] more short-term CSS tweaks to clean up look and feel for flock

- imported a version of patternlab stylesheet for media-list styles
- cleaned up all bz/pagure/github widget displays
- refinement of meeting widget
- a few other widgets cleaned up

---

diff --git a/hubs/static/css/style-patternlab.css b/hubs/static/css/style-patternlab.css
new file mode 100644
index 0000000..9be59f4
--- /dev/null
+++ b/hubs/static/css/style-patternlab.css
@@ -0,0 +1,2224 @@
+/*
+                                                ,,            ,,                          ,,
+ .M"""bgd mm                                    db          `7MM        mm         mm   `7MM                                    OO OO OO
+,MI    "Y MM                                                  MM        MM         MM     MM                                    88 88 88
+`MMb.   mmMMmm ,pW"Wq.`7MMpdMAo.     `7Mb,od8 `7MM  .P"Ybmmm  MMpMMMb.mmMMmm     mmMMmm   MMpMMMb.  .gP"Ya `7Mb,od8 .gP"Ya      || || ||
+  `YMMNq. MM  6W'   `Wb MM   `Wb       MM' "'   MM :MI  I8    MM    MM  MM         MM     MM    MM ,M'   Yb  MM' "',M'   Yb     || || ||
+.     `MM MM  8M     M8 MM    M8       MM       MM  WmmmP"    MM    MM  MM         MM     MM    MM 8M""""""  MM    8M""""""     `' `' `'
+Mb     dM MM  YA.   ,A9 MM   ,AP       MM       MM 8M         MM    MM  MM         MM     MM    MM YM.    ,  MM    YM.    ,     ,, ,, ,,
+P"Ybmmd"  `Mbmo`Ybmd9'  MMbmmd'      .JMML.   .JMML.YMMMMMb .JMML  JMML.`Mbmo      `Mbmo.JMML  JMML.`Mbmmd'.JMML.   `Mbmmd'     db db db
+                        MM                         6'     dP
+                      .JMML.                       Ybmmmd'
+
+Pattern Lab doesn't have any CSS requirements, which means you can write your styles however you want. Hooray!
+You can use Sass, Less, vanilla CSS, or some other crazy thing I haven't heard of yet.
+So please don't use these styles. They're just here to put together the demo, and nothing more.
+They're intentionally gray, boring, and crappy because you're supposed to do this stuff yourself.
+
+Atomic design is philosophically complimentary with these CSS approaches:
+
+* SMACSS by Jonathan Snook http://smacss.com/
+* OOCSS by Nicole Sullivan http://oocss.org/
+* BEM CSS Methology : http://bem.info/method/
+* CSS Guidelines by Harry Roberts : https://github.com/csswizardry/CSS-Guidelines
+
+So feel free to use any of these approaches. Or don't. It's totally up to you.
+
+*/
+/*------------------------------------*\
+    $TABLE OF CONTENTS
+    based generally on Harry Roberts excellent CSS Guidelines https://github.com/csswizardry/CSS-Guidelines
+\*------------------------------------*/
+/**
+ * ABSTRACTS..............Declarations of Sass variables and mixins
+ * Mixins.................Mixin styles that are included in the site
+ * Variables..............Variables for styles that are used in the site
+ *
+ * BASE...................Base/reset styles for certain elements
+ * Animation..............Animation base styles
+ * Forms..................Form field base styles
+ * Global Classes.........Base styles used across the entirety of the site
+ * Headings...............Base styles for headings (h1, h2, etc.)
+ * Links..................Base styles for links
+ * Lists..................Base styles lists
+ * Main...................Base styles for main section
+ * Media..................Base styles for various media (videos, iframes, etc.)
+ * Reset..................Reset base styles (i.e. Display block on certain elements)
+ * Tables.................Base styles for tables
+ * Text...................Base styles for text elements
+ *
+ * COMPONENTS.............Styles for certain components
+ * Accordion..............Styles for accordion components
+ * Article................Styles for article components
+ * Blocks.................Styles for block components
+ * Buttons................Styles for button components
+ * Carousels..............Styles for carousels
+ * Comments...............Styles for comments component
+ * Footer.................Styles for the footer component
+ * Forms..................Styles for form components
+ * Header.................Styles for header component
+ * Icons..................Styles for icons
+ * Lists..................Styles for types of lists
+ * Main...................Styles for main section
+ * Messaging..............Styles for alerts/messaging components
+ * Nav....................Styles for navigation components
+ * Sections...............Styles for section components
+ * Tabs...................Styles for tabs
+ * Text...................Styles for text components
+ * Tooltip................Styles for tooltips
+
+ *
+ * LAYOUT.................Styles that affect the site's general layout
+ * Layout.................Layout styles
+ *
+ * UTILITIES..............Styles that require a utility class
+ *
+ *
+ * OBJECTS................Styles for object types
+ * Widgets................Styles specific for widget patterns
+ * Modals................Styles specific for modal patterns
+ */
+/*------------------------------------*\
+    $ABSTRACTS
+\*------------------------------------*/
+/*------------------------------------*\
+    #MIXINS
+\*------------------------------------*/
+/** CSS Transition
+ *	Usage: @include transition(width,0.3s,ease-out);
+ */
+/** Rem Unit font sizes with relative fallback http:/seesparkbox.com/foundry/scss_rem_mixin_now_with_a_better_fallback  
+ *	Usage: @include font-size(1, large);
+ */
+/*------------------------------------*\
+    #VARIABLES
+\*------------------------------------*/
+/*------------------------------------*\
+    #COLORS
+\*------------------------------------*/
+/*
+ * 1) Color variables involve a two-tier system to keep colors in sync. The
+ *    first tier defines the brand and neutral colors, and the second tier
+ *    defines the application of those colors.
+ */
+/*
+ * Brand Colors
+ * 1) Brand color variables use English names to define colors to make palettes easier to
+ *    identify. Names are generated using this tool: http://chir.ag/projects/name-that-color/
+ * 2) Brand color variables should typically not be used directly in Sass partials. Instead, use
+ *    second-tier application colors.
+ *
+ */
+/*
+ * Neutral Colors
+ * 1) Neutral color variables use a numbered system to define variables for better maintainability.
+ *    "$color-gray-10" means "10% gray", which is a gray closer to white than to black. For more info
+ *    read https://medium.com/eightshapes-llc/color-in-design-systems-a1c80f65fa3#.brevrq67p
+ */
+/**
+ * Utility Colors
+ * 1) Utility colors are colors used to provide feedback, such as alert messages,
+ * form validation, etc.
+ */
+/*
+ * Text Colors
+ * 1) These are non-linked text colors, such as body copy.
+ */
+/*
+ * Heading Colors
+ * 1) These are non-linked heading colors, such as h2, h3, etc.
+ */
+/*
+ * Text Link Colors
+ * 1) These are for linked text, such as a link found within an article,
+ *    navigation link, footer link, etc.
+ */
+/*
+ * Border Colors
+ * 1) Border colors are used as decoration or dividers, such as as a seperator
+ *    for navigation items, block borders, etc.
+ */
+/*------------------------------------*\
+    #TYPOGRAPHY
+\*------------------------------------*/
+@import url("https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css");
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-ExtraBold.ttf") format("opentype");
+  font-weight: 900; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-Bold.ttf") format("opentype");
+  font-weight: 700; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-Regular.ttf") format("opentype");
+  font-weight: 500; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-Light.ttf") format("opentype");
+  font-weight: 300; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-ExtraBoldItalic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 900; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-BoldItalic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 700; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-SemiboldItalic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 600; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-Italic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 500; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-LightItalic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 300; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Black.otf") format("opentype");
+  font-weight: 900; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-ExtraBold.otf") format("opentype");
+  font-weight: 800; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Bold.otf") format("opentype");
+  font-weight: 700; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-SemiBold.otf") format("opentype");
+  font-weight: 600; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Regular.otf") format("opentype");
+  font-weight: 400; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Light.otf") format("opentype");
+  font-weight: 300; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-UltraLight.otf") format("opentype");
+  font-weight: 200; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Hairline.otf") format("opentype");
+  font-weight: 100; }
+
+/* Override on the styleguide module */
+.sg-pattern-category-body {
+  font-size: 100% !important; }
+
+/*------------------------------------*\
+    #LAYOUT
+\*------------------------------------*/
+/**
+ * Spacing Defaults
+ */
+/*------------------------------------*\
+    #BORDERS
+\*------------------------------------*/
+/**
+ * Border Width
+ */
+/**
+ * Border Radius
+ */
+/*------------------------------------*\
+    #ANIMATION
+\*------------------------------------*/
+/**
+ * Animation Duration
+ */
+/**
+ * Animation Easing
+ */
+/*------------------------------------*\
+    #BREAKPOINTS
+\*------------------------------------*/
+/**
+ * Breakpoints
+ */
+/*------------------------------------*\
+    $BASE
+\*------------------------------------*/
+/*------------------------------------*\
+    #BODY
+\*------------------------------------*/
+/**
+ * Body base styles
+ */
+
+/*------------------------------------*\
+    #ANIMATION
+\*------------------------------------*/
+/**
+ * Fade Animation
+ */
+.animate-fade {
+  -webkit-transition: opacity 0.3s ease-out;
+  -moz-transition: opacity 0.3s ease-out;
+  -ms-transition: opacity 0.3s ease-out;
+  -o-transition: opacity 0.3s ease-out;
+  transition: opacity 0.3s ease-out; }
+  .animate-fade:hover {
+    opacity: 0; }
+
+/*------------------------------------*\
+    #FORMS
+\*------------------------------------*/
+/**
+ * Fieldset base styles
+ */
+fieldset {
+  border: 0;
+  padding: 0;
+  margin: 0; }
+
+/**
+ * Label base styles
+ */
+label {
+  display: block;
+  padding-bottom: 0.2rem;
+  font-weight: bold; }
+
+/**
+ * Form button, input, select, and text area base styles
+ * 1) Zero out margin and inherit font styles
+ */
+button, input, select, textarea {
+  font-family: inherit;
+  font-size: 100%;
+  margin: 0; }
+
+/**
+ * Input and text area base styles
+ * 1) Width entire container, gray border, padding
+ */
+input, textarea {
+  width: 100%;
+  border: 1px solid #a5a5a5;
+  border-radius: 3px;
+  padding: 1rem; }
+
+/**
+ * Input areas base styles
+ * 1) Get rid of webkit appearance of these areas
+ */
+input[type=text], input[type=search], input[type=url], input[type=number], textarea {
+  -webkit-appearance: none; }
+
+/**
+ * Button/Submit button base styles
+ */
+button, input[type="submit"] {
+  padding: 0.5em;
+  background: #444444;
+  border: 1px solid gray;
+  cursor: pointer; }
+
+/**
+ * Checkboxes/Radio button base styles
+ */
+input[type="checkbox"],
+input[type="radio"] {
+  width: auto;
+  margin-right: 0.3em; }
+
+/**
+ * Search cancel button and search decoration webkit appearance none
+ */
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none; }
+
+/*------------------------------------*\
+    #GLOBAL CLASSES
+\*------------------------------------*/
+/**
+ * Hide on small screens
+ */
+@media all and (max-width: 46.8em) {
+  .hide-small {
+    display: none; } }
+
+/**
+ * Hide on medium screens
+ */
+@media all and (min-width: 46.8em) and (max-width: 50em) {
+  .hide-med {
+    display: none; } }
+
+/**
+ * Hide on large screens
+ */
+@media all and (min-width: 50em) {
+  .hide-large {
+    display: none; } }
+
+/**
+ * Show valid text color
+ */
+.valid {
+  color: #03804d; }
+
+/**
+ * Show error text color
+ */
+.error {
+  color: #b12a0b; }
+
+/**
+ * Show warning text color
+ */
+.warning {
+  color: #a59b15; }
+
+/**
+ * Show informational text color
+ */
+.information {
+  color: #0192d0; }
+
+/**
+ * Display secondary font family
+ */
+.font-secondary {
+  font-family: "Montserrat", Georgia, Times, "Times New Roman", serif; }
+
+/*------------------------------------*\
+    #HEADINGS
+\*------------------------------------*/
+/**
+ * Heading 1
+ */
+h1 {
+  font-size: 3rem;
+  line-height: 1.2;
+  text-transform: uppercase !important;
+  font-family: "Montserrat", Georgia, Times, "Times New Roman", serif; }
+
+/**
+ * Heading 2
+ */
+h2 {
+  font-size: 2.4rem;
+  line-height: 1.2;
+  font-weight: 700;
+  font-family: "Montserrat", Georgia, Times, "Times New Roman", serif; }
+
+/**
+ * Heading 3
+ */
+h3 {
+  line-height: 1.2;
+  font-size: 1.5rem;
+  font-weight: 600;
+  font-family: "Montserrat", Georgia, Times, "Times New Roman", serif; }
+
+/**
+ * Heading 4
+ */
+h4 {
+  font-size: 1.3rem;
+  font-weight: 500;
+  font-family: "Montserrat", Georgia, Times, "Times New Roman", serif; }
+
+/**
+ * Heading 5
+ */
+h5 {
+  font-size: 1.4rem;
+  font-weight: 600;
+  font-family: "Montserrat", Georgia, Times, "Times New Roman", serif; }
+
+/**
+ * Heading 6
+ */
+h6 {
+  font-size: 1.1rem;
+  font-family: "Montserrat", Georgia, Times, "Times New Roman", serif; }
+
+/**
+ * Subheading
+ */
+.subheading {
+  font-family: "Montserrat", Georgia, Times, "Times New Roman", serif;
+  font-weight: normal; }
+
+/*------------------------------------*\
+    #LINKS
+\*------------------------------------*/
+/**
+ * Links
+ */
+a {
+  color: #428bca;
+  text-decoration: none;
+  outline: 0;
+  transition: all 0.2s ease; }
+
+/*------------------------------------*\
+    #LINKS
+\*------------------------------------*/
+/**
+ * Ordered/Unordered list base styles
+ */
+ol, ul {
+  margin: 0;
+  padding: 0;
+  list-style: none; }
+
+/**
+ * Definition list base styles
+ */
+dl {
+  overflow: hidden;
+  margin: 0 0 1em; }
+
+/**
+ * Terms/Names base styles
+ */
+dt {
+  font-weight: bold; }
+
+/**
+ * Definition list description base styles
+ */
+dd {
+  margin-left: 0; }
+
+/*------------------------------------*\
+    #MAIN
+\*------------------------------------*/
+/**
+ * Main content area
+ */
+[role=main] {
+  flex: 1; }
+
+/*------------------------------------*\
+    #MEDIA ELEMENTS
+\*------------------------------------*/
+/**
+ * Make media elements responsive
+ */
+img, video, object {
+  max-width: 100%;
+  height: auto; }
+
+/**
+ * Iframe base styles
+ */
+iframe {
+  margin-bottom: 1em; }
+
+/**
+ * Figure base styles
+ */
+figure {
+  margin-bottom: 1em;
+  /**
+   * Figure image base styles
+   */ }
+  figure img {
+    margin-bottom: 0.5em; }
+
+/**
+ * Figure caption base styles
+ */
+figcaption {
+  font-style: italic; }
+
+/*------------------------------------*\
+    #RESET
+\*------------------------------------*/
+/**
+ * Use border box on all elements
+ */
+* {
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box; }
+
+/**
+ * Zero out margin and padding on most elements as base style
+ */
+html, body, div, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, ol, ul, li, form, legend, label, table, header, footer, nav, section, figure {
+  margin: 0;
+  padding: 0; }
+
+/**
+ * Display block as base for these elements
+ */
+header, footer, nav, section, article, hgroup, figure {
+  display: block; }
+
+/*------------------------------------*\
+    #TEXT
+\*------------------------------------*/
+/**
+ * Paragraph base styles
+ */
+p {
+  margin-bottom: 1em; }
+
+/**
+ * Blockquote base styles
+ */
+blockquote {
+  font-style: italic;
+  border-left: 1px solid gray;
+  color: gray;
+  padding-left: 1em;
+  margin-bottom: 1em; }
+
+/**
+ * Horizontal rule base styles
+ */
+hr {
+  border: 0;
+  height: 2px;
+  background: #d9d9d9;
+  margin: 2em 0; }
+
+/**
+ * Abbreviation base styles
+ */
+abbr {
+  border-bottom: 1px dotted gray;
+  cursor: help; }
+
+/*------------------------------------*\
+    $COMPONENTS
+\*------------------------------------*/
+/*------------------------------------*\
+    #BLOCKS
+\*------------------------------------*/
+/**
+ * 1) Blocks are collections of text and/or images/media working together as a unit.
+ */
+/*------------------------------------*\
+	#HERO BLOCK
+\*------------------------------------*/
+.c-block-hero {
+  display: block;
+  position: relative; }
+
+/**
+ * Hero Image
+ * 1) This is the primary hero image that runs full-bleed across the layout
+ */
+.c-block-hero__img {
+  display: block;
+  width: 100%;
+  max-height: 50vh;
+  object-fit: cover; }
+
+/**
+ * Hero Headline
+ * 1) This sits overtop of the hero image when space permits
+ */
+.c-block-hero__headline {
+  background: rgba(0, 0, 0, 0.5);
+  color: white;
+  padding: 1rem;
+  font-size: 2.6rem;
+  transition: all 0.2s ease; }
+  @media all and (min-width: 50em) {
+    .c-block-hero__headline {
+      position: absolute;
+      top: 3rem;
+      left: 1rem;
+      width: 50%;
+      border-radius: 3px; } }
+  .c-block-hero:hover .c-block-hero__headline, .c-block-hero:focus .c-block-hero__headline {
+    background: #444444; }
+
+.c-block-hero h2 {
+  font-family: "Open Sans", "Helvetica", "Arial", sans-serif !important;
+  font-weight: 200;
+  text-transform: capitalize !important; }
+
+/*------------------------------------*\
+	#MEDIA BLOCK
+\*------------------------------------*/
+/**
+ * 1) Media block contains an image (or some other media) on the left
+ * and text on the right.
+ * 2) For more info, read http://www.stubbornella.org/content/2010/06/25/the-media-object-saves-hundreds-of-lines-of-code/
+ */
+.c-block-media {
+  display: flex;
+  transition: all 0.2s ease; }
+  .c-block-media:hover .c-block-media__headline, .c-block-media:focus .c-block-media__headline {
+    color: #428bca; }
+  .c-block-media.small {
+    font-size: 0.95rem; }
+
+/**
+ * Media Container
+ * 1) This is the container that holds the block image (or media)
+ */
+.c-block-media__media {
+  width: 20%;
+  max-width: 11em;
+  margin-right: 1rem; }
+  .c-block-media--small .c-block-media__media {
+    max-width: 3.5em;
+    margin-right: 0.5rem; }
+  @media all and (min-width: 46.8em) {
+    .c-block-media__media {
+      width: 50%;
+      margin-right: 1.5rem; } }
+
+.c-block-media__img {
+  border-radius: 3px; }
+
+.c-block-media__headline {
+  margin-bottom: 0.2em;
+  color: #428bca;
+  transition: all 0.2s ease; }
+  .c-block-media--small .c-block-media__headline {
+    font-size: 1.0625rem; }
+
+.c-block-media__body {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  flex: 1; }
+
+.c-block-media__excerpt {
+  color: #a5a5a5;
+  transition: all 0.2s ease; }
+  .c-block-media--small .c-block-media__excerpt {
+    margin-bottom: 0;
+    line-height: 1.2; }
+
+/*------------------------------------*\
+	#TOUT BLOCK
+\*------------------------------------*/
+/**
+ * 1) The tout block contains an image and headline overlayed over the image.
+ */
+.c-block-tout {
+  display: inline-block;
+  margin-bottom: 0.5em;
+  position: relative;
+  overflow: hidden;
+  border-radius: 3px; }
+
+/**
+ *  Tout image
+ */
+.c-block-tout__img {
+  display: block; }
+
+/**
+ *  Tout headline
+ */
+.c-block-tout__headline {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  background: rgba(0, 0, 0, 0.5);
+  color: white;
+  padding: 0.5em;
+  font-size: 1.4rem;
+  transition: all 0.2s ease; }
+  .c-block-tout:hover .c-block-tout__headline, .c-block-tout:focus .c-block-tout__headline {
+    padding-bottom: 2rem; }
+
+/*------------------------------------*\
+	#TILE BLOCK
+\*------------------------------------*/
+/**
+ * 1) The tile block contains a span and headline overlayed on a background
+ */
+.c-block-tile {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  background: rgba(0, 0, 0, 0.5);
+  color: white;
+  border-radius: 3px;
+  padding: 1em 1em;
+  text-align: center;
+  overflow: hidden;
+  transition: all 0.2s ease; }
+  .c-block-tile:hover, .c-block-tile:focus {
+    background: rgba(0, 0, 0, 0.7);
+    color: white; }
+  @media all and (min-width: 55rem) {
+    .c-block-tile {
+      padding: 4em 1em; } }
+
+/**
+ * Featured tile block
+ */
+.c-block-tile--featured {
+  min-height: 200px; }
+
+/**
+ * Tile block value
+ */
+.c-block-tile__value {
+  font-size: 1.5rem;
+  line-height: 1.2;
+  /**
+   * Tile value when inside featured tile parent selector
+   */ }
+  .c-block-tile--featured .c-block-tile__value {
+    font-size: 2.5rem; }
+    @media all and (min-width: 46.8em) {
+      .c-block-tile--featured .c-block-tile__value {
+        font-size: 5rem; } }
+  @media all and (min-width: 55rem) {
+    .c-block-tile__value {
+      font-size: 3rem; } }
+
+.c-block-tile__label {
+  color: #d9d9d9;
+  font-weight: normal;
+  font-size: 1.0625rem; }
+
+/*------------------------------------*\
+    #BUTTONS
+\*------------------------------------*/
+/**
+ * Button
+ */
+.c-btn {
+  display: inline-block;
+  background: #428bca;
+  color: white;
+  line-height: 1;
+  font-weight: bold;
+  padding: .75rem 3rem;
+  border: 0;
+  border-radius: 3px;
+  text-align: center;
+  transition: background 0.2s ease;
+  transition: text-shadow 0.2s ease;
+  text-shadow: 0 2px 1px rgba(0, 0, 0, 0.2);
+  /**
+   * Disabled button
+   */ }
+  .c-btn:hover, .c-btn:focus {
+    background: gray;
+    color: white;
+    text-shadow: 0 4px 5px rgba(0, 0, 0, 0.4); }
+  .c-btn.disabled {
+    background: #d9d9d9;
+    color: gray; }
+
+/**
+ * Small button
+ */
+.c-btn-small {
+  padding: 0.5em; }
+
+/**
+ * Large button
+ */
+.c-btn-large {
+  padding: 0.5em;
+  text-transform: uppercase;
+  background: gray;
+  font-size: 1.4rem;
+  font-weight: normal; }
+
+/**
+ * Text button
+ */
+.c-text-btn {
+  position: relative;
+  background: none;
+  border: none;
+  font-style: normal;
+  font-weight: 600;
+  font-size: 1.2rem; }
+  .c-text-btn:after {
+    position: absolute;
+    content: "";
+    height: 20px;
+    width: 20px;
+    background: url("../../../images/icon-arrowhead.svg") no-repeat;
+    top: 9px;
+    right: -26px;
+    transition: all 0.2s ease; }
+  .c-text-btn:hover, .c-text-btn:focus {
+    color: #444444; }
+    .c-text-btn:hover:after, .c-text-btn:focus:after {
+      right: -28px; }
+  .c-block-media--small .c-text-btn {
+    font-size: 1rem; }
+
+/**
+ * Button on overlay
+ */
+.c-btn--overlay {
+  background: #a5a5a5; }
+
+/*------------------------------------*\
+    #CAROUSEL
+\*------------------------------------*/
+/**
+ * Horizontal carousel
+ */
+.carousel-horizontal {
+  margin-bottom: 1em;
+  overflow: hidden;
+  position: relative; }
+
+/**
+ * Carousel island container
+ */
+.carousel-island-container {
+  overflow: hidden; }
+
+/**
+ * Carousel container
+ */
+.carousel-container {
+  position: relative; }
+
+/**
+ * Carousel list
+ */
+/**
+ * Carousel controls
+ */
+.carousel-controls {
+  display: table;
+  width: 100%;
+  margin: -0.5em 0 1em;
+  /**
+   * Carousel pagination
+   */
+  /**
+   * Carousel next button
+   */ }
+  .carousel-controls a, .carousel-controls div {
+    display: table-cell;
+    padding: 0.5em; }
+  .carousel-controls .carousel-pagination {
+    text-align: center; }
+  .carousel-controls .carousel-next {
+    text-align: right; }
+
+/*------------------------------------*\
+    #FOOTER
+\*------------------------------------*/
+/**
+ * Footer
+ */
+.c-footer {
+  clear: both;
+  overflow: hidden;
+  background: #3b4a20;
+  color: white;
+  line-height: 1.2;
+  padding: 1em 0; }
+
+/**
+ * Footer nav
+ */
+.c-footer__info {
+  max-width: 40em; }
+  .c-footer__info a {
+    color: #d9d9d9;
+    /*text-decoration: underline;*/ }
+    .c-footer__info a:hover, .c-footer__info a:focus {
+      text-decoration: none; }
+
+/*------------------------------------*\
+    #FOOTER NAVIGATION
+\*------------------------------------*/
+/**
+ * Footer Nav
+ */
+.c-footer-nav {
+  display: block;
+  margin-right: 1rem; }
+
+/**
+ * Footer Nav List
+ */
+.c-footer-nav__list {
+  display: flex;
+  flex-direction: column; }
+  @media all and (min-width: 24em) {
+    .c-footer-nav__list {
+      flex-direction: row; } }
+
+/**
+ * Footer Nav List Item
+ */
+.c-footer-nav__item {
+  width: 50%; }
+  @media all and (min-width: 24em) {
+    .c-footer-nav__item {
+      width: inherit; } }
+
+/**
+ * Footer Nav Links
+ */
+.c-footer-nav__link {
+  font-weight: bold;
+  display: block;
+  padding: 1rem 2rem 1rem 0;
+  color: white; }
+  .c-footer-nav__link:hover, .c-footer-nav__link:focus {
+    color: #a5a5a5; }
+
+/*------------------------------------*\
+    #FORMS
+\*------------------------------------*/
+/**
+ * Search form
+ */
+.c-search-form {
+  display: none; }
+  .c-search-form.is-active {
+    display: block;
+    position: absolute;
+    top: 67px;
+    right: 2px;
+    width: 100%;
+    padding: 1em;
+    box-shadow: 0px 3px 5px -2px rgba(0, 0, 0, 0.2);
+    background: white;
+    z-index: 1; }
+  @media all and (min-width: 29.75em) {
+    .c-search-form {
+      display: block; } }
+
+/**
+ * Search input
+ */
+.c-search-form__input {
+  padding: 0.5rem; }
+
+/**
+ * Stacked form button wrapper
+ */
+.c-form__actions {
+  margin-bottom: 2rem; }
+
+/*------------------------------------*\
+    #FIELDS
+\*------------------------------------*/
+.c-field {
+  margin-bottom: 1rem; }
+
+.c-field__note {
+  font-size: 0.875rem; }
+  .c-field__note a {
+    /*text-decoration: underline;*/ }
+
+/*------------------------------------*\
+    #HEADER
+\*------------------------------------*/
+/**
+ * Header
+ */
+.c-header {
+  display: flex;
+  align-items: center;
+  box-shadow: 0px 3px 5px -2px rgba(0, 0, 0, 0.2);
+  padding: 0.5em 0; }
+  @media all and (min-height: 46.8em) {
+    .c-header {
+      padding: 1em 0; } }
+
+/**
+ * Header Controls
+ * 1) This container holds the primary nav and search menu
+ */
+.c-header__controls {
+  margin-left: auto;
+  display: flex;
+  align-items: center;
+  padding-right: 1rem; }
+
+/**
+ * Nav toggle button
+ * 1) Styles for the general nav toggle button
+ */
+.nav-toggle {
+  display: block;
+  padding: 0.9rem 1rem 0.7rem;
+  font-size: 1.3rem;
+  line-height: 1; }
+  @media all and (min-width: 46.8em) {
+    .nav-toggle {
+      display: none; } }
+  @media all and (max-width: 17em) {
+    .nav-toggle {
+      padding-left: 0.2rem;
+      padding-right: 0.2rem; } }
+
+/**
+ * Search nav toggle button
+ * 1) Specific nav toggle button for the search form
+ */
+.nav-toggle-search {
+  display: block; }
+  @media all and (min-width: 29.75em) {
+    .nav-toggle-search {
+      display: none; } }
+
+/*------------------------------------*\
+    #LOGO
+\*------------------------------------*/
+.c-logo {
+  display: block;
+  max-width: 200px; }
+  .c-box__header .c-logo {
+    max-width: 12em;
+    margin: 0 auto; }
+
+.c-logo-link {
+  display: inline-block;
+  padding: 0.2rem 1rem; }
+
+/*------------------------------------*\
+    #ICONS
+\*------------------------------------*/
+/**
+ * Icon fonts
+ */
+@font-face {
+  font-family: 'icons';
+  src: url("../fonts/icons.eot");
+  src: url("../fonts/icons.eot?#iefix") format("embedded-opentype"), url("../fonts/icons.woff") format("woff"), url("../fonts/icons.ttf") format("truetype"), url("../fonts/icons.svg#icons") format("svg");
+  font-weight: normal;
+  font-style: normal; }
+
+/**
+ * Use the following CSS code if you want to use data attributes for inserting your icons
+ */
+[data-icon]:before {
+  font-family: 'icons';
+  content: attr(data-icon);
+  speak: none;
+  font-weight: normal;
+  line-height: 1;
+  -webkit-font-smoothing: antialiased; }
+
+/**
+ * Icons and icon pseudo-elements
+ */
+.icon-twitter:before, .icon-stumbleupon:before, .icon-pinterest:before, .icon-linkedin:before, .icon-google-plus:before, .icon-search:before, .icon-play:before, .icon-menu:before, .icon-arrow-left:before, .icon-arrow-right:before, .icon-bubble:before, .icon-facebook:before, .icon-feed:before, .icon-youtube:before, .icon-tag:before, .icon-tumblr:before, .icon-instagram, .icon-podcast, .icon-apple, .icon-android, .icon-arrow:after, .icon-envelope:before {
+  font-family: 'icons';
+  speak: none;
+  font-style: normal;
+  font-weight: normal;
+  font-variant: normal;
+  text-transform: none;
+  line-height: 1;
+  -webkit-font-smoothing: antialiased; }
+
+/**
+ * Twitter icon
+ */
+.icon-twitter:before {
+  content: "\74"; }
+
+/**
+ * Stumbleupon icon
+ */
+.icon-stumbleupon:before {
+  content: "\75"; }
+
+/**
+ * Pinterest icon
+ */
+.icon-pinterest:before {
+  content: "\70"; }
+
+/**
+ * LinkedIn icon
+ */
+.icon-linkedin:before {
+  content: "\69"; }
+
+/**
+ * Google plus icon
+ */
+.icon-google-plus:before {
+  content: "\67"; }
+
+/**
+ * Icon search
+ */
+.icon-search:before {
+  content: "\73"; }
+
+/**
+ * Play button icon
+ */
+.icon-play:before {
+  content: "\61"; }
+
+/**
+ * Menu icon
+ */
+.icon-menu:before {
+  content: "\21"; }
+
+/**
+ * Arrow left icon
+ */
+.icon-arrow-left:before {
+  content: "\23"; }
+
+/**
+ * Arrow right icon
+ */
+.icon-arrow-right:before {
+  content: "\24"; }
+
+/**
+ * Bubble icon
+ */
+.icon-bubble:before {
+  content: "\25"; }
+
+/**
+ * Facebook icon
+ */
+.icon-facebook:before {
+  content: "\66"; }
+
+/**
+ * Feed icon
+ */
+.icon-feed:before {
+  content: "\27"; }
+
+/**
+ * YouTube icon
+ */
+.icon-youtube:before {
+  content: "\79"; }
+
+/**
+ * Tag icon
+ */
+.icon-tag:before {
+  content: "\28"; }
+
+/**
+ * Tumblr icon
+ */
+.icon-tumblr:before {
+  content: "\6d"; }
+
+/**
+ * Instagram icon
+ */
+.icon-instagram:before {
+  content: "\22"; }
+
+/**
+ * Podcast icon
+ */
+.icon-podcast:before {
+  content: "\26"; }
+
+/**
+ * Android icon
+ */
+.icon-android:before {
+  content: "\29"; }
+
+/**
+ * Twitter icon
+ */
+.icon-apple:before {
+  content: "\2a"; }
+
+/**
+ * Envelope icon
+ */
+.icon-envelope:before {
+  content: "\2b"; }
+
+/**
+ * Arrow icon
+ */
+.icon-arrow:after {
+  content: "\61";
+  display: inline-block;
+  -webkit-transform: rotate(90deg);
+  -moz-transform: rotate(90deg);
+  -ms-transform: rotate(90deg);
+  -o-transform: rotate(90deg);
+  transform: rotate(90deg); }
+
+/**
+ * Play icon
+ */
+.icon-play:before {
+  font-size: 0.7rem;
+  padding-left: 0.2em; }
+
+/**
+ * Play box icon
+ */
+.icon-play-box {
+  display: block;
+  margin-left: 2em; }
+
+/**
+ * Play box icon before
+ */
+.icon-play-box:before {
+  padding: 0.25em;
+  background: gray;
+  color: white;
+  margin-left: -1.7rem;
+  margin-right: 0.5em; }
+
+/*------------------------------------*\
+    #LISTS
+\*------------------------------------*/
+/**
+ * Inline list
+ */
+.inline-list li {
+  display: inline-block; }
+
+/**
+ * Social list
+ */
+.social-list li {
+  margin: 0 0.4rem 1em 0; }
+.social-list a {
+  font-size: 1.6em; }
+
+/**
+ * Headline list
+ */
+.headline-list {
+  margin-bottom: 1em; }
+  .headline-list.flush {
+    margin: 0; }
+  .headline-list h4 {
+    font-weight: normal; }
+  .headline-list li {
+    padding: 0.25em 0;
+    border-top: 1px solid #a5a5a5; }
+
+/**
+ * Post list
+ */
+.post-list li {
+  margin-bottom: 1em; }
+
+/**
+ * Bullet list
+ */
+.bullet-list {
+  list-style: square;
+  margin: 0 0 1em 1.2em;
+  line-height: 1.3; }
+  .bullet-list li {
+    margin-bottom: 1em; }
+
+/**
+ * Text list
+ */
+.text-list {
+  margin: 0 0 1em;
+  line-height: 1.3; }
+  .text-list li {
+    margin-bottom: 1em; }
+
+/**
+ * Media List
+ */
+.c-media-list__item {
+  margin-bottom: 1.5em; }
+
+/**
+ * Tile list
+ */
+.c-tile-list {
+  display: flex;
+  flex-direction: column; }
+  @media all and (min-width: 55rem) {
+    .c-tile-list {
+      flex-direction: row;
+      flex-wrap: wrap; } }
+
+/**
+ * Tile list item
+ */
+.c-tile-list__item {
+  width: 100%;
+  margin-bottom: 1em;
+  position: relative; }
+  .c-tile-list__item:nth-child(2n) {
+    padding-right: 0; }
+  @media all and (min-width: 55rem) {
+    .c-tile-list__item {
+      width: 50%;
+      margin: 0;
+      padding: 0 1em 1em 0; } }
+
+/** Thumbnail list
+ *
+ */
+.c-thumbnail-list li {
+  margin-bottom: 1.5em; }
+
+.c-thumbnail-list .c-block-media__media {
+  width: 80px; }
+
+.c-thumbnail-list .c-block-media__headline {
+  text-transform: none !important;
+  font-size: 1.5em; }
+
+/**
+ * Color bars list
+ */
+.c-color-bars-list li {
+  max-width: 480px;
+  position: relative;
+  height: 80px;
+  padding-top: 15px;
+  padding-left: 20px;
+  border: 1px solid #d5d5d5;
+  border-top: 0;
+  color: #55595c;
+  font-size: 1.3rem;
+  font-weight: bold; }
+  .c-color-bars-list li:first-child {
+    border-top: 1px solid #d5d5d5; }
+  .c-color-bars-list li.cur {
+    height: 120px; }
+    .c-color-bars-list li.cur:before {
+      position: absolute;
+      height: 100%;
+      width: 10px;
+      bottom: 0px;
+      left: 0px;
+      content: "";
+      background: #3c6eb4; }
+  .c-color-bars-list li.prev:before {
+    position: absolute;
+    height: 100%;
+    width: 10px;
+    bottom: 0px;
+    left: 0px;
+    content: "";
+    background: #79db32; }
+  .c-color-bars-list li.old {
+    color: #d5d5d5; }
+
+/**
+ * Ticket list
+ */
+.c-ticket-list {
+  max-width: 480px; }
+  .c-ticket-list li {
+    border: 1px solid #d5d5d5;
+    border-top: 0;
+    padding: 15px 20px;
+    color: gray; }
+  .c-ticket-list:first-child {
+    border-top: 1px solid #d5d5d5; }
+  .c-ticket-list .list-item-title, .c-ticket-list .list-item-data {
+    float: left; }
+  .c-ticket-list .list-item-title {
+    border-radius: 20px;
+    padding: 4px 10px;
+    background: gray;
+    color: white;
+    font-size: 1.2rem;
+    font-weight: bold; }
+  .c-ticket-list .origin {
+    float: right;
+    margin-top: 3px; }
+    .c-ticket-list .origin p {
+      display: inline-block;
+      margin-right: 2px; }
+    .c-ticket-list .origin img {
+      margin-bottom: 5px; }
+  .c-ticket-list .c-widget-action-btn.btn {
+    float: right;
+    padding: 3px 15px; }
+    .c-ticket-list .c-widget-action-btn.btn img {
+      display: block; }
+  .c-ticket-list .list-subheader {
+    font-size: 1.2rem;
+    font-weight: bold; }
+  .c-ticket-list .list-item-info, .c-ticket-list .list-item-data {
+    margin: 0;
+    font-size: 1.2rem; }
+
+/*------------------------------------*\
+    #MESSAGING
+\*------------------------------------*/
+/**
+ * Alert
+ */
+.alert {
+  text-align: center;
+  padding: 0 1rem;
+  background: #f7f9f9;
+  overflow: hidden;
+  font-size: 1em;
+  animation: slideDown 2s forwards; }
+  .alert a {
+    color: inherit;
+    /*text-decoration: underline;*/ }
+
+/**
+ * Error alert
+ */
+.alert--error {
+  color: #b12a0b;
+  background: #fdded8; }
+
+/**
+ * Success alert
+ */
+.alert--success {
+  color: #03804d;
+  background: #d4f3e6; }
+
+/**
+ * Warning alert
+ */
+.alert--warning {
+  color: #a59b15;
+  background: #fffecf; }
+
+/**
+ * Info alert
+ */
+.alert--info {
+  color: #0192d0;
+  background: #d3f2ff; }
+
+/**
+ * Slidedown animation
+ */
+@keyframes slideDown {
+  0% {
+    max-height: 0;
+    padding: 0; }
+
+  100% {
+    padding: 1rem;
+    max-height: 12em; } }
+
+/**
+ * Overlay
+ */
+.c-overlay {
+  display: block;
+  padding: 1em;
+  background: rgba(0, 0, 0, 0.7);
+  border-radius: 3px;
+  position: relative;
+  height: 100%;
+  width: 100%;
+  top: 0;
+  left: 0;
+  border-radius: 3px;
+  text-align: center;
+  padding: 1em;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column; }
+  .c-overlay.is-hidden {
+    display: none; }
+  .c-tile-grid__primary .c-overlay {
+    position: absolute; }
+  .c-tile-list__item .c-overlay {
+    position: absolute; }
+  .c-section .c-overlay {
+    position: absolute; }
+
+/**
+* Overlay Intro
+*/
+.c-overlay__intro {
+  font-size: 1.5rem;
+  color: white; }
+
+/*------------------------------------*\
+    #PRIMARY NAVIGATION
+\*------------------------------------*/
+/**
+ * Navigation tag
+ */
+.c-primary-nav {
+  display: none; }
+  .c-primary-nav.is-active {
+    display: block;
+    position: absolute;
+    padding: 1em 2em;
+    top: 67px;
+    right: 0;
+    box-shadow: -3px 3px 5px -2px rgba(0, 0, 0, 0.2);
+    z-index: 2;
+    background: white; }
+  @media all and (min-width: 46.8em) {
+    .c-primary-nav {
+      display: block;
+      margin-right: 1rem; } }
+
+/**
+ * Nav List
+ */
+.c-primary-nav__list {
+  display: none; }
+  @media all and (min-width: 46.8em) {
+    .c-primary-nav__list {
+      display: flex; } }
+  .c-primary-nav--is-active .c-primary-nav__list {
+    display: block; }
+
+/**
+ * Nav Links
+ */
+.c-primary-nav__link {
+  font-weight: bold;
+  display: block;
+  padding: 1rem; }
+
+/**
+ * Pagination
+ */
+.pagination {
+  overflow: hidden; }
+  .pagination li {
+    float: left;
+    border-right: 1px solid #d9d9d9; }
+    .pagination li:last-child {
+      border: 0; }
+  .pagination a {
+    padding: 1em; }
+
+/*------------------------------------*\
+    #PAGE HEADER
+\*------------------------------------*/
+/**
+ * 1) The page header contains the page's heading, as perhaps other page information
+ *    such as description or actions (edit, delete, etc).
+ */
+.c-page-header__title {
+  padding: 1rem 0 0.5rem;
+  position: relative;
+  color: #444444; }
+  .c-page-header__title:after {
+    content: "";
+    display: block;
+    position: absolute;
+    width: 3rem;
+    height: 0.5rem;
+    bottom: 0;
+    background: #a5a5a5; }
+
+/*------------------------------------*\
+    #SECTIONS
+\*------------------------------------*/
+/**
+ * Section
+ */
+.c-section {
+  position: relative;
+  margin: 0 0 2em; }
+  @media all and (min-width: 39.8em) {
+    .l-sidebar .c-section {
+      margin-right: 2em;
+      width: 50%; }
+      .l-sidebar .c-section:last-child {
+        margin-right: 0; } }
+  @media all and (min-width: 50em) {
+    .l-sidebar .c-section {
+      width: 100%;
+      margin-right: 0; } }
+
+/**
+ * Section title
+ */
+.c-section__title {
+  position: relative;
+  color: #444444;
+  margin-bottom: 1.5rem; }
+  .c-section__title:after {
+    content: "";
+    display: block;
+    position: absolute;
+    width: 2rem;
+    height: 0.3rem;
+    top: 30px;
+    left: 1px;
+    background: #a5a5a5; }
+
+/**
+ * Section block
+ */
+.c-tile-grid {
+  background: url(../../images/sample/hero-mountains.jpg) no-repeat 50% 50% #444444;
+  background-size: cover; }
+
+.c-tile-grid__inner {
+  display: flex;
+  flex-direction: column; }
+  @media all and (min-width: 46.8em) {
+    .c-tile-grid__inner {
+      flex-direction: row; } }
+
+.c-tile-grid__primary {
+  display: flex;
+  position: relative;
+  width: 100%;
+  margin-bottom: 1rem; }
+  @media all and (min-width: 46.8em) {
+    .c-tile-grid__primary {
+      width: 50%; } }
+  @media all and (min-width: 55rem) {
+    .c-tile-grid__primary {
+      width: 30%; } }
+
+.c-tile-grid__secondary {
+  flex: 1; }
+  @media all and (min-width: 46.8em) {
+    .c-tile-grid__secondary {
+      padding: 0 0 0 1em; } }
+
+/*------------------------------------*\
+    #TEXT
+\*------------------------------------*/
+/**
+ * Passages of text
+ */
+.text a {
+  text-decoration: none; }
+.text ul {
+  list-style: disc;
+  margin: 0 0 1em 1.2em; }
+  .text ul ul {
+    margin-bottom: 0; }
+.text ol {
+  list-style: decimal;
+  margin: 0 0 1em 1.5em; }
+  .text ol ol {
+    margin-bottom: 0; }
+
+/**
+ * Text passage
+ */
+.s-text-passage {
+  margin-bottom: 1rem; }
+
+/**
+ * Image within text passage
+ */
+.c-text-passage__img {
+  /*
+  	border-radius: $border-radius;
+  	margin-bottom: 1rem;
+      */ }
+
+/*------------------------------------*\
+    #BOX
+\*------------------------------------*/
+/**
+ * 1) This component is a modal-like
+ */
+.c-box {
+  border: 1px solid gray;
+  border-radius: 3px;
+  padding: 2rem;
+  margin: 2rem;
+  align-self: center;
+  justify-content: center;
+  max-width: 32em;
+  margin: 2rem auto; }
+
+.c-box__header {
+  text-align: center;
+  margin-bottom: 2rem; }
+
+/*------------------------------------*\
+    #FEEDBACK
+\*------------------------------------*/
+/**
+ * 1) Feedback consists of components that give information back to the user. Examples include progress bars, progress wheels, etc.
+ */
+/**
+* Progress bar
+*/
+.c-progress {
+  -webkit-appearance: none;
+  appearance: none;
+  border: 1px solid rgba(0, 0, 0, 0.5);
+  background: #cdcaa2;
+  background-size: auto;
+  width: 100%;
+  max-width: 300px;
+  height: 0.5rem;
+  border-radius: 3px;
+  margin-bottom: 1em; }
+
+.c-progress::-moz-progress-bar {
+  background-color: #3884ee;
+  background-size: 300px 50px;
+  border-radius: 3px; }
+
+.c-progress::-webkit-progress-value {
+  background-color: #3884ee;
+  background-size: 300px 50px;
+  border-radius: 3px; }
+
+progress[value]::-webkit-progress-bar {
+  border-radius: 3px; }
+
+.anim::-moz-progress-bar {
+  -moz-transition: width 4s ease; }
+
+.anim::-webkit-progress-value {
+  -webkit-transition: width 4s ease;
+  -o-transition: width 4s ease;
+  transition: width 4s ease; }
+
+.c-progress.start::-moz-progress-bar {
+  width: 0% !important;
+  background: #cdcaa2 !important; }
+
+.c-progress.start::-webkit-progress-value {
+  width: 0% !important;
+  background: #cdcaa2 !important; }
+
+/*------------------------------------*\
+    $LAYOUT
+\*------------------------------------*/
+/*------------------------------------*\
+    #LAYOUT
+\*------------------------------------*/
+/**
+ * Layout container
+ */
+.l {
+  max-width: 80em;
+  margin: 0 auto;
+  padding: 1rem; }
+
+/*------------------------------------*\
+    #TEMPLATES
+\*------------------------------------*/
+/**
+ * 2 column layout
+ */
+.l--two-col {
+  display: flex;
+  flex-direction: column;
+  /**
+   * Sidebar
+   */ }
+  @media all and (min-width: 50em) {
+    .l--two-col .l-main {
+      width: 70%;
+      padding-right: 1em; } }
+  @media all and (min-width: 39.8em) {
+    .l--two-col .l-sidebar {
+      display: flex; } }
+  @media all and (min-width: 50em) {
+    .l--two-col .l-sidebar {
+      flex-direction: column;
+      width: 30%;
+      padding: 0 0 0 1em; } }
+  @media all and (min-width: 50em) {
+    .l--two-col {
+      flex-direction: row; } }
+
+/*------------------------------------*\
+    #GRIDS
+\*------------------------------------*/
+/**
+ * Grid
+ */
+.g {
+  overflow: hidden;
+  margin: 0 -0.5em; }
+
+/**
+ * Grid item
+ */
+.gi {
+  padding: 0.5em; }
+  .gi img {
+    display: block; }
+  @media all and (min-width: 46.8em) {
+    .gi {
+      float: left; } }
+
+/**
+ * 2 up grid
+ */
+@media all and (min-width: 46.8em) {
+  .g-2up > .gi {
+    float: left;
+    width: 50%; }
+    .g-2up > .gi:nth-of-type(odd) {
+      clear: left; } }
+
+/**
+ * Grid side by side
+ */
+.g-half > .gi {
+  float: left;
+  width: 50%; }
+  .g-half > .gi:nth-of-type(odd) {
+    clear: left; }
+
+/**
+ * 3 up grid
+ */
+@media all and (min-width: 46.8em) {
+  .g-3up > .gi {
+    float: left;
+    width: 50%; }
+    .g-3up > .gi:nth-of-type(2n+1) {
+      clear: left; } }
+@media all and (min-width: 50em) {
+  .g-3up > .gi {
+    width: 33.3333333%; }
+    .g-3up > .gi:nth-of-type(2n+1) {
+      clear: none; }
+    .g-3up > .gi:nth-of-type(3n+1) {
+      clear: left; } }
+
+/**
+ * 4 up grid
+ */
+@media all and (min-width: 46.8em) {
+  .g-4up > .gi {
+    float: left;
+    width: 50%; }
+    .g-4up > .gi:nth-of-type(2n+1) {
+      clear: both; } }
+@media all and (min-width: 50em) {
+  .g-4up > .gi {
+    width: 25%; }
+    .g-4up > .gi:nth-of-type(2n+1) {
+      clear: none; }
+    .g-4up > .gi:nth-of-type(4n+1) {
+      clear: left; } }
+
+/**
+ * Quarter grid always displayed side by side
+ */
+.g-quarter > .gi {
+  float: left;
+  width: 24%; }
+  .g-quarter > .gi:nth-of-type(4n+1) {
+    clear: left; }
+
+/**
+ * Grid max 4 up
+ */
+@media all and (min-width: 29.75em) {
+  .g-max4 > .gi {
+    float: left;
+    width: 50%; }
+    .g-max4 > .gi:nth-of-type(2n+1) {
+      clear: both; } }
+@media all and (min-width: 39.8em) {
+  .g-max4 > .gi {
+    width: 33.3333333%; }
+    .g-max4 > .gi:nth-of-type(2n+1) {
+      clear: none; }
+    .g-max4 > .gi:nth-of-type(3n+1) {
+      clear: left; } }
+@media all and (min-width: 50em) {
+  .g-max4 > .gi {
+    width: 25%; }
+    .g-max4 > .gi:nth-of-type(3n+1) {
+      clear: none; }
+    .g-max4 > .gi:nth-of-type(4n+1) {
+      clear: left; } }
+
+/**
+ * Grid max of 5 up
+ */
+.g-max5 > .gi {
+  float: left;
+  width: 50%; }
+  .g-max5 > .gi:nth-of-type(2n+1) {
+    clear: both; }
+@media all and (min-width: 39.8em) {
+  .g-max5 > .gi {
+    width: 33.3333333%; }
+    .g-max5 > .gi:nth-of-type(2n+1) {
+      clear: none; }
+    .g-max5 > .gi:nth-of-type(3n+1) {
+      clear: left; } }
+@media all and (min-width: 46.8em) {
+  .g-max5 > .gi {
+    width: 25%; }
+    .g-max5 > .gi:nth-of-type(3n+1) {
+      clear: none; }
+    .g-max5 > .gi:nth-of-type(4n+1) {
+      clear: left; } }
+@media all and (min-width: 48em) {
+  .g-max5 > .gi {
+    width: 20%; }
+    .g-max5 > .gi:nth-of-type(4n+1) {
+      clear: none; }
+    .g-max5 > .gi:nth-of-type(5n+1) {
+      clear: left; } }
+
+/*------------------------------------*\
+    WIP
+\*------------------------------------*/
+#atoms-fonts .sg-pattern-example div {
+  font-size: 140%; }
+
+/*------------------------------------*\
+    #TYPOGRAPHY
+\*------------------------------------*/
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-ExtraBold.ttf") format("opentype");
+  font-weight: 900; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-Bold.ttf") format("opentype");
+  font-weight: 700; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-Regular.ttf") format("opentype");
+  font-weight: 500; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-Light.ttf") format("opentype");
+  font-weight: 300; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-ExtraBoldItalic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 900; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-BoldItalic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 700; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-SemiboldItalic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 600; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-Italic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 500; }
+
+@font-face {
+  font-family: "Open Sans";
+  src: url("../../fonts/OpenSans-LightItalic.ttf") format("opentype");
+  font-style: italic;
+  font-weight: 300; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Black.otf") format("opentype");
+  font-weight: 900; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-ExtraBold.otf") format("opentype");
+  font-weight: 800; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Bold.otf") format("opentype");
+  font-weight: 700; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-SemiBold.otf") format("opentype");
+  font-weight: 600; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Regular.otf") format("opentype");
+  font-weight: 400; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Light.otf") format("opentype");
+  font-weight: 300; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-UltraLight.otf") format("opentype");
+  font-weight: 200; }
+
+@font-face {
+  font-family: "Montserrat";
+  src: url("../../fonts/Montserrat-Hairline.otf") format("opentype");
+  font-weight: 100; }
+
+/* Override on the styleguide module */
+.sg-pattern-category-body {
+  font-size: 100% !important; }
+
+/*------------------------------------*\
+    #OBJECTS
+\*------------------------------------*/
+/**
+ * Widget header
+ */
+.c-widget-header.card-header {
+  padding: 10px 10px 5px 10px;
+  max-width: 480px;
+  border: 1px solid #d5d5d5;
+  border-radius: 0 !important;
+  background: #f7f7f9; }
+
+.c-widget-header h6 {
+  font-family: "Open Sans";
+  font-size: 1.3rem;
+  font-weight: normal; }
+
+.c-widget-header-btn {
+  margin-top: -29px;
+  float: right; }
+
+/**
+ * Widget action button
+ */
+.c-widget-action-btn.btn {
+  padding: 5px 10px;
+  color: #a07cbc;
+  font-weight: bold; }
+  .c-widget-action-btn.btn:hover, .c-widget-action-btn.btn:focus, .c-widget-action-btn.btn:active, .c-widget-action-btn.btn:active:focus {
+    color: #a07cbc; }
+
+/**
+ * Widget view more button
+ */
+.c-widget-view-more-btn button {
+  padding: 0px;
+  margin-right: 5px;
+  color: gray;
+  font-size: 1.2rem; }
+  .c-widget-view-more-btn button:hover, .c-widget-view-more-btn button:focus {
+    color: #55595c; }
+.c-widget-view-more-btn img {
+  margin-top: 2px; }
+
+/**
+ * Widget meeting event
+ */
+.c-widget-meeting-event {
+  max-width: 480px;
+  border: 1px solid #d5d5d5;
+  padding: 15px 20px; }
+  .c-widget-meeting-event h6, .c-widget-meeting-event h5, .c-widget-meeting-event p {
+    color: #55595c;
+    font-family: "Open Sans"; }
+  .c-widget-meeting-event h5 {
+    font-weight: bold;
+    font-size: 2rem; }
+  .c-widget-meeting-event h6 {
+    margin-top: 2px;
+    margin-bottom: 10px;
+    font-size: 1.1rem; }
+  .c-widget-meeting-event .date, .c-widget-meeting-event .time-ch {
+    font-size: 0.9rem;
+    float: left; }
+  .c-widget-meeting-event button {
+    float: right; }
+  .c-widget-meeting-event .date {
+    margin-right: 20px; }
+  .c-widget-meeting-event .time-ch p, .c-widget-meeting-event .time-ch a {
+    padding: 0;
+    margin: 0; }
+
+/**
+ * Widget meeting request
+ */
+.c-widget-meeting-request {
+  max-width: 480px;
+  border: 1px solid #d5d5d5;
+  padding: 15px 20px; }
+  .c-widget-meeting-request h6, .c-widget-meeting-request h5 {
+    color: #55595c;
+    font-family: "Open Sans"; }
+  .c-widget-meeting-request h5 {
+    float: left;
+    font-weight: bold;
+    font-size: 2rem; }
+  .c-widget-meeting-request h6 {
+    margin-top: 2px;
+    margin-bottom: 10px;
+    font-size: 1.1rem; }
+  .c-widget-meeting-request .meeting-request-btn {
+    float: right; }
+
+.modal-header {
+  background-color: #eceeef; }
+
+.modal-footer {
+  border-top: 0px !important; }
+
+.modal h4 {
+  text-transform: none !important; }
+
+.modal-card {
+  background-color: #d5d5d5;
+  padding: 15px; }
+
+.modal-body h4 {
+  font-weight: 600 !important; }
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index d512d2c..46faaea 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -357,6 +357,7 @@ font-size: 32pt;
 
 .meeting h5 { 
     font-size: small !important;
+    margin-bottom: .5rem;
 }
 
 .meeting .meeting-date {
@@ -581,6 +582,28 @@ font-size: 32pt;
 
 
 /*
+ * Issue Widgets
+ */
+ 
+.widget .widget-pagure_pr h5,
+.widget .widget-githubissues h5,
+.widget .widget-bugzilla h5 {
+  font-weight: bold;
+}
+
+.widget .widget-pagure_pr li,
+.widget .widget-githubissues li,
+.widget .widget-bugzilla li {
+  border-bottom: 1px solid rgba(0, 0, 0, .125);
+}
+
+.widget .widget-pagure_pr li:last-child,
+.widget .widget-githubissues li:last-child,
+.widget .widget-bugzilla li:last-child {
+border: 0}
+
+
+/*
  * Widget Feed
  */
 
@@ -628,7 +651,7 @@ header h5.m-b-1 {
 }
 
 #right_widgets .widget .card-block {
-  padding: 0.25rem 0.6rem !important;
+  padding: 0.6rem !important;
 }
 
 #right_widgets .widget-rules .card-block {
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 10c831e..f269e51 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -2,6 +2,7 @@
 <html lang='en'>
 <head>
   <title>{% block title %}{% endblock %}</title>
+  <link href="{{ url_for('static', filename='css/style-patternlab.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.min.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
diff --git a/hubs/widgets/bugzilla/templates/root.html b/hubs/widgets/bugzilla/templates/root.html
index 5fc68b5..e539ece 100644
--- a/hubs/widgets/bugzilla/templates/root.html
+++ b/hubs/widgets/bugzilla/templates/root.html
@@ -10,10 +10,10 @@
         </a>
       </div>
       <div class="media-body">
-        <h4 class="media-heading">
+        <h5 class="media-heading">
           <a href="https://apps.fedoraproject.org/packages/{{ item['pkg_name'] }}" target="_blank">{{ item['pkg_name'] }}</a>:
           {{ item['title'] }}
-        </h4>
+        </h5>
       </div>
     </li>
   {% endfor %}
diff --git a/hubs/widgets/githubissues/templates/root.html b/hubs/widgets/githubissues/templates/root.html
index 31943ae..33cde81 100644
--- a/hubs/widgets/githubissues/templates/root.html
+++ b/hubs/widgets/githubissues/templates/root.html
@@ -1,41 +1,46 @@
 {% extends "panel.html" %}
 
 {% block content %}
+
+<ul class="media-list">
+    
 {% for i in range(display_number) %}
-<div>
-  <table class="table-responsive table-condensed">
-    <tr>
-      <td valign="top" class="panel-heading">
-        <b>#{{ all_issues[i]['num'] }}</b>
-      </td>
-      <td width="300px">
-        <b>{{ all_issues[i]['title'] }}</b>
-      </td>
-    </tr>
-  </table>
-  <table class="table-responsive table-condensed">
-    <tr>
-      <td width="300px">
-        <font size="2">
-          <i>Opened by <a href="https://github.com/{{ all_issues[i]['openedby'] }}" target="_blank">{{ all_issues[i]['openedby'] }}</a></i>
+<li class="media">
+  <div class="media-left">
+    <a href="#" target="_blank">
+      <span class="label label-default">#{{ all_issues[i]['num'] }}</span>
+    </a>
+  </div>
+  <div class="media-body">
+    <h5 class="media-heading">
+        {{ all_issues[i]['title'] }}
+    </h5>
+    <div class="row no-gutters">
+      <div class="col-md-10">
+        <i>Opened by <a href="https://github.com/{{ all_issues[i]['openedby'] }}" target="_blank">{{ all_issues[i]['openedby'] }}</a></i>
           {% if all_issues[i]['assignee']|string() == "None" %}
             <br /><i>Unclaimed</i>
           {% else %}
              <br /><i>Assigned by <a href="https://github.com/{{ all_issues[i]['assignee'] }}" target="_blank">{{ all_issues[i]['assignee'] }}</a></i>
           {% endif %}
-        </font>
-      </td>
-      <td>
-         <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
-           <button type="button" class="btn btn-secondary" aria-label="Left Align">
-             <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+
+      </div>
+      <div class="col-md-2">
+      <a href="https://github.com/{{ org }}/{{ repo }}/issues/{{ all_issues[i]['num'] }}" target="_blank">
+           <button type="button" class="btn btn-secondary btn-sm" aria-label="Left Align">
+             <i class="fa fa-chevron-right" aria-hidden="true"></i>
            </button>
          </a>
-      </td>
-    </tr>
-  </table>
-</div>
+      </div>
+    </div>
+    
+             
+    </div>
+</li>
 {% endfor %}
+
+</ul>
+
 <div class="row">
   <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
 </div>
diff --git a/hubs/widgets/meetings/templates/root.html b/hubs/widgets/meetings/templates/root.html
index e3948aa..3b49aba 100644
--- a/hubs/widgets/meetings/templates/root.html
+++ b/hubs/widgets/meetings/templates/root.html
@@ -14,13 +14,13 @@
       <strong>{{next.start_date}}</strong>
       {% endif %}
     </div>
-    <div class="col-md-4 meeting-time">
+    <div class="col-md-4 col-lg-5 meeting-time">
       {% if next.display_time %}
       @{{ next.start_time }}{% endif %}<br>
 
       <a href="#">{{ next.location }}</a>
     </div>
-    <div class="col-md-5">
+    <div class="col-md-5 col-lg-4 text-right">
       <a href="https://apps.fedoraproject.org/calendar/ical/calendar/meeting/{{ next.meeting_id }}/">
         <button class="btn btn-secondary btn-sm add-calendar">
           <strong>Add to calendar</strong>
diff --git a/hubs/widgets/pagure_pr/templates/root.html b/hubs/widgets/pagure_pr/templates/root.html
index 9a7f3f2..e41a43a 100644
--- a/hubs/widgets/pagure_pr/templates/root.html
+++ b/hubs/widgets/pagure_pr/templates/root.html
@@ -11,13 +11,13 @@
         </a>
       </div>
       <div class="media-body">
-        <h4 class="media-heading">
+        <h5 class="media-heading">
           {{ pr['pr_project_name'] }} -
           <span title="{{ pr['pr_title_full'] }}">
             {{ pr['pr_title'] }} {% if
               pr['pr_title_full'] | length > 45 %} ... {% endif %}
           </span>
-        </h4>
+        </h5>
         Opened by:
           <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
               target="_blank">

From d9cffe7e2e742375c200897896ea1c6a9fd11834 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 08:50:55 +0000
Subject: [PATCH 927/1001] Set some defaults for the autodoc Sphinx extension


---

diff --git a/docs/api/utils.rst b/docs/api/utils.rst
index 773eb40..5338291 100644
--- a/docs/api/utils.rst
+++ b/docs/api/utils.rst
@@ -5,23 +5,18 @@ View utils
 ----------
 
 .. automodule:: hubs.utils.views
-   :members:
 
 Caching utils
 -------------
 
 .. automodule:: hubs.utils.cache
-   :members:
 
 Package database utils
 ----------------------
 
 .. automodule:: hubs.utils.packages
-   :members:
 
 Datagrepper utils
 -----------------
 
 .. automodule:: hubs.utils.datagrepper
-   :members:
-
diff --git a/docs/api/widgets.rst b/docs/api/widgets.rst
index 021bf49..f828673 100644
--- a/docs/api/widgets.rst
+++ b/docs/api/widgets.rst
@@ -5,40 +5,31 @@ Widgets
 =======
 
 .. automodule:: hubs.widgets
-   :members:
-   :show-inheritance:
 
 Widgets registry
 ----------------
 
 .. automodule:: hubs.widgets.registry
-   :members:
-   :show-inheritance:
 
 Widget class
 ------------
 
 .. automodule:: hubs.widgets.base
-   :members:
-   :show-inheritance:
+   :private-members:
 
 Widget parameter validators
 ---------------------------
 
 .. automodule:: hubs.widgets.validators
-   :members:
-   :show-inheritance:
 
 Widget view
 -----------
 
 .. automodule:: hubs.widgets.view
-   :members:
-   :show-inheritance:
+   :private-members:
 
 Caching
 -------
 
 .. automodule:: hubs.widgets.caching
-   :members:
-   :show-inheritance:
+   :private-members:
diff --git a/docs/conf.py b/docs/conf.py
index 30c5281..194929b 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -119,6 +119,9 @@ pygments_style = 'sphinx'
 # If true, `todo` and `todoList` produce output, else they produce nothing.
 todo_include_todos = True
 
+# Default flags for the autodoc extension: show public members (some private members need to be overriiden
+autodoc_default_flags = ['members', 'show-inheritance']
+
 
 # -- Options for HTML output ----------------------------------------------
 

From 45084e03264d0cbd773eb8cbb1795459b7d2deff Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 08:50:55 +0000
Subject: [PATCH 928/1001] Add a switch for config-independant cached functions


---

diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index c531cc0..2476ca8 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -34,16 +34,22 @@ class CachedFunction(object):
     To call the function, instantiate the class and execute it. You may also
     call the :py:meth:`.get_data` method.
 
-    Args:
+    Attributes:
         instance (hubs.models.Widget): The widget instance.
+        invalidate_on_config_change (bool): ``True`` if the cached result
+            depends on the widget configuration, ``False`` otherwise. Defaults
+            to ``True``. E.g: the function retrieves a lot of raw data from an
+            external service, and config-dependant filtering is done in the
+            view calling the function.
     """
 
+    invalidate_on_config_change = True
+
     def __init__(self, instance):
         self.instance = instance
 
     def execute(self):
-        """
-        The function to cache.
+        """The function to cache.
 
         This is the main method, it must be implemented.
 
@@ -53,11 +59,10 @@ class CachedFunction(object):
         raise NotImplementedError
 
     def get_cache_key(self):
-        return "|".join([
-            str(self.instance.idx),
-            self.__class__.__name__,
-            json.dumps(self.instance.config),
-        ]).encode('utf-8')
+        key_elements = [str(self.instance.idx), self.__class__.__name__]
+        if self.invalidate_on_config_change:
+            key_elements.append(json.dumps(self.instance.config))
+        return "|".join(key_elements).encode('utf-8')
 
     def get_data(self):
         key = self.get_cache_key()
diff --git a/hubs/widgets/halp/functions.py b/hubs/widgets/halp/functions.py
index 662081d..0191710 100644
--- a/hubs/widgets/halp/functions.py
+++ b/hubs/widgets/halp/functions.py
@@ -25,6 +25,7 @@ class GetRequests(CachedFunction):
     them.
     """
 
+    invalidate_on_config_change = False
     TOPIC = "org.fedoraproject.prod.meetbot.meeting.item.help"
 
     def execute(self):

From d2a300e741de607b5be91bfd547e8a7f10d84966 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 08:50:55 +0000
Subject: [PATCH 929/1001] Add a subclassable function to signal a value should not be cached


---

diff --git a/hubs/widgets/caching.py b/hubs/widgets/caching.py
index 2476ca8..6a499a5 100644
--- a/hubs/widgets/caching.py
+++ b/hubs/widgets/caching.py
@@ -68,10 +68,24 @@ class CachedFunction(object):
         key = self.get_cache_key()
         log.debug("Accessing cache key %s", key)
         return cache.get_or_create(
-            key, self.execute)
+            key, self.execute, should_cache_fn=self._should_cache)
 
     __call__ = get_data
 
+    def _should_cache(self, value):
+        """Indicates if the result should be cached.
+
+        This function which will receive the value returned by
+        :py:meth:`.execute`, and will then return ``True`` or ``False``,
+        indicating if the value should actually be cached or not. If it returns
+        ``False``, the value is still returned, but isn't cached. E.g.::
+
+                return (value is not None)
+
+        Defaults to ``True``.
+        """
+        return True
+
     def should_invalidate(self, message):
         """
         Tell the cache invalidator if the received message should invalidate

From 97171f7865532c2985804851f7fdec21710fad59 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 08:52:48 +0000
Subject: [PATCH 930/1001] Filter out widgets that have been disabled


---

diff --git a/check-cache-coverage.py b/check-cache-coverage.py
index 4e623cc..f79f4c1 100755
--- a/check-cache-coverage.py
+++ b/check-cache-coverage.py
@@ -29,6 +29,8 @@ session = hubs.app.session
 hubs.widgets.registry.register_list(hubs.app.app.config["WIDGETS"])
 
 for w_instance in session.query(hubs.models.Widget).all():
+    if not w_instance.enabled:
+        continue
     for fn_name, fn_class in w_instance.module.get_cached_functions().items():
         if fn_class(w_instance).is_cached():
             full += 1
diff --git a/hubs/backend/triage.py b/hubs/backend/triage.py
index f59769b..b4bb412 100755
--- a/hubs/backend/triage.py
+++ b/hubs/backend/triage.py
@@ -91,6 +91,8 @@ def get_widgets():
     # Get a list of all our widgets:
     log.debug("Querying for all widgets.")
     widgets = session.query(hubs.models.Widget).all()
+    # Filter out widgets that have been disabled.
+    widgets = [w for w in widgets if w.enabled]
     # Randomize so that all the triage daemons work on widgets in different
     # orders.  This should hopefully prevent cache thrashing.
     log.debug("Randomizing list of all widgets.")
diff --git a/hubs/models.py b/hubs/models.py
index f894c22..eebd178 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -456,6 +456,10 @@ class Widget(ObjectAuthzMixin, BASE):
     def edit_url(self):
         return self.module.get_edit_url(self.hub, self)
 
+    @property
+    def enabled(self):
+        return self.plugin in hubs.widgets.registry
+
 
 class User(BASE):
     __tablename__ = 'users'
diff --git a/smart_cache_invalidator.py b/smart_cache_invalidator.py
index 75b4487..b74fdad 100755
--- a/smart_cache_invalidator.py
+++ b/smart_cache_invalidator.py
@@ -27,6 +27,8 @@ hubs.widgets.registry.register_list(hubs.app.app.config["WIDGETS"])
 def do_list(args):
     ''' List the different widget for which there is data cached. '''
     for w_instance in session.query(hubs.models.Widget).all():
+        if not w_instance.enabled:
+            continue
         widget = w_instance.module
         for fn_name, fn_class in widget.get_cached_functions().items():
             if fn_class(w_instance).is_cached():

From 6aa5e8f3abbf1b926fbfab8f8795dc213391dd19 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 08:52:48 +0000
Subject: [PATCH 931/1001] Add a couple unit tests


---

diff --git a/hubs/tests/backend/__init__.py b/hubs/tests/backend/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/tests/backend/__init__.py
diff --git a/hubs/tests/backend/test_triage.py b/hubs/tests/backend/test_triage.py
new file mode 100644
index 0000000..10d0794
--- /dev/null
+++ b/hubs/tests/backend/test_triage.py
@@ -0,0 +1,28 @@
+from __future__ import unicode_literals
+
+from hubs.app import app
+from hubs.backend import triage
+from hubs.models import Hub, Widget
+from hubs.tests import APPTest
+
+
+class TriageTest(APPTest):
+
+    def setUp(self):
+        super(TriageTest, self).setUp()
+        # Set the session
+        triage.session = self.session
+
+
+    def test_get_widgets(self):
+        # Get all widgets except those whose module isn't installed.
+        hub = Hub.by_name('ralph')
+        widget = Widget(
+            plugin='non-existant',
+            index=500,
+            _config="{}",
+            )
+        hub.widgets.append(widget)
+        module_names = [w.plugin for w in triage.get_widgets()]
+        self.assertNotIn("non-existant", module_names)
+        self.assertEqual(len(module_names), 59)
diff --git a/hubs/tests/test_models.py b/hubs/tests/test_models.py
index 175caa1..be7be21 100644
--- a/hubs/tests/test_models.py
+++ b/hubs/tests/test_models.py
@@ -229,3 +229,9 @@ class ModelTest(hubs.tests.APPTest):
         widget.visibility = "restricted"
         self.assertEqual(
             widget._get_auth_permission_name("view"), "widget.restricted.view")
+
+    def test_widget_enabled(self):
+        hub = hubs.models.Hub.get("ralph")
+        widget = hubs.models.Widget(hub=hub, plugin="does-not-exist")
+        self.session.add(widget)
+        self.assertFalse(widget.enabled)

From 2b75eeece26aa09a646ae545d5c4dc29393e9ccb Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 08:54:40 +0000
Subject: [PATCH 932/1001] Implement two widgets' should_invalidate methods


Fixes: #349, #350

---

diff --git a/hubs/tests/widgets/__init__.py b/hubs/tests/widgets/__init__.py
index 653e9d6..73de0fc 100644
--- a/hubs/tests/widgets/__init__.py
+++ b/hubs/tests/widgets/__init__.py
@@ -10,10 +10,11 @@ from hubs.tests import APPTest, FakeAuthorization, widget_instance
 class WidgetTest(APPTest):
 
     plugin = None  # The name in hubs.widgets.registry
+    initial_widget_config = None
 
     def populate(self):
         super(WidgetTest, self).populate()
-        hub = hubs.models.Hub.by_name('ralph')
+        hub = hubs.models.Hub.query.get("ralph")
         widget = hubs.models.Widget(
             plugin='library',
             index=51,
@@ -23,6 +24,17 @@ class WidgetTest(APPTest):
         hub.widgets.append(widget)
         self.session.commit()
 
+    def _add_widget_under_test(self):
+        hub = hubs.models.Hub.query.get("ralph")
+        self.widget = hubs.models.Widget(
+            plugin=self.plugin,
+            index=1,
+            _config=json.dumps(self.initial_widget_config or {}),
+        )
+        hub.widgets.append(self.widget)
+        self.session.commit()
+        self.session.refresh(self.widget)
+
     def _test_view_authz(self):
         # Test authorizations on the root view.
         if not self.plugin:
diff --git a/hubs/tests/widgets/test_githubissues.py b/hubs/tests/widgets/test_githubissues.py
new file mode 100644
index 0000000..d36c243
--- /dev/null
+++ b/hubs/tests/widgets/test_githubissues.py
@@ -0,0 +1,54 @@
+from __future__ import unicode_literals
+
+from . import WidgetTest
+
+
+class TestGithubIssues(WidgetTest):
+
+    plugin = "githubissues"
+    initial_widget_config = {
+        "org": "fedora-infra",
+        "repo": "fedora-hubs",
+    }
+
+    def populate(self):
+        super(TestGithubIssues, self).populate()
+        self._add_widget_under_test()
+
+    def _get_should_invalidate_result(self, msg):
+        func = self.widget.module.get_cached_functions()['GetIssues']
+        return func(self.widget).should_invalidate(msg)
+
+    def test_should_invalidate_wrong_topic(self):
+        msg = {'topic': 'hubs.widget.update.WRONG.TOPIC'}
+        self.assertFalse(self._get_should_invalidate_result(msg))
+
+    def test_should_invalidate_good_match(self):
+        msg = {
+            'topic': 'tests.github.issue.opened',
+            'msg': {
+                'organization': 'fedora-infra',
+                'repository': 'fedora-hubs',
+            }
+        }
+        self.assertTrue(self._get_should_invalidate_result(msg))
+
+    def test_should_invalidate_wrong_org(self):
+        msg = {
+            'topic': 'tests.github.issue.opened',
+            'msg': {
+                'organization': 'not_fedora_infra',
+                'repository': 'fedora-hubs',
+            }
+        }
+        self.assertFalse(self._get_should_invalidate_result(msg))
+
+    def test_should_invalidate_wrong_repo(self):
+        msg = {
+            'topic': 'tests.github.issue.opened',
+            'msg': {
+                'organization': 'fedora-infra',
+                'repository': 'not-fedora-hubs',
+            }
+        }
+        self.assertFalse(self._get_should_invalidate_result(msg))
diff --git a/hubs/tests/widgets/test_pagureissues.py b/hubs/tests/widgets/test_pagureissues.py
new file mode 100644
index 0000000..a55c272
--- /dev/null
+++ b/hubs/tests/widgets/test_pagureissues.py
@@ -0,0 +1,45 @@
+from __future__ import unicode_literals
+
+from . import WidgetTest
+
+
+class TestPagureIssues(WidgetTest):
+
+    plugin = "pagureissues"
+    initial_widget_config = {
+        "repo": "fedora-hubs",
+    }
+
+    def populate(self):
+        super(TestPagureIssues, self).populate()
+        self._add_widget_under_test()
+
+    def _get_should_invalidate_result(self, msg):
+        func = self.widget.module.get_cached_functions()['GetIssues']
+        return func(self.widget).should_invalidate(msg)
+
+    def test_should_invalidate_wrong_topic(self):
+        msg = {'topic': 'hubs.widget.update.WRONG.TOPIC'}
+        self.assertFalse(self._get_should_invalidate_result(msg))
+
+    def test_should_invalidate_good_match(self):
+        msg = {
+            'topic': 'tests.pagure.issue.new',
+            'msg': {
+                "project": {
+                    "name": "fedora-hubs",
+                },
+            },
+        }
+        self.assertTrue(self._get_should_invalidate_result(msg))
+
+    def test_should_invalidate_wrong_repo(self):
+        msg = {
+            'topic': 'tests.pagure.issue.new',
+            'msg': {
+                "project": {
+                    "name": "not-fedora-hubs",
+                },
+            },
+        }
+        self.assertFalse(self._get_should_invalidate_result(msg))
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index e2a25e2..0575545 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -76,4 +76,15 @@ class GetIssues(CachedFunction):
         return all_issues
 
     def should_invalidate(self, message):
-        raise NotImplementedError
+        if ".github.issue." not in message["topic"]:
+            return False
+        try:
+            org = message['msg']['organization']
+            repo = message['msg']['repository']
+        except KeyError:
+            return False
+        return (
+            org == self.instance.config["org"]
+            and
+            repo == self.instance.config["repo"]
+            )
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index d8db995..3ba90d9 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -87,4 +87,10 @@ class GetIssues(CachedFunction):
         )
 
     def should_invalidate(self, message):
-        raise NotImplementedError
+        if ".pagure.issue." not in message["topic"]:
+            return False
+        try:
+            repo = message['msg']['project']['name']
+        except KeyError:
+            return False
+        return (repo == self.instance.config['repo'])

From c93664a357193fc3388dbc166356364d2b738815 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 09:48:19 +0000
Subject: [PATCH 933/1001] Fix lint errors


---

diff --git a/docs/conf.py b/docs/conf.py
index 194929b..28fcba2 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -119,7 +119,8 @@ pygments_style = 'sphinx'
 # If true, `todo` and `todoList` produce output, else they produce nothing.
 todo_include_todos = True
 
-# Default flags for the autodoc extension: show public members (some private members need to be overriiden
+# Default flags for the autodoc extension: show public members (some private
+# members need to be overridden)
 autodoc_default_flags = ['members', 'show-inheritance']
 
 
diff --git a/hubs/tests/backend/test_triage.py b/hubs/tests/backend/test_triage.py
index 10d0794..f7ce077 100644
--- a/hubs/tests/backend/test_triage.py
+++ b/hubs/tests/backend/test_triage.py
@@ -1,6 +1,5 @@
 from __future__ import unicode_literals
 
-from hubs.app import app
 from hubs.backend import triage
 from hubs.models import Hub, Widget
 from hubs.tests import APPTest
@@ -13,7 +12,6 @@ class TriageTest(APPTest):
         # Set the session
         triage.session = self.session
 
-
     def test_get_widgets(self):
         # Get all widgets except those whose module isn't installed.
         hub = Hub.by_name('ralph')

From ef755b65375fbf1668bb55eb93ccc6bf97c7c7f9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 09:59:19 +0000
Subject: [PATCH 934/1001] Don't traceback when the PlusPlus service isn't reachable


---

diff --git a/hubs/tests/widgets/test_contact.py b/hubs/tests/widgets/test_contact.py
index 8bea137..7e06862 100644
--- a/hubs/tests/widgets/test_contact.py
+++ b/hubs/tests/widgets/test_contact.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
 import json
 
 import mock
+import requests
 
 import hubs
 from hubs.models import Hub, Widget
@@ -172,3 +173,11 @@ class ContactsTest(WidgetTest):
         result = self.app.get(url)
         self.assertEqual(result.status_code, 404)
         self.assertEqual(result.get_data(as_text=True), 'User does not exist')
+
+    @mock.patch('requests.get')
+    def test_plus_plus_connection_error(self, mock_get):
+        mock_get.side_effect = requests.ConnectionError("connection error")
+        url = "/ralph/w/contact/%d/plus-plus/%s/status" % (
+            self.widget_idx, "decause")
+        result = self.app.get(url)
+        self.assertEqual(result.status_code, 504)
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index 0d6c6b3..288fc92 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -93,6 +93,8 @@ class PlusPlusStatus(WidgetView):
             req = requests.get(pp_url, timeout=5)
         except requests.Timeout:
             return 'The request to {url} timed out'.format(url=pp_url), 504
+        except requests.ConnectionError:
+            return 'Could not connect to {url}'.format(url=pp_url), 504
         if req.status_code == 200:
             return flask.jsonify(req.json())
         else:

From 74f3a34eab01279837f4715de6ae864dcbaf9e5d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 10:02:50 +0000
Subject: [PATCH 935/1001] Protect the badges widget against invalid and malformed data


---

diff --git a/hubs/tests/widgets/test_badges.py b/hubs/tests/widgets/test_badges.py
index d460a1f..a984070 100644
--- a/hubs/tests/widgets/test_badges.py
+++ b/hubs/tests/widgets/test_badges.py
@@ -2,6 +2,8 @@ from __future__ import unicode_literals
 
 import json
 
+from mock import Mock, patch
+
 import hubs.widgets
 from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
@@ -63,3 +65,23 @@ class TestBadges(WidgetTest):
 
     def test_view_authz(self):
         self._test_view_authz()
+
+    @patch("hubs.widgets.badges.requests")
+    def test_invalid_data(self, requests):
+        response = Mock()
+        response.json.side_effect = ValueError("invalid value")
+        requests.get.return_value = response
+        widget = widget_instance('ralph', self.plugin)
+        func = widget.module.get_cached_functions()['GetBadges']
+        result = func(widget).execute()
+        self.assertEqual(result, dict(assertions=[]))
+
+    @patch("hubs.widgets.badges.requests")
+    def test_malformed_data(self, requests):
+        response = Mock()
+        response.json.return_value = {}
+        requests.get.return_value = response
+        widget = widget_instance('ralph', self.plugin)
+        func = widget.module.get_cached_functions()['GetBadges']
+        result = func(widget).execute()
+        self.assertEqual(result, dict(assertions=[]))
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index 1e5fcea..f3e8f78 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -38,7 +38,10 @@ class GetBadges(CachedFunction):
         url = "https://badges.fedoraproject.org/user/{username}/json"
         url = url.format(username=username)
         response = requests.get(url)
-        assertions = response.json()['assertions']
+        try:
+            assertions = response.json()['assertions']
+        except (KeyError, ValueError):
+            assertions = []
         key = operator.itemgetter('issued')
         return dict(assertions=sorted(assertions, key=key, reverse=True))
 

From e6715a752d3bdfadbd26642297a0b143f0bd870d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 10:03:34 +0000
Subject: [PATCH 936/1001] Protect get_user_packages from malformed JSON


---

diff --git a/hubs/tests/utils/test_packages.py b/hubs/tests/utils/test_packages.py
index 5b258d1..bb50742 100644
--- a/hubs/tests/utils/test_packages.py
+++ b/hubs/tests/utils/test_packages.py
@@ -63,3 +63,13 @@ class PackageUtilsTest(APPTest):
         get_user_packages("abompard", use_cache=True)
         self.assertTrue(self._is_cached())
         self.assertEqual(requests.get.call_count, 1)
+
+    @patch("hubs.utils.packages.requests")
+    def test_get_user_packages_malformed(self, requests):
+        response = Mock()
+        response.json.return_value = {
+            "error": "something bad happened"
+        }
+        requests.get.return_value = response
+        pkgs = get_user_packages("abompard", use_cache=False)
+        self.assertListEqual(pkgs, [])
diff --git a/hubs/utils/packages.py b/hubs/utils/packages.py
index 0335ceb..e2276e6 100644
--- a/hubs/utils/packages.py
+++ b/hubs/utils/packages.py
@@ -40,8 +40,15 @@ def get_user_packages(username, only_owned=False, use_cache=True):
                 "Invalid JSON response getting the list of packages "
                 "owned by %s: %s", username, response.text)
             return []
+        try:
+            repos = data["repos"]
+        except KeyError:
+            log.warning(
+                "Malformed JSON response getting the list of packages "
+                "owned by %s: %s", username, response.text)
+            return []
         return sorted(set(
-            repo['name'] for repo in data["repos"]
+            repo['name'] for repo in repos
             if not only_owned or repo["user"]["name"] == username
             ))
     if not use_cache:

From e5248bb57795ad48fb7c4b8228d10b5b117f9039 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 11:23:19 +0000
Subject: [PATCH 937/1001] Fix links in the feed


The HTML links for the feed items were generated when the backend
received a message. At that point, the backend did not now on which URL
the front-end is mounted, so it couldn't generate proper links. On
`hubs-dev`, the links were of the form `http://0.0.0.0:5000/hubname/`.

This commit has the front-end generate the links instead of the
backend, so the request context is known.

---

diff --git a/hubs/feed.py b/hubs/feed.py
index 5fb9546..1cbe510 100644
--- a/hubs/feed.py
+++ b/hubs/feed.py
@@ -60,22 +60,44 @@ def on_new_message(msg):
         feed.add(msg)
 
 
-def format_msg(msg):
+def add_dom_id(msg):
+    """Compute a deterministic dom_id.
+
+    Since this is the identifier stored when the message is saved by the user
+    in the SQL DB, it has to be invariant through conglomerate() calls.
+    """
     if "msg_ids" not in msg:
         msg = fedmsg.meta.conglomerate([msg])[0]
-    # Compute a deterministic dom_id.  Since this is the identifier stored
-    # when the message is saved by the user in the SQL DB, it has to be
-    # invariant through conglomerate() calls.
     msg["dom_id"] = hashlib.sha1(
         b":".join(
             [mid.encode("utf-8") for mid in sorted(msg["msg_ids"])]
         )).hexdigest()
-    # TODO: generate markup
-    msg["markup"] = _make_hub_links(msg, "subtitle")
-    msg["markup_subjective"] = _make_hub_links(msg, "subjective")
     return msg
 
 
+def format_msgs(msgs):
+    """Add keys with message text formatted in HTML to a list of messages.
+
+    This method must not be called by the backed, or the links generated by
+    ``url_for()`` will be wrong (no proper request context).
+
+    Arguments:
+        msgs (list): a list of messages to format in HTML
+
+    Returns:
+        list: the list of messages with additional ``markup*`` keys.
+    """
+    if not msgs:
+        return []
+    # TODO: generate more markup
+    existing_usernames = [r[0] for r in User.query.values(User.username)]
+    for msg in msgs:
+        msg["markup"] = _make_hub_links(msg, "subtitle", existing_usernames)
+        msg["markup_subjective"] = _make_hub_links(
+            msg, "subjective", existing_usernames)
+    return msgs
+
+
 _word_split_re = re.compile(r'(\s+)')
 _punctuation_re = re.compile(
     '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
@@ -85,11 +107,13 @@ _punctuation_re = re.compile(
 )
 
 
-def _make_hub_links(msg, attr):
+def _make_hub_links(msg, attr, existing_usernames):
     if not msg.get(attr):
         return ""
-    existing_usernames = [r[0] for r in User.query.values(User.username)]
-    usernames = [u for u in msg["usernames"] if u in existing_usernames]
+    usernames = [u for u in msg.get("usernames", [])
+                 if u in existing_usernames]
+    if not usernames:
+        return msg[attr]
     words = _word_split_re.split(msg[attr])
     for i, word in enumerate(words):
         match = _punctuation_re.match(word)
@@ -148,9 +172,13 @@ class Feed(object):
         if self.db is None:
             self.connect()
         log.debug("Adding message %s to %s", msg["msg_id"], self.key)
-        self.db.lpush(self.key, dumps(self._format_msg(msg)))
+        self.db.lpush(self.key, dumps(self._preprocess_msg(msg)))
         self.db.ltrim(self.key, 0, self.max_items)
 
+    def _preprocess_msg(self, msg):
+        # Default implementation: no-op.
+        return msg
+
     def length(self):
         if self.db is None:
             self.connect()
@@ -183,18 +211,16 @@ class Notifications(Feed):
 
     msgtype = "notif"
 
-    def _format_msg(self, msg):
-        return format_msg(msg)
+    def _preprocess_msg(self, msg):
+        return add_dom_id(msg)
 
 
 class Activity(Feed):
 
     msgtype = "activity"
 
-    def _format_msg(self, msg):
-        # No-op, we want raw messages in the DB to conglomerate and format them
-        # later.
-        return msg
+    # We leave a no-op implementation of_preprocess_msg because we want
+    # raw messages in the DB to conglomerate and format them later.
 
 
 def _load_json(username):
diff --git a/hubs/tests/test_feed.py b/hubs/tests/test_feed.py
index 042ff55..4df4ca4 100644
--- a/hubs/tests/test_feed.py
+++ b/hubs/tests/test_feed.py
@@ -7,7 +7,7 @@ from mock import Mock, patch
 from hubs.app import app
 from hubs.models import User, Hub, Association
 from hubs.feed import (
-    Notifications, Activity, format_msg, get_hubs_for_msg,
+    Notifications, Activity, add_dom_id, format_msgs, get_hubs_for_msg,
     on_new_message, on_new_notification)
 from hubs.tests import APPTest
 
@@ -118,7 +118,7 @@ class FeedTest(APPTest):
             ["infra", "ralph", "testhub"]
             )
 
-    def test_format_msg(self):
+    def test_add_dom_id(self):
         msg = {
             "msg_ids": {
                 "testid1": {"msg_id": "testid1"},
@@ -130,10 +130,19 @@ class FeedTest(APPTest):
             "subjective": "your ticket was commented by decause",
         }
         with app.test_request_context():
-            result = format_msg(msg)
+            result = add_dom_id(msg)
         self.assertEqual(
             result["dom_id"],
             "067306d0b091ec48d9e2dded1ca9b1f8b1b2ac93")
+
+    def test_format_msgs(self):
+        msg = {
+            "usernames": ["ralph", "decause"],
+            "subtitle": "ralph's ticket was commented by decause",
+            "subjective": "your ticket was commented by decause",
+        }
+        with app.test_request_context():
+            result = format_msgs([msg])[0]
         self.assertEqual(
             result["markup"],
             """<a href="/ralph/">ralph</a>'s ticket was commented by """
diff --git a/hubs/tests/views/test_user.py b/hubs/tests/views/test_user.py
index f15192c..127fd36 100644
--- a/hubs/tests/views/test_user.py
+++ b/hubs/tests/views/test_user.py
@@ -18,7 +18,7 @@ class TestStreamExisting(hubs.tests.APPTest):
         feed = Mock()
         Notifications.return_value = feed
         feed.get.return_value = [{
-            "markup": "foo", "link": "bar",
+            "subtitle": "foo", "link": "bar",
         }]
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.get('/stream/existing')
@@ -27,6 +27,7 @@ class TestStreamExisting(hubs.tests.APPTest):
         data = json.loads(resp.get_data(as_text=True))
         self.assertEqual(data["status"], "OK")
         self.assertEqual(len(data["data"]), 1)
+        self.assertEqual(data["data"][0]['subtitle'], 'foo')
         self.assertEqual(data["data"][0]['markup'], 'foo')
         self.assertEqual(data["data"][0]['link'], 'bar')
 
diff --git a/hubs/views/user.py b/hubs/views/user.py
index e33c638..c0e2b99 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -26,7 +26,7 @@ def stream():
 def stream_existing():
     username = flask.g.user.username
     feed = hubs.feed.Notifications(username)
-    existing = feed.get()  # TODO: paging?
+    existing = hubs.feed.format_msgs(feed.get())  # TODO: paging?
     # Right now, stream and actions are the same.
     # Once mentions is implemented, then each will be its own.
     return flask.jsonify(dict(
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index 9a58891..f37ec2e 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals, absolute_import
 
 import logging
 
+from hubs.feed import format_msgs
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
 from hubs.widgets.view import WidgetView, RootWidgetView
@@ -46,7 +47,7 @@ class ExistingView(WidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         get_data = GetData(instance)
-        existing = get_data()
+        existing = format_msgs(get_data())
         return {
             "status": "OK",
             "data": existing,
diff --git a/hubs/widgets/feed/functions.py b/hubs/widgets/feed/functions.py
index da6d8df..b323ca8 100644
--- a/hubs/widgets/feed/functions.py
+++ b/hubs/widgets/feed/functions.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals, absolute_import
 
 import fedmsg.meta
 
-from hubs.feed import Activity, format_msg
+from hubs.feed import Activity, add_dom_id
 from hubs.widgets.caching import CachedFunction
 
 
@@ -15,9 +15,8 @@ class GetData(CachedFunction):
         feed = Activity(hub_name)
         raw_msgs = feed.get()  # TODO: paging?
         msgs = fedmsg.meta.conglomerate(raw_msgs)
-        msgs = [format_msg(msg) for msg in msgs]
         limit = self.instance.config["message_limit"]
-        return msgs[:limit]
+        return [add_dom_id(msg) for msg in msgs[:limit]]
 
     def should_invalidate(self, message):
         if "_hubs" not in message:

From 265b192e024205b02ea1abb05515f327b4e0763f Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 11:40:07 +0000
Subject: [PATCH 938/1001] Protect get_user_packages against unknown users


---

diff --git a/hubs/tests/utils/test_packages.py b/hubs/tests/utils/test_packages.py
index bb50742..10d003a 100644
--- a/hubs/tests/utils/test_packages.py
+++ b/hubs/tests/utils/test_packages.py
@@ -65,11 +65,20 @@ class PackageUtilsTest(APPTest):
         self.assertEqual(requests.get.call_count, 1)
 
     @patch("hubs.utils.packages.requests")
-    def test_get_user_packages_malformed(self, requests):
+    def test_get_user_packages_no_user(self, requests):
         response = Mock()
         response.json.return_value = {
-            "error": "something bad happened"
+            "error": "No such user found",
+            "error_code": "ENOUSER"
         }
         requests.get.return_value = response
         pkgs = get_user_packages("abompard", use_cache=False)
         self.assertListEqual(pkgs, [])
+
+    @patch("hubs.utils.packages.requests")
+    def test_get_user_packages_malformed(self, requests):
+        response = Mock()
+        response.json.return_value = {}
+        requests.get.return_value = response
+        pkgs = get_user_packages("abompard", use_cache=False)
+        self.assertListEqual(pkgs, [])
diff --git a/hubs/utils/packages.py b/hubs/utils/packages.py
index e2276e6..cedc89c 100644
--- a/hubs/utils/packages.py
+++ b/hubs/utils/packages.py
@@ -40,6 +40,9 @@ def get_user_packages(username, only_owned=False, use_cache=True):
                 "Invalid JSON response getting the list of packages "
                 "owned by %s: %s", username, response.text)
             return []
+        if "error_code" in data and data["error_code"] == "ENOUSER":
+            # No user found, no packages.
+            return []
         try:
             repos = data["repos"]
         except KeyError:

From cdcd419d0331a08c6516da1d05c3497f35193f1c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 13:08:28 +0000
Subject: [PATCH 939/1001] Log to level INFO by default


---

diff --git a/ansible/roles/hubs/files/logging.ini b/ansible/roles/hubs/files/logging.ini
index 3512fa6..5aa083a 100644
--- a/ansible/roles/hubs/files/logging.ini
+++ b/ansible/roles/hubs/files/logging.ini
@@ -1,4 +1,3 @@
-# From https://docs.python.org/2/howto/logging.html
 [loggers]
 keys=root
 
@@ -6,18 +5,22 @@ keys=root
 keys=console
 
 [formatters]
-keys=simple
+keys=simple,minimal
 
 [logger_root]
-level=DEBUG
+level=INFO
 handlers=console
 
 [handler_console]
 class=StreamHandler
 level=DEBUG
-formatter=simple
+formatter=minimal
 args=(sys.stdout,)
 
 [formatter_simple]
 format=[%(asctime)s][%(process)d][%(levelname)s] (%(name)s) %(message)s
 datefmt=%H:%M:%S
+
+[formatter_minimal]
+format=[%(levelname)s] (%(name)s) %(message)s
+datefmt=%H:%M:%S

From 86edd6d423f501e68b5bb2ca569130da31ce808c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 25 2017 14:37:19 +0000
Subject: [PATCH 940/1001] Adapt to fedora-bootstrap 1.0.3


Commit 51bfc72 had imported an older version from the patternlab CSS.

---

diff --git a/hubs/static/client/app/widgets/halp/Config.jsx b/hubs/static/client/app/widgets/halp/Config.jsx
index 4a65107..61a3e50 100644
--- a/hubs/static/client/app/widgets/halp/Config.jsx
+++ b/hubs/static/client/app/widgets/halp/Config.jsx
@@ -190,7 +190,7 @@ export default class Config extends React.Component {
                 </div>
               </div>
               <div className="modal-footer">
-                <button type="button" className="btn btn-default" data-dismiss="modal">
+                <button type="button" className="btn btn-secondary" data-dismiss="modal">
                   {this.props.mode === "add" ?
                     <FormattedMessage {...messages.cancel} />
                   :
diff --git a/hubs/static/css/style-patternlab.css b/hubs/static/css/style-patternlab.css
index 9be59f4..196c6f8 100644
--- a/hubs/static/css/style-patternlab.css
+++ b/hubs/static/css/style-patternlab.css
@@ -141,7 +141,6 @@ So feel free to use any of these approaches. Or don't. It's totally up to you.
 /*------------------------------------*\
     #TYPOGRAPHY
 \*------------------------------------*/
-@import url("https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css");
 @font-face {
   font-family: "Open Sans";
   src: url("../../fonts/OpenSans-ExtraBold.ttf") format("opentype");
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 46faaea..f55fdce 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -585,12 +585,6 @@ font-size: 32pt;
  * Issue Widgets
  */
  
-.widget .widget-pagure_pr h5,
-.widget .widget-githubissues h5,
-.widget .widget-bugzilla h5 {
-  font-weight: bold;
-}
-
 .widget .widget-pagure_pr li,
 .widget .widget-githubissues li,
 .widget .widget-bugzilla li {
diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
index a194aa3..878c2fd 100644
--- a/hubs/templates/add_widget.html
+++ b/hubs/templates/add_widget.html
@@ -18,7 +18,7 @@
         </select>
       </div>
       <div class="modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">
+        <button type="button" class="btn btn-secondary" data-dismiss="modal">
           Close
         </button>
         <button type="submit" class="btn btn-primary" id="submit_btn">
diff --git a/hubs/templates/widget_add.html b/hubs/templates/widget_add.html
index 3e0d4d6..d3cf376 100644
--- a/hubs/templates/widget_add.html
+++ b/hubs/templates/widget_add.html
@@ -37,7 +37,7 @@
       {% endif %}
       </div> <!-- /modal-body -->
       <div class="modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">
+        <button type="button" class="btn btn-secondary" data-dismiss="modal">
           Cancel
         </button>
         <button type="submit" class="btn btn-primary">
diff --git a/hubs/templates/widget_edit.html b/hubs/templates/widget_edit.html
index 6118e57..fc4f8ce 100644
--- a/hubs/templates/widget_edit.html
+++ b/hubs/templates/widget_edit.html
@@ -40,7 +40,7 @@
       {% endif %}
       </div> <!-- /modal-body -->
       <div class="modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">
+        <button type="button" class="btn btn-secondary" data-dismiss="modal">
           Close
         </button>
         <button type="submit" class="btn btn-primary">
diff --git a/hubs/widgets/bugzilla/templates/root.html b/hubs/widgets/bugzilla/templates/root.html
index e539ece..2ee01e7 100644
--- a/hubs/widgets/bugzilla/templates/root.html
+++ b/hubs/widgets/bugzilla/templates/root.html
@@ -1,16 +1,16 @@
 {% extends "panel.html" %}
 
 {% block content %}
-<ul class="media-list">
+<ul class="list-unstyled mb-0">
   {% for item in issues %}
-    <li class="media">
-      <div class="media-left">
+    <li class="media py-2">
+      <div class="align-self-center mr-3">
         <a href="https://bugzilla.redhat.com/show_bug.cgi?id={{ item['id'] }}" target="_blank">
-        <span class="label label-default">#{{ item['id'] }}</span>
+        <span class="badge badge-primary">#{{ item['id'] }}</span>
         </a>
       </div>
       <div class="media-body">
-        <h5 class="media-heading">
+        <h5 class="mt-0">
           <a href="https://apps.fedoraproject.org/packages/{{ item['pkg_name'] }}" target="_blank">{{ item['pkg_name'] }}</a>:
           {{ item['title'] }}
         </h5>
diff --git a/hubs/widgets/github_pr/templates/root.html b/hubs/widgets/github_pr/templates/root.html
index 379771a..ff31d64 100644
--- a/hubs/widgets/github_pr/templates/root.html
+++ b/hubs/widgets/github_pr/templates/root.html
@@ -6,23 +6,23 @@
   Organization Github Page
 </a>
 <hr/>
-<ul class="media-list">
+<ul class="list-unstyled">
 {% for pr in pulls[:display_number] %}
   <li class="media">
-    <div class="media-left">
+    <div class="align-self-center mr-3">
       <a  href="{{ pr['url'] }}" 
           target="_blank">
-      <span class="label label-default">#{{ pr['number'] }}</span>
+      <span class="badge badge-primary">#{{ pr['number'] }}</span>
       </a>
     </div>
     <div class="media-body">
-      <h4 class="media-heading">
+      <h5 class="mt-0">
         {{ organization }} -
         <span title="{{ pr['title'] }}">
           {{ pr['title'] }} {% if
             pr['title'] | length > 45 %} ... {% endif %}
         </span>
-      </h4>
+      </h5>
       Opened by:
         <a href="https://github.com/{{ pr['user'] }}" 
             target="_blank">
diff --git a/hubs/widgets/githubissues/templates/root.html b/hubs/widgets/githubissues/templates/root.html
index 33cde81..8f0cb1d 100644
--- a/hubs/widgets/githubissues/templates/root.html
+++ b/hubs/widgets/githubissues/templates/root.html
@@ -2,17 +2,17 @@
 
 {% block content %}
 
-<ul class="media-list">
+<ul class="list-unstyled">
     
 {% for i in range(display_number) %}
 <li class="media">
-  <div class="media-left">
+  <div class="align-self-center mr-3">
     <a href="#" target="_blank">
-      <span class="label label-default">#{{ all_issues[i]['num'] }}</span>
+      <span class="badge badge-primary">#{{ all_issues[i]['num'] }}</span>
     </a>
   </div>
   <div class="media-body">
-    <h5 class="media-heading">
+    <h5 class="mt-0">
         {{ all_issues[i]['title'] }}
     </h5>
     <div class="row no-gutters">
diff --git a/hubs/widgets/pagure_pr/templates/root.html b/hubs/widgets/pagure_pr/templates/root.html
index e41a43a..2207ce3 100644
--- a/hubs/widgets/pagure_pr/templates/root.html
+++ b/hubs/widgets/pagure_pr/templates/root.html
@@ -1,23 +1,24 @@
 {% extends "panel.html" %}
 
 {% block content %}
-<ul class="media-list">
+<ul class="list-unstyled">
   {% for pr in all_pr[:10] %}
-    <li class="media">
-      <div class="media-left">
+    <li class="media py-2">
+      <div class="align-self-center mr-3">
         <a  href="https://pagure.io/{{ repo }}/pull-request/{{ pr['pr_id'] }}"
             target="_blank">
-        <span class="label label-default">#{{ pr['pr_id'] }}</span>
+        <span class="badge badge-primary">#{{ pr['pr_id'] }}</span>
         </a>
       </div>
       <div class="media-body">
-        <h5 class="media-heading">
+        <h5 class="mt-0">
           {{ pr['pr_project_name'] }} -
           <span title="{{ pr['pr_title_full'] }}">
             {{ pr['pr_title'] }} {% if
               pr['pr_title_full'] | length > 45 %} ... {% endif %}
           </span>
         </h5>
+	<small>
         Opened by:
           <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
               target="_blank">
@@ -33,6 +34,7 @@
         {% else %}
           <span class="text-muted">Unassigned</span>
         {% endif %}
+	</small>
       </div>
     </li>
   {% endfor %}
diff --git a/hubs/widgets/pagureissues/templates/root.html b/hubs/widgets/pagureissues/templates/root.html
index 989ccd4..5e4fbd5 100644
--- a/hubs/widgets/pagureissues/templates/root.html
+++ b/hubs/widgets/pagureissues/templates/root.html
@@ -7,23 +7,24 @@
 </a>
 <hr/>
 
-<ul class="media-list">
+<ul class="list-unstyled">
   {% for issue in all_issues[:10] %}
-    <li class="media">
-      <div class="media-left">
+    <li class="media py-2">
+      <div class="align-self-center mr-3">
         <a  href="https://pagure.io/{{ repo }}/issue/{{ issue['issue_id'] }}"
             target="_blank">
           {{ issue['issue_project_name'] }}
-        <span class="label label-default">#{{ issue['issue_id'] }}</span>
+        <span class="badge badge-primary">#{{ issue['issue_id'] }}</span>
         </a>
       </div>
       <div class="media-body">
-        <h4 class="media-heading">
+        <h5 class="mt-0">
           <span title="{{ issue['issue_title_full'] }}">
             {{ issue['issue_title'] }} {% if
               issue['issue_title_full'] | length > 45 %} ... {% endif %}
           </span>
-        </h4>
+        </h5>
+	<small>
         Opened by:
           <a href="https://pagure.io/user/{{ issue['issue_openedby'] }}"
               target="_blank">
@@ -39,6 +40,7 @@
         {% else %}
           <span class="text-muted">Unassigned</span>
         {% endif %}
+	</small>
       </div>
     </li>
   {% endfor %}
diff --git a/hubs/widgets/workflow/templates/updates2stable.html b/hubs/widgets/workflow/templates/updates2stable.html
index f32efca..e44e040 100644
--- a/hubs/widgets/workflow/templates/updates2stable.html
+++ b/hubs/widgets/workflow/templates/updates2stable.html
@@ -6,16 +6,18 @@
 <a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
 <hr/>
 {% endif %}
-<ul class="media-list">
+<ul class="list-unstyled mb-0">
 {% for update in updates %}
     <li class="media">
-        <div class="media-left">
+        <div class="align-self-center mr-3">
             <a href="{{update['link']}}" target="_blank">
                 <img class="media-object square-32" src="{{update['icon']}}"/>
             </a>
         </div>
         <div class="media-body">
-            <h4 class="media-heading">{{update['title']}} (karma {{update['karma']}})</h4>
+            <h5 class="mt-0">
+                {{update['title']}} (karma {{update['karma']}})
+            </h5>
             can be pushed to stable
         </div>
     </li>

From 13e8bc15184d54a93033166d16c825168d24f454 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 30 2017 14:40:53 +0000
Subject: [PATCH 941/1001] Fix memory leak in the Fedmsg consumer


---

diff --git a/hubs/backend/consumer.py b/hubs/backend/consumer.py
index 7ea5083..fa84545 100644
--- a/hubs/backend/consumer.py
+++ b/hubs/backend/consumer.py
@@ -15,21 +15,24 @@ log = logging.getLogger("hubs")
 class CacheInvalidatorExtraordinaire(fedmsg.consumers.FedmsgConsumer):
     topic = '*'
     config_key = 'hubs.consumer.enabled'
+    validate_signatures = False
 
     def __init__(self, *args, **kwargs):
         log.debug("CacheInvalidatorExtraordinaire initializing")
         super(CacheInvalidatorExtraordinaire, self).__init__(*args, **kwargs)
 
-        self.queue_name = self.hub.config['hubs.redis.triage-queue-name']
+        queue_name = self.hub.config['hubs.redis.triage-queue-name']
+        self.queue = retask.queue.Queue(queue_name)
 
         log.debug("CacheInvalidatorExtraordinaire initialized")
 
     def consume(self, raw_msg):
         msg = raw_msg['body']
-        queue = retask.queue.Queue(self.queue_name)
-        queue.connect()
         task = retask.task.Task(fedmsg.encoding.dumps(msg))
-        queue.enqueue(task)
+        if not self.queue.connected:
+            log.debug("CacheInvalidatorExtraordinaire connecting")
+            self.queue.connect()
+        self.queue.enqueue(task)
 
     def stop(self):
         log.info("Cleaning up CacheInvalidatorExtraordinaire.")

From d8ed17d821fcd9fe8e1373fd1a7e9f8da88030de Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 31 2017 14:29:42 +0000
Subject: [PATCH 942/1001] Fix logout and abusive reuse of auth info


---

diff --git a/hubs/app.py b/hubs/app.py
index c24a9e0..8974ae4 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -67,7 +67,12 @@ def check_auth():
     flask.g.fedmsg_config = fedmsg_config
 
     if OIDC.user_loggedin:
-        if "auth" not in flask.session or not flask.session["auth"]:
+        # The "sub" value is unique per user, and does not make an HTTP API
+        # request.
+        user_sub = OIDC.user_getfield("sub")
+        if ("auth" not in flask.session
+            or not flask.session["auth"]
+            or flask.session["auth"]["sub"] != user_sub):
             user_info = OIDC.user_getinfo([
                 "name", "nickname", "sub", "email", "zoneinfo", "cla",
                 "groups",
@@ -80,6 +85,7 @@ def check_auth():
                 cla_done=('http://admin.fedoraproject.org/accounts/cla/done'
                           in user_info['cla']),
                 groups=user_info['groups'],
+                sub=user_info['sub'],
                 logged_in=True,
             )
             flask.session["auth"]["avatar"] = username2avatar(
@@ -95,6 +101,7 @@ def check_auth():
     else:
         flask.g.auth = munch.Munch(logged_in=False)
         flask.g.user = None
+        OIDC.logout()
 
 
 # Register widgets
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index f269e51..8b3706c 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -52,7 +52,7 @@
           <a href="#" class="dropdown-item">Full Name: {{ g.auth.fullname }}</a>
           <a href="#" class="dropdown-item">Email: {{ g.auth.email }}</a>
           <div class="dropdown-divider"></div>
-          <a href="#" class="dropdown-item">Separated link</a>
+          <a href="{{ url_for('logout', next=request.url) }}" class="dropdown-item">Logout</a>
         </div>
       </li>
     </ul>
diff --git a/hubs/views/root.py b/hubs/views/root.py
index be77ce6..132647d 100644
--- a/hubs/views/root.py
+++ b/hubs/views/root.py
@@ -66,7 +66,7 @@ def logout():
 
     if authenticated():
         OIDC.logout()
-        flask.session.auth = None
+        flask.session.clear()
         flask.flash('You have been logged out')
 
     return flask.redirect(next_url)

From e8708d3402b5ceb4e2133e126b2df1c32c1f3d6a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Aug 31 2017 14:30:25 +0000
Subject: [PATCH 943/1001] Override a PatternLab style


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index f55fdce..8dd75cd 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -632,6 +632,11 @@ header h5.m-b-1 {
 }
 
 
+/** Patternlab styles make the login/logout alert boxes bigger than necessary **/
+.alert {
+  overflow: visible;
+}
+
 
 .row.no-gutters {
   margin-left: 0;

From ca3904870354c04a4e758b63837a64ff2f28d71b Mon Sep 17 00:00:00 2001
From: Sayan Chowdhury <sayan.chowdhury2012@gmail.com>
Date: Sep 12 2017 11:51:48 +0000
Subject: [PATCH 944/1001] readme: Update the README to have the steps to run the meeting


Signed-off-by: Sayan Chowdhury <sayan.chowdhury2012@gmail.com>

---

diff --git a/README.rst b/README.rst
index 3e063f1..0e10fd1 100644
--- a/README.rst
+++ b/README.rst
@@ -1,24 +1,47 @@
+===========
 Fedora Hubs
 ===========
+
 Fedora Hubs will provide a communication and collaboration center for Fedora
 contributors of all types. The idea is that contributors will be able to visit
 Hubs to check on their involvements across Fedora, discover new places that they
 can contribute, and more.
 
 Hubs is currently under development. (We had a development instance at 
-https://hubs-dev.fedorainfracloud.org/ but that isn't currently maintained.)
+https://hubs-dev.fedorainfracloud.org/)
 
 Get Involved
-------------
+============
 
 Visit our `mailing list <https://lists.fedoraproject.org/archives/list/hubs-devel@lists.fedoraproject.org>`_
-and join us in the ``#fedora-hubs`` IRC channel on irc.freenode.net. Meetings are held
-weekly in ``#fedora-hubs`` at 14:00UTC and the minutes for every meeting are
-`archived <https://meetbot.fedoraproject.org/sresults/?group_id=fedora-hubs&type=team>`_.
-In the meetings we review our statuses from the preceding week and do ticket triage, too.
+and join us in the ``#fedora-hubs`` IRC channel on irc.freenode.net.
 
 For a more detailed overview of what Fedora Hubs is, see the
 `documentation <https://docs.pagure.org/fedora-hubs/overview.html>`_.
 
 To set up a development environment and start contributing, check out
 the `development guide <https://docs.pagure.org/fedora-hubs/dev-guide.html>`_.
+
+
+Meetings
+========
+
+Meetings are held weekly in ``#fedora-hubs`` at 14:00UTC and the minutes for
+every meeting are `archived <https://meetbot.fedoraproject.org/sresults/?group_id=hubs-devel&type=team>`_.
+In the meetings we review our statuses from the preceding week and do ticket triage, too.
+
+----------------------
+Steps to run a meeting
+----------------------
+
+- #startmeeting hubs-devel
+- #topic Roll Call (Wait for 2 minutes for the Roll Call)
+- #chair [nick 1, nick 2,...., nick N](All the people present for the meeting)
+- #topic Action items from last meeting (Find the last meeting log from https://meetbot-raw.fedoraproject.org/teams/hubs-devel)
+- #topic Status Updates (Cycle through all the nicks)
+- #topic Ticket <subject link_to_the_ticket>
+- #topic Open Floor
+- #endmeeting
+
+Send the minutes of the meeting to hubs-devel@lists.fedoraproject.org
+

From 0c26d2d228b3fc2a4f024af01863d820cd0bb869 Mon Sep 17 00:00:00 2001
From: Sayan Chowdhury <sayan.chowdhury2012@gmail.com>
Date: Sep 20 2017 09:24:11 +0000
Subject: [PATCH 945/1001] Move around the dependencies to the devDependencies


Signed-off-by: Sayan Chowdhury <sayan.chowdhury2012@gmail.com>

---

diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 420bd05..504071d 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -7,10 +7,6 @@
     "doc": "docs"
   },
   "dependencies": {
-    "babel-loader": "~6.2.4",
-    "babel-plugin-transform-class-properties": "^6.10.2",
-    "babel-preset-es2015": "~6.9.0",
-    "babel-preset-react": "~6.5.0",
     "prop-types": "^15.5.8",
     "react": "^15.4.0",
     "react-autosuggest": "~6.1.0",
@@ -18,10 +14,13 @@
     "react-intl": "~2.1.5",
     "react-linkify": "^0.1.3",
     "react-timeago": "^3.1.1",
-    "reconnecting-eventsource": "^1.0.1",
-    "webpack": "~1.13.1"
+    "reconnecting-eventsource": "^1.0.1"
   },
   "devDependencies": {
+    "babel-loader": "~6.2.4",
+    "babel-plugin-transform-class-properties": "^6.10.2",
+    "babel-preset-es2015": "~6.9.0",
+    "babel-preset-react": "~6.5.0",
     "babel-jest": "^14.1.0",
     "babel-preset-es2015": "^6.9.0",
     "babel-preset-jest": "^14.1.0",
@@ -30,7 +29,8 @@
     "eslint": "^2.13.1",
     "jest": "^14.1.0",
     "react-addons-test-utils": "^15.4.0",
-    "react-test-renderer": "^15.4.0"
+    "react-test-renderer": "^15.4.0",
+    "webpack": "~1.13.1"
   },
   "scripts": {
     "dev": "webpack --watch",

From 52d7cb61cd14b1d4ea9fe84a93127c1156243cd6 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:30:56 +0000
Subject: [PATCH 946/1001] Add tests for d8ed17d


---

diff --git a/hubs/tests/test_authn.py b/hubs/tests/test_authn.py
new file mode 100644
index 0000000..350edf3
--- /dev/null
+++ b/hubs/tests/test_authn.py
@@ -0,0 +1,52 @@
+from __future__ import absolute_import, unicode_literals
+
+import flask
+
+import hubs.app
+from hubs.tests import APPTest, FakeAuthorization
+
+
+class AuthnTestCase(APPTest):
+
+    def setUp(self):
+        super(AuthnTestCase, self).setUp()
+        self.app_context = hubs.app.app.app_context()
+        self.app_context.__enter__()
+        self.req_context = hubs.app.app.test_request_context()
+        self.req_context.__enter__()
+        flask.g.db = self.session
+
+    def tearDown(self):
+        self.req_context.__exit__(None, None, None)
+        self.app_context.__exit__(None, None, None)
+        super(AuthnTestCase, self).tearDown()
+
+    def test_expired_auth(self):
+        # Previous user is still in the session
+ 
+        flask.session["auth"] = dict(
+            nickname="olduser",
+            name="olduser",
+            fullname="olduser",
+            email="olduser@example.com",
+            zoneinfo="UTC",
+            sub="olduser",
+            cla="",
+            groups=[],
+            logged_in=True,
+            )
+        # Now the new user logs in
+        flask.g.oidc_id_token = dict(
+            nickname="newuser",
+            name="newuser",
+            fullname="newuser",
+            email="newuser@example.com",
+            zoneinfo="UTC",
+            sub="newuser",
+            cla="",
+            groups=[],
+            )
+        # And the hook is called
+        hubs.app.check_auth()
+        self.assertEqual(flask.g.auth.nickname, "newuser")
+        self.assertEqual(flask.session["auth"]["nickname"], "newuser")

From fdabc6a32b6c0295d174e2477876c947e0ce02b9 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:33:46 +0000
Subject: [PATCH 947/1001] Migrate to webpack 2+


---

diff --git a/hubs/static/client/.babelrc b/hubs/static/client/.babelrc
index aef231b..25043d0 100644
--- a/hubs/static/client/.babelrc
+++ b/hubs/static/client/.babelrc
@@ -1,5 +1,5 @@
 {
-  "presets" : ["es2015", "react", "stage-1"],
-  "plugins": ["transform-class-properties"]
+  "presets" : ["es2015", "react"],
+  "plugins": ["syntax-dynamic-import"]
 }
 
diff --git a/hubs/static/client/.eslintrc.json b/hubs/static/client/.eslintrc.json
index 434bab5..86fbafe 100644
--- a/hubs/static/client/.eslintrc.json
+++ b/hubs/static/client/.eslintrc.json
@@ -1,4 +1,8 @@
 {
+  "parser": "babel-eslint",
+  "plugins": [
+    "react"
+  ],
   "rules": {
     "arrow-body-style": "off",
     "func-names": "off",
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 504071d..553d1c1 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -1,36 +1,39 @@
 {
   "name": "fedora-hubs",
-  "version": "0.0.0",
+  "version": "0.1.0",
   "description": "Fedora Hubs will provide a communication and collaboration center for Fedora contributors of all types. The idea is that contributors will be able to visit Hubs to check on their involvements across Fedora, discover new places that they can contribute, and more.",
   "main": "webpack.config.js",
   "directories": {
     "doc": "docs"
   },
   "dependencies": {
-    "prop-types": "^15.5.8",
-    "react": "^15.4.0",
-    "react-autosuggest": "~6.1.0",
-    "react-dom": "^15.4.0",
-    "react-intl": "~2.1.5",
-    "react-linkify": "^0.1.3",
-    "react-timeago": "^3.1.1",
+    "prop-types": "^15.5.10",
+    "react": "^15.6.1",
+    "react-autosuggest": "^9.3.2",
+    "react-dom": "^15.6.1",
+    "react-intl": "^2.3.0",
+    "react-linkify": "^0.2.1",
+    "react-loadable": "^4.0.4",
+    "react-timeago": "^3.4.3",
     "reconnecting-eventsource": "^1.0.1"
   },
   "devDependencies": {
-    "babel-loader": "~6.2.4",
-    "babel-plugin-transform-class-properties": "^6.10.2",
-    "babel-preset-es2015": "~6.9.0",
-    "babel-preset-react": "~6.5.0",
-    "babel-jest": "^14.1.0",
-    "babel-preset-es2015": "^6.9.0",
-    "babel-preset-jest": "^14.1.0",
-    "babel-preset-react": "^6.5.0",
-    "babel-preset-stage-1": "^6.5.0",
-    "eslint": "^2.13.1",
-    "jest": "^14.1.0",
-    "react-addons-test-utils": "^15.4.0",
-    "react-test-renderer": "^15.4.0",
-    "webpack": "~1.13.1"
+    "babel-core": "^6.26.0",
+    "babel-eslint": "^7.2.3",
+    "babel-jest": "^20.0.3",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-syntax-dynamic-import": "^6.18.0",
+    "babel-preset-es2015": "^6.24.1",
+    "babel-preset-react": "^6.24.1",
+    "css-loader": "^0.28.4",
+    "eslint": "^4.4.1",
+    "eslint-loader": "^1.9.0",
+    "eslint-plugin-react": "^7.2.1",
+    "file-loader": "^0.11.2",
+    "jest": "^20.0.4",
+    "react-test-renderer": "^15.6.1",
+    "style-loader": "^0.18.2",
+    "webpack": "^3.5.5"
   },
   "scripts": {
     "dev": "webpack --watch",
diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
index 532e978..efbe75b 100644
--- a/hubs/static/client/webpack.config.js
+++ b/hubs/static/client/webpack.config.js
@@ -23,14 +23,41 @@ const config = {
         'react-dom': 'ReactDOM',
     },
     module : {
-        loaders : [{
+        rules: [
+        {
+            test: /\.jsx?$/,
+            enforce: 'pre',
+            loader: 'eslint-loader',
+            options: {
+                emitWarning: true,
+            },
+            include : PATHS.app
+        },
+        {
             test : /\.jsx?$/,
-            loader : 'babel',
-            exclude: /(node_modules|bowercomponents)/,
+            loader : 'babel-loader',
+            options: {
+                cacheDirectory: true,
+            },
+            exclude: /node_modules/,
             include : PATHS.app
-        }]
+        },
+        {
+            test: /\.css$/,
+            use: [
+                'style-loader',
+                'css-loader'
+            ]
+        },
+        {
+            test: /\.(png|svg|jpg|gif)$/,
+            use: [ 'file-loader' ]
+        }
+        ]
     },
-    plugins: [ new webpack.optimize.CommonsChunkPlugin("common.js") ]
+    plugins: [
+        new webpack.optimize.CommonsChunkPlugin("common")
+    ]
 };
 
 module.exports = config;

From a22209d3c3ecfb9df4013a1906e6fc9fcd150d1d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:33:46 +0000
Subject: [PATCH 948/1001] Reformat spaces


---

diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
index efbe75b..c308851 100644
--- a/hubs/static/client/webpack.config.js
+++ b/hubs/static/client/webpack.config.js
@@ -2,62 +2,62 @@ const webpack = require('webpack');
 const path = require('path');
 
 const PATHS = {
-    app: path.join(__dirname, 'app'),
-    build: path.join(__dirname, '..', 'js', 'build')
+  app: path.join(__dirname, 'app'),
+  build: path.join(__dirname, '..', 'js', 'build')
 };
 
 const config = {
-    entry: {
-        Hubs: path.join(PATHS.app, 'core', 'Hubs.js'),
-        Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.js'),
-        Halp: path.join(PATHS.app, 'widgets', 'halp', 'Halp.js')
+  entry: {
+    Hubs: path.join(PATHS.app, 'core', 'Hubs.js'),
+    Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.js'),
+    Halp: path.join(PATHS.app, 'widgets', 'halp', 'Halp.js')
+  },
+  output: {
+    path: PATHS.build,
+    filename: '[name].js',
+    library: '[name]',
+  },
+  externals: {
+    'jquery': 'jQuery',
+    'react': 'React',
+    'react-dom': 'ReactDOM',
+  },
+  module: {
+    rules: [
+    {
+      test: /\.jsx?$/,
+      enforce: 'pre',
+      loader: 'eslint-loader',
+      options: {
+        emitWarning: true,
+      },
+      include : PATHS.app
     },
-    output: {
-        path: PATHS.build,
-        filename: '[name].js',
-        library: '[name]',
+    {
+      test : /\.jsx?$/,
+      loader : 'babel-loader',
+      options: {
+        cacheDirectory: true,
+      },
+      exclude: /node_modules/,
+      include : PATHS.app
     },
-    externals: {
-        'jquery': 'jQuery',
-        'react': 'React',
-        'react-dom': 'ReactDOM',
+    {
+      test: /\.css$/,
+      use: [
+        'style-loader',
+        'css-loader'
+      ]
     },
-    module : {
-        rules: [
-        {
-            test: /\.jsx?$/,
-            enforce: 'pre',
-            loader: 'eslint-loader',
-            options: {
-                emitWarning: true,
-            },
-            include : PATHS.app
-        },
-        {
-            test : /\.jsx?$/,
-            loader : 'babel-loader',
-            options: {
-                cacheDirectory: true,
-            },
-            exclude: /node_modules/,
-            include : PATHS.app
-        },
-        {
-            test: /\.css$/,
-            use: [
-                'style-loader',
-                'css-loader'
-            ]
-        },
-        {
-            test: /\.(png|svg|jpg|gif)$/,
-            use: [ 'file-loader' ]
-        }
-        ]
-    },
-    plugins: [
-        new webpack.optimize.CommonsChunkPlugin("common")
+    {
+      test: /\.(png|svg|jpg|gif)$/,
+      use: [ 'file-loader' ]
+    }
     ]
+  },
+  plugins: [
+    new webpack.optimize.CommonsChunkPlugin("common")
+  ]
 };
 
 module.exports = config;

From a79f9cd88ada2554b6a8e0c8b52fd156e8d89319 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:08 +0000
Subject: [PATCH 949/1001] Make auth and user change more robust


---

diff --git a/hubs/app.py b/hubs/app.py
index 8974ae4..56173d1 100644
--- a/hubs/app.py
+++ b/hubs/app.py
@@ -71,8 +71,8 @@ def check_auth():
         # request.
         user_sub = OIDC.user_getfield("sub")
         if ("auth" not in flask.session
-            or not flask.session["auth"]
-            or flask.session["auth"]["sub"] != user_sub):
+                or not flask.session["auth"]
+                or flask.session["auth"].get("sub") != user_sub):
             user_info = OIDC.user_getinfo([
                 "name", "nickname", "sub", "email", "zoneinfo", "cla",
                 "groups",
diff --git a/hubs/tests/test_authn.py b/hubs/tests/test_authn.py
index 350edf3..1ff17c1 100644
--- a/hubs/tests/test_authn.py
+++ b/hubs/tests/test_authn.py
@@ -3,7 +3,7 @@ from __future__ import absolute_import, unicode_literals
 import flask
 
 import hubs.app
-from hubs.tests import APPTest, FakeAuthorization
+from hubs.tests import APPTest
 
 
 class AuthnTestCase(APPTest):
@@ -23,7 +23,6 @@ class AuthnTestCase(APPTest):
 
     def test_expired_auth(self):
         # Previous user is still in the session
- 
         flask.session["auth"] = dict(
             nickname="olduser",
             name="olduser",

From ddbc205ba1704675024ad2503d01f5d8c7c4205e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:08 +0000
Subject: [PATCH 950/1001] Make auth testing closer to real auth


---

diff --git a/hubs/tests/__init__.py b/hubs/tests/__init__.py
index 15051a6..fddf404 100644
--- a/hubs/tests/__init__.py
+++ b/hubs/tests/__init__.py
@@ -141,7 +141,7 @@ def auth_set(APP, auth):
             g.auth = munch.Munch(logged_in=False)
             g.user = None
         else:
-            g.user = auth.user
+            g.user = FakeUser(auth.nickname)
 
     if flask._app_ctx_stack.top is None:
         # App context isn't pushed yet
@@ -162,25 +162,19 @@ class FakeUser(object):
             supposed to be.
         """
         self.username = username
-        self.booksmarks = []
+        self.bookmarks = []
         self.groups = []
 
 
-class FakeAuthorization(object):
+def FakeAuthorization(username):
     """ Fake Authorization used to set as flask.g.auth. """
-
-    def __init__(self, username='username'):
-        """ Constructor.
-        :arg groups: list of the groups in which this fake user is
-            supposed to be.
-        """
-        self.logged_in = True
-        self.fullname = 'fullname: ' + username
-        self.email = 'email: ' + username
-        self.user = FakeUser(username)
-        self.avatar = 'avatar_src_url'
-        self.nickname = username
-        self.username = username
+    return munch.Munch(
+        logged_in=True,
+        fullname='fullname: ' + username,
+        nickname=username,
+        email='email: ' + username,
+        avatar='avatar_src_url',
+    )
 
 
 @contextmanager
diff --git a/hubs/tests/test_authz.py b/hubs/tests/test_authz.py
index 7a7c85a..f47b85f 100644
--- a/hubs/tests/test_authz.py
+++ b/hubs/tests/test_authz.py
@@ -2,7 +2,7 @@ from __future__ import absolute_import, unicode_literals
 
 from hubs.app import app
 from hubs.authz import ObjectAuthzMixin, AccessLevel, PERMISSIONS
-from hubs.tests import APPTest, FakeAuthorization
+from hubs.tests import APPTest, FakeUser
 
 
 class TestObj(ObjectAuthzMixin):
@@ -35,25 +35,25 @@ class AuthzTestCase(APPTest):
 
     def test_mixin_access_level_logged_in(self):
         obj = TestObj()
-        user = FakeAuthorization('ralph')
+        user = FakeUser('ralph')
         self.assertEqual(
             obj._get_auth_access_level(user), AccessLevel.logged_in)
 
     def test_mixin_group_access_level(self):
         obj = TestObj(roles={"auth-group": "member"})
-        user = FakeAuthorization('ralph')
+        user = FakeUser('ralph')
         self.assertEqual(
             obj._get_auth_access_level(user), AccessLevel.member)
 
     def test_mixin_group_access_level_no_role(self):
         obj = TestObj(roles={"unrelated-group": "member"})
-        user = FakeAuthorization('ralph')
+        user = FakeUser('ralph')
         self.assertEqual(
             obj._get_auth_access_level(user), AccessLevel.logged_in)
 
     def test_mixin_group_access_level_unsupported(self):
         obj = TestObj(roles={"auth-group": "dark_lord"})
-        user = FakeAuthorization('ralph')
+        user = FakeUser('ralph')
         self.assertEqual(
             obj._get_auth_access_level(user), AccessLevel.logged_in)
 
@@ -68,7 +68,7 @@ class AuthzTestCase(APPTest):
         self.assertFalse(obj.allows(None, 'widget.restricted.view'))
 
     def test_allows_logged_in(self):
-        user = FakeAuthorization('ralph')
+        user = FakeUser('ralph')
         obj = TestObj()
         self.assertTrue(obj.allows(user, 'hub.public.view'))
         self.assertTrue(obj.allows(user, 'hub.preview.view'))
@@ -79,7 +79,7 @@ class AuthzTestCase(APPTest):
         self.assertTrue(obj.allows(user, 'widget.restricted.view'))
 
     def test_allows_member(self):
-        user = FakeAuthorization('ralph')
+        user = FakeUser('ralph')
         obj = TestObj(roles={"auth-group": "member"})
         self.assertTrue(obj.allows(user, 'hub.public.view'))
         self.assertTrue(obj.allows(user, 'hub.preview.view'))
@@ -90,7 +90,7 @@ class AuthzTestCase(APPTest):
         self.assertTrue(obj.allows(user, 'widget.restricted.view'))
 
     def test_allows_sponsor(self):
-        user = FakeAuthorization('ralph')
+        user = FakeUser('ralph')
         obj = TestObj(roles={"auth-group": "sponsor"})
         self.assertTrue(obj.allows(user, 'hub.public.view'))
         self.assertTrue(obj.allows(user, 'hub.preview.view'))
@@ -101,7 +101,7 @@ class AuthzTestCase(APPTest):
         self.assertTrue(obj.allows(user, 'widget.restricted.view'))
 
     def test_allows_owner(self):
-        user = FakeAuthorization('ralph')
+        user = FakeUser('ralph')
         obj = TestObj(roles={"auth-group": "owner"})
         self.assertTrue(obj.allows(user, 'hub.public.view'))
         self.assertTrue(obj.allows(user, 'hub.preview.view'))
@@ -112,7 +112,7 @@ class AuthzTestCase(APPTest):
         self.assertTrue(obj.allows(user, 'widget.restricted.view'))
 
     def test_allows_site_admin(self):
-        user = FakeAuthorization('admin')
+        user = FakeUser('admin')
         obj = TestObj()
         for perm in PERMISSIONS.keys():
             self.assertTrue(obj.allows(user, perm))
diff --git a/hubs/tests/views/test_user.py b/hubs/tests/views/test_user.py
index 127fd36..eb1ed6a 100644
--- a/hubs/tests/views/test_user.py
+++ b/hubs/tests/views/test_user.py
@@ -50,7 +50,7 @@ class TestGetNotifications(hubs.tests.APPTest):
     def test_get_notifications_valid_name(self):
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.get('/stream/saved/'.format(
-                self.user.username))
+                self.user.nickname))
 
         self.assertEqual(resp.status_code, 200)
         data = json.loads(resp.get_data(as_text=True))
@@ -63,7 +63,7 @@ class TestGetNotifications(hubs.tests.APPTest):
 class TestPostNotifications(hubs.tests.APPTest):
     user = hubs.tests.FakeAuthorization('ralph')
     valid_payload = {
-        'username': user.username,
+        'username': user.nickname,
         'markup': 'foobar',
         'link': 'baz',
         'secondary_icon': 'http://placekitten.com/g/200/300',
@@ -71,7 +71,7 @@ class TestPostNotifications(hubs.tests.APPTest):
     }
 
     invalid_payload = {
-        'username': user.username,
+        'username': user.nickname,
     }
 
     def test_post_notification_invalid_payload(self):
@@ -99,7 +99,7 @@ class TestPostNotifications(hubs.tests.APPTest):
         self.assertEqual(notification['link'], 'baz')
 
         all_saved = hubs.models.SavedNotification.by_username(
-            self.user.username)
+            self.user.nickname)
         self.assertEqual(len(all_saved), 2)
         all_saved = [s.__json__() for s in all_saved]
         self.assertTrue(any(str(s['markup']) == self.valid_payload['markup']
@@ -140,7 +140,7 @@ class TestDeleteNotifications(hubs.tests.APPTest):
 
         with hubs.tests.auth_set(app, self.user):
             resp = self.app.delete(
-                '/stream/saved/{}/'.format(self.user.username, idx)
+                '/stream/saved/{}/'.format(self.user.nickname, idx)
             )
         self.assertEqual(resp.status_code, 404)
 

From f563d019796d8b536d1be0acfd31a47e8c6a232c Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:08 +0000
Subject: [PATCH 951/1001] Use functions for widget parameter validators


---

diff --git a/hubs/tests/test_widget_validators.py b/hubs/tests/test_widget_validators.py
index ba0c2b8..d421aa5 100644
--- a/hubs/tests/test_widget_validators.py
+++ b/hubs/tests/test_widget_validators.py
@@ -10,50 +10,50 @@ from hubs.tests import APPTest
 class ValidatorsTest(APPTest):
 
     def test_required(self):
-        self.assertRaises(ValueError, validators.Required.from_string, "")
+        self.assertRaises(ValueError, validators.Required, "")
 
     def test_text(self):
-        self.assertEqual(validators.Text.from_string("\xe9"), "\xe9")
+        self.assertEqual(validators.Text("\xe9"), "\xe9")
 
     def test_integer(self):
-        self.assertEqual(validators.Integer.from_string("1"), 1)
-        self.assertRaises(ValueError, validators.Integer.from_string, "text")
+        self.assertEqual(validators.Integer("1"), 1)
+        self.assertRaises(ValueError, validators.Integer, "text")
 
     @unittest.skip("Not implemented yet")
     def test_link(self):
         value = '<a href="somewhere">dummy</a>'
         self.assertEqual(validators.Link.from_string(value), value)
-        self.assertRaises(ValueError, validators.Link.from_string, "text")
+        self.assertRaises(ValueError, validators.Link, "text")
 
     def test_username(self):
-        self.assertEqual(validators.Username.from_string("ralph"), "ralph")
+        self.assertEqual(validators.Username("ralph"), "ralph")
         self.assertRaises(
-            ValueError, validators.Username.from_string, "nobody")
+            ValueError, validators.Username, "nobody")
 
     @unittest.skip("Not implemented yet")
     def test_github_organization(self):
         self.assertEqual(
-            validators.GithubOrganization.from_string("fedora-infra"),
+            validators.GithubOrganization("fedora-infra"),
             "fedora-infra")
         self.assertRaises(
             ValueError,
-            validators.GithubOrganization.from_string,
+            validators.GithubOrganization,
             "something-that-does-not-exist")
 
     @unittest.skip("Not implemented yet")
     def test_github_repo(self):
         self.assertEqual(
-            validators.GithubRepo.from_string("fedmsg"), "fedmsg")
-        self.assertRaises(ValueError, validators.GithubRepo.from_string,
+            validators.GithubRepo("fedmsg"), "fedmsg")
+        self.assertRaises(ValueError, validators.GithubRepo,
                           "something-that-does-not-exist")
 
     def test_fmncontext(self):
-        self.assertEqual(validators.FMNContext.from_string("email"), "email")
+        self.assertEqual(validators.FMNContext("email"), "email")
         self.assertRaises(
-            ValueError, validators.FMNContext.from_string, "dummy")
+            ValueError, validators.FMNContext, "dummy")
 
     def test_pagure_repo(self):
         self.assertEqual(
-            validators.PagureRepo.from_string("fedora-hubs"), "fedora-hubs")
-        self.assertRaises(ValueError, validators.PagureRepo.from_string,
+            validators.PagureRepo("fedora-hubs"), "fedora-hubs")
+        self.assertRaises(ValueError, validators.PagureRepo,
                           "something-that-does-not-exist")
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 7f35b37..b562662 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -9,7 +9,6 @@ import six
 from importlib import import_module
 from .caching import CachedFunction
 from .view import WidgetView
-from .validators import Validator
 
 
 log = logging.getLogger(__name__)
@@ -25,18 +24,17 @@ class WidgetParameter(object):
     :py:meth:`~Widget.get_parameters` method.
 
     The value of the parameter is stored in the database as the value returned
-    by the validator's :py:meth:`from_string` method.  It can thus be a string,
-    an integer, a list, a dict, or any JSON-serializable value.
+    by the validator's call.  It can thus be a string, an integer, a list, a
+    dict, or any JSON-serializable value.
 
     Attributes:
         name (str): The name of the parameter.
         label (str): A humanized name of the parameter, which will be shown in
             the UI.
         default: The default value if this parameter is not set.
-        validator (hubs.widgets.validators.Validator): A validator subclass
-            that will be used to convert the parameter value to and from
-            string, raising an exception if it is invalid. This attribute
-            points to the validator subclass, not an instance of the class.
+        validator (callable): A validator function that will be used to convert
+            the parameter value to a JSON-serializable value, raising an
+            exception if it is invalid.
         help (str): A help text that will be shown in the UI.
     """
 
@@ -49,7 +47,7 @@ class WidgetParameter(object):
             raise TypeError("Invalid attribute: %s" % name)
         # Set default validator
         if self.validator is None:
-            self.validator = Validator
+            self.validator = lambda x: x
 
 
 class Widget(object):
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index bf05a53..f8c5b8f 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -1,82 +1,50 @@
+"""
+Validate and convert the value of widget parameters.
+
+Validators are used to validate and convert
+:py:class:`~hubs.widgets.base.WidgetParameter` values. They will raise a
+``ValueError`` exception if the value is invalid.
+
+A validator is a function that will receive the value as unique argument, and
+will return the validated value.
+"""
+
 from __future__ import unicode_literals
 
 import flask
 import hubs.models
 import kitchen.text.converters
 import requests
+import six
 
 
-class Validator(object):
-    """Convert widget parameters to and from string, and validate their value.
-
-    Validators are used to convert
-    :py:class:`~hubs.widgets.base.WidgetParameter` values to and from string.
-    They will raise an exception if the value is invalid.
-
-    A validator is a subclass of the :py:class:`Validator` class and implements
-    two class methods: :py:meth:`from_string` and :py:meth:`to_string`.
-    """
-
-    @classmethod
-    def from_string(cls, value):
-        """Convert the value from a string to a JSON-serializable value.
-
-        The result of this function will be stored in the database for widget
-        parameters.
-
-        Raises:
-            ValueError: The value is invalid.
-        """
-        if value is None:
-            return ""
-        return value
-
-    @classmethod
-    def to_string(cls, value):
-        """Convert the value to a string.
-
-        The result of this function will be used in the widget configuration
-        form fields.
-        """
-        return value
-
-
-class Required(Validator):
+def Required(value):
     """Raises an error if the value is ``False``-like."""
-
-    @classmethod
-    def from_string(cls, value):
-        if not bool(value):
-            raise ValueError("the parameter is required")
-        return value
+    if not bool(value):
+        raise ValueError("the parameter is required")
+    # if callable(value):
+    #     # Act as a decorator
+    #     return lambda v: Required(value(v))
+    return value
 
 
-class Text(Validator):
+def Text(value):
     """Raises an error if the value can't be converted to unicode."""
+    return kitchen.text.converters.to_unicode(value)
 
-    @classmethod
-    def from_string(cls, value):
-        return kitchen.text.converters.to_unicode(value)
 
-
-class Integer(Validator):
+def Integer(value):
     """Raises an error if the value can't be converted to an integer."""
-
-    @classmethod
-    def from_string(cls, value):
-        return int(value)
+    return int(value)
 
 
-class Link(Validator):
+def Link(value):
     """Raises an error if the value doesn't look like a link."""
-
-    @classmethod
-    def from_string(cls, value):
-        # TODO -- verify that this is actually a link
-        return value
+    # TODO -- verify that this is actually a link
+    return value
 
 
-class Username(Validator):
+def Username(value):
     """Raises an error if the value isn't an existing username.
 
     There must be a corresponding :py:class:`~hubs.models.User` record.
@@ -84,77 +52,55 @@ class Username(Validator):
     This validator does not return the User instance because it is not
     JSON-serializable, it returns the username unchanged.
     """
-
-    @classmethod
-    def from_string(cls, value):
-        if hubs.models.User.by_username(value) is not None:
-            return value
-        raise ValueError('Invalid username')
-
-    @classmethod
-    def to_string(cls, value):
-        if value is None and flask.g.auth.logged_in:
-            return flask.g.user.username
+    if value is None and flask.g.auth.logged_in:
+        return flask.g.user.username
+    if hubs.models.User.by_username(value) is not None:
         return value
+    raise ValueError('Invalid username')
 
 
-class GithubOrganization(Validator):
+def GithubOrganization(value):
     """Fails if the Github organization name does not exist."""
-
-    @classmethod
-    def from_string(cls, value):
-        # TODO -- implement this.
-        return value
+    # TODO -- implement this.
+    return value
 
 
-class GithubRepo(Validator):
+def GithubRepo(value):
     """Fails if the Github repository name does not exist."""
-
-    @classmethod
-    def from_string(cls, value):
-        # TODO -- implement this.
-        return value
+    # TODO -- implement this.
+    return value
 
 
-class FMNContext(Validator):
+def FMNContext(value):
     """Fails if the value is not a valid FMN context name."""
-
-    @classmethod
-    def from_string(cls, value):
-        # TODO get this from the fedmsg config.
-        if value in ['irc', 'email', 'android', 'desktop', 'hubs']:
-            return value
-        raise ValueError('Invalid FMN context')
+    # TODO get this from the fedmsg config.
+    if value in ['irc', 'email', 'android', 'desktop', 'hubs']:
+        return value
+    raise ValueError('Invalid FMN context')
 
 
-class PagureRepo(Validator):
+def PagureRepo(value):
     """Fails if the Pagure repository name does not exist."""
-
-    @classmethod
-    def from_string(cls, value):
-        response = requests.get("https://pagure.io/%s" % value, timeout=5)
-        if response.status_code == 200:
-            return value
-        raise ValueError('Invalid pagure repo')
+    response = requests.get("https://pagure.io/%s" % value, timeout=5)
+    if response.status_code == 200:
+        return value
+    raise ValueError('Invalid pagure repo')
 
 
-class CommaSeparatedList(Validator):
-    """Fails if the value isn't a comma-separated list.
+def CommaSeparatedList(value):
+    """Fails if the value isn't a list.
 
-    The value will be converted to a Python list. If there is no comma in the
-    original value, it will produce a list with a single element. Whitespaces
-    will be stripped from the elements, so spaces are allowed around the
-    commas.
+    If the value is a string, list, it will be interpreted as a comma-separated
+    list and converted to a Python list. If there is no comma in the original
+    value, it will produce a list with a single element. Whitespaces will be
+    stripped from the elements, so spaces are allowed around the commas.
     """
-
-    @classmethod
-    def from_string(cls, value):
+    if not value:
+        return []
+    if isinstance(value, six.string_types):
         return [
             elem.strip() for elem in value.split(",") if elem.strip()
             ]
-
-    @classmethod
-    def to_string(cls, value):
-        if not value:
-            return ""
-        return ", ".join(value)
+    if not isinstance(value, list):
+        raise ValueError("Expected a list")
+    return value

From 107e4fb9f5bcc363d0552b98328983b87fc223e5 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:08 +0000
Subject: [PATCH 952/1001] Sort widgets by index by default


---

diff --git a/hubs/models.py b/hubs/models.py
index eebd178..3b7283d 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -142,7 +142,8 @@ class Hub(ObjectAuthzMixin, BASE):
     __tablename__ = 'hubs'
     name = sa.Column(sa.String(50), primary_key=True)
     created_on = sa.Column(sa.DateTime, default=datetime.datetime.utcnow)
-    widgets = relation('Widget', cascade='all,delete', backref='hub')
+    widgets = relation('Widget', cascade='all,delete', backref='hub',
+                       order_by="Widget.index")
     config = relation('HubConfig', uselist=False, cascade='all,delete',
                       backref='hub')
     archived = sa.Column(sa.Boolean, default=False)

From cee7c15211ac5929154f9b2e40b5fc616bbdc8cc Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:08 +0000
Subject: [PATCH 953/1001] Add the hub's right width as a property with a setter


---

diff --git a/hubs/models.py b/hubs/models.py
index 3b7283d..498d4fa 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -337,6 +337,7 @@ class HubConfig(BASE):
         return {
             'summary': self.summary,
             'left_width': self.left_width,
+            'right_width': self.right_width,
             'avatar': self.avatar,
             'chat_channel': self.chat_channel,
             'chat_domain': self.chat_domain,
@@ -347,6 +348,10 @@ class HubConfig(BASE):
     def right_width(self):
         return 12 - self.left_width
 
+    @right_width.setter
+    def right_width(self, value):
+        self.left_width = 12 - value
+
 
 class SpecificDefaultDict(defaultdict):
     """A more specific version of defaultdict.

From 455ab9a811e66ad6ae2cb46a3fa616584da39a29 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:08 +0000
Subject: [PATCH 954/1001] Use a REST API for hub and widget config


---

diff --git a/hubs/tests/utils/test_views.py b/hubs/tests/utils/test_views.py
index 262df3d..9c4f54f 100644
--- a/hubs/tests/utils/test_views.py
+++ b/hubs/tests/utils/test_views.py
@@ -5,7 +5,7 @@ import flask
 import hubs.models
 from hubs.app import app
 from hubs.tests import APPTest, FakeAuthorization, auth_set, app_config
-from hubs.utils.views import get_visible_widgets, get_sse_url
+from hubs.utils.views import get_visible_widgets, get_sse_url, move_widget
 
 
 class ViewUtilsTest(APPTest):
@@ -129,3 +129,50 @@ class ViewUtilsTest(APPTest):
                 self.assertEqual(
                     get_sse_url("hub/ralph"),
                     "http://example.com/hub/ralph")
+
+    def test_move_widget(self):
+        hub = hubs.models.Hub(name="testing")
+        self.session.add(hub)
+        widget_names = ["about", "badges", "bugzilla", "contact", "dummy"]
+
+        def get_names():
+            return [
+                w.plugin for w in
+                hubs.models.Widget.query.filter_by(hub=hub).order_by(hubs.models.Widget.index)
+                ]
+
+        def get_widget(name):
+            return hubs.models.Widget.query.filter_by(hub=hub, plugin=name).one()
+
+        def check_move(name, position, expected):
+            move_widget(get_widget(name), position)
+            self.session.flush()
+            self.session.refresh(hub)
+            self.assertListEqual(get_names(), expected)
+
+        for index, name in enumerate(widget_names):
+            widget = hubs.models.Widget(
+                hub=hub, plugin=name,
+                left=True, index=index, _config="{}")
+            self.session.add(widget)
+        self.assertListEqual(get_names(), widget_names)
+        # From middle to middle forwards
+        check_move(
+            "badges", 3,
+            ["about", "bugzilla", "contact", "badges", "dummy"])
+        # From middle to middle backwards
+        check_move(
+            "badges", 1,
+            ["about", "badges", "bugzilla", "contact", "dummy"])
+        # From middle to start
+        check_move(
+            "contact", 0,
+            ["contact", "about", "badges", "bugzilla", "dummy"])
+        # From middle to end
+        check_move(
+            "badges", 5,
+            ["contact", "about", "bugzilla", "dummy", "badges"])
+        # From start to end
+        check_move(
+            "contact", 5,
+            ["about", "bugzilla", "dummy", "badges", "contact"])
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete
new file mode 100644
index 0000000..1c79340
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete
@@ -0,0 +1,450 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://pagure.io/pagure
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - pagure - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\"\
+        \n        href=\"/static/favicon.ico\"/>\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/vendor/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/vendor/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/pagure git https://pagure.io/pagure.git\">\n  </head>\n\
+        \  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"masthead\"\
+        >\n      <div class=\"container\">\n        <div class=\"row\">\n        \
+        \  <div class=\"col-sm-3\">\n            <a href=\"/\">\n              <img\
+        \ height=40px src=\"/static/pagure-logo.png\"\n                alt=\"pagure\
+        \ Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n       \
+        \   <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav class=\"\
+        navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\">\n    \
+        \    <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n         \
+        \     <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link btn\
+        \ btn-primary\" href=\"/login/?next=https://pagure.io/pagure\">Log In</a>\n\
+        \              </li>\n        </ul>\n      </div>\n    </nav>\n\n        \
+        \    </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n<a href=\"/pagure\">pagure</a>\n        </h2>\n\
+        \        <div class=\"projectinfo m-t-1 m-b-1\">\nA git centered forge &nbsp;|\
+        \ &nbsp;<a class=\"inline\" href=\"https://pagure.io\">https://pagure.io</a>\
+        \        </div>\n\n    </header>\n    <ul class=\"nav nav-tabs nav-small\"\
+        >\n      <li class=\"nav-item\">\n        <a class=\"nav-link active\" href=\"\
+        /pagure\">\n            <span class=\"oi hidden-md-up\" data-glyph=\"home\"\
+        ></span>\n            <span class=\"hidden-sm-down\">Overview</span>\n   \
+        \     </a>\n      </li>\n        <li class=\"nav-item\" >\n          <a  class=\"\
+        nav-link\" href=\"/docs/pagure/\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"book\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Docs</span>\n          </a>\n        </li>\n\n        <li class=\"nav-item\"\
+        >\n          <a class=\"nav-link\" href=\"/pagure/commits/master\">\n    \
+        \          <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n \
+        \             </span><span class=\"hidden-sm-down\">Commits</span>\n     \
+        \       </a>\n        </li>\n\n        <li class=\"nav-item\">\n         \
+        \ <a class=\"nav-link\" href=\"/pagure/tree/master\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/pagure/issues\">\n                <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n             \
+        \   <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n                <span\
+        \ class=\"label label-default label-pill hidden-sm-down\">\n             \
+        \     339\n                </span>\n            </a>\n        </li>\n\n  \
+        \      <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"/pagure/pull-requests\"\
+        >\n              <span class=\"oi hidden-md-up\" data-glyph=\"task\"></span>\n\
+        \              <span class=\"hidden-sm-down\">Pull Requests&nbsp;</span>\n\
+        \              <span class=\"label label-default label-pill hidden-sm-down\"\
+        >\n                16\n              </span>\n          </a>\n        </li>\n\
+        \n        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/forks\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        fork\"></span>\n              <span class=\"hidden-sm-down\">Forks&nbsp;</span>\n\
+        \              <span class=\"hidden-sm-down label label-default label-pill\"\
+        >\n                131\n              </span>\n            </a>\n        </li>\n\
+        \n\n    </ul>\n  </div>\n</div>\n\n<div class=\"container p-t-3\">\n  <div\
+        \ class=\"row\">\n        <div class=\"col-md-8\">\n            <section class=\"\
+        readme\">\n              <div class=\"document\">\n<div class=\"section\"\
+        >\n<h1>Pagure</h1>\n<table class=\"docutils field-list\">\n<colgroup><col>\n\
+        <col>\n</colgroup><tbody>\n<tr><th>Author:</th><td>Pierre-Yves Chibon &lt;<a\
+        \ href=\"mailto:pingou@pingoured.fr\">pingou@pingoured.fr</a>&gt;</td>\n</tr>\n\
+        </tbody>\n</table>\n<p>Pagure is a git-centered forge, python based using\
+        \ pygit2.</p>\n<p>With pagure you can host your project with its documentation,\
+        \ let your users\nreport issues or request enhancements using the ticketing\
+        \ system and build your\ncommunity of contributors by allowing them to fork\
+        \ your projects and contribute\nto it via the now-popular pull-request mechanism.</p>\n\
+        <p>Homepage: <a href=\"https://pagure.io/pagure\">https://pagure.io/pagure</a></p>\n\
+        <p>See it at work: <a href=\"https://pagure.io\">https://pagure.io</a></p>\n\
+        <p>Playground version: <a href=\"https://stg.pagure.io\">https://stg.pagure.io</a></p>\n\
+        </div>\n<div class=\"section\">\n<h1>Get it running</h1>\n<p>There are several\
+        \ options when it comes to a development environment. Vagrant\nwill provide\
+        \ you with a virtual machine which you can develop on, or you can\ninstall\
+        \ it directly on your host machine.</p>\n<div class=\"section\">\n<h2>Vagrant</h2>\n\
+        <p>For a more thorough introduction to Vagrant, see\n<a href=\"https://fedoraproject.org/wiki/Vagrant\"\
+        >https://fedoraproject.org/wiki/Vagrant</a>.</p>\n<p>An example Vagrantfile\
+        \ is provided as <code>Vagrantfile.example</code>. To use it,\njust copy it\
+        \ and install Vagrant:</p>\n<pre>$ cp dev/Vagrantfile.example Vagrantfile\n\
+        $ sudo dnf install ansible libvirt vagrant-libvirt vagrant-sshfs vagrant-hostmanager\n\
+        $ vagrant up\n</pre>\n<p>The default <code>Vagrantfile</code> forwards ports\
+        \ from the host to the guest,\nso you can interact with the application as\
+        \ if it were running on your\nhost machine.</p>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p><code><span class=\"pre\">vagrant-hostmanager</span></code> will automatically\
+        \ maintain /etc/hosts for you so you\ncan access the development environment\
+        \ from the host using its hostname, which\nby default is <code><span class=\"\
+        pre\">pagure-dev.example.com</span></code>. You can choose not to use this\n\
+        functionality by simply not installing the <code><span class=\"pre\">vagrant-hostmanager</span></code>\
+        \ plugin, but\nif you want Pagure to provide valid URLs in the UI for git\
+        \ repositories, you\nwill need to adjust Pagure's configuration found in ~/pagure.cfg\
+        \ on the guest.</p>\n</div>\n</div>\n<div class=\"section\">\n<h2>Manually</h2>\n\
+        <ul>\n<li><p>Install the needed system libraries:</p>\n<pre>sudo dnf install\
+        \ git python2-virtualenv libgit2-devel \\\n                 libjpeg-devel\
+        \ gcc libffi-devel redhat-rpm-config\n</pre>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p>Do note the version of libgit2 that you install, for example\nin <code><span\
+        \ class=\"pre\">libgit2-0.23.4-1</span></code> you need to keep in mind the\
+        \ <code>0.23</code></p>\n</div>\n<div class=\"note\">\n<p>Note</p>\n<p>On\
+        \ Fedora 23 and earlier or on RHEL and derivative (CentOS,\nScientific Linux)\
+        \ the package <cite>python2-virtualenv</cite> is named\n<cite>python-virtualenv</cite></p>\n\
+        </div>\n</li>\n<li><p>Retrieve the sources:</p>\n<pre>git clone https://pagure.io/pagure.git\n\
+        cd pagure\n</pre>\n</li>\n<li><p>Install dependencies</p>\n<ul>\n<li><p>create\
+        \ the virtualenv:</p>\n<pre>virtualenv pagure_env\nsource ./pagure_env/bin/activate\n\
+        </pre>\n</li>\n<li><p>Install the correct version of pygit2:</p>\n<pre>pip\
+        \ install pygit2==&lt;version of libgit2 found&gt;.*\n</pre>\n<p>So in our\
+        \ example:</p>\n<pre>pip install pygit2==0.23.*\n</pre>\n</li>\n<li><p>Install\
+        \ the rest of the dependencies:</p>\n<pre>pip install -r requirements.txt\n\
+        </pre>\n</li>\n</ul>\n</li>\n<li><p>Create the folder that will receive the\
+        \ projects, forks, docs, requests and\ntickets' git repo:</p>\n<pre>mkdir\
+        \ -p lcl/{repos,docs,forks,tickets,requests,remotes,attachments,releases}\n\
+        </pre>\n</li>\n<li><p>Create the inital database scheme:</p>\n<pre>python\
+        \ createdb.py\n</pre>\n</li>\n<li><p>Start a worker, in one terminal:</p>\n\
+        <pre>./runworker.py\n</pre>\n</li>\n<li><p>Run the application, in another\
+        \ terminal:</p>\n<pre>./runserver.py\n</pre>\n</li>\n<li><p>To get some profiling\
+        \ information you can also run it as:</p>\n<pre>./runserver.py --profile\n\
+        </pre>\n</li>\n</ul>\n<p>This will launch the application at <a href=\"http://127.0.0.1:5000\"\
+        >http://127.0.0.1:5000</a></p>\n<ul>\n<li><p>To run unit-tests on pagure</p>\n\
+        <ul>\n<li><p>Install the dependencies:</p>\n<pre>pip install -r tests_requirements.txt\n\
+        </pre>\n</li>\n<li><p>Run it:</p>\n<pre>./runtests.sh\n</pre>\n<div class=\"\
+        note\">\n<p>Note</p>\n<p>While testing for worker tasks, pagure uses celery\
+        \ in /usr/bin/\nCelery then looks for eventlet (which we use for testing only)\
+        \ at\nsystem level and not in virtualenv. You will need to install eventlet\n\
+        outside of your virtualenv if you are using one.</p>\n</div>\n</li>\n</ul>\n\
+        </li>\n</ul>\n</div>\n</div>\n</div>\n\n            </section>\n        </div>\n\
+        \      <div class=\"col-md-4\">\n        <div class=\"card\">\n          <div\
+        \ class=\"card-block\">\n            <h5><strong>Contributors</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/pingou\">\n                  <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \               -  main admin\n              </div>\n                  <div>\n\
+        \                    <a href=\"/user/ryanlerch\">\n                      <img\
+        \ class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                      Ryan Lerch (ryanlerch)\n                    </a>\n\
+        \                    - admin\n                  </div>\n                 \
+        \ <div>\n                    <a href=\"/user/puiterwijk\">\n             \
+        \         <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/85f8b5f58b9808429ad69ba3722d64da01ce850635e348e838dfdc053e1140e3?s=20&d=retro\"\
+        />\n                      Patrick &#34;\u30DE\u30EB\u30BF\u30A4\u30F3\u30A2\
+        \u30F3\u30C9\u30EC\u30A2\u30B9&#34; Uiterwijk (puiterwijk)\n             \
+        \       </a>\n                    - commit\n                  </div>\n   \
+        \               <div>\n                    <a href=\"/user/vivekanand1101\"\
+        >\n                      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                      Vivek Anand (vivekanand1101)\n                 \
+        \   </a>\n                    - ticket\n                  </div>\n       \
+        \           <div>\n                    <a href=\"/user/farhaan\">\n      \
+        \                <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b681ddfaffa293b03c57e5f0ed90eb1e06a8f748f4dccdccef8cdd301c66c9ae?s=20&d=retro\"\
+        />\n                      Farhaan Bukhsh (farhaan)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/cverna\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/c7844b93c43c862adaa29920c09bdfb91efed57a843203e5d0b72673e664c003?s=20&d=retro\"\
+        />\n                      Clement Verna (cverna)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/jcline\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                      Jeremy Cline (jcline)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/lslebodn\">\n              \
+        \        <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/8c6fcfe0eec099f1f01f5c237935bb5c97f2063a5c1068e57c5815e0bfecbf70?s=20&d=retro\"\
+        />\n                      Lukas Slebodnik (lslebodn)\n                   \
+        \ </a>\n                    - ticket\n                  </div>\n         \
+        \         <div>\n                    <a href=\"/user/mprahl\">\n         \
+        \             <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/ecae5ad9b37619a38e699de00049e449f120b433c9f26a8beb05b990dfc54c9d?s=20&d=retro\"\
+        />\n                      Matt Prahl (mprahl)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n            </div>\n\
+        \            <h5><strong>Branches</strong></h5>\n            <div class=\"\
+        m-b-2\">\n              <div id=\"branch-master\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"\n          \
+        \          title=\"Default branch\"></span>\n                  <strong title=\"\
+        Currently viewing branch master\" data-toggle=\"tooltip\">master</strong>\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"star\"\n \
+        \                   title=\"Default branch\"></span>\n                </div>\n\
+        \              </div>\n\n              <div id=\"branch-2.9.x\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/2.9.x\"\n           \
+        \         title=\"2.9.x\" data-toggle=\"tooltip\">2.9.x\n                \
+        \  </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-alembic_changes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/alembic_changes\"\n        \
+        \            title=\"alembic_changes\" data-toggle=\"tooltip\">alembic_changes\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-confirm_merge\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/confirm_merge\"\n   \
+        \                 title=\"confirm_merge\" data-toggle=\"tooltip\">confirm_merge\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-css_tables\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/css_tables\"\n      \
+        \              title=\"css_tables\" data-toggle=\"tooltip\">css_tables\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_del_project\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_del_project\"\n \
+        \                   title=\"fix_del_project\" data-toggle=\"tooltip\">fix_del_project\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_delete\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_delete\"\n      \
+        \              title=\"fix_delete\" data-toggle=\"tooltip\">fix_delete\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_diff_refs\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_diff_refs\"\n   \
+        \                 title=\"fix_diff_refs\" data-toggle=\"tooltip\">fix_diff_refs\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_doc\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_doc\"\n                \
+        \    title=\"fix_doc\" data-toggle=\"tooltip\">fix_doc\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_linking\" class=\"repoinfo-branchlistitem row\">\n\
+        \                <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/fix_linking\"\n                   \
+        \ title=\"fix_linking\" data-toggle=\"tooltip\">fix_linking\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_pygit_error\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_pygit_error\"\n        \
+        \            title=\"fix_pygit_error\" data-toggle=\"tooltip\">fix_pygit_error\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_reply_to\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_reply_to\"\n    \
+        \                title=\"fix_reply_to\" data-toggle=\"tooltip\">fix_reply_to\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_sse\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse\"\n                \
+        \    title=\"fix_sse\" data-toggle=\"tooltip\">fix_sse\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_sse_status\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse_status\"\n         \
+        \           title=\"fix_sse_status\" data-toggle=\"tooltip\">fix_sse_status\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_templates\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_templates\"\n   \
+        \                 title=\"fix_templates\" data-toggle=\"tooltip\">fix_templates\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fixes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fixes\"\n                  \
+        \  title=\"fixes\" data-toggle=\"tooltip\">fixes\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-force_flag\" class=\"repoinfo-branchlistitem row\">\n             \
+        \   <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/force_flag\"\n                    title=\"force_flag\"\
+        \ data-toggle=\"tooltip\">force_flag\n                  </a>\n\n         \
+        \       </div>\n                <div class=\"branch_del col-md-4\">\n    \
+        \            </div>\n              </div>\n              <div id=\"branch-gpg_check\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/gpg_check\"\
+        \n                    title=\"gpg_check\" data-toggle=\"tooltip\">gpg_check\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-logging_milter\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/logging_milter\"\n  \
+        \                  title=\"logging_milter\" data-toggle=\"tooltip\">logging_milter\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-mirroring\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/mirroring\"\n              \
+        \      title=\"mirroring\" data-toggle=\"tooltip\">mirroring\n           \
+        \       </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-py3_work2\" class=\"repoinfo-branchlistitem row\">\n \
+        \               <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/py3_work2\"\n                    title=\"\
+        py3_work2\" data-toggle=\"tooltip\">py3_work2\n                  </a>\n\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-rel_2.2.z\" class=\"repoinfo-branchlistitem row\">\n              \
+        \  <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/rel_2.2.z\"\n                    title=\"rel_2.2.z\"\
+        \ data-toggle=\"tooltip\">rel_2.2.z\n                  </a>\n\n          \
+        \      </div>\n                <div class=\"branch_del col-md-4\">\n     \
+        \           </div>\n              </div>\n              <div id=\"branch-rel_2.3.z\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/rel_2.3.z\"\
+        \n                    title=\"rel_2.3.z\" data-toggle=\"tooltip\">rel_2.3.z\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-scroll_metadata\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/scroll_metadata\"\n \
+        \                   title=\"scroll_metadata\" data-toggle=\"tooltip\">scroll_metadata\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-utf_search\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/utf_search\"\n      \
+        \              title=\"utf_search\" data-toggle=\"tooltip\">utf_search\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \         </div>\n            <h5><strong>Source GIT URLs</strong>       \
+        \           <span class=\"pull-xs-right\"><a data-toggle=\"collapse\" href=\"\
+        #moregiturls\"\n                  aria-expanded=\"false\" aria-controls=\"\
+        moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n \
+        \           <div>\n              <div class=\"form-group\">\n            \
+        \    <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">GIT</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"https://pagure.io/pagure.git\" readonly>\n       \
+        \         </div>\n              </div>\n              <div class=\"collapse\"\
+        \ id=\"moregiturls\">\n                  <h5><strong>Docs GIT URLs</strong></h5>\n\
+        \                  <div class=\"form-group\">\n                    <div class=\"\
+        input-group input-group-sm\">\n                      <div class=\"input-group-addon\"\
+        >GIT</div>\n                      <input class=\"form-control\" type=\"text\"\
+        \ value=\"https://pagure.io/docs/pagure.git\" readonly>\n                \
+        \    </div>\n                  </div>\n              </div>\n            </div>\n\
+        \          </div>\n          <div class=\"repo_date\" title=\"2015-05-13 20:38:10.552662\"\
+        >\n              created 2 years ago\n          </div>\n        </div>\n\n\
+        \          <div class=\"card\">\n            <div class=\"card-header\">\n\
+        \              <strong>Recent Commits in\n                <span class=\"pr-toplabel\"\
+        >\n                  <span class=\"oi\" data-glyph=\"random\"></span>\n  \
+        \                master\n                </span>\n              </strong>\n\
+        \            </div>\n            <div class=\"card-block p-a-0\">\n      \
+        \        <div class=\"list-group list-group-flush\">\n                  <a\
+        \ href=\"/pagure/c/75b9021afbb08a3bdc1128cb282ea9c2394c0b67\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Sep 21 2017 08:20:29\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Add unit-tests for the fixes around loading issue template\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/pagure/c/fc1d7f885d8b658ce7ba2fbd9cf20692b32f7732\" class=\"\
+        list-group-item\">\n                    <div class=\"commitdate\" title=\"\
+        Sep 21 2017 08:20:29\">\n                      <small>\n                 \
+        \       <strong>\n                          <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Flake8 fix fixing the tests\n                    </small></div>\n\
+        \                  </a>\n                  <a href=\"/pagure/c/91c1f357adc77f0b21e15f6177c68ffc97f3ec67\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Sep 21 2017 08:20:29\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Adjust the documentation around ticket templates\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          3.7.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage/index.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/vendor/jquery/jquery.min.js\">\n    </script>\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/vendor/jquery-ui/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n        var currentWatchStatusButton\
+        \ = $('#unwatch_button');\n    currentWatchStatusButton.prepend('<span class=\"\
+        oi\" data-glyph=\"circle-check\" style=\"padding-right:0.5em\"></span>');\n\
+        \    $('.watch-menu a').not(currentWatchStatusButton).css('padding-left',\
+        \ '2.85em');\n\n    $(\".watch-menu a\").click(function(){\n        var selectedValue\
+        \ = $(this).attr('id');\n        var watchProjectForm = $(\"#watch_project\"\
+        );\n        var action = watchProjectForm.attr('action');\n\n        if (selectedValue\
+        \ === \"watch_issues_button\") {\n            action = action.replace('/settings/0',\
+        \ '/settings/1');\n        } else if (selectedValue === \"watch_commits_button\"\
+        ) {\n            action = action.replace('/settings/0', '/settings/2');\n\
+        \        } else if (selectedValue === \"watch_issues_commits_button\") {\n\
+        \            action = action.replace('/settings/0', '/settings/3');\n    \
+        \    } else if (selectedValue === \"reset_button\") {\n            action\
+        \ = action.replace('/settings/0', '/settings/-1');\n        }\n\n        watchProjectForm.attr('action',\
+        \ action);\n        watchProjectForm.submit();\n    });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      Connection: [Keep-Alive]
+      Content-Length: ['31652']
+      Content-Type: [text/html; charset=utf-8]
+      Date: ['Tue, 26 Sep 2017 15:29:31 GMT']
+      Keep-Alive: ['timeout=5, max=100']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      Set-Cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiWkRBMk1qSmpOakUzWkdGaU1qRTRNemd5WkdFNFlUWTVOakUwTkRoak9UWXhOR1V5T0dGa05RPT0ifX0.DKwD3A.-Hon7IeCBYGJMVcECsPCVMDRot4;
+          Expires=Fri, 27-Oct-2017 15:29:32 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete_unauthorized b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete_unauthorized
new file mode 100644
index 0000000..002f0d8
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete_unauthorized
@@ -0,0 +1,450 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://pagure.io/pagure
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - pagure - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\"\
+        \n        href=\"/static/favicon.ico\"/>\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/vendor/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/vendor/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/pagure git https://pagure.io/pagure.git\">\n  </head>\n\
+        \  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"masthead\"\
+        >\n      <div class=\"container\">\n        <div class=\"row\">\n        \
+        \  <div class=\"col-sm-3\">\n            <a href=\"/\">\n              <img\
+        \ height=40px src=\"/static/pagure-logo.png\"\n                alt=\"pagure\
+        \ Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n       \
+        \   <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav class=\"\
+        navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\">\n    \
+        \    <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n         \
+        \     <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link btn\
+        \ btn-primary\" href=\"/login/?next=https://pagure.io/pagure\">Log In</a>\n\
+        \              </li>\n        </ul>\n      </div>\n    </nav>\n\n        \
+        \    </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n<a href=\"/pagure\">pagure</a>\n        </h2>\n\
+        \        <div class=\"projectinfo m-t-1 m-b-1\">\nA git centered forge &nbsp;|\
+        \ &nbsp;<a class=\"inline\" href=\"https://pagure.io\">https://pagure.io</a>\
+        \        </div>\n\n    </header>\n    <ul class=\"nav nav-tabs nav-small\"\
+        >\n      <li class=\"nav-item\">\n        <a class=\"nav-link active\" href=\"\
+        /pagure\">\n            <span class=\"oi hidden-md-up\" data-glyph=\"home\"\
+        ></span>\n            <span class=\"hidden-sm-down\">Overview</span>\n   \
+        \     </a>\n      </li>\n        <li class=\"nav-item\" >\n          <a  class=\"\
+        nav-link\" href=\"/docs/pagure/\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"book\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Docs</span>\n          </a>\n        </li>\n\n        <li class=\"nav-item\"\
+        >\n          <a class=\"nav-link\" href=\"/pagure/commits/master\">\n    \
+        \          <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n \
+        \             </span><span class=\"hidden-sm-down\">Commits</span>\n     \
+        \       </a>\n        </li>\n\n        <li class=\"nav-item\">\n         \
+        \ <a class=\"nav-link\" href=\"/pagure/tree/master\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/pagure/issues\">\n                <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n             \
+        \   <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n                <span\
+        \ class=\"label label-default label-pill hidden-sm-down\">\n             \
+        \     339\n                </span>\n            </a>\n        </li>\n\n  \
+        \      <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"/pagure/pull-requests\"\
+        >\n              <span class=\"oi hidden-md-up\" data-glyph=\"task\"></span>\n\
+        \              <span class=\"hidden-sm-down\">Pull Requests&nbsp;</span>\n\
+        \              <span class=\"label label-default label-pill hidden-sm-down\"\
+        >\n                16\n              </span>\n          </a>\n        </li>\n\
+        \n        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/forks\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        fork\"></span>\n              <span class=\"hidden-sm-down\">Forks&nbsp;</span>\n\
+        \              <span class=\"hidden-sm-down label label-default label-pill\"\
+        >\n                131\n              </span>\n            </a>\n        </li>\n\
+        \n\n    </ul>\n  </div>\n</div>\n\n<div class=\"container p-t-3\">\n  <div\
+        \ class=\"row\">\n        <div class=\"col-md-8\">\n            <section class=\"\
+        readme\">\n              <div class=\"document\">\n<div class=\"section\"\
+        >\n<h1>Pagure</h1>\n<table class=\"docutils field-list\">\n<colgroup><col>\n\
+        <col>\n</colgroup><tbody>\n<tr><th>Author:</th><td>Pierre-Yves Chibon &lt;<a\
+        \ href=\"mailto:pingou@pingoured.fr\">pingou@pingoured.fr</a>&gt;</td>\n</tr>\n\
+        </tbody>\n</table>\n<p>Pagure is a git-centered forge, python based using\
+        \ pygit2.</p>\n<p>With pagure you can host your project with its documentation,\
+        \ let your users\nreport issues or request enhancements using the ticketing\
+        \ system and build your\ncommunity of contributors by allowing them to fork\
+        \ your projects and contribute\nto it via the now-popular pull-request mechanism.</p>\n\
+        <p>Homepage: <a href=\"https://pagure.io/pagure\">https://pagure.io/pagure</a></p>\n\
+        <p>See it at work: <a href=\"https://pagure.io\">https://pagure.io</a></p>\n\
+        <p>Playground version: <a href=\"https://stg.pagure.io\">https://stg.pagure.io</a></p>\n\
+        </div>\n<div class=\"section\">\n<h1>Get it running</h1>\n<p>There are several\
+        \ options when it comes to a development environment. Vagrant\nwill provide\
+        \ you with a virtual machine which you can develop on, or you can\ninstall\
+        \ it directly on your host machine.</p>\n<div class=\"section\">\n<h2>Vagrant</h2>\n\
+        <p>For a more thorough introduction to Vagrant, see\n<a href=\"https://fedoraproject.org/wiki/Vagrant\"\
+        >https://fedoraproject.org/wiki/Vagrant</a>.</p>\n<p>An example Vagrantfile\
+        \ is provided as <code>Vagrantfile.example</code>. To use it,\njust copy it\
+        \ and install Vagrant:</p>\n<pre>$ cp dev/Vagrantfile.example Vagrantfile\n\
+        $ sudo dnf install ansible libvirt vagrant-libvirt vagrant-sshfs vagrant-hostmanager\n\
+        $ vagrant up\n</pre>\n<p>The default <code>Vagrantfile</code> forwards ports\
+        \ from the host to the guest,\nso you can interact with the application as\
+        \ if it were running on your\nhost machine.</p>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p><code><span class=\"pre\">vagrant-hostmanager</span></code> will automatically\
+        \ maintain /etc/hosts for you so you\ncan access the development environment\
+        \ from the host using its hostname, which\nby default is <code><span class=\"\
+        pre\">pagure-dev.example.com</span></code>. You can choose not to use this\n\
+        functionality by simply not installing the <code><span class=\"pre\">vagrant-hostmanager</span></code>\
+        \ plugin, but\nif you want Pagure to provide valid URLs in the UI for git\
+        \ repositories, you\nwill need to adjust Pagure's configuration found in ~/pagure.cfg\
+        \ on the guest.</p>\n</div>\n</div>\n<div class=\"section\">\n<h2>Manually</h2>\n\
+        <ul>\n<li><p>Install the needed system libraries:</p>\n<pre>sudo dnf install\
+        \ git python2-virtualenv libgit2-devel \\\n                 libjpeg-devel\
+        \ gcc libffi-devel redhat-rpm-config\n</pre>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p>Do note the version of libgit2 that you install, for example\nin <code><span\
+        \ class=\"pre\">libgit2-0.23.4-1</span></code> you need to keep in mind the\
+        \ <code>0.23</code></p>\n</div>\n<div class=\"note\">\n<p>Note</p>\n<p>On\
+        \ Fedora 23 and earlier or on RHEL and derivative (CentOS,\nScientific Linux)\
+        \ the package <cite>python2-virtualenv</cite> is named\n<cite>python-virtualenv</cite></p>\n\
+        </div>\n</li>\n<li><p>Retrieve the sources:</p>\n<pre>git clone https://pagure.io/pagure.git\n\
+        cd pagure\n</pre>\n</li>\n<li><p>Install dependencies</p>\n<ul>\n<li><p>create\
+        \ the virtualenv:</p>\n<pre>virtualenv pagure_env\nsource ./pagure_env/bin/activate\n\
+        </pre>\n</li>\n<li><p>Install the correct version of pygit2:</p>\n<pre>pip\
+        \ install pygit2==&lt;version of libgit2 found&gt;.*\n</pre>\n<p>So in our\
+        \ example:</p>\n<pre>pip install pygit2==0.23.*\n</pre>\n</li>\n<li><p>Install\
+        \ the rest of the dependencies:</p>\n<pre>pip install -r requirements.txt\n\
+        </pre>\n</li>\n</ul>\n</li>\n<li><p>Create the folder that will receive the\
+        \ projects, forks, docs, requests and\ntickets' git repo:</p>\n<pre>mkdir\
+        \ -p lcl/{repos,docs,forks,tickets,requests,remotes,attachments,releases}\n\
+        </pre>\n</li>\n<li><p>Create the inital database scheme:</p>\n<pre>python\
+        \ createdb.py\n</pre>\n</li>\n<li><p>Start a worker, in one terminal:</p>\n\
+        <pre>./runworker.py\n</pre>\n</li>\n<li><p>Run the application, in another\
+        \ terminal:</p>\n<pre>./runserver.py\n</pre>\n</li>\n<li><p>To get some profiling\
+        \ information you can also run it as:</p>\n<pre>./runserver.py --profile\n\
+        </pre>\n</li>\n</ul>\n<p>This will launch the application at <a href=\"http://127.0.0.1:5000\"\
+        >http://127.0.0.1:5000</a></p>\n<ul>\n<li><p>To run unit-tests on pagure</p>\n\
+        <ul>\n<li><p>Install the dependencies:</p>\n<pre>pip install -r tests_requirements.txt\n\
+        </pre>\n</li>\n<li><p>Run it:</p>\n<pre>./runtests.sh\n</pre>\n<div class=\"\
+        note\">\n<p>Note</p>\n<p>While testing for worker tasks, pagure uses celery\
+        \ in /usr/bin/\nCelery then looks for eventlet (which we use for testing only)\
+        \ at\nsystem level and not in virtualenv. You will need to install eventlet\n\
+        outside of your virtualenv if you are using one.</p>\n</div>\n</li>\n</ul>\n\
+        </li>\n</ul>\n</div>\n</div>\n</div>\n\n            </section>\n        </div>\n\
+        \      <div class=\"col-md-4\">\n        <div class=\"card\">\n          <div\
+        \ class=\"card-block\">\n            <h5><strong>Contributors</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/pingou\">\n                  <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \               -  main admin\n              </div>\n                  <div>\n\
+        \                    <a href=\"/user/ryanlerch\">\n                      <img\
+        \ class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                      Ryan Lerch (ryanlerch)\n                    </a>\n\
+        \                    - admin\n                  </div>\n                 \
+        \ <div>\n                    <a href=\"/user/puiterwijk\">\n             \
+        \         <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/85f8b5f58b9808429ad69ba3722d64da01ce850635e348e838dfdc053e1140e3?s=20&d=retro\"\
+        />\n                      Patrick &#34;\u30DE\u30EB\u30BF\u30A4\u30F3\u30A2\
+        \u30F3\u30C9\u30EC\u30A2\u30B9&#34; Uiterwijk (puiterwijk)\n             \
+        \       </a>\n                    - commit\n                  </div>\n   \
+        \               <div>\n                    <a href=\"/user/vivekanand1101\"\
+        >\n                      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                      Vivek Anand (vivekanand1101)\n                 \
+        \   </a>\n                    - ticket\n                  </div>\n       \
+        \           <div>\n                    <a href=\"/user/farhaan\">\n      \
+        \                <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b681ddfaffa293b03c57e5f0ed90eb1e06a8f748f4dccdccef8cdd301c66c9ae?s=20&d=retro\"\
+        />\n                      Farhaan Bukhsh (farhaan)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/cverna\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/c7844b93c43c862adaa29920c09bdfb91efed57a843203e5d0b72673e664c003?s=20&d=retro\"\
+        />\n                      Clement Verna (cverna)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/jcline\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                      Jeremy Cline (jcline)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/lslebodn\">\n              \
+        \        <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/8c6fcfe0eec099f1f01f5c237935bb5c97f2063a5c1068e57c5815e0bfecbf70?s=20&d=retro\"\
+        />\n                      Lukas Slebodnik (lslebodn)\n                   \
+        \ </a>\n                    - ticket\n                  </div>\n         \
+        \         <div>\n                    <a href=\"/user/mprahl\">\n         \
+        \             <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/ecae5ad9b37619a38e699de00049e449f120b433c9f26a8beb05b990dfc54c9d?s=20&d=retro\"\
+        />\n                      Matt Prahl (mprahl)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n            </div>\n\
+        \            <h5><strong>Branches</strong></h5>\n            <div class=\"\
+        m-b-2\">\n              <div id=\"branch-master\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"\n          \
+        \          title=\"Default branch\"></span>\n                  <strong title=\"\
+        Currently viewing branch master\" data-toggle=\"tooltip\">master</strong>\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"star\"\n \
+        \                   title=\"Default branch\"></span>\n                </div>\n\
+        \              </div>\n\n              <div id=\"branch-2.9.x\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/2.9.x\"\n           \
+        \         title=\"2.9.x\" data-toggle=\"tooltip\">2.9.x\n                \
+        \  </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-alembic_changes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/alembic_changes\"\n        \
+        \            title=\"alembic_changes\" data-toggle=\"tooltip\">alembic_changes\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-confirm_merge\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/confirm_merge\"\n   \
+        \                 title=\"confirm_merge\" data-toggle=\"tooltip\">confirm_merge\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-css_tables\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/css_tables\"\n      \
+        \              title=\"css_tables\" data-toggle=\"tooltip\">css_tables\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_del_project\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_del_project\"\n \
+        \                   title=\"fix_del_project\" data-toggle=\"tooltip\">fix_del_project\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_delete\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_delete\"\n      \
+        \              title=\"fix_delete\" data-toggle=\"tooltip\">fix_delete\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_diff_refs\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_diff_refs\"\n   \
+        \                 title=\"fix_diff_refs\" data-toggle=\"tooltip\">fix_diff_refs\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_doc\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_doc\"\n                \
+        \    title=\"fix_doc\" data-toggle=\"tooltip\">fix_doc\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_linking\" class=\"repoinfo-branchlistitem row\">\n\
+        \                <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/fix_linking\"\n                   \
+        \ title=\"fix_linking\" data-toggle=\"tooltip\">fix_linking\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_pygit_error\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_pygit_error\"\n        \
+        \            title=\"fix_pygit_error\" data-toggle=\"tooltip\">fix_pygit_error\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_reply_to\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_reply_to\"\n    \
+        \                title=\"fix_reply_to\" data-toggle=\"tooltip\">fix_reply_to\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_sse\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse\"\n                \
+        \    title=\"fix_sse\" data-toggle=\"tooltip\">fix_sse\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_sse_status\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse_status\"\n         \
+        \           title=\"fix_sse_status\" data-toggle=\"tooltip\">fix_sse_status\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_templates\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_templates\"\n   \
+        \                 title=\"fix_templates\" data-toggle=\"tooltip\">fix_templates\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fixes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fixes\"\n                  \
+        \  title=\"fixes\" data-toggle=\"tooltip\">fixes\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-force_flag\" class=\"repoinfo-branchlistitem row\">\n             \
+        \   <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/force_flag\"\n                    title=\"force_flag\"\
+        \ data-toggle=\"tooltip\">force_flag\n                  </a>\n\n         \
+        \       </div>\n                <div class=\"branch_del col-md-4\">\n    \
+        \            </div>\n              </div>\n              <div id=\"branch-gpg_check\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/gpg_check\"\
+        \n                    title=\"gpg_check\" data-toggle=\"tooltip\">gpg_check\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-logging_milter\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/logging_milter\"\n  \
+        \                  title=\"logging_milter\" data-toggle=\"tooltip\">logging_milter\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-mirroring\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/mirroring\"\n              \
+        \      title=\"mirroring\" data-toggle=\"tooltip\">mirroring\n           \
+        \       </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-py3_work2\" class=\"repoinfo-branchlistitem row\">\n \
+        \               <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/py3_work2\"\n                    title=\"\
+        py3_work2\" data-toggle=\"tooltip\">py3_work2\n                  </a>\n\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-rel_2.2.z\" class=\"repoinfo-branchlistitem row\">\n              \
+        \  <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/rel_2.2.z\"\n                    title=\"rel_2.2.z\"\
+        \ data-toggle=\"tooltip\">rel_2.2.z\n                  </a>\n\n          \
+        \      </div>\n                <div class=\"branch_del col-md-4\">\n     \
+        \           </div>\n              </div>\n              <div id=\"branch-rel_2.3.z\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/rel_2.3.z\"\
+        \n                    title=\"rel_2.3.z\" data-toggle=\"tooltip\">rel_2.3.z\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-scroll_metadata\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/scroll_metadata\"\n \
+        \                   title=\"scroll_metadata\" data-toggle=\"tooltip\">scroll_metadata\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-utf_search\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/utf_search\"\n      \
+        \              title=\"utf_search\" data-toggle=\"tooltip\">utf_search\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \         </div>\n            <h5><strong>Source GIT URLs</strong>       \
+        \           <span class=\"pull-xs-right\"><a data-toggle=\"collapse\" href=\"\
+        #moregiturls\"\n                  aria-expanded=\"false\" aria-controls=\"\
+        moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n \
+        \           <div>\n              <div class=\"form-group\">\n            \
+        \    <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">GIT</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"https://pagure.io/pagure.git\" readonly>\n       \
+        \         </div>\n              </div>\n              <div class=\"collapse\"\
+        \ id=\"moregiturls\">\n                  <h5><strong>Docs GIT URLs</strong></h5>\n\
+        \                  <div class=\"form-group\">\n                    <div class=\"\
+        input-group input-group-sm\">\n                      <div class=\"input-group-addon\"\
+        >GIT</div>\n                      <input class=\"form-control\" type=\"text\"\
+        \ value=\"https://pagure.io/docs/pagure.git\" readonly>\n                \
+        \    </div>\n                  </div>\n              </div>\n            </div>\n\
+        \          </div>\n          <div class=\"repo_date\" title=\"2015-05-13 20:38:10.552662\"\
+        >\n              created 2 years ago\n          </div>\n        </div>\n\n\
+        \          <div class=\"card\">\n            <div class=\"card-header\">\n\
+        \              <strong>Recent Commits in\n                <span class=\"pr-toplabel\"\
+        >\n                  <span class=\"oi\" data-glyph=\"random\"></span>\n  \
+        \                master\n                </span>\n              </strong>\n\
+        \            </div>\n            <div class=\"card-block p-a-0\">\n      \
+        \        <div class=\"list-group list-group-flush\">\n                  <a\
+        \ href=\"/pagure/c/75b9021afbb08a3bdc1128cb282ea9c2394c0b67\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Sep 21 2017 08:20:29\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Add unit-tests for the fixes around loading issue template\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/pagure/c/fc1d7f885d8b658ce7ba2fbd9cf20692b32f7732\" class=\"\
+        list-group-item\">\n                    <div class=\"commitdate\" title=\"\
+        Sep 21 2017 08:20:29\">\n                      <small>\n                 \
+        \       <strong>\n                          <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Flake8 fix fixing the tests\n                    </small></div>\n\
+        \                  </a>\n                  <a href=\"/pagure/c/91c1f357adc77f0b21e15f6177c68ffc97f3ec67\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Sep 21 2017 08:20:29\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Adjust the documentation around ticket templates\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          3.7.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage/index.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/vendor/jquery/jquery.min.js\">\n    </script>\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/vendor/jquery-ui/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n        var currentWatchStatusButton\
+        \ = $('#unwatch_button');\n    currentWatchStatusButton.prepend('<span class=\"\
+        oi\" data-glyph=\"circle-check\" style=\"padding-right:0.5em\"></span>');\n\
+        \    $('.watch-menu a').not(currentWatchStatusButton).css('padding-left',\
+        \ '2.85em');\n\n    $(\".watch-menu a\").click(function(){\n        var selectedValue\
+        \ = $(this).attr('id');\n        var watchProjectForm = $(\"#watch_project\"\
+        );\n        var action = watchProjectForm.attr('action');\n\n        if (selectedValue\
+        \ === \"watch_issues_button\") {\n            action = action.replace('/settings/0',\
+        \ '/settings/1');\n        } else if (selectedValue === \"watch_commits_button\"\
+        ) {\n            action = action.replace('/settings/0', '/settings/2');\n\
+        \        } else if (selectedValue === \"watch_issues_commits_button\") {\n\
+        \            action = action.replace('/settings/0', '/settings/3');\n    \
+        \    } else if (selectedValue === \"reset_button\") {\n            action\
+        \ = action.replace('/settings/0', '/settings/-1');\n        }\n\n        watchProjectForm.attr('action',\
+        \ action);\n        watchProjectForm.submit();\n    });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      Connection: [Keep-Alive]
+      Content-Length: ['31652']
+      Content-Type: [text/html; charset=utf-8]
+      Date: ['Tue, 26 Sep 2017 15:29:34 GMT']
+      Keep-Alive: ['timeout=5, max=100']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      Set-Cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiTnpZelpqTmxZVGhoT1RJMk16aGlabVV4WkRnellUVXdPR00xWmpKbU9EVmtORGcyWVRZeE9BPT0ifX0.DKwD3g.EYEwG8LIbAU2xuYJw0UJyjisahM;
+          Expires=Fri, 27-Oct-2017 15:29:34 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_removed_widget b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_removed_widget
new file mode 100644
index 0000000..3cb4651
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_removed_widget
@@ -0,0 +1,450 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://pagure.io/pagure
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - pagure - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\"\
+        \n        href=\"/static/favicon.ico\"/>\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/vendor/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/vendor/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/pagure git https://pagure.io/pagure.git\">\n  </head>\n\
+        \  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"masthead\"\
+        >\n      <div class=\"container\">\n        <div class=\"row\">\n        \
+        \  <div class=\"col-sm-3\">\n            <a href=\"/\">\n              <img\
+        \ height=40px src=\"/static/pagure-logo.png\"\n                alt=\"pagure\
+        \ Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n       \
+        \   <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav class=\"\
+        navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\">\n    \
+        \    <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n         \
+        \     <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link btn\
+        \ btn-primary\" href=\"/login/?next=https://pagure.io/pagure\">Log In</a>\n\
+        \              </li>\n        </ul>\n      </div>\n    </nav>\n\n        \
+        \    </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n<a href=\"/pagure\">pagure</a>\n        </h2>\n\
+        \        <div class=\"projectinfo m-t-1 m-b-1\">\nA git centered forge &nbsp;|\
+        \ &nbsp;<a class=\"inline\" href=\"https://pagure.io\">https://pagure.io</a>\
+        \        </div>\n\n    </header>\n    <ul class=\"nav nav-tabs nav-small\"\
+        >\n      <li class=\"nav-item\">\n        <a class=\"nav-link active\" href=\"\
+        /pagure\">\n            <span class=\"oi hidden-md-up\" data-glyph=\"home\"\
+        ></span>\n            <span class=\"hidden-sm-down\">Overview</span>\n   \
+        \     </a>\n      </li>\n        <li class=\"nav-item\" >\n          <a  class=\"\
+        nav-link\" href=\"/docs/pagure/\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"book\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Docs</span>\n          </a>\n        </li>\n\n        <li class=\"nav-item\"\
+        >\n          <a class=\"nav-link\" href=\"/pagure/commits/master\">\n    \
+        \          <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n \
+        \             </span><span class=\"hidden-sm-down\">Commits</span>\n     \
+        \       </a>\n        </li>\n\n        <li class=\"nav-item\">\n         \
+        \ <a class=\"nav-link\" href=\"/pagure/tree/master\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/pagure/issues\">\n                <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n             \
+        \   <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n                <span\
+        \ class=\"label label-default label-pill hidden-sm-down\">\n             \
+        \     340\n                </span>\n            </a>\n        </li>\n\n  \
+        \      <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"/pagure/pull-requests\"\
+        >\n              <span class=\"oi hidden-md-up\" data-glyph=\"task\"></span>\n\
+        \              <span class=\"hidden-sm-down\">Pull Requests&nbsp;</span>\n\
+        \              <span class=\"label label-default label-pill hidden-sm-down\"\
+        >\n                15\n              </span>\n          </a>\n        </li>\n\
+        \n        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/forks\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        fork\"></span>\n              <span class=\"hidden-sm-down\">Forks&nbsp;</span>\n\
+        \              <span class=\"hidden-sm-down label label-default label-pill\"\
+        >\n                131\n              </span>\n            </a>\n        </li>\n\
+        \n\n    </ul>\n  </div>\n</div>\n\n<div class=\"container p-t-3\">\n  <div\
+        \ class=\"row\">\n        <div class=\"col-md-8\">\n            <section class=\"\
+        readme\">\n              <div class=\"document\">\n<div class=\"section\"\
+        >\n<h1>Pagure</h1>\n<table class=\"docutils field-list\">\n<colgroup><col>\n\
+        <col>\n</colgroup><tbody>\n<tr><th>Author:</th><td>Pierre-Yves Chibon &lt;<a\
+        \ href=\"mailto:pingou@pingoured.fr\">pingou@pingoured.fr</a>&gt;</td>\n</tr>\n\
+        </tbody>\n</table>\n<p>Pagure is a git-centered forge, python based using\
+        \ pygit2.</p>\n<p>With pagure you can host your project with its documentation,\
+        \ let your users\nreport issues or request enhancements using the ticketing\
+        \ system and build your\ncommunity of contributors by allowing them to fork\
+        \ your projects and contribute\nto it via the now-popular pull-request mechanism.</p>\n\
+        <p>Homepage: <a href=\"https://pagure.io/pagure\">https://pagure.io/pagure</a></p>\n\
+        <p>See it at work: <a href=\"https://pagure.io\">https://pagure.io</a></p>\n\
+        <p>Playground version: <a href=\"https://stg.pagure.io\">https://stg.pagure.io</a></p>\n\
+        </div>\n<div class=\"section\">\n<h1>Get it running</h1>\n<p>There are several\
+        \ options when it comes to a development environment. Vagrant\nwill provide\
+        \ you with a virtual machine which you can develop on, or you can\ninstall\
+        \ it directly on your host machine.</p>\n<div class=\"section\">\n<h2>Vagrant</h2>\n\
+        <p>For a more thorough introduction to Vagrant, see\n<a href=\"https://fedoraproject.org/wiki/Vagrant\"\
+        >https://fedoraproject.org/wiki/Vagrant</a>.</p>\n<p>An example Vagrantfile\
+        \ is provided as <code>Vagrantfile.example</code>. To use it,\njust copy it\
+        \ and install Vagrant:</p>\n<pre>$ cp dev/Vagrantfile.example Vagrantfile\n\
+        $ sudo dnf install ansible libvirt vagrant-libvirt vagrant-sshfs vagrant-hostmanager\n\
+        $ vagrant up\n</pre>\n<p>The default <code>Vagrantfile</code> forwards ports\
+        \ from the host to the guest,\nso you can interact with the application as\
+        \ if it were running on your\nhost machine.</p>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p><code><span class=\"pre\">vagrant-hostmanager</span></code> will automatically\
+        \ maintain /etc/hosts for you so you\ncan access the development environment\
+        \ from the host using its hostname, which\nby default is <code><span class=\"\
+        pre\">pagure-dev.example.com</span></code>. You can choose not to use this\n\
+        functionality by simply not installing the <code><span class=\"pre\">vagrant-hostmanager</span></code>\
+        \ plugin, but\nif you want Pagure to provide valid URLs in the UI for git\
+        \ repositories, you\nwill need to adjust Pagure's configuration found in ~/pagure.cfg\
+        \ on the guest.</p>\n</div>\n</div>\n<div class=\"section\">\n<h2>Manually</h2>\n\
+        <ul>\n<li><p>Install the needed system libraries:</p>\n<pre>sudo dnf install\
+        \ git python2-virtualenv libgit2-devel \\\n                 libjpeg-devel\
+        \ gcc libffi-devel redhat-rpm-config\n</pre>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p>Do note the version of libgit2 that you install, for example\nin <code><span\
+        \ class=\"pre\">libgit2-0.23.4-1</span></code> you need to keep in mind the\
+        \ <code>0.23</code></p>\n</div>\n<div class=\"note\">\n<p>Note</p>\n<p>On\
+        \ Fedora 23 and earlier or on RHEL and derivative (CentOS,\nScientific Linux)\
+        \ the package <cite>python2-virtualenv</cite> is named\n<cite>python-virtualenv</cite></p>\n\
+        </div>\n</li>\n<li><p>Retrieve the sources:</p>\n<pre>git clone https://pagure.io/pagure.git\n\
+        cd pagure\n</pre>\n</li>\n<li><p>Install dependencies</p>\n<ul>\n<li><p>create\
+        \ the virtualenv:</p>\n<pre>virtualenv pagure_env\nsource ./pagure_env/bin/activate\n\
+        </pre>\n</li>\n<li><p>Install the correct version of pygit2:</p>\n<pre>pip\
+        \ install pygit2==&lt;version of libgit2 found&gt;.*\n</pre>\n<p>So in our\
+        \ example:</p>\n<pre>pip install pygit2==0.23.*\n</pre>\n</li>\n<li><p>Install\
+        \ the rest of the dependencies:</p>\n<pre>pip install -r requirements.txt\n\
+        </pre>\n</li>\n</ul>\n</li>\n<li><p>Create the folder that will receive the\
+        \ projects, forks, docs, requests and\ntickets' git repo:</p>\n<pre>mkdir\
+        \ -p lcl/{repos,docs,forks,tickets,requests,remotes,attachments,releases}\n\
+        </pre>\n</li>\n<li><p>Create the inital database scheme:</p>\n<pre>python\
+        \ createdb.py\n</pre>\n</li>\n<li><p>Start a worker, in one terminal:</p>\n\
+        <pre>./runworker.py\n</pre>\n</li>\n<li><p>Run the application, in another\
+        \ terminal:</p>\n<pre>./runserver.py\n</pre>\n</li>\n<li><p>To get some profiling\
+        \ information you can also run it as:</p>\n<pre>./runserver.py --profile\n\
+        </pre>\n</li>\n</ul>\n<p>This will launch the application at <a href=\"http://127.0.0.1:5000\"\
+        >http://127.0.0.1:5000</a></p>\n<ul>\n<li><p>To run unit-tests on pagure</p>\n\
+        <ul>\n<li><p>Install the dependencies:</p>\n<pre>pip install -r tests_requirements.txt\n\
+        </pre>\n</li>\n<li><p>Run it:</p>\n<pre>./runtests.sh\n</pre>\n<div class=\"\
+        note\">\n<p>Note</p>\n<p>While testing for worker tasks, pagure uses celery\
+        \ in /usr/bin/\nCelery then looks for eventlet (which we use for testing only)\
+        \ at\nsystem level and not in virtualenv. You will need to install eventlet\n\
+        outside of your virtualenv if you are using one.</p>\n</div>\n</li>\n</ul>\n\
+        </li>\n</ul>\n</div>\n</div>\n</div>\n\n            </section>\n        </div>\n\
+        \      <div class=\"col-md-4\">\n        <div class=\"card\">\n          <div\
+        \ class=\"card-block\">\n            <h5><strong>Contributors</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/pingou\">\n                  <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \               -  main admin\n              </div>\n                  <div>\n\
+        \                    <a href=\"/user/ryanlerch\">\n                      <img\
+        \ class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                      Ryan Lerch (ryanlerch)\n                    </a>\n\
+        \                    - admin\n                  </div>\n                 \
+        \ <div>\n                    <a href=\"/user/puiterwijk\">\n             \
+        \         <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/85f8b5f58b9808429ad69ba3722d64da01ce850635e348e838dfdc053e1140e3?s=20&d=retro\"\
+        />\n                      Patrick &#34;\u30DE\u30EB\u30BF\u30A4\u30F3\u30A2\
+        \u30F3\u30C9\u30EC\u30A2\u30B9&#34; Uiterwijk (puiterwijk)\n             \
+        \       </a>\n                    - commit\n                  </div>\n   \
+        \               <div>\n                    <a href=\"/user/vivekanand1101\"\
+        >\n                      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                      Vivek Anand (vivekanand1101)\n                 \
+        \   </a>\n                    - ticket\n                  </div>\n       \
+        \           <div>\n                    <a href=\"/user/farhaan\">\n      \
+        \                <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b681ddfaffa293b03c57e5f0ed90eb1e06a8f748f4dccdccef8cdd301c66c9ae?s=20&d=retro\"\
+        />\n                      Farhaan Bukhsh (farhaan)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/cverna\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/c7844b93c43c862adaa29920c09bdfb91efed57a843203e5d0b72673e664c003?s=20&d=retro\"\
+        />\n                      Clement Verna (cverna)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/jcline\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                      Jeremy Cline (jcline)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/lslebodn\">\n              \
+        \        <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/8c6fcfe0eec099f1f01f5c237935bb5c97f2063a5c1068e57c5815e0bfecbf70?s=20&d=retro\"\
+        />\n                      Lukas Slebodnik (lslebodn)\n                   \
+        \ </a>\n                    - ticket\n                  </div>\n         \
+        \         <div>\n                    <a href=\"/user/mprahl\">\n         \
+        \             <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/ecae5ad9b37619a38e699de00049e449f120b433c9f26a8beb05b990dfc54c9d?s=20&d=retro\"\
+        />\n                      Matt Prahl (mprahl)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n            </div>\n\
+        \            <h5><strong>Branches</strong></h5>\n            <div class=\"\
+        m-b-2\">\n              <div id=\"branch-master\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"\n          \
+        \          title=\"Default branch\"></span>\n                  <strong title=\"\
+        Currently viewing branch master\" data-toggle=\"tooltip\">master</strong>\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"star\"\n \
+        \                   title=\"Default branch\"></span>\n                </div>\n\
+        \              </div>\n\n              <div id=\"branch-2.9.x\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/2.9.x\"\n           \
+        \         title=\"2.9.x\" data-toggle=\"tooltip\">2.9.x\n                \
+        \  </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-alembic_changes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/alembic_changes\"\n        \
+        \            title=\"alembic_changes\" data-toggle=\"tooltip\">alembic_changes\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-confirm_merge\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/confirm_merge\"\n   \
+        \                 title=\"confirm_merge\" data-toggle=\"tooltip\">confirm_merge\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-css_tables\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/css_tables\"\n      \
+        \              title=\"css_tables\" data-toggle=\"tooltip\">css_tables\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_del_project\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_del_project\"\n \
+        \                   title=\"fix_del_project\" data-toggle=\"tooltip\">fix_del_project\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_delete\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_delete\"\n      \
+        \              title=\"fix_delete\" data-toggle=\"tooltip\">fix_delete\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_diff_refs\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_diff_refs\"\n   \
+        \                 title=\"fix_diff_refs\" data-toggle=\"tooltip\">fix_diff_refs\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_doc\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_doc\"\n                \
+        \    title=\"fix_doc\" data-toggle=\"tooltip\">fix_doc\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_linking\" class=\"repoinfo-branchlistitem row\">\n\
+        \                <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/fix_linking\"\n                   \
+        \ title=\"fix_linking\" data-toggle=\"tooltip\">fix_linking\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_pygit_error\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_pygit_error\"\n        \
+        \            title=\"fix_pygit_error\" data-toggle=\"tooltip\">fix_pygit_error\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_reply_to\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_reply_to\"\n    \
+        \                title=\"fix_reply_to\" data-toggle=\"tooltip\">fix_reply_to\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_sse\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse\"\n                \
+        \    title=\"fix_sse\" data-toggle=\"tooltip\">fix_sse\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_sse_status\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse_status\"\n         \
+        \           title=\"fix_sse_status\" data-toggle=\"tooltip\">fix_sse_status\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_templates\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_templates\"\n   \
+        \                 title=\"fix_templates\" data-toggle=\"tooltip\">fix_templates\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fixes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fixes\"\n                  \
+        \  title=\"fixes\" data-toggle=\"tooltip\">fixes\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-force_flag\" class=\"repoinfo-branchlistitem row\">\n             \
+        \   <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/force_flag\"\n                    title=\"force_flag\"\
+        \ data-toggle=\"tooltip\">force_flag\n                  </a>\n\n         \
+        \       </div>\n                <div class=\"branch_del col-md-4\">\n    \
+        \            </div>\n              </div>\n              <div id=\"branch-gpg_check\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/gpg_check\"\
+        \n                    title=\"gpg_check\" data-toggle=\"tooltip\">gpg_check\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-logging_milter\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/logging_milter\"\n  \
+        \                  title=\"logging_milter\" data-toggle=\"tooltip\">logging_milter\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-mirroring\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/mirroring\"\n              \
+        \      title=\"mirroring\" data-toggle=\"tooltip\">mirroring\n           \
+        \       </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-py3_work2\" class=\"repoinfo-branchlistitem row\">\n \
+        \               <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/py3_work2\"\n                    title=\"\
+        py3_work2\" data-toggle=\"tooltip\">py3_work2\n                  </a>\n\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-rel_2.2.z\" class=\"repoinfo-branchlistitem row\">\n              \
+        \  <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/rel_2.2.z\"\n                    title=\"rel_2.2.z\"\
+        \ data-toggle=\"tooltip\">rel_2.2.z\n                  </a>\n\n          \
+        \      </div>\n                <div class=\"branch_del col-md-4\">\n     \
+        \           </div>\n              </div>\n              <div id=\"branch-rel_2.3.z\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/rel_2.3.z\"\
+        \n                    title=\"rel_2.3.z\" data-toggle=\"tooltip\">rel_2.3.z\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-scroll_metadata\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/scroll_metadata\"\n \
+        \                   title=\"scroll_metadata\" data-toggle=\"tooltip\">scroll_metadata\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-utf_search\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/utf_search\"\n      \
+        \              title=\"utf_search\" data-toggle=\"tooltip\">utf_search\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \         </div>\n            <h5><strong>Source GIT URLs</strong>       \
+        \           <span class=\"pull-xs-right\"><a data-toggle=\"collapse\" href=\"\
+        #moregiturls\"\n                  aria-expanded=\"false\" aria-controls=\"\
+        moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n \
+        \           <div>\n              <div class=\"form-group\">\n            \
+        \    <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">GIT</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"https://pagure.io/pagure.git\" readonly>\n       \
+        \         </div>\n              </div>\n              <div class=\"collapse\"\
+        \ id=\"moregiturls\">\n                  <h5><strong>Docs GIT URLs</strong></h5>\n\
+        \                  <div class=\"form-group\">\n                    <div class=\"\
+        input-group input-group-sm\">\n                      <div class=\"input-group-addon\"\
+        >GIT</div>\n                      <input class=\"form-control\" type=\"text\"\
+        \ value=\"https://pagure.io/docs/pagure.git\" readonly>\n                \
+        \    </div>\n                  </div>\n              </div>\n            </div>\n\
+        \          </div>\n          <div class=\"repo_date\" title=\"2015-05-13 20:38:10.552662\"\
+        >\n              created 2 years ago\n          </div>\n        </div>\n\n\
+        \          <div class=\"card\">\n            <div class=\"card-header\">\n\
+        \              <strong>Recent Commits in\n                <span class=\"pr-toplabel\"\
+        >\n                  <span class=\"oi\" data-glyph=\"random\"></span>\n  \
+        \                master\n                </span>\n              </strong>\n\
+        \            </div>\n            <div class=\"card-block p-a-0\">\n      \
+        \        <div class=\"list-group list-group-flush\">\n                  <a\
+        \ href=\"/pagure/c/a324b4120738bb9765b59625f3e767f9b50d599f\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Sep 25 2017 12:50:46\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 2 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Fix the unit-tests\n                    </small></div>\n\
+        \                  </a>\n                  <a href=\"/pagure/c/ef569a5160891b30cc2aa4d614b39f4a266d7ad7\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Sep 21 2017 12:15:51\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                          Vivek Anand\n                        </strong>\n\
+        \                        commited 5 days ago\n                      </small>\n\
+        \                    </div>\n                    <div><small>\n          \
+        \            give project: generate gitolite acls after giving a project\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/pagure/c/16c5781815d4695fe89db3c5cec5191dc1b81c6f\" class=\"\
+        list-group-item\">\n                    <div class=\"commitdate\" title=\"\
+        Sep 21 2017 10:26:39\">\n                      <small>\n                 \
+        \       <strong>\n                          <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                          Vivek Anand\n                        </strong>\n\
+        \                        commited 6 days ago\n                      </small>\n\
+        \                    </div>\n                    <div><small>\n          \
+        \            read only repo: Add unit test for update_read_only_mode method\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          3.7.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage/index.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/vendor/jquery/jquery.min.js\">\n    </script>\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/vendor/jquery-ui/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n        var currentWatchStatusButton\
+        \ = $('#unwatch_button');\n    currentWatchStatusButton.prepend('<span class=\"\
+        oi\" data-glyph=\"circle-check\" style=\"padding-right:0.5em\"></span>');\n\
+        \    $('.watch-menu a').not(currentWatchStatusButton).css('padding-left',\
+        \ '2.85em');\n\n    $(\".watch-menu a\").click(function(){\n        var selectedValue\
+        \ = $(this).attr('id');\n        var watchProjectForm = $(\"#watch_project\"\
+        );\n        var action = watchProjectForm.attr('action');\n\n        if (selectedValue\
+        \ === \"watch_issues_button\") {\n            action = action.replace('/settings/0',\
+        \ '/settings/1');\n        } else if (selectedValue === \"watch_commits_button\"\
+        ) {\n            action = action.replace('/settings/0', '/settings/2');\n\
+        \        } else if (selectedValue === \"watch_issues_commits_button\") {\n\
+        \            action = action.replace('/settings/0', '/settings/3');\n    \
+        \    } else if (selectedValue === \"reset_button\") {\n            action\
+        \ = action.replace('/settings/0', '/settings/-1');\n        }\n\n        watchProjectForm.attr('action',\
+        \ action);\n        watchProjectForm.submit();\n    });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      Connection: [Keep-Alive]
+      Content-Length: ['31644']
+      Content-Type: [text/html; charset=utf-8]
+      Date: ['Wed, 27 Sep 2017 12:13:40 GMT']
+      Keep-Alive: ['timeout=5, max=100']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      Set-Cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiTkdKbVlUZGhZVFU1TmpNeE4yUTVZMkk0WkdFNFpUWm1aVGcyT0RZNVpERTBaRFEyTURnMVlRPT0ifX0.DK0ndA.2Ge7Vf_BJoy4ILHFnc5mQsTH6QQ;
+          Expires=Sat, 28-Oct-2017 12:13:40 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets
new file mode 100644
index 0000000..3c51168
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets
@@ -0,0 +1,450 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://pagure.io/pagure
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - pagure - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\"\
+        \n        href=\"/static/favicon.ico\"/>\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/vendor/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/vendor/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/pagure git https://pagure.io/pagure.git\">\n  </head>\n\
+        \  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"masthead\"\
+        >\n      <div class=\"container\">\n        <div class=\"row\">\n        \
+        \  <div class=\"col-sm-3\">\n            <a href=\"/\">\n              <img\
+        \ height=40px src=\"/static/pagure-logo.png\"\n                alt=\"pagure\
+        \ Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n       \
+        \   <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav class=\"\
+        navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\">\n    \
+        \    <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n         \
+        \     <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link btn\
+        \ btn-primary\" href=\"/login/?next=https://pagure.io/pagure\">Log In</a>\n\
+        \              </li>\n        </ul>\n      </div>\n    </nav>\n\n        \
+        \    </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n<a href=\"/pagure\">pagure</a>\n        </h2>\n\
+        \        <div class=\"projectinfo m-t-1 m-b-1\">\nA git centered forge &nbsp;|\
+        \ &nbsp;<a class=\"inline\" href=\"https://pagure.io\">https://pagure.io</a>\
+        \        </div>\n\n    </header>\n    <ul class=\"nav nav-tabs nav-small\"\
+        >\n      <li class=\"nav-item\">\n        <a class=\"nav-link active\" href=\"\
+        /pagure\">\n            <span class=\"oi hidden-md-up\" data-glyph=\"home\"\
+        ></span>\n            <span class=\"hidden-sm-down\">Overview</span>\n   \
+        \     </a>\n      </li>\n        <li class=\"nav-item\" >\n          <a  class=\"\
+        nav-link\" href=\"/docs/pagure/\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"book\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Docs</span>\n          </a>\n        </li>\n\n        <li class=\"nav-item\"\
+        >\n          <a class=\"nav-link\" href=\"/pagure/commits/master\">\n    \
+        \          <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n \
+        \             </span><span class=\"hidden-sm-down\">Commits</span>\n     \
+        \       </a>\n        </li>\n\n        <li class=\"nav-item\">\n         \
+        \ <a class=\"nav-link\" href=\"/pagure/tree/master\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/pagure/issues\">\n                <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n             \
+        \   <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n                <span\
+        \ class=\"label label-default label-pill hidden-sm-down\">\n             \
+        \     339\n                </span>\n            </a>\n        </li>\n\n  \
+        \      <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"/pagure/pull-requests\"\
+        >\n              <span class=\"oi hidden-md-up\" data-glyph=\"task\"></span>\n\
+        \              <span class=\"hidden-sm-down\">Pull Requests&nbsp;</span>\n\
+        \              <span class=\"label label-default label-pill hidden-sm-down\"\
+        >\n                16\n              </span>\n          </a>\n        </li>\n\
+        \n        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/forks\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        fork\"></span>\n              <span class=\"hidden-sm-down\">Forks&nbsp;</span>\n\
+        \              <span class=\"hidden-sm-down label label-default label-pill\"\
+        >\n                131\n              </span>\n            </a>\n        </li>\n\
+        \n\n    </ul>\n  </div>\n</div>\n\n<div class=\"container p-t-3\">\n  <div\
+        \ class=\"row\">\n        <div class=\"col-md-8\">\n            <section class=\"\
+        readme\">\n              <div class=\"document\">\n<div class=\"section\"\
+        >\n<h1>Pagure</h1>\n<table class=\"docutils field-list\">\n<colgroup><col>\n\
+        <col>\n</colgroup><tbody>\n<tr><th>Author:</th><td>Pierre-Yves Chibon &lt;<a\
+        \ href=\"mailto:pingou@pingoured.fr\">pingou@pingoured.fr</a>&gt;</td>\n</tr>\n\
+        </tbody>\n</table>\n<p>Pagure is a git-centered forge, python based using\
+        \ pygit2.</p>\n<p>With pagure you can host your project with its documentation,\
+        \ let your users\nreport issues or request enhancements using the ticketing\
+        \ system and build your\ncommunity of contributors by allowing them to fork\
+        \ your projects and contribute\nto it via the now-popular pull-request mechanism.</p>\n\
+        <p>Homepage: <a href=\"https://pagure.io/pagure\">https://pagure.io/pagure</a></p>\n\
+        <p>See it at work: <a href=\"https://pagure.io\">https://pagure.io</a></p>\n\
+        <p>Playground version: <a href=\"https://stg.pagure.io\">https://stg.pagure.io</a></p>\n\
+        </div>\n<div class=\"section\">\n<h1>Get it running</h1>\n<p>There are several\
+        \ options when it comes to a development environment. Vagrant\nwill provide\
+        \ you with a virtual machine which you can develop on, or you can\ninstall\
+        \ it directly on your host machine.</p>\n<div class=\"section\">\n<h2>Vagrant</h2>\n\
+        <p>For a more thorough introduction to Vagrant, see\n<a href=\"https://fedoraproject.org/wiki/Vagrant\"\
+        >https://fedoraproject.org/wiki/Vagrant</a>.</p>\n<p>An example Vagrantfile\
+        \ is provided as <code>Vagrantfile.example</code>. To use it,\njust copy it\
+        \ and install Vagrant:</p>\n<pre>$ cp dev/Vagrantfile.example Vagrantfile\n\
+        $ sudo dnf install ansible libvirt vagrant-libvirt vagrant-sshfs vagrant-hostmanager\n\
+        $ vagrant up\n</pre>\n<p>The default <code>Vagrantfile</code> forwards ports\
+        \ from the host to the guest,\nso you can interact with the application as\
+        \ if it were running on your\nhost machine.</p>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p><code><span class=\"pre\">vagrant-hostmanager</span></code> will automatically\
+        \ maintain /etc/hosts for you so you\ncan access the development environment\
+        \ from the host using its hostname, which\nby default is <code><span class=\"\
+        pre\">pagure-dev.example.com</span></code>. You can choose not to use this\n\
+        functionality by simply not installing the <code><span class=\"pre\">vagrant-hostmanager</span></code>\
+        \ plugin, but\nif you want Pagure to provide valid URLs in the UI for git\
+        \ repositories, you\nwill need to adjust Pagure's configuration found in ~/pagure.cfg\
+        \ on the guest.</p>\n</div>\n</div>\n<div class=\"section\">\n<h2>Manually</h2>\n\
+        <ul>\n<li><p>Install the needed system libraries:</p>\n<pre>sudo dnf install\
+        \ git python2-virtualenv libgit2-devel \\\n                 libjpeg-devel\
+        \ gcc libffi-devel redhat-rpm-config\n</pre>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p>Do note the version of libgit2 that you install, for example\nin <code><span\
+        \ class=\"pre\">libgit2-0.23.4-1</span></code> you need to keep in mind the\
+        \ <code>0.23</code></p>\n</div>\n<div class=\"note\">\n<p>Note</p>\n<p>On\
+        \ Fedora 23 and earlier or on RHEL and derivative (CentOS,\nScientific Linux)\
+        \ the package <cite>python2-virtualenv</cite> is named\n<cite>python-virtualenv</cite></p>\n\
+        </div>\n</li>\n<li><p>Retrieve the sources:</p>\n<pre>git clone https://pagure.io/pagure.git\n\
+        cd pagure\n</pre>\n</li>\n<li><p>Install dependencies</p>\n<ul>\n<li><p>create\
+        \ the virtualenv:</p>\n<pre>virtualenv pagure_env\nsource ./pagure_env/bin/activate\n\
+        </pre>\n</li>\n<li><p>Install the correct version of pygit2:</p>\n<pre>pip\
+        \ install pygit2==&lt;version of libgit2 found&gt;.*\n</pre>\n<p>So in our\
+        \ example:</p>\n<pre>pip install pygit2==0.23.*\n</pre>\n</li>\n<li><p>Install\
+        \ the rest of the dependencies:</p>\n<pre>pip install -r requirements.txt\n\
+        </pre>\n</li>\n</ul>\n</li>\n<li><p>Create the folder that will receive the\
+        \ projects, forks, docs, requests and\ntickets' git repo:</p>\n<pre>mkdir\
+        \ -p lcl/{repos,docs,forks,tickets,requests,remotes,attachments,releases}\n\
+        </pre>\n</li>\n<li><p>Create the inital database scheme:</p>\n<pre>python\
+        \ createdb.py\n</pre>\n</li>\n<li><p>Start a worker, in one terminal:</p>\n\
+        <pre>./runworker.py\n</pre>\n</li>\n<li><p>Run the application, in another\
+        \ terminal:</p>\n<pre>./runserver.py\n</pre>\n</li>\n<li><p>To get some profiling\
+        \ information you can also run it as:</p>\n<pre>./runserver.py --profile\n\
+        </pre>\n</li>\n</ul>\n<p>This will launch the application at <a href=\"http://127.0.0.1:5000\"\
+        >http://127.0.0.1:5000</a></p>\n<ul>\n<li><p>To run unit-tests on pagure</p>\n\
+        <ul>\n<li><p>Install the dependencies:</p>\n<pre>pip install -r tests_requirements.txt\n\
+        </pre>\n</li>\n<li><p>Run it:</p>\n<pre>./runtests.sh\n</pre>\n<div class=\"\
+        note\">\n<p>Note</p>\n<p>While testing for worker tasks, pagure uses celery\
+        \ in /usr/bin/\nCelery then looks for eventlet (which we use for testing only)\
+        \ at\nsystem level and not in virtualenv. You will need to install eventlet\n\
+        outside of your virtualenv if you are using one.</p>\n</div>\n</li>\n</ul>\n\
+        </li>\n</ul>\n</div>\n</div>\n</div>\n\n            </section>\n        </div>\n\
+        \      <div class=\"col-md-4\">\n        <div class=\"card\">\n          <div\
+        \ class=\"card-block\">\n            <h5><strong>Contributors</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/pingou\">\n                  <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \               -  main admin\n              </div>\n                  <div>\n\
+        \                    <a href=\"/user/ryanlerch\">\n                      <img\
+        \ class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                      Ryan Lerch (ryanlerch)\n                    </a>\n\
+        \                    - admin\n                  </div>\n                 \
+        \ <div>\n                    <a href=\"/user/puiterwijk\">\n             \
+        \         <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/85f8b5f58b9808429ad69ba3722d64da01ce850635e348e838dfdc053e1140e3?s=20&d=retro\"\
+        />\n                      Patrick &#34;\u30DE\u30EB\u30BF\u30A4\u30F3\u30A2\
+        \u30F3\u30C9\u30EC\u30A2\u30B9&#34; Uiterwijk (puiterwijk)\n             \
+        \       </a>\n                    - commit\n                  </div>\n   \
+        \               <div>\n                    <a href=\"/user/vivekanand1101\"\
+        >\n                      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                      Vivek Anand (vivekanand1101)\n                 \
+        \   </a>\n                    - ticket\n                  </div>\n       \
+        \           <div>\n                    <a href=\"/user/farhaan\">\n      \
+        \                <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b681ddfaffa293b03c57e5f0ed90eb1e06a8f748f4dccdccef8cdd301c66c9ae?s=20&d=retro\"\
+        />\n                      Farhaan Bukhsh (farhaan)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/cverna\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/c7844b93c43c862adaa29920c09bdfb91efed57a843203e5d0b72673e664c003?s=20&d=retro\"\
+        />\n                      Clement Verna (cverna)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/jcline\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                      Jeremy Cline (jcline)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/lslebodn\">\n              \
+        \        <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/8c6fcfe0eec099f1f01f5c237935bb5c97f2063a5c1068e57c5815e0bfecbf70?s=20&d=retro\"\
+        />\n                      Lukas Slebodnik (lslebodn)\n                   \
+        \ </a>\n                    - ticket\n                  </div>\n         \
+        \         <div>\n                    <a href=\"/user/mprahl\">\n         \
+        \             <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/ecae5ad9b37619a38e699de00049e449f120b433c9f26a8beb05b990dfc54c9d?s=20&d=retro\"\
+        />\n                      Matt Prahl (mprahl)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n            </div>\n\
+        \            <h5><strong>Branches</strong></h5>\n            <div class=\"\
+        m-b-2\">\n              <div id=\"branch-master\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"\n          \
+        \          title=\"Default branch\"></span>\n                  <strong title=\"\
+        Currently viewing branch master\" data-toggle=\"tooltip\">master</strong>\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"star\"\n \
+        \                   title=\"Default branch\"></span>\n                </div>\n\
+        \              </div>\n\n              <div id=\"branch-2.9.x\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/2.9.x\"\n           \
+        \         title=\"2.9.x\" data-toggle=\"tooltip\">2.9.x\n                \
+        \  </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-alembic_changes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/alembic_changes\"\n        \
+        \            title=\"alembic_changes\" data-toggle=\"tooltip\">alembic_changes\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-confirm_merge\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/confirm_merge\"\n   \
+        \                 title=\"confirm_merge\" data-toggle=\"tooltip\">confirm_merge\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-css_tables\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/css_tables\"\n      \
+        \              title=\"css_tables\" data-toggle=\"tooltip\">css_tables\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_del_project\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_del_project\"\n \
+        \                   title=\"fix_del_project\" data-toggle=\"tooltip\">fix_del_project\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_delete\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_delete\"\n      \
+        \              title=\"fix_delete\" data-toggle=\"tooltip\">fix_delete\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_diff_refs\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_diff_refs\"\n   \
+        \                 title=\"fix_diff_refs\" data-toggle=\"tooltip\">fix_diff_refs\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_doc\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_doc\"\n                \
+        \    title=\"fix_doc\" data-toggle=\"tooltip\">fix_doc\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_linking\" class=\"repoinfo-branchlistitem row\">\n\
+        \                <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/fix_linking\"\n                   \
+        \ title=\"fix_linking\" data-toggle=\"tooltip\">fix_linking\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_pygit_error\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_pygit_error\"\n        \
+        \            title=\"fix_pygit_error\" data-toggle=\"tooltip\">fix_pygit_error\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_reply_to\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_reply_to\"\n    \
+        \                title=\"fix_reply_to\" data-toggle=\"tooltip\">fix_reply_to\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_sse\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse\"\n                \
+        \    title=\"fix_sse\" data-toggle=\"tooltip\">fix_sse\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_sse_status\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse_status\"\n         \
+        \           title=\"fix_sse_status\" data-toggle=\"tooltip\">fix_sse_status\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_templates\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_templates\"\n   \
+        \                 title=\"fix_templates\" data-toggle=\"tooltip\">fix_templates\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fixes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fixes\"\n                  \
+        \  title=\"fixes\" data-toggle=\"tooltip\">fixes\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-force_flag\" class=\"repoinfo-branchlistitem row\">\n             \
+        \   <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/force_flag\"\n                    title=\"force_flag\"\
+        \ data-toggle=\"tooltip\">force_flag\n                  </a>\n\n         \
+        \       </div>\n                <div class=\"branch_del col-md-4\">\n    \
+        \            </div>\n              </div>\n              <div id=\"branch-gpg_check\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/gpg_check\"\
+        \n                    title=\"gpg_check\" data-toggle=\"tooltip\">gpg_check\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-logging_milter\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/logging_milter\"\n  \
+        \                  title=\"logging_milter\" data-toggle=\"tooltip\">logging_milter\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-mirroring\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/mirroring\"\n              \
+        \      title=\"mirroring\" data-toggle=\"tooltip\">mirroring\n           \
+        \       </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-py3_work2\" class=\"repoinfo-branchlistitem row\">\n \
+        \               <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/py3_work2\"\n                    title=\"\
+        py3_work2\" data-toggle=\"tooltip\">py3_work2\n                  </a>\n\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-rel_2.2.z\" class=\"repoinfo-branchlistitem row\">\n              \
+        \  <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/rel_2.2.z\"\n                    title=\"rel_2.2.z\"\
+        \ data-toggle=\"tooltip\">rel_2.2.z\n                  </a>\n\n          \
+        \      </div>\n                <div class=\"branch_del col-md-4\">\n     \
+        \           </div>\n              </div>\n              <div id=\"branch-rel_2.3.z\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/rel_2.3.z\"\
+        \n                    title=\"rel_2.3.z\" data-toggle=\"tooltip\">rel_2.3.z\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-scroll_metadata\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/scroll_metadata\"\n \
+        \                   title=\"scroll_metadata\" data-toggle=\"tooltip\">scroll_metadata\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-utf_search\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/utf_search\"\n      \
+        \              title=\"utf_search\" data-toggle=\"tooltip\">utf_search\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \         </div>\n            <h5><strong>Source GIT URLs</strong>       \
+        \           <span class=\"pull-xs-right\"><a data-toggle=\"collapse\" href=\"\
+        #moregiturls\"\n                  aria-expanded=\"false\" aria-controls=\"\
+        moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n \
+        \           <div>\n              <div class=\"form-group\">\n            \
+        \    <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">GIT</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"https://pagure.io/pagure.git\" readonly>\n       \
+        \         </div>\n              </div>\n              <div class=\"collapse\"\
+        \ id=\"moregiturls\">\n                  <h5><strong>Docs GIT URLs</strong></h5>\n\
+        \                  <div class=\"form-group\">\n                    <div class=\"\
+        input-group input-group-sm\">\n                      <div class=\"input-group-addon\"\
+        >GIT</div>\n                      <input class=\"form-control\" type=\"text\"\
+        \ value=\"https://pagure.io/docs/pagure.git\" readonly>\n                \
+        \    </div>\n                  </div>\n              </div>\n            </div>\n\
+        \          </div>\n          <div class=\"repo_date\" title=\"2015-05-13 20:38:10.552662\"\
+        >\n              created 2 years ago\n          </div>\n        </div>\n\n\
+        \          <div class=\"card\">\n            <div class=\"card-header\">\n\
+        \              <strong>Recent Commits in\n                <span class=\"pr-toplabel\"\
+        >\n                  <span class=\"oi\" data-glyph=\"random\"></span>\n  \
+        \                master\n                </span>\n              </strong>\n\
+        \            </div>\n            <div class=\"card-block p-a-0\">\n      \
+        \        <div class=\"list-group list-group-flush\">\n                  <a\
+        \ href=\"/pagure/c/75b9021afbb08a3bdc1128cb282ea9c2394c0b67\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Sep 21 2017 08:20:29\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Add unit-tests for the fixes around loading issue template\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/pagure/c/fc1d7f885d8b658ce7ba2fbd9cf20692b32f7732\" class=\"\
+        list-group-item\">\n                    <div class=\"commitdate\" title=\"\
+        Sep 21 2017 08:20:29\">\n                      <small>\n                 \
+        \       <strong>\n                          <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Flake8 fix fixing the tests\n                    </small></div>\n\
+        \                  </a>\n                  <a href=\"/pagure/c/91c1f357adc77f0b21e15f6177c68ffc97f3ec67\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Sep 21 2017 08:20:29\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Adjust the documentation around ticket templates\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          3.7.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage/index.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/vendor/jquery/jquery.min.js\">\n    </script>\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/vendor/jquery-ui/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n        var currentWatchStatusButton\
+        \ = $('#unwatch_button');\n    currentWatchStatusButton.prepend('<span class=\"\
+        oi\" data-glyph=\"circle-check\" style=\"padding-right:0.5em\"></span>');\n\
+        \    $('.watch-menu a').not(currentWatchStatusButton).css('padding-left',\
+        \ '2.85em');\n\n    $(\".watch-menu a\").click(function(){\n        var selectedValue\
+        \ = $(this).attr('id');\n        var watchProjectForm = $(\"#watch_project\"\
+        );\n        var action = watchProjectForm.attr('action');\n\n        if (selectedValue\
+        \ === \"watch_issues_button\") {\n            action = action.replace('/settings/0',\
+        \ '/settings/1');\n        } else if (selectedValue === \"watch_commits_button\"\
+        ) {\n            action = action.replace('/settings/0', '/settings/2');\n\
+        \        } else if (selectedValue === \"watch_issues_commits_button\") {\n\
+        \            action = action.replace('/settings/0', '/settings/3');\n    \
+        \    } else if (selectedValue === \"reset_button\") {\n            action\
+        \ = action.replace('/settings/0', '/settings/-1');\n        }\n\n        watchProjectForm.attr('action',\
+        \ action);\n        watchProjectForm.submit();\n    });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      Connection: [Keep-Alive]
+      Content-Length: ['31652']
+      Content-Type: [text/html; charset=utf-8]
+      Date: ['Tue, 26 Sep 2017 15:29:35 GMT']
+      Keep-Alive: ['timeout=5, max=100']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      Set-Cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiTmprM01qQTJabUZtTVRNd01tTXlORGcyWkRSbE9EQXlZV0poT0Roak1UVmhaalpqTURaaFlRPT0ifX0.DKwD4A.AdJ1dfCC4-moxHJCgtqkdcKir-o;
+          Expires=Fri, 27-Oct-2017 15:29:36 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_preview b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_preview
new file mode 100644
index 0000000..6146a59
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_preview
@@ -0,0 +1,898 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://pagure.io/pagure
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - pagure - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\"\
+        \n        href=\"/static/favicon.ico\"/>\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/vendor/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/vendor/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/pagure git https://pagure.io/pagure.git\">\n  </head>\n\
+        \  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"masthead\"\
+        >\n      <div class=\"container\">\n        <div class=\"row\">\n        \
+        \  <div class=\"col-sm-3\">\n            <a href=\"/\">\n              <img\
+        \ height=40px src=\"/static/pagure-logo.png\"\n                alt=\"pagure\
+        \ Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n       \
+        \   <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav class=\"\
+        navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\">\n    \
+        \    <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n         \
+        \     <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link btn\
+        \ btn-primary\" href=\"/login/?next=https://pagure.io/pagure\">Log In</a>\n\
+        \              </li>\n        </ul>\n      </div>\n    </nav>\n\n        \
+        \    </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n<a href=\"/pagure\">pagure</a>\n        </h2>\n\
+        \        <div class=\"projectinfo m-t-1 m-b-1\">\nA git centered forge &nbsp;|\
+        \ &nbsp;<a class=\"inline\" href=\"https://pagure.io\">https://pagure.io</a>\
+        \        </div>\n\n    </header>\n    <ul class=\"nav nav-tabs nav-small\"\
+        >\n      <li class=\"nav-item\">\n        <a class=\"nav-link active\" href=\"\
+        /pagure\">\n            <span class=\"oi hidden-md-up\" data-glyph=\"home\"\
+        ></span>\n            <span class=\"hidden-sm-down\">Overview</span>\n   \
+        \     </a>\n      </li>\n        <li class=\"nav-item\" >\n          <a  class=\"\
+        nav-link\" href=\"/docs/pagure/\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"book\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Docs</span>\n          </a>\n        </li>\n\n        <li class=\"nav-item\"\
+        >\n          <a class=\"nav-link\" href=\"/pagure/commits/master\">\n    \
+        \          <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n \
+        \             </span><span class=\"hidden-sm-down\">Commits</span>\n     \
+        \       </a>\n        </li>\n\n        <li class=\"nav-item\">\n         \
+        \ <a class=\"nav-link\" href=\"/pagure/tree/master\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/pagure/issues\">\n                <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n             \
+        \   <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n                <span\
+        \ class=\"label label-default label-pill hidden-sm-down\">\n             \
+        \     340\n                </span>\n            </a>\n        </li>\n\n  \
+        \      <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"/pagure/pull-requests\"\
+        >\n              <span class=\"oi hidden-md-up\" data-glyph=\"task\"></span>\n\
+        \              <span class=\"hidden-sm-down\">Pull Requests&nbsp;</span>\n\
+        \              <span class=\"label label-default label-pill hidden-sm-down\"\
+        >\n                15\n              </span>\n          </a>\n        </li>\n\
+        \n        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/forks\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        fork\"></span>\n              <span class=\"hidden-sm-down\">Forks&nbsp;</span>\n\
+        \              <span class=\"hidden-sm-down label label-default label-pill\"\
+        >\n                131\n              </span>\n            </a>\n        </li>\n\
+        \n\n    </ul>\n  </div>\n</div>\n\n<div class=\"container p-t-3\">\n  <div\
+        \ class=\"row\">\n        <div class=\"col-md-8\">\n            <section class=\"\
+        readme\">\n              <div class=\"document\">\n<div class=\"section\"\
+        >\n<h1>Pagure</h1>\n<table class=\"docutils field-list\">\n<colgroup><col>\n\
+        <col>\n</colgroup><tbody>\n<tr><th>Author:</th><td>Pierre-Yves Chibon &lt;<a\
+        \ href=\"mailto:pingou@pingoured.fr\">pingou@pingoured.fr</a>&gt;</td>\n</tr>\n\
+        </tbody>\n</table>\n<p>Pagure is a git-centered forge, python based using\
+        \ pygit2.</p>\n<p>With pagure you can host your project with its documentation,\
+        \ let your users\nreport issues or request enhancements using the ticketing\
+        \ system and build your\ncommunity of contributors by allowing them to fork\
+        \ your projects and contribute\nto it via the now-popular pull-request mechanism.</p>\n\
+        <p>Homepage: <a href=\"https://pagure.io/pagure\">https://pagure.io/pagure</a></p>\n\
+        <p>See it at work: <a href=\"https://pagure.io\">https://pagure.io</a></p>\n\
+        <p>Playground version: <a href=\"https://stg.pagure.io\">https://stg.pagure.io</a></p>\n\
+        </div>\n<div class=\"section\">\n<h1>Get it running</h1>\n<p>There are several\
+        \ options when it comes to a development environment. Vagrant\nwill provide\
+        \ you with a virtual machine which you can develop on, or you can\ninstall\
+        \ it directly on your host machine.</p>\n<div class=\"section\">\n<h2>Vagrant</h2>\n\
+        <p>For a more thorough introduction to Vagrant, see\n<a href=\"https://fedoraproject.org/wiki/Vagrant\"\
+        >https://fedoraproject.org/wiki/Vagrant</a>.</p>\n<p>An example Vagrantfile\
+        \ is provided as <code>Vagrantfile.example</code>. To use it,\njust copy it\
+        \ and install Vagrant:</p>\n<pre>$ cp dev/Vagrantfile.example Vagrantfile\n\
+        $ sudo dnf install ansible libvirt vagrant-libvirt vagrant-sshfs vagrant-hostmanager\n\
+        $ vagrant up\n</pre>\n<p>The default <code>Vagrantfile</code> forwards ports\
+        \ from the host to the guest,\nso you can interact with the application as\
+        \ if it were running on your\nhost machine.</p>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p><code><span class=\"pre\">vagrant-hostmanager</span></code> will automatically\
+        \ maintain /etc/hosts for you so you\ncan access the development environment\
+        \ from the host using its hostname, which\nby default is <code><span class=\"\
+        pre\">pagure-dev.example.com</span></code>. You can choose not to use this\n\
+        functionality by simply not installing the <code><span class=\"pre\">vagrant-hostmanager</span></code>\
+        \ plugin, but\nif you want Pagure to provide valid URLs in the UI for git\
+        \ repositories, you\nwill need to adjust Pagure's configuration found in ~/pagure.cfg\
+        \ on the guest.</p>\n</div>\n</div>\n<div class=\"section\">\n<h2>Manually</h2>\n\
+        <ul>\n<li><p>Install the needed system libraries:</p>\n<pre>sudo dnf install\
+        \ git python2-virtualenv libgit2-devel \\\n                 libjpeg-devel\
+        \ gcc libffi-devel redhat-rpm-config\n</pre>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p>Do note the version of libgit2 that you install, for example\nin <code><span\
+        \ class=\"pre\">libgit2-0.23.4-1</span></code> you need to keep in mind the\
+        \ <code>0.23</code></p>\n</div>\n<div class=\"note\">\n<p>Note</p>\n<p>On\
+        \ Fedora 23 and earlier or on RHEL and derivative (CentOS,\nScientific Linux)\
+        \ the package <cite>python2-virtualenv</cite> is named\n<cite>python-virtualenv</cite></p>\n\
+        </div>\n</li>\n<li><p>Retrieve the sources:</p>\n<pre>git clone https://pagure.io/pagure.git\n\
+        cd pagure\n</pre>\n</li>\n<li><p>Install dependencies</p>\n<ul>\n<li><p>create\
+        \ the virtualenv:</p>\n<pre>virtualenv pagure_env\nsource ./pagure_env/bin/activate\n\
+        </pre>\n</li>\n<li><p>Install the correct version of pygit2:</p>\n<pre>pip\
+        \ install pygit2==&lt;version of libgit2 found&gt;.*\n</pre>\n<p>So in our\
+        \ example:</p>\n<pre>pip install pygit2==0.23.*\n</pre>\n</li>\n<li><p>Install\
+        \ the rest of the dependencies:</p>\n<pre>pip install -r requirements.txt\n\
+        </pre>\n</li>\n</ul>\n</li>\n<li><p>Create the folder that will receive the\
+        \ projects, forks, docs, requests and\ntickets' git repo:</p>\n<pre>mkdir\
+        \ -p lcl/{repos,docs,forks,tickets,requests,remotes,attachments,releases}\n\
+        </pre>\n</li>\n<li><p>Create the inital database scheme:</p>\n<pre>python\
+        \ createdb.py\n</pre>\n</li>\n<li><p>Start a worker, in one terminal:</p>\n\
+        <pre>./runworker.py\n</pre>\n</li>\n<li><p>Run the application, in another\
+        \ terminal:</p>\n<pre>./runserver.py\n</pre>\n</li>\n<li><p>To get some profiling\
+        \ information you can also run it as:</p>\n<pre>./runserver.py --profile\n\
+        </pre>\n</li>\n</ul>\n<p>This will launch the application at <a href=\"http://127.0.0.1:5000\"\
+        >http://127.0.0.1:5000</a></p>\n<ul>\n<li><p>To run unit-tests on pagure</p>\n\
+        <ul>\n<li><p>Install the dependencies:</p>\n<pre>pip install -r tests_requirements.txt\n\
+        </pre>\n</li>\n<li><p>Run it:</p>\n<pre>./runtests.sh\n</pre>\n<div class=\"\
+        note\">\n<p>Note</p>\n<p>While testing for worker tasks, pagure uses celery\
+        \ in /usr/bin/\nCelery then looks for eventlet (which we use for testing only)\
+        \ at\nsystem level and not in virtualenv. You will need to install eventlet\n\
+        outside of your virtualenv if you are using one.</p>\n</div>\n</li>\n</ul>\n\
+        </li>\n</ul>\n</div>\n</div>\n</div>\n\n            </section>\n        </div>\n\
+        \      <div class=\"col-md-4\">\n        <div class=\"card\">\n          <div\
+        \ class=\"card-block\">\n            <h5><strong>Contributors</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/pingou\">\n                  <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \               -  main admin\n              </div>\n                  <div>\n\
+        \                    <a href=\"/user/ryanlerch\">\n                      <img\
+        \ class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                      Ryan Lerch (ryanlerch)\n                    </a>\n\
+        \                    - admin\n                  </div>\n                 \
+        \ <div>\n                    <a href=\"/user/puiterwijk\">\n             \
+        \         <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/85f8b5f58b9808429ad69ba3722d64da01ce850635e348e838dfdc053e1140e3?s=20&d=retro\"\
+        />\n                      Patrick &#34;\u30DE\u30EB\u30BF\u30A4\u30F3\u30A2\
+        \u30F3\u30C9\u30EC\u30A2\u30B9&#34; Uiterwijk (puiterwijk)\n             \
+        \       </a>\n                    - commit\n                  </div>\n   \
+        \               <div>\n                    <a href=\"/user/vivekanand1101\"\
+        >\n                      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                      Vivek Anand (vivekanand1101)\n                 \
+        \   </a>\n                    - ticket\n                  </div>\n       \
+        \           <div>\n                    <a href=\"/user/farhaan\">\n      \
+        \                <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b681ddfaffa293b03c57e5f0ed90eb1e06a8f748f4dccdccef8cdd301c66c9ae?s=20&d=retro\"\
+        />\n                      Farhaan Bukhsh (farhaan)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/cverna\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/c7844b93c43c862adaa29920c09bdfb91efed57a843203e5d0b72673e664c003?s=20&d=retro\"\
+        />\n                      Clement Verna (cverna)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/jcline\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                      Jeremy Cline (jcline)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/lslebodn\">\n              \
+        \        <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/8c6fcfe0eec099f1f01f5c237935bb5c97f2063a5c1068e57c5815e0bfecbf70?s=20&d=retro\"\
+        />\n                      Lukas Slebodnik (lslebodn)\n                   \
+        \ </a>\n                    - ticket\n                  </div>\n         \
+        \         <div>\n                    <a href=\"/user/mprahl\">\n         \
+        \             <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/ecae5ad9b37619a38e699de00049e449f120b433c9f26a8beb05b990dfc54c9d?s=20&d=retro\"\
+        />\n                      Matt Prahl (mprahl)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n            </div>\n\
+        \            <h5><strong>Branches</strong></h5>\n            <div class=\"\
+        m-b-2\">\n              <div id=\"branch-master\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"\n          \
+        \          title=\"Default branch\"></span>\n                  <strong title=\"\
+        Currently viewing branch master\" data-toggle=\"tooltip\">master</strong>\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"star\"\n \
+        \                   title=\"Default branch\"></span>\n                </div>\n\
+        \              </div>\n\n              <div id=\"branch-2.9.x\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/2.9.x\"\n           \
+        \         title=\"2.9.x\" data-toggle=\"tooltip\">2.9.x\n                \
+        \  </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-alembic_changes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/alembic_changes\"\n        \
+        \            title=\"alembic_changes\" data-toggle=\"tooltip\">alembic_changes\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-confirm_merge\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/confirm_merge\"\n   \
+        \                 title=\"confirm_merge\" data-toggle=\"tooltip\">confirm_merge\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-css_tables\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/css_tables\"\n      \
+        \              title=\"css_tables\" data-toggle=\"tooltip\">css_tables\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_del_project\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_del_project\"\n \
+        \                   title=\"fix_del_project\" data-toggle=\"tooltip\">fix_del_project\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_delete\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_delete\"\n      \
+        \              title=\"fix_delete\" data-toggle=\"tooltip\">fix_delete\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_diff_refs\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_diff_refs\"\n   \
+        \                 title=\"fix_diff_refs\" data-toggle=\"tooltip\">fix_diff_refs\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_doc\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_doc\"\n                \
+        \    title=\"fix_doc\" data-toggle=\"tooltip\">fix_doc\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_linking\" class=\"repoinfo-branchlistitem row\">\n\
+        \                <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/fix_linking\"\n                   \
+        \ title=\"fix_linking\" data-toggle=\"tooltip\">fix_linking\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_pygit_error\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_pygit_error\"\n        \
+        \            title=\"fix_pygit_error\" data-toggle=\"tooltip\">fix_pygit_error\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_reply_to\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_reply_to\"\n    \
+        \                title=\"fix_reply_to\" data-toggle=\"tooltip\">fix_reply_to\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_sse\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse\"\n                \
+        \    title=\"fix_sse\" data-toggle=\"tooltip\">fix_sse\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_sse_status\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse_status\"\n         \
+        \           title=\"fix_sse_status\" data-toggle=\"tooltip\">fix_sse_status\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_templates\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_templates\"\n   \
+        \                 title=\"fix_templates\" data-toggle=\"tooltip\">fix_templates\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fixes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fixes\"\n                  \
+        \  title=\"fixes\" data-toggle=\"tooltip\">fixes\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-force_flag\" class=\"repoinfo-branchlistitem row\">\n             \
+        \   <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/force_flag\"\n                    title=\"force_flag\"\
+        \ data-toggle=\"tooltip\">force_flag\n                  </a>\n\n         \
+        \       </div>\n                <div class=\"branch_del col-md-4\">\n    \
+        \            </div>\n              </div>\n              <div id=\"branch-gpg_check\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/gpg_check\"\
+        \n                    title=\"gpg_check\" data-toggle=\"tooltip\">gpg_check\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-logging_milter\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/logging_milter\"\n  \
+        \                  title=\"logging_milter\" data-toggle=\"tooltip\">logging_milter\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-mirroring\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/mirroring\"\n              \
+        \      title=\"mirroring\" data-toggle=\"tooltip\">mirroring\n           \
+        \       </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-py3_work2\" class=\"repoinfo-branchlistitem row\">\n \
+        \               <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/py3_work2\"\n                    title=\"\
+        py3_work2\" data-toggle=\"tooltip\">py3_work2\n                  </a>\n\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-rel_2.2.z\" class=\"repoinfo-branchlistitem row\">\n              \
+        \  <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/rel_2.2.z\"\n                    title=\"rel_2.2.z\"\
+        \ data-toggle=\"tooltip\">rel_2.2.z\n                  </a>\n\n          \
+        \      </div>\n                <div class=\"branch_del col-md-4\">\n     \
+        \           </div>\n              </div>\n              <div id=\"branch-rel_2.3.z\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/rel_2.3.z\"\
+        \n                    title=\"rel_2.3.z\" data-toggle=\"tooltip\">rel_2.3.z\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-scroll_metadata\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/scroll_metadata\"\n \
+        \                   title=\"scroll_metadata\" data-toggle=\"tooltip\">scroll_metadata\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-utf_search\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/utf_search\"\n      \
+        \              title=\"utf_search\" data-toggle=\"tooltip\">utf_search\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \         </div>\n            <h5><strong>Source GIT URLs</strong>       \
+        \           <span class=\"pull-xs-right\"><a data-toggle=\"collapse\" href=\"\
+        #moregiturls\"\n                  aria-expanded=\"false\" aria-controls=\"\
+        moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n \
+        \           <div>\n              <div class=\"form-group\">\n            \
+        \    <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">GIT</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"https://pagure.io/pagure.git\" readonly>\n       \
+        \         </div>\n              </div>\n              <div class=\"collapse\"\
+        \ id=\"moregiturls\">\n                  <h5><strong>Docs GIT URLs</strong></h5>\n\
+        \                  <div class=\"form-group\">\n                    <div class=\"\
+        input-group input-group-sm\">\n                      <div class=\"input-group-addon\"\
+        >GIT</div>\n                      <input class=\"form-control\" type=\"text\"\
+        \ value=\"https://pagure.io/docs/pagure.git\" readonly>\n                \
+        \    </div>\n                  </div>\n              </div>\n            </div>\n\
+        \          </div>\n          <div class=\"repo_date\" title=\"2015-05-13 20:38:10.552662\"\
+        >\n              created 2 years ago\n          </div>\n        </div>\n\n\
+        \          <div class=\"card\">\n            <div class=\"card-header\">\n\
+        \              <strong>Recent Commits in\n                <span class=\"pr-toplabel\"\
+        >\n                  <span class=\"oi\" data-glyph=\"random\"></span>\n  \
+        \                master\n                </span>\n              </strong>\n\
+        \            </div>\n            <div class=\"card-block p-a-0\">\n      \
+        \        <div class=\"list-group list-group-flush\">\n                  <a\
+        \ href=\"/pagure/c/a324b4120738bb9765b59625f3e767f9b50d599f\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Sep 25 2017 12:50:46\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 2 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Fix the unit-tests\n                    </small></div>\n\
+        \                  </a>\n                  <a href=\"/pagure/c/ef569a5160891b30cc2aa4d614b39f4a266d7ad7\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Sep 21 2017 12:15:51\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                          Vivek Anand\n                        </strong>\n\
+        \                        commited 5 days ago\n                      </small>\n\
+        \                    </div>\n                    <div><small>\n          \
+        \            give project: generate gitolite acls after giving a project\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/pagure/c/16c5781815d4695fe89db3c5cec5191dc1b81c6f\" class=\"\
+        list-group-item\">\n                    <div class=\"commitdate\" title=\"\
+        Sep 21 2017 10:26:39\">\n                      <small>\n                 \
+        \       <strong>\n                          <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                          Vivek Anand\n                        </strong>\n\
+        \                        commited 6 days ago\n                      </small>\n\
+        \                    </div>\n                    <div><small>\n          \
+        \            read only repo: Add unit test for update_read_only_mode method\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          3.7.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage/index.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/vendor/jquery/jquery.min.js\">\n    </script>\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/vendor/jquery-ui/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n        var currentWatchStatusButton\
+        \ = $('#unwatch_button');\n    currentWatchStatusButton.prepend('<span class=\"\
+        oi\" data-glyph=\"circle-check\" style=\"padding-right:0.5em\"></span>');\n\
+        \    $('.watch-menu a').not(currentWatchStatusButton).css('padding-left',\
+        \ '2.85em');\n\n    $(\".watch-menu a\").click(function(){\n        var selectedValue\
+        \ = $(this).attr('id');\n        var watchProjectForm = $(\"#watch_project\"\
+        );\n        var action = watchProjectForm.attr('action');\n\n        if (selectedValue\
+        \ === \"watch_issues_button\") {\n            action = action.replace('/settings/0',\
+        \ '/settings/1');\n        } else if (selectedValue === \"watch_commits_button\"\
+        ) {\n            action = action.replace('/settings/0', '/settings/2');\n\
+        \        } else if (selectedValue === \"watch_issues_commits_button\") {\n\
+        \            action = action.replace('/settings/0', '/settings/3');\n    \
+        \    } else if (selectedValue === \"reset_button\") {\n            action\
+        \ = action.replace('/settings/0', '/settings/-1');\n        }\n\n        watchProjectForm.attr('action',\
+        \ action);\n        watchProjectForm.submit();\n    });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      Connection: [Keep-Alive]
+      Content-Length: ['31644']
+      Content-Type: [text/html; charset=utf-8]
+      Date: ['Wed, 27 Sep 2017 12:07:28 GMT']
+      Keep-Alive: ['timeout=5, max=100']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      Set-Cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiWldWa1lqZ3lNVFpoT1RBNE5qSmhZemRsTURNeU56TmxNekExTXpnNVlUZGxPV016TlRVMVpnPT0ifX0.DK0mAQ.YtILWDOD3ZiRyLDyFcyzpcGTfaM;
+          Expires=Sat, 28-Oct-2017 12:07:29 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://pagure.io/pagure
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - pagure - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\"\
+        \n        href=\"/static/favicon.ico\"/>\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/vendor/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/vendor/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/pagure git https://pagure.io/pagure.git\">\n  </head>\n\
+        \  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"masthead\"\
+        >\n      <div class=\"container\">\n        <div class=\"row\">\n        \
+        \  <div class=\"col-sm-3\">\n            <a href=\"/\">\n              <img\
+        \ height=40px src=\"/static/pagure-logo.png\"\n                alt=\"pagure\
+        \ Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n       \
+        \   <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav class=\"\
+        navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\">\n    \
+        \    <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n         \
+        \     <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link btn\
+        \ btn-primary\" href=\"/login/?next=https://pagure.io/pagure\">Log In</a>\n\
+        \              </li>\n        </ul>\n      </div>\n    </nav>\n\n        \
+        \    </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n<a href=\"/pagure\">pagure</a>\n        </h2>\n\
+        \        <div class=\"projectinfo m-t-1 m-b-1\">\nA git centered forge &nbsp;|\
+        \ &nbsp;<a class=\"inline\" href=\"https://pagure.io\">https://pagure.io</a>\
+        \        </div>\n\n    </header>\n    <ul class=\"nav nav-tabs nav-small\"\
+        >\n      <li class=\"nav-item\">\n        <a class=\"nav-link active\" href=\"\
+        /pagure\">\n            <span class=\"oi hidden-md-up\" data-glyph=\"home\"\
+        ></span>\n            <span class=\"hidden-sm-down\">Overview</span>\n   \
+        \     </a>\n      </li>\n        <li class=\"nav-item\" >\n          <a  class=\"\
+        nav-link\" href=\"/docs/pagure/\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"book\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Docs</span>\n          </a>\n        </li>\n\n        <li class=\"nav-item\"\
+        >\n          <a class=\"nav-link\" href=\"/pagure/commits/master\">\n    \
+        \          <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n \
+        \             </span><span class=\"hidden-sm-down\">Commits</span>\n     \
+        \       </a>\n        </li>\n\n        <li class=\"nav-item\">\n         \
+        \ <a class=\"nav-link\" href=\"/pagure/tree/master\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/pagure/issues\">\n                <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n             \
+        \   <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n                <span\
+        \ class=\"label label-default label-pill hidden-sm-down\">\n             \
+        \     340\n                </span>\n            </a>\n        </li>\n\n  \
+        \      <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"/pagure/pull-requests\"\
+        >\n              <span class=\"oi hidden-md-up\" data-glyph=\"task\"></span>\n\
+        \              <span class=\"hidden-sm-down\">Pull Requests&nbsp;</span>\n\
+        \              <span class=\"label label-default label-pill hidden-sm-down\"\
+        >\n                15\n              </span>\n          </a>\n        </li>\n\
+        \n        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/forks\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        fork\"></span>\n              <span class=\"hidden-sm-down\">Forks&nbsp;</span>\n\
+        \              <span class=\"hidden-sm-down label label-default label-pill\"\
+        >\n                131\n              </span>\n            </a>\n        </li>\n\
+        \n\n    </ul>\n  </div>\n</div>\n\n<div class=\"container p-t-3\">\n  <div\
+        \ class=\"row\">\n        <div class=\"col-md-8\">\n            <section class=\"\
+        readme\">\n              <div class=\"document\">\n<div class=\"section\"\
+        >\n<h1>Pagure</h1>\n<table class=\"docutils field-list\">\n<colgroup><col>\n\
+        <col>\n</colgroup><tbody>\n<tr><th>Author:</th><td>Pierre-Yves Chibon &lt;<a\
+        \ href=\"mailto:pingou@pingoured.fr\">pingou@pingoured.fr</a>&gt;</td>\n</tr>\n\
+        </tbody>\n</table>\n<p>Pagure is a git-centered forge, python based using\
+        \ pygit2.</p>\n<p>With pagure you can host your project with its documentation,\
+        \ let your users\nreport issues or request enhancements using the ticketing\
+        \ system and build your\ncommunity of contributors by allowing them to fork\
+        \ your projects and contribute\nto it via the now-popular pull-request mechanism.</p>\n\
+        <p>Homepage: <a href=\"https://pagure.io/pagure\">https://pagure.io/pagure</a></p>\n\
+        <p>See it at work: <a href=\"https://pagure.io\">https://pagure.io</a></p>\n\
+        <p>Playground version: <a href=\"https://stg.pagure.io\">https://stg.pagure.io</a></p>\n\
+        </div>\n<div class=\"section\">\n<h1>Get it running</h1>\n<p>There are several\
+        \ options when it comes to a development environment. Vagrant\nwill provide\
+        \ you with a virtual machine which you can develop on, or you can\ninstall\
+        \ it directly on your host machine.</p>\n<div class=\"section\">\n<h2>Vagrant</h2>\n\
+        <p>For a more thorough introduction to Vagrant, see\n<a href=\"https://fedoraproject.org/wiki/Vagrant\"\
+        >https://fedoraproject.org/wiki/Vagrant</a>.</p>\n<p>An example Vagrantfile\
+        \ is provided as <code>Vagrantfile.example</code>. To use it,\njust copy it\
+        \ and install Vagrant:</p>\n<pre>$ cp dev/Vagrantfile.example Vagrantfile\n\
+        $ sudo dnf install ansible libvirt vagrant-libvirt vagrant-sshfs vagrant-hostmanager\n\
+        $ vagrant up\n</pre>\n<p>The default <code>Vagrantfile</code> forwards ports\
+        \ from the host to the guest,\nso you can interact with the application as\
+        \ if it were running on your\nhost machine.</p>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p><code><span class=\"pre\">vagrant-hostmanager</span></code> will automatically\
+        \ maintain /etc/hosts for you so you\ncan access the development environment\
+        \ from the host using its hostname, which\nby default is <code><span class=\"\
+        pre\">pagure-dev.example.com</span></code>. You can choose not to use this\n\
+        functionality by simply not installing the <code><span class=\"pre\">vagrant-hostmanager</span></code>\
+        \ plugin, but\nif you want Pagure to provide valid URLs in the UI for git\
+        \ repositories, you\nwill need to adjust Pagure's configuration found in ~/pagure.cfg\
+        \ on the guest.</p>\n</div>\n</div>\n<div class=\"section\">\n<h2>Manually</h2>\n\
+        <ul>\n<li><p>Install the needed system libraries:</p>\n<pre>sudo dnf install\
+        \ git python2-virtualenv libgit2-devel \\\n                 libjpeg-devel\
+        \ gcc libffi-devel redhat-rpm-config\n</pre>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p>Do note the version of libgit2 that you install, for example\nin <code><span\
+        \ class=\"pre\">libgit2-0.23.4-1</span></code> you need to keep in mind the\
+        \ <code>0.23</code></p>\n</div>\n<div class=\"note\">\n<p>Note</p>\n<p>On\
+        \ Fedora 23 and earlier or on RHEL and derivative (CentOS,\nScientific Linux)\
+        \ the package <cite>python2-virtualenv</cite> is named\n<cite>python-virtualenv</cite></p>\n\
+        </div>\n</li>\n<li><p>Retrieve the sources:</p>\n<pre>git clone https://pagure.io/pagure.git\n\
+        cd pagure\n</pre>\n</li>\n<li><p>Install dependencies</p>\n<ul>\n<li><p>create\
+        \ the virtualenv:</p>\n<pre>virtualenv pagure_env\nsource ./pagure_env/bin/activate\n\
+        </pre>\n</li>\n<li><p>Install the correct version of pygit2:</p>\n<pre>pip\
+        \ install pygit2==&lt;version of libgit2 found&gt;.*\n</pre>\n<p>So in our\
+        \ example:</p>\n<pre>pip install pygit2==0.23.*\n</pre>\n</li>\n<li><p>Install\
+        \ the rest of the dependencies:</p>\n<pre>pip install -r requirements.txt\n\
+        </pre>\n</li>\n</ul>\n</li>\n<li><p>Create the folder that will receive the\
+        \ projects, forks, docs, requests and\ntickets' git repo:</p>\n<pre>mkdir\
+        \ -p lcl/{repos,docs,forks,tickets,requests,remotes,attachments,releases}\n\
+        </pre>\n</li>\n<li><p>Create the inital database scheme:</p>\n<pre>python\
+        \ createdb.py\n</pre>\n</li>\n<li><p>Start a worker, in one terminal:</p>\n\
+        <pre>./runworker.py\n</pre>\n</li>\n<li><p>Run the application, in another\
+        \ terminal:</p>\n<pre>./runserver.py\n</pre>\n</li>\n<li><p>To get some profiling\
+        \ information you can also run it as:</p>\n<pre>./runserver.py --profile\n\
+        </pre>\n</li>\n</ul>\n<p>This will launch the application at <a href=\"http://127.0.0.1:5000\"\
+        >http://127.0.0.1:5000</a></p>\n<ul>\n<li><p>To run unit-tests on pagure</p>\n\
+        <ul>\n<li><p>Install the dependencies:</p>\n<pre>pip install -r tests_requirements.txt\n\
+        </pre>\n</li>\n<li><p>Run it:</p>\n<pre>./runtests.sh\n</pre>\n<div class=\"\
+        note\">\n<p>Note</p>\n<p>While testing for worker tasks, pagure uses celery\
+        \ in /usr/bin/\nCelery then looks for eventlet (which we use for testing only)\
+        \ at\nsystem level and not in virtualenv. You will need to install eventlet\n\
+        outside of your virtualenv if you are using one.</p>\n</div>\n</li>\n</ul>\n\
+        </li>\n</ul>\n</div>\n</div>\n</div>\n\n            </section>\n        </div>\n\
+        \      <div class=\"col-md-4\">\n        <div class=\"card\">\n          <div\
+        \ class=\"card-block\">\n            <h5><strong>Contributors</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/pingou\">\n                  <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \               -  main admin\n              </div>\n                  <div>\n\
+        \                    <a href=\"/user/ryanlerch\">\n                      <img\
+        \ class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                      Ryan Lerch (ryanlerch)\n                    </a>\n\
+        \                    - admin\n                  </div>\n                 \
+        \ <div>\n                    <a href=\"/user/puiterwijk\">\n             \
+        \         <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/85f8b5f58b9808429ad69ba3722d64da01ce850635e348e838dfdc053e1140e3?s=20&d=retro\"\
+        />\n                      Patrick &#34;\u30DE\u30EB\u30BF\u30A4\u30F3\u30A2\
+        \u30F3\u30C9\u30EC\u30A2\u30B9&#34; Uiterwijk (puiterwijk)\n             \
+        \       </a>\n                    - commit\n                  </div>\n   \
+        \               <div>\n                    <a href=\"/user/vivekanand1101\"\
+        >\n                      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                      Vivek Anand (vivekanand1101)\n                 \
+        \   </a>\n                    - ticket\n                  </div>\n       \
+        \           <div>\n                    <a href=\"/user/farhaan\">\n      \
+        \                <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b681ddfaffa293b03c57e5f0ed90eb1e06a8f748f4dccdccef8cdd301c66c9ae?s=20&d=retro\"\
+        />\n                      Farhaan Bukhsh (farhaan)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/cverna\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/c7844b93c43c862adaa29920c09bdfb91efed57a843203e5d0b72673e664c003?s=20&d=retro\"\
+        />\n                      Clement Verna (cverna)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/jcline\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                      Jeremy Cline (jcline)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/lslebodn\">\n              \
+        \        <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/8c6fcfe0eec099f1f01f5c237935bb5c97f2063a5c1068e57c5815e0bfecbf70?s=20&d=retro\"\
+        />\n                      Lukas Slebodnik (lslebodn)\n                   \
+        \ </a>\n                    - ticket\n                  </div>\n         \
+        \         <div>\n                    <a href=\"/user/mprahl\">\n         \
+        \             <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/ecae5ad9b37619a38e699de00049e449f120b433c9f26a8beb05b990dfc54c9d?s=20&d=retro\"\
+        />\n                      Matt Prahl (mprahl)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n            </div>\n\
+        \            <h5><strong>Branches</strong></h5>\n            <div class=\"\
+        m-b-2\">\n              <div id=\"branch-master\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"\n          \
+        \          title=\"Default branch\"></span>\n                  <strong title=\"\
+        Currently viewing branch master\" data-toggle=\"tooltip\">master</strong>\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"star\"\n \
+        \                   title=\"Default branch\"></span>\n                </div>\n\
+        \              </div>\n\n              <div id=\"branch-2.9.x\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/2.9.x\"\n           \
+        \         title=\"2.9.x\" data-toggle=\"tooltip\">2.9.x\n                \
+        \  </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-alembic_changes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/alembic_changes\"\n        \
+        \            title=\"alembic_changes\" data-toggle=\"tooltip\">alembic_changes\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-confirm_merge\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/confirm_merge\"\n   \
+        \                 title=\"confirm_merge\" data-toggle=\"tooltip\">confirm_merge\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-css_tables\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/css_tables\"\n      \
+        \              title=\"css_tables\" data-toggle=\"tooltip\">css_tables\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_del_project\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_del_project\"\n \
+        \                   title=\"fix_del_project\" data-toggle=\"tooltip\">fix_del_project\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_delete\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_delete\"\n      \
+        \              title=\"fix_delete\" data-toggle=\"tooltip\">fix_delete\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_diff_refs\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_diff_refs\"\n   \
+        \                 title=\"fix_diff_refs\" data-toggle=\"tooltip\">fix_diff_refs\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_doc\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_doc\"\n                \
+        \    title=\"fix_doc\" data-toggle=\"tooltip\">fix_doc\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_linking\" class=\"repoinfo-branchlistitem row\">\n\
+        \                <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/fix_linking\"\n                   \
+        \ title=\"fix_linking\" data-toggle=\"tooltip\">fix_linking\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_pygit_error\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_pygit_error\"\n        \
+        \            title=\"fix_pygit_error\" data-toggle=\"tooltip\">fix_pygit_error\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_reply_to\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_reply_to\"\n    \
+        \                title=\"fix_reply_to\" data-toggle=\"tooltip\">fix_reply_to\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_sse\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse\"\n                \
+        \    title=\"fix_sse\" data-toggle=\"tooltip\">fix_sse\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_sse_status\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse_status\"\n         \
+        \           title=\"fix_sse_status\" data-toggle=\"tooltip\">fix_sse_status\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_templates\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_templates\"\n   \
+        \                 title=\"fix_templates\" data-toggle=\"tooltip\">fix_templates\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fixes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fixes\"\n                  \
+        \  title=\"fixes\" data-toggle=\"tooltip\">fixes\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-force_flag\" class=\"repoinfo-branchlistitem row\">\n             \
+        \   <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/force_flag\"\n                    title=\"force_flag\"\
+        \ data-toggle=\"tooltip\">force_flag\n                  </a>\n\n         \
+        \       </div>\n                <div class=\"branch_del col-md-4\">\n    \
+        \            </div>\n              </div>\n              <div id=\"branch-gpg_check\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/gpg_check\"\
+        \n                    title=\"gpg_check\" data-toggle=\"tooltip\">gpg_check\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-logging_milter\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/logging_milter\"\n  \
+        \                  title=\"logging_milter\" data-toggle=\"tooltip\">logging_milter\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-mirroring\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/mirroring\"\n              \
+        \      title=\"mirroring\" data-toggle=\"tooltip\">mirroring\n           \
+        \       </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-py3_work2\" class=\"repoinfo-branchlistitem row\">\n \
+        \               <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/py3_work2\"\n                    title=\"\
+        py3_work2\" data-toggle=\"tooltip\">py3_work2\n                  </a>\n\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-rel_2.2.z\" class=\"repoinfo-branchlistitem row\">\n              \
+        \  <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/rel_2.2.z\"\n                    title=\"rel_2.2.z\"\
+        \ data-toggle=\"tooltip\">rel_2.2.z\n                  </a>\n\n          \
+        \      </div>\n                <div class=\"branch_del col-md-4\">\n     \
+        \           </div>\n              </div>\n              <div id=\"branch-rel_2.3.z\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/rel_2.3.z\"\
+        \n                    title=\"rel_2.3.z\" data-toggle=\"tooltip\">rel_2.3.z\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-scroll_metadata\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/scroll_metadata\"\n \
+        \                   title=\"scroll_metadata\" data-toggle=\"tooltip\">scroll_metadata\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-utf_search\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/utf_search\"\n      \
+        \              title=\"utf_search\" data-toggle=\"tooltip\">utf_search\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \         </div>\n            <h5><strong>Source GIT URLs</strong>       \
+        \           <span class=\"pull-xs-right\"><a data-toggle=\"collapse\" href=\"\
+        #moregiturls\"\n                  aria-expanded=\"false\" aria-controls=\"\
+        moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n \
+        \           <div>\n              <div class=\"form-group\">\n            \
+        \    <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">GIT</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"https://pagure.io/pagure.git\" readonly>\n       \
+        \         </div>\n              </div>\n              <div class=\"collapse\"\
+        \ id=\"moregiturls\">\n                  <h5><strong>Docs GIT URLs</strong></h5>\n\
+        \                  <div class=\"form-group\">\n                    <div class=\"\
+        input-group input-group-sm\">\n                      <div class=\"input-group-addon\"\
+        >GIT</div>\n                      <input class=\"form-control\" type=\"text\"\
+        \ value=\"https://pagure.io/docs/pagure.git\" readonly>\n                \
+        \    </div>\n                  </div>\n              </div>\n            </div>\n\
+        \          </div>\n          <div class=\"repo_date\" title=\"2015-05-13 20:38:10.552662\"\
+        >\n              created 2 years ago\n          </div>\n        </div>\n\n\
+        \          <div class=\"card\">\n            <div class=\"card-header\">\n\
+        \              <strong>Recent Commits in\n                <span class=\"pr-toplabel\"\
+        >\n                  <span class=\"oi\" data-glyph=\"random\"></span>\n  \
+        \                master\n                </span>\n              </strong>\n\
+        \            </div>\n            <div class=\"card-block p-a-0\">\n      \
+        \        <div class=\"list-group list-group-flush\">\n                  <a\
+        \ href=\"/pagure/c/a324b4120738bb9765b59625f3e767f9b50d599f\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Sep 25 2017 12:50:46\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 2 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Fix the unit-tests\n                    </small></div>\n\
+        \                  </a>\n                  <a href=\"/pagure/c/ef569a5160891b30cc2aa4d614b39f4a266d7ad7\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Sep 21 2017 12:15:51\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                          Vivek Anand\n                        </strong>\n\
+        \                        commited 5 days ago\n                      </small>\n\
+        \                    </div>\n                    <div><small>\n          \
+        \            give project: generate gitolite acls after giving a project\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/pagure/c/16c5781815d4695fe89db3c5cec5191dc1b81c6f\" class=\"\
+        list-group-item\">\n                    <div class=\"commitdate\" title=\"\
+        Sep 21 2017 10:26:39\">\n                      <small>\n                 \
+        \       <strong>\n                          <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                          Vivek Anand\n                        </strong>\n\
+        \                        commited 6 days ago\n                      </small>\n\
+        \                    </div>\n                    <div><small>\n          \
+        \            read only repo: Add unit test for update_read_only_mode method\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          3.7.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage/index.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/vendor/jquery/jquery.min.js\">\n    </script>\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/vendor/jquery-ui/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n        var currentWatchStatusButton\
+        \ = $('#unwatch_button');\n    currentWatchStatusButton.prepend('<span class=\"\
+        oi\" data-glyph=\"circle-check\" style=\"padding-right:0.5em\"></span>');\n\
+        \    $('.watch-menu a').not(currentWatchStatusButton).css('padding-left',\
+        \ '2.85em');\n\n    $(\".watch-menu a\").click(function(){\n        var selectedValue\
+        \ = $(this).attr('id');\n        var watchProjectForm = $(\"#watch_project\"\
+        );\n        var action = watchProjectForm.attr('action');\n\n        if (selectedValue\
+        \ === \"watch_issues_button\") {\n            action = action.replace('/settings/0',\
+        \ '/settings/1');\n        } else if (selectedValue === \"watch_commits_button\"\
+        ) {\n            action = action.replace('/settings/0', '/settings/2');\n\
+        \        } else if (selectedValue === \"watch_issues_commits_button\") {\n\
+        \            action = action.replace('/settings/0', '/settings/3');\n    \
+        \    } else if (selectedValue === \"reset_button\") {\n            action\
+        \ = action.replace('/settings/0', '/settings/-1');\n        }\n\n        watchProjectForm.attr('action',\
+        \ action);\n        watchProjectForm.submit();\n    });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      Connection: [Keep-Alive]
+      Content-Length: ['31644']
+      Content-Type: [text/html; charset=utf-8]
+      Date: ['Wed, 27 Sep 2017 12:07:31 GMT']
+      Keep-Alive: ['timeout=5, max=100']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      Set-Cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiWVdVd01XWTBOVFE0Tnpoak16VXpOV0ZoT1RnME1EUTFNVEV5TUdabVpUUmhaalE1WWpWbFl3PT0ifX0.DK0mAw.6BBoDXAt_1zLVnTcZQa68xAzzTg;
+          Expires=Sat, 28-Oct-2017 12:07:31 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_private b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_private
new file mode 100644
index 0000000..0450f91
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_private
@@ -0,0 +1,450 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://pagure.io/pagure
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - pagure - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\"\
+        \n        href=\"/static/favicon.ico\"/>\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/vendor/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/vendor/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/pagure git https://pagure.io/pagure.git\">\n  </head>\n\
+        \  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"masthead\"\
+        >\n      <div class=\"container\">\n        <div class=\"row\">\n        \
+        \  <div class=\"col-sm-3\">\n            <a href=\"/\">\n              <img\
+        \ height=40px src=\"/static/pagure-logo.png\"\n                alt=\"pagure\
+        \ Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n       \
+        \   <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav class=\"\
+        navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\">\n    \
+        \    <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n         \
+        \     <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link btn\
+        \ btn-primary\" href=\"/login/?next=https://pagure.io/pagure\">Log In</a>\n\
+        \              </li>\n        </ul>\n      </div>\n    </nav>\n\n        \
+        \    </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n<a href=\"/pagure\">pagure</a>\n        </h2>\n\
+        \        <div class=\"projectinfo m-t-1 m-b-1\">\nA git centered forge &nbsp;|\
+        \ &nbsp;<a class=\"inline\" href=\"https://pagure.io\">https://pagure.io</a>\
+        \        </div>\n\n    </header>\n    <ul class=\"nav nav-tabs nav-small\"\
+        >\n      <li class=\"nav-item\">\n        <a class=\"nav-link active\" href=\"\
+        /pagure\">\n            <span class=\"oi hidden-md-up\" data-glyph=\"home\"\
+        ></span>\n            <span class=\"hidden-sm-down\">Overview</span>\n   \
+        \     </a>\n      </li>\n        <li class=\"nav-item\" >\n          <a  class=\"\
+        nav-link\" href=\"/docs/pagure/\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"book\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Docs</span>\n          </a>\n        </li>\n\n        <li class=\"nav-item\"\
+        >\n          <a class=\"nav-link\" href=\"/pagure/commits/master\">\n    \
+        \          <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n \
+        \             </span><span class=\"hidden-sm-down\">Commits</span>\n     \
+        \       </a>\n        </li>\n\n        <li class=\"nav-item\">\n         \
+        \ <a class=\"nav-link\" href=\"/pagure/tree/master\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/pagure/issues\">\n                <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n             \
+        \   <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n                <span\
+        \ class=\"label label-default label-pill hidden-sm-down\">\n             \
+        \     340\n                </span>\n            </a>\n        </li>\n\n  \
+        \      <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"/pagure/pull-requests\"\
+        >\n              <span class=\"oi hidden-md-up\" data-glyph=\"task\"></span>\n\
+        \              <span class=\"hidden-sm-down\">Pull Requests&nbsp;</span>\n\
+        \              <span class=\"label label-default label-pill hidden-sm-down\"\
+        >\n                15\n              </span>\n          </a>\n        </li>\n\
+        \n        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/forks\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        fork\"></span>\n              <span class=\"hidden-sm-down\">Forks&nbsp;</span>\n\
+        \              <span class=\"hidden-sm-down label label-default label-pill\"\
+        >\n                131\n              </span>\n            </a>\n        </li>\n\
+        \n\n    </ul>\n  </div>\n</div>\n\n<div class=\"container p-t-3\">\n  <div\
+        \ class=\"row\">\n        <div class=\"col-md-8\">\n            <section class=\"\
+        readme\">\n              <div class=\"document\">\n<div class=\"section\"\
+        >\n<h1>Pagure</h1>\n<table class=\"docutils field-list\">\n<colgroup><col>\n\
+        <col>\n</colgroup><tbody>\n<tr><th>Author:</th><td>Pierre-Yves Chibon &lt;<a\
+        \ href=\"mailto:pingou@pingoured.fr\">pingou@pingoured.fr</a>&gt;</td>\n</tr>\n\
+        </tbody>\n</table>\n<p>Pagure is a git-centered forge, python based using\
+        \ pygit2.</p>\n<p>With pagure you can host your project with its documentation,\
+        \ let your users\nreport issues or request enhancements using the ticketing\
+        \ system and build your\ncommunity of contributors by allowing them to fork\
+        \ your projects and contribute\nto it via the now-popular pull-request mechanism.</p>\n\
+        <p>Homepage: <a href=\"https://pagure.io/pagure\">https://pagure.io/pagure</a></p>\n\
+        <p>See it at work: <a href=\"https://pagure.io\">https://pagure.io</a></p>\n\
+        <p>Playground version: <a href=\"https://stg.pagure.io\">https://stg.pagure.io</a></p>\n\
+        </div>\n<div class=\"section\">\n<h1>Get it running</h1>\n<p>There are several\
+        \ options when it comes to a development environment. Vagrant\nwill provide\
+        \ you with a virtual machine which you can develop on, or you can\ninstall\
+        \ it directly on your host machine.</p>\n<div class=\"section\">\n<h2>Vagrant</h2>\n\
+        <p>For a more thorough introduction to Vagrant, see\n<a href=\"https://fedoraproject.org/wiki/Vagrant\"\
+        >https://fedoraproject.org/wiki/Vagrant</a>.</p>\n<p>An example Vagrantfile\
+        \ is provided as <code>Vagrantfile.example</code>. To use it,\njust copy it\
+        \ and install Vagrant:</p>\n<pre>$ cp dev/Vagrantfile.example Vagrantfile\n\
+        $ sudo dnf install ansible libvirt vagrant-libvirt vagrant-sshfs vagrant-hostmanager\n\
+        $ vagrant up\n</pre>\n<p>The default <code>Vagrantfile</code> forwards ports\
+        \ from the host to the guest,\nso you can interact with the application as\
+        \ if it were running on your\nhost machine.</p>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p><code><span class=\"pre\">vagrant-hostmanager</span></code> will automatically\
+        \ maintain /etc/hosts for you so you\ncan access the development environment\
+        \ from the host using its hostname, which\nby default is <code><span class=\"\
+        pre\">pagure-dev.example.com</span></code>. You can choose not to use this\n\
+        functionality by simply not installing the <code><span class=\"pre\">vagrant-hostmanager</span></code>\
+        \ plugin, but\nif you want Pagure to provide valid URLs in the UI for git\
+        \ repositories, you\nwill need to adjust Pagure's configuration found in ~/pagure.cfg\
+        \ on the guest.</p>\n</div>\n</div>\n<div class=\"section\">\n<h2>Manually</h2>\n\
+        <ul>\n<li><p>Install the needed system libraries:</p>\n<pre>sudo dnf install\
+        \ git python2-virtualenv libgit2-devel \\\n                 libjpeg-devel\
+        \ gcc libffi-devel redhat-rpm-config\n</pre>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p>Do note the version of libgit2 that you install, for example\nin <code><span\
+        \ class=\"pre\">libgit2-0.23.4-1</span></code> you need to keep in mind the\
+        \ <code>0.23</code></p>\n</div>\n<div class=\"note\">\n<p>Note</p>\n<p>On\
+        \ Fedora 23 and earlier or on RHEL and derivative (CentOS,\nScientific Linux)\
+        \ the package <cite>python2-virtualenv</cite> is named\n<cite>python-virtualenv</cite></p>\n\
+        </div>\n</li>\n<li><p>Retrieve the sources:</p>\n<pre>git clone https://pagure.io/pagure.git\n\
+        cd pagure\n</pre>\n</li>\n<li><p>Install dependencies</p>\n<ul>\n<li><p>create\
+        \ the virtualenv:</p>\n<pre>virtualenv pagure_env\nsource ./pagure_env/bin/activate\n\
+        </pre>\n</li>\n<li><p>Install the correct version of pygit2:</p>\n<pre>pip\
+        \ install pygit2==&lt;version of libgit2 found&gt;.*\n</pre>\n<p>So in our\
+        \ example:</p>\n<pre>pip install pygit2==0.23.*\n</pre>\n</li>\n<li><p>Install\
+        \ the rest of the dependencies:</p>\n<pre>pip install -r requirements.txt\n\
+        </pre>\n</li>\n</ul>\n</li>\n<li><p>Create the folder that will receive the\
+        \ projects, forks, docs, requests and\ntickets' git repo:</p>\n<pre>mkdir\
+        \ -p lcl/{repos,docs,forks,tickets,requests,remotes,attachments,releases}\n\
+        </pre>\n</li>\n<li><p>Create the inital database scheme:</p>\n<pre>python\
+        \ createdb.py\n</pre>\n</li>\n<li><p>Start a worker, in one terminal:</p>\n\
+        <pre>./runworker.py\n</pre>\n</li>\n<li><p>Run the application, in another\
+        \ terminal:</p>\n<pre>./runserver.py\n</pre>\n</li>\n<li><p>To get some profiling\
+        \ information you can also run it as:</p>\n<pre>./runserver.py --profile\n\
+        </pre>\n</li>\n</ul>\n<p>This will launch the application at <a href=\"http://127.0.0.1:5000\"\
+        >http://127.0.0.1:5000</a></p>\n<ul>\n<li><p>To run unit-tests on pagure</p>\n\
+        <ul>\n<li><p>Install the dependencies:</p>\n<pre>pip install -r tests_requirements.txt\n\
+        </pre>\n</li>\n<li><p>Run it:</p>\n<pre>./runtests.sh\n</pre>\n<div class=\"\
+        note\">\n<p>Note</p>\n<p>While testing for worker tasks, pagure uses celery\
+        \ in /usr/bin/\nCelery then looks for eventlet (which we use for testing only)\
+        \ at\nsystem level and not in virtualenv. You will need to install eventlet\n\
+        outside of your virtualenv if you are using one.</p>\n</div>\n</li>\n</ul>\n\
+        </li>\n</ul>\n</div>\n</div>\n</div>\n\n            </section>\n        </div>\n\
+        \      <div class=\"col-md-4\">\n        <div class=\"card\">\n          <div\
+        \ class=\"card-block\">\n            <h5><strong>Contributors</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/pingou\">\n                  <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \               -  main admin\n              </div>\n                  <div>\n\
+        \                    <a href=\"/user/ryanlerch\">\n                      <img\
+        \ class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                      Ryan Lerch (ryanlerch)\n                    </a>\n\
+        \                    - admin\n                  </div>\n                 \
+        \ <div>\n                    <a href=\"/user/puiterwijk\">\n             \
+        \         <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/85f8b5f58b9808429ad69ba3722d64da01ce850635e348e838dfdc053e1140e3?s=20&d=retro\"\
+        />\n                      Patrick &#34;\u30DE\u30EB\u30BF\u30A4\u30F3\u30A2\
+        \u30F3\u30C9\u30EC\u30A2\u30B9&#34; Uiterwijk (puiterwijk)\n             \
+        \       </a>\n                    - commit\n                  </div>\n   \
+        \               <div>\n                    <a href=\"/user/vivekanand1101\"\
+        >\n                      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                      Vivek Anand (vivekanand1101)\n                 \
+        \   </a>\n                    - ticket\n                  </div>\n       \
+        \           <div>\n                    <a href=\"/user/farhaan\">\n      \
+        \                <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b681ddfaffa293b03c57e5f0ed90eb1e06a8f748f4dccdccef8cdd301c66c9ae?s=20&d=retro\"\
+        />\n                      Farhaan Bukhsh (farhaan)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/cverna\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/c7844b93c43c862adaa29920c09bdfb91efed57a843203e5d0b72673e664c003?s=20&d=retro\"\
+        />\n                      Clement Verna (cverna)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/jcline\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                      Jeremy Cline (jcline)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/lslebodn\">\n              \
+        \        <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/8c6fcfe0eec099f1f01f5c237935bb5c97f2063a5c1068e57c5815e0bfecbf70?s=20&d=retro\"\
+        />\n                      Lukas Slebodnik (lslebodn)\n                   \
+        \ </a>\n                    - ticket\n                  </div>\n         \
+        \         <div>\n                    <a href=\"/user/mprahl\">\n         \
+        \             <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/ecae5ad9b37619a38e699de00049e449f120b433c9f26a8beb05b990dfc54c9d?s=20&d=retro\"\
+        />\n                      Matt Prahl (mprahl)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n            </div>\n\
+        \            <h5><strong>Branches</strong></h5>\n            <div class=\"\
+        m-b-2\">\n              <div id=\"branch-master\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"\n          \
+        \          title=\"Default branch\"></span>\n                  <strong title=\"\
+        Currently viewing branch master\" data-toggle=\"tooltip\">master</strong>\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"star\"\n \
+        \                   title=\"Default branch\"></span>\n                </div>\n\
+        \              </div>\n\n              <div id=\"branch-2.9.x\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/2.9.x\"\n           \
+        \         title=\"2.9.x\" data-toggle=\"tooltip\">2.9.x\n                \
+        \  </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-alembic_changes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/alembic_changes\"\n        \
+        \            title=\"alembic_changes\" data-toggle=\"tooltip\">alembic_changes\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-confirm_merge\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/confirm_merge\"\n   \
+        \                 title=\"confirm_merge\" data-toggle=\"tooltip\">confirm_merge\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-css_tables\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/css_tables\"\n      \
+        \              title=\"css_tables\" data-toggle=\"tooltip\">css_tables\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_del_project\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_del_project\"\n \
+        \                   title=\"fix_del_project\" data-toggle=\"tooltip\">fix_del_project\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_delete\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_delete\"\n      \
+        \              title=\"fix_delete\" data-toggle=\"tooltip\">fix_delete\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_diff_refs\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_diff_refs\"\n   \
+        \                 title=\"fix_diff_refs\" data-toggle=\"tooltip\">fix_diff_refs\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_doc\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_doc\"\n                \
+        \    title=\"fix_doc\" data-toggle=\"tooltip\">fix_doc\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_linking\" class=\"repoinfo-branchlistitem row\">\n\
+        \                <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/fix_linking\"\n                   \
+        \ title=\"fix_linking\" data-toggle=\"tooltip\">fix_linking\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_pygit_error\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_pygit_error\"\n        \
+        \            title=\"fix_pygit_error\" data-toggle=\"tooltip\">fix_pygit_error\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_reply_to\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_reply_to\"\n    \
+        \                title=\"fix_reply_to\" data-toggle=\"tooltip\">fix_reply_to\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_sse\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse\"\n                \
+        \    title=\"fix_sse\" data-toggle=\"tooltip\">fix_sse\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_sse_status\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse_status\"\n         \
+        \           title=\"fix_sse_status\" data-toggle=\"tooltip\">fix_sse_status\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_templates\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_templates\"\n   \
+        \                 title=\"fix_templates\" data-toggle=\"tooltip\">fix_templates\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fixes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fixes\"\n                  \
+        \  title=\"fixes\" data-toggle=\"tooltip\">fixes\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-force_flag\" class=\"repoinfo-branchlistitem row\">\n             \
+        \   <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/force_flag\"\n                    title=\"force_flag\"\
+        \ data-toggle=\"tooltip\">force_flag\n                  </a>\n\n         \
+        \       </div>\n                <div class=\"branch_del col-md-4\">\n    \
+        \            </div>\n              </div>\n              <div id=\"branch-gpg_check\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/gpg_check\"\
+        \n                    title=\"gpg_check\" data-toggle=\"tooltip\">gpg_check\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-logging_milter\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/logging_milter\"\n  \
+        \                  title=\"logging_milter\" data-toggle=\"tooltip\">logging_milter\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-mirroring\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/mirroring\"\n              \
+        \      title=\"mirroring\" data-toggle=\"tooltip\">mirroring\n           \
+        \       </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-py3_work2\" class=\"repoinfo-branchlistitem row\">\n \
+        \               <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/py3_work2\"\n                    title=\"\
+        py3_work2\" data-toggle=\"tooltip\">py3_work2\n                  </a>\n\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-rel_2.2.z\" class=\"repoinfo-branchlistitem row\">\n              \
+        \  <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/rel_2.2.z\"\n                    title=\"rel_2.2.z\"\
+        \ data-toggle=\"tooltip\">rel_2.2.z\n                  </a>\n\n          \
+        \      </div>\n                <div class=\"branch_del col-md-4\">\n     \
+        \           </div>\n              </div>\n              <div id=\"branch-rel_2.3.z\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/rel_2.3.z\"\
+        \n                    title=\"rel_2.3.z\" data-toggle=\"tooltip\">rel_2.3.z\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-scroll_metadata\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/scroll_metadata\"\n \
+        \                   title=\"scroll_metadata\" data-toggle=\"tooltip\">scroll_metadata\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-utf_search\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/utf_search\"\n      \
+        \              title=\"utf_search\" data-toggle=\"tooltip\">utf_search\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \         </div>\n            <h5><strong>Source GIT URLs</strong>       \
+        \           <span class=\"pull-xs-right\"><a data-toggle=\"collapse\" href=\"\
+        #moregiturls\"\n                  aria-expanded=\"false\" aria-controls=\"\
+        moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n \
+        \           <div>\n              <div class=\"form-group\">\n            \
+        \    <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">GIT</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"https://pagure.io/pagure.git\" readonly>\n       \
+        \         </div>\n              </div>\n              <div class=\"collapse\"\
+        \ id=\"moregiturls\">\n                  <h5><strong>Docs GIT URLs</strong></h5>\n\
+        \                  <div class=\"form-group\">\n                    <div class=\"\
+        input-group input-group-sm\">\n                      <div class=\"input-group-addon\"\
+        >GIT</div>\n                      <input class=\"form-control\" type=\"text\"\
+        \ value=\"https://pagure.io/docs/pagure.git\" readonly>\n                \
+        \    </div>\n                  </div>\n              </div>\n            </div>\n\
+        \          </div>\n          <div class=\"repo_date\" title=\"2015-05-13 20:38:10.552662\"\
+        >\n              created 2 years ago\n          </div>\n        </div>\n\n\
+        \          <div class=\"card\">\n            <div class=\"card-header\">\n\
+        \              <strong>Recent Commits in\n                <span class=\"pr-toplabel\"\
+        >\n                  <span class=\"oi\" data-glyph=\"random\"></span>\n  \
+        \                master\n                </span>\n              </strong>\n\
+        \            </div>\n            <div class=\"card-block p-a-0\">\n      \
+        \        <div class=\"list-group list-group-flush\">\n                  <a\
+        \ href=\"/pagure/c/a324b4120738bb9765b59625f3e767f9b50d599f\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Sep 25 2017 12:50:46\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 2 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Fix the unit-tests\n                    </small></div>\n\
+        \                  </a>\n                  <a href=\"/pagure/c/ef569a5160891b30cc2aa4d614b39f4a266d7ad7\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Sep 21 2017 12:15:51\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                          Vivek Anand\n                        </strong>\n\
+        \                        commited 5 days ago\n                      </small>\n\
+        \                    </div>\n                    <div><small>\n          \
+        \            give project: generate gitolite acls after giving a project\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/pagure/c/16c5781815d4695fe89db3c5cec5191dc1b81c6f\" class=\"\
+        list-group-item\">\n                    <div class=\"commitdate\" title=\"\
+        Sep 21 2017 10:26:39\">\n                      <small>\n                 \
+        \       <strong>\n                          <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                          Vivek Anand\n                        </strong>\n\
+        \                        commited 6 days ago\n                      </small>\n\
+        \                    </div>\n                    <div><small>\n          \
+        \            read only repo: Add unit test for update_read_only_mode method\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          3.7.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage/index.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/vendor/jquery/jquery.min.js\">\n    </script>\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/vendor/jquery-ui/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n        var currentWatchStatusButton\
+        \ = $('#unwatch_button');\n    currentWatchStatusButton.prepend('<span class=\"\
+        oi\" data-glyph=\"circle-check\" style=\"padding-right:0.5em\"></span>');\n\
+        \    $('.watch-menu a').not(currentWatchStatusButton).css('padding-left',\
+        \ '2.85em');\n\n    $(\".watch-menu a\").click(function(){\n        var selectedValue\
+        \ = $(this).attr('id');\n        var watchProjectForm = $(\"#watch_project\"\
+        );\n        var action = watchProjectForm.attr('action');\n\n        if (selectedValue\
+        \ === \"watch_issues_button\") {\n            action = action.replace('/settings/0',\
+        \ '/settings/1');\n        } else if (selectedValue === \"watch_commits_button\"\
+        ) {\n            action = action.replace('/settings/0', '/settings/2');\n\
+        \        } else if (selectedValue === \"watch_issues_commits_button\") {\n\
+        \            action = action.replace('/settings/0', '/settings/3');\n    \
+        \    } else if (selectedValue === \"reset_button\") {\n            action\
+        \ = action.replace('/settings/0', '/settings/-1');\n        }\n\n        watchProjectForm.attr('action',\
+        \ action);\n        watchProjectForm.submit();\n    });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      Connection: [Keep-Alive]
+      Content-Length: ['31644']
+      Content-Type: [text/html; charset=utf-8]
+      Date: ['Wed, 27 Sep 2017 12:07:33 GMT']
+      Keep-Alive: ['timeout=5, max=100']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      Set-Cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiT1daa01tWTBOak01WkRCak5ESXlaR1EzTmprNE5qSmpPVGRsTkRSaFlUazJNV0UxWXpZMk5RPT0ifX0.DK0mBQ.zItnVKliuOGIIH4LSzZAPjrw0HY;
+          Expires=Sat, 28-Oct-2017 12:07:33 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_post_valid_widget_name_no_config b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_post_valid_widget_name_no_config
new file mode 100644
index 0000000..cad3a65
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_post_valid_widget_name_no_config
@@ -0,0 +1,450 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://pagure.io/pagure
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - pagure - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\"\
+        \n        href=\"/static/favicon.ico\"/>\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/vendor/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/vendor/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/pagure git https://pagure.io/pagure.git\">\n  </head>\n\
+        \  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"masthead\"\
+        >\n      <div class=\"container\">\n        <div class=\"row\">\n        \
+        \  <div class=\"col-sm-3\">\n            <a href=\"/\">\n              <img\
+        \ height=40px src=\"/static/pagure-logo.png\"\n                alt=\"pagure\
+        \ Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n       \
+        \   <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav class=\"\
+        navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\">\n    \
+        \    <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n         \
+        \     <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link btn\
+        \ btn-primary\" href=\"/login/?next=https://pagure.io/pagure\">Log In</a>\n\
+        \              </li>\n        </ul>\n      </div>\n    </nav>\n\n        \
+        \    </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n<a href=\"/pagure\">pagure</a>\n        </h2>\n\
+        \        <div class=\"projectinfo m-t-1 m-b-1\">\nA git centered forge &nbsp;|\
+        \ &nbsp;<a class=\"inline\" href=\"https://pagure.io\">https://pagure.io</a>\
+        \        </div>\n\n    </header>\n    <ul class=\"nav nav-tabs nav-small\"\
+        >\n      <li class=\"nav-item\">\n        <a class=\"nav-link active\" href=\"\
+        /pagure\">\n            <span class=\"oi hidden-md-up\" data-glyph=\"home\"\
+        ></span>\n            <span class=\"hidden-sm-down\">Overview</span>\n   \
+        \     </a>\n      </li>\n        <li class=\"nav-item\" >\n          <a  class=\"\
+        nav-link\" href=\"/docs/pagure/\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"book\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Docs</span>\n          </a>\n        </li>\n\n        <li class=\"nav-item\"\
+        >\n          <a class=\"nav-link\" href=\"/pagure/commits/master\">\n    \
+        \          <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n \
+        \             </span><span class=\"hidden-sm-down\">Commits</span>\n     \
+        \       </a>\n        </li>\n\n        <li class=\"nav-item\">\n         \
+        \ <a class=\"nav-link\" href=\"/pagure/tree/master\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/pagure/issues\">\n                <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n             \
+        \   <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n                <span\
+        \ class=\"label label-default label-pill hidden-sm-down\">\n             \
+        \     339\n                </span>\n            </a>\n        </li>\n\n  \
+        \      <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"/pagure/pull-requests\"\
+        >\n              <span class=\"oi hidden-md-up\" data-glyph=\"task\"></span>\n\
+        \              <span class=\"hidden-sm-down\">Pull Requests&nbsp;</span>\n\
+        \              <span class=\"label label-default label-pill hidden-sm-down\"\
+        >\n                16\n              </span>\n          </a>\n        </li>\n\
+        \n        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/forks\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        fork\"></span>\n              <span class=\"hidden-sm-down\">Forks&nbsp;</span>\n\
+        \              <span class=\"hidden-sm-down label label-default label-pill\"\
+        >\n                131\n              </span>\n            </a>\n        </li>\n\
+        \n\n    </ul>\n  </div>\n</div>\n\n<div class=\"container p-t-3\">\n  <div\
+        \ class=\"row\">\n        <div class=\"col-md-8\">\n            <section class=\"\
+        readme\">\n              <div class=\"document\">\n<div class=\"section\"\
+        >\n<h1>Pagure</h1>\n<table class=\"docutils field-list\">\n<colgroup><col>\n\
+        <col>\n</colgroup><tbody>\n<tr><th>Author:</th><td>Pierre-Yves Chibon &lt;<a\
+        \ href=\"mailto:pingou@pingoured.fr\">pingou@pingoured.fr</a>&gt;</td>\n</tr>\n\
+        </tbody>\n</table>\n<p>Pagure is a git-centered forge, python based using\
+        \ pygit2.</p>\n<p>With pagure you can host your project with its documentation,\
+        \ let your users\nreport issues or request enhancements using the ticketing\
+        \ system and build your\ncommunity of contributors by allowing them to fork\
+        \ your projects and contribute\nto it via the now-popular pull-request mechanism.</p>\n\
+        <p>Homepage: <a href=\"https://pagure.io/pagure\">https://pagure.io/pagure</a></p>\n\
+        <p>See it at work: <a href=\"https://pagure.io\">https://pagure.io</a></p>\n\
+        <p>Playground version: <a href=\"https://stg.pagure.io\">https://stg.pagure.io</a></p>\n\
+        </div>\n<div class=\"section\">\n<h1>Get it running</h1>\n<p>There are several\
+        \ options when it comes to a development environment. Vagrant\nwill provide\
+        \ you with a virtual machine which you can develop on, or you can\ninstall\
+        \ it directly on your host machine.</p>\n<div class=\"section\">\n<h2>Vagrant</h2>\n\
+        <p>For a more thorough introduction to Vagrant, see\n<a href=\"https://fedoraproject.org/wiki/Vagrant\"\
+        >https://fedoraproject.org/wiki/Vagrant</a>.</p>\n<p>An example Vagrantfile\
+        \ is provided as <code>Vagrantfile.example</code>. To use it,\njust copy it\
+        \ and install Vagrant:</p>\n<pre>$ cp dev/Vagrantfile.example Vagrantfile\n\
+        $ sudo dnf install ansible libvirt vagrant-libvirt vagrant-sshfs vagrant-hostmanager\n\
+        $ vagrant up\n</pre>\n<p>The default <code>Vagrantfile</code> forwards ports\
+        \ from the host to the guest,\nso you can interact with the application as\
+        \ if it were running on your\nhost machine.</p>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p><code><span class=\"pre\">vagrant-hostmanager</span></code> will automatically\
+        \ maintain /etc/hosts for you so you\ncan access the development environment\
+        \ from the host using its hostname, which\nby default is <code><span class=\"\
+        pre\">pagure-dev.example.com</span></code>. You can choose not to use this\n\
+        functionality by simply not installing the <code><span class=\"pre\">vagrant-hostmanager</span></code>\
+        \ plugin, but\nif you want Pagure to provide valid URLs in the UI for git\
+        \ repositories, you\nwill need to adjust Pagure's configuration found in ~/pagure.cfg\
+        \ on the guest.</p>\n</div>\n</div>\n<div class=\"section\">\n<h2>Manually</h2>\n\
+        <ul>\n<li><p>Install the needed system libraries:</p>\n<pre>sudo dnf install\
+        \ git python2-virtualenv libgit2-devel \\\n                 libjpeg-devel\
+        \ gcc libffi-devel redhat-rpm-config\n</pre>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p>Do note the version of libgit2 that you install, for example\nin <code><span\
+        \ class=\"pre\">libgit2-0.23.4-1</span></code> you need to keep in mind the\
+        \ <code>0.23</code></p>\n</div>\n<div class=\"note\">\n<p>Note</p>\n<p>On\
+        \ Fedora 23 and earlier or on RHEL and derivative (CentOS,\nScientific Linux)\
+        \ the package <cite>python2-virtualenv</cite> is named\n<cite>python-virtualenv</cite></p>\n\
+        </div>\n</li>\n<li><p>Retrieve the sources:</p>\n<pre>git clone https://pagure.io/pagure.git\n\
+        cd pagure\n</pre>\n</li>\n<li><p>Install dependencies</p>\n<ul>\n<li><p>create\
+        \ the virtualenv:</p>\n<pre>virtualenv pagure_env\nsource ./pagure_env/bin/activate\n\
+        </pre>\n</li>\n<li><p>Install the correct version of pygit2:</p>\n<pre>pip\
+        \ install pygit2==&lt;version of libgit2 found&gt;.*\n</pre>\n<p>So in our\
+        \ example:</p>\n<pre>pip install pygit2==0.23.*\n</pre>\n</li>\n<li><p>Install\
+        \ the rest of the dependencies:</p>\n<pre>pip install -r requirements.txt\n\
+        </pre>\n</li>\n</ul>\n</li>\n<li><p>Create the folder that will receive the\
+        \ projects, forks, docs, requests and\ntickets' git repo:</p>\n<pre>mkdir\
+        \ -p lcl/{repos,docs,forks,tickets,requests,remotes,attachments,releases}\n\
+        </pre>\n</li>\n<li><p>Create the inital database scheme:</p>\n<pre>python\
+        \ createdb.py\n</pre>\n</li>\n<li><p>Start a worker, in one terminal:</p>\n\
+        <pre>./runworker.py\n</pre>\n</li>\n<li><p>Run the application, in another\
+        \ terminal:</p>\n<pre>./runserver.py\n</pre>\n</li>\n<li><p>To get some profiling\
+        \ information you can also run it as:</p>\n<pre>./runserver.py --profile\n\
+        </pre>\n</li>\n</ul>\n<p>This will launch the application at <a href=\"http://127.0.0.1:5000\"\
+        >http://127.0.0.1:5000</a></p>\n<ul>\n<li><p>To run unit-tests on pagure</p>\n\
+        <ul>\n<li><p>Install the dependencies:</p>\n<pre>pip install -r tests_requirements.txt\n\
+        </pre>\n</li>\n<li><p>Run it:</p>\n<pre>./runtests.sh\n</pre>\n<div class=\"\
+        note\">\n<p>Note</p>\n<p>While testing for worker tasks, pagure uses celery\
+        \ in /usr/bin/\nCelery then looks for eventlet (which we use for testing only)\
+        \ at\nsystem level and not in virtualenv. You will need to install eventlet\n\
+        outside of your virtualenv if you are using one.</p>\n</div>\n</li>\n</ul>\n\
+        </li>\n</ul>\n</div>\n</div>\n</div>\n\n            </section>\n        </div>\n\
+        \      <div class=\"col-md-4\">\n        <div class=\"card\">\n          <div\
+        \ class=\"card-block\">\n            <h5><strong>Contributors</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/pingou\">\n                  <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \               -  main admin\n              </div>\n                  <div>\n\
+        \                    <a href=\"/user/ryanlerch\">\n                      <img\
+        \ class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                      Ryan Lerch (ryanlerch)\n                    </a>\n\
+        \                    - admin\n                  </div>\n                 \
+        \ <div>\n                    <a href=\"/user/puiterwijk\">\n             \
+        \         <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/85f8b5f58b9808429ad69ba3722d64da01ce850635e348e838dfdc053e1140e3?s=20&d=retro\"\
+        />\n                      Patrick &#34;\u30DE\u30EB\u30BF\u30A4\u30F3\u30A2\
+        \u30F3\u30C9\u30EC\u30A2\u30B9&#34; Uiterwijk (puiterwijk)\n             \
+        \       </a>\n                    - commit\n                  </div>\n   \
+        \               <div>\n                    <a href=\"/user/vivekanand1101\"\
+        >\n                      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                      Vivek Anand (vivekanand1101)\n                 \
+        \   </a>\n                    - ticket\n                  </div>\n       \
+        \           <div>\n                    <a href=\"/user/farhaan\">\n      \
+        \                <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b681ddfaffa293b03c57e5f0ed90eb1e06a8f748f4dccdccef8cdd301c66c9ae?s=20&d=retro\"\
+        />\n                      Farhaan Bukhsh (farhaan)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/cverna\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/c7844b93c43c862adaa29920c09bdfb91efed57a843203e5d0b72673e664c003?s=20&d=retro\"\
+        />\n                      Clement Verna (cverna)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/jcline\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                      Jeremy Cline (jcline)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/lslebodn\">\n              \
+        \        <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/8c6fcfe0eec099f1f01f5c237935bb5c97f2063a5c1068e57c5815e0bfecbf70?s=20&d=retro\"\
+        />\n                      Lukas Slebodnik (lslebodn)\n                   \
+        \ </a>\n                    - ticket\n                  </div>\n         \
+        \         <div>\n                    <a href=\"/user/mprahl\">\n         \
+        \             <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/ecae5ad9b37619a38e699de00049e449f120b433c9f26a8beb05b990dfc54c9d?s=20&d=retro\"\
+        />\n                      Matt Prahl (mprahl)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n            </div>\n\
+        \            <h5><strong>Branches</strong></h5>\n            <div class=\"\
+        m-b-2\">\n              <div id=\"branch-master\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"\n          \
+        \          title=\"Default branch\"></span>\n                  <strong title=\"\
+        Currently viewing branch master\" data-toggle=\"tooltip\">master</strong>\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"star\"\n \
+        \                   title=\"Default branch\"></span>\n                </div>\n\
+        \              </div>\n\n              <div id=\"branch-2.9.x\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/2.9.x\"\n           \
+        \         title=\"2.9.x\" data-toggle=\"tooltip\">2.9.x\n                \
+        \  </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-alembic_changes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/alembic_changes\"\n        \
+        \            title=\"alembic_changes\" data-toggle=\"tooltip\">alembic_changes\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-confirm_merge\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/confirm_merge\"\n   \
+        \                 title=\"confirm_merge\" data-toggle=\"tooltip\">confirm_merge\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-css_tables\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/css_tables\"\n      \
+        \              title=\"css_tables\" data-toggle=\"tooltip\">css_tables\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_del_project\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_del_project\"\n \
+        \                   title=\"fix_del_project\" data-toggle=\"tooltip\">fix_del_project\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_delete\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_delete\"\n      \
+        \              title=\"fix_delete\" data-toggle=\"tooltip\">fix_delete\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_diff_refs\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_diff_refs\"\n   \
+        \                 title=\"fix_diff_refs\" data-toggle=\"tooltip\">fix_diff_refs\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_doc\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_doc\"\n                \
+        \    title=\"fix_doc\" data-toggle=\"tooltip\">fix_doc\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_linking\" class=\"repoinfo-branchlistitem row\">\n\
+        \                <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/fix_linking\"\n                   \
+        \ title=\"fix_linking\" data-toggle=\"tooltip\">fix_linking\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_pygit_error\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_pygit_error\"\n        \
+        \            title=\"fix_pygit_error\" data-toggle=\"tooltip\">fix_pygit_error\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_reply_to\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_reply_to\"\n    \
+        \                title=\"fix_reply_to\" data-toggle=\"tooltip\">fix_reply_to\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_sse\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse\"\n                \
+        \    title=\"fix_sse\" data-toggle=\"tooltip\">fix_sse\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_sse_status\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse_status\"\n         \
+        \           title=\"fix_sse_status\" data-toggle=\"tooltip\">fix_sse_status\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_templates\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_templates\"\n   \
+        \                 title=\"fix_templates\" data-toggle=\"tooltip\">fix_templates\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fixes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fixes\"\n                  \
+        \  title=\"fixes\" data-toggle=\"tooltip\">fixes\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-force_flag\" class=\"repoinfo-branchlistitem row\">\n             \
+        \   <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/force_flag\"\n                    title=\"force_flag\"\
+        \ data-toggle=\"tooltip\">force_flag\n                  </a>\n\n         \
+        \       </div>\n                <div class=\"branch_del col-md-4\">\n    \
+        \            </div>\n              </div>\n              <div id=\"branch-gpg_check\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/gpg_check\"\
+        \n                    title=\"gpg_check\" data-toggle=\"tooltip\">gpg_check\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-logging_milter\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/logging_milter\"\n  \
+        \                  title=\"logging_milter\" data-toggle=\"tooltip\">logging_milter\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-mirroring\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/mirroring\"\n              \
+        \      title=\"mirroring\" data-toggle=\"tooltip\">mirroring\n           \
+        \       </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-py3_work2\" class=\"repoinfo-branchlistitem row\">\n \
+        \               <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/py3_work2\"\n                    title=\"\
+        py3_work2\" data-toggle=\"tooltip\">py3_work2\n                  </a>\n\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-rel_2.2.z\" class=\"repoinfo-branchlistitem row\">\n              \
+        \  <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/rel_2.2.z\"\n                    title=\"rel_2.2.z\"\
+        \ data-toggle=\"tooltip\">rel_2.2.z\n                  </a>\n\n          \
+        \      </div>\n                <div class=\"branch_del col-md-4\">\n     \
+        \           </div>\n              </div>\n              <div id=\"branch-rel_2.3.z\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/rel_2.3.z\"\
+        \n                    title=\"rel_2.3.z\" data-toggle=\"tooltip\">rel_2.3.z\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-scroll_metadata\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/scroll_metadata\"\n \
+        \                   title=\"scroll_metadata\" data-toggle=\"tooltip\">scroll_metadata\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-utf_search\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/utf_search\"\n      \
+        \              title=\"utf_search\" data-toggle=\"tooltip\">utf_search\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \         </div>\n            <h5><strong>Source GIT URLs</strong>       \
+        \           <span class=\"pull-xs-right\"><a data-toggle=\"collapse\" href=\"\
+        #moregiturls\"\n                  aria-expanded=\"false\" aria-controls=\"\
+        moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n \
+        \           <div>\n              <div class=\"form-group\">\n            \
+        \    <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">GIT</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"https://pagure.io/pagure.git\" readonly>\n       \
+        \         </div>\n              </div>\n              <div class=\"collapse\"\
+        \ id=\"moregiturls\">\n                  <h5><strong>Docs GIT URLs</strong></h5>\n\
+        \                  <div class=\"form-group\">\n                    <div class=\"\
+        input-group input-group-sm\">\n                      <div class=\"input-group-addon\"\
+        >GIT</div>\n                      <input class=\"form-control\" type=\"text\"\
+        \ value=\"https://pagure.io/docs/pagure.git\" readonly>\n                \
+        \    </div>\n                  </div>\n              </div>\n            </div>\n\
+        \          </div>\n          <div class=\"repo_date\" title=\"2015-05-13 20:38:10.552662\"\
+        >\n              created 2 years ago\n          </div>\n        </div>\n\n\
+        \          <div class=\"card\">\n            <div class=\"card-header\">\n\
+        \              <strong>Recent Commits in\n                <span class=\"pr-toplabel\"\
+        >\n                  <span class=\"oi\" data-glyph=\"random\"></span>\n  \
+        \                master\n                </span>\n              </strong>\n\
+        \            </div>\n            <div class=\"card-block p-a-0\">\n      \
+        \        <div class=\"list-group list-group-flush\">\n                  <a\
+        \ href=\"/pagure/c/75b9021afbb08a3bdc1128cb282ea9c2394c0b67\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Sep 21 2017 08:20:29\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Add unit-tests for the fixes around loading issue template\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/pagure/c/fc1d7f885d8b658ce7ba2fbd9cf20692b32f7732\" class=\"\
+        list-group-item\">\n                    <div class=\"commitdate\" title=\"\
+        Sep 21 2017 08:20:29\">\n                      <small>\n                 \
+        \       <strong>\n                          <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Flake8 fix fixing the tests\n                    </small></div>\n\
+        \                  </a>\n                  <a href=\"/pagure/c/91c1f357adc77f0b21e15f6177c68ffc97f3ec67\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Sep 21 2017 08:20:29\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Adjust the documentation around ticket templates\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          3.7.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage/index.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/vendor/jquery/jquery.min.js\">\n    </script>\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/vendor/jquery-ui/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n        var currentWatchStatusButton\
+        \ = $('#unwatch_button');\n    currentWatchStatusButton.prepend('<span class=\"\
+        oi\" data-glyph=\"circle-check\" style=\"padding-right:0.5em\"></span>');\n\
+        \    $('.watch-menu a').not(currentWatchStatusButton).css('padding-left',\
+        \ '2.85em');\n\n    $(\".watch-menu a\").click(function(){\n        var selectedValue\
+        \ = $(this).attr('id');\n        var watchProjectForm = $(\"#watch_project\"\
+        );\n        var action = watchProjectForm.attr('action');\n\n        if (selectedValue\
+        \ === \"watch_issues_button\") {\n            action = action.replace('/settings/0',\
+        \ '/settings/1');\n        } else if (selectedValue === \"watch_commits_button\"\
+        ) {\n            action = action.replace('/settings/0', '/settings/2');\n\
+        \        } else if (selectedValue === \"watch_issues_commits_button\") {\n\
+        \            action = action.replace('/settings/0', '/settings/3');\n    \
+        \    } else if (selectedValue === \"reset_button\") {\n            action\
+        \ = action.replace('/settings/0', '/settings/-1');\n        }\n\n        watchProjectForm.attr('action',\
+        \ action);\n        watchProjectForm.submit();\n    });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      Connection: [Keep-Alive]
+      Content-Length: ['31652']
+      Content-Type: [text/html; charset=utf-8]
+      Date: ['Tue, 26 Sep 2017 15:29:38 GMT']
+      Keep-Alive: ['timeout=5, max=100']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      Set-Cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiWm1Ga09UUTJOR1ExT1RJeVlqRTBNbUV5TlRBMVlqa3lOakZrT0dRNU1tUTBaR000T0dJMk53PT0ifX0.DKwD4g.-AtNMHr2H1oGruvPTfjxzELawsw;
+          Expires=Fri, 27-Oct-2017 15:29:38 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_private_get b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_private_get
new file mode 100644
index 0000000..8119372
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_private_get
@@ -0,0 +1,450 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.12.5]
+    method: GET
+    uri: https://pagure.io/pagure
+  response:
+    body: {string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n    <meta http-equiv=\"\
+        Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <title>Overview\
+        \ - pagure - Pagure</title>\n    <link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\"\
+        \n        href=\"/static/favicon.ico\"/>\n    <link href=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/pagure.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/vendor/open-iconic/css/open-iconic.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <link href=\"/static/fonts/fonts.css\"\
+        \n        rel=\"stylesheet\" type=\"text/css\" />\n    <link href=\"/static/vendor/hack_fonts/css/hack-extended.min.css\"\
+        \n        type=\"text/css\" rel=\"stylesheet\" />\n    <meta name=\"go-import\"\
+        \ content=\"pagure.io/pagure git https://pagure.io/pagure.git\">\n  </head>\n\
+        \  <body id=\"home\">\n  <!-- start masthead -->\n    <div class=\"masthead\"\
+        >\n      <div class=\"container\">\n        <div class=\"row\">\n        \
+        \  <div class=\"col-sm-3\">\n            <a href=\"/\">\n              <img\
+        \ height=40px src=\"/static/pagure-logo.png\"\n                alt=\"pagure\
+        \ Logo\" id=\"pagureLogo\"/>\n            </a>\n          </div>\n       \
+        \   <div class=\"col-sm-9\">\n            <div class=\"row\">\n\n  <nav class=\"\
+        navbar navbar-light p-t-0 p-b-0\">\n      <div class=\"container\">\n    \
+        \    <ul class=\"nav navbar-nav nav-underline pull-xs-right\">\n         \
+        \     <li class=\"nav-item p-l-1\">\n                <a class=\"nav-link btn\
+        \ btn-primary\" href=\"/login/?next=https://pagure.io/pagure\">Log In</a>\n\
+        \              </li>\n        </ul>\n      </div>\n    </nav>\n\n        \
+        \    </div>\n          </div>\n        </div>\n      </div>\n    </div><!--\
+        \ close masthead-->\n\n    <div class=\"bodycontent p-b-3\">\n\n\n<div class=\"\
+        repo-header p-t-1\">\n  <div class=\"container\">\n    <header>\n      <h2\
+        \ class=\"repo-name m-b-0\">\n<a href=\"/pagure\">pagure</a>\n        </h2>\n\
+        \        <div class=\"projectinfo m-t-1 m-b-1\">\nA git centered forge &nbsp;|\
+        \ &nbsp;<a class=\"inline\" href=\"https://pagure.io\">https://pagure.io</a>\
+        \        </div>\n\n    </header>\n    <ul class=\"nav nav-tabs nav-small\"\
+        >\n      <li class=\"nav-item\">\n        <a class=\"nav-link active\" href=\"\
+        /pagure\">\n            <span class=\"oi hidden-md-up\" data-glyph=\"home\"\
+        ></span>\n            <span class=\"hidden-sm-down\">Overview</span>\n   \
+        \     </a>\n      </li>\n        <li class=\"nav-item\" >\n          <a  class=\"\
+        nav-link\" href=\"/docs/pagure/\">\n              <span class=\"oi hidden-md-up\"\
+        \ data-glyph=\"book\"></span>\n              <span class=\"hidden-sm-down\"\
+        >Docs</span>\n          </a>\n        </li>\n\n        <li class=\"nav-item\"\
+        >\n          <a class=\"nav-link\" href=\"/pagure/commits/master\">\n    \
+        \          <span class=\"oi hidden-md-up\" data-glyph=\"spreadsheet\">\n \
+        \             </span><span class=\"hidden-sm-down\">Commits</span>\n     \
+        \       </a>\n        </li>\n\n        <li class=\"nav-item\">\n         \
+        \ <a class=\"nav-link\" href=\"/pagure/tree/master\">\n              <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"file\"></span>\n              <span\
+        \ class=\"hidden-sm-down\">Files</span>\n          </a>\n        </li>\n\n\
+        \        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/releases\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        box\"></span>\n              <span class=\"hidden-sm-down\">Releases</span>\n\
+        \          </a>\n        </li>\n\n        <li class=\"nav-item\">\n      \
+        \      <a class=\"nav-link\" href=\"/pagure/issues\">\n                <span\
+        \ class=\"oi hidden-md-up\" data-glyph=\"warning\"></span>\n             \
+        \   <span class=\"hidden-sm-down\">Issues&nbsp;</span>\n                <span\
+        \ class=\"label label-default label-pill hidden-sm-down\">\n             \
+        \     339\n                </span>\n            </a>\n        </li>\n\n  \
+        \      <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"/pagure/pull-requests\"\
+        >\n              <span class=\"oi hidden-md-up\" data-glyph=\"task\"></span>\n\
+        \              <span class=\"hidden-sm-down\">Pull Requests&nbsp;</span>\n\
+        \              <span class=\"label label-default label-pill hidden-sm-down\"\
+        >\n                16\n              </span>\n          </a>\n        </li>\n\
+        \n        <li class=\"nav-item\">\n          <a class=\"nav-link\" href=\"\
+        /pagure/forks\">\n              <span class=\"oi hidden-md-up\" data-glyph=\"\
+        fork\"></span>\n              <span class=\"hidden-sm-down\">Forks&nbsp;</span>\n\
+        \              <span class=\"hidden-sm-down label label-default label-pill\"\
+        >\n                131\n              </span>\n            </a>\n        </li>\n\
+        \n\n    </ul>\n  </div>\n</div>\n\n<div class=\"container p-t-3\">\n  <div\
+        \ class=\"row\">\n        <div class=\"col-md-8\">\n            <section class=\"\
+        readme\">\n              <div class=\"document\">\n<div class=\"section\"\
+        >\n<h1>Pagure</h1>\n<table class=\"docutils field-list\">\n<colgroup><col>\n\
+        <col>\n</colgroup><tbody>\n<tr><th>Author:</th><td>Pierre-Yves Chibon &lt;<a\
+        \ href=\"mailto:pingou@pingoured.fr\">pingou@pingoured.fr</a>&gt;</td>\n</tr>\n\
+        </tbody>\n</table>\n<p>Pagure is a git-centered forge, python based using\
+        \ pygit2.</p>\n<p>With pagure you can host your project with its documentation,\
+        \ let your users\nreport issues or request enhancements using the ticketing\
+        \ system and build your\ncommunity of contributors by allowing them to fork\
+        \ your projects and contribute\nto it via the now-popular pull-request mechanism.</p>\n\
+        <p>Homepage: <a href=\"https://pagure.io/pagure\">https://pagure.io/pagure</a></p>\n\
+        <p>See it at work: <a href=\"https://pagure.io\">https://pagure.io</a></p>\n\
+        <p>Playground version: <a href=\"https://stg.pagure.io\">https://stg.pagure.io</a></p>\n\
+        </div>\n<div class=\"section\">\n<h1>Get it running</h1>\n<p>There are several\
+        \ options when it comes to a development environment. Vagrant\nwill provide\
+        \ you with a virtual machine which you can develop on, or you can\ninstall\
+        \ it directly on your host machine.</p>\n<div class=\"section\">\n<h2>Vagrant</h2>\n\
+        <p>For a more thorough introduction to Vagrant, see\n<a href=\"https://fedoraproject.org/wiki/Vagrant\"\
+        >https://fedoraproject.org/wiki/Vagrant</a>.</p>\n<p>An example Vagrantfile\
+        \ is provided as <code>Vagrantfile.example</code>. To use it,\njust copy it\
+        \ and install Vagrant:</p>\n<pre>$ cp dev/Vagrantfile.example Vagrantfile\n\
+        $ sudo dnf install ansible libvirt vagrant-libvirt vagrant-sshfs vagrant-hostmanager\n\
+        $ vagrant up\n</pre>\n<p>The default <code>Vagrantfile</code> forwards ports\
+        \ from the host to the guest,\nso you can interact with the application as\
+        \ if it were running on your\nhost machine.</p>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p><code><span class=\"pre\">vagrant-hostmanager</span></code> will automatically\
+        \ maintain /etc/hosts for you so you\ncan access the development environment\
+        \ from the host using its hostname, which\nby default is <code><span class=\"\
+        pre\">pagure-dev.example.com</span></code>. You can choose not to use this\n\
+        functionality by simply not installing the <code><span class=\"pre\">vagrant-hostmanager</span></code>\
+        \ plugin, but\nif you want Pagure to provide valid URLs in the UI for git\
+        \ repositories, you\nwill need to adjust Pagure's configuration found in ~/pagure.cfg\
+        \ on the guest.</p>\n</div>\n</div>\n<div class=\"section\">\n<h2>Manually</h2>\n\
+        <ul>\n<li><p>Install the needed system libraries:</p>\n<pre>sudo dnf install\
+        \ git python2-virtualenv libgit2-devel \\\n                 libjpeg-devel\
+        \ gcc libffi-devel redhat-rpm-config\n</pre>\n<div class=\"note\">\n<p>Note</p>\n\
+        <p>Do note the version of libgit2 that you install, for example\nin <code><span\
+        \ class=\"pre\">libgit2-0.23.4-1</span></code> you need to keep in mind the\
+        \ <code>0.23</code></p>\n</div>\n<div class=\"note\">\n<p>Note</p>\n<p>On\
+        \ Fedora 23 and earlier or on RHEL and derivative (CentOS,\nScientific Linux)\
+        \ the package <cite>python2-virtualenv</cite> is named\n<cite>python-virtualenv</cite></p>\n\
+        </div>\n</li>\n<li><p>Retrieve the sources:</p>\n<pre>git clone https://pagure.io/pagure.git\n\
+        cd pagure\n</pre>\n</li>\n<li><p>Install dependencies</p>\n<ul>\n<li><p>create\
+        \ the virtualenv:</p>\n<pre>virtualenv pagure_env\nsource ./pagure_env/bin/activate\n\
+        </pre>\n</li>\n<li><p>Install the correct version of pygit2:</p>\n<pre>pip\
+        \ install pygit2==&lt;version of libgit2 found&gt;.*\n</pre>\n<p>So in our\
+        \ example:</p>\n<pre>pip install pygit2==0.23.*\n</pre>\n</li>\n<li><p>Install\
+        \ the rest of the dependencies:</p>\n<pre>pip install -r requirements.txt\n\
+        </pre>\n</li>\n</ul>\n</li>\n<li><p>Create the folder that will receive the\
+        \ projects, forks, docs, requests and\ntickets' git repo:</p>\n<pre>mkdir\
+        \ -p lcl/{repos,docs,forks,tickets,requests,remotes,attachments,releases}\n\
+        </pre>\n</li>\n<li><p>Create the inital database scheme:</p>\n<pre>python\
+        \ createdb.py\n</pre>\n</li>\n<li><p>Start a worker, in one terminal:</p>\n\
+        <pre>./runworker.py\n</pre>\n</li>\n<li><p>Run the application, in another\
+        \ terminal:</p>\n<pre>./runserver.py\n</pre>\n</li>\n<li><p>To get some profiling\
+        \ information you can also run it as:</p>\n<pre>./runserver.py --profile\n\
+        </pre>\n</li>\n</ul>\n<p>This will launch the application at <a href=\"http://127.0.0.1:5000\"\
+        >http://127.0.0.1:5000</a></p>\n<ul>\n<li><p>To run unit-tests on pagure</p>\n\
+        <ul>\n<li><p>Install the dependencies:</p>\n<pre>pip install -r tests_requirements.txt\n\
+        </pre>\n</li>\n<li><p>Run it:</p>\n<pre>./runtests.sh\n</pre>\n<div class=\"\
+        note\">\n<p>Note</p>\n<p>While testing for worker tasks, pagure uses celery\
+        \ in /usr/bin/\nCelery then looks for eventlet (which we use for testing only)\
+        \ at\nsystem level and not in virtualenv. You will need to install eventlet\n\
+        outside of your virtualenv if you are using one.</p>\n</div>\n</li>\n</ul>\n\
+        </li>\n</ul>\n</div>\n</div>\n</div>\n\n            </section>\n        </div>\n\
+        \      <div class=\"col-md-4\">\n        <div class=\"card\">\n          <div\
+        \ class=\"card-block\">\n            <h5><strong>Contributors</strong></h5>\n\
+        \            <div class=\"m-b-2\">\n              <div>\n                <a\
+        \ href=\"/user/pingou\">\n                  <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                  Pierre-YvesChibon (pingou)\n                </a>\n \
+        \               -  main admin\n              </div>\n                  <div>\n\
+        \                    <a href=\"/user/ryanlerch\">\n                      <img\
+        \ class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/de5bf8d06663adb3bb1b8d49ccab259828fad7dddeb233b073d0c447d79b4c14?s=20&d=retro\"\
+        />\n                      Ryan Lerch (ryanlerch)\n                    </a>\n\
+        \                    - admin\n                  </div>\n                 \
+        \ <div>\n                    <a href=\"/user/puiterwijk\">\n             \
+        \         <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/85f8b5f58b9808429ad69ba3722d64da01ce850635e348e838dfdc053e1140e3?s=20&d=retro\"\
+        />\n                      Patrick &#34;\u30DE\u30EB\u30BF\u30A4\u30F3\u30A2\
+        \u30F3\u30C9\u30EC\u30A2\u30B9&#34; Uiterwijk (puiterwijk)\n             \
+        \       </a>\n                    - commit\n                  </div>\n   \
+        \               <div>\n                    <a href=\"/user/vivekanand1101\"\
+        >\n                      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/342d1c36d5c2f6984933a1238581dfbe74a08bf09ccaf110793703f1e8067169?s=20&d=retro\"\
+        />\n                      Vivek Anand (vivekanand1101)\n                 \
+        \   </a>\n                    - ticket\n                  </div>\n       \
+        \           <div>\n                    <a href=\"/user/farhaan\">\n      \
+        \                <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b681ddfaffa293b03c57e5f0ed90eb1e06a8f748f4dccdccef8cdd301c66c9ae?s=20&d=retro\"\
+        />\n                      Farhaan Bukhsh (farhaan)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/cverna\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/c7844b93c43c862adaa29920c09bdfb91efed57a843203e5d0b72673e664c003?s=20&d=retro\"\
+        />\n                      Clement Verna (cverna)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/jcline\">\n                \
+        \      <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/1a108f46a960aa35efcabd0b779cd59b8c3aba2927213fe63373921e1aa3fac4?s=20&d=retro\"\
+        />\n                      Jeremy Cline (jcline)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n                \
+        \  <div>\n                    <a href=\"/user/lslebodn\">\n              \
+        \        <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/8c6fcfe0eec099f1f01f5c237935bb5c97f2063a5c1068e57c5815e0bfecbf70?s=20&d=retro\"\
+        />\n                      Lukas Slebodnik (lslebodn)\n                   \
+        \ </a>\n                    - ticket\n                  </div>\n         \
+        \         <div>\n                    <a href=\"/user/mprahl\">\n         \
+        \             <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/ecae5ad9b37619a38e699de00049e449f120b433c9f26a8beb05b990dfc54c9d?s=20&d=retro\"\
+        />\n                      Matt Prahl (mprahl)\n                    </a>\n\
+        \                    - ticket\n                  </div>\n            </div>\n\
+        \            <h5><strong>Branches</strong></h5>\n            <div class=\"\
+        m-b-2\">\n              <div id=\"branch-master\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"\n          \
+        \          title=\"Default branch\"></span>\n                  <strong title=\"\
+        Currently viewing branch master\" data-toggle=\"tooltip\">master</strong>\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                  <span class=\"oi text-muted\" data-glyph=\"star\"\n \
+        \                   title=\"Default branch\"></span>\n                </div>\n\
+        \              </div>\n\n              <div id=\"branch-2.9.x\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/2.9.x\"\n           \
+        \         title=\"2.9.x\" data-toggle=\"tooltip\">2.9.x\n                \
+        \  </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-alembic_changes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/alembic_changes\"\n        \
+        \            title=\"alembic_changes\" data-toggle=\"tooltip\">alembic_changes\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-confirm_merge\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/confirm_merge\"\n   \
+        \                 title=\"confirm_merge\" data-toggle=\"tooltip\">confirm_merge\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-css_tables\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/css_tables\"\n      \
+        \              title=\"css_tables\" data-toggle=\"tooltip\">css_tables\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_del_project\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_del_project\"\n \
+        \                   title=\"fix_del_project\" data-toggle=\"tooltip\">fix_del_project\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_delete\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_delete\"\n      \
+        \              title=\"fix_delete\" data-toggle=\"tooltip\">fix_delete\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_diff_refs\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_diff_refs\"\n   \
+        \                 title=\"fix_diff_refs\" data-toggle=\"tooltip\">fix_diff_refs\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_doc\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_doc\"\n                \
+        \    title=\"fix_doc\" data-toggle=\"tooltip\">fix_doc\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_linking\" class=\"repoinfo-branchlistitem row\">\n\
+        \                <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/fix_linking\"\n                   \
+        \ title=\"fix_linking\" data-toggle=\"tooltip\">fix_linking\n            \
+        \      </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_pygit_error\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_pygit_error\"\n        \
+        \            title=\"fix_pygit_error\" data-toggle=\"tooltip\">fix_pygit_error\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_reply_to\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_reply_to\"\n    \
+        \                title=\"fix_reply_to\" data-toggle=\"tooltip\">fix_reply_to\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_sse\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse\"\n                \
+        \    title=\"fix_sse\" data-toggle=\"tooltip\">fix_sse\n                 \
+        \ </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-fix_sse_status\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fix_sse_status\"\n         \
+        \           title=\"fix_sse_status\" data-toggle=\"tooltip\">fix_sse_status\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fix_templates\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/fix_templates\"\n   \
+        \                 title=\"fix_templates\" data-toggle=\"tooltip\">fix_templates\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-fixes\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/fixes\"\n                  \
+        \  title=\"fixes\" data-toggle=\"tooltip\">fixes\n                  </a>\n\
+        \n                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-force_flag\" class=\"repoinfo-branchlistitem row\">\n             \
+        \   <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/force_flag\"\n                    title=\"force_flag\"\
+        \ data-toggle=\"tooltip\">force_flag\n                  </a>\n\n         \
+        \       </div>\n                <div class=\"branch_del col-md-4\">\n    \
+        \            </div>\n              </div>\n              <div id=\"branch-gpg_check\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/gpg_check\"\
+        \n                    title=\"gpg_check\" data-toggle=\"tooltip\">gpg_check\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-logging_milter\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/logging_milter\"\n  \
+        \                  title=\"logging_milter\" data-toggle=\"tooltip\">logging_milter\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-mirroring\" class=\"repoinfo-branchlistitem row\"\
+        >\n                <div class=\"branch_name col-md-8\">\n                \
+        \  <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n         \
+        \         <a class=\"\" href=\"/pagure/branch/mirroring\"\n              \
+        \      title=\"mirroring\" data-toggle=\"tooltip\">mirroring\n           \
+        \       </a>\n\n                </div>\n                <div class=\"branch_del\
+        \ col-md-4\">\n                </div>\n              </div>\n            \
+        \  <div id=\"branch-py3_work2\" class=\"repoinfo-branchlistitem row\">\n \
+        \               <div class=\"branch_name col-md-8\">\n                  <span\
+        \ class=\"oi text-muted\" data-glyph=\"random\"></span>\n                \
+        \  <a class=\"\" href=\"/pagure/branch/py3_work2\"\n                    title=\"\
+        py3_work2\" data-toggle=\"tooltip\">py3_work2\n                  </a>\n\n\
+        \                </div>\n                <div class=\"branch_del col-md-4\"\
+        >\n                </div>\n              </div>\n              <div id=\"\
+        branch-rel_2.2.z\" class=\"repoinfo-branchlistitem row\">\n              \
+        \  <div class=\"branch_name col-md-8\">\n                  <span class=\"\
+        oi text-muted\" data-glyph=\"random\"></span>\n                  <a class=\"\
+        \" href=\"/pagure/branch/rel_2.2.z\"\n                    title=\"rel_2.2.z\"\
+        \ data-toggle=\"tooltip\">rel_2.2.z\n                  </a>\n\n          \
+        \      </div>\n                <div class=\"branch_del col-md-4\">\n     \
+        \           </div>\n              </div>\n              <div id=\"branch-rel_2.3.z\"\
+        \ class=\"repoinfo-branchlistitem row\">\n                <div class=\"branch_name\
+        \ col-md-8\">\n                  <span class=\"oi text-muted\" data-glyph=\"\
+        random\"></span>\n                  <a class=\"\" href=\"/pagure/branch/rel_2.3.z\"\
+        \n                    title=\"rel_2.3.z\" data-toggle=\"tooltip\">rel_2.3.z\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-scroll_metadata\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/scroll_metadata\"\n \
+        \                   title=\"scroll_metadata\" data-toggle=\"tooltip\">scroll_metadata\n\
+        \                  </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \           <div id=\"branch-utf_search\" class=\"repoinfo-branchlistitem\
+        \ row\">\n                <div class=\"branch_name col-md-8\">\n         \
+        \         <span class=\"oi text-muted\" data-glyph=\"random\"></span>\n  \
+        \                <a class=\"\" href=\"/pagure/branch/utf_search\"\n      \
+        \              title=\"utf_search\" data-toggle=\"tooltip\">utf_search\n \
+        \                 </a>\n\n                </div>\n                <div class=\"\
+        branch_del col-md-4\">\n                </div>\n              </div>\n   \
+        \         </div>\n            <h5><strong>Source GIT URLs</strong>       \
+        \           <span class=\"pull-xs-right\"><a data-toggle=\"collapse\" href=\"\
+        #moregiturls\"\n                  aria-expanded=\"false\" aria-controls=\"\
+        moregiturls\"\n                  id=\"more_gits\">more</a></span></h5>\n \
+        \           <div>\n              <div class=\"form-group\">\n            \
+        \    <div class=\"input-group input-group-sm\">\n                  <div class=\"\
+        input-group-addon\">GIT</div>\n                  <input class=\"form-control\"\
+        \ type=\"text\" value=\"https://pagure.io/pagure.git\" readonly>\n       \
+        \         </div>\n              </div>\n              <div class=\"collapse\"\
+        \ id=\"moregiturls\">\n                  <h5><strong>Docs GIT URLs</strong></h5>\n\
+        \                  <div class=\"form-group\">\n                    <div class=\"\
+        input-group input-group-sm\">\n                      <div class=\"input-group-addon\"\
+        >GIT</div>\n                      <input class=\"form-control\" type=\"text\"\
+        \ value=\"https://pagure.io/docs/pagure.git\" readonly>\n                \
+        \    </div>\n                  </div>\n              </div>\n            </div>\n\
+        \          </div>\n          <div class=\"repo_date\" title=\"2015-05-13 20:38:10.552662\"\
+        >\n              created 2 years ago\n          </div>\n        </div>\n\n\
+        \          <div class=\"card\">\n            <div class=\"card-header\">\n\
+        \              <strong>Recent Commits in\n                <span class=\"pr-toplabel\"\
+        >\n                  <span class=\"oi\" data-glyph=\"random\"></span>\n  \
+        \                master\n                </span>\n              </strong>\n\
+        \            </div>\n            <div class=\"card-block p-a-0\">\n      \
+        \        <div class=\"list-group list-group-flush\">\n                  <a\
+        \ href=\"/pagure/c/75b9021afbb08a3bdc1128cb282ea9c2394c0b67\" class=\"list-group-item\"\
+        >\n                    <div class=\"commitdate\" title=\"Sep 21 2017 08:20:29\"\
+        >\n                      <small>\n                        <strong>\n     \
+        \                     <img class=\"avatar circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Add unit-tests for the fixes around loading issue template\n\
+        \                    </small></div>\n                  </a>\n            \
+        \      <a href=\"/pagure/c/fc1d7f885d8b658ce7ba2fbd9cf20692b32f7732\" class=\"\
+        list-group-item\">\n                    <div class=\"commitdate\" title=\"\
+        Sep 21 2017 08:20:29\">\n                      <small>\n                 \
+        \       <strong>\n                          <img class=\"avatar circle\" src=\"\
+        https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Flake8 fix fixing the tests\n                    </small></div>\n\
+        \                  </a>\n                  <a href=\"/pagure/c/91c1f357adc77f0b21e15f6177c68ffc97f3ec67\"\
+        \ class=\"list-group-item\">\n                    <div class=\"commitdate\"\
+        \ title=\"Sep 21 2017 08:20:29\">\n                      <small>\n       \
+        \                 <strong>\n                          <img class=\"avatar\
+        \ circle\" src=\"https://seccdn.libravatar.org/avatar/b3ee7bb4de70b6522c2478df3b4cd6322b5ec5d62ac7ceb1128e3d4ff42f6928?s=20&d=retro\"\
+        />\n                          Pierre-Yves Chibon\n                       \
+        \ </strong>\n                        commited 5 days ago\n               \
+        \       </small>\n                    </div>\n                    <div><small>\n\
+        \                      Adjust the documentation around ticket templates\n\
+        \                    </small></div>\n                  </a>\n            \
+        \  </div>\n              </div>\n            </div>\n          </div>\n  \
+        \    </div>\n    </div>\n\n\n</div>\n    </div>\n\n    <div class=\"footer\
+        \ p-t-1 p-b-1\">\n        <div class=\"container\">\n            <p class=\"\
+        text-muted credit\">\n         Copyright &copy; 2014-2017 Red Hat\n      \
+        \    <a href=\"https://pagure.io/pagure\">pagure</a> &mdash;\n          3.7.1\
+        \ &mdash; <a href=\"https://docs.pagure.org/pagure/usage/index.html\">Documentation</a>\n\
+        \            </p>\n            <p><a href=\"/ssh_info\">SSH Hostkey/Fingerprint</a></p>\n\
+        \        </div>\n    </div>\n\n    <script type=\"text/javascript\"\n    \
+        \    src=\"/static/vendor/jquery/jquery.min.js\">\n    </script>\n    <script\
+        \ type=\"text/javascript\"\n        src=\"/static/vendor/jquery-ui/jquery-ui.min.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\"\n        src=\"https://apps.fedoraproject.org/global/fedora-bootstrap-1.0.1/fedora-bootstrap.js\"\
+        >\n    </script>\n    <script type=\"text/javascript\">\n$('[data-toggle=\"\
+        tooltip\"]').tooltip({placement : 'bottom'});\n    </script>\n\n<script type=\"\
+        text/javascript\">\n$(document).ready(function() {\n        var currentWatchStatusButton\
+        \ = $('#unwatch_button');\n    currentWatchStatusButton.prepend('<span class=\"\
+        oi\" data-glyph=\"circle-check\" style=\"padding-right:0.5em\"></span>');\n\
+        \    $('.watch-menu a').not(currentWatchStatusButton).css('padding-left',\
+        \ '2.85em');\n\n    $(\".watch-menu a\").click(function(){\n        var selectedValue\
+        \ = $(this).attr('id');\n        var watchProjectForm = $(\"#watch_project\"\
+        );\n        var action = watchProjectForm.attr('action');\n\n        if (selectedValue\
+        \ === \"watch_issues_button\") {\n            action = action.replace('/settings/0',\
+        \ '/settings/1');\n        } else if (selectedValue === \"watch_commits_button\"\
+        ) {\n            action = action.replace('/settings/0', '/settings/2');\n\
+        \        } else if (selectedValue === \"watch_issues_commits_button\") {\n\
+        \            action = action.replace('/settings/0', '/settings/3');\n    \
+        \    } else if (selectedValue === \"reset_button\") {\n            action\
+        \ = action.replace('/settings/0', '/settings/-1');\n        }\n\n        watchProjectForm.attr('action',\
+        \ action);\n        watchProjectForm.submit();\n    });\n});\n</script>\n\n\
+        <script type=\"text/javascript\">\n$(document).ready(function() {\n    $(\"\
+        .extra_gits\").hide();\n});\n\n$(function() {\n  $( \"#more_gits\" ).click(function()\
+        \ {\n      if ($( \"#more_gits\" ).html() == 'more') {\n        $( \"#more_gits\"\
+        \ ).html('less');\n      } else {\n        $( \"#more_gits\" ).html('more');\n\
+        \      }\n  });\n\n});\n</script>\n\n\n</body>\n</html>"}
+    headers:
+      Connection: [Keep-Alive]
+      Content-Length: ['31652']
+      Content-Type: [text/html; charset=utf-8]
+      Date: ['Tue, 26 Sep 2017 15:29:39 GMT']
+      Keep-Alive: ['timeout=5, max=100']
+      Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4
+          Python/2.7.5]
+      Set-Cookie: ['pagure=eyJfcGVybWFuZW50Ijp0cnVlLCJjc3JmIjp7IiBiIjoiWVRBNU16ZGpNV0ptTlRkaU1qRm1OR0V3WlRjMk1UWXhOREUwTUdGa05qWXhPVEUwTjJRNU13PT0ifX0.DKwD5A.sIltPbKIPmLrrToF0bppHY_o6Cs;
+          Expires=Fri, 27-Oct-2017 15:29:40 GMT; Secure; HttpOnly; Path=/']
+      Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
+    status: {code: 200, message: OK}
+version: 1
diff --git a/hubs/tests/views/test_api.py b/hubs/tests/views/test_api.py
deleted file mode 100644
index abf1e3d..0000000
--- a/hubs/tests/views/test_api.py
+++ /dev/null
@@ -1,151 +0,0 @@
-from __future__ import unicode_literals
-
-from six.moves.urllib.parse import urlparse
-
-import hubs.tests
-import hubs.models
-from hubs.app import app
-
-
-def usernames(collection): return [u.username for u in collection]
-
-
-class TestHubSubscribe(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_subscribe_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_subscribe_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/subscribe'.format(hub.name),
-                                 follow_redirects=True)
-            self.assertEqual(resp.status_code, 200)
-            # Need to find the Hub again to avoid DetachedInstanceError
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username in usernames(h.subscribers))
-
-
-class TestHubUnsubscribe(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_unsubscribe_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_unsubscribe_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        # Need a real user model to subscribe to the hub
-        User = hubs.models.User.by_username(self.user.username)
-        hub.subscribe(User)
-
-        self.assertTrue(self.user.username in usernames(hub.subscribers))
-
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/unsubscribe'.format(hub.name),
-                                 follow_redirects=True)
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username not in usernames(h.subscribers))
-
-
-class TestHubStar(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_star_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/star'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_star_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/star'.format(hub.name),
-                                 follow_redirects=True)
-
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username in usernames(h.stargazers))
-
-
-class TestHubUnstar(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_unstar_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_unstar_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        # Need a real user model to subscribe to the hub
-        User = hubs.models.User.by_username(self.user.username)
-        hub.subscribe(User, role='stargazer')
-
-        self.assertTrue(self.user.username in [u.username for
-                                               u in hub.stargazers])
-
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/unstar'.format(hub.name),
-                                 follow_redirects=True)
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username not in usernames(h.stargazers))
-
-
-class TestHubJoin(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_join_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/join'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_join_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/join'.format(hub.name),
-                                 follow_redirects=True)
-
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username in usernames(h.members))
-
-
-class TestHubLeave(hubs.tests.APPTest):
-    user = hubs.tests.FakeAuthorization('decause')
-
-    def test_leave_redirects_when_logged_out(self):
-        hub = hubs.models.Hub.by_name('infra')
-        resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
-                             follow_redirects=False)
-        self.assertEqual(resp.status_code, 302)
-        self.assertEqual(urlparse(resp.location).path, '/login')
-
-    def test_star_when_logged_in(self):
-        hub = hubs.models.Hub.by_name('infra')
-        # Need a real user model to subscribe to the hub
-        User = hubs.models.User.by_username(self.user.username)
-        hub.subscribe(User, role='member')
-
-        with hubs.tests.auth_set(app, self.user):
-            resp = self.app.post('/api/hub/{}/leave'.format(hub.name),
-                                 follow_redirects=True)
-
-            self.assertEqual(resp.status_code, 200)
-            h = hubs.models.Hub.by_name('infra')
-            self.assertTrue(self.user.username not in usernames(h.members))
diff --git a/hubs/tests/views/test_api_association.py b/hubs/tests/views/test_api_association.py
new file mode 100644
index 0000000..26eaaa5
--- /dev/null
+++ b/hubs/tests/views/test_api_association.py
@@ -0,0 +1,151 @@
+from __future__ import unicode_literals
+
+from six.moves.urllib.parse import urlparse
+
+import hubs.tests
+import hubs.models
+from hubs.app import app
+
+
+def usernames(collection): return [u.username for u in collection]
+
+
+class TestHubSubscribe(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_subscribe_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hubs/{}/subscribe'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_subscribe_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hubs/{}/subscribe'.format(hub.name),
+                                 follow_redirects=True)
+            self.assertEqual(resp.status_code, 200)
+            # Need to find the Hub again to avoid DetachedInstanceError
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.nickname in usernames(h.subscribers))
+
+
+class TestHubUnsubscribe(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_unsubscribe_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hubs/{}/unsubscribe'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_unsubscribe_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        # Need a real user model to subscribe to the hub
+        User = hubs.models.User.by_username(self.user.nickname)
+        hub.subscribe(User)
+
+        self.assertTrue(self.user.nickname in usernames(hub.subscribers))
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hubs/{}/unsubscribe'.format(hub.name),
+                                 follow_redirects=True)
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.nickname not in usernames(h.subscribers))
+
+
+class TestHubStar(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_star_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hubs/{}/star'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_star_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hubs/{}/star'.format(hub.name),
+                                 follow_redirects=True)
+
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.nickname in usernames(h.stargazers))
+
+
+class TestHubUnstar(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_unstar_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hubs/{}/unstar'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_unstar_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        # Need a real user model to subscribe to the hub
+        User = hubs.models.User.by_username(self.user.nickname)
+        hub.subscribe(User, role='stargazer')
+
+        self.assertTrue(self.user.nickname in [u.username for
+                                               u in hub.stargazers])
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hubs/{}/unstar'.format(hub.name),
+                                 follow_redirects=True)
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.nickname not in usernames(h.stargazers))
+
+
+class TestHubJoin(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_join_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hubs/{}/join'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_join_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hubs/{}/join'.format(hub.name),
+                                 follow_redirects=True)
+
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.nickname in usernames(h.members))
+
+
+class TestHubLeave(hubs.tests.APPTest):
+    user = hubs.tests.FakeAuthorization('decause')
+
+    def test_leave_redirects_when_logged_out(self):
+        hub = hubs.models.Hub.by_name('infra')
+        resp = self.app.post('/api/hubs/{}/leave'.format(hub.name),
+                             follow_redirects=False)
+        self.assertEqual(resp.status_code, 302)
+        self.assertEqual(urlparse(resp.location).path, '/login')
+
+    def test_star_when_logged_in(self):
+        hub = hubs.models.Hub.by_name('infra')
+        # Need a real user model to subscribe to the hub
+        User = hubs.models.User.by_username(self.user.nickname)
+        hub.subscribe(User, role='member')
+
+        with hubs.tests.auth_set(app, self.user):
+            resp = self.app.post('/api/hubs/{}/leave'.format(hub.name),
+                                 follow_redirects=True)
+
+            self.assertEqual(resp.status_code, 200)
+            h = hubs.models.Hub.by_name('infra')
+            self.assertTrue(self.user.nickname not in usernames(h.members))
diff --git a/hubs/tests/views/test_api_hub_config.py b/hubs/tests/views/test_api_hub_config.py
new file mode 100644
index 0000000..b542ce1
--- /dev/null
+++ b/hubs/tests/views/test_api_hub_config.py
@@ -0,0 +1,185 @@
+from __future__ import unicode_literals
+
+import datetime
+
+from flask import json
+
+from hubs.app import app
+from hubs.models import Hub, User
+from hubs.tests import APPTest, FakeAuthorization, auth_set
+
+
+class TestAPIHubConfig(APPTest):
+
+    def test_get(self):
+        hub = Hub.by_name('ralph')
+        hub.last_refreshed = datetime.datetime(2017, 1, 1, 0, 0, 0)
+        self.session.commit()
+        user = FakeAuthorization('ralph')
+        response = self.check_url("/api/hubs/ralph/config", user=user)
+        expected_data = {
+            "user_hub": True,
+            "config": {
+                "avatar": "https://seccdn.libravatar.org/avatar/"
+                          "9c9f7784935381befc302fe3c814f9136e7a339"
+                          "53d0318761669b8643f4df55c?s=312&d=retro",
+                'chat_channel': None,
+                'chat_domain': None,
+                "left_width": 8,
+                "right_width": 4,
+                "summary": "Ralph",
+                "visibility": "public",
+            },
+            "mtime": "Sun, 01 Jan 2017 00:00:00 GMT",
+            "users": {
+                "owner": [
+                    {"username": "ralph", "fullname": "Ralph"},
+                ],
+                "member": [],
+            },
+            "name": "ralph",
+        }
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertDictEqual(
+            response_data, {"status": "OK", "data": expected_data})
+
+    def test_private_get(self):
+        hub = Hub.by_name('ralph')
+        hub.config.visibility = "private"
+        self.session.commit()
+        # Private hubs are not accessible to anonymous users.
+        response = self.check_url("/api/hubs/ralph/config", code=403)
+        self.assertDictEqual(
+            json.loads(response.get_data(as_text=True)),
+            {
+              "hub": "ralph",
+              "message": "This hub is for members only.",
+              "status": "ERROR"
+            }
+        )
+        # But they are accessible to members.
+        decause = User.by_username("decause")
+        hub.subscribe(decause, role='member')
+        self.check_url(
+            "/api/hubs/ralph/config", user=FakeAuthorization("decause"))
+
+    def test_put(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.put(
+                '/api/hubs/ralph/config',
+                content_type="application/json",
+                data=json.dumps({
+                    "config": {
+                        "summary": "changed value",
+                        "chat_domain": "",
+                    }
+                })
+            )
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        hub_config = Hub.query.get("ralph").config
+        self.assertEqual(hub_config.summary, "changed value")
+        self.assertEqual(
+            hub_config.chat_domain,
+            app.config["CHAT_NETWORKS"][0]["domain"])
+
+    def test_put_unknown_data(self):
+        # Unknown PUT data is silently ignored
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.put(
+                '/api/hubs/ralph/config',
+                content_type="application/json",
+                data=json.dumps({"config": {"non_existant": "dummy"}}))
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "ERROR")
+        self.assertEqual(result_data["message"], "Invalid value(s)")
+        self.assertIn("non_existant", result_data["fields"])
+        self.assertEqual(
+            result_data["fields"]["non_existant"],
+            "Unexpected parameter."
+            )
+
+    def test_put_invalid_chat_domain(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.put(
+                '/api/hubs/ralph/config',
+                content_type="application/json",
+                data=json.dumps({"config": {"chat_domain": "dummy"}}))
+        self.assertEqual(result.status_code, 200)
+        result_data = json.loads(result.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "ERROR")
+        self.assertEqual(result_data["message"], "Invalid value(s)")
+        self.assertIn("chat_domain", result_data["fields"])
+        self.assertEqual(
+            result_data["fields"]["chat_domain"],
+            "Unsupported chat domain."
+            )
+
+    def test_put_unauthorized(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.put(
+                '/api/hubs/decause/config',
+                content_type="application/json",
+                data=json.dumps({"config": {"summary": "Defaced!"}}))
+        self.assertEqual(result.status_code, 403)
+        hub_config = Hub.query.get("decause").config
+        self.assertEqual(hub_config.summary, "Decause")
+
+    def test_suggest_users_no_filter(self):
+        user = FakeAuthorization('ralph')
+        expected = [
+            dict(username=u.username, fullname=u.fullname)
+            for u in User.query.order_by(User.username).all()
+            ]
+        # Check without filter
+        response = self.check_url(
+            "/api/hubs/ralph/config/suggest-users", user=user)
+        result_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertListEqual(result_data["data"], expected)
+
+    def test_suggest_users_filter_owners(self):
+        # Filters on owners
+        user = FakeAuthorization('ralph')
+        expected = [
+            dict(username=u.username, fullname=u.fullname)
+            for u in
+            User.query.order_by(User.username).filter(
+                User.username != "ralph").all()
+            ]
+        response = self.check_url(
+            "/api/hubs/ralph/config/suggest-users?exclude-role=owner",
+            user=user)
+        result_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertListEqual(result_data["data"], expected)
+
+    def test_suggest_users_filter_members(self):
+        # Filters on members
+        user = FakeAuthorization('ralph')
+        hub = Hub.get('ralph')
+        decause = User.query.get("decause")
+        devyani7 = User.query.get("devyani7")
+        hub.subscribe(decause, "member")
+        hub.subscribe(devyani7, "member")
+        expected = [
+            dict(username=u.username, fullname=u.fullname)
+            for u in
+            User.query.order_by(
+                User.username
+            ).filter(
+                User.username != "decause",
+                User.username != "devyani7"
+            ).all()]
+        response = self.check_url(
+            "/api/hubs/ralph/config/suggest-users?exclude-role=member",
+            user=user)
+        result_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(result_data["status"], "OK")
+        self.assertListEqual(result_data["data"], expected)
diff --git a/hubs/tests/views/test_api_hub_widget.py b/hubs/tests/views/test_api_hub_widget.py
new file mode 100644
index 0000000..5684d29
--- /dev/null
+++ b/hubs/tests/views/test_api_hub_widget.py
@@ -0,0 +1,240 @@
+from __future__ import unicode_literals
+
+from flask import json
+
+from hubs.app import app
+from hubs.models import Hub, User, Widget
+from hubs.widgets import registry
+from hubs.tests import APPTest, FakeAuthorization, auth_set
+
+
+class TestAPIHubWidgets(APPTest):
+
+    def test_get_widgets(self):
+        expected_ids = [35, 36, 34, 37, 38, 39, 40, 41, 42, 43, 44, 56]
+        response = self.check_url("/api/hubs/ralph/widgets/")
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(response_data["status"], "OK")
+        self.assertListEqual(
+            [w["idx"] for w in response_data["data"]],
+            expected_ids)
+
+    def test_get_widgets_private(self):
+        hub = Hub.by_name('ralph')
+        hub.config.visibility = "private"
+        self.session.commit()
+        # Private hubs are not accessible to anonymous users.
+        response = self.check_url("/api/hubs/ralph/widgets/", code=403)
+        self.assertDictEqual(
+            json.loads(response.get_data(as_text=True)),
+            {
+              "hub": "ralph",
+              "message": "This hub is for members only.",
+              "status": "ERROR"
+            }
+        )
+        # But they are accessible to members.
+        decause = User.by_username("decause")
+        hub.subscribe(decause, role='member')
+        self.check_url(
+            "/api/hubs/ralph/widgets/", user=FakeAuthorization("decause"))
+
+    def test_get_widgets_preview(self):
+        hub = Hub.by_name('ralph')
+        hub.config.visibility = "preview"
+        meetings = Widget.query.filter_by(
+            hub=hub, plugin="meetings").first()
+        # set the widget to "restricted"
+        meetings.visibility = "restricted"
+        # Restricted widgets in preview hubs aren't displayed to
+        # anonymous users.
+        response = self.check_url("/api/hubs/ralph/widgets/")
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(response_data["status"], "OK")
+        self.assertNotIn(
+            "meetings", [w["name"] for w in response_data["data"]])
+        # But they are displayed to members.
+        response = self.check_url(
+            "/api/hubs/ralph/widgets/", user=FakeAuthorization('ralph'))
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(response_data["status"], "OK")
+        self.assertIn(
+            "meetings", [w["name"] for w in response_data["data"]])
+
+    def test_get_removed_widget(self):
+        hub = Hub.get("ralph")
+        widget = Widget(
+            hub=hub, plugin="does-not-exist",
+            left=True, index=-1, _config="{}")
+        self.session.add(widget)
+        response = self.check_url(
+            "/api/hubs/ralph/widgets/", user=FakeAuthorization('ralph'))
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertNotIn(
+            "does-not-exist", [w["name"] for w in response_data["data"]])
+
+    def test_get_available(self):
+        response = self.check_url("/api/widgets/")
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(response_data["status"], "OK")
+        self.assertListEqual(
+            [w["name"] for w in response_data["data"]],
+            list(registry.keys()))
+
+    def test_post_invalid_request(self):
+        invalid_data = [
+            {
+                "position": "left",
+                'config': {},
+            }, {
+                'name': 'about',
+                'position': 'right',
+            }, {
+                'name': 'about',
+                'config': {},
+            }, {
+                'name': 'about',
+                'config': {},
+                'position': 'invalid_position',
+            },
+        ]
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            for data in invalid_data:
+                result = self.app.post(
+                    '/api/hubs/ralph/widgets/',
+                    content_type="application/json",
+                    data=json.dumps(data))
+                self.assertEqual(result.status_code, 400)
+                expected_str = 'Invalid request sent'
+                self.assertIn(expected_str, result.get_data(as_text=True))
+
+    def test_post_unknown_widget(self):
+        invalid_data = [
+            {
+                'name': 'invalid_widget_name',
+                'config': {},
+                'position': 'right',
+            },
+        ]
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            for data in invalid_data:
+                result = self.app.post(
+                    '/api/hubs/ralph/widgets/',
+                    content_type="application/json",
+                    data=json.dumps(data))
+                self.assertEqual(result.status_code, 400)
+                expected_str = 'Unknown widget'
+                self.assertIn(expected_str, result.get_data(as_text=True))
+
+    def test_post_valid_widget_name_no_config(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            data = {
+                'name': 'memberships',
+                'position': 'right',
+                "config": {},
+                }
+            result = self.app.post(
+                '/api/hubs/ralph/widgets/',
+                content_type="application/json",
+                data=json.dumps(data))
+        self.assertEqual(result.status_code, 200)
+        self.assertEqual(
+            json.loads(result.get_data(as_text=True)),
+            {"status": "OK"})
+        response = self.check_url("/api/hubs/ralph/widgets/")
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(response_data["status"], "OK")
+        self.assertIn("memberships",
+                      [w["name"] for w in response_data["data"]])
+
+    def test_post_valid_widget_name_with_config(self):
+        self.assertEqual(
+            Widget.query.filter(
+                Hub.name == "ralph",
+                Widget.plugin == "about",
+            ).count(), 1)
+        data = {
+            "name": "about",
+            "config": {'text': 'text of widget'},
+            'position': 'right',
+            }
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.post(
+                '/api/hubs/ralph/widgets/',
+                content_type="application/json",
+                data=json.dumps(data))
+        self.assertEqual(result.status_code, 200)
+        self.assertEqual(
+            json.loads(result.get_data(as_text=True)),
+            {"status": "OK"})
+        self.assertEqual(
+            Widget.query.filter(
+                Hub.name == "ralph",
+                Widget.plugin == "about",
+            ).count(), 2)
+
+
+class TestAPIHubWidget(APPTest):
+
+    def test_get_logged_in(self):
+        user = FakeAuthorization('ralph')
+        response = self.check_url("/api/hubs/ralph/widgets/37/", user=user)
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(response_data["status"], "OK")
+        self.assertEqual(response_data["data"]["name"], "fedmsgstats")
+
+    def test_get_logged_out(self):
+        hub = Hub.by_name('ralph')
+        hub.config.visibility = "private"
+        self.session.commit()
+        response = self.check_url("/api/hubs/ralph/widgets/31/", code=403)
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(response_data["status"], "ERROR")
+
+    def test_put_empty_data_logged_in(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.put(
+                '/api/hubs/ralph/widgets/37/',
+                content_type="application/json",
+                data=json.dumps({}))
+        self.assertEqual(result.status_code, 200)
+        self.assertEqual(
+            json.loads(result.get_data(as_text=True)),
+            {"status": "OK"})
+
+    def test_put_unauthorized(self):
+        user = FakeAuthorization('decause')
+        with auth_set(app, user):
+            result = self.app.put(
+                '/api/hubs/ralph/widgets/37/',
+                content_type="application/json",
+                data=json.dumps({"config": {"text": "Defaced!"}}))
+        self.assertEqual(result.status_code, 403)
+
+    def test_delete(self):
+        user = FakeAuthorization('ralph')
+        with auth_set(app, user):
+            result = self.app.delete('/api/hubs/ralph/widgets/37/')
+        self.assertEqual(result.status_code, 200)
+        self.assertEqual(
+            json.loads(result.get_data(as_text=True)),
+            {"status": "OK"})
+        response = self.check_url("/api/hubs/ralph/widgets/")
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertNotIn(37, [w["idx"] for w in response_data["data"]])
+
+    def test_delete_unauthorized(self):
+        user = FakeAuthorization('decause')
+        with auth_set(app, user):
+            response = self.app.delete('/api/hubs/ralph/widgets/37/')
+        self.assertEqual(response.status_code, 403)
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertEqual(response_data["status"], "ERROR")
+        response = self.check_url("/api/hubs/ralph/widgets/")
+        response_data = json.loads(response.get_data(as_text=True))
+        self.assertIn(37, [w["idx"] for w in response_data["data"]])
diff --git a/hubs/tests/views/test_hub_config.py b/hubs/tests/views/test_hub_config.py
deleted file mode 100644
index 9b66b03..0000000
--- a/hubs/tests/views/test_hub_config.py
+++ /dev/null
@@ -1,166 +0,0 @@
-from __future__ import unicode_literals
-
-from flask import json
-
-from hubs.app import app
-from hubs.models import Hub, HubConfig, User
-from hubs.tests import APPTest, FakeAuthorization, auth_set
-
-
-class HubConfigTestCase(APPTest):
-
-    def test_hub_config_get(self):
-        expected = {
-            "hubconfig": {
-                "summary": "Ralph",
-                "left_width": 8,
-                "avatar": (
-                    "https://seccdn.libravatar.org/avatar/9c9f7784935381befc30"
-                    "2fe3c814f9136e7a33953d0318761669b8643f4df55c"
-                    "?s=312&d=retro"
-                    ),
-                "chat_channel": None,
-                "chat_domain": None,
-                "visibility": "public",
-            },
-            "general": {
-                "chat_networks": app.config["CHAT_NETWORKS"],
-                "roles": ["owner", "member"],
-                "hub_visibility": HubConfig.VISIBILITY,
-            },
-            "users": {
-                "member": [],
-                "owner": [{
-                    "fullname": "Ralph",
-                    "locked": True,
-                    "role": "owner",
-                    "username": "ralph",
-                }],
-            },
-        }
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            url = '/ralph/config'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertDictEqual(result_data["result"], expected)
-
-    def test_hub_config_post(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            url = '/ralph/config?category=config'
-            result = self.app.post(url, data={
-                "summary": "changed value",
-                "chat_domain": "",
-            })
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertEqual(
-            result_data["result"]["hubconfig"]["summary"],
-            "changed value")
-        self.assertEqual(
-            result_data["result"]["hubconfig"]["chat_domain"],
-            app.config["CHAT_NETWORKS"][0]["domain"])
-
-    def test_hub_config_post_unknown_post_data(self):
-        # Unknown POST data is silently ignored
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            url = '/ralph/config?category=config'
-            result = self.app.post(url, data={"non_existant": "dummy"})
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "ERROR")
-        self.assertEqual(result_data["message"], "Invalid value(s)")
-        self.assertIn("non_existant", result_data["fields"])
-        self.assertEqual(
-            result_data["fields"]["non_existant"],
-            "Unexpected parameter."
-            )
-
-    def test_hub_config_post_invalid_chat_domain(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            url = '/ralph/config?category=config'
-            result = self.app.post(url, data={"chat_domain": "dummy"})
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "ERROR")
-        self.assertEqual(result_data["message"], "Invalid value(s)")
-        self.assertIn("chat_domain", result_data["fields"])
-        self.assertEqual(
-            result_data["fields"]["chat_domain"],
-            "Unsupported chat domain."
-            )
-
-    def test_hub_config_get_unauthorized(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            url = '/decause/config'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 403)
-
-    def test_hub_config_post_unauthorized(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            url = '/decause/config?category=config'
-            result = self.app.post(url, data={"summary": "Defaced!"})
-        self.assertEqual(result.status_code, 403)
-
-    def test_hub_config_suggest_users_no_filter(self):
-        user = FakeAuthorization('ralph')
-        expected = [
-            u.username for u in
-            User.query.order_by(User.username).all()
-            ]
-        # Check without filter
-        with auth_set(app, user):
-            url = '/ralph/config/suggest-users'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertListEqual(result_data["results"], expected)
-
-    def test_hub_config_suggest_users_filter_owners(self):
-        # Filters on owners
-        user = FakeAuthorization('ralph')
-        expected = [
-            u.username for u in
-            User.query.order_by(User.username).filter(
-                User.username != "ralph").all()
-            ]
-        with auth_set(app, user):
-            url = '/ralph/config/suggest-users?exclude-role=owner'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertListEqual(result_data["results"], expected)
-
-    def test_hub_config_suggest_users_filter_members(self):
-        # Filters on members
-        user = FakeAuthorization('ralph')
-        hub = Hub.get('ralph')
-        decause = User.query.get("decause")
-        devyani7 = User.query.get("devyani7")
-        hub.subscribe(decause, "member")
-        hub.subscribe(devyani7, "member")
-        expected = [
-            u.username for u in
-            User.query.order_by(
-                User.username
-            ).filter(
-                User.username != "decause",
-                User.username != "devyani7"
-            ).all()]
-        with auth_set(app, user):
-            url = '/ralph/config/suggest-users?exclude-role=member'
-            result = self.app.get(url)
-        self.assertEqual(result.status_code, 200)
-        result_data = json.loads(result.get_data(as_text=True))
-        self.assertEqual(result_data["status"], "OK")
-        self.assertListEqual(result_data["results"], expected)
diff --git a/hubs/tests/views/test_hub_edit.py b/hubs/tests/views/test_hub_edit.py
deleted file mode 100644
index 2ff727e..0000000
--- a/hubs/tests/views/test_hub_edit.py
+++ /dev/null
@@ -1,114 +0,0 @@
-from __future__ import unicode_literals
-
-from six.moves.urllib.parse import urlparse
-from werkzeug.datastructures import ImmutableMultiDict
-
-from hubs.app import app
-from hubs.tests import APPTest, FakeAuthorization, auth_set
-
-
-class HubEditTestCase(APPTest):
-
-    def test_hub_edit_get_logged_out(self):
-        with auth_set(app, None):
-            result = self.app.get('/ralph/edit', follow_redirects=False)
-        self.assertEqual(result.status_code, 302)
-        self.assertEqual(urlparse(result.location).path, "/login")
-
-    def test_hub_edit_get_logged_in_not_owner(self):
-        user = FakeAuthorization('not_ralph')
-        with auth_set(app, user):
-            result = self.app.get('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)
-
-    def test_hub_edit_get_logged_in_owner(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.get('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-
-    def test_hub_edit_post_logged_out(self):
-        with auth_set(app, None):
-            result = self.app.post('/ralph/edit', follow_redirects=False)
-        self.assertEqual(result.status_code, 302)
-        self.assertEqual(urlparse(result.location).path, "/login")
-
-    def test_hub_edit_post_logged_in_not_owner(self):
-        user = FakeAuthorization('not_ralph')
-        with auth_set(app, user):
-            result = self.app.post('/ralph/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)
-
-    def test_hub_edit_post_logged_in_owner_empty_data(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.post('/ralph/edit', data={},
-                                   follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            self.assertNotIn(
-                'Not logged in.  Click to <a href="/login">login</a>',
-                result.get_data(as_text=True))
-            self.assertIn(
-                '<a href="#" class="dropdown-item">Full Name: '
-                'fullname: ralph</a>', result.get_data(as_text=True))
-
-    def test_hub_edit_post_logged_in_owner_valid_data(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            data = ImmutableMultiDict(
-                [('right_indexes[]', u'0'), ('right_indexes[]', u'1'),
-                 ('right_indexes[]', u'2'), ('right_indexes[]', u'3'),
-                 ('right_indexes[]', u'4'), ('right_indexes[]', u'5'),
-                 ('right_indexes[]', u'6'), ('right_indexes[]', u'7'),
-                 ('right_indexes[]', u'8'), ('right_widgets[]', u'32'),
-                 ('right_widgets[]', u'33'), ('right_widgets[]', u'34'),
-                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
-                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
-                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
-                 ('js', u'true'), ('left_indexes[]', u'0'),
-                 ('left_indexes[]', u'1'), ('left_widgets[]', u'31'),
-                 ('left_widgets[]', u'32')])
-            result = self.app.post('/ralph/edit', data=data,
-                                   follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            self.assertEqual(result.get_data(as_text=True), 'ok')
-
-    def test_hub_edit_post_logged_in_owner_invalid_data_1(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            # some indexes and widgets are not integers
-            data = ImmutableMultiDict(
-                [('right_indexes[]', u'0a'), ('right_indexes[]', u'1'),
-                 ('right_indexes[]', u'2'), ('right_indexes[]', u'3'),
-                 ('right_indexes[]', u'4'), ('right_indexes[]', u'5'),
-                 ('right_indexes[]', u'6'), ('right_indexes[]', u'7'),
-                 ('right_indexes[]', u'8'), ('right_widgets[]', u'32'),
-                 ('right_widgets[]', u'33a'), ('right_widgets[]', u'34'),
-                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
-                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
-                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
-                 ('js', u'true'), ('left_indexes[]', u'0a'),
-                 ('left_indexes[]', u'1'), ('left_widgets[]', u'31a'),
-                 ('left_widgets[]', u'32')])
-            result = self.app.post('/ralph/edit', data=data,
-                                   follow_redirects=True)
-            self.assertEqual(result.status_code, 400)
-
-    def test_hub_edit_post_logged_in_owner_invalid_data_2(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            # indexes len don't match widgets len
-            data = ImmutableMultiDict(
-                [('right_indexes[]', u'1'), ('right_indexes[]', u'2'),
-                 ('right_indexes[]', u'3'), ('right_indexes[]', u'4'),
-                 ('right_indexes[]', u'5'), ('right_indexes[]', u'6'),
-                 ('right_indexes[]', u'7'), ('right_indexes[]', u'8'),
-                 ('right_widgets[]', u'32'), ('right_widgets[]', u'34'),
-                 ('right_widgets[]', u'35'), ('right_widgets[]', u'36'),
-                 ('right_widgets[]', u'37'), ('right_widgets[]', u'38'),
-                 ('right_widgets[]', u'39'), ('right_widgets[]', u'40'),
-                 ('js', u'true'), ('left_indexes[]', u'0'),
-                 ('left_indexes[]', u'1'), ('left_widgets[]', u'32')])
-            result = self.app.post('/ralph/edit', data=data,
-                                   follow_redirects=True)
-            self.assertEqual(result.status_code, 400)
diff --git a/hubs/tests/views/test_hub_widgets.py b/hubs/tests/views/test_hub_widgets.py
deleted file mode 100644
index bef72bb..0000000
--- a/hubs/tests/views/test_hub_widgets.py
+++ /dev/null
@@ -1,138 +0,0 @@
-from __future__ import unicode_literals
-
-from flask import json
-from six.moves.urllib.parse import urlparse
-
-from hubs.app import app
-from hubs.models import Hub, Widget
-from hubs.tests import APPTest, FakeAuthorization, auth_set
-
-
-class HubWidgetsTestCase(APPTest):
-
-    def test_hub_add_widget_get_no_args(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.get('/ralph/add', follow_redirects=False)
-        self.assertEqual(result.status_code, 400)
-        expected_str = 'Invalid position provided'
-        self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_hub_add_widget_get_with_args(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.get('/ralph/add?position=right',
-                                  follow_redirects=True)
-        self.assertEqual(result.status_code, 200)
-        page_html = result.get_data(as_text=True)
-        self.assertIn('Adding a widget to hub: ralph', page_html)
-        self.assertIn('<form method="post" action="/ralph/add">', page_html)
-        self.assertIn('<input type="hidden" name="position" value="right" />',
-                      page_html)
-
-    def test_hub_add_widget_post_no_widget_name(self):
-        data = {"position": "left"}
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.post(
-                '/ralph/add', data=data, follow_redirects=False)
-        self.assertEqual(result.status_code, 400)
-        expected_str = 'Invalid request sent'
-        self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_hub_add_widget_post_invalid_widget_name(self):
-        data = {'widget': 'invalid_widget_name',
-                'position': 'right'}
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.post(
-                '/ralph/add', data=data, follow_redirects=False)
-        self.assertEqual(result.status_code, 404)
-        expected_str = 'Unknown widget called'
-        self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_hub_add_widget_post_valid_widget_name_no_args(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            data = {
-                'widget': 'memberships',
-                'position': 'right',
-                }
-            result = self.app.post('/ralph/add', data=data)
-            self.assertEqual(result.status_code, 200)
-            self.assertEqual(
-                json.loads(result.get_data(as_text=True)),
-                {"status": "ADDED"})
-            result = self.app.get('/ralph/edit')
-            self.assertEqual(result.status_code, 200)
-            page_html = result.get_data(as_text=True)
-            self.assertIn('data-url="/ralph/w/memberships/', page_html)
-
-    def test_hub_add_widget_post_valid_widget_name_with_args(self):
-        self.assertEqual(
-            Widget.query.filter(
-                Hub.name == "ralph",
-                Widget.plugin == "about",
-            ).count(), 1)
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            data = {
-                'text': 'text of widget',
-                'position': 'right',
-                }
-            result = self.app.post('/ralph/add/about', data=data,
-                                   follow_redirects=False)
-            self.assertEqual(result.status_code, 200)
-            self.assertEqual(
-                json.loads(result.get_data(as_text=True)),
-                {"status": "ADDED"})
-            self.assertEqual(
-                Widget.query.filter(
-                    Hub.name == "ralph",
-                    Widget.plugin == "about",
-                ).count(), 2)
-
-    def test_hub_edit_widget_get_logged_in(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.get('/ralph/37/edit', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            expected_str = '/ralph/37/edit'
-            self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_hub_edit_widget_get_logged_out(self):
-        result = self.app.get('/ralph/31/edit', follow_redirects=False)
-        self.assertEqual(result.status_code, 302)
-        self.assertEqual(urlparse(result.location).path, "/login")
-
-    def test_hub_edit_widget_post_empty_data_logged_in(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            data = {}
-            url = '/ralph/37/edit'
-            result = self.app.post(url, data=data, follow_redirects=False)
-            self.assertEqual(result.status_code, 302)
-            self.assertEqual(urlparse(result.location).path, '/ralph/edit')
-
-    def test_hub_add_widget_valid_side(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            url = '/ralph/add/about?position=right'
-            result = self.app.get(url)
-            self.assertIn('Adding widget "about" to hub ralph',
-                          result.get_data(as_text=True))
-
-    def test_hub_add_widget_invalid_side(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            url = '/ralph/add/about?position=invalid'
-            result = self.app.get(url)
-            self.assertEqual(result.status_code, 400)
-
-    def test_hub_delete(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            url = '/ralph/37/delete'  # 37 is widget fedmsgstats for ralph
-            result = self.app.post(url)
-            self.assertEqual(result.status_code, 302)
-            self.assertIn('/ralph/edit', result.get_data(as_text=True))
diff --git a/hubs/tests/views/test_widget.py b/hubs/tests/views/test_widget.py
deleted file mode 100644
index 7a8d2f7..0000000
--- a/hubs/tests/views/test_widget.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from __future__ import unicode_literals
-
-
-from hubs.app import app
-from hubs.tests import APPTest, auth_set
-
-
-class WidgetTestCase(APPTest):
-
-    def test_source_name(self):
-        with auth_set(app, None):
-            url = '/source/about'
-            result = self.app.get(url)
-            self.assertEqual(result.status_code, 302)
-            expected_str = 'https://pagure.io/fedora-hubs/' \
-                           'blob/develop/f/hubs/widgets/about/__init__.py'
-            self.assertIn(expected_str, result.get_data(as_text=True))
-
-    def test_source_name_not_existent(self):
-        with auth_set(app, None):
-            url = '/source/notexistent'
-            result = self.app.get(url)
-            self.assertEqual(result.status_code, 404)
diff --git a/hubs/tests/widgets/test_about.py b/hubs/tests/widgets/test_about.py
index 1cb4ab1..703af25 100644
--- a/hubs/tests/widgets/test_about.py
+++ b/hubs/tests/widgets/test_about.py
@@ -1,25 +1,10 @@
 from __future__ import unicode_literals
 
-import json
-
-from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
 
 
 class TestAbout(WidgetTest):
     plugin = 'about'  # The name in hubs.widgets.registry
 
-    def test_data_simple(self):
-        widget = widget_instance('ralph', self.plugin)
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data['data'], {
-            'text': 'Testing.',
-            'title': "<span class='glyphicon glyphicon-info-sign' "
-                     "aria-hidden='true'></span> About",
-            'edit_mode': False,
-        })
-
     def test_view_authz(self):
         self._test_view_authz()
diff --git a/hubs/tests/widgets/test_badges.py b/hubs/tests/widgets/test_badges.py
index a984070..9151ed2 100644
--- a/hubs/tests/widgets/test_badges.py
+++ b/hubs/tests/widgets/test_badges.py
@@ -1,11 +1,9 @@
 from __future__ import unicode_literals
 
-import json
-
 from mock import Mock, patch
 
 import hubs.widgets
-from hubs.tests import FakeAuthorization, widget_instance
+from hubs.tests import widget_instance
 from . import WidgetTest
 
 
@@ -14,11 +12,9 @@ class TestBadges(WidgetTest):
 
     def test_data_simple(self):
         widget = widget_instance('ralph', self.plugin)
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertEquals(data['plugin'], 'badges')
-        self.assertIn('assertions', data['data'].keys())
+        func = widget.module.get_cached_functions()['GetBadges']
+        result = func(widget)()
+        self.assertIn('assertions', result.keys())
 
     def test_should_invalidate_wrong_topic(self):
         widget = widget_instance('ralph', self.plugin)
diff --git a/hubs/tests/widgets/test_contact.py b/hubs/tests/widgets/test_contact.py
index 7e06862..f011392 100644
--- a/hubs/tests/widgets/test_contact.py
+++ b/hubs/tests/widgets/test_contact.py
@@ -76,9 +76,10 @@ class ContactsTest(WidgetTest):
 
     def test_data_simple(self):
         user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % self.widget_idx, user)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data['data'], {
+        widget = Widget.query.get(self.widget_idx)
+        response = self.check_url(
+            '/ralph/w/contact/%i/' % self.widget_idx, user)
+        self.assertDictEqual(response.context, {
             'account_age': 'Oct 2010',
             'email': 'ralph@fedoraproject.org',
             'ircnick': 'ralph',
@@ -88,6 +89,8 @@ class ContactsTest(WidgetTest):
             'timezone': 'UTC',
             'usergroup': True,
             'edit_mode': False,
+            'widget': widget.module,
+            'widget_instance': widget,
         })
 
     def test_view_authz(self):
diff --git a/hubs/tests/widgets/test_fedmsgstats.py b/hubs/tests/widgets/test_fedmsgstats.py
index 2a4508a..91778b4 100644
--- a/hubs/tests/widgets/test_fedmsgstats.py
+++ b/hubs/tests/widgets/test_fedmsgstats.py
@@ -1,7 +1,5 @@
 from __future__ import unicode_literals
 
-import json
-
 from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
 
@@ -12,9 +10,9 @@ class TestFedmsgStats(WidgetTest):
     def test_data_simple(self):
         widget = widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertDictEqual(data['data'], {
+        response = self.check_url(
+            '/ralph/w/%s/%i/' % (self.plugin, widget.idx), user)
+        self.assertDictEqual(response.context, {
             'fedmsgs': 83854,
             'fedmsgs_text': '83,854',
             'subscribers': [],
@@ -22,9 +20,11 @@ class TestFedmsgStats(WidgetTest):
             'subscribers_text': '0',
             'subscribed_text': '0',
             'username': 'ralph',
-            'hub_subscribe_url': '/api/hub/ralph/subscribe',
-            'hub_unsubscribe_url': '/api/hub/ralph/unsubscribe',
+            'hub_subscribe_url': '/api/hubs/ralph/subscribe',
+            'hub_unsubscribe_url': '/api/hubs/ralph/unsubscribe',
             'edit_mode': False,
+            'widget': widget.module,
+            'widget_instance': widget,
         })
 
     def test_view_authz(self):
diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index 2e33ade..5a489d3 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -117,57 +117,6 @@ class HalpViewsTestCase(WidgetTest):
     def test_view_authz(self):
         self._test_view_authz()
 
-    def test_json(self):
-        response = self.app.get('/ralph/%i/json' % self.widget.idx)
-        self.assertEqual(response.status_code, 200)
-        data = json.loads(response.get_data(as_text=True))
-        self.assertEquals(data['plugin'], 'halp')
-        self.assertIn('hubs', data['data'].keys())
-
-    def test_config_add(self):
-        user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/w/halp/add?position=right', user)
-        self.assertEqual(response.context["mode"], "add")
-        self.assertEqual(response.context["initial"], {
-            "hubs": ["ralph"], "per_page": 4,
-            })
-        self.assertEqual(
-            response.context["url"], "/ralph/add/halp?position=right")
-
-    def test_config_edit(self):
-        user = FakeAuthorization('ralph')
-        url = '/ralph/w/halp/%i/config' % self.widget.idx
-        response = self.check_url(url, user)
-        self.assertEqual(response.context["mode"], "edit")
-        self.assertEqual(response.context["initial"], {
-            'hubs': ['fedora-devel'],
-            'per_page': 3,
-            })
-        self.assertEqual(
-            response.context["url"], "/ralph/%i/edit" % self.widget.idx)
-
-    def test_config_authz(self):
-        urls = [
-            '/ralph/w/halp/add',
-            '/ralph/w/halp/%i/config' % self.widget.idx,
-            ]
-        # Anonymous
-        for url in urls:
-            self.check_url(url, None, 403)
-        # Logged-in
-        user = FakeAuthorization('decause')
-        for url in urls:
-            self.check_url(url, user, 403)
-        # Member
-        hub = Hub.query.get("ralph")
-        hub.subscribe(User.query.get("decause"), "member")
-        for url in urls:
-            self.check_url(url, user, 403)
-        # Owner
-        user = FakeAuthorization('ralph')
-        for url in urls:
-            self.check_url(url, user, 200)
-
     def test_config_hubs_suggest(self):
         response = self.app.get('/w/halp/hubs')
         self.assertEqual(response.status_code, 200)
diff --git a/hubs/tests/widgets/test_library.py b/hubs/tests/widgets/test_library.py
index 11e4c92..6cb8297 100644
--- a/hubs/tests/widgets/test_library.py
+++ b/hubs/tests/widgets/test_library.py
@@ -1,7 +1,5 @@
 from __future__ import unicode_literals
 
-import json
-
 from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
 
@@ -12,27 +10,17 @@ class TestLibrary(WidgetTest):
     def test_data_simple(self):
         widget = widget_instance('ralph', self.plugin)
         user = FakeAuthorization('ralph')
-        response = self.check_url('/ralph/%i/json' % widget.idx, user)
-        data = json.loads(response.get_data(as_text=True))
+        response = self.check_url(
+            '/ralph/w/%s/%i/' % (self.plugin, widget.idx), user)
         expected_dict = {
-            "config": {
-                "urls": "ralph/"
-            },
-            "data": {
-                'title': 'Library',
-                "urls": [
-                    "<a href=\"ralph/\">ralph/</a>"
-                ],
-                'edit_mode': False,
-            },
-            "description": None,
-            "hub": "ralph",
-            "id": 52,
-            "index": 51,
-            "left": False,
-            "plugin": "library"
+            "urls": [
+                "<a href=\"ralph/\">ralph/</a>"
+            ],
+            'edit_mode': False,
+            'widget': widget.module,
+            'widget_instance': widget,
         }
-        self.assertDictEqual(data['data'], expected_dict['data'])
+        self.assertDictEqual(response.context, expected_dict)
 
     def test_view_authz(self):
         self._test_view_authz()
diff --git a/hubs/tests/widgets/test_meetings.py b/hubs/tests/widgets/test_meetings.py
index 0ac32a6..6536856 100644
--- a/hubs/tests/widgets/test_meetings.py
+++ b/hubs/tests/widgets/test_meetings.py
@@ -1,7 +1,5 @@
 from __future__ import unicode_literals
 
-import json
-
 from hubs.tests import FakeAuthorization, widget_instance
 from . import WidgetTest
 
@@ -13,10 +11,9 @@ class TestMeetings(WidgetTest):
         team = 'i18n'
         widget = widget_instance(team, self.plugin)
         user = FakeAuthorization('ralph')
-        response = self.check_url('/%s/%i/json' % (team, widget.idx), user)
-        data = json.loads(response.get_data(as_text=True))
-        calendar_name = data['data']['calendar']
-        self.assertIn(team, calendar_name)
+        response = self.check_url(
+            '/%s/w/%s/%i/' % (team, self.plugin, widget.idx), user)
+        self.assertIn(team, response.context["calendar"])
 
     def test_render_simple(self):
         team = 'i18n'
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
index cc576c7..36df575 100644
--- a/hubs/utils/views.py
+++ b/hubs/utils/views.py
@@ -74,13 +74,14 @@ class WidgetConfigError(Exception):
     pass
 
 
-def create_widget_instance(hub, widget, position):
+def create_widget_instance(hub, widget, position, config=None):
     """View helper to instanciate a widget on a hub.
 
     Arguments:
         hub (hubs.models.Hub): Instance of the hub to create the widget in.
         widget (hubs.widgets.base.Widget): Widget to instanciate.
-        position (str): either ``left`` or ``right``.
+        position (str): Either ``left`` or ``right``.
+        config (dict): Initial configuration for the widget.
     """
     widget_instance = Widget(
         hub=hub, plugin=widget.name, index=-1,
@@ -88,28 +89,34 @@ def create_widget_instance(hub, widget, position):
     flask.g.db.add(widget_instance)
     flask.g.db.flush()  # will populate Widget.config
     try:
-        configure_widget_instance(widget_instance)
+        configure_widget_instance(widget_instance, config)
     except WidgetConfigError as e:
         flask.flash(e.args[0], "error")
     else:
         flask.flash("The widget has been added.")
+    # reorder widgets
+    reorder_widgets(hub, widget_instance.left)
+    return widget_instance
 
 
-def configure_widget_instance(widget_instance):
+def configure_widget_instance(widget_instance, widget_config):
     """Configure a widget instance using the request form data.
 
     Arguments:
         widget_instance (hubs.models.Widget): Instance of the widget that is to
             be configured.
+        widget_config (dict): Configuration to apply to the widget.
     """
+    if not widget_config:
+        return
     config = {}
     for param in widget_instance.module.get_parameters():
-        val = flask.request.form.get(param.name)
+        val = widget_config.get(param.name)
         if not val:
             raise WidgetConfigError(
                 'You must provide a value for: %s' % param.name)
         try:
-            config[param.name] = param.validator.from_string(val)
+            config[param.name] = param.validator(val)
         except ValueError as err:
             raise WidgetConfigError('Invalid data provided, error: %s' % err)
     # Updating in-place is not supported, it's a class property.
@@ -119,7 +126,7 @@ def configure_widget_instance(widget_instance):
     widget_instance.config = cur_config
     # Set the visibility parameter.
     try:
-        widget_instance.visibility = flask.request.form["visibility"]
+        widget_instance.visibility = widget_config["visibility"]
     except KeyError:
         pass  # the value is optional.
     # Update the hub's mtime.  TODO: use a SQLAlchemy signal here.
@@ -136,6 +143,27 @@ def configure_widget_instance(widget_instance):
             'if the error persists, please warn an admin')
 
 
+def reorder_widgets(hub, is_left):
+    """Reset widget instances indicies for a hub and a column."""
+    all_widgets = [w for w in hub.widgets if w.left == is_left]
+    for index, widget in enumerate(all_widgets):
+        widget.index = index
+
+
+def move_widget(widget_instance, new_index):
+    """Move a widget instance to a new index in the same column."""
+    all_widgets = [
+        w for w in widget_instance.hub.widgets
+        if w.left == widget_instance.left
+        ]
+    old_index = [w.idx for w in all_widgets].index(widget_instance.idx)
+    # Move the widget in the list
+    all_widgets.insert(new_index, all_widgets.pop(old_index))
+    # Apply indices according to the position in the list
+    for index, widget in enumerate(all_widgets):
+        widget.index = index
+
+
 def authenticated():
     """ Utility function checking if the current auth is set or not."""
     return hasattr(flask.g, 'auth') \
@@ -158,33 +186,43 @@ def login_required(function):
     return decorated_function
 
 
+def check_hub_access(hub, action, json=False):
+    """Check access to the hub for the specified action.
+
+    Raises:
+        :py:class:`werkzeug.exceptions.Forbidden`: The action is denied (403).
+    """
+    try:
+        user = flask.g.user
+    except AttributeError:
+        user = None
+    if not hub.allows(user, action):
+        if action == "view":
+            msg = "This hub is for members only."
+        elif action == "config":
+            msg = "You are not allowed to configure this hub."
+        else:
+            msg = "Access forbidden."
+        if json:
+            response = flask.jsonify({
+                "status": "ERROR", "message": msg, "hub": hub.name,
+                })
+        else:
+            response = flask.render_template(
+                'errors/hub.html', hub=hub, msg=msg,
+                )
+        flask.abort(403, response=flask.make_response(response, 403))
+    return True
+
+
 def require_hub_access(action, url_param="name", json=False):
-    """Check access to the hub for the specified action."""
+    """View decorator to check access to the hub for the specified action."""
     def decorator(function):
         @functools.wraps(function)
         def wrapper(*args, **kwargs):
             hub_name = kwargs[url_param]
             hub = get_hub(hub_name, load_config=True)
-            try:
-                user = flask.g.user
-            except AttributeError:
-                user = None
-            if not hub.allows(user, action):
-                if action == "view":
-                    msg = "This hub is for members only."
-                elif action == "config":
-                    msg = "You are not allowed to configure this hub."
-                else:
-                    msg = "Access forbidden."
-                if json:
-                    result = flask.jsonify({
-                        "status": "ERROR", "message": msg, "hub": hub.name,
-                        })
-                else:
-                    result = flask.render_template(
-                        'errors/hub.html', hub=hub, msg=msg,
-                        )
-                return result, 403
+            check_hub_access(hub, action, json)
             return function(*args, **kwargs)
         return wrapper
     return decorator
diff --git a/hubs/views/__init__.py b/hubs/views/__init__.py
index 33b68f2..4ea49ec 100644
--- a/hubs/views/__init__.py
+++ b/hubs/views/__init__.py
@@ -4,6 +4,5 @@ from __future__ import absolute_import
 
 from .root import *
 from .hub import *
-from .widget import *
 from .user import *
 from .api import *
diff --git a/hubs/views/api.py b/hubs/views/api.py
deleted file mode 100644
index b1232a5..0000000
--- a/hubs/views/api.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from __future__ import unicode_literals, absolute_import
-
-
-import flask
-import hubs.models
-
-from hubs.app import app
-from hubs.utils.views import get_hub, login_required
-
-
-@app.route('/api/hub/<hub>/subscribe', methods=['POST'])
-@login_required
-def hub_subscribe(hub):
-    hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.auth.nickname)
-    hub.subscribe(user)
-    flask.g.db.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/unsubscribe', methods=['POST'])
-@login_required
-def hub_unsubscribe(hub):
-    hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.auth.nickname)
-    try:
-        hub.unsubscribe(user)
-    except KeyError:
-        return flask.abort(400)
-    flask.g.db.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/star', methods=['POST'])
-@login_required
-def hub_star(hub):
-    hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.auth.nickname)
-    hub.subscribe(user, role='stargazer')
-    flask.g.db.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/unstar', methods=['POST'])
-@login_required
-def hub_unstar(hub):
-    hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.auth.nickname)
-    try:
-        hub.unsubscribe(user, role='stargazer')
-    except KeyError:
-        return flask.abort(400)
-    flask.g.db.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/join', methods=['POST'])
-@login_required
-def hub_join(hub):
-    hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.auth.nickname)
-    hub.subscribe(user, role='member')
-    flask.g.db.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/api/hub/<hub>/leave', methods=['POST'])
-@login_required
-def hub_leave(hub):
-    hub = get_hub(hub)
-    user = hubs.models.User.by_username(flask.g.auth.nickname)
-    try:
-        hub.unsubscribe(user, role='member')
-    except KeyError:
-        return flask.abort(400)
-    flask.g.db.commit()
-    return flask.redirect(flask.url_for('hub', name=hub.name))
diff --git a/hubs/views/api/__init__.py b/hubs/views/api/__init__.py
new file mode 100644
index 0000000..5375623
--- /dev/null
+++ b/hubs/views/api/__init__.py
@@ -0,0 +1,7 @@
+from __future__ import absolute_import
+
+# flake8: noqa
+
+from .hub_association import *
+from .hub_config import *
+from .hub_widget import *
diff --git a/hubs/views/api/hub_association.py b/hubs/views/api/hub_association.py
new file mode 100644
index 0000000..9b5e8ba
--- /dev/null
+++ b/hubs/views/api/hub_association.py
@@ -0,0 +1,80 @@
+from __future__ import absolute_import
+
+import logging
+
+import flask
+
+import hubs.models
+from hubs.app import app
+from hubs.utils.views import get_hub, login_required
+
+log = logging.getLogger(__name__)
+
+
+@app.route('/api/hubs/<hub>/subscribe', methods=['POST'])
+@login_required
+def api_hub_subscribe(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
+    hub.subscribe(user)
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hubs/<hub>/unsubscribe', methods=['POST'])
+@login_required
+def api_hub_unsubscribe(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
+    try:
+        hub.unsubscribe(user)
+    except KeyError:
+        return flask.abort(400)
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hubs/<hub>/star', methods=['POST'])
+@login_required
+def api_hub_star(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
+    hub.subscribe(user, role='stargazer')
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hubs/<hub>/unstar', methods=['POST'])
+@login_required
+def api_hub_unstar(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
+    try:
+        hub.unsubscribe(user, role='stargazer')
+    except KeyError:
+        return flask.abort(400)
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hubs/<hub>/join', methods=['POST'])
+@login_required
+def api_hub_join(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
+    hub.subscribe(user, role='member')
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
+
+
+@app.route('/api/hubs/<hub>/leave', methods=['POST'])
+@login_required
+def api_hub_leave(hub):
+    hub = get_hub(hub)
+    user = hubs.models.User.by_username(flask.g.auth.nickname)
+    try:
+        hub.unsubscribe(user, role='member')
+    except KeyError:
+        return flask.abort(400)
+    flask.g.db.commit()
+    return flask.redirect(flask.url_for('hub', name=hub.name))
diff --git a/hubs/views/api/hub_config.py b/hubs/views/api/hub_config.py
new file mode 100644
index 0000000..fa76e29
--- /dev/null
+++ b/hubs/views/api/hub_config.py
@@ -0,0 +1,144 @@
+from __future__ import absolute_import
+
+import logging
+
+import flask
+
+import hubs.models
+from hubs.app import app
+from hubs.utils.views import (
+    get_hub, check_hub_access, RequestValidator, require_hub_access,
+    )
+
+log = logging.getLogger(__name__)
+
+
+class ConfigChangeError(Exception):
+    pass
+
+
+@app.route('/api/hubs/<name>/config', methods=['GET', 'PUT'])
+@require_hub_access("view", json=True)
+def api_hub_config(name):
+    hub = get_hub(name)
+    if flask.request.method == 'PUT':
+        check_hub_access(hub, "config", json=True)
+        request_data = flask.request.get_json()
+        if request_data is None:
+            return flask.jsonify({
+                "status": "ERROR",
+                "message": "No configuration change provided"
+                })
+        try:
+            if request_data.get("config"):
+                result = hub_config_put_config(hub, request_data["config"])
+            if request_data.get("users"):
+                result = hub_config_put_users(hub, request_data["users"])
+        except ConfigChangeError as e:
+            result = e.args[0]
+        else:
+            result = {"status": "OK"}
+        try:
+            flask.g.db.commit()
+        except Exception as err:
+            result = {"status": "ERROR", "message": str(err)}
+        return flask.jsonify(result)
+    result = {"status": "OK", "data": hub.get_props()}
+    return flask.jsonify(result)
+
+
+def hub_config_put_config(hub, config):
+    # Validate values
+    def _validate_chat_domain(value):
+        valid_chat_domains = [
+            network["domain"] for network in app.config["CHAT_NETWORKS"]
+            ]
+        if not value and len(valid_chat_domains) > 0:
+            value = valid_chat_domains[0]
+        if value not in valid_chat_domains:
+            raise ValueError("Unsupported chat domain.")
+        return value
+
+    validator = RequestValidator(dict(
+        # Only allow the parameters listed in __json__().
+        (key, None) for key in hub.config.__json__().keys()
+    ))
+    validator.converters["chat_domain"] = _validate_chat_domain
+    try:
+        values = validator(config)
+    except ValueError as e:
+        result = {"status": "ERROR", "message": "Invalid value(s)"}
+        result["fields"] = e.args[0]
+        raise ConfigChangeError(result)
+
+    # Now set the configuration values.
+    for key, value in values.items():
+        setattr(hub.config, key, value)
+
+
+def hub_config_put_users(hub, user_roles):
+    new_associations = []
+    for role in user_roles:
+        for u in user_roles[role]:
+            new_associations.append((u["username"], role))
+    # Remove old associations
+    for assoc in hub.associations:
+        if assoc.hub != hub:
+            continue
+        try:
+            new_associations.remove(
+                (assoc.user.username, assoc.role))
+        except ValueError:
+            hub.associations.remove(assoc)
+    # Add new associations
+    for assoc in new_associations:
+        username, role = assoc
+        user = hubs.models.User.get(username=username)
+        if user is None:
+            result = {
+                "status": "ERROR",
+                "fields": {"username": "Unknown user"},
+                "message": "Unknown user {}".format(u["username"]),
+                }
+            raise ConfigChangeError(result)
+        hub.associations.append(hubs.models.Association(
+            hub=hub, user=user, role=role))
+    flask.g.db.commit()
+
+
+@app.route('/api/hubs/<name>/config/suggest-users')
+@require_hub_access("config", json=True)
+def api_hub_config_suggest_users(name):
+    MAX_SUGGESTS = 10
+    hub = get_hub(name)
+    results = flask.g.db.query(
+        hubs.models.User.username,
+        hubs.models.User.fullname,
+        )
+    query = flask.request.args.get("q")
+    if query:
+        results = results.filter(
+            hubs.models.User.username.ilike("%{}%".format(query))
+        )
+    exclude = flask.request.args.get("exclude-role")
+    if exclude:
+        exclude_query = flask.g.db.query(
+                hubs.models.User.username
+            ).join(
+                hubs.models.Association
+            ).join(
+                hubs.models.Hub
+            ).filter(
+                hubs.models.Hub.name == hub.name,
+                hubs.models.Association.role == exclude,
+            )
+        results = results.filter(
+            ~hubs.models.User.username.in_(exclude_query)
+            )
+    results = results.order_by(hubs.models.User.username).limit(MAX_SUGGESTS)
+    return flask.jsonify({
+        "status": "OK",
+        "data": [
+            {"username": r[0], "fullname": r[1]} for r in results
+            ],
+        })
diff --git a/hubs/views/api/hub_widget.py b/hubs/views/api/hub_widget.py
new file mode 100644
index 0000000..3ef777d
--- /dev/null
+++ b/hubs/views/api/hub_widget.py
@@ -0,0 +1,111 @@
+from __future__ import absolute_import
+
+import logging
+
+import flask
+from hubs.app import app
+from hubs.widgets import registry
+from hubs.utils.views import (
+    create_widget_instance, configure_widget_instance, get_hub,
+    get_widget_instance, WidgetConfigError,
+    check_hub_access, require_hub_access,
+    move_widget, reorder_widgets,
+    )
+
+log = logging.getLogger(__name__)
+
+
+@app.route('/api/widgets/', methods=['GET'])
+def api_widgets():
+    widgets = []
+    for widget in registry.values():
+        widgets.append(widget.get_props(None))
+    return flask.jsonify({"status": "OK", "data": widgets})
+
+
+@app.route('/api/hubs/<hub>/widgets/', methods=['GET', 'POST'])
+@require_hub_access("view", url_param="hub", json=True)
+def api_hub_widgets(hub):
+    hub = get_hub(hub)
+    try:
+        user = flask.g.user
+    except AttributeError:
+        user = None
+    if flask.request.method == 'POST':
+        check_hub_access(hub, "config", json=True)
+        request_data = flask.request.get_json()
+        try:
+            widget_name = request_data["name"]
+            widget_config = request_data["config"]
+            position = request_data["position"]
+        except KeyError:
+            flask.abort(400, 'Invalid request sent')
+        if position not in ["left", "right"]:
+            flask.abort(400, 'Invalid request sent')
+        available_widgets = [
+            widget.name
+            for widget in registry.values()
+            if widget.position in ['both', position]
+            ]
+        if widget_name not in available_widgets:
+            flask.abort(400, 'Unknown widget')
+        widget = registry[widget_name]
+        create_widget_instance(hub, widget, position, widget_config)
+        flask.g.db.commit()
+        return flask.jsonify({"status": "OK"})
+    user_can_config = hub.allows(user, "config")
+    widgets = []
+    for widget_instance in hub.widgets:
+        if not widget_instance.enabled:
+            continue
+        if not widget_instance.allows(user, "view"):
+            continue
+        widgets.append(widget_instance.get_props(
+            with_secret_config=user_can_config))
+    return flask.jsonify({"status": "OK", "data": widgets})
+
+
+@app.route('/api/hubs/<hub>/widgets/<int:idx>/',
+           methods=['GET', 'PUT', 'DELETE'])
+@require_hub_access("view", url_param="hub", json=True)
+def api_hub_widget(hub, idx):
+    widget_instance = get_widget_instance(hub, idx)
+    hub = widget_instance.hub
+    try:
+        user = flask.g.user
+    except AttributeError:
+        user = None
+    if flask.request.method == "GET":
+        user_can_config = hub.allows(user, "config")
+        result = widget_instance.get_props(with_secret_config=user_can_config)
+        return flask.jsonify({"status": "OK", "data": result})
+    elif flask.request.method == "PUT":
+        check_hub_access(hub, "config", json=True)
+        request_data = flask.request.get_json()
+        widget_config = request_data.get("config", {})
+        try:
+            configure_widget_instance(widget_instance, widget_config)
+        except WidgetConfigError as e:
+            return flask.jsonify({"status": "ERROR", "message": e.args[0]})
+        if "index" in request_data:
+            # Reorder the widgets
+            move_widget(widget_instance, request_data["index"])
+        try:
+            flask.g.db.commit()
+        except Exception as e:
+            msg = "Could not configure this widget: {}".format(e)
+            return flask.jsonify({"status": "ERROR", "message": msg})
+        return flask.jsonify({"status": "OK"})
+    elif flask.request.method == "DELETE":
+        # Remove the widget from the hub.
+        check_hub_access(hub, "config", json=True)
+        is_left = widget_instance.left
+        flask.g.db.delete(widget_instance)
+        try:
+            flask.g.db.commit()
+        except Exception as e:
+            msg = "Could not remove this widget: {}".format(e)
+            return flask.jsonify({"status": "ERROR", "message": msg})
+        reorder_widgets(hub, is_left)
+        return flask.jsonify({"status": "OK"})
+    flask.abort(400)
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index ff52725..6677a7e 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -1,13 +1,11 @@
 from __future__ import unicode_literals, absolute_import
 
-import datetime
 import flask
 import hubs.models
 
 from hubs.app import app
 from hubs.utils.views import (
-    get_hub, get_sse_url, get_visible_widgets, login_required,
-    RequestValidator, require_hub_access,
+    get_hub, get_sse_url, get_menu_entries, get_visible_widgets, require_hub_access,
     )
 
 
@@ -24,269 +22,3 @@ def hub(name):
         edit=False,
         sse_url=get_sse_url("hub/{}".format(hub.name)),
         )
-
-
-@app.route('/<name>/json/')
-@app.route('/<name>/json')
-@require_hub_access("view", json=True)
-def hub_json(name):
-    hub = get_hub(name)
-    response = flask.jsonify(hub.__json__())
-    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
-    return response
-
-
-@app.route('/<name>/edit', methods=['GET', 'POST'])
-@login_required
-@require_hub_access("config")
-def hub_edit(name):
-    hub = get_hub(name, load_config=True)
-    if flask.request.method == 'POST':
-        return hub_edit_post(hub)
-    else:
-        return hub_edit_get(hub)
-
-
-def hub_edit_get(hub):
-    widgets = get_visible_widgets(hub)
-    return flask.render_template(
-        'hubs.html',
-        hub=hub,
-        widgets=widgets,
-        edit=True,
-        sse_url=get_sse_url("hub/{}".format(hub.name)),
-        )
-
-
-def hub_edit_post(hub):
-    is_js = flask.request.form.get('js', False)
-
-    error = False
-
-    # Check the input submitted
-    # Right side
-    r_widget_ids = [
-        w.strip().replace('widget-', '')
-        for w in flask.request.form.getlist('right_widgets[]')
-        if w.strip()
-        ]
-    try:
-        r_widget_ids = [int(w) for w in r_widget_ids]
-    except:
-        flask.flash('Invalid widget identifiers submitted', 'error')
-        error = True
-
-    r_indexes = [
-        i.strip() for i in flask.request.form.getlist('right_indexes[]')
-        if i.strip()
-        ]
-
-    try:
-        r_indexes = [int(i) for i in r_indexes]
-    except:
-        if not is_js:
-            flask.flash('Invalid indexes submitted', 'error')
-        error = True
-
-    if len(r_widget_ids) != len(r_indexes):
-        if not is_js:
-            flask.flash(
-                'The number of indexes and the number of widgets are not of '
-                'the same length', 'error')
-        error = True
-
-    # Left side
-    l_widget_ids = [
-        w.strip().replace('widget-', '')
-        for w in flask.request.form.getlist('left_widgets[]')
-        if w.strip()
-        ]
-    try:
-        l_widget_ids = [int(w) for w in l_widget_ids]
-    except:
-        flask.flash('Invalid widget identifiers submitted', 'error')
-        error = True
-
-    l_indexes = [
-        i.strip() for i in flask.request.form.getlist('left_indexes[]')
-        if i.strip()
-        ]
-
-    try:
-        l_indexes = [int(i) for i in l_indexes]
-    except:
-        if not is_js:
-            flask.flash('Invalid indexes submitted', 'error')
-        error = True
-
-    if len(l_widget_ids) != len(l_indexes):
-        if not is_js:
-            flask.flash(
-                'The number of indexes and the number of widgets are not of '
-                'the same length', 'error')
-        error = True
-
-    # If all good, update the database
-    if not error:
-        for cnt, wid in enumerate(r_widget_ids):
-            widget = flask.g.db.query(hubs.models.Widget).get(wid)
-            if widget.index != r_indexes[cnt]:
-                widget.index = r_indexes[cnt]
-                flask.g.db.add(widget)
-        for cnt, wid in enumerate(l_widget_ids):
-            widget = flask.g.db.query(hubs.models.Widget).get(wid)
-            if widget.index != l_indexes[cnt]:
-                widget.index = l_indexes[cnt]
-                flask.g.db.add(widget)
-        hub.last_edited = datetime.datetime.utcnow()
-        flask.g.db.add(hub)
-        try:
-            flask.g.db.commit()
-        except Exception as err:
-            error = True
-            if not is_js:
-                flask.flash(
-                    'Could not save your changes to the database '
-                    'if the error persists, please warn an admin',
-                    'error')
-    if is_js:
-        if error:
-            flask.abort(400)
-        else:
-            return ('ok', 200)
-    else:
-        return flask.redirect(flask.url_for('hub', name=hub.name))
-
-
-@app.route('/<name>/config', methods=['GET', 'POST'])
-@login_required
-@require_hub_access("config", json=True)
-def hub_config(name):
-    hub = get_hub(name)
-    if flask.request.method == 'POST':
-        category = flask.request.args["category"]
-        if category == "config":
-            result = hub_config_post_config(hub)
-        if category == "role_change":
-            result = hub_config_post_role_change(hub)
-        if result is not None:
-            return result
-    result = hub_config_get(hub)
-    return flask.jsonify(result)
-
-
-def hub_config_get(hub):
-    roles = ["owner", "member"]
-    result = {
-        "status": "OK",
-        "result": {
-            "hubconfig": hub.config.__json__(),
-            "general": {
-                "chat_networks": app.config["CHAT_NETWORKS"],
-                "hub_visibility": hubs.models.HubConfig.VISIBILITY,
-                "roles": roles,
-            },
-            "users": {role: [] for role in roles},
-        },
-    }
-    for assoc in sorted(hub.associations, key=lambda a: a.user.username):
-        if assoc.role not in roles:
-            continue
-        user = {
-            "username": assoc.user.username,
-            "fullname": assoc.user.fullname,
-            "role": assoc.role,
-        }
-        if (assoc.role == "owner" and
-                assoc.user.username == flask.g.user.username):
-            user["locked"] = True
-        result["result"]["users"][assoc.role].append(user)
-    return result
-
-
-def hub_config_post_config(hub):
-    # Validate values
-    def _validate_chat_domain(value):
-        valid_chat_domains = [
-            network["domain"] for network in app.config["CHAT_NETWORKS"]
-            ]
-        if not value and len(valid_chat_domains) > 0:
-            value = valid_chat_domains[0]
-        if value not in valid_chat_domains:
-            raise ValueError("Unsupported chat domain.")
-        return value
-
-    validator = RequestValidator(dict(
-        # Only allow the parameters listed in __json__().
-        (key, None) for key in hub.config.__json__().keys()
-    ))
-    validator.converters["chat_domain"] = _validate_chat_domain
-    try:
-        values = validator(flask.request.form)
-    except ValueError as e:
-        result = {"status": "ERROR", "message": "Invalid value(s)"}
-        result["fields"] = e.args[0]
-        return flask.jsonify(result)
-
-    # Now set the configuration values
-    for key, value in values.items():
-        setattr(hub.config, key, value)
-    try:
-        flask.g.db.commit()
-    except Exception as err:
-        result = {"status": "ERROR", "message": str(err)}
-        return flask.jsonify(result)
-
-
-def hub_config_post_role_change(hub):
-    username = flask.request.form["username"]
-    user = hubs.models.User.get(username=username)
-    if user is None:
-        result = {
-            "status": "ERROR",
-            "fields": {"username": "Unknown user"},
-            "message": "Unknown user",
-            }
-        return flask.jsonify(result)
-    role = flask.request.form.get("role")
-    for assoc in hub.associations:
-        if assoc.hub == hub and assoc.user == user:
-            hub.associations.remove(assoc)
-    if role:
-        hub.associations.append(hubs.models.Association(
-            hub=hub, user=user, role=role))
-    flask.g.db.commit()
-
-
-@app.route('/<name>/config/suggest-users')
-@login_required
-@require_hub_access("config", json=True)
-def hub_config_suggest_users(name):
-    MAX_SUGGESTS = 10
-    hub = get_hub(name)
-    results = flask.g.db.query(hubs.models.User.username)
-    query = flask.request.args.get("q")
-    if query:
-        results = results.filter(
-            hubs.models.User.username.ilike("%{}%".format(query))
-        )
-    exclude = flask.request.args.get("exclude-role")
-    if exclude:
-        exclude_query = flask.g.db.query(
-                hubs.models.User.username
-            ).join(
-                hubs.models.Association
-            ).join(
-                hubs.models.Hub
-            ).filter(
-                hubs.models.Hub.name == hub.name,
-                hubs.models.Association.role == exclude,
-            )
-        results = results.filter(
-            ~hubs.models.User.username.in_(exclude_query)
-            )
-    results = results.order_by(hubs.models.User.username).limit(MAX_SUGGESTS)
-    return flask.jsonify({
-        "status": "OK",
-        "results": [r[0] for r in results],
-        })
diff --git a/hubs/views/widget.py b/hubs/views/widget.py
deleted file mode 100644
index 2cd7f98..0000000
--- a/hubs/views/widget.py
+++ /dev/null
@@ -1,130 +0,0 @@
-from __future__ import unicode_literals, absolute_import
-
-import flask
-
-from hubs.app import app
-from hubs.widgets import registry
-from pkg_resources import resource_isdir
-from hubs.utils.views import (
-    create_widget_instance, configure_widget_instance, get_hub,
-    get_widget_instance, login_required, WidgetConfigError,
-    get_position, require_hub_access,
-    )
-
-
-@app.route('/<name>/add', methods=['GET', 'POST'])
-@login_required
-@require_hub_access("config")
-def hub_add_widget(name):
-    hub = get_hub(name)
-    position = get_position()
-    widgets = [
-        widget
-        for widget in registry.values()
-        if widget.position in ['both', position]
-        ]
-
-    if flask.request.method == 'POST':
-        widget_name = flask.request.form.get('widget')
-        if not widget_name:
-            flask.abort(400, 'Invalid request sent')
-        if widget_name not in [w.name for w in widgets]:
-            flask.abort(404, 'Unknown widget called')
-        widget = registry[widget_name]
-        if widget.get_parameters():
-            return flask.jsonify({
-                "status": "CONFIGURE",
-                "url": widget.get_add_url(hub, position),
-                })
-        create_widget_instance(hub, widget, position)
-        return flask.jsonify({"status": "ADDED"})
-    return flask.render_template(
-        'add_widget.html',
-        hub=hub,
-        widgets=widgets,
-        position=position,
-    )
-
-
-@app.route('/<hub>/add/<widget>', methods=['GET', 'POST'])
-@login_required
-@require_hub_access("config", url_param="hub")
-def widget_add(hub, widget):
-    hub = get_hub(hub)
-    position = get_position()
-    try:
-        widget = registry[widget]
-    except KeyError:
-        flask.abort(404, 'Unknown widget: %s' % widget)
-    if flask.request.method == 'POST':
-        create_widget_instance(hub, widget, position)
-        return flask.jsonify({"status": "ADDED"})
-    return flask.render_template(
-        'widget_add.html',
-        hub=hub,
-        widget=widget,
-        position=position,
-    )
-
-
-@app.route('/<hub>/<int:idx>/edit', methods=['GET', 'POST'])
-@login_required
-@require_hub_access("config", url_param="hub")
-def widget_edit(hub, idx):
-    widget_instance = get_widget_instance(hub, idx)
-    if flask.request.method == 'POST':
-        try:
-            configure_widget_instance(widget_instance)
-        except WidgetConfigError as e:
-            flask.flash(e.args[0], "error")
-        else:
-            flask.flash("The widget has been updated.")
-        return flask.redirect(flask.url_for('hub_edit', name=hub))
-    else:
-        return flask.render_template(
-            'widget_edit.html',
-            hub=widget_instance.hub,
-            widget_instance=widget_instance,
-        )
-
-
-@app.route('/<hub>/<int:idx>/delete', methods=['POST'])
-@login_required
-@require_hub_access("config", url_param="hub")
-def widget_edit_delete(hub, idx):
-    ''' Remove a widget from a hub. '''
-    widget_instance = get_widget_instance(hub, idx)
-    flask.g.db.delete(widget_instance)
-    try:
-        flask.g.db.commit()
-    except Exception:
-        flask.flash(
-            'Could not delete this widget from this hub in the database '
-            'if the error persists, please warn an admin',
-            'error')
-    return flask.redirect(flask.url_for('hub_edit', name=hub))
-
-
-@app.route('/<hub>/<int:idx>/json')
-@require_hub_access("view", url_param="hub")
-def widget_json(hub, idx):
-    widget = get_widget_instance(hub, idx)
-    response = flask.jsonify(widget.__json__())
-    # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
-    return response
-
-
-@app.route('/source/<name>')
-def widget_source(name):
-    try:
-        widget_path = registry[name].__module__
-    except KeyError:
-        flask.abort(404)
-    widget_url = widget_path.replace(".", "/")
-    parent, _ignore, module = widget_path.rpartition(".")
-    if resource_isdir(parent, module):
-        widget_url += "/__init__.py"
-    else:
-        widget_url += ".py"
-    url = "/".join([app.config.get('SOURCE_URL'), widget_url])
-    return flask.redirect(url)
diff --git a/hubs/widgets/fedmsgstats/__init__.py b/hubs/widgets/fedmsgstats/__init__.py
index 2cecb75..62fe099 100644
--- a/hubs/widgets/fedmsgstats/__init__.py
+++ b/hubs/widgets/fedmsgstats/__init__.py
@@ -37,9 +37,9 @@ class BaseView(RootWidgetView):
         context = dict(
             username=username,
             hub_subscribe_url=flask.url_for(
-                'hub_subscribe', hub=instance.hub.name),
+                'api_hub_subscribe', hub=instance.hub.name),
             hub_unsubscribe_url=flask.url_for(
-                'hub_unsubscribe', hub=instance.hub.name),
+                'api_hub_unsubscribe', hub=instance.hub.name),
         )
         get_stats = GetStats(instance)
         context.update(get_stats())
diff --git a/hubs/widgets/stats/__init__.py b/hubs/widgets/stats/__init__.py
index b893feb..589d0ce 100644
--- a/hubs/widgets/stats/__init__.py
+++ b/hubs/widgets/stats/__init__.py
@@ -41,13 +41,14 @@ class GetStats(CachedFunction):
             subscribers_text=commas(len(subscribers)),
             stargazers_text=commas(len(stargazers)),
 
-            hub_leave_url=flask.url_for('hub_leave', hub=hub.name),
-            hub_join_url=flask.url_for('hub_join', hub=hub.name),
-            hub_unstar_url=flask.url_for('hub_unstar', hub=hub.name),
-            hub_star_url=flask.url_for('hub_star', hub=hub.name),
-            hub_subscribe_url=flask.url_for('hub_subscribe', hub=hub.name),
+            hub_leave_url=flask.url_for('api_hub_leave', hub=hub.name),
+            hub_join_url=flask.url_for('api_hub_join', hub=hub.name),
+            hub_unstar_url=flask.url_for('api_hub_unstar', hub=hub.name),
+            hub_star_url=flask.url_for('api_hub_star', hub=hub.name),
+            hub_subscribe_url=flask.url_for(
+                'api_hub_subscribe', hub=hub.name),
             hub_unsubscribe_url=flask.url_for(
-                'hub_unsubscribe', hub=hub.name),
+                'api_hub_unsubscribe', hub=hub.name),
         )
 
     def should_invalidate(self, message):

From 1389bb26b55cf2bb05b252f494489dd252d7b5df Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:09 +0000
Subject: [PATCH 955/1001] Widget add and config panels are now React-based


---

diff --git a/hubs/models.py b/hubs/models.py
index 498d4fa..55530f9 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -458,9 +458,6 @@ class Widget(ObjectAuthzMixin, BASE):
     def module(self):
         return hubs.widgets.registry[self.plugin]
 
-    @property
-    def edit_url(self):
-        return self.module.get_edit_url(self.hub, self)
 
     @property
     def enabled(self):
diff --git a/hubs/templates/add_widget.html b/hubs/templates/add_widget.html
deleted file mode 100644
index 878c2fd..0000000
--- a/hubs/templates/add_widget.html
+++ /dev/null
@@ -1,30 +0,0 @@
-
-<div class="modal-dialog" id="adding_form">
-  <div class="modal-content">
-    <form method="post" action="{{ url_for('hub_add_widget', name=hub.name) }}">
-    <input type="hidden" name="position" value="{{ position }}" />
-    <!-- Modal content-->
-      <div class="modal-header">
-        <button type="button" class="close" data-dismiss="modal">&times;</button>
-        <h4 class="modal-title">
-          Adding a widget to hub: {{ hub.name }}
-        </h4>
-      </div>
-      <div class="modal-body">
-        <select id="widget" class="c-select" name="widget">
-            {% for widget in widgets %}
-            <option value="{{ widget.name }}">{{ widget.label }}</option>
-            {% endfor %}
-        </select>
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-secondary" data-dismiss="modal">
-          Close
-        </button>
-        <button type="submit" class="btn btn-primary" id="submit_btn">
-          Add
-        </button>
-      </div>
-    </form>
-  </div>
-</div>
diff --git a/hubs/templates/widget_add.html b/hubs/templates/widget_add.html
deleted file mode 100644
index d3cf376..0000000
--- a/hubs/templates/widget_add.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<div class="modal-dialog widget-add">
-  <div class="modal-content">
-    <form method="post" action="{{ url_for('widget_add', hub=hub.name, widget=widget.name) }}">
-      <input type="hidden" name="position" value="{{ position }}" />
-      <!-- Modal content-->
-      <div class="modal-header">
-        <button type="button" class="close" data-dismiss="modal">&times;</button>
-        <h4 class="modal-title">
-            Adding widget "{{ widget.name }}" to hub {{ hub.name }}
-        </h4>
-      </div> <!-- /modal-header -->
-      <div class="modal-body">
-      {% for param in widget.get_parameters() %}
-        <fieldset class="form-group ">
-          <strong>{{ param.label | capitalize }}</strong>
-          <input id="{{ param.name }}" class="form-control" type="text"
-              value="{{ param.validator.to_string(param.default) }}"
-              name="{{ param.name }}" />
-          {% if param.help %}
-          <small class="text-muted">{{ param.help }}</small>
-          {% endif %}
-        </fieldset>
-      {% else %}
-        <p>Nothing to configure</p>
-      {% endfor %}
-      {% if hub.config.visibility == "preview" %}
-        <fieldset class="form-group ">
-          <strong>Visibility</strong>
-          <select name="visibility" class="form-control">
-            <option value="public">Public</option>
-            <option value="restricted">Restricted</option>
-          </select>
-          <small class="text-muted">
-            Restricted widgets will only be visible by logged-in users.
-          </small>
-        </fieldset>
-      {% endif %}
-      </div> <!-- /modal-body -->
-      <div class="modal-footer">
-        <button type="button" class="btn btn-secondary" data-dismiss="modal">
-          Cancel
-        </button>
-        <button type="submit" class="btn btn-primary">
-            Add
-        </button>
-      </div> <!-- /modal-footer -->
-    </form>
-  </div>
-</div>
diff --git a/hubs/templates/widget_edit.html b/hubs/templates/widget_edit.html
deleted file mode 100644
index fc4f8ce..0000000
--- a/hubs/templates/widget_edit.html
+++ /dev/null
@@ -1,59 +0,0 @@
-<div class="modal-dialog widget-edit">
-  <div class="modal-content">
-    <form method="post" action="{{ url_for('widget_edit', hub=hub.name, idx=widget_instance.idx) }}">
-    <!-- Modal content-->
-      <div class="modal-header">
-        <button type="button" class="close" data-dismiss="modal">&times;</button>
-        <h4 class="modal-title">
-            Configure {{ widget_instance.plugin }}
-        </h4>
-      </div> <!-- /modal-header -->
-      <div class="modal-body">
-      {% for param in widget_instance.module.get_parameters() %}
-        <fieldset class="form-group ">
-          <strong>{{ param.label | capitalize }}</strong>
-          <input id="{{ param.name }}" class="form-control" type="text"
-              value="{{ param.validator.to_string(widget_instance.config.get(param.name, param.default)) }}"
-              name="{{ param.name }}" />
-          {% if param.help %}
-          <small class="text-muted">{{ param.help }}</small>
-          {% endif %}
-        </fieldset>
-      {% else %}
-        <p>Nothing to configure</p>
-      {% endfor %}
-      {% if hub.config.visibility == "preview" %}
-        <fieldset class="form-group ">
-          <strong>Visibility</strong>
-          <select name="visibility" class="form-control">
-            <option value="public"
-                {% if widget_instance.visibility == "public" %}selected{% endif %}
-                >Public</option>
-            <option value="restricted"
-                {% if widget_instance.visibility == "restricted" %}selected{% endif %}
-                >Restricted</option>
-          </select>
-          <small class="text-muted">
-            Restricted widgets will only be visible by logged-in users.
-          </small>
-        </fieldset>
-      {% endif %}
-      </div> <!-- /modal-body -->
-      <div class="modal-footer">
-        <button type="button" class="btn btn-secondary" data-dismiss="modal">
-          Close
-        </button>
-        <button type="submit" class="btn btn-primary">
-          Save
-        </button>
-      </div> <!-- /modal-footer -->
-    </form>
-    <form method="POST" action="{{ url_for(
-        'widget_edit_delete', hub=hub.name, idx=widget_instance.idx) }}"
-        class="modal-footer p-abs" >
-        <button type="submit" class="btn btn-danger" id="delete_widget">
-          Remove this widget
-        </button>
-    </form>
-  </div>
-</div>
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index b562662..698f34d 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -202,45 +202,6 @@ class Widget(object):
                     self.name, url_rule.lstrip("/"))
                 app.add_url_rule(rule, view_func=view_func)
 
-    def get_add_url(self, hub, position):
-        """Returns the URL to the configuration panel to add this widget.
-
-        By default, it returns the URL to the common widget configuration panel
-        that will simply display the widget's parameters in a form.  Widgets
-        override this method to implement a more complex configuration view.
-
-        If a more complex configuration view is implemented, the resulting HTML
-        code will be wrapped in a ``<div class="modal-dialog">`` tag.
-
-        Args:
-            hub (hubs.models.Hub): The hub instance in the database.
-            position (str): the position where the widget should be added. It
-                must be either ``left`` or ``right``, and must be in the
-                supported positions for this widget (see :py:attr:`position`).
-
-        Returns:
-            The URL to add this widget, as a string.
-        """
-        return "%s?position=%s" % (
-            flask.url_for('widget_add', hub=hub.name, widget=self.name),
-            position)
-
-    def get_edit_url(self, hub, widget_instance):
-        """Returns the URL to the configuration panel to edit this widget.
-
-        This method works like :py:meth:`get_add_url`.
-
-        Args:
-            hub (hubs.models.Hub): The hub instance in the database.
-            widget_instance (hubs.models.Widget): The widget instance in the
-                database that must be configured.
-
-        Returns:
-            The URL to edit this widget, as a string.
-        """
-        return flask.url_for(
-            'widget_edit', hub=hub.name, idx=widget_instance.idx)
-
     def get_cached_functions(self):
         """
         Returns:
diff --git a/hubs/widgets/halp/__init__.py b/hubs/widgets/halp/__init__.py
index 47b47fb..741b1e6 100644
--- a/hubs/widgets/halp/__init__.py
+++ b/hubs/widgets/halp/__init__.py
@@ -6,7 +6,7 @@ import flask
 
 from hubs.widgets.base import Widget
 from hubs.widgets import validators
-from .views import add_view, hubs_suggest_view
+from .views import hubs_suggest_view
 
 
 class Halp(Widget):
@@ -43,20 +43,8 @@ class Halp(Widget):
         env.filters['humanize'] = lambda d: arrow.get(d).humanize()
         return env
 
-    def get_add_url(self, hub, position):
-        return "%s?position=%s" % (
-            flask.url_for('halp_config_add', hub=hub.name), position)
-
-    def get_edit_url(self, hub, widget_instance):
-        return flask.url_for(
-            'halp_config', hub=hub.name, idx=widget_instance.idx)
-
     def register_routes(self, app):
         super(Halp, self).register_routes(app)
-        # Add the widget add view
-        rule = "/<hub>/w/%s/add" % self.name
-        endpoint = "%s_config_add" % self.name
-        app.add_url_rule(rule, endpoint=endpoint, view_func=add_view)
         # Add the hubs suggestion view
         rule = "/w/%s/hubs" % self.name
         endpoint = "%s_config_hubs" % self.name
diff --git a/hubs/widgets/halp/templates/halp_config.html b/hubs/widgets/halp/templates/halp_config.html
deleted file mode 100644
index 5587c3d..0000000
--- a/hubs/widgets/halp/templates/halp_config.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<div id="widget-halp-config">
-  <div class="modal-dialog">
-    <div class="modal-content">
-      <div class="modal-body">
-        <img src="{{ url_for("static", filename="img/spinner.gif") }}"
-             class="mx-auto" alt="loading..." />
-      </div>
-    </div>
-  </div>
-</div>
-
-<script src="{{url_for('static', filename='js/build/Halp.js')}}"></script>
-<script>
-(function() {
-    const ConfigPanel = React.createElement(Halp.Config, {
-        mode: {{ mode|tojson }},
-        initialState: {{ initial|tojson }},
-        urls: {
-            post: {{ url|tojson }},
-            hubs: '{{ url_for("halp_config_hubs") }}',
-            {% if mode != "add" %}
-            remove: '{{ url_for("widget_edit_delete", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
-            {% endif %}
-            spinnerCircle: '{{ url_for("static", filename="img/spinner-circle.gif") }}'
-        }
-    });
-    ReactDOM.render(ConfigPanel, document.getElementById('widget-halp-config'));
-})();
-</script>
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index a00ad6e..dfd1e30 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -140,27 +140,6 @@ class RequestersView(WidgetView):
         return {"results": results}
 
 
-class ConfigView(WidgetView):
-    """
-    The custom configuration panel.
-    """
-
-    name = "config"
-    url_rules = ["config"]
-    template_name = "halp_config.html"
-    permission = "config"
-
-    def get_context(self, instance, *args, **kwargs):
-        post_url = flask.url_for(
-            'widget_edit', hub=instance.hub.name, idx=instance.idx)
-        initial = instance.config.copy()
-        return dict(
-            mode="edit",
-            url=post_url,
-            initial=initial,
-            )
-
-
 def hubs_suggest_view():
     """
     Returns suggestions for the "hubs" list in the configuration.
@@ -172,36 +151,3 @@ def hubs_suggest_view():
             "%s%%" % flask.request.args.get("q")))
     results = results.order_by(Hub.name)[:MAX_SUGGESTS]
     return flask.jsonify({"results": [h.name for h in results]})
-
-
-@require_hub_access("config", url_param="hub")
-def add_view(hub):
-    """The custom configuration panel when adding the widget.
-
-    This is not a subclass of WidgetView because it is not specific
-    to a widget instance, therefore it does not have the same URL
-    parameters.
-    """
-    hub = get_hub(hub)
-    widget = registry["halp"]
-    tpl_env = widget.get_template_environment()
-    template = tpl_env.get_template("halp_config.html")
-    post_url = "%s?position=%s" % (
-        flask.url_for('widget_add', hub=hub.name, widget="halp"),
-        flask.request.args.get("position"))
-    initial = dict(
-        (param.name, param.default)
-        for param in widget.get_parameters()
-        )
-    initial["hubs"] = [hub.name]
-    context = dict(mode="add", url=post_url, initial=initial)
-    # Mimic flask.templating._render(). Too bad it's not a public API.
-    if before_render_template is not None:
-        before_render_template.send(
-            flask._app_ctx_stack.top.app,
-            template=template, context=context)
-    output = template.render(**context)
-    template_rendered.send(
-        flask._app_ctx_stack.top.app,
-        template=template, context=context)
-    return output

From 52964f9665949c2219418a580b2b39d57e83fcc2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:09 +0000
Subject: [PATCH 956/1001] The widget panel wrapper is handled in React


---

diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index 76f17b0..be454bd 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -40,15 +40,10 @@ use of any Jinja2 feature, including inheritance, macros, etc.
 
 .. _Jinja2: http://jinja.pocoo.org/docs/
 
-If you want to add filters to youre widget's Jinja2 environment, you can do so
+If you want to add filters to your widget's Jinja2 environment, you can do so
 by overriding the widget's
 :py:meth:`~hubs.widgets.base.Widget.get_template_environment` method.
 
-Hubs provides the ``panel.html`` master template for widgets that want their
-output to be wrapped in the common panel chrome, just use the ``extends`` tag
-to take advantage of it.  You can also set a ``title`` variable in your root
-view context, and it will be used for the panel title.
-
 Refer to the API documentation to learn more on how to write a widget view.
 
 A widget can also have any number of cached functions.  A cached function is a
diff --git a/hubs/widgets/about/__init__.py b/hubs/widgets/about/__init__.py
index 0c01124..0da5c7b 100644
--- a/hubs/widgets/about/__init__.py
+++ b/hubs/widgets/about/__init__.py
@@ -23,6 +23,4 @@ class BaseView(RootWidgetView):
     def get_context(self, instance, *args, **kwargs):
         return dict(
             text=instance.config["text"],
-            title="<span class='glyphicon glyphicon-info-sign' "
-                  "aria-hidden='true'></span> About",
             )
diff --git a/hubs/widgets/about/templates/root.html b/hubs/widgets/about/templates/root.html
index eafc55a..9089da2 100644
--- a/hubs/widgets/about/templates/root.html
+++ b/hubs/widgets/about/templates/root.html
@@ -1,5 +1 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<p>{{text}}</p>
-{% endblock %}
+<p class="mb-0">{{text}}</p>
diff --git a/hubs/widgets/badges/__init__.py b/hubs/widgets/badges/__init__.py
index f3e8f78..505d2b3 100644
--- a/hubs/widgets/badges/__init__.py
+++ b/hubs/widgets/badges/__init__.py
@@ -25,7 +25,7 @@ class Badges(Widget):
 class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
-        context = {"title": self.widget.label}
+        context = {}
         get_badges = GetBadges(instance)
         context.update(get_badges())
         return context
diff --git a/hubs/widgets/badges/templates/root.html b/hubs/widgets/badges/templates/root.html
index c7201d2..8f5056f 100644
--- a/hubs/widgets/badges/templates/root.html
+++ b/hubs/widgets/badges/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <div class="flex-container">
 {% for badge in assertions %}
   <a width="60px" href="https://badges.fedoraproject.org/badge/{{badge['id']}}">
@@ -8,4 +5,3 @@
   </a>
 {% endfor %}
 </div>
-{% endblock %}
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 698f34d..2dad1a1 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -60,6 +60,7 @@ class Widget(object):
             URL-compatible characters.
         label (str): A humanized name for the widget, which will be shown in
             the UI.
+        display_css (str): A CSS class to use when displaying the widget.
         position (str): The position of the widget in the rendered page. It
             should be one of the following values: ``left``, ``right``, or
             ``both``.
@@ -71,14 +72,20 @@ class Widget(object):
         cached_functions_module (list): The Python path to the module where the
             cached functions must be looked for.  By default, they are looked
             for in the same module.
+        hidden_if_empty (bool): Set to True if the widget box should be
+            entirely hidden from the UI when no data is produced. As a
+            consequence, there will also be no progress spinner when the widget
+            is loading.
     """
 
     name = None
     label = None
+    display_css = None
     position = None
     parameters = []
     views_module = None
     cached_functions_module = None
+    hidden_if_empty = False
 
     def __init__(self):
         if self.name is None:
diff --git a/hubs/widgets/bugzilla/__init__.py b/hubs/widgets/bugzilla/__init__.py
index 363f7b2..a0643cc 100644
--- a/hubs/widgets/bugzilla/__init__.py
+++ b/hubs/widgets/bugzilla/__init__.py
@@ -39,7 +39,6 @@ class BaseView(RootWidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
         return dict(
-            title=self.widget.label,
             username=instance.config["username"],
             issues=get_issues()
             )
diff --git a/hubs/widgets/bugzilla/templates/root.html b/hubs/widgets/bugzilla/templates/root.html
index 2ee01e7..d88d6bd 100644
--- a/hubs/widgets/bugzilla/templates/root.html
+++ b/hubs/widgets/bugzilla/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <ul class="list-unstyled mb-0">
   {% for item in issues %}
     <li class="media py-2">
@@ -18,4 +15,3 @@
     </li>
   {% endfor %}
 </ul>
-{% endblock %}
diff --git a/hubs/widgets/contact/__init__.py b/hubs/widgets/contact/__init__.py
index 288fc92..6992015 100644
--- a/hubs/widgets/contact/__init__.py
+++ b/hubs/widgets/contact/__init__.py
@@ -14,6 +14,7 @@ class Contact(Widget):
 
     name = "contact"
     position = "both"
+    display_title = None
 
 
 class BaseView(RootWidgetView):
diff --git a/hubs/widgets/contact/templates/root.html b/hubs/widgets/contact/templates/root.html
index d4844e9..7c3cccf 100644
--- a/hubs/widgets/contact/templates/root.html
+++ b/hubs/widgets/contact/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <div class="contactinfo-container">
   {% if usergroup %}
     <ul style="list-style: none; padding-left: 5px">
@@ -71,4 +68,3 @@
     </ul>
   {% endif %}
 </div>
-{% endblock %}
diff --git a/hubs/widgets/dummy/__init__.py b/hubs/widgets/dummy/__init__.py
index d6733b7..c5e4f1d 100644
--- a/hubs/widgets/dummy/__init__.py
+++ b/hubs/widgets/dummy/__init__.py
@@ -22,6 +22,5 @@ class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
         return dict(
-            title="This is a dummy widget",
             text=instance.config["text"],
             )
diff --git a/hubs/widgets/dummy/templates/root.html b/hubs/widgets/dummy/templates/root.html
index f2b2486..8d15644 100644
--- a/hubs/widgets/dummy/templates/root.html
+++ b/hubs/widgets/dummy/templates/root.html
@@ -1,5 +1 @@
-{% extends "panel.html" %}
-
-{% block content %}
 {{text}}
-{% endblock %}
diff --git a/hubs/widgets/fedmsgstats/templates/root.html b/hubs/widgets/fedmsgstats/templates/root.html
index 6c6efe1..73664d0 100644
--- a/hubs/widgets/fedmsgstats/templates/root.html
+++ b/hubs/widgets/fedmsgstats/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <div class="stats-container row">
   <div class="col-sm-7 col-md-12 col-lg-7">
   <table class="stats-table">
@@ -24,4 +21,3 @@
   {% endif %}
   </div>
 </div>
-{% endblock %}
diff --git a/hubs/widgets/github_pr/__init__.py b/hubs/widgets/github_pr/__init__.py
index f52c149..a8b350a 100644
--- a/hubs/widgets/github_pr/__init__.py
+++ b/hubs/widgets/github_pr/__init__.py
@@ -43,7 +43,6 @@ class BaseView(RootWidgetView):
         context = dict(
             organization=org,
             display_number=instance.config["display_number"],
-            title=self.widget.label,
         )
         context.update(get_prs())
         return context
diff --git a/hubs/widgets/github_pr/templates/root.html b/hubs/widgets/github_pr/templates/root.html
index ff31d64..2d46c56 100644
--- a/hubs/widgets/github_pr/templates/root.html
+++ b/hubs/widgets/github_pr/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <a class="btn btn-success" target="_blank"
     href="https://github.com/{{ organization }}" >
   Organization Github Page
@@ -47,4 +44,3 @@
   </li>
 {% endif %}
 </ul>
-{% endblock %}
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index 0575545..fa0c996 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -43,7 +43,6 @@ class BaseView(RootWidgetView):
             org=instance.config["org"],
             repo=instance.config["repo"],
             display_number=instance.config["display_number"],
-            title=self.widget.label,
             all_issues=get_issues(),
         )
 
diff --git a/hubs/widgets/githubissues/templates/root.html b/hubs/widgets/githubissues/templates/root.html
index 8f0cb1d..4200aca 100644
--- a/hubs/widgets/githubissues/templates/root.html
+++ b/hubs/widgets/githubissues/templates/root.html
@@ -1,9 +1,5 @@
-{% extends "panel.html" %}
-
-{% block content %}
-
 <ul class="list-unstyled">
-    
+
 {% for i in range(display_number) %}
 <li class="media">
   <div class="align-self-center mr-3">
@@ -33,9 +29,7 @@
          </a>
       </div>
     </div>
-    
-             
-    </div>
+  </div>
 </li>
 {% endfor %}
 
@@ -44,4 +38,3 @@
 <div class="row">
   <a href="https://github.com/{{ org }}/{{ repo }}/issues" target="_blank"><center>All Issues</center></a>
 </div>
-{% endblock %}
diff --git a/hubs/widgets/library/__init__.py b/hubs/widgets/library/__init__.py
index 3eddd2d..e8315d3 100644
--- a/hubs/widgets/library/__init__.py
+++ b/hubs/widgets/library/__init__.py
@@ -29,7 +29,4 @@ class BaseView(RootWidgetView):
             for u in instance.config.get('urls', '').split(',')
             if u.strip()
         ]
-        return dict(
-            title=self.widget.label,
-            urls=urls,
-            )
+        return dict(urls=urls)
diff --git a/hubs/widgets/library/templates/root.html b/hubs/widgets/library/templates/root.html
index b32cfcb..4cbff48 100644
--- a/hubs/widgets/library/templates/root.html
+++ b/hubs/widgets/library/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <div class="rules-container">
   <div class="row">
     <ul>
@@ -12,4 +9,3 @@
     </ul>
   </div>
 </div>
-{% endblock %}
diff --git a/hubs/widgets/linechart/__init__.py b/hubs/widgets/linechart/__init__.py
index 39b5be8..9fdccb2 100644
--- a/hubs/widgets/linechart/__init__.py
+++ b/hubs/widgets/linechart/__init__.py
@@ -38,7 +38,4 @@ class BaseView(RootWidgetView):
                "&user={username}&split_on=categories")
         url = url + "&" + categories
         url = url.format(username=username)
-        return dict(
-            title=self.widget.label,
-            url=url,
-            )
+        return dict(url=url)
diff --git a/hubs/widgets/linechart/templates/root.html b/hubs/widgets/linechart/templates/root.html
index 573d452..5b4e756 100644
--- a/hubs/widgets/linechart/templates/root.html
+++ b/hubs/widgets/linechart/templates/root.html
@@ -1,7 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <div class="flex-container">
     <img src="{{url}}" />
 </div>
-{% endblock %}
diff --git a/hubs/widgets/meetings/__init__.py b/hubs/widgets/meetings/__init__.py
index 0633d40..9d8fc2e 100644
--- a/hubs/widgets/meetings/__init__.py
+++ b/hubs/widgets/meetings/__init__.py
@@ -49,7 +49,6 @@ class BaseView(RootWidgetView):
             if meeting['start_dt'] > now
             }
         return dict(
-            title=self.widget.label,
             calendar=instance.config["calendar"],
             meetings=meetings,
             )
diff --git a/hubs/widgets/meetings/templates/root.html b/hubs/widgets/meetings/templates/root.html
index 3b49aba..7028ac2 100644
--- a/hubs/widgets/meetings/templates/root.html
+++ b/hubs/widgets/meetings/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 {% for title, next in meetings.items() %}
 <div class="meeting">
   <div class="row no-gutters">
@@ -48,16 +45,9 @@
     No coming meetings in {{ calendar }}.
   </div>
 </div>
+<p class="text-center mt-3">
+  <button class="btn btn-secondary">
+    <strong>Request A New Meeting</strong>
+  </button>
+</p>
 {% endfor %}
-{% endblock %}
-
-
-{% block footer %}
-<div class="panel-footer">
-  <div class="text-center">
-    <button class="btn btn-secondary">
-      <strong>Request A New Meeting</strong>
-    </button>
-  </div>
-</div>
-{% endblock %}
diff --git a/hubs/widgets/memberships/__init__.py b/hubs/widgets/memberships/__init__.py
index ff57c74..78433b8 100644
--- a/hubs/widgets/memberships/__init__.py
+++ b/hubs/widgets/memberships/__init__.py
@@ -36,7 +36,6 @@ class BaseView(RootWidgetView):
         oldest_members = sorted(
             members, key=lambda m: m.get('created_on'))[:ELLIPSIS_LIMIT]
         return dict(
-            title=self.widget.label,
             memberships=list(members),
             oldest_members=list(oldest_members),
             )
diff --git a/hubs/widgets/memberships/templates/root.html b/hubs/widgets/memberships/templates/root.html
index 621ea9f..d195b0c 100644
--- a/hubs/widgets/memberships/templates/root.html
+++ b/hubs/widgets/memberships/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <div class="card-block">
   {% if memberships|length > oldest_members|length %}
   {% for member in oldest_members %}
@@ -77,4 +74,3 @@
    padding: 10px;
  }
 </style>
-{% endblock %}
diff --git a/hubs/widgets/pagure_pr/__init__.py b/hubs/widgets/pagure_pr/__init__.py
index 9346e54..4dc5562 100644
--- a/hubs/widgets/pagure_pr/__init__.py
+++ b/hubs/widgets/pagure_pr/__init__.py
@@ -30,7 +30,6 @@ class BaseView(RootWidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_prs = GetPRs(instance)
         context = dict(
-            title=self.widget.label,
             repo=instance.config["repo"],
             )
         context.update(get_prs())
diff --git a/hubs/widgets/pagure_pr/templates/root.html b/hubs/widgets/pagure_pr/templates/root.html
index 2207ce3..bf8ae43 100644
--- a/hubs/widgets/pagure_pr/templates/root.html
+++ b/hubs/widgets/pagure_pr/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <ul class="list-unstyled">
   {% for pr in all_pr[:10] %}
     <li class="media py-2">
@@ -51,4 +48,3 @@
     href="https://pagure.io/{{ repo }}/pull-requests">
   All Pull-Requests
 </a>
-{% endblock %}
diff --git a/hubs/widgets/pagureissues/__init__.py b/hubs/widgets/pagureissues/__init__.py
index 3ba90d9..4cc033f 100644
--- a/hubs/widgets/pagureissues/__init__.py
+++ b/hubs/widgets/pagureissues/__init__.py
@@ -30,7 +30,6 @@ class BaseView(RootWidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_issues = GetIssues(instance)
         context = dict(
-            title=self.widget.label,
             repo=instance.config["repo"],
             )
         context.update(get_issues())
diff --git a/hubs/widgets/pagureissues/templates/root.html b/hubs/widgets/pagureissues/templates/root.html
index 5e4fbd5..53823b7 100644
--- a/hubs/widgets/pagureissues/templates/root.html
+++ b/hubs/widgets/pagureissues/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <a class="btn btn-success" target="_blank"
     href="https://pagure.io/{{ repo }}/issues">
   All Issues
@@ -50,4 +47,3 @@
   </li>
   {% endif %}
 </ul>
-{% endblock %}
diff --git a/hubs/widgets/rules/templates/root.html b/hubs/widgets/rules/templates/root.html
index 0803f95..e3abc68 100644
--- a/hubs/widgets/rules/templates/root.html
+++ b/hubs/widgets/rules/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <div class="rules-container">
   {% if link %}
   <h6>community rules</h6>
@@ -88,4 +85,3 @@
    border-bottom: 0;
  }
 </style>
-{% endblock %}
diff --git a/hubs/widgets/stats/templates/root.html b/hubs/widgets/stats/templates/root.html
index 5dc307e..22aa78c 100644
--- a/hubs/widgets/stats/templates/root.html
+++ b/hubs/widgets/stats/templates/root.html
@@ -1,6 +1,3 @@
-{% extends "panel.html" %}
-
-{% block content %}
 <div class="stats-container row">
 <div class="col-md-7">
   <table class="stats-table">
@@ -75,4 +72,3 @@
   </ul>
 </div>
 </div>
-{% endblock %}
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index f452d24..13c6af3 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -10,6 +10,7 @@ class Sticky(Widget):
     name = "sticky"
     label = "Sticky Note"
     position = "both"
+    display_css = "card-info"
     parameters = [
         dict(
             name="text",
@@ -26,6 +27,4 @@ class BaseView(RootWidgetView):
         # TODO -- render with markdown
         return dict(
             text=instance.config["text"],
-            title=self.widget.label,
-            panel_css_class="card-info",
             )
diff --git a/hubs/widgets/sticky/templates/root.html b/hubs/widgets/sticky/templates/root.html
index f2b2486..8d15644 100644
--- a/hubs/widgets/sticky/templates/root.html
+++ b/hubs/widgets/sticky/templates/root.html
@@ -1,5 +1 @@
-{% extends "panel.html" %}
-
-{% block content %}
 {{text}}
-{% endblock %}
diff --git a/hubs/widgets/subscriptions/__init__.py b/hubs/widgets/subscriptions/__init__.py
index c3b9cb8..01a1f57 100644
--- a/hubs/widgets/subscriptions/__init__.py
+++ b/hubs/widgets/subscriptions/__init__.py
@@ -19,6 +19,8 @@ class Subscriptions(Widget):
 
     name = "subscriptions"
     position = "right"
+    display_title = "Hubs"
+    hidden_if_empty = True
     parameters = [
         dict(
             name="username",
@@ -32,7 +34,7 @@ class Subscriptions(Widget):
 class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
-        context = dict(title="Hubs")
+        context = {}
         get_subs = GetSubs(instance)
         context.update(get_subs())
         return context
diff --git a/hubs/widgets/subscriptions/templates/root.html b/hubs/widgets/subscriptions/templates/root.html
index 83033dd..248d86f 100644
--- a/hubs/widgets/subscriptions/templates/root.html
+++ b/hubs/widgets/subscriptions/templates/root.html
@@ -1,7 +1,5 @@
-{% if associations or edit_mode %}
-{% extends "panel.html" %}
+{% if associations %}
 
-{% block content %}
     {% if memberships %}
         <p><strong>Belongs to: </strong> {{memberships_text}}</p>
     {% endif %}
@@ -13,5 +11,5 @@
         {{subscription}}</a>
         {% endfor %}</p>
     {% endif %}
-{% endblock %}
+
 {% endif %}
diff --git a/hubs/widgets/templates/panel.html b/hubs/widgets/templates/panel.html
deleted file mode 100644
index 9374f19..0000000
--- a/hubs/widgets/templates/panel.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<div class="card {{ panel_css_class }} widget-{{ widget.name }}"
-     {% if disable_autoreload %}data-disable-autoreload="true"{% endif %}
-    >
-  <div class="widget-buttons">
-    <!-- the AGPLv3 wrapper puts the source url in all responses -->
-    <a href="{{ url_for('widget_source', name=widget.name) }}"><span><i class="fa fa-eye" aria-hidden="true"></i></span></a>
-    <a href="{{ url_for('%s_root' % widget.name, hub=widget_instance.hub.name, idx=widget_instance.idx) }}">
-        <span><i class="fa fa-external-link" aria-hidden="true"></i></span>
-    </a>
-    {% if edit_mode and widget_instance.hub.allows(g.user, "config") %}
-    <a data-target="#edit_modal" data-toggle="modal" type="button"
-        class="edit_widget" data-url="{{ widget_instance.edit_url }}">
-      <span><i class="fa fa-cog" aria-hidden="true"></i></span>
-    </a>
-    {% endif %}
-  </div>
-  {% if title %}
-  <div class="card-header">
-    {{title}}
-  </div> <!-- end card-header -->
-  {% endif %}
-  <div class="card-block">
-    {% block content %}{% endblock %}
-  </div> <!-- end card-block -->
-  {% block footer %}{% endblock %}
-</div> <!-- end card -->
diff --git a/hubs/widgets/workflow/templates/updates2stable.html b/hubs/widgets/workflow/templates/updates2stable.html
index e44e040..5ba04b0 100644
--- a/hubs/widgets/workflow/templates/updates2stable.html
+++ b/hubs/widgets/workflow/templates/updates2stable.html
@@ -1,27 +1,23 @@
-{% if updates or edit_mode %}
-{% extends "panel.html" %}
-
-{% block content %}
-{% if session['nickname'] == username %}
-<a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
-<hr/>
-{% endif %}
-<ul class="list-unstyled mb-0">
-{% for update in updates %}
-    <li class="media">
-        <div class="align-self-center mr-3">
-            <a href="{{update['link']}}" target="_blank">
-                <img class="media-object square-32" src="{{update['icon']}}"/>
-            </a>
-        </div>
-        <div class="media-body">
-            <h5 class="mt-0">
-                {{update['title']}} (karma {{update['karma']}})
-            </h5>
-            can be pushed to stable
-        </div>
-    </li>
-{% endfor %}
-</ul>
-{% endblock %}
+{% if updates %}
+    {% if session['nickname'] == username %}
+    <a class="btn btn-success" target="_blank" href="https://admin.fedoraproject.org/updates/mine">Manage updates</a>
+    <hr/>
+    {% endif %}
+    <ul class="list-unstyled mb-0">
+    {% for update in updates %}
+        <li class="media">
+            <div class="align-self-center mr-3">
+                <a href="{{update['link']}}" target="_blank">
+                    <img class="media-object square-32" src="{{update['icon']}}"/>
+                </a>
+            </div>
+            <div class="media-body">
+                <h5 class="mt-0">
+                    {{update['title']}} (karma {{update['karma']}})
+                </h5>
+                can be pushed to stable
+            </div>
+        </li>
+    {% endfor %}
+    </ul>
 {% endif %}
diff --git a/hubs/widgets/workflow/updates2stable.py b/hubs/widgets/workflow/updates2stable.py
index 25cc62d..9845cc4 100644
--- a/hubs/widgets/workflow/updates2stable.py
+++ b/hubs/widgets/workflow/updates2stable.py
@@ -18,6 +18,7 @@ class Updates2Stable(Widget):
     name = "workflow.updates2stable"
     label = 'Updates Ready for Stable'
     position = "right"
+    hidden_if_empty = True
     parameters = [
         dict(
             name="username",
@@ -35,7 +36,6 @@ class BaseView(RootWidgetView):
     def get_context(self, instance, *args, **kwargs):
         get_pending = GetPending(instance)
         context = dict(
-            title=self.widget.label,
             username=instance.config["username"],
             )
         context.update(get_pending())

From 4468ec9f0698ff6990e4d6922a6f5a0f0f73063b Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:09 +0000
Subject: [PATCH 957/1001] Hubs and widgets expose 'props' to the JS UI


---

diff --git a/hubs/models.py b/hubs/models.py
index 55530f9..3cc5850 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -299,6 +299,26 @@ class Hub(ObjectAuthzMixin, BASE):
             action = "{}.view".format(self.config.visibility)
         return "hub.{}".format(action)
 
+    def get_props(self):
+        """Get the hub properties for the Javascrip UI"""
+        roles = ["owner", "member"]
+        result = {
+            "name": self.name,
+            "config": self.config.__json__(),
+            "users": {role: [] for role in roles},
+            "mtime": self.last_refreshed,
+            "user_hub": self.user_hub,
+        }
+        for assoc in sorted(self.associations, key=lambda a: a.user.username):
+            if assoc.role not in roles:
+                continue
+            user = {
+                "username": assoc.user.username,
+                "fullname": assoc.user.fullname,
+            }
+            result["users"][assoc.role].append(user)
+        return result
+
     def __json__(self):
         return {
             'name': self.name,
@@ -458,6 +478,8 @@ class Widget(ObjectAuthzMixin, BASE):
     def module(self):
         return hubs.widgets.registry[self.plugin]
 
+    def get_props(self, with_secret_config=False):
+        return self.module.get_props(self, with_secret_config)
 
     @property
     def enabled(self):
diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index 832c2f8..cb834d1 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -4,7 +4,7 @@ import six
 from mock import Mock
 
 from hubs.app import app
-from hubs.tests import APPTest
+from hubs.tests import APPTest, widget_instance
 from hubs.widgets.base import Widget
 from hubs.widgets.caching import CachedFunction
 from hubs.widgets.view import WidgetView
@@ -140,3 +140,28 @@ class WidgetTest(APPTest):
         rules = list(app.url_map.iter_rules(endpoint="testing_test2"))
         self.assertEqual(len(rules), 1)
         self.assertEqual(rules[0].rule, "/<hub>/w/testing/<int:idx>/test-2")
+
+    def test_get_props(self):
+        widget = widget_instance('ralph', "about")
+        with app.test_request_context('/'):
+            props = widget.get_props()
+        self.assertDictEqual(props, {
+            'config': {'text': 'Testing.'},
+            'contentUrl': '/ralph/w/about/{}/'.format(widget.idx),
+            'cssClass': None,
+            'hiddenIfEmpty': False,
+            'idx': widget.idx,
+            'index': 500,
+            'isReact': False,
+            'label': 'About',
+            'name': 'about',
+            'params': [
+                {'default': 'I am a Fedora user, and this is my about',
+                 'help': 'Text about a user.',
+                 'label': 'Text',
+                 'name': 'text'},
+            ],
+            'position': 'right',
+            'selfUrl': '/api/hubs/ralph/widgets/{}/'.format(widget.idx),
+            'title': 'About',
+        })
diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index 5a489d3..f160993 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -117,6 +117,43 @@ class HalpViewsTestCase(WidgetTest):
     def test_view_authz(self):
         self._test_view_authz()
 
+    def test_props(self):
+        with app.test_request_context('/'):
+            props = self.widget.get_props()
+        self.assertDictEqual(props, {
+            'component': 'halp',
+            'config': {'hubs': ['fedora-devel'], 'per_page': 3},
+            'cssClass': None,
+            'hiddenIfEmpty': False,
+            'idx': self.widget.idx,
+            'index': 9,
+            'isReact': True,
+            'label': 'Help Requests',
+            'name': 'halp',
+            'params': [
+                {'default': [],
+                 'help': 'A comma-separated list of hubs to monitor.',
+                 'label': 'Hubs',
+                 'name': 'hubs',
+                 },
+                {'default': 4,
+                 'help': 'The number of requests per page to display.',
+                 'label': 'Requests per page',
+                 'name': 'per_page',
+                 },
+            ],
+            'position': 'right',
+            'selfUrl': '/api/hubs/ralph/widgets/{}/'.format(self.widget.idx),
+            'title': 'Help Requests',
+            'urls': {
+                'allHubs': '/w/halp/hubs',
+                'data': '/ralph/w/halp/{}/data'.format(self.widget.idx),
+                'requesters': '/ralph/w/halp/{}/requesters'.format(
+                    self.widget.idx),
+                'search': '/ralph/w/halp/{}/search'.format(self.widget.idx),
+            }
+        })
+
     def test_config_hubs_suggest(self):
         response = self.app.get('/w/halp/hubs')
         self.assertEqual(response.status_code, 200)
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 2dad1a1..5523385 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -36,9 +36,12 @@ class WidgetParameter(object):
             the parameter value to a JSON-serializable value, raising an
             exception if it is invalid.
         help (str): A help text that will be shown in the UI.
+        secret (bool): If True, this parameter will not be exposed to users
+            viewing the widget, it will only be available in the widget
+            configuration.
     """
 
-    _attrs = ('name', 'label', 'default', 'validator', 'help')
+    _attrs = ('name', 'label', 'default', 'validator', 'help', 'secret')
 
     def __init__(self, **kwargs):
         for name in self._attrs:
@@ -72,6 +75,7 @@ class Widget(object):
         cached_functions_module (list): The Python path to the module where the
             cached functions must be looked for.  By default, they are looked
             for in the same module.
+        is_react (bool): Set to True if the widget is React-based.
         hidden_if_empty (bool): Set to True if the widget box should be
             entirely hidden from the UI when no data is produced. As a
             consequence, there will also be no progress spinner when the widget
@@ -85,6 +89,7 @@ class Widget(object):
     parameters = []
     views_module = None
     cached_functions_module = None
+    is_react = False
     hidden_if_empty = False
 
     def __init__(self):
@@ -220,3 +225,62 @@ class Widget(object):
                 CachedFunction, self.cached_functions_module):
             result[fn_class.__name__] = fn_class
         return result
+
+    @property
+    def display_title(self):
+        """The title of the widget box in the UI."""
+        return self.label
+
+    def get_props(self, instance, with_secret_config=False):
+        """Generate the widget's properties for the Javascript UI.
+
+        Args:
+            instance (:py:class:`~hubs.models.Widget` or None): the widget
+                instance to generate the properties for. If None, only generate
+                the generic properties for this widget class.
+            with_secret_config (bool): include widget parameter values that are
+                marked as secret.
+
+        Returns:
+            dict: A dictionary that will be serialized to JSON
+        """
+        props = dict(
+            name=self.name,
+            label=self.label,
+            title=self.display_title,
+            position=self.position,
+            hiddenIfEmpty=self.hidden_if_empty,
+            cssClass=self.display_css,
+            isReact=self.is_react,
+            params=[],
+        )
+        for param in self.get_parameters():
+            param_data = dict(
+                name=param.name,
+                label=param.label,
+                default=param.default,
+                help=param.help,
+                )
+            props["params"].append(param_data)
+        if instance is not None:
+            props.update({
+                "idx": instance.idx,
+                "position": "left" if instance.left else "right",
+                "index": instance.index,
+                "selfUrl": flask.url_for(
+                    "api_hub_widget", hub=instance.hub.name, idx=instance.idx),
+                "config": {},
+            })
+            for param in self.get_parameters():
+                if param.secret and not with_secret_config:
+                    continue
+                value = param.validator(instance.config[param.name])
+                props["config"][param.name] = value
+            if self.is_react:
+                props["component"] = self.name
+            else:
+                props["contentUrl"] = flask.url_for(
+                    "%s_root" % self.name,
+                    hub=instance.hub.name,
+                    idx=instance.idx)
+        return props
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index f37ec2e..a9a265d 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -3,6 +3,8 @@ from __future__ import unicode_literals, absolute_import
 
 import logging
 
+import flask
+
 from hubs.feed import format_msgs
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
@@ -28,6 +30,17 @@ class Feed(Widget):
             "help": "Max number of feed messages to display.",
         }]
     cached_functions_module = ".functions"
+    is_react = True
+
+    def get_props(self, instance, *args, **kwargs):
+        props = super(Feed, self).get_props(instance, *args, **kwargs)
+        if instance is not None:
+            hub_name = instance.hub.name
+            props.update(dict(
+                url=flask.url_for(
+                    "feed_existing", hub=hub_name, idx=instance.idx),
+                ))
+        return props
 
 
 class BaseView(RootWidgetView):
diff --git a/hubs/widgets/halp/__init__.py b/hubs/widgets/halp/__init__.py
index 741b1e6..8fc82d4 100644
--- a/hubs/widgets/halp/__init__.py
+++ b/hubs/widgets/halp/__init__.py
@@ -37,6 +37,7 @@ class Halp(Widget):
         )]
     views_module = ".views"
     cached_functions_module = ".functions"
+    is_react = True
 
     def get_template_environment(self):
         env = super(Halp, self).get_template_environment()
@@ -49,3 +50,20 @@ class Halp(Widget):
         rule = "/w/%s/hubs" % self.name
         endpoint = "%s_config_hubs" % self.name
         app.add_url_rule(rule, endpoint=endpoint, view_func=hubs_suggest_view)
+
+    def get_props(self, instance, *args, **kwargs):
+        props = super(Halp, self).get_props(instance, *args, **kwargs)
+        props["urls"] = dict(
+            allHubs=flask.url_for("halp_config_hubs"),
+        )
+        if instance is not None:
+            hub_name = instance.hub.name
+            props["urls"].update(dict(
+                data=flask.url_for(
+                    "halp_data", hub=hub_name, idx=instance.idx),
+                search=flask.url_for(
+                    "halp_search", hub=hub_name, idx=instance.idx),
+                requesters=flask.url_for(
+                    "halp_requesters", hub=hub_name, idx=instance.idx),
+                ))
+        return props

From ed878ec261a738a7a4fbc86fc89f7c1eb03b4df2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:09 +0000
Subject: [PATCH 958/1001] Prepare the root view to use React only for the UI


---

diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 8dd75cd..d19cc3e 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -115,6 +115,12 @@ header span.edit {
     }
 
 
+.flash-messages {
+  /* place it on top so they cover content and can be clicked */
+  position: relative;
+  z-index: 3;
+}
+
 .nav-tabs {
   list-style: none;
 }
diff --git a/hubs/templates/errors/hub.html b/hubs/templates/errors/hub.html
index ad55d2a..d2e84c6 100644
--- a/hubs/templates/errors/hub.html
+++ b/hubs/templates/errors/hub.html
@@ -1,4 +1,4 @@
-{% extends "hubs.html" %}
+{% extends "master.html" %}
 
 {% block content %}
 
diff --git a/hubs/templates/hubs.html b/hubs/templates/hubs.html
deleted file mode 100644
index ff6ed6d..0000000
--- a/hubs/templates/hubs.html
+++ /dev/null
@@ -1,340 +0,0 @@
-{% extends "master.html" %}
-
-{% block title %}{{ hub.name }}{% endblock %}
-
-
-{% block header %}
-        
-<div class="row">
-
-  <!-- Left side of header -->
-  <div class="col-md-{{ hub.config.left_width }}">
-    {% if hub.user_hub %}
-      <img src="{{ hub.config.avatar }}" class="avatar" />
-      <h2 class="user m-b-0">{{ hub.name }}</h2>
-      <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
-      <div class="clearfix"></div>
-    {% else %}
-      <h2 class="team">{{ hub.name }}</h2>
-      <h5 class="m-t-1 m-b-1">{{ hub.config.summary }}</h5>
-    {% endif %}
-  </div>
-          
-  <!-- right side of header -->
-  <div class="col-md-{{ hub.config.right_width }} text-center align-self-end">
-    {% if hub.allows(g.user, "config") %}
-      <button class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#settings-modal">
-        <i class="fa fa-cog" aria-hidden="true"></i>
-        hub settings
-      </button>
-      {% if not edit %}
-        <a href="{{ url_for('hub_edit', name=hub.name) }}" class="btn btn-sm btn-secondary">
-          <i class="fa fa-pencil" aria-hidden="true"></i>
-          edit page layout
-        </a>
-      {% else %}
-        <button class="btn btn-sm btn-primary" href="#" id="save_edits_btn">
-          <i class="fa fa-download" aria-hidden="true"></i>
-          Save changes
-        </button>
-      {% endif %}
-    {% endif %}
-  </div>
-
-</div>
-        
-{% endblock header %}
-
-
-
-{% block content %}
-
-<div class="row">
-  <div class="col-md-{{ hub.config.left_width }}">
-    <!--
-      First, before the proper widgets.. a cobweb built-in widget.
-      https://pagure.io/fedora-hubs/issue/133
-    -->
-    {% if hub.archived or hub.last_refreshed | days_since > 31 %}
-    <ul class="media-list">
-      <li class="media">
-        <div class="media-left">
-        {% if hub.archived %}
-          <img class="media-object square-32"
-            src="{{ url_for('static', filename='img/archived.png') }}"/>
-        {% else %}
-          <img class="media-object square-32"
-            src="{{ url_for('static', filename='img/cobweb.png') }}"/>
-        {% endif %}
-        </div>
-        <div class="media-body">
-          {% if hub.archived %}
-          This hub has been archived and locked.
-          {% else %}
-          Cobweb alert!  This hub was last active {{
-            hub.last_refreshed | days_since }} days ago.
-          {% endif %}
-        </div>
-      </li>
-    </ul>
-    {% endif %}
-
-    {% if edit %}
-    <div id='add-widget-left' class='widget row'>
-      <div class="card">
-        <div class="card-block">
-          <h4>
-          <a href="{{ url_for("hub_add_widget", name=hub.name) }}?position=left" class="add_widget">
-            <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
-          </a>
-          </h4>
-        </div>
-      </div>
-    </div>
-    {% endif %}
-
-    <div id="left_widgets">
-      {% for widget in widgets["left"] %}
-      <div id="widget-{{ widget.idx }}" class="widget row"
-           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}{% if edit %}?editmode=1{% endif %}"
-           ></div>
-      {% endfor %}
-    </div>
-  </div>
-
-  <div class="col-md-{{ hub.config.right_width }}">
-    {% if edit %}
-    <div id='add-widget-right' class='widget row'>
-      <div class="card">
-        <div class="card-block">
-          <h4>
-          <a href="{{ url_for("hub_add_widget", name=hub.name) }}?position=right" class="add_widget">
-          <span><i class="fa fa-plus" aria-hidden="true"></i></span> Add a widget
-          </a>
-          </h4>
-        </div>
-      </div>
-    </div>
-    {% endif %}
-
-    <div id="right_widgets">
-      {% for widget in widgets["right"] %}
-      <div id="widget-{{ widget.idx }}" class="widget row"
-           data-url="{{ url_for('%s_root' % widget.plugin, hub=hub.name, idx=widget.idx) }}{% if edit %}?editmode=1{% endif %}"
-           ></div>
-      {% endfor %}
-    </div>
-  </div>
-
-</div>  <!-- /row -->
-
-<div id="settings-modal" class="modal fade" tabindex="-1" role="dialog">
-</div>
-
-
-<div id="edit_modal" class="modal fade" role="dialog">
-  <div class="modal-dialog" id="edit_modal_content">
-  </div>
-</div>
-
-{% endblock content %}
-
-
-
-{% block jscripts %}
-{{ super() }}
-
-{% if edit %}
-<script src="{{ url_for('static', filename='js/Sortable.min.js') }}"></script>
-<script>
-
-function make_widget_sortable() {
-  var byId = function (id) { return document.getElementById(id); }
-
-  Sortable.create(byId('left_widgets'), {
-    animation: 150,
-    draggable: '.widget',
-    handle: '.card',
-  });
-
-  Sortable.create(byId('right_widgets'), {
-    animation: 150,
-    draggable: '.widget',
-    handle: '.card',
-  });
-
-};
-
-function setup_add_btns() {
-  // Setup events for the "add widget" button.
-  $(".add_widget").click(function(e) {
-    e.preventDefault();
-    $.ajax({
-      url: $(this).attr('href'),
-      dataType: 'html',
-      success: function(html) {
-        $('#edit_modal_content').html(html);
-      },
-      error: function(html) {
-        $('#edit_modal_content').html(
-          '<div class="modal-dialog"><div class="modal-content"> \
-          <div class="modal-body"> \
-          An error occured when trying to add a new widget\
-          </div></div></div>'
-        );
-        console.log('error');
-        console.trace();
-        console.log(html);
-      },
-      complete: function() {
-        $('#edit_modal').modal();
-      }
-    });
-    return false;
-  });
-  // Setup events for the "add widget" form using delegated events because it's
-  // not in the DOM yet.
-  $("body").on("submit", "#adding_form form", function(e) {
-      var form = $(this);
-      e.preventDefault();
-      $.ajax({
-          type: "POST",
-          url: form.attr("action"),
-          dataType: "json",
-          data: form.serialize(),
-          success: function(data) {
-              if (data.status === "CONFIGURE") {
-                  $("#adding_form").load(data.url);
-              } else if (data.status === "ADDED") {
-                  // no config necessary, reload the page
-                  window.location = window.location;
-              } else {
-                $('#adding_form .modal-body').html(
-                  "An error occured when trying to add a new widget."
-                );
-                $('#adding_form .modal-footer button[type="submit"]').remove();
-                console.log('error');
-                console.trace();
-                console.log(data);
-              }
-          },
-          error: function(html) {
-            $('#adding_form .modal-body').html(
-              "An error occured when trying to add a new widget."
-            );
-            $('#adding_form .modal-footer button[type="submit"]').remove();
-            console.log('error');
-            console.trace();
-            console.log(html);
-          }
-        });
-  });
-}
-
-$('#save_edits_btn').click(function(e) {
-  e.preventDefault();
-  var _r_indexes = [];
-  var _r_widgets = [];
-  $.each($('#right_widgets .widget'), function(i, el) {
-    _r_indexes.push(i);
-    _r_widgets.push($(el).attr('id').split('widget-')[1])
-  });
-
-  var _l_indexes = [];
-  var _l_widgets = [];
-  $.each($('#left_widgets .widget'), function(i, el) {
-    _l_indexes.push(i);
-    _l_widgets.push($(el).attr('id').split('widget-')[1])
-  });
-
-  $.post(
-    '{{ url_for("hub_edit", name=hub.name) }}',
-    {'right_indexes': _r_indexes, 'right_widgets': _r_widgets,
-     'left_indexes': _l_indexes, 'left_widgets': _l_widgets,
-     'js': true},
-    function(){ window.location = '{{ url_for("hub", name=hub.name) }}' }
-  );
-});
-</script>
-{% endif %}
-
-<script type="text/javascript">
-function setup_edit_btns() {
-  $("body").on("click", ".edit_widget", function(e) {
-    e.preventDefault();
-    var url = $(this).attr('data-url');
-
-    $.ajax({
-      url: url,
-      dataType: 'html',
-      success: function(html) {
-        $('#edit_modal_content').html(html);
-        $('#edit_modal').modal();
-      },
-      error: function() {
-        $('#edit_modal_content').html(
-          '<div class="modal-dialog"><div class="modal-content"> \
-          <div class="modal-body"> \
-          Nothing to configure for this widget\
-          </div></div></div>'
-        );
-        console.log('error');
-        console.trace();
-        $('#edit_modal').modal();
-      },
-    });
-    return false;
-  });
-}
-
-function visit_counter() {
-  if (window.performance.navigation.type == 0) {
-    var username = '{{ g.auth.nickname }}'
-    var visited_hub = '{{ hub.name }}'
-    if(username != null && username != '' && username != visited_hub) {
-      url_str = '/visit/' + visited_hub;
-
-      $.ajax({
-        method: "POST",
-        url: url_str,
-        dataType: 'html',
-        success: function(html) {
-          console.log('Success: incrementing counter')
-        },
-        error: function() {
-          console.log('Error: incrementing counter');
-        },
-      });
-    }
-  }
-}
-
-function setup_settings() {
-  var settingsPanel = React.createElement(Hubs.HubConfig, {
-    urls: {
-      config: {{ url_for("hub_config", name=hub.name)|tojson }},
-      suggestUsers: {{ url_for("hub_config_suggest_users", name=hub.name)|tojson }},
-    }
-  });
-  ReactDOM.render(settingsPanel, document.getElementById("settings-modal"));
-}
-
-$(function() {
-  visit_counter()
-
-  setup_widgets();
-  setup_sse({{ sse_url | tojson }});
-  setup_edit_btns();
-  {% if hub.allows(g.user, "config") %}
-  setup_settings();
-  {% endif %}
-
-  {% if edit -%}
-  make_widget_sortable();
-  setup_add_btns();
-  {%- endif %}
-});
-
-</script>
-{% endblock %}
-{# vim: set ts=2 sw=2 et: #}
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 8b3706c..1a74f82 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -68,12 +68,15 @@
 </nav>
 
 
+{% block fullcontent %}
+
 <header>
 
+  {% block flash_messages %}
   <!-- Flash messages -->
   {%- with messages = get_flashed_messages(with_categories=true) -%}
   {%- if category, messages -%}
-    <div class="row p-t-2">
+    <div class="row pt-2 flash-messages">
       <div class="col-md-6 offset-md-3">
       {%- for category, message in messages -%}
         <div class="alert {%
@@ -91,6 +94,7 @@
     </div>
   {%- endif -%}
   {%- endwith -%}
+  {% endblock flash_messages %}
 
   <div class="row">
     <div class="offset-lg-2 col-lg-10">
@@ -154,6 +158,7 @@
     </div>
   </div>
 </div> <!-- /.container-fluid -->
+{% endblock fullcontent %}
 
 {% block jscripts %}
 <script src="{{ url_for('static', filename='js/jquery-1.10.2.min.js') }}"></script>
diff --git a/hubs/templates/react.html b/hubs/templates/react.html
new file mode 100644
index 0000000..731b5be
--- /dev/null
+++ b/hubs/templates/react.html
@@ -0,0 +1,27 @@
+{% extends "master.html" %}
+
+{% block title %}{{ page_title }}{% endblock %}
+
+{% block flash_messages %}
+<!-- Flash messages handled in React -->
+{% endblock flash_messages %}
+
+{% block fullcontent %}
+
+<div id="page"></div>
+
+{% endblock fullcontent %}
+
+
+
+{% block jscripts %}
+{{ super() }}
+
+<script>
+(function() {
+  Hubs.setupPage("page", {{ initial_state|tojson }});
+})();
+</script>
+{% endblock %}
+
+{# vim: set ts=2 sw=2 et: #}
diff --git a/hubs/tests/utils/test_views.py b/hubs/tests/utils/test_views.py
index 9c4f54f..13d9c1c 100644
--- a/hubs/tests/utils/test_views.py
+++ b/hubs/tests/utils/test_views.py
@@ -2,10 +2,10 @@ from __future__ import unicode_literals
 
 import flask
 
-import hubs.models
+from hubs.models import Hub, Widget
 from hubs.app import app
-from hubs.tests import APPTest, FakeAuthorization, auth_set, app_config
-from hubs.utils.views import get_visible_widgets, get_sse_url, move_widget
+from hubs.tests import APPTest, app_config
+from hubs.utils.views import get_sse_url, move_widget
 
 
 class ViewUtilsTest(APPTest):
@@ -19,74 +19,6 @@ class ViewUtilsTest(APPTest):
         self.app_context.__exit__(None, None, None)
         super(ViewUtilsTest, self).tearDown()
 
-    def test_removed_widget(self):
-        hub = hubs.models.Hub.get("ralph")
-        widget = hubs.models.Widget(
-            hub=hub, plugin="does-not-exist",
-            left=True, index=-1, _config="{}")
-        self.session.add(widget)
-        with auth_set(app, FakeAuthorization('ralph')):
-            widgets = get_visible_widgets(hub)
-        self.assertNotIn(
-            "does-not-exist", [w.plugin for w in widgets["left"]])
-        widget.left = False
-        self.assertNotIn(
-            "does-not-exist", [w.plugin for w in widgets["right"]])
-
-    def test_get_visible_widgets(self):
-        hub = hubs.models.Hub.get('ralph')
-        with auth_set(app, None):
-            widgets = get_visible_widgets(hub)
-        self.assertListEqual(
-            [w.plugin for w in widgets["left"]],
-            ["feed"])
-        self.assertListEqual(
-            [w.plugin for w in widgets["right"]],
-            ['contact', 'meetings', 'fedmsgstats', 'workflow.updates2stable',
-             'subscriptions', 'badges', 'pagure_pr', 'github_pr', 'bugzilla',
-             'halp', 'about']
-            )
-
-    def test_get_visible_widgets_preview(self):
-        hub = hubs.models.Hub.by_name('ralph')
-        hub.config.visibility = "preview"
-        meetings = hubs.models.Widget.query.filter_by(
-            hub=hub, plugin="meetings").first()
-        # make sure the test is valid
-        assert meetings.left is False
-        # set the widget to "restricted"
-        meetings.visibility = "restricted"
-        # Restricted widgets in preview hubs aren't displayed to
-        # anonymous users.
-        with auth_set(app, None):
-            widgets = get_visible_widgets(hub)
-        self.assertNotIn(
-            "meetings", [w.plugin for w in widgets["right"]])
-        # But they are displayed to members.
-        with auth_set(app, FakeAuthorization('ralph')):
-            widgets = get_visible_widgets(hub)
-        self.assertIn(
-            "meetings", [w.plugin for w in widgets["right"]])
-
-    def test_get_visible_widgets_private(self):
-        hub = hubs.models.Hub.by_name('ralph')
-        hub.config.visibility = "private"
-        meetings = hubs.models.Widget.query.filter_by(
-            hub=hub, plugin="meetings").first()
-        # make sure the test is valid
-        assert meetings.left is False
-        # Widgets in private hubs aren't displayed to
-        # anonymous users.
-        with auth_set(app, None):
-            widgets = get_visible_widgets(hub)
-        self.assertEqual(widgets["left"], [])
-        self.assertEqual(widgets["right"], [])
-        # But they are displayed to members.
-        with auth_set(app, FakeAuthorization('ralph')):
-            widgets = get_visible_widgets(hub)
-        self.assertNotEqual(len(widgets["left"]), 0)
-        self.assertNotEqual(len(widgets["right"]), 0)
-
     def test_sse_url(self):
         with app.test_request_context():
             self.assertEqual(get_sse_url(""), "http://localhost:8080/sse/")
@@ -131,18 +63,18 @@ class ViewUtilsTest(APPTest):
                     "http://example.com/hub/ralph")
 
     def test_move_widget(self):
-        hub = hubs.models.Hub(name="testing")
+        hub = Hub(name="testing")
         self.session.add(hub)
         widget_names = ["about", "badges", "bugzilla", "contact", "dummy"]
 
         def get_names():
             return [
                 w.plugin for w in
-                hubs.models.Widget.query.filter_by(hub=hub).order_by(hubs.models.Widget.index)
+                Widget.query.filter_by(hub=hub).order_by(Widget.index)
                 ]
 
         def get_widget(name):
-            return hubs.models.Widget.query.filter_by(hub=hub, plugin=name).one()
+            return Widget.query.filter_by(hub=hub, plugin=name).one()
 
         def check_move(name, position, expected):
             move_widget(get_widget(name), position)
@@ -151,7 +83,7 @@ class ViewUtilsTest(APPTest):
             self.assertListEqual(get_names(), expected)
 
         for index, name in enumerate(widget_names):
-            widget = hubs.models.Widget(
+            widget = Widget(
                 hub=hub, plugin=name,
                 left=True, index=index, _config="{}")
             self.session.add(widget)
diff --git a/hubs/tests/views/test_hub_view.py b/hubs/tests/views/test_hub_view.py
index 68b822c..be57081 100644
--- a/hubs/tests/views/test_hub_view.py
+++ b/hubs/tests/views/test_hub_view.py
@@ -1,91 +1,46 @@
 from __future__ import unicode_literals
 
-from flask import json
-
-from hubs.app import app
-from hubs.models import Hub
-from hubs.tests import APPTest, FakeAuthorization, auth_set
+from hubs.models import Hub, User
+from hubs.tests import APPTest, FakeAuthorization
 
 
 class HubViewTestCase(APPTest):
 
     def test_hub_logged_out(self):
-        with auth_set(app, None):  # check_auth doesn't load in unittest
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            match_expected = r'<h5[^>]*>Ralph</h5>'
-            self.assertRegexpMatches(
-                result.get_data(as_text=True), match_expected)
-            str_expected = 'Not logged in.'
-            self.assertIn(str_expected, result.get_data(as_text=True))
+        response = self.check_url("/ralph/")
+        self.assertIn("Not logged in.", response.get_data(as_text=True))
+        self.assertEqual(response.context["page_title"], "ralph")
+        state = response.context["initial_state"]
+        self.assertEqual(state["urls"]["hubConfig"], "/api/hubs/ralph/config")
+        self.assertFalse(state["currentUser"]["logged_in"])
+        self.assertFalse(state["currentUser"]["can_config_hub"])
+        self.assertFalse(state["currentUser"]["can_manage_users"])
 
     def test_hub_logged_in(self):
         user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-            self.assertNotIn(
-                'Not logged in.  Click to <a href="/login">login</a>',
-                result.get_data(as_text=True))
+        response = self.check_url("/ralph/", user=user)
+        self.assertNotIn(
+            'Not logged in.  Click to <a href="/login">login</a>',
+            response.get_data(as_text=True))
+        state = response.context["initial_state"]
+        self.assertTrue(state["currentUser"]["logged_in"])
+        self.assertTrue(state["currentUser"]["can_config_hub"])
+        self.assertTrue(state["currentUser"]["can_manage_users"])
 
     def test_hub_preview(self):
         hub = Hub.by_name('ralph')
         hub.config.visibility = "preview"
         # Preview hubs are accessible to anonymous users (but some
         # widgets may be restricted).
-        with auth_set(app, None):
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
+        self.check_url("/ralph/")
 
     def test_hub_private(self):
         hub = Hub.by_name('ralph')
         hub.config.visibility = "private"
         self.session.commit()
         # Private hubs are not accessible to anonymous users.
-        with auth_set(app, None):
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)
+        self.check_url("/ralph/", code=403)
         # But they are accessible to members.
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.get('/ralph', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
-
-    def test_hub_json(self):
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.get('/ralph/json', follow_redirects=True)
-        # assert the status code of the response
-        self.assertEqual(result.status_code, 200)
-        data = {
-            "config": {
-                "avatar": "https://seccdn.libravatar.org/avatar/"
-                          "9c9f7784935381befc302fe3c814f9136e7a339"
-                          "53d0318761669b8643f4df55c?s=312&d=retro",
-                'chat_channel': None,
-                'chat_domain': None,
-                "left_width": 8,
-                "summary": "Ralph",
-                "visibility": "public",
-            },
-            "members": ["ralph"],
-            "name": "ralph",
-            "owners": ["ralph"],
-            "subscribers": [],
-            "widgets": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 56],
-        }
-        self.assertDictEqual(data, json.loads(result.get_data(as_text=True)))
-
-    def test_hub_private_json(self):
-        hub = Hub.by_name('ralph')
-        hub.config.visibility = "private"
-        self.session.commit()
-        # Private hubs are not accessible to anonymous users.
-        with auth_set(app, None):
-            result = self.app.get('/ralph/json', follow_redirects=True)
-            self.assertEqual(result.status_code, 403)
-        # But they are accessible to members.
-        user = FakeAuthorization('ralph')
-        with auth_set(app, user):
-            result = self.app.get('/ralph/json', follow_redirects=True)
-            self.assertEqual(result.status_code, 200)
+        decause = User.by_username("decause")
+        hub.subscribe(decause, role='member')
+        self.check_url("/ralph/", user=FakeAuthorization("decause"))
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
index 36df575..2445387 100644
--- a/hubs/utils/views.py
+++ b/hubs/utils/views.py
@@ -49,25 +49,34 @@ def get_widget_instance(hub, idx, session=None):
         flask.abort(404)
 
 
-def get_visible_widgets(hub):
-    from hubs.widgets import registry
-    widgets = {"left": [], "right": []}
-    try:
+def get_menu_entries():
+    """Get the entries for the left menu."""
+    menu = []
+    if flask.g.auth.logged_in:
         user = flask.g.user
-    except AttributeError:
-        user = None
-    for widget in hub.widgets:
-        if widget.plugin not in registry:
-            continue  # disabled widget
-        if not widget.allows(user, "view"):
-            continue
-        if widget.left:
-            widgets["left"].append(widget)
-        else:
-            widgets["right"].append(widget)
-    widgets["left"].sort(key=lambda w: w.index)
-    widgets["right"].sort(key=lambda w: w.index)
-    return widgets
+        menu.append({
+            "url": flask.url_for("hub", name=user.username),
+            "icon": "home",
+            "text": "My Hub",
+        })
+        menu.append({
+            "url": flask.url_for("stream"),
+            "icon": "home",
+            "text": "My Stream",
+        })
+        for hub in user.bookmarks:
+            menu.append({
+                "url": flask.url_for("hub", name=hub.name),
+                "icon": "bookmark",
+                "text": hub.name,
+                "cssClass": "idle-{}".format(hub.activity_class),
+            })
+    menu.append({
+        "url": flask.url_for("groups"),
+        "icon": "users",
+        "text": "All groups",
+    })
+    return menu
 
 
 class WidgetConfigError(Exception):
diff --git a/hubs/views/hub.py b/hubs/views/hub.py
index 6677a7e..9dcd3d5 100644
--- a/hubs/views/hub.py
+++ b/hubs/views/hub.py
@@ -5,20 +5,49 @@ import hubs.models
 
 from hubs.app import app
 from hubs.utils.views import (
-    get_hub, get_sse_url, get_menu_entries, get_visible_widgets, require_hub_access,
+    get_hub, get_sse_url, get_menu_entries, require_hub_access,
     )
 
 
-@app.route('/<name>')
 @app.route('/<name>/')
 @require_hub_access("view")
 def hub(name):
     hub = get_hub(name, load_config=True)
-    widgets = get_visible_widgets(hub)
+    global_config = {
+        "chat_networks": app.config["CHAT_NETWORKS"],
+        "hub_visibility": hubs.models.HubConfig.VISIBILITY,
+        "roles": ["owner", "member"],
+    }
+    urls = {
+        "widgets": flask.url_for("api_hub_widgets", hub=hub.name),
+        "availableWidgets": flask.url_for("api_widgets"),
+        "sse": get_sse_url("hub/{}".format(hub.name)),
+        "hubConfig": flask.url_for("api_hub_config", name=hub.name),
+        "hubConfigSuggestUsers": flask.url_for(
+            "api_hub_config_suggest_users", name=hub.name),
+    }
+    current_user = flask.g.auth.copy()
+    current_user.update({
+        "can_view_hub": hub.allows(flask.g.user, "view"),
+        "can_config_hub": hub.allows(flask.g.user, "config"),
+        "can_manage_users": hub.allows(flask.g.user, "users.manage"),
+    })
+    menu = get_menu_entries()
+    flash_messages = [
+        {"msg": msg[1], "type": msg[0]} for msg in
+        flask.get_flashed_messages(with_categories=True)
+        ]
     return flask.render_template(
-        'hubs.html',
-        hub=hub,
-        widgets=widgets,
-        edit=False,
-        sse_url=get_sse_url("hub/{}".format(hub.name)),
+        'react.html',
+        page_title=hub.name,
+        initial_state=dict(
+            ui=dict(
+                page="Hub",
+                flashMessages=flash_messages,
+                leftMenu=menu,
+            ),
+            globalConfig=global_config,
+            urls=urls,
+            currentUser=current_user,
+            ),
         )

From 97d3d53db5a71c8380e75b2aa4214421156cd588 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:09 +0000
Subject: [PATCH 959/1001] React-based widgets are allowed to have no root view


---

diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index f160993..53c27f6 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -3,8 +3,8 @@ from __future__ import unicode_literals, absolute_import
 import json
 
 from hubs.app import app
-from hubs.models import Hub, User
-from hubs.tests import FakeAuthorization, widget_instance
+from hubs.models import Hub
+from hubs.tests import widget_instance
 from hubs.widgets import registry
 from . import WidgetTest
 
@@ -110,13 +110,6 @@ class HalpViewsTestCase(WidgetTest):
                 })
         return data
 
-    def test_root(self):
-        response = self.check_url('/ralph/w/halp/%i/' % self.widget.idx)
-        self.assertEqual(response.context["hubs"], ['fedora-devel'])
-
-    def test_view_authz(self):
-        self._test_view_authz()
-
     def test_props(self):
         with app.test_request_context('/'):
             props = self.widget.get_props()
diff --git a/hubs/widgets/__init__.py b/hubs/widgets/__init__.py
index be454bd..5dd0a8d 100644
--- a/hubs/widgets/__init__.py
+++ b/hubs/widgets/__init__.py
@@ -27,7 +27,7 @@ In order to be valid, a widget must:
 - have a valid :py:attr:`~hubs.widgets.base.Widget.name` attribute,
 - have a valid :py:attr:`~hubs.widgets.base.Widget.position` attribute,
 - contain at least one widget view named "``root``", registered for the "``/``"
-  URL.
+  URL, unless the widget is React-based.
 
 A widget view is a class which inherits from the
 :py:class:`hubs.widgets.view.WidgetView` class.  A widget can have one or more
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 5523385..db63192 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -116,12 +116,14 @@ class Widget(object):
                 )
         root_view = self.get_views().get("root")
         if root_view is None:
-            raise AttributeError(
-                'widgets must have a "root" view, please refer to the '
-                'documentation.')
-        if "/" not in root_view.url_rules:
-            raise AttributeError(
-                'the root view must be registered for the "/" URL rule.')
+            if not self.is_react:
+                raise AttributeError(
+                    'widgets must have a "root" view, please refer to the '
+                    'documentation.')
+        else:
+            if "/" not in root_view.url_rules:
+                raise AttributeError(
+                    'the root view must be registered for the "/" URL rule.')
 
     def get_parameters(self):
         """
diff --git a/hubs/widgets/feed/__init__.py b/hubs/widgets/feed/__init__.py
index a9a265d..d6c4c61 100644
--- a/hubs/widgets/feed/__init__.py
+++ b/hubs/widgets/feed/__init__.py
@@ -8,7 +8,7 @@ import flask
 from hubs.feed import format_msgs
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import WidgetView
 
 from .functions import GetData
 
@@ -43,15 +43,6 @@ class Feed(Widget):
         return props
 
 
-class BaseView(RootWidgetView):
-
-    def get_context(self, instance, *args, **kwargs):
-        return dict(
-            title=self.widget.label,
-            disable_autoreload=True,
-            )
-
-
 class ExistingView(WidgetView):
 
     name = "existing"
diff --git a/hubs/widgets/feed/templates/root.html b/hubs/widgets/feed/templates/root.html
deleted file mode 100644
index f687dd4..0000000
--- a/hubs/widgets/feed/templates/root.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div id="feed-{{ widget_instance.idx }}">
-</div>
-
-<script type="text/javascript"
-  src ="{{ url_for('static', filename='js/build/Feed.js') }}"></script>
-<script>
-(function() {
-    const FeedElement = React.createElement(Feed.Widget, {
-        url: {{ url_for("feed_existing", hub=widget_instance.hub.name, idx=widget_instance.idx) | tojson }},
-        widgetIdx: {{ widget_instance.idx | tojson }}
-    });
-    ReactDOM.render(FeedElement, document.getElementById('feed-' + {{ widget_instance.idx | tojson }}));
-})();
-</script>
-{% endblock %}
diff --git a/hubs/widgets/halp/templates/root.html b/hubs/widgets/halp/templates/root.html
deleted file mode 100644
index 8709b0e..0000000
--- a/hubs/widgets/halp/templates/root.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% extends "panel.html" %}
-
-{% block content %}
-<div id="widget-halp">
-</div>
-<script src="{{url_for('static', filename='js/build/Halp.js')}}"></script>
-<script>
-(function() {
-    const Widget = React.createElement(Halp.Widget, {
-        hubs: {{ hubs|tojson }},
-        urls: {
-            data: '{{ url_for("halp_data", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
-            search: '{{ url_for("halp_search", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
-            requesters: '{{ url_for("halp_requesters", hub=widget_instance.hub.name, idx=widget_instance.idx) }}',
-            spinner: '{{ url_for("static", filename="img/spinner.gif") }}',
-            spinnerCircle: '{{ url_for("static", filename="img/spinner-circle.gif") }}'
-        }
-    });
-    ReactDOM.render(Widget, document.getElementById('widget-halp'));
-})();
-</script>
-{% endblock %}
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index dfd1e30..184140f 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -4,12 +4,9 @@ import datetime
 import time
 
 import flask
-from flask.signals import template_rendered
 
 from hubs.models import Hub
-from hubs.utils.views import get_hub, require_hub_access
-from hubs.widgets import registry
-from hubs.widgets.view import WidgetView, RootWidgetView
+from hubs.widgets.view import WidgetView
 from .functions import GetRequests
 from .utils import find_hubs_for_msg, paginate
 
@@ -19,17 +16,6 @@ except ImportError:
     before_render_template = None  # Flask < 0.11
 
 
-class BaseView(RootWidgetView):
-    """The base view to instantiate the widget."""
-
-    def get_context(self, instance, *args, **kwargs):
-        return dict(
-            hubs=instance.config.get("hubs", []),
-            title=self.widget.label,
-            disable_autoreload=True,
-            )
-
-
 class DataView(WidgetView):
     """Get the requests in JSON format."""
 
diff --git a/hubs/widgets/view.py b/hubs/widgets/view.py
index fce34b3..86dd615 100644
--- a/hubs/widgets/view.py
+++ b/hubs/widgets/view.py
@@ -22,7 +22,8 @@ class WidgetView(View):
     - the :py:meth:`.get_context` method must be implemented
 
     Every widget must have a view with the name "``root``" registered to
-    ``['/']``, which will be the main entry point for the widget.
+    ``['/']`` (unless they are React-based). This view will be the main entry
+    point for the widget.
 
     The resulting endpoint will be composed using the widget name and the view
     name as ``<widget_name>_<view_name>``, for example ``meetings_root``.

From e572637bb33473546262df0ba892f4254727ba45 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:09 +0000
Subject: [PATCH 960/1001] Make the Halp REST API similar to the main REST API


---

diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index 53c27f6..715fa78 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -152,13 +152,15 @@ class HalpViewsTestCase(WidgetTest):
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data, {
-            'results': ['decause', 'devyani7', 'dhrish', 'i18n', 'infra']
+            'status': 'OK',
+            'data': ['decause', 'devyani7', 'dhrish', 'i18n', 'infra']
         })
         response = self.app.get('/w/halp/hubs?q=de')
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data, {
-            'results': ['decause', 'devyani7']
+            'status': 'OK',
+            'data': ['decause', 'devyani7']
         })
 
     def test_data(self):
@@ -167,13 +169,19 @@ class HalpViewsTestCase(WidgetTest):
         response = self.app.get('/ralph/w/halp/%i/data' % self.widget.idx)
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
-        self.assertEqual(data, {"requests": expected[:3]})
+        self.assertEqual(data, {
+            'status': 'OK',
+            "data": {"requests": expected[:3]}
+        })
         # Test with the right hub selected
         response = self.app.get('/ralph/w/halp/%i/data?hubs=decause'
                                 % self.widget.idx)
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
-        self.assertEqual(data, {"requests": expected[3:5]})
+        self.assertEqual(data, {
+            'status': 'OK',
+            "data": {"requests": expected[3:5]},
+        })
 
     def test_data_wrong_hub(self):
         # Test with the wrong hub selected
@@ -181,7 +189,9 @@ class HalpViewsTestCase(WidgetTest):
                                 % self.widget.idx)
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
-        self.assertEqual(data, {"requests": []})
+        self.assertEqual(data, {
+            'status': 'OK', "data": {"requests": []}
+        })
 
     def test_search_requesters(self):
         response = self.app.get(
@@ -189,15 +199,16 @@ class HalpViewsTestCase(WidgetTest):
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data, {
-            'results': ['jborean93', 'jkurik', 'mattdm', 'nitzmahone',
-                        'stoney']
-        })
+            'status': 'OK',
+            'data': ['jborean93', 'jkurik', 'mattdm', 'nitzmahone', 'stoney']
+            })
         response = self.app.get(
             '/ralph/w/halp/%i/requesters?q=j' % self.widget.idx)
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertDictEqual(data, {
-            'results': ['jborean93', 'jkurik']
+            'status': 'OK',
+            'data': ['jborean93', 'jkurik']
         })
 
     def test_search_all(self):
@@ -207,7 +218,8 @@ class HalpViewsTestCase(WidgetTest):
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertEqual(data, {
-            "requests": expected[:3],
+            'status': 'OK',
+            'data': {"requests": expected[:3]},
             'page': {
                 'has_next': True,
                 'has_prev': False,
@@ -222,7 +234,8 @@ class HalpViewsTestCase(WidgetTest):
         self.assertEqual(response.status_code, 200)
         data = json.loads(response.get_data(as_text=True))
         self.assertEqual(data, {
-            "requests": expected[3:],
+            'status': 'OK',
+            'data': {"requests": expected[3:]},
             'page': {
                 'has_next': False,
                 'has_prev': True,
@@ -239,7 +252,8 @@ class HalpViewsTestCase(WidgetTest):
         data = json.loads(response.get_data(as_text=True))
         expected = self._get_sample_data_with_hub_keys()
         self.assertEqual(data, {
-            "requests": expected[0:1],
+            'status': 'OK',
+            "data": {"requests": expected[0:1]},
             'page': {
                 'has_next': False,
                 'has_prev': False,
@@ -256,7 +270,8 @@ class HalpViewsTestCase(WidgetTest):
         data = json.loads(response.get_data(as_text=True))
         expected = self._get_sample_data_with_hub_keys()
         self.assertEqual(data, {
-            "requests": expected[3:4],
+            'status': 'OK',
+            "data": {"requests": expected[3:4]},
             'page': {
                 'has_next': False,
                 'has_prev': False,
@@ -273,7 +288,8 @@ class HalpViewsTestCase(WidgetTest):
         data = json.loads(response.get_data(as_text=True))
         expected = self._get_sample_data_with_hub_keys()
         self.assertEqual(data, {
-            "requests": expected[1:2],
+            'status': 'OK',
+            "data": {"requests": expected[1:2]},
             'page': {
                 'has_next': False,
                 'has_prev': False,
@@ -291,7 +307,8 @@ class HalpViewsTestCase(WidgetTest):
         data = json.loads(response.get_data(as_text=True))
         expected = self._get_sample_data_with_hub_keys()
         self.assertEqual(data, {
-            "requests": expected[1:2],
+            'status': 'OK',
+            "data": {"requests": expected[1:2]},
             'page': {
                 'has_next': False,
                 'has_prev': False,
diff --git a/hubs/widgets/halp/functions.py b/hubs/widgets/halp/functions.py
index 0191710..c99f611 100644
--- a/hubs/widgets/halp/functions.py
+++ b/hubs/widgets/halp/functions.py
@@ -29,7 +29,6 @@ class GetRequests(CachedFunction):
     TOPIC = "org.fedoraproject.prod.meetbot.meeting.item.help"
 
     def execute(self):
-        # return [_format_message(msg) for msg in EXAMPLE_DATA]
         raw_messages = datagrepper_get({
             "topic": self.TOPIC,
             "delta": str(86400 * 10),  # 10 days
diff --git a/hubs/widgets/halp/views.py b/hubs/widgets/halp/views.py
index 184140f..d8a0c41 100644
--- a/hubs/widgets/halp/views.py
+++ b/hubs/widgets/halp/views.py
@@ -24,12 +24,15 @@ class DataView(WidgetView):
     json = True
 
     def get_context(self, instance, *args, **kwargs):
-        get_requests = GetRequests(instance)
         data = {"requests": []}
+        get_requests = GetRequests(instance)
         requests = get_requests() or []
+        # from .functions import _format_message, EXAMPLE_DATA
+        # requests = [_format_message(msg) for msg in EXAMPLE_DATA]
         hubs_filter = flask.request.args.getlist("hubs")
         for req in requests:
             req["hubs"] = find_hubs_for_msg(req)
+            # req["hubs"] = ["infrastructure", "commops"]
             if not req["hubs"]:
                 continue
             req["hub"] = req["hubs"][0]  # Arbitrarily assign the first hub.
@@ -44,7 +47,7 @@ class DataView(WidgetView):
             if len(data["requests"]) == 3:
                 # Only 3 requests on the main widget.
                 break
-        return data
+        return dict(status="OK", data=data)
 
 
 class SearchView(WidgetView):
@@ -101,8 +104,7 @@ class SearchView(WidgetView):
         requests, page_data = paginate(
             data["requests"], instance.config["per_page"])
         data["requests"] = requests
-        data["page"] = page_data
-        return data
+        return dict(status="OK", data=data, page=page_data)
 
 
 class RequestersView(WidgetView):
@@ -123,7 +125,7 @@ class RequestersView(WidgetView):
         if query:
             results = [name for name in results if name.startswith(query)]
         results = sorted(list(results))[:self.MAX_SUGGESTS]
-        return {"results": results}
+        return {"status": "OK", "data": results}
 
 
 def hubs_suggest_view():
@@ -136,4 +138,4 @@ def hubs_suggest_view():
         results = results.filter(Hub.name.ilike(
             "%s%%" % flask.request.args.get("q")))
     results = results.order_by(Hub.name)[:MAX_SUGGESTS]
-    return flask.jsonify({"results": [h.name for h in results]})
+    return flask.jsonify({"status": "OK", "data": [h.name for h in results]})

From 10aac805c08c356183fd4113331d659ce394e00d Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:09 +0000
Subject: [PATCH 961/1001] Make the Streams page use React too


---

diff --git a/hubs/templates/stream.html b/hubs/templates/stream.html
deleted file mode 100644
index 4292f6d..0000000
--- a/hubs/templates/stream.html
+++ /dev/null
@@ -1,43 +0,0 @@
-{% extends "master.html" %}
-
-{% block title %}My Stream{% endblock %}
-
-
-{% block header %}
-  <h1>My Stream</h1>
-  <p>Notifications, actions, and other things of interest to me</p>
-{% endblock header %}
-
-
-{% block content %}
-
-<div class="row">
-  <div class="col-sm-8">
-    <div id="streams">
-    </div>
-  </div>
-
-  <div class="col-sm-4">
-    <!-- put some content here! :) -->
-  </div>
-</div>
-
-{% endblock content %}
-
-
-{% block jscripts %}
-{{ super() }}
-<script>
- $(function() {
-    setup_sse({{ sse_url | tojson }});
-    const StreamsElement = React.createElement(Hubs.Streams, {
-        username: {{ g.auth.nickname | tojson }},
-        urls: {
-            saved: {{ url_for("saved_notifs") | tojson }},
-            content: {{ url_for("stream_existing") | tojson }},
-        },
-    });
-    ReactDOM.render(StreamsElement, document.getElementById('streams'));
- });
-</script>
-{% endblock %}
diff --git a/hubs/views/user.py b/hubs/views/user.py
index c0e2b99..02b2e54 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -5,20 +5,38 @@ import hubs.models
 import hubs.feed
 
 from hubs.app import app
-from hubs.utils.views import login_required, get_hub, get_sse_url
+from hubs.utils.views import (
+    login_required, get_sse_url, get_menu_entries)
 
 
 @app.route('/stream')
 @app.route('/stream/')
 @login_required
 def stream():
-    username = flask.g.user.username
-    hub = get_hub(username)
+    current_user = flask.g.auth.copy()
+    urls = {
+        "sse": get_sse_url("user/{}".format(current_user.nickname)),
+        "notifications": flask.url_for("stream_existing"),
+        "saved": flask.url_for("saved_notifs"),
+    }
+    menu = get_menu_entries()
+    flash_messages = [
+        {"msg": msg[1], "type": msg[0]} for msg in
+        flask.get_flashed_messages(with_categories=True)
+        ]
     return flask.render_template(
-        'stream.html',
-        hub=hub,
-        sse_url=get_sse_url("user/{}".format(username)),
-    )
+        'react.html',
+        page_title="My Stream",
+        initial_state=dict(
+            ui=dict(
+                page="Streams",
+                flashMessages=flash_messages,
+                leftMenu=menu,
+            ),
+            urls=urls,
+            currentUser=current_user,
+            ),
+        )
 
 
 @app.route('/stream/existing')

From d01121338496a18d86faba39e0a54c2316d07267 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Sep 28 2017 17:35:09 +0000
Subject: [PATCH 962/1001] Remove dead JS code


---

diff --git a/hubs/static/js/Sortable.min.js b/hubs/static/js/Sortable.min.js
deleted file mode 100644
index e95d2a3..0000000
--- a/hubs/static/js/Sortable.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! Sortable 1.4.2 - MIT | git://github.com/rubaxa/Sortable.git */
-!function(a){"use strict";"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=a():"undefined"!=typeof Package?Sortable=a():window.Sortable=a()}(function(){"use strict";function a(a,b){if(!a||!a.nodeType||1!==a.nodeType)throw"Sortable: `el` must be HTMLElement, and not "+{}.toString.call(a);this.el=a,this.options=b=r({},b),a[L]=this;var c={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[uo]l/i.test(a.nodeName)?"li":">*",ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",ignore:"a, img",filter:null,animation:0,setData:function(a,b){a.setData("Text",b.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1};for(var d in c)!(d in b)&&(b[d]=c[d]);V(b);for(var f in this)"_"===f.charAt(0)&&(this[f]=this[f].bind(this));this.nativeDraggable=b.forceFallback?!1:P,e(a,"mousedown",this._onTapStart),e(a,"touchstart",this._onTapStart),this.nativeDraggable&&(e(a,"dragover",this),e(a,"dragenter",this)),T.push(this._onDragOver),b.store&&this.sort(b.store.get(this))}function b(a){v&&v.state!==a&&(h(v,"display",a?"none":""),!a&&v.state&&w.insertBefore(v,s),v.state=a)}function c(a,b,c){if(a){c=c||N,b=b.split(".");var d=b.shift().toUpperCase(),e=new RegExp("\\s("+b.join("|")+")(?=\\s)","g");do if(">*"===d&&a.parentNode===c||(""===d||a.nodeName.toUpperCase()==d)&&(!b.length||((" "+a.className+" ").match(e)||[]).length==b.length))return a;while(a!==c&&(a=a.parentNode))}return null}function d(a){a.dataTransfer&&(a.dataTransfer.dropEffect="move"),a.preventDefault()}function e(a,b,c){a.addEventListener(b,c,!1)}function f(a,b,c){a.removeEventListener(b,c,!1)}function g(a,b,c){if(a)if(a.classList)a.classList[c?"add":"remove"](b);else{var d=(" "+a.className+" ").replace(K," ").replace(" "+b+" "," ");a.className=(d+(c?" "+b:"")).replace(K," ")}}function h(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return N.defaultView&&N.defaultView.getComputedStyle?c=N.defaultView.getComputedStyle(a,""):a.currentStyle&&(c=a.currentStyle),void 0===b?c:c[b];b in d||(b="-webkit-"+b),d[b]=c+("string"==typeof c?"":"px")}}function i(a,b,c){if(a){var d=a.getElementsByTagName(b),e=0,f=d.length;if(c)for(;f>e;e++)c(d[e],e);return d}return[]}function j(a,b,c,d,e,f,g){var h=N.createEvent("Event"),i=(a||b[L]).options,j="on"+c.charAt(0).toUpperCase()+c.substr(1);h.initEvent(c,!0,!0),h.to=b,h.from=e||b,h.item=d||b,h.clone=v,h.oldIndex=f,h.newIndex=g,b.dispatchEvent(h),i[j]&&i[j].call(a,h)}function k(a,b,c,d,e,f){var g,h,i=a[L],j=i.options.onMove;return g=N.createEvent("Event"),g.initEvent("move",!0,!0),g.to=b,g.from=a,g.dragged=c,g.draggedRect=d,g.related=e||b,g.relatedRect=f||b.getBoundingClientRect(),a.dispatchEvent(g),j&&(h=j.call(i,g)),h}function l(a){a.draggable=!1}function m(){R=!1}function n(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return(b.clientY-(d.top+d.height)>5||b.clientX-(d.right+d.width)>5)&&c}function o(a){for(var b=a.tagName+a.className+a.src+a.href+a.textContent,c=b.length,d=0;c--;)d+=b.charCodeAt(c);return d.toString(36)}function p(a){var b=0;if(!a||!a.parentNode)return-1;for(;a&&(a=a.previousElementSibling);)"TEMPLATE"!==a.nodeName.toUpperCase()&&b++;return b}function q(a,b){var c,d;return function(){void 0===c&&(c=arguments,d=this,setTimeout(function(){1===c.length?a.call(d,c[0]):a.apply(d,c),c=void 0},b))}}function r(a,b){if(a&&b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}var s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J={},K=/\s+/g,L="Sortable"+(new Date).getTime(),M=window,N=M.document,O=M.parseInt,P=!!("draggable"in N.createElement("div")),Q=function(a){return a=N.createElement("x"),a.style.cssText="pointer-events:auto","auto"===a.style.pointerEvents}(),R=!1,S=Math.abs,T=([].slice,[]),U=q(function(a,b,c){if(c&&b.scroll){var d,e,f,g,h=b.scrollSensitivity,i=b.scrollSpeed,j=a.clientX,k=a.clientY,l=window.innerWidth,m=window.innerHeight;if(z!==c&&(y=b.scroll,z=c,y===!0)){y=c;do if(y.offsetWidth<y.scrollWidth||y.offsetHeight<y.scrollHeight)break;while(y=y.parentNode)}y&&(d=y,e=y.getBoundingClientRect(),f=(S(e.right-j)<=h)-(S(e.left-j)<=h),g=(S(e.bottom-k)<=h)-(S(e.top-k)<=h)),f||g||(f=(h>=l-j)-(h>=j),g=(h>=m-k)-(h>=k),(f||g)&&(d=M)),(J.vx!==f||J.vy!==g||J.el!==d)&&(J.el=d,J.vx=f,J.vy=g,clearInterval(J.pid),d&&(J.pid=setInterval(function(){d===M?M.scrollTo(M.pageXOffset+f*i,M.pageYOffset+g*i):(g&&(d.scrollTop+=g*i),f&&(d.scrollLeft+=f*i))},24)))}},30),V=function(a){var b=a.group;b&&"object"==typeof b||(b=a.group={name:b}),["pull","put"].forEach(function(a){a in b||(b[a]=!0)}),a.groups=" "+b.name+(b.put.join?" "+b.put.join(" "):"")+" "};return a.prototype={constructor:a,_onTapStart:function(a){var b=this,d=this.el,e=this.options,f=a.type,g=a.touches&&a.touches[0],h=(g||a).target,i=h,k=e.filter;if(!("mousedown"===f&&0!==a.button||e.disabled)&&(h=c(h,e.draggable,d))){if(D=p(h),"function"==typeof k){if(k.call(this,a,h,this))return j(b,i,"filter",h,d,D),void a.preventDefault()}else if(k&&(k=k.split(",").some(function(a){return a=c(i,a.trim(),d),a?(j(b,a,"filter",h,d,D),!0):void 0})))return void a.preventDefault();(!e.handle||c(i,e.handle,d))&&this._prepareDragStart(a,g,h)}},_prepareDragStart:function(a,b,c){var d,f=this,h=f.el,j=f.options,k=h.ownerDocument;c&&!s&&c.parentNode===h&&(G=a,w=h,s=c,t=s.parentNode,x=s.nextSibling,F=j.group,d=function(){f._disableDelayedDrag(),s.draggable=!0,g(s,f.options.chosenClass,!0),f._triggerDragStart(b)},j.ignore.split(",").forEach(function(a){i(s,a.trim(),l)}),e(k,"mouseup",f._onDrop),e(k,"touchend",f._onDrop),e(k,"touchcancel",f._onDrop),j.delay?(e(k,"mouseup",f._disableDelayedDrag),e(k,"touchend",f._disableDelayedDrag),e(k,"touchcancel",f._disableDelayedDrag),e(k,"mousemove",f._disableDelayedDrag),e(k,"touchmove",f._disableDelayedDrag),f._dragStartTimer=setTimeout(d,j.delay)):d())},_disableDelayedDrag:function(){var a=this.el.ownerDocument;clearTimeout(this._dragStartTimer),f(a,"mouseup",this._disableDelayedDrag),f(a,"touchend",this._disableDelayedDrag),f(a,"touchcancel",this._disableDelayedDrag),f(a,"mousemove",this._disableDelayedDrag),f(a,"touchmove",this._disableDelayedDrag)},_triggerDragStart:function(a){a?(G={target:s,clientX:a.clientX,clientY:a.clientY},this._onDragStart(G,"touch")):this.nativeDraggable?(e(s,"dragend",this),e(w,"dragstart",this._onDragStart)):this._onDragStart(G,!0);try{N.selection?N.selection.empty():window.getSelection().removeAllRanges()}catch(b){}},_dragStarted:function(){w&&s&&(g(s,this.options.ghostClass,!0),a.active=this,j(this,w,"start",s,w,D))},_emulateDragOver:function(){if(H){if(this._lastX===H.clientX&&this._lastY===H.clientY)return;this._lastX=H.clientX,this._lastY=H.clientY,Q||h(u,"display","none");var a=N.elementFromPoint(H.clientX,H.clientY),b=a,c=" "+this.options.group.name,d=T.length;if(b)do{if(b[L]&&b[L].options.groups.indexOf(c)>-1){for(;d--;)T[d]({clientX:H.clientX,clientY:H.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);Q||h(u,"display","")}},_onTouchMove:function(b){if(G){a.active||this._dragStarted(),this._appendGhost();var c=b.touches?b.touches[0]:b,d=c.clientX-G.clientX,e=c.clientY-G.clientY,f=b.touches?"translate3d("+d+"px,"+e+"px,0)":"translate("+d+"px,"+e+"px)";I=!0,H=c,h(u,"webkitTransform",f),h(u,"mozTransform",f),h(u,"msTransform",f),h(u,"transform",f),b.preventDefault()}},_appendGhost:function(){if(!u){var a,b=s.getBoundingClientRect(),c=h(s),d=this.options;u=s.cloneNode(!0),g(u,d.ghostClass,!1),g(u,d.fallbackClass,!0),h(u,"top",b.top-O(c.marginTop,10)),h(u,"left",b.left-O(c.marginLeft,10)),h(u,"width",b.width),h(u,"height",b.height),h(u,"opacity","0.8"),h(u,"position","fixed"),h(u,"zIndex","100000"),h(u,"pointerEvents","none"),d.fallbackOnBody&&N.body.appendChild(u)||w.appendChild(u),a=u.getBoundingClientRect(),h(u,"width",2*b.width-a.width),h(u,"height",2*b.height-a.height)}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;this._offUpEvents(),"clone"==F.pull&&(v=s.cloneNode(!0),h(v,"display","none"),w.insertBefore(v,s)),b?("touch"===b?(e(N,"touchmove",this._onTouchMove),e(N,"touchend",this._onDrop),e(N,"touchcancel",this._onDrop)):(e(N,"mousemove",this._onTouchMove),e(N,"mouseup",this._onDrop)),this._loopId=setInterval(this._emulateDragOver,50)):(c&&(c.effectAllowed="move",d.setData&&d.setData.call(this,c,s)),e(N,"drop",this),setTimeout(this._dragStarted,0))},_onDragOver:function(a){var d,e,f,g=this.el,i=this.options,j=i.group,l=j.put,o=F===j,p=i.sort;if(void 0!==a.preventDefault&&(a.preventDefault(),!i.dragoverBubble&&a.stopPropagation()),I=!0,F&&!i.disabled&&(o?p||(f=!w.contains(s)):F.pull&&l&&(F.name===j.name||l.indexOf&&~l.indexOf(F.name)))&&(void 0===a.rootEl||a.rootEl===this.el)){if(U(a,i,this.el),R)return;if(d=c(a.target,i.draggable,g),e=s.getBoundingClientRect(),f)return b(!0),void(v||x?w.insertBefore(s,v||x):p||w.appendChild(s));if(0===g.children.length||g.children[0]===u||g===a.target&&(d=n(g,a))){if(d){if(d.animated)return;r=d.getBoundingClientRect()}b(o),k(w,g,s,e,d,r)!==!1&&(s.contains(g)||(g.appendChild(s),t=g),this._animate(e,s),d&&this._animate(r,d))}else if(d&&!d.animated&&d!==s&&void 0!==d.parentNode[L]){A!==d&&(A=d,B=h(d),C=h(d.parentNode));var q,r=d.getBoundingClientRect(),y=r.right-r.left,z=r.bottom-r.top,D=/left|right|inline/.test(B.cssFloat+B.display)||"flex"==C.display&&0===C["flex-direction"].indexOf("row"),E=d.offsetWidth>s.offsetWidth,G=d.offsetHeight>s.offsetHeight,H=(D?(a.clientX-r.left)/y:(a.clientY-r.top)/z)>.5,J=d.nextElementSibling,K=k(w,g,s,e,d,r);if(K!==!1){if(R=!0,setTimeout(m,30),b(o),1===K||-1===K)q=1===K;else if(D){var M=s.offsetTop,N=d.offsetTop;q=M===N?d.previousElementSibling===s&&!E||H&&E:N>M}else q=J!==s&&!G||H&&G;s.contains(g)||(q&&!J?g.appendChild(s):d.parentNode.insertBefore(s,q?J:d)),t=s.parentNode,this._animate(e,s),this._animate(r,d)}}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();h(b,"transition","none"),h(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,h(b,"transition","all "+c+"ms"),h(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){h(b,"transition",""),h(b,"transform",""),b.animated=!1},c)}},_offUpEvents:function(){var a=this.el.ownerDocument;f(N,"touchmove",this._onTouchMove),f(a,"mouseup",this._onDrop),f(a,"touchend",this._onDrop),f(a,"touchcancel",this._onDrop)},_onDrop:function(b){var c=this.el,d=this.options;clearInterval(this._loopId),clearInterval(J.pid),clearTimeout(this._dragStartTimer),f(N,"mousemove",this._onTouchMove),this.nativeDraggable&&(f(N,"drop",this),f(c,"dragstart",this._onDragStart)),this._offUpEvents(),b&&(I&&(b.preventDefault(),!d.dropBubble&&b.stopPropagation()),u&&u.parentNode.removeChild(u),s&&(this.nativeDraggable&&f(s,"dragend",this),l(s),g(s,this.options.ghostClass,!1),g(s,this.options.chosenClass,!1),w!==t?(E=p(s),E>=0&&(j(null,t,"sort",s,w,D,E),j(this,w,"sort",s,w,D,E),j(null,t,"add",s,w,D,E),j(this,w,"remove",s,w,D,E))):(v&&v.parentNode.removeChild(v),s.nextSibling!==x&&(E=p(s),E>=0&&(j(this,w,"update",s,w,D,E),j(this,w,"sort",s,w,D,E)))),a.active&&((null===E||-1===E)&&(E=D),j(this,w,"end",s,w,D,E),this.save())),w=s=t=u=x=v=y=z=G=H=I=E=A=B=F=a.active=null)},handleEvent:function(a){var b=a.type;"dragover"===b||"dragenter"===b?s&&(this._onDragOver(a),d(a)):("drop"===b||"dragend"===b)&&this._onDrop(a)},toArray:function(){for(var a,b=[],d=this.el.children,e=0,f=d.length,g=this.options;f>e;e++)a=d[e],c(a,g.draggable,this.el)&&b.push(a.getAttribute(g.dataIdAttr)||o(a));return b},sort:function(a){var b={},d=this.el;this.toArray().forEach(function(a,e){var f=d.children[e];c(f,this.options.draggable,d)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(d.removeChild(b[a]),d.appendChild(b[a]))})},save:function(){var a=this.options.store;a&&a.set(this)},closest:function(a,b){return c(a,b||this.options.draggable,this.el)},option:function(a,b){var c=this.options;return void 0===b?c[a]:(c[a]=b,void("group"===a&&V(c)))},destroy:function(){var a=this.el;a[L]=null,f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),this.nativeDraggable&&(f(a,"dragover",this),f(a,"dragenter",this)),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),T.splice(T.indexOf(this._onDragOver),1),this._onDrop(),this.el=a=null}},a.utils={on:e,off:f,css:h,find:i,is:function(a,b){return!!c(a,b,a)},extend:r,throttle:q,closest:c,toggleClass:g,index:p},a.create=function(b,c){return new a(b,c)},a.version="1.4.2",a});
\ No newline at end of file
diff --git a/hubs/static/js/bootstrap3-typeahead.min.js b/hubs/static/js/bootstrap3-typeahead.min.js
deleted file mode 100644
index b8ffd9d..0000000
--- a/hubs/static/js/bootstrap3-typeahead.min.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/* =============================================================
- * bootstrap3-typeahead.js v3.1.0
- * https://github.com/bassjobsen/Bootstrap-3-Typeahead
- * =============================================================
- * Original written by @mdo and @fat
- * =============================================================
- * Copyright 2014 Bass Jobsen @bassjobsen
- *
- * Licensed under the Apache License, Version 2.0 (the 'License');
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an 'AS IS' BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============================================================ */
-!function(a,b){"use strict";"undefined"!=typeof module&&module.exports?module.exports=b(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):b(a.jQuery)}(this,function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.select=this.options.select||this.select,this.autoSelect="boolean"==typeof this.options.autoSelect?this.options.autoSelect:!0,this.highlighter=this.options.highlighter||this.highlighter,this.render=this.options.render||this.render,this.updater=this.options.updater||this.updater,this.displayText=this.options.displayText||this.displayText,this.source=this.options.source,this.delay=this.options.delay,this.$menu=a(this.options.menu),this.$appendTo=this.options.appendTo?a(this.options.appendTo):null,this.shown=!1,this.listen(),this.showHintOnFocus="boolean"==typeof this.options.showHintOnFocus?this.options.showHintOnFocus:!1,this.afterSelect=this.options.afterSelect,this.addItem=!1};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").data("value");if(this.$element.data("active",a),this.autoSelect||a){var b=this.updater(a);b||(b=""),this.$element.val(this.displayText(b)||b).text(this.displayText(b)||b).change(),this.afterSelect(b)}return this.hide()},updater:function(a){return a},setSource:function(a){this.source=a},show:function(){var b,c=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight}),d="function"==typeof this.options.scrollHeight?this.options.scrollHeight.call():this.options.scrollHeight;b=this.shown?this.$menu:this.$appendTo?this.$menu.appendTo(this.$appendTo):this.$menu.insertAfter(this.$element);var e=a(b).parent().hasClass("dropup"),f=e?"auto":c.top+c.height+d,g=a(b).hasClass("dropdown-menu-right"),h=g?"auto":c.left;return b.css({top:f,left:h}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){if("undefined"!=typeof b&&null!==b?this.query=b:this.query=this.$element.val()||this.$element.text()||"",this.query.length<this.options.minLength&&!this.options.showHintOnFocus)return this.shown?this.hide():this;var c=a.proxy(function(){a.isFunction(this.source)?this.source(this.query,a.proxy(this.process,this)):this.source&&this.process(this.source)},this);clearTimeout(this.lookupWorker),this.lookupWorker=setTimeout(c,this.delay)},process:function(b){var c=this;return b=a.grep(b,function(a){return c.matcher(a)}),b=this.sorter(b),b.length||this.options.addItem?(b.length>0?this.$element.data("active",b[0]):this.$element.data("active",null),this.options.addItem&&b.push(this.options.addItem),"all"==this.options.items?this.render(b).show():this.render(b.slice(0,this.options.items)).show()):this.shown?this.hide():this},matcher:function(a){var b=this.displayText(a);return~b.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){for(var b,c=[],d=[],e=[];b=a.shift();){var f=this.displayText(b);f.toLowerCase().indexOf(this.query.toLowerCase())?~f.indexOf(this.query)?d.push(b):e.push(b):c.push(b)}return c.concat(d,e)},highlighter:function(b){var c,d,e,f,g=a("<div></div>"),h=this.query,i=b.toLowerCase().indexOf(h.toLowerCase()),j=h.length;if(0===j)return g.text(b).html();for(;i>-1;)c=b.substr(0,i),d=b.substr(i,j),e=b.substr(i+j),f=a("<strong></strong>").text(d),g.append(document.createTextNode(c)).append(f),b=e,i=b.toLowerCase().indexOf(h.toLowerCase());return g.append(document.createTextNode(b)).html()},render:function(b){var c=this,d=this,e=!1,f=[],g=c.options.separator;return a.each(b,function(a,c){a>0&&c[g]!==b[a-1][g]&&f.push({__type:"divider"}),!c[g]||0!==a&&c[g]===b[a-1][g]||f.push({__type:"category",name:c[g]}),f.push(c)}),b=a(f).map(function(b,f){if("category"==(f.__type||!1))return a(c.options.headerHtml).text(f.name)[0];if("divider"==(f.__type||!1))return a(c.options.headerDivider)[0];var g=d.displayText(f);return b=a(c.options.item).data("value",f),b.find("a").html(c.highlighter(g,f)),g==d.$element.val()&&(b.addClass("active"),d.$element.data("active",f),e=!0),b[0]}),this.autoSelect&&!e&&(b.filter(":not(.dropdown-header)").first().addClass("active"),this.$element.data("active",b.first().data("value"))),this.$menu.html(b),this},displayText:function(a){return"undefined"!=typeof a&&"undefined"!=typeof a.name&&a.name||a},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("input",a.proxy(this.input,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this)).on("mousedown",a.proxy(this.mousedown,this))},mousedown:function(a){this.mouseddown=!0,a.stopPropagation(),a.preventDefault()},destroy:function(){this.$element.data("typeahead",null),this.$element.data("active",null),this.$element.off("focus").off("blur").off("keypress").off("input").off("keyup"),this.eventSupported("keydown")&&this.$element.off("keydown"),this.$menu.remove();this.destroyed=true;},eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b="function"==typeof this.$element[a]),b},move:function(a){if(this.shown)switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.shiftKey)return;a.preventDefault(),this.prev();break;case 40:if(a.shiftKey)return;a.preventDefault(),this.next()}},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.shown||40!=b.keyCode?this.move(b):this.lookup()},keypress:function(a){this.suppressKeyPressRepeat||this.move(a)},input:function(a){this.lookup(),a.preventDefault()},keyup:function(a){if(this.destroyed){return};switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide()}a.preventDefault()},focus:function(a){this.focused||(this.focused=!0,this.options.showHintOnFocus&&this.lookup())},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&(this.mouseddown&&a.originalEvent?this.mouseddown=!1:this.hide())},click:function(a){a.preventDefault(),this.select(),this.$element.focus(),this.hide()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1}};var c=a.fn.typeahead;a.fn.typeahead=function(c){var d=arguments;return"string"==typeof c&&"getActive"==c?this.data("active"):this.each(function(){var e=a(this),f=e.data("typeahead"),g="object"==typeof c&&c;f||e.data("typeahead",f=new b(this,g)),"string"==typeof c&&f[c]&&(d.length>1?f[c].apply(f,Array.prototype.slice.call(d,1)):f[c]())})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu" role="listbox"></ul>',item:'<li><a class="dropdown-item" href="#" role="option"></a></li>',minLength:1,scrollHeight:0,autoSelect:!0,afterSelect:a.noop,addItem:!1,delay:0,separator:"category",headerHtml:'<li class="dropdown-header"></li>',headerDivider:'<li class="divider" role="separator"></li>'},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);c.data("typeahead")||c.typeahead(c.data())})});
diff --git a/hubs/static/js/hubs_input.js b/hubs/static/js/hubs_input.js
deleted file mode 100644
index 79b0fb0..0000000
--- a/hubs/static/js/hubs_input.js
+++ /dev/null
@@ -1,13 +0,0 @@
-$(function(){
-  if ($('#calendar') != null){
-    $.get(
-      'https://apps.fedoraproject.org/calendar/api/calendars/',
-      function(data){
-        data = JSON.parse(data);
-        var d = data.calendars.map(function(cal) { return cal.calendar_name; });
-        $('#calendar').typeahead({ source: d });
-      },
-      'jsonp'
-    );
-  }
-});
diff --git a/hubs/static/js/utils.js b/hubs/static/js/utils.js
deleted file mode 100644
index 63f3ed0..0000000
--- a/hubs/static/js/utils.js
+++ /dev/null
@@ -1,77 +0,0 @@
-// These two functions are used by the feed widget to expand and collapse
-// entries.
-var expand_feed_entries = function(idx) {
-    $("#expand-" + idx).addClass('hidden');
-    $("#collapse-" + idx).removeClass('hidden');
-    $("#content-" + idx).removeClass('hidden');
-}
-var collapse_feed_entries = function(idx) {
-    $("#expand-" + idx).removeClass('hidden');
-    $("#collapse-" + idx).addClass('hidden');
-    $("#content-" + idx).addClass('hidden');
-}
-
-// Load widgets
-function setup_widgets() {
-    $("div.widget[data-url]").each(function() {
-        var element=$(this);
-        $.ajax({
-            url: element.attr("data-url"),
-            dataType: 'html',
-            success: function(html) {
-                element.html(html);
-                setTimeout(function() {
-                  element.find('.panel').toggleClass('panel-visible');
-                }, 100);
-            },
-            error: function() {
-                element.html('Got an error retrieving this widget.  Sorry :(');
-                console.log('error');
-                console.trace();
-            },
-        });
-    });
-}
-
-function setup_sse(url) {
-    if (!url || !window.EventSource) {
-      // Auto-update is disabled.
-      return;
-    }
-    var sseSource = new Hubs.ReconnectingEventSource(url),
-        notifTimeout = null;
-    sseSource.addEventListener("hubs:widget-updated", function(e) {
-        var widget = $("#widget-" + e.data);
-        if (widget.length === 0) { return; }
-        if (widget.find("div.card[data-disable-autoreload]").length !== 0) { return; }
-        $.ajax({
-            url: widget.attr("data-url"),
-            dataType: 'html',
-            success: function(html) {
-                widget.css("opacity", "0.5");
-                widget.html(html);
-                widget.animate({opacity: 1}, 200);
-            },
-            error: function() {
-                console.log('error updating the widget');
-                console.trace();
-            },
-        });
-    });
-    function change_notify_icon(color) {
-        // Set the notify icon for 5s
-        if (color == "green") {
-            color = "#33ff00";
-        } else if (color == "red") {
-            color = "#eb361e";
-        }
-        Notificon(color);
-        if (notifTimeout) { clearTimeout(notifTimeout); }
-        notifTimeout = setTimeout(function(){ Notificon(); }, 5000)
-    }
-    // Icon to red on disconnect, icon to green on reconnect.
-    sseSource.addEventListener("error", function() { change_notify_icon("red"); });
-    sseSource.addEventListener("open", function() { change_notify_icon("green"); });
-    // Make it accessible by other components on the page.
-    document.sseSource = sseSource;
-  }
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 1a74f82..3e65d31 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -165,7 +165,6 @@
 <script src="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.min.js') }}"></script>
 <script src="https://unpkg.com/react@15/dist/react{% if not config.DEBUG %}.min{% endif %}.js"></script>
 <script src="https://unpkg.com/react-dom@15/dist/react-dom{% if not config.DEBUG %}.min{% endif %}.js"></script>
-<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
 <script src="{{ url_for('static', filename='js/build/common.js') }}"></script>
 <script src="{{ url_for('static', filename='js/build/Hubs.js') }}"></script>
 {% endblock %}

From 76b462461bf63f4cfdfae695792ebb962d6d5d61 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 02 2017 15:27:34 +0000
Subject: [PATCH 963/1001] Add the new and reworked React UI


---

diff --git a/hubs/static/client/.babelrc b/hubs/static/client/.babelrc
index 25043d0..aa30d85 100644
--- a/hubs/static/client/.babelrc
+++ b/hubs/static/client/.babelrc
@@ -1,5 +1,10 @@
 {
-  "presets" : ["es2015", "react"],
-  "plugins": ["syntax-dynamic-import"]
+  "presets" : [["es2015", {"modules": false}], "react"],
+  "plugins": ["syntax-dynamic-import", "transform-object-rest-spread"],
+  "env": {
+    "test": {
+      "plugins": ["transform-es2015-modules-commonjs", "dynamic-import-node", "transform-object-rest-spread"]
+    }
+  }
 }
 
diff --git a/hubs/static/client/.eslintrc.json b/hubs/static/client/.eslintrc.json
index 86fbafe..2fe5df5 100644
--- a/hubs/static/client/.eslintrc.json
+++ b/hubs/static/client/.eslintrc.json
@@ -1,12 +1,20 @@
 {
   "parser": "babel-eslint",
+  "env": {
+    "browser": true,
+    "node": true,
+    "jquery": true
+  },
   "plugins": [
     "react"
   ],
   "rules": {
-    "arrow-body-style": "off",
-    "func-names": "off",
-    "react/prefer-stateless-function": "off",
     "react/prop-types": "off"
-  }
+  },
+  "parserOptions": {
+    "ecmaFeatures": {
+      "jsx": true
+    }
+  },
+  "extends": ["plugin:react/recommended"]
 }
diff --git a/hubs/static/client/__mocks__/fileMock.js b/hubs/static/client/__mocks__/fileMock.js
new file mode 100644
index 0000000..7275f13
--- /dev/null
+++ b/hubs/static/client/__mocks__/fileMock.js
@@ -0,0 +1,2 @@
+// http://facebook.github.io/jest/docs/en/webpack.html
+module.exports = 'test-file-stub';
diff --git a/hubs/static/client/__mocks__/styleMock.js b/hubs/static/client/__mocks__/styleMock.js
new file mode 100644
index 0000000..6a99daa
--- /dev/null
+++ b/hubs/static/client/__mocks__/styleMock.js
@@ -0,0 +1,2 @@
+// http://facebook.github.io/jest/docs/en/webpack.html
+module.exports = {};
diff --git a/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js b/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js
new file mode 100644
index 0000000..2d48f90
--- /dev/null
+++ b/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js
@@ -0,0 +1,198 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import SimpleWidgetConfig from '../SimpleWidgetConfig';
+import WidgetSelectDialog from './WidgetSelectDialog';
+import Modal from '../Modal';
+import { getAvailableWidgets } from '../../core/actions/widgets';
+import { addWidget } from '../../core/actions/widget';
+import {
+  makeLoadable,
+  makeLoadingComponent
+} from '../../core/utils';
+
+
+class AddWidgetDialog extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      selectedWidget: null,
+      tempSelectedWidget: null, // only track the select dropdown state
+      widgetConfig: {visibility: "public"},
+    };
+    this.handleSelectClicked = this.handleSelectClicked.bind(this);
+    this.handleAddClicked = this.handleAddClicked.bind(this);
+    this.handleWidgetSelectChanged = this.handleWidgetSelectChanged.bind(this);
+    this.setWidgetConfig = this.setWidgetConfig.bind(this);
+  }
+
+  componentDidMount() {
+    this.props.dispatch(getAvailableWidgets());
+  }
+
+  componentDidUpdate(prevProps, prevState) {
+    // Select the first available widget by default.
+    const widgets = this.props.availableWidgets[this.props.position];
+    if (widgets.length > 0 && !this.state.tempSelectedWidget) {
+      this.setState({tempSelectedWidget: widgets[0]});
+    }
+  }
+
+  handleWidgetSelectChanged(e) {
+    this.setState({tempSelectedWidget: e.target.value});
+  }
+
+  setWidgetConfig(name, value) {
+    this.setState((prevState, props) => {
+      prevState.widgetConfig[name] = value;
+      return {widgetConfig: prevState.widgetConfig};
+    });
+  }
+
+  handleSelectClicked(e) {
+    e.preventDefault();
+    this.setState((prevState, props) => {
+      let selectedName = prevState.tempSelectedWidget,
+          selectedWidget = this.props.availableWidgets.byName[selectedName],
+          widgetConfig = {};
+      selectedWidget.params.forEach((param) => {
+        widgetConfig[param.name] = param.default;
+      });
+      return { selectedWidget, widgetConfig };
+    });
+  }
+
+  handleAddClicked(e) {
+    e.preventDefault();
+    this.props.dispatch(addWidget(
+      this.state.selectedWidget.name,
+      this.state.widgetConfig,
+      this.props.position)
+    );
+    this.props.handleDialogCloseClicked(e);
+  }
+
+  render() {
+    const widgets = this.props.availableWidgets[this.props.position].map(
+      (name) => (this.props.availableWidgets.byName[name])
+    );
+    let title = "Add a new widget",
+        contents, submitButton;
+
+    if (this.props.isLoading) {
+      contents = (
+        <p className="text-muted">Loading...</p>
+        );
+      submitButton = (
+        <button
+          type="button"
+          className="btn btn-primary"
+          disabled={true}
+          >
+          Loading...
+        </button>
+      );
+
+    } else if (this.state.selectedWidget === null) {
+      // First step: select the widget
+      contents = (
+        <WidgetSelectDialog
+          availableWidgets={widgets}
+          handleWidgetSelectChanged={this.handleWidgetSelectChanged}
+          selectedWidgetName={this.state.tempSelectedWidget}
+          selectedVisibility={this.state.widgetConfig.visibility}
+          setConfig={this.setWidgetConfig}
+          showVisibilitySelect={this.props.showVisibilitySelect}
+          />
+      );
+      submitButton = (
+        <button
+          type="button"
+          className="btn btn-primary ml-3"
+          onClick={this.handleSelectClicked}
+          >
+          Select widget
+        </button>
+      );
+
+    } else {
+      // Second step: configure the widget
+      title = "Adding widget " + this.state.selectedWidget.label;
+      if (this.state.selectedWidget.isReact) {
+        const AsyncComponent = makeLoadable(
+          () => import(`../../widgets/${this.state.selectedWidget.name}/Config`),
+          makeLoadingComponent(
+            "Loading widget configuration...",
+            "Sorry, there was a problem loading the widget configuration."
+          )
+        );
+        contents = (
+          <AsyncComponent
+            widget={this.state.selectedWidget}
+            values={this.state.widgetConfig}
+            setConfig={this.setWidgetConfig}
+            />
+        );
+      } else {
+        contents = (
+          <SimpleWidgetConfig
+            widget={this.state.selectedWidget}
+            values={this.state.widgetConfig}
+            setConfig={this.setWidgetConfig}
+            />
+        );
+      }
+      submitButton = (
+        <button
+          type="button"
+          className="btn btn-primary ml-3"
+          onClick={this.handleAddClicked}
+          >
+          Add widget
+        </button>
+      );
+    }
+
+    const footer = (
+      <div className="d-flex justify-content-end w-100">
+        <button
+          type="button"
+          className="btn btn-secondary"
+          onClick={this.props.handleDialogCloseClicked}
+          >
+          Close
+        </button>
+        {submitButton}
+      </div>
+    );
+
+    return (
+      <Modal
+        onCloseClicked={this.props.handleDialogCloseClicked}
+        isLarge={this.state.selectedWidget && this.state.selectedWidget.isReact}
+        title={title}
+        footer={footer}
+        >
+        {contents}
+      </Modal>
+    );
+  }
+}
+AddWidgetDialog.propTypes = {
+  position: PropTypes.string.isRequired,
+  handleDialogCloseClicked: PropTypes.func,
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    availableWidgets: state.entities.availableWidgets,
+    isLoading: state.entities.availableWidgets.isLoading,
+    showVisibilitySelect: (
+      state.entities.hub.config.visibility === "preview"
+    ),
+  }
+};
+
+export default connect(mapStateToProps)(AddWidgetDialog);
diff --git a/hubs/static/client/app/components/AddWidget/WidgetSelectDialog.js b/hubs/static/client/app/components/AddWidget/WidgetSelectDialog.js
new file mode 100644
index 0000000..9577e71
--- /dev/null
+++ b/hubs/static/client/app/components/AddWidget/WidgetSelectDialog.js
@@ -0,0 +1,53 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import VisibilitySelect from '../VisibilitySelect';
+
+
+export default class WidgetSelectDialog extends React.Component {
+
+  propTypes: {
+    availableWidgets: PropTypes.array.isRequired,
+    showVisibilitySelect: PropTypes.bool,
+    handleWidgetSelectChanged: PropTypes.func.isRequired,
+    selectedWidgetName: PropTypes.string.isRequired,
+    selectedVisibility: PropTypes.string.isRequired,
+    setConfig: PropTypes.func.isRequired,
+  }
+
+  render() {
+    const options = this.props.availableWidgets.map((widget) => {
+      return (
+        <option
+          key={widget.name}
+          value={widget.name}
+          >
+          {widget.label}
+        </option>
+      );
+    });
+    return (
+      <div>
+        <fieldset className="form-group">
+          { this.props.showVisibilitySelect &&
+            <label htmlFor="widgetname">Widget name:</label>
+          }
+          <select
+            className="form-control"
+            name="widgetname"
+            onChange={this.props.handleWidgetSelectChanged}
+            value={this.props.selectedWidgetName || ""}
+            >
+            {options}
+          </select>
+        </fieldset>
+        { this.props.showVisibilitySelect &&
+          <VisibilitySelect
+            selectedVisibility={this.props.selectedVisibility}
+            setConfig={this.props.setConfig}
+            />
+        }
+      </div>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/AddWidget/index.js b/hubs/static/client/app/components/AddWidget/index.js
new file mode 100644
index 0000000..18c3455
--- /dev/null
+++ b/hubs/static/client/app/components/AddWidget/index.js
@@ -0,0 +1,75 @@
+import React from 'react';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import PropTypes from 'prop-types';
+import AddWidgetDialog from './AddWidgetDialog';
+
+
+const messages = defineMessages({
+  button: {
+    id: "hubs.core.widgets.add.button",
+    defaultMessage: "Add a widget",
+  },
+});
+
+
+class AddWidgetButton extends React.Component {
+
+  render() {
+    return (
+      <div className='widget row AddWidgetButton'>
+        <button
+          className="btn btn-lg btn-secondary w-100"
+          onClick={this.props.handleClicked}
+          >
+          <i className="fa fa-plus mr-2" aria-hidden="true"></i>
+          <FormattedMessage {...messages.button} />
+        </button>
+      </div>
+    );
+  }
+}
+
+
+export default class AddWidget extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      isDialogOpen: false,
+    };
+    this.handleOpenClicked = this.handleOpenClicked.bind(this);
+    this.handleCloseClicked = this.handleCloseClicked.bind(this);
+  }
+
+  handleOpenClicked(e) {
+    e.preventDefault();
+    this.setState({
+      isDialogOpen: true,
+    });
+  }
+
+  handleCloseClicked(e) {
+    if (e) { e.preventDefault(); }
+    this.setState({isDialogOpen: false});
+  }
+
+  render() {
+    return (
+      <div>
+        <AddWidgetButton
+          handleClicked={this.handleOpenClicked}
+          />
+        { this.state.isDialogOpen &&
+          <AddWidgetDialog
+            position={this.props.position}
+            handleDialogCloseClicked={this.handleCloseClicked}
+            />
+        }
+      </div>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/components/CobWeb/archived.png b/hubs/static/client/app/components/CobWeb/archived.png
new file mode 100644
index 0000000..0084328
Binary files /dev/null and b/hubs/static/client/app/components/CobWeb/archived.png differ
diff --git a/hubs/static/client/app/components/CobWeb/cobweb.png b/hubs/static/client/app/components/CobWeb/cobweb.png
new file mode 100644
index 0000000..4d94b12
Binary files /dev/null and b/hubs/static/client/app/components/CobWeb/cobweb.png differ
diff --git a/hubs/static/client/app/components/CobWeb/index.js b/hubs/static/client/app/components/CobWeb/index.js
new file mode 100644
index 0000000..65b807a
--- /dev/null
+++ b/hubs/static/client/app/components/CobWeb/index.js
@@ -0,0 +1,34 @@
+import React from 'react';
+import TimeAgo from 'react-timeago';
+//import './cobweb.css';
+import ArchivedIcon from './archived.png';
+import CobWebIcon from './cobweb.png';
+
+
+export default class CobWeb extends React.Component {
+
+  render() {
+    let icon = null, msg = null;
+    if (this.props.cause == "archived") {
+        icon = ArchivedIcon;
+        msg = "This hub has been archived and locked.";
+    } else {
+        icon = CobWebIcon;
+        msg = (
+            <span>
+                <span>Cobweb alert!  This hub was last active </span>
+                <TimeAgo date={this.props.mtime} />
+            </span>
+            );
+    }
+    return (
+      <div className="CobWeb media mb-3">
+        <img className="d-flex align-self-center mr-3 square-32" src={icon} />
+        <div className="media-body">
+          {msg}
+        </div>
+      </div>
+    );
+  }
+}
+
diff --git a/hubs/static/client/app/components/CompletionInput.css b/hubs/static/client/app/components/CompletionInput.css
new file mode 100644
index 0000000..1628fe3
--- /dev/null
+++ b/hubs/static/client/app/components/CompletionInput.css
@@ -0,0 +1,36 @@
+.CompletionInput {
+  position: relative;
+}
+
+.CompletionInput .react-autosuggest__suggestions-container {
+  position: absolute;
+  width: 100%;
+  z-index: 10;
+}
+
+.CompletionInput .react-autosuggest__suggestions-list {
+  list-style: none;
+  padding: 0.3em 0.8em;
+  background-color: #fafafa;
+  border-bottom-left-radius: .25rem;
+  border-bottom-right-radius: .25rem;
+  border: 1px solid #ccc;
+  border-top: none;
+  text-align: left;
+}
+
+.CompletionInput .react-autosuggest__suggestion {
+  cursor: pointer;
+}
+
+.CompletionInput .react-autosuggest__container--open input {
+  border-bottom-left-radius: 0px;
+  border-bottom-right-radius: 0px;
+}
+
+.CompletionInput .SpinnerCircle {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+}
diff --git a/hubs/static/client/app/components/CompletionInput.js b/hubs/static/client/app/components/CompletionInput.js
new file mode 100644
index 0000000..a90cd07
--- /dev/null
+++ b/hubs/static/client/app/components/CompletionInput.js
@@ -0,0 +1,144 @@
+import React from 'react';
+import Autosuggest from 'react-autosuggest';
+import Spinner from "./Spinner";
+import "./CompletionInput.css";
+
+
+export default class CompletionInput extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      value: "",
+      suggestions: [],
+      isLoading: false
+    }
+    this.resultsDomNodeStyle = {
+      position: "absolute",
+      width: "auto"
+    }
+    this.queryTimeout = null;
+    this.handleChange = this.handleChange.bind(this);
+    this.handleSuggestionSelected = this.handleSuggestionSelected.bind(this);
+    this.handleSuggestionsFetchRequested = this.handleSuggestionsFetchRequested.bind(this);
+    this.handleSuggestionsClearRequested = this.handleSuggestionsClearRequested.bind(this);
+    this.loadFromServer = this.loadFromServer.bind(this);
+  }
+
+  componentWillUnmount() {
+    if (this.serverRequest) { this.serverRequest.abort(); }
+  }
+
+  handleChange(e, {newValue}) {
+    this.setState({
+      value: newValue
+    });
+    // Transmit a "fake" changed event to the parent, if asked to.
+    if (this.props.onChange) {
+      const mockedEvent = {
+        type: 'change',
+        target: {
+          type: 'input',
+          name: this.props.name || "completioninput",
+          value: newValue,
+        },
+      }
+      this.props.onChange(mockedEvent, newValue);
+    }
+  }
+
+  handleSuggestionSelected(e, {suggestion}) {
+    if (this.props.onSelect) {
+      this.props.onSelect(suggestion);
+    }
+  }
+
+  // Autosuggest will call this function every time you need to update
+  // suggestions.
+  handleSuggestionsFetchRequested({value}) {
+    var inputValue = value.trim().toLowerCase();
+    if (this.queryTimeout !== null) {
+      window.clearTimeout(this.queryTimeout);
+    }
+    if (this.serverRequest) { this.serverRequest.abort(); }
+    if (inputValue.length === 0) {
+      this.setState({
+        suggestions: [],
+        isLoading: false
+      });
+    } else {
+      this.queryTimeout = window.setTimeout(
+        this.loadFromServer, this.props.queryDelay, inputValue);
+    }
+  }
+
+  loadFromServer(value) {
+    this.setState({isLoading: true});
+    this.serverRequest = $.ajax({
+      url: this.props.url,
+      method: 'GET',
+      data: {q: value},
+      dataType: 'json',
+      cache: false,
+      success: function(result) {
+        var suggestions = result.data;
+        if (this.props.filterResults) {
+          suggestions = suggestions.filter(this.props.filterResults);
+        }
+        this.setState({suggestions: suggestions});
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.url, status, err.toString());
+      }.bind(this),
+      complete: function(xhr, status) {
+        this.setState({isLoading: false});
+      }.bind(this)
+    });
+  }
+
+  // Autosuggest will call this function every time you need to clear
+  // suggestions.
+  handleSuggestionsClearRequested() {
+    this.setState({
+      suggestions: []
+    });
+  }
+
+  render() {
+    // When a suggestion is clicked, this method will return the value to
+    // populate the input with.
+    const getSuggestionValue = (suggestion) => (suggestion);
+    // Render suggestions.
+    const renderSuggestion = (suggestion) => (suggestion);
+    // Autosuggest will pass through all these props to the input element.
+    const inputProps = {
+      className: "form-control",
+      value: this.state.value,
+      onChange: this.handleChange,
+    };
+    Object.assign(inputProps, this.props.inputProps);
+
+    // Render the widget.
+    return (
+      <div className="CompletionInput">
+        <Autosuggest
+          suggestions={this.state.suggestions}
+          onSuggestionsFetchRequested={this.handleSuggestionsFetchRequested}
+          onSuggestionsClearRequested={this.handleSuggestionsClearRequested}
+          onSuggestionSelected={this.handleSuggestionSelected}
+          getSuggestionValue={this.props.getSuggestionValue || getSuggestionValue}
+          renderSuggestion={this.props.renderSuggestion || renderSuggestion}
+          inputProps={inputProps}
+        />
+        {this.state.isLoading &&
+          <Spinner circle={true} />
+        }
+      </div>
+    );
+  }
+
+}
+CompletionInput.defaultProps = {
+    inputProps: {},
+    queryDelay: 800,
+};
diff --git a/hubs/static/client/app/components/CompletionInput.jsx b/hubs/static/client/app/components/CompletionInput.jsx
deleted file mode 100644
index a97fc7f..0000000
--- a/hubs/static/client/app/components/CompletionInput.jsx
+++ /dev/null
@@ -1,146 +0,0 @@
-import React from 'react';
-import Autosuggest from 'react-autosuggest';
-
-
-export default class CompletionInput extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      value: "",
-      suggestions: [],
-      loading: false
-    }
-    this.resultsDomNodeStyle = {
-      position: "absolute",
-      width: "auto"
-    }
-    this.queryTimeout = null;
-    this.onResultClick = this.onResultClick.bind(this);
-    this.onChange = this.onChange.bind(this);
-    this.onSuggestionsFetchRequested = this.onSuggestionsFetchRequested.bind(this);
-    this.onSuggestionsClearRequested = this.onSuggestionsClearRequested.bind(this);
-    this.loadFromServer = this.loadFromServer.bind(this);
-  }
-
-  componentWillUnmount() {
-    if (this.serverRequest) { this.serverRequest.abort(); }
-  }
-
-  onResultClick(result) {
-    this.setState({
-      results: [],
-      value: result
-    });
-  }
-
-  onChange(e, {newValue}) {
-    this.setState({
-      value: newValue
-    });
-    // Transmit a "fake" changed event to the parent, if asked to.
-    if (this.props.onChange) {
-      const mockedEvent = {
-        type: 'change',
-        target: {
-          type: 'input',
-          name: this.props.name,
-          value: newValue,
-        },
-      }
-      this.props.onChange(mockedEvent);
-    }
-  }
-
-  // Autosuggest will call this function every time you need to update
-  // suggestions.
-  onSuggestionsFetchRequested({value}) {
-    var inputValue = value.trim().toLowerCase();
-    if (this.queryTimeout !== null) {
-      window.clearTimeout(this.queryTimeout);
-    }
-    if (this.serverRequest) { this.serverRequest.abort(); }
-    if (inputValue.length === 0) {
-      this.setState({
-        suggestions: [],
-        loading: false
-      });
-    } else {
-      this.queryTimeout = window.setTimeout(
-        this.loadFromServer, this.props.queryDelay, inputValue);
-    }
-  }
-
-  loadFromServer(value) {
-    this.setState({loading: true});
-    this.serverRequest = $.ajax({
-      url: this.props.url,
-      method: 'GET',
-      data: {q: value},
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        var suggestions = data.results;
-        if (this.props.filterResults) {
-          suggestions = suggestions.filter(this.props.filterResults);
-        }
-        this.setState({suggestions: suggestions});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this),
-      complete: function(xhr, status) {
-        this.setState({loading: false});
-      }.bind(this)
-    });
-  }
-
-  // Autosuggest will call this function every time you need to clear
-  // suggestions.
-  onSuggestionsClearRequested() {
-    this.setState({
-      suggestions: []
-    });
-  }
-
-  render() {
-    // When a suggestion is clicked, this method will return the value to
-    // populate the input with.
-    const getSuggestionValue = suggestion => suggestion;
-    // Render suggestions.
-    const renderSuggestion = suggestion => suggestion;
-    // Autosuggest will pass through all these props to the input element.
-    const inputProps = {
-      className: "form-control",
-      value: this.state.value,
-      onChange: this.onChange,
-    };
-    Object.assign(inputProps, this.props.inputProps);
-
-    // Render the widget.
-    return (
-      <div className="completion-input">
-        <Autosuggest
-          suggestions={this.state.suggestions}
-          onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
-          onSuggestionsClearRequested={this.onSuggestionsClearRequested}
-          getSuggestionValue={getSuggestionValue}
-          renderSuggestion={renderSuggestion}
-          inputProps={inputProps}
-        />
-        <div
-          className="loading-circle"
-          style={this.state.loading ? {display: "block"} : {}}
-          ></div>
-      </div>
-    );
-  }
-
-}
-CompletionInput.defaultProps = {
-    inputProps: {},
-    queryDelay: 800,
-};
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/EditModeButton.css b/hubs/static/client/app/components/EditModeButton.css
new file mode 100644
index 0000000..69930aa
--- /dev/null
+++ b/hubs/static/client/app/components/EditModeButton.css
@@ -0,0 +1,3 @@
+.EditModeButton {
+    margin: 0.25rem 0.5rem
+}
diff --git a/hubs/static/client/app/components/EditModeButton.js b/hubs/static/client/app/components/EditModeButton.js
new file mode 100644
index 0000000..70eb64d
--- /dev/null
+++ b/hubs/static/client/app/components/EditModeButton.js
@@ -0,0 +1,74 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import { setEditMode } from "../core/actions/widgets";
+import "./EditModeButton.css";
+
+
+const messages = defineMessages({
+  save: {
+    id: "hubs.core.EditModeButton.save",
+    defaultMessage: "Save changes",
+  },
+  edit: {
+    id: "hubs.core.EditModeButton.edit",
+    defaultMessage: "Edit page layout",
+  },
+});
+
+
+class EditModeButton extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.handleClicked = this.handleClicked.bind(this);
+  }
+
+  handleClicked(e) {
+    e.preventDefault();
+    this.props.dispatch(setEditMode(!this.props.editMode));
+  }
+
+  render() {
+    if (this.props.editMode) {
+      return (
+        <button
+          className="EditModeButton btn btn-sm btn-primary"
+          onClick={this.handleClicked}
+          >
+          <i className="fa fa-download mr-2" aria-hidden="true"></i>
+          <FormattedMessage {...messages.save} />
+        </button>
+      );
+    } else {
+      return (
+        <button
+          className="EditModeButton btn btn-sm btn-secondary"
+          onClick={this.handleClicked}
+          >
+          <i className="fa fa-pencil mr-2" aria-hidden="true"></i>
+          <FormattedMessage {...messages.edit} />
+        </button>
+      );
+    }
+  }
+}
+EditModeButton.propTypes = {
+  editMode: PropTypes.bool,
+}
+EditModeButton.defaultProps = {
+  editMode: false
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    editMode: state.ui.widgetsEditMode
+  }
+};
+
+export default connect(mapStateToProps)(EditModeButton);
diff --git a/hubs/static/client/app/components/FlashMessages/FlashMessage.js b/hubs/static/client/app/components/FlashMessages/FlashMessage.js
new file mode 100644
index 0000000..02b903d
--- /dev/null
+++ b/hubs/static/client/app/components/FlashMessages/FlashMessage.js
@@ -0,0 +1,54 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+
+const MSG_TYPES = ["success", "info", "warning", "danger"];
+
+
+export default class FlashMessage extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.handleClose = this.handleClose.bind(this);
+  }
+
+  handleClose(e) {
+    this.props.onClose(this.props.index);
+  }
+
+  render() {
+    let cssClass = this.props.type;
+    if (cssClass === "error") {
+      cssClass = "danger";
+    }
+    if (!MSG_TYPES.includes(cssClass)) {
+      cssClass = "info";
+    }
+    return (
+      <div
+        className={`alert alert-dismissible alert-${cssClass}`}
+        role="alert"
+        >
+        <button
+          type="button"
+          className="close"
+          aria-label="Close"
+          name={this.props.index}
+          onClick={this.handleClose}
+          >
+          <span aria-hidden="true">&times;</span>
+        </button>
+        {this.props.message}
+      </div>
+    );
+  }
+}
+FlashMessage.propTypes = {
+  message: PropTypes.string.isRequired,
+  index: PropTypes.number.isRequired,
+  type: PropTypes.string,
+  onClose: PropTypes.func,
+}
+FlashMessage.defaultProps = {
+  type: "info",
+}
diff --git a/hubs/static/client/app/components/FlashMessages/FlashMessages.css b/hubs/static/client/app/components/FlashMessages/FlashMessages.css
new file mode 100644
index 0000000..566132f
--- /dev/null
+++ b/hubs/static/client/app/components/FlashMessages/FlashMessages.css
@@ -0,0 +1,6 @@
+.FlashMessages {
+  /* place it on top so they cover content and can be clicked */
+  position: absolute;
+  width: 100%;
+  z-index: 3;
+}
diff --git a/hubs/static/client/app/components/FlashMessages/FlashMessagesList.js b/hubs/static/client/app/components/FlashMessages/FlashMessagesList.js
new file mode 100644
index 0000000..851da6a
--- /dev/null
+++ b/hubs/static/client/app/components/FlashMessages/FlashMessagesList.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import FlashMessage from './FlashMessage';
+import "./FlashMessages.css";
+
+
+export default class FlashMessagesList extends React.Component {
+
+  render() {
+    if (this.props.messages.length === 0) {
+      return null;
+    }
+    let messages = this.props.messages.map(({msg, type}, index) => {
+      return (
+        <FlashMessage
+          key={index}
+          message={msg}
+          type={type}
+          index={index}
+          onClose={this.props.onClose}
+          />
+      );
+    });
+    return (
+      <div className="FlashMessages row pt-2">
+        <div className="col-md-6 offset-md-3">
+          {messages}
+        </div>
+      </div>
+    );
+  }
+}
+FlashMessagesList.propTypes = {
+  messages: PropTypes.array,
+  onClose: PropTypes.func,
+}
+FlashMessagesList.defaultProps = {
+  messages: [],
+}
diff --git a/hubs/static/client/app/components/FlashMessages/index.js b/hubs/static/client/app/components/FlashMessages/index.js
new file mode 100644
index 0000000..278af61
--- /dev/null
+++ b/hubs/static/client/app/components/FlashMessages/index.js
@@ -0,0 +1,23 @@
+import { connect } from 'react-redux';
+import { closeFlashMessage } from '../../core/actions/flashMessages';
+import FlashMessagesList from "./FlashMessagesList";
+
+
+const mapStateToProps = (state) => {
+  return {
+    messages: state.flashMessages
+  }
+};
+
+const mapDispatchToProps = (dispatch) => {
+  return {
+    onClose: (id) => {
+      dispatch(closeFlashMessage(id))
+    }
+  }
+};
+
+export default connect(
+  mapStateToProps,
+  mapDispatchToProps
+)(FlashMessagesList);
diff --git a/hubs/static/client/app/components/HubConfig/HubConfig.css b/hubs/static/client/app/components/HubConfig/HubConfig.css
new file mode 100644
index 0000000..d676968
--- /dev/null
+++ b/hubs/static/client/app/components/HubConfig/HubConfig.css
@@ -0,0 +1,46 @@
+.HubConfig {
+    display: inline;
+    margin: 0.25rem 0.5rem;
+    text-align: left;
+}
+.HubConfigDialog .modal-title {
+  line-height: 1;
+}
+
+.HubConfigDialog .nav {
+  border: 0;
+  background-color: #eee;
+}
+
+.HubConfigDialog .nav-tabs .nav-item {
+  float: none;
+  margin-bottom: 0;
+}
+.HubConfigDialog .nav-tabs .nav-link {
+  border: 0;
+}
+
+.HubConfigDialog .modal-body {
+  padding: 0;
+}
+.HubConfigDialog .modal-body h3 {
+  margin-bottom: 1em;
+}
+.HubConfigDialog .modal-body label {
+  font-size: 115%;
+}
+.HubConfigDialog .modal-body .tab-content {
+  padding: 1em;
+  padding-bottom: 2em;
+}
+
+@media (min-width: 768px) {
+  /* the menu is on the left */
+  .HubConfigDialog .nav .nav-item {
+    margin-bottom: 0;
+  }
+  .HubConfigDialog .nav .nav-link {
+    border-radius: 0.25rem 0 0 0.25rem;
+  }
+}
+
diff --git a/hubs/static/client/app/components/HubConfig/HubConfigDialog.js b/hubs/static/client/app/components/HubConfig/HubConfigDialog.js
new file mode 100644
index 0000000..6d00e05
--- /dev/null
+++ b/hubs/static/client/app/components/HubConfig/HubConfigDialog.js
@@ -0,0 +1,129 @@
+import React from 'react';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import PropTypes from 'prop-types';
+import GeneralPanel from './HubConfigPanelGeneral';
+import UserPanel from './HubConfigPanelUser';
+import ChatPanel from './HubConfigPanelChat';
+import NotImplementedPanel from './HubConfigPanelNotImpl';
+import Modal from '../../components/Modal';
+import TabSet from '../../components/TabSet';
+
+
+const messages = defineMessages({
+  title: {
+    id: "hubs.core.config.title",
+    defaultMessage: "Hub settings",
+  },
+  general: {
+    id: "hubs.core.config.general",
+    defaultMessage: "General",
+  },
+  owners: {
+    id: "hubs.core.config.owners",
+    defaultMessage: "Owners",
+  },
+  members: {
+    id: "hubs.core.config.members",
+    defaultMessage: "Members",
+  },
+  chat: {
+    id: "hubs.core.config.chat",
+    defaultMessage: "Chat",
+  },
+  other: {
+    id: "hubs.core.config.other",
+    defaultMessage: "Other",
+  },
+  close: {
+    id: "hubs.core.config.close",
+    defaultMessage: "Close",
+  },
+  save_changes: {
+    id: "hubs.core.config.save_changes",
+    defaultMessage: "Save changes",
+  },
+});
+
+
+
+export default class HubConfigDialog extends React.Component {
+
+  render() {
+    const title = (
+      <FormattedMessage {...messages.title} />
+    );
+    const footer = (
+      <div className="d-flex justify-content-end w-100">
+        <button
+          type="button"
+          className="btn btn-secondary ml-3"
+          onClick={this.props.onCloseClicked}
+          >
+          <FormattedMessage {...messages.close} />
+        </button>
+        <button
+          type="button"
+          className="btn btn-primary ml-3"
+          onClick={this.props.onSaveClicked}
+          >
+          <FormattedMessage {...messages.save_changes} />
+        </button>
+      </div>
+    );
+
+    return (
+      <Modal
+        onCloseClicked={this.props.onCloseClicked}
+        isLarge={true}
+        title={title}
+        footer={footer}
+        cssClass="HubConfigDialog"
+        >
+        <TabSet
+          tabWrapperProps={{className: "row pt-0"}}
+          tabListClass="flex-md-column justify-content-center justify-content-md-start col-md-3 pt-2 pt-md-3 pb-md-4 pr-md-0 pl-md-2"
+          tabLinkClass="my-md-2"
+          tabContentClass="col-md-9 p-3 pb-4"
+          >
+          <GeneralPanel
+            hubConfig={this.props.hubConfig}
+            globalConfig={this.props.globalConfig}
+            tabTitle={<FormattedMessage {...messages.general} />}
+            handleChange={this.props.onConfigChange}
+            />
+          <UserPanel
+            users={this.props.users.owner}
+            globalConfig={this.props.globalConfig}
+            role="owner"
+            handleChange={this.props.onUserChange}
+            tabTitle={<FormattedMessage {...messages.owners} />}
+            urls={this.props.urls}
+            currentUser={this.props.currentUser}
+            />
+          <UserPanel
+            users={this.props.users.member}
+            globalConfig={this.props.globalConfig}
+            role="member"
+            handleChange={this.props.onUserChange}
+            tabTitle={<FormattedMessage {...messages.members} />}
+            urls={this.props.urls}
+            currentUser={this.props.currentUser}
+            />
+          <ChatPanel
+            hubConfig={this.props.hubConfig}
+            globalConfig={this.props.globalConfig}
+            tabTitle={<FormattedMessage {...messages.chat} />}
+            handleChange={this.props.onConfigChange}
+            />
+          <NotImplementedPanel
+            tabTitle={<FormattedMessage {...messages.other} />}
+            />
+        </TabSet>
+      </Modal>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/components/HubConfig/HubConfigPanelChat.js b/hubs/static/client/app/components/HubConfig/HubConfigPanelChat.js
new file mode 100644
index 0000000..f756e9d
--- /dev/null
+++ b/hubs/static/client/app/components/HubConfig/HubConfigPanelChat.js
@@ -0,0 +1,103 @@
+import React from 'react';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+
+
+const messages = defineMessages({
+  title: {
+    id: "hubs.core.config.chat.title",
+    defaultMessage: "Chat Settings",
+  },
+  intro_1: {
+    id: "hubs.core.config.chat.intro1",
+    defaultMessage: (
+      "If your team or project has an IRC channel associated with it, you "
+     +"can connect this hub to it via the Hubs chat widget."
+     ),
+  },
+  intro_2: {
+    id: "hubs.core.config.chat.intro2",
+    defaultMessage: "Please indicate your team's IRC channel below:",
+  },
+  channel_name: {
+    id: "hubs.core.config.chat.channel_name",
+    defaultMessage: "Channel name",
+  },
+  example: {
+    id: "hubs.core.config.chat.example",
+    defaultMessage: "Example:",
+  },
+  network: {
+    id: "hubs.core.config.chat.network",
+    defaultMessage: "IRC network",
+  },
+});
+
+
+export default class ChatPanel extends React.Component {
+
+  render() {
+    var networks = [],
+        channel = "#",
+        stillLoading = (
+          typeof this.props.hubConfig.chat_channel === "undefined"
+        );
+
+    if (this.props.hubConfig.chat_channel) {
+      channel = "#" + this.props.hubConfig.chat_channel.replace(/^#*/, "");
+    }
+
+    if (this.props.globalConfig.chat_networks) {
+      networks = this.props.globalConfig.chat_networks.map(
+        function(network, index) {
+          return (
+            <option value={network.domain} key={network.domain}>
+              {network.name} - {network.domain}
+            </option>
+          );
+        }.bind(this)
+      );
+    }
+
+    return (
+      <form onSubmit={(e) => {e.preventDefault();}}>
+        <FormattedMessage {...messages.title} tagName="h3" />
+        <FormattedMessage {...messages.intro_1} tagName="p" />
+        <FormattedMessage {...messages.intro_2} tagName="p" />
+        <div className="form-group">
+          <label htmlFor="hub-settings-chat-channel">
+            <FormattedMessage {...messages.channel_name} />
+          </label>
+          <input
+            type="text" className="form-control" name="chat_channel"
+            id="hub-settings-chat-channel"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={channel}
+            />
+          <p className="form-text text-muted">
+            <FormattedMessage {...messages.example} tagName="strong" />
+            <span className="ml-2">#fedora-devel</span>
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-chat-domain">
+            <FormattedMessage {...messages.network} />
+          </label>
+          <select
+            name="chat_domain" className="form-control"
+            id="hub-settings-chat-domain"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.chat_domain || ""}
+            >
+            {networks}
+          </select>
+        </div>
+      </form>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/components/HubConfig/HubConfigPanelGeneral.js b/hubs/static/client/app/components/HubConfig/HubConfigPanelGeneral.js
new file mode 100644
index 0000000..9e5972a
--- /dev/null
+++ b/hubs/static/client/app/components/HubConfig/HubConfigPanelGeneral.js
@@ -0,0 +1,142 @@
+import React from 'react';
+import {
+  defineMessages,
+  FormattedMessage,
+  FormattedHTMLMessage,
+  } from 'react-intl';
+
+
+const messages = defineMessages({
+  title: {
+    id: "hubs.core.config.general.title",
+    defaultMessage: "General Settings",
+  },
+  intro: {
+    id: "hubs.core.config.general.intro",
+    defaultMessage: "Change your global hub parameters here.",
+  },
+  summary: {
+    id: "hubs.core.config.general.summary",
+    defaultMessage: "Summary",
+  },
+  summary_help: {
+    id: "hubs.core.config.general.summary_help",
+    defaultMessage: "This text will be displayed at the top of the hub.",
+  },
+  left_width: {
+    id: "hubs.core.config.general.left_width",
+    defaultMessage: "Left width",
+  },
+  left_width_help: {
+    id: "hubs.core.config.general.left_width_help",
+    defaultMessage: (
+      "Change the proportions of you hub's columns by setting the width of "
+     +"the left column (the right column's width will be {right_width})."
+      ),
+  },
+  visibility: {
+    id: "hubs.core.config.general.visibility",
+    defaultMessage: "Visibility",
+  },
+  visibility_help: {
+    id: "hubs.core.config.general.visibility_help",
+    defaultMessage: (
+      "Public: the hub is visible to anyone.<br />"
+     +"Private: the hub is only visible to members.<br />"
+     +"Preview: some widgets can be made visible to logged-in users only."
+      ),
+  },
+  avatar: {
+    id: "hubs.core.config.general.avatar",
+    defaultMessage: "Avatar",
+  },
+  avatar_help: {
+    id: "hubs.core.config.general.avatar_help",
+    defaultMessage: "An URL to you hub's main image or logo."
+  },
+});
+
+
+export default class GeneralPanel extends React.Component {
+
+  render() {
+    var stillLoading = (typeof this.props.hubConfig.summary === "undefined");
+    var visibilities = this.props.globalConfig.hub_visibility || [];
+    return (
+      <form onSubmit={(e) => {e.preventDefault();}}>
+        <FormattedMessage {...messages.title} tagName="h3" />
+        <FormattedMessage {...messages.intro} tagName="p" />
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-summary">
+            <FormattedMessage {...messages.summary} />
+          </label>
+          <input
+            type="text" className="form-control" name="summary"
+            id="hub-settings-general-summary"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.summary || ""}
+            />
+          <p className="form-text text-muted">
+            <FormattedMessage {...messages.summary_help} />
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-leftwidth">
+            <FormattedMessage {...messages.left_width} />
+          </label>
+          <input
+            type="number" className="form-control" name="left_width"
+            id="hub-settings-general-leftwidth"
+            disabled={stillLoading}
+            min="1" max="11"
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.left_width || ""}
+            />
+          <p className="form-text text-muted">
+            <FormattedMessage
+              {...messages.left_width_help}
+              values={{right_width: 12 - (this.props.hubConfig.left_width || 8)}}
+              />
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-visibility">
+            <FormattedMessage {...messages.visibility} />
+          </label>
+          <select
+            className="form-control" name="visibility"
+            value={this.props.hubConfig.visibility || ""}
+            onChange={this.props.handleChange}
+            disabled={stillLoading}
+            >
+            {visibilities.map(function(value) {
+              return (
+                <option value={value} key={value}>{value}</option>
+                );
+            })}
+          </select>
+          <p className="form-text text-muted">
+            <FormattedHTMLMessage {...messages.visibility_help} />
+          </p>
+        </div>
+        <div className="form-group">
+          <label htmlFor="hub-settings-general-avatar">
+            <FormattedMessage {...messages.avatar} />
+          </label>
+          <input
+            type="text" className="form-control" name="avatar"
+            id="hub-settings-general-avatar"
+            disabled={stillLoading}
+            onChange={this.props.handleChange}
+            value={this.props.hubConfig.avatar || ""}
+            />
+          <p className="form-text text-muted">
+            <FormattedMessage {...messages.avatar_help} />
+          </p>
+        </div>
+      </form>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/components/HubConfig/HubConfigPanelNotImpl.js b/hubs/static/client/app/components/HubConfig/HubConfigPanelNotImpl.js
new file mode 100644
index 0000000..7ec90c0
--- /dev/null
+++ b/hubs/static/client/app/components/HubConfig/HubConfigPanelNotImpl.js
@@ -0,0 +1,14 @@
+import React from 'react';
+
+
+export default class NotImplementedPanel extends React.Component {
+
+  render() {
+    return (
+      <div>
+        Not implemented yet.
+      </div>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/components/HubConfig/HubConfigPanelUser.js b/hubs/static/client/app/components/HubConfig/HubConfigPanelUser.js
new file mode 100644
index 0000000..c516c19
--- /dev/null
+++ b/hubs/static/client/app/components/HubConfig/HubConfigPanelUser.js
@@ -0,0 +1,229 @@
+import React from 'react';
+import {
+  injectIntl,
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import CompletionInput from '../CompletionInput';
+
+
+const messages = defineMessages({
+  fullname: {
+    id: "hubs.core.config.users.fullname",
+    defaultMessage: "Full name",
+  },
+  username: {
+    id: "hubs.core.config.users.username",
+    defaultMessage: "Username",
+  },
+  change_role: {
+    id: "hubs.core.config.users.change_role",
+    defaultMessage: "Change role",
+  },
+  na: {
+    id: "hubs.core.config.users.na",
+    defaultMessage: "(N/A)",
+  },
+  remove_user: {
+    id: "hubs.core.config.users.remove_user",
+    defaultMessage: "(remove user)",
+  },
+  add_user: {
+    id: "hubs.core.config.users.add_user",
+    defaultMessage: "Add user...",
+  },
+  add: {
+    id: "hubs.core.config.users.add",
+    defaultMessage: "Add",
+  },
+});
+
+
+export default class UserPanel extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      addUser: null,
+      addUserInputContents: "",
+    };
+    this.handleAdd = this.handleAdd.bind(this);
+    this.handleAddChanged = this.handleAddChanged.bind(this);
+    this.handleAddSelected = this.handleAddSelected.bind(this);
+    this.filterSuggestedUsers = this.filterSuggestedUsers.bind(this);
+  }
+
+  handleAdd(e) {
+    e.preventDefault();
+    this.props.handleChange(this.state.addUser, null, this.props.role);
+    this.setState({addUser: null, addUserInputContents: ""});
+  }
+
+  handleAddChanged(e, username) {
+    this.setState({addUserInputContents: username});
+  }
+
+  handleAddSelected(addUser) {
+    this.setState({addUser});
+  }
+
+  filterSuggestedUsers(user) {
+    // Only suggest non-members.
+    return (this.props.users.indexOf(user) === -1);
+  }
+
+  render() {
+    var users = this.props.users.map(function(user) {
+      const locked = (
+        this.props.role === "owner" &&
+        this.props.currentUser.logged_in &&
+        user.username === this.props.currentUser.nickname
+      );
+      return (
+        <UserRow
+          key={user.username}
+          user={user}
+          role={this.props.role}
+          globalConfig={this.props.globalConfig}
+          onChange={this.props.handleChange}
+          locked={locked}
+          />
+        );
+    }.bind(this));
+
+    /*
+    const IntlCompletionInput = injectIntl(function(props) {
+        return (
+          <CompletionInput
+            inputProps={{
+              name: "username",
+              placeholder: props.intl.formatMessage(messages.add_user),
+            }}
+            url={(
+              props.urls.hubConfigSuggestUsers
+              + "?exclude-role=" + props.role
+            )}
+            onChange={this.handleAddInputChange}
+            />
+            );
+    }.bind(this));
+    */
+    const getSuggestionValue = (suggestion) => {
+      return suggestion.username;
+    };
+    const renderSuggestion = (suggestion) => (
+      <span>
+        {suggestion.username}
+        {" "}
+        <small className="text-muted float-right">
+          ({suggestion.fullname})
+        </small>
+      </span>
+    );
+
+    return (
+      <div>
+        <h3>{this.props.tabTitle}</h3>
+        {(this.props.role == "member") &&
+          <div>
+            <p className="text-muted">
+              [Membership requests will be shown here]
+            </p>
+            <hr />
+          </div>
+        }
+        <form
+          className="form-inline mb-3"
+          onSubmit={this.handleAdd}
+          >
+          <div className="form-group">
+            <FormattedMessage {...messages.add_user}>
+              {(message) => (
+                <CompletionInput
+                  inputProps={{
+                    name: "username",
+                    placeholder: message,
+                    value: this.state.addUserInputContents
+                  }}
+                  url={(
+                    this.props.urls.hubConfigSuggestUsers
+                    + "?exclude-role=" + this.props.role
+                  )}
+                  getSuggestionValue={getSuggestionValue}
+                  renderSuggestion={renderSuggestion}
+                  onChange={this.handleAddChanged}
+                  onSelect={this.handleAddSelected}
+                  />
+              )}
+            </FormattedMessage>
+            </div>
+          <button
+            className="btn btn-primary ml-3"
+            disabled={this.props.loading}
+            >
+            <FormattedMessage {...messages.add} />
+          </button>
+        </form>
+        {users.length !== 0 &&
+        <table className="table table-hover table-sm">
+          <thead>
+            <tr>
+              <FormattedMessage {...messages.fullname} tagName="th" />
+              <FormattedMessage {...messages.username} tagName="th" />
+              <FormattedMessage {...messages.change_role} tagName="th" />
+            </tr>
+          </thead>
+          <tbody>
+            {users}
+          </tbody>
+        </table>
+        }
+      </div>
+    );
+  }
+
+}
+
+
+class UserRow extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  handleChange(e) {
+    e.preventDefault();
+    this.props.onChange(this.props.user, this.props.role, e.target.value);
+  }
+
+  render() {
+    return (
+      <tr>
+        <td>{this.props.user.fullname}</td>
+        <td>{this.props.user.username}</td>
+        <td>
+          {this.props.locked ?
+            <FormattedMessage {...messages.na} />
+          :
+            <select
+              name={this.props.user.username}
+              value={this.props.role}
+              className="form-control"
+              onChange={this.handleChange}
+              >
+              {this.props.globalConfig.roles.map(function(role) {
+                return (
+                  <option value={role} key={role}>{role}</option>
+                  );
+              })}
+              <FormattedMessage {...messages.remove_user}>
+                {(value) => ( <option value="">{value}</option> )}
+              </FormattedMessage>
+            </select>
+          }
+        </td>
+      </tr>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/HubConfig/index.js b/hubs/static/client/app/components/HubConfig/index.js
new file mode 100644
index 0000000..8446004
--- /dev/null
+++ b/hubs/static/client/app/components/HubConfig/index.js
@@ -0,0 +1,122 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import { saveHub } from '../../core/actions/hub';
+import HubConfigDialog from './HubConfigDialog';
+import "./HubConfig.css";
+
+
+const messages = defineMessages({
+  button: {
+    id: "hubs.core.config.button",
+    defaultMessage: "Hub settings",
+  },
+});
+
+
+class HubConfig extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      config: null,
+      users: null,
+      isDialogOpen: false,
+    };
+    this.handleConfigChange = this.handleConfigChange.bind(this);
+    this.doUserChange = this.doUserChange.bind(this);
+    this.handleOpenClicked = this.handleOpenClicked.bind(this);
+    this.handleCloseClicked = this.handleCloseClicked.bind(this);
+    this.handleSaveClicked = this.handleSaveClicked.bind(this);
+  }
+
+  handleOpenClicked(e) {
+    e.preventDefault();
+    this.setState({
+      isDialogOpen: true,
+      config: this.props.hub.config,
+      users: this.props.hub.users,
+    });
+  }
+
+  handleCloseClicked(e) {
+    e.preventDefault();
+    this.setState({isDialogOpen: false});
+  }
+
+  handleConfigChange(e) {
+    const name = e.target.name, value = e.target.value;
+    this.setState((prevState, props) => {
+      prevState.config[name] = value;
+      return prevState;
+    });
+  }
+
+  doUserChange(user, oldRole, newRole) {
+    this.setState((prevState, props) => {
+      if (oldRole) {
+        // Remove previous role
+        prevState.users[oldRole] = prevState.users[oldRole].filter(
+          (u) => (u.username !== user.username)
+        );
+      }
+      if (newRole) {
+        prevState.users[newRole].push(user);
+      }
+      return {users: prevState.users};
+    });
+  }
+
+  handleSaveClicked(e) {
+    e.preventDefault();
+    this.props.dispatch(saveHub(this.state.config, this.state.users));
+    this.setState({isDialogOpen: false});
+  }
+
+  render() {
+    const openButton = (
+      <button
+        className="open-button btn btn-sm btn-secondary"
+        onClick={this.handleOpenClicked}
+        >
+        <i className="fa fa-cog mr-2" aria-hidden="true"></i>
+        <FormattedMessage {...messages.button} />
+      </button>
+    );
+    return (
+      <div className="HubConfig">
+        {openButton}
+        {this.state.isDialogOpen &&
+          <HubConfigDialog
+            onCloseClicked={this.handleCloseClicked}
+            onSaveClicked={this.handleSaveClicked}
+            hubConfig={this.state.config}
+            users={this.state.users}
+            globalConfig={this.props.globalConfig}
+            onConfigChange={this.handleConfigChange}
+            onUserChange={this.doUserChange}
+            urls={this.props.urls}
+            currentUser={this.props.currentUser}
+            />
+        }
+      </div>
+    );
+  }
+
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    hub: state.entities.hub,
+    globalConfig: state.globalConfig,
+    urls: state.urls,
+    currentUser: state.currentUser,
+  }
+};
+
+export default connect(mapStateToProps)(HubConfig);
diff --git a/hubs/static/client/app/components/HubHeader.css b/hubs/static/client/app/components/HubHeader.css
new file mode 100644
index 0000000..2407253
--- /dev/null
+++ b/hubs/static/client/app/components/HubHeader.css
@@ -0,0 +1,34 @@
+.HubHeader {
+  font-family: 'Open Sans', sans-serif;
+  /*
+  color: #373a3c;
+  width: 100%;
+  background: #f3f3f3 none repeat scroll 0 0;
+  border-bottom: 1px solid #ddd;
+  padding-bottom: .5rem;
+  */
+}
+
+.HubHeader img.avatar {
+    width: 70px;
+    float: left;
+    margin-right: 15px;
+    display: inline;
+    border: 5px solid #fff;
+}
+
+.HubHeader h2 {
+    font-weight: 500;
+    padding-top: .5rem;
+}
+
+@media (max-width:768px) {
+  .header h2.team {
+    top: 170px !important;
+  }
+}
+
+.HubHeader > .Spinner {
+    position: absolute;
+    left: 1rem;
+}
diff --git a/hubs/static/client/app/components/HubHeader.js b/hubs/static/client/app/components/HubHeader.js
new file mode 100644
index 0000000..509c9d1
--- /dev/null
+++ b/hubs/static/client/app/components/HubHeader.js
@@ -0,0 +1,74 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import Spinner from "./Spinner";
+import HubConfig from './HubConfig';
+import EditModeButton from './EditModeButton';
+import "./HubHeader.css";
+
+
+class HubHeader extends React.Component {
+
+  propTypes: {
+    hub: PropTypes.object.isRequired,
+    isLoading: PropTypes.bool,
+    currentUser: PropTypes.object,
+  }
+
+  render() {
+    return (
+      <div className="HubHeader">
+        { this.props.isLoading &&
+          <Spinner />
+        }
+        { this.props.hub.name &&
+          <div className="row">
+            <div className={`col-md-${this.props.hub.config.left_width}`}>
+              { this.props.hub.user_hub ?
+                <div>
+                  <img
+                    className="avatar"
+                    src={this.props.hub.config.avatar}
+                    />
+                  <h2 className="user mb-0">
+                    {this.props.hub.name}
+                  </h2>
+                  <h5 className="mt-1 mb-1">
+                    {this.props.hub.config.summary}
+                  </h5>
+                  <div className="clearfix"></div>
+                </div>
+              :
+                <div>
+                  <h2 className="team">
+                    {this.props.hub.name}
+                  </h2>
+                  <h5 className="mt-1 mb-1">
+                    {this.props.hub.config.summary}
+                  </h5>
+                </div>
+              }
+            </div>
+            { this.props.currentUser.can_config_hub &&
+              <div className={`col-md-${this.props.hub.config.right_width} text-center align-self-end`}>
+                <HubConfig />
+                <EditModeButton />
+              </div>
+            }
+          </div>
+        }
+      </div>
+    );
+  }
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    hub: state.entities.hub,
+    isLoading: state.entities.hub.isLoading,
+    currentUser: state.currentUser,
+  }
+};
+
+export default connect(mapStateToProps)(HubHeader);
diff --git a/hubs/static/client/app/components/HubPage.css b/hubs/static/client/app/components/HubPage.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hubs/static/client/app/components/HubPage.css
diff --git a/hubs/static/client/app/components/HubPage.js b/hubs/static/client/app/components/HubPage.js
new file mode 100644
index 0000000..57ce5d0
--- /dev/null
+++ b/hubs/static/client/app/components/HubPage.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import PageStructure from './PageStructure';
+import WidgetsArea from './WidgetsArea';
+import HubHeader from './HubHeader';
+import { fetchHub } from '../core/actions/hub';
+import "./HubPage.css";
+
+
+class HubPage extends React.Component {
+
+  componentDidMount() {
+    this.props.dispatch(fetchHub());
+  }
+
+  render() {
+    return (
+      <PageStructure
+        cssClass="HubPage"
+        header={
+          <HubHeader />
+        }
+        content={
+          <WidgetsArea />
+        }
+        />
+    );
+  }
+}
+
+
+export default connect()(HubPage);
diff --git a/hubs/static/client/app/components/LeftMenu.css b/hubs/static/client/app/components/LeftMenu.css
new file mode 100644
index 0000000..1b0fd47
--- /dev/null
+++ b/hubs/static/client/app/components/LeftMenu.css
@@ -0,0 +1,27 @@
+.LeftMenu {
+  width: 100%;
+  padding: 0 15px;
+  z-index: 1;
+}
+
+.LeftMenu .nav {
+  background-color: #fcfcfc;
+  border: 1px solid #dddddd;
+}
+@media (min-width: 992px) {
+  .LeftMenu {
+    position: absolute;
+    padding: 0.5rem 0 0 0;
+  }
+}
+
+.LeftMenu a.nav-link {
+  color: #373a3c;
+  font-size: 85%;
+}
+
+.LeftMenu a.nav-link.active {
+  color: white;
+  /*background-color: #373a3c;*/
+}
+
diff --git a/hubs/static/client/app/components/LeftMenu.js b/hubs/static/client/app/components/LeftMenu.js
new file mode 100644
index 0000000..066cf6d
--- /dev/null
+++ b/hubs/static/client/app/components/LeftMenu.js
@@ -0,0 +1,76 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import "./LeftMenu.css";
+
+
+class LeftMenu extends React.Component {
+
+  propTypes: {
+    menu: PropTypes.array,
+  }
+  defaultProps: {
+    menu: [],
+  }
+
+  render() {
+    return (
+      <div className="LeftMenu">
+        <ul
+          className="nav nav-pills flex-lg-column mb-3 rounded"
+          role="navigation"
+          >
+          {this.props.menu.map((entry) => (
+            <LeftMenuEntry
+              key={entry.url}
+              {...entry}
+              />
+            ))
+          }
+        </ul>
+      </div>
+    );
+  }
+}
+
+const mapStateToProps = (state) => {
+  return {
+    menu: state.ui.leftMenu,
+  }
+};
+
+export default connect(mapStateToProps)(LeftMenu);
+
+
+class LeftMenuEntry extends React.Component {
+
+  propTypes: {
+    url: PropTypes.string.isRequired,
+    icon: PropTypes.string.isRequired,
+    text: PropTypes.string.isRequired,
+    cssClass: PropTypes.string,
+  }
+  defaultProps: {
+    cssClass: null,
+  }
+
+  render() {
+    const isActive = window.location.pathname.indexOf(this.props.url) !== -1;
+    let cssClass = "nav-link";
+    if (isActive) {
+      cssClass += " active";
+    }
+    if (this.props.cssClass) {
+      cssClass += " " + this.props.cssClass;
+    }
+    return (
+      <li className="nav-item">
+        <a className={cssClass} href={this.props.url}>
+          <i className={`fa fa-${this.props.icon} mr-2`}
+             aria-hidden="true"></i>
+          {this.props.text}
+        </a>
+      </li>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/Modal.js b/hubs/static/client/app/components/Modal.js
new file mode 100644
index 0000000..5a468f1
--- /dev/null
+++ b/hubs/static/client/app/components/Modal.js
@@ -0,0 +1,69 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+
+export default class Modal extends React.Component {
+
+  propTypes: {
+    isLarge: PropTypes.bool,
+    onCloseClicked: PropTypes.func,
+    title: PropTypes.node,
+    footer: PropTypes.node,
+    cssClass: PropTypes.string,
+  }
+  defaultProps: {
+    isLarge: false,
+  }
+
+  constructor(props) {
+    super(props);
+    this.handleCloseClicked = this.handleCloseClicked.bind(this);
+  }
+
+  handleCloseClicked(e) {
+    if (this.props.onCloseClicked) {
+      this.props.onCloseClicked(e);
+    }
+  }
+
+  stopPropagation(e) {
+    e.stopPropagation();
+  }
+
+  render() {
+    return (
+      <div className={this.props.cssClass}>
+        <div className="modal-backdrop show"></div>
+        <div
+          className="modal" style={{display: "block"}}
+          onClick={this.handleCloseClicked}
+          >
+          <div
+            className={"modal-dialog" + (this.props.isLarge ? " modal-lg" : "")}
+            onClick={this.stopPropagation}
+            >
+            <div className="modal-content">
+                <div className="modal-header">
+                  <h5 className="modal-title">
+                    {this.props.title}
+                  </h5>
+                  <button
+                    type="button" className="close" aria-label="Close"
+                    onClick={this.handleCloseClicked}
+                    >
+                    <span aria-hidden="true">&times;</span>
+                  </button>
+                </div>
+                <div className="modal-body">
+                  {this.props.children}
+                </div>
+                <div className="modal-footer">
+                  {this.props.footer}
+                </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/Modal.jsx b/hubs/static/client/app/components/Modal.jsx
deleted file mode 100644
index 3b18312..0000000
--- a/hubs/static/client/app/components/Modal.jsx
+++ /dev/null
@@ -1,121 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-
-export default class Modal extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      open: false,
-    }
-    this.onShow = this.onShow.bind(this);
-    this.onShown = this.onShown.bind(this);
-    this.onHide = this.onHide.bind(this);
-    this.onHidden = this.onHidden.bind(this);
-    this.hide = this.hide.bind(this);
-    this.show = this.show.bind(this);
-    this.getModalBody = this.getModalBody.bind(this);
-    this.getModalFooter = this.getModalFooter.bind(this);
-  }
-
-  componentDidMount() {
-    if (this.domNode) {
-      $(this.domNode).on("show.bs.modal", this.onShow);
-      $(this.domNode).on("shown.bs.modal", this.onShown);
-      $(this.domNode).on("hide.bs.modal", this.onHide);
-      $(this.domNode).on("hidden.bs.modal", this.onHidden);
-    }
-  }
-
-  componentWillUnmount() {
-    if (this.domNode) {
-      $(this.domNode).off("show.bs.modal", this.onShow);
-      $(this.domNode).off("shown.bs.modal", this.onShown);
-      $(this.domNode).off("hide.bs.modal", this.onHide);
-      $(this.domNode).off("hidden.bs.modal", this.onHidden);
-    }
-  }
-
-  onShow(e) {
-    if (this.props.onShow) { this.props.onShow(); }
-  }
-  onShown(e) {
-    if (this.props.onShown) { this.props.onShown(); }
-  }
-  onHide(e) {
-    if (this.props.onHide) { this.props.onHide(); }
-  }
-  onHidden(e) {
-    if (this.props.onHidden) { this.props.onHidden(); }
-  }
-
-  hide(callback) {
-    if (!this.domNode) { return; }
-    var domNode = $(this.domNode);
-    if (callback) { domNode.one("hidden.bs.modal", callback); }
-    domNode.modal("hide");
-  }
-
-  show(callback) {
-    if (!this.domNode) { return; }
-    var domNode = $(this.domNode);
-    if (callback) { domNode.one("shown.bs.modal", callback); }
-    domNode.modal("show");
-  }
-
-  componentWillUpdate(nextProps, nextState) {
-    if (!this.domNode) { return; }
-    const domNode = $(this.domNode);
-    if (domNode.is(":visible") && !nextProps.open) {
-      this.hide();
-    }
-  }
-
-  componentDidUpdate() {
-    if (!this.domNode) { return; }
-    const domNode = $(this.domNode);
-    if (this.props.open && !domNode.is(":visible")) {
-      this.show();
-    }
-  }
-
-  getModalBody() {
-    if (!this.props.data) { return ""; }
-  }
-
-  getModalFooter() {
-    return null;
-  }
-
-  render() {
-    var footer = this.getModalFooter();
-    return (
-      <div className="modal fade" role="dialog" ref={(ref) => this.domNode = ref}>
-        <div className="modal-dialog" role="document">
-          <div className="modal-content">
-            <div className="modal-header">
-              <h4 className="modal-title">{this.props.title}</h4>
-              <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
-            </div>
-            <div className="modal-body">
-              {this.getModalBody()}
-            </div>
-            {footer ?
-            <div className="modal-footer">
-              {footer}
-            </div>
-             : null}
-          </div>
-        </div>
-      </div>
-    );
-  }
-}
-Modal.propTypes = {
-    open: PropTypes.bool,
-    data: PropTypes.object
-};
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/NotifIcon.js b/hubs/static/client/app/components/NotifIcon.js
new file mode 100644
index 0000000..9330e99
--- /dev/null
+++ b/hubs/static/client/app/components/NotifIcon.js
@@ -0,0 +1,55 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+
+
+class NotifIcon extends React.PureComponent {
+
+  constructor(props) {
+    super(props);
+    this.notifTimeout = null;
+    this.changeNotifyIcon = this.changeNotifyIcon.bind(this);
+  }
+
+  componentDidUpdate(prevProps, prevState) {
+    // Icon to red on disconnect, icon to green on reconnect.
+    if (!prevProps.sseConnected && this.props.sseConnected) {
+      // Connected
+      this.changeNotifyIcon("green");
+    } else if (prevProps.sseConnected && !this.props.sseConnected) {
+      // Disconnected
+      this.changeNotifyIcon("red");
+    }
+  }
+
+  changeNotifyIcon(color) {
+    // Set the notify icon for 5s
+    if (color == "green") {
+      color = "#33ff00";
+    } else if (color == "red") {
+      color = "#eb361e";
+    }
+    window.Notificon(color);
+    if (this.notifTimeout) { clearTimeout(this.notifTimeout); }
+    this.notifTimeout = setTimeout(() => (window.Notificon()), 5000);
+  }
+
+  render() {
+    return null;
+  }
+}
+NotifIcon.propTypes = {
+  sseConnected: PropTypes.bool,
+}
+NotifIcon.defaultProps = {
+  sseConnected: false,
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    sseConnected: state.sse.connected,
+  }
+};
+
+export default connect(mapStateToProps)(NotifIcon);
diff --git a/hubs/static/client/app/components/PageStructure.js b/hubs/static/client/app/components/PageStructure.js
new file mode 100644
index 0000000..ee6cd14
--- /dev/null
+++ b/hubs/static/client/app/components/PageStructure.js
@@ -0,0 +1,34 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import FlashMessages from './FlashMessages';
+import LeftMenu from './LeftMenu';
+
+
+export default class PageStructure extends React.Component {
+
+  render() {
+    return (
+      <div className={this.props.cssClass}>
+        <header>
+          <FlashMessages />
+          <div className="row">
+            <div className="col-lg-2">
+              <LeftMenu />
+            </div>
+            <div className="col-lg-10">
+              {this.props.header}
+            </div>
+          </div>
+        </header>
+
+        <div className="container-fluid">
+          <div className="row">
+            <div className="offset-lg-2 col-lg-10 px-0">
+              {this.props.content}
+            </div>
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/SSESource.js b/hubs/static/client/app/components/SSESource.js
new file mode 100644
index 0000000..930a38c
--- /dev/null
+++ b/hubs/static/client/app/components/SSESource.js
@@ -0,0 +1,82 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import ReconnectingEventSource from "reconnecting-eventsource";
+import {
+  sseEvent,
+  sseConnected,
+  sseDisconnected
+} from "../core/actions/sse";
+
+
+const MESSAGE_TYPES = [
+  "hubs:widget-updated",
+  "hubs:new-notification",
+];
+
+
+class SSESource extends React.PureComponent {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      isEnabled: true,
+    }
+    this.source = null;
+    this.notifTimeout = null;
+    this.setupSource = this.setupSource.bind(this);
+  }
+
+  componentDidMount() {
+    if (!this.props.url || !window.EventSource) {
+      // Auto-update is disabled.
+      this.setState({isEnabled: false});
+    } else {
+      this.setupSource();
+    }
+  }
+
+  componentWillUnmount() {
+    if (this.source) {
+      this.source.close();
+    }
+    //window.removeEventListener("beforeunload", this.tearDownSSESource);
+  }
+
+  setupSource() {
+    this.source = new ReconnectingEventSource(this.props.url),
+    MESSAGE_TYPES.forEach((msgType) => {
+      this.source.addEventListener(msgType, (e) => {
+        this.props.dispatch(sseEvent(msgType, JSON.parse(e.data)));
+      });
+    });
+    this.source.onopen = () => (
+      this.props.dispatch(sseConnected(this.source))
+    );
+    this.source.onerror = () => (
+      this.props.dispatch(sseDisconnected(this.source))
+    );
+    // This is necessary to avoid the error message being displayed right
+    // before the user changes page.
+    // Pretty much like: https://bugzilla.mozilla.org/show_bug.cgi?id=833462
+    window.addEventListener("beforeunload", () => {
+      this.source.onerror = () => (null);
+    });
+  }
+
+  render() {
+    return null;
+  }
+}
+SSESource.propTypes = {
+  url: PropTypes.string.isRequired,
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    url: state.urls.sse,
+  }
+};
+
+export default connect(mapStateToProps)(SSESource);
diff --git a/hubs/static/client/app/components/SimpleWidget.js b/hubs/static/client/app/components/SimpleWidget.js
new file mode 100644
index 0000000..9a62fe5
--- /dev/null
+++ b/hubs/static/client/app/components/SimpleWidget.js
@@ -0,0 +1,86 @@
+import React from 'react';
+import {
+  widgetDidUpdate,
+  widgetWillUpdate
+  } from "../core/actions/widget";
+import { backendCall } from "../core/utils";
+import SimpleWidgetConfig from './SimpleWidgetConfig';
+import WidgetChrome from './WidgetChrome';
+
+
+export default class SimpleWidget extends React.PureComponent {
+
+  propTypes: {
+    widget: PropTypes.object.isRequired,
+    editMode: PropTypes.bool,
+    needsUpdate: PropTypes.bool,
+  }
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      isLoading: false,
+      contents: "",
+    };
+  }
+
+  componentDidMount() {
+    if (!this.props.editMode) {
+      this.loadFromServer();
+    }
+  }
+
+  componentDidUpdate(prevProps, prevState) {
+    if (this.props.needsUpdate && !this.props.editMode && !this.state.isLoading) {
+      this.loadFromServer();
+    }
+  }
+
+  loadFromServer() {
+    this.props.dispatch(widgetWillUpdate(this.props.widget.idx));
+    this.setState({ isLoading: true });
+    let url = this.props.widget.contentUrl;
+    if (this.props.editMode) {
+      url += "?edit=1";
+    }
+    return backendCall(url).catch(
+      (error) => (
+        `<div class="text-danger">Cannot display this widget: ${error.message}</div>`
+      )
+    ).then(
+      (contents) => {
+        this.setState({
+          isLoading: false, contents
+        }, () => (
+          this.props.dispatch(widgetDidUpdate(this.props.widget.idx))
+        ));
+      }
+    );
+  }
+
+  render() {
+    if (this.props.widget.hiddenIfEmpty) {
+      if (
+        this.state.isLoading ||
+        !this.props.editMode && (
+          !this.state.contents || !this.state.contents.trim()
+        )
+      ) {
+        // Hide when loading and when the contents is empty in view mode.
+        return null;
+      }
+    }
+    return (
+      <WidgetChrome
+        widget={this.props.widget}
+        editMode={this.props.editMode}
+        >
+        { this.state.isLoading &&
+          <div className="text-muted">Loading...</div>
+          ||
+          <div dangerouslySetInnerHTML={{__html: this.state.contents}} />
+        }
+      </WidgetChrome>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/SimpleWidgetConfig.js b/hubs/static/client/app/components/SimpleWidgetConfig.js
new file mode 100644
index 0000000..f323b52
--- /dev/null
+++ b/hubs/static/client/app/components/SimpleWidgetConfig.js
@@ -0,0 +1,42 @@
+import React from 'react';
+
+
+export default class SimpleWidgetConfig extends React.Component {
+
+  propTypes: {
+    widget: PropTypes.object.isRequired,
+    values: PropTypes.object.isRequired,
+    setConfig: PropTypes.func.isRequired,
+  }
+
+  render() {
+    let fields = this.props.widget.params.map((field) => {
+      return (
+        <fieldset className="form-group" key={field.name}>
+          <strong>{field.label}</strong>
+          <input
+            className="form-control"
+            type="text"
+            value={this.props.values[field.name] || ""}
+            name={field.name}
+            onChange={(e) => {
+              this.props.setConfig(e.target.name, e.target.value)
+            }}
+            />
+          { field.help &&
+            <small className="text-muted">{field.help}</small>
+          }
+        </fieldset>
+      );
+    });
+    return (
+      <div>
+        { fields.length === 0 ?
+          <p>Nothing to configure</p>
+          :
+          fields
+        }
+      </div>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/Spinner/Spinner.css b/hubs/static/client/app/components/Spinner/Spinner.css
new file mode 100644
index 0000000..97b52cb
--- /dev/null
+++ b/hubs/static/client/app/components/Spinner/Spinner.css
@@ -0,0 +1,12 @@
+.Spinner {
+   width: 50px;
+   height: 10px;
+   vertical-align: bottom;
+}
+
+.SpinnerCircle {
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+  vertical-align: bottom;
+}
diff --git a/hubs/static/client/app/components/Spinner/index.js b/hubs/static/client/app/components/Spinner/index.js
new file mode 100644
index 0000000..4979621
--- /dev/null
+++ b/hubs/static/client/app/components/Spinner/index.js
@@ -0,0 +1,31 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import "./Spinner.css";
+import SpinnerImg from "./spinner.gif";
+import SpinnerCircleImg from "./spinner-circle.gif";
+
+
+export default class Spinner extends React.Component {
+
+  render() {
+    let img, className;
+    if (this.props.circle) {
+      className = "SpinnerCircle";
+      img = SpinnerCircleImg;
+    } else {
+      className = "Spinner";
+      img = SpinnerImg;
+    }
+    return (
+      <div className={className}>
+        <img src={img} />
+      </div>
+    );
+  }
+}
+Spinner.propTypes = {
+  circle: PropTypes.bool
+}
+Spinner.defaultProps = {
+  circle: false
+}
diff --git a/hubs/static/client/app/components/Spinner/spinner-circle.gif b/hubs/static/client/app/components/Spinner/spinner-circle.gif
new file mode 100644
index 0000000..d0bce15
Binary files /dev/null and b/hubs/static/client/app/components/Spinner/spinner-circle.gif differ
diff --git a/hubs/static/client/app/components/Spinner/spinner.gif b/hubs/static/client/app/components/Spinner/spinner.gif
new file mode 100644
index 0000000..8a3ea9f
Binary files /dev/null and b/hubs/static/client/app/components/Spinner/spinner.gif differ
diff --git a/hubs/static/client/app/components/Streams.js b/hubs/static/client/app/components/Streams.js
new file mode 100644
index 0000000..b2b0ff3
--- /dev/null
+++ b/hubs/static/client/app/components/Streams.js
@@ -0,0 +1,193 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import {
+  streamWillUpdate,
+  streamDidUpdate,
+  } from "../core/actions/stream";
+import SSESource from "./SSESource";
+import TabSet from '../components/TabSet';
+import ItemsGetter from '../components/feed/ItemsGetter';
+import Feed from '../components/feed/Feed';
+
+
+class Streams extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      notifItems: [],
+      savedItems: [],
+    };
+    this.handleStreamData = this.handleStreamData.bind(this);
+    this.handleStreamRequestStart = this.handleStreamRequestStart.bind(this);
+    this.handleSavedData = this.handleSavedData.bind(this);
+    this.handleSave = this.handleSave.bind(this);
+    this.handleUnsave = this.handleUnsave.bind(this);
+  }
+
+  handleStreamData(data) {
+    this.setState({
+      notifItems: data
+    },
+      () => (
+        this.props.dispatch(streamDidUpdate())
+      )
+    );
+  }
+
+  handleStreamRequestStart() {
+    this.props.dispatch(streamWillUpdate());
+  }
+
+  handleSavedData(data) {
+    this.setState({savedItems: data});
+  }
+
+  handleSave(item) {
+    if (!this.props.savedUrl) { return; }
+    const payload = {
+      link: item.link,
+      markup: item.markup,
+      secondary_icon: item.secondary_icon,
+      dom_id: item.dom_id,
+    };
+    $.ajax({
+      type: 'POST',
+      url: this.props.savedUrl,
+      data: JSON.stringify(payload),
+      contentType: 'application/json',
+      success: (data) => {
+        this.setState((prevState, props) => {
+          prevState.savedItems.push(data.data);
+          return {savedItems: prevState.savedItems};
+        });
+      },
+    });
+  }
+
+  handleUnsave(item) {
+    if (!this.props.savedUrl) { return; }
+    var updateSavedItems = (item) => {
+      this.setState((prevState, props) => {
+        var items = prevState.savedItems.filter(
+          (currentItem) => (currentItem.dom_id !== item.dom_id)
+        );
+        return {savedItems: items};
+      });
+    };
+    if (item.idx) {
+      // Already saved
+      $.ajax({
+        type: 'DELETE',
+        url: `${this.props.savedUrl}${item.idx}/`,
+        success: () => { updateSavedItems(item) },
+      });
+    } else {
+      updateSavedItems(item);
+    }
+  }
+
+  render() {
+    // Add saved state.
+    var savedItemsIds = this.state.savedItems.map((item) => {
+      return item.dom_id;
+    });
+    var notifs = this.state.notifItems.map((item) => {
+      item.saved = (savedItemsIds.indexOf(item.dom_id) !== -1);
+      return item;
+    });
+
+    return (
+      <div className="Streams">
+        <TabSet tabListClass="mb-3">
+          <FeedPanel
+            username={this.props.username}
+            tabTitle="My Stream"
+            >
+            <ItemsGetter
+              url={this.props.notificationsUrl}
+              useSSE={true}
+              handleData={this.handleStreamData}
+              needsUpdate={false}
+              >
+              <Feed
+                items={notifs}
+                handleSave={this.handleSave}
+                handleUnsave={this.handleUnsave}
+                />
+            </ItemsGetter>
+          </FeedPanel>
+          <FeedPanel
+            username={this.props.username}
+            tabTitle="My Actions"
+            >
+            <Feed
+              items={this.state.notifItems}
+              />
+          </FeedPanel>
+          <FeedPanel
+            username={this.props.username}
+            tabTitle="Saved Notifications"
+            >
+            <ItemsGetter
+              url={this.props.savedUrl}
+              handleData={this.handleSavedData}
+              useSSE={false}
+              >
+              <Feed
+                items={this.state.savedItems}
+                handleUnsave={this.handleUnsave}
+                />
+            </ItemsGetter>
+          </FeedPanel>
+        </TabSet>
+
+        <SSESource />
+      </div>
+    );
+  }
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    savedUrl: state.urls.saved,
+    notificationsUrl: state.urls.notifications,
+    username: state.currentUser.nickname,
+  }
+};
+
+export default connect(mapStateToProps)(Streams);
+
+
+
+class FeedPanel extends React.Component {
+
+  render() {
+    const filters_url = `https://apps.fedoraproject.org/notifications/${this.props.username}.id.fedoraproject.org/`;
+
+    return (
+      <div>
+        <div className="input-group">
+          <input
+            type="search" className="form-control"
+            placeholder="Search this activity stream..."
+            aria-describedby="searchform-addon" />
+          <span className="input-group-addon">
+            <span><i className="fa fa-search" aria-hidden="true"></i></span>
+          </span>
+        </div>
+        <br/>
+        <div className="alert alert-warning" role="alert">
+          This stream is filtered. <a href={filters_url} target="_blank">View Filters</a>
+        </div>
+        {this.props.children}
+      </div>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/components/StreamsHeader.js b/hubs/static/client/app/components/StreamsHeader.js
new file mode 100644
index 0000000..7a6900f
--- /dev/null
+++ b/hubs/static/client/app/components/StreamsHeader.js
@@ -0,0 +1,15 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+
+export default class StreamsHeader extends React.Component {
+
+  render() {
+    return (
+      <div className="StreamsHeader">
+        <h1>My Stream</h1>
+        <p>Notifications, actions, and other things of interest to me</p>
+      </div>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/StreamsPage.js b/hubs/static/client/app/components/StreamsPage.js
new file mode 100644
index 0000000..3206280
--- /dev/null
+++ b/hubs/static/client/app/components/StreamsPage.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import PageStructure from './PageStructure';
+import StreamsHeader from './StreamsHeader';
+import Streams from './Streams';
+
+
+export default class StreamsPage extends React.Component {
+
+  render() {
+    return (
+      <PageStructure
+        cssClass="StreamsPage"
+        header={
+          <StreamsHeader />
+        }
+        content={
+          <Streams />
+        }
+        />
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/Tab.js b/hubs/static/client/app/components/Tab.js
new file mode 100644
index 0000000..1084065
--- /dev/null
+++ b/hubs/static/client/app/components/Tab.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+
+export default class Tab extends React.Component {
+  render() {
+    var linkClass = `nav-link ${this.props.tabLinkClass}`;
+    if (this.props.active) { linkClass += " active"; }
+    return (
+      <li className="nav-item">
+        <a href="#" role="tab"
+           className={linkClass}
+           onClick={this.props.linkClicked}
+           >
+          {this.props.children}
+        </a>
+      </li>
+    );
+  }
+}
+
+Tab.propTypes = {
+  tabLinkClass: PropTypes.string,
+};
+Tab.defaultProps = {
+  tabLinkClass: '',
+};
diff --git a/hubs/static/client/app/components/Tab.jsx b/hubs/static/client/app/components/Tab.jsx
deleted file mode 100644
index a26e1b7..0000000
--- a/hubs/static/client/app/components/Tab.jsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-
-export default class Tab extends React.Component {
-  render() {
-    var linkClass = `nav-link ${this.props.tabLinkClass}`;
-    if (this.props.active) { linkClass += " active"; }
-    return (
-      <li className="nav-item">
-        <a href="#" role="tab"
-           className={linkClass}
-           onClick={this.props.linkClicked}
-           >
-          {this.props.children}
-        </a>
-      </li>
-    );
-  }
-}
-
-Tab.propTypes = {
-  tabLinkClass: PropTypes.string,
-};
-Tab.defaultProps = {
-  tabLinkClass: '',
-};
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/TabPanel.js b/hubs/static/client/app/components/TabPanel.js
new file mode 100644
index 0000000..a72dcee
--- /dev/null
+++ b/hubs/static/client/app/components/TabPanel.js
@@ -0,0 +1,13 @@
+import React from 'react';
+
+
+export default class TabPanel extends React.Component {
+  render() {
+    return (
+      <div role="tabpanel"
+           className={"tab-pane" + (this.props.active ? " active" : "")}>
+        {this.props.children}
+      </div>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/TabPanel.jsx b/hubs/static/client/app/components/TabPanel.jsx
deleted file mode 100644
index 7d3a4ee..0000000
--- a/hubs/static/client/app/components/TabPanel.jsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-
-
-export default class TabPanel extends React.Component {
-  render() {
-    return (
-      <div role="tabpanel"
-           className={"tab-pane" + (this.props.active ? " active" : "")}>
-        {this.props.children}
-      </div>
-    );
-  }
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/TabSet.js b/hubs/static/client/app/components/TabSet.js
new file mode 100644
index 0000000..25dad18
--- /dev/null
+++ b/hubs/static/client/app/components/TabSet.js
@@ -0,0 +1,71 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Tab from './Tab';
+import TabPanel from './TabPanel';
+
+
+export default class TabSet extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      activeTab: 0
+    }
+  }
+
+  linkClicked(e, index) {
+    e.preventDefault();
+    this.setState({activeTab: index});
+  }
+
+  render() {
+    var tabLinks = this.props.children.map(function(panel, index) {
+      return (
+        <Tab active={this.state.activeTab === index}
+             linkClicked={(e) => this.linkClicked(e, index)}
+             key={index.toString()}>
+          {panel.props.tabTitle}
+        </Tab>
+        );
+    }.bind(this));
+
+    var tabPanels = this.props.children.map(function(panel, index) {
+      return (
+        <TabPanel
+          active={this.state.activeTab === index}
+          key={index.toString()}>
+          {panel}
+        </TabPanel>
+        );
+    }.bind(this));
+
+    return (
+      <div {...this.props.tabWrapperProps}>
+        <ul role="tablist"
+            className={`nav nav-${this.props.tabType} ${this.props.tabListClass}`}
+            >
+          {tabLinks}
+        </ul>
+        <div
+          className={"tab-content " + this.props.tabContentClass}
+          >
+          {tabPanels}
+        </div>
+      </div>
+    );
+  }
+
+}
+
+TabSet.propTypes = {
+  tabWrapperProps: PropTypes.object,
+  tabType: PropTypes.string,
+  tabListClass: PropTypes.string,
+  tabContentClass: PropTypes.string,
+};
+TabSet.defaultProps = {
+  tabWrapperProps: {},
+  tabType: 'tabs',
+  tabListClass: '',
+  tabContentClass: '',
+};
diff --git a/hubs/static/client/app/components/TabSet.jsx b/hubs/static/client/app/components/TabSet.jsx
deleted file mode 100644
index c3064c5..0000000
--- a/hubs/static/client/app/components/TabSet.jsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import Tab from './Tab.jsx';
-import TabPanel from './TabPanel.jsx';
-
-
-export default class TabSet extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      activeTab: 0
-    }
-  }
-
-  linkClicked(e, index) {
-    e.preventDefault();
-    this.setState({activeTab: index});
-  }
-
-  render() {
-    var tabLinks = this.props.children.map(function(panel, index) {
-      return (
-        <Tab active={this.state.activeTab === index}
-             linkClicked={(e) => this.linkClicked(e, index)}
-             key={index.toString()}>
-          {panel.props.tabTitle}
-        </Tab>
-        );
-    }.bind(this));
-
-    var tabPanels = this.props.children.map(function(panel, index) {
-      return (
-        <TabPanel
-          active={this.state.activeTab === index}
-          key={index.toString()}>
-          {panel}
-        </TabPanel>
-        );
-    }.bind(this));
-
-    return (
-      <div {...this.props.tabWrapperProps}>
-        <ul role="tablist"
-            className={`nav nav-${this.props.tabType} ${this.props.tabListClass}`}
-            >
-          {tabLinks}
-        </ul>
-        <div
-          className={"tab-content " + this.props.tabContentClass}
-          >
-          {tabPanels}
-        </div>
-      </div>
-    );
-  }
-
-}
-
-TabSet.propTypes = {
-  tabWrapperProps: PropTypes.object,
-  tabType: PropTypes.string,
-  tabListClass: PropTypes.string,
-  tabContentClass: PropTypes.string,
-};
-TabSet.defaultProps = {
-  tabWrapperProps: {},
-  tabType: 'tabs',
-  tabListClass: '',
-  tabContentClass: '',
-};
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/VisibilitySelect.js b/hubs/static/client/app/components/VisibilitySelect.js
new file mode 100644
index 0000000..7eedaa1
--- /dev/null
+++ b/hubs/static/client/app/components/VisibilitySelect.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+
+export default class VisibilitySelect extends React.Component {
+
+  propTypes: {
+    selectedVisibility: PropTypes.string.isRequired,
+    setConfig: PropTypes.func.isRequired,
+  }
+
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  handleChange(e) {
+    this.props.setConfig(e.target.name, e.target.value);
+  }
+
+  render() {
+    return (
+      <fieldset className="form-group">
+        <label htmlFor="visibility">Visibility:</label>
+        <select
+          className="form-control"
+          name="visibility"
+          value={this.props.selectedVisibility || "public"}
+          onChange={this.handleChange}
+          >
+          <option value="public">Public</option>
+          <option value="restricted">Restricted</option>
+        </select>
+        <small className="text-muted">
+          Restricted widgets will only be visible by logged-in users.
+        </small>
+      </fieldset>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/Widget.js b/hubs/static/client/app/components/Widget.js
new file mode 100644
index 0000000..880c1c4
--- /dev/null
+++ b/hubs/static/client/app/components/Widget.js
@@ -0,0 +1,74 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import {
+  makeLoadable,
+  makeLoadingComponent
+} from '../core/utils';
+import SimpleWidget from '../components/SimpleWidget';
+
+/*
+import HalpWidget from '../widgets/halp/Widget';
+import FeedWidget from '../widgets/feed/Widget';
+*/
+
+
+class Widget extends React.PureComponent {
+
+  propTypes: {
+    widget: PropTypes.array.isRequired,
+    editMode: PropTypes.bool,
+    needsUpdate: PropTypes.bool,
+  }
+  defaultProps: {
+    editMode: false,
+    needsUpdate: false,
+  }
+
+  render() {
+    let widgetComponent;
+    if (!this.props.editMode && this.props.widget.isReact) {
+      const AsyncComponent = makeLoadable(
+        () => import(`../widgets/${this.props.widget.component}/Widget`),
+        makeLoadingComponent(
+          "Loading widget...",
+          "Sorry, there was a problem loading the widget."
+        )
+      );
+      /*
+      console.log(this.props.widget);
+      let AsyncComponent = null;
+      if (this.props.widget.component === "halp") { AsyncComponent = HalpWidget; }
+      if (this.props.widget.component === "feed") { AsyncComponent = FeedWidget; }
+      */
+      widgetComponent = (
+        <AsyncComponent {...this.props} />
+      );
+    } else {
+      widgetComponent = (
+        <SimpleWidget {...this.props} />
+      );
+    }
+    return (
+      <div
+        key={this.props.widget.idx}
+        id={`widget-${this.props.widget.idx}`}
+        className={"widget" + (this.props.editMode ? " widget-edit" : "")}
+        >
+        {widgetComponent}
+      </div>
+    );
+  }
+}
+
+
+const mapStateToProps = (state, ownProps) => {
+  return {
+    editMode: state.ui.widgetsEditMode,
+    needsUpdate: (
+      state.entities.widgets.needUpdate.indexOf(ownProps.widget.idx) !== -1
+    ),
+  }
+};
+
+export default connect(mapStateToProps)(Widget);
diff --git a/hubs/static/client/app/components/WidgetChrome.css b/hubs/static/client/app/components/WidgetChrome.css
new file mode 100644
index 0000000..6878ef8
--- /dev/null
+++ b/hubs/static/client/app/components/WidgetChrome.css
@@ -0,0 +1,28 @@
+.widget {
+  font-family: 'Open Sans', sans-serif;
+  margin-bottom: .5rem;
+}
+
+.widget .card {
+  width: 100%;
+}
+
+.widget-buttons {
+  font-size: 80%;
+  position: absolute;
+  top: 0;
+  right: 0;
+  padding: .3rem;
+}
+
+.widget .widget-buttons a {
+  margin-right: .4rem;
+  color: #373a3c;
+}
+.widget .widget-buttons a:hover {
+  text-decoration: none;
+}
+
+.widget-edit .card-header {
+    cursor: ns-resize;
+}
diff --git a/hubs/static/client/app/components/WidgetChrome.js b/hubs/static/client/app/components/WidgetChrome.js
new file mode 100644
index 0000000..374b610
--- /dev/null
+++ b/hubs/static/client/app/components/WidgetChrome.js
@@ -0,0 +1,83 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { openConfigDialog } from "../core/actions/widget";
+import "./WidgetChrome.css";
+
+
+class WidgetChrome extends React.PureComponent {
+
+  propTypes: {
+    widget: PropTypes.object.isRequired,
+    editMode: PropTypes.bool,
+  }
+  defaultProps: {
+    editMode: false,
+  }
+
+  constructor(props) {
+    super(props);
+    this.handleEditButtonClicked = this.handleEditButtonClicked.bind(this)
+  }
+
+  handleEditButtonClicked(e) {
+    e.preventDefault();
+    this.props.onEdit(this.props.widget.idx);
+  }
+
+  render() {
+    const title = (this.props.editMode && !this.props.widget.title) ? this.props.widget.label : this.props.widget.title;
+    let cssClass = `WidgetChrome card widget-${this.props.widget.name}`;
+    if (this.props.widget.cssClass) {
+      cssClass += " " + this.props.widget.cssClass;
+    }
+    return (
+      <div className={cssClass}>
+        <div className="widget-buttons">
+          { this.props.editMode &&
+            <a href="#"
+              onClick={this.handleEditButtonClicked}
+              >
+              <i className="fa fa-cog" aria-hidden="true"></i>
+            </a>
+          }
+        </div>
+        { title ?
+          <div className="card-header">
+            {title}
+          </div>
+          : null
+        }
+        <div className="card-block">
+          { this.props.editMode &&
+            <div className="text-muted">Content hidden in edit mode</div>
+            ||
+            this.props.children
+          }
+        </div>
+        { this.props.widget.footer ?
+          <div className="card-footer">
+            {this.props.widget.footer}
+          </div>
+          : null
+        }
+      </div>
+    );
+  }
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    editMode: state.ui.widgetsEditMode,
+  }
+};
+const mapDispatchToProps = dispatch => {
+  return {
+    onEdit: (widgetId) => { dispatch(openConfigDialog(widgetId)); }
+  }
+}
+
+export default connect(
+  mapStateToProps, mapDispatchToProps
+  )(WidgetChrome);
diff --git a/hubs/static/client/app/components/WidgetConfigDialog.js b/hubs/static/client/app/components/WidgetConfigDialog.js
new file mode 100644
index 0000000..1548956
--- /dev/null
+++ b/hubs/static/client/app/components/WidgetConfigDialog.js
@@ -0,0 +1,145 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import {
+  saveConfig,
+  deleteWidget,
+  closeConfigDialog,
+  } from "../core/actions/widget";
+import {
+  makeLoadable,
+  makeLoadingComponent
+} from '../core/utils';
+import SimpleWidgetConfig from '../components/SimpleWidgetConfig';
+import Modal from '../components/Modal';
+
+
+class WidgetConfigDialog extends React.Component {
+
+  propTypes: {
+    widget: PropTypes.object.isRequired,
+    showVisibilitySelect: PropTypes.bool,
+  }
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      widgetConfig: null,
+    };
+    this.handleClose = this.handleClose.bind(this);
+    this.handleWidgetEdited = this.handleWidgetEdited.bind(this);
+    this.handleWidgetDeleted = this.handleWidgetDeleted.bind(this);
+    this.setWidgetConfig = this.setWidgetConfig.bind(this);
+  }
+
+  componentWillReceiveProps(nextProps){
+    if (nextProps.widget.config && (
+        !this.state.widgetConfig ||
+        this.props.widget.idx !== nextProps.widget.idx
+      )) {
+      // Preload the config on initial load and on widget change
+      this.setState({widgetConfig: nextProps.widget.config});
+    }
+  }
+
+  setWidgetConfig(name, value) {
+    this.setState((prevState, props) => {
+      prevState.widgetConfig[name] = value;
+      return {widgetConfig: prevState.widgetConfig};
+    });
+  }
+
+  handleWidgetEdited(e) {
+    e.preventDefault();
+    this.props.dispatch(saveConfig(this.props.widget.idx, this.state.widgetConfig));
+  }
+
+  handleWidgetDeleted(e) {
+    e.preventDefault();
+    this.props.dispatch(deleteWidget(this.props.widget.idx));
+  }
+
+  handleClose(e) {
+    this.props.dispatch(closeConfigDialog());
+  }
+
+  render() {
+    if (!this.props.widget) {
+      return null;
+    }
+    const widgetName = this.props.widget.name;
+    let contents;
+    if (this.props.widget.isReact) {
+      const AsyncComponent = makeLoadable(
+        () => import(`../widgets/${widgetName}/Config`),
+        makeLoadingComponent(
+          "Loading widget configuration...",
+          "Sorry, there was a problem loading the widget configuration."
+        )
+      );
+      contents = (
+        <AsyncComponent
+          widget={this.props.widget}
+          values={this.state.widgetConfig}
+          setConfig={this.setWidgetConfig}
+          />
+      );
+    } else {
+      contents = (
+        <SimpleWidgetConfig
+          widget={this.props.widget}
+          values={this.state.widgetConfig}
+          setConfig={this.setWidgetConfig}
+          />
+      );
+    }
+    const footer = (
+      <div className="d-flex justify-content-end w-100">
+        <button
+          type="button"
+          className="btn btn-danger mr-auto"
+          onClick={this.handleWidgetDeleted}
+          >
+          Remove this widget
+        </button>
+        <button
+          type="button"
+          className="btn btn-secondary ml-3"
+          onClick={this.handleClose}
+          >
+          Close
+        </button>
+        <button
+          type="button"
+          className="btn btn-primary ml-3"
+          onClick={this.handleWidgetEdited}
+          >
+          Save
+        </button>
+      </div>
+    );
+
+    return (
+      <Modal
+        onCloseClicked={this.handleClose}
+        isLarge={this.props.widget.isReact}
+        title={`Configuring widget ${this.props.widget.label}`}
+        footer={footer}
+        >
+        {contents}
+      </Modal>
+    );
+  }
+}
+
+
+const mapStateToProps = (state) => {
+  const confWidgetId = state.ui.widgetConfigDialogOpen;
+  return {
+    widget: (
+      confWidgetId && state.entities.widgets.byId[confWidgetId]
+    ),
+  }
+};
+
+export default connect(mapStateToProps)(WidgetConfigDialog);
diff --git a/hubs/static/client/app/components/WidgetsArea.css b/hubs/static/client/app/components/WidgetsArea.css
new file mode 100644
index 0000000..2cd1368
--- /dev/null
+++ b/hubs/static/client/app/components/WidgetsArea.css
@@ -0,0 +1,5 @@
+.WidgetsArea > .Spinner {
+    position: absolute;
+    left: 1rem;
+    z-index: 1;
+}
diff --git a/hubs/static/client/app/components/WidgetsArea.js b/hubs/static/client/app/components/WidgetsArea.js
new file mode 100644
index 0000000..a23e3df
--- /dev/null
+++ b/hubs/static/client/app/components/WidgetsArea.js
@@ -0,0 +1,90 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import WidgetsColumn from './WidgetsColumn';
+import CobWeb from './CobWeb';
+import WidgetConfigDialog from './WidgetConfigDialog';
+import SSESource from "./SSESource";
+import NotifIcon from "./NotifIcon";
+import Spinner from "./Spinner";
+import { fetchWidgets } from '../core/actions/widgets';
+import "./WidgetsArea.css";
+
+
+class WidgetsArea extends React.PureComponent {
+
+  componentDidMount() {
+    this.props.dispatch(fetchWidgets());
+  }
+
+  render() {
+    if (!this.props.hub.name) {
+      return null;
+    }
+    return (
+      <div className="WidgetsArea">
+        { this.props.widgets.isLoading &&
+          <Spinner />
+        }
+        <div className="row">
+          <div className={`col-md-${this.props.hub.config.left_width}`}>
+
+            { /*
+              First, before the proper widgets.. a cobweb built-in widget.
+              https://pagure.io/fedora-hubs/issue/133
+            */
+              !this.props.editMode &&
+              <CobWeb
+                cause={this.props.hub.config.archived ? "archived" : "old"}
+                mtime={this.props.hub.mtime}
+                />
+            }
+
+            <WidgetsColumn
+              position="left"
+              widgets={
+                this.props.widgets.left.map((widgetIdx) => (
+                  this.props.widgets.byId[widgetIdx]
+                ))
+              }
+              handleWidgetMoved={this.handleWidgetMoved}
+              />
+          </div>
+
+          <div className={`col-md-${this.props.hub.config.right_width}`}>
+            <WidgetsColumn
+              position="right"
+              widgets={
+                this.props.widgets.right.map((widgetIdx) => (
+                  this.props.widgets.byId[widgetIdx]
+                ))
+              }
+              handleWidgetMoved={this.handleWidgetMoved}
+              />
+          </div>
+        </div>
+
+        <WidgetConfigDialog />
+        <SSESource />
+        <NotifIcon />
+      </div>
+    );
+  }
+}
+WidgetsArea.propTypes = {
+  hub: PropTypes.object.isRequired,
+  widgets: PropTypes.object.isRequired,
+  editMode: PropTypes.bool,
+}
+
+
+const mapStateToProps = (state) => {
+  const confWidgetId = state.ui.widgetConfigDialogOpen;
+  return {
+    hub: state.entities.hub,
+    widgets: state.entities.widgets,
+    editMode: state.ui.widgetsEditMode,
+  }
+};
+
+export default connect(mapStateToProps)(WidgetsArea);
diff --git a/hubs/static/client/app/components/WidgetsColumn.js b/hubs/static/client/app/components/WidgetsColumn.js
new file mode 100644
index 0000000..7a4b25c
--- /dev/null
+++ b/hubs/static/client/app/components/WidgetsColumn.js
@@ -0,0 +1,59 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { moveWidget } from '../core/actions/widget';
+import WidgetsList from './WidgetsList';
+import AddWidget from './AddWidget';
+
+
+class WidgetsColumn extends React.Component {
+
+  propTypes: {
+    position: PropTypes.string.isRequired,
+    widgets: PropTypes.array.isRequired,
+    editMode: PropTypes.bool,
+  }
+
+  constructor(props) {
+    super(props);
+    this.handleWidgetMoved = this.handleWidgetMoved.bind(this);
+  }
+
+  handleWidgetMoved({oldIndex, newIndex}, e) {
+    if (oldIndex === newIndex) {
+      return;
+    }
+    this.props.dispatch(moveWidget(this.props.position, oldIndex, newIndex));
+  }
+
+  render() {
+    return (
+      <div className="WidgetsColumn">
+
+        {this.props.editMode &&
+          <AddWidget
+            position={this.props.position}
+            availableWidgetsUrl={this.props.availableWidgetsUrl}
+            />
+        }
+
+        <div id={`${this.props.position}_widgets`}>
+          <WidgetsList
+            widgets={this.props.widgets}
+            handleWidgetMoved={this.handleWidgetMoved}
+            />
+        </div>
+
+      </div>
+    );
+  }
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    editMode: state.ui.widgetsEditMode,
+  }
+};
+
+export default connect(mapStateToProps)(WidgetsColumn);
diff --git a/hubs/static/client/app/components/WidgetsList.js b/hubs/static/client/app/components/WidgetsList.js
new file mode 100644
index 0000000..137b120
--- /dev/null
+++ b/hubs/static/client/app/components/WidgetsList.js
@@ -0,0 +1,69 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import {SortableContainer, SortableElement} from 'react-sortable-hoc';
+import Widget from './Widget';
+
+
+class WidgetsList extends React.Component {
+  render() {
+    const WidgetComponent = this.props.component;
+    return (
+      <div className="Widgets">
+        {this.props.widgets.map((widget, index) => (
+          <WidgetComponent
+            key={widget.idx}
+            index={index}
+            widget={widget}
+            />
+        ))}
+      </div>
+    );
+  }
+}
+WidgetsList.propTypes = {
+  widgets: PropTypes.array.isRequired,
+  editMode: PropTypes.bool,
+  component: PropTypes.func,
+}
+WidgetsList.defaultProps = {
+  component: Widget,
+  editMode: false,
+}
+
+
+const SortableWidget = SortableElement(Widget);
+const SortableWidgetList = SortableContainer((props) => (
+  <WidgetsList component={SortableWidget} {...props} />
+));
+
+
+function EditableWidgetsList(props) {
+  if (props.editMode) {
+    return (
+      <SortableWidgetList
+        lockAxis="y"
+        onSortEnd={props.handleWidgetMoved}
+        helperClass="widget--dragged"
+        {...props}
+        />
+      );
+  } else {
+    return (<WidgetsList {...props} />);
+  }
+}
+EditableWidgetsList.propTypes = {
+  editMode: PropTypes.bool,
+}
+EditableWidgetsList.defaultProps = {
+  editMode: false,
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    editMode: state.ui.widgetsEditMode,
+  }
+};
+
+export default connect(mapStateToProps)(EditableWidgetsList);
diff --git a/hubs/static/client/app/components/feed/Actions.js b/hubs/static/client/app/components/feed/Actions.js
new file mode 100644
index 0000000..7219821
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Actions.js
@@ -0,0 +1,36 @@
+import React from 'react';
+
+
+export default class Actions extends React.Component {
+
+  render() {
+    var buttonProps = {
+      id: `save-${this.props.item.dom_id}`,
+      className: "btn btn-sm ",
+    };
+    var buttonText;
+
+    if (this.props.item.saved) {
+      buttonProps.className += "btn-success";
+      buttonProps.onClick = () => {
+        this.props.handleUnsave(this.props.item);
+      };
+      buttonText = "Saved";
+    } else {
+      buttonProps.className += "btn-primary";
+      buttonProps.onClick = () => {
+        this.props.handleSave(this.props.item);
+      };
+      buttonText = "Save";
+    }
+
+    return (
+      <div className="float-right">
+        <button {...buttonProps}>
+          {buttonText}
+        </button>
+      </div>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/components/feed/Actions.jsx b/hubs/static/client/app/components/feed/Actions.jsx
deleted file mode 100644
index 69890f1..0000000
--- a/hubs/static/client/app/components/feed/Actions.jsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import React from 'react';
-
-
-export default class Actions extends React.Component {
-
-  render() {
-    var buttonProps = {
-      id: `save-${this.props.item.dom_id}`,
-      className: "btn btn-sm ",
-    };
-    var buttonText;
-
-    if (this.props.item.saved) {
-      buttonProps.className += "btn-success";
-      buttonProps.onClick = () => {
-        this.props.handleUnsave(this.props.item);
-      };
-      buttonText = "Saved";
-    } else {
-      buttonProps.className += "btn-primary";
-      buttonProps.onClick = () => {
-        this.props.handleSave(this.props.item);
-      };
-      buttonText = "Save";
-    }
-
-    return (
-      <div className="float-right">
-        <button {...buttonProps}>
-          {buttonText}
-        </button>
-      </div>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/Feed.css b/hubs/static/client/app/components/feed/Feed.css
new file mode 100644
index 0000000..2286faa
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Feed.css
@@ -0,0 +1,11 @@
+.ItemsGetter .Spinner {
+    margin: 0 auto;
+}
+
+.Feed .media {
+  border-bottom: 1px solid rgba(0, 0, 0, .125);
+}
+
+.Feed .media:last-child {
+  border: 0
+}
diff --git a/hubs/static/client/app/components/feed/Feed.js b/hubs/static/client/app/components/feed/Feed.js
new file mode 100644
index 0000000..338eb2f
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Feed.js
@@ -0,0 +1,47 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import Panel from './Panel';
+import "./Feed.css";
+
+
+const messages = defineMessages({
+  no_items: {
+    id: "hubs.components.feed.no_items",
+    defaultMessage: "No items yet.",
+  },
+});
+
+
+export default class Feed extends React.Component {
+
+  render() {
+    var items = this.props.items || [];
+    items = items.map((item, idx) => {
+      return (
+        <Panel item={item} {...this.props} key={item.dom_id} />
+        );
+    });
+    return (
+      <div className="Feed">
+        { (items.length == 0 && this.props.loaded) ?
+          <FormattedMessage {...messages.no_items} tagName="i" />
+          :
+          items
+        }
+      </div>
+    );
+  }
+
+}
+
+
+Feed.propTypes = {
+  loaded: PropTypes.bool,
+};
+Feed.defaultProps = {
+  loaded: true,
+};
diff --git a/hubs/static/client/app/components/feed/Feed.jsx b/hubs/static/client/app/components/feed/Feed.jsx
deleted file mode 100644
index a11176e..0000000
--- a/hubs/static/client/app/components/feed/Feed.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import {
-  defineMessages,
-  FormattedMessage,
-  } from 'react-intl';
-import Panel from './Panel.jsx';
-
-
-const messages = defineMessages({
-  no_items: {
-    id: "hubs.components.feed.no_items",
-    defaultMessage: "No items yet.",
-  },
-});
-
-
-export default class Feed extends React.Component {
-
-  render() {
-    var items = this.props.items || [];
-    items = items.map((item, idx) => {
-      return (
-        <Panel item={item} {...this.props} key={item.dom_id} />
-        );
-    });
-    return (
-      <div className="component-feed">
-        { (items.length == 0 && this.props.loaded) ?
-          <FormattedMessage {...messages.no_items} tagName="i" />
-          :
-          items
-        }
-      </div>
-    );
-  }
-
-}
-
-
-Feed.propTypes = {
-  loaded: PropTypes.bool,
-};
-Feed.defaultProps = {
-  loaded: true,
-};
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/Icon.js b/hubs/static/client/app/components/feed/Icon.js
new file mode 100644
index 0000000..4ae2f25
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Icon.js
@@ -0,0 +1,18 @@
+import React from 'react';
+
+export default class Icon extends React.Component {
+  render() {
+    return (
+      <a href={this.props.item.link ? this.props.item.link : '#'}
+         target="_blank"
+         className="d-flex align-self-start mr-3"
+         >
+        <img
+          alt="User avatar"
+          className="square-32 img-circle"
+          src={this.props.item.secondary_icon}
+        />
+      </a>
+    );
+  }
+}
diff --git a/hubs/static/client/app/components/feed/Icon.jsx b/hubs/static/client/app/components/feed/Icon.jsx
deleted file mode 100644
index 9e0cfbe..0000000
--- a/hubs/static/client/app/components/feed/Icon.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-
-export default class Icon extends React.Component {
-  render() {
-    return (
-      <a href={this.props.item.link ? this.props.item.link : '#'}
-         target="_blank"
-         className="d-flex align-self-start mr-3"
-         >
-        <img
-          alt="User avatar"
-          className="square-32 img-circle"
-          src={this.props.item.secondary_icon}
-        />
-      </a>
-    );
-  }
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/ItemsGetter.js b/hubs/static/client/app/components/feed/ItemsGetter.js
new file mode 100644
index 0000000..ff0fb0e
--- /dev/null
+++ b/hubs/static/client/app/components/feed/ItemsGetter.js
@@ -0,0 +1,121 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import Spinner from "../Spinner";
+
+
+class ItemsGetter extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      isLoading: false,
+      errorMessage: null,
+    };
+    this.loadFromServer = this.loadFromServer.bind(this);
+    this.showErrorMessage = this.showErrorMessage.bind(this);
+    this.errorTimeout = null;
+  }
+
+  componentDidMount() {
+    this.loadFromServer();
+  }
+
+  componentWillUnmount() {
+    this.serverRequest.abort();
+  }
+
+  componentDidUpdate(prevProps, prevState) {
+    if (this.props.needsUpdate && !this.state.isLoading) {
+      this.loadFromServer();
+    }
+    if (this.props.useSSE) {
+      if (this.props.sseConnected && this.state.errorMessage) {
+        // Reconnected
+        if (this.errorTimeout) {
+          window.clearTimeout(this.errorTimeout);
+        }
+        this.setState({errorMessage: null});
+      } else if (!this.state.errorMessage && !this.props.sseConnected) {
+        // Disconnected
+        this.errorTimeout = window.setTimeout(this.showErrorMessage, 3000);
+      }
+    }
+  }
+
+  loadFromServer() {
+    if (this.props.onRequestStart) {
+      this.props.onRequestStart();
+    }
+    this.setState({isLoading: true});
+    if (this.serverRequest &&
+        this.serverRequest.readyState !== XMLHttpRequest.DONE) {
+      this.serverRequest.abort();
+    }
+    this.serverRequest = $.ajax({
+      url: this.props.url,
+      method: 'GET',
+      dataType: 'json',
+      cache: false,
+      success: (data, textStatus, jqXHR) => {
+        this.props.handleData(data.data);
+      },
+      error: (xhr, status, err) => {
+        console.error(status, err.toString());
+      },
+      complete: (xhr, status) => {
+        this.setState({isLoading: false});
+      },
+    });
+  }
+
+  showErrorMessage() {
+    let msg = null;
+    switch (this.props.sseReadyState) {
+      case 2:
+        msg = (
+          "Cannot auto-update the feed, you will have to refresh " +
+          "the page manually to see new elements."
+        );
+      case 0:
+        msg = (
+          "Reconnecting to the auto-update source..."
+        );
+    }
+    this.setState({errorMessage: msg});
+  }
+
+  render() {
+    return (
+      <div className="ItemsGetter">
+        {this.props.children}
+        { this.state.isLoading &&
+          <Spinner />
+        }
+        { this.state.errorMessage &&
+          <div className="alert alert-warning mt-3 mb-0">
+            {this.state.errorMessage}
+          </div>
+        }
+      </div>
+    );
+  }
+}
+ItemsGetter.propTypes = {
+  useSSE: PropTypes.bool,
+  needsUpdate: PropTypes.bool,
+}
+ItemsGetter.defaultProps = {
+  useSSE: false,
+  needsUpdate: false,
+}
+
+
+const mapStateToProps = (state) => {
+  return {
+    sseConnected: state.sse.connected,
+    sseReadyState: state.sse.readyState,
+  }
+};
+
+export default connect(mapStateToProps)(ItemsGetter);
diff --git a/hubs/static/client/app/components/feed/ItemsGetter.jsx b/hubs/static/client/app/components/feed/ItemsGetter.jsx
deleted file mode 100644
index 678f420..0000000
--- a/hubs/static/client/app/components/feed/ItemsGetter.jsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import React from 'react';
-
-
-export default class ItemsGetter extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      sseError: false,
-      loading: false,
-    };
-    this.sseSource = null;
-    this.setupSSESource = this.setupSSESource.bind(this);
-    this.tearDownSSESource = this.tearDownSSESource.bind(this);
-    this.handleSSEEvent = this.handleSSEEvent.bind(this);
-    this.handleSSEEventError = this.handleSSEEventError.bind(this);
-    this.handleSSEEventOpen = this.handleSSEEventOpen.bind(this);
-    this.loadFromServer = this.loadFromServer.bind(this);
-  }
-
-  componentDidMount() {
-    this.setupSSESource();
-    this.loadFromServer();
-  }
-
-  componentWillUnmount() {
-    this.serverRequest.abort();
-    this.tearDownSSESource();
-    window.removeEventListener("beforeunload", this.tearDownSSESource);
-  }
-
-  setupSSESource() {
-    if (!this.props.sse ||
-        !this.props.sse.eventName ||
-        !this.props.sse.shouldReload) {
-      // Auto-update is disabled.
-      return;
-    }
-
-    this.sseSource = document.sseSource;
-    if (!this.sseSource || this.sseSource.readyState === EventSource.CLOSED) {
-      this.handleSSEEventError();
-      return;
-    }
-
-    this.sseSource.addEventListener('open', this.handleSSEEventOpen);
-    this.sseSource.addEventListener('error', this.handleSSEEventError);
-    this.sseSource.addEventListener(
-      this.props.sse.eventName, this.handleSSEEvent);
-    // This is necessary to avoid the error message being displayed right
-    // before the user changes page.
-    // Pretty much like: https://bugzilla.mozilla.org/show_bug.cgi?id=833462
-    window.addEventListener("beforeunload", this.tearDownSSESource);
-  }
-
-  tearDownSSESource() {
-    if (!this.sseSource) { return; }
-    this.sseSource.removeEventListener(
-      this.props.sse.eventName, this.handleSSEEvent);
-    this.sseSource.removeEventListener('error', this.handleSSEEventError);
-    this.sseSource = null;
-  }
-
-  handleSSEEvent(e) {
-    if (this.props.sse.shouldReload(e.data)) {
-      this.loadFromServer();
-    }
-  }
-
-  handleSSEEventOpen(e) {
-    this.setState({sseError: false});
-  }
-
-  handleSSEEventError(e) {
-    if (this.sseSource.readyState === 2) {
-      // Connection closed.
-      this.setState({
-        sseError: ("Cannot auto-update the feed, you will have to refresh "
-                  +"the page manually to see new elements.")
-      });
-    } else if (this.sseSource.readyState === 0) {
-      // Reconnecting
-      this.setState({
-        sseError: "Reconnecting to the auto-update source...",
-      });
-    }
-  }
-
-  loadFromServer() {
-    this.setState({loading: true});
-    if (this.serverRequest &&
-        this.serverRequest.readyState !== XMLHttpRequest.DONE) {
-      this.serverRequest.abort();
-    }
-    this.serverRequest = $.ajax({
-      url: this.props.url,
-      method: 'GET',
-      dataType: 'json',
-      cache: false,
-      success: (data, textStatus, jqXHR) => {
-        this.props.handleData(data.data);
-      },
-      error: (xhr, status, err) => {
-        console.error(status, err.toString());
-      },
-      complete: (xhr, status) => {
-        this.setState({loading: false});
-      },
-    });
-  }
-
-  render() {
-    return (
-      <div>
-        {this.props.children}
-        <div
-          className="loading mx-auto"
-          style={{display: this.state.loading ? "block" : "none"}}
-          ></div>
-        { (this.state.sseError !== false) &&
-          <div className="alert alert-warning mt-3">
-            {this.state.sseError}
-          </div>
-        }
-      </div>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/Markup.js b/hubs/static/client/app/components/feed/Markup.js
new file mode 100644
index 0000000..f5a50f2
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Markup.js
@@ -0,0 +1,50 @@
+import React from 'react';
+import TimeAgo from 'react-timeago';
+
+
+export default class Markup extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.createMarkup = this.createMarkup.bind(this);
+  }
+
+  createMarkup(item) {
+    return { __html: item.markup || item.subtitle };
+  }
+
+  render() {
+    const timestamp = this.props.item.end_time || this.props.item.timestamp;
+    const submsgs = this.props.item.msg_ids;
+    var submessages = [];
+    if (submsgs && Object.keys(submsgs).length > 1) {
+      submessages = Object.keys(submsgs).map((msgid) => {
+        return (
+          <li key={msgid}>
+            <small dangerouslySetInnerHTML={this.createMarkup(submsgs[msgid])}></small>
+          </li>
+        );
+      });
+    }
+
+    return (
+      <div className="media-body align-self-start">
+        <span dangerouslySetInnerHTML={this.createMarkup(this.props.item)}></span>
+        {timestamp &&
+          <small className="text-muted ml-3">
+            <TimeAgo date={timestamp * 1000} />
+          </small>
+        }
+        {submessages.length !== 0 &&
+          <ul
+            className="submessages"
+            style={{display: this.props.detailsOpened ? "block" : "none" }}
+            >
+            {submessages}
+          </ul>
+        }
+      </div>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/components/feed/Markup.jsx b/hubs/static/client/app/components/feed/Markup.jsx
deleted file mode 100644
index 1ea749e..0000000
--- a/hubs/static/client/app/components/feed/Markup.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import TimeAgo from 'react-timeago';
-
-
-export default class Markup extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.createMarkup = this.createMarkup.bind(this);
-  }
-
-  createMarkup(item) {
-    return { __html: item.markup || item.subtitle };
-  }
-
-  render() {
-    const timestamp = this.props.item.end_time || this.props.item.timestamp;
-    const submsgs = this.props.item.msg_ids;
-    var submessages = [];
-    if (submsgs && Object.keys(submsgs).length > 1) {
-      submessages = Object.keys(submsgs).map((msgid) => {
-        return (
-          <li key={msgid}>
-            <small dangerouslySetInnerHTML={this.createMarkup(submsgs[msgid])}></small>
-          </li>
-        );
-      });
-    }
-
-    return (
-      <div className="media-body align-self-start">
-        <span dangerouslySetInnerHTML={this.createMarkup(this.props.item)}></span>
-        {timestamp &&
-          <small className="text-muted ml-3">
-            <TimeAgo date={timestamp * 1000} />
-          </small>
-        }
-        {submessages.length !== 0 &&
-          <ul
-            className="submessages"
-            style={{display: this.props.detailsOpened ? "block" : "none" }}
-            >
-            {submessages}
-          </ul>
-        }
-      </div>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/Panel.js b/hubs/static/client/app/components/feed/Panel.js
new file mode 100644
index 0000000..2dcee5b
--- /dev/null
+++ b/hubs/static/client/app/components/feed/Panel.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import Icon from './Icon';
+import Markup from './Markup';
+import Actions from './Actions';
+
+
+export default class Panel extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      detailsOpened: false,
+    }
+    this.toggleDetails = this.toggleDetails.bind(this);
+  }
+
+  toggleDetails(e) {
+    e.preventDefault();
+    this.setState((prevState, props) => (
+      {detailsOpened: !prevState.detailsOpened}
+    ));
+  }
+
+  render() {
+    return (
+      <div className="media py-3" id={this.props.item.id}>
+        <Icon item={this.props.item} />
+        <Markup
+          {...this.props}
+          detailsOpened={this.state.detailsOpened}
+          />
+        <div className="d-flex flex-column align-self-start ml-3 text-right">
+          { (this.props.handleSave || this.props.handleUnsave) &&
+            <Actions {...this.props} />
+          }
+          { (this.props.item.msg_ids &&
+             Object.keys(this.props.item.msg_ids).length > 1) &&
+            <div className="mt-auto">
+              <small>
+                <a href="#" onClick={this.toggleDetails}>details</a>
+              </small>
+            </div>
+          }
+        </div>
+      </div>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/components/feed/Panel.jsx b/hubs/static/client/app/components/feed/Panel.jsx
deleted file mode 100644
index 5be00e7..0000000
--- a/hubs/static/client/app/components/feed/Panel.jsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import React from 'react';
-import Icon from './Icon.jsx';
-import Markup from './Markup.jsx';
-import Actions from './Actions.jsx';
-
-
-export default class Panel extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      detailsOpened: false,
-    }
-    this.toggleDetails = this.toggleDetails.bind(this);
-  }
-
-  toggleDetails(e) {
-    e.preventDefault();
-    this.setState((prevState, props) => (
-      {detailsOpened: !prevState.detailsOpened}
-    ));
-  }
-
-  render() {
-    return (
-      <div className="media py-3" id={this.props.item.id}>
-        <Icon item={this.props.item} />
-        <Markup
-          {...this.props}
-          detailsOpened={this.state.detailsOpened}
-          />
-        <div className="d-flex flex-column align-self-start ml-3 text-right">
-          { (this.props.handleSave || this.props.handleUnsave) &&
-            <Actions {...this.props} />
-          }
-          { (this.props.item.msg_ids &&
-             Object.keys(this.props.item.msg_ids).length > 1) &&
-            <div className="mt-auto">
-              <small>
-                <a href="#" onClick={this.toggleDetails}>details</a>
-              </small>
-            </div>
-          }
-        </div>
-      </div>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/__tests__/Feed.test.js b/hubs/static/client/app/components/feed/__tests__/Feed.test.js
index 9f2e9be..501da7f 100644
--- a/hubs/static/client/app/components/feed/__tests__/Feed.test.js
+++ b/hubs/static/client/app/components/feed/__tests__/Feed.test.js
@@ -1,13 +1,13 @@
 /* eslint-env jasmine, jest */
 
-jest.unmock('../Feed.jsx');
-
 import React from 'react';
 import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
+import {mount} from 'enzyme';
+
+import Feed from '../Feed';
 
-import Feed from '../Feed.jsx';
-import Panel from '../Panel.jsx';
+jest.mock("../Panel");
+import Panel from '../Panel';
 
 describe('Feed', () => {
   const item = {
@@ -22,13 +22,9 @@ describe('Feed', () => {
   });
 
   it('should create the children', () => {
-    const component = TestUtils.renderIntoDocument(
+    const component = mount(
       <Feed items={items} />
     );
-    const node = ReactDOM.findDOMNode(component);
     expect(Panel.mock.calls.length).toEqual(3);
   });
 });
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/__tests__/Icon.test.js b/hubs/static/client/app/components/feed/__tests__/Icon.test.js
index 3cd5bb8..fe1c3cd 100644
--- a/hubs/static/client/app/components/feed/__tests__/Icon.test.js
+++ b/hubs/static/client/app/components/feed/__tests__/Icon.test.js
@@ -1,12 +1,9 @@
 /* eslint-env jasmine, jest */
 
-jest.unmock('../Icon.jsx');
-
 import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
+import {shallow} from 'enzyme';
 
-import Icon from '../Icon.jsx';
+import Icon from '../Icon';
 
 describe('Icon', () => {
   const item = {
@@ -15,24 +12,17 @@ describe('Icon', () => {
   };
 
   it('has the correct link', () => {
-    const component = TestUtils.renderIntoDocument(
+    const component = shallow(
       <Icon item={item} />
     );
     expect(component).toBeTruthy();
-    const node = ReactDOM.findDOMNode(component);
-    expect(node.getAttribute('href')).toEqual(item.link);
+    expect(component.find("a").prop('href')).toEqual(item.link);
   });
   it('has the correct image source', () => {
-    const component = TestUtils.renderIntoDocument(
+    const component = shallow(
       <Icon item={item} />
     );
     expect(component).toBeTruthy();
-
-    const node = ReactDOM.findDOMNode(component);
-    const image = node.querySelector('img');
-    expect(image.getAttribute('src')).toEqual(item.secondary_icon);
+    expect(component.find("img").prop('src')).toEqual(item.secondary_icon);
   });
 });
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/__tests__/Markup.test.js b/hubs/static/client/app/components/feed/__tests__/Markup.test.js
index 6305d51..97d9c93 100644
--- a/hubs/static/client/app/components/feed/__tests__/Markup.test.js
+++ b/hubs/static/client/app/components/feed/__tests__/Markup.test.js
@@ -1,12 +1,9 @@
 /* eslint-env jasmine, jest */
 
-jest.unmock('../Markup.jsx');
-
 import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
+import {shallow} from 'enzyme';
 
-import Markup from '../Markup.jsx';
+import Markup from '../Markup';
 
 describe('Markup', () => {
   const item = {
@@ -15,19 +12,13 @@ describe('Markup', () => {
   };
 
   it('should set the inner html of the markup', () => {
-    const component = TestUtils.renderIntoDocument(
+    const component = shallow(
       <Markup item={item} />
     );
     expect(component).toBeTruthy();
-
-    const node = ReactDOM.findDOMNode(component);
-    const markup = node.querySelector('span');
-
-    expect(markup.innerHTML).toEqual(item.markup);
+    expect(component.find("span").html()).toEqual(
+      "<span>" + item.markup + "</span>");
   });
 
   // we don't test TimeAgo, the library should have its own tests
 });
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/components/feed/__tests__/Panel.test.js b/hubs/static/client/app/components/feed/__tests__/Panel.test.js
index ff93dbe..abdea82 100644
--- a/hubs/static/client/app/components/feed/__tests__/Panel.test.js
+++ b/hubs/static/client/app/components/feed/__tests__/Panel.test.js
@@ -1,12 +1,9 @@
 /* eslint-env jasmine, jest */
 
-jest.unmock('../Panel.jsx');
-
 import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
+import {shallow} from 'enzyme';
 
-import Panel from '../Panel.jsx';
+import Panel from '../Panel';
 
 describe('Panel', () => {
   const item = {
@@ -21,29 +18,25 @@ describe('Panel', () => {
   };
 
   it('should render the actions block', () => {
-    const component = TestUtils.renderIntoDocument(
-      <Panel item={item} />
+    let node;
+    const component = shallow(
+      <Panel item={item} ref={(el) => {node = el; }} />
     );
     expect(component).toBeTruthy();
 
-    const node = ReactDOM.findDOMNode(component);
-    const block = node.querySelector('div.ml-3.text-right');
-
-    expect(block).toBeTruthy();
+    //const block = node.querySelector('div.ml-3.text-right');
+    expect(component.find("div.ml-3.text-right")).toBeTruthy();
   });
 
   it('should show the details link', () => {
-    const component = TestUtils.renderIntoDocument(
-      <Panel item={item} />
+    let node;
+    const component = shallow(
+      <Panel item={item} ref={(el) => {node = el; }} />
     );
     expect(component).toBeTruthy();
 
-    const node = ReactDOM.findDOMNode(component);
-    const details = node.querySelector('.text-right small a');
+    //const details = node.querySelector('.text-right small a');
 
-    expect(details).toBeTruthy();
+    expect(component.find(".text-right small a")).toBeTruthy();
   });
 });
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/App.js b/hubs/static/client/app/core/App.js
new file mode 100644
index 0000000..6c90b23
--- /dev/null
+++ b/hubs/static/client/app/core/App.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import {
+  connect,
+  Provider
+  } from 'react-redux';
+import { IntlProvider } from 'react-intl';
+import * as Pages from "../core/Pages";
+
+
+const PageContainer = connect(
+  (state) => ({pageName: state.ui.page})
+)(
+  (props) => {
+    if (!Pages[props.pageName]) {
+      console.error("No such page: " + props.pageName + ". Choose one of:", Object.keys(Pages).join(", "));
+      return null;
+    }
+    return React.createElement(Pages[props.pageName], {});
+  }
+);
+
+
+const App = (props) => {
+  return (
+    <Provider store={props.store}>
+      <IntlProvider locale={navigator.language}>
+        <PageContainer />
+      </IntlProvider>
+    </Provider>
+  );
+}
+export default App;
diff --git a/hubs/static/client/app/core/HubConfig.jsx b/hubs/static/client/app/core/HubConfig.jsx
deleted file mode 100644
index 01c079f..0000000
--- a/hubs/static/client/app/core/HubConfig.jsx
+++ /dev/null
@@ -1,250 +0,0 @@
-import React from 'react';
-import {
-  IntlProvider,
-  defineMessages,
-  FormattedMessage,
-  } from 'react-intl';
-import GeneralPanel from './HubConfigPanelGeneral.jsx';
-import UserPanel from './HubConfigPanelUser.jsx';
-import ChatPanel from './HubConfigPanelChat.jsx';
-import NotImplementedPanel from './HubConfigPanelNotImpl.jsx';
-import TabSet from '../components/TabSet.jsx';
-
-
-const messages = defineMessages({
-  title: {
-    id: "hubs.core.config.title",
-    defaultMessage: "Hub settings",
-  },
-  general: {
-    id: "hubs.core.config.general",
-    defaultMessage: "General",
-  },
-  owners: {
-    id: "hubs.core.config.owners",
-    defaultMessage: "Owners",
-  },
-  members: {
-    id: "hubs.core.config.members",
-    defaultMessage: "Members",
-  },
-  chat: {
-    id: "hubs.core.config.chat",
-    defaultMessage: "Chat",
-  },
-  other: {
-    id: "hubs.core.config.other",
-    defaultMessage: "Other",
-  },
-  close: {
-    id: "hubs.core.config.close",
-    defaultMessage: "Close",
-  },
-  save_changes: {
-    id: "hubs.core.config.save_changes",
-    defaultMessage: "Save changes",
-  },
-});
-
-
-
-export default class HubConfig extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      hubConfig: {},
-      generalConfig: {},
-      users: {owner: [], member: []},
-      dirty: false,
-      mustReload: false,  // the settings were changed at least once
-      error: null,
-      loading: false
-    };
-    this.serverRequest = null;
-    this.handleChange = this.handleChange.bind(this);
-    this.handleUserChange = this.handleUserChange.bind(this);
-    this.loadState = this.loadState.bind(this);
-    this.pushState = this.pushState.bind(this);
-  }
-
-  getRequestParams() {
-    return {
-      url: this.props.urls.config,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        if (data.status === "OK") {
-          this.setState({
-            hubConfig: data.result.hubconfig,
-            generalConfig: data.result.general,
-            users: data.result.users,
-            dirty: false,
-            error: null,
-          });
-        } else if (data.status === "ERROR") {
-          this.setState({error: data.message});
-        } else {
-          this.setState({
-            error: "Unknown status: " + data.status
-          });
-        }
-      }.bind(this),
-      error: function(xhr, status, err) {
-        var msg = err.toString();
-        if (!msg) { msg = "Error communicating with the server"; }
-        console.error(this.props.urls.config, status, msg);
-        this.setState({error: msg});
-      }.bind(this),
-      complete: function(xhr, status) {
-        this.setState({loading: false});
-      }.bind(this),
-    }
-  }
-
-  loadState() {
-    var params = this.getRequestParams();
-    params.method = "GET";
-    this.setState({loading: true});
-    this.serverRequest = $.ajax(params);
-  }
-
-  pushState(data, category) {
-    var params = this.getRequestParams();
-    params.method = "POST";
-    params.data = data;
-    params.url += "?category=" + category;
-    this.setState({loading: true});
-    this.serverRequest = $.ajax(params);
-  }
-
-  handleChange(e) {
-    var config = this.state.hubConfig;
-    config[e.target.name] = e.target.value;
-    this.setState({
-      hubConfig: config,
-      dirty: true,
-      mustReload: true,
-    }, function() {
-      window.clearTimeout(this.pushTimer);
-      this.pushTimer = window.setTimeout(
-        this.pushState, 1000, this.state.hubConfig, "config");
-    });
-  }
-
-  handleUserChange(username, role) {
-    var data = {username: username, role: role};
-    this.pushState(data, "role_change");
-  }
-
-  componentDidMount() {
-    this.loadState();
-  }
-
-  componentWillUnmount() {
-    if (this.serverRequest) { this.serverRequest.abort(); }
-    if (this.state.mustReload) {
-      // The configuration was changed but the current display may not
-      // reflect it (for example, the displayed summary may be the old one).
-      // The only way to make the changes visible is to reload the page.
-      window.location.reload(true);
-    }
-  }
-
-  render() {
-    return (
-      <IntlProvider locale={navigator.language}>
-        <div className="modal-dialog modal-lg" role="document">
-          <div className="modal-content">
-              <div className="modal-header">
-                <h5 className="modal-title">
-                  <FormattedMessage {...messages.title} />
-                </h5>
-                <button
-                  type="button"
-                  className="close"
-                  data-dismiss="modal"
-                  aria-label="Close"
-                  disabled={this.state.dirty}
-                  >
-                  <span aria-hidden="true">&times;</span>
-                </button>
-              </div>
-              <div className="modal-body p-0">
-                <TabSet
-                  tabWrapperProps={{className: "row pt-0"}}
-                  tabListClass="flex-md-column justify-content-center justify-content-md-start col-md-3 pt-2 pt-md-3 pb-md-4 pr-md-0 pl-md-2"
-                  tabLinkClass="my-md-2"
-                  tabContentClass="col-md-9 p-3 pb-4"
-                  >
-                  <GeneralPanel
-                    hubConfig={this.state.hubConfig}
-                    generalConfig={this.state.generalConfig}
-                    tabTitle={<FormattedMessage {...messages.general} />}
-                    handleChange={this.handleChange}
-                    loading={this.state.loading}
-                    />
-                  <UserPanel
-                    users={this.state.users.owner}
-                    generalConfig={this.state.generalConfig}
-                    role="owner"
-                    handleChange={this.handleUserChange}
-                    tabTitle={<FormattedMessage {...messages.owners} />}
-                    loading={this.state.loading}
-                    urls={this.props.urls}
-                    />
-                  <UserPanel
-                    users={this.state.users.member}
-                    generalConfig={this.state.generalConfig}
-                    role="member"
-                    handleChange={this.handleUserChange}
-                    tabTitle={<FormattedMessage {...messages.members} />}
-                    loading={this.state.loading}
-                    urls={this.props.urls}
-                    />
-                  <ChatPanel
-                    hubConfig={this.state.hubConfig}
-                    generalConfig={this.state.generalConfig}
-                    tabTitle={<FormattedMessage {...messages.chat} />}
-                    handleChange={this.handleChange}
-                    loading={this.state.loading}
-                    />
-                  <NotImplementedPanel
-                    tabTitle={<FormattedMessage {...messages.other} />}
-                    loading={this.state.loading}
-                    />
-                </TabSet>
-              </div>
-              <div className="modal-footer">
-                { this.state.error &&
-                  <div
-                    className="alert alert-danger my-0 mx-3 py-1 px-2"
-                    role="alert"
-                    >
-                    { this.state.error }
-                  </div>
-                }
-                <span
-                  className="loading"
-                  style={this.state.loading ? {display: "inline-block"} : {display: "none"}}
-                  ></span>
-                <button
-                  type="button"
-                  className="btn btn-secondary"
-                  data-dismiss="modal"
-                  disabled={this.state.dirty}
-                  >
-                  <FormattedMessage {...messages.close} />
-                </button>
-              </div>
-          </div>
-        </div>
-      </IntlProvider>
-    );
-  }
-
-}
-
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfigPanelChat.jsx b/hubs/static/client/app/core/HubConfigPanelChat.jsx
deleted file mode 100644
index e15a141..0000000
--- a/hubs/static/client/app/core/HubConfigPanelChat.jsx
+++ /dev/null
@@ -1,106 +0,0 @@
-import React from 'react';
-import {
-  defineMessages,
-  FormattedMessage,
-  } from 'react-intl';
-
-
-const messages = defineMessages({
-  title: {
-    id: "hubs.core.config.chat.title",
-    defaultMessage: "Chat Settings",
-  },
-  intro_1: {
-    id: "hubs.core.config.chat.intro1",
-    defaultMessage: (
-      "If your team or project has an IRC channel associated with it, you "
-     +"can connect this hub to it via the Hubs chat widget."
-     ),
-  },
-  intro_2: {
-    id: "hubs.core.config.chat.intro2",
-    defaultMessage: "Please indicate your team's IRC channel below:",
-  },
-  channel_name: {
-    id: "hubs.core.config.chat.channel_name",
-    defaultMessage: "Channel name",
-  },
-  example: {
-    id: "hubs.core.config.chat.example",
-    defaultMessage: "Example:",
-  },
-  network: {
-    id: "hubs.core.config.chat.network",
-    defaultMessage: "IRC network",
-  },
-});
-
-
-export default class ChatPanel extends React.Component {
-
-  render() {
-    var networks = [],
-        channel = "#",
-        stillLoading = (
-          typeof this.props.hubConfig.chat_channel === "undefined"
-        );
-
-    if (this.props.hubConfig.chat_channel) {
-      channel = "#" + this.props.hubConfig.chat_channel.replace(/^#*/, "");
-    }
-
-    if (this.props.generalConfig.chat_networks) {
-      networks = this.props.generalConfig.chat_networks.map(
-        function(network, index) {
-          return (
-            <option value={network.domain} key={network.domain}>
-              {network.name} - {network.domain}
-            </option>
-          );
-        }.bind(this)
-      );
-    }
-
-    return (
-      <form onSubmit={(e) => {e.preventDefault();}}>
-        <FormattedMessage {...messages.title} tagName="h3" />
-        <FormattedMessage {...messages.intro_1} tagName="p" />
-        <FormattedMessage {...messages.intro_2} tagName="p" />
-        <div className="form-group">
-          <label htmlFor="hub-settings-chat-channel">
-            <FormattedMessage {...messages.channel_name} />
-          </label>
-          <input
-            type="text" className="form-control" name="chat_channel"
-            id="hub-settings-chat-channel"
-            disabled={stillLoading}
-            onChange={this.props.handleChange}
-            value={channel}
-            />
-          <p className="form-text text-muted">
-            <FormattedMessage {...messages.example} tagName="strong" />
-            <span className="ml-2">#fedora-devel</span>
-          </p>
-        </div>
-        <div className="form-group">
-          <label htmlFor="hub-settings-chat-domain">
-            <FormattedMessage {...messages.network} />
-          </label>
-          <select
-            name="chat_domain" className="form-control"
-            id="hub-settings-chat-domain"
-            disabled={stillLoading}
-            onChange={this.props.handleChange}
-            value={this.props.hubConfig.chat_domain || ""}
-            >
-            {networks}
-          </select>
-        </div>
-      </form>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfigPanelGeneral.jsx b/hubs/static/client/app/core/HubConfigPanelGeneral.jsx
deleted file mode 100644
index 15d53ab..0000000
--- a/hubs/static/client/app/core/HubConfigPanelGeneral.jsx
+++ /dev/null
@@ -1,145 +0,0 @@
-import React from 'react';
-import {
-  defineMessages,
-  FormattedMessage,
-  FormattedHTMLMessage,
-  } from 'react-intl';
-
-
-const messages = defineMessages({
-  title: {
-    id: "hubs.core.config.general.title",
-    defaultMessage: "General Settings",
-  },
-  intro: {
-    id: "hubs.core.config.general.intro",
-    defaultMessage: "Change your global hub parameters here.",
-  },
-  summary: {
-    id: "hubs.core.config.general.summary",
-    defaultMessage: "Summary",
-  },
-  summary_help: {
-    id: "hubs.core.config.general.summary_help",
-    defaultMessage: "This text will be displayed at the top of the hub.",
-  },
-  left_width: {
-    id: "hubs.core.config.general.left_width",
-    defaultMessage: "Left width",
-  },
-  left_width_help: {
-    id: "hubs.core.config.general.left_width_help",
-    defaultMessage: (
-      "Change the proportions of you hub's columns by setting the width of "
-     +"the left column (the right column's width will be {right_width})."
-      ),
-  },
-  visibility: {
-    id: "hubs.core.config.general.visibility",
-    defaultMessage: "Visibility",
-  },
-  visibility_help: {
-    id: "hubs.core.config.general.visibility_help",
-    defaultMessage: (
-      "Public: the hub is visible to anyone.<br />"
-     +"Private: the hub is only visible to members.<br />"
-     +"Preview: some widgets can be made visible to logged-in users only."
-      ),
-  },
-  avatar: {
-    id: "hubs.core.config.general.avatar",
-    defaultMessage: "Avatar",
-  },
-  avatar_help: {
-    id: "hubs.core.config.general.avatar_help",
-    defaultMessage: "An URL to you hub's main image or logo."
-  },
-});
-
-
-export default class GeneralPanel extends React.Component {
-
-  render() {
-    var stillLoading = (typeof this.props.hubConfig.summary === "undefined");
-    var visibilities = this.props.generalConfig.hub_visibility || [];
-    return (
-      <form onSubmit={(e) => {e.preventDefault();}}>
-        <FormattedMessage {...messages.title} tagName="h3" />
-        <FormattedMessage {...messages.intro} tagName="p" />
-        <div className="form-group">
-          <label htmlFor="hub-settings-general-summary">
-            <FormattedMessage {...messages.summary} />
-          </label>
-          <input
-            type="text" className="form-control" name="summary"
-            id="hub-settings-general-summary"
-            disabled={stillLoading}
-            onChange={this.props.handleChange}
-            value={this.props.hubConfig.summary || ""}
-            />
-          <p className="form-text text-muted">
-            <FormattedMessage {...messages.summary_help} />
-          </p>
-        </div>
-        <div className="form-group">
-          <label htmlFor="hub-settings-general-leftwidth">
-            <FormattedMessage {...messages.left_width} />
-          </label>
-          <input
-            type="number" className="form-control" name="left_width"
-            id="hub-settings-general-leftwidth"
-            disabled={stillLoading}
-            min="1" max="11"
-            onChange={this.props.handleChange}
-            value={this.props.hubConfig.left_width || ""}
-            />
-          <p className="form-text text-muted">
-            <FormattedMessage
-              {...messages.left_width_help}
-              values={{right_width: 12 - (this.props.hubConfig.left_width || 8)}}
-              />
-          </p>
-        </div>
-        <div className="form-group">
-          <label htmlFor="hub-settings-general-visibility">
-            <FormattedMessage {...messages.visibility} />
-          </label>
-          <select
-            className="form-control" name="visibility"
-            value={this.props.hubConfig.visibility || ""}
-            onChange={this.props.handleChange}
-            disabled={stillLoading}
-            >
-            {visibilities.map(function(value) {
-              return (
-                <option value={value} key={value}>{value}</option>
-                );
-            })}
-          </select>
-          <p className="form-text text-muted">
-            <FormattedHTMLMessage {...messages.visibility_help} />
-          </p>
-        </div>
-        <div className="form-group">
-          <label htmlFor="hub-settings-general-avatar">
-            <FormattedMessage {...messages.avatar} />
-          </label>
-          <input
-            type="text" className="form-control" name="avatar"
-            id="hub-settings-general-avatar"
-            disabled={stillLoading}
-            onChange={this.props.handleChange}
-            value={this.props.hubConfig.avatar || ""}
-            />
-          <p className="form-text text-muted">
-            <FormattedMessage {...messages.avatar_help} />
-          </p>
-        </div>
-      </form>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfigPanelNotImpl.jsx b/hubs/static/client/app/core/HubConfigPanelNotImpl.jsx
deleted file mode 100644
index 31803be..0000000
--- a/hubs/static/client/app/core/HubConfigPanelNotImpl.jsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-
-
-export default class NotImplementedPanel extends React.Component {
-
-  render() {
-    return (
-      <div>
-        Not implemented yet.
-      </div>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/HubConfigPanelUser.jsx b/hubs/static/client/app/core/HubConfigPanelUser.jsx
deleted file mode 100644
index 7ef5175..0000000
--- a/hubs/static/client/app/core/HubConfigPanelUser.jsx
+++ /dev/null
@@ -1,186 +0,0 @@
-import React from 'react';
-import {
-  injectIntl,
-  defineMessages,
-  FormattedMessage,
-  } from 'react-intl';
-import CompletionInput from '../components/CompletionInput.jsx';
-
-
-const messages = defineMessages({
-  fullname: {
-    id: "hubs.core.config.users.fullname",
-    defaultMessage: "Full name",
-  },
-  username: {
-    id: "hubs.core.config.users.username",
-    defaultMessage: "Username",
-  },
-  change_role: {
-    id: "hubs.core.config.users.change_role",
-    defaultMessage: "Change role",
-  },
-  na: {
-    id: "hubs.core.config.users.na",
-    defaultMessage: "(N/A)",
-  },
-  remove_user: {
-    id: "hubs.core.config.users.remove_user",
-    defaultMessage: "(remove user)",
-  },
-  add_user: {
-    id: "hubs.core.config.users.add_user",
-    defaultMessage: "Add user...",
-  },
-  add: {
-    id: "hubs.core.config.users.add",
-    defaultMessage: "Add",
-  },
-});
-
-
-export default class UserPanel extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      addUsername: "",
-    };
-    this.handleAdd = this.handleAdd.bind(this);
-    this.handleAddInputChange = this.handleAddInputChange.bind(this);
-    this.handleChange = this.handleChange.bind(this);
-    this.filterSuggestedUsers = this.filterSuggestedUsers.bind(this);
-  }
-
-  handleAdd(e) {
-    e.preventDefault();
-    this.props.handleChange(this.state.addUsername, this.props.role);
-    this.setState({addUsername: ""});
-  }
-
-  handleAddInputChange(e) {
-    this.setState({
-      addUsername: e.target.value,
-    });
-  }
-
-  handleChange(e) {
-    e.preventDefault();
-    this.props.handleChange(e.target.name, e.target.value);
-  }
-
-  filterSuggestedUsers(user) {
-    // Only suggest non-members.
-    return (this.props.users.indexOf(user) === -1);
-  }
-
-  render() {
-    var users = this.props.users.map(function(user) {
-      return (
-        <tr key={user.username}>
-          <td>{user.fullname}</td>
-          <td>{user.username}</td>
-          <td>
-            {user.locked ?
-              <FormattedMessage {...messages.na} />
-            :
-              <select
-                name={user.username}
-                value={user.role}
-                className="form-control"
-                onChange={this.handleChange}
-                disabled={this.props.loading}
-                >
-                {this.props.generalConfig.roles.map(function(role) {
-                  return (
-                    <option value={role} key={role}>{role}</option>
-                    );
-                })}
-                <FormattedMessage {...messages.remove_user}>
-                  {(value) => ( <option value="">{value}</option> )}
-                </FormattedMessage>
-              </select>
-            }
-          </td>
-        </tr>
-        );
-    }.bind(this));
-
-    const IntlCompletionInput = injectIntl(function(props) {
-        return (
-          <CompletionInput
-            inputProps={{
-              name: "username",
-              placeholder: props.intl.formatMessage(messages.add_user),
-            }}
-            url={(
-              props.urls.suggestUsers
-              + "?exclude-role=" + props.role
-            )}
-            onChange={this.handleAddInputChange}
-            />
-            );
-    }.bind(this));
-
-    return (
-      <div>
-        <h3>{this.props.tabTitle}</h3>
-        {(this.props.role == "member") &&
-          <div>
-            <p className="text-muted">
-              [Membership requests will be shown here]
-            </p>
-            <hr />
-          </div>
-        }
-        <form
-          className="form-inline mb-3"
-          onSubmit={this.handleAdd}
-          >
-          <div className="form-group">
-            <FormattedMessage {...messages.add_user}>
-              {(message) => (
-                <CompletionInput
-                  inputProps={{
-                    name: "username",
-                    placeholder: message,
-                    value: this.state.addUsername,
-                  }}
-                  url={(
-                    this.props.urls.suggestUsers
-                    + "?exclude-role=" + this.props.role
-                  )}
-                  onChange={this.handleAddInputChange}
-                  />
-              )}
-            </FormattedMessage>
-            </div>
-          <button
-            className="btn btn-primary ml-3"
-            disabled={this.props.loading}
-            >
-            <FormattedMessage {...messages.add} />
-          </button>
-        </form>
-        {users.length !== 0 &&
-        <table className="table table-hover table-sm">
-          <thead>
-            <tr>
-              <FormattedMessage {...messages.fullname} tagName="th" />
-              <FormattedMessage {...messages.username} tagName="th" />
-              <FormattedMessage {...messages.change_role} tagName="th" />
-            </tr>
-          </thead>
-          <tbody>
-            {users}
-          </tbody>
-        </table>
-        }
-      </div>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/Hubs.js b/hubs/static/client/app/core/Hubs.js
deleted file mode 100644
index 6f24426..0000000
--- a/hubs/static/client/app/core/Hubs.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import HubConfig from './HubConfig.jsx';
-import Streams from './Streams.jsx';
-import ReconnectingEventSource from "reconnecting-eventsource";
-
-module.exports = {HubConfig, Streams, ReconnectingEventSource}
diff --git a/hubs/static/client/app/core/Pages.js b/hubs/static/client/app/core/Pages.js
new file mode 100644
index 0000000..def36e4
--- /dev/null
+++ b/hubs/static/client/app/core/Pages.js
@@ -0,0 +1,26 @@
+import React from 'react';
+import {
+  makeLoadable,
+  makeLoadingComponent
+} from '../core/utils';
+
+
+const PageLoadingComponent = makeLoadingComponent(
+  "Loading...",
+  "Sorry, there was a problem loading the page."
+);
+
+
+let Hub = makeLoadable(
+  () => import(/* webpackChunkName: "page-hub" */ '../components/HubPage'),
+  PageLoadingComponent
+);
+let Streams = makeLoadable(
+  () => import(/* webpackChunkName: "page-streams" */ '../components/StreamsPage'),
+  PageLoadingComponent
+);
+
+//Hub = require('../components/HubPage').default;
+//Streams = require('../components/StreamsPage').default;
+
+export {Hub, Streams};
diff --git a/hubs/static/client/app/core/Streams.jsx b/hubs/static/client/app/core/Streams.jsx
deleted file mode 100644
index a681951..0000000
--- a/hubs/static/client/app/core/Streams.jsx
+++ /dev/null
@@ -1,167 +0,0 @@
-import React from 'react';
-import {
-  IntlProvider,
-  defineMessages,
-  FormattedMessage,
-  } from 'react-intl';
-import TabSet from '../components/TabSet.jsx';
-import ItemsGetter from '../components/feed/ItemsGetter.jsx';
-import Feed from '../components/feed/Feed.jsx';
-
-
-export default class Streams extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      notifItems: [],
-      savedItems: [],
-    };
-    this.handleStreamData = this.handleStreamData.bind(this);
-    this.handleSavedData = this.handleSavedData.bind(this);
-    this.handleSave = this.handleSave.bind(this);
-    this.handleUnsave = this.handleUnsave.bind(this);
-  }
-
-  handleStreamData(data) {
-    this.setState({notifItems: data});
-  }
-
-  handleSavedData(data) {
-    this.setState({savedItems: data});
-  }
-
-  handleSave(item) {
-    if (!this.props.urls.saved) { return; }
-    const payload = {
-      link: item.link,
-      markup: item.markup,
-      secondary_icon: item.secondary_icon,
-      dom_id: item.dom_id,
-    };
-    $.ajax({
-      type: 'POST',
-      url: this.props.urls.saved,
-      data: JSON.stringify(payload),
-      contentType: 'application/json',
-      success: (data) => {
-        this.setState((prevState, props) => {
-          prevState.savedItems.push(data.data);
-          return {savedItems: prevState.savedItems};
-        });
-      },
-    });
-  }
-
-  handleUnsave(item) {
-    if (!this.props.urls.saved) { return; }
-    var updateSavedItems = (item) => {
-      this.setState((prevState, props) => {
-        var items = prevState.savedItems.filter(
-          (currentItem) => (currentItem.dom_id !== item.dom_id)
-        );
-        return {savedItems: items};
-      });
-    };
-    if (item.idx) {
-      // Already saved
-      $.ajax({
-        type: 'DELETE',
-        url: `${this.props.urls.saved}${item.idx}/`,
-        success: () => { updateSavedItems(item) },
-      });
-    } else {
-      updateSavedItems(item);
-    }
-  }
-
-  render() {
-    // Add saved state.
-    var savedItemsIds = this.state.savedItems.map((item) => {
-      return item.dom_id;
-    });
-    var notifs = this.state.notifItems.map((item) => {
-      item.saved = (savedItemsIds.indexOf(item.dom_id) !== -1);
-      return item;
-    });
-
-    return (
-      <IntlProvider locale={navigator.language}>
-        <TabSet tabListClass="mb-3">
-          <FeedPanel
-            username={this.props.username}
-            tabTitle="My Stream"
-            >
-            <ItemsGetter
-              url={this.props.urls.content}
-              sse={{
-                eventName: "hubs:new-notification",
-                shouldReload: (username) => (username === this.props.username),
-              }}
-              handleData={this.handleStreamData}
-              >
-              <Feed
-                items={notifs}
-                handleSave={this.handleSave}
-                handleUnsave={this.handleUnsave}
-                />
-            </ItemsGetter>
-          </FeedPanel>
-          <FeedPanel
-            username={this.props.username}
-            tabTitle="My Actions"
-            >
-            <Feed
-              items={this.state.notifItems}
-              />
-          </FeedPanel>
-          <FeedPanel
-            username={this.props.username}
-            tabTitle="Saved Notifications"
-            >
-            <ItemsGetter
-              url={this.props.urls.saved}
-              handleData={this.handleSavedData}
-              >
-              <Feed
-                items={this.state.savedItems}
-                handleUnsave={this.handleUnsave}
-                />
-            </ItemsGetter>
-          </FeedPanel>
-        </TabSet>
-      </IntlProvider>
-    );
-  }
-}
-
-
-class FeedPanel extends React.Component {
-
-  render() {
-    const filters_url = `https://apps.fedoraproject.org/notifications/${this.props.username}.id.fedoraproject.org/`;
-
-    return (
-      <div>
-        <div className="input-group">
-          <input
-            type="search" className="form-control"
-            placeholder="Search this activity stream..."
-            aria-describedby="searchform-addon" />
-          <span className="input-group-addon">
-            <span><i className="fa fa-search" aria-hidden="true"></i></span>
-          </span>
-        </div>
-        <br/>
-        <div className="alert alert-warning" role="alert">
-          This stream is filtered. <a href={filters_url} target="_blank">View Filters</a>
-        </div>
-        {this.props.children}
-      </div>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/core/actions/flashMessages.js b/hubs/static/client/app/core/actions/flashMessages.js
new file mode 100644
index 0000000..2333032
--- /dev/null
+++ b/hubs/static/client/app/core/actions/flashMessages.js
@@ -0,0 +1,19 @@
+/*
+ * Messages
+ */
+
+export const ADD_FLASH_MESSAGE = "ADD_FLASH_MESSAGE";
+export function addFlashMessage(text, msgType) {
+  return {
+    type: ADD_FLASH_MESSAGE,
+    text, msgType
+  }
+}
+
+export const CLOSE_FLASH_MESSAGE = "CLOSE_FLASH_MESSAGE";
+export function closeFlashMessage(index) {
+  return {
+    type: CLOSE_FLASH_MESSAGE,
+    index
+  }
+}
diff --git a/hubs/static/client/app/core/actions/hub.js b/hubs/static/client/app/core/actions/hub.js
new file mode 100644
index 0000000..6099d2e
--- /dev/null
+++ b/hubs/static/client/app/core/actions/hub.js
@@ -0,0 +1,81 @@
+import { apiCall } from '../utils';
+import { addFlashMessage } from './flashMessages';
+
+
+/* GET */
+
+export const HUB_FETCH_REQUEST = 'HUB_FETCH_REQUEST';
+export const HUB_FETCH_SUCCESS = 'HUB_FETCH_SUCCESS';
+export const HUB_FETCH_FAILURE = 'HUB_FETCH_FAILURE';
+
+function requestHub() {
+  return {
+    type: HUB_FETCH_REQUEST,
+  }
+}
+
+function receiveHub(hub) {
+  return {
+    type: HUB_FETCH_SUCCESS,
+    hub: hub,
+    receivedAt: Date.now()
+  }
+}
+
+function hubRequestFailed() {
+  return {
+    type: HUB_FETCH_FAILURE,
+  }
+}
+
+export function fetchHub() {
+  return (dispatch, getState) => {
+    let url = getState().urls.hubConfig;
+    dispatch(requestHub());
+    return apiCall(url).then(
+      hub => dispatch(receiveHub(hub)),
+      error => {
+        dispatch(addFlashMessage(error.message, "error"));
+        return hubRequestFailed();
+      }
+    );
+  }
+}
+
+
+/* PUT */
+
+export const HUB_PUT_REQUEST = 'HUB_PUT_REQUEST';
+export const HUB_PUT_FAILURE = 'HUB_PUT_FAILURE';
+
+function putHub(config, users) {
+  return {
+    type: HUB_PUT_REQUEST,
+    config, users
+  }
+}
+
+function putHubFailure(message) {
+  return {
+    type: HUB_PUT_FAILURE,
+    message
+  }
+}
+
+
+export function saveHub(config, users) {
+  return (dispatch, getState) => {
+    let url = getState().urls.hubConfig;
+    dispatch(putHub(config, users));
+    const body = JSON.stringify({config, users});
+    return apiCall(url, {method: "PUT", body}).then(
+      result => {
+        dispatch(addFlashMessage("Configuration updated", "success"));
+        return dispatch(fetchHub());
+      },
+      error => {
+        dispatch(addFlashMessage(error.message, "error"));
+        return putHubFailure(error.message);
+      })
+  }
+}
diff --git a/hubs/static/client/app/core/actions/sse.js b/hubs/static/client/app/core/actions/sse.js
new file mode 100644
index 0000000..6fc4a66
--- /dev/null
+++ b/hubs/static/client/app/core/actions/sse.js
@@ -0,0 +1,40 @@
+export const SSE_CONNECTED = 'SSE_CONNECTED';
+export const SSE_DISCONNECTED = 'SSE_DISCONNECTED';
+
+
+export function sseConnected(source) {
+  return {
+    type: SSE_CONNECTED,
+    readyState: source.readyState
+  };
+}
+
+export function sseDisconnected(source) {
+  return {
+    type: SSE_DISCONNECTED,
+    readyState: source.readyState
+  };
+}
+
+
+export const WIDGET_NEEDS_UPDATE = 'WIDGET_NEEDS_UPDATE';
+export const NEW_NOTIFICATION = 'NEW_NOTIFICATION';
+
+export function sseEvent(type, data) {
+  switch (type) {
+    case "hubs:widget-updated":
+      const widgetId = data;
+      return {
+        type: WIDGET_NEEDS_UPDATE,
+        widgetId,
+      };
+    case "hubs:new-notification":
+      // TODO: implement the reducers for this action
+      const username = data;
+      return {
+        type: NEW_NOTIFICATION,
+        username,
+      };
+  }
+}
+
diff --git a/hubs/static/client/app/core/actions/stream.js b/hubs/static/client/app/core/actions/stream.js
new file mode 100644
index 0000000..a8dc405
--- /dev/null
+++ b/hubs/static/client/app/core/actions/stream.js
@@ -0,0 +1,16 @@
+export const STREAM_WILL_UPDATE = 'STREAM_WILL_UPDATE';
+export const STREAM_DID_UPDATE = 'STREAM_DID_UPDATE';
+
+export function streamWillUpdate() {
+  // TODO: implement the reducers for this action
+  return {
+    type: STREAM_WILL_UPDATE,
+  };
+}
+
+export function streamDidUpdate() {
+  // TODO: implement the reducers for this action
+  return {
+    type: STREAM_DID_UPDATE,
+  };
+}
diff --git a/hubs/static/client/app/core/actions/widget.js b/hubs/static/client/app/core/actions/widget.js
new file mode 100644
index 0000000..e7784a4
--- /dev/null
+++ b/hubs/static/client/app/core/actions/widget.js
@@ -0,0 +1,204 @@
+import { apiCall } from '../utils';
+import { addFlashMessage } from './flashMessages';
+import { fetchWidgets } from "./widgets";
+
+
+/* Update status */
+
+export const WIDGET_WILL_UPDATE = 'WIDGET_WILL_UPDATE'
+export const WIDGET_DID_UPDATE = 'WIDGET_DID_UPDATE'
+
+export function widgetWillUpdate(widgetId) {
+  return {
+    type: WIDGET_WILL_UPDATE,
+    widgetId,
+    receivedAt: Date.now()
+  }
+}
+
+export function widgetDidUpdate(widgetId) {
+  return {
+    type: WIDGET_DID_UPDATE,
+    widgetId,
+    receivedAt: Date.now()
+  }
+}
+
+
+/* PUT config */
+
+export const WIDGET_PUT_REQUEST = 'WIDGET_PUT_REQUEST';
+export const WIDGET_PUT_SUCCESS = 'WIDGET_PUT_SUCCESS';
+export const WIDGET_PUT_FAILURE = 'WIDGET_PUT_FAILURE';
+
+function putConfigRequest(widgetId, config) {
+  return {
+    type: WIDGET_PUT_REQUEST,
+    widgetId, config
+  }
+}
+function putConfigSuccess(widgetId, widgetProps) {
+  return {
+    type: WIDGET_PUT_SUCCESS,
+    widgetId, widgetProps
+  }
+}
+function putConfigSucceeded(widgetId) {
+  return (dispatch, getState) => {
+    const state = getState();
+    let url = state.entities.widgets.byId[widgetId].selfUrl;
+    return apiCall(url).then(
+      (widgetProps) => (dispatch(putConfigSuccess(widgetId, widgetProps))),
+      error => (putConfigFailure(widgetId, error.message))
+    );
+  }
+}
+function putConfigFailure(widgetId, message) {
+  return {
+    type: WIDGET_PUT_FAILURE,
+    widgetId, message
+  }
+}
+
+export function saveConfig(widgetId, config) {
+  return (dispatch, getState) => {
+    let url = getState().entities.widgets.byId[widgetId].selfUrl;
+    dispatch(putConfigRequest(widgetId, config));
+    const body = JSON.stringify({config});
+    return apiCall(url, {method: "PUT", body}).then(
+      result => {
+        dispatch(addFlashMessage("Widget configuration changed.", "success"));
+        return dispatch(putConfigSucceeded(widgetId));
+      },
+      error => {
+        dispatch(addFlashMessage(error.message, "error"));
+        return putConfigFailure(error.message);
+      })
+  }
+}
+
+
+
+/* DELETE */
+
+export const WIDGET_DELETE_SUCCESS = 'WIDGET_DELETE_SUCCESS';
+
+function widgetDeleted(widgetId, config) {
+  return {
+    type: WIDGET_DELETE_SUCCESS,
+    widgetId,
+  }
+}
+
+export function deleteWidget(widgetId) {
+  return (dispatch, getState) => {
+    let url = getState().entities.widgets.byId[widgetId].selfUrl;
+    return apiCall(url, {method: "DELETE"}).then(
+      result => {
+        dispatch(addFlashMessage("Widget removed.", "success"));
+        return dispatch(widgetDeleted(widgetId));
+      },
+      error => {
+        return dispatch(addFlashMessage(error.message, "error"));
+      })
+  }
+}
+
+
+
+/* Create (POST) */
+
+export const HUB_WIDGETS_ADD_REQUEST = 'HUB_WIDGETS_ADD_REQUEST';
+export const HUB_WIDGETS_ADD_FAILURE = 'HUB_WIDGETS_ADD_FAILURE';
+
+function widgetAddRequest(name, config, position) {
+  return {
+    type: HUB_WIDGETS_ADD_REQUEST,
+    name, config, position
+  }
+}
+function widgetAddFailure(name, message) {
+  return {
+    type: HUB_WIDGETS_ADD_FAILURE,
+    name, message
+  }
+}
+
+
+export function addWidget(name, config, position) {
+  return (dispatch, getState) => {
+    const state = getState();
+    let url = state.urls.widgets;
+    dispatch(widgetAddRequest(name, config));
+    const body = JSON.stringify({name, config, position});
+    return apiCall(url, {method: "POST", body}).then(
+      result => {
+        dispatch(addFlashMessage("Widget added.", "success"));
+        return dispatch(fetchWidgets());
+      },
+      error => {
+        dispatch(addFlashMessage(error.message, "error"));
+        return widgetAddFailure(error.message);
+      })
+  }
+}
+
+
+
+/* Move */
+
+export const WIDGET_MOVE_REQUEST = 'WIDGET_MOVE_REQUEST'
+export const WIDGET_MOVE_FAILURE = 'WIDGET_MOVE_FAILURE'
+
+
+function moveWidgetRequest(position, oldIndex, newIndex) {
+  return {
+    type: WIDGET_MOVE_REQUEST,
+    position, oldIndex, newIndex
+  }
+}
+function moveWidgetFailure(position, oldIndex, newIndex, message) {
+  return {
+    type: WIDGET_MOVE_FAILURE,
+    position, oldIndex, newIndex, message
+  }
+}
+
+export function moveWidget(position, oldIndex, newIndex) {
+  return (dispatch, getState) => {
+    const state = getState();
+    const widgetId = state.entities.widgets[position][oldIndex];
+    const widget = state.entities.widgets.byId[widgetId];
+    console.log("Moving widget", widget.name, "at index", oldIndex, "to", newIndex);
+    dispatch(moveWidgetRequest(position, oldIndex, newIndex));
+    const body = JSON.stringify({index: newIndex});
+    return apiCall(widget.selfUrl, {method: "PUT", body}).then(
+      result => {
+        return dispatch(fetchWidgets());
+      },
+      error => {
+        return dispatch(moveWidgetFailure(position, oldIndex, newIndex, e.message));
+      })
+  }
+}
+
+
+
+/* UI */
+
+export const WIDGET_OPEN_CONFIG = 'WIDGET_OPEN_CONFIG';
+export const WIDGET_CLOSE_CONFIG = 'WIDGET_CLOSE_CONFIG';
+
+export function openConfigDialog(widgetId) {
+  return {
+    type: WIDGET_OPEN_CONFIG,
+    widgetId,
+  }
+}
+
+export function closeConfigDialog(widgetId) {
+  return {
+    type: WIDGET_CLOSE_CONFIG,
+    widgetId,
+  }
+}
diff --git a/hubs/static/client/app/core/actions/widgets.js b/hubs/static/client/app/core/actions/widgets.js
new file mode 100644
index 0000000..4a4abaf
--- /dev/null
+++ b/hubs/static/client/app/core/actions/widgets.js
@@ -0,0 +1,104 @@
+import { apiCall } from '../utils';
+import { addFlashMessage } from './flashMessages';
+
+
+/* GET */
+
+export const HUB_WIDGETS_FETCH_REQUEST = 'HUB_WIDGETS_FETCH_REQUEST'
+export const HUB_WIDGETS_FETCH_SUCCESS = 'HUB_WIDGETS_FETCH_SUCCESS'
+export const HUB_WIDGETS_FETCH_FAILURE = 'HUB_WIDGETS_FETCH_FAILURE'
+
+
+function requestWidgets() {
+  return {
+    type: HUB_WIDGETS_FETCH_REQUEST,
+  }
+}
+
+function receiveWidgets(widgets) {
+  return {
+    type: HUB_WIDGETS_FETCH_SUCCESS,
+    widgets: widgets,
+    receivedAt: Date.now()
+  }
+}
+
+function widgetsRequestFailed() {
+  return {
+    type: HUB_WIDGETS_FETCH_FAILURE,
+  }
+}
+
+
+export function fetchWidgets() {
+  return (dispatch, getState) => {
+    let url = getState().urls.widgets;
+    dispatch(requestWidgets());
+    return apiCall(url).then(
+      widgets => dispatch(receiveWidgets(widgets)),
+      error => {
+        dispatch(addFlashMessage(error.message, "error"));
+        return widgetsRequestFailed();
+      }
+    );
+  }
+}
+
+
+
+/* Get list of widgets */
+
+export const HUB_WIDGETS_AVAIL_REQUEST = 'HUB_WIDGETS_AVAIL_REQUEST';
+export const HUB_WIDGETS_AVAIL_SUCCESS = 'HUB_WIDGETS_AVAIL_SUCCESS';
+export const HUB_WIDGETS_AVAIL_FAILURE = 'HUB_WIDGETS_AVAIL_FAILURE';
+
+function widgetsAvailRequest() {
+  return {
+    type: HUB_WIDGETS_AVAIL_REQUEST,
+  }
+}
+function widgetsAvailSuccess(widgets) {
+  return {
+    type: HUB_WIDGETS_AVAIL_SUCCESS,
+    widgets
+  }
+}
+function widgetsAvailFailure(message) {
+  return {
+    type: HUB_WIDGETS_AVAIL_FAILURE,
+    message
+  }
+}
+
+
+export function getAvailableWidgets() {
+  return (dispatch, getState) => {
+    const state = getState();
+    if (
+      state.entities.availableWidgets.left.length > 0 ||
+      state.entities.availableWidgets.right.length > 0) {
+      return Promise.resolve();  // Already in the cache
+    }
+    let url = state.urls.availableWidgets;
+    dispatch(widgetsAvailRequest());
+    return apiCall(url).then(
+      widgets => {
+        return dispatch(widgetsAvailSuccess(widgets));
+      },
+      error => {
+        dispatch(addFlashMessage(error.message, "error"));
+        return widgetsAvailFailure(error.message);
+      })
+  }
+}
+
+
+/* Edit mode */
+
+export const HUB_WIDGETS_EDIT_MODE = 'HUB_WIDGETS_EDIT_MODE'
+export function setEditMode(editMode) {
+  return {
+    type: HUB_WIDGETS_EDIT_MODE,
+    editMode
+  }
+}
diff --git a/hubs/static/client/app/core/index.js b/hubs/static/client/app/core/index.js
new file mode 100644
index 0000000..a6cbb81
--- /dev/null
+++ b/hubs/static/client/app/core/index.js
@@ -0,0 +1,27 @@
+/* Add the ES6 Promise polyfill because all browsers don't have it yet. */
+import 'babel-polyfill';
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { createStore, applyMiddleware } from 'redux';
+import thunk from 'redux-thunk';
+import rootReducer from './reducers';
+import App from "./App";
+
+
+export function setupPage(elementId, initialState) {
+
+  const store = createStore(
+    rootReducer,
+    initialState,
+    applyMiddleware(thunk)
+  );
+  //store.subscribe(() =>
+  //  console.log(store.getState())
+  //)
+  ReactDOM.render(
+    <App store={store} />,
+    document.getElementById(elementId)
+    );
+
+}
diff --git a/hubs/static/client/app/core/reducers/flashMessages.js b/hubs/static/client/app/core/reducers/flashMessages.js
new file mode 100644
index 0000000..ae961a0
--- /dev/null
+++ b/hubs/static/client/app/core/reducers/flashMessages.js
@@ -0,0 +1,24 @@
+import {
+  ADD_FLASH_MESSAGE,
+  CLOSE_FLASH_MESSAGE
+} from '../actions/flashMessages';
+
+
+export default function flashMessages(state=[], action) {
+  switch (action.type) {
+    case ADD_FLASH_MESSAGE:
+      return [
+        ...state,
+        {
+          msg: action.text,
+          type: action.msgType
+        }
+      ];
+    case CLOSE_FLASH_MESSAGE:
+      let stateCopy = state.slice();
+      stateCopy.splice(action.index, 1);
+      return stateCopy;
+    default:
+      return state
+  }
+}
diff --git a/hubs/static/client/app/core/reducers/hub.js b/hubs/static/client/app/core/reducers/hub.js
new file mode 100644
index 0000000..ab788ed
--- /dev/null
+++ b/hubs/static/client/app/core/reducers/hub.js
@@ -0,0 +1,56 @@
+import {
+  HUB_FETCH_REQUEST,
+  HUB_FETCH_SUCCESS,
+  HUB_FETCH_FAILURE,
+  HUB_PUT_REQUEST,
+  HUB_PUT_FAILURE,
+  } from '../actions/hub';
+
+
+export function hubReducer(
+  state={
+    name: null,
+    isLoading: false,
+    old: {},
+  },
+  action
+) {
+  switch (action.type) {
+    case HUB_FETCH_REQUEST:
+      return {
+        ...state,
+        isLoading: true
+      };
+    case HUB_FETCH_SUCCESS:
+      return {
+        ...state,
+        ...action.hub,
+        isLoading: false,
+        old: {}
+      };
+    case HUB_FETCH_FAILURE:
+      return {
+        ...state,
+        isLoading: false
+      };
+    case HUB_PUT_REQUEST:
+      return {
+        ...state,
+        isLoading: true,
+        // Optimistic update
+        config: action.config,
+        users: action.users,
+        old: {config: state.config, users: state.users},
+      };
+    case HUB_PUT_FAILURE:
+      return {
+        ...state,
+        isLoading: false,
+        // Optimism failed... ;-(
+        config: state.old.config,
+        users: state.old.users,
+      };
+    default:
+      return state
+  }
+}
diff --git a/hubs/static/client/app/core/reducers/index.js b/hubs/static/client/app/core/reducers/index.js
new file mode 100644
index 0000000..3d4e9df
--- /dev/null
+++ b/hubs/static/client/app/core/reducers/index.js
@@ -0,0 +1,47 @@
+import { combineReducers } from 'redux';
+import flashMessages from "./flashMessages";
+import sseReducer from "./sse";
+import {
+  hubReducer,
+  hubEditMode
+  } from "./hub";
+import {
+  widgetsReducer,
+  widgetsEditMode,
+  widgetConfigDialogOpen,
+  availableWidgetsReducer,
+  } from "./widgets";
+
+
+const entities = combineReducers({
+  hub: hubReducer,
+  widgets: widgetsReducer,
+  availableWidgets: availableWidgetsReducer,
+});
+
+
+const ui = combineReducers({
+  page: noop,
+  flashMessages,
+  widgetsEditMode,
+  widgetConfigDialogOpen,
+  leftMenu: noop,
+});
+
+
+function noop(state=null, action) {
+  return state;
+}
+
+
+const rootReducer = combineReducers({
+  flashMessages,
+  sse: sseReducer,
+  globalConfig: noop,
+  urls: noop,
+  currentUser: noop,
+  ui,
+  entities,
+});
+
+export default rootReducer;
diff --git a/hubs/static/client/app/core/reducers/sse.js b/hubs/static/client/app/core/reducers/sse.js
new file mode 100644
index 0000000..fb2b7d9
--- /dev/null
+++ b/hubs/static/client/app/core/reducers/sse.js
@@ -0,0 +1,32 @@
+import {
+  SSE_CONNECTED,
+  SSE_DISCONNECTED
+} from '../actions/sse';
+
+
+export default function sseReducer(state={
+  connected: false,
+  readyState: 2
+}, action) {
+  switch (action.type) {
+    case SSE_CONNECTED:
+      if (state.connected) {
+        return state;  // No change
+      }
+      return {
+        connected: true,
+        readyState: action.readyState,
+      };
+    case SSE_DISCONNECTED:
+      if (!state.connected) {
+        return state;  // No change
+      }
+      return {
+        connected: false,
+        readyState: action.readyState,
+      };
+    default:
+      return state
+  }
+}
+
diff --git a/hubs/static/client/app/core/reducers/widget.js b/hubs/static/client/app/core/reducers/widget.js
new file mode 100644
index 0000000..524e024
--- /dev/null
+++ b/hubs/static/client/app/core/reducers/widget.js
@@ -0,0 +1,29 @@
+import {
+  WIDGET_PUT_REQUEST, WIDGET_PUT_SUCCESS, WIDGET_PUT_FAILURE,
+  } from '../actions/widget';
+import { WIDGET_NEEDS_UPDATE } from '../actions/sse';
+
+
+export default function singleWidgetReducer(state, action) {
+  switch (action.type) {
+    case WIDGET_PUT_REQUEST:
+      return {
+        ...state,
+        // Optimistic update
+        config: action.config,
+        old: {config: state.config},
+      };
+    case WIDGET_PUT_SUCCESS:
+      return {
+        ...action.widgetProps,
+      };
+    case WIDGET_PUT_FAILURE:
+      return {
+        ...state,
+        // Optimism failed... ;-(
+        config: state.old.config,
+      };
+    default:
+      return state
+  }
+}
diff --git a/hubs/static/client/app/core/reducers/widgets.js b/hubs/static/client/app/core/reducers/widgets.js
new file mode 100644
index 0000000..014b85c
--- /dev/null
+++ b/hubs/static/client/app/core/reducers/widgets.js
@@ -0,0 +1,185 @@
+import { combineReducers } from 'redux';
+import { arrayMove } from 'react-sortable-hoc';
+import {
+  HUB_WIDGETS_FETCH_REQUEST, HUB_WIDGETS_FETCH_SUCCESS, HUB_WIDGETS_FETCH_FAILURE,
+  HUB_WIDGETS_EDIT_MODE,
+  HUB_WIDGETS_AVAIL_REQUEST, HUB_WIDGETS_AVAIL_SUCCESS, HUB_WIDGETS_AVAIL_FAILURE,
+  } from '../actions/widgets';
+import {
+  WIDGET_PUT_SUCCESS, WIDGET_DELETE_SUCCESS,
+  WIDGET_WILL_UPDATE, WIDGET_DID_UPDATE,
+  HUB_WIDGETS_ADD_REQUEST, HUB_WIDGETS_ADD_FAILURE,
+  WIDGET_MOVE_REQUEST, WIDGET_MOVE_FAILURE,
+  WIDGET_OPEN_CONFIG, WIDGET_CLOSE_CONFIG,
+  } from '../actions/widget';
+import { WIDGET_NEEDS_UPDATE } from '../actions/sse';
+import singleWidgetReducer from './widget';
+
+
+function widgetsAreLoading(state=false, action) {
+  switch (action.type) {
+    case HUB_WIDGETS_FETCH_REQUEST:
+    case HUB_WIDGETS_ADD_REQUEST:
+    case HUB_WIDGETS_AVAIL_REQUEST:
+    case WIDGET_MOVE_REQUEST:
+      return true;
+    case HUB_WIDGETS_FETCH_SUCCESS:
+    case HUB_WIDGETS_FETCH_FAILURE:
+    case HUB_WIDGETS_ADD_FAILURE:
+    case HUB_WIDGETS_AVAIL_SUCCESS:
+    case HUB_WIDGETS_AVAIL_FAILURE:
+    case WIDGET_MOVE_FAILURE:
+      return false;
+    default:
+      return state
+  }
+}
+
+
+function widgetList(position) {
+  return (state=[], action) => {
+    switch (action.type) {
+      case HUB_WIDGETS_FETCH_SUCCESS:
+        return action.widgets.filter(
+          widget => (widget.position === position)
+        ).map(widget => widget.idx);
+      case WIDGET_DELETE_SUCCESS:
+        return state.filter((idx) => (idx != action.widgetId));
+      case WIDGET_MOVE_REQUEST:
+        // Optimistic update
+        if (action.position !== position) {
+          return state;
+        }
+        return arrayMove(state, action.oldIndex, action.newIndex);
+      case WIDGET_MOVE_FAILURE:
+        if (action.position !== position) {
+          return state;
+        }
+        return arrayMove(state, action.newIndex, action.oldIndex);
+      default:
+        return state
+    }
+  }
+}
+
+
+function widgetsNeedUpdate(state=[], action) {
+  switch (action.type) {
+    case HUB_WIDGETS_FETCH_SUCCESS:
+      return action.widgets.map((widget) => (widget.idx));
+    case WIDGET_DELETE_SUCCESS:
+    case WIDGET_WILL_UPDATE:
+      if (state.indexOf(action.widgetId) === -1) {
+        return state;
+      } else {
+        return state.filter((idx) => (idx != action.widgetId));
+      }
+    case WIDGET_PUT_SUCCESS:
+    case WIDGET_NEEDS_UPDATE:
+      return [...state, action.widgetId];
+    default:
+      return state
+  }
+}
+
+
+function widgetsById(state={}, action){
+  let newState;
+  switch (action.type) {
+    case HUB_WIDGETS_FETCH_SUCCESS:
+      newState = {};
+      action.widgets.forEach((widget) => {
+        newState[widget.idx] = widget;
+      });
+      return newState;
+    case WIDGET_DELETE_SUCCESS:
+      newState = Object.assign({}, state);
+      delete newState[action.widgetId];
+      return newState;
+    default:
+      if (!action.widgetId) {
+        return state;
+      }
+      let widget = state[action.widgetId];
+      return {
+        ...state,
+        [action.widgetId]: singleWidgetReducer(widget, action),
+      };
+  }
+}
+
+
+export const widgetsReducer = combineReducers({
+  isLoading: widgetsAreLoading,
+  left: widgetList("left"),
+  right: widgetList("right"),
+  byId: widgetsById,
+  needUpdate: widgetsNeedUpdate,
+});
+
+
+
+/* Available widgets */
+
+
+function availWidgetsList(position) {
+  return (state=[], action) => {
+    switch (action.type) {
+      case HUB_WIDGETS_AVAIL_SUCCESS:
+        return action.widgets.filter(
+          widget => (
+            widget.position === position || widget.position === "both"
+          )
+        ).map(widget => widget.name);
+      default:
+        return state
+    }
+  }
+}
+
+function availWidgetsByName(state={}, action){
+  let newState = {};
+  switch (action.type) {
+    case HUB_WIDGETS_AVAIL_SUCCESS:
+      action.widgets.forEach((widget) => {
+        newState[widget.name] = widget;
+      });
+      return newState;
+    default:
+      return state
+  }
+}
+
+export const availableWidgetsReducer = combineReducers({
+  isLoading: widgetsAreLoading,
+  left: availWidgetsList("left"),
+  right: availWidgetsList("right"),
+  byName: availWidgetsByName,
+});
+
+
+
+/* UI */
+
+export function widgetsEditMode(state=false, action) {
+  switch (action.type) {
+    case HUB_WIDGETS_EDIT_MODE:
+      return action.editMode;
+    default:
+      return state
+  }
+}
+
+
+export function widgetConfigDialogOpen(state=false, action) {
+  switch (action.type) {
+    case WIDGET_OPEN_CONFIG:
+      return action.widgetId;
+    case WIDGET_CLOSE_CONFIG:
+    case WIDGET_PUT_SUCCESS:
+    case WIDGET_DELETE_SUCCESS:
+      return false;
+    default:
+      return state
+  }
+}
diff --git a/hubs/static/client/app/core/utils.js b/hubs/static/client/app/core/utils.js
new file mode 100644
index 0000000..0699a93
--- /dev/null
+++ b/hubs/static/client/app/core/utils.js
@@ -0,0 +1,88 @@
+import React from 'react';
+import fetch from 'isomorphic-fetch';
+import Loadable from 'react-loadable';
+
+
+export function backendCall(url, fetchConfig, json=false) {
+  console.log("Calling backend:", url, fetchConfig);
+  const baseFetchConfig = {
+    credentials: "same-origin",
+    headers: {"Content-Type": "application/json"},
+  }
+  fetchConfig = Object.assign({}, baseFetchConfig, fetchConfig);
+  return fetch(url, {...baseFetchConfig, ...fetchConfig}).then(
+    (response) => {
+      if (response.ok) {
+        return json ? response.json() : response.text();
+      } else {
+        return response.text().then((msg) => {
+          throw new Error(msg);
+        });
+      }
+    }
+  ).catch((error) => {
+    console.error(error.message);
+    throw error;
+  });
+}
+
+
+export function apiCall(url, fetchConfig) {
+  return backendCall(url, fetchConfig, true).then(result => {
+    if (result.status === "OK") {
+      return result.data;
+    } else {
+      throw new Error(result.message);
+    }
+  });
+}
+
+
+export function makeLoadable(loader, loading) {
+  const renderDefault = (loaded, props) => {
+    const Component = loaded.default;
+    return <Component {...props} />;
+  }
+  return Loadable({
+    loader,
+    loading,
+    render: renderDefault,
+    delay: 200,
+  });
+}
+
+export function makeLoadingComponent(loadingText, errorText) {
+  class LoadingComponent extends React.Component {
+    render() {
+      // Handle the loading state
+      if (this.props.isLoading) {
+        if (this.props.timedOut) {
+          // In case we've timed out loading our other component.
+          return <div className="text-warning">Loader timed out!</div>;
+        } else if (this.props.pastDelay) {
+          // Display a loading screen after a set delay.
+          return (
+            <div className="text-muted">
+              {loadingText}
+            </div>
+          );
+        } else {
+          // Don't flash "Loading..." when we don't need to.
+          return null;
+        }
+      }
+      // Handle the error state
+      else if (this.props.error) {
+        return (
+          <div>
+            {errorText}
+          </div>
+        );
+      }
+      else {
+        return null;
+      }
+    }
+  }
+  return LoadingComponent;
+}
diff --git a/hubs/static/client/app/widgets/feed/Config.js b/hubs/static/client/app/widgets/feed/Config.js
new file mode 100644
index 0000000..1fc4fa8
--- /dev/null
+++ b/hubs/static/client/app/widgets/feed/Config.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import SimpleWidgetConfig from '../../components/SimpleWidgetConfig';
+
+
+// Use the default configuration, it's sufficient.
+
+export default function Config(props) {
+  return (
+    <SimpleWidgetConfig {...props} />
+  );
+}
diff --git a/hubs/static/client/app/widgets/feed/Feed.js b/hubs/static/client/app/widgets/feed/Feed.js
deleted file mode 100644
index af0b1c6..0000000
--- a/hubs/static/client/app/widgets/feed/Feed.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Widget from './Widget.jsx';
-
-
-// Don't use the ES6 "export default" construct:
-// http://stackoverflow.com/questions/40294870/module-exports-vs-export-default-in-node-js-and-es6
-
-module.exports = {Widget};
diff --git a/hubs/static/client/app/widgets/feed/Widget.js b/hubs/static/client/app/widgets/feed/Widget.js
new file mode 100644
index 0000000..31e6f6f
--- /dev/null
+++ b/hubs/static/client/app/widgets/feed/Widget.js
@@ -0,0 +1,66 @@
+import React from 'react';
+import {
+  widgetDidUpdate,
+  widgetWillUpdate
+  } from "../../core/actions/widget";
+import ItemsGetter from '../../components/feed/ItemsGetter';
+import Feed from '../../components/feed/Feed';
+import WidgetChrome from '../../components/WidgetChrome';
+
+
+export default class Widget extends React.PureComponent {
+
+  propTypes: {
+    widget: PropTypes.object.isRequired,
+    editMode: PropTypes.bool,
+    needsUpdate: PropTypes.bool,
+  }
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      items: [],
+      loaded: false,
+    };
+    this.handleServerData = this.handleServerData.bind(this);
+    this.handleServerRequestStart = this.handleServerRequestStart.bind(this);
+  }
+
+  handleServerData(data) {
+    this.setState({
+      items: data,
+      loaded: true,
+    },
+      () => (
+        this.props.dispatch(widgetDidUpdate(this.props.widget.idx))
+      )
+    );
+  }
+
+  handleServerRequestStart() {
+    this.props.dispatch(widgetWillUpdate(this.props.widget.idx));
+  }
+
+  render() {
+    return (
+      <WidgetChrome
+        widget={this.props.widget}
+        editMode={this.props.editMode}
+        >
+        <ItemsGetter
+          url={this.props.widget.url}
+          useSSE={true}
+          needsUpdate={this.props.needsUpdate}
+          handleData={this.handleServerData}
+          onRequestStart={this.handleServerRequestStart}
+          >
+          <Feed
+            items={this.state.items}
+            loaded={this.state.loaded}
+            />
+        </ItemsGetter>
+      </WidgetChrome>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/widgets/feed/Widget.jsx b/hubs/static/client/app/widgets/feed/Widget.jsx
deleted file mode 100644
index b60a6eb..0000000
--- a/hubs/static/client/app/widgets/feed/Widget.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-import {IntlProvider} from 'react-intl';
-import ItemsGetter from '../../components/feed/ItemsGetter.jsx';
-import Feed from '../../components/feed/Feed.jsx';
-
-
-export default class Widget extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      items: [],
-      loaded: false,
-    };
-    this.handleServerData = this.handleServerData.bind(this);
-  }
-
-  handleServerData(data) {
-    this.setState({
-      items: data,
-      loaded: true,
-    });
-  }
-
-  render() {
-    return (
-      <IntlProvider locale={navigator.language}>
-        <ItemsGetter
-          url={this.props.url}
-          sse={{
-            eventName: "hubs:widget-updated",
-            shouldReload: (idx) => (parseInt(idx) === this.props.widgetIdx),
-          }}
-          handleData={this.handleServerData}
-          >
-          <Feed
-            items={this.state.items}
-            loaded={this.state.loaded}
-            />
-        </ItemsGetter>
-      </IntlProvider>
-    );
-  }
-
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/Config.js b/hubs/static/client/app/widgets/halp/Config.js
new file mode 100644
index 0000000..8f48cff
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Config.js
@@ -0,0 +1,206 @@
+import React from 'react';
+import {
+  defineMessages,
+  injectIntl,
+  FormattedMessage,
+  } from 'react-intl';
+import CompletionInput from '../../components/CompletionInput';
+import "./halp.css";
+
+
+const messages = defineMessages({
+  title_add: {
+    id: "hubs.widgets.halp.config.title.add",
+    defaultMessage: "Adding \"halp\" widget",
+  },
+  title_edit: {
+    id: "hubs.widgets.halp.config.title.edit",
+    defaultMessage: "Configuring \"halp\" widget",
+  },
+  followed_hubs: {
+    id: "hubs.widgets.halp.config.followed_hubs",
+    defaultMessage: "Followed hubs:",
+  },
+  no_hubs: {
+    id: "hubs.widgets.halp.config.no_hubs",
+    defaultMessage: "No hubs. Use the form to the right to add some.",
+  },
+  main_title: {
+    id: "hubs.widgets.halp.config.main_title",
+    defaultMessage: "Track help requests in hubs",
+  },
+  main_subtitle: {
+    id: "hubs.widgets.halp.config.main_subtitle",
+    defaultMessage: "Enter a team name below to add it to the list of hubs this widget will follow.",
+  },
+  placeholder: {
+    id: "hubs.widgets.halp.config.placeholder",
+    defaultMessage: "Enter team name here...",
+  },
+  add: {
+    id: "hubs.widgets.halp.config.add",
+    defaultMessage: "Add",
+  },
+  per_page: {
+    id: "hubs.widgets.halp.config.per_page",
+    defaultMessage: "Requests per page:",
+  },
+  per_page_help: {
+    id: "hubs.widgets.halp.config.per_page_help",
+    defaultMessage: "The number of requests per page to display.",
+  },
+  close: {
+    id: "hubs.widgets.halp.config.close",
+    defaultMessage: "Close",
+  },
+  cancel: {
+    id: "hubs.widgets.halp.config.cancel",
+    defaultMessage: "Cancel",
+  },
+  save: {
+    id: "hubs.widgets.halp.config.save",
+    defaultMessage: "Save",
+  },
+  remove_widget: {
+    id: "hubs.widgets.halp.config.remove_widget",
+    defaultMessage: "Remove this widget",
+  },
+});
+
+
+export default class Config extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      selectedHub: null,
+    }
+    this.getFollowedHubs = this.getFollowedHubs.bind(this);
+    this.handleAddClicked = this.handleAddClicked.bind(this);
+    this.handleHubSelected = this.handleHubSelected.bind(this);
+    this.handlePerPageChanged = this.handlePerPageChanged.bind(this);
+  }
+
+  getFollowedHubs() {
+    return this.props.values.hubs || [];
+  }
+
+  addHub(name) {
+    let config = this.getFollowedHubs();
+    if (config.indexOf(name) === -1) {
+      config.push(name);
+    }
+    this.props.setConfig("hubs", config);
+  }
+
+  removeHub(name) {
+    let config = this.getFollowedHubs();
+    config.splice(config.indexOf(name), 1);
+    this.props.setConfig("hubs", config);
+  }
+
+  handleAddClicked(e) {
+    e.preventDefault();
+    if (this.state.selectedHub === null) {
+      console.log("No hub to add!");
+      return;
+    }
+    this.addHub(this.state.selectedHub);
+    this.setState({selectedHub: null});
+  }
+
+  handleHubSelected(e) {
+    this.setState({selectedHub: e.target.value});
+  }
+
+  handlePerPageChanged(e) {
+    this.props.setConfig("per_page", e.target.value);
+  }
+
+  render() {
+    let followedHubs = this.getFollowedHubs();
+    followedHubs = followedHubs.map((hub, idx) => {
+      return (
+        <li key={hub}>
+          <span className="hub">{hub}</span>
+          <span className="fa fa-times remove-hub"
+                onClick={(e) => {this.removeHub(hub)}}
+            />
+        </li>
+        );
+    });
+
+    /*
+    const IntlCompletionInput = injectIntl((props) => (
+        <CompletionInput
+          inputProps={{
+            name: "hub-add",
+            placeholder: props.intl.formatMessage(messages.placeholder),
+          }}
+          url={props.widget.urls.allHubs}
+          onChange={this.handleHubSelected}
+          />
+    ));
+              //<IntlCompletionInput {...this.props} />
+    */
+
+    return (
+      <div className="row widget-halp-config">
+        <div className="col-sm-4 hubs-list">
+          <FormattedMessage {...messages.followed_hubs} tagName="h5" />
+          {followedHubs.length === 0 ?
+            <p>
+              <FormattedMessage {...messages.no_hubs} tagName="small" />
+            </p>
+          :
+            <ul className="list-unstyled">
+              {followedHubs}
+            </ul>
+          }
+        </div>
+        <div className="col-sm-8 form-side">
+          <FormattedMessage {...messages.main_title} tagName="h4" />
+          <FormattedMessage {...messages.main_subtitle} tagName="p" />
+          <form onSubmit={this.handleAddClicked}>
+            <fieldset className="row">
+              <div className="col-sm-9">
+                <CompletionInput
+                  inputProps={{
+                    name: "hub-add",
+                    placeholder: "Enter team name here...",
+                    value: this.state.selectedHub || "",
+                  }}
+                  url={this.props.widget.urls.allHubs}
+                  onChange={this.handleHubSelected}
+                  />
+              </div>
+              <div className="col-sm-3">
+                <button className="btn btn-info" onClick={this.handleAddClicked}>
+                  <FormattedMessage {...messages.add} />
+                </button>
+              </div>
+            </fieldset>
+          </form>
+          <fieldset className="row">
+            <label className="col-sm-6 control-label">
+              <FormattedMessage {...messages.per_page} />
+            </label>
+            <div className="col-sm-6">
+              <input
+                name="per_page"
+                type="number"
+                value={this.props.values.per_page || "5"}
+                onChange={this.handlePerPageChanged}
+                className="form-control input-sm"
+                />
+            </div>
+            <div className="col-sm-12 text-muted">
+              <FormattedMessage {...messages.per_page_help} tagName="small" />
+            </div>
+          </fieldset>
+        </div>
+      </div>
+    );
+  }
+
+}
diff --git a/hubs/static/client/app/widgets/halp/Config.jsx b/hubs/static/client/app/widgets/halp/Config.jsx
deleted file mode 100644
index 61a3e50..0000000
--- a/hubs/static/client/app/widgets/halp/Config.jsx
+++ /dev/null
@@ -1,227 +0,0 @@
-import React from 'react';
-import {
-  IntlProvider,
-  defineMessages,
-  injectIntl,
-  FormattedMessage,
-  } from 'react-intl';
-import CompletionInput from '../../components/CompletionInput.jsx';
-
-
-const messages = defineMessages({
-  title_add: {
-    id: "hubs.widgets.halp.config.title.add",
-    defaultMessage: "Adding \"halp\" widget",
-  },
-  title_edit: {
-    id: "hubs.widgets.halp.config.title.edit",
-    defaultMessage: "Configuring \"halp\" widget",
-  },
-  followed_hubs: {
-    id: "hubs.widgets.halp.config.followed_hubs",
-    defaultMessage: "Followed hubs:",
-  },
-  no_hubs: {
-    id: "hubs.widgets.halp.config.no_hubs",
-    defaultMessage: "No hubs. Use the form to the right to add some.",
-  },
-  main_title: {
-    id: "hubs.widgets.halp.config.main_title",
-    defaultMessage: "Track help requests in hubs",
-  },
-  main_subtitle: {
-    id: "hubs.widgets.halp.config.main_subtitle",
-    defaultMessage: "Enter a team name below to add it to the list of hubs this widget will follow.",
-  },
-  placeholder: {
-    id: "hubs.widgets.halp.config.placeholder",
-    defaultMessage: "Enter team name here...",
-  },
-  add: {
-    id: "hubs.widgets.halp.config.add",
-    defaultMessage: "Add",
-  },
-  per_page: {
-    id: "hubs.widgets.halp.config.per_page",
-    defaultMessage: "Requests per page:",
-  },
-  per_page_help: {
-    id: "hubs.widgets.halp.config.per_page_help",
-    defaultMessage: "The number of requests per page to display.",
-  },
-  close: {
-    id: "hubs.widgets.halp.config.close",
-    defaultMessage: "Close",
-  },
-  cancel: {
-    id: "hubs.widgets.halp.config.cancel",
-    defaultMessage: "Cancel",
-  },
-  save: {
-    id: "hubs.widgets.halp.config.save",
-    defaultMessage: "Save",
-  },
-  remove_widget: {
-    id: "hubs.widgets.halp.config.remove_widget",
-    defaultMessage: "Remove this widget",
-  },
-});
-
-
-export default class Config extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = this.props.initialState;
-    this.addHub = this.addHub.bind(this);
-    this.removeHub = this.removeHub.bind(this);
-    this.onAddClick = this.onAddClick.bind(this);
-  }
-
-  addHub(name) {
-    // React may batch state updates:
-    // https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
-    this.setState(function(prevState, props) {
-      if (prevState.hubs.indexOf(name) === -1) {
-        prevState.hubs.push(name);
-      }
-      return {hubs: prevState.hubs};
-    });
-  }
-
-  removeHub(name) {
-    // React may batch state updates:
-    // https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
-    this.setState(function(prevState, props) {
-      prevState.hubs.splice(prevState.hubs.indexOf(name), 1);
-      return {hubs: prevState.hubs};
-    });
-  }
-
-  onAddClick(e) {
-    e.preventDefault();
-    var hubName = $(this.formDom).find("input[name='hub-add']").val();
-    this.addHub(hubName);
-  }
-
-  render() {
-    var titleMsg, followedHubs;
-    if (this.props.mode == "add") {
-      titleMsg = messages.title_add;
-    } else {
-      titleMsg = messages.title_edit;
-    }
-
-    followedHubs = this.state.hubs.map(function(hub, idx) {
-      return (
-        <li key={hub}>
-          <span className="hub">{hub}</span>
-          <span className="fa fa-times remove-hub"
-                onClick={(e) => this.removeHub(hub)}
-            />
-        </li>
-        );
-    }.bind(this));
-
-    const IntlCompletionInput = injectIntl((props) => (
-        <CompletionInput
-          inputProps={{
-            name: "hub-add",
-            placeholder: props.intl.formatMessage(messages.placeholder),
-          }}
-          url={props.urls.hubs}
-          />
-    ));
-
-    return (
-      <IntlProvider locale={navigator.language}>
-        <div className={"modal-dialog widget-halp-config widget-" + this.props.mode}>
-          <div className="modal-content">
-            <form method="post" action={this.props.urls.post}
-                  ref={(ref) => this.formDom = ref}>
-              <div className="modal-header">
-                <button type="button" className="close" data-dismiss="modal">&times;</button>
-                <h4 className="modal-title">
-                  <FormattedMessage {...titleMsg} />
-                </h4>
-              </div>
-              <div className="modal-body row">
-                <div className="col-sm-4 hubs-list">
-                  <FormattedMessage {...messages.followed_hubs} tagName="h5" />
-                  {this.state.hubs.length === 0 ?
-                    <FormattedMessage {...messages.no_hubs} tagName="p" />
-                  :
-                    <ul className="list-unstyled">
-                      {followedHubs}
-                    </ul>
-                  }
-                </div>
-                <div className="col-sm-8 form-side">
-                  <FormattedMessage {...messages.main_title} tagName="h4" />
-                  <FormattedMessage {...messages.main_subtitle} tagName="p" />
-                  <input type="hidden" name="hubs" value={this.state.hubs.join(",")} />
-                  <fieldset className="row">
-                    <div className="col-sm-9">
-                      <IntlCompletionInput {...this.props} />
-                    </div>
-                    <div className="col-sm-3">
-                      <button className="btn btn-info" onClick={this.onAddClick}>
-                        <FormattedMessage {...messages.add} />
-                      </button>
-                    </div>
-                  </fieldset>
-                  <fieldset className="row">
-                    <label className="col-sm-6 control-label">
-                      <FormattedMessage {...messages.per_page} />
-                    </label>
-                    <div className="col-sm-6">
-                      <input
-                        name="per_page"
-                        type="number"
-                        value={this.state.per_page}
-                        onChange={(e) => this.setState({per_page: e.target.value})}
-                        className="form-control input-sm"
-                        />
-                    </div>
-                    <div className="col-sm-12 text-muted">
-                      <FormattedMessage {...messages.per_page_help} tagName="small" />
-                    </div>
-                  </fieldset>
-                </div>
-              </div>
-              <div className="modal-footer">
-                <button type="button" className="btn btn-secondary" data-dismiss="modal">
-                  {this.props.mode === "add" ?
-                    <FormattedMessage {...messages.cancel} />
-                  :
-                    <FormattedMessage {...messages.close} />
-                  }
-                </button>
-                <button type="submit" className="btn btn-primary"
-                        disabled={this.state.hubs.length === 0 ? true : null}>
-                {this.props.mode === "add" ?
-                    <FormattedMessage {...messages.add} />
-                :
-                    <FormattedMessage {...messages.save} />
-                }
-                </button>
-              </div>
-            </form>
-            {this.props.mode !== "add" &&
-              <form method="POST" action={this.props.urls.remove} className="modal-footer p-abs" >
-                  <button type="submit" className="btn btn-danger" id="delete_widget">
-                    <FormattedMessage {...messages.remove_widget} />
-                  </button>
-              </form>
-            }
-          </div>
-        </div>
-      </IntlProvider>
-    );
-  }
-
-}
-
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/Halp.js b/hubs/static/client/app/widgets/halp/Halp.js
deleted file mode 100644
index 5b821f5..0000000
--- a/hubs/static/client/app/widgets/halp/Halp.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import Widget from './Widget.jsx';
-import Config from './Config.jsx';
-
-module.exports = {Widget, Config};
diff --git a/hubs/static/client/app/widgets/halp/Hub.js b/hubs/static/client/app/widgets/halp/Hub.js
new file mode 100644
index 0000000..7728662
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Hub.js
@@ -0,0 +1,20 @@
+import React from 'react';
+
+
+export default class Hub extends React.Component {
+
+  onClick(e) {
+    e.preventDefault();
+    this.props.onClick(this.props.name);
+  }
+
+  render() {
+    var activeClass = this.props.active ? "active" : "inactive";
+    return (
+      <span
+        className={"hub " + activeClass}
+        onClick={this.onClick.bind(this)}
+        >{"@" + this.props.name}</span>
+    );
+  }
+}
diff --git a/hubs/static/client/app/widgets/halp/Hub.jsx b/hubs/static/client/app/widgets/halp/Hub.jsx
deleted file mode 100644
index 044e6d9..0000000
--- a/hubs/static/client/app/widgets/halp/Hub.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-
-
-export default class Hub extends React.Component {
-
-  onClick(e) {
-    e.preventDefault();
-    this.props.onClick(this.props.name);
-  }
-
-  render() {
-    var activeClass = this.props.active ? "active" : "inactive";
-    return (
-      <span
-        className={"hub " + activeClass}
-        onClick={this.onClick.bind(this)}
-        >{"@" + this.props.name}</span>
-    );
-  }
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/HubsList.js b/hubs/static/client/app/widgets/halp/HubsList.js
new file mode 100644
index 0000000..9f39afe
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/HubsList.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import { defineMessages, FormattedMessage } from 'react-intl';
+import Hub from './Hub';
+
+
+const messages = defineMessages({
+  watching_all_hubs: {
+    id: "hubs.widgets.halp.watching_all_hubs",
+    defaultMessage: "Watching all hubs"
+  },
+});
+
+
+export default class HubsList extends React.Component {
+  render() {
+    var hubNodes = this.props.hubs.map(function(hub, idx) {
+      return (
+        <Hub
+          name={hub.name}
+          active={hub.active}
+          onClick={this.props.onHubClick}
+          key={idx}
+          />
+      );
+    }.bind(this));
+    return (
+      <div className="hubs">
+        <span className="fa fa-tags" aria-hidden="true"></span>
+        { (hubNodes.length !== 0) ?
+            hubNodes
+          :
+            <FormattedMessage
+              tagName="em"
+              {...messages.watching_all_hubs}
+              />
+        }
+      </div>
+    );
+  }
+}
diff --git a/hubs/static/client/app/widgets/halp/HubsList.jsx b/hubs/static/client/app/widgets/halp/HubsList.jsx
deleted file mode 100644
index 3915dd4..0000000
--- a/hubs/static/client/app/widgets/halp/HubsList.jsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from 'react';
-import { defineMessages, FormattedMessage } from 'react-intl';
-import Hub from './Hub.jsx';
-
-
-const messages = defineMessages({
-  watching_all_hubs: {
-    id: "hubs.widgets.halp.watching_all_hubs",
-    defaultMessage: "Watching all hubs"
-  },
-});
-
-
-export default class HubsList extends React.Component {
-  render() {
-    var hubNodes = this.props.hubs.map(function(hub, idx) {
-      return (
-        <Hub
-          name={hub.name}
-          active={hub.active}
-          onClick={this.props.onHubClick}
-          key={idx}
-          />
-      );
-    }.bind(this));
-    return (
-      <div className="hubs row">
-        <span className="fa fa-tags" aria-hidden="true"></span>
-        { (hubNodes.length !== 0) ?
-            hubNodes
-          :
-            <FormattedMessage
-              tagName="em"
-              {...messages.watching_all_hubs}
-              />
-        }
-      </div>
-    );
-  }
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/ModalAllRequests.js b/hubs/static/client/app/widgets/halp/ModalAllRequests.js
new file mode 100644
index 0000000..8f0e1a8
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/ModalAllRequests.js
@@ -0,0 +1,238 @@
+import React from 'react';
+import { defineMessages, FormattedMessage } from 'react-intl';
+import CompletionInput from '../../components/CompletionInput';
+import Spinner from "../../components/Spinner";
+import Modal from '../../components/Modal';
+import Request from './Request';
+
+
+const messages = defineMessages({
+  no_request_found: {
+    id: "hubs.widgets.halp.no_request_found",
+    defaultMessage: "No request found."
+  },
+  search_meeting_name: {
+    id: "hubs.widgets.halp.search.meeting_name",
+    defaultMessage: "Meeting name"
+  },
+  search_between_dates: {
+    id: "hubs.widgets.halp.search.between_dates",
+    defaultMessage: "Between dates"
+  },
+  search_people: {
+    id: "hubs.widgets.halp.search.people",
+    defaultMessage: "People"
+  },
+  search_button: {
+    id: "hubs.widgets.halp.search.button",
+    defaultMessage: "Search"
+  },
+  pager_newer: {
+    id: "hubs.widgets.halp.pager.newer",
+    defaultMessage: "Newer"
+  },
+  pager_older: {
+    id: "hubs.widgets.halp.pager.older",
+    defaultMessage: "Older"
+  },
+  pager_status: {
+    id: "hubs.widgets.halp.pager.status",
+    defaultMessage: "Page {page} / {total}"
+  },
+});
+
+
+export default class ModalAllRequests extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      requests: [],
+      page: {nr: 1, has_prev: false, has_next: false},
+      formData: {
+        hubs: this.props.hubs.filter(
+            function(hub) { return hub.active; }
+          ).map(
+            function(hub) { return hub.name; }
+          ),
+        },
+      isLoading: false,
+    };
+    this.onSubmit = this.onSubmit.bind(this);
+    this.loadFromServer = this.loadFromServer.bind(this);
+    this.onPageChange = this.onPageChange.bind(this);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  componentDidMount() {
+    if (this.state.requests.length === 0) {
+      this.loadFromServer();
+    }
+  }
+
+  componentWillUnmount() {
+    if (this.serverRequest) {
+      this.serverRequest.abort()
+    };
+  }
+
+  onSubmit(e) {
+    e.preventDefault();
+    this.loadFromServer();
+  }
+
+  onPageChange(e) {
+    const inc = parseInt(e.target.value);
+    const requestedPage = this.state.page.nr + inc;
+    this.loadFromServer(requestedPage);
+  }
+
+  loadFromServer(requestedPage) {
+    const formData = this.state.formData;
+    formData.page = requestedPage || 1;
+    this.setState({isLoading: true});
+    this.serverRequest = $.ajax({
+      url: this.props.urls.search,
+      method: 'GET',
+      data: formData,
+      dataType: 'json',
+      cache: false,
+      success: function(data) {
+        this.setState({
+          requests: data.data.requests,
+          page: data.page,
+          isLoading: false
+        });
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.urls.search, status, err.toString());
+        this.setState({isLoading: false});
+      }.bind(this)
+    });
+  }
+
+  handleChange(e) {
+    const name = e.target.name;
+    const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+    this.setState((prevState, props) => {
+      prevState.formData[name] = value;
+      return {formData: prevState.formData};
+    });
+  }
+
+  render() {
+    let footer;
+    if (this.state.requests.length === 0
+        || (!this.state.page.has_prev && !this.state.page.has_next)) {
+      // No results or only one page: don't show the pager.
+      footer = null;
+    } else {
+      footer = (
+        <nav aria-label="...">
+          <ul className="pager">
+            <li className={"pager-prev" + (this.state.page.has_prev ? "" : " disabled")}>
+              <button className="btn btn-link" value="-1" onClick={this.onPageChange}>
+                <span aria-hidden="true">&larr;</span>
+                <FormattedMessage {...messages.pager_newer} />
+              </button>
+            </li>
+            <FormattedMessage
+              tagName="li"
+              {...messages.pager_status}
+              values={{page: this.state.page.nr, total: this.state.page.total_pages}}
+              />
+            <li className={"pager-next" + (this.state.page.has_next ? "" : " disabled")}>
+              <button className="btn btn-link" value="1" onClick={this.onPageChange}>
+                <FormattedMessage {...messages.pager_older} />
+                <span aria-hidden="true">&rarr;</span>
+              </button>
+            </li>
+          </ul>
+        </nav>
+      );
+    }
+
+    let requestNodes;
+    if (this.state.requests.length === 0) {
+      requestNodes = (
+        <p className="no-request">
+          <FormattedMessage {...messages.no_request_found} />
+        </p>
+      );
+    } else {
+      requestNodes = this.state.requests.map((request, idx) => {
+        return (
+          <Request
+            request={request}
+            showdate={false}
+            onZoomRequest={this.props.onZoomRequest}
+            key={idx} />
+        );
+      });
+    }
+
+    return (
+      <Modal
+        title={this.props.title}
+        footer={footer}
+        onCloseClicked={this.props.onCloseClicked}
+        cssClass="ModalAllRequests"
+        >
+        <form className="" method="post"
+              action={this.props.urls.search} onSubmit={this.onSubmit}>
+          <div className="form-group row">
+            <label htmlFor="meetingname" className="col-sm-4 control-label">
+              <FormattedMessage {...messages.search_meeting_name} />
+            </label>
+            <div className="col-sm-8">
+              <input type="text" className="form-control" name="meetingname"
+                     onChange={this.handleChange} />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label htmlFor="startdate" className="col-sm-4 control-label">
+              <FormattedMessage {...messages.search_between_dates} />
+            </label>
+            <div className="col-sm-4">
+              <input type="date" className="form-control" name="startdate"
+                     onChange={this.handleChange} />
+            </div>
+            <div className="col-sm-4">
+              <input type="date" className="form-control" name="enddate"
+                     onChange={this.handleChange} />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label htmlFor="people" className="col-sm-4 control-label">
+              <FormattedMessage {...messages.search_people} />
+            </label>
+            <div className="col-sm-8">
+              <CompletionInput
+                inputProps={{name: "people"}}
+                url={this.props.urls.requesters}
+                onChange={this.handleChange}
+                />
+            </div>
+          </div>
+          <div className="form-group row">
+            <div className="offset-sm-4 col-sm-8">
+              <button
+                type="submit"
+                className="btn btn-primary mr-3"
+                >
+                <FormattedMessage {...messages.search_button} />
+              </button>
+              { this.state.isLoading &&
+                  <Spinner circle={true} />
+              }
+            </div>
+          </div>
+        </form>
+        <hr />
+        <div className="requests">
+          {requestNodes}
+        </div>
+      </Modal>
+    );
+  }
+}
diff --git a/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx b/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
deleted file mode 100644
index e7365a9..0000000
--- a/hubs/static/client/app/widgets/halp/ModalAllRequests.jsx
+++ /dev/null
@@ -1,240 +0,0 @@
-import { defineMessages, FormattedMessage } from 'react-intl';
-import CompletionInput from '../../components/CompletionInput.jsx';
-import Modal from '../../components/Modal.jsx';
-import Request from './Request.jsx';
-
-
-const messages = defineMessages({
-  no_request_found: {
-    id: "hubs.widgets.halp.no_request_found",
-    defaultMessage: "No request found."
-  },
-  search_meeting_name: {
-    id: "hubs.widgets.halp.search.meeting_name",
-    defaultMessage: "Meeting name"
-  },
-  search_between_dates: {
-    id: "hubs.widgets.halp.search.between_dates",
-    defaultMessage: "Between dates"
-  },
-  search_people: {
-    id: "hubs.widgets.halp.search.people",
-    defaultMessage: "People"
-  },
-  search_button: {
-    id: "hubs.widgets.halp.search.button",
-    defaultMessage: "Search"
-  },
-  pager_newer: {
-    id: "hubs.widgets.halp.pager.newer",
-    defaultMessage: "Newer"
-  },
-  pager_older: {
-    id: "hubs.widgets.halp.pager.older",
-    defaultMessage: "Older"
-  },
-  pager_status: {
-    id: "hubs.widgets.halp.pager.status",
-    defaultMessage: "Page {page} / {total}"
-  },
-});
-
-
-export default class ModalAllRequests extends Modal {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      requests: [],
-      page: {nr: 1, has_prev: false, has_next: false},
-      formData: {
-        hubs: this.props.hubs.filter(
-            function(hub) { return hub.active; }
-          ).map(
-            function(hub) { return hub.name; }
-          ),
-        },
-      loading: false,
-    };
-    this.onSubmit = this.onSubmit.bind(this);
-    this.loadFromServer = this.loadFromServer.bind(this);
-    this.onZoomRequest = this.onZoomRequest.bind(this);
-    this.changePage = this.changePage.bind(this);
-    this.handleChange = this.handleChange.bind(this);
-  }
-
-  componentWillUnmount() {
-    super.componentWillUnmount();
-    this.serverRequest.abort();
-  }
-
-  onShown(e) {
-    super.onShown(e);
-    if (this.state.requests.length === 0) { this.loadFromServer(); }
-  }
-
-  onHidden(e) {
-    super.onHidden(e);
-    if (this.serverRequest) { this.serverRequest.abort(); }
-  }
-
-  onZoomRequest(request) {
-    // Close this modal and open the request modal
-    this.hide(function() {
-      this.props.onZoomRequest(request);
-    }.bind(this));
-  }
-
-  onSubmit(e) {
-    e.preventDefault();
-    this.loadFromServer();
-  }
-
-  changePage(inc) {
-    var requestedPage = this.state.page.nr + inc;
-    this.loadFromServer(requestedPage);
-  }
-
-  loadFromServer(requestedPage) {
-    const formData = this.state.formData;
-    formData.page = requestedPage || 1;
-    this.setState({loading: true});
-    this.serverRequest = $.ajax({
-      url: this.props.urls.search,
-      method: 'GET',
-      data: formData,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({
-          requests: data.requests,
-          page: data.page,
-          loading: false
-        });
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.urls.search, status, err.toString());
-        this.setState({loading: false});
-      }.bind(this)
-    });
-  }
-
-  handleChange(e) {
-    const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
-    const name = e.target.name;
-    var data = this.state.formData;
-    data[name] = value;
-    this.setState({formData: data});
-  }
-
-  getModalBody() {
-    var requestNodes;
-    if (this.state.requests.length === 0) {
-      requestNodes = (<p className="no-request">
-        <FormattedMessage {...messages.no_request_found} />
-      </p>);
-    } else {
-      requestNodes = this.state.requests.map(function(request, idx) {
-        return (
-          <Request
-            request={request}
-            showdate={false}
-            onZoomRequest={this.onZoomRequest}
-            key={idx} />
-        );
-      }.bind(this));
-    }
-    return (
-      <div>
-        <form className="" method="post"
-              action={this.props.urls.search} onSubmit={this.onSubmit}>
-          <div className="form-group row">
-            <label htmlFor="meetingname" className="col-sm-4 control-label">
-              <FormattedMessage {...messages.search_meeting_name} />
-            </label>
-            <div className="col-sm-8">
-              <input type="text" className="form-control" name="meetingname"
-                     onChange={this.handleChange} />
-            </div>
-          </div>
-          <div className="form-group row">
-            <label htmlFor="startdate" className="col-sm-4 control-label">
-              <FormattedMessage {...messages.search_between_dates} />
-            </label>
-            <div className="col-sm-4">
-              <input type="date" className="form-control" name="startdate"
-                     onChange={this.handleChange} />
-            </div>
-            <div className="col-sm-4">
-              <input type="date" className="form-control" name="enddate"
-                     onChange={this.handleChange} />
-            </div>
-          </div>
-          <div className="form-group row">
-            <label htmlFor="people" className="col-sm-4 control-label">
-              <FormattedMessage {...messages.search_people} />
-            </label>
-            <div className="col-sm-8">
-              <CompletionInput
-                inputProps={{name: "people"}}
-                url={this.props.urls.requesters}
-                onChange={this.handleChange}
-                />
-            </div>
-          </div>
-          <div className="form-group row">
-            <div className="offset-sm-4 col-sm-8">
-              <button
-                type="submit"
-                className="btn btn-primary mr-3"
-                >
-                <FormattedMessage {...messages.search_button} />
-              </button>
-              <div
-                className="loading-circle"
-                style={this.state.loading ? {display: "inline-block"} : {}}
-                ></div>
-            </div>
-          </div>
-        </form>
-        <hr />
-        <div className="requests">
-          {requestNodes}
-        </div>
-      </div>
-    );
-  }
-
-  getModalFooter() {
-    if (this.state.requests.length === 0
-        || (!this.state.page.has_prev && !this.state.page.has_next)) {
-      // No results or only one page: don't show the pager.
-      return null;
-    }
-    return (
-      <nav aria-label="...">
-        <ul className="pager">
-          <li className={"pager-prev" + (this.state.page.has_prev ? "" : " disabled")}>
-            <a href="#" onClick={this.changePage.bind(this, -1)}>
-              <span aria-hidden="true">&larr;</span>
-              <FormattedMessage {...messages.pager_newer} />
-              </a>
-          </li>
-          <FormattedMessage
-            tagName="li"
-            {...messages.pager_status}
-            values={{page: this.state.page.nr, total: this.state.page.total_pages}}
-            />
-          <li className={"pager-next" + (this.state.page.has_next ? "" : " disabled")}>
-            <a href="#" onClick={this.changePage.bind(this, 1)}>
-              <FormattedMessage {...messages.pager_older} />
-              <span aria-hidden="true">&rarr;</span></a>
-          </li>
-        </ul>
-      </nav>
-    );
-  }
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/ModalRequest.js b/hubs/static/client/app/widgets/halp/ModalRequest.js
new file mode 100644
index 0000000..36ed228
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/ModalRequest.js
@@ -0,0 +1,111 @@
+import React from 'react';
+import { defineMessages, FormattedMessage } from 'react-intl';
+import Modal from '../../components/Modal';
+import getRequestView from './getRequestView';
+
+
+const messages = defineMessages({
+  zoom_part2_title: {
+    id: "hubs.widgets.halp.zoom.part2_title",
+    defaultMessage: "Want to help with this request?"
+  },
+  zoom_part2_subtitle: {
+    id: "hubs.widgets.halp.zoom.part2_subtitle",
+    defaultMessage: "Awesome! Here's some tips on getting started:"
+  },
+  zoom_tip1: {
+    id: "hubs.widgets.halp.zoom.tip1",
+    defaultMessage: "Take a look at the link provided in the request. It should have more information about the problem and may have instructions on how to get starter helping out:"
+  },
+  zoom_tip2: {
+    id: "hubs.widgets.halp.zoom.tip2",
+    defaultMessage: "Contact the person who requested help to get more information. By clicking on their name, you'll be taken to their profile where you can contact them:"
+  },
+  zoom_tip3: {
+    id: "hubs.widgets.halp.zoom.tip3",
+    defaultMessage: "Read through the chat log where the request occured. There may be additional context in the log that can help you figure out how to get started:"
+  },
+});
+
+
+export default class ModalRequest extends React.Component {
+
+  render() {
+    let content;
+    if (!this.props.data) {
+      content = "";
+    } else {
+      content = (
+        <div className="zoomed-request">
+          {getRequestView(this.props.data)}
+          <hr />
+          <FormattedMessage
+            tagName="h4"
+            {...messages.zoom_part2_title}
+            />
+          <FormattedMessage
+            tag="p"
+            {...messages.zoom_part2_subtitle}
+            />
+          <ol>
+            { this.props.data.urls ?
+            <li>
+              <FormattedMessage
+                {...messages.zoom_tip1}
+                />
+              <ul>
+                { this.props.data.urls.map(function(url, index) {
+                  return (
+                    <li key={index}><a href={url}>
+                      {url.replace(/^https?:\/\//, '')}
+                    </a></li>);
+                  }) }
+              </ul>
+            </li>
+            : null }
+            <li>
+              <FormattedMessage
+                {...messages.zoom_tip2}
+                />
+              <ul className="list-unstyled">
+                <li className="media">
+                  <div className="media-left media-middle">
+                    <a href={this.props.data.author.url} target="_blank">
+                      <img className="square-32 img-circle"
+                           src={this.props.data.author.avatar} />
+                    </a>
+                  </div>
+                  <div className="media-body">
+                    <a href={this.props.data.author.url} target="_blank">
+                      {this.props.data.author.name}
+                    </a>
+                  </div>
+                </li>
+              </ul>
+            </li>
+            <li>
+              <FormattedMessage
+                {...messages.zoom_tip3}
+                />
+              <ul className="list-unstyled">
+                <a href={this.props.data.context_url}>
+                  {this.props.data.context_url.replace(/^https?:\/\//, '')}
+                </a>
+              </ul>
+            </li>
+          </ol>
+        </div>
+      );
+    }
+
+    return (
+      <Modal
+        title={this.props.title}
+        onCloseClicked={this.props.onCloseClicked}
+        cssClass="ModalRequest"
+        >
+        {content}
+      </Modal>
+    );
+  }
+}
diff --git a/hubs/static/client/app/widgets/halp/ModalRequest.jsx b/hubs/static/client/app/widgets/halp/ModalRequest.jsx
deleted file mode 100644
index 36ea130..0000000
--- a/hubs/static/client/app/widgets/halp/ModalRequest.jsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import { defineMessages, FormattedMessage } from 'react-intl';
-import Modal from '../../components/Modal.jsx';
-import getRequestView from './getRequestView.jsx';
-
-
-const messages = defineMessages({
-  zoom_part2_title: {
-    id: "hubs.widgets.halp.zoom.part2_title",
-    defaultMessage: "Want to help with this request?"
-  },
-  zoom_part2_subtitle: {
-    id: "hubs.widgets.halp.zoom.part2_subtitle",
-    defaultMessage: "Awesome! Here's some tips on getting started:"
-  },
-  zoom_tip1: {
-    id: "hubs.widgets.halp.zoom.tip1",
-    defaultMessage: "Take a look at the link provided in the request. It should have more information about the problem and may have instructions on how to get starter helping out:"
-  },
-  zoom_tip2: {
-    id: "hubs.widgets.halp.zoom.tip2",
-    defaultMessage: "Contact the person who requested help to get more information. By clicking on their name, you'll be taken to their profile where you can contact them:"
-  },
-  zoom_tip3: {
-    id: "hubs.widgets.halp.zoom.tip3",
-    defaultMessage: "Read through the chat log where the request occured. There may be additional context in the log that can help you figure out how to get started:"
-  },
-});
-
-
-export default class ModalRequest extends Modal {
-
-  getModalBody() {
-    if (!this.props.data) { return ""; }
-    return (
-      <div className="zoomed-request">
-        {getRequestView(this.props.data)}
-        <hr />
-        <FormattedMessage
-          tagName="h4"
-          {...messages.zoom_part2_title}
-          />
-        <FormattedMessage
-          tag="p"
-          {...messages.zoom_part2_subtitle}
-          />
-        <ol>
-          { this.props.data.urls ?
-          <li>
-            <FormattedMessage
-              {...messages.zoom_tip1}
-              />
-            <ul>
-              { this.props.data.urls.map(function(url, index) {
-                return (
-                  <li key={index}><a href={url}>
-                    {url.replace(/^https?:\/\//, '')}
-                  </a></li>);
-                }) }
-            </ul>
-          </li>
-          : null }
-          <li>
-            <FormattedMessage
-              {...messages.zoom_tip2}
-              />
-            <ul className="list-unstyled">
-              <li className="media">
-                <div className="media-left media-middle">
-                  <a href={this.props.data.author.url} target="_blank">
-                    <img className="square-32 img-circle"
-                         src={this.props.data.author.avatar} />
-                  </a>
-                </div>
-                <div className="media-body">
-                  <a href={this.props.data.author.url} target="_blank">
-                    {this.props.data.author.name}
-                  </a>
-                </div>
-              </li>
-            </ul>
-          </li>
-          <li>
-            <FormattedMessage
-              {...messages.zoom_tip3}
-              />
-            <ul className="list-unstyled">
-              <a href={this.props.data.context_url}>
-                {this.props.data.context_url.replace(/^https?:\/\//, '')}
-              </a>
-            </ul>
-          </li>
-        </ol>
-      </div>
-    );
-  }
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/Request.js b/hubs/static/client/app/widgets/halp/Request.js
new file mode 100644
index 0000000..a6c0ec9
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Request.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import {FormattedRelative} from 'react-intl';
+import getRequestView from './getRequestView';
+
+
+export default class Request extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.onClick = this.onClick.bind(this);
+  }
+
+  onClick(e) {
+    e.preventDefault;
+    this.props.onZoomRequest(this.props.request);
+  }
+
+  render() {
+    var requestView = getRequestView(
+      this.props.request,
+      this.props.onZoomRequest ? this.onClick : null);
+    return (
+      <div>
+        { this.props.showdate ?
+            <div className="date text-uppercase">
+              <FormattedRelative value={new Date(this.props.request.date * 1000)} />
+            </div>
+          : ""
+        }
+        {requestView}
+      </div>
+    );
+  }
+}
+Request.defaultProps = {
+    onZoomRequest: null,
+};
diff --git a/hubs/static/client/app/widgets/halp/Request.jsx b/hubs/static/client/app/widgets/halp/Request.jsx
deleted file mode 100644
index bc80c6c..0000000
--- a/hubs/static/client/app/widgets/halp/Request.jsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react';
-import {FormattedRelative} from 'react-intl';
-import getRequestView from './getRequestView.jsx';
-
-
-export default class Request extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.onClick = this.onClick.bind(this);
-  }
-
-  onClick(e) {
-    e.preventDefault;
-    this.props.onZoomRequest(this.props.request);
-  }
-
-  render() {
-    var requestView = getRequestView(
-      this.props.request,
-      this.props.onZoomRequest ? this.onClick : null);
-    return (
-      <div>
-        { this.props.showdate ?
-            <div className="date text-uppercase">
-              <FormattedRelative value={new Date(this.props.request.date * 1000)} />
-            </div>
-          : ""
-        }
-        {requestView}
-      </div>
-    );
-  }
-}
-Request.defaultProps = {
-    onZoomRequest: null,
-};
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/Widget.js b/hubs/static/client/app/widgets/halp/Widget.js
new file mode 100644
index 0000000..099adb2
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/Widget.js
@@ -0,0 +1,213 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+  defineMessages,
+  FormattedMessage,
+  } from 'react-intl';
+import {
+  widgetDidUpdate,
+  widgetWillUpdate
+  } from "../../core/actions/widget";
+import HubsList from './HubsList';
+import ModalRequest from './ModalRequest';
+import ModalAllRequests from './ModalAllRequests';
+import Request from './Request';
+import WidgetChrome from '../../components/WidgetChrome';
+import Spinner from "../../components/Spinner";
+import "./halp.css";
+
+
+const messages = defineMessages({
+  no_request: {
+    id: "hubs.widgets.halp.no_request",
+    defaultMessage: "No request for now."
+  },
+  view_more: {
+    id: "hubs.widgets.halp.view_more",
+    defaultMessage: "View more"
+  },
+  zoom_title: {
+    id: "hubs.widgets.halp.zoom.title",
+    defaultMessage: "Help request"
+  },
+  search_title: {
+    id: "hubs.widgets.halp.search.title",
+    defaultMessage: "All Help Requests"
+  },
+});
+
+
+export default class Widget extends React.Component {
+
+  propTypes: {
+    widget: PropTypes.object.isRequired,
+    editMode: PropTypes.bool,
+    needsUpdate: PropTypes.bool,
+  }
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      requests: [],
+      inactiveHubs: [],
+      zoomedRequest: null,
+      allRequestsOpen: false,
+      isLoading: false
+    };
+    this.zoomOnRequest = this.zoomOnRequest.bind(this);
+    this.onZoomClose = this.onZoomClose.bind(this);
+    this.openAllRequests = this.openAllRequests.bind(this);
+    this.onAllRequestsClose = this.onAllRequestsClose.bind(this);
+    this.onHubClick = this.onHubClick.bind(this);
+  }
+
+  componentDidMount() {
+    if (!this.props.editMode) {
+      this.loadFromServer();
+    }
+  }
+
+  componentWillUnmount() {
+    this.serverRequest.abort();
+  }
+
+  componentDidUpdate(prevProps, prevState) {
+    if (this.props.needsUpdate && !this.props.editMode && !this.state.isLoading) {
+      this.loadFromServer();
+    }
+  }
+
+  loadFromServer() {
+    let hubs = this.props.widget.config.hubs || [];
+    hubs = hubs.filter((hub) => (this.state.inactiveHubs.indexOf(hub) === -1));
+    const params = hubs.length > 0 ? $.param({hubs}, true) : "hubs=";
+    this.props.dispatch(widgetWillUpdate(this.props.widget.idx));
+    this.setState({isLoading: true});
+    this.serverRequest = $.ajax({
+      url: this.props.widget.urls.data,
+      method: 'GET',
+      data: params,
+      dataType: 'json',
+      cache: false,
+      success: (data) => {
+        this.setState({
+          requests: data.data.requests,
+          isLoading: false
+        },
+          () => (
+            this.props.dispatch(widgetDidUpdate(this.props.widget.idx))
+          )
+        );
+      },
+      error: (xhr, status, err) => {
+        console.error(this.props.widget.urls.data, status, err.toString());
+        this.setState({isLoading: false});
+      }
+    });
+  }
+
+  zoomOnRequest(request) {
+    this.setState({
+      zoomedRequest: request,
+      allRequestsOpen: false,
+      });
+  }
+  onZoomClose() {
+    this.setState({zoomedRequest: null});
+  }
+
+  openAllRequests(e) {
+    e.preventDefault();
+    this.setState({allRequestsOpen: true});
+  }
+  onAllRequestsClose() {
+    this.setState({allRequestsOpen: false});
+  }
+
+  onHubClick(hubName) {
+    var newInactiveHubs = this.state.inactiveHubs.slice(),
+        inactiveIndex = this.state.inactiveHubs.indexOf(hubName);
+    if (inactiveIndex === -1) {
+      newInactiveHubs.push(hubName);
+    } else {
+      newInactiveHubs.splice(inactiveIndex, 1);
+    }
+    this.setState(
+      { inactiveHubs: newInactiveHubs },
+      this.loadFromServer);
+  }
+
+  render() {
+    let requestNodes;
+    if (this.state.requests.length === 0) {
+      requestNodes = (
+        <p className="no-request">
+          <FormattedMessage {...messages.no_request} />
+        </p>
+        );
+    } else {
+      let previousDate = null;
+      requestNodes = this.state.requests.map(function(request, idx) {
+        const showDate = (request.date !== previousDate);
+        previousDate = request.date;
+        return (
+          <Request
+            request={request}
+            showdate={showDate}
+            onZoomRequest={this.zoomOnRequest}
+            key={idx} />
+        );
+      }.bind(this));
+    }
+    let hubs = this.props.widget.config.hubs || [];
+    hubs = hubs.map(function(hub) {
+      return {
+        name: hub,
+        active: (this.state.inactiveHubs.indexOf(hub) === -1)
+      }
+    }.bind(this));
+    return (
+      <WidgetChrome
+        widget={this.props.widget}
+        editMode={this.props.editMode}
+        >
+        <div className="widget-halp">
+          <HubsList
+            hubs={hubs}
+            onHubClick={this.onHubClick}
+            />
+          { this.state.isLoading ?
+              <Spinner />
+            :
+              <div className="requests">
+                {requestNodes}
+              </div>
+          }
+          <div className="view-more text-muted">
+            <button className="btn btn-secondary" onClick={this.openAllRequests}>
+              <FormattedMessage {...messages.view_more} />
+              &nbsp; <span className="fa fa-chevron-right" aria-hidden="true"></span>
+            </button>
+          </div>
+          { this.state.zoomedRequest &&
+          <ModalRequest
+            open={this.state.zoomedRequest !== null}
+            data={this.state.zoomedRequest}
+            title={<FormattedMessage {...messages.zoom_title} />}
+            onCloseClicked={this.onZoomClose}
+            />
+          }
+          { this.state.allRequestsOpen &&
+            <ModalAllRequests
+              onCloseClicked={this.onAllRequestsClose}
+              onZoomRequest={this.zoomOnRequest}
+              title={<FormattedMessage {...messages.search_title} />}
+              urls={this.props.widget.urls}
+              hubs={hubs}
+              />
+          }
+        </div>
+      </WidgetChrome>
+    );
+  }
+}
diff --git a/hubs/static/client/app/widgets/halp/Widget.jsx b/hubs/static/client/app/widgets/halp/Widget.jsx
deleted file mode 100644
index 8d64895..0000000
--- a/hubs/static/client/app/widgets/halp/Widget.jsx
+++ /dev/null
@@ -1,182 +0,0 @@
-import React from 'react';
-import {
-  IntlProvider,
-  defineMessages,
-  FormattedMessage,
-  } from 'react-intl';
-import HubsList from './HubsList.jsx';
-import ModalRequest from './ModalRequest.jsx';
-import ModalAllRequests from './ModalAllRequests.jsx';
-import Request from './Request.jsx';
-
-
-const messages = defineMessages({
-  no_request: {
-    id: "hubs.widgets.halp.no_request",
-    defaultMessage: "No request for now."
-  },
-  view_more: {
-    id: "hubs.widgets.halp.view_more",
-    defaultMessage: "View more"
-  },
-  zoom_title: {
-    id: "hubs.widgets.halp.zoom.title",
-    defaultMessage: "Help request"
-  },
-  search_title: {
-    id: "hubs.widgets.halp.search.title",
-    defaultMessage: "All Help Requests"
-  },
-});
-
-
-export default class Widget extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      requests: [],
-      inactiveHubs: [],
-      zoomedRequest: null,
-      allRequestsOpen: false,
-      loading: false
-    };
-    this.zoomOnRequest = this.zoomOnRequest.bind(this);
-    this.onZoomClose = this.onZoomClose.bind(this);
-    this.openAllRequests = this.openAllRequests.bind(this);
-    this.onAllRequestsClose = this.onAllRequestsClose.bind(this);
-    this.onHubClick = this.onHubClick.bind(this);
-  }
-
-  loadFromServer() {
-    this.setState({loading: true});
-    var data = { hubs: [] };
-    this.props.hubs.forEach(function(hub) {
-      if (this.state.inactiveHubs.indexOf(hub) === -1) {
-        data.hubs.push(hub);
-      }
-    }.bind(this));
-    this.serverRequest = $.ajax({
-      url: this.props.urls.data,
-      method: 'GET',
-      data: $.param(data, true),
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({
-          requests: data.requests,
-          loading: false
-        });
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.urls.data, status, err.toString());
-        this.setState({loading: false});
-      }.bind(this)
-    });
-  }
-
-  componentDidMount() {
-    this.loadFromServer();
-  }
-
-  componentWillUnmount() {
-    this.serverRequest.abort();
-  }
-
-  zoomOnRequest(request) {
-    this.setState({zoomedRequest: request});
-  }
-  onZoomClose() {
-    this.setState({zoomedRequest: null});
-  }
-
-  openAllRequests(e) {
-    e.preventDefault();
-    this.setState({allRequestsOpen: true});
-  }
-  onAllRequestsClose() {
-    this.setState({allRequestsOpen: false});
-  }
-
-  onHubClick(hubName) {
-    var newInactiveHubs = this.state.inactiveHubs.slice(),
-        inactiveIndex = this.state.inactiveHubs.indexOf(hubName);
-    if (inactiveIndex === -1) {
-      newInactiveHubs.push(hubName);
-    } else {
-      newInactiveHubs.splice(inactiveIndex, 1);
-    }
-    this.setState(
-      { inactiveHubs: newInactiveHubs },
-      this.loadFromServer);
-  }
-
-  render() {
-    var requestNodes;
-    if (this.state.requests.length === 0) {
-      requestNodes = (
-        <p className="no-request">
-          <FormattedMessage {...messages.no_request} />
-        </p>
-        );
-    } else {
-      var previousDate = null;
-      requestNodes = this.state.requests.map(function(request, idx) {
-        var showDate = (request.date !== previousDate);
-        previousDate = request.date;
-        return (
-          <Request
-            request={request}
-            showdate={showDate}
-            onZoomRequest={this.zoomOnRequest}
-            key={idx} />
-        );
-      }.bind(this));
-    }
-    var hubs = this.props.hubs.map(function(hub) {
-      return {
-        name: hub,
-        active: (this.state.inactiveHubs.indexOf(hub) === -1)
-      }
-    }.bind(this));
-    return (
-      <IntlProvider locale={navigator.language}>
-        <div className="widget-halp">
-          <HubsList
-            hubs={hubs}
-            onHubClick={this.onHubClick}
-            />
-          { this.state.loading ?
-              <div className="loading-circle mx-auto d-block"></div>
-            :
-              <div className="requests">
-                {requestNodes}
-              </div>
-          }
-          <div className="view-more text-muted">
-            <button className="btn btn-secondary" onClick={this.openAllRequests}>
-              <FormattedMessage {...messages.view_more} />
-              &nbsp; <span className="fa fa-chevron-right" aria-hidden="true"></span>
-            </button>
-          </div>
-          <ModalRequest
-            open={this.state.zoomedRequest !== null}
-            data={this.state.zoomedRequest}
-            title={<FormattedMessage {...messages.zoom_title} />}
-            onHidden={this.onZoomClose} />
-          <ModalAllRequests
-            open={this.state.allRequestsOpen}
-            onHidden={this.onAllRequestsClose.bind(this)}
-            onZoomRequest={this.zoomOnRequest}
-            title={<FormattedMessage {...messages.search_title} />}
-            urls={this.props.urls}
-            hubs={hubs}
-            />
-        </div>
-      </IntlProvider>
-    );
-  }
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/getRequestView.js b/hubs/static/client/app/widgets/halp/getRequestView.js
new file mode 100644
index 0000000..13e3d17
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/getRequestView.js
@@ -0,0 +1,64 @@
+import React from 'react';
+import { FormattedMessage, defineMessages } from 'react-intl';
+import Linkify from 'react-linkify';
+
+
+const messages = defineMessages({
+  req_no_text: {
+    id: "hubs.widgets.halp.req_no_text",
+    defaultMessage: "(no message)"
+  },
+});
+
+
+export default function getRequestView(request, openCallback) {
+    var openButton = "";
+    if (openCallback) {
+      openButton = (
+        <div className="media-right media-middle">
+          <button className="btn btn-secondary btn-sm" onClick={openCallback}>
+            <span className="fa fa-chevron-right" aria-hidden="true"></span>
+          </button>
+        </div>
+      );
+    }
+    return (
+      <div className="request row">
+        <div className="hub col-sm-6">
+          <span>@{request.hub}</span>
+        </div>
+        <div className="channel col-sm-6">
+          {request.channel}
+        </div>
+        <div className="text col-sm-12">
+          { request.text ?
+            <Linkify>{'"'}{request.text}{'"'}</Linkify>
+          :
+            <em><FormattedMessage {...messages.req_no_text } /></em>
+          }
+        </div>
+        { request.url ?
+        <div className="url col-sm-12">
+          <a href={request.url}>
+            {request.url.replace(/^https?:\/\//, '')}
+          </a>
+        </div>
+        : null }
+        <div className="author media col-sm-12">
+          <a
+            href={request.author.url} target="_blank"
+            className="d-flex mr-3"
+            >
+            <img className="square-32 img-circle"
+                 src={request.author.avatar} />
+          </a>
+          <div className="media-body align-self-center">
+            <a href={request.author.url}>
+              {request.author.name}
+            </a>
+          </div>
+          {openButton}
+        </div>
+      </div>
+    );
+}
diff --git a/hubs/static/client/app/widgets/halp/getRequestView.jsx b/hubs/static/client/app/widgets/halp/getRequestView.jsx
deleted file mode 100644
index 1f7627b..0000000
--- a/hubs/static/client/app/widgets/halp/getRequestView.jsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import { FormattedMessage, defineMessages } from 'react-intl';
-import Linkify from 'react-linkify';
-
-
-const messages = defineMessages({
-  req_no_text: {
-    id: "hubs.widgets.halp.req_no_text",
-    defaultMessage: "(no message)"
-  },
-});
-
-
-export default function getRequestView(request, openCallback) {
-    var openButton = "";
-    if (openCallback) {
-      openButton = (
-        <div className="media-right media-middle">
-          <button className="btn btn-secondary btn-sm" onClick={openCallback}>
-            <span className="fa fa-chevron-right" aria-hidden="true"></span>
-          </button>
-        </div>
-      );
-    }
-    return (
-      <div className="request row">
-        <div className="hub col-sm-6">
-          <span>@{request.hub}</span>
-        </div>
-        <div className="channel col-sm-6">
-          {request.channel}
-        </div>
-        <div className="text col-sm-12">
-          { request.text ?
-            <Linkify>"{request.text}"</Linkify>
-          :
-            <em><FormattedMessage {...messages.req_no_text } /></em>
-          }
-        </div>
-        { request.url ?
-        <div className="url col-sm-12">
-          <a href={request.url}>
-            {request.url.replace(/^https?:\/\//, '')}
-          </a>
-        </div>
-        : null }
-        <div className="author media col-sm-12">
-          <a
-            href={request.author.url} target="_blank"
-            className="d-flex mr-3"
-            >
-            <img className="square-32 img-circle"
-                 src={request.author.avatar} />
-          </a>
-          <div className="media-body align-self-center">
-            <a href={request.author.url}>
-              {request.author.name}
-            </a>
-          </div>
-          {openButton}
-        </div>
-      </div>
-    );
-}
-
-
-// vim: set ts=2 sw=2 et:
diff --git a/hubs/static/client/app/widgets/halp/halp.css b/hubs/static/client/app/widgets/halp/halp.css
new file mode 100644
index 0000000..e533bcc
--- /dev/null
+++ b/hubs/static/client/app/widgets/halp/halp.css
@@ -0,0 +1,126 @@
+
+
+/*
+ * Widget halp
+ */
+
+.widget-halp {
+}
+.widget-halp .hubs {
+    color: gray;
+}
+.widget-halp .hubs .fa {
+    margin-right: 4px;
+}
+.widget-halp .hubs span.hub {
+    border: 1px solid gray;
+    border-radius: 2px;
+    background-color: #eee;
+    display: inline-block;
+    margin: 2px 3px 2px 0;
+    padding: 1px 2px;
+    font-size: 90%;
+    cursor: pointer;
+}
+.widget-halp .hubs span.hub.inactive {
+    background-color: white;
+}
+.widget-halp .Spinner {
+    margin: 0 auto;
+}
+.widget-halp .requests {
+}
+.widget-halp .requests .no-request {
+    margin-top: 10px;
+}
+.widget-halp .requests .date {
+    text-transform: uppercase;
+    font-size: 110%;
+    margin-top: 10px;
+}
+.widget-halp .request {
+    background-color: #f5f5f5;
+    padding: 1em 0;
+    margin-top: 5px;
+}
+.widget-halp .request .hub span {
+    float: left;
+    font-weight: bold;
+    color: white;
+    background-color: #5bc0de;
+    border-radius: 10px;
+    padding: 2px 4px;
+}
+.widget-halp .request .channel {
+    color: gray;
+    text-align: right;
+}
+.widget-halp .request .text {
+    margin-top: 10px;
+}
+.widget-halp .request .url {
+    margin-top: 5px;
+    margin-bottom: 15px;
+}
+.widget-halp .request .author {
+}
+.widget-halp .request .open {
+    text-align: right;
+}
+.widget-halp .request .open button {
+    background-color: white;
+    border-color: gray;
+}
+.widget-halp .request .open button:hover {
+    background-color: #ccc;
+}
+.widget-halp .zoomed-request ol>li {
+    margin-top: 1em;
+}
+.widget-halp .view-more {
+    margin-top: 2em;
+    text-align: center;
+}
+.widget-halp .view-more a {
+    color: gray;
+}
+.widget-halp .ModalAllRequests .SpinnerCircle {
+    display: inline-block;
+    vertical-align: middle;
+}
+
+
+
+/*
+ * Config panel
+ */
+
+.widget-halp-config .hubs-list h5 {
+  font-weight: bold;
+}
+.widget-halp-config .hubs-list ul {
+  color: gray;
+}
+.widget-halp-config .hubs-list .hub {
+  border: 1px solid #aaa;
+  border-radius: 4px;
+  display: inline-block;
+  margin: 0.7em 0.5em 0 0;
+  padding: 1px 4px;
+  color: #aaa;
+}
+.widget-halp-config .hubs-list .remove-hub {
+  cursor: pointer;
+  font-weight: bold;
+}
+.widget-halp-config .form-side {
+  border-left: 1px solid #aaa;
+}
+.widget-halp-config h4 {
+  font-weight: bold;
+  margin-bottom: 1em;
+}
+.widget-halp-config fieldset {
+  margin-top: 1.5em;
+}
+
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 553d1c1..d6e4a1b 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -7,6 +7,8 @@
     "doc": "docs"
   },
   "dependencies": {
+    "babel-polyfill": "^6.26.0",
+    "isomorphic-fetch": "^2.2.1",
     "prop-types": "^15.5.10",
     "react": "^15.6.1",
     "react-autosuggest": "^9.3.2",
@@ -14,34 +16,58 @@
     "react-intl": "^2.3.0",
     "react-linkify": "^0.2.1",
     "react-loadable": "^4.0.4",
+    "react-redux": "^5.0.6",
+    "react-sortable-hoc": "^0.6.7",
     "react-timeago": "^3.4.3",
-    "reconnecting-eventsource": "^1.0.1"
+    "reconnecting-eventsource": "^1.0.1",
+    "redux": "^3.7.2",
+    "redux-thunk": "^2.2.0"
   },
   "devDependencies": {
     "babel-core": "^6.26.0",
     "babel-eslint": "^7.2.3",
     "babel-jest": "^20.0.3",
     "babel-loader": "^7.1.1",
+    "babel-plugin-dynamic-import-node": "^1.1.0",
     "babel-plugin-syntax-dynamic-import": "^6.18.0",
+    "babel-plugin-transform-object-rest-spread": "^6.26.0",
     "babel-preset-es2015": "^6.24.1",
     "babel-preset-react": "^6.24.1",
+    "clean-webpack-plugin": "^0.1.17",
     "css-loader": "^0.28.4",
+    "enzyme": "^3.0.0",
+    "enzyme-adapter-react-15": "^1.0.0",
     "eslint": "^4.4.1",
     "eslint-loader": "^1.9.0",
     "eslint-plugin-react": "^7.2.1",
+    "extract-text-webpack-plugin": "^3.0.0",
     "file-loader": "^0.11.2",
     "jest": "^20.0.4",
     "react-test-renderer": "^15.6.1",
+    "redux-devtools": "^3.4.0",
     "style-loader": "^0.18.2",
-    "webpack": "^3.5.5"
+    "uglifyjs-webpack-plugin": "^0.4.6",
+    "webpack": "^3.5.5",
+    "webpack-merge": "^4.1.0"
   },
   "scripts": {
-    "dev": "webpack --watch",
-    "build": "webpack -p",
+    "dev": "webpack --watch --config webpack.dev.js",
+    "build": "webpack -p --config webpack.prod.js",
     "lint": "eslint app/*",
     "test": "jest"
   },
   "jest": {
+    "moduleFileExtensions": [
+      "js",
+      "jsx"
+    ],
+    "moduleDirectories": [
+      "node_modules"
+    ],
+    "moduleNameMapper": {
+      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
+      "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
+    },
     "unmockedModulePathPatterns": [
       "<rootDir>/node_modules/react/",
       "<rootDir>/node_modules/react-dom/",
@@ -49,8 +75,11 @@
       "<rootDir>/node_modules/react-addons-test-utils/",
       "<rootDir>/node_modules/react-intl/",
       "<rootDir>/node_modules/intl-messageformat/"
+    ],
+    "setupFiles": [
+      "<rootDir>/setupTests.js"
     ]
   },
-  "author": "Eric Barbour <ebarbour@redhat.com>",
+  "author": "Aurelien Bompard <abompard@fedoraproject.org>",
   "license": "AGPL-3.0"
 }
diff --git a/hubs/static/client/setupTests.js b/hubs/static/client/setupTests.js
new file mode 100644
index 0000000..d74d0e0
--- /dev/null
+++ b/hubs/static/client/setupTests.js
@@ -0,0 +1,4 @@
+import Enzyme from 'enzyme';
+import Adapter from 'enzyme-adapter-react-15';
+
+Enzyme.configure({ adapter: new Adapter() });
diff --git a/hubs/static/client/webpack.common.js b/hubs/static/client/webpack.common.js
new file mode 100644
index 0000000..e060cd7
--- /dev/null
+++ b/hubs/static/client/webpack.common.js
@@ -0,0 +1,61 @@
+const webpack = require('webpack');
+const path = require('path');
+const CleanWebpackPlugin = require('clean-webpack-plugin');
+
+const PATHS = {
+  app: path.join(__dirname, 'app'),
+  build: path.join(__dirname, '..', 'js', 'build')
+};
+
+module.exports = {
+  entry: {
+    Hubs: path.join(PATHS.app, 'core', 'index.js'),
+  },
+  output: {
+    path: PATHS.build,
+    filename: '[name].js',
+    chunkFilename: '[name].[chunkhash:8].bundle.js',
+    publicPath: "/static/js/build/", // TODO: https://webpack.js.org/guides/public-path/
+    library: 'Hubs',
+  },
+  externals: {
+    'jquery': 'jQuery',
+    'react': 'React',
+    'react-dom': 'ReactDOM',
+  },
+  module: {
+    rules: [
+    {
+      test: /\.jsx?$/,
+      enforce: 'pre',
+      loader: 'eslint-loader',
+      options: {
+        emitWarning: true,
+      },
+      include : PATHS.app
+    },
+    {
+      test : /\.jsx?$/,
+      loader : 'babel-loader',
+      options: {
+        cacheDirectory: true,
+      },
+      exclude: /node_modules/,
+      include : PATHS.app
+    },
+    {
+      test: /\.(png|svg|jpg|gif)$/,
+      use: [ 'file-loader' ]
+    }
+    ]
+  },
+  plugins: [
+    new CleanWebpackPlugin(
+      [PATHS.build], {
+        allowExternal: true,
+        exclude: ['.gitignore']
+      }
+    ),
+    new webpack.optimize.CommonsChunkPlugin("common")
+  ]
+};
diff --git a/hubs/static/client/webpack.config.js b/hubs/static/client/webpack.config.js
deleted file mode 100644
index c308851..0000000
--- a/hubs/static/client/webpack.config.js
+++ /dev/null
@@ -1,63 +0,0 @@
-const webpack = require('webpack');
-const path = require('path');
-
-const PATHS = {
-  app: path.join(__dirname, 'app'),
-  build: path.join(__dirname, '..', 'js', 'build')
-};
-
-const config = {
-  entry: {
-    Hubs: path.join(PATHS.app, 'core', 'Hubs.js'),
-    Feed: path.join(PATHS.app, 'widgets', 'feed', 'Feed.js'),
-    Halp: path.join(PATHS.app, 'widgets', 'halp', 'Halp.js')
-  },
-  output: {
-    path: PATHS.build,
-    filename: '[name].js',
-    library: '[name]',
-  },
-  externals: {
-    'jquery': 'jQuery',
-    'react': 'React',
-    'react-dom': 'ReactDOM',
-  },
-  module: {
-    rules: [
-    {
-      test: /\.jsx?$/,
-      enforce: 'pre',
-      loader: 'eslint-loader',
-      options: {
-        emitWarning: true,
-      },
-      include : PATHS.app
-    },
-    {
-      test : /\.jsx?$/,
-      loader : 'babel-loader',
-      options: {
-        cacheDirectory: true,
-      },
-      exclude: /node_modules/,
-      include : PATHS.app
-    },
-    {
-      test: /\.css$/,
-      use: [
-        'style-loader',
-        'css-loader'
-      ]
-    },
-    {
-      test: /\.(png|svg|jpg|gif)$/,
-      use: [ 'file-loader' ]
-    }
-    ]
-  },
-  plugins: [
-    new webpack.optimize.CommonsChunkPlugin("common")
-  ]
-};
-
-module.exports = config;
diff --git a/hubs/static/client/webpack.dev.js b/hubs/static/client/webpack.dev.js
new file mode 100644
index 0000000..01164e2
--- /dev/null
+++ b/hubs/static/client/webpack.dev.js
@@ -0,0 +1,17 @@
+const merge = require('webpack-merge');
+const common = require('./webpack.common.js');
+
+module.exports = merge(common, {
+  devtool: 'inline-source-map',
+  module: {
+    rules: [
+    {
+      test: /\.css$/,
+      use: [
+        'style-loader',
+        'css-loader'
+      ]
+    }
+    ]
+  },
+});
diff --git a/hubs/static/client/webpack.prod.js b/hubs/static/client/webpack.prod.js
new file mode 100644
index 0000000..5db728b
--- /dev/null
+++ b/hubs/static/client/webpack.prod.js
@@ -0,0 +1,34 @@
+const webpack = require('webpack');
+const merge = require('webpack-merge');
+const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
+const ExtractTextPlugin = require("extract-text-webpack-plugin");
+const common = require('./webpack.common.js');
+
+module.exports = merge(common, {
+  devtool: 'source-map',
+  module: {
+    rules: [
+    {
+      test: /\.css$/,
+      use: ExtractTextPlugin.extract({
+        fallback: "style-loader",
+        use: "css-loader"
+      })
+    }
+    ]
+  },
+  plugins: [
+    new ExtractTextPlugin({
+      filename: "style.css",
+      allChunks: true,
+    }),
+    new UglifyJSPlugin({
+      sourceMap: true
+    }),
+    new webpack.DefinePlugin({
+      'process.env': {
+        'NODE_ENV': JSON.stringify('production')
+      }
+    })
+  ]
+})
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index d19cc3e..8d77ee2 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -128,94 +128,11 @@ header span.edit {
   outline: 0;
 }
 
-  .loading {
-      width: 50px;
-      height: 10px;
-      background: url("../img/spinner.gif") no-repeat center center;
-      vertical-align: bottom;
-      display: none;  /* hidden by default */
-  }
-
-.loading-circle {
-  width: 32px;
-  height: 32px;
-  line-height: 32px;
-  background: url("../img/spinner-circle.gif") no-repeat center center;
-  vertical-align: bottom;
-  display: none;  /* hidden by default */
-}
-
-
-
-/*
- * Settings
- */
-
-#settings-modal .modal-title {
-  line-height: 1;
-}
-#settings-modal .nav {
-  border: 0;
-  background-color: #eee;
-}
-#settings-modal .nav-tabs .nav-item {
-  float: none;
-  margin-bottom: 0;
-}
-#settings-modal .nav-tabs .nav-link {
-  border: 0;
-}
-#settings-modal .modal-body h3 {
-  margin-bottom: 1em;
-}
-#settings-modal .modal-body label {
-  font-size: 115%;
-}
-#settings-modal .modal-body .tab-content {
-  padding: 1em;
-  padding-bottom: 2em;
-}
-
-@media (min-width: 768px) {
-  /* the menu is on the left */
-  #settings-modal .nav .nav-item {
-    margin-bottom: 0;
-  }
-  #settings-modal .nav .nav-link {
-    border-radius: 0.25rem 0 0 0.25rem;
-  }
-}
-
 
 /*
  * Widgets
  */
 
-.widget {
-  font-family: 'Open Sans', sans-serif;
-  margin-bottom: .5rem;
-}
-
-.widget .card {
-  width: 100%;
-}
-
-.widget-buttons {
-  font-size: 10px;
-  position: absolute;
-  top: 0;
-  right: 0;
-  padding: .3rem;
-}
-
-.widget .widget-buttons a {
-  margin-right: .4rem;
-  color: #373a3c;
-}
-.widget .widget-buttons a:hover {
-  text-decoration: none;
-}
-
 /* hub widgets */
 .rules-table {
   width: 180px
@@ -288,27 +205,6 @@ font-size: 32pt;
 .navbar-nav > li.idle-2years  > a { color: #BBB; }
 .navbar-nav > li.idle-5years  > a { color: #CCC; }
 
-#vertical-navbar {
-  background-color: #fcfcfc;
-  border: 1px solid #dddddd;
-}
-@media (min-width: 992px) {
-  #vertical-navbar {
-    position: relative;
-    top: -85px;
-  }
-}
-
-#vertical-navbar a.nav-link {
-  color: #373a3c;
-  font-size: 85%;
-}
-
-#vertical-navbar a.nav-link.active {
-  color: white;
-  /*background-color: #373a3c;*/
-}
-
 
 
 
@@ -395,11 +291,6 @@ font-size: 32pt;
   border-bottom: none !important;
 }
 
-.modal-footer button {
-  float: right;
-  margin-left: 1em;
-}
-
 .p-abs {
   position: absolute;
   bottom: 0;
@@ -420,168 +311,16 @@ font-size: 32pt;
 }
 
 
-/*
- * Autosuggest
- */
-.completion-input {
-  position: relative;
-}
-.react-autosuggest__suggestions-container {
-  position: absolute;
-  width: 100%;
-  z-index: 10;
-}
-.react-autosuggest__suggestions-list {
-  list-style: none;
-  padding: 0.3em 0.8em;
-  background-color: #fafafa;
-  border-bottom-left-radius: .25rem;
-  border-bottom-right-radius: .25rem;
-  border: 1px solid #ccc;
-  border-top: none;
-}
-.react-autosuggest__suggestion {
-  cursor: pointer;
-}
-.react-autosuggest__container--open input {
-  border-bottom-left-radius: 0px;
-  border-bottom-right-radius: 0px;
-}
-
-.completion-input .loading-circle {
-  position: absolute;
-  top: 0;
-  right: 0;
-  z-index: 2;
-}
-
-
-
-/*
- * Widget halp
- */
-.widget-halp {
-}
-.widget-halp .hubs {
-    color: gray;
-}
-.widget-halp .hubs .fa {
-    margin-right: 4px;
-}
-.widget-halp .hubs span.hub {
-    border: 1px solid gray;
-    border-radius: 2px;
-    background-color: #eee;
-    display: inline-block;
-    margin: 2px 3px 2px 0;
-    padding: 1px 2px;
-    font-size: 90%;
-    cursor: pointer;
-}
-.widget-halp .hubs span.hub.inactive {
-    background-color: white;
-}
-.widget-halp .requests {
-}
-.widget-halp .requests .no-request {
-    margin-top: 10px;
-}
-.widget-halp .requests .date {
-    text-transform: uppercase;
-    font-size: 110%;
-    margin-top: 10px;
-}
-.widget-halp .request {
-    background-color: #f5f5f5;
-    padding: 1em 0;
-    margin-top: 5px;
-}
-.widget-halp .request .hub span {
-    float: left;
-    font-weight: bold;
-    color: white;
-    background-color: #5bc0de;
-    border-radius: 10px;
-    padding: 2px 4px;
-}
-.widget-halp .request .channel {
-    color: gray;
-    text-align: right;
-}
-.widget-halp .request .text {
-    margin-top: 10px;
-}
-.widget-halp .request .url {
-    margin-top: 5px;
-    margin-bottom: 15px;
-}
-.widget-halp .request .author {
-}
-.widget-halp .request .open {
-    text-align: right;
-}
-.widget-halp .request .open button {
-    background-color: white;
-    border-color: gray;
-}
-.widget-halp .request .open button:hover {
-    background-color: #ccc;
-}
-.widget-halp .zoomed-request ol>li {
-    margin-top: 1em;
-}
-.widget-halp .view-more {
-    margin-top: 2em;
-    text-align: center;
-}
-.widget-halp .view-more a {
-    color: gray;
-}
-
-/* Config panel */
-.widget-halp-config .modal-body {
-  padding-top: 1em;
-}
-.widget-halp-config .hubs-list h5 {
-  font-weight: bold;
-}
-.widget-halp-config .hubs-list ul {
-  color: gray;
-}
-.widget-halp-config .hubs-list .hub {
-  border: 1px solid #aaa;
-  border-radius: 4px;
-  display: inline-block;
-  margin: 0.7em 0.5em 0 0;
-  padding: 1px 4px;
-  color: #aaa;
-}
-.widget-halp-config .hubs-list .remove-hub {
-  cursor: pointer;
-  font-weight: bold;
-}
-.widget-halp-config .modal-body .form-side {
-  border-left: 1px solid #aaa;
-}
-.widget-halp-config .modal-body h4 {
-  font-weight: bold;
-  margin-bottom: 1em;
-}
-.widget-halp-config fieldset {
-  margin-top: 1.5em;
-}
-
 
 /*
  *  Contact Widget
  */
- 
- 
+
 .widget-contact .card-block ul {
   padding: 0px; 
 }
 
-.widget-contact i {
+.widget-contact .card-block i {
   width: 25px;
   text-align: center;
 }
@@ -590,7 +329,7 @@ font-size: 32pt;
 /*
  * Issue Widgets
  */
- 
+
 .widget .widget-pagure_pr li,
 .widget .widget-githubissues li,
 .widget .widget-bugzilla li {
@@ -603,16 +342,6 @@ font-size: 32pt;
 border: 0}
 
 
-/*
- * Widget Feed
- */
-
-.component-feed .media {
-  border-bottom: 1px solid rgba(0, 0, 0, .125);
-}
-.component-feed .media:last-child {
-  border: 0
-}
 
 
 /** fedora bootstrap overrides **/
@@ -665,8 +394,7 @@ header h5.m-b-1 {
 }
 
 
-#right_widgets .widget-contact .card-block {
-  padding-top: 1rem !important;
+#right_widgets .widget-contact .contactinfo-container {
   font-size: 80%;
 }
 
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 3e65d31..98efe34 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -6,6 +6,7 @@
   <link href="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.min.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
+  <link href="{{ url_for('static', filename='js/build/style.css') }}" rel="stylesheet" />
   <script type="text/javascript"  src="{{ url_for('static', filename='js/pace.min.js') }}"></script>
   <script type="text/javascript"  src="{{ url_for('static', filename='notificon.js') }}"></script>
   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css">
diff --git a/tox.ini b/tox.ini
index a6609a0..c7e54cf 100644
--- a/tox.ini
+++ b/tox.ini
@@ -52,4 +52,4 @@ commands =
 
 [flake8]
 show-source = True
-exclude = .git,.tox,dist,*egg,doc
+exclude = .git,.tox,dist,*egg,doc,node_modules

From 27779006a2b6826a24a920ffd7ec489358a17ed0 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 06 2017 16:30:51 +0000
Subject: [PATCH 964/1001] Various minor refactoring


---

diff --git a/hubs/static/client/.babelrc b/hubs/static/client/.babelrc
index aa30d85..bfa2dab 100644
--- a/hubs/static/client/.babelrc
+++ b/hubs/static/client/.babelrc
@@ -1,9 +1,16 @@
 {
   "presets" : [["es2015", {"modules": false}], "react"],
-  "plugins": ["syntax-dynamic-import", "transform-object-rest-spread"],
+  "plugins": [
+    "syntax-dynamic-import",
+    "transform-object-rest-spread"
+  ],
   "env": {
     "test": {
-      "plugins": ["transform-es2015-modules-commonjs", "dynamic-import-node", "transform-object-rest-spread"]
+      "plugins": [
+        "transform-es2015-modules-commonjs",
+        "dynamic-import-node",
+        "transform-object-rest-spread",
+      ]
     }
   }
 }
diff --git a/hubs/static/client/app/core/App.js b/hubs/static/client/app/core/App.js
index 6c90b23..2fb30fc 100644
--- a/hubs/static/client/app/core/App.js
+++ b/hubs/static/client/app/core/App.js
@@ -1,32 +1,14 @@
 import React from 'react';
-import {
-  connect,
-  Provider
-  } from 'react-redux';
+import { Provider } from 'react-redux';
 import { IntlProvider } from 'react-intl';
-import * as Pages from "../core/Pages";
+import PageContainer from "./PageContainer";
 
 
-const PageContainer = connect(
-  (state) => ({pageName: state.ui.page})
-)(
-  (props) => {
-    if (!Pages[props.pageName]) {
-      console.error("No such page: " + props.pageName + ". Choose one of:", Object.keys(Pages).join(", "));
-      return null;
-    }
-    return React.createElement(Pages[props.pageName], {});
-  }
+const App = (props) => (
+  <Provider store={props.store}>
+    <IntlProvider locale={navigator.language}>
+      <PageContainer />
+    </IntlProvider>
+  </Provider>
 );
-
-
-const App = (props) => {
-  return (
-    <Provider store={props.store}>
-      <IntlProvider locale={navigator.language}>
-        <PageContainer />
-      </IntlProvider>
-    </Provider>
-  );
-}
 export default App;
diff --git a/hubs/static/client/app/core/PageContainer.js b/hubs/static/client/app/core/PageContainer.js
new file mode 100644
index 0000000..ddb5bf0
--- /dev/null
+++ b/hubs/static/client/app/core/PageContainer.js
@@ -0,0 +1,24 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import * as Pages from "./Pages";
+
+
+const PageContainer = (props) => {
+  const Page = Pages[props.pageName];
+  if (!Page) {
+    throw new Error(
+      "No such page: " + props.pageName
+      + ". Choose one of:",
+      Object.keys(Pages).join(", ")
+    );
+  }
+  return (
+    <Page />
+  );
+}
+
+export default connect(
+  (state) => ({pageName: state.ui.page})
+)(
+  PageContainer
+);
diff --git a/hubs/static/client/app/core/index.js b/hubs/static/client/app/core/index.js
deleted file mode 100644
index a6cbb81..0000000
--- a/hubs/static/client/app/core/index.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Add the ES6 Promise polyfill because all browsers don't have it yet. */
-import 'babel-polyfill';
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import { createStore, applyMiddleware } from 'redux';
-import thunk from 'redux-thunk';
-import rootReducer from './reducers';
-import App from "./App";
-
-
-export function setupPage(elementId, initialState) {
-
-  const store = createStore(
-    rootReducer,
-    initialState,
-    applyMiddleware(thunk)
-  );
-  //store.subscribe(() =>
-  //  console.log(store.getState())
-  //)
-  ReactDOM.render(
-    <App store={store} />,
-    document.getElementById(elementId)
-    );
-
-}
diff --git a/hubs/static/client/app/core/store.js b/hubs/static/client/app/core/store.js
new file mode 100644
index 0000000..f04ec7f
--- /dev/null
+++ b/hubs/static/client/app/core/store.js
@@ -0,0 +1,21 @@
+import { createStore, applyMiddleware } from 'redux';
+import thunk from 'redux-thunk';
+import rootReducer from './reducers';
+
+
+let middleware = [
+  thunk
+]
+
+if (process.env.NODE_ENV === "development") {
+  const { logger } = require("redux-logger");
+  middleware.push(logger);
+}
+
+export default function getStore(initialState) {
+  return createStore(
+    rootReducer,
+    initialState,
+    applyMiddleware(...middleware)
+  );
+}
diff --git a/hubs/static/client/app/index.js b/hubs/static/client/app/index.js
new file mode 100644
index 0000000..f1c3824
--- /dev/null
+++ b/hubs/static/client/app/index.js
@@ -0,0 +1,13 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import getStore from "./core/store";
+import App from "./core/App";
+
+
+export function setupPage(elementId, initialState) {
+  const store = getStore(initialState);
+  ReactDOM.render(
+    <App store={store} />,
+    document.getElementById(elementId)
+  );
+}
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index d6e4a1b..c2b0fc5 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -45,6 +45,7 @@
     "jest": "^20.0.4",
     "react-test-renderer": "^15.6.1",
     "redux-devtools": "^3.4.0",
+    "redux-logger": "^3.0.6",
     "style-loader": "^0.18.2",
     "uglifyjs-webpack-plugin": "^0.4.6",
     "webpack": "^3.5.5",
diff --git a/hubs/static/client/webpack.common.js b/hubs/static/client/webpack.common.js
index e060cd7..cdf4140 100644
--- a/hubs/static/client/webpack.common.js
+++ b/hubs/static/client/webpack.common.js
@@ -3,59 +3,63 @@ const path = require('path');
 const CleanWebpackPlugin = require('clean-webpack-plugin');
 
 const PATHS = {
-  app: path.join(__dirname, 'app'),
-  build: path.join(__dirname, '..', 'js', 'build')
+  app: path.resolve(path.join(__dirname, 'app')),
+  build: path.resolve(path.join(__dirname, '..', 'js', 'build'))
 };
 
 module.exports = {
-  entry: {
-    Hubs: path.join(PATHS.app, 'core', 'index.js'),
-  },
-  output: {
-    path: PATHS.build,
-    filename: '[name].js',
-    chunkFilename: '[name].[chunkhash:8].bundle.js',
-    publicPath: "/static/js/build/", // TODO: https://webpack.js.org/guides/public-path/
-    library: 'Hubs',
-  },
-  externals: {
-    'jquery': 'jQuery',
-    'react': 'React',
-    'react-dom': 'ReactDOM',
-  },
-  module: {
-    rules: [
-    {
-      test: /\.jsx?$/,
-      enforce: 'pre',
-      loader: 'eslint-loader',
-      options: {
-        emitWarning: true,
-      },
-      include : PATHS.app
+  paths: PATHS,
+  config: {
+    entry: [
+      'babel-polyfill',
+      path.join(PATHS.app, 'index.js')
+    ],
+    output: {
+      path: PATHS.build,
+      filename: '[name].js',
+      chunkFilename: '[name].[chunkhash:8].bundle.js',
+      publicPath: "/static/js/build/", // TODO: https://webpack.js.org/guides/public-path/
+      library: 'Hubs',
+    },
+    externals: {
+      'jquery': 'jQuery',
+      'react': 'React',
+      'react-dom': 'ReactDOM',
     },
-    {
-      test : /\.jsx?$/,
-      loader : 'babel-loader',
-      options: {
-        cacheDirectory: true,
+    module: {
+      rules: [
+      {
+        test: /\.jsx?$/,
+        enforce: 'pre',
+        loader: 'eslint-loader',
+        options: {
+          emitWarning: true,
+        },
+        include : PATHS.app
+      },
+      {
+        test : /\.jsx?$/,
+        loader : 'babel-loader',
+        options: {
+          cacheDirectory: true,
+        },
+        exclude: /node_modules/,
+        include : PATHS.app
       },
-      exclude: /node_modules/,
-      include : PATHS.app
+      {
+        test: /\.(png|svg|jpg|gif)$/,
+        use: [ 'file-loader' ]
+      }
+      ]
     },
-    {
-      test: /\.(png|svg|jpg|gif)$/,
-      use: [ 'file-loader' ]
-    }
+    plugins: [
+      new CleanWebpackPlugin(
+        [PATHS.build], {
+          allowExternal: true,
+          exclude: ['.gitignore']
+        }
+      ),
+      new webpack.optimize.CommonsChunkPlugin("common"),
     ]
-  },
-  plugins: [
-    new CleanWebpackPlugin(
-      [PATHS.build], {
-        allowExternal: true,
-        exclude: ['.gitignore']
-      }
-    ),
-    new webpack.optimize.CommonsChunkPlugin("common")
-  ]
+  }
 };
diff --git a/hubs/static/client/webpack.dev.js b/hubs/static/client/webpack.dev.js
index 01164e2..56efa9e 100644
--- a/hubs/static/client/webpack.dev.js
+++ b/hubs/static/client/webpack.dev.js
@@ -1,7 +1,8 @@
+const webpack = require('webpack');
 const merge = require('webpack-merge');
 const common = require('./webpack.common.js');
 
-module.exports = merge(common, {
+module.exports = merge(common.config, {
   devtool: 'inline-source-map',
   module: {
     rules: [
@@ -14,4 +15,11 @@ module.exports = merge(common, {
     }
     ]
   },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env': {
+        'NODE_ENV': JSON.stringify('development')
+      }
+    }),
+  ]
 });
diff --git a/hubs/static/client/webpack.prod.js b/hubs/static/client/webpack.prod.js
index 5db728b..2784ad9 100644
--- a/hubs/static/client/webpack.prod.js
+++ b/hubs/static/client/webpack.prod.js
@@ -23,12 +23,8 @@ module.exports = merge(common, {
       allChunks: true,
     }),
     new UglifyJSPlugin({
-      sourceMap: true
+      sourceMap: true,
+      comments: false
     }),
-    new webpack.DefinePlugin({
-      'process.env': {
-        'NODE_ENV': JSON.stringify('production')
-      }
-    })
   ]
 })
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 98efe34..a0f8b8c 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -167,7 +167,7 @@
 <script src="https://unpkg.com/react@15/dist/react{% if not config.DEBUG %}.min{% endif %}.js"></script>
 <script src="https://unpkg.com/react-dom@15/dist/react-dom{% if not config.DEBUG %}.min{% endif %}.js"></script>
 <script src="{{ url_for('static', filename='js/build/common.js') }}"></script>
-<script src="{{ url_for('static', filename='js/build/Hubs.js') }}"></script>
+<script src="{{ url_for('static', filename='js/build/main.js') }}"></script>
 {% endblock %}
 
 </body>

From e36fdb54aede63f8de4eecee672d1b88798ee107 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 06 2017 16:31:05 +0000
Subject: [PATCH 965/1001] Inform the JS UI of the public build path


---

diff --git a/hubs/static/client/app/index.js b/hubs/static/client/app/index.js
index f1c3824..cccae63 100644
--- a/hubs/static/client/app/index.js
+++ b/hubs/static/client/app/index.js
@@ -1,3 +1,7 @@
+// Read the public path from the backend
+// https://webpack.js.org/guides/public-path/
+__webpack_public_path__ = window.resourceBaseUrl;
+
 import React from 'react';
 import ReactDOM from 'react-dom';
 import getStore from "./core/store";
diff --git a/hubs/static/client/webpack.common.js b/hubs/static/client/webpack.common.js
index cdf4140..1f8308f 100644
--- a/hubs/static/client/webpack.common.js
+++ b/hubs/static/client/webpack.common.js
@@ -18,7 +18,6 @@ module.exports = {
       path: PATHS.build,
       filename: '[name].js',
       chunkFilename: '[name].[chunkhash:8].bundle.js',
-      publicPath: "/static/js/build/", // TODO: https://webpack.js.org/guides/public-path/
       library: 'Hubs',
     },
     externals: {
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index a0f8b8c..cbdab08 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -166,6 +166,10 @@
 <script src="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.min.js') }}"></script>
 <script src="https://unpkg.com/react@15/dist/react{% if not config.DEBUG %}.min{% endif %}.js"></script>
 <script src="https://unpkg.com/react-dom@15/dist/react-dom{% if not config.DEBUG %}.min{% endif %}.js"></script>
+<script>
+{# Inform the JS UI of the public build path. It *must* end with a slash. #}
+window.resourceBaseUrl = {{ url_for('static', filename='js/build/') | tojson }};
+</script>
 <script src="{{ url_for('static', filename='js/build/common.js') }}"></script>
 <script src="{{ url_for('static', filename='js/build/main.js') }}"></script>
 {% endblock %}

From 4259cf05e927b47b2f392ef5f11c8dadc7ba0d69 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 06 2017 16:31:14 +0000
Subject: [PATCH 966/1001] Add JS lint to tox


---

diff --git a/tox.ini b/tox.ini
index c7e54cf..74cc729 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py{27,34,35}-flask01{0,1,2},js,docs,lint
+envlist = py{27,34,35}-flask01{0,1,2},js,jslint,docs,lint
 skipsdist = True
 
 
@@ -31,6 +31,17 @@ commands =
     npm install
     npm test
 
+[testenv:jslint]
+skip_install = True
+usedevelop = False
+deps =
+whitelist_externals =
+    npm
+changedir = {toxinidir}/hubs/static/client
+commands =
+    npm install
+    npm run lint
+
 [testenv:docs]
 changedir = docs
 deps =

From d0d386401d136475d94d785c79acae21b5253cc6 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 09 2017 10:51:41 +0000
Subject: [PATCH 967/1001] Fix typo


---

diff --git a/hubs/static/client/webpack.prod.js b/hubs/static/client/webpack.prod.js
index 2784ad9..3c7b3ed 100644
--- a/hubs/static/client/webpack.prod.js
+++ b/hubs/static/client/webpack.prod.js
@@ -4,7 +4,7 @@ const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
 const ExtractTextPlugin = require("extract-text-webpack-plugin");
 const common = require('./webpack.common.js');
 
-module.exports = merge(common, {
+module.exports = merge(common.config, {
   devtool: 'source-map',
   module: {
     rules: [

From b08a2df303b8dec61b49ca9c2ef545b401282dae Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 09 2017 10:58:16 +0000
Subject: [PATCH 968/1001] The .copy() method of Munch instances convert them to dicts


---

diff --git a/hubs/views/user.py b/hubs/views/user.py
index 02b2e54..a85337f 100644
--- a/hubs/views/user.py
+++ b/hubs/views/user.py
@@ -15,7 +15,7 @@ from hubs.utils.views import (
 def stream():
     current_user = flask.g.auth.copy()
     urls = {
-        "sse": get_sse_url("user/{}".format(current_user.nickname)),
+        "sse": get_sse_url("user/{}".format(current_user["nickname"])),
         "notifications": flask.url_for("stream_existing"),
         "saved": flask.url_for("saved_notifs"),
     }

From 478377431b28e3442ca62d8a8d5189e5ed551e54 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 09 2017 11:19:12 +0000
Subject: [PATCH 969/1001] [visual] Wrap the Streams page


---

diff --git a/hubs/static/client/app/components/StreamsPage.js b/hubs/static/client/app/components/StreamsPage.js
index 3206280..122c7dd 100644
--- a/hubs/static/client/app/components/StreamsPage.js
+++ b/hubs/static/client/app/components/StreamsPage.js
@@ -17,10 +17,18 @@ export default class StreamsPage extends React.Component {
       <PageStructure
         cssClass="StreamsPage"
         header={
-          <StreamsHeader />
+          <div className="row">
+            <div className="col-md-12">
+              <StreamsHeader />
+            </div>
+          </div>
         }
         content={
-          <Streams />
+          <div className="row">
+            <div className="col-md-12">
+              <Streams />
+            </div>
+          </div>
         }
         />
     );

From 23b08266d991640a76b376704d3b054228e3fd3a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 09 2017 14:51:58 +0000
Subject: [PATCH 970/1001] Fix ansible command to build JS assets


---

diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index 2aa310a..b105524 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -136,8 +136,8 @@
     creates: node_modules
     chdir: "{{ hubs_code_dir }}/hubs/static/client"
 
-- name: Build JavaScript assests
-  command: node_modules/.bin/webpack
+- name: Build JavaScript assets
+  command: npm run build
   become_user: "{{ main_user }}"
   args:
     chdir: "{{ hubs_code_dir }}/hubs/static/client"

From c4553001ad3c75d873612e30b72b4d5273432ed5 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 09 2017 15:06:13 +0000
Subject: [PATCH 971/1001] In Ansible, 'include' is deprecated


---

diff --git a/ansible/roles/hubs/handlers/main.yml b/ansible/roles/hubs/handlers/main.yml
index 7913d42..7f7235b 100644
--- a/ansible/roles/hubs/handlers/main.yml
+++ b/ansible/roles/hubs/handlers/main.yml
@@ -22,4 +22,10 @@
   when: not hubs_dev_mode
 
 # Webserver
-- include: webserver.yml
+- name: restart hubs webapp
+  service: name=hubs-webapp state=restarted
+  listen: "hubs configuration change"
+  when: not hubs_dev_mode
+
+- name: restart nginx
+  service: name=nginx state=restarted
diff --git a/ansible/roles/hubs/handlers/webserver.yml b/ansible/roles/hubs/handlers/webserver.yml
deleted file mode 100644
index e6cb871..0000000
--- a/ansible/roles/hubs/handlers/webserver.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-- name: restart hubs webapp
-  service: name=hubs-webapp state=restarted
-  listen: "hubs configuration change"
-  when: not hubs_dev_mode
-
-- name: restart nginx
-  service: name=nginx state=restarted
diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index b105524..2ac3f8a 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -125,7 +125,7 @@
 
 
 # Set up, create, and populate the database.
-- include: db-{{ hubs_db_type }}.yml
+- include_tasks: db-{{ hubs_db_type }}.yml
 
 
 # Set up JavaScript requirements
@@ -156,8 +156,8 @@
 
 # Include mode-specific tasks
 
-- include: dev.yml
+- include_tasks: dev.yml
   when: hubs_dev_mode
 
-- include: prod.yml
+- include_tasks: prod.yml
   when: not hubs_dev_mode
diff --git a/ansible/roles/hubs/tasks/prod.yml b/ansible/roles/hubs/tasks/prod.yml
index 0f8bb3d..0969ffd 100644
--- a/ansible/roles/hubs/tasks/prod.yml
+++ b/ansible/roles/hubs/tasks/prod.yml
@@ -23,4 +23,4 @@
     - hubs-sse
     - hubs-fedmsg-hub
 
-- include: webserver.yml
+- include_tasks: webserver.yml

From 10cab8eaddf1543edf9307faf2278c953217922e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 09 2017 15:22:37 +0000
Subject: [PATCH 972/1001] Fix an issue with unicode and Honcho in Vagrant


---

diff --git a/ansible/roles/hubs/templates/bashrc b/ansible/roles/hubs/templates/bashrc
index f7004fa..c1f32e2 100644
--- a/ansible/roles/hubs/templates/bashrc
+++ b/ansible/roles/hubs/templates/bashrc
@@ -13,6 +13,10 @@ fi
 # by defining a variable with name _<function>_help containing the help text
 
 
+# Honcho has issues outputing UTF-8 in Vagrant SSH
+# https://github.com/nickstenning/honcho/issues/51
+export PYTHONIOENCODING=utf-8
+
 export HUBS_CONFIG={{ hubs_conf_dir }}/hubs_config.py
 export FLASK_APP={{ hubs_code_dir }}/hubs/app.py
 

From 4e1ccae4905a14827ae162d739ab0d7950c92433 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 09 2017 15:50:19 +0000
Subject: [PATCH 973/1001] Don't show the Cobweb widget all the time


---

diff --git a/hubs/static/client/app/components/CobWeb/index.js b/hubs/static/client/app/components/CobWeb/index.js
index 65b807a..4333f20 100644
--- a/hubs/static/client/app/components/CobWeb/index.js
+++ b/hubs/static/client/app/components/CobWeb/index.js
@@ -8,11 +8,13 @@ import CobWebIcon from './cobweb.png';
 export default class CobWeb extends React.Component {
 
   render() {
+    const old_limit = Date.now() - (1000 * 86400 * 31);  // 31 days
     let icon = null, msg = null;
-    if (this.props.cause == "archived") {
+
+    if (this.props.hub.config.archived) {
         icon = ArchivedIcon;
         msg = "This hub has been archived and locked.";
-    } else {
+    } else if (this.props.hub.mtime < old_limit) {
         icon = CobWebIcon;
         msg = (
             <span>
@@ -20,7 +22,10 @@ export default class CobWeb extends React.Component {
                 <TimeAgo date={this.props.mtime} />
             </span>
             );
+    } else {
+      return null;
     }
+
     return (
       <div className="CobWeb media mb-3">
         <img className="d-flex align-self-center mr-3 square-32" src={icon} />
@@ -30,5 +35,5 @@ export default class CobWeb extends React.Component {
       </div>
     );
   }
-}
 
+}
diff --git a/hubs/static/client/app/components/WidgetsArea.js b/hubs/static/client/app/components/WidgetsArea.js
index a23e3df..9fe6508 100644
--- a/hubs/static/client/app/components/WidgetsArea.js
+++ b/hubs/static/client/app/components/WidgetsArea.js
@@ -34,10 +34,7 @@ class WidgetsArea extends React.PureComponent {
               https://pagure.io/fedora-hubs/issue/133
             */
               !this.props.editMode &&
-              <CobWeb
-                cause={this.props.hub.config.archived ? "archived" : "old"}
-                mtime={this.props.hub.mtime}
-                />
+              <CobWeb hub={this.props.hub} />
             }
 
             <WidgetsColumn

From d426d7b06723da458556bf3a87d0c307ba5514cd Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 10 2017 08:24:31 +0000
Subject: [PATCH 974/1001] Transmit the 'archived' status to the UI.


---

diff --git a/hubs/models.py b/hubs/models.py
index 3cc5850..55730c3 100644
--- a/hubs/models.py
+++ b/hubs/models.py
@@ -322,6 +322,7 @@ class Hub(ObjectAuthzMixin, BASE):
     def __json__(self):
         return {
             'name': self.name,
+            'archived': self.archived,
             'config': self.config.__json__(),
 
             'widgets': [widget.idx for widget in self.widgets],
diff --git a/hubs/static/client/app/components/CobWeb/index.js b/hubs/static/client/app/components/CobWeb/index.js
index 4333f20..582b494 100644
--- a/hubs/static/client/app/components/CobWeb/index.js
+++ b/hubs/static/client/app/components/CobWeb/index.js
@@ -11,7 +11,7 @@ export default class CobWeb extends React.Component {
     const old_limit = Date.now() - (1000 * 86400 * 31);  // 31 days
     let icon = null, msg = null;
 
-    if (this.props.hub.config.archived) {
+    if (this.props.hub.archived) {
         icon = ArchivedIcon;
         msg = "This hub has been archived and locked.";
     } else if (this.props.hub.mtime < old_limit) {

From 2f6cc499ec2182ec54c669c1ad0145fd4dfea5bf Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 11 2017 08:11:00 +0000
Subject: [PATCH 975/1001] Upgrade to babel-preset-env


http://babeljs.io/env

---

diff --git a/hubs/static/client/.babelrc b/hubs/static/client/.babelrc
index bfa2dab..b5e1a56 100644
--- a/hubs/static/client/.babelrc
+++ b/hubs/static/client/.babelrc
@@ -1,5 +1,8 @@
 {
-  "presets" : [["es2015", {"modules": false}], "react"],
+  "presets" : [
+    ["env", {"modules": false}],
+    "react"
+  ],
   "plugins": [
     "syntax-dynamic-import",
     "transform-object-rest-spread"
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index c2b0fc5..569397b 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -31,6 +31,7 @@
     "babel-plugin-dynamic-import-node": "^1.1.0",
     "babel-plugin-syntax-dynamic-import": "^6.18.0",
     "babel-plugin-transform-object-rest-spread": "^6.26.0",
+    "babel-preset-env": "^1.6.0",
     "babel-preset-es2015": "^6.24.1",
     "babel-preset-react": "^6.24.1",
     "clean-webpack-plugin": "^0.1.17",

From 0ca052bb26f1f8bec51bc0c5a0c61647183871e2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 11 2017 11:09:42 +0000
Subject: [PATCH 976/1001] Fix moving widgets when there are disabled ones


---

diff --git a/hubs/tests/utils/test_views.py b/hubs/tests/utils/test_views.py
index 13d9c1c..50af636 100644
--- a/hubs/tests/utils/test_views.py
+++ b/hubs/tests/utils/test_views.py
@@ -108,3 +108,30 @@ class ViewUtilsTest(APPTest):
         check_move(
             "contact", 5,
             ["about", "bugzilla", "dummy", "badges", "contact"])
+
+    def test_move_widget_disabled(self):
+        # Make sure moving works even if there are disabled widgets
+        hub = Hub(name="testing")
+        self.session.add(hub)
+
+        def _make_widget(name, index):
+            widget = Widget(
+                hub=hub, plugin=name,
+                left=True, index=index, _config="{}")
+            self.session.add(widget)
+            return widget
+
+        nonexistant_widget = _make_widget("nonexistant", 0)
+        about_widget = _make_widget("about", 1)
+        badges_widget = _make_widget("badges", 1)
+        # The UI does not display the disabled widget, so moving the second
+        # widget to the third slot is actually a move from index 0 to 1.
+        move_widget(about_widget, 1)
+        self.session.flush()
+        self.session.refresh(hub)
+        self.session.refresh(nonexistant_widget)
+        self.assertEqual(nonexistant_widget.index, 0)  # no change
+        self.session.refresh(about_widget)
+        self.session.refresh(badges_widget)
+        self.assertEqual(about_widget.index, 1)
+        self.assertEqual(badges_widget.index, 0)
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
index 2445387..2508dad 100644
--- a/hubs/utils/views.py
+++ b/hubs/utils/views.py
@@ -154,7 +154,10 @@ def configure_widget_instance(widget_instance, widget_config):
 
 def reorder_widgets(hub, is_left):
     """Reset widget instances indicies for a hub and a column."""
-    all_widgets = [w for w in hub.widgets if w.left == is_left]
+    all_widgets = [
+        w for w in hub.widgets
+        if w.left == is_left and w.enabled
+        ]
     for index, widget in enumerate(all_widgets):
         widget.index = index
 
@@ -163,7 +166,7 @@ def move_widget(widget_instance, new_index):
     """Move a widget instance to a new index in the same column."""
     all_widgets = [
         w for w in widget_instance.hub.widgets
-        if w.left == widget_instance.left
+        if w.left == widget_instance.left and w.enabled
         ]
     old_index = [w.idx for w in all_widgets].index(widget_instance.idx)
     # Move the widget in the list

From dc3654fb30b88e34625058ed922c30cd098315ce Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 11 2017 14:19:40 +0000
Subject: [PATCH 977/1001] Switch from react-loadable to react-universal-component


---

diff --git a/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js b/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js
index 2d48f90..068d1de 100644
--- a/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js
+++ b/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js
@@ -6,10 +6,7 @@ import WidgetSelectDialog from './WidgetSelectDialog';
 import Modal from '../Modal';
 import { getAvailableWidgets } from '../../core/actions/widgets';
 import { addWidget } from '../../core/actions/widget';
-import {
-  makeLoadable,
-  makeLoadingComponent
-} from '../../core/utils';
+import { makeLoadable } from '../../core/utils';
 
 
 class AddWidgetDialog extends React.Component {
@@ -122,10 +119,8 @@ class AddWidgetDialog extends React.Component {
       if (this.state.selectedWidget.isReact) {
         const AsyncComponent = makeLoadable(
           () => import(`../../widgets/${this.state.selectedWidget.name}/Config`),
-          makeLoadingComponent(
-            "Loading widget configuration...",
-            "Sorry, there was a problem loading the widget configuration."
-          )
+          "Loading widget configuration...",
+          "Sorry, there was a problem loading the widget configuration."
         );
         contents = (
           <AsyncComponent
diff --git a/hubs/static/client/app/components/Widget.js b/hubs/static/client/app/components/Widget.js
index 880c1c4..96c5d5b 100644
--- a/hubs/static/client/app/components/Widget.js
+++ b/hubs/static/client/app/components/Widget.js
@@ -1,17 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
-import {
-  makeLoadable,
-  makeLoadingComponent
-} from '../core/utils';
+import { makeLoadable } from '../core/utils';
 import SimpleWidget from '../components/SimpleWidget';
 
-/*
-import HalpWidget from '../widgets/halp/Widget';
-import FeedWidget from '../widgets/feed/Widget';
-*/
-
 
 class Widget extends React.PureComponent {
 
@@ -30,17 +22,9 @@ class Widget extends React.PureComponent {
     if (!this.props.editMode && this.props.widget.isReact) {
       const AsyncComponent = makeLoadable(
         () => import(`../widgets/${this.props.widget.component}/Widget`),
-        makeLoadingComponent(
-          "Loading widget...",
-          "Sorry, there was a problem loading the widget."
-        )
+        "Loading widget...",
+        "Sorry, there was a problem loading the widget."
       );
-      /*
-      console.log(this.props.widget);
-      let AsyncComponent = null;
-      if (this.props.widget.component === "halp") { AsyncComponent = HalpWidget; }
-      if (this.props.widget.component === "feed") { AsyncComponent = FeedWidget; }
-      */
       widgetComponent = (
         <AsyncComponent {...this.props} />
       );
diff --git a/hubs/static/client/app/components/WidgetConfigDialog.js b/hubs/static/client/app/components/WidgetConfigDialog.js
index 1548956..1a8bd33 100644
--- a/hubs/static/client/app/components/WidgetConfigDialog.js
+++ b/hubs/static/client/app/components/WidgetConfigDialog.js
@@ -6,10 +6,7 @@ import {
   deleteWidget,
   closeConfigDialog,
   } from "../core/actions/widget";
-import {
-  makeLoadable,
-  makeLoadingComponent
-} from '../core/utils';
+import { makeLoadable } from '../core/utils';
 import SimpleWidgetConfig from '../components/SimpleWidgetConfig';
 import Modal from '../components/Modal';
 
@@ -72,10 +69,8 @@ class WidgetConfigDialog extends React.Component {
     if (this.props.widget.isReact) {
       const AsyncComponent = makeLoadable(
         () => import(`../widgets/${widgetName}/Config`),
-        makeLoadingComponent(
-          "Loading widget configuration...",
-          "Sorry, there was a problem loading the widget configuration."
-        )
+        "Loading widget configuration...",
+        "Sorry, there was a problem loading the widget configuration."
       );
       contents = (
         <AsyncComponent
diff --git a/hubs/static/client/app/core/Pages.js b/hubs/static/client/app/core/Pages.js
index def36e4..6277719 100644
--- a/hubs/static/client/app/core/Pages.js
+++ b/hubs/static/client/app/core/Pages.js
@@ -1,26 +1,19 @@
 import React from 'react';
 import {
   makeLoadable,
-  makeLoadingComponent
 } from '../core/utils';
 
 
-const PageLoadingComponent = makeLoadingComponent(
-  "Loading...",
-  "Sorry, there was a problem loading the page."
-);
-
-
 let Hub = makeLoadable(
   () => import(/* webpackChunkName: "page-hub" */ '../components/HubPage'),
-  PageLoadingComponent
+  "Loading...",
+  "Sorry, there was a problem loading the page."
 );
 let Streams = makeLoadable(
   () => import(/* webpackChunkName: "page-streams" */ '../components/StreamsPage'),
-  PageLoadingComponent
+  "Loading...",
+  "Sorry, there was a problem loading the page."
 );
 
-//Hub = require('../components/HubPage').default;
-//Streams = require('../components/StreamsPage').default;
 
 export {Hub, Streams};
diff --git a/hubs/static/client/app/core/utils.js b/hubs/static/client/app/core/utils.js
index 0699a93..d3dd241 100644
--- a/hubs/static/client/app/core/utils.js
+++ b/hubs/static/client/app/core/utils.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import fetch from 'isomorphic-fetch';
-import Loadable from 'react-loadable';
+import universal from 'react-universal-component'
 
 
 export function backendCall(url, fetchConfig, json=false) {
@@ -38,51 +38,44 @@ export function apiCall(url, fetchConfig) {
 }
 
 
-export function makeLoadable(loader, loading) {
-  const renderDefault = (loaded, props) => {
-    const Component = loaded.default;
-    return <Component {...props} />;
-  }
-  return Loadable({
-    loader,
-    loading,
-    render: renderDefault,
-    delay: 200,
+export function makeLoadable(loader, loadingText, errorText) {
+  //return makeSyncLoadable(loader);
+  const LoadingComponent = () => (
+    <div className="text-muted">
+      {loadingText}
+    </div>
+  );
+  const ErrorComponent = ({ error }) => (
+    <div>
+      {error ? error.message : errorText}
+    </div>
+  );
+  const AsyncComponent = universal(loader, {
+    loading: LoadingComponent,
+    error: ErrorComponent
   });
+  return AsyncComponent;
 }
 
-export function makeLoadingComponent(loadingText, errorText) {
-  class LoadingComponent extends React.Component {
+function makeSyncLoadable(loader) {
+  class SyncLoadable extends React.Component {
+    constructor(props) {
+      super(props);
+      this.state = {component: null}
+    }
+    componentDidMount() {
+      loader().then((module) => {
+        this.setState({component: module.default});
+      }).catch((error) => {
+        console.error(error);
+      });
+    }
     render() {
-      // Handle the loading state
-      if (this.props.isLoading) {
-        if (this.props.timedOut) {
-          // In case we've timed out loading our other component.
-          return <div className="text-warning">Loader timed out!</div>;
-        } else if (this.props.pastDelay) {
-          // Display a loading screen after a set delay.
-          return (
-            <div className="text-muted">
-              {loadingText}
-            </div>
-          );
-        } else {
-          // Don't flash "Loading..." when we don't need to.
-          return null;
-        }
-      }
-      // Handle the error state
-      else if (this.props.error) {
-        return (
-          <div>
-            {errorText}
-          </div>
-        );
-      }
-      else {
+      if (!this.state.component) {
         return null;
       }
+      return <this.state.component {...this.props} />;
     }
   }
-  return LoadingComponent;
+  return SyncLoadable;
 }
diff --git a/hubs/static/client/app/widgets/feed/Widget.js b/hubs/static/client/app/widgets/feed/Widget.js
index 31e6f6f..fdecb36 100644
--- a/hubs/static/client/app/widgets/feed/Widget.js
+++ b/hubs/static/client/app/widgets/feed/Widget.js
@@ -8,7 +8,7 @@ import Feed from '../../components/feed/Feed';
 import WidgetChrome from '../../components/WidgetChrome';
 
 
-export default class Widget extends React.PureComponent {
+export default class FeedWidget extends React.PureComponent {
 
   propTypes: {
     widget: PropTypes.object.isRequired,
diff --git a/hubs/static/client/app/widgets/halp/Widget.js b/hubs/static/client/app/widgets/halp/Widget.js
index 099adb2..8f54123 100644
--- a/hubs/static/client/app/widgets/halp/Widget.js
+++ b/hubs/static/client/app/widgets/halp/Widget.js
@@ -37,7 +37,7 @@ const messages = defineMessages({
 });
 
 
-export default class Widget extends React.Component {
+export default class HalpWidget extends React.Component {
 
   propTypes: {
     widget: PropTypes.object.isRequired,
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 569397b..7b34774 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -15,10 +15,10 @@
     "react-dom": "^15.6.1",
     "react-intl": "^2.3.0",
     "react-linkify": "^0.2.1",
-    "react-loadable": "^4.0.4",
     "react-redux": "^5.0.6",
     "react-sortable-hoc": "^0.6.7",
     "react-timeago": "^3.4.3",
+    "react-universal-component": "^2.5.5",
     "reconnecting-eventsource": "^1.0.1",
     "redux": "^3.7.2",
     "redux-thunk": "^2.2.0"

From 3778a85b75a9fa02c1ddab81dc0d14748a4acab4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 11 2017 14:29:58 +0000
Subject: [PATCH 978/1001] Use MongoDB to store the feed items


---

diff --git a/ansible/roles/hubs/tasks/main.yml b/ansible/roles/hubs/tasks/main.yml
index 2ac3f8a..f26adaf 100644
--- a/ansible/roles/hubs/tasks/main.yml
+++ b/ansible/roles/hubs/tasks/main.yml
@@ -10,6 +10,7 @@
   with_items:
     - npm
     - redis
+    - mongodb-server
     - fedmsg-hub
     - python-virtualenv
     - python3-flask-oidc
@@ -152,6 +153,7 @@
   service: name={{ item }} state=started enabled=yes
   with_items:
     - redis
+    - mongod
 
 
 # Include mode-specific tasks
diff --git a/hubs/feed.py b/hubs/feed.py
index 1cbe510..4c92454 100644
--- a/hubs/feed.py
+++ b/hubs/feed.py
@@ -7,7 +7,7 @@ import re
 
 import fedmsg.meta
 import flask
-import redis
+import pymongo
 from fedmsg.encoding import loads, dumps
 
 import hubs.app
@@ -130,7 +130,6 @@ def _make_hub_links(msg, attr, existing_usernames):
 class Feed(object):
 
     max_items = 100
-    connection_pool = None
     msgtype = None
 
     def __init__(self, owner):
@@ -145,35 +144,23 @@ class Feed(object):
         self.db = None
         fedmsg_config = hubs.app.fedmsg_config
         self.db_config = {
-            'host': fedmsg_config.get('hubs.redis.host', 'localhost'),
-            'port': fedmsg_config.get('hubs.redis.port', 6379),
-            'db': fedmsg_config.get('hubs.redis.db', 0),
-            'password': fedmsg_config.get('hubs.redis.password', None),
-            }
-        self.key = self._get_key()
-
-    def _get_key(self):
-        parts = ["feed", self.msgtype, self.owner]
-        key_prefix = hubs.app.fedmsg_config.get('hubs.redis.feed-prefix')
-        if key_prefix:
-            parts.insert(0, key_prefix)
-        return "|".join(parts)
-
-    def get(self, start=0, end=None):
-        end = end or -1
+            "url": fedmsg_config.get('hubs.mongodb.url'),
+            "db": fedmsg_config.get('hubs.mongodb.database', "hubs"),
+        }
+
+    def get(self):
         if self.db is None:
             self.connect()
         return [
-            loads(item.decode("utf-8")) for item in
-            self.db.lrange(self.key, start, end)
+            loads(item["msg"]) for item in
+            self.db.find(sort=[('$natural', pymongo.DESCENDING)])
             ]
 
     def add(self, msg):
         if self.db is None:
             self.connect()
-        log.debug("Adding message %s to %s", msg["msg_id"], self.key)
-        self.db.lpush(self.key, dumps(self._preprocess_msg(msg)))
-        self.db.ltrim(self.key, 0, self.max_items)
+        log.debug("Adding message %s to %s", msg["msg_id"], self.db.name)
+        self.db.insert_one({"msg": dumps(self._preprocess_msg(msg))})
 
     def _preprocess_msg(self, msg):
         # Default implementation: no-op.
@@ -182,29 +169,35 @@ class Feed(object):
     def length(self):
         if self.db is None:
             self.connect()
-        return self.db.llen(self.key)
+        return self.db.count()
 
     __len__ = length
 
     def connect(self):
-        if self.connection_pool is None:
-            self.connection_pool = redis.ConnectionPool(**self.db_config)
-        self.db = redis.Redis(connection_pool=self.connection_pool)
         try:
-            self.db.info()
-        except redis.exceptions.ConnectionError:
-            log.warning("Could not connect to Redis")
+            client = pymongo.MongoClient(self.db_config["url"])
+            database = client[self.db_config["db"]]
+            collection_name = "|".join(["feed", self.msgtype, self.owner])
+            existing = database.collection_names(
+                include_system_collections=False)
+            if collection_name in existing:
+                self.db = database[collection_name]
+            else:
+                self.db = database.create_collection(
+                    collection_name,
+                    capped=True, size=5242880, max=self.max_items)
+        except pymongo.errors.ConnectionFailure:
+            log.warning("Could not connect to MongoDB")
             self.db = None
             raise  # XXX: do better?
 
     def close(self):
         try:
-            self.db.close()
-        except redis.exceptions.ConnectionError:
-            log.warning("Could not disconnect from Redis")
+            self.db.database.client.close()
+        except pymongo.errors.ConnectionFailure:
+            log.warning("Could not disconnect from MongoDB")
             raise  # XXX: do better?
         self.db = None
-        self.connection_pool = None
 
 
 class Notifications(Feed):
diff --git a/hubs/tests/test_feed.py b/hubs/tests/test_feed.py
index 4df4ca4..526aac7 100644
--- a/hubs/tests/test_feed.py
+++ b/hubs/tests/test_feed.py
@@ -2,7 +2,8 @@ from __future__ import unicode_literals
 
 import json
 
-from mock import Mock, patch
+import pymongo
+from mock import MagicMock, Mock, patch
 
 from hubs.app import app
 from hubs.models import User, Hub, Association
@@ -24,14 +25,33 @@ class FeedTest(APPTest):
     def tearDown(self):
         super(FeedTest, self).tearDown()
 
+    @patch("hubs.feed.pymongo")
+    def test_connect(self, pymongo_mock):
+        client = MagicMock()
+        pymongo_mock.MongoClient.return_value = client
+        for feed_class, msgtype in self.feed_classes:
+            database = Mock()
+            database.collection_names.return_value = []
+            database.create_collection.return_value = db = object()
+            client.__getitem__.return_value = database
+            db_name = "feed|%s|testuser" % msgtype
+            feed = feed_class("testuser")
+            feed.connect()
+            pymongo_mock.MongoClient.assert_called_with(None)
+            client.__getitem__.assert_called_with("hubs")
+            database.create_collection.assert_called_with(
+                db_name, capped=True, size=5242880, max=100
+                )
+            self.assertIs(feed.db, db)
+
     def test_get(self):
         for feed_class, msgtype in self.feed_classes:
             feed = feed_class("testuser")
             feed.db = Mock()
-            feed.db.lrange.return_value = []
+            feed.db.find.return_value = []
             feed.get()
-            feed.db.lrange.assert_called_once_with(
-                "feed|{}|testuser".format(msgtype), 0, -1)
+            feed.db.find.assert_called_once_with(
+                sort=[('$natural', pymongo.DESCENDING)])
 
     def test_add(self):
         msg = {
@@ -43,34 +63,30 @@ class FeedTest(APPTest):
         for feed_class, msgtype in self.feed_classes:
             feed = feed_class("testuser")
             feed.db = Mock()
-            key = "feed|{}|testuser".format(msgtype)
             feed.add(msg)
-            feed.db.lpush.assert_called_once()
-            lpush_call_args = feed.db.lpush.call_args_list[0][0]
-            self.assertEqual(lpush_call_args[0], key)
+            feed.db.insert_one.assert_called_once()
+            insert_call_args = feed.db.insert_one.call_args_list[0][0]
+            inserted_msg = json.loads(insert_call_args[0]["msg"])
             if feed_class == Notifications:
-                self.assertIn("msg_ids", json.loads(lpush_call_args[1]))
+                self.assertIn("msg_ids", inserted_msg)
             elif feed_class == Activity:
-                self.assertEqual(json.loads(lpush_call_args[1]), msg)
-            feed.db.ltrim.assert_called_once_with(key, 0, 100)
+                self.assertEqual(inserted_msg, msg)
 
     def test_length(self):
         for feed_class, msgtype in self.feed_classes:
             feed = feed_class("testuser")
             feed.db = Mock()
-            feed.db.llen.return_value = 42
+            feed.db.count.return_value = 42
             self.assertEqual(feed.length(), 42)
-            feed.db.llen.assert_called_once_with(
-                "feed|{}|testuser".format(msgtype))
+            feed.db.count.assert_called_once_with()
 
     def test_close(self):
         for feed_class, msgtype in self.feed_classes:
             feed = feed_class("testuser")
-            redis_mock = feed.db = Mock()
+            db_mock = feed.db = Mock()
             feed.close()
-            redis_mock.close.assert_called_once()
+            db_mock.database.client.close.assert_called_once()
             self.assertIsNone(feed.db)
-            self.assertIsNone(feed.connection_pool)
 
     @patch("hubs.feed.Activity")
     def test_on_new_message(self, mock_activity):
diff --git a/requirements.txt b/requirements.txt
index 07dab88..4a42cec 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -15,6 +15,7 @@ gunicorn
 html5lib==0.9999999
 munch
 psycopg2
+pymongo
 pytz
 requests
 setuptools

From cf53484647a7ef822009ed1f36256b53c444fac7 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 11 2017 14:32:12 +0000
Subject: [PATCH 979/1001] Upgrade to Fedora-Bootstrap 1.1.0


Rebased on Bootstrap 4.0 beta.

https://pagure.io/fedora-bootstrap/

---

diff --git a/hubs/static/client/app/components/AddWidget/WidgetSelectDialog.js b/hubs/static/client/app/components/AddWidget/WidgetSelectDialog.js
index 9577e71..dae41ec 100644
--- a/hubs/static/client/app/components/AddWidget/WidgetSelectDialog.js
+++ b/hubs/static/client/app/components/AddWidget/WidgetSelectDialog.js
@@ -28,7 +28,7 @@ export default class WidgetSelectDialog extends React.Component {
     });
     return (
       <div>
-        <fieldset className="form-group">
+        <fieldset className="form-group row">
           { this.props.showVisibilitySelect &&
             <label htmlFor="widgetname">Widget name:</label>
           }
diff --git a/hubs/static/client/app/components/FlashMessages/FlashMessages.css b/hubs/static/client/app/components/FlashMessages/FlashMessages.css
index 566132f..0203ea3 100644
--- a/hubs/static/client/app/components/FlashMessages/FlashMessages.css
+++ b/hubs/static/client/app/components/FlashMessages/FlashMessages.css
@@ -1,6 +1,5 @@
 .FlashMessages {
   /* place it on top so they cover content and can be clicked */
   position: absolute;
-  width: 100%;
   z-index: 3;
 }
diff --git a/hubs/static/client/app/components/FlashMessages/FlashMessagesList.js b/hubs/static/client/app/components/FlashMessages/FlashMessagesList.js
index 851da6a..26c749b 100644
--- a/hubs/static/client/app/components/FlashMessages/FlashMessagesList.js
+++ b/hubs/static/client/app/components/FlashMessages/FlashMessagesList.js
@@ -22,8 +22,8 @@ export default class FlashMessagesList extends React.Component {
       );
     });
     return (
-      <div className="FlashMessages row pt-2">
-        <div className="col-md-6 offset-md-3">
+      <div className="d-flex justify-content-center">
+        <div className="FlashMessages">
           {messages}
         </div>
       </div>
diff --git a/hubs/static/client/app/components/HubConfig/HubConfigPanelChat.js b/hubs/static/client/app/components/HubConfig/HubConfigPanelChat.js
index f756e9d..516f846 100644
--- a/hubs/static/client/app/components/HubConfig/HubConfigPanelChat.js
+++ b/hubs/static/client/app/components/HubConfig/HubConfigPanelChat.js
@@ -66,7 +66,7 @@ export default class ChatPanel extends React.Component {
         <FormattedMessage {...messages.title} tagName="h3" />
         <FormattedMessage {...messages.intro_1} tagName="p" />
         <FormattedMessage {...messages.intro_2} tagName="p" />
-        <div className="form-group">
+        <div className="form-group row">
           <label htmlFor="hub-settings-chat-channel">
             <FormattedMessage {...messages.channel_name} />
           </label>
@@ -82,7 +82,7 @@ export default class ChatPanel extends React.Component {
             <span className="ml-2">#fedora-devel</span>
           </p>
         </div>
-        <div className="form-group">
+        <div className="form-group row">
           <label htmlFor="hub-settings-chat-domain">
             <FormattedMessage {...messages.network} />
           </label>
diff --git a/hubs/static/client/app/components/HubConfig/HubConfigPanelGeneral.js b/hubs/static/client/app/components/HubConfig/HubConfigPanelGeneral.js
index 9e5972a..00b1e44 100644
--- a/hubs/static/client/app/components/HubConfig/HubConfigPanelGeneral.js
+++ b/hubs/static/client/app/components/HubConfig/HubConfigPanelGeneral.js
@@ -66,7 +66,7 @@ export default class GeneralPanel extends React.Component {
       <form onSubmit={(e) => {e.preventDefault();}}>
         <FormattedMessage {...messages.title} tagName="h3" />
         <FormattedMessage {...messages.intro} tagName="p" />
-        <div className="form-group">
+        <div className="form-group row">
           <label htmlFor="hub-settings-general-summary">
             <FormattedMessage {...messages.summary} />
           </label>
@@ -81,7 +81,7 @@ export default class GeneralPanel extends React.Component {
             <FormattedMessage {...messages.summary_help} />
           </p>
         </div>
-        <div className="form-group">
+        <div className="form-group row">
           <label htmlFor="hub-settings-general-leftwidth">
             <FormattedMessage {...messages.left_width} />
           </label>
@@ -100,7 +100,7 @@ export default class GeneralPanel extends React.Component {
               />
           </p>
         </div>
-        <div className="form-group">
+        <div className="form-group row">
           <label htmlFor="hub-settings-general-visibility">
             <FormattedMessage {...messages.visibility} />
           </label>
@@ -120,7 +120,7 @@ export default class GeneralPanel extends React.Component {
             <FormattedHTMLMessage {...messages.visibility_help} />
           </p>
         </div>
-        <div className="form-group">
+        <div className="form-group row">
           <label htmlFor="hub-settings-general-avatar">
             <FormattedMessage {...messages.avatar} />
           </label>
diff --git a/hubs/static/client/app/components/HubConfig/HubConfigPanelUser.js b/hubs/static/client/app/components/HubConfig/HubConfigPanelUser.js
index c516c19..705d44f 100644
--- a/hubs/static/client/app/components/HubConfig/HubConfigPanelUser.js
+++ b/hubs/static/client/app/components/HubConfig/HubConfigPanelUser.js
@@ -136,7 +136,7 @@ export default class UserPanel extends React.Component {
           className="form-inline mb-3"
           onSubmit={this.handleAdd}
           >
-          <div className="form-group">
+          <div className="form-group row">
             <FormattedMessage {...messages.add_user}>
               {(message) => (
                 <CompletionInput
diff --git a/hubs/static/client/app/components/PageStructure.js b/hubs/static/client/app/components/PageStructure.js
index ee6cd14..645a3c1 100644
--- a/hubs/static/client/app/components/PageStructure.js
+++ b/hubs/static/client/app/components/PageStructure.js
@@ -23,7 +23,7 @@ export default class PageStructure extends React.Component {
 
         <div className="container-fluid">
           <div className="row">
-            <div className="offset-lg-2 col-lg-10 px-0">
+            <div className="col-lg-10 ml-auto px-0">
               {this.props.content}
             </div>
           </div>
diff --git a/hubs/static/client/app/components/SimpleWidgetConfig.js b/hubs/static/client/app/components/SimpleWidgetConfig.js
index f323b52..ca817dd 100644
--- a/hubs/static/client/app/components/SimpleWidgetConfig.js
+++ b/hubs/static/client/app/components/SimpleWidgetConfig.js
@@ -12,7 +12,7 @@ export default class SimpleWidgetConfig extends React.Component {
   render() {
     let fields = this.props.widget.params.map((field) => {
       return (
-        <fieldset className="form-group" key={field.name}>
+        <fieldset className="form-group row" key={field.name}>
           <strong>{field.label}</strong>
           <input
             className="form-control"
diff --git a/hubs/static/client/app/components/Streams.js b/hubs/static/client/app/components/Streams.js
index b2b0ff3..ebc0b98 100644
--- a/hubs/static/client/app/components/Streams.js
+++ b/hubs/static/client/app/components/Streams.js
@@ -177,8 +177,8 @@ class FeedPanel extends React.Component {
             type="search" className="form-control"
             placeholder="Search this activity stream..."
             aria-describedby="searchform-addon" />
-          <span className="input-group-addon">
-            <span><i className="fa fa-search" aria-hidden="true"></i></span>
+          <span className="input-group-btn">
+            <button className="btn btn-secondary"><i className="fa fa-search" aria-hidden="true"></i></button>
           </span>
         </div>
         <br/>
diff --git a/hubs/static/client/app/components/VisibilitySelect.js b/hubs/static/client/app/components/VisibilitySelect.js
index 7eedaa1..42552ff 100644
--- a/hubs/static/client/app/components/VisibilitySelect.js
+++ b/hubs/static/client/app/components/VisibilitySelect.js
@@ -20,7 +20,7 @@ export default class VisibilitySelect extends React.Component {
 
   render() {
     return (
-      <fieldset className="form-group">
+      <fieldset className="form-group row">
         <label htmlFor="visibility">Visibility:</label>
         <select
           className="form-control"
diff --git a/hubs/static/client/app/components/feed/Icon.js b/hubs/static/client/app/components/feed/Icon.js
index 4ae2f25..1c59c19 100644
--- a/hubs/static/client/app/components/feed/Icon.js
+++ b/hubs/static/client/app/components/feed/Icon.js
@@ -5,7 +5,7 @@ export default class Icon extends React.Component {
     return (
       <a href={this.props.item.link ? this.props.item.link : '#'}
          target="_blank"
-         className="d-flex align-self-start mr-3"
+         className="d-flex align-self-start mr-2"
          >
         <img
           alt="User avatar"
diff --git a/hubs/static/client/app/components/feed/Panel.js b/hubs/static/client/app/components/feed/Panel.js
index 2dcee5b..a11dbf6 100644
--- a/hubs/static/client/app/components/feed/Panel.js
+++ b/hubs/static/client/app/components/feed/Panel.js
@@ -23,7 +23,7 @@ export default class Panel extends React.Component {
 
   render() {
     return (
-      <div className="media py-3" id={this.props.item.id}>
+      <div className="media py-3 px-2" id={this.props.item.id}>
         <Icon item={this.props.item} />
         <Markup
           {...this.props}
diff --git a/hubs/static/client/app/widgets/halp/Config.js b/hubs/static/client/app/widgets/halp/Config.js
index 8f48cff..4c61e76 100644
--- a/hubs/static/client/app/widgets/halp/Config.js
+++ b/hubs/static/client/app/widgets/halp/Config.js
@@ -182,7 +182,7 @@ export default class Config extends React.Component {
             </fieldset>
           </form>
           <fieldset className="row">
-            <label className="col-sm-6 control-label">
+            <label className="col-sm-6 form-control-label">
               <FormattedMessage {...messages.per_page} />
             </label>
             <div className="col-sm-6">
@@ -191,7 +191,7 @@ export default class Config extends React.Component {
                 type="number"
                 value={this.props.values.per_page || "5"}
                 onChange={this.handlePerPageChanged}
-                className="form-control input-sm"
+                className="form-control form-control-sm"
                 />
             </div>
             <div className="col-sm-12 text-muted">
diff --git a/hubs/static/client/app/widgets/halp/ModalAllRequests.js b/hubs/static/client/app/widgets/halp/ModalAllRequests.js
index 8f0e1a8..4853c85 100644
--- a/hubs/static/client/app/widgets/halp/ModalAllRequests.js
+++ b/hubs/static/client/app/widgets/halp/ModalAllRequests.js
@@ -128,10 +128,10 @@ export default class ModalAllRequests extends React.Component {
       footer = null;
     } else {
       footer = (
-        <nav aria-label="...">
-          <ul className="pager">
-            <li className={"pager-prev" + (this.state.page.has_prev ? "" : " disabled")}>
-              <button className="btn btn-link" value="-1" onClick={this.onPageChange}>
+        <nav aria-label="Page navigation">
+          <ul className="pagination">
+            <li className={"page-item" + (this.state.page.has_prev ? "" : " disabled")}>
+              <button className="btn btn-link page-link" value="-1" onClick={this.onPageChange}>
                 <span aria-hidden="true">&larr;</span>
                 <FormattedMessage {...messages.pager_newer} />
               </button>
@@ -141,8 +141,8 @@ export default class ModalAllRequests extends React.Component {
               {...messages.pager_status}
               values={{page: this.state.page.nr, total: this.state.page.total_pages}}
               />
-            <li className={"pager-next" + (this.state.page.has_next ? "" : " disabled")}>
-              <button className="btn btn-link" value="1" onClick={this.onPageChange}>
+            <li className={"page-item" + (this.state.page.has_next ? "" : " disabled")}>
+              <button className="btn btn-link page-link" value="1" onClick={this.onPageChange}>
                 <FormattedMessage {...messages.pager_older} />
                 <span aria-hidden="true">&rarr;</span>
               </button>
@@ -181,7 +181,7 @@ export default class ModalAllRequests extends React.Component {
         <form className="" method="post"
               action={this.props.urls.search} onSubmit={this.onSubmit}>
           <div className="form-group row">
-            <label htmlFor="meetingname" className="col-sm-4 control-label">
+            <label htmlFor="meetingname" className="col-sm-4 form-control-label">
               <FormattedMessage {...messages.search_meeting_name} />
             </label>
             <div className="col-sm-8">
@@ -190,7 +190,7 @@ export default class ModalAllRequests extends React.Component {
             </div>
           </div>
           <div className="form-group row">
-            <label htmlFor="startdate" className="col-sm-4 control-label">
+            <label htmlFor="startdate" className="col-sm-4 form-control-label">
               <FormattedMessage {...messages.search_between_dates} />
             </label>
             <div className="col-sm-4">
@@ -203,7 +203,7 @@ export default class ModalAllRequests extends React.Component {
             </div>
           </div>
           <div className="form-group row">
-            <label htmlFor="people" className="col-sm-4 control-label">
+            <label htmlFor="people" className="col-sm-4 form-control-label">
               <FormattedMessage {...messages.search_people} />
             </label>
             <div className="col-sm-8">
@@ -215,7 +215,7 @@ export default class ModalAllRequests extends React.Component {
             </div>
           </div>
           <div className="form-group row">
-            <div className="offset-sm-4 col-sm-8">
+            <div className="col-sm-8 ml-auto">
               <button
                 type="submit"
                 className="btn btn-primary mr-3"
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 8d77ee2..ba35ebf 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -117,7 +117,7 @@ header span.edit {
 
 .flash-messages {
   /* place it on top so they cover content and can be clicked */
-  position: relative;
+  position: absolute;
   z-index: 3;
 }
 
@@ -311,6 +311,17 @@ font-size: 32pt;
 }
 
 
+/*
+ * Sticky widget
+ */
+.card-info {
+  border-color: #17a2b8;
+}
+.card-info > .card-header{
+  background-color: #17a2b8;
+  color: #f8f9fa;
+}
+
 
 /*
  *  Contact Widget
diff --git a/hubs/static/fedora-bootstrap/fedora-bootstrap.min.css b/hubs/static/fedora-bootstrap/fedora-bootstrap.min.css
index 0476390..957fe8f 100644
--- a/hubs/static/fedora-bootstrap/fedora-bootstrap.min.css
+++ b/hubs/static/fedora-bootstrap/fedora-bootstrap.min.css
@@ -1,6 +1,6 @@
 /*!
- * Bootstrap v4.0.0-alpha.6 (https://getbootstrap.com)
+ * Bootstrap v4.0.0-beta (https://getbootstrap.com)
  * Copyright 2011-2017 The Bootstrap Authors
  * Copyright 2011-2017 Twitter, Inc.
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- *//*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}code,kbd,samp{font-family:monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}@media print{*,:after,:before,blockquote:first-letter,blockquote:first-line,div:first-letter,div:first-line,li:first-letter,li:first-line,p:first-letter,p:first-line{text-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]:after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}@-ms-viewport{width:device-width}html{-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}body{font-family:Open Sans;font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{cursor:help}address{font-style:normal;line-height:inherit}address,dl,ol,ul{margin-bottom:1rem}dl,ol,ul{margin-top:0}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}a{color:#0275d8;text-decoration:none}a:focus,a:hover{color:#014c8c;text-decoration:underline}a:not([href]):not([tabindex]),a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle}[role=button]{cursor:pointer}[role=button],a,area,button,input,label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse;background-color:transparent}caption{padding-top:.75rem;padding-bottom:.75rem;color:#d5d5d5;caption-side:bottom}caption,th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,select,textarea{line-height:inherit}input[type=checkbox]:disabled,input[type=radio]:disabled{cursor:not-allowed}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}input[type=search]{-webkit-appearance:none}output{display:inline-block}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1,h1{font-size:2rem}.h2,h2{font-size:1.75rem}.h3,h3{font-size:1.5rem}.h4,h4{font-size:1.25rem}.h5,.h6,h5,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem}.display-1,.display-2{font-weight:300;line-height:1.1}.display-2{font-size:5.5rem}.display-3{font-size:4.5rem}.display-3,.display-4{font-weight:300;line-height:1.1}.display-4{font-size:3.5rem}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.initialism{font-size:90%;text-transform:uppercase}.blockquote{padding:.5rem 1rem;margin-bottom:1rem;font-size:1.25rem;border-left:.25rem solid #eceeef}.blockquote-footer{display:block;font-size:80%;color:#d5d5d5}.blockquote-footer:before{content:"\2014   \A0"}.blockquote-reverse{padding-right:1rem;padding-left:0;text-align:right;border-right:.25rem solid #eceeef;border-left:0}.blockquote-reverse .blockquote-footer:before{content:""}.blockquote-reverse .blockquote-footer:after{content:"\A0   \2014"}.img-fluid,.img-thumbnail{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #ddd;border-radius:.25rem;transition:all .2s ease-in-out}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#d5d5d5}code,kbd,pre,samp{font-family:Hack,monospace}code{padding:.2rem .4rem;font-size:90%;color:#bd4147;background-color:#f3f3f3;border-radius:.25rem}a>code{padding:0;color:inherit;background-color:inherit}kbd{padding:.2rem .4rem;font-size:90%;color:#fff;background-color:#373a3c;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;margin-top:0;margin-bottom:1rem;font-size:90%;color:#586e75}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{position:relative;margin-left:auto;margin-right:auto;padding-right:15px;padding-left:15px}@media (min-width:576px){.container{padding-right:15px;padding-left:15px}}@media (min-width:768px){.container{padding-right:15px;padding-left:15px}}@media (min-width:992px){.container{padding-right:15px;padding-left:15px}}@media (min-width:1200px){.container{padding-right:15px;padding-left:15px}}@media (min-width:576px){.container{width:540px;max-width:100%}}@media (min-width:768px){.container{width:45pc;max-width:100%}}@media (min-width:992px){.container{width:60pc;max-width:100%}}@media (min-width:1200px){.container{width:855pt;max-width:100%}}.container-fluid{position:relative;margin-left:auto;margin-right:auto;padding-right:15px;padding-left:15px}@media (min-width:576px){.container-fluid{padding-right:15px;padding-left:15px}}@media (min-width:768px){.container-fluid{padding-right:15px;padding-left:15px}}@media (min-width:992px){.container-fluid{padding-right:15px;padding-left:15px}}@media (min-width:1200px){.container-fluid{padding-right:15px;padding-left:15px}}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}@media (min-width:576px){.row{margin-right:-15px;margin-left:-15px}}@media (min-width:768px){.row{margin-right:-15px;margin-left:-15px}}@media (min-width:992px){.row{margin-right:-15px;margin-left:-15px}}@media (min-width:1200px){.row{margin-right:-15px;margin-left:-15px}}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}@media (min-width:576px){.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{padding-right:15px;padding-left:15px}}@media (min-width:768px){.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{padding-right:15px;padding-left:15px}}@media (min-width:992px){.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{padding-right:15px;padding-left:15px}}@media (min-width:1200px){.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12{padding-right:15px;padding-left:15px}}.col{flex-basis:0;flex-grow:1;max-width:100%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.pull-0{right:auto}.pull-1{right:8.33333%}.pull-2{right:16.66667%}.pull-3{right:25%}.pull-4{right:33.33333%}.pull-5{right:41.66667%}.pull-6{right:50%}.pull-7{right:58.33333%}.pull-8{right:66.66667%}.pull-9{right:75%}.pull-10{right:83.33333%}.pull-11{right:91.66667%}.pull-12{right:100%}.push-0{left:auto}.push-1{left:8.33333%}.push-2{left:16.66667%}.push-3{left:25%}.push-4{left:33.33333%}.push-5{left:41.66667%}.push-6{left:50%}.push-7{left:58.33333%}.push-8{left:66.66667%}.push-9{left:75%}.push-10{left:83.33333%}.push-11{left:91.66667%}.push-12{left:100%}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.pull-sm-0{right:auto}.pull-sm-1{right:8.33333%}.pull-sm-2{right:16.66667%}.pull-sm-3{right:25%}.pull-sm-4{right:33.33333%}.pull-sm-5{right:41.66667%}.pull-sm-6{right:50%}.pull-sm-7{right:58.33333%}.pull-sm-8{right:66.66667%}.pull-sm-9{right:75%}.pull-sm-10{right:83.33333%}.pull-sm-11{right:91.66667%}.pull-sm-12{right:100%}.push-sm-0{left:auto}.push-sm-1{left:8.33333%}.push-sm-2{left:16.66667%}.push-sm-3{left:25%}.push-sm-4{left:33.33333%}.push-sm-5{left:41.66667%}.push-sm-6{left:50%}.push-sm-7{left:58.33333%}.push-sm-8{left:66.66667%}.push-sm-9{left:75%}.push-sm-10{left:83.33333%}.push-sm-11{left:91.66667%}.push-sm-12{left:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.pull-md-0{right:auto}.pull-md-1{right:8.33333%}.pull-md-2{right:16.66667%}.pull-md-3{right:25%}.pull-md-4{right:33.33333%}.pull-md-5{right:41.66667%}.pull-md-6{right:50%}.pull-md-7{right:58.33333%}.pull-md-8{right:66.66667%}.pull-md-9{right:75%}.pull-md-10{right:83.33333%}.pull-md-11{right:91.66667%}.pull-md-12{right:100%}.push-md-0{left:auto}.push-md-1{left:8.33333%}.push-md-2{left:16.66667%}.push-md-3{left:25%}.push-md-4{left:33.33333%}.push-md-5{left:41.66667%}.push-md-6{left:50%}.push-md-7{left:58.33333%}.push-md-8{left:66.66667%}.push-md-9{left:75%}.push-md-10{left:83.33333%}.push-md-11{left:91.66667%}.push-md-12{left:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:992px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.pull-lg-0{right:auto}.pull-lg-1{right:8.33333%}.pull-lg-2{right:16.66667%}.pull-lg-3{right:25%}.pull-lg-4{right:33.33333%}.pull-lg-5{right:41.66667%}.pull-lg-6{right:50%}.pull-lg-7{right:58.33333%}.pull-lg-8{right:66.66667%}.pull-lg-9{right:75%}.pull-lg-10{right:83.33333%}.pull-lg-11{right:91.66667%}.pull-lg-12{right:100%}.push-lg-0{left:auto}.push-lg-1{left:8.33333%}.push-lg-2{left:16.66667%}.push-lg-3{left:25%}.push-lg-4{left:33.33333%}.push-lg-5{left:41.66667%}.push-lg-6{left:50%}.push-lg-7{left:58.33333%}.push-lg-8{left:66.66667%}.push-lg-9{left:75%}.push-lg-10{left:83.33333%}.push-lg-11{left:91.66667%}.push-lg-12{left:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.pull-xl-0{right:auto}.pull-xl-1{right:8.33333%}.pull-xl-2{right:16.66667%}.pull-xl-3{right:25%}.pull-xl-4{right:33.33333%}.pull-xl-5{right:41.66667%}.pull-xl-6{right:50%}.pull-xl-7{right:58.33333%}.pull-xl-8{right:66.66667%}.pull-xl-9{right:75%}.pull-xl-10{right:83.33333%}.pull-xl-11{right:91.66667%}.pull-xl-12{right:100%}.push-xl-0{left:auto}.push-xl-1{left:8.33333%}.push-xl-2{left:16.66667%}.push-xl-3{left:25%}.push-xl-4{left:33.33333%}.push-xl-5{left:41.66667%}.push-xl-6{left:50%}.push-xl-7{left:58.33333%}.push-xl-8{left:66.66667%}.push-xl-9{left:75%}.push-xl-10{left:83.33333%}.push-xl-11{left:91.66667%}.push-xl-12{left:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;max-width:100%;margin-bottom:1rem}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #eceeef}.table thead th{vertical-align:bottom;border-bottom:2px solid #eceeef}.table tbody+tbody{border-top:2px solid #eceeef}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #eceeef}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-active,.table-active>td,.table-active>th,.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th,.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-success,.table-success>td,.table-success>th{background-color:#dff0d8}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#d0e9c6}.table-info,.table-info>td,.table-info>th{background-color:#d9edf7}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#c4e3f3}.table-warning,.table-warning>td,.table-warning>th{background-color:#fcf8e3}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#faf2cc}.table-danger,.table-danger>td,.table-danger>th{background-color:#f2dede}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#ebcccc}.thead-inverse th{color:#fff;background-color:#373a3c}.thead-default th{color:#55595c;background-color:#eceeef}.table-inverse{color:#fff;background-color:#373a3c}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#fff}.table-inverse.table-bordered{border:0}.table-responsive{display:block;width:100%;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive.table-bordered{border:0}.form-control{display:block;width:100%;padding:.5rem .75rem;font-size:1rem;line-height:1.25;color:#55595c;background-color:#fff;background-image:none;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#55595c;background-color:#fff;border-color:#5cb3fd;outline:0}.form-control::placeholder{color:#d5d5d5;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#eceeef;opacity:1}.form-control:disabled{cursor:not-allowed}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#55595c;background-color:#fff}.form-control-file,.form-control-range{display:block}.col-form-label{padding-top:calc(.5rem - 1px * 2);padding-bottom:calc(.5rem - 1px * 2);margin-bottom:0}.col-form-label-lg{padding-top:calc(.75rem - 1px * 2);padding-bottom:calc(.75rem - 1px * 2);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem - 1px * 2);padding-bottom:calc(.25rem - 1px * 2);font-size:.875rem}.col-form-legend{font-size:1rem}.col-form-legend,.form-control-static{padding-top:.5rem;padding-bottom:.5rem;margin-bottom:0}.form-control-static{line-height:1.25;border:solid transparent;border-width:1px 0}.form-control-static.form-control-lg,.form-control-static.form-control-sm,.input-group-lg>.form-control-static.form-control,.input-group-lg>.form-control-static.input-group-addon,.input-group-lg>.input-group-btn>.form-control-static.btn,.input-group-sm>.form-control-static.form-control,.input-group-sm>.form-control-static.input-group-addon,.input-group-sm>.input-group-btn>.form-control-static.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-sm>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),.input-group-sm>select.input-group-addon:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:1.8125rem}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.75rem 1.5rem;font-size:1.25rem;border-radius:.3rem}.input-group-lg>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),.input-group-lg>select.input-group-addon:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:3.16667rem}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-check{position:relative;display:block;margin-bottom:.5rem}.form-check.disabled .form-check-label{color:#d5d5d5;cursor:not-allowed}.form-check-label{padding-left:1.25rem;margin-bottom:0;cursor:pointer}.form-check-input{position:absolute;margin-top:.25rem;margin-left:-1.25rem}.form-check-input:only-child{position:static}.form-check-inline{display:inline-block}.form-check-inline .form-check-label{vertical-align:middle}.form-check-inline+.form-check-inline{margin-left:.75rem}.form-control-feedback{margin-top:.25rem}.form-control-danger,.form-control-success,.form-control-warning{padding-right:2.25rem;background-repeat:no-repeat;background-position:center right .5625rem;background-size:1.125rem 1.125rem}.has-success .col-form-label,.has-success .custom-control,.has-success .form-check-label,.has-success .form-control-feedback,.has-success .form-control-label{color:#5cb85c}.has-success .form-control{border-color:#5cb85c}.has-success .input-group-addon{color:#5cb85c;border-color:#5cb85c;background-color:#eaf6ea}.has-success .form-control-success{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%235cb85c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E")}.has-warning .col-form-label,.has-warning .custom-control,.has-warning .form-check-label,.has-warning .form-control-feedback,.has-warning .form-control-label{color:#f0ad4e}.has-warning .form-control{border-color:#f0ad4e}.has-warning .input-group-addon{color:#f0ad4e;border-color:#f0ad4e;background-color:#fff}.has-warning .form-control-warning{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23f0ad4e' d='M4.4 5.324h-.8v-2.46h.8zm0 1.42h-.8V5.89h.8zM3.76.63L.04 7.075c-.115.2.016.425.26.426h7.397c.242 0 .372-.226.258-.426C6.726 4.924 5.47 2.79 4.253.63c-.113-.174-.39-.174-.494 0z'/%3E%3C/svg%3E")}.has-danger .col-form-label,.has-danger .custom-control,.has-danger .form-check-label,.has-danger .form-control-feedback,.has-danger .form-control-label{color:#d9534f}.has-danger .form-control{border-color:#d9534f}.has-danger .input-group-addon{color:#d9534f;border-color:#d9534f;background-color:#fdf7f7}.has-danger .form-control-danger{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23d9534f' viewBox='-2 -2 7 7'%3E%3Cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3E%3Ccircle r='.5'/%3E%3Ccircle cx='3' r='.5'/%3E%3Ccircle cy='3' r='.5'/%3E%3Ccircle cx='3' cy='3' r='.5'/%3E%3C/svg%3E")}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{justify-content:center}.form-inline .form-group,.form-inline label{display:flex;align-items:center;margin-bottom:0}.form-inline .form-group{flex:0 0 auto;flex-flow:row wrap}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-control-label{margin-bottom:0;vertical-align:middle}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;margin-top:0;margin-bottom:0}.form-inline .form-check-label{padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{display:flex;align-items:center;justify-content:center;padding-left:0}.form-inline .custom-control-indicator{position:static;display:inline-block;margin-right:.25rem;vertical-align:text-bottom}.form-inline .has-feedback .form-control-feedback{top:0}}.btn{display:inline-block;font-weight:400;line-height:1.25;text-align:center;white-space:nowrap;vertical-align:middle;user-select:none;border:1px solid transparent;padding:.5rem 1rem;font-size:1rem;border-radius:.25rem;transition:all .2s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 2px rgba(2,117,216,.25)}.btn.disabled,.btn:disabled{cursor:not-allowed;opacity:.65}.btn.active,.btn:active{background-image:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary:hover{color:#fff;background-color:#025aa5;border-color:#01549b}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 2px rgba(2,117,216,.5)}.btn-primary.disabled,.btn-primary:disabled{background-color:#0275d8;border-color:#0275d8}.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#025aa5;background-image:none;border-color:#01549b}.btn-secondary{color:#373a3c;background-color:#fff;border-color:#ccc}.btn-secondary:hover{color:#373a3c;background-color:#e6e6e6;border-color:#adadad}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 2px hsla(0,0%,80%,.5)}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#fff;border-color:#ccc}.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#373a3c;background-color:#e6e6e6;background-image:none;border-color:#adadad}.btn-info{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#2aabd2}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 2px rgba(91,192,222,.5)}.btn-info.disabled,.btn-info:disabled{background-color:#5bc0de;border-color:#5bc0de}.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#31b0d5;background-image:none;border-color:#2aabd2}.btn-success{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#419641}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 2px rgba(92,184,92,.5)}.btn-success.disabled,.btn-success:disabled{background-color:#5cb85c;border-color:#5cb85c}.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#449d44;background-image:none;border-color:#419641}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#eb9316}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 2px rgba(240,173,78,.5)}.btn-warning.disabled,.btn-warning:disabled{background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#fff;background-color:#ec971f;background-image:none;border-color:#eb9316}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#c12e2a}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 2px rgba(217,83,79,.5)}.btn-danger.disabled,.btn-danger:disabled{background-color:#d9534f;border-color:#d9534f}.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#c9302c;background-image:none;border-color:#c12e2a}.btn-outline-primary{color:#0275d8;background-image:none;background-color:transparent;border-color:#0275d8}.btn-outline-primary:hover{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 2px rgba(2,117,216,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0275d8;background-color:transparent}.btn-outline-primary.active,.btn-outline-primary:active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-outline-secondary{color:#ccc;background-image:none;background-color:transparent;border-color:#ccc}.btn-outline-secondary:hover{color:#fff;background-color:#ccc;border-color:#ccc}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 2px hsla(0,0%,80%,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#ccc;background-color:transparent}.btn-outline-secondary.active,.btn-outline-secondary:active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#ccc;border-color:#ccc}.btn-outline-info{color:#5bc0de;background-image:none;background-color:transparent;border-color:#5bc0de}.btn-outline-info:hover{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 2px rgba(91,192,222,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#5bc0de;background-color:transparent}.btn-outline-info.active,.btn-outline-info:active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-outline-success{color:#5cb85c;background-image:none;background-color:transparent;border-color:#5cb85c}.btn-outline-success:hover{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 2px rgba(92,184,92,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#5cb85c;background-color:transparent}.btn-outline-success.active,.btn-outline-success:active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-outline-warning{color:#f0ad4e;background-image:none;background-color:transparent;border-color:#f0ad4e}.btn-outline-warning:hover{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 2px rgba(240,173,78,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#f0ad4e;background-color:transparent}.btn-outline-warning.active,.btn-outline-warning:active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-outline-danger{color:#d9534f;background-image:none;background-color:transparent;border-color:#d9534f}.btn-outline-danger:hover{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 2px rgba(217,83,79,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#d9534f;background-color:transparent}.btn-outline-danger.active,.btn-outline-danger:active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-link{font-weight:400;color:#0275d8;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#014c8c;text-decoration:underline;background-color:transparent}.btn-link:disabled{color:#d5d5d5}.btn-link:disabled:focus,.btn-link:disabled:hover{text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.75rem 1.5rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{height:0;overflow:hidden;transition:height .35s ease}.collapsing,.dropdown,.dropup{position:relative}.dropdown-toggle:after{display:inline-block;width:0;height:0;margin-left:.3em;vertical-align:middle;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:focus{outline:0}.dropup .dropdown-toggle:after{border-top:0;border-bottom:.3em solid}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-divider{height:1px;margin:.5rem 0;overflow:hidden;background-color:#eceeef}.dropdown-item{display:block;width:100%;padding:3px 1.5rem;clear:both;font-weight:400;color:#373a3c;text-align:inherit;white-space:nowrap;background:none;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#2b2d2f;text-decoration:none;background-color:#f3f3f3}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0275d8}.dropdown-item.disabled,.dropdown-item:disabled{color:#d5d5d5;cursor:not-allowed;background-color:transparent}.show>.dropdown-menu{display:block}.show>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#d5d5d5;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.dropup .dropdown-menu{top:auto;bottom:100%;margin-bottom:.125rem}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:0 1 auto}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:flex;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn+.dropdown-toggle-split:after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:1.125rem;padding-left:1.125rem}.btn-group-vertical{display:inline-flex;flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:flex;width:100%}.input-group .form-control{position:relative;z-index:2;flex:1 1 auto;width:1%;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover{z-index:3}.input-group .form-control,.input-group-addon,.input-group-btn{display:flex;flex-direction:column;justify-content:center}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{white-space:nowrap;vertical-align:middle}.input-group-addon{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.25;color:#55595c;text-align:center;background-color:#eceeef;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.75rem 1.5rem;font-size:1.25rem;border-radius:.3rem}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:not(:last-child),.input-group-addon:not(:last-child),.input-group-btn:not(:first-child)>.btn-group:not(:last-child)>.btn,.input-group-btn:not(:first-child)>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group>.btn,.input-group-btn:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:not(:last-child){border-right:0}.input-group .form-control:not(:first-child),.input-group-addon:not(:first-child),.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group>.btn,.input-group-btn:not(:first-child)>.dropdown-toggle,.input-group-btn:not(:last-child)>.btn-group:not(:first-child)>.btn,.input-group-btn:not(:last-child)>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.form-control+.input-group-addon:not(:first-child){border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative;flex:1}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group{margin-right:-1px}.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group{z-index:2;margin-left:-1px}.input-group-btn:not(:first-child)>.btn-group:active,.input-group-btn:not(:first-child)>.btn-group:focus,.input-group-btn:not(:first-child)>.btn-group:hover,.input-group-btn:not(:first-child)>.btn:active,.input-group-btn:not(:first-child)>.btn:focus,.input-group-btn:not(:first-child)>.btn:hover{z-index:3}.custom-control{position:relative;display:inline-flex;min-height:1.5rem;padding-left:1.5rem;margin-right:1rem;cursor:pointer}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-indicator{color:#fff;background-color:#0275d8}.custom-control-input:focus~.custom-control-indicator{box-shadow:0 0 0 1px #fff,0 0 0 3px #0275d8}.custom-control-input:active~.custom-control-indicator{color:#fff;background-color:#8fcafe}.custom-control-input:disabled~.custom-control-indicator{cursor:not-allowed;background-color:#eceeef}.custom-control-input:disabled~.custom-control-description{color:#d5d5d5;cursor:not-allowed}.custom-control-indicator{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;user-select:none;background-color:#ddd;background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-indicator{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-indicator{background-color:#0275d8;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-radio .custom-control-indicator{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-controls-stacked{display:flex;flex-direction:column}.custom-controls-stacked .custom-control{margin-bottom:.25rem}.custom-controls-stacked .custom-control+.custom-control{margin-left:0}.custom-select{display:inline-block;max-width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.25;color:#55595c;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;-moz-appearance:none;-webkit-appearance:none}.custom-select:focus{border-color:#5cb3fd;outline:0}.custom-select:focus::-ms-value{color:#55595c;background-color:#fff}.custom-select:disabled{color:#d5d5d5;cursor:not-allowed;background-color:#eceeef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-file{position:relative;display:inline-block;max-width:100%;height:2.5rem;margin-bottom:0;cursor:pointer}.custom-file-input{min-width:14rem;max-width:100%;height:2.5rem;margin:0;filter:alpha(opacity=0);opacity:0}.custom-file-control{position:absolute;top:0;right:0;left:0;z-index:5;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#55595c;pointer-events:none;user-select:none;background-color:#fff;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.custom-file-control:lang(en):after{content:"Choose file..."}.custom-file-control:before{position:absolute;top:-1px;right:-1px;bottom:-1px;z-index:6;display:block;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#55595c;background-color:#eceeef;border:1px solid rgba(0,0,0,.15);border-radius:0 .25rem .25rem 0}.custom-file-control:lang(en):before{content:"Browse"}.nav{display:flex;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5em 1em}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#d5d5d5;cursor:not-allowed}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-right-radius:.25rem;border-top-left-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#eceeef #eceeef #ddd}.nav-tabs .nav-link.disabled{color:#d5d5d5;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#55595c;background-color:#fff;border-color:#ddd #ddd #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-item.show .nav-link,.nav-pills .nav-link.active{color:#fff;cursor:default;background-color:#0275d8}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex:1 1 100%;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-direction:column;padding:.5rem 1rem}.navbar-brand{display:inline-block;padding-top:.25rem;padding-bottom:.25rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-text{display:inline-block;padding-top:.425rem;padding-bottom:.425rem}.navbar-toggler{align-self:flex-start;padding:.25rem .75rem;font-size:1.25rem;line-height:1;background:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}.navbar-toggler-left{position:absolute;left:1rem}.navbar-toggler-right{position:absolute;right:1rem}@media (max-width:575px){.navbar-toggleable .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable>.container{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-toggleable{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable .navbar-nav{flex-direction:row}.navbar-toggleable .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable .navbar-toggler{display:none}}@media (max-width:767px){.navbar-toggleable-sm .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable-sm>.container{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-toggleable-sm{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable-sm .navbar-nav{flex-direction:row}.navbar-toggleable-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable-sm>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable-sm .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable-sm .navbar-toggler{display:none}}@media (max-width:991px){.navbar-toggleable-md .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable-md>.container{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-toggleable-md{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable-md .navbar-nav{flex-direction:row}.navbar-toggleable-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable-md>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable-md .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable-md .navbar-toggler{display:none}}@media (max-width:1199px){.navbar-toggleable-lg .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable-lg>.container{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-toggleable-lg{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable-lg .navbar-nav{flex-direction:row}.navbar-toggleable-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable-lg>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable-lg .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable-lg .navbar-toggler{display:none}}.navbar-toggleable-xl{flex-direction:row;flex-wrap:nowrap;align-items:center}.navbar-toggleable-xl .navbar-nav .dropdown-menu{position:static;float:none}.navbar-toggleable-xl>.container{padding-right:0;padding-left:0}.navbar-toggleable-xl .navbar-nav{flex-direction:row}.navbar-toggleable-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-toggleable-xl>.container{display:flex;flex-wrap:nowrap;align-items:center}.navbar-toggleable-xl .navbar-collapse{display:flex!important;width:100%}.navbar-toggleable-xl .navbar-toggler{display:none}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover,.navbar-light .navbar-toggler,.navbar-light .navbar-toggler:focus,.navbar-light .navbar-toggler:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.open,.navbar-light .navbar-nav .open>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0,0,0,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-toggler,.navbar-inverse .navbar-toggler:focus,.navbar-inverse .navbar-toggler:hover{color:#fff}.navbar-inverse .navbar-nav .nav-link{color:hsla(0,0%,100%,.5)}.navbar-inverse .navbar-nav .nav-link:focus,.navbar-inverse .navbar-nav .nav-link:hover{color:hsla(0,0%,100%,.75)}.navbar-inverse .navbar-nav .nav-link.disabled{color:hsla(0,0%,100%,.25)}.navbar-inverse .navbar-nav .active>.nav-link,.navbar-inverse .navbar-nav .nav-link.active,.navbar-inverse .navbar-nav .nav-link.open,.navbar-inverse .navbar-nav .open>.nav-link{color:#fff}.navbar-inverse .navbar-toggler{border-color:hsla(0,0%,100%,.1)}.navbar-inverse .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255,255,255,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E")}.navbar-inverse .navbar-text{color:hsla(0,0%,100%,.5)}.card{position:relative;display:flex;flex-direction:column;background-color:#fff;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card-block{flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem}.card-subtitle,.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card>.list-group:first-child .list-group-item:first-child{border-top-right-radius:.25rem;border-top-left-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:#f3f3f3;border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.75rem 1.25rem;background-color:#f3f3f3;border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-bottom:-.75rem;border-bottom:0}.card-header-pills,.card-header-tabs{margin-right:-.625rem;margin-left:-.625rem}.card-primary{background-color:#0275d8;border-color:#0275d8}.card-primary .card-footer,.card-primary .card-header{background-color:transparent}.card-success{background-color:#5cb85c;border-color:#5cb85c}.card-success .card-footer,.card-success .card-header{background-color:transparent}.card-info{background-color:#5bc0de;border-color:#5bc0de}.card-info .card-footer,.card-info .card-header{background-color:transparent}.card-warning{background-color:#f0ad4e;border-color:#f0ad4e}.card-warning .card-footer,.card-warning .card-header{background-color:transparent}.card-danger{background-color:#d9534f;border-color:#d9534f}.card-danger .card-footer,.card-danger .card-header,.card-outline-primary{background-color:transparent}.card-outline-primary{border-color:#0275d8}.card-outline-secondary{background-color:transparent;border-color:#ccc}.card-outline-info{background-color:transparent;border-color:#5bc0de}.card-outline-success{background-color:transparent;border-color:#5cb85c}.card-outline-warning{background-color:transparent;border-color:#f0ad4e}.card-outline-danger{background-color:transparent;border-color:#d9534f}.card-inverse{color:hsla(0,0%,100%,.65)}.card-inverse .card-footer,.card-inverse .card-header{background-color:transparent;border-color:hsla(0,0%,100%,.2)}.card-inverse .card-blockquote,.card-inverse .card-footer,.card-inverse .card-header,.card-inverse .card-title{color:#fff}.card-inverse .card-blockquote .blockquote-footer,.card-inverse .card-link,.card-inverse .card-subtitle,.card-inverse .card-text{color:hsla(0,0%,100%,.65)}.card-inverse .card-link:focus,.card-inverse .card-link:hover{color:#fff}.card-blockquote{padding:0;margin-bottom:0;border-left:0}.card-img{border-radius:calc(.25rem - 1px)}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img-top{border-top-right-radius:calc(.25rem - 1px);border-top-left-radius:calc(.25rem - 1px)}.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}@media (min-width:576px){.card-deck{display:flex;flex-flow:row wrap}.card-deck .card{display:flex;flex:1 0 0;flex-direction:column}.card-deck .card:not(:first-child){margin-left:15px}.card-deck .card:not(:last-child){margin-right:15px}}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group .card{flex:1 0 0}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-bottom-right-radius:0;border-top-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-bottom-left-radius:0;border-top-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child),.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}}@media (min-width:576px){.card-columns{column-count:3;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%;margin-bottom:.75rem}}.breadcrumb{padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#eceeef;border-radius:.25rem}.breadcrumb:after{display:block;content:"";clear:both}.breadcrumb-item{float:left}.breadcrumb-item+.breadcrumb-item:before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#d5d5d5;content:"/"}.breadcrumb-item+.breadcrumb-item:hover:before{text-decoration:underline;text-decoration:none}.breadcrumb-item.active{color:#d5d5d5}.pagination{display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-item:first-child .page-link{margin-left:0;border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.page-item:last-child .page-link{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.page-item.active .page-link{z-index:2;color:#fff;background-color:#0275d8;border-color:#0275d8}.page-item.disabled .page-link{color:#d5d5d5;pointer-events:none;cursor:not-allowed;background-color:#fff;border-color:#ddd}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#0275d8;background-color:#fff;border:1px solid #ddd}.page-link:focus,.page-link:hover{color:#014c8c;text-decoration:none;background-color:#eceeef;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-bottom-left-radius:.3rem;border-top-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-bottom-right-radius:.3rem;border-top-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-bottom-left-radius:.2rem;border-top-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-bottom-right-radius:.2rem;border-top-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-default{background-color:#d5d5d5}.badge-default[href]:focus,.badge-default[href]:hover{background-color:#bcbcbc}.badge-primary{background-color:#0275d8}.badge-primary[href]:focus,.badge-primary[href]:hover{background-color:#025aa5}.badge-success{background-color:#5cb85c}.badge-success[href]:focus,.badge-success[href]:hover{background-color:#449d44}.badge-info{background-color:#5bc0de}.badge-info[href]:focus,.badge-info[href]:hover{background-color:#31b0d5}.badge-warning{background-color:#f0ad4e}.badge-warning[href]:focus,.badge-warning[href]:hover{background-color:#ec971f}.badge-danger{background-color:#d9534f}.badge-danger[href]:focus,.badge-danger[href]:hover{background-color:#c9302c}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#eceeef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-hr{border-top-color:#d0d5d8}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible .close{position:relative;top:-.75rem;right:-1.25rem;padding:.75rem 1.25rem;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d0e9c6;color:#3c763d}.alert-success hr{border-top-color:#c1e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.alert-info hr{border-top-color:#a6d5ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faf2cc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7ecb5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebcccc;color:#a94442}.alert-danger hr{border-top-color:#e4b9b9}.alert-danger .alert-link{color:#843534}@keyframes progress-bar-stripes{0%{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;overflow:hidden;font-size:.75rem;line-height:1rem;text-align:center;background-color:#eceeef;border-radius:.25rem}.progress-bar{height:1rem;color:#fff;background-color:#0275d8}.progress-bar-striped{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 25%,transparent 50%,hsla(0,0%,100%,.15) 50%,hsla(0,0%,100%,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#55595c;text-align:inherit}.list-group-item-action .list-group-item-heading{color:#373a3c}.list-group-item-action:focus,.list-group-item-action:hover{color:#55595c;text-decoration:none;background-color:#f3f3f3}.list-group-item-action:active{color:#373a3c;background-color:#eceeef}.list-group-item{position:relative;display:flex;flex-flow:row wrap;align-items:center;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-right-radius:.25rem;border-top-left-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#d5d5d5;cursor:not-allowed;background-color:#fff}.list-group-item.disabled .list-group-item-heading,.list-group-item:disabled .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item:disabled .list-group-item-text{color:#d5d5d5}.list-group-item.active{z-index:2;color:#fff;background-color:#0275d8;border-color:#0275d8}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text{color:#daeeff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,button.list-group-item-success.active{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,button.list-group-item-info.active{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,button.list-group-item-warning.active{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,button.list-group-item-danger.active{color:#fff;background-color:#a94442;border-color:#a94442}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive:before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9:before{padding-top:42.85714%}.embed-responsive-16by9:before{padding-top:56.25%}.embed-responsive-4by3:before{padding-top:75%}.embed-responsive-1by1:before{padding-top:100%}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.75}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal,.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;outline:0}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -25%)}.modal.show .modal-dialog{transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;display:flex;flex-direction:column;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;align-items:center;justify-content:space-between;padding:15px;border-bottom:1px solid #eceeef}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:15px}.modal-footer{display:flex;align-items:center;justify-content:flex-end;padding:15px;border-top:1px solid #eceeef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:30px auto}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:50pc}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Open Sans;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip.bs-tether-element-attached-bottom,.tooltip.tooltip-top{padding:5px 0;margin-top:-3px}.tooltip.bs-tether-element-attached-bottom .tooltip-inner:before,.tooltip.tooltip-top .tooltip-inner:before{bottom:0;left:50%;margin-left:-5px;content:"";border-width:5px 5px 0;border-top-color:#000}.tooltip.bs-tether-element-attached-left,.tooltip.tooltip-right{padding:0 5px;margin-left:3px}.tooltip.bs-tether-element-attached-left .tooltip-inner:before,.tooltip.tooltip-right .tooltip-inner:before{top:50%;left:0;margin-top:-5px;content:"";border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.bs-tether-element-attached-top,.tooltip.tooltip-bottom{padding:5px 0;margin-top:3px}.tooltip.bs-tether-element-attached-top .tooltip-inner:before,.tooltip.tooltip-bottom .tooltip-inner:before{top:0;left:50%;margin-left:-5px;content:"";border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bs-tether-element-attached-right,.tooltip.tooltip-left{padding:0 5px;margin-left:-3px}.tooltip.bs-tether-element-attached-right .tooltip-inner:before,.tooltip.tooltip-left .tooltip-inner:before{top:50%;right:0;margin-top:-5px;content:"";border-width:5px 0 5px 5px;border-left-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.tooltip-inner:before{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;padding:1px;font-family:Open Sans;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover.bs-tether-element-attached-bottom,.popover.popover-top{margin-top:-10px}.popover.bs-tether-element-attached-bottom:after,.popover.bs-tether-element-attached-bottom:before,.popover.popover-top:after,.popover.popover-top:before{left:50%;border-bottom-width:0}.popover.bs-tether-element-attached-bottom:before,.popover.popover-top:before{bottom:-11px;margin-left:-11px;border-top-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-bottom:after,.popover.popover-top:after{bottom:-10px;margin-left:-10px;border-top-color:#fff}.popover.bs-tether-element-attached-left,.popover.popover-right{margin-left:10px}.popover.bs-tether-element-attached-left:after,.popover.bs-tether-element-attached-left:before,.popover.popover-right:after,.popover.popover-right:before{top:50%;border-left-width:0}.popover.bs-tether-element-attached-left:before,.popover.popover-right:before{left:-11px;margin-top:-11px;border-right-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-left:after,.popover.popover-right:after{left:-10px;margin-top:-10px;border-right-color:#fff}.popover.bs-tether-element-attached-top,.popover.popover-bottom{margin-top:10px}.popover.bs-tether-element-attached-top:after,.popover.bs-tether-element-attached-top:before,.popover.popover-bottom:after,.popover.popover-bottom:before{left:50%;border-top-width:0}.popover.bs-tether-element-attached-top:before,.popover.popover-bottom:before{top:-11px;margin-left:-11px;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-top:after,.popover.popover-bottom:after{top:-10px;margin-left:-10px;border-bottom-color:#f7f7f7}.popover.bs-tether-element-attached-top .popover-title:before,.popover.popover-bottom .popover-title:before{position:absolute;top:0;left:50%;display:block;width:20px;margin-left:-10px;content:"";border-bottom:1px solid #f7f7f7}.popover.bs-tether-element-attached-right,.popover.popover-left{margin-left:-10px}.popover.bs-tether-element-attached-right:after,.popover.bs-tether-element-attached-right:before,.popover.popover-left:after,.popover.popover-left:before{top:50%;border-right-width:0}.popover.bs-tether-element-attached-right:before,.popover.popover-left:before{right:-11px;margin-top:-11px;border-left-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-right:after,.popover.popover-left:after{right:-10px;margin-top:-10px;border-left-color:#fff}.popover-title{padding:8px 14px;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-right-radius:calc(.3rem - 1px);border-top-left-radius:calc(.3rem - 1px)}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover:after,.popover:before{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover:before{content:"";border-width:11px}.popover:after{content:"";border-width:10px}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;width:100%}@media (-webkit-transform-3d){.carousel-item{transition:transform .6s ease-in-out;backface-visibility:hidden;perspective:750pt}}@supports (transform:translate3d(0,0,0)){.carousel-item{transition:transform .6s ease-in-out;backface-visibility:hidden;perspective:750pt}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:flex}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}@media (-webkit-transform-3d){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translate3d(0,0,0)}.active.carousel-item-right,.carousel-item-next{transform:translate3d(100%,0,0)}.active.carousel-item-left,.carousel-item-prev{transform:translate3d(-100%,0,0)}}@supports (transform:translate3d(0,0,0)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translate3d(0,0,0)}.active.carousel-item-right,.carousel-item-next{transform:translate3d(100%,0,0)}.active.carousel-item-left,.carousel-item-prev{transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:flex;align-items:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M4 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;flex:1 0 auto;max-width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:hsla(0,0%,100%,.5)}.carousel-indicators li:before{top:-10px}.carousel-indicators li:after,.carousel-indicators li:before{position:absolute;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li:after{bottom:-10px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-faded{background-color:#f7f7f7}.bg-primary{background-color:#0275d8!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#025aa5!important}.bg-success{background-color:#5cb85c!important}a.bg-success:focus,a.bg-success:hover{background-color:#449d44!important}.bg-info{background-color:#5bc0de!important}a.bg-info:focus,a.bg-info:hover{background-color:#31b0d5!important}.bg-warning{background-color:#f0ad4e!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#ec971f!important}.bg-danger{background-color:#d9534f!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#c9302c!important}.bg-inverse{background-color:#373a3c!important}a.bg-inverse:focus,a.bg-inverse:hover{background-color:#1f2021!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.rounded{border-radius:.25rem}.rounded-top{border-top-left-radius:.25rem}.rounded-right,.rounded-top{border-top-right-radius:.25rem}.rounded-bottom,.rounded-right{border-bottom-right-radius:.25rem}.rounded-bottom,.rounded-left{border-bottom-left-radius:.25rem}.rounded-left{border-top-left-radius:.25rem}.rounded-circle{border-radius:50%}.rounded-0{border-radius:0}.clearfix:after{display:block;content:"";clear:both}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}.flex-first{order:-1}.flex-last{order:1}.flex-unordered{order:0}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:576px){.flex-sm-first{order:-1}.flex-sm-last{order:1}.flex-sm-unordered{order:0}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:768px){.flex-md-first{order:-1}.flex-md-last{order:1}.flex-md-unordered{order:0}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:992px){.flex-lg-first{order:-1}.flex-lg-last{order:1}.flex-lg-unordered{order:0}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1200px){.flex-xl-first{order:-1}.flex-xl-last{order:1}.flex-xl-unordered{order:0}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.fixed-top{top:0}.fixed-bottom,.fixed-top{position:fixed;right:0;left:0;z-index:1030}.fixed-bottom{bottom:0}.sticky-top{position:sticky;top:0;z-index:1030}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.mx-0{margin-right:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.25rem!important}.mt-1{margin-top:.25rem!important}.mr-1{margin-right:.25rem!important}.mb-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.mx-1{margin-right:.25rem!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-2{margin:.5rem!important}.mt-2{margin-top:.5rem!important}.mr-2{margin-right:.5rem!important}.mb-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.mx-2{margin-right:.5rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-3{margin:1rem!important}.mt-3{margin-top:1rem!important}.mr-3{margin-right:1rem!important}.mb-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.mx-3{margin-right:1rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-4{margin:1.5rem!important}.mt-4{margin-top:1.5rem!important}.mr-4{margin-right:1.5rem!important}.mb-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.mx-4{margin-right:1.5rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-5{margin:3rem!important}.mt-5{margin-top:3rem!important}.mr-5{margin-right:3rem!important}.mb-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.mx-5{margin-right:3rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.px-0{padding-right:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.25rem!important}.pt-1{padding-top:.25rem!important}.pr-1{padding-right:.25rem!important}.pb-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.px-1{padding-right:.25rem!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-2{padding:.5rem!important}.pt-2{padding-top:.5rem!important}.pr-2{padding-right:.5rem!important}.pb-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.px-2{padding-right:.5rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-3{padding:1rem!important}.pt-3{padding-top:1rem!important}.pr-3{padding-right:1rem!important}.pb-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.px-3{padding-right:1rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-4{padding:1.5rem!important}.pt-4{padding-top:1.5rem!important}.pr-4{padding-right:1.5rem!important}.pb-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.px-4{padding-right:1.5rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-5{padding:3rem!important}.pt-5{padding-top:3rem!important}.pr-5{padding-right:3rem!important}.pb-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.px-5{padding-right:3rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-auto{margin:auto!important}.mt-auto{margin-top:auto!important}.mr-auto{margin-right:auto!important}.mb-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}.mx-auto{margin-right:auto!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0{margin-top:0!important}.mr-sm-0{margin-right:0!important}.mb-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.mx-sm-0{margin-right:0!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1{margin-top:.25rem!important}.mr-sm-1{margin-right:.25rem!important}.mb-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.mx-sm-1{margin-right:.25rem!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2{margin-top:.5rem!important}.mr-sm-2{margin-right:.5rem!important}.mb-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.mx-sm-2{margin-right:.5rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3{margin-top:1rem!important}.mr-sm-3{margin-right:1rem!important}.mb-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.mx-sm-3{margin-right:1rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4{margin-top:1.5rem!important}.mr-sm-4{margin-right:1.5rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.mx-sm-4{margin-right:1.5rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5{margin-top:3rem!important}.mr-sm-5{margin-right:3rem!important}.mb-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.mx-sm-5{margin-right:3rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0{padding-top:0!important}.pr-sm-0{padding-right:0!important}.pb-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.px-sm-0{padding-right:0!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1{padding-top:.25rem!important}.pr-sm-1{padding-right:.25rem!important}.pb-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.px-sm-1{padding-right:.25rem!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2{padding-top:.5rem!important}.pr-sm-2{padding-right:.5rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.px-sm-2{padding-right:.5rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3{padding-top:1rem!important}.pr-sm-3{padding-right:1rem!important}.pb-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.px-sm-3{padding-right:1rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4{padding-top:1.5rem!important}.pr-sm-4{padding-right:1.5rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.px-sm-4{padding-right:1.5rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5{padding-top:3rem!important}.pr-sm-5{padding-right:3rem!important}.pb-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.px-sm-5{padding-right:3rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto{margin-top:auto!important}.mr-sm-auto{margin-right:auto!important}.mb-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}.mx-sm-auto{margin-right:auto!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0{margin-top:0!important}.mr-md-0{margin-right:0!important}.mb-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.mx-md-0{margin-right:0!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.m-md-1{margin:.25rem!important}.mt-md-1{margin-top:.25rem!important}.mr-md-1{margin-right:.25rem!important}.mb-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.mx-md-1{margin-right:.25rem!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2{margin-top:.5rem!important}.mr-md-2{margin-right:.5rem!important}.mb-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.mx-md-2{margin-right:.5rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3{margin-top:1rem!important}.mr-md-3{margin-right:1rem!important}.mb-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.mx-md-3{margin-right:1rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4{margin-top:1.5rem!important}.mr-md-4{margin-right:1.5rem!important}.mb-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.mx-md-4{margin-right:1.5rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5{margin-top:3rem!important}.mr-md-5{margin-right:3rem!important}.mb-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.mx-md-5{margin-right:3rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-md-0{padding:0!important}.pt-md-0{padding-top:0!important}.pr-md-0{padding-right:0!important}.pb-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.px-md-0{padding-right:0!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.p-md-1{padding:.25rem!important}.pt-md-1{padding-top:.25rem!important}.pr-md-1{padding-right:.25rem!important}.pb-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.px-md-1{padding-right:.25rem!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2{padding-top:.5rem!important}.pr-md-2{padding-right:.5rem!important}.pb-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.px-md-2{padding-right:.5rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3{padding-top:1rem!important}.pr-md-3{padding-right:1rem!important}.pb-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.px-md-3{padding-right:1rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4{padding-top:1.5rem!important}.pr-md-4{padding-right:1.5rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.px-md-4{padding-right:1.5rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5{padding-top:3rem!important}.pr-md-5{padding-right:3rem!important}.pb-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.px-md-5{padding-right:3rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto{margin-top:auto!important}.mr-md-auto{margin-right:auto!important}.mb-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}.mx-md-auto{margin-right:auto!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0{margin-top:0!important}.mr-lg-0{margin-right:0!important}.mb-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.mx-lg-0{margin-right:0!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1{margin-top:.25rem!important}.mr-lg-1{margin-right:.25rem!important}.mb-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.mx-lg-1{margin-right:.25rem!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2{margin-top:.5rem!important}.mr-lg-2{margin-right:.5rem!important}.mb-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.mx-lg-2{margin-right:.5rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3{margin-top:1rem!important}.mr-lg-3{margin-right:1rem!important}.mb-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.mx-lg-3{margin-right:1rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4{margin-top:1.5rem!important}.mr-lg-4{margin-right:1.5rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.mx-lg-4{margin-right:1.5rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5{margin-top:3rem!important}.mr-lg-5{margin-right:3rem!important}.mb-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.mx-lg-5{margin-right:3rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0{padding-top:0!important}.pr-lg-0{padding-right:0!important}.pb-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.px-lg-0{padding-right:0!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1{padding-top:.25rem!important}.pr-lg-1{padding-right:.25rem!important}.pb-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.px-lg-1{padding-right:.25rem!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2{padding-top:.5rem!important}.pr-lg-2{padding-right:.5rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.px-lg-2{padding-right:.5rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3{padding-top:1rem!important}.pr-lg-3{padding-right:1rem!important}.pb-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.px-lg-3{padding-right:1rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4{padding-top:1.5rem!important}.pr-lg-4{padding-right:1.5rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.px-lg-4{padding-right:1.5rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5{padding-top:3rem!important}.pr-lg-5{padding-right:3rem!important}.pb-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.px-lg-5{padding-right:3rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto{margin-top:auto!important}.mr-lg-auto{margin-right:auto!important}.mb-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}.mx-lg-auto{margin-right:auto!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0{margin-top:0!important}.mr-xl-0{margin-right:0!important}.mb-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.mx-xl-0{margin-right:0!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1{margin-top:.25rem!important}.mr-xl-1{margin-right:.25rem!important}.mb-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.mx-xl-1{margin-right:.25rem!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2{margin-top:.5rem!important}.mr-xl-2{margin-right:.5rem!important}.mb-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.mx-xl-2{margin-right:.5rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3{margin-top:1rem!important}.mr-xl-3{margin-right:1rem!important}.mb-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.mx-xl-3{margin-right:1rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4{margin-top:1.5rem!important}.mr-xl-4{margin-right:1.5rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.mx-xl-4{margin-right:1.5rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5{margin-top:3rem!important}.mr-xl-5{margin-right:3rem!important}.mb-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.mx-xl-5{margin-right:3rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0{padding-top:0!important}.pr-xl-0{padding-right:0!important}.pb-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.px-xl-0{padding-right:0!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1{padding-top:.25rem!important}.pr-xl-1{padding-right:.25rem!important}.pb-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.px-xl-1{padding-right:.25rem!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2{padding-top:.5rem!important}.pr-xl-2{padding-right:.5rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.px-xl-2{padding-right:.5rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3{padding-top:1rem!important}.pr-xl-3{padding-right:1rem!important}.pb-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.px-xl-3{padding-right:1rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4{padding-top:1.5rem!important}.pr-xl-4{padding-right:1.5rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.px-xl-4{padding-right:1.5rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5{padding-top:3rem!important}.pr-xl-5{padding-right:3rem!important}.pb-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.px-xl-5{padding-right:3rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto{margin-top:auto!important}.mr-xl-auto{margin-right:auto!important}.mb-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}.mx-xl-auto{margin-right:auto!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-white{color:#fff!important}.text-muted{color:#d5d5d5!important}a.text-muted:focus,a.text-muted:hover{color:#bcbcbc!important}.text-primary{color:#0275d8!important}a.text-primary:focus,a.text-primary:hover{color:#025aa5!important}.text-success{color:#5cb85c!important}a.text-success:focus,a.text-success:hover{color:#449d44!important}.text-info{color:#5bc0de!important}a.text-info:focus,a.text-info:hover{color:#31b0d5!important}.text-warning{color:#f0ad4e!important}a.text-warning:focus,a.text-warning:hover{color:#ec971f!important}.text-danger{color:#d9534f!important}a.text-danger:focus,a.text-danger:hover{color:#c9302c!important}.text-gray-dark{color:#373a3c!important}a.text-gray-dark:focus,a.text-gray-dark:hover{color:#1f2021!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.invisible{visibility:hidden!important}.hidden-xs-up{display:none!important}@media (max-width:575px){.hidden-xs-down{display:none!important}}@media (min-width:576px){.hidden-sm-up{display:none!important}}@media (max-width:767px){.hidden-sm-down{display:none!important}}@media (min-width:768px){.hidden-md-up{display:none!important}}@media (max-width:991px){.hidden-md-down{display:none!important}}@media (min-width:992px){.hidden-lg-up{display:none!important}}@media (max-width:1199px){.hidden-lg-down{display:none!important}}@media (min-width:1200px){.hidden-xl-up{display:none!important}}.hidden-xl-down,.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}.container-narrow{position:relative;margin-left:auto;margin-right:auto;padding-right:15px;padding-left:15px}@media (min-width:576px){.container-narrow{padding-right:15px;padding-left:15px}}@media (min-width:768px){.container-narrow{padding-right:15px;padding-left:15px}}@media (min-width:992px){.container-narrow{padding-right:15px;padding-left:15px}}@media (min-width:1200px){.container-narrow{padding-right:15px;padding-left:15px}}@media (min-width:576px){.container-narrow{max-width:34rem}}@media (min-width:768px){.container-narrow{max-width:45rem}}@media (min-width:992px){.container-narrow{max-width:45rem}}@media (min-width:1200px){.container-narrow{max-width:45rem}}.nav-underline .nav-item.active,.nav-underline .nav-item.active:hover{box-shadow:0 -3px 0 0 #0275d8 inset}.nav-underline .nav-item.active .nav-link,.nav-underline .nav-item.active:hover .nav-link{color:#0275d8}.nav-underline li:hover{box-shadow:0 -3px 0 0 #ddd inset}.nav-underline li{padding-top:.2rem;padding-bottom:.2rem}.navbar-underline{background-color:#d5d5d5;border-top:1px solid #c8c8c8}pre{background-color:#fdf6e3;padding:1rem}.table-expand-col{min-width:100%}body{background-color:#373a3c}.card-success{background-color:#dff0d8;border-color:#d0e9c6;color:#3c763d}.card-success hr{border-top-color:#c1e2b3}.card-success .alert-link{color:#2b542c}.card-success .card-header{background-color:#d0e9c6;border-bottom:1px solid #c1e2b3}.card-info{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.card-info hr{border-top-color:#a6d5ec}.card-info .alert-link{color:#245269}.card-info .card-header{background-color:#c4e3f3;border-bottom:1px solid #afd9ee}.card-primary{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.card-primary hr{border-top-color:#a6d5ec}.card-primary .alert-link{color:#245269}.card-primary .card-header{background-color:#c4e3f3;border-bottom:1px solid #afd9ee}.card-warning{background-color:#fcf8e3;border-color:#faf2cc;color:#8a6d3b}.card-warning hr{border-top-color:#f7ecb5}.card-warning .alert-link{color:#66512c}.card-warning .card-header{background-color:#faf2cc;border-bottom:1px solid #f7ecb5}.card-danger{background-color:#f2dede;border-color:#ebcccc;color:#a94442}.card-danger hr{border-top-color:#e4b9b9}.card-danger .alert-link{color:#843534}.card-danger .card-header{background-color:#ebcccc;border-bottom:1px solid #e4b9b9}.masthead{background-image:linear-gradient(to bottom,#eee 0%,#ddd 100%);background-repeat:repeat-x;padding-top:10px;padding-bottom:10px}.subheader{background:#f3f3f3;border-bottom:1px solid #d5d5d5}.subheader .nav-tabs{margin-bottom:-1px}.footer{background-color:#373a3c}.bodycontent{background:#fff}.document-docutils>.section{padding-bottom:1rem}.document-docutils pre .comment{color:#586e75}.document-docutils pre .error,.document-docutils pre .generic{color:#93a1a1}.document-docutils pre .keyword{color:#859900}.document-docutils pre .literal,.document-docutils pre .name{color:#93a1a1}.document-docutils pre .operator{color:#859900}.document-docutils pre .other{color:#cb4b16}.document-docutils pre .punctuation{color:#93a1a1}.document-docutils pre .comment.multiline{color:#586e75}.document-docutils pre .comment.preproc{color:#859900}.document-docutils pre .comment.single{color:#586e75}.document-docutils pre .comment.special{color:#859900}.document-docutils pre .generic.deleted{color:#2aa198}.document-docutils pre .generic.emph{color:#93a1a1;font-style:italic}.document-docutils pre .generic.error{color:#dc322f}.document-docutils pre .generic.heading{color:#cb4b16}.document-docutils pre .generic.inserted{color:#859900}.document-docutils pre .generic.output,.document-docutils pre .generic.prompt{color:#93a1a1}.document-docutils pre .generic.strong{color:#93a1a1;font-weight:700}.document-docutils pre .generic.subheading{color:#cb4b16}.document-docutils pre .generic.traceback{color:#93a1a1}.document-docutils pre .keyword.constant{color:#cb4b16}.document-docutils pre .keyword.declaration{color:#268bd2}.document-docutils pre .keyword.namespace,.document-docutils pre .keyword.pseudo{color:#859900}.document-docutils pre .keyword.reserved{color:#268bd2}.document-docutils pre .keyword.type{color:#dc322f}.document-docutils pre .literal.date{color:#93a1a1}.document-docutils pre .literal.number,.document-docutils pre .literal.string{color:#2aa198}.document-docutils pre .name.attribute{color:#93a1a1}.document-docutils pre .name.builtin{color:#b58900}.document-docutils pre .name.class{color:#268bd2}.document-docutils pre .name.constant{color:#cb4b16}.document-docutils pre .name.decorator{color:#268bd2}.document-docutils pre .name.entity,.document-docutils pre .name.exception{color:#cb4b16}.document-docutils pre .name.function{color:#268bd2}.document-docutils pre .name.label,.document-docutils pre .name.namespace,.document-docutils pre .name.other,.document-docutils pre .name.property{color:#93a1a1}.document-docutils pre .name.tag,.document-docutils pre .name.variable{color:#268bd2}.document-docutils pre .operator.word{color:#859900}.document-docutils pre .text.whitespace{color:#93a1a1}.document-docutils pre .literal.number.float,.document-docutils pre .literal.number.hex,.document-docutils pre .literal.number.integer,.document-docutils pre .literal.number.oct{color:#2aa198}.document-docutils pre .literal.string.backtick{color:#586e75}.document-docutils pre .literal.string.char{color:#2aa198}.document-docutils pre .literal.string.doc{color:#93a1a1}.document-docutils pre .literal.string.double{color:#2aa198}.document-docutils pre .literal.string.escape{color:#cb4b16}.document-docutils pre .literal.string.heredoc{color:#93a1a1}.document-docutils pre .literal.string.interpol,.document-docutils pre .literal.string.other{color:#2aa198}.document-docutils pre .literal.string.regex{color:#dc322f}.document-docutils pre .literal.string.single,.document-docutils pre .literal.string.symbol{color:#2aa198}.document-docutils pre .name.builtin.pseudo,.document-docutils pre .name.variable.class,.document-docutils pre .name.variable.global,.document-docutils pre .name.variable.instance{color:#268bd2}.document-docutils pre .literal.number.integer.long{color:#2aa198}
\ No newline at end of file
+ */@media print{*,:after,:before{text-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]:after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}html{box-sizing:border-box;font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}*,:after,:before{box-sizing:inherit}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;text-decoration:underline dotted;cursor:help;border-bottom:0}address{font-style:normal;line-height:inherit}address,dl,ol,ul{margin-bottom:1rem}dl,ol,ul{margin-top:0}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]),a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input,label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;caption-side:bottom}caption,th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem}.display-1,.display-2{font-weight:300;line-height:1.1}.display-2{font-size:5.5rem}.display-3{font-size:4.5rem}.display-3,.display-4{font-weight:300;line-height:1.1}.display-4{font-size:3.5rem}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#868e96}.blockquote-footer:before{content:"\2014   \A0"}.img-fluid,.img-thumbnail{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #ddd;border-radius:.25rem;transition:all .2s ease-in-out}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#868e96}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}code{padding:.2rem .4rem;font-size:90%;color:#bd4147;background-color:#f8f9fa;border-radius:.25rem}a>code{padding:0;color:inherit;background-color:inherit}kbd{padding:.2rem .4rem;font-size:90%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;margin-top:0;margin-bottom:1rem;font-size:90%;color:#212529}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-right:15px;padding-left:15px;width:100%}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:45pc}}@media (min-width:992px){.container{max-width:60pc}}@media (min-width:1200px){.container{max-width:855pt}}.container-fluid{margin-right:auto;margin-left:auto;padding-right:15px;padding-left:15px;width:100%}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-auto,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-auto,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md-auto,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{flex-basis:0;flex-grow:1;max-width:100%}.col-auto{flex:0 0 auto;width:auto;max-width:none}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-auto{flex:0 0 auto;width:auto;max-width:none}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-auto{flex:0 0 auto;width:auto;max-width:none}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}}@media (min-width:992px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-auto{flex:0 0 auto;width:auto;max-width:none}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-auto{flex:0 0 auto;width:auto;max-width:none}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #e9ecef}.table thead th{vertical-align:bottom;border-bottom:2px solid #e9ecef}.table tbody+tbody{border-top:2px solid #e9ecef}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #e9ecef}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover,.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#dddfe2}.table-hover .table-secondary:hover,.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#cfd2d6}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover,.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover,.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th,.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.thead-inverse th{color:#fff;background-color:#212529}.thead-default th{color:#495057;background-color:#e9ecef}.table-inverse{color:#fff;background-color:#212529}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#32383e}.table-inverse.table-bordered{border:0}.table-inverse.table-striped tbody tr:nth-of-type(odd){background-color:hsla(0,0%,100%,.05)}.table-inverse.table-hover tbody tr:hover{background-color:hsla(0,0%,100%,.075)}@media (max-width:991px){.table-responsive{display:block;width:100%;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive.table-bordered{border:0}}.form-control{display:block;width:100%;padding:.5rem .75rem;font-size:1rem;line-height:1.25;color:#495057;background-color:#fff;background-image:none;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0}.form-control::placeholder{color:#868e96;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block}.col-form-label{margin-bottom:0}.col-form-label,.col-form-label-lg{padding-top:calc(.5rem - 1px * 2);padding-bottom:calc(.5rem - 1px * 2)}.col-form-label-lg{font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem - 1px * 2);padding-bottom:calc(.25rem - 1px * 2);font-size:.875rem}.col-form-legend{font-size:1rem}.col-form-legend,.form-control-plaintext{padding-top:.5rem;padding-bottom:.5rem;margin-bottom:0}.form-control-plaintext{line-height:1.25;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.form-control-plaintext.input-group-addon,.input-group-lg>.input-group-btn>.form-control-plaintext.btn,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.form-control-plaintext.input-group-addon,.input-group-sm>.input-group-btn>.form-control-plaintext.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),.input-group-sm>select.input-group-addon:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),.input-group-lg>select.input-group-addon:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.3125rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;margin-bottom:.5rem}.form-check.disabled .form-check-label{color:#868e96}.form-check-label{padding-left:1.25rem;margin-bottom:0}.form-check-input{position:absolute;margin-top:.25rem;margin-left:-1.25rem}.form-check-input:only-child{position:static}.form-check-inline{display:inline-block}.form-check-inline .form-check-label{vertical-align:middle}.form-check-inline+.form-check-inline{margin-left:.75rem}.invalid-feedback{display:none;margin-top:.25rem;font-size:.875rem;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;width:250px;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.invalid-feedback,.custom-select.is-valid~.invalid-tooltip,.form-control.is-valid~.invalid-feedback,.form-control.is-valid~.invalid-tooltip,.was-validated .custom-select:valid~.invalid-feedback,.was-validated .custom-select:valid~.invalid-tooltip,.was-validated .form-control:valid~.invalid-feedback,.was-validated .form-control:valid~.invalid-tooltip{display:block}.form-check-input.is-valid+.form-check-label,.was-validated .form-check-input:valid+.form-check-label{color:#28a745}.custom-control-input.is-valid~.custom-control-indicator,.was-validated .custom-control-input:valid~.custom-control-indicator{background-color:rgba(40,167,69,.25)}.custom-control-input.is-valid~.custom-control-description,.was-validated .custom-control-input:valid~.custom-control-description{color:#28a745}.custom-file-input.is-valid~.custom-file-control,.was-validated .custom-file-input:valid~.custom-file-control{border-color:#28a745}.custom-file-input.is-valid~.custom-file-control:before,.was-validated .custom-file-input:valid~.custom-file-control:before{border-color:inherit}.custom-file-input.is-valid:focus,.was-validated .custom-file-input:valid:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid+.form-check-label,.was-validated .form-check-input:invalid+.form-check-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-indicator,.was-validated .custom-control-input:invalid~.custom-control-indicator{background-color:rgba(220,53,69,.25)}.custom-control-input.is-invalid~.custom-control-description,.was-validated .custom-control-input:invalid~.custom-control-description{color:#dc3545}.custom-file-input.is-invalid~.custom-file-control,.was-validated .custom-file-input:invalid~.custom-file-control{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-control:before,.was-validated .custom-file-input:invalid~.custom-file-control:before{border-color:inherit}.custom-file-input.is-invalid:focus,.was-validated .custom-file-input:invalid:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{justify-content:center}.form-inline .form-group,.form-inline label{display:flex;align-items:center;margin-bottom:0}.form-inline .form-group{flex:0 0 auto;flex-flow:row wrap}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-control-label{margin-bottom:0;vertical-align:middle}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;margin-top:0;margin-bottom:0}.form-inline .form-check-label{padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{display:flex;align-items:center;justify-content:center;padding-left:0}.form-inline .custom-control-indicator{position:static;display:inline-block;margin-right:.25rem;vertical-align:text-bottom}.form-inline .has-feedback .form-control-feedback{top:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;user-select:none;border:1px solid transparent;padding:.5rem .75rem;font-size:1rem;line-height:1.25;border-radius:.25rem;transition:all .15s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 3px rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn.active,.btn:active{background-image:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 3px rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{background-color:#007bff;border-color:#007bff}.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{background-color:#0069d9;background-image:none;border-color:#0062cc}.btn-secondary{color:#fff;background-color:#868e96;border-color:#868e96}.btn-secondary:hover{color:#fff;background-color:#727b84;border-color:#6c757d}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 3px hsla(210,7%,56%,.5)}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#868e96;border-color:#868e96}.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{background-color:#727b84;background-image:none;border-color:#6c757d}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 3px rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{background-color:#28a745;border-color:#28a745}.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{background-color:#218838;background-image:none;border-color:#1e7e34}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 3px rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{background-color:#17a2b8;border-color:#17a2b8}.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{background-color:#138496;background-image:none;border-color:#117a8b}.btn-warning{color:#111;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#111;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 3px rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{background-color:#ffc107;border-color:#ffc107}.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{background-color:#e0a800;background-image:none;border-color:#d39e00}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 3px rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{background-color:#dc3545;border-color:#dc3545}.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{background-color:#c82333;background-image:none;border-color:#bd2130}.btn-light{color:#111;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#111;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 3px rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{background-color:#f8f9fa;border-color:#f8f9fa}.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{background-color:#e2e6ea;background-image:none;border-color:#dae0e5}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 3px rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{background-color:#343a40;border-color:#343a40}.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{background-color:#23272b;background-image:none;border-color:#1d2124}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 3px rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary.active,.btn-outline-primary:active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-secondary{color:#868e96;background-color:transparent;background-image:none;border-color:#868e96}.btn-outline-secondary:hover{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 3px hsla(210,7%,56%,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#868e96;background-color:transparent}.btn-outline-secondary.active,.btn-outline-secondary:active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 3px rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success.active,.btn-outline-success:active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 3px rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info.active,.btn-outline-info:active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 3px rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning.active,.btn-outline-warning:active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 3px rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger.active,.btn-outline-danger:active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 3px rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light.active,.btn-outline-light:active,.show>.btn-outline-light.dropdown-toggle{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 3px rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark.active,.btn-outline-dark:active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-link{font-weight:400;color:#007bff;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus{border-color:transparent;box-shadow:none}.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent}.btn-link:disabled{color:#868e96}.btn-link:disabled:focus,.btn-link:disabled:hover{text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{height:0;overflow:hidden;transition:height .35s ease}.collapsing,.dropdown,.dropup{position:relative}.dropdown-toggle:after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:empty:after{margin-left:0}.dropup .dropdown-menu{margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle:after{border-top:0;border-bottom:.3em solid}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background:none;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#868e96;background-color:transparent}.show>a{outline:0}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#868e96;white-space:nowrap}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:0 1 auto;margin-bottom:0}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn+.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.btn+.dropdown-toggle-split:after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{display:inline-flex;flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:flex;width:100%}.input-group .form-control{position:relative;z-index:2;flex:1 1 auto;width:1%;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover{z-index:3}.input-group .form-control,.input-group-addon,.input-group-btn{display:flex;align-items:center}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{white-space:nowrap;vertical-align:middle}.input-group-addon{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.25;color:#495057;text-align:center;background-color:#e9ecef;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:not(:last-child),.input-group-addon:not(:last-child),.input-group-btn:not(:first-child)>.btn-group:not(:last-child)>.btn,.input-group-btn:not(:first-child)>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group>.btn,.input-group-btn:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:not(:last-child){border-right:0}.input-group .form-control:not(:first-child),.input-group-addon:not(:first-child),.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group>.btn,.input-group-btn:not(:first-child)>.dropdown-toggle,.input-group-btn:not(:last-child)>.btn-group:not(:first-child)>.btn,.input-group-btn:not(:last-child)>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.form-control+.input-group-addon:not(:first-child){border-left:0}.input-group-btn{font-size:0;white-space:nowrap}.input-group-btn,.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group{margin-right:-1px}.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group{z-index:2;margin-left:-1px}.input-group-btn:not(:first-child)>.btn-group:active,.input-group-btn:not(:first-child)>.btn-group:focus,.input-group-btn:not(:first-child)>.btn-group:hover,.input-group-btn:not(:first-child)>.btn:active,.input-group-btn:not(:first-child)>.btn:focus,.input-group-btn:not(:first-child)>.btn:hover{z-index:3}.custom-control{position:relative;display:inline-flex;min-height:1.5rem;padding-left:1.5rem;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-indicator{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-indicator{box-shadow:0 0 0 1px #fff,0 0 0 3px #007bff}.custom-control-input:active~.custom-control-indicator{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-indicator{background-color:#e9ecef}.custom-control-input:disabled~.custom-control-description{color:#868e96}.custom-control-indicator{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;user-select:none;background-color:#ddd;background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-indicator{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-indicator{background-color:#007bff;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-radio .custom-control-indicator{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-controls-stacked{display:flex;flex-direction:column}.custom-controls-stacked .custom-control{margin-bottom:.25rem}.custom-controls-stacked .custom-control+.custom-control{margin-left:0}.custom-select{display:inline-block;max-width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.25;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select:disabled{color:#868e96;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-file{position:relative;display:inline-block;max-width:100%;height:2.5rem;margin-bottom:0}.custom-file-input{min-width:14rem;max-width:100%;height:2.5rem;margin:0;opacity:0}.custom-file-control{position:absolute;top:0;right:0;left:0;z-index:5;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#495057;pointer-events:none;user-select:none;background-color:#fff;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.custom-file-control:lang(en):empty:after{content:"Choose file..."}.custom-file-control:before{position:absolute;top:-1px;right:-1px;bottom:-1px;z-index:6;display:block;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#495057;background-color:#e9ecef;border:1px solid rgba(0,0,0,.15);border-radius:0 .25rem .25rem 0}.custom-file-control:lang(en):before{content:"Browse"}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#868e96}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #ddd}.nav-tabs .nav-link.disabled{color:#868e96;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#ddd #ddd #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.show>.nav-pills .nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;padding:.5rem 1rem}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm,.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex!important}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md,.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex!important}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg,.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex!important}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl,.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex!important}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{flex-direction:row;flex-wrap:nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex!important}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0,0,0,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-dark .navbar-brand,.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:hsla(0,0%,100%,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:hsla(0,0%,100%,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:hsla(0,0%,100%,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:hsla(0,0%,100%,.5);border-color:hsla(0,0%,100%,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255,255,255,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:hsla(0,0%,100%,.5)}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card-body{flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem}.card-subtitle,.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-bottom:-.75rem;border-bottom:0}.card-header-pills,.card-header-tabs{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}@media (min-width:576px){.card-deck{display:flex;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:flex;flex:1 0 0%;flex-direction:column;margin-right:15px;margin-left:15px}}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group .card{flex:1 0 0%}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child),.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{column-count:3;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb:after{display:block;clear:both;content:""}.breadcrumb-item{float:left}.breadcrumb-item+.breadcrumb-item:before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#868e96;content:"/"}.breadcrumb-item+.breadcrumb-item:hover:before{text-decoration:underline;text-decoration:none}.breadcrumb-item.active{color:#868e96}.pagination{display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#868e96;pointer-events:none;background-color:#fff;border-color:#ddd}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #ddd}.page-link:focus,.page-link:hover{color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#868e96}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#6c757d}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#111;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#111;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#111;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#111;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible .close{position:relative;top:-.75rem;right:-1.25rem;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#464a4e;background-color:#e7e8ea;border-color:#dddfe2}.alert-secondary hr{border-top-color:#cfd2d6}.alert-secondary .alert-link{color:#2e3133}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@keyframes progress-bar-stripes{0%{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;overflow:hidden;font-size:.75rem;line-height:1rem;text-align:center;background-color:#e9ecef;border-radius:.25rem}.progress-bar{height:1rem;line-height:1rem;color:#fff;background-color:#007bff;transition:width .6s ease}.progress-bar-striped{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 25%,transparent 50%,hsla(0,0%,100%,.15) 50%,hsla(0,0%,100%,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#868e96;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}a.list-group-item-primary,button.list-group-item-primary{color:#004085}a.list-group-item-primary:focus,a.list-group-item-primary:hover,button.list-group-item-primary:focus,button.list-group-item-primary:hover{color:#004085;background-color:#9fcdff}a.list-group-item-primary.active,button.list-group-item-primary.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#464a4e;background-color:#dddfe2}a.list-group-item-secondary,button.list-group-item-secondary{color:#464a4e}a.list-group-item-secondary:focus,a.list-group-item-secondary:hover,button.list-group-item-secondary:focus,button.list-group-item-secondary:hover{color:#464a4e;background-color:#cfd2d6}a.list-group-item-secondary.active,button.list-group-item-secondary.active{color:#fff;background-color:#464a4e;border-color:#464a4e}.list-group-item-success{color:#155724;background-color:#c3e6cb}a.list-group-item-success,button.list-group-item-success{color:#155724}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#155724;background-color:#b1dfbb}a.list-group-item-success.active,button.list-group-item-success.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}a.list-group-item-info,button.list-group-item-info{color:#0c5460}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#0c5460;background-color:#abdde5}a.list-group-item-info.active,button.list-group-item-info.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}a.list-group-item-warning,button.list-group-item-warning{color:#856404}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#856404;background-color:#ffe8a1}a.list-group-item-warning.active,button.list-group-item-warning.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}a.list-group-item-danger,button.list-group-item-danger{color:#721c24}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#721c24;background-color:#f1b0b7}a.list-group-item-danger.active,button.list-group-item-danger.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}a.list-group-item-light,button.list-group-item-light{color:#818182}a.list-group-item-light:focus,a.list-group-item-light:hover,button.list-group-item-light:focus,button.list-group-item-light:hover{color:#818182;background-color:#ececf6}a.list-group-item-light.active,button.list-group-item-light.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}a.list-group-item-dark,button.list-group-item-dark{color:#1b1e21}a.list-group-item-dark:focus,a.list-group-item-dark:hover,button.list-group-item-dark:focus,button.list-group-item-dark:hover{color:#1b1e21;background-color:#b9bbbe}a.list-group-item-dark.active,button.list-group-item-dark.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;opacity:.75}button.close{padding:0;background:transparent;border:0;-webkit-appearance:none}.modal,.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;outline:0}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -25%)}.modal.show .modal-dialog{transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;display:flex;flex-direction:column;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;align-items:center;justify-content:space-between;padding:15px;border-bottom:1px solid #e9ecef}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:15px}.modal-footer{display:flex;align-items:center;justify-content:flex-end;padding:15px;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:30px auto}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:50pc}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:5px;height:5px}.tooltip.bs-tooltip-auto[x-placement^=top],.tooltip.bs-tooltip-top{padding:5px 0}.tooltip.bs-tooltip-auto[x-placement^=top] .arrow,.tooltip.bs-tooltip-top .arrow{bottom:0}.tooltip.bs-tooltip-auto[x-placement^=top] .arrow:before,.tooltip.bs-tooltip-top .arrow:before{margin-left:-3px;content:"";border-width:5px 5px 0;border-top-color:#000}.tooltip.bs-tooltip-auto[x-placement^=right],.tooltip.bs-tooltip-right{padding:0 5px}.tooltip.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.bs-tooltip-right .arrow{left:0}.tooltip.bs-tooltip-auto[x-placement^=right] .arrow:before,.tooltip.bs-tooltip-right .arrow:before{margin-top:-3px;content:"";border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.bs-tooltip-auto[x-placement^=bottom],.tooltip.bs-tooltip-bottom{padding:5px 0}.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow,.tooltip.bs-tooltip-bottom .arrow{top:0}.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow:before,.tooltip.bs-tooltip-bottom .arrow:before{margin-left:-3px;content:"";border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bs-tooltip-auto[x-placement^=left],.tooltip.bs-tooltip-left{padding:0 5px}.tooltip.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.bs-tooltip-left .arrow{right:0}.tooltip.bs-tooltip-auto[x-placement^=left] .arrow:before,.tooltip.bs-tooltip-left .arrow:before{right:0;margin-top:-3px;content:"";border-width:5px 0 5px 5px;border-left-color:#000}.tooltip .arrow:before{position:absolute;border-color:transparent;border-style:solid}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{top:0;left:0;z-index:1060;max-width:276px;padding:1px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover,.popover .arrow{position:absolute;display:block}.popover .arrow{width:10px;height:5px}.popover .arrow:after,.popover .arrow:before{position:absolute;display:block;border-color:transparent;border-style:solid}.popover .arrow:after,.popover .arrow:before{content:"";border-width:11px}.popover.bs-popover-auto[x-placement^=top],.popover.bs-popover-top{margin-bottom:10px}.popover.bs-popover-auto[x-placement^=top] .arrow,.popover.bs-popover-top .arrow{bottom:0}.popover.bs-popover-auto[x-placement^=top] .arrow:after,.popover.bs-popover-auto[x-placement^=top] .arrow:before,.popover.bs-popover-top .arrow:after,.popover.bs-popover-top .arrow:before{border-bottom-width:0}.popover.bs-popover-auto[x-placement^=top] .arrow:before,.popover.bs-popover-top .arrow:before{bottom:-11px;margin-left:-6px;border-top-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=top] .arrow:after,.popover.bs-popover-top .arrow:after{bottom:-10px;margin-left:-6px;border-top-color:#fff}.popover.bs-popover-auto[x-placement^=right],.popover.bs-popover-right{margin-left:10px}.popover.bs-popover-auto[x-placement^=right] .arrow,.popover.bs-popover-right .arrow{left:0}.popover.bs-popover-auto[x-placement^=right] .arrow:after,.popover.bs-popover-auto[x-placement^=right] .arrow:before,.popover.bs-popover-right .arrow:after,.popover.bs-popover-right .arrow:before{margin-top:-8px;border-left-width:0}.popover.bs-popover-auto[x-placement^=right] .arrow:before,.popover.bs-popover-right .arrow:before{left:-11px;border-right-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=right] .arrow:after,.popover.bs-popover-right .arrow:after{left:-10px;border-right-color:#fff}.popover.bs-popover-auto[x-placement^=bottom],.popover.bs-popover-bottom{margin-top:10px}.popover.bs-popover-auto[x-placement^=bottom] .arrow,.popover.bs-popover-bottom .arrow{top:0}.popover.bs-popover-auto[x-placement^=bottom] .arrow:after,.popover.bs-popover-auto[x-placement^=bottom] .arrow:before,.popover.bs-popover-bottom .arrow:after,.popover.bs-popover-bottom .arrow:before{margin-left:-7px;border-top-width:0}.popover.bs-popover-auto[x-placement^=bottom] .arrow:before,.popover.bs-popover-bottom .arrow:before{top:-11px;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=bottom] .arrow:after,.popover.bs-popover-bottom .arrow:after{top:-10px;border-bottom-color:#fff}.popover.bs-popover-auto[x-placement^=bottom] .popover-header:before,.popover.bs-popover-bottom .popover-header:before{position:absolute;top:0;left:50%;display:block;width:20px;margin-left:-10px;content:"";border-bottom:1px solid #f7f7f7}.popover.bs-popover-auto[x-placement^=left],.popover.bs-popover-left{margin-right:10px}.popover.bs-popover-auto[x-placement^=left] .arrow,.popover.bs-popover-left .arrow{right:0}.popover.bs-popover-auto[x-placement^=left] .arrow:after,.popover.bs-popover-auto[x-placement^=left] .arrow:before,.popover.bs-popover-left .arrow:after,.popover.bs-popover-left .arrow:before{margin-top:-8px;border-right-width:0}.popover.bs-popover-auto[x-placement^=left] .arrow:before,.popover.bs-popover-left .arrow:before{right:-11px;border-left-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=left] .arrow:after,.popover.bs-popover-left .arrow:after{right:-10px;border-left-color:#fff}.popover-header{padding:8px 14px;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:9px 14px;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;align-items:center;width:100%;transition:transform .6s ease;backface-visibility:hidden;perspective:750pt}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translateX(0)}@supports (transform-style:preserve-3d){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{transform:translateX(100%)}@supports (transform-style:preserve-3d){.active.carousel-item-right,.carousel-item-next{transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{transform:translateX(-100%)}@supports (transform-style:preserve-3d){.active.carousel-item-left,.carousel-item-prev{transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:flex;align-items:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M4 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:hsla(0,0%,100%,.5)}.carousel-indicators li:before{top:-10px}.carousel-indicators li:after,.carousel-indicators li:before{position:absolute;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li:after{bottom:-10px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#868e96!important}a.bg-secondary:focus,a.bg-secondary:hover{background-color:#6c757d!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #e9ecef!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#868e96!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important}.rounded-right,.rounded-top{border-top-right-radius:.25rem!important}.rounded-bottom,.rounded-right{border-bottom-right-radius:.25rem!important}.rounded-bottom,.rounded-left{border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important}.rounded-circle{border-radius:50%}.rounded-0{border-radius:0}.clearfix:after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}.d-print-block{display:none!important}@media print{.d-print-block{display:block!important}}.d-print-inline{display:none!important}@media print{.d-print-inline{display:inline!important}}.d-print-inline-block{display:none!important}@media print{.d-print-inline-block{display:inline-block!important}}@media print{.d-print-none{display:none!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive:before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9:before{padding-top:42.85714%}.embed-responsive-16by9:before{padding-top:56.25%}.embed-responsive-4by3:before{padding-top:75%}.embed-responsive-1by1:before{padding-top:100%}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:576px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.fixed-top{top:0}.fixed-bottom,.fixed-top{position:fixed;right:0;left:0;z-index:1030}.fixed-bottom{bottom:0}@supports (position:sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;clip-path:none}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.mx-0{margin-right:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.25rem!important}.mt-1{margin-top:.25rem!important}.mr-1{margin-right:.25rem!important}.mb-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.mx-1{margin-right:.25rem!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-2{margin:.5rem!important}.mt-2{margin-top:.5rem!important}.mr-2{margin-right:.5rem!important}.mb-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.mx-2{margin-right:.5rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-3{margin:1rem!important}.mt-3{margin-top:1rem!important}.mr-3{margin-right:1rem!important}.mb-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.mx-3{margin-right:1rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-4{margin:1.5rem!important}.mt-4{margin-top:1.5rem!important}.mr-4{margin-right:1.5rem!important}.mb-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.mx-4{margin-right:1.5rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-5{margin:3rem!important}.mt-5{margin-top:3rem!important}.mr-5{margin-right:3rem!important}.mb-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.mx-5{margin-right:3rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.px-0{padding-right:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.25rem!important}.pt-1{padding-top:.25rem!important}.pr-1{padding-right:.25rem!important}.pb-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.px-1{padding-right:.25rem!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-2{padding:.5rem!important}.pt-2{padding-top:.5rem!important}.pr-2{padding-right:.5rem!important}.pb-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.px-2{padding-right:.5rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-3{padding:1rem!important}.pt-3{padding-top:1rem!important}.pr-3{padding-right:1rem!important}.pb-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.px-3{padding-right:1rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-4{padding:1.5rem!important}.pt-4{padding-top:1.5rem!important}.pr-4{padding-right:1.5rem!important}.pb-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.px-4{padding-right:1.5rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-5{padding:3rem!important}.pt-5{padding-top:3rem!important}.pr-5{padding-right:3rem!important}.pb-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.px-5{padding-right:3rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-auto{margin:auto!important}.mt-auto{margin-top:auto!important}.mr-auto{margin-right:auto!important}.mb-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}.mx-auto{margin-right:auto!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0{margin-top:0!important}.mr-sm-0{margin-right:0!important}.mb-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.mx-sm-0{margin-right:0!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1{margin-top:.25rem!important}.mr-sm-1{margin-right:.25rem!important}.mb-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.mx-sm-1{margin-right:.25rem!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2{margin-top:.5rem!important}.mr-sm-2{margin-right:.5rem!important}.mb-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.mx-sm-2{margin-right:.5rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3{margin-top:1rem!important}.mr-sm-3{margin-right:1rem!important}.mb-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.mx-sm-3{margin-right:1rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4{margin-top:1.5rem!important}.mr-sm-4{margin-right:1.5rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.mx-sm-4{margin-right:1.5rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5{margin-top:3rem!important}.mr-sm-5{margin-right:3rem!important}.mb-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.mx-sm-5{margin-right:3rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0{padding-top:0!important}.pr-sm-0{padding-right:0!important}.pb-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.px-sm-0{padding-right:0!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1{padding-top:.25rem!important}.pr-sm-1{padding-right:.25rem!important}.pb-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.px-sm-1{padding-right:.25rem!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2{padding-top:.5rem!important}.pr-sm-2{padding-right:.5rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.px-sm-2{padding-right:.5rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3{padding-top:1rem!important}.pr-sm-3{padding-right:1rem!important}.pb-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.px-sm-3{padding-right:1rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4{padding-top:1.5rem!important}.pr-sm-4{padding-right:1.5rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.px-sm-4{padding-right:1.5rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5{padding-top:3rem!important}.pr-sm-5{padding-right:3rem!important}.pb-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.px-sm-5{padding-right:3rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto{margin-top:auto!important}.mr-sm-auto{margin-right:auto!important}.mb-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}.mx-sm-auto{margin-right:auto!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0{margin-top:0!important}.mr-md-0{margin-right:0!important}.mb-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.mx-md-0{margin-right:0!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.m-md-1{margin:.25rem!important}.mt-md-1{margin-top:.25rem!important}.mr-md-1{margin-right:.25rem!important}.mb-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.mx-md-1{margin-right:.25rem!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2{margin-top:.5rem!important}.mr-md-2{margin-right:.5rem!important}.mb-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.mx-md-2{margin-right:.5rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3{margin-top:1rem!important}.mr-md-3{margin-right:1rem!important}.mb-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.mx-md-3{margin-right:1rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4{margin-top:1.5rem!important}.mr-md-4{margin-right:1.5rem!important}.mb-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.mx-md-4{margin-right:1.5rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5{margin-top:3rem!important}.mr-md-5{margin-right:3rem!important}.mb-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.mx-md-5{margin-right:3rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-md-0{padding:0!important}.pt-md-0{padding-top:0!important}.pr-md-0{padding-right:0!important}.pb-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.px-md-0{padding-right:0!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.p-md-1{padding:.25rem!important}.pt-md-1{padding-top:.25rem!important}.pr-md-1{padding-right:.25rem!important}.pb-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.px-md-1{padding-right:.25rem!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2{padding-top:.5rem!important}.pr-md-2{padding-right:.5rem!important}.pb-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.px-md-2{padding-right:.5rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3{padding-top:1rem!important}.pr-md-3{padding-right:1rem!important}.pb-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.px-md-3{padding-right:1rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4{padding-top:1.5rem!important}.pr-md-4{padding-right:1.5rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.px-md-4{padding-right:1.5rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5{padding-top:3rem!important}.pr-md-5{padding-right:3rem!important}.pb-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.px-md-5{padding-right:3rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto{margin-top:auto!important}.mr-md-auto{margin-right:auto!important}.mb-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}.mx-md-auto{margin-right:auto!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0{margin-top:0!important}.mr-lg-0{margin-right:0!important}.mb-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.mx-lg-0{margin-right:0!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1{margin-top:.25rem!important}.mr-lg-1{margin-right:.25rem!important}.mb-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.mx-lg-1{margin-right:.25rem!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2{margin-top:.5rem!important}.mr-lg-2{margin-right:.5rem!important}.mb-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.mx-lg-2{margin-right:.5rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3{margin-top:1rem!important}.mr-lg-3{margin-right:1rem!important}.mb-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.mx-lg-3{margin-right:1rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4{margin-top:1.5rem!important}.mr-lg-4{margin-right:1.5rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.mx-lg-4{margin-right:1.5rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5{margin-top:3rem!important}.mr-lg-5{margin-right:3rem!important}.mb-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.mx-lg-5{margin-right:3rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0{padding-top:0!important}.pr-lg-0{padding-right:0!important}.pb-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.px-lg-0{padding-right:0!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1{padding-top:.25rem!important}.pr-lg-1{padding-right:.25rem!important}.pb-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.px-lg-1{padding-right:.25rem!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2{padding-top:.5rem!important}.pr-lg-2{padding-right:.5rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.px-lg-2{padding-right:.5rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3{padding-top:1rem!important}.pr-lg-3{padding-right:1rem!important}.pb-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.px-lg-3{padding-right:1rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4{padding-top:1.5rem!important}.pr-lg-4{padding-right:1.5rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.px-lg-4{padding-right:1.5rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5{padding-top:3rem!important}.pr-lg-5{padding-right:3rem!important}.pb-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.px-lg-5{padding-right:3rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto{margin-top:auto!important}.mr-lg-auto{margin-right:auto!important}.mb-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}.mx-lg-auto{margin-right:auto!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0{margin-top:0!important}.mr-xl-0{margin-right:0!important}.mb-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.mx-xl-0{margin-right:0!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1{margin-top:.25rem!important}.mr-xl-1{margin-right:.25rem!important}.mb-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.mx-xl-1{margin-right:.25rem!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2{margin-top:.5rem!important}.mr-xl-2{margin-right:.5rem!important}.mb-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.mx-xl-2{margin-right:.5rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3{margin-top:1rem!important}.mr-xl-3{margin-right:1rem!important}.mb-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.mx-xl-3{margin-right:1rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4{margin-top:1.5rem!important}.mr-xl-4{margin-right:1.5rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.mx-xl-4{margin-right:1.5rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5{margin-top:3rem!important}.mr-xl-5{margin-right:3rem!important}.mb-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.mx-xl-5{margin-right:3rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0{padding-top:0!important}.pr-xl-0{padding-right:0!important}.pb-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.px-xl-0{padding-right:0!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1{padding-top:.25rem!important}.pr-xl-1{padding-right:.25rem!important}.pb-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.px-xl-1{padding-right:.25rem!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2{padding-top:.5rem!important}.pr-xl-2{padding-right:.5rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.px-xl-2{padding-right:.5rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3{padding-top:1rem!important}.pr-xl-3{padding-right:1rem!important}.pb-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.px-xl-3{padding-right:1rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4{padding-top:1.5rem!important}.pr-xl-4{padding-right:1.5rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.px-xl-4{padding-right:1.5rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5{padding-top:3rem!important}.pr-xl-5{padding-right:3rem!important}.pb-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.px-xl-5{padding-right:3rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto{margin-top:auto!important}.mr-xl-auto{margin-right:auto!important}.mb-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}.mx-xl-auto{margin-right:auto!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#868e96!important}a.text-secondary:focus,a.text-secondary:hover{color:#6c757d!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-muted{color:#868e96!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.container-narrow{margin-right:auto;margin-left:auto;padding-right:15px;padding-left:15px;width:100%}@media (min-width:576px){.container-narrow{max-width:34rem}}@media (min-width:768px){.container-narrow{max-width:45rem}}@media (min-width:992px){.container-narrow{max-width:45rem}}@media (min-width:1200px){.container-narrow{max-width:45rem}}.nav-underline .nav-item.active,.nav-underline .nav-item.active:hover{box-shadow:0 -3px 0 0 #007bff inset}.nav-underline .nav-item.active .nav-link,.nav-underline .nav-item.active:hover .nav-link{color:#007bff}.nav-underline li:hover{box-shadow:0 -3px 0 0 #ddd inset}.nav-underline li{padding-top:.2rem;padding-bottom:.2rem}.navbar-underline{background-color:#d5d5d5;border-top:1px solid #c8c8c8}pre{background-color:#fdf6e3;padding:1rem}.table-expand-col{min-width:100%}body{background-color:#495057}.masthead{background-image:linear-gradient(to bottom,#eee 0%,#ddd 100%);background-repeat:repeat-x;padding-top:10px;padding-bottom:10px}.subheader{background:#f8f9fa;border-bottom:1px solid #dee2e6}.subheader .nav-tabs{margin-bottom:-1px}.footer{background-color:#495057}.bodycontent{background:#fff}.document-docutils>.section{padding-bottom:1rem}.document-docutils pre .comment{color:#586e75}.document-docutils pre .error,.document-docutils pre .generic{color:#93a1a1}.document-docutils pre .keyword{color:#859900}.document-docutils pre .literal,.document-docutils pre .name{color:#93a1a1}.document-docutils pre .operator{color:#859900}.document-docutils pre .other{color:#cb4b16}.document-docutils pre .punctuation{color:#93a1a1}.document-docutils pre .comment.multiline{color:#586e75}.document-docutils pre .comment.preproc{color:#859900}.document-docutils pre .comment.single{color:#586e75}.document-docutils pre .comment.special{color:#859900}.document-docutils pre .generic.deleted{color:#2aa198}.document-docutils pre .generic.emph{color:#93a1a1;font-style:italic}.document-docutils pre .generic.error{color:#dc322f}.document-docutils pre .generic.heading{color:#cb4b16}.document-docutils pre .generic.inserted{color:#859900}.document-docutils pre .generic.output,.document-docutils pre .generic.prompt{color:#93a1a1}.document-docutils pre .generic.strong{color:#93a1a1;font-weight:700}.document-docutils pre .generic.subheading{color:#cb4b16}.document-docutils pre .generic.traceback{color:#93a1a1}.document-docutils pre .keyword.constant{color:#cb4b16}.document-docutils pre .keyword.declaration{color:#268bd2}.document-docutils pre .keyword.namespace,.document-docutils pre .keyword.pseudo{color:#859900}.document-docutils pre .keyword.reserved{color:#268bd2}.document-docutils pre .keyword.type{color:#dc322f}.document-docutils pre .literal.date{color:#93a1a1}.document-docutils pre .literal.number,.document-docutils pre .literal.string{color:#2aa198}.document-docutils pre .name.attribute{color:#93a1a1}.document-docutils pre .name.builtin{color:#b58900}.document-docutils pre .name.class{color:#268bd2}.document-docutils pre .name.constant{color:#cb4b16}.document-docutils pre .name.decorator{color:#268bd2}.document-docutils pre .name.entity,.document-docutils pre .name.exception{color:#cb4b16}.document-docutils pre .name.function{color:#268bd2}.document-docutils pre .name.label,.document-docutils pre .name.namespace,.document-docutils pre .name.other,.document-docutils pre .name.property{color:#93a1a1}.document-docutils pre .name.tag,.document-docutils pre .name.variable{color:#268bd2}.document-docutils pre .operator.word{color:#859900}.document-docutils pre .text.whitespace{color:#93a1a1}.document-docutils pre .literal.number.float,.document-docutils pre .literal.number.hex,.document-docutils pre .literal.number.integer,.document-docutils pre .literal.number.oct{color:#2aa198}.document-docutils pre .literal.string.backtick{color:#586e75}.document-docutils pre .literal.string.char{color:#2aa198}.document-docutils pre .literal.string.doc{color:#93a1a1}.document-docutils pre .literal.string.double{color:#2aa198}.document-docutils pre .literal.string.escape{color:#cb4b16}.document-docutils pre .literal.string.heredoc{color:#93a1a1}.document-docutils pre .literal.string.interpol,.document-docutils pre .literal.string.other{color:#2aa198}.document-docutils pre .literal.string.regex{color:#dc322f}.document-docutils pre .literal.string.single,.document-docutils pre .literal.string.symbol{color:#2aa198}.document-docutils pre .name.builtin.pseudo,.document-docutils pre .name.variable.class,.document-docutils pre .name.variable.global,.document-docutils pre .name.variable.instance{color:#268bd2}.document-docutils pre .literal.number.integer.long{color:#2aa198}
\ No newline at end of file
diff --git a/hubs/static/fedora-bootstrap/fedora-bootstrap.min.js b/hubs/static/fedora-bootstrap/fedora-bootstrap.min.js
index 3624839..b4810a7 100644
--- a/hubs/static/fedora-bootstrap/fedora-bootstrap.min.js
+++ b/hubs/static/fedora-bootstrap/fedora-bootstrap.min.js
@@ -1,8 +1,6 @@
-!function(t){function e(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return t[i].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";n(1),n(2),n(3)},function(t,e,n){var i,o;/*! tether 1.4.0 */
-!function(r,s){i=s,o="function"==typeof i?i.call(e,n,e,t):i,!(void 0!==o&&(t.exports=o))}(this,function(t,e,n){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t){var e=t.getBoundingClientRect(),n={};for(var i in e)n[i]=e[i];if(t.ownerDocument!==document){var r=t.ownerDocument.defaultView.frameElement;if(r){var s=o(r);n.top+=s.top,n.bottom+=s.top,n.left+=s.left,n.right+=s.left}}return n}function r(t){var e=getComputedStyle(t)||{},n=e.position,i=[];if("fixed"===n)return[t];for(var o=t;(o=o.parentNode)&&o&&1===o.nodeType;){var r=void 0;try{r=getComputedStyle(o)}catch(t){}if("undefined"==typeof r||null===r)return i.push(o),i;var s=r,a=s.overflow,l=s.overflowX,h=s.overflowY;/(auto|scroll)/.test(a+h+l)&&("absolute"!==n||["relative","absolute","fixed"].indexOf(r.position)>=0)&&i.push(o)}return i.push(t.ownerDocument.body),t.ownerDocument!==document&&i.push(t.ownerDocument.defaultView),i}function s(){b&&document.body.removeChild(b),b=null}function a(t){var e=void 0;t===document?(e=document,t=document.documentElement):e=t.ownerDocument;var n=e.documentElement,i=o(t),r=D();return i.top-=r.top,i.left-=r.left,"undefined"==typeof i.width&&(i.width=document.body.scrollWidth-i.left-i.right),"undefined"==typeof i.height&&(i.height=document.body.scrollHeight-i.top-i.bottom),i.top=i.top-n.clientTop,i.left=i.left-n.clientLeft,i.right=e.body.clientWidth-i.width-i.left,i.bottom=e.body.clientHeight-i.height-i.top,i}function l(t){return t.offsetParent||document.documentElement}function h(){if(w)return w;var t=document.createElement("div");t.style.width="100%",t.style.height="200px";var e=document.createElement("div");f(e.style,{position:"absolute",top:0,left:0,pointerEvents:"none",visibility:"hidden",width:"200px",height:"150px",overflow:"hidden"}),e.appendChild(t),document.body.appendChild(e);var n=t.offsetWidth;e.style.overflow="scroll";var i=t.offsetWidth;n===i&&(i=e.clientWidth),document.body.removeChild(e);var o=n-i;return w={width:o,height:o}}function f(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],e=[];return Array.prototype.push.apply(e,arguments),e.slice(1).forEach(function(e){if(e)for(var n in e)({}).hasOwnProperty.call(e,n)&&(t[n]=e[n])}),t}function u(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.remove(e)});else{var n=new RegExp("(^| )"+e.split(" ").join("|")+"( |$)","gi"),i=p(t).replace(n," ");g(t,i)}}function c(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.add(e)});else{u(t,e);var n=p(t)+(" "+e);g(t,n)}}function d(t,e){if("undefined"!=typeof t.classList)return t.classList.contains(e);var n=p(t);return new RegExp("(^| )"+e+"( |$)","gi").test(n)}function p(t){return t.className instanceof t.ownerDocument.defaultView.SVGAnimatedString?t.className.baseVal:t.className}function g(t,e){t.setAttribute("class",e)}function m(t,e,n){n.forEach(function(n){e.indexOf(n)===-1&&d(t,n)&&u(t,n)}),e.forEach(function(e){d(t,e)||c(t,e)})}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function _(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function v(t,e){var n=arguments.length<=2||void 0===arguments[2]?1:arguments[2];return t+n>=e&&e>=t-n}function E(){return"undefined"!=typeof performance&&"undefined"!=typeof performance.now?performance.now():+new Date}function y(){for(var t={top:0,left:0},e=arguments.length,n=Array(e),i=0;i<e;i++)n[i]=arguments[i];return n.forEach(function(e){var n=e.top,i=e.left;"string"==typeof n&&(n=parseFloat(n,10)),"string"==typeof i&&(i=parseFloat(i,10)),t.top+=n,t.left+=i}),t}function T(t,e){return"string"==typeof t.left&&t.left.indexOf("%")!==-1&&(t.left=parseFloat(t.left,10)/100*e.width),"string"==typeof t.top&&t.top.indexOf("%")!==-1&&(t.top=parseFloat(t.top,10)/100*e.height),t}function C(t,e){return"scrollParent"===e?e=t.scrollParents[0]:"window"===e&&(e=[pageXOffset,pageYOffset,innerWidth+pageXOffset,innerHeight+pageYOffset]),e===document&&(e=e.documentElement),"undefined"!=typeof e.nodeType&&!function(){var t=e,n=a(e),i=n,o=getComputedStyle(e);if(e=[i.left,i.top,n.width+i.left,n.height+i.top],t.ownerDocument!==document){var r=t.ownerDocument.defaultView;e[0]+=r.pageXOffset,e[1]+=r.pageYOffset,e[2]+=r.pageXOffset,e[3]+=r.pageYOffset}z.forEach(function(t,n){t=t[0].toUpperCase()+t.substr(1),"Top"===t||"Left"===t?e[n]+=parseFloat(o["border"+t+"Width"]):e[n]-=parseFloat(o["border"+t+"Width"])})}(),e}var A=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),O=void 0;"undefined"==typeof O&&(O={modules:[]});var b=null,I=function(){var t=0;return function(){return++t}}(),S={},D=function(){var t=b;t&&document.body.contains(t)||(t=document.createElement("div"),t.setAttribute("data-tether-id",I()),f(t.style,{top:0,left:0,position:"absolute"}),document.body.appendChild(t),b=t);var e=t.getAttribute("data-tether-id");return"undefined"==typeof S[e]&&(S[e]=o(t),L(function(){delete S[e]})),S[e]},w=null,N=[],L=function(t){N.push(t)},P=function(){for(var t=void 0;t=N.pop();)t()},H=function(){function t(){i(this,t)}return A(t,[{key:"on",value:function(t,e,n){var i=!(arguments.length<=3||void 0===arguments[3])&&arguments[3];"undefined"==typeof this.bindings&&(this.bindings={}),"undefined"==typeof this.bindings[t]&&(this.bindings[t]=[]),this.bindings[t].push({handler:e,ctx:n,once:i})}},{key:"once",value:function(t,e,n){this.on(t,e,n,!0)}},{key:"off",value:function(t,e){if("undefined"!=typeof this.bindings&&"undefined"!=typeof this.bindings[t])if("undefined"==typeof e)delete this.bindings[t];else for(var n=0;n<this.bindings[t].length;)this.bindings[t][n].handler===e?this.bindings[t].splice(n,1):++n}},{key:"trigger",value:function(t){if("undefined"!=typeof this.bindings&&this.bindings[t]){for(var e=0,n=arguments.length,i=Array(n>1?n-1:0),o=1;o<n;o++)i[o-1]=arguments[o];for(;e<this.bindings[t].length;){var r=this.bindings[t][e],s=r.handler,a=r.ctx,l=r.once,h=a;"undefined"==typeof h&&(h=this),s.apply(h,i),l?this.bindings[t].splice(e,1):++e}}}}]),t}();O.Utils={getActualBoundingClientRect:o,getScrollParents:r,getBounds:a,getOffsetParent:l,extend:f,addClass:c,removeClass:u,hasClass:d,updateClasses:m,defer:L,flush:P,uniqueId:I,Evented:H,getScrollBarSize:h,removeUtilElements:s};var k=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{!i&&a.return&&a.return()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),A=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),W=function(t,e,n){for(var i=!0;i;){var o=t,r=e,s=n;i=!1,null===o&&(o=Function.prototype);var a=Object.getOwnPropertyDescriptor(o,r);if(void 0!==a){if("value"in a)return a.value;var l=a.get;if(void 0===l)return;return l.call(s)}var h=Object.getPrototypeOf(o);if(null===h)return;t=h,e=r,n=s,i=!0,a=h=void 0}};if("undefined"==typeof O)throw new Error("You must include the utils.js file before tether.js");var R=O.Utils,r=R.getScrollParents,a=R.getBounds,l=R.getOffsetParent,f=R.extend,c=R.addClass,u=R.removeClass,m=R.updateClasses,L=R.defer,P=R.flush,h=R.getScrollBarSize,s=R.removeUtilElements,x=function(){if("undefined"==typeof document)return"";for(var t=document.createElement("div"),e=["transform","WebkitTransform","OTransform","MozTransform","msTransform"],n=0;n<e.length;++n){var i=e[n];if(void 0!==t.style[i])return i}}(),M=[],V=function(){M.forEach(function(t){t.position(!1)}),P()};!function(){var t=null,e=null,n=null,i=function i(){return"undefined"!=typeof e&&e>16?(e=Math.min(e-16,250),void(n=setTimeout(i,250))):void("undefined"!=typeof t&&E()-t<10||(null!=n&&(clearTimeout(n),n=null),t=E(),V(),e=E()-t))};"undefined"!=typeof window&&"undefined"!=typeof window.addEventListener&&["resize","scroll","touchmove"].forEach(function(t){window.addEventListener(t,i)})}();var j={center:"center",left:"right",right:"left"},F={middle:"middle",top:"bottom",bottom:"top"},U={top:0,left:0,middle:"50%",center:"50%",bottom:"100%",right:"100%"},B=function(t,e){var n=t.left,i=t.top;return"auto"===n&&(n=j[e.left]),"auto"===i&&(i=F[e.top]),{left:n,top:i}},K=function(t){var e=t.left,n=t.top;return"undefined"!=typeof U[t.left]&&(e=U[t.left]),"undefined"!=typeof U[t.top]&&(n=U[t.top]),{left:e,top:n}},G=function(t){var e=t.split(" "),n=k(e,2),i=n[0],o=n[1];return{top:i,left:o}},Q=G,Y=function(t){function e(t){var n=this;i(this,e),W(Object.getPrototypeOf(e.prototype),"constructor",this).call(this),this.position=this.position.bind(this),M.push(this),this.history=[],this.setOptions(t,!1),O.modules.forEach(function(t){"undefined"!=typeof t.initialize&&t.initialize.call(n)}),this.position()}return _(e,t),A(e,[{key:"getClass",value:function(){var t=arguments.length<=0||void 0===arguments[0]?"":arguments[0],e=this.options.classes;return"undefined"!=typeof e&&e[t]?this.options.classes[t]:this.options.classPrefix?this.options.classPrefix+"-"+t:t}},{key:"setOptions",value:function(t){var e=this,n=arguments.length<=1||void 0===arguments[1]||arguments[1],i={offset:"0 0",targetOffset:"0 0",targetAttachment:"auto auto",classPrefix:"tether"};this.options=f(i,t);var o=this.options,s=o.element,a=o.target,l=o.targetModifier;if(this.element=s,this.target=a,this.targetModifier=l,"viewport"===this.target?(this.target=document.body,this.targetModifier="visible"):"scroll-handle"===this.target&&(this.target=document.body,this.targetModifier="scroll-handle"),["element","target"].forEach(function(t){if("undefined"==typeof e[t])throw new Error("Tether Error: Both element and target must be defined");"undefined"!=typeof e[t].jquery?e[t]=e[t][0]:"string"==typeof e[t]&&(e[t]=document.querySelector(e[t]))}),c(this.element,this.getClass("element")),this.options.addTargetClasses!==!1&&c(this.target,this.getClass("target")),!this.options.attachment)throw new Error("Tether Error: You must provide an attachment");this.targetAttachment=Q(this.options.targetAttachment),this.attachment=Q(this.options.attachment),this.offset=G(this.options.offset),this.targetOffset=G(this.options.targetOffset),"undefined"!=typeof this.scrollParents&&this.disable(),"scroll-handle"===this.targetModifier?this.scrollParents=[this.target]:this.scrollParents=r(this.target),this.options.enabled!==!1&&this.enable(n)}},{key:"getTargetBounds",value:function(){if("undefined"==typeof this.targetModifier)return a(this.target);if("visible"===this.targetModifier){if(this.target===document.body)return{top:pageYOffset,left:pageXOffset,height:innerHeight,width:innerWidth};var t=a(this.target),e={height:t.height,width:t.width,top:t.top,left:t.left};return e.height=Math.min(e.height,t.height-(pageYOffset-t.top)),e.height=Math.min(e.height,t.height-(t.top+t.height-(pageYOffset+innerHeight))),e.height=Math.min(innerHeight,e.height),e.height-=2,e.width=Math.min(e.width,t.width-(pageXOffset-t.left)),e.width=Math.min(e.width,t.width-(t.left+t.width-(pageXOffset+innerWidth))),e.width=Math.min(innerWidth,e.width),e.width-=2,e.top<pageYOffset&&(e.top=pageYOffset),e.left<pageXOffset&&(e.left=pageXOffset),e}if("scroll-handle"===this.targetModifier){var t=void 0,n=this.target;n===document.body?(n=document.documentElement,t={left:pageXOffset,top:pageYOffset,height:innerHeight,width:innerWidth}):t=a(n);var i=getComputedStyle(n),o=n.scrollWidth>n.clientWidth||[i.overflow,i.overflowX].indexOf("scroll")>=0||this.target!==document.body,r=0;o&&(r=15);var s=t.height-parseFloat(i.borderTopWidth)-parseFloat(i.borderBottomWidth)-r,e={width:15,height:.975*s*(s/n.scrollHeight),left:t.left+t.width-parseFloat(i.borderLeftWidth)-15},l=0;s<408&&this.target===document.body&&(l=-11e-5*Math.pow(s,2)-.00727*s+22.58),this.target!==document.body&&(e.height=Math.max(e.height,24));var h=this.target.scrollTop/(n.scrollHeight-s);return e.top=h*(s-e.height-l)+t.top+parseFloat(i.borderTopWidth),this.target===document.body&&(e.height=Math.max(e.height,24)),e}}},{key:"clearCache",value:function(){this._cache={}}},{key:"cache",value:function(t,e){return"undefined"==typeof this._cache&&(this._cache={}),"undefined"==typeof this._cache[t]&&(this._cache[t]=e.call(this)),this._cache[t]}},{key:"enable",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]||arguments[0];this.options.addTargetClasses!==!1&&c(this.target,this.getClass("enabled")),c(this.element,this.getClass("enabled")),this.enabled=!0,this.scrollParents.forEach(function(e){e!==t.target.ownerDocument&&e.addEventListener("scroll",t.position)}),e&&this.position()}},{key:"disable",value:function(){var t=this;u(this.target,this.getClass("enabled")),u(this.element,this.getClass("enabled")),this.enabled=!1,"undefined"!=typeof this.scrollParents&&this.scrollParents.forEach(function(e){e.removeEventListener("scroll",t.position)})}},{key:"destroy",value:function(){var t=this;this.disable(),M.forEach(function(e,n){e===t&&M.splice(n,1)}),0===M.length&&s()}},{key:"updateAttachClasses",value:function(t,e){var n=this;t=t||this.attachment,e=e||this.targetAttachment;var i=["left","top","bottom","right","middle","center"];"undefined"!=typeof this._addAttachClasses&&this._addAttachClasses.length&&this._addAttachClasses.splice(0,this._addAttachClasses.length),"undefined"==typeof this._addAttachClasses&&(this._addAttachClasses=[]);var o=this._addAttachClasses;t.top&&o.push(this.getClass("element-attached")+"-"+t.top),t.left&&o.push(this.getClass("element-attached")+"-"+t.left),e.top&&o.push(this.getClass("target-attached")+"-"+e.top),e.left&&o.push(this.getClass("target-attached")+"-"+e.left);var r=[];i.forEach(function(t){r.push(n.getClass("element-attached")+"-"+t),r.push(n.getClass("target-attached")+"-"+t)}),L(function(){"undefined"!=typeof n._addAttachClasses&&(m(n.element,n._addAttachClasses,r),n.options.addTargetClasses!==!1&&m(n.target,n._addAttachClasses,r),delete n._addAttachClasses)})}},{key:"position",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]||arguments[0];if(this.enabled){this.clearCache();var n=B(this.targetAttachment,this.attachment);this.updateAttachClasses(this.attachment,n);var i=this.cache("element-bounds",function(){return a(t.element)}),o=i.width,r=i.height;if(0===o&&0===r&&"undefined"!=typeof this.lastSize){var s=this.lastSize;o=s.width,r=s.height}else this.lastSize={width:o,height:r};var f=this.cache("target-bounds",function(){return t.getTargetBounds()}),u=f,c=T(K(this.attachment),{width:o,height:r}),d=T(K(n),u),p=T(this.offset,{width:o,height:r}),g=T(this.targetOffset,u);c=y(c,p),d=y(d,g);for(var m=f.left+d.left-c.left,_=f.top+d.top-c.top,v=0;v<O.modules.length;++v){var E=O.modules[v],C=E.position.call(this,{left:m,top:_,targetAttachment:n,targetPos:f,elementPos:i,offset:c,targetOffset:d,manualOffset:p,manualTargetOffset:g,scrollbarSize:S,attachment:this.attachment});if(C===!1)return!1;"undefined"!=typeof C&&"object"==typeof C&&(_=C.top,m=C.left)}var A={page:{top:_,left:m},viewport:{top:_-pageYOffset,bottom:pageYOffset-_-r+innerHeight,left:m-pageXOffset,right:pageXOffset-m-o+innerWidth}},b=this.target.ownerDocument,I=b.defaultView,S=void 0;return I.innerHeight>b.documentElement.clientHeight&&(S=this.cache("scrollbar-size",h),A.viewport.bottom-=S.height),I.innerWidth>b.documentElement.clientWidth&&(S=this.cache("scrollbar-size",h),A.viewport.right-=S.width),["","static"].indexOf(b.body.style.position)!==-1&&["","static"].indexOf(b.body.parentElement.style.position)!==-1||(A.page.bottom=b.body.scrollHeight-_-r,A.page.right=b.body.scrollWidth-m-o),"undefined"!=typeof this.options.optimizations&&this.options.optimizations.moveElement!==!1&&"undefined"==typeof this.targetModifier&&!function(){var e=t.cache("target-offsetparent",function(){return l(t.target)}),n=t.cache("target-offsetparent-bounds",function(){return a(e)}),i=getComputedStyle(e),o=n,r={};if(["Top","Left","Bottom","Right"].forEach(function(t){r[t.toLowerCase()]=parseFloat(i["border"+t+"Width"])}),n.right=b.body.scrollWidth-n.left-o.width+r.right,n.bottom=b.body.scrollHeight-n.top-o.height+r.bottom,A.page.top>=n.top+r.top&&A.page.bottom>=n.bottom&&A.page.left>=n.left+r.left&&A.page.right>=n.right){var s=e.scrollTop,h=e.scrollLeft;A.offset={top:A.page.top-n.top+s-r.top,left:A.page.left-n.left+h-r.left}}}(),this.move(A),this.history.unshift(A),this.history.length>3&&this.history.pop(),e&&P(),!0}}},{key:"move",value:function(t){var e=this;if("undefined"!=typeof this.element.parentNode){var n={};for(var i in t){n[i]={};for(var o in t[i]){for(var r=!1,s=0;s<this.history.length;++s){var a=this.history[s];if("undefined"!=typeof a[i]&&!v(a[i][o],t[i][o])){r=!0;break}}r||(n[i][o]=!0)}}var h={top:"",left:"",right:"",bottom:""},u=function(t,n){var i="undefined"!=typeof e.options.optimizations,o=i?e.options.optimizations.gpu:null;if(o!==!1){var r=void 0,s=void 0;if(t.top?(h.top=0,r=n.top):(h.bottom=0,r=-n.bottom),t.left?(h.left=0,s=n.left):(h.right=0,s=-n.right),window.matchMedia){var a=window.matchMedia("only screen and (min-resolution: 1.3dppx)").matches||window.matchMedia("only screen and (-webkit-min-device-pixel-ratio: 1.3)").matches;a||(s=Math.round(s),r=Math.round(r))}h[x]="translateX("+s+"px) translateY("+r+"px)","msTransform"!==x&&(h[x]+=" translateZ(0)")}else t.top?h.top=n.top+"px":h.bottom=n.bottom+"px",t.left?h.left=n.left+"px":h.right=n.right+"px"},c=!1;if((n.page.top||n.page.bottom)&&(n.page.left||n.page.right)?(h.position="absolute",u(n.page,t.page)):(n.viewport.top||n.viewport.bottom)&&(n.viewport.left||n.viewport.right)?(h.position="fixed",u(n.viewport,t.viewport)):"undefined"!=typeof n.offset&&n.offset.top&&n.offset.left?!function(){h.position="absolute";var i=e.cache("target-offsetparent",function(){return l(e.target)});l(e.element)!==i&&L(function(){e.element.parentNode.removeChild(e.element),i.appendChild(e.element)}),u(n.offset,t.offset),c=!0}():(h.position="absolute",u({top:!0,left:!0},t.page)),!c)if(this.options.bodyElement)this.options.bodyElement.appendChild(this.element);else{for(var d=!0,p=this.element.parentNode;p&&1===p.nodeType&&"BODY"!==p.tagName;){if("static"!==getComputedStyle(p).position){d=!1;break}p=p.parentNode}d||(this.element.parentNode.removeChild(this.element),this.element.ownerDocument.body.appendChild(this.element))}var g={},m=!1;for(var o in h){var _=h[o],E=this.element.style[o];E!==_&&(m=!0,g[o]=_)}m&&L(function(){f(e.element.style,g),e.trigger("repositioned")})}}}]),e}(H);Y.modules=[],O.position=V;var X=f(Y,O),k=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{!i&&a.return&&a.return()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),R=O.Utils,a=R.getBounds,f=R.extend,m=R.updateClasses,L=R.defer,z=["left","top","right","bottom"];O.modules.push({position:function(t){var e=this,n=t.top,i=t.left,o=t.targetAttachment;if(!this.options.constraints)return!0;var r=this.cache("element-bounds",function(){return a(e.element)}),s=r.height,l=r.width;if(0===l&&0===s&&"undefined"!=typeof this.lastSize){var h=this.lastSize;l=h.width,s=h.height}var u=this.cache("target-bounds",function(){return e.getTargetBounds()}),c=u.height,d=u.width,p=[this.getClass("pinned"),this.getClass("out-of-bounds")];this.options.constraints.forEach(function(t){var e=t.outOfBoundsClass,n=t.pinnedClass;e&&p.push(e),n&&p.push(n)}),p.forEach(function(t){["left","top","right","bottom"].forEach(function(e){p.push(t+"-"+e)})});var g=[],_=f({},o),v=f({},this.attachment);return this.options.constraints.forEach(function(t){var r=t.to,a=t.attachment,h=t.pin;"undefined"==typeof a&&(a="");var f=void 0,u=void 0;if(a.indexOf(" ")>=0){var p=a.split(" "),m=k(p,2);u=m[0],f=m[1]}else f=u=a;var E=C(e,r);"target"!==u&&"both"!==u||(n<E[1]&&"top"===_.top&&(n+=c,_.top="bottom"),n+s>E[3]&&"bottom"===_.top&&(n-=c,_.top="top")),"together"===u&&("top"===_.top&&("bottom"===v.top&&n<E[1]?(n+=c,_.top="bottom",n+=s,v.top="top"):"top"===v.top&&n+s>E[3]&&n-(s-c)>=E[1]&&(n-=s-c,_.top="bottom",v.top="bottom")),"bottom"===_.top&&("top"===v.top&&n+s>E[3]?(n-=c,_.top="top",n-=s,v.top="bottom"):"bottom"===v.top&&n<E[1]&&n+(2*s-c)<=E[3]&&(n+=s-c,_.top="top",v.top="top")),"middle"===_.top&&(n+s>E[3]&&"top"===v.top?(n-=s,v.top="bottom"):n<E[1]&&"bottom"===v.top&&(n+=s,v.top="top"))),"target"!==f&&"both"!==f||(i<E[0]&&"left"===_.left&&(i+=d,_.left="right"),i+l>E[2]&&"right"===_.left&&(i-=d,_.left="left")),"together"===f&&(i<E[0]&&"left"===_.left?"right"===v.left?(i+=d,_.left="right",i+=l,v.left="left"):"left"===v.left&&(i+=d,_.left="right",i-=l,v.left="right"):i+l>E[2]&&"right"===_.left?"left"===v.left?(i-=d,_.left="left",i-=l,v.left="right"):"right"===v.left&&(i-=d,_.left="left",i+=l,v.left="left"):"center"===_.left&&(i+l>E[2]&&"left"===v.left?(i-=l,v.left="right"):i<E[0]&&"right"===v.left&&(i+=l,v.left="left"))),"element"!==u&&"both"!==u||(n<E[1]&&"bottom"===v.top&&(n+=s,v.top="top"),n+s>E[3]&&"top"===v.top&&(n-=s,v.top="bottom")),"element"!==f&&"both"!==f||(i<E[0]&&("right"===v.left?(i+=l,v.left="left"):"center"===v.left&&(i+=l/2,v.left="left")),i+l>E[2]&&("left"===v.left?(i-=l,v.left="right"):"center"===v.left&&(i-=l/2,v.left="right"))),"string"==typeof h?h=h.split(",").map(function(t){return t.trim()}):h===!0&&(h=["top","left","right","bottom"]),h=h||[];var y=[],T=[];n<E[1]&&(h.indexOf("top")>=0?(n=E[1],y.push("top")):T.push("top")),n+s>E[3]&&(h.indexOf("bottom")>=0?(n=E[3]-s,y.push("bottom")):T.push("bottom")),i<E[0]&&(h.indexOf("left")>=0?(i=E[0],y.push("left")):T.push("left")),i+l>E[2]&&(h.indexOf("right")>=0?(i=E[2]-l,y.push("right")):T.push("right")),y.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.pinnedClass?e.options.pinnedClass:e.getClass("pinned"),g.push(t),y.forEach(function(e){g.push(t+"-"+e)})}(),T.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.outOfBoundsClass?e.options.outOfBoundsClass:e.getClass("out-of-bounds"),g.push(t),T.forEach(function(e){g.push(t+"-"+e)})}(),(y.indexOf("left")>=0||y.indexOf("right")>=0)&&(v.left=_.left=!1),(y.indexOf("top")>=0||y.indexOf("bottom")>=0)&&(v.top=_.top=!1),_.top===o.top&&_.left===o.left&&v.top===e.attachment.top&&v.left===e.attachment.left||(e.updateAttachClasses(v,_),e.trigger("update",{attachment:v,targetAttachment:_}))}),L(function(){e.options.addTargetClasses!==!1&&m(e.target,g,p),m(e.element,g,p)}),{top:n,left:i}}});var R=O.Utils,a=R.getBounds,m=R.updateClasses,L=R.defer;O.modules.push({position:function(t){var e=this,n=t.top,i=t.left,o=this.cache("element-bounds",function(){return a(e.element)}),r=o.height,s=o.width,l=this.getTargetBounds(),h=n+r,f=i+s,u=[];n<=l.bottom&&h>=l.top&&["left","right"].forEach(function(t){var e=l[t];e!==i&&e!==f||u.push(t)}),i<=l.right&&f>=l.left&&["top","bottom"].forEach(function(t){var e=l[t];e!==n&&e!==h||u.push(t)});var c=[],d=[],p=["left","top","right","bottom"];return c.push(this.getClass("abutted")),p.forEach(function(t){c.push(e.getClass("abutted")+"-"+t)}),u.length&&d.push(this.getClass("abutted")),u.forEach(function(t){d.push(e.getClass("abutted")+"-"+t)}),L(function(){e.options.addTargetClasses!==!1&&m(e.target,d,c),m(e.element,d,c)}),!0}});var k=function(){function t(t,e){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!e||n.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{!i&&a.return&&a.return()}finally{if(o)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();return O.modules.push({position:function(t){var e=t.top,n=t.left;if(this.options.shift){var i=this.options.shift;"function"==typeof this.options.shift&&(i=this.options.shift.call(this,{top:e,left:n}));var o=void 0,r=void 0;if("string"==typeof i){i=i.split(" "),i[1]=i[1]||i[0];var s=i,a=k(s,2);o=a[0],r=a[1],o=parseFloat(o,10),r=parseFloat(r,10)}else o=i.top,r=i.left;return e+=o,n+=r,{top:e,left:n}}}}),X})},function(t,e,n){(function(t){/*!
-	 * Bootstrap v4.0.0-alpha.6 (https://getbootstrap.com)
-	 * Copyright 2011-2017 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
-	 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
-	 */
-if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.");+function(t){var e=t.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||e[0]>=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(jQuery),+function(){function e(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function n(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=function(t){function e(t){return{}.toString.call(t).match(/\s([a-zA-Z]+)/)[1].toLowerCase()}function n(t){return(t[0]||t).nodeType}function i(){return{bindType:a.end,delegateType:a.end,handle:function(e){if(t(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}}}function o(){if(window.QUnit)return!1;var t=document.createElement("bootstrap");for(var e in h)if(void 0!==t.style[e])return{end:h[e]};return!1}function r(e){var n=this,i=!1;return t(this).one(f.TRANSITION_END,function(){i=!0}),setTimeout(function(){i||f.triggerTransitionEnd(n)},e),this}function s(){a=o(),t.fn.emulateTransitionEnd=r,f.supportsTransitionEnd()&&(t.event.special[f.TRANSITION_END]=i())}var a=!1,l=1e6,h={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},f={TRANSITION_END:"bsTransitionEnd",getUID:function(t){do t+=~~(Math.random()*l);while(document.getElementById(t));return t},getSelectorFromElement:function(t){var e=t.getAttribute("data-target");return e||(e=t.getAttribute("href")||"",e=/^#[a-z]/i.test(e)?e:null),e},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(e){t(e).trigger(a.end)},supportsTransitionEnd:function(){return Boolean(a)},typeCheckConfig:function(t,i,o){for(var r in o)if(o.hasOwnProperty(r)){var s=o[r],a=i[r],l=a&&n(a)?"element":e(a);if(!new RegExp(s).test(l))throw new Error(t.toUpperCase()+": "+('Option "'+r+'" provided type "'+l+'" ')+('but expected type "'+s+'".'))}}};return s(),f}(jQuery),a=(function(t){var e="alert",n="4.0.0-alpha.6",o="bs.alert",a="."+o,l=".data-api",h=t.fn[e],f=150,u={DISMISS:'[data-dismiss="alert"]'},c={CLOSE:"close"+a,CLOSED:"closed"+a,CLICK_DATA_API:"click"+a+l},d={ALERT:"alert",FADE:"fade",SHOW:"show"},p=function(){function e(t){i(this,e),this._element=t}return e.prototype.close=function(t){t=t||this._element;var e=this._getRootElement(t),n=this._triggerCloseEvent(e);n.isDefaultPrevented()||this._removeElement(e)},e.prototype.dispose=function(){t.removeData(this._element,o),this._element=null},e.prototype._getRootElement=function(e){var n=s.getSelectorFromElement(e),i=!1;return n&&(i=t(n)[0]),i||(i=t(e).closest("."+d.ALERT)[0]),i},e.prototype._triggerCloseEvent=function(e){var n=t.Event(c.CLOSE);return t(e).trigger(n),n},e.prototype._removeElement=function(e){var n=this;return t(e).removeClass(d.SHOW),s.supportsTransitionEnd()&&t(e).hasClass(d.FADE)?void t(e).one(s.TRANSITION_END,function(t){return n._destroyElement(e,t)}).emulateTransitionEnd(f):void this._destroyElement(e)},e.prototype._destroyElement=function(e){t(e).detach().trigger(c.CLOSED).remove()},e._jQueryInterface=function(n){return this.each(function(){var i=t(this),r=i.data(o);r||(r=new e(this),i.data(o,r)),"close"===n&&r[n](this)})},e._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},r(e,null,[{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(c.CLICK_DATA_API,u.DISMISS,p._handleDismiss(new p)),t.fn[e]=p._jQueryInterface,t.fn[e].Constructor=p,t.fn[e].noConflict=function(){return t.fn[e]=h,p._jQueryInterface},p}(jQuery),function(t){var e="button",n="4.0.0-alpha.6",o="bs.button",s="."+o,a=".data-api",l=t.fn[e],h={ACTIVE:"active",BUTTON:"btn",FOCUS:"focus"},f={DATA_TOGGLE_CARROT:'[data-toggle^="button"]',DATA_TOGGLE:'[data-toggle="buttons"]',INPUT:"input",ACTIVE:".active",BUTTON:".btn"},u={CLICK_DATA_API:"click"+s+a,FOCUS_BLUR_DATA_API:"focus"+s+a+" "+("blur"+s+a)},c=function(){function e(t){i(this,e),this._element=t}return e.prototype.toggle=function(){var e=!0,n=t(this._element).closest(f.DATA_TOGGLE)[0];if(n){var i=t(this._element).find(f.INPUT)[0];if(i){if("radio"===i.type)if(i.checked&&t(this._element).hasClass(h.ACTIVE))e=!1;else{var o=t(n).find(f.ACTIVE)[0];o&&t(o).removeClass(h.ACTIVE)}e&&(i.checked=!t(this._element).hasClass(h.ACTIVE),t(i).trigger("change")),i.focus()}}this._element.setAttribute("aria-pressed",!t(this._element).hasClass(h.ACTIVE)),e&&t(this._element).toggleClass(h.ACTIVE)},e.prototype.dispose=function(){t.removeData(this._element,o),this._element=null},e._jQueryInterface=function(n){return this.each(function(){var i=t(this).data(o);i||(i=new e(this),t(this).data(o,i)),"toggle"===n&&i[n]()})},r(e,null,[{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(u.CLICK_DATA_API,f.DATA_TOGGLE_CARROT,function(e){e.preventDefault();var n=e.target;t(n).hasClass(h.BUTTON)||(n=t(n).closest(f.BUTTON)),c._jQueryInterface.call(t(n),"toggle")}).on(u.FOCUS_BLUR_DATA_API,f.DATA_TOGGLE_CARROT,function(e){var n=t(e.target).closest(f.BUTTON)[0];t(n).toggleClass(h.FOCUS,/^focus(in)?$/.test(e.type))}),t.fn[e]=c._jQueryInterface,t.fn[e].Constructor=c,t.fn[e].noConflict=function(){return t.fn[e]=l,c._jQueryInterface},c}(jQuery),function(t){var e="carousel",n="4.0.0-alpha.6",a="bs.carousel",l="."+a,h=".data-api",f=t.fn[e],u=600,c=37,d=39,p={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0},g={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean"},m={NEXT:"next",PREV:"prev",LEFT:"left",RIGHT:"right"},_={SLIDE:"slide"+l,SLID:"slid"+l,KEYDOWN:"keydown"+l,MOUSEENTER:"mouseenter"+l,MOUSELEAVE:"mouseleave"+l,LOAD_DATA_API:"load"+l+h,CLICK_DATA_API:"click"+l+h},v={CAROUSEL:"carousel",ACTIVE:"active",SLIDE:"slide",RIGHT:"carousel-item-right",LEFT:"carousel-item-left",NEXT:"carousel-item-next",PREV:"carousel-item-prev",ITEM:"carousel-item"},E={ACTIVE:".active",ACTIVE_ITEM:".active.carousel-item",ITEM:".carousel-item",NEXT_PREV:".carousel-item-next, .carousel-item-prev",INDICATORS:".carousel-indicators",DATA_SLIDE:"[data-slide], [data-slide-to]",DATA_RIDE:'[data-ride="carousel"]'},y=function(){function h(e,n){i(this,h),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this._config=this._getConfig(n),this._element=t(e)[0],this._indicatorsElement=t(this._element).find(E.INDICATORS)[0],this._addEventListeners()}return h.prototype.next=function(){if(this._isSliding)throw new Error("Carousel is sliding");this._slide(m.NEXT)},h.prototype.nextWhenVisible=function(){document.hidden||this.next()},h.prototype.prev=function(){if(this._isSliding)throw new Error("Carousel is sliding");this._slide(m.PREVIOUS)},h.prototype.pause=function(e){e||(this._isPaused=!0),t(this._element).find(E.NEXT_PREV)[0]&&s.supportsTransitionEnd()&&(s.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},h.prototype.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},h.prototype.to=function(e){var n=this;this._activeElement=t(this._element).find(E.ACTIVE_ITEM)[0];var i=this._getItemIndex(this._activeElement);if(!(e>this._items.length-1||e<0)){if(this._isSliding)return void t(this._element).one(_.SLID,function(){return n.to(e)});if(i===e)return this.pause(),void this.cycle();var o=e>i?m.NEXT:m.PREVIOUS;this._slide(o,this._items[e])}},h.prototype.dispose=function(){t(this._element).off(l),t.removeData(this._element,a),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},h.prototype._getConfig=function(n){return n=t.extend({},p,n),s.typeCheckConfig(e,n,g),n},h.prototype._addEventListeners=function(){var e=this;this._config.keyboard&&t(this._element).on(_.KEYDOWN,function(t){return e._keydown(t)}),"hover"!==this._config.pause||"ontouchstart"in document.documentElement||t(this._element).on(_.MOUSEENTER,function(t){return e.pause(t)}).on(_.MOUSELEAVE,function(t){return e.cycle(t)})},h.prototype._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case c:t.preventDefault(),this.prev();break;case d:t.preventDefault(),this.next();break;default:return}},h.prototype._getItemIndex=function(e){return this._items=t.makeArray(t(e).parent().find(E.ITEM)),this._items.indexOf(e)},h.prototype._getItemByDirection=function(t,e){var n=t===m.NEXT,i=t===m.PREVIOUS,o=this._getItemIndex(e),r=this._items.length-1,s=i&&0===o||n&&o===r;if(s&&!this._config.wrap)return e;var a=t===m.PREVIOUS?-1:1,l=(o+a)%this._items.length;return l===-1?this._items[this._items.length-1]:this._items[l]},h.prototype._triggerSlideEvent=function(e,n){var i=t.Event(_.SLIDE,{relatedTarget:e,direction:n});return t(this._element).trigger(i),i},h.prototype._setActiveIndicatorElement=function(e){if(this._indicatorsElement){t(this._indicatorsElement).find(E.ACTIVE).removeClass(v.ACTIVE);var n=this._indicatorsElement.children[this._getItemIndex(e)];n&&t(n).addClass(v.ACTIVE)}},h.prototype._slide=function(e,n){var i=this,o=t(this._element).find(E.ACTIVE_ITEM)[0],r=n||o&&this._getItemByDirection(e,o),a=Boolean(this._interval),l=void 0,h=void 0,f=void 0;if(e===m.NEXT?(l=v.LEFT,h=v.NEXT,f=m.LEFT):(l=v.RIGHT,h=v.PREV,f=m.RIGHT),r&&t(r).hasClass(v.ACTIVE))return void(this._isSliding=!1);var c=this._triggerSlideEvent(r,f);if(!c.isDefaultPrevented()&&o&&r){this._isSliding=!0,a&&this.pause(),this._setActiveIndicatorElement(r);var d=t.Event(_.SLID,{relatedTarget:r,direction:f});s.supportsTransitionEnd()&&t(this._element).hasClass(v.SLIDE)?(t(r).addClass(h),s.reflow(r),t(o).addClass(l),t(r).addClass(l),t(o).one(s.TRANSITION_END,function(){t(r).removeClass(l+" "+h).addClass(v.ACTIVE),t(o).removeClass(v.ACTIVE+" "+h+" "+l),i._isSliding=!1,setTimeout(function(){return t(i._element).trigger(d)},0)}).emulateTransitionEnd(u)):(t(o).removeClass(v.ACTIVE),t(r).addClass(v.ACTIVE),this._isSliding=!1,t(this._element).trigger(d)),a&&this.cycle()}},h._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(a),i=t.extend({},p,t(this).data());"object"===("undefined"==typeof e?"undefined":o(e))&&t.extend(i,e);var r="string"==typeof e?e:i.slide;if(n||(n=new h(this,i),t(this).data(a,n)),"number"==typeof e)n.to(e);else if("string"==typeof r){if(void 0===n[r])throw new Error('No method named "'+r+'"');n[r]()}else i.interval&&(n.pause(),n.cycle())})},h._dataApiClickHandler=function(e){var n=s.getSelectorFromElement(this);if(n){var i=t(n)[0];if(i&&t(i).hasClass(v.CAROUSEL)){var o=t.extend({},t(i).data(),t(this).data()),r=this.getAttribute("data-slide-to");r&&(o.interval=!1),h._jQueryInterface.call(t(i),o),r&&t(i).data(a).to(r),e.preventDefault()}}},r(h,null,[{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return p}}]),h}();return t(document).on(_.CLICK_DATA_API,E.DATA_SLIDE,y._dataApiClickHandler),t(window).on(_.LOAD_DATA_API,function(){t(E.DATA_RIDE).each(function(){var e=t(this);y._jQueryInterface.call(e,e.data())})}),t.fn[e]=y._jQueryInterface,t.fn[e].Constructor=y,t.fn[e].noConflict=function(){return t.fn[e]=f,y._jQueryInterface},y}(jQuery),function(t){var e="collapse",n="4.0.0-alpha.6",a="bs.collapse",l="."+a,h=".data-api",f=t.fn[e],u=600,c={toggle:!0,parent:""},d={toggle:"boolean",parent:"string"},p={SHOW:"show"+l,SHOWN:"shown"+l,HIDE:"hide"+l,HIDDEN:"hidden"+l,CLICK_DATA_API:"click"+l+h},g={SHOW:"show",COLLAPSE:"collapse",COLLAPSING:"collapsing",COLLAPSED:"collapsed"},m={WIDTH:"width",HEIGHT:"height"},_={ACTIVES:".card > .show, .card > .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},v=function(){function l(e,n){i(this,l),this._isTransitioning=!1,this._element=e,this._config=this._getConfig(n),this._triggerArray=t.makeArray(t('[data-toggle="collapse"][href="#'+e.id+'"],'+('[data-toggle="collapse"][data-target="#'+e.id+'"]'))),this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}return l.prototype.toggle=function(){t(this._element).hasClass(g.SHOW)?this.hide():this.show()},l.prototype.show=function(){var e=this;if(this._isTransitioning)throw new Error("Collapse is transitioning");if(!t(this._element).hasClass(g.SHOW)){var n=void 0,i=void 0;if(this._parent&&(n=t.makeArray(t(this._parent).find(_.ACTIVES)),n.length||(n=null)),!(n&&(i=t(n).data(a),i&&i._isTransitioning))){var o=t.Event(p.SHOW);if(t(this._element).trigger(o),!o.isDefaultPrevented()){n&&(l._jQueryInterface.call(t(n),"hide"),i||t(n).data(a,null));var r=this._getDimension();t(this._element).removeClass(g.COLLAPSE).addClass(g.COLLAPSING),this._element.style[r]=0,this._element.setAttribute("aria-expanded",!0),this._triggerArray.length&&t(this._triggerArray).removeClass(g.COLLAPSED).attr("aria-expanded",!0),this.setTransitioning(!0);var h=function(){t(e._element).removeClass(g.COLLAPSING).addClass(g.COLLAPSE).addClass(g.SHOW),e._element.style[r]="",e.setTransitioning(!1),t(e._element).trigger(p.SHOWN)};if(!s.supportsTransitionEnd())return void h();var f=r[0].toUpperCase()+r.slice(1),c="scroll"+f;t(this._element).one(s.TRANSITION_END,h).emulateTransitionEnd(u),this._element.style[r]=this._element[c]+"px"}}}},l.prototype.hide=function(){var e=this;if(this._isTransitioning)throw new Error("Collapse is transitioning");if(t(this._element).hasClass(g.SHOW)){var n=t.Event(p.HIDE);if(t(this._element).trigger(n),!n.isDefaultPrevented()){var i=this._getDimension(),o=i===m.WIDTH?"offsetWidth":"offsetHeight";this._element.style[i]=this._element[o]+"px",s.reflow(this._element),t(this._element).addClass(g.COLLAPSING).removeClass(g.COLLAPSE).removeClass(g.SHOW),this._element.setAttribute("aria-expanded",!1),this._triggerArray.length&&t(this._triggerArray).addClass(g.COLLAPSED).attr("aria-expanded",!1),this.setTransitioning(!0);var r=function(){e.setTransitioning(!1),t(e._element).removeClass(g.COLLAPSING).addClass(g.COLLAPSE).trigger(p.HIDDEN)};return this._element.style[i]="",s.supportsTransitionEnd()?void t(this._element).one(s.TRANSITION_END,r).emulateTransitionEnd(u):void r()}}},l.prototype.setTransitioning=function(t){this._isTransitioning=t},l.prototype.dispose=function(){t.removeData(this._element,a),this._config=null,this._parent=null,this._element=null,this._triggerArray=null,this._isTransitioning=null},l.prototype._getConfig=function(n){return n=t.extend({},c,n),n.toggle=Boolean(n.toggle),s.typeCheckConfig(e,n,d),n},l.prototype._getDimension=function(){var e=t(this._element).hasClass(m.WIDTH);return e?m.WIDTH:m.HEIGHT},l.prototype._getParent=function(){var e=this,n=t(this._config.parent)[0],i='[data-toggle="collapse"][data-parent="'+this._config.parent+'"]';return t(n).find(i).each(function(t,n){e._addAriaAndCollapsedClass(l._getTargetFromElement(n),[n])}),n},l.prototype._addAriaAndCollapsedClass=function(e,n){if(e){var i=t(e).hasClass(g.SHOW);e.setAttribute("aria-expanded",i),n.length&&t(n).toggleClass(g.COLLAPSED,!i).attr("aria-expanded",i)}},l._getTargetFromElement=function(e){var n=s.getSelectorFromElement(e);return n?t(n)[0]:null},l._jQueryInterface=function(e){return this.each(function(){var n=t(this),i=n.data(a),r=t.extend({},c,n.data(),"object"===("undefined"==typeof e?"undefined":o(e))&&e);if(!i&&r.toggle&&/show|hide/.test(e)&&(r.toggle=!1),i||(i=new l(this,r),n.data(a,i)),"string"==typeof e){if(void 0===i[e])throw new Error('No method named "'+e+'"');i[e]()}})},r(l,null,[{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return c}}]),l}();return t(document).on(p.CLICK_DATA_API,_.DATA_TOGGLE,function(e){e.preventDefault();var n=v._getTargetFromElement(this),i=t(n).data(a),o=i?"toggle":t(this).data();v._jQueryInterface.call(t(n),o)}),t.fn[e]=v._jQueryInterface,t.fn[e].Constructor=v,t.fn[e].noConflict=function(){return t.fn[e]=f,v._jQueryInterface},v}(jQuery),function(t){var e="dropdown",n="4.0.0-alpha.6",o="bs.dropdown",a="."+o,l=".data-api",h=t.fn[e],f=27,u=38,c=40,d=3,p={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,CLICK:"click"+a,CLICK_DATA_API:"click"+a+l,FOCUSIN_DATA_API:"focusin"+a+l,KEYDOWN_DATA_API:"keydown"+a+l},g={BACKDROP:"dropdown-backdrop",DISABLED:"disabled",SHOW:"show"},m={BACKDROP:".dropdown-backdrop",DATA_TOGGLE:'[data-toggle="dropdown"]',FORM_CHILD:".dropdown form",ROLE_MENU:'[role="menu"]',ROLE_LISTBOX:'[role="listbox"]',NAVBAR_NAV:".navbar-nav",VISIBLE_ITEMS:'[role="menu"] li:not(.disabled) a, [role="listbox"] li:not(.disabled) a'},_=function(){function e(t){i(this,e),this._element=t,this._addEventListeners()}return e.prototype.toggle=function(){if(this.disabled||t(this).hasClass(g.DISABLED))return!1;var n=e._getParentFromElement(this),i=t(n).hasClass(g.SHOW);if(e._clearMenus(),i)return!1;if("ontouchstart"in document.documentElement&&!t(n).closest(m.NAVBAR_NAV).length){var o=document.createElement("div");o.className=g.BACKDROP,t(o).insertBefore(this),t(o).on("click",e._clearMenus)}var r={relatedTarget:this},s=t.Event(p.SHOW,r);return t(n).trigger(s),!s.isDefaultPrevented()&&(this.focus(),this.setAttribute("aria-expanded",!0),t(n).toggleClass(g.SHOW),t(n).trigger(t.Event(p.SHOWN,r)),!1)},e.prototype.dispose=function(){t.removeData(this._element,o),t(this._element).off(a),this._element=null},e.prototype._addEventListeners=function(){t(this._element).on(p.CLICK,this.toggle)},e._jQueryInterface=function(n){return this.each(function(){var i=t(this).data(o);if(i||(i=new e(this),t(this).data(o,i)),"string"==typeof n){if(void 0===i[n])throw new Error('No method named "'+n+'"');i[n].call(this)}})},e._clearMenus=function(n){if(!n||n.which!==d){var i=t(m.BACKDROP)[0];i&&i.parentNode.removeChild(i);for(var o=t.makeArray(t(m.DATA_TOGGLE)),r=0;r<o.length;r++){var s=e._getParentFromElement(o[r]),a={relatedTarget:o[r]};if(t(s).hasClass(g.SHOW)&&!(n&&("click"===n.type&&/input|textarea/i.test(n.target.tagName)||"focusin"===n.type)&&t.contains(s,n.target))){var l=t.Event(p.HIDE,a);t(s).trigger(l),l.isDefaultPrevented()||(o[r].setAttribute("aria-expanded","false"),t(s).removeClass(g.SHOW).trigger(t.Event(p.HIDDEN,a)))}}}},e._getParentFromElement=function(e){var n=void 0,i=s.getSelectorFromElement(e);return i&&(n=t(i)[0]),n||e.parentNode},e._dataApiKeydownHandler=function(n){if(/(38|40|27|32)/.test(n.which)&&!/input|textarea/i.test(n.target.tagName)&&(n.preventDefault(),n.stopPropagation(),!this.disabled&&!t(this).hasClass(g.DISABLED))){var i=e._getParentFromElement(this),o=t(i).hasClass(g.SHOW);if(!o&&n.which!==f||o&&n.which===f){if(n.which===f){var r=t(i).find(m.DATA_TOGGLE)[0];t(r).trigger("focus")}return void t(this).trigger("click")}var s=t(i).find(m.VISIBLE_ITEMS).get();if(s.length){var a=s.indexOf(n.target);n.which===u&&a>0&&a--,n.which===c&&a<s.length-1&&a++,a<0&&(a=0),s[a].focus()}}},r(e,null,[{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(p.KEYDOWN_DATA_API,m.DATA_TOGGLE,_._dataApiKeydownHandler).on(p.KEYDOWN_DATA_API,m.ROLE_MENU,_._dataApiKeydownHandler).on(p.KEYDOWN_DATA_API,m.ROLE_LISTBOX,_._dataApiKeydownHandler).on(p.CLICK_DATA_API+" "+p.FOCUSIN_DATA_API,_._clearMenus).on(p.CLICK_DATA_API,m.DATA_TOGGLE,_.prototype.toggle).on(p.CLICK_DATA_API,m.FORM_CHILD,function(t){t.stopPropagation()}),t.fn[e]=_._jQueryInterface,t.fn[e].Constructor=_,t.fn[e].noConflict=function(){return t.fn[e]=h,_._jQueryInterface},_}(jQuery),function(t){var e="modal",n="4.0.0-alpha.6",a="bs.modal",l="."+a,h=".data-api",f=t.fn[e],u=300,c=150,d=27,p={backdrop:!0,keyboard:!0,focus:!0,show:!0},g={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean",show:"boolean"},m={HIDE:"hide"+l,HIDDEN:"hidden"+l,SHOW:"show"+l,SHOWN:"shown"+l,FOCUSIN:"focusin"+l,RESIZE:"resize"+l,CLICK_DISMISS:"click.dismiss"+l,KEYDOWN_DISMISS:"keydown.dismiss"+l,MOUSEUP_DISMISS:"mouseup.dismiss"+l,MOUSEDOWN_DISMISS:"mousedown.dismiss"+l,CLICK_DATA_API:"click"+l+h},_={SCROLLBAR_MEASURER:"modal-scrollbar-measure",BACKDROP:"modal-backdrop",OPEN:"modal-open",FADE:"fade",SHOW:"show"},v={DIALOG:".modal-dialog",DATA_TOGGLE:'[data-toggle="modal"]',DATA_DISMISS:'[data-dismiss="modal"]',FIXED_CONTENT:".fixed-top, .fixed-bottom, .is-fixed, .sticky-top"},E=function(){function h(e,n){i(this,h),this._config=this._getConfig(n),this._element=e,this._dialog=t(e).find(v.DIALOG)[0],this._backdrop=null,this._isShown=!1,this._isBodyOverflowing=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._originalBodyPadding=0,this._scrollbarWidth=0}return h.prototype.toggle=function(t){return this._isShown?this.hide():this.show(t)},h.prototype.show=function(e){var n=this;if(this._isTransitioning)throw new Error("Modal is transitioning");s.supportsTransitionEnd()&&t(this._element).hasClass(_.FADE)&&(this._isTransitioning=!0);var i=t.Event(m.SHOW,{relatedTarget:e});t(this._element).trigger(i),this._isShown||i.isDefaultPrevented()||(this._isShown=!0,this._checkScrollbar(),this._setScrollbar(),t(document.body).addClass(_.OPEN),this._setEscapeEvent(),this._setResizeEvent(),t(this._element).on(m.CLICK_DISMISS,v.DATA_DISMISS,function(t){return n.hide(t)}),t(this._dialog).on(m.MOUSEDOWN_DISMISS,function(){t(n._element).one(m.MOUSEUP_DISMISS,function(e){t(e.target).is(n._element)&&(n._ignoreBackdropClick=!0)})}),this._showBackdrop(function(){return n._showElement(e)}))},h.prototype.hide=function(e){var n=this;if(e&&e.preventDefault(),this._isTransitioning)throw new Error("Modal is transitioning");var i=s.supportsTransitionEnd()&&t(this._element).hasClass(_.FADE);i&&(this._isTransitioning=!0);var o=t.Event(m.HIDE);t(this._element).trigger(o),this._isShown&&!o.isDefaultPrevented()&&(this._isShown=!1,this._setEscapeEvent(),this._setResizeEvent(),t(document).off(m.FOCUSIN),t(this._element).removeClass(_.SHOW),t(this._element).off(m.CLICK_DISMISS),t(this._dialog).off(m.MOUSEDOWN_DISMISS),i?t(this._element).one(s.TRANSITION_END,function(t){return n._hideModal(t)}).emulateTransitionEnd(u):this._hideModal())},h.prototype.dispose=function(){t.removeData(this._element,a),t(window,document,this._element,this._backdrop).off(l),this._config=null,this._element=null,this._dialog=null,this._backdrop=null,this._isShown=null,this._isBodyOverflowing=null,this._ignoreBackdropClick=null,this._originalBodyPadding=null,this._scrollbarWidth=null},h.prototype._getConfig=function(n){return n=t.extend({},p,n),s.typeCheckConfig(e,n,g),n},h.prototype._showElement=function(e){var n=this,i=s.supportsTransitionEnd()&&t(this._element).hasClass(_.FADE);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.scrollTop=0,i&&s.reflow(this._element),t(this._element).addClass(_.SHOW),this._config.focus&&this._enforceFocus();var o=t.Event(m.SHOWN,{relatedTarget:e}),r=function(){n._config.focus&&n._element.focus(),n._isTransitioning=!1,t(n._element).trigger(o)};i?t(this._dialog).one(s.TRANSITION_END,r).emulateTransitionEnd(u):r()},h.prototype._enforceFocus=function(){var e=this;t(document).off(m.FOCUSIN).on(m.FOCUSIN,function(n){document===n.target||e._element===n.target||t(e._element).has(n.target).length||e._element.focus()})},h.prototype._setEscapeEvent=function(){var e=this;this._isShown&&this._config.keyboard?t(this._element).on(m.KEYDOWN_DISMISS,function(t){t.which===d&&e.hide()}):this._isShown||t(this._element).off(m.KEYDOWN_DISMISS)},h.prototype._setResizeEvent=function(){var e=this;this._isShown?t(window).on(m.RESIZE,function(t){return e._handleUpdate(t)}):t(window).off(m.RESIZE)},h.prototype._hideModal=function(){var e=this;this._element.style.display="none",this._element.setAttribute("aria-hidden","true"),this._isTransitioning=!1,this._showBackdrop(function(){t(document.body).removeClass(_.OPEN),e._resetAdjustments(),e._resetScrollbar(),t(e._element).trigger(m.HIDDEN)})},h.prototype._removeBackdrop=function(){this._backdrop&&(t(this._backdrop).remove(),this._backdrop=null)},h.prototype._showBackdrop=function(e){var n=this,i=t(this._element).hasClass(_.FADE)?_.FADE:"";if(this._isShown&&this._config.backdrop){var o=s.supportsTransitionEnd()&&i;if(this._backdrop=document.createElement("div"),this._backdrop.className=_.BACKDROP,i&&t(this._backdrop).addClass(i),t(this._backdrop).appendTo(document.body),t(this._element).on(m.CLICK_DISMISS,function(t){return n._ignoreBackdropClick?void(n._ignoreBackdropClick=!1):void(t.target===t.currentTarget&&("static"===n._config.backdrop?n._element.focus():n.hide()))}),o&&s.reflow(this._backdrop),t(this._backdrop).addClass(_.SHOW),!e)return;if(!o)return void e();t(this._backdrop).one(s.TRANSITION_END,e).emulateTransitionEnd(c)}else if(!this._isShown&&this._backdrop){t(this._backdrop).removeClass(_.SHOW);var r=function(){n._removeBackdrop(),e&&e()};s.supportsTransitionEnd()&&t(this._element).hasClass(_.FADE)?t(this._backdrop).one(s.TRANSITION_END,r).emulateTransitionEnd(c):r()}else e&&e()},h.prototype._handleUpdate=function(){this._adjustDialog()},h.prototype._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},h.prototype._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},h.prototype._checkScrollbar=function(){this._isBodyOverflowing=document.body.clientWidth<window.innerWidth,this._scrollbarWidth=this._getScrollbarWidth()},h.prototype._setScrollbar=function(){var e=parseInt(t(v.FIXED_CONTENT).css("padding-right")||0,10);this._originalBodyPadding=document.body.style.paddingRight||"",this._isBodyOverflowing&&(document.body.style.paddingRight=e+this._scrollbarWidth+"px")},h.prototype._resetScrollbar=function(){document.body.style.paddingRight=this._originalBodyPadding},h.prototype._getScrollbarWidth=function(){var t=document.createElement("div");t.className=_.SCROLLBAR_MEASURER,document.body.appendChild(t);var e=t.offsetWidth-t.clientWidth;return document.body.removeChild(t),e},h._jQueryInterface=function(e,n){return this.each(function(){var i=t(this).data(a),r=t.extend({},h.Default,t(this).data(),"object"===("undefined"==typeof e?"undefined":o(e))&&e);if(i||(i=new h(this,r),t(this).data(a,i)),"string"==typeof e){if(void 0===i[e])throw new Error('No method named "'+e+'"');i[e](n)}else r.show&&i.show(n)})},r(h,null,[{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return p}}]),h}();return t(document).on(m.CLICK_DATA_API,v.DATA_TOGGLE,function(e){var n=this,i=void 0,o=s.getSelectorFromElement(this);o&&(i=t(o)[0]);var r=t(i).data(a)?"toggle":t.extend({},t(i).data(),t(this).data());"A"!==this.tagName&&"AREA"!==this.tagName||e.preventDefault();var l=t(i).one(m.SHOW,function(e){e.isDefaultPrevented()||l.one(m.HIDDEN,function(){t(n).is(":visible")&&n.focus()})});E._jQueryInterface.call(t(i),r,this)}),t.fn[e]=E._jQueryInterface,t.fn[e].Constructor=E,t.fn[e].noConflict=function(){return t.fn[e]=f,E._jQueryInterface},E}(jQuery),function(t){var e="scrollspy",n="4.0.0-alpha.6",a="bs.scrollspy",l="."+a,h=".data-api",f=t.fn[e],u={offset:10,method:"auto",target:""},c={offset:"number",method:"string",target:"(string|element)"},d={ACTIVATE:"activate"+l,SCROLL:"scroll"+l,LOAD_DATA_API:"load"+l+h},p={DROPDOWN_ITEM:"dropdown-item",DROPDOWN_MENU:"dropdown-menu",NAV_LINK:"nav-link",NAV:"nav",ACTIVE:"active"},g={DATA_SPY:'[data-spy="scroll"]',ACTIVE:".active",LIST_ITEM:".list-item",LI:"li",LI_DROPDOWN:"li.dropdown",NAV_LINKS:".nav-link",DROPDOWN:".dropdown",DROPDOWN_ITEMS:".dropdown-item",DROPDOWN_TOGGLE:".dropdown-toggle"},m={OFFSET:"offset",POSITION:"position"},_=function(){function h(e,n){var o=this;i(this,h),this._element=e,this._scrollElement="BODY"===e.tagName?window:e,this._config=this._getConfig(n),this._selector=this._config.target+" "+g.NAV_LINKS+","+(this._config.target+" "+g.DROPDOWN_ITEMS),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,t(this._scrollElement).on(d.SCROLL,function(t){return o._process(t)}),this.refresh(),this._process()}return h.prototype.refresh=function(){var e=this,n=this._scrollElement!==this._scrollElement.window?m.POSITION:m.OFFSET,i="auto"===this._config.method?n:this._config.method,o=i===m.POSITION?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight();var r=t.makeArray(t(this._selector));r.map(function(e){var n=void 0,r=s.getSelectorFromElement(e);return r&&(n=t(r)[0]),n&&(n.offsetWidth||n.offsetHeight)?[t(n)[i]().top+o,r]:null}).filter(function(t){return t}).sort(function(t,e){return t[0]-e[0]}).forEach(function(t){e._offsets.push(t[0]),e._targets.push(t[1])})},h.prototype.dispose=function(){t.removeData(this._element,a),t(this._scrollElement).off(l),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},h.prototype._getConfig=function(n){if(n=t.extend({},u,n),"string"!=typeof n.target){var i=t(n.target).attr("id");i||(i=s.getUID(e),t(n.target).attr("id",i)),n.target="#"+i}return s.typeCheckConfig(e,n,c),n},h.prototype._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},h.prototype._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},h.prototype._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.offsetHeight},h.prototype._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];return void(this._activeTarget!==i&&this._activate(i))}if(this._activeTarget&&t<this._offsets[0]&&this._offsets[0]>0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;){var r=this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&(void 0===this._offsets[o+1]||t<this._offsets[o+1]);r&&this._activate(this._targets[o])}},h.prototype._activate=function(e){this._activeTarget=e,this._clear();var n=this._selector.split(",");n=n.map(function(t){return t+'[data-target="'+e+'"],'+(t+'[href="'+e+'"]')});var i=t(n.join(","));i.hasClass(p.DROPDOWN_ITEM)?(i.closest(g.DROPDOWN).find(g.DROPDOWN_TOGGLE).addClass(p.ACTIVE),i.addClass(p.ACTIVE)):i.parents(g.LI).find("> "+g.NAV_LINKS).addClass(p.ACTIVE),t(this._scrollElement).trigger(d.ACTIVATE,{relatedTarget:e})},h.prototype._clear=function(){t(this._selector).filter(g.ACTIVE).removeClass(p.ACTIVE)},h._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(a),i="object"===("undefined"==typeof e?"undefined":o(e))&&e;
-if(n||(n=new h(this,i),t(this).data(a,n)),"string"==typeof e){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})},r(h,null,[{key:"VERSION",get:function(){return n}},{key:"Default",get:function(){return u}}]),h}();return t(window).on(d.LOAD_DATA_API,function(){for(var e=t.makeArray(t(g.DATA_SPY)),n=e.length;n--;){var i=t(e[n]);_._jQueryInterface.call(i,i.data())}}),t.fn[e]=_._jQueryInterface,t.fn[e].Constructor=_,t.fn[e].noConflict=function(){return t.fn[e]=f,_._jQueryInterface},_}(jQuery),function(t){var e="tab",n="4.0.0-alpha.6",o="bs.tab",a="."+o,l=".data-api",h=t.fn[e],f=150,u={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,CLICK_DATA_API:"click"+a+l},c={DROPDOWN_MENU:"dropdown-menu",ACTIVE:"active",DISABLED:"disabled",FADE:"fade",SHOW:"show"},d={A:"a",LI:"li",DROPDOWN:".dropdown",LIST:"ul:not(.dropdown-menu), ol:not(.dropdown-menu), nav:not(.dropdown-menu)",FADE_CHILD:"> .nav-item .fade, > .fade",ACTIVE:".active",ACTIVE_CHILD:"> .nav-item > .active, > .active",DATA_TOGGLE:'[data-toggle="tab"], [data-toggle="pill"]',DROPDOWN_TOGGLE:".dropdown-toggle",DROPDOWN_ACTIVE_CHILD:"> .dropdown-menu .active"},p=function(){function e(t){i(this,e),this._element=t}return e.prototype.show=function(){var e=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&t(this._element).hasClass(c.ACTIVE)||t(this._element).hasClass(c.DISABLED))){var n=void 0,i=void 0,o=t(this._element).closest(d.LIST)[0],r=s.getSelectorFromElement(this._element);o&&(i=t.makeArray(t(o).find(d.ACTIVE)),i=i[i.length-1]);var a=t.Event(u.HIDE,{relatedTarget:this._element}),l=t.Event(u.SHOW,{relatedTarget:i});if(i&&t(i).trigger(a),t(this._element).trigger(l),!l.isDefaultPrevented()&&!a.isDefaultPrevented()){r&&(n=t(r)[0]),this._activate(this._element,o);var h=function(){var n=t.Event(u.HIDDEN,{relatedTarget:e._element}),o=t.Event(u.SHOWN,{relatedTarget:i});t(i).trigger(n),t(e._element).trigger(o)};n?this._activate(n,n.parentNode,h):h()}}},e.prototype.dispose=function(){t.removeClass(this._element,o),this._element=null},e.prototype._activate=function(e,n,i){var o=this,r=t(n).find(d.ACTIVE_CHILD)[0],a=i&&s.supportsTransitionEnd()&&(r&&t(r).hasClass(c.FADE)||Boolean(t(n).find(d.FADE_CHILD)[0])),l=function(){return o._transitionComplete(e,r,a,i)};r&&a?t(r).one(s.TRANSITION_END,l).emulateTransitionEnd(f):l(),r&&t(r).removeClass(c.SHOW)},e.prototype._transitionComplete=function(e,n,i,o){if(n){t(n).removeClass(c.ACTIVE);var r=t(n.parentNode).find(d.DROPDOWN_ACTIVE_CHILD)[0];r&&t(r).removeClass(c.ACTIVE),n.setAttribute("aria-expanded",!1)}if(t(e).addClass(c.ACTIVE),e.setAttribute("aria-expanded",!0),i?(s.reflow(e),t(e).addClass(c.SHOW)):t(e).removeClass(c.FADE),e.parentNode&&t(e.parentNode).hasClass(c.DROPDOWN_MENU)){var a=t(e).closest(d.DROPDOWN)[0];a&&t(a).find(d.DROPDOWN_TOGGLE).addClass(c.ACTIVE),e.setAttribute("aria-expanded",!0)}o&&o()},e._jQueryInterface=function(n){return this.each(function(){var i=t(this),r=i.data(o);if(r||(r=new e(this),i.data(o,r)),"string"==typeof n){if(void 0===r[n])throw new Error('No method named "'+n+'"');r[n]()}})},r(e,null,[{key:"VERSION",get:function(){return n}}]),e}();return t(document).on(u.CLICK_DATA_API,d.DATA_TOGGLE,function(e){e.preventDefault(),p._jQueryInterface.call(t(this),"show")}),t.fn[e]=p._jQueryInterface,t.fn[e].Constructor=p,t.fn[e].noConflict=function(){return t.fn[e]=h,p._jQueryInterface},p}(jQuery),function(e){if("undefined"==typeof t)throw new Error("Bootstrap tooltips require Tether (http://tether.io/)");var n="tooltip",a="4.0.0-alpha.6",l="bs.tooltip",h="."+l,f=e.fn[n],u=150,c="bs-tether",d={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:"0 0",constraints:[],container:!1},p={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"string",constraints:"array",container:"(string|element|boolean)"},g={TOP:"bottom center",RIGHT:"middle left",BOTTOM:"top center",LEFT:"middle right"},m={SHOW:"show",OUT:"out"},_={HIDE:"hide"+h,HIDDEN:"hidden"+h,SHOW:"show"+h,SHOWN:"shown"+h,INSERTED:"inserted"+h,CLICK:"click"+h,FOCUSIN:"focusin"+h,FOCUSOUT:"focusout"+h,MOUSEENTER:"mouseenter"+h,MOUSELEAVE:"mouseleave"+h},v={FADE:"fade",SHOW:"show"},E={TOOLTIP:".tooltip",TOOLTIP_INNER:".tooltip-inner"},y={element:!1,enabled:!1},T={HOVER:"hover",FOCUS:"focus",CLICK:"click",MANUAL:"manual"},C=function(){function f(t,e){i(this,f),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._isTransitioning=!1,this._tether=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}return f.prototype.enable=function(){this._isEnabled=!0},f.prototype.disable=function(){this._isEnabled=!1},f.prototype.toggleEnabled=function(){this._isEnabled=!this._isEnabled},f.prototype.toggle=function(t){if(t){var n=this.constructor.DATA_KEY,i=e(t.currentTarget).data(n);i||(i=new this.constructor(t.currentTarget,this._getDelegateConfig()),e(t.currentTarget).data(n,i)),i._activeTrigger.click=!i._activeTrigger.click,i._isWithActiveTrigger()?i._enter(null,i):i._leave(null,i)}else{if(e(this.getTipElement()).hasClass(v.SHOW))return void this._leave(null,this);this._enter(null,this)}},f.prototype.dispose=function(){clearTimeout(this._timeout),this.cleanupTether(),e.removeData(this.element,this.constructor.DATA_KEY),e(this.element).off(this.constructor.EVENT_KEY),e(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&e(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._tether=null,this.element=null,this.config=null,this.tip=null},f.prototype.show=function(){var n=this;if("none"===e(this.element).css("display"))throw new Error("Please use show on visible elements");var i=e.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){if(this._isTransitioning)throw new Error("Tooltip is transitioning");e(this.element).trigger(i);var o=e.contains(this.element.ownerDocument.documentElement,this.element);if(i.isDefaultPrevented()||!o)return;var r=this.getTipElement(),a=s.getUID(this.constructor.NAME);r.setAttribute("id",a),this.element.setAttribute("aria-describedby",a),this.setContent(),this.config.animation&&e(r).addClass(v.FADE);var l="function"==typeof this.config.placement?this.config.placement.call(this,r,this.element):this.config.placement,h=this._getAttachment(l),u=this.config.container===!1?document.body:e(this.config.container);e(r).data(this.constructor.DATA_KEY,this).appendTo(u),e(this.element).trigger(this.constructor.Event.INSERTED),this._tether=new t({attachment:h,element:r,target:this.element,classes:y,classPrefix:c,offset:this.config.offset,constraints:this.config.constraints,addTargetClasses:!1}),s.reflow(r),this._tether.position(),e(r).addClass(v.SHOW);var d=function(){var t=n._hoverState;n._hoverState=null,n._isTransitioning=!1,e(n.element).trigger(n.constructor.Event.SHOWN),t===m.OUT&&n._leave(null,n)};if(s.supportsTransitionEnd()&&e(this.tip).hasClass(v.FADE))return this._isTransitioning=!0,void e(this.tip).one(s.TRANSITION_END,d).emulateTransitionEnd(f._TRANSITION_DURATION);d()}},f.prototype.hide=function(t){var n=this,i=this.getTipElement(),o=e.Event(this.constructor.Event.HIDE);if(this._isTransitioning)throw new Error("Tooltip is transitioning");var r=function(){n._hoverState!==m.SHOW&&i.parentNode&&i.parentNode.removeChild(i),n.element.removeAttribute("aria-describedby"),e(n.element).trigger(n.constructor.Event.HIDDEN),n._isTransitioning=!1,n.cleanupTether(),t&&t()};e(this.element).trigger(o),o.isDefaultPrevented()||(e(i).removeClass(v.SHOW),this._activeTrigger[T.CLICK]=!1,this._activeTrigger[T.FOCUS]=!1,this._activeTrigger[T.HOVER]=!1,s.supportsTransitionEnd()&&e(this.tip).hasClass(v.FADE)?(this._isTransitioning=!0,e(i).one(s.TRANSITION_END,r).emulateTransitionEnd(u)):r(),this._hoverState="")},f.prototype.isWithContent=function(){return Boolean(this.getTitle())},f.prototype.getTipElement=function(){return this.tip=this.tip||e(this.config.template)[0]},f.prototype.setContent=function(){var t=e(this.getTipElement());this.setElementContent(t.find(E.TOOLTIP_INNER),this.getTitle()),t.removeClass(v.FADE+" "+v.SHOW),this.cleanupTether()},f.prototype.setElementContent=function(t,n){var i=this.config.html;"object"===("undefined"==typeof n?"undefined":o(n))&&(n.nodeType||n.jquery)?i?e(n).parent().is(t)||t.empty().append(n):t.text(e(n).text()):t[i?"html":"text"](n)},f.prototype.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},f.prototype.cleanupTether=function(){this._tether&&this._tether.destroy()},f.prototype._getAttachment=function(t){return g[t.toUpperCase()]},f.prototype._setListeners=function(){var t=this,n=this.config.trigger.split(" ");n.forEach(function(n){if("click"===n)e(t.element).on(t.constructor.Event.CLICK,t.config.selector,function(e){return t.toggle(e)});else if(n!==T.MANUAL){var i=n===T.HOVER?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,o=n===T.HOVER?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;e(t.element).on(i,t.config.selector,function(e){return t._enter(e)}).on(o,t.config.selector,function(e){return t._leave(e)})}e(t.element).closest(".modal").on("hide.bs.modal",function(){return t.hide()})}),this.config.selector?this.config=e.extend({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},f.prototype._fixTitle=function(){var t=o(this.element.getAttribute("data-original-title"));(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},f.prototype._enter=function(t,n){var i=this.constructor.DATA_KEY;return n=n||e(t.currentTarget).data(i),n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),e(t.currentTarget).data(i,n)),t&&(n._activeTrigger["focusin"===t.type?T.FOCUS:T.HOVER]=!0),e(n.getTipElement()).hasClass(v.SHOW)||n._hoverState===m.SHOW?void(n._hoverState=m.SHOW):(clearTimeout(n._timeout),n._hoverState=m.SHOW,n.config.delay&&n.config.delay.show?void(n._timeout=setTimeout(function(){n._hoverState===m.SHOW&&n.show()},n.config.delay.show)):void n.show())},f.prototype._leave=function(t,n){var i=this.constructor.DATA_KEY;if(n=n||e(t.currentTarget).data(i),n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),e(t.currentTarget).data(i,n)),t&&(n._activeTrigger["focusout"===t.type?T.FOCUS:T.HOVER]=!1),!n._isWithActiveTrigger())return clearTimeout(n._timeout),n._hoverState=m.OUT,n.config.delay&&n.config.delay.hide?void(n._timeout=setTimeout(function(){n._hoverState===m.OUT&&n.hide()},n.config.delay.hide)):void n.hide()},f.prototype._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},f.prototype._getConfig=function(t){return t=e.extend({},this.constructor.Default,e(this.element).data(),t),t.delay&&"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),s.typeCheckConfig(n,t,this.constructor.DefaultType),t},f.prototype._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},f._jQueryInterface=function(t){return this.each(function(){var n=e(this).data(l),i="object"===("undefined"==typeof t?"undefined":o(t))&&t;if((n||!/dispose|hide/.test(t))&&(n||(n=new f(this,i),e(this).data(l,n)),"string"==typeof t)){if(void 0===n[t])throw new Error('No method named "'+t+'"');n[t]()}})},r(f,null,[{key:"VERSION",get:function(){return a}},{key:"Default",get:function(){return d}},{key:"NAME",get:function(){return n}},{key:"DATA_KEY",get:function(){return l}},{key:"Event",get:function(){return _}},{key:"EVENT_KEY",get:function(){return h}},{key:"DefaultType",get:function(){return p}}]),f}();return e.fn[n]=C._jQueryInterface,e.fn[n].Constructor=C,e.fn[n].noConflict=function(){return e.fn[n]=f,C._jQueryInterface},C}(jQuery));(function(t){var s="popover",l="4.0.0-alpha.6",h="bs.popover",f="."+h,u=t.fn[s],c=t.extend({},a.Default,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),d=t.extend({},a.DefaultType,{content:"(string|element|function)"}),p={FADE:"fade",SHOW:"show"},g={TITLE:".popover-title",CONTENT:".popover-content"},m={HIDE:"hide"+f,HIDDEN:"hidden"+f,SHOW:"show"+f,SHOWN:"shown"+f,INSERTED:"inserted"+f,CLICK:"click"+f,FOCUSIN:"focusin"+f,FOCUSOUT:"focusout"+f,MOUSEENTER:"mouseenter"+f,MOUSELEAVE:"mouseleave"+f},_=function(a){function u(){return i(this,u),e(this,a.apply(this,arguments))}return n(u,a),u.prototype.isWithContent=function(){return this.getTitle()||this._getContent()},u.prototype.getTipElement=function(){return this.tip=this.tip||t(this.config.template)[0]},u.prototype.setContent=function(){var e=t(this.getTipElement());this.setElementContent(e.find(g.TITLE),this.getTitle()),this.setElementContent(e.find(g.CONTENT),this._getContent()),e.removeClass(p.FADE+" "+p.SHOW),this.cleanupTether()},u.prototype._getContent=function(){return this.element.getAttribute("data-content")||("function"==typeof this.config.content?this.config.content.call(this.element):this.config.content)},u._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(h),i="object"===("undefined"==typeof e?"undefined":o(e))?e:null;if((n||!/destroy|hide/.test(e))&&(n||(n=new u(this,i),t(this).data(h,n)),"string"==typeof e)){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})},r(u,null,[{key:"VERSION",get:function(){return l}},{key:"Default",get:function(){return c}},{key:"NAME",get:function(){return s}},{key:"DATA_KEY",get:function(){return h}},{key:"Event",get:function(){return m}},{key:"EVENT_KEY",get:function(){return f}},{key:"DefaultType",get:function(){return d}}]),u}(a);return t.fn[s]=_._jQueryInterface,t.fn[s].Constructor=_,t.fn[s].noConflict=function(){return t.fn[s]=u,_._jQueryInterface},_})(jQuery)}()}).call(e,n(1))},function(t,e){}]);
\ No newline at end of file
+!function(t){function e(i){if(n[i])return n[i].exports;var o=n[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,i){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:i})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=2)}([function(t,e,n){(function(t){/*!
+ * Bootstrap v4.0.0-beta (https://getbootstrap.com)
+ * Copyright 2011-2017 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.");!function(t){var e=t.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||e[0]>=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(jQuery),function(){function e(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function n(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),s=function(t){function e(t){return{}.toString.call(t).match(/\s([a-zA-Z]+)/)[1].toLowerCase()}function n(t){return(t[0]||t).nodeType}function i(){return{bindType:s.end,delegateType:s.end,handle:function(e){if(t(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}}}function o(){if(window.QUnit)return!1;var t=document.createElement("bootstrap");for(var e in a)if(void 0!==t.style[e])return{end:a[e]};return!1}function r(e){var n=this,i=!1;return t(this).one(l.TRANSITION_END,function(){i=!0}),setTimeout(function(){i||l.triggerTransitionEnd(n)},e),this}var s=!1,a={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},l={TRANSITION_END:"bsTransitionEnd",getUID:function(t){do{t+=~~(1e6*Math.random())}while(document.getElementById(t));return t},getSelectorFromElement:function(e){var n=e.getAttribute("data-target");n&&"#"!==n||(n=e.getAttribute("href")||"");try{return t(n).length>0?n:null}catch(t){return null}},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(e){t(e).trigger(s.end)},supportsTransitionEnd:function(){return Boolean(s)},typeCheckConfig:function(t,i,o){for(var r in o)if(o.hasOwnProperty(r)){var s=o[r],a=i[r],l=a&&n(a)?"element":e(a);if(!new RegExp(s).test(l))throw new Error(t.toUpperCase()+': Option "'+r+'" provided type "'+l+'" but expected type "'+s+'".')}}};return function(){s=o(),t.fn.emulateTransitionEnd=r,l.supportsTransitionEnd()&&(t.event.special[l.TRANSITION_END]=i())}(),l}(jQuery),a=(function(t){var e="alert",n=t.fn[e],o={DISMISS:'[data-dismiss="alert"]'},a={CLOSE:"close.bs.alert",CLOSED:"closed.bs.alert",CLICK_DATA_API:"click.bs.alert.data-api"},l={ALERT:"alert",FADE:"fade",SHOW:"show"},c=function(){function e(t){i(this,e),this._element=t}return e.prototype.close=function(t){t=t||this._element;var e=this._getRootElement(t);this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.prototype.dispose=function(){t.removeData(this._element,"bs.alert"),this._element=null},e.prototype._getRootElement=function(e){var n=s.getSelectorFromElement(e),i=!1;return n&&(i=t(n)[0]),i||(i=t(e).closest("."+l.ALERT)[0]),i},e.prototype._triggerCloseEvent=function(e){var n=t.Event(a.CLOSE);return t(e).trigger(n),n},e.prototype._removeElement=function(e){var n=this;if(t(e).removeClass(l.SHOW),!s.supportsTransitionEnd()||!t(e).hasClass(l.FADE))return void this._destroyElement(e);t(e).one(s.TRANSITION_END,function(t){return n._destroyElement(e,t)}).emulateTransitionEnd(150)},e.prototype._destroyElement=function(e){t(e).detach().trigger(a.CLOSED).remove()},e._jQueryInterface=function(n){return this.each(function(){var i=t(this),o=i.data("bs.alert");o||(o=new e(this),i.data("bs.alert",o)),"close"===n&&o[n](this)})},e._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},r(e,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}}]),e}();t(document).on(a.CLICK_DATA_API,o.DISMISS,c._handleDismiss(new c)),t.fn[e]=c._jQueryInterface,t.fn[e].Constructor=c,t.fn[e].noConflict=function(){return t.fn[e]=n,c._jQueryInterface}}(jQuery),function(t){var e="button",n=t.fn[e],o={ACTIVE:"active",BUTTON:"btn",FOCUS:"focus"},s={DATA_TOGGLE_CARROT:'[data-toggle^="button"]',DATA_TOGGLE:'[data-toggle="buttons"]',INPUT:"input",ACTIVE:".active",BUTTON:".btn"},a={CLICK_DATA_API:"click.bs.button.data-api",FOCUS_BLUR_DATA_API:"focus.bs.button.data-api blur.bs.button.data-api"},l=function(){function e(t){i(this,e),this._element=t}return e.prototype.toggle=function(){var e=!0,n=!0,i=t(this._element).closest(s.DATA_TOGGLE)[0];if(i){var r=t(this._element).find(s.INPUT)[0];if(r){if("radio"===r.type)if(r.checked&&t(this._element).hasClass(o.ACTIVE))e=!1;else{var a=t(i).find(s.ACTIVE)[0];a&&t(a).removeClass(o.ACTIVE)}if(e){if(r.hasAttribute("disabled")||i.hasAttribute("disabled")||r.classList.contains("disabled")||i.classList.contains("disabled"))return;r.checked=!t(this._element).hasClass(o.ACTIVE),t(r).trigger("change")}r.focus(),n=!1}}n&&this._element.setAttribute("aria-pressed",!t(this._element).hasClass(o.ACTIVE)),e&&t(this._element).toggleClass(o.ACTIVE)},e.prototype.dispose=function(){t.removeData(this._element,"bs.button"),this._element=null},e._jQueryInterface=function(n){return this.each(function(){var i=t(this).data("bs.button");i||(i=new e(this),t(this).data("bs.button",i)),"toggle"===n&&i[n]()})},r(e,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}}]),e}();t(document).on(a.CLICK_DATA_API,s.DATA_TOGGLE_CARROT,function(e){e.preventDefault();var n=e.target;t(n).hasClass(o.BUTTON)||(n=t(n).closest(s.BUTTON)),l._jQueryInterface.call(t(n),"toggle")}).on(a.FOCUS_BLUR_DATA_API,s.DATA_TOGGLE_CARROT,function(e){var n=t(e.target).closest(s.BUTTON)[0];t(n).toggleClass(o.FOCUS,/^focus(in)?$/.test(e.type))}),t.fn[e]=l._jQueryInterface,t.fn[e].Constructor=l,t.fn[e].noConflict=function(){return t.fn[e]=n,l._jQueryInterface}}(jQuery),function(t){var e="carousel",n="bs.carousel",a="."+n,l=t.fn[e],c={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0},u={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean"},h={NEXT:"next",PREV:"prev",LEFT:"left",RIGHT:"right"},f={SLIDE:"slide"+a,SLID:"slid"+a,KEYDOWN:"keydown"+a,MOUSEENTER:"mouseenter"+a,MOUSELEAVE:"mouseleave"+a,TOUCHEND:"touchend"+a,LOAD_DATA_API:"load.bs.carousel.data-api",CLICK_DATA_API:"click.bs.carousel.data-api"},d={CAROUSEL:"carousel",ACTIVE:"active",SLIDE:"slide",RIGHT:"carousel-item-right",LEFT:"carousel-item-left",NEXT:"carousel-item-next",PREV:"carousel-item-prev",ITEM:"carousel-item"},p={ACTIVE:".active",ACTIVE_ITEM:".active.carousel-item",ITEM:".carousel-item",NEXT_PREV:".carousel-item-next, .carousel-item-prev",INDICATORS:".carousel-indicators",DATA_SLIDE:"[data-slide], [data-slide-to]",DATA_RIDE:'[data-ride="carousel"]'},g=function(){function l(e,n){i(this,l),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this._config=this._getConfig(n),this._element=t(e)[0],this._indicatorsElement=t(this._element).find(p.INDICATORS)[0],this._addEventListeners()}return l.prototype.next=function(){this._isSliding||this._slide(h.NEXT)},l.prototype.nextWhenVisible=function(){document.hidden||this.next()},l.prototype.prev=function(){this._isSliding||this._slide(h.PREV)},l.prototype.pause=function(e){e||(this._isPaused=!0),t(this._element).find(p.NEXT_PREV)[0]&&s.supportsTransitionEnd()&&(s.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},l.prototype.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},l.prototype.to=function(e){var n=this;this._activeElement=t(this._element).find(p.ACTIVE_ITEM)[0];var i=this._getItemIndex(this._activeElement);if(!(e>this._items.length-1||e<0)){if(this._isSliding)return void t(this._element).one(f.SLID,function(){return n.to(e)});if(i===e)return this.pause(),void this.cycle();var o=e>i?h.NEXT:h.PREV;this._slide(o,this._items[e])}},l.prototype.dispose=function(){t(this._element).off(a),t.removeData(this._element,n),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},l.prototype._getConfig=function(n){return n=t.extend({},c,n),s.typeCheckConfig(e,n,u),n},l.prototype._addEventListeners=function(){var e=this;this._config.keyboard&&t(this._element).on(f.KEYDOWN,function(t){return e._keydown(t)}),"hover"===this._config.pause&&(t(this._element).on(f.MOUSEENTER,function(t){return e.pause(t)}).on(f.MOUSELEAVE,function(t){return e.cycle(t)}),"ontouchstart"in document.documentElement&&t(this._element).on(f.TOUCHEND,function(){e.pause(),e.touchTimeout&&clearTimeout(e.touchTimeout),e.touchTimeout=setTimeout(function(t){return e.cycle(t)},500+e._config.interval)}))},l.prototype._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next();break;default:return}},l.prototype._getItemIndex=function(e){return this._items=t.makeArray(t(e).parent().find(p.ITEM)),this._items.indexOf(e)},l.prototype._getItemByDirection=function(t,e){var n=t===h.NEXT,i=t===h.PREV,o=this._getItemIndex(e),r=this._items.length-1;if((i&&0===o||n&&o===r)&&!this._config.wrap)return e;var s=t===h.PREV?-1:1,a=(o+s)%this._items.length;return-1===a?this._items[this._items.length-1]:this._items[a]},l.prototype._triggerSlideEvent=function(e,n){var i=this._getItemIndex(e),o=this._getItemIndex(t(this._element).find(p.ACTIVE_ITEM)[0]),r=t.Event(f.SLIDE,{relatedTarget:e,direction:n,from:o,to:i});return t(this._element).trigger(r),r},l.prototype._setActiveIndicatorElement=function(e){if(this._indicatorsElement){t(this._indicatorsElement).find(p.ACTIVE).removeClass(d.ACTIVE);var n=this._indicatorsElement.children[this._getItemIndex(e)];n&&t(n).addClass(d.ACTIVE)}},l.prototype._slide=function(e,n){var i=this,o=t(this._element).find(p.ACTIVE_ITEM)[0],r=this._getItemIndex(o),a=n||o&&this._getItemByDirection(e,o),l=this._getItemIndex(a),c=Boolean(this._interval),u=void 0,g=void 0,m=void 0;if(e===h.NEXT?(u=d.LEFT,g=d.NEXT,m=h.LEFT):(u=d.RIGHT,g=d.PREV,m=h.RIGHT),a&&t(a).hasClass(d.ACTIVE))return void(this._isSliding=!1);if(!this._triggerSlideEvent(a,m).isDefaultPrevented()&&o&&a){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(a);var _=t.Event(f.SLID,{relatedTarget:a,direction:m,from:r,to:l});s.supportsTransitionEnd()&&t(this._element).hasClass(d.SLIDE)?(t(a).addClass(g),s.reflow(a),t(o).addClass(u),t(a).addClass(u),t(o).one(s.TRANSITION_END,function(){t(a).removeClass(u+" "+g).addClass(d.ACTIVE),t(o).removeClass(d.ACTIVE+" "+g+" "+u),i._isSliding=!1,setTimeout(function(){return t(i._element).trigger(_)},0)}).emulateTransitionEnd(600)):(t(o).removeClass(d.ACTIVE),t(a).addClass(d.ACTIVE),this._isSliding=!1,t(this._element).trigger(_)),c&&this.cycle()}},l._jQueryInterface=function(e){return this.each(function(){var i=t(this).data(n),r=t.extend({},c,t(this).data());"object"===(void 0===e?"undefined":o(e))&&t.extend(r,e);var s="string"==typeof e?e:r.slide;if(i||(i=new l(this,r),t(this).data(n,i)),"number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new Error('No method named "'+s+'"');i[s]()}else r.interval&&(i.pause(),i.cycle())})},l._dataApiClickHandler=function(e){var i=s.getSelectorFromElement(this);if(i){var o=t(i)[0];if(o&&t(o).hasClass(d.CAROUSEL)){var r=t.extend({},t(o).data(),t(this).data()),a=this.getAttribute("data-slide-to");a&&(r.interval=!1),l._jQueryInterface.call(t(o),r),a&&t(o).data(n).to(a),e.preventDefault()}}},r(l,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return c}}]),l}();t(document).on(f.CLICK_DATA_API,p.DATA_SLIDE,g._dataApiClickHandler),t(window).on(f.LOAD_DATA_API,function(){t(p.DATA_RIDE).each(function(){var e=t(this);g._jQueryInterface.call(e,e.data())})}),t.fn[e]=g._jQueryInterface,t.fn[e].Constructor=g,t.fn[e].noConflict=function(){return t.fn[e]=l,g._jQueryInterface}}(jQuery),function(t){var e="collapse",n="bs.collapse",a=t.fn[e],l={toggle:!0,parent:""},c={toggle:"boolean",parent:"string"},u={SHOW:"show.bs.collapse",SHOWN:"shown.bs.collapse",HIDE:"hide.bs.collapse",HIDDEN:"hidden.bs.collapse",CLICK_DATA_API:"click.bs.collapse.data-api"},h={SHOW:"show",COLLAPSE:"collapse",COLLAPSING:"collapsing",COLLAPSED:"collapsed"},f={WIDTH:"width",HEIGHT:"height"},d={ACTIVES:".show, .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},p=function(){function a(e,n){i(this,a),this._isTransitioning=!1,this._element=e,this._config=this._getConfig(n),this._triggerArray=t.makeArray(t('[data-toggle="collapse"][href="#'+e.id+'"],[data-toggle="collapse"][data-target="#'+e.id+'"]'));for(var o=t(d.DATA_TOGGLE),r=0;r<o.length;r++){var l=o[r],c=s.getSelectorFromElement(l);null!==c&&t(c).filter(e).length>0&&this._triggerArray.push(l)}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}return a.prototype.toggle=function(){t(this._element).hasClass(h.SHOW)?this.hide():this.show()},a.prototype.show=function(){var e=this;if(!this._isTransitioning&&!t(this._element).hasClass(h.SHOW)){var i=void 0,o=void 0;if(this._parent&&(i=t.makeArray(t(this._parent).children().children(d.ACTIVES)),i.length||(i=null)),!(i&&(o=t(i).data(n))&&o._isTransitioning)){var r=t.Event(u.SHOW);if(t(this._element).trigger(r),!r.isDefaultPrevented()){i&&(a._jQueryInterface.call(t(i),"hide"),o||t(i).data(n,null));var l=this._getDimension();t(this._element).removeClass(h.COLLAPSE).addClass(h.COLLAPSING),this._element.style[l]=0,this._triggerArray.length&&t(this._triggerArray).removeClass(h.COLLAPSED).attr("aria-expanded",!0),this.setTransitioning(!0);var c=function(){t(e._element).removeClass(h.COLLAPSING).addClass(h.COLLAPSE).addClass(h.SHOW),e._element.style[l]="",e.setTransitioning(!1),t(e._element).trigger(u.SHOWN)};if(!s.supportsTransitionEnd())return void c();var f=l[0].toUpperCase()+l.slice(1),p="scroll"+f;t(this._element).one(s.TRANSITION_END,c).emulateTransitionEnd(600),this._element.style[l]=this._element[p]+"px"}}}},a.prototype.hide=function(){var e=this;if(!this._isTransitioning&&t(this._element).hasClass(h.SHOW)){var n=t.Event(u.HIDE);if(t(this._element).trigger(n),!n.isDefaultPrevented()){var i=this._getDimension();if(this._element.style[i]=this._element.getBoundingClientRect()[i]+"px",s.reflow(this._element),t(this._element).addClass(h.COLLAPSING).removeClass(h.COLLAPSE).removeClass(h.SHOW),this._triggerArray.length)for(var o=0;o<this._triggerArray.length;o++){var r=this._triggerArray[o],a=s.getSelectorFromElement(r);if(null!==a){var l=t(a);l.hasClass(h.SHOW)||t(r).addClass(h.COLLAPSED).attr("aria-expanded",!1)}}this.setTransitioning(!0);var c=function(){e.setTransitioning(!1),t(e._element).removeClass(h.COLLAPSING).addClass(h.COLLAPSE).trigger(u.HIDDEN)};if(this._element.style[i]="",!s.supportsTransitionEnd())return void c();t(this._element).one(s.TRANSITION_END,c).emulateTransitionEnd(600)}}},a.prototype.setTransitioning=function(t){this._isTransitioning=t},a.prototype.dispose=function(){t.removeData(this._element,n),this._config=null,this._parent=null,this._element=null,this._triggerArray=null,this._isTransitioning=null},a.prototype._getConfig=function(n){return n=t.extend({},l,n),n.toggle=Boolean(n.toggle),s.typeCheckConfig(e,n,c),n},a.prototype._getDimension=function(){return t(this._element).hasClass(f.WIDTH)?f.WIDTH:f.HEIGHT},a.prototype._getParent=function(){var e=this,n=t(this._config.parent)[0],i='[data-toggle="collapse"][data-parent="'+this._config.parent+'"]';return t(n).find(i).each(function(t,n){e._addAriaAndCollapsedClass(a._getTargetFromElement(n),[n])}),n},a.prototype._addAriaAndCollapsedClass=function(e,n){if(e){var i=t(e).hasClass(h.SHOW);n.length&&t(n).toggleClass(h.COLLAPSED,!i).attr("aria-expanded",i)}},a._getTargetFromElement=function(e){var n=s.getSelectorFromElement(e);return n?t(n)[0]:null},a._jQueryInterface=function(e){return this.each(function(){var i=t(this),r=i.data(n),s=t.extend({},l,i.data(),"object"===(void 0===e?"undefined":o(e))&&e);if(!r&&s.toggle&&/show|hide/.test(e)&&(s.toggle=!1),r||(r=new a(this,s),i.data(n,r)),"string"==typeof e){if(void 0===r[e])throw new Error('No method named "'+e+'"');r[e]()}})},r(a,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return l}}]),a}();t(document).on(u.CLICK_DATA_API,d.DATA_TOGGLE,function(e){/input|textarea/i.test(e.target.tagName)||e.preventDefault();var i=t(this),o=s.getSelectorFromElement(this);t(o).each(function(){var e=t(this),o=e.data(n),r=o?"toggle":i.data();p._jQueryInterface.call(e,r)})}),t.fn[e]=p._jQueryInterface,t.fn[e].Constructor=p,t.fn[e].noConflict=function(){return t.fn[e]=a,p._jQueryInterface}}(jQuery),function(e){if(void 0===t)throw new Error("Bootstrap dropdown require Popper.js (https://popper.js.org)");var n="dropdown",a="bs.dropdown",l="."+a,c=e.fn[n],u=new RegExp("38|40|27"),h={HIDE:"hide"+l,HIDDEN:"hidden"+l,SHOW:"show"+l,SHOWN:"shown"+l,CLICK:"click"+l,CLICK_DATA_API:"click.bs.dropdown.data-api",KEYDOWN_DATA_API:"keydown.bs.dropdown.data-api",KEYUP_DATA_API:"keyup.bs.dropdown.data-api"},f={DISABLED:"disabled",SHOW:"show",DROPUP:"dropup",MENURIGHT:"dropdown-menu-right",MENULEFT:"dropdown-menu-left"},d={DATA_TOGGLE:'[data-toggle="dropdown"]',FORM_CHILD:".dropdown form",MENU:".dropdown-menu",NAVBAR_NAV:".navbar-nav",VISIBLE_ITEMS:".dropdown-menu .dropdown-item:not(.disabled)"},p={TOP:"top-start",TOPEND:"top-end",BOTTOM:"bottom-start",BOTTOMEND:"bottom-end"},g={placement:p.BOTTOM,offset:0,flip:!0},m={placement:"string",offset:"(number|string)",flip:"boolean"},_=function(){function c(t,e){i(this,c),this._element=t,this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar(),this._addEventListeners()}return c.prototype.toggle=function(){if(!this._element.disabled&&!e(this._element).hasClass(f.DISABLED)){var n=c._getParentFromElement(this._element),i=e(this._menu).hasClass(f.SHOW);if(c._clearMenus(),!i){var o={relatedTarget:this._element},r=e.Event(h.SHOW,o);if(e(n).trigger(r),!r.isDefaultPrevented()){var s=this._element;e(n).hasClass(f.DROPUP)&&(e(this._menu).hasClass(f.MENULEFT)||e(this._menu).hasClass(f.MENURIGHT))&&(s=n),this._popper=new t(s,this._menu,this._getPopperConfig()),"ontouchstart"in document.documentElement&&!e(n).closest(d.NAVBAR_NAV).length&&e("body").children().on("mouseover",null,e.noop),this._element.focus(),this._element.setAttribute("aria-expanded",!0),e(this._menu).toggleClass(f.SHOW),e(n).toggleClass(f.SHOW).trigger(e.Event(h.SHOWN,o))}}}},c.prototype.dispose=function(){e.removeData(this._element,a),e(this._element).off(l),this._element=null,this._menu=null,null!==this._popper&&this._popper.destroy(),this._popper=null},c.prototype.update=function(){this._inNavbar=this._detectNavbar(),null!==this._popper&&this._popper.scheduleUpdate()},c.prototype._addEventListeners=function(){var t=this;e(this._element).on(h.CLICK,function(e){e.preventDefault(),e.stopPropagation(),t.toggle()})},c.prototype._getConfig=function(t){var i=e(this._element).data();return void 0!==i.placement&&(i.placement=p[i.placement.toUpperCase()]),t=e.extend({},this.constructor.Default,e(this._element).data(),t),s.typeCheckConfig(n,t,this.constructor.DefaultType),t},c.prototype._getMenuElement=function(){if(!this._menu){var t=c._getParentFromElement(this._element);this._menu=e(t).find(d.MENU)[0]}return this._menu},c.prototype._getPlacement=function(){var t=e(this._element).parent(),n=this._config.placement;return t.hasClass(f.DROPUP)||this._config.placement===p.TOP?(n=p.TOP,e(this._menu).hasClass(f.MENURIGHT)&&(n=p.TOPEND)):e(this._menu).hasClass(f.MENURIGHT)&&(n=p.BOTTOMEND),n},c.prototype._detectNavbar=function(){return e(this._element).closest(".navbar").length>0},c.prototype._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:{offset:this._config.offset},flip:{enabled:this._config.flip}}};return this._inNavbar&&(t.modifiers.applyStyle={enabled:!this._inNavbar}),t},c._jQueryInterface=function(t){return this.each(function(){var n=e(this).data(a),i="object"===(void 0===t?"undefined":o(t))?t:null;if(n||(n=new c(this,i),e(this).data(a,n)),"string"==typeof t){if(void 0===n[t])throw new Error('No method named "'+t+'"');n[t]()}})},c._clearMenus=function(t){if(!t||3!==t.which&&("keyup"!==t.type||9===t.which))for(var n=e.makeArray(e(d.DATA_TOGGLE)),i=0;i<n.length;i++){var o=c._getParentFromElement(n[i]),r=e(n[i]).data(a),s={relatedTarget:n[i]};if(r){var l=r._menu;if(e(o).hasClass(f.SHOW)&&!(t&&("click"===t.type&&/input|textarea/i.test(t.target.tagName)||"keyup"===t.type&&9===t.which)&&e.contains(o,t.target))){var u=e.Event(h.HIDE,s);e(o).trigger(u),u.isDefaultPrevented()||("ontouchstart"in document.documentElement&&e("body").children().off("mouseover",null,e.noop),n[i].setAttribute("aria-expanded","false"),e(l).removeClass(f.SHOW),e(o).removeClass(f.SHOW).trigger(e.Event(h.HIDDEN,s)))}}}},c._getParentFromElement=function(t){var n=void 0,i=s.getSelectorFromElement(t);return i&&(n=e(i)[0]),n||t.parentNode},c._dataApiKeydownHandler=function(t){if(!(!u.test(t.which)||/button/i.test(t.target.tagName)&&32===t.which||/input|textarea/i.test(t.target.tagName)||(t.preventDefault(),t.stopPropagation(),this.disabled||e(this).hasClass(f.DISABLED)))){var n=c._getParentFromElement(this),i=e(n).hasClass(f.SHOW);if(!i&&(27!==t.which||32!==t.which)||i&&(27===t.which||32===t.which)){if(27===t.which){var o=e(n).find(d.DATA_TOGGLE)[0];e(o).trigger("focus")}return void e(this).trigger("click")}var r=e(n).find(d.VISIBLE_ITEMS).get();if(r.length){var s=r.indexOf(t.target);38===t.which&&s>0&&s--,40===t.which&&s<r.length-1&&s++,s<0&&(s=0),r[s].focus()}}},r(c,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return g}},{key:"DefaultType",get:function(){return m}}]),c}();e(document).on(h.KEYDOWN_DATA_API,d.DATA_TOGGLE,_._dataApiKeydownHandler).on(h.KEYDOWN_DATA_API,d.MENU,_._dataApiKeydownHandler).on(h.CLICK_DATA_API+" "+h.KEYUP_DATA_API,_._clearMenus).on(h.CLICK_DATA_API,d.DATA_TOGGLE,function(t){t.preventDefault(),t.stopPropagation(),_._jQueryInterface.call(e(this),"toggle")}).on(h.CLICK_DATA_API,d.FORM_CHILD,function(t){t.stopPropagation()}),e.fn[n]=_._jQueryInterface,e.fn[n].Constructor=_,e.fn[n].noConflict=function(){return e.fn[n]=c,_._jQueryInterface}}(jQuery),function(t){var e="modal",n=".bs.modal",a=t.fn[e],l={backdrop:!0,keyboard:!0,focus:!0,show:!0},c={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean",show:"boolean"},u={HIDE:"hide.bs.modal",HIDDEN:"hidden.bs.modal",SHOW:"show.bs.modal",SHOWN:"shown.bs.modal",FOCUSIN:"focusin.bs.modal",RESIZE:"resize.bs.modal",CLICK_DISMISS:"click.dismiss.bs.modal",KEYDOWN_DISMISS:"keydown.dismiss.bs.modal",MOUSEUP_DISMISS:"mouseup.dismiss.bs.modal",MOUSEDOWN_DISMISS:"mousedown.dismiss.bs.modal",CLICK_DATA_API:"click.bs.modal.data-api"},h={SCROLLBAR_MEASURER:"modal-scrollbar-measure",BACKDROP:"modal-backdrop",OPEN:"modal-open",FADE:"fade",SHOW:"show"},f={DIALOG:".modal-dialog",DATA_TOGGLE:'[data-toggle="modal"]',DATA_DISMISS:'[data-dismiss="modal"]',FIXED_CONTENT:".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",NAVBAR_TOGGLER:".navbar-toggler"},d=function(){function a(e,n){i(this,a),this._config=this._getConfig(n),this._element=e,this._dialog=t(e).find(f.DIALOG)[0],this._backdrop=null,this._isShown=!1,this._isBodyOverflowing=!1,this._ignoreBackdropClick=!1,this._originalBodyPadding=0,this._scrollbarWidth=0}return a.prototype.toggle=function(t){return this._isShown?this.hide():this.show(t)},a.prototype.show=function(e){var n=this;if(!this._isTransitioning){s.supportsTransitionEnd()&&t(this._element).hasClass(h.FADE)&&(this._isTransitioning=!0);var i=t.Event(u.SHOW,{relatedTarget:e});t(this._element).trigger(i),this._isShown||i.isDefaultPrevented()||(this._isShown=!0,this._checkScrollbar(),this._setScrollbar(),t(document.body).addClass(h.OPEN),this._setEscapeEvent(),this._setResizeEvent(),t(this._element).on(u.CLICK_DISMISS,f.DATA_DISMISS,function(t){return n.hide(t)}),t(this._dialog).on(u.MOUSEDOWN_DISMISS,function(){t(n._element).one(u.MOUSEUP_DISMISS,function(e){t(e.target).is(n._element)&&(n._ignoreBackdropClick=!0)})}),this._showBackdrop(function(){return n._showElement(e)}))}},a.prototype.hide=function(e){var n=this;if(e&&e.preventDefault(),!this._isTransitioning&&this._isShown){var i=s.supportsTransitionEnd()&&t(this._element).hasClass(h.FADE);i&&(this._isTransitioning=!0);var o=t.Event(u.HIDE);t(this._element).trigger(o),this._isShown&&!o.isDefaultPrevented()&&(this._isShown=!1,this._setEscapeEvent(),this._setResizeEvent(),t(document).off(u.FOCUSIN),t(this._element).removeClass(h.SHOW),t(this._element).off(u.CLICK_DISMISS),t(this._dialog).off(u.MOUSEDOWN_DISMISS),i?t(this._element).one(s.TRANSITION_END,function(t){return n._hideModal(t)}).emulateTransitionEnd(300):this._hideModal())}},a.prototype.dispose=function(){t.removeData(this._element,"bs.modal"),t(window,document,this._element,this._backdrop).off(n),this._config=null,this._element=null,this._dialog=null,this._backdrop=null,this._isShown=null,this._isBodyOverflowing=null,this._ignoreBackdropClick=null,this._scrollbarWidth=null},a.prototype.handleUpdate=function(){this._adjustDialog()},a.prototype._getConfig=function(n){return n=t.extend({},l,n),s.typeCheckConfig(e,n,c),n},a.prototype._showElement=function(e){var n=this,i=s.supportsTransitionEnd()&&t(this._element).hasClass(h.FADE);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.scrollTop=0,i&&s.reflow(this._element),t(this._element).addClass(h.SHOW),this._config.focus&&this._enforceFocus();var o=t.Event(u.SHOWN,{relatedTarget:e}),r=function(){n._config.focus&&n._element.focus(),n._isTransitioning=!1,t(n._element).trigger(o)};i?t(this._dialog).one(s.TRANSITION_END,r).emulateTransitionEnd(300):r()},a.prototype._enforceFocus=function(){var e=this;t(document).off(u.FOCUSIN).on(u.FOCUSIN,function(n){document===n.target||e._element===n.target||t(e._element).has(n.target).length||e._element.focus()})},a.prototype._setEscapeEvent=function(){var e=this;this._isShown&&this._config.keyboard?t(this._element).on(u.KEYDOWN_DISMISS,function(t){27===t.which&&(t.preventDefault(),e.hide())}):this._isShown||t(this._element).off(u.KEYDOWN_DISMISS)},a.prototype._setResizeEvent=function(){var e=this;this._isShown?t(window).on(u.RESIZE,function(t){return e.handleUpdate(t)}):t(window).off(u.RESIZE)},a.prototype._hideModal=function(){var e=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._isTransitioning=!1,this._showBackdrop(function(){t(document.body).removeClass(h.OPEN),e._resetAdjustments(),e._resetScrollbar(),t(e._element).trigger(u.HIDDEN)})},a.prototype._removeBackdrop=function(){this._backdrop&&(t(this._backdrop).remove(),this._backdrop=null)},a.prototype._showBackdrop=function(e){var n=this,i=t(this._element).hasClass(h.FADE)?h.FADE:"";if(this._isShown&&this._config.backdrop){var o=s.supportsTransitionEnd()&&i;if(this._backdrop=document.createElement("div"),this._backdrop.className=h.BACKDROP,i&&t(this._backdrop).addClass(i),t(this._backdrop).appendTo(document.body),t(this._element).on(u.CLICK_DISMISS,function(t){if(n._ignoreBackdropClick)return void(n._ignoreBackdropClick=!1);t.target===t.currentTarget&&("static"===n._config.backdrop?n._element.focus():n.hide())}),o&&s.reflow(this._backdrop),t(this._backdrop).addClass(h.SHOW),!e)return;if(!o)return void e();t(this._backdrop).one(s.TRANSITION_END,e).emulateTransitionEnd(150)}else if(!this._isShown&&this._backdrop){t(this._backdrop).removeClass(h.SHOW);var r=function(){n._removeBackdrop(),e&&e()};s.supportsTransitionEnd()&&t(this._element).hasClass(h.FADE)?t(this._backdrop).one(s.TRANSITION_END,r).emulateTransitionEnd(150):r()}else e&&e()},a.prototype._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},a.prototype._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},a.prototype._checkScrollbar=function(){this._isBodyOverflowing=document.body.clientWidth<window.innerWidth,this._scrollbarWidth=this._getScrollbarWidth()},a.prototype._setScrollbar=function(){var e=this;if(this._isBodyOverflowing){t(f.FIXED_CONTENT).each(function(n,i){var o=t(i)[0].style.paddingRight,r=t(i).css("padding-right");t(i).data("padding-right",o).css("padding-right",parseFloat(r)+e._scrollbarWidth+"px")}),t(f.NAVBAR_TOGGLER).each(function(n,i){var o=t(i)[0].style.marginRight,r=t(i).css("margin-right");t(i).data("margin-right",o).css("margin-right",parseFloat(r)+e._scrollbarWidth+"px")});var n=document.body.style.paddingRight,i=t("body").css("padding-right");t("body").data("padding-right",n).css("padding-right",parseFloat(i)+this._scrollbarWidth+"px")}},a.prototype._resetScrollbar=function(){t(f.FIXED_CONTENT).each(function(e,n){var i=t(n).data("padding-right");void 0!==i&&t(n).css("padding-right",i).removeData("padding-right")}),t(f.NAVBAR_TOGGLER).each(function(e,n){var i=t(n).data("margin-right");void 0!==i&&t(n).css("margin-right",i).removeData("margin-right")});var e=t("body").data("padding-right");void 0!==e&&t("body").css("padding-right",e).removeData("padding-right")},a.prototype._getScrollbarWidth=function(){var t=document.createElement("div");t.className=h.SCROLLBAR_MEASURER,document.body.appendChild(t);var e=t.getBoundingClientRect().width-t.clientWidth;return document.body.removeChild(t),e},a._jQueryInterface=function(e,n){return this.each(function(){var i=t(this).data("bs.modal"),r=t.extend({},a.Default,t(this).data(),"object"===(void 0===e?"undefined":o(e))&&e);if(i||(i=new a(this,r),t(this).data("bs.modal",i)),"string"==typeof e){if(void 0===i[e])throw new Error('No method named "'+e+'"');i[e](n)}else r.show&&i.show(n)})},r(a,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return l}}]),a}();t(document).on(u.CLICK_DATA_API,f.DATA_TOGGLE,function(e){var n=this,i=void 0,o=s.getSelectorFromElement(this);o&&(i=t(o)[0]);var r=t(i).data("bs.modal")?"toggle":t.extend({},t(i).data(),t(this).data());"A"!==this.tagName&&"AREA"!==this.tagName||e.preventDefault();var a=t(i).one(u.SHOW,function(e){e.isDefaultPrevented()||a.one(u.HIDDEN,function(){t(n).is(":visible")&&n.focus()})});d._jQueryInterface.call(t(i),r,this)}),t.fn[e]=d._jQueryInterface,t.fn[e].Constructor=d,t.fn[e].noConflict=function(){return t.fn[e]=a,d._jQueryInterface}}(jQuery),function(t){var e="scrollspy",n=t.fn[e],a={offset:10,method:"auto",target:""},l={offset:"number",method:"string",target:"(string|element)"},c={ACTIVATE:"activate.bs.scrollspy",SCROLL:"scroll.bs.scrollspy",LOAD_DATA_API:"load.bs.scrollspy.data-api"},u={DROPDOWN_ITEM:"dropdown-item",DROPDOWN_MENU:"dropdown-menu",ACTIVE:"active"},h={DATA_SPY:'[data-spy="scroll"]',ACTIVE:".active",NAV_LIST_GROUP:".nav, .list-group",NAV_LINKS:".nav-link",LIST_ITEMS:".list-group-item",DROPDOWN:".dropdown",DROPDOWN_ITEMS:".dropdown-item",DROPDOWN_TOGGLE:".dropdown-toggle"},f={OFFSET:"offset",POSITION:"position"},d=function(){function n(e,o){var r=this;i(this,n),this._element=e,this._scrollElement="BODY"===e.tagName?window:e,this._config=this._getConfig(o),this._selector=this._config.target+" "+h.NAV_LINKS+","+this._config.target+" "+h.LIST_ITEMS+","+this._config.target+" "+h.DROPDOWN_ITEMS,this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,t(this._scrollElement).on(c.SCROLL,function(t){return r._process(t)}),this.refresh(),this._process()}return n.prototype.refresh=function(){var e=this,n=this._scrollElement!==this._scrollElement.window?f.POSITION:f.OFFSET,i="auto"===this._config.method?n:this._config.method,o=i===f.POSITION?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),t.makeArray(t(this._selector)).map(function(e){var n=void 0,r=s.getSelectorFromElement(e);if(r&&(n=t(r)[0]),n){var a=n.getBoundingClientRect();if(a.width||a.height)return[t(n)[i]().top+o,r]}return null}).filter(function(t){return t}).sort(function(t,e){return t[0]-e[0]}).forEach(function(t){e._offsets.push(t[0]),e._targets.push(t[1])})},n.prototype.dispose=function(){t.removeData(this._element,"bs.scrollspy"),t(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},n.prototype._getConfig=function(n){if(n=t.extend({},a,n),"string"!=typeof n.target){var i=t(n.target).attr("id");i||(i=s.getUID(e),t(n.target).attr("id",i)),n.target="#"+i}return s.typeCheckConfig(e,n,l),n},n.prototype._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},n.prototype._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},n.prototype._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},n.prototype._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];return void(this._activeTarget!==i&&this._activate(i))}if(this._activeTarget&&t<this._offsets[0]&&this._offsets[0]>0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;){this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&(void 0===this._offsets[o+1]||t<this._offsets[o+1])&&this._activate(this._targets[o])}},n.prototype._activate=function(e){this._activeTarget=e,this._clear();var n=this._selector.split(",");n=n.map(function(t){return t+'[data-target="'+e+'"],'+t+'[href="'+e+'"]'});var i=t(n.join(","));i.hasClass(u.DROPDOWN_ITEM)?(i.closest(h.DROPDOWN).find(h.DROPDOWN_TOGGLE).addClass(u.ACTIVE),i.addClass(u.ACTIVE)):(i.addClass(u.ACTIVE),i.parents(h.NAV_LIST_GROUP).prev(h.NAV_LINKS+", "+h.LIST_ITEMS).addClass(u.ACTIVE)),t(this._scrollElement).trigger(c.ACTIVATE,{relatedTarget:e})},n.prototype._clear=function(){t(this._selector).filter(h.ACTIVE).removeClass(u.ACTIVE)},n._jQueryInterface=function(e){return this.each(function(){var i=t(this).data("bs.scrollspy"),r="object"===(void 0===e?"undefined":o(e))&&e;if(i||(i=new n(this,r),t(this).data("bs.scrollspy",i)),"string"==typeof e){if(void 0===i[e])throw new Error('No method named "'+e+'"');i[e]()}})},r(n,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return a}}]),n}();t(window).on(c.LOAD_DATA_API,function(){for(var e=t.makeArray(t(h.DATA_SPY)),n=e.length;n--;){var i=t(e[n]);d._jQueryInterface.call(i,i.data())}}),t.fn[e]=d._jQueryInterface,t.fn[e].Constructor=d,t.fn[e].noConflict=function(){return t.fn[e]=n,d._jQueryInterface}}(jQuery),function(t){var e=t.fn.tab,n={HIDE:"hide.bs.tab",HIDDEN:"hidden.bs.tab",SHOW:"show.bs.tab",SHOWN:"shown.bs.tab",CLICK_DATA_API:"click.bs.tab.data-api"},o={DROPDOWN_MENU:"dropdown-menu",ACTIVE:"active",DISABLED:"disabled",FADE:"fade",SHOW:"show"},a={DROPDOWN:".dropdown",NAV_LIST_GROUP:".nav, .list-group",ACTIVE:".active",DATA_TOGGLE:'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',DROPDOWN_TOGGLE:".dropdown-toggle",DROPDOWN_ACTIVE_CHILD:"> .dropdown-menu .active"},l=function(){function e(t){i(this,e),this._element=t}return e.prototype.show=function(){var e=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&t(this._element).hasClass(o.ACTIVE)||t(this._element).hasClass(o.DISABLED))){var i=void 0,r=void 0,l=t(this._element).closest(a.NAV_LIST_GROUP)[0],c=s.getSelectorFromElement(this._element);l&&(r=t.makeArray(t(l).find(a.ACTIVE)),r=r[r.length-1]);var u=t.Event(n.HIDE,{relatedTarget:this._element}),h=t.Event(n.SHOW,{relatedTarget:r});if(r&&t(r).trigger(u),t(this._element).trigger(h),!h.isDefaultPrevented()&&!u.isDefaultPrevented()){c&&(i=t(c)[0]),this._activate(this._element,l);var f=function(){var i=t.Event(n.HIDDEN,{relatedTarget:e._element}),o=t.Event(n.SHOWN,{relatedTarget:r});t(r).trigger(i),t(e._element).trigger(o)};i?this._activate(i,i.parentNode,f):f()}}},e.prototype.dispose=function(){t.removeData(this._element,"bs.tab"),this._element=null},e.prototype._activate=function(e,n,i){var r=this,l=t(n).find(a.ACTIVE)[0],c=i&&s.supportsTransitionEnd()&&l&&t(l).hasClass(o.FADE),u=function(){return r._transitionComplete(e,l,c,i)};l&&c?t(l).one(s.TRANSITION_END,u).emulateTransitionEnd(150):u(),l&&t(l).removeClass(o.SHOW)},e.prototype._transitionComplete=function(e,n,i,r){if(n){t(n).removeClass(o.ACTIVE);var l=t(n.parentNode).find(a.DROPDOWN_ACTIVE_CHILD)[0];l&&t(l).removeClass(o.ACTIVE),n.setAttribute("aria-expanded",!1)}if(t(e).addClass(o.ACTIVE),e.setAttribute("aria-expanded",!0),i?(s.reflow(e),t(e).addClass(o.SHOW)):t(e).removeClass(o.FADE),e.parentNode&&t(e.parentNode).hasClass(o.DROPDOWN_MENU)){var c=t(e).closest(a.DROPDOWN)[0];c&&t(c).find(a.DROPDOWN_TOGGLE).addClass(o.ACTIVE),e.setAttribute("aria-expanded",!0)}r&&r()},e._jQueryInterface=function(n){return this.each(function(){var i=t(this),o=i.data("bs.tab");if(o||(o=new e(this),i.data("bs.tab",o)),"string"==typeof n){if(void 0===o[n])throw new Error('No method named "'+n+'"');o[n]()}})},r(e,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}}]),e}();t(document).on(n.CLICK_DATA_API,a.DATA_TOGGLE,function(e){e.preventDefault(),l._jQueryInterface.call(t(this),"show")}),t.fn.tab=l._jQueryInterface,t.fn.tab.Constructor=l,t.fn.tab.noConflict=function(){return t.fn.tab=e,l._jQueryInterface}}(jQuery),function(e){if(void 0===t)throw new Error("Bootstrap tooltips require Popper.js (https://popper.js.org)");var n="tooltip",a=".bs.tooltip",l=e.fn[n],c=new RegExp("(^|\\s)bs-tooltip\\S+","g"),u={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)"},h={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"},f={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip"},d={SHOW:"show",OUT:"out"},p={HIDE:"hide"+a,HIDDEN:"hidden"+a,SHOW:"show"+a,SHOWN:"shown"+a,INSERTED:"inserted"+a,CLICK:"click"+a,FOCUSIN:"focusin"+a,FOCUSOUT:"focusout"+a,MOUSEENTER:"mouseenter"+a,MOUSELEAVE:"mouseleave"+a},g={FADE:"fade",SHOW:"show"},m={TOOLTIP:".tooltip",TOOLTIP_INNER:".tooltip-inner",ARROW:".arrow"},_={HOVER:"hover",FOCUS:"focus",CLICK:"click",MANUAL:"manual"},v=function(){function l(t,e){i(this,l),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}return l.prototype.enable=function(){this._isEnabled=!0},l.prototype.disable=function(){this._isEnabled=!1},l.prototype.toggleEnabled=function(){this._isEnabled=!this._isEnabled},l.prototype.toggle=function(t){if(t){var n=this.constructor.DATA_KEY,i=e(t.currentTarget).data(n);i||(i=new this.constructor(t.currentTarget,this._getDelegateConfig()),e(t.currentTarget).data(n,i)),i._activeTrigger.click=!i._activeTrigger.click,i._isWithActiveTrigger()?i._enter(null,i):i._leave(null,i)}else{if(e(this.getTipElement()).hasClass(g.SHOW))return void this._leave(null,this);this._enter(null,this)}},l.prototype.dispose=function(){clearTimeout(this._timeout),e.removeData(this.element,this.constructor.DATA_KEY),e(this.element).off(this.constructor.EVENT_KEY),e(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&e(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,null!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},l.prototype.show=function(){var n=this;if("none"===e(this.element).css("display"))throw new Error("Please use show on visible elements");var i=e.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){e(this.element).trigger(i);var o=e.contains(this.element.ownerDocument.documentElement,this.element);if(i.isDefaultPrevented()||!o)return;var r=this.getTipElement(),a=s.getUID(this.constructor.NAME);r.setAttribute("id",a),this.element.setAttribute("aria-describedby",a),this.setContent(),this.config.animation&&e(r).addClass(g.FADE);var c="function"==typeof this.config.placement?this.config.placement.call(this,r,this.element):this.config.placement,u=this._getAttachment(c);this.addAttachmentClass(u);var h=!1===this.config.container?document.body:e(this.config.container);e(r).data(this.constructor.DATA_KEY,this),e.contains(this.element.ownerDocument.documentElement,this.tip)||e(r).appendTo(h),e(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new t(this.element,r,{placement:u,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:m.ARROW}},onCreate:function(t){t.originalPlacement!==t.placement&&n._handlePopperPlacementChange(t)},onUpdate:function(t){n._handlePopperPlacementChange(t)}}),e(r).addClass(g.SHOW),"ontouchstart"in document.documentElement&&e("body").children().on("mouseover",null,e.noop);var f=function(){n.config.animation&&n._fixTransition();var t=n._hoverState;n._hoverState=null,e(n.element).trigger(n.constructor.Event.SHOWN),t===d.OUT&&n._leave(null,n)};s.supportsTransitionEnd()&&e(this.tip).hasClass(g.FADE)?e(this.tip).one(s.TRANSITION_END,f).emulateTransitionEnd(l._TRANSITION_DURATION):f()}},l.prototype.hide=function(t){var n=this,i=this.getTipElement(),o=e.Event(this.constructor.Event.HIDE),r=function(){n._hoverState!==d.SHOW&&i.parentNode&&i.parentNode.removeChild(i),n._cleanTipClass(),n.element.removeAttribute("aria-describedby"),e(n.element).trigger(n.constructor.Event.HIDDEN),null!==n._popper&&n._popper.destroy(),t&&t()};e(this.element).trigger(o),o.isDefaultPrevented()||(e(i).removeClass(g.SHOW),"ontouchstart"in document.documentElement&&e("body").children().off("mouseover",null,e.noop),this._activeTrigger[_.CLICK]=!1,this._activeTrigger[_.FOCUS]=!1,this._activeTrigger[_.HOVER]=!1,s.supportsTransitionEnd()&&e(this.tip).hasClass(g.FADE)?e(i).one(s.TRANSITION_END,r).emulateTransitionEnd(150):r(),this._hoverState="")},l.prototype.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},l.prototype.isWithContent=function(){return Boolean(this.getTitle())},l.prototype.addAttachmentClass=function(t){e(this.getTipElement()).addClass("bs-tooltip-"+t)},l.prototype.getTipElement=function(){return this.tip=this.tip||e(this.config.template)[0]},l.prototype.setContent=function(){var t=e(this.getTipElement());this.setElementContent(t.find(m.TOOLTIP_INNER),this.getTitle()),t.removeClass(g.FADE+" "+g.SHOW)},l.prototype.setElementContent=function(t,n){var i=this.config.html;"object"===(void 0===n?"undefined":o(n))&&(n.nodeType||n.jquery)?i?e(n).parent().is(t)||t.empty().append(n):t.text(e(n).text()):t[i?"html":"text"](n)},l.prototype.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},l.prototype._getAttachment=function(t){return h[t.toUpperCase()]},l.prototype._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach(function(n){if("click"===n)e(t.element).on(t.constructor.Event.CLICK,t.config.selector,function(e){return t.toggle(e)});else if(n!==_.MANUAL){var i=n===_.HOVER?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,o=n===_.HOVER?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;e(t.element).on(i,t.config.selector,function(e){return t._enter(e)}).on(o,t.config.selector,function(e){return t._leave(e)})}e(t.element).closest(".modal").on("hide.bs.modal",function(){return t.hide()})}),this.config.selector?this.config=e.extend({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},l.prototype._fixTitle=function(){var t=o(this.element.getAttribute("data-original-title"));(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},l.prototype._enter=function(t,n){var i=this.constructor.DATA_KEY;return n=n||e(t.currentTarget).data(i),n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),e(t.currentTarget).data(i,n)),t&&(n._activeTrigger["focusin"===t.type?_.FOCUS:_.HOVER]=!0),e(n.getTipElement()).hasClass(g.SHOW)||n._hoverState===d.SHOW?void(n._hoverState=d.SHOW):(clearTimeout(n._timeout),n._hoverState=d.SHOW,n.config.delay&&n.config.delay.show?void(n._timeout=setTimeout(function(){n._hoverState===d.SHOW&&n.show()},n.config.delay.show)):void n.show())},l.prototype._leave=function(t,n){var i=this.constructor.DATA_KEY;if(n=n||e(t.currentTarget).data(i),n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),e(t.currentTarget).data(i,n)),t&&(n._activeTrigger["focusout"===t.type?_.FOCUS:_.HOVER]=!1),!n._isWithActiveTrigger()){if(clearTimeout(n._timeout),n._hoverState=d.OUT,!n.config.delay||!n.config.delay.hide)return void n.hide();n._timeout=setTimeout(function(){n._hoverState===d.OUT&&n.hide()},n.config.delay.hide)}},l.prototype._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},l.prototype._getConfig=function(t){return t=e.extend({},this.constructor.Default,e(this.element).data(),t),t.delay&&"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),t.title&&"number"==typeof t.title&&(t.title=t.title.toString()),t.content&&"number"==typeof t.content&&(t.content=t.content.toString()),s.typeCheckConfig(n,t,this.constructor.DefaultType),t},l.prototype._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},l.prototype._cleanTipClass=function(){var t=e(this.getTipElement()),n=t.attr("class").match(c);null!==n&&n.length>0&&t.removeClass(n.join(""))},l.prototype._handlePopperPlacementChange=function(t){this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},l.prototype._fixTransition=function(){var t=this.getTipElement(),n=this.config.animation;null===t.getAttribute("x-placement")&&(e(t).removeClass(g.FADE),this.config.animation=!1,this.hide(),this.show(),this.config.animation=n)},l._jQueryInterface=function(t){return this.each(function(){var n=e(this).data("bs.tooltip"),i="object"===(void 0===t?"undefined":o(t))&&t;if((n||!/dispose|hide/.test(t))&&(n||(n=new l(this,i),e(this).data("bs.tooltip",n)),"string"==typeof t)){if(void 0===n[t])throw new Error('No method named "'+t+'"');n[t]()}})},r(l,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return f}},{key:"NAME",get:function(){return n}},{key:"DATA_KEY",get:function(){return"bs.tooltip"}},{key:"Event",get:function(){return p}},{key:"EVENT_KEY",get:function(){return a}},{key:"DefaultType",get:function(){return u}}]),l}();return e.fn[n]=v._jQueryInterface,e.fn[n].Constructor=v,e.fn[n].noConflict=function(){return e.fn[n]=l,v._jQueryInterface},v}(jQuery));!function(t){var s="popover",l=".bs.popover",c=t.fn[s],u=new RegExp("(^|\\s)bs-popover\\S+","g"),h=t.extend({},a.Default,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'}),f=t.extend({},a.DefaultType,{content:"(string|element|function)"}),d={FADE:"fade",SHOW:"show"},p={TITLE:".popover-header",CONTENT:".popover-body"},g={HIDE:"hide"+l,HIDDEN:"hidden"+l,SHOW:"show"+l,SHOWN:"shown"+l,INSERTED:"inserted"+l,CLICK:"click"+l,FOCUSIN:"focusin"+l,FOCUSOUT:"focusout"+l,MOUSEENTER:"mouseenter"+l,MOUSELEAVE:"mouseleave"+l},m=function(a){function c(){return i(this,c),e(this,a.apply(this,arguments))}return n(c,a),c.prototype.isWithContent=function(){return this.getTitle()||this._getContent()},c.prototype.addAttachmentClass=function(e){t(this.getTipElement()).addClass("bs-popover-"+e)},c.prototype.getTipElement=function(){return this.tip=this.tip||t(this.config.template)[0]},c.prototype.setContent=function(){var e=t(this.getTipElement());this.setElementContent(e.find(p.TITLE),this.getTitle()),this.setElementContent(e.find(p.CONTENT),this._getContent()),e.removeClass(d.FADE+" "+d.SHOW)},c.prototype._getContent=function(){return this.element.getAttribute("data-content")||("function"==typeof this.config.content?this.config.content.call(this.element):this.config.content)},c.prototype._cleanTipClass=function(){var e=t(this.getTipElement()),n=e.attr("class").match(u);null!==n&&n.length>0&&e.removeClass(n.join(""))},c._jQueryInterface=function(e){return this.each(function(){var n=t(this).data("bs.popover"),i="object"===(void 0===e?"undefined":o(e))?e:null;if((n||!/destroy|hide/.test(e))&&(n||(n=new c(this,i),t(this).data("bs.popover",n)),"string"==typeof e)){if(void 0===n[e])throw new Error('No method named "'+e+'"');n[e]()}})},r(c,null,[{key:"VERSION",get:function(){return"4.0.0-beta"}},{key:"Default",get:function(){return h}},{key:"NAME",get:function(){return s}},{key:"DATA_KEY",get:function(){return"bs.popover"}},{key:"Event",get:function(){return g}},{key:"EVENT_KEY",get:function(){return l}},{key:"DefaultType",get:function(){return f}}]),c}(a);t.fn[s]=m._jQueryInterface,t.fn[s].Constructor=m,t.fn[s].noConflict=function(){return t.fn[s]=c,m._jQueryInterface}}(jQuery)}()}).call(e,n(3).default)},function(t,e){},function(t,e,n){"use strict";n(0),n(1)},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),function(t){function n(t){var e=!1,n=0,i=document.createElement("span");return new MutationObserver(function(){t(),e=!1}).observe(i,{attributes:!0}),function(){e||(e=!0,i.setAttribute("x-index",n),n+=1)}}function i(t){var e=!1;return function(){e||(e=!0,setTimeout(function(){e=!1,t()},ct))}}function o(t){var e={};return t&&"[object Function]"===e.toString.call(t)}function r(t,e){if(1!==t.nodeType)return[];var n=window.getComputedStyle(t,null);return e?n[e]:n}function s(t){return"HTML"===t.nodeName?t:t.parentNode||t.host}function a(t){if(!t||-1!==["HTML","BODY","#document"].indexOf(t.nodeName))return window.document.body;var e=r(t),n=e.overflow,i=e.overflowX;return/(auto|scroll)/.test(n+e.overflowY+i)?t:a(s(t))}function l(t){var e=t&&t.offsetParent,n=e&&e.nodeName;return n&&"BODY"!==n&&"HTML"!==n?-1!==["TD","TABLE"].indexOf(e.nodeName)&&"static"===r(e,"position")?l(e):e:window.document.documentElement}function c(t){var e=t.nodeName;return"BODY"!==e&&("HTML"===e||l(t.firstElementChild)===t)}function u(t){return null!==t.parentNode?u(t.parentNode):t}function h(t,e){if(!(t&&t.nodeType&&e&&e.nodeType))return window.document.documentElement;var n=t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING,i=n?t:e,o=n?e:t,r=document.createRange();r.setStart(i,0),r.setEnd(o,0);var s=r.commonAncestorContainer;if(t!==s&&e!==s||i.contains(o))return c(s)?s:l(s);var a=u(t);return a.host?h(a.host,e):h(t,u(e).host)}function f(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"top",n="top"===e?"scrollTop":"scrollLeft",i=t.nodeName;if("BODY"===i||"HTML"===i){var o=window.document.documentElement;return(window.document.scrollingElement||o)[n]}return t[n]}function d(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=f(e,"top"),o=f(e,"left"),r=n?-1:1;return t.top+=i*r,t.bottom+=i*r,t.left+=o*r,t.right+=o*r,t}function p(t,e){var n="x"===e?"Left":"Top",i="Left"===n?"Right":"Bottom";return+t["border"+n+"Width"].split("px")[0]+ +t["border"+i+"Width"].split("px")[0]}function g(t,e,n,i){return Math.max(e["offset"+t],e["scroll"+t],n["client"+t],n["offset"+t],n["scroll"+t],pt()?n["offset"+t]+i["margin"+("Height"===t?"Top":"Left")]+i["margin"+("Height"===t?"Bottom":"Right")]:0)}function m(){var t=window.document.body,e=window.document.documentElement,n=pt()&&window.getComputedStyle(e);return{height:g("Height",t,e,n),width:g("Width",t,e,n)}}function _(t){return vt({},t,{right:t.left+t.width,bottom:t.top+t.height})}function v(t){var e={};if(pt())try{e=t.getBoundingClientRect();var n=f(t,"top"),i=f(t,"left");e.top+=n,e.left+=i,e.bottom+=n,e.right+=i}catch(t){}else e=t.getBoundingClientRect();var o={left:e.left,top:e.top,width:e.right-e.left,height:e.bottom-e.top},s="HTML"===t.nodeName?m():{},a=s.width||t.clientWidth||o.right-o.left,l=s.height||t.clientHeight||o.bottom-o.top,c=t.offsetWidth-a,u=t.offsetHeight-l;if(c||u){var h=r(t);c-=p(h,"x"),u-=p(h,"y"),o.width-=c,o.height-=u}return _(o)}function E(t,e){var n=pt(),i="HTML"===e.nodeName,o=v(t),s=v(e),l=a(t),c=r(e),u=+c.borderTopWidth.split("px")[0],h=+c.borderLeftWidth.split("px")[0],f=_({top:o.top-s.top-u,left:o.left-s.left-h,width:o.width,height:o.height});if(f.marginTop=0,f.marginLeft=0,!n&&i){var p=+c.marginTop.split("px")[0],g=+c.marginLeft.split("px")[0];f.top-=u-p,f.bottom-=u-p,f.left-=h-g,f.right-=h-g,f.marginTop=p,f.marginLeft=g}return(n?e.contains(l):e===l&&"BODY"!==l.nodeName)&&(f=d(f,e)),f}function T(t){var e=window.document.documentElement,n=E(t,e),i=Math.max(e.clientWidth,window.innerWidth||0),o=Math.max(e.clientHeight,window.innerHeight||0),r=f(e),s=f(e,"left");return _({top:r-n.top+n.marginTop,left:s-n.left+n.marginLeft,width:i,height:o})}function y(t){var e=t.nodeName;return"BODY"!==e&&"HTML"!==e&&("fixed"===r(t,"position")||y(s(t)))}function b(t,e,n,i){var o={top:0,left:0},r=h(t,e);if("viewport"===i)o=T(r);else{var l=void 0;"scrollParent"===i?(l=a(s(t)),"BODY"===l.nodeName&&(l=window.document.documentElement)):l="window"===i?window.document.documentElement:i;var c=E(l,r);if("HTML"!==l.nodeName||y(r))o=c;else{var u=m(),f=u.height,d=u.width;o.top+=c.top-c.marginTop,o.bottom=f+c.top,o.left+=c.left-c.marginLeft,o.right=d+c.left}}return o.left+=n,o.top+=n,o.right-=n,o.bottom-=n,o}function C(t){return t.width*t.height}function A(t,e,n,i,o){var r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0;if(-1===t.indexOf("auto"))return t;var s=b(n,i,r,o),a={top:{width:s.width,height:e.top-s.top},right:{width:s.right-e.right,height:s.height},bottom:{width:s.width,height:s.bottom-e.bottom},left:{width:e.left-s.left,height:s.height}},l=Object.keys(a).map(function(t){return vt({key:t},a[t],{area:C(a[t])})}).sort(function(t,e){return e.area-t.area}),c=l.filter(function(t){var e=t.width,i=t.height;return e>=n.clientWidth&&i>=n.clientHeight}),u=c.length>0?c[0].key:l[0].key,h=t.split("-")[1];return u+(h?"-"+h:"")}function O(t,e,n){return E(n,h(e,n))}function I(t){var e=window.getComputedStyle(t),n=parseFloat(e.marginTop)+parseFloat(e.marginBottom),i=parseFloat(e.marginLeft)+parseFloat(e.marginRight);return{width:t.offsetWidth+i,height:t.offsetHeight+n}}function w(t){var e={left:"right",right:"left",bottom:"top",top:"bottom"};return t.replace(/left|right|bottom|top/g,function(t){return e[t]})}function D(t,e,n){n=n.split("-")[0];var i=I(t),o={width:i.width,height:i.height},r=-1!==["right","left"].indexOf(n),s=r?"top":"left",a=r?"left":"top",l=r?"height":"width",c=r?"width":"height";return o[s]=e[s]+e[l]/2-i[l]/2,o[a]=n===a?e[a]-i[c]:e[w(a)],o}function S(t,e){return Array.prototype.find?t.find(e):t.filter(e)[0]}function N(t,e,n){if(Array.prototype.findIndex)return t.findIndex(function(t){return t[e]===n});var i=S(t,function(t){return t[e]===n});return t.indexOf(i)}function L(t,e,n){return(void 0===n?t:t.slice(0,N(t,"name",n))).forEach(function(t){t.function&&console.warn("`modifier.function` is deprecated, use `modifier.fn`!");var n=t.function||t.fn;t.enabled&&o(n)&&(e.offsets.popper=_(e.offsets.popper),e.offsets.reference=_(e.offsets.reference),e=n(e,t))}),e}function P(){if(!this.state.isDestroyed){var t={instance:this,styles:{},arrowStyles:{},attributes:{},flipped:!1,offsets:{}};t.offsets.reference=O(this.state,this.popper,this.reference),t.placement=A(this.options.placement,t.offsets.reference,this.popper,this.reference,this.options.modifiers.flip.boundariesElement,this.options.modifiers.flip.padding),t.originalPlacement=t.placement,t.offsets.popper=D(this.popper,t.offsets.reference,t.placement),t.offsets.popper.position="absolute",t=L(this.modifiers,t),this.state.isCreated?this.options.onUpdate(t):(this.state.isCreated=!0,this.options.onCreate(t))}}function R(t,e){return t.some(function(t){var n=t.name;return t.enabled&&n===e})}function H(t){for(var e=[!1,"ms","Webkit","Moz","O"],n=t.charAt(0).toUpperCase()+t.slice(1),i=0;i<e.length-1;i++){var o=e[i],r=o?""+o+n:t;if(void 0!==window.document.body.style[r])return r}return null}function k(){return this.state.isDestroyed=!0,R(this.modifiers,"applyStyle")&&(this.popper.removeAttribute("x-placement"),this.popper.style.left="",this.popper.style.position="",this.popper.style.top="",this.popper.style[H("transform")]=""),this.disableEventListeners(),this.options.removeOnDestroy&&this.popper.parentNode.removeChild(this.popper),this}function W(t,e,n,i){var o="BODY"===t.nodeName,r=o?window:t;r.addEventListener(e,n,{passive:!0}),o||W(a(r.parentNode),e,n,i),i.push(r)}function x(t,e,n,i){n.updateBound=i,window.addEventListener("resize",n.updateBound,{passive:!0});var o=a(t);return W(o,"scroll",n.updateBound,n.scrollParents),n.scrollElement=o,n.eventsEnabled=!0,n}function M(){this.state.eventsEnabled||(this.state=x(this.reference,this.options,this.state,this.scheduleUpdate))}function U(t,e){return window.removeEventListener("resize",e.updateBound),e.scrollParents.forEach(function(t){t.removeEventListener("scroll",e.updateBound)}),e.updateBound=null,e.scrollParents=[],e.scrollElement=null,e.eventsEnabled=!1,e}function j(){this.state.eventsEnabled&&(window.cancelAnimationFrame(this.scheduleUpdate),this.state=U(this.reference,this.state))}function V(t){return""!==t&&!isNaN(parseFloat(t))&&isFinite(t)}function F(t,e){Object.keys(e).forEach(function(n){var i="";-1!==["width","height","top","right","bottom","left"].indexOf(n)&&V(e[n])&&(i="px"),t.style[n]=e[n]+i})}function B(t,e){Object.keys(e).forEach(function(n){!1!==e[n]?t.setAttribute(n,e[n]):t.removeAttribute(n)})}function G(t){return F(t.instance.popper,t.styles),B(t.instance.popper,t.attributes),t.arrowElement&&Object.keys(t.arrowStyles).length&&F(t.arrowElement,t.arrowStyles),t}function K(t,e,n,i,o){var r=O(o,e,t),s=A(n.placement,r,e,t,n.modifiers.flip.boundariesElement,n.modifiers.flip.padding);return e.setAttribute("x-placement",s),F(e,{position:"absolute"}),n}function Q(t,e){var n=e.x,i=e.y,o=t.offsets.popper,r=S(t.instance.modifiers,function(t){return"applyStyle"===t.name}).gpuAcceleration;void 0!==r&&console.warn("WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!");var s=void 0!==r?r:e.gpuAcceleration,a=l(t.instance.popper),c=v(a),u={position:o.position},h={left:Math.floor(o.left),top:Math.floor(o.top),bottom:Math.floor(o.bottom),right:Math.floor(o.right)},f="bottom"===n?"top":"bottom",d="right"===i?"left":"right",p=H("transform"),g=void 0,m=void 0;if(m="bottom"===f?-c.height+h.bottom:h.top,g="right"===d?-c.width+h.right:h.left,s&&p)u[p]="translate3d("+g+"px, "+m+"px, 0)",u[f]=0,u[d]=0,u.willChange="transform";else{var _="bottom"===f?-1:1,E="right"===d?-1:1;u[f]=m*_,u[d]=g*E,u.willChange=f+", "+d}var T={"x-placement":t.placement};return t.attributes=vt({},T,t.attributes),t.styles=vt({},u,t.styles),t.arrowStyles=vt({},t.offsets.arrow,t.arrowStyles),t}function Y(t,e,n){var i=S(t,function(t){return t.name===e}),o=!!i&&t.some(function(t){return t.name===n&&t.enabled&&t.order<i.order});if(!o){var r="`"+e+"`",s="`"+n+"`";console.warn(s+" modifier is required by "+r+" modifier in order to work, be sure to include it before "+r+"!")}return o}function X(t,e){if(!Y(t.instance.modifiers,"arrow","keepTogether"))return t;var n=e.element;if("string"==typeof n){if(!(n=t.instance.popper.querySelector(n)))return t}else if(!t.instance.popper.contains(n))return console.warn("WARNING: `arrow.element` must be child of its popper element!"),t;var i=t.placement.split("-")[0],o=t.offsets,s=o.popper,a=o.reference,l=-1!==["left","right"].indexOf(i),c=l?"height":"width",u=l?"Top":"Left",h=u.toLowerCase(),f=l?"left":"top",d=l?"bottom":"right",p=I(n)[c];a[d]-p<s[h]&&(t.offsets.popper[h]-=s[h]-(a[d]-p)),a[h]+p>s[d]&&(t.offsets.popper[h]+=a[h]+p-s[d]);var g=a[h]+a[c]/2-p/2,m=r(t.instance.popper,"margin"+u).replace("px",""),v=g-_(t.offsets.popper)[h]-m;return v=Math.max(Math.min(s[c]-p,v),0),t.arrowElement=n,t.offsets.arrow={},t.offsets.arrow[h]=Math.round(v),t.offsets.arrow[f]="",t}function q(t){return"end"===t?"start":"start"===t?"end":t}function z(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=Tt.indexOf(t),i=Tt.slice(n+1).concat(Tt.slice(0,n));return e?i.reverse():i}function Z(t,e){if(R(t.instance.modifiers,"inner"))return t;if(t.flipped&&t.placement===t.originalPlacement)return t;var n=b(t.instance.popper,t.instance.reference,e.padding,e.boundariesElement),i=t.placement.split("-")[0],o=w(i),r=t.placement.split("-")[1]||"",s=[];switch(e.behavior){case yt.FLIP:s=[i,o];break;case yt.CLOCKWISE:s=z(i);break;case yt.COUNTERCLOCKWISE:s=z(i,!0);break;default:s=e.behavior}return s.forEach(function(a,l){if(i!==a||s.length===l+1)return t;i=t.placement.split("-")[0],o=w(i);var c=t.offsets.popper,u=t.offsets.reference,h=Math.floor,f="left"===i&&h(c.right)>h(u.left)||"right"===i&&h(c.left)<h(u.right)||"top"===i&&h(c.bottom)>h(u.top)||"bottom"===i&&h(c.top)<h(u.bottom),d=h(c.left)<h(n.left),p=h(c.right)>h(n.right),g=h(c.top)<h(n.top),m=h(c.bottom)>h(n.bottom),_="left"===i&&d||"right"===i&&p||"top"===i&&g||"bottom"===i&&m,v=-1!==["top","bottom"].indexOf(i),E=!!e.flipVariations&&(v&&"start"===r&&d||v&&"end"===r&&p||!v&&"start"===r&&g||!v&&"end"===r&&m);(f||_||E)&&(t.flipped=!0,(f||_)&&(i=s[l+1]),E&&(r=q(r)),t.placement=i+(r?"-"+r:""),t.offsets.popper=vt({},t.offsets.popper,D(t.instance.popper,t.offsets.reference,t.placement)),t=L(t.instance.modifiers,t,"flip"))}),t}function J(t){var e=t.offsets,n=e.popper,i=e.reference,o=t.placement.split("-")[0],r=Math.floor,s=-1!==["top","bottom"].indexOf(o),a=s?"right":"bottom",l=s?"left":"top",c=s?"width":"height";return n[a]<r(i[l])&&(t.offsets.popper[l]=r(i[l])-n[c]),n[l]>r(i[a])&&(t.offsets.popper[l]=r(i[a])),t}function $(t,e,n,i){var o=t.match(/((?:\-|\+)?\d*\.?\d*)(.*)/),r=+o[1],s=o[2];if(!r)return t;if(0===s.indexOf("%")){var a=void 0;switch(s){case"%p":a=n;break;case"%":case"%r":default:a=i}return _(a)[e]/100*r}if("vh"===s||"vw"===s){return("vh"===s?Math.max(document.documentElement.clientHeight,window.innerHeight||0):Math.max(document.documentElement.clientWidth,window.innerWidth||0))/100*r}return r}function tt(t,e,n,i){var o=[0,0],r=-1!==["right","left"].indexOf(i),s=t.split(/(\+|\-)/).map(function(t){return t.trim()}),a=s.indexOf(S(s,function(t){return-1!==t.search(/,|\s/)}));s[a]&&-1===s[a].indexOf(",")&&console.warn("Offsets separated by white space(s) are deprecated, use a comma (,) instead.");var l=/\s*,\s*|\s+/,c=-1!==a?[s.slice(0,a).concat([s[a].split(l)[0]]),[s[a].split(l)[1]].concat(s.slice(a+1))]:[s];return c=c.map(function(t,i){var o=(1===i?!r:r)?"height":"width",s=!1;return t.reduce(function(t,e){return""===t[t.length-1]&&-1!==["+","-"].indexOf(e)?(t[t.length-1]=e,s=!0,t):s?(t[t.length-1]+=e,s=!1,t):t.concat(e)},[]).map(function(t){return $(t,o,e,n)})}),c.forEach(function(t,e){t.forEach(function(n,i){V(n)&&(o[e]+=n*("-"===t[i-1]?-1:1))})}),o}function et(t,e){var n=e.offset,i=t.placement,o=t.offsets,r=o.popper,s=o.reference,a=i.split("-")[0],l=void 0;return l=V(+n)?[+n,0]:tt(n,r,s,a),"left"===a?(r.top+=l[0],r.left-=l[1]):"right"===a?(r.top+=l[0],r.left+=l[1]):"top"===a?(r.left+=l[0],r.top-=l[1]):"bottom"===a&&(r.left+=l[0],r.top+=l[1]),t.popper=r,t}function nt(t,e){var n=e.boundariesElement||l(t.instance.popper);t.instance.reference===n&&(n=l(n));var i=b(t.instance.popper,t.instance.reference,e.padding,n);e.boundaries=i;var o=e.priority,r=t.offsets.popper,s={primary:function(t){var n=r[t];return r[t]<i[t]&&!e.escapeWithReference&&(n=Math.max(r[t],i[t])),_t({},t,n)},secondary:function(t){var n="right"===t?"left":"top",o=r[n];return r[t]>i[t]&&!e.escapeWithReference&&(o=Math.min(r[n],i[t]-("right"===t?r.width:r.height))),_t({},n,o)}};return o.forEach(function(t){var e=-1!==["left","top"].indexOf(t)?"primary":"secondary";r=vt({},r,s[e](t))}),t.offsets.popper=r,t}function it(t){var e=t.placement,n=e.split("-")[0],i=e.split("-")[1];if(i){var o=t.offsets,r=o.reference,s=o.popper,a=-1!==["bottom","top"].indexOf(n),l=a?"left":"top",c=a?"width":"height",u={start:_t({},l,r[l]),end:_t({},l,r[l]+r[c]-s[c])};t.offsets.popper=vt({},s,u[i])}return t}function ot(t){if(!Y(t.instance.modifiers,"hide","preventOverflow"))return t;var e=t.offsets.reference,n=S(t.instance.modifiers,function(t){return"preventOverflow"===t.name}).boundaries;if(e.bottom<n.top||e.left>n.right||e.top>n.bottom||e.right<n.left){if(!0===t.hide)return t;t.hide=!0,t.attributes["x-out-of-boundaries"]=""}else{if(!1===t.hide)return t;t.hide=!1,t.attributes["x-out-of-boundaries"]=!1}return t}function rt(t){var e=t.placement,n=e.split("-")[0],i=t.offsets,o=i.popper,r=i.reference,s=-1!==["left","right"].indexOf(n),a=-1===["top","left"].indexOf(n);return o[s?"left":"top"]=r[n]-(a?o[s?"width":"height"]:0),t.placement=w(e),t.offsets.popper=_(o),t}for(var st=["native code","[object MutationObserverConstructor]"],at="undefined"!=typeof window,lt=["Edge","Trident","Firefox"],ct=0,ut=0;ut<lt.length;ut+=1)if(at&&navigator.userAgent.indexOf(lt[ut])>=0){ct=1;break}var ht=at&&function(t){return st.some(function(e){return(t||"").toString().indexOf(e)>-1})}(window.MutationObserver),ft=ht?n:i,dt=void 0,pt=function(){return void 0===dt&&(dt=-1!==navigator.appVersion.indexOf("MSIE 10")),dt},gt=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},mt=function(){function t(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,n,i){return n&&t(e.prototype,n),i&&t(e,i),e}}(),_t=function(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t},vt=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(t[i]=n[i])}return t},Et=["auto-start","auto","auto-end","top-start","top","top-end","right-start","right","right-end","bottom-end","bottom","bottom-start","left-end","left","left-start"],Tt=Et.slice(3),yt={FLIP:"flip",CLOCKWISE:"clockwise",COUNTERCLOCKWISE:"counterclockwise"},bt={shift:{order:100,enabled:!0,fn:it},offset:{order:200,enabled:!0,fn:et,offset:0},preventOverflow:{order:300,enabled:!0,fn:nt,priority:["left","right","top","bottom"],padding:5,boundariesElement:"scrollParent"},keepTogether:{order:400,enabled:!0,fn:J},arrow:{order:500,enabled:!0,fn:X,element:"[x-arrow]"},flip:{order:600,enabled:!0,fn:Z,behavior:"flip",padding:5,boundariesElement:"viewport"},inner:{order:700,enabled:!1,fn:rt},hide:{order:800,enabled:!0,fn:ot},computeStyle:{order:850,enabled:!0,fn:Q,gpuAcceleration:!0,x:"bottom",y:"right"},applyStyle:{order:900,enabled:!0,fn:G,onLoad:K,gpuAcceleration:void 0}},Ct={placement:"bottom",eventsEnabled:!0,removeOnDestroy:!1,onCreate:function(){},onUpdate:function(){},modifiers:bt},At=function(){function t(e,n){var i=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};gt(this,t),this.scheduleUpdate=function(){return requestAnimationFrame(i.update)},this.update=ft(this.update.bind(this)),this.options=vt({},t.Defaults,r),this.state={isDestroyed:!1,isCreated:!1,scrollParents:[]},this.reference=e.jquery?e[0]:e,this.popper=n.jquery?n[0]:n,this.options.modifiers={},Object.keys(vt({},t.Defaults.modifiers,r.modifiers)).forEach(function(e){i.options.modifiers[e]=vt({},t.Defaults.modifiers[e]||{},r.modifiers?r.modifiers[e]:{})}),this.modifiers=Object.keys(this.options.modifiers).map(function(t){return vt({name:t},i.options.modifiers[t])}).sort(function(t,e){return t.order-e.order}),this.modifiers.forEach(function(t){t.enabled&&o(t.onLoad)&&t.onLoad(i.reference,i.popper,i.options,t,i.state)}),this.update();var s=this.options.eventsEnabled;s&&this.enableEventListeners(),this.state.eventsEnabled=s}return mt(t,[{key:"update",value:function(){return P.call(this)}},{key:"destroy",value:function(){return k.call(this)}},{key:"enableEventListeners",value:function(){return M.call(this)}},{key:"disableEventListeners",value:function(){return j.call(this)}}]),t}();At.Utils=("undefined"!=typeof window?window:t).PopperUtils,At.placements=Et,At.Defaults=Ct,e.default=At}.call(e,n(4))},function(t,e){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(t){"object"==typeof window&&(n=window)}t.exports=n}]);
\ No newline at end of file
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index cbdab08..c50b572 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -17,15 +17,16 @@
 </head>
 <body>
 
-<nav class="navbar navbar-toggleable-sm navbar-light" id="navbar-top">
-  <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbar-top-menu" aria-controls="navbar-top" aria-expanded="false" aria-label="Toggle navigation">
-    <span class="navbar-toggler-icon"></span>
-  </button>
+<nav class="navbar navbar-expand-md navbar-light" id="navbar-top">
 
   <a class="navbar-brand" href="#">
     <img src="{{ url_for('static', filename='img/logo-hubs.png') }}" alt="Hubs">
   </a>
 
+  <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbar-top-menu" aria-controls="navbar-top" aria-expanded="false" aria-label="Toggle navigation">
+    <span class="navbar-toggler-icon"></span>
+  </button>
+
   <div class="collapse navbar-collapse" id="navbar-top-menu">
     <!-- NOT HOOKED UP TO ANYTHING XOXO -->
     <form class="form-inline mx-auto">
@@ -42,12 +43,12 @@
     {% if g.auth.logged_in %}
     <ul class="navbar-nav ml-auto">
       <li class="nav-item mr-4">
-        <img class="chaticon pull-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
+        <img class="chaticon float-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
       </li>
       <li class="nav-item dropdown">
-        <span href="#" class="dropdown-toggle showpointer" id="navbar-dropdown-user" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+        <a href="#" class="nav-link dropdown-toggle" id="navbar-dropdown-user" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
           <img src="{{ g.auth.avatar }}" class="avatar" alt="User Icon"/>
-        </span>
+        </a>
         <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbar-dropdown-user">
           <h6 class="dropdown-header">Account Information</h6>
           <a href="#" class="dropdown-item">Full Name: {{ g.auth.fullname }}</a>
@@ -77,8 +78,8 @@
   <!-- Flash messages -->
   {%- with messages = get_flashed_messages(with_categories=true) -%}
   {%- if category, messages -%}
-    <div class="row pt-2 flash-messages">
-      <div class="col-md-6 offset-md-3">
+    <div class="d-flex justify-content-center">
+      <div class="flash-messages">
       {%- for category, message in messages -%}
         <div class="alert {%
           if category == 'error' %}alert-warning{%
diff --git a/hubs/widgets/contact/templates/root.html b/hubs/widgets/contact/templates/root.html
index 7c3cccf..249542f 100644
--- a/hubs/widgets/contact/templates/root.html
+++ b/hubs/widgets/contact/templates/root.html
@@ -4,7 +4,7 @@
       <!--<li><i class="fa fa-map-marker" aria-hidden="true"></i>
           <span class="col-md-offset-1">{{location}}</span></li>-->
       <li><i class="fa fa-clock-o" aria-hidden="true"></i>
-          <span class="col-md-offset-1">Current-Time :</span>
+          <span class="ml-2">Current-Time :</span>
           <script type="text/javascript">
             // TODO: send offset after querying fas3
             function calcTime(offset) {
@@ -49,22 +49,22 @@
           </script>
           <span id="time"></span></li>
       <li><i class="fa fa-envelope" aria-hidden="true"></i>
-          <span class="col-md-offset-1">{{email}}</span></li>
+          <span class="ml-2">{{email}}</span></li>
       <li><i class="fa fa-comment" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span>{{ircnick}}</li>
+          <span class="ml-2"></span>{{ircnick}}</li>
       <li><i class="fa fa-user-plus" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span><span id="karma_current"></span></li>
+          <span class="ml-2"></span><span id="karma_current"></span></li>
       <li><i class="fa fa-certificate" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span> Member Since {{account_age}}</li>
+          <span class="ml-2"></span> Member Since {{account_age}}</li>
     </ul>
   {% else %}
     <ul style="list-style: none">
       <li><i class="fa fa-comment" aria-hidden="true"></i>
-          <span class="col-md-offset-1"></span>fedora-{{ircchannel}}</li>
+          <span class="ml-2"></span>fedora-{{ircchannel}}</li>
       <li><i class="fa fa-envelope" aria-hidden="true"></i>
-          <span class="col-md-offset-1"><a href="{{ mailinglist }}">{{ hubname }}@lists.fedoraproject.org</a></span></li>
+          <span class="ml-2"><a href="{{ mailinglist }}">{{ hubname }}@lists.fedoraproject.org</a></span></li>
       <li><i class="fa fa-info" aria-hidden="true"></i>
-          <span class="col-md-offset-1"><a href="{{ wikilink }}">fedoraproject.org/wiki/{{ hubname }}</a></span></li>
+          <span class="ml-2"><a href="{{ wikilink }}">fedoraproject.org/wiki/{{ hubname }}</a></span></li>
     </ul>
   {% endif %}
 </div>
diff --git a/hubs/widgets/github_pr/templates/root.html b/hubs/widgets/github_pr/templates/root.html
index 2d46c56..4ad7357 100644
--- a/hubs/widgets/github_pr/templates/root.html
+++ b/hubs/widgets/github_pr/templates/root.html
@@ -1,7 +1,10 @@
-<a class="btn btn-success" target="_blank"
-    href="https://github.com/{{ organization }}" >
-  Organization Github Page
-</a>
+<div class="text-center">
+  <a class="btn btn-primary" target="_blank"
+      href="https://github.com/{{ organization }}" >
+    Organization Github Page
+  </a>
+</div>
+{% if pulls %}
 <hr/>
 <ul class="list-unstyled">
 {% for pr in pulls[:display_number] %}
@@ -44,3 +47,4 @@
   </li>
 {% endif %}
 </ul>
+{% endif %}
diff --git a/hubs/widgets/pagure_pr/templates/root.html b/hubs/widgets/pagure_pr/templates/root.html
index bf8ae43..75cb916 100644
--- a/hubs/widgets/pagure_pr/templates/root.html
+++ b/hubs/widgets/pagure_pr/templates/root.html
@@ -8,13 +8,13 @@
         </a>
       </div>
       <div class="media-body">
-        <h5 class="mt-0">
+        <div>
           {{ pr['pr_project_name'] }} -
           <span title="{{ pr['pr_title_full'] }}">
             {{ pr['pr_title'] }} {% if
               pr['pr_title_full'] | length > 45 %} ... {% endif %}
           </span>
-        </h5>
+        </div>
 	<small>
         Opened by:
           <a href="https://pagure.io/user/{{ pr['pr_openedby'] }}"
@@ -44,7 +44,9 @@
 
 <hr/>
 
-<a class="btn btn-success" target="_blank"
-    href="https://pagure.io/{{ repo }}/pull-requests">
-  All Pull-Requests
-</a>
+<div class="text-center">
+  <a class="btn btn-primary" target="_blank"
+      href="https://pagure.io/{{ repo }}/pull-requests">
+    All Pull-Requests
+  </a>
+</div>

From c32b424ebf2db075f27aa19e826da46edab0c188 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 11 2017 16:15:29 +0000
Subject: [PATCH 980/1001] Fixup the commit to switch to react-universal-component


---

diff --git a/hubs/static/client/.babelrc b/hubs/static/client/.babelrc
index b5e1a56..5229299 100644
--- a/hubs/static/client/.babelrc
+++ b/hubs/static/client/.babelrc
@@ -5,7 +5,8 @@
   ],
   "plugins": [
     "syntax-dynamic-import",
-    "transform-object-rest-spread"
+    "transform-object-rest-spread",
+    "universal-import"
   ],
   "env": {
     "test": {
diff --git a/hubs/static/client/package.json b/hubs/static/client/package.json
index 7b34774..fdb5d95 100644
--- a/hubs/static/client/package.json
+++ b/hubs/static/client/package.json
@@ -31,6 +31,7 @@
     "babel-plugin-dynamic-import-node": "^1.1.0",
     "babel-plugin-syntax-dynamic-import": "^6.18.0",
     "babel-plugin-transform-object-rest-spread": "^6.26.0",
+    "babel-plugin-universal-import": "^1.2.7",
     "babel-preset-env": "^1.6.0",
     "babel-preset-es2015": "^6.24.1",
     "babel-preset-react": "^6.24.1",

From 5107273f12f673ac0e2de4493406b2283e9a608f Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 11 2017 17:28:53 +0000
Subject: [PATCH 981/1001] Some more adaptations to Fedora Bootstrap 1.1


---

diff --git a/hubs/static/client/app/components/LeftMenu.css b/hubs/static/client/app/components/LeftMenu.css
index 1b0fd47..287a768 100644
--- a/hubs/static/client/app/components/LeftMenu.css
+++ b/hubs/static/client/app/components/LeftMenu.css
@@ -25,3 +25,9 @@
   /*background-color: #373a3c;*/
 }
 
+.LeftMenu a.nav-link:hover {
+  background-color: #eee;
+}
+.LeftMenu a.nav-link.active:hover {
+  background-color: #007bff;
+}
diff --git a/hubs/static/client/app/components/SimpleWidget.js b/hubs/static/client/app/components/SimpleWidget.js
index 9a62fe5..5d644cc 100644
--- a/hubs/static/client/app/components/SimpleWidget.js
+++ b/hubs/static/client/app/components/SimpleWidget.js
@@ -78,7 +78,7 @@ export default class SimpleWidget extends React.PureComponent {
         { this.state.isLoading &&
           <div className="text-muted">Loading...</div>
           ||
-          <div dangerouslySetInnerHTML={{__html: this.state.contents}} />
+          <div className="p-2" dangerouslySetInnerHTML={{__html: this.state.contents}} />
         }
       </WidgetChrome>
     );
diff --git a/hubs/static/client/app/components/feed/ItemsGetter.js b/hubs/static/client/app/components/feed/ItemsGetter.js
index ff0fb0e..27f0975 100644
--- a/hubs/static/client/app/components/feed/ItemsGetter.js
+++ b/hubs/static/client/app/components/feed/ItemsGetter.js
@@ -93,8 +93,8 @@ class ItemsGetter extends React.Component {
           <Spinner />
         }
         { this.state.errorMessage &&
-          <div className="alert alert-warning mt-3 mb-0">
-            {this.state.errorMessage}
+          <div className="alert alert-warning mt-3 mb-0 py-1">
+            <small>{this.state.errorMessage}</small>
           </div>
         }
       </div>
diff --git a/hubs/static/client/app/widgets/halp/Widget.js b/hubs/static/client/app/widgets/halp/Widget.js
index 8f54123..ebeefa2 100644
--- a/hubs/static/client/app/widgets/halp/Widget.js
+++ b/hubs/static/client/app/widgets/halp/Widget.js
@@ -171,7 +171,7 @@ export default class HalpWidget extends React.Component {
         widget={this.props.widget}
         editMode={this.props.editMode}
         >
-        <div className="widget-halp">
+        <div className="widget-halp p-2">
           <HubsList
             hubs={hubs}
             onHubClick={this.onHubClick}
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index ba35ebf..0260884 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -133,29 +133,6 @@ header span.edit {
  * Widgets
  */
 
-/* hub widgets */
-.rules-table {
-  width: 180px
-  padding: 0px;
-  margin: 0px;
-  display: inline-block;
-}
-.rules-table td {
-  font-size: 32pt;
-}
-.rules-container h6 {
-  font-family: 'Open Sans', sans-serif;
-  text-transform: capitalize;
-  font-size: normal;
-  font-weight: 700;
-  color: #808080;
-  margin-bottom: 5px;
-}
-
-.rules-container img {
-  margin-bottom: 15px;
-}
-
 #add-widget-left h4 a, #add-widget-right h4 a {
   color: #60605b;
 }
@@ -276,11 +253,6 @@ font-size: 32pt;
     font-size: 14px;
 }
 
-.meeting .add-calendar {
-    font-size: 10px;
-    color: #a07cbc;
-}
-
 .meeting .row {
   border-bottom: 1px solid #ddd;
   padding-top: 0.5rem !important;
@@ -312,12 +284,13 @@ font-size: 32pt;
 
 
 /*
- * Sticky widget
+ * Widgets
  */
+
 .card-info {
   border-color: #17a2b8;
 }
-.card-info > .card-header{
+.card-info > .card-header {
   background-color: #17a2b8;
   color: #f8f9fa;
 }
@@ -326,21 +299,21 @@ font-size: 32pt;
 /*
  *  Contact Widget
  */
-
 .widget-contact .card-block ul {
   padding: 0px; 
 }
-
 .widget-contact .card-block i {
   width: 25px;
   text-align: center;
 }
+.widget-contact .contactinfo-container {
+  font-size: 80%;
+}
 
 
 /*
- * Issue Widgets
+ * Issue widgets
  */
-
 .widget .widget-pagure_pr li,
 .widget .widget-githubissues li,
 .widget .widget-bugzilla li {
@@ -353,6 +326,37 @@ font-size: 32pt;
 border: 0}
 
 
+/*
+ * Rules widget
+ */
+.widget-rules .rules-table {
+  width: 180px
+  padding: 0px;
+  margin: 0px;
+  display: inline-block;
+}
+.widget-rules .rules-table td {
+  font-size: 32pt;
+}
+.widget-rules .rules-container h6 {
+  font-family: 'Open Sans', sans-serif;
+  text-transform: capitalize;
+  font-size: normal;
+  font-weight: 700;
+  color: #808080;
+  margin-bottom: 5px;
+}
+.widget-rules .rules-container img {
+  margin-bottom: 15px;
+}
+.widget-rules .img-circle-lg {
+  height: 4em;
+  width: 4em;
+  padding: 10px;
+}
+.widget-rules .modal-header {
+  border-bottom: 0;
+}
 
 
 /** fedora bootstrap overrides **/
@@ -395,29 +399,7 @@ header h5.m-b-1 {
   }
 }
 
-#right_widgets .widget .card-block {
-  padding: 0.6rem !important;
-}
-
-#right_widgets .widget-rules .card-block {
-  padding: 1.25rem 0.9rem !important;
-  background: #e7e7e7;
-}
-
-
-#right_widgets .widget-contact .contactinfo-container {
-  font-size: 80%;
-}
-
-#right_widgets hr {
-  margin-top: 0.33rem;
-  margin-bottom: 0.33rem;
-}
 
 .small {
   font-size: small;
 }
-
-
-
-/* vim: set ts=2 sw=2 et: */
diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index c50b572..3f344a9 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -43,7 +43,9 @@
     {% if g.auth.logged_in %}
     <ul class="navbar-nav ml-auto">
       <li class="nav-item mr-4">
-        <img class="chaticon float-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
+        <span class="navbar-text">
+          <img class="chaticon float-xs-right m-r-2" src="{{ url_for('static', filename='img/irc_icon.png') }}" alt="IRC Chats">
+        </span>
       </li>
       <li class="nav-item dropdown">
         <a href="#" class="nav-link dropdown-toggle" id="navbar-dropdown-user" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
diff --git a/hubs/widgets/meetings/templates/root.html b/hubs/widgets/meetings/templates/root.html
index 7028ac2..7072d8c 100644
--- a/hubs/widgets/meetings/templates/root.html
+++ b/hubs/widgets/meetings/templates/root.html
@@ -19,8 +19,8 @@
     </div>
     <div class="col-md-5 col-lg-4 text-right">
       <a href="https://apps.fedoraproject.org/calendar/ical/calendar/meeting/{{ next.meeting_id }}/">
-        <button class="btn btn-secondary btn-sm add-calendar">
-          <strong>Add to calendar</strong>
+        <button class="btn btn-secondary btn-sm">
+          <small><strong>Add to calendar</strong></small>
         </button>
       </a>
     </div>
diff --git a/hubs/widgets/rules/__init__.py b/hubs/widgets/rules/__init__.py
index 7331acd..32b5c71 100644
--- a/hubs/widgets/rules/__init__.py
+++ b/hubs/widgets/rules/__init__.py
@@ -15,6 +15,7 @@ class Rules(Widget):
 
     name = "rules"
     position = "both"
+    display_css = "card-info"
     parameters = [
         dict(
             name="link",
diff --git a/hubs/widgets/rules/templates/root.html b/hubs/widgets/rules/templates/root.html
index e3abc68..bd1533f 100644
--- a/hubs/widgets/rules/templates/root.html
+++ b/hubs/widgets/rules/templates/root.html
@@ -1,4 +1,4 @@
-<div class="rules-container">
+<div class="rules-container py-2">
   {% if link %}
   <h6>community rules</h6>
   <p><a href="{{link}}">Community Rules and Guidelines</a></h6>
@@ -66,22 +66,4 @@
 </div>
 
 <style>
-  .rules-table {
-    width: 180px
-    padding: 0px;
-    margin: 0px;
-    display: inline-block;
-  }
-  .rules-table td {
-    font-size: 32pt;
-  }
-
- .img-circle-lg {
-   height: 4em;
-   width: 4em;
-   padding: 10px;
- }
- .modal-header {
-   border-bottom: 0;
- }
 </style>

From 452afefbb0e52b7d4d36057f5be9ad63fb8b6db5 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 12 2017 12:43:09 +0000
Subject: [PATCH 982/1001] A couple improvements related to react-universal-component


Use top-level components to make HMR easier one day.

---

diff --git a/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js b/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js
index 068d1de..efce753 100644
--- a/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js
+++ b/hubs/static/client/app/components/AddWidget/AddWidgetDialog.js
@@ -9,6 +9,16 @@ import { addWidget } from '../../core/actions/widget';
 import { makeLoadable } from '../../core/utils';
 
 
+const AsyncComponent = makeLoadable(
+  (props) => import(
+    /* webpackChunkName: "[request]" */
+    `../../widgets/${props.widget.name}/Config`
+  ),
+  "Loading widget configuration...",
+  "Sorry, there was a problem loading the widget configuration."
+);
+
+
 class AddWidgetDialog extends React.Component {
 
   constructor(props) {
@@ -117,11 +127,6 @@ class AddWidgetDialog extends React.Component {
       // Second step: configure the widget
       title = "Adding widget " + this.state.selectedWidget.label;
       if (this.state.selectedWidget.isReact) {
-        const AsyncComponent = makeLoadable(
-          () => import(`../../widgets/${this.state.selectedWidget.name}/Config`),
-          "Loading widget configuration...",
-          "Sorry, there was a problem loading the widget configuration."
-        );
         contents = (
           <AsyncComponent
             widget={this.state.selectedWidget}
diff --git a/hubs/static/client/app/components/SimpleWidget.js b/hubs/static/client/app/components/SimpleWidget.js
index 5d644cc..5695b40 100644
--- a/hubs/static/client/app/components/SimpleWidget.js
+++ b/hubs/static/client/app/components/SimpleWidget.js
@@ -76,7 +76,7 @@ export default class SimpleWidget extends React.PureComponent {
         editMode={this.props.editMode}
         >
         { this.state.isLoading &&
-          <div className="text-muted">Loading...</div>
+          <div className="p-2 text-muted">Loading...</div>
           ||
           <div className="p-2" dangerouslySetInnerHTML={{__html: this.state.contents}} />
         }
diff --git a/hubs/static/client/app/components/Widget.js b/hubs/static/client/app/components/Widget.js
index 96c5d5b..f2951b6 100644
--- a/hubs/static/client/app/components/Widget.js
+++ b/hubs/static/client/app/components/Widget.js
@@ -5,6 +5,16 @@ import { makeLoadable } from '../core/utils';
 import SimpleWidget from '../components/SimpleWidget';
 
 
+const AsyncComponent = makeLoadable(
+  (props) => import(
+    /* webpackChunkName: "[request]" */
+    `../widgets/${props.widget.component}/Widget`
+  ),
+  "Loading widget...",
+  "Sorry, there was a problem loading the widget."
+);
+
+
 class Widget extends React.PureComponent {
 
   propTypes: {
@@ -20,11 +30,6 @@ class Widget extends React.PureComponent {
   render() {
     let widgetComponent;
     if (!this.props.editMode && this.props.widget.isReact) {
-      const AsyncComponent = makeLoadable(
-        () => import(`../widgets/${this.props.widget.component}/Widget`),
-        "Loading widget...",
-        "Sorry, there was a problem loading the widget."
-      );
       widgetComponent = (
         <AsyncComponent {...this.props} />
       );
diff --git a/hubs/static/client/app/components/WidgetConfigDialog.js b/hubs/static/client/app/components/WidgetConfigDialog.js
index 1a8bd33..58987da 100644
--- a/hubs/static/client/app/components/WidgetConfigDialog.js
+++ b/hubs/static/client/app/components/WidgetConfigDialog.js
@@ -11,6 +11,16 @@ import SimpleWidgetConfig from '../components/SimpleWidgetConfig';
 import Modal from '../components/Modal';
 
 
+const AsyncComponent = makeLoadable(
+  (props) => import(
+    /* webpackChunkName: "[request]" */
+    `../widgets/${props.widget.name}/Config`
+  ),
+  "Loading widget configuration...",
+  "Sorry, there was a problem loading the widget configuration."
+);
+
+
 class WidgetConfigDialog extends React.Component {
 
   propTypes: {
@@ -64,14 +74,8 @@ class WidgetConfigDialog extends React.Component {
     if (!this.props.widget) {
       return null;
     }
-    const widgetName = this.props.widget.name;
     let contents;
     if (this.props.widget.isReact) {
-      const AsyncComponent = makeLoadable(
-        () => import(`../widgets/${widgetName}/Config`),
-        "Loading widget configuration...",
-        "Sorry, there was a problem loading the widget configuration."
-      );
       contents = (
         <AsyncComponent
           widget={this.props.widget}
diff --git a/hubs/static/client/app/core/Pages.js b/hubs/static/client/app/core/Pages.js
index 6277719..67aee23 100644
--- a/hubs/static/client/app/core/Pages.js
+++ b/hubs/static/client/app/core/Pages.js
@@ -4,12 +4,12 @@ import {
 } from '../core/utils';
 
 
-let Hub = makeLoadable(
+const Hub = makeLoadable(
   () => import(/* webpackChunkName: "page-hub" */ '../components/HubPage'),
   "Loading...",
   "Sorry, there was a problem loading the page."
 );
-let Streams = makeLoadable(
+const Streams = makeLoadable(
   () => import(/* webpackChunkName: "page-streams" */ '../components/StreamsPage'),
   "Loading...",
   "Sorry, there was a problem loading the page."
diff --git a/hubs/static/client/app/index.js b/hubs/static/client/app/index.js
index cccae63..4b97cc6 100644
--- a/hubs/static/client/app/index.js
+++ b/hubs/static/client/app/index.js
@@ -1,6 +1,8 @@
 // Read the public path from the backend
 // https://webpack.js.org/guides/public-path/
-__webpack_public_path__ = window.resourceBaseUrl;
+if(window.resourceBaseUrl) {
+  __webpack_public_path__ = window.resourceBaseUrl;
+}
 
 import React from 'react';
 import ReactDOM from 'react-dom';

From 8b4ad65231e04a23ffb2a7a9b6d87a7c7c85b2fa Mon Sep 17 00:00:00 2001
From: anar <anar@localhost.localdomain>
Date: Oct 13 2017 12:13:13 +0000
Subject: [PATCH 983/1001] Changed the way validation occurs. Implemented GithubRepo and GithubOrg validators and their tests.


---

diff --git a/hubs/tests/test_widget_validators.py b/hubs/tests/test_widget_validators.py
index d421aa5..96d887f 100644
--- a/hubs/tests/test_widget_validators.py
+++ b/hubs/tests/test_widget_validators.py
@@ -30,7 +30,6 @@ class ValidatorsTest(APPTest):
         self.assertRaises(
             ValueError, validators.Username, "nobody")
 
-    @unittest.skip("Not implemented yet")
     def test_github_organization(self):
         self.assertEqual(
             validators.GithubOrganization("fedora-infra"),
@@ -40,12 +39,14 @@ class ValidatorsTest(APPTest):
             validators.GithubOrganization,
             "something-that-does-not-exist")
 
-    @unittest.skip("Not implemented yet")
     def test_github_repo(self):
         self.assertEqual(
-            validators.GithubRepo("fedmsg"), "fedmsg")
+            validators.GithubRepo('/'.join(["fedora-infra",
+                                            "fedmsg"])),
+            "fedmsg")
         self.assertRaises(ValueError, validators.GithubRepo,
-                          "something-that-does-not-exist")
+                          '/'.join(["fedora-infra",
+                                    "something-that-does-not-exist"]))
 
     def test_fmncontext(self):
         self.assertEqual(validators.FMNContext("email"), "email")
diff --git a/hubs/utils/github.py b/hubs/utils/github.py
index 47c1018..71ef257 100644
--- a/hubs/utils/github.py
+++ b/hubs/utils/github.py
@@ -9,6 +9,30 @@ import requests
 log = logging.getLogger(__name__)
 
 
+def github_org_is_valid(token, username):
+    log.info("Finding github organization for {}".format(username))
+    tmpl = "https://api.github.com/users/{username}"
+    url = tmpl.format(username=username)
+    auth = dict(access_token=token)
+    result = requests.get(url, params=auth)
+    if not bool(result):
+        return False
+    else:
+        return True
+
+
+def github_repo_is_valid(token, username, repo):
+    log.info("Finding github repo for {} and {} ".format(repo, username))
+    tmpl = "https://api.github.com/repos/{username}/{repo}"
+    url = tmpl.format(username=username, repo=repo)
+    auth = dict(access_token=token)
+    result = requests.get(url, params=auth)
+    if not bool(result):
+        return False
+    else:
+        return True
+
+
 def github_repos(token, username):
     log.info("Finding github repos for %r" % username)
     tmpl = "https://api.github.com/users/{username}/repos?per_page=100"
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
index 2508dad..5e7581b 100644
--- a/hubs/utils/views.py
+++ b/hubs/utils/views.py
@@ -118,16 +118,17 @@ def configure_widget_instance(widget_instance, widget_config):
     """
     if not widget_config:
         return
-    config = {}
+    vals = {}
     for param in widget_instance.module.get_parameters():
         val = widget_config.get(param.name)
         if not val:
             raise WidgetConfigError(
                 'You must provide a value for: %s' % param.name)
-        try:
-            config[param.name] = param.validator(val)
-        except ValueError as err:
-            raise WidgetConfigError('Invalid data provided, error: %s' % err)
+        vals[param.name] = val
+    try:
+        config = widget_instance.module.validate_parameters(vals)
+    except ValueError as err:
+        raise WidgetConfigError('Invalid data provided, error: %s' % err)
     # Updating in-place is not supported, it's a class property.
     cur_config = widget_instance.config or {}
     cur_config = cur_config.copy()
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index db63192..42a1965 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -99,7 +99,15 @@ class Widget(object):
             # Try to be smart-ish with the default label.
             self.label = self.name.replace("_", " ").replace(".", ": ").title()
         self._template_environment = None
+#
 
+    def validate_parameters(self, vals):
+        config = {}
+        for param in self.get_parameters():
+            config[param.name] = param.validator(vals[param.name])
+        return config
+
+#
     def validate(self):
         """
         Ensure that the widget has the bits it needs.
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index fa0c996..8334c23 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -34,6 +34,17 @@ class GitHubIssues(Widget):
             help="The number of tickets to display.",
         )]
 
+    def validate_parameters(self, vals):
+        config = {}
+        config["org"] = \
+            validators.GithubOrganization(vals["org"])
+        config["repo"] = \
+            validators.GithubRepo('/'.join([vals["org"],
+                                           vals["repo"]]))
+        config["display_number"] = \
+            validators.Integer(vals["display_number"])
+        return config
+
 
 class BaseView(RootWidgetView):
 
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index f8c5b8f..75257ba 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -10,6 +10,8 @@ will return the validated value.
 """
 
 from __future__ import unicode_literals
+from hubs.utils.github import github_org_is_valid, github_repo_is_valid
+from hubs.utils import get_fedmsg_config
 
 import flask
 import hubs.models
@@ -17,6 +19,8 @@ import kitchen.text.converters
 import requests
 import six
 
+fedmsg_config = get_fedmsg_config()
+
 
 def Required(value):
     """Raises an error if the value is ``False``-like."""
@@ -61,14 +65,19 @@ def Username(value):
 
 def GithubOrganization(value):
     """Fails if the Github organization name does not exist."""
-    # TODO -- implement this.
+    token = fedmsg_config.get('github.oauth_token')
+    if not github_org_is_valid(token, value):
+        raise ValueError('Github organization does not exist')
     return value
 
 
 def GithubRepo(value):
     """Fails if the Github repository name does not exist."""
-    # TODO -- implement this.
-    return value
+    token = fedmsg_config.get('github.oauth_token')
+    username, repo = value.split('/')
+    if not github_repo_is_valid(token, username, repo):
+        raise ValueError('Github repository does not exist')
+    return repo
 
 
 def FMNContext(value):

From 8d9d32826a030b8dbf6e5bf041397ab10539dd34 Mon Sep 17 00:00:00 2001
From: anar <anar@localhost.localdomain>
Date: Oct 13 2017 12:13:13 +0000
Subject: [PATCH 984/1001] Some minor polishing


---

diff --git a/hubs/utils/github.py b/hubs/utils/github.py
index 71ef257..78880de 100644
--- a/hubs/utils/github.py
+++ b/hubs/utils/github.py
@@ -9,25 +9,23 @@ import requests
 log = logging.getLogger(__name__)
 
 
-def github_org_is_valid(token, username):
+def github_org_is_valid(username):
     log.info("Finding github organization for {}".format(username))
     tmpl = "https://api.github.com/users/{username}"
     url = tmpl.format(username=username)
-    auth = dict(access_token=token)
-    result = requests.get(url, params=auth)
-    if not bool(result):
+    result = requests.get(url)
+    if not result.ok:
         return False
     else:
         return True
 
 
-def github_repo_is_valid(token, username, repo):
+def github_repo_is_valid(username, repo):
     log.info("Finding github repo for {} and {} ".format(repo, username))
     tmpl = "https://api.github.com/repos/{username}/{repo}"
     url = tmpl.format(username=username, repo=repo)
-    auth = dict(access_token=token)
-    result = requests.get(url, params=auth)
-    if not bool(result):
+    result = requests.get(url)
+    if not result.ok:
         return False
     else:
         return True
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
index 5e7581b..0fe1e2b 100644
--- a/hubs/utils/views.py
+++ b/hubs/utils/views.py
@@ -118,15 +118,15 @@ def configure_widget_instance(widget_instance, widget_config):
     """
     if not widget_config:
         return
-    vals = {}
+    values = {}
     for param in widget_instance.module.get_parameters():
         val = widget_config.get(param.name)
         if not val:
             raise WidgetConfigError(
                 'You must provide a value for: %s' % param.name)
-        vals[param.name] = val
+        values[param.name] = val
     try:
-        config = widget_instance.module.validate_parameters(vals)
+        config = widget_instance.module.validate_parameters(values)
     except ValueError as err:
         raise WidgetConfigError('Invalid data provided, error: %s' % err)
     # Updating in-place is not supported, it's a class property.
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 42a1965..eae34cc 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -10,7 +10,6 @@ from importlib import import_module
 from .caching import CachedFunction
 from .view import WidgetView
 
-
 log = logging.getLogger(__name__)
 
 
@@ -99,15 +98,17 @@ class Widget(object):
             # Try to be smart-ish with the default label.
             self.label = self.name.replace("_", " ").replace(".", ": ").title()
         self._template_environment = None
-#
 
-    def validate_parameters(self, vals):
+    def validate_parameters(self, values):
+        """
+        Get a dictionary of values associated with corresponding parameters,
+        validate them and return.
+        """
         config = {}
         for param in self.get_parameters():
-            config[param.name] = param.validator(vals[param.name])
+            config[param.name] = param.validator(values[param.name])
         return config
 
-#
     def validate(self):
         """
         Ensure that the widget has the bits it needs.
@@ -281,10 +282,11 @@ class Widget(object):
                     "api_hub_widget", hub=instance.hub.name, idx=instance.idx),
                 "config": {},
             })
+            validated = self.validate_parameters(instance.config)
             for param in self.get_parameters():
                 if param.secret and not with_secret_config:
                     continue
-                value = param.validator(instance.config[param.name])
+                value = validated[param.name]
                 props["config"][param.name] = value
             if self.is_react:
                 props["component"] = self.name
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index 75257ba..77504b9 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -11,7 +11,6 @@ will return the validated value.
 
 from __future__ import unicode_literals
 from hubs.utils.github import github_org_is_valid, github_repo_is_valid
-from hubs.utils import get_fedmsg_config
 
 import flask
 import hubs.models
@@ -19,8 +18,6 @@ import kitchen.text.converters
 import requests
 import six
 
-fedmsg_config = get_fedmsg_config()
-
 
 def Required(value):
     """Raises an error if the value is ``False``-like."""
@@ -65,17 +62,15 @@ def Username(value):
 
 def GithubOrganization(value):
     """Fails if the Github organization name does not exist."""
-    token = fedmsg_config.get('github.oauth_token')
-    if not github_org_is_valid(token, value):
+    if not github_org_is_valid(value):
         raise ValueError('Github organization does not exist')
     return value
 
 
 def GithubRepo(value):
     """Fails if the Github repository name does not exist."""
-    token = fedmsg_config.get('github.oauth_token')
     username, repo = value.split('/')
-    if not github_repo_is_valid(token, username, repo):
+    if not github_repo_is_valid(username, repo):
         raise ValueError('Github repository does not exist')
     return repo
 

From fd41c203324d0399901971f6c98c929d48310996 Mon Sep 17 00:00:00 2001
From: anar <anar@localhost.localdomain>
Date: Oct 13 2017 12:13:13 +0000
Subject: [PATCH 985/1001] Addressed comments


---

diff --git a/hubs/utils/github.py b/hubs/utils/github.py
index 78880de..5da725a 100644
--- a/hubs/utils/github.py
+++ b/hubs/utils/github.py
@@ -14,10 +14,7 @@ def github_org_is_valid(username):
     tmpl = "https://api.github.com/users/{username}"
     url = tmpl.format(username=username)
     result = requests.get(url)
-    if not result.ok:
-        return False
-    else:
-        return True
+    return result.ok
 
 
 def github_repo_is_valid(username, repo):
@@ -25,10 +22,7 @@ def github_repo_is_valid(username, repo):
     tmpl = "https://api.github.com/repos/{username}/{repo}"
     url = tmpl.format(username=username, repo=repo)
     result = requests.get(url)
-    if not result.ok:
-        return False
-    else:
-        return True
+    return result.ok
 
 
 def github_repos(token, username):
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index eae34cc..bc10b01 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -101,8 +101,14 @@ class Widget(object):
 
     def validate_parameters(self, values):
         """
-        Get a dictionary of values associated with corresponding parameters,
-        validate them and return.
+        Validate the parameters of a widget.
+
+        Args:
+            values (dict): dictionary of values associated
+                           with corresponding parameters.
+
+        Returns:
+            dict: validated parameter values.
         """
         config = {}
         for param in self.get_parameters():
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index 8334c23..c8c2956 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -34,15 +34,15 @@ class GitHubIssues(Widget):
             help="The number of tickets to display.",
         )]
 
-    def validate_parameters(self, vals):
+    def validate_parameters(self, values):
         config = {}
         config["org"] = \
-            validators.GithubOrganization(vals["org"])
+            validators.GithubOrganization(values["org"])
         config["repo"] = \
-            validators.GithubRepo('/'.join([vals["org"],
-                                           vals["repo"]]))
+            validators.GithubRepo('/'.join([values["org"],
+                                           values["repo"]]))
         config["display_number"] = \
-            validators.Integer(vals["display_number"])
+            validators.Integer(values["display_number"])
         return config
 
 

From f6a511bf7af19fca44e7fa80872664e8a9412a1e Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 13 2017 17:26:09 +0000
Subject: [PATCH 986/1001] Allow using other tags than input in the widget config


---

diff --git a/docs/api/widgets.rst b/docs/api/widgets.rst
index f828673..f1102bc 100644
--- a/docs/api/widgets.rst
+++ b/docs/api/widgets.rst
@@ -17,6 +17,11 @@ Widget class
 .. automodule:: hubs.widgets.base
    :private-members:
 
+Widget parameters
+-----------------
+
+.. automodule:: hubs.widgets.parameters
+
 Widget parameter validators
 ---------------------------
 
diff --git a/hubs/static/client/app/components/SimpleWidgetConfig.js b/hubs/static/client/app/components/SimpleWidgetConfig.js
index ca817dd..8228438 100644
--- a/hubs/static/client/app/components/SimpleWidgetConfig.js
+++ b/hubs/static/client/app/components/SimpleWidgetConfig.js
@@ -14,9 +14,11 @@ export default class SimpleWidgetConfig extends React.Component {
       return (
         <fieldset className="form-group row" key={field.name}>
           <strong>{field.label}</strong>
-          <input
+          <field.renderTag
             className="form-control"
-            type="text"
+            type={
+              field.renderTag === "input" ? field.renderType : null
+            }
             value={this.props.values[field.name] || ""}
             name={field.name}
             onChange={(e) => {
diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index cb834d1..d416897 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -159,7 +159,10 @@ class WidgetTest(APPTest):
                 {'default': 'I am a Fedora user, and this is my about',
                  'help': 'Text about a user.',
                  'label': 'Text',
-                 'name': 'text'},
+                 'name': 'text',
+                 'renderTag': 'input',
+                 'renderType': 'text',
+                 },
             ],
             'position': 'right',
             'selfUrl': '/api/hubs/ralph/widgets/{}/'.format(widget.idx),
diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index 715fa78..673ae66 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -128,11 +128,15 @@ class HalpViewsTestCase(WidgetTest):
                  'help': 'A comma-separated list of hubs to monitor.',
                  'label': 'Hubs',
                  'name': 'hubs',
+                 'renderTag': 'input',
+                 'renderType': 'text',
                  },
                 {'default': 4,
                  'help': 'The number of requests per page to display.',
                  'label': 'Requests per page',
                  'name': 'per_page',
+                 'renderTag': 'input',
+                 'renderType': 'text',
                  },
             ],
             'position': 'right',
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index db63192..bd10afc 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -9,50 +9,12 @@ import six
 from importlib import import_module
 from .caching import CachedFunction
 from .view import WidgetView
+from .parameters import WidgetParameter
 
 
 log = logging.getLogger(__name__)
 
 
-class WidgetParameter(object):
-    """
-    Configuration option for a widget.
-
-    A widget can be configured differently for each instance of this widget in
-    a hub.  The list of configuration options is described by the list of
-    :py:class:`WidgetParameter` objects returned by the widget's
-    :py:meth:`~Widget.get_parameters` method.
-
-    The value of the parameter is stored in the database as the value returned
-    by the validator's call.  It can thus be a string, an integer, a list, a
-    dict, or any JSON-serializable value.
-
-    Attributes:
-        name (str): The name of the parameter.
-        label (str): A humanized name of the parameter, which will be shown in
-            the UI.
-        default: The default value if this parameter is not set.
-        validator (callable): A validator function that will be used to convert
-            the parameter value to a JSON-serializable value, raising an
-            exception if it is invalid.
-        help (str): A help text that will be shown in the UI.
-        secret (bool): If True, this parameter will not be exposed to users
-            viewing the widget, it will only be available in the widget
-            configuration.
-    """
-
-    _attrs = ('name', 'label', 'default', 'validator', 'help', 'secret')
-
-    def __init__(self, **kwargs):
-        for name in self._attrs:
-            setattr(self, name, kwargs.pop(name, None))
-        for name in kwargs:
-            raise TypeError("Invalid attribute: %s" % name)
-        # Set default validator
-        if self.validator is None:
-            self.validator = lambda x: x
-
-
 class Widget(object):
     """
     The main widget class, you must subclass it to create a widget.
@@ -254,16 +216,10 @@ class Widget(object):
             hiddenIfEmpty=self.hidden_if_empty,
             cssClass=self.display_css,
             isReact=self.is_react,
-            params=[],
+            params=[
+                param.to_dict() for param in self.get_parameters()
+            ],
         )
-        for param in self.get_parameters():
-            param_data = dict(
-                name=param.name,
-                label=param.label,
-                default=param.default,
-                help=param.help,
-                )
-            props["params"].append(param_data)
         if instance is not None:
             props.update({
                 "idx": instance.idx,
diff --git a/hubs/widgets/parameters.py b/hubs/widgets/parameters.py
new file mode 100644
index 0000000..43c672e
--- /dev/null
+++ b/hubs/widgets/parameters.py
@@ -0,0 +1,65 @@
+from __future__ import unicode_literals, absolute_import
+
+from .validators import Noop
+
+
+class WidgetParameter(object):
+    """
+    Configuration option for a widget.
+
+    A widget can be configured differently for each instance of this widget in
+    a hub.  The list of configuration options is described by the list of
+    :py:class:`WidgetParameter` objects returned by the widget's
+    :py:meth:`~Widget.get_parameters` method.
+
+    The value of the parameter is stored in the database as the value returned
+    by the validator's call.  It can thus be a string, an integer, a list, a
+    dict, or any JSON-serializable value.
+
+    Attributes:
+        name (str): The name of the parameter.
+        label (str): A humanized name of the parameter, which will be shown in
+            the UI.
+        default: The default value if this parameter is not set.
+        validator (callable): A validator function that will be used to convert
+            the parameter value to a JSON-serializable value, raising an
+            exception if it is invalid.
+        help (str): A help text that will be shown in the UI.
+        secret (bool): If True, this parameter will not be exposed to users
+            viewing the widget, it will only be available in the widget
+            configuration.
+        render_tag (str): The HTML tag to use when rendering.
+        render_type (str): The HTML type attribute to use when rendering if the
+            tag is ``input``.
+    """
+
+    _defaults = {
+        "label": None,
+        "default": None,
+        "help": None,
+        "validator": Noop,
+        "secret": False,
+        "render_tag": "input",
+        "render_type": "text",
+    }
+
+    def __init__(self, name, **kwargs):
+        self.name = name
+        for attr, default in self._defaults.items():
+            setattr(self, attr, kwargs.pop(attr, default))
+        for kw in kwargs:
+            raise TypeError("Invalid argument: %s" % kw)
+
+    def to_dict(self):
+        """
+        Returns:
+            (dict): A JS-ready representation of the parameter.
+        """
+        return dict(
+            name=self.name,
+            label=self.label,
+            default=self.default,
+            renderTag=self.render_tag,
+            renderType=self.render_type,
+            help=self.help,
+            )
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index f8c5b8f..85424fb 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -18,6 +18,11 @@ import requests
 import six
 
 
+def Noop(value):
+    """Does no validation, just return the value."""
+    return value
+
+
 def Required(value):
     """Raises an error if the value is ``False``-like."""
     if not bool(value):

From 360a203fd9a579f0f163f8086f291d14d5db63fd Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 13 2017 18:00:17 +0000
Subject: [PATCH 987/1001] Some more CSS fixes


---

diff --git a/hubs/static/client/app/components/WidgetChrome.css b/hubs/static/client/app/components/WidgetChrome.css
index 6878ef8..bd8a405 100644
--- a/hubs/static/client/app/components/WidgetChrome.css
+++ b/hubs/static/client/app/components/WidgetChrome.css
@@ -3,7 +3,7 @@
   margin-bottom: .5rem;
 }
 
-.widget .card {
+.WidgetChrome {
   width: 100%;
 }
 
diff --git a/hubs/static/client/app/components/WidgetChrome.js b/hubs/static/client/app/components/WidgetChrome.js
index 374b610..3f04c90 100644
--- a/hubs/static/client/app/components/WidgetChrome.js
+++ b/hubs/static/client/app/components/WidgetChrome.js
@@ -50,7 +50,7 @@ class WidgetChrome extends React.PureComponent {
         }
         <div className="card-block">
           { this.props.editMode &&
-            <div className="text-muted">Content hidden in edit mode</div>
+            <div className="text-muted p-2">Content hidden in edit mode</div>
             ||
             this.props.children
           }

From 8dd308a50c1b0ead6c8ad8052dbba4f95b5f7da1 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 13 2017 18:00:19 +0000
Subject: [PATCH 988/1001] Enable Redux devtools extension


---

diff --git a/hubs/static/client/app/components/WidgetsArea.js b/hubs/static/client/app/components/WidgetsArea.js
index 9fe6508..5dcbc18 100644
--- a/hubs/static/client/app/components/WidgetsArea.js
+++ b/hubs/static/client/app/components/WidgetsArea.js
@@ -76,7 +76,6 @@ WidgetsArea.propTypes = {
 
 
 const mapStateToProps = (state) => {
-  const confWidgetId = state.ui.widgetConfigDialogOpen;
   return {
     hub: state.entities.hub,
     widgets: state.entities.widgets,
diff --git a/hubs/static/client/app/core/store.js b/hubs/static/client/app/core/store.js
index f04ec7f..7d412f4 100644
--- a/hubs/static/client/app/core/store.js
+++ b/hubs/static/client/app/core/store.js
@@ -1,8 +1,14 @@
-import { createStore, applyMiddleware } from 'redux';
+import {
+  createStore,
+  applyMiddleware,
+  compose
+  } from 'redux';
 import thunk from 'redux-thunk';
 import rootReducer from './reducers';
 
 
+const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
+
 let middleware = [
   thunk
 ]
@@ -16,6 +22,8 @@ export default function getStore(initialState) {
   return createStore(
     rootReducer,
     initialState,
-    applyMiddleware(...middleware)
+    composeEnhancers(
+      applyMiddleware(...middleware)
+    )
   );
 }

From f0f2a78d5854ad34dc63f67e3fc325d3241645f4 Mon Sep 17 00:00:00 2001
From: anar <anar@localhost.localdomain>
Date: Oct 18 2017 15:09:20 +0000
Subject: [PATCH 989/1001] Added files created by testing


---

diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_organization b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_organization
new file mode 100644
index 0000000..dcfc6ae
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_organization
@@ -0,0 +1,86 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Wed, 18 Oct 2017 14:57:08 GMT']
+      etag: [W/"26ff4247338ae3b104803156575c2cff"]
+      expect-ct: ['max-age=2592000; report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['8483:248DD:3178E2B:58E7F3D:59E76BC3']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['39']
+      x-ratelimit-reset: ['1508341503']
+      x-runtime-rack: ['0.020675']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/something-that-does-not-exist
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAxXJMQ7CMAwF0Ksgs5J6YOsBGHsFFJqvNFISV7HdBfXuhfW9LzWoxgyaaRG7vcR7
+        ogclWb2hW7Qi/e2j/n4z23VmTjhQZceYcrHNP9MqjY8nu2Io3zMsxKCl54rwNzovaRNpS2YAAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Wed, 18 Oct 2017 14:57:09 GMT']
+      expect-ct: ['max-age=2592000; report-uri="https://api.github.com/_private/browser/errors"']
+      server: [GitHub.com]
+      status: [404 Not Found]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['9928:248DC:1970632:35564D7:59E76BC4']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['38']
+      x-ratelimit-reset: ['1508341503']
+      x-runtime-rack: ['0.013258']
+      x-xss-protection: [1; mode=block]
+    status: {code: 404, message: Not Found}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_repo b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_repo
new file mode 100644
index 0000000..575ba8d
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_repo
@@ -0,0 +1,99 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/repos/fedora-infra/fedmsg
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA+1Yy27jOBD8lUDXdUzbSjIZAYvZ094GuwvkNBeDlmiJE4kUSMpGIuTft0jqZQN+
+        hL4GCBybYBWLTXazu9uIZ1ESx6vv8fPTLBK0YlESbVlW6TyaRdumLNfjoFT0noutomSYIfeCqShp
+        o1LmXHjsMA0Mnn759BR/m0V0Rw1V60aVmFgYU+uEED+ol/Ocm6LZNJqpVArDhJmnsiINiWMH/7H7
+        8wGEuepYLHOEgSO2mndEHg02bdVONRWmKo9E+LUd5GjyVpal3IPlWPalhciAtIZ0LFzkgSxAtkSa
+        gsF62NKHNQTX5vOiHKol9t+aZ5ZH40gUyz4trMNBlr0CHy1RrJaOsNnoVPHacCk+L/AADTapcir4
+        Ow1jA1qDxEr7vBSHAprtcBk/D/ewltSK72j6Zk2jWMr4DsYOpDzCg9G81dZj/5lYyR4BN2xNs8p6
+        5JaWmn3MIifDYLIbmMH/rvWC0dszNpwsFv2bZUyBMrv7ybSm8P/8bg8nvvvFlPz5H3RspXodFjzr
+        qM7WB743rmpZLpj/JBxeCDCkvLK3YA6LbQk+O5dJ4c10g5Bi5KW4cFrYAUlLpj/tVTGMVsGCHRgk
+        hZThlnNgkHCtG3bVjT29WcehSe8Soqk2Popd4winaT0aGqnWPBeMBVtsIGhJH2A3ioq0CKfs8S3x
+        39yp0jxYosWCYlPKTTAH3jniCFqiC+qfEbO+RZVltPgDQsW2N0m0+IHQqBvO1cmzBAMd3i2DIw7W
+        1+NJ21mwpCJvaB7OOBDgdO2rmtP3i/nGaZ8YGUBnMynFN81tgWrksAr98w7/DTfhSDESunzhfBZy
+        ZtOTnMNtu6r4pSf7NFsHP7jSN1Lae3hMa39fzizOy7T4lozx1AfrjjnUml207vVN+bvUPPjoezxp
+        /6ipKWwEwjI1VSxUbAcn7YYiz5nP523BqMtsK6Zu8EqPBg1VaYGkLVRf2+ORiVTUuER5a+VlSJxL
+        SbNgWw4EIPNHFqrRo6fnXKPyCxbmwFO2ipdMGynCY+TIMOUV0vAtT68pDk670QFJ+0NzkbIZLcsZ
+        bqXhKcc9RWZrTwxJHwu3ikdDPopsXwyUDFc22MqKeXxLfCGXsbqUbzdFlAmFdUzFbHa/pgbJ/mqx
+        XN0v8Ld8WS2Tx0WyfP6FOU2dHcz5dr9c3C8eXxarZPGQxAs7p250MaFxU5bxywocj8niyU5BeOzu
+        Lr6hKXCiHu9qAlvhA6R1MYL+GiHJtIQ/hKQlLuGRl1y31u74bToPg7xCVqxGXjDpdfi2yRx2zVDL
+        ZzLVcy6J3Qp/x7zV9+f4IAVIZSNg/OUDhvfUIBvFozsd7FMHrPHvmymksOtSvfYOHSVGNbbUw0it
+        5G+WGj0dGwPIZOKev/KxSLRIm9sMI74Y6zTYnlHFlZJdU0fA8VGy10x0CnqxMTbgK7HEYiYzbPdp
+        3Fy314xtaVOatU+csbkMmX4pa+xu2g/46ju5YuW4bu47VrDWV9+pazJe7NZ99Z3QfD3RM0XGctC3
+        wsW6vu8kmNmjB9NHAuv+0xKiiyTx6uN/dyzNvYwWAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Wed, 18 Oct 2017 14:57:10 GMT']
+      etag: [W/"38e039a20d5cd6cc6f07ddf3cecca325"]
+      expect-ct: ['max-age=2592000; report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Thu, 05 Oct 2017 02:04:30 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['B0BB:248DD:3178F42:58E812F:59E76BC5']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['37']
+      x-ratelimit-reset: ['1508341503']
+      x-runtime-rack: ['0.039710']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/repos/fedora-infra/something-that-does-not-exist
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA6tWyk0tLk5MT1WyUvLLL1Fwyy/NS1HSUUrJTy7NTc0rSSzJzM+LLy3KAcpnlJQU
+        FFvp66eklqXm5BekFumlZ5ZklCbpJefn6pcZK9UCAP6TTUJNAAAA
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Wed, 18 Oct 2017 14:57:10 GMT']
+      expect-ct: ['max-age=2592000; report-uri="https://api.github.com/_private/browser/errors"']
+      server: [GitHub.com]
+      status: [404 Not Found]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['5100:248DD:3178FF1:58E825A:59E76BC6']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['36']
+      x-ratelimit-reset: ['1508341503']
+      x-runtime-rack: ['0.018622']
+      x-xss-protection: [1; mode=block]
+    status: {code: 404, message: Not Found}
+version: 1

From 5db2f3c7a4a826ef4f87c0eb52dc806f677d4f58 Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Oct 18 2017 15:23:22 +0000
Subject: [PATCH 990/1001] Merge #400 `Implementation of GithubOrganization and GithubRepo validators`


---

diff --git a/hubs/tests/test_widget_validators.py b/hubs/tests/test_widget_validators.py
index d421aa5..96d887f 100644
--- a/hubs/tests/test_widget_validators.py
+++ b/hubs/tests/test_widget_validators.py
@@ -30,7 +30,6 @@ class ValidatorsTest(APPTest):
         self.assertRaises(
             ValueError, validators.Username, "nobody")
 
-    @unittest.skip("Not implemented yet")
     def test_github_organization(self):
         self.assertEqual(
             validators.GithubOrganization("fedora-infra"),
@@ -40,12 +39,14 @@ class ValidatorsTest(APPTest):
             validators.GithubOrganization,
             "something-that-does-not-exist")
 
-    @unittest.skip("Not implemented yet")
     def test_github_repo(self):
         self.assertEqual(
-            validators.GithubRepo("fedmsg"), "fedmsg")
+            validators.GithubRepo('/'.join(["fedora-infra",
+                                            "fedmsg"])),
+            "fedmsg")
         self.assertRaises(ValueError, validators.GithubRepo,
-                          "something-that-does-not-exist")
+                          '/'.join(["fedora-infra",
+                                    "something-that-does-not-exist"]))
 
     def test_fmncontext(self):
         self.assertEqual(validators.FMNContext("email"), "email")
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_organization b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_organization
new file mode 100644
index 0000000..dcfc6ae
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_organization
@@ -0,0 +1,86 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Wed, 18 Oct 2017 14:57:08 GMT']
+      etag: [W/"26ff4247338ae3b104803156575c2cff"]
+      expect-ct: ['max-age=2592000; report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['8483:248DD:3178E2B:58E7F3D:59E76BC3']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['39']
+      x-ratelimit-reset: ['1508341503']
+      x-runtime-rack: ['0.020675']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/something-that-does-not-exist
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAxXJMQ7CMAwF0Ksgs5J6YOsBGHsFFJqvNFISV7HdBfXuhfW9LzWoxgyaaRG7vcR7
+        ogclWb2hW7Qi/e2j/n4z23VmTjhQZceYcrHNP9MqjY8nu2Io3zMsxKCl54rwNzovaRNpS2YAAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Wed, 18 Oct 2017 14:57:09 GMT']
+      expect-ct: ['max-age=2592000; report-uri="https://api.github.com/_private/browser/errors"']
+      server: [GitHub.com]
+      status: [404 Not Found]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['9928:248DC:1970632:35564D7:59E76BC4']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['38']
+      x-ratelimit-reset: ['1508341503']
+      x-runtime-rack: ['0.013258']
+      x-xss-protection: [1; mode=block]
+    status: {code: 404, message: Not Found}
+version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_repo b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_repo
new file mode 100644
index 0000000..575ba8d
--- /dev/null
+++ b/hubs/tests/vcr-request-data/hubs.tests.test_widget_validators.ValidatorsTest.test_github_repo
@@ -0,0 +1,99 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/repos/fedora-infra/fedmsg
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA+1Yy27jOBD8lUDXdUzbSjIZAYvZ094GuwvkNBeDlmiJE4kUSMpGIuTft0jqZQN+
+        hL4GCBybYBWLTXazu9uIZ1ESx6vv8fPTLBK0YlESbVlW6TyaRdumLNfjoFT0noutomSYIfeCqShp
+        o1LmXHjsMA0Mnn759BR/m0V0Rw1V60aVmFgYU+uEED+ol/Ocm6LZNJqpVArDhJmnsiINiWMH/7H7
+        8wGEuepYLHOEgSO2mndEHg02bdVONRWmKo9E+LUd5GjyVpal3IPlWPalhciAtIZ0LFzkgSxAtkSa
+        gsF62NKHNQTX5vOiHKol9t+aZ5ZH40gUyz4trMNBlr0CHy1RrJaOsNnoVPHacCk+L/AADTapcir4
+        Ow1jA1qDxEr7vBSHAprtcBk/D/ewltSK72j6Zk2jWMr4DsYOpDzCg9G81dZj/5lYyR4BN2xNs8p6
+        5JaWmn3MIifDYLIbmMH/rvWC0dszNpwsFv2bZUyBMrv7ybSm8P/8bg8nvvvFlPz5H3RspXodFjzr
+        qM7WB743rmpZLpj/JBxeCDCkvLK3YA6LbQk+O5dJ4c10g5Bi5KW4cFrYAUlLpj/tVTGMVsGCHRgk
+        hZThlnNgkHCtG3bVjT29WcehSe8Soqk2Popd4winaT0aGqnWPBeMBVtsIGhJH2A3ioq0CKfs8S3x
+        39yp0jxYosWCYlPKTTAH3jniCFqiC+qfEbO+RZVltPgDQsW2N0m0+IHQqBvO1cmzBAMd3i2DIw7W
+        1+NJ21mwpCJvaB7OOBDgdO2rmtP3i/nGaZ8YGUBnMynFN81tgWrksAr98w7/DTfhSDESunzhfBZy
+        ZtOTnMNtu6r4pSf7NFsHP7jSN1Lae3hMa39fzizOy7T4lozx1AfrjjnUml207vVN+bvUPPjoezxp
+        /6ipKWwEwjI1VSxUbAcn7YYiz5nP523BqMtsK6Zu8EqPBg1VaYGkLVRf2+ORiVTUuER5a+VlSJxL
+        SbNgWw4EIPNHFqrRo6fnXKPyCxbmwFO2ipdMGynCY+TIMOUV0vAtT68pDk670QFJ+0NzkbIZLcsZ
+        bqXhKcc9RWZrTwxJHwu3ikdDPopsXwyUDFc22MqKeXxLfCGXsbqUbzdFlAmFdUzFbHa/pgbJ/mqx
+        XN0v8Ld8WS2Tx0WyfP6FOU2dHcz5dr9c3C8eXxarZPGQxAs7p250MaFxU5bxywocj8niyU5BeOzu
+        Lr6hKXCiHu9qAlvhA6R1MYL+GiHJtIQ/hKQlLuGRl1y31u74bToPg7xCVqxGXjDpdfi2yRx2zVDL
+        ZzLVcy6J3Qp/x7zV9+f4IAVIZSNg/OUDhvfUIBvFozsd7FMHrPHvmymksOtSvfYOHSVGNbbUw0it
+        5G+WGj0dGwPIZOKev/KxSLRIm9sMI74Y6zTYnlHFlZJdU0fA8VGy10x0CnqxMTbgK7HEYiYzbPdp
+        3Fy314xtaVOatU+csbkMmX4pa+xu2g/46ju5YuW4bu47VrDWV9+pazJe7NZ99Z3QfD3RM0XGctC3
+        wsW6vu8kmNmjB9NHAuv+0xKiiyTx6uN/dyzNvYwWAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Wed, 18 Oct 2017 14:57:10 GMT']
+      etag: [W/"38e039a20d5cd6cc6f07ddf3cecca325"]
+      expect-ct: ['max-age=2592000; report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Thu, 05 Oct 2017 02:04:30 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['B0BB:248DD:3178F42:58E812F:59E76BC5']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['37']
+      x-ratelimit-reset: ['1508341503']
+      x-runtime-rack: ['0.039710']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/repos/fedora-infra/something-that-does-not-exist
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA6tWyk0tLk5MT1WyUvLLL1Fwyy/NS1HSUUrJTy7NTc0rSSzJzM+LLy3KAcpnlJQU
+        FFvp66eklqXm5BekFumlZ5ZklCbpJefn6pcZK9UCAP6TTUJNAAAA
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Wed, 18 Oct 2017 14:57:10 GMT']
+      expect-ct: ['max-age=2592000; report-uri="https://api.github.com/_private/browser/errors"']
+      server: [GitHub.com]
+      status: [404 Not Found]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['5100:248DD:3178FF1:58E825A:59E76BC6']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['36']
+      x-ratelimit-reset: ['1508341503']
+      x-runtime-rack: ['0.018622']
+      x-xss-protection: [1; mode=block]
+    status: {code: 404, message: Not Found}
+version: 1
diff --git a/hubs/utils/github.py b/hubs/utils/github.py
index 47c1018..5da725a 100644
--- a/hubs/utils/github.py
+++ b/hubs/utils/github.py
@@ -9,6 +9,22 @@ import requests
 log = logging.getLogger(__name__)
 
 
+def github_org_is_valid(username):
+    log.info("Finding github organization for {}".format(username))
+    tmpl = "https://api.github.com/users/{username}"
+    url = tmpl.format(username=username)
+    result = requests.get(url)
+    return result.ok
+
+
+def github_repo_is_valid(username, repo):
+    log.info("Finding github repo for {} and {} ".format(repo, username))
+    tmpl = "https://api.github.com/repos/{username}/{repo}"
+    url = tmpl.format(username=username, repo=repo)
+    result = requests.get(url)
+    return result.ok
+
+
 def github_repos(token, username):
     log.info("Finding github repos for %r" % username)
     tmpl = "https://api.github.com/users/{username}/repos?per_page=100"
diff --git a/hubs/utils/views.py b/hubs/utils/views.py
index 2508dad..0fe1e2b 100644
--- a/hubs/utils/views.py
+++ b/hubs/utils/views.py
@@ -118,16 +118,17 @@ def configure_widget_instance(widget_instance, widget_config):
     """
     if not widget_config:
         return
-    config = {}
+    values = {}
     for param in widget_instance.module.get_parameters():
         val = widget_config.get(param.name)
         if not val:
             raise WidgetConfigError(
                 'You must provide a value for: %s' % param.name)
-        try:
-            config[param.name] = param.validator(val)
-        except ValueError as err:
-            raise WidgetConfigError('Invalid data provided, error: %s' % err)
+        values[param.name] = val
+    try:
+        config = widget_instance.module.validate_parameters(values)
+    except ValueError as err:
+        raise WidgetConfigError('Invalid data provided, error: %s' % err)
     # Updating in-place is not supported, it's a class property.
     cur_config = widget_instance.config or {}
     cur_config = cur_config.copy()
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index bd10afc..dba77a0 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -11,7 +11,6 @@ from .caching import CachedFunction
 from .view import WidgetView
 from .parameters import WidgetParameter
 
-
 log = logging.getLogger(__name__)
 
 
@@ -62,6 +61,22 @@ class Widget(object):
             self.label = self.name.replace("_", " ").replace(".", ": ").title()
         self._template_environment = None
 
+    def validate_parameters(self, values):
+        """
+        Validate the parameters of a widget.
+
+        Args:
+            values (dict): dictionary of values associated
+                           with corresponding parameters.
+
+        Returns:
+            dict: validated parameter values.
+        """
+        config = {}
+        for param in self.get_parameters():
+            config[param.name] = param.validator(values[param.name])
+        return config
+
     def validate(self):
         """
         Ensure that the widget has the bits it needs.
@@ -229,10 +244,11 @@ class Widget(object):
                     "api_hub_widget", hub=instance.hub.name, idx=instance.idx),
                 "config": {},
             })
+            validated = self.validate_parameters(instance.config)
             for param in self.get_parameters():
                 if param.secret and not with_secret_config:
                     continue
-                value = param.validator(instance.config[param.name])
+                value = validated[param.name]
                 props["config"][param.name] = value
             if self.is_react:
                 props["component"] = self.name
diff --git a/hubs/widgets/githubissues/__init__.py b/hubs/widgets/githubissues/__init__.py
index fa0c996..c8c2956 100644
--- a/hubs/widgets/githubissues/__init__.py
+++ b/hubs/widgets/githubissues/__init__.py
@@ -34,6 +34,17 @@ class GitHubIssues(Widget):
             help="The number of tickets to display.",
         )]
 
+    def validate_parameters(self, values):
+        config = {}
+        config["org"] = \
+            validators.GithubOrganization(values["org"])
+        config["repo"] = \
+            validators.GithubRepo('/'.join([values["org"],
+                                           values["repo"]]))
+        config["display_number"] = \
+            validators.Integer(values["display_number"])
+        return config
+
 
 class BaseView(RootWidgetView):
 
diff --git a/hubs/widgets/validators.py b/hubs/widgets/validators.py
index 85424fb..47f185a 100644
--- a/hubs/widgets/validators.py
+++ b/hubs/widgets/validators.py
@@ -10,6 +10,7 @@ will return the validated value.
 """
 
 from __future__ import unicode_literals
+from hubs.utils.github import github_org_is_valid, github_repo_is_valid
 
 import flask
 import hubs.models
@@ -66,14 +67,17 @@ def Username(value):
 
 def GithubOrganization(value):
     """Fails if the Github organization name does not exist."""
-    # TODO -- implement this.
+    if not github_org_is_valid(value):
+        raise ValueError('Github organization does not exist')
     return value
 
 
 def GithubRepo(value):
     """Fails if the Github repository name does not exist."""
-    # TODO -- implement this.
-    return value
+    username, repo = value.split('/')
+    if not github_repo_is_valid(username, repo):
+        raise ValueError('Github repository does not exist')
+    return repo
 
 
 def FMNContext(value):

From 56b117cd94b5939c55ba7b369953b66d95e15777 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 19 2017 09:42:04 +0000
Subject: [PATCH 991/1001] Improve upon commit f6a511bf


---

diff --git a/hubs/static/client/app/components/SimpleWidgetConfig.js b/hubs/static/client/app/components/SimpleWidgetConfig.js
index 8228438..24d8e24 100644
--- a/hubs/static/client/app/components/SimpleWidgetConfig.js
+++ b/hubs/static/client/app/components/SimpleWidgetConfig.js
@@ -11,14 +11,15 @@ export default class SimpleWidgetConfig extends React.Component {
 
   render() {
     let fields = this.props.widget.params.map((field) => {
+      const attributes = {
+        className: "form-control",
+        ...field.renderAttributes
+      };
       return (
         <fieldset className="form-group row" key={field.name}>
           <strong>{field.label}</strong>
           <field.renderTag
-            className="form-control"
-            type={
-              field.renderTag === "input" ? field.renderType : null
-            }
+            {...attributes}
             value={this.props.values[field.name] || ""}
             name={field.name}
             onChange={(e) => {
diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index d416897..03bb58e 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -161,7 +161,7 @@ class WidgetTest(APPTest):
                  'label': 'Text',
                  'name': 'text',
                  'renderTag': 'input',
-                 'renderType': 'text',
+                 'renderAttributes': {'type': 'text'},
                  },
             ],
             'position': 'right',
diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index 673ae66..b12401e 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -129,14 +129,14 @@ class HalpViewsTestCase(WidgetTest):
                  'label': 'Hubs',
                  'name': 'hubs',
                  'renderTag': 'input',
-                 'renderType': 'text',
+                 'renderAttributes': {'type': 'text'},
                  },
                 {'default': 4,
                  'help': 'The number of requests per page to display.',
                  'label': 'Requests per page',
                  'name': 'per_page',
                  'renderTag': 'input',
-                 'renderType': 'text',
+                 'renderAttributes': {'type': 'text'},
                  },
             ],
             'position': 'right',
diff --git a/hubs/widgets/parameters.py b/hubs/widgets/parameters.py
index 43c672e..0b04bff 100644
--- a/hubs/widgets/parameters.py
+++ b/hubs/widgets/parameters.py
@@ -29,8 +29,8 @@ class WidgetParameter(object):
             viewing the widget, it will only be available in the widget
             configuration.
         render_tag (str): The HTML tag to use when rendering.
-        render_type (str): The HTML type attribute to use when rendering if the
-            tag is ``input``.
+        render_attributes (dict): A mapping of HTML attribute names to values
+            to use when rendering.
     """
 
     _defaults = {
@@ -40,13 +40,15 @@ class WidgetParameter(object):
         "validator": Noop,
         "secret": False,
         "render_tag": "input",
-        "render_type": "text",
+        "render_attributes": {},
     }
 
     def __init__(self, name, **kwargs):
         self.name = name
         for attr, default in self._defaults.items():
             setattr(self, attr, kwargs.pop(attr, default))
+        if self.render_tag == "input" and "type" not in self.render_attributes:
+            self.render_attributes["type"] = "text"
         for kw in kwargs:
             raise TypeError("Invalid argument: %s" % kw)
 
@@ -60,6 +62,6 @@ class WidgetParameter(object):
             label=self.label,
             default=self.default,
             renderTag=self.render_tag,
-            renderType=self.render_type,
+            renderAttributes=self.render_attributes,
             help=self.help,
             )

From b9ecaaa73efc910d8581310ce834a9fd49771627 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 19 2017 16:16:19 +0000
Subject: [PATCH 992/1001] Use a drag handle for widgets


---

diff --git a/hubs/static/client/app/components/WidgetChrome.css b/hubs/static/client/app/components/WidgetChrome.css
index bd8a405..16c3f48 100644
--- a/hubs/static/client/app/components/WidgetChrome.css
+++ b/hubs/static/client/app/components/WidgetChrome.css
@@ -7,22 +7,8 @@
   width: 100%;
 }
 
-.widget-buttons {
-  font-size: 80%;
-  position: absolute;
-  top: 0;
-  right: 0;
-  padding: .3rem;
-}
-
-.widget .widget-buttons a {
-  margin-right: .4rem;
-  color: #373a3c;
-}
-.widget .widget-buttons a:hover {
-  text-decoration: none;
-}
-
-.widget-edit .card-header {
+.widget-edit .drag-handle {
     cursor: ns-resize;
+    margin-right: .5rem;
+    font-size: 14px;
 }
diff --git a/hubs/static/client/app/components/WidgetChrome.js b/hubs/static/client/app/components/WidgetChrome.js
index 3f04c90..485303b 100644
--- a/hubs/static/client/app/components/WidgetChrome.js
+++ b/hubs/static/client/app/components/WidgetChrome.js
@@ -1,10 +1,16 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
+import { SortableHandle } from 'react-sortable-hoc';
 import { openConfigDialog } from "../core/actions/widget";
 import "./WidgetChrome.css";
 
 
+const DragHandle = SortableHandle(() => (
+  <i className="fa fa-bars mr-2 drag-handle" aria-hidden="true"></i>
+))
+
+
 class WidgetChrome extends React.PureComponent {
 
   propTypes: {
@@ -26,28 +32,36 @@ class WidgetChrome extends React.PureComponent {
   }
 
   render() {
+    // Make sure there's always a title in edit mode
     const title = (this.props.editMode && !this.props.widget.title) ? this.props.widget.label : this.props.widget.title;
     let cssClass = `WidgetChrome card widget-${this.props.widget.name}`;
     if (this.props.widget.cssClass) {
       cssClass += " " + this.props.widget.cssClass;
     }
+    let header = null;
+    if (this.props.editMode) {
+      header = (
+        <div className="card-header">
+          <DragHandle />
+          {title}
+          <a href="#"
+            className="float-right text-dark"
+            onClick={this.handleEditButtonClicked}
+            >
+            <i className="fa fa-cog" aria-hidden="true"></i>
+          </a>
+        </div>
+      );
+    } else if (title) {
+      header = (
+        <div className="card-header">
+          {title}
+        </div>
+      );
+    }
     return (
       <div className={cssClass}>
-        <div className="widget-buttons">
-          { this.props.editMode &&
-            <a href="#"
-              onClick={this.handleEditButtonClicked}
-              >
-              <i className="fa fa-cog" aria-hidden="true"></i>
-            </a>
-          }
-        </div>
-        { title ?
-          <div className="card-header">
-            {title}
-          </div>
-          : null
-        }
+        {header}
         <div className="card-block">
           { this.props.editMode &&
             <div className="text-muted p-2">Content hidden in edit mode</div>
diff --git a/hubs/static/client/app/components/WidgetsList.js b/hubs/static/client/app/components/WidgetsList.js
index 137b120..c23de78 100644
--- a/hubs/static/client/app/components/WidgetsList.js
+++ b/hubs/static/client/app/components/WidgetsList.js
@@ -44,6 +44,7 @@ function EditableWidgetsList(props) {
       <SortableWidgetList
         lockAxis="y"
         onSortEnd={props.handleWidgetMoved}
+        useDragHandle={true}
         helperClass="widget--dragged"
         {...props}
         />
diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css
index 0260884..9257a3b 100644
--- a/hubs/static/css/style.css
+++ b/hubs/static/css/style.css
@@ -294,6 +294,9 @@ font-size: 32pt;
   background-color: #17a2b8;
   color: #f8f9fa;
 }
+.card-info > .card-header > a {
+  color: #f8f9fa !important;
+}
 
 
 /*

From 129869f512e9c6ba2c6225fadfa258699a98b3fd Mon Sep 17 00:00:00 2001
From: Shaily <shaily15297@yahoo.com>
Date: Oct 22 2017 08:36:23 +0000
Subject: [PATCH 993/1001] Add prop to allow making any widget's configuration modal large


---

diff --git a/hubs/static/client/app/components/WidgetConfigDialog.js b/hubs/static/client/app/components/WidgetConfigDialog.js
index 58987da..2d0e158 100644
--- a/hubs/static/client/app/components/WidgetConfigDialog.js
+++ b/hubs/static/client/app/components/WidgetConfigDialog.js
@@ -121,7 +121,7 @@ class WidgetConfigDialog extends React.Component {
     return (
       <Modal
         onCloseClicked={this.handleClose}
-        isLarge={this.props.widget.isReact}
+        isLarge={this.props.widget.isReact || this.props.widget.isLarge}
         title={`Configuring widget ${this.props.widget.label}`}
         footer={footer}
         >
diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index dba77a0..07735e4 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -37,6 +37,8 @@ class Widget(object):
             cached functions must be looked for.  By default, they are looked
             for in the same module.
         is_react (bool): Set to True if the widget is React-based.
+        is_large (bool): Set to True if the widget configuration modal should
+            be large.
         hidden_if_empty (bool): Set to True if the widget box should be
             entirely hidden from the UI when no data is produced. As a
             consequence, there will also be no progress spinner when the widget
@@ -51,6 +53,7 @@ class Widget(object):
     views_module = None
     cached_functions_module = None
     is_react = False
+    is_large = False
     hidden_if_empty = False
 
     def __init__(self):
@@ -231,6 +234,7 @@ class Widget(object):
             hiddenIfEmpty=self.hidden_if_empty,
             cssClass=self.display_css,
             isReact=self.is_react,
+            isLarge=self.is_large,
             params=[
                 param.to_dict() for param in self.get_parameters()
             ],

From 443932c6bffbf1663e6b7e2c173226311faaa0d8 Mon Sep 17 00:00:00 2001
From: Shaily <shaily15297@yahoo.com>
Date: Oct 22 2017 11:06:56 +0000
Subject: [PATCH 994/1001] Remove pattern lab CSS


---

diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 3f344a9..01a0ad2 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -2,7 +2,6 @@
 <html lang='en'>
 <head>
   <title>{% block title %}{% endblock %}</title>
-  <link href="{{ url_for('static', filename='css/style-patternlab.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.min.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />

From 58011e58080baaf6bdfe3aee2b88f570406b3122 Mon Sep 17 00:00:00 2001
From: Shaily <shaily15297@yahoo.com>
Date: Oct 22 2017 11:08:16 +0000
Subject: [PATCH 995/1001] Add markdown rendering capability to Sticky Note widget


---

diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index 13c6af3..7399bff 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -2,8 +2,11 @@ from __future__ import unicode_literals
 
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
+from hubs.widgets.caching import CachedFunction
 from hubs.widgets.view import RootWidgetView
 
+from markdown import markdown
+
 
 class Sticky(Widget):
 
@@ -11,9 +14,12 @@ class Sticky(Widget):
     label = "Sticky Note"
     position = "both"
     display_css = "card-info"
+    is_large = True
     parameters = [
         dict(
             name="text",
+            render_tag="textarea",
+            render_attributes={"rows": "30"},
             label="Text",
             default="Lorem ipsum dolor...",
             validator=validators.Text,
@@ -24,7 +30,18 @@ class Sticky(Widget):
 class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
-        # TODO -- render with markdown
+        md = ParseMarkdown(instance)
         return dict(
-            text=instance.config["text"],
-            )
+            text=md()
+        )
+
+
+class ParseMarkdown(CachedFunction):
+
+    def execute(self):
+        text = self.instance.config["text"]
+        return markdown(text, extensions=['markdown.extensions.extra',
+                                          'markdown.extensions.sane_lists'])
+
+    def should_invalidate(self, message):
+        return False
diff --git a/requirements.txt b/requirements.txt
index 4a42cec..8232aff 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,6 +13,7 @@ fmn.lib
 fmn.rules
 gunicorn
 html5lib==0.9999999
+markdown
 munch
 psycopg2
 pymongo

From 4dbc5804b2923ba869c3e79a33f4ba915873fec4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 23 2017 09:59:16 +0000
Subject: [PATCH 996/1001] Fix VCR files following the GitHub validators implementation


---

diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete
index 1c79340..e823b14 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete
@@ -447,4 +447,51 @@ interactions:
           Expires=Fri, 27-Oct-2017 15:29:32 GMT; Secure; HttpOnly; Path=/']
       Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
     status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Mon, 23 Oct 2017 09:56:33 GMT']
+      etag: [W/"26ff4247338ae3b104803156575c2cff"]
+      expect-ct: ['max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['96D4:2E786:106B535:2457CA2:59EDBCD1']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['42']
+      x-ratelimit-reset: ['1508753124']
+      x-runtime-rack: ['0.019921']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
 version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete_unauthorized b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete_unauthorized
index 002f0d8..ffa0900 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete_unauthorized
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidget.test_delete_unauthorized
@@ -447,4 +447,51 @@ interactions:
           Expires=Fri, 27-Oct-2017 15:29:34 GMT; Secure; HttpOnly; Path=/']
       Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
     status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Mon, 23 Oct 2017 09:56:34 GMT']
+      etag: [W/"26ff4247338ae3b104803156575c2cff"]
+      expect-ct: ['max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['CE90:2E786:106B578:2457D46:59EDBCD2']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['41']
+      x-ratelimit-reset: ['1508753124']
+      x-runtime-rack: ['0.024875']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
 version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_removed_widget b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_removed_widget
index 3cb4651..6e4a914 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_removed_widget
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_removed_widget
@@ -447,4 +447,51 @@ interactions:
           Expires=Sat, 28-Oct-2017 12:13:40 GMT; Secure; HttpOnly; Path=/']
       Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
     status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Mon, 23 Oct 2017 09:56:35 GMT']
+      etag: [W/"26ff4247338ae3b104803156575c2cff"]
+      expect-ct: ['max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['96D8:2E787:20A5C95:40179E8:59EDBCD3']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['40']
+      x-ratelimit-reset: ['1508753124']
+      x-runtime-rack: ['0.021827']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
 version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets
index 3c51168..c84838b 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets
@@ -447,4 +447,51 @@ interactions:
           Expires=Fri, 27-Oct-2017 15:29:36 GMT; Secure; HttpOnly; Path=/']
       Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
     status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Mon, 23 Oct 2017 09:56:36 GMT']
+      etag: [W/"26ff4247338ae3b104803156575c2cff"]
+      expect-ct: ['max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['CE94:2E787:20A5CFE:4017AEB:59EDBCD4']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['39']
+      x-ratelimit-reset: ['1508753124']
+      x-runtime-rack: ['0.024877']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
 version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_preview b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_preview
index 6146a59..0ba4ad0 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_preview
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_preview
@@ -895,4 +895,98 @@ interactions:
           Expires=Sat, 28-Oct-2017 12:07:31 GMT; Secure; HttpOnly; Path=/']
       Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
     status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Mon, 23 Oct 2017 09:56:37 GMT']
+      etag: [W/"26ff4247338ae3b104803156575c2cff"]
+      expect-ct: ['max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['96DC:2E787:20A5D96:4017C00:59EDBCD5']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['38']
+      x-ratelimit-reset: ['1508753124']
+      x-runtime-rack: ['0.020314']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.3]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      Access-Control-Allow-Origin: ['*']
+      Access-Control-Expose-Headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      Cache-Control: ['public, max-age=60, s-maxage=60']
+      Content-Encoding: [gzip]
+      Content-Security-Policy: [default-src 'none']
+      Content-Type: [application/json; charset=utf-8]
+      Date: ['Mon, 23 Oct 2017 09:57:15 GMT']
+      ETag: [W/"26ff4247338ae3b104803156575c2cff"]
+      Expect-CT: ['max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"']
+      Last-Modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      Server: [GitHub.com]
+      Status: [200 OK]
+      Strict-Transport-Security: [max-age=31536000; includeSubdomains; preload]
+      Vary: [Accept]
+      X-Content-Type-Options: [nosniff]
+      X-Frame-Options: [deny]
+      X-GitHub-Media-Type: [github.v3; format=json]
+      X-GitHub-Request-Id: ['96F8:2E788:1981E34:44C59DD:59EDBCFB']
+      X-RateLimit-Limit: ['60']
+      X-RateLimit-Remaining: ['35']
+      X-RateLimit-Reset: ['1508753124']
+      X-Runtime-rack: ['0.017265']
+      X-XSS-Protection: [1; mode=block]
+    status: {code: 200, message: OK}
 version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_private b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_private
index 0450f91..ab0907c 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_private
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_get_widgets_private
@@ -447,4 +447,51 @@ interactions:
           Expires=Sat, 28-Oct-2017 12:07:33 GMT; Secure; HttpOnly; Path=/']
       Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
     status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Mon, 23 Oct 2017 09:56:38 GMT']
+      etag: [W/"26ff4247338ae3b104803156575c2cff"]
+      expect-ct: ['max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['CE98:2E785:7479EC:112E68A:59EDBCD6']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['37']
+      x-ratelimit-reset: ['1508753124']
+      x-runtime-rack: ['0.020721']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
 version: 1
diff --git a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_post_valid_widget_name_no_config b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_post_valid_widget_name_no_config
index cad3a65..2f29d37 100644
--- a/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_post_valid_widget_name_no_config
+++ b/hubs/tests/vcr-request-data/hubs.tests.views.test_api_hub_widget.TestAPIHubWidgets.test_post_valid_widget_name_no_config
@@ -447,4 +447,51 @@ interactions:
           Expires=Fri, 27-Oct-2017 15:29:38 GMT; Secure; HttpOnly; Path=/']
       Strict-Transport-Security: [max-age=15768000; includeSubDomains; preload]
     status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: ['*/*']
+      Accept-Encoding: ['gzip, deflate']
+      Connection: [keep-alive]
+      User-Agent: [python-requests/2.18.4]
+    method: GET
+    uri: https://api.github.com/users/fedora-infra
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAA52TzW6cMBSFXyXyehjjMJ02lqruKnXVzayyGRnjgRsZ2/IP0RTl3XsNJJogVRWz
+        Aiyf7x6OfUaibQuGcHJRjfWiAHPxguwINIRXFTseq687IgYRhT8nr3FjF6MLnNJ5MbB9C7FLdQrK
+        S2uiMnEvbU8TXeQ/hu8HBLZ+oWQywYUVzcECmtVIC3TlqYu9XpmYZ0+S1eaL1dq+ImVt+3+D6IcS
+        Tc7vYNo7KagcqY2dwvTwl95yEBDidlOTaqT5cYYmcwIeiVfNZmOLDm29GnQ0Uq+cnYCpDtKDi2DN
+        doOf1EizvhUG/oj7aKgOCMnWtluZVKhWA17G7fJZNlLnYRDymqPxSioYMOw7kSs9EuPVKezB75uU
+        8hFAVGfR9LmRF6GD2hEj+rzx51TPh1+5niH6JGPyChV4850wV8JN0npHaqzzbUedC/u5GM7bFyXj
+        HpOlqNNWTkfzLlS9AGz3TOnAK1FrnLtQwf7LwsNJiR55LtUa5HmOnrOSfSxNN5fw8r1MWMmbLyzI
+        9CVxYsSARcRJjyWripIV7OnEnvjhGz98ecYZyTWf9hyLsirY4fRY8orxsnomb38BYQwDb9AEAAA=
+    headers:
+      access-control-allow-origin: ['*']
+      access-control-expose-headers: ['ETag, Link, X-GitHub-OTP, X-RateLimit-Limit,
+          X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
+          X-Poll-Interval']
+      cache-control: ['public, max-age=60, s-maxage=60']
+      content-encoding: [gzip]
+      content-security-policy: [default-src 'none']
+      content-type: [application/json; charset=utf-8]
+      date: ['Mon, 23 Oct 2017 09:56:39 GMT']
+      etag: [W/"26ff4247338ae3b104803156575c2cff"]
+      expect-ct: ['max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"']
+      last-modified: ['Mon, 14 Mar 2016 20:31:03 GMT']
+      server: [GitHub.com]
+      status: [200 OK]
+      strict-transport-security: [max-age=31536000; includeSubdomains; preload]
+      vary: [Accept]
+      x-content-type-options: [nosniff]
+      x-frame-options: [deny]
+      x-github-media-type: [github.v3; format=json]
+      x-github-request-id: ['96E2:2E787:20A5ECB:4017E6C:59EDBCD7']
+      x-ratelimit-limit: ['60']
+      x-ratelimit-remaining: ['36']
+      x-ratelimit-reset: ['1508753124']
+      x-runtime-rack: ['0.019871']
+      x-xss-protection: [1; mode=block]
+    status: {code: 200, message: OK}
 version: 1

From e36cc8f197da50e8fe1300929d2a433b1c5288aa Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 23 2017 10:00:13 +0000
Subject: [PATCH 997/1001] Fix unit tests following 129869f5


---

diff --git a/hubs/tests/test_widget_base.py b/hubs/tests/test_widget_base.py
index 03bb58e..2db5f36 100644
--- a/hubs/tests/test_widget_base.py
+++ b/hubs/tests/test_widget_base.py
@@ -153,6 +153,7 @@ class WidgetTest(APPTest):
             'idx': widget.idx,
             'index': 500,
             'isReact': False,
+            'isLarge': False,
             'label': 'About',
             'name': 'about',
             'params': [
diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index b12401e..accc87e 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -121,6 +121,7 @@ class HalpViewsTestCase(WidgetTest):
             'idx': self.widget.idx,
             'index': 9,
             'isReact': True,
+            'isLarge': False,
             'label': 'Help Requests',
             'name': 'halp',
             'params': [

From 6e43c8667a612e57aa8860574b8be46b8845c0be Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 23 2017 10:12:42 +0000
Subject: [PATCH 998/1001] Be explicit with is_large


Don't assume all React widgets want a large config panel.

---

diff --git a/hubs/static/client/app/components/WidgetConfigDialog.js b/hubs/static/client/app/components/WidgetConfigDialog.js
index 2d0e158..b0b648c 100644
--- a/hubs/static/client/app/components/WidgetConfigDialog.js
+++ b/hubs/static/client/app/components/WidgetConfigDialog.js
@@ -121,7 +121,7 @@ class WidgetConfigDialog extends React.Component {
     return (
       <Modal
         onCloseClicked={this.handleClose}
-        isLarge={this.props.widget.isReact || this.props.widget.isLarge}
+        isLarge={this.props.widget.isLarge}
         title={`Configuring widget ${this.props.widget.label}`}
         footer={footer}
         >
diff --git a/hubs/tests/widgets/test_halp.py b/hubs/tests/widgets/test_halp.py
index accc87e..158f525 100644
--- a/hubs/tests/widgets/test_halp.py
+++ b/hubs/tests/widgets/test_halp.py
@@ -121,7 +121,7 @@ class HalpViewsTestCase(WidgetTest):
             'idx': self.widget.idx,
             'index': 9,
             'isReact': True,
-            'isLarge': False,
+            'isLarge': True,
             'label': 'Help Requests',
             'name': 'halp',
             'params': [
diff --git a/hubs/widgets/halp/__init__.py b/hubs/widgets/halp/__init__.py
index 8fc82d4..0164582 100644
--- a/hubs/widgets/halp/__init__.py
+++ b/hubs/widgets/halp/__init__.py
@@ -38,6 +38,7 @@ class Halp(Widget):
     views_module = ".views"
     cached_functions_module = ".functions"
     is_react = True
+    is_large = True
 
     def get_template_environment(self):
         env = super(Halp, self).get_template_environment()

From e8e1e4c71804ba06940724998cfe1dcae53dafb1 Mon Sep 17 00:00:00 2001
From: Shaily <shaily15297@yahoo.com>
Date: Oct 25 2017 23:04:58 +0000
Subject: [PATCH 999/1001] Add markdown test for Sticky Note widget


---

diff --git a/hubs/tests/widgets/test_sticky.py b/hubs/tests/widgets/test_sticky.py
new file mode 100644
index 0000000..d4b9902
--- /dev/null
+++ b/hubs/tests/widgets/test_sticky.py
@@ -0,0 +1,25 @@
+from __future__ import unicode_literals
+
+from . import WidgetTest
+
+
+class StickyTest(WidgetTest):
+
+    plugin = "sticky"
+    initial_widget_config = {
+        "text": """| Tables        | Are           | Cool  |
+                   | ------------- |:-------------:| -----:|
+                   | col 3 is      | right-aligned | $1600 |
+                   | col 2 is      | centered      |   $12 |
+                   | zebra stripes | are neat      |    $1 |
+                """
+    }
+
+    def populate(self):
+        super(StickyTest, self).populate()
+        self._add_widget_under_test()
+
+    def test_markdown_parse(self):
+        func = self.widget.module.get_cached_functions()['ParseMarkdown']
+        result = func(self.widget).execute()
+        self.assertRegexpMatches(result, r'^<table>(?s).*</table>$')

From b9b205977eb8767d61c7f57831a632d8f38b47bb Mon Sep 17 00:00:00 2001
From: Aurélien Bompard <aurelien@bompard.org>
Date: Oct 26 2017 13:35:06 +0000
Subject: [PATCH 1000/1001] Dont re-validate on config read


---

diff --git a/hubs/widgets/base.py b/hubs/widgets/base.py
index 07735e4..db6a67d 100644
--- a/hubs/widgets/base.py
+++ b/hubs/widgets/base.py
@@ -248,11 +248,10 @@ class Widget(object):
                     "api_hub_widget", hub=instance.hub.name, idx=instance.idx),
                 "config": {},
             })
-            validated = self.validate_parameters(instance.config)
             for param in self.get_parameters():
                 if param.secret and not with_secret_config:
                     continue
-                value = validated[param.name]
+                value = instance.config[param.name]
                 props["config"][param.name] = value
             if self.is_react:
                 props["component"] = self.name

From 6dd9cc00889a863c421e1a9588cd112f46c81cec Mon Sep 17 00:00:00 2001
From: Aurelien Bompard <aurelien@bompard.org>
Date: Oct 26 2017 14:09:04 +0000
Subject: [PATCH 1001/1001] Merge #408 `Use Markdown to render Sticky widget`


---

diff --git a/hubs/templates/master.html b/hubs/templates/master.html
index 3f344a9..01a0ad2 100644
--- a/hubs/templates/master.html
+++ b/hubs/templates/master.html
@@ -2,7 +2,6 @@
 <html lang='en'>
 <head>
   <title>{% block title %}{% endblock %}</title>
-  <link href="{{ url_for('static', filename='css/style-patternlab.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='fedora-bootstrap/fedora-bootstrap.min.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" />
   <link href="{{ url_for('static', filename='css/pace-theme-minimal.css') }}" rel="stylesheet" />
diff --git a/hubs/tests/widgets/test_sticky.py b/hubs/tests/widgets/test_sticky.py
new file mode 100644
index 0000000..d4b9902
--- /dev/null
+++ b/hubs/tests/widgets/test_sticky.py
@@ -0,0 +1,25 @@
+from __future__ import unicode_literals
+
+from . import WidgetTest
+
+
+class StickyTest(WidgetTest):
+
+    plugin = "sticky"
+    initial_widget_config = {
+        "text": """| Tables        | Are           | Cool  |
+                   | ------------- |:-------------:| -----:|
+                   | col 3 is      | right-aligned | $1600 |
+                   | col 2 is      | centered      |   $12 |
+                   | zebra stripes | are neat      |    $1 |
+                """
+    }
+
+    def populate(self):
+        super(StickyTest, self).populate()
+        self._add_widget_under_test()
+
+    def test_markdown_parse(self):
+        func = self.widget.module.get_cached_functions()['ParseMarkdown']
+        result = func(self.widget).execute()
+        self.assertRegexpMatches(result, r'^<table>(?s).*</table>$')
diff --git a/hubs/widgets/sticky/__init__.py b/hubs/widgets/sticky/__init__.py
index 13c6af3..7399bff 100644
--- a/hubs/widgets/sticky/__init__.py
+++ b/hubs/widgets/sticky/__init__.py
@@ -2,8 +2,11 @@ from __future__ import unicode_literals
 
 from hubs.widgets import validators
 from hubs.widgets.base import Widget
+from hubs.widgets.caching import CachedFunction
 from hubs.widgets.view import RootWidgetView
 
+from markdown import markdown
+
 
 class Sticky(Widget):
 
@@ -11,9 +14,12 @@ class Sticky(Widget):
     label = "Sticky Note"
     position = "both"
     display_css = "card-info"
+    is_large = True
     parameters = [
         dict(
             name="text",
+            render_tag="textarea",
+            render_attributes={"rows": "30"},
             label="Text",
             default="Lorem ipsum dolor...",
             validator=validators.Text,
@@ -24,7 +30,18 @@ class Sticky(Widget):
 class BaseView(RootWidgetView):
 
     def get_context(self, instance, *args, **kwargs):
-        # TODO -- render with markdown
+        md = ParseMarkdown(instance)
         return dict(
-            text=instance.config["text"],
-            )
+            text=md()
+        )
+
+
+class ParseMarkdown(CachedFunction):
+
+    def execute(self):
+        text = self.instance.config["text"]
+        return markdown(text, extensions=['markdown.extensions.extra',
+                                          'markdown.extensions.sane_lists'])
+
+    def should_invalidate(self, message):
+        return False
diff --git a/requirements.txt b/requirements.txt
index 4a42cec..8232aff 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,6 +13,7 @@ fmn.lib
 fmn.rules
 gunicorn
 html5lib==0.9999999
+markdown
 munch
 psycopg2
 pymongo

